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
This commit is contained in:
bsalomon@google.com 2011-05-16 20:56:06 +00:00
parent 852fa0fafa
commit f2d91557b2
5 changed files with 379 additions and 140 deletions

View File

@ -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;
@ -342,6 +349,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.

View File

@ -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 {
}
}
/**
* Create a text coefficient to be used in fragment shader code.
*/
static void coefficientString(GrStringBuilder* str, SkXfermode::Coeff coeff,
const char* src, const char* dst) {
switch (coeff) {
case SkXfermode::kZero_Coeff: /** 0 */
*str = "0.0";
break;
case SkXfermode::kOne_Coeff: /** 1 */
*str = "1.0";
break;
case SkXfermode::kSA_Coeff: /** src alpha */
str->appendf("%s.a", src);
break;
case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
str->appendf("(1.0 - %s.a)", src);
break;
case SkXfermode::kDA_Coeff: /** dst alpha */
str->appendf("%s.a", dst);
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);
break;
default:
break;
// 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 blend_coeff * value string to be used in shader code. Sets empty
* string if result is trivially zero.
*/
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 = "";
break;
case SkXfermode::kOne_Coeff: /** 1 */
*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->printf("(%s.a * %s)", src, value);
break;
case SkXfermode::kISA_Coeff: /** inverse src alpha (i.e. 1 - sa) */
str->printf("((1.0 - %s.a) * %s)", src, value);
break;
case SkXfermode::kDA_Coeff: /** dst alpha */
str->printf("(%s.a * %s)", dst, value);
break;
case SkXfermode::kIDA_Coeff: /** inverse dst alpha (i.e. 1 - da) */
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;
}
///////////////////////////////////////////////////////////////////////////
// compute the final color
// 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;
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);

View File

@ -99,6 +99,7 @@ private:
kUniform_ColorType = 2,
} fColorType;
int fFirstCoverageStage;
bool fEmitsPointSize;
bool fUsesEdgeAA;

View File

@ -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;
}

View File

@ -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,