1 /* 2 * Copyright 2011 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 #ifndef GrPathRenderer_DEFINED 9 #define GrPathRenderer_DEFINED 10 11 #include "GrCaps.h" 12 #include "GrDrawContext.h" 13 #include "GrPaint.h" 14 #include "GrResourceProvider.h" 15 #include "GrShape.h" 16 17 #include "SkDrawProcs.h" 18 #include "SkTArray.h" 19 20 class SkPath; 21 class GrFixedClip; 22 struct GrPoint; 23 24 /** 25 * Base class for drawing paths into a GrDrawTarget. 26 * 27 * Derived classes can use stages GrPaint::kTotalStages through GrPipelineBuilder::kNumStages-1. 28 * The stages before GrPaint::kTotalStages are reserved for setting up the draw (i.e., textures and 29 * filter masks). 30 */ 31 class SK_API GrPathRenderer : public SkRefCnt { 32 public: 33 GrPathRenderer(); 34 35 /** 36 * A caller may wish to use a path renderer to draw a path into the stencil buffer. However, 37 * the path renderer itself may require use of the stencil buffer. Also a path renderer may 38 * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are 39 * covered by bounding geometry but outside the path. These exterior pixels would still be 40 * rendered into the stencil. 41 * 42 * A GrPathRenderer can provide three levels of support for stenciling paths: 43 * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target 44 * and calls drawPath(). The path is rendered exactly as the draw state 45 * indicates including support for simultaneous color and stenciling with 46 * arbitrary stenciling rules. Pixels partially covered by AA paths are 47 * affected by the stencil settings. 48 * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil 49 * simultaneously. The path renderer does support the stencilPath() function 50 * which performs no color writes and writes a non-zero stencil value to pixels 51 * covered by the path. 52 * 3) kNoSupport: This path renderer cannot be used to stencil the path. 53 */ 54 enum StencilSupport { 55 kNoSupport_StencilSupport, 56 kStencilOnly_StencilSupport, 57 kNoRestriction_StencilSupport, 58 }; 59 60 /** 61 * This function is to get the stencil support for a particular path. The path's fill must 62 * not be an inverse type. The path will always be filled and not stroked. 63 * 64 * @param shape the shape that will be drawn. Must be simple fill styled and non-inverse 65 * filled. 66 */ getStencilSupport(const GrShape & shape)67 StencilSupport getStencilSupport(const GrShape& shape) const { 68 SkDEBUGCODE(SkPath path;) 69 SkDEBUGCODE(shape.asPath(&path);) 70 SkASSERT(shape.style().isSimpleFill()); 71 SkASSERT(!path.isInverseFillType()); 72 return this->onGetStencilSupport(shape); 73 } 74 75 /** Args to canDrawPath() 76 * 77 * fShaderCaps The shader caps 78 * fPipelineBuilder The pipelineBuilder 79 * fViewMatrix The viewMatrix 80 * fShape The shape to draw 81 * fAntiAlias True if anti-aliasing is required. 82 */ 83 struct CanDrawPathArgs { 84 const GrShaderCaps* fShaderCaps; 85 const SkMatrix* fViewMatrix; 86 const GrShape* fShape; 87 bool fAntiAlias; 88 89 // These next two are only used by GrStencilAndCoverPathRenderer 90 bool fHasUserStencilSettings; 91 bool fIsStencilBufferMSAA; 92 93 #ifdef SK_DEBUG validateCanDrawPathArgs94 void validate() const { 95 SkASSERT(fShaderCaps); 96 SkASSERT(fViewMatrix); 97 SkASSERT(fShape); 98 } 99 #endif 100 }; 101 102 /** 103 * Returns true if this path renderer is able to render the path. Returning false allows the 104 * caller to fallback to another path renderer This function is called when searching for a path 105 * renderer capable of rendering a path. 106 * 107 * @return true if the path can be drawn by this object, false otherwise. 108 */ canDrawPath(const CanDrawPathArgs & args)109 bool canDrawPath(const CanDrawPathArgs& args) const { 110 SkDEBUGCODE(args.validate();) 111 return this->onCanDrawPath(args); 112 } 113 114 /** 115 * Args to drawPath() 116 * 117 * fTarget The target that the path will be rendered to 118 * fResourceProvider The resource provider for creating gpu resources to render the path 119 * fPipelineBuilder The pipelineBuilder 120 * fClip The clip 121 * fColor Color to render with 122 * fViewMatrix The viewMatrix 123 * fShape The shape to draw 124 * fAntiAlias true if anti-aliasing is required. 125 * fGammaCorrect true if gamma-correct rendering is to be used. 126 */ 127 struct DrawPathArgs { 128 GrResourceProvider* fResourceProvider; 129 const GrPaint* fPaint; 130 const GrUserStencilSettings*fUserStencilSettings; 131 132 GrDrawContext* fDrawContext; 133 const GrClip* fClip; 134 const SkMatrix* fViewMatrix; 135 const GrShape* fShape; 136 bool fAntiAlias; 137 bool fGammaCorrect; 138 #ifdef SK_DEBUG validateDrawPathArgs139 void validate() const { 140 SkASSERT(fResourceProvider); 141 SkASSERT(fPaint); 142 SkASSERT(fUserStencilSettings); 143 SkASSERT(fDrawContext); 144 SkASSERT(fClip); 145 SkASSERT(fViewMatrix); 146 SkASSERT(fShape); 147 } 148 #endif 149 }; 150 151 /** 152 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then 153 * the subclass must respect the stencil settings of the GrPipelineBuilder. 154 */ drawPath(const DrawPathArgs & args)155 bool drawPath(const DrawPathArgs& args) { 156 SkDEBUGCODE(args.validate();) 157 #ifdef SK_DEBUG 158 CanDrawPathArgs canArgs; 159 canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps(); 160 canArgs.fViewMatrix = args.fViewMatrix; 161 canArgs.fShape = args.fShape; 162 canArgs.fAntiAlias = args.fAntiAlias; 163 164 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused(); 165 canArgs.fIsStencilBufferMSAA = args.fDrawContext->isStencilBufferMultisampled(); 166 SkASSERT(this->canDrawPath(canArgs)); 167 if (!args.fUserStencilSettings->isUnused()) { 168 SkPath path; 169 args.fShape->asPath(&path); 170 SkASSERT(args.fShape->style().isSimpleFill()); 171 SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape)); 172 } 173 #endif 174 return this->onDrawPath(args); 175 } 176 177 /* Args to stencilPath(). 178 * 179 * fResourceProvider The resource provider for creating gpu resources to render the path 180 * fDrawContext The target of the draws 181 * fViewMatrix Matrix applied to the path. 182 * fPath The path to draw. 183 * fIsAA Is the path to be drawn AA (only set when MSAA is available) 184 */ 185 struct StencilPathArgs { 186 GrResourceProvider* fResourceProvider; 187 GrDrawContext* fDrawContext; 188 const GrClip* fClip; 189 const SkMatrix* fViewMatrix; 190 bool fIsAA; 191 const GrShape* fShape; 192 193 #ifdef SK_DEBUG validateStencilPathArgs194 void validate() const { 195 SkASSERT(fResourceProvider); 196 SkASSERT(fDrawContext); 197 SkASSERT(fViewMatrix); 198 SkASSERT(fShape); 199 SkASSERT(fShape->style().isSimpleFill()); 200 SkPath path; 201 fShape->asPath(&path); 202 SkASSERT(!path.isInverseFillType()); 203 } 204 #endif 205 }; 206 207 /** 208 * Draws the path to the stencil buffer. Assume the writable stencil bits are already 209 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards. 210 */ stencilPath(const StencilPathArgs & args)211 void stencilPath(const StencilPathArgs& args) { 212 SkDEBUGCODE(args.validate();) 213 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape)); 214 this->onStencilPath(args); 215 } 216 217 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage. 218 // If we can, we draw lots faster (raster device does this same test). IsStrokeHairlineOrEquivalent(const GrStyle & style,const SkMatrix & matrix,SkScalar * outCoverage)219 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix, 220 SkScalar* outCoverage) { 221 if (style.pathEffect()) { 222 return false; 223 } 224 const SkStrokeRec& stroke = style.strokeRec(); 225 if (stroke.isHairlineStyle()) { 226 if (outCoverage) { 227 *outCoverage = SK_Scalar1; 228 } 229 return true; 230 } 231 return stroke.getStyle() == SkStrokeRec::kStroke_Style && 232 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage); 233 } 234 235 protected: 236 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set 237 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize. 238 static void GetPathDevBounds(const SkPath& path, 239 int devW, 240 int devH, 241 const SkMatrix& matrix, 242 SkRect* bounds); 243 244 private: 245 /** 246 * Subclass overrides if it has any limitations of stenciling support. 247 */ onGetStencilSupport(const GrShape &)248 virtual StencilSupport onGetStencilSupport(const GrShape&) const { 249 return kNoRestriction_StencilSupport; 250 } 251 252 /** 253 * Subclass implementation of drawPath() 254 */ 255 virtual bool onDrawPath(const DrawPathArgs& args) = 0; 256 257 /** 258 * Subclass implementation of canDrawPath() 259 */ 260 virtual bool onCanDrawPath(const CanDrawPathArgs& args) const = 0; 261 262 /** 263 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns 264 * kStencilOnly in onGetStencilSupport(). 265 */ onStencilPath(const StencilPathArgs & args)266 virtual void onStencilPath(const StencilPathArgs& args) { 267 static constexpr GrUserStencilSettings kIncrementStencil( 268 GrUserStencilSettings::StaticInit< 269 0xffff, 270 GrUserStencilTest::kAlways, 271 0xffff, 272 GrUserStencilOp::kReplace, 273 GrUserStencilOp::kReplace, 274 0xffff>() 275 ); 276 277 GrPaint paint; 278 279 DrawPathArgs drawArgs; 280 drawArgs.fResourceProvider = args.fResourceProvider; 281 drawArgs.fPaint = &paint; 282 drawArgs.fUserStencilSettings = &kIncrementStencil; 283 drawArgs.fDrawContext = args.fDrawContext; 284 drawArgs.fViewMatrix = args.fViewMatrix; 285 drawArgs.fShape = args.fShape; 286 drawArgs.fAntiAlias = false; // In this case the MSAA handles the AA so we want to draw BW 287 drawArgs.fGammaCorrect = false; 288 this->drawPath(drawArgs); 289 } 290 291 typedef SkRefCnt INHERITED; 292 }; 293 294 #endif 295