From b32708a507c98702293221a5dbb79b0bcfbd4fac Mon Sep 17 00:00:00 2001 From: Michael Ludwig Date: Thu, 6 May 2021 10:23:24 -0400 Subject: [PATCH] Use SkM44 for SkDevice's device-to-global transform The device-to-global transforms are used to determine image filter mappings, so this is necessary dependency on updating skif::Mapping to SkM44. It's also just a step towards removing SkMatrix in general. Some usages of the device-to-global transforms were able to use the new MapRect function and stay in SkM44 land. Other usages just pushed the conversion to M33 lower (until they themselves can be updated). Bug: skia:11726 Change-Id: Ia7f8ac3472f948f4a183a995b06352388914f237 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/405199 Reviewed-by: Brian Osman Reviewed-by: Mike Reed Commit-Queue: Michael Ludwig --- src/core/SkBitmapDevice.cpp | 4 ++-- src/core/SkCanvas.cpp | 4 ++-- src/core/SkClipStackDevice.cpp | 3 ++- src/core/SkDevice.cpp | 39 ++++++++++++++++++---------------- src/core/SkDevice.h | 18 +++++++--------- src/gpu/SkGpuDevice.cpp | 4 ++-- src/gpu/SkGpuDevice.h | 4 ++-- src/pdf/SkPDFDevice.cpp | 2 +- 8 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 241b9381e4..32808ed563 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -677,8 +677,8 @@ void SkBitmapDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { void SkBitmapDevice::onReplaceClip(const SkIRect& rect) { // Transform from "global/canvas" coordinates to relative to this device - SkIRect deviceRect = this->globalToDevice().mapRect(SkRect::Make(rect)).round(); - fRCStack.replaceClip(deviceRect); + SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect)); + fRCStack.replaceClip(deviceRect.round()); } void SkBitmapDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) { diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index 833df7470f..8d0322c2ef 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -1595,8 +1595,8 @@ SkRect SkCanvas::computeDeviceClipBounds(bool outsetForAA) const { if (dev->onGetClipType() == SkBaseDevice::ClipType::kEmpty) { return SkRect::MakeEmpty(); } else { - SkRect devClipBounds = SkRect::Make(dev->devClipBounds()); - dev->deviceToGlobal().mapRect(&devClipBounds); + SkRect devClipBounds = + SkMatrixPriv::MapRect(dev->deviceToGlobal(), SkRect::Make(dev->devClipBounds())); if (outsetForAA) { // Expand bounds out by 1 in case we are anti-aliasing. We store the // bounds as floats to enable a faster quick reject implementation. diff --git a/src/core/SkClipStackDevice.cpp b/src/core/SkClipStackDevice.cpp index bcaf8944ca..7b4efe884b 100644 --- a/src/core/SkClipStackDevice.cpp +++ b/src/core/SkClipStackDevice.cpp @@ -55,7 +55,8 @@ void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { void SkClipStackDevice::onReplaceClip(const SkIRect& rect) { // FIXME When the deprecated clip ops are completely removed, SkClipStack will need to be // updated to have a better way of tracking replacement. - fClipStack.clipRect(SkRect::Make(rect), this->globalToDevice(), kReplace_SkClipOp, false); + fClipStack.clipRect(SkRect::Make(rect), this->globalToDevice().asM33(), + kReplace_SkClipOp, false); } void SkClipStackDevice::onSetDeviceClipRestriction(SkIRect* clipRestriction) { diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index 2143781ed4..bf9affc6d1 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -37,11 +37,11 @@ SkBaseDevice::SkBaseDevice(const SkImageInfo& info, const SkSurfaceProps& surfac : SkMatrixProvider(/* localToDevice = */ SkMatrix::I()) , fInfo(info) , fSurfaceProps(surfaceProps) { - fDeviceToGlobal.reset(); - fGlobalToDevice.reset(); + fDeviceToGlobal.setIdentity(); + fGlobalToDevice.setIdentity(); } -void SkBaseDevice::setDeviceCoordinateSystem(const SkMatrix& deviceToGlobal, +void SkBaseDevice::setDeviceCoordinateSystem(const SkM44& deviceToGlobal, const SkM44& localToDevice, int bufferOriginX, int bufferOriginY) { @@ -62,17 +62,18 @@ void SkBaseDevice::setDeviceCoordinateSystem(const SkMatrix& deviceToGlobal, void SkBaseDevice::setGlobalCTM(const SkM44& ctm) { fLocalToDevice = ctm; fLocalToDevice.normalizePerspective(); - if (!fGlobalToDevice.isIdentity()) { - // Map from the global CTM state to this device's coordinate system. - fLocalToDevice.postConcat(SkM44(fGlobalToDevice)); - } + // Map from the global CTM state to this device's coordinate system. + fLocalToDevice.postConcat(fGlobalToDevice); fLocalToDevice33 = fLocalToDevice.asM33(); } bool SkBaseDevice::isPixelAlignedToGlobal() const { - return fDeviceToGlobal.isTranslate() && - SkScalarIsInt(fDeviceToGlobal.getTranslateX()) && - SkScalarIsInt(fDeviceToGlobal.getTranslateY()); + // pixelAligned is set to the identity + integer translation of the device-to-global matrix. + // If they are equal then the device is by definition pixel aligned. + SkM44 pixelAligned = SkM44(); + pixelAligned.setRC(0, 3, SkScalarFloorToScalar(fDeviceToGlobal.rc(0, 3))); + pixelAligned.setRC(1, 3, SkScalarFloorToScalar(fDeviceToGlobal.rc(1, 3))); + return pixelAligned == fDeviceToGlobal; } SkIPoint SkBaseDevice::getOrigin() const { @@ -83,14 +84,14 @@ SkIPoint SkBaseDevice::getOrigin() const { // (e.g. Android's device-space clip regions are going away, and are not compatible with the // generalized device coordinate system). SkASSERT(this->isPixelAlignedToGlobal()); - return SkIPoint::Make(SkScalarFloorToInt(fDeviceToGlobal.getTranslateX()), - SkScalarFloorToInt(fDeviceToGlobal.getTranslateY())); + return SkIPoint::Make(SkScalarFloorToInt(fDeviceToGlobal.rc(0, 3)), + SkScalarFloorToInt(fDeviceToGlobal.rc(1, 3))); } SkMatrix SkBaseDevice::getRelativeTransform(const SkBaseDevice& dstDevice) const { // To get the transform from this space to the other device's, transform from our space to // global and then from global to the other device. - return SkMatrix::Concat(dstDevice.fGlobalToDevice, fDeviceToGlobal); + return (dstDevice.fGlobalToDevice * fDeviceToGlobal).asM33(); } bool SkBaseDevice::getLocalToMarker(uint32_t id, SkM44* localToMarker) const { @@ -542,8 +543,9 @@ void SkNoPixelsDevice::onClipRegion(const SkRegion& globalRgn, SkClipOp op) { deviceRgn.translate(-origin.fX, -origin.fY); this->writableClip().opRegion(deviceRgn, (SkRegion::Op) op); } else { - this->writableClip().opRect(SkRect::Make(globalRgn.getBounds()), this->globalToDevice(), - this->bounds(), (SkRegion::Op) op, false); + this->writableClip().opRect(SkRect::Make(globalRgn.getBounds()), + this->globalToDevice().asM33(), this->bounds(), + (SkRegion::Op) op, false); } } @@ -552,7 +554,7 @@ void SkNoPixelsDevice::onClipShader(sk_sp shader) { } void SkNoPixelsDevice::onReplaceClip(const SkIRect& rect) { - SkIRect deviceRect = this->globalToDevice().mapRect(SkRect::Make(rect)).round(); + SkIRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect)).round(); if (!deviceRect.intersect(this->bounds())) { deviceRect.setEmpty(); } @@ -564,8 +566,9 @@ void SkNoPixelsDevice::onSetDeviceClipRestriction(SkIRect* mutableClipRestrictio // The subset clip restriction is gone, so just store the actual device bounds as the limit fDeviceClipRestriction.setEmpty(); } else { - fDeviceClipRestriction = - this->globalToDevice().mapRect(SkRect::Make(*mutableClipRestriction)).round(); + fDeviceClipRestriction = SkMatrixPriv::MapRect(this->globalToDevice(), + SkRect::Make(*mutableClipRestriction)) + .round(); // Besides affecting future ops, it acts as an immediate intersection this->writableClip().opIRect(fDeviceClipRestriction, SkRegion::kIntersect_Op); } diff --git a/src/core/SkDevice.h b/src/core/SkDevice.h index d923bde5a1..dea58faaaa 100644 --- a/src/core/SkDevice.h +++ b/src/core/SkDevice.h @@ -15,6 +15,7 @@ #include "include/core/SkShader.h" #include "include/core/SkSurfaceProps.h" #include "include/private/SkNoncopyable.h" +#include "src/core/SkMatrixPriv.h" #include "src/core/SkMatrixProvider.h" #include "src/core/SkRasterClip.h" #include "src/shaders/SkShaderBase.h" @@ -27,7 +28,6 @@ class SkImageFilter; class SkImageFilterCache; struct SkIRect; class SkMarkerStack; -class SkMatrix; class SkRasterHandleAllocator; class SkSpecialImage; @@ -61,9 +61,7 @@ public: */ void getGlobalBounds(SkIRect* bounds) const { SkASSERT(bounds); - SkRect localBounds = SkRect::Make(this->bounds()); - fDeviceToGlobal.mapRect(&localBounds); - *bounds = localBounds.roundOut(); + *bounds = SkMatrixPriv::MapRect(fDeviceToGlobal, SkRect::Make(this->bounds())).roundOut(); } SkIRect getGlobalBounds() const { @@ -116,12 +114,12 @@ public: * into the global canvas' space (or root device space). This includes the translation * necessary to account for the device's origin. */ - const SkMatrix& deviceToGlobal() const { return fDeviceToGlobal; } + const SkM44& deviceToGlobal() const { return fDeviceToGlobal; } /** * Return the inverse of getDeviceToGlobal(), mapping from the global canvas' space (or root * device space) into this device's coordinate space. */ - const SkMatrix& globalToDevice() const { return fGlobalToDevice; } + const SkM44& globalToDevice() const { return fGlobalToDevice; } /** * DEPRECATED: This asserts that 'getDeviceToGlobal' is a translation matrix with integer * components. In the future some SkDevices will have more complex device-to-global transforms, @@ -439,12 +437,12 @@ private: // is anchored in the device space. The final device-to-global matrix stored by the SkDevice // will include a pre-translation by T(deviceOriginX, deviceOriginY), and the final // local-to-device matrix will have a post-translation of T(-deviceOriginX, -deviceOriginY). - void setDeviceCoordinateSystem(const SkMatrix& deviceToGlobal, const SkM44& localToDevice, + void setDeviceCoordinateSystem(const SkM44& deviceToGlobal, const SkM44& localToDevice, int bufferOriginX, int bufferOriginY); // Convenience to configure the device to be axis-aligned with the root canvas, but with a // unique origin. void setOrigin(const SkM44& globalCTM, int x, int y) { - this->setDeviceCoordinateSystem(SkMatrix::I(), globalCTM, x, y); + this->setDeviceCoordinateSystem(SkM44(), globalCTM, x, y); } virtual SkImageFilterCache* getImageFilterCache() { return nullptr; } @@ -461,8 +459,8 @@ private: const SkSurfaceProps fSurfaceProps; // fDeviceToGlobal and fGlobalToDevice are inverses of each other; there are never that many // SkDevices, so pay the memory cost to avoid recalculating the inverse. - SkMatrix fDeviceToGlobal; - SkMatrix fGlobalToDevice; + SkM44 fDeviceToGlobal; + SkM44 fGlobalToDevice; // fLocalToDevice (inherited from SkMatrixProvider) is the device CTM, not the global CTM // It maps from local space to the device's coordinate space. diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 98130037da..058f733f2d 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -275,11 +275,11 @@ void SkGpuDevice::onClipRegion(const SkRegion& globalRgn, SkClipOp op) { if (globalRgn.isEmpty()) { fClip.clipRect(SkMatrix::I(), SkRect::MakeEmpty(), aa, op); } else if (globalRgn.isRect()) { - fClip.clipRect(this->globalToDevice(), SkRect::Make(globalRgn.getBounds()), aa, op); + fClip.clipRect(this->globalToDevice().asM33(), SkRect::Make(globalRgn.getBounds()), aa, op); } else { SkPath path; globalRgn.getBoundaryPath(&path); - fClip.clipPath(this->globalToDevice(), path, aa, op); + fClip.clipPath(this->globalToDevice().asM33(), path, aa, op); } } diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index c27b381314..6d0baf14d9 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -143,8 +143,8 @@ protected: } void onReplaceClip(const SkIRect& rect) override { // Transform from "global/canvas" coordinates to relative to this device - SkIRect deviceRect = this->globalToDevice().mapRect(SkRect::Make(rect)).round(); - fClip.replaceClip(deviceRect); + SkRect deviceRect = SkMatrixPriv::MapRect(this->globalToDevice(), SkRect::Make(rect)); + fClip.replaceClip(deviceRect.round()); } void onClipRegion(const SkRegion& globalRgn, SkClipOp op) override; void onAsRgnClip(SkRegion*) const override; diff --git a/src/pdf/SkPDFDevice.cpp b/src/pdf/SkPDFDevice.cpp index c75dfac0e5..6be5ab7786 100644 --- a/src/pdf/SkPDFDevice.cpp +++ b/src/pdf/SkPDFDevice.cpp @@ -333,7 +333,7 @@ void SkPDFDevice::drawAnnotation(const SkRect& rect, const char key[], SkData* v } // Annotations are specified in absolute coordinates, so the page xform maps from device space // to the global space, and applies the document transform. - SkMatrix pageXform = this->deviceToGlobal(); + SkMatrix pageXform = this->deviceToGlobal().asM33(); pageXform.postConcat(fDocument->currentPageTransform()); if (rect.isEmpty()) { if (!strcmp(key, SkPDFGetNodeIdKey())) {