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 "GrContext.h" 12#include "GrDrawTargetCaps.h" 13#include "GrGpu.h" 14#include "GrPath.h" 15#include "GrRenderTarget.h" 16#include "GrRenderTargetPriv.h" 17#include "GrResourceProvider.h" 18#include "GrStrokeInfo.h" 19 20/* 21 * For now paths only natively support winding and even odd fill types 22 */ 23static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) { 24 switch (fill) { 25 default: 26 SkFAIL("Incomplete Switch\n"); 27 case SkPath::kWinding_FillType: 28 case SkPath::kInverseWinding_FillType: 29 return GrPathRendering::kWinding_FillType; 30 case SkPath::kEvenOdd_FillType: 31 case SkPath::kInverseEvenOdd_FillType: 32 return GrPathRendering::kEvenOdd_FillType; 33 } 34} 35 36GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) { 37 SkASSERT(context); 38 SkASSERT(context->getGpu()); 39 if (context->getGpu()->caps()->shaderCaps()->pathRenderingSupport()) { 40 return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu())); 41 } else { 42 return NULL; 43 } 44} 45 46GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) { 47 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport()); 48 fGpu = gpu; 49 gpu->ref(); 50} 51 52GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() { 53 fGpu->unref(); 54} 55 56bool GrStencilAndCoverPathRenderer::canDrawPath(const GrDrawTarget* target, 57 const GrPipelineBuilder* pipelineBuilder, 58 const SkMatrix& viewMatrix, 59 const SkPath& path, 60 const GrStrokeInfo& stroke, 61 bool antiAlias) const { 62 return !stroke.getStrokeRec().isHairlineStyle() && 63 !stroke.isDashed() && 64 !antiAlias && // doesn't do per-path AA, relies on the target having MSAA 65 pipelineBuilder->getStencil().isDisabled(); 66} 67 68GrPathRenderer::StencilSupport 69GrStencilAndCoverPathRenderer::onGetStencilSupport(const GrDrawTarget*, 70 const GrPipelineBuilder*, 71 const SkPath&, 72 const GrStrokeInfo&) const { 73 return GrPathRenderer::kStencilOnly_StencilSupport; 74} 75 76static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const SkStrokeRec& stroke) { 77 GrContext* ctx = gpu->getContext(); 78 GrUniqueKey key; 79 GrPath::ComputeKey(skPath, stroke, &key); 80 SkAutoTUnref<GrPath> path( 81 static_cast<GrPath*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key))); 82 if (NULL == path || !path->isEqualTo(skPath, stroke)) { 83 path.reset(gpu->pathRendering()->createPath(skPath, stroke)); 84 ctx->resourceProvider()->assignUniqueKeyToResource(key, path); 85 } 86 return path.detach(); 87} 88 89void GrStencilAndCoverPathRenderer::onStencilPath(GrDrawTarget* target, 90 GrPipelineBuilder* pipelineBuilder, 91 const SkMatrix& viewMatrix, 92 const SkPath& path, 93 const GrStrokeInfo& stroke) { 94 SkASSERT(!path.isInverseFillType()); 95 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix)); 96 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke.getStrokeRec())); 97 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); 98} 99 100bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target, 101 GrPipelineBuilder* pipelineBuilder, 102 GrColor color, 103 const SkMatrix& viewMatrix, 104 const SkPath& path, 105 const GrStrokeInfo& stroke, 106 bool antiAlias) { 107 SkASSERT(!antiAlias); 108 SkASSERT(!stroke.getStrokeRec().isHairlineStyle()); 109 SkASSERT(!stroke.isDashed()); 110 SkASSERT(pipelineBuilder->getStencil().isDisabled()); 111 112 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke.getStrokeRec())); 113 114 if (path.isInverseFillType()) { 115 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass, 116 kZero_StencilOp, 117 kZero_StencilOp, 118 // We know our rect will hit pixels outside the clip and the user bits will be 0 119 // outside the clip. So we can't just fill where the user bits are 0. We also need to 120 // check that the clip bit is set. 121 kEqualIfInClip_StencilFunc, 122 0xffff, 123 0x0000, 124 0xffff); 125 126 pipelineBuilder->setStencil(kInvertedStencilPass); 127 128 // fake inverse with a stencil and cover 129 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix)); 130 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); 131 132 SkMatrix invert = SkMatrix::I(); 133 SkRect bounds = 134 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()), 135 SkIntToScalar(pipelineBuilder->getRenderTarget()->height())); 136 SkMatrix vmi; 137 // mapRect through persp matrix may not be correct 138 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) { 139 vmi.mapRect(&bounds); 140 // theoretically could set bloat = 0, instead leave it because of matrix inversion 141 // precision. 142 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf; 143 bounds.outset(bloat, bloat); 144 } else { 145 if (!viewMatrix.invert(&invert)) { 146 return false; 147 } 148 } 149 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix; 150 target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert); 151 } else { 152 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, 153 kZero_StencilOp, 154 kZero_StencilOp, 155 kNotEqual_StencilFunc, 156 0xffff, 157 0x0000, 158 0xffff); 159 160 pipelineBuilder->setStencil(kStencilPass); 161 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color, viewMatrix)); 162 target->drawPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType())); 163 } 164 165 pipelineBuilder->stencil()->setDisabled(); 166 return true; 167} 168