Revert of Revert of Extract most of the mutable state of SkShader into a separate Context object. (https://codereview.chromium.org/249643002/)
Reason for revert:
Chromium side change landed along side DEPS roll that includes r14323.
Original issue's description:
> Revert of Extract most of the mutable state of SkShader into a separate Context object. (https://codereview.chromium.org/207683004/)
>
> Reason for revert:
> This is blocking the DEPS roll into Chromium. Failures can be seen here:
>
> http://build.chromium.org/p/tryserver.chromium/builders/android_dbg/builds/174333
>
> Original issue's description:
> > 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
> >
> > Committed: http://code.google.com/p/skia/source/detail?r=14216
> >
> > Committed: http://code.google.com/p/skia/source/detail?r=14323
>
> TBR=scroggo@google.com,skyostil@chromium.org,tomhudson@chromium.org,senorblanco@chromium.org,reed@google.com,bungeman@google.com,dominikg@chromium.org
> NOTREECHECKS=true
> NOTRY=true
> BUG=skia:1976
>
> Committed: http://code.google.com/p/skia/source/detail?r=14326
R=scroggo@google.com, skyostil@chromium.org, tomhudson@chromium.org, senorblanco@chromium.org, reed@google.com, bungeman@google.com, dominikg@chromium.org
TBR=bungeman@google.com, dominikg@chromium.org, reed@google.com, scroggo@google.com, senorblanco@chromium.org, skyostil@chromium.org, tomhudson@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=skia:1976
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/246403013
git-svn-id: http://skia.googlecode.com/svn/trunk@14328 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index bf31285..dc5c90b 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -49,7 +49,7 @@
fPicture->flatten(buffer);
}
-bool SkPictureShader::buildBitmapShader(const SkMatrix& matrix) const {
+SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix) const {
SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);
SkMatrix m;
@@ -70,17 +70,20 @@
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);
@@ -88,66 +91,91 @@
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());
+ fCachedBitmapShader->setLocalMatrix(shaderMatrix);
}
- SkMatrix shaderMatrix = this->getLocalMatrix();
- shaderMatrix.preScale(1 / tileScale.width(), 1 / tileScale.height());
- fCachedShader->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;
+ SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(matrix));
+ if (!bitmapShader || !bitmapShader->validContext(device, paint, matrix)) {
+ return NULL;
}
- SkASSERT(fCachedShader);
- if (!fCachedShader->setContext(device, paint, matrix)) {
- this->INHERITED::endContext();
- return false;
+ return bitmapShader.detach();
+}
+
+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;
+}
+
+SkShader::Context* SkPictureShader::createContext(const SkBitmap& device, const SkPaint& paint,
+ const SkMatrix& matrix, void* storage) const {
+ SkAutoTUnref<SkShader> bitmapShader(this->validInternal(device, paint, matrix, NULL));
+ if (!bitmapShader) {
+ return NULL;
}
- return true;
+ return SkNEW_PLACEMENT_ARGS(storage, PictureShaderContext,
+ (*this, device, paint, matrix, bitmapShader.detach()));
}
-void SkPictureShader::endContext() {
- SkASSERT(fCachedShader);
- fCachedShader->endContext();
-
- this->INHERITED::endContext();
+size_t SkPictureShader::contextSize() const {
+ return sizeof(PictureShaderContext);
}
-uint32_t SkPictureShader::getFlags() {
- if (NULL != fCachedShader) {
- return fCachedShader->getFlags();
- }
- return 0;
+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);
}
-SkShader::ShadeProc SkPictureShader::asAShadeProc(void** ctx) {
- if (fCachedShader) {
- return fCachedShader->asAShadeProc(ctx);
- }
- return NULL;
+SkPictureShader::PictureShaderContext::~PictureShaderContext() {
+ fBitmapShaderContext->~Context();
+ sk_free(fBitmapShaderContextStorage);
}
-void SkPictureShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan(x, y, dstC, count);
+uint32_t SkPictureShader::PictureShaderContext::getFlags() const {
+ return fBitmapShaderContext->getFlags();
}
-void SkPictureShader::shadeSpan16(int x, int y, uint16_t dstC[], int count) {
- SkASSERT(fCachedShader);
- fCachedShader->shadeSpan16(x, y, dstC, count);
+SkShader::Context::ShadeProc SkPictureShader::PictureShaderContext::asAShadeProc(void** ctx) {
+ return fBitmapShaderContext->asAShadeProc(ctx);
+}
+
+void SkPictureShader::PictureShaderContext::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
+ SkASSERT(fBitmapShaderContext);
+ fBitmapShaderContext->shadeSpan(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
@@ -168,10 +196,10 @@
#if SK_SUPPORT_GPU
GrEffectRef* SkPictureShader::asNewEffect(GrContext* context, const SkPaint& paint) const {
- if (!this->buildBitmapShader(context->getMatrix())) {
+ SkAutoTUnref<SkShader> bitmapShader(this->refBitmapShader(context->getMatrix()));
+ if (!bitmapShader) {
return NULL;
}
- SkASSERT(fCachedShader);
- return fCachedShader->asNewEffect(context, paint);
+ return bitmapShader->asNewEffect(context, paint);
}
#endif