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 "SkDraw.h" 13 #include "GrGpu.h" 14 #include "GrGpuResourcePriv.h" 15 #include "GrImageIDTextureAdjuster.h" 16 #include "GrLayerHoister.h" 17 #include "GrRecordReplaceDraw.h" 18 #include "GrStrokeInfo.h" 19 #include "GrTracing.h" 20 #include "SkCanvasPriv.h" 21 #include "SkErrorInternals.h" 22 #include "SkGlyphCache.h" 23 #include "SkGrTexturePixelRef.h" 24 #include "SkGr.h" 25 #include "SkGrPriv.h" 26 #include "SkImage_Base.h" 27 #include "SkImageCacherator.h" 28 #include "SkImageFilter.h" 29 #include "SkLayerInfo.h" 30 #include "SkMaskFilter.h" 31 #include "SkNinePatchIter.h" 32 #include "SkPathEffect.h" 33 #include "SkPicture.h" 34 #include "SkPictureData.h" 35 #include "SkRRect.h" 36 #include "SkRecord.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/GrRRectEffect.h" 48 #include "effects/GrSimpleTextureEffect.h" 49 #include "effects/GrTextureDomain.h" 50 #include "text/GrTextUtils.h" 51 52 #if SK_SUPPORT_GPU 53 54 #define ASSERT_SINGLE_OWNER \ 55 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());) 56 57 enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 }; 58 59 #if 0 60 extern bool (*gShouldDrawProc)(); 61 #define CHECK_SHOULD_DRAW(draw) \ 62 do { \ 63 if (gShouldDrawProc && !gShouldDrawProc()) return; \ 64 this->prepareDraw(draw); \ 65 } while (0) 66 #else 67 #define CHECK_SHOULD_DRAW(draw) this->prepareDraw(draw) 68 #endif 69 70 /////////////////////////////////////////////////////////////////////////////// 71 72 #define CHECK_FOR_ANNOTATION(paint) \ 73 do { if (paint.getAnnotation()) { return; } } while (0) 74 75 /////////////////////////////////////////////////////////////////////////////// 76 77 // Helper for turning a bitmap into a texture. If the bitmap is GrTexture backed this 78 // just accesses the backing GrTexture. Otherwise, it creates a cached texture 79 // representation and releases it in the destructor. 80 class AutoBitmapTexture : public SkNoncopyable { 81 public: 82 AutoBitmapTexture() {} 83 84 AutoBitmapTexture(GrContext* context, 85 const SkBitmap& bitmap, 86 const GrTextureParams& params, 87 GrTexture** texture) { 88 SkASSERT(texture); 89 *texture = this->set(context, bitmap, params); 90 } 91 92 GrTexture* set(GrContext* context, 93 const SkBitmap& bitmap, 94 const GrTextureParams& params) { 95 // Either get the texture directly from the bitmap, or else use the cache and 96 // remember to unref it. 97 if (GrTexture* bmpTexture = bitmap.getTexture()) { 98 fTexture.reset(nullptr); 99 return bmpTexture; 100 } else { 101 fTexture.reset(GrRefCachedBitmapTexture(context, bitmap, params)); 102 return fTexture.get(); 103 } 104 } 105 106 private: 107 SkAutoTUnref<GrTexture> fTexture; 108 }; 109 110 /////////////////////////////////////////////////////////////////////////////// 111 112 /** Checks that the alpha type is legal and gets constructor flags. Returns false if device creation 113 should fail. */ 114 bool SkGpuDevice::CheckAlphaTypeAndGetFlags( 115 const SkImageInfo* info, SkGpuDevice::InitContents init, unsigned* flags) { 116 *flags = 0; 117 if (info) { 118 switch (info->alphaType()) { 119 case kPremul_SkAlphaType: 120 break; 121 case kOpaque_SkAlphaType: 122 *flags |= SkGpuDevice::kIsOpaque_Flag; 123 break; 124 default: // If it is unpremul or unknown don't try to render 125 return false; 126 } 127 } 128 if (kClear_InitContents == init) { 129 *flags |= kNeedClear_Flag; 130 } 131 return true; 132 } 133 134 SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, const SkSurfaceProps* props, 135 InitContents init) { 136 return SkGpuDevice::Create(rt, rt->width(), rt->height(), props, init); 137 } 138 139 SkGpuDevice* SkGpuDevice::Create(GrRenderTarget* rt, int width, int height, 140 const SkSurfaceProps* props, InitContents init) { 141 if (!rt || rt->wasDestroyed()) { 142 return nullptr; 143 } 144 unsigned flags; 145 if (!CheckAlphaTypeAndGetFlags(nullptr, init, &flags)) { 146 return nullptr; 147 } 148 return new SkGpuDevice(rt, width, height, props, flags); 149 } 150 151 SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkBudgeted budgeted, 152 const SkImageInfo& info, int sampleCount, 153 const SkSurfaceProps* props, InitContents init, 154 GrTextureStorageAllocator customAllocator) { 155 unsigned flags; 156 if (!CheckAlphaTypeAndGetFlags(&info, init, &flags)) { 157 return nullptr; 158 } 159 160 SkAutoTUnref<GrRenderTarget> rt(CreateRenderTarget( 161 context, budgeted, info, sampleCount, customAllocator)); 162 if (nullptr == rt) { 163 return nullptr; 164 } 165 166 return new SkGpuDevice(rt, info.width(), info.height(), props, flags); 167 } 168 169 SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height, 170 const SkSurfaceProps* props, unsigned flags) 171 : INHERITED(SkSurfacePropsCopyOrDefault(props)) 172 , fContext(SkRef(rt->getContext())) 173 , fRenderTarget(SkRef(rt)) { 174 fOpaque = SkToBool(flags & kIsOpaque_Flag); 175 176 SkAlphaType at = fOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 177 SkImageInfo info = rt->surfacePriv().info(at).makeWH(width, height); 178 SkPixelRef* pr = new SkGrPixelRef(info, rt); 179 fLegacyBitmap.setInfo(info); 180 fLegacyBitmap.setPixelRef(pr)->unref(); 181 182 fDrawContext.reset(this->context()->drawContext(rt, &this->surfaceProps())); 183 if (flags & kNeedClear_Flag) { 184 this->clearAll(); 185 } 186 } 187 188 GrRenderTarget* SkGpuDevice::CreateRenderTarget( 189 GrContext* context, SkBudgeted budgeted, const SkImageInfo& origInfo, 190 int sampleCount, GrTextureStorageAllocator textureStorageAllocator) { 191 if (kUnknown_SkColorType == origInfo.colorType() || 192 origInfo.width() < 0 || origInfo.height() < 0) { 193 return nullptr; 194 } 195 196 if (!context) { 197 return nullptr; 198 } 199 200 SkColorType ct = origInfo.colorType(); 201 SkAlphaType at = origInfo.alphaType(); 202 if (kRGB_565_SkColorType == ct) { 203 at = kOpaque_SkAlphaType; // force this setting 204 } else if (ct != kBGRA_8888_SkColorType && ct != kRGBA_8888_SkColorType) { 205 // Fall back from whatever ct was to default of kRGBA or kBGRA which is aliased as kN32 206 ct = kN32_SkColorType; 207 } 208 if (kOpaque_SkAlphaType != at) { 209 at = kPremul_SkAlphaType; // force this setting 210 } 211 const SkImageInfo info = SkImageInfo::Make(origInfo.width(), origInfo.height(), ct, at); 212 213 GrSurfaceDesc desc; 214 desc.fFlags = kRenderTarget_GrSurfaceFlag; 215 desc.fWidth = info.width(); 216 desc.fHeight = info.height(); 217 desc.fConfig = SkImageInfo2GrPixelConfig(info); 218 desc.fSampleCnt = sampleCount; 219 desc.fTextureStorageAllocator = textureStorageAllocator; 220 GrTexture* texture = context->textureProvider()->createTexture(desc, budgeted, nullptr, 0); 221 if (nullptr == texture) { 222 return nullptr; 223 } 224 SkASSERT(nullptr != texture->asRenderTarget()); 225 return texture->asRenderTarget(); 226 } 227 228 /////////////////////////////////////////////////////////////////////////////// 229 230 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 231 int x, int y) { 232 ASSERT_SINGLE_OWNER 233 234 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels 235 GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo); 236 if (kUnknown_GrPixelConfig == config) { 237 return false; 238 } 239 240 uint32_t flags = 0; 241 if (kUnpremul_SkAlphaType == dstInfo.alphaType()) { 242 flags = GrContext::kUnpremul_PixelOpsFlag; 243 } 244 return fRenderTarget->readPixels(x, y, dstInfo.width(), dstInfo.height(), config, dstPixels, 245 dstRowBytes, flags); 246 } 247 248 bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, 249 int x, int y) { 250 ASSERT_SINGLE_OWNER 251 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels 252 GrPixelConfig config = SkImageInfo2GrPixelConfig(info); 253 if (kUnknown_GrPixelConfig == config) { 254 return false; 255 } 256 uint32_t flags = 0; 257 if (kUnpremul_SkAlphaType == info.alphaType()) { 258 flags = GrContext::kUnpremul_PixelOpsFlag; 259 } 260 fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags); 261 262 // need to bump our genID for compatibility with clients that "know" we have a bitmap 263 fLegacyBitmap.notifyPixelsChanged(); 264 265 return true; 266 } 267 268 const SkBitmap& SkGpuDevice::onAccessBitmap() { 269 ASSERT_SINGLE_OWNER 270 return fLegacyBitmap; 271 } 272 273 bool SkGpuDevice::onAccessPixels(SkPixmap* pmap) { 274 ASSERT_SINGLE_OWNER 275 // For compatibility with clients the know we're backed w/ a bitmap, and want to inspect its 276 // genID. When we can hide/remove that fact, we can eliminate this call to notify. 277 // ... ugh. 278 fLegacyBitmap.notifyPixelsChanged(); 279 return false; 280 } 281 282 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) { 283 ASSERT_SINGLE_OWNER 284 INHERITED::onAttachToCanvas(canvas); 285 286 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 287 fClipStack.reset(SkRef(canvas->getClipStack())); 288 } 289 290 void SkGpuDevice::onDetachFromCanvas() { 291 ASSERT_SINGLE_OWNER 292 INHERITED::onDetachFromCanvas(); 293 fClip.reset(); 294 fClipStack.reset(nullptr); 295 } 296 297 // call this every draw call, to ensure that the context reflects our state, 298 // and not the state from some other canvas/device 299 void SkGpuDevice::prepareDraw(const SkDraw& draw) { 300 ASSERT_SINGLE_OWNER 301 SkASSERT(fClipStack.get()); 302 303 SkASSERT(draw.fClipStack && draw.fClipStack == fClipStack); 304 305 fClip.setClipStack(fClipStack, &this->getOrigin()); 306 } 307 308 GrRenderTarget* SkGpuDevice::accessRenderTarget() { 309 ASSERT_SINGLE_OWNER 310 return fRenderTarget; 311 } 312 313 void SkGpuDevice::clearAll() { 314 ASSERT_SINGLE_OWNER 315 GrColor color = 0; 316 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext); 317 SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); 318 fDrawContext->clear(&rect, color, true); 319 } 320 321 void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) { 322 ASSERT_SINGLE_OWNER 323 324 SkBudgeted budgeted = fRenderTarget->resourcePriv().isBudgeted(); 325 326 SkAutoTUnref<GrRenderTarget> newRT(CreateRenderTarget( 327 this->context(), budgeted, this->imageInfo(), fRenderTarget->desc().fSampleCnt, 328 fRenderTarget->desc().fTextureStorageAllocator)); 329 330 if (nullptr == newRT) { 331 return; 332 } 333 334 if (shouldRetainContent) { 335 if (fRenderTarget->wasDestroyed()) { 336 return; 337 } 338 this->context()->copySurface(newRT, fRenderTarget); 339 } 340 341 SkASSERT(fRenderTarget != newRT); 342 343 fRenderTarget.reset(newRT.detach()); 344 345 #ifdef SK_DEBUG 346 SkImageInfo info = fRenderTarget->surfacePriv().info(fOpaque ? kOpaque_SkAlphaType : 347 kPremul_SkAlphaType); 348 SkASSERT(info == fLegacyBitmap.info()); 349 #endif 350 SkPixelRef* pr = new SkGrPixelRef(fLegacyBitmap.info(), fRenderTarget); 351 fLegacyBitmap.setPixelRef(pr)->unref(); 352 353 fDrawContext.reset(this->context()->drawContext(fRenderTarget, &this->surfaceProps())); 354 } 355 356 /////////////////////////////////////////////////////////////////////////////// 357 358 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 359 ASSERT_SINGLE_OWNER 360 CHECK_SHOULD_DRAW(draw); 361 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext); 362 363 GrPaint grPaint; 364 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 365 return; 366 } 367 368 fDrawContext->drawPaint(fClip, grPaint, *draw.fMatrix); 369 } 370 371 // must be in SkCanvas::PointMode order 372 static const GrPrimitiveType gPointMode2PrimtiveType[] = { 373 kPoints_GrPrimitiveType, 374 kLines_GrPrimitiveType, 375 kLineStrip_GrPrimitiveType 376 }; 377 378 // suppress antialiasing on axis-aligned integer-coordinate lines 379 static bool needs_antialiasing(SkCanvas::PointMode mode, size_t count, const SkPoint pts[]) { 380 if (mode == SkCanvas::PointMode::kPoints_PointMode) { 381 return false; 382 } 383 if (count == 2) { 384 // We do not antialias as long as the primary axis of the line is integer-aligned, even if 385 // the other coordinates are not. This does mean the two end pixels of the line will be 386 // sharp even when they shouldn't be, but turning antialiasing on (as things stand 387 // currently) means that the line will turn into a two-pixel-wide blur. While obviously a 388 // more complete fix is possible down the road, for the time being we accept the error on 389 // the two end pixels as being the lesser of two evils. 390 if (pts[0].fX == pts[1].fX) { 391 return ((int) pts[0].fX) != pts[0].fX; 392 } 393 if (pts[0].fY == pts[1].fY) { 394 return ((int) pts[0].fY) != pts[0].fY; 395 } 396 } 397 return true; 398 } 399 400 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 401 size_t count, const SkPoint pts[], const SkPaint& paint) { 402 ASSERT_SINGLE_OWNER 403 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPoints", fContext); 404 CHECK_FOR_ANNOTATION(paint); 405 CHECK_SHOULD_DRAW(draw); 406 407 SkScalar width = paint.getStrokeWidth(); 408 if (width < 0) { 409 return; 410 } 411 412 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) { 413 GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style); 414 GrPaint grPaint; 415 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 416 return; 417 } 418 SkPath path; 419 path.setIsVolatile(true); 420 path.moveTo(pts[0]); 421 path.lineTo(pts[1]); 422 fDrawContext->drawPath(fClip, grPaint, *draw.fMatrix, path, strokeInfo); 423 return; 424 } 425 426 // we only handle non-antialiased hairlines and paints without path effects or mask filters, 427 // else we let the SkDraw call our drawPath() 428 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter() || 429 (paint.isAntiAlias() && needs_antialiasing(mode, count, pts))) { 430 draw.drawPoints(mode, count, pts, paint, true); 431 return; 432 } 433 434 GrPaint grPaint; 435 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 436 return; 437 } 438 439 fDrawContext->drawVertices(fClip, 440 grPaint, 441 *draw.fMatrix, 442 gPointMode2PrimtiveType[mode], 443 SkToS32(count), 444 (SkPoint*)pts, 445 nullptr, 446 nullptr, 447 nullptr, 448 0); 449 } 450 451 /////////////////////////////////////////////////////////////////////////////// 452 453 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, const SkPaint& paint) { 454 ASSERT_SINGLE_OWNER 455 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRect", fContext); 456 CHECK_FOR_ANNOTATION(paint); 457 CHECK_SHOULD_DRAW(draw); 458 459 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 460 SkScalar width = paint.getStrokeWidth(); 461 462 /* 463 We have special code for hairline strokes, miter-strokes, bevel-stroke 464 and fills. Anything else we just call our path code. 465 */ 466 bool usePath = doStroke && width > 0 && 467 (paint.getStrokeJoin() == SkPaint::kRound_Join || 468 (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty())); 469 470 // a few other reasons we might need to call drawPath... 471 if (paint.getMaskFilter() || paint.getPathEffect() || 472 paint.getStyle() == SkPaint::kStrokeAndFill_Style) { // we can't both stroke and fill rects 473 usePath = true; 474 } 475 476 if (usePath) { 477 SkPath path; 478 path.setIsVolatile(true); 479 path.addRect(rect); 480 GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, 481 fClip, path, paint, 482 *draw.fMatrix, nullptr, 483 draw.fClip->getBounds(), true); 484 return; 485 } 486 487 GrPaint grPaint; 488 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 489 return; 490 } 491 492 GrStrokeInfo strokeInfo(paint); 493 494 fDrawContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &strokeInfo); 495 } 496 497 /////////////////////////////////////////////////////////////////////////////// 498 499 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, 500 const SkPaint& paint) { 501 ASSERT_SINGLE_OWNER 502 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext); 503 CHECK_FOR_ANNOTATION(paint); 504 CHECK_SHOULD_DRAW(draw); 505 506 GrPaint grPaint; 507 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 508 return; 509 } 510 511 GrStrokeInfo strokeInfo(paint); 512 if (paint.getMaskFilter()) { 513 // try to hit the fast path for drawing filtered round rects 514 515 SkRRect devRRect; 516 if (rect.transform(*draw.fMatrix, &devRRect)) { 517 if (devRRect.allCornersCircular()) { 518 SkRect maskRect; 519 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect, 520 draw.fClip->getBounds(), 521 *draw.fMatrix, 522 &maskRect)) { 523 SkIRect finalIRect; 524 maskRect.roundOut(&finalIRect); 525 if (draw.fClip->quickReject(finalIRect)) { 526 // clipped out 527 return; 528 } 529 if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext->textureProvider(), 530 fDrawContext, 531 &grPaint, 532 fClip, 533 *draw.fMatrix, 534 strokeInfo, 535 devRRect)) { 536 return; 537 } 538 } 539 540 } 541 } 542 } 543 544 if (paint.getMaskFilter() || paint.getPathEffect()) { 545 // The only mask filter the native rrect drawing code could've handle was taken 546 // care of above. 547 // A path effect will presumably transform this rrect into something else. 548 SkPath path; 549 path.setIsVolatile(true); 550 path.addRRect(rect); 551 GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, 552 fClip, path, paint, 553 *draw.fMatrix, nullptr, 554 draw.fClip->getBounds(), true); 555 return; 556 } 557 558 SkASSERT(!strokeInfo.isDashed()); 559 560 fDrawContext->drawRRect(fClip, grPaint, *draw.fMatrix, rect, strokeInfo); 561 } 562 563 bool SkGpuDevice::drawFilledDRRect(const SkMatrix& viewMatrix, const SkRRect& origOuter, 564 const SkRRect& origInner, const SkPaint& paint) { 565 SkASSERT(!origInner.isEmpty()); 566 SkASSERT(!origOuter.isEmpty()); 567 568 bool applyAA = paint.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled(); 569 570 GrPrimitiveEdgeType innerEdgeType = applyAA ? kInverseFillAA_GrProcessorEdgeType : 571 kInverseFillBW_GrProcessorEdgeType; 572 GrPrimitiveEdgeType outerEdgeType = applyAA ? kFillAA_GrProcessorEdgeType : 573 kFillBW_GrProcessorEdgeType; 574 575 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter); 576 SkMatrix inverseVM; 577 if (!viewMatrix.isIdentity()) { 578 if (!origInner.transform(viewMatrix, inner.writable())) { 579 return false; 580 } 581 if (!origOuter.transform(viewMatrix, outer.writable())) { 582 return false; 583 } 584 if (!viewMatrix.invert(&inverseVM)) { 585 return false; 586 } 587 } else { 588 inverseVM.reset(); 589 } 590 591 GrPaint grPaint; 592 593 if (!SkPaintToGrPaint(this->context(), paint, viewMatrix, &grPaint)) { 594 return false; 595 } 596 597 grPaint.setAntiAlias(false); 598 599 // TODO these need to be a geometry processors 600 SkAutoTUnref<GrFragmentProcessor> innerEffect(GrRRectEffect::Create(innerEdgeType, *inner)); 601 if (!innerEffect) { 602 return false; 603 } 604 605 SkAutoTUnref<GrFragmentProcessor> outerEffect(GrRRectEffect::Create(outerEdgeType, *outer)); 606 if (!outerEffect) { 607 return false; 608 } 609 610 grPaint.addCoverageFragmentProcessor(innerEffect); 611 grPaint.addCoverageFragmentProcessor(outerEffect); 612 613 SkRect bounds = outer->getBounds(); 614 if (applyAA) { 615 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); 616 } 617 618 fDrawContext->fillRectWithLocalMatrix(fClip, grPaint, SkMatrix::I(), bounds, inverseVM); 619 return true; 620 } 621 622 623 void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, 624 const SkRRect& inner, const SkPaint& paint) { 625 ASSERT_SINGLE_OWNER 626 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDRRect", fContext); 627 CHECK_FOR_ANNOTATION(paint); 628 CHECK_SHOULD_DRAW(draw); 629 630 if (outer.isEmpty()) { 631 return; 632 } 633 634 if (inner.isEmpty()) { 635 return this->drawRRect(draw, outer, paint); 636 } 637 638 SkStrokeRec stroke(paint); 639 640 if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) { 641 if (this->drawFilledDRRect(*draw.fMatrix, outer, inner, paint)) { 642 return; 643 } 644 } 645 646 SkPath path; 647 path.setIsVolatile(true); 648 path.addRRect(outer); 649 path.addRRect(inner); 650 path.setFillType(SkPath::kEvenOdd_FillType); 651 652 GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, 653 fClip, path, paint, 654 *draw.fMatrix, nullptr, 655 draw.fClip->getBounds(), true); 656 } 657 658 659 ///////////////////////////////////////////////////////////////////////////// 660 661 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) { 662 ASSERT_SINGLE_OWNER 663 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawOval", fContext); 664 CHECK_FOR_ANNOTATION(paint); 665 CHECK_SHOULD_DRAW(draw); 666 667 // Presumably the path effect warps this to something other than an oval 668 if (paint.getPathEffect()) { 669 SkPath path; 670 path.setIsVolatile(true); 671 path.addOval(oval); 672 this->drawPath(draw, path, paint, nullptr, true); 673 return; 674 } 675 676 if (paint.getMaskFilter()) { 677 // The RRect path can handle special case blurring 678 SkRRect rr = SkRRect::MakeOval(oval); 679 return this->drawRRect(draw, rr, paint); 680 } 681 682 GrPaint grPaint; 683 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 684 return; 685 } 686 687 GrStrokeInfo strokeInfo(paint); 688 SkASSERT(!strokeInfo.isDashed()); 689 690 fDrawContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, strokeInfo); 691 } 692 693 #include "SkMaskFilter.h" 694 695 /////////////////////////////////////////////////////////////////////////////// 696 697 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, 698 const SkPaint& paint, const SkMatrix* prePathMatrix, 699 bool pathIsMutable) { 700 ASSERT_SINGLE_OWNER 701 if (!origSrcPath.isInverseFillType() && !paint.getPathEffect() && !prePathMatrix) { 702 bool isClosed; 703 SkRect rect; 704 if (origSrcPath.isRect(&rect, &isClosed) && isClosed) { 705 this->drawRect(draw, rect, paint); 706 return; 707 } 708 if (origSrcPath.isOval(&rect)) { 709 this->drawOval(draw, rect, paint); 710 return; 711 } 712 SkRRect rrect; 713 if (origSrcPath.isRRect(&rrect)) { 714 this->drawRRect(draw, rrect, paint); 715 return; 716 } 717 } 718 719 CHECK_FOR_ANNOTATION(paint); 720 CHECK_SHOULD_DRAW(draw); 721 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPath", fContext); 722 723 GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, 724 fClip, origSrcPath, paint, 725 *draw.fMatrix, prePathMatrix, 726 draw.fClip->getBounds(), pathIsMutable); 727 } 728 729 static const int kBmpSmallTileSize = 1 << 10; 730 731 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { 732 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; 733 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; 734 return tilesX * tilesY; 735 } 736 737 static int determine_tile_size(const SkIRect& src, int maxTileSize) { 738 if (maxTileSize <= kBmpSmallTileSize) { 739 return maxTileSize; 740 } 741 742 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); 743 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); 744 745 maxTileTotalTileSize *= maxTileSize * maxTileSize; 746 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; 747 748 if (maxTileTotalTileSize > 2 * smallTotalTileSize) { 749 return kBmpSmallTileSize; 750 } else { 751 return maxTileSize; 752 } 753 } 754 755 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what 756 // pixels from the bitmap are necessary. 757 static void determine_clipped_src_rect(const GrRenderTarget* rt, 758 const GrClip& clip, 759 const SkMatrix& viewMatrix, 760 const SkISize& imageSize, 761 const SkRect* srcRectPtr, 762 SkIRect* clippedSrcIRect) { 763 clip.getConservativeBounds(rt->width(), rt->height(), clippedSrcIRect, nullptr); 764 SkMatrix inv; 765 if (!viewMatrix.invert(&inv)) { 766 clippedSrcIRect->setEmpty(); 767 return; 768 } 769 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect); 770 inv.mapRect(&clippedSrcRect); 771 if (srcRectPtr) { 772 // we've setup src space 0,0 to map to the top left of the src rect. 773 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop); 774 if (!clippedSrcRect.intersect(*srcRectPtr)) { 775 clippedSrcIRect->setEmpty(); 776 return; 777 } 778 } 779 clippedSrcRect.roundOut(clippedSrcIRect); 780 SkIRect bmpBounds = SkIRect::MakeSize(imageSize); 781 if (!clippedSrcIRect->intersect(bmpBounds)) { 782 clippedSrcIRect->setEmpty(); 783 } 784 } 785 786 bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect, 787 const SkMatrix& viewMatrix, 788 const GrTextureParams& params, 789 const SkRect* srcRectPtr, 790 int maxTileSize, 791 int* tileSize, 792 SkIRect* clippedSubset) const { 793 ASSERT_SINGLE_OWNER 794 // if it's larger than the max tile size, then we have no choice but tiling. 795 if (imageRect.width() > maxTileSize || imageRect.height() > maxTileSize) { 796 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(), 797 srcRectPtr, clippedSubset); 798 *tileSize = determine_tile_size(*clippedSubset, maxTileSize); 799 return true; 800 } 801 802 // If the image would only produce 4 tiles of the smaller size, don't bother tiling it. 803 const size_t area = imageRect.width() * imageRect.height(); 804 if (area < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { 805 return false; 806 } 807 808 // At this point we know we could do the draw by uploading the entire bitmap 809 // as a texture. However, if the texture would be large compared to the 810 // cache size and we don't require most of it for this draw then tile to 811 // reduce the amount of upload and cache spill. 812 813 // assumption here is that sw bitmap size is a good proxy for its size as 814 // a texture 815 size_t bmpSize = area * sizeof(SkPMColor); // assume 32bit pixels 816 size_t cacheSize; 817 fContext->getResourceCacheLimits(nullptr, &cacheSize); 818 if (bmpSize < cacheSize / 2) { 819 return false; 820 } 821 822 // Figure out how much of the src we will need based on the src rect and clipping. Reject if 823 // tiling memory savings would be < 50%. 824 determine_clipped_src_rect(fRenderTarget, fClip, viewMatrix, imageRect.size(), srcRectPtr, 825 clippedSubset); 826 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile. 827 size_t usedTileBytes = get_tile_count(*clippedSubset, kBmpSmallTileSize) * 828 kBmpSmallTileSize * kBmpSmallTileSize; 829 830 return usedTileBytes < 2 * bmpSize; 831 } 832 833 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, 834 const SkMatrix& viewMatrix, 835 const GrTextureParams& params, 836 const SkRect* srcRectPtr, 837 int maxTileSize, 838 int* tileSize, 839 SkIRect* clippedSrcRect) const { 840 ASSERT_SINGLE_OWNER 841 // if bitmap is explictly texture backed then just use the texture 842 if (bitmap.getTexture()) { 843 return false; 844 } 845 846 return this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix, params, 847 srcRectPtr, maxTileSize, tileSize, clippedSrcRect); 848 } 849 850 bool SkGpuDevice::shouldTileImage(const SkImage* image, const SkRect* srcRectPtr, 851 SkCanvas::SrcRectConstraint constraint, SkFilterQuality quality, 852 const SkMatrix& viewMatrix) const { 853 ASSERT_SINGLE_OWNER 854 // if image is explictly texture backed then just use the texture 855 if (as_IB(image)->peekTexture()) { 856 return false; 857 } 858 859 GrTextureParams params; 860 bool doBicubic; 861 GrTextureParams::FilterMode textureFilterMode = 862 GrSkFilterQualityToGrFilterMode(quality, viewMatrix, SkMatrix::I(), &doBicubic); 863 864 int tileFilterPad; 865 if (doBicubic) { 866 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 867 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { 868 tileFilterPad = 0; 869 } else { 870 tileFilterPad = 1; 871 } 872 params.setFilterMode(textureFilterMode); 873 874 int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad; 875 876 // these are output, which we safely ignore, as we just want to know the predicate 877 int outTileSize; 878 SkIRect outClippedSrcRect; 879 880 return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, params, srcRectPtr, 881 maxTileSize, &outTileSize, &outClippedSrcRect); 882 } 883 884 void SkGpuDevice::drawBitmap(const SkDraw& origDraw, 885 const SkBitmap& bitmap, 886 const SkMatrix& m, 887 const SkPaint& paint) { 888 ASSERT_SINGLE_OWNER 889 CHECK_SHOULD_DRAW(origDraw); 890 SkMatrix viewMatrix; 891 viewMatrix.setConcat(*origDraw.fMatrix, m); 892 if (bitmap.getTexture()) { 893 GrBitmapTextureAdjuster adjuster(&bitmap); 894 // We can use kFast here because we know texture-backed bitmaps don't support extractSubset. 895 this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 896 viewMatrix, fClip, paint); 897 return; 898 } 899 int maxTileSize = fContext->caps()->maxTileSize(); 900 901 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could 902 // draw untiled, then we bypass checking for tiling purely for optimization reasons. 903 bool drawAA = !fRenderTarget->isUnifiedMultisampled() && 904 paint.isAntiAlias() && 905 bitmap.width() <= maxTileSize && 906 bitmap.height() <= maxTileSize; 907 908 bool skipTileCheck = drawAA || paint.getMaskFilter(); 909 910 if (!skipTileCheck) { 911 SkRect srcRect = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 912 int tileSize; 913 SkIRect clippedSrcRect; 914 915 GrTextureParams params; 916 bool doBicubic; 917 GrTextureParams::FilterMode textureFilterMode = 918 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(), 919 &doBicubic); 920 921 int tileFilterPad; 922 923 if (doBicubic) { 924 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 925 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { 926 tileFilterPad = 0; 927 } else { 928 tileFilterPad = 1; 929 } 930 params.setFilterMode(textureFilterMode); 931 932 int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad; 933 if (this->shouldTileBitmap(bitmap, viewMatrix, params, &srcRect, 934 maxTileSizeForFilter, &tileSize, &clippedSrcRect)) { 935 this->drawTiledBitmap(bitmap, viewMatrix, srcRect, clippedSrcRect, params, paint, 936 SkCanvas::kStrict_SrcRectConstraint, tileSize, doBicubic); 937 return; 938 } 939 } 940 GrBitmapTextureMaker maker(fContext, bitmap); 941 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kStrict_SrcRectConstraint, 942 viewMatrix, fClip, paint); 943 } 944 945 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to 946 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner 947 // of 'iRect' for all possible outsets/clamps. 948 static inline void clamped_outset_with_offset(SkIRect* iRect, 949 int outset, 950 SkPoint* offset, 951 const SkIRect& clamp) { 952 iRect->outset(outset, outset); 953 954 int leftClampDelta = clamp.fLeft - iRect->fLeft; 955 if (leftClampDelta > 0) { 956 offset->fX -= outset - leftClampDelta; 957 iRect->fLeft = clamp.fLeft; 958 } else { 959 offset->fX -= outset; 960 } 961 962 int topClampDelta = clamp.fTop - iRect->fTop; 963 if (topClampDelta > 0) { 964 offset->fY -= outset - topClampDelta; 965 iRect->fTop = clamp.fTop; 966 } else { 967 offset->fY -= outset; 968 } 969 970 if (iRect->fRight > clamp.fRight) { 971 iRect->fRight = clamp.fRight; 972 } 973 if (iRect->fBottom > clamp.fBottom) { 974 iRect->fBottom = clamp.fBottom; 975 } 976 } 977 978 // Break 'bitmap' into several tiles to draw it since it has already 979 // been determined to be too large to fit in VRAM 980 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, 981 const SkMatrix& viewMatrix, 982 const SkRect& srcRect, 983 const SkIRect& clippedSrcIRect, 984 const GrTextureParams& params, 985 const SkPaint& origPaint, 986 SkCanvas::SrcRectConstraint constraint, 987 int tileSize, 988 bool bicubic) { 989 ASSERT_SINGLE_OWNER 990 991 // This is the funnel for all paths that draw tiled bitmaps/images. Log histogram entry. 992 SK_HISTOGRAM_BOOLEAN("DrawTiled", true); 993 994 // The following pixel lock is technically redundant, but it is desirable 995 // to lock outside of the tile loop to prevent redecoding the whole image 996 // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that 997 // is larger than the limit of the discardable memory pool. 998 SkAutoLockPixels alp(bitmap); 999 1000 const SkPaint* paint = &origPaint; 1001 SkPaint tempPaint; 1002 if (origPaint.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled()) { 1003 // Drop antialiasing to avoid seams at tile boundaries. 1004 tempPaint = origPaint; 1005 tempPaint.setAntiAlias(false); 1006 paint = &tempPaint; 1007 } 1008 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect); 1009 1010 int nx = bitmap.width() / tileSize; 1011 int ny = bitmap.height() / tileSize; 1012 for (int x = 0; x <= nx; x++) { 1013 for (int y = 0; y <= ny; y++) { 1014 SkRect tileR; 1015 tileR.set(SkIntToScalar(x * tileSize), 1016 SkIntToScalar(y * tileSize), 1017 SkIntToScalar((x + 1) * tileSize), 1018 SkIntToScalar((y + 1) * tileSize)); 1019 1020 if (!SkRect::Intersects(tileR, clippedSrcRect)) { 1021 continue; 1022 } 1023 1024 if (!tileR.intersect(srcRect)) { 1025 continue; 1026 } 1027 1028 SkBitmap tmpB; 1029 SkIRect iTileR; 1030 tileR.roundOut(&iTileR); 1031 SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft), 1032 SkIntToScalar(iTileR.fTop)); 1033 1034 // Adjust the context matrix to draw at the right x,y in device space 1035 SkMatrix viewM = viewMatrix; 1036 SkMatrix tmpM; 1037 tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop); 1038 viewM.preConcat(tmpM); 1039 1040 if (GrTextureParams::kNone_FilterMode != params.filterMode() || bicubic) { 1041 SkIRect iClampRect; 1042 1043 if (SkCanvas::kFast_SrcRectConstraint == constraint) { 1044 // In bleed mode we want to always expand the tile on all edges 1045 // but stay within the bitmap bounds 1046 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1047 } else { 1048 // In texture-domain/clamp mode we only want to expand the 1049 // tile on edges interior to "srcRect" (i.e., we want to 1050 // not bleed across the original clamped edges) 1051 srcRect.roundOut(&iClampRect); 1052 } 1053 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1; 1054 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect); 1055 } 1056 1057 if (bitmap.extractSubset(&tmpB, iTileR)) { 1058 // now offset it to make it "local" to our tmp bitmap 1059 tileR.offset(-offset.fX, -offset.fY); 1060 GrTextureParams paramsTemp = params; 1061 // de-optimized this determination 1062 bool needsTextureDomain = true; 1063 this->internalDrawBitmap(tmpB, 1064 viewM, 1065 tileR, 1066 paramsTemp, 1067 *paint, 1068 constraint, 1069 bicubic, 1070 needsTextureDomain); 1071 } 1072 } 1073 } 1074 } 1075 1076 /* 1077 * This is called by drawBitmap(), which has to handle images that may be too 1078 * large to be represented by a single texture. 1079 * 1080 * internalDrawBitmap assumes that the specified bitmap will fit in a texture 1081 * and that non-texture portion of the GrPaint has already been setup. 1082 */ 1083 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, 1084 const SkMatrix& viewMatrix, 1085 const SkRect& srcRect, 1086 const GrTextureParams& params, 1087 const SkPaint& paint, 1088 SkCanvas::SrcRectConstraint constraint, 1089 bool bicubic, 1090 bool needsTextureDomain) { 1091 // We should have already handled bitmaps larger than the max texture size. 1092 SkASSERT(bitmap.width() <= fContext->caps()->maxTextureSize() && 1093 bitmap.height() <= fContext->caps()->maxTextureSize()); 1094 // Unless the bitmap is inherently texture-backed, we should be respecting the max tile size 1095 // by the time we get here. 1096 SkASSERT(bitmap.getTexture() || 1097 (bitmap.width() <= fContext->caps()->maxTileSize() && 1098 bitmap.height() <= fContext->caps()->maxTileSize())); 1099 1100 GrTexture* texture; 1101 AutoBitmapTexture abt(fContext, bitmap, params, &texture); 1102 if (nullptr == texture) { 1103 return; 1104 } 1105 1106 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() }; 1107 SkRect paintRect; 1108 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width())); 1109 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height())); 1110 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv), 1111 SkScalarMul(srcRect.fTop, hInv), 1112 SkScalarMul(srcRect.fRight, wInv), 1113 SkScalarMul(srcRect.fBottom, hInv)); 1114 1115 SkMatrix texMatrix; 1116 texMatrix.reset(); 1117 if (kAlpha_8_SkColorType == bitmap.colorType() && paint.getShader()) { 1118 // In cases where we are doing an A8 bitmap draw with a shader installed, we cannot use 1119 // local coords with the bitmap draw since it may mess up texture look ups for the shader. 1120 // Thus we need to pass in the transform matrix directly to the texture processor used for 1121 // the bitmap draw. 1122 texMatrix.setScale(wInv, hInv); 1123 } 1124 1125 SkRect textureDomain = SkRect::MakeEmpty(); 1126 1127 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring 1128 // the rest from the SkPaint. 1129 SkAutoTUnref<const GrFragmentProcessor> fp; 1130 1131 if (needsTextureDomain && (SkCanvas::kStrict_SrcRectConstraint == constraint)) { 1132 // Use a constrained texture domain to avoid color bleeding 1133 SkScalar left, top, right, bottom; 1134 if (srcRect.width() > SK_Scalar1) { 1135 SkScalar border = SK_ScalarHalf / texture->width(); 1136 left = paintRect.left() + border; 1137 right = paintRect.right() - border; 1138 } else { 1139 left = right = SkScalarHalf(paintRect.left() + paintRect.right()); 1140 } 1141 if (srcRect.height() > SK_Scalar1) { 1142 SkScalar border = SK_ScalarHalf / texture->height(); 1143 top = paintRect.top() + border; 1144 bottom = paintRect.bottom() - border; 1145 } else { 1146 top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom()); 1147 } 1148 textureDomain.setLTRB(left, top, right, bottom); 1149 if (bicubic) { 1150 fp.reset(GrBicubicEffect::Create(texture, texMatrix, textureDomain)); 1151 } else { 1152 fp.reset(GrTextureDomainEffect::Create(texture, 1153 texMatrix, 1154 textureDomain, 1155 GrTextureDomain::kClamp_Mode, 1156 params.filterMode())); 1157 } 1158 } else if (bicubic) { 1159 SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode()); 1160 SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() }; 1161 fp.reset(GrBicubicEffect::Create(texture, texMatrix, tileModes)); 1162 } else { 1163 fp.reset(GrSimpleTextureEffect::Create(texture, texMatrix, params)); 1164 } 1165 1166 GrPaint grPaint; 1167 if (!SkPaintToGrPaintWithTexture(this->context(), paint, viewMatrix, fp, 1168 kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) { 1169 return; 1170 } 1171 1172 if (kAlpha_8_SkColorType == bitmap.colorType() && paint.getShader()) { 1173 // We don't have local coords in this case and have previously set the transform 1174 // matrices directly on the texture processor. 1175 fDrawContext->drawRect(fClip, grPaint, viewMatrix, dstRect); 1176 } else { 1177 fDrawContext->fillRectToRect(fClip, grPaint, viewMatrix, dstRect, paintRect); 1178 } 1179 } 1180 1181 bool SkGpuDevice::filterTexture(GrContext* context, GrTexture* texture, 1182 int width, int height, 1183 const SkImageFilter* filter, 1184 const SkImageFilter::Context& ctx, 1185 SkBitmap* result, SkIPoint* offset) { 1186 ASSERT_SINGLE_OWNER 1187 SkASSERT(filter); 1188 1189 SkImageFilter::DeviceProxy proxy(this); 1190 1191 if (filter->canFilterImageGPU()) { 1192 SkBitmap bm; 1193 GrWrapTextureInBitmap(texture, width, height, false, &bm); 1194 return filter->filterImageGPUDeprecated(&proxy, bm, ctx, result, offset); 1195 } else { 1196 return false; 1197 } 1198 } 1199 1200 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 1201 int left, int top, const SkPaint& paint) { 1202 ASSERT_SINGLE_OWNER 1203 // drawSprite is defined to be in device coords. 1204 CHECK_SHOULD_DRAW(draw); 1205 1206 SkAutoLockPixels alp(bitmap, !bitmap.getTexture()); 1207 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1208 return; 1209 } 1210 1211 int w = bitmap.width(); 1212 int h = bitmap.height(); 1213 1214 GrTexture* texture; 1215 // draw sprite neither filters nor tiles. 1216 AutoBitmapTexture abt(fContext, bitmap, GrTextureParams::ClampNoFilter(), &texture); 1217 if (!texture) { 1218 return; 1219 } 1220 1221 bool alphaOnly = kAlpha_8_SkColorType == bitmap.colorType(); 1222 1223 SkImageFilter* filter = paint.getImageFilter(); 1224 // This bitmap will own the filtered result as a texture. 1225 SkBitmap filteredBitmap; 1226 1227 if (filter) { 1228 SkIPoint offset = SkIPoint::Make(0, 0); 1229 SkMatrix matrix(*draw.fMatrix); 1230 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top)); 1231 SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-left, -top); 1232 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache()); 1233 // This cache is transient, and is freed (along with all its contained 1234 // textures) when it goes out of scope. 1235 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1236 if (this->filterTexture(fContext, texture, w, h, filter, ctx, &filteredBitmap, 1237 &offset)) { 1238 texture = (GrTexture*) filteredBitmap.getTexture(); 1239 w = filteredBitmap.width(); 1240 h = filteredBitmap.height(); 1241 left += offset.x(); 1242 top += offset.y(); 1243 } else { 1244 return; 1245 } 1246 SkASSERT(!GrPixelConfigIsAlphaOnly(texture->config())); 1247 alphaOnly = false; 1248 } 1249 1250 GrPaint grPaint; 1251 SkAutoTUnref<const GrFragmentProcessor> fp( 1252 GrSimpleTextureEffect::Create(texture, SkMatrix::I())); 1253 if (alphaOnly) { 1254 fp.reset(GrFragmentProcessor::MulOutputByInputUnpremulColor(fp)); 1255 } else { 1256 fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp)); 1257 } 1258 if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) { 1259 return; 1260 } 1261 1262 fDrawContext->fillRectToRect(fClip, 1263 grPaint, 1264 SkMatrix::I(), 1265 SkRect::MakeXYWH(SkIntToScalar(left), 1266 SkIntToScalar(top), 1267 SkIntToScalar(w), 1268 SkIntToScalar(h)), 1269 SkRect::MakeXYWH(0, 1270 0, 1271 SK_Scalar1 * w / texture->width(), 1272 SK_Scalar1 * h / texture->height())); 1273 } 1274 1275 void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1276 const SkRect* src, const SkRect& origDst, 1277 const SkPaint& paint, SkCanvas::SrcRectConstraint constraint) { 1278 ASSERT_SINGLE_OWNER 1279 CHECK_SHOULD_DRAW(draw); 1280 if (bitmap.getTexture()) { 1281 GrBitmapTextureAdjuster adjuster(&bitmap); 1282 this->drawTextureProducer(&adjuster, src, &origDst, constraint, *draw.fMatrix, fClip, 1283 paint); 1284 return; 1285 } 1286 // The src rect is inferred to be the bmp bounds if not provided. Otherwise, the src rect must 1287 // be clipped to the bmp bounds. To determine tiling parameters we need the filter mode which 1288 // in turn requires knowing the src-to-dst mapping. If the src was clipped to the bmp bounds 1289 // then we use the src-to-dst mapping to compute a new clipped dst rect. 1290 const SkRect* dst = &origDst; 1291 const SkRect bmpBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height()); 1292 // Compute matrix from the two rectangles 1293 if (!src) { 1294 src = &bmpBounds; 1295 } 1296 1297 SkMatrix srcToDstMatrix; 1298 if (!srcToDstMatrix.setRectToRect(*src, *dst, SkMatrix::kFill_ScaleToFit)) { 1299 return; 1300 } 1301 SkRect tmpSrc, tmpDst; 1302 if (src != &bmpBounds) { 1303 if (!bmpBounds.contains(*src)) { 1304 tmpSrc = *src; 1305 if (!tmpSrc.intersect(bmpBounds)) { 1306 return; // nothing to draw 1307 } 1308 src = &tmpSrc; 1309 srcToDstMatrix.mapRect(&tmpDst, *src); 1310 dst = &tmpDst; 1311 } 1312 } 1313 1314 int maxTileSize = fContext->caps()->maxTileSize(); 1315 1316 // The tile code path doesn't currently support AA, so if the paint asked for aa and we could 1317 // draw untiled, then we bypass checking for tiling purely for optimization reasons. 1318 bool drawAA = !fRenderTarget->isUnifiedMultisampled() && 1319 paint.isAntiAlias() && 1320 bitmap.width() <= maxTileSize && 1321 bitmap.height() <= maxTileSize; 1322 1323 bool skipTileCheck = drawAA || paint.getMaskFilter(); 1324 1325 if (!skipTileCheck) { 1326 int tileSize; 1327 SkIRect clippedSrcRect; 1328 1329 GrTextureParams params; 1330 bool doBicubic; 1331 GrTextureParams::FilterMode textureFilterMode = 1332 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, srcToDstMatrix, 1333 &doBicubic); 1334 1335 int tileFilterPad; 1336 1337 if (doBicubic) { 1338 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 1339 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { 1340 tileFilterPad = 0; 1341 } else { 1342 tileFilterPad = 1; 1343 } 1344 params.setFilterMode(textureFilterMode); 1345 1346 int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad; 1347 // Fold the dst rect into the view matrix. This is only OK because we don't get here if 1348 // we have a mask filter. 1349 SkMatrix viewMatrix = *draw.fMatrix; 1350 viewMatrix.preTranslate(dst->fLeft, dst->fTop); 1351 viewMatrix.preScale(dst->width()/src->width(), dst->height()/src->height()); 1352 if (this->shouldTileBitmap(bitmap, viewMatrix, params, src, 1353 maxTileSizeForFilter, &tileSize, &clippedSrcRect)) { 1354 this->drawTiledBitmap(bitmap, viewMatrix, *src, clippedSrcRect, params, paint, 1355 constraint, tileSize, doBicubic); 1356 return; 1357 } 1358 } 1359 GrBitmapTextureMaker maker(fContext, bitmap); 1360 this->drawTextureProducer(&maker, src, dst, constraint, *draw.fMatrix, fClip, paint); 1361 } 1362 1363 void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 1364 int x, int y, const SkPaint& paint) { 1365 ASSERT_SINGLE_OWNER 1366 // clear of the source device must occur before CHECK_SHOULD_DRAW 1367 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawDevice", fContext); 1368 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device); 1369 1370 // drawDevice is defined to be in device coords. 1371 CHECK_SHOULD_DRAW(draw); 1372 1373 GrRenderTarget* devRT = dev->accessRenderTarget(); 1374 GrTexture* devTex; 1375 if (nullptr == (devTex = devRT->asTexture())) { 1376 return; 1377 } 1378 1379 const SkImageInfo ii = dev->imageInfo(); 1380 int w = ii.width(); 1381 int h = ii.height(); 1382 1383 SkImageFilter* filter = paint.getImageFilter(); 1384 // This bitmap will own the filtered result as a texture. 1385 SkBitmap filteredBitmap; 1386 1387 if (filter) { 1388 SkIPoint offset = SkIPoint::Make(0, 0); 1389 SkMatrix matrix(*draw.fMatrix); 1390 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1391 SkIRect clipBounds = draw.fClip->getBounds().makeOffset(-x, -y); 1392 // This cache is transient, and is freed (along with all its contained 1393 // textures) when it goes out of scope. 1394 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache()); 1395 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1396 if (this->filterTexture(fContext, devTex, device->width(), device->height(), 1397 filter, ctx, &filteredBitmap, &offset)) { 1398 devTex = filteredBitmap.getTexture(); 1399 w = filteredBitmap.width(); 1400 h = filteredBitmap.height(); 1401 x += offset.fX; 1402 y += offset.fY; 1403 } else { 1404 return; 1405 } 1406 } 1407 1408 GrPaint grPaint; 1409 SkAutoTUnref<const GrFragmentProcessor> fp( 1410 GrSimpleTextureEffect::Create(devTex, SkMatrix::I())); 1411 if (GrPixelConfigIsAlphaOnly(devTex->config())) { 1412 // Can this happen? 1413 fp.reset(GrFragmentProcessor::MulOutputByInputUnpremulColor(fp)); 1414 } else { 1415 fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp)); 1416 } 1417 1418 if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) { 1419 return; 1420 } 1421 1422 SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x), 1423 SkIntToScalar(y), 1424 SkIntToScalar(w), 1425 SkIntToScalar(h)); 1426 1427 // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate 1428 // scratch texture). 1429 SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(), 1430 SK_Scalar1 * h / devTex->height()); 1431 1432 fDrawContext->fillRectToRect(fClip, grPaint, SkMatrix::I(), dstRect, srcRect); 1433 } 1434 1435 bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) { 1436 ASSERT_SINGLE_OWNER 1437 return filter->canFilterImageGPU(); 1438 } 1439 1440 bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, 1441 const SkImageFilter::Context& ctx, 1442 SkBitmap* result, SkIPoint* offset) { 1443 ASSERT_SINGLE_OWNER 1444 // want explicitly our impl, so guard against a subclass of us overriding it 1445 if (!this->SkGpuDevice::canHandleImageFilter(filter)) { 1446 return false; 1447 } 1448 1449 SkAutoLockPixels alp(src, !src.getTexture()); 1450 if (!src.getTexture() && !src.readyToDraw()) { 1451 return false; 1452 } 1453 1454 GrTexture* texture; 1455 // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup 1456 // must be pushed upstack. 1457 AutoBitmapTexture abt(fContext, src, GrTextureParams::ClampNoFilter(), &texture); 1458 if (!texture) { 1459 return false; 1460 } 1461 1462 return this->filterTexture(fContext, texture, src.width(), src.height(), 1463 filter, ctx, result, offset); 1464 } 1465 1466 void SkGpuDevice::drawImage(const SkDraw& draw, const SkImage* image, SkScalar x, SkScalar y, 1467 const SkPaint& paint) { 1468 ASSERT_SINGLE_OWNER 1469 SkMatrix viewMatrix = *draw.fMatrix; 1470 viewMatrix.preTranslate(x, y); 1471 if (as_IB(image)->peekTexture()) { 1472 CHECK_SHOULD_DRAW(draw); 1473 GrImageTextureAdjuster adjuster(as_IB(image)); 1474 this->drawTextureProducer(&adjuster, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 1475 viewMatrix, fClip, paint); 1476 return; 1477 } else { 1478 SkBitmap bm; 1479 if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint, 1480 paint.getFilterQuality(), *draw.fMatrix)) { 1481 // only support tiling as bitmap at the moment, so force raster-version 1482 if (!as_IB(image)->getROPixels(&bm)) { 1483 return; 1484 } 1485 this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); 1486 } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { 1487 CHECK_SHOULD_DRAW(draw); 1488 GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); 1489 this->drawTextureProducer(&maker, nullptr, nullptr, SkCanvas::kFast_SrcRectConstraint, 1490 viewMatrix, fClip, paint); 1491 } else if (as_IB(image)->getROPixels(&bm)) { 1492 this->drawBitmap(draw, bm, SkMatrix::MakeTrans(x, y), paint); 1493 } 1494 } 1495 } 1496 1497 void SkGpuDevice::drawImageRect(const SkDraw& draw, const SkImage* image, const SkRect* src, 1498 const SkRect& dst, const SkPaint& paint, 1499 SkCanvas::SrcRectConstraint constraint) { 1500 ASSERT_SINGLE_OWNER 1501 if (as_IB(image)->peekTexture()) { 1502 CHECK_SHOULD_DRAW(draw); 1503 GrImageTextureAdjuster adjuster(as_IB(image)); 1504 this->drawTextureProducer(&adjuster, src, &dst, constraint, *draw.fMatrix, fClip, paint); 1505 return; 1506 } 1507 SkBitmap bm; 1508 SkMatrix totalMatrix = *draw.fMatrix; 1509 totalMatrix.preScale(dst.width() / (src ? src->width() : image->width()), 1510 dst.height() / (src ? src->height() : image->height())); 1511 if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), totalMatrix)) { 1512 // only support tiling as bitmap at the moment, so force raster-version 1513 if (!as_IB(image)->getROPixels(&bm)) { 1514 return; 1515 } 1516 this->drawBitmapRect(draw, bm, src, dst, paint, constraint); 1517 } else if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { 1518 CHECK_SHOULD_DRAW(draw); 1519 GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); 1520 this->drawTextureProducer(&maker, src, &dst, constraint, *draw.fMatrix, fClip, paint); 1521 } else if (as_IB(image)->getROPixels(&bm)) { 1522 this->drawBitmapRect(draw, bm, src, dst, paint, constraint); 1523 } 1524 } 1525 1526 void SkGpuDevice::drawProducerNine(const SkDraw& draw, GrTextureProducer* producer, 1527 const SkIRect& center, const SkRect& dst, const SkPaint& paint) { 1528 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerNine", fContext); 1529 1530 CHECK_FOR_ANNOTATION(paint); 1531 CHECK_SHOULD_DRAW(draw); 1532 1533 bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() || 1534 fRenderTarget->isUnifiedMultisampled(); 1535 bool doBicubic; 1536 GrTextureParams::FilterMode textureFilterMode = 1537 GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), *draw.fMatrix, SkMatrix::I(), 1538 &doBicubic); 1539 if (useFallback || doBicubic || GrTextureParams::kNone_FilterMode != textureFilterMode) { 1540 SkNinePatchIter iter(producer->width(), producer->height(), center, dst); 1541 1542 SkRect srcR, dstR; 1543 while (iter.next(&srcR, &dstR)) { 1544 this->drawTextureProducer(producer, &srcR, &dstR, SkCanvas::kStrict_SrcRectConstraint, 1545 *draw.fMatrix, fClip, paint); 1546 } 1547 return; 1548 } 1549 1550 static const GrTextureParams::FilterMode kMode = GrTextureParams::kNone_FilterMode; 1551 SkAutoTUnref<const GrFragmentProcessor> fp( 1552 producer->createFragmentProcessor(SkMatrix::I(), 1553 SkRect::MakeIWH(producer->width(), producer->height()), 1554 GrTextureProducer::kNo_FilterConstraint, true, 1555 &kMode)); 1556 GrPaint grPaint; 1557 if (!SkPaintToGrPaintWithTexture(this->context(), paint, *draw.fMatrix, fp, 1558 producer->isAlphaOnly(), &grPaint)) { 1559 return; 1560 } 1561 1562 fDrawContext->drawImageNine(fClip, grPaint, *draw.fMatrix, producer->width(), 1563 producer->height(), center, dst); 1564 } 1565 1566 void SkGpuDevice::drawImageNine(const SkDraw& draw, const SkImage* image, 1567 const SkIRect& center, const SkRect& dst, const SkPaint& paint) { 1568 ASSERT_SINGLE_OWNER 1569 if (as_IB(image)->peekTexture()) { 1570 GrImageTextureAdjuster adjuster(as_IB(image)); 1571 this->drawProducerNine(draw, &adjuster, center, dst, paint); 1572 } else { 1573 SkBitmap bm; 1574 if (SkImageCacherator* cacher = as_IB(image)->peekCacherator()) { 1575 GrImageTextureMaker maker(fContext, cacher, image, SkImage::kAllow_CachingHint); 1576 this->drawProducerNine(draw, &maker, center, dst, paint); 1577 } else if (as_IB(image)->getROPixels(&bm)) { 1578 this->drawBitmapNine(draw, bm, center, dst, paint); 1579 } 1580 } 1581 } 1582 1583 void SkGpuDevice::drawBitmapNine(const SkDraw& draw, const SkBitmap& bitmap, const SkIRect& center, 1584 const SkRect& dst, const SkPaint& paint) { 1585 ASSERT_SINGLE_OWNER 1586 if (bitmap.getTexture()) { 1587 GrBitmapTextureAdjuster adjuster(&bitmap); 1588 this->drawProducerNine(draw, &adjuster, center, dst, paint); 1589 } else { 1590 GrBitmapTextureMaker maker(fContext, bitmap); 1591 this->drawProducerNine(draw, &maker, center, dst, paint); 1592 } 1593 } 1594 1595 /////////////////////////////////////////////////////////////////////////////// 1596 1597 // must be in SkCanvas::VertexMode order 1598 static const GrPrimitiveType gVertexMode2PrimitiveType[] = { 1599 kTriangles_GrPrimitiveType, 1600 kTriangleStrip_GrPrimitiveType, 1601 kTriangleFan_GrPrimitiveType, 1602 }; 1603 1604 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 1605 int vertexCount, const SkPoint vertices[], 1606 const SkPoint texs[], const SkColor colors[], 1607 SkXfermode* xmode, 1608 const uint16_t indices[], int indexCount, 1609 const SkPaint& paint) { 1610 ASSERT_SINGLE_OWNER 1611 CHECK_SHOULD_DRAW(draw); 1612 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawVertices", fContext); 1613 1614 // If both textures and vertex-colors are nullptr, strokes hairlines with the paint's color. 1615 if ((nullptr == texs || nullptr == paint.getShader()) && nullptr == colors) { 1616 1617 texs = nullptr; 1618 1619 SkPaint copy(paint); 1620 copy.setStyle(SkPaint::kStroke_Style); 1621 copy.setStrokeWidth(0); 1622 1623 GrPaint grPaint; 1624 // we ignore the shader if texs is null. 1625 if (!SkPaintToGrPaintNoShader(this->context(), copy, &grPaint)) { 1626 return; 1627 } 1628 1629 int triangleCount = 0; 1630 int n = (nullptr == indices) ? vertexCount : indexCount; 1631 switch (vmode) { 1632 case SkCanvas::kTriangles_VertexMode: 1633 triangleCount = n / 3; 1634 break; 1635 case SkCanvas::kTriangleStrip_VertexMode: 1636 case SkCanvas::kTriangleFan_VertexMode: 1637 triangleCount = n - 2; 1638 break; 1639 } 1640 1641 VertState state(vertexCount, indices, indexCount); 1642 VertState::Proc vertProc = state.chooseProc(vmode); 1643 1644 //number of indices for lines per triangle with kLines 1645 indexCount = triangleCount * 6; 1646 1647 SkAutoTDeleteArray<uint16_t> lineIndices(new uint16_t[indexCount]); 1648 int i = 0; 1649 while (vertProc(&state)) { 1650 lineIndices[i] = state.f0; 1651 lineIndices[i + 1] = state.f1; 1652 lineIndices[i + 2] = state.f1; 1653 lineIndices[i + 3] = state.f2; 1654 lineIndices[i + 4] = state.f2; 1655 lineIndices[i + 5] = state.f0; 1656 i += 6; 1657 } 1658 fDrawContext->drawVertices(fClip, 1659 grPaint, 1660 *draw.fMatrix, 1661 kLines_GrPrimitiveType, 1662 vertexCount, 1663 vertices, 1664 texs, 1665 colors, 1666 lineIndices.get(), 1667 indexCount); 1668 return; 1669 } 1670 1671 GrPrimitiveType primType = gVertexMode2PrimitiveType[vmode]; 1672 1673 SkAutoSTMalloc<128, GrColor> convertedColors(0); 1674 if (colors) { 1675 // need to convert byte order and from non-PM to PM. TODO: Keep unpremul until after 1676 // interpolation. 1677 convertedColors.reset(vertexCount); 1678 for (int i = 0; i < vertexCount; ++i) { 1679 convertedColors[i] = SkColorToPremulGrColor(colors[i]); 1680 } 1681 colors = convertedColors.get(); 1682 } 1683 GrPaint grPaint; 1684 if (texs && paint.getShader()) { 1685 if (colors) { 1686 // When there are texs and colors the shader and colors are combined using xmode. A null 1687 // xmode is defined to mean modulate. 1688 SkXfermode::Mode colorMode; 1689 if (xmode) { 1690 if (!xmode->asMode(&colorMode)) { 1691 return; 1692 } 1693 } else { 1694 colorMode = SkXfermode::kModulate_Mode; 1695 } 1696 if (!SkPaintToGrPaintWithXfermode(this->context(), paint, *draw.fMatrix, colorMode, 1697 false, &grPaint)) { 1698 return; 1699 } 1700 } else { 1701 // We have a shader, but no colors to blend it against. 1702 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 1703 return; 1704 } 1705 } 1706 } else { 1707 if (colors) { 1708 // We have colors, but either have no shader or no texture coords (which implies that 1709 // we should ignore the shader). 1710 if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), paint, &grPaint)) { 1711 return; 1712 } 1713 } else { 1714 // No colors and no shaders. Just draw with the paint color. 1715 if (!SkPaintToGrPaintNoShader(this->context(), paint, &grPaint)) { 1716 return; 1717 } 1718 } 1719 } 1720 1721 fDrawContext->drawVertices(fClip, 1722 grPaint, 1723 *draw.fMatrix, 1724 primType, 1725 vertexCount, 1726 vertices, 1727 texs, 1728 colors, 1729 indices, 1730 indexCount); 1731 } 1732 1733 /////////////////////////////////////////////////////////////////////////////// 1734 1735 void SkGpuDevice::drawAtlas(const SkDraw& draw, const SkImage* atlas, const SkRSXform xform[], 1736 const SkRect texRect[], const SkColor colors[], int count, 1737 SkXfermode::Mode mode, const SkPaint& paint) { 1738 ASSERT_SINGLE_OWNER 1739 if (paint.isAntiAlias()) { 1740 this->INHERITED::drawAtlas(draw, atlas, xform, texRect, colors, count, mode, paint); 1741 return; 1742 } 1743 1744 CHECK_SHOULD_DRAW(draw); 1745 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); 1746 1747 SkPaint p(paint); 1748 p.setShader(atlas->newShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); 1749 1750 GrPaint grPaint; 1751 if (colors) { 1752 if (!SkPaintToGrPaintWithXfermode(this->context(), p, *draw.fMatrix, mode, true, 1753 &grPaint)) { 1754 return; 1755 } 1756 } else { 1757 if (!SkPaintToGrPaint(this->context(), p, *draw.fMatrix, &grPaint)) { 1758 return; 1759 } 1760 } 1761 1762 SkDEBUGCODE(this->validate();) 1763 fDrawContext->drawAtlas(fClip, grPaint, *draw.fMatrix, count, xform, texRect, colors); 1764 } 1765 1766 /////////////////////////////////////////////////////////////////////////////// 1767 1768 void SkGpuDevice::drawText(const SkDraw& draw, const void* text, 1769 size_t byteLength, SkScalar x, SkScalar y, 1770 const SkPaint& paint) { 1771 ASSERT_SINGLE_OWNER 1772 CHECK_SHOULD_DRAW(draw); 1773 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext); 1774 1775 GrPaint grPaint; 1776 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 1777 return; 1778 } 1779 1780 SkDEBUGCODE(this->validate();) 1781 1782 fDrawContext->drawText(fClip, grPaint, paint, *draw.fMatrix, 1783 (const char *)text, byteLength, x, y, draw.fClip->getBounds()); 1784 } 1785 1786 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, size_t byteLength, 1787 const SkScalar pos[], int scalarsPerPos, 1788 const SkPoint& offset, const SkPaint& paint) { 1789 ASSERT_SINGLE_OWNER 1790 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPosText", fContext); 1791 CHECK_SHOULD_DRAW(draw); 1792 1793 GrPaint grPaint; 1794 if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) { 1795 return; 1796 } 1797 1798 SkDEBUGCODE(this->validate();) 1799 1800 fDrawContext->drawPosText(fClip, grPaint, paint, *draw.fMatrix, 1801 (const char *)text, byteLength, pos, scalarsPerPos, offset, 1802 draw.fClip->getBounds()); 1803 } 1804 1805 void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkScalar x, SkScalar y, 1806 const SkPaint& paint, SkDrawFilter* drawFilter) { 1807 ASSERT_SINGLE_OWNER 1808 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawTextBlob", fContext); 1809 CHECK_SHOULD_DRAW(draw); 1810 1811 SkDEBUGCODE(this->validate();) 1812 1813 fDrawContext->drawTextBlob(fClip, paint, *draw.fMatrix, 1814 blob, x, y, drawFilter, draw.fClip->getBounds()); 1815 } 1816 1817 /////////////////////////////////////////////////////////////////////////////// 1818 1819 bool SkGpuDevice::onShouldDisableLCD(const SkPaint& paint) const { 1820 return GrTextUtils::ShouldDisableLCD(paint); 1821 } 1822 1823 void SkGpuDevice::flush() { 1824 ASSERT_SINGLE_OWNER 1825 1826 fRenderTarget->prepareForExternalIO(); 1827 } 1828 1829 /////////////////////////////////////////////////////////////////////////////// 1830 1831 SkBaseDevice* SkGpuDevice::onCreateDevice(const CreateInfo& cinfo, const SkPaint*) { 1832 ASSERT_SINGLE_OWNER 1833 GrSurfaceDesc desc; 1834 desc.fConfig = fRenderTarget->config(); 1835 desc.fFlags = kRenderTarget_GrSurfaceFlag; 1836 desc.fWidth = cinfo.fInfo.width(); 1837 desc.fHeight = cinfo.fInfo.height(); 1838 desc.fSampleCnt = fRenderTarget->desc().fSampleCnt; 1839 1840 SkAutoTUnref<GrTexture> texture; 1841 // Skia's convention is to only clear a device if it is non-opaque. 1842 InitContents init = cinfo.fInfo.isOpaque() ? kUninit_InitContents : kClear_InitContents; 1843 1844 // layers are never draw in repeat modes, so we can request an approx 1845 // match and ignore any padding. 1846 if (kNever_TileUsage == cinfo.fTileUsage) { 1847 texture.reset(fContext->textureProvider()->createApproxTexture(desc)); 1848 } else { 1849 texture.reset(fContext->textureProvider()->createTexture(desc, SkBudgeted::kYes)); 1850 } 1851 1852 if (texture) { 1853 SkSurfaceProps props(this->surfaceProps().flags(), cinfo.fPixelGeometry); 1854 return SkGpuDevice::Create( 1855 texture->asRenderTarget(), cinfo.fInfo.width(), cinfo.fInfo.height(), &props, init); 1856 } else { 1857 SkErrorInternals::SetError( kInternalError_SkError, 1858 "---- failed to create gpu device texture [%d %d]\n", 1859 cinfo.fInfo.width(), cinfo.fInfo.height()); 1860 return nullptr; 1861 } 1862 } 1863 1864 SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1865 ASSERT_SINGLE_OWNER 1866 // TODO: Change the signature of newSurface to take a budgeted parameter. 1867 static const SkBudgeted kBudgeted = SkBudgeted::kNo; 1868 return SkSurface::NewRenderTarget(fContext, kBudgeted, info, fRenderTarget->desc().fSampleCnt, 1869 &props); 1870 } 1871 1872 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture, 1873 const SkMatrix* matrix, const SkPaint* paint) { 1874 ASSERT_SINGLE_OWNER 1875 #ifndef SK_IGNORE_GPU_LAYER_HOISTING 1876 // todo: should handle this natively 1877 if (paint) { 1878 return false; 1879 } 1880 1881 const SkBigPicture::AccelData* data = nullptr; 1882 if (const SkBigPicture* bp = mainPicture->asSkBigPicture()) { 1883 data = bp->accelData(); 1884 } 1885 if (!data) { 1886 return false; 1887 } 1888 1889 const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data); 1890 if (0 == gpuData->numBlocks()) { 1891 return false; 1892 } 1893 1894 SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled; 1895 1896 SkIRect iBounds; 1897 if (!mainCanvas->getClipDeviceBounds(&iBounds)) { 1898 return false; 1899 } 1900 1901 SkRect clipBounds = SkRect::Make(iBounds); 1902 1903 SkMatrix initialMatrix = mainCanvas->getTotalMatrix(); 1904 1905 GrLayerHoister::Begin(fContext); 1906 1907 GrLayerHoister::FindLayersToAtlas(fContext, mainPicture, 1908 initialMatrix, 1909 clipBounds, 1910 &atlasedNeedRendering, &atlasedRecycled, 1911 fRenderTarget->numColorSamples()); 1912 1913 GrLayerHoister::DrawLayersToAtlas(fContext, atlasedNeedRendering); 1914 1915 SkTDArray<GrHoistedLayer> needRendering, recycled; 1916 1917 SkAutoCanvasMatrixPaint acmp(mainCanvas, matrix, paint, mainPicture->cullRect()); 1918 1919 GrLayerHoister::FindLayersToHoist(fContext, mainPicture, 1920 initialMatrix, 1921 clipBounds, 1922 &needRendering, &recycled, 1923 fRenderTarget->numColorSamples()); 1924 1925 GrLayerHoister::DrawLayers(fContext, needRendering); 1926 1927 // Render the entire picture using new layers 1928 GrRecordReplaceDraw(mainPicture, mainCanvas, fContext->getLayerCache(), 1929 initialMatrix, nullptr); 1930 1931 GrLayerHoister::UnlockLayers(fContext, needRendering); 1932 GrLayerHoister::UnlockLayers(fContext, recycled); 1933 GrLayerHoister::UnlockLayers(fContext, atlasedNeedRendering); 1934 GrLayerHoister::UnlockLayers(fContext, atlasedRecycled); 1935 GrLayerHoister::End(fContext); 1936 1937 return true; 1938 #else 1939 return false; 1940 #endif 1941 } 1942 1943 SkImageFilter::Cache* SkGpuDevice::NewImageFilterCache() { 1944 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); 1945 } 1946 1947 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { 1948 ASSERT_SINGLE_OWNER 1949 // We always return a transient cache, so it is freed after each 1950 // filter traversal. 1951 return SkGpuDevice::NewImageFilterCache(); 1952 } 1953 1954 #endif 1955