From fa8963252e122c5288c8e92b5ecc25a8fea21c3b Mon Sep 17 00:00:00 2001 From: egdaniel Date: Wed, 13 Jan 2016 12:19:30 -0800 Subject: Move some program building utils from GL to GLSL BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1535603006 Review URL: https://codereview.chromium.org/1535603006 --- include/gpu/GrTypesPriv.h | 29 ++++ src/gpu/gl/GrGLProgram.cpp | 43 +++-- src/gpu/gl/GrGLProgram.h | 15 +- src/gpu/gl/builders/GrGLProgramBuilder.cpp | 257 ++--------------------------- src/gpu/gl/builders/GrGLProgramBuilder.h | 91 +--------- src/gpu/glsl/GrGLSLCaps.h | 1 + src/gpu/glsl/GrGLSLFragmentShaderBuilder.h | 1 + src/gpu/glsl/GrGLSLProgramBuilder.cpp | 223 ++++++++++++++++++++++++- src/gpu/glsl/GrGLSLProgramBuilder.h | 65 ++++++++ src/gpu/glsl/GrGLSLShaderBuilder.h | 2 + 10 files changed, 361 insertions(+), 366 deletions(-) diff --git a/include/gpu/GrTypesPriv.h b/include/gpu/GrTypesPriv.h index 491b23b37b..6a9c44ff9f 100644 --- a/include/gpu/GrTypesPriv.h +++ b/include/gpu/GrTypesPriv.h @@ -107,6 +107,35 @@ static inline bool GrSLTypeIsFloatType(GrSLType type) { GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); GR_STATIC_ASSERT(9 == kGrSLTypeCount); } + +/** Returns the size in bytes for floating point GrSLTypes. For non floating point type returns 0 */ +static inline size_t GrSLTypeSize(GrSLType type) { + SkASSERT(GrSLTypeIsFloatType(type)); + static const size_t kSizes[] = { + 0, // kVoid_GrSLType + sizeof(float), // kFloat_GrSLType + 2 * sizeof(float), // kVec2f_GrSLType + 3 * sizeof(float), // kVec3f_GrSLType + 4 * sizeof(float), // kVec4f_GrSLType + 9 * sizeof(float), // kMat33f_GrSLType + 16 * sizeof(float), // kMat44f_GrSLType + 0, // kSampler2D_GrSLType + 0 // kSamplerExternal_GrSLType + }; + return kSizes[type]; + + GR_STATIC_ASSERT(0 == kVoid_GrSLType); + GR_STATIC_ASSERT(1 == kFloat_GrSLType); + GR_STATIC_ASSERT(2 == kVec2f_GrSLType); + GR_STATIC_ASSERT(3 == kVec3f_GrSLType); + GR_STATIC_ASSERT(4 == kVec4f_GrSLType); + GR_STATIC_ASSERT(5 == kMat33f_GrSLType); + GR_STATIC_ASSERT(6 == kMat44f_GrSLType); + GR_STATIC_ASSERT(7 == kSampler2D_GrSLType); + GR_STATIC_ASSERT(8 == kSamplerExternal_GrSLType); + GR_STATIC_ASSERT(9 == kGrSLTypeCount); +} + ////////////////////////////////////////////////////////////////////////////// /** diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index c1f5b37b07..007d9670bc 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -31,15 +31,15 @@ GrGLProgram::GrGLProgram(GrGLGpu* gpu, GrGLuint programID, const UniformInfoArray& uniforms, const VaryingInfoArray& pathProcVaryings, - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledXferProc* xferProcessor, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLSLPrimitiveProcessor* geometryProcessor, + GrGLSLXferProcessor* xferProcessor, + const GrGLSLFragProcs& fragmentProcessors, SkTArray* passSamplerUniforms) : fBuiltinUniformHandles(builtinUniforms) , fProgramID(programID) , fGeometryProcessor(geometryProcessor) , fXferProcessor(xferProcessor) - , fFragmentProcessors(SkRef(fragmentProcessors)) + , fFragmentProcessors(fragmentProcessors) , fDesc(desc) , fGpu(gpu) , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) { @@ -55,6 +55,9 @@ GrGLProgram::~GrGLProgram() { if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } + for (int i = 0; i < fFragmentProcessors.count(); ++i) { + delete fFragmentProcessors[i]; + } } void GrGLProgram::abandon() { @@ -63,12 +66,9 @@ void GrGLProgram::abandon() { /////////////////////////////////////////////////////////////////////////////// -template -static void append_texture_bindings(const Proc* ip, - const GrProcessor& processor, +static void append_texture_bindings(const GrProcessor& processor, SkTArray* textureBindings) { if (int numTextures = processor.numTextures()) { - SkASSERT(textureBindings->count() == ip->fSamplersIdx); const GrTextureAccess** bindings = textureBindings->push_back_n(numTextures); int i = 0; do { @@ -84,37 +84,32 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, // we set the textures, and uniforms for installed processors in a generic way, but subclasses // of GLProgram determine how to set coord transforms - fGeometryProcessor->fGLProc->setData(fProgramDataManager, primProc); - append_texture_bindings(fGeometryProcessor.get(), primProc, textureBindings); + fGeometryProcessor->setData(fProgramDataManager, primProc); + append_texture_bindings(primProc, textureBindings); this->setFragmentData(primProc, pipeline, textureBindings); const GrXferProcessor& xp = pipeline.getXferProcessor(); - fXferProcessor->fGLProc->setData(fProgramDataManager, xp); - append_texture_bindings(fXferProcessor.get(), xp, textureBindings); + fXferProcessor->setData(fProgramDataManager, xp); + append_texture_bindings(xp, textureBindings); } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, SkTArray* textureBindings) { - int numProcessors = fFragmentProcessors->fProcs.count(); + int numProcessors = fFragmentProcessors.count(); for (int i = 0; i < numProcessors; ++i) { const GrFragmentProcessor& processor = pipeline.getFragmentProcessor(i); - fFragmentProcessors->fProcs[i]->fGLProc->setData(fProgramDataManager, processor); - this->setTransformData(primProc, - processor, - i, - fFragmentProcessors->fProcs[i]); - append_texture_bindings(fFragmentProcessors->fProcs[i], processor, textureBindings); + fFragmentProcessors[i]->setData(fProgramDataManager, processor); + this->setTransformData(primProc, processor, i); + append_texture_bindings(processor, textureBindings); } } void GrGLProgram::setTransformData(const GrPrimitiveProcessor& primProc, const GrFragmentProcessor& processor, - int index, - GrGLInstalledFragProc* ip) { - GrGLSLPrimitiveProcessor* gp = fGeometryProcessor.get()->fGLProc.get(); - gp->setTransformData(primProc, fProgramDataManager, index, - processor.coordTransforms()); + int index) { + fGeometryProcessor->setTransformData(primProc, fProgramDataManager, index, + processor.coordTransforms()); } void GrGLProgram::setRenderTargetState(const GrPrimitiveProcessor& primProc, diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index ad0569817b..22678cb6a3 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -108,9 +108,9 @@ protected: GrGLuint programID, const UniformInfoArray&, const VaryingInfoArray&, // used for NVPR only currently - GrGLInstalledGeoProc* geometryProcessor, - GrGLInstalledXferProc* xferProcessor, - GrGLInstalledFragProcs* fragmentProcessors, + GrGLSLPrimitiveProcessor* geometryProcessor, + GrGLSLXferProcessor* xferProcessor, + const GrGLSLFragProcs& fragmentProcessors, SkTArray* passSamplerUniforms); // A templated helper to loop over effects, set the transforms(via subclass) and bind textures @@ -118,8 +118,7 @@ protected: SkTArray* textureBindings); void setTransformData(const GrPrimitiveProcessor&, const GrFragmentProcessor&, - int index, - GrGLInstalledFragProc*); + int index); // Helper for setData() that sets the view matrix and loads the render target height uniform void setRenderTargetState(const GrPrimitiveProcessor&, const GrPipeline&); @@ -130,9 +129,9 @@ protected: GrGLuint fProgramID; // the installed effects - SkAutoTDelete fGeometryProcessor; - SkAutoTDelete fXferProcessor; - SkAutoTUnref fFragmentProcessors; + SkAutoTDelete fGeometryProcessor; + SkAutoTDelete fXferProcessor; + GrGLSLFragProcs fFragmentProcessors; GrProgramDesc fDesc; GrGLGpu* fGpu; diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 4360f7858d..4503d1a197 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -42,7 +42,10 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp GrGLSLExpr4 inputColor; GrGLSLExpr4 inputCoverage; - if (!pb->emitAndInstallProcs(&inputColor, &inputCoverage)) { + if (!pb->emitAndInstallProcs(&inputColor, + &inputCoverage, + gpu->glCaps().maxFragmentTextureUnits())) { + pb->cleanupFragmentProcessors(); return nullptr; } @@ -53,243 +56,18 @@ GrGLProgram* GrGLProgramBuilder::CreateProgram(const DrawArgs& args, GrGLGpu* gp GrGLProgramBuilder::GrGLProgramBuilder(GrGLGpu* gpu, const DrawArgs& args) : INHERITED(args) - , fGeometryProcessor(nullptr) - , fXferProcessor(nullptr) , fGpu(gpu) , fSamplerUniforms(4) , fVaryingHandler(this) , fUniformHandler(this) { } -const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { - return this->fGpu->ctxInfo().caps()->glslCaps(); -} - -bool GrGLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage) { - // First we loop over all of the installed processors and collect coord transforms. These will - // be sent to the GrGLSLPrimitiveProcessor in its emitCode function - const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); - int totalTextures = primProc.numTextures(); - const int maxTextureUnits = fGpu->glCaps().maxFragmentTextureUnits(); - - for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { - const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i); - - if (!primProc.hasTransformedLocalCoords()) { - SkTArray& procCoords = fCoordTransforms.push_back(); - processor.gatherCoordTransforms(&procCoords); - } - - totalTextures += processor.numTextures(); - if (totalTextures >= maxTextureUnits) { - GrCapsDebugf(fGpu->caps(), "Program would use too many texture units\n"); - return false; - } - } - - this->emitAndInstallProc(primProc, inputColor, inputCoverage); - - fFragmentProcessors.reset(new GrGLInstalledFragProcs); - int numProcs = this->pipeline().numFragmentProcessors(); - this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor); - this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs, - inputCoverage); - this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage, - this->pipeline().ignoresCoverage()); - this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); - return true; -} - -void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset, - int numProcs, - GrGLSLExpr4* inOut) { - for (int i = procOffset; i < numProcs; ++i) { - GrGLSLExpr4 output; - const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i); - this->emitAndInstallProc(fp, i, *inOut, &output); - *inOut = output; - } -} - -void GrGLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) { - // create var to hold stage result. If we already have a valid output name, just use that - // otherwise create a new mangled one. This name is only valid if we are reordering stages - // and have to tell stage exactly where to put its output. - SkString outName; - if (output->isValid()) { - outName = output->c_str(); - } else { - this->nameVariable(&outName, '\0', baseName); - } - fFS.codeAppendf("vec4 %s;", outName.c_str()); - *output = outName; -} - -// TODO Processors cannot output zeros because an empty string is all 1s -// the fix is to allow effects to take the GrGLSLExpr4 directly -void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, - int index, - const GrGLSLExpr4& input, - GrGLSLExpr4* output) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - this->nameExpression(output, "output"); - - // Enclose custom code in a block to avoid namespace conflicts - SkString openBrace; - openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); - fFS.codeAppend(openBrace.c_str()); - - this->emitAndInstallProc(fp, index, output->c_str(), input.isOnes() ? nullptr : input.c_str()); - - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& proc, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - this->nameExpression(outputColor, "outputColor"); - this->nameExpression(outputCoverage, "outputCoverage"); - - // Enclose custom code in a block to avoid namespace conflicts - SkString openBrace; - openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); - fFS.codeAppend(openBrace.c_str()); - fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); - - this->emitAndInstallProc(proc, outputColor->c_str(), outputCoverage->c_str()); - - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitAndInstallProc(const GrFragmentProcessor& fp, - int index, - const char* outColor, - const char* inColor) { - GrGLInstalledFragProc* ifp = new GrGLInstalledFragProc; - - ifp->fGLProc.reset(fp.createGLSLInstance()); - - SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); - this->emitSamplers(fp, &samplers, ifp); - - GrGLSLFragmentProcessor::EmitArgs args(&fFS, - &fUniformHandler, - this->glslCaps(), - fp, - outColor, - inColor, - fOutCoords[index], - samplers); - ifp->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(fp); - fFragmentProcessors->fProcs.push_back(ifp); +const GrCaps* GrGLProgramBuilder::caps() const { + return fGpu->caps(); } -void GrGLProgramBuilder::emitAndInstallProc(const GrPrimitiveProcessor& gp, - const char* outColor, - const char* outCoverage) { - SkASSERT(!fGeometryProcessor); - fGeometryProcessor = new GrGLInstalledGeoProc; - - fGeometryProcessor->fGLProc.reset(gp.createGLSLInstance(*fGpu->glCaps().glslCaps())); - - SkSTArray<4, GrGLSLTextureSampler> samplers(gp.numTextures()); - this->emitSamplers(gp, &samplers, fGeometryProcessor); - - GrGLSLGeometryProcessor::EmitArgs args(&fVS, - &fFS, - &fVaryingHandler, - &fUniformHandler, - this->glslCaps(), - gp, - outColor, - outCoverage, - samplers, - fCoordTransforms, - &fOutCoords); - fGeometryProcessor->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(gp); -} - -void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage) { - // Program builders have a bit of state we need to clear with each effect - AutoStageAdvance adv(this); - - SkASSERT(!fXferProcessor); - fXferProcessor = new GrGLInstalledXferProc; - - fXferProcessor->fGLProc.reset(xp.createGLSLInstance()); - - // Enable dual source secondary output if we have one - if (xp.hasSecondaryOutput()) { - fFS.enableSecondaryOutput(); - } - - if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { - fFS.enableCustomOutput(); - } - - SkString openBrace; - openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); - fFS.codeAppend(openBrace.c_str()); - - SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); - this->emitSamplers(xp, &samplers, fXferProcessor); - - GrGLSLXferProcessor::EmitArgs args(&fFS, - &fUniformHandler, - this->glslCaps(), - xp, colorIn.c_str(), - ignoresCoverage ? nullptr : coverageIn.c_str(), - fFS.getPrimaryColorOutputName(), - fFS.getSecondaryColorOutputName(), - samplers); - fXferProcessor->fGLProc->emitCode(args); - - // We have to check that effects and the code they emit are consistent, ie if an effect - // asks for dst color, then the emit code needs to follow suit - verify(xp); - fFS.codeAppend("}"); -} - -void GrGLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { - // Swizzle the fragment shader outputs if necessary. - GrSwizzle swizzle; - swizzle.setFromKey(this->desc().header().fOutputSwizzle); - if (swizzle != GrSwizzle::RGBA()) { - fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), - fFS.getPrimaryColorOutputName(), - swizzle.c_str()); - if (hasSecondaryOutput) { - fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), - fFS.getSecondaryColorOutputName(), - swizzle.c_str()); - } - } -} - -void GrGLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { - SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); -} - -void GrGLProgramBuilder::verify(const GrXferProcessor& xp) { - SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); -} - -void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) { - SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); +const GrGLSLCaps* GrGLProgramBuilder::glslCaps() const { + return fGpu->ctxInfo().caps()->glslCaps(); } static GrSLType get_sampler_type(const GrTextureAccess& access) { @@ -302,11 +80,8 @@ static GrSLType get_sampler_type(const GrTextureAccess& access) { } } -template void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor, - GrGLSLTextureSampler::TextureSamplerArray* outSamplers, - GrGLInstalledProc* ip) { - SkDEBUGCODE(ip->fSamplersIdx = fSamplerUniforms.count();) + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) { int numTextures = processor.numTextures(); UniformHandle* localSamplerUniforms = fSamplerUniforms.push_back_n(numTextures); SkString name; @@ -356,6 +131,7 @@ GrGLProgram* GrGLProgramBuilder::finalize() { GrGLuint programID; GL_CALL_RET(programID, CreateProgram()); if (0 == programID) { + this->cleanupFragmentProcessors(); return nullptr; } @@ -474,7 +250,8 @@ void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID) { void GrGLProgramBuilder::cleanupProgram(GrGLuint programID, const SkTDArray& shaderIDs) { GL_CALL(DeleteProgram(programID)); - cleanupShaders(shaderIDs); + this->cleanupShaders(shaderIDs); + this->cleanupFragmentProcessors(); } void GrGLProgramBuilder::cleanupShaders(const SkTDArray& shaderIDs) { for (int i = 0; i < shaderIDs.count(); ++i) { @@ -491,15 +268,7 @@ GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) { fVaryingHandler.fPathProcVaryingInfos, fGeometryProcessor, fXferProcessor, - fFragmentProcessors.get(), + fFragmentProcessors, &fSamplerUniforms); } -/////////////////////////////////////////////////////////////////////////////////////////////////// - -GrGLInstalledFragProcs::~GrGLInstalledFragProcs() { - int numProcs = fProcs.count(); - for (int i = 0; i < numProcs; ++i) { - delete fProcs[i]; - } -} diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index 70cfad5633..20879253ca 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -12,42 +12,14 @@ #include "gl/GrGLProgramDataManager.h" #include "gl/GrGLUniformHandler.h" #include "gl/GrGLVaryingHandler.h" -#include "glsl/GrGLSLPrimitiveProcessor.h" #include "glsl/GrGLSLProgramBuilder.h" #include "glsl/GrGLSLProgramDataManager.h" -#include "glsl/GrGLSLTextureSampler.h" -#include "glsl/GrGLSLXferProcessor.h" class GrFragmentProcessor; class GrGLContextInfo; class GrGLSLShaderBuilder; class GrGLSLCaps; -/** - * The below struct represent processors installed in programs. - */ -template -struct GrGLInstalledProc { - SkDEBUGCODE(int fSamplersIdx;) - SkAutoTDelete fGLProc; -}; - -typedef GrGLInstalledProc GrGLInstalledGeoProc; -typedef GrGLInstalledProc GrGLInstalledXferProc; -typedef GrGLInstalledProc GrGLInstalledFragProc; - -struct GrGLInstalledFragProcs : public SkRefCnt { - virtual ~GrGLInstalledFragProcs(); - SkSTArray<8, GrGLInstalledFragProc*, true> fProcs; -}; - -/* - * Please note - no diamond problems because of virtual inheritance. Also, both base classes - * are pure virtual with no data members. This is the base class for program building. - * Subclasses are nearly identical but each has their own way of emitting transforms. State for - * each of the elements of the shader pipeline, ie vertex, fragment, geometry, etc, lives in those - * respective builders -*/ class GrGLProgramBuilder : public GrGLSLProgramBuilder { public: /** Generates a shader program. @@ -59,6 +31,7 @@ public: */ static GrGLProgram* CreateProgram(const DrawArgs&, GrGLGpu*); + const GrCaps* caps() const override; const GrGLSLCaps* glslCaps() const override; GrGLGpu* gpu() const { return fGpu; } @@ -66,41 +39,8 @@ public: private: GrGLProgramBuilder(GrGLGpu*, const DrawArgs&); - // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. - // If GrGLSLExpr4 has a valid name then it will use that instead - void nameExpression(GrGLSLExpr4*, const char* baseName); - bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage); - void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut); - void emitAndInstallProc(const GrFragmentProcessor&, - int index, - const GrGLSLExpr4& input, - GrGLSLExpr4* output); - - void emitAndInstallProc(const GrPrimitiveProcessor&, - GrGLSLExpr4* outputColor, - GrGLSLExpr4* outputCoverage); - - // these emit functions help to keep the createAndEmitProcessors template general - void emitAndInstallProc(const GrFragmentProcessor&, - int index, - const char* outColor, - const char* inColor); - void emitAndInstallProc(const GrPrimitiveProcessor&, - const char* outColor, - const char* outCoverage); - void emitAndInstallXferProc(const GrXferProcessor&, - const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - bool ignoresCoverage); - void emitFSOutputSwizzle(bool hasSecondaryOutput); - - void verify(const GrPrimitiveProcessor&); - void verify(const GrXferProcessor&); - void verify(const GrFragmentProcessor&); - template void emitSamplers(const GrProcessor&, - GrGLSLTextureSampler::TextureSamplerArray* outSamplers, - GrGLInstalledProc*); + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) override; bool compileAndAttachShaders(GrGLSLShaderBuilder& shader, GrGLuint programId, @@ -120,35 +60,8 @@ private: const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; } - // reset is called by program creator between each processor's emit code. It increments the - // stage offset for variable name mangling, and also ensures verfication variables in the - // fragment shader are cleared. - void reset() { - this->addStage(); - fFS.reset(); - } - void addStage() { fStageIndex++; } - - class AutoStageAdvance { - public: - AutoStageAdvance(GrGLProgramBuilder* pb) - : fPB(pb) { - fPB->reset(); - // Each output to the fragment processor gets its own code section - fPB->fFS.nextStage(); - } - ~AutoStageAdvance() {} - private: - GrGLProgramBuilder* fPB; - }; - - GrGLInstalledGeoProc* fGeometryProcessor; - GrGLInstalledXferProc* fXferProcessor; - SkAutoTUnref fFragmentProcessors; GrGLGpu* fGpu; - GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms; - GrGLSLPrimitiveProcessor::TransformsOut fOutCoords; typedef GrGLSLUniformHandler::UniformHandle UniformHandle; SkTArray fSamplerUniforms; diff --git a/src/gpu/glsl/GrGLSLCaps.h b/src/gpu/glsl/GrGLSLCaps.h index 136bef466c..060539645e 100755 --- a/src/gpu/glsl/GrGLSLCaps.h +++ b/src/gpu/glsl/GrGLSLCaps.h @@ -158,6 +158,7 @@ private: GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt]; friend class GrGLCaps; // For initialization. + friend class GrVkCaps; typedef GrShaderCaps INHERITED; }; diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index a55fdd2860..820cf17ae4 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -194,6 +194,7 @@ private: bool fHasReadDstColor; bool fHasReadFragmentPosition; + friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; typedef GrGLSLXPFragmentBuilder INHERITED; diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index d3ed719fdc..6e0e95f16a 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -7,6 +7,11 @@ #include "glsl/GrGLSLProgramBuilder.h" +#include "GrPipeline.h" +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLGeometryProcessor.h" +#include "glsl/GrGLSLXferProcessor.h" + const int GrGLSLProgramBuilder::kVarsPerBlock = 8; GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) @@ -14,7 +19,203 @@ GrGLSLProgramBuilder::GrGLSLProgramBuilder(const DrawArgs& args) , fGS(this) , fFS(this, args.fDesc->header().fFragPosKey) , fStageIndex(-1) - , fArgs(args) { + , fArgs(args) + , fGeometryProcessor(nullptr) + , fXferProcessor(nullptr) { +} + +bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, + GrGLSLExpr4* inputCoverage, + int maxTextures) { + // First we loop over all of the installed processors and collect coord transforms. These will + // be sent to the GrGLSLPrimitiveProcessor in its emitCode function + const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); + int totalTextures = primProc.numTextures(); + + for (int i = 0; i < this->pipeline().numFragmentProcessors(); i++) { + const GrFragmentProcessor& processor = this->pipeline().getFragmentProcessor(i); + + if (!primProc.hasTransformedLocalCoords()) { + SkTArray& procCoords = fCoordTransforms.push_back(); + processor.gatherCoordTransforms(&procCoords); + } + + totalTextures += processor.numTextures(); + if (totalTextures >= maxTextures) { + GrCapsDebugf(this->caps(), "Program would use too many texture units\n"); + return false; + } + } + + this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); + + int numProcs = this->pipeline().numFragmentProcessors(); + this->emitAndInstallFragProcs(0, this->pipeline().numColorFragmentProcessors(), inputColor); + this->emitAndInstallFragProcs(this->pipeline().numColorFragmentProcessors(), numProcs, + inputCoverage); + this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage, + this->pipeline().ignoresCoverage()); + this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); + return true; +} + +void GrGLSLProgramBuilder::emitAndInstallPrimProc(const GrPrimitiveProcessor& proc, + GrGLSLExpr4* outputColor, + GrGLSLExpr4* outputCoverage) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + this->nameExpression(outputColor, "outputColor"); + this->nameExpression(outputCoverage, "outputCoverage"); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("{ // Stage %d, %s\n", fStageIndex, proc.name()); + fFS.codeAppend(openBrace.c_str()); + fVS.codeAppendf("// Primitive Processor %s\n", proc.name()); + + SkASSERT(!fGeometryProcessor); + fGeometryProcessor = proc.createGLSLInstance(*this->glslCaps()); + + SkSTArray<4, GrGLSLTextureSampler> samplers(proc.numTextures()); + this->emitSamplers(proc, &samplers); + + GrGLSLGeometryProcessor::EmitArgs args(&fVS, + &fFS, + this->varyingHandler(), + this->uniformHandler(), + this->glslCaps(), + proc, + outputColor->c_str(), + outputCoverage->c_str(), + samplers, + fCoordTransforms, + &fOutCoords); + fGeometryProcessor->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(proc); + + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitAndInstallFragProcs(int procOffset, + int numProcs, + GrGLSLExpr4* inOut) { + for (int i = procOffset; i < numProcs; ++i) { + GrGLSLExpr4 output; + const GrFragmentProcessor& fp = this->pipeline().getFragmentProcessor(i); + this->emitAndInstallFragProc(fp, i, *inOut, &output); + *inOut = output; + } +} + +// TODO Processors cannot output zeros because an empty string is all 1s +// the fix is to allow effects to take the GrGLSLExpr4 directly +void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, + int index, + const GrGLSLExpr4& input, + GrGLSLExpr4* output) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + this->nameExpression(output, "output"); + + // Enclose custom code in a block to avoid namespace conflicts + SkString openBrace; + openBrace.printf("{ // Stage %d, %s\n", fStageIndex, fp.name()); + fFS.codeAppend(openBrace.c_str()); + + GrGLSLFragmentProcessor* fragProc = fp.createGLSLInstance(); + + SkSTArray<4, GrGLSLTextureSampler> samplers(fp.numTextures()); + this->emitSamplers(fp, &samplers); + + GrGLSLFragmentProcessor::EmitArgs args(&fFS, + this->uniformHandler(), + this->glslCaps(), + fp, + output->c_str(), + input.isOnes() ? nullptr : input.c_str(), + fOutCoords[index], + samplers); + fragProc->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(fp); + fFragmentProcessors.push_back(fragProc); + + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn, + bool ignoresCoverage) { + // Program builders have a bit of state we need to clear with each effect + AutoStageAdvance adv(this); + + SkASSERT(!fXferProcessor); + fXferProcessor = xp.createGLSLInstance(); + + // Enable dual source secondary output if we have one + if (xp.hasSecondaryOutput()) { + fFS.enableSecondaryOutput(); + } + + if (this->glslCaps()->mustDeclareFragmentShaderOutput()) { + fFS.enableCustomOutput(); + } + + SkString openBrace; + openBrace.printf("{ // Xfer Processor: %s\n", xp.name()); + fFS.codeAppend(openBrace.c_str()); + + SkSTArray<4, GrGLSLTextureSampler> samplers(xp.numTextures()); + this->emitSamplers(xp, &samplers); + + GrGLSLXferProcessor::EmitArgs args(&fFS, + this->uniformHandler(), + this->glslCaps(), + xp, colorIn.c_str(), + ignoresCoverage ? nullptr : coverageIn.c_str(), + fFS.getPrimaryColorOutputName(), + fFS.getSecondaryColorOutputName(), + samplers); + fXferProcessor->emitCode(args); + + // We have to check that effects and the code they emit are consistent, ie if an effect + // asks for dst color, then the emit code needs to follow suit + verify(xp); + fFS.codeAppend("}"); +} + +void GrGLSLProgramBuilder::emitFSOutputSwizzle(bool hasSecondaryOutput) { + // Swizzle the fragment shader outputs if necessary. + GrSwizzle swizzle; + swizzle.setFromKey(this->desc().header().fOutputSwizzle); + if (swizzle != GrSwizzle::RGBA()) { + fFS.codeAppendf("%s = %s.%s;", fFS.getPrimaryColorOutputName(), + fFS.getPrimaryColorOutputName(), + swizzle.c_str()); + if (hasSecondaryOutput) { + fFS.codeAppendf("%s = %s.%s;", fFS.getSecondaryColorOutputName(), + fFS.getSecondaryColorOutputName(), + swizzle.c_str()); + } + } +} + +void GrGLSLProgramBuilder::verify(const GrPrimitiveProcessor& gp) { + SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition()); +} + +void GrGLSLProgramBuilder::verify(const GrXferProcessor& xp) { + SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor()); +} + +void GrGLSLProgramBuilder::verify(const GrFragmentProcessor& fp) { + SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition()); } void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name, bool mangle) { @@ -32,6 +233,20 @@ void GrGLSLProgramBuilder::nameVariable(SkString* out, char prefix, const char* } } +void GrGLSLProgramBuilder::nameExpression(GrGLSLExpr4* output, const char* baseName) { + // create var to hold stage result. If we already have a valid output name, just use that + // otherwise create a new mangled one. This name is only valid if we are reordering stages + // and have to tell stage exactly where to put its output. + SkString outName; + if (output->isValid()) { + outName = output->c_str(); + } else { + this->nameVariable(&outName, '\0', baseName); + } + fFS.codeAppendf("vec4 %s;", outName.c_str()); + *output = outName; +} + void GrGLSLProgramBuilder::appendUniformDecls(ShaderVisibility visibility, SkString* out) const { this->uniformHandler()->appendUniformDecls(visibility, out); @@ -58,3 +273,9 @@ void GrGLSLProgramBuilder::addRTHeightUniform(const char* name, const char** out name, false, 0, outName); } +void GrGLSLProgramBuilder::cleanupFragmentProcessors() { + for (int i = 0; i < fFragmentProcessors.count(); ++i) { + delete fFragmentProcessors[i]; + } +} + diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h index 2a3b48508c..964d320298 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -12,14 +12,19 @@ #include "GrGpu.h" #include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryShaderBuilder.h" +#include "glsl/GrGLSLPrimitiveProcessor.h" #include "glsl/GrGLSLProgramDataManager.h" #include "glsl/GrGLSLUniformHandler.h" +#include "glsl/GrGLSLTextureSampler.h" #include "glsl/GrGLSLVertexShaderBuilder.h" +#include "glsl/GrGLSLXferProcessor.h" class GrGLSLCaps; class GrGLSLShaderVar; class GrGLSLVaryingHandler; +typedef SkSTArray<8, GrGLSLFragmentProcessor*, true> GrGLSLFragProcs; + class GrGLSLProgramBuilder { public: typedef GrGpu::DrawArgs DrawArgs; @@ -28,6 +33,7 @@ public: virtual ~GrGLSLProgramBuilder() {} + virtual const GrCaps* caps() const = 0; virtual const GrGLSLCaps* glslCaps() const = 0; const GrPrimitiveProcessor& primitiveProcessor() const { return *fArgs.fPrimitiveProcessor; } @@ -76,8 +82,67 @@ public: BuiltinUniformHandles fUniformHandles; + GrGLSLPrimitiveProcessor* fGeometryProcessor; + GrGLSLXferProcessor* fXferProcessor; + GrGLSLFragProcs fFragmentProcessors; + protected: explicit GrGLSLProgramBuilder(const DrawArgs& args); + + bool emitAndInstallProcs(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage, int maxTextures); + + void cleanupFragmentProcessors(); + +private: + // reset is called by program creator between each processor's emit code. It increments the + // stage offset for variable name mangling, and also ensures verfication variables in the + // fragment shader are cleared. + void reset() { + this->addStage(); + fFS.reset(); + } + void addStage() { fStageIndex++; } + + class AutoStageAdvance { + public: + AutoStageAdvance(GrGLSLProgramBuilder* pb) + : fPB(pb) { + fPB->reset(); + // Each output to the fragment processor gets its own code section + fPB->fFS.nextStage(); + } + ~AutoStageAdvance() {} + private: + GrGLSLProgramBuilder* fPB; + }; + + // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. + // If GrGLSLExpr4 has a valid name then it will use that instead + void nameExpression(GrGLSLExpr4*, const char* baseName); + + void emitAndInstallPrimProc(const GrPrimitiveProcessor&, + GrGLSLExpr4* outputColor, + GrGLSLExpr4* outputCoverage); + void emitAndInstallFragProcs(int procOffset, int numProcs, GrGLSLExpr4* inOut); + void emitAndInstallFragProc(const GrFragmentProcessor&, + int index, + const GrGLSLExpr4& input, + GrGLSLExpr4* output); + void emitAndInstallXferProc(const GrXferProcessor&, + const GrGLSLExpr4& colorIn, + const GrGLSLExpr4& coverageIn, + bool ignoresCoverage); + void emitFSOutputSwizzle(bool hasSecondaryOutput); + + void verify(const GrPrimitiveProcessor&); + void verify(const GrXferProcessor&); + void verify(const GrFragmentProcessor&); + + virtual void emitSamplers(const GrProcessor& processor, + GrGLSLTextureSampler::TextureSamplerArray* outSamplers) = 0; + + GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms; + GrGLSLPrimitiveProcessor::TransformsOut fOutCoords; }; #endif diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h index 1a8255dbb4..16a0756306 100644 --- a/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -191,7 +191,9 @@ protected: int fCodeIndex; bool fFinalized; + friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; friend class GrGLPathProgramBuilder; // to access fInputs. + friend class GrVkProgramBuilder; }; #endif -- cgit v1.2.3