Move some program building utils from GL to GLSL
authoregdaniel <egdaniel@google.com>
Wed, 13 Jan 2016 20:19:30 +0000 (12:19 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 13 Jan 2016 20:19:30 +0000 (12:19 -0800)
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
src/gpu/gl/GrGLProgram.cpp
src/gpu/gl/GrGLProgram.h
src/gpu/gl/builders/GrGLProgramBuilder.cpp
src/gpu/gl/builders/GrGLProgramBuilder.h
src/gpu/glsl/GrGLSLCaps.h
src/gpu/glsl/GrGLSLFragmentShaderBuilder.h
src/gpu/glsl/GrGLSLProgramBuilder.cpp
src/gpu/glsl/GrGLSLProgramBuilder.h
src/gpu/glsl/GrGLSLShaderBuilder.h

index 491b23b..6a9c44f 100644 (file)
@@ -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);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 /**
index c1f5b37..007d967 100644 (file)
@@ -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<UniformHandle>* 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 <class Proc>
-static void append_texture_bindings(const Proc* ip,
-                                    const GrProcessor& processor,
+static void append_texture_bindings(const GrProcessor& processor,
                                     SkTArray<const GrTextureAccess*>* 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<const GrTextureAccess*>* 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,
index ad05698..22678cb 100644 (file)
@@ -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<UniformHandle>* passSamplerUniforms);
 
     // A templated helper to loop over effects, set the transforms(via subclass) and bind textures
@@ -118,8 +118,7 @@ protected:
                          SkTArray<const GrTextureAccess*>* 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<GrGLInstalledGeoProc> fGeometryProcessor;
-    SkAutoTDelete<GrGLInstalledXferProc> fXferProcessor;
-    SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
+    SkAutoTDelete<GrGLSLPrimitiveProcessor> fGeometryProcessor;
+    SkAutoTDelete<GrGLSLXferProcessor> fXferProcessor;
+    GrGLSLFragProcs fFragmentProcessors;
 
     GrProgramDesc fDesc;
     GrGLGpu* fGpu;
index 4360f78..4503d1a 100644 (file)
@@ -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<const GrCoordTransform*, true>& 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 <class Proc>
 void GrGLProgramBuilder::emitSamplers(const GrProcessor& processor,
-                                      GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
-                                      GrGLInstalledProc<Proc>* 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<GrGLuint>& shaderIDs) {
     GL_CALL(DeleteProgram(programID));
-    cleanupShaders(shaderIDs);
+    this->cleanupShaders(shaderIDs);
+    this->cleanupFragmentProcessors();
 }
 void GrGLProgramBuilder::cleanupShaders(const SkTDArray<GrGLuint>& 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];
-    }
-}
index 70cfad5..2087925 100644 (file)
 #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 <class Proc>
-struct GrGLInstalledProc {
-    SkDEBUGCODE(int fSamplersIdx;)
-    SkAutoTDelete<Proc> fGLProc;
-};
-
-typedef GrGLInstalledProc<GrGLSLPrimitiveProcessor> GrGLInstalledGeoProc;
-typedef GrGLInstalledProc<GrGLSLXferProcessor> GrGLInstalledXferProc;
-typedef GrGLInstalledProc<GrGLSLFragmentProcessor> 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 <class Proc>
     void emitSamplers(const GrProcessor&,
-                      GrGLSLTextureSampler::TextureSamplerArray* outSamplers,
-                      GrGLInstalledProc<Proc>*);
+                      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<GrGLInstalledFragProcs> fFragmentProcessors;
 
     GrGLGpu* fGpu;
-    GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
-    GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
     typedef GrGLSLUniformHandler::UniformHandle UniformHandle;
     SkTArray<UniformHandle> fSamplerUniforms;
 
index 136bef4..0605396 100755 (executable)
@@ -158,6 +158,7 @@ private:
     GrSwizzle fConfigOutputSwizzle[kGrPixelConfigCnt];
 
     friend class GrGLCaps;  // For initialization.
+    friend class GrVkCaps;
 
     typedef GrShaderCaps INHERITED;
 };
index a55fdd2..820cf17 100644 (file)
@@ -194,6 +194,7 @@ private:
     bool fHasReadDstColor;
     bool fHasReadFragmentPosition;
 
+    friend class GrGLSLProgramBuilder;
     friend class GrGLProgramBuilder;
 
     typedef GrGLSLXPFragmentBuilder INHERITED;
index d3ed719..6e0e95f 100644 (file)
@@ -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<const GrCoordTransform*, true>& 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];
+    }
+}
+
index 2a3b485..964d320 100644 (file)
 #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
index 1a8255d..16a0756 100644 (file)
@@ -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