1/* 2 * Copyright 2011 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 "src/gpu/v1/Device_v1.h" 9 10#include "include/core/SkImageFilter.h" 11#include "include/core/SkMaskFilter.h" 12#include "include/core/SkPathEffect.h" 13#include "include/core/SkPicture.h" 14#include "include/core/SkSurface.h" 15#include "include/core/SkVertices.h" 16#include "include/effects/SkRuntimeEffect.h" 17#include "include/gpu/GrDirectContext.h" 18#include "include/gpu/GrRecordingContext.h" 19#include "include/private/SkShadowFlags.h" 20#include "include/private/SkTo.h" 21#include "src/core/SkCanvasPriv.h" 22#include "src/core/SkClipStack.h" 23#include "src/core/SkDraw.h" 24#include "src/core/SkImageFilterCache.h" 25#include "src/core/SkImageFilter_Base.h" 26#include "src/core/SkLatticeIter.h" 27#include "src/core/SkPictureData.h" 28#include "src/core/SkRRectPriv.h" 29#include "src/core/SkRasterClip.h" 30#include "src/core/SkRecord.h" 31#include "src/core/SkStroke.h" 32#include "src/core/SkTLazy.h" 33#include "src/core/SkVerticesPriv.h" 34#include "src/gpu/GrBlurUtils.h" 35#include "src/gpu/GrDirectContextPriv.h" 36#include "src/gpu/GrGpu.h" 37#include "src/gpu/GrRecordingContextPriv.h" 38#include "src/gpu/GrStyle.h" 39#include "src/gpu/GrSurfaceProxyPriv.h" 40#include "src/gpu/GrTracing.h" 41#include "src/gpu/SkGr.h" 42#include "src/gpu/effects/GrDisableColorXP.h" 43#include "src/gpu/effects/GrRRectEffect.h" 44#include "src/gpu/geometry/GrStyledShape.h" 45#include "src/image/SkImage_Base.h" 46#include "src/image/SkReadPixelsRec.h" 47#include "src/image/SkSurface_Gpu.h" 48#include "src/utils/SkUTF.h" 49 50#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner()) 51 52 53/////////////////////////////////////////////////////////////////////////////// 54 55namespace { 56 57bool force_aa_clip(const skgpu::v1::SurfaceDrawContext* sdc) { 58 return sdc->numSamples() > 1 || sdc->alwaysAntialias(); 59} 60 61inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) { 62 switch (mode) { 63 case SkCanvas::kPoints_PointMode: 64 return GrPrimitiveType::kPoints; 65 case SkCanvas::kLines_PointMode: 66 return GrPrimitiveType::kLines; 67 case SkCanvas::kPolygon_PointMode: 68 return GrPrimitiveType::kLineStrip; 69 } 70 SK_ABORT("Unexpected mode"); 71} 72 73std::unique_ptr<GrFragmentProcessor> make_inverse_rrect_fp(const SkMatrix& viewMatrix, 74 const SkRRect& rrect, GrAA aa, 75 const GrShaderCaps& shaderCaps) { 76 SkTCopyOnFirstWrite<SkRRect> devRRect(rrect); 77 if (viewMatrix.isIdentity() || rrect.transform(viewMatrix, devRRect.writable())) { 78 auto edgeType = (aa == GrAA::kYes) ? GrClipEdgeType::kInverseFillAA 79 : GrClipEdgeType::kInverseFillBW; 80 auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, edgeType, *devRRect, 81 shaderCaps); 82 return (success) ? std::move(fp) : nullptr; 83 } 84 return nullptr; 85} 86 87bool init_vertices_paint(GrRecordingContext* rContext, 88 const GrColorInfo& colorInfo, 89 const SkPaint& skPaint, 90 const SkMatrixProvider& matrixProvider, 91 SkBlendMode bmode, 92 bool hasColors, 93 GrPaint* grPaint) { 94 if (hasColors) { 95 // When there are colors and a shader, the shader and colors are combined using bmode. 96 // With no shader, we just use the colors (kDst). 97 return SkPaintToGrPaintWithBlend(rContext, 98 colorInfo, 99 skPaint, 100 matrixProvider, 101 skPaint.getShader() ? bmode : SkBlendMode::kDst, 102 grPaint); 103 } else { 104 return SkPaintToGrPaint(rContext, colorInfo, skPaint, matrixProvider, grPaint); 105 } 106} 107 108} // anonymous namespace 109 110namespace skgpu::v1 { 111 112sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext, 113 GrColorType colorType, 114 sk_sp<GrSurfaceProxy> proxy, 115 sk_sp<SkColorSpace> colorSpace, 116 GrSurfaceOrigin origin, 117 const SkSurfaceProps& surfaceProps, 118 InitContents init) { 119 auto sdc = SurfaceDrawContext::Make(rContext, 120 colorType, 121 std::move(proxy), 122 std::move(colorSpace), 123 origin, 124 surfaceProps); 125 126 return Device::Make(std::move(sdc), kPremul_SkAlphaType, init); 127} 128 129sk_sp<BaseDevice> Device::Make(std::unique_ptr<SurfaceDrawContext> sdc, 130 SkAlphaType alphaType, 131 InitContents init) { 132 if (!sdc) { 133 return nullptr; 134 } 135 136 GrRecordingContext* rContext = sdc->recordingContext(); 137 if (rContext->abandoned()) { 138 return nullptr; 139 } 140 141 SkColorType ct = GrColorTypeToSkColorType(sdc->colorInfo().colorType()); 142 143 DeviceFlags flags; 144 if (!rContext->colorTypeSupportedAsSurface(ct) || 145 !CheckAlphaTypeAndGetFlags(alphaType, init, &flags)) { 146 return nullptr; 147 } 148 return sk_sp<Device>(new Device(std::move(sdc), flags)); 149} 150 151sk_sp<BaseDevice> Device::Make(GrRecordingContext* rContext, 152 SkBudgeted budgeted, 153 const SkImageInfo& ii, 154 SkBackingFit fit, 155 int sampleCount, 156 GrMipmapped mipMapped, 157 GrProtected isProtected, 158 GrSurfaceOrigin origin, 159 const SkSurfaceProps& props, 160 InitContents init) { 161 if (!rContext) { 162 return nullptr; 163 } 164 165 auto sdc = SurfaceDrawContext::Make(rContext, 166 SkColorTypeToGrColorType(ii.colorType()), 167 ii.refColorSpace(), 168 fit, 169 ii.dimensions(), 170 props, 171 sampleCount, 172 mipMapped, 173 isProtected, 174 origin, 175 budgeted); 176 177 return Device::Make(std::move(sdc), ii.alphaType(), init); 178} 179 180Device::Device(std::unique_ptr<SurfaceDrawContext> sdc, DeviceFlags flags) 181 : INHERITED(sk_ref_sp(sdc->recordingContext()), 182 MakeInfo(sdc.get(), flags), 183 sdc->surfaceProps()) 184 , fSurfaceDrawContext(std::move(sdc)) 185 , fClip(SkIRect::MakeSize(fSurfaceDrawContext->dimensions()), 186 &this->asMatrixProvider(), 187 force_aa_clip(fSurfaceDrawContext.get())) { 188 if (flags & DeviceFlags::kNeedClear) { 189 this->clearAll(); 190 } 191} 192 193/////////////////////////////////////////////////////////////////////////////// 194 195bool Device::onReadPixels(const SkPixmap& pm, int x, int y) { 196 ASSERT_SINGLE_OWNER 197 198 // Context TODO: Elevate direct context requirement to public API 199 auto dContext = fContext->asDirectContext(); 200 if (!dContext || !SkImageInfoValidConversion(pm.info(), this->imageInfo())) { 201 return false; 202 } 203 204 return fSurfaceDrawContext->readPixels(dContext, pm, {x, y}); 205} 206 207bool Device::onWritePixels(const SkPixmap& pm, int x, int y) { 208 ASSERT_SINGLE_OWNER 209 210 // Context TODO: Elevate direct context requirement to public API 211 auto dContext = fContext->asDirectContext(); 212 if (!dContext || !SkImageInfoValidConversion(this->imageInfo(), pm.info())) { 213 return false; 214 } 215 216 return fSurfaceDrawContext->writePixels(dContext, pm, {x, y}); 217} 218 219bool Device::onAccessPixels(SkPixmap* pmap) { 220 ASSERT_SINGLE_OWNER 221 return false; 222} 223 224SurfaceDrawContext* Device::surfaceDrawContext() { 225 ASSERT_SINGLE_OWNER 226 return fSurfaceDrawContext.get(); 227} 228 229const SurfaceDrawContext* Device::surfaceDrawContext() const { 230 ASSERT_SINGLE_OWNER 231 return fSurfaceDrawContext.get(); 232} 233 234skgpu::SurfaceFillContext* Device::surfaceFillContext() { 235 ASSERT_SINGLE_OWNER 236 return fSurfaceDrawContext.get(); 237} 238 239void Device::clearAll() { 240 ASSERT_SINGLE_OWNER 241 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "clearAll", fContext.get()); 242 243 SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); 244 fSurfaceDrawContext->clearAtLeast(rect, SK_PMColor4fTRANSPARENT); 245} 246 247/////////////////////////////////////////////////////////////////////////////// 248 249void Device::onClipPath(const SkPath& path, SkClipOp op, bool aa) { 250#if GR_TEST_UTILS 251 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) { 252 this->onClipPath(SkPath(path).setIsVolatile(true), op, aa); 253 return; 254 } 255#endif 256 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference); 257 fClip.clipPath(this->localToDevice(), path, GrAA(aa), op); 258} 259 260void Device::onClipRegion(const SkRegion& globalRgn, SkClipOp op) { 261 SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference); 262 263 // Regions don't actually need AA, but in DMSAA mode every clip element is antialiased. 264 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias()); 265 266 if (globalRgn.isEmpty()) { 267 fClip.clipRect(SkMatrix::I(), SkRect::MakeEmpty(), aa, op); 268 } else if (globalRgn.isRect()) { 269 fClip.clipRect(this->globalToDevice().asM33(), SkRect::Make(globalRgn.getBounds()), aa, op); 270 } else { 271 SkPath path; 272 globalRgn.getBoundaryPath(&path); 273 fClip.clipPath(this->globalToDevice().asM33(), path, aa, op); 274 } 275} 276 277void Device::onAsRgnClip(SkRegion* region) const { 278 SkIRect bounds = fClip.getConservativeBounds(); 279 // Assume wide open and then perform intersect/difference operations reducing the region 280 region->setRect(bounds); 281 const SkRegion deviceBounds(bounds); 282 for (const ClipStack::Element& e : fClip) { 283 SkRegion tmp; 284 if (e.fShape.isRect() && e.fLocalToDevice.isIdentity()) { 285 tmp.setRect(e.fShape.rect().roundOut()); 286 } else { 287 SkPath tmpPath; 288 e.fShape.asPath(&tmpPath); 289 tmpPath.transform(e.fLocalToDevice); 290 tmp.setPath(tmpPath, deviceBounds); 291 } 292 293 region->op(tmp, (SkRegion::Op) e.fOp); 294 } 295} 296 297bool Device::onClipIsAA() const { 298 for (const ClipStack::Element& e : fClip) { 299 if (e.fAA == GrAA::kYes) { 300 return true; 301 } 302 SkASSERT(!fSurfaceDrawContext->alwaysAntialias()); 303 } 304 return false; 305} 306 307SkBaseDevice::ClipType Device::onGetClipType() const { 308 ClipStack::ClipState state = fClip.clipState(); 309 if (state == ClipStack::ClipState::kEmpty) { 310 return ClipType::kEmpty; 311 } else if (state == ClipStack::ClipState::kDeviceRect || 312 state == ClipStack::ClipState::kWideOpen) { 313 return ClipType::kRect; 314 } else { 315 return ClipType::kComplex; 316 } 317} 318 319/////////////////////////////////////////////////////////////////////////////// 320 321void Device::drawPaint(const SkPaint& paint) { 322 ASSERT_SINGLE_OWNER 323 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get()); 324 325 GrPaint grPaint; 326 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 327 this->asMatrixProvider(), &grPaint)) { 328 return; 329 } 330 331 fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice()); 332} 333 334void Device::drawPoints(SkCanvas::PointMode mode, 335 size_t count, 336 const SkPoint pts[], 337 const SkPaint& paint) { 338 ASSERT_SINGLE_OWNER 339 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get()); 340 SkScalar width = paint.getStrokeWidth(); 341 if (width < 0) { 342 return; 343 } 344 345 GrAA aa = fSurfaceDrawContext->chooseAA(paint); 346 347 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) { 348 GrStyle style(paint, SkPaint::kStroke_Style); 349 GrPaint grPaint; 350 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 351 this->asMatrixProvider(), &grPaint)) { 352 return; 353 } 354 SkPath path; 355 path.setIsVolatile(true); 356 path.moveTo(pts[0]); 357 path.lineTo(pts[1]); 358 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint), aa, this->localToDevice(), 359 path, style); 360 return; 361 } 362 363 SkScalar scales[2]; 364 bool isHairline = (0 == width) || 365 (1 == width && this->localToDevice().getMinMaxScales(scales) && 366 SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f)); 367 // we only handle non-coverage-aa hairlines and paints without path effects or mask filters, 368 // else we let the SkDraw call our drawPath() 369 if (!isHairline || 370 paint.getPathEffect() || 371 paint.getMaskFilter() || 372 fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) { 373 SkRasterClip rc(this->devClipBounds()); 374 SkDraw draw; 375 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0); 376 draw.fMatrixProvider = this; 377 draw.fRC = &rc; 378 draw.drawPoints(mode, count, pts, paint, this); 379 return; 380 } 381 382 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode); 383 384 const SkMatrixProvider* matrixProvider = this; 385#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 386 SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider; 387 // This offsetting in device space matches the expectations of the Android framework for non-AA 388 // points and lines. 389 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) { 390 static const SkScalar kOffset = 0.063f; // Just greater than 1/16. 391 matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset); 392 } 393#endif 394 395 GrPaint grPaint; 396 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 397 *matrixProvider, &grPaint)) { 398 return; 399 } 400 401 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; 402 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr, 403 nullptr); 404 405 fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider, 406 std::move(vertices), &primitiveType); 407} 408 409/////////////////////////////////////////////////////////////////////////////// 410 411void Device::drawRect(const SkRect& rect, const SkPaint& paint) { 412 ASSERT_SINGLE_OWNER 413 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRect", fContext.get()); 414 415 GrStyle style(paint); 416 417 // A couple reasons we might need to call drawPath. 418 if (paint.getMaskFilter() || paint.getPathEffect()) { 419 GrStyledShape shape(rect, style); 420 421 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), 422 this->clip(), paint, this->asMatrixProvider(), shape); 423 return; 424 } 425 426 GrPaint grPaint; 427 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 428 this->asMatrixProvider(), &grPaint)) { 429 return; 430 } 431 432 fSurfaceDrawContext->drawRect(this->clip(), std::move(grPaint), 433 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), rect, 434 &style); 435} 436 437void Device::drawEdgeAAQuad(const SkRect& rect, 438 const SkPoint clip[4], 439 SkCanvas::QuadAAFlags aaFlags, 440 const SkColor4f& color, 441 SkBlendMode mode) { 442 ASSERT_SINGLE_OWNER 443 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawEdgeAAQuad", fContext.get()); 444 445 SkPMColor4f dstColor = SkColor4fPrepForDst(color, fSurfaceDrawContext->colorInfo()).premul(); 446 447 GrPaint grPaint; 448 grPaint.setColor4f(dstColor); 449 if (mode != SkBlendMode::kSrcOver) { 450 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode)); 451 } 452 453 // This is exclusively meant for tiling operations, so keep AA enabled to handle MSAA seaming 454 GrQuadAAFlags grAA = SkToGrQuadAAFlags(aaFlags); 455 if (clip) { 456 // Use fillQuadWithEdgeAA 457 fSurfaceDrawContext->fillQuadWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA, 458 this->localToDevice(), clip, nullptr); 459 } else { 460 // Use fillRectWithEdgeAA to preserve mathematical properties of dst being rectangular 461 fSurfaceDrawContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), GrAA::kYes, grAA, 462 this->localToDevice(), rect); 463 } 464} 465 466/////////////////////////////////////////////////////////////////////////////// 467 468void Device::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 469 ASSERT_SINGLE_OWNER 470 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawRRect", fContext.get()); 471 472 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter()); 473 if (mf) { 474 if (mf->hasFragmentProcessor()) { 475 mf = nullptr; // already handled in SkPaintToGrPaint 476 } 477 } 478 479 GrStyle style(paint); 480 481 if (mf || style.pathEffect()) { 482 // A path effect will presumably transform this rrect into something else. 483 GrStyledShape shape(rrect, style); 484 485 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), 486 this->clip(), paint, this->asMatrixProvider(), shape); 487 return; 488 } 489 490 SkASSERT(!style.pathEffect()); 491 492 GrPaint grPaint; 493 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 494 this->asMatrixProvider(), &grPaint)) { 495 return; 496 } 497 498 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint), 499 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), 500 rrect, style); 501} 502 503void Device::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 504 ASSERT_SINGLE_OWNER 505 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDRRect", fContext.get()); 506 if (outer.isEmpty()) { 507 return; 508 } 509 510 if (inner.isEmpty()) { 511 return this->drawRRect(outer, paint); 512 } 513 514 SkStrokeRec stroke(paint); 515 516 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) { 517 // For axis-aligned filled DRRects, just draw a regular rrect with inner clipped out using a 518 // coverage FP instead of using path rendering. 519 if (auto fp = make_inverse_rrect_fp(this->localToDevice(), inner, 520 fSurfaceDrawContext->chooseAA(paint), 521 *fSurfaceDrawContext->caps()->shaderCaps())) { 522 GrPaint grPaint; 523 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 524 this->asMatrixProvider(), &grPaint)) { 525 return; 526 } 527 SkASSERT(!grPaint.hasCoverageFragmentProcessor()); 528 grPaint.setCoverageFragmentProcessor(std::move(fp)); 529 fSurfaceDrawContext->drawRRect(this->clip(), std::move(grPaint), 530 fSurfaceDrawContext->chooseAA(paint), 531 this->localToDevice(), outer, GrStyle()); 532 return; 533 } 534 } 535 536 SkPath path; 537 path.setIsVolatile(true); 538 path.addRRect(outer); 539 path.addRRect(inner); 540 path.setFillType(SkPathFillType::kEvenOdd); 541 542 // TODO: We are losing the possible mutability of the path here but this should probably be 543 // fixed by upgrading GrStyledShape to handle DRRects. 544 GrStyledShape shape(path, paint); 545 546 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(), 547 paint, this->asMatrixProvider(), shape); 548} 549 550///////////////////////////////////////////////////////////////////////////// 551 552void Device::drawRegion(const SkRegion& region, const SkPaint& paint) { 553 ASSERT_SINGLE_OWNER 554 555 if (paint.getMaskFilter()) { 556 SkPath path; 557 region.getBoundaryPath(&path); 558 path.setIsVolatile(true); 559 return this->drawPath(path, paint, true); 560 } 561 562 GrPaint grPaint; 563 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 564 this->asMatrixProvider(), &grPaint)) { 565 return; 566 } 567 568 fSurfaceDrawContext->drawRegion(this->clip(), std::move(grPaint), 569 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), 570 region, GrStyle(paint)); 571} 572 573void Device::drawOval(const SkRect& oval, const SkPaint& paint) { 574 ASSERT_SINGLE_OWNER 575 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawOval", fContext.get()); 576 577 if (paint.getMaskFilter()) { 578 // The RRect path can handle special case blurring 579 SkRRect rr = SkRRect::MakeOval(oval); 580 return this->drawRRect(rr, paint); 581 } 582 583 GrPaint grPaint; 584 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 585 this->asMatrixProvider(), &grPaint)) { 586 return; 587 } 588 589 fSurfaceDrawContext->drawOval(this->clip(), std::move(grPaint), 590 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval, 591 GrStyle(paint)); 592} 593 594void Device::drawArc(const SkRect& oval, 595 SkScalar startAngle, 596 SkScalar sweepAngle, 597 bool useCenter, 598 const SkPaint& paint) { 599 ASSERT_SINGLE_OWNER 600 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawArc", fContext.get()); 601 if (paint.getMaskFilter()) { 602 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint); 603 return; 604 } 605 GrPaint grPaint; 606 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 607 this->asMatrixProvider(), &grPaint)) { 608 return; 609 } 610 611 fSurfaceDrawContext->drawArc(this->clip(), std::move(grPaint), 612 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), oval, 613 startAngle, sweepAngle, useCenter, GrStyle(paint)); 614} 615 616/////////////////////////////////////////////////////////////////////////////// 617 618void Device::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) { 619#if GR_TEST_UTILS 620 if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) { 621 this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true); 622 return; 623 } 624#endif 625 ASSERT_SINGLE_OWNER 626 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPath", fContext.get()); 627 if (!paint.getMaskFilter()) { 628 GrPaint grPaint; 629 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, 630 this->asMatrixProvider(), &grPaint)) { 631 return; 632 } 633 fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint), 634 fSurfaceDrawContext->chooseAA(paint), this->localToDevice(), 635 origSrcPath, GrStyle(paint)); 636 return; 637 } 638 639 // TODO: losing possible mutability of 'origSrcPath' here 640 GrStyledShape shape(origSrcPath, paint); 641 642 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fSurfaceDrawContext.get(), this->clip(), 643 paint, this->asMatrixProvider(), shape); 644} 645 646sk_sp<SkSpecialImage> Device::makeSpecial(const SkBitmap& bitmap) { 647 ASSERT_SINGLE_OWNER 648 649 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's 650 // semantics). Since this is cached we would have to bake the fit into the cache key though. 651 auto view = std::get<0>(GrMakeCachedBitmapProxyView(fContext.get(), bitmap)); 652 if (!view) { 653 return nullptr; 654 } 655 656 const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions()); 657 658 // GrMakeCachedBitmapProxyView creates a tight copy of 'bitmap' so we don't have to subset 659 // the special image 660 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 661 rect, 662 bitmap.getGenerationID(), 663 std::move(view), 664 SkColorTypeToGrColorType(bitmap.colorType()), 665 bitmap.refColorSpace(), 666 this->surfaceProps()); 667} 668 669sk_sp<SkSpecialImage> Device::makeSpecial(const SkImage* image) { 670 ASSERT_SINGLE_OWNER 671 672 SkPixmap pm; 673 if (image->isTextureBacked()) { 674 auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); 675 SkASSERT(view); 676 677 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 678 SkIRect::MakeWH(image->width(), image->height()), 679 image->uniqueID(), 680 std::move(view), 681 ct, 682 image->refColorSpace(), 683 this->surfaceProps()); 684 } else if (image->peekPixels(&pm)) { 685 SkBitmap bm; 686 687 bm.installPixels(pm); 688 return this->makeSpecial(bm); 689 } else { 690 return nullptr; 691 } 692} 693 694sk_sp<SkSpecialImage> Device::snapSpecial(const SkIRect& subset, bool forceCopy) { 695 ASSERT_SINGLE_OWNER 696 697 auto sdc = fSurfaceDrawContext.get(); 698 699 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image 700 // since it would require us to make a copy of the underlying VkImage which we don't have access 701 // to. Additionaly we can't stop and start the render pass that is used with the secondary 702 // command buffer. 703 if (sdc->wrapsVkSecondaryCB()) { 704 return nullptr; 705 } 706 707 SkASSERT(sdc->asSurfaceProxy()); 708 709 SkIRect finalSubset = subset; 710 GrSurfaceProxyView view = sdc->readSurfaceView(); 711 if (forceCopy || !view.asTextureProxy()) { 712 // When the device doesn't have a texture, or a copy is requested, we create a temporary 713 // texture that matches the device contents 714 view = GrSurfaceProxyView::Copy(fContext.get(), 715 std::move(view), 716 GrMipmapped::kNo, // Don't auto generate mips 717 subset, 718 SkBackingFit::kApprox, 719 SkBudgeted::kYes); // Always budgeted 720 if (!view) { 721 return nullptr; 722 } 723 // Since this copied only the requested subset, the special image wrapping the proxy no 724 // longer needs the original subset. 725 finalSubset = SkIRect::MakeSize(view.dimensions()); 726 } 727 728 GrColorType ct = SkColorTypeToGrColorType(this->imageInfo().colorType()); 729 730 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 731 finalSubset, 732 kNeedNewImageUniqueID_SpecialImage, 733 std::move(view), 734 ct, 735 this->imageInfo().refColorSpace(), 736 this->surfaceProps()); 737} 738 739void Device::drawDevice(SkBaseDevice* device, 740 const SkSamplingOptions& sampling, 741 const SkPaint& paint) { 742 ASSERT_SINGLE_OWNER 743 // clear of the source device must occur before CHECK_SHOULD_DRAW 744 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawDevice", fContext.get()); 745 this->INHERITED::drawDevice(device, sampling, paint); 746} 747 748void Device::drawImageRect(const SkImage* image, 749 const SkRect* src, 750 const SkRect& dst, 751 const SkSamplingOptions& sampling, 752 const SkPaint& paint, 753 SkCanvas::SrcRectConstraint constraint) { 754 ASSERT_SINGLE_OWNER 755 GrAA aa = fSurfaceDrawContext->chooseAA(paint); 756 GrQuadAAFlags aaFlags = (aa == GrAA::kYes) ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone; 757 this->drawImageQuad(image, src, &dst, nullptr, aa, aaFlags, nullptr, sampling, paint, 758 constraint); 759} 760 761void Device::drawViewLattice(GrSurfaceProxyView view, 762 const GrColorInfo& info, 763 std::unique_ptr<SkLatticeIter> iter, 764 const SkRect& dst, 765 SkFilterMode filter, 766 const SkPaint& origPaint) { 767 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawViewLattice", fContext.get()); 768 SkASSERT(view); 769 770 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint); 771 772 if (!info.isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) { 773 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF)); 774 } 775 GrPaint grPaint; 776 if (!SkPaintToGrPaintWithPrimitiveColor(this->recordingContext(), 777 fSurfaceDrawContext->colorInfo(), *paint, 778 this->asMatrixProvider(), &grPaint)) { 779 return; 780 } 781 782 if (info.isAlphaOnly()) { 783 // If we were doing this with an FP graph we'd use a kDstIn blend between the texture and 784 // the paint color. 785 view.concatSwizzle(GrSwizzle("aaaa")); 786 } 787 auto csxf = GrColorSpaceXform::Make(info, fSurfaceDrawContext->colorInfo()); 788 789 fSurfaceDrawContext->drawImageLattice(this->clip(), std::move(grPaint), this->localToDevice(), 790 std::move(view), info.alphaType(), std::move(csxf), 791 filter, std::move(iter), dst); 792} 793 794void Device::drawImageLattice(const SkImage* image, 795 const SkCanvas::Lattice& lattice, 796 const SkRect& dst, 797 SkFilterMode filter, 798 const SkPaint& paint) { 799 ASSERT_SINGLE_OWNER 800 auto iter = std::make_unique<SkLatticeIter>(lattice, dst); 801 if (auto [view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) { 802 GrColorInfo colorInfo(ct, image->alphaType(), image->refColorSpace()); 803 this->drawViewLattice(std::move(view), 804 std::move(colorInfo), 805 std::move(iter), 806 dst, 807 filter, 808 paint); 809 } 810} 811 812void Device::drawVertices(const SkVertices* vertices, SkBlendMode mode, const SkPaint& paint) { 813 ASSERT_SINGLE_OWNER 814 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawVertices", fContext.get()); 815 SkASSERT(vertices); 816 817 SkVerticesPriv info(vertices->priv()); 818 819 GrPaint grPaint; 820 if (!init_vertices_paint(fContext.get(), fSurfaceDrawContext->colorInfo(), paint, 821 this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) { 822 return; 823 } 824 fSurfaceDrawContext->drawVertices(this->clip(), 825 std::move(grPaint), 826 this->asMatrixProvider(), 827 sk_ref_sp(const_cast<SkVertices*>(vertices)), 828 nullptr); 829} 830 831/////////////////////////////////////////////////////////////////////////////// 832 833void Device::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) { 834#if GR_TEST_UTILS 835 if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) { 836 this->drawShadow(SkPath(path).setIsVolatile(true), rec); 837 return; 838 } 839#endif 840 ASSERT_SINGLE_OWNER 841 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawShadow", fContext.get()); 842 843 if (!fSurfaceDrawContext->drawFastShadow(this->clip(), this->localToDevice(), path, rec)) { 844 // failed to find an accelerated case 845 this->INHERITED::drawShadow(path, rec); 846 } 847} 848 849/////////////////////////////////////////////////////////////////////////////// 850 851void Device::drawAtlas(const SkRSXform xform[], 852 const SkRect texRect[], 853 const SkColor colors[], 854 int count, 855 SkBlendMode mode, 856 const SkPaint& paint) { 857 ASSERT_SINGLE_OWNER 858 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawAtlas", fContext.get()); 859 860 GrPaint grPaint; 861 if (colors) { 862 if (!SkPaintToGrPaintWithBlend(this->recordingContext(), fSurfaceDrawContext->colorInfo(), 863 paint, this->asMatrixProvider(), mode, &grPaint)) { 864 return; 865 } 866 } else { 867 if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), 868 paint, this->asMatrixProvider(), &grPaint)) { 869 return; 870 } 871 } 872 873 fSurfaceDrawContext->drawAtlas(this->clip(), std::move(grPaint), this->localToDevice(), count, 874 xform, texRect, colors); 875} 876 877/////////////////////////////////////////////////////////////////////////////// 878 879void Device::onDrawGlyphRunList(const SkGlyphRunList& glyphRunList, const SkPaint& paint) { 880 ASSERT_SINGLE_OWNER 881 GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawGlyphRunList", fContext.get()); 882 SkASSERT(!glyphRunList.hasRSXForm()); 883 884 fSurfaceDrawContext->drawGlyphRunList( 885 this->clip(), this->asMatrixProvider(), glyphRunList, paint); 886} 887 888/////////////////////////////////////////////////////////////////////////////// 889 890void Device::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) { 891 ASSERT_SINGLE_OWNER 892 893 GrBackendApi api = this->recordingContext()->backend(); 894 if (GrBackendApi::kVulkan == api) { 895 const SkMatrix& ctm = this->localToDevice(); 896 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm; 897 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw = 898 drawable->snapGpuDrawHandler(api, combinedMatrix, this->devClipBounds(), 899 this->imageInfo()); 900 if (gpuDraw) { 901 fSurfaceDrawContext->drawDrawable( 902 std::move(gpuDraw), combinedMatrix.mapRect(drawable->getBounds())); 903 return; 904 } 905 } 906 this->INHERITED::drawDrawable(drawable, matrix, canvas); 907} 908 909 910/////////////////////////////////////////////////////////////////////////////// 911 912bool Device::wait(int numSemaphores, 913 const GrBackendSemaphore* waitSemaphores, 914 bool deleteSemaphoresAfterWait) { 915 ASSERT_SINGLE_OWNER 916 917 return fSurfaceDrawContext->waitOnSemaphores(numSemaphores, waitSemaphores, 918 deleteSemaphoresAfterWait); 919} 920 921bool Device::replaceBackingProxy(SkSurface::ContentChangeMode mode, 922 sk_sp<GrRenderTargetProxy> newRTP, 923 GrColorType grColorType, 924 sk_sp<SkColorSpace> colorSpace, 925 GrSurfaceOrigin origin, 926 const SkSurfaceProps& props) { 927 auto sdc = SurfaceDrawContext::Make(fContext.get(), grColorType, std::move(newRTP), 928 std::move(colorSpace), origin, props); 929 if (!sdc) { 930 return false; 931 } 932 933 SkASSERT(sdc->dimensions() == fSurfaceDrawContext->dimensions()); 934 SkASSERT(sdc->numSamples() == fSurfaceDrawContext->numSamples()); 935 SkASSERT(sdc->asSurfaceProxy()->priv().isExact()); 936 if (mode == SkSurface::kRetain_ContentChangeMode) { 937 if (fContext->abandoned()) { 938 return false; 939 } 940 941 SkASSERT(fSurfaceDrawContext->asTextureProxy()); 942 SkAssertResult(sdc->blitTexture(fSurfaceDrawContext->readSurfaceView(), 943 SkIRect::MakeWH(this->width(), this->height()), 944 SkIPoint::Make(0, 0))); 945 } 946 947 fSurfaceDrawContext = std::move(sdc); 948 return true; 949} 950 951void Device::asyncRescaleAndReadPixels(const SkImageInfo& info, 952 const SkIRect& srcRect, 953 RescaleGamma rescaleGamma, 954 RescaleMode rescaleMode, 955 ReadPixelsCallback callback, 956 ReadPixelsContext context) { 957 auto* sdc = fSurfaceDrawContext.get(); 958 // Context TODO: Elevate direct context requirement to public API. 959 auto dContext = sdc->recordingContext()->asDirectContext(); 960 if (!dContext) { 961 return; 962 } 963 sdc->asyncRescaleAndReadPixels(dContext, info, srcRect, rescaleGamma, rescaleMode, callback, 964 context); 965} 966 967void Device::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, 968 sk_sp<SkColorSpace> dstColorSpace, 969 const SkIRect& srcRect, 970 SkISize dstSize, 971 RescaleGamma rescaleGamma, 972 RescaleMode rescaleMode, 973 ReadPixelsCallback callback, 974 ReadPixelsContext context) { 975 auto* sdc = fSurfaceDrawContext.get(); 976 // Context TODO: Elevate direct context requirement to public API. 977 auto dContext = sdc->recordingContext()->asDirectContext(); 978 if (!dContext) { 979 return; 980 } 981 sdc->asyncRescaleAndReadPixelsYUV420(dContext, 982 yuvColorSpace, 983 std::move(dstColorSpace), 984 srcRect, 985 dstSize, 986 rescaleGamma, 987 rescaleMode, 988 callback, 989 context); 990} 991 992/////////////////////////////////////////////////////////////////////////////// 993 994SkBaseDevice* Device::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 995 ASSERT_SINGLE_OWNER 996 997 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry); 998 999 // layers are never drawn in repeat modes, so we can request an approx 1000 // match and ignore any padding. 1001 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox 1002 : SkBackingFit::kExact; 1003 1004 SkASSERT(cinfo.fInfo.colorType() != kRGBA_1010102_SkColorType); 1005 1006 auto sdc = SurfaceDrawContext::MakeWithFallback( 1007 fContext.get(), SkColorTypeToGrColorType(cinfo.fInfo.colorType()), 1008 fSurfaceDrawContext->colorInfo().refColorSpace(), fit, cinfo.fInfo.dimensions(), props, 1009 fSurfaceDrawContext->numSamples(), GrMipmapped::kNo, 1010 fSurfaceDrawContext->asSurfaceProxy()->isProtected(), kBottomLeft_GrSurfaceOrigin, 1011 SkBudgeted::kYes); 1012 if (!sdc) { 1013 return nullptr; 1014 } 1015 1016 // Skia's convention is to only clear a device if it is non-opaque. 1017 InitContents init = cinfo.fInfo.isOpaque() ? InitContents::kUninit : InitContents::kClear; 1018 1019 return Device::Make(std::move(sdc), cinfo.fInfo.alphaType(), init).release(); 1020} 1021 1022sk_sp<SkSurface> Device::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1023 ASSERT_SINGLE_OWNER 1024 // TODO: Change the signature of newSurface to take a budgeted parameter. 1025 static const SkBudgeted kBudgeted = SkBudgeted::kNo; 1026 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info, 1027 fSurfaceDrawContext->numSamples(), 1028 fSurfaceDrawContext->origin(), &props); 1029} 1030 1031SkImageFilterCache* Device::getImageFilterCache() { 1032 ASSERT_SINGLE_OWNER 1033 // We always return a transient cache, so it is freed after each 1034 // filter traversal. 1035 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize); 1036} 1037 1038//////////////////////////////////////////////////////////////////////////////////// 1039 1040bool Device::android_utils_clipWithStencil() { 1041 SkRegion clipRegion; 1042 this->onAsRgnClip(&clipRegion); 1043 if (clipRegion.isEmpty()) { 1044 return false; 1045 } 1046 auto sdc = fSurfaceDrawContext.get(); 1047 SkASSERT(sdc); 1048 GrPaint grPaint; 1049 grPaint.setXPFactory(GrDisableColorXPFactory::Get()); 1050 static constexpr GrUserStencilSettings kDrawToStencil( 1051 GrUserStencilSettings::StaticInit< 1052 0x1, 1053 GrUserStencilTest::kAlways, 1054 0x1, 1055 GrUserStencilOp::kReplace, 1056 GrUserStencilOp::kReplace, 1057 0x1>() 1058 ); 1059 // Regions don't actually need AA, but in DMSAA mode everything is antialiased. 1060 GrAA aa = GrAA(fSurfaceDrawContext->alwaysAntialias()); 1061 sdc->drawRegion(nullptr, std::move(grPaint), aa, SkMatrix::I(), clipRegion, 1062 GrStyle::SimpleFill(), &kDrawToStencil); 1063 return true; 1064} 1065 1066bool Device::drawBlurImage(const SkImage* image, const SkBlurArg& blurArg) 1067{ 1068 if (image == nullptr) { 1069 return false; 1070 } 1071 if (auto[view, ct] = as_IB(image)->asView(this->recordingContext(), GrMipmapped::kNo); view) { 1072 return fSurfaceDrawContext->drawBlurImage(std::move(view), blurArg); 1073 } 1074} 1075 1076} // namespace skgpu::v1 1077