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 <brianosman@google.com>
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
Michael Ludwig 2021-05-06 10:23:24 -04:00 committed by Skia Commit-Bot
parent 9176a65eff
commit b32708a507
8 changed files with 40 additions and 38 deletions

View File

@ -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) {

View File

@ -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.

View File

@ -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) {

View File

@ -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<SkShader> 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);
}

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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())) {