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