1
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 "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrDrawPathBatch.h"
14 #include "GrGpu.h"
15 #include "GrPath.h"
16 #include "GrRenderTarget.h"
17 #include "GrResourceProvider.h"
18 #include "GrStrokeInfo.h"
19 #include "batches/GrRectBatchFactory.h"
20
Create(GrResourceProvider * resourceProvider,const GrCaps & caps)21 GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
22 const GrCaps& caps) {
23 if (caps.shaderCaps()->pathRenderingSupport()) {
24 return new GrStencilAndCoverPathRenderer(resourceProvider);
25 } else {
26 return nullptr;
27 }
28 }
29
GrStencilAndCoverPathRenderer(GrResourceProvider * resourceProvider)30 GrStencilAndCoverPathRenderer::GrStencilAndCoverPathRenderer(GrResourceProvider* resourceProvider)
31 : fResourceProvider(resourceProvider) {
32 }
33
onCanDrawPath(const CanDrawPathArgs & args) const34 bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
35 if (args.fStroke->isHairlineStyle()) {
36 return false;
37 }
38 if (!args.fIsStencilDisabled) {
39 return false;
40 }
41 if (args.fAntiAlias) {
42 return args.fIsStencilBufferMSAA;
43 } else {
44 return true; // doesn't do per-path AA, relies on the target having MSAA
45 }
46 }
47
get_gr_path(GrResourceProvider * resourceProvider,const SkPath & skPath,const GrStrokeInfo & stroke)48 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const SkPath& skPath,
49 const GrStrokeInfo& stroke) {
50 GrUniqueKey key;
51 bool isVolatile;
52 GrPath::ComputeKey(skPath, stroke, &key, &isVolatile);
53 SkAutoTUnref<GrPath> path(
54 static_cast<GrPath*>(resourceProvider->findAndRefResourceByUniqueKey(key)));
55 if (!path) {
56 path.reset(resourceProvider->createPath(skPath, stroke));
57 if (!isVolatile) {
58 resourceProvider->assignUniqueKeyToResource(key, path);
59 }
60 } else {
61 SkASSERT(path->isEqualTo(skPath, stroke));
62 }
63 return path.detach();
64 }
65
onStencilPath(const StencilPathArgs & args)66 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
67 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
68 "GrStencilAndCoverPathRenderer::onStencilPath");
69 SkASSERT(!args.fPath->isInverseFillType());
70 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, *args.fPath, *args.fStroke));
71 args.fTarget->stencilPath(*args.fPipelineBuilder, *args.fViewMatrix, p, p->getFillType());
72 }
73
onDrawPath(const DrawPathArgs & args)74 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
75 GR_AUDIT_TRAIL_AUTO_FRAME(args.fTarget->getAuditTrail(),
76 "GrStencilAndCoverPathRenderer::onDrawPath");
77 SkASSERT(!args.fStroke->isHairlineStyle());
78 const SkPath& path = *args.fPath;
79 GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
80 const SkMatrix& viewMatrix = *args.fViewMatrix;
81
82 SkASSERT(pipelineBuilder->getStencil().isDisabled());
83
84 if (args.fAntiAlias) {
85 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
86 pipelineBuilder->enableState(GrPipelineBuilder::kHWAntialias_Flag);
87 }
88
89 SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStroke));
90
91 if (path.isInverseFillType()) {
92 GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
93 kKeep_StencilOp,
94 kZero_StencilOp,
95 // We know our rect will hit pixels outside the clip and the user bits will be 0
96 // outside the clip. So we can't just fill where the user bits are 0. We also need to
97 // check that the clip bit is set.
98 kEqualIfInClip_StencilFunc,
99 0xffff,
100 0x0000,
101 0xffff);
102
103 pipelineBuilder->setStencil(kInvertedStencilPass);
104
105 // fake inverse with a stencil and cover
106 args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
107
108 SkMatrix invert = SkMatrix::I();
109 SkRect bounds =
110 SkRect::MakeLTRB(0, 0, SkIntToScalar(pipelineBuilder->getRenderTarget()->width()),
111 SkIntToScalar(pipelineBuilder->getRenderTarget()->height()));
112 SkMatrix vmi;
113 // mapRect through persp matrix may not be correct
114 if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
115 vmi.mapRect(&bounds);
116 // theoretically could set bloat = 0, instead leave it because of matrix inversion
117 // precision.
118 SkScalar bloat = viewMatrix.getMaxScale() * SK_ScalarHalf;
119 bounds.outset(bloat, bloat);
120 } else {
121 if (!viewMatrix.invert(&invert)) {
122 return false;
123 }
124 }
125 const SkMatrix& viewM = viewMatrix.hasPerspective() ? SkMatrix::I() : viewMatrix;
126 if (pipelineBuilder->getRenderTarget()->hasMixedSamples()) {
127 pipelineBuilder->disableState(GrPipelineBuilder::kHWAntialias_Flag);
128 }
129
130 SkAutoTUnref<GrDrawBatch> batch(
131 GrRectBatchFactory::CreateNonAAFill(args.fColor, viewM, bounds, nullptr,
132 &invert));
133 args.fTarget->drawBatch(*pipelineBuilder, batch);
134 } else {
135 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
136 kZero_StencilOp,
137 kKeep_StencilOp,
138 kNotEqual_StencilFunc,
139 0xffff,
140 0x0000,
141 0xffff);
142
143 pipelineBuilder->setStencil(kStencilPass);
144 SkAutoTUnref<GrDrawPathBatchBase> batch(
145 GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
146 args.fTarget->drawPathBatch(*pipelineBuilder, batch);
147 }
148
149 pipelineBuilder->stencil()->setDisabled();
150 return true;
151 }
152