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