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 "GrRenderTargetContext.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 GrOpList. 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 44 * target and calls drawPath(). The path is rendered exactly as the draw 45 * state indicates including support for simultaneous color and stenciling 46 * with 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 The type of anti aliasing required. 82 */ 83 struct CanDrawPathArgs { 84 const GrShaderCaps* fShaderCaps; 85 const SkMatrix* fViewMatrix; 86 const GrShape* fShape; 87 GrAAType fAAType; 88 89 // These next two are only used by GrStencilAndCoverPathRenderer 90 bool fHasUserStencilSettings; 91 92 #ifdef SK_DEBUG validateCanDrawPathArgs93 void validate() const { 94 SkASSERT(fShaderCaps); 95 SkASSERT(fViewMatrix); 96 SkASSERT(fShape); 97 } 98 #endif 99 }; 100 101 /** 102 * Returns true if this path renderer is able to render the path. Returning false allows the 103 * caller to fallback to another path renderer This function is called when searching for a path 104 * renderer capable of rendering a path. 105 * 106 * @return true if the path can be drawn by this object, false otherwise. 107 */ canDrawPath(const CanDrawPathArgs & args)108 bool canDrawPath(const CanDrawPathArgs& args) const { 109 SkDEBUGCODE(args.validate();) 110 return this->onCanDrawPath(args); 111 } 112 113 /** 114 * Args to drawPath() 115 * 116 * fTarget The target that the path will be rendered to 117 * fResourceProvider The resource provider for creating gpu resources to render the path 118 * fPipelineBuilder The pipelineBuilder 119 * fClip The clip 120 * fColor Color to render with 121 * fViewMatrix The viewMatrix 122 * fShape The shape to draw 123 * fAAtype true if anti-aliasing is required. 124 * fGammaCorrect true if gamma-correct rendering is to be used. 125 */ 126 struct DrawPathArgs { 127 GrContext* fContext; 128 GrPaint&& fPaint; 129 const GrUserStencilSettings* fUserStencilSettings; 130 GrRenderTargetContext* fRenderTargetContext; 131 const GrClip* fClip; 132 const SkMatrix* fViewMatrix; 133 const GrShape* fShape; 134 GrAAType fAAType; 135 bool fGammaCorrect; 136 #ifdef SK_DEBUG validateDrawPathArgs137 void validate() const { 138 SkASSERT(fContext); 139 SkASSERT(fUserStencilSettings); 140 SkASSERT(fRenderTargetContext); 141 SkASSERT(fClip); 142 SkASSERT(fViewMatrix); 143 SkASSERT(fShape); 144 } 145 #endif 146 }; 147 148 /** 149 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then 150 * the subclass must respect the stencil settings of the GrPipelineBuilder. 151 */ drawPath(const DrawPathArgs & args)152 bool drawPath(const DrawPathArgs& args) { 153 SkDEBUGCODE(args.validate();) 154 #ifdef SK_DEBUG 155 CanDrawPathArgs canArgs; 156 canArgs.fShaderCaps = args.fContext->caps()->shaderCaps(); 157 canArgs.fViewMatrix = args.fViewMatrix; 158 canArgs.fShape = args.fShape; 159 canArgs.fAAType = args.fAAType; 160 161 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused(); 162 SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA && 163 !args.fRenderTargetContext->isUnifiedMultisampled())); 164 SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples && 165 !args.fRenderTargetContext->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 * fRenderTargetContext The target of the draws 181 * fViewMatrix Matrix applied to the path. 182 * fPath The path to draw. 183 * fAAType The type of AA, cannot be kCoverage. 184 */ 185 struct StencilPathArgs { 186 GrContext* fContext; 187 GrRenderTargetContext* fRenderTargetContext; 188 const GrClip* fClip; 189 const SkMatrix* fViewMatrix; 190 GrAAType fAAType; 191 const GrShape* fShape; 192 193 #ifdef SK_DEBUG validateStencilPathArgs194 void validate() const { 195 SkASSERT(fContext); 196 SkASSERT(fRenderTargetContext); 197 SkASSERT(fViewMatrix); 198 SkASSERT(fShape); 199 SkASSERT(fShape->style().isSimpleFill()); 200 SkASSERT(GrAAType::kCoverage != fAAType); 201 SkPath path; 202 fShape->asPath(&path); 203 SkASSERT(!path.isInverseFillType()); 204 } 205 #endif 206 }; 207 208 /** 209 * Draws the path to the stencil buffer. Assume the writable stencil bits are already 210 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards. 211 */ stencilPath(const StencilPathArgs & args)212 void stencilPath(const StencilPathArgs& args) { 213 SkDEBUGCODE(args.validate();) 214 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape)); 215 this->onStencilPath(args); 216 } 217 218 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage. 219 // If we can, we draw lots faster (raster device does this same test). IsStrokeHairlineOrEquivalent(const GrStyle & style,const SkMatrix & matrix,SkScalar * outCoverage)220 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix, 221 SkScalar* outCoverage) { 222 if (style.pathEffect()) { 223 return false; 224 } 225 const SkStrokeRec& stroke = style.strokeRec(); 226 if (stroke.isHairlineStyle()) { 227 if (outCoverage) { 228 *outCoverage = SK_Scalar1; 229 } 230 return true; 231 } 232 return stroke.getStyle() == SkStrokeRec::kStroke_Style && 233 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage); 234 } 235 236 protected: 237 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set 238 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize. 239 static void GetPathDevBounds(const SkPath& path, 240 int devW, 241 int devH, 242 const SkMatrix& matrix, 243 SkRect* bounds); 244 245 private: 246 /** 247 * Subclass overrides if it has any limitations of stenciling support. 248 */ onGetStencilSupport(const GrShape &)249 virtual StencilSupport onGetStencilSupport(const GrShape&) const { 250 return kNoRestriction_StencilSupport; 251 } 252 253 /** 254 * Subclass implementation of drawPath() 255 */ 256 virtual bool onDrawPath(const DrawPathArgs& args) = 0; 257 258 /** 259 * Subclass implementation of canDrawPath() 260 */ 261 virtual bool onCanDrawPath(const CanDrawPathArgs& args) const = 0; 262 263 /** 264 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns 265 * kStencilOnly in onGetStencilSupport(). 266 */ onStencilPath(const StencilPathArgs & args)267 virtual void onStencilPath(const StencilPathArgs& args) { 268 static constexpr GrUserStencilSettings kIncrementStencil( 269 GrUserStencilSettings::StaticInit< 270 0xffff, 271 GrUserStencilTest::kAlways, 272 0xffff, 273 GrUserStencilOp::kReplace, 274 GrUserStencilOp::kReplace, 275 0xffff>() 276 ); 277 278 GrPaint paint; 279 280 DrawPathArgs drawArgs{args.fContext, 281 std::move(paint), 282 &kIncrementStencil, 283 args.fRenderTargetContext, 284 nullptr, // clip 285 args.fViewMatrix, 286 args.fShape, 287 args.fAAType, 288 false}; 289 this->drawPath(drawArgs); 290 } 291 292 typedef SkRefCnt INHERITED; 293 }; 294 295 #endif 296