blob: e60bea215a702fffc7eb56729def2c3acb8048be [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;
bsalomon24db3b12015-01-23 04:24:04 -080078 GrPath::ComputeKey(skPath, stroke, &key);
bsalomond309e7a2015-04-30 14:18:54 -070079 SkAutoTUnref<GrPath> path(
80 static_cast<GrPath*>(ctx->resourceProvider()->findAndRefResourceByUniqueKey(key)));
kkinnunen50b58e62015-05-18 23:02:07 -070081 if (NULL == path) {
cdalton4e205b12014-09-17 09:41:24 -070082 path.reset(gpu->pathRendering()->createPath(skPath, stroke));
bsalomond309e7a2015-04-30 14:18:54 -070083 ctx->resourceProvider()->assignUniqueKeyToResource(key, path);
kkinnunen50b58e62015-05-18 23:02:07 -070084 } else {
85 SkASSERT(path->isEqualTo(skPath, stroke));
cdalton4e205b12014-09-17 09:41:24 -070086 }
87 return path.detach();
88}
89
joshualitt9853cce2014-11-17 14:22:48 -080090void GrStencilAndCoverPathRenderer::onStencilPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -080091 GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -080092 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -080093 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -070094 const GrStrokeInfo& stroke) {
robertphillips@google.come79f3202014-02-11 16:30:21 +000095 SkASSERT(!path.isInverseFillType());
joshualitt8059eb92014-12-29 15:10:07 -080096 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix));
kkinnunend156d362015-05-18 22:23:54 -070097 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
egdaniel8dd688b2015-01-22 10:16:09 -080098 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000099}
100
joshualitt9853cce2014-11-17 14:22:48 -0800101bool GrStencilAndCoverPathRenderer::onDrawPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800102 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800103 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800104 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800105 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -0700106 const GrStrokeInfo& stroke,
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +0000107 bool antiAlias) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000108 SkASSERT(!antiAlias);
kkinnunend156d362015-05-18 22:23:54 -0700109 SkASSERT(!stroke.isHairlineStyle());
egdaniel8dd688b2015-01-22 10:16:09 -0800110 SkASSERT(pipelineBuilder->getStencil().isDisabled());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000111
kkinnunend156d362015-05-18 22:23:54 -0700112 SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke));
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +0000113
commit-bot@chromium.org6803c212014-05-04 18:08:27 +0000114 if (path.isInverseFillType()) {
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000115 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
116 kZero_StencilOp,
117 kZero_StencilOp,
bsalomon@google.com05a718c2012-06-29 14:01:53 +0000118 // We know our rect will hit pixels outside the clip and the user bits will be 0
119 // outside the clip. So we can't just fill where the user bits are 0. We also need to
120 // check that the clip bit is set.
121 kEqualIfInClip_StencilFunc,
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000122 0xffff,
123 0x0000,
124 0xffff);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000125
egdaniel8dd688b2015-01-22 10:16:09 -0800126 pipelineBuilder->setStencil(kInvertedStencilPass);
joshualitt92e496f2014-10-31 13:56:50 -0700127
128 // fake inverse with a stencil and cover
joshualitt8059eb92014-12-29 15:10:07 -0800129 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(GrColor_WHITE, viewMatrix));
egdaniel8dd688b2015-01-22 10:16:09 -0800130 target->stencilPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
joshualitt92e496f2014-10-31 13:56:50 -0700131
joshualittd27f73e2014-12-29 07:43:36 -0800132 SkMatrix invert = SkMatrix::I();
egdaniel8dd688b2015-01-22 10:16:09 -0800133 SkRect bounds =
134 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
135 SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
joshualitt92e496f2014-10-31 13:56:50 -0700136 SkMatrix vmi;
137 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800138 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
joshualitt92e496f2014-10-31 13:56:50 -0700139 vmi.mapRect(&bounds);
140 // theoretically could set bloat = 0, instead leave it because of matrix inversion
141 // precision.
joshualitt8059eb92014-12-29 15:10:07 -0800142 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
joshualitt92e496f2014-10-31 13:56:50 -0700143 bounds.outset(bloat, bloat);
144 } else {
joshualitt8059eb92014-12-29 15:10:07 -0800145 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800146 return false;
147 }
joshualitt92e496f2014-10-31 13:56:50 -0700148 }
joshualitt8059eb92014-12-29 15:10:07 -0800149 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
egdaniel8dd688b2015-01-22 10:16:09 -0800150 target->drawRect(pipelineBuilder, color, viewM, bounds, NULL, &invert);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000151 } else {
152 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
153 kZero_StencilOp,
154 kZero_StencilOp,
155 kNotEqual_StencilFunc,
156 0xffff,
157 0x0000,
158 0xffff);
159
egdaniel8dd688b2015-01-22 10:16:09 -0800160 pipelineBuilder->setStencil(kStencilPass);
joshualitt8059eb92014-12-29 15:10:07 -0800161 SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(color, viewMatrix));
egdaniel8dd688b2015-01-22 10:16:09 -0800162 target->drawPath(pipelineBuilder, pp, p, convert_skpath_filltype(path.getFillType()));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000163 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000164
egdaniel8dd688b2015-01-22 10:16:09 -0800165 pipelineBuilder->stencil()->setDisabled();
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000166 return true;
167}