aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-19 13:14:45 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-04-19 13:14:45 +0000
commit5920ac276877b36624e07baf97c7768e80a07f98 (patch)
tree28adb3da6aa138be9eee7f01f2fe218ea11e05e3 /src
parent87f99cb543dbba608136bbd2a7b1e6b3356fd6f9 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/gpu/SkGpuDevice.cpp4
-rw-r--r--src/gpu/gl/GrGLProgram.cpp91
-rw-r--r--src/gpu/gl/GrGLProgramDesc.cpp13
-rw-r--r--src/gpu/gl/GrGLProgramDesc.h41
4 files changed, 109 insertions, 40 deletions
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 356fcac243..299cf3de66 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -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");)
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 0b338f2faa..1b4baa40ea 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -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
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 73846b8df3..86771794d9 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -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;
}
}
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index d2167c758b..8d7ca8d1bc 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -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;