diff options
author | 2013-09-30 15:30:27 +0000 | |
---|---|---|
committer | 2013-09-30 15:30:27 +0000 | |
commit | 410552a73d59611901033b2bc5147cc6ade0207c (patch) | |
tree | e628e55244cfc90c1e834ece089735f80b97fbff /src/gpu | |
parent | a4acf12a9353ffc834d2c6ee673be447487963c9 (diff) |
Move the GL shader compilation step into GrGLShaderBuilder
Moves the compilation step and a few other blocks of code from
GrGLProgram to GrGLShaderBuilder. This way GrGLProgram doesn't have to
know whether or not there is a vertex shader.
R=bsalomon@google.com
Author: cdalton@nvidia.com
Review URL: https://codereview.chromium.org/23533066
git-svn-id: http://skia.googlecode.com/svn/trunk@11523 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/gl/GrGLProgram.cpp | 382 | ||||
-rw-r--r-- | src/gpu/gl/GrGLProgram.h | 20 | ||||
-rw-r--r-- | src/gpu/gl/GrGLSL.cpp | 8 | ||||
-rw-r--r-- | src/gpu/gl/GrGLSL.h | 18 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.cpp | 437 | ||||
-rw-r--r-- | src/gpu/gl/GrGLShaderBuilder.h | 98 |
6 files changed, 419 insertions, 544 deletions
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index ac9794d4d5..f10e8954f2 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -14,28 +14,13 @@ #include "GrGpuGL.h" #include "GrGLShaderVar.h" #include "GrGLSL.h" -#include "SkTrace.h" #include "SkXfermode.h" -#include "SkRTConf.h" - SK_DEFINE_INST_COUNT(GrGLProgram) #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) -SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, - "Print the source code for all shaders generated."); - -#define COL_ATTR_NAME "aColor" -#define COV_ATTR_NAME "aCoverage" -#define EDGE_ATTR_NAME "aEdge" - -namespace { -inline const char* declared_color_output_name() { return "fsColorOut"; } -inline const char* dual_source_output_name() { return "dualSourceOut"; } -} - GrGLProgram* GrGLProgram::Create(GrGpuGL* gpu, const GrGLProgramDesc& desc, const GrEffectStage* colorStages[], @@ -55,9 +40,6 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, : fGpu(gpu) , fUniformManager(gpu) { fDesc = desc; - fVShaderID = 0; - fGShaderID = 0; - fFShaderID = 0; fProgramID = 0; fDstCopyTexUnit = -1; @@ -72,24 +54,12 @@ GrGLProgram::GrGLProgram(GrGpuGL* gpu, } GrGLProgram::~GrGLProgram() { - if (fVShaderID) { - GL_CALL(DeleteShader(fVShaderID)); - } - if (fGShaderID) { - GL_CALL(DeleteShader(fGShaderID)); - } - if (fFShaderID) { - GL_CALL(DeleteShader(fFShaderID)); - } if (fProgramID) { GL_CALL(DeleteProgram(fProgramID)); } } void GrGLProgram::abandon() { - fVShaderID = 0; - fGShaderID = 0; - fFShaderID = 0; fProgramID = 0; } @@ -219,167 +189,7 @@ void add_color_filter(GrGLShaderBuilder* builder, } } -GrSLConstantVec GrGLProgram::genInputColor(GrGLShaderBuilder* builder, SkString* inColor) { - switch (fDesc.getHeader().fColorInput) { - case GrGLProgramDesc::kAttribute_ColorInput: { - GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder(); - SkASSERT(NULL != vertexBuilder); - vertexBuilder->addAttribute(kVec4f_GrSLType, COL_ATTR_NAME); - const char *vsName, *fsName; - vertexBuilder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); - vertexBuilder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName); - *inColor = fsName; - return kNone_GrSLConstantVec; - } - case GrGLProgramDesc::kUniform_ColorInput: { - const char* name; - fUniformHandles.fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, - kVec4f_GrSLType, "Color", &name); - *inColor = name; - return kNone_GrSLConstantVec; - } - case GrGLProgramDesc::kTransBlack_ColorInput: - inColor->reset(); - return kZeros_GrSLConstantVec; - case GrGLProgramDesc::kSolidWhite_ColorInput: - inColor->reset(); - return kOnes_GrSLConstantVec; - default: - GrCrash("Unknown color type."); - return kNone_GrSLConstantVec; - } -} - -GrSLConstantVec GrGLProgram::genInputCoverage(GrGLShaderBuilder* builder, SkString* inCoverage) { - switch (fDesc.getHeader().fCoverageInput) { - case GrGLProgramDesc::kAttribute_ColorInput: { - GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder(); - SkASSERT(NULL != vertexBuilder); - vertexBuilder->addAttribute(kVec4f_GrSLType, COV_ATTR_NAME); - const char *vsName, *fsName; - vertexBuilder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); - vertexBuilder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName); - *inCoverage = fsName; - return kNone_GrSLConstantVec; - } - case GrGLProgramDesc::kUniform_ColorInput: { - const char* name; - fUniformHandles.fCoverageUni = - builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, - kVec4f_GrSLType, "Coverage", &name); - *inCoverage = name; - return kNone_GrSLConstantVec; - } - case GrGLProgramDesc::kTransBlack_ColorInput: - inCoverage->reset(); - return kZeros_GrSLConstantVec; - case GrGLProgramDesc::kSolidWhite_ColorInput: - inCoverage->reset(); - return kOnes_GrSLConstantVec; - default: - GrCrash("Unknown color type."); - return kNone_GrSLConstantVec; - } -} - -void GrGLProgram::genGeometryShader(GrGLShaderBuilder::VertexBuilder* vertexBuilder) const { -#if GR_GL_EXPERIMENTAL_GS - // TODO: The builder should add all this glue code. - if (fDesc.getHeader().fExperimentalGS) { - SkASSERT(fGpu->glslGeneration() >= k150_GrGLSLGeneration); - vertexBuilder->fGSHeader.append("layout(triangles) in;\n" - "layout(triangle_strip, max_vertices = 6) out;\n"); - vertexBuilder->gsCodeAppend("\tfor (int i = 0; i < 3; ++i) {\n" - "\t\tgl_Position = gl_in[i].gl_Position;\n"); - if (fDesc.getHeader().fEmitsPointSize) { - vertexBuilder->gsCodeAppend("\t\tgl_PointSize = 1.0;\n"); - } - SkASSERT(vertexBuilder->fGSInputs.count() == vertexBuilder->fGSOutputs.count()); - int count = vertexBuilder->fGSInputs.count(); - for (int i = 0; i < count; ++i) { - vertexBuilder->gsCodeAppendf("\t\t%s = %s[i];\n", - vertexBuilder->fGSOutputs[i].getName().c_str(), - vertexBuilder->fGSInputs[i].getName().c_str()); - } - vertexBuilder->gsCodeAppend("\t\tEmitVertex();\n" - "\t}\n" - "\tEndPrimitive();\n"); - } -#endif -} - -const char* GrGLProgram::adjustInColor(const SkString& inColor) const { - if (inColor.size()) { - return inColor.c_str(); - } else { - if (GrGLProgramDesc::kSolidWhite_ColorInput == fDesc.getHeader().fColorInput) { - return GrGLSLOnesVecf(4); - } else { - return GrGLSLZerosVecf(4); - } - } -} - namespace { -// prints a shader using params similar to glShaderSource -void print_shader(GrGLint stringCnt, - const GrGLchar** strings, - GrGLint* stringLengths) { - for (int i = 0; i < stringCnt; ++i) { - if (NULL == stringLengths || stringLengths[i] < 0) { - GrPrintf(strings[i]); - } else { - GrPrintf("%.*s", stringLengths[i], strings[i]); - } - } -} - -// Compiles a GL shader, returns shader ID or 0 if failed params have same meaning as glShaderSource -GrGLuint compile_shader(const GrGLInterface* gli, - GrGLenum type, - int stringCnt, - const char** strings, - int* stringLengths) { - SK_TRACE_EVENT1("GrGLProgram::CompileShader", - "stringCount", SkStringPrintf("%i", stringCnt).c_str()); - - GrGLuint shader; - GR_GL_CALL_RET(gli, shader, CreateShader(type)); - if (0 == shader) { - return 0; - } - - GrGLint compiled = GR_GL_INIT_ZERO; - GR_GL_CALL(gli, ShaderSource(shader, stringCnt, strings, stringLengths)); - GR_GL_CALL(gli, CompileShader(shader)); - GR_GL_CALL(gli, GetShaderiv(shader, GR_GL_COMPILE_STATUS, &compiled)); - - if (!compiled) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GR_GL_CALL(gli, GetShaderiv(shader, GR_GL_INFO_LOG_LENGTH, &infoLen)); - SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - // retrieve length even though we don't need it to workaround bug in chrome cmd buffer - // param validation. - GrGLsizei length = GR_GL_INIT_ZERO; - GR_GL_CALL(gli, GetShaderInfoLog(shader, infoLen+1, - &length, (char*)log.get())); - print_shader(stringCnt, strings, stringLengths); - GrPrintf("\n%s", log.get()); - } - SkDEBUGFAIL("Shader compilation failed!"); - GR_GL_CALL(gli, DeleteShader(shader)); - return 0; - } - return shader; -} - -// helper version of above for when shader is already flattened into a single SkString -GrGLuint compile_shader(const GrGLInterface* gli, GrGLenum type, const SkString& shader) { - const GrGLchar* str = shader.c_str(); - int length = shader.size(); - return compile_shader(gli, type, 1, &str, &length); -} void expand_known_value4f(SkString* string, GrSLConstantVec vec) { SkASSERT(string->isEmpty() == (vec != kNone_GrSLConstantVec)); @@ -397,50 +207,6 @@ void expand_known_value4f(SkString* string, GrSLConstantVec vec) { } -// compiles all the shaders from builder and stores the shader IDs -bool GrGLProgram::compileShaders(const GrGLShaderBuilder& builder) { - - SkASSERT(!fVShaderID); - SkASSERT(!fGShaderID); - SkASSERT(!fFShaderID); - - SkString shader; - if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) { - vertexBuilder->vsGetShader(&shader); - if (c_PrintShaders) { - GrPrintf(shader.c_str()); - GrPrintf("\n"); - } - if (!(fVShaderID = compile_shader(fGpu->glInterface(), GR_GL_VERTEX_SHADER, shader))) { - return false; - } - -#if GR_GL_EXPERIMENTAL_GS - if (fDesc.getHeader().fExperimentalGS) { - vertexBuilder->gsGetShader(&shader); - if (c_PrintShaders) { - GrPrintf(shader.c_str()); - GrPrintf("\n"); - } - if (!(fGShaderID = compile_shader(fGpu->glInterface(), GR_GL_GEOMETRY_SHADER, shader))) { - return false; - } - } -#endif - } - - builder.fsGetShader(&shader); - if (c_PrintShaders) { - GrPrintf(shader.c_str()); - GrPrintf("\n"); - } - if (!(fFShaderID = compile_shader(fGpu->glInterface(), GR_GL_FRAGMENT_SHADER, shader))) { - return false; - } - - return true; -} - bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]) { SkASSERT(0 == fProgramID); @@ -449,42 +215,14 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], bool needsVertexShader = true; - GrGLShaderBuilder builder(fGpu->ctxInfo(), fUniformManager, fDesc, needsVertexShader); - + GrGLShaderBuilder builder(fGpu, fUniformManager, fDesc, needsVertexShader); if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) { - const char* viewMName; - fUniformHandles.fViewMatrixUni = builder.addUniform(GrGLShaderBuilder::kVertex_Visibility, - kMat33f_GrSLType, "ViewM", &viewMName); - - vertexBuilder->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n" - "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n", - viewMName, vertexBuilder->positionAttribute().c_str()); - - // we output point size in the GS if present - if (header.fEmitsPointSize -#if GR_GL_EXPERIMENTAL_GS - && !header.fExperimentalGS -#endif - ) { - vertexBuilder->vsCodeAppend("\tgl_PointSize = 1.0;\n"); - } - } - - // the dual source output has no canonical var name, have to - // declare an output, which is incompatible with gl_FragColor/gl_FragData. - bool dualSourceOutputWritten = false; - - GrGLShaderVar colorOutput; - bool isColorDeclared = GrGLSLSetupFSColorOuput(fGpu->glslGeneration(), - declared_color_output_name(), - &colorOutput); - if (isColorDeclared) { - builder.fsOutputAppend(colorOutput); + fUniformHandles.fViewMatrixUni = vertexBuilder->getViewMatrixUniform(); } // incoming color to current stage being processed. - SkString inColor; - GrSLConstantVec knownColorValue = this->genInputColor(&builder, &inColor); + SkString inColor = builder.getInputColor(); + GrSLConstantVec knownColorValue = builder.getKnownColorValue(); // Get the coeffs for the Mode-based color filter, determine if color is needed. SkXfermode::Coeff colorCoeff; @@ -544,8 +282,8 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], /////////////////////////////////////////////////////////////////////////// // compute the partial coverage - SkString inCoverage; - GrSLConstantVec knownCoverageValue = this->genInputCoverage(&builder, &inCoverage); + SkString inCoverage = builder.getInputCoverage(); + GrSLConstantVec knownCoverageValue = builder.getKnownCoverageValue(); for (int e = 0; e < fDesc.numCoverageEffects(); ++e) { effectUniformArrays[e] = &fCoverageEffects[e].fSamplerUnis; @@ -576,9 +314,8 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], GrGLProgramDesc::CoverageOutput coverageOutput = static_cast<GrGLProgramDesc::CoverageOutput>(header.fCoverageOutput); if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(coverageOutput)) { - builder.fsOutputAppend().set(kVec4f_GrSLType, - GrGLShaderVar::kOut_TypeModifier, - dual_source_output_name()); + const char* secondaryOutputName = builder.enableSecondaryOutput(); + // default coeff to ones for kCoverage_DualSrcOutput SkString coeff; GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec; @@ -613,8 +350,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], knownCoeffValue, knownCoverageValue, false); - builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), modulate.c_str()); - dualSourceOutputWritten = true; + builder.fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, modulate.c_str()); } /////////////////////////////////////////////////////////////////////////// @@ -655,33 +391,17 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], } else { expand_known_value4f(&fragColor, knownFragColorValue); } - builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), fragColor.c_str()); - - /////////////////////////////////////////////////////////////////////////// - // insert GS -#ifdef SK_DEBUG - if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) { - this->genGeometryShader(vertexBuilder); - } -#endif + builder.fsCodeAppendf("\t%s = %s;\n", builder.getColorOutputName(), fragColor.c_str()); - /////////////////////////////////////////////////////////////////////////// - // compile and setup attribs and unis - - if (!this->compileShaders(builder)) { - return false; - } - - if (!this->bindOutputsAttribsAndLinkProgram(builder, - isColorDeclared, - dualSourceOutputWritten)) { + if (!builder.finish(&fProgramID)) { return false; } - builder.finished(fProgramID); fUniformHandles.fRTHeightUni = builder.getRTHeightUniform(); fUniformHandles.fDstCopyTopLeftUni = builder.getDstCopyTopLeftUniform(); fUniformHandles.fDstCopyScaleUni = builder.getDstCopyScaleUniform(); + fUniformHandles.fColorUni = builder.getColorUniform(); + fUniformHandles.fCoverageUni = builder.getCoverageUniform(); fUniformHandles.fDstCopySamplerUni = builder.getDstCopySamplerUniform(); // This must be called after we set fDstCopySamplerUni above. this->initSamplerUniforms(); @@ -689,82 +409,6 @@ bool GrGLProgram::genProgram(const GrEffectStage* colorStages[], return true; } -bool GrGLProgram::bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder, - bool bindColorOut, - bool bindDualSrcOut) { - GL_CALL_RET(fProgramID, CreateProgram()); - if (!fProgramID) { - return false; - } - - if (fVShaderID) { - GL_CALL(AttachShader(fProgramID, fVShaderID)); - } - if (fGShaderID) { - GL_CALL(AttachShader(fProgramID, fGShaderID)); - } - GL_CALL(AttachShader(fProgramID, fFShaderID)); - - if (bindColorOut) { - GL_CALL(BindFragDataLocation(fProgramID, 0, declared_color_output_name())); - } - if (bindDualSrcOut) { - GL_CALL(BindFragDataLocationIndexed(fProgramID, 0, 1, dual_source_output_name())); - } - - const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); - - // Bind the attrib locations to same values for all shaders - if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) { - GL_CALL(BindAttribLocation(fProgramID, - header.fPositionAttributeIndex, - vertexBuilder->positionAttribute().c_str())); - if (-1 != header.fLocalCoordAttributeIndex) { - GL_CALL(BindAttribLocation(fProgramID, - header.fLocalCoordAttributeIndex, - vertexBuilder->localCoordsAttribute().c_str())); - } - if (-1 != header.fColorAttributeIndex) { - GL_CALL(BindAttribLocation(fProgramID, header.fColorAttributeIndex, COL_ATTR_NAME)); - } - if (-1 != header.fCoverageAttributeIndex) { - GL_CALL(BindAttribLocation(fProgramID, header.fCoverageAttributeIndex, COV_ATTR_NAME)); - } - - const GrGLShaderBuilder::VertexBuilder::AttributePair* attribEnd = vertexBuilder->getEffectAttributes().end(); - for (const GrGLShaderBuilder::VertexBuilder::AttributePair* attrib = vertexBuilder->getEffectAttributes().begin(); - attrib != attribEnd; - ++attrib) { - GL_CALL(BindAttribLocation(fProgramID, attrib->fIndex, attrib->fName.c_str())); - } - } - - GL_CALL(LinkProgram(fProgramID)); - - GrGLint linked = GR_GL_INIT_ZERO; - GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked)); - if (!linked) { - GrGLint infoLen = GR_GL_INIT_ZERO; - GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen)); - SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger - if (infoLen > 0) { - // retrieve length even though we don't need it to workaround - // bug in chrome cmd buffer param validation. - GrGLsizei length = GR_GL_INIT_ZERO; - GL_CALL(GetProgramInfoLog(fProgramID, - infoLen+1, - &length, - (char*)log.get())); - GrPrintf((char*)log.get()); - } - SkDEBUGFAIL("Error linking program"); - GL_CALL(DeleteProgram(fProgramID)); - fProgramID = 0; - return false; - } - return true; -} - void GrGLProgram::initSamplerUniforms() { GL_CALL(UseProgram(fProgramID)); GrGLint texUnitIdx = 0; diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h index 09f7668be2..0304acf2c7 100644 --- a/src/gpu/gl/GrGLProgram.h +++ b/src/gpu/gl/GrGLProgram.h @@ -172,25 +172,10 @@ private: */ bool genProgram(const GrEffectStage* colorStages[], const GrEffectStage* coverageStages[]); - GrSLConstantVec genInputColor(GrGLShaderBuilder* builder, SkString* inColor); - - GrSLConstantVec genInputCoverage(GrGLShaderBuilder* builder, SkString* inCoverage); - - void genGeometryShader(GrGLShaderBuilder::VertexBuilder* vertexBuilder) const; - - // Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program - bool bindOutputsAttribsAndLinkProgram(const GrGLShaderBuilder& builder, - bool bindColorOut, - bool bindDualSrcOut); - // Sets the texture units for samplers void initSamplerUniforms(); void initEffectSamplerUniforms(EffectAndSamplers* effect, int* texUnitIdx); - bool compileShaders(const GrGLShaderBuilder& builder); - - const char* adjustInColor(const SkString& inColor) const; - // Helper for setData(). void setEffectData(const GrEffectStage& stage, const EffectAndSamplers& effect); @@ -205,10 +190,7 @@ private: // Helper for setData() that sets the view matrix and loads the render target height uniform void setMatrixAndRenderTargetHeight(const GrDrawState&); - // GL IDs - GrGLuint fVShaderID; - GrGLuint fGShaderID; - GrGLuint fFShaderID; + // GL program ID GrGLuint fProgramID; // these reflect the current values of uniforms (GL uniform values travel with program) diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp index 29596827da..f48f038546 100644 --- a/src/gpu/gl/GrGLSL.cpp +++ b/src/gpu/gl/GrGLSL.cpp @@ -63,14 +63,6 @@ const char* GrGetGLSLVersionDecl(const GrGLContextInfo& info) { } } -bool GrGLSLSetupFSColorOuput(GrGLSLGeneration gen, const char* nameIfDeclared, GrGLShaderVar* var) { - bool declaredOutput = k110_GrGLSLGeneration != gen; - var->set(kVec4f_GrSLType, - GrGLShaderVar::kOut_TypeModifier, - declaredOutput ? nameIfDeclared : "gl_FragColor"); - return declaredOutput; -} - const char* GrGLSLVectorHomogCoord(int count) { static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"}; SkASSERT(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS)); diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h index a54bd3b3d7..b97e709aca 100644 --- a/src/gpu/gl/GrGLSL.h +++ b/src/gpu/gl/GrGLSL.h @@ -87,24 +87,6 @@ GrGLSLGeneration GrGetGLSLGeneration(GrGLBinding binding, const char* GrGetGLSLVersionDecl(const GrGLContextInfo&); /** - * Depending on the GLSL version being emitted there may be an assumed output - * variable from the fragment shader for the color. Otherwise, the shader must - * declare an output variable for the color. If this function returns true: - * * Parameter var's name will be set to nameIfDeclared - * * The variable must be declared in the fragment shader - * * The variable has to be bound as the color output - * (using glBindFragDataLocation) - * If the function returns false: - * * Parameter var's name will be set to the GLSL built-in color output name. - * * Do not declare the variable in the shader. - * * Do not use glBindFragDataLocation to bind the variable - * In either case var is initialized to represent the color output in the - * shader. - */ -bool GrGLSLSetupFSColorOuput(GrGLSLGeneration gen, - const char* nameIfDeclared, - GrGLShaderVar* var); -/** * Converts a GrSLType to a string containing the name of the equivalent GLSL type. */ static const char* GrGLSLTypeString(GrSLType t) { diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp index d11394a7b3..f4ffb4dd2c 100644 --- a/src/gpu/gl/GrGLShaderBuilder.cpp +++ b/src/gpu/gl/GrGLShaderBuilder.cpp @@ -9,7 +9,13 @@ #include "gl/GrGLProgram.h" #include "gl/GrGLUniformHandle.h" #include "GrDrawEffect.h" +#include "GrGpuGL.h" #include "GrTexture.h" +#include "SkRTConf.h" +#include "SkTrace.h" + +#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) +#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X) // number of each input/output type in a single allocation block static const int kVarsPerBlock = 8; @@ -21,10 +27,18 @@ static const int kMaxFSOutputs = 2; static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision; typedef GrGLUniformManager::UniformHandle UniformHandle; + +SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false, + "Print the source code for all shaders generated."); + /////////////////////////////////////////////////////////////////////////////// namespace { +inline const char* color_attribute_name() { return "aColor"; } +inline const char* coverage_attribute_name() { return "aCoverage"; } +inline const char* declared_color_output_name() { return "fsColorOut"; } +inline const char* dual_source_output_name() { return "dualSourceOut"; } inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) { if (kVec2f_GrSLType == type) { return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D"; @@ -91,28 +105,32 @@ static const char kDstCopyColorName[] = "_dstColor"; /////////////////////////////////////////////////////////////////////////////// -GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo, +GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu, GrGLUniformManager& uniformManager, const GrGLProgramDesc& desc, bool needsVertexShader) : fUniforms(kVarsPerBlock) - , fCtxInfo(ctxInfo) + , fGpu(gpu) , fUniformManager(uniformManager) , fFSFeaturesAddedMask(0) , fFSInputs(kVarsPerBlock) , fFSOutputs(kMaxFSOutputs) , fSetupFragPosition(false) + , fKnownColorValue(kNone_GrSLConstantVec) + , fKnownCoverageValue(kNone_GrSLConstantVec) + , fHasCustomColorOutput(false) + , fHasSecondaryOutput(false) , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) { const GrGLProgramDesc::KeyHeader& header = desc.getHeader(); if (needsVertexShader) { - fVertexBuilder.reset(SkNEW_ARGS(VertexBuilder, (this, desc))); + fVertexBuilder.reset(SkNEW_ARGS(VertexBuilder, (this, fGpu, desc))); } // Emit code to read the dst copy textue if necessary. if (kNoDstRead_DstReadKey != header.fDstReadKey && - GrGLCaps::kNone_FBFetchType == ctxInfo.caps()->fbFetchType()) { + GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) { bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey); const char* dstCopyTopLeftName; const char* dstCopyCoordScaleName; @@ -143,15 +161,76 @@ GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo, this->fsAppendTextureLookup(fDstCopySampler, "_dstTexCoord"); this->fsCodeAppend(";\n\n"); } + + switch (header.fColorInput) { + case GrGLProgramDesc::kAttribute_ColorInput: { + SkASSERT(NULL != fVertexBuilder.get()); + fVertexBuilder->addAttribute(kVec4f_GrSLType, color_attribute_name()); + const char *vsName, *fsName; + fVertexBuilder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName); + fVertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name()); + fInputColor = fsName; + break; + } + case GrGLProgramDesc::kUniform_ColorInput: { + const char* name; + fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, "Color", &name); + fInputColor = name; + break; + } + case GrGLProgramDesc::kTransBlack_ColorInput: + fKnownColorValue = kZeros_GrSLConstantVec; + break; + case GrGLProgramDesc::kSolidWhite_ColorInput: + fKnownColorValue = kOnes_GrSLConstantVec; + break; + default: + GrCrash("Unknown color type."); + } + + switch (header.fCoverageInput) { + case GrGLProgramDesc::kAttribute_ColorInput: { + SkASSERT(NULL != fVertexBuilder.get()); + fVertexBuilder->addAttribute(kVec4f_GrSLType, coverage_attribute_name()); + const char *vsName, *fsName; + fVertexBuilder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName); + fVertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name()); + fInputCoverage = fsName; + break; + } + case GrGLProgramDesc::kUniform_ColorInput: { + const char* name; + fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec4f_GrSLType, "Coverage", &name); + fInputCoverage = name; + break; + } + case GrGLProgramDesc::kTransBlack_ColorInput: + fKnownCoverageValue = kZeros_GrSLConstantVec; + break; + case GrGLProgramDesc::kSolidWhite_ColorInput: + fKnownCoverageValue = kOnes_GrSLConstantVec; + break; + default: + GrCrash("Unknown coverage type."); + } + + if (k110_GrGLSLGeneration != fGpu->glslGeneration()) { + fFSOutputs.push_back().set(kVec4f_GrSLType, + GrGLShaderVar::kOut_TypeModifier, + declared_color_output_name()); + fHasCustomColorOutput = true; + } } bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) { switch (feature) { case kStandardDerivatives_GLSLFeature: - if (!fCtxInfo.caps()->shaderDerivativeSupport()) { + if (!fGpu->glCaps().shaderDerivativeSupport()) { return false; } - if (kES_GrGLBinding == fCtxInfo.binding()) { + if (kES_GrGLBinding == fGpu->glBinding()) { this->addFSFeature(1 << kStandardDerivatives_GLSLFeature, "GL_OES_standard_derivatives"); } @@ -165,23 +244,23 @@ bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) { bool GrGLShaderBuilder::enablePrivateFeature(GLSLPrivateFeature feature) { switch (feature) { case kFragCoordConventions_GLSLPrivateFeature: - if (!fCtxInfo.caps()->fragCoordConventionsSupport()) { + if (!fGpu->glCaps().fragCoordConventionsSupport()) { return false; } - if (fCtxInfo.glslGeneration() < k150_GrGLSLGeneration) { + if (fGpu->glslGeneration() < k150_GrGLSLGeneration) { this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature, "GL_ARB_fragment_coord_conventions"); } return true; case kEXTShaderFramebufferFetch_GLSLPrivateFeature: - if (GrGLCaps::kEXT_FBFetchType != fCtxInfo.caps()->fbFetchType()) { + if (GrGLCaps::kEXT_FBFetchType != fGpu->glCaps().fbFetchType()) { return false; } this->addFSFeature(1 << kEXTShaderFramebufferFetch_GLSLPrivateFeature, "GL_EXT_shader_framebuffer_fetch"); return true; case kNVShaderFramebufferFetch_GLSLPrivateFeature: - if (GrGLCaps::kNV_FBFetchType != fCtxInfo.caps()->fbFetchType()) { + if (GrGLCaps::kNV_FBFetchType != fGpu->glCaps().fbFetchType()) { return false; } this->addFSFeature(1 << kNVShaderFramebufferFetch_GLSLPrivateFeature, @@ -225,7 +304,7 @@ const char* GrGLShaderBuilder::dstColor() { } } static const char kFBFetchColorName[] = "gl_LastFragData[0]"; - GrGLCaps::FBFetchType fetchType = fCtxInfo.caps()->fbFetchType(); + GrGLCaps::FBFetchType fetchType = fGpu->glCaps().fbFetchType(); if (GrGLCaps::kEXT_FBFetchType == fetchType) { SkAssertResult(this->enablePrivateFeature(kEXTShaderFramebufferFetch_GLSLPrivateFeature)); return kFBFetchColorName; @@ -246,10 +325,10 @@ void GrGLShaderBuilder::appendTextureLookup(SkString* out, SkASSERT(NULL != coordName); out->appendf("%s(%s, %s)", - sample_function_name(varyingType, fCtxInfo.glslGeneration()), + sample_function_name(varyingType, fGpu->glslGeneration()), this->getUniformCStr(sampler.fSamplerUniform), coordName); - append_swizzle(out, sampler, *fCtxInfo.caps()); + append_swizzle(out, sampler, fGpu->glCaps()); } void GrGLShaderBuilder::fsAppendTextureLookup(const GrGLShaderBuilder::TextureSampler& sampler, @@ -379,7 +458,7 @@ const char* GrGLShaderBuilder::fragmentPosition() { fSetupFragPosition = true; } return "gl_FragCoord"; - } else if (fCtxInfo.caps()->fragCoordConventionsSupport()) { + } else if (fGpu->glCaps().fragCoordConventionsSupport()) { if (!fSetupFragPosition) { SkAssertResult(this->enablePrivateFeature(kFragCoordConventions_GLSLPrivateFeature)); fFSInputs.push_back().set(kVec4f_GrSLType, @@ -425,7 +504,7 @@ void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType, fFSFunctions.appendf(" %s", outName->c_str()); fFSFunctions.append("("); for (int i = 0; i < argCnt; ++i) { - args[i].appendDecl(fCtxInfo, &fFSFunctions); + args[i].appendDecl(this->ctxInfo(), &fFSFunctions); if (i < argCnt - 1) { fFSFunctions.append(", "); } @@ -463,7 +542,7 @@ inline void append_default_precision_qualifier(GrGLShaderVar::Precision p, void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const { for (int i = 0; i < vars.count(); ++i) { - vars[i].appendDecl(fCtxInfo, out); + vars[i].appendDecl(this->ctxInfo(), out); out->append(";\n"); } } @@ -472,33 +551,12 @@ void GrGLShaderBuilder::appendUniformDecls(ShaderVisibility visibility, SkString* out) const { for (int i = 0; i < fUniforms.count(); ++i) { if (fUniforms[i].fVisibility & visibility) { - fUniforms[i].fVariable.appendDecl(fCtxInfo, out); + fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out); out->append(";\n"); } } } -void GrGLShaderBuilder::fsGetShader(SkString* shaderStr) const { - *shaderStr = GrGetGLSLVersionDecl(fCtxInfo); - shaderStr->append(fFSExtensions); - append_default_precision_qualifier(kDefaultFragmentPrecision, - fCtxInfo.binding(), - shaderStr); - this->appendUniformDecls(kFragment_Visibility, shaderStr); - this->appendDecls(fFSInputs, shaderStr); - // We shouldn't have declared outputs on 1.10 - SkASSERT(k110_GrGLSLGeneration != fCtxInfo.glslGeneration() || fFSOutputs.empty()); - this->appendDecls(fFSOutputs, shaderStr); - shaderStr->append(fFSFunctions); - shaderStr->append("void main() {\n"); - shaderStr->append(fFSCode); - shaderStr->append("}\n"); -} - -void GrGLShaderBuilder::finished(GrGLuint programID) { - fUniformManager.getUniformLocations(programID, fUniforms); -} - void GrGLShaderBuilder::emitEffects( const GrEffectStage* effectStages[], const GrBackendEffectFactory::EffectKey effectKeys[], @@ -526,7 +584,7 @@ void GrGLShaderBuilder::emitEffects( textureSamplers[t].init(this, &effect->textureAccess(t), t); effectSamplerHandles[e]->push_back(textureSamplers[t].fSamplerUniform); } - GrDrawEffect drawEffect(stage, fVertexBuilder.get() + GrDrawEffect drawEffect(stage, NULL != fVertexBuilder.get() && fVertexBuilder->hasExplicitLocalCoords()); int numAttributes = stage.getVertexAttribIndexCount(); @@ -534,7 +592,7 @@ void GrGLShaderBuilder::emitEffects( SkSTArray<GrEffect::kMaxVertexAttribs, SkString> attributeNames; for (int a = 0; a < numAttributes; ++a) { // TODO: Make addAttribute mangle the name. - SkASSERT(fVertexBuilder.get()); + SkASSERT(NULL != fVertexBuilder.get()); SkString attributeName("aAttr"); attributeName.appendS32(attributeIndices[a]); fVertexBuilder->addEffectAttribute(attributeIndices[a], @@ -557,7 +615,7 @@ void GrGLShaderBuilder::emitEffects( // Enclose custom code in a block to avoid namespace conflicts SkString openBrace; openBrace.printf("\t{ // Stage %d: %s\n", fCodeStage.stageIndex(), glEffects[e]->name()); - if (fVertexBuilder.get()) { + if (NULL != fVertexBuilder.get()) { fVertexBuilder->vsCodeAppend(openBrace.c_str()); } this->fsCodeAppend(openBrace.c_str()); @@ -569,7 +627,7 @@ void GrGLShaderBuilder::emitEffects( inColor.isEmpty() ? NULL : inColor.c_str(), textureSamplers); - if (fVertexBuilder.get()) { + if (NULL != fVertexBuilder.get()) { fVertexBuilder->vsCodeAppend("\t}\n"); } this->fsCodeAppend("\t}\n"); @@ -584,22 +642,170 @@ void GrGLShaderBuilder::emitEffects( } } +const char* GrGLShaderBuilder::getColorOutputName() const { + return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor"; +} + +const char* GrGLShaderBuilder::enableSecondaryOutput() { + if (!fHasSecondaryOutput) { + fFSOutputs.push_back().set(kVec4f_GrSLType, + GrGLShaderVar::kOut_TypeModifier, + dual_source_output_name()); + fHasSecondaryOutput = true; + } + return dual_source_output_name(); +} + + +bool GrGLShaderBuilder::finish(GrGLuint* outProgramId) { + SK_TRACE_EVENT0("GrGLShaderBuilder::finish"); + + GrGLuint programId = 0; + GL_CALL_RET(programId, CreateProgram()); + if (!programId) { + return false; + } + + if (!this->compileAndAttachShaders(programId)) { + GL_CALL(DeleteProgram(programId)); + return false; + } + + this->bindProgramLocations(programId); + + GL_CALL(LinkProgram(programId)); + GrGLint linked = GR_GL_INIT_ZERO; + GL_CALL(GetProgramiv(programId, GR_GL_LINK_STATUS, &linked)); + if (!linked) { + GrGLint infoLen = GR_GL_INIT_ZERO; + GL_CALL(GetProgramiv(programId, GR_GL_INFO_LOG_LENGTH, &infoLen)); + SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger + if (infoLen > 0) { + // retrieve length even though we don't need it to workaround + // bug in chrome cmd buffer param validation. + GrGLsizei length = GR_GL_INIT_ZERO; + GL_CALL(GetProgramInfoLog(programId, + infoLen+1, + &length, + (char*)log.get())); + GrPrintf((char*)log.get()); + } + SkDEBUGFAIL("Error linking program"); + GL_CALL(DeleteProgram(programId)); + return false; + } + + fUniformManager.getUniformLocations(programId, fUniforms); + *outProgramId = programId; + return true; +} + +namespace { +// Compiles a GL shader, attaches it to a program, and releases the shader's reference. +// (That way there's no need to hang on to the GL shader id and delete it later.) +bool attach_shader(const GrGLInterface* gli, + GrGLuint programId, + GrGLenum type, + const SkString& shaderSrc) { + GrGLuint shaderId; + GR_GL_CALL_RET(gli, shaderId, CreateShader(type)); + if (0 == shaderId) { + return false; + } + + const GrGLchar* sourceStr = shaderSrc.c_str(); + int sourceLength = shaderSrc.size(); + GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength)); + + GrGLint compiled = GR_GL_INIT_ZERO; + GR_GL_CALL(gli, CompileShader(shaderId)); + GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled)); + + if (!compiled) { + GrGLint infoLen = GR_GL_INIT_ZERO; + GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen)); + SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger + if (infoLen > 0) { + // retrieve length even though we don't need it to workaround bug in chrome cmd buffer + // param validation. + GrGLsizei length = GR_GL_INIT_ZERO; + GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, + &length, (char*)log.get())); + GrPrintf(shaderSrc.c_str()); + GrPrintf("\n%s", log.get()); + } + SkDEBUGFAIL("Shader compilation failed!"); + GR_GL_CALL(gli, DeleteShader(shaderId)); + return false; + } else if (c_PrintShaders) { + GrPrintf(shaderSrc.c_str()); + GrPrintf("\n"); + } + + GR_GL_CALL(gli, AttachShader(programId, shaderId)); + GR_GL_CALL(gli, DeleteShader(shaderId)); + return true; +} + +} + +bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId) const { + if (NULL != fVertexBuilder.get() && !fVertexBuilder->compileAndAttachShaders(programId)) { + return false; + } + + SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo())); + fragShaderSrc.append(fFSExtensions); + append_default_precision_qualifier(kDefaultFragmentPrecision, + fGpu->glBinding(), + &fragShaderSrc); + this->appendUniformDecls(kFragment_Visibility, &fragShaderSrc); + this->appendDecls(fFSInputs, &fragShaderSrc); + // We shouldn't have declared outputs on 1.10 + SkASSERT(k110_GrGLSLGeneration != fGpu->glslGeneration() || fFSOutputs.empty()); + this->appendDecls(fFSOutputs, &fragShaderSrc); + fragShaderSrc.append(fFSFunctions); + fragShaderSrc.append("void main() {\n"); + fragShaderSrc.append(fFSCode); + fragShaderSrc.append("}\n"); + if (!attach_shader(fGpu->glInterface(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc)) { + return false; + } + + return true; +} + +void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) const { + if (NULL != fVertexBuilder.get()) { + fVertexBuilder->bindProgramLocations(programId); + } + + if (fHasCustomColorOutput) { + GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name())); + } + if (fHasSecondaryOutput) { + GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_name())); + } +} + +const GrGLContextInfo& GrGLShaderBuilder::ctxInfo() const { + return fGpu->ctxInfo(); +} + //////////////////////////////////////////////////////////////////////////// GrGLShaderBuilder::VertexBuilder::VertexBuilder(GrGLShaderBuilder* parent, + GrGpuGL* gpu, const GrGLProgramDesc& desc) - : fVSAttrs(kVarsPerBlock) + : fParent(parent) + , fGpu(gpu) + , fDesc(desc) + , fVSAttrs(kVarsPerBlock) , fVSOutputs(kVarsPerBlock) , fGSInputs(kVarsPerBlock) - , fGSOutputs(kVarsPerBlock) - , fParent(parent) -#if GR_GL_EXPERIMENTAL_GS - , fUsesGS(SkToBool(desc.getHeader().fExperimentalGS)) -#else - , fUsesGS(false) -#endif -{ - const GrGLProgramDesc::KeyHeader& header = desc.getHeader(); + , fGSOutputs(kVarsPerBlock) { + + const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); fPositionVar = &fVSAttrs.push_back(); fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition"); @@ -611,6 +817,23 @@ GrGLShaderBuilder::VertexBuilder::VertexBuilder(GrGLShaderBuilder* parent, } else { fLocalCoordsVar = fPositionVar; } + + const char* viewMName; + fViewMatrixUniform = fParent->addUniform(GrGLShaderBuilder::kVertex_Visibility, + kMat33f_GrSLType, "ViewM", &viewMName); + + this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n" + "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n", + viewMName, fPositionVar->c_str()); + + // we output point size in the GS if present + if (header.fEmitsPointSize +#if GR_GL_EXPERIMENTAL_GS + && !header.fExperimentalGS +#endif + ) { + this->vsCodeAppend("\tgl_PointSize = 1.0;\n"); + } } bool GrGLShaderBuilder::VertexBuilder::addAttribute(GrSLType type, @@ -654,7 +877,8 @@ void GrGLShaderBuilder::VertexBuilder::addVarying(GrSLType type, } // input to FS comes either from VS or GS const SkString* fsName; - if (fUsesGS) { +#if GR_GL_EXPERIMENTAL_GS + if (fDesc.getHeader().fExperimentalGS) { // if we have a GS take each varying in as an array // and output as non-array. fGSInputs.push_back(); @@ -667,7 +891,9 @@ void GrGLShaderBuilder::VertexBuilder::addVarying(GrSLType type, fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier); fParent->nameVariable(fGSOutputs.back().accessName(), 'g', name); fsName = fGSOutputs.back().accessName(); - } else { + } else +#endif + { fsName = fVSOutputs.back().accessName(); } fParent->fsInputAppend().set(type, @@ -678,41 +904,88 @@ void GrGLShaderBuilder::VertexBuilder::addVarying(GrSLType type, } } -void GrGLShaderBuilder::VertexBuilder::vsGetShader(SkString* shaderStr) const { - *shaderStr = GrGetGLSLVersionDecl(fParent->ctxInfo()); - fParent->appendUniformDecls(kVertex_Visibility, shaderStr); - fParent->appendDecls(fVSAttrs, shaderStr); - fParent->appendDecls(fVSOutputs, shaderStr); - shaderStr->append("void main() {\n"); - shaderStr->append(fVSCode); - shaderStr->append("}\n"); +const SkString* GrGLShaderBuilder::VertexBuilder::getEffectAttributeName(int attributeIndex) const { + const AttributePair* attribEnd = fEffectAttributes.end(); + for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { + if (attrib->fIndex == attributeIndex) { + return &attrib->fName; + } + } + + return NULL; } -void GrGLShaderBuilder::VertexBuilder::gsGetShader(SkString* shaderStr) const { - if (!fUsesGS) { - shaderStr->reset(); - return; +bool GrGLShaderBuilder::VertexBuilder::compileAndAttachShaders(GrGLuint programId) const { + SkString vertShaderSrc(GrGetGLSLVersionDecl(fParent->ctxInfo())); + fParent->appendUniformDecls(kVertex_Visibility, &vertShaderSrc); + fParent->appendDecls(fVSAttrs, &vertShaderSrc); + fParent->appendDecls(fVSOutputs, &vertShaderSrc); + vertShaderSrc.append("void main() {\n"); + vertShaderSrc.append(fVSCode); + vertShaderSrc.append("}\n"); + if (!attach_shader(fGpu->glInterface(), programId, GR_GL_VERTEX_SHADER, vertShaderSrc)) { + return false; } - *shaderStr = GrGetGLSLVersionDecl(fParent->ctxInfo()); - shaderStr->append(fGSHeader); - fParent->appendDecls(fGSInputs, shaderStr); - fParent->appendDecls(fGSOutputs, shaderStr); - shaderStr->append("void main() {\n"); - shaderStr->append(fGSCode); - shaderStr->append("}\n"); +#if GR_GL_EXPERIMENTAL_GS + if (fDesc.getHeader().fExperimentalGS) { + SkASSERT(fGpu->glslGeneration() >= k150_GrGLSLGeneration); + SkString geomShaderSrc(GrGetGLSLVersionDecl(fParent->ctxInfo())); + geomShaderSrc.append("layout(triangles) in;\n" + "layout(triangle_strip, max_vertices = 6) out;\n"); + fParent->appendDecls(fGSInputs, &geomShaderSrc); + fParent->appendDecls(fGSOutputs, &geomShaderSrc); + geomShaderSrc.append("void main() {\n"); + geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n" + "\t\tgl_Position = gl_in[i].gl_Position;\n"); + if (fDesc.getHeader().fEmitsPointSize) { + geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n"); + } + SkASSERT(fGSInputs.count() == fGSOutputs.count()); + for (int i = 0; i < fGSInputs.count(); ++i) { + geomShaderSrc.appendf("\t\t%s = %s[i];\n", + fGSOutputs[i].getName().c_str(), + fGSInputs[i].getName().c_str()); + } + geomShaderSrc.append("\t\tEmitVertex();\n" + "\t}\n" + "\tEndPrimitive();\n"); + geomShaderSrc.append("}\n"); + if (!attach_shader(fGpu->glInterface(), programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc)) { + return false; + } + } +#endif + + return true; } +void GrGLShaderBuilder::VertexBuilder::bindProgramLocations(GrGLuint programId) const { + const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader(); -const SkString* GrGLShaderBuilder::VertexBuilder::getEffectAttributeName(int attributeIndex) const { - const AttributePair* attribEnd = this->getEffectAttributes().end(); - for (const AttributePair* attrib = this->getEffectAttributes().begin(); - attrib != attribEnd; - ++attrib) { - if (attrib->fIndex == attributeIndex) { - return &attrib->fName; - } + // Bind the attrib locations to same values for all shaders + SkASSERT(-1 != header.fPositionAttributeIndex); + GL_CALL(BindAttribLocation(programId, + header.fPositionAttributeIndex, + fPositionVar->c_str())); + if (-1 != header.fLocalCoordAttributeIndex) { + GL_CALL(BindAttribLocation(programId, + header.fLocalCoordAttributeIndex, + fLocalCoordsVar->c_str())); + } + if (-1 != header.fColorAttributeIndex) { + GL_CALL(BindAttribLocation(programId, + header.fColorAttributeIndex, + color_attribute_name())); + } + if (-1 != header.fCoverageAttributeIndex) { + GL_CALL(BindAttribLocation(programId, + header.fCoverageAttributeIndex, + coverage_attribute_name())); } - return NULL; + const AttributePair* attribEnd = fEffectAttributes.end(); + for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) { + GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str())); + } } diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h index 3c3275ce36..d73a731a7c 100644 --- a/src/gpu/gl/GrGLShaderBuilder.h +++ b/src/gpu/gl/GrGLShaderBuilder.h @@ -105,7 +105,7 @@ public: kFragment_Visibility = 0x4, }; - GrGLShaderBuilder(const GrGLContextInfo&, + GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&, bool needsVertexShader); @@ -171,9 +171,6 @@ public: /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */ GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); } - GrGLShaderVar& fsOutputAppend() { return fFSOutputs.push_back(); } - GrGLShaderVar& fsInputAppend(const GrGLShaderVar& var) { return fFSInputs.push_back(var); } - GrGLShaderVar& fsOutputAppend(const GrGLShaderVar& var) { return fFSOutputs.push_back(var); } /** Generates a EffectKey for the shader code based on the texture access parameters and the capabilities of the GL context. This is useful for keying the shader programs that may @@ -238,13 +235,13 @@ public: /** * Interfaces used by GrGLProgram. - * TODO: Hide these from the GrEffects using friend or splitting this into two related classes. - * Also, GrGLProgram's shader string construction should be moved to this class. + * TODO: These are used by GrGLProgram to insert a mode color filter. Remove these when the + * color filter is expressed as a GrEffect. */ - - /** Called after building is complete to get the final shader string. To acces the vertex - and geometry shaders, use the VertexBuilder. */ - void fsGetShader(SkString*) const; + const SkString& getInputColor() const { return fInputColor; } + GrSLConstantVec getKnownColorValue() const { return fKnownColorValue; } + const SkString& getInputCoverage() const { return fInputCoverage; } + GrSLConstantVec getKnownCoverageValue() const { return fKnownCoverageValue; } /** * Adds code for effects. effectStages contains the effects to add. effectKeys[i] is the key @@ -265,6 +262,9 @@ public: SkTArray<GrGLUniformManager::UniformHandle, true>* effectSamplerHandles[], GrGLEffect* glEffects[]); + const char* getColorOutputName() const; + const char* enableSecondaryOutput(); + GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; } GrGLUniformManager::UniformHandle getDstCopyTopLeftUniform() const { return fDstCopyTopLeftUniform; @@ -272,6 +272,8 @@ public: GrGLUniformManager::UniformHandle getDstCopyScaleUniform() const { return fDstCopyScaleUniform; } + GrGLUniformManager::UniformHandle getColorUniform() const { return fColorUniform; } + GrGLUniformManager::UniformHandle getCoverageUniform() const { return fCoverageUniform; } GrGLUniformManager::UniformHandle getDstCopySamplerUniform() const { return fDstCopySampler.fSamplerUniform; } @@ -281,7 +283,7 @@ public: that only use the fragment shader. */ class VertexBuilder { public: - VertexBuilder(GrGLShaderBuilder* parent, const GrGLProgramDesc&); + VertexBuilder(GrGLShaderBuilder* parent, GrGpuGL* gpu, const GrGLProgramDesc&); /** * Called by GrGLEffects to add code to one of the shaders. @@ -293,15 +295,7 @@ public: va_end(args); } - void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) { - va_list args; - va_start(args, format); - fGSCode.appendf(format, args); - va_end(args); - } - void vsCodeAppend(const char* str) { fVSCode.append(str); } - void gsCodeAppend(const char* str) { fGSCode.append(str); } /** Add a vertex attribute to the current program that is passed in from the vertex data. Returns false if the attribute was already there, true otherwise. */ @@ -330,42 +324,38 @@ public: */ bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); } - /** Called after building is complete to get the final shader string. */ - void vsGetShader(SkString*) const; - void gsGetShader(SkString*) const; - - struct AttributePair { - void set(int index, const SkString& name) { - fIndex = index; fName = name; - } - int fIndex; - SkString fName; - }; - const SkTArray<AttributePair, true>& getEffectAttributes() const { - return fEffectAttributes; - } bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name); const SkString* getEffectAttributeName(int attributeIndex) const; - // TODO: Everything below here private. - public: + GrGLUniformManager::UniformHandle getViewMatrixUniform() const { + return fViewMatrixUniform; + } - VarArray fVSAttrs; - VarArray fVSOutputs; - VarArray fGSInputs; - VarArray fGSOutputs; - SkString fGSHeader; // layout qualifiers specific to GS + bool compileAndAttachShaders(GrGLuint programId) const; + void bindProgramLocations(GrGLuint programId) const; private: GrGLShaderBuilder* fParent; - - bool fUsesGS; + GrGpuGL* fGpu; + const GrGLProgramDesc& fDesc; + VarArray fVSAttrs; + VarArray fVSOutputs; + VarArray fGSInputs; + VarArray fGSOutputs; SkString fVSCode; - SkString fGSCode; + struct AttributePair { + void set(int index, const SkString& name) { + fIndex = index; fName = name; + } + int fIndex; + SkString fName; + }; SkSTArray<10, AttributePair, true> fEffectAttributes; + GrGLUniformManager::UniformHandle fViewMatrixUniform; + GrGLShaderVar* fPositionVar; GrGLShaderVar* fLocalCoordsVar; }; @@ -374,15 +364,17 @@ public: It may be NULL if this shader program is only meant to have a fragment shader. */ VertexBuilder* getVertexBuilder() const { return fVertexBuilder.get(); } - // TODO: Make this do all the compiling, linking, etc. - void finished(GrGLuint programID); + bool finish(GrGLuint* outProgramId); - const GrGLContextInfo& ctxInfo() const { return fCtxInfo; } + const GrGLContextInfo& ctxInfo() const; private: void appendDecls(const VarArray&, SkString*) const; void appendUniformDecls(ShaderVisibility, SkString*) const; + bool compileAndAttachShaders(GrGLuint programId) const; + void bindProgramLocations(GrGLuint programId) const; + typedef GrGLUniformManager::BuilderUniform BuilderUniform; GrGLUniformManager::BuilderUniformArray fUniforms; @@ -471,7 +463,7 @@ private: kBottomLeftFragPosRead_FragPosKey = 0x2,// Read frag pos relative to bottom-left. }; - const GrGLContextInfo& fCtxInfo; + GrGpuGL* fGpu; GrGLUniformManager& fUniformManager; uint32_t fFSFeaturesAddedMask; SkString fFSFunctions; @@ -484,13 +476,23 @@ private: bool fSetupFragPosition; TextureSampler fDstCopySampler; + SkString fInputColor; + GrSLConstantVec fKnownColorValue; + SkString fInputCoverage; + GrSLConstantVec fKnownCoverageValue; + + bool fHasCustomColorOutput; + bool fHasSecondaryOutput; + GrGLUniformManager::UniformHandle fRTHeightUniform; GrGLUniformManager::UniformHandle fDstCopyTopLeftUniform; GrGLUniformManager::UniformHandle fDstCopyScaleUniform; + GrGLUniformManager::UniformHandle fColorUniform; + GrGLUniformManager::UniformHandle fCoverageUniform; bool fTopLeftFragPosRead; - SkAutoTDelete<VertexBuilder> fVertexBuilder; + SkAutoTDelete<VertexBuilder> fVertexBuilder; }; #endif |