OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrClipMaskManager.h" | 8 #include "GrClipMaskManager.h" |
9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
11 #include "GrDrawTarget.h" | 11 #include "GrDrawTarget.h" |
12 #include "GrGpuResourcePriv.h" | 12 #include "GrGpuResourcePriv.h" |
13 #include "GrPaint.h" | 13 #include "GrPaint.h" |
14 #include "GrPathRenderer.h" | 14 #include "GrPathRenderer.h" |
15 #include "GrRenderTarget.h" | 15 #include "GrRenderTarget.h" |
16 #include "GrRenderTargetPriv.h" | 16 #include "GrRenderTargetPriv.h" |
17 #include "GrResourceProvider.h" | 17 #include "GrResourceProvider.h" |
18 #include "GrStencilAttachment.h" | 18 #include "GrStencilAttachment.h" |
19 #include "GrSWMaskHelper.h" | 19 #include "GrSWMaskHelper.h" |
20 #include "SkRasterClip.h" | 20 #include "SkRasterClip.h" |
21 #include "SkTLazy.h" | 21 #include "SkTLazy.h" |
22 #include "effects/GrConvexPolyEffect.h" | 22 #include "effects/GrConvexPolyEffect.h" |
23 #include "effects/GrPorterDuffXferProcessor.h" | 23 #include "effects/GrPorterDuffXferProcessor.h" |
24 #include "effects/GrRRectEffect.h" | 24 #include "effects/GrRRectEffect.h" |
25 #include "effects/GrTextureDomain.h" | 25 #include "effects/GrTextureDomain.h" |
26 | 26 |
27 typedef SkClipStack::Element Element; | 27 typedef SkClipStack::Element Element; |
28 | 28 |
29 //////////////////////////////////////////////////////////////////////////////// | 29 //////////////////////////////////////////////////////////////////////////////// |
30 namespace { | |
31 // set up the draw state to enable the aa clipping mask. Besides setting up the | 30 // set up the draw state to enable the aa clipping mask. Besides setting up the |
32 // stage matrix this also alters the vertex layout | 31 // stage matrix this also alters the vertex layout |
33 void setup_drawstate_aaclip(const GrPipelineBuilder& pipelineBuilder, | 32 static const GrFragmentProcessor* create_fp_for_mask(GrTexture* result, const Sk IRect &devBound) { |
34 GrTexture* result, | |
35 GrPipelineBuilder::AutoRestoreFragmentProcessorState * arfps, | |
36 const SkIRect &devBound) { | |
37 SkASSERT(arfps); | |
38 arfps->set(&pipelineBuilder); | |
39 | |
40 SkMatrix mat; | 33 SkMatrix mat; |
41 // We use device coords to compute the texture coordinates. We set our matri x to be a | 34 // We use device coords to compute the texture coordinates. We set our matri x to be a |
42 // translation to the devBound, and then a scaling matrix to normalized coor ds. | 35 // translation to the devBound, and then a scaling matrix to normalized coor ds. |
43 mat.setIDiv(result->width(), result->height()); | 36 mat.setIDiv(result->width(), result->height()); |
44 mat.preTranslate(SkIntToScalar(-devBound.fLeft), | 37 mat.preTranslate(SkIntToScalar(-devBound.fLeft), |
45 SkIntToScalar(-devBound.fTop)); | 38 SkIntToScalar(-devBound.fTop)); |
46 | 39 |
47 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 40 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
48 // This could be a long-lived effect that is cached with the alpha-mask. | 41 return GrTextureDomainEffect::Create(result, |
49 arfps->addCoverageFragmentProcessor( | 42 mat, |
50 GrTextureDomainEffect::Create(result, | 43 GrTextureDomain::MakeTexelDomain(result , domainTexels), |
51 mat, | 44 GrTextureDomain::kDecal_Mode, |
52 GrTextureDomain::MakeTexelDomain(result, d omainTexels), | 45 GrTextureParams::kNone_FilterMode, |
53 GrTextureDomain::kDecal_Mode, | 46 kDevice_GrCoordSet); |
54 GrTextureParams::kNone_FilterMode, | |
55 kDevice_GrCoordSet))->unref(); | |
56 } | 47 } |
57 | 48 |
58 bool path_needs_SW_renderer(GrContext* context, | 49 static bool path_needs_SW_renderer(GrContext* context, |
59 const GrDrawTarget* gpu, | 50 const GrDrawTarget* gpu, |
60 const GrPipelineBuilder& pipelineBuilder, | 51 const GrPipelineBuilder& pipelineBuilder, |
61 const SkMatrix& viewMatrix, | 52 const SkMatrix& viewMatrix, |
62 const SkPath& origPath, | 53 const SkPath& origPath, |
63 const GrStrokeInfo& stroke, | 54 const GrStrokeInfo& stroke, |
64 bool doAA) { | 55 bool doAA) { |
65 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b uffer | 56 // the gpu alpha mask will draw the inverse paths as non-inverse to a temp b uffer |
66 SkTCopyOnFirstWrite<SkPath> path(origPath); | 57 SkTCopyOnFirstWrite<SkPath> path(origPath); |
67 if (path->isInverseFillType()) { | 58 if (path->isInverseFillType()) { |
68 path.writable()->toggleInverseFillType(); | 59 path.writable()->toggleInverseFillType(); |
69 } | 60 } |
70 // last (false) parameter disallows use of the SW path renderer | 61 // last (false) parameter disallows use of the SW path renderer |
71 GrPathRendererChain::DrawType type = doAA ? | 62 GrPathRendererChain::DrawType type = doAA ? |
72 GrPathRendererChain::kColorAntiAlias_Dr awType : | 63 GrPathRendererChain::kColorAntiAlias_Dr awType : |
73 GrPathRendererChain::kColor_DrawType; | 64 GrPathRendererChain::kColor_DrawType; |
74 | 65 |
75 return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix , *path, stroke, | 66 return nullptr == context->getPathRenderer(gpu, &pipelineBuilder, viewMatrix , *path, stroke, |
76 false, type); | 67 false, type); |
77 } | 68 } |
78 } | |
79 | 69 |
80 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) | 70 GrClipMaskManager::GrClipMaskManager(GrDrawTarget* drawTarget) |
81 : fCurrClipMaskType(kNone_ClipMaskType) | 71 : fCurrClipMaskType(kNone_ClipMaskType) |
82 , fDrawTarget(drawTarget) | 72 , fDrawTarget(drawTarget) |
83 , fClipMode(kIgnoreClip_StencilClipMode) { | 73 , fClipMode(kIgnoreClip_StencilClipMode) { |
84 } | 74 } |
85 | 75 |
86 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con text(); } | 76 GrContext* GrClipMaskManager::getContext() { return fDrawTarget->cmmAccess().con text(); } |
87 | 77 |
88 /* | 78 /* |
(...skipping 23 matching lines...) Expand all Loading... | |
112 element->asPath(&path); | 102 element->asPath(&path); |
113 if (path_needs_SW_renderer(this->getContext(), fDrawTarget, pipeline Builder, translate, | 103 if (path_needs_SW_renderer(this->getContext(), fDrawTarget, pipeline Builder, translate, |
114 path, stroke, element->isAA())) { | 104 path, stroke, element->isAA())) { |
115 return true; | 105 return true; |
116 } | 106 } |
117 } | 107 } |
118 } | 108 } |
119 return false; | 109 return false; |
120 } | 110 } |
121 | 111 |
122 bool GrClipMaskManager::installClipEffects( | 112 const GrFragmentProcessor* GrClipMaskManager::getAnalyticClipProcessor( |
123 const GrPipelineBuilder& pipelineBuilder, | 113 const GrReducedClip::Ele mentList& elements, |
124 GrPipelineBuilder::AutoRestoreFragmentProcessorState* arfps, | 114 const SkVector& clipToRT Offset, |
125 const GrReducedClip::ElementList& elements, | 115 const SkRect* drawBounds ) { |
126 const SkVector& clipToRTOffset, | |
127 const SkRect* drawBounds) { | |
128 SkRect boundsInClipSpace; | 116 SkRect boundsInClipSpace; |
129 if (drawBounds) { | 117 if (drawBounds) { |
130 boundsInClipSpace = *drawBounds; | 118 boundsInClipSpace = *drawBounds; |
131 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); | 119 boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); |
132 } | 120 } |
133 | 121 SkASSERT(elements.count() <= kMaxAnalyticElements); |
robertphillips
2015/10/07 13:06:43
Init this ('fps') to all 0s here and rm the "fps[f
bsalomon
2015/10/07 13:38:24
Done, but I don't think it improved safety as it i
robertphillips
2015/10/07 15:42:42
Yeah - I know it's just a sop but the fragility of
| |
134 arfps->set(&pipelineBuilder); | 122 const GrFragmentProcessor* fps[kMaxAnalyticElements]; |
135 GrRenderTarget* rt = pipelineBuilder.getRenderTarget(); | 123 int fpCnt = 0; |
136 GrReducedClip::ElementList::Iter iter(elements); | 124 GrReducedClip::ElementList::Iter iter(elements); |
137 bool failed = false; | 125 bool failed = false; |
138 while (iter.get()) { | 126 while (iter.get()) { |
139 SkRegion::Op op = iter.get()->getOp(); | 127 SkRegion::Op op = iter.get()->getOp(); |
140 bool invert; | 128 bool invert; |
141 bool skip = false; | 129 bool skip = false; |
142 switch (op) { | 130 switch (op) { |
143 case SkRegion::kReplace_Op: | 131 case SkRegion::kReplace_Op: |
144 SkASSERT(iter.get() == elements.head()); | 132 SkASSERT(iter.get() == elements.head()); |
145 // Fallthrough, handled same as intersect. | 133 // Fallthrough, handled same as intersect. |
(...skipping 10 matching lines...) Expand all Loading... | |
156 break; | 144 break; |
157 default: | 145 default: |
158 failed = true; | 146 failed = true; |
159 break; | 147 break; |
160 } | 148 } |
161 if (failed) { | 149 if (failed) { |
162 break; | 150 break; |
163 } | 151 } |
164 | 152 |
165 if (!skip) { | 153 if (!skip) { |
154 fps[fpCnt] = nullptr; | |
166 GrPrimitiveEdgeType edgeType; | 155 GrPrimitiveEdgeType edgeType; |
167 if (iter.get()->isAA()) { | 156 if (iter.get()->isAA()) { |
168 if (rt->isUnifiedMultisampled()) { | |
169 // Coverage based AA clips don't place nicely with MSAA. | |
170 failed = true; | |
171 break; | |
172 } | |
173 edgeType = | 157 edgeType = |
174 invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_Gr ProcessorEdgeType; | 158 invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProc essorEdgeType; |
175 } else { | 159 } else { |
176 edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : | 160 edgeType = |
177 kFillBW_GrProcessorEdgeType; | 161 invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProc essorEdgeType; |
178 } | 162 } |
179 SkAutoTUnref<GrFragmentProcessor> fp; | |
180 switch (iter.get()->getType()) { | 163 switch (iter.get()->getType()) { |
181 case SkClipStack::Element::kPath_Type: | 164 case SkClipStack::Element::kPath_Type: |
182 fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->ge tPath(), | 165 fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, iter.get() ->getPath(), |
183 &clipToRTOffset)); | 166 &clipToRTOffset); |
184 break; | 167 break; |
185 case SkClipStack::Element::kRRect_Type: { | 168 case SkClipStack::Element::kRRect_Type: { |
186 SkRRect rrect = iter.get()->getRRect(); | 169 SkRRect rrect = iter.get()->getRRect(); |
187 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 170 rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
188 fp.reset(GrRRectEffect::Create(edgeType, rrect)); | 171 fps[fpCnt] = GrRRectEffect::Create(edgeType, rrect); |
189 break; | 172 break; |
190 } | 173 } |
191 case SkClipStack::Element::kRect_Type: { | 174 case SkClipStack::Element::kRect_Type: { |
192 SkRect rect = iter.get()->getRect(); | 175 SkRect rect = iter.get()->getRect(); |
193 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); | 176 rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); |
194 fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); | 177 fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, rect); |
195 break; | 178 break; |
196 } | 179 } |
197 default: | 180 default: |
198 break; | 181 break; |
199 } | 182 } |
200 if (fp) { | 183 if (!fps[fpCnt]) { |
201 arfps->addCoverageFragmentProcessor(fp); | |
202 } else { | |
203 failed = true; | 184 failed = true; |
204 break; | 185 break; |
205 } | 186 } |
187 fpCnt++; | |
206 } | 188 } |
207 iter.next(); | 189 iter.next(); |
208 } | 190 } |
209 | 191 |
210 if (failed) { | 192 const GrFragmentProcessor* resultFP = nullptr; |
211 arfps->set(nullptr); | 193 if (!failed) { |
194 resultFP = GrFragmentProcessor::RunInSeries(fps, fpCnt); | |
212 } | 195 } |
213 return !failed; | 196 for (int i = 0; i < fpCnt; ++i) { |
197 fps[i]->unref(); | |
198 } | |
199 return resultFP; | |
214 } | 200 } |
215 | 201 |
216 //////////////////////////////////////////////////////////////////////////////// | 202 //////////////////////////////////////////////////////////////////////////////// |
217 // sort out what kind of clip mask needs to be created: alpha, stencil, | 203 // sort out what kind of clip mask needs to be created: alpha, stencil, |
218 // scissor, or entirely software | 204 // scissor, or entirely software |
219 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, | 205 bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder, |
220 GrPipelineBuilder::AutoRestoreFragmentProc essorState* arfps, | |
221 GrPipelineBuilder::AutoRestoreStencil* ars , | 206 GrPipelineBuilder::AutoRestoreStencil* ars , |
222 GrScissorState* scissorState, | 207 GrScissorState* scissorState, |
223 const SkRect* devBounds) { | 208 const SkRect* devBounds, |
209 GrAppliedClip* out) { | |
224 fCurrClipMaskType = kNone_ClipMaskType; | 210 fCurrClipMaskType = kNone_ClipMaskType; |
225 if (kRespectClip_StencilClipMode == fClipMode) { | 211 if (kRespectClip_StencilClipMode == fClipMode) { |
226 fClipMode = kIgnoreClip_StencilClipMode; | 212 fClipMode = kIgnoreClip_StencilClipMode; |
227 } | 213 } |
228 | 214 |
229 GrReducedClip::ElementList elements(16); | 215 GrReducedClip::ElementList elements(16); |
230 int32_t genID = 0; | 216 int32_t genID = 0; |
231 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat e; | 217 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat e; |
232 SkIRect clipSpaceIBounds; | 218 SkIRect clipSpaceIBounds; |
233 bool requiresAA = false; | 219 bool requiresAA = false; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
281 } | 267 } |
282 | 268 |
283 // An element count of 4 was chosen because of the common pattern in Blink o f: | 269 // An element count of 4 was chosen because of the common pattern in Blink o f: |
284 // isect RR | 270 // isect RR |
285 // diff RR | 271 // diff RR |
286 // isect convex_poly | 272 // isect convex_poly |
287 // isect convex_poly | 273 // isect convex_poly |
288 // when drawing rounded div borders. This could probably be tuned based on a | 274 // when drawing rounded div borders. This could probably be tuned based on a |
289 // configuration's relative costs of switching RTs to generate a mask vs | 275 // configuration's relative costs of switching RTs to generate a mask vs |
290 // longer shaders. | 276 // longer shaders. |
291 if (elements.count() <= 4) { | 277 if (elements.count() <= kMaxAnalyticElements) { |
292 SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), | 278 SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), |
293 SkIntToScalar(-clip.origin().fY) }; | 279 SkIntToScalar(-clip.origin().fY) }; |
280 // When there are multiple color samples we want to do per-sample clippi ng, not compute | |
281 // a fractional pixel coverage. | |
282 bool disallowAnalyticAA = pipelineBuilder.getRenderTarget()->isUnifiedMu ltisampled(); | |
283 const GrFragmentProcessor* clipFP = nullptr; | |
294 if (elements.isEmpty() || | 284 if (elements.isEmpty() || |
295 (requiresAA && this->installClipEffects(pipelineBuilder, arfps, elem ents, clipToRTOffset, | 285 (requiresAA && !disallowAnalyticAA && |
296 devBounds))) { | 286 SkToBool(clipFP = this->getAnalyticClipProcessor(elements, clipToRT Offset, devBounds)))) { |
297 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 287 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
298 scissorSpaceIBounds.offset(-clip.origin()); | 288 scissorSpaceIBounds.offset(-clip.origin()); |
299 if (nullptr == devBounds || | 289 if (nullptr == devBounds || |
300 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { | 290 !SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) { |
301 scissorState->set(scissorSpaceIBounds); | 291 scissorState->set(scissorSpaceIBounds); |
302 } | 292 } |
303 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 293 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
294 out->fClipCoverageFP.reset(clipFP); | |
304 return true; | 295 return true; |
305 } | 296 } |
306 } | 297 } |
307 | 298 |
308 // If MSAA is enabled we can do everything in the stencil buffer. | 299 // If MSAA is enabled we can do everything in the stencil buffer. |
309 if (0 == rt->numStencilSamples() && requiresAA) { | 300 if (0 == rt->numStencilSamples() && requiresAA) { |
310 SkAutoTUnref<GrTexture> result; | 301 SkAutoTUnref<GrTexture> result; |
311 | 302 |
312 // The top-left of the mask corresponds to the top-left corner of the bo unds. | 303 // The top-left of the mask corresponds to the top-left corner of the bo unds. |
313 SkVector clipToMaskOffset = { | 304 SkVector clipToMaskOffset = { |
(...skipping 11 matching lines...) Expand all Loading... | |
325 clipSpaceIBounds)); | 316 clipSpaceIBounds)); |
326 } else { | 317 } else { |
327 result.reset(this->createAlphaClipMask(genID, | 318 result.reset(this->createAlphaClipMask(genID, |
328 initialState, | 319 initialState, |
329 elements, | 320 elements, |
330 clipToMaskOffset, | 321 clipToMaskOffset, |
331 clipSpaceIBounds)); | 322 clipSpaceIBounds)); |
332 } | 323 } |
333 | 324 |
334 if (result) { | 325 if (result) { |
335 arfps->set(&pipelineBuilder); | |
336 // The mask's top left coord should be pinned to the rounded-out top left corner of | 326 // The mask's top left coord should be pinned to the rounded-out top left corner of |
337 // clipSpace bounds. We determine the mask's position WRT to the ren der target here. | 327 // clipSpace bounds. We determine the mask's position WRT to the ren der target here. |
338 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 328 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
339 rtSpaceMaskBounds.offset(-clip.origin()); | 329 rtSpaceMaskBounds.offset(-clip.origin()); |
340 setup_drawstate_aaclip(pipelineBuilder, result, arfps, rtSpaceMaskBo unds); | 330 out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBou nds)); |
341 this->setPipelineBuilderStencil(pipelineBuilder, ars); | 331 this->setPipelineBuilderStencil(pipelineBuilder, ars); |
342 return true; | 332 return true; |
343 } | 333 } |
344 // if alpha clip mask creation fails fall through to the non-AA code pat hs | 334 // if alpha clip mask creation fails fall through to the non-AA code pat hs |
345 } | 335 } |
346 | 336 |
347 // use the stencil clip if we can't represent the clip as a rectangle. | 337 // use the stencil clip if we can't represent the clip as a rectangle. |
348 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); | 338 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); |
349 this->createStencilClipMask(rt, | 339 this->createStencilClipMask(rt, |
350 genID, | 340 genID, |
(...skipping 781 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1132 | 1122 |
1133 //////////////////////////////////////////////////////////////////////////////// | 1123 //////////////////////////////////////////////////////////////////////////////// |
1134 | 1124 |
1135 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc ilAttachment, | 1125 void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stenc ilAttachment, |
1136 GrStencilSettings* settings) { | 1126 GrStencilSettings* settings) { |
1137 if (stencilAttachment) { | 1127 if (stencilAttachment) { |
1138 int stencilBits = stencilAttachment->bits(); | 1128 int stencilBits = stencilAttachment->bits(); |
1139 this->adjustStencilParams(settings, fClipMode, stencilBits); | 1129 this->adjustStencilParams(settings, fClipMode, stencilBits); |
1140 } | 1130 } |
1141 } | 1131 } |
OLD | NEW |