blob: 7ada6d10f79a3fe658d81c067ca1a9742325f50a [file] [log] [blame]
skia.committer@gmail.com3e50e992013-05-21 07:01:40 +00001
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * 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.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00007 */
8
9#ifndef GrPathRenderer_DEFINED
10#define GrPathRenderer_DEFINED
11
12#include "GrDrawTarget.h"
bsalomon@google.com45a15f52012-12-10 19:10:17 +000013#include "GrStencil.h"
kkinnunen18996512015-04-26 23:18:49 -070014#include "GrStrokeInfo.h"
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000015
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +000016#include "SkDrawProcs.h"
bsalomon@google.com49313f62011-09-14 13:54:05 +000017#include "SkTArray.h"
18
reed@google.com07f3ee12011-05-16 17:21:57 +000019class SkPath;
bsalomon@google.com30085192011-08-19 15:42:31 +000020
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000021struct GrPoint;
22
23/**
24 * Base class for drawing paths into a GrDrawTarget.
robertphillips@google.combf5cad42012-05-10 12:40:40 +000025 *
egdaniel8dd688b2015-01-22 10:16:09 -080026 * 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
bsalomon@google.com45a15f52012-12-10 19:10:17 +000028 * filter masks).
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000029 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000030class SK_API GrPathRenderer : public SkRefCnt {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000031public:
bsalomon@google.comc2099d22012-03-02 21:26:50 +000032 GrPathRenderer();
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000033
34 /**
bsalomon@google.com45a15f52012-12-10 19:10:17 +000035 * 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
joshualittb0a8a372014-09-23 09:50:21 -070037 * 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.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000040 *
41 * A GrPathRenderer can provide three levels of support for stenciling paths:
egdaniel8dd688b2015-01-22 10:16:09 -080042 * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target
bsalomon@google.com45a15f52012-12-10 19:10:17 +000043 * 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 */
robertphillips68737822015-10-29 12:12:21 -070053 enum StencilSupport {
54 kNoSupport_StencilSupport,
55 kStencilOnly_StencilSupport,
56 kNoRestriction_StencilSupport,
57 };
bsalomon@google.com45a15f52012-12-10 19:10:17 +000058
59 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +000060 * This function is to get the stencil support for a particular path. The path's fill must
bsalomon@google.com45a15f52012-12-10 19:10:17 +000061 * not be an inverse type.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000062 *
robertphillips@google.come79f3202014-02-11 16:30:21 +000063 * @param path the path that will be drawn
64 * @param stroke the stroke information (width, join, cap).
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000065 */
robertphillipse7d4b2f2015-08-13 07:57:10 -070066 StencilSupport getStencilSupport(const SkPath& path, const GrStrokeInfo& stroke) const {
robertphillips@google.come79f3202014-02-11 16:30:21 +000067 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -070068 return this->onGetStencilSupport(path, stroke);
bsalomon@google.comc2099d22012-03-02 21:26:50 +000069 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070
bsalomon0aff2fa2015-07-31 06:48:27 -070071 /** Args to canDrawPath()
72 *
robertphillipse7d4b2f2015-08-13 07:57:10 -070073 * fShaderCaps The shader caps
bsalomon0aff2fa2015-07-31 06:48:27 -070074 * 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 {
robertphillipse7d4b2f2015-08-13 07:57:10 -070081 const GrShaderCaps* fShaderCaps;
bsalomon0aff2fa2015-07-31 06:48:27 -070082 const SkMatrix* fViewMatrix;
83 const SkPath* fPath;
84 const GrStrokeInfo* fStroke;
85 bool fAntiAlias;
robertphillipse7d4b2f2015-08-13 07:57:10 -070086
robertphillips68737822015-10-29 12:12:21 -070087 // These next two are only used by GrStencilAndCoverPathRenderer
88 bool fIsStencilDisabled;
89 bool fIsStencilBufferMSAA;
90
robertphillipse7d4b2f2015-08-13 07:57:10 -070091 void validate() const {
92 SkASSERT(fShaderCaps);
robertphillipse7d4b2f2015-08-13 07:57:10 -070093 SkASSERT(fViewMatrix);
94 SkASSERT(fPath);
95 SkASSERT(fStroke);
96 SkASSERT(!fPath->isEmpty());
97 }
bsalomon0aff2fa2015-07-31 06:48:27 -070098 };
99
bsalomon@google.com208236d2012-03-12 13:15:33 +0000100 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000101 * 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.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000104 *
bsalomon@google.com208236d2012-03-12 13:15:33 +0000105 * @return true if the path can be drawn by this object, false otherwise.
106 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700107 bool canDrawPath(const CanDrawPathArgs& args) const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700108 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700109 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
jvanverth512e4372015-11-23 11:50:02 -0800118 * fColor Color to render with
bsalomon0aff2fa2015-07-31 06:48:27 -0700119 * 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;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700133
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 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700143 };
144
bsalomon@google.comee435122011-07-01 14:57:55 +0000145 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000146 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
bsalomon0aff2fa2015-07-31 06:48:27 -0700147 * the subclass must respect the stencil settings of the GrPipelineBuilder.
bsalomon@google.comee435122011-07-01 14:57:55 +0000148 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700149 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700150 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700151#ifdef SK_DEBUG
152 CanDrawPathArgs canArgs;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700153 canArgs.fShaderCaps = args.fTarget->caps()->shaderCaps();
bsalomon0aff2fa2015-07-31 06:48:27 -0700154 canArgs.fViewMatrix = args.fViewMatrix;
155 canArgs.fPath = args.fPath;
156 canArgs.fStroke = args.fStroke;
157 canArgs.fAntiAlias = args.fAntiAlias;
robertphillips68737822015-10-29 12:12:21 -0700158
159 canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
160 canArgs.fIsStencilBufferMSAA =
161 args.fPipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
bsalomon0aff2fa2015-07-31 06:48:27 -0700162 SkASSERT(this->canDrawPath(canArgs));
163 SkASSERT(args.fPipelineBuilder->getStencil().isDisabled() ||
robertphillipse7d4b2f2015-08-13 07:57:10 -0700164 kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath,
bsalomon0aff2fa2015-07-31 06:48:27 -0700165 *args.fStroke));
166#endif
167 return this->onDrawPath(args);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000168 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000169
bsalomon0aff2fa2015-07-31 06:48:27 -0700170 /* Args to stencilPath().
171 *
172 * fTarget The target that the path will be rendered to.
robertphillipse7d4b2f2015-08-13 07:57:10 -0700173 * fResourceProvider The resource provider for creating gpu resources to render the path
bsalomon0aff2fa2015-07-31 06:48:27 -0700174 * 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;
bsalomon0aff2fa2015-07-31 06:48:27 -0700181 GrResourceProvider* fResourceProvider;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700182 GrPipelineBuilder* fPipelineBuilder;
bsalomon0aff2fa2015-07-31 06:48:27 -0700183 const SkMatrix* fViewMatrix;
184 const SkPath* fPath;
185 const GrStrokeInfo* fStroke;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700186
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 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700196 };
197
bsalomon@google.comee435122011-07-01 14:57:55 +0000198 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000199 * 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.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000201 *
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000202 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700203 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700204 SkDEBUGCODE(args.validate();)
205 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fPath, *args.fStroke));
206
bsalomon0aff2fa2015-07-31 06:48:27 -0700207 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000208 }
209
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000210 // 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).
kkinnunen18996512015-04-26 23:18:49 -0700212 static bool IsStrokeHairlineOrEquivalent(const GrStrokeInfo& stroke, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000213 SkScalar* outCoverage) {
kkinnunen18996512015-04-26 23:18:49 -0700214 if (stroke.isDashed()) {
215 return false;
216 }
kkinnunend156d362015-05-18 22:23:54 -0700217 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700218 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000219 *outCoverage = SK_Scalar1;
220 }
221 return true;
222 }
kkinnunend156d362015-05-18 22:23:54 -0700223 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
224 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000225 }
226
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000227protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000228 // 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
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000244private:
bsalomon0aff2fa2015-07-31 06:48:27 -0700245 /**
246 * Subclass overrides if it has any limitations of stenciling support.
247 */
robertphillipse7d4b2f2015-08-13 07:57:10 -0700248 virtual StencilSupport onGetStencilSupport(const SkPath&, const GrStrokeInfo&) const {
bsalomon0aff2fa2015-07-31 06:48:27 -0700249 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
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000288
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000289 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000290};
291
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000292#endif