aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-01-11 21:08:55 +0000
committerGravatar bsalomon@google.com <bsalomon@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-01-11 21:08:55 +0000
commit371e105da5d9fdfff3b4242b37ff6fc09214c8c8 (patch)
treecfcca4200f2b8eb016f6ea3643f2602bc4076909 /src
parent95146ebc43175ae0c1cd3a116509d92aa1a445ab (diff)
Add GrEffect::updateKnownColorComponents(). It is used to determine whether the output of an effect has a constant output value for r,g,b, or a.
Review URL: https://codereview.appspot.com/7064057 git-svn-id: http://skia.googlecode.com/svn/trunk@7144 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r--src/effects/SkBlendImageFilter.cpp15
-rw-r--r--src/effects/SkColorMatrixFilter.cpp45
-rw-r--r--src/effects/SkLightingImageFilter.cpp7
-rw-r--r--src/effects/SkTableColorFilter.cpp48
-rw-r--r--src/effects/gradients/SkGradientShader.cpp2
-rw-r--r--src/effects/gradients/SkGradientShaderPriv.h10
-rw-r--r--src/gpu/GrDrawTarget.cpp62
-rw-r--r--src/gpu/GrEffect.cpp4
-rw-r--r--src/gpu/effects/GrSingleTextureEffect.cpp11
-rw-r--r--src/gpu/effects/GrSingleTextureEffect.h4
10 files changed, 168 insertions, 40 deletions
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index 6dd5eab4c5..3c625bb0b4 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -153,6 +153,8 @@ public:
typedef GrGLBlendEffect GLEffect;
static const char* Name() { return "Blend"; }
+ void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
private:
GrTextureAccess fForegroundAccess;
GrTextureAccess fBackgroundAccess;
@@ -245,6 +247,19 @@ const GrBackendEffectFactory& GrBlendEffect::getFactory() const {
return GrTBackendEffectFactory<GrBlendEffect>::getInstance();
}
+void GrBlendEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ // The output alpha is always 1 - (1 - FGa) * (1 - BGa). So if either FGa or BGa is known to
+ // be one then the output alpha is one. (This effect ignores its input. We should have a way to
+ // communicate this.)
+ if (GrPixelConfigIsOpaque(fForegroundAccess.getTexture()->config()) ||
+ GrPixelConfigIsOpaque(fBackgroundAccess.getTexture()->config())) {
+ *validFlags = kA_ValidComponentFlag;
+ *color = GrColorPackRGBA(0, 0, 0, 0xff);
+ } else {
+ *validFlags = 0;
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory, const GrEffect& effect)
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index ed34f64ea3..2ff4fd6f48 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -338,6 +338,51 @@ public:
return cme.fMatrix == fMatrix;
}
+ virtual void getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const SK_OVERRIDE {
+ // We only bother to check whether the alpha channel will be constant. If SkColorMatrix had
+ // type flags it might be worth checking the other components.
+
+ // The matrix is defined such the 4th row determines the output alpha. The first four
+ // columns of that row multiply the input r, g, b, and a, respectively, and the last column
+ // is the "translation".
+ static const ValidComponentFlags kRGBAFlags[] = {
+ kR_ValidComponentFlag,
+ kG_ValidComponentFlag,
+ kB_ValidComponentFlag,
+ kA_ValidComponentFlag
+ };
+ static const int kShifts[] = {
+ GrColor_SHIFT_R, GrColor_SHIFT_G, GrColor_SHIFT_B, GrColor_SHIFT_A,
+ };
+ enum {
+ kAlphaRowStartIdx = 15,
+ kAlphaRowTranslateIdx = 19,
+ };
+
+ SkScalar outputA = 0;
+ for (int i = 0; i < 4; ++i) {
+ // If any relevant component of the color to be passed through the matrix is non-const
+ // then we can't know the final result.
+ if (0 != fMatrix.fMat[kAlphaRowStartIdx + i]) {
+ if (!(*validFlags & kRGBAFlags[i])) {
+ *validFlags = 0;
+ return;
+ } else {
+ uint32_t component = (*color >> kShifts[i]) & 0xFF;
+ outputA += fMatrix.fMat[kAlphaRowStartIdx + i] * component;
+ }
+ }
+ }
+ outputA += fMatrix.fMat[kAlphaRowTranslateIdx];
+ *validFlags = kA_ValidComponentFlag;
+ // We pin the color to [0,1]. This would happen to the *final* color output from the frag
+ // shader but currently the effect does not pin its own output. So in the case of over/
+ // underflow this may deviate from the actual result. Maybe the effect should pin its
+ // result if the matrix could over/underflow for any component?
+ *color = static_cast<uint8_t>(SkScalarPin(outputA, 0, 255)) << GrColor_SHIFT_A;
+ }
+
GR_DECLARE_EFFECT_TEST;
class GLEffect : public GrGLEffect {
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 48f16b3ff8..fc819deb17 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -311,6 +311,13 @@ public:
const SkLight* light() const { return fLight; }
SkScalar surfaceScale() const { return fSurfaceScale; }
+
+ virtual void getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const SK_OVERRIDE {
+ // lighting shaders are complicated. We just throw up our hands.
+ *validFlags = 0;
+ }
+
private:
typedef GrSingleTextureEffect INHERITED;
const SkLight* fLight;
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index eb59425aa7..2577cb4b76 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -49,6 +49,13 @@ public:
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkTable_ColorFilter)
+ enum {
+ kA_Flag = 1 << 0,
+ kR_Flag = 1 << 1,
+ kG_Flag = 1 << 2,
+ kB_Flag = 1 << 3,
+ };
+
protected:
SkTable_ColorFilter(SkFlattenableReadBuffer& buffer);
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
@@ -56,12 +63,6 @@ protected:
private:
mutable const SkBitmap* fBitmap; // lazily allocated
- enum {
- kA_Flag = 1 << 0,
- kR_Flag = 1 << 1,
- kG_Flag = 1 << 2,
- kB_Flag = 1 << 3,
- };
uint8_t fStorage[256 * 4];
unsigned fFlags;
@@ -226,19 +227,23 @@ class GLColorTableEffect;
class ColorTableEffect : public GrEffect {
public:
- explicit ColorTableEffect(GrTexture* texture);
+ explicit ColorTableEffect(GrTexture* texture, unsigned flags);
virtual ~ColorTableEffect();
static const char* Name() { return "ColorTable"; }
virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
virtual bool isEqual(const GrEffect&) const SK_OVERRIDE;
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
typedef GLColorTableEffect GLEffect;
private:
GR_DECLARE_EFFECT_TEST;
GrTextureAccess fTextureAccess;
+ unsigned fFlags; // currently not used in shader code, just to assist
+ // getConstantColorComponents().
typedef GrEffect INHERITED;
};
@@ -321,8 +326,9 @@ GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrEffectStage&, const GrG
///////////////////////////////////////////////////////////////////////////////
-ColorTableEffect::ColorTableEffect(GrTexture* texture)
- : fTextureAccess(texture, "a") {
+ColorTableEffect::ColorTableEffect(GrTexture* texture, unsigned flags)
+ : fTextureAccess(texture, "a")
+ , fFlags(flags) {
this->addTextureAccess(&fTextureAccess);
}
@@ -337,6 +343,24 @@ bool ColorTableEffect::isEqual(const GrEffect& sBase) const {
return INHERITED::isEqual(sBase);
}
+void ColorTableEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ // If we kept the table in the effect then we could actually run known inputs through the
+ // table.
+ if (fFlags & SkTable_ColorFilter::kR_Flag) {
+ *validFlags = ~kR_ValidComponentFlag;
+ }
+ if (fFlags & SkTable_ColorFilter::kG_Flag) {
+ *validFlags &= ~kG_ValidComponentFlag;
+ }
+ if (fFlags & SkTable_ColorFilter::kB_Flag) {
+ *validFlags &= ~kB_ValidComponentFlag;
+ }
+ if (fFlags & SkTable_ColorFilter::kA_Flag) {
+ *validFlags &= ~kA_ValidComponentFlag;
+ }
+}
+
+
///////////////////////////////////////////////////////////////////////////////
GR_DEFINE_EFFECT_TEST(ColorTableEffect);
@@ -344,7 +368,9 @@ GR_DEFINE_EFFECT_TEST(ColorTableEffect);
GrEffect* ColorTableEffect::TestCreate(SkRandom* random,
GrContext* context,
GrTexture* textures[]) {
- return SkNEW_ARGS(ColorTableEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx]));
+ static unsigned kAllFlags = SkTable_ColorFilter::kR_Flag | SkTable_ColorFilter::kG_Flag |
+ SkTable_ColorFilter::kB_Flag | SkTable_ColorFilter::kA_Flag;
+ return SkNEW_ARGS(ColorTableEffect, (textures[GrEffectUnitTest::kAlphaTextureIdx], kAllFlags));
}
GrEffect* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
@@ -352,7 +378,7 @@ GrEffect* SkTable_ColorFilter::asNewEffect(GrContext* context) const {
this->asComponentTable(&bitmap);
// passing NULL because this effect does no tiling or filtering.
GrTexture* texture = GrLockCachedBitmapTexture(context, bitmap, NULL);
- GrEffect* effect = SkNEW_ARGS(ColorTableEffect, (texture));
+ GrEffect* effect = SkNEW_ARGS(ColorTableEffect, (texture, fFlags));
// Unlock immediately, this is not great, but we don't have a way of
// knowing when else to unlock it currently. TODO: Remove this when
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 8521bdbf61..7d779708f6 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -753,6 +753,8 @@ GrGradientEffect::GrGradientEffect(GrContext* ctx,
SkBitmap bitmap;
shader.getGradientTableBitmap(&bitmap);
+ fIsOpaque = shader.isOpaque();
+
GrTextureStripAtlas::Desc desc;
desc.fWidth = bitmap.width();
desc.fHeight = 32;
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 552013efa5..b2b8c47a1c 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -243,6 +243,15 @@ public:
fYCoord == s.getYCoord() && fMatrix.cheapEqualTo(s.getMatrix());
}
+ virtual void getConstantColorComponents(GrColor* color,
+ uint32_t* validFlags) const SK_OVERRIDE {
+ if (fIsOpaque && (kA_ValidComponentFlag & *validFlags) && 0xff == GrColorUnpackA(*color)) {
+ *validFlags = kA_ValidComponentFlag;
+ } else {
+ *validFlags = 0;
+ }
+ }
+
protected:
/** Populates a pair of arrays with colors and stop info to construct a random gradient.
@@ -264,6 +273,7 @@ private:
GrTextureStripAtlas* fAtlas;
int fRow;
SkMatrix fMatrix;
+ bool fIsOpaque;
typedef GrEffect INHERITED;
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 3c112871e5..e7609d88fc 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -827,40 +827,52 @@ bool GrDrawTarget::canTweakAlphaForCoverage() const {
bool GrDrawTarget::srcAlphaWillBeOne(GrVertexLayout layout) const {
const GrDrawState& drawState = this->getDrawState();
+ uint32_t validComponentFlags;
+ GrColor color;
// Check if per-vertex or constant color may have partial alpha
- if ((layout & kColor_VertexLayoutBit) ||
- 0xff != GrColorUnpackA(drawState.getColor())) {
- return false;
- }
- // Check if color filter could introduce an alpha
- // (TODO: Consider being more aggressive with regards to detecting 0xff
- // final alpha from color filter).
- if (SkXfermode::kDst_Mode != drawState.getColorFilterMode()) {
- return false;
- }
- int stageCnt;
- // Check whether coverage is treated as color
- if (drawState.isCoverageDrawing()) {
- if (0xff != GrColorUnpackA(drawState.getCoverage())) {
- return false;
- }
- stageCnt = GrDrawState::kNumStages;
+ if (layout & kColor_VertexLayoutBit) {
+ validComponentFlags = 0;
} else {
- stageCnt = drawState.getFirstCoverageStage();
+ validComponentFlags = GrEffect::kAll_ValidComponentFlags;
+ color = drawState.getColor();
}
- // Check if a color stage could create a partial alpha
+
+ // Run through the color stages
+ int stageCnt = drawState.getFirstCoverageStage();
for (int s = 0; s < stageCnt; ++s) {
const GrEffect* effect = drawState.getStage(s).getEffect();
if (NULL != effect) {
- // FIXME: The param indicates whether the texture is opaque or not. However, the effect
- // already controls its textures. It really needs to know whether the incoming color
- // (from a uni, per-vertex colors, or previous stage) is opaque or not.
- if (!effect->isOpaque(true)) {
- return false;
+ effect->getConstantColorComponents(&color, &validComponentFlags);
+ }
+ }
+
+ // Check if the color filter could introduce an alpha.
+ // We could skip the above work when this is true, but it is rare and the right fix is to make
+ // the color filter a GrEffect and implement getConstantColorComponents() for it.
+ if (SkXfermode::kDst_Mode != drawState.getColorFilterMode()) {
+ validComponentFlags = 0;
+ }
+
+ // Check whether coverage is treated as color. If so we run through the coverage computation.
+ if (drawState.isCoverageDrawing()) {
+ GrColor coverageColor = drawState.getCoverage();
+ GrColor oldColor = color;
+ color = 0;
+ for (int c = 0; c < 4; ++c) {
+ if (validComponentFlags & (1 << c)) {
+ U8CPU a = (oldColor >> (c * 8)) & 0xff;
+ U8CPU b = (coverageColor >> (c * 8)) & 0xff;
+ color |= (SkMulDiv255Round(a, b) << (c * 8));
+ }
+ }
+ for (int s = drawState.getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) {
+ const GrEffect* effect = drawState.getStage(s).getEffect();
+ if (NULL != effect) {
+ effect->getConstantColorComponents(&color, &validComponentFlags);
}
}
}
- return true;
+ return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color);
}
namespace {
diff --git a/src/gpu/GrEffect.cpp b/src/gpu/GrEffect.cpp
index dbfb6b014a..534489fd4e 100644
--- a/src/gpu/GrEffect.cpp
+++ b/src/gpu/GrEffect.cpp
@@ -61,10 +61,6 @@ int32_t GrBackendEffectFactory::fCurrEffectClassID = GrBackendEffectFactory::kIl
GrEffect::~GrEffect() {
}
-bool GrEffect::isOpaque(bool inputTextureIsOpaque) const {
- return false;
-}
-
const char* GrEffect::name() const {
return this->getFactory().name();
}
diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp
index 14f5b64472..2cf83472d7 100644
--- a/src/gpu/effects/GrSingleTextureEffect.cpp
+++ b/src/gpu/effects/GrSingleTextureEffect.cpp
@@ -98,6 +98,17 @@ GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
GrSingleTextureEffect::~GrSingleTextureEffect() {
}
+void GrSingleTextureEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
+ // If the input alpha is 0xff and the texture has no alpha channel, then the output alpha is
+ // 0xff
+ if ((*validFlags & kA_ValidComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
+ GrPixelConfigIsOpaque(fTextureAccess.getTexture()->config())) {
+ *validFlags = kA_ValidComponentFlag;
+ } else {
+ *validFlags = 0;
+ }
+}
+
const GrBackendEffectFactory& GrSingleTextureEffect::getFactory() const {
return GrTBackendEffectFactory<GrSingleTextureEffect>::getInstance();
}
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index fca5e93858..b732913c38 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -35,6 +35,10 @@ public:
static const char* Name() { return "Single Texture"; }
+ /** Note that if this class is sub-classed, the subclass may have to override this function.
+ */
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
const SkMatrix& getMatrix() const { return fMatrix; }
typedef GrGLSingleTextureEffect GLEffect;