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