Use DrawQuad struct to group device+local coords
This is part of a series to make it easier to manipulate the device and
local coordinates as the ops are being created. By instantiating a
single DrawQuad and allowing the functions to avoid having to copy the
GrQuads before making modifications (e.g. cropping, normalization,
or perspective clipping).
Bug: skia:9779
Change-Id: I0c6eefaee10638bc7483049d1993addeddc97005
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269141
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index ea78d13..655739f 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -605,17 +605,18 @@
GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization(
const GrClip& clip, const SkPMColor4f* constColor,
- const GrUserStencilSettings* stencilSettings, GrAA* aa, GrQuadAAFlags* edgeFlags,
- GrQuad* deviceQuad, GrQuad* localQuad) {
+ const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad) {
// Optimization requirements:
// 1. kDiscard applies when clip bounds and quad bounds do not intersect
- // 2. kClear applies when constColor and final geom is pixel aligned rect;
- // pixel aligned rect requires rect clip and (rect quad or quad covers clip)
- // 3. kRRect applies when constColor and rrect clip and quad covers clip
- // 4. kExplicitClip applies when rect clip and (rect quad or quad covers clip)
- // 5. kCropped applies when rect quad (currently)
- // 6. kNone always applies
- GrQuadAAFlags newFlags = *edgeFlags;
+ // 2a. kSubmitted applies when constColor and final geom is pixel aligned rect;
+ // pixel aligned rect requires rect clip and (rect quad or quad covers clip) OR
+ // 2b. kSubmitted applies when constColor and rrect clip and quad covers clip
+ // 4. kClipApplied applies when rect clip and (rect quad or quad covers clip)
+ // 5. kCropped in all other scenarios (although a crop may be a no-op)
+
+ // Save the old AA flags since CropToRect will modify 'quad' and if kCropped is returned, it's
+ // better to just keep the old flags instead of introducing mixed edge flags.
+ GrQuadAAFlags oldFlags = quad->fEdgeFlags;
SkRect rtRect;
if (stencilSettings) {
@@ -628,27 +629,25 @@
rtRect = SkRect::MakeWH(this->width(), this->height());
}
- SkRect drawBounds = deviceQuad->bounds();
+ SkRect drawBounds = quad->fDevice.bounds();
if (constColor) {
- // Don't bother updating local coordinates when the paint will ignore them anyways
- localQuad = nullptr;
// If the device quad is not finite, coerce into a finite quad. This is acceptable since it
// will be cropped to the finite 'clip' or render target and there is no local space mapping
- if (!deviceQuad->isFinite()) {
+ if (!quad->fDevice.isFinite()) {
for (int i = 0; i < 4; ++i) {
- if (!make_vertex_finite(deviceQuad->xs() + i) ||
- !make_vertex_finite(deviceQuad->ys() + i) ||
- !make_vertex_finite(deviceQuad->ws() + i)) {
+ if (!make_vertex_finite(quad->fDevice.xs() + i) ||
+ !make_vertex_finite(quad->fDevice.ys() + i) ||
+ !make_vertex_finite(quad->fDevice.ws() + i)) {
// Discard if we see a nan
return QuadOptimization::kDiscarded;
}
}
- SkASSERT(deviceQuad->isFinite());
+ SkASSERT(quad->fDevice.isFinite());
}
} else {
// CropToRect requires the quads to be finite. If they are not finite and we have local
// coordinates, the mapping from local space to device space is poorly defined so drop it
- if (!deviceQuad->isFinite()) {
+ if (!quad->fDevice.isFinite()) {
return QuadOptimization::kDiscarded;
}
}
@@ -684,11 +683,11 @@
if (clipRRect.isRect()) {
// No rounded corners, so the kClear and kExplicitClip optimizations are possible
- if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad)) {
+ if (GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /*compute local*/ !constColor)) {
if (!stencilSettings && constColor &&
- deviceQuad->quadType() == GrQuad::Type::kAxisAligned) {
+ quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
// Clear optimization is possible
- drawBounds = deviceQuad->bounds();
+ drawBounds = quad->fDevice.bounds();
if (drawBounds.contains(rtRect)) {
// Fullscreen clear
this->clear(nullptr, *constColor, CanClearFullscreen::kYes);
@@ -704,9 +703,8 @@
}
// Update overall AA setting.
- *edgeFlags = newFlags;
if (*aa == GrAA::kNo && clipAA == GrAA::kYes &&
- newFlags != GrQuadAAFlags::kNone) {
+ quad->fEdgeFlags != GrQuadAAFlags::kNone) {
// The clip was anti-aliased and now the draw needs to be upgraded to AA to
// properly reflect the smooth edge of the clip.
*aa = GrAA::kYes;
@@ -721,14 +719,15 @@
} else {
// The quads have been updated to better fit the clip bounds, but can't get rid of
// the clip entirely
+ quad->fEdgeFlags = oldFlags;
return QuadOptimization::kCropped;
}
} else if (!stencilSettings && constColor) {
// Rounded corners and constant filled color (limit ourselves to solid colors because
// there is no way to use custom local coordinates with drawRRect).
- if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad) &&
- deviceQuad->quadType() == GrQuad::Type::kAxisAligned &&
- deviceQuad->bounds().contains(clipBounds)) {
+ if (GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /* compute local */ false) &&
+ quad->fDevice.quadType() == GrQuad::Type::kAxisAligned &&
+ quad->fDevice.bounds().contains(clipBounds)) {
// Since the cropped quad became a rectangle which covered the bounds of the rrect,
// we can draw the rrect directly and ignore the edge flags
GrPaint paint;
@@ -738,6 +737,7 @@
return QuadOptimization::kSubmitted;
} else {
// The quad has been updated to better fit clip bounds, but can't remove the clip
+ quad->fEdgeFlags = oldFlags;
return QuadOptimization::kCropped;
}
}
@@ -755,7 +755,8 @@
// Even if this were to return true, the crop rect does not exactly match the clip, so can not
// report explicit-clip. Since these edges aren't visible, don't update the final edge flags.
- GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad);
+ GrQuadUtils::CropToRect(clipBounds, clipAA, quad, /* compute local */ !constColor);
+ quad->fEdgeFlags = oldFlags;
return QuadOptimization::kCropped;
}
@@ -763,9 +764,7 @@
void GrRenderTargetContext::drawFilledQuad(const GrClip& clip,
GrPaint&& paint,
GrAA aa,
- GrQuadAAFlags edgeFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const GrUserStencilSettings* ss) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
@@ -782,18 +781,15 @@
constColor = &paintColor;
}
- GrQuad croppedDeviceQuad = deviceQuad;
- GrQuad croppedLocalQuad = localQuad;
- QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, &edgeFlags,
- &croppedDeviceQuad, &croppedLocalQuad);
+ QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, quad);
if (opt >= QuadOptimization::kClipApplied) {
// These optimizations require caller to add an op themselves
const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
: clip;
GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone)
: this->chooseAAType(aa);
- this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
- croppedDeviceQuad, croppedLocalQuad, ss));
+ this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType,
+ quad, ss));
}
// All other optimization levels were completely handled inside attempt(), so no extra op needed
}
@@ -806,9 +802,7 @@
const SkPMColor4f& color,
SkBlendMode blendMode,
GrAA aa,
- GrQuadAAFlags edgeFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const SkRect* domain) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
@@ -820,10 +814,7 @@
// Functionally this is very similar to drawFilledQuad except that there's no constColor to
// enable the kSubmitted optimizations, no stencil settings support, and its a GrTextureOp.
- GrQuad croppedDeviceQuad = deviceQuad;
- GrQuad croppedLocalQuad = localQuad;
- QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr, nullptr, &aa, &edgeFlags,
- &croppedDeviceQuad, &croppedLocalQuad);
+ QuadOptimization opt = this->attemptQuadOptimization(clip, nullptr, nullptr, &aa, quad);
SkASSERT(opt != QuadOptimization::kSubmitted);
if (opt != QuadOptimization::kDiscarded) {
@@ -836,11 +827,10 @@
: GrTextureOp::Saturate::kNo;
// Use the provided domain, although hypothetically we could detect that the cropped local
// quad is sufficiently inside the domain and the constraint could be dropped.
- this->addDrawOp(
- finalClip,
- GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
- std::move(textureXform), filter, color, saturate, blendMode,
- aaType, edgeFlags, croppedDeviceQuad, croppedLocalQuad, domain));
+ this->addDrawOp(finalClip,
+ GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
+ std::move(textureXform), filter, color, saturate,
+ blendMode, aaType, quad, domain));
}
}
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 1799ee9..f1c74ae 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -174,9 +174,9 @@
const SkMatrix& viewMatrix,
const SkRect& rectToDraw,
const SkRect& localRect) {
- this->drawFilledQuad(clip, std::move(paint), aa,
- aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
- GrQuad::MakeFromRect(rectToDraw, viewMatrix), GrQuad(localRect));
+ DrawQuad quad{GrQuad::MakeFromRect(rectToDraw, viewMatrix), GrQuad(localRect),
+ aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone};
+ this->drawFilledQuad(clip, std::move(paint), aa, &quad);
}
/**
@@ -188,10 +188,10 @@
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkMatrix& localMatrix) {
- this->drawFilledQuad(clip, std::move(paint), aa,
- aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
- GrQuad::MakeFromRect(rect, viewMatrix),
- GrQuad::MakeFromRect(rect, localMatrix));
+ DrawQuad quad{GrQuad::MakeFromRect(rect, viewMatrix),
+ GrQuad::MakeFromRect(rect, localMatrix),
+ aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone};
+ this->drawFilledQuad(clip, std::move(paint), aa, &quad);
}
/**
@@ -204,8 +204,8 @@
const SkMatrix& viewMatrix, const SkRect& rect,
const SkRect* optionalLocalRect = nullptr) {
const SkRect& localRect = optionalLocalRect ? *optionalLocalRect : rect;
- this->drawFilledQuad(clip, std::move(paint), aa, edgeAA,
- GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(localRect));
+ DrawQuad quad{GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(localRect), edgeAA};
+ this->drawFilledQuad(clip, std::move(paint), aa, &quad);
}
/**
@@ -221,12 +221,12 @@
* necessary.
*/
void fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA,
- const SkMatrix& viewMatrix, const SkPoint quad[4],
- const SkPoint optionalLocalQuad[4]) {
- const SkPoint* localQuad = optionalLocalQuad ? optionalLocalQuad : quad;
- this->drawFilledQuad(clip, std::move(paint), aa, edgeAA,
- GrQuad::MakeFromSkQuad(quad, viewMatrix),
- GrQuad::MakeFromSkQuad(localQuad, SkMatrix::I()));
+ const SkMatrix& viewMatrix, const SkPoint points[4],
+ const SkPoint optionalLocalPoints[4]) {
+ const SkPoint* localPoints = optionalLocalPoints ? optionalLocalPoints : points;
+ DrawQuad quad{GrQuad::MakeFromSkQuad(points, viewMatrix),
+ GrQuad::MakeFromSkQuad(localPoints, SkMatrix::I()), edgeAA};
+ this->drawFilledQuad(clip, std::move(paint), aa, &quad);
}
/** Used with drawQuadSet */
@@ -254,9 +254,10 @@
sk_sp<GrColorSpaceXform> texXform) {
const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint ?
&srcRect : nullptr;
+ DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
+
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform),
- filter, color, mode, aa, edgeAA,
- GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), domain);
+ filter, color, mode, aa, &quad, domain);
}
/**
@@ -274,10 +275,10 @@
GrSurfaceOrigin origin = proxy->origin();
const GrSwizzle& swizzle = proxy->textureSwizzle();
GrSurfaceProxyView proxyView(std::move(proxy), origin, swizzle);
+ DrawQuad quad{GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
+ GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()), edgeAA};
this->drawTexturedQuad(clip, std::move(proxyView), srcAlphaType, std::move(texXform),
- filter, color, mode, aa, edgeAA,
- GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
- GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()), domain);
+ filter, color, mode, aa, &quad, domain);
}
/** Used with drawTextureSet */
@@ -620,23 +621,20 @@
const SkPMColor4f* constColor,
const GrUserStencilSettings* stencilSettings,
GrAA* aa,
- GrQuadAAFlags* edgeFlags,
- GrQuad* deviceQuad,
- GrQuad* localQuad);
+ DrawQuad* quad);
// If stencil settings, 'ss', are non-null, AA controls MSAA or no AA. If they are null, then AA
// can choose between coverage, MSAA as per chooseAAType(). This will always attempt to apply
// quad optimizations, so all quad/rect public APIs should rely on this function for consistent
- // clipping behavior.
+ // clipping behavior. 'quad' will be modified in place to reflect final rendered geometry.
void drawFilledQuad(const GrClip& clip,
GrPaint&& paint,
GrAA aa,
- GrQuadAAFlags edgeFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const GrUserStencilSettings* ss = nullptr);
- // Like drawFilledQuad but does not require using a GrPaint or FP for texturing
+ // Like drawFilledQuad but does not require using a GrPaint or FP for texturing.
+ // 'quad' may be modified in place to reflect final geometry.
void drawTexturedQuad(const GrClip& clip,
GrSurfaceProxyView proxyView,
SkAlphaType alphaType,
@@ -645,9 +643,7 @@
const SkPMColor4f& color,
SkBlendMode blendMode,
GrAA aa,
- GrQuadAAFlags edgeFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const SkRect* domain = nullptr);
void drawShapeUsingPathRenderer(const GrClip&, GrPaint&&, GrAA, const SkMatrix&,
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index ecc5cd9..188d251 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -58,10 +58,10 @@
const SkMatrix* localMatrix = nullptr) {
// Since this provides stencil settings to drawFilledQuad, it performs a different AA type
// resolution compared to regular rect draws, which is the main reason it remains separate.
- GrQuad localQuad = localMatrix ? GrQuad::MakeFromRect(rect, *localMatrix) : GrQuad(rect);
- fRenderTargetContext->drawFilledQuad(
- clip, std::move(paint), doStencilMSAA, GrQuadAAFlags::kNone,
- GrQuad::MakeFromRect(rect, viewMatrix), localQuad, ss);
+ DrawQuad quad{GrQuad::MakeFromRect(rect, viewMatrix),
+ localMatrix ? GrQuad::MakeFromRect(rect, *localMatrix) : GrQuad(rect),
+ GrQuadAAFlags::kNone};
+ fRenderTargetContext->drawFilledQuad(clip, std::move(paint), doStencilMSAA, &quad, ss);
}
void stencilPath(
diff --git a/src/gpu/geometry/GrQuad.h b/src/gpu/geometry/GrQuad.h
index 2094a4b..58f59f0 100644
--- a/src/gpu/geometry/GrQuad.h
+++ b/src/gpu/geometry/GrQuad.h
@@ -13,6 +13,8 @@
#include "include/core/SkPoint3.h"
#include "include/private/SkVx.h"
+enum class GrQuadAAFlags;
+
/**
* GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The
* points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right).
@@ -161,4 +163,12 @@
Type fType = Type::kAxisAligned;
};
+// A simple struct representing the common work unit of a pair of device and local coordinates, as
+// well as the edge flags controlling anti-aliasing for the quadrilateral when drawn.
+struct DrawQuad {
+ GrQuad fDevice;
+ GrQuad fLocal;
+ GrQuadAAFlags fEdgeFlags;
+};
+
#endif
diff --git a/src/gpu/geometry/GrQuadUtils.cpp b/src/gpu/geometry/GrQuadUtils.cpp
index 7450c31..7b53a01 100644
--- a/src/gpu/geometry/GrQuadUtils.cpp
+++ b/src/gpu/geometry/GrQuadUtils.cpp
@@ -381,28 +381,28 @@
}
}
-bool CropToRect(const SkRect& cropRect, GrAA cropAA, GrQuadAAFlags* edgeFlags, GrQuad* quad,
- GrQuad* local) {
- SkASSERT(quad->isFinite());
+bool CropToRect(const SkRect& cropRect, GrAA cropAA, DrawQuad* quad, bool computeLocal) {
+ SkASSERT(quad->fDevice.isFinite());
- if (quad->quadType() == GrQuad::Type::kAxisAligned) {
+ if (quad->fDevice.quadType() == GrQuad::Type::kAxisAligned) {
// crop_rect and crop_rect_simple keep the rectangles as rectangles, so the intersection
// of the crop and quad can be calculated exactly. Some care must be taken if the quad
// is axis-aligned but does not satisfy asRect() due to flips, etc.
GrQuadAAFlags clippedEdges;
- if (local) {
- if (is_simple_rect(*quad) && is_simple_rect(*local)) {
- clippedEdges = crop_simple_rect(cropRect, quad->xs(), quad->ys(),
- local->xs(), local->ys());
+ if (computeLocal) {
+ if (is_simple_rect(quad->fDevice) && is_simple_rect(quad->fLocal)) {
+ clippedEdges = crop_simple_rect(cropRect, quad->fDevice.xs(), quad->fDevice.ys(),
+ quad->fLocal.xs(), quad->fLocal.ys());
} else {
- clippedEdges = crop_rect(cropRect, quad->xs(), quad->ys(),
- local->xs(), local->ys(), local->ws());
+ clippedEdges = crop_rect(cropRect, quad->fDevice.xs(), quad->fDevice.ys(),
+ quad->fLocal.xs(), quad->fLocal.ys(), quad->fLocal.ws());
}
} else {
- if (is_simple_rect(*quad)) {
- clippedEdges = crop_simple_rect(cropRect, quad->xs(), quad->ys(), nullptr, nullptr);
+ if (is_simple_rect(quad->fDevice)) {
+ clippedEdges = crop_simple_rect(cropRect, quad->fDevice.xs(), quad->fDevice.ys(),
+ nullptr, nullptr);
} else {
- clippedEdges = crop_rect(cropRect, quad->xs(), quad->ys(),
+ clippedEdges = crop_rect(cropRect, quad->fDevice.xs(), quad->fDevice.ys(),
nullptr, nullptr, nullptr);
}
}
@@ -410,26 +410,31 @@
// Apply the clipped edge updates to the original edge flags
if (cropAA == GrAA::kYes) {
// Turn on all edges that were clipped
- *edgeFlags |= clippedEdges;
+ quad->fEdgeFlags |= clippedEdges;
} else {
// Turn off all edges that were clipped
- *edgeFlags &= ~clippedEdges;
+ quad->fEdgeFlags &= ~clippedEdges;
}
return true;
}
- if (local) {
+ if (computeLocal) {
// FIXME (michaelludwig) Calculate cropped local coordinates when not kAxisAligned
return false;
}
- V4f devX = quad->x4f();
- V4f devY = quad->y4f();
- V4f devIW = quad->iw4f();
+ V4f devX = quad->fDevice.x4f();
+ V4f devY = quad->fDevice.y4f();
// Project the 3D coordinates to 2D
- if (quad->quadType() == GrQuad::Type::kPerspective) {
- devX *= devIW;
- devY *= devIW;
+ if (quad->fDevice.quadType() == GrQuad::Type::kPerspective) {
+ V4f devW = quad->fDevice.w4f();
+ if (any(devW < SkPathPriv::kW0PlaneDistance)) {
+ // The rest of this function assumes the quad is in front of w = 0
+ return false;
+ }
+ devW = 1.f / devW;
+ devX *= devW;
+ devY *= devW;
}
V4f clipX = {cropRect.fLeft, cropRect.fLeft, cropRect.fRight, cropRect.fRight};
@@ -460,21 +465,17 @@
// FIXME (michaelludwig) - once we have local coordinates handled, it may be desirable to
// keep the draw as perspective so that the hardware does perspective interpolation instead
// of pushing it into a local coord w and having the shader do an extra divide.
- clipX.store(quad->xs());
- clipY.store(quad->ys());
- quad->ws()[0] = 1.f;
- quad->ws()[1] = 1.f;
- quad->ws()[2] = 1.f;
- quad->ws()[3] = 1.f;
- quad->setQuadType(GrQuad::Type::kAxisAligned);
+ clipX.store(quad->fDevice.xs());
+ clipY.store(quad->fDevice.ys());
+ quad->fDevice.setQuadType(GrQuad::Type::kAxisAligned);
// Update the edge flags to match the clip setting since all 4 edges have been clipped
- *edgeFlags = cropAA == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
+ quad->fEdgeFlags = cropAA == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
return true;
}
- // FIXME (michaelludwig) - use the GrQuadPerEdgeAA tessellation inset/outset math to move
+ // FIXME (michaelludwig) - use TessellationHelper's inset/outset math to move
// edges to the closest clip corner they are outside of
return false;
diff --git a/src/gpu/geometry/GrQuadUtils.h b/src/gpu/geometry/GrQuadUtils.h
index 63d3415..48be862 100644
--- a/src/gpu/geometry/GrQuadUtils.h
+++ b/src/gpu/geometry/GrQuadUtils.h
@@ -33,12 +33,9 @@
* based on cropAA policy). If provided, the local coordinates will be updated to reflect the
* updated device coordinates of this quad.
*
- * 'local' may be null, in which case the new local coordinates will not be calculated. This is
- * useful when it's known a paint does not require local coordinates. However, neither
- * 'edgeFlags' nore 'quad' can be null.
+ * If 'computeLocal' is false, the local coordinates in 'quad' will not be modified.
*/
- bool CropToRect(const SkRect& cropRect, GrAA cropAA, GrQuadAAFlags* edgeFlags, GrQuad* quad,
- GrQuad* local=nullptr);
+ bool CropToRect(const SkRect& cropRect, GrAA cropAA, DrawQuad* quad, bool computeLocal=true);
class TessellationHelper {
public:
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index 4c6bfda..a65ab8e 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -64,30 +64,28 @@
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags edgeAA,
- const GrUserStencilSettings* stencilSettings,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad) {
+ DrawQuad* quad,
+ const GrUserStencilSettings* stencilSettings) {
// Clean up deviations between aaType and edgeAA
- GrQuadUtils::ResolveAAType(aaType, edgeAA, deviceQuad, &aaType, &edgeAA);
- return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, edgeAA,
- stencilSettings, deviceQuad, localQuad);
+ GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
+ &aaType, &quad->fEdgeFlags);
+ return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, quad,
+ stencilSettings);
}
// aaType is passed to Helper in the initializer list, so incongruities between aaType and
// edgeFlags must be resolved prior to calling this constructor.
FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
- GrQuadAAFlags edgeFlags, const GrUserStencilSettings* stencil,
- const GrQuad& deviceQuad, const GrQuad& localQuad)
+ DrawQuad* quad, const GrUserStencilSettings* stencil)
: INHERITED(ClassID())
, fHelper(args, aaType, stencil)
, fQuads(1, !fHelper.isTrivial()) {
// Conservatively keep track of the local coordinates; it may be that the paint doesn't
// need them after analysis is finished. If the paint is known to be solid up front they
// can be skipped entirely.
- fQuads.append(deviceQuad, { paintColor, edgeFlags },
- fHelper.isTrivial() ? nullptr : &localQuad);
- this->setBounds(deviceQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
+ fQuads.append(quad->fDevice, {paintColor, quad->fEdgeFlags},
+ fHelper.isTrivial() ? nullptr : &quad->fLocal);
+ this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
IsHairline::kNo);
}
@@ -335,8 +333,7 @@
// But since it's avoiding the op list management, it must update the op's bounds. This is only
// used with quad sets, which uses the same view matrix for each quad so this assumes that the
// device quad type of the new quad is the same as the op's.
- bool addQuad(const GrQuad& deviceQuad, const GrQuad& localQuad,
- const SkPMColor4f& color, GrQuadAAFlags edgeAA, GrAAType aaType) {
+ bool addQuad(DrawQuad* quad, const SkPMColor4f& color, GrAAType aaType) {
// The new quad's aa type should be the same as the first quad's or none, except when the
// first quad's aa type was already downgraded to none, in which case the stored type must
// be lifted to back to the requested type.
@@ -362,10 +359,11 @@
// Update the bounds and add the quad to this op's storage
SkRect newBounds = this->bounds();
- newBounds.joinPossiblyEmptyRect(deviceQuad.bounds());
+ newBounds.joinPossiblyEmptyRect(quad->fDevice.bounds());
this->setBounds(newBounds, HasAABloat(fHelper.aaType() == GrAAType::kCoverage),
IsHairline::kNo);
- fQuads.append(deviceQuad, { color, edgeAA }, fHelper.isTrivial() ? nullptr : &localQuad);
+ fQuads.append(quad->fDevice, { color, quad->fEdgeFlags },
+ fHelper.isTrivial() ? nullptr : &quad->fLocal);
return true;
}
@@ -388,12 +386,9 @@
std::unique_ptr<GrDrawOp> GrFillRectOp::Make(GrRecordingContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const GrUserStencilSettings* stencil) {
- return FillRectOp::Make(context, std::move(paint), aaType, aaFlags, stencil,
- deviceQuad, localQuad);
+ return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil);
}
std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
@@ -401,8 +396,8 @@
const SkMatrix& view,
const SkRect& rect,
const GrUserStencilSettings* stencil) {
- return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
- stencil, GrQuad::MakeFromRect(rect, view), GrQuad(rect));
+ DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
+ return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil);
}
std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
@@ -416,27 +411,26 @@
// First make a draw op for the first quad in the set
SkASSERT(cnt > 0);
+ DrawQuad quad{GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
+ GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix),
+ quads[0].fAAFlags};
paint.setColor4f(quads[0].fColor);
- std::unique_ptr<GrDrawOp> op = FillRectOp::Make(
- context, std::move(paint), aaType,
- quads[0].fAAFlags, stencilSettings,
- GrQuad::MakeFromRect(quads[0].fRect, viewMatrix),
- GrQuad::MakeFromRect(quads[0].fRect, quads[0].fLocalMatrix));
+ std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
+ &quad, stencilSettings);
FillRectOp* fillRects = op->cast<FillRectOp>();
*numConsumed = 1;
// Accumulate remaining quads similar to onCombineIfPossible() without creating an op
for (int i = 1; i < cnt; ++i) {
- GrQuad deviceQuad = GrQuad::MakeFromRect(quads[i].fRect, viewMatrix);
+ quad = {GrQuad::MakeFromRect(quads[i].fRect, viewMatrix),
+ GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
+ quads[i].fAAFlags};
GrAAType resolvedAA;
- GrQuadAAFlags resolvedEdgeFlags;
- GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, deviceQuad,
- &resolvedAA, &resolvedEdgeFlags);
+ GrQuadUtils::ResolveAAType(aaType, quads[i].fAAFlags, quad.fDevice,
+ &resolvedAA, &quad.fEdgeFlags);
- if (!fillRects->addQuad(deviceQuad,
- GrQuad::MakeFromRect(quads[i].fRect, quads[i].fLocalMatrix),
- quads[i].fColor, resolvedEdgeFlags, resolvedAA)) {
+ if (!fillRects->addQuad(&quad, quads[i].fColor, resolvedAA)) {
break;
}
@@ -504,21 +498,20 @@
if (random->nextBool()) {
// Single local matrix
SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
- GrQuad::MakeFromRect(rect, viewMatrix),
- GrQuad::MakeFromRect(rect, localMatrix), stencil);
+ DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
+ GrQuad::MakeFromRect(rect, localMatrix), aaFlags};
+ return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
} else {
// Pass local rect directly
SkRect localRect = GrTest::TestRect(random);
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
- GrQuad::MakeFromRect(rect, viewMatrix),
- GrQuad(localRect), stencil);
+ DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix),
+ GrQuad(localRect), aaFlags};
+ return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
}
} else {
// The simplest constructor
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
- GrQuad::MakeFromRect(rect, viewMatrix),
- GrQuad(rect), stencil);
+ DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(rect), aaFlags};
+ return GrFillRectOp::Make(context, std::move(paint), aaType, &quad, stencil);
}
}
diff --git a/src/gpu/ops/GrFillRectOp.h b/src/gpu/ops/GrFillRectOp.h
index 600e87b..e44dae52 100644
--- a/src/gpu/ops/GrFillRectOp.h
+++ b/src/gpu/ops/GrFillRectOp.h
@@ -31,9 +31,7 @@
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
GrPaint&& paint,
GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const GrUserStencilSettings* stencil = nullptr);
// Utility function to create a non-AA rect transformed by view. This is used commonly enough
diff --git a/src/gpu/ops/GrStrokeRectOp.cpp b/src/gpu/ops/GrStrokeRectOp.cpp
index 81ce82b..c45185c 100644
--- a/src/gpu/ops/GrStrokeRectOp.cpp
+++ b/src/gpu/ops/GrStrokeRectOp.cpp
@@ -798,10 +798,9 @@
if (devOutside.isEmpty()) {
return nullptr;
}
- return GrFillRectOp::Make(context, std::move(paint), GrAAType::kCoverage,
- GrQuadAAFlags::kAll,
- GrQuad::MakeFromRect(rects[0], viewMatrix),
- GrQuad(rects[0]));
+ DrawQuad quad{GrQuad::MakeFromRect(rects[0], viewMatrix), GrQuad(rects[0]),
+ GrQuadAAFlags::kAll};
+ return GrFillRectOp::Make(context, std::move(paint), GrAAType::kCoverage, &quad);
}
SkVector devHalfStrokeSize{ SkScalarHalf(devOutside.fRight - devInside.fRight),
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index 49b1590..550b648 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -201,14 +201,11 @@
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const SkRect* domain) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<TextureOp>(std::move(proxyView), std::move(textureXform), filter,
- color, saturate, aaType, aaFlags, deviceQuad, localQuad,
- domain);
+ color, saturate, aaType, quad, domain);
}
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
@@ -451,17 +448,14 @@
};
- // dstQuad should be the geometry transformed by the view matrix. If domainRect
- // is not null it will be used to apply the strict src rect constraint.
+ // If domainRect is not null it will be used to apply a strict src rect-style constraint.
TextureOp(GrSurfaceProxyView proxyView,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
GrSamplerState::Filter filter,
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& dstQuad,
- const GrQuad& srcQuad,
+ DrawQuad* quad,
const SkRect* domainRect)
: INHERITED(ClassID())
, fQuads(1, true /* includes locals */)
@@ -471,7 +465,8 @@
// Clean up disparities between the overall aa type and edge configuration and apply
// optimizations based on the rect and matrix when appropriate
- GrQuadUtils::ResolveAAType(aaType, aaFlags, dstQuad, &aaType, &aaFlags);
+ GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
+ &aaType, &quad->fEdgeFlags);
fMetadata.fAAType = static_cast<uint16_t>(aaType);
// We expect our caller to have already caught this optimization.
@@ -490,14 +485,13 @@
// Normalize src coordinates and the domain (if set)
NormalizationParams params = proxy_normalization_params(proxyView.proxy(),
proxyView.origin());
- GrQuad normalizedSrcQuad = srcQuad;
- normalize_src_quad(params, &normalizedSrcQuad);
+ normalize_src_quad(params, &quad->fLocal);
SkRect domain = normalize_domain(filter, params, domainRect);
- fQuads.append(dstQuad, {color, domain, aaFlags}, &normalizedSrcQuad);
+ fQuads.append(quad->fDevice, {color, domain, quad->fEdgeFlags}, &quad->fLocal);
fViewCountPairs[0] = {proxyView.detachProxy(), 1};
- this->setBounds(dstQuad.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
+ this->setBounds(quad->fDevice.bounds(), HasAABloat(aaType == GrAAType::kCoverage),
IsHairline::kNo);
}
@@ -560,20 +554,20 @@
// Use dstRect/srcRect unless dstClip is provided, in which case derive new source
// coordinates by mapping dstClipQuad by the dstRect to srcRect transform.
- GrQuad quad, srcQuad;
+ DrawQuad quad;
if (set[q].fDstClipQuad) {
- quad = GrQuad::MakeFromSkQuad(set[q].fDstClipQuad, ctm);
+ quad.fDevice = GrQuad::MakeFromSkQuad(set[q].fDstClipQuad, ctm);
SkPoint srcPts[4];
GrMapRectPoints(set[q].fDstRect, set[q].fSrcRect, set[q].fDstClipQuad, srcPts, 4);
- srcQuad = GrQuad::MakeFromSkQuad(srcPts, SkMatrix::I());
+ quad.fLocal = GrQuad::MakeFromSkQuad(srcPts, SkMatrix::I());
} else {
- quad = GrQuad::MakeFromRect(set[q].fDstRect, ctm);
- srcQuad = GrQuad(set[q].fSrcRect);
+ quad.fDevice = GrQuad::MakeFromRect(set[q].fDstRect, ctm);
+ quad.fLocal = GrQuad(set[q].fSrcRect);
}
// Before normalizing the source coordinates, determine if bilerp is actually needed
- if (netFilter != filter && filter_has_effect(srcQuad, quad)) {
+ if (netFilter != filter && filter_has_effect(quad.fLocal, quad.fDevice)) {
// The only way netFilter != filter is if bilerp is requested and we haven't yet
// found a quad that requires bilerp (so net is still nearest).
SkASSERT(netFilter == GrSamplerState::Filter::kNearest &&
@@ -587,15 +581,15 @@
// Normalize the src quads and apply origin
NormalizationParams proxyParams = proxy_normalization_params(
curProxy, set[q].fProxyView.origin());
- normalize_src_quad(proxyParams, &srcQuad);
+ normalize_src_quad(proxyParams, &quad.fLocal);
// Update overall bounds of the op as the union of all quads
- bounds.joinPossiblyEmptyRect(quad.bounds());
+ bounds.joinPossiblyEmptyRect(quad.fDevice.bounds());
// Determine the AA type for the quad, then merge with net AA type
- GrQuadAAFlags aaFlags;
GrAAType aaForQuad;
- GrQuadUtils::ResolveAAType(aaType, set[q].fAAFlags, quad, &aaForQuad, &aaFlags);
+ GrQuadUtils::ResolveAAType(aaType, set[q].fAAFlags, quad.fDevice,
+ &aaForQuad, &quad.fEdgeFlags);
// Resolve sets aaForQuad to aaType or None, there is never a change between aa methods
SkASSERT(aaForQuad == GrAAType::kNone || aaForQuad == aaType);
if (netAAType == GrAAType::kNone && aaForQuad != GrAAType::kNone) {
@@ -621,7 +615,8 @@
// (this frequently happens when Chrome draws 9-patches).
SkRect domain = normalize_domain(filter, proxyParams, domainForQuad);
float alpha = SkTPin(set[q].fAlpha, 0.f, 1.f);
- fQuads.append(quad, {{alpha, alpha, alpha, alpha}, domain, aaFlags}, &srcQuad);
+ fQuads.append(quad.fDevice, {{alpha, alpha, alpha, alpha}, domain, quad.fEdgeFlags},
+ &quad.fLocal);
fViewCountPairs[p].fQuadCnt++;
}
// The # of proxy switches should match what was provided (+1 because we incremented p
@@ -1046,9 +1041,7 @@
Saturate saturate,
SkBlendMode blendMode,
GrAAType aaType,
- GrQuadAAFlags aaFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad* quad,
const SkRect* domain) {
// Apply optimizations that are valid whether or not using GrTextureOp or GrFillRectOp
if (domain && domain->contains(proxyView.proxy()->backingStoreBoundsRect())) {
@@ -1056,13 +1049,14 @@
domain = nullptr;
}
- if (filter != GrSamplerState::Filter::kNearest && !filter_has_effect(localQuad, deviceQuad)) {
+ if (filter != GrSamplerState::Filter::kNearest &&
+ !filter_has_effect(quad->fLocal, quad->fDevice)) {
filter = GrSamplerState::Filter::kNearest;
}
if (blendMode == SkBlendMode::kSrcOver) {
return TextureOp::Make(context, std::move(proxyView), std::move(textureXform), filter,
- color, saturate, aaType, aaFlags, deviceQuad, localQuad, domain);
+ color, saturate, aaType, std::move(quad), domain);
} else {
// Emulate complex blending using GrFillRectOp
GrPaint paint;
@@ -1073,7 +1067,7 @@
if (domain) {
const auto& caps = *context->priv().caps();
SkRect localRect;
- if (localQuad.asRect(&localRect)) {
+ if (quad->fLocal.asRect(&localRect)) {
fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), filter,
*domain, localRect, caps);
} else {
@@ -1089,8 +1083,7 @@
paint.addColorFragmentProcessor(GrClampFragmentProcessor::Make(false));
}
- return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags, deviceQuad,
- localQuad);
+ return GrFillRectOp::Make(context, std::move(paint), aaType, quad);
}
}
@@ -1181,16 +1174,17 @@
ctm.preConcat(*set[i].fPreViewMatrix);
}
- GrQuad quad, srcQuad;
+ DrawQuad quad;
+ quad.fEdgeFlags = set[i].fAAFlags;
if (set[i].fDstClipQuad) {
- quad = GrQuad::MakeFromSkQuad(set[i].fDstClipQuad, ctm);
+ quad.fDevice = GrQuad::MakeFromSkQuad(set[i].fDstClipQuad, ctm);
SkPoint srcPts[4];
GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcPts, 4);
- srcQuad = GrQuad::MakeFromSkQuad(srcPts, SkMatrix::I());
+ quad.fLocal = GrQuad::MakeFromSkQuad(srcPts, SkMatrix::I());
} else {
- quad = GrQuad::MakeFromRect(set[i].fDstRect, ctm);
- srcQuad = GrQuad(set[i].fSrcRect);
+ quad.fDevice = GrQuad::MakeFromRect(set[i].fDstRect, ctm);
+ quad.fLocal = GrQuad(set[i].fSrcRect);
}
const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
@@ -1198,7 +1192,7 @@
auto op = Make(context, set[i].fProxyView, set[i].fSrcAlphaType, textureColorSpaceXform,
filter, {alpha, alpha, alpha, alpha}, saturate, blendMode, aaType,
- set[i].fAAFlags, quad, srcQuad, domain);
+ &quad, domain);
rtc->addDrawOp(clip, std::move(op));
}
return;
@@ -1333,10 +1327,10 @@
auto alphaType = static_cast<SkAlphaType>(
random->nextRangeU(kUnknown_SkAlphaType + 1, kLastEnum_SkAlphaType));
+ DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(srcRect), aaFlags};
return GrTextureOp::Make(context, std::move(proxyView), alphaType, std::move(texXform), filter,
- color, saturate, SkBlendMode::kSrcOver, aaType, aaFlags,
- GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(srcRect),
- useDomain ? &srcRect : nullptr);
+ color, saturate, SkBlendMode::kSrcOver, aaType,
+ &quad, useDomain ? &srcRect : nullptr);
}
#endif
diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h
index 079159b..21d9b9a 100644
--- a/src/gpu/ops/GrTextureOp.h
+++ b/src/gpu/ops/GrTextureOp.h
@@ -49,9 +49,7 @@
Saturate,
SkBlendMode,
GrAAType,
- GrQuadAAFlags,
- const GrQuad& deviceQuad,
- const GrQuad& localQuad,
+ DrawQuad*,
const SkRect* domain = nullptr);
// Automatically falls back to using one GrFillRectOp per entry if dynamic states are not
diff --git a/tests/GrQuadCropTest.cpp b/tests/GrQuadCropTest.cpp
index 36fafe4..255cc77 100644
--- a/tests/GrQuadCropTest.cpp
+++ b/tests/GrQuadCropTest.cpp
@@ -26,21 +26,20 @@
// Should use run_crop_fully_covers_test for non-rect matrices
SkASSERT(viewMatrix.rectStaysRect());
- GrQuad drawQuad = GrQuad::MakeFromRect(kDrawRect, viewMatrix);
- GrQuad localQuad = GrQuad::MakeFromRect(kDrawRect, localMatrix ? *localMatrix : SkMatrix::I());
- GrQuad* localQuadPtr = localMatrix ? &localQuad : nullptr;
- GrQuadAAFlags edgeFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
+ DrawQuad quad = {GrQuad::MakeFromRect(kDrawRect, viewMatrix),
+ GrQuad::MakeFromRect(kDrawRect, localMatrix ? *localMatrix : SkMatrix::I()),
+ clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll};
- bool exact = GrQuadUtils::CropToRect(clipRect, clipAA, &edgeFlags, &drawQuad, localQuadPtr);
+ bool exact = GrQuadUtils::CropToRect(clipRect, clipAA, &quad, /* calc. locals */ !!localMatrix);
ASSERTF(exact, "Expected exact crop");
- ASSERTF(drawQuad.quadType() == GrQuad::Type::kAxisAligned,
+ ASSERTF(quad.fDevice.quadType() == GrQuad::Type::kAxisAligned,
"Expected quad to remain axis-aligned");
// Since we remained a rectangle, the bounds will exactly match the coordinates
SkRect expectedBounds = viewMatrix.mapRect(kDrawRect);
SkAssertResult(expectedBounds.intersect(clipRect));
- SkRect actualBounds = drawQuad.bounds();
+ SkRect actualBounds = quad.fDevice.bounds();
ASSERT_NEARLY_EQUAL(expectedBounds.fLeft, actualBounds.fLeft);
ASSERT_NEARLY_EQUAL(expectedBounds.fTop, actualBounds.fTop);
ASSERT_NEARLY_EQUAL(expectedBounds.fRight, actualBounds.fRight);
@@ -54,9 +53,9 @@
SkMatrix toLocal = SkMatrix::Concat(*localMatrix, invViewMatrix);
for (int p = 0; p < 4; ++p) {
- SkPoint expectedPoint = drawQuad.point(p);
+ SkPoint expectedPoint = quad.fDevice.point(p);
toLocal.mapPoints(&expectedPoint, 1);
- SkPoint actualPoint = localQuad.point(p);
+ SkPoint actualPoint = quad.fLocal.point(p);
ASSERT_NEARLY_EQUAL(expectedPoint.fX, actualPoint.fX);
ASSERT_NEARLY_EQUAL(expectedPoint.fY, actualPoint.fY);
@@ -68,30 +67,30 @@
SkRect drawClip = invViewMatrix.mapRect(clipRect);
if (drawClip.fLeft > kDrawRect.fLeft) {
if (clipAA == GrAA::kYes) {
- ASSERTF(edgeFlags & GrQuadAAFlags::kLeft, "Expected left edge AA set");
+ ASSERTF(quad.fEdgeFlags & GrQuadAAFlags::kLeft, "Expected left edge AA set");
} else {
- ASSERTF(!(edgeFlags & GrQuadAAFlags::kLeft), "Expected left edge AA unset");
+ ASSERTF(!(quad.fEdgeFlags & GrQuadAAFlags::kLeft), "Expected left edge AA unset");
}
}
if (drawClip.fRight < kDrawRect.fRight) {
if (clipAA == GrAA::kYes) {
- ASSERTF(edgeFlags & GrQuadAAFlags::kRight, "Expected right edge AA set");
+ ASSERTF(quad.fEdgeFlags & GrQuadAAFlags::kRight, "Expected right edge AA set");
} else {
- ASSERTF(!(edgeFlags & GrQuadAAFlags::kRight), "Expected right edge AA unset");
+ ASSERTF(!(quad.fEdgeFlags & GrQuadAAFlags::kRight), "Expected right edge AA unset");
}
}
if (drawClip.fTop > kDrawRect.fTop) {
if (clipAA == GrAA::kYes) {
- ASSERTF(edgeFlags & GrQuadAAFlags::kTop, "Expected top edge AA set");
+ ASSERTF(quad.fEdgeFlags & GrQuadAAFlags::kTop, "Expected top edge AA set");
} else {
- ASSERTF(!(edgeFlags & GrQuadAAFlags::kTop), "Expected top edge AA unset");
+ ASSERTF(!(quad.fEdgeFlags & GrQuadAAFlags::kTop), "Expected top edge AA unset");
}
}
if (drawClip.fBottom < kDrawRect.fBottom) {
if (clipAA == GrAA::kYes) {
- ASSERTF(edgeFlags & GrQuadAAFlags::kBottom, "Expected bottom edge AA set");
+ ASSERTF(quad.fEdgeFlags & GrQuadAAFlags::kBottom, "Expected bottom edge AA set");
} else {
- ASSERTF(!(edgeFlags & GrQuadAAFlags::kBottom), "Expected bottom edge AA unset");
+ ASSERTF(!(quad.fEdgeFlags & GrQuadAAFlags::kBottom), "Expected bottom edge AA unset");
}
}
}
@@ -110,57 +109,56 @@
containsCrop.outset(10.f, 10.f);
SkRect drawRect = invViewMatrix.mapRect(containsCrop);
- GrQuad drawQuad = GrQuad::MakeFromRect(drawRect, viewMatrix);
- GrQuadAAFlags edgeFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
+ DrawQuad quad = {GrQuad::MakeFromRect(drawRect, viewMatrix),
+ GrQuad::MakeFromRect(drawRect, localMatrix ? *localMatrix : SkMatrix::I()),
+ clipAA == GrAA::kYes ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll};
if (localMatrix) {
- GrQuad localQuad = GrQuad::MakeFromRect(drawRect, *localMatrix);
+ DrawQuad originalQuad = quad;
- GrQuad originalDrawQuad = drawQuad;
- GrQuad originalLocalQuad = localQuad;
- GrQuadAAFlags originalEdgeFlags = edgeFlags;
-
- bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &edgeFlags, &drawQuad, &localQuad);
+ bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &quad);
// Currently non-rect matrices don't know how to update local coordinates, so the crop
// doesn't know how to restrict itself and should leave the inputs unmodified
ASSERTF(!exact, "Expected crop to be not exact");
- ASSERTF(edgeFlags == originalEdgeFlags, "Expected edge flags not to be modified");
+ ASSERTF(quad.fEdgeFlags == originalQuad.fEdgeFlags,
+ "Expected edge flags not to be modified");
for (int i = 0; i < 4; ++i) {
- ASSERT_NEARLY_EQUAL(originalDrawQuad.x(i), drawQuad.x(i));
- ASSERT_NEARLY_EQUAL(originalDrawQuad.y(i), drawQuad.y(i));
- ASSERT_NEARLY_EQUAL(originalDrawQuad.w(i), drawQuad.w(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fDevice.x(i), quad.fDevice.x(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fDevice.y(i), quad.fDevice.y(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fDevice.w(i), quad.fDevice.w(i));
- ASSERT_NEARLY_EQUAL(originalLocalQuad.x(i), localQuad.x(i));
- ASSERT_NEARLY_EQUAL(originalLocalQuad.y(i), localQuad.y(i));
- ASSERT_NEARLY_EQUAL(originalLocalQuad.w(i), localQuad.w(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fLocal.x(i), quad.fLocal.x(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fLocal.y(i), quad.fLocal.y(i));
+ ASSERT_NEARLY_EQUAL(originalQuad.fLocal.w(i), quad.fLocal.w(i));
}
} else {
// Since no local coordinates were provided, and the input draw geometry is known to
// fully cover the crop rect, the quad should be updated to match cropRect exactly
- bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &edgeFlags, &drawQuad, nullptr);
+ bool exact = GrQuadUtils::CropToRect(kDrawRect, clipAA, &quad, /* calc. local */ false);
ASSERTF(exact, "Expected crop to be exact");
GrQuadAAFlags expectedFlags = clipAA == GrAA::kYes ? GrQuadAAFlags::kAll
: GrQuadAAFlags::kNone;
- ASSERTF(expectedFlags == edgeFlags, "Expected edge flags do not match clip AA setting");
- ASSERTF(drawQuad.quadType() == GrQuad::Type::kAxisAligned, "Unexpected quad type");
+ ASSERTF(expectedFlags == quad.fEdgeFlags,
+ "Expected edge flags do not match clip AA setting");
+ ASSERTF(quad.fDevice.quadType() == GrQuad::Type::kAxisAligned, "Unexpected quad type");
- ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, drawQuad.x(0));
- ASSERT_NEARLY_EQUAL(kDrawRect.fTop, drawQuad.y(0));
- ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(0));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, quad.fDevice.x(0));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fTop, quad.fDevice.y(0));
+ ASSERT_NEARLY_EQUAL(1.f, quad.fDevice.w(0));
- ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, drawQuad.x(1));
- ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, drawQuad.y(1));
- ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(1));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fLeft, quad.fDevice.x(1));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, quad.fDevice.y(1));
+ ASSERT_NEARLY_EQUAL(1.f, quad.fDevice.w(1));
- ASSERT_NEARLY_EQUAL(kDrawRect.fRight, drawQuad.x(2));
- ASSERT_NEARLY_EQUAL(kDrawRect.fTop, drawQuad.y(2));
- ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(2));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fRight, quad.fDevice.x(2));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fTop, quad.fDevice.y(2));
+ ASSERT_NEARLY_EQUAL(1.f, quad.fDevice.w(2));
- ASSERT_NEARLY_EQUAL(kDrawRect.fRight, drawQuad.x(3));
- ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, drawQuad.y(3));
- ASSERT_NEARLY_EQUAL(1.f, drawQuad.w(3));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fRight, quad.fDevice.x(3));
+ ASSERT_NEARLY_EQUAL(kDrawRect.fBottom, quad.fDevice.y(3));
+ ASSERT_NEARLY_EQUAL(1.f, quad.fDevice.w(3));
}
}