SkGpuDevice.cpp revision 46d3d39e65e0b3ea2ad7c91c176ccafb4df0fa24
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/GrTextureDomainEffect.h" 11#include "effects/GrSimpleTextureEffect.h" 12 13#include "GrContext.h" 14#include "GrTextContext.h" 15 16#include "SkGrTexturePixelRef.h" 17 18#include "SkColorFilter.h" 19#include "SkDeviceImageFilterProxy.h" 20#include "SkDrawProcs.h" 21#include "SkGlyphCache.h" 22#include "SkImageFilter.h" 23#include "SkPathEffect.h" 24#include "SkStroke.h" 25#include "SkUtils.h" 26 27#define CACHE_COMPATIBLE_DEVICE_TEXTURES 1 28 29#if 0 30 extern bool (*gShouldDrawProc)(); 31 #define CHECK_SHOULD_DRAW(draw, forceI) \ 32 do { \ 33 if (gShouldDrawProc && !gShouldDrawProc()) return; \ 34 this->prepareDraw(draw, forceI); \ 35 } while (0) 36#else 37 #define CHECK_SHOULD_DRAW(draw, forceI) this->prepareDraw(draw, forceI) 38#endif 39 40// we use the same texture slot on GrPaint for bitmaps and shaders 41// (since drawBitmap, drawSprite, and drawDevice ignore skia's shader) 42enum { 43 kBitmapTextureIdx = 0, 44 kShaderTextureIdx = 0, 45 kColorFilterTextureIdx = 1 46}; 47 48#define MAX_BLUR_SIGMA 4.0f 49// FIXME: This value comes from from SkBlurMaskFilter.cpp. 50// Should probably be put in a common header someplace. 51#define MAX_BLUR_RADIUS SkIntToScalar(128) 52// This constant approximates the scaling done in the software path's 53// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). 54// IMHO, it actually should be 1: we blur "less" than we should do 55// according to the CSS and canvas specs, simply because Safari does the same. 56// Firefox used to do the same too, until 4.0 where they fixed it. So at some 57// point we should probably get rid of these scaling constants and rebaseline 58// all the blur tests. 59#define BLUR_SIGMA_SCALE 0.6f 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 SkFloatToScalar(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_NODRAW_ANNOTATION(paint) \ 75 do { if (paint.isNoDrawAnnotation()) { return; } } while (0) 76 77/////////////////////////////////////////////////////////////////////////////// 78 79 80class SkGpuDevice::SkAutoCachedTexture : public ::SkNoncopyable { 81public: 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 GrAssert(NULL != texture); 94 *texture = this->set(device, bitmap, params); 95 } 96 97 ~SkAutoCachedTexture() { 98 if (NULL != fTexture) { 99 GrUnlockCachedBitmapTexture(fTexture); 100 } 101 } 102 103 GrTexture* set(SkGpuDevice* device, 104 const SkBitmap& bitmap, 105 const GrTextureParams* params) { 106 if (NULL != fTexture) { 107 GrUnlockCachedBitmapTexture(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 = GrLockCachedBitmapTexture(device->context(), bitmap, params); 115 result = fTexture; 116 } 117 return result; 118 } 119 120private: 121 SkGpuDevice* fDevice; 122 GrTexture* fTexture; 123}; 124 125/////////////////////////////////////////////////////////////////////////////// 126 127struct GrSkDrawProcs : public SkDrawProcs { 128public: 129 GrContext* fContext; 130 GrTextContext* fTextContext; 131 GrFontScaler* fFontScaler; // cached in the skia glyphcache 132}; 133 134/////////////////////////////////////////////////////////////////////////////// 135 136static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) { 137 switch (config) { 138 case kAlpha_8_GrPixelConfig: 139 *isOpaque = false; 140 return SkBitmap::kA8_Config; 141 case kRGB_565_GrPixelConfig: 142 *isOpaque = true; 143 return SkBitmap::kRGB_565_Config; 144 case kRGBA_4444_GrPixelConfig: 145 *isOpaque = false; 146 return SkBitmap::kARGB_4444_Config; 147 case kSkia8888_PM_GrPixelConfig: 148 // we don't currently have a way of knowing whether 149 // a 8888 is opaque based on the config. 150 *isOpaque = false; 151 return SkBitmap::kARGB_8888_Config; 152 default: 153 *isOpaque = false; 154 return SkBitmap::kNo_Config; 155 } 156} 157 158static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) { 159 GrPixelConfig config = renderTarget->config(); 160 161 bool isOpaque; 162 SkBitmap bitmap; 163 bitmap.setConfig(grConfig2skConfig(config, &isOpaque), 164 renderTarget->width(), renderTarget->height()); 165 bitmap.setIsOpaque(isOpaque); 166 return bitmap; 167} 168 169SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture) 170: SkDevice(make_bitmap(context, texture->asRenderTarget())) { 171 this->initFromRenderTarget(context, texture->asRenderTarget(), false); 172} 173 174SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget) 175: SkDevice(make_bitmap(context, renderTarget)) { 176 this->initFromRenderTarget(context, renderTarget, false); 177} 178 179void SkGpuDevice::initFromRenderTarget(GrContext* context, 180 GrRenderTarget* renderTarget, 181 bool cached) { 182 fDrawProcs = NULL; 183 184 fContext = context; 185 fContext->ref(); 186 187 fRenderTarget = NULL; 188 fNeedClear = false; 189 190 GrAssert(NULL != renderTarget); 191 fRenderTarget = renderTarget; 192 fRenderTarget->ref(); 193 194 // Hold onto to the texture in the pixel ref (if there is one) because the texture holds a ref 195 // on the RT but not vice-versa. 196 // TODO: Remove this trickery once we figure out how to make SkGrPixelRef do this without 197 // busting chrome (for a currently unknown reason). 198 GrSurface* surface = fRenderTarget->asTexture(); 199 if (NULL == surface) { 200 surface = fRenderTarget; 201 } 202 SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (surface, cached)); 203 204 this->setPixelRef(pr, 0)->unref(); 205} 206 207SkGpuDevice::SkGpuDevice(GrContext* context, 208 SkBitmap::Config config, 209 int width, 210 int height, 211 int sampleCount) 212 : SkDevice(config, width, height, false /*isOpaque*/) { 213 214 fDrawProcs = NULL; 215 216 fContext = context; 217 fContext->ref(); 218 219 fRenderTarget = NULL; 220 fNeedClear = false; 221 222 if (config != SkBitmap::kRGB_565_Config) { 223 config = SkBitmap::kARGB_8888_Config; 224 } 225 226 GrTextureDesc desc; 227 desc.fFlags = kRenderTarget_GrTextureFlagBit; 228 desc.fWidth = width; 229 desc.fHeight = height; 230 desc.fConfig = SkBitmapConfig2GrPixelConfig(config); 231 desc.fSampleCnt = sampleCount; 232 233 SkAutoTUnref<GrTexture> texture(fContext->createUncachedTexture(desc, NULL, 0)); 234 235 if (NULL != texture) { 236 fRenderTarget = texture->asRenderTarget(); 237 fRenderTarget->ref(); 238 239 GrAssert(NULL != fRenderTarget); 240 241 // wrap the bitmap with a pixelref to expose our texture 242 SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (texture)); 243 this->setPixelRef(pr, 0)->unref(); 244 } else { 245 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n", 246 width, height); 247 GrAssert(false); 248 } 249} 250 251SkGpuDevice::~SkGpuDevice() { 252 if (fDrawProcs) { 253 delete fDrawProcs; 254 } 255 256 // The GrContext takes a ref on the target. We don't want to cause the render 257 // target to be unnecessarily kept alive. 258 if (fContext->getRenderTarget() == fRenderTarget) { 259 fContext->setRenderTarget(NULL); 260 } 261 262 if (fContext->getClip() == &fClipData) { 263 fContext->setClip(NULL); 264 } 265 266 SkSafeUnref(fRenderTarget); 267 fContext->unref(); 268} 269 270/////////////////////////////////////////////////////////////////////////////// 271 272void SkGpuDevice::makeRenderTargetCurrent() { 273 DO_DEFERRED_CLEAR(); 274 fContext->setRenderTarget(fRenderTarget); 275} 276 277/////////////////////////////////////////////////////////////////////////////// 278 279namespace { 280GrPixelConfig config8888_to_grconfig_and_flags(SkCanvas::Config8888 config8888, uint32_t* flags) { 281 switch (config8888) { 282 case SkCanvas::kNative_Premul_Config8888: 283 *flags = 0; 284 return kSkia8888_GrPixelConfig; 285 case SkCanvas::kNative_Unpremul_Config8888: 286 *flags = GrContext::kUnpremul_PixelOpsFlag; 287 return kSkia8888_PM_GrPixelConfig; 288 case SkCanvas::kBGRA_Premul_Config8888: 289 *flags = 0; 290 return kBGRA_8888_GrPixelConfig; 291 case SkCanvas::kBGRA_Unpremul_Config8888: 292 *flags = GrContext::kUnpremul_PixelOpsFlag; 293 return kBGRA_8888_GrPixelConfig; 294 case SkCanvas::kRGBA_Premul_Config8888: 295 *flags = 0; 296 return kRGBA_8888_GrPixelConfig; 297 case SkCanvas::kRGBA_Unpremul_Config8888: 298 *flags = GrContext::kUnpremul_PixelOpsFlag; 299 return kRGBA_8888_GrPixelConfig; 300 default: 301 GrCrash("Unexpected Config8888."); 302 *flags = 0; // suppress warning 303 return kSkia8888_PM_GrPixelConfig; 304 } 305} 306} 307 308bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap, 309 int x, int y, 310 SkCanvas::Config8888 config8888) { 311 DO_DEFERRED_CLEAR(); 312 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 313 SkASSERT(!bitmap.isNull()); 314 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); 315 316 SkAutoLockPixels alp(bitmap); 317 GrPixelConfig config; 318 uint32_t flags; 319 config = config8888_to_grconfig_and_flags(config8888, &flags); 320 return fContext->readRenderTargetPixels(fRenderTarget, 321 x, y, 322 bitmap.width(), 323 bitmap.height(), 324 config, 325 bitmap.getPixels(), 326 bitmap.rowBytes(), 327 flags); 328} 329 330void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y, 331 SkCanvas::Config8888 config8888) { 332 SkAutoLockPixels alp(bitmap); 333 if (!bitmap.readyToDraw()) { 334 return; 335 } 336 337 GrPixelConfig config; 338 uint32_t flags; 339 if (SkBitmap::kARGB_8888_Config == bitmap.config()) { 340 config = config8888_to_grconfig_and_flags(config8888, &flags); 341 } else { 342 flags = 0; 343 config= SkBitmapConfig2GrPixelConfig(bitmap.config()); 344 } 345 346 fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(), 347 config, bitmap.getPixels(), bitmap.rowBytes(), flags); 348} 349 350namespace { 351void purgeClipCB(int genID, void* ) { 352 353 if (SkClipStack::kInvalidGenID == genID || 354 SkClipStack::kEmptyGenID == genID || 355 SkClipStack::kWideOpenGenID == genID) { 356 // none of these cases will have a cached clip mask 357 return; 358 } 359 360} 361}; 362 363void SkGpuDevice::onAttachToCanvas(SkCanvas* canvas) { 364 INHERITED::onAttachToCanvas(canvas); 365 366 // Canvas promises that this ptr is valid until onDetachFromCanvas is called 367 fClipData.fClipStack = canvas->getClipStack(); 368 369 fClipData.fClipStack->addPurgeClipCallback(purgeClipCB, fContext); 370} 371 372void SkGpuDevice::onDetachFromCanvas() { 373 INHERITED::onDetachFromCanvas(); 374 375 // TODO: iterate through the clip stack and clean up any cached clip masks 376 fClipData.fClipStack->removePurgeClipCallback(purgeClipCB, fContext); 377 378 fClipData.fClipStack = NULL; 379} 380 381#ifdef SK_DEBUG 382static void check_bounds(const GrClipData& clipData, 383 const SkRegion& clipRegion, 384 int renderTargetWidth, 385 int renderTargetHeight) { 386 387 SkIRect devBound; 388 389 devBound.setLTRB(0, 0, renderTargetWidth, renderTargetHeight); 390 391 SkClipStack::BoundsType boundType; 392 SkRect canvTemp; 393 394 clipData.fClipStack->getBounds(&canvTemp, &boundType); 395 if (SkClipStack::kNormal_BoundsType == boundType) { 396 SkIRect devTemp; 397 398 canvTemp.roundOut(&devTemp); 399 400 devTemp.offset(-clipData.fOrigin.fX, -clipData.fOrigin.fY); 401 402 if (!devBound.intersect(devTemp)) { 403 devBound.setEmpty(); 404 } 405 } 406 407 GrAssert(devBound.contains(clipRegion.getBounds())); 408} 409#endif 410 411/////////////////////////////////////////////////////////////////////////////// 412 413// call this every draw call, to ensure that the context reflects our state, 414// and not the state from some other canvas/device 415void SkGpuDevice::prepareDraw(const SkDraw& draw, bool forceIdentity) { 416 GrAssert(NULL != fClipData.fClipStack); 417 418 fContext->setRenderTarget(fRenderTarget); 419 420 SkASSERT(draw.fClipStack && draw.fClipStack == fClipData.fClipStack); 421 422 if (forceIdentity) { 423 fContext->setIdentityMatrix(); 424 } else { 425 fContext->setMatrix(*draw.fMatrix); 426 } 427 fClipData.fOrigin = this->getOrigin(); 428 429#ifdef SK_DEBUG 430 check_bounds(fClipData, *draw.fClip, fRenderTarget->width(), fRenderTarget->height()); 431#endif 432 433 fContext->setClip(&fClipData); 434 435 DO_DEFERRED_CLEAR(); 436} 437 438SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() { 439 DO_DEFERRED_CLEAR(); 440 return (SkGpuRenderTarget*)fRenderTarget; 441} 442 443bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) { 444 GrTexture* texture = fRenderTarget->asTexture(); 445 if (NULL != texture) { 446 paint->colorStage(kBitmapTextureIdx)->setEffect( 447 GrSimpleTextureEffect::Create(texture, SkMatrix::I()))->unref(); 448 return true; 449 } 450 return false; 451} 452 453/////////////////////////////////////////////////////////////////////////////// 454 455SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch); 456SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch); 457SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch); 458SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch); 459SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4, 460 shader_type_mismatch); 461SK_COMPILE_ASSERT(SkShader::kTwoPointConical_BitmapType == 5, 462 shader_type_mismatch); 463SK_COMPILE_ASSERT(SkShader::kLinear_BitmapType == 6, shader_type_mismatch); 464SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 6, shader_type_mismatch); 465 466namespace { 467 468// converts a SkPaint to a GrPaint, ignoring the skPaint's shader 469// justAlpha indicates that skPaint's alpha should be used rather than the color 470// Callers may subsequently modify the GrPaint. Setting constantColor indicates 471// that the final paint will draw the same color at every pixel. This allows 472// an optimization where the the color filter can be applied to the skPaint's 473// color once while converting to GrPaint and then ignored. 474inline bool skPaint2GrPaintNoShader(SkGpuDevice* dev, 475 const SkPaint& skPaint, 476 bool justAlpha, 477 bool constantColor, 478 GrPaint* grPaint) { 479 480 grPaint->setDither(skPaint.isDither()); 481 grPaint->setAntiAlias(skPaint.isAntiAlias()); 482 483 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff; 484 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff; 485 486 SkXfermode* mode = skPaint.getXfermode(); 487 if (mode) { 488 if (!mode->asCoeff(&sm, &dm)) { 489 //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");) 490#if 0 491 return false; 492#endif 493 } 494 } 495 grPaint->setBlendFunc(sk_blend_to_grblend(sm), sk_blend_to_grblend(dm)); 496 497 if (justAlpha) { 498 uint8_t alpha = skPaint.getAlpha(); 499 grPaint->setColor(GrColorPackRGBA(alpha, alpha, alpha, alpha)); 500 // justAlpha is currently set to true only if there is a texture, 501 // so constantColor should not also be true. 502 GrAssert(!constantColor); 503 } else { 504 grPaint->setColor(SkColor2GrColor(skPaint.getColor())); 505 GrAssert(!grPaint->isColorStageEnabled(kShaderTextureIdx)); 506 } 507 508 SkColorFilter* colorFilter = skPaint.getColorFilter(); 509 if (NULL != colorFilter) { 510 // if the source color is a constant then apply the filter here once rather than per pixel 511 // in a shader. 512 if (constantColor) { 513 SkColor filtered = colorFilter->filterColor(skPaint.getColor()); 514 grPaint->setColor(SkColor2GrColor(filtered)); 515 } else { 516 SkAutoTUnref<GrEffectRef> effect(colorFilter->asNewEffect(dev->context())); 517 if (NULL != effect.get()) { 518 grPaint->colorStage(kColorFilterTextureIdx)->setEffect(effect); 519 } else { 520 // TODO: rewrite this using asNewEffect() 521 SkColor color; 522 SkXfermode::Mode filterMode; 523 if (colorFilter->asColorMode(&color, &filterMode)) { 524 grPaint->setXfermodeColorFilter(filterMode, SkColor2GrColor(color)); 525 } 526 } 527 } 528 } 529 530 return true; 531} 532 533// This function is similar to skPaint2GrPaintNoShader but also converts 534// skPaint's shader to a GrTexture/GrEffectStage if possible. The texture to 535// be used is set on grPaint and returned in param act. constantColor has the 536// same meaning as in skPaint2GrPaintNoShader. 537inline bool skPaint2GrPaintShader(SkGpuDevice* dev, 538 const SkPaint& skPaint, 539 bool constantColor, 540 GrPaint* grPaint) { 541 SkShader* shader = skPaint.getShader(); 542 if (NULL == shader) { 543 return skPaint2GrPaintNoShader(dev, skPaint, false, constantColor, grPaint); 544 } else if (!skPaint2GrPaintNoShader(dev, skPaint, true, false, grPaint)) { 545 return false; 546 } 547 548 SkAutoTUnref<GrEffectRef> effect(shader->asNewEffect(dev->context(), skPaint)); 549 if (NULL != effect.get()) { 550 grPaint->colorStage(kShaderTextureIdx)->setEffect(effect); 551 return true; 552 } 553 554 // We still don't have SkColorShader::asNewEffect() implemented. 555 SkShader::GradientInfo info; 556 SkColor color; 557 558 info.fColors = &color; 559 info.fColorOffsets = NULL; 560 info.fColorCount = 1; 561 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) { 562 SkPaint copy(skPaint); 563 copy.setShader(NULL); 564 // modulate the paint alpha by the shader's solid color alpha 565 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha()); 566 copy.setColor(SkColorSetA(color, newA)); 567 return skPaint2GrPaintNoShader(dev, copy, false, constantColor, grPaint); 568 } 569 return false; 570} 571} 572 573/////////////////////////////////////////////////////////////////////////////// 574void SkGpuDevice::clear(SkColor color) { 575 fContext->clear(NULL, SkColor2GrColor(color), fRenderTarget); 576 fNeedClear = false; 577} 578 579void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 580 CHECK_SHOULD_DRAW(draw, false); 581 582 GrPaint grPaint; 583 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 584 return; 585 } 586 587 fContext->drawPaint(grPaint); 588} 589 590// must be in SkCanvas::PointMode order 591static const GrPrimitiveType gPointMode2PrimtiveType[] = { 592 kPoints_GrPrimitiveType, 593 kLines_GrPrimitiveType, 594 kLineStrip_GrPrimitiveType 595}; 596 597void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 598 size_t count, const SkPoint pts[], const SkPaint& paint) { 599 CHECK_SHOULD_DRAW(draw, false); 600 601 SkScalar width = paint.getStrokeWidth(); 602 if (width < 0) { 603 return; 604 } 605 606 // we only handle hairlines and paints without path effects or mask filters, 607 // else we let the SkDraw call our drawPath() 608 if (width > 0 || paint.getPathEffect() || paint.getMaskFilter()) { 609 draw.drawPoints(mode, count, pts, paint, true); 610 return; 611 } 612 613 GrPaint grPaint; 614 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 615 return; 616 } 617 618 fContext->drawVertices(grPaint, 619 gPointMode2PrimtiveType[mode], 620 count, 621 (GrPoint*)pts, 622 NULL, 623 NULL, 624 NULL, 625 0); 626} 627 628/////////////////////////////////////////////////////////////////////////////// 629 630void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, 631 const SkPaint& paint) { 632 CHECK_FOR_NODRAW_ANNOTATION(paint); 633 CHECK_SHOULD_DRAW(draw, false); 634 635 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 636 SkScalar width = paint.getStrokeWidth(); 637 638 /* 639 We have special code for hairline strokes, miter-strokes, and fills. 640 Anything else we just call our path code. 641 */ 642 bool usePath = doStroke && width > 0 && 643 paint.getStrokeJoin() != SkPaint::kMiter_Join; 644 // another two reasons we might need to call drawPath... 645 if (paint.getMaskFilter() || paint.getPathEffect()) { 646 usePath = true; 647 } 648 // until we aa rotated rects... 649 if (!usePath && paint.isAntiAlias() && !fContext->getMatrix().rectStaysRect()) { 650 usePath = true; 651 } 652 // small miter limit means right angles show bevel... 653 if (SkPaint::kMiter_Join == paint.getStrokeJoin() && 654 paint.getStrokeMiter() < SK_ScalarSqrt2) 655 { 656 usePath = true; 657 } 658 // until we can both stroke and fill rectangles 659 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) { 660 usePath = true; 661 } 662 663 if (usePath) { 664 SkPath path; 665 path.addRect(rect); 666 this->drawPath(draw, path, paint, NULL, true); 667 return; 668 } 669 670 GrPaint grPaint; 671 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 672 return; 673 } 674 fContext->drawRect(grPaint, rect, doStroke ? width : -1); 675} 676 677/////////////////////////////////////////////////////////////////////////////// 678 679void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, 680 const SkPaint& paint) { 681 CHECK_FOR_NODRAW_ANNOTATION(paint); 682 CHECK_SHOULD_DRAW(draw, false); 683 684 bool usePath = false; 685 // some basic reasons we might need to call drawPath... 686 if (paint.getMaskFilter() || paint.getPathEffect()) { 687 usePath = true; 688 } 689 690 if (usePath) { 691 SkPath path; 692 path.addOval(oval); 693 this->drawPath(draw, path, paint, NULL, true); 694 return; 695 } 696 697 GrPaint grPaint; 698 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 699 return; 700 } 701 SkStrokeRec stroke(paint); 702 703 fContext->drawOval(grPaint, oval, stroke); 704} 705 706#include "SkMaskFilter.h" 707#include "SkBounder.h" 708 709/////////////////////////////////////////////////////////////////////////////// 710 711// helpers for applying mask filters 712namespace { 713 714// We prefer to blur small rect with small radius via CPU. 715#define MIN_GPU_BLUR_SIZE SkIntToScalar(64) 716#define MIN_GPU_BLUR_RADIUS SkIntToScalar(32) 717inline bool shouldDrawBlurWithCPU(const SkRect& rect, SkScalar radius) { 718 if (rect.width() <= MIN_GPU_BLUR_SIZE && 719 rect.height() <= MIN_GPU_BLUR_SIZE && 720 radius <= MIN_GPU_BLUR_RADIUS) { 721 return true; 722 } 723 return false; 724} 725 726bool drawWithGPUMaskFilter(GrContext* context, const SkPath& devPath, const SkStrokeRec& stroke, 727 SkMaskFilter* filter, const SkRegion& clip, 728 SkBounder* bounder, GrPaint* grp) { 729 SkMaskFilter::BlurInfo info; 730 SkMaskFilter::BlurType blurType = filter->asABlur(&info); 731 if (SkMaskFilter::kNone_BlurType == blurType) { 732 return false; 733 } 734 SkScalar radius = info.fIgnoreTransform ? info.fRadius 735 : context->getMatrix().mapRadius(info.fRadius); 736 radius = SkMinScalar(radius, MAX_BLUR_RADIUS); 737 if (radius <= 0) { 738 return false; 739 } 740 741 SkRect srcRect = devPath.getBounds(); 742 if (shouldDrawBlurWithCPU(srcRect, radius)) { 743 return false; 744 } 745 746 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE; 747 float sigma3 = sigma * 3.0f; 748 749 SkRect clipRect; 750 clipRect.set(clip.getBounds()); 751 752 // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area. 753 srcRect.inset(SkFloatToScalar(-sigma3), SkFloatToScalar(-sigma3)); 754 clipRect.inset(SkFloatToScalar(-sigma3), SkFloatToScalar(-sigma3)); 755 srcRect.intersect(clipRect); 756 SkRect finalRect = srcRect; 757 SkIRect finalIRect; 758 finalRect.roundOut(&finalIRect); 759 if (clip.quickReject(finalIRect)) { 760 return true; 761 } 762 if (bounder && !bounder->doIRect(finalIRect)) { 763 return true; 764 } 765 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop); 766 srcRect.offset(offset); 767 GrTextureDesc desc; 768 desc.fFlags = kRenderTarget_GrTextureFlagBit; 769 desc.fWidth = SkScalarCeilToInt(srcRect.width()); 770 desc.fHeight = SkScalarCeilToInt(srcRect.height()); 771 // We actually only need A8, but it often isn't supported as a 772 // render target so default to RGBA_8888 773 desc.fConfig = kRGBA_8888_GrPixelConfig; 774 775 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig)) { 776 desc.fConfig = kAlpha_8_GrPixelConfig; 777 } 778 779 GrAutoScratchTexture pathEntry(context, desc); 780 GrTexture* pathTexture = pathEntry.texture(); 781 if (NULL == pathTexture) { 782 return false; 783 } 784 785 SkAutoTUnref<GrTexture> blurTexture; 786 787 { 788 GrContext::AutoRenderTarget art(context, pathTexture->asRenderTarget()); 789 GrContext::AutoClip ac(context, srcRect); 790 791 context->clear(NULL, 0); 792 793 GrPaint tempPaint; 794 if (grp->isAntiAlias()) { 795 tempPaint.setAntiAlias(true); 796 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst 797 // blend coeff of zero requires dual source blending support in order 798 // to properly blend partially covered pixels. This means the AA 799 // code path may not be taken. So we use a dst blend coeff of ISA. We 800 // could special case AA draws to a dst surface with known alpha=0 to 801 // use a zero dst coeff when dual source blending isn't available.f 802 tempPaint.setBlendFunc(kOne_GrBlendCoeff, kISC_GrBlendCoeff); 803 } 804 805 GrContext::AutoMatrix am; 806 807 // Draw hard shadow to pathTexture with path top-left at origin using tempPaint. 808 SkMatrix translate; 809 translate.setTranslate(offset.fX, offset.fY); 810 am.set(context, translate); 811 context->drawPath(tempPaint, devPath, stroke); 812 813 // If we're doing a normal blur, we can clobber the pathTexture in the 814 // gaussianBlur. Otherwise, we need to save it for later compositing. 815 bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType; 816 blurTexture.reset(context->gaussianBlur(pathTexture, isNormalBlur, 817 srcRect, sigma, sigma)); 818 if (NULL == blurTexture) { 819 return false; 820 } 821 822 if (!isNormalBlur) { 823 context->setIdentityMatrix(); 824 GrPaint paint; 825 SkMatrix matrix; 826 matrix.setIDiv(pathTexture->width(), pathTexture->height()); 827 // Blend pathTexture over blurTexture. 828 context->setRenderTarget(blurTexture->asRenderTarget()); 829 paint.colorStage(0)->setEffect( 830 GrSimpleTextureEffect::Create(pathTexture, matrix))->unref(); 831 if (SkMaskFilter::kInner_BlurType == blurType) { 832 // inner: dst = dst * src 833 paint.setBlendFunc(kDC_GrBlendCoeff, kZero_GrBlendCoeff); 834 } else if (SkMaskFilter::kSolid_BlurType == blurType) { 835 // solid: dst = src + dst - src * dst 836 // = (1 - dst) * src + 1 * dst 837 paint.setBlendFunc(kIDC_GrBlendCoeff, kOne_GrBlendCoeff); 838 } else if (SkMaskFilter::kOuter_BlurType == blurType) { 839 // outer: dst = dst * (1 - src) 840 // = 0 * src + (1 - src) * dst 841 paint.setBlendFunc(kZero_GrBlendCoeff, kISC_GrBlendCoeff); 842 } 843 context->drawRect(paint, srcRect); 844 } 845 } 846 847 GrContext::AutoMatrix am; 848 if (!am.setIdentity(context, grp)) { 849 return false; 850 } 851 852 static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1; 853 // we assume the last mask index is available for use 854 GrAssert(!grp->isCoverageStageEnabled(MASK_IDX)); 855 856 SkMatrix matrix; 857 matrix.setTranslate(-finalRect.fLeft, -finalRect.fTop); 858 matrix.postIDiv(blurTexture->width(), blurTexture->height()); 859 860 grp->coverageStage(MASK_IDX)->reset(); 861 grp->coverageStage(MASK_IDX)->setEffect( 862 GrSimpleTextureEffect::Create(blurTexture, matrix))->unref(); 863 context->drawRect(*grp, finalRect); 864 return true; 865} 866 867bool drawWithMaskFilter(GrContext* context, const SkPath& devPath, 868 SkMaskFilter* filter, const SkRegion& clip, SkBounder* bounder, 869 GrPaint* grp, SkPaint::Style style) { 870 SkMask srcM, dstM; 871 872 if (!SkDraw::DrawToMask(devPath, &clip.getBounds(), filter, &context->getMatrix(), &srcM, 873 SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) { 874 return false; 875 } 876 SkAutoMaskFreeImage autoSrc(srcM.fImage); 877 878 if (!filter->filterMask(&dstM, srcM, context->getMatrix(), NULL)) { 879 return false; 880 } 881 // this will free-up dstM when we're done (allocated in filterMask()) 882 SkAutoMaskFreeImage autoDst(dstM.fImage); 883 884 if (clip.quickReject(dstM.fBounds)) { 885 return false; 886 } 887 if (bounder && !bounder->doIRect(dstM.fBounds)) { 888 return false; 889 } 890 891 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using 892 // the current clip (and identity matrix) and GrPaint settings 893 GrContext::AutoMatrix am; 894 am.setIdentity(context, grp); 895 896 GrTextureDesc desc; 897 desc.fWidth = dstM.fBounds.width(); 898 desc.fHeight = dstM.fBounds.height(); 899 desc.fConfig = kAlpha_8_GrPixelConfig; 900 901 GrAutoScratchTexture ast(context, desc); 902 GrTexture* texture = ast.texture(); 903 904 if (NULL == texture) { 905 return false; 906 } 907 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, 908 dstM.fImage, dstM.fRowBytes); 909 910 static const int MASK_IDX = GrPaint::kMaxCoverageStages - 1; 911 // we assume the last mask index is available for use 912 GrAssert(!grp->isCoverageStageEnabled(MASK_IDX)); 913 914 SkMatrix m; 915 m.setTranslate(-dstM.fBounds.fLeft*SK_Scalar1, -dstM.fBounds.fTop*SK_Scalar1); 916 m.postIDiv(texture->width(), texture->height()); 917 918 grp->coverageStage(MASK_IDX)->setEffect(GrSimpleTextureEffect::Create(texture, m))->unref(); 919 GrRect d; 920 d.setLTRB(SkIntToScalar(dstM.fBounds.fLeft), 921 SkIntToScalar(dstM.fBounds.fTop), 922 SkIntToScalar(dstM.fBounds.fRight), 923 SkIntToScalar(dstM.fBounds.fBottom)); 924 925 context->drawRect(*grp, d); 926 return true; 927} 928 929} 930 931/////////////////////////////////////////////////////////////////////////////// 932 933void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, 934 const SkPaint& paint, const SkMatrix* prePathMatrix, 935 bool pathIsMutable) { 936 CHECK_FOR_NODRAW_ANNOTATION(paint); 937 CHECK_SHOULD_DRAW(draw, false); 938 939 GrPaint grPaint; 940 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 941 return; 942 } 943 944 // can we cheat, and treat a thin stroke as a hairline w/ coverage 945 // if we can, we draw lots faster (raster device does this same test) 946 SkScalar hairlineCoverage; 947 bool doHairLine = SkDrawTreatAsHairline(paint, fContext->getMatrix(), &hairlineCoverage); 948 if (doHairLine) { 949 grPaint.setCoverage(SkScalarRoundToInt(hairlineCoverage * grPaint.getCoverage())); 950 } 951 952 // If we have a prematrix, apply it to the path, optimizing for the case 953 // where the original path can in fact be modified in place (even though 954 // its parameter type is const). 955 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); 956 SkPath tmpPath, effectPath; 957 958 if (prePathMatrix) { 959 SkPath* result = pathPtr; 960 961 if (!pathIsMutable) { 962 result = &tmpPath; 963 pathIsMutable = true; 964 } 965 // should I push prePathMatrix on our MV stack temporarily, instead 966 // of applying it here? See SkDraw.cpp 967 pathPtr->transform(*prePathMatrix, result); 968 pathPtr = result; 969 } 970 // at this point we're done with prePathMatrix 971 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 972 973 SkStrokeRec stroke(paint); 974 SkPathEffect* pathEffect = paint.getPathEffect(); 975 if (pathEffect && pathEffect->filterPath(&effectPath, *pathPtr, &stroke)) { 976 pathPtr = &effectPath; 977 } 978 979 if (!pathEffect && doHairLine) { 980 stroke.setHairlineStyle(); 981 } 982 983 if (paint.getMaskFilter()) { 984 if (!stroke.isHairlineStyle()) { 985 if (stroke.applyToPath(&tmpPath, *pathPtr)) { 986 pathPtr = &tmpPath; 987 stroke.setFillStyle(); 988 } 989 } 990 991 // avoid possibly allocating a new path in transform if we can 992 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 993 994 // transform the path into device space 995 pathPtr->transform(fContext->getMatrix(), devPathPtr); 996 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, stroke, paint.getMaskFilter(), 997 *draw.fClip, draw.fBounder, &grPaint)) { 998 SkPaint::Style style = stroke.isHairlineStyle() ? SkPaint::kStroke_Style : 999 SkPaint::kFill_Style; 1000 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(), 1001 *draw.fClip, draw.fBounder, &grPaint, style); 1002 } 1003 return; 1004 } 1005 1006 fContext->drawPath(grPaint, *pathPtr, stroke); 1007} 1008 1009namespace { 1010 1011inline int get_tile_count(int l, int t, int r, int b, int tileSize) { 1012 int tilesX = (r / tileSize) - (l / tileSize) + 1; 1013 int tilesY = (b / tileSize) - (t / tileSize) + 1; 1014 return tilesX * tilesY; 1015} 1016 1017inline int determine_tile_size(const SkBitmap& bitmap, 1018 const SkRect& src, 1019 int maxTextureSize) { 1020 static const int kSmallTileSize = 1 << 10; 1021 if (maxTextureSize <= kSmallTileSize) { 1022 return maxTextureSize; 1023 } 1024 1025 size_t maxTexTotalTileSize; 1026 size_t smallTotalTileSize; 1027 1028 SkIRect iSrc; 1029 src.roundOut(&iSrc); 1030 1031 maxTexTotalTileSize = get_tile_count(iSrc.fLeft, 1032 iSrc.fTop, 1033 iSrc.fRight, 1034 iSrc.fBottom, 1035 maxTextureSize); 1036 smallTotalTileSize = get_tile_count(iSrc.fLeft, 1037 iSrc.fTop, 1038 iSrc.fRight, 1039 iSrc.fBottom, 1040 kSmallTileSize); 1041 1042 maxTexTotalTileSize *= maxTextureSize * maxTextureSize; 1043 smallTotalTileSize *= kSmallTileSize * kSmallTileSize; 1044 1045 if (maxTexTotalTileSize > 2 * smallTotalTileSize) { 1046 return kSmallTileSize; 1047 } else { 1048 return maxTextureSize; 1049 } 1050} 1051} 1052 1053bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, 1054 const GrTextureParams& params, 1055 const SkRect* srcRectPtr) const { 1056 // if bitmap is explictly texture backed then just use the texture 1057 if (NULL != bitmap.getTexture()) { 1058 return false; 1059 } 1060 // if it's larger than the max texture size, then we have no choice but 1061 // tiling 1062 const int maxTextureSize = fContext->getMaxTextureSize(); 1063 if (bitmap.width() > maxTextureSize || 1064 bitmap.height() > maxTextureSize) { 1065 return true; 1066 } 1067 // if we are going to have to draw the whole thing, then don't tile 1068 if (NULL == srcRectPtr) { 1069 return false; 1070 } 1071 // if the entire texture is already in our cache then no reason to tile it 1072 if (GrIsBitmapInCache(fContext, bitmap, ¶ms)) { 1073 return false; 1074 } 1075 1076 // At this point we know we could do the draw by uploading the entire bitmap 1077 // as a texture. However, if the texture would be large compared to the 1078 // cache size and we don't require most of it for this draw then tile to 1079 // reduce the amount of upload and cache spill. 1080 1081 // assumption here is that sw bitmap size is a good proxy for its size as 1082 // a texture 1083 size_t bmpSize = bitmap.getSize(); 1084 size_t cacheSize; 1085 fContext->getTextureCacheLimits(NULL, &cacheSize); 1086 if (bmpSize < cacheSize / 2) { 1087 return false; 1088 } 1089 1090 SkScalar fracUsed = SkScalarMul(srcRectPtr->width() / bitmap.width(), 1091 srcRectPtr->height() / bitmap.height()); 1092 if (fracUsed <= SK_ScalarHalf) { 1093 return true; 1094 } else { 1095 return false; 1096 } 1097} 1098 1099void SkGpuDevice::drawBitmap(const SkDraw& draw, 1100 const SkBitmap& bitmap, 1101 const SkIRect* srcRectPtr, 1102 const SkMatrix& m, 1103 const SkPaint& paint) { 1104 1105 SkRect tmp; 1106 SkRect* tmpPtr = NULL; 1107 1108 // convert from SkIRect to SkRect 1109 if (NULL != srcRectPtr) { 1110 tmp.set(*srcRectPtr); 1111 tmpPtr = &tmp; 1112 } 1113 1114 // We cannot call drawBitmapRect here since 'm' could be anything 1115 this->drawBitmapCommon(draw, bitmap, tmpPtr, m, paint); 1116} 1117 1118void SkGpuDevice::drawBitmapCommon(const SkDraw& draw, 1119 const SkBitmap& bitmap, 1120 const SkRect* srcRectPtr, 1121 const SkMatrix& m, 1122 const SkPaint& paint) { 1123 CHECK_SHOULD_DRAW(draw, false); 1124 1125 SkRect srcRect; 1126 if (NULL == srcRectPtr) { 1127 srcRect.set(0, 0, SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height())); 1128 } else { 1129 srcRect = *srcRectPtr; 1130 } 1131 1132 if (paint.getMaskFilter()){ 1133 // Convert the bitmap to a shader so that the rect can be drawn 1134 // through drawRect, which supports mask filters. 1135 SkMatrix newM(m); 1136 SkBitmap tmp; // subset of bitmap, if necessary 1137 const SkBitmap* bitmapPtr = &bitmap; 1138 if (NULL != srcRectPtr) { 1139 SkIRect iSrc; 1140 srcRect.roundOut(&iSrc); 1141 if (!bitmap.extractSubset(&tmp, iSrc)) { 1142 return; // extraction failed 1143 } 1144 bitmapPtr = &tmp; 1145 srcRect.offset(SkIntToScalar(-iSrc.fLeft), SkIntToScalar(-iSrc.fTop)); 1146 // The source rect has changed so update the matrix 1147 newM.preTranslate(SkIntToScalar(iSrc.fLeft), SkIntToScalar(iSrc.fTop)); 1148 } 1149 1150 SkPaint paintWithTexture(paint); 1151 paintWithTexture.setShader(SkShader::CreateBitmapShader(*bitmapPtr, 1152 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); 1153 1154 // Transform 'newM' needs to be concatenated to the current matrix, 1155 // rather than transforming the primitive directly, so that 'newM' will 1156 // also affect the behavior of the mask filter. 1157 SkMatrix drawMatrix; 1158 drawMatrix.setConcat(fContext->getMatrix(), newM); 1159 SkDraw transformedDraw(draw); 1160 transformedDraw.fMatrix = &drawMatrix; 1161 1162 this->drawRect(transformedDraw, srcRect, paintWithTexture); 1163 1164 return; 1165 } 1166 1167 GrPaint grPaint; 1168 1169 bool alphaOnly = !(SkBitmap::kA8_Config == bitmap.config()); 1170 if (!skPaint2GrPaintNoShader(this, paint, alphaOnly, false, &grPaint)) { 1171 return; 1172 } 1173 GrTextureParams params; 1174 params.setBilerp(paint.isFilterBitmap()); 1175 1176 if (!this->shouldTileBitmap(bitmap, params, srcRectPtr)) { 1177 // take the simple case 1178 this->internalDrawBitmap(bitmap, srcRect, m, params, &grPaint); 1179 } else { 1180 this->drawTiledBitmap(bitmap, srcRect, m, params, &grPaint); 1181 } 1182} 1183 1184// Break 'bitmap' into several tiles to draw it since it has already 1185// been determined to be too large to fit in VRAM 1186void SkGpuDevice::drawTiledBitmap(const SkBitmap& bitmap, 1187 const SkRect& srcRect, 1188 const SkMatrix& m, 1189 const GrTextureParams& params, 1190 GrPaint* grPaint) { 1191 const int maxTextureSize = fContext->getMaxTextureSize(); 1192 1193 int tileSize = determine_tile_size(bitmap, srcRect, maxTextureSize); 1194 1195 // compute clip bounds in local coordinates 1196 SkRect clipRect; 1197 { 1198 const GrRenderTarget* rt = fContext->getRenderTarget(); 1199 clipRect.setWH(SkIntToScalar(rt->width()), SkIntToScalar(rt->height())); 1200 if (!fContext->getClip()->fClipStack->intersectRectWithClip(&clipRect)) { 1201 return; 1202 } 1203 SkMatrix matrix, inverse; 1204 matrix.setConcat(fContext->getMatrix(), m); 1205 if (!matrix.invert(&inverse)) { 1206 return; 1207 } 1208 inverse.mapRect(&clipRect); 1209 } 1210 1211 int nx = bitmap.width() / tileSize; 1212 int ny = bitmap.height() / tileSize; 1213 for (int x = 0; x <= nx; x++) { 1214 for (int y = 0; y <= ny; y++) { 1215 SkRect tileR; 1216 tileR.set(SkIntToScalar(x * tileSize), 1217 SkIntToScalar(y * tileSize), 1218 SkIntToScalar((x + 1) * tileSize), 1219 SkIntToScalar((y + 1) * tileSize)); 1220 1221 if (!SkRect::Intersects(tileR, clipRect)) { 1222 continue; 1223 } 1224 1225 if (!tileR.intersect(srcRect)) { 1226 continue; 1227 } 1228 1229 SkBitmap tmpB; 1230 SkIRect iTileR; 1231 tileR.roundOut(&iTileR); 1232 if (bitmap.extractSubset(&tmpB, iTileR)) { 1233 // now offset it to make it "local" to our tmp bitmap 1234 tileR.offset(SkIntToScalar(-iTileR.fLeft), SkIntToScalar(-iTileR.fTop)); 1235 SkMatrix tmpM(m); 1236 tmpM.preTranslate(SkIntToScalar(iTileR.fLeft), 1237 SkIntToScalar(iTileR.fTop)); 1238 1239 this->internalDrawBitmap(tmpB, tileR, tmpM, params, grPaint); 1240 } 1241 } 1242 } 1243} 1244 1245namespace { 1246 1247bool hasAlignedSamples(const SkRect& srcRect, const SkRect& transformedRect) { 1248 // detect pixel disalignment 1249 if (SkScalarAbs(SkScalarRoundToScalar(transformedRect.left()) - 1250 transformedRect.left()) < COLOR_BLEED_TOLERANCE && 1251 SkScalarAbs(SkScalarRoundToScalar(transformedRect.top()) - 1252 transformedRect.top()) < COLOR_BLEED_TOLERANCE && 1253 SkScalarAbs(transformedRect.width() - srcRect.width()) < 1254 COLOR_BLEED_TOLERANCE && 1255 SkScalarAbs(transformedRect.height() - srcRect.height()) < 1256 COLOR_BLEED_TOLERANCE) { 1257 return true; 1258 } 1259 return false; 1260} 1261 1262bool mayColorBleed(const SkRect& srcRect, const SkRect& transformedRect, 1263 const SkMatrix& m) { 1264 // Only gets called if hasAlignedSamples returned false. 1265 // So we can assume that sampling is axis aligned but not texel aligned. 1266 GrAssert(!hasAlignedSamples(srcRect, transformedRect)); 1267 SkRect innerSrcRect(srcRect), innerTransformedRect, 1268 outerTransformedRect(transformedRect); 1269 innerSrcRect.inset(SK_ScalarHalf, SK_ScalarHalf); 1270 m.mapRect(&innerTransformedRect, innerSrcRect); 1271 1272 // The gap between outerTransformedRect and innerTransformedRect 1273 // represents the projection of the source border area, which is 1274 // problematic for color bleeding. We must check whether any 1275 // destination pixels sample the border area. 1276 outerTransformedRect.inset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE); 1277 innerTransformedRect.outset(COLOR_BLEED_TOLERANCE, COLOR_BLEED_TOLERANCE); 1278 SkIRect outer, inner; 1279 outerTransformedRect.round(&outer); 1280 innerTransformedRect.round(&inner); 1281 // If the inner and outer rects round to the same result, it means the 1282 // border does not overlap any pixel centers. Yay! 1283 return inner != outer; 1284} 1285 1286} // unnamed namespace 1287 1288/* 1289 * This is called by drawBitmap(), which has to handle images that may be too 1290 * large to be represented by a single texture. 1291 * 1292 * internalDrawBitmap assumes that the specified bitmap will fit in a texture 1293 * and that non-texture portion of the GrPaint has already been setup. 1294 */ 1295void SkGpuDevice::internalDrawBitmap(const SkBitmap& bitmap, 1296 const SkRect& srcRect, 1297 const SkMatrix& m, 1298 const GrTextureParams& params, 1299 GrPaint* grPaint) { 1300 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() && 1301 bitmap.height() <= fContext->getMaxTextureSize()); 1302 1303 SkAutoLockPixels alp(bitmap, !bitmap.getTexture()); 1304 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1305 SkDebugf("nothing to draw\n"); 1306 return; 1307 } 1308 1309 GrTexture* texture; 1310 SkAutoCachedTexture act(this, bitmap, ¶ms, &texture); 1311 if (NULL == texture) { 1312 return; 1313 } 1314 1315 GrRect dstRect(srcRect); 1316 GrRect paintRect; 1317 SkScalar wInv = SkScalarInvert(SkIntToScalar(bitmap.width())); 1318 SkScalar hInv = SkScalarInvert(SkIntToScalar(bitmap.height())); 1319 paintRect.setLTRB(SkScalarMul(srcRect.fLeft, wInv), 1320 SkScalarMul(srcRect.fTop, hInv), 1321 SkScalarMul(srcRect.fRight, wInv), 1322 SkScalarMul(srcRect.fBottom, hInv)); 1323 1324 bool needsTextureDomain = false; 1325 if (params.isBilerp()) { 1326 // Need texture domain if drawing a sub rect. 1327 needsTextureDomain = srcRect.width() < bitmap.width() || 1328 srcRect.height() < bitmap.height(); 1329 if (m.rectStaysRect() && fContext->getMatrix().rectStaysRect()) { 1330 // sampling is axis-aligned 1331 GrRect transformedRect; 1332 SkMatrix srcToDeviceMatrix(m); 1333 srcToDeviceMatrix.postConcat(fContext->getMatrix()); 1334 srcToDeviceMatrix.mapRect(&transformedRect, srcRect); 1335 1336 if (hasAlignedSamples(srcRect, transformedRect)) { 1337 // We could also turn off filtering here (but we already did a cache lookup with 1338 // params). 1339 needsTextureDomain = false; 1340 } else { 1341 needsTextureDomain = needsTextureDomain && 1342 mayColorBleed(srcRect, transformedRect, m); 1343 } 1344 } 1345 } 1346 1347 GrRect textureDomain = GrRect::MakeEmpty(); 1348 SkAutoTUnref<GrEffectRef> effect; 1349 if (needsTextureDomain) { 1350 // Use a constrained texture domain to avoid color bleeding 1351 SkScalar left, top, right, bottom; 1352 if (srcRect.width() > SK_Scalar1) { 1353 SkScalar border = SK_ScalarHalf / bitmap.width(); 1354 left = paintRect.left() + border; 1355 right = paintRect.right() - border; 1356 } else { 1357 left = right = SkScalarHalf(paintRect.left() + paintRect.right()); 1358 } 1359 if (srcRect.height() > SK_Scalar1) { 1360 SkScalar border = SK_ScalarHalf / bitmap.height(); 1361 top = paintRect.top() + border; 1362 bottom = paintRect.bottom() - border; 1363 } else { 1364 top = bottom = SkScalarHalf(paintRect.top() + paintRect.bottom()); 1365 } 1366 textureDomain.setLTRB(left, top, right, bottom); 1367 effect.reset(GrTextureDomainEffect::Create(texture, 1368 SkMatrix::I(), 1369 textureDomain, 1370 GrTextureDomainEffect::kClamp_WrapMode, 1371 params.isBilerp())); 1372 } else { 1373 effect.reset(GrSimpleTextureEffect::Create(texture, SkMatrix::I(), params)); 1374 } 1375 grPaint->colorStage(kBitmapTextureIdx)->setEffect(effect); 1376 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m); 1377} 1378 1379namespace { 1380 1381void apply_effect(GrContext* context, 1382 GrTexture* srcTexture, 1383 GrTexture* dstTexture, 1384 const GrRect& rect, 1385 GrEffectRef* effect) { 1386 SkASSERT(srcTexture && srcTexture->getContext() == context); 1387 GrContext::AutoMatrix am; 1388 am.setIdentity(context); 1389 GrContext::AutoRenderTarget art(context, dstTexture->asRenderTarget()); 1390 GrContext::AutoClip acs(context, rect); 1391 1392 GrPaint paint; 1393 paint.colorStage(0)->setEffect(effect); 1394 context->drawRect(paint, rect); 1395} 1396 1397}; 1398 1399static GrTexture* filter_texture(SkDevice* device, GrContext* context, 1400 GrTexture* texture, SkImageFilter* filter, 1401 const GrRect& rect) { 1402 GrAssert(filter); 1403 SkDeviceImageFilterProxy proxy(device); 1404 1405 GrTextureDesc desc; 1406 desc.fFlags = kRenderTarget_GrTextureFlagBit, 1407 desc.fWidth = SkScalarCeilToInt(rect.width()); 1408 desc.fHeight = SkScalarCeilToInt(rect.height()); 1409 desc.fConfig = kRGBA_8888_GrPixelConfig; 1410 GrEffectRef* effect; 1411 1412 if (filter->canFilterImageGPU()) { 1413 // Save the render target and set it to NULL, so we don't accidentally draw to it in the 1414 // filter. Also set the clip wide open and the matrix to identity. 1415 GrContext::AutoWideOpenIdentityDraw awo(context, NULL); 1416 texture = filter->filterImageGPU(&proxy, texture, rect); 1417 } else if (filter->asNewEffect(&effect, texture)) { 1418 GrAutoScratchTexture dst(context, desc); 1419 apply_effect(context, texture, dst.texture(), rect, effect); 1420 texture = dst.detach(); 1421 effect->unref(); 1422 } 1423 return texture; 1424} 1425 1426void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 1427 int left, int top, const SkPaint& paint) { 1428 // drawSprite is defined to be in device coords. 1429 CHECK_SHOULD_DRAW(draw, true); 1430 1431 SkAutoLockPixels alp(bitmap, !bitmap.getTexture()); 1432 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1433 return; 1434 } 1435 1436 int w = bitmap.width(); 1437 int h = bitmap.height(); 1438 1439 GrPaint grPaint; 1440 if(!skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) { 1441 return; 1442 } 1443 1444 GrEffectStage* stage = grPaint.colorStage(kBitmapTextureIdx); 1445 1446 GrTexture* texture; 1447 stage->reset(); 1448 // draw sprite uses the default texture params 1449 SkAutoCachedTexture act(this, bitmap, NULL, &texture); 1450 grPaint.colorStage(kBitmapTextureIdx)->setEffect( 1451 GrSimpleTextureEffect::Create(texture, SkMatrix::I()))->unref(); 1452 1453 SkImageFilter* filter = paint.getImageFilter(); 1454 if (NULL != filter) { 1455 GrTexture* filteredTexture = filter_texture(this, fContext, texture, filter, 1456 GrRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h))); 1457 if (filteredTexture) { 1458 grPaint.colorStage(kBitmapTextureIdx)->setEffect( 1459 GrSimpleTextureEffect::Create(filteredTexture, SkMatrix::I()))->unref(); 1460 texture = filteredTexture; 1461 filteredTexture->unref(); 1462 } 1463 } 1464 1465 fContext->drawRectToRect(grPaint, 1466 GrRect::MakeXYWH(SkIntToScalar(left), 1467 SkIntToScalar(top), 1468 SkIntToScalar(w), 1469 SkIntToScalar(h)), 1470 GrRect::MakeWH(SK_Scalar1 * w / texture->width(), 1471 SK_Scalar1 * h / texture->height())); 1472} 1473 1474void SkGpuDevice::drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap, 1475 const SkRect* src, const SkRect& dst, 1476 const SkPaint& paint) { 1477 SkMatrix matrix; 1478 SkRect bitmapBounds, tmpSrc; 1479 1480 bitmapBounds.set(0, 0, 1481 SkIntToScalar(bitmap.width()), 1482 SkIntToScalar(bitmap.height())); 1483 1484 // Compute matrix from the two rectangles 1485 if (NULL != src) { 1486 tmpSrc = *src; 1487 } else { 1488 tmpSrc = bitmapBounds; 1489 } 1490 matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit); 1491 1492 // clip the tmpSrc to the bounds of the bitmap. No check needed if src==null. 1493 if (NULL != src) { 1494 if (!bitmapBounds.contains(tmpSrc)) { 1495 if (!tmpSrc.intersect(bitmapBounds)) { 1496 return; // nothing to draw 1497 } 1498 } 1499 } 1500 1501 this->drawBitmapCommon(draw, bitmap, &tmpSrc, matrix, paint); 1502} 1503 1504void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device, 1505 int x, int y, const SkPaint& paint) { 1506 // clear of the source device must occur before CHECK_SHOULD_DRAW 1507 SkGpuDevice* dev = static_cast<SkGpuDevice*>(device); 1508 if (dev->fNeedClear) { 1509 // TODO: could check here whether we really need to draw at all 1510 dev->clear(0x0); 1511 } 1512 1513 // drawDevice is defined to be in device coords. 1514 CHECK_SHOULD_DRAW(draw, true); 1515 1516 GrPaint grPaint; 1517 grPaint.colorStage(kBitmapTextureIdx)->reset(); 1518 if (!dev->bindDeviceAsTexture(&grPaint) || 1519 !skPaint2GrPaintNoShader(this, paint, true, false, &grPaint)) { 1520 return; 1521 } 1522 1523 GrTexture* devTex = grPaint.getColorStage(kBitmapTextureIdx).getEffect()->texture(0); 1524 SkASSERT(NULL != devTex); 1525 1526 SkImageFilter* filter = paint.getImageFilter(); 1527 if (NULL != filter) { 1528 GrRect rect = GrRect::MakeWH(SkIntToScalar(devTex->width()), 1529 SkIntToScalar(devTex->height())); 1530 GrTexture* filteredTexture = filter_texture(this, fContext, devTex, filter, rect); 1531 if (filteredTexture) { 1532 grPaint.colorStage(kBitmapTextureIdx)->setEffect( 1533 GrSimpleTextureEffect::Create(filteredTexture, SkMatrix::I()))->unref(); 1534 devTex = filteredTexture; 1535 filteredTexture->unref(); 1536 } 1537 } 1538 1539 const SkBitmap& bm = dev->accessBitmap(false); 1540 int w = bm.width(); 1541 int h = bm.height(); 1542 1543 GrRect dstRect = GrRect::MakeXYWH(SkIntToScalar(x), 1544 SkIntToScalar(y), 1545 SkIntToScalar(w), 1546 SkIntToScalar(h)); 1547 1548 // The device being drawn may not fill up its texture (saveLayer uses 1549 // the approximate ). 1550 GrRect srcRect = GrRect::MakeWH(SK_Scalar1 * w / devTex->width(), 1551 SK_Scalar1 * h / devTex->height()); 1552 1553 fContext->drawRectToRect(grPaint, dstRect, srcRect); 1554} 1555 1556bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) { 1557 if (!filter->asNewEffect(NULL, NULL) && 1558 !filter->canFilterImageGPU()) { 1559 return false; 1560 } 1561 return true; 1562} 1563 1564bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, 1565 const SkMatrix& ctm, 1566 SkBitmap* result, SkIPoint* offset) { 1567 // want explicitly our impl, so guard against a subclass of us overriding it 1568 if (!this->SkGpuDevice::canHandleImageFilter(filter)) { 1569 return false; 1570 } 1571 1572 SkAutoLockPixels alp(src, !src.getTexture()); 1573 if (!src.getTexture() && !src.readyToDraw()) { 1574 return false; 1575 } 1576 1577 GrPaint paint; 1578 1579 GrTexture* texture; 1580 // We assume here that the filter will not attempt to tile the src. Otherwise, this cache lookup 1581 // must be pushed upstack. 1582 SkAutoCachedTexture act(this, src, NULL, &texture); 1583 1584 result->setConfig(src.config(), src.width(), src.height()); 1585 GrRect rect = GrRect::MakeWH(SkIntToScalar(src.width()), 1586 SkIntToScalar(src.height())); 1587 GrTexture* resultTexture = filter_texture(this, fContext, texture, filter, rect); 1588 if (resultTexture) { 1589 result->setPixelRef(SkNEW_ARGS(SkGrTexturePixelRef, 1590 (resultTexture)))->unref(); 1591 resultTexture->unref(); 1592 } 1593 return true; 1594} 1595 1596/////////////////////////////////////////////////////////////////////////////// 1597 1598// must be in SkCanvas::VertexMode order 1599static const GrPrimitiveType gVertexMode2PrimitiveType[] = { 1600 kTriangles_GrPrimitiveType, 1601 kTriangleStrip_GrPrimitiveType, 1602 kTriangleFan_GrPrimitiveType, 1603}; 1604 1605void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 1606 int vertexCount, const SkPoint vertices[], 1607 const SkPoint texs[], const SkColor colors[], 1608 SkXfermode* xmode, 1609 const uint16_t indices[], int indexCount, 1610 const SkPaint& paint) { 1611 CHECK_SHOULD_DRAW(draw, false); 1612 1613 GrPaint grPaint; 1614 // we ignore the shader if texs is null. 1615 if (NULL == texs) { 1616 if (!skPaint2GrPaintNoShader(this, paint, false, NULL == colors, &grPaint)) { 1617 return; 1618 } 1619 } else { 1620 if (!skPaint2GrPaintShader(this, paint, NULL == colors, &grPaint)) { 1621 return; 1622 } 1623 } 1624 1625 if (NULL != xmode && NULL != texs && NULL != colors) { 1626 if (!SkXfermode::IsMode(xmode, SkXfermode::kMultiply_Mode)) { 1627 SkDebugf("Unsupported vertex-color/texture xfer mode.\n"); 1628#if 0 1629 return 1630#endif 1631 } 1632 } 1633 1634 SkAutoSTMalloc<128, GrColor> convertedColors(0); 1635 if (NULL != colors) { 1636 // need to convert byte order and from non-PM to PM 1637 convertedColors.reset(vertexCount); 1638 for (int i = 0; i < vertexCount; ++i) { 1639 convertedColors[i] = SkColor2GrColor(colors[i]); 1640 } 1641 colors = convertedColors.get(); 1642 } 1643 fContext->drawVertices(grPaint, 1644 gVertexMode2PrimitiveType[vmode], 1645 vertexCount, 1646 (GrPoint*) vertices, 1647 (GrPoint*) texs, 1648 colors, 1649 indices, 1650 indexCount); 1651} 1652 1653/////////////////////////////////////////////////////////////////////////////// 1654 1655static void GlyphCacheAuxProc(void* data) { 1656 GrFontScaler* scaler = (GrFontScaler*)data; 1657 SkSafeUnref(scaler); 1658} 1659 1660static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) { 1661 void* auxData; 1662 GrFontScaler* scaler = NULL; 1663 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) { 1664 scaler = (GrFontScaler*)auxData; 1665 } 1666 if (NULL == scaler) { 1667 scaler = SkNEW_ARGS(SkGrFontScaler, (cache)); 1668 cache->setAuxProc(GlyphCacheAuxProc, scaler); 1669 } 1670 return scaler; 1671} 1672 1673static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state, 1674 SkFixed fx, SkFixed fy, 1675 const SkGlyph& glyph) { 1676 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1677 1678 GrSkDrawProcs* procs = static_cast<GrSkDrawProcs*>(state.fDraw->fProcs); 1679 1680 if (NULL == procs->fFontScaler) { 1681 procs->fFontScaler = get_gr_font_scaler(state.fCache); 1682 } 1683 1684 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1685 glyph.getSubXFixed(), 1686 glyph.getSubYFixed()), 1687 SkFixedFloorToFixed(fx), 1688 SkFixedFloorToFixed(fy), 1689 procs->fFontScaler); 1690} 1691 1692SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) { 1693 1694 // deferred allocation 1695 if (NULL == fDrawProcs) { 1696 fDrawProcs = SkNEW(GrSkDrawProcs); 1697 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph; 1698 fDrawProcs->fContext = fContext; 1699 } 1700 1701 // init our (and GL's) state 1702 fDrawProcs->fTextContext = context; 1703 fDrawProcs->fFontScaler = NULL; 1704 return fDrawProcs; 1705} 1706 1707void SkGpuDevice::drawText(const SkDraw& draw, const void* text, 1708 size_t byteLength, SkScalar x, SkScalar y, 1709 const SkPaint& paint) { 1710 CHECK_SHOULD_DRAW(draw, false); 1711 1712 if (fContext->getMatrix().hasPerspective()) { 1713 // this guy will just call our drawPath() 1714 draw.drawText((const char*)text, byteLength, x, y, paint); 1715 } else { 1716 SkDraw myDraw(draw); 1717 1718 GrPaint grPaint; 1719 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 1720 return; 1721 } 1722 GrTextContext context(fContext, grPaint); 1723 myDraw.fProcs = this->initDrawForText(&context); 1724 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint); 1725 } 1726} 1727 1728void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, 1729 size_t byteLength, const SkScalar pos[], 1730 SkScalar constY, int scalarsPerPos, 1731 const SkPaint& paint) { 1732 CHECK_SHOULD_DRAW(draw, false); 1733 1734 if (fContext->getMatrix().hasPerspective()) { 1735 // this guy will just call our drawPath() 1736 draw.drawPosText((const char*)text, byteLength, pos, constY, 1737 scalarsPerPos, paint); 1738 } else { 1739 SkDraw myDraw(draw); 1740 1741 GrPaint grPaint; 1742 if (!skPaint2GrPaintShader(this, paint, true, &grPaint)) { 1743 return; 1744 } 1745 GrTextContext context(fContext, grPaint); 1746 myDraw.fProcs = this->initDrawForText(&context); 1747 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY, 1748 scalarsPerPos, paint); 1749 } 1750} 1751 1752void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text, 1753 size_t len, const SkPath& path, 1754 const SkMatrix* m, const SkPaint& paint) { 1755 CHECK_SHOULD_DRAW(draw, false); 1756 1757 SkASSERT(draw.fDevice == this); 1758 draw.drawTextOnPath((const char*)text, len, path, m, paint); 1759} 1760 1761/////////////////////////////////////////////////////////////////////////////// 1762 1763bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 1764 if (!paint.isLCDRenderText()) { 1765 // we're cool with the paint as is 1766 return false; 1767 } 1768 1769 if (paint.getShader() || 1770 paint.getXfermode() || // unless its srcover 1771 paint.getMaskFilter() || 1772 paint.getRasterizer() || 1773 paint.getColorFilter() || 1774 paint.getPathEffect() || 1775 paint.isFakeBoldText() || 1776 paint.getStyle() != SkPaint::kFill_Style) { 1777 // turn off lcd 1778 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 1779 flags->fHinting = paint.getHinting(); 1780 return true; 1781 } 1782 // we're cool with the paint as is 1783 return false; 1784} 1785 1786void SkGpuDevice::flush() { 1787 DO_DEFERRED_CLEAR(); 1788 fContext->resolveRenderTarget(fRenderTarget); 1789} 1790 1791/////////////////////////////////////////////////////////////////////////////// 1792 1793SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config, 1794 int width, int height, 1795 bool isOpaque, 1796 Usage usage) { 1797 GrTextureDesc desc; 1798 desc.fConfig = fRenderTarget->config(); 1799 desc.fFlags = kRenderTarget_GrTextureFlagBit; 1800 desc.fWidth = width; 1801 desc.fHeight = height; 1802 desc.fSampleCnt = fRenderTarget->numSamples(); 1803 1804 GrTexture* texture; 1805 SkAutoTUnref<GrTexture> tunref; 1806 // Skia's convention is to only clear a device if it is non-opaque. 1807 bool needClear = !isOpaque; 1808 1809#if CACHE_COMPATIBLE_DEVICE_TEXTURES 1810 // layers are never draw in repeat modes, so we can request an approx 1811 // match and ignore any padding. 1812 const GrContext::ScratchTexMatch match = (kSaveLayer_Usage == usage) ? 1813 GrContext::kApprox_ScratchTexMatch : 1814 GrContext::kExact_ScratchTexMatch; 1815 texture = fContext->lockScratchTexture(desc, match); 1816#else 1817 tunref.reset(fContext->createUncachedTexture(desc, NULL, 0)); 1818 texture = tunref.get(); 1819#endif 1820 if (texture) { 1821 return SkNEW_ARGS(SkGpuDevice,(fContext, 1822 texture, 1823 needClear)); 1824 } else { 1825 GrPrintf("---- failed to create compatible device texture [%d %d]\n", 1826 width, height); 1827 return NULL; 1828 } 1829} 1830 1831SkGpuDevice::SkGpuDevice(GrContext* context, 1832 GrTexture* texture, 1833 bool needClear) 1834 : SkDevice(make_bitmap(context, texture->asRenderTarget())) { 1835 1836 GrAssert(texture && texture->asRenderTarget()); 1837 // This constructor is called from onCreateCompatibleDevice. It has locked the RT in the texture 1838 // cache. We pass true for the third argument so that it will get unlocked. 1839 this->initFromRenderTarget(context, texture->asRenderTarget(), true); 1840 fNeedClear = needClear; 1841} 1842