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