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:
parent
852fa0fafa
commit
f2d91557b2
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -99,6 +99,7 @@ private:
|
||||
kUniform_ColorType = 2,
|
||||
} fColorType;
|
||||
|
||||
int fFirstCoverageStage;
|
||||
bool fEmitsPointSize;
|
||||
bool fUsesEdgeAA;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user