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