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