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:
parent
87e3bef6f8
commit
6b45c5d3da
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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&,
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user