OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 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 "GrClipStackClip.h" | 8 #include "GrClipStackClip.h" |
9 | 9 |
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 "GrStencilAttachment.h" | 13 #include "GrStencilAttachment.h" |
14 #include "GrSWMaskHelper.h" | 14 #include "GrSWMaskHelper.h" |
15 #include "effects/GrConvexPolyEffect.h" | 15 #include "effects/GrConvexPolyEffect.h" |
16 #include "effects/GrRRectEffect.h" | 16 #include "effects/GrRRectEffect.h" |
17 #include "effects/GrTextureDomain.h" | 17 #include "effects/GrTextureDomain.h" |
18 | 18 |
19 typedef SkClipStack::Element Element; | 19 typedef SkClipStack::Element Element; |
20 typedef GrReducedClip::InitialState InitialState; | 20 typedef GrReducedClip::InitialState InitialState; |
| 21 typedef GrReducedClip::ElementList ElementList; |
21 | 22 |
22 static const int kMaxAnalyticElements = 4; | 23 static const int kMaxAnalyticElements = 4; |
23 | 24 |
24 bool GrClipStackClip::quickContains(const SkRect& rect) const { | 25 bool GrClipStackClip::quickContains(const SkRect& rect) const { |
25 if (!fStack) { | 26 if (!fStack) { |
26 return true; | 27 return true; |
27 } | 28 } |
28 return fStack->quickContains(rect.makeOffset(SkIntToScalar(fOrigin.x()), | 29 return fStack->quickContains(rect.makeOffset(SkIntToScalar(fOrigin.x()), |
29 SkIntToScalar(fOrigin.y()))); | 30 SkIntToScalar(fOrigin.y()))); |
30 } | 31 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 | 128 |
128 /* | 129 /* |
129 * This method traverses the clip stack to see if the GrSoftwarePathRenderer | 130 * This method traverses the clip stack to see if the GrSoftwarePathRenderer |
130 * will be used on any element. If so, it returns true to indicate that the | 131 * will be used on any element. If so, it returns true to indicate that the |
131 * entire clip should be rendered in SW and then uploaded en masse to the gpu. | 132 * entire clip should be rendered in SW and then uploaded en masse to the gpu. |
132 */ | 133 */ |
133 bool GrClipStackClip::UseSWOnlyPath(GrContext* context, | 134 bool GrClipStackClip::UseSWOnlyPath(GrContext* context, |
134 bool hasUserStencilSettings, | 135 bool hasUserStencilSettings, |
135 const GrDrawContext* drawContext, | 136 const GrDrawContext* drawContext, |
136 const SkVector& clipToMaskOffset, | 137 const SkVector& clipToMaskOffset, |
137 const GrReducedClip::ElementList& elements)
{ | 138 const ElementList& elements) { |
138 // TODO: generalize this function so that when | 139 // TODO: generalize this function so that when |
139 // a clip gets complex enough it can just be done in SW regardless | 140 // a clip gets complex enough it can just be done in SW regardless |
140 // of whether it would invoke the GrSoftwarePathRenderer. | 141 // of whether it would invoke the GrSoftwarePathRenderer. |
141 | 142 |
142 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 143 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
143 // space. | 144 // space. |
144 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 145 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
145 | 146 |
146 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.get();
iter.next()) { | 147 for (ElementList::Iter iter(elements); iter.get(); iter.next()) { |
147 const Element* element = iter.get(); | 148 const Element* element = iter.get(); |
148 | 149 |
149 SkRegion::Op op = element->getOp(); | 150 SkRegion::Op op = element->getOp(); |
150 bool invert = element->isInverseFilled(); | 151 bool invert = element->isInverseFilled(); |
151 bool needsStencil = invert || | 152 bool needsStencil = invert || |
152 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; | 153 SkRegion::kIntersect_Op == op || SkRegion::kReverseD
ifference_Op == op; |
153 | 154 |
154 if (PathNeedsSWRenderer(context, hasUserStencilSettings, | 155 if (PathNeedsSWRenderer(context, hasUserStencilSettings, |
155 drawContext, translate, element, nullptr, needsS
tencil)) { | 156 drawContext, translate, element, nullptr, needsS
tencil)) { |
156 return true; | 157 return true; |
157 } | 158 } |
158 } | 159 } |
159 return false; | 160 return false; |
160 } | 161 } |
161 | 162 |
162 static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elemen
ts, | 163 static bool get_analytic_clip_processor(const ElementList& elements, |
163 bool abortIfAA, | 164 bool abortIfAA, |
164 const SkVector& clipToRTOffset, | 165 const SkVector& clipToRTOffset, |
165 const SkRect& drawBounds, | 166 const SkRect& drawBounds, |
166 sk_sp<GrFragmentProcessor>* resultFP) { | 167 sk_sp<GrFragmentProcessor>* resultFP) { |
167 SkRect boundsInClipSpace; | 168 SkRect boundsInClipSpace; |
168 boundsInClipSpace = drawBounds.makeOffset(-clipToRTOffset.fX, -clipToRTOffse
t.fY); | 169 boundsInClipSpace = drawBounds.makeOffset(-clipToRTOffset.fX, -clipToRTOffse
t.fY); |
169 SkASSERT(elements.count() <= kMaxAnalyticElements); | 170 SkASSERT(elements.count() <= kMaxAnalyticElements); |
170 SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps; | 171 SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps; |
171 GrReducedClip::ElementList::Iter iter(elements); | 172 ElementList::Iter iter(elements); |
172 while (iter.get()) { | 173 while (iter.get()) { |
173 SkRegion::Op op = iter.get()->getOp(); | 174 SkRegion::Op op = iter.get()->getOp(); |
174 bool invert; | 175 bool invert; |
175 bool skip = false; | 176 bool skip = false; |
176 switch (op) { | 177 switch (op) { |
177 case SkRegion::kReplace_Op: | 178 case SkRegion::kReplace_Op: |
178 SkASSERT(iter.get() == elements.head()); | 179 SkASSERT(iter.get() == elements.head()); |
179 // Fallthrough, handled same as intersect. | 180 // Fallthrough, handled same as intersect. |
180 case SkRegion::kIntersect_Op: | 181 case SkRegion::kIntersect_Op: |
181 invert = false; | 182 invert = false; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 } | 253 } |
253 | 254 |
254 SkRect devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height
()); | 255 SkRect devBounds = SkRect::MakeIWH(drawContext->width(), drawContext->height
()); |
255 if (origDevBounds && !devBounds.intersect(*origDevBounds)) { | 256 if (origDevBounds && !devBounds.intersect(*origDevBounds)) { |
256 return false; | 257 return false; |
257 } | 258 } |
258 | 259 |
259 const SkScalar clipX = SkIntToScalar(fOrigin.x()), | 260 const SkScalar clipX = SkIntToScalar(fOrigin.x()), |
260 clipY = SkIntToScalar(fOrigin.y()); | 261 clipY = SkIntToScalar(fOrigin.y()); |
261 | 262 |
262 GrReducedClip::ElementList elements; | 263 SkRect clipSpaceDevBounds = devBounds.makeOffset(clipX, clipY); |
263 int32_t genID = 0; | 264 const GrReducedClip reducedClip(*fStack, clipSpaceDevBounds); |
264 SkIRect clipSpaceIBounds; | |
265 bool requiresAA = false; | |
266 | 265 |
267 InitialState initialState = GrReducedClip::ReduceClipStack(*fStack, | 266 if (reducedClip.elements().isEmpty()) { |
268 devBounds.makeOff
set(clipX, clipY), | 267 if (GrReducedClip::InitialState::kAllOut == reducedClip.initialState())
{ |
269 &elements, | |
270 &genID, | |
271 &clipSpaceIBounds
, | |
272 &requiresAA); | |
273 if (elements.isEmpty()) { | |
274 if (GrReducedClip::kAllOut_InitialState == initialState || clipSpaceIBou
nds.isEmpty()) { | |
275 return false; | 268 return false; |
276 } else { | 269 } |
277 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 270 if (!GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) { |
| 271 SkIRect scissorSpaceIBounds(reducedClip.iBounds()); |
278 scissorSpaceIBounds.offset(-fOrigin); | 272 scissorSpaceIBounds.offset(-fOrigin); |
279 if (!GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) { | 273 out->makeScissored(scissorSpaceIBounds); |
280 out->makeScissored(scissorSpaceIBounds); | |
281 } | |
282 return true; | |
283 } | 274 } |
| 275 return true; |
284 } | 276 } |
285 | 277 |
286 // An element count of 4 was chosen because of the common pattern in Blink o
f: | 278 // An element count of 4 was chosen because of the common pattern in Blink o
f: |
287 // isect RR | 279 // isect RR |
288 // diff RR | 280 // diff RR |
289 // isect convex_poly | 281 // isect convex_poly |
290 // isect convex_poly | 282 // isect convex_poly |
291 // when drawing rounded div borders. This could probably be tuned based on a | 283 // when drawing rounded div borders. This could probably be tuned based on a |
292 // configuration's relative costs of switching RTs to generate a mask vs | 284 // configuration's relative costs of switching RTs to generate a mask vs |
293 // longer shaders. | 285 // longer shaders. |
294 if (elements.count() <= kMaxAnalyticElements) { | 286 if (reducedClip.elements().count() <= kMaxAnalyticElements) { |
295 // When there are multiple samples we want to do per-sample clipping, no
t compute a | 287 // When there are multiple samples we want to do per-sample clipping, no
t compute a |
296 // fractional pixel coverage. | 288 // fractional pixel coverage. |
297 bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled(); | 289 bool disallowAnalyticAA = drawContext->isStencilBufferMultisampled(); |
298 if (disallowAnalyticAA && !drawContext->numColorSamples()) { | 290 if (disallowAnalyticAA && !drawContext->numColorSamples()) { |
299 // With a single color sample, any coverage info is lost from color
once it hits the | 291 // With a single color sample, any coverage info is lost from color
once it hits the |
300 // color buffer anyway, so we may as well use coverage AA if nothing
else in the pipe | 292 // color buffer anyway, so we may as well use coverage AA if nothing
else in the pipe |
301 // is multisampled. | 293 // is multisampled. |
302 disallowAnalyticAA = useHWAA || hasUserStencilSettings; | 294 disallowAnalyticAA = useHWAA || hasUserStencilSettings; |
303 } | 295 } |
304 sk_sp<GrFragmentProcessor> clipFP; | 296 sk_sp<GrFragmentProcessor> clipFP; |
305 if (requiresAA && | 297 if (reducedClip.requiresAA() && |
306 get_analytic_clip_processor(elements, disallowAnalyticAA, {-clipX, -
clipY}, devBounds, | 298 get_analytic_clip_processor(reducedClip.elements(), disallowAnalytic
AA, |
307 &clipFP)) { | 299 {-clipX, -clipY}, devBounds, &clipFP)) { |
308 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 300 SkIRect scissorSpaceIBounds(reducedClip.iBounds()); |
309 scissorSpaceIBounds.offset(-fOrigin); | 301 scissorSpaceIBounds.offset(-fOrigin); |
310 if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) { | 302 if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) { |
311 out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBo
unds)); | 303 out->makeFPBased(std::move(clipFP), SkRect::Make(scissorSpaceIBo
unds)); |
312 } else { | 304 } else { |
313 out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds
); | 305 out->makeScissoredFPBased(std::move(clipFP), scissorSpaceIBounds
); |
314 } | 306 } |
315 return true; | 307 return true; |
316 } | 308 } |
317 } | 309 } |
318 | 310 |
319 // If the stencil buffer is multisampled we can use it to do everything. | 311 // If the stencil buffer is multisampled we can use it to do everything. |
320 if (!drawContext->isStencilBufferMultisampled() && requiresAA) { | 312 if (!drawContext->isStencilBufferMultisampled() && reducedClip.requiresAA())
{ |
321 sk_sp<GrTexture> result; | 313 sk_sp<GrTexture> result; |
322 | 314 |
323 // The top-left of the mask corresponds to the top-left corner of the bo
unds. | 315 // The top-left of the mask corresponds to the top-left corner of the bo
unds. |
324 SkVector clipToMaskOffset = { | 316 SkVector clipToMaskOffset = { |
325 SkIntToScalar(-clipSpaceIBounds.fLeft), | 317 SkIntToScalar(-reducedClip.left()), |
326 SkIntToScalar(-clipSpaceIBounds.fTop) | 318 SkIntToScalar(-reducedClip.top()) |
327 }; | 319 }; |
328 | 320 |
329 if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, | 321 if (UseSWOnlyPath(context, hasUserStencilSettings, drawContext, |
330 clipToMaskOffset, elements)) { | 322 clipToMaskOffset, reducedClip.elements())) { |
331 // The clip geometry is complex enough that it will be more efficien
t to create it | 323 // The clip geometry is complex enough that it will be more efficien
t to create it |
332 // entirely in software | 324 // entirely in software |
333 result = CreateSoftwareClipMask(context->textureProvider(), | 325 result = CreateSoftwareClipMask(context->textureProvider(), reducedC
lip, |
334 genID, | 326 clipToMaskOffset); |
335 initialState, | |
336 elements, | |
337 clipToMaskOffset, | |
338 clipSpaceIBounds); | |
339 } else { | 327 } else { |
340 result = CreateAlphaClipMask(context, | 328 result = CreateAlphaClipMask(context, reducedClip, clipToMaskOffset)
; |
341 genID, | |
342 initialState, | |
343 elements, | |
344 clipToMaskOffset, | |
345 clipSpaceIBounds); | |
346 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug | 329 // If createAlphaClipMask fails it means UseSWOnlyPath has a bug |
347 SkASSERT(result); | 330 SkASSERT(result); |
348 } | 331 } |
349 | 332 |
350 if (result) { | 333 if (result) { |
351 // The mask's top left coord should be pinned to the rounded-out top
left corner of | 334 // The mask's top left coord should be pinned to the rounded-out top
left corner of |
352 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. | 335 // clipSpace bounds. We determine the mask's position WRT to the ren
der target here. |
353 SkIRect rtSpaceMaskBounds = clipSpaceIBounds; | 336 SkIRect rtSpaceMaskBounds = reducedClip.iBounds(); |
354 rtSpaceMaskBounds.offset(-fOrigin); | 337 rtSpaceMaskBounds.offset(-fOrigin); |
355 out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds)
, | 338 out->makeFPBased(create_fp_for_mask(result.get(), rtSpaceMaskBounds)
, |
356 SkRect::Make(rtSpaceMaskBounds)); | 339 SkRect::Make(rtSpaceMaskBounds)); |
357 return true; | 340 return true; |
358 } | 341 } |
359 // if alpha clip mask creation fails fall through to the non-AA code pat
hs | 342 // if alpha clip mask creation fails fall through to the non-AA code pat
hs |
360 } | 343 } |
361 | 344 |
362 // use the stencil clip if we can't represent the clip as a rectangle. | 345 // use the stencil clip if we can't represent the clip as a rectangle. |
363 SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin; | 346 SkIPoint clipSpaceToStencilSpaceOffset = -fOrigin; |
364 CreateStencilClipMask(context, | 347 CreateStencilClipMask(context, drawContext, reducedClip, clipSpaceToStencilS
paceOffset); |
365 drawContext, | |
366 genID, | |
367 initialState, | |
368 elements, | |
369 clipSpaceIBounds, | |
370 clipSpaceToStencilSpaceOffset); | |
371 | 348 |
372 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it | 349 // This must occur after createStencilClipMask. That function may change the
scissor. Also, it |
373 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must | 350 // only guarantees that the stencil mask is correct within the bounds it was
passed, so we must |
374 // use both stencil and scissor test to the bounds for the final draw. | 351 // use both stencil and scissor test to the bounds for the final draw. |
375 SkIRect scissorSpaceIBounds(clipSpaceIBounds); | 352 if (GrClip::IsInsideClip(reducedClip.iBounds(), clipSpaceDevBounds)) { |
376 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); | |
377 if (GrClip::IsInsideClip(scissorSpaceIBounds, devBounds)) { | |
378 out->makeStencil(true, devBounds); | 353 out->makeStencil(true, devBounds); |
379 } else { | 354 } else { |
| 355 SkIRect scissorSpaceIBounds(reducedClip.iBounds()); |
| 356 scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset); |
380 out->makeScissoredStencil(scissorSpaceIBounds); | 357 out->makeScissoredStencil(scissorSpaceIBounds); |
381 } | 358 } |
382 return true; | 359 return true; |
383 } | 360 } |
384 | 361 |
385 static bool stencil_element(GrDrawContext* dc, | 362 static bool stencil_element(GrDrawContext* dc, |
386 const GrFixedClip& clip, | 363 const GrFixedClip& clip, |
387 const GrUserStencilSettings* ss, | 364 const GrUserStencilSettings* ss, |
388 const SkMatrix& viewMatrix, | 365 const SkMatrix& viewMatrix, |
389 const SkClipStack::Element* element) { | 366 const SkClipStack::Element* element) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
450 | 427 |
451 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { | 428 static void GetClipMaskKey(int32_t clipGenID, const SkIRect& bounds, GrUniqueKey
* key) { |
452 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); | 429 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); |
453 GrUniqueKey::Builder builder(key, kDomain, 3); | 430 GrUniqueKey::Builder builder(key, kDomain, 3); |
454 builder[0] = clipGenID; | 431 builder[0] = clipGenID; |
455 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); | 432 builder[1] = SkToU16(bounds.fLeft) | (SkToU16(bounds.fRight) << 16); |
456 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); | 433 builder[2] = SkToU16(bounds.fTop) | (SkToU16(bounds.fBottom) << 16); |
457 } | 434 } |
458 | 435 |
459 sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, | 436 sk_sp<GrTexture> GrClipStackClip::CreateAlphaClipMask(GrContext* context, |
460 int32_t elementsGenID, | 437 const GrReducedClip& reduc
edClip, |
461 GrReducedClip::InitialStat
e initialState, | 438 const SkVector& clipToMask
Offset) { |
462 const GrReducedClip::Eleme
ntList& elements, | |
463 const SkVector& clipToMask
Offset, | |
464 const SkIRect& clipSpaceIB
ounds) { | |
465 GrResourceProvider* resourceProvider = context->resourceProvider(); | 439 GrResourceProvider* resourceProvider = context->resourceProvider(); |
466 GrUniqueKey key; | 440 GrUniqueKey key; |
467 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 441 GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key); |
468 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { | 442 if (GrTexture* texture = resourceProvider->findAndRefTextureByUniqueKey(key)
) { |
469 return sk_sp<GrTexture>(texture); | 443 return sk_sp<GrTexture>(texture); |
470 } | 444 } |
471 | 445 |
472 // There's no texture in the cache. Let's try to allocate it then. | 446 // There's no texture in the cache. Let's try to allocate it then. |
473 GrPixelConfig config = kRGBA_8888_GrPixelConfig; | 447 GrPixelConfig config = kRGBA_8888_GrPixelConfig; |
474 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { | 448 if (context->caps()->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { |
475 config = kAlpha_8_GrPixelConfig; | 449 config = kAlpha_8_GrPixelConfig; |
476 } | 450 } |
477 | 451 |
478 sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kApprox, | 452 sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kApprox, |
479 clipSpaceIBounds.width(), | 453 reducedClip.width(), |
480 clipSpaceIBounds.height(), | 454 reducedClip.height(), |
481 config, nullptr)); | 455 config, nullptr)); |
482 if (!dc) { | 456 if (!dc) { |
483 return nullptr; | 457 return nullptr; |
484 } | 458 } |
485 | 459 |
486 // The texture may be larger than necessary, this rect represents the part o
f the texture | 460 // The texture may be larger than necessary, this rect represents the part o
f the texture |
487 // we populate with a rasterization of the clip. | 461 // we populate with a rasterization of the clip. |
488 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 462 SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.
height()); |
489 | 463 |
490 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only | 464 // The scratch texture that we are drawing into can be substantially larger
than the mask. Only |
491 // clear the part that we care about. | 465 // clear the part that we care about. |
492 dc->clear(&maskSpaceIBounds, | 466 dc->clear(&maskSpaceIBounds, |
493 GrReducedClip::kAllIn_InitialState == initialState ? 0xffffffff :
0x00000000, | 467 GrReducedClip::InitialState::kAllIn == reducedClip.initialState()
? -1 : 0, |
494 true); | 468 true); |
495 | 469 |
496 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 470 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
497 // space. | 471 // space. |
498 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); | 472 const SkMatrix translate = SkMatrix::MakeTrans(clipToMaskOffset.fX, clipToMa
skOffset.fY); |
499 | 473 |
500 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. | 474 // It is important that we use maskSpaceIBounds as the stencil rect in the b
elow loop. |
501 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first | 475 // The second pass that zeros the stencil buffer renders the rect maskSpaceI
Bounds so the first |
502 // pass must not set values outside of this bounds or stencil values outside
the rect won't be | 476 // pass must not set values outside of this bounds or stencil values outside
the rect won't be |
503 // cleared. | 477 // cleared. |
504 | 478 |
505 // walk through each clip element and perform its set op | 479 // walk through each clip element and perform its set op |
506 for (GrReducedClip::ElementList::Iter iter = elements.headIter(); iter.get()
; iter.next()) { | 480 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { |
507 const Element* element = iter.get(); | 481 const Element* element = iter.get(); |
508 SkRegion::Op op = element->getOp(); | 482 SkRegion::Op op = element->getOp(); |
509 bool invert = element->isInverseFilled(); | 483 bool invert = element->isInverseFilled(); |
510 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { | 484 if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDiffere
nce_Op == op) { |
511 GrFixedClip clip(maskSpaceIBounds); | 485 GrFixedClip clip(maskSpaceIBounds); |
512 | 486 |
513 // draw directly into the result with the stencil set to make the pi
xels affected | 487 // draw directly into the result with the stencil set to make the pi
xels affected |
514 // by the clip shape be non-zero. | 488 // by the clip shape be non-zero. |
515 static constexpr GrUserStencilSettings kStencilInElement( | 489 static constexpr GrUserStencilSettings kStencilInElement( |
516 GrUserStencilSettings::StaticInit< | 490 GrUserStencilSettings::StaticInit< |
(...skipping 15 matching lines...) Expand all Loading... |
532 0x0000, | 506 0x0000, |
533 GrUserStencilTest::kEqual, | 507 GrUserStencilTest::kEqual, |
534 0xffff, | 508 0xffff, |
535 GrUserStencilOp::kZero, | 509 GrUserStencilOp::kZero, |
536 GrUserStencilOp::kZero, | 510 GrUserStencilOp::kZero, |
537 0xffff>() | 511 0xffff>() |
538 ); | 512 ); |
539 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, | 513 if (!dc->drawContextPriv().drawAndStencilRect(clip, &kDrawOutsideEle
ment, |
540 op, !invert, false, | 514 op, !invert, false, |
541 translate, | 515 translate, |
542 SkRect::Make(clipSpace
IBounds))) { | 516 SkRect::Make(reducedCl
ip.iBounds()))) { |
543 return nullptr; | 517 return nullptr; |
544 } | 518 } |
545 } else { | 519 } else { |
546 // all the remaining ops can just be directly draw into the accumula
tion buffer | 520 // all the remaining ops can just be directly draw into the accumula
tion buffer |
547 GrPaint paint; | 521 GrPaint paint; |
548 paint.setAntiAlias(element->isAA()); | 522 paint.setAntiAlias(element->isAA()); |
549 paint.setCoverageSetOpXPFactory(op, false); | 523 paint.setCoverageSetOpXPFactory(op, false); |
550 | 524 |
551 draw_element(dc.get(), GrNoClip(), paint, translate, element); | 525 draw_element(dc.get(), GrNoClip(), paint, translate, element); |
552 } | 526 } |
553 } | 527 } |
554 | 528 |
555 sk_sp<GrTexture> texture(dc->asTexture()); | 529 sk_sp<GrTexture> texture(dc->asTexture()); |
556 SkASSERT(texture); | 530 SkASSERT(texture); |
557 texture->resourcePriv().setUniqueKey(key); | 531 texture->resourcePriv().setUniqueKey(key); |
558 return texture; | 532 return texture; |
559 } | 533 } |
560 | 534 |
561 //////////////////////////////////////////////////////////////////////////////// | 535 //////////////////////////////////////////////////////////////////////////////// |
562 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device | 536 // Create a 1-bit clip mask in the stencil buffer. 'devClipBounds' are in device |
563 // (as opposed to canvas) coordinates | 537 // (as opposed to canvas) coordinates |
564 bool GrClipStackClip::CreateStencilClipMask(GrContext* context, | 538 bool GrClipStackClip::CreateStencilClipMask(GrContext* context, |
565 GrDrawContext* drawContext, | 539 GrDrawContext* drawContext, |
566 int32_t elementsGenID, | 540 const GrReducedClip& reducedClip, |
567 GrReducedClip::InitialState initialS
tate, | |
568 const GrReducedClip::ElementList& el
ements, | |
569 const SkIRect& clipSpaceIBounds, | |
570 const SkIPoint& clipSpaceToStencilOf
fset) { | 541 const SkIPoint& clipSpaceToStencilOf
fset) { |
571 SkASSERT(drawContext); | 542 SkASSERT(drawContext); |
572 | 543 |
573 GrStencilAttachment* stencilAttachment = context->resourceProvider()->attach
StencilAttachment( | 544 GrStencilAttachment* stencilAttachment = context->resourceProvider()->attach
StencilAttachment( |
574 drawContext->accessRenderTar
get()); | 545 drawContext->accessRenderTar
get()); |
575 if (nullptr == stencilAttachment) { | 546 if (nullptr == stencilAttachment) { |
576 return false; | 547 return false; |
577 } | 548 } |
578 | 549 |
579 // TODO: these need to be swapped over to using a StencilAttachmentProxy | 550 // TODO: these need to be swapped over to using a StencilAttachmentProxy |
580 if (stencilAttachment->mustRenderClip(elementsGenID, clipSpaceIBounds, clipS
paceToStencilOffset)) { | 551 if (stencilAttachment->mustRenderClip(reducedClip.genID(), reducedClip.iBoun
ds(), |
581 stencilAttachment->setLastClip(elementsGenID, clipSpaceIBounds, clipSpac
eToStencilOffset); | 552 clipSpaceToStencilOffset)) { |
| 553 stencilAttachment->setLastClip(reducedClip.genID(), reducedClip.iBounds(
), |
| 554 clipSpaceToStencilOffset); |
582 // Set the matrix so that rendered clip elements are transformed from cl
ip to stencil space. | 555 // Set the matrix so that rendered clip elements are transformed from cl
ip to stencil space. |
583 SkVector translate = { | 556 SkVector translate = { |
584 SkIntToScalar(clipSpaceToStencilOffset.fX), | 557 SkIntToScalar(clipSpaceToStencilOffset.fX), |
585 SkIntToScalar(clipSpaceToStencilOffset.fY) | 558 SkIntToScalar(clipSpaceToStencilOffset.fY) |
586 }; | 559 }; |
587 SkMatrix viewMatrix; | 560 SkMatrix viewMatrix; |
588 viewMatrix.setTranslate(translate); | 561 viewMatrix.setTranslate(translate); |
589 | 562 |
590 // We set the current clip to the bounds so that our recursive draws are
scissored to them. | 563 // We set the current clip to the bounds so that our recursive draws are
scissored to them. |
591 SkIRect stencilSpaceIBounds(clipSpaceIBounds); | 564 SkIRect stencilSpaceIBounds(reducedClip.iBounds()); |
592 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); | 565 stencilSpaceIBounds.offset(clipSpaceToStencilOffset); |
593 GrFixedClip clip(stencilSpaceIBounds); | 566 GrFixedClip clip(stencilSpaceIBounds); |
594 | 567 |
595 drawContext->drawContextPriv().clearStencilClip( | 568 bool insideClip = GrReducedClip::InitialState::kAllIn == reducedClip.ini
tialState(); |
596 stencilSpaceIBounds, | 569 drawContext->drawContextPriv().clearStencilClip(stencilSpaceIBounds, ins
ideClip); |
597 GrReducedClip::kAllIn_InitialState =
= initialState); | |
598 | 570 |
599 // walk through each clip element and perform its set op | 571 // walk through each clip element and perform its set op |
600 // with the existing clip. | 572 // with the existing clip. |
601 for (GrReducedClip::ElementList::Iter iter(elements.headIter()); iter.ge
t(); iter.next()) { | 573 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.ne
xt()) { |
602 const Element* element = iter.get(); | 574 const Element* element = iter.get(); |
603 bool useHWAA = element->isAA() && drawContext->isStencilBufferMultis
ampled(); | 575 bool useHWAA = element->isAA() && drawContext->isStencilBufferMultis
ampled(); |
604 | 576 |
605 bool fillInverted = false; | 577 bool fillInverted = false; |
606 // enabled at bottom of loop | 578 // enabled at bottom of loop |
607 clip.disableStencilClip(); | 579 clip.disableStencilClip(); |
608 | 580 |
609 // This will be used to determine whether the clip shape can be rend
ered into the | 581 // This will be used to determine whether the clip shape can be rend
ered into the |
610 // stencil with arbitrary stencil settings. | 582 // stencil with arbitrary stencil settings. |
611 GrPathRenderer::StencilSupport stencilSupport; | 583 GrPathRenderer::StencilSupport stencilSupport; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 args.fClip = &clip; | 697 args.fClip = &clip; |
726 args.fViewMatrix = &viewMatrix; | 698 args.fViewMatrix = &viewMatrix; |
727 args.fShape = &shape; | 699 args.fShape = &shape; |
728 args.fAntiAlias = false; | 700 args.fAntiAlias = false; |
729 args.fGammaCorrect = false; | 701 args.fGammaCorrect = false; |
730 pr->drawPath(args); | 702 pr->drawPath(args); |
731 } | 703 } |
732 } else { | 704 } else { |
733 // The view matrix is setup to do clip space -> stencil spac
e translation, so | 705 // The view matrix is setup to do clip space -> stencil spac
e translation, so |
734 // draw rect in clip space. | 706 // draw rect in clip space. |
735 SkRect bounds = SkRect::Make(clipSpaceIBounds); | 707 SkRect bounds = SkRect::Make(reducedClip.iBounds()); |
736 bounds.offset(translate.fX, translate.fY); | 708 bounds.offset(translate.fX, translate.fY); |
737 clip.enableStencilClip(bounds); | 709 clip.enableStencilClip(bounds); |
738 drawContext->drawContextPriv().stencilRect(clip, *pass, fals
e, viewMatrix, | 710 drawContext->drawContextPriv().stencilRect(clip, *pass, fals
e, viewMatrix, |
739 SkRect::Make(clip
SpaceIBounds)); | 711 SkRect::Make(redu
cedClip.iBounds())); |
740 } | 712 } |
741 } | 713 } |
742 } | 714 } |
743 } | 715 } |
744 return true; | 716 return true; |
745 } | 717 } |
746 | 718 |
747 //////////////////////////////////////////////////////////////////////////////// | 719 //////////////////////////////////////////////////////////////////////////////// |
748 sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
rovider, | 720 sk_sp<GrTexture> GrClipStackClip::CreateSoftwareClipMask(GrTextureProvider* texP
rovider, |
749 int32_t elementsGenID, | 721 const GrReducedClip& re
ducedClip, |
750 GrReducedClip::InitialS
tate initialState, | 722 const SkVector& clipToM
askOffset) { |
751 const GrReducedClip::El
ementList& elements, | |
752 const SkVector& clipToM
askOffset, | |
753 const SkIRect& clipSpac
eIBounds) { | |
754 GrUniqueKey key; | 723 GrUniqueKey key; |
755 GetClipMaskKey(elementsGenID, clipSpaceIBounds, &key); | 724 GetClipMaskKey(reducedClip.genID(), reducedClip.iBounds(), &key); |
756 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { | 725 if (GrTexture* texture = texProvider->findAndRefTextureByUniqueKey(key)) { |
757 return sk_sp<GrTexture>(texture); | 726 return sk_sp<GrTexture>(texture); |
758 } | 727 } |
759 | 728 |
760 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin | 729 // The mask texture may be larger than necessary. We round out the clip spac
e bounds and pin |
761 // the top left corner of the resulting rect to the top left of the texture. | 730 // the top left corner of the resulting rect to the top left of the texture. |
762 SkIRect maskSpaceIBounds = SkIRect::MakeWH(clipSpaceIBounds.width(), clipSpa
ceIBounds.height()); | 731 SkIRect maskSpaceIBounds = SkIRect::MakeWH(reducedClip.width(), reducedClip.
height()); |
763 | 732 |
764 GrSWMaskHelper helper(texProvider); | 733 GrSWMaskHelper helper(texProvider); |
765 | 734 |
766 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip | 735 // Set the matrix so that rendered clip elements are transformed to mask spa
ce from clip |
767 // space. | 736 // space. |
768 SkMatrix translate; | 737 SkMatrix translate; |
769 translate.setTranslate(clipToMaskOffset); | 738 translate.setTranslate(clipToMaskOffset); |
770 | 739 |
771 helper.init(maskSpaceIBounds, &translate); | 740 helper.init(maskSpaceIBounds, &translate); |
772 helper.clear(GrReducedClip::kAllIn_InitialState == initialState ? 0xFF : 0x0
0); | 741 helper.clear(GrReducedClip::InitialState::kAllIn == reducedClip.initialState
() ? 0xFF : 0x00); |
773 | 742 |
774 for (GrReducedClip::ElementList::Iter iter(elements.headIter()) ; iter.get()
; iter.next()) { | 743 for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()
) { |
775 const Element* element = iter.get(); | 744 const Element* element = iter.get(); |
776 SkRegion::Op op = element->getOp(); | 745 SkRegion::Op op = element->getOp(); |
777 | 746 |
778 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { | 747 if (SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op ==
op) { |
779 // Intersect and reverse difference require modifying pixels outside
of the geometry | 748 // Intersect and reverse difference require modifying pixels outside
of the geometry |
780 // that is being "drawn". In both cases we erase all the pixels outs
ide of the geometry | 749 // that is being "drawn". In both cases we erase all the pixels outs
ide of the geometry |
781 // but leave the pixels inside the geometry alone. For reverse diffe
rence we invert all | 750 // but leave the pixels inside the geometry alone. For reverse diffe
rence we invert all |
782 // the pixels before clearing the ones outside the geometry. | 751 // the pixels before clearing the ones outside the geometry. |
783 if (SkRegion::kReverseDifference_Op == op) { | 752 if (SkRegion::kReverseDifference_Op == op) { |
784 SkRect temp = SkRect::Make(clipSpaceIBounds); | 753 SkRect temp = SkRect::Make(reducedClip.iBounds()); |
785 // invert the entire scene | 754 // invert the entire scene |
786 helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF); | 755 helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF); |
787 } | 756 } |
788 SkPath clipPath; | 757 SkPath clipPath; |
789 element->asPath(&clipPath); | 758 element->asPath(&clipPath); |
790 clipPath.toggleInverseFillType(); | 759 clipPath.toggleInverseFillType(); |
791 GrShape shape(clipPath, GrStyle::SimpleFill()); | 760 GrShape shape(clipPath, GrStyle::SimpleFill()); |
792 helper.drawShape(shape, SkRegion::kReplace_Op, element->isAA(), 0x00
); | 761 helper.drawShape(shape, SkRegion::kReplace_Op, element->isAA(), 0x00
); |
793 continue; | 762 continue; |
794 } | 763 } |
795 | 764 |
796 // The other ops (union, xor, diff) only affect pixels inside | 765 // The other ops (union, xor, diff) only affect pixels inside |
797 // the geometry so they can just be drawn normally | 766 // the geometry so they can just be drawn normally |
798 if (Element::kRect_Type == element->getType()) { | 767 if (Element::kRect_Type == element->getType()) { |
799 helper.drawRect(element->getRect(), op, element->isAA(), 0xFF); | 768 helper.drawRect(element->getRect(), op, element->isAA(), 0xFF); |
800 } else { | 769 } else { |
801 SkPath path; | 770 SkPath path; |
802 element->asPath(&path); | 771 element->asPath(&path); |
803 GrShape shape(path, GrStyle::SimpleFill()); | 772 GrShape shape(path, GrStyle::SimpleFill()); |
804 helper.drawShape(shape, op, element->isAA(), 0xFF); | 773 helper.drawShape(shape, op, element->isAA(), 0xFF); |
805 } | 774 } |
806 } | 775 } |
807 | 776 |
808 // Allocate clip mask texture | 777 // Allocate clip mask texture |
809 GrSurfaceDesc desc; | 778 GrSurfaceDesc desc; |
810 desc.fWidth = clipSpaceIBounds.width(); | 779 desc.fWidth = reducedClip.width(); |
811 desc.fHeight = clipSpaceIBounds.height(); | 780 desc.fHeight = reducedClip.height(); |
812 desc.fConfig = kAlpha_8_GrPixelConfig; | 781 desc.fConfig = kAlpha_8_GrPixelConfig; |
813 | 782 |
814 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); | 783 sk_sp<GrTexture> result(texProvider->createApproxTexture(desc)); |
815 if (!result) { | 784 if (!result) { |
816 return nullptr; | 785 return nullptr; |
817 } | 786 } |
818 result->resourcePriv().setUniqueKey(key); | 787 result->resourcePriv().setUniqueKey(key); |
819 | 788 |
820 helper.toTexture(result.get()); | 789 helper.toTexture(result.get()); |
821 | 790 |
822 return result; | 791 return result; |
823 } | 792 } |
OLD | NEW |