1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2012 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/ops/AAConvexPathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkString.h" 11cb93a386Sopenharmony_ci#include "include/core/SkTypes.h" 12cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 14cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 15cb93a386Sopenharmony_ci#include "src/core/SkPointPriv.h" 16cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 23cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h" 24cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 25cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" 26cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLProgramDataManager.h" 27cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLUniformHandler.h" 28cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVarying.h" 29cb93a386Sopenharmony_ci#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" 30cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 31cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 32cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cinamespace skgpu::v1 { 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cinamespace { 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_cistruct Segment { 39cb93a386Sopenharmony_ci enum { 40cb93a386Sopenharmony_ci // These enum values are assumed in member functions below. 41cb93a386Sopenharmony_ci kLine = 0, 42cb93a386Sopenharmony_ci kQuad = 1, 43cb93a386Sopenharmony_ci } fType; 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci // line uses one pt, quad uses 2 pts 46cb93a386Sopenharmony_ci SkPoint fPts[2]; 47cb93a386Sopenharmony_ci // normal to edge ending at each pt 48cb93a386Sopenharmony_ci SkVector fNorms[2]; 49cb93a386Sopenharmony_ci // is the corner where the previous segment meets this segment 50cb93a386Sopenharmony_ci // sharp. If so, fMid is a normalized bisector facing outward. 51cb93a386Sopenharmony_ci SkVector fMid; 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci int countPoints() { 54cb93a386Sopenharmony_ci static_assert(0 == kLine && 1 == kQuad); 55cb93a386Sopenharmony_ci return fType + 1; 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci const SkPoint& endPt() const { 58cb93a386Sopenharmony_ci static_assert(0 == kLine && 1 == kQuad); 59cb93a386Sopenharmony_ci return fPts[fType]; 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci const SkPoint& endNorm() const { 62cb93a386Sopenharmony_ci static_assert(0 == kLine && 1 == kQuad); 63cb93a386Sopenharmony_ci return fNorms[fType]; 64cb93a386Sopenharmony_ci } 65cb93a386Sopenharmony_ci}; 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_citypedef SkTArray<Segment, true> SegmentArray; 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_cibool center_of_mass(const SegmentArray& segments, SkPoint* c) { 70cb93a386Sopenharmony_ci SkScalar area = 0; 71cb93a386Sopenharmony_ci SkPoint center = {0, 0}; 72cb93a386Sopenharmony_ci int count = segments.count(); 73cb93a386Sopenharmony_ci SkPoint p0 = {0, 0}; 74cb93a386Sopenharmony_ci if (count > 2) { 75cb93a386Sopenharmony_ci // We translate the polygon so that the first point is at the origin. 76cb93a386Sopenharmony_ci // This avoids some precision issues with small area polygons far away 77cb93a386Sopenharmony_ci // from the origin. 78cb93a386Sopenharmony_ci p0 = segments[0].endPt(); 79cb93a386Sopenharmony_ci SkPoint pi; 80cb93a386Sopenharmony_ci SkPoint pj; 81cb93a386Sopenharmony_ci // the first and last iteration of the below loop would compute 82cb93a386Sopenharmony_ci // zeros since the starting / ending point is (0,0). So instead we start 83cb93a386Sopenharmony_ci // at i=1 and make the last iteration i=count-2. 84cb93a386Sopenharmony_ci pj = segments[1].endPt() - p0; 85cb93a386Sopenharmony_ci for (int i = 1; i < count - 1; ++i) { 86cb93a386Sopenharmony_ci pi = pj; 87cb93a386Sopenharmony_ci pj = segments[i + 1].endPt() - p0; 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ci SkScalar t = SkPoint::CrossProduct(pi, pj); 90cb93a386Sopenharmony_ci area += t; 91cb93a386Sopenharmony_ci center.fX += (pi.fX + pj.fX) * t; 92cb93a386Sopenharmony_ci center.fY += (pi.fY + pj.fY) * t; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci // If the poly has no area then we instead return the average of 97cb93a386Sopenharmony_ci // its points. 98cb93a386Sopenharmony_ci if (SkScalarNearlyZero(area)) { 99cb93a386Sopenharmony_ci SkPoint avg; 100cb93a386Sopenharmony_ci avg.set(0, 0); 101cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 102cb93a386Sopenharmony_ci const SkPoint& pt = segments[i].endPt(); 103cb93a386Sopenharmony_ci avg.fX += pt.fX; 104cb93a386Sopenharmony_ci avg.fY += pt.fY; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci SkScalar denom = SK_Scalar1 / count; 107cb93a386Sopenharmony_ci avg.scale(denom); 108cb93a386Sopenharmony_ci *c = avg; 109cb93a386Sopenharmony_ci } else { 110cb93a386Sopenharmony_ci area *= 3; 111cb93a386Sopenharmony_ci area = SkScalarInvert(area); 112cb93a386Sopenharmony_ci center.scale(area); 113cb93a386Sopenharmony_ci // undo the translate of p0 to the origin. 114cb93a386Sopenharmony_ci *c = center + p0; 115cb93a386Sopenharmony_ci } 116cb93a386Sopenharmony_ci return !SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY) && c->isFinite(); 117cb93a386Sopenharmony_ci} 118cb93a386Sopenharmony_ci 119cb93a386Sopenharmony_cibool compute_vectors(SegmentArray* segments, 120cb93a386Sopenharmony_ci SkPoint* fanPt, 121cb93a386Sopenharmony_ci SkPathFirstDirection dir, 122cb93a386Sopenharmony_ci int* vCount, 123cb93a386Sopenharmony_ci int* iCount) { 124cb93a386Sopenharmony_ci if (!center_of_mass(*segments, fanPt)) { 125cb93a386Sopenharmony_ci return false; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci int count = segments->count(); 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci // Make the normals point towards the outside 130cb93a386Sopenharmony_ci SkPointPriv::Side normSide; 131cb93a386Sopenharmony_ci if (dir == SkPathFirstDirection::kCCW) { 132cb93a386Sopenharmony_ci normSide = SkPointPriv::kRight_Side; 133cb93a386Sopenharmony_ci } else { 134cb93a386Sopenharmony_ci normSide = SkPointPriv::kLeft_Side; 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci int64_t vCount64 = 0; 138cb93a386Sopenharmony_ci int64_t iCount64 = 0; 139cb93a386Sopenharmony_ci // compute normals at all points 140cb93a386Sopenharmony_ci for (int a = 0; a < count; ++a) { 141cb93a386Sopenharmony_ci Segment& sega = (*segments)[a]; 142cb93a386Sopenharmony_ci int b = (a + 1) % count; 143cb93a386Sopenharmony_ci Segment& segb = (*segments)[b]; 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci const SkPoint* prevPt = &sega.endPt(); 146cb93a386Sopenharmony_ci int n = segb.countPoints(); 147cb93a386Sopenharmony_ci for (int p = 0; p < n; ++p) { 148cb93a386Sopenharmony_ci segb.fNorms[p] = segb.fPts[p] - *prevPt; 149cb93a386Sopenharmony_ci segb.fNorms[p].normalize(); 150cb93a386Sopenharmony_ci segb.fNorms[p] = SkPointPriv::MakeOrthog(segb.fNorms[p], normSide); 151cb93a386Sopenharmony_ci prevPt = &segb.fPts[p]; 152cb93a386Sopenharmony_ci } 153cb93a386Sopenharmony_ci if (Segment::kLine == segb.fType) { 154cb93a386Sopenharmony_ci vCount64 += 5; 155cb93a386Sopenharmony_ci iCount64 += 9; 156cb93a386Sopenharmony_ci } else { 157cb93a386Sopenharmony_ci vCount64 += 6; 158cb93a386Sopenharmony_ci iCount64 += 12; 159cb93a386Sopenharmony_ci } 160cb93a386Sopenharmony_ci } 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ci // compute mid-vectors where segments meet. TODO: Detect shallow corners 163cb93a386Sopenharmony_ci // and leave out the wedges and close gaps by stitching segments together. 164cb93a386Sopenharmony_ci for (int a = 0; a < count; ++a) { 165cb93a386Sopenharmony_ci const Segment& sega = (*segments)[a]; 166cb93a386Sopenharmony_ci int b = (a + 1) % count; 167cb93a386Sopenharmony_ci Segment& segb = (*segments)[b]; 168cb93a386Sopenharmony_ci segb.fMid = segb.fNorms[0] + sega.endNorm(); 169cb93a386Sopenharmony_ci segb.fMid.normalize(); 170cb93a386Sopenharmony_ci // corner wedges 171cb93a386Sopenharmony_ci vCount64 += 4; 172cb93a386Sopenharmony_ci iCount64 += 6; 173cb93a386Sopenharmony_ci } 174cb93a386Sopenharmony_ci if (vCount64 > SK_MaxS32 || iCount64 > SK_MaxS32) { 175cb93a386Sopenharmony_ci return false; 176cb93a386Sopenharmony_ci } 177cb93a386Sopenharmony_ci *vCount = vCount64; 178cb93a386Sopenharmony_ci *iCount = iCount64; 179cb93a386Sopenharmony_ci return true; 180cb93a386Sopenharmony_ci} 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_cistruct DegenerateTestData { 183cb93a386Sopenharmony_ci DegenerateTestData() { fStage = kInitial; } 184cb93a386Sopenharmony_ci bool isDegenerate() const { return kNonDegenerate != fStage; } 185cb93a386Sopenharmony_ci enum { 186cb93a386Sopenharmony_ci kInitial, 187cb93a386Sopenharmony_ci kPoint, 188cb93a386Sopenharmony_ci kLine, 189cb93a386Sopenharmony_ci kNonDegenerate 190cb93a386Sopenharmony_ci } fStage; 191cb93a386Sopenharmony_ci SkPoint fFirstPoint; 192cb93a386Sopenharmony_ci SkVector fLineNormal; 193cb93a386Sopenharmony_ci SkScalar fLineC; 194cb93a386Sopenharmony_ci}; 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_cistatic const SkScalar kClose = (SK_Scalar1 / 16); 197cb93a386Sopenharmony_cistatic const SkScalar kCloseSqd = kClose * kClose; 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_civoid update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) { 200cb93a386Sopenharmony_ci switch (data->fStage) { 201cb93a386Sopenharmony_ci case DegenerateTestData::kInitial: 202cb93a386Sopenharmony_ci data->fFirstPoint = pt; 203cb93a386Sopenharmony_ci data->fStage = DegenerateTestData::kPoint; 204cb93a386Sopenharmony_ci break; 205cb93a386Sopenharmony_ci case DegenerateTestData::kPoint: 206cb93a386Sopenharmony_ci if (SkPointPriv::DistanceToSqd(pt, data->fFirstPoint) > kCloseSqd) { 207cb93a386Sopenharmony_ci data->fLineNormal = pt - data->fFirstPoint; 208cb93a386Sopenharmony_ci data->fLineNormal.normalize(); 209cb93a386Sopenharmony_ci data->fLineNormal = SkPointPriv::MakeOrthog(data->fLineNormal); 210cb93a386Sopenharmony_ci data->fLineC = -data->fLineNormal.dot(data->fFirstPoint); 211cb93a386Sopenharmony_ci data->fStage = DegenerateTestData::kLine; 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci break; 214cb93a386Sopenharmony_ci case DegenerateTestData::kLine: 215cb93a386Sopenharmony_ci if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) { 216cb93a386Sopenharmony_ci data->fStage = DegenerateTestData::kNonDegenerate; 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci break; 219cb93a386Sopenharmony_ci case DegenerateTestData::kNonDegenerate: 220cb93a386Sopenharmony_ci break; 221cb93a386Sopenharmony_ci default: 222cb93a386Sopenharmony_ci SK_ABORT("Unexpected degenerate test stage."); 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci} 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ciinline bool get_direction(const SkPath& path, const SkMatrix& m, SkPathFirstDirection* dir) { 227cb93a386Sopenharmony_ci // At this point, we've already returned true from canDraw(), which checked that the path's 228cb93a386Sopenharmony_ci // direction could be determined, so this should just be fetching the cached direction. 229cb93a386Sopenharmony_ci // However, if perspective is involved, we're operating on a transformed path, which may no 230cb93a386Sopenharmony_ci // longer have a computable direction. 231cb93a386Sopenharmony_ci *dir = SkPathPriv::ComputeFirstDirection(path); 232cb93a386Sopenharmony_ci if (*dir == SkPathFirstDirection::kUnknown) { 233cb93a386Sopenharmony_ci return false; 234cb93a386Sopenharmony_ci } 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci // check whether m reverses the orientation 237cb93a386Sopenharmony_ci SkASSERT(!m.hasPerspective()); 238cb93a386Sopenharmony_ci SkScalar det2x2 = m.get(SkMatrix::kMScaleX) * m.get(SkMatrix::kMScaleY) - 239cb93a386Sopenharmony_ci m.get(SkMatrix::kMSkewX) * m.get(SkMatrix::kMSkewY); 240cb93a386Sopenharmony_ci if (det2x2 < 0) { 241cb93a386Sopenharmony_ci *dir = SkPathPriv::OppositeFirstDirection(*dir); 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci return true; 245cb93a386Sopenharmony_ci} 246cb93a386Sopenharmony_ci 247cb93a386Sopenharmony_ciinline void add_line_to_segment(const SkPoint& pt, SegmentArray* segments) { 248cb93a386Sopenharmony_ci segments->push_back(); 249cb93a386Sopenharmony_ci segments->back().fType = Segment::kLine; 250cb93a386Sopenharmony_ci segments->back().fPts[0] = pt; 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ciinline void add_quad_segment(const SkPoint pts[3], SegmentArray* segments) { 254cb93a386Sopenharmony_ci if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) { 255cb93a386Sopenharmony_ci if (pts[0] != pts[2]) { 256cb93a386Sopenharmony_ci add_line_to_segment(pts[2], segments); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci } else { 259cb93a386Sopenharmony_ci segments->push_back(); 260cb93a386Sopenharmony_ci segments->back().fType = Segment::kQuad; 261cb93a386Sopenharmony_ci segments->back().fPts[0] = pts[1]; 262cb93a386Sopenharmony_ci segments->back().fPts[1] = pts[2]; 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci} 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ciinline void add_cubic_segments(const SkPoint pts[4], 267cb93a386Sopenharmony_ci SkPathFirstDirection dir, 268cb93a386Sopenharmony_ci SegmentArray* segments) { 269cb93a386Sopenharmony_ci SkSTArray<15, SkPoint, true> quads; 270cb93a386Sopenharmony_ci GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads); 271cb93a386Sopenharmony_ci int count = quads.count(); 272cb93a386Sopenharmony_ci for (int q = 0; q < count; q += 3) { 273cb93a386Sopenharmony_ci add_quad_segment(&quads[q], segments); 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci} 276cb93a386Sopenharmony_ci 277cb93a386Sopenharmony_cibool get_segments(const SkPath& path, 278cb93a386Sopenharmony_ci const SkMatrix& m, 279cb93a386Sopenharmony_ci SegmentArray* segments, 280cb93a386Sopenharmony_ci SkPoint* fanPt, 281cb93a386Sopenharmony_ci int* vCount, 282cb93a386Sopenharmony_ci int* iCount) { 283cb93a386Sopenharmony_ci SkPath::Iter iter(path, true); 284cb93a386Sopenharmony_ci // This renderer over-emphasizes very thin path regions. We use the distance 285cb93a386Sopenharmony_ci // to the path from the sample to compute coverage. Every pixel intersected 286cb93a386Sopenharmony_ci // by the path will be hit and the maximum distance is sqrt(2)/2. We don't 287cb93a386Sopenharmony_ci // notice that the sample may be close to a very thin area of the path and 288cb93a386Sopenharmony_ci // thus should be very light. This is particularly egregious for degenerate 289cb93a386Sopenharmony_ci // line paths. We detect paths that are very close to a line (zero area) and 290cb93a386Sopenharmony_ci // draw nothing. 291cb93a386Sopenharmony_ci DegenerateTestData degenerateData; 292cb93a386Sopenharmony_ci SkPathFirstDirection dir; 293cb93a386Sopenharmony_ci if (!get_direction(path, m, &dir)) { 294cb93a386Sopenharmony_ci return false; 295cb93a386Sopenharmony_ci } 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci for (;;) { 298cb93a386Sopenharmony_ci SkPoint pts[4]; 299cb93a386Sopenharmony_ci SkPath::Verb verb = iter.next(pts); 300cb93a386Sopenharmony_ci switch (verb) { 301cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 302cb93a386Sopenharmony_ci m.mapPoints(pts, 1); 303cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[0]); 304cb93a386Sopenharmony_ci break; 305cb93a386Sopenharmony_ci case SkPath::kLine_Verb: { 306cb93a386Sopenharmony_ci if (!SkPathPriv::AllPointsEq(pts, 2)) { 307cb93a386Sopenharmony_ci m.mapPoints(&pts[1], 1); 308cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[1]); 309cb93a386Sopenharmony_ci add_line_to_segment(pts[1], segments); 310cb93a386Sopenharmony_ci } 311cb93a386Sopenharmony_ci break; 312cb93a386Sopenharmony_ci } 313cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 314cb93a386Sopenharmony_ci if (!SkPathPriv::AllPointsEq(pts, 3)) { 315cb93a386Sopenharmony_ci m.mapPoints(pts, 3); 316cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[1]); 317cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[2]); 318cb93a386Sopenharmony_ci add_quad_segment(pts, segments); 319cb93a386Sopenharmony_ci } 320cb93a386Sopenharmony_ci break; 321cb93a386Sopenharmony_ci case SkPath::kConic_Verb: { 322cb93a386Sopenharmony_ci if (!SkPathPriv::AllPointsEq(pts, 3)) { 323cb93a386Sopenharmony_ci m.mapPoints(pts, 3); 324cb93a386Sopenharmony_ci SkScalar weight = iter.conicWeight(); 325cb93a386Sopenharmony_ci SkAutoConicToQuads converter; 326cb93a386Sopenharmony_ci const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f); 327cb93a386Sopenharmony_ci for (int i = 0; i < converter.countQuads(); ++i) { 328cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, quadPts[2*i + 1]); 329cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, quadPts[2*i + 2]); 330cb93a386Sopenharmony_ci add_quad_segment(quadPts + 2*i, segments); 331cb93a386Sopenharmony_ci } 332cb93a386Sopenharmony_ci } 333cb93a386Sopenharmony_ci break; 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: { 336cb93a386Sopenharmony_ci if (!SkPathPriv::AllPointsEq(pts, 4)) { 337cb93a386Sopenharmony_ci m.mapPoints(pts, 4); 338cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[1]); 339cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[2]); 340cb93a386Sopenharmony_ci update_degenerate_test(°enerateData, pts[3]); 341cb93a386Sopenharmony_ci add_cubic_segments(pts, dir, segments); 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci break; 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 346cb93a386Sopenharmony_ci if (degenerateData.isDegenerate()) { 347cb93a386Sopenharmony_ci return false; 348cb93a386Sopenharmony_ci } else { 349cb93a386Sopenharmony_ci return compute_vectors(segments, fanPt, dir, vCount, iCount); 350cb93a386Sopenharmony_ci } 351cb93a386Sopenharmony_ci default: 352cb93a386Sopenharmony_ci break; 353cb93a386Sopenharmony_ci } 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci} 356cb93a386Sopenharmony_ci 357cb93a386Sopenharmony_cistruct Draw { 358cb93a386Sopenharmony_ci Draw() : fVertexCnt(0), fIndexCnt(0) {} 359cb93a386Sopenharmony_ci int fVertexCnt; 360cb93a386Sopenharmony_ci int fIndexCnt; 361cb93a386Sopenharmony_ci}; 362cb93a386Sopenharmony_ci 363cb93a386Sopenharmony_citypedef SkTArray<Draw, true> DrawArray; 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_civoid create_vertices(const SegmentArray& segments, 366cb93a386Sopenharmony_ci const SkPoint& fanPt, 367cb93a386Sopenharmony_ci const GrVertexColor& color, 368cb93a386Sopenharmony_ci DrawArray* draws, 369cb93a386Sopenharmony_ci VertexWriter& verts, 370cb93a386Sopenharmony_ci uint16_t* idxs, 371cb93a386Sopenharmony_ci size_t vertexStride) { 372cb93a386Sopenharmony_ci Draw* draw = &draws->push_back(); 373cb93a386Sopenharmony_ci // alias just to make vert/index assignments easier to read. 374cb93a386Sopenharmony_ci int* v = &draw->fVertexCnt; 375cb93a386Sopenharmony_ci int* i = &draw->fIndexCnt; 376cb93a386Sopenharmony_ci 377cb93a386Sopenharmony_ci int count = segments.count(); 378cb93a386Sopenharmony_ci for (int a = 0; a < count; ++a) { 379cb93a386Sopenharmony_ci const Segment& sega = segments[a]; 380cb93a386Sopenharmony_ci int b = (a + 1) % count; 381cb93a386Sopenharmony_ci const Segment& segb = segments[b]; 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci // Check whether adding the verts for this segment to the current draw would cause index 384cb93a386Sopenharmony_ci // values to overflow. 385cb93a386Sopenharmony_ci int vCount = 4; 386cb93a386Sopenharmony_ci if (Segment::kLine == segb.fType) { 387cb93a386Sopenharmony_ci vCount += 5; 388cb93a386Sopenharmony_ci } else { 389cb93a386Sopenharmony_ci vCount += 6; 390cb93a386Sopenharmony_ci } 391cb93a386Sopenharmony_ci if (draw->fVertexCnt + vCount > (1 << 16)) { 392cb93a386Sopenharmony_ci idxs += *i; 393cb93a386Sopenharmony_ci draw = &draws->push_back(); 394cb93a386Sopenharmony_ci v = &draw->fVertexCnt; 395cb93a386Sopenharmony_ci i = &draw->fIndexCnt; 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci 398cb93a386Sopenharmony_ci const SkScalar negOneDists[2] = { -SK_Scalar1, -SK_Scalar1 }; 399cb93a386Sopenharmony_ci 400cb93a386Sopenharmony_ci // FIXME: These tris are inset in the 1 unit arc around the corner 401cb93a386Sopenharmony_ci SkPoint p0 = sega.endPt(); 402cb93a386Sopenharmony_ci // Position, Color, UV, D0, D1 403cb93a386Sopenharmony_ci verts << p0 << color << SkPoint{0, 0} << negOneDists; 404cb93a386Sopenharmony_ci verts << (p0 + sega.endNorm()) << color << SkPoint{0, -SK_Scalar1} << negOneDists; 405cb93a386Sopenharmony_ci verts << (p0 + segb.fMid) << color << SkPoint{0, -SK_Scalar1} << negOneDists; 406cb93a386Sopenharmony_ci verts << (p0 + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists; 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci idxs[*i + 0] = *v + 0; 409cb93a386Sopenharmony_ci idxs[*i + 1] = *v + 2; 410cb93a386Sopenharmony_ci idxs[*i + 2] = *v + 1; 411cb93a386Sopenharmony_ci idxs[*i + 3] = *v + 0; 412cb93a386Sopenharmony_ci idxs[*i + 4] = *v + 3; 413cb93a386Sopenharmony_ci idxs[*i + 5] = *v + 2; 414cb93a386Sopenharmony_ci 415cb93a386Sopenharmony_ci *v += 4; 416cb93a386Sopenharmony_ci *i += 6; 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci if (Segment::kLine == segb.fType) { 419cb93a386Sopenharmony_ci // we draw the line edge as a degenerate quad (u is 0, v is the 420cb93a386Sopenharmony_ci // signed distance to the edge) 421cb93a386Sopenharmony_ci SkPoint v1Pos = sega.endPt(); 422cb93a386Sopenharmony_ci SkPoint v2Pos = segb.fPts[0]; 423cb93a386Sopenharmony_ci SkScalar dist = SkPointPriv::DistanceToLineBetween(fanPt, v1Pos, v2Pos); 424cb93a386Sopenharmony_ci 425cb93a386Sopenharmony_ci verts << fanPt << color << SkPoint{0, dist} << negOneDists; 426cb93a386Sopenharmony_ci verts << v1Pos << color << SkPoint{0, 0} << negOneDists; 427cb93a386Sopenharmony_ci verts << v2Pos << color << SkPoint{0, 0} << negOneDists; 428cb93a386Sopenharmony_ci verts << (v1Pos + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists; 429cb93a386Sopenharmony_ci verts << (v2Pos + segb.fNorms[0]) << color << SkPoint{0, -SK_Scalar1} << negOneDists; 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci idxs[*i + 0] = *v + 3; 432cb93a386Sopenharmony_ci idxs[*i + 1] = *v + 1; 433cb93a386Sopenharmony_ci idxs[*i + 2] = *v + 2; 434cb93a386Sopenharmony_ci 435cb93a386Sopenharmony_ci idxs[*i + 3] = *v + 4; 436cb93a386Sopenharmony_ci idxs[*i + 4] = *v + 3; 437cb93a386Sopenharmony_ci idxs[*i + 5] = *v + 2; 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci *i += 6; 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci // Draw the interior fan if it exists. 442cb93a386Sopenharmony_ci // TODO: Detect and combine colinear segments. This will ensure we catch every case 443cb93a386Sopenharmony_ci // with no interior, and that the resulting shared edge uses the same endpoints. 444cb93a386Sopenharmony_ci if (count >= 3) { 445cb93a386Sopenharmony_ci idxs[*i + 0] = *v + 0; 446cb93a386Sopenharmony_ci idxs[*i + 1] = *v + 2; 447cb93a386Sopenharmony_ci idxs[*i + 2] = *v + 1; 448cb93a386Sopenharmony_ci 449cb93a386Sopenharmony_ci *i += 3; 450cb93a386Sopenharmony_ci } 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ci *v += 5; 453cb93a386Sopenharmony_ci } else { 454cb93a386Sopenharmony_ci SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]}; 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci SkScalar c0 = segb.fNorms[0].dot(qpts[0]); 457cb93a386Sopenharmony_ci SkScalar c1 = segb.fNorms[1].dot(qpts[2]); 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci // We must transform the positions into UV in cpu memory and then copy them to the gpu 460cb93a386Sopenharmony_ci // buffer. If we write the position first into the gpu buffer then calculate the UVs, it 461cb93a386Sopenharmony_ci // will cause us to read from the GPU buffer which can be very slow. 462cb93a386Sopenharmony_ci struct PosAndUV { 463cb93a386Sopenharmony_ci SkPoint fPos; 464cb93a386Sopenharmony_ci SkPoint fUV; 465cb93a386Sopenharmony_ci }; 466cb93a386Sopenharmony_ci PosAndUV posAndUVPoints[6]; 467cb93a386Sopenharmony_ci posAndUVPoints[0].fPos = fanPt; 468cb93a386Sopenharmony_ci posAndUVPoints[1].fPos = qpts[0]; 469cb93a386Sopenharmony_ci posAndUVPoints[2].fPos = qpts[2]; 470cb93a386Sopenharmony_ci posAndUVPoints[3].fPos = qpts[0] + segb.fNorms[0]; 471cb93a386Sopenharmony_ci posAndUVPoints[4].fPos = qpts[2] + segb.fNorms[1]; 472cb93a386Sopenharmony_ci SkVector midVec = segb.fNorms[0] + segb.fNorms[1]; 473cb93a386Sopenharmony_ci midVec.normalize(); 474cb93a386Sopenharmony_ci posAndUVPoints[5].fPos = qpts[1] + midVec; 475cb93a386Sopenharmony_ci 476cb93a386Sopenharmony_ci GrPathUtils::QuadUVMatrix toUV(qpts); 477cb93a386Sopenharmony_ci toUV.apply(posAndUVPoints, 6, sizeof(PosAndUV), sizeof(SkPoint)); 478cb93a386Sopenharmony_ci 479cb93a386Sopenharmony_ci verts << posAndUVPoints[0].fPos << color << posAndUVPoints[0].fUV 480cb93a386Sopenharmony_ci << (-segb.fNorms[0].dot(fanPt) + c0) 481cb93a386Sopenharmony_ci << (-segb.fNorms[1].dot(fanPt) + c1); 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci verts << posAndUVPoints[1].fPos << color << posAndUVPoints[1].fUV 484cb93a386Sopenharmony_ci << 0.0f 485cb93a386Sopenharmony_ci << (-segb.fNorms[1].dot(qpts[0]) + c1); 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci verts << posAndUVPoints[2].fPos << color << posAndUVPoints[2].fUV 488cb93a386Sopenharmony_ci << (-segb.fNorms[0].dot(qpts[2]) + c0) 489cb93a386Sopenharmony_ci << 0.0f; 490cb93a386Sopenharmony_ci // We need a negative value that is very large that it won't effect results if it is 491cb93a386Sopenharmony_ci // interpolated with. However, the value can't be too large of a negative that it 492cb93a386Sopenharmony_ci // effects numerical precision on less powerful GPUs. 493cb93a386Sopenharmony_ci static const SkScalar kStableLargeNegativeValue = -SK_ScalarMax/1000000; 494cb93a386Sopenharmony_ci verts << posAndUVPoints[3].fPos << color << posAndUVPoints[3].fUV 495cb93a386Sopenharmony_ci << kStableLargeNegativeValue 496cb93a386Sopenharmony_ci << kStableLargeNegativeValue; 497cb93a386Sopenharmony_ci 498cb93a386Sopenharmony_ci verts << posAndUVPoints[4].fPos << color << posAndUVPoints[4].fUV 499cb93a386Sopenharmony_ci << kStableLargeNegativeValue 500cb93a386Sopenharmony_ci << kStableLargeNegativeValue; 501cb93a386Sopenharmony_ci 502cb93a386Sopenharmony_ci verts << posAndUVPoints[5].fPos << color << posAndUVPoints[5].fUV 503cb93a386Sopenharmony_ci << kStableLargeNegativeValue 504cb93a386Sopenharmony_ci << kStableLargeNegativeValue; 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci idxs[*i + 0] = *v + 3; 507cb93a386Sopenharmony_ci idxs[*i + 1] = *v + 1; 508cb93a386Sopenharmony_ci idxs[*i + 2] = *v + 2; 509cb93a386Sopenharmony_ci idxs[*i + 3] = *v + 4; 510cb93a386Sopenharmony_ci idxs[*i + 4] = *v + 3; 511cb93a386Sopenharmony_ci idxs[*i + 5] = *v + 2; 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci idxs[*i + 6] = *v + 5; 514cb93a386Sopenharmony_ci idxs[*i + 7] = *v + 3; 515cb93a386Sopenharmony_ci idxs[*i + 8] = *v + 4; 516cb93a386Sopenharmony_ci 517cb93a386Sopenharmony_ci *i += 9; 518cb93a386Sopenharmony_ci 519cb93a386Sopenharmony_ci // Draw the interior fan if it exists. 520cb93a386Sopenharmony_ci // TODO: Detect and combine colinear segments. This will ensure we catch every case 521cb93a386Sopenharmony_ci // with no interior, and that the resulting shared edge uses the same endpoints. 522cb93a386Sopenharmony_ci if (count >= 3) { 523cb93a386Sopenharmony_ci idxs[*i + 0] = *v + 0; 524cb93a386Sopenharmony_ci idxs[*i + 1] = *v + 2; 525cb93a386Sopenharmony_ci idxs[*i + 2] = *v + 1; 526cb93a386Sopenharmony_ci 527cb93a386Sopenharmony_ci *i += 3; 528cb93a386Sopenharmony_ci } 529cb93a386Sopenharmony_ci 530cb93a386Sopenharmony_ci *v += 6; 531cb93a386Sopenharmony_ci } 532cb93a386Sopenharmony_ci } 533cb93a386Sopenharmony_ci} 534cb93a386Sopenharmony_ci 535cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci/* 538cb93a386Sopenharmony_ci * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 539cb93a386Sopenharmony_ci * two components of the vertex attribute. Coverage is based on signed 540cb93a386Sopenharmony_ci * distance with negative being inside, positive outside. The edge is specified in 541cb93a386Sopenharmony_ci * window space (y-down). If either the third or fourth component of the interpolated 542cb93a386Sopenharmony_ci * vertex coord is > 0 then the pixel is considered outside the edge. This is used to 543cb93a386Sopenharmony_ci * attempt to trim to a portion of the infinite quad. 544cb93a386Sopenharmony_ci * Requires shader derivative instruction support. 545cb93a386Sopenharmony_ci */ 546cb93a386Sopenharmony_ci 547cb93a386Sopenharmony_ciclass QuadEdgeEffect : public GrGeometryProcessor { 548cb93a386Sopenharmony_cipublic: 549cb93a386Sopenharmony_ci static GrGeometryProcessor* Make(SkArenaAlloc* arena, 550cb93a386Sopenharmony_ci const SkMatrix& localMatrix, 551cb93a386Sopenharmony_ci bool usesLocalCoords, 552cb93a386Sopenharmony_ci bool wideColor) { 553cb93a386Sopenharmony_ci return arena->make([&](void* ptr) { 554cb93a386Sopenharmony_ci return new (ptr) QuadEdgeEffect(localMatrix, usesLocalCoords, wideColor); 555cb93a386Sopenharmony_ci }); 556cb93a386Sopenharmony_ci } 557cb93a386Sopenharmony_ci 558cb93a386Sopenharmony_ci ~QuadEdgeEffect() override {} 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci const char* name() const override { return "QuadEdge"; } 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci SkString getShaderDfxInfo() const override { 563cb93a386Sopenharmony_ci SkString format; 564cb93a386Sopenharmony_ci format.printf("ShaderDfx_QuadEdgeEffect_%d_%d_%d_%d", fUsesLocalCoords, 565cb93a386Sopenharmony_ci fLocalMatrix.isIdentity(), fLocalMatrix.isScaleTranslate(), fLocalMatrix.hasPerspective()); 566cb93a386Sopenharmony_ci return format; 567cb93a386Sopenharmony_ci } 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci void addToKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { 570cb93a386Sopenharmony_ci b->addBool(fUsesLocalCoords, "usesLocalCoords"); 571cb93a386Sopenharmony_ci b->addBits(ProgramImpl::kMatrixKeyBits, 572cb93a386Sopenharmony_ci ProgramImpl::ComputeMatrixKey(caps, fLocalMatrix), 573cb93a386Sopenharmony_ci "localMatrixType"); 574cb93a386Sopenharmony_ci } 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ci std::unique_ptr<ProgramImpl> makeProgramImpl(const GrShaderCaps&) const override; 577cb93a386Sopenharmony_ci 578cb93a386Sopenharmony_ciprivate: 579cb93a386Sopenharmony_ci QuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords, bool wideColor) 580cb93a386Sopenharmony_ci : INHERITED(kQuadEdgeEffect_ClassID) 581cb93a386Sopenharmony_ci , fLocalMatrix(localMatrix) 582cb93a386Sopenharmony_ci , fUsesLocalCoords(usesLocalCoords) { 583cb93a386Sopenharmony_ci fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; 584cb93a386Sopenharmony_ci fInColor = MakeColorAttribute("inColor", wideColor); 585cb93a386Sopenharmony_ci // GL on iOS 14 needs more precision for the quadedge attributes 586cb93a386Sopenharmony_ci fInQuadEdge = {"inQuadEdge", kFloat4_GrVertexAttribType, kFloat4_GrSLType}; 587cb93a386Sopenharmony_ci this->setVertexAttributes(&fInPosition, 3); 588cb93a386Sopenharmony_ci } 589cb93a386Sopenharmony_ci 590cb93a386Sopenharmony_ci Attribute fInPosition; 591cb93a386Sopenharmony_ci Attribute fInColor; 592cb93a386Sopenharmony_ci Attribute fInQuadEdge; 593cb93a386Sopenharmony_ci 594cb93a386Sopenharmony_ci SkMatrix fLocalMatrix; 595cb93a386Sopenharmony_ci bool fUsesLocalCoords; 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci GR_DECLARE_GEOMETRY_PROCESSOR_TEST 598cb93a386Sopenharmony_ci 599cb93a386Sopenharmony_ci using INHERITED = GrGeometryProcessor; 600cb93a386Sopenharmony_ci}; 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_cistd::unique_ptr<GrGeometryProcessor::ProgramImpl> QuadEdgeEffect::makeProgramImpl( 603cb93a386Sopenharmony_ci const GrShaderCaps&) const { 604cb93a386Sopenharmony_ci class Impl : public ProgramImpl { 605cb93a386Sopenharmony_ci public: 606cb93a386Sopenharmony_ci void setData(const GrGLSLProgramDataManager& pdman, 607cb93a386Sopenharmony_ci const GrShaderCaps& shaderCaps, 608cb93a386Sopenharmony_ci const GrGeometryProcessor& geomProc) override { 609cb93a386Sopenharmony_ci const QuadEdgeEffect& qe = geomProc.cast<QuadEdgeEffect>(); 610cb93a386Sopenharmony_ci SetTransform(pdman, shaderCaps, fLocalMatrixUniform, qe.fLocalMatrix, &fLocalMatrix); 611cb93a386Sopenharmony_ci } 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_ci private: 614cb93a386Sopenharmony_ci void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { 615cb93a386Sopenharmony_ci const QuadEdgeEffect& qe = args.fGeomProc.cast<QuadEdgeEffect>(); 616cb93a386Sopenharmony_ci GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; 617cb93a386Sopenharmony_ci GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; 618cb93a386Sopenharmony_ci GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; 619cb93a386Sopenharmony_ci GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; 620cb93a386Sopenharmony_ci 621cb93a386Sopenharmony_ci // emit attributes 622cb93a386Sopenharmony_ci varyingHandler->emitAttributes(qe); 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_ci // GL on iOS 14 needs more precision for the quadedge attributes 625cb93a386Sopenharmony_ci // We might as well enable it everywhere 626cb93a386Sopenharmony_ci GrGLSLVarying v(kFloat4_GrSLType); 627cb93a386Sopenharmony_ci varyingHandler->addVarying("QuadEdge", &v); 628cb93a386Sopenharmony_ci vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.fInQuadEdge.name()); 629cb93a386Sopenharmony_ci 630cb93a386Sopenharmony_ci // Setup pass through color 631cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s;", args.fOutputColor); 632cb93a386Sopenharmony_ci varyingHandler->addPassThroughAttribute(qe.fInColor.asShaderVar(), args.fOutputColor); 633cb93a386Sopenharmony_ci 634cb93a386Sopenharmony_ci // Setup position 635cb93a386Sopenharmony_ci WriteOutputPosition(vertBuilder, gpArgs, qe.fInPosition.name()); 636cb93a386Sopenharmony_ci if (qe.fUsesLocalCoords) { 637cb93a386Sopenharmony_ci WriteLocalCoord(vertBuilder, 638cb93a386Sopenharmony_ci uniformHandler, 639cb93a386Sopenharmony_ci *args.fShaderCaps, 640cb93a386Sopenharmony_ci gpArgs, 641cb93a386Sopenharmony_ci qe.fInPosition.asShaderVar(), 642cb93a386Sopenharmony_ci qe.fLocalMatrix, 643cb93a386Sopenharmony_ci &fLocalMatrixUniform); 644cb93a386Sopenharmony_ci } 645cb93a386Sopenharmony_ci 646cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half edgeAlpha;"); 647cb93a386Sopenharmony_ci 648cb93a386Sopenharmony_ci // keep the derivative instructions outside the conditional 649cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn()); 650cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn()); 651cb93a386Sopenharmony_ci fragBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn()); 652cb93a386Sopenharmony_ci // today we know z and w are in device space. We could use derivatives 653cb93a386Sopenharmony_ci fragBuilder->codeAppendf("edgeAlpha = half(min(min(%s.z, %s.w) + 0.5, 1.0));", v.fsIn(), 654cb93a386Sopenharmony_ci v.fsIn()); 655cb93a386Sopenharmony_ci fragBuilder->codeAppendf ("} else {"); 656cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half2 gF = half2(half(2.0*%s.x*duvdx.x - duvdx.y)," 657cb93a386Sopenharmony_ci " half(2.0*%s.x*duvdy.x - duvdy.y));", 658cb93a386Sopenharmony_ci v.fsIn(), v.fsIn()); 659cb93a386Sopenharmony_ci fragBuilder->codeAppendf("edgeAlpha = half(%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(), 660cb93a386Sopenharmony_ci v.fsIn()); 661cb93a386Sopenharmony_ci fragBuilder->codeAppendf("edgeAlpha = " 662cb93a386Sopenharmony_ci "saturate(0.5 - edgeAlpha / length(gF));}"); 663cb93a386Sopenharmony_ci 664cb93a386Sopenharmony_ci fragBuilder->codeAppendf("half4 %s = half4(edgeAlpha);", args.fOutputCoverage); 665cb93a386Sopenharmony_ci } 666cb93a386Sopenharmony_ci 667cb93a386Sopenharmony_ci private: 668cb93a386Sopenharmony_ci SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); 669cb93a386Sopenharmony_ci 670cb93a386Sopenharmony_ci UniformHandle fLocalMatrixUniform; 671cb93a386Sopenharmony_ci }; 672cb93a386Sopenharmony_ci 673cb93a386Sopenharmony_ci return std::make_unique<Impl>(); 674cb93a386Sopenharmony_ci} 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_ciGR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect); 677cb93a386Sopenharmony_ci 678cb93a386Sopenharmony_ci#if GR_TEST_UTILS 679cb93a386Sopenharmony_ciGrGeometryProcessor* QuadEdgeEffect::TestCreate(GrProcessorTestData* d) { 680cb93a386Sopenharmony_ci SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom); 681cb93a386Sopenharmony_ci bool usesLocalCoords = d->fRandom->nextBool(); 682cb93a386Sopenharmony_ci bool wideColor = d->fRandom->nextBool(); 683cb93a386Sopenharmony_ci // Doesn't work without derivative instructions. 684cb93a386Sopenharmony_ci return d->caps()->shaderCaps()->shaderDerivativeSupport() 685cb93a386Sopenharmony_ci ? QuadEdgeEffect::Make(d->allocator(), localMatrix, usesLocalCoords, wideColor) 686cb93a386Sopenharmony_ci : nullptr; 687cb93a386Sopenharmony_ci} 688cb93a386Sopenharmony_ci#endif 689cb93a386Sopenharmony_ci 690cb93a386Sopenharmony_ciclass AAConvexPathOp final : public GrMeshDrawOp { 691cb93a386Sopenharmony_ciprivate: 692cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 693cb93a386Sopenharmony_ci 694cb93a386Sopenharmony_cipublic: 695cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 696cb93a386Sopenharmony_ci 697cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 698cb93a386Sopenharmony_ci GrPaint&& paint, 699cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 700cb93a386Sopenharmony_ci const SkPath& path, 701cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 702cb93a386Sopenharmony_ci return Helper::FactoryHelper<AAConvexPathOp>(context, std::move(paint), viewMatrix, path, 703cb93a386Sopenharmony_ci stencilSettings); 704cb93a386Sopenharmony_ci } 705cb93a386Sopenharmony_ci 706cb93a386Sopenharmony_ci AAConvexPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, 707cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, const SkPath& path, 708cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) 709cb93a386Sopenharmony_ci : INHERITED(ClassID()), fHelper(processorSet, GrAAType::kCoverage, stencilSettings) { 710cb93a386Sopenharmony_ci fPaths.emplace_back(PathData{viewMatrix, path, color}); 711cb93a386Sopenharmony_ci this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes, 712cb93a386Sopenharmony_ci IsHairline::kNo); 713cb93a386Sopenharmony_ci } 714cb93a386Sopenharmony_ci 715cb93a386Sopenharmony_ci const char* name() const override { return "AAConvexPathOp"; } 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 718cb93a386Sopenharmony_ci if (fProgramInfo) { 719cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 720cb93a386Sopenharmony_ci } else { 721cb93a386Sopenharmony_ci fHelper.visitProxies(func); 722cb93a386Sopenharmony_ci } 723cb93a386Sopenharmony_ci } 724cb93a386Sopenharmony_ci 725cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 726cb93a386Sopenharmony_ci 727cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 728cb93a386Sopenharmony_ci GrClampType clampType) override { 729cb93a386Sopenharmony_ci return fHelper.finalizeProcessors( 730cb93a386Sopenharmony_ci caps, clip, clampType, GrProcessorAnalysisCoverage::kSingleChannel, 731cb93a386Sopenharmony_ci &fPaths.back().fColor, &fWideColor); 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci 734cb93a386Sopenharmony_ciprivate: 735cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return fProgramInfo; } 736cb93a386Sopenharmony_ci 737cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 738cb93a386Sopenharmony_ci SkArenaAlloc* arena, 739cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 740cb93a386Sopenharmony_ci bool usesMSAASurface, 741cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 742cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 743cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 744cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 745cb93a386Sopenharmony_ci SkMatrix invert; 746cb93a386Sopenharmony_ci if (fHelper.usesLocalCoords() && !fPaths.back().fViewMatrix.invert(&invert)) { 747cb93a386Sopenharmony_ci return; 748cb93a386Sopenharmony_ci } 749cb93a386Sopenharmony_ci 750cb93a386Sopenharmony_ci GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Make(arena, invert, 751cb93a386Sopenharmony_ci fHelper.usesLocalCoords(), 752cb93a386Sopenharmony_ci fWideColor); 753cb93a386Sopenharmony_ci 754cb93a386Sopenharmony_ci fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface, 755cb93a386Sopenharmony_ci std::move(appliedClip), 756cb93a386Sopenharmony_ci dstProxyView, quadProcessor, 757cb93a386Sopenharmony_ci GrPrimitiveType::kTriangles, 758cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 759cb93a386Sopenharmony_ci } 760cb93a386Sopenharmony_ci 761cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 762cb93a386Sopenharmony_ci int instanceCount = fPaths.count(); 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_ci if (!fProgramInfo) { 765cb93a386Sopenharmony_ci this->createProgramInfo(target); 766cb93a386Sopenharmony_ci if (!fProgramInfo) { 767cb93a386Sopenharmony_ci return; 768cb93a386Sopenharmony_ci } 769cb93a386Sopenharmony_ci } 770cb93a386Sopenharmony_ci 771cb93a386Sopenharmony_ci const size_t kVertexStride = fProgramInfo->geomProc().vertexStride(); 772cb93a386Sopenharmony_ci 773cb93a386Sopenharmony_ci fDraws.reserve(instanceCount); 774cb93a386Sopenharmony_ci 775cb93a386Sopenharmony_ci // TODO generate all segments for all paths and use one vertex buffer 776cb93a386Sopenharmony_ci for (int i = 0; i < instanceCount; i++) { 777cb93a386Sopenharmony_ci const PathData& args = fPaths[i]; 778cb93a386Sopenharmony_ci 779cb93a386Sopenharmony_ci // We use the fact that SkPath::transform path does subdivision based on 780cb93a386Sopenharmony_ci // perspective. Otherwise, we apply the view matrix when copying to the 781cb93a386Sopenharmony_ci // segment representation. 782cb93a386Sopenharmony_ci const SkMatrix* viewMatrix = &args.fViewMatrix; 783cb93a386Sopenharmony_ci 784cb93a386Sopenharmony_ci // We avoid initializing the path unless we have to 785cb93a386Sopenharmony_ci const SkPath* pathPtr = &args.fPath; 786cb93a386Sopenharmony_ci SkTLazy<SkPath> tmpPath; 787cb93a386Sopenharmony_ci if (viewMatrix->hasPerspective()) { 788cb93a386Sopenharmony_ci SkPath* tmpPathPtr = tmpPath.init(*pathPtr); 789cb93a386Sopenharmony_ci tmpPathPtr->setIsVolatile(true); 790cb93a386Sopenharmony_ci tmpPathPtr->transform(*viewMatrix); 791cb93a386Sopenharmony_ci viewMatrix = &SkMatrix::I(); 792cb93a386Sopenharmony_ci pathPtr = tmpPathPtr; 793cb93a386Sopenharmony_ci } 794cb93a386Sopenharmony_ci 795cb93a386Sopenharmony_ci int vertexCount; 796cb93a386Sopenharmony_ci int indexCount; 797cb93a386Sopenharmony_ci enum { 798cb93a386Sopenharmony_ci kPreallocSegmentCnt = 512 / sizeof(Segment), 799cb93a386Sopenharmony_ci kPreallocDrawCnt = 4, 800cb93a386Sopenharmony_ci }; 801cb93a386Sopenharmony_ci SkSTArray<kPreallocSegmentCnt, Segment, true> segments; 802cb93a386Sopenharmony_ci SkPoint fanPt; 803cb93a386Sopenharmony_ci 804cb93a386Sopenharmony_ci if (!get_segments(*pathPtr, *viewMatrix, &segments, &fanPt, &vertexCount, 805cb93a386Sopenharmony_ci &indexCount)) { 806cb93a386Sopenharmony_ci continue; 807cb93a386Sopenharmony_ci } 808cb93a386Sopenharmony_ci 809cb93a386Sopenharmony_ci sk_sp<const GrBuffer> vertexBuffer; 810cb93a386Sopenharmony_ci int firstVertex; 811cb93a386Sopenharmony_ci 812cb93a386Sopenharmony_ci VertexWriter verts{target->makeVertexSpace(kVertexStride, 813cb93a386Sopenharmony_ci vertexCount, 814cb93a386Sopenharmony_ci &vertexBuffer, 815cb93a386Sopenharmony_ci &firstVertex)}; 816cb93a386Sopenharmony_ci 817cb93a386Sopenharmony_ci if (!verts) { 818cb93a386Sopenharmony_ci SkDebugf("Could not allocate vertices\n"); 819cb93a386Sopenharmony_ci return; 820cb93a386Sopenharmony_ci } 821cb93a386Sopenharmony_ci 822cb93a386Sopenharmony_ci sk_sp<const GrBuffer> indexBuffer; 823cb93a386Sopenharmony_ci int firstIndex; 824cb93a386Sopenharmony_ci 825cb93a386Sopenharmony_ci uint16_t *idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex); 826cb93a386Sopenharmony_ci if (!idxs) { 827cb93a386Sopenharmony_ci SkDebugf("Could not allocate indices\n"); 828cb93a386Sopenharmony_ci return; 829cb93a386Sopenharmony_ci } 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci SkSTArray<kPreallocDrawCnt, Draw, true> draws; 832cb93a386Sopenharmony_ci GrVertexColor color(args.fColor, fWideColor); 833cb93a386Sopenharmony_ci create_vertices(segments, fanPt, color, &draws, verts, idxs, kVertexStride); 834cb93a386Sopenharmony_ci 835cb93a386Sopenharmony_ci GrSimpleMesh* meshes = target->allocMeshes(draws.count()); 836cb93a386Sopenharmony_ci for (int j = 0; j < draws.count(); ++j) { 837cb93a386Sopenharmony_ci const Draw& draw = draws[j]; 838cb93a386Sopenharmony_ci meshes[j].setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0, 839cb93a386Sopenharmony_ci draw.fVertexCnt - 1, GrPrimitiveRestart::kNo, vertexBuffer, 840cb93a386Sopenharmony_ci firstVertex); 841cb93a386Sopenharmony_ci firstIndex += draw.fIndexCnt; 842cb93a386Sopenharmony_ci firstVertex += draw.fVertexCnt; 843cb93a386Sopenharmony_ci } 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_ci fDraws.push_back({ meshes, draws.count() }); 846cb93a386Sopenharmony_ci } 847cb93a386Sopenharmony_ci } 848cb93a386Sopenharmony_ci 849cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 850cb93a386Sopenharmony_ci if (!fProgramInfo || fDraws.isEmpty()) { 851cb93a386Sopenharmony_ci return; 852cb93a386Sopenharmony_ci } 853cb93a386Sopenharmony_ci 854cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 855cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 856cb93a386Sopenharmony_ci for (int i = 0; i < fDraws.count(); ++i) { 857cb93a386Sopenharmony_ci for (int j = 0; j < fDraws[i].fMeshCount; ++j) { 858cb93a386Sopenharmony_ci flushState->drawMesh(fDraws[i].fMeshes[j]); 859cb93a386Sopenharmony_ci } 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci } 862cb93a386Sopenharmony_ci 863cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 864cb93a386Sopenharmony_ci AAConvexPathOp* that = t->cast<AAConvexPathOp>(); 865cb93a386Sopenharmony_ci if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 866cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 867cb93a386Sopenharmony_ci } 868cb93a386Sopenharmony_ci if (fHelper.usesLocalCoords() && 869cb93a386Sopenharmony_ci !SkMatrixPriv::CheapEqual(fPaths[0].fViewMatrix, that->fPaths[0].fViewMatrix)) { 870cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 871cb93a386Sopenharmony_ci } 872cb93a386Sopenharmony_ci 873cb93a386Sopenharmony_ci fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); 874cb93a386Sopenharmony_ci fWideColor |= that->fWideColor; 875cb93a386Sopenharmony_ci return CombineResult::kMerged; 876cb93a386Sopenharmony_ci } 877cb93a386Sopenharmony_ci 878cb93a386Sopenharmony_ci#if GR_TEST_UTILS 879cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 880cb93a386Sopenharmony_ci return SkStringPrintf("Count: %d\n%s", fPaths.count(), fHelper.dumpInfo().c_str()); 881cb93a386Sopenharmony_ci } 882cb93a386Sopenharmony_ci#endif 883cb93a386Sopenharmony_ci 884cb93a386Sopenharmony_ci struct PathData { 885cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 886cb93a386Sopenharmony_ci SkPath fPath; 887cb93a386Sopenharmony_ci SkPMColor4f fColor; 888cb93a386Sopenharmony_ci }; 889cb93a386Sopenharmony_ci 890cb93a386Sopenharmony_ci Helper fHelper; 891cb93a386Sopenharmony_ci SkSTArray<1, PathData, true> fPaths; 892cb93a386Sopenharmony_ci bool fWideColor; 893cb93a386Sopenharmony_ci 894cb93a386Sopenharmony_ci struct MeshDraw { 895cb93a386Sopenharmony_ci GrSimpleMesh* fMeshes; 896cb93a386Sopenharmony_ci int fMeshCount; 897cb93a386Sopenharmony_ci }; 898cb93a386Sopenharmony_ci 899cb93a386Sopenharmony_ci SkTDArray<MeshDraw> fDraws; 900cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 901cb93a386Sopenharmony_ci 902cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 903cb93a386Sopenharmony_ci}; 904cb93a386Sopenharmony_ci 905cb93a386Sopenharmony_ci} // anonymous namespace 906cb93a386Sopenharmony_ci 907cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 908cb93a386Sopenharmony_ci 909cb93a386Sopenharmony_ciPathRenderer::CanDrawPath AAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 910cb93a386Sopenharmony_ci // This check requires convexity and known direction, since the direction is used to build 911cb93a386Sopenharmony_ci // the geometry segments. Degenerate convex paths will fall through to some other path renderer. 912cb93a386Sopenharmony_ci if (args.fCaps->shaderCaps()->shaderDerivativeSupport() && 913cb93a386Sopenharmony_ci (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() && 914cb93a386Sopenharmony_ci !args.fShape->inverseFilled() && args.fShape->knownToBeConvex() && 915cb93a386Sopenharmony_ci args.fShape->knownDirection()) { 916cb93a386Sopenharmony_ci return CanDrawPath::kYes; 917cb93a386Sopenharmony_ci } 918cb93a386Sopenharmony_ci return CanDrawPath::kNo; 919cb93a386Sopenharmony_ci} 920cb93a386Sopenharmony_ci 921cb93a386Sopenharmony_cibool AAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { 922cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 923cb93a386Sopenharmony_ci "AAConvexPathRenderer::onDrawPath"); 924cb93a386Sopenharmony_ci SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1); 925cb93a386Sopenharmony_ci SkASSERT(!args.fShape->isEmpty()); 926cb93a386Sopenharmony_ci 927cb93a386Sopenharmony_ci SkPath path; 928cb93a386Sopenharmony_ci args.fShape->asPath(&path); 929cb93a386Sopenharmony_ci 930cb93a386Sopenharmony_ci GrOp::Owner op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint), 931cb93a386Sopenharmony_ci *args.fViewMatrix, 932cb93a386Sopenharmony_ci path, args.fUserStencilSettings); 933cb93a386Sopenharmony_ci args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op)); 934cb93a386Sopenharmony_ci return true; 935cb93a386Sopenharmony_ci} 936cb93a386Sopenharmony_ci 937cb93a386Sopenharmony_ci} // namespace skgpu::v1 938cb93a386Sopenharmony_ci 939cb93a386Sopenharmony_ci#if GR_TEST_UTILS 940cb93a386Sopenharmony_ci 941cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(AAConvexPathOp) { 942cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); 943cb93a386Sopenharmony_ci const SkPath& path = GrTest::TestPathConvex(random); 944cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context); 945cb93a386Sopenharmony_ci return skgpu::v1::AAConvexPathOp::Make(context, std::move(paint), viewMatrix, path, 946cb93a386Sopenharmony_ci stencilSettings); 947cb93a386Sopenharmony_ci} 948cb93a386Sopenharmony_ci 949cb93a386Sopenharmony_ci#endif 950