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/AALinearizingConvexPathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkString.h" 11cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h" 12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 13cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h" 14cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h" 17cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h" 18cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h" 19cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h" 20cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h" 21cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h" 22cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h" 23cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 24cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrAAConvexTessellator.h" 25cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h" 26cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 27cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h" 28cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h" 29cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 32cb93a386Sopenharmony_cinamespace skgpu::v1 { 33cb93a386Sopenharmony_ci 34cb93a386Sopenharmony_cinamespace { 35cb93a386Sopenharmony_ci 36cb93a386Sopenharmony_cistatic const int DEFAULT_BUFFER_SIZE = 100; 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For 39cb93a386Sopenharmony_ci// the time being, we simply drop back to software rendering above this stroke width. 40cb93a386Sopenharmony_cistatic const SkScalar kMaxStrokeWidth = 20.0; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci// extract the result vertices and indices from the GrAAConvexTessellator 43cb93a386Sopenharmony_civoid extract_verts(const GrAAConvexTessellator& tess, 44cb93a386Sopenharmony_ci const SkMatrix* localCoordsMatrix, 45cb93a386Sopenharmony_ci void* vertData, 46cb93a386Sopenharmony_ci const GrVertexColor& color, 47cb93a386Sopenharmony_ci uint16_t firstIndex, 48cb93a386Sopenharmony_ci uint16_t* idxs) { 49cb93a386Sopenharmony_ci VertexWriter verts{vertData}; 50cb93a386Sopenharmony_ci for (int i = 0; i < tess.numPts(); ++i) { 51cb93a386Sopenharmony_ci SkPoint lc; 52cb93a386Sopenharmony_ci if (localCoordsMatrix) { 53cb93a386Sopenharmony_ci localCoordsMatrix->mapPoints(&lc, &tess.point(i), 1); 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci verts << tess.point(i) << color << VertexWriter::If(localCoordsMatrix, lc) 56cb93a386Sopenharmony_ci << tess.coverage(i); 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ci for (int i = 0; i < tess.numIndices(); ++i) { 60cb93a386Sopenharmony_ci idxs[i] = tess.index(i) + firstIndex; 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci} 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_ciGrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena, 65cb93a386Sopenharmony_ci bool tweakAlphaForCoverage, 66cb93a386Sopenharmony_ci bool usesLocalCoords, 67cb93a386Sopenharmony_ci bool wideColor) { 68cb93a386Sopenharmony_ci using namespace GrDefaultGeoProcFactory; 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci Coverage::Type coverageType = 71cb93a386Sopenharmony_ci tweakAlphaForCoverage ? Coverage::kAttributeTweakAlpha_Type : Coverage::kAttribute_Type; 72cb93a386Sopenharmony_ci LocalCoords::Type localCoordsType = 73cb93a386Sopenharmony_ci usesLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type; 74cb93a386Sopenharmony_ci Color::Type colorType = 75cb93a386Sopenharmony_ci wideColor ? Color::kPremulWideColorAttribute_Type : Color::kPremulGrColorAttribute_Type; 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ci return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I()); 78cb93a386Sopenharmony_ci} 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ciclass AAFlatteningConvexPathOp final : public GrMeshDrawOp { 81cb93a386Sopenharmony_ciprivate: 82cb93a386Sopenharmony_ci using Helper = GrSimpleMeshDrawOpHelperWithStencil; 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_cipublic: 85cb93a386Sopenharmony_ci DEFINE_OP_CLASS_ID 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ci static GrOp::Owner Make(GrRecordingContext* context, 88cb93a386Sopenharmony_ci GrPaint&& paint, 89cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 90cb93a386Sopenharmony_ci const SkPath& path, 91cb93a386Sopenharmony_ci SkScalar strokeWidth, 92cb93a386Sopenharmony_ci SkStrokeRec::Style style, 93cb93a386Sopenharmony_ci SkPaint::Join join, 94cb93a386Sopenharmony_ci SkScalar miterLimit, 95cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) { 96cb93a386Sopenharmony_ci return Helper::FactoryHelper<AAFlatteningConvexPathOp>(context, std::move(paint), 97cb93a386Sopenharmony_ci viewMatrix, path, 98cb93a386Sopenharmony_ci strokeWidth, style, join, miterLimit, 99cb93a386Sopenharmony_ci stencilSettings); 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci AAFlatteningConvexPathOp(GrProcessorSet* processorSet, 103cb93a386Sopenharmony_ci const SkPMColor4f& color, 104cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 105cb93a386Sopenharmony_ci const SkPath& path, 106cb93a386Sopenharmony_ci SkScalar strokeWidth, 107cb93a386Sopenharmony_ci SkStrokeRec::Style style, 108cb93a386Sopenharmony_ci SkPaint::Join join, 109cb93a386Sopenharmony_ci SkScalar miterLimit, 110cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings) 111cb93a386Sopenharmony_ci : INHERITED(ClassID()), fHelper(processorSet, GrAAType::kCoverage, stencilSettings) { 112cb93a386Sopenharmony_ci fPaths.emplace_back( 113cb93a386Sopenharmony_ci PathData{viewMatrix, path, color, strokeWidth, miterLimit, style, join}); 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci // compute bounds 116cb93a386Sopenharmony_ci SkRect bounds = path.getBounds(); 117cb93a386Sopenharmony_ci SkScalar w = strokeWidth; 118cb93a386Sopenharmony_ci if (w > 0) { 119cb93a386Sopenharmony_ci w /= 2; 120cb93a386Sopenharmony_ci SkScalar maxScale = viewMatrix.getMaxScale(); 121cb93a386Sopenharmony_ci // We should not have a perspective matrix, thus we should have a valid scale. 122cb93a386Sopenharmony_ci SkASSERT(maxScale != -1); 123cb93a386Sopenharmony_ci if (SkPaint::kMiter_Join == join && w * maxScale > 1.f) { 124cb93a386Sopenharmony_ci w *= miterLimit; 125cb93a386Sopenharmony_ci } 126cb93a386Sopenharmony_ci bounds.outset(w, w); 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsHairline::kNo); 129cb93a386Sopenharmony_ci } 130cb93a386Sopenharmony_ci 131cb93a386Sopenharmony_ci const char* name() const override { return "AAFlatteningConvexPathOp"; } 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci void visitProxies(const GrVisitProxyFunc& func) const override { 134cb93a386Sopenharmony_ci if (fProgramInfo) { 135cb93a386Sopenharmony_ci fProgramInfo->visitFPProxies(func); 136cb93a386Sopenharmony_ci } else { 137cb93a386Sopenharmony_ci fHelper.visitProxies(func); 138cb93a386Sopenharmony_ci } 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip, 144cb93a386Sopenharmony_ci GrClampType clampType) override { 145cb93a386Sopenharmony_ci return fHelper.finalizeProcessors(caps, clip, clampType, 146cb93a386Sopenharmony_ci GrProcessorAnalysisCoverage::kSingleChannel, 147cb93a386Sopenharmony_ci &fPaths.back().fColor, &fWideColor); 148cb93a386Sopenharmony_ci } 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_ciprivate: 151cb93a386Sopenharmony_ci GrProgramInfo* programInfo() override { return fProgramInfo; } 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci void onCreateProgramInfo(const GrCaps* caps, 154cb93a386Sopenharmony_ci SkArenaAlloc* arena, 155cb93a386Sopenharmony_ci const GrSurfaceProxyView& writeView, 156cb93a386Sopenharmony_ci bool usesMSAASurface, 157cb93a386Sopenharmony_ci GrAppliedClip&& appliedClip, 158cb93a386Sopenharmony_ci const GrDstProxyView& dstProxyView, 159cb93a386Sopenharmony_ci GrXferBarrierFlags renderPassXferBarriers, 160cb93a386Sopenharmony_ci GrLoadOp colorLoadOp) override { 161cb93a386Sopenharmony_ci GrGeometryProcessor* gp = create_lines_only_gp(arena, 162cb93a386Sopenharmony_ci fHelper.compatibleWithCoverageAsAlpha(), 163cb93a386Sopenharmony_ci fHelper.usesLocalCoords(), 164cb93a386Sopenharmony_ci fWideColor); 165cb93a386Sopenharmony_ci if (!gp) { 166cb93a386Sopenharmony_ci SkDebugf("Couldn't create a GrGeometryProcessor\n"); 167cb93a386Sopenharmony_ci return; 168cb93a386Sopenharmony_ci } 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_ci fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface, 171cb93a386Sopenharmony_ci std::move(appliedClip), dstProxyView, 172cb93a386Sopenharmony_ci gp, GrPrimitiveType::kTriangles, 173cb93a386Sopenharmony_ci renderPassXferBarriers, colorLoadOp); 174cb93a386Sopenharmony_ci } 175cb93a386Sopenharmony_ci 176cb93a386Sopenharmony_ci void recordDraw(GrMeshDrawTarget* target, 177cb93a386Sopenharmony_ci int vertexCount, size_t vertexStride, void* vertices, 178cb93a386Sopenharmony_ci int indexCount, uint16_t* indices) { 179cb93a386Sopenharmony_ci if (vertexCount == 0 || indexCount == 0) { 180cb93a386Sopenharmony_ci return; 181cb93a386Sopenharmony_ci } 182cb93a386Sopenharmony_ci sk_sp<const GrBuffer> vertexBuffer; 183cb93a386Sopenharmony_ci int firstVertex; 184cb93a386Sopenharmony_ci void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer, 185cb93a386Sopenharmony_ci &firstVertex); 186cb93a386Sopenharmony_ci if (!verts) { 187cb93a386Sopenharmony_ci SkDebugf("Could not allocate vertices\n"); 188cb93a386Sopenharmony_ci return; 189cb93a386Sopenharmony_ci } 190cb93a386Sopenharmony_ci memcpy(verts, vertices, vertexCount * vertexStride); 191cb93a386Sopenharmony_ci 192cb93a386Sopenharmony_ci sk_sp<const GrBuffer> indexBuffer; 193cb93a386Sopenharmony_ci int firstIndex; 194cb93a386Sopenharmony_ci uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex); 195cb93a386Sopenharmony_ci if (!idxs) { 196cb93a386Sopenharmony_ci SkDebugf("Could not allocate indices\n"); 197cb93a386Sopenharmony_ci return; 198cb93a386Sopenharmony_ci } 199cb93a386Sopenharmony_ci memcpy(idxs, indices, indexCount * sizeof(uint16_t)); 200cb93a386Sopenharmony_ci GrSimpleMesh* mesh = target->allocMesh(); 201cb93a386Sopenharmony_ci mesh->setIndexed(std::move(indexBuffer), indexCount, firstIndex, 0, vertexCount - 1, 202cb93a386Sopenharmony_ci GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex); 203cb93a386Sopenharmony_ci fMeshes.push_back(mesh); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci void onPrepareDraws(GrMeshDrawTarget* target) override { 207cb93a386Sopenharmony_ci if (!fProgramInfo) { 208cb93a386Sopenharmony_ci this->createProgramInfo(target); 209cb93a386Sopenharmony_ci if (!fProgramInfo) { 210cb93a386Sopenharmony_ci return; 211cb93a386Sopenharmony_ci } 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci size_t vertexStride = fProgramInfo->geomProc().vertexStride(); 215cb93a386Sopenharmony_ci int instanceCount = fPaths.count(); 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci int64_t vertexCount = 0; 218cb93a386Sopenharmony_ci int64_t indexCount = 0; 219cb93a386Sopenharmony_ci int64_t maxVertices = DEFAULT_BUFFER_SIZE; 220cb93a386Sopenharmony_ci int64_t maxIndices = DEFAULT_BUFFER_SIZE; 221cb93a386Sopenharmony_ci uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride); 222cb93a386Sopenharmony_ci uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t)); 223cb93a386Sopenharmony_ci for (int i = 0; i < instanceCount; i++) { 224cb93a386Sopenharmony_ci const PathData& args = fPaths[i]; 225cb93a386Sopenharmony_ci GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth, 226cb93a386Sopenharmony_ci args.fJoin, args.fMiterLimit); 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ci if (!tess.tessellate(args.fViewMatrix, args.fPath)) { 229cb93a386Sopenharmony_ci continue; 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci int currentVertices = tess.numPts(); 233cb93a386Sopenharmony_ci if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) { 234cb93a386Sopenharmony_ci // if we added the current instance, we would overflow the indices we can store in a 235cb93a386Sopenharmony_ci // uint16_t. Draw what we've got so far and reset. 236cb93a386Sopenharmony_ci this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices); 237cb93a386Sopenharmony_ci vertexCount = 0; 238cb93a386Sopenharmony_ci indexCount = 0; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci if (vertexCount + currentVertices > maxVertices) { 241cb93a386Sopenharmony_ci maxVertices = std::max(vertexCount + currentVertices, maxVertices * 2); 242cb93a386Sopenharmony_ci if (maxVertices * vertexStride > SK_MaxS32) { 243cb93a386Sopenharmony_ci sk_free(vertices); 244cb93a386Sopenharmony_ci sk_free(indices); 245cb93a386Sopenharmony_ci return; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride); 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci int currentIndices = tess.numIndices(); 250cb93a386Sopenharmony_ci if (indexCount + currentIndices > maxIndices) { 251cb93a386Sopenharmony_ci maxIndices = std::max(indexCount + currentIndices, maxIndices * 2); 252cb93a386Sopenharmony_ci if (maxIndices * sizeof(uint16_t) > SK_MaxS32) { 253cb93a386Sopenharmony_ci sk_free(vertices); 254cb93a386Sopenharmony_ci sk_free(indices); 255cb93a386Sopenharmony_ci return; 256cb93a386Sopenharmony_ci } 257cb93a386Sopenharmony_ci indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t)); 258cb93a386Sopenharmony_ci } 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci const SkMatrix* localCoordsMatrix = nullptr; 261cb93a386Sopenharmony_ci SkMatrix ivm; 262cb93a386Sopenharmony_ci if (fHelper.usesLocalCoords()) { 263cb93a386Sopenharmony_ci if (!args.fViewMatrix.invert(&ivm)) { 264cb93a386Sopenharmony_ci ivm = SkMatrix::I(); 265cb93a386Sopenharmony_ci } 266cb93a386Sopenharmony_ci localCoordsMatrix = &ivm; 267cb93a386Sopenharmony_ci } 268cb93a386Sopenharmony_ci 269cb93a386Sopenharmony_ci extract_verts(tess, localCoordsMatrix, vertices + vertexStride * vertexCount, 270cb93a386Sopenharmony_ci GrVertexColor(args.fColor, fWideColor), vertexCount, 271cb93a386Sopenharmony_ci indices + indexCount); 272cb93a386Sopenharmony_ci vertexCount += currentVertices; 273cb93a386Sopenharmony_ci indexCount += currentIndices; 274cb93a386Sopenharmony_ci } 275cb93a386Sopenharmony_ci if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) { 276cb93a386Sopenharmony_ci this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices); 277cb93a386Sopenharmony_ci } 278cb93a386Sopenharmony_ci sk_free(vertices); 279cb93a386Sopenharmony_ci sk_free(indices); 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override { 283cb93a386Sopenharmony_ci if (!fProgramInfo || fMeshes.isEmpty()) { 284cb93a386Sopenharmony_ci return; 285cb93a386Sopenharmony_ci } 286cb93a386Sopenharmony_ci 287cb93a386Sopenharmony_ci flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds); 288cb93a386Sopenharmony_ci flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline()); 289cb93a386Sopenharmony_ci for (int i = 0; i < fMeshes.count(); ++i) { 290cb93a386Sopenharmony_ci flushState->drawMesh(*fMeshes[i]); 291cb93a386Sopenharmony_ci } 292cb93a386Sopenharmony_ci } 293cb93a386Sopenharmony_ci 294cb93a386Sopenharmony_ci CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override { 295cb93a386Sopenharmony_ci AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>(); 296cb93a386Sopenharmony_ci if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 297cb93a386Sopenharmony_ci return CombineResult::kCannotCombine; 298cb93a386Sopenharmony_ci } 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin()); 301cb93a386Sopenharmony_ci fWideColor |= that->fWideColor; 302cb93a386Sopenharmony_ci return CombineResult::kMerged; 303cb93a386Sopenharmony_ci } 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci#if GR_TEST_UTILS 306cb93a386Sopenharmony_ci SkString onDumpInfo() const override { 307cb93a386Sopenharmony_ci SkString string; 308cb93a386Sopenharmony_ci for (const auto& path : fPaths) { 309cb93a386Sopenharmony_ci string.appendf( 310cb93a386Sopenharmony_ci "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, " 311cb93a386Sopenharmony_ci "MiterLimit: %.2f\n", 312cb93a386Sopenharmony_ci path.fColor.toBytes_RGBA(), path.fStrokeWidth, path.fStyle, path.fJoin, 313cb93a386Sopenharmony_ci path.fMiterLimit); 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci string += fHelper.dumpInfo(); 316cb93a386Sopenharmony_ci return string; 317cb93a386Sopenharmony_ci } 318cb93a386Sopenharmony_ci#endif 319cb93a386Sopenharmony_ci 320cb93a386Sopenharmony_ci struct PathData { 321cb93a386Sopenharmony_ci SkMatrix fViewMatrix; 322cb93a386Sopenharmony_ci SkPath fPath; 323cb93a386Sopenharmony_ci SkPMColor4f fColor; 324cb93a386Sopenharmony_ci SkScalar fStrokeWidth; 325cb93a386Sopenharmony_ci SkScalar fMiterLimit; 326cb93a386Sopenharmony_ci SkStrokeRec::Style fStyle; 327cb93a386Sopenharmony_ci SkPaint::Join fJoin; 328cb93a386Sopenharmony_ci }; 329cb93a386Sopenharmony_ci 330cb93a386Sopenharmony_ci SkSTArray<1, PathData, true> fPaths; 331cb93a386Sopenharmony_ci Helper fHelper; 332cb93a386Sopenharmony_ci bool fWideColor; 333cb93a386Sopenharmony_ci 334cb93a386Sopenharmony_ci SkTDArray<GrSimpleMesh*> fMeshes; 335cb93a386Sopenharmony_ci GrProgramInfo* fProgramInfo = nullptr; 336cb93a386Sopenharmony_ci 337cb93a386Sopenharmony_ci using INHERITED = GrMeshDrawOp; 338cb93a386Sopenharmony_ci}; 339cb93a386Sopenharmony_ci 340cb93a386Sopenharmony_ci} // anonymous namespace 341cb93a386Sopenharmony_ci 342cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////////////////////////// 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ciPathRenderer::CanDrawPath 345cb93a386Sopenharmony_ciAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 346cb93a386Sopenharmony_ci if (GrAAType::kCoverage != args.fAAType) { 347cb93a386Sopenharmony_ci return CanDrawPath::kNo; 348cb93a386Sopenharmony_ci } 349cb93a386Sopenharmony_ci if (!args.fShape->knownToBeConvex()) { 350cb93a386Sopenharmony_ci return CanDrawPath::kNo; 351cb93a386Sopenharmony_ci } 352cb93a386Sopenharmony_ci if (args.fShape->style().pathEffect()) { 353cb93a386Sopenharmony_ci return CanDrawPath::kNo; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci if (args.fShape->inverseFilled()) { 356cb93a386Sopenharmony_ci return CanDrawPath::kNo; 357cb93a386Sopenharmony_ci } 358cb93a386Sopenharmony_ci if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) { 359cb93a386Sopenharmony_ci // Stroked zero length lines should draw, but this PR doesn't handle that case 360cb93a386Sopenharmony_ci return CanDrawPath::kNo; 361cb93a386Sopenharmony_ci } 362cb93a386Sopenharmony_ci const SkStrokeRec& stroke = args.fShape->style().strokeRec(); 363cb93a386Sopenharmony_ci 364cb93a386Sopenharmony_ci if (stroke.getStyle() == SkStrokeRec::kStroke_Style || 365cb93a386Sopenharmony_ci stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) { 366cb93a386Sopenharmony_ci if (!args.fViewMatrix->isSimilarity()) { 367cb93a386Sopenharmony_ci return CanDrawPath::kNo; 368cb93a386Sopenharmony_ci } 369cb93a386Sopenharmony_ci SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth(); 370cb93a386Sopenharmony_ci if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) { 371cb93a386Sopenharmony_ci return CanDrawPath::kNo; 372cb93a386Sopenharmony_ci } 373cb93a386Sopenharmony_ci if (strokeWidth > kMaxStrokeWidth || 374cb93a386Sopenharmony_ci !args.fShape->knownToBeClosed() || 375cb93a386Sopenharmony_ci stroke.getJoin() == SkPaint::Join::kRound_Join) { 376cb93a386Sopenharmony_ci return CanDrawPath::kNo; 377cb93a386Sopenharmony_ci } 378cb93a386Sopenharmony_ci return CanDrawPath::kYes; 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci if (stroke.getStyle() != SkStrokeRec::kFill_Style) { 381cb93a386Sopenharmony_ci return CanDrawPath::kNo; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci // This can almost handle perspective. It would need to use 3 component explicit local coords 384cb93a386Sopenharmony_ci // when there are FPs that require them. This is difficult to test because AAConvexPathRenderer 385cb93a386Sopenharmony_ci // takes almost all filled paths that could get here. So just avoid perspective fills. 386cb93a386Sopenharmony_ci if (args.fViewMatrix->hasPerspective()) { 387cb93a386Sopenharmony_ci return CanDrawPath::kNo; 388cb93a386Sopenharmony_ci } 389cb93a386Sopenharmony_ci return CanDrawPath::kYes; 390cb93a386Sopenharmony_ci} 391cb93a386Sopenharmony_ci 392cb93a386Sopenharmony_cibool AALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { 393cb93a386Sopenharmony_ci GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(), 394cb93a386Sopenharmony_ci "AALinearizingConvexPathRenderer::onDrawPath"); 395cb93a386Sopenharmony_ci SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1); 396cb93a386Sopenharmony_ci SkASSERT(!args.fShape->isEmpty()); 397cb93a386Sopenharmony_ci SkASSERT(!args.fShape->style().pathEffect()); 398cb93a386Sopenharmony_ci 399cb93a386Sopenharmony_ci SkPath path; 400cb93a386Sopenharmony_ci args.fShape->asPath(&path); 401cb93a386Sopenharmony_ci bool fill = args.fShape->style().isSimpleFill(); 402cb93a386Sopenharmony_ci const SkStrokeRec& stroke = args.fShape->style().strokeRec(); 403cb93a386Sopenharmony_ci SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth(); 404cb93a386Sopenharmony_ci SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin(); 405cb93a386Sopenharmony_ci SkScalar miterLimit = stroke.getMiter(); 406cb93a386Sopenharmony_ci 407cb93a386Sopenharmony_ci GrOp::Owner op = AAFlatteningConvexPathOp::Make( 408cb93a386Sopenharmony_ci args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth, 409cb93a386Sopenharmony_ci stroke.getStyle(), join, miterLimit, args.fUserStencilSettings); 410cb93a386Sopenharmony_ci args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op)); 411cb93a386Sopenharmony_ci return true; 412cb93a386Sopenharmony_ci} 413cb93a386Sopenharmony_ci 414cb93a386Sopenharmony_ci} // namespace skgpu::v1 415cb93a386Sopenharmony_ci 416cb93a386Sopenharmony_ci#if GR_TEST_UTILS 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) { 419cb93a386Sopenharmony_ci SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random); 420cb93a386Sopenharmony_ci const SkPath& path = GrTest::TestPathConvex(random); 421cb93a386Sopenharmony_ci 422cb93a386Sopenharmony_ci SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style, 423cb93a386Sopenharmony_ci SkStrokeRec::kStroke_Style, 424cb93a386Sopenharmony_ci SkStrokeRec::kStrokeAndFill_Style }; 425cb93a386Sopenharmony_ci 426cb93a386Sopenharmony_ci SkStrokeRec::Style style = styles[random->nextU() % 3]; 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci SkScalar strokeWidth = -1.f; 429cb93a386Sopenharmony_ci SkPaint::Join join = SkPaint::kMiter_Join; 430cb93a386Sopenharmony_ci SkScalar miterLimit = 0.5f; 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci if (SkStrokeRec::kFill_Style != style) { 433cb93a386Sopenharmony_ci strokeWidth = random->nextRangeF(1.0f, 10.0f); 434cb93a386Sopenharmony_ci if (random->nextBool()) { 435cb93a386Sopenharmony_ci join = SkPaint::kMiter_Join; 436cb93a386Sopenharmony_ci } else { 437cb93a386Sopenharmony_ci join = SkPaint::kBevel_Join; 438cb93a386Sopenharmony_ci } 439cb93a386Sopenharmony_ci miterLimit = random->nextRangeF(0.5f, 2.0f); 440cb93a386Sopenharmony_ci } 441cb93a386Sopenharmony_ci const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context); 442cb93a386Sopenharmony_ci return skgpu::v1::AAFlatteningConvexPathOp::Make(context, std::move(paint), viewMatrix, path, 443cb93a386Sopenharmony_ci strokeWidth, style, join, miterLimit, 444cb93a386Sopenharmony_ci stencilSettings); 445cb93a386Sopenharmony_ci} 446cb93a386Sopenharmony_ci 447cb93a386Sopenharmony_ci#endif 448