1419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton/* 2419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * Copyright 2017 Google Inc. 3419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * 4419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * Use of this source code is governed by a BSD-style license that can be 5419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * found in the LICENSE file. 6419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton */ 7419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton 8383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton#ifndef GrGrCCGeometry_DEFINED 9383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton#define GrGrCCGeometry_DEFINED 10419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton 117f578bf07b016778e3105b7655a895728b12d847Chris Dalton#include "SkGeometry.h" 12c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton#include "SkNx.h" 13c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton#include "SkPoint.h" 14c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton#include "SkTArray.h" 15419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton 16c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton/** 17c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton * This class chops device-space contours up into a series of segments that CCPR knows how to 18383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton * render. (See GrCCGeometry::Verb.) 19419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * 20419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * NOTE: This must be done in device space, since an affine transformation can change whether a 21419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton * curve is monotonic. 22419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton */ 23383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltonclass GrCCGeometry { 24c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Daltonpublic: 25c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // These are the verbs that CCPR knows how to draw. If a path has any segments that don't map to 26c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // this list, then they are chopped into smaller ones that do. A list of these comprise a 27c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // compact representation of what can later be expanded into GPU instance data. 28c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton enum class Verb : uint8_t { 29c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kBeginPath, // Included only for caller convenience. 30c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kBeginContour, 31c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kLineTo, 32c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kMonotonicQuadraticTo, // Monotonic relative to the vector between its endpoints [P2 - P0]. 33be4ffab4e208ec47b4298621b9c9e8456f31717eChris Dalton kMonotonicCubicTo, 34c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kEndClosedContour, // endPt == startPt. 35c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton kEndOpenContour // endPt != startPt. 36c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton }; 37c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 3884403d7f53d88b2449fd19415538ba1479fe300bChris Dalton // These tallies track numbers of CCPR primitives that are required to draw a contour. 39c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton struct PrimitiveTallies { 40c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton int fTriangles; // Number of triangles in the contour's fan. 4184403d7f53d88b2449fd19415538ba1479fe300bChris Dalton int fWoundTriangles; // Triangles (from the tessellator) whose winding magnitude > 1. 42c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton int fQuadratics; 43be4ffab4e208ec47b4298621b9c9e8456f31717eChris Dalton int fCubics; 44c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 45c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void operator+=(const PrimitiveTallies&); 46c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton PrimitiveTallies operator-(const PrimitiveTallies&) const; 479ca27849d8259e4b35243094bdca969612efba2fChris Dalton bool operator==(const PrimitiveTallies&); 48c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton }; 49c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 50383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton GrCCGeometry(int numSkPoints = 0, int numSkVerbs = 0) 51c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton : fPoints(numSkPoints * 3) // Reserve for a 3x expansion in points and verbs. 52c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton , fVerbs(numSkVerbs * 3) {} 53c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 54c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton const SkTArray<SkPoint, true>& points() const { SkASSERT(!fBuildingContour); return fPoints; } 55c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton const SkTArray<Verb, true>& verbs() const { SkASSERT(!fBuildingContour); return fVerbs; } 56c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 57c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void reset() { 58c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton SkASSERT(!fBuildingContour); 59c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fPoints.reset(); 60c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fVerbs.reset(); 61c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton } 62c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 63c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // This is included in case the caller needs to discard previously added contours. It is up to 64c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // the caller to track counts and ensure we don't pop back into the middle of a different 65c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // contour. 66c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void resize_back(int numPoints, int numVerbs) { 67c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton SkASSERT(!fBuildingContour); 68c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fPoints.resize_back(numPoints); 69c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fVerbs.resize_back(numVerbs); 70c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton SkASSERT(fVerbs.empty() || fVerbs.back() == Verb::kEndOpenContour || 71c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fVerbs.back() == Verb::kEndClosedContour); 72c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton } 73c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 74c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void beginPath(); 75c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void beginContour(const SkPoint& devPt); 76c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void lineTo(const SkPoint& devPt); 77c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton void quadraticTo(const SkPoint& devP1, const SkPoint& devP2); 787f578bf07b016778e3105b7655a895728b12d847Chris Dalton 797f578bf07b016778e3105b7655a895728b12d847Chris Dalton // We pass through inflection points and loop intersections using a line and quadratic(s) 807f578bf07b016778e3105b7655a895728b12d847Chris Dalton // respectively. 'inflectPad' and 'loopIntersectPad' specify how close (in pixels) cubic 817f578bf07b016778e3105b7655a895728b12d847Chris Dalton // segments are allowed to get to these points. For normal rendering you will want to use the 827f578bf07b016778e3105b7655a895728b12d847Chris Dalton // default values, but these can be overridden for testing purposes. 837f578bf07b016778e3105b7655a895728b12d847Chris Dalton // 847f578bf07b016778e3105b7655a895728b12d847Chris Dalton // NOTE: loops do appear to require two full pixels of padding around the intersection point. 857f578bf07b016778e3105b7655a895728b12d847Chris Dalton // With just one pixel-width of pad, we start to see bad pixels. Ultimately this has a 867f578bf07b016778e3105b7655a895728b12d847Chris Dalton // minimal effect on the total amount of segments produced. Most sections that pass 877f578bf07b016778e3105b7655a895728b12d847Chris Dalton // through the loop intersection can be approximated with a single quadratic anyway, 887f578bf07b016778e3105b7655a895728b12d847Chris Dalton // regardless of whether we are use one pixel of pad or two (1.622 avg. quads per loop 897f578bf07b016778e3105b7655a895728b12d847Chris Dalton // intersection vs. 1.489 on the tiger). 907f578bf07b016778e3105b7655a895728b12d847Chris Dalton void cubicTo(const SkPoint& devP1, const SkPoint& devP2, const SkPoint& devP3, 917f578bf07b016778e3105b7655a895728b12d847Chris Dalton float inflectPad = 0.55f, float loopIntersectPad = 2); 927f578bf07b016778e3105b7655a895728b12d847Chris Dalton 93c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton PrimitiveTallies endContour(); // Returns the numbers of primitives needed to draw the contour. 94c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 95c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Daltonprivate: 9643646533fa6fb7cd6724cf00f6b8af15ac1649eaChris Dalton inline void appendMonotonicQuadratics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2); 9743646533fa6fb7cd6724cf00f6b8af15ac1649eaChris Dalton inline void appendSingleMonotonicQuadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2); 987f578bf07b016778e3105b7655a895728b12d847Chris Dalton 99383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton using AppendCubicFn = void(GrCCGeometry::*)(const Sk2f& p0, const Sk2f& p1, 100383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton const Sk2f& p2, const Sk2f& p3, 101383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Dalton int maxSubdivisions); 1027f578bf07b016778e3105b7655a895728b12d847Chris Dalton static constexpr int kMaxSubdivionsPerCubicSection = 2; 1037f578bf07b016778e3105b7655a895728b12d847Chris Dalton 1047f578bf07b016778e3105b7655a895728b12d847Chris Dalton template<AppendCubicFn AppendLeftRight> 1057f578bf07b016778e3105b7655a895728b12d847Chris Dalton inline void chopCubicAtMidTangent(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, 1067f578bf07b016778e3105b7655a895728b12d847Chris Dalton const Sk2f& p3, const Sk2f& tan0, const Sk2f& tan3, 1077f578bf07b016778e3105b7655a895728b12d847Chris Dalton int maxFutureSubdivisions = kMaxSubdivionsPerCubicSection); 1087f578bf07b016778e3105b7655a895728b12d847Chris Dalton 1097f578bf07b016778e3105b7655a895728b12d847Chris Dalton template<AppendCubicFn AppendLeft, AppendCubicFn AppendRight> 1107f578bf07b016778e3105b7655a895728b12d847Chris Dalton inline void chopCubic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3, 1117f578bf07b016778e3105b7655a895728b12d847Chris Dalton float T, int maxFutureSubdivisions = kMaxSubdivionsPerCubicSection); 1127f578bf07b016778e3105b7655a895728b12d847Chris Dalton 1137f578bf07b016778e3105b7655a895728b12d847Chris Dalton void appendMonotonicCubics(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3, 1147f578bf07b016778e3105b7655a895728b12d847Chris Dalton int maxSubdivisions = kMaxSubdivionsPerCubicSection); 1157f578bf07b016778e3105b7655a895728b12d847Chris Dalton void appendCubicApproximation(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, const Sk2f& p3, 1167f578bf07b016778e3105b7655a895728b12d847Chris Dalton int maxSubdivisions = kMaxSubdivionsPerCubicSection); 117c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 118c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // Transient state used while building a contour. 11984403d7f53d88b2449fd19415538ba1479fe300bChris Dalton SkPoint fCurrAnchorPoint; 12084403d7f53d88b2449fd19415538ba1479fe300bChris Dalton SkPoint fCurrFanPoint; 12184403d7f53d88b2449fd19415538ba1479fe300bChris Dalton PrimitiveTallies fCurrContourTallies; 12284403d7f53d88b2449fd19415538ba1479fe300bChris Dalton SkCubicType fCurrCubicType; 12384403d7f53d88b2449fd19415538ba1479fe300bChris Dalton SkDEBUGCODE(bool fBuildingContour = false); 124c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 125c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton // TODO: These points could eventually be written directly to block-allocated GPU buffers. 126c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton SkSTArray<128, SkPoint, true> fPoints; 127c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton SkSTArray<128, Verb, true> fVerbs; 128c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton}; 129c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 130383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltoninline void GrCCGeometry::PrimitiveTallies::operator+=(const PrimitiveTallies& b) { 131c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fTriangles += b.fTriangles; 13284403d7f53d88b2449fd19415538ba1479fe300bChris Dalton fWoundTriangles += b.fWoundTriangles; 133c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fQuadratics += b.fQuadratics; 134be4ffab4e208ec47b4298621b9c9e8456f31717eChris Dalton fCubics += b.fCubics; 135c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton} 136c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton 137383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris DaltonGrCCGeometry::PrimitiveTallies 138383a2ef6edb84dbebc7a9c22ea7423037bbf6a2fChris Daltoninline GrCCGeometry::PrimitiveTallies::operator-(const PrimitiveTallies& b) const { 139c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton return {fTriangles - b.fTriangles, 14084403d7f53d88b2449fd19415538ba1479fe300bChris Dalton fWoundTriangles - b.fWoundTriangles, 141c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton fQuadratics - b.fQuadratics, 142be4ffab4e208ec47b4298621b9c9e8456f31717eChris Dalton fCubics - b.fCubics}; 143c1e59638b4a08f5210f72f671292b1b3759f54c6Chris Dalton} 144419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton 1459ca27849d8259e4b35243094bdca969612efba2fChris Daltoninline bool GrCCGeometry::PrimitiveTallies::operator==(const PrimitiveTallies& b) { 14684403d7f53d88b2449fd19415538ba1479fe300bChris Dalton return fTriangles == b.fTriangles && fWoundTriangles == b.fWoundTriangles && 14784403d7f53d88b2449fd19415538ba1479fe300bChris Dalton fQuadratics == b.fQuadratics && fCubics == b.fCubics; 1489ca27849d8259e4b35243094bdca969612efba2fChris Dalton} 1499ca27849d8259e4b35243094bdca969612efba2fChris Dalton 150419a94da028b33425a0feeb44d0d022a5d3d3704Chris Dalton#endif 151