Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Unified Diff: src/gpu/effects/GrPorterDuffXferProcessor.cpp

Issue 759713002: Make all blending up to GrOptDrawState be handled by the xp/xp factory. (Closed) Base URL: https://skia.googlesource.com/skia.git@xferFactorySolo
Patch Set: rebase Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/SkGr.cpp ('k') | tests/GLProgramsTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/effects/GrPorterDuffXferProcessor.cpp
diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
index 55e0c93b23ad03d355ea39969e31c5a7c0cb2eb2..2b4b1334f89828b96cc142a688f8492437f7dcfa 100644
--- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp
+++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp
@@ -7,6 +7,7 @@
#include "effects/GrPorterDuffXferProcessor.h"
+#include "GrBlend.h"
#include "GrDrawState.h"
#include "GrInvariantOutput.h"
#include "GrProcessor.h"
@@ -16,6 +17,25 @@
#include "gl/builders/GrGLFragmentShaderBuilder.h"
#include "gl/builders/GrGLProgramBuilder.h"
+static bool can_tweak_alpha_for_coverage(GrBlendCoeff dstCoeff, bool isCoverageDrawing) {
+ /*
+ The fractional coverage is f.
+ The src and dst coeffs are Cs and Cd.
+ The dst and src colors are S and D.
+ We want the blend to compute: f*Cs*S + (f*Cd + (1-f))D. By tweaking the source color's alpha
+ we're replacing S with S'=fS. It's obvious that that first term will always be ok. The second
+ term can be rearranged as [1-(1-Cd)f]D. By substituting in the various possibilities for Cd we
+ find that only 1, ISA, and ISC produce the correct destination when applied to S' and D.
+ Also, if we're directly rendering coverage (isCoverageDrawing) then coverage is treated as
+ color by definition.
+ */
+ // TODO: Once we have a CoverageDrawing XP, we don't need to check is CoverageDrawing here
+ return kOne_GrBlendCoeff == dstCoeff ||
+ kISA_GrBlendCoeff == dstCoeff ||
+ kISC_GrBlendCoeff == dstCoeff ||
+ isCoverageDrawing;
+}
+
class GrGLPorterDuffXferProcessor : public GrGLXferProcessor {
public:
GrGLPorterDuffXferProcessor(const GrProcessor&) {}
@@ -42,8 +62,9 @@ private:
///////////////////////////////////////////////////////////////////////////////
-GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend)
- : fSrcBlend(srcBlend), fDstBlend(dstBlend) {
+GrPorterDuffXferProcessor::GrPorterDuffXferProcessor(GrBlendCoeff srcBlend, GrBlendCoeff dstBlend,
+ GrColor constant)
+ : fSrcBlend(srcBlend), fDstBlend(dstBlend), fBlendConstant(constant) {
this->initClassID<GrPorterDuffXferProcessor>();
}
@@ -60,13 +81,121 @@ GrGLFragmentProcessor* GrPorterDuffXferProcessor::createGLInstance() const {
}
void GrPorterDuffXferProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
- inout->setToUnknown(GrInvariantOutput::kWillNot_ReadInput);
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
}
+GrXferProcessor::OptFlags
+GrPorterDuffXferProcessor::getOptimizations(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool isCoverageDrawing,
+ bool colorWriteDisabled,
+ bool doesStencilWrite,
+ GrColor* color, uint8_t* coverage) {
+ if (colorWriteDisabled) {
+ fSrcBlend = kZero_GrBlendCoeff;
+ fDstBlend = kOne_GrBlendCoeff;
+ }
+
+ bool srcAIsOne;
+ bool hasCoverage;
+ if (isCoverageDrawing) {
+ srcAIsOne = colorPOI.isOpaque() && coveragePOI.isOpaque();
+ hasCoverage = false;
+ } else {
+ srcAIsOne = colorPOI.isOpaque();
+ hasCoverage = !coveragePOI.isSolidWhite();
+ }
+
+ bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstBlend ||
+ (kSA_GrBlendCoeff == fDstBlend && srcAIsOne);
+ bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstBlend ||
+ (kISA_GrBlendCoeff == fDstBlend && srcAIsOne);
+
+ // Optimizations when doing RGB Coverage
+ if (coveragePOI.isFourChannelOutput()) {
+ // We want to force our primary output to be alpha * Coverage, where alpha is the alpha
+ // value of the blend the constant. We should already have valid blend coeff's if we are at
+ // a point where we have RGB coverage. We don't need any color stages since the known color
+ // output is already baked into the blendConstant.
+ uint8_t alpha = GrColorUnpackA(fBlendConstant);
+ *color = GrColorPackRGBA(alpha, alpha, alpha, alpha);
+ return GrXferProcessor::kClearColorStages_OptFlag;
+ }
+
+ // When coeffs are (0,1) there is no reason to draw at all, unless
+ // stenciling is enabled. Having color writes disabled is effectively
+ // (0,1).
+ if ((kZero_GrBlendCoeff == fSrcBlend && dstCoeffIsOne)) {
+ if (doesStencilWrite) {
+ *color = 0xffffffff;
+ return GrXferProcessor::kClearColorStages_OptFlag |
+ GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ } else {
+ fDstBlend = kOne_GrBlendCoeff;
+ return GrXferProcessor::kSkipDraw_OptFlag;
+ }
+ }
+
+ // if we don't have coverage we can check whether the dst
+ // has to read at all. If not, we'll disable blending.
+ if (!hasCoverage) {
+ if (dstCoeffIsZero) {
+ if (kOne_GrBlendCoeff == fSrcBlend) {
+ // if there is no coverage and coeffs are (1,0) then we
+ // won't need to read the dst at all, it gets replaced by src
+ fDstBlend = kZero_GrBlendCoeff;
+ return GrXferProcessor::kNone_Opt;
+ } else if (kZero_GrBlendCoeff == fSrcBlend) {
+ // if the op is "clear" then we don't need to emit a color
+ // or blend, just write transparent black into the dst.
+ fSrcBlend = kOne_GrBlendCoeff;
+ fDstBlend = kZero_GrBlendCoeff;
+ *color = 0;
+ *coverage = 0xff;
+ return GrXferProcessor::kClearColorStages_OptFlag |
+ GrXferProcessor::kClearCoverageStages_OptFlag;
+ }
+ }
+ } else if (isCoverageDrawing) {
+ // we have coverage but we aren't distinguishing it from alpha by request.
+ return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ } else {
+ // check whether coverage can be safely rolled into alpha
+ // of if we can skip color computation and just emit coverage
+ if (can_tweak_alpha_for_coverage(fDstBlend, isCoverageDrawing)) {
+ return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ }
+ if (dstCoeffIsZero) {
+ if (kZero_GrBlendCoeff == fSrcBlend) {
+ // the source color is not included in the blend
+ // the dst coeff is effectively zero so blend works out to:
+ // (c)(0)D + (1-c)D = (1-c)D.
+ fDstBlend = kISA_GrBlendCoeff;
+ *color = 0xffffffff;
+ return GrXferProcessor::kClearColorStages_OptFlag |
+ GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ } else if (srcAIsOne) {
+ // the dst coeff is effectively zero so blend works out to:
+ // cS + (c)(0)D + (1-c)D = cS + (1-c)D.
+ // If Sa is 1 then we can replace Sa with c
+ // and set dst coeff to 1-Sa.
+ fDstBlend = kISA_GrBlendCoeff;
+ return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ }
+ } else if (dstCoeffIsOne) {
+ // the dst coeff is effectively one so blend works out to:
+ // cS + (c)(1)D + (1-c)D = cS + D.
+ fDstBlend = kOne_GrBlendCoeff;
+ return GrXferProcessor::kSetCoverageDrawing_OptFlag;
+ }
+ }
+
+ return GrXferProcessor::kNone_Opt;
+}
///////////////////////////////////////////////////////////////////////////////
GrPorterDuffXPFactory::GrPorterDuffXPFactory(GrBlendCoeff src, GrBlendCoeff dst)
- : fSrc(src), fDst(dst) {
+ : fSrcCoeff(src), fDstCoeff(dst) {
this->initClassID<GrPorterDuffXPFactory>();
}
@@ -152,16 +281,173 @@ GrXPFactory* GrPorterDuffXPFactory::Create(SkXfermode::Mode mode) {
}
}
-const GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor() const {
- return GrPorterDuffXferProcessor::Create(fSrc, fDst);
+GrXferProcessor* GrPorterDuffXPFactory::createXferProcessor(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& covPOI) const {
+ if (!covPOI.isFourChannelOutput()) {
+ return GrPorterDuffXferProcessor::Create(fSrcCoeff, fDstCoeff);
+ } else {
+ if (this->supportsRGBCoverage(colorPOI.color(), colorPOI.validFlags())) {
+ SkASSERT(kRGBA_GrColorComponentFlags == colorPOI.validFlags());
+ GrColor blendConstant = GrUnPreMulColor(colorPOI.color());
+ return GrPorterDuffXferProcessor::Create(kConstC_GrBlendCoeff, kISC_GrBlendCoeff,
+ blendConstant);
+ } else {
+ return NULL;
+ }
+ }
}
bool GrPorterDuffXPFactory::supportsRGBCoverage(GrColor /*knownColor*/,
uint32_t knownColorFlags) const {
- if (kOne_GrBlendCoeff == fSrc && kISA_GrBlendCoeff == fDst &&
+ if (kOne_GrBlendCoeff == fSrcCoeff && kISA_GrBlendCoeff == fDstCoeff &&
kRGBA_GrColorComponentFlags == knownColorFlags) {
return true;
}
return false;
}
+bool GrPorterDuffXPFactory::canApplyCoverage(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool isCoverageDrawing,
+ bool colorWriteDisabled) const {
+ bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
+
+ if (colorWriteDisabled) {
+ return true;
+ }
+
+ bool dstCoeffIsOne = kOne_GrBlendCoeff == fDstCoeff ||
+ (kSA_GrBlendCoeff == fDstCoeff && srcAIsOne);
+ bool dstCoeffIsZero = kZero_GrBlendCoeff == fDstCoeff ||
+ (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne);
+
+ if ((kZero_GrBlendCoeff == fSrcCoeff && dstCoeffIsOne)) {
+ return true;
+ }
+
+ // if we don't have coverage we can check whether the dst
+ // has to read at all.
+ if (isCoverageDrawing) {
+ // we have coverage but we aren't distinguishing it from alpha by request.
+ return true;
+ } else {
+ // check whether coverage can be safely rolled into alpha
+ // of if we can skip color computation and just emit coverage
+ if (this->canTweakAlphaForCoverage(isCoverageDrawing)) {
+ return true;
+ }
+ if (dstCoeffIsZero) {
+ if (kZero_GrBlendCoeff == fSrcCoeff) {
+ return true;
+ } else if (srcAIsOne) {
+ return true;
+ }
+ } else if (dstCoeffIsOne) {
+ return true;
+ }
+ }
+
+ // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
+ // will readDst and PD XP's don't read dst.
+ if ((colorPOI.readsDst() || coveragePOI.readsDst()) &&
+ kOne_GrBlendCoeff == fSrcCoeff && kZero_GrBlendCoeff == fDstCoeff) {
+ return true;
+ }
+
+ return false;
+}
+
+bool GrPorterDuffXPFactory::willBlendWithDst(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ bool isCoverageDrawing,
+ bool colorWriteDisabled) const {
+ if (!(isCoverageDrawing || coveragePOI.isSolidWhite())) {
+ return true;
+ }
+
+ // TODO: once all SkXferEffects are XP's then we will never reads dst here since only XP's
+ // will readDst and PD XP's don't read dst.
+ if ((!colorWriteDisabled && colorPOI.readsDst()) || coveragePOI.readsDst()) {
+ return true;
+ }
+
+ if (GrBlendCoeffRefsDst(fSrcCoeff)) {
+ return true;
+ }
+
+ bool srcAIsOne = colorPOI.isOpaque() && (!isCoverageDrawing || coveragePOI.isOpaque());
+
+ if (!(kZero_GrBlendCoeff == fDstCoeff ||
+ (kISA_GrBlendCoeff == fDstCoeff && srcAIsOne))) {
+ return true;
+ }
+
+ return false;
+}
+
+bool GrPorterDuffXPFactory::canTweakAlphaForCoverage(bool isCoverageDrawing) const {
+ return can_tweak_alpha_for_coverage(fDstCoeff, isCoverageDrawing);
+}
+
+bool GrPorterDuffXPFactory::getOpaqueAndKnownColor(const GrProcOptInfo& colorPOI,
+ const GrProcOptInfo& coveragePOI,
+ GrColor* solidColor,
+ uint32_t* solidColorKnownComponents) const {
+ if (!coveragePOI.isSolidWhite()) {
+ return false;
+ }
+
+ SkASSERT((NULL == solidColor) == (NULL == solidColorKnownComponents));
+
+ GrBlendCoeff srcCoeff = fSrcCoeff;
+ GrBlendCoeff dstCoeff = fDstCoeff;
+
+ // TODO: figure out to merge this simplify with other current optimization code paths and
+ // eventually remove from GrBlend
+ GrSimplifyBlend(&srcCoeff, &dstCoeff, colorPOI.color(), colorPOI.validFlags(),
+ 0, 0, 0);
+
+ bool opaque = kZero_GrBlendCoeff == dstCoeff && !GrBlendCoeffRefsDst(srcCoeff);
+ if (solidColor) {
+ if (opaque) {
+ switch (srcCoeff) {
+ case kZero_GrBlendCoeff:
+ *solidColor = 0;
+ *solidColorKnownComponents = kRGBA_GrColorComponentFlags;
+ break;
+
+ case kOne_GrBlendCoeff:
+ *solidColor = colorPOI.color();
+ *solidColorKnownComponents = colorPOI.validFlags();
+ break;
+
+ // The src coeff should never refer to the src and if it refers to dst then opaque
+ // should have been false.
+ case kSC_GrBlendCoeff:
+ case kISC_GrBlendCoeff:
+ case kDC_GrBlendCoeff:
+ case kIDC_GrBlendCoeff:
+ case kSA_GrBlendCoeff:
+ case kISA_GrBlendCoeff:
+ case kDA_GrBlendCoeff:
+ case kIDA_GrBlendCoeff:
+ default:
+ SkFAIL("srcCoeff should not refer to src or dst.");
+ break;
+
+ // TODO: update this once GrPaint actually has a const color.
+ case kConstC_GrBlendCoeff:
+ case kIConstC_GrBlendCoeff:
+ case kConstA_GrBlendCoeff:
+ case kIConstA_GrBlendCoeff:
+ *solidColorKnownComponents = 0;
+ break;
+ }
+ } else {
+ solidColorKnownComponents = 0;
+ }
+ }
+ return opaque;
+}
+
+
« no previous file with comments | « src/gpu/SkGr.cpp ('k') | tests/GLProgramsTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698