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