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