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