From bbfe4541ef154696313374de2130b1ac90e28482 Mon Sep 17 00:00:00 2001 From: "commit-bot@chromium.org" Date: Thu, 24 Oct 2013 01:46:11 +0000 Subject: [PATCH] Apply matrix early in draw bitmap Committed: http://code.google.com/p/skia/source/detail?r=11930 Reverted: https://code.google.com/p/skia/source/detail?r=11932 R=robertphillips@google.com, senorblanco@chromium.org Author: bsalomon@google.com Review URL: https://codereview.chromium.org/30593003 git-svn-id: http://skia.googlecode.com/svn/trunk@11933 2bbb7eff-a529-9590-31e7-b0007b416f81 --- expectations/gm/ignored-tests.txt | 2 + gm/imagefiltersgraph.cpp | 86 ++++++++++++++++++++++++++++++- include/gpu/SkGpuDevice.h | 2 - src/core/SkImageFilterUtils.cpp | 9 ++-- src/gpu/SkGpuDevice.cpp | 35 ++++++------- 5 files changed, 109 insertions(+), 25 deletions(-) diff --git a/expectations/gm/ignored-tests.txt b/expectations/gm/ignored-tests.txt index 561ac6b474..2c38df0438 100644 --- a/expectations/gm/ignored-tests.txt +++ b/expectations/gm/ignored-tests.txt @@ -31,3 +31,5 @@ # ('Poppler random failures'): ignore any Poppler failures, for now pdf-poppler +# Added by bsalomon, test case added in https://codereview.chromium.org/30593003 +imagefiltersgraph \ No newline at end of file diff --git a/gm/imagefiltersgraph.cpp b/gm/imagefiltersgraph.cpp index 363a4147e9..98f82f5340 100644 --- a/gm/imagefiltersgraph.cpp +++ b/gm/imagefiltersgraph.cpp @@ -7,22 +7,88 @@ #include "gm.h" +#include "SkArithmeticMode.h" #include "SkBitmapSource.h" #include "SkBlurImageFilter.h" #include "SkColorFilter.h" #include "SkColorMatrixFilter.h" #include "SkColorFilterImageFilter.h" +#include "SkFlattenableBuffers.h" #include "SkMergeImageFilter.h" #include "SkMorphologyImageFilter.h" +#include "SkOnce.h" #include "SkXfermodeImageFilter.h" #include "SkTestImageFilters.h" /////////////////////////////////////////////////////////////////////////////// +namespace { +// More closely models how Blink's OffsetFilter works as of 10/23/13. SkOffsetImageFilter doesn't +// perform a draw and this one does. +class SimpleOffsetFilter : public SkImageFilter { +public: + SimpleOffsetFilter(SkScalar dx, SkScalar dy, SkImageFilter* input) + : SkImageFilter(input), fDX(dx), fDY(dy) {} + + virtual bool onFilterImage(Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, + SkBitmap* dst, SkIPoint* offset) SK_OVERRIDE { + SkBitmap source = src; + SkImageFilter* input = getInput(0); + SkIPoint srcOffset = SkIPoint::Make(0, 0); + if (NULL != input && !input->filterImage(proxy, src, ctm, &source, &srcOffset)) { + return false; + } + + SkIRect bounds; + source.getBounds(&bounds); + + if (!this->applyCropRect(&bounds, ctm)) { + return false; + } + + SkAutoTUnref device(proxy->createDevice(bounds.width(), bounds.height())); + SkCanvas canvas(device); + SkPaint paint; + paint.setXfermodeMode(SkXfermode::kSrc_Mode); + canvas.drawBitmap(source, fDX - bounds.left(), fDY - bounds.top(), &paint); + *dst = device->accessBitmap(false); + offset->fX += bounds.left(); + offset->fY += bounds.top(); + return true; + } + + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SimpleOffsetFilter); + +protected: + explicit SimpleOffsetFilter(SkFlattenableReadBuffer& buffer) + : SkImageFilter(buffer) { + fDX = buffer.readScalar(); + fDY = buffer.readScalar(); + } + + virtual void flatten(SkFlattenableWriteBuffer& buffer) const SK_OVERRIDE { + this->SkImageFilter::flatten(buffer); + buffer.writeScalar(fDX); + buffer.writeScalar(fDY); + } + +private: + SkScalar fDX, fDY; +}; +} + +static void init_flattenable(int*) { + SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SimpleOffsetFilter) +} + class ImageFiltersGraphGM : public skiagm::GM { public: - ImageFiltersGraphGM() : fInitialized(false) {} + ImageFiltersGraphGM() : fInitialized(false) { + int dummy; + SK_DECLARE_STATIC_ONCE(once); + SkOnce(&once, init_flattenable, &dummy); + } protected: virtual SkString onShortName() { @@ -43,7 +109,7 @@ protected: canvas.drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint); } - virtual SkISize onISize() { return SkISize::Make(200, 100); } + virtual SkISize onISize() { return SkISize::Make(500, 150); } virtual void onDraw(SkCanvas* canvas) { if (!fInitialized) { @@ -81,6 +147,22 @@ protected: paint.setImageFilter(blendColor); canvas->drawBitmap(fBitmap, 100, 0, &paint); } + { + SkScalar matrix[20] = { SK_Scalar1, 0, 0, 0, 0, + 0, SK_Scalar1, 0, 0, 0, + 0, 0, SK_Scalar1, 0, 0, + 0, 0, 0, SkFloatToScalar(0.5f), 0 }; + SkColorMatrixFilter matrixCF(matrix); + SkAutoTUnref matrixFilter(SkColorFilterImageFilter::Create(&matrixCF)); + SimpleOffsetFilter offsetFilter(SkIntToScalar(10), SkIntToScalar(10), matrixFilter); + + SkAutoTUnref arith(SkArithmeticMode::Create(0, SK_Scalar1, SK_Scalar1, 0)); + SkXfermodeImageFilter arithFilter(arith, matrixFilter, &offsetFilter); + + SkPaint paint; + paint.setImageFilter(&arithFilter); + canvas->drawSprite(fBitmap, 200, 0, &paint); + } } private: diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h index 5d669e40fd..debfd37170 100644 --- a/include/gpu/SkGpuDevice.h +++ b/include/gpu/SkGpuDevice.h @@ -191,13 +191,11 @@ private: const SkRect* srcRectPtr) const; void internalDrawBitmap(const SkBitmap&, const SkRect&, - const SkMatrix&, const GrTextureParams& params, const SkPaint& paint, SkCanvas::DrawBitmapRectFlags flags); void drawTiledBitmap(const SkBitmap& bitmap, const SkRect& srcRect, - const SkMatrix& m, const GrTextureParams& params, const SkPaint& paint, SkCanvas::DrawBitmapRectFlags flags); diff --git a/src/core/SkImageFilterUtils.cpp b/src/core/SkImageFilterUtils.cpp index a4ce51eb91..8385fb446a 100644 --- a/src/core/SkImageFilterUtils.cpp +++ b/src/core/SkImageFilterUtils.cpp @@ -23,6 +23,11 @@ bool SkImageFilterUtils::WrapTexture(GrTexture* texture, int width, int height, bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter::Proxy* proxy, const SkBitmap& src, const SkMatrix& ctm, SkBitmap* result, SkIPoint* offset) { + // Ensure that GrContext calls under filterImage and filterImageGPU below will see an identity + // matrix with no clip and that the matrix, clip, and render target set before this function was + // called are restored before we return to the caller. + GrContext* context = src.getTexture()->getContext(); + GrContext::AutoWideOpenIdentityDraw awoid(context, NULL); if (!filter) { *result = src; return true; @@ -31,9 +36,7 @@ bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter: } else { if (filter->filterImage(proxy, src, ctm, result, offset)) { if (!result->getTexture()) { - GrContext* context = ((GrTexture *) src.getTexture())->getContext(); - GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, - *result, NULL); + GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL); result->setPixelRef(new SkGrPixelRef(resultTex))->unref(); GrUnlockAndUnrefCachedBitmapTexture(resultTex); } diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 47ddd521cb..6617989848 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1164,6 +1164,8 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, return; } + fContext->concatMatrix(m); + GrTextureParams params; SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel(); GrTextureParams::FilterMode textureFilterMode; @@ -1195,9 +1197,9 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) { // take the simple case - this->internalDrawBitmap(bitmap, srcRect, m, params, paint, flags); + this->internalDrawBitmap(bitmap, srcRect, params, paint, flags); } else { - this->drawTiledBitmap(bitmap, srcRect, m, params, paint, flags); + this->drawTiledBitmap(bitmap, srcRect, params, paint, flags); } } @@ -1205,7 +1207,6 @@ void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, // been determined to be too large to fit in VRAM void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, const SkRect& srcRect, - const SkMatrix& m, const GrTextureParams& params, const SkPaint& paint, SkCanvas::DrawBitmapRectFlags flags) { @@ -1226,9 +1227,8 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, if (!fContext->getClip()->fClipStack->intersectRectWithClip(&clipRect)) { return; } - SkMatrix matrix, inverse; - matrix.setConcat(fContext->getMatrix(), m); - if (!matrix.invert(&inverse)) { + SkMatrix inverse; + if (!fContext->getMatrix().invert(&inverse)) { return; } inverse.mapRect(&clipRect); @@ -1278,10 +1278,11 @@ void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, if (bitmap.extractSubset(&tmpB, iTileR)) { // now offset it to make it "local" to our tmp bitmap tileR.offset(-offset.fX, -offset.fY); - SkMatrix tmpM(m); - tmpM.preTranslate(offset.fX, offset.fY); - - this->internalDrawBitmap(tmpB, tileR, tmpM, params, paint, flags); + SkMatrix tmpM; + tmpM.setTranslate(offset.fX, offset.fY); + GrContext::AutoMatrix am; + am.setPreConcat(fContext, tmpM); + this->internalDrawBitmap(tmpB, tileR, params, paint, flags); } } } @@ -1338,7 +1339,6 @@ static bool may_color_bleed(const SkRect& srcRect, */ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, const SkRect& srcRect, - const SkMatrix& m, const GrTextureParams& params, const SkPaint& paint, SkCanvas::DrawBitmapRectFlags flags) { @@ -1366,19 +1366,18 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, // Need texture domain if drawing a sub rect. needsTextureDomain = srcRect.width() < bitmap.width() || srcRect.height() < bitmap.height(); - if (needsTextureDomain && m.rectStaysRect() && fContext->getMatrix().rectStaysRect()) { + if (needsTextureDomain && fContext->getMatrix().rectStaysRect()) { + const SkMatrix& matrix = fContext->getMatrix(); // sampling is axis-aligned SkRect transformedRect; - SkMatrix srcToDeviceMatrix(m); - srcToDeviceMatrix.postConcat(fContext->getMatrix()); - srcToDeviceMatrix.mapRect(&transformedRect, srcRect); - + matrix.mapRect(&transformedRect, srcRect); + if (has_aligned_samples(srcRect, transformedRect)) { // We could also turn off filtering here (but we already did a cache lookup with // params). needsTextureDomain = false; } else { - needsTextureDomain = may_color_bleed(srcRect, transformedRect, m); + needsTextureDomain = may_color_bleed(srcRect, transformedRect, matrix); } } } @@ -1421,7 +1420,7 @@ void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, return; } - fContext->drawRectToRect(grPaint, dstRect, paintRect, &m); + fContext->drawRectToRect(grPaint, dstRect, paintRect, NULL); } static bool filter_texture(SkBaseDevice* device, GrContext* context,