AI 143743: interpret xfermodes+solid_color to take a faster case when possible in the blitter chooser
BUG=1748928
Automated import of CL 143743
diff --git a/include/core/SkXfermode.h b/include/core/SkXfermode.h
index f7e6510..6a7edec 100644
--- a/include/core/SkXfermode.h
+++ b/include/core/SkXfermode.h
@@ -41,20 +41,38 @@
virtual void xferA8(SkAlpha dst[], const SkPMColor src[], int count,
const SkAlpha aa[]);
+ /** Enum of possible coefficients to describe some xfermodes
+ */
enum Coeff {
- kZero_Coeff,
- kOne_Coeff,
- kSC_Coeff,
- kISC_Coeff,
- kDC_Coeff,
- kIDC_Coeff,
- kSA_Coeff,
- kISA_Coeff,
- kDA_Coeff,
- kIDA_Coeff,
+ kZero_Coeff, /** 0 */
+ kOne_Coeff, /** 1 */
+ kSC_Coeff, /** src color */
+ kISC_Coeff, /** inverse src color (i.e. 1 - sc) */
+ kDC_Coeff, /** dst color */
+ kIDC_Coeff, /** inverse dst color (i.e. 1 - dc) */
+ kSA_Coeff, /** src alpha */
+ kISA_Coeff, /** inverse src alpha (i.e. 1 - sa) */
+ kDA_Coeff, /** dst alpha */
+ kIDA_Coeff, /** inverse dst alpha (i.e. 1 - da) */
kCoeffCount
};
+
+ /** If the xfermode can be expressed as an equation using the coefficients
+ in Coeff, then asCoeff() returns true, and sets (if not null) src and
+ dst accordingly.
+
+ result = src_coeff * src_color + dst_coeff * dst_color;
+
+ As examples, here are some of the porterduff coefficients
+
+ MODE SRC_COEFF DST_COEFF
+ clear zero zero
+ src one zero
+ dst zero one
+ srcover one isa
+ dstover ida one
+ */
virtual bool asCoeff(Coeff* src, Coeff* dst);
protected:
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp
index 9208429..25303ac 100644
--- a/src/core/SkBlitter.cpp
+++ b/src/core/SkBlitter.cpp
@@ -784,6 +784,64 @@
SkDELETE((SkBlitter*)blitter);
}
+static bool just_solid_color(const SkPaint& paint) {
+ if (paint.getAlpha() == 0xFF && paint.getColorFilter() == NULL) {
+ SkShader* shader = paint.getShader();
+ if (NULL == shader ||
+ (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/** By analyzing the paint (with an xfermode), we may decide we can take
+ special action. This enum lists our possible actions
+ */
+enum XferInterp {
+ kNormal_XferInterp, // no special interpretation, draw normally
+ kSrcOver_XferInterp, // draw as if in srcover mode
+ kSkipDrawing_XferInterp // draw nothing
+};
+
+static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
+ SkBitmap::Config deviceConfig) {
+ SkPorterDuff::Mode mode;
+
+ if (SkPorterDuff::IsMode(xfer, &mode)) {
+ switch (mode) {
+ case SkPorterDuff::kSrc_Mode:
+ if (just_solid_color(paint)) {
+ return kSrcOver_XferInterp;
+ }
+ break;
+ case SkPorterDuff::kDst_Mode:
+ return kSkipDrawing_XferInterp;
+ case SkPorterDuff::kSrcOver_Mode:
+ return kSrcOver_XferInterp;
+ case SkPorterDuff::kDstOver_Mode:
+ if (SkBitmap::kRGB_565_Config == deviceConfig) {
+ return kSkipDrawing_XferInterp;
+ }
+ break;
+ case SkPorterDuff::kSrcIn_Mode:
+ if (SkBitmap::kRGB_565_Config == deviceConfig &&
+ just_solid_color(paint)) {
+ return kSrcOver_XferInterp;
+ }
+ break;
+ case SkPorterDuff::kDstIn_Mode:
+ if (just_solid_color(paint)) {
+ return kSkipDrawing_XferInterp;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return kNormal_XferInterp;
+}
+
SkBlitter* SkBlitter::Choose(const SkBitmap& device,
const SkMatrix& matrix,
const SkPaint& paint,
@@ -813,6 +871,19 @@
}
SkXfermode* mode = paint.getXfermode();
+ if (NULL != mode) {
+ switch (interpret_xfermode(paint, mode, device.config())) {
+ case kSrcOver_XferInterp:
+ mode = NULL;
+ break;
+ case kSkipDrawing_XferInterp:
+ SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
+ return blitter;
+ default:
+ break;
+ }
+ }
+
if (NULL == shader && (NULL != mode || paint.getColorFilter() != NULL))
{
// xfermodes require shaders for our current set of blitters