diff options
Diffstat (limited to 'src/gpu/gl/builders/GrGLProgramBuilder.h')
-rw-r--r-- | src/gpu/gl/builders/GrGLProgramBuilder.h | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h new file mode 100644 index 0000000000..09f7eba511 --- /dev/null +++ b/src/gpu/gl/builders/GrGLProgramBuilder.h @@ -0,0 +1,318 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGLProgramBuilder_DEFINED +#define GrGLProgramBuilder_DEFINED + +#include "GrAllocator.h" +#include "GrBackendEffectFactory.h" +#include "GrColor.h" +#include "GrEffect.h" +#include "GrGLFragmentShaderBuilder.h" +#include "GrGLGeometryShaderBuilder.h" +#include "GrGLVertexShaderBuilder.h" +#include "SkTypes.h" +#include "gl/GrGLProgramDesc.h" +#include "gl/GrGLProgramEffects.h" +#include "gl/GrGLSL.h" +#include "gl/GrGLProgramDataManager.h" + +#include <stdarg.h> + +class GrGLContextInfo; +class GrEffectStage; +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 { +public: + enum ShaderVisibility { + kVertex_Visibility = 0x1, + kGeometry_Visibility = 0x2, + kFragment_Visibility = 0x4, + }; + + typedef GrGLProgramDataManager::UniformHandle UniformHandle; + + // 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; + }; + + struct UniformInfo { + GrGLShaderVar fVariable; + uint32_t fVisibility; + GrGLint fLocation; + }; + + // 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<UniformInfo> UniformInfoArray; + + /** Generates a shader program. + * + * The program implements what is specified in the stages given as input. + * After successful generation, the builder result objects are available + * to be used. + * @return true if generation was successful. + */ + bool genProgram(const GrEffectStage* inColorStages[], + const GrEffectStage* inCoverageStages[]); + + // Below are the results of the shader generation. + + 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; } + + 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) { + 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); + + const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandle u) const { + return fUniforms[u.toShaderBuilderIndex()].fVariable; + } + + /** + * Shortcut for getUniformVariable(u).c_str() + */ + const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const { + return this->getUniformVariable(u).c_str(); + } + + const GrGLContextInfo& ctxInfo() const; + + GrGLFragmentShaderBuilder* getFragmentShaderBuilder() { return &fFS; } + +protected: + typedef GrTAllocator<GrGLShaderVar> VarArray; + GrGLProgramBuilder(GrGpuGL*, const GrGLProgramDesc&); + + GrGpuGL* gpu() const { return fGpu; } + + const GrGLProgramDesc& desc() const { return fDesc; } + + // Helper for emitEffects(). + void createAndEmitEffects(GrGLProgramEffectsBuilder*, + const GrEffectStage* effectStages[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor); + + // 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); + + virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const; + + virtual void bindProgramLocations(GrGLuint programId); + void resolveProgramLocations(GrGLuint programId); + + void appendDecls(const VarArray&, SkString*) const; + void appendUniformDecls(ShaderVisibility, SkString*) const; + + SkAutoTUnref<GrGLProgramEffects> fColorEffects; + SkAutoTUnref<GrGLProgramEffects> fCoverageEffects; + BuiltinUniformHandles fUniformHandles; + bool fFragOnly; + int fTexCoordSetCnt; + GrGLuint fProgramID; + GrGLFragmentShaderBuilder fFS; +private: + class CodeStage : SkNoncopyable { + public: + CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {} + + bool inStageCode() const { + this->validate(); + return NULL != fEffectStage; + } + + const GrEffectStage* effectStage() const { + this->validate(); + return fEffectStage; + } + + int stageIndex() const { + this->validate(); + return fCurrentIndex; + } + + class AutoStageRestore : SkNoncopyable { + public: + AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) { + SkASSERT(NULL != 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 GrEffectStage* fSavedEffectStage; + }; + private: + void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); } + int fNextIndex; + int fCurrentIndex; + const GrEffectStage* fEffectStage; + } fCodeStage; + + /** + * The base class will emit the fragment code that precedes the per-effect code and then call + * this function. The subclass can use it to insert additional fragment code that should + * execute before the effects' code and/or emit other shaders (e.g. geometry, vertex). + * + * The subclass can modify the initial color or coverage + */ + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0; + + /** + * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for + * deleting it when finished. effectStages contains the effects to add. The effect key provider + * is used to communicate the key each effect created in its GenKey function. inOutFSColor + * specifies the input color to the first stage and is updated to be the output color of the + * last stage. The handles to texture samplers for effectStage[i] are added to + * effectSamplerHandles[i]. + */ + virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor) = 0; + + /** + * Similar to emitCodeBeforeEffects() but called after per-effect code is emitted. + */ + virtual void emitCodeAfterEffects() = 0; + + /** + * Compiles all the shaders, links them into a program, and writes the program id to the output + * struct. + **/ + bool finish(); + + const GrGLProgramDesc& fDesc; + GrGpuGL* fGpu; + UniformInfoArray fUniforms; + + friend class GrGLShaderBuilder; + friend class GrGLVertexShaderBuilder; + friend class GrGLFragmentShaderBuilder; + friend class GrGLGeometryShaderBuilder; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class GrGLFullProgramBuilder : public GrGLProgramBuilder { +public: + GrGLFullProgramBuilder(GrGpuGL*, const GrGLProgramDesc&); + + /** Add a varying variable to the current program to pass values between vertex and fragment + shaders. If the last two parameters are non-NULL, they are filled in with the name + generated. */ + void addVarying(GrSLType type, + const char* name, + const char** vsOutName = NULL, + const char** fsInName = NULL); + + GrGLVertexShaderBuilder* getVertexShaderBuilder() { return &fVS; } + +private: + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE; + + virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; + + virtual void emitCodeAfterEffects() SK_OVERRIDE; + + virtual bool compileAndAttachShaders(GrGLuint programId, + SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE; + + virtual void bindProgramLocations(GrGLuint programId) SK_OVERRIDE; + + GrGLGeometryShaderBuilder fGS; + GrGLVertexShaderBuilder fVS; + + typedef GrGLProgramBuilder INHERITED; +}; + +//////////////////////////////////////////////////////////////////////////////// + +class GrGLFragmentOnlyProgramBuilder : public GrGLProgramBuilder { +public: + GrGLFragmentOnlyProgramBuilder(GrGpuGL*, const GrGLProgramDesc&); + + int addTexCoordSets(int count); + +private: + virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {} + + virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[], + int effectCnt, + const GrGLProgramDesc::EffectKeyProvider&, + GrGLSLExpr4* inOutFSColor) SK_OVERRIDE; + + virtual void emitCodeAfterEffects() SK_OVERRIDE {} + + typedef GrGLProgramBuilder INHERITED; +}; + +#endif |