| 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 |