blob: c5a1f63fa1060a0d39b3dcdad57e494b0c233403 [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;
Chris Dalton4c92d4a2017-11-06 13:48:04 -070022class GrHardClip;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000023struct GrPoint;
24
25/**
Robert Phillipsf2361d22016-10-25 14:20:06 -040026 * Base class for drawing paths into a GrOpList.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000027 */
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000028class SK_API GrPathRenderer : public SkRefCnt {
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000029public:
bsalomon@google.comc2099d22012-03-02 21:26:50 +000030 GrPathRenderer();
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000031
32 /**
bsalomon@google.com45a15f52012-12-10 19:10:17 +000033 * A caller may wish to use a path renderer to draw a path into the stencil buffer. However,
34 * the path renderer itself may require use of the stencil buffer. Also a path renderer may
joshualittb0a8a372014-09-23 09:50:21 -070035 * use a GrProcessor coverage stage that sets coverage to zero to eliminate pixels that are
36 * covered by bounding geometry but outside the path. These exterior pixels would still be
37 * rendered into the stencil.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000038 *
39 * A GrPathRenderer can provide three levels of support for stenciling paths:
Brian Salomone5b399e2017-07-19 13:50:54 -040040 * 1) kNoRestriction: This is the most general. The caller passes a GrPaint and calls drawPath().
41 * The path is rendered exactly as the draw state indicates including support
42 * for simultaneous color and stenciling with arbitrary stenciling rules.
43 * Pixels partially covered by AA paths are affected by the stencil settings.
bsalomon@google.com45a15f52012-12-10 19:10:17 +000044 * 2) kStencilOnly: The path renderer cannot apply arbitrary stencil rules nor shade and stencil
45 * simultaneously. The path renderer does support the stencilPath() function
46 * which performs no color writes and writes a non-zero stencil value to pixels
47 * covered by the path.
48 * 3) kNoSupport: This path renderer cannot be used to stencil the path.
49 */
robertphillips68737822015-10-29 12:12:21 -070050 enum StencilSupport {
51 kNoSupport_StencilSupport,
52 kStencilOnly_StencilSupport,
53 kNoRestriction_StencilSupport,
54 };
bsalomon@google.com45a15f52012-12-10 19:10:17 +000055
56 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +000057 * This function is to get the stencil support for a particular path. The path's fill must
bsalomond6f25bf2016-05-05 09:26:21 -070058 * not be an inverse type. The path will always be filled and not stroked.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000059 *
bsalomon8acedde2016-06-24 10:42:16 -070060 * @param shape the shape that will be drawn. Must be simple fill styled and non-inverse
61 * filled.
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000062 */
bsalomon8acedde2016-06-24 10:42:16 -070063 StencilSupport getStencilSupport(const GrShape& shape) const {
64 SkDEBUGCODE(SkPath path;)
65 SkDEBUGCODE(shape.asPath(&path);)
66 SkASSERT(shape.style().isSimpleFill());
robertphillips@google.come79f3202014-02-11 16:30:21 +000067 SkASSERT(!path.isInverseFillType());
bsalomon8acedde2016-06-24 10:42:16 -070068 return this->onGetStencilSupport(shape);
bsalomon@google.comc2099d22012-03-02 21:26:50 +000069 }
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +000070
Chris Dalton5ed44232017-09-07 13:22:46 -060071 enum class CanDrawPath {
72 kNo,
73 kAsBackup, // i.e. This renderer is better than SW fallback if no others can draw the path.
74 kYes
75 };
76
bsalomon0aff2fa2015-07-31 06:48:27 -070077 struct CanDrawPathArgs {
Chris Daltondb91c6e2017-09-08 16:25:08 -060078 SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
79
Eric Karl5c779752017-05-08 12:02:07 -070080 const GrCaps* fCaps;
Chris Daltondb91c6e2017-09-08 16:25:08 -060081 const SkIRect* fClipConservativeBounds;
bsalomon0aff2fa2015-07-31 06:48:27 -070082 const SkMatrix* fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -070083 const GrShape* fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050084 GrAAType fAAType;
robertphillipse7d4b2f2015-08-13 07:57:10 -070085
robertphillips68737822015-10-29 12:12:21 -070086 // These next two are only used by GrStencilAndCoverPathRenderer
cdalton93a379b2016-05-11 13:58:08 -070087 bool fHasUserStencilSettings;
robertphillips68737822015-10-29 12:12:21 -070088
bsalomon8acedde2016-06-24 10:42:16 -070089#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -070090 void validate() const {
Eric Karl5c779752017-05-08 12:02:07 -070091 SkASSERT(fCaps);
Chris Daltondb91c6e2017-09-08 16:25:08 -060092 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -070093 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -070094 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -070095 }
bsalomon8acedde2016-06-24 10:42:16 -070096#endif
bsalomon0aff2fa2015-07-31 06:48:27 -070097 };
98
bsalomon@google.com208236d2012-03-12 13:15:33 +000099 /**
Chris Dalton5ed44232017-09-07 13:22:46 -0600100 * Returns how well this path renderer is able to render the given path. Returning kNo or
101 * kAsBackup allows the caller to keep searching for a better path renderer. This function is
102 * called when searching for the best path renderer to draw a path.
bsalomon@google.com208236d2012-03-12 13:15:33 +0000103 */
Chris Dalton5ed44232017-09-07 13:22:46 -0600104 CanDrawPath canDrawPath(const CanDrawPathArgs& args) const {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700105 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700106 return this->onCanDrawPath(args);
107 }
108
bsalomon0aff2fa2015-07-31 06:48:27 -0700109 struct DrawPathArgs {
Robert Phillips256c37b2017-03-01 14:32:46 -0500110 GrContext* fContext;
Brian Salomon82f44312017-01-11 13:42:54 -0500111 GrPaint&& fPaint;
112 const GrUserStencilSettings* fUserStencilSettings;
113 GrRenderTargetContext* fRenderTargetContext;
114 const GrClip* fClip;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600115 const SkIRect* fClipConservativeBounds;
Brian Salomon82f44312017-01-11 13:42:54 -0500116 const SkMatrix* fViewMatrix;
117 const GrShape* fShape;
118 GrAAType fAAType;
119 bool fGammaCorrect;
bsalomon8acedde2016-06-24 10:42:16 -0700120#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700121 void validate() const {
Robert Phillips256c37b2017-03-01 14:32:46 -0500122 SkASSERT(fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700123 SkASSERT(fUserStencilSettings);
Brian Osman11052242016-10-27 14:47:55 -0400124 SkASSERT(fRenderTargetContext);
cdalton862cff32016-05-12 15:09:48 -0700125 SkASSERT(fClip);
Chris Daltondb91c6e2017-09-08 16:25:08 -0600126 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700127 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700128 SkASSERT(fShape);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700129 }
bsalomon8acedde2016-06-24 10:42:16 -0700130#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700131 };
132
bsalomon@google.comee435122011-07-01 14:57:55 +0000133 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000134 * Draws the path into the draw target. If getStencilSupport() would return kNoRestriction then
Brian Salomone5b399e2017-07-19 13:50:54 -0400135 * the subclass must respect the stencil settings.
bsalomon@google.comee435122011-07-01 14:57:55 +0000136 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700137 bool drawPath(const DrawPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700138 SkDEBUGCODE(args.validate();)
bsalomon0aff2fa2015-07-31 06:48:27 -0700139#ifdef SK_DEBUG
140 CanDrawPathArgs canArgs;
Eric Karl5c779752017-05-08 12:02:07 -0700141 canArgs.fCaps = args.fContext->caps();
Chris Daltondb91c6e2017-09-08 16:25:08 -0600142 canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
bsalomon0aff2fa2015-07-31 06:48:27 -0700143 canArgs.fViewMatrix = args.fViewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -0700144 canArgs.fShape = args.fShape;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500145 canArgs.fAAType = args.fAAType;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600146 canArgs.validate();
robertphillips68737822015-10-29 12:12:21 -0700147
robertphillips976f5f02016-06-03 10:59:20 -0700148 canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500149 SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
Brian Salomon7c8460e2017-05-12 11:36:10 -0400150 GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType()));
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500151 SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
Brian Salomon7c8460e2017-05-12 11:36:10 -0400152 GrFSAAType::kMixedSamples != args.fRenderTargetContext->fsaaType()));
Chris Dalton5ed44232017-09-07 13:22:46 -0600153 SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
robertphillips976f5f02016-06-03 10:59:20 -0700154 if (!args.fUserStencilSettings->isUnused()) {
bsalomon8acedde2016-06-24 10:42:16 -0700155 SkPath path;
156 args.fShape->asPath(&path);
157 SkASSERT(args.fShape->style().isSimpleFill());
158 SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fShape));
bsalomond6f25bf2016-05-05 09:26:21 -0700159 }
bsalomon0aff2fa2015-07-31 06:48:27 -0700160#endif
161 return this->onDrawPath(args);
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000162 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000163
Chris Daltondb91c6e2017-09-08 16:25:08 -0600164 /**
165 * Args to stencilPath(). fAAType cannot be kCoverage.
bsalomon0aff2fa2015-07-31 06:48:27 -0700166 */
167 struct StencilPathArgs {
Chris Daltondb91c6e2017-09-08 16:25:08 -0600168 SkDEBUGCODE(StencilPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
169
Robert Phillips256c37b2017-03-01 14:32:46 -0500170 GrContext* fContext;
Brian Osman11052242016-10-27 14:47:55 -0400171 GrRenderTargetContext* fRenderTargetContext;
Chris Dalton4c92d4a2017-11-06 13:48:04 -0700172 const GrHardClip* fClip;
Chris Daltondb91c6e2017-09-08 16:25:08 -0600173 const SkIRect* fClipConservativeBounds;
Brian Osman11052242016-10-27 14:47:55 -0400174 const SkMatrix* fViewMatrix;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500175 GrAAType fAAType;
Brian Osman11052242016-10-27 14:47:55 -0400176 const GrShape* fShape;
robertphillipse7d4b2f2015-08-13 07:57:10 -0700177
bsalomon8acedde2016-06-24 10:42:16 -0700178#ifdef SK_DEBUG
robertphillipse7d4b2f2015-08-13 07:57:10 -0700179 void validate() const {
Robert Phillips256c37b2017-03-01 14:32:46 -0500180 SkASSERT(fContext);
Brian Osman11052242016-10-27 14:47:55 -0400181 SkASSERT(fRenderTargetContext);
Chris Daltondb91c6e2017-09-08 16:25:08 -0600182 SkASSERT(fClipConservativeBounds);
robertphillipse7d4b2f2015-08-13 07:57:10 -0700183 SkASSERT(fViewMatrix);
bsalomon8acedde2016-06-24 10:42:16 -0700184 SkASSERT(fShape);
caryclarkd6562002016-07-27 12:02:07 -0700185 SkASSERT(fShape->style().isSimpleFill());
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500186 SkASSERT(GrAAType::kCoverage != fAAType);
bsalomon8acedde2016-06-24 10:42:16 -0700187 SkPath path;
188 fShape->asPath(&path);
189 SkASSERT(!path.isInverseFillType());
robertphillipse7d4b2f2015-08-13 07:57:10 -0700190 }
bsalomon8acedde2016-06-24 10:42:16 -0700191#endif
bsalomon0aff2fa2015-07-31 06:48:27 -0700192 };
193
bsalomon@google.comee435122011-07-01 14:57:55 +0000194 /**
robertphillips@google.come79f3202014-02-11 16:30:21 +0000195 * Draws the path to the stencil buffer. Assume the writable stencil bits are already
196 * initialized to zero. The pixels inside the path will have non-zero stencil values afterwards.
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000197 */
bsalomon0aff2fa2015-07-31 06:48:27 -0700198 void stencilPath(const StencilPathArgs& args) {
robertphillipse7d4b2f2015-08-13 07:57:10 -0700199 SkDEBUGCODE(args.validate();)
bsalomon8acedde2016-06-24 10:42:16 -0700200 SkASSERT(kNoSupport_StencilSupport != this->getStencilSupport(*args.fShape));
bsalomon0aff2fa2015-07-31 06:48:27 -0700201 this->onStencilPath(args);
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000202 }
203
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000204 // Helper for determining if we can treat a thin stroke as a hairline w/ coverage.
205 // If we can, we draw lots faster (raster device does this same test).
bsalomon6663acf2016-05-10 09:14:17 -0700206 static bool IsStrokeHairlineOrEquivalent(const GrStyle& style, const SkMatrix& matrix,
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000207 SkScalar* outCoverage) {
bsalomon6663acf2016-05-10 09:14:17 -0700208 if (style.pathEffect()) {
kkinnunen18996512015-04-26 23:18:49 -0700209 return false;
210 }
bsalomon6663acf2016-05-10 09:14:17 -0700211 const SkStrokeRec& stroke = style.strokeRec();
kkinnunend156d362015-05-18 22:23:54 -0700212 if (stroke.isHairlineStyle()) {
bsalomon49f085d2014-09-05 13:34:00 -0700213 if (outCoverage) {
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000214 *outCoverage = SK_Scalar1;
215 }
216 return true;
217 }
kkinnunend156d362015-05-18 22:23:54 -0700218 return stroke.getStyle() == SkStrokeRec::kStroke_Style &&
219 SkDrawTreatAAStrokeAsHairline(stroke.getWidth(), matrix, outCoverage);
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +0000220 }
221
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000222protected:
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000223 // Helper for getting the device bounds of a path. Inverse filled paths will have bounds set
224 // by devSize. Non-inverse path bounds will not necessarily be clipped to devSize.
225 static void GetPathDevBounds(const SkPath& path,
226 int devW,
227 int devH,
228 const SkMatrix& matrix,
229 SkRect* bounds);
230
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000231private:
bsalomon0aff2fa2015-07-31 06:48:27 -0700232 /**
233 * Subclass overrides if it has any limitations of stenciling support.
234 */
bsalomon8acedde2016-06-24 10:42:16 -0700235 virtual StencilSupport onGetStencilSupport(const GrShape&) const {
bsalomon0aff2fa2015-07-31 06:48:27 -0700236 return kNoRestriction_StencilSupport;
237 }
238
239 /**
240 * Subclass implementation of drawPath()
241 */
242 virtual bool onDrawPath(const DrawPathArgs& args) = 0;
243
244 /**
245 * Subclass implementation of canDrawPath()
246 */
Chris Dalton5ed44232017-09-07 13:22:46 -0600247 virtual CanDrawPath onCanDrawPath(const CanDrawPathArgs& args) const = 0;
bsalomon0aff2fa2015-07-31 06:48:27 -0700248
249 /**
250 * Subclass implementation of stencilPath(). Subclass must override iff it ever returns
251 * kStencilOnly in onGetStencilSupport().
252 */
253 virtual void onStencilPath(const StencilPathArgs& args) {
cdalton93a379b2016-05-11 13:58:08 -0700254 static constexpr GrUserStencilSettings kIncrementStencil(
255 GrUserStencilSettings::StaticInit<
256 0xffff,
257 GrUserStencilTest::kAlways,
258 0xffff,
259 GrUserStencilOp::kReplace,
260 GrUserStencilOp::kReplace,
261 0xffff>()
262 );
robertphillips976f5f02016-06-03 10:59:20 -0700263
264 GrPaint paint;
Robert Phillips256c37b2017-03-01 14:32:46 -0500265 DrawPathArgs drawArgs{args.fContext,
Brian Salomon82f44312017-01-11 13:42:54 -0500266 std::move(paint),
267 &kIncrementStencil,
268 args.fRenderTargetContext,
269 nullptr, // clip
Chris Daltondb91c6e2017-09-08 16:25:08 -0600270 args.fClipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -0500271 args.fViewMatrix,
272 args.fShape,
273 args.fAAType,
274 false};
bsalomon0aff2fa2015-07-31 06:48:27 -0700275 this->drawPath(drawArgs);
276 }
277
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000278 typedef SkRefCnt INHERITED;
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000279};
280
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +0000281#endif