1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2015 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/TriangulatingPathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkIDChangeListener.h" 11cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrEagerVertexAllocator.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrResourceCache.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrResourceProvider.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrSimpleMesh.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 24cb93a386Sopenharmony_ci#include "src/gpu/GrThreadSafeCache.h" 25cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrAATriangulator.h" 26cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h" 27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 28cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrTriangulator.h" 29cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 30cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 31cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci#include <cstdio> 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci#ifndef GR_AA_TESSELLATOR_MAX_VERB_COUNT 36cb93a386Sopenharmony_ci#define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10 37cb93a386Sopenharmony_ci#endif 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci/* 40cb93a386Sopenharmony_ci * This path renderer linearizes and decomposes the path into triangles using GrTriangulator, 41cb93a386Sopenharmony_ci * uploads the triangles to a vertex buffer, and renders them with a single draw call. It can do 42cb93a386Sopenharmony_ci * screenspace antialiasing with a one-pixel coverage ramp. 43cb93a386Sopenharmony_ci */ 44cb93a386Sopenharmony_cinamespace { 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci// The TessInfo struct contains ancillary data not specifically required for the triangle 47cb93a386Sopenharmony_ci// data (which is stored in a GrThreadSafeCache::VertexData object). 48cb93a386Sopenharmony_ci// The 'fNumVertices' field is a temporary exception. It is still needed to support the 49cb93a386Sopenharmony_ci// AA triangulated path case - which doesn't use the GrThreadSafeCache nor the VertexData object). 50cb93a386Sopenharmony_ci// When there is an associated VertexData, its numVertices should always match the TessInfo's 51cb93a386Sopenharmony_ci// value. 52cb93a386Sopenharmony_cistruct TessInfo { 53cb93a386Sopenharmony_ci int fNumVertices; 54cb93a386Sopenharmony_ci bool fIsLinear; 55cb93a386Sopenharmony_ci SkScalar fTolerance; 56cb93a386Sopenharmony_ci}; 57cb93a386Sopenharmony_ci 58cb93a386Sopenharmony_cistatic sk_sp<SkData> create_data(int numVertices, bool isLinear, SkScalar tol) { 59cb93a386Sopenharmony_ci TessInfo info { numVertices, isLinear, tol }; 60cb93a386Sopenharmony_ci return SkData::MakeWithCopy(&info, sizeof(info)); 61cb93a386Sopenharmony_ci} 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_cibool cache_match(const SkData* data, SkScalar tol) { 64cb93a386Sopenharmony_ci SkASSERT(data); 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci const TessInfo* info = static_cast<const TessInfo*>(data->data()); 67cb93a386Sopenharmony_ci 68cb93a386Sopenharmony_ci return info->fIsLinear || info->fTolerance < 3.0f * tol; 69cb93a386Sopenharmony_ci} 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci// Should 'challenger' replace 'incumbent' in the cache if there is a collision? 72cb93a386Sopenharmony_cibool is_newer_better(SkData* incumbent, SkData* challenger) { 73cb93a386Sopenharmony_ci const TessInfo* i = static_cast<const TessInfo*>(incumbent->data()); 74cb93a386Sopenharmony_ci const TessInfo* c = static_cast<const TessInfo*>(challenger->data()); 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_ci if (i->fIsLinear || i->fTolerance <= c->fTolerance) { 77cb93a386Sopenharmony_ci return false; // prefer the incumbent 78cb93a386Sopenharmony_ci } 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ci return true; 81cb93a386Sopenharmony_ci} 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key. 84cb93a386Sopenharmony_ciclass UniqueKeyInvalidator : public SkIDChangeListener { 85cb93a386Sopenharmony_cipublic: 86cb93a386Sopenharmony_ci UniqueKeyInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID) 87cb93a386Sopenharmony_ci : fMsg(key, contextUniqueID, /* inThreadSafeCache */ true) {} 88cb93a386Sopenharmony_ci 89cb93a386Sopenharmony_ciprivate: 90cb93a386Sopenharmony_ci GrUniqueKeyInvalidatedMessage fMsg; 91cb93a386Sopenharmony_ci 92cb93a386Sopenharmony_ci void changed() override { SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Post(fMsg); } 93cb93a386Sopenharmony_ci}; 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ciclass StaticVertexAllocator : public GrEagerVertexAllocator { 96cb93a386Sopenharmony_cipublic: 97cb93a386Sopenharmony_ci StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB) 98cb93a386Sopenharmony_ci : fResourceProvider(resourceProvider) 99cb93a386Sopenharmony_ci , fCanMapVB(canMapVB) { 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci#ifdef SK_DEBUG 103cb93a386Sopenharmony_ci ~StaticVertexAllocator() override { 104cb93a386Sopenharmony_ci SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci#endif 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci void* lock(size_t stride, int eagerCount) override { 109cb93a386Sopenharmony_ci SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData); 110cb93a386Sopenharmony_ci SkASSERT(stride && eagerCount); 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci size_t size = eagerCount * stride; 113cb93a386Sopenharmony_ci fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex, 114cb93a386Sopenharmony_ci kStatic_GrAccessPattern); 115cb93a386Sopenharmony_ci if (!fVertexBuffer) { 116cb93a386Sopenharmony_ci return nullptr; 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci if (fCanMapVB) { 119cb93a386Sopenharmony_ci fVertices = fVertexBuffer->map(); 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ci if (!fVertices) { 122cb93a386Sopenharmony_ci fVertices = sk_malloc_throw(eagerCount * stride); 123cb93a386Sopenharmony_ci fCanMapVB = false; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci fLockStride = stride; 126cb93a386Sopenharmony_ci return fVertices; 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_ci void unlock(int actualCount) override { 130cb93a386Sopenharmony_ci SkASSERT(fLockStride && fVertices && fVertexBuffer && !fVertexData); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci if (fCanMapVB) { 133cb93a386Sopenharmony_ci fVertexBuffer->unmap(); 134cb93a386Sopenharmony_ci } else { 135cb93a386Sopenharmony_ci fVertexBuffer->updateData(fVertices, actualCount * fLockStride); 136cb93a386Sopenharmony_ci sk_free(fVertices); 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci fVertexData = GrThreadSafeCache::MakeVertexData(std::move(fVertexBuffer), 140cb93a386Sopenharmony_ci actualCount, fLockStride); 141cb93a386Sopenharmony_ci 142cb93a386Sopenharmony_ci fVertices = nullptr; 143cb93a386Sopenharmony_ci fLockStride = 0; 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::VertexData> detachVertexData() { 147cb93a386Sopenharmony_ci SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && fVertexData); 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci return std::move(fVertexData); 150cb93a386Sopenharmony_ci } 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciprivate: 153cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::VertexData> fVertexData; 154cb93a386Sopenharmony_ci sk_sp<GrGpuBuffer> fVertexBuffer; 155cb93a386Sopenharmony_ci GrResourceProvider* fResourceProvider; 156cb93a386Sopenharmony_ci bool fCanMapVB; 157cb93a386Sopenharmony_ci void* fVertices = nullptr; 158cb93a386Sopenharmony_ci size_t fLockStride = 0; 159cb93a386Sopenharmony_ci}; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ciclass TriangulatingPathOp final : public GrMeshDrawOp { 162cb93a386Sopenharmony_ciprivate: 163cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_cipublic: 166cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 169cb93a386Sopenharmony_ci GrPaint&& paint, 170cb93a386Sopenharmony_ci const GrStyledShape& shape, 171cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 172cb93a386Sopenharmony_ci SkIRect devClipBounds, 173cb93a386Sopenharmony_ci GrAAType aaType, 174cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 175cb93a386Sopenharmony_ci return Helper::FactoryHelper<TriangulatingPathOp>(context, std::move(paint), shape, 176cb93a386Sopenharmony_ci viewMatrix, devClipBounds, aaType, 177cb93a386Sopenharmony_ci stencilSettings); 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci const char* name() const override { return "TriangulatingPathOp"; } 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 183cb93a386Sopenharmony_ci if (fProgramInfo) { 184cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 185cb93a386Sopenharmony_ci } else { 186cb93a386Sopenharmony_ci fHelper.visitProxies(func); 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci TriangulatingPathOp(GrProcessorSet* processorSet, 191cb93a386Sopenharmony_ci const SkPMColor4f& color, 192cb93a386Sopenharmony_ci const GrStyledShape& shape, 193cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 194cb93a386Sopenharmony_ci const SkIRect& devClipBounds, 195cb93a386Sopenharmony_ci GrAAType aaType, 196cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) 197cb93a386Sopenharmony_ci : INHERITED(ClassID()) 198cb93a386Sopenharmony_ci , fHelper(processorSet, aaType, stencilSettings) 199cb93a386Sopenharmony_ci , fColor(color) 200cb93a386Sopenharmony_ci , fShape(shape) 201cb93a386Sopenharmony_ci , fViewMatrix(viewMatrix) 202cb93a386Sopenharmony_ci , fDevClipBounds(devClipBounds) 203cb93a386Sopenharmony_ci , fAntiAlias(GrAAType::kCoverage == aaType) { 204cb93a386Sopenharmony_ci SkRect devBounds; 205cb93a386Sopenharmony_ci viewMatrix.mapRect(&devBounds, shape.bounds()); 206cb93a386Sopenharmony_ci if (shape.inverseFilled()) { 207cb93a386Sopenharmony_ci // Because the clip bounds are used to add a contour for inverse fills, they must also 208cb93a386Sopenharmony_ci // include the path bounds. 209cb93a386Sopenharmony_ci devBounds.join(SkRect::Make(fDevClipBounds)); 210cb93a386Sopenharmony_ci } 211cb93a386Sopenharmony_ci this->setBounds(devBounds, HasAABloat(fAntiAlias), IsHairline::kNo); 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 215cb93a386Sopenharmony_ci 216cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 217cb93a386Sopenharmony_ci GrClampType clampType) override { 218cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage coverage = fAntiAlias 219cb93a386Sopenharmony_ci ? GrProcessorAnalysisCoverage::kSingleChannel 220cb93a386Sopenharmony_ci : GrProcessorAnalysisCoverage::kNone; 221cb93a386Sopenharmony_ci // This Op uses uniform (not vertex) color, so doesn't need to track wide color. 222cb93a386Sopenharmony_ci return fHelper.finalizeProcessors(caps, clip, clampType, coverage, &fColor, nullptr); 223cb93a386Sopenharmony_ci } 224cb93a386Sopenharmony_ci 225cb93a386Sopenharmony_ciprivate: 226cb93a386Sopenharmony_ci SkPath getPath() const { 227cb93a386Sopenharmony_ci SkASSERT(!fShape.style().applies()); 228cb93a386Sopenharmony_ci SkPath path; 229cb93a386Sopenharmony_ci fShape.asPath(&path); 230cb93a386Sopenharmony_ci return path; 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci 233cb93a386Sopenharmony_ci static void CreateKey(GrUniqueKey* key, 234cb93a386Sopenharmony_ci const GrStyledShape& shape, 235cb93a386Sopenharmony_ci const SkIRect& devClipBounds) { 236cb93a386Sopenharmony_ci static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_ci bool inverseFill = shape.inverseFilled(); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t); 241cb93a386Sopenharmony_ci int shapeKeyDataCnt = shape.unstyledKeySize(); 242cb93a386Sopenharmony_ci SkASSERT(shapeKeyDataCnt >= 0); 243cb93a386Sopenharmony_ci GrUniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path"); 244cb93a386Sopenharmony_ci shape.writeUnstyledKey(&builder[0]); 245cb93a386Sopenharmony_ci // For inverse fills, the tessellation is dependent on clip bounds. 246cb93a386Sopenharmony_ci if (inverseFill) { 247cb93a386Sopenharmony_ci memcpy(&builder[shapeKeyDataCnt], &devClipBounds, sizeof(devClipBounds)); 248cb93a386Sopenharmony_ci } else { 249cb93a386Sopenharmony_ci memset(&builder[shapeKeyDataCnt], 0, sizeof(devClipBounds)); 250cb93a386Sopenharmony_ci } 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci builder.finish(); 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci // Triangulate the provided 'shape' in the shape's coordinate space. 'tol' should already 256cb93a386Sopenharmony_ci // have been mapped back from device space. 257cb93a386Sopenharmony_ci static int Triangulate(GrEagerVertexAllocator* allocator, 258cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 259cb93a386Sopenharmony_ci const GrStyledShape& shape, 260cb93a386Sopenharmony_ci const SkIRect& devClipBounds, 261cb93a386Sopenharmony_ci SkScalar tol, 262cb93a386Sopenharmony_ci bool* isLinear) { 263cb93a386Sopenharmony_ci SkRect clipBounds = SkRect::Make(devClipBounds); 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_ci SkMatrix vmi; 266cb93a386Sopenharmony_ci if (!viewMatrix.invert(&vmi)) { 267cb93a386Sopenharmony_ci return 0; 268cb93a386Sopenharmony_ci } 269cb93a386Sopenharmony_ci vmi.mapRect(&clipBounds); 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci SkASSERT(!shape.style().applies()); 272cb93a386Sopenharmony_ci SkPath path; 273cb93a386Sopenharmony_ci shape.asPath(&path); 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator, isLinear); 276cb93a386Sopenharmony_ci } 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_ci void createNonAAMesh(GrMeshDrawTarget* target) { 279cb93a386Sopenharmony_ci SkASSERT(!fAntiAlias); 280cb93a386Sopenharmony_ci GrResourceProvider* rp = target->resourceProvider(); 281cb93a386Sopenharmony_ci auto threadSafeCache = target->threadSafeCache(); 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci GrUniqueKey key; 284cb93a386Sopenharmony_ci CreateKey(&key, fShape, fDevClipBounds); 285cb93a386Sopenharmony_ci 286cb93a386Sopenharmony_ci SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance, 287cb93a386Sopenharmony_ci fViewMatrix, fShape.bounds()); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci if (!fVertexData) { 290cb93a386Sopenharmony_ci auto [cachedVerts, data] = threadSafeCache->findVertsWithData(key); 291cb93a386Sopenharmony_ci if (cachedVerts && cache_match(data.get(), tol)) { 292cb93a386Sopenharmony_ci fVertexData = std::move(cachedVerts); 293cb93a386Sopenharmony_ci } 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci if (fVertexData) { 297cb93a386Sopenharmony_ci if (!fVertexData->gpuBuffer()) { 298cb93a386Sopenharmony_ci sk_sp<GrGpuBuffer> buffer = rp->createBuffer(fVertexData->size(), 299cb93a386Sopenharmony_ci GrGpuBufferType::kVertex, 300cb93a386Sopenharmony_ci kStatic_GrAccessPattern, 301cb93a386Sopenharmony_ci fVertexData->vertices()); 302cb93a386Sopenharmony_ci if (!buffer) { 303cb93a386Sopenharmony_ci return; 304cb93a386Sopenharmony_ci } 305cb93a386Sopenharmony_ci 306cb93a386Sopenharmony_ci // Since we have a direct context and a ref on 'fVertexData' we need not worry 307cb93a386Sopenharmony_ci // about any threading issues in this call. 308cb93a386Sopenharmony_ci fVertexData->setGpuBuffer(std::move(buffer)); 309cb93a386Sopenharmony_ci } 310cb93a386Sopenharmony_ci 311cb93a386Sopenharmony_ci fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices()); 312cb93a386Sopenharmony_ci return; 313cb93a386Sopenharmony_ci } 314cb93a386Sopenharmony_ci 315cb93a386Sopenharmony_ci bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags(); 316cb93a386Sopenharmony_ci StaticVertexAllocator allocator(rp, canMapVB); 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci bool isLinear; 319cb93a386Sopenharmony_ci int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol, 320cb93a386Sopenharmony_ci &isLinear); 321cb93a386Sopenharmony_ci if (vertexCount == 0) { 322cb93a386Sopenharmony_ci return; 323cb93a386Sopenharmony_ci } 324cb93a386Sopenharmony_ci 325cb93a386Sopenharmony_ci fVertexData = allocator.detachVertexData(); 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci key.setCustomData(create_data(vertexCount, isLinear, tol)); 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_ci auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better); 330cb93a386Sopenharmony_ci if (tmpV != fVertexData) { 331cb93a386Sopenharmony_ci SkASSERT(!tmpV->gpuBuffer()); 332cb93a386Sopenharmony_ci // In this case, although the different triangulation found in the cache is better, 333cb93a386Sopenharmony_ci // we will continue on with the current triangulation since it is already on the gpu. 334cb93a386Sopenharmony_ci } else { 335cb93a386Sopenharmony_ci // This isn't perfect. The current triangulation is in the cache but it may have 336cb93a386Sopenharmony_ci // replaced a pre-existing one. A duplicated listener is unlikely and not that 337cb93a386Sopenharmony_ci // expensive so we just roll with it. 338cb93a386Sopenharmony_ci fShape.addGenIDChangeListener( 339cb93a386Sopenharmony_ci sk_make_sp<UniqueKeyInvalidator>(key, target->contextUniqueID())); 340cb93a386Sopenharmony_ci } 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices()); 343cb93a386Sopenharmony_ci } 344cb93a386Sopenharmony_ci 345cb93a386Sopenharmony_ci void createAAMesh(GrMeshDrawTarget* target) { 346cb93a386Sopenharmony_ci SkASSERT(!fVertexData); 347cb93a386Sopenharmony_ci SkASSERT(fAntiAlias); 348cb93a386Sopenharmony_ci SkPath path = this->getPath(); 349cb93a386Sopenharmony_ci if (path.isEmpty()) { 350cb93a386Sopenharmony_ci return; 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci SkRect clipBounds = SkRect::Make(fDevClipBounds); 353cb93a386Sopenharmony_ci path.transform(fViewMatrix); 354cb93a386Sopenharmony_ci SkScalar tol = GrPathUtils::kDefaultTolerance; 355cb93a386Sopenharmony_ci sk_sp<const GrBuffer> vertexBuffer; 356cb93a386Sopenharmony_ci int firstVertex; 357cb93a386Sopenharmony_ci GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex); 358cb93a386Sopenharmony_ci int vertexCount = GrAATriangulator::PathToAATriangles(path, tol, clipBounds, &allocator); 359cb93a386Sopenharmony_ci if (vertexCount == 0) { 360cb93a386Sopenharmony_ci return; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci fMesh = CreateMesh(target, std::move(vertexBuffer), firstVertex, vertexCount); 363cb93a386Sopenharmony_ci } 364cb93a386Sopenharmony_ci 365cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return fProgramInfo; } 366cb93a386Sopenharmony_ci 367cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 368cb93a386Sopenharmony_ci SkArenaAlloc* arena, 369cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 370cb93a386Sopenharmony_ci bool usesMSAASurface, 371cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 372cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 373cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 374cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 375cb93a386Sopenharmony_ci GrGeometryProcessor* gp; 376cb93a386Sopenharmony_ci { 377cb93a386Sopenharmony_ci using namespace GrDefaultGeoProcFactory; 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci Color color(fColor); 380cb93a386Sopenharmony_ci LocalCoords::Type localCoordsType = fHelper.usesLocalCoords() 381cb93a386Sopenharmony_ci ? LocalCoords::kUsePosition_Type 382cb93a386Sopenharmony_ci : LocalCoords::kUnused_Type; 383cb93a386Sopenharmony_ci Coverage::Type coverageType; 384cb93a386Sopenharmony_ci if (fAntiAlias) { 385cb93a386Sopenharmony_ci if (fHelper.compatibleWithCoverageAsAlpha()) { 386cb93a386Sopenharmony_ci coverageType = Coverage::kAttributeTweakAlpha_Type; 387cb93a386Sopenharmony_ci } else { 388cb93a386Sopenharmony_ci coverageType = Coverage::kAttribute_Type; 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci } else { 391cb93a386Sopenharmony_ci coverageType = Coverage::kSolid_Type; 392cb93a386Sopenharmony_ci } 393cb93a386Sopenharmony_ci if (fAntiAlias) { 394cb93a386Sopenharmony_ci gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(arena, color, coverageType, 395cb93a386Sopenharmony_ci localCoordsType, fViewMatrix); 396cb93a386Sopenharmony_ci } else { 397cb93a386Sopenharmony_ci gp = GrDefaultGeoProcFactory::Make(arena, color, coverageType, localCoordsType, 398cb93a386Sopenharmony_ci fViewMatrix); 399cb93a386Sopenharmony_ci } 400cb93a386Sopenharmony_ci } 401cb93a386Sopenharmony_ci if (!gp) { 402cb93a386Sopenharmony_ci return; 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci 405cb93a386Sopenharmony_ci#ifdef SK_DEBUG 406cb93a386Sopenharmony_ci auto vertexStride = sizeof(SkPoint); 407cb93a386Sopenharmony_ci if (fAntiAlias) { 408cb93a386Sopenharmony_ci vertexStride += sizeof(float); 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci SkASSERT(vertexStride == gp->vertexStride()); 411cb93a386Sopenharmony_ci#endif 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_ci GrPrimitiveType primitiveType = TRIANGULATOR_WIREFRAME ? GrPrimitiveType::kLines 414cb93a386Sopenharmony_ci : GrPrimitiveType::kTriangles; 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, 417cb93a386Sopenharmony_ci usesMSAASurface, 418cb93a386Sopenharmony_ci std::move(appliedClip), dstProxyView, 419cb93a386Sopenharmony_ci gp, primitiveType, 420cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci 423cb93a386Sopenharmony_ci void onPrePrepareDraws(GrRecordingContext* rContext, 424cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 425cb93a386Sopenharmony_ci GrAppliedClip* clip, 426cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 427cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 428cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 429cb93a386Sopenharmony_ci TRACE_EVENT0("skia.gpu", TRACE_FUNC); 430cb93a386Sopenharmony_ci 431cb93a386Sopenharmony_ci INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView, 432cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_ci if (fAntiAlias) { 435cb93a386Sopenharmony_ci // TODO: pull the triangulation work forward to the recording thread for the AA case 436cb93a386Sopenharmony_ci // too. 437cb93a386Sopenharmony_ci return; 438cb93a386Sopenharmony_ci } 439cb93a386Sopenharmony_ci 440cb93a386Sopenharmony_ci auto threadSafeViewCache = rContext->priv().threadSafeCache(); 441cb93a386Sopenharmony_ci 442cb93a386Sopenharmony_ci GrUniqueKey key; 443cb93a386Sopenharmony_ci CreateKey(&key, fShape, fDevClipBounds); 444cb93a386Sopenharmony_ci 445cb93a386Sopenharmony_ci SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance, 446cb93a386Sopenharmony_ci fViewMatrix, fShape.bounds()); 447cb93a386Sopenharmony_ci 448cb93a386Sopenharmony_ci auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key); 449cb93a386Sopenharmony_ci if (cachedVerts && cache_match(data.get(), tol)) { 450cb93a386Sopenharmony_ci fVertexData = std::move(cachedVerts); 451cb93a386Sopenharmony_ci return; 452cb93a386Sopenharmony_ci } 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_ci GrCpuVertexAllocator allocator; 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci bool isLinear; 457cb93a386Sopenharmony_ci int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol, 458cb93a386Sopenharmony_ci &isLinear); 459cb93a386Sopenharmony_ci if (vertexCount == 0) { 460cb93a386Sopenharmony_ci return; 461cb93a386Sopenharmony_ci } 462cb93a386Sopenharmony_ci 463cb93a386Sopenharmony_ci fVertexData = allocator.detachVertexData(); 464cb93a386Sopenharmony_ci 465cb93a386Sopenharmony_ci key.setCustomData(create_data(vertexCount, isLinear, tol)); 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci // If some other thread created and cached its own triangulation, the 'is_newer_better' 468cb93a386Sopenharmony_ci // predicate will replace the version in the cache if 'fVertexData' is a more accurate 469cb93a386Sopenharmony_ci // triangulation. This will leave some other recording threads using a poorer triangulation 470cb93a386Sopenharmony_ci // but will result in a version with greater applicability being in the cache. 471cb93a386Sopenharmony_ci auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData, 472cb93a386Sopenharmony_ci is_newer_better); 473cb93a386Sopenharmony_ci if (tmpV != fVertexData) { 474cb93a386Sopenharmony_ci // Someone beat us to creating the triangulation (and it is better than ours) so 475cb93a386Sopenharmony_ci // just go ahead and use it. 476cb93a386Sopenharmony_ci SkASSERT(cache_match(tmpD.get(), tol)); 477cb93a386Sopenharmony_ci fVertexData = std::move(tmpV); 478cb93a386Sopenharmony_ci } else { 479cb93a386Sopenharmony_ci // This isn't perfect. The current triangulation is in the cache but it may have 480cb93a386Sopenharmony_ci // replaced a pre-existing one. A duplicated listener is unlikely and not that 481cb93a386Sopenharmony_ci // expensive so we just roll with it. 482cb93a386Sopenharmony_ci fShape.addGenIDChangeListener( 483cb93a386Sopenharmony_ci sk_make_sp<UniqueKeyInvalidator>(key, rContext->priv().contextID())); 484cb93a386Sopenharmony_ci } 485cb93a386Sopenharmony_ci } 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 488cb93a386Sopenharmony_ci if (fAntiAlias) { 489cb93a386Sopenharmony_ci this->createAAMesh(target); 490cb93a386Sopenharmony_ci } else { 491cb93a386Sopenharmony_ci this->createNonAAMesh(target); 492cb93a386Sopenharmony_ci } 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci static GrSimpleMesh* CreateMesh(GrMeshDrawTarget* target, 496cb93a386Sopenharmony_ci sk_sp<const GrBuffer> vb, 497cb93a386Sopenharmony_ci int firstVertex, 498cb93a386Sopenharmony_ci int count) { 499cb93a386Sopenharmony_ci auto mesh = target->allocMesh(); 500cb93a386Sopenharmony_ci mesh->set(std::move(vb), count, firstVertex); 501cb93a386Sopenharmony_ci return mesh; 502cb93a386Sopenharmony_ci } 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 505cb93a386Sopenharmony_ci if (!fProgramInfo) { 506cb93a386Sopenharmony_ci this->createProgramInfo(flushState); 507cb93a386Sopenharmony_ci } 508cb93a386Sopenharmony_ci 509cb93a386Sopenharmony_ci if (!fProgramInfo || !fMesh) { 510cb93a386Sopenharmony_ci return; 511cb93a386Sopenharmony_ci } 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 514cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 515cb93a386Sopenharmony_ci flushState->drawMesh(*fMesh); 516cb93a386Sopenharmony_ci } 517cb93a386Sopenharmony_ci 518cb93a386Sopenharmony_ci#if GR_TEST_UTILS 519cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 520cb93a386Sopenharmony_ci return SkStringPrintf("Color 0x%08x, aa: %d\n%s", 521cb93a386Sopenharmony_ci fColor.toBytes_RGBA(), fAntiAlias, fHelper.dumpInfo().c_str()); 522cb93a386Sopenharmony_ci } 523cb93a386Sopenharmony_ci#endif 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci Helper fHelper; 526cb93a386Sopenharmony_ci SkPMColor4f fColor; 527cb93a386Sopenharmony_ci GrStyledShape fShape; 528cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 529cb93a386Sopenharmony_ci SkIRect fDevClipBounds; 530cb93a386Sopenharmony_ci bool fAntiAlias; 531cb93a386Sopenharmony_ci 532cb93a386Sopenharmony_ci GrSimpleMesh* fMesh = nullptr; 533cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 534cb93a386Sopenharmony_ci 535cb93a386Sopenharmony_ci sk_sp<GrThreadSafeCache::VertexData> fVertexData; 536cb93a386Sopenharmony_ci 537cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 538cb93a386Sopenharmony_ci}; 539cb93a386Sopenharmony_ci 540cb93a386Sopenharmony_ci} // anonymous namespace 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 543cb93a386Sopenharmony_ci 544cb93a386Sopenharmony_ci#if GR_TEST_UTILS 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp) { 547cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); 548cb93a386Sopenharmony_ci const SkPath& path = GrTest::TestPath(random); 549cb93a386Sopenharmony_ci SkIRect devClipBounds = SkIRect::MakeLTRB( 550cb93a386Sopenharmony_ci random->nextU(), random->nextU(), random->nextU(), random->nextU()); 551cb93a386Sopenharmony_ci devClipBounds.sort(); 552cb93a386Sopenharmony_ci static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage}; 553cb93a386Sopenharmony_ci GrAAType aaType; 554cb93a386Sopenharmony_ci do { 555cb93a386Sopenharmony_ci aaType = kAATypes[random->nextULessThan(SK_ARRAY_COUNT(kAATypes))]; 556cb93a386Sopenharmony_ci } while(GrAAType::kMSAA == aaType && numSamples <= 1); 557cb93a386Sopenharmony_ci GrStyle style; 558cb93a386Sopenharmony_ci do { 559cb93a386Sopenharmony_ci GrTest::TestStyle(random, &style); 560cb93a386Sopenharmony_ci } while (!style.isSimpleFill()); 561cb93a386Sopenharmony_ci GrStyledShape shape(path, style); 562cb93a386Sopenharmony_ci return TriangulatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds, 563cb93a386Sopenharmony_ci aaType, GrGetRandomStencil(random, context)); 564cb93a386Sopenharmony_ci} 565cb93a386Sopenharmony_ci 566cb93a386Sopenharmony_ci#endif 567cb93a386Sopenharmony_ci 568cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 569cb93a386Sopenharmony_ci 570cb93a386Sopenharmony_cinamespace skgpu::v1 { 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ciTriangulatingPathRenderer::TriangulatingPathRenderer() 573cb93a386Sopenharmony_ci : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) { 574cb93a386Sopenharmony_ci} 575cb93a386Sopenharmony_ci 576cb93a386Sopenharmony_ciPathRenderer::CanDrawPath TriangulatingPathRenderer::onCanDrawPath( 577cb93a386Sopenharmony_ci const CanDrawPathArgs& args) const { 578cb93a386Sopenharmony_ci 579cb93a386Sopenharmony_ci // Don't use this path renderer with dynamic MSAA. DMSAA tries to not rely on caching. 580cb93a386Sopenharmony_ci if (args.fSurfaceProps->flags() & SkSurfaceProps::kDynamicMSAA_Flag) { 581cb93a386Sopenharmony_ci return CanDrawPath::kNo; 582cb93a386Sopenharmony_ci } 583cb93a386Sopenharmony_ci // This path renderer can draw fill styles, and can do screenspace antialiasing via a 584cb93a386Sopenharmony_ci // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex 585cb93a386Sopenharmony_ci // ones to simpler algorithms. We pass on paths that have styles, though they may come back 586cb93a386Sopenharmony_ci // around after applying the styling information to the geometry to create a filled path. 587cb93a386Sopenharmony_ci if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) { 588cb93a386Sopenharmony_ci return CanDrawPath::kNo; 589cb93a386Sopenharmony_ci } 590cb93a386Sopenharmony_ci switch (args.fAAType) { 591cb93a386Sopenharmony_ci case GrAAType::kNone: 592cb93a386Sopenharmony_ci case GrAAType::kMSAA: 593cb93a386Sopenharmony_ci // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that 594cb93a386Sopenharmony_ci // don't have a key since the real advantage of this path renderer comes from caching 595cb93a386Sopenharmony_ci // the tessellated geometry. 596cb93a386Sopenharmony_ci if (!args.fShape->hasUnstyledKey()) { 597cb93a386Sopenharmony_ci return CanDrawPath::kNo; 598cb93a386Sopenharmony_ci } 599cb93a386Sopenharmony_ci break; 600cb93a386Sopenharmony_ci case GrAAType::kCoverage: 601cb93a386Sopenharmony_ci // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept 602cb93a386Sopenharmony_ci // paths without keys. 603cb93a386Sopenharmony_ci SkPath path; 604cb93a386Sopenharmony_ci args.fShape->asPath(&path); 605cb93a386Sopenharmony_ci if (path.countVerbs() > fMaxVerbCount) { 606cb93a386Sopenharmony_ci return CanDrawPath::kNo; 607cb93a386Sopenharmony_ci } 608cb93a386Sopenharmony_ci break; 609cb93a386Sopenharmony_ci } 610cb93a386Sopenharmony_ci return CanDrawPath::kYes; 611cb93a386Sopenharmony_ci} 612cb93a386Sopenharmony_ci 613cb93a386Sopenharmony_cibool TriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) { 614cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 615cb93a386Sopenharmony_ci "GrTriangulatingPathRenderer::onDrawPath"); 616cb93a386Sopenharmony_ci 617cb93a386Sopenharmony_ci GrOp::Owner op = TriangulatingPathOp::Make( 618cb93a386Sopenharmony_ci args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, 619cb93a386Sopenharmony_ci *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings); 620cb93a386Sopenharmony_ci args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op)); 621cb93a386Sopenharmony_ci return true; 622cb93a386Sopenharmony_ci} 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_ci} // namespace skgpu::v1 625