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 "GrContext.h" 11 #include "GrDrawPathOp.h" 12 #include "GrFixedClip.h" 13 #include "GrGpu.h" 14 #include "GrPath.h" 15 #include "GrRenderTargetContextPriv.h" 16 #include "GrResourceProvider.h" 17 #include "GrStencilPathOp.h" 18 #include "GrStyle.h" 19 #include "ops/GrRectOpFactory.h" 20 21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, 22 const GrCaps& caps) { 23 if (caps.shaderCaps()->pathRenderingSupport() && !caps.avoidStencilBuffers()) { 24 return new GrStencilAndCoverPathRenderer(resourceProvider); 25 } else { 26 return nullptr; 27 } 28 } 29 30 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider) 31 : fResourceProvider(resourceProvider) { 32 } 33 34 bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { 35 // GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline 36 // path. 37 if (args.fShape->style().strokeRec().isHairlineStyle() || 38 args.fShape->style().hasNonDashPathEffect()) { 39 return false; 40 } 41 if (args.fHasUserStencilSettings) { 42 return false; 43 } 44 // doesn't do per-path AA, relies on the target having MSAA. 45 return (GrAAType::kCoverage != args.fAAType); 46 } 47 48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) { 49 GrUniqueKey key; 50 bool isVolatile; 51 GrPath::ComputeKey(shape, &key, &isVolatile); 52 sk_sp<GrPath> path; 53 if (!isVolatile) { 54 path.reset( 55 static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key))); 56 } 57 if (!path) { 58 SkPath skPath; 59 shape.asPath(&skPath); 60 path = resourceProvider->createPath(skPath, shape.style()); 61 if (!isVolatile) { 62 resourceProvider->assignUniqueKeyToResource(key, path.get()); 63 } 64 } else { 65 #ifdef SK_DEBUG 66 SkPath skPath; 67 shape.asPath(&skPath); 68 SkASSERT(path->isEqualTo(skPath, shape.style())); 69 #endif 70 } 71 return path.release(); 72 } 73 74 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { 75 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 76 "GrStencilAndCoverPathRenderer::onStencilPath"); 77 sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape)); 78 args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, 79 *args.fViewMatrix, p.get()); 80 } 81 82 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { 83 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), 84 "GrStencilAndCoverPathRenderer::onDrawPath"); 85 SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle()); 86 87 const SkMatrix& viewMatrix = *args.fViewMatrix; 88 89 90 sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape)); 91 92 if (args.fShape->inverseFilled()) { 93 SkMatrix invert = SkMatrix::I(); 94 SkRect bounds = 95 SkRect::MakeLTRB(0, 0, 96 SkIntToScalar(args.fRenderTargetContext->width()), 97 SkIntToScalar(args.fRenderTargetContext->height())); 98 SkMatrix vmi; 99 // mapRect through persp matrix may not be correct 100 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 101 vmi.mapRect(&bounds); 102 // theoretically could set bloat = 0, instead leave it because of matrix inversion 103 // precision. 104 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; 105 bounds.outset(bloat, bloat); 106 } else { 107 if (!viewMatrix.invert(&invert)) { 108 return false; 109 } 110 } 111 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; 112 113 // fake inverse with a stencil and cover 114 args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix, 115 path.get()); 116 117 { 118 static constexpr GrUserStencilSettings kInvertedCoverPass( 119 GrUserStencilSettings::StaticInit< 120 0x0000, 121 // We know our rect will hit pixels outside the clip and the user bits will 122 // be 0 outside the clip. So we can't just fill where the user bits are 0. We 123 // also need to check that the clip bit is set. 124 GrUserStencilTest::kEqualIfInClip, 125 0xffff, 126 GrUserStencilOp::kKeep, 127 GrUserStencilOp::kZero, 128 0xffff>() 129 ); 130 // We have to suppress enabling MSAA for mixed samples or we will get seams due to 131 // coverage modulation along the edge where two triangles making up the rect meet. 132 GrAAType coverAAType = args.fAAType; 133 if (GrAAType::kMixedSamples == coverAAType) { 134 coverAAType = GrAAType::kNone; 135 } 136 args.fRenderTargetContext->addDrawOp(*args.fClip, 137 GrRectOpFactory::MakeNonAAFillWithLocalMatrix( 138 std::move(args.fPaint), viewM, invert, 139 bounds, coverAAType, &kInvertedCoverPass)); 140 } 141 } else { 142 std::unique_ptr<GrDrawOp> op = 143 GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), args.fAAType, path.get()); 144 args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); 145 } 146 147 return true; 148 } 149