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 "effects/GrBicubicEffect.h" 11 #include "effects/GrDashingEffect.h" 12 #include "effects/GrTextureDomain.h" 13 #include "effects/GrSimpleTextureEffect.h" 14 15 #include "GrContext.h" 16 #include "GrBitmapTextContext.h" 17 #include "GrDistanceFieldTextContext.h" 18 #include "GrLayerCache.h" 19 #include "GrLayerHoister.h" 20 #include "GrPictureUtils.h" 21 #include "GrRecordReplaceDraw.h" 22 #include "GrStrokeInfo.h" 23 #include "GrTracing.h" 24 25 #include "SkGrTexturePixelRef.h" 26 27 #include "SkDeviceImageFilterProxy.h" 28 #include "SkDrawProcs.h" 29 #include "SkGlyphCache.h" 30 #include "SkImageFilter.h" 31 #include "SkMaskFilter.h" 32 #include "SkPathEffect.h" 33 #include "SkPicture.h" 34 #include "SkPictureData.h" 35 #include "SkRecord.h" 36 #include "SkRRect.h" 37 #include "SkStroke.h" 38 #include "SkSurface.h" 39 #include "SkTLazy.h" 40 #include "SkUtils.h" 41 #include "SkVertState.h" 42 #include "SkXfermode.h" 43 #include "SkErrorInternals.h" 44 45 enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 }; 46 47 #define CACHE_COMPATIBLE_DEVICE_TEXTURES 1 48 49 #if 0 50 extern bool (*gShouldDrawProc)(); 51 #define CHECK_SHOULD_DRAW(draw, forceI) \ 52 do { \ 53 if (gShouldDrawProc && !gShouldDrawProc()) return; \ 54 this->prepareDraw(draw, forceI); \ 55 } while (0) 56 #else 57 #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI) 58 #endif 59 60 // This constant represents the screen alignment criterion in texels for 61 // requiring texture domain clamping to prevent color bleeding when drawing 62 // a sub region of a larger source image. 63 #define COLOR_BLEED_TOLERANCE 0.001f 64 65 #define DO_DEFERRED_CLEAR() \ 66 do { \ 67 if (fNeedClear) { \ 68 this->clear(SK_ColorTRANSPARENT); \ 69 } \ 70 } while (false) \ 71 72 /////////////////////////////////////////////////////////////////////////////// 73 74 #define CHECK_FOR_ANNOTATION(paint) \ 75 do { if (paint.getAnnotation()) { return; } } while (0) 76 77 /////////////////////////////////////////////////////////////////////////////// 78 79 80 class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable { 81 public: 82 SkAutoCachedTexture() 83 : fDevice(NULL) 84 , fTexture(NULL) { 85 } 86 87 SkAutoCachedTexture(SkGpuDevice* device, 88 const SkBitmap& bitmap, 89 const GrTextureParams* params, 90 GrTexture** texture) 91 : fDevice(NULL) 92 , fTexture(NULL) { 93 SkASSERT(texture); 94 *texture = this->set(device, bitmap, params); 95 } 96 97 ~SkAutoCachedTexture() { 98 if (fTexture) { 99 GrUnlockAndUnrefCachedBitmapTexture(fTexture); 100 } 101 } 102 103 GrTexture* set(SkGpuDevice* device, 104 const SkBitmap& bitmap, 105 const GrTextureParams* params) { 106 if (fTexture) { 107 GrUnlockAndUnrefCachedBitmapTexture(fTexture); 108 fTexture = NULL; 109 } 110 fDevice = device; 111 GrTexture* result = (GrTexture*)bitmap.getTexture(); 112 if (NULL == result) { 113 // Cannot return the native texture so look it up in our cache 114 fTexture = GrLockAndRefCachedBitmapTexture(device->context(), bitmap, params); 115 result = fTexture; 116 } 117 return result; 118 } 119 120 private: 121 SkGpuDevice* fDevice; 122 GrTexture* fTexture; 123 }; 124 125 /////////////////////////////////////////////////////////////////////////////// 126 127 struct GrSkDrawProcs : public SkDrawProcs { 128 public: 129 GrContext* fContext; 130 GrTextContext* fTextContext; 131 GrFontScaler* fFontScaler; // cached in the skia glyphcache 132 }; 133 134 /////////////////////////////////////////////////////////////////////////////// 135 136 SkGpuDevice* SkGpuDevice::Create(GrSurface* surface, const SkSurfaceProps& props, unsigned flags) { 137 SkASSERT(surface); 138 if (NULL == surface->asRenderTarget() || surface->wasDestroyed()) { 139 return NULL; 140 } 141 return SkNEW_ARGS(SkGpuDevice, (surface, props, flags)); 142 } 143 144 SkGpuDevice::SkGpuDevice(GrSurface* surface, const SkSurfaceProps& props, unsigned flags) { 145 146 fDrawProcs = NULL; 147 148 fContext = SkRef(surface->getContext()); 149 150 fNeedClear = flags & kNeedClear_Flag; 151 152 fRenderTarget = SkRef(surface->asRenderTarget()); 153 154 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, 155 (surface->info(), surface, SkToBool(flags & kCached_Flag))); 156 fLegacyBitmap.setInfo(surface->info()); 157 fLegacyBitmap.setPixelRef(pr)->unref(); 158 159 this->setPixelGeometry(props.pixelGeometry()); 160 161 bool useDFFonts = !!(flags & kDFFonts_Flag); 162 fMainTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProperties(), useDFFonts); 163 fFallbackTextContext = SkNEW_ARGS(GrBitmapTextContext, (fContext, this->getLeakyProperties())); 164 } 165 166 SkGpuDevice* SkGpuDevice::Create(GrContext* context, const SkImageInfo& origInfo, 167 const SkSurfaceProps& props, int sampleCount) { 168 if (kUnknown_SkColorType == origInfo.colorType() || 169 origInfo.width() < 0 || origInfo.height() < 0) { 170 return NULL; 171 } 172 173 SkColorType ct = origInfo.colorType(); 174 SkAlphaType at = origInfo.alphaType(); 175 // TODO: perhaps we can loosen this check now that colortype is more detailed 176 // e.g. can we support both RGBA and BGRA here? 177 if (kRGB_565_SkColorType == ct) { 178 at = kOpaque_SkAlphaType; // force this setting 179 } else { 180 ct = kN32_SkColorType; 181 if (kOpaque_SkAlphaType != at) { 182 at = kPremul_SkAlphaType; // force this setting 183 } 184 } 185 const SkImageInfo info = SkImageInfo::Make(origInfo.width(), origInfo.height(), ct, at); 186 187 GrTextureDesc desc; 188 desc.fFlags = kRenderTarget_GrTextureFlagBit; 189 desc.fWidth = info.width(); 190 desc.fHeight = info.height(); 191 desc.fConfig = SkImageInfo2GrPixelConfig(info); 192 desc.fSampleCnt = sampleCount; 193 194 SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0)); 195 if (!texture.get()) { 196 return NULL; 197 } 198 199 return SkNEW_ARGS(SkGpuDevice, (texture.get(), props)); 200 } 201 202 SkGpuDevice::~SkGpuDevice() { 203 if (fDrawProcs) { 204 delete fDrawProcs; 205 } 206 207 delete fMainTextContext; 208 delete fFallbackTextContext; 209 210 // The GrContext takes a ref on the target. We don't want to cause the render 211 // target to be unnecessarily kept alive. 212 if (fContext->getRenderTarget() == fRenderTarget) { 213 fContext->setRenderTarget(NULL); 214 } 215 216 if (fContext->getClip() == &fClipData) { 217 fContext->setClip(NULL); 218 } 219 220 fRenderTarget->unref(); 221 fContext->unref(); 222 } 223 224 /////////////////////////////////////////////////////////////////////////////// 225 226 bool SkGpuDevice::onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 227 int x, int y) { 228 DO_DEFERRED_CLEAR(); 229 230 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels 231 GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo); 232 if (kUnknown_GrPixelConfig == config) { 233 return false; 234 } 235 236 uint32_t flags = 0; 237 if (kUnpremul_SkAlphaType == dstInfo.alphaType()) { 238 flags = GrContext::kUnpremul_PixelOpsFlag; 239 } 240 return fContext->readRenderTargetPixels(fRenderTarget, x, y, dstInfo.width(), dstInfo.height(), 241 config, dstPixels, dstRowBytes, flags); 242 } 243 244 bool SkGpuDevice::onWritePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, 245 int x, int y) { 246 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels 247 GrPixelConfig config = SkImageInfo2GrPixelConfig(info); 248 if (kUnknown_GrPixelConfig == config) { 249 return false; 250 } 251 uint32_t flags = 0; 252 if (kUnpremul_SkAlphaType == info.alphaType()) { 253 flags = GrContext::kUnpremul_PixelOpsFlag; 254 } 255 fRenderTarget->writePixels(x, y, info.width(), info.height(), config, pixels, rowBytes, flags); 256 257 // need to bump our genID for compatibility with clients that "know" we have a bitmap 258 fLegacyBitmap.notifyPixelsChanged(); 259 260 return true; 261 } 262 263 const SkBitmap& SkGpuDevice::onAccessBitmap() { 264 DO_DEFERRED_CLEAR(); 265 return fLegacyBitmap; 266 } 267 268 void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) { 269 INHERITED::onAttachToCanvas(canvas); 270 271 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 272 fClipData.fClipStack = canvas->getClipStack(); 273 } 274 275 void SkGpuDevice::onDetachFromCanvas() { 276 INHERITED::onDetachFromCanvas(); 277 fClipData.fClipStack = NULL; 278 } 279 280 // call this every draw call, to ensure that the context reflects our state, 281 // and not the state from some other canvas/device 282 void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) { 283 SkASSERT(fClipData.fClipStack); 284 285 fContext->setRenderTarget(fRenderTarget); 286 287 SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack); 288 289 if (forceIdentity) { 290 fContext->setIdentityMatrix(); 291 } else { 292 fContext->setMatrix(*draw.fMatrix); 293 } 294 fClipData.fOrigin = this->getOrigin(); 295 296 fContext->setClip(&fClipData); 297 298 DO_DEFERRED_CLEAR(); 299 } 300 301 GrRenderTarget* SkGpuDevice::accessRenderTarget() { 302 DO_DEFERRED_CLEAR(); 303 return fRenderTarget; 304 } 305 306 /////////////////////////////////////////////////////////////////////////////// 307 308 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch); 309 SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch); 310 SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch); 311 SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch); 312 SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4, 313 shader_type_mismatch); 314 SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5, 315 shader_type_mismatch); 316 SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch); 317 SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch); 318 319 /////////////////////////////////////////////////////////////////////////////// 320 321 void SkGpuDevice::clear(SkColor color) { 322 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::clear", fContext); 323 SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); 324 fContext->clear(&rect, SkColor2GrColor(color), true, fRenderTarget); 325 fNeedClear = false; 326 } 327 328 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 329 CHECK_SHOULD_DRAW(draw, false); 330 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPaint", fContext); 331 332 GrPaint grPaint; 333 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 334 335 fContext->drawPaint(grPaint); 336 } 337 338 // must be in SkCanvas::PointMode order 339 static const GrPrimitiveType gPointMode2PrimtiveType[] = { 340 kPoints_GrPrimitiveType, 341 kLines_GrPrimitiveType, 342 kLineStrip_GrPrimitiveType 343 }; 344 345 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 346 size_t count, const SkPoint pts[], const SkPaint& paint) { 347 CHECK_FOR_ANNOTATION(paint); 348 CHECK_SHOULD_DRAW(draw, false); 349 350 SkScalar width = paint.getStrokeWidth(); 351 if (width < 0) { 352 return; 353 } 354 355 if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) { 356 GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style); 357 GrPaint grPaint; 358 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 359 SkPath path; 360 path.moveTo(pts[0]); 361 path.lineTo(pts[1]); 362 fContext->drawPath(grPaint, path, strokeInfo); 363 return; 364 } 365 366 // we only handle hairlines and paints without path effects or mask filters, 367 // else we let the SkDraw call our drawPath() 368 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { 369 draw.drawPoints(mode, count, pts, paint, true); 370 return; 371 } 372 373 GrPaint grPaint; 374 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 375 376 fContext->drawVertices(grPaint, 377 gPointMode2PrimtiveType[mode], 378 SkToS32(count), 379 (SkPoint*)pts, 380 NULL, 381 NULL, 382 NULL, 383 0); 384 } 385 386 /////////////////////////////////////////////////////////////////////////////// 387 388 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, 389 const SkPaint& paint) { 390 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRect", fContext); 391 392 CHECK_FOR_ANNOTATION(paint); 393 CHECK_SHOULD_DRAW(draw, false); 394 395 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 396 SkScalar width = paint.getStrokeWidth(); 397 398 /* 399 We have special code for hairline strokes, miter-strokes, bevel-stroke 400 and fills. Anything else we just call our path code. 401 */ 402 bool usePath = doStroke && width > 0 && 403 (paint.getStrokeJoin() == SkPaint::kRound_Join || 404 (paint.getStrokeJoin() == SkPaint::kBevel_Join && rect.isEmpty())); 405 // another two reasons we might need to call drawPath... 406 407 if (paint.getMaskFilter()) { 408 usePath = true; 409 } 410 411 if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) { 412 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) 413 if (doStroke) { 414 #endif 415 usePath = true; 416 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT) 417 } else { 418 usePath = !fContext->getMatrix().preservesRightAngles(); 419 } 420 #endif 421 } 422 // until we can both stroke and fill rectangles 423 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) { 424 usePath = true; 425 } 426 427 GrStrokeInfo strokeInfo(paint); 428 429 const SkPathEffect* pe = paint.getPathEffect(); 430 if (!usePath && pe && !strokeInfo.isDashed()) { 431 usePath = true; 432 } 433 434 if (usePath) { 435 SkPath path; 436 path.addRect(rect); 437 this->drawPath(draw, path, paint, NULL, true); 438 return; 439 } 440 441 GrPaint grPaint; 442 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 443 444 fContext->drawRect(grPaint, rect, &strokeInfo); 445 } 446 447 /////////////////////////////////////////////////////////////////////////////// 448 449 void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rect, 450 const SkPaint& paint) { 451 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawRRect", fContext); 452 CHECK_FOR_ANNOTATION(paint); 453 CHECK_SHOULD_DRAW(draw, false); 454 455 GrPaint grPaint; 456 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 457 458 GrStrokeInfo strokeInfo(paint); 459 if (paint.getMaskFilter()) { 460 // try to hit the fast path for drawing filtered round rects 461 462 SkRRect devRRect; 463 if (rect.transform(fContext->getMatrix(), &devRRect)) { 464 if (devRRect.allCornersCircular()) { 465 SkRect maskRect; 466 if (paint.getMaskFilter()->canFilterMaskGPU(devRRect.rect(), 467 draw.fClip->getBounds(), 468 fContext->getMatrix(), 469 &maskRect)) { 470 SkIRect finalIRect; 471 maskRect.roundOut(&finalIRect); 472 if (draw.fClip->quickReject(finalIRect)) { 473 // clipped out 474 return; 475 } 476 if (paint.getMaskFilter()->directFilterRRectMaskGPU(fContext, &grPaint, 477 strokeInfo.getStrokeRec(), 478 devRRect)) { 479 return; 480 } 481 } 482 483 } 484 } 485 486 } 487 488 bool usePath = false; 489 490 if (paint.getMaskFilter()) { 491 usePath = true; 492 } else { 493 const SkPathEffect* pe = paint.getPathEffect(); 494 if (pe && !strokeInfo.isDashed()) { 495 usePath = true; 496 } 497 } 498 499 500 if (usePath) { 501 SkPath path; 502 path.addRRect(rect); 503 this->drawPath(draw, path, paint, NULL, true); 504 return; 505 } 506 507 fContext->drawRRect(grPaint, rect, strokeInfo); 508 } 509 510 void SkGpuDevice::drawDRRect(const SkDraw& draw, const SkRRect& outer, 511 const SkRRect& inner, const SkPaint& paint) { 512 SkStrokeRec stroke(paint); 513 if (stroke.isFillStyle()) { 514 515 CHECK_FOR_ANNOTATION(paint); 516 CHECK_SHOULD_DRAW(draw, false); 517 518 GrPaint grPaint; 519 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 520 521 if (NULL == paint.getMaskFilter() && NULL == paint.getPathEffect()) { 522 fContext->drawDRRect(grPaint, outer, inner); 523 return; 524 } 525 } 526 527 SkPath path; 528 path.addRRect(outer); 529 path.addRRect(inner); 530 path.setFillType(SkPath::kEvenOdd_FillType); 531 532 this->drawPath(draw, path, paint, NULL, true); 533 } 534 535 536 ///////////////////////////////////////////////////////////////////////////// 537 538 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, 539 const SkPaint& paint) { 540 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawOval", fContext); 541 CHECK_FOR_ANNOTATION(paint); 542 CHECK_SHOULD_DRAW(draw, false); 543 544 GrStrokeInfo strokeInfo(paint); 545 546 bool usePath = false; 547 // some basic reasons we might need to call drawPath... 548 if (paint.getMaskFilter()) { 549 usePath = true; 550 } else { 551 const SkPathEffect* pe = paint.getPathEffect(); 552 if (pe && !strokeInfo.isDashed()) { 553 usePath = true; 554 } 555 } 556 557 if (usePath) { 558 SkPath path; 559 path.addOval(oval); 560 this->drawPath(draw, path, paint, NULL, true); 561 return; 562 } 563 564 GrPaint grPaint; 565 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 566 567 fContext->drawOval(grPaint, oval, strokeInfo); 568 } 569 570 #include "SkMaskFilter.h" 571 572 /////////////////////////////////////////////////////////////////////////////// 573 574 // helpers for applying mask filters 575 namespace { 576 577 // Draw a mask using the supplied paint. Since the coverage/geometry 578 // is already burnt into the mask this boils down to a rect draw. 579 // Return true if the mask was successfully drawn. 580 bool draw_mask(GrContext* context, const SkRect& maskRect, 581 GrPaint* grp, GrTexture* mask) { 582 GrContext::AutoMatrix am; 583 if (!am.setIdentity(context, grp)) { 584 return false; 585 } 586 587 SkMatrix matrix; 588 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); 589 matrix.postIDiv(mask->width(), mask->height()); 590 591 grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix))->unref(); 592 context->drawRect(*grp, maskRect); 593 return true; 594 } 595 596 bool draw_with_mask_filter(GrContext* context, const SkPath& devPath, 597 SkMaskFilter* filter, const SkRegion& clip, 598 GrPaint* grp, SkPaint::Style style) { 599 SkMask srcM, dstM; 600 601 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM, 602 SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) { 603 return false; 604 } 605 SkAutoMaskFreeImage autoSrc(srcM.fImage); 606 607 if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) { 608 return false; 609 } 610 // this will free-up dstM when we're done (allocated in filterMask()) 611 SkAutoMaskFreeImage autoDst(dstM.fImage); 612 613 if (clip.quickReject(dstM.fBounds)) { 614 return false; 615 } 616 617 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using 618 // the current clip (and identity matrix) and GrPaint settings 619 GrTextureDesc desc; 620 desc.fWidth = dstM.fBounds.width(); 621 desc.fHeight = dstM.fBounds.height(); 622 desc.fConfig = kAlpha_8_GrPixelConfig; 623 624 GrAutoScratchTexture ast(context, desc); 625 GrTexture* texture = ast.texture(); 626 627 if (NULL == texture) { 628 return false; 629 } 630 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, 631 dstM.fImage, dstM.fRowBytes); 632 633 SkRect maskRect = SkRect::Make(dstM.fBounds); 634 635 return draw_mask(context, maskRect, grp, texture); 636 } 637 638 // Create a mask of 'devPath' and place the result in 'mask'. Return true on 639 // success; false otherwise. 640 bool create_mask_GPU(GrContext* context, 641 const SkRect& maskRect, 642 const SkPath& devPath, 643 const GrStrokeInfo& strokeInfo, 644 bool doAA, 645 GrAutoScratchTexture* mask) { 646 GrTextureDesc desc; 647 desc.fFlags = kRenderTarget_GrTextureFlagBit; 648 desc.fWidth = SkScalarCeilToInt(maskRect.width()); 649 desc.fHeight = SkScalarCeilToInt(maskRect.height()); 650 // We actually only need A8, but it often isn't supported as a 651 // render target so default to RGBA_8888 652 desc.fConfig = kRGBA_8888_GrPixelConfig; 653 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) { 654 desc.fConfig = kAlpha_8_GrPixelConfig; 655 } 656 657 mask->set(context, desc); 658 if (NULL == mask->texture()) { 659 return false; 660 } 661 662 GrTexture* maskTexture = mask->texture(); 663 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); 664 665 GrContext::AutoRenderTarget art(context, maskTexture->asRenderTarget()); 666 GrContext::AutoClip ac(context, clipRect); 667 668 context->clear(NULL, 0x0, true); 669 670 GrPaint tempPaint; 671 if (doAA) { 672 tempPaint.setAntiAlias(true); 673 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst 674 // blend coeff of zero requires dual source blending support in order 675 // to properly blend partially covered pixels. This means the AA 676 // code path may not be taken. So we use a dst blend coeff of ISA. We 677 // could special case AA draws to a dst surface with known alpha=0 to 678 // use a zero dst coeff when dual source blending isn't available. 679 tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 680 } 681 682 GrContext::AutoMatrix am; 683 684 // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint. 685 SkMatrix translate; 686 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); 687 am.set(context, translate); 688 context->drawPath(tempPaint, devPath, strokeInfo); 689 return true; 690 } 691 692 SkBitmap wrap_texture(GrTexture* texture) { 693 SkBitmap result; 694 result.setInfo(texture->info()); 695 result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref(); 696 return result; 697 } 698 699 }; 700 701 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, 702 const SkPaint& paint, const SkMatrix* prePathMatrix, 703 bool pathIsMutable) { 704 CHECK_FOR_ANNOTATION(paint); 705 CHECK_SHOULD_DRAW(draw, false); 706 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext); 707 708 GrPaint grPaint; 709 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 710 711 // If we have a prematrix, apply it to the path, optimizing for the case 712 // where the original path can in fact be modified in place (even though 713 // its parameter type is const). 714 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); 715 SkTLazy<SkPath> tmpPath; 716 SkTLazy<SkPath> effectPath; 717 718 if (prePathMatrix) { 719 SkPath* result = pathPtr; 720 721 if (!pathIsMutable) { 722 result = tmpPath.init(); 723 pathIsMutable = true; 724 } 725 // should I push prePathMatrix on our MV stack temporarily, instead 726 // of applying it here? See SkDraw.cpp 727 pathPtr->transform(*prePathMatrix, result); 728 pathPtr = result; 729 } 730 // at this point we're done with prePathMatrix 731 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 732 733 GrStrokeInfo strokeInfo(paint); 734 SkPathEffect* pathEffect = paint.getPathEffect(); 735 const SkRect* cullRect = NULL; // TODO: what is our bounds? 736 SkStrokeRec* strokePtr = strokeInfo.getStrokeRecPtr(); 737 if (pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr, strokePtr, 738 cullRect)) { 739 pathPtr = effectPath.get(); 740 pathIsMutable = true; 741 strokeInfo.removeDash(); 742 } 743 744 const SkStrokeRec& stroke = strokeInfo.getStrokeRec(); 745 if (paint.getMaskFilter()) { 746 if (!stroke.isHairlineStyle()) { 747 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); 748 if (stroke.applyToPath(strokedPath, *pathPtr)) { 749 pathPtr = strokedPath; 750 pathIsMutable = true; 751 strokeInfo.setFillStyle(); 752 } 753 } 754 755 // avoid possibly allocating a new path in transform if we can 756 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); 757 758 // transform the path into device space 759 pathPtr->transform(fContext->getMatrix(), devPathPtr); 760 761 SkRect maskRect; 762 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), 763 draw.fClip->getBounds(), 764 fContext->getMatrix(), 765 &maskRect)) { 766 // The context's matrix may change while creating the mask, so save the CTM here to 767 // pass to filterMaskGPU. 768 const SkMatrix ctm = fContext->getMatrix(); 769 770 SkIRect finalIRect; 771 maskRect.roundOut(&finalIRect); 772 if (draw.fClip->quickReject(finalIRect)) { 773 // clipped out 774 return; 775 } 776 777 if (paint.getMaskFilter()->directFilterMaskGPU(fContext, &grPaint, 778 stroke, *devPathPtr)) { 779 // the mask filter was able to draw itself directly, so there's nothing 780 // left to do. 781 return; 782 } 783 784 GrAutoScratchTexture mask; 785 786 if (create_mask_GPU(fContext, maskRect, *devPathPtr, strokeInfo, 787 grPaint.isAntiAlias(), &mask)) { 788 GrTexture* filtered; 789 790 if (paint.getMaskFilter()->filterMaskGPU(mask.texture(), 791 ctm, maskRect, &filtered, true)) { 792 // filterMaskGPU gives us ownership of a ref to the result 793 SkAutoTUnref<GrTexture> atu(filtered); 794 795 // If the scratch texture that we used as the filter src also holds the filter 796 // result then we must detach so that this texture isn't recycled for a later 797 // draw. 798 if (filtered == mask.texture()) { 799 mask.detach(); 800 filtered->unref(); // detach transfers GrAutoScratchTexture's ref to us. 801 } 802 803 if (draw_mask(fContext, maskRect, &grPaint, filtered)) { 804 // This path is completely drawn 805 return; 806 } 807 } 808 } 809 } 810 811 // draw the mask on the CPU - this is a fallthrough path in case the 812 // GPU path fails 813 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style : 814 SkPaint::kFill_Style; 815 draw_with_mask_filter(fContext, *devPathPtr, paint.getMaskFilter(), 816 *draw.fClip, &grPaint, style); 817 return; 818 } 819 820 fContext->drawPath(grPaint, *pathPtr, strokeInfo); 821 } 822 823 static const int kBmpSmallTileSize = 1 << 10; 824 825 static inline int get_tile_count(const SkIRect& srcRect, int tileSize) { 826 int tilesX = (srcRect.fRight / tileSize) - (srcRect.fLeft / tileSize) + 1; 827 int tilesY = (srcRect.fBottom / tileSize) - (srcRect.fTop / tileSize) + 1; 828 return tilesX * tilesY; 829 } 830 831 static int determine_tile_size(const SkBitmap& bitmap, const SkIRect& src, int maxTileSize) { 832 if (maxTileSize <= kBmpSmallTileSize) { 833 return maxTileSize; 834 } 835 836 size_t maxTileTotalTileSize = get_tile_count(src, maxTileSize); 837 size_t smallTotalTileSize = get_tile_count(src, kBmpSmallTileSize); 838 839 maxTileTotalTileSize *= maxTileSize * maxTileSize; 840 smallTotalTileSize *= kBmpSmallTileSize * kBmpSmallTileSize; 841 842 if (maxTileTotalTileSize > 2 * smallTotalTileSize) { 843 return kBmpSmallTileSize; 844 } else { 845 return maxTileSize; 846 } 847 } 848 849 // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what 850 // pixels from the bitmap are necessary. 851 static void determine_clipped_src_rect(const GrContext* context, 852 const SkBitmap& bitmap, 853 const SkRect* srcRectPtr, 854 SkIRect* clippedSrcIRect) { 855 const GrClipData* clip = context->getClip(); 856 clip->getConservativeBounds(context->getRenderTarget(), clippedSrcIRect, NULL); 857 SkMatrix inv; 858 if (!context->getMatrix().invert(&inv)) { 859 clippedSrcIRect->setEmpty(); 860 return; 861 } 862 SkRect clippedSrcRect = SkRect::Make(*clippedSrcIRect); 863 inv.mapRect(&clippedSrcRect); 864 if (srcRectPtr) { 865 // we've setup src space 0,0 to map to the top left of the src rect. 866 clippedSrcRect.offset(srcRectPtr->fLeft, srcRectPtr->fTop); 867 if (!clippedSrcRect.intersect(*srcRectPtr)) { 868 clippedSrcIRect->setEmpty(); 869 return; 870 } 871 } 872 clippedSrcRect.roundOut(clippedSrcIRect); 873 SkIRect bmpBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 874 if (!clippedSrcIRect->intersect(bmpBounds)) { 875 clippedSrcIRect->setEmpty(); 876 } 877 } 878 879 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, 880 const GrTextureParams& params, 881 const SkRect* srcRectPtr, 882 int maxTileSize, 883 int* tileSize, 884 SkIRect* clippedSrcRect) const { 885 // if bitmap is explictly texture backed then just use the texture 886 if (bitmap.getTexture()) { 887 return false; 888 } 889 890 // if it's larger than the max tile size, then we have no choice but tiling. 891 if (bitmap.width() > maxTileSize || bitmap.height() > maxTileSize) { 892 determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect); 893 *tileSize = determine_tile_size(bitmap, *clippedSrcRect, maxTileSize); 894 return true; 895 } 896 897 if (bitmap.width() * bitmap.height() < 4 * kBmpSmallTileSize * kBmpSmallTileSize) { 898 return false; 899 } 900 901 // if the entire texture is already in our cache then no reason to tile it 902 if (GrIsBitmapInCache(fContext, bitmap, ¶ms)) { 903 return false; 904 } 905 906 // At this point we know we could do the draw by uploading the entire bitmap 907 // as a texture. However, if the texture would be large compared to the 908 // cache size and we don't require most of it for this draw then tile to 909 // reduce the amount of upload and cache spill. 910 911 // assumption here is that sw bitmap size is a good proxy for its size as 912 // a texture 913 size_t bmpSize = bitmap.getSize(); 914 size_t cacheSize; 915 fContext->getResourceCacheLimits(NULL, &cacheSize); 916 if (bmpSize < cacheSize / 2) { 917 return false; 918 } 919 920 // Figure out how much of the src we will need based on the src rect and clipping. 921 determine_clipped_src_rect(fContext, bitmap, srcRectPtr, clippedSrcRect); 922 *tileSize = kBmpSmallTileSize; // already know whole bitmap fits in one max sized tile. 923 size_t usedTileBytes = get_tile_count(*clippedSrcRect, kBmpSmallTileSize) * 924 kBmpSmallTileSize * kBmpSmallTileSize; 925 926 return usedTileBytes < 2 * bmpSize; 927 } 928 929 void SkGpuDevice::drawBitmap(const SkDraw& origDraw, 930 const SkBitmap& bitmap, 931 const SkMatrix& m, 932 const SkPaint& paint) { 933 SkMatrix concat; 934 SkTCopyOnFirstWrite<SkDraw> draw(origDraw); 935 if (!m.isIdentity()) { 936 concat.setConcat(*draw->fMatrix, m); 937 draw.writable()->fMatrix = &concat; 938 } 939 this->drawBitmapCommon(*draw, bitmap, NULL, NULL, paint, SkCanvas::kNone_DrawBitmapRectFlag); 940 } 941 942 // This method outsets 'iRect' by 'outset' all around and then clamps its extents to 943 // 'clamp'. 'offset' is adjusted to remain positioned over the top-left corner 944 // of 'iRect' for all possible outsets/clamps. 945 static inline void clamped_outset_with_offset(SkIRect* iRect, 946 int outset, 947 SkPoint* offset, 948 const SkIRect& clamp) { 949 iRect->outset(outset, outset); 950 951 int leftClampDelta = clamp.fLeft - iRect->fLeft; 952 if (leftClampDelta > 0) { 953 offset->fX -= outset - leftClampDelta; 954 iRect->fLeft = clamp.fLeft; 955 } else { 956 offset->fX -= outset; 957 } 958 959 int topClampDelta = clamp.fTop - iRect->fTop; 960 if (topClampDelta > 0) { 961 offset->fY -= outset - topClampDelta; 962 iRect->fTop = clamp.fTop; 963 } else { 964 offset->fY -= outset; 965 } 966 967 if (iRect->fRight > clamp.fRight) { 968 iRect->fRight = clamp.fRight; 969 } 970 if (iRect->fBottom > clamp.fBottom) { 971 iRect->fBottom = clamp.fBottom; 972 } 973 } 974 975 static bool has_aligned_samples(const SkRect& srcRect, 976 const SkRect& transformedRect) { 977 // detect pixel disalignment 978 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) - 979 transformedRect.left()) < COLOR_BLEED_TOLERANCE && 980 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) - 981 transformedRect.top()) < COLOR_BLEED_TOLERANCE && 982 SkScalarAbs(transformedRect.width() - srcRect.width()) < 983 COLOR_BLEED_TOLERANCE && 984 SkScalarAbs(transformedRect.height() - srcRect.height()) < 985 COLOR_BLEED_TOLERANCE) { 986 return true; 987 } 988 return false; 989 } 990 991 static bool may_color_bleed(const SkRect& srcRect, 992 const SkRect& transformedRect, 993 const SkMatrix& m) { 994 // Only gets called if has_aligned_samples returned false. 995 // So we can assume that sampling is axis aligned but not texel aligned. 996 SkASSERT(!has_aligned_samples(srcRect, transformedRect)); 997 SkRect innerSrcRect(srcRect), innerTransformedRect, 998 outerTransformedRect(transformedRect); 999 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf); 1000 m.mapRect(&innerTransformedRect, innerSrcRect); 1001 1002 // The gap between outerTransformedRect and innerTransformedRect 1003 // represents the projection of the source border area, which is 1004 // problematic for color bleeding. We must check whether any 1005 // destination pixels sample the border area. 1006 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE); 1007 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE); 1008 SkIRect outer, inner; 1009 outerTransformedRect.round(&outer); 1010 innerTransformedRect.round(&inner); 1011 // If the inner and outer rects round to the same result, it means the 1012 // border does not overlap any pixel centers. Yay! 1013 return inner != outer; 1014 } 1015 1016 static bool needs_texture_domain(const SkBitmap& bitmap, 1017 const SkRect& srcRect, 1018 GrTextureParams ¶ms, 1019 const SkMatrix& contextMatrix, 1020 bool bicubic) { 1021 bool needsTextureDomain = false; 1022 1023 if (bicubic || params.filterMode() != GrTextureParams::kNone_FilterMode) { 1024 // Need texture domain if drawing a sub rect 1025 needsTextureDomain = srcRect.width() < bitmap.width() || 1026 srcRect.height() < bitmap.height(); 1027 if (!bicubic && needsTextureDomain && contextMatrix.rectStaysRect()) { 1028 // sampling is axis-aligned 1029 SkRect transformedRect; 1030 contextMatrix.mapRect(&transformedRect, srcRect); 1031 1032 if (has_aligned_samples(srcRect, transformedRect)) { 1033 params.setFilterMode(GrTextureParams::kNone_FilterMode); 1034 needsTextureDomain = false; 1035 } else { 1036 needsTextureDomain = may_color_bleed(srcRect, transformedRect, contextMatrix); 1037 } 1038 } 1039 } 1040 return needsTextureDomain; 1041 } 1042 1043 void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, 1044 const SkBitmap& bitmap, 1045 const SkRect* srcRectPtr, 1046 const SkSize* dstSizePtr, 1047 const SkPaint& paint, 1048 SkCanvas::DrawBitmapRectFlags flags) { 1049 CHECK_SHOULD_DRAW(draw, false); 1050 1051 SkRect srcRect; 1052 SkSize dstSize; 1053 // If there is no src rect, or the src rect contains the entire bitmap then we're effectively 1054 // in the (easier) bleed case, so update flags. 1055 if (NULL == srcRectPtr) { 1056 SkScalar w = SkIntToScalar(bitmap.width()); 1057 SkScalar h = SkIntToScalar(bitmap.height()); 1058 dstSize.fWidth = w; 1059 dstSize.fHeight = h; 1060 srcRect.set(0, 0, w, h); 1061 flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag); 1062 } else { 1063 SkASSERT(dstSizePtr); 1064 srcRect = *srcRectPtr; 1065 dstSize = *dstSizePtr; 1066 if (srcRect.fLeft <= 0 && srcRect.fTop <= 0 && 1067 srcRect.fRight >= bitmap.width() && srcRect.fBottom >= bitmap.height()) { 1068 flags = (SkCanvas::DrawBitmapRectFlags) (flags | SkCanvas::kBleed_DrawBitmapRectFlag); 1069 } 1070 } 1071 1072 if (paint.getMaskFilter()){ 1073 // Convert the bitmap to a shader so that the rect can be drawn 1074 // through drawRect, which supports mask filters. 1075 SkBitmap tmp; // subset of bitmap, if necessary 1076 const SkBitmap* bitmapPtr = &bitmap; 1077 SkMatrix localM; 1078 if (srcRectPtr) { 1079 localM.setTranslate(-srcRectPtr->fLeft, -srcRectPtr->fTop); 1080 localM.postScale(dstSize.fWidth / srcRectPtr->width(), 1081 dstSize.fHeight / srcRectPtr->height()); 1082 // In bleed mode we position and trim the bitmap based on the src rect which is 1083 // already accounted for in 'm' and 'srcRect'. In clamp mode we need to chop out 1084 // the desired portion of the bitmap and then update 'm' and 'srcRect' to 1085 // compensate. 1086 if (!(SkCanvas::kBleed_DrawBitmapRectFlag & flags)) { 1087 SkIRect iSrc; 1088 srcRect.roundOut(&iSrc); 1089 1090 SkPoint offset = SkPoint::Make(SkIntToScalar(iSrc.fLeft), 1091 SkIntToScalar(iSrc.fTop)); 1092 1093 if (!bitmap.extractSubset(&tmp, iSrc)) { 1094 return; // extraction failed 1095 } 1096 bitmapPtr = &tmp; 1097 srcRect.offset(-offset.fX, -offset.fY); 1098 1099 // The source rect has changed so update the matrix 1100 localM.preTranslate(offset.fX, offset.fY); 1101 } 1102 } else { 1103 localM.reset(); 1104 } 1105 1106 SkPaint paintWithShader(paint); 1107 paintWithShader.setShader(SkShader::CreateBitmapShader(*bitmapPtr, 1108 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode, &localM))->unref(); 1109 SkRect dstRect = {0, 0, dstSize.fWidth, dstSize.fHeight}; 1110 this->drawRect(draw, dstRect, paintWithShader); 1111 1112 return; 1113 } 1114 1115 // If there is no mask filter than it is OK to handle the src rect -> dst rect scaling using 1116 // the view matrix rather than a local matrix. 1117 SkMatrix m; 1118 m.setScale(dstSize.fWidth / srcRect.width(), 1119 dstSize.fHeight / srcRect.height()); 1120 fContext->concatMatrix(m); 1121 1122 GrTextureParams params; 1123 SkPaint::FilterLevel paintFilterLevel = paint.getFilterLevel(); 1124 GrTextureParams::FilterMode textureFilterMode; 1125 1126 bool doBicubic = false; 1127 1128 switch(paintFilterLevel) { 1129 case SkPaint::kNone_FilterLevel: 1130 textureFilterMode = GrTextureParams::kNone_FilterMode; 1131 break; 1132 case SkPaint::kLow_FilterLevel: 1133 textureFilterMode = GrTextureParams::kBilerp_FilterMode; 1134 break; 1135 case SkPaint::kMedium_FilterLevel: 1136 if (fContext->getMatrix().getMinScale() < SK_Scalar1) { 1137 textureFilterMode = GrTextureParams::kMipMap_FilterMode; 1138 } else { 1139 // Don't trigger MIP level generation unnecessarily. 1140 textureFilterMode = GrTextureParams::kBilerp_FilterMode; 1141 } 1142 break; 1143 case SkPaint::kHigh_FilterLevel: 1144 // Minification can look bad with the bicubic effect. 1145 doBicubic = 1146 GrBicubicEffect::ShouldUseBicubic(fContext->getMatrix(), &textureFilterMode); 1147 break; 1148 default: 1149 SkErrorInternals::SetError( kInvalidPaint_SkError, 1150 "Sorry, I don't understand the filtering " 1151 "mode you asked for. Falling back to " 1152 "MIPMaps."); 1153 textureFilterMode = GrTextureParams::kMipMap_FilterMode; 1154 break; 1155 } 1156 1157 int tileFilterPad; 1158 if (doBicubic) { 1159 tileFilterPad = GrBicubicEffect::kFilterTexelPad; 1160 } else if (GrTextureParams::kNone_FilterMode == textureFilterMode) { 1161 tileFilterPad = 0; 1162 } else { 1163 tileFilterPad = 1; 1164 } 1165 params.setFilterMode(textureFilterMode); 1166 1167 int maxTileSize = fContext->getMaxTextureSize() - 2 * tileFilterPad; 1168 int tileSize; 1169 1170 SkIRect clippedSrcRect; 1171 if (this->shouldTileBitmap(bitmap, params, srcRectPtr, maxTileSize, &tileSize, 1172 &clippedSrcRect)) { 1173 this->drawTiledBitmap(bitmap, srcRect, clippedSrcRect, params, paint, flags, tileSize, 1174 doBicubic); 1175 } else { 1176 // take the simple case 1177 bool needsTextureDomain = needs_texture_domain(bitmap, 1178 srcRect, 1179 params, 1180 fContext->getMatrix(), 1181 doBicubic); 1182 this->internalDrawBitmap(bitmap, 1183 srcRect, 1184 params, 1185 paint, 1186 flags, 1187 doBicubic, 1188 needsTextureDomain); 1189 } 1190 } 1191 1192 // Break 'bitmap' into several tiles to draw it since it has already 1193 // been determined to be too large to fit in VRAM 1194 void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, 1195 const SkRect& srcRect, 1196 const SkIRect& clippedSrcIRect, 1197 const GrTextureParams& params, 1198 const SkPaint& paint, 1199 SkCanvas::DrawBitmapRectFlags flags, 1200 int tileSize, 1201 bool bicubic) { 1202 // The following pixel lock is technically redundant, but it is desirable 1203 // to lock outside of the tile loop to prevent redecoding the whole image 1204 // at each tile in cases where 'bitmap' holds an SkDiscardablePixelRef that 1205 // is larger than the limit of the discardable memory pool. 1206 SkAutoLockPixels alp(bitmap); 1207 SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect); 1208 1209 int nx = bitmap.width() / tileSize; 1210 int ny = bitmap.height() / tileSize; 1211 for (int x = 0; x <= nx; x++) { 1212 for (int y = 0; y <= ny; y++) { 1213 SkRect tileR; 1214 tileR.set(SkIntToScalar(x * tileSize), 1215 SkIntToScalar(y * tileSize), 1216 SkIntToScalar((x + 1) * tileSize), 1217 SkIntToScalar((y + 1) * tileSize)); 1218 1219 if (!SkRect::Intersects(tileR, clippedSrcRect)) { 1220 continue; 1221 } 1222 1223 if (!tileR.intersect(srcRect)) { 1224 continue; 1225 } 1226 1227 SkBitmap tmpB; 1228 SkIRect iTileR; 1229 tileR.roundOut(&iTileR); 1230 SkPoint offset = SkPoint::Make(SkIntToScalar(iTileR.fLeft), 1231 SkIntToScalar(iTileR.fTop)); 1232 1233 // Adjust the context matrix to draw at the right x,y in device space 1234 SkMatrix tmpM; 1235 GrContext::AutoMatrix am; 1236 tmpM.setTranslate(offset.fX - srcRect.fLeft, offset.fY - srcRect.fTop); 1237 am.setPreConcat(fContext, tmpM); 1238 1239 if (SkPaint::kNone_FilterLevel != paint.getFilterLevel() || bicubic) { 1240 SkIRect iClampRect; 1241 1242 if (SkCanvas::kBleed_DrawBitmapRectFlag & flags) { 1243 // In bleed mode we want to always expand the tile on all edges 1244 // but stay within the bitmap bounds 1245 iClampRect = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1246 } else { 1247 // In texture-domain/clamp mode we only want to expand the 1248 // tile on edges interior to "srcRect" (i.e., we want to 1249 // not bleed across the original clamped edges) 1250 srcRect.roundOut(&iClampRect); 1251 } 1252 int outset = bicubic ? GrBicubicEffect::kFilterTexelPad : 1; 1253 clamped_outset_with_offset(&iTileR, outset, &offset, iClampRect); 1254 } 1255 1256 if (bitmap.extractSubset(&tmpB, iTileR)) { 1257 // now offset it to make it "local" to our tmp bitmap 1258 tileR.offset(-offset.fX, -offset.fY); 1259 GrTextureParams paramsTemp = params; 1260 bool needsTextureDomain = needs_texture_domain(bitmap, 1261 srcRect, 1262 paramsTemp, 1263 fContext->getMatrix(), 1264 bicubic); 1265 this->internalDrawBitmap(tmpB, 1266 tileR, 1267 paramsTemp, 1268 paint, 1269 flags, 1270 bicubic, 1271 needsTextureDomain); 1272 } 1273 } 1274 } 1275 } 1276 1277 1278 /* 1279 * This is called by drawBitmap(), which has to handle images that may be too 1280 * large to be represented by a single texture. 1281 * 1282 * internalDrawBitmap assumes that the specified bitmap will fit in a texture 1283 * and that non-texture portion of the GrPaint has already been setup. 1284 */ 1285 void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, 1286 const SkRect& srcRect, 1287 const GrTextureParams& params, 1288 const SkPaint& paint, 1289 SkCanvas::DrawBitmapRectFlags flags, 1290 bool bicubic, 1291 bool needsTextureDomain) { 1292 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() && 1293 bitmap.height() <= fContext->getMaxTextureSize()); 1294 1295 GrTexture* texture; 1296 SkAutoCachedTexture act(this, bitmap, ¶ms, &texture); 1297 if (NULL == texture) { 1298 return; 1299 } 1300 1301 SkRect dstRect = {0, 0, srcRect.width(), srcRect.height() }; 1302 SkRect paintRect; 1303 SkScalar wInv = SkScalarInvert(SkIntToScalar(texture->width())); 1304 SkScalar hInv = SkScalarInvert(SkIntToScalar(texture->height())); 1305 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv), 1306 SkScalarMul(srcRect.fTop, hInv), 1307 SkScalarMul(srcRect.fRight, wInv), 1308 SkScalarMul(srcRect.fBottom, hInv)); 1309 1310 SkRect textureDomain = SkRect::MakeEmpty(); 1311 SkAutoTUnref<GrFragmentProcessor> fp; 1312 if (needsTextureDomain && !(flags & SkCanvas::kBleed_DrawBitmapRectFlag)) { 1313 // Use a constrained texture domain to avoid color bleeding 1314 SkScalar left, top, right, bottom; 1315 if (srcRect.width() > SK_Scalar1) { 1316 SkScalar border = SK_ScalarHalf / texture->width(); 1317 left = paintRect.left() + border; 1318 right = paintRect.right() - border; 1319 } else { 1320 left = right = SkScalarHalf(paintRect.left() + paintRect.right()); 1321 } 1322 if (srcRect.height() > SK_Scalar1) { 1323 SkScalar border = SK_ScalarHalf / texture->height(); 1324 top = paintRect.top() + border; 1325 bottom = paintRect.bottom() - border; 1326 } else { 1327 top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom()); 1328 } 1329 textureDomain.setLTRB(left, top, right, bottom); 1330 if (bicubic) { 1331 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), textureDomain)); 1332 } else { 1333 fp.reset(GrTextureDomainEffect::Create(texture, 1334 SkMatrix::I(), 1335 textureDomain, 1336 GrTextureDomain::kClamp_Mode, 1337 params.filterMode())); 1338 } 1339 } else if (bicubic) { 1340 SkASSERT(GrTextureParams::kNone_FilterMode == params.filterMode()); 1341 SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() }; 1342 fp.reset(GrBicubicEffect::Create(texture, SkMatrix::I(), tileModes)); 1343 } else { 1344 fp.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params)); 1345 } 1346 1347 // Construct a GrPaint by setting the bitmap texture as the first effect and then configuring 1348 // the rest from the SkPaint. 1349 GrPaint grPaint; 1350 grPaint.addColorProcessor(fp); 1351 bool alphaOnly = !(kAlpha_8_SkColorType == bitmap.colorType()); 1352 GrColor paintColor = (alphaOnly) ? SkColor2GrColorJustAlpha(paint.getColor()) : 1353 SkColor2GrColor(paint.getColor()); 1354 SkPaint2GrPaintNoShader(this->context(), paint, paintColor, false, &grPaint); 1355 1356 fContext->drawRectToRect(grPaint, dstRect, paintRect); 1357 } 1358 1359 static bool filter_texture(SkBaseDevice* device, GrContext* context, 1360 GrTexture* texture, const SkImageFilter* filter, 1361 int w, int h, const SkImageFilter::Context& ctx, 1362 SkBitmap* result, SkIPoint* offset) { 1363 SkASSERT(filter); 1364 SkDeviceImageFilterProxy proxy(device); 1365 1366 if (filter->canFilterImageGPU()) { 1367 // Save the render target and set it to NULL, so we don't accidentally draw to it in the 1368 // filter. Also set the clip wide open and the matrix to identity. 1369 GrContext::AutoWideOpenIdentityDraw awo(context, NULL); 1370 return filter->filterImageGPU(&proxy, wrap_texture(texture), ctx, result, offset); 1371 } else { 1372 return false; 1373 } 1374 } 1375 1376 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 1377 int left, int top, const SkPaint& paint) { 1378 // drawSprite is defined to be in device coords. 1379 CHECK_SHOULD_DRAW(draw, true); 1380 1381 SkAutoLockPixels alp(bitmap, !bitmap.getTexture()); 1382 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1383 return; 1384 } 1385 1386 int w = bitmap.width(); 1387 int h = bitmap.height(); 1388 1389 GrTexture* texture; 1390 // draw sprite uses the default texture params 1391 SkAutoCachedTexture act(this, bitmap, NULL, &texture); 1392 1393 SkImageFilter* filter = paint.getImageFilter(); 1394 // This bitmap will own the filtered result as a texture. 1395 SkBitmap filteredBitmap; 1396 1397 if (filter) { 1398 SkIPoint offset = SkIPoint::Make(0, 0); 1399 SkMatrix matrix(*draw.fMatrix); 1400 matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top)); 1401 SkIRect clipBounds = SkIRect::MakeWH(bitmap.width(), bitmap.height()); 1402 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache()); 1403 // This cache is transient, and is freed (along with all its contained 1404 // textures) when it goes out of scope. 1405 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1406 if (filter_texture(this, fContext, texture, filter, w, h, ctx, &filteredBitmap, 1407 &offset)) { 1408 texture = (GrTexture*) filteredBitmap.getTexture(); 1409 w = filteredBitmap.width(); 1410 h = filteredBitmap.height(); 1411 left += offset.x(); 1412 top += offset.y(); 1413 } else { 1414 return; 1415 } 1416 } 1417 1418 GrPaint grPaint; 1419 grPaint.addColorTextureProcessor(texture, SkMatrix::I()); 1420 1421 SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColorJustAlpha(paint.getColor()), 1422 false, &grPaint); 1423 1424 fContext->drawRectToRect(grPaint, 1425 SkRect::MakeXYWH(SkIntToScalar(left), 1426 SkIntToScalar(top), 1427 SkIntToScalar(w), 1428 SkIntToScalar(h)), 1429 SkRect::MakeXYWH(0, 1430 0, 1431 SK_Scalar1 * w / texture->width(), 1432 SK_Scalar1 * h / texture->height())); 1433 } 1434 1435 void SkGpuDevice::drawBitmapRect(const SkDraw& origDraw, const SkBitmap& bitmap, 1436 const SkRect* src, const SkRect& dst, 1437 const SkPaint& paint, 1438 SkCanvas::DrawBitmapRectFlags flags) { 1439 SkMatrix matrix; 1440 SkRect bitmapBounds, tmpSrc; 1441 1442 bitmapBounds.set(0, 0, 1443 SkIntToScalar(bitmap.width()), 1444 SkIntToScalar(bitmap.height())); 1445 1446 // Compute matrix from the two rectangles 1447 if (src) { 1448 tmpSrc = *src; 1449 } else { 1450 tmpSrc = bitmapBounds; 1451 } 1452 1453 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1454 1455 // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null. 1456 if (src) { 1457 if (!bitmapBounds.contains(tmpSrc)) { 1458 if (!tmpSrc.intersect(bitmapBounds)) { 1459 return; // nothing to draw 1460 } 1461 } 1462 } 1463 1464 SkRect tmpDst; 1465 matrix.mapRect(&tmpDst, tmpSrc); 1466 1467 SkTCopyOnFirstWrite<SkDraw> draw(origDraw); 1468 if (0 != tmpDst.fLeft || 0 != tmpDst.fTop) { 1469 // Translate so that tempDst's top left is at the origin. 1470 matrix = *origDraw.fMatrix; 1471 matrix.preTranslate(tmpDst.fLeft, tmpDst.fTop); 1472 draw.writable()->fMatrix = &matrix; 1473 } 1474 SkSize dstSize; 1475 dstSize.fWidth = tmpDst.width(); 1476 dstSize.fHeight = tmpDst.height(); 1477 1478 this->drawBitmapCommon(*draw, bitmap, &tmpSrc, &dstSize, paint, flags); 1479 } 1480 1481 void SkGpuDevice::drawDevice(const SkDraw& draw, SkBaseDevice* device, 1482 int x, int y, const SkPaint& paint) { 1483 // clear of the source device must occur before CHECK_SHOULD_DRAW 1484 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawDevice", fContext); 1485 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device); 1486 if (dev->fNeedClear) { 1487 // TODO: could check here whether we really need to draw at all 1488 dev->clear(0x0); 1489 } 1490 1491 // drawDevice is defined to be in device coords. 1492 CHECK_SHOULD_DRAW(draw, true); 1493 1494 GrRenderTarget* devRT = dev->accessRenderTarget(); 1495 GrTexture* devTex; 1496 if (NULL == (devTex = devRT->asTexture())) { 1497 return; 1498 } 1499 1500 const SkBitmap& bm = dev->accessBitmap(false); 1501 int w = bm.width(); 1502 int h = bm.height(); 1503 1504 SkImageFilter* filter = paint.getImageFilter(); 1505 // This bitmap will own the filtered result as a texture. 1506 SkBitmap filteredBitmap; 1507 1508 if (filter) { 1509 SkIPoint offset = SkIPoint::Make(0, 0); 1510 SkMatrix matrix(*draw.fMatrix); 1511 matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); 1512 SkIRect clipBounds = SkIRect::MakeWH(devTex->width(), devTex->height()); 1513 // This cache is transient, and is freed (along with all its contained 1514 // textures) when it goes out of scope. 1515 SkAutoTUnref<SkImageFilter::Cache> cache(getImageFilterCache()); 1516 SkImageFilter::Context ctx(matrix, clipBounds, cache); 1517 if (filter_texture(this, fContext, devTex, filter, w, h, ctx, &filteredBitmap, 1518 &offset)) { 1519 devTex = filteredBitmap.getTexture(); 1520 w = filteredBitmap.width(); 1521 h = filteredBitmap.height(); 1522 x += offset.fX; 1523 y += offset.fY; 1524 } else { 1525 return; 1526 } 1527 } 1528 1529 GrPaint grPaint; 1530 grPaint.addColorTextureProcessor(devTex, SkMatrix::I()); 1531 1532 SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColorJustAlpha(paint.getColor()), 1533 false, &grPaint); 1534 1535 SkRect dstRect = SkRect::MakeXYWH(SkIntToScalar(x), 1536 SkIntToScalar(y), 1537 SkIntToScalar(w), 1538 SkIntToScalar(h)); 1539 1540 // The device being drawn may not fill up its texture (e.g. saveLayer uses approximate 1541 // scratch texture). 1542 SkRect srcRect = SkRect::MakeWH(SK_Scalar1 * w / devTex->width(), 1543 SK_Scalar1 * h / devTex->height()); 1544 1545 fContext->drawRectToRect(grPaint, dstRect, srcRect); 1546 } 1547 1548 bool SkGpuDevice::canHandleImageFilter(const SkImageFilter* filter) { 1549 return filter->canFilterImageGPU(); 1550 } 1551 1552 bool SkGpuDevice::filterImage(const SkImageFilter* filter, const SkBitmap& src, 1553 const SkImageFilter::Context& ctx, 1554 SkBitmap* result, SkIPoint* offset) { 1555 // want explicitly our impl, so guard against a subclass of us overriding it 1556 if (!this->SkGpuDevice::canHandleImageFilter(filter)) { 1557 return false; 1558 } 1559 1560 SkAutoLockPixels alp(src, !src.getTexture()); 1561 if (!src.getTexture() && !src.readyToDraw()) { 1562 return false; 1563 } 1564 1565 GrTexture* texture; 1566 // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup 1567 // must be pushed upstack. 1568 SkAutoCachedTexture act(this, src, NULL, &texture); 1569 1570 return filter_texture(this, fContext, texture, filter, src.width(), src.height(), ctx, 1571 result, offset); 1572 } 1573 1574 /////////////////////////////////////////////////////////////////////////////// 1575 1576 // must be in SkCanvas::VertexMode order 1577 static const GrPrimitiveType gVertexMode2PrimitiveType[] = { 1578 kTriangles_GrPrimitiveType, 1579 kTriangleStrip_GrPrimitiveType, 1580 kTriangleFan_GrPrimitiveType, 1581 }; 1582 1583 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 1584 int vertexCount, const SkPoint vertices[], 1585 const SkPoint texs[], const SkColor colors[], 1586 SkXfermode* xmode, 1587 const uint16_t indices[], int indexCount, 1588 const SkPaint& paint) { 1589 CHECK_SHOULD_DRAW(draw, false); 1590 1591 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawVertices", fContext); 1592 1593 const uint16_t* outIndices; 1594 SkAutoTDeleteArray<uint16_t> outAlloc(NULL); 1595 GrPrimitiveType primType; 1596 GrPaint grPaint; 1597 1598 // If both textures and vertex-colors are NULL, strokes hairlines with the paint's color. 1599 if ((NULL == texs || NULL == paint.getShader()) && NULL == colors) { 1600 1601 texs = NULL; 1602 1603 SkPaint copy(paint); 1604 copy.setStyle(SkPaint::kStroke_Style); 1605 copy.setStrokeWidth(0); 1606 1607 // we ignore the shader if texs is null. 1608 SkPaint2GrPaintNoShader(this->context(), copy, SkColor2GrColor(copy.getColor()), 1609 NULL == colors, &grPaint); 1610 1611 primType = kLines_GrPrimitiveType; 1612 int triangleCount = 0; 1613 int n = (NULL == indices) ? vertexCount : indexCount; 1614 switch (vmode) { 1615 case SkCanvas::kTriangles_VertexMode: 1616 triangleCount = n / 3; 1617 break; 1618 case SkCanvas::kTriangleStrip_VertexMode: 1619 case SkCanvas::kTriangleFan_VertexMode: 1620 triangleCount = n - 2; 1621 break; 1622 } 1623 1624 VertState state(vertexCount, indices, indexCount); 1625 VertState::Proc vertProc = state.chooseProc(vmode); 1626 1627 //number of indices for lines per triangle with kLines 1628 indexCount = triangleCount * 6; 1629 1630 outAlloc.reset(SkNEW_ARRAY(uint16_t, indexCount)); 1631 outIndices = outAlloc.get(); 1632 uint16_t* auxIndices = outAlloc.get(); 1633 int i = 0; 1634 while (vertProc(&state)) { 1635 auxIndices[i] = state.f0; 1636 auxIndices[i + 1] = state.f1; 1637 auxIndices[i + 2] = state.f1; 1638 auxIndices[i + 3] = state.f2; 1639 auxIndices[i + 4] = state.f2; 1640 auxIndices[i + 5] = state.f0; 1641 i += 6; 1642 } 1643 } else { 1644 outIndices = indices; 1645 primType = gVertexMode2PrimitiveType[vmode]; 1646 1647 if (NULL == texs || NULL == paint.getShader()) { 1648 SkPaint2GrPaintNoShader(this->context(), paint, SkColor2GrColor(paint.getColor()), 1649 NULL == colors, &grPaint); 1650 } else { 1651 SkPaint2GrPaintShader(this->context(), paint, NULL == colors, &grPaint); 1652 } 1653 } 1654 1655 #if 0 1656 if (xmode && texs && colors) { 1657 if (!SkXfermode::IsMode(xmode, SkXfermode::kModulate_Mode)) { 1658 SkDebugf("Unsupported vertex-color/texture xfer mode.\n"); 1659 return; 1660 } 1661 } 1662 #endif 1663 1664 SkAutoSTMalloc<128, GrColor> convertedColors(0); 1665 if (colors) { 1666 // need to convert byte order and from non-PM to PM 1667 convertedColors.reset(vertexCount); 1668 SkColor color; 1669 for (int i = 0; i < vertexCount; ++i) { 1670 color = colors[i]; 1671 if (paint.getAlpha() != 255) { 1672 color = SkColorSetA(color, SkMulDiv255Round(SkColorGetA(color), paint.getAlpha())); 1673 } 1674 convertedColors[i] = SkColor2GrColor(color); 1675 } 1676 colors = convertedColors.get(); 1677 } 1678 fContext->drawVertices(grPaint, 1679 primType, 1680 vertexCount, 1681 vertices, 1682 texs, 1683 colors, 1684 outIndices, 1685 indexCount); 1686 } 1687 1688 /////////////////////////////////////////////////////////////////////////////// 1689 1690 void SkGpuDevice::drawText(const SkDraw& draw, const void* text, 1691 size_t byteLength, SkScalar x, SkScalar y, 1692 const SkPaint& paint) { 1693 CHECK_SHOULD_DRAW(draw, false); 1694 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawText", fContext); 1695 1696 if (fMainTextContext->canDraw(paint)) { 1697 GrPaint grPaint; 1698 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 1699 1700 SkDEBUGCODE(this->validate();) 1701 1702 fMainTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y); 1703 } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) { 1704 GrPaint grPaint; 1705 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 1706 1707 SkDEBUGCODE(this->validate();) 1708 1709 fFallbackTextContext->drawText(grPaint, paint, (const char *)text, byteLength, x, y); 1710 } else { 1711 // this guy will just call our drawPath() 1712 draw.drawText_asPaths((const char*)text, byteLength, x, y, paint); 1713 } 1714 } 1715 1716 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, 1717 size_t byteLength, const SkScalar pos[], 1718 SkScalar constY, int scalarsPerPos, 1719 const SkPaint& paint) { 1720 GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPosText", fContext); 1721 CHECK_SHOULD_DRAW(draw, false); 1722 1723 if (fMainTextContext->canDraw(paint)) { 1724 GrPaint grPaint; 1725 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 1726 1727 SkDEBUGCODE(this->validate();) 1728 1729 fMainTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos, 1730 constY, scalarsPerPos); 1731 } else if (fFallbackTextContext && fFallbackTextContext->canDraw(paint)) { 1732 GrPaint grPaint; 1733 SkPaint2GrPaintShader(this->context(), paint, true, &grPaint); 1734 1735 SkDEBUGCODE(this->validate();) 1736 1737 fFallbackTextContext->drawPosText(grPaint, paint, (const char *)text, byteLength, pos, 1738 constY, scalarsPerPos); 1739 } else { 1740 draw.drawPosText_asPaths((const char*)text, byteLength, pos, constY, 1741 scalarsPerPos, paint); 1742 } 1743 } 1744 1745 void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text, 1746 size_t len, const SkPath& path, 1747 const SkMatrix* m, const SkPaint& paint) { 1748 CHECK_SHOULD_DRAW(draw, false); 1749 1750 SkASSERT(draw.fDevice == this); 1751 draw.drawTextOnPath((const char*)text, len, path, m, paint); 1752 } 1753 1754 /////////////////////////////////////////////////////////////////////////////// 1755 1756 bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 1757 if (!paint.isLCDRenderText()) { 1758 // we're cool with the paint as is 1759 return false; 1760 } 1761 1762 if (paint.getShader() || 1763 paint.getXfermode() || // unless its srcover 1764 paint.getMaskFilter() || 1765 paint.getRasterizer() || 1766 paint.getColorFilter() || 1767 paint.getPathEffect() || 1768 paint.isFakeBoldText() || 1769 paint.getStyle() != SkPaint::kFill_Style) { 1770 // turn off lcd, but turn on kGenA8 1771 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 1772 flags->fFlags |= SkPaint::kGenA8FromLCD_Flag; 1773 return true; 1774 } 1775 // we're cool with the paint as is 1776 return false; 1777 } 1778 1779 void SkGpuDevice::flush() { 1780 DO_DEFERRED_CLEAR(); 1781 fContext->resolveRenderTarget(fRenderTarget); 1782 } 1783 1784 /////////////////////////////////////////////////////////////////////////////// 1785 1786 SkBaseDevice* SkGpuDevice::onCreateDevice(const SkImageInfo& info, Usage usage) { 1787 GrTextureDesc desc; 1788 desc.fConfig = fRenderTarget->config(); 1789 desc.fFlags = kRenderTarget_GrTextureFlagBit; 1790 desc.fWidth = info.width(); 1791 desc.fHeight = info.height(); 1792 desc.fSampleCnt = fRenderTarget->numSamples(); 1793 1794 SkAutoTUnref<GrTexture> texture; 1795 // Skia's convention is to only clear a device if it is non-opaque. 1796 unsigned flags = info.isOpaque() ? 0 : kNeedClear_Flag; 1797 1798 #if CACHE_COMPATIBLE_DEVICE_TEXTURES 1799 // layers are never draw in repeat modes, so we can request an approx 1800 // match and ignore any padding. 1801 flags |= kCached_Flag; 1802 const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ? 1803 GrContext::kApprox_ScratchTexMatch : 1804 GrContext::kExact_ScratchTexMatch; 1805 texture.reset(fContext->lockAndRefScratchTexture(desc, match)); 1806 #else 1807 texture.reset(fContext->createUncachedTexture(desc, NULL, 0)); 1808 #endif 1809 if (texture.get()) { 1810 return SkGpuDevice::Create(texture, SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType), flags); 1811 } else { 1812 GrPrintf("---- failed to create compatible device texture [%d %d]\n", 1813 info.width(), info.height()); 1814 return NULL; 1815 } 1816 } 1817 1818 SkSurface* SkGpuDevice::newSurface(const SkImageInfo& info, const SkSurfaceProps& props) { 1819 return SkSurface::NewRenderTarget(fContext, info, fRenderTarget->numSamples(), &props); 1820 } 1821 1822 void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) { 1823 fContext->getLayerCache()->processDeletedPictures(); 1824 1825 if (picture->fData.get() && !picture->fData->suitableForLayerOptimization()) { 1826 return; 1827 } 1828 1829 SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); 1830 1831 const SkPicture::AccelData* existing = picture->EXPERIMENTAL_getAccelData(key); 1832 if (existing) { 1833 return; 1834 } 1835 1836 GPUOptimize(picture); 1837 1838 fContext->getLayerCache()->trackPicture(picture); 1839 } 1840 1841 bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* mainPicture, 1842 const SkMatrix* matrix, const SkPaint* paint) { 1843 // todo: should handle these natively 1844 if (matrix || paint) { 1845 return false; 1846 } 1847 1848 fContext->getLayerCache()->processDeletedPictures(); 1849 1850 SkRect clipBounds; 1851 if (!mainCanvas->getClipBounds(&clipBounds)) { 1852 return true; 1853 } 1854 1855 SkTDArray<GrLayerHoister::HoistedLayer> atlased, nonAtlased; 1856 1857 if (!GrLayerHoister::FindLayersToHoist(mainPicture, clipBounds, &atlased, &nonAtlased, 1858 fContext->getLayerCache())) { 1859 return false; 1860 } 1861 1862 GrReplacements replacements; 1863 1864 GrLayerHoister::DrawLayers(atlased, nonAtlased, &replacements); 1865 1866 // Render the entire picture using new layers 1867 GrRecordReplaceDraw(*mainPicture->fRecord, mainCanvas, mainPicture->fBBH.get(), 1868 &replacements, NULL); 1869 1870 GrLayerHoister::UnlockLayers(fContext->getLayerCache(), atlased, nonAtlased); 1871 1872 return true; 1873 } 1874 1875 SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { 1876 // We always return a transient cache, so it is freed after each 1877 // filter traversal. 1878 return SkImageFilter::Cache::Create(kDefaultImageFilterCacheSize); 1879 } 1880