blob: 854808764177dc18e36a6c43b9ce75f9c2e19f78 [file] [log] [blame]
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00006 */
7
8#ifndef GrPathRenderer_DEFINED
9#define GrPathRenderer_DEFINED
10
robertphillips5fa7f302016-07-21 09:21:04 -070011#include "GrCaps.h"
Brian Osman11052242016-10-27 14:47:55 -040012#include "GrRenderTargetContext.h"
robertphillips976f5f02016-06-03 10:59:20 -070013#include "GrPaint.h"
14#include "GrResourceProvider.h"
bsalomon8acedde2016-06-24 10:42:16 -070015#include "GrShape.h"
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000016
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +000017#include "SkDrawProcs.h"
bsalomon@google.com49313f62011-09-14 13:54:05 +000018#include "SkTArray.h"
19
reed@google.com07f3ee12011-05-16 17:21:57 +000020class SkPath;
robertphillips976f5f02016-06-03 10:59:20 -070021class GrFixedClip;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000022struct GrPoint;
23
24/**
Robert Phillipsf2361d22016-10-25 14:20:06 -040025 * Base class for drawing paths into a GrOpList.
robertphillips@google.combf5cad42012-05-10 12:40:40 +000026 *
egdaniel8dd688b2015-01-22 10:16:09 -080027 * 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
bsalomon@google.com45a15f52012-12-10 19:10:17 +000029 * filter masks).
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000030 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000031class SK_API GrPathRenderer : public SkRefCnt {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000032public:
bsalomon@google.comc2099d22012-03-02 21:26:50 +000033 GrPathRenderer();
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000034
35 /**
bsalomon@google.com45a15f52012-12-10 19:10:17 +000036 * 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
joshualittb0a8a372014-09-23 09:50:21 -070038 * 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.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000041 *
42 * A GrPathRenderer can provide three levels of support for stenciling paths:
Brian Salomon82125e92016-12-10 09:35:48 -050043 * 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
bsalomon@google.com45a15f52012-12-10 19:10:17 +000047 * 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 */
robertphillips68737822015-10-29 12:12:21 -070054 enum StencilSupport {
55 kNoSupport_StencilSupport,
56 kStencilOnly_StencilSupport,
57 kNoRestriction_StencilSupport,
58 };
bsalomon@google.com45a15f52012-12-10 19:10:17 +000059
60 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +000061 * This function is to get the stencil support for a particular path. The path's fill must
bsalomond6f25bf2016-05-05 09:26:21 -070062 * not be an inverse type. The path will always be filled and not stroked.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000063 *
bsalomon8acedde2016-06-24 10:42:16 -070064 * @param shape the shape that will be drawn. Must be simple fill styled and non-inverse
65 * filled.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000066 */
bsalomon8acedde2016-06-24 10:42:16 -070067 StencilSupport getStencilSupport(const GrShape& shape) const {
68 SkDEBUGCODE(SkPath path;)
69 SkDEBUGCODE(shape.asPath(&path);)
70 SkASSERT(shape.style().isSimpleFill());
robertphillips@google.come79f3202014-02-11 16:30:21 +000071 SkASSERT(!path.isInverseFillType());
bsalomon8acedde2016-06-24 10:42:16 -070072 return this->onGetStencilSupport(shape);
bsalomon@google.comc2099d22012-03-02 21:26:50 +000073 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000074
bsalomon0aff2fa2015-07-31 06:48:27 -070075 /** Args to canDrawPath()
76 *
robertphillipse7d4b2f2015-08-13 07:57:10 -070077 * fShaderCaps The shader caps
bsalomon0aff2fa2015-07-31 06:48:27 -070078 * fPipelineBuilder The pipelineBuilder
79 * fViewMatrix The viewMatrix
bsalomon8acedde2016-06-24 10:42:16 -070080 * fShape The shape to draw
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050081 * fAntiAlias The type of anti aliasing required.
bsalomon0aff2fa2015-07-31 06:48:27 -070082 */
83 struct CanDrawPathArgs {
robertphillipse7d4b2f2015-08-13 07:57:10 -070084 const GrShaderCaps* fShaderCaps;
bsalomon0aff2fa2015-07-31 06:48:27 -070085 const SkMatrix* fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -070086 const GrShape* fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050087 GrAAType fAAType;
robertphillipse7d4b2f2015-08-13 07:57:10 -070088
robertphillips68737822015-10-29 12:12:21 -070089 // These next two are only used by GrStencilAndCoverPathRenderer
cdalton93a379b2016-05-11 13:58:08 -070090 bool fHasUserStencilSettings;
robertphillips68737822015-10-29 12:12:21 -070091
bsalomon8acedde2016-06-24 10:42:16 -070092#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -070093 void validate() const {
94 SkASSERT(fShaderCaps);
robertphillipse7d4b2f2015-08-13 07:57:10 -070095 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -070096 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -070097 }
bsalomon8acedde2016-06-24 10:42:16 -070098#endif
bsalomon0aff2fa2015-07-31 06:48:27 -070099 };
100
bsalomon@google.com208236d2012-03-12 13:15:33 +0000101 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000102 * 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.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000105 *
bsalomon@google.com208236d2012-03-12 13:15:33 +0000106 * @return true if the path can be drawn by this object, false otherwise.
107 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700108 bool canDrawPath(const CanDrawPathArgs& args) const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700109 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700110 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
cdalton862cff32016-05-12 15:09:48 -0700119 * fClip The clip
jvanverth512e4372015-11-23 11:50:02 -0800120 * fColor Color to render with
bsalomon0aff2fa2015-07-31 06:48:27 -0700121 * fViewMatrix The viewMatrix
bsalomon8acedde2016-06-24 10:42:16 -0700122 * fShape The shape to draw
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500123 * fAAtype true if anti-aliasing is required.
brianosman0e3c5542016-04-13 13:56:21 -0700124 * fGammaCorrect true if gamma-correct rendering is to be used.
bsalomon0aff2fa2015-07-31 06:48:27 -0700125 */
126 struct DrawPathArgs {
bsalomon0aff2fa2015-07-31 06:48:27 -0700127 GrResourceProvider* fResourceProvider;
robertphillips976f5f02016-06-03 10:59:20 -0700128 const GrPaint* fPaint;
129 const GrUserStencilSettings*fUserStencilSettings;
130
Brian Osman11052242016-10-27 14:47:55 -0400131 GrRenderTargetContext* fRenderTargetContext;
cdalton862cff32016-05-12 15:09:48 -0700132 const GrClip* fClip;
bsalomon0aff2fa2015-07-31 06:48:27 -0700133 const SkMatrix* fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700134 const GrShape* fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500135 GrAAType fAAType;
brianosman0e3c5542016-04-13 13:56:21 -0700136 bool fGammaCorrect;
bsalomon8acedde2016-06-24 10:42:16 -0700137#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700138 void validate() const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700139 SkASSERT(fResourceProvider);
robertphillips976f5f02016-06-03 10:59:20 -0700140 SkASSERT(fPaint);
141 SkASSERT(fUserStencilSettings);
Brian Osman11052242016-10-27 14:47:55 -0400142 SkASSERT(fRenderTargetContext);
cdalton862cff32016-05-12 15:09:48 -0700143 SkASSERT(fClip);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700144 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700145 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700146 }
bsalomon8acedde2016-06-24 10:42:16 -0700147#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700148 };
149
bsalomon@google.comee435122011-07-01 14:57:55 +0000150 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000151 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
bsalomon0aff2fa2015-07-31 06:48:27 -0700152 * the subclass must respect the stencil settings of the GrPipelineBuilder.
bsalomon@google.comee435122011-07-01 14:57:55 +0000153 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700154 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700155 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700156#ifdef SK_DEBUG
157 CanDrawPathArgs canArgs;
robertphillips976f5f02016-06-03 10:59:20 -0700158 canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps();
bsalomon0aff2fa2015-07-31 06:48:27 -0700159 canArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700160 canArgs.fShape = args.fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500161 canArgs.fAAType = args.fAAType;
robertphillips68737822015-10-29 12:12:21 -0700162
robertphillips976f5f02016-06-03 10:59:20 -0700163 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500164 SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
165 !args.fRenderTargetContext->isUnifiedMultisampled()));
166 SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
167 !args.fRenderTargetContext->isStencilBufferMultisampled()));
bsalomon0aff2fa2015-07-31 06:48:27 -0700168 SkASSERT(this->canDrawPath(canArgs));
robertphillips976f5f02016-06-03 10:59:20 -0700169 if (!args.fUserStencilSettings->isUnused()) {
bsalomon8acedde2016-06-24 10:42:16 -0700170 SkPath path;
171 args.fShape->asPath(&path);
172 SkASSERT(args.fShape->style().isSimpleFill());
173 SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
bsalomond6f25bf2016-05-05 09:26:21 -0700174 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700175#endif
176 return this->onDrawPath(args);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000177 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000178
bsalomon0aff2fa2015-07-31 06:48:27 -0700179 /* Args to stencilPath().
180 *
robertphillipse7d4b2f2015-08-13 07:57:10 -0700181 * fResourceProvider The resource provider for creating gpu resources to render the path
Brian Osman11052242016-10-27 14:47:55 -0400182 * fRenderTargetContext The target of the draws
bsalomon0aff2fa2015-07-31 06:48:27 -0700183 * fViewMatrix Matrix applied to the path.
184 * fPath The path to draw.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500185 * fAAType The type of AA, cannot be kCoverage.
bsalomon0aff2fa2015-07-31 06:48:27 -0700186 */
187 struct StencilPathArgs {
Brian Osman11052242016-10-27 14:47:55 -0400188 GrResourceProvider* fResourceProvider;
189 GrRenderTargetContext* fRenderTargetContext;
190 const GrClip* fClip;
191 const SkMatrix* fViewMatrix;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500192 GrAAType fAAType;
Brian Osman11052242016-10-27 14:47:55 -0400193 const GrShape* fShape;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700194
bsalomon8acedde2016-06-24 10:42:16 -0700195#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700196 void validate() const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700197 SkASSERT(fResourceProvider);
Brian Osman11052242016-10-27 14:47:55 -0400198 SkASSERT(fRenderTargetContext);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700199 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700200 SkASSERT(fShape);
caryclarkd6562002016-07-27 12:02:07 -0700201 SkASSERT(fShape->style().isSimpleFill());
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500202 SkASSERT(GrAAType::kCoverage != fAAType);
bsalomon8acedde2016-06-24 10:42:16 -0700203 SkPath path;
204 fShape->asPath(&path);
205 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -0700206 }
bsalomon8acedde2016-06-24 10:42:16 -0700207#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700208 };
209
bsalomon@google.comee435122011-07-01 14:57:55 +0000210 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000211 * Draws the path to the stencil buffer. Assume the writable stencil bits are already
212 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000213 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700214 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700215 SkDEBUGCODE(args.validate();)
bsalomon8acedde2016-06-24 10:42:16 -0700216 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
bsalomon0aff2fa2015-07-31 06:48:27 -0700217 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000218 }
219
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000220 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
221 // If we can, we draw lots faster (raster device does this same test).
bsalomon6663acf2016-05-10 09:14:17 -0700222 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000223 SkScalar* outCoverage) {
bsalomon6663acf2016-05-10 09:14:17 -0700224 if (style.pathEffect()) {
kkinnunen18996512015-04-26 23:18:49 -0700225 return false;
226 }
bsalomon6663acf2016-05-10 09:14:17 -0700227 const SkStrokeRec& stroke = style.strokeRec();
kkinnunend156d362015-05-18 22:23:54 -0700228 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700229 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000230 *outCoverage = SK_Scalar1;
231 }
232 return true;
233 }
kkinnunend156d362015-05-18 22:23:54 -0700234 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
235 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000236 }
237
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000238protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000239 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
240 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
241 static void GetPathDevBounds(const SkPath& path,
242 int devW,
243 int devH,
244 const SkMatrix& matrix,
245 SkRect* bounds);
246
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000247private:
bsalomon0aff2fa2015-07-31 06:48:27 -0700248 /**
249 * Subclass overrides if it has any limitations of stenciling support.
250 */
bsalomon8acedde2016-06-24 10:42:16 -0700251 virtual StencilSupport onGetStencilSupport(const GrShape&) const {
bsalomon0aff2fa2015-07-31 06:48:27 -0700252 return kNoRestriction_StencilSupport;
253 }
254
255 /**
256 * Subclass implementation of drawPath()
257 */
258 virtual bool onDrawPath(const DrawPathArgs& args) = 0;
259
260 /**
261 * Subclass implementation of canDrawPath()
262 */
263 virtual bool onCanDrawPath(const CanDrawPathArgs& args) const = 0;
264
265 /**
266 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
267 * kStencilOnly in onGetStencilSupport().
268 */
269 virtual void onStencilPath(const StencilPathArgs& args) {
cdalton93a379b2016-05-11 13:58:08 -0700270 static constexpr GrUserStencilSettings kIncrementStencil(
271 GrUserStencilSettings::StaticInit<
272 0xffff,
273 GrUserStencilTest::kAlways,
274 0xffff,
275 GrUserStencilOp::kReplace,
276 GrUserStencilOp::kReplace,
277 0xffff>()
278 );
robertphillips976f5f02016-06-03 10:59:20 -0700279
280 GrPaint paint;
281
bsalomon0aff2fa2015-07-31 06:48:27 -0700282 DrawPathArgs drawArgs;
bsalomon0aff2fa2015-07-31 06:48:27 -0700283 drawArgs.fResourceProvider = args.fResourceProvider;
robertphillips976f5f02016-06-03 10:59:20 -0700284 drawArgs.fPaint = &paint;
285 drawArgs.fUserStencilSettings = &kIncrementStencil;
Brian Osman11052242016-10-27 14:47:55 -0400286 drawArgs.fRenderTargetContext = args.fRenderTargetContext;
bsalomon0aff2fa2015-07-31 06:48:27 -0700287 drawArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700288 drawArgs.fShape = args.fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500289 drawArgs.fAAType = args.fAAType;
brianosman0e3c5542016-04-13 13:56:21 -0700290 drawArgs.fGammaCorrect = false;
bsalomon0aff2fa2015-07-31 06:48:27 -0700291 this->drawPath(drawArgs);
292 }
293
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000294 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000295};
296
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000297#endif