From fe1233c3f12f81bb675718516bbb32f72af726ec Mon Sep 17 00:00:00 2001 From: joshualitt Date: Tue, 7 Oct 2014 12:16:35 -0700 Subject: Cleanup of shader building system this is a huge refactor and cleanup of the gl shader building system in Skia. The entire shader building pipeline is now part of GrGLProgramCreator, which takes a gp, and some fps, and creates a program. I added some subclasses of GrGLProgram to handle the eccentricities of Nvpr/Nvpres. Outside of the builders folder and GrGLPrograms, this change is basically just a rename solo gp BUG=skia: Review URL: https://codereview.chromium.org/611653002 --- src/gpu/gl/builders/GrGLProgramBuilder.h | 516 ++++++++++++++++--------------- 1 file changed, 260 insertions(+), 256 deletions(-) (limited to 'src/gpu/gl/builders/GrGLProgramBuilder.h') diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h index 7fa8ba266c..c51dcbba9f 100644 --- a/src/gpu/gl/builders/GrGLProgramBuilder.h +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -8,31 +8,25 @@ #ifndef GrGLProgramBuilder_DEFINED #define GrGLProgramBuilder_DEFINED -#include "GrAllocator.h" -#include "GrBackendProcessorFactory.h" -#include "GrColor.h" -#include "GrProcessor.h" #include "GrGLFragmentShaderBuilder.h" #include "GrGLGeometryShaderBuilder.h" #include "GrGLVertexShaderBuilder.h" -#include "SkTypes.h" -#include "gl/GrGLProcessor.h" -#include "gl/GrGLProgramDesc.h" -#include "gl/GrGLProgramEffects.h" -#include "gl/GrGLSL.h" -#include "gl/GrGLProgramDataManager.h" +#include "../GrGLProgramDataManager.h" +#include "../GrGLUniformHandle.h" -#include +class GrGLInstalledProcessors; -class GrGLContextInfo; -class GrProcessorStage; -class GrGLProgramDesc; - -/** - Contains all the incremental state of a shader as it is being built,as well as helpers to - manipulate that state. -*/ -class GrGLProgramBuilder { +/* + * This is the base class for a series of interfaces. This base class *MUST* remain abstract with + * NO data members because it is used in multiple interface inheritance. + * Heirarchy: + * GrGLUniformBuilder + * / \ + * GrGLFPBuilder GrGLGPBuilder + * \ / + * GrGLProgramBuilder(internal use only) + */ +class GrGLUniformBuilder { public: enum ShaderVisibility { kVertex_Visibility = 0x1, @@ -40,44 +34,80 @@ public: kFragment_Visibility = 0x4, }; + virtual ~GrGLUniformBuilder() {} + typedef GrGLProgramDataManager::UniformHandle UniformHandle; - typedef GrGLProgramDataManager::VaryingHandle VaryingHandle; - // Handles for program uniforms (other than per-effect uniforms) - struct BuiltinUniformHandles { - UniformHandle fViewMatrixUni; - UniformHandle fRTAdjustmentUni; - UniformHandle fColorUni; - UniformHandle fCoverageUni; + /** Add a uniform variable to the current program, that has visibility in one or more shaders. + visibility is a bitfield of ShaderVisibility values indicating from which shaders the + uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not + supported at this time. The actual uniform name will be mangled. If outName is not NULL then + it will refer to the final uniform name after return. Use the addUniformArray variant to add + an array of uniforms. */ + virtual UniformHandle addUniform(uint32_t visibility, + GrSLType type, + const char* name, + const char** outName = NULL) = 0; + virtual UniformHandle addUniformArray(uint32_t visibility, + GrSLType type, + const char* name, + int arrayCount, + const char** outName = NULL) = 0; + + virtual const GrGLShaderVar& getUniformVariable(UniformHandle u) const = 0; - // We use the render target height to provide a y-down frag coord when specifying - // origin_upper_left is not supported. - UniformHandle fRTHeightUni; + /** + * Shortcut for getUniformVariable(u).c_str() + */ + virtual const char* getUniformCStr(UniformHandle u) const = 0; - // Uniforms for computing texture coords to do the dst-copy lookup - UniformHandle fDstCopyTopLeftUni; - UniformHandle fDstCopyScaleUni; - UniformHandle fDstCopySamplerUni; - }; + virtual const GrGLContextInfo& ctxInfo() const = 0; - struct UniformInfo { - GrGLShaderVar fVariable; - uint32_t fVisibility; - GrGLint fLocation; - }; + virtual GrGpuGL* gpu() const = 0; + + /* + * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE + */ +}; - // This uses an allocator rather than array so that the GrGLShaderVars don't move in memory - // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their - // name strings. Otherwise, we'd have to hand out copies. - typedef GrTAllocator UniformInfoArray; +/* a specialization of the above for GPs. Lets the user add uniforms, varyings, and VS / FS code */ +class GrGLGPBuilder : public virtual GrGLUniformBuilder { +public: + virtual void addVarying(GrSLType type, + const char* name, + const char** vsOutName = NULL, + const char** fsInName = NULL, + GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision) = 0; - struct SeparableVaryingInfo { - GrGLShaderVar fVariable; - GrGLint fLocation; - }; + // TODO rename getFragmentBuilder + virtual GrGLGPFragmentBuilder* getFragmentShaderBuilder() = 0; + virtual GrGLVertexBuilder* getVertexShaderBuilder() = 0; + + /* + * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE + */ +}; - typedef GrTAllocator SeparableVaryingInfoArray; +/* a specializations for FPs. Lets the user add uniforms and FS code */ +class GrGLFPBuilder : public virtual GrGLUniformBuilder { +public: + virtual GrGLFPFragmentBuilder* getFragmentShaderBuilder() = 0; + + /* + * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE + */ +}; +/* + * 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 GrGLGPBuilder, + public GrGLFPBuilder { +public: /** Generates a shader program. * * The program implements what is specified in the stages given as input. @@ -85,252 +115,226 @@ public: * to be used. * @return true if generation was successful. */ - - bool genProgram(const GrGeometryStage* inGeometryProcessor, - const GrFragmentStage* inColorStages[], - const GrFragmentStage* inCoverageStages[]); - - GrGLProgramEffects* getGeometryProcessor() const { - SkASSERT(fProgramID); return fGeometryProcessor.get(); - } - GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return fColorEffects.get(); } - GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); return fCoverageEffects.get(); } - const BuiltinUniformHandles& getBuiltinUniformHandles() const { - SkASSERT(fProgramID); - return fUniformHandles; - } - GrGLuint getProgramID() const { SkASSERT(fProgramID); return fProgramID; } - bool hasVertexShader() const { SkASSERT(fProgramID); return !fFragOnly; } - int getTexCoordSetCount() const { SkASSERT(fProgramID); return fTexCoordSetCnt; } - const UniformInfoArray& getUniformInfos() const { return fUniforms; } - const SeparableVaryingInfoArray& getSeparableVaryingInfos() const { - return fSeparableVaryingInfos; - } - - virtual ~GrGLProgramBuilder() {} - - /** Add a uniform variable to the current program, that has visibility in one or more shaders. - visibility is a bitfield of ShaderVisibility values indicating from which shaders the - uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not - supported at this time. The actual uniform name will be mangled. If outName is not NULL then - it will refer to the final uniform name after return. Use the addUniformArray variant to add - an array of uniforms. */ - GrGLProgramDataManager::UniformHandle addUniform(uint32_t visibility, - GrSLType type, - const char* name, - const char** outName = NULL) { + static GrGLProgram* CreateProgram(const GrOptDrawState&, + const GrGLProgramDesc&, + GrGpu::DrawType, + const GrGeometryStage* inGeometryProcessor, + const GrFragmentStage* inColorStages[], + const GrFragmentStage* inCoverageStages[], + GrGpuGL* gpu); + + virtual UniformHandle addUniform(uint32_t visibility, + GrSLType type, + const char* name, + const char** outName = NULL) SK_OVERRIDE { return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName); } - GrGLProgramDataManager::UniformHandle addUniformArray(uint32_t visibility, - GrSLType type, - const char* name, - int arrayCount, - const char** outName = NULL); + virtual UniformHandle addUniformArray(uint32_t visibility, + GrSLType type, + const char* name, + int arrayCount, + const char** outName = NULL) SK_OVERRIDE; - const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandle u) const { + virtual const GrGLShaderVar& getUniformVariable(UniformHandle u) const SK_OVERRIDE { return fUniforms[u.toShaderBuilderIndex()].fVariable; } - /** - * Shortcut for getUniformVariable(u).c_str() - */ - const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const { + virtual const char* getUniformCStr(UniformHandle u) const SK_OVERRIDE { return this->getUniformVariable(u).c_str(); } - const GrGLContextInfo& ctxInfo() const; + virtual const GrGLContextInfo& ctxInfo() const SK_OVERRIDE; - GrGLFragmentShaderBuilder* getFragmentShaderBuilder() { return &fFS; } - GrGpuGL* gpu() const { return fGpu; } + virtual GrGpuGL* gpu() const SK_OVERRIDE { return fGpu; } + + virtual GrGLFragmentShaderBuilder* getFragmentShaderBuilder() SK_OVERRIDE { return &fFS; } + virtual GrGLVertexBuilder* getVertexShaderBuilder() SK_OVERRIDE { return &fVS; } + + virtual void addVarying(GrSLType type, + const char* name, + const char** vsOutName = NULL, + const char** fsInName = NULL, + GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision); + + // Handles for program uniforms (other than per-effect uniforms) + struct BuiltinUniformHandles { + UniformHandle fViewMatrixUni; + UniformHandle fRTAdjustmentUni; + UniformHandle fColorUni; + UniformHandle fCoverageUni; + + // We use the render target height to provide a y-down frag coord when specifying + // origin_upper_left is not supported. + UniformHandle fRTHeightUni; + + // Uniforms for computing texture coords to do the dst-copy lookup + UniformHandle fDstCopyTopLeftUni; + UniformHandle fDstCopyScaleUni; + UniformHandle fDstCopySamplerUni; + }; protected: - typedef GrTAllocator VarArray; + static GrGLProgramBuilder* CreateProgramBuilder(const GrGLProgramDesc&, + const GrOptDrawState&, + GrGpu::DrawType, + bool hasGeometryProcessor, + GrGpuGL*); + GrGLProgramBuilder(GrGpuGL*, const GrOptDrawState&, const GrGLProgramDesc&); const GrOptDrawState& optState() const { return fOptState; } const GrGLProgramDesc& desc() const { return fDesc; } - - // Helper for emitEffects(). - void createAndEmitEffects(const GrFragmentStage* effectStages[], - int effectCnt, - const GrGLProgramDesc::EffectKeyProvider&, - GrGLSLExpr4* inOutFSColor); - - /* - * A helper function called to emit the geometry processor as well as individual coverage - * and color stages. this will call into subclasses emit effect - */ - void emitEffect(const GrProcessorStage& effectStage, - int effectIndex, - const GrGLProgramDesc::EffectKeyProvider& keyProvider, - GrGLSLExpr4* inColor, - GrGLSLExpr4* outColor); - - /** - * Helper for emitEffect() in subclasses. Emits uniforms for an effect's texture accesses and - * appends the necessary data to the TextureSamplerArray* object so effects can add texture - * lookups to their code. This method is only meant to be called during the construction phase. - */ - void emitSamplers(const GrProcessor& effect, - GrGLProcessor::TextureSamplerArray* outSamplers); + const GrGLProgramDesc::KeyHeader& header() const { return fDesc.getHeader(); } // Generates a name for a variable. The generated string will be name prefixed by the prefix // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're // generating stage code. void nameVariable(SkString* out, char prefix, const char* name); + void setupUniformColorAndCoverageIfNeeded(GrGLSLExpr4* inputColor, GrGLSLExpr4* inputCoverage); + void createAndEmitProcessors(const GrGeometryStage* geometryProcessor, + const GrFragmentStage* colorStages[], + const GrFragmentStage* coverageStages[], + GrGLSLExpr4* inputColor, + GrGLSLExpr4* inputCoverage); + template + void createAndEmitProcessors(const ProcessorStage*[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* fsInOutColor, + GrGLInstalledProcessors*); + void verify(const GrGeometryProcessor&); + void verify(const GrFragmentProcessor&); + void emitSamplers(const GrProcessor&, + GrGLProcessor::TextureSamplerArray* outSamplers, + GrGLInstalledProcessors*); + + // each specific program builder has a distinct transform and must override this function + virtual void emitTransforms(const GrProcessorStage&, + GrGLProcessor::TransformedCoordsArray* outCoords, + GrGLInstalledProcessors*); + GrGLProgram* finalize(); + void bindUniformLocations(GrGLuint programID); + bool checkLinkStatus(GrGLuint programID); + void resolveUniformLocations(GrGLuint programID); + + void cleanupProgram(GrGLuint programID, const SkTDArray& shaderIDs); + void cleanupShaders(const SkTDArray& shaderIDs); + + // Subclasses create different programs + virtual GrGLProgram* createProgram(GrGLuint programID); - virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray* shaderIds) const; - - virtual void bindProgramLocations(GrGLuint programId); - void resolveProgramLocations(GrGLuint programId); - - void appendDecls(const VarArray&, SkString*) const; void appendUniformDecls(ShaderVisibility, SkString*) const; - class CodeStage : SkNoncopyable { + // 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->enterStage(); + this->addStage(); + fFS.reset(); + } + void addStage() { fStageIndex++; } + + // This simple class exits the stage and then restores the stage when it goes out of scope + class AutoStageRestore { public: - CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} + AutoStageRestore(GrGLProgramBuilder* pb) + : fPB(pb), fOutOfStage(pb->fOutOfStage) { pb->exitStage(); } + ~AutoStageRestore() { fPB->fOutOfStage = fOutOfStage; } + private: + GrGLProgramBuilder* fPB; + bool fOutOfStage; + }; + void exitStage() { fOutOfStage = true; } + void enterStage() { fOutOfStage = false; } + int stageIndex() const { return fStageIndex; } - bool inStageCode() const { - this->validate(); - return SkToBool(fEffectStage); - } + typedef GrGLProgramDesc::EffectKeyProvider EffectKeyProvider; + typedef GrGLProgramDataManager::UniformInfo UniformInfo; + typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray; - const GrProcessorStage* effectStage() const { - this->validate(); - return fEffectStage; - } + // number of each input/output type in a single allocation block, used by many builders + static const int kVarsPerBlock; - int stageIndex() const { - this->validate(); - return fCurrentIndex; - } + BuiltinUniformHandles fUniformHandles; + GrGLVertexBuilder fVS; + GrGLGeometryBuilder fGS; + GrGLFragmentShaderBuilder fFS; + bool fOutOfStage; + int fStageIndex; - class AutoStageRestore : SkNoncopyable { - public: - AutoStageRestore(CodeStage* codeStage, const GrProcessorStage* newStage) { - SkASSERT(codeStage); - fSavedIndex = codeStage->fCurrentIndex; - fSavedEffectStage = codeStage->fEffectStage; - - if (NULL == newStage) { - codeStage->fCurrentIndex = -1; - } else { - codeStage->fCurrentIndex = codeStage->fNextIndex++; - } - codeStage->fEffectStage = newStage; - - fCodeStage = codeStage; - } - ~AutoStageRestore() { - fCodeStage->fCurrentIndex = fSavedIndex; - fCodeStage->fEffectStage = fSavedEffectStage; - } - private: - CodeStage* fCodeStage; - int fSavedIndex; - const GrProcessorStage* fSavedEffectStage; - }; - private: - void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } - int fNextIndex; - int fCurrentIndex; - const GrProcessorStage* fEffectStage; - }; + SkAutoTUnref fGeometryProcessor; + SkAutoTUnref fColorEffects; + SkAutoTUnref fCoverageEffects; + + const GrOptDrawState& fOptState; + const GrGLProgramDesc& fDesc; + GrGpuGL* fGpu; + UniformInfoArray fUniforms; + + friend class GrGLShaderBuilder; + friend class GrGLVertexBuilder; + friend class GrGLFragmentShaderBuilder; + friend class GrGLGeometryBuilder; +}; - class GrGLProcessorEmitterInterface { - public: - virtual ~GrGLProcessorEmitterInterface() {} - virtual GrGLProcessor* createGLInstance() = 0; - virtual void emit(const GrProcessorKey& key, - const char* outColor, - const char* inColor, - const GrGLProcessor::TransformedCoordsArray& coords, - const GrGLProcessor::TextureSamplerArray& samplers) = 0; +/** + * This class encapsulates an array of GrGLProcessors and their supporting data (coord transforms + * and textures). It is built by GrGLProgramBuilder, then used to manage the necessary GL + * state and shader uniforms in GLPrograms. Its just Plain old data, and as such is entirely public + * + * TODO We really don't need this class to have an array of processors. It makes sense for it + * to just have one, also break out the transforms + */ +class GrGLInstalledProcessors : public SkRefCnt { +public: + GrGLInstalledProcessors(int reserveCount, bool hasExplicitLocalCoords = false) + : fGLProcessors(reserveCount) + , fSamplers(reserveCount) + , fTransforms(reserveCount) + , fHasExplicitLocalCoords(hasExplicitLocalCoords) { + } + + virtual ~GrGLInstalledProcessors(); + + typedef GrGLProgramDataManager::UniformHandle UniformHandle; + + struct Sampler { + SkDEBUGCODE(Sampler() : fTextureUnit(-1) {}) + UniformHandle fUniform; + int fTextureUnit; }; - class GrGLFragmentProcessorEmitter : public GrGLProcessorEmitterInterface { + class ShaderVarHandle { public: - GrGLFragmentProcessorEmitter(GrGLProgramBuilder* builder) - : fBuilder(builder) - , fFragmentProcessor(NULL) - , fGLFragmentProcessor(NULL) {} - virtual ~GrGLFragmentProcessorEmitter() {} - void set(const GrFragmentProcessor* fp) { - SkASSERT(NULL == fFragmentProcessor); - fFragmentProcessor = fp; - } - virtual GrGLProcessor* createGLInstance() { - SkASSERT(fFragmentProcessor); - SkASSERT(NULL == fGLFragmentProcessor); - fGLFragmentProcessor = - fFragmentProcessor->getFactory().createGLInstance(*fFragmentProcessor); - return fGLFragmentProcessor; - } - virtual void emit(const GrProcessorKey& key, - const char* outColor, - const char* inColor, - const GrGLProcessor::TransformedCoordsArray& coords, - const GrGLProcessor::TextureSamplerArray& samplers) { - SkASSERT(fFragmentProcessor); - SkASSERT(fGLFragmentProcessor); - fGLFragmentProcessor->emitCode(fBuilder, *fFragmentProcessor, key, outColor, inColor, - coords, samplers); - // this will not leak because it hasa already been used by createGLInstance - fGLFragmentProcessor = NULL; - fFragmentProcessor = NULL; + bool isValid() const { return fHandle > -1; } + ShaderVarHandle() : fHandle(-1) {} + ShaderVarHandle(int value) : fHandle(value) { SkASSERT(this->isValid()); } + int handle() const { SkASSERT(this->isValid()); return fHandle; } + UniformHandle convertToUniformHandle() { + SkASSERT(this->isValid()); + return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fHandle); } + private: - GrGLProgramBuilder* fBuilder; - const GrFragmentProcessor* fFragmentProcessor; - GrGLFragmentProcessor* fGLFragmentProcessor; + int fHandle; }; - GrGLProcessorEmitterInterface* fEffectEmitter; - CodeStage fCodeStage; - SkAutoTUnref fGeometryProcessor; - SkAutoTUnref fColorEffects; - SkAutoTUnref fCoverageEffects; - BuiltinUniformHandles fUniformHandles; - bool fFragOnly; - int fTexCoordSetCnt; - GrGLuint fProgramID; - GrGLFragmentShaderBuilder fFS; - SeparableVaryingInfoArray fSeparableVaryingInfos; - -private: - virtual void createAndEmitEffects(const GrGeometryStage* geometryProcessor, - const GrFragmentStage* colorStages[], - const GrFragmentStage* coverageStages[], - GrGLSLExpr4* inputColor, - GrGLSLExpr4* inputCoverage) = 0; - /* - * Subclasses override emitEffect below to emit data and code for a specific single effect - */ - virtual void emitEffect(const GrProcessorStage&, - const GrProcessorKey&, - const char* outColor, - const char* inColor, - int stageIndex) = 0; - - /* - * Because we have fragment only builders, and those builders need to implement a subclass - * of program effects, we have to have base classes overload the program effects here - */ - virtual GrGLProgramEffects* getProgramEffects() = 0; - - /** - * Compiles all the shaders, links them into a program, and writes the program id to the output - * struct. - **/ - bool finish(); + struct Transform { + Transform() : fType(kVoid_GrSLType) { fCurrentValue = SkMatrix::InvalidMatrix(); } + ShaderVarHandle fHandle; + SkMatrix fCurrentValue; + GrSLType fType; + }; - GrGLFragmentProcessorEmitter fGrProcessorEmitter; + void addEffect(GrGLProcessor* effect) { fGLProcessors.push_back(effect); } + SkTArray& addSamplers() { return fSamplers.push_back(); } + SkTArray& addTransforms() { return fTransforms.push_back(); } - const GrOptDrawState& fOptState; - const GrGLProgramDesc& fDesc; - GrGpuGL* fGpu; - UniformInfoArray fUniforms; + SkTArray fGLProcessors; + SkTArray > fSamplers; + SkTArray > fTransforms; + bool fHasExplicitLocalCoords; friend class GrGLShaderBuilder; friend class GrGLVertexShaderBuilder; -- cgit v1.2.3