blob: 97b20773a7e0e6797d1e7f60d38937fe1d749c86 [file] [log] [blame]
bsalomon@google.comded4f4b2012-06-28 18:48:06 +00001
2/*
3 * Copyright 2012 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.
7 */
8
9
10#include "GrStencilAndCoverPathRenderer.h"
11#include "GrContext.h"
bsalomon@google.comc26d94f2013-03-25 18:19:00 +000012#include "GrDrawTargetCaps.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000013#include "GrGpu.h"
14#include "GrPath.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080015#include "GrRenderTarget.h"
16#include "GrRenderTargetPriv.h"
bsalomond309e7a2015-04-30 14:18:54 -070017#include "GrResourceProvider.h"
kkinnunen18996512015-04-26 23:18:49 -070018#include "GrStrokeInfo.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000019
joshualitt92e496f2014-10-31 13:56:50 -070020/*
21 * For now paths only natively support winding and even odd fill types
22 */
23static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) {
24 switch (fill) {
25 default:
26 SkFAIL("Incomplete Switch\n");
27 case SkPath::kWinding_FillType:
28 case SkPath::kInverseWinding_FillType:
29 return GrPathRendering::kWinding_FillType;
30 case SkPath::kEvenOdd_FillType:
31 case SkPath::kInverseEvenOdd_FillType:
32 return GrPathRendering::kEvenOdd_FillType;
33 }
34}
35
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000036GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrContext* context) {
bsalomon49f085d2014-09-05 13:34:00 -070037 SkASSERT(context);
38 SkASSERT(context->getGpu());
jvanverthe9c0fc62015-04-29 11:18:05 -070039 if (context->getGpu()->caps()->shaderCaps()->pathRenderingSupport()) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +000040 return SkNEW_ARGS(GrStencilAndCoverPathRenderer, (context->getGpu()));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000041 } else {
42 return NULL;
43 }
44}
45
46GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrGpu* gpu) {
jvanverthe9c0fc62015-04-29 11:18:05 -070047 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000048 fGpu = gpu;
49 gpu->ref();
50}
51
52GrStencilAndCoverPathRenderer::~GrStencilAndCoverPathRenderer() {
53 fGpu->unref();
54}
55
joshualitt9853cce2014-11-17 14:22:48 -080056bool GrStencilAndCoverPathRenderer::canDrawPath(const GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -080057 const GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -080058 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -080059 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -070060 const GrStrokeInfo& stroke,
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000061 bool antiAlias) const {
kkinnunend156d362015-05-18 22:23:54 -070062 return !stroke.isHairlineStyle() &&
kkinnunen18996512015-04-26 23:18:49 -070063 !antiAlias && // doesn't do per-path AA, relies on the target having MSAA
64 pipelineBuilder->getStencil().isDisabled();
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000065}
66
joshualitt92e496f2014-10-31 13:56:50 -070067GrPathRenderer::StencilSupport
joshualitt9853cce2014-11-17 14:22:48 -080068GrStencilAndCoverPathRenderer::onGetStencilSupport(const GrDrawTarget*,
egdaniel8dd688b2015-01-22 10:16:09 -080069 const GrPipelineBuilder*,
joshualitt9853cce2014-11-17 14:22:48 -080070 const SkPath&,
kkinnunen18996512015-04-26 23:18:49 -070071 const GrStrokeInfo&) const {
bsalomon@google.com45a15f52012-12-10 19:10:17 +000072 return GrPathRenderer::kStencilOnly_StencilSupport;
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000073}
74
kkinnunen50b58e62015-05-18 23:02:07 -070075static GrPath* get_gr_path(GrGpu* gpu, const SkPath& skPath, const GrStrokeInfo& stroke) {
cdalton4e205b12014-09-17 09:41:24 -070076 GrContext* ctx = gpu->getContext();
bsalomon8718aaf2015-02-19 07:24:21 -080077 GrUniqueKey key;
kkinnunen070e0102015-05-21 00:37:30 -070078 bool isVolatile;
79 GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
bsalomond309e7a2015-04-30 14:18:54 -070080 SkAutoTUnref<GrPath> path(
81 static_cast<GrPath*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key)));
kkinnunen50b58e62015-05-18 23:02:07 -070082 if (NULL == path) {
cdalton4e205b12014-09-17 09:41:24 -070083 path.reset(gpu->pathRendering()->createPath(skPath, stroke));
kkinnunen070e0102015-05-21 00:37:30 -070084 if (!isVolatile) {
85 ctx->resourceProvider()->assignUniqueKeyToResource(key, path);
86 }
kkinnunen50b58e62015-05-18 23:02:07 -070087 } else {
88 SkASSERT(path->isEqualTo(skPath, stroke));
cdalton4e205b12014-09-17 09:41:24 -070089 }
90 return path.detach();
91}
92
joshualitt9853cce2014-11-17 14:22:48 -080093void GrStencilAndCoverPathRenderer::onStencilPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -080094 GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -080095 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -080096 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -070097 const GrStrokeInfo& stroke) {
robertphillips@google.come79f3202014-02-11 16:30:21 +000098 SkASSERT(!path.isInverseFillType());
joshualitt8059eb92014-12-29 15:10:07 -080099 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix));
kkinnunend156d362015-05-18 22:23:54 -0700100 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
egdaniel8dd688b2015-01-22 10:16:09 -0800101 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000102}
103
joshualitt9853cce2014-11-17 14:22:48 -0800104bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800105 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800106 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800107 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800108 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -0700109 const GrStrokeInfo& stroke,
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +0000110 bool antiAlias) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000111 SkASSERT(!antiAlias);
kkinnunend156d362015-05-18 22:23:54 -0700112 SkASSERT(!stroke.isHairlineStyle());
egdaniel8dd688b2015-01-22 10:16:09 -0800113 SkASSERT(pipelineBuilder->getStencil().isDisabled());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000114
kkinnunend156d362015-05-18 22:23:54 -0700115 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +0000116
commit-bot@chromium.org6803c212014-05-04 18:08:27 +0000117 if (path.isInverseFillType()) {
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000118 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
119 kZero_StencilOp,
120 kZero_StencilOp,
bsalomon@google.com05a718c2012-06-29 14:01:53 +0000121 // We know our rect will hit pixels outside the clip and the user bits will be 0
122 // outside the clip. So we can't just fill where the user bits are 0. We also need to
123 // check that the clip bit is set.
124 kEqualIfInClip_StencilFunc,
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000125 0xffff,
126 0x0000,
127 0xffff);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000128
egdaniel8dd688b2015-01-22 10:16:09 -0800129 pipelineBuilder->setStencil(kInvertedStencilPass);
joshualitt92e496f2014-10-31 13:56:50 -0700130
131 // fake inverse with a stencil and cover
joshualitt8059eb92014-12-29 15:10:07 -0800132 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix));
egdaniel8dd688b2015-01-22 10:16:09 -0800133 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
joshualitt92e496f2014-10-31 13:56:50 -0700134
joshualittd27f73e2014-12-29 07:43:36 -0800135 SkMatrix invert = SkMatrix::I();
egdaniel8dd688b2015-01-22 10:16:09 -0800136 SkRect bounds =
137 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
138 SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
joshualitt92e496f2014-10-31 13:56:50 -0700139 SkMatrix vmi;
140 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800141 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
joshualitt92e496f2014-10-31 13:56:50 -0700142 vmi.mapRect(&bounds);
143 // theoretically could set bloat = 0, instead leave it because of matrix inversion
144 // precision.
joshualitt8059eb92014-12-29 15:10:07 -0800145 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
joshualitt92e496f2014-10-31 13:56:50 -0700146 bounds.outset(bloat, bloat);
147 } else {
joshualitt8059eb92014-12-29 15:10:07 -0800148 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800149 return false;
150 }
joshualitt92e496f2014-10-31 13:56:50 -0700151 }
joshualitt8059eb92014-12-29 15:10:07 -0800152 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
egdaniel8dd688b2015-01-22 10:16:09 -0800153 target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000154 } else {
155 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
156 kZero_StencilOp,
157 kZero_StencilOp,
158 kNotEqual_StencilFunc,
159 0xffff,
160 0x0000,
161 0xffff);
162
egdaniel8dd688b2015-01-22 10:16:09 -0800163 pipelineBuilder->setStencil(kStencilPass);
joshualitt8059eb92014-12-29 15:10:07 -0800164 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color, viewMatrix));
egdaniel8dd688b2015-01-22 10:16:09 -0800165 target->drawPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000166 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000167
egdaniel8dd688b2015-01-22 10:16:09 -0800168 pipelineBuilder->stencil()->setDisabled();
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000169 return true;
170}