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 "GrClipStackClip.h" |
9 #include "GrCaps.h" | 9 #include "GrCaps.h" |
10 #include "GrDrawingManager.h" | 10 #include "GrDrawingManager.h" |
11 #include "GrDrawContextPriv.h" | 11 #include "GrDrawContextPriv.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 "batches/GrRectBatchFactory.h" | 22 #include "batches/GrRectBatchFactory.h" |
23 #include "effects/GrConvexPolyEffect.h" | 23 #include "effects/GrConvexPolyEffect.h" |
24 #include "effects/GrPorterDuffXferProcessor.h" | 24 #include "effects/GrPorterDuffXferProcessor.h" |
25 #include "effects/GrRRectEffect.h" | 25 #include "effects/GrRRectEffect.h" |
26 #include "effects/GrTextureDomain.h" | 26 #include "effects/GrTextureDomain.h" |
27 | 27 |
28 typedef SkClipStack::Element Element; | 28 typedef SkClipStack::Element Element; |
29 | 29 |
| 30 bool GrClipStackClip::quickContains(const SkRect& rect) const { |
| 31 if (!fStack) { |
| 32 return true; |
| 33 } |
| 34 return fStack->quickContains(rect.makeOffset(SkIntToScalar(fOrigin.x()), |
| 35 SkIntToScalar(fOrigin.y()))); |
| 36 } |
| 37 |
| 38 void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devR
esult, |
| 39 bool* isIntersectionOfRects) const { |
| 40 if (!fStack) { |
| 41 devResult->setXYWH(0, 0, width, height); |
| 42 if (isIntersectionOfRects) { |
| 43 *isIntersectionOfRects = true; |
| 44 } |
| 45 return; |
| 46 } |
| 47 SkRect devBounds; |
| 48 fStack->getConservativeBounds(-fOrigin.x(), -fOrigin.y(), width, height, &de
vBounds, |
| 49 isIntersectionOfRects); |
| 50 devBounds.roundOut(devResult); |
| 51 } |
| 52 |
30 static const int kMaxAnalyticElements = 4; | 53 static const int kMaxAnalyticElements = 4; |
31 | 54 |
32 //////////////////////////////////////////////////////////////////////////////// | 55 //////////////////////////////////////////////////////////////////////////////// |
33 // set up the draw state to enable the aa clipping mask. Besides setting up the | 56 // set up the draw state to enable the aa clipping mask. Besides setting up the |
34 // stage matrix this also alters the vertex layout | 57 // stage matrix this also alters the vertex layout |
35 static sk_sp<GrFragmentProcessor> create_fp_for_mask(GrTexture* result, | 58 static sk_sp<GrFragmentProcessor> create_fp_for_mask(GrTexture* result, |
36 const SkIRect &devBound) { | 59 const SkIRect &devBound) { |
37 SkMatrix mat; | 60 SkMatrix mat; |
38 // We use device coords to compute the texture coordinates. We set our matri
x to be a | 61 // We use device coords to compute the texture coordinates. We set our matri
x to be a |
39 // translation to the devBound, and then a scaling matrix to normalized coor
ds. | 62 // translation to the devBound, and then a scaling matrix to normalized coor
ds. |
40 mat.setIDiv(result->width(), result->height()); | 63 mat.setIDiv(result->width(), result->height()); |
41 mat.preTranslate(SkIntToScalar(-devBound.fLeft), | 64 mat.preTranslate(SkIntToScalar(-devBound.fLeft), |
42 SkIntToScalar(-devBound.fTop)); | 65 SkIntToScalar(-devBound.fTop)); |
43 | 66 |
44 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); | 67 SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height()); |
45 return sk_sp<GrFragmentProcessor>(GrTextureDomainEffect::Make( | 68 return sk_sp<GrFragmentProcessor>(GrTextureDomainEffect::Make( |
46 result, | 69 result, |
47 mat, | 70 mat, |
48 GrTextureDomain::MakeTexelDomain(result
, domainTexels), | 71 GrTextureDomain::MakeTexelDomain(result
, domainTexels), |
49 GrTextureDomain::kDecal_Mode, | 72 GrTextureDomain::kDecal_Mode, |
50 GrTextureParams::kNone_FilterMode, | 73 GrTextureParams::kNone_FilterMode, |
51 kDevice_GrCoordSet)); | 74 kDevice_GrCoordSet)); |
52 } | 75 } |
53 | 76 |
54 // Does the path in 'element' require SW rendering? If so, return true (and, | 77 // Does the path in 'element' require SW rendering? If so, return true (and, |
55 // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set | 78 // optionally, set 'prOut' to NULL. If not, return false (and, optionally, set |
56 // 'prOut' to the non-SW path renderer that will do the job). | 79 // 'prOut' to the non-SW path renderer that will do the job). |
57 bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context, | 80 bool GrClipStackClip::PathNeedsSWRenderer(GrContext* context, |
58 bool hasUserStencilSettings, | 81 bool hasUserStencilSettings, |
59 const GrDrawContext* drawContext, | 82 const GrDrawContext* drawContext, |
60 const SkMatrix& viewMatrix, | 83 const SkMatrix& viewMatrix, |
61 const Element* element, | 84 const Element* element, |
62 GrPathRenderer** prOut, | 85 GrPathRenderer** prOut, |
63 bool needsStencil) { | 86 bool needsStencil) { |
64 if (Element::kRect_Type == element->getType()) { | 87 if (Element::kRect_Type == element->getType()) { |
65 // rects can always be drawn directly w/o using the software path | 88 // rects can always be drawn directly w/o using the software path |
66 // TODO: skip rrects once we're drawing them directly. | 89 // TODO: skip rrects once we're drawing them directly. |
67 if (prOut) { | 90 if (prOut) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 } | 130 } |
108 return SkToBool(!pr); | 131 return SkToBool(!pr); |
109 } | 132 } |
110 } | 133 } |
111 | 134 |
112 /* | 135 /* |
113 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 136 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
114 * will be used on any element. If so, it returns true to indicate that the | 137 * will be used on any element. If so, it returns true to indicate that the |
115 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 138 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
116 */ | 139 */ |
117 bool GrClipMaskManager::UseSWOnlyPath(GrContext* context, | 140 bool GrClipStackClip::UseSWOnlyPath(GrContext* context, |
118 const GrPipelineBuilder& pipelineBuilder, | 141 const GrPipelineBuilder& pipelineBuilder, |
119 const GrDrawContext* drawContext, | 142 const GrDrawContext* drawContext, |
120 const SkVector& clipToMaskOffset, | 143 const SkVector& clipToMaskOffset, |
121 const GrReducedClip::ElementList& elements
) { | 144 const GrReducedClip::ElementList& elements)
{ |
122 // TODO: generalize this function so that when | 145 // TODO: generalize this function so that when |
123 // a clip gets complex enough it can just be done in SW regardless | 146 // a clip gets complex enough it can just be done in SW regardless |
124 // of whether it would invoke the GrSoftwarePathRenderer. | 147 // of whether it would invoke the GrSoftwarePathRenderer. |
125 | 148 |
126 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 149 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
127 // space. | 150 // space. |
128 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 151 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
129 | 152 |
130 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 153 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { |
131 const Element* element = iter.get(); | 154 const Element* element = iter.get(); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 iter.next(); | 238 iter.next(); |
216 } | 239 } |
217 | 240 |
218 *resultFP = nullptr; | 241 *resultFP = nullptr; |
219 if (fps.count()) { | 242 if (fps.count()) { |
220 *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count()); | 243 *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count()); |
221 } | 244 } |
222 return true; | 245 return true; |
223 } | 246 } |
224 | 247 |
225 //////////////////////////////////////////////////////////////////////////////// | |
226 // sort out what kind of clip mask needs to be created: alpha, stencil, | |
227 // scissor, or entirely software | |
228 bool GrClipMaskManager::SetupClipping(GrContext* context, | |
229 const GrPipelineBuilder& pipelineBuilder, | |
230 GrDrawContext* drawContext, | |
231 const GrClipStackClip& clip, | |
232 const SkRect* origDevBounds, | |
233 GrAppliedClip* out) { | |
234 if (!clip.clipStack() || clip.clipStack()->isWideOpen()) { | |
235 return true; | |
236 } | |
237 | |
238 GrReducedClip::ElementList elements; | |
239 int32_t genID = 0; | |
240 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat
e; | |
241 SkIRect clipSpaceIBounds; | |
242 bool requiresAA = false; | |
243 | |
244 SkIRect clipSpaceReduceQueryBounds; | |
245 SkRect devBounds; | |
246 if (origDevBounds) { | |
247 if (!devBounds.intersect(SkRect::MakeIWH(drawContext->width(), drawConte
xt->height()), | |
248 *origDevBounds)) { | |
249 return false; | |
250 } | |
251 devBounds.roundOut(&clipSpaceReduceQueryBounds); | |
252 clipSpaceReduceQueryBounds.offset(clip.origin()); | |
253 } else { | |
254 devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height())
; | |
255 clipSpaceReduceQueryBounds.setXYWH(0, 0, drawContext->width(), drawConte
xt->height()); | |
256 clipSpaceReduceQueryBounds.offset(clip.origin()); | |
257 } | |
258 GrReducedClip::ReduceClipStack(*clip.clipStack(), | |
259 clipSpaceReduceQueryBounds, | |
260 &elements, | |
261 &genID, | |
262 &initialState, | |
263 &clipSpaceIBounds, | |
264 &requiresAA); | |
265 if (elements.isEmpty()) { | |
266 if (GrReducedClip::kAllOut_InitialState == initialState) { | |
267 return false; | |
268 } else { | |
269 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | |
270 scissorSpaceIBounds.offset(-clip.origin()); | |
271 if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) { | |
272 out->makeScissored(scissorSpaceIBounds); | |
273 } | |
274 return true; | |
275 } | |
276 } | |
277 | |
278 // An element count of 4 was chosen because of the common pattern in Blink o
f: | |
279 // isect RR | |
280 // diff RR | |
281 // isect convex_poly | |
282 // isect convex_poly | |
283 // when drawing rounded div borders. This could probably be tuned based on a | |
284 // configuration's relative costs of switching RTs to generate a mask vs | |
285 // longer shaders. | |
286 if (elements.count() <= kMaxAnalyticElements) { | |
287 SkVector clipToRTOffset = { SkIntToScalar(-clip.origin().fX), | |
288 SkIntToScalar(-clip.origin().fY) }; | |
289 // When there are multiple samples we want to do per-sample clipping, no
t compute a | |
290 // fractional pixel coverage. | |
291 bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled(); | |
292 if (disallowAnalyticAA && !drawContext->numColorSamples()) { | |
293 // With a single color sample, any coverage info is lost from color
once it hits the | |
294 // color buffer anyway, so we may as well use coverage AA if nothing
else in the pipe | |
295 // is multisampled. | |
296 disallowAnalyticAA = pipelineBuilder.isHWAntialias() || | |
297 pipelineBuilder.hasUserStencilSettings(); | |
298 } | |
299 sk_sp<GrFragmentProcessor> clipFP; | |
300 if (requiresAA && | |
301 get_analytic_clip_processor(elements, disallowAnalyticAA, clipToRTOf
fset, devBounds, | |
302 &clipFP)) { | |
303 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | |
304 scissorSpaceIBounds.offset(-clip.origin()); | |
305 if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) { | |
306 out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds
); | |
307 return true; | |
308 } | |
309 out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds
)); | |
310 return true; | |
311 } | |
312 } | |
313 | |
314 // If the stencil buffer is multisampled we can use it to do everything. | |
315 if (!drawContext->isStencilBufferMultisampled() && requiresAA) { | |
316 sk_sp<GrTexture> result; | |
317 | |
318 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | |
319 SkVector clipToMaskOffset = { | |
320 SkIntToScalar(-clipSpaceIBounds.fLeft), | |
321 SkIntToScalar(-clipSpaceIBounds.fTop) | |
322 }; | |
323 | |
324 if (UseSWOnlyPath(context, pipelineBuilder, drawContext, | |
325 clipToMaskOffset, elements)) { | |
326 // The clip geometry is complex enough that it will be more efficien
t to create it | |
327 // entirely in software | |
328 result = CreateSoftwareClipMask(context->textureProvider(), | |
329 genID, | |
330 initialState, | |
331 elements, | |
332 clipToMaskOffset, | |
333 clipSpaceIBounds); | |
334 } else { | |
335 result = CreateAlphaClipMask(context, | |
336 genID, | |
337 initialState, | |
338 elements, | |
339 clipToMaskOffset, | |
340 clipSpaceIBounds); | |
341 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug | |
342 SkASSERT(result); | |
343 } | |
344 | |
345 if (result) { | |
346 // The mask's top left coord should be pinned to the rounded-out top
left corner of | |
347 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | |
348 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | |
349 rtSpaceMaskBounds.offset(-clip.origin()); | |
350 out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds)
, | |
351 SkRect::Make(rtSpaceMaskBounds)); | |
352 return true; | |
353 } | |
354 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | |
355 } | |
356 | |
357 // use the stencil clip if we can't represent the clip as a rectangle. | |
358 SkIPoint clipSpaceToStencilSpaceOffset = -clip.origin(); | |
359 CreateStencilClipMask(context, | |
360 drawContext, | |
361 genID, | |
362 initialState, | |
363 elements, | |
364 clipSpaceIBounds, | |
365 clipSpaceToStencilSpaceOffset); | |
366 | |
367 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it | |
368 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must | |
369 // use both stencil and scissor test to the bounds for the final draw. | |
370 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | |
371 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); | |
372 out->makeScissoredStencil(scissorSpaceIBounds); | |
373 return true; | |
374 } | |
375 | |
376 static bool stencil_element(GrDrawContext* dc, | 248 static bool stencil_element(GrDrawContext* dc, |
377 const GrFixedClip& clip, | 249 const GrFixedClip& clip, |
378 const GrUserStencilSettings* ss, | 250 const GrUserStencilSettings* ss, |
379 const SkMatrix& viewMatrix, | 251 const SkMatrix& viewMatrix, |
380 const SkClipStack::Element* element) { | 252 const SkClipStack::Element* element) { |
381 | 253 |
382 // TODO: Draw rrects directly here. | 254 // TODO: Draw rrects directly here. |
383 switch (element->getType()) { | 255 switch (element->getType()) { |
384 case Element::kEmpty_Type: | 256 case Element::kEmpty_Type: |
385 SkDEBUGFAIL("Should never get here with an empty element."); | 257 SkDEBUGFAIL("Should never get here with an empty element."); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
440 // Create a 8-bit clip mask in alpha | 312 // Create a 8-bit clip mask in alpha |
441 | 313 |
442 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { | 314 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { |
443 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 315 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
444 GrUniqueKey::Builder builder(key, kDomain, 3); | 316 GrUniqueKey::Builder builder(key, kDomain, 3); |
445 builder[0] = clipGenID; | 317 builder[0] = clipGenID; |
446 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); | 318 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); |
447 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); | 319 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); |
448 } | 320 } |
449 | 321 |
450 sk_sp<GrTexture> GrClipMaskManager::CreateAlphaClipMask(GrContext* context, | 322 sk_sp<GrTexture> CreateAlphaClipMask(GrContext* context, |
451 int32_t elementsGenID, | 323 int32_t elementsGenID, |
452 GrReducedClip::InitialSt
ate initialState, | 324 GrReducedClip::InitialSt
ate initialState, |
453 const GrReducedClip::Ele
mentList& elements, | 325 const GrReducedClip::Ele
mentList& elements, |
454 const SkVector& clipToMa
skOffset, | 326 const SkVector& clipToMa
skOffset, |
455 const SkIRect& clipSpace
IBounds) { | 327 const SkIRect& clipSpace
IBounds) { |
456 GrResourceProvider* resourceProvider = context->resourceProvider(); | 328 GrResourceProvider* resourceProvider = context->resourceProvider(); |
457 GrUniqueKey key; | 329 GrUniqueKey key; |
458 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 330 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
459 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 331 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
460 return sk_sp<GrTexture>(texture); | 332 return sk_sp<GrTexture>(texture); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 | 417 |
546 sk_sp<GrTexture> texture(dc->asTexture()); | 418 sk_sp<GrTexture> texture(dc->asTexture()); |
547 SkASSERT(texture); | 419 SkASSERT(texture); |
548 texture->resourcePriv().setUniqueKey(key); | 420 texture->resourcePriv().setUniqueKey(key); |
549 return texture; | 421 return texture; |
550 } | 422 } |
551 | 423 |
552 //////////////////////////////////////////////////////////////////////////////// | 424 //////////////////////////////////////////////////////////////////////////////// |
553 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 425 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
554 // (as opposed to canvas) coordinates | 426 // (as opposed to canvas) coordinates |
555 bool GrClipMaskManager::CreateStencilClipMask(GrContext* context, | 427 bool GrClipStackClip::CreateStencilClipMask(GrContext* context, |
556 GrDrawContext* drawContext, | 428 GrDrawContext* drawContext, |
557 int32_t elementsGenID, | 429 int32_t elementsGenID, |
558 GrReducedClip::InitialState initia
lState, | 430 GrReducedClip::InitialState initialS
tate, |
559 const GrReducedClip::ElementList&
elements, | 431 const GrReducedClip::ElementList& el
ements, |
560 const SkIRect& clipSpaceIBounds, | 432 const SkIRect& clipSpaceIBounds, |
561 const SkIPoint& clipSpaceToStencil
Offset) { | 433 const SkIPoint& clipSpaceToStencilOf
fset) { |
562 SkASSERT(drawContext); | 434 SkASSERT(drawContext); |
563 | 435 |
564 GrStencilAttachment* stencilAttachment = context->resourceProvider()->attach
StencilAttachment( | 436 GrStencilAttachment* stencilAttachment = context->resourceProvider()->attach
StencilAttachment( |
565 drawContext->accessRenderTar
get()); | 437 drawContext->accessRenderTar
get()); |
566 if (nullptr == stencilAttachment) { | 438 if (nullptr == stencilAttachment) { |
567 return false; | 439 return false; |
568 } | 440 } |
569 | 441 |
570 // TODO: these need to be swapped over to using a StencilAttachmentProxy | 442 // TODO: these need to be swapped over to using a StencilAttachmentProxy |
571 if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipS
paceToStencilOffset)) { | 443 if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipS
paceToStencilOffset)) { |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
728 drawContext->drawContextPriv().stencilRect(clip, *pass, fals
e, viewMatrix, | 600 drawContext->drawContextPriv().stencilRect(clip, *pass, fals
e, viewMatrix, |
729 SkRect::Make(clip
SpaceIBounds)); | 601 SkRect::Make(clip
SpaceIBounds)); |
730 } | 602 } |
731 } | 603 } |
732 } | 604 } |
733 } | 605 } |
734 return true; | 606 return true; |
735 } | 607 } |
736 | 608 |
737 //////////////////////////////////////////////////////////////////////////////// | 609 //////////////////////////////////////////////////////////////////////////////// |
738 sk_sp<GrTexture> GrClipMaskManager::CreateSoftwareClipMask( | 610 sk_sp<GrTexture> CreateSoftwareClipMask( |
739 GrTextureProvider* texProvid
er, | 611 GrTextureProvider* texProvid
er, |
740 int32_t elementsGenID, | 612 int32_t elementsGenID, |
741 GrReducedClip::InitialState
initialState, | 613 GrReducedClip::InitialState
initialState, |
742 const GrReducedClip::Element
List& elements, | 614 const GrReducedClip::Element
List& elements, |
743 const SkVector& clipToMaskOf
fset, | 615 const SkVector& clipToMaskOf
fset, |
744 const SkIRect& clipSpaceIBou
nds) { | 616 const SkIRect& clipSpaceIBou
nds) { |
745 GrUniqueKey key; | 617 GrUniqueKey key; |
746 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 618 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); |
747 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { | 619 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { |
748 return sk_sp<GrTexture>(texture); | 620 return sk_sp<GrTexture>(texture); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); | 677 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); |
806 if (!result) { | 678 if (!result) { |
807 return nullptr; | 679 return nullptr; |
808 } | 680 } |
809 result->resourcePriv().setUniqueKey(key); | 681 result->resourcePriv().setUniqueKey(key); |
810 | 682 |
811 helper.toTexture(result.get()); | 683 helper.toTexture(result.get()); |
812 | 684 |
813 return result; | 685 return result; |
814 } | 686 } |
| 687 |
| 688 bool GrClipStackClip::apply(GrContext* context, |
| 689 const GrPipelineBuilder& pipelineBuilder, GrDrawCont
ext* drawContext, |
| 690 const SkRect* origDevBounds, GrAppliedClip* out) con
st { |
| 691 ////////////////////////////////////////////////////////////////////////////
//// |
| 692 // sort out what kind of clip mask needs to be created: alpha, stencil, |
| 693 // scissor, or entirely software |
| 694 |
| 695 GrReducedClip::ElementList elements; |
| 696 int32_t genID = 0; |
| 697 GrReducedClip::InitialState initialState = GrReducedClip::kAllIn_InitialStat
e; |
| 698 SkIRect clipSpaceIBounds; |
| 699 bool requiresAA = false; |
| 700 |
| 701 SkIRect clipSpaceReduceQueryBounds; |
| 702 SkRect devBounds; |
| 703 if (origDevBounds) { |
| 704 if (!devBounds.intersect(SkRect::MakeIWH(drawContext->width(), drawConte
xt->height()), |
| 705 *origDevBounds)) { |
| 706 return false; |
| 707 } |
| 708 devBounds.roundOut(&clipSpaceReduceQueryBounds); |
| 709 clipSpaceReduceQueryBounds.offset(this->origin()); |
| 710 } else { |
| 711 devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height())
; |
| 712 clipSpaceReduceQueryBounds.setXYWH(0, 0, drawContext->width(), drawConte
xt->height()); |
| 713 clipSpaceReduceQueryBounds.offset(this->origin()); |
| 714 } |
| 715 GrReducedClip::ReduceClipStack(*this->clipStack(), |
| 716 clipSpaceReduceQueryBounds, |
| 717 &elements, |
| 718 &genID, |
| 719 &initialState, |
| 720 &clipSpaceIBounds, |
| 721 &requiresAA); |
| 722 if (elements.isEmpty()) { |
| 723 if (GrReducedClip::kAllOut_InitialState == initialState) { |
| 724 return false; |
| 725 } else { |
| 726 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 727 scissorSpaceIBounds.offset(-this->origin()); |
| 728 if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) { |
| 729 out->makeScissored(scissorSpaceIBounds); |
| 730 } |
| 731 return true; |
| 732 } |
| 733 } |
| 734 |
| 735 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
| 736 // isect RR |
| 737 // diff RR |
| 738 // isect convex_poly |
| 739 // isect convex_poly |
| 740 // when drawing rounded div borders. This could probably be tuned based on a |
| 741 // configuration's relative costs of switching RTs to generate a mask vs |
| 742 // longer shaders. |
| 743 if (elements.count() <= kMaxAnalyticElements) { |
| 744 SkVector clipToRTOffset = { SkIntToScalar(-this->origin().fX), |
| 745 SkIntToScalar(-this->origin().fY) }; |
| 746 // When there are multiple samples we want to do per-sample clipping, no
t compute a |
| 747 // fractional pixel coverage. |
| 748 bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled(); |
| 749 if (disallowAnalyticAA && !drawContext->numColorSamples()) { |
| 750 // With a single color sample, any coverage info is lost from color
once it hits the |
| 751 // color buffer anyway, so we may as well use coverage AA if nothing
else in the pipe |
| 752 // is multisampled. |
| 753 disallowAnalyticAA = pipelineBuilder.isHWAntialias() || |
| 754 pipelineBuilder.hasUserStencilSettings(); |
| 755 } |
| 756 sk_sp<GrFragmentProcessor> clipFP; |
| 757 if (requiresAA && |
| 758 get_analytic_clip_processor(elements, disallowAnalyticAA, clipToRTOf
fset, devBounds, |
| 759 &clipFP)) { |
| 760 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 761 scissorSpaceIBounds.offset(-this->origin()); |
| 762 if (!SkRect::Make(scissorSpaceIBounds).contains(devBounds)) { |
| 763 out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds
); |
| 764 return true; |
| 765 } |
| 766 out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBounds
)); |
| 767 return true; |
| 768 } |
| 769 } |
| 770 |
| 771 // If the stencil buffer is multisampled we can use it to do everything. |
| 772 if (!drawContext->isStencilBufferMultisampled() && requiresAA) { |
| 773 sk_sp<GrTexture> result; |
| 774 |
| 775 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
| 776 SkVector clipToMaskOffset = { |
| 777 SkIntToScalar(-clipSpaceIBounds.fLeft), |
| 778 SkIntToScalar(-clipSpaceIBounds.fTop) |
| 779 }; |
| 780 |
| 781 if (UseSWOnlyPath(context, pipelineBuilder, drawContext, |
| 782 clipToMaskOffset, elements)) { |
| 783 // The clip geometry is complex enough that it will be more efficien
t to create it |
| 784 // entirely in software |
| 785 result = CreateSoftwareClipMask(context->textureProvider(), |
| 786 genID, |
| 787 initialState, |
| 788 elements, |
| 789 clipToMaskOffset, |
| 790 clipSpaceIBounds); |
| 791 } else { |
| 792 result = CreateAlphaClipMask(context, |
| 793 genID, |
| 794 initialState, |
| 795 elements, |
| 796 clipToMaskOffset, |
| 797 clipSpaceIBounds); |
| 798 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug |
| 799 SkASSERT(result); |
| 800 } |
| 801 |
| 802 if (result) { |
| 803 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
| 804 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
| 805 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; |
| 806 rtSpaceMaskBounds.offset(-this->origin()); |
| 807 out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds)
, |
| 808 SkRect::Make(rtSpaceMaskBounds)); |
| 809 return true; |
| 810 } |
| 811 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
| 812 } |
| 813 |
| 814 // use the stencil clip if we can't represent the clip as a rectangle. |
| 815 SkIPoint clipSpaceToStencilSpaceOffset = -this->origin(); |
| 816 CreateStencilClipMask(context, |
| 817 drawContext, |
| 818 genID, |
| 819 initialState, |
| 820 elements, |
| 821 clipSpaceIBounds, |
| 822 clipSpaceToStencilSpaceOffset); |
| 823 |
| 824 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it |
| 825 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must |
| 826 // use both stencil and scissor test to the bounds for the final draw. |
| 827 SkIRect scissorSpaceIBounds(clipSpaceIBounds); |
| 828 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
| 829 out->makeScissoredStencil(scissorSpaceIBounds); |
| 830 return true; |
| 831 } |
OLD | NEW |