blob: 4a7fb92e9f568cf64ea4cd98625cbacd8bb58b2f [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"
bsalomon8acedde2016-06-24 10:42:16 -070014#include "GrShape.h"
Robert Phillips646e4292017-06-13 12:44:56 -040015#include "GrUserStencilSettings.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.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000026 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000027class SK_API GrPathRenderer : public SkRefCnt {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000028public:
bsalomon@google.comc2099d22012-03-02 21:26:50 +000029 GrPathRenderer();
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000030
31 /**
bsalomon@google.com45a15f52012-12-10 19:10:17 +000032 * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
33 * the path renderer itself may require use of the stencil buffer. Also a path renderer may
joshualittb0a8a372014-09-23 09:50:21 -070034 * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
35 * covered by bounding geometry but outside the path. These exterior pixels would still be
36 * rendered into the stencil.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000037 *
38 * A GrPathRenderer can provide three levels of support for stenciling paths:
Brian Salomone5b399e2017-07-19 13:50:54 -040039 * 1) kNoRestriction: This is the most general. The caller passes a GrPaint and calls drawPath().
40 * The path is rendered exactly as the draw state indicates including support
41 * for simultaneous color and stenciling with arbitrary stenciling rules.
42 * Pixels partially covered by AA paths are affected by the stencil settings.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000043 * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
44 * simultaneously. The path renderer does support the stencilPath() function
45 * which performs no color writes and writes a non-zero stencil value to pixels
46 * covered by the path.
47 * 3) kNoSupport: This path renderer cannot be used to stencil the path.
48 */
robertphillips68737822015-10-29 12:12:21 -070049 enum StencilSupport {
50 kNoSupport_StencilSupport,
51 kStencilOnly_StencilSupport,
52 kNoRestriction_StencilSupport,
53 };
bsalomon@google.com45a15f52012-12-10 19:10:17 +000054
55 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +000056 * This function is to get the stencil support for a particular path. The path's fill must
bsalomond6f25bf2016-05-05 09:26:21 -070057 * not be an inverse type. The path will always be filled and not stroked.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000058 *
bsalomon8acedde2016-06-24 10:42:16 -070059 * @param shape the shape that will be drawn. Must be simple fill styled and non-inverse
60 * filled.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000061 */
bsalomon8acedde2016-06-24 10:42:16 -070062 StencilSupport getStencilSupport(const GrShape& shape) const {
63 SkDEBUGCODE(SkPath path;)
64 SkDEBUGCODE(shape.asPath(&path);)
65 SkASSERT(shape.style().isSimpleFill());
robertphillips@google.come79f3202014-02-11 16:30:21 +000066 SkASSERT(!path.isInverseFillType());
bsalomon8acedde2016-06-24 10:42:16 -070067 return this->onGetStencilSupport(shape);
bsalomon@google.comc2099d22012-03-02 21:26:50 +000068 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000069
Chris Dalton5ed44232017-09-07 13:22:46 -060070 enum class CanDrawPath {
71 kNo,
72 kAsBackup, // i.e. This renderer is better than SW fallback if no others can draw the path.
73 kYes
74 };
75
bsalomon0aff2fa2015-07-31 06:48:27 -070076 struct CanDrawPathArgs {
Chris Daltondb91c6e2017-09-08 16:25:08 -060077 SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
78
Eric Karl5c779752017-05-08 12:02:07 -070079 const GrCaps* fCaps;
Chris Daltondb91c6e2017-09-08 16:25:08 -060080 const SkIRect* fClipConservativeBounds;
bsalomon0aff2fa2015-07-31 06:48:27 -070081 const SkMatrix* fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -070082 const GrShape* fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050083 GrAAType fAAType;
robertphillipse7d4b2f2015-08-13 07:57:10 -070084
robertphillips68737822015-10-29 12:12:21 -070085 // These next two are only used by GrStencilAndCoverPathRenderer
cdalton93a379b2016-05-11 13:58:08 -070086 bool fHasUserStencilSettings;
robertphillips68737822015-10-29 12:12:21 -070087
bsalomon8acedde2016-06-24 10:42:16 -070088#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -070089 void validate() const {
Eric Karl5c779752017-05-08 12:02:07 -070090 SkASSERT(fCaps);
Chris Daltondb91c6e2017-09-08 16:25:08 -060091 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -070092 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -070093 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -070094 }
bsalomon8acedde2016-06-24 10:42:16 -070095#endif
bsalomon0aff2fa2015-07-31 06:48:27 -070096 };
97
bsalomon@google.com208236d2012-03-12 13:15:33 +000098 /**
Chris Dalton5ed44232017-09-07 13:22:46 -060099 * Returns how well this path renderer is able to render the given path. Returning kNo or
100 * kAsBackup allows the caller to keep searching for a better path renderer. This function is
101 * called when searching for the best path renderer to draw a path.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000102 */
Chris Dalton5ed44232017-09-07 13:22:46 -0600103 CanDrawPath canDrawPath(const CanDrawPathArgs& args) const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700104 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700105 return this->onCanDrawPath(args);
106 }
107
bsalomon0aff2fa2015-07-31 06:48:27 -0700108 struct DrawPathArgs {
Robert Phillips256c37b2017-03-01 14:32:46 -0500109 GrContext* fContext;
Brian Salomon82f44312017-01-11 13:42:54 -0500110 GrPaint&& fPaint;
111 const GrUserStencilSettings* fUserStencilSettings;
112 GrRenderTargetContext* fRenderTargetContext;
113 const GrClip* fClip;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600114 const SkIRect* fClipConservativeBounds;
Brian Salomon82f44312017-01-11 13:42:54 -0500115 const SkMatrix* fViewMatrix;
116 const GrShape* fShape;
117 GrAAType fAAType;
118 bool fGammaCorrect;
bsalomon8acedde2016-06-24 10:42:16 -0700119#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700120 void validate() const {
Robert Phillips256c37b2017-03-01 14:32:46 -0500121 SkASSERT(fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700122 SkASSERT(fUserStencilSettings);
Brian Osman11052242016-10-27 14:47:55 -0400123 SkASSERT(fRenderTargetContext);
cdalton862cff32016-05-12 15:09:48 -0700124 SkASSERT(fClip);
Chris Daltondb91c6e2017-09-08 16:25:08 -0600125 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700126 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700127 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700128 }
bsalomon8acedde2016-06-24 10:42:16 -0700129#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700130 };
131
bsalomon@google.comee435122011-07-01 14:57:55 +0000132 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000133 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
Brian Salomone5b399e2017-07-19 13:50:54 -0400134 * the subclass must respect the stencil settings.
bsalomon@google.comee435122011-07-01 14:57:55 +0000135 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700136 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700137 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700138#ifdef SK_DEBUG
139 CanDrawPathArgs canArgs;
Eric Karl5c779752017-05-08 12:02:07 -0700140 canArgs.fCaps = args.fContext->caps();
Chris Daltondb91c6e2017-09-08 16:25:08 -0600141 canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
bsalomon0aff2fa2015-07-31 06:48:27 -0700142 canArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700143 canArgs.fShape = args.fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500144 canArgs.fAAType = args.fAAType;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600145 canArgs.validate();
robertphillips68737822015-10-29 12:12:21 -0700146
robertphillips976f5f02016-06-03 10:59:20 -0700147 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500148 SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
Brian Salomon7c8460e2017-05-12 11:36:10 -0400149 GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType()));
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500150 SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
Brian Salomon7c8460e2017-05-12 11:36:10 -0400151 GrFSAAType::kMixedSamples != args.fRenderTargetContext->fsaaType()));
Chris Dalton5ed44232017-09-07 13:22:46 -0600152 SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
robertphillips976f5f02016-06-03 10:59:20 -0700153 if (!args.fUserStencilSettings->isUnused()) {
bsalomon8acedde2016-06-24 10:42:16 -0700154 SkPath path;
155 args.fShape->asPath(&path);
156 SkASSERT(args.fShape->style().isSimpleFill());
157 SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
bsalomond6f25bf2016-05-05 09:26:21 -0700158 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700159#endif
160 return this->onDrawPath(args);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000161 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000162
Chris Daltondb91c6e2017-09-08 16:25:08 -0600163 /**
164 * Args to stencilPath(). fAAType cannot be kCoverage.
bsalomon0aff2fa2015-07-31 06:48:27 -0700165 */
166 struct StencilPathArgs {
Chris Daltondb91c6e2017-09-08 16:25:08 -0600167 SkDEBUGCODE(StencilPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
168
Robert Phillips256c37b2017-03-01 14:32:46 -0500169 GrContext* fContext;
Brian Osman11052242016-10-27 14:47:55 -0400170 GrRenderTargetContext* fRenderTargetContext;
171 const GrClip* fClip;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600172 const SkIRect* fClipConservativeBounds;
Brian Osman11052242016-10-27 14:47:55 -0400173 const SkMatrix* fViewMatrix;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500174 GrAAType fAAType;
Brian Osman11052242016-10-27 14:47:55 -0400175 const GrShape* fShape;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700176
bsalomon8acedde2016-06-24 10:42:16 -0700177#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700178 void validate() const {
Robert Phillips256c37b2017-03-01 14:32:46 -0500179 SkASSERT(fContext);
Brian Osman11052242016-10-27 14:47:55 -0400180 SkASSERT(fRenderTargetContext);
Chris Daltondb91c6e2017-09-08 16:25:08 -0600181 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700182 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700183 SkASSERT(fShape);
caryclarkd6562002016-07-27 12:02:07 -0700184 SkASSERT(fShape->style().isSimpleFill());
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500185 SkASSERT(GrAAType::kCoverage != fAAType);
bsalomon8acedde2016-06-24 10:42:16 -0700186 SkPath path;
187 fShape->asPath(&path);
188 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -0700189 }
bsalomon8acedde2016-06-24 10:42:16 -0700190#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700191 };
192
bsalomon@google.comee435122011-07-01 14:57:55 +0000193 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000194 * Draws the path to the stencil buffer. Assume the writable stencil bits are already
195 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000196 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700197 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700198 SkDEBUGCODE(args.validate();)
bsalomon8acedde2016-06-24 10:42:16 -0700199 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
bsalomon0aff2fa2015-07-31 06:48:27 -0700200 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000201 }
202
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000203 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
204 // If we can, we draw lots faster (raster device does this same test).
bsalomon6663acf2016-05-10 09:14:17 -0700205 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000206 SkScalar* outCoverage) {
bsalomon6663acf2016-05-10 09:14:17 -0700207 if (style.pathEffect()) {
kkinnunen18996512015-04-26 23:18:49 -0700208 return false;
209 }
bsalomon6663acf2016-05-10 09:14:17 -0700210 const SkStrokeRec& stroke = style.strokeRec();
kkinnunend156d362015-05-18 22:23:54 -0700211 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700212 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000213 *outCoverage = SK_Scalar1;
214 }
215 return true;
216 }
kkinnunend156d362015-05-18 22:23:54 -0700217 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
218 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000219 }
220
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000221protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000222 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
223 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
224 static void GetPathDevBounds(const SkPath& path,
225 int devW,
226 int devH,
227 const SkMatrix& matrix,
228 SkRect* bounds);
229
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000230private:
bsalomon0aff2fa2015-07-31 06:48:27 -0700231 /**
232 * Subclass overrides if it has any limitations of stenciling support.
233 */
bsalomon8acedde2016-06-24 10:42:16 -0700234 virtual StencilSupport onGetStencilSupport(const GrShape&) const {
bsalomon0aff2fa2015-07-31 06:48:27 -0700235 return kNoRestriction_StencilSupport;
236 }
237
238 /**
239 * Subclass implementation of drawPath()
240 */
241 virtual bool onDrawPath(const DrawPathArgs& args) = 0;
242
243 /**
244 * Subclass implementation of canDrawPath()
245 */
Chris Dalton5ed44232017-09-07 13:22:46 -0600246 virtual CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const = 0;
bsalomon0aff2fa2015-07-31 06:48:27 -0700247
248 /**
249 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
250 * kStencilOnly in onGetStencilSupport().
251 */
252 virtual void onStencilPath(const StencilPathArgs& args) {
cdalton93a379b2016-05-11 13:58:08 -0700253 static constexpr GrUserStencilSettings kIncrementStencil(
254 GrUserStencilSettings::StaticInit<
255 0xffff,
256 GrUserStencilTest::kAlways,
257 0xffff,
258 GrUserStencilOp::kReplace,
259 GrUserStencilOp::kReplace,
260 0xffff>()
261 );
robertphillips976f5f02016-06-03 10:59:20 -0700262
263 GrPaint paint;
Robert Phillips256c37b2017-03-01 14:32:46 -0500264 DrawPathArgs drawArgs{args.fContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500265 std::move(paint),
266 &kIncrementStencil,
267 args.fRenderTargetContext,
268 nullptr, // clip
Chris Daltondb91c6e2017-09-08 16:25:08 -0600269 args.fClipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -0500270 args.fViewMatrix,
271 args.fShape,
272 args.fAAType,
273 false};
bsalomon0aff2fa2015-07-31 06:48:27 -0700274 this->drawPath(drawArgs);
275 }
276
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000277 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000278};
279
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000280#endif