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