1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "include/private/GrRecordingContext.h" 9 #include "src/gpu/GrCaps.h" 10 #include "src/gpu/GrFixedClip.h" 11 #include "src/gpu/GrGpu.h" 12 #include "src/gpu/GrPath.h" 13 #include "src/gpu/GrRenderTargetContextPriv.h" 14 #include "src/gpu/GrResourceProvider.h" 15 #include "src/gpu/GrStencilClip.h" 16 #include "src/gpu/GrStyle.h" 17 #include "src/gpu/geometry/GrShape.h" 18 #include "src/gpu/ops/GrDrawPathOp.h" 19 #include "src/gpu/ops/GrStencilAndCoverPathRenderer.h" 20 #include "src/gpu/ops/GrStencilPathOp.h" 21 Create(GrResourceProvider * resourceProvider,const GrCaps & caps)22 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, 23 const GrCaps& caps) { 24 if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) { 25 return new GrStencilAndCoverPathRenderer(resourceProvider); 26 } else { 27 return nullptr; 28 } 29 } 30 GrStencilAndCoverPathRenderer(GrResourceProvider * resourceProvider)31 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider) 32 : fResourceProvider(resourceProvider) { 33 } 34 35 GrPathRenderer::CanDrawPath onCanDrawPath(const CanDrawPathArgs & args) const36 GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 37 SkASSERT(!args.fTargetIsWrappedVkSecondaryCB); 38 // GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline 39 // path. 40 if (args.fShape->style().strokeRec().isHairlineStyle() || 41 args.fShape->style().hasNonDashPathEffect() || 42 args.fHasUserStencilSettings) { 43 return CanDrawPath::kNo; 44 } 45 if (GrAAType::kCoverage == args.fAAType && !args.fProxy->canUseMixedSamples(*args.fCaps)) { 46 // We rely on a mixed sampled stencil buffer to implement coverage AA. 47 return CanDrawPath::kNo; 48 } 49 return CanDrawPath::kYes; 50 } 51 get_gr_path(GrResourceProvider * resourceProvider,const GrShape & shape)52 static sk_sp<GrPath> get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) { 53 GrUniqueKey key; 54 bool isVolatile; 55 GrPath::ComputeKey(shape, &key, &isVolatile); 56 sk_sp<GrPath> path; 57 if (!isVolatile) { 58 path = resourceProvider->findByUniqueKey<GrPath>(key); 59 } 60 if (!path) { 61 SkPath skPath; 62 shape.asPath(&skPath); 63 path = resourceProvider->createPath(skPath, shape.style()); 64 if (!isVolatile) { 65 resourceProvider->assignUniqueKeyToResource(key, path.get()); 66 } 67 } else { 68 #ifdef SK_DEBUG 69 SkPath skPath; 70 shape.asPath(&skPath); 71 SkASSERT(path->isEqualTo(skPath, shape.style())); 72 #endif 73 } 74 return path; 75 } 76 onStencilPath(const StencilPathArgs & args)77 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { 78 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 79 "GrStencilAndCoverPathRenderer::onStencilPath"); 80 sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape)); 81 args.fRenderTargetContext->priv().stencilPath( 82 *args.fClip, args.fDoStencilMSAA, *args.fViewMatrix, p.get()); 83 } 84 onDrawPath(const DrawPathArgs & args)85 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { 86 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 87 "GrStencilAndCoverPathRenderer::onDrawPath"); 88 SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle()); 89 90 const SkMatrix& viewMatrix = *args.fViewMatrix; 91 92 bool doStencilMSAA = GrAAType::kNone != args.fAAType; 93 94 sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape)); 95 96 if (args.fShape->inverseFilled()) { 97 SkMatrix vmi; 98 if (!viewMatrix.invert(&vmi)) { 99 return true; 100 } 101 102 SkRect devBounds = SkRect::MakeIWH(args.fRenderTargetContext->width(), 103 args.fRenderTargetContext->height()); // Inverse fill. 104 105 // fake inverse with a stencil and cover 106 GrAppliedClip appliedClip; 107 if (!args.fClip->apply( 108 args.fContext, args.fRenderTargetContext, doStencilMSAA, true, &appliedClip, 109 &devBounds)) { 110 return true; 111 } 112 GrStencilClip stencilClip(appliedClip.stencilStackID()); 113 if (appliedClip.scissorState().enabled()) { 114 stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect()); 115 } 116 if (appliedClip.windowRectsState().enabled()) { 117 stencilClip.fixedClip().setWindowRectangles(appliedClip.windowRectsState().windows(), 118 appliedClip.windowRectsState().mode()); 119 } 120 // Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the 121 // final draw and it is meaningless to multiply by coverage when drawing to stencil. 122 args.fRenderTargetContext->priv().stencilPath( 123 stencilClip, GrAA(doStencilMSAA), viewMatrix, path.get()); 124 125 { 126 static constexpr GrUserStencilSettings kInvertedCoverPass( 127 GrUserStencilSettings::StaticInit< 128 0x0000, 129 // We know our rect will hit pixels outside the clip and the user bits will 130 // be 0 outside the clip. So we can't just fill where the user bits are 0. We 131 // also need to check that the clip bit is set. 132 GrUserStencilTest::kEqualIfInClip, 133 0xffff, 134 GrUserStencilOp::kKeep, 135 GrUserStencilOp::kZero, 136 0xffff>() 137 ); 138 139 SkRect coverBounds; 140 // mapRect through persp matrix may not be correct 141 if (!viewMatrix.hasPerspective()) { 142 vmi.mapRect(&coverBounds, devBounds); 143 // theoretically could set bloat = 0, instead leave it because of matrix inversion 144 // precision. 145 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; 146 coverBounds.outset(bloat, bloat); 147 } else { 148 coverBounds = devBounds; 149 } 150 const SkMatrix& coverMatrix = !viewMatrix.hasPerspective() ? viewMatrix : SkMatrix::I(); 151 const SkMatrix& localMatrix = !viewMatrix.hasPerspective() ? SkMatrix::I() : vmi; 152 153 // We have to suppress enabling MSAA for mixed samples or we will get seams due to 154 // coverage modulation along the edge where two triangles making up the rect meet. 155 GrAA doStencilMSAA = GrAA::kNo; 156 if (GrAAType::kMSAA == args.fAAType) { 157 doStencilMSAA = GrAA::kYes; 158 } 159 args.fRenderTargetContext->priv().stencilRect( 160 *args.fClip, &kInvertedCoverPass, std::move(args.fPaint), doStencilMSAA, 161 coverMatrix, coverBounds, &localMatrix); 162 } 163 } else { 164 std::unique_ptr<GrDrawOp> op = GrDrawPathOp::Make( 165 args.fContext, viewMatrix, std::move(args.fPaint), GrAA(doStencilMSAA), path.get()); 166 args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); 167 } 168 169 return true; 170 } 171