1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2015 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef GrQuad_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define GrQuad_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint3.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkFloatingPoint.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkVx.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h" 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm> 21*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> 22*c8dee2aaSAndroid Build Coastguard Worker 23*c8dee2aaSAndroid Build Coastguard Worker class SkMatrix; 24*c8dee2aaSAndroid Build Coastguard Worker enum class GrQuadAAFlags; 25*c8dee2aaSAndroid Build Coastguard Worker 26*c8dee2aaSAndroid Build Coastguard Worker /** 27*c8dee2aaSAndroid Build Coastguard Worker * GrQuad is a collection of 4 points which can be used to represent an arbitrary quadrilateral. The 28*c8dee2aaSAndroid Build Coastguard Worker * points make a triangle strip with CCW triangles (top-left, bottom-left, top-right, bottom-right). 29*c8dee2aaSAndroid Build Coastguard Worker */ 30*c8dee2aaSAndroid Build Coastguard Worker class GrQuad { 31*c8dee2aaSAndroid Build Coastguard Worker public: 32*c8dee2aaSAndroid Build Coastguard Worker // Quadrilaterals can be classified in several useful ways that assist AA tessellation and other 33*c8dee2aaSAndroid Build Coastguard Worker // analysis when drawing, in particular, knowing if it was originally a rectangle transformed by 34*c8dee2aaSAndroid Build Coastguard Worker // certain types of matrices: 35*c8dee2aaSAndroid Build Coastguard Worker enum class Type { 36*c8dee2aaSAndroid Build Coastguard Worker // The 4 points remain an axis-aligned rectangle; their logical indices may not respect 37*c8dee2aaSAndroid Build Coastguard Worker // TL, BL, TR, BR ordering if the transform was a 90 degree rotation or mirror. 38*c8dee2aaSAndroid Build Coastguard Worker kAxisAligned, 39*c8dee2aaSAndroid Build Coastguard Worker // The 4 points represent a rectangle subjected to a rotation, its corners are right angles. 40*c8dee2aaSAndroid Build Coastguard Worker kRectilinear, 41*c8dee2aaSAndroid Build Coastguard Worker // Arbitrary 2D quadrilateral; may have been a rectangle transformed with skew or some 42*c8dee2aaSAndroid Build Coastguard Worker // clipped polygon. Its w coordinates will all be 1. 43*c8dee2aaSAndroid Build Coastguard Worker kGeneral, 44*c8dee2aaSAndroid Build Coastguard Worker // Even more general-purpose than kGeneral, this allows the w coordinates to be non-unity. 45*c8dee2aaSAndroid Build Coastguard Worker kPerspective, 46*c8dee2aaSAndroid Build Coastguard Worker kLast = kPerspective 47*c8dee2aaSAndroid Build Coastguard Worker }; 48*c8dee2aaSAndroid Build Coastguard Worker static const int kTypeCount = static_cast<int>(Type::kLast) + 1; 49*c8dee2aaSAndroid Build Coastguard Worker 50*c8dee2aaSAndroid Build Coastguard Worker // This enforces W == 1 for non-perspective quads, but does not initialize X or Y. 51*c8dee2aaSAndroid Build Coastguard Worker GrQuad() = default; 52*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const GrQuad&) = default; 53*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const SkRect & rect)54*c8dee2aaSAndroid Build Coastguard Worker explicit GrQuad(const SkRect& rect) 55*c8dee2aaSAndroid Build Coastguard Worker : fX{rect.fLeft, rect.fLeft, rect.fRight, rect.fRight} 56*c8dee2aaSAndroid Build Coastguard Worker , fY{rect.fTop, rect.fBottom, rect.fTop, rect.fBottom} {} 57*c8dee2aaSAndroid Build Coastguard Worker 58*c8dee2aaSAndroid Build Coastguard Worker static GrQuad MakeFromRect(const SkRect&, const SkMatrix&); 59*c8dee2aaSAndroid Build Coastguard Worker 60*c8dee2aaSAndroid Build Coastguard Worker // Creates a GrQuad from the quadrilateral 'pts', transformed by the matrix. The input 61*c8dee2aaSAndroid Build Coastguard Worker // points array is arranged as per SkRect::toQuad (top-left, top-right, bottom-right, 62*c8dee2aaSAndroid Build Coastguard Worker // bottom-left). The returned instance's point order will still be CCW tri-strip order. 63*c8dee2aaSAndroid Build Coastguard Worker static GrQuad MakeFromSkQuad(const SkPoint pts[4], const SkMatrix&); 64*c8dee2aaSAndroid Build Coastguard Worker 65*c8dee2aaSAndroid Build Coastguard Worker GrQuad& operator=(const GrQuad&) = default; 66*c8dee2aaSAndroid Build Coastguard Worker point3(int i)67*c8dee2aaSAndroid Build Coastguard Worker SkPoint3 point3(int i) const { return {fX[i], fY[i], fW[i]}; } 68*c8dee2aaSAndroid Build Coastguard Worker point(int i)69*c8dee2aaSAndroid Build Coastguard Worker SkPoint point(int i) const { 70*c8dee2aaSAndroid Build Coastguard Worker if (fType == Type::kPerspective) { 71*c8dee2aaSAndroid Build Coastguard Worker return {fX[i] / fW[i], fY[i] / fW[i]}; 72*c8dee2aaSAndroid Build Coastguard Worker } else { 73*c8dee2aaSAndroid Build Coastguard Worker return {fX[i], fY[i]}; 74*c8dee2aaSAndroid Build Coastguard Worker } 75*c8dee2aaSAndroid Build Coastguard Worker } 76*c8dee2aaSAndroid Build Coastguard Worker writeVertex(int cornerIdx,skgpu::VertexWriter & w)77*c8dee2aaSAndroid Build Coastguard Worker void writeVertex(int cornerIdx, skgpu::VertexWriter& w) const { 78*c8dee2aaSAndroid Build Coastguard Worker w << this->point(cornerIdx); 79*c8dee2aaSAndroid Build Coastguard Worker } 80*c8dee2aaSAndroid Build Coastguard Worker bounds()81*c8dee2aaSAndroid Build Coastguard Worker SkRect bounds() const { 82*c8dee2aaSAndroid Build Coastguard Worker if (fType == GrQuad::Type::kPerspective) { 83*c8dee2aaSAndroid Build Coastguard Worker return this->projectedBounds(); 84*c8dee2aaSAndroid Build Coastguard Worker } 85*c8dee2aaSAndroid Build Coastguard Worker // Calculate min/max directly on the 4 floats, instead of loading/unloading into SIMD. Since 86*c8dee2aaSAndroid Build Coastguard Worker // there's no horizontal min/max, it's not worth it. Defining non-perspective case in header 87*c8dee2aaSAndroid Build Coastguard Worker // also leads to substantial performance boost due to inlining. 88*c8dee2aaSAndroid Build Coastguard Worker auto min = [](const float c[4]) { return std::min(std::min(c[0], c[1]), 89*c8dee2aaSAndroid Build Coastguard Worker std::min(c[2], c[3]));}; 90*c8dee2aaSAndroid Build Coastguard Worker auto max = [](const float c[4]) { return std::max(std::max(c[0], c[1]), 91*c8dee2aaSAndroid Build Coastguard Worker std::max(c[2], c[3]));}; 92*c8dee2aaSAndroid Build Coastguard Worker return { min(fX), min(fY), max(fX), max(fY) }; 93*c8dee2aaSAndroid Build Coastguard Worker } 94*c8dee2aaSAndroid Build Coastguard Worker isFinite()95*c8dee2aaSAndroid Build Coastguard Worker bool isFinite() const { 96*c8dee2aaSAndroid Build Coastguard Worker // If any coordinate is infinity or NaN, then multiplying it with 0 will make accum NaN 97*c8dee2aaSAndroid Build Coastguard Worker float accum = 0; 98*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < 4; ++i) { 99*c8dee2aaSAndroid Build Coastguard Worker accum *= fX[i]; 100*c8dee2aaSAndroid Build Coastguard Worker accum *= fY[i]; 101*c8dee2aaSAndroid Build Coastguard Worker accum *= fW[i]; 102*c8dee2aaSAndroid Build Coastguard Worker } 103*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 == accum || SkIsNaN(accum)); 104*c8dee2aaSAndroid Build Coastguard Worker 105*c8dee2aaSAndroid Build Coastguard Worker return accum == 0.0f; 106*c8dee2aaSAndroid Build Coastguard Worker } 107*c8dee2aaSAndroid Build Coastguard Worker x(int i)108*c8dee2aaSAndroid Build Coastguard Worker float x(int i) const { return fX[i]; } y(int i)109*c8dee2aaSAndroid Build Coastguard Worker float y(int i) const { return fY[i]; } w(int i)110*c8dee2aaSAndroid Build Coastguard Worker float w(int i) const { return fW[i]; } iw(int i)111*c8dee2aaSAndroid Build Coastguard Worker float iw(int i) const { return sk_ieee_float_divide(1.f, fW[i]); } 112*c8dee2aaSAndroid Build Coastguard Worker x4f()113*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> x4f() const { return skvx::Vec<4, float>::Load(fX); } y4f()114*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> y4f() const { return skvx::Vec<4, float>::Load(fY); } w4f()115*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> w4f() const { return skvx::Vec<4, float>::Load(fW); } iw4f()116*c8dee2aaSAndroid Build Coastguard Worker skvx::Vec<4, float> iw4f() const { return 1.f / this->w4f(); } 117*c8dee2aaSAndroid Build Coastguard Worker quadType()118*c8dee2aaSAndroid Build Coastguard Worker Type quadType() const { return fType; } 119*c8dee2aaSAndroid Build Coastguard Worker hasPerspective()120*c8dee2aaSAndroid Build Coastguard Worker bool hasPerspective() const { return fType == Type::kPerspective; } 121*c8dee2aaSAndroid Build Coastguard Worker 122*c8dee2aaSAndroid Build Coastguard Worker // True if anti-aliasing affects this quad. Only valid when quadType == kAxisAligned 123*c8dee2aaSAndroid Build Coastguard Worker bool aaHasEffectOnRect(GrQuadAAFlags edgeFlags) const; 124*c8dee2aaSAndroid Build Coastguard Worker 125*c8dee2aaSAndroid Build Coastguard Worker // True if this quad is axis-aligned and still has its top-left corner at v0. Equivalently, 126*c8dee2aaSAndroid Build Coastguard Worker // quad == GrQuad(quad->bounds()). Axis-aligned quads with flips and rotations may exactly 127*c8dee2aaSAndroid Build Coastguard Worker // fill their bounds, but their vertex order will not match TL BL TR BR anymore. 128*c8dee2aaSAndroid Build Coastguard Worker bool asRect(SkRect* rect) const; 129*c8dee2aaSAndroid Build Coastguard Worker 130*c8dee2aaSAndroid Build Coastguard Worker // The non-const pointers are provided to support modifying a GrQuad in-place, but care must be 131*c8dee2aaSAndroid Build Coastguard Worker // taken to keep its quad type aligned with the geometric nature of the new coordinates. xs()132*c8dee2aaSAndroid Build Coastguard Worker const float* xs() const { return fX; } xs()133*c8dee2aaSAndroid Build Coastguard Worker float* xs() { return fX; } ys()134*c8dee2aaSAndroid Build Coastguard Worker const float* ys() const { return fY; } ys()135*c8dee2aaSAndroid Build Coastguard Worker float* ys() { return fY; } ws()136*c8dee2aaSAndroid Build Coastguard Worker const float* ws() const { return fW; } ws()137*c8dee2aaSAndroid Build Coastguard Worker float* ws() { return fW; } 138*c8dee2aaSAndroid Build Coastguard Worker 139*c8dee2aaSAndroid Build Coastguard Worker // Automatically ensures ws are 1 if new type is not perspective. setQuadType(Type newType)140*c8dee2aaSAndroid Build Coastguard Worker void setQuadType(Type newType) { 141*c8dee2aaSAndroid Build Coastguard Worker if (newType != Type::kPerspective && fType == Type::kPerspective) { 142*c8dee2aaSAndroid Build Coastguard Worker fW[0] = fW[1] = fW[2] = fW[3] = 1.f; 143*c8dee2aaSAndroid Build Coastguard Worker } 144*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(newType == Type::kPerspective || 145*c8dee2aaSAndroid Build Coastguard Worker (SkScalarNearlyEqual(fW[0], 1.f) && SkScalarNearlyEqual(fW[1], 1.f) && 146*c8dee2aaSAndroid Build Coastguard Worker SkScalarNearlyEqual(fW[2], 1.f) && SkScalarNearlyEqual(fW[3], 1.f))); 147*c8dee2aaSAndroid Build Coastguard Worker 148*c8dee2aaSAndroid Build Coastguard Worker fType = newType; 149*c8dee2aaSAndroid Build Coastguard Worker } 150*c8dee2aaSAndroid Build Coastguard Worker private: 151*c8dee2aaSAndroid Build Coastguard Worker template<typename T> 152*c8dee2aaSAndroid Build Coastguard Worker friend class GrQuadListBase; // for access to fX, fY, fW 153*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,Type type)154*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, Type type) 155*c8dee2aaSAndroid Build Coastguard Worker : fType(type) { 156*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(type != Type::kPerspective); 157*c8dee2aaSAndroid Build Coastguard Worker xs.store(fX); 158*c8dee2aaSAndroid Build Coastguard Worker ys.store(fY); 159*c8dee2aaSAndroid Build Coastguard Worker } 160*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const skvx::Vec<4,float> & xs,const skvx::Vec<4,float> & ys,const skvx::Vec<4,float> & ws,Type type)161*c8dee2aaSAndroid Build Coastguard Worker GrQuad(const skvx::Vec<4, float>& xs, const skvx::Vec<4, float>& ys, 162*c8dee2aaSAndroid Build Coastguard Worker const skvx::Vec<4, float>& ws, Type type) 163*c8dee2aaSAndroid Build Coastguard Worker : fW{} // Include fW in member initializer to avoid redundant default initializer 164*c8dee2aaSAndroid Build Coastguard Worker , fType(type) { 165*c8dee2aaSAndroid Build Coastguard Worker xs.store(fX); 166*c8dee2aaSAndroid Build Coastguard Worker ys.store(fY); 167*c8dee2aaSAndroid Build Coastguard Worker ws.store(fW); 168*c8dee2aaSAndroid Build Coastguard Worker } 169*c8dee2aaSAndroid Build Coastguard Worker 170*c8dee2aaSAndroid Build Coastguard Worker // Defined in GrQuadUtils.cpp to share the coord clipping code 171*c8dee2aaSAndroid Build Coastguard Worker SkRect projectedBounds() const; 172*c8dee2aaSAndroid Build Coastguard Worker 173*c8dee2aaSAndroid Build Coastguard Worker float fX[4]; 174*c8dee2aaSAndroid Build Coastguard Worker float fY[4]; 175*c8dee2aaSAndroid Build Coastguard Worker float fW[4] = {1.f, 1.f, 1.f, 1.f}; 176*c8dee2aaSAndroid Build Coastguard Worker 177*c8dee2aaSAndroid Build Coastguard Worker Type fType = Type::kAxisAligned; 178*c8dee2aaSAndroid Build Coastguard Worker }; 179*c8dee2aaSAndroid Build Coastguard Worker 180*c8dee2aaSAndroid Build Coastguard Worker template<> struct skgpu::VertexWriter::is_quad<GrQuad> : std::true_type {}; 181*c8dee2aaSAndroid Build Coastguard Worker 182*c8dee2aaSAndroid Build Coastguard Worker // A simple struct representing the common work unit of a pair of device and local coordinates, as 183*c8dee2aaSAndroid Build Coastguard Worker // well as the edge flags controlling anti-aliasing for the quadrilateral when drawn. 184*c8dee2aaSAndroid Build Coastguard Worker struct DrawQuad { 185*c8dee2aaSAndroid Build Coastguard Worker GrQuad fDevice; 186*c8dee2aaSAndroid Build Coastguard Worker GrQuad fLocal; 187*c8dee2aaSAndroid Build Coastguard Worker GrQuadAAFlags fEdgeFlags; 188*c8dee2aaSAndroid Build Coastguard Worker }; 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker #endif 191