blob: 1309dedd4c3c073ed60b5bd51ad964d3fb2be81d [file] [log] [blame]
bsalomon@google.comded4f4b2012-06-28 18:48:06 +00001/*
2 * Copyright 2012 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.
6 */
7
8
9#include "GrStencilAndCoverPathRenderer.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070010#include "GrCaps.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000011#include "GrContext.h"
cdalton8ff8d242015-12-08 10:20:32 -080012#include "GrDrawPathBatch.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070013#include "GrGpu.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000014#include "GrPath.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080015#include "GrRenderTarget.h"
bsalomond309e7a2015-04-30 14:18:54 -070016#include "GrResourceProvider.h"
bsalomon6663acf2016-05-10 09:14:17 -070017#include "GrStyle.h"
joshualitt04194f32016-01-13 10:08:27 -080018#include "batches/GrRectBatchFactory.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000019
bsalomon706f08f2015-05-22 07:35:58 -070020GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
21 const GrCaps& caps) {
22 if (caps.shaderCaps()->pathRenderingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -070023 return new GrStencilAndCoverPathRenderer(resourceProvider);
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000024 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070025 return nullptr;
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000026 }
27}
28
bsalomon706f08f2015-05-22 07:35:58 -070029GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
halcanary9d524f22016-03-29 09:03:52 -070030 : fResourceProvider(resourceProvider) {
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000031}
32
bsalomon0aff2fa2015-07-31 06:48:27 -070033bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bsalomon6663acf2016-05-10 09:14:17 -070034 // GrPath doesn't support hairline paths. Also, an arbitrary path effect could change
35 // the style type to hairline.
bsalomonc1216072016-05-10 11:57:04 -070036 if (args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
vbuzinovdded6962015-06-12 08:59:45 -070037 return false;
38 }
cdalton12dbb392016-05-10 14:23:01 -070039 if (args.fHasUserStencilSettings) {
vbuzinovdded6962015-06-12 08:59:45 -070040 return false;
41 }
bsalomon0aff2fa2015-07-31 06:48:27 -070042 if (args.fAntiAlias) {
robertphillips68737822015-10-29 12:12:21 -070043 return args.fIsStencilBufferMSAA;
vbuzinovdded6962015-06-12 08:59:45 -070044 } else {
45 return true; // doesn't do per-path AA, relies on the target having MSAA
46 }
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000047}
48
bsalomon706f08f2015-05-22 07:35:58 -070049static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
bsalomon6663acf2016-05-10 09:14:17 -070050 const GrStyle& style) {
bsalomon8718aaf2015-02-19 07:24:21 -080051 GrUniqueKey key;
kkinnunen070e0102015-05-21 00:37:30 -070052 bool isVolatile;
bsalomon6663acf2016-05-10 09:14:17 -070053 GrPath::ComputeKey(skPath, style, &key, &isVolatile);
bsalomond309e7a2015-04-30 14:18:54 -070054 SkAutoTUnref<GrPath> path(
bsalomon706f08f2015-05-22 07:35:58 -070055 static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
56 if (!path) {
bsalomon6663acf2016-05-10 09:14:17 -070057 path.reset(resourceProvider->createPath(skPath, style));
kkinnunen070e0102015-05-21 00:37:30 -070058 if (!isVolatile) {
bsalomon706f08f2015-05-22 07:35:58 -070059 resourceProvider->assignUniqueKeyToResource(key, path);
kkinnunen070e0102015-05-21 00:37:30 -070060 }
kkinnunen50b58e62015-05-18 23:02:07 -070061 } else {
bsalomon6663acf2016-05-10 09:14:17 -070062 SkASSERT(path->isEqualTo(skPath, style));
cdalton4e205b12014-09-17 09:41:24 -070063 }
mtklein18300a32016-03-16 13:53:35 -070064 return path.release();
cdalton4e205b12014-09-17 09:41:24 -070065}
66
bsalomon0aff2fa2015-07-31 06:48:27 -070067void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
joshualittde83b412016-01-14 09:58:36 -080068 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
69 "GrStencilAndCoverPathRenderer::onStencilPath");
bsalomon0aff2fa2015-07-31 06:48:27 -070070 SkASSERT(!args.fPath->isInverseFillType());
bsalomon6663acf2016-05-10 09:14:17 -070071 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, GrStyle::SimpleFill()));
kkinnunenc6e7a132015-12-07 23:39:01 -080072 args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000073}
74
bsalomon0aff2fa2015-07-31 06:48:27 -070075bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
joshualittde83b412016-01-14 09:58:36 -080076 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
77 "GrStencilAndCoverPathRenderer::onDrawPath");
bsalomon6663acf2016-05-10 09:14:17 -070078 SkASSERT(!args.fStyle->strokeRec().isHairlineStyle());
bsalomon0aff2fa2015-07-31 06:48:27 -070079 const SkPath& path = *args.fPath;
80 GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
81 const SkMatrix& viewMatrix = *args.fViewMatrix;
82
cdalton12dbb392016-05-10 14:23:01 -070083 SkASSERT(!pipelineBuilder->hasUserStencilSettings());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000084
bsalomon0aff2fa2015-07-31 06:48:27 -070085 if (args.fAntiAlias) {
vbuzinovdded6962015-06-12 08:59:45 -070086 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
87 pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
88 }
89
bsalomon6663acf2016-05-10 09:14:17 -070090 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +000091
commit-bot@chromium.org6803c212014-05-04 18:08:27 +000092 if (path.isInverseFillType()) {
cdalton12dbb392016-05-10 14:23:01 -070093 static constexpr GrUserStencilSettings kInvertedCoverPass(
94 GrUserStencilSettings::StaticInit<
95 0x0000,
96 // We know our rect will hit pixels outside the clip and the user bits will be 0
97 // outside the clip. So we can't just fill where the user bits are 0. We also need
98 // to check that the clip bit is set.
99 GrUserStencilTest::kEqualIfInClip,
100 0xffff,
101 GrUserStencilOp::kKeep,
102 GrUserStencilOp::kZero,
103 0xffff>()
104 );
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000105
cdalton12dbb392016-05-10 14:23:01 -0700106
107 pipelineBuilder->setUserStencil(&kInvertedCoverPass);
joshualitt92e496f2014-10-31 13:56:50 -0700108
109 // fake inverse with a stencil and cover
kkinnunenc6e7a132015-12-07 23:39:01 -0800110 args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
joshualitt92e496f2014-10-31 13:56:50 -0700111
joshualittd27f73e2014-12-29 07:43:36 -0800112 SkMatrix invert = SkMatrix::I();
egdaniel8dd688b2015-01-22 10:16:09 -0800113 SkRect bounds =
114 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
115 SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
joshualitt92e496f2014-10-31 13:56:50 -0700116 SkMatrix vmi;
117 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800118 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
joshualitt92e496f2014-10-31 13:56:50 -0700119 vmi.mapRect(&bounds);
120 // theoretically could set bloat = 0, instead leave it because of matrix inversion
121 // precision.
joshualitt8059eb92014-12-29 15:10:07 -0800122 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
joshualitt92e496f2014-10-31 13:56:50 -0700123 bounds.outset(bloat, bloat);
124 } else {
joshualitt8059eb92014-12-29 15:10:07 -0800125 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800126 return false;
127 }
joshualitt92e496f2014-10-31 13:56:50 -0700128 }
joshualitt8059eb92014-12-29 15:10:07 -0800129 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
cdalton3aea7252015-11-12 09:18:49 -0800130 if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
131 pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
132 }
joshualitt04194f32016-01-13 10:08:27 -0800133
134 SkAutoTUnref<GrDrawBatch> batch(
135 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
136 &invert));
137 args.fTarget->drawBatch(*pipelineBuilder, batch);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000138 } else {
cdalton12dbb392016-05-10 14:23:01 -0700139 static constexpr GrUserStencilSettings kCoverPass(
140 GrUserStencilSettings::StaticInit<
141 0x0000,
142 GrUserStencilTest::kNotEqual,
143 0xffff,
144 GrUserStencilOp::kZero,
145 GrUserStencilOp::kKeep,
146 0xffff>()
147 );
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000148
cdalton12dbb392016-05-10 14:23:01 -0700149 pipelineBuilder->setUserStencil(&kCoverPass);
cdalton8ff8d242015-12-08 10:20:32 -0800150 SkAutoTUnref<GrDrawPathBatchBase> batch(
151 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
152 args.fTarget->drawPathBatch(*pipelineBuilder, batch);
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000153 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000154
cdalton12dbb392016-05-10 14:23:01 -0700155 pipelineBuilder->disableUserStencil();
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000156 return true;
157}