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