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>
This commit is contained in:
Michael Ludwig 2020-02-07 09:56:38 -05:00 committed by Skia Commit-Bot
parent 87e3bef6f8
commit 6b45c5d3da
12 changed files with 237 additions and 263 deletions

View File

@ -605,17 +605,18 @@ static bool make_vertex_finite(float* value) {
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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
}
// 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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
} 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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
// 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 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi
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 @@ void GrRenderTargetContext::drawFilledQuad(const GrClip& clip,
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 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
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 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
// 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 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
: 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));
}
}

View File

@ -174,9 +174,9 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
* 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 @@ public:
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 @@ public:
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 @@ private:
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 @@ private:
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&,

View File

@ -58,10 +58,10 @@ public:
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(

View File

@ -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 @@ private:
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

View File

@ -381,28 +381,28 @@ void ResolveAAType(GrAAType requestedAAType, GrQuadAAFlags requestedEdgeFlags, c
}
}
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 @@ bool CropToRect(const SkRect& cropRect, GrAA cropAA, GrQuadAAFlags* edgeFlags, G
// 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 @@ bool CropToRect(const SkRect& cropRect, GrAA cropAA, GrQuadAAFlags* edgeFlags, G
// 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;

View File

@ -33,12 +33,9 @@ namespace GrQuadUtils {
* 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:

View File

@ -64,30 +64,28 @@ public:
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 @@ private:
// 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 @@ private:
// 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 @@ private:
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 @@ std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* contex
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 @@ std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
// 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 @@ GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
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);
}
}

View File

@ -31,9 +31,7 @@ public:
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

View File

@ -798,10 +798,9 @@ std::unique_ptr<GrDrawOp> MakeNested(GrRecordingContext* context,
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),

View File

@ -201,14 +201,11 @@ public:
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 @@ private:
};
// 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 @@ private:
// 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 @@ private:
// 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 @@ private:
// 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 @@ private:
// 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 @@ private:
// (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 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
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 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
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 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
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 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
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 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc,
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 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc,
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 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) {
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

View File

@ -49,9 +49,7 @@ public:
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

View File

@ -26,21 +26,20 @@ static void run_crop_axis_aligned_test(skiatest::Reporter* r, const SkRect& clip
// 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 @@ static void run_crop_axis_aligned_test(skiatest::Reporter* r, const SkRect& clip
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 @@ static void run_crop_axis_aligned_test(skiatest::Reporter* r, const SkRect& clip
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 @@ static void run_crop_fully_covered_test(skiatest::Reporter* r, GrAA clipAA,
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));
}
}