Add quad type and persp/aa utilities to GrQuad
This refactor makes some of the quad logic in GrTextureOp available for use with other quad GrOps. Bug: skia: Change-Id: I1c173cfdf61b33c8422ddd8b91406a970a1c8e5d Reviewed-on: https://skia-review.googlesource.com/c/163253 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
12956725cc
commit
1f7e4385d2
@ -7,6 +7,59 @@
|
||||
|
||||
#include "GrQuad.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions for identifying the quad type from its coordinates, which are kept debug-only since
|
||||
// production code should rely on the matrix to derive the quad type more efficiently. These are
|
||||
// useful in asserts that the quad type is as expected.
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
// Allow some tolerance from floating point matrix transformations, but SkScalarNearlyEqual doesn't
|
||||
// support comparing infinity, and coords_form_rect should return true for infinite edges
|
||||
#define NEARLY_EQUAL(f1, f2) (f1 == f2 || SkScalarNearlyEqual(f1, f2, 1e-5f))
|
||||
|
||||
// This is not the most performance critical function; code using GrQuad should rely on the faster
|
||||
// quad type from matrix path, so this will only be called as part of SkASSERT.
|
||||
static bool coords_form_rect(const float xs[4], const float ys[4]) {
|
||||
return (NEARLY_EQUAL(xs[0], xs[1]) && NEARLY_EQUAL(xs[2], xs[3]) &&
|
||||
NEARLY_EQUAL(ys[0], ys[2]) && NEARLY_EQUAL(ys[1], ys[3])) ||
|
||||
(NEARLY_EQUAL(xs[0], xs[2]) && NEARLY_EQUAL(xs[1], xs[3]) &&
|
||||
NEARLY_EQUAL(ys[0], ys[1]) && NEARLY_EQUAL(ys[2], ys[3]));
|
||||
}
|
||||
|
||||
GrQuadType GrQuad::quadType() const {
|
||||
// Since GrQuad applies any perspective information at construction time, there's only two
|
||||
// types to choose from.
|
||||
return coords_form_rect(fX, fY) ? GrQuadType::kRect_QuadType : GrQuadType::kStandard_QuadType;
|
||||
}
|
||||
|
||||
GrQuadType GrPerspQuad::quadType() const {
|
||||
if (this->hasPerspective()) {
|
||||
return GrQuadType::kPerspective_QuadType;
|
||||
} else {
|
||||
// Rect or standard quad, can ignore w since they are all ones
|
||||
return coords_form_rect(fX, fY) ? GrQuadType::kRect_QuadType
|
||||
: GrQuadType::kStandard_QuadType;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool aa_affects_rect(float ql, float qt, float qr, float qb) {
|
||||
return !SkScalarIsInt(ql) || !SkScalarIsInt(qr) || !SkScalarIsInt(qt) || !SkScalarIsInt(qb);
|
||||
}
|
||||
|
||||
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix) {
|
||||
if (matrix.rectStaysRect()) {
|
||||
return GrQuadType::kRect_QuadType;
|
||||
} else if (matrix.hasPerspective()) {
|
||||
return GrQuadType::kPerspective_QuadType;
|
||||
} else {
|
||||
return GrQuadType::kStandard_QuadType;
|
||||
}
|
||||
}
|
||||
|
||||
GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
|
||||
SkMatrix::TypeMask tm = m.getType();
|
||||
if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
|
||||
@ -44,6 +97,11 @@ GrQuad::GrQuad(const SkRect& rect, const SkMatrix& m) {
|
||||
}
|
||||
}
|
||||
|
||||
bool GrQuad::aaHasEffectOnRect() const {
|
||||
SkASSERT(this->quadType() == GrQuadType::kRect_QuadType);
|
||||
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
||||
}
|
||||
|
||||
GrPerspQuad::GrPerspQuad(const SkRect& rect, const SkMatrix& m) {
|
||||
SkMatrix::TypeMask tm = m.getType();
|
||||
if (tm <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
|
||||
@ -83,3 +141,9 @@ GrPerspQuad::GrPerspQuad(const SkRect& rect, const SkMatrix& m) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GrPerspQuad::aaHasEffectOnRect() const {
|
||||
SkASSERT(this->quadType() == GrQuadType::kRect_QuadType);
|
||||
// If rect, ws must all be 1s so no need to divide
|
||||
return aa_affects_rect(fX[0], fY[0], fX[3], fY[3]);
|
||||
}
|
||||
|
@ -13,6 +13,24 @@
|
||||
#include "SkPoint.h"
|
||||
#include "SkPoint3.h"
|
||||
|
||||
// Rectangles transformed by matrices (view or local) can be classified in three ways:
|
||||
// 1. Stays a rectangle - the matrix rectStaysRect() is true, or x(0) == x(1) && x(2) == x(3)
|
||||
// and y(0) == y(2) && y(1) == y(3). Or under mirrors, x(0) == x(2) && x(1) == x(3) and
|
||||
// y(0) == y(1) && y(2) == y(3).
|
||||
// 2. Is a quadrilateral - the matrix does not have perspective, but may rotate or skew, or
|
||||
// ws() == all ones.
|
||||
// 3. Is a perspective quad - the matrix has perspective, subsuming all previous quad types.
|
||||
enum class GrQuadType {
|
||||
kRect_QuadType,
|
||||
kStandard_QuadType,
|
||||
kPerspective_QuadType
|
||||
};
|
||||
|
||||
// If an SkRect is transformed by this matrix, what class of quad is required to represent it. Since
|
||||
// quadType() is only provided on Gr[Persp]Quad in debug builds, production code should use this
|
||||
// to efficiently determine quad types.
|
||||
GrQuadType GrQuadTypeForTransformedRect(const SkMatrix& matrix);
|
||||
|
||||
/**
|
||||
* 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).
|
||||
@ -49,6 +67,13 @@ public:
|
||||
Sk4f x4f() const { return Sk4f::Load(fX); }
|
||||
Sk4f y4f() const { return Sk4f::Load(fY); }
|
||||
|
||||
// True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType
|
||||
bool aaHasEffectOnRect() const;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
GrQuadType quadType() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
float fX[4];
|
||||
float fY[4];
|
||||
@ -80,6 +105,15 @@ public:
|
||||
Sk4f w4f() const { return Sk4f::Load(fW); }
|
||||
Sk4f iw4f() const { return Sk4f::Load(fIW); }
|
||||
|
||||
bool hasPerspective() const { return (w4f() != Sk4f(1.f)).anyTrue(); }
|
||||
|
||||
// True if anti-aliasing affects this quad. Requires quadType() == kRect_QuadType
|
||||
bool aaHasEffectOnRect() const;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
GrQuadType quadType() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
float fX[4];
|
||||
float fY[4];
|
||||
|
@ -351,7 +351,7 @@ public:
|
||||
GrQuadAAFlags aaFlags, const SkRect& texRect) {
|
||||
// Should be kNone for non-AA and kAll for MSAA.
|
||||
SkASSERT(aaFlags == GrQuadAAFlags::kNone || aaFlags == GrQuadAAFlags::kAll);
|
||||
SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
|
||||
SkASSERT(!quad.hasPerspective());
|
||||
SkPointPriv::SetRectTriStrip(&vertices[0].fTextureCoords, texRect, sizeof(V));
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
vertices[i].fPosition = {quad.x(i), quad.y(i)};
|
||||
@ -376,7 +376,7 @@ template<typename V> class VertexAAHandler<V, GrAA::kYes, SkPoint> {
|
||||
public:
|
||||
static void AssignPositionsAndTexCoords(V* vertices, const GrPerspQuad& quad,
|
||||
GrQuadAAFlags aaFlags, const SkRect& texRect) {
|
||||
SkASSERT((quad.w4f() == Sk4f(1.f)).allTrue());
|
||||
SkASSERT(!quad.hasPerspective());
|
||||
if (aaFlags == GrQuadAAFlags::kNone) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
vertices[i].fPosition = {quad.x(i), quad.y(i)};
|
||||
@ -593,17 +593,8 @@ static void tessellate_quad(const GrPerspQuad& devQuad, GrQuadAAFlags aaFlags,
|
||||
DomainAssigner<V>::Assign(vertices, domain, filter, srcRect, origin, iw, ih);
|
||||
}
|
||||
|
||||
static bool aa_has_effect_for_rect_stays_rect(const GrPerspQuad& quad) {
|
||||
SkASSERT((quad.w4f() == Sk4f(1)).allTrue());
|
||||
float ql = quad.x(0);
|
||||
float qt = quad.y(0);
|
||||
float qr = quad.x(3);
|
||||
float qb = quad.y(3);
|
||||
return !SkScalarIsInt(ql) || !SkScalarIsInt(qr) || !SkScalarIsInt(qt) || !SkScalarIsInt(qb);
|
||||
}
|
||||
|
||||
static bool filter_has_effect_for_rect_stays_rect(const GrPerspQuad& quad, const SkRect& srcRect) {
|
||||
SkASSERT((quad.w4f() == Sk4f(1)).allTrue());
|
||||
SkASSERT(quad.quadType() == GrQuadType::kRect_QuadType);
|
||||
float ql = quad.x(0);
|
||||
float qt = quad.y(0);
|
||||
float qr = quad.x(3);
|
||||
@ -751,7 +742,7 @@ private:
|
||||
SkASSERT(!srcRect.contains(proxy->getWorstCaseBoundsRect()) ||
|
||||
constraint == SkCanvas::kFast_SrcRectConstraint);
|
||||
if (viewMatrix.rectStaysRect()) {
|
||||
if (this->aaType() == GrAAType::kCoverage && !aa_has_effect_for_rect_stays_rect(quad)) {
|
||||
if (this->aaType() == GrAAType::kCoverage && !quad.aaHasEffectOnRect()) {
|
||||
fAAType = static_cast<unsigned>(GrAAType::kNone);
|
||||
aaFlags = GrQuadAAFlags::kNone;
|
||||
}
|
||||
@ -811,8 +802,7 @@ private:
|
||||
break;
|
||||
case GrAAType::kCoverage:
|
||||
if (rectStaysRect) {
|
||||
if (aaFlags != GrQuadAAFlags::kNone &&
|
||||
!aa_has_effect_for_rect_stays_rect(quad)) {
|
||||
if (aaFlags != GrQuadAAFlags::kNone && !quad.aaHasEffectOnRect()) {
|
||||
aaFlags = GrQuadAAFlags::kNone;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user