diff options
author | 2014-04-16 10:16:39 +0000 | |
---|---|---|
committer | 2014-04-16 10:16:39 +0000 | |
commit | 001f4ed2fb62ecdc98ce2884d925de11b7516d23 (patch) | |
tree | 1acb3cdef582b7a33a97e6c6631c62320ca39331 /src/core/SkBlitter.cpp | |
parent | d1061e254af7fa8267dc1a5ed444d1c4b1743b6d (diff) |
Extract most of the mutable state of SkShader into a separate Context object.
SkShader currently stores some state during draw calls via setContext(...).
Move that mutable state into a separate SkShader::Context class that is
constructed on demand for the duration of the draw.
Calls to setContext() are replaced with createContext() which returns a context
corresponding to the shader object or NULL if the parameters to createContext
are invalid.
TEST=out/Debug/dm
BUG=skia:1976
R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com
Author: dominikg@chromium.org
Review URL: https://codereview.chromium.org/207683004
git-svn-id: http://skia.googlecode.com/svn/trunk@14216 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkBlitter.cpp')
-rw-r--r-- | src/core/SkBlitter.cpp | 277 |
1 files changed, 180 insertions, 97 deletions
diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index 52a05eded8..ad51874271 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -26,6 +26,15 @@ SkBlitter::~SkBlitter() {} bool SkBlitter::isNullBlitter() const { return false; } +bool SkBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) { + return true; +} + +SkShader::Context* SkBlitter::getShaderContext() const { + return NULL; +} + const SkBitmap* SkBlitter::justAnOpaqueColor(uint32_t* value) { return NULL; } @@ -568,102 +577,149 @@ class Sk3DShader : public SkShader { public: Sk3DShader(SkShader* proxy) : fProxy(proxy) { SkSafeRef(proxy); - fMask = NULL; } virtual ~Sk3DShader() { SkSafeUnref(fProxy); } - void setMask(const SkMask* mask) { fMask = mask; } + virtual size_t contextSize() const SK_OVERRIDE { + size_t size = sizeof(Sk3DShaderContext); + if (fProxy) { + size += fProxy->contextSize(); + } + return size; + } - virtual bool setContext(const SkBitmap& device, const SkPaint& paint, - const SkMatrix& matrix) SK_OVERRIDE { - if (!this->INHERITED::setContext(device, paint, matrix)) { + virtual bool validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse = NULL) const + SK_OVERRIDE + { + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { return false; } if (fProxy) { - if (!fProxy->setContext(device, paint, matrix)) { - // must keep our set/end context calls balanced - this->INHERITED::endContext(); - return false; - } - } else { - fPMColor = SkPreMultiplyColor(paint.getColor()); + return fProxy->validContext(device, paint, matrix); } return true; } - virtual void endContext() SK_OVERRIDE { + virtual SkShader::Context* createContext(const SkBitmap& device, + const SkPaint& paint, + const SkMatrix& matrix, + void* storage) const SK_OVERRIDE + { + if (!this->validContext(device, paint, matrix)) { + return NULL; + } + + SkShader::Context* proxyContext; if (fProxy) { - fProxy->endContext(); + char* proxyContextStorage = (char*) storage + sizeof(Sk3DShaderContext); + proxyContext = fProxy->createContext(device, paint, matrix, proxyContextStorage); + SkASSERT(proxyContext); + } else { + proxyContext = NULL; } - this->INHERITED::endContext(); + return SkNEW_PLACEMENT_ARGS(storage, Sk3DShaderContext, (*this, device, paint, matrix, + proxyContext)); } - virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE { - if (fProxy) { - fProxy->shadeSpan(x, y, span, count); + class Sk3DShaderContext : public SkShader::Context { + public: + // Calls proxyContext's destructor but will NOT free its memory. + Sk3DShaderContext(const Sk3DShader& shader, const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkShader::Context* proxyContext) + : INHERITED(shader, device, paint, matrix) + , fMask(NULL) + , fProxyContext(proxyContext) + { + if (!fProxyContext) { + fPMColor = SkPreMultiplyColor(paint.getColor()); + } } - if (fMask == NULL) { - if (fProxy == NULL) { - sk_memset32(span, fPMColor, count); + virtual ~Sk3DShaderContext() { + if (fProxyContext) { + fProxyContext->SkShader::Context::~Context(); } - return; } - SkASSERT(fMask->fBounds.contains(x, y)); - SkASSERT(fMask->fBounds.contains(x + count - 1, y)); + void setMask(const SkMask* mask) { fMask = mask; } - size_t size = fMask->computeImageSize(); - const uint8_t* alpha = fMask->getAddr8(x, y); - const uint8_t* mulp = alpha + size; - const uint8_t* addp = mulp + size; + virtual void shadeSpan(int x, int y, SkPMColor span[], int count) SK_OVERRIDE { + if (fProxyContext) { + fProxyContext->shadeSpan(x, y, span, count); + } - if (fProxy) { - for (int i = 0; i < count; i++) { - if (alpha[i]) { - SkPMColor c = span[i]; - if (c) { - unsigned a = SkGetPackedA32(c); - unsigned r = SkGetPackedR32(c); - unsigned g = SkGetPackedG32(c); - unsigned b = SkGetPackedB32(c); + if (fMask == NULL) { + if (fProxyContext == NULL) { + sk_memset32(span, fPMColor, count); + } + return; + } + SkASSERT(fMask->fBounds.contains(x, y)); + SkASSERT(fMask->fBounds.contains(x + count - 1, y)); + + size_t size = fMask->computeImageSize(); + const uint8_t* alpha = fMask->getAddr8(x, y); + const uint8_t* mulp = alpha + size; + const uint8_t* addp = mulp + size; + + if (fProxyContext) { + for (int i = 0; i < count; i++) { + if (alpha[i]) { + SkPMColor c = span[i]; + if (c) { + unsigned a = SkGetPackedA32(c); + unsigned r = SkGetPackedR32(c); + unsigned g = SkGetPackedG32(c); + unsigned b = SkGetPackedB32(c); + + unsigned mul = SkAlpha255To256(mulp[i]); + unsigned add = addp[i]; + + r = SkFastMin32(SkAlphaMul(r, mul) + add, a); + g = SkFastMin32(SkAlphaMul(g, mul) + add, a); + b = SkFastMin32(SkAlphaMul(b, mul) + add, a); + + span[i] = SkPackARGB32(a, r, g, b); + } + } else { + span[i] = 0; + } + } + } else { // color + unsigned a = SkGetPackedA32(fPMColor); + unsigned r = SkGetPackedR32(fPMColor); + unsigned g = SkGetPackedG32(fPMColor); + unsigned b = SkGetPackedB32(fPMColor); + for (int i = 0; i < count; i++) { + if (alpha[i]) { unsigned mul = SkAlpha255To256(mulp[i]); unsigned add = addp[i]; - r = SkFastMin32(SkAlphaMul(r, mul) + add, a); - g = SkFastMin32(SkAlphaMul(g, mul) + add, a); - b = SkFastMin32(SkAlphaMul(b, mul) + add, a); - - span[i] = SkPackARGB32(a, r, g, b); + span[i] = SkPackARGB32( a, + SkFastMin32(SkAlphaMul(r, mul) + add, a), + SkFastMin32(SkAlphaMul(g, mul) + add, a), + SkFastMin32(SkAlphaMul(b, mul) + add, a)); + } else { + span[i] = 0; } - } else { - span[i] = 0; - } - } - } else { // color - unsigned a = SkGetPackedA32(fPMColor); - unsigned r = SkGetPackedR32(fPMColor); - unsigned g = SkGetPackedG32(fPMColor); - unsigned b = SkGetPackedB32(fPMColor); - for (int i = 0; i < count; i++) { - if (alpha[i]) { - unsigned mul = SkAlpha255To256(mulp[i]); - unsigned add = addp[i]; - - span[i] = SkPackARGB32( a, - SkFastMin32(SkAlphaMul(r, mul) + add, a), - SkFastMin32(SkAlphaMul(g, mul) + add, a), - SkFastMin32(SkAlphaMul(b, mul) + add, a)); - } else { - span[i] = 0; } } } - } + + private: + // Unowned. + const SkMask* fMask; + // Memory is unowned, but we need to call the destructor. + SkShader::Context* fProxyContext; + SkPMColor fPMColor; + + typedef SkShader::Context INHERITED; + }; #ifndef SK_IGNORE_TO_STRING virtual void toString(SkString* str) const SK_OVERRIDE { @@ -685,29 +741,30 @@ public: protected: Sk3DShader(SkReadBuffer& buffer) : INHERITED(buffer) { fProxy = buffer.readShader(); - fPMColor = buffer.readColor(); - fMask = NULL; + // Leaving this here until we bump the picture version, though this + // shader should never be recorded. + buffer.readColor(); } virtual void flatten(SkWriteBuffer& buffer) const SK_OVERRIDE { this->INHERITED::flatten(buffer); buffer.writeFlattenable(fProxy); - buffer.writeColor(fPMColor); + // Leaving this here until we bump the picture version, though this + // shader should never be recorded. + buffer.writeColor(SkColor()); } private: SkShader* fProxy; - SkPMColor fPMColor; - const SkMask* fMask; typedef SkShader INHERITED; }; class Sk3DBlitter : public SkBlitter { public: - Sk3DBlitter(SkBlitter* proxy, Sk3DShader* shader) + Sk3DBlitter(SkBlitter* proxy, Sk3DShader::Sk3DShaderContext* shaderContext) : fProxy(proxy) - , f3DShader(SkRef(shader)) + , f3DShaderContext(shaderContext) {} virtual void blitH(int x, int y, int width) { @@ -729,22 +786,22 @@ public: virtual void blitMask(const SkMask& mask, const SkIRect& clip) { if (mask.fFormat == SkMask::k3D_Format) { - f3DShader->setMask(&mask); + f3DShaderContext->setMask(&mask); ((SkMask*)&mask)->fFormat = SkMask::kA8_Format; fProxy->blitMask(mask, clip); ((SkMask*)&mask)->fFormat = SkMask::k3D_Format; - f3DShader->setMask(NULL); + f3DShaderContext->setMask(NULL); } else { fProxy->blitMask(mask, clip); } } private: - // fProxy is unowned. It will be deleted by SkSmallAllocator. - SkBlitter* fProxy; - SkAutoTUnref<Sk3DShader> f3DShader; + // Both pointers are unowned. They will be deleted by SkSmallAllocator. + SkBlitter* fProxy; + Sk3DShader::Sk3DShaderContext* f3DShaderContext; }; /////////////////////////////////////////////////////////////////////////////// @@ -754,8 +811,7 @@ private: 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)) { + if (NULL == shader) { return true; } } @@ -893,16 +949,22 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, } /* - * We need to have balanced calls to the shader: - * setContext - * endContext - * We make the first call here, in case it fails we can abort the draw. - * The endContext() call is made by the blitter (assuming setContext did - * not fail) in its destructor. + * We create a SkShader::Context object, and store it on the blitter. */ - if (shader && !shader->setContext(device, *paint, matrix)) { - blitter = allocator->createT<SkNullBlitter>(); - return blitter; + SkShader::Context* shaderContext; + if (shader) { + // Try to create the ShaderContext + void* storage = allocator->reserveT<SkShader::Context>(shader->contextSize()); + shaderContext = shader->createContext(device, *paint, matrix, storage); + if (!shaderContext) { + allocator->freeLast(); + blitter = allocator->createT<SkNullBlitter>(); + return blitter; + } + SkASSERT(shaderContext); + SkASSERT((void*) shaderContext == storage); + } else { + shaderContext = NULL; } @@ -913,19 +975,20 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, SkASSERT(NULL == paint->getXfermode()); blitter = allocator->createT<SkA8_Coverage_Blitter>(device, *paint); } else if (shader) { - blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint); + blitter = allocator->createT<SkA8_Shader_Blitter>(device, *paint, shaderContext); } else { blitter = allocator->createT<SkA8_Blitter>(device, *paint); } break; case kRGB_565_SkColorType: - blitter = SkBlitter_ChooseD565(device, *paint, allocator); + blitter = SkBlitter_ChooseD565(device, *paint, shaderContext, allocator); break; case kN32_SkColorType: if (shader) { - blitter = allocator->createT<SkARGB32_Shader_Blitter>(device, *paint); + blitter = allocator->createT<SkARGB32_Shader_Blitter>( + device, *paint, shaderContext); } else if (paint->getColor() == SK_ColorBLACK) { blitter = allocator->createT<SkARGB32_Black_Blitter>(device, *paint); } else if (paint->getAlpha() == 0xFF) { @@ -944,7 +1007,9 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, if (shader3D) { SkBlitter* innerBlitter = blitter; // innerBlitter was allocated by allocator, which will delete it. - blitter = allocator->createT<Sk3DBlitter>(innerBlitter, shader3D); + // We know shaderContext is of type Sk3DShaderContext because it belongs to shader3D. + blitter = allocator->createT<Sk3DBlitter>(innerBlitter, + static_cast<Sk3DShader::Sk3DShaderContext*>(shaderContext)); } return blitter; } @@ -956,18 +1021,36 @@ const uint32_t gMask_00FF00FF = 0xFF00FF; /////////////////////////////////////////////////////////////////////////////// -SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint) - : INHERITED(device) { - fShader = paint.getShader(); +SkShaderBlitter::SkShaderBlitter(const SkBitmap& device, const SkPaint& paint, + SkShader::Context* shaderContext) + : INHERITED(device) + , fShader(paint.getShader()) + , fShaderContext(shaderContext) { SkASSERT(fShader); - SkASSERT(fShader->setContextHasBeenCalled()); + SkASSERT(fShaderContext); fShader->ref(); - fShaderFlags = fShader->getFlags(); + fShaderFlags = fShaderContext->getFlags(); } SkShaderBlitter::~SkShaderBlitter() { - SkASSERT(fShader->setContextHasBeenCalled()); - fShader->endContext(); fShader->unref(); } + +bool SkShaderBlitter::resetShaderContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix) { + if (!fShader->validContext(device, paint, matrix)) { + return false; + } + + // Only destroy the old context if we have a new one. We need to ensure to have a + // live context in fShaderContext because the storage is owned by an SkSmallAllocator + // outside of this class. + // The new context will be of the same size as the old one because we use the same + // shader to create it. It is therefore safe to re-use the storage. + fShaderContext->SkShader::Context::~Context(); + fShaderContext = fShader->createContext(device, paint, matrix, (void*)fShaderContext); + SkASSERT(fShaderContext); + + return true; +} |