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