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