GrRenderTargetContext.cpp revision 17b7c054339dfa592571ebd92d2419949baca6f0
1/* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrRenderTargetContext.h" 9#include "../private/GrAuditTrail.h" 10#include "../private/SkShadowFlags.h" 11#include "GrAppliedClip.h" 12#include "GrBackendSemaphore.h" 13#include "GrBlurUtils.h" 14#include "GrColor.h" 15#include "GrContextPriv.h" 16#include "GrDrawingManager.h" 17#include "GrFixedClip.h" 18#include "GrGpuResourcePriv.h" 19#include "GrOpList.h" 20#include "GrPathRenderer.h" 21#include "GrQuad.h" 22#include "GrRenderTarget.h" 23#include "GrRenderTargetContextPriv.h" 24#include "GrResourceProvider.h" 25#include "GrStencilAttachment.h" 26#include "GrTracing.h" 27#include "SkDrawShadowInfo.h" 28#include "SkGr.h" 29#include "SkLatticeIter.h" 30#include "SkMatrixPriv.h" 31#include "SkShadowUtils.h" 32#include "SkSurfacePriv.h" 33#include "effects/GrRRectEffect.h" 34#include "ops/GrAtlasTextOp.h" 35#include "ops/GrClearOp.h" 36#include "ops/GrClearStencilClipOp.h" 37#include "ops/GrDebugMarkerOp.h" 38#include "ops/GrDrawAtlasOp.h" 39#include "ops/GrDrawOp.h" 40#include "ops/GrDrawVerticesOp.h" 41#include "ops/GrLatticeOp.h" 42#include "ops/GrOp.h" 43#include "ops/GrOvalOpFactory.h" 44#include "ops/GrRectOpFactory.h" 45#include "ops/GrRegionOp.h" 46#include "ops/GrSemaphoreOp.h" 47#include "ops/GrShadowRRectOp.h" 48#include "ops/GrStencilPathOp.h" 49#include "ops/GrTextureOp.h" 50#include "text/GrAtlasTextContext.h" 51#include "text/GrStencilAndCoverTextContext.h" 52#include "text/GrTextUtils.h" 53 54class GrRenderTargetContext::TextTarget : public GrTextUtils::Target { 55public: 56 TextTarget(GrRenderTargetContext* renderTargetContext) 57 : Target(renderTargetContext->width(), renderTargetContext->height(), 58 renderTargetContext->colorSpaceInfo()) 59 , fRenderTargetContext(renderTargetContext) {} 60 61 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) { 62 fRenderTargetContext->addDrawOp(clip, std::move(op)); 63 } 64 65 void drawPath(const GrClip& clip, const SkPath& path, const SkPaint& paint, 66 const SkMatrix& viewMatrix, const SkMatrix* pathMatrix, 67 const SkIRect& clipBounds) { 68 GrBlurUtils::drawPathWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext, 69 clip, path, paint, viewMatrix, pathMatrix, clipBounds, 70 false); 71 } 72 73 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix, 74 GrPaint* grPaint) { 75 GrContext* context = fRenderTargetContext->fContext; 76 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo(); 77 if (kARGB_GrMaskFormat == maskFormat) { 78 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint); 79 } else { 80 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint); 81 } 82 } 83 84private: 85 GrRenderTargetContext* fRenderTargetContext; 86}; 87 88#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext()) 89#define ASSERT_SINGLE_OWNER \ 90 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) 91#define ASSERT_SINGLE_OWNER_PRIV \ 92 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());) 93#define RETURN_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return; } 94#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return; } 95#define RETURN_FALSE_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return false; } 96#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return false; } 97#define RETURN_NULL_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return nullptr; } 98 99////////////////////////////////////////////////////////////////////////////// 100 101GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples, 102 const GrCaps& caps) { 103 if (GrAA::kNo == aa) { 104 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect 105 // that. 106 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) { 107 return GrAAType::kMSAA; 108 } 109 return GrAAType::kNone; 110 } 111 switch (fsaaType) { 112 case GrFSAAType::kNone: 113 return GrAAType::kCoverage; 114 case GrFSAAType::kUnifiedMSAA: 115 return GrAAType::kMSAA; 116 case GrFSAAType::kMixedSamples: 117 return GrAllowMixedSamples::kYes == allowMixedSamples ? GrAAType::kMixedSamples 118 : GrAAType::kCoverage; 119 } 120 SK_ABORT("Unexpected fsaa type"); 121 return GrAAType::kNone; 122} 123 124////////////////////////////////////////////////////////////////////////////// 125 126class AutoCheckFlush { 127public: 128 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) { 129 SkASSERT(fDrawingManager); 130 } 131 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); } 132 133private: 134 GrDrawingManager* fDrawingManager; 135}; 136 137bool GrRenderTargetContext::wasAbandoned() const { 138 return this->drawingManager()->wasAbandoned(); 139} 140 141// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress 142// GrOpLists to be picked up and added to by renderTargetContexts lower in the call 143// stack. When this occurs with a closed GrOpList, a new one will be allocated 144// when the renderTargetContext attempts to use it (via getOpList). 145GrRenderTargetContext::GrRenderTargetContext(GrContext* context, 146 GrDrawingManager* drawingMgr, 147 sk_sp<GrRenderTargetProxy> rtp, 148 sk_sp<SkColorSpace> colorSpace, 149 const SkSurfaceProps* surfaceProps, 150 GrAuditTrail* auditTrail, 151 GrSingleOwner* singleOwner, 152 bool managedOpList) 153 : GrSurfaceContext(context, drawingMgr, rtp->config(), std::move(colorSpace), auditTrail, 154 singleOwner) 155 , fRenderTargetProxy(std::move(rtp)) 156 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList())) 157 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) 158 , fManagedOpList(managedOpList) { 159#ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION 160 // MDB TODO: to ensure all resources still get allocated in the correct order in the hybrid 161 // world we need to get the correct opList here so that it, in turn, can grab and hold 162 // its rendertarget. 163 this->getRTOpList(); 164#endif 165 fTextTarget.reset(new TextTarget(this)); 166 SkDEBUGCODE(this->validate();) 167} 168 169#ifdef SK_DEBUG 170void GrRenderTargetContext::validate() const { 171 SkASSERT(fRenderTargetProxy); 172 fRenderTargetProxy->validate(fContext); 173 174 if (fOpList && !fOpList->isClosed()) { 175 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get()); 176 } 177} 178#endif 179 180GrRenderTargetContext::~GrRenderTargetContext() { 181 ASSERT_SINGLE_OWNER 182} 183 184GrTextureProxy* GrRenderTargetContext::asTextureProxy() { 185 return fRenderTargetProxy->asTextureProxy(); 186} 187 188const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const { 189 return fRenderTargetProxy->asTextureProxy(); 190} 191 192sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() { 193 return sk_ref_sp(fRenderTargetProxy->asTextureProxy()); 194} 195 196GrMipMapped GrRenderTargetContext::mipMapped() const { 197 if (const GrTextureProxy* proxy = this->asTextureProxy()) { 198 return proxy->mipMapped(); 199 } 200 return GrMipMapped::kNo; 201} 202 203GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() { 204 ASSERT_SINGLE_OWNER 205 SkDEBUGCODE(this->validate();) 206 207 if (!fOpList || fOpList->isClosed()) { 208 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy.get(), fManagedOpList); 209 } 210 211 return fOpList.get(); 212} 213 214GrOpList* GrRenderTargetContext::getOpList() { 215 return this->getRTOpList(); 216} 217 218void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint, 219 const SkMatrix& viewMatrix, const char text[], 220 size_t byteLength, SkScalar x, SkScalar y, 221 const SkIRect& clipBounds) { 222 ASSERT_SINGLE_OWNER 223 RETURN_IF_ABANDONED 224 SkDEBUGCODE(this->validate();) 225 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawText", fContext); 226 227 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); 228 atlasTextContext->drawText(fContext, fTextTarget.get(), clip, skPaint, viewMatrix, 229 fSurfaceProps, text, byteLength, x, y, clipBounds); 230} 231 232void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint, 233 const SkMatrix& viewMatrix, const char text[], 234 size_t byteLength, const SkScalar pos[], 235 int scalarsPerPosition, const SkPoint& offset, 236 const SkIRect& clipBounds) { 237 ASSERT_SINGLE_OWNER 238 RETURN_IF_ABANDONED 239 SkDEBUGCODE(this->validate();) 240 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPosText", fContext); 241 242 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); 243 atlasTextContext->drawPosText(fContext, fTextTarget.get(), clip, paint, viewMatrix, 244 fSurfaceProps, text, byteLength, pos, scalarsPerPosition, offset, 245 clipBounds); 246} 247 248void GrRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& paint, 249 const SkMatrix& viewMatrix, const SkTextBlob* blob, 250 SkScalar x, SkScalar y, SkDrawFilter* filter, 251 const SkIRect& clipBounds) { 252 ASSERT_SINGLE_OWNER 253 RETURN_IF_ABANDONED 254 SkDEBUGCODE(this->validate();) 255 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextBlob", fContext); 256 257 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext(); 258 atlasTextContext->drawTextBlob(fContext, fTextTarget.get(), clip, paint, viewMatrix, 259 fSurfaceProps, blob, x, y, filter, clipBounds); 260} 261 262void GrRenderTargetContext::discard() { 263 ASSERT_SINGLE_OWNER 264 RETURN_IF_ABANDONED 265 SkDEBUGCODE(this->validate();) 266 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext); 267 268 AutoCheckFlush acf(this->drawingManager()); 269 270 this->getRTOpList()->discard(); 271} 272 273void GrRenderTargetContext::clear(const SkIRect* rect, 274 const GrColor color, 275 CanClearFullscreen canClearFullscreen) { 276 ASSERT_SINGLE_OWNER 277 RETURN_IF_ABANDONED 278 SkDEBUGCODE(this->validate();) 279 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext); 280 281 AutoCheckFlush acf(this->drawingManager()); 282 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, 283 canClearFullscreen); 284} 285 286void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor color) { 287 ASSERT_SINGLE_OWNER_PRIV 288 RETURN_IF_ABANDONED_PRIV 289 SkDEBUGCODE(fRenderTargetContext->validate();) 290 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear", 291 fRenderTargetContext->fContext); 292 293 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 294 295 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(), 296 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight()); 297 298 if (clearRect) { 299 if (clearRect->contains(rtRect)) { 300 clearRect = nullptr; // full screen 301 } else { 302 if (!rtRect.intersect(*clearRect)) { 303 return; 304 } 305 } 306 } 307 308 // TODO: in a post-MDB world this should be handled at the OpList level. 309 // An op-list that is initially cleared and has no other ops should receive an 310 // extra draw. 311 // This path doesn't handle coalescing of full screen clears b.c. it 312 // has to clear the entire render target - not just the content area. 313 // It could be done but will take more finagling. 314 std::unique_ptr<GrOp> op(GrClearOp::Make(rtRect, color, !clearRect)); 315 if (!op) { 316 return; 317 } 318 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps()); 319} 320 321void GrRenderTargetContextPriv::clear(const GrFixedClip& clip, 322 const GrColor color, 323 CanClearFullscreen canClearFullscreen) { 324 ASSERT_SINGLE_OWNER_PRIV 325 RETURN_IF_ABANDONED_PRIV 326 SkDEBUGCODE(fRenderTargetContext->validate();) 327 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear", 328 fRenderTargetContext->fContext); 329 330 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 331 fRenderTargetContext->internalClear(clip, color, canClearFullscreen); 332} 333 334void GrRenderTargetContext::internalClear(const GrFixedClip& clip, 335 const GrColor color, 336 CanClearFullscreen canClearFullscreen) { 337 bool isFull = false; 338 if (!clip.hasWindowRectangles()) { 339 isFull = !clip.scissorEnabled() || 340 (CanClearFullscreen::kYes == canClearFullscreen && 341 fContext->caps()->preferFullscreenClears()) || 342 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height())); 343 } 344 345 if (isFull) { 346 this->getRTOpList()->fullClear(*this->caps(), color); 347 } else { 348 std::unique_ptr<GrOp> op(GrClearOp::Make(clip, color, this->asSurfaceProxy())); 349 if (!op) { 350 return; 351 } 352 this->getRTOpList()->addOp(std::move(op), *this->caps()); 353 } 354} 355 356void GrRenderTargetContext::drawPaint(const GrClip& clip, 357 GrPaint&& paint, 358 const SkMatrix& viewMatrix) { 359 ASSERT_SINGLE_OWNER 360 RETURN_IF_ABANDONED 361 SkDEBUGCODE(this->validate();) 362 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext); 363 364 // set rect to be big enough to fill the space, but not super-huge, so we 365 // don't overflow fixed-point implementations 366 367 SkRect r = fRenderTargetProxy->getBoundsRect(); 368 369 SkRRect rrect; 370 GrAA aa; 371 // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the 372 // transformation for non-rect rrects. Rects caused a performance regression on an Android 373 // test that needs investigation. We also skip cases where there are fragment processors 374 // because they may depend on having correct local coords and this path draws in device space 375 // without a local matrix. 376 if (!paint.numTotalFragmentProcessors() && clip.isRRect(r, &rrect, &aa) && !rrect.isRect()) { 377 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect, 378 GrStyle::SimpleFill()); 379 return; 380 } 381 382 383 bool isPerspective = viewMatrix.hasPerspective(); 384 385 // We attempt to map r by the inverse matrix and draw that. mapRect will 386 // map the four corners and bound them with a new rect. This will not 387 // produce a correct result for some perspective matrices. 388 if (!isPerspective) { 389 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) { 390 SkDebugf("Could not invert matrix\n"); 391 return; 392 } 393 this->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, r); 394 } else { 395 SkMatrix localMatrix; 396 if (!viewMatrix.invert(&localMatrix)) { 397 SkDebugf("Could not invert matrix\n"); 398 return; 399 } 400 401 AutoCheckFlush acf(this->drawingManager()); 402 403 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix( 404 std::move(paint), SkMatrix::I(), localMatrix, r, GrAAType::kNone); 405 this->addDrawOp(clip, std::move(op)); 406 } 407} 408 409static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) { 410 return point.fX >= rect.fLeft && point.fX <= rect.fRight && 411 point.fY >= rect.fTop && point.fY <= rect.fBottom; 412} 413 414// Attempts to crop a rect and optional local rect to the clip boundaries. 415// Returns false if the draw can be skipped entirely. 416static bool crop_filled_rect(int width, int height, const GrClip& clip, 417 const SkMatrix& viewMatrix, SkRect* rect, 418 SkRect* localRect = nullptr) { 419 if (!viewMatrix.rectStaysRect()) { 420 return true; 421 } 422 423 SkIRect clipDevBounds; 424 SkRect clipBounds; 425 426 clip.getConservativeBounds(width, height, &clipDevBounds); 427 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) { 428 return false; 429 } 430 431 if (localRect) { 432 if (!rect->intersects(clipBounds)) { 433 return false; 434 } 435 const SkScalar dx = localRect->width() / rect->width(); 436 const SkScalar dy = localRect->height() / rect->height(); 437 if (clipBounds.fLeft > rect->fLeft) { 438 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx; 439 rect->fLeft = clipBounds.fLeft; 440 } 441 if (clipBounds.fTop > rect->fTop) { 442 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy; 443 rect->fTop = clipBounds.fTop; 444 } 445 if (clipBounds.fRight < rect->fRight) { 446 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx; 447 rect->fRight = clipBounds.fRight; 448 } 449 if (clipBounds.fBottom < rect->fBottom) { 450 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy; 451 rect->fBottom = clipBounds.fBottom; 452 } 453 return true; 454 } 455 456 return rect->intersect(clipBounds); 457} 458 459bool GrRenderTargetContext::drawFilledRect(const GrClip& clip, 460 GrPaint&& paint, 461 GrAA aa, 462 const SkMatrix& viewMatrix, 463 const SkRect& rect, 464 const GrUserStencilSettings* ss) { 465 SkRect croppedRect = rect; 466 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { 467 return true; 468 } 469 470 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 471 std::unique_ptr<GrDrawOp> op; 472 if (GrAAType::kCoverage == aaType) { 473 op = GrRectOpFactory::MakeAAFill(std::move(paint), viewMatrix, croppedRect, ss); 474 } else { 475 op = GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, croppedRect, aaType, ss); 476 } 477 if (!op) { 478 return false; 479 } 480 this->addDrawOp(clip, std::move(op)); 481 return true; 482} 483 484void GrRenderTargetContext::drawRect(const GrClip& clip, 485 GrPaint&& paint, 486 GrAA aa, 487 const SkMatrix& viewMatrix, 488 const SkRect& rect, 489 const GrStyle* style) { 490 if (!style) { 491 style = &GrStyle::SimpleFill(); 492 } 493 ASSERT_SINGLE_OWNER 494 RETURN_IF_ABANDONED 495 SkDEBUGCODE(this->validate();) 496 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext); 497 498 // Path effects should've been devolved to a path in SkGpuDevice 499 SkASSERT(!style->pathEffect()); 500 501 AutoCheckFlush acf(this->drawingManager()); 502 503 const SkStrokeRec& stroke = style->strokeRec(); 504 if (stroke.getStyle() == SkStrokeRec::kFill_Style) { 505 // Check if this is a full RT draw and can be replaced with a clear. We don't bother 506 // checking cases where the RT is fully inside a stroke. 507 SkRect rtRect = fRenderTargetProxy->getBoundsRect(); 508 // Does the clip contain the entire RT? 509 if (clip.quickContains(rtRect)) { 510 SkMatrix invM; 511 if (!viewMatrix.invert(&invM)) { 512 return; 513 } 514 // Does the rect bound the RT? 515 GrQuad quad; 516 quad.setFromMappedRect(rtRect, invM); 517 if (rect_contains_inclusive(rect, quad.point(0)) && 518 rect_contains_inclusive(rect, quad.point(1)) && 519 rect_contains_inclusive(rect, quad.point(2)) && 520 rect_contains_inclusive(rect, quad.point(3))) { 521 // Will it blend? 522 GrColor clearColor; 523 if (paint.isConstantBlendedColor(&clearColor)) { 524 this->clear(nullptr, clearColor, 525 GrRenderTargetContext::CanClearFullscreen::kYes); 526 return; 527 } 528 } 529 } 530 531 if (this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, nullptr)) { 532 return; 533 } 534 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style || 535 stroke.getStyle() == SkStrokeRec::kHairline_Style) { 536 if ((!rect.width() || !rect.height()) && 537 SkStrokeRec::kHairline_Style != stroke.getStyle()) { 538 SkScalar r = stroke.getWidth() / 2; 539 // TODO: Move these stroke->fill fallbacks to GrShape? 540 switch (stroke.getJoin()) { 541 case SkPaint::kMiter_Join: 542 this->drawRect( 543 clip, std::move(paint), aa, viewMatrix, 544 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r}, 545 &GrStyle::SimpleFill()); 546 return; 547 case SkPaint::kRound_Join: 548 // Raster draws nothing when both dimensions are empty. 549 if (rect.width() || rect.height()){ 550 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r); 551 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, 552 GrStyle::SimpleFill()); 553 return; 554 } 555 case SkPaint::kBevel_Join: 556 if (!rect.width()) { 557 this->drawRect(clip, std::move(paint), aa, viewMatrix, 558 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom}, 559 &GrStyle::SimpleFill()); 560 } else { 561 this->drawRect(clip, std::move(paint), aa, viewMatrix, 562 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r}, 563 &GrStyle::SimpleFill()); 564 } 565 return; 566 } 567 } 568 569 std::unique_ptr<GrDrawOp> op; 570 571 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 572 if (GrAAType::kCoverage == aaType) { 573 // The stroke path needs the rect to remain axis aligned (no rotation or skew). 574 if (viewMatrix.rectStaysRect()) { 575 op = GrRectOpFactory::MakeAAStroke(std::move(paint), viewMatrix, rect, stroke); 576 } 577 } else { 578 op = GrRectOpFactory::MakeNonAAStroke(std::move(paint), viewMatrix, rect, stroke, 579 aaType); 580 } 581 582 if (op) { 583 this->addDrawOp(clip, std::move(op)); 584 return; 585 } 586 } 587 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style)); 588} 589 590int GrRenderTargetContextPriv::maxWindowRectangles() const { 591 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles( 592 *fRenderTargetContext->fContext->caps()); 593} 594 595void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { 596 ASSERT_SINGLE_OWNER_PRIV 597 RETURN_IF_ABANDONED_PRIV 598 SkDEBUGCODE(fRenderTargetContext->validate();) 599 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip", 600 fRenderTargetContext->fContext); 601 602 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 603 604 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make( 605 clip, insideStencilMask, 606 fRenderTargetContext->fRenderTargetProxy.get())); 607 if (!op) { 608 return; 609 } 610 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps()); 611} 612 613void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip, 614 GrAAType aaType, 615 const SkMatrix& viewMatrix, 616 const GrPath* path) { 617 ASSERT_SINGLE_OWNER_PRIV 618 RETURN_IF_ABANDONED_PRIV 619 SkDEBUGCODE(fRenderTargetContext->validate();) 620 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath", 621 fRenderTargetContext->fContext); 622 623 SkASSERT(aaType != GrAAType::kCoverage); 624 625 bool useHWAA = GrAATypeIsHW(aaType); 626 // TODO: extract portions of checkDraw that are relevant to path stenciling. 627 SkASSERT(path); 628 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport()); 629 630 // FIXME: Use path bounds instead of this WAR once 631 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved. 632 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height()); 633 634 // Setup clip 635 GrAppliedHardClip appliedClip; 636 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip, 637 &bounds)) { 638 return; 639 } 640 641 fRenderTargetContext->setNeedsStencil(); 642 643 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix, 644 useHWAA, 645 path->getFillType(), 646 appliedClip.hasStencilClip(), 647 appliedClip.scissorState(), 648 path); 649 if (!op) { 650 return; 651 } 652 op->setClippedBounds(bounds); 653 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps()); 654} 655 656void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip, 657 const GrUserStencilSettings* ss, 658 GrAAType aaType, 659 const SkMatrix& viewMatrix, 660 const SkRect& rect) { 661 ASSERT_SINGLE_OWNER_PRIV 662 RETURN_IF_ABANDONED_PRIV 663 SkDEBUGCODE(fRenderTargetContext->validate();) 664 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect", 665 fRenderTargetContext->fContext); 666 667 SkASSERT(GrAAType::kCoverage != aaType); 668 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 669 670 GrPaint paint; 671 paint.setXPFactory(GrDisableColorXPFactory::Get()); 672 std::unique_ptr<GrDrawOp> op = 673 GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, rect, aaType, ss); 674 fRenderTargetContext->addDrawOp(clip, std::move(op)); 675} 676 677bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip, 678 const GrUserStencilSettings* ss, 679 SkRegion::Op op, 680 bool invert, 681 GrAA aa, 682 const SkMatrix& viewMatrix, 683 const SkRect& rect) { 684 ASSERT_SINGLE_OWNER_PRIV 685 RETURN_FALSE_IF_ABANDONED_PRIV 686 SkDEBUGCODE(fRenderTargetContext->validate();) 687 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilRect", 688 fRenderTargetContext->fContext); 689 690 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 691 692 GrPaint paint; 693 paint.setCoverageSetOpXPFactory(op, invert); 694 695 if (fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss)) { 696 return true; 697 } 698 SkPath path; 699 path.setIsVolatile(true); 700 path.addRect(rect); 701 return this->drawAndStencilPath(clip, ss, op, invert, aa, viewMatrix, path); 702} 703 704void GrRenderTargetContext::fillRectToRect(const GrClip& clip, 705 GrPaint&& paint, 706 GrAA aa, 707 const SkMatrix& viewMatrix, 708 const SkRect& rectToDraw, 709 const SkRect& localRect) { 710 ASSERT_SINGLE_OWNER 711 RETURN_IF_ABANDONED 712 SkDEBUGCODE(this->validate();) 713 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectToRect", fContext); 714 715 SkRect croppedRect = rectToDraw; 716 SkRect croppedLocalRect = localRect; 717 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, 718 &croppedRect, &croppedLocalRect)) { 719 return; 720 } 721 722 AutoCheckFlush acf(this->drawingManager()); 723 724 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 725 if (GrAAType::kCoverage != aaType) { 726 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalRect( 727 std::move(paint), viewMatrix, croppedRect, croppedLocalRect, aaType); 728 this->addDrawOp(clip, std::move(op)); 729 return; 730 } 731 732 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalRect( 733 std::move(paint), viewMatrix, croppedRect, croppedLocalRect); 734 if (op) { 735 this->addDrawOp(clip, std::move(op)); 736 return; 737 } 738 739 SkMatrix viewAndUnLocalMatrix; 740 if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) { 741 SkDebugf("fillRectToRect called with empty local matrix.\n"); 742 return; 743 } 744 viewAndUnLocalMatrix.postConcat(viewMatrix); 745 746 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix, 747 GrShape(localRect)); 748} 749 750static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ctm) { 751 // We don't currently look for 90 degree rotations, mirroring, or downscales that sample at 752 // texel centers. 753 if (!ctm.isTranslate()) { 754 return true; 755 } 756 if (src.width() != dst.width() || src.height() != dst.height()) { 757 return true; 758 } 759 // Check that the device space rectangle's fractional offset is the same as the src rectangle, 760 // and that therefore integers in the src image fall on integers in device space. 761 SkScalar x = ctm.getTranslateX(), y = ctm.getTranslateY(); 762 x += dst.fLeft; y += dst.fTop; 763 x -= src.fLeft; y -= src.fTop; 764 return !SkScalarIsInt(x) || !SkScalarIsInt(y); 765} 766 767void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy, 768 GrSamplerState::Filter filter, GrColor color, 769 const SkRect& srcRect, const SkRect& dstRect, 770 const SkMatrix& viewMatrix, 771 sk_sp<GrColorSpaceXform> colorSpaceXform) { 772 ASSERT_SINGLE_OWNER 773 RETURN_IF_ABANDONED 774 SkDEBUGCODE(this->validate();) 775 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureAffine", fContext); 776 SkASSERT(!viewMatrix.hasPerspective()); 777 if (filter != GrSamplerState::Filter::kNearest && !must_filter(srcRect, dstRect, viewMatrix)) { 778 filter = GrSamplerState::Filter::kNearest; 779 } 780 SkRect clippedDstRect = dstRect; 781 SkRect clippedSrcRect = srcRect; 782 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect, 783 &clippedSrcRect)) { 784 return; 785 } 786 787 bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace()); 788 this->addDrawOp(clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, 789 clippedDstRect, viewMatrix, std::move(colorSpaceXform), 790 allowSRGB)); 791} 792 793void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, 794 GrPaint&& paint, 795 GrAA aa, 796 const SkMatrix& viewMatrix, 797 const SkRect& rectToDraw, 798 const SkMatrix& localMatrix) { 799 ASSERT_SINGLE_OWNER 800 RETURN_IF_ABANDONED 801 SkDEBUGCODE(this->validate();) 802 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext); 803 804 SkRect croppedRect = rectToDraw; 805 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) { 806 return; 807 } 808 809 AutoCheckFlush acf(this->drawingManager()); 810 811 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 812 if (GrAAType::kCoverage != aaType) { 813 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix( 814 std::move(paint), viewMatrix, localMatrix, croppedRect, aaType); 815 this->addDrawOp(clip, std::move(op)); 816 return; 817 } 818 819 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalMatrix( 820 std::move(paint), viewMatrix, localMatrix, croppedRect); 821 if (op) { 822 this->addDrawOp(clip, std::move(op)); 823 return; 824 } 825 826 SkMatrix viewAndUnLocalMatrix; 827 if (!localMatrix.invert(&viewAndUnLocalMatrix)) { 828 SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n"); 829 return; 830 } 831 viewAndUnLocalMatrix.postConcat(viewMatrix); 832 833 SkPath path; 834 path.setIsVolatile(true); 835 path.addRect(rectToDraw); 836 path.transform(localMatrix); 837 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix, 838 GrShape(path)); 839} 840 841void GrRenderTargetContext::drawVertices(const GrClip& clip, 842 GrPaint&& paint, 843 const SkMatrix& viewMatrix, 844 sk_sp<SkVertices> vertices, 845 GrPrimitiveType* overridePrimType) { 846 ASSERT_SINGLE_OWNER 847 RETURN_IF_ABANDONED 848 SkDEBUGCODE(this->validate();) 849 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext); 850 851 AutoCheckFlush acf(this->drawingManager()); 852 853 SkASSERT(vertices); 854 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo); 855 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make( 856 std::move(paint), std::move(vertices), viewMatrix, aaType, 857 this->colorSpaceInfo().isGammaCorrect(), 858 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType); 859 this->addDrawOp(clip, std::move(op)); 860} 861 862/////////////////////////////////////////////////////////////////////////////// 863 864void GrRenderTargetContext::drawAtlas(const GrClip& clip, 865 GrPaint&& paint, 866 const SkMatrix& viewMatrix, 867 int spriteCount, 868 const SkRSXform xform[], 869 const SkRect texRect[], 870 const SkColor colors[]) { 871 ASSERT_SINGLE_OWNER 872 RETURN_IF_ABANDONED 873 SkDEBUGCODE(this->validate();) 874 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext); 875 876 AutoCheckFlush acf(this->drawingManager()); 877 878 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo); 879 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(std::move(paint), viewMatrix, aaType, 880 spriteCount, xform, texRect, colors); 881 this->addDrawOp(clip, std::move(op)); 882} 883 884/////////////////////////////////////////////////////////////////////////////// 885 886void GrRenderTargetContext::drawRRect(const GrClip& origClip, 887 GrPaint&& paint, 888 GrAA aa, 889 const SkMatrix& viewMatrix, 890 const SkRRect& rrect, 891 const GrStyle& style) { 892 ASSERT_SINGLE_OWNER 893 RETURN_IF_ABANDONED 894 SkDEBUGCODE(this->validate();) 895 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext); 896 if (rrect.isEmpty()) { 897 return; 898 } 899 900 GrNoClip noclip; 901 const GrClip* clip = &origClip; 902#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 903 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the 904 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it 905 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test 906 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack 907 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. 908 SkRRect devRRect; 909 if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) { 910 clip = &noclip; 911 } 912#endif 913 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice 914 915 AutoCheckFlush acf(this->drawingManager()); 916 const SkStrokeRec stroke = style.strokeRec(); 917 918 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 919 if (GrAAType::kCoverage == aaType) { 920 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); 921 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint), 922 viewMatrix, 923 rrect, 924 stroke, 925 shaderCaps); 926 if (op) { 927 this->addDrawOp(*clip, std::move(op)); 928 return; 929 } 930 } 931 932 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix, 933 GrShape(rrect, style)); 934} 935 936/////////////////////////////////////////////////////////////////////////////// 937 938static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) { 939 SkPoint3 result; 940 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX); 941 result.fZ = pt.fZ; 942 return result; 943} 944 945bool GrRenderTargetContext::drawFastShadow(const GrClip& clip, 946 GrColor color4ub, 947 const SkMatrix& viewMatrix, 948 const SkPath& path, 949 const SkDrawShadowRec& rec) { 950 ASSERT_SINGLE_OWNER 951 if (this->drawingManager()->wasAbandoned()) { 952 return true; 953 } 954 SkDEBUGCODE(this->validate();) 955 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext); 956 957 // check z plane 958 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) || 959 !SkScalarNearlyZero(rec.fZPlaneParams.fY)); 960 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag); 961 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) { 962 return false; 963 } 964 965 SkRRect rrect; 966 SkRect rect; 967 // we can only handle rects, circles, and rrects with circular corners 968 bool isRRect = path.isRRect(&rrect) && rrect.isSimpleCircular() && 969 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero; 970 if (!isRRect && 971 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) && 972 rect.width() > SK_ScalarNearlyZero) { 973 rrect.setOval(rect); 974 isRRect = true; 975 } 976 if (!isRRect && path.isRect(&rect)) { 977 rrect.setRect(rect); 978 isRRect = true; 979 } 980 981 if (!isRRect) { 982 return false; 983 } 984 985 if (rrect.isEmpty()) { 986 return true; 987 } 988 989 AutoCheckFlush acf(this->drawingManager()); 990 991 // transform light 992 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos); 993 994 // 1/scale 995 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ? 996 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) : 997 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] + 998 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]); 999 1000 SkScalar occluderHeight = rec.fZPlaneParams.fZ; 1001 GrColor4f color = GrColor4f::FromGrColor(color4ub); 1002 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag); 1003 bool tonalColor = !SkToBool(rec.fFlags & SkShadowFlags::kDisableTonalColor_ShadowFlag); 1004 1005 if (rec.fAmbientAlpha > 0) { 1006 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight); 1007 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight); 1008 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha; 1009 1010 // Outset the shadow rrect to the border of the penumbra 1011 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale; 1012 SkRRect ambientRRect; 1013 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset); 1014 // If the rrect was an oval then its outset will also be one. 1015 // We set it explicitly to avoid errors. 1016 if (rrect.isOval()) { 1017 ambientRRect = SkRRect::MakeOval(outsetRect); 1018 } else { 1019 SkScalar outsetRad = rrect.getSimpleRadii().fX + ambientPathOutset; 1020 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad); 1021 } 1022 1023 GrColor ambientColor; 1024 if (tonalColor) { 1025 // with tonal color, the color only applies to the spot shadow 1026 ambientColor = GrColorPackRGBA(0, 0, 0, 255.999f*rec.fAmbientAlpha); 1027 } else { 1028 ambientColor = color.mulByScalar(rec.fAmbientAlpha).toGrColor(); 1029 } 1030 if (transparent) { 1031 // set a large inset to force a fill 1032 devSpaceInsetWidth = ambientRRect.width(); 1033 } 1034 // the fraction of the blur we want to apply is devSpaceInsetWidth/devSpaceAmbientBlur, 1035 // which is just 1/umbraRecipAlpha. 1036 SkScalar blurClamp = SkScalarInvert(umbraRecipAlpha); 1037 1038 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(ambientColor, viewMatrix, 1039 ambientRRect, 1040 devSpaceAmbientBlur, 1041 devSpaceInsetWidth, 1042 blurClamp); 1043 SkASSERT(op); 1044 this->addDrawOp(clip, std::move(op)); 1045 } 1046 1047 if (rec.fSpotAlpha > 0) { 1048 SkScalar devSpaceSpotBlur; 1049 SkScalar spotScale; 1050 SkVector spotOffset; 1051 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY, 1052 devLightPos.fZ, rec.fLightRadius, 1053 &devSpaceSpotBlur, &spotScale, &spotOffset); 1054 // handle scale of radius due to CTM 1055 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale; 1056 1057 // Adjust translate for the effect of the scale. 1058 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX]; 1059 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY]; 1060 // This offset is in dev space, need to transform it into source space. 1061 SkMatrix ctmInverse; 1062 if (viewMatrix.invert(&ctmInverse)) { 1063 ctmInverse.mapPoints(&spotOffset, 1); 1064 } else { 1065 // Since the matrix is a similarity, this should never happen, but just in case... 1066 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n"); 1067 SkASSERT(false); 1068 } 1069 1070 // Compute the transformed shadow rrect 1071 SkRRect spotShadowRRect; 1072 SkMatrix shadowTransform; 1073 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY); 1074 rrect.transform(shadowTransform, &spotShadowRRect); 1075 SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX; 1076 1077 // Compute the insetWidth 1078 SkScalar blurOutset = srcSpaceSpotBlur; 1079 SkScalar insetWidth = blurOutset; 1080 if (transparent) { 1081 // If transparent, just do a fill 1082 insetWidth += spotShadowRRect.width(); 1083 } else { 1084 // For shadows, instead of using a stroke we specify an inset from the penumbra 1085 // border. We want to extend this inset area so that it meets up with the caster 1086 // geometry. The inset geometry will by default already be inset by the blur width. 1087 // 1088 // We compare the min and max corners inset by the radius between the original 1089 // rrect and the shadow rrect. The distance between the two plus the difference 1090 // between the scaled radius and the original radius gives the distance from the 1091 // transformed shadow shape to the original shape in that corner. The max 1092 // of these gives the maximum distance we need to cover. 1093 // 1094 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to 1095 // that to get the full insetWidth. 1096 SkScalar maxOffset; 1097 if (rrect.isRect()) { 1098 // Manhattan distance works better for rects 1099 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft - 1100 rrect.rect().fLeft), 1101 SkTAbs(spotShadowRRect.rect().fTop - 1102 rrect.rect().fTop)), 1103 SkTMax(SkTAbs(spotShadowRRect.rect().fRight - 1104 rrect.rect().fRight), 1105 SkTAbs(spotShadowRRect.rect().fBottom - 1106 rrect.rect().fBottom))); 1107 } else { 1108 SkScalar dr = spotRadius - rrect.getSimpleRadii().fX; 1109 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft - 1110 rrect.rect().fLeft + dr, 1111 spotShadowRRect.rect().fTop - 1112 rrect.rect().fTop + dr); 1113 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight - 1114 rrect.rect().fRight - dr, 1115 spotShadowRRect.rect().fBottom - 1116 rrect.rect().fBottom - dr); 1117 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset), 1118 SkPointPriv::LengthSqd(lowerRightOffset))) + dr; 1119 } 1120 insetWidth += maxOffset; 1121 } 1122 1123 // Outset the shadow rrect to the border of the penumbra 1124 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset); 1125 if (spotShadowRRect.isOval()) { 1126 spotShadowRRect = SkRRect::MakeOval(outsetRect); 1127 } else { 1128 SkScalar outsetRad = spotRadius + blurOutset; 1129 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad); 1130 } 1131 1132 GrColor spotColor; 1133 if (tonalColor) { 1134 SkScalar colorScale; 1135 SkScalar tonalAlpha; 1136 SkShadowUtils::ComputeTonalColorParams(color.fRGBA[0], color.fRGBA[1], 1137 color.fRGBA[2], color.fRGBA[3]*rec.fSpotAlpha, 1138 &colorScale, &tonalAlpha); 1139 color.fRGBA[0] *= colorScale; 1140 color.fRGBA[1] *= colorScale; 1141 color.fRGBA[2] *= colorScale; 1142 color.fRGBA[3] = tonalAlpha; 1143 spotColor = color.toGrColor(); 1144 } else { 1145 spotColor = color.mulByScalar(rec.fSpotAlpha).toGrColor(); 1146 } 1147 1148 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(spotColor, viewMatrix, 1149 spotShadowRRect, 1150 2.0f * devSpaceSpotBlur, 1151 insetWidth); 1152 SkASSERT(op); 1153 this->addDrawOp(clip, std::move(op)); 1154 } 1155 1156 return true; 1157} 1158 1159/////////////////////////////////////////////////////////////////////////////// 1160 1161bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, 1162 GrPaint&& paint, 1163 GrAA aa, 1164 const SkMatrix& viewMatrix, 1165 const SkRRect& origOuter, 1166 const SkRRect& origInner) { 1167 SkASSERT(!origInner.isEmpty()); 1168 SkASSERT(!origOuter.isEmpty()); 1169 1170 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter); 1171 1172 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 1173 1174 if (GrAAType::kMSAA == aaType) { 1175 return false; 1176 } 1177 1178 if (GrAAType::kCoverage == aaType && inner->isCircle() && outer->isCircle()) { 1179 auto outerR = outer->width() / 2.f; 1180 auto innerR = inner->width() / 2.f; 1181 auto cx = outer->getBounds().fLeft + outerR; 1182 auto cy = outer->getBounds().fTop + outerR; 1183 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) && 1184 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) { 1185 auto avgR = (innerR + outerR) / 2.f; 1186 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR); 1187 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 1188 stroke.setStrokeStyle(outerR - innerR); 1189 auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds, 1190 stroke, this->caps()->shaderCaps()); 1191 if (op) { 1192 this->addDrawOp(clip, std::move(op)); 1193 return true; 1194 } 1195 } 1196 } 1197 1198 GrClipEdgeType innerEdgeType, outerEdgeType; 1199 if (GrAAType::kCoverage == aaType) { 1200 innerEdgeType = GrClipEdgeType::kInverseFillAA; 1201 outerEdgeType = GrClipEdgeType::kFillAA; 1202 } else { 1203 innerEdgeType = GrClipEdgeType::kInverseFillBW; 1204 outerEdgeType = GrClipEdgeType::kFillBW; 1205 } 1206 1207 SkMatrix inverseVM; 1208 if (!viewMatrix.isIdentity()) { 1209 if (!origInner.transform(viewMatrix, inner.writable())) { 1210 return false; 1211 } 1212 if (!origOuter.transform(viewMatrix, outer.writable())) { 1213 return false; 1214 } 1215 if (!viewMatrix.invert(&inverseVM)) { 1216 return false; 1217 } 1218 } else { 1219 inverseVM.reset(); 1220 } 1221 1222 const auto& caps = *this->caps()->shaderCaps(); 1223 // TODO these need to be a geometry processors 1224 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps); 1225 if (!innerEffect) { 1226 return false; 1227 } 1228 1229 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps); 1230 if (!outerEffect) { 1231 return false; 1232 } 1233 1234 paint.addCoverageFragmentProcessor(std::move(innerEffect)); 1235 paint.addCoverageFragmentProcessor(std::move(outerEffect)); 1236 1237 SkRect bounds = outer->getBounds(); 1238 if (GrAAType::kCoverage == aaType) { 1239 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 1240 } 1241 1242 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds, 1243 inverseVM); 1244 return true; 1245} 1246 1247void GrRenderTargetContext::drawDRRect(const GrClip& clip, 1248 GrPaint&& paint, 1249 GrAA aa, 1250 const SkMatrix& viewMatrix, 1251 const SkRRect& outer, 1252 const SkRRect& inner) { 1253 ASSERT_SINGLE_OWNER 1254 RETURN_IF_ABANDONED 1255 SkDEBUGCODE(this->validate();) 1256 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext); 1257 1258 SkASSERT(!outer.isEmpty()); 1259 SkASSERT(!inner.isEmpty()); 1260 1261 AutoCheckFlush acf(this->drawingManager()); 1262 1263 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) { 1264 return; 1265 } 1266 1267 SkPath path; 1268 path.setIsVolatile(true); 1269 path.addRRect(inner); 1270 path.addRRect(outer); 1271 path.setFillType(SkPath::kEvenOdd_FillType); 1272 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path)); 1273} 1274 1275/////////////////////////////////////////////////////////////////////////////// 1276 1277void GrRenderTargetContext::drawRegion(const GrClip& clip, 1278 GrPaint&& paint, 1279 GrAA aa, 1280 const SkMatrix& viewMatrix, 1281 const SkRegion& region, 1282 const GrStyle& style, 1283 const GrUserStencilSettings* ss) { 1284 ASSERT_SINGLE_OWNER 1285 RETURN_IF_ABANDONED 1286 SkDEBUGCODE(this->validate();) 1287 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext); 1288 1289 if (GrAA::kYes == aa) { 1290 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix 1291 // to see whether aa is really required. 1292 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) && 1293 SkScalarIsInt(viewMatrix.getTranslateX()) && 1294 SkScalarIsInt(viewMatrix.getTranslateY())) { 1295 aa = GrAA::kNo; 1296 } 1297 } 1298 bool complexStyle = !style.isSimpleFill(); 1299 if (complexStyle || GrAA::kYes == aa) { 1300 SkPath path; 1301 region.getBoundaryPath(&path); 1302 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style); 1303 } 1304 1305 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo); 1306 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(std::move(paint), viewMatrix, region, aaType, 1307 ss); 1308 this->addDrawOp(clip, std::move(op)); 1309} 1310 1311void GrRenderTargetContext::drawOval(const GrClip& clip, 1312 GrPaint&& paint, 1313 GrAA aa, 1314 const SkMatrix& viewMatrix, 1315 const SkRect& oval, 1316 const GrStyle& style) { 1317 ASSERT_SINGLE_OWNER 1318 RETURN_IF_ABANDONED 1319 SkDEBUGCODE(this->validate();) 1320 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext); 1321 1322 if (oval.isEmpty()) { 1323 return; 1324 } 1325 1326 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice 1327 1328 AutoCheckFlush acf(this->drawingManager()); 1329 const SkStrokeRec& stroke = style.strokeRec(); 1330 1331 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 1332 if (GrAAType::kCoverage == aaType) { 1333 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); 1334 std::unique_ptr<GrDrawOp> op = 1335 GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps); 1336 if (op) { 1337 this->addDrawOp(clip, std::move(op)); 1338 return; 1339 } 1340 } 1341 1342 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, 1343 GrShape(SkRRect::MakeOval(oval), style)); 1344} 1345 1346void GrRenderTargetContext::drawArc(const GrClip& clip, 1347 GrPaint&& paint, 1348 GrAA aa, 1349 const SkMatrix& viewMatrix, 1350 const SkRect& oval, 1351 SkScalar startAngle, 1352 SkScalar sweepAngle, 1353 bool useCenter, 1354 const GrStyle& style) { 1355 ASSERT_SINGLE_OWNER 1356 RETURN_IF_ABANDONED 1357 SkDEBUGCODE(this->validate();) 1358 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext); 1359 1360 AutoCheckFlush acf(this->drawingManager()); 1361 1362 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 1363 if (GrAAType::kCoverage == aaType) { 1364 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps(); 1365 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint), 1366 viewMatrix, 1367 oval, 1368 startAngle, 1369 sweepAngle, 1370 useCenter, 1371 style, 1372 shaderCaps); 1373 if (op) { 1374 this->addDrawOp(clip, std::move(op)); 1375 return; 1376 } 1377 } 1378 SkPath path; 1379 SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter, 1380 style.isSimpleFill()); 1381 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style)); 1382} 1383 1384void GrRenderTargetContext::drawImageLattice(const GrClip& clip, 1385 GrPaint&& paint, 1386 const SkMatrix& viewMatrix, 1387 int imageWidth, 1388 int imageHeight, 1389 std::unique_ptr<SkLatticeIter> iter, 1390 const SkRect& dst) { 1391 ASSERT_SINGLE_OWNER 1392 RETURN_IF_ABANDONED 1393 SkDEBUGCODE(this->validate();) 1394 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext); 1395 1396 AutoCheckFlush acf(this->drawingManager()); 1397 1398 std::unique_ptr<GrDrawOp> op = GrLatticeOp::MakeNonAA(std::move(paint), viewMatrix, imageWidth, 1399 imageHeight, std::move(iter), dst); 1400 this->addDrawOp(clip, std::move(op)); 1401} 1402 1403GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO( 1404 int numSemaphores, GrBackendSemaphore backendSemaphores[]) { 1405 ASSERT_SINGLE_OWNER 1406 if (this->drawingManager()->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; } 1407 SkDEBUGCODE(this->validate();) 1408 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "prepareForExternalIO", fContext); 1409 1410 return this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get(), 1411 numSemaphores, 1412 backendSemaphores); 1413} 1414 1415bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores, 1416 const GrBackendSemaphore* waitSemaphores) { 1417 ASSERT_SINGLE_OWNER 1418 RETURN_FALSE_IF_ABANDONED 1419 SkDEBUGCODE(this->validate();) 1420 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext); 1421 1422 AutoCheckFlush acf(this->drawingManager()); 1423 1424 if (numSemaphores && !this->caps()->fenceSyncSupport()) { 1425 return false; 1426 } 1427 1428 SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores); 1429 for (int i = 0; i < numSemaphores; ++i) { 1430 sk_sp<GrSemaphore> sema = fContext->resourceProvider()->wrapBackendSemaphore( 1431 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait, 1432 kAdopt_GrWrapOwnership); 1433 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get())); 1434 this->getRTOpList()->addOp(std::move(waitOp), *this->caps()); 1435 } 1436 return true; 1437} 1438 1439void GrRenderTargetContext::insertEventMarker(const SkString& str) { 1440 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fRenderTargetProxy.get(), str)); 1441 this->getRTOpList()->addOp(std::move(op), *this->caps()); 1442} 1443 1444 1445// Can 'path' be drawn as a pair of filled nested rectangles? 1446static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) { 1447 1448 if (path.isInverseFillType()) { 1449 return false; 1450 } 1451 1452 // TODO: this restriction could be lifted if we were willing to apply 1453 // the matrix to all the points individually rather than just to the rect 1454 if (!viewMatrix.rectStaysRect()) { 1455 return false; 1456 } 1457 1458 SkPath::Direction dirs[2]; 1459 if (!path.isNestedFillRects(rects, dirs)) { 1460 return false; 1461 } 1462 1463 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) { 1464 // The two rects need to be wound opposite to each other 1465 return false; 1466 } 1467 1468 // Right now, nested rects where the margin is not the same width 1469 // all around do not render correctly 1470 const SkScalar* outer = rects[0].asScalars(); 1471 const SkScalar* inner = rects[1].asScalars(); 1472 1473 bool allEq = true; 1474 1475 SkScalar margin = SkScalarAbs(outer[0] - inner[0]); 1476 bool allGoE1 = margin >= SK_Scalar1; 1477 1478 for (int i = 1; i < 4; ++i) { 1479 SkScalar temp = SkScalarAbs(outer[i] - inner[i]); 1480 if (temp < SK_Scalar1) { 1481 allGoE1 = false; 1482 } 1483 if (!SkScalarNearlyEqual(margin, temp)) { 1484 allEq = false; 1485 } 1486 } 1487 1488 return allEq || allGoE1; 1489} 1490 1491void GrRenderTargetContext::drawPath(const GrClip& clip, 1492 GrPaint&& paint, 1493 GrAA aa, 1494 const SkMatrix& viewMatrix, 1495 const SkPath& path, 1496 const GrStyle& style) { 1497 ASSERT_SINGLE_OWNER 1498 RETURN_IF_ABANDONED 1499 SkDEBUGCODE(this->validate();) 1500 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawPath", fContext); 1501 1502 GrShape shape(path, style); 1503 if (shape.isEmpty()) { 1504 if (shape.inverseFilled()) { 1505 this->drawPaint(clip, std::move(paint), viewMatrix); 1506 } 1507 return; 1508 } 1509 1510 AutoCheckFlush acf(this->drawingManager()); 1511 1512 if (!shape.style().hasPathEffect()) { 1513 SkRRect rrect; 1514 // We can ignore the starting point and direction since there is no path effect. 1515 bool inverted; 1516 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) { 1517 if (rrect.isRect()) { 1518 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(), 1519 &shape.style()); 1520 return; 1521 } else if (rrect.isOval()) { 1522 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style()); 1523 return; 1524 } 1525 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style()); 1526 return; 1527 } 1528 } 1529 1530 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo); 1531 if (GrAAType::kCoverage == aaType) { 1532 // TODO: Make GrShape check for nested rects. 1533 SkRect rects[2]; 1534 if (shape.style().isSimpleFill() && fills_as_nested_rects(viewMatrix, path, rects)) { 1535 // Concave AA paths are expensive - try to avoid them for special cases 1536 SkRect rects[2]; 1537 1538 if (fills_as_nested_rects(viewMatrix, path, rects)) { 1539 std::unique_ptr<GrDrawOp> op = 1540 GrRectOpFactory::MakeAAFillNestedRects(std::move(paint), viewMatrix, rects); 1541 if (op) { 1542 this->addDrawOp(clip, std::move(op)); 1543 } 1544 // A null return indicates that there is nothing to draw in this case. 1545 return; 1546 } 1547 } 1548 } 1549 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape); 1550} 1551 1552bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip, 1553 const GrUserStencilSettings* ss, 1554 SkRegion::Op op, 1555 bool invert, 1556 GrAA aa, 1557 const SkMatrix& viewMatrix, 1558 const SkPath& path) { 1559 ASSERT_SINGLE_OWNER_PRIV 1560 RETURN_FALSE_IF_ABANDONED_PRIV 1561 SkDEBUGCODE(fRenderTargetContext->validate();) 1562 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath", 1563 fRenderTargetContext->fContext); 1564 1565 if (path.isEmpty() && path.isInverseFillType()) { 1566 this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(), 1567 SkRect::MakeIWH(fRenderTargetContext->width(), 1568 fRenderTargetContext->height())); 1569 return true; 1570 } 1571 1572 AutoCheckFlush acf(fRenderTargetContext->drawingManager()); 1573 1574 // An Assumption here is that path renderer would use some form of tweaking 1575 // the src color (either the input alpha or in the frag shader) to implement 1576 // aa. If we have some future driver-mojo path AA that can do the right 1577 // thing WRT to the blend then we'll need some query on the PR. 1578 GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo); 1579 bool hasUserStencilSettings = !ss->isUnused(); 1580 1581 SkIRect clipConservativeBounds; 1582 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(), 1583 &clipConservativeBounds, nullptr); 1584 1585 GrShape shape(path, GrStyle::SimpleFill()); 1586 GrPathRenderer::CanDrawPathArgs canDrawArgs; 1587 canDrawArgs.fCaps = fRenderTargetContext->drawingManager()->getContext()->caps(); 1588 canDrawArgs.fViewMatrix = &viewMatrix; 1589 canDrawArgs.fShape = &shape; 1590 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds; 1591 canDrawArgs.fAAType = aaType; 1592 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings; 1593 1594 // Don't allow the SW renderer 1595 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer( 1596 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor); 1597 if (!pr) { 1598 return false; 1599 } 1600 1601 GrPaint paint; 1602 paint.setCoverageSetOpXPFactory(op, invert); 1603 1604 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(), 1605 std::move(paint), 1606 ss, 1607 fRenderTargetContext, 1608 &clip, 1609 &clipConservativeBounds, 1610 &viewMatrix, 1611 &shape, 1612 aaType, 1613 fRenderTargetContext->colorSpaceInfo().isGammaCorrect()}; 1614 pr->drawPath(args); 1615 return true; 1616} 1617 1618SkBudgeted GrRenderTargetContextPriv::isBudgeted() const { 1619 ASSERT_SINGLE_OWNER_PRIV 1620 1621 if (fRenderTargetContext->wasAbandoned()) { 1622 return SkBudgeted::kNo; 1623 } 1624 1625 SkDEBUGCODE(fRenderTargetContext->validate();) 1626 1627 return fRenderTargetContext->fRenderTargetProxy->isBudgeted(); 1628} 1629 1630void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip, 1631 GrPaint&& paint, 1632 GrAA aa, 1633 const SkMatrix& viewMatrix, 1634 const GrShape& originalShape) { 1635 ASSERT_SINGLE_OWNER 1636 RETURN_IF_ABANDONED 1637 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext); 1638 1639 SkIRect clipConservativeBounds; 1640 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr); 1641 1642 GrShape tempShape; 1643 // NVPR cannot handle hairlines, so this would get picked up by a different stencil and 1644 // cover path renderer (i.e. default path renderer). The hairline renderer produces much 1645 // smoother hairlines than MSAA. 1646 GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline() 1647 ? GrAllowMixedSamples::kNo 1648 : GrAllowMixedSamples::kYes; 1649 GrAAType aaType = this->chooseAAType(aa, allowMixedSamples); 1650 GrPathRenderer::CanDrawPathArgs canDrawArgs; 1651 canDrawArgs.fCaps = this->drawingManager()->getContext()->caps(); 1652 canDrawArgs.fViewMatrix = &viewMatrix; 1653 canDrawArgs.fShape = &originalShape; 1654 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds; 1655 canDrawArgs.fHasUserStencilSettings = false; 1656 1657 GrPathRenderer* pr; 1658 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor; 1659 if (originalShape.isEmpty() && !originalShape.inverseFilled()) { 1660 return; 1661 } 1662 1663 canDrawArgs.fAAType = aaType; 1664 1665 // Try a 1st time without applying any of the style to the geometry (and barring sw) 1666 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); 1667 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix); 1668 1669 if (!pr && originalShape.style().pathEffect()) { 1670 // It didn't work above, so try again with the path effect applied. 1671 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale); 1672 if (tempShape.isEmpty()) { 1673 return; 1674 } 1675 canDrawArgs.fShape = &tempShape; 1676 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType); 1677 } 1678 if (!pr) { 1679 if (canDrawArgs.fShape->style().applies()) { 1680 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, 1681 styleScale); 1682 if (tempShape.isEmpty()) { 1683 return; 1684 } 1685 canDrawArgs.fShape = &tempShape; 1686 } 1687 // This time, allow SW renderer 1688 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType); 1689 } 1690 1691 if (!pr) { 1692#ifdef SK_DEBUG 1693 SkDebugf("Unable to find path renderer compatible with path.\n"); 1694#endif 1695 return; 1696 } 1697 1698 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(), 1699 std::move(paint), 1700 &GrUserStencilSettings::kUnused, 1701 this, 1702 &clip, 1703 &clipConservativeBounds, 1704 &viewMatrix, 1705 canDrawArgs.fShape, 1706 aaType, 1707 this->colorSpaceInfo().isGammaCorrect()}; 1708 pr->drawPath(args); 1709} 1710 1711static void op_bounds(SkRect* bounds, const GrOp* op) { 1712 *bounds = op->bounds(); 1713 if (op->hasZeroArea()) { 1714 if (op->hasAABloat()) { 1715 bounds->outset(0.5f, 0.5f); 1716 } else { 1717 // We don't know which way the particular GPU will snap lines or points at integer 1718 // coords. So we ensure that the bounds is large enough for either snap. 1719 SkRect before = *bounds; 1720 bounds->roundOut(bounds); 1721 if (bounds->fLeft == before.fLeft) { 1722 bounds->fLeft -= 1; 1723 } 1724 if (bounds->fTop == before.fTop) { 1725 bounds->fTop -= 1; 1726 } 1727 if (bounds->fRight == before.fRight) { 1728 bounds->fRight += 1; 1729 } 1730 if (bounds->fBottom == before.fBottom) { 1731 bounds->fBottom += 1; 1732 } 1733 } 1734 } 1735} 1736 1737uint32_t GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op) { 1738 ASSERT_SINGLE_OWNER 1739 if (this->drawingManager()->wasAbandoned()) { 1740 return SK_InvalidUniqueID; 1741 } 1742 SkDEBUGCODE(this->validate();) 1743 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext); 1744 1745 // Setup clip 1746 SkRect bounds; 1747 op_bounds(&bounds, op.get()); 1748 GrAppliedClip appliedClip; 1749 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags(); 1750 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA, 1751 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip, 1752 &bounds)) { 1753 return SK_InvalidUniqueID; 1754 } 1755 1756 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil || 1757 appliedClip.hasStencilClip()) { 1758 this->getOpList()->setStencilLoadOp(GrLoadOp::kClear); 1759 1760 this->setNeedsStencil(); 1761 } 1762 1763 GrPixelConfigIsClamped dstIsClamped = 1764 GrGetPixelConfigIsClamped(this->colorSpaceInfo().config()); 1765 GrXferProcessor::DstProxy dstProxy; 1766 if (GrDrawOp::RequiresDstTexture::kYes == op->finalize(*this->caps(), &appliedClip, 1767 dstIsClamped)) { 1768 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, op->bounds(), &dstProxy)) { 1769 return SK_InvalidUniqueID; 1770 } 1771 } 1772 1773 op->setClippedBounds(bounds); 1774 return this->getRTOpList()->addOp(std::move(op), *this->caps(), 1775 std::move(appliedClip), dstProxy); 1776} 1777 1778bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip, 1779 const SkRect& opBounds, 1780 GrXferProcessor::DstProxy* dstProxy) { 1781 if (this->caps()->textureBarrierSupport()) { 1782 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) { 1783 // The render target is a texture, so we can read from it directly in the shader. The XP 1784 // will be responsible to detect this situation and request a texture barrier. 1785 dstProxy->setProxy(sk_ref_sp(texProxy)); 1786 dstProxy->setOffset(0, 0); 1787 return true; 1788 } 1789 } 1790 1791 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height()); 1792 1793 SkIRect clippedRect; 1794 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect); 1795 SkIRect drawIBounds; 1796 opBounds.roundOut(&drawIBounds); 1797 // Cover up for any precision issues by outsetting the op bounds a pixel in each direction. 1798 drawIBounds.outset(1, 1); 1799 if (!clippedRect.intersect(drawIBounds)) { 1800#ifdef SK_DEBUG 1801 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw."); 1802#endif 1803 return false; 1804 } 1805 1806 // MSAA consideration: When there is support for reading MSAA samples in the shader we could 1807 // have per-sample dst values by making the copy multisampled. 1808 GrSurfaceDesc desc; 1809 bool rectsMustMatch = false; 1810 bool disallowSubrect = false; 1811 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch, &disallowSubrect)) { 1812 desc.fFlags = kRenderTarget_GrSurfaceFlag; 1813 desc.fOrigin = kBottomLeft_GrSurfaceOrigin; 1814 desc.fConfig = rtProxy->config(); 1815 } 1816 1817 if (!disallowSubrect) { 1818 copyRect = clippedRect; 1819 } 1820 1821 SkIPoint dstPoint, dstOffset; 1822 SkBackingFit fit; 1823 if (rectsMustMatch) { 1824 SkASSERT(desc.fOrigin == rtProxy->origin()); 1825 desc.fWidth = rtProxy->width(); 1826 desc.fHeight = rtProxy->height(); 1827 dstPoint = {copyRect.fLeft, copyRect.fTop}; 1828 dstOffset = {0, 0}; 1829 fit = SkBackingFit::kExact; 1830 } else { 1831 desc.fWidth = copyRect.width(); 1832 desc.fHeight = copyRect.height(); 1833 dstPoint = {0, 0}; 1834 dstOffset = {copyRect.fLeft, copyRect.fTop}; 1835 fit = SkBackingFit::kApprox; 1836 } 1837 1838 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeDeferredSurfaceContext( 1839 desc, 1840 GrMipMapped::kNo, 1841 fit, 1842 SkBudgeted::kYes); 1843 if (!sContext) { 1844 SkDebugf("setupDstTexture: surfaceContext creation failed.\n"); 1845 return false; 1846 } 1847 1848 if (!sContext->copy(rtProxy, copyRect, dstPoint)) { 1849 SkDebugf("setupDstTexture: copy failed.\n"); 1850 return false; 1851 } 1852 1853 dstProxy->setProxy(sContext->asTextureProxyRef()); 1854 dstProxy->setOffset(dstOffset); 1855 return true; 1856} 1857