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