add shader flag kConstInY_Flag

this signals blitters that the shader will return the same results for a given
x value, independent of y. Useful inside blitRect(), where it can cache the
first call to shadeSpan() and reuse it on all subsequent scans. Works with
(non-rotated) linear-gradients, and Nx1 bitmaps.



git-svn-id: http://skia.googlecode.com/svn/trunk@214 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@android.com 2009-06-12 21:27:03 +00:00
parent b2c5f2d260
commit 5119bdb952
10 changed files with 96 additions and 19 deletions

View File

@ -29,14 +29,15 @@ public:
/** Create a ColorShader that will inherit its color from the Paint
at draw time.
*/
SkColorShader() : fInheritColor(true) {}
SkColorShader() : fFlags(0), fInheritColor(true) {}
/** Create a ColorShader that ignores the color in the paint, and uses the
specified color. Note: like all shaders, at draw time the paint's alpha
will be respected, and is applied to the specified color.
*/
SkColorShader(SkColor c) : fColor(c), fInheritColor(false) {}
SkColorShader(SkColor c) : fColor(c), fFlags(0), fInheritColor(false) {}
virtual uint32_t getFlags();
virtual uint32_t getFlags() { return fFlags; }
virtual uint8_t getSpan16Alpha() const;
virtual bool setContext(const SkBitmap& device, const SkPaint& paint,
const SkMatrix& matrix);
@ -54,6 +55,7 @@ private:
}
SkColor fColor; // ignored if fInheritColor is true
SkPMColor fPMColor; // cached after setContext()
uint32_t fFlags; // cached after setContext()
uint16_t fColor16; // cached after setContext()
SkBool8 fInheritColor;

View File

@ -63,14 +63,22 @@ public:
enum Flags {
//!< set if all of the colors will be opaque
kOpaqueAlpha_Flag = 0x01,
//! set if this shader's shadeSpan16() method can be called
kHasSpan16_Flag = 0x02,
/** Set this bit if the shader's native data type is instrinsically 16
bit, meaning that calling the 32bit shadeSpan() entry point will
mean the the impl has to up-sample 16bit data into 32bit. Used as a
a means of clearing a dither request if the it will have no effect
*/
kIntrinsicly16_Flag = 0x04
kIntrinsicly16_Flag = 0x04,
/** set (after setContext) if the spans only vary in X (const in Y).
e.g. an Nx1 bitmap that is being tiled in Y, or a linear-gradient
that varies from left-to-right
*/
kConstInY_Flag = 0x08
};
/** Called sometimes before drawing with this shader.

View File

@ -9,6 +9,19 @@
#include "SkShader.h"
#include "SkUtils.h"
static void show_ramp(SkCanvas* canvas, const SkRect& r) {
SkPoint pts[] = { r.fLeft, 0, r.fRight, 0 };
SkColor colors[] = { SK_ColorRED, SK_ColorBLUE };
SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2,
SkShader::kRepeat_TileMode);
SkPaint p;
p.setShader(s)->unref();
canvas->drawRect(r, p);
canvas->translate(r.width() + SkIntToScalar(8), 0);
p.setDither(true);
canvas->drawRect(r, p);
}
class TestGLView : public SkView {
public:
TestGLView() {
@ -49,6 +62,9 @@ protected:
canvas->translate(r.width() + SkIntToScalar(20), 0);
paint.setStrokeWidth(SkIntToScalar(5));
canvas->drawRect(r, paint);
canvas->translate(r.width() * 10/9, 0);
show_ramp(canvas, r);
}
private:

View File

@ -67,6 +67,11 @@ void SkBitmapProcShader::flatten(SkFlattenableWriteBuffer& buffer) {
buffer.write8(fState.fTileModeY);
}
static bool only_scale_and_translate(const SkMatrix& matrix) {
unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
return (matrix.getType() & ~mask) == 0;
}
bool SkBitmapProcShader::setContext(const SkBitmap& device,
const SkPaint& paint,
const SkMatrix& matrix) {
@ -117,6 +122,12 @@ bool SkBitmapProcShader::setContext(const SkBitmap& device,
default:
break;
}
// if we're only 1-pixel heigh, and we don't rotate, then we can claim this
if (1 == fState.fBitmap->height() &&
only_scale_and_translate(this->getTotalInverse())) {
fFlags |= kConstInY_Flag;
}
return true;
}

View File

@ -977,17 +977,16 @@ const uint32_t gMask_00FF00FF = 0xFF00FF;
//////////////////////////////////////////////////////////////////////////////////////////////////////
SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint)
: INHERITED(device)
{
: INHERITED(device) {
fShader = paint.getShader();
SkASSERT(fShader);
fShader->ref();
fShader->beginSession();
fShaderFlags = fShader->getFlags();
}
SkShaderBlitter::~SkShaderBlitter()
{
SkShaderBlitter::~SkShaderBlitter() {
fShader->endSession();
fShader->unref();
}

View File

@ -483,7 +483,7 @@ void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) {
SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device,
const SkPaint& paint)
: SkRGB16_Shader_Blitter(device, paint) {
SkASSERT(SkShader::CanCallShadeSpan16(fShader->getFlags()));
SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags));
}
void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) SK_RESTRICT {
@ -569,7 +569,7 @@ SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device,
// compute SkBlitRow::Procs
unsigned flags = 0;
uint32_t shaderFlags = fShader->getFlags();
uint32_t shaderFlags = fShaderFlags;
// shaders take care of global alpha, so we never set it in SkBlitRow
if (!(shaderFlags & SkShader::kOpaqueAlpha_Flag)) {
flags |= SkBlitRow::kSrcPixelAlpha_Flag;
@ -597,6 +597,30 @@ void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) {
fOpaqueProc(fDevice.getAddr16(x, y), fBuffer, width, 0xFF, x, y);
}
void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
SkShader* shader = fShader;
SkBlitRow::Proc proc = fOpaqueProc;
SkPMColor* buffer = fBuffer;
uint16_t* dst = fDevice.getAddr16(x, y);
size_t dstRB = fDevice.rowBytes();
if (fShaderFlags & SkShader::kConstInY_Flag) {
shader->shadeSpan(x, y, buffer, width);
do {
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
} else {
do {
shader->shadeSpan(x, y, buffer, width);
proc(dst, buffer, width, 0xFF, x, y);
y += 1;
dst = (uint16_t*)((char*)dst + dstRB);
} while (--height);
}
}
static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
int count = 0;
for (;;) {

View File

@ -38,7 +38,8 @@ public:
virtual ~SkShaderBlitter();
protected:
SkShader* fShader;
uint32_t fShaderFlags;
SkShader* fShader;
private:
// illegal
@ -192,7 +193,8 @@ public:
virtual ~SkRGB16_Shader_Blitter();
virtual void blitH(int x, int y, int width);
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
virtual void blitRect(int x, int y, int width, int height);
protected:
SkPMColor* fBuffer;
SkBlitRow::Proc fOpaqueProc;

View File

@ -210,6 +210,7 @@ SkShader* SkShader::CreateBitmapShader(const SkBitmap& src,
#include "SkUtils.h"
SkColorShader::SkColorShader(SkFlattenableReadBuffer& b) : INHERITED(b) {
fFlags = 0; // computed in setContext
fInheritColor = b.readU8();
if (fInheritColor) {
return;
@ -226,11 +227,6 @@ void SkColorShader::flatten(SkFlattenableWriteBuffer& buffer) {
buffer.write32(fColor);
}
uint32_t SkColorShader::getFlags() {
return (SkGetPackedA32(fPMColor) == 255 ? kOpaqueAlpha_Flag : 0) |
kHasSpan16_Flag;
}
uint8_t SkColorShader::getSpan16Alpha() const {
return SkGetPackedA32(fPMColor);
}
@ -267,6 +263,11 @@ bool SkColorShader::setContext(const SkBitmap& device, const SkPaint& paint,
}
fPMColor = SkPackARGB32(a, r, g, b);
fFlags = kHasSpan16_Flag | kConstInY_Flag;
if (SkGetPackedA32(fPMColor) == 255) {
fFlags |= kOpaqueAlpha_Flag;
}
return true;
}

View File

@ -620,6 +620,7 @@ public:
}
}
virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&);
virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
virtual void shadeSpan16(int x, int y, uint16_t dstC[], int count);
virtual bool asABitmap(SkBitmap*, SkMatrix*, TileMode*);
@ -646,6 +647,19 @@ private:
typedef Gradient_Shader INHERITED;
};
bool Linear_Gradient::setContext(const SkBitmap& device, const SkPaint& paint,
const SkMatrix& matrix) {
if (!this->INHERITED::setContext(device, paint, matrix)) {
return false;
}
unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask;
if ((fDstToIndex.getType() & ~mask) == 0) {
fFlags |= SkShader::kConstInY_Flag;
}
return true;
}
// Return true if fx, fx+dx, fx+2*dx, ... is always in range
static inline bool no_need_for_clamp(int fx, int dx, int count)
{

View File

@ -71,7 +71,7 @@
00A728270FD43D0400D5051F /* SampleMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6760FCCCB01002BD8B4 /* SampleMovie.cpp */; };
00A7282F0FD43D3700D5051F /* SkMovie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A7282D0FD43D3700D5051F /* SkMovie.cpp */; };
00A7295D0FD8397600D5051F /* SampleAll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2762F6740FCCCB01002BD8B4 /* SampleAll.cpp */; };
00A729650FD93ED600D5051F /* SampleTestGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A729630FD93ED600D5051F /* SampleTestGL.cpp */; };
00AF77B00FE2EA2D007F9650 /* SampleTestGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A729630FD93ED600D5051F /* SampleTestGL.cpp */; };
00C55DA10F8552DC000CAC09 /* SampleGradients.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */; };
00FF39140FC6ED2C00915187 /* SampleEffects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */; };
0156F80407C56A3000C6122B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0156F80307C56A3000C6122B /* Foundation.framework */; };
@ -569,8 +569,8 @@
00A728270FD43D0400D5051F /* SampleMovie.cpp in Sources */,
00A7282F0FD43D3700D5051F /* SkMovie.cpp in Sources */,
00A7295D0FD8397600D5051F /* SampleAll.cpp in Sources */,
00A729650FD93ED600D5051F /* SampleTestGL.cpp in Sources */,
000A99820FD97526007E45BD /* SampleArc.cpp in Sources */,
00AF77B00FE2EA2D007F9650 /* SampleTestGL.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};