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/SkPictureShader.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/SkPictureShader.cpp')
-rw-r--r-- | src/core/SkPictureShader.cpp | 125 |
1 files changed, 79 insertions, 46 deletions
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp index 15df3a37a5..1e9507190c 100644 --- a/src/core/SkPictureShader.cpp +++ b/src/core/SkPictureShader.cpp @@ -55,9 +55,9 @@ void SkPictureShader::flatten(SkWriteBuffer& buffer) const { } } -bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { +SkShader* SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { if (!fPicture || (0 == fPicture->width() && 0 == fPicture->height())) { - return false; + return NULL; } SkMatrix m; @@ -78,17 +78,20 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { SkISize tileSize = scaledSize.toRound(); if (tileSize.isEmpty()) { - return false; + return NULL; } // The actual scale, compensating for rounding. SkSize tileScale = SkSize::Make(SkIntToScalar(tileSize.width()) / fPicture->width(), SkIntToScalar(tileSize.height()) / fPicture->height()); - if (!fCachedShader || tileScale != fCachedTileScale) { + SkAutoMutexAcquire ama(fCachedBitmapShaderMutex); + + if (!fCachedBitmapShader || tileScale != fCachedTileScale || + this->getLocalMatrix() != fCachedLocalMatrix) { SkBitmap bm; if (!bm.allocN32Pixels(tileSize.width(), tileSize.height())) { - return false; + return NULL; } bm.eraseColor(SK_ColorTRANSPARENT); @@ -96,66 +99,96 @@ bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const { canvas.scale(tileScale.width(), tileScale.height()); canvas.drawPicture(*fPicture); - fCachedShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); + fCachedBitmapShader.reset(CreateBitmapShader(bm, fTmx, fTmy)); fCachedTileScale = tileScale; - } + fCachedLocalMatrix = this->getLocalMatrix(); - SkMatrix shaderMatrix = this->getLocalMatrix(); - shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); - fCachedShader->setLocalMatrix(shaderMatrix); + SkMatrix shaderMatrix = this->getLocalMatrix(); + shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height()); + fCachedBitmapShader->setLocalMatrix(shaderMatrix); + } - return true; + // Increment the ref counter inside the mutex to ensure the returned pointer is still valid. + // Otherwise, the pointer may have been overwritten on a different thread before the object's + // ref count was incremented. + fCachedBitmapShader.get()->ref(); + return fCachedBitmapShader; } -bool SkPictureShader::setContext(const SkBitmap& device, - const SkPaint& paint, - const SkMatrix& matrix) { - if (!this->buildBitmapShader(matrix)) { - return false; +SkShader* SkPictureShader::validInternal(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const { + if (!this->INHERITED::validContext(device, paint, matrix, totalInverse)) { + return NULL; } - if (!this->INHERITED::setContext(device, paint, matrix)) { - return false; + SkShader* bitmapShader = this->buildBitmapShader(matrix); + if (!bitmapShader) { + return NULL; } - SkASSERT(fCachedShader); - if (!fCachedShader->setContext(device, paint, matrix)) { - this->INHERITED::endContext(); - return false; + if (!bitmapShader->validContext(device, paint, matrix)) { + bitmapShader->unref(); + return NULL; } - return true; + return bitmapShader; } -void SkPictureShader::endContext() { - SkASSERT(fCachedShader); - fCachedShader->endContext(); - - this->INHERITED::endContext(); +bool SkPictureShader::validContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, SkMatrix* totalInverse) const { + SkAutoTUnref<SkShader> shader(this->validInternal(device, paint, matrix, totalInverse)); + return shader != NULL; } -uint32_t SkPictureShader::getFlags() { - if (NULL != fCachedShader) { - return fCachedShader->getFlags(); +SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint, + const SkMatrix& matrix, void* storage) const { + SkShader* bitmapShader = this->validInternal(device, paint, matrix, NULL); + if (!bitmapShader) { + return NULL; } - return 0; + + return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext, + (*this, device, paint, matrix, bitmapShader)); } -SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) { - if (fCachedShader) { - return fCachedShader->asAShadeProc(ctx); - } - return NULL; +size_t SkPictureShader::contextSize() const { + return sizeof(PictureShaderContext); +} + +SkPictureShader::PictureShaderContext::PictureShaderContext( + const SkPictureShader& shader, const SkBitmap& device, + const SkPaint& paint, const SkMatrix& matrix, SkShader* bitmapShader) + : INHERITED(shader, device, paint, matrix) + , fBitmapShader(bitmapShader) +{ + SkASSERT(fBitmapShader); + fBitmapShaderContextStorage = sk_malloc_throw(fBitmapShader->contextSize()); + fBitmapShaderContext = fBitmapShader->createContext( + device, paint, matrix, fBitmapShaderContextStorage); + SkASSERT(fBitmapShaderContext); +} + +SkPictureShader::PictureShaderContext::~PictureShaderContext() { + fBitmapShaderContext->SkShader::Context::~Context(); + sk_free(fBitmapShaderContextStorage); +} + +uint32_t SkPictureShader::PictureShaderContext::getFlags() const { + return fBitmapShaderContext->getFlags(); +} + +SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) { + return fBitmapShaderContext->asAShadeProc(ctx); } -void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) { - SkASSERT(fCachedShader); - fCachedShader->shadeSpan(x, y, dstC, count); +void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) { + SkASSERT(fBitmapShaderContext); + fBitmapShaderContext->shadeSpan(x, y, dstC, count); } -void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) { - SkASSERT(fCachedShader); - fCachedShader->shadeSpan16(x, y, dstC, count); +void SkPictureShader::PictureShaderContext::shadeSpan16(int x, int y, uint16_t dstC[], int count) { + SkASSERT(fBitmapShaderContext); + fBitmapShaderContext->shadeSpan16(x, y, dstC, count); } #ifndef SK_IGNORE_TO_STRING @@ -176,10 +209,10 @@ void SkPictureShader::toString(SkString* str) const { #if SK_SUPPORT_GPU GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const { - if (!this->buildBitmapShader(context->getMatrix())) { + SkAutoTUnref<SkShader> bitmapShader(this->buildBitmapShader(context->getMatrix())); + if (!bitmapShader) { return NULL; } - SkASSERT(fCachedShader); - return fCachedShader->asNewEffect(context, paint); + return bitmapShader->asNewEffect(context, paint); } #endif |