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