/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef GrGLSLProgramBuilder_DEFINED #define GrGLSLProgramBuilder_DEFINED #include "include/private/base/SkDebug.h" #include "include/private/base/SkTArray.h" #include "include/private/gpu/ganesh/GrTypesPriv.h" #include "src/gpu/Swizzle.h" #include "src/gpu/ganesh/GrCaps.h" #include "src/gpu/ganesh/GrFragmentProcessor.h" #include "src/gpu/ganesh/GrGeometryProcessor.h" #include "src/gpu/ganesh/GrPipeline.h" #include "src/gpu/ganesh/GrProgramInfo.h" #include "src/gpu/ganesh/GrSamplerState.h" #include "src/gpu/ganesh/GrShaderVar.h" #include "src/gpu/ganesh/GrXferProcessor.h" #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h" #include "src/gpu/ganesh/glsl/GrGLSLUniformHandler.h" #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h" #include #include #include #include class GrBackendFormat; class GrGLSLVaryingHandler; class GrProgramDesc; class SkString; enum GrSurfaceOrigin : int; struct GrShaderCaps; class GrGLSLProgramBuilder { public: using UniformHandle = GrGLSLUniformHandler::UniformHandle; using SamplerHandle = GrGLSLUniformHandler::SamplerHandle; virtual ~GrGLSLProgramBuilder(); virtual const GrCaps* caps() const = 0; const GrShaderCaps* shaderCaps() const { return this->caps()->shaderCaps(); } GrSurfaceOrigin origin() const { return fProgramInfo.origin(); } const GrPipeline& pipeline() const { return fProgramInfo.pipeline(); } const GrGeometryProcessor& geometryProcessor() const { return fProgramInfo.geomProc(); } bool snapVerticesToPixelCenters() const { return fProgramInfo.pipeline().snapVerticesToPixelCenters(); } bool hasPointSize() const { return fProgramInfo.primitiveType() == GrPrimitiveType::kPoints; } const GrProgramDesc& desc() const { return fDesc; } void appendUniformDecls(GrShaderFlags visibility, SkString*) const; const char* samplerVariable(SamplerHandle handle) const { return this->uniformHandler()->samplerVariable(handle); } skgpu::Swizzle samplerSwizzle(SamplerHandle handle) const { return this->uniformHandler()->samplerSwizzle(handle); } const char* inputSamplerVariable(SamplerHandle handle) const { return this->uniformHandler()->inputSamplerVariable(handle); } skgpu::Swizzle inputSamplerSwizzle(SamplerHandle handle) const { return this->uniformHandler()->inputSamplerSwizzle(handle); } // Used to add a uniform for render target flip (used for dFdy, sk_Clockwise, and sk_FragCoord) // without mangling the name of the uniform inside of a stage. void addRTFlipUniform(const char* name); // Generates a name for a variable. The generated string will be name prefixed by the prefix // char (unless the prefix is '\0'). It also will mangle the name to be stage-specific unless // explicitly asked not to. `nameVariable` can also be used to generate names for functions or // other types of symbols where unique names are important. SkString nameVariable(char prefix, const char* name, bool mangle = true); /** * Emits samplers for TextureEffect fragment processors as needed. `fp` can be a TextureEffect, * or a tree containing zero or more TextureEffects. */ bool emitTextureSamplersForFPs(const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl, int* samplerIndex); /** * advanceStage is called by program creator between each processor's emit code. It increments * the stage index for variable name mangling, and also ensures verification variables in the * fragment shader are cleared. */ void advanceStage() { fStageIndex++; SkDEBUGCODE(fFS.debugOnly_resetPerStageVerification();) fFS.nextStage(); } /** Adds the SkSL function that implements an FP assuming its children are already written. */ void writeFPFunction(const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl); /** * Returns a function-call invocation of `fp` in string form, passing the appropriate * combination of `inputColor`, `destColor` and `fLocalCoordsVar` for the FP. */ std::string invokeFP(const GrFragmentProcessor& fp, const GrFragmentProcessor::ProgramImpl& impl, const char* inputColor, const char* destColor, const char* coords) const; /** * If the FP's coords are unused or all uses have been lifted to interpolated varyings then * don't put coords in the FP's function signature or call sites. */ bool fragmentProcessorHasCoordsParam(const GrFragmentProcessor*) const; virtual GrGLSLUniformHandler* uniformHandler() = 0; virtual const GrGLSLUniformHandler* uniformHandler() const = 0; virtual GrGLSLVaryingHandler* varyingHandler() = 0; // Used for backend customization of the secondary color variable from the fragment processor. // Only used if the output is explicitly declared in the shaders. virtual void finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {} // number of each input/output type in a single allocation block, used by many builders static const int kVarsPerBlock; GrGLSLVertexBuilder fVS; GrGLSLFragmentShaderBuilder fFS; const GrProgramDesc& fDesc; const GrProgramInfo& fProgramInfo; GrGLSLBuiltinUniformHandles fUniformHandles; std::unique_ptr fGPImpl; std::unique_ptr fXPImpl; std::vector> fFPImpls; SamplerHandle fDstTextureSamplerHandle; GrSurfaceOrigin fDstTextureOrigin; protected: explicit GrGLSLProgramBuilder(const GrProgramDesc&, const GrProgramInfo&); void addFeature(GrShaderFlags shaders, uint32_t featureBit, const char* extensionName); bool emitAndInstallProcs(); void finalizeShaders(); bool fragColorIsInOut() const { return fFS.primaryColorOutputIsInOut(); } private: SkString getMangleSuffix() const; // Generates a possibly mangled name for a stage variable and writes it to the fragment shader. void nameExpression(SkString*, const char* baseName); bool emitAndInstallPrimProc(SkString* outputColor, SkString* outputCoverage); bool emitAndInstallDstTexture(); /** Adds the root FPs */ bool emitAndInstallFragProcs(SkString* colorInOut, SkString* coverageInOut); /** Adds a single root FP tree. */ SkString emitRootFragProc(const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl, const SkString& input, SkString output); /** Recursive step to write out children FPs' functions before parent's. */ void writeChildFPFunctions(const GrFragmentProcessor& fp, GrFragmentProcessor::ProgramImpl& impl); bool emitAndInstallXferProc(const SkString& colorIn, const SkString& coverageIn); SamplerHandle emitSampler(const GrBackendFormat&, GrSamplerState, const skgpu::Swizzle&, const char* name); SamplerHandle emitInputSampler(const skgpu::Swizzle& swizzle, const char* name); bool checkSamplerCounts(); #ifdef SK_DEBUG void verify(const GrGeometryProcessor&); void verify(const GrFragmentProcessor&); void verify(const GrXferProcessor&); #endif // This is used to check that we don't excede the allowable number of resources in a shader. int fNumFragmentSamplers; GrGeometryProcessor::ProgramImpl::FPCoordsMap fFPCoordsMap; GrShaderVar fLocalCoordsVar; /** * Each root processor has an stage index. The GP is stage 0. The first root FP is stage 1, * the second root FP is stage 2, etc. The XP's stage index is last and its value depends on * how many root FPs there are. Names are mangled by appending _S. */ int fStageIndex = -1; /** * When emitting FP stages we track the children FPs as "substages" and do additional name * mangling based on where in the FP hierarchy we are. The first FP is stage index 1. It's first * child would be substage 0 of stage 1. If that FP also has three children then its third child * would be substage 2 of stubstage 0 of stage 1 and would be mangled as "_S1_c0_c2". */ skia_private::TArray fSubstageIndices; }; #endif