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