blob: a4e32acff3f20278062638e3e2042607e3b74a43 [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
bsalomon@google.comded4f4b2012-06-28 18:48:06 +00008#include "GrStencilAndCoverPathRenderer.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -07009#include "GrCaps.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000010#include "GrContext.h"
Brian Salomon82c263f2016-12-15 09:54:06 -050011#include "GrDrawPathOp.h"
csmartdalton02fa32c2016-08-19 13:29:27 -070012#include "GrFixedClip.h"
bsalomoneb1cb5c2015-05-22 08:01:09 -070013#include "GrGpu.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000014#include "GrPath.h"
bsalomonbb243832016-07-22 07:10:19 -070015#include "GrPipelineBuilder.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080016#include "GrRenderTarget.h"
Brian Salomon6a639042016-12-14 11:08:17 -050017#include "GrRenderTargetContextPriv.h"
bsalomond309e7a2015-04-30 14:18:54 -070018#include "GrResourceProvider.h"
Brian Salomon82c263f2016-12-15 09:54:06 -050019#include "GrStencilPathOp.h"
bsalomon6663acf2016-05-10 09:14:17 -070020#include "GrStyle.h"
Brian Salomon89527432016-12-16 09:52:16 -050021#include "ops/GrRectOpFactory.h"
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000022
bsalomon706f08f2015-05-22 07:35:58 -070023GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
24 const GrCaps& caps) {
25 if (caps.shaderCaps()->pathRenderingSupport()) {
halcanary385fe4d2015-08-26 13:07:48 -070026 return new GrStencilAndCoverPathRenderer(resourceProvider);
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000027 } else {
halcanary96fcdcc2015-08-27 07:41:13 -070028 return nullptr;
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000029 }
30}
31
bsalomon706f08f2015-05-22 07:35:58 -070032GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
halcanary9d524f22016-03-29 09:03:52 -070033 : fResourceProvider(resourceProvider) {
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000034}
35
bsalomon0aff2fa2015-07-31 06:48:27 -070036bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
bsalomonee432412016-06-27 07:18:18 -070037 // GrPath doesn't support hairline paths. An arbitrary path effect could produce a hairline
38 // path.
39 if (args.fShape->style().strokeRec().isHairlineStyle() ||
40 args.fShape->style().hasNonDashPathEffect()) {
vbuzinovdded6962015-06-12 08:59:45 -070041 return false;
42 }
cdalton93a379b2016-05-11 13:58:08 -070043 if (args.fHasUserStencilSettings) {
vbuzinovdded6962015-06-12 08:59:45 -070044 return false;
45 }
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050046 // doesn't do per-path AA, relies on the target having MSAA.
47 return (GrAAType::kCoverage != args.fAAType);
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000048}
49
bsalomon7bffcd22016-09-15 13:55:33 -070050static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
bsalomon8718aaf2015-02-19 07:24:21 -080051 GrUniqueKey key;
kkinnunen070e0102015-05-21 00:37:30 -070052 bool isVolatile;
bsalomon7bffcd22016-09-15 13:55:33 -070053 GrPath::ComputeKey(shape, &key, &isVolatile);
54 sk_sp<GrPath> path;
55 if (!isVolatile) {
56 path.reset(
57 static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
58 }
bsalomon706f08f2015-05-22 07:35:58 -070059 if (!path) {
bsalomon7bffcd22016-09-15 13:55:33 -070060 SkPath skPath;
61 shape.asPath(&skPath);
62 path.reset(resourceProvider->createPath(skPath, shape.style()));
kkinnunen070e0102015-05-21 00:37:30 -070063 if (!isVolatile) {
bsalomon7bffcd22016-09-15 13:55:33 -070064 resourceProvider->assignUniqueKeyToResource(key, path.get());
kkinnunen070e0102015-05-21 00:37:30 -070065 }
kkinnunen50b58e62015-05-18 23:02:07 -070066 } else {
bsalomon7bffcd22016-09-15 13:55:33 -070067#ifdef SK_DEBUG
68 SkPath skPath;
69 shape.asPath(&skPath);
70 SkASSERT(path->isEqualTo(skPath, shape.style()));
71#endif
cdalton4e205b12014-09-17 09:41:24 -070072 }
mtklein18300a32016-03-16 13:53:35 -070073 return path.release();
cdalton4e205b12014-09-17 09:41:24 -070074}
75
bsalomon0aff2fa2015-07-31 06:48:27 -070076void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -040077 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
joshualittde83b412016-01-14 09:58:36 -080078 "GrStencilAndCoverPathRenderer::onStencilPath");
Hal Canary144caf52016-11-07 17:57:18 -050079 sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
Brian Salomon0e8fc8b2016-12-09 15:10:07 -050080 args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
Hal Canary144caf52016-11-07 17:57:18 -050081 *args.fViewMatrix, p.get());
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000082}
83
bsalomon0aff2fa2015-07-31 06:48:27 -070084bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -040085 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
joshualittde83b412016-01-14 09:58:36 -080086 "GrStencilAndCoverPathRenderer::onDrawPath");
bsalomon8acedde2016-06-24 10:42:16 -070087 SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
88
bsalomon0aff2fa2015-07-31 06:48:27 -070089 const SkMatrix& viewMatrix = *args.fViewMatrix;
90
bsalomon8acedde2016-06-24 10:42:16 -070091
Hal Canary144caf52016-11-07 17:57:18 -050092 sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
bsalomon@google.com0f11e1a2012-10-08 14:48:36 +000093
bsalomona224bb72016-10-03 09:48:22 -070094 if (args.fShape->inverseFilled()) {
joshualittd27f73e2014-12-29 07:43:36 -080095 SkMatrix invert = SkMatrix::I();
egdaniel8dd688b2015-01-22 10:16:09 -080096 SkRect bounds =
robertphillips976f5f02016-06-03 10:59:20 -070097 SkRect::MakeLTRB(0, 0,
Brian Osman11052242016-10-27 14:47:55 -040098 SkIntToScalar(args.fRenderTargetContext->width()),
99 SkIntToScalar(args.fRenderTargetContext->height()));
joshualitt92e496f2014-10-31 13:56:50 -0700100 SkMatrix vmi;
101 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800102 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
joshualitt92e496f2014-10-31 13:56:50 -0700103 vmi.mapRect(&bounds);
104 // theoretically could set bloat = 0, instead leave it because of matrix inversion
105 // precision.
joshualitt8059eb92014-12-29 15:10:07 -0800106 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
joshualitt92e496f2014-10-31 13:56:50 -0700107 bounds.outset(bloat, bloat);
108 } else {
joshualitt8059eb92014-12-29 15:10:07 -0800109 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800110 return false;
111 }
joshualitt92e496f2014-10-31 13:56:50 -0700112 }
joshualitt8059eb92014-12-29 15:10:07 -0800113 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
joshualitt04194f32016-01-13 10:08:27 -0800114
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400115 std::unique_ptr<GrLegacyMeshDrawOp> coverOp(GrRectOpFactory::MakeNonAAFill(
Brian Salomon82f44312017-01-11 13:42:54 -0500116 args.fPaint.getColor(), viewM, bounds, nullptr, &invert));
robertphillips976f5f02016-06-03 10:59:20 -0700117
csmartdalton5c6fc4f2016-08-12 15:11:51 -0700118 // fake inverse with a stencil and cover
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500119 args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix,
120 path.get());
csmartdalton5c6fc4f2016-08-12 15:11:51 -0700121
bsalomonbb243832016-07-22 07:10:19 -0700122 {
csmartdalton5c6fc4f2016-08-12 15:11:51 -0700123 static constexpr GrUserStencilSettings kInvertedCoverPass(
124 GrUserStencilSettings::StaticInit<
125 0x0000,
126 // We know our rect will hit pixels outside the clip and the user bits will
127 // be 0 outside the clip. So we can't just fill where the user bits are 0. We
128 // also need to check that the clip bit is set.
129 GrUserStencilTest::kEqualIfInClip,
130 0xffff,
131 GrUserStencilOp::kKeep,
132 GrUserStencilOp::kZero,
133 0xffff>()
134 );
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500135 // We have to suppress enabling MSAA for mixed samples or we will get seams due to
136 // coverage modulation along the edge where two triangles making up the rect meet.
137 GrAAType coverAAType = args.fAAType;
138 if (GrAAType::kMixedSamples == coverAAType) {
139 coverAAType = GrAAType::kNone;
140 }
Brian Salomon82f44312017-01-11 13:42:54 -0500141 GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), coverAAType);
bsalomonbb243832016-07-22 07:10:19 -0700142 pipelineBuilder.setUserStencil(&kInvertedCoverPass);
143
Brian Salomone14bd802017-04-04 15:13:25 -0400144 args.fRenderTargetContext->addLegacyMeshDrawOp(std::move(pipelineBuilder), *args.fClip,
Brian Salomond3ccb0a2017-04-03 10:38:00 -0400145 std::move(coverOp));
bsalomonbb243832016-07-22 07:10:19 -0700146 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000147 } else {
Brian Salomon5dac9b32017-04-08 02:53:30 +0000148 GrAA aa = GrBoolToAA(GrAATypeIsHW(args.fAAType));
Brian Salomonf8334782017-01-03 09:42:58 -0500149 std::unique_ptr<GrDrawOp> op =
Brian Salomon5dac9b32017-04-08 02:53:30 +0000150 GrDrawPathOp::Make(viewMatrix, std::move(args.fPaint), aa, path.get());
Brian Salomon54d212e2017-03-21 14:22:38 -0400151 args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000152 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000153
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000154 return true;
155}