1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 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/DefaultPathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkString.h" 11cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h" 12cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 13cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h" 14cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h" 15cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrSimpleMesh.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 25cb93a386Sopenharmony_ci#include "src/gpu/GrUtil.h" 26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDisableColorXP.h" 27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h" 28cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 29cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 30cb93a386Sopenharmony_ci#include "src/gpu/ops/GrPathStencilSettings.h" 31cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 32cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_ci//////////////////////////////////////////////////////////////////////////////// 35cb93a386Sopenharmony_ci// Helpers for drawPath 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cinamespace { 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci#define STENCIL_OFF 0 // Always disable stencil (even when needed) 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ciinline bool single_pass_shape(const GrStyledShape& shape) { 42cb93a386Sopenharmony_ci#if STENCIL_OFF 43cb93a386Sopenharmony_ci return true; 44cb93a386Sopenharmony_ci#else 45cb93a386Sopenharmony_ci // Inverse fill is always two pass. 46cb93a386Sopenharmony_ci if (shape.inverseFilled()) { 47cb93a386Sopenharmony_ci return false; 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci // This path renderer only accepts simple fill paths or stroke paths that are either hairline 50cb93a386Sopenharmony_ci // or have a stroke width small enough to treat as hairline. Hairline paths are always single 51cb93a386Sopenharmony_ci // pass. Filled paths are single pass if they're convex. 52cb93a386Sopenharmony_ci if (shape.style().isSimpleFill()) { 53cb93a386Sopenharmony_ci return shape.knownToBeConvex(); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci return true; 56cb93a386Sopenharmony_ci#endif 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ciclass PathGeoBuilder { 60cb93a386Sopenharmony_cipublic: 61cb93a386Sopenharmony_ci PathGeoBuilder(GrPrimitiveType primitiveType, 62cb93a386Sopenharmony_ci GrMeshDrawTarget* target, 63cb93a386Sopenharmony_ci SkTDArray<GrSimpleMesh*>* meshes) 64cb93a386Sopenharmony_ci : fPrimitiveType(primitiveType) 65cb93a386Sopenharmony_ci , fTarget(target) 66cb93a386Sopenharmony_ci , fVertexStride(sizeof(SkPoint)) 67cb93a386Sopenharmony_ci , fFirstIndex(0) 68cb93a386Sopenharmony_ci , fIndicesInChunk(0) 69cb93a386Sopenharmony_ci , fIndices(nullptr) 70cb93a386Sopenharmony_ci , fMeshes(meshes) { 71cb93a386Sopenharmony_ci this->allocNewBuffers(); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_ci ~PathGeoBuilder() { 75cb93a386Sopenharmony_ci this->createMeshAndPutBackReserve(); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci /** 79cb93a386Sopenharmony_ci * Path verbs 80cb93a386Sopenharmony_ci */ 81cb93a386Sopenharmony_ci void moveTo(const SkPoint& p) { 82cb93a386Sopenharmony_ci if (!this->ensureSpace(1)) { 83cb93a386Sopenharmony_ci return; 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci if (!this->isHairline()) { 87cb93a386Sopenharmony_ci fSubpathIndexStart = this->currentIndex(); 88cb93a386Sopenharmony_ci fSubpathStartPoint = p; 89cb93a386Sopenharmony_ci } 90cb93a386Sopenharmony_ci *(fCurVert++) = p; 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci void addLine(const SkPoint pts[]) { 94cb93a386Sopenharmony_ci if (!this->ensureSpace(1, this->indexScale(), &pts[0])) { 95cb93a386Sopenharmony_ci return; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci if (this->isIndexed()) { 99cb93a386Sopenharmony_ci uint16_t prevIdx = this->currentIndex() - 1; 100cb93a386Sopenharmony_ci this->appendCountourEdgeIndices(prevIdx); 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci *(fCurVert++) = pts[1]; 103cb93a386Sopenharmony_ci } 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) { 106cb93a386Sopenharmony_ci if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve, 107cb93a386Sopenharmony_ci GrPathUtils::kMaxPointsPerCurve * this->indexScale(), 108cb93a386Sopenharmony_ci &pts[0])) { 109cb93a386Sopenharmony_ci return; 110cb93a386Sopenharmony_ci } 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci // First pt of quad is the pt we ended on in previous step 113cb93a386Sopenharmony_ci uint16_t firstQPtIdx = this->currentIndex() - 1; 114cb93a386Sopenharmony_ci uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints( 115cb93a386Sopenharmony_ci pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert, 116cb93a386Sopenharmony_ci GrPathUtils::quadraticPointCount(pts, srcSpaceTol)); 117cb93a386Sopenharmony_ci if (this->isIndexed()) { 118cb93a386Sopenharmony_ci for (uint16_t i = 0; i < numPts; ++i) { 119cb93a386Sopenharmony_ci this->appendCountourEdgeIndices(firstQPtIdx + i); 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci 124cb93a386Sopenharmony_ci void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd, 125cb93a386Sopenharmony_ci SkScalar srcSpaceTol) { 126cb93a386Sopenharmony_ci SkAutoConicToQuads converter; 127cb93a386Sopenharmony_ci const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol); 128cb93a386Sopenharmony_ci for (int i = 0; i < converter.countQuads(); ++i) { 129cb93a386Sopenharmony_ci this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol); 130cb93a386Sopenharmony_ci } 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) { 134cb93a386Sopenharmony_ci if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve, 135cb93a386Sopenharmony_ci GrPathUtils::kMaxPointsPerCurve * this->indexScale(), 136cb93a386Sopenharmony_ci &pts[0])) { 137cb93a386Sopenharmony_ci return; 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci 140cb93a386Sopenharmony_ci // First pt of cubic is the pt we ended on in previous step 141cb93a386Sopenharmony_ci uint16_t firstCPtIdx = this->currentIndex() - 1; 142cb93a386Sopenharmony_ci uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints( 143cb93a386Sopenharmony_ci pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert, 144cb93a386Sopenharmony_ci GrPathUtils::cubicPointCount(pts, srcSpaceTol)); 145cb93a386Sopenharmony_ci if (this->isIndexed()) { 146cb93a386Sopenharmony_ci for (uint16_t i = 0; i < numPts; ++i) { 147cb93a386Sopenharmony_ci this->appendCountourEdgeIndices(firstCPtIdx + i); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ci void addPath(const SkPath& path, SkScalar srcSpaceTol) { 153cb93a386Sopenharmony_ci SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol; 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci SkPath::Iter iter(path, false); 156cb93a386Sopenharmony_ci SkPoint pts[4]; 157cb93a386Sopenharmony_ci 158cb93a386Sopenharmony_ci bool done = false; 159cb93a386Sopenharmony_ci while (!done) { 160cb93a386Sopenharmony_ci SkPath::Verb verb = iter.next(pts); 161cb93a386Sopenharmony_ci switch (verb) { 162cb93a386Sopenharmony_ci case SkPath::kMove_Verb: 163cb93a386Sopenharmony_ci this->moveTo(pts[0]); 164cb93a386Sopenharmony_ci break; 165cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 166cb93a386Sopenharmony_ci this->addLine(pts); 167cb93a386Sopenharmony_ci break; 168cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 169cb93a386Sopenharmony_ci this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol); 170cb93a386Sopenharmony_ci break; 171cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 172cb93a386Sopenharmony_ci this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol); 173cb93a386Sopenharmony_ci break; 174cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 175cb93a386Sopenharmony_ci this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol); 176cb93a386Sopenharmony_ci break; 177cb93a386Sopenharmony_ci case SkPath::kClose_Verb: 178cb93a386Sopenharmony_ci break; 179cb93a386Sopenharmony_ci case SkPath::kDone_Verb: 180cb93a386Sopenharmony_ci done = true; 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci } 183cb93a386Sopenharmony_ci } 184cb93a386Sopenharmony_ci 185cb93a386Sopenharmony_ci static bool PathHasMultipleSubpaths(const SkPath& path) { 186cb93a386Sopenharmony_ci bool first = true; 187cb93a386Sopenharmony_ci 188cb93a386Sopenharmony_ci SkPath::Iter iter(path, false); 189cb93a386Sopenharmony_ci SkPath::Verb verb; 190cb93a386Sopenharmony_ci 191cb93a386Sopenharmony_ci SkPoint pts[4]; 192cb93a386Sopenharmony_ci while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 193cb93a386Sopenharmony_ci if (SkPath::kMove_Verb == verb && !first) { 194cb93a386Sopenharmony_ci return true; 195cb93a386Sopenharmony_ci } 196cb93a386Sopenharmony_ci first = false; 197cb93a386Sopenharmony_ci } 198cb93a386Sopenharmony_ci return false; 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ciprivate: 202cb93a386Sopenharmony_ci /** 203cb93a386Sopenharmony_ci * Derived properties 204cb93a386Sopenharmony_ci * TODO: Cache some of these for better performance, rather than re-computing? 205cb93a386Sopenharmony_ci */ 206cb93a386Sopenharmony_ci bool isIndexed() const { 207cb93a386Sopenharmony_ci return GrPrimitiveType::kLines == fPrimitiveType || 208cb93a386Sopenharmony_ci GrPrimitiveType::kTriangles == fPrimitiveType; 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci bool isHairline() const { 211cb93a386Sopenharmony_ci return GrPrimitiveType::kLines == fPrimitiveType || 212cb93a386Sopenharmony_ci GrPrimitiveType::kLineStrip == fPrimitiveType; 213cb93a386Sopenharmony_ci } 214cb93a386Sopenharmony_ci int indexScale() const { 215cb93a386Sopenharmony_ci switch (fPrimitiveType) { 216cb93a386Sopenharmony_ci case GrPrimitiveType::kLines: 217cb93a386Sopenharmony_ci return 2; 218cb93a386Sopenharmony_ci case GrPrimitiveType::kTriangles: 219cb93a386Sopenharmony_ci return 3; 220cb93a386Sopenharmony_ci default: 221cb93a386Sopenharmony_ci return 0; 222cb93a386Sopenharmony_ci } 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ci uint16_t currentIndex() const { return fCurVert - fVertices; } 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci // Allocate vertex and (possibly) index buffers 228cb93a386Sopenharmony_ci void allocNewBuffers() { 229cb93a386Sopenharmony_ci SkASSERT(fValid); 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_ci // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points 232cb93a386Sopenharmony_ci // from previous mesh piece (up to two verts to continue fanning). If we can't get that 233cb93a386Sopenharmony_ci // many, ask for a much larger number. This needs to be fairly big to handle quads/cubics, 234cb93a386Sopenharmony_ci // which have a worst-case of 1k points. 235cb93a386Sopenharmony_ci static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2; 236cb93a386Sopenharmony_ci static const int kFallbackVerticesPerChunk = 16384; 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride, 239cb93a386Sopenharmony_ci kMinVerticesPerChunk, 240cb93a386Sopenharmony_ci kFallbackVerticesPerChunk, 241cb93a386Sopenharmony_ci &fVertexBuffer, 242cb93a386Sopenharmony_ci &fFirstVertex, 243cb93a386Sopenharmony_ci &fVerticesInChunk)); 244cb93a386Sopenharmony_ci if (!fVertices) { 245cb93a386Sopenharmony_ci SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n"); 246cb93a386Sopenharmony_ci fCurVert = nullptr; 247cb93a386Sopenharmony_ci fCurIdx = fIndices = nullptr; 248cb93a386Sopenharmony_ci fSubpathIndexStart = 0; 249cb93a386Sopenharmony_ci fValid = false; 250cb93a386Sopenharmony_ci return; 251cb93a386Sopenharmony_ci } 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci if (this->isIndexed()) { 254cb93a386Sopenharmony_ci // Similar to above: Ensure we get enough indices for one worst-case quad/cubic. 255cb93a386Sopenharmony_ci // No extra indices are needed for stitching, though. If we can't get that many, ask 256cb93a386Sopenharmony_ci // for enough to match our large vertex request. 257cb93a386Sopenharmony_ci const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale(); 258cb93a386Sopenharmony_ci const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale(); 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk, 261cb93a386Sopenharmony_ci &fIndexBuffer, &fFirstIndex, 262cb93a386Sopenharmony_ci &fIndicesInChunk); 263cb93a386Sopenharmony_ci if (!fIndices) { 264cb93a386Sopenharmony_ci SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n"); 265cb93a386Sopenharmony_ci fVertices = nullptr; 266cb93a386Sopenharmony_ci fValid = false; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci 270cb93a386Sopenharmony_ci fCurVert = fVertices; 271cb93a386Sopenharmony_ci fCurIdx = fIndices; 272cb93a386Sopenharmony_ci fSubpathIndexStart = 0; 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci void appendCountourEdgeIndices(uint16_t edgeV0Idx) { 276cb93a386Sopenharmony_ci SkASSERT(fCurIdx); 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci // When drawing lines we're appending line segments along the countour. When applying the 279cb93a386Sopenharmony_ci // other fill rules we're drawing triangle fans around the start of the current (sub)path. 280cb93a386Sopenharmony_ci if (!this->isHairline()) { 281cb93a386Sopenharmony_ci *(fCurIdx++) = fSubpathIndexStart; 282cb93a386Sopenharmony_ci } 283cb93a386Sopenharmony_ci *(fCurIdx++) = edgeV0Idx; 284cb93a386Sopenharmony_ci *(fCurIdx++) = edgeV0Idx + 1; 285cb93a386Sopenharmony_ci } 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci // Emits a single draw with all accumulated vertex/index data 288cb93a386Sopenharmony_ci void createMeshAndPutBackReserve() { 289cb93a386Sopenharmony_ci if (!fValid) { 290cb93a386Sopenharmony_ci return; 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci 293cb93a386Sopenharmony_ci int vertexCount = fCurVert - fVertices; 294cb93a386Sopenharmony_ci int indexCount = fCurIdx - fIndices; 295cb93a386Sopenharmony_ci SkASSERT(vertexCount <= fVerticesInChunk); 296cb93a386Sopenharmony_ci SkASSERT(indexCount <= fIndicesInChunk); 297cb93a386Sopenharmony_ci 298cb93a386Sopenharmony_ci GrSimpleMesh* mesh = nullptr; 299cb93a386Sopenharmony_ci if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) { 300cb93a386Sopenharmony_ci mesh = fTarget->allocMesh(); 301cb93a386Sopenharmony_ci if (!this->isIndexed()) { 302cb93a386Sopenharmony_ci mesh->set(std::move(fVertexBuffer), vertexCount, fFirstVertex); 303cb93a386Sopenharmony_ci } else { 304cb93a386Sopenharmony_ci mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0, 305cb93a386Sopenharmony_ci vertexCount - 1, GrPrimitiveRestart::kNo, std::move(fVertexBuffer), 306cb93a386Sopenharmony_ci fFirstVertex); 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci } 309cb93a386Sopenharmony_ci 310cb93a386Sopenharmony_ci fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount)); 311cb93a386Sopenharmony_ci fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride); 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci if (mesh) { 314cb93a386Sopenharmony_ci fMeshes->push_back(mesh); 315cb93a386Sopenharmony_ci } 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci bool ensureSpace(int vertsNeeded, int indicesNeeded = 0, const SkPoint* lastPoint = nullptr) { 319cb93a386Sopenharmony_ci if (!fValid) { 320cb93a386Sopenharmony_ci return false; 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci 323cb93a386Sopenharmony_ci if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk || 324cb93a386Sopenharmony_ci fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) { 325cb93a386Sopenharmony_ci // We are about to run out of space (possibly) 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci#ifdef SK_DEBUG 328cb93a386Sopenharmony_ci // To maintain continuity, we need to remember one or two points from the current mesh. 329cb93a386Sopenharmony_ci // Lines only need the last point, fills need the first point from the current contour. 330cb93a386Sopenharmony_ci // We always grab both here, and append the ones we need at the end of this process. 331cb93a386Sopenharmony_ci SkASSERT(fSubpathIndexStart < fVerticesInChunk); 332cb93a386Sopenharmony_ci // This assert is reading from the gpu buffer fVertices and will be slow, but for debug 333cb93a386Sopenharmony_ci // that is okay. 334cb93a386Sopenharmony_ci if (!this->isHairline()) { 335cb93a386Sopenharmony_ci SkASSERT(fSubpathStartPoint == fVertices[fSubpathIndexStart]); 336cb93a386Sopenharmony_ci } 337cb93a386Sopenharmony_ci if (lastPoint) { 338cb93a386Sopenharmony_ci SkASSERT(*(fCurVert - 1) == *lastPoint); 339cb93a386Sopenharmony_ci } 340cb93a386Sopenharmony_ci#endif 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci // Draw the mesh we've accumulated, and put back any unused space 343cb93a386Sopenharmony_ci this->createMeshAndPutBackReserve(); 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci // Get new buffers 346cb93a386Sopenharmony_ci this->allocNewBuffers(); 347cb93a386Sopenharmony_ci if (!fValid) { 348cb93a386Sopenharmony_ci return false; 349cb93a386Sopenharmony_ci } 350cb93a386Sopenharmony_ci 351cb93a386Sopenharmony_ci // On moves we don't need to copy over any points to the new buffer and we pass in a 352cb93a386Sopenharmony_ci // null lastPoint. 353cb93a386Sopenharmony_ci if (lastPoint) { 354cb93a386Sopenharmony_ci // Append copies of the points we saved so the two meshes will weld properly 355cb93a386Sopenharmony_ci if (!this->isHairline()) { 356cb93a386Sopenharmony_ci *(fCurVert++) = fSubpathStartPoint; 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci *(fCurVert++) = *lastPoint; 359cb93a386Sopenharmony_ci } 360cb93a386Sopenharmony_ci } 361cb93a386Sopenharmony_ci 362cb93a386Sopenharmony_ci return true; 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci GrPrimitiveType fPrimitiveType; 366cb93a386Sopenharmony_ci GrMeshDrawTarget* fTarget; 367cb93a386Sopenharmony_ci size_t fVertexStride; 368cb93a386Sopenharmony_ci 369cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fVertexBuffer; 370cb93a386Sopenharmony_ci int fFirstVertex; 371cb93a386Sopenharmony_ci int fVerticesInChunk; 372cb93a386Sopenharmony_ci SkPoint* fVertices; 373cb93a386Sopenharmony_ci SkPoint* fCurVert; 374cb93a386Sopenharmony_ci 375cb93a386Sopenharmony_ci sk_sp<const GrBuffer> fIndexBuffer; 376cb93a386Sopenharmony_ci int fFirstIndex; 377cb93a386Sopenharmony_ci int fIndicesInChunk; 378cb93a386Sopenharmony_ci uint16_t* fIndices; 379cb93a386Sopenharmony_ci uint16_t* fCurIdx; 380cb93a386Sopenharmony_ci uint16_t fSubpathIndexStart; 381cb93a386Sopenharmony_ci SkPoint fSubpathStartPoint; 382cb93a386Sopenharmony_ci 383cb93a386Sopenharmony_ci bool fValid = true; 384cb93a386Sopenharmony_ci SkTDArray<GrSimpleMesh*>* fMeshes; 385cb93a386Sopenharmony_ci}; 386cb93a386Sopenharmony_ci 387cb93a386Sopenharmony_ciclass DefaultPathOp final : public GrMeshDrawOp { 388cb93a386Sopenharmony_ciprivate: 389cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 390cb93a386Sopenharmony_ci 391cb93a386Sopenharmony_cipublic: 392cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 393cb93a386Sopenharmony_ci 394cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 395cb93a386Sopenharmony_ci GrPaint&& paint, 396cb93a386Sopenharmony_ci const SkPath& path, 397cb93a386Sopenharmony_ci SkScalar tolerance, 398cb93a386Sopenharmony_ci uint8_t coverage, 399cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 400cb93a386Sopenharmony_ci bool isHairline, 401cb93a386Sopenharmony_ci GrAAType aaType, 402cb93a386Sopenharmony_ci const SkRect& devBounds, 403cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 404cb93a386Sopenharmony_ci return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance, 405cb93a386Sopenharmony_ci coverage, viewMatrix, isHairline, aaType, 406cb93a386Sopenharmony_ci devBounds, stencilSettings); 407cb93a386Sopenharmony_ci } 408cb93a386Sopenharmony_ci 409cb93a386Sopenharmony_ci const char* name() const override { return "DefaultPathOp"; } 410cb93a386Sopenharmony_ci 411cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 412cb93a386Sopenharmony_ci if (fProgramInfo) { 413cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 414cb93a386Sopenharmony_ci } else { 415cb93a386Sopenharmony_ci fHelper.visitProxies(func); 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci } 418cb93a386Sopenharmony_ci 419cb93a386Sopenharmony_ci DefaultPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkPath& path, 420cb93a386Sopenharmony_ci SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline, 421cb93a386Sopenharmony_ci GrAAType aaType, const SkRect& devBounds, 422cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) 423cb93a386Sopenharmony_ci : INHERITED(ClassID()) 424cb93a386Sopenharmony_ci , fHelper(processorSet, aaType, stencilSettings) 425cb93a386Sopenharmony_ci , fColor(color) 426cb93a386Sopenharmony_ci , fCoverage(coverage) 427cb93a386Sopenharmony_ci , fViewMatrix(viewMatrix) 428cb93a386Sopenharmony_ci , fIsHairline(isHairline) { 429cb93a386Sopenharmony_ci fPaths.emplace_back(PathData{path, tolerance}); 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes; 432cb93a386Sopenharmony_ci this->setBounds(devBounds, aaBloat, 433cb93a386Sopenharmony_ci isHairline ? IsHairline::kYes : IsHairline::kNo); 434cb93a386Sopenharmony_ci } 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 437cb93a386Sopenharmony_ci 438cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 439cb93a386Sopenharmony_ci GrClampType clampType) override { 440cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage gpCoverage = 441cb93a386Sopenharmony_ci this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone 442cb93a386Sopenharmony_ci : GrProcessorAnalysisCoverage::kSingleChannel; 443cb93a386Sopenharmony_ci // This Op uses uniform (not vertex) color, so doesn't need to track wide color. 444cb93a386Sopenharmony_ci return fHelper.finalizeProcessors(caps, clip, clampType, gpCoverage, &fColor, nullptr); 445cb93a386Sopenharmony_ci } 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ciprivate: 448cb93a386Sopenharmony_ci GrPrimitiveType primType() const { 449cb93a386Sopenharmony_ci if (this->isHairline()) { 450cb93a386Sopenharmony_ci int instanceCount = fPaths.count(); 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ci // We avoid indices when we have a single hairline contour. 453cb93a386Sopenharmony_ci bool isIndexed = instanceCount > 1 || 454cb93a386Sopenharmony_ci PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath); 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip; 457cb93a386Sopenharmony_ci } 458cb93a386Sopenharmony_ci 459cb93a386Sopenharmony_ci return GrPrimitiveType::kTriangles; 460cb93a386Sopenharmony_ci } 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return fProgramInfo; } 463cb93a386Sopenharmony_ci 464cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 465cb93a386Sopenharmony_ci SkArenaAlloc* arena, 466cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 467cb93a386Sopenharmony_ci bool usesMSAASurface, 468cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 469cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 470cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 471cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 472cb93a386Sopenharmony_ci GrGeometryProcessor* gp; 473cb93a386Sopenharmony_ci { 474cb93a386Sopenharmony_ci using namespace GrDefaultGeoProcFactory; 475cb93a386Sopenharmony_ci Color color(this->color()); 476cb93a386Sopenharmony_ci Coverage coverage(this->coverage()); 477cb93a386Sopenharmony_ci LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type 478cb93a386Sopenharmony_ci : LocalCoords::kUnused_Type); 479cb93a386Sopenharmony_ci gp = GrDefaultGeoProcFactory::Make(arena, 480cb93a386Sopenharmony_ci color, 481cb93a386Sopenharmony_ci coverage, 482cb93a386Sopenharmony_ci localCoords, 483cb93a386Sopenharmony_ci this->viewMatrix()); 484cb93a386Sopenharmony_ci } 485cb93a386Sopenharmony_ci 486cb93a386Sopenharmony_ci SkASSERT(gp->vertexStride() == sizeof(SkPoint)); 487cb93a386Sopenharmony_ci 488cb93a386Sopenharmony_ci fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, 489cb93a386Sopenharmony_ci usesMSAASurface, 490cb93a386Sopenharmony_ci std::move(appliedClip), dstProxyView, 491cb93a386Sopenharmony_ci gp, this->primType(), 492cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 493cb93a386Sopenharmony_ci 494cb93a386Sopenharmony_ci } 495cb93a386Sopenharmony_ci 496cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 497cb93a386Sopenharmony_ci PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes); 498cb93a386Sopenharmony_ci 499cb93a386Sopenharmony_ci // fill buffers 500cb93a386Sopenharmony_ci for (int i = 0; i < fPaths.count(); i++) { 501cb93a386Sopenharmony_ci const PathData& args = fPaths[i]; 502cb93a386Sopenharmony_ci pathGeoBuilder.addPath(args.fPath, args.fTolerance); 503cb93a386Sopenharmony_ci } 504cb93a386Sopenharmony_ci } 505cb93a386Sopenharmony_ci 506cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 507cb93a386Sopenharmony_ci if (!fProgramInfo) { 508cb93a386Sopenharmony_ci this->createProgramInfo(flushState); 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci 511cb93a386Sopenharmony_ci if (!fProgramInfo || !fMeshes.count()) { 512cb93a386Sopenharmony_ci return; 513cb93a386Sopenharmony_ci } 514cb93a386Sopenharmony_ci 515cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 516cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 517cb93a386Sopenharmony_ci for (int i = 0; i < fMeshes.count(); ++i) { 518cb93a386Sopenharmony_ci flushState->drawMesh(*fMeshes[i]); 519cb93a386Sopenharmony_ci } 520cb93a386Sopenharmony_ci } 521cb93a386Sopenharmony_ci 522cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 523cb93a386Sopenharmony_ci DefaultPathOp* that = t->cast<DefaultPathOp>(); 524cb93a386Sopenharmony_ci if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 525cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 526cb93a386Sopenharmony_ci } 527cb93a386Sopenharmony_ci 528cb93a386Sopenharmony_ci if (this->color() != that->color()) { 529cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 530cb93a386Sopenharmony_ci } 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_ci if (this->coverage() != that->coverage()) { 533cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 534cb93a386Sopenharmony_ci } 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ci if (!SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) { 537cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 538cb93a386Sopenharmony_ci } 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci if (this->isHairline() != that->isHairline()) { 541cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 542cb93a386Sopenharmony_ci } 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); 545cb93a386Sopenharmony_ci return CombineResult::kMerged; 546cb93a386Sopenharmony_ci } 547cb93a386Sopenharmony_ci 548cb93a386Sopenharmony_ci#if GR_TEST_UTILS 549cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 550cb93a386Sopenharmony_ci SkString string = SkStringPrintf("Color: 0x%08x Count: %d\n", 551cb93a386Sopenharmony_ci fColor.toBytes_RGBA(), fPaths.count()); 552cb93a386Sopenharmony_ci for (const auto& path : fPaths) { 553cb93a386Sopenharmony_ci string.appendf("Tolerance: %.2f\n", path.fTolerance); 554cb93a386Sopenharmony_ci } 555cb93a386Sopenharmony_ci string += fHelper.dumpInfo(); 556cb93a386Sopenharmony_ci return string; 557cb93a386Sopenharmony_ci } 558cb93a386Sopenharmony_ci#endif 559cb93a386Sopenharmony_ci 560cb93a386Sopenharmony_ci const SkPMColor4f& color() const { return fColor; } 561cb93a386Sopenharmony_ci uint8_t coverage() const { return fCoverage; } 562cb93a386Sopenharmony_ci const SkMatrix& viewMatrix() const { return fViewMatrix; } 563cb93a386Sopenharmony_ci bool isHairline() const { return fIsHairline; } 564cb93a386Sopenharmony_ci 565cb93a386Sopenharmony_ci struct PathData { 566cb93a386Sopenharmony_ci SkPath fPath; 567cb93a386Sopenharmony_ci SkScalar fTolerance; 568cb93a386Sopenharmony_ci }; 569cb93a386Sopenharmony_ci 570cb93a386Sopenharmony_ci SkSTArray<1, PathData, true> fPaths; 571cb93a386Sopenharmony_ci Helper fHelper; 572cb93a386Sopenharmony_ci SkPMColor4f fColor; 573cb93a386Sopenharmony_ci uint8_t fCoverage; 574cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 575cb93a386Sopenharmony_ci bool fIsHairline; 576cb93a386Sopenharmony_ci 577cb93a386Sopenharmony_ci SkTDArray<GrSimpleMesh*> fMeshes; 578cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 579cb93a386Sopenharmony_ci 580cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 581cb93a386Sopenharmony_ci}; 582cb93a386Sopenharmony_ci 583cb93a386Sopenharmony_ci} // anonymous namespace 584cb93a386Sopenharmony_ci 585cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 586cb93a386Sopenharmony_ci 587cb93a386Sopenharmony_ci#if GR_TEST_UTILS 588cb93a386Sopenharmony_ci 589cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(DefaultPathOp) { 590cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrix(random); 591cb93a386Sopenharmony_ci 592cb93a386Sopenharmony_ci // For now just hairlines because the other types of draws require two ops. 593cb93a386Sopenharmony_ci // TODO we should figure out a way to combine the stencil and cover steps into one op. 594cb93a386Sopenharmony_ci GrStyle style(SkStrokeRec::kHairline_InitStyle); 595cb93a386Sopenharmony_ci const SkPath& path = GrTest::TestPath(random); 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci // Compute srcSpaceTol 598cb93a386Sopenharmony_ci SkRect bounds = path.getBounds(); 599cb93a386Sopenharmony_ci SkScalar tol = GrPathUtils::kDefaultTolerance; 600cb93a386Sopenharmony_ci SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds); 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_ci viewMatrix.mapRect(&bounds); 603cb93a386Sopenharmony_ci uint8_t coverage = GrTest::RandomCoverage(random); 604cb93a386Sopenharmony_ci GrAAType aaType = GrAAType::kNone; 605cb93a386Sopenharmony_ci if (numSamples > 1 && random->nextBool()) { 606cb93a386Sopenharmony_ci aaType = GrAAType::kMSAA; 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix, 609cb93a386Sopenharmony_ci true, aaType, bounds, GrGetRandomStencil(random, context)); 610cb93a386Sopenharmony_ci} 611cb93a386Sopenharmony_ci 612cb93a386Sopenharmony_ci#endif 613cb93a386Sopenharmony_ci 614cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 615cb93a386Sopenharmony_ci 616cb93a386Sopenharmony_cinamespace skgpu::v1 { 617cb93a386Sopenharmony_ci 618cb93a386Sopenharmony_cibool DefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc, 619cb93a386Sopenharmony_ci GrPaint&& paint, 620cb93a386Sopenharmony_ci GrAAType aaType, 621cb93a386Sopenharmony_ci const GrUserStencilSettings& userStencilSettings, 622cb93a386Sopenharmony_ci const GrClip* clip, 623cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 624cb93a386Sopenharmony_ci const GrStyledShape& shape, 625cb93a386Sopenharmony_ci bool stencilOnly) { 626cb93a386Sopenharmony_ci auto context = sdc->recordingContext(); 627cb93a386Sopenharmony_ci 628cb93a386Sopenharmony_ci SkASSERT(GrAAType::kCoverage != aaType); 629cb93a386Sopenharmony_ci SkPath path; 630cb93a386Sopenharmony_ci shape.asPath(&path); 631cb93a386Sopenharmony_ci 632cb93a386Sopenharmony_ci SkScalar hairlineCoverage; 633cb93a386Sopenharmony_ci uint8_t newCoverage = 0xff; 634cb93a386Sopenharmony_ci bool isHairline = false; 635cb93a386Sopenharmony_ci if (GrIsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) { 636cb93a386Sopenharmony_ci newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); 637cb93a386Sopenharmony_ci isHairline = true; 638cb93a386Sopenharmony_ci } else { 639cb93a386Sopenharmony_ci SkASSERT(shape.style().isSimpleFill()); 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci 642cb93a386Sopenharmony_ci int passCount = 0; 643cb93a386Sopenharmony_ci const GrUserStencilSettings* passes[2]; 644cb93a386Sopenharmony_ci bool reverse = false; 645cb93a386Sopenharmony_ci bool lastPassIsBounds; 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci if (isHairline) { 648cb93a386Sopenharmony_ci passCount = 1; 649cb93a386Sopenharmony_ci if (stencilOnly) { 650cb93a386Sopenharmony_ci passes[0] = &gDirectToStencil; 651cb93a386Sopenharmony_ci } else { 652cb93a386Sopenharmony_ci passes[0] = &userStencilSettings; 653cb93a386Sopenharmony_ci } 654cb93a386Sopenharmony_ci lastPassIsBounds = false; 655cb93a386Sopenharmony_ci } else { 656cb93a386Sopenharmony_ci if (single_pass_shape(shape)) { 657cb93a386Sopenharmony_ci passCount = 1; 658cb93a386Sopenharmony_ci if (stencilOnly) { 659cb93a386Sopenharmony_ci passes[0] = &gDirectToStencil; 660cb93a386Sopenharmony_ci } else { 661cb93a386Sopenharmony_ci passes[0] = &userStencilSettings; 662cb93a386Sopenharmony_ci } 663cb93a386Sopenharmony_ci lastPassIsBounds = false; 664cb93a386Sopenharmony_ci } else { 665cb93a386Sopenharmony_ci switch (path.getFillType()) { 666cb93a386Sopenharmony_ci case SkPathFillType::kInverseEvenOdd: 667cb93a386Sopenharmony_ci reverse = true; 668cb93a386Sopenharmony_ci [[fallthrough]]; 669cb93a386Sopenharmony_ci case SkPathFillType::kEvenOdd: 670cb93a386Sopenharmony_ci passes[0] = &gEOStencilPass; 671cb93a386Sopenharmony_ci if (stencilOnly) { 672cb93a386Sopenharmony_ci passCount = 1; 673cb93a386Sopenharmony_ci lastPassIsBounds = false; 674cb93a386Sopenharmony_ci } else { 675cb93a386Sopenharmony_ci passCount = 2; 676cb93a386Sopenharmony_ci lastPassIsBounds = true; 677cb93a386Sopenharmony_ci if (reverse) { 678cb93a386Sopenharmony_ci passes[1] = &gInvEOColorPass; 679cb93a386Sopenharmony_ci } else { 680cb93a386Sopenharmony_ci passes[1] = &gEOColorPass; 681cb93a386Sopenharmony_ci } 682cb93a386Sopenharmony_ci } 683cb93a386Sopenharmony_ci break; 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci case SkPathFillType::kInverseWinding: 686cb93a386Sopenharmony_ci reverse = true; 687cb93a386Sopenharmony_ci [[fallthrough]]; 688cb93a386Sopenharmony_ci case SkPathFillType::kWinding: 689cb93a386Sopenharmony_ci passes[0] = &gWindStencilPass; 690cb93a386Sopenharmony_ci passCount = 2; 691cb93a386Sopenharmony_ci if (stencilOnly) { 692cb93a386Sopenharmony_ci lastPassIsBounds = false; 693cb93a386Sopenharmony_ci --passCount; 694cb93a386Sopenharmony_ci } else { 695cb93a386Sopenharmony_ci lastPassIsBounds = true; 696cb93a386Sopenharmony_ci if (reverse) { 697cb93a386Sopenharmony_ci passes[passCount-1] = &gInvWindColorPass; 698cb93a386Sopenharmony_ci } else { 699cb93a386Sopenharmony_ci passes[passCount-1] = &gWindColorPass; 700cb93a386Sopenharmony_ci } 701cb93a386Sopenharmony_ci } 702cb93a386Sopenharmony_ci break; 703cb93a386Sopenharmony_ci default: 704cb93a386Sopenharmony_ci SkDEBUGFAIL("Unknown path fFill!"); 705cb93a386Sopenharmony_ci return false; 706cb93a386Sopenharmony_ci } 707cb93a386Sopenharmony_ci } 708cb93a386Sopenharmony_ci } 709cb93a386Sopenharmony_ci 710cb93a386Sopenharmony_ci SkScalar tol = GrPathUtils::kDefaultTolerance; 711cb93a386Sopenharmony_ci SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds()); 712cb93a386Sopenharmony_ci 713cb93a386Sopenharmony_ci SkRect devBounds; 714cb93a386Sopenharmony_ci GetPathDevBounds(path, sdc->asRenderTargetProxy()->backingStoreDimensions(), 715cb93a386Sopenharmony_ci viewMatrix, &devBounds); 716cb93a386Sopenharmony_ci 717cb93a386Sopenharmony_ci for (int p = 0; p < passCount; ++p) { 718cb93a386Sopenharmony_ci if (lastPassIsBounds && (p == passCount-1)) { 719cb93a386Sopenharmony_ci SkRect bounds; 720cb93a386Sopenharmony_ci SkMatrix localMatrix = SkMatrix::I(); 721cb93a386Sopenharmony_ci if (reverse) { 722cb93a386Sopenharmony_ci // draw over the dev bounds (which will be the whole dst surface for inv fill). 723cb93a386Sopenharmony_ci bounds = devBounds; 724cb93a386Sopenharmony_ci SkMatrix vmi; 725cb93a386Sopenharmony_ci // mapRect through persp matrix may not be correct 726cb93a386Sopenharmony_ci if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 727cb93a386Sopenharmony_ci vmi.mapRect(&bounds); 728cb93a386Sopenharmony_ci } else { 729cb93a386Sopenharmony_ci if (!viewMatrix.invert(&localMatrix)) { 730cb93a386Sopenharmony_ci return false; 731cb93a386Sopenharmony_ci } 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci } else { 734cb93a386Sopenharmony_ci bounds = path.getBounds(); 735cb93a386Sopenharmony_ci } 736cb93a386Sopenharmony_ci const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() : 737cb93a386Sopenharmony_ci viewMatrix; 738cb93a386Sopenharmony_ci // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start 739cb93a386Sopenharmony_ci assert_alive(paint); 740cb93a386Sopenharmony_ci sdc->stencilRect(clip, passes[p], std::move(paint), 741cb93a386Sopenharmony_ci GrAA(aaType == GrAAType::kMSAA), viewM, bounds, 742cb93a386Sopenharmony_ci &localMatrix); 743cb93a386Sopenharmony_ci } else { 744cb93a386Sopenharmony_ci bool stencilPass = stencilOnly || passCount > 1; 745cb93a386Sopenharmony_ci GrOp::Owner op; 746cb93a386Sopenharmony_ci if (stencilPass) { 747cb93a386Sopenharmony_ci GrPaint stencilPaint; 748cb93a386Sopenharmony_ci stencilPaint.setXPFactory(GrDisableColorXPFactory::Get()); 749cb93a386Sopenharmony_ci op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol, 750cb93a386Sopenharmony_ci newCoverage, viewMatrix, isHairline, aaType, devBounds, 751cb93a386Sopenharmony_ci passes[p]); 752cb93a386Sopenharmony_ci } else { 753cb93a386Sopenharmony_ci assert_alive(paint); 754cb93a386Sopenharmony_ci op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage, 755cb93a386Sopenharmony_ci viewMatrix, isHairline, aaType, devBounds, passes[p]); 756cb93a386Sopenharmony_ci } 757cb93a386Sopenharmony_ci sdc->addDrawOp(clip, std::move(op)); 758cb93a386Sopenharmony_ci } 759cb93a386Sopenharmony_ci } 760cb93a386Sopenharmony_ci return true; 761cb93a386Sopenharmony_ci} 762cb93a386Sopenharmony_ci 763cb93a386Sopenharmony_ci 764cb93a386Sopenharmony_ciPathRenderer::StencilSupport 765cb93a386Sopenharmony_ciDefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const { 766cb93a386Sopenharmony_ci if (single_pass_shape(shape)) { 767cb93a386Sopenharmony_ci return kNoRestriction_StencilSupport; 768cb93a386Sopenharmony_ci } else { 769cb93a386Sopenharmony_ci return kStencilOnly_StencilSupport; 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci} 772cb93a386Sopenharmony_ci 773cb93a386Sopenharmony_ciPathRenderer::CanDrawPath DefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 774cb93a386Sopenharmony_ci bool isHairline = GrIsStrokeHairlineOrEquivalent( 775cb93a386Sopenharmony_ci args.fShape->style(), *args.fViewMatrix, nullptr); 776cb93a386Sopenharmony_ci // If we aren't a single_pass_shape or hairline, we require stencil buffers. 777cb93a386Sopenharmony_ci if (!(single_pass_shape(*args.fShape) || isHairline) && 778cb93a386Sopenharmony_ci !args.fProxy->canUseStencil(*args.fCaps)) { 779cb93a386Sopenharmony_ci return CanDrawPath::kNo; 780cb93a386Sopenharmony_ci } 781cb93a386Sopenharmony_ci // If antialiasing is required, we only support MSAA. 782cb93a386Sopenharmony_ci if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) { 783cb93a386Sopenharmony_ci return CanDrawPath::kNo; 784cb93a386Sopenharmony_ci } 785cb93a386Sopenharmony_ci // This can draw any path with any simple fill style. 786cb93a386Sopenharmony_ci if (!args.fShape->style().isSimpleFill() && !isHairline) { 787cb93a386Sopenharmony_ci return CanDrawPath::kNo; 788cb93a386Sopenharmony_ci } 789cb93a386Sopenharmony_ci // This is the fallback renderer for when a path is too complicated for the others to draw. 790cb93a386Sopenharmony_ci return CanDrawPath::kAsBackup; 791cb93a386Sopenharmony_ci} 792cb93a386Sopenharmony_ci 793cb93a386Sopenharmony_cibool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { 794cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 795cb93a386Sopenharmony_ci "DefaultPathRenderer::onDrawPath"); 796cb93a386Sopenharmony_ci GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone; 797cb93a386Sopenharmony_ci 798cb93a386Sopenharmony_ci return this->internalDrawPath( 799cb93a386Sopenharmony_ci args.fSurfaceDrawContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings, 800cb93a386Sopenharmony_ci args.fClip, *args.fViewMatrix, *args.fShape, false); 801cb93a386Sopenharmony_ci} 802cb93a386Sopenharmony_ci 803cb93a386Sopenharmony_civoid DefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { 804cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 805cb93a386Sopenharmony_ci "DefaultPathRenderer::onStencilPath"); 806cb93a386Sopenharmony_ci SkASSERT(!args.fShape->inverseFilled()); 807cb93a386Sopenharmony_ci 808cb93a386Sopenharmony_ci GrPaint paint; 809cb93a386Sopenharmony_ci paint.setXPFactory(GrDisableColorXPFactory::Get()); 810cb93a386Sopenharmony_ci 811cb93a386Sopenharmony_ci auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone; 812cb93a386Sopenharmony_ci 813cb93a386Sopenharmony_ci this->internalDrawPath( 814cb93a386Sopenharmony_ci args.fSurfaceDrawContext, std::move(paint), aaType, GrUserStencilSettings::kUnused, 815cb93a386Sopenharmony_ci args.fClip, *args.fViewMatrix, *args.fShape, true); 816cb93a386Sopenharmony_ci} 817cb93a386Sopenharmony_ci 818cb93a386Sopenharmony_ci} // namespace skgpu::v1 819