Clean up GrQuad ctors
Refactor Sk4f transformations into reusable internal function.
Switches the SkRect+SkMatrix ctor to a factory method.
Adds simple constructors for Sk4fs and SkRects w/o transforms.
Bug: skia:
Change-Id: I88a4a5f7304b1cf00d68c7772bb0fc19c97abee3
Reviewed-on: https://skia-review.googlesource.com/c/191569
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/gpu/GrQuad.cpp b/src/gpu/GrQuad.cpp
index 0996ec7..8898f18 100644
--- a/src/gpu/GrQuad.cpp
+++ b/src/gpu/GrQuad.cpp
@@ -91,6 +91,53 @@
return !SkScalarIsInt(ql) || !SkScalarIsInt(qr) || !SkScalarIsInt(qt) || !SkScalarIsInt(qb);
}
+static void map_rect_translate_scale(const SkRect& rect, const SkMatrix& m,
+ Sk4f* xs, Sk4f* ys) {
+ SkMatrix::TypeMask tm = m.getType();
+ SkASSERT(tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
+
+ Sk4f r = Sk4f::Load(&rect);
+ if (tm > SkMatrix::kIdentity_Mask) {
+ const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
+ if (tm <= SkMatrix::kTranslate_Mask) {
+ r += t;
+ } else {
+ const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
+ r = r * s + t;
+ }
+ }
+ *xs = SkNx_shuffle<0, 0, 2, 2>(r);
+ *ys = SkNx_shuffle<1, 3, 1, 3>(r);
+}
+
+static void map_quad_general(const Sk4f& qx, const Sk4f& qy, const SkMatrix& m,
+ Sk4f* xs, Sk4f* ys, Sk4f* ws) {
+ static constexpr auto fma = SkNx_fma<4, float>;
+ *xs = fma(m.getScaleX(), qx, fma(m.getSkewX(), qy, m.getTranslateX()));
+ *ys = fma(m.getSkewY(), qx, fma(m.getScaleY(), qy, m.getTranslateY()));
+ if (m.hasPerspective()) {
+ Sk4f w = fma(m.getPerspX(), qx, fma(m.getPerspY(), qy, m.get(SkMatrix::kMPersp2)));
+ if (ws) {
+ // Output the calculated w coordinates
+ *ws = w;
+ } else {
+ // Apply perspective division immediately
+ Sk4f iw = w.invert();
+ *xs *= iw;
+ *ys *= iw;
+ }
+ } else if (ws) {
+ *ws = 1.f;
+ }
+}
+
+static void map_rect_general(const SkRect& rect, const SkMatrix& matrix,
+ Sk4f* xs, Sk4f* ys, Sk4f* ws) {
+ Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
+ Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
+ map_quad_general(rx, ry, matrix, xs, ys, ws);
+}
+
template <typename Q>
void GrResolveAATypeForQuad(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags,
const Q& quad, GrQuadType knownType,
@@ -146,41 +193,15 @@
}
}
-GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
+GrQuad GrQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
+ Sk4f x, y;
SkMatrix::TypeMask tm = m.getType();
if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
- auto r = Sk4f::Load(&rect);
- const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
- if (tm <= SkMatrix::kTranslate_Mask) {
- r += t;
- } else {
- const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
- r = r * s + t;
- }
- SkNx_shuffle<0, 0, 2, 2>(r).store(fX);
- SkNx_shuffle<1, 3, 1, 3>(r).store(fY);
+ map_rect_translate_scale(rect, m, &x, &y);
} else {
- Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
- Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
- Sk4f sx(m.getScaleX());
- Sk4f kx(m.getSkewX());
- Sk4f tx(m.getTranslateX());
- Sk4f ky(m.getSkewY());
- Sk4f sy(m.getScaleY());
- Sk4f ty(m.getTranslateY());
- auto x = SkNx_fma(sx, rx, SkNx_fma(kx, ry, tx));
- auto y = SkNx_fma(ky, rx, SkNx_fma(sy, ry, ty));
- if (m.hasPerspective()) {
- Sk4f w0(m.getPerspX());
- Sk4f w1(m.getPerspY());
- Sk4f w2(m.get(SkMatrix::kMPersp2));
- auto iw = SkNx_fma(w0, rx, SkNx_fma(w1, ry, w2)).invert();
- x *= iw;
- y *= iw;
- }
- x.store(fX);
- y.store(fY);
+ map_rect_general(rect, m, &x, &y, nullptr);
}
+ return GrQuad(x, y);
}
bool GrQuad::aaHasEffectOnRect() const {
@@ -188,43 +209,6 @@
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
}
-GrPerspQuad::GrPerspQuad(const SkRect& rect, const SkMatrix& m) {
- SkMatrix::TypeMask tm = m.getType();
- if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
- auto r = Sk4f::Load(&rect);
- const Sk4f t(m.getTranslateX(), m.getTranslateY(), m.getTranslateX(), m.getTranslateY());
- if (tm <= SkMatrix::kTranslate_Mask) {
- r += t;
- } else {
- const Sk4f s(m.getScaleX(), m.getScaleY(), m.getScaleX(), m.getScaleY());
- r = r * s + t;
- }
- SkNx_shuffle<0, 0, 2, 2>(r).store(fX);
- SkNx_shuffle<1, 3, 1, 3>(r).store(fY);
- fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
- } else {
- Sk4f rx(rect.fLeft, rect.fLeft, rect.fRight, rect.fRight);
- Sk4f ry(rect.fTop, rect.fBottom, rect.fTop, rect.fBottom);
- Sk4f sx(m.getScaleX());
- Sk4f kx(m.getSkewX());
- Sk4f tx(m.getTranslateX());
- Sk4f ky(m.getSkewY());
- Sk4f sy(m.getScaleY());
- Sk4f ty(m.getTranslateY());
- SkNx_fma(sx, rx, SkNx_fma(kx, ry, tx)).store(fX);
- SkNx_fma(ky, rx, SkNx_fma(sy, ry, ty)).store(fY);
- if (m.hasPerspective()) {
- Sk4f w0(m.getPerspX());
- Sk4f w1(m.getPerspY());
- Sk4f w2(m.get(SkMatrix::kMPersp2));
- auto w = SkNx_fma(w0, rx, SkNx_fma(w1, ry, w2));
- w.store(fW);
- } else {
- fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
- }
- }
-}
-
// Private constructor used by GrQuadList to quickly fill in a quad's values from the channel arrays
GrPerspQuad::GrPerspQuad(const float* xs, const float* ys, const float* ws) {
memcpy(fX, xs, 4 * sizeof(float));
@@ -232,6 +216,18 @@
memcpy(fW, ws, 4 * sizeof(float));
}
+GrPerspQuad GrPerspQuad::MakeFromRect(const SkRect& rect, const SkMatrix& m) {
+ Sk4f x, y, w;
+ SkMatrix::TypeMask tm = m.getType();
+ if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
+ map_rect_translate_scale(rect, m, &x, &y);
+ w = 1.f;
+ } else {
+ map_rect_general(rect, m, &x, &y, &w);
+ }
+ return GrPerspQuad(x, y, w);
+}
+
bool GrPerspQuad::aaHasEffectOnRect() const {
SkASSERT(this->quadType() == GrQuadType::kRect);
// If rect, ws must all be 1s so no need to divide
diff --git a/src/gpu/GrQuad.h b/src/gpu/GrQuad.h
index 33fd326..c754d5a 100644
--- a/src/gpu/GrQuad.h
+++ b/src/gpu/GrQuad.h
@@ -61,13 +61,18 @@
: fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
, fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {}
- /** Sets the quad to the rect as transformed by the matrix. */
- GrQuad(const SkRect&, const SkMatrix&);
+ GrQuad(const Sk4f& xs, const Sk4f& ys) {
+ xs.store(fX);
+ ys.store(fY);
+ }
explicit GrQuad(const SkPoint pts[4])
: fX{pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX}
, fY{pts[0].fY, pts[1].fY, pts[2].fY, pts[3].fY} {}
+ /** Sets the quad to the rect as transformed by the matrix. */
+ static GrQuad MakeFromRect(const SkRect&, const SkMatrix&);
+
GrQuad& operator=(const GrQuad& that) = default;
SkPoint point(int i) const { return {fX[i], fY[i]}; }
@@ -102,7 +107,23 @@
public:
GrPerspQuad() = default;
- GrPerspQuad(const SkRect&, const SkMatrix&);
+ explicit GrPerspQuad(const SkRect& rect)
+ : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight}
+ , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom}
+ , fW{1.f, 1.f, 1.f, 1.f} {}
+
+ GrPerspQuad(const Sk4f& xs, const Sk4f& ys) {
+ xs.store(fX);
+ ys.store(fY);
+ fW[0] = fW[1] = fW[2] = fW[3] = 1.f;
+ }
+ GrPerspQuad(const Sk4f& xs, const Sk4f& ys, const Sk4f& ws) {
+ xs.store(fX);
+ ys.store(fY);
+ ws.store(fW);
+ }
+
+ static GrPerspQuad MakeFromRect(const SkRect&, const SkMatrix&);
GrPerspQuad& operator=(const GrPerspQuad&) = default;
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 427ab9a..7d5918b 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -598,7 +598,7 @@
}
// The clip region in the rect's local space, so the test becomes the local rect containing
// the quad's points.
- GrQuad quad(rtRect, invM);
+ GrQuad quad = GrQuad::MakeFromRect(rtRect, invM);
if (!rect_contains_inclusive(rect, quad.point(0)) ||
!rect_contains_inclusive(rect, quad.point(1)) ||
!rect_contains_inclusive(rect, quad.point(2)) ||
diff --git a/src/gpu/ops/GrDashOp.cpp b/src/gpu/ops/GrDashOp.cpp
index e493607..ca97f29 100644
--- a/src/gpu/ops/GrDashOp.cpp
+++ b/src/gpu/ops/GrDashOp.cpp
@@ -162,7 +162,7 @@
SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f;
SkScalar centerX = SkScalarHalf(endInterval);
- vertices.writeQuad(GrQuad(rect, matrix),
+ vertices.writeQuad(GrQuad::MakeFromRect(rect, matrix),
GrVertexWriter::TriStripFromRect(dashRect),
intervalLength,
radius,
@@ -175,7 +175,7 @@
rectParam.set(halfOffLen + 0.5f, -halfStroke + 0.5f,
halfOffLen + startInterval - 0.5f, halfStroke - 0.5f);
- vertices.writeQuad(GrQuad(rect, matrix),
+ vertices.writeQuad(GrQuad::MakeFromRect(rect, matrix),
GrVertexWriter::TriStripFromRect(dashRect),
intervalLength,
rectParam);
@@ -586,7 +586,7 @@
draws[i].fLineLength, draws[i].fHalfDevStroke, draws[i].fIntervals[0],
draws[i].fIntervals[1], draws[i].fStrokeWidth, capType);
} else {
- vertices.writeQuad(GrQuad(rects[rectIndex], geom.fSrcRotInv));
+ vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv));
}
}
rectIndex++;
@@ -599,7 +599,7 @@
draws[i].fIntervals[0], draws[i].fHalfDevStroke, draws[i].fIntervals[0],
draws[i].fIntervals[1], draws[i].fStrokeWidth, capType);
} else {
- vertices.writeQuad(GrQuad(rects[rectIndex], geom.fSrcRotInv));
+ vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv));
}
}
rectIndex++;
@@ -612,7 +612,7 @@
draws[i].fIntervals[0], draws[i].fHalfDevStroke, draws[i].fIntervals[0],
draws[i].fIntervals[1], draws[i].fStrokeWidth, capType);
} else {
- vertices.writeQuad(GrQuad(rects[rectIndex], geom.fSrcRotInv));
+ vertices.writeQuad(GrQuad::MakeFromRect(rects[rectIndex], geom.fSrcRotInv));
}
}
rectIndex++;
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index bdf1a2e..8dcec21 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -204,7 +204,8 @@
void* vertices = vdata;
if (fHelper.isTrivial()) {
SkASSERT(fLocalQuads.count() == 0); // No local coords, so send an ignored dummy quad
- static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty(), SkMatrix::I());
+ static const GrPerspQuad kIgnoredLocal(SkRect::MakeEmpty());
+
for (int i = 0; i < this->quadCount(); ++i) {
const ColorAndAA& info = fDeviceQuads.metadata(i);
vertices = GrQuadPerEdgeAA::Tessellate(vertices, vertexSpec, fDeviceQuads[i],
@@ -340,9 +341,10 @@
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
+ GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
- GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
- GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
+ GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
+ GrPerspQuad(rect), GrQuadType::kRect);
}
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrRecordingContext* context,
@@ -353,10 +355,11 @@
const SkMatrix& localMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
+ GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
- GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
- GrPerspQuad(rect, localMatrix), localQuadType);
+ GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
+ GrPerspQuad::MakeFromRect(rect, localMatrix), localQuadType);
}
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrRecordingContext* context,
@@ -367,9 +370,10 @@
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencilSettings) {
+ GrQuadType dstQuadType = GrQuadTypeForTransformedRect(viewMatrix);
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
- GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
- GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
+ GrPerspQuad::MakeFromRect(rect, viewMatrix), dstQuadType,
+ GrPerspQuad(localRect), GrQuadType::kRect);
}
std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
@@ -385,21 +389,23 @@
paint.setColor4f(quads[0].fColor);
std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
- quads[0].fAAFlags, stencilSettings, GrPerspQuad(quads[0].fRect, viewMatrix),
- deviceQuadType, GrPerspQuad(quads[0].fRect, quads[0].fLocalMatrix),
+ quads[0].fAAFlags, stencilSettings,
+ GrPerspQuad::MakeFromRect(quads[0].fRect, viewMatrix), deviceQuadType,
+ GrPerspQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
GrQuadTypeForTransformedRect(quads[0].fLocalMatrix));
auto* fillRects = op->cast<FillRectOp>();
// Accumulate remaining quads similar to onCombineIfPossible() without creating an op
for (int i = 1; i < cnt; ++i) {
- GrPerspQuad deviceQuad(quads[i].fRect, viewMatrix);
+ GrPerspQuad deviceQuad = GrPerspQuad::MakeFromRect(quads[i].fRect, viewMatrix);
GrAAType resolvedAA;
GrQuadAAFlags resolvedEdgeFlags;
GrResolveAATypeForQuad(aaType, quads[i].fAAFlags, deviceQuad, deviceQuadType,
&resolvedAA, &resolvedEdgeFlags);
- fillRects->addQuad(deviceQuad, GrPerspQuad(quads[i].fRect, quads[i].fLocalMatrix),
+ fillRects->addQuad(deviceQuad,
+ GrPerspQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
GrQuadTypeForTransformedRect(quads[i].fLocalMatrix), quads[i].fColor,
resolvedEdgeFlags,resolvedAA);
}
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index eb3ee7a..7d7e7c8 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -760,8 +760,7 @@
};
if (fUsesDistanceField && !ctm.hasPerspective()) {
- GrQuad quad(translatedBounds, ctm);
- vertices.writeQuad(quad,
+ vertices.writeQuad(GrQuad::MakeFromRect(translatedBounds, ctm),
color,
texCoords);
} else {
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 8d44a43..e3c75ce 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -87,7 +87,7 @@
texRect.fTop = h - texRect.fTop;
texRect.fBottom = h - texRect.fBottom;
}
- return GrPerspQuad(texRect, SkMatrix::I());
+ return GrPerspQuad(texRect);
}
/**
@@ -201,7 +201,7 @@
, fFilter(static_cast<unsigned>(filter))
, fFinalized(0) {
GrQuadType quadType = GrQuadTypeForTransformedRect(viewMatrix);
- auto quad = GrPerspQuad(dstRect, viewMatrix);
+ auto quad = GrPerspQuad::MakeFromRect(dstRect, viewMatrix);
// Clean up disparities between the overall aa type and edge configuration and apply
// optimizations based on the rect and matrix when appropriate
@@ -264,7 +264,7 @@
if (!fProxies[p].fProxy->canSkipResourceAllocator()) {
fCanSkipAllocatorGather = static_cast<unsigned>(false);
}
- auto quad = GrPerspQuad(set[p].fDstRect, viewMatrix);
+ auto quad = GrPerspQuad::MakeFromRect(set[p].fDstRect, viewMatrix);
bounds.joinPossiblyEmptyRect(quad.bounds(quadType));
GrQuadAAFlags aaFlags;
// Don't update the overall aaType, might be inappropriate for some of the quads
diff --git a/tests/GrQuadListTest.cpp b/tests/GrQuadListTest.cpp
index fd88dde..fbbfab7 100644
--- a/tests/GrQuadListTest.cpp
+++ b/tests/GrQuadListTest.cpp
@@ -30,7 +30,7 @@
}
static GrPerspQuad make_2d_persp_quad() {
- return GrPerspQuad(SkRect::MakeLTRB(5.f, 6.f, 7.f, 8.f), SkMatrix::I());
+ return GrPerspQuad(SkRect::MakeLTRB(5.f, 6.f, 7.f, 8.f));
}
static bool is_2d_persp_quad(const GrPerspQuad& quad) {
return quad.x(0) == 5.f && quad.x(1) == 5.f && quad.x(2) == 7.f && quad.x(3) == 7.f &&
@@ -43,7 +43,7 @@
SkMatrix p = SkMatrix::I();
p[SkMatrix::kMPersp2] = 13.f;
SkASSERT(p.hasPerspective()); // Sanity check
- return GrPerspQuad(SkRect::MakeLTRB(9.f, 10.f, 11.f, 12.f), p);
+ return GrPerspQuad::MakeFromRect(SkRect::MakeLTRB(9.f, 10.f, 11.f, 12.f), p);
}
static bool is_3d_persp_quad(const GrPerspQuad& quad) {
return quad.x(0) == 9.f && quad.x(1) == 9.f && quad.x(2) == 11.f && quad.x(3) == 11.f &&