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 "SkGpuDevice.h" 9 10 #include "../private/SkShadowFlags.h" 11 #include "GrBitmapTextureMaker.h" 12 #include "GrBlurUtils.h" 13 #include "GrColorSpaceXform.h" 14 #include "GrContext.h" 15 #include "GrContextPriv.h" 16 #include "GrGpu.h" 17 #include "GrImageTextureMaker.h" 18 #include "GrRenderTargetContextPriv.h" 19 #include "GrShape.h" 20 #include "GrStyle.h" 21 #include "GrSurfaceProxyPriv.h" 22 #include "GrTextureAdjuster.h" 23 #include "GrTextureProxy.h" 24 #include "GrTracing.h" 25 #include "SkCanvasPriv.h" 26 #include "SkDraw.h" 27 #include "SkGr.h" 28 #include "SkImageFilter.h" 29 #include "SkImageFilterCache.h" 30 #include "SkImageInfoPriv.h" 31 #include "SkImage_Base.h" 32 #include "SkLatticeIter.h" 33 #include "SkMakeUnique.h" 34 #include "SkMaskFilterBase.h" 35 #include "SkPathEffect.h" 36 #include "SkPicture.h" 37 #include "SkPictureData.h" 38 #include "SkRRectPriv.h" 39 #include "SkRasterClip.h" 40 #include "SkReadPixelsRec.h" 41 #include "SkRecord.h" 42 #include "SkSpecialImage.h" 43 #include "SkStroke.h" 44 #include "SkSurface.h" 45 #include "SkSurface_Gpu.h" 46 #include "SkTLazy.h" 47 #include "SkTo.h" 48 #include "SkUTF.h" 49 #include "SkVertState.h" 50 #include "SkVertices.h" 51 #include "SkWritePixelsRec.h" 52 #include "SkYUVAIndex.h" 53 #include "effects/GrBicubicEffect.h" 54 #include "effects/GrSimpleTextureEffect.h" 55 #include "effects/GrTextureDomain.h" 56 #include "text/GrTextTarget.h" 57 58 #define ASSERT_SINGLE_OWNER \ 59 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->contextPriv().debugSingleOwner());) 60 61 62 /////////////////////////////////////////////////////////////////////////////// 63 64 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation 65 should fail. */ 66 bool SkGpuDevice::CheckAlphaTypeAndGetFlags( 67 const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) { 68 *flags = 0; 69 if (info) { 70 switch (info->alphaType()) { 71 case kPremul_SkAlphaType: 72 break; 73 case kOpaque_SkAlphaType: 74 *flags |= SkGpuDevice::kIsOpaque_Flag; 75 break; 76 default: // If it is unpremul or unknown don't try to render 77 return false; 78 } 79 } 80 if (kClear_InitContents == init) { 81 *flags |= kNeedClear_Flag; 82 } 83 return true; 84 } 85 86 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context, 87 sk_sp<GrRenderTargetContext> renderTargetContext, 88 int width, int height, 89 InitContents init) { 90 if (!renderTargetContext || renderTargetContext->wasAbandoned()) { 91 return nullptr; 92 } 93 unsigned flags; 94 if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) { 95 return nullptr; 96 } 97 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext), 98 width, height, flags)); 99 } 100 101 sk_sp<SkGpuDevice> SkGpuDevice::Make(GrContext* context, SkBudgeted budgeted, 102 const SkImageInfo& info, int sampleCount, 103 GrSurfaceOrigin origin, const SkSurfaceProps* props, 104 GrMipMapped mipMapped, InitContents init) { 105 unsigned flags; 106 if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) { 107 return nullptr; 108 } 109 110 sk_sp<GrRenderTargetContext> renderTargetContext(MakeRenderTargetContext(context, budgeted, 111 info, sampleCount, 112 origin, props, 113 mipMapped)); 114 if (!renderTargetContext) { 115 return nullptr; 116 } 117 118 return sk_sp<SkGpuDevice>(new SkGpuDevice(context, std::move(renderTargetContext), 119 info.width(), info.height(), flags)); 120 } 121 122 static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) { 123 SkColorType colorType; 124 if (!GrPixelConfigToColorType(context->colorSpaceInfo().config(), &colorType)) { 125 colorType = kUnknown_SkColorType; 126 } 127 return SkImageInfo::Make(w, h, colorType, opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType, 128 context->colorSpaceInfo().refColorSpace()); 129 } 130 131 SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp<GrRenderTargetContext> renderTargetContext, 132 int width, int height, unsigned flags) 133 : INHERITED(make_info(renderTargetContext.get(), width, height, 134 SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps()) 135 , fContext(SkRef(context)) 136 , fRenderTargetContext(std::move(renderTargetContext)) 137 { 138 fSize.set(width, height); 139 140 if (flags & kNeedClear_Flag) { 141 this->clearAll(); 142 } 143 } 144 145 sk_sp<GrRenderTargetContext> SkGpuDevice::MakeRenderTargetContext( 146 GrContext* context, 147 SkBudgeted budgeted, 148 const SkImageInfo& origInfo, 149 int sampleCount, 150 GrSurfaceOrigin origin, 151 const SkSurfaceProps* surfaceProps, 152 GrMipMapped mipMapped) { 153 if (kUnknown_SkColorType == origInfo.colorType() || 154 origInfo.width() < 0 || origInfo.height() < 0) { 155 return nullptr; 156 } 157 158 if (!context) { 159 return nullptr; 160 } 161 162 GrPixelConfig config = SkImageInfo2GrPixelConfig(origInfo); 163 if (kUnknown_GrPixelConfig == config) { 164 return nullptr; 165 } 166 GrBackendFormat format = 167 context->contextPriv().caps()->getBackendFormatFromColorType(origInfo.colorType()); 168 // This method is used to create SkGpuDevice's for SkSurface_Gpus. In this case 169 // they need to be exact. 170 return context->contextPriv().makeDeferredRenderTargetContext( 171 format, SkBackingFit::kExact, 172 origInfo.width(), origInfo.height(), 173 config, origInfo.refColorSpace(), sampleCount, 174 mipMapped, origin, surfaceProps, budgeted); 175 } 176 177 sk_sp<SkSpecialImage> SkGpuDevice::filterTexture(SkSpecialImage* srcImg, 178 int left, int top, 179 SkIPoint* offset, 180 const SkImageFilter* filter) { 181 SkASSERT(srcImg->isTextureBacked()); 182 SkASSERT(filter); 183 184 SkMatrix matrix = this->ctm(); 185 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top)); 186 const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top); 187 sk_sp<SkImageFilterCache> cache(this->getImageFilterCache()); 188 SkColorType colorType; 189 if (!GrPixelConfigToColorType(fRenderTargetContext->colorSpaceInfo().config(), &colorType)) { 190 colorType = kN32_SkColorType; 191 } 192 SkImageFilter::OutputProperties outputProperties( 193 colorType, fRenderTargetContext->colorSpaceInfo().colorSpace()); 194 SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties); 195 196 return filter->filterImage(srcImg, ctx, offset); 197 } 198 199 /////////////////////////////////////////////////////////////////////////////// 200 201 bool SkGpuDevice::onReadPixels(const SkPixmap& pm, int x, int y) { 202 ASSERT_SINGLE_OWNER 203 204 if (!SkImageInfoValidConversion(pm.info(), this->imageInfo())) { 205 return false; 206 } 207 208 SkReadPixelsRec rec(pm, x, y); 209 if (!rec.trim(this->width(), this->height())) { 210 return false; 211 } 212 213 return fRenderTargetContext->readPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); 214 } 215 216 bool SkGpuDevice::onWritePixels(const SkPixmap& pm, int x, int y) { 217 ASSERT_SINGLE_OWNER 218 219 if (!SkImageInfoValidConversion(this->imageInfo(), pm.info())) { 220 return false; 221 } 222 223 SkWritePixelsRec rec(pm, x, y); 224 if (!rec.trim(this->width(), this->height())) { 225 return false; 226 } 227 228 return fRenderTargetContext->writePixels(rec.fInfo, rec.fPixels, rec.fRowBytes, rec.fX, rec.fY); 229 } 230 231 bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { 232 ASSERT_SINGLE_OWNER 233 return false; 234 } 235 236 GrRenderTargetContext* SkGpuDevice::accessRenderTargetContext() { 237 ASSERT_SINGLE_OWNER 238 return fRenderTargetContext.get(); 239 } 240 241 void SkGpuDevice::clearAll() { 242 ASSERT_SINGLE_OWNER 243 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get()); 244 245 SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); 246 fRenderTargetContext->clear(&rect, SK_PMColor4fTRANSPARENT, 247 GrRenderTargetContext::CanClearFullscreen::kYes); 248 } 249 250 void SkGpuDevice::replaceRenderTargetContext(bool shouldRetainContent) { 251 ASSERT_SINGLE_OWNER 252 253 SkBudgeted budgeted = fRenderTargetContext->priv().isBudgeted(); 254 255 // This entry point is used by SkSurface_Gpu::onCopyOnWrite so it must create a 256 // kExact-backed render target context. 257 sk_sp<GrRenderTargetContext> newRTC(MakeRenderTargetContext( 258 this->context(), 259 budgeted, 260 this->imageInfo(), 261 fRenderTargetContext->numColorSamples(), 262 fRenderTargetContext->origin(), 263 &this->surfaceProps(), 264 fRenderTargetContext->mipMapped())); 265 if (!newRTC) { 266 return; 267 } 268 SkASSERT(newRTC->asSurfaceProxy()->priv().isExact()); 269 270 if (shouldRetainContent) { 271 if (fRenderTargetContext->wasAbandoned()) { 272 return; 273 } 274 newRTC->copy(fRenderTargetContext->asSurfaceProxy()); 275 } 276 277 fRenderTargetContext = newRTC; 278 } 279 280 /////////////////////////////////////////////////////////////////////////////// 281 282 void SkGpuDevice::drawPaint(const SkPaint& paint) { 283 ASSERT_SINGLE_OWNER 284 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get()); 285 286 GrPaint grPaint; 287 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 288 this->ctm(), &grPaint)) { 289 return; 290 } 291 292 fRenderTargetContext->drawPaint(this->clip(), std::move(grPaint), this->ctm()); 293 } 294 295 static inline GrPrimitiveType point_mode_to_primitive_type(SkCanvas::PointMode mode) { 296 switch (mode) { 297 case SkCanvas::kPoints_PointMode: 298 return GrPrimitiveType::kPoints; 299 case SkCanvas::kLines_PointMode: 300 return GrPrimitiveType::kLines; 301 case SkCanvas::kPolygon_PointMode: 302 return GrPrimitiveType::kLineStrip; 303 } 304 SK_ABORT("Unexpected mode"); 305 return GrPrimitiveType::kPoints; 306 } 307 308 void SkGpuDevice::drawPoints(SkCanvas::PointMode mode, 309 size_t count, const SkPoint pts[], const SkPaint& paint) { 310 ASSERT_SINGLE_OWNER 311 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext.get()); 312 SkScalar width = paint.getStrokeWidth(); 313 if (width < 0) { 314 return; 315 } 316 317 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) { 318 GrStyle style(paint, SkPaint::kStroke_Style); 319 GrPaint grPaint; 320 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 321 this->ctm(), &grPaint)) { 322 return; 323 } 324 SkPath path; 325 path.setIsVolatile(true); 326 path.moveTo(pts[0]); 327 path.lineTo(pts[1]); 328 fRenderTargetContext->drawPath(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 329 this->ctm(), path, style); 330 return; 331 } 332 333 SkScalar scales[2]; 334 bool isHairline = (0 == width) || (1 == width && this->ctm().getMinMaxScales(scales) && 335 SkScalarNearlyEqual(scales[0], 1.f) && 336 SkScalarNearlyEqual(scales[1], 1.f)); 337 // we only handle non-antialiased hairlines and paints without path effects or mask filters, 338 // else we let the SkDraw call our drawPath() 339 if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || paint.isAntiAlias()) { 340 SkRasterClip rc(this->devClipBounds()); 341 SkDraw draw; 342 draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0); 343 draw.fMatrix = &this->ctm(); 344 draw.fRC = &rc; 345 draw.drawPoints(mode, count, pts, paint, this); 346 return; 347 } 348 349 GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode); 350 351 const SkMatrix* viewMatrix = &this->ctm(); 352 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 353 // This offsetting in device space matches the expectations of the Android framework for non-AA 354 // points and lines. 355 SkMatrix tempMatrix; 356 if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) { 357 tempMatrix = *viewMatrix; 358 static const SkScalar kOffset = 0.063f; // Just greater than 1/16. 359 tempMatrix.postTranslate(kOffset, kOffset); 360 viewMatrix = &tempMatrix; 361 } 362 #endif 363 364 GrPaint grPaint; 365 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 366 *viewMatrix, &grPaint)) { 367 return; 368 } 369 370 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; 371 sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr, 372 nullptr); 373 374 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), *viewMatrix, 375 std::move(vertices), nullptr, 0, &primitiveType); 376 } 377 378 /////////////////////////////////////////////////////////////////////////////// 379 380 void SkGpuDevice::drawRect(const SkRect& rect, const SkPaint& paint) { 381 ASSERT_SINGLE_OWNER 382 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext.get()); 383 384 GrStyle style(paint); 385 386 // A couple reasons we might need to call drawPath. 387 if (paint.getMaskFilter() || paint.getPathEffect()) { 388 GrShape shape(rect, style); 389 390 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), 391 this->clip(), paint, this->ctm(), shape); 392 return; 393 } 394 395 GrPaint grPaint; 396 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 397 this->ctm(), &grPaint)) { 398 return; 399 } 400 401 fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 402 this->ctm(), rect, &style); 403 } 404 405 void SkGpuDevice::drawEdgeAARect(const SkRect& r, SkCanvas::QuadAAFlags aa, SkColor color, 406 SkBlendMode mode) { 407 ASSERT_SINGLE_OWNER 408 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawEdgeAARect", fContext.get()); 409 410 SkPMColor4f dstColor = SkColor4fPrepForDst(SkColor4f::FromColor(color), 411 fRenderTargetContext->colorSpaceInfo(), 412 *fContext->contextPriv().caps()) 413 .premul(); 414 415 GrPaint grPaint; 416 grPaint.setColor4f(dstColor); 417 if (mode != SkBlendMode::kSrcOver) { 418 grPaint.setXPFactory(SkBlendMode_AsXPFactory(mode)); 419 } 420 421 fRenderTargetContext->fillRectWithEdgeAA(this->clip(), std::move(grPaint), 422 SkToGrQuadAAFlags(aa), this->ctm(), r); 423 } 424 425 /////////////////////////////////////////////////////////////////////////////// 426 427 void SkGpuDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 428 ASSERT_SINGLE_OWNER 429 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get()); 430 431 SkMaskFilterBase* mf = as_MFB(paint.getMaskFilter()); 432 if (mf) { 433 if (mf->hasFragmentProcessor()) { 434 mf = nullptr; // already handled in SkPaintToGrPaint 435 } 436 } 437 438 GrStyle style(paint); 439 440 if (mf || style.pathEffect()) { 441 // A path effect will presumably transform this rrect into something else. 442 GrShape shape(rrect, style); 443 444 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), 445 this->clip(), paint, this->ctm(), shape); 446 return; 447 } 448 449 SkASSERT(!style.pathEffect()); 450 451 GrPaint grPaint; 452 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 453 this->ctm(), &grPaint)) { 454 return; 455 } 456 457 fRenderTargetContext->drawRRect(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 458 this->ctm(), rrect, style); 459 } 460 461 462 void SkGpuDevice::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) { 463 ASSERT_SINGLE_OWNER 464 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext.get()); 465 if (outer.isEmpty()) { 466 return; 467 } 468 469 if (inner.isEmpty()) { 470 return this->drawRRect(outer, paint); 471 } 472 473 SkStrokeRec stroke(paint); 474 475 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) { 476 GrPaint grPaint; 477 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 478 this->ctm(), &grPaint)) { 479 return; 480 } 481 482 fRenderTargetContext->drawDRRect(this->clip(), std::move(grPaint), 483 GrAA(paint.isAntiAlias()), this->ctm(), outer, inner); 484 return; 485 } 486 487 SkPath path; 488 path.setIsVolatile(true); 489 path.addRRect(outer); 490 path.addRRect(inner); 491 path.setFillType(SkPath::kEvenOdd_FillType); 492 493 // TODO: We are losing the possible mutability of the path here but this should probably be 494 // fixed by upgrading GrShape to handle DRRects. 495 GrShape shape(path, paint); 496 497 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(), 498 paint, this->ctm(), shape); 499 } 500 501 502 ///////////////////////////////////////////////////////////////////////////// 503 504 void SkGpuDevice::drawRegion(const SkRegion& region, const SkPaint& paint) { 505 if (paint.getMaskFilter()) { 506 SkPath path; 507 region.getBoundaryPath(&path); 508 path.setIsVolatile(true); 509 return this->drawPath(path, paint, true); 510 } 511 512 GrPaint grPaint; 513 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 514 this->ctm(), &grPaint)) { 515 return; 516 } 517 518 fRenderTargetContext->drawRegion(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 519 this->ctm(), region, GrStyle(paint)); 520 } 521 522 void SkGpuDevice::drawOval(const SkRect& oval, const SkPaint& paint) { 523 ASSERT_SINGLE_OWNER 524 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext.get()); 525 526 if (paint.getMaskFilter()) { 527 // The RRect path can handle special case blurring 528 SkRRect rr = SkRRect::MakeOval(oval); 529 return this->drawRRect(rr, paint); 530 } 531 532 GrPaint grPaint; 533 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 534 this->ctm(), &grPaint)) { 535 return; 536 } 537 538 fRenderTargetContext->drawOval(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 539 this->ctm(), oval, GrStyle(paint)); 540 } 541 542 void SkGpuDevice::drawArc(const SkRect& oval, SkScalar startAngle, 543 SkScalar sweepAngle, bool useCenter, const SkPaint& paint) { 544 ASSERT_SINGLE_OWNER 545 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawArc", fContext.get()); 546 if (paint.getMaskFilter()) { 547 this->INHERITED::drawArc(oval, startAngle, sweepAngle, useCenter, paint); 548 return; 549 } 550 GrPaint grPaint; 551 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 552 this->ctm(), &grPaint)) { 553 return; 554 } 555 556 fRenderTargetContext->drawArc(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 557 this->ctm(), oval, startAngle, sweepAngle, useCenter, 558 GrStyle(paint)); 559 } 560 561 #include "SkMaskFilter.h" 562 563 /////////////////////////////////////////////////////////////////////////////// 564 void SkGpuDevice::drawStrokedLine(const SkPoint points[2], 565 const SkPaint& origPaint) { 566 ASSERT_SINGLE_OWNER 567 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawStrokedLine", fContext.get()); 568 // Adding support for round capping would require a 569 // GrRenderTargetContext::fillRRectWithLocalMatrix entry point 570 SkASSERT(SkPaint::kRound_Cap != origPaint.getStrokeCap()); 571 SkASSERT(SkPaint::kStroke_Style == origPaint.getStyle()); 572 SkASSERT(!origPaint.getPathEffect()); 573 SkASSERT(!origPaint.getMaskFilter()); 574 575 const SkScalar halfWidth = 0.5f * origPaint.getStrokeWidth(); 576 SkASSERT(halfWidth > 0); 577 578 SkVector v = points[1] - points[0]; 579 580 SkScalar length = SkPoint::Normalize(&v); 581 if (!length) { 582 v.fX = 1.0f; 583 v.fY = 0.0f; 584 } 585 586 SkPaint newPaint(origPaint); 587 newPaint.setStyle(SkPaint::kFill_Style); 588 589 SkScalar xtraLength = 0.0f; 590 if (SkPaint::kButt_Cap != origPaint.getStrokeCap()) { 591 xtraLength = halfWidth; 592 } 593 594 SkPoint mid = points[0] + points[1]; 595 mid.scale(0.5f); 596 597 SkRect rect = SkRect::MakeLTRB(mid.fX-halfWidth, mid.fY - 0.5f*length - xtraLength, 598 mid.fX+halfWidth, mid.fY + 0.5f*length + xtraLength); 599 SkMatrix m; 600 m.setSinCos(v.fX, -v.fY, mid.fX, mid.fY); 601 602 SkMatrix local = m; 603 604 m.postConcat(this->ctm()); 605 606 GrPaint grPaint; 607 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), newPaint, m, 608 &grPaint)) { 609 return; 610 } 611 612 fRenderTargetContext->fillRectWithLocalMatrix( 613 this->clip(), std::move(grPaint), GrAA(newPaint.isAntiAlias()), m, rect, local); 614 } 615 616 void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) { 617 ASSERT_SINGLE_OWNER 618 if (!origSrcPath.isInverseFillType() && !paint.getPathEffect()) { 619 SkPoint points[2]; 620 if (SkPaint::kStroke_Style == paint.getStyle() && paint.getStrokeWidth() > 0 && 621 !paint.getMaskFilter() && SkPaint::kRound_Cap != paint.getStrokeCap() && 622 this->ctm().preservesRightAngles() && origSrcPath.isLine(points)) { 623 // Path-based stroking looks better for thin rects 624 SkScalar strokeWidth = this->ctm().getMaxScale() * paint.getStrokeWidth(); 625 if (strokeWidth >= 1.0f) { 626 // Round capping support is currently disabled b.c. it would require a RRect 627 // GrDrawOp that takes a localMatrix. 628 this->drawStrokedLine(points, paint); 629 return; 630 } 631 } 632 } 633 634 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext.get()); 635 if (!paint.getMaskFilter()) { 636 GrPaint grPaint; 637 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 638 this->ctm(), &grPaint)) { 639 return; 640 } 641 fRenderTargetContext->drawPath(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), 642 this->ctm(), origSrcPath, GrStyle(paint)); 643 return; 644 } 645 646 // TODO: losing possible mutability of 'origSrcPath' here 647 GrShape shape(origSrcPath, paint); 648 649 GrBlurUtils::drawShapeWithMaskFilter(fContext.get(), fRenderTargetContext.get(), this->clip(), 650 paint, this->ctm(), shape); 651 } 652 653 static const int kBmpSmallTileSize = 1 << 10; 654 655 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { 656 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; 657 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; 658 return tilesX * tilesY; 659 } 660 661 static int determine_tile_size(const SkIRect& src, int maxTileSize) { 662 if (maxTileSize <= kBmpSmallTileSize) { 663 return maxTileSize; 664 } 665 666 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); 667 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); 668 669 maxTileTotalTileSize *= maxTileSize * maxTileSize; 670 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; 671 672 if (maxTileTotalTileSize > 2 * smallTotalTileSize) { 673 return kBmpSmallTileSize; 674 } else { 675 return maxTileSize; 676 } 677 } 678 679 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what 680 // pixels from the bitmap are necessary. 681 static void determine_clipped_src_rect(int width, int height, 682 const GrClip& clip, 683 const SkMatrix& viewMatrix, 684 const SkMatrix& srcToDstRect, 685 const SkISize& imageSize, 686 const SkRect* srcRectPtr, 687 SkIRect* clippedSrcIRect) { 688 clip.getConservativeBounds(width, height, clippedSrcIRect, nullptr); 689 SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect); 690 if (!inv.invert(&inv)) { 691 clippedSrcIRect->setEmpty(); 692 return; 693 } 694 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect); 695 inv.mapRect(&clippedSrcRect); 696 if (srcRectPtr) { 697 if (!clippedSrcRect.intersect(*srcRectPtr)) { 698 clippedSrcIRect->setEmpty(); 699 return; 700 } 701 } 702 clippedSrcRect.roundOut(clippedSrcIRect); 703 SkIRect bmpBounds = SkIRect::MakeSize(imageSize); 704 if (!clippedSrcIRect->intersect(bmpBounds)) { 705 clippedSrcIRect->setEmpty(); 706 } 707 } 708 709 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, 710 const SkIRect& imageRect, 711 const SkMatrix& viewMatrix, 712 const SkMatrix& srcToDstRect, 713 const GrSamplerState& params, 714 const SkRect* srcRectPtr, 715 int maxTileSize, 716 int* tileSize, 717 SkIRect* clippedSubset) const { 718 ASSERT_SINGLE_OWNER 719 // if it's larger than the max tile size, then we have no choice but tiling. 720 if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) { 721 determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(), 722 this->clip(), viewMatrix, srcToDstRect, imageRect.size(), 723 srcRectPtr, clippedSubset); 724 *tileSize = determine_tile_size(*clippedSubset, maxTileSize); 725 return true; 726 } 727 728 // If the image would only produce 4 tiles of the smaller size, don't bother tiling it. 729 const size_t area = imageRect.width() * imageRect.height(); 730 if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { 731 return false; 732 } 733 734 // At this point we know we could do the draw by uploading the entire bitmap 735 // as a texture. However, if the texture would be large compared to the 736 // cache size and we don't require most of it for this draw then tile to 737 // reduce the amount of upload and cache spill. 738 739 // assumption here is that sw bitmap size is a good proxy for its size as 740 // a texture 741 size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels 742 size_t cacheSize; 743 fContext->getResourceCacheLimits(nullptr, &cacheSize); 744 if (bmpSize < cacheSize / 2) { 745 return false; 746 } 747 748 // Figure out how much of the src we will need based on the src rect and clipping. Reject if 749 // tiling memory savings would be < 50%. 750 determine_clipped_src_rect(fRenderTargetContext->width(), fRenderTargetContext->height(), 751 this->clip(), viewMatrix, srcToDstRect, imageRect.size(), srcRectPtr, 752 clippedSubset); 753 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile. 754 size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) * 755 kBmpSmallTileSize * kBmpSmallTileSize * 756 sizeof(SkPMColor); // assume 32bit pixels; 757 758 return usedTileBytes * 2 < bmpSize; 759 } 760 761 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr, 762 SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality, 763 const SkMatrix& viewMatrix, 764 const SkMatrix& srcToDstRect) const { 765 ASSERT_SINGLE_OWNER 766 // If image is explicitly texture backed then we shouldn't get here. 767 SkASSERT(!image->isTextureBacked()); 768 769 GrSamplerState samplerState; 770 bool doBicubic; 771 GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( 772 quality, viewMatrix, srcToDstRect, fContext->contextPriv().sharpenMipmappedTextures(), 773 &doBicubic); 774 775 int tileFilterPad; 776 if (doBicubic) { 777 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 778 } else if (GrSamplerState::Filter::kNearest == textureFilterMode) { 779 tileFilterPad = 0; 780 } else { 781 tileFilterPad = 1; 782 } 783 samplerState.setFilterMode(textureFilterMode); 784 785 int maxTileSize = this->caps()->maxTileSize() - 2 * tileFilterPad; 786 787 // these are output, which we safely ignore, as we just want to know the predicate 788 int outTileSize; 789 SkIRect outClippedSrcRect; 790 791 return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect, 792 samplerState, srcRectPtr, maxTileSize, &outTileSize, 793 &outClippedSrcRect); 794 } 795 796 void SkGpuDevice::drawBitmap(const SkBitmap& bitmap, 797 SkScalar x, 798 SkScalar y, 799 const SkPaint& paint) { 800 SkMatrix m = SkMatrix::MakeTrans(x, y); 801 ASSERT_SINGLE_OWNER 802 SkMatrix viewMatrix; 803 viewMatrix.setConcat(this->ctm(), m); 804 805 int maxTileSize = this->caps()->maxTileSize(); 806 807 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could 808 // draw untiled, then we bypass checking for tiling purely for optimization reasons. 809 bool drawAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() && 810 paint.isAntiAlias() && bitmap.width() <= maxTileSize && 811 bitmap.height() <= maxTileSize; 812 813 bool skipTileCheck = drawAA || paint.getMaskFilter(); 814 815 if (!skipTileCheck) { 816 SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 817 int tileSize; 818 SkIRect clippedSrcRect; 819 820 GrSamplerState samplerState; 821 bool doBicubic; 822 GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( 823 paint.getFilterQuality(), viewMatrix, SkMatrix::I(), 824 fContext->contextPriv().sharpenMipmappedTextures(), &doBicubic); 825 826 int tileFilterPad; 827 828 if (doBicubic) { 829 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 830 } else if (GrSamplerState::Filter::kNearest == textureFilterMode) { 831 tileFilterPad = 0; 832 } else { 833 tileFilterPad = 1; 834 } 835 samplerState.setFilterMode(textureFilterMode); 836 837 int maxTileSizeForFilter = this->caps()->maxTileSize() - 2 * tileFilterPad; 838 if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix, 839 SkMatrix::I(), samplerState, &srcRect, maxTileSizeForFilter, 840 &tileSize, &clippedSrcRect)) { 841 this->drawTiledBitmap(bitmap, viewMatrix, SkMatrix::I(), srcRect, clippedSrcRect, 842 samplerState, paint, SkCanvas::kStrict_SrcRectConstraint, 843 tileSize, doBicubic); 844 return; 845 } 846 } 847 GrBitmapTextureMaker maker(fContext.get(), bitmap); 848 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint, 849 viewMatrix, paint, true); 850 } 851 852 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to 853 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner 854 // of 'iRect' for all possible outsets/clamps. 855 static inline void clamped_outset_with_offset(SkIRect* iRect, 856 int outset, 857 SkPoint* offset, 858 const SkIRect& clamp) { 859 iRect->outset(outset, outset); 860 861 int leftClampDelta = clamp.fLeft - iRect->fLeft; 862 if (leftClampDelta > 0) { 863 offset->fX -= outset - leftClampDelta; 864 iRect->fLeft = clamp.fLeft; 865 } else { 866 offset->fX -= outset; 867 } 868 869 int topClampDelta = clamp.fTop - iRect->fTop; 870 if (topClampDelta > 0) { 871 offset->fY -= outset - topClampDelta; 872 iRect->fTop = clamp.fTop; 873 } else { 874 offset->fY -= outset; 875 } 876 877 if (iRect->fRight > clamp.fRight) { 878 iRect->fRight = clamp.fRight; 879 } 880 if (iRect->fBottom > clamp.fBottom) { 881 iRect->fBottom = clamp.fBottom; 882 } 883 } 884 885 // Break 'bitmap' into several tiles to draw it since it has already 886 // been determined to be too large to fit in VRAM 887 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, 888 const SkMatrix& viewMatrix, 889 const SkMatrix& dstMatrix, 890 const SkRect& srcRect, 891 const SkIRect& clippedSrcIRect, 892 const GrSamplerState& params, 893 const SkPaint& origPaint, 894 SkCanvas::SrcRectConstraint constraint, 895 int tileSize, 896 bool bicubic) { 897 ASSERT_SINGLE_OWNER 898 899 // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entries. 900 SK_HISTOGRAM_BOOLEAN("DrawTiled", true); 901 LogDrawScaleFactor(viewMatrix, origPaint.getFilterQuality()); 902 903 const SkPaint* paint = &origPaint; 904 SkPaint tempPaint; 905 if (origPaint.isAntiAlias() && GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType()) { 906 // Drop antialiasing to avoid seams at tile boundaries. 907 tempPaint = origPaint; 908 tempPaint.setAntiAlias(false); 909 paint = &tempPaint; 910 } 911 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect); 912 913 int nx = bitmap.width() / tileSize; 914 int ny = bitmap.height() / tileSize; 915 for (int x = 0; x <= nx; x++) { 916 for (int y = 0; y <= ny; y++) { 917 SkRect tileR; 918 tileR.set(SkIntToScalar(x * tileSize), 919 SkIntToScalar(y * tileSize), 920 SkIntToScalar((x + 1) * tileSize), 921 SkIntToScalar((y + 1) * tileSize)); 922 923 if (!SkRect::Intersects(tileR, clippedSrcRect)) { 924 continue; 925 } 926 927 if (!tileR.intersect(srcRect)) { 928 continue; 929 } 930 931 SkIRect iTileR; 932 tileR.roundOut(&iTileR); 933 SkVector offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft), 934 SkIntToScalar(iTileR.fTop)); 935 SkRect rectToDraw = tileR; 936 dstMatrix.mapRect(&rectToDraw); 937 if (GrSamplerState::Filter::kNearest != params.filter() || bicubic) { 938 SkIRect iClampRect; 939 940 if (SkCanvas::kFast_SrcRectConstraint == constraint) { 941 // In bleed mode we want to always expand the tile on all edges 942 // but stay within the bitmap bounds 943 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 944 } else { 945 // In texture-domain/clamp mode we only want to expand the 946 // tile on edges interior to "srcRect" (i.e., we want to 947 // not bleed across the original clamped edges) 948 srcRect.roundOut(&iClampRect); 949 } 950 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1; 951 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect); 952 } 953 954 SkBitmap tmpB; 955 if (bitmap.extractSubset(&tmpB, iTileR)) { 956 // now offset it to make it "local" to our tmp bitmap 957 tileR.offset(-offset.fX, -offset.fY); 958 // de-optimized this determination 959 bool needsTextureDomain = true; 960 this->drawBitmapTile(tmpB, 961 viewMatrix, 962 rectToDraw, 963 tileR, 964 params, 965 *paint, 966 constraint, 967 bicubic, 968 needsTextureDomain); 969 } 970 } 971 } 972 } 973 974 void SkGpuDevice::drawBitmapTile(const SkBitmap& bitmap, 975 const SkMatrix& viewMatrix, 976 const SkRect& dstRect, 977 const SkRect& srcRect, 978 const GrSamplerState& samplerState, 979 const SkPaint& paint, 980 SkCanvas::SrcRectConstraint constraint, 981 bool bicubic, 982 bool needsTextureDomain) { 983 // We should have already handled bitmaps larger than the max texture size. 984 SkASSERT(bitmap.width() <= this->caps()->maxTextureSize() && 985 bitmap.height() <= this->caps()->maxTextureSize()); 986 // We should be respecting the max tile size by the time we get here. 987 SkASSERT(bitmap.width() <= this->caps()->maxTileSize() && 988 bitmap.height() <= this->caps()->maxTileSize()); 989 SkASSERT(!samplerState.isRepeated()); 990 991 SkScalar scales[2] = {1.f, 1.f}; 992 sk_sp<GrTextureProxy> proxy = 993 GrRefCachedBitmapTextureProxy(fContext.get(), bitmap, samplerState, scales); 994 if (!proxy) { 995 return; 996 } 997 998 // Compute a matrix that maps the rect we will draw to the src rect. 999 SkMatrix texMatrix = SkMatrix::MakeRectToRect(dstRect, srcRect, SkMatrix::kFill_ScaleToFit); 1000 texMatrix.postScale(scales[0], scales[1]); 1001 1002 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring 1003 // the rest from the SkPaint. 1004 std::unique_ptr<GrFragmentProcessor> fp; 1005 1006 if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) { 1007 // Use a constrained texture domain to avoid color bleeding 1008 SkRect domain; 1009 if (srcRect.width() > SK_Scalar1) { 1010 domain.fLeft = srcRect.fLeft + 0.5f; 1011 domain.fRight = srcRect.fRight - 0.5f; 1012 } else { 1013 domain.fLeft = domain.fRight = srcRect.centerX(); 1014 } 1015 if (srcRect.height() > SK_Scalar1) { 1016 domain.fTop = srcRect.fTop + 0.5f; 1017 domain.fBottom = srcRect.fBottom - 0.5f; 1018 } else { 1019 domain.fTop = domain.fBottom = srcRect.centerY(); 1020 } 1021 if (bicubic) { 1022 fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, domain); 1023 } else { 1024 fp = GrTextureDomainEffect::Make(std::move(proxy), texMatrix, domain, 1025 GrTextureDomain::kClamp_Mode, samplerState.filter()); 1026 } 1027 } else if (bicubic) { 1028 SkASSERT(GrSamplerState::Filter::kNearest == samplerState.filter()); 1029 GrSamplerState::WrapMode wrapMode[2] = {samplerState.wrapModeX(), samplerState.wrapModeY()}; 1030 fp = GrBicubicEffect::Make(std::move(proxy), texMatrix, wrapMode); 1031 } else { 1032 fp = GrSimpleTextureEffect::Make(std::move(proxy), texMatrix, samplerState); 1033 } 1034 1035 fp = GrColorSpaceXformEffect::Make(std::move(fp), bitmap.colorSpace(), bitmap.alphaType(), 1036 fRenderTargetContext->colorSpaceInfo().colorSpace()); 1037 GrPaint grPaint; 1038 if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext->colorSpaceInfo(), paint, 1039 viewMatrix, std::move(fp), 1040 kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) { 1041 return; 1042 } 1043 1044 // Coverage-based AA would cause seams between tiles. 1045 GrAA aa = GrAA(paint.isAntiAlias() && 1046 GrFSAAType::kNone != fRenderTargetContext->fsaaType()); 1047 fRenderTargetContext->drawRect(this->clip(), std::move(grPaint), aa, viewMatrix, dstRect); 1048 } 1049 1050 void SkGpuDevice::drawSprite(const SkBitmap& bitmap, 1051 int left, int top, const SkPaint& paint) { 1052 ASSERT_SINGLE_OWNER 1053 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSprite", fContext.get()); 1054 1055 if (fContext->abandoned()) { 1056 return; 1057 } 1058 1059 sk_sp<SkSpecialImage> srcImg = this->makeSpecial(bitmap); 1060 if (!srcImg) { 1061 return; 1062 } 1063 1064 this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I()); 1065 } 1066 1067 1068 void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const SkPaint& paint, 1069 SkImage* clipImage, const SkMatrix& clipMatrix) { 1070 ASSERT_SINGLE_OWNER 1071 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get()); 1072 1073 // TODO: clipImage support. 1074 1075 sk_sp<SkSpecialImage> result; 1076 if (paint.getImageFilter()) { 1077 SkIPoint offset = { 0, 0 }; 1078 1079 result = this->filterTexture(special, left, top, &offset, paint.getImageFilter()); 1080 if (!result) { 1081 return; 1082 } 1083 1084 left += offset.fX; 1085 top += offset.fY; 1086 } else { 1087 result = sk_ref_sp(special); 1088 } 1089 1090 SkASSERT(result->isTextureBacked()); 1091 sk_sp<GrTextureProxy> proxy = result->asTextureProxyRef(this->context()); 1092 if (!proxy) { 1093 return; 1094 } 1095 1096 const GrPixelConfig config = proxy->config(); 1097 1098 SkPaint tmpUnfiltered(paint); 1099 if (tmpUnfiltered.getMaskFilter()) { 1100 SkMatrix ctm = this->ctm(); 1101 ctm.postTranslate(-SkIntToScalar(left), -SkIntToScalar(top)); 1102 tmpUnfiltered.setMaskFilter(tmpUnfiltered.getMaskFilter()->makeWithMatrix(ctm)); 1103 } 1104 1105 tmpUnfiltered.setImageFilter(nullptr); 1106 1107 auto fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I()); 1108 fp = GrColorSpaceXformEffect::Make(std::move(fp), result->getColorSpace(), result->alphaType(), 1109 fRenderTargetContext->colorSpaceInfo().colorSpace()); 1110 if (GrPixelConfigIsAlphaOnly(config)) { 1111 fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp)); 1112 } else { 1113 fp = GrFragmentProcessor::MulChildByInputAlpha(std::move(fp)); 1114 } 1115 1116 GrPaint grPaint; 1117 if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext->colorSpaceInfo(), 1118 tmpUnfiltered, std::move(fp), &grPaint)) { 1119 return; 1120 } 1121 1122 const SkIRect& subset = result->subset(); 1123 1124 fRenderTargetContext->fillRectToRect( 1125 this->clip(), 1126 std::move(grPaint), 1127 GrAA(tmpUnfiltered.isAntiAlias()), 1128 SkMatrix::I(), 1129 SkRect::Make(SkIRect::MakeXYWH(left, top, subset.width(), subset.height())), 1130 SkRect::Make(subset)); 1131 } 1132 1133 void SkGpuDevice::drawBitmapRect(const SkBitmap& bitmap, 1134 const SkRect* src, const SkRect& origDst, 1135 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 1136 ASSERT_SINGLE_OWNER 1137 // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must 1138 // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which 1139 // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds 1140 // then we use the src-to-dst mapping to compute a new clipped dst rect. 1141 const SkRect* dst = &origDst; 1142 const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 1143 // Compute matrix from the two rectangles 1144 if (!src) { 1145 src = &bmpBounds; 1146 } 1147 1148 SkMatrix srcToDstMatrix; 1149 if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) { 1150 return; 1151 } 1152 SkRect tmpSrc, tmpDst; 1153 if (src != &bmpBounds) { 1154 if (!bmpBounds.contains(*src)) { 1155 tmpSrc = *src; 1156 if (!tmpSrc.intersect(bmpBounds)) { 1157 return; // nothing to draw 1158 } 1159 src = &tmpSrc; 1160 srcToDstMatrix.mapRect(&tmpDst, *src); 1161 dst = &tmpDst; 1162 } 1163 } 1164 1165 int maxTileSize = this->caps()->maxTileSize(); 1166 1167 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could 1168 // draw untiled, then we bypass checking for tiling purely for optimization reasons. 1169 bool useCoverageAA = GrFSAAType::kUnifiedMSAA != fRenderTargetContext->fsaaType() && 1170 paint.isAntiAlias() && bitmap.width() <= maxTileSize && 1171 bitmap.height() <= maxTileSize; 1172 1173 bool skipTileCheck = useCoverageAA || paint.getMaskFilter(); 1174 1175 if (!skipTileCheck) { 1176 int tileSize; 1177 SkIRect clippedSrcRect; 1178 1179 GrSamplerState sampleState; 1180 bool doBicubic; 1181 GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( 1182 paint.getFilterQuality(), this->ctm(), srcToDstMatrix, 1183 fContext->contextPriv().sharpenMipmappedTextures(), &doBicubic); 1184 1185 int tileFilterPad; 1186 1187 if (doBicubic) { 1188 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 1189 } else if (GrSamplerState::Filter::kNearest == textureFilterMode) { 1190 tileFilterPad = 0; 1191 } else { 1192 tileFilterPad = 1; 1193 } 1194 sampleState.setFilterMode(textureFilterMode); 1195 1196 int maxTileSizeForFilter = this->caps()->maxTileSize() - 2 * tileFilterPad; 1197 if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(), 1198 srcToDstMatrix, sampleState, src, maxTileSizeForFilter, 1199 &tileSize, &clippedSrcRect)) { 1200 this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect, 1201 sampleState, paint, constraint, tileSize, doBicubic); 1202 return; 1203 } 1204 } 1205 GrBitmapTextureMaker maker(fContext.get(), bitmap); 1206 this->drawTextureProducer(&maker, src, dst, constraint, this->ctm(), paint, true); 1207 } 1208 1209 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkBitmap& bitmap) { 1210 // TODO: this makes a tight copy of 'bitmap' but it doesn't have to be (given SkSpecialImage's 1211 // semantics). Since this is cached we would have to bake the fit into the cache key though. 1212 sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(fContext->contextPriv().proxyProvider(), 1213 bitmap); 1214 if (!proxy) { 1215 return nullptr; 1216 } 1217 1218 const SkIRect rect = SkIRect::MakeWH(proxy->width(), proxy->height()); 1219 1220 // GrMakeCachedBitmapProxy creates a tight copy of 'bitmap' so we don't have to subset 1221 // the special image 1222 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 1223 rect, 1224 bitmap.getGenerationID(), 1225 std::move(proxy), 1226 bitmap.refColorSpace(), 1227 &this->surfaceProps()); 1228 } 1229 1230 sk_sp<SkSpecialImage> SkGpuDevice::makeSpecial(const SkImage* image) { 1231 SkPixmap pm; 1232 if (image->isTextureBacked()) { 1233 sk_sp<GrTextureProxy> proxy = as_IB(image)->asTextureProxyRef(); 1234 1235 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 1236 SkIRect::MakeWH(image->width(), image->height()), 1237 image->uniqueID(), 1238 std::move(proxy), 1239 as_IB(image)->onImageInfo().refColorSpace(), 1240 &this->surfaceProps()); 1241 } else if (image->peekPixels(&pm)) { 1242 SkBitmap bm; 1243 1244 bm.installPixels(pm); 1245 return this->makeSpecial(bm); 1246 } else { 1247 return nullptr; 1248 } 1249 } 1250 1251 sk_sp<SkSpecialImage> SkGpuDevice::snapSpecial() { 1252 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image 1253 // since it would require us to make a copy of the underlying VkImage which we don't have access 1254 // to. Additionaly we can't stop and start the render pass that is used with the secondary 1255 // command buffer. 1256 if (this->accessRenderTargetContext()->wrapsVkSecondaryCB()) { 1257 return nullptr; 1258 } 1259 1260 sk_sp<GrTextureProxy> proxy(this->accessRenderTargetContext()->asTextureProxyRef()); 1261 if (!proxy) { 1262 // When the device doesn't have a texture, we create a temporary texture. 1263 // TODO: we should actually only copy the portion of the source needed to apply the image 1264 // filter 1265 proxy = GrSurfaceProxy::Copy(fContext.get(), 1266 this->accessRenderTargetContext()->asSurfaceProxy(), 1267 GrMipMapped::kNo, 1268 SkBackingFit::kApprox, 1269 SkBudgeted::kYes); 1270 if (!proxy) { 1271 return nullptr; 1272 } 1273 } 1274 1275 const SkImageInfo ii = this->imageInfo(); 1276 const SkIRect srcRect = SkIRect::MakeWH(ii.width(), ii.height()); 1277 1278 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 1279 srcRect, 1280 kNeedNewImageUniqueID_SpecialImage, 1281 std::move(proxy), 1282 ii.refColorSpace(), 1283 &this->surfaceProps()); 1284 } 1285 1286 sk_sp<SkSpecialImage> SkGpuDevice::snapBackImage(const SkIRect& subset) { 1287 GrRenderTargetContext* rtc = this->accessRenderTargetContext(); 1288 1289 // If we are wrapping a vulkan secondary command buffer, then we can't snap off a special image 1290 // since it would require us to make a copy of the underlying VkImage which we don't have access 1291 // to. Additionaly we can't stop and start the render pass that is used with the secondary 1292 // command buffer. 1293 if (rtc->wrapsVkSecondaryCB()) { 1294 return nullptr; 1295 } 1296 1297 1298 GrContext* ctx = this->context(); 1299 SkASSERT(rtc->asSurfaceProxy()); 1300 1301 auto srcProxy = 1302 GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), rtc->mipMapped(), subset, 1303 SkBackingFit::kApprox, rtc->asSurfaceProxy()->isBudgeted()); 1304 if (!srcProxy) { 1305 return nullptr; 1306 } 1307 1308 // Note, can't move srcProxy since we also refer to this in the 2nd parameter 1309 return SkSpecialImage::MakeDeferredFromGpu(fContext.get(), 1310 SkIRect::MakeSize(srcProxy->isize()), 1311 kNeedNewImageUniqueID_SpecialImage, 1312 srcProxy, 1313 this->imageInfo().refColorSpace(), 1314 &this->surfaceProps()); 1315 } 1316 1317 void SkGpuDevice::drawDevice(SkBaseDevice* device, 1318 int left, int top, const SkPaint& paint) { 1319 SkASSERT(!paint.getImageFilter()); 1320 1321 ASSERT_SINGLE_OWNER 1322 // clear of the source device must occur before CHECK_SHOULD_DRAW 1323 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext.get()); 1324 1325 // drawDevice is defined to be in device coords. 1326 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device); 1327 sk_sp<SkSpecialImage> srcImg(dev->snapSpecial()); 1328 if (!srcImg) { 1329 return; 1330 } 1331 1332 this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I()); 1333 } 1334 1335 void SkGpuDevice::drawImage(const SkImage* image, SkScalar x, SkScalar y, const SkPaint& paint) { 1336 ASSERT_SINGLE_OWNER 1337 SkMatrix viewMatrix = this->ctm(); 1338 viewMatrix.preTranslate(x, y); 1339 if (as_IB(image)->isYUVA()) { 1340 GrYUVAImageTextureMaker maker(fContext.get(), image); 1341 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 1342 viewMatrix, paint, false); 1343 return; 1344 } 1345 uint32_t pinnedUniqueID; 1346 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { 1347 this->drawPinnedTextureProxy(std::move(proxy), pinnedUniqueID, as_IB(image)->colorSpace(), 1348 image->alphaType(), nullptr, nullptr, 1349 SkCanvas::kFast_SrcRectConstraint, viewMatrix, paint); 1350 return; 1351 } 1352 SkBitmap bm; 1353 if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint, 1354 paint.getFilterQuality(), viewMatrix, SkMatrix::I())) { 1355 // only support tiling as bitmap at the moment, so force raster-version 1356 if (!as_IB(image)->getROPixels(&bm)) { 1357 return; 1358 } 1359 this->drawBitmap(bm, x, y, paint); 1360 return; 1361 } 1362 if (image->isLazyGenerated()) { 1363 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint); 1364 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 1365 viewMatrix, paint, true); 1366 return; 1367 } 1368 if (as_IB(image)->getROPixels(&bm)) { 1369 GrBitmapTextureMaker maker(fContext.get(), bm); 1370 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 1371 viewMatrix, paint, true); 1372 } 1373 } 1374 1375 void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, 1376 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 1377 ASSERT_SINGLE_OWNER 1378 if (!src || src->contains(image->bounds())) { 1379 constraint = SkCanvas::kFast_SrcRectConstraint; 1380 } 1381 if (as_IB(image)->isYUVA()) { 1382 GrYUVAImageTextureMaker maker(fContext.get(), image); 1383 this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), paint, false); 1384 return; 1385 } 1386 uint32_t pinnedUniqueID; 1387 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { 1388 this->drawPinnedTextureProxy(std::move(proxy), pinnedUniqueID, as_IB(image)->colorSpace(), 1389 image->alphaType(), src, &dst, constraint, this->ctm(), paint); 1390 return; 1391 } 1392 SkBitmap bm; 1393 SkMatrix srcToDstRect; 1394 srcToDstRect.setRectToRect((src ? *src : SkRect::MakeIWH(image->width(), image->height())), 1395 dst, SkMatrix::kFill_ScaleToFit); 1396 if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(), 1397 srcToDstRect)) { 1398 // only support tiling as bitmap at the moment, so force raster-version 1399 if (!as_IB(image)->getROPixels(&bm)) { 1400 return; 1401 } 1402 this->drawBitmapRect(bm, src, dst, paint, constraint); 1403 return; 1404 } 1405 if (image->isLazyGenerated()) { 1406 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint); 1407 this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), paint, true); 1408 return; 1409 } 1410 if (as_IB(image)->getROPixels(&bm)) { 1411 GrBitmapTextureMaker maker(fContext.get(), bm); 1412 this->drawTextureProducer(&maker, src, &dst, constraint, this->ctm(), paint, true); 1413 } 1414 } 1415 1416 // When drawing nine-patches or n-patches, cap the filter quality at kBilerp. 1417 static GrSamplerState::Filter compute_lattice_filter_mode(const SkPaint& paint) { 1418 if (paint.getFilterQuality() == kNone_SkFilterQuality) { 1419 return GrSamplerState::Filter::kNearest; 1420 } 1421 1422 return GrSamplerState::Filter::kBilerp; 1423 } 1424 1425 void SkGpuDevice::drawImageNine(const SkImage* image, 1426 const SkIRect& center, const SkRect& dst, const SkPaint& paint) { 1427 ASSERT_SINGLE_OWNER 1428 uint32_t pinnedUniqueID; 1429 auto iter = skstd::make_unique<SkLatticeIter>(image->width(), image->height(), center, dst); 1430 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { 1431 GrTextureAdjuster adjuster(this->context(), std::move(proxy), 1432 image->alphaType(), pinnedUniqueID, 1433 as_IB(image)->onImageInfo().colorSpace()); 1434 this->drawProducerLattice(&adjuster, std::move(iter), dst, paint); 1435 } else { 1436 SkBitmap bm; 1437 if (image->isLazyGenerated()) { 1438 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint); 1439 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1440 } else if (as_IB(image)->getROPixels(&bm)) { 1441 GrBitmapTextureMaker maker(fContext.get(), bm); 1442 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1443 } 1444 } 1445 } 1446 1447 void SkGpuDevice::drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, 1448 const SkRect& dst, const SkPaint& paint) { 1449 ASSERT_SINGLE_OWNER 1450 auto iter = skstd::make_unique<SkLatticeIter>(bitmap.width(), bitmap.height(), center, dst); 1451 GrBitmapTextureMaker maker(fContext.get(), bitmap); 1452 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1453 } 1454 1455 void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer, 1456 std::unique_ptr<SkLatticeIter> iter, const SkRect& dst, 1457 const SkPaint& origPaint) { 1458 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get()); 1459 SkTCopyOnFirstWrite<SkPaint> paint(&origPaint); 1460 1461 if (!producer->isAlphaOnly() && (paint->getColor() & 0x00FFFFFF) != 0x00FFFFFF) { 1462 paint.writable()->setColor(SkColorSetARGB(origPaint.getAlpha(), 0xFF, 0xFF, 0xFF)); 1463 } 1464 GrPaint grPaint; 1465 if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), fRenderTargetContext->colorSpaceInfo(), 1466 *paint, &grPaint)) { 1467 return; 1468 } 1469 1470 auto dstColorSpace = fRenderTargetContext->colorSpaceInfo().colorSpace(); 1471 const GrSamplerState::Filter filter = compute_lattice_filter_mode(*paint); 1472 auto proxy = producer->refTextureProxyForParams(filter, nullptr); 1473 if (!proxy) { 1474 return; 1475 } 1476 auto csxf = GrColorSpaceXform::Make(producer->colorSpace(), producer->alphaType(), 1477 dstColorSpace, kPremul_SkAlphaType); 1478 1479 fRenderTargetContext->drawImageLattice(this->clip(), std::move(grPaint), this->ctm(), 1480 std::move(proxy), std::move(csxf), filter, 1481 std::move(iter), dst); 1482 } 1483 1484 void SkGpuDevice::drawImageLattice(const SkImage* image, 1485 const SkCanvas::Lattice& lattice, const SkRect& dst, 1486 const SkPaint& paint) { 1487 ASSERT_SINGLE_OWNER 1488 uint32_t pinnedUniqueID; 1489 auto iter = skstd::make_unique<SkLatticeIter>(lattice, dst); 1490 if (sk_sp<GrTextureProxy> proxy = as_IB(image)->refPinnedTextureProxy(&pinnedUniqueID)) { 1491 GrTextureAdjuster adjuster(this->context(), std::move(proxy), 1492 image->alphaType(), pinnedUniqueID, 1493 as_IB(image)->onImageInfo().colorSpace()); 1494 this->drawProducerLattice(&adjuster, std::move(iter), dst, paint); 1495 } else { 1496 SkBitmap bm; 1497 if (image->isLazyGenerated()) { 1498 GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint); 1499 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1500 } else if (as_IB(image)->getROPixels(&bm)) { 1501 GrBitmapTextureMaker maker(fContext.get(), bm); 1502 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1503 } 1504 } 1505 } 1506 1507 void SkGpuDevice::drawBitmapLattice(const SkBitmap& bitmap, 1508 const SkCanvas::Lattice& lattice, const SkRect& dst, 1509 const SkPaint& paint) { 1510 ASSERT_SINGLE_OWNER 1511 auto iter = skstd::make_unique<SkLatticeIter>(lattice, dst); 1512 GrBitmapTextureMaker maker(fContext.get(), bitmap); 1513 this->drawProducerLattice(&maker, std::move(iter), dst, paint); 1514 } 1515 1516 void SkGpuDevice::drawImageSet(const SkCanvas::ImageSetEntry set[], int count, 1517 SkFilterQuality filterQuality, SkBlendMode mode) { 1518 SkASSERT(count > 0); 1519 1520 GrSamplerState sampler; 1521 sampler.setFilterMode(kNone_SkFilterQuality == filterQuality ? GrSamplerState::Filter::kNearest 1522 : GrSamplerState::Filter::kBilerp); 1523 SkAutoTArray<GrRenderTargetContext::TextureSetEntry> textures(count); 1524 // We accumulate compatible proxies until we find an an incompatible one or reach the end and 1525 // issue the accumulated 'n' draws starting at 'base'. 1526 int base = 0, n = 0; 1527 auto draw = [&] { 1528 if (n > 0) { 1529 auto textureXform = GrColorSpaceXform::Make( 1530 set[base].fImage->colorSpace(), set[base].fImage->alphaType(), 1531 fRenderTargetContext->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType); 1532 fRenderTargetContext->drawTextureSet(this->clip(), textures.get() + base, n, 1533 sampler.filter(), mode, this->ctm(), 1534 std::move(textureXform)); 1535 } 1536 }; 1537 for (int i = 0; i < count; ++i) { 1538 // The default SkBaseDevice implementation is based on drawImageRect which does not allow 1539 // non-sorted src rects. TODO: Decide this is OK or make sure we handle it. 1540 if (!set[i].fSrcRect.isSorted()) { 1541 draw(); 1542 base = i + 1; 1543 n = 0; 1544 continue; 1545 } 1546 uint32_t uniqueID; 1547 textures[i].fProxy = as_IB(set[i].fImage.get())->refPinnedTextureProxy(&uniqueID); 1548 if (!textures[i].fProxy) { 1549 textures[i].fProxy = 1550 as_IB(set[i].fImage.get()) 1551 ->asTextureProxyRef(fContext.get(), GrSamplerState::ClampBilerp(), 1552 nullptr); 1553 // If we failed to make a proxy then flush the accumulated set and reset for the next 1554 // image. 1555 if (!textures[i].fProxy) { 1556 draw(); 1557 base = i + 1; 1558 n = 0; 1559 continue; 1560 } 1561 } 1562 textures[i].fSrcRect = set[i].fSrcRect; 1563 textures[i].fDstRect = set[i].fDstRect; 1564 textures[i].fAlpha = set[i].fAlpha; 1565 textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags); 1566 if (n > 0 && 1567 (!GrTextureProxy::ProxiesAreCompatibleAsDynamicState(textures[i].fProxy.get(), 1568 textures[base].fProxy.get()) || 1569 set[i].fImage->alphaType() != set[base].fImage->alphaType() || 1570 !SkColorSpace::Equals(set[i].fImage->colorSpace(), set[base].fImage->colorSpace()))) { 1571 draw(); 1572 base = i; 1573 n = 1; 1574 } else { 1575 ++n; 1576 } 1577 } 1578 draw(); 1579 } 1580 1581 static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo, 1582 const SkPaint& skPaint, const SkMatrix& matrix, SkBlendMode bmode, 1583 bool hasTexs, bool hasColors, GrPaint* grPaint) { 1584 if (hasTexs && skPaint.getShader()) { 1585 if (hasColors) { 1586 // When there are texs and colors the shader and colors are combined using bmode. 1587 return SkPaintToGrPaintWithXfermode(context, colorSpaceInfo, skPaint, matrix, bmode, 1588 grPaint); 1589 } else { 1590 // We have a shader, but no colors to blend it against. 1591 return SkPaintToGrPaint(context, colorSpaceInfo, skPaint, matrix, grPaint); 1592 } 1593 } else { 1594 if (hasColors) { 1595 // We have colors, but either have no shader or no texture coords (which implies that 1596 // we should ignore the shader). 1597 return SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint); 1598 } else { 1599 // No colors and no shaders. Just draw with the paint color. 1600 return SkPaintToGrPaintNoShader(context, colorSpaceInfo, skPaint, grPaint); 1601 } 1602 } 1603 } 1604 1605 void SkGpuDevice::wireframeVertices(SkVertices::VertexMode vmode, int vertexCount, 1606 const SkPoint vertices[], 1607 const SkVertices::Bone bones[], int boneCount, 1608 SkBlendMode bmode, 1609 const uint16_t indices[], int indexCount, 1610 const SkPaint& paint) { 1611 ASSERT_SINGLE_OWNER 1612 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "wireframeVertices", fContext.get()); 1613 1614 SkPaint copy(paint); 1615 copy.setStyle(SkPaint::kStroke_Style); 1616 copy.setStrokeWidth(0); 1617 1618 GrPaint grPaint; 1619 // we ignore the shader since we have no texture coordinates. 1620 if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext->colorSpaceInfo(), copy, 1621 &grPaint)) { 1622 return; 1623 } 1624 1625 int triangleCount = 0; 1626 int n = (nullptr == indices) ? vertexCount : indexCount; 1627 switch (vmode) { 1628 case SkVertices::kTriangles_VertexMode: 1629 triangleCount = n / 3; 1630 break; 1631 case SkVertices::kTriangleStrip_VertexMode: 1632 triangleCount = n - 2; 1633 break; 1634 case SkVertices::kTriangleFan_VertexMode: 1635 SK_ABORT("Unexpected triangle fan."); 1636 break; 1637 } 1638 1639 VertState state(vertexCount, indices, indexCount); 1640 VertState::Proc vertProc = state.chooseProc(vmode); 1641 1642 //number of indices for lines per triangle with kLines 1643 indexCount = triangleCount * 6; 1644 1645 static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; 1646 SkVertices::Builder builder(kIgnoredMode, vertexCount, indexCount, 0); 1647 memcpy(builder.positions(), vertices, vertexCount * sizeof(SkPoint)); 1648 1649 uint16_t* lineIndices = builder.indices(); 1650 int i = 0; 1651 while (vertProc(&state)) { 1652 lineIndices[i] = state.f0; 1653 lineIndices[i + 1] = state.f1; 1654 lineIndices[i + 2] = state.f1; 1655 lineIndices[i + 3] = state.f2; 1656 lineIndices[i + 4] = state.f2; 1657 lineIndices[i + 5] = state.f0; 1658 i += 6; 1659 } 1660 1661 GrPrimitiveType primitiveType = GrPrimitiveType::kLines; 1662 fRenderTargetContext->drawVertices(this->clip(), 1663 std::move(grPaint), 1664 this->ctm(), 1665 builder.detach(), 1666 bones, 1667 boneCount, 1668 &primitiveType); 1669 } 1670 1671 void SkGpuDevice::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[], 1672 int boneCount, SkBlendMode mode, const SkPaint& paint) { 1673 ASSERT_SINGLE_OWNER 1674 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext.get()); 1675 1676 SkASSERT(vertices); 1677 GrPaint grPaint; 1678 bool hasColors = vertices->hasColors(); 1679 bool hasTexs = vertices->hasTexCoords(); 1680 if ((!hasTexs || !paint.getShader()) && !hasColors) { 1681 // The dreaded wireframe mode. Fallback to drawVertices and go so slooooooow. 1682 this->wireframeVertices(vertices->mode(), vertices->vertexCount(), vertices->positions(), 1683 bones, boneCount, mode, vertices->indices(), vertices->indexCount(), 1684 paint); 1685 return; 1686 } 1687 if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorSpaceInfo(), paint, 1688 this->ctm(), mode, hasTexs, hasColors, &grPaint)) { 1689 return; 1690 } 1691 fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(), 1692 sk_ref_sp(const_cast<SkVertices*>(vertices)), 1693 bones, boneCount); 1694 } 1695 1696 /////////////////////////////////////////////////////////////////////////////// 1697 1698 void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) { 1699 1700 ASSERT_SINGLE_OWNER 1701 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get()); 1702 1703 if (!fRenderTargetContext->drawFastShadow(this->clip(), this->ctm(), path, rec)) { 1704 // failed to find an accelerated case 1705 this->INHERITED::drawShadow(path, rec); 1706 } 1707 } 1708 1709 /////////////////////////////////////////////////////////////////////////////// 1710 1711 void SkGpuDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[], 1712 const SkRect texRect[], const SkColor colors[], int count, 1713 SkBlendMode mode, const SkPaint& paint) { 1714 ASSERT_SINGLE_OWNER 1715 if (paint.isAntiAlias()) { 1716 this->INHERITED::drawAtlas(atlas, xform, texRect, colors, count, mode, paint); 1717 return; 1718 } 1719 1720 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext.get()); 1721 1722 SkPaint p(paint); 1723 p.setShader(atlas->makeShader()); 1724 1725 GrPaint grPaint; 1726 if (colors) { 1727 if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext->colorSpaceInfo(), 1728 p, this->ctm(), (SkBlendMode)mode, &grPaint)) { 1729 return; 1730 } 1731 } else { 1732 if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), p, 1733 this->ctm(), &grPaint)) { 1734 return; 1735 } 1736 } 1737 1738 fRenderTargetContext->drawAtlas( 1739 this->clip(), std::move(grPaint), this->ctm(), count, xform, texRect, colors); 1740 } 1741 1742 /////////////////////////////////////////////////////////////////////////////// 1743 1744 void SkGpuDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) { 1745 ASSERT_SINGLE_OWNER 1746 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawGlyphRunList", fContext.get()); 1747 1748 // Check for valid input 1749 const SkMatrix& ctm = this->ctm(); 1750 if (!ctm.isFinite() || !glyphRunList.allFontsFinite()) { 1751 return; 1752 } 1753 1754 fRenderTargetContext->drawGlyphRunList(this->clip(), ctm, glyphRunList); 1755 } 1756 1757 /////////////////////////////////////////////////////////////////////////////// 1758 1759 void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) { 1760 GrBackendApi api = this->context()->backend(); 1761 if (GrBackendApi::kVulkan == api) { 1762 const SkMatrix& ctm = canvas->getTotalMatrix(); 1763 const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm; 1764 std::unique_ptr<SkDrawable::GpuDrawHandler> gpuDraw = 1765 drawable->snapGpuDrawHandler(api, combinedMatrix, canvas->getDeviceClipBounds(), 1766 this->imageInfo()); 1767 if (gpuDraw) { 1768 fRenderTargetContext->drawDrawable(std::move(gpuDraw), drawable->getBounds()); 1769 return; 1770 } 1771 } 1772 this->INHERITED::drawDrawable(drawable, matrix, canvas); 1773 } 1774 1775 1776 /////////////////////////////////////////////////////////////////////////////// 1777 1778 void SkGpuDevice::flush() { 1779 this->flushAndSignalSemaphores(0, nullptr); 1780 } 1781 1782 GrSemaphoresSubmitted SkGpuDevice::flushAndSignalSemaphores(int numSemaphores, 1783 GrBackendSemaphore signalSemaphores[]) { 1784 ASSERT_SINGLE_OWNER 1785 1786 return fRenderTargetContext->prepareForExternalIO(numSemaphores, signalSemaphores); 1787 } 1788 1789 bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) { 1790 ASSERT_SINGLE_OWNER 1791 1792 return fRenderTargetContext->waitOnSemaphores(numSemaphores, waitSemaphores); 1793 } 1794 1795 /////////////////////////////////////////////////////////////////////////////// 1796 1797 SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 1798 ASSERT_SINGLE_OWNER 1799 1800 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry); 1801 1802 // layers are never drawn in repeat modes, so we can request an approx 1803 // match and ignore any padding. 1804 SkBackingFit fit = kNever_TileUsage == cinfo.fTileUsage ? SkBackingFit::kApprox 1805 : SkBackingFit::kExact; 1806 1807 GrPixelConfig config = fRenderTargetContext->colorSpaceInfo().config(); 1808 const GrBackendFormat& origFormat = fRenderTargetContext->asSurfaceProxy()->backendFormat(); 1809 GrBackendFormat format = origFormat.makeTexture2D(); 1810 if (!format.isValid()) { 1811 return nullptr; 1812 } 1813 if (kRGBA_1010102_GrPixelConfig == config) { 1814 // If the original device is 1010102, fall back to 8888 so that we have a usable alpha 1815 // channel in the layer. 1816 config = kRGBA_8888_GrPixelConfig; 1817 format = 1818 fContext->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 1819 } 1820 1821 sk_sp<GrRenderTargetContext> rtc(fContext->contextPriv().makeDeferredRenderTargetContext( 1822 format, fit, cinfo.fInfo.width(), cinfo.fInfo.height(), config, 1823 fRenderTargetContext->colorSpaceInfo().refColorSpace(), 1824 fRenderTargetContext->numStencilSamples(), GrMipMapped::kNo, 1825 kBottomLeft_GrSurfaceOrigin, &props)); 1826 if (!rtc) { 1827 return nullptr; 1828 } 1829 1830 // Skia's convention is to only clear a device if it is non-opaque. 1831 InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents; 1832 1833 return SkGpuDevice::Make(fContext.get(), std::move(rtc), 1834 cinfo.fInfo.width(), cinfo.fInfo.height(), init).release(); 1835 } 1836 1837 sk_sp<SkSurface> SkGpuDevice::makeSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1838 ASSERT_SINGLE_OWNER 1839 // TODO: Change the signature of newSurface to take a budgeted parameter. 1840 static const SkBudgeted kBudgeted = SkBudgeted::kNo; 1841 return SkSurface::MakeRenderTarget(fContext.get(), kBudgeted, info, 1842 fRenderTargetContext->numStencilSamples(), 1843 fRenderTargetContext->origin(), &props); 1844 } 1845 1846 SkImageFilterCache* SkGpuDevice::getImageFilterCache() { 1847 ASSERT_SINGLE_OWNER 1848 // We always return a transient cache, so it is freed after each 1849 // filter traversal. 1850 return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize); 1851 } 1852 1853