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