blob: 2b5ccdc8834a69566f99f13b7014a6291540e65e [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:
egdaniel8dd688b2015-01-22 10:16:09 -080043 * 1) kNoRestriction: This is the most general. The caller sets up the GrPipelineBuilder on the target
bsalomon@google.com45a15f52012-12-10 19:10:17 +000044 * and calls drawPath(). The path is rendered exactly as the draw state
45 * indicates including support for simultaneous color and stenciling with
46 * arbitrary stenciling rules. Pixels partially covered by AA paths are
47 * 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 Salomon073285c2016-12-09 20:02:08 +000081 * fAntiAlias True if anti-aliasing is 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 Salomon073285c2016-12-09 20:02:08 +000087 bool fAntiAlias;
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;
Brian Salomon073285c2016-12-09 20:02:08 +000091 bool fIsStencilBufferMSAA;
robertphillips68737822015-10-29 12:12:21 -070092
bsalomon8acedde2016-06-24 10:42:16 -070093#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -070094 void validate() const {
95 SkASSERT(fShaderCaps);
robertphillipse7d4b2f2015-08-13 07:57:10 -070096 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -070097 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -070098 }
bsalomon8acedde2016-06-24 10:42:16 -070099#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700100 };
101
bsalomon@google.com208236d2012-03-12 13:15:33 +0000102 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000103 * Returns true if this path renderer is able to render the path. Returning false allows the
104 * caller to fallback to another path renderer This function is called when searching for a path
105 * renderer capable of rendering a path.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000106 *
bsalomon@google.com208236d2012-03-12 13:15:33 +0000107 * @return true if the path can be drawn by this object, false otherwise.
108 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700109 bool canDrawPath(const CanDrawPathArgs& args) const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700110 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700111 return this->onCanDrawPath(args);
112 }
113
114 /**
115 * Args to drawPath()
116 *
117 * fTarget The target that the path will be rendered to
118 * fResourceProvider The resource provider for creating gpu resources to render the path
119 * fPipelineBuilder The pipelineBuilder
cdalton862cff32016-05-12 15:09:48 -0700120 * fClip The clip
jvanverth512e4372015-11-23 11:50:02 -0800121 * fColor Color to render with
bsalomon0aff2fa2015-07-31 06:48:27 -0700122 * fViewMatrix The viewMatrix
bsalomon8acedde2016-06-24 10:42:16 -0700123 * fShape The shape to draw
Brian Salomon073285c2016-12-09 20:02:08 +0000124 * fAntiAlias true if anti-aliasing is required.
brianosman0e3c5542016-04-13 13:56:21 -0700125 * fGammaCorrect true if gamma-correct rendering is to be used.
bsalomon0aff2fa2015-07-31 06:48:27 -0700126 */
127 struct DrawPathArgs {
bsalomon0aff2fa2015-07-31 06:48:27 -0700128 GrResourceProvider* fResourceProvider;
robertphillips976f5f02016-06-03 10:59:20 -0700129 const GrPaint* fPaint;
130 const GrUserStencilSettings*fUserStencilSettings;
131
Brian Osman11052242016-10-27 14:47:55 -0400132 GrRenderTargetContext* fRenderTargetContext;
cdalton862cff32016-05-12 15:09:48 -0700133 const GrClip* fClip;
bsalomon0aff2fa2015-07-31 06:48:27 -0700134 const SkMatrix* fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700135 const GrShape* fShape;
Brian Salomon073285c2016-12-09 20:02:08 +0000136 bool fAntiAlias;
brianosman0e3c5542016-04-13 13:56:21 -0700137 bool fGammaCorrect;
bsalomon8acedde2016-06-24 10:42:16 -0700138#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700139 void validate() const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700140 SkASSERT(fResourceProvider);
robertphillips976f5f02016-06-03 10:59:20 -0700141 SkASSERT(fPaint);
142 SkASSERT(fUserStencilSettings);
Brian Osman11052242016-10-27 14:47:55 -0400143 SkASSERT(fRenderTargetContext);
cdalton862cff32016-05-12 15:09:48 -0700144 SkASSERT(fClip);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700145 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700146 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700147 }
bsalomon8acedde2016-06-24 10:42:16 -0700148#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700149 };
150
bsalomon@google.comee435122011-07-01 14:57:55 +0000151 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000152 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
bsalomon0aff2fa2015-07-31 06:48:27 -0700153 * the subclass must respect the stencil settings of the GrPipelineBuilder.
bsalomon@google.comee435122011-07-01 14:57:55 +0000154 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700155 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700156 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700157#ifdef SK_DEBUG
158 CanDrawPathArgs canArgs;
robertphillips976f5f02016-06-03 10:59:20 -0700159 canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps();
bsalomon0aff2fa2015-07-31 06:48:27 -0700160 canArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700161 canArgs.fShape = args.fShape;
Brian Salomon073285c2016-12-09 20:02:08 +0000162 canArgs.fAntiAlias = args.fAntiAlias;
robertphillips68737822015-10-29 12:12:21 -0700163
robertphillips976f5f02016-06-03 10:59:20 -0700164 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
Brian Salomon073285c2016-12-09 20:02:08 +0000165 canArgs.fIsStencilBufferMSAA = 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 Salomon073285c2016-12-09 20:02:08 +0000183 * fIsAA Is the path to be drawn AA (only set when MSAA is available)
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 Salomon073285c2016-12-09 20:02:08 +0000190 bool fIsAA;
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());
bsalomon8acedde2016-06-24 10:42:16 -0700200 SkPath path;
201 fShape->asPath(&path);
202 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -0700203 }
bsalomon8acedde2016-06-24 10:42:16 -0700204#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700205 };
206
bsalomon@google.comee435122011-07-01 14:57:55 +0000207 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000208 * Draws the path to the stencil buffer. Assume the writable stencil bits are already
209 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000210 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700211 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700212 SkDEBUGCODE(args.validate();)
bsalomon8acedde2016-06-24 10:42:16 -0700213 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
bsalomon0aff2fa2015-07-31 06:48:27 -0700214 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000215 }
216
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000217 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
218 // If we can, we draw lots faster (raster device does this same test).
bsalomon6663acf2016-05-10 09:14:17 -0700219 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000220 SkScalar* outCoverage) {
bsalomon6663acf2016-05-10 09:14:17 -0700221 if (style.pathEffect()) {
kkinnunen18996512015-04-26 23:18:49 -0700222 return false;
223 }
bsalomon6663acf2016-05-10 09:14:17 -0700224 const SkStrokeRec& stroke = style.strokeRec();
kkinnunend156d362015-05-18 22:23:54 -0700225 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700226 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000227 *outCoverage = SK_Scalar1;
228 }
229 return true;
230 }
kkinnunend156d362015-05-18 22:23:54 -0700231 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
232 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000233 }
234
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000235protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000236 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
237 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
238 static void GetPathDevBounds(const SkPath& path,
239 int devW,
240 int devH,
241 const SkMatrix& matrix,
242 SkRect* bounds);
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 */
bsalomon8acedde2016-06-24 10:42:16 -0700248 virtual StencilSupport onGetStencilSupport(const GrShape&) 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) {
cdalton93a379b2016-05-11 13:58:08 -0700267 static constexpr GrUserStencilSettings kIncrementStencil(
268 GrUserStencilSettings::StaticInit<
269 0xffff,
270 GrUserStencilTest::kAlways,
271 0xffff,
272 GrUserStencilOp::kReplace,
273 GrUserStencilOp::kReplace,
274 0xffff>()
275 );
robertphillips976f5f02016-06-03 10:59:20 -0700276
277 GrPaint paint;
278
bsalomon0aff2fa2015-07-31 06:48:27 -0700279 DrawPathArgs drawArgs;
bsalomon0aff2fa2015-07-31 06:48:27 -0700280 drawArgs.fResourceProvider = args.fResourceProvider;
robertphillips976f5f02016-06-03 10:59:20 -0700281 drawArgs.fPaint = &paint;
282 drawArgs.fUserStencilSettings = &kIncrementStencil;
Brian Osman11052242016-10-27 14:47:55 -0400283 drawArgs.fRenderTargetContext = args.fRenderTargetContext;
bsalomon0aff2fa2015-07-31 06:48:27 -0700284 drawArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700285 drawArgs.fShape = args.fShape;
Brian Salomon073285c2016-12-09 20:02:08 +0000286 drawArgs.fAntiAlias = false; // In this case the MSAA handles the AA so we want to draw BW
brianosman0e3c5542016-04-13 13:56:21 -0700287 drawArgs.fGammaCorrect = false;
bsalomon0aff2fa2015-07-31 06:48:27 -0700288 this->drawPath(drawArgs);
289 }
290
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000291 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000292};
293
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000294#endif