Perform coverage blend with the dst in the shader when using a dst-reading xfermode.

Review URL: https://codereview.chromium.org/14233006

git-svn-id: http://skia.googlecode.com/svn/trunk@8762 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
bsalomon@google.com 2013-04-19 13:14:45 +00:00
parent 87f99cb543
commit 5920ac2768
5 changed files with 119 additions and 45 deletions

View File

@ -501,10 +501,8 @@ inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev,
if (SkXfermode::AsNewEffectOrCoeff(mode, dev->context(), &xferEffect, &sm, &dm)) {
if (NULL != xferEffect) {
grPaint->colorStage(kXfermodeEffectIdx)->setEffect(xferEffect)->unref();
// This may not be the right place to have this logic but we set the GPU blend to
// src-over so that fractional coverage will be accounted for correctly.
sm = SkXfermode::kOne_Coeff;
dm = SkXfermode::kISA_Coeff;
dm = SkXfermode::kZero_Coeff;
}
} else {
//SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");)

View File

@ -96,24 +96,28 @@ void GrGLProgram::abandon() {
void GrGLProgram::overrideBlend(GrBlendCoeff* srcCoeff,
GrBlendCoeff* dstCoeff) const {
switch (fDesc.fDualSrcOutput) {
case GrGLProgramDesc::kNone_DualSrcOutput:
switch (fDesc.fCoverageOutput) {
case GrGLProgramDesc::kModulate_CoverageOutput:
break;
// the prog will write a coverage value to the secondary
// The prog will write a coverage value to the secondary
// output and the dst is blended by one minus that value.
case GrGLProgramDesc::kCoverage_DualSrcOutput:
case GrGLProgramDesc::kCoverageISA_DualSrcOutput:
case GrGLProgramDesc::kCoverageISC_DualSrcOutput:
*dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
break;
case GrGLProgramDesc::kSecondaryCoverage_CoverageOutput:
case GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput:
case GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput:
*dstCoeff = (GrBlendCoeff)GrGpu::kIS2C_GrBlendCoeff;
break;
case GrGLProgramDesc::kCombineWithDst_CoverageOutput:
// We should only have set this if the blend was specified as (1, 0)
GrAssert(kOne_GrBlendCoeff == *srcCoeff && kZero_GrBlendCoeff == *dstCoeff);
break;
default:
GrCrash("Unexpected dual source blend output");
GrCrash("Unexpected coverage output");
break;
}
}
namespace {
// given two blend coeffecients determine whether the src
// given two blend coefficients determine whether the src
// and/or dst computation can be omitted.
inline void need_blend_inputs(SkXfermode::Coeff srcCoeff,
SkXfermode::Coeff dstCoeff,
@ -375,6 +379,20 @@ GrGLuint compile_shader(const GrGLContext& gl, GrGLenum type, const SkString& sh
return compile_shader(gl, type, 1, &str, &length);
}
void expand_known_value4f(SkString* string, GrSLConstantVec vec) {
GrAssert(string->isEmpty() == (vec != kNone_GrSLConstantVec));
switch (vec) {
case kNone_GrSLConstantVec:
break;
case kZeros_GrSLConstantVec:
*string = GrGLSLZerosVecf(4);
break;
case kOnes_GrSLConstantVec:
*string = GrGLSLOnesVecf(4);
break;
}
}
}
// compiles all the shaders from builder and stores the shader IDs
@ -564,14 +582,16 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
}
}
if (GrGLProgramDesc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
GrGLProgramDesc::CoverageOutput coverageOutput =
static_cast<GrGLProgramDesc::CoverageOutput>(fDesc.fCoverageOutput);
if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(coverageOutput)) {
builder.fFSOutputs.push_back().set(kVec4f_GrSLType,
GrGLShaderVar::kOut_TypeModifier,
dual_source_output_name());
// default coeff to ones for kCoverage_DualSrcOutput
SkString coeff;
GrSLConstantVec knownCoeffValue = kOnes_GrSLConstantVec;
if (GrGLProgramDesc::kCoverageISA_DualSrcOutput == fDesc.fDualSrcOutput) {
if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == fDesc.fCoverageOutput) {
// Get (1-A) into coeff
SkString inColorAlpha;
GrGLSLGetComponent4f(&inColorAlpha,
@ -585,7 +605,7 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
kOnes_GrSLConstantVec,
knownColorValue,
true);
} else if (GrGLProgramDesc::kCoverageISC_DualSrcOutput == fDesc.fDualSrcOutput) {
} else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput == coverageOutput) {
// Get (1-RGBA) into coeff
knownCoeffValue = GrGLSLSubtractf<4>(&coeff,
NULL,
@ -609,15 +629,42 @@ bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
///////////////////////////////////////////////////////////////////////////
// combine color and coverage as frag color
// Get color * coverage into modulate and write that to frag shader's output.
SkString modulate;
GrGLSLModulatef<4>(&modulate,
inColor.c_str(),
inCoverage.c_str(),
knownColorValue,
knownCoverageValue,
false);
builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), modulate.c_str());
// Get "color * coverage" into fragColor
SkString fragColor;
GrSLConstantVec knownFragColorValue = GrGLSLModulatef<4>(&fragColor,
inColor.c_str(),
inCoverage.c_str(),
knownColorValue,
knownCoverageValue,
true);
// Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == coverageOutput) {
SkString dstCoeff;
GrSLConstantVec knownDstCoeffValue = GrGLSLSubtractf<4>(&dstCoeff,
NULL,
inCoverage.c_str(),
kOnes_GrSLConstantVec,
knownCoverageValue,
true);
SkString dstContribution;
GrSLConstantVec knownDstContributionValue = GrGLSLModulatef<4>(&dstContribution,
dstCoeff.c_str(),
builder.dstColor(),
knownDstCoeffValue,
kNone_GrSLConstantVec,
true);
SkString oldFragColor = fragColor;
fragColor.reset();
GrGLSLAddf<4>(&fragColor,
oldFragColor.c_str(),
dstContribution.c_str(),
knownFragColorValue,
knownDstContributionValue,
false);
} else {
expand_known_value4f(&fragColor, knownFragColorValue);
}
builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), fragColor.c_str());
///////////////////////////////////////////////////////////////////////////
// insert GS

View File

@ -103,7 +103,7 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
desc->fDstRead = 0;
}
desc->fDualSrcOutput = kNone_DualSrcOutput;
desc->fCoverageOutput = kModulate_CoverageOutput;
// Currently the experimental GS will only work with triangle prims (and it doesn't do anything
// other than pass through values from the VS to the FS anyway).
@ -151,17 +151,22 @@ void GrGLProgramDesc::Build(const GrDrawState& drawState,
GrDrawState::kCoverageAsAlpha_BlendOptFlag))) {
if (kZero_GrBlendCoeff == dstCoeff) {
// write the coverage value to second color
desc->fDualSrcOutput = kCoverage_DualSrcOutput;
desc->fCoverageOutput = kSecondaryCoverage_CoverageOutput;
desc->fFirstCoverageStage = firstCoverageStage;
} else if (kSA_GrBlendCoeff == dstCoeff) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
desc->fDualSrcOutput = kCoverageISA_DualSrcOutput;
desc->fCoverageOutput = kSecondaryCoverageISA_CoverageOutput;
desc->fFirstCoverageStage = firstCoverageStage;
} else if (kSC_GrBlendCoeff == dstCoeff) {
// SA dst coeff becomes 1-(1-SA)*coverage when dst is partially covered.
desc->fDualSrcOutput = kCoverageISC_DualSrcOutput;
desc->fCoverageOutput = kSecondaryCoverageISC_CoverageOutput;
desc->fFirstCoverageStage = firstCoverageStage;
}
} else if (readsDst &&
kOne_GrBlendCoeff == drawState.getSrcBlendCoeff() &&
kZero_GrBlendCoeff == drawState.getDstBlendCoeff()) {
desc->fCoverageOutput = kCombineWithDst_CoverageOutput;
desc->fFirstCoverageStage = firstCoverageStage;
}
}

View File

@ -65,18 +65,37 @@ private:
kColorInputCnt
};
// Dual-src blending makes use of a secondary output color that can be
// used as a per-pixel blend coefficient. This controls whether a
// secondary source is output and what value it holds.
enum DualSrcOutput {
kNone_DualSrcOutput,
kCoverage_DualSrcOutput,
kCoverageISA_DualSrcOutput,
kCoverageISC_DualSrcOutput,
kDualSrcOutputCnt
enum CoverageOutput {
// modulate color and coverage, write result as the color output.
kModulate_CoverageOutput,
// Writes color*coverage as the primary color output and also writes coverage as the
// secondary output. Only set if dual source blending is supported.
kSecondaryCoverage_CoverageOutput,
// Writes color*coverage as the primary color output and also writes coverage * (1 - colorA)
// as the secondary output. Only set if dual source blending is supported.
kSecondaryCoverageISA_CoverageOutput,
// Writes color*coverage as the primary color output and also writes coverage *
// (1 - colorRGB) as the secondary output. Only set if dual source blending is supported.
kSecondaryCoverageISC_CoverageOutput,
// Combines the coverage, dst, and color as coverage * color + (1 - coverage) * dst. This
// can only be set if fDstRead is set.
kCombineWithDst_CoverageOutput,
kCoverageOutputCnt
};
static bool CoverageOutputUsesSecondaryOutput(CoverageOutput co) {
switch (co) {
case kSecondaryCoverage_CoverageOutput: // fallthru
case kSecondaryCoverageISA_CoverageOutput:
case kSecondaryCoverageISC_CoverageOutput:
return true;
default:
return false;
}
}
/** Non-zero if this stage has an effect */
GrGLEffect::EffectKey fEffectKeys[GrDrawState::kNumStages];
@ -95,7 +114,7 @@ private:
uint8_t fColorInput; // casts to enum ColorInput
uint8_t fCoverageInput; // casts to enum ColorInput
uint8_t fDualSrcOutput; // casts to enum DualSrcOutput
uint8_t fCoverageOutput; // casts to enum CoverageOutput
int8_t fFirstCoverageStage;
SkBool8 fEmitsPointSize;

View File

@ -54,12 +54,6 @@ void GrGLProgramDesc::setRandom(SkMWCRandom* random,
fDiscardIfZeroCoverage = random->nextBool();
if (gpu->caps()->dualSourceBlendingSupport()) {
fDualSrcOutput = random->nextULessThan(kDualSrcOutputCnt);
} else {
fDualSrcOutput = kNone_DualSrcOutput;
}
bool useLocalCoords = random->nextBool() && currAttribIndex < GrDrawState::kMaxVertexAttribCnt;
fLocalCoordAttributeIndex = useLocalCoords ? currAttribIndex++ : -1;
@ -78,6 +72,17 @@ void GrGLProgramDesc::setRandom(SkMWCRandom* random,
if (dstRead) {
this->fDstRead = GrGLShaderBuilder::KeyForDstRead(dstTexture, gpu->glCaps());
}
CoverageOutput coverageOutput;
bool illegalCoverageOutput;
do {
coverageOutput = static_cast<CoverageOutput>(random->nextULessThan(kCoverageOutputCnt));
illegalCoverageOutput = (!gpu->caps()->dualSourceBlendingSupport() &&
CoverageOutputUsesSecondaryOutput(coverageOutput)) ||
!dstRead && kCombineWithDst_CoverageOutput == coverageOutput;
} while (illegalCoverageOutput);
fCoverageOutput = coverageOutput;
}
bool GrGpuGL::programUnitTest(int maxStages) {