blob: 9d8d07de84b1aa3a88452313eeacf3b9e67a57b3 [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.
36 if (!args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
vbuzinovdded6962015-06-12 08:59:45 -070037 return false;
38 }
robertphillips68737822015-10-29 12:12:21 -070039 if (!args.fIsStencilDisabled) {
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
egdaniel8dd688b2015-01-22 10:16:09 -080083 SkASSERT(pipelineBuilder->getStencil().isDisabled());
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()) {
bsalomon3de75da2016-04-29 08:44:16 -070093 static constexpr GrStencilSettings kInvertedStencilPass(
vbuzinovc5d58f02015-08-21 05:24:24 -070094 kKeep_StencilOp,
bsalomon@google.comded4f4b2012-06-28 18:48:06 +000095 kZero_StencilOp,
bsalomon@google.com05a718c2012-06-29 14:01:53 +000096 // 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 to
98 // check that the clip bit is set.
99 kEqualIfInClip_StencilFunc,
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000100 0xffff,
101 0x0000,
102 0xffff);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000103
egdaniel8dd688b2015-01-22 10:16:09 -0800104 pipelineBuilder->setStencil(kInvertedStencilPass);
joshualitt92e496f2014-10-31 13:56:50 -0700105
106 // fake inverse with a stencil and cover
kkinnunenc6e7a132015-12-07 23:39:01 -0800107 args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
joshualitt92e496f2014-10-31 13:56:50 -0700108
joshualittd27f73e2014-12-29 07:43:36 -0800109 SkMatrix invert = SkMatrix::I();
egdaniel8dd688b2015-01-22 10:16:09 -0800110 SkRect bounds =
111 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
112 SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
joshualitt92e496f2014-10-31 13:56:50 -0700113 SkMatrix vmi;
114 // mapRect through persp matrix may not be correct
joshualitt8059eb92014-12-29 15:10:07 -0800115 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
joshualitt92e496f2014-10-31 13:56:50 -0700116 vmi.mapRect(&bounds);
117 // theoretically could set bloat = 0, instead leave it because of matrix inversion
118 // precision.
joshualitt8059eb92014-12-29 15:10:07 -0800119 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
joshualitt92e496f2014-10-31 13:56:50 -0700120 bounds.outset(bloat, bloat);
121 } else {
joshualitt8059eb92014-12-29 15:10:07 -0800122 if (!viewMatrix.invert(&invert)) {
joshualittd27f73e2014-12-29 07:43:36 -0800123 return false;
124 }
joshualitt92e496f2014-10-31 13:56:50 -0700125 }
joshualitt8059eb92014-12-29 15:10:07 -0800126 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
cdalton3aea7252015-11-12 09:18:49 -0800127 if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
128 pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
129 }
joshualitt04194f32016-01-13 10:08:27 -0800130
131 SkAutoTUnref<GrDrawBatch> batch(
132 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
133 &invert));
134 args.fTarget->drawBatch(*pipelineBuilder, batch);
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000135 } else {
bsalomon3de75da2016-04-29 08:44:16 -0700136 static constexpr GrStencilSettings kStencilPass(
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000137 kZero_StencilOp,
vbuzinovc5d58f02015-08-21 05:24:24 -0700138 kKeep_StencilOp,
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000139 kNotEqual_StencilFunc,
140 0xffff,
141 0x0000,
142 0xffff);
143
egdaniel8dd688b2015-01-22 10:16:09 -0800144 pipelineBuilder->setStencil(kStencilPass);
cdalton8ff8d242015-12-08 10:20:32 -0800145 SkAutoTUnref<GrDrawPathBatchBase> batch(
146 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
147 args.fTarget->drawPathBatch(*pipelineBuilder, batch);
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000148 }
commit-bot@chromium.orgc4dc0ad2013-10-09 14:11:33 +0000149
egdaniel8dd688b2015-01-22 10:16:09 -0800150 pipelineBuilder->stencil()->setDisabled();
bsalomon@google.comded4f4b2012-06-28 18:48:06 +0000151 return true;
152}