diff options
author | Florin Malita <fmalita@chromium.org> | 2017-05-10 15:26:44 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-05-11 13:38:53 +0000 |
commit | 87f807136c216f5db12568afc2e5c8e893b99ef1 (patch) | |
tree | 1625d2b629a5edf49278f939fc80c0a41f6dd07a /src/core/SkBitmapDevice.cpp | |
parent | 4a41355057ce3b4488e2055f4b6544441a06bcfe (diff) |
A8 fast path for raster clip masks
When the clip mask is already A8, we don't need to convert explicitly.
Before:
792.72 clipmask_a8 8888
After:
560.06 clipmask_a8 8888
BUG=skia:6005
Change-Id: I9a319df9a82edfc9b412787a36f037bbe82c2825
Reviewed-on: https://skia-review.googlesource.com/16420
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/core/SkBitmapDevice.cpp')
-rw-r--r-- | src/core/SkBitmapDevice.cpp | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index f6286210aa..981273ad9d 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -388,6 +388,30 @@ void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPain /////////////////////////////////////////////////////////////////////////////// +namespace { + +class SkAutoDeviceClipRestore { +public: + SkAutoDeviceClipRestore(SkBaseDevice* device, const SkIRect& clip) + : fDevice(device) + , fPrevCTM(device->ctm()) { + fDevice->save(); + fDevice->setCTM(SkMatrix::I()); + fDevice->clipRect(SkRect::Make(clip), SkClipOp::kIntersect, false); + fDevice->setCTM(fPrevCTM); + } + + ~SkAutoDeviceClipRestore() { + fDevice->restore(fPrevCTM); + } + +private: + SkBaseDevice* fDevice; + const SkMatrix fPrevCTM; +}; + +} // anonymous ns + void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPaint& origPaint, SkImage* clipImage, const SkMatrix& clipMatrix) { SkASSERT(!src->isTextureBacked()); @@ -430,7 +454,6 @@ void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPain } const SkMatrix totalMatrix = SkMatrix::Concat(this->ctm(), clipMatrix); - SkRect clipBounds; totalMatrix.mapRect(&clipBounds, SkRect::Make(clipImage->bounds())); const SkIRect srcBounds = srcImage->bounds().makeOffset(x, y); @@ -440,18 +463,40 @@ void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPain return; } - sk_sp<SkSurface> surf = SkSurface::MakeRaster(SkImageInfo::MakeA8(maskBounds.width(), - maskBounds.height())); - SkCanvas* canvas = surf->getCanvas(); - canvas->translate(-maskBounds.x(), -maskBounds.y()); - canvas->concat(totalMatrix); - canvas->drawImage(clipImage, 0, 0); - sk_sp<SkImage> mask = surf->makeImageSnapshot(); + sk_sp<SkImage> mask; + SkMatrix maskMatrix, shaderMatrix; + SkTLazy<SkAutoDeviceClipRestore> autoClipRestore; + + SkMatrix totalInverse; + if (clipImage->isAlphaOnly() && totalMatrix.invert(&totalInverse)) { + // If the mask is already in A8 format, we can draw it directly + // (while compensating in the shader matrix). + mask = sk_ref_sp(clipImage); + maskMatrix = totalMatrix; + shaderMatrix = SkMatrix::Concat(totalInverse, SkMatrix::MakeTrans(x, y)); + + // If the mask is not fully contained within the src layer, we must clip. + if (!srcBounds.contains(clipBounds)) { + autoClipRestore.init(this, srcBounds); + } - const SkMatrix m = SkMatrix::MakeTrans(x - maskBounds.x(), y - maskBounds.y()); - paint.writable()->setShader(srcImage->makeShader(&m)); + maskBounds.offsetTo(0, 0); + } else { + // Otherwise, we convert the mask to A8 explicitly. + sk_sp<SkSurface> surf = SkSurface::MakeRaster(SkImageInfo::MakeA8(maskBounds.width(), + maskBounds.height())); + SkCanvas* canvas = surf->getCanvas(); + canvas->translate(-maskBounds.x(), -maskBounds.y()); + canvas->concat(totalMatrix); + canvas->drawImage(clipImage, 0, 0); + + mask = surf->makeImageSnapshot(); + maskMatrix = SkMatrix::I(); + shaderMatrix = SkMatrix::MakeTrans(x - maskBounds.x(), y - maskBounds.y()); + } - SkAutoDeviceCTMRestore adctmr(this, SkMatrix::I()); + SkAutoDeviceCTMRestore adctmr(this, maskMatrix); + paint.writable()->setShader(srcImage->makeShader(&shaderMatrix)); this->drawImage(mask.get(), maskBounds.x(), maskBounds.y(), *paint); } |