diff options
author | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-16 20:56:06 +0000 |
---|---|---|
committer | bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-05-16 20:56:06 +0000 |
commit | f2d91557b2c353429e40aa0f87c523119002f41b (patch) | |
tree | 75ac4c31ac3cbf4af818072543811a1274e6625c | |
parent | 852fa0fafaad359f3feffae28747e17ccadc70c5 (diff) |
separate coverage stages from color stages.
Review URL: http://codereview.appspot.com/4538064/
git-svn-id: http://skia.googlecode.com/svn/trunk@1339 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gpu/include/GrDrawTarget.h | 31 | ||||
-rw-r--r-- | gpu/src/GrGLProgram.cpp | 392 | ||||
-rw-r--r-- | gpu/src/GrGLProgram.h | 1 | ||||
-rw-r--r-- | gpu/src/GrGpuGLShaders.cpp | 51 | ||||
-rw-r--r-- | include/core/SkXfermode.h | 10 |
5 files changed, 362 insertions, 123 deletions
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h index 93b381dd9f..5020e1659c 100644 --- a/gpu/include/GrDrawTarget.h +++ b/gpu/include/GrDrawTarget.h @@ -137,10 +137,16 @@ protected: // all DrState members should default to something // valid by the memset memset(this, 0, sizeof(DrState)); - // This is an exception to our memset, since it will - // result in no change. + + // memset exceptions fColorFilterXfermode = SkXfermode::kDstIn_Mode; + fFirstCoverageStage = kNumStages; + + // pedantic assertion that our ptrs will + // be NULL (0 ptr is mem addr 0) GrAssert((intptr_t)(void*)NULL == 0LL); + + // default stencil setting should be disabled GrAssert(fStencilSettings.isDisabled()); } uint32_t fFlagBits; @@ -150,6 +156,7 @@ protected: GrTexture* fTextures[kNumStages]; GrEffect* fEffects[kNumStages]; GrSamplerState fSamplerStates[kNumStages]; + int fFirstCoverageStage; GrRenderTarget* fRenderTarget; GrColor fColor; DrawFace fDrawFace; @@ -343,6 +350,26 @@ public: void setDrawFace(DrawFace face) { fCurrDrawState.fDrawFace = face; } /** + * A common pattern is to compute a color with the initial stages and then + * modulate that color by a coverage value in later stage(s) (AA, mask- + * filters, glyph mask, etc). Color-filters, xfermodes, etc should be + * computed based on the pre-coverage-modulated color. The division of + * stages between color-computing and coverage-computing is specified by + * this method. Initially this is kNumStages (all stages are color- + * computing). + */ + void setFirstCoverageStage(int firstCoverageStage) { + fCurrDrawState.fFirstCoverageStage = firstCoverageStage; + } + + /** + * Gets the index of the first coverage-computing stage. + */ + int getFirstCoverageStage() const { + return fCurrDrawState.fFirstCoverageStage; + } + + /** * Gets whether the target is drawing clockwise, counterclockwise, * or both faces. * @return the current draw face(s). diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp index ab327d0e7d..bd95f3cb8c 100644 --- a/gpu/src/GrGLProgram.cpp +++ b/gpu/src/GrGLProgram.cpp @@ -86,6 +86,20 @@ static inline const char* vector_all_coords(int count) { return ALL[count]; } +static inline const char* all_ones_vec(int count) { + static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)", + "vec3(1,1,1)", "vec4(1,1,1,1)"}; + GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC)); + return ONESVEC[count]; +} + +static inline const char* all_zeros_vec(int count) { + static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)", + "vec3(0,0,0)", "vec4(0,0,0,0)"}; + GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC)); + return ZEROSVEC[count]; +} + static void tex_matrix_name(int stage, GrStringBuilder* s) { #if GR_GL_ATTRIBUTE_MATRICES *s = "aTexM"; @@ -183,55 +197,157 @@ void GrGLProgram::doGLPost() const { } } +// assigns modulation of two vars to an output var +// if either var is "" then assign to the other var +// if both are "" then assign all ones +static inline void modulate_helper(const char* outputVar, + const char* var0, + const char* var1, + GrStringBuilder* code) { + GrAssert(NULL != outputVar); + GrAssert(NULL != var0); + GrAssert(NULL != var1); + GrAssert(NULL != code); + + bool has0 = '\0' != *var0; + bool has1 = '\0' != *var1; + + if (!has0 && !has1) { + code->appendf("\t%s = %s;\n", outputVar, all_ones_vec(4)); + } else if (!has0) { + code->appendf("\t%s = %s;\n", outputVar, var1); + } else if (!has1) { + code->appendf("\t%s = %s;\n", outputVar, var0); + } else { + code->appendf("\t%s = %s * %s;\n", outputVar, var0, var1); + } +} + +// assigns addition of two vars to an output var +// if either var is "" then assign to the other var +// if both are "" then assign all zeros +static inline void add_helper(const char* outputVar, + const char* var0, + const char* var1, + GrStringBuilder* code) { + GrAssert(NULL != outputVar); + GrAssert(NULL != var0); + GrAssert(NULL != var1); + GrAssert(NULL != code); + + bool has0 = '\0' != *var0; + bool has1 = '\0' != *var1; + + if (!has0 && !has1) { + code->appendf("\t%s = %s;\n", outputVar, all_zeros_vec(4)); + } else if (!has0) { + code->appendf("\t%s = %s;\n", outputVar, var1); + } else if (!has1) { + code->appendf("\t%s = %s;\n", outputVar, var0); + } else { + code->appendf("\t%s = %s + %s;\n", outputVar, var0, var1); + } +} + +// given two blend coeffecients determine whether the src +// and/or dst computation can be omitted. +static inline void needBlendInputs(SkXfermode::Coeff srcCoeff, + SkXfermode::Coeff dstCoeff, + bool* needSrcValue, + bool* needDstValue) { + if (SkXfermode::kZero_Coeff == srcCoeff) { + switch (dstCoeff) { + // these all read the src + case SkXfermode::kSC_Coeff: + case SkXfermode::kISC_Coeff: + case SkXfermode::kSA_Coeff: + case SkXfermode::kISA_Coeff: + *needSrcValue = true; + break; + default: + *needSrcValue = false; + break; + } + } else { + *needSrcValue = true; + } + if (SkXfermode::kZero_Coeff == dstCoeff) { + switch (srcCoeff) { + // these all read the dst + case SkXfermode::kDC_Coeff: + case SkXfermode::kIDC_Coeff: + case SkXfermode::kDA_Coeff: + case SkXfermode::kIDA_Coeff: + *needDstValue = true; + break; + default: + *needDstValue = false; + break; + } + } else { + *needDstValue = true; + } +} + /** - * Create a text coefficient to be used in fragment shader code. + * Create a blend_coeff * value string to be used in shader code. Sets empty + * string if result is trivially zero. */ -static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff, - const char* src, const char* dst) { +static void blendTermString(GrStringBuilder* str, SkXfermode::Coeff coeff, + const char* src, const char* dst, + const char* value) { + switch (coeff) { case SkXfermode::kZero_Coeff: /** 0 */ - *str = "0.0"; + *str = ""; break; case SkXfermode::kOne_Coeff: /** 1 */ - *str = "1.0"; + *str = value; + break; + case SkXfermode::kSC_Coeff: + str->printf("(%s * %s)", src, value); + break; + case SkXfermode::kISC_Coeff: + str->printf("((%s - %s) * %s)", all_ones_vec(4), src, value); + break; + case SkXfermode::kDC_Coeff: + str->printf("(%s * %s)", dst, value); + break; + case SkXfermode::kIDC_Coeff: + str->printf("((%s - %s) * %s)", all_ones_vec(4), dst, value); break; case SkXfermode::kSA_Coeff: /** src alpha */ - str->appendf("%s.a", src); + str->printf("(%s.a * %s)", src, value); break; case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */ - str->appendf("(1.0 - %s.a)", src); + str->printf("((1.0 - %s.a) * %s)", src, value); break; case SkXfermode::kDA_Coeff: /** dst alpha */ - str->appendf("%s.a", dst); + str->printf("(%s.a * %s)", dst, value); break; case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */ - str->appendf("(1.0 - %s.a)", dst); - break; - case SkXfermode::kSC_Coeff: - str->append(src); + str->printf("((1.0 - %s.a) * %s)", dst, value); break; default: + GrCrash("Unexpected xfer coeff."); break; } } - /** * Adds a line to the fragment shader code which modifies the color by * the specified color filter. */ -static void addColorFilter(GrStringBuilder* FSCode, const char * outputVar, - SkXfermode::Mode colorFilterXfermode, const char* dstColor) { - SkXfermode::Coeff srcCoeff, dstCoeff; - SkDEBUGCODE(bool success =) - SkXfermode::ModeAsCoeff(colorFilterXfermode, &srcCoeff, &dstCoeff); - // We currently do not handle modes that cannot be represented as - // coefficients. - GrAssert(success); - GrStringBuilder srcCoeffStr, dstCoeffStr; - coefficientString(&srcCoeffStr, srcCoeff, COL_FILTER_UNI_NAME, dstColor); - coefficientString(&dstCoeffStr, dstCoeff, COL_FILTER_UNI_NAME, dstColor); - FSCode->appendf("\t%s = %s*%s + %s*%s;\n", outputVar, srcCoeffStr.c_str(), - COL_FILTER_UNI_NAME, dstCoeffStr.c_str(), dstColor); +static void addColorFilter(GrStringBuilder* fsCode, const char * outputVar, + SkXfermode::Coeff uniformCoeff, + SkXfermode::Coeff colorCoeff, + const char* inColor) { + GrStringBuilder colorStr, constStr; + blendTermString(&colorStr, colorCoeff, COL_FILTER_UNI_NAME, + inColor, inColor); + blendTermString(&constStr, uniformCoeff, COL_FILTER_UNI_NAME, + inColor, COL_FILTER_UNI_NAME); + + add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode); } bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { @@ -241,6 +357,22 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { programData->fUniLocations.reset(); + SkXfermode::Coeff colorCoeff, uniformCoeff; + // The rest of transfer mode color filters have not been implemented + if (fProgramDesc.fColorFilterXfermode < SkXfermode::kCoeffModesCnt) { + GR_DEBUGCODE(bool success =) + SkXfermode::ModeAsCoeff(fProgramDesc.fColorFilterXfermode, &uniformCoeff, &colorCoeff); + GR_DEBUGASSERT(success); + } else { + colorCoeff = SkXfermode::kOne_Coeff; + uniformCoeff = SkXfermode::kZero_Coeff; + } + + bool needColorFilterUniform; + bool needComputedColor; + needBlendInputs(uniformCoeff, colorCoeff, + &needColorFilterUniform, &needComputedColor); + #if GR_GL_ATTRIBUTE_MATRICES segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n"; programData->fUniLocations.fViewMatrixUni = kSetAsAttribute; @@ -258,21 +390,23 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { // incoming color to current stage being processed. GrStringBuilder inColor; - switch (fProgramDesc.fColorType) { - case ProgramDesc::kAttribute_ColorType: - segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n"); - segments.fVaryings.append("varying vec4 vColor;\n"); - segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n"); - inColor = "vColor"; - break; - case ProgramDesc::kUniform_ColorType: - segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n"); - programData->fUniLocations.fColorUni = kUseUniform; - inColor = COL_UNI_NAME; - break; - case ProgramDesc::kNone_ColorType: - inColor = ""; - break; + if (needComputedColor) { + switch (fProgramDesc.fColorType) { + case ProgramDesc::kAttribute_ColorType: + segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n"); + segments.fVaryings.append("varying vec4 vColor;\n"); + segments.fVSCode.append( "\tvColor = " COL_ATTR_NAME ";\n"); + inColor = "vColor"; + break; + case ProgramDesc::kUniform_ColorType: + segments.fFSUnis.append( "uniform vec4 " COL_UNI_NAME ";\n"); + programData->fUniLocations.fColorUni = kUseUniform; + inColor = COL_UNI_NAME; + break; + default: + GrAssert(ProgramDesc::kNone_ColorType == fProgramDesc.fColorType); + break; + } } if (fProgramDesc.fUsesEdgeAA) { @@ -294,74 +428,82 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { } } - bool useColorFilter = - // The rest of transfer mode color filters have not been implemented - fProgramDesc.fColorFilterXfermode <= SkXfermode::kMultiply_Mode - // This mode has no effect. - && fProgramDesc.fColorFilterXfermode != SkXfermode::kDst_Mode; - bool onlyUseColorFilter = useColorFilter - && (fProgramDesc.fColorFilterXfermode == SkXfermode::kClear_Mode - || fProgramDesc.fColorFilterXfermode == SkXfermode::kSrc_Mode); - if (useColorFilter) { - // Set up a uniform for the color - segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n"); - programData->fUniLocations.fColorFilterUni = kUseUniform; - } - - // for each enabled stage figure out what the input coordinates are - // and count the number of stages in use. - const char* stageInCoords[GrDrawTarget::kNumStages]; - int numActiveStages = 0; + /////////////////////////////////////////////////////////////////////////// + // compute the final color - if (!onlyUseColorFilter) { - for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { + // if we have color stages string them together, feeding the output color + // of each to the next and generating code for each stage. + if (needComputedColor) { + GrStringBuilder outColor; + for (int s = 0; s < fProgramDesc.fFirstCoverageStage; ++s) { if (fProgramDesc.fStages[s].fEnabled) { - if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { - stageInCoords[s] = POS_ATTR_NAME; + // create var to hold stage result + outColor = "color"; + outColor.appendS32(s); + segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); + + const char* inCoords; + // figure out what our input coords are + if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & + layout) { + inCoords = POS_ATTR_NAME; } else { int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); // we better have input tex coordinates if stage is enabled. GrAssert(tcIdx >= 0); GrAssert(texCoordAttrs[tcIdx].size()); - stageInCoords[s] = texCoordAttrs[tcIdx].c_str(); - } - ++numActiveStages; - } - } - } - - // if we have active stages string them together, feeding the output color - // of each to the next and generating code for each stage. - if (numActiveStages) { - int currActiveStage = 0; - GrStringBuilder outColor; - for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { - if (fProgramDesc.fStages[s].fEnabled) { - if (currActiveStage < (numActiveStages - 1) || useColorFilter) { - outColor = "color"; - outColor.appendS32(currActiveStage); - segments.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str()); - } else { - outColor = "gl_FragColor"; + inCoords = texCoordAttrs[tcIdx].c_str(); } genStageCode(s, fProgramDesc.fStages[s], inColor.size() ? inColor.c_str() : NULL, outColor.c_str(), - stageInCoords[s], + inCoords, &segments, &programData->fUniLocations.fStages[s]); - ++currActiveStage; inColor = outColor; } } - if (useColorFilter) { - addColorFilter(&segments.fFSCode, "gl_FragColor", - fProgramDesc.fColorFilterXfermode, outColor.c_str()); - } + } - } else { + // if have all ones for the "dst" input to the color filter then we can make + // additional optimizations. + if (needColorFilterUniform && !inColor.size() && + (SkXfermode::kIDC_Coeff == uniformCoeff || + SkXfermode::kIDA_Coeff == uniformCoeff)) { + uniformCoeff = SkXfermode::kZero_Coeff; + bool bogus; + needBlendInputs(SkXfermode::kZero_Coeff, colorCoeff, + &needColorFilterUniform, &bogus); + } + if (needColorFilterUniform) { + segments.fFSUnis.append( "uniform vec4 " COL_FILTER_UNI_NAME ";\n"); + programData->fUniLocations.fColorFilterUni = kUseUniform; + } + + bool wroteFragColorZero = false; + if (SkXfermode::kZero_Coeff == uniformCoeff && + SkXfermode::kZero_Coeff == colorCoeff) { + segments.fFSCode.appendf("\tgl_FragColor = %s;\n", all_zeros_vec(4)); + wroteFragColorZero = true; + } else if (SkXfermode::kDst_Mode != fProgramDesc.fColorFilterXfermode) { + segments.fFSCode.appendf("\tvec4 filteredColor;\n"); + const char* color = inColor.size() ? inColor.c_str() : all_ones_vec(4); + addColorFilter(&segments.fFSCode, "filteredColor", uniformCoeff, + colorCoeff, color); + inColor = "filteredColor"; + } + + /////////////////////////////////////////////////////////////////////////// + // compute the partial coverage (coverage stages and edge aa) + + GrStringBuilder inCoverage; + bool coverageIsScalar = false; + + // we will want to compute coverage for some blend when there is no + // color (when dual source blending is enabled). But for now we have this if + if (!wroteFragColorZero) { if (fProgramDesc.fUsesEdgeAA) { // FIXME: put the a's in a loop segments.fFSCode.append( @@ -373,25 +515,68 @@ bool GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const { "\tfloat a4 = clamp(dot(uEdges[4], pos), 0.0, 1.0);\n" "\tfloat a5 = clamp(dot(uEdges[5], pos), 0.0, 1.0);\n" "\tfloat edgeAlpha = min(min(a0 * a1, a2 * a3), a4 * a5);\n"); - if (inColor.size()) { - inColor.append(" * edgeAlpha"); - } else { - inColor = "vec4(edgeAlpha)"; + inCoverage = "edgeAlpha"; + coverageIsScalar = true; + } + + GrStringBuilder outCoverage; + const int& startStage = fProgramDesc.fFirstCoverageStage; + for (int s = startStage; s < GrDrawTarget::kNumStages; ++s) { + if (fProgramDesc.fStages[s].fEnabled) { + + // create var to hold stage output + outCoverage = "coverage"; + outCoverage.appendS32(s); + segments.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str()); + + const char* inCoords; + // figure out what our input coords are + if (GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s) & layout) { + inCoords = POS_ATTR_NAME; + } else { + int tcIdx = GrDrawTarget::VertexTexCoordsForStage(s, layout); + // we better have input tex coordinates if stage is enabled. + GrAssert(tcIdx >= 0); + GrAssert(texCoordAttrs[tcIdx].size()); + inCoords = texCoordAttrs[tcIdx].c_str(); + } + + genStageCode(s, + fProgramDesc.fStages[s], + inCoverage.size() ? inCoverage.c_str() : NULL, + outCoverage.c_str(), + inCoords, + &segments, + &programData->fUniLocations.fStages[s]); + inCoverage = outCoverage; + coverageIsScalar = false; } } - // we may not have any incoming color - const char * incomingColor = (inColor.size() ? inColor.c_str() - : "vec4(1,1,1,1)"); - if (useColorFilter) { - addColorFilter(&segments.fFSCode, "gl_FragColor", - fProgramDesc.fColorFilterXfermode, incomingColor); - } else { - segments.fFSCode.appendf("\tgl_FragColor = %s;\n", incomingColor); + } + + // TODO: ADD dual source blend output based on coverage here + + /////////////////////////////////////////////////////////////////////////// + // combine color and coverage as frag color + + if (!wroteFragColorZero) { + if (coverageIsScalar && !inColor.size()) { + GrStringBuilder oldCoverage = inCoverage; + inCoverage.swap(oldCoverage); + inCoverage.printf("vec4(%s,%s,%s,%s)", oldCoverage.c_str(), + oldCoverage.c_str(), oldCoverage.c_str(), + oldCoverage.c_str()); } + modulate_helper("gl_FragColor", inColor.c_str(), + inCoverage.c_str(), &segments.fFSCode); } + segments.fVSCode.append("}\n"); segments.fFSCode.append("}\n"); + /////////////////////////////////////////////////////////////////////////// + // compile and setup attribs and unis + if (!CompileFSAndVS(segments, programData)) { return false; } @@ -565,7 +750,6 @@ bool GrGLProgram::bindAttribsAndLinkProgram(GrStringBuilder texCoordAttrNames[], } } - GR_GL(BindAttribLocation(progID, ColorAttributeIdx(), COL_ATTR_NAME)); GR_GL(LinkProgram(progID)); @@ -610,7 +794,7 @@ void GrGLProgram::getUniformLocationsAndInitCache(CachedData* programData) const GrAssert(kUnusedUniform != programData->fUniLocations.fColorFilterUni); } - if (fProgramDesc.fUsesEdgeAA) { + if (kUseUniform == programData->fUniLocations.fEdgesUni) { programData->fUniLocations.fEdgesUni = GR_GL(GetUniformLocation(progID, EDGES_UNI_NAME)); GrAssert(kUnusedUniform != programData->fUniLocations.fEdgesUni); diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h index 74078e30b3..64d7088b72 100644 --- a/gpu/src/GrGLProgram.h +++ b/gpu/src/GrGLProgram.h @@ -99,6 +99,7 @@ private: kUniform_ColorType = 2, } fColorType; + int fFirstCoverageStage; bool fEmitsPointSize; bool fUsesEdgeAA; diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp index 125b8205af..bcf29ae56d 100644 --- a/gpu/src/GrGpuGLShaders.cpp +++ b/gpu/src/GrGpuGLShaders.cpp @@ -169,6 +169,14 @@ void GrGpuGLShaders::ProgramUnitTest() { GrRandom random; for (int t = 0; t < NUM_TESTS; ++t) { +#if 0 + GrPrintf("\nTest Program %d\n-------------\n", t); + static const int stop = -1; + if (t == stop) { + int breakpointhere = 9; + } +#endif + pdesc.fVertexLayout = 0; pdesc.fEmitsPointSize = random.nextF() > .5f; float colorType = random.nextF(); @@ -179,6 +187,15 @@ void GrGpuGLShaders::ProgramUnitTest() { } else { pdesc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; } + + int idx = (int)(random.nextF() * (SkXfermode::kCoeffModesCnt)); + pdesc.fColorFilterXfermode = (SkXfermode::Mode)idx; + + idx = (int)(random.nextF() * (kNumStages+1)); + pdesc.fFirstCoverageStage = idx; + + pdesc.fUsesEdgeAA = (random.nextF() > .5f); + for (int s = 0; s < kNumStages; ++s) { // enable the stage? if (random.nextF() > .5f) { @@ -194,19 +211,15 @@ void GrGpuGLShaders::ProgramUnitTest() { if (random.nextF() > .5f) { pdesc.fVertexLayout |= kTextFormat_VertexLayoutBit; } - } - - for (int s = 0; s < kNumStages; ++s) { - int x; pdesc.fStages[s].fEnabled = VertexUsesStage(s, pdesc.fVertexLayout); - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); - pdesc.fStages[s].fOptFlags = STAGE_OPTS[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); - pdesc.fStages[s].fModulation = STAGE_MODULATES[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); - pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x]; - x = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); - pdesc.fStages[s].fFetchMode = FETCH_MODES[x]; + idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS)); + pdesc.fStages[s].fOptFlags = STAGE_OPTS[idx]; + idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES)); + pdesc.fStages[s].fModulation = STAGE_MODULATES[idx]; + idx = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS)); + pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[idx]; + idx = (int)(random.nextF() * GR_ARRAY_COUNT(FETCH_MODES)); + pdesc.fStages[s].fFetchMode = FETCH_MODES[idx]; } GrGLProgram::CachedData cachedData; program.genProgram(&cachedData); @@ -219,7 +232,6 @@ void GrGpuGLShaders::ProgramUnitTest() { } } - GrGpuGLShaders::GrGpuGLShaders() { resetContext(); @@ -668,6 +680,18 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { // existing program in the cache. desc.fVertexLayout &= ~(kColor_VertexLayoutBit); + desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; + + // coverage vs. color only applies when there is a color filter + // (currently) + if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) { + desc.fFirstCoverageStage = fCurrDrawState.fFirstCoverageStage; + } else { + // use canonical value when this won't affect generated + // code to prevent duplicate programs. + desc.fFirstCoverageStage = kNumStages; + } + #if GR_AGGRESSIVE_SHADER_OPTS if (!requiresAttributeColors && (0xffffffff == fCurrDrawState.fColor)) { desc.fColorType = GrGLProgram::ProgramDesc::kNone_ColorType; @@ -764,7 +788,6 @@ void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { fCurrentProgram.fStageEffects[s] = NULL; } } - desc.fColorFilterXfermode = fCurrDrawState.fColorFilterXfermode; } diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h index 4d46bb919a..6ab9d6d562 100644 --- a/include/core/SkXfermode.h +++ b/include/core/SkXfermode.h @@ -103,11 +103,15 @@ public: kDstATop_Mode, //!< [Sa, Sa * Dc + Sc * (1 - Da)] kXor_Mode, //!< [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] - // these modes are defined in the SVG Compositing standard + // all remaining modes are defined in the SVG Compositing standard // http://www.w3.org/TR/2009/WD-SVGCompositing-20090430/ kPlus_Mode, - kMultiply_Mode, - kScreen_Mode, + kMultiply_Mode, + + // all above modes can be expressed as pair of src/dst Coeffs + kCoeffModesCnt, + + kScreen_Mode = kCoeffModesCnt, kOverlay_Mode, kDarken_Mode, kLighten_Mode, |