1 2 /* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10 11 #include "GrContext.h" 12 #include "GrTextContext.h" 13 14 #include "SkGpuDevice.h" 15 #include "SkGrTexturePixelRef.h" 16 17 #include "SkColorFilter.h" 18 #include "SkDrawProcs.h" 19 #include "SkGlyphCache.h" 20 #include "SkImageFilter.h" 21 #include "SkTLazy.h" 22 #include "SkUtils.h" 23 24 #define CACHE_LAYER_TEXTURES 1 25 26 #if 0 27 extern bool (*gShouldDrawProc)(); 28 #define CHECK_SHOULD_DRAW(draw) \ 29 do { \ 30 if (gShouldDrawProc && !gShouldDrawProc()) return; \ 31 this->prepareRenderTarget(draw); \ 32 } while (0) 33 #else 34 #define CHECK_SHOULD_DRAW(draw) this->prepareRenderTarget(draw) 35 #endif 36 37 // we use the same texture slot on GrPaint for bitmaps and shaders 38 // (since drawBitmap, drawSprite, and drawDevice ignore skia's shader) 39 enum { 40 kBitmapTextureIdx = 0, 41 kShaderTextureIdx = 0 42 }; 43 44 45 #define MAX_BLUR_SIGMA 4.0f 46 // FIXME: This value comes from from SkBlurMaskFilter.cpp. 47 // Should probably be put in a common header someplace. 48 #define MAX_BLUR_RADIUS SkIntToScalar(128) 49 // This constant approximates the scaling done in the software path's 50 // "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)). 51 // IMHO, it actually should be 1: we blur "less" than we should do 52 // according to the CSS and canvas specs, simply because Safari does the same. 53 // Firefox used to do the same too, until 4.0 where they fixed it. So at some 54 // point we should probably get rid of these scaling constants and rebaseline 55 // all the blur tests. 56 #define BLUR_SIGMA_SCALE 0.6f 57 /////////////////////////////////////////////////////////////////////////////// 58 59 SkGpuDevice::SkAutoCachedTexture:: 60 SkAutoCachedTexture(SkGpuDevice* device, 61 const SkBitmap& bitmap, 62 const GrSamplerState* sampler, 63 GrTexture** texture) { 64 GrAssert(texture); 65 *texture = this->set(device, bitmap, sampler); 66 } 67 68 SkGpuDevice::SkAutoCachedTexture::SkAutoCachedTexture() { 69 } 70 71 GrTexture* SkGpuDevice::SkAutoCachedTexture::set(SkGpuDevice* device, 72 const SkBitmap& bitmap, 73 const GrSamplerState* sampler) { 74 if (fTex.texture()) { 75 fDevice->unlockCachedTexture(fTex); 76 } 77 fDevice = device; 78 GrTexture* texture = (GrTexture*)bitmap.getTexture(); 79 if (texture) { 80 // return the native texture 81 fTex.reset(); 82 } else { 83 // look it up in our cache 84 fTex = device->lockCachedTexture(bitmap, sampler); 85 texture = fTex.texture(); 86 } 87 return texture; 88 } 89 90 SkGpuDevice::SkAutoCachedTexture::~SkAutoCachedTexture() { 91 if (fTex.texture()) { 92 fDevice->unlockCachedTexture(fTex); 93 } 94 } 95 96 /////////////////////////////////////////////////////////////////////////////// 97 98 bool gDoTraceDraw; 99 100 struct GrSkDrawProcs : public SkDrawProcs { 101 public: 102 GrContext* fContext; 103 GrTextContext* fTextContext; 104 GrFontScaler* fFontScaler; // cached in the skia glyphcache 105 }; 106 107 /////////////////////////////////////////////////////////////////////////////// 108 109 static SkBitmap::Config grConfig2skConfig(GrPixelConfig config, bool* isOpaque) { 110 switch (config) { 111 case kAlpha_8_GrPixelConfig: 112 *isOpaque = false; 113 return SkBitmap::kA8_Config; 114 case kRGB_565_GrPixelConfig: 115 *isOpaque = true; 116 return SkBitmap::kRGB_565_Config; 117 case kRGBA_4444_GrPixelConfig: 118 *isOpaque = false; 119 return SkBitmap::kARGB_4444_Config; 120 case kSkia8888_PM_GrPixelConfig: 121 // we don't currently have a way of knowing whether 122 // a 8888 is opaque based on the config. 123 *isOpaque = false; 124 return SkBitmap::kARGB_8888_Config; 125 default: 126 *isOpaque = false; 127 return SkBitmap::kNo_Config; 128 } 129 } 130 131 static SkBitmap make_bitmap(GrContext* context, GrRenderTarget* renderTarget) { 132 GrPixelConfig config = renderTarget->config(); 133 134 bool isOpaque; 135 SkBitmap bitmap; 136 bitmap.setConfig(grConfig2skConfig(config, &isOpaque), 137 renderTarget->width(), renderTarget->height()); 138 bitmap.setIsOpaque(isOpaque); 139 return bitmap; 140 } 141 142 SkGpuDevice::SkGpuDevice(GrContext* context, GrTexture* texture) 143 : SkDevice(make_bitmap(context, texture->asRenderTarget())) { 144 this->initFromRenderTarget(context, texture->asRenderTarget()); 145 } 146 147 SkGpuDevice::SkGpuDevice(GrContext* context, GrRenderTarget* renderTarget) 148 : SkDevice(make_bitmap(context, renderTarget)) { 149 this->initFromRenderTarget(context, renderTarget); 150 } 151 152 void SkGpuDevice::initFromRenderTarget(GrContext* context, 153 GrRenderTarget* renderTarget) { 154 fNeedPrepareRenderTarget = false; 155 fDrawProcs = NULL; 156 157 fContext = context; 158 fContext->ref(); 159 160 fTexture = NULL; 161 fRenderTarget = NULL; 162 fNeedClear = false; 163 164 GrAssert(NULL != renderTarget); 165 fRenderTarget = renderTarget; 166 fRenderTarget->ref(); 167 // if this RT is also a texture, hold a ref on it 168 fTexture = fRenderTarget->asTexture(); 169 SkSafeRef(fTexture); 170 171 // Create a pixel ref for the underlying SkBitmap. We prefer a texture pixel 172 // ref to a render target pixel reft. The pixel ref may get ref'ed outside 173 // the device via accessBitmap. This external ref may outlive the device. 174 // Since textures own their render targets (but not vice-versa) we 175 // are ensuring that both objects will live as long as the pixel ref. 176 SkPixelRef* pr; 177 if (fTexture) { 178 pr = new SkGrTexturePixelRef(fTexture); 179 } else { 180 pr = new SkGrRenderTargetPixelRef(fRenderTarget); 181 } 182 this->setPixelRef(pr, 0)->unref(); 183 } 184 185 SkGpuDevice::SkGpuDevice(GrContext* context, SkBitmap::Config config, int width, 186 int height, Usage usage) 187 : SkDevice(config, width, height, false /*isOpaque*/) { 188 fNeedPrepareRenderTarget = false; 189 fDrawProcs = NULL; 190 191 fContext = context; 192 fContext->ref(); 193 194 fTexture = NULL; 195 fRenderTarget = NULL; 196 fNeedClear = false; 197 198 if (config != SkBitmap::kRGB_565_Config) { 199 config = SkBitmap::kARGB_8888_Config; 200 } 201 SkBitmap bm; 202 bm.setConfig(config, width, height); 203 204 #if CACHE_LAYER_TEXTURES 205 TexType type = (kSaveLayer_Usage == usage) ? 206 kSaveLayerDeviceRenderTarget_TexType : 207 kDeviceRenderTarget_TexType; 208 fCache = this->lockCachedTexture(bm, NULL, type); 209 fTexture = fCache.texture(); 210 if (fTexture) { 211 SkASSERT(NULL != fTexture->asRenderTarget()); 212 // hold a ref directly on fTexture (even though fCache has one) to match 213 // other constructor paths. Simplifies cleanup. 214 fTexture->ref(); 215 } 216 #else 217 const GrTextureDesc desc = { 218 kRenderTarget_GrTextureFlagBit, 219 width, 220 height, 221 SkGr::Bitmap2PixelConfig(bm), 222 {0} // samples 223 }; 224 225 fTexture = fContext->createUncachedTexture(desc, NULL, 0); 226 #endif 227 if (NULL != fTexture) { 228 fRenderTarget = fTexture->asRenderTarget(); 229 fRenderTarget->ref(); 230 231 GrAssert(NULL != fRenderTarget); 232 233 // we defer the actual clear until our gainFocus() 234 fNeedClear = true; 235 236 // wrap the bitmap with a pixelref to expose our texture 237 SkGrTexturePixelRef* pr = new SkGrTexturePixelRef(fTexture); 238 this->setPixelRef(pr, 0)->unref(); 239 } else { 240 GrPrintf("--- failed to create gpu-offscreen [%d %d]\n", 241 width, height); 242 GrAssert(false); 243 } 244 } 245 246 SkGpuDevice::~SkGpuDevice() { 247 if (fDrawProcs) { 248 delete fDrawProcs; 249 } 250 251 SkSafeUnref(fTexture); 252 SkSafeUnref(fRenderTarget); 253 if (fCache.texture()) { 254 GrAssert(NULL != fTexture); 255 GrAssert(fRenderTarget == fTexture->asRenderTarget()); 256 fContext->unlockTexture(fCache); 257 } 258 fContext->unref(); 259 } 260 261 /////////////////////////////////////////////////////////////////////////////// 262 263 void SkGpuDevice::makeRenderTargetCurrent() { 264 fContext->setRenderTarget(fRenderTarget); 265 fContext->flush(true); 266 fNeedPrepareRenderTarget = true; 267 } 268 269 /////////////////////////////////////////////////////////////////////////////// 270 271 namespace { 272 GrPixelConfig config8888_to_gr_config(SkCanvas::Config8888 config8888) { 273 switch (config8888) { 274 case SkCanvas::kNative_Premul_Config8888: 275 return kSkia8888_PM_GrPixelConfig; 276 case SkCanvas::kNative_Unpremul_Config8888: 277 return kSkia8888_UPM_GrPixelConfig; 278 case SkCanvas::kBGRA_Premul_Config8888: 279 return kBGRA_8888_PM_GrPixelConfig; 280 case SkCanvas::kBGRA_Unpremul_Config8888: 281 return kBGRA_8888_UPM_GrPixelConfig; 282 case SkCanvas::kRGBA_Premul_Config8888: 283 return kRGBA_8888_PM_GrPixelConfig; 284 case SkCanvas::kRGBA_Unpremul_Config8888: 285 return kRGBA_8888_UPM_GrPixelConfig; 286 default: 287 GrCrash("Unexpected Config8888."); 288 return kSkia8888_PM_GrPixelConfig; 289 } 290 } 291 } 292 293 bool SkGpuDevice::onReadPixels(const SkBitmap& bitmap, 294 int x, int y, 295 SkCanvas::Config8888 config8888) { 296 SkASSERT(SkBitmap::kARGB_8888_Config == bitmap.config()); 297 SkASSERT(!bitmap.isNull()); 298 SkASSERT(SkIRect::MakeWH(this->width(), this->height()).contains(SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height()))); 299 300 SkAutoLockPixels alp(bitmap); 301 GrPixelConfig config; 302 config = config8888_to_gr_config(config8888); 303 return fContext->readRenderTargetPixels(fRenderTarget, 304 x, y, 305 bitmap.width(), 306 bitmap.height(), 307 config, 308 bitmap.getPixels(), 309 bitmap.rowBytes()); 310 } 311 312 void SkGpuDevice::writePixels(const SkBitmap& bitmap, int x, int y, 313 SkCanvas::Config8888 config8888) { 314 SkAutoLockPixels alp(bitmap); 315 if (!bitmap.readyToDraw()) { 316 return; 317 } 318 319 GrPixelConfig config; 320 if (SkBitmap::kARGB_8888_Config == bitmap.config()) { 321 config = config8888_to_gr_config(config8888); 322 } else { 323 config= SkGr::BitmapConfig2PixelConfig(bitmap.config(), 324 bitmap.isOpaque()); 325 } 326 327 fRenderTarget->writePixels(x, y, bitmap.width(), bitmap.height(), 328 config, bitmap.getPixels(), bitmap.rowBytes()); 329 } 330 331 /////////////////////////////////////////////////////////////////////////////// 332 333 static void convert_matrixclip(GrContext* context, const SkMatrix& matrix, 334 const SkClipStack& clipStack, 335 const SkRegion& clipRegion, 336 const SkIPoint& origin) { 337 context->setMatrix(matrix); 338 339 SkGrClipIterator iter; 340 iter.reset(clipStack); 341 const SkIRect& skBounds = clipRegion.getBounds(); 342 GrRect bounds; 343 bounds.setLTRB(GrIntToScalar(skBounds.fLeft), 344 GrIntToScalar(skBounds.fTop), 345 GrIntToScalar(skBounds.fRight), 346 GrIntToScalar(skBounds.fBottom)); 347 GrClip grc(&iter, GrIntToScalar(-origin.x()), GrIntToScalar(-origin.y()), 348 &bounds); 349 context->setClip(grc); 350 } 351 352 // call this ever each draw call, to ensure that the context reflects our state, 353 // and not the state from some other canvas/device 354 void SkGpuDevice::prepareRenderTarget(const SkDraw& draw) { 355 if (fNeedPrepareRenderTarget || 356 fContext->getRenderTarget() != fRenderTarget) { 357 358 fContext->setRenderTarget(fRenderTarget); 359 SkASSERT(draw.fClipStack); 360 convert_matrixclip(fContext, *draw.fMatrix, 361 *draw.fClipStack, *draw.fClip, this->getOrigin()); 362 fNeedPrepareRenderTarget = false; 363 } 364 } 365 366 void SkGpuDevice::setMatrixClip(const SkMatrix& matrix, const SkRegion& clip, 367 const SkClipStack& clipStack) { 368 this->INHERITED::setMatrixClip(matrix, clip, clipStack); 369 // We don't need to set them now because the context may not reflect this device. 370 fNeedPrepareRenderTarget = true; 371 } 372 373 void SkGpuDevice::gainFocus(SkCanvas* canvas, const SkMatrix& matrix, 374 const SkRegion& clip, const SkClipStack& clipStack) { 375 376 fContext->setRenderTarget(fRenderTarget); 377 378 this->INHERITED::gainFocus(canvas, matrix, clip, clipStack); 379 380 convert_matrixclip(fContext, matrix, clipStack, clip, this->getOrigin()); 381 382 if (fNeedClear) { 383 fContext->clear(NULL, 0x0); 384 fNeedClear = false; 385 } 386 } 387 388 SkGpuRenderTarget* SkGpuDevice::accessRenderTarget() { 389 return (SkGpuRenderTarget*)fRenderTarget; 390 } 391 392 bool SkGpuDevice::bindDeviceAsTexture(GrPaint* paint) { 393 if (NULL != fTexture) { 394 paint->setTexture(kBitmapTextureIdx, fTexture); 395 return true; 396 } 397 return false; 398 } 399 400 /////////////////////////////////////////////////////////////////////////////// 401 402 SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch); 403 SK_COMPILE_ASSERT(SkShader::kDefault_BitmapType == 1, shader_type_mismatch); 404 SK_COMPILE_ASSERT(SkShader::kRadial_BitmapType == 2, shader_type_mismatch); 405 SK_COMPILE_ASSERT(SkShader::kSweep_BitmapType == 3, shader_type_mismatch); 406 SK_COMPILE_ASSERT(SkShader::kTwoPointRadial_BitmapType == 4, 407 shader_type_mismatch); 408 SK_COMPILE_ASSERT(SkShader::kLast_BitmapType == 4, shader_type_mismatch); 409 410 static const GrSamplerState::SampleMode sk_bmp_type_to_sample_mode[] = { 411 (GrSamplerState::SampleMode) -1, // kNone_BitmapType 412 GrSamplerState::kNormal_SampleMode, // kDefault_BitmapType 413 GrSamplerState::kRadial_SampleMode, // kRadial_BitmapType 414 GrSamplerState::kSweep_SampleMode, // kSweep_BitmapType 415 GrSamplerState::kRadial2_SampleMode, // kTwoPointRadial_BitmapType 416 }; 417 418 bool SkGpuDevice::skPaint2GrPaintNoShader(const SkPaint& skPaint, 419 bool justAlpha, 420 GrPaint* grPaint, 421 bool constantColor) { 422 423 grPaint->fDither = skPaint.isDither(); 424 grPaint->fAntiAlias = skPaint.isAntiAlias(); 425 grPaint->fCoverage = 0xFF; 426 427 SkXfermode::Coeff sm = SkXfermode::kOne_Coeff; 428 SkXfermode::Coeff dm = SkXfermode::kISA_Coeff; 429 430 SkXfermode* mode = skPaint.getXfermode(); 431 if (mode) { 432 if (!mode->asCoeff(&sm, &dm)) { 433 //SkDEBUGCODE(SkDebugf("Unsupported xfer mode.\n");) 434 #if 0 435 return false; 436 #endif 437 } 438 } 439 grPaint->fSrcBlendCoeff = sk_blend_to_grblend(sm); 440 grPaint->fDstBlendCoeff = sk_blend_to_grblend(dm); 441 442 if (justAlpha) { 443 uint8_t alpha = skPaint.getAlpha(); 444 grPaint->fColor = GrColorPackRGBA(alpha, alpha, alpha, alpha); 445 // justAlpha is currently set to true only if there is a texture, 446 // so constantColor should not also be true. 447 GrAssert(!constantColor); 448 } else { 449 grPaint->fColor = SkGr::SkColor2GrColor(skPaint.getColor()); 450 grPaint->setTexture(kShaderTextureIdx, NULL); 451 } 452 SkColorFilter* colorFilter = skPaint.getColorFilter(); 453 SkColor color; 454 SkXfermode::Mode filterMode; 455 SkScalar matrix[20]; 456 if (colorFilter != NULL && colorFilter->asColorMode(&color, &filterMode)) { 457 grPaint->fColorMatrixEnabled = false; 458 if (!constantColor) { 459 grPaint->fColorFilterColor = SkGr::SkColor2GrColor(color); 460 grPaint->fColorFilterXfermode = filterMode; 461 } else { 462 SkColor filtered = colorFilter->filterColor(skPaint.getColor()); 463 grPaint->fColor = SkGr::SkColor2GrColor(filtered); 464 grPaint->resetColorFilter(); 465 } 466 } else if (colorFilter != NULL && colorFilter->asColorMatrix(matrix)) { 467 grPaint->fColorMatrixEnabled = true; 468 memcpy(grPaint->fColorMatrix, matrix, sizeof(matrix)); 469 grPaint->fColorFilterXfermode = SkXfermode::kDst_Mode; 470 } else { 471 grPaint->resetColorFilter(); 472 } 473 return true; 474 } 475 476 bool SkGpuDevice::skPaint2GrPaintShader(const SkPaint& skPaint, 477 SkAutoCachedTexture* act, 478 const SkMatrix& ctm, 479 GrPaint* grPaint, 480 bool constantColor) { 481 482 SkASSERT(NULL != act); 483 484 SkShader* shader = skPaint.getShader(); 485 if (NULL == shader) { 486 return this->skPaint2GrPaintNoShader(skPaint, 487 false, 488 grPaint, 489 constantColor); 490 } else if (!this->skPaint2GrPaintNoShader(skPaint, true, grPaint, false)) { 491 return false; 492 } 493 494 SkBitmap bitmap; 495 SkMatrix* matrix = grPaint->textureSampler(kShaderTextureIdx)->matrix(); 496 SkShader::TileMode tileModes[2]; 497 SkScalar twoPointParams[3]; 498 SkShader::BitmapType bmptype = shader->asABitmap(&bitmap, matrix, 499 tileModes, twoPointParams); 500 501 GrSamplerState::SampleMode sampleMode = sk_bmp_type_to_sample_mode[bmptype]; 502 if (-1 == sampleMode) { 503 SkShader::GradientInfo info; 504 SkColor color; 505 506 info.fColors = &color; 507 info.fColorOffsets = NULL; 508 info.fColorCount = 1; 509 if (SkShader::kColor_GradientType == shader->asAGradient(&info)) { 510 SkPaint copy(skPaint); 511 copy.setShader(NULL); 512 // modulate the paint alpha by the shader's solid color alpha 513 U8CPU newA = SkMulDiv255Round(SkColorGetA(color), copy.getAlpha()); 514 copy.setColor(SkColorSetA(color, newA)); 515 return this->skPaint2GrPaintNoShader(copy, 516 false, 517 grPaint, 518 constantColor); 519 } 520 return false; 521 } 522 GrSamplerState* sampler = grPaint->textureSampler(kShaderTextureIdx); 523 sampler->setSampleMode(sampleMode); 524 if (skPaint.isFilterBitmap()) { 525 sampler->setFilter(GrSamplerState::kBilinear_Filter); 526 } else { 527 sampler->setFilter(GrSamplerState::kNearest_Filter); 528 } 529 sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0])); 530 sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1])); 531 if (GrSamplerState::kRadial2_SampleMode == sampleMode) { 532 sampler->setRadial2Params(twoPointParams[0], 533 twoPointParams[1], 534 twoPointParams[2] < 0); 535 } 536 537 GrTexture* texture = act->set(this, bitmap, sampler); 538 if (NULL == texture) { 539 SkDebugf("Couldn't convert bitmap to texture.\n"); 540 return false; 541 } 542 grPaint->setTexture(kShaderTextureIdx, texture); 543 544 // since our texture coords will be in local space, we wack the texture 545 // matrix to map them back into 0...1 before we load it 546 SkMatrix localM; 547 if (shader->getLocalMatrix(&localM)) { 548 SkMatrix inverse; 549 if (localM.invert(&inverse)) { 550 matrix->preConcat(inverse); 551 } 552 } 553 if (SkShader::kDefault_BitmapType == bmptype) { 554 GrScalar sx = GrFixedToScalar(GR_Fixed1 / bitmap.width()); 555 GrScalar sy = GrFixedToScalar(GR_Fixed1 / bitmap.height()); 556 matrix->postScale(sx, sy); 557 } else if (SkShader::kRadial_BitmapType == bmptype) { 558 GrScalar s = GrFixedToScalar(GR_Fixed1 / bitmap.width()); 559 matrix->postScale(s, s); 560 } 561 562 return true; 563 } 564 565 /////////////////////////////////////////////////////////////////////////////// 566 567 void SkGpuDevice::clear(SkColor color) { 568 fContext->clear(NULL, color); 569 } 570 571 void SkGpuDevice::drawPaint(const SkDraw& draw, const SkPaint& paint) { 572 CHECK_SHOULD_DRAW(draw); 573 574 GrPaint grPaint; 575 SkAutoCachedTexture act; 576 if (!this->skPaint2GrPaintShader(paint, 577 &act, 578 *draw.fMatrix, 579 &grPaint, 580 true)) { 581 return; 582 } 583 584 fContext->drawPaint(grPaint); 585 } 586 587 // must be in SkCanvas::PointMode order 588 static const GrPrimitiveType gPointMode2PrimtiveType[] = { 589 kPoints_PrimitiveType, 590 kLines_PrimitiveType, 591 kLineStrip_PrimitiveType 592 }; 593 594 void SkGpuDevice::drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, 595 size_t count, const SkPoint pts[], const SkPaint& paint) { 596 CHECK_SHOULD_DRAW(draw); 597 598 SkScalar width = paint.getStrokeWidth(); 599 if (width < 0) { 600 return; 601 } 602 603 // we only handle hairlines here, else we let the SkDraw call our drawPath() 604 if (width > 0) { 605 draw.drawPoints(mode, count, pts, paint, true); 606 return; 607 } 608 609 GrPaint grPaint; 610 SkAutoCachedTexture act; 611 if (!this->skPaint2GrPaintShader(paint, 612 &act, 613 *draw.fMatrix, 614 &grPaint, 615 true)) { 616 return; 617 } 618 619 fContext->drawVertices(grPaint, 620 gPointMode2PrimtiveType[mode], 621 count, 622 (GrPoint*)pts, 623 NULL, 624 NULL, 625 NULL, 626 0); 627 } 628 629 /////////////////////////////////////////////////////////////////////////////// 630 631 void SkGpuDevice::drawRect(const SkDraw& draw, const SkRect& rect, 632 const SkPaint& paint) { 633 CHECK_SHOULD_DRAW(draw); 634 635 bool doStroke = paint.getStyle() != SkPaint::kFill_Style; 636 SkScalar width = paint.getStrokeWidth(); 637 638 /* 639 We have special code for hairline strokes, miter-strokes, and fills. 640 Anything else we just call our path code. 641 */ 642 bool usePath = doStroke && width > 0 && 643 paint.getStrokeJoin() != SkPaint::kMiter_Join; 644 // another reason we might need to call drawPath... 645 if (paint.getMaskFilter()) { 646 usePath = true; 647 } 648 // until we aa rotated rects... 649 if (!usePath && paint.isAntiAlias() && !draw.fMatrix->rectStaysRect()) { 650 usePath = true; 651 } 652 // small miter limit means right angles show bevel... 653 if (SkPaint::kMiter_Join == paint.getStrokeJoin() && 654 paint.getStrokeMiter() < SK_ScalarSqrt2) 655 { 656 usePath = true; 657 } 658 // until we can both stroke and fill rectangles 659 if (paint.getStyle() == SkPaint::kStrokeAndFill_Style) { 660 usePath = true; 661 } 662 663 if (usePath) { 664 SkPath path; 665 path.addRect(rect); 666 this->drawPath(draw, path, paint, NULL, true); 667 return; 668 } 669 670 GrPaint grPaint; 671 SkAutoCachedTexture act; 672 if (!this->skPaint2GrPaintShader(paint, 673 &act, 674 *draw.fMatrix, 675 &grPaint, 676 true)) { 677 return; 678 } 679 fContext->drawRect(grPaint, rect, doStroke ? width : -1); 680 } 681 682 #include "SkMaskFilter.h" 683 #include "SkBounder.h" 684 685 static GrPathFill skToGrFillType(SkPath::FillType fillType) { 686 switch (fillType) { 687 case SkPath::kWinding_FillType: 688 return kWinding_PathFill; 689 case SkPath::kEvenOdd_FillType: 690 return kEvenOdd_PathFill; 691 case SkPath::kInverseWinding_FillType: 692 return kInverseWinding_PathFill; 693 case SkPath::kInverseEvenOdd_FillType: 694 return kInverseEvenOdd_PathFill; 695 default: 696 SkDebugf("Unsupported path fill type\n"); 697 return kHairLine_PathFill; 698 } 699 } 700 701 static GrTexture* applyMorphology(GrContext* context, GrTexture* texture, 702 const GrRect& srcRect, 703 GrTexture* temp1, GrTexture* temp2, 704 GrSamplerState::Filter filter, 705 SkISize radius) { 706 GrRenderTarget* oldRenderTarget = context->getRenderTarget(); 707 GrAutoMatrix avm(context, GrMatrix::I()); 708 GrClip oldClip = context->getClip(); 709 context->setClip(GrRect::MakeWH(texture->width(), texture->height())); 710 if (radius.fWidth > 0) { 711 context->setRenderTarget(temp1->asRenderTarget()); 712 context->applyMorphology(texture, srcRect, radius.fWidth, filter, 713 GrSamplerState::kX_FilterDirection); 714 SkIRect clearRect = SkIRect::MakeXYWH( 715 srcRect.fLeft, srcRect.fBottom, 716 srcRect.width(), radius.fHeight); 717 context->clear(&clearRect, 0x0); 718 texture = temp1; 719 } 720 if (radius.fHeight > 0) { 721 context->setRenderTarget(temp2->asRenderTarget()); 722 context->applyMorphology(texture, srcRect, radius.fHeight, filter, 723 GrSamplerState::kY_FilterDirection); 724 texture = temp2; 725 } 726 context->setRenderTarget(oldRenderTarget); 727 context->setClip(oldClip); 728 return texture; 729 } 730 731 static void buildKernel(float sigma, float* kernel, int kernelWidth) { 732 int halfWidth = (kernelWidth - 1) / 2; 733 float sum = 0.0f; 734 float denom = 1.0f / (2.0f * sigma * sigma); 735 for (int i = 0; i < kernelWidth; ++i) { 736 float x = static_cast<float>(i - halfWidth); 737 // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian 738 // is dropped here, since we renormalize the kernel below. 739 kernel[i] = sk_float_exp(- x * x * denom); 740 sum += kernel[i]; 741 } 742 // Normalize the kernel 743 float scale = 1.0f / sum; 744 for (int i = 0; i < kernelWidth; ++i) 745 kernel[i] *= scale; 746 } 747 748 static void scaleRect(SkRect* rect, float xScale, float yScale) { 749 rect->fLeft *= xScale; 750 rect->fTop *= yScale; 751 rect->fRight *= xScale; 752 rect->fBottom *= yScale; 753 } 754 755 static float adjustSigma(float sigma, int *scaleFactor, int *halfWidth, 756 int *kernelWidth) { 757 *scaleFactor = 1; 758 while (sigma > MAX_BLUR_SIGMA) { 759 *scaleFactor *= 2; 760 sigma *= 0.5f; 761 } 762 *halfWidth = static_cast<int>(ceilf(sigma * 3.0f)); 763 *kernelWidth = *halfWidth * 2 + 1; 764 return sigma; 765 } 766 767 // Apply a Gaussian blur to srcTexture by sigmaX and sigmaY, within the given 768 // rect. 769 // temp1 and temp2 are used for allocation of intermediate textures. 770 // If temp2 is non-NULL, srcTexture will be untouched, and the return 771 // value will be either temp1 or temp2. 772 // If temp2 is NULL, srcTexture will be overwritten with intermediate 773 // results, and the return value will either be temp1 or srcTexture. 774 static GrTexture* gaussianBlur(GrContext* context, GrTexture* srcTexture, 775 GrAutoScratchTexture* temp1, 776 GrAutoScratchTexture* temp2, 777 const SkRect& rect, 778 float sigmaX, float sigmaY) { 779 780 GrRenderTarget* oldRenderTarget = context->getRenderTarget(); 781 GrClip oldClip = context->getClip(); 782 GrTexture* origTexture = srcTexture; 783 GrAutoMatrix avm(context, GrMatrix::I()); 784 SkIRect clearRect; 785 int scaleFactorX, halfWidthX, kernelWidthX; 786 int scaleFactorY, halfWidthY, kernelWidthY; 787 sigmaX = adjustSigma(sigmaX, &scaleFactorX, &halfWidthX, &kernelWidthX); 788 sigmaY = adjustSigma(sigmaY, &scaleFactorY, &halfWidthY, &kernelWidthY); 789 790 SkRect srcRect(rect); 791 scaleRect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); 792 srcRect.roundOut(); 793 scaleRect(&srcRect, scaleFactorX, scaleFactorY); 794 context->setClip(srcRect); 795 796 const GrTextureDesc desc = { 797 kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit, 798 srcRect.width(), 799 srcRect.height(), 800 kRGBA_8888_GrPixelConfig, 801 {0} // samples 802 }; 803 804 temp1->set(context, desc); 805 if (temp2) temp2->set(context, desc); 806 807 GrTexture* dstTexture = temp1->texture(); 808 GrPaint paint; 809 paint.reset(); 810 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); 811 812 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { 813 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), 814 srcTexture->height()); 815 context->setRenderTarget(dstTexture->asRenderTarget()); 816 SkRect dstRect(srcRect); 817 scaleRect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, 818 i < scaleFactorY ? 0.5f : 1.0f); 819 paint.setTexture(0, srcTexture); 820 context->drawRectToRect(paint, dstRect, srcRect); 821 srcRect = dstRect; 822 SkTSwap(srcTexture, dstTexture); 823 // If temp2 is non-NULL, don't render back to origTexture 824 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); 825 } 826 827 if (sigmaX > 0.0f) { 828 SkAutoTMalloc<float> kernelStorageX(kernelWidthX); 829 float* kernelX = kernelStorageX.get(); 830 buildKernel(sigmaX, kernelX, kernelWidthX); 831 832 if (scaleFactorX > 1) { 833 // Clear out a halfWidth to the right of the srcRect to prevent the 834 // X convolution from reading garbage. 835 clearRect = SkIRect::MakeXYWH( 836 srcRect.fRight, srcRect.fTop, halfWidthX, srcRect.height()); 837 context->clear(&clearRect, 0x0); 838 } 839 840 context->setRenderTarget(dstTexture->asRenderTarget()); 841 context->convolve(srcTexture, srcRect, kernelX, kernelWidthX, 842 GrSamplerState::kX_FilterDirection); 843 SkTSwap(srcTexture, dstTexture); 844 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); 845 } 846 847 if (sigmaY > 0.0f) { 848 SkAutoTMalloc<float> kernelStorageY(kernelWidthY); 849 float* kernelY = kernelStorageY.get(); 850 buildKernel(sigmaY, kernelY, kernelWidthY); 851 852 if (scaleFactorY > 1 || sigmaX > 0.0f) { 853 // Clear out a halfWidth below the srcRect to prevent the Y 854 // convolution from reading garbage. 855 clearRect = SkIRect::MakeXYWH( 856 srcRect.fLeft, srcRect.fBottom, srcRect.width(), halfWidthY); 857 context->clear(&clearRect, 0x0); 858 } 859 860 context->setRenderTarget(dstTexture->asRenderTarget()); 861 context->convolve(srcTexture, srcRect, kernelY, kernelWidthY, 862 GrSamplerState::kY_FilterDirection); 863 SkTSwap(srcTexture, dstTexture); 864 if (temp2 && dstTexture == origTexture) dstTexture = temp2->texture(); 865 } 866 867 if (scaleFactorX > 1 || scaleFactorY > 1) { 868 // Clear one pixel to the right and below, to accommodate bilinear 869 // upsampling. 870 clearRect = SkIRect::MakeXYWH( 871 srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); 872 context->clear(&clearRect, 0x0); 873 clearRect = SkIRect::MakeXYWH( 874 srcRect.fRight, srcRect.fTop, 1, srcRect.height()); 875 context->clear(&clearRect, 0x0); 876 // FIXME: This should be mitchell, not bilinear. 877 paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter); 878 paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(), 879 srcTexture->height()); 880 context->setRenderTarget(dstTexture->asRenderTarget()); 881 paint.setTexture(0, srcTexture); 882 SkRect dstRect(srcRect); 883 scaleRect(&dstRect, scaleFactorX, scaleFactorY); 884 context->drawRectToRect(paint, dstRect, srcRect); 885 srcRect = dstRect; 886 SkTSwap(srcTexture, dstTexture); 887 } 888 context->setRenderTarget(oldRenderTarget); 889 context->setClip(oldClip); 890 return srcTexture; 891 } 892 893 static bool drawWithGPUMaskFilter(GrContext* context, const SkPath& path, 894 SkMaskFilter* filter, const SkMatrix& matrix, 895 const SkRegion& clip, SkBounder* bounder, 896 GrPaint* grp) { 897 #ifdef SK_DISABLE_GPU_BLUR 898 return false; 899 #endif 900 SkMaskFilter::BlurInfo info; 901 SkMaskFilter::BlurType blurType = filter->asABlur(&info); 902 if (SkMaskFilter::kNone_BlurType == blurType) { 903 return false; 904 } 905 SkScalar radius = info.fIgnoreTransform ? info.fRadius 906 : matrix.mapRadius(info.fRadius); 907 radius = SkMinScalar(radius, MAX_BLUR_RADIUS); 908 if (radius <= 0) { 909 return false; 910 } 911 float sigma = SkScalarToFloat(radius) * BLUR_SIGMA_SCALE; 912 float sigma3 = sigma * 3.0f; 913 914 SkRect srcRect = path.getBounds(); 915 SkRect clipRect; 916 clipRect.set(clip.getBounds()); 917 918 // Outset srcRect and clipRect by 3 * sigma, to compute affected blur area. 919 srcRect.inset(-sigma3, -sigma3); 920 clipRect.inset(-sigma3, -sigma3); 921 srcRect.intersect(clipRect); 922 SkRect finalRect = srcRect; 923 SkIRect finalIRect; 924 finalRect.roundOut(&finalIRect); 925 if (clip.quickReject(finalIRect)) { 926 return true; 927 } 928 if (bounder && !bounder->doIRect(finalIRect)) { 929 return true; 930 } 931 GrPoint offset = GrPoint::Make(-srcRect.fLeft, -srcRect.fTop); 932 srcRect.offset(offset); 933 const GrTextureDesc desc = { 934 kRenderTarget_GrTextureFlagBit, 935 srcRect.width(), 936 srcRect.height(), 937 // We actually only need A8, but it often isn't supported as a 938 // render target 939 kRGBA_8888_PM_GrPixelConfig, 940 {0} // samples 941 }; 942 943 GrAutoScratchTexture pathEntry(context, desc); 944 GrTexture* pathTexture = pathEntry.texture(); 945 if (NULL == pathTexture) { 946 return false; 947 } 948 GrRenderTarget* oldRenderTarget = context->getRenderTarget(); 949 // Once this code moves into GrContext, this should be changed to use 950 // an AutoClipRestore. 951 GrClip oldClip = context->getClip(); 952 context->setRenderTarget(pathTexture->asRenderTarget()); 953 context->setClip(srcRect); 954 context->clear(NULL, 0); 955 GrPaint tempPaint; 956 tempPaint.reset(); 957 958 GrAutoMatrix avm(context, GrMatrix::I()); 959 tempPaint.fAntiAlias = grp->fAntiAlias; 960 if (tempPaint.fAntiAlias) { 961 // AA uses the "coverage" stages on GrDrawTarget. Coverage with a dst 962 // blend coeff of zero requires dual source blending support in order 963 // to properly blend partially covered pixels. This means the AA 964 // code path may not be taken. So we use a dst blend coeff of ISA. We 965 // could special case AA draws to a dst surface with known alpha=0 to 966 // use a zero dst coeff when dual source blending isn't available. 967 tempPaint.fSrcBlendCoeff = kOne_BlendCoeff; 968 tempPaint.fDstBlendCoeff = kISC_BlendCoeff; 969 } 970 // Draw hard shadow to pathTexture with path topleft at origin 0,0. 971 context->drawPath(tempPaint, path, skToGrFillType(path.getFillType()), &offset); 972 973 GrAutoScratchTexture temp1, temp2; 974 // If we're doing a normal blur, we can clobber the pathTexture in the 975 // gaussianBlur. Otherwise, we need to save it for later compositing. 976 bool isNormalBlur = blurType == SkMaskFilter::kNormal_BlurType; 977 GrTexture* blurTexture = gaussianBlur(context, pathTexture, 978 &temp1, isNormalBlur ? NULL : &temp2, 979 srcRect, sigma, sigma); 980 981 if (!isNormalBlur) { 982 GrPaint paint; 983 paint.reset(); 984 paint.textureSampler(0)->setFilter(GrSamplerState::kNearest_Filter); 985 paint.textureSampler(0)->matrix()->setIDiv(pathTexture->width(), 986 pathTexture->height()); 987 // Blend pathTexture over blurTexture. 988 context->setRenderTarget(blurTexture->asRenderTarget()); 989 paint.setTexture(0, pathTexture); 990 if (SkMaskFilter::kInner_BlurType == blurType) { 991 // inner: dst = dst * src 992 paint.fSrcBlendCoeff = kDC_BlendCoeff; 993 paint.fDstBlendCoeff = kZero_BlendCoeff; 994 } else if (SkMaskFilter::kSolid_BlurType == blurType) { 995 // solid: dst = src + dst - src * dst 996 // = (1 - dst) * src + 1 * dst 997 paint.fSrcBlendCoeff = kIDC_BlendCoeff; 998 paint.fDstBlendCoeff = kOne_BlendCoeff; 999 } else if (SkMaskFilter::kOuter_BlurType == blurType) { 1000 // outer: dst = dst * (1 - src) 1001 // = 0 * src + (1 - src) * dst 1002 paint.fSrcBlendCoeff = kZero_BlendCoeff; 1003 paint.fDstBlendCoeff = kISC_BlendCoeff; 1004 } 1005 context->drawRect(paint, srcRect); 1006 } 1007 context->setRenderTarget(oldRenderTarget); 1008 context->setClip(oldClip); 1009 1010 if (grp->hasTextureOrMask()) { 1011 GrMatrix inverse; 1012 if (!matrix.invert(&inverse)) { 1013 return false; 1014 } 1015 grp->preConcatActiveSamplerMatrices(inverse); 1016 } 1017 1018 static const int MASK_IDX = GrPaint::kMaxMasks - 1; 1019 // we assume the last mask index is available for use 1020 GrAssert(NULL == grp->getMask(MASK_IDX)); 1021 grp->setMask(MASK_IDX, blurTexture); 1022 grp->maskSampler(MASK_IDX)->reset(); 1023 1024 grp->maskSampler(MASK_IDX)->matrix()->setTranslate(-finalRect.fLeft, 1025 -finalRect.fTop); 1026 grp->maskSampler(MASK_IDX)->matrix()->postIDiv(blurTexture->width(), 1027 blurTexture->height()); 1028 context->drawRect(*grp, finalRect); 1029 return true; 1030 } 1031 1032 static bool drawWithMaskFilter(GrContext* context, const SkPath& path, 1033 SkMaskFilter* filter, const SkMatrix& matrix, 1034 const SkRegion& clip, SkBounder* bounder, 1035 GrPaint* grp) { 1036 SkMask srcM, dstM; 1037 1038 if (!SkDraw::DrawToMask(path, &clip.getBounds(), filter, &matrix, &srcM, 1039 SkMask::kComputeBoundsAndRenderImage_CreateMode)) { 1040 return false; 1041 } 1042 SkAutoMaskFreeImage autoSrc(srcM.fImage); 1043 1044 if (!filter->filterMask(&dstM, srcM, matrix, NULL)) { 1045 return false; 1046 } 1047 // this will free-up dstM when we're done (allocated in filterMask()) 1048 SkAutoMaskFreeImage autoDst(dstM.fImage); 1049 1050 if (clip.quickReject(dstM.fBounds)) { 1051 return false; 1052 } 1053 if (bounder && !bounder->doIRect(dstM.fBounds)) { 1054 return false; 1055 } 1056 1057 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using 1058 // the current clip (and identity matrix) and grpaint settings 1059 1060 // used to compute inverse view, if necessary 1061 GrMatrix ivm = context->getMatrix(); 1062 1063 GrAutoMatrix avm(context, GrMatrix::I()); 1064 1065 const GrTextureDesc desc = { 1066 kNone_GrTextureFlags, 1067 dstM.fBounds.width(), 1068 dstM.fBounds.height(), 1069 kAlpha_8_GrPixelConfig, 1070 {0}, // samples 1071 }; 1072 1073 GrAutoScratchTexture ast(context, desc); 1074 GrTexture* texture = ast.texture(); 1075 1076 if (NULL == texture) { 1077 return false; 1078 } 1079 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, 1080 dstM.fImage, dstM.fRowBytes); 1081 1082 if (grp->hasTextureOrMask() && ivm.invert(&ivm)) { 1083 grp->preConcatActiveSamplerMatrices(ivm); 1084 } 1085 1086 static const int MASK_IDX = GrPaint::kMaxMasks - 1; 1087 // we assume the last mask index is available for use 1088 GrAssert(NULL == grp->getMask(MASK_IDX)); 1089 grp->setMask(MASK_IDX, texture); 1090 grp->maskSampler(MASK_IDX)->reset(); 1091 1092 GrRect d; 1093 d.setLTRB(GrIntToScalar(dstM.fBounds.fLeft), 1094 GrIntToScalar(dstM.fBounds.fTop), 1095 GrIntToScalar(dstM.fBounds.fRight), 1096 GrIntToScalar(dstM.fBounds.fBottom)); 1097 1098 GrMatrix* m = grp->maskSampler(MASK_IDX)->matrix(); 1099 m->setTranslate(-dstM.fBounds.fLeft*SK_Scalar1, 1100 -dstM.fBounds.fTop*SK_Scalar1); 1101 m->postIDiv(texture->width(), texture->height()); 1102 context->drawRect(*grp, d); 1103 return true; 1104 } 1105 1106 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath, 1107 const SkPaint& paint, const SkMatrix* prePathMatrix, 1108 bool pathIsMutable) { 1109 CHECK_SHOULD_DRAW(draw); 1110 1111 bool doFill = true; 1112 1113 SkScalar coverage = SK_Scalar1; 1114 // can we cheat, and threat a thin stroke as a hairline w/ coverage 1115 // if we can, we draw lots faster (raster device does this same test) 1116 if (SkDrawTreatAsHairline(paint, *draw.fMatrix, &coverage)) { 1117 doFill = false; 1118 } 1119 1120 GrPaint grPaint; 1121 SkAutoCachedTexture act; 1122 if (!this->skPaint2GrPaintShader(paint, 1123 &act, 1124 *draw.fMatrix, 1125 &grPaint, 1126 true)) { 1127 return; 1128 } 1129 1130 grPaint.fCoverage = SkScalarRoundToInt(coverage * grPaint.fCoverage); 1131 1132 // If we have a prematrix, apply it to the path, optimizing for the case 1133 // where the original path can in fact be modified in place (even though 1134 // its parameter type is const). 1135 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); 1136 SkPath tmpPath; 1137 1138 if (prePathMatrix) { 1139 SkPath* result = pathPtr; 1140 1141 if (!pathIsMutable) { 1142 result = &tmpPath; 1143 pathIsMutable = true; 1144 } 1145 // should I push prePathMatrix on our MV stack temporarily, instead 1146 // of applying it here? See SkDraw.cpp 1147 pathPtr->transform(*prePathMatrix, result); 1148 pathPtr = result; 1149 } 1150 // at this point we're done with prePathMatrix 1151 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) 1152 1153 if (paint.getPathEffect() || 1154 (doFill && paint.getStyle() != SkPaint::kFill_Style)) { 1155 // it is safe to use tmpPath here, even if we already used it for the 1156 // prepathmatrix, since getFillPath can take the same object for its 1157 // input and output safely. 1158 doFill = paint.getFillPath(*pathPtr, &tmpPath); 1159 pathPtr = &tmpPath; 1160 } 1161 1162 if (paint.getMaskFilter()) { 1163 // avoid possibly allocating a new path in transform if we can 1164 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath; 1165 1166 // transform the path into device space 1167 pathPtr->transform(*draw.fMatrix, devPathPtr); 1168 if (!drawWithGPUMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(), 1169 *draw.fMatrix, *draw.fClip, draw.fBounder, 1170 &grPaint)) { 1171 drawWithMaskFilter(fContext, *devPathPtr, paint.getMaskFilter(), 1172 *draw.fMatrix, *draw.fClip, draw.fBounder, 1173 &grPaint); 1174 } 1175 return; 1176 } 1177 1178 GrPathFill fill = kHairLine_PathFill; 1179 1180 if (doFill) { 1181 switch (pathPtr->getFillType()) { 1182 case SkPath::kWinding_FillType: 1183 fill = kWinding_PathFill; 1184 break; 1185 case SkPath::kEvenOdd_FillType: 1186 fill = kEvenOdd_PathFill; 1187 break; 1188 case SkPath::kInverseWinding_FillType: 1189 fill = kInverseWinding_PathFill; 1190 break; 1191 case SkPath::kInverseEvenOdd_FillType: 1192 fill = kInverseEvenOdd_PathFill; 1193 break; 1194 default: 1195 SkDebugf("Unsupported path fill type\n"); 1196 return; 1197 } 1198 } 1199 1200 fContext->drawPath(grPaint, *pathPtr, fill); 1201 } 1202 1203 namespace { 1204 1205 inline int get_tile_count(int l, int t, int r, int b, int tileSize) { 1206 int tilesX = (r / tileSize) - (l / tileSize) + 1; 1207 int tilesY = (b / tileSize) - (t / tileSize) + 1; 1208 return tilesX * tilesY; 1209 } 1210 1211 inline int determine_tile_size(const SkBitmap& bitmap, 1212 const SkIRect* srcRectPtr, 1213 int maxTextureSize) { 1214 static const int kSmallTileSize = 1 << 10; 1215 if (maxTextureSize <= kSmallTileSize) { 1216 return maxTextureSize; 1217 } 1218 1219 size_t maxTexTotalTileSize; 1220 size_t smallTotalTileSize; 1221 1222 if (NULL == srcRectPtr) { 1223 int w = bitmap.width(); 1224 int h = bitmap.height(); 1225 maxTexTotalTileSize = get_tile_count(0, 0, w, h, maxTextureSize); 1226 smallTotalTileSize = get_tile_count(0, 0, w, h, kSmallTileSize); 1227 } else { 1228 maxTexTotalTileSize = get_tile_count(srcRectPtr->fLeft, 1229 srcRectPtr->fTop, 1230 srcRectPtr->fRight, 1231 srcRectPtr->fBottom, 1232 maxTextureSize); 1233 smallTotalTileSize = get_tile_count(srcRectPtr->fLeft, 1234 srcRectPtr->fTop, 1235 srcRectPtr->fRight, 1236 srcRectPtr->fBottom, 1237 kSmallTileSize); 1238 } 1239 maxTexTotalTileSize *= maxTextureSize * maxTextureSize; 1240 smallTotalTileSize *= kSmallTileSize * kSmallTileSize; 1241 1242 if (maxTexTotalTileSize > 2 * smallTotalTileSize) { 1243 return kSmallTileSize; 1244 } else { 1245 return maxTextureSize; 1246 } 1247 } 1248 } 1249 1250 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap, 1251 const GrSamplerState& sampler, 1252 const SkIRect* srcRectPtr, 1253 int* tileSize) const { 1254 SkASSERT(NULL != tileSize); 1255 1256 // if bitmap is explictly texture backed then just use the texture 1257 if (NULL != bitmap.getTexture()) { 1258 return false; 1259 } 1260 // if it's larger than the max texture size, then we have no choice but 1261 // tiling 1262 const int maxTextureSize = fContext->getMaxTextureSize(); 1263 if (bitmap.width() > maxTextureSize || 1264 bitmap.height() > maxTextureSize) { 1265 *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize); 1266 return true; 1267 } 1268 // if we are going to have to draw the whole thing, then don't tile 1269 if (NULL == srcRectPtr) { 1270 return false; 1271 } 1272 // if the entire texture is already in our cache then no reason to tile it 1273 if (this->isBitmapInTextureCache(bitmap, sampler)) { 1274 return false; 1275 } 1276 1277 // At this point we know we could do the draw by uploading the entire bitmap 1278 // as a texture. However, if the texture would be large compared to the 1279 // cache size and we don't require most of it for this draw then tile to 1280 // reduce the amount of upload and cache spill. 1281 1282 // assumption here is that sw bitmap size is a good proxy for its size as 1283 // a texture 1284 size_t bmpSize = bitmap.getSize(); 1285 size_t cacheSize; 1286 fContext->getTextureCacheLimits(NULL, &cacheSize); 1287 if (bmpSize < cacheSize / 2) { 1288 return false; 1289 } 1290 1291 SkFixed fracUsed = 1292 SkFixedMul((srcRectPtr->width() << 16) / bitmap.width(), 1293 (srcRectPtr->height() << 16) / bitmap.height()); 1294 if (fracUsed <= SK_FixedHalf) { 1295 *tileSize = determine_tile_size(bitmap, srcRectPtr, maxTextureSize); 1296 return true; 1297 } else { 1298 return false; 1299 } 1300 } 1301 1302 void SkGpuDevice::drawBitmap(const SkDraw& draw, 1303 const SkBitmap& bitmap, 1304 const SkIRect* srcRectPtr, 1305 const SkMatrix& m, 1306 const SkPaint& paint) { 1307 CHECK_SHOULD_DRAW(draw); 1308 1309 SkIRect srcRect; 1310 if (NULL == srcRectPtr) { 1311 srcRect.set(0, 0, bitmap.width(), bitmap.height()); 1312 } else { 1313 srcRect = *srcRectPtr; 1314 } 1315 1316 if (paint.getMaskFilter()){ 1317 // Convert the bitmap to a shader so that the rect can be drawn 1318 // through drawRect, which supports mask filters. 1319 SkBitmap tmp; // subset of bitmap, if necessary 1320 const SkBitmap* bitmapPtr = &bitmap; 1321 if (srcRectPtr) { 1322 if (!bitmap.extractSubset(&tmp, srcRect)) { 1323 return; // extraction failed 1324 } 1325 bitmapPtr = &tmp; 1326 srcRect.set(0,0, srcRect.width(), srcRect.height()); 1327 } 1328 SkPaint paintWithTexture(paint); 1329 paintWithTexture.setShader(SkShader::CreateBitmapShader( *bitmapPtr, 1330 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode))->unref(); 1331 SkRect ScalarRect; 1332 ScalarRect.set(srcRect); 1333 1334 // Transform 'm' needs to be concatenated to the draw matrix, 1335 // rather than transforming the primitive directly, so that 'm' will 1336 // also affect the behavior of the mask filter. 1337 SkMatrix drawMatrix; 1338 drawMatrix.setConcat(*draw.fMatrix, m); 1339 SkDraw transformedDraw(draw); 1340 transformedDraw.fMatrix = &drawMatrix; 1341 1342 this->drawRect(transformedDraw, ScalarRect, paintWithTexture); 1343 1344 return; 1345 } 1346 1347 GrPaint grPaint; 1348 if (!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) { 1349 return; 1350 } 1351 GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx); 1352 if (paint.isFilterBitmap()) { 1353 sampler->setFilter(GrSamplerState::kBilinear_Filter); 1354 } else { 1355 sampler->setFilter(GrSamplerState::kNearest_Filter); 1356 } 1357 1358 int tileSize; 1359 if (!this->shouldTileBitmap(bitmap, *sampler, srcRectPtr, &tileSize)) { 1360 // take the simple case 1361 this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint); 1362 return; 1363 } 1364 1365 // undo the translate done by SkCanvas 1366 int DX = SkMax32(0, srcRect.fLeft); 1367 int DY = SkMax32(0, srcRect.fTop); 1368 // compute clip bounds in local coordinates 1369 SkIRect clipRect; 1370 { 1371 SkRect r; 1372 r.set(draw.fClip->getBounds()); 1373 SkMatrix matrix, inverse; 1374 matrix.setConcat(*draw.fMatrix, m); 1375 if (!matrix.invert(&inverse)) { 1376 return; 1377 } 1378 inverse.mapRect(&r); 1379 r.roundOut(&clipRect); 1380 // apply the canvas' translate to our local clip 1381 clipRect.offset(DX, DY); 1382 } 1383 1384 int nx = bitmap.width() / tileSize; 1385 int ny = bitmap.height() / tileSize; 1386 for (int x = 0; x <= nx; x++) { 1387 for (int y = 0; y <= ny; y++) { 1388 SkIRect tileR; 1389 tileR.set(x * tileSize, y * tileSize, 1390 (x + 1) * tileSize, (y + 1) * tileSize); 1391 if (!SkIRect::Intersects(tileR, clipRect)) { 1392 continue; 1393 } 1394 1395 SkIRect srcR = tileR; 1396 if (!srcR.intersect(srcRect)) { 1397 continue; 1398 } 1399 1400 SkBitmap tmpB; 1401 if (bitmap.extractSubset(&tmpB, tileR)) { 1402 // now offset it to make it "local" to our tmp bitmap 1403 srcR.offset(-tileR.fLeft, -tileR.fTop); 1404 1405 SkMatrix tmpM(m); 1406 { 1407 int dx = tileR.fLeft - DX + SkMax32(0, srcR.fLeft); 1408 int dy = tileR.fTop - DY + SkMax32(0, srcR.fTop); 1409 tmpM.preTranslate(SkIntToScalar(dx), SkIntToScalar(dy)); 1410 } 1411 this->internalDrawBitmap(draw, tmpB, srcR, tmpM, &grPaint); 1412 } 1413 } 1414 } 1415 } 1416 1417 /* 1418 * This is called by drawBitmap(), which has to handle images that may be too 1419 * large to be represented by a single texture. 1420 * 1421 * internalDrawBitmap assumes that the specified bitmap will fit in a texture 1422 * and that non-texture portion of the GrPaint has already been setup. 1423 */ 1424 void SkGpuDevice::internalDrawBitmap(const SkDraw& draw, 1425 const SkBitmap& bitmap, 1426 const SkIRect& srcRect, 1427 const SkMatrix& m, 1428 GrPaint* grPaint) { 1429 SkASSERT(bitmap.width() <= fContext->getMaxTextureSize() && 1430 bitmap.height() <= fContext->getMaxTextureSize()); 1431 1432 SkAutoLockPixels alp(bitmap, !bitmap.getTexture()); 1433 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1434 SkDebugf("nothing to draw\n"); 1435 return; 1436 } 1437 1438 GrSamplerState* sampler = grPaint->textureSampler(kBitmapTextureIdx); 1439 1440 sampler->setWrapX(GrSamplerState::kClamp_WrapMode); 1441 sampler->setWrapY(GrSamplerState::kClamp_WrapMode); 1442 sampler->setSampleMode(GrSamplerState::kNormal_SampleMode); 1443 sampler->matrix()->reset(); 1444 1445 GrTexture* texture; 1446 SkAutoCachedTexture act(this, bitmap, sampler, &texture); 1447 if (NULL == texture) { 1448 return; 1449 } 1450 1451 grPaint->setTexture(kBitmapTextureIdx, texture); 1452 1453 GrRect dstRect = SkRect::MakeWH(GrIntToScalar(srcRect.width()), 1454 GrIntToScalar(srcRect.height())); 1455 GrRect paintRect; 1456 paintRect.setLTRB(GrFixedToScalar((srcRect.fLeft << 16) / bitmap.width()), 1457 GrFixedToScalar((srcRect.fTop << 16) / bitmap.height()), 1458 GrFixedToScalar((srcRect.fRight << 16) / bitmap.width()), 1459 GrFixedToScalar((srcRect.fBottom << 16) / bitmap.height())); 1460 1461 if (GrSamplerState::kNearest_Filter != sampler->getFilter() && 1462 (srcRect.width() < bitmap.width() || 1463 srcRect.height() < bitmap.height())) { 1464 // If drawing a subrect of the bitmap and filtering is enabled, 1465 // use a constrained texture domain to avoid color bleeding 1466 GrScalar left, top, right, bottom; 1467 if (srcRect.width() > 1) { 1468 GrScalar border = GR_ScalarHalf / bitmap.width(); 1469 left = paintRect.left() + border; 1470 right = paintRect.right() - border; 1471 } else { 1472 left = right = GrScalarHalf(paintRect.left() + paintRect.right()); 1473 } 1474 if (srcRect.height() > 1) { 1475 GrScalar border = GR_ScalarHalf / bitmap.height(); 1476 top = paintRect.top() + border; 1477 bottom = paintRect.bottom() - border; 1478 } else { 1479 top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom()); 1480 } 1481 GrRect textureDomain; 1482 textureDomain.setLTRB(left, top, right, bottom); 1483 sampler->setTextureDomain(textureDomain); 1484 } 1485 1486 fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m); 1487 } 1488 1489 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap, 1490 int left, int top, const SkPaint& paint) { 1491 CHECK_SHOULD_DRAW(draw); 1492 1493 SkAutoLockPixels alp(bitmap); 1494 if (!bitmap.getTexture() && !bitmap.readyToDraw()) { 1495 return; 1496 } 1497 1498 int w = bitmap.width(); 1499 int h = bitmap.height(); 1500 1501 GrPaint grPaint; 1502 if(!this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) { 1503 return; 1504 } 1505 1506 GrAutoMatrix avm(fContext, GrMatrix::I()); 1507 1508 GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx); 1509 1510 GrTexture* texture; 1511 sampler->reset(); 1512 SkAutoCachedTexture act(this, bitmap, sampler, &texture); 1513 1514 SkImageFilter* imageFilter = paint.getImageFilter(); 1515 SkSize blurSize; 1516 SkISize radius; 1517 if (NULL != imageFilter && imageFilter->asABlur(&blurSize)) { 1518 GrAutoScratchTexture temp1, temp2; 1519 GrTexture* blurTexture = gaussianBlur(fContext, 1520 texture, &temp1, &temp2, 1521 GrRect::MakeWH(w, h), 1522 blurSize.width(), 1523 blurSize.height()); 1524 texture = blurTexture; 1525 grPaint.setTexture(kBitmapTextureIdx, texture); 1526 } else if (NULL != imageFilter && imageFilter->asADilate(&radius)) { 1527 const GrTextureDesc desc = { 1528 kRenderTarget_GrTextureFlagBit, 1529 w, 1530 h, 1531 kRGBA_8888_PM_GrPixelConfig, 1532 {0} // samples 1533 }; 1534 GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc); 1535 texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h), 1536 temp1.texture(), temp2.texture(), 1537 GrSamplerState::kDilate_Filter, radius); 1538 grPaint.setTexture(kBitmapTextureIdx, texture); 1539 } else if (NULL != imageFilter && imageFilter->asAnErode(&radius)) { 1540 const GrTextureDesc desc = { 1541 kRenderTarget_GrTextureFlagBit, 1542 w, 1543 h, 1544 kRGBA_8888_PM_GrPixelConfig, 1545 {0} // samples 1546 }; 1547 GrAutoScratchTexture temp1(fContext, desc), temp2(fContext, desc); 1548 texture = applyMorphology(fContext, texture, GrRect::MakeWH(w, h), 1549 temp1.texture(), temp2.texture(), 1550 GrSamplerState::kErode_Filter, radius); 1551 grPaint.setTexture(kBitmapTextureIdx, texture); 1552 } else { 1553 grPaint.setTexture(kBitmapTextureIdx, texture); 1554 } 1555 1556 fContext->drawRectToRect(grPaint, 1557 GrRect::MakeXYWH(GrIntToScalar(left), 1558 GrIntToScalar(top), 1559 GrIntToScalar(w), 1560 GrIntToScalar(h)), 1561 GrRect::MakeWH(GR_Scalar1 * w / texture->width(), 1562 GR_Scalar1 * h / texture->height())); 1563 } 1564 1565 void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* dev, 1566 int x, int y, const SkPaint& paint) { 1567 CHECK_SHOULD_DRAW(draw); 1568 1569 GrPaint grPaint; 1570 if (!((SkGpuDevice*)dev)->bindDeviceAsTexture(&grPaint) || 1571 !this->skPaint2GrPaintNoShader(paint, true, &grPaint, false)) { 1572 return; 1573 } 1574 1575 GrTexture* devTex = grPaint.getTexture(0); 1576 SkASSERT(NULL != devTex); 1577 1578 const SkBitmap& bm = dev->accessBitmap(false); 1579 int w = bm.width(); 1580 int h = bm.height(); 1581 1582 GrAutoMatrix avm(fContext, GrMatrix::I()); 1583 1584 grPaint.textureSampler(kBitmapTextureIdx)->reset(); 1585 1586 GrRect dstRect = GrRect::MakeXYWH(GrIntToScalar(x), 1587 GrIntToScalar(y), 1588 GrIntToScalar(w), 1589 GrIntToScalar(h)); 1590 1591 // The device being drawn may not fill up its texture (saveLayer uses 1592 // the approximate ). 1593 GrRect srcRect = GrRect::MakeWH(GR_Scalar1 * w / devTex->width(), 1594 GR_Scalar1 * h / devTex->height()); 1595 1596 fContext->drawRectToRect(grPaint, dstRect, srcRect); 1597 } 1598 1599 bool SkGpuDevice::filterImage(SkImageFilter* filter, const SkBitmap& src, 1600 const SkMatrix& ctm, 1601 SkBitmap* result, SkIPoint* offset) { 1602 SkSize size; 1603 SkISize radius; 1604 if (!filter->asABlur(&size) && !filter->asADilate(&radius) && !filter->asAnErode(&radius)) { 1605 return false; 1606 } 1607 SkDevice* dev = this->createCompatibleDevice(SkBitmap::kARGB_8888_Config, 1608 src.width(), 1609 src.height(), 1610 false); 1611 if (NULL == dev) { 1612 return false; 1613 } 1614 SkAutoUnref aur(dev); 1615 SkCanvas canvas(dev); 1616 SkPaint paint; 1617 paint.setImageFilter(filter); 1618 canvas.drawSprite(src, 0, 0, &paint); 1619 *result = dev->accessBitmap(false); 1620 return true; 1621 } 1622 1623 /////////////////////////////////////////////////////////////////////////////// 1624 1625 // must be in SkCanvas::VertexMode order 1626 static const GrPrimitiveType gVertexMode2PrimitiveType[] = { 1627 kTriangles_PrimitiveType, 1628 kTriangleStrip_PrimitiveType, 1629 kTriangleFan_PrimitiveType, 1630 }; 1631 1632 void SkGpuDevice::drawVertices(const SkDraw& draw, SkCanvas::VertexMode vmode, 1633 int vertexCount, const SkPoint vertices[], 1634 const SkPoint texs[], const SkColor colors[], 1635 SkXfermode* xmode, 1636 const uint16_t indices[], int indexCount, 1637 const SkPaint& paint) { 1638 CHECK_SHOULD_DRAW(draw); 1639 1640 GrPaint grPaint; 1641 SkAutoCachedTexture act; 1642 // we ignore the shader if texs is null. 1643 if (NULL == texs) { 1644 if (!this->skPaint2GrPaintNoShader(paint, 1645 false, 1646 &grPaint, 1647 NULL == colors)) { 1648 return; 1649 } 1650 } else { 1651 if (!this->skPaint2GrPaintShader(paint, &act, 1652 *draw.fMatrix, 1653 &grPaint, 1654 NULL == colors)) { 1655 return; 1656 } 1657 } 1658 1659 if (NULL != xmode && NULL != texs && NULL != colors) { 1660 if (!SkXfermode::IsMode(xmode, SkXfermode::kMultiply_Mode)) { 1661 SkDebugf("Unsupported vertex-color/texture xfer mode.\n"); 1662 #if 0 1663 return 1664 #endif 1665 } 1666 } 1667 1668 SkAutoSTMalloc<128, GrColor> convertedColors(0); 1669 if (NULL != colors) { 1670 // need to convert byte order and from non-PM to PM 1671 convertedColors.reset(vertexCount); 1672 for (int i = 0; i < vertexCount; ++i) { 1673 convertedColors[i] = SkGr::SkColor2GrColor(colors[i]); 1674 } 1675 colors = convertedColors.get(); 1676 } 1677 fContext->drawVertices(grPaint, 1678 gVertexMode2PrimitiveType[vmode], 1679 vertexCount, 1680 (GrPoint*) vertices, 1681 (GrPoint*) texs, 1682 colors, 1683 indices, 1684 indexCount); 1685 } 1686 1687 /////////////////////////////////////////////////////////////////////////////// 1688 1689 static void GlyphCacheAuxProc(void* data) { 1690 delete (GrFontScaler*)data; 1691 } 1692 1693 static GrFontScaler* get_gr_font_scaler(SkGlyphCache* cache) { 1694 void* auxData; 1695 GrFontScaler* scaler = NULL; 1696 if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) { 1697 scaler = (GrFontScaler*)auxData; 1698 } 1699 if (NULL == scaler) { 1700 scaler = new SkGrFontScaler(cache); 1701 cache->setAuxProc(GlyphCacheAuxProc, scaler); 1702 } 1703 return scaler; 1704 } 1705 1706 static void SkGPU_Draw1Glyph(const SkDraw1Glyph& state, 1707 SkFixed fx, SkFixed fy, 1708 const SkGlyph& glyph) { 1709 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0); 1710 1711 GrSkDrawProcs* procs = static_cast<GrSkDrawProcs*>(state.fDraw->fProcs); 1712 1713 if (NULL == procs->fFontScaler) { 1714 procs->fFontScaler = get_gr_font_scaler(state.fCache); 1715 } 1716 1717 procs->fTextContext->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1718 glyph.getSubXFixed(), 1719 glyph.getSubYFixed()), 1720 SkFixedFloorToFixed(fx), 1721 SkFixedFloorToFixed(fy), 1722 procs->fFontScaler); 1723 } 1724 1725 SkDrawProcs* SkGpuDevice::initDrawForText(GrTextContext* context) { 1726 1727 // deferred allocation 1728 if (NULL == fDrawProcs) { 1729 fDrawProcs = new GrSkDrawProcs; 1730 fDrawProcs->fD1GProc = SkGPU_Draw1Glyph; 1731 fDrawProcs->fContext = fContext; 1732 } 1733 1734 // init our (and GL's) state 1735 fDrawProcs->fTextContext = context; 1736 fDrawProcs->fFontScaler = NULL; 1737 return fDrawProcs; 1738 } 1739 1740 void SkGpuDevice::drawText(const SkDraw& draw, const void* text, 1741 size_t byteLength, SkScalar x, SkScalar y, 1742 const SkPaint& paint) { 1743 CHECK_SHOULD_DRAW(draw); 1744 1745 if (draw.fMatrix->hasPerspective()) { 1746 // this guy will just call our drawPath() 1747 draw.drawText((const char*)text, byteLength, x, y, paint); 1748 } else { 1749 SkDraw myDraw(draw); 1750 1751 GrPaint grPaint; 1752 SkAutoCachedTexture act; 1753 1754 if (!this->skPaint2GrPaintShader(paint, 1755 &act, 1756 *draw.fMatrix, 1757 &grPaint, 1758 true)) { 1759 return; 1760 } 1761 GrTextContext context(fContext, grPaint, draw.fExtMatrix); 1762 myDraw.fProcs = this->initDrawForText(&context); 1763 this->INHERITED::drawText(myDraw, text, byteLength, x, y, paint); 1764 } 1765 } 1766 1767 void SkGpuDevice::drawPosText(const SkDraw& draw, const void* text, 1768 size_t byteLength, const SkScalar pos[], 1769 SkScalar constY, int scalarsPerPos, 1770 const SkPaint& paint) { 1771 CHECK_SHOULD_DRAW(draw); 1772 1773 if (draw.fMatrix->hasPerspective()) { 1774 // this guy will just call our drawPath() 1775 draw.drawPosText((const char*)text, byteLength, pos, constY, 1776 scalarsPerPos, paint); 1777 } else { 1778 SkDraw myDraw(draw); 1779 1780 GrPaint grPaint; 1781 SkAutoCachedTexture act; 1782 if (!this->skPaint2GrPaintShader(paint, 1783 &act, 1784 *draw.fMatrix, 1785 &grPaint, 1786 true)) { 1787 return; 1788 } 1789 1790 GrTextContext context(fContext, grPaint, draw.fExtMatrix); 1791 myDraw.fProcs = this->initDrawForText(&context); 1792 this->INHERITED::drawPosText(myDraw, text, byteLength, pos, constY, 1793 scalarsPerPos, paint); 1794 } 1795 } 1796 1797 void SkGpuDevice::drawTextOnPath(const SkDraw& draw, const void* text, 1798 size_t len, const SkPath& path, 1799 const SkMatrix* m, const SkPaint& paint) { 1800 CHECK_SHOULD_DRAW(draw); 1801 1802 SkASSERT(draw.fDevice == this); 1803 draw.drawTextOnPath((const char*)text, len, path, m, paint); 1804 } 1805 1806 /////////////////////////////////////////////////////////////////////////////// 1807 1808 bool SkGpuDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { 1809 if (!paint.isLCDRenderText()) { 1810 // we're cool with the paint as is 1811 return false; 1812 } 1813 1814 if (paint.getShader() || 1815 paint.getXfermode() || // unless its srcover 1816 paint.getMaskFilter() || 1817 paint.getRasterizer() || 1818 paint.getColorFilter() || 1819 paint.getPathEffect() || 1820 paint.isFakeBoldText() || 1821 paint.getStyle() != SkPaint::kFill_Style) { 1822 // turn off lcd 1823 flags->fFlags = paint.getFlags() & ~SkPaint::kLCDRenderText_Flag; 1824 flags->fHinting = paint.getHinting(); 1825 return true; 1826 } 1827 // we're cool with the paint as is 1828 return false; 1829 } 1830 1831 void SkGpuDevice::flush() { 1832 fContext->resolveRenderTarget(fRenderTarget); 1833 } 1834 1835 /////////////////////////////////////////////////////////////////////////////// 1836 1837 SkGpuDevice::TexCache SkGpuDevice::lockCachedTexture(const SkBitmap& bitmap, 1838 const GrSamplerState* sampler, 1839 TexType type) { 1840 GrContext::TextureCacheEntry entry; 1841 GrContext* ctx = this->context(); 1842 1843 if (kBitmap_TexType != type) { 1844 const GrTextureDesc desc = { 1845 kRenderTarget_GrTextureFlagBit, 1846 bitmap.width(), 1847 bitmap.height(), 1848 SkGr::Bitmap2PixelConfig(bitmap), 1849 {0} // samples 1850 }; 1851 GrContext::ScratchTexMatch match; 1852 if (kSaveLayerDeviceRenderTarget_TexType == type) { 1853 // we know layers will only be drawn through drawDevice. 1854 // drawDevice has been made to work with content embedded in a 1855 // larger texture so its okay to use the approximate version. 1856 match = GrContext::kApprox_ScratchTexMatch; 1857 } else { 1858 SkASSERT(kDeviceRenderTarget_TexType == type); 1859 match = GrContext::kExact_ScratchTexMatch; 1860 } 1861 entry = ctx->lockScratchTexture(desc, match); 1862 } else { 1863 if (!bitmap.isVolatile()) { 1864 GrContext::TextureKey key = bitmap.getGenerationID(); 1865 key |= ((uint64_t) bitmap.pixelRefOffset()) << 32; 1866 1867 entry = ctx->findAndLockTexture(key, bitmap.width(), 1868 bitmap.height(), sampler); 1869 if (NULL == entry.texture()) { 1870 entry = sk_gr_create_bitmap_texture(ctx, key, sampler, 1871 bitmap); 1872 } 1873 } else { 1874 entry = sk_gr_create_bitmap_texture(ctx, gUNCACHED_KEY, 1875 sampler, bitmap); 1876 } 1877 if (NULL == entry.texture()) { 1878 GrPrintf("---- failed to create texture for cache [%d %d]\n", 1879 bitmap.width(), bitmap.height()); 1880 } 1881 } 1882 return entry; 1883 } 1884 1885 void SkGpuDevice::unlockCachedTexture(TexCache cache) { 1886 this->context()->unlockTexture(cache); 1887 } 1888 1889 bool SkGpuDevice::isBitmapInTextureCache(const SkBitmap& bitmap, 1890 const GrSamplerState& sampler) const { 1891 GrContext::TextureKey key = bitmap.getGenerationID(); 1892 key |= ((uint64_t) bitmap.pixelRefOffset()) << 32; 1893 return this->context()->isTextureInCache(key, bitmap.width(), 1894 bitmap.height(), &sampler); 1895 1896 } 1897 1898 1899 SkDevice* SkGpuDevice::onCreateCompatibleDevice(SkBitmap::Config config, 1900 int width, int height, 1901 bool isOpaque, 1902 Usage usage) { 1903 return SkNEW_ARGS(SkGpuDevice,(this->context(), config, 1904 width, height, usage)); 1905 } 1906 1907