1 2 /* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 #include "GrStencilAndCoverPathRenderer.h" 11 #include "GrCaps.h" 12 #include "GrContext.h" 13 #include "GrDrawPathBatch.h" 14 #include "GrGpu.h" 15 #include "GrPath.h" 16 #include "GrRenderTarget.h" 17 #include "GrResourceProvider.h" 18 #include "GrStrokeInfo.h" 19 #include "batches/GrRectBatchFactory.h" 20 21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider, 22 const GrCaps& caps) { 23 if (caps.shaderCaps()->pathRenderingSupport()) { 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 if (args.fStroke->isHairlineStyle()) { 36 return false; 37 } 38 if (!args.fIsStencilDisabled) { 39 return false; 40 } 41 if (args.fAntiAlias) { 42 return args.fIsStencilBufferMSAA; 43 } else { 44 return true; // doesn't do per-path AA, relies on the target having MSAA 45 } 46 } 47 48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath, 49 const GrStrokeInfo& stroke) { 50 GrUniqueKey key; 51 bool isVolatile; 52 GrPath::ComputeKey(skPath, stroke, &key, &isVolatile); 53 SkAutoTUnref<GrPath> path( 54 static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key))); 55 if (!path) { 56 path.reset(resourceProvider->createPath(skPath, stroke)); 57 if (!isVolatile) { 58 resourceProvider->assignUniqueKeyToResource(key, path); 59 } 60 } else { 61 SkASSERT(path->isEqualTo(skPath, stroke)); 62 } 63 return path.detach(); 64 } 65 66 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { 67 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), 68 "GrStencilAndCoverPathRenderer::onStencilPath"); 69 SkASSERT(!args.fPath->isInverseFillType()); 70 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke)); 71 args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType()); 72 } 73 74 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { 75 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(), 76 "GrStencilAndCoverPathRenderer::onDrawPath"); 77 SkASSERT(!args.fStroke->isHairlineStyle()); 78 const SkPath& path = *args.fPath; 79 GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder; 80 const SkMatrix& viewMatrix = *args.fViewMatrix; 81 82 SkASSERT(pipelineBuilder->getStencil().isDisabled()); 83 84 if (args.fAntiAlias) { 85 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled()); 86 pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag); 87 } 88 89 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke)); 90 91 if (path.isInverseFillType()) { 92 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, 93 kKeep_StencilOp, 94 kZero_StencilOp, 95 // We know our rect will hit pixels outside the clip and the user bits will be 0 96 // outside the clip. So we can't just fill where the user bits are 0. We also need to 97 // check that the clip bit is set. 98 kEqualIfInClip_StencilFunc, 99 0xffff, 100 0x0000, 101 0xffff); 102 103 pipelineBuilder->setStencil(kInvertedStencilPass); 104 105 // fake inverse with a stencil and cover 106 args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType()); 107 108 SkMatrix invert = SkMatrix::I(); 109 SkRect bounds = 110 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()), 111 SkIntToScalar(pipelineBuilder->getRenderTarget()->height())); 112 SkMatrix vmi; 113 // mapRect through persp matrix may not be correct 114 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 115 vmi.mapRect(&bounds); 116 // theoretically could set bloat = 0, instead leave it because of matrix inversion 117 // precision. 118 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; 119 bounds.outset(bloat, bloat); 120 } else { 121 if (!viewMatrix.invert(&invert)) { 122 return false; 123 } 124 } 125 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; 126 if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) { 127 pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag); 128 } 129 130 SkAutoTUnref<GrDrawBatch> batch( 131 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr, 132 &invert)); 133 args.fTarget->drawBatch(*pipelineBuilder, batch); 134 } else { 135 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, 136 kZero_StencilOp, 137 kKeep_StencilOp, 138 kNotEqual_StencilFunc, 139 0xffff, 140 0x0000, 141 0xffff); 142 143 pipelineBuilder->setStencil(kStencilPass); 144 SkAutoTUnref<GrDrawPathBatchBase> batch( 145 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p)); 146 args.fTarget->drawPathBatch(*pipelineBuilder, batch); 147 } 148 149 pipelineBuilder->stencil()->setDisabled(); 150 return true; 151 } 152