blob: f1164a9503159e32eaee32c9a7288e63b1b5d4dc [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 {
Brian Salomon82f44312017-01-11 13:42:54 -0500127 GrResourceProvider* fResourceProvider;
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;
bsalomon8acedde2016-06-24 10:42:16 -0700136#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700137 void validate() const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700138 SkASSERT(fResourceProvider);
robertphillips976f5f02016-06-03 10:59:20 -0700139 SkASSERT(fUserStencilSettings);
Brian Osman11052242016-10-27 14:47:55 -0400140 SkASSERT(fRenderTargetContext);
cdalton862cff32016-05-12 15:09:48 -0700141 SkASSERT(fClip);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700142 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700143 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700144 }
bsalomon8acedde2016-06-24 10:42:16 -0700145#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700146 };
147
bsalomon@google.comee435122011-07-01 14:57:55 +0000148 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000149 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
bsalomon0aff2fa2015-07-31 06:48:27 -0700150 * the subclass must respect the stencil settings of the GrPipelineBuilder.
bsalomon@google.comee435122011-07-01 14:57:55 +0000151 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700152 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700153 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700154#ifdef SK_DEBUG
155 CanDrawPathArgs canArgs;
robertphillips976f5f02016-06-03 10:59:20 -0700156 canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps();
bsalomon0aff2fa2015-07-31 06:48:27 -0700157 canArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700158 canArgs.fShape = args.fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500159 canArgs.fAAType = args.fAAType;
robertphillips68737822015-10-29 12:12:21 -0700160
robertphillips976f5f02016-06-03 10:59:20 -0700161 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500162 SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
163 !args.fRenderTargetContext->isUnifiedMultisampled()));
164 SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
165 !args.fRenderTargetContext->isStencilBufferMultisampled()));
bsalomon0aff2fa2015-07-31 06:48:27 -0700166 SkASSERT(this->canDrawPath(canArgs));
robertphillips976f5f02016-06-03 10:59:20 -0700167 if (!args.fUserStencilSettings->isUnused()) {
bsalomon8acedde2016-06-24 10:42:16 -0700168 SkPath path;
169 args.fShape->asPath(&path);
170 SkASSERT(args.fShape->style().isSimpleFill());
171 SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
bsalomond6f25bf2016-05-05 09:26:21 -0700172 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700173#endif
174 return this->onDrawPath(args);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000175 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000176
bsalomon0aff2fa2015-07-31 06:48:27 -0700177 /* Args to stencilPath().
178 *
robertphillipse7d4b2f2015-08-13 07:57:10 -0700179 * fResourceProvider The resource provider for creating gpu resources to render the path
Brian Osman11052242016-10-27 14:47:55 -0400180 * fRenderTargetContext The target of the draws
bsalomon0aff2fa2015-07-31 06:48:27 -0700181 * fViewMatrix Matrix applied to the path.
182 * fPath The path to draw.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500183 * fAAType The type of AA, cannot be kCoverage.
bsalomon0aff2fa2015-07-31 06:48:27 -0700184 */
185 struct StencilPathArgs {
Brian Osman11052242016-10-27 14:47:55 -0400186 GrResourceProvider* fResourceProvider;
187 GrRenderTargetContext* fRenderTargetContext;
188 const GrClip* fClip;
189 const SkMatrix* fViewMatrix;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500190 GrAAType fAAType;
Brian Osman11052242016-10-27 14:47:55 -0400191 const GrShape* fShape;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700192
bsalomon8acedde2016-06-24 10:42:16 -0700193#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700194 void validate() const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700195 SkASSERT(fResourceProvider);
Brian Osman11052242016-10-27 14:47:55 -0400196 SkASSERT(fRenderTargetContext);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700197 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700198 SkASSERT(fShape);
caryclarkd6562002016-07-27 12:02:07 -0700199 SkASSERT(fShape->style().isSimpleFill());
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500200 SkASSERT(GrAAType::kCoverage != fAAType);
bsalomon8acedde2016-06-24 10:42:16 -0700201 SkPath path;
202 fShape->asPath(&path);
203 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -0700204 }
bsalomon8acedde2016-06-24 10:42:16 -0700205#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700206 };
207
bsalomon@google.comee435122011-07-01 14:57:55 +0000208 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000209 * 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.
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000211 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700212 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700213 SkDEBUGCODE(args.validate();)
bsalomon8acedde2016-06-24 10:42:16 -0700214 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
bsalomon0aff2fa2015-07-31 06:48:27 -0700215 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000216 }
217
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000218 // 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).
bsalomon6663acf2016-05-10 09:14:17 -0700220 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000221 SkScalar* outCoverage) {
bsalomon6663acf2016-05-10 09:14:17 -0700222 if (style.pathEffect()) {
kkinnunen18996512015-04-26 23:18:49 -0700223 return false;
224 }
bsalomon6663acf2016-05-10 09:14:17 -0700225 const SkStrokeRec& stroke = style.strokeRec();
kkinnunend156d362015-05-18 22:23:54 -0700226 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700227 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000228 *outCoverage = SK_Scalar1;
229 }
230 return true;
231 }
kkinnunend156d362015-05-18 22:23:54 -0700232 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
233 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000234 }
235
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000236protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000237 // 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
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000245private:
bsalomon0aff2fa2015-07-31 06:48:27 -0700246 /**
247 * Subclass overrides if it has any limitations of stenciling support.
248 */
bsalomon8acedde2016-06-24 10:42:16 -0700249 virtual StencilSupport onGetStencilSupport(const GrShape&) const {
bsalomon0aff2fa2015-07-31 06:48:27 -0700250 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 */
267 virtual void onStencilPath(const StencilPathArgs& args) {
cdalton93a379b2016-05-11 13:58:08 -0700268 static constexpr GrUserStencilSettings kIncrementStencil(
269 GrUserStencilSettings::StaticInit<
270 0xffff,
271 GrUserStencilTest::kAlways,
272 0xffff,
273 GrUserStencilOp::kReplace,
274 GrUserStencilOp::kReplace,
275 0xffff>()
276 );
robertphillips976f5f02016-06-03 10:59:20 -0700277
278 GrPaint paint;
279
Brian Salomon82f44312017-01-11 13:42:54 -0500280 DrawPathArgs drawArgs{args.fResourceProvider,
281 std::move(paint),
282 &kIncrementStencil,
283 args.fRenderTargetContext,
284 nullptr, // clip
285 args.fViewMatrix,
286 args.fShape,
287 args.fAAType,
288 false};
bsalomon0aff2fa2015-07-31 06:48:27 -0700289 this->drawPath(drawArgs);
290 }
291
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000292 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000293};
294
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000295#endif