From fda77b84900b03fef84e104c351716e4bf30af63 Mon Sep 17 00:00:00 2001 From: domrjchen Date: Mon, 9 Oct 2023 18:21:51 +0800 Subject: [PATCH] Add a ProgramInfo class to decouple the Program from the Pipeline class. --- tgfx/src/gpu/OpsRenderPass.cpp | 5 +- tgfx/src/gpu/OpsRenderPass.h | 7 ++- tgfx/src/gpu/Pipeline.cpp | 77 +++++++++++++++++------- tgfx/src/gpu/Pipeline.h | 55 ++++++++++------- tgfx/src/gpu/Program.h | 14 ----- tgfx/src/gpu/ProgramBuilder.cpp | 7 +-- tgfx/src/gpu/ProgramBuilder.h | 5 ++ tgfx/src/gpu/ProgramCache.cpp | 6 +- tgfx/src/gpu/ProgramCache.h | 3 +- tgfx/src/gpu/ProgramInfo.h | 71 ++++++++++++++++++++++ tgfx/src/gpu/StagedUniformBuffer.cpp | 5 -- tgfx/src/gpu/StagedUniformBuffer.h | 9 +-- tgfx/src/gpu/ops/DrawOp.cpp | 31 +++++----- tgfx/src/gpu/ops/DrawOp.h | 1 + tgfx/src/gpu/ops/FillRectOp.cpp | 2 +- tgfx/src/gpu/ops/RRectOp.cpp | 2 +- tgfx/src/gpu/ops/TriangulatingPathOp.cpp | 2 +- tgfx/src/opengl/GLOpsRenderPass.cpp | 14 ++--- tgfx/src/opengl/GLOpsRenderPass.h | 2 +- tgfx/src/opengl/GLProgram.cpp | 47 +++------------ tgfx/src/opengl/GLProgram.h | 10 ++- tgfx/src/opengl/GLProgramBuilder.cpp | 3 +- tgfx/src/opengl/GLProgramBuilder.h | 11 +--- tgfx/src/opengl/GLProgramCreator.cpp | 34 ----------- tgfx/src/opengl/GLProgramCreator.h | 37 ------------ tgfx/src/opengl/GLUniformBuffer.cpp | 4 +- tgfx/src/opengl/GLUniformBuffer.h | 3 +- 27 files changed, 227 insertions(+), 240 deletions(-) create mode 100644 tgfx/src/gpu/ProgramInfo.h delete mode 100644 tgfx/src/opengl/GLProgramCreator.cpp delete mode 100644 tgfx/src/opengl/GLProgramCreator.h diff --git a/tgfx/src/gpu/OpsRenderPass.cpp b/tgfx/src/gpu/OpsRenderPass.cpp index 7df52a600a..094ec6232f 100644 --- a/tgfx/src/gpu/OpsRenderPass.cpp +++ b/tgfx/src/gpu/OpsRenderPass.cpp @@ -33,9 +33,10 @@ void OpsRenderPass::resetActiveBuffers() { _vertexBuffer = nullptr; } -void OpsRenderPass::bindPipelineAndScissorClip(const Pipeline* pipeline, const Rect& drawBounds) { +void OpsRenderPass::bindProgramAndScissorClip(const ProgramInfo* programInfo, + const Rect& drawBounds) { resetActiveBuffers(); - if (!onBindPipelineAndScissorClip(pipeline, drawBounds)) { + if (!onBindProgramAndScissorClip(programInfo, drawBounds)) { drawPipelineStatus = DrawPipelineStatus::FailedToBind; return; } diff --git a/tgfx/src/gpu/OpsRenderPass.h b/tgfx/src/gpu/OpsRenderPass.h index 0029c5b676..b35a8e461a 100644 --- a/tgfx/src/gpu/OpsRenderPass.h +++ b/tgfx/src/gpu/OpsRenderPass.h @@ -21,8 +21,8 @@ #include #include "Blend.h" #include "GpuBuffer.h" -#include "Pipeline.h" #include "Program.h" +#include "gpu/ProgramInfo.h" #include "gpu/RenderTarget.h" #include "gpu/processors/GeometryProcessor.h" #include "tgfx/core/BlendMode.h" @@ -59,14 +59,15 @@ class OpsRenderPass { void begin(); void end(); - void bindPipelineAndScissorClip(const Pipeline* pipeline, const Rect& drawBounds); + void bindProgramAndScissorClip(const ProgramInfo* programInfo, const Rect& drawBounds); void bindBuffers(std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer); void draw(PrimitiveType primitiveType, int baseVertex, int vertexCount); void drawIndexed(PrimitiveType primitiveType, int baseIndex, int indexCount); void clear(const Rect& scissor, Color color); protected: - virtual bool onBindPipelineAndScissorClip(const Pipeline* pipeline, const Rect& drawBounds) = 0; + virtual bool onBindProgramAndScissorClip(const ProgramInfo* programInfo, + const Rect& drawBounds) = 0; virtual void onBindBuffers(std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer) = 0; virtual void onDraw(PrimitiveType primitiveType, int baseVertex, int vertexCount) = 0; diff --git a/tgfx/src/gpu/Pipeline.cpp b/tgfx/src/gpu/Pipeline.cpp index c0ddf669c7..5cb757acfb 100644 --- a/tgfx/src/gpu/Pipeline.cpp +++ b/tgfx/src/gpu/Pipeline.cpp @@ -17,6 +17,8 @@ ///////////////////////////////////////////////////////////////////////////////////////////////// #include "Pipeline.h" +#include "gpu/ProgramBuilder.h" +#include "gpu/StagedUniformBuffer.h" #include "gpu/TextureSampler.h" #include "gpu/processors/PorterDuffXferProcessor.h" @@ -24,31 +26,17 @@ namespace tgfx { Pipeline::Pipeline(std::unique_ptr geometryProcessor, std::vector> fragmentProcessors, size_t numColorProcessors, BlendMode blendMode, - std::shared_ptr dstTexture, Point dstTextureOffset, - const Swizzle* outputSwizzle) + const DstTextureInfo& dstTextureInfo, const Swizzle* outputSwizzle) : geometryProcessor(std::move(geometryProcessor)), fragmentProcessors(std::move(fragmentProcessors)), numColorProcessors(numColorProcessors), - dstTexture(std::move(dstTexture)), - dstTextureOffset(dstTextureOffset), + dstTextureInfo(dstTextureInfo), _outputSwizzle(outputSwizzle) { if (!BlendModeAsCoeff(blendMode, &_blendInfo)) { xferProcessor = PorterDuffXferProcessor::Make(blendMode); } } -void Pipeline::computeKey(Context* context, BytesKey* bytesKey) const { - geometryProcessor->computeProcessorKey(context, bytesKey); - if (dstTexture != nullptr) { - dstTexture->getSampler()->computeKey(context, bytesKey); - } - for (const auto& processor : fragmentProcessors) { - processor->computeProcessorKey(context, bytesKey); - } - getXferProcessor()->computeProcessorKey(context, bytesKey); - bytesKey->write(static_cast(_outputSwizzle->asKey())); -} - const XferProcessor* Pipeline::getXferProcessor() const { if (xferProcessor == nullptr) { return EmptyXferProcessor::GetInstance(); @@ -56,13 +44,58 @@ const XferProcessor* Pipeline::getXferProcessor() const { return xferProcessor.get(); } -const Texture* Pipeline::getDstTexture(Point* offset) const { - if (dstTexture == nullptr) { - return nullptr; +void Pipeline::getUniforms(UniformBuffer* uniformBuffer) const { + auto buffer = static_cast(uniformBuffer); + buffer->advanceStage(); + FragmentProcessor::CoordTransformIter coordTransformIter(this); + geometryProcessor->setData(buffer, &coordTransformIter); + for (auto& fragmentProcessor : fragmentProcessors) { + buffer->advanceStage(); + FragmentProcessor::Iter iter(fragmentProcessor.get()); + const FragmentProcessor* fp = iter.next(); + while (fp) { + fp->setData(buffer); + fp = iter.next(); + } + } + if (dstTextureInfo.texture != nullptr) { + buffer->advanceStage(); + xferProcessor->setData(buffer, dstTextureInfo.texture.get(), dstTextureInfo.offset); + } + buffer->resetStage(); +} + +std::vector Pipeline::getSamplers() const { + std::vector samplers = {}; + FragmentProcessor::Iter iter(this); + const FragmentProcessor* fp = iter.next(); + while (fp) { + for (size_t i = 0; i < fp->numTextureSamplers(); ++i) { + SamplerInfo sampler = {fp->textureSampler(i), fp->samplerState(i)}; + samplers.push_back(sampler); + } + fp = iter.next(); + } + if (dstTextureInfo.texture != nullptr) { + SamplerInfo sampler = {dstTextureInfo.texture->getSampler(), {}}; + samplers.push_back(sampler); + } + return samplers; +} + +void Pipeline::computeUniqueKey(Context* context, BytesKey* bytesKey) const { + geometryProcessor->computeProcessorKey(context, bytesKey); + if (dstTextureInfo.texture != nullptr) { + dstTextureInfo.texture->getSampler()->computeKey(context, bytesKey); } - if (offset) { - *offset = dstTextureOffset; + for (const auto& processor : fragmentProcessors) { + processor->computeProcessorKey(context, bytesKey); } - return dstTexture.get(); + getXferProcessor()->computeProcessorKey(context, bytesKey); + bytesKey->write(static_cast(_outputSwizzle->asKey())); +} + +std::unique_ptr Pipeline::createProgram(Context* context) const { + return ProgramBuilder::CreateProgram(context, this); } } // namespace tgfx diff --git a/tgfx/src/gpu/Pipeline.h b/tgfx/src/gpu/Pipeline.h index a571f46226..66d65a2af4 100644 --- a/tgfx/src/gpu/Pipeline.h +++ b/tgfx/src/gpu/Pipeline.h @@ -20,23 +20,28 @@ #include "Swizzle.h" #include "gpu/Blend.h" +#include "gpu/ProgramInfo.h" #include "gpu/processors/EmptyXferProcessor.h" #include "gpu/processors/FragmentProcessor.h" #include "gpu/processors/GeometryProcessor.h" namespace tgfx { +struct DstTextureInfo { + bool requiresBarrier = false; + Point offset = Point::Zero(); + std::shared_ptr texture = nullptr; +}; + /** - * This immutable object contains information needed to build a shader program and set API state for - * a draw. + * Pipeline is a ProgramInfo that uses a list of Processors to assemble a shader program and set API + * state for a draw. */ -class Pipeline { +class Pipeline : public ProgramInfo { public: Pipeline(std::unique_ptr geometryProcessor, std::vector> fragmentProcessors, - size_t numColorProcessors, BlendMode blendMode, std::shared_ptr dstTexture, - Point dstTextureOffset, const Swizzle* outputSwizzle); - - void computeKey(Context* context, BytesKey* bytesKey) const; + size_t numColorProcessors, BlendMode blendMode, const DstTextureInfo& dstTextureInfo, + const Swizzle* outputSwizzle); size_t numColorFragmentProcessors() const { return numColorProcessors; @@ -50,30 +55,40 @@ class Pipeline { return geometryProcessor.get(); } - const XferProcessor* getXferProcessor() const; - - const Texture* getDstTexture(Point* offset = nullptr) const; - const FragmentProcessor* getFragmentProcessor(size_t idx) const { return fragmentProcessors[idx].get(); } - void setRequiresBarrier(bool requiresBarrier) { - _requiresBarrier = requiresBarrier; + const XferProcessor* getXferProcessor() const; + + const Swizzle* outputSwizzle() const { + return _outputSwizzle; + } + + const Texture* dstTexture() const { + return dstTextureInfo.texture.get(); } - bool requiresBarrier() const { - return _requiresBarrier; + const Point& dstTextureOffset() const { + return dstTextureInfo.offset; } - const Swizzle* outputSwizzle() const { - return _outputSwizzle; + bool requiresBarrier() const override { + return dstTextureInfo.requiresBarrier; } - const BlendInfo* blendInfo() const { + const BlendInfo* blendInfo() const override { return xferProcessor == nullptr ? &_blendInfo : nullptr; } + void getUniforms(UniformBuffer* uniformBuffer) const override; + + std::vector getSamplers() const override; + + void computeUniqueKey(Context* context, BytesKey* uniqueKey) const override; + + std::unique_ptr createProgram(Context* context) const override; + private: std::unique_ptr geometryProcessor; std::vector> fragmentProcessors; @@ -81,9 +96,7 @@ class Pipeline { size_t numColorProcessors = 0; std::unique_ptr xferProcessor; BlendInfo _blendInfo = {}; - std::shared_ptr dstTexture; - bool _requiresBarrier = false; - Point dstTextureOffset = Point::Zero(); + DstTextureInfo dstTextureInfo = {}; const Swizzle* _outputSwizzle = nullptr; }; } // namespace tgfx diff --git a/tgfx/src/gpu/Program.h b/tgfx/src/gpu/Program.h index c60c5791a7..7d0f051068 100644 --- a/tgfx/src/gpu/Program.h +++ b/tgfx/src/gpu/Program.h @@ -54,18 +54,4 @@ class Program { friend class ProgramCache; }; - -class ProgramCreator { - public: - virtual ~ProgramCreator() = default; - /** - * Overridden to compute a unique key for the program. - */ - virtual void computeUniqueKey(Context* context, BytesKey* uniqueKey) const = 0; - - /** - * Overridden to create a new program. - */ - virtual std::unique_ptr createProgram(Context* context) const = 0; -}; } // namespace tgfx diff --git a/tgfx/src/gpu/ProgramBuilder.cpp b/tgfx/src/gpu/ProgramBuilder.cpp index 14628e0eae..a39ef42c50 100644 --- a/tgfx/src/gpu/ProgramBuilder.cpp +++ b/tgfx/src/gpu/ProgramBuilder.cpp @@ -42,11 +42,10 @@ void ProgramBuilder::advanceStage() { } void ProgramBuilder::emitAndInstallGeoProc(std::string* outputColor, std::string* outputCoverage) { + uniformHandler()->addUniform(ShaderFlags::Vertex, SLType::Float4, RTAdjustName); advanceStage(); nameExpression(outputColor, "outputColor"); nameExpression(outputCoverage, "outputCoverage"); - - uniformHandler()->addUniform(ShaderFlags::Vertex, SLType::Float4, RTAdjustName); auto geometryProcessor = pipeline->getGeometryProcessor(); // Enclose custom code in a block to avoid namespace conflicts fragmentShaderBuilder()->codeAppendf("{ // Stage %d %s\n", _stageIndex, @@ -129,7 +128,7 @@ void ProgramBuilder::emitAndInstallXferProc(const std::string& colorIn, fragmentShaderBuilder()->codeAppendf("{ // Xfer Processor %s\n", xferProcessor->name().c_str()); SamplerHandle dstTextureSamplerHandle; - if (const auto* dstTexture = pipeline->getDstTexture()) { + if (auto dstTexture = pipeline->dstTexture()) { dstTextureSamplerHandle = emitSampler(dstTexture->getSampler(), "DstTextureSampler"); } @@ -163,7 +162,7 @@ std::string ProgramBuilder::nameVariable(char prefix, const std::string& name, b out += prefix; } out += name; - if (mangle) { + if (mangle && _stageIndex >= 0) { if (out.rfind('_') == out.length() - 1) { // Names containing "__" are reserved. out += "x"; diff --git a/tgfx/src/gpu/ProgramBuilder.h b/tgfx/src/gpu/ProgramBuilder.h index 3dff898c1c..5dd74b2bb6 100644 --- a/tgfx/src/gpu/ProgramBuilder.h +++ b/tgfx/src/gpu/ProgramBuilder.h @@ -28,6 +28,11 @@ namespace tgfx { class ProgramBuilder { public: + /** + * Generates a shader program. + */ + static std::unique_ptr CreateProgram(Context* context, const Pipeline* pipeline); + virtual ~ProgramBuilder() = default; Context* getContext() const { diff --git a/tgfx/src/gpu/ProgramCache.cpp b/tgfx/src/gpu/ProgramCache.cpp index 715130076e..17708d110e 100644 --- a/tgfx/src/gpu/ProgramCache.cpp +++ b/tgfx/src/gpu/ProgramCache.cpp @@ -28,9 +28,9 @@ bool ProgramCache::empty() const { return programMap.empty(); } -Program* ProgramCache::getProgram(const ProgramCreator* programMaker) { +Program* ProgramCache::getProgram(const ProgramInfo* programInfo) { BytesKey uniqueKey = {}; - programMaker->computeUniqueKey(context, &uniqueKey); + programInfo->computeUniqueKey(context, &uniqueKey); auto result = programMap.find(uniqueKey); if (result != programMap.end()) { programLRU.remove(result->second); @@ -38,7 +38,7 @@ Program* ProgramCache::getProgram(const ProgramCreator* programMaker) { return result->second; } // TODO(domrjchen): createProgram() 应该统计到 programCompilingTime 里。 - auto program = programMaker->createProgram(context).release(); + auto program = programInfo->createProgram(context).release(); if (program == nullptr) { return nullptr; } diff --git a/tgfx/src/gpu/ProgramCache.h b/tgfx/src/gpu/ProgramCache.h index be9a19a488..b06df75944 100644 --- a/tgfx/src/gpu/ProgramCache.h +++ b/tgfx/src/gpu/ProgramCache.h @@ -21,6 +21,7 @@ #include #include #include "Program.h" +#include "ProgramInfo.h" namespace tgfx { /** @@ -40,7 +41,7 @@ class ProgramCache { * a new program will be created by programMaker. Returns null if the programMaker fails to make a * new program. */ - Program* getProgram(const ProgramCreator* programMaker); + Program* getProgram(const ProgramInfo* programInfo); private: Context* context = nullptr; diff --git a/tgfx/src/gpu/ProgramInfo.h b/tgfx/src/gpu/ProgramInfo.h new file mode 100644 index 0000000000..51305339bb --- /dev/null +++ b/tgfx/src/gpu/ProgramInfo.h @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////////////////////////// +// +// Tencent is pleased to support the open source community by making libpag available. +// +// Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file +// except in compliance with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// unless required by applicable law or agreed to in writing, software distributed under the +// license is distributed on an "as is" basis, without warranties or conditions of any kind, +// either express or implied. see the license for the specific language governing permissions +// and limitations under the license. +// +///////////////////////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "gpu/Blend.h" +#include "gpu/Program.h" +#include "gpu/SamplerState.h" +#include "gpu/TextureSampler.h" +#include "gpu/UniformBuffer.h" + +namespace tgfx { +struct SamplerInfo { + const TextureSampler* sampler; + SamplerState state; +}; +/** + * This immutable object contains information needed to build a shader program and set API state for + * a draw. + */ +class ProgramInfo { + public: + virtual ~ProgramInfo() = default; + + /** + * Returns true if the draw requires a texture barrier. + */ + virtual bool requiresBarrier() const = 0; + + /** + * Returns the blend info for the draw. A nullptr is returned if the draw does not require + * blending. + */ + virtual const BlendInfo* blendInfo() const = 0; + + /** + * Collects uniform data for the draw. + */ + virtual void getUniforms(UniformBuffer* uniformBuffer) const = 0; + + /** + * Collects texture samplers for the draw. + */ + virtual std::vector getSamplers() const = 0; + + /** + * Computes a unique key for the program. + */ + virtual void computeUniqueKey(Context* context, BytesKey* uniqueKey) const = 0; + + /** + * Creates a new program. + */ + virtual std::unique_ptr createProgram(Context* context) const = 0; +}; +} // namespace tgfx diff --git a/tgfx/src/gpu/StagedUniformBuffer.cpp b/tgfx/src/gpu/StagedUniformBuffer.cpp index 6ccc637f55..4ffdcc4e5c 100644 --- a/tgfx/src/gpu/StagedUniformBuffer.cpp +++ b/tgfx/src/gpu/StagedUniformBuffer.cpp @@ -26,11 +26,6 @@ std::string StagedUniformBuffer::GetMangledName(const std::string& name, int sta return name; } -void StagedUniformBuffer::resetStateAndUpload(Context* context) { - stageIndex = -1; - onUploadToGPU(context); -} - std::string StagedUniformBuffer::getUniformKey(const std::string& name) const { return GetMangledName(name, stageIndex); } diff --git a/tgfx/src/gpu/StagedUniformBuffer.h b/tgfx/src/gpu/StagedUniformBuffer.h index 4fd5e5ccf4..d0d6f31769 100644 --- a/tgfx/src/gpu/StagedUniformBuffer.h +++ b/tgfx/src/gpu/StagedUniformBuffer.h @@ -44,7 +44,9 @@ class StagedUniformBuffer : public UniformBuffer { /** * Resets the stage offset and uploads the uniform data to the GPU. */ - void resetStateAndUpload(Context* context); + void resetStage() { + stageIndex = -1; + } protected: /** @@ -52,11 +54,6 @@ class StagedUniformBuffer : public UniformBuffer { */ std::string getUniformKey(const std::string& name) const; - /** - * Called by Program to upload the uniform data to the GPU. - */ - virtual void onUploadToGPU(Context* context) = 0; - private: int stageIndex = -1; }; diff --git a/tgfx/src/gpu/ops/DrawOp.cpp b/tgfx/src/gpu/ops/DrawOp.cpp index dbe70595b1..7ff5ae7514 100644 --- a/tgfx/src/gpu/ops/DrawOp.cpp +++ b/tgfx/src/gpu/ops/DrawOp.cpp @@ -42,12 +42,13 @@ void DrawOp::execute(OpsRenderPass* opsRenderPass) { onExecute(opsRenderPass); } -static std::shared_ptr CreateDstTexture(OpsRenderPass* opsRenderPass, Rect dstRect, - Point* dstOffset) { +static DstTextureInfo CreateDstTextureInfo(OpsRenderPass* opsRenderPass, Rect dstRect) { + DstTextureInfo dstTextureInfo = {}; if (opsRenderPass->context()->caps()->textureBarrierSupport && opsRenderPass->renderTargetTexture()) { - *dstOffset = {0, 0}; - return opsRenderPass->renderTargetTexture(); + dstTextureInfo.texture = opsRenderPass->renderTargetTexture(); + dstTextureInfo.requiresBarrier = true; + return dstTextureInfo; } auto bounds = Rect::MakeWH(opsRenderPass->renderTarget()->width(), opsRenderPass->renderTarget()->height()); @@ -57,20 +58,21 @@ static std::shared_ptr CreateDstTexture(OpsRenderPass* opsRenderPass, R dstRect.bottom = dstRect.top + height; } if (!dstRect.intersect(bounds)) { - return nullptr; + return {}; } dstRect.roundOut(); - *dstOffset = {dstRect.x(), dstRect.y()}; + dstTextureInfo.offset = {dstRect.x(), dstRect.y()}; auto dstTexture = Texture::MakeRGBA(opsRenderPass->context(), static_cast(dstRect.width()), static_cast(dstRect.height()), opsRenderPass->renderTarget()->origin()); if (dstTexture == nullptr) { LOGE("Failed to create dst texture(%f*%f).", dstRect.width(), dstRect.height()); - return nullptr; + return {}; } + dstTextureInfo.texture = dstTexture; opsRenderPass->context()->gpu()->copyRenderTargetToTexture( opsRenderPass->renderTarget().get(), dstTexture.get(), dstRect, Point::Zero()); - return dstTexture; + return dstTextureInfo; } std::unique_ptr DrawOp::createPipeline(OpsRenderPass* renderPass, @@ -81,19 +83,14 @@ std::unique_ptr DrawOp::createPipeline(OpsRenderPass* renderPass, std::move(_colors.begin(), _colors.end(), fragmentProcessors.begin()); std::move(_masks.begin(), _masks.end(), fragmentProcessors.begin() + static_cast(numColorProcessors)); - std::shared_ptr dstTexture; - Point dstTextureOffset = Point::Zero(); + DstTextureInfo dstTextureInfo = {}; auto caps = renderPass->context()->caps(); if (!BlendModeAsCoeff(blendMode) && !caps->frameBufferFetchSupport) { - dstTexture = CreateDstTexture(renderPass, bounds(), &dstTextureOffset); + dstTextureInfo = CreateDstTextureInfo(renderPass, bounds()); } const auto& swizzle = renderPass->renderTarget()->writeSwizzle(); - auto pipeline = - std::make_unique(std::move(gp), std::move(fragmentProcessors), numColorProcessors, - blendMode, dstTexture, dstTextureOffset, &swizzle); - pipeline->setRequiresBarrier(dstTexture != nullptr && - dstTexture == renderPass->renderTargetTexture()); - return pipeline; + return std::make_unique(std::move(gp), std::move(fragmentProcessors), + numColorProcessors, blendMode, dstTextureInfo, &swizzle); } static bool CompareFragments(const std::vector>& frags1, diff --git a/tgfx/src/gpu/ops/DrawOp.h b/tgfx/src/gpu/ops/DrawOp.h index 419245b0b9..04b5952f2f 100644 --- a/tgfx/src/gpu/ops/DrawOp.h +++ b/tgfx/src/gpu/ops/DrawOp.h @@ -22,6 +22,7 @@ #include "Op.h" #include "gpu/AAType.h" #include "gpu/OpsRenderPass.h" +#include "gpu/Pipeline.h" namespace tgfx { class DrawOp : public Op { diff --git a/tgfx/src/gpu/ops/FillRectOp.cpp b/tgfx/src/gpu/ops/FillRectOp.cpp index 26168842db..7d396edee6 100644 --- a/tgfx/src/gpu/ops/FillRectOp.cpp +++ b/tgfx/src/gpu/ops/FillRectOp.cpp @@ -169,7 +169,7 @@ void FillRectOp::onExecute(OpsRenderPass* opsRenderPass) { opsRenderPass, QuadPerEdgeAAGeometryProcessor::Make(opsRenderPass->renderTarget()->width(), opsRenderPass->renderTarget()->height(), aa, !colors.empty())); - opsRenderPass->bindPipelineAndScissorClip(pipeline.get(), scissorRect()); + opsRenderPass->bindProgramAndScissorClip(pipeline.get(), scissorRect()); opsRenderPass->bindBuffers(indexBuffer, vertexBuffer); if (needsIndexBuffer()) { uint16_t numIndicesPerQuad; diff --git a/tgfx/src/gpu/ops/RRectOp.cpp b/tgfx/src/gpu/ops/RRectOp.cpp index da9b1f6269..42864e3d1e 100644 --- a/tgfx/src/gpu/ops/RRectOp.cpp +++ b/tgfx/src/gpu/ops/RRectOp.cpp @@ -273,7 +273,7 @@ void RRectOp::onExecute(OpsRenderPass* opsRenderPass) { EllipseGeometryProcessor::Make(opsRenderPass->renderTarget()->width(), opsRenderPass->renderTarget()->height(), false, UseScale(opsRenderPass->context()), localMatrix)); - opsRenderPass->bindPipelineAndScissorClip(pipeline.get(), scissorRect()); + opsRenderPass->bindProgramAndScissorClip(pipeline.get(), scissorRect()); opsRenderPass->bindBuffers(indexBuffer, vertexBuffer); opsRenderPass->drawIndexed(PrimitiveType::Triangles, 0, static_cast(rRects.size() * kIndicesPerFillRRect)); diff --git a/tgfx/src/gpu/ops/TriangulatingPathOp.cpp b/tgfx/src/gpu/ops/TriangulatingPathOp.cpp index fc3b0e1a5b..2f3deb5dc0 100644 --- a/tgfx/src/gpu/ops/TriangulatingPathOp.cpp +++ b/tgfx/src/gpu/ops/TriangulatingPathOp.cpp @@ -91,7 +91,7 @@ void TriangulatingPathOp::onExecute(OpsRenderPass* opsRenderPass) { opsRenderPass, DefaultGeometryProcessor::Make(color, opsRenderPass->renderTarget()->width(), opsRenderPass->renderTarget()->height(), viewMatrix, localMatrix)); - opsRenderPass->bindPipelineAndScissorClip(pipeline.get(), scissorRect()); + opsRenderPass->bindProgramAndScissorClip(pipeline.get(), scissorRect()); opsRenderPass->bindBuffers(nullptr, buffer); opsRenderPass->draw(PrimitiveType::Triangles, 0, vertexCount); } diff --git a/tgfx/src/opengl/GLOpsRenderPass.cpp b/tgfx/src/opengl/GLOpsRenderPass.cpp index e4b67d45bd..025a0a78c1 100644 --- a/tgfx/src/opengl/GLOpsRenderPass.cpp +++ b/tgfx/src/opengl/GLOpsRenderPass.cpp @@ -18,7 +18,6 @@ #include "GLOpsRenderPass.h" #include "GLGpu.h" -#include "GLProgramCreator.h" #include "GLUtil.h" #include "gpu/ProgramCache.h" @@ -133,10 +132,9 @@ void GLOpsRenderPass::reset() { _renderTargetTexture = nullptr; } -bool GLOpsRenderPass::onBindPipelineAndScissorClip(const Pipeline* pipeline, - const Rect& drawBounds) { - GLProgramCreator creator(pipeline); - _program = static_cast(_context->programCache()->getProgram(&creator)); +bool GLOpsRenderPass::onBindProgramAndScissorClip(const ProgramInfo* programInfo, + const Rect& drawBounds) { + _program = static_cast(_context->programCache()->getProgram(programInfo)); if (_program == nullptr) { return false; } @@ -148,11 +146,11 @@ bool GLOpsRenderPass::onBindPipelineAndScissorClip(const Pipeline* pipeline, gl->bindFramebuffer(GL_FRAMEBUFFER, glRT->getFrameBufferID()); gl->viewport(0, 0, glRT->width(), glRT->height()); UpdateScissor(_context, drawBounds); - UpdateBlend(_context, pipeline->blendInfo()); - if (pipeline->requiresBarrier()) { + UpdateBlend(_context, programInfo->blendInfo()); + if (programInfo->requiresBarrier()) { gl->textureBarrier(); } - program->updateUniformsAndTextureBindings(glRT, pipeline); + program->updateUniformsAndTextureBindings(glRT, programInfo); return true; } diff --git a/tgfx/src/opengl/GLOpsRenderPass.h b/tgfx/src/opengl/GLOpsRenderPass.h index 823f71cc0f..8d91f03288 100644 --- a/tgfx/src/opengl/GLOpsRenderPass.h +++ b/tgfx/src/opengl/GLOpsRenderPass.h @@ -41,7 +41,7 @@ class GLOpsRenderPass : public OpsRenderPass { void reset(); - bool onBindPipelineAndScissorClip(const Pipeline* pipeline, const Rect& drawBounds) override; + bool onBindProgramAndScissorClip(const ProgramInfo* programInfo, const Rect& drawBounds) override; void onBindBuffers(std::shared_ptr indexBuffer, std::shared_ptr vertexBuffer) override; void onDraw(PrimitiveType primitiveType, int baseVertex, int vertexCount) override; diff --git a/tgfx/src/opengl/GLProgram.cpp b/tgfx/src/opengl/GLProgram.cpp index a7561a52e8..62d2e0e7a4 100644 --- a/tgfx/src/opengl/GLProgram.cpp +++ b/tgfx/src/opengl/GLProgram.cpp @@ -19,7 +19,6 @@ #include "GLProgram.h" #include "GLGpu.h" #include "GLUtil.h" -#include "gpu/Pipeline.h" namespace tgfx { GLProgram::GLProgram(Context* context, unsigned programID, @@ -53,45 +52,15 @@ void GLProgram::onReleaseGPU() { } void GLProgram::updateUniformsAndTextureBindings(const GLRenderTarget* renderTarget, - const Pipeline* pipeline) { - // we set the textures, and uniforms for installed processors in a generic way. - - // We must bind to texture units in the same order in which we set the uniforms in - // GLProgramDataManager. That is, we bind textures for processors in this order: - // geometryProcessor, fragmentProcessors, XferProcessor. - uniformBuffer->advanceStage(); + const ProgramInfo* programInfo) { setRenderTargetState(renderTarget); - FragmentProcessor::CoordTransformIter coordTransformIter(pipeline); - auto gp = pipeline->getGeometryProcessor(); - gp->setData(uniformBuffer.get(), &coordTransformIter); - int nextTexSamplerIdx = 0; - setFragmentData(pipeline, &nextTexSamplerIdx); - - auto offset = Point::Zero(); - const auto* dstTexture = pipeline->getDstTexture(&offset); - if (dstTexture) { - uniformBuffer->advanceStage(); - auto xferProcessor = pipeline->getXferProcessor(); - xferProcessor->setData(uniformBuffer.get(), dstTexture, offset); - static_cast(context->gpu())->bindTexture(nextTexSamplerIdx++, dstTexture->getSampler()); - } - uniformBuffer->resetStateAndUpload(context); -} - -void GLProgram::setFragmentData(const Pipeline* pipeline, int* nextTexSamplerIdx) { - for (size_t index = 0; index < pipeline->numFragmentProcessors(); ++index) { - uniformBuffer->advanceStage(); - const auto* currentFP = pipeline->getFragmentProcessor(index); - FragmentProcessor::Iter iter(currentFP); - const FragmentProcessor* fp = iter.next(); - while (fp) { - fp->setData(uniformBuffer.get()); - for (size_t i = 0; i < fp->numTextureSamplers(); ++i) { - static_cast(context->gpu()) - ->bindTexture((*nextTexSamplerIdx)++, fp->textureSampler(i), fp->samplerState(i)); - } - fp = iter.next(); - } + programInfo->getUniforms(uniformBuffer.get()); + uniformBuffer->uploadToGPU(context); + auto samplers = programInfo->getSamplers(); + int textureUnit = 0; + auto gpu = static_cast(context->gpu()); + for (auto& info : samplers) { + gpu->bindTexture(textureUnit++, info.sampler, info.state); } } diff --git a/tgfx/src/opengl/GLProgram.h b/tgfx/src/opengl/GLProgram.h index 28771c33a9..f5dfa5d234 100644 --- a/tgfx/src/opengl/GLProgram.h +++ b/tgfx/src/opengl/GLProgram.h @@ -20,10 +20,11 @@ #include #include "GLContext.h" -#include "GLUniformHandler.h" -#include "gpu/Pipeline.h" #include "gpu/Program.h" +#include "gpu/ProgramInfo.h" +#include "gpu/SLType.h" #include "opengl/GLRenderTarget.h" +#include "opengl/GLUniformHandler.h" namespace tgfx { class GLProgram : public Program { @@ -53,7 +54,7 @@ class GLProgram : public Program { * It is the caller's responsibility to ensure the program is bound before calling. */ void updateUniformsAndTextureBindings(const GLRenderTarget* renderTarget, - const Pipeline* pipeline); + const ProgramInfo* programInfo); int vertexStride() const { return _vertexStride; @@ -70,9 +71,6 @@ class GLProgram : public Program { std::optional origin; }; - // A helper to loop over effects, set the transforms (via subclass) and bind textures - void setFragmentData(const Pipeline* pipeline, int* nextTexSamplerIdx); - void setRenderTargetState(const GLRenderTarget* renderTarget); void onReleaseGPU() override; diff --git a/tgfx/src/opengl/GLProgramBuilder.cpp b/tgfx/src/opengl/GLProgramBuilder.cpp index 804bf461d1..898aee4511 100644 --- a/tgfx/src/opengl/GLProgramBuilder.cpp +++ b/tgfx/src/opengl/GLProgramBuilder.cpp @@ -64,8 +64,7 @@ static std::string SLTypeString(SLType t) { return ""; } -std::unique_ptr GLProgramBuilder::CreateProgram(Context* context, - const Pipeline* pipeline) { +std::unique_ptr ProgramBuilder::CreateProgram(Context* context, const Pipeline* pipeline) { GLProgramBuilder builder(context, pipeline); if (!builder.emitAndInstallProcessors()) { return nullptr; diff --git a/tgfx/src/opengl/GLProgramBuilder.h b/tgfx/src/opengl/GLProgramBuilder.h index 6e431912eb..5cc1e6e172 100644 --- a/tgfx/src/opengl/GLProgramBuilder.h +++ b/tgfx/src/opengl/GLProgramBuilder.h @@ -28,15 +28,6 @@ namespace tgfx { class GLProgramBuilder : public ProgramBuilder { public: - /** - * Generates a shader program. - * - * The program implements what is specified in the stages given as input. - * After successful generation, the builder result objects are available - * to be used. - */ - static std::unique_ptr CreateProgram(Context* context, const Pipeline* pipeline); - std::string versionDeclString() override; std::string textureFuncName() const override; @@ -84,5 +75,7 @@ class GLProgramBuilder : public ProgramBuilder { GLFragmentShaderBuilder _fragBuilder; std::vector attributes; int vertexStride = 0; + + friend class ProgramBuilder; }; } // namespace tgfx diff --git a/tgfx/src/opengl/GLProgramCreator.cpp b/tgfx/src/opengl/GLProgramCreator.cpp deleted file mode 100644 index 96288f4ff4..0000000000 --- a/tgfx/src/opengl/GLProgramCreator.cpp +++ /dev/null @@ -1,34 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////////////////////// -// -// Tencent is pleased to support the open source community by making libpag available. -// -// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// unless required by applicable law or agreed to in writing, software distributed under the -// license is distributed on an "as is" basis, without warranties or conditions of any kind, -// either express or implied. see the license for the specific language governing permissions -// and limitations under the license. -// -///////////////////////////////////////////////////////////////////////////////////////////////// - -#include "GLProgramCreator.h" -#include "GLContext.h" -#include "GLProgramBuilder.h" - -namespace tgfx { -GLProgramCreator::GLProgramCreator(const Pipeline* pipeline) : pipeline(pipeline) { -} - -void GLProgramCreator::computeUniqueKey(Context* context, BytesKey* bytesKey) const { - pipeline->computeKey(context, bytesKey); -} - -std::unique_ptr GLProgramCreator::createProgram(Context* context) const { - return GLProgramBuilder::CreateProgram(context, pipeline); -} -} // namespace tgfx diff --git a/tgfx/src/opengl/GLProgramCreator.h b/tgfx/src/opengl/GLProgramCreator.h deleted file mode 100644 index 9faaca15a1..0000000000 --- a/tgfx/src/opengl/GLProgramCreator.h +++ /dev/null @@ -1,37 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////////////////////// -// -// Tencent is pleased to support the open source community by making libpag available. -// -// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file -// except in compliance with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// unless required by applicable law or agreed to in writing, software distributed under the -// license is distributed on an "as is" basis, without warranties or conditions of any kind, -// either express or implied. see the license for the specific language governing permissions -// and limitations under the license. -// -///////////////////////////////////////////////////////////////////////////////////////////////// - -#pragma once - -#include "gpu/Pipeline.h" -#include "gpu/Program.h" -#include "gpu/processors/GeometryProcessor.h" - -namespace tgfx { -class GLProgramCreator : public ProgramCreator { - public: - explicit GLProgramCreator(const Pipeline* pipeline); - - void computeUniqueKey(Context* context, BytesKey* uniqueKey) const override; - - std::unique_ptr createProgram(Context* context) const override; - - private: - const Pipeline* pipeline; -}; -} // namespace tgfx diff --git a/tgfx/src/opengl/GLUniformBuffer.cpp b/tgfx/src/opengl/GLUniformBuffer.cpp index 213d3b33eb..58644f6106 100644 --- a/tgfx/src/opengl/GLUniformBuffer.cpp +++ b/tgfx/src/opengl/GLUniformBuffer.cpp @@ -18,6 +18,7 @@ #include "GLUniformBuffer.h" #include "tgfx/opengl/GLFunctions.h" +#include "utils/Log.h" namespace tgfx { static size_t GetUniformSize(GLUniform::Type type) { @@ -68,6 +69,7 @@ void GLUniformBuffer::setData(const std::string& name, const void* data) { auto key = getUniformKey(name); auto result = uniforms.find(key); if (result == uniforms.end()) { + LOGE("GLUniformBuffer::setData: uniform %s not found", name.c_str()); return; } auto& uniform = result->second; @@ -80,7 +82,7 @@ void GLUniformBuffer::setData(const std::string& name, const void* data) { memcpy(buffer + uniform.offset, data, size); } -void GLUniformBuffer::onUploadToGPU(Context* context) { +void GLUniformBuffer::uploadToGPU(Context* context) { if (!bufferChanged) { return; } diff --git a/tgfx/src/opengl/GLUniformBuffer.h b/tgfx/src/opengl/GLUniformBuffer.h index 519be5317e..da5744c6cb 100644 --- a/tgfx/src/opengl/GLUniformBuffer.h +++ b/tgfx/src/opengl/GLUniformBuffer.h @@ -56,8 +56,7 @@ class GLUniformBuffer : public StagedUniformBuffer { void setData(const std::string& name, const void* data) override; - protected: - void onUploadToGPU(Context* context) override; + void uploadToGPU(Context* context); private: struct UniformBlock {