1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2019 Google LLC. 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/TessellationPathRenderer.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/private/SkVx.h" 11cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrVx.h" 16cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDisableColorXP.h" 17cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 18cb93a386Sopenharmony_ci#include "src/gpu/ops/PathInnerTriangulateOp.h" 19cb93a386Sopenharmony_ci#include "src/gpu/ops/PathStencilCoverOp.h" 20cb93a386Sopenharmony_ci#include "src/gpu/ops/PathTessellateOp.h" 21cb93a386Sopenharmony_ci#include "src/gpu/ops/StrokeTessellateOp.h" 22cb93a386Sopenharmony_ci#include "src/gpu/tessellate/Tessellation.h" 23cb93a386Sopenharmony_ci#include "src/gpu/tessellate/WangsFormula.h" 24cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_cinamespace { 27cb93a386Sopenharmony_ci 28cb93a386Sopenharmony_ciGrOp::Owner make_non_convex_fill_op(GrRecordingContext* rContext, 29cb93a386Sopenharmony_ci SkArenaAlloc* arena, 30cb93a386Sopenharmony_ci skgpu::v1::FillPathFlags fillPathFlags, 31cb93a386Sopenharmony_ci GrAAType aaType, 32cb93a386Sopenharmony_ci const SkRect& drawBounds, 33cb93a386Sopenharmony_ci const SkMatrix& viewMatrix, 34cb93a386Sopenharmony_ci const SkPath& path, 35cb93a386Sopenharmony_ci GrPaint&& paint) { 36cb93a386Sopenharmony_ci SkASSERT(!path.isConvex() || path.isInverseFillType()); 37cb93a386Sopenharmony_ci int numVerbs = path.countVerbs(); 38cb93a386Sopenharmony_ci if (numVerbs > 0 && !path.isInverseFillType()) { 39cb93a386Sopenharmony_ci // Check if the path is large and/or simple enough that we can triangulate the inner fan 40cb93a386Sopenharmony_ci // on the CPU. This is our fastest approach. It allows us to stencil only the curves, 41cb93a386Sopenharmony_ci // and then fill the inner fan directly to the final render target, thus drawing the 42cb93a386Sopenharmony_ci // majority of pixels in a single render pass. 43cb93a386Sopenharmony_ci float gpuFragmentWork = drawBounds.height() * drawBounds.width(); 44cb93a386Sopenharmony_ci float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N. 45cb93a386Sopenharmony_ci constexpr static float kCpuWeight = 512; 46cb93a386Sopenharmony_ci constexpr static float kMinNumPixelsToTriangulate = 256 * 256; 47cb93a386Sopenharmony_ci if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) { 48cb93a386Sopenharmony_ci return GrOp::Make<skgpu::v1::PathInnerTriangulateOp>(rContext, 49cb93a386Sopenharmony_ci viewMatrix, 50cb93a386Sopenharmony_ci path, 51cb93a386Sopenharmony_ci std::move(paint), 52cb93a386Sopenharmony_ci aaType, 53cb93a386Sopenharmony_ci fillPathFlags, 54cb93a386Sopenharmony_ci drawBounds); 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci return GrOp::Make<skgpu::v1::PathStencilCoverOp>(rContext, 58cb93a386Sopenharmony_ci arena, 59cb93a386Sopenharmony_ci viewMatrix, 60cb93a386Sopenharmony_ci path, 61cb93a386Sopenharmony_ci std::move(paint), 62cb93a386Sopenharmony_ci aaType, 63cb93a386Sopenharmony_ci fillPathFlags, 64cb93a386Sopenharmony_ci drawBounds); 65cb93a386Sopenharmony_ci} 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci} // anonymous namespace 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_cinamespace skgpu::v1 { 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_cibool TessellationPathRenderer::IsSupported(const GrCaps& caps) { 72cb93a386Sopenharmony_ci return !caps.avoidStencilBuffers() && 73cb93a386Sopenharmony_ci caps.drawInstancedSupport() && 74cb93a386Sopenharmony_ci !caps.disableTessellationPathRenderer(); 75cb93a386Sopenharmony_ci} 76cb93a386Sopenharmony_ci 77cb93a386Sopenharmony_ciPathRenderer::StencilSupport TessellationPathRenderer::onGetStencilSupport( 78cb93a386Sopenharmony_ci const GrStyledShape& shape) const { 79cb93a386Sopenharmony_ci if (!shape.style().isSimpleFill() || shape.inverseFilled()) { 80cb93a386Sopenharmony_ci // Don't bother with stroke stencilling or inverse fills yet. The Skia API doesn't support 81cb93a386Sopenharmony_ci // clipping by a stroke, and the stencilling code already knows how to invert a fill. 82cb93a386Sopenharmony_ci return kNoSupport_StencilSupport; 83cb93a386Sopenharmony_ci } 84cb93a386Sopenharmony_ci return shape.knownToBeConvex() ? kNoRestriction_StencilSupport : kStencilOnly_StencilSupport; 85cb93a386Sopenharmony_ci} 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ciPathRenderer::CanDrawPath TessellationPathRenderer::onCanDrawPath( 88cb93a386Sopenharmony_ci const CanDrawPathArgs& args) const { 89cb93a386Sopenharmony_ci const GrStyledShape& shape = *args.fShape; 90cb93a386Sopenharmony_ci if (args.fAAType == GrAAType::kCoverage || 91cb93a386Sopenharmony_ci shape.style().hasPathEffect() || 92cb93a386Sopenharmony_ci args.fViewMatrix->hasPerspective() || 93cb93a386Sopenharmony_ci shape.style().strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style || 94cb93a386Sopenharmony_ci !args.fProxy->canUseStencil(*args.fCaps)) { 95cb93a386Sopenharmony_ci return CanDrawPath::kNo; 96cb93a386Sopenharmony_ci } 97cb93a386Sopenharmony_ci if (!shape.style().isSimpleFill()) { 98cb93a386Sopenharmony_ci if (shape.inverseFilled()) { 99cb93a386Sopenharmony_ci return CanDrawPath::kNo; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci } 102cb93a386Sopenharmony_ci if (args.fHasUserStencilSettings) { 103cb93a386Sopenharmony_ci // Non-convex paths and strokes use the stencil buffer internally, so they can't support 104cb93a386Sopenharmony_ci // draws with stencil settings. 105cb93a386Sopenharmony_ci if (!shape.style().isSimpleFill() || !shape.knownToBeConvex() || shape.inverseFilled()) { 106cb93a386Sopenharmony_ci return CanDrawPath::kNo; 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci } 109cb93a386Sopenharmony_ci return CanDrawPath::kYes; 110cb93a386Sopenharmony_ci} 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_cibool TessellationPathRenderer::onDrawPath(const DrawPathArgs& args) { 113cb93a386Sopenharmony_ci auto sdc = args.fSurfaceDrawContext; 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ci SkPath path; 116cb93a386Sopenharmony_ci args.fShape->asPath(&path); 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci const SkRect pathDevBounds = args.fViewMatrix->mapRect(args.fShape->bounds()); 119cb93a386Sopenharmony_ci float n = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision, 120cb93a386Sopenharmony_ci pathDevBounds.width(), 121cb93a386Sopenharmony_ci pathDevBounds.height()); 122cb93a386Sopenharmony_ci if (n > pow4(kMaxTessellationSegmentsPerCurve)) { 123cb93a386Sopenharmony_ci // The path is extremely large. Pre-chop its curves to keep the number of tessellation 124cb93a386Sopenharmony_ci // segments tractable. This will also flatten curves that fall completely outside the 125cb93a386Sopenharmony_ci // viewport. 126cb93a386Sopenharmony_ci SkRect viewport = SkRect::Make(*args.fClipConservativeBounds); 127cb93a386Sopenharmony_ci if (!args.fShape->style().isSimpleFill()) { 128cb93a386Sopenharmony_ci // Outset the viewport to pad for the stroke width. 129cb93a386Sopenharmony_ci const SkStrokeRec& stroke = args.fShape->style().strokeRec(); 130cb93a386Sopenharmony_ci float inflationRadius; 131cb93a386Sopenharmony_ci if (stroke.isHairlineStyle()) { 132cb93a386Sopenharmony_ci // SkStrokeRec::getInflationRadius() doesn't handle hairlines robustly. Instead 133cb93a386Sopenharmony_ci // find the inflation of an equivalent stroke in device space with a width of 1. 134cb93a386Sopenharmony_ci inflationRadius = SkStrokeRec::GetInflationRadius(stroke.getJoin(), 135cb93a386Sopenharmony_ci stroke.getMiter(), 136cb93a386Sopenharmony_ci stroke.getCap(), 1); 137cb93a386Sopenharmony_ci } else { 138cb93a386Sopenharmony_ci inflationRadius = stroke.getInflationRadius() * args.fViewMatrix->getMaxScale(); 139cb93a386Sopenharmony_ci } 140cb93a386Sopenharmony_ci viewport.outset(inflationRadius, inflationRadius); 141cb93a386Sopenharmony_ci } 142cb93a386Sopenharmony_ci path = PreChopPathCurves(path, *args.fViewMatrix, viewport); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci // Handle strokes first. 146cb93a386Sopenharmony_ci if (!args.fShape->style().isSimpleFill()) { 147cb93a386Sopenharmony_ci SkASSERT(!path.isInverseFillType()); // See onGetStencilSupport(). 148cb93a386Sopenharmony_ci SkASSERT(args.fUserStencilSettings->isUnused()); 149cb93a386Sopenharmony_ci const SkStrokeRec& stroke = args.fShape->style().strokeRec(); 150cb93a386Sopenharmony_ci SkASSERT(stroke.getStyle() != SkStrokeRec::kStrokeAndFill_Style); 151cb93a386Sopenharmony_ci auto op = GrOp::Make<StrokeTessellateOp>(args.fContext, args.fAAType, *args.fViewMatrix, 152cb93a386Sopenharmony_ci path, stroke, std::move(args.fPaint)); 153cb93a386Sopenharmony_ci sdc->addDrawOp(args.fClip, std::move(op)); 154cb93a386Sopenharmony_ci return true; 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci 157cb93a386Sopenharmony_ci // Handle empty paths. 158cb93a386Sopenharmony_ci if (pathDevBounds.isEmpty()) { 159cb93a386Sopenharmony_ci if (path.isInverseFillType()) { 160cb93a386Sopenharmony_ci args.fSurfaceDrawContext->drawPaint(args.fClip, std::move(args.fPaint), 161cb93a386Sopenharmony_ci *args.fViewMatrix); 162cb93a386Sopenharmony_ci } 163cb93a386Sopenharmony_ci return true; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci // Handle convex paths. 167cb93a386Sopenharmony_ci if (args.fShape->knownToBeConvex() && !path.isInverseFillType()) { 168cb93a386Sopenharmony_ci auto op = GrOp::Make<PathTessellateOp>(args.fContext, 169cb93a386Sopenharmony_ci args.fSurfaceDrawContext->arenaAlloc(), 170cb93a386Sopenharmony_ci args.fAAType, 171cb93a386Sopenharmony_ci args.fUserStencilSettings, 172cb93a386Sopenharmony_ci *args.fViewMatrix, 173cb93a386Sopenharmony_ci path, 174cb93a386Sopenharmony_ci std::move(args.fPaint), 175cb93a386Sopenharmony_ci pathDevBounds); 176cb93a386Sopenharmony_ci sdc->addDrawOp(args.fClip, std::move(op)); 177cb93a386Sopenharmony_ci return true; 178cb93a386Sopenharmony_ci } 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ci SkASSERT(args.fUserStencilSettings->isUnused()); // See onGetStencilSupport(). 181cb93a386Sopenharmony_ci const SkRect& drawBounds = path.isInverseFillType() 182cb93a386Sopenharmony_ci ? args.fSurfaceDrawContext->asSurfaceProxy()->backingStoreBoundsRect() 183cb93a386Sopenharmony_ci : pathDevBounds; 184cb93a386Sopenharmony_ci auto op = make_non_convex_fill_op(args.fContext, 185cb93a386Sopenharmony_ci args.fSurfaceDrawContext->arenaAlloc(), 186cb93a386Sopenharmony_ci FillPathFlags::kNone, 187cb93a386Sopenharmony_ci args.fAAType, 188cb93a386Sopenharmony_ci drawBounds, 189cb93a386Sopenharmony_ci *args.fViewMatrix, 190cb93a386Sopenharmony_ci path, 191cb93a386Sopenharmony_ci std::move(args.fPaint)); 192cb93a386Sopenharmony_ci sdc->addDrawOp(args.fClip, std::move(op)); 193cb93a386Sopenharmony_ci return true; 194cb93a386Sopenharmony_ci} 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_civoid TessellationPathRenderer::onStencilPath(const StencilPathArgs& args) { 197cb93a386Sopenharmony_ci SkASSERT(args.fShape->style().isSimpleFill()); // See onGetStencilSupport(). 198cb93a386Sopenharmony_ci SkASSERT(!args.fShape->inverseFilled()); // See onGetStencilSupport(). 199cb93a386Sopenharmony_ci 200cb93a386Sopenharmony_ci auto sdc = args.fSurfaceDrawContext; 201cb93a386Sopenharmony_ci GrAAType aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone; 202cb93a386Sopenharmony_ci 203cb93a386Sopenharmony_ci SkRect pathDevBounds; 204cb93a386Sopenharmony_ci args.fViewMatrix->mapRect(&pathDevBounds, args.fShape->bounds()); 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci SkPath path; 207cb93a386Sopenharmony_ci args.fShape->asPath(&path); 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci float n = wangs_formula::worst_case_cubic_pow4(kTessellationPrecision, 210cb93a386Sopenharmony_ci pathDevBounds.width(), 211cb93a386Sopenharmony_ci pathDevBounds.height()); 212cb93a386Sopenharmony_ci if (n > pow4(kMaxTessellationSegmentsPerCurve)) { 213cb93a386Sopenharmony_ci SkRect viewport = SkRect::Make(*args.fClipConservativeBounds); 214cb93a386Sopenharmony_ci path = PreChopPathCurves(path, *args.fViewMatrix, viewport); 215cb93a386Sopenharmony_ci } 216cb93a386Sopenharmony_ci 217cb93a386Sopenharmony_ci if (args.fShape->knownToBeConvex()) { 218cb93a386Sopenharmony_ci constexpr static GrUserStencilSettings kMarkStencil( 219cb93a386Sopenharmony_ci GrUserStencilSettings::StaticInit< 220cb93a386Sopenharmony_ci 0x0001, 221cb93a386Sopenharmony_ci GrUserStencilTest::kAlways, 222cb93a386Sopenharmony_ci 0xffff, 223cb93a386Sopenharmony_ci GrUserStencilOp::kReplace, 224cb93a386Sopenharmony_ci GrUserStencilOp::kKeep, 225cb93a386Sopenharmony_ci 0xffff>()); 226cb93a386Sopenharmony_ci 227cb93a386Sopenharmony_ci GrPaint stencilPaint; 228cb93a386Sopenharmony_ci stencilPaint.setXPFactory(GrDisableColorXPFactory::Get()); 229cb93a386Sopenharmony_ci auto op = GrOp::Make<PathTessellateOp>(args.fContext, 230cb93a386Sopenharmony_ci args.fSurfaceDrawContext->arenaAlloc(), 231cb93a386Sopenharmony_ci aaType, 232cb93a386Sopenharmony_ci &kMarkStencil, 233cb93a386Sopenharmony_ci *args.fViewMatrix, 234cb93a386Sopenharmony_ci path, 235cb93a386Sopenharmony_ci std::move(stencilPaint), 236cb93a386Sopenharmony_ci pathDevBounds); 237cb93a386Sopenharmony_ci sdc->addDrawOp(args.fClip, std::move(op)); 238cb93a386Sopenharmony_ci return; 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci 241cb93a386Sopenharmony_ci auto op = make_non_convex_fill_op(args.fContext, 242cb93a386Sopenharmony_ci args.fSurfaceDrawContext->arenaAlloc(), 243cb93a386Sopenharmony_ci FillPathFlags::kStencilOnly, 244cb93a386Sopenharmony_ci aaType, 245cb93a386Sopenharmony_ci pathDevBounds, 246cb93a386Sopenharmony_ci *args.fViewMatrix, 247cb93a386Sopenharmony_ci path, 248cb93a386Sopenharmony_ci GrPaint()); 249cb93a386Sopenharmony_ci sdc->addDrawOp(args.fClip, std::move(op)); 250cb93a386Sopenharmony_ci} 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci} // namespace skgpu::v1 253