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