Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a ProgramInfo class to decouple the Program from the Pipeline class. #1765

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions tgfx/src/gpu/OpsRenderPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
7 changes: 4 additions & 3 deletions tgfx/src/gpu/OpsRenderPass.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
#include <optional>
#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"
Expand Down Expand Up @@ -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<GpuBuffer> indexBuffer, std::shared_ptr<GpuBuffer> 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<GpuBuffer> indexBuffer,
std::shared_ptr<GpuBuffer> vertexBuffer) = 0;
virtual void onDraw(PrimitiveType primitiveType, int baseVertex, int vertexCount) = 0;
Expand Down
77 changes: 55 additions & 22 deletions tgfx/src/gpu/Pipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,52 +17,85 @@
/////////////////////////////////////////////////////////////////////////////////////////////////

#include "Pipeline.h"
#include "gpu/ProgramBuilder.h"
#include "gpu/StagedUniformBuffer.h"
#include "gpu/TextureSampler.h"
#include "gpu/processors/PorterDuffXferProcessor.h"

namespace tgfx {
Pipeline::Pipeline(std::unique_ptr<GeometryProcessor> geometryProcessor,
std::vector<std::unique_ptr<FragmentProcessor>> fragmentProcessors,
size_t numColorProcessors, BlendMode blendMode,
std::shared_ptr<Texture> 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<uint32_t>(_outputSwizzle->asKey()));
}

const XferProcessor* Pipeline::getXferProcessor() const {
if (xferProcessor == nullptr) {
return EmptyXferProcessor::GetInstance();
}
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<StagedUniformBuffer*>(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<SamplerInfo> Pipeline::getSamplers() const {
std::vector<SamplerInfo> 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<uint32_t>(_outputSwizzle->asKey()));
}

std::unique_ptr<Program> Pipeline::createProgram(Context* context) const {
return ProgramBuilder::CreateProgram(context, this);
}
} // namespace tgfx
55 changes: 34 additions & 21 deletions tgfx/src/gpu/Pipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -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> 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> geometryProcessor,
std::vector<std::unique_ptr<FragmentProcessor>> fragmentProcessors,
size_t numColorProcessors, BlendMode blendMode, std::shared_ptr<Texture> 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;
Expand All @@ -50,40 +55,48 @@ 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<SamplerInfo> getSamplers() const override;

void computeUniqueKey(Context* context, BytesKey* uniqueKey) const override;

std::unique_ptr<Program> createProgram(Context* context) const override;

private:
std::unique_ptr<GeometryProcessor> geometryProcessor;
std::vector<std::unique_ptr<FragmentProcessor>> fragmentProcessors;
// This value is also the index in fragmentProcessors where coverage processors begin.
size_t numColorProcessors = 0;
std::unique_ptr<XferProcessor> xferProcessor;
BlendInfo _blendInfo = {};
std::shared_ptr<Texture> dstTexture;
bool _requiresBarrier = false;
Point dstTextureOffset = Point::Zero();
DstTextureInfo dstTextureInfo = {};
const Swizzle* _outputSwizzle = nullptr;
};
} // namespace tgfx
14 changes: 0 additions & 14 deletions tgfx/src/gpu/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<Program> createProgram(Context* context) const = 0;
};
} // namespace tgfx
7 changes: 3 additions & 4 deletions tgfx/src/gpu/ProgramBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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");
}

Expand Down Expand Up @@ -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";
Expand Down
5 changes: 5 additions & 0 deletions tgfx/src/gpu/ProgramBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
namespace tgfx {
class ProgramBuilder {
public:
/**
* Generates a shader program.
*/
static std::unique_ptr<Program> CreateProgram(Context* context, const Pipeline* pipeline);

virtual ~ProgramBuilder() = default;

Context* getContext() const {
Expand Down
6 changes: 3 additions & 3 deletions tgfx/src/gpu/ProgramCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ 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);
programLRU.push_front(result->second);
return result->second;
}
// TODO(domrjchen): createProgram() 应该统计到 programCompilingTime 里。
auto program = programMaker->createProgram(context).release();
auto program = programInfo->createProgram(context).release();
if (program == nullptr) {
return nullptr;
}
Expand Down
3 changes: 2 additions & 1 deletion tgfx/src/gpu/ProgramCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <list>
#include <unordered_map>
#include "Program.h"
#include "ProgramInfo.h"

namespace tgfx {
/**
Expand All @@ -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;
Expand Down
Loading
Loading