GrContext.cpp revision 00b1c3ad30c2cfc73a2b83d18a851d872b533cbc
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#include "GrContext.h" 11 12#include "effects/GrConvolutionEffect.h" 13#include "effects/GrSingleTextureEffect.h" 14#include "effects/GrConfigConversionEffect.h" 15 16#include "GrBufferAllocPool.h" 17#include "GrGpu.h" 18#include "GrIndexBuffer.h" 19#include "GrInOrderDrawBuffer.h" 20#include "GrPathRenderer.h" 21#include "GrPathUtils.h" 22#include "GrResourceCache.h" 23#include "GrSoftwarePathRenderer.h" 24#include "GrStencilBuffer.h" 25#include "GrTextStrike.h" 26#include "SkRTConf.h" 27#include "SkStrokeRec.h" 28#include "SkTLazy.h" 29#include "SkTLS.h" 30#include "SkTrace.h" 31 32SK_DEFINE_INST_COUNT(GrContext) 33SK_DEFINE_INST_COUNT(GrDrawState) 34 35// It can be useful to set this to false to test whether a bug is caused by using the 36// InOrderDrawBuffer, to compare performance of using/not using InOrderDrawBuffer, or to make 37// debugging simpler. 38SK_CONF_DECLARE(bool, c_Defer, "gpu.deferContext", true, "Defers rendering in GrContext via GrInOrderDrawBuffer."); 39 40#define BUFFERED_DRAW (c_Defer ? kYes_BufferedDraw : kNo_BufferedDraw) 41 42#define MAX_BLUR_SIGMA 4.0f 43 44// When we're using coverage AA but the blend is incompatible (given gpu 45// limitations) should we disable AA or draw wrong? 46#define DISABLE_COVERAGE_AA_FOR_BLEND 1 47 48#if GR_DEBUG 49 // change this to a 1 to see notifications when partial coverage fails 50 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0 51#else 52 #define GR_DEBUG_PARTIAL_COVERAGE_CHECK 0 53#endif 54 55static const size_t MAX_TEXTURE_CACHE_COUNT = 2048; 56static const size_t MAX_TEXTURE_CACHE_BYTES = GR_DEFAULT_TEXTURE_CACHE_MB_LIMIT * 1024 * 1024; 57 58static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15; 59static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; 60 61static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11; 62static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; 63 64#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this) 65 66GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) { 67 GrContext* context = SkNEW(GrContext); 68 if (context->init(backend, backendContext)) { 69 return context; 70 } else { 71 context->unref(); 72 return NULL; 73 } 74} 75 76namespace { 77void* CreateThreadInstanceCount() { 78 return SkNEW_ARGS(int, (0)); 79} 80void DeleteThreadInstanceCount(void* v) { 81 delete reinterpret_cast<int*>(v); 82} 83#define THREAD_INSTANCE_COUNT \ 84 (*reinterpret_cast<int*>(SkTLS::Get(CreateThreadInstanceCount, DeleteThreadInstanceCount))) 85} 86 87GrContext::GrContext() { 88 ++THREAD_INSTANCE_COUNT; 89 fDrawState = NULL; 90 fGpu = NULL; 91 fPathRendererChain = NULL; 92 fSoftwarePathRenderer = NULL; 93 fTextureCache = NULL; 94 fFontCache = NULL; 95 fDrawBuffer = NULL; 96 fDrawBufferVBAllocPool = NULL; 97 fDrawBufferIBAllocPool = NULL; 98 fAARectRenderer = NULL; 99} 100 101bool GrContext::init(GrBackend backend, GrBackendContext backendContext) { 102 GrAssert(NULL == fGpu); 103 104 fGpu = GrGpu::Create(backend, backendContext, this); 105 if (NULL == fGpu) { 106 return false; 107 } 108 109 fDrawState = SkNEW(GrDrawState); 110 fGpu->setDrawState(fDrawState); 111 112 113 fTextureCache = SkNEW_ARGS(GrResourceCache, 114 (MAX_TEXTURE_CACHE_COUNT, 115 MAX_TEXTURE_CACHE_BYTES)); 116 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu)); 117 118 fLastDrawWasBuffered = kNo_BufferedDraw; 119 120 fAARectRenderer = SkNEW(GrAARectRenderer); 121 122 fDidTestPMConversions = false; 123 124 this->setupDrawBuffer(); 125 126 return true; 127} 128 129int GrContext::GetThreadInstanceCount() { 130 return THREAD_INSTANCE_COUNT; 131} 132 133GrContext::~GrContext() { 134 for (int i = 0; i < fCleanUpData.count(); ++i) { 135 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); 136 } 137 138 this->flush(); 139 140 // Since the gpu can hold scratch textures, give it a chance to let go 141 // of them before freeing the texture cache 142 fGpu->purgeResources(); 143 144 delete fTextureCache; 145 fTextureCache = NULL; 146 delete fFontCache; 147 delete fDrawBuffer; 148 delete fDrawBufferVBAllocPool; 149 delete fDrawBufferIBAllocPool; 150 151 fAARectRenderer->unref(); 152 153 fGpu->unref(); 154 GrSafeUnref(fPathRendererChain); 155 GrSafeUnref(fSoftwarePathRenderer); 156 fDrawState->unref(); 157 158 --THREAD_INSTANCE_COUNT; 159} 160 161void GrContext::contextLost() { 162 this->contextDestroyed(); 163 this->setupDrawBuffer(); 164} 165 166void GrContext::contextDestroyed() { 167 // abandon first to so destructors 168 // don't try to free the resources in the API. 169 fGpu->abandonResources(); 170 171 // a path renderer may be holding onto resources that 172 // are now unusable 173 GrSafeSetNull(fPathRendererChain); 174 GrSafeSetNull(fSoftwarePathRenderer); 175 176 delete fDrawBuffer; 177 fDrawBuffer = NULL; 178 179 delete fDrawBufferVBAllocPool; 180 fDrawBufferVBAllocPool = NULL; 181 182 delete fDrawBufferIBAllocPool; 183 fDrawBufferIBAllocPool = NULL; 184 185 fAARectRenderer->reset(); 186 187 fTextureCache->purgeAllUnlocked(); 188 fFontCache->freeAll(); 189 fGpu->markContextDirty(); 190} 191 192void GrContext::resetContext() { 193 fGpu->markContextDirty(); 194} 195 196void GrContext::freeGpuResources() { 197 this->flush(); 198 199 fGpu->purgeResources(); 200 201 fAARectRenderer->reset(); 202 203 fTextureCache->purgeAllUnlocked(); 204 fFontCache->freeAll(); 205 // a path renderer may be holding onto resources 206 GrSafeSetNull(fPathRendererChain); 207 GrSafeSetNull(fSoftwarePathRenderer); 208} 209 210size_t GrContext::getGpuTextureCacheBytes() const { 211 return fTextureCache->getCachedResourceBytes(); 212} 213 214//////////////////////////////////////////////////////////////////////////////// 215 216namespace { 217 218void scale_rect(SkRect* rect, float xScale, float yScale) { 219 rect->fLeft = SkScalarMul(rect->fLeft, SkFloatToScalar(xScale)); 220 rect->fTop = SkScalarMul(rect->fTop, SkFloatToScalar(yScale)); 221 rect->fRight = SkScalarMul(rect->fRight, SkFloatToScalar(xScale)); 222 rect->fBottom = SkScalarMul(rect->fBottom, SkFloatToScalar(yScale)); 223} 224 225float adjust_sigma(float sigma, int *scaleFactor, int *radius) { 226 *scaleFactor = 1; 227 while (sigma > MAX_BLUR_SIGMA) { 228 *scaleFactor *= 2; 229 sigma *= 0.5f; 230 } 231 *radius = static_cast<int>(ceilf(sigma * 3.0f)); 232 GrAssert(*radius <= GrConvolutionEffect::kMaxKernelRadius); 233 return sigma; 234} 235 236void convolve_gaussian(GrDrawTarget* target, 237 GrTexture* texture, 238 const SkRect& rect, 239 float sigma, 240 int radius, 241 Gr1DKernelEffect::Direction direction) { 242 GrRenderTarget* rt = target->drawState()->getRenderTarget(); 243 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kReset_ASRInit); 244 GrDrawState* drawState = target->drawState(); 245 drawState->setRenderTarget(rt); 246 SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, 247 direction, 248 radius, 249 sigma)); 250 drawState->setEffect(0, conv); 251 target->drawSimpleRect(rect, NULL); 252} 253 254} 255 256//////////////////////////////////////////////////////////////////////////////// 257 258GrTexture* GrContext::findAndRefTexture(const GrTextureDesc& desc, 259 const GrCacheID& cacheID, 260 const GrTextureParams* params) { 261 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID); 262 GrResource* resource = fTextureCache->find(resourceKey); 263 SkSafeRef(resource); 264 return static_cast<GrTexture*>(resource); 265} 266 267bool GrContext::isTextureInCache(const GrTextureDesc& desc, 268 const GrCacheID& cacheID, 269 const GrTextureParams* params) const { 270 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID); 271 return fTextureCache->hasKey(resourceKey); 272} 273 274void GrContext::addStencilBuffer(GrStencilBuffer* sb) { 275 ASSERT_OWNED_RESOURCE(sb); 276 277 GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(sb->width(), 278 sb->height(), 279 sb->numSamples()); 280 fTextureCache->addResource(resourceKey, sb); 281} 282 283GrStencilBuffer* GrContext::findStencilBuffer(int width, int height, 284 int sampleCnt) { 285 GrResourceKey resourceKey = GrStencilBuffer::ComputeKey(width, 286 height, 287 sampleCnt); 288 GrResource* resource = fTextureCache->find(resourceKey); 289 return static_cast<GrStencilBuffer*>(resource); 290} 291 292static void stretchImage(void* dst, 293 int dstW, 294 int dstH, 295 void* src, 296 int srcW, 297 int srcH, 298 int bpp) { 299 GrFixed dx = (srcW << 16) / dstW; 300 GrFixed dy = (srcH << 16) / dstH; 301 302 GrFixed y = dy >> 1; 303 304 int dstXLimit = dstW*bpp; 305 for (int j = 0; j < dstH; ++j) { 306 GrFixed x = dx >> 1; 307 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp; 308 void* dstRow = (uint8_t*)dst + j*dstW*bpp; 309 for (int i = 0; i < dstXLimit; i += bpp) { 310 memcpy((uint8_t*) dstRow + i, 311 (uint8_t*) srcRow + (x>>16)*bpp, 312 bpp); 313 x += dx; 314 } 315 y += dy; 316 } 317} 318 319// The desired texture is NPOT and tiled but that isn't supported by 320// the current hardware. Resize the texture to be a POT 321GrTexture* GrContext::createResizedTexture(const GrTextureDesc& desc, 322 const GrCacheID& cacheID, 323 void* srcData, 324 size_t rowBytes, 325 bool needsFiltering) { 326 SkAutoTUnref<GrTexture> clampedTexture(this->findAndRefTexture(desc, cacheID, NULL)); 327 if (NULL == clampedTexture) { 328 clampedTexture.reset(this->createTexture(NULL, desc, cacheID, srcData, rowBytes)); 329 330 if (NULL == clampedTexture) { 331 return NULL; 332 } 333 } 334 335 GrTextureDesc rtDesc = desc; 336 rtDesc.fFlags = rtDesc.fFlags | 337 kRenderTarget_GrTextureFlagBit | 338 kNoStencil_GrTextureFlagBit; 339 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64)); 340 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64)); 341 342 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0); 343 344 if (NULL != texture) { 345 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 346 GrDrawState* drawState = fGpu->drawState(); 347 drawState->setRenderTarget(texture->asRenderTarget()); 348 349 // if filtering is not desired then we want to ensure all 350 // texels in the resampled image are copies of texels from 351 // the original. 352 GrTextureParams params(SkShader::kClamp_TileMode, needsFiltering); 353 drawState->createTextureEffect(0, clampedTexture, SkMatrix::I(), params); 354 355 // position + texture coordinate 356 static const GrVertexAttrib kVertexAttribs[] = { 357 GrVertexAttrib(kVec2f_GrVertexAttribType, 0), 358 GrVertexAttrib(kVec2f_GrVertexAttribType, sizeof(GrPoint)) 359 }; 360 static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(0); 361 drawState->setAttribBindings(kAttribBindings); 362 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); 363 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); 364 drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1); 365 GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0); 366 367 if (arg.succeeded()) { 368 GrPoint* verts = (GrPoint*) arg.vertices(); 369 verts[0].setIRectFan(0, 0, texture->width(), texture->height(), 2 * sizeof(GrPoint)); 370 verts[1].setIRectFan(0, 0, 1, 1, 2 * sizeof(GrPoint)); 371 fGpu->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4); 372 } 373 texture->releaseRenderTarget(); 374 } else { 375 // TODO: Our CPU stretch doesn't filter. But we create separate 376 // stretched textures when the texture params is either filtered or 377 // not. Either implement filtered stretch blit on CPU or just create 378 // one when FBO case fails. 379 380 rtDesc.fFlags = kNone_GrTextureFlags; 381 // no longer need to clamp at min RT size. 382 rtDesc.fWidth = GrNextPow2(desc.fWidth); 383 rtDesc.fHeight = GrNextPow2(desc.fHeight); 384 int bpp = GrBytesPerPixel(desc.fConfig); 385 SkAutoSMalloc<128*128*4> stretchedPixels(bpp * rtDesc.fWidth * rtDesc.fHeight); 386 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight, 387 srcData, desc.fWidth, desc.fHeight, bpp); 388 389 size_t stretchedRowBytes = rtDesc.fWidth * bpp; 390 391 SkDEBUGCODE(GrTexture* texture = )fGpu->createTexture(rtDesc, stretchedPixels.get(), stretchedRowBytes); 392 GrAssert(NULL != texture); 393 } 394 395 return texture; 396} 397 398GrTexture* GrContext::createTexture(const GrTextureParams* params, 399 const GrTextureDesc& desc, 400 const GrCacheID& cacheID, 401 void* srcData, 402 size_t rowBytes) { 403 SK_TRACE_EVENT0("GrContext::createTexture"); 404 405 GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, cacheID); 406 407 GrTexture* texture; 408 if (GrTexture::NeedsResizing(resourceKey)) { 409 texture = this->createResizedTexture(desc, cacheID, 410 srcData, rowBytes, 411 GrTexture::NeedsFiltering(resourceKey)); 412 } else { 413 texture= fGpu->createTexture(desc, srcData, rowBytes); 414 } 415 416 if (NULL != texture) { 417 fTextureCache->addResource(resourceKey, texture); 418 } 419 420 return texture; 421} 422 423GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, ScratchTexMatch match) { 424 GrTextureDesc desc = inDesc; 425 426 GrAssert((desc.fFlags & kRenderTarget_GrTextureFlagBit) || 427 !(desc.fFlags & kNoStencil_GrTextureFlagBit)); 428 429 if (kApprox_ScratchTexMatch == match) { 430 // bin by pow2 with a reasonable min 431 static const int MIN_SIZE = 256; 432 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth)); 433 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight)); 434 } 435 436 GrResource* resource = NULL; 437 int origWidth = desc.fWidth; 438 int origHeight = desc.fHeight; 439 bool doubledW = false; 440 bool doubledH = false; 441 442 do { 443 GrResourceKey key = GrTexture::ComputeScratchKey(desc); 444 // Ensure we have exclusive access to the texture so future 'find' calls don't return it 445 resource = fTextureCache->find(key, GrResourceCache::kHide_OwnershipFlag); 446 if (NULL != resource) { 447 resource->ref(); 448 break; 449 } 450 if (kExact_ScratchTexMatch == match) { 451 break; 452 } 453 // We had a cache miss and we are in approx mode, relax the fit of the flags... then try 454 // doubling width... then the height. 455 456 // We no longer try to reuse textures that were previously used as render targets in 457 // situations where no RT is needed; doing otherwise can confuse the video driver and 458 // cause significant performance problems in some cases. 459 if (desc.fFlags & kNoStencil_GrTextureFlagBit) { 460 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit; 461 } else if (!doubledW) { 462 desc.fFlags = inDesc.fFlags; 463 desc.fWidth *= 2; 464 doubledW = true; 465 } else if (!doubledH) { 466 desc.fFlags = inDesc.fFlags; 467 desc.fWidth = origWidth; 468 desc.fHeight *= 2; 469 doubledH = true; 470 } else { 471 break; 472 } 473 474 } while (true); 475 476 if (NULL == resource) { 477 desc.fFlags = inDesc.fFlags; 478 desc.fWidth = origWidth; 479 desc.fHeight = origHeight; 480 GrTexture* texture = fGpu->createTexture(desc, NULL, 0); 481 if (NULL != texture) { 482 GrResourceKey key = GrTexture::ComputeScratchKey(texture->desc()); 483 // Make the resource exclusive so future 'find' calls don't return it 484 fTextureCache->addResource(key, texture, GrResourceCache::kHide_OwnershipFlag); 485 resource = texture; 486 } 487 } 488 489 return static_cast<GrTexture*>(resource); 490} 491 492void GrContext::addExistingTextureToCache(GrTexture* texture) { 493 494 if (NULL == texture) { 495 return; 496 } 497 498 // This texture should already have a cache entry since it was once 499 // attached 500 GrAssert(NULL != texture->getCacheEntry()); 501 502 // Conceptually, the cache entry is going to assume responsibility 503 // for the creation ref. 504 GrAssert(1 == texture->getRefCnt()); 505 506 // Since this texture came from an AutoScratchTexture it should 507 // still be in the exclusive pile 508 fTextureCache->makeNonExclusive(texture->getCacheEntry()); 509 510 this->purgeCache(); 511} 512 513 514void GrContext::unlockScratchTexture(GrTexture* texture) { 515 ASSERT_OWNED_RESOURCE(texture); 516 GrAssert(NULL != texture->getCacheEntry()); 517 518 // If this is a scratch texture we detached it from the cache 519 // while it was locked (to avoid two callers simultaneously getting 520 // the same texture). 521 if (texture->getCacheEntry()->key().isScratch()) { 522 fTextureCache->makeNonExclusive(texture->getCacheEntry()); 523 } 524 525 this->purgeCache(); 526} 527 528void GrContext::purgeCache() { 529 if (NULL != fTextureCache) { 530 fTextureCache->purgeAsNeeded(); 531 } 532} 533 534GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& descIn, 535 void* srcData, 536 size_t rowBytes) { 537 GrTextureDesc descCopy = descIn; 538 return fGpu->createTexture(descCopy, srcData, rowBytes); 539} 540 541void GrContext::getTextureCacheLimits(int* maxTextures, 542 size_t* maxTextureBytes) const { 543 fTextureCache->getLimits(maxTextures, maxTextureBytes); 544} 545 546void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { 547 fTextureCache->setLimits(maxTextures, maxTextureBytes); 548} 549 550int GrContext::getMaxTextureSize() const { 551 return fGpu->getCaps().maxTextureSize(); 552} 553 554int GrContext::getMaxRenderTargetSize() const { 555 return fGpu->getCaps().maxRenderTargetSize(); 556} 557 558/////////////////////////////////////////////////////////////////////////////// 559 560GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) { 561 return fGpu->wrapBackendTexture(desc); 562} 563 564GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) { 565 return fGpu->wrapBackendRenderTarget(desc); 566} 567 568/////////////////////////////////////////////////////////////////////////////// 569 570bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params, 571 int width, int height) const { 572 const GrDrawTarget::Caps& caps = fGpu->getCaps(); 573 if (!caps.eightBitPaletteSupport()) { 574 return false; 575 } 576 577 bool isPow2 = GrIsPow2(width) && GrIsPow2(height); 578 579 if (!isPow2) { 580 bool tiled = NULL != params && params->isTiled(); 581 if (tiled && !caps.npotTextureTileSupport()) { 582 return false; 583 } 584 } 585 return true; 586} 587 588//////////////////////////////////////////////////////////////////////////////// 589 590const GrClipData* GrContext::getClip() const { 591 return fGpu->getClip(); 592} 593 594void GrContext::setClip(const GrClipData* clipData) { 595 fGpu->setClip(clipData); 596 597 fDrawState->setState(GrDrawState::kClip_StateBit, 598 clipData && clipData->fClipStack && !clipData->fClipStack->isWideOpen()); 599} 600 601//////////////////////////////////////////////////////////////////////////////// 602 603void GrContext::clear(const GrIRect* rect, 604 const GrColor color, 605 GrRenderTarget* target) { 606 this->prepareToDraw(NULL, BUFFERED_DRAW)->clear(rect, color, target); 607} 608 609void GrContext::drawPaint(const GrPaint& origPaint) { 610 // set rect to be big enough to fill the space, but not super-huge, so we 611 // don't overflow fixed-point implementations 612 GrRect r; 613 r.setLTRB(0, 0, 614 SkIntToScalar(getRenderTarget()->width()), 615 SkIntToScalar(getRenderTarget()->height())); 616 SkMatrix inverse; 617 SkTCopyOnFirstWrite<GrPaint> paint(origPaint); 618 AutoMatrix am; 619 620 // We attempt to map r by the inverse matrix and draw that. mapRect will 621 // map the four corners and bound them with a new rect. This will not 622 // produce a correct result for some perspective matrices. 623 if (!this->getMatrix().hasPerspective()) { 624 if (!fDrawState->getViewInverse(&inverse)) { 625 GrPrintf("Could not invert matrix\n"); 626 return; 627 } 628 inverse.mapRect(&r); 629 } else { 630 if (!am.setIdentity(this, paint.writable())) { 631 GrPrintf("Could not invert matrix\n"); 632 return; 633 } 634 } 635 // by definition this fills the entire clip, no need for AA 636 if (paint->isAntiAlias()) { 637 paint.writable()->setAntiAlias(false); 638 } 639 this->drawRect(*paint, r); 640} 641 642//////////////////////////////////////////////////////////////////////////////// 643 644namespace { 645inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) { 646 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage(); 647} 648} 649 650//////////////////////////////////////////////////////////////////////////////// 651 652/* create a triangle strip that strokes the specified triangle. There are 8 653 unique vertices, but we repreat the last 2 to close up. Alternatively we 654 could use an indices array, and then only send 8 verts, but not sure that 655 would be faster. 656 */ 657static void setStrokeRectStrip(GrPoint verts[10], GrRect rect, 658 SkScalar width) { 659 const SkScalar rad = SkScalarHalf(width); 660 rect.sort(); 661 662 verts[0].set(rect.fLeft + rad, rect.fTop + rad); 663 verts[1].set(rect.fLeft - rad, rect.fTop - rad); 664 verts[2].set(rect.fRight - rad, rect.fTop + rad); 665 verts[3].set(rect.fRight + rad, rect.fTop - rad); 666 verts[4].set(rect.fRight - rad, rect.fBottom - rad); 667 verts[5].set(rect.fRight + rad, rect.fBottom + rad); 668 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); 669 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); 670 verts[8] = verts[0]; 671 verts[9] = verts[1]; 672} 673 674/** 675 * Returns true if the rects edges are integer-aligned. 676 */ 677static bool isIRect(const GrRect& r) { 678 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) && 679 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom); 680} 681 682static bool apply_aa_to_rect(GrDrawTarget* target, 683 const GrRect& rect, 684 SkScalar width, 685 const SkMatrix* matrix, 686 SkMatrix* combinedMatrix, 687 GrRect* devRect, 688 bool* useVertexCoverage) { 689 // we use a simple coverage ramp to do aa on axis-aligned rects 690 // we check if the rect will be axis-aligned, and the rect won't land on 691 // integer coords. 692 693 // we are keeping around the "tweak the alpha" trick because 694 // it is our only hope for the fixed-pipe implementation. 695 // In a shader implementation we can give a separate coverage input 696 // TODO: remove this ugliness when we drop the fixed-pipe impl 697 *useVertexCoverage = false; 698 if (!target->getDrawState().canTweakAlphaForCoverage()) { 699 if (disable_coverage_aa_for_blend(target)) { 700#if GR_DEBUG 701 //GrPrintf("Turning off AA to correctly apply blend.\n"); 702#endif 703 return false; 704 } else { 705 *useVertexCoverage = true; 706 } 707 } 708 const GrDrawState& drawState = target->getDrawState(); 709 if (drawState.getRenderTarget()->isMultisampled()) { 710 return false; 711 } 712 713 if (0 == width && target->willUseHWAALines()) { 714 return false; 715 } 716 717 if (!drawState.getViewMatrix().preservesAxisAlignment()) { 718 return false; 719 } 720 721 if (NULL != matrix && 722 !matrix->preservesAxisAlignment()) { 723 return false; 724 } 725 726 *combinedMatrix = drawState.getViewMatrix(); 727 if (NULL != matrix) { 728 combinedMatrix->preConcat(*matrix); 729 GrAssert(combinedMatrix->preservesAxisAlignment()); 730 } 731 732 combinedMatrix->mapRect(devRect, rect); 733 devRect->sort(); 734 735 if (width < 0) { 736 return !isIRect(*devRect); 737 } else { 738 return true; 739 } 740} 741 742void GrContext::drawRect(const GrPaint& paint, 743 const GrRect& rect, 744 SkScalar width, 745 const SkMatrix* matrix) { 746 SK_TRACE_EVENT0("GrContext::drawRect"); 747 748 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); 749 GrDrawState::AutoStageDisable atr(fDrawState); 750 751 GrRect devRect = rect; 752 SkMatrix combinedMatrix; 753 bool useVertexCoverage; 754 bool needAA = paint.isAntiAlias() && 755 !this->getRenderTarget()->isMultisampled(); 756 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, 757 &combinedMatrix, &devRect, 758 &useVertexCoverage); 759 760 if (doAA) { 761 GrDrawState::AutoDeviceCoordDraw adcd(target->drawState()); 762 if (!adcd.succeeded()) { 763 return; 764 } 765 if (width >= 0) { 766 GrVec strokeSize; 767 if (width > 0) { 768 strokeSize.set(width, width); 769 combinedMatrix.mapVectors(&strokeSize, 1); 770 strokeSize.setAbs(strokeSize); 771 } else { 772 strokeSize.set(SK_Scalar1, SK_Scalar1); 773 } 774 fAARectRenderer->strokeAARect(this->getGpu(), target, devRect, 775 strokeSize, useVertexCoverage); 776 } else { 777 fAARectRenderer->fillAARect(this->getGpu(), target, 778 devRect, useVertexCoverage); 779 } 780 return; 781 } 782 783 if (width >= 0) { 784 // TODO: consider making static vertex buffers for these cases. 785 // Hairline could be done by just adding closing vertex to 786 // unitSquareVertexBuffer() 787 788 static const int worstCaseVertCount = 10; 789 target->drawState()->setDefaultVertexAttribs(); 790 GrDrawTarget::AutoReleaseGeometry geo(target, worstCaseVertCount, 0); 791 792 if (!geo.succeeded()) { 793 GrPrintf("Failed to get space for vertices!\n"); 794 return; 795 } 796 797 GrPrimitiveType primType; 798 int vertCount; 799 GrPoint* vertex = geo.positions(); 800 801 if (width > 0) { 802 vertCount = 10; 803 primType = kTriangleStrip_GrPrimitiveType; 804 setStrokeRectStrip(vertex, rect, width); 805 } else { 806 // hairline 807 vertCount = 5; 808 primType = kLineStrip_GrPrimitiveType; 809 vertex[0].set(rect.fLeft, rect.fTop); 810 vertex[1].set(rect.fRight, rect.fTop); 811 vertex[2].set(rect.fRight, rect.fBottom); 812 vertex[3].set(rect.fLeft, rect.fBottom); 813 vertex[4].set(rect.fLeft, rect.fTop); 814 } 815 816 GrDrawState::AutoViewMatrixRestore avmr; 817 if (NULL != matrix) { 818 GrDrawState* drawState = target->drawState(); 819 avmr.set(drawState, *matrix); 820 } 821 822 target->drawNonIndexed(primType, 0, vertCount); 823 } else { 824#if GR_STATIC_RECT_VB 825 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 826 if (NULL == sqVB) { 827 GrPrintf("Failed to create static rect vb.\n"); 828 return; 829 } 830 831 GrDrawState* drawState = target->drawState(); 832 target->drawState()->setDefaultVertexAttribs(); 833 target->setVertexSourceToBuffer(sqVB); 834 SkMatrix m; 835 m.setAll(rect.width(), 0, rect.fLeft, 836 0, rect.height(), rect.fTop, 837 0, 0, SkMatrix::I()[8]); 838 839 if (NULL != matrix) { 840 m.postConcat(*matrix); 841 } 842 GrDrawState::AutoViewMatrixRestore avmr(drawState, m); 843 844 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4); 845#else 846 target->drawSimpleRect(rect, matrix); 847#endif 848 } 849} 850 851void GrContext::drawRectToRect(const GrPaint& paint, 852 const GrRect& dstRect, 853 const GrRect& srcRect, 854 const SkMatrix* dstMatrix, 855 const SkMatrix* srcMatrix) { 856 SK_TRACE_EVENT0("GrContext::drawRectToRect"); 857 858 // srcRect refers to paint's first color stage 859 if (!paint.isColorStageEnabled(0)) { 860 drawRect(paint, dstRect, -1, dstMatrix); 861 return; 862 } 863 864 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); 865 866#if GR_STATIC_RECT_VB 867 GrDrawState::AutoStageDisable atr(fDrawState); 868 GrDrawState* drawState = target->drawState(); 869 870 SkMatrix m; 871 872 m.setAll(dstRect.width(), 0, dstRect.fLeft, 873 0, dstRect.height(), dstRect.fTop, 874 0, 0, SkMatrix::I()[8]); 875 if (NULL != dstMatrix) { 876 m.postConcat(*dstMatrix); 877 } 878 879 // The first color stage's coords come from srcRect rather than applying a matrix to dstRect. 880 // We explicitly compute a matrix for that stage below, no need to adjust here. 881 static const uint32_t kExplicitCoordMask = 1 << GrPaint::kFirstColorStage; 882 GrDrawState::AutoViewMatrixRestore avmr(drawState, m, kExplicitCoordMask); 883 884 m.setAll(srcRect.width(), 0, srcRect.fLeft, 885 0, srcRect.height(), srcRect.fTop, 886 0, 0, SkMatrix::I()[8]); 887 if (NULL != srcMatrix) { 888 m.postConcat(*srcMatrix); 889 } 890 891 drawState->preConcatStageMatrices(kExplicitCoordMask, m); 892 893 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 894 if (NULL == sqVB) { 895 GrPrintf("Failed to create static rect vb.\n"); 896 return; 897 } 898 drawState->setDefaultVertexAttribs(); 899 target->setVertexSourceToBuffer(sqVB); 900 target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4); 901#else 902 GrDrawState::AutoStageDisable atr(fDrawState); 903 904 target->drawRect(dstRect, dstMatrix, &srcRect, srcMatrix, 0); 905#endif 906} 907 908void GrContext::drawVertices(const GrPaint& paint, 909 GrPrimitiveType primitiveType, 910 int vertexCount, 911 const GrPoint positions[], 912 const GrPoint texCoords[], 913 const GrColor colors[], 914 const uint16_t indices[], 915 int indexCount) { 916 SK_TRACE_EVENT0("GrContext::drawVertices"); 917 918 GrDrawTarget::AutoReleaseGeometry geo; 919 920 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); 921 GrDrawState::AutoStageDisable atr(fDrawState); 922 923 GrDrawState* drawState = target->drawState(); 924 925 GrVertexAttribArray<3> attribs; 926 size_t currentOffset = 0; 927 int colorOffset = -1, texOffset = -1; 928 GrAttribBindings bindings = GrDrawState::kDefault_AttribBindings; 929 930 // set position attribute 931 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, attribs.count()); 932 attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset)); 933 currentOffset += sizeof(GrPoint); 934 935 // set up optional texture coordinate attributes 936 if (NULL != texCoords) { 937 bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(0); 938 drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, attribs.count()); 939 attribs.push_back(GrVertexAttrib(kVec2f_GrVertexAttribType, currentOffset)); 940 texOffset = currentOffset; 941 currentOffset += sizeof(GrPoint); 942 } 943 944 // set up optional color attributes 945 if (NULL != colors) { 946 bindings |= GrDrawState::kColor_AttribBindingsBit; 947 drawState->setAttribIndex(GrDrawState::kColor_AttribIndex, attribs.count()); 948 attribs.push_back(GrVertexAttrib(kVec4ub_GrVertexAttribType, currentOffset)); 949 colorOffset = currentOffset; 950 currentOffset += sizeof(GrColor); 951 } 952 953 drawState->setVertexAttribs(attribs.begin(), attribs.count()); 954 drawState->setAttribBindings(bindings); 955 956 size_t vertexSize = drawState->getVertexSize(); 957 GrAssert(vertexSize == currentOffset); 958 if (sizeof(GrPoint) != vertexSize) { 959 if (!geo.set(target, vertexCount, 0)) { 960 GrPrintf("Failed to get space for vertices!\n"); 961 return; 962 } 963 void* curVertex = geo.vertices(); 964 965 for (int i = 0; i < vertexCount; ++i) { 966 *((GrPoint*)curVertex) = positions[i]; 967 968 if (texOffset >= 0) { 969 *(GrPoint*)((intptr_t)curVertex + texOffset) = texCoords[i]; 970 } 971 if (colorOffset >= 0) { 972 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i]; 973 } 974 curVertex = (void*)((intptr_t)curVertex + vertexSize); 975 } 976 } else { 977 target->setVertexSourceToArray(positions, vertexCount); 978 } 979 980 // we don't currently apply offscreen AA to this path. Need improved 981 // management of GrDrawTarget's geometry to avoid copying points per-tile. 982 983 if (NULL != indices) { 984 target->setIndexSourceToArray(indices, indexCount); 985 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); 986 } else { 987 target->drawNonIndexed(primitiveType, 0, vertexCount); 988 } 989} 990 991/////////////////////////////////////////////////////////////////////////////// 992namespace { 993 994struct CircleVertex { 995 GrPoint fPos; 996 GrPoint fCenter; 997 SkScalar fOuterRadius; 998 SkScalar fInnerRadius; 999}; 1000 1001inline bool circleStaysCircle(const SkMatrix& m) { 1002 return m.isSimilarity(); 1003} 1004 1005} 1006 1007void GrContext::drawOval(const GrPaint& paint, 1008 const GrRect& oval, 1009 const SkStrokeRec& stroke) { 1010 1011 if (!canDrawOval(paint, oval, stroke)) { 1012 SkPath path; 1013 path.addOval(oval); 1014 this->drawPath(paint, path, stroke); 1015 return; 1016 } 1017 1018 internalDrawOval(paint, oval, stroke); 1019} 1020 1021bool GrContext::canDrawOval(const GrPaint& paint, const GrRect& oval, const SkStrokeRec& stroke) const { 1022 1023 if (!paint.isAntiAlias()) { 1024 return false; 1025 } 1026 1027 // we can draw circles in any style 1028 bool isCircle = SkScalarNearlyEqual(oval.width(), oval.height()) 1029 && circleStaysCircle(this->getMatrix()); 1030 // and for now, axis-aligned ellipses only with fill or stroke-and-fill 1031 SkStrokeRec::Style style = stroke.getStyle(); 1032 bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style); 1033 bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke; 1034 1035 return isCircle || isFilledAxisAlignedEllipse; 1036} 1037 1038void GrContext::internalDrawOval(const GrPaint& paint, 1039 const GrRect& oval, 1040 const SkStrokeRec& stroke) { 1041 1042 SkScalar xRadius = SkScalarHalf(oval.width()); 1043 SkScalar yRadius = SkScalarHalf(oval.height()); 1044 1045 SkScalar strokeWidth = stroke.getWidth(); 1046 SkStrokeRec::Style style = stroke.getStyle(); 1047 1048 bool isCircle = SkScalarNearlyEqual(xRadius, yRadius) && circleStaysCircle(this->getMatrix()); 1049#ifdef SK_DEBUG 1050 { 1051 // we should have checked for this previously 1052 bool isStroke = (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style); 1053 bool isFilledAxisAlignedEllipse = this->getMatrix().rectStaysRect() && !isStroke; 1054 SkASSERT(paint.isAntiAlias() && (isCircle || isFilledAxisAlignedEllipse)); 1055 } 1056#endif 1057 1058 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); 1059 1060 GrDrawState* drawState = target->drawState(); 1061 GrDrawState::AutoStageDisable atr(fDrawState); 1062 const SkMatrix vm = drawState->getViewMatrix(); 1063 1064 const GrRenderTarget* rt = drawState->getRenderTarget(); 1065 if (NULL == rt) { 1066 return; 1067 } 1068 1069 GrDrawState::AutoDeviceCoordDraw adcd(drawState); 1070 if (!adcd.succeeded()) { 1071 return; 1072 } 1073 1074 // position + edge 1075 static const GrVertexAttrib kVertexAttribs[] = { 1076 GrVertexAttrib(kVec2f_GrVertexAttribType, 0), 1077 GrVertexAttrib(kVec4f_GrVertexAttribType, sizeof(GrPoint)) 1078 }; 1079 static const GrAttribBindings kAttributeBindings = GrDrawState::kEdge_AttribBindingsBit; 1080 1081 drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs)); 1082 drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0); 1083 drawState->setAttribIndex(GrDrawState::kEdge_AttribIndex, 1); 1084 drawState->setAttribBindings(kAttributeBindings); 1085 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); 1086 1087 GrDrawTarget::AutoReleaseGeometry geo(target, 4, 0); 1088 if (!geo.succeeded()) { 1089 GrPrintf("Failed to get space for vertices!\n"); 1090 return; 1091 } 1092 1093 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); 1094 1095 GrPoint center = GrPoint::Make(oval.centerX(), oval.centerY()); 1096 vm.mapPoints(¢er, 1); 1097 1098 SkScalar L; 1099 SkScalar R; 1100 SkScalar T; 1101 SkScalar B; 1102 1103 if (isCircle) { 1104 drawState->setVertexEdgeType(GrDrawState::kCircle_EdgeType); 1105 1106 xRadius = vm.mapRadius(xRadius); 1107 1108 SkScalar outerRadius = xRadius; 1109 SkScalar innerRadius = 0; 1110 SkScalar halfWidth = 0; 1111 if (style != SkStrokeRec::kFill_Style) { 1112 strokeWidth = vm.mapRadius(strokeWidth); 1113 if (SkScalarNearlyZero(strokeWidth)) { 1114 halfWidth = SK_ScalarHalf; 1115 } else { 1116 halfWidth = SkScalarHalf(strokeWidth); 1117 } 1118 1119 outerRadius += halfWidth; 1120 if (style == SkStrokeRec::kStroke_Style || style == SkStrokeRec::kHairline_Style) { 1121 innerRadius = SkMaxScalar(0, xRadius - halfWidth); 1122 } 1123 } 1124 1125 for (int i = 0; i < 4; ++i) { 1126 verts[i].fCenter = center; 1127 verts[i].fOuterRadius = outerRadius; 1128 verts[i].fInnerRadius = innerRadius; 1129 } 1130 1131 L = -outerRadius; 1132 R = +outerRadius; 1133 T = -outerRadius; 1134 B = +outerRadius; 1135 } else { // is axis-aligned ellipse 1136 drawState->setVertexEdgeType(GrDrawState::kEllipse_EdgeType); 1137 1138 SkRect xformedRect; 1139 vm.mapRect(&xformedRect, oval); 1140 1141 xRadius = SkScalarHalf(xformedRect.width()); 1142 yRadius = SkScalarHalf(xformedRect.height()); 1143 1144 if (style == SkStrokeRec::kStrokeAndFill_Style && strokeWidth > 0.0f) { 1145 SkScalar halfWidth = SkScalarHalf(strokeWidth); 1146 // do (potentially) anisotropic mapping 1147 SkVector scaledStroke; 1148 scaledStroke.set(halfWidth, halfWidth); 1149 vm.mapVectors(&scaledStroke, 1); 1150 // this is legit only if scale & translation (which should be the case at the moment) 1151 xRadius += scaledStroke.fX; 1152 yRadius += scaledStroke.fY; 1153 } 1154 1155 SkScalar ratio = SkScalarDiv(xRadius, yRadius); 1156 1157 for (int i = 0; i < 4; ++i) { 1158 verts[i].fCenter = center; 1159 verts[i].fOuterRadius = xRadius; 1160 verts[i].fInnerRadius = ratio; 1161 } 1162 1163 L = -xRadius; 1164 R = +xRadius; 1165 T = -yRadius; 1166 B = +yRadius; 1167 } 1168 1169 // The fragment shader will extend the radius out half a pixel 1170 // to antialias. Expand the drawn rect here so all the pixels 1171 // will be captured. 1172 L += center.fX - SK_ScalarHalf; 1173 R += center.fX + SK_ScalarHalf; 1174 T += center.fY - SK_ScalarHalf; 1175 B += center.fY + SK_ScalarHalf; 1176 1177 verts[0].fPos = SkPoint::Make(L, T); 1178 verts[1].fPos = SkPoint::Make(R, T); 1179 verts[2].fPos = SkPoint::Make(L, B); 1180 verts[3].fPos = SkPoint::Make(R, B); 1181 1182 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); 1183} 1184 1185void GrContext::drawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { 1186 1187 if (path.isEmpty()) { 1188 if (path.isInverseFillType()) { 1189 this->drawPaint(paint); 1190 } 1191 return; 1192 } 1193 1194 SkRect ovalRect; 1195 bool isOval = path.isOval(&ovalRect); 1196 1197 if (isOval && !path.isInverseFillType() && this->canDrawOval(paint, ovalRect, stroke)) { 1198 this->drawOval(paint, ovalRect, stroke); 1199 return; 1200 } 1201 1202 this->internalDrawPath(paint, path, stroke); 1203} 1204 1205void GrContext::internalDrawPath(const GrPaint& paint, const SkPath& path, const SkStrokeRec& stroke) { 1206 1207 // Note that below we may sw-rasterize the path into a scratch texture. 1208 // Scratch textures can be recycled after they are returned to the texture 1209 // cache. This presents a potential hazard for buffered drawing. However, 1210 // the writePixels that uploads to the scratch will perform a flush so we're 1211 // OK. 1212 GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW); 1213 GrDrawState::AutoStageDisable atr(fDrawState); 1214 1215 bool prAA = paint.isAntiAlias() && !this->getRenderTarget()->isMultisampled(); 1216 1217 // An Assumption here is that path renderer would use some form of tweaking 1218 // the src color (either the input alpha or in the frag shader) to implement 1219 // aa. If we have some future driver-mojo path AA that can do the right 1220 // thing WRT to the blend then we'll need some query on the PR. 1221 if (disable_coverage_aa_for_blend(target)) { 1222#if GR_DEBUG 1223 //GrPrintf("Turning off AA to correctly apply blend.\n"); 1224#endif 1225 prAA = false; 1226 } 1227 1228 GrPathRendererChain::DrawType type = prAA ? GrPathRendererChain::kColorAntiAlias_DrawType : 1229 GrPathRendererChain::kColor_DrawType; 1230 1231 const SkPath* pathPtr = &path; 1232 SkPath tmpPath; 1233 SkStrokeRec strokeRec(stroke); 1234 1235 // Try a 1st time without stroking the path and without allowing the SW renderer 1236 GrPathRenderer* pr = this->getPathRenderer(*pathPtr, strokeRec, target, false, type); 1237 1238 if (NULL == pr) { 1239 if (!strokeRec.isHairlineStyle()) { 1240 // It didn't work the 1st time, so try again with the stroked path 1241 if (strokeRec.applyToPath(&tmpPath, *pathPtr)) { 1242 pathPtr = &tmpPath; 1243 strokeRec.setFillStyle(); 1244 } 1245 } 1246 // This time, allow SW renderer 1247 pr = this->getPathRenderer(*pathPtr, strokeRec, target, true, type); 1248 } 1249 1250 if (NULL == pr) { 1251#if GR_DEBUG 1252 GrPrintf("Unable to find path renderer compatible with path.\n"); 1253#endif 1254 return; 1255 } 1256 1257 pr->drawPath(*pathPtr, strokeRec, target, prAA); 1258} 1259 1260//////////////////////////////////////////////////////////////////////////////// 1261 1262void GrContext::flush(int flagsBitfield) { 1263 if (kDiscard_FlushBit & flagsBitfield) { 1264 fDrawBuffer->reset(); 1265 } else { 1266 this->flushDrawBuffer(); 1267 } 1268 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) { 1269 fGpu->forceRenderTargetFlush(); 1270 } 1271} 1272 1273void GrContext::flushDrawBuffer() { 1274 if (NULL != fDrawBuffer && !fDrawBuffer->isFlushing()) { 1275 fDrawBuffer->flush(); 1276 } 1277} 1278 1279bool GrContext::writeTexturePixels(GrTexture* texture, 1280 int left, int top, int width, int height, 1281 GrPixelConfig config, const void* buffer, size_t rowBytes, 1282 uint32_t flags) { 1283 SK_TRACE_EVENT0("GrContext::writeTexturePixels"); 1284 ASSERT_OWNED_RESOURCE(texture); 1285 1286 if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture, config)) { 1287 if (NULL != texture->asRenderTarget()) { 1288 return this->writeRenderTargetPixels(texture->asRenderTarget(), 1289 left, top, width, height, 1290 config, buffer, rowBytes, flags); 1291 } else { 1292 return false; 1293 } 1294 } 1295 1296 if (!(kDontFlush_PixelOpsFlag & flags)) { 1297 this->flush(); 1298 } 1299 1300 return fGpu->writeTexturePixels(texture, left, top, width, height, 1301 config, buffer, rowBytes); 1302} 1303 1304bool GrContext::readTexturePixels(GrTexture* texture, 1305 int left, int top, int width, int height, 1306 GrPixelConfig config, void* buffer, size_t rowBytes, 1307 uint32_t flags) { 1308 SK_TRACE_EVENT0("GrContext::readTexturePixels"); 1309 ASSERT_OWNED_RESOURCE(texture); 1310 1311 // TODO: code read pixels for textures that aren't also rendertargets 1312 GrRenderTarget* target = texture->asRenderTarget(); 1313 if (NULL != target) { 1314 return this->readRenderTargetPixels(target, 1315 left, top, width, height, 1316 config, buffer, rowBytes, 1317 flags); 1318 } else { 1319 return false; 1320 } 1321} 1322 1323#include "SkConfig8888.h" 1324 1325namespace { 1326/** 1327 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel 1328 * formats are representable as Config8888 and so the function returns false 1329 * if the GrPixelConfig has no equivalent Config8888. 1330 */ 1331bool grconfig_to_config8888(GrPixelConfig config, 1332 bool unpremul, 1333 SkCanvas::Config8888* config8888) { 1334 switch (config) { 1335 case kRGBA_8888_GrPixelConfig: 1336 if (unpremul) { 1337 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888; 1338 } else { 1339 *config8888 = SkCanvas::kRGBA_Premul_Config8888; 1340 } 1341 return true; 1342 case kBGRA_8888_GrPixelConfig: 1343 if (unpremul) { 1344 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888; 1345 } else { 1346 *config8888 = SkCanvas::kBGRA_Premul_Config8888; 1347 } 1348 return true; 1349 default: 1350 return false; 1351 } 1352} 1353 1354// It returns a configuration with where the byte position of the R & B components are swapped in 1355// relation to the input config. This should only be called with the result of 1356// grconfig_to_config8888 as it will fail for other configs. 1357SkCanvas::Config8888 swap_config8888_red_and_blue(SkCanvas::Config8888 config8888) { 1358 switch (config8888) { 1359 case SkCanvas::kBGRA_Premul_Config8888: 1360 return SkCanvas::kRGBA_Premul_Config8888; 1361 case SkCanvas::kBGRA_Unpremul_Config8888: 1362 return SkCanvas::kRGBA_Unpremul_Config8888; 1363 case SkCanvas::kRGBA_Premul_Config8888: 1364 return SkCanvas::kBGRA_Premul_Config8888; 1365 case SkCanvas::kRGBA_Unpremul_Config8888: 1366 return SkCanvas::kBGRA_Unpremul_Config8888; 1367 default: 1368 GrCrash("Unexpected input"); 1369 return SkCanvas::kBGRA_Unpremul_Config8888;; 1370 } 1371} 1372} 1373 1374bool GrContext::readRenderTargetPixels(GrRenderTarget* target, 1375 int left, int top, int width, int height, 1376 GrPixelConfig dstConfig, void* buffer, size_t rowBytes, 1377 uint32_t flags) { 1378 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels"); 1379 ASSERT_OWNED_RESOURCE(target); 1380 1381 if (NULL == target) { 1382 target = fDrawState->getRenderTarget(); 1383 if (NULL == target) { 1384 return false; 1385 } 1386 } 1387 1388 if (!(kDontFlush_PixelOpsFlag & flags)) { 1389 this->flush(); 1390 } 1391 1392 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul. 1393 1394 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll 1395 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read. 1396 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top, 1397 width, height, dstConfig, 1398 rowBytes); 1399 // We ignore the preferred config if it is different than our config unless it is an R/B swap. 1400 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped 1401 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during 1402 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from 1403 // dstConfig. 1404 GrPixelConfig readConfig = dstConfig; 1405 bool swapRAndB = false; 1406 if (GrPixelConfigSwapRAndB(dstConfig) == fGpu->preferredReadPixelsConfig(dstConfig)) { 1407 readConfig = GrPixelConfigSwapRAndB(readConfig); 1408 swapRAndB = true; 1409 } 1410 1411 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); 1412 1413 if (unpremul && !GrPixelConfigIs8888(dstConfig)) { 1414 // The unpremul flag is only allowed for these two configs. 1415 return false; 1416 } 1417 1418 // If the src is a texture and we would have to do conversions after read pixels, we instead 1419 // do the conversions by drawing the src to a scratch texture. If we handle any of the 1420 // conversions in the draw we set the corresponding bool to false so that we don't reapply it 1421 // on the read back pixels. 1422 GrTexture* src = target->asTexture(); 1423 GrAutoScratchTexture ast; 1424 if (NULL != src && (swapRAndB || unpremul || flipY)) { 1425 // Make the scratch a render target because we don't have a robust readTexturePixels as of 1426 // yet. It calls this function. 1427 GrTextureDesc desc; 1428 desc.fFlags = kRenderTarget_GrTextureFlagBit; 1429 desc.fWidth = width; 1430 desc.fHeight = height; 1431 desc.fConfig = readConfig; 1432 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 1433 1434 // When a full read back is faster than a partial we could always make the scratch exactly 1435 // match the passed rect. However, if we see many different size rectangles we will trash 1436 // our texture cache and pay the cost of creating and destroying many textures. So, we only 1437 // request an exact match when the caller is reading an entire RT. 1438 ScratchTexMatch match = kApprox_ScratchTexMatch; 1439 if (0 == left && 1440 0 == top && 1441 target->width() == width && 1442 target->height() == height && 1443 fGpu->fullReadPixelsIsFasterThanPartial()) { 1444 match = kExact_ScratchTexMatch; 1445 } 1446 ast.set(this, desc, match); 1447 GrTexture* texture = ast.texture(); 1448 if (texture) { 1449 // compute a matrix to perform the draw 1450 SkMatrix textureMatrix; 1451 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); 1452 textureMatrix.postIDiv(src->width(), src->height()); 1453 1454 SkAutoTUnref<const GrEffectRef> effect; 1455 if (unpremul) { 1456 effect.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix)); 1457 if (NULL != effect) { 1458 unpremul = false; // we no longer need to do this on CPU after the read back. 1459 } 1460 } 1461 // If we failed to create a PM->UPM effect and have no other conversions to perform then 1462 // there is no longer any point to using the scratch. 1463 if (NULL != effect || flipY || swapRAndB) { 1464 if (!effect) { 1465 effect.reset(GrConfigConversionEffect::Create( 1466 src, 1467 swapRAndB, 1468 GrConfigConversionEffect::kNone_PMConversion, 1469 textureMatrix)); 1470 } 1471 swapRAndB = false; // we will handle the swap in the draw. 1472 1473 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 1474 GrDrawState* drawState = fGpu->drawState(); 1475 GrAssert(effect); 1476 drawState->setEffect(0, effect); 1477 1478 drawState->setRenderTarget(texture->asRenderTarget()); 1479 GrRect rect = GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 1480 fGpu->drawSimpleRect(rect, NULL); 1481 // we want to read back from the scratch's origin 1482 left = 0; 1483 top = 0; 1484 target = texture->asRenderTarget(); 1485 } 1486 } 1487 } 1488 if (!fGpu->readPixels(target, 1489 left, top, width, height, 1490 readConfig, buffer, rowBytes)) { 1491 return false; 1492 } 1493 // Perform any conversions we weren't able to perform using a scratch texture. 1494 if (unpremul || swapRAndB) { 1495 // These are initialized to suppress a warning 1496 SkCanvas::Config8888 srcC8888 = SkCanvas::kNative_Premul_Config8888; 1497 SkCanvas::Config8888 dstC8888 = SkCanvas::kNative_Premul_Config8888; 1498 1499 SkDEBUGCODE(bool c8888IsValid =) grconfig_to_config8888(dstConfig, false, &srcC8888); 1500 grconfig_to_config8888(dstConfig, unpremul, &dstC8888); 1501 1502 if (swapRAndB) { 1503 GrAssert(c8888IsValid); // we should only do r/b swap on 8888 configs 1504 srcC8888 = swap_config8888_red_and_blue(srcC8888); 1505 } 1506 GrAssert(c8888IsValid); 1507 uint32_t* b32 = reinterpret_cast<uint32_t*>(buffer); 1508 SkConvertConfig8888Pixels(b32, rowBytes, dstC8888, 1509 b32, rowBytes, srcC8888, 1510 width, height); 1511 } 1512 return true; 1513} 1514 1515void GrContext::resolveRenderTarget(GrRenderTarget* target) { 1516 GrAssert(target); 1517 ASSERT_OWNED_RESOURCE(target); 1518 // In the future we may track whether there are any pending draws to this 1519 // target. We don't today so we always perform a flush. We don't promise 1520 // this to our clients, though. 1521 this->flush(); 1522 fGpu->resolveRenderTarget(target); 1523} 1524 1525void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst, const SkIPoint* topLeft) { 1526 if (NULL == src || NULL == dst) { 1527 return; 1528 } 1529 ASSERT_OWNED_RESOURCE(src); 1530 1531 // Writes pending to the source texture are not tracked, so a flush 1532 // is required to ensure that the copy captures the most recent contents 1533 // of the source texture. See similar behavior in 1534 // GrContext::resolveRenderTarget. 1535 this->flush(); 1536 1537 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 1538 GrDrawState* drawState = fGpu->drawState(); 1539 drawState->setRenderTarget(dst); 1540 SkMatrix sampleM; 1541 sampleM.setIDiv(src->width(), src->height()); 1542 SkIRect srcRect = SkIRect::MakeWH(dst->width(), dst->height()); 1543 if (NULL != topLeft) { 1544 srcRect.offset(*topLeft); 1545 } 1546 SkIRect srcBounds = SkIRect::MakeWH(src->width(), src->height()); 1547 if (!srcRect.intersect(srcBounds)) { 1548 return; 1549 } 1550 sampleM.preTranslate(SkIntToScalar(srcRect.fLeft), SkIntToScalar(srcRect.fTop)); 1551 drawState->createTextureEffect(0, src, sampleM); 1552 SkRect dstR = SkRect::MakeWH(SkIntToScalar(srcRect.width()), SkIntToScalar(srcRect.height())); 1553 fGpu->drawSimpleRect(dstR, NULL); 1554} 1555 1556bool GrContext::writeRenderTargetPixels(GrRenderTarget* target, 1557 int left, int top, int width, int height, 1558 GrPixelConfig srcConfig, 1559 const void* buffer, 1560 size_t rowBytes, 1561 uint32_t flags) { 1562 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels"); 1563 ASSERT_OWNED_RESOURCE(target); 1564 1565 if (NULL == target) { 1566 target = fDrawState->getRenderTarget(); 1567 if (NULL == target) { 1568 return false; 1569 } 1570 } 1571 1572 // TODO: when underlying api has a direct way to do this we should use it (e.g. glDrawPixels on 1573 // desktop GL). 1574 1575 // We will always call some form of writeTexturePixels and we will pass our flags on to it. 1576 // Thus, we don't perform a flush here since that call will do it (if the kNoFlush flag isn't 1577 // set.) 1578 1579 // If the RT is also a texture and we don't have to premultiply then take the texture path. 1580 // We expect to be at least as fast or faster since it doesn't use an intermediate texture as 1581 // we do below. 1582 1583#if !GR_MAC_BUILD 1584 // At least some drivers on the Mac get confused when glTexImage2D is called on a texture 1585 // attached to an FBO. The FBO still sees the old image. TODO: determine what OS versions and/or 1586 // HW is affected. 1587 if (NULL != target->asTexture() && !(kUnpremul_PixelOpsFlag & flags) && 1588 fGpu->canWriteTexturePixels(target->asTexture(), srcConfig)) { 1589 return this->writeTexturePixels(target->asTexture(), 1590 left, top, width, height, 1591 srcConfig, buffer, rowBytes, flags); 1592 } 1593#endif 1594 1595 // We ignore the preferred config unless it is a R/B swap of the src config. In that case 1596 // we will upload the original src data to a scratch texture but we will spoof it as the swapped 1597 // config. This scratch will then have R and B swapped. We correct for this by swapping again 1598 // when drawing the scratch to the dst using a conversion effect. 1599 bool swapRAndB = false; 1600 GrPixelConfig writeConfig = srcConfig; 1601 if (fGpu->preferredWritePixelsConfig(srcConfig) == GrPixelConfigSwapRAndB(srcConfig)) { 1602 writeConfig = GrPixelConfigSwapRAndB(srcConfig); 1603 swapRAndB = true; 1604 } 1605 1606 GrTextureDesc desc; 1607 desc.fWidth = width; 1608 desc.fHeight = height; 1609 desc.fConfig = writeConfig; 1610 GrAutoScratchTexture ast(this, desc); 1611 GrTexture* texture = ast.texture(); 1612 if (NULL == texture) { 1613 return false; 1614 } 1615 1616 SkAutoTUnref<const GrEffectRef> effect; 1617 SkMatrix textureMatrix; 1618 textureMatrix.setIDiv(texture->width(), texture->height()); 1619 1620 // allocate a tmp buffer and sw convert the pixels to premul 1621 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); 1622 1623 if (kUnpremul_PixelOpsFlag & flags) { 1624 if (!GrPixelConfigIs8888(srcConfig)) { 1625 return false; 1626 } 1627 effect.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix)); 1628 // handle the unpremul step on the CPU if we couldn't create an effect to do it. 1629 if (NULL == effect) { 1630 SkCanvas::Config8888 srcConfig8888, dstConfig8888; 1631 GR_DEBUGCODE(bool success = ) 1632 grconfig_to_config8888(srcConfig, true, &srcConfig8888); 1633 GrAssert(success); 1634 GR_DEBUGCODE(success = ) 1635 grconfig_to_config8888(srcConfig, false, &dstConfig8888); 1636 GrAssert(success); 1637 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer); 1638 tmpPixels.reset(width * height); 1639 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888, 1640 src, rowBytes, srcConfig8888, 1641 width, height); 1642 buffer = tmpPixels.get(); 1643 rowBytes = 4 * width; 1644 } 1645 } 1646 if (NULL == effect) { 1647 effect.reset(GrConfigConversionEffect::Create(texture, 1648 swapRAndB, 1649 GrConfigConversionEffect::kNone_PMConversion, 1650 textureMatrix)); 1651 } 1652 1653 if (!this->writeTexturePixels(texture, 1654 0, 0, width, height, 1655 writeConfig, buffer, rowBytes, 1656 flags & ~kUnpremul_PixelOpsFlag)) { 1657 return false; 1658 } 1659 1660 GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit); 1661 GrDrawState* drawState = fGpu->drawState(); 1662 GrAssert(effect); 1663 drawState->setEffect(0, effect); 1664 1665 SkMatrix matrix; 1666 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 1667 drawState->setViewMatrix(matrix); 1668 drawState->setRenderTarget(target); 1669 1670 fGpu->drawSimpleRect(GrRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)), NULL); 1671 return true; 1672} 1673//////////////////////////////////////////////////////////////////////////////// 1674 1675GrDrawTarget* GrContext::prepareToDraw(const GrPaint* paint, BufferedDraw buffered) { 1676 if (kNo_BufferedDraw == buffered && kYes_BufferedDraw == fLastDrawWasBuffered) { 1677 this->flushDrawBuffer(); 1678 fLastDrawWasBuffered = kNo_BufferedDraw; 1679 } 1680 if (NULL != paint) { 1681 GrAssert(fDrawState->stagesDisabled()); 1682 fDrawState->setFromPaint(*paint); 1683#if GR_DEBUG_PARTIAL_COVERAGE_CHECK 1684 if ((paint->hasMask() || 0xff != paint->fCoverage) && 1685 !fGpu->canApplyCoverage()) { 1686 GrPrintf("Partial pixel coverage will be incorrectly blended.\n"); 1687 } 1688#endif 1689 } 1690 if (kYes_BufferedDraw == buffered) { 1691 fDrawBuffer->setClip(fGpu->getClip()); 1692 fLastDrawWasBuffered = kYes_BufferedDraw; 1693 return fDrawBuffer; 1694 } else { 1695 GrAssert(kNo_BufferedDraw == buffered); 1696 return fGpu; 1697 } 1698} 1699 1700/* 1701 * This method finds a path renderer that can draw the specified path on 1702 * the provided target. 1703 * Due to its expense, the software path renderer has split out so it can 1704 * can be individually allowed/disallowed via the "allowSW" boolean. 1705 */ 1706GrPathRenderer* GrContext::getPathRenderer(const SkPath& path, 1707 const SkStrokeRec& stroke, 1708 const GrDrawTarget* target, 1709 bool allowSW, 1710 GrPathRendererChain::DrawType drawType, 1711 GrPathRendererChain::StencilSupport* stencilSupport) { 1712 1713 if (NULL == fPathRendererChain) { 1714 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this)); 1715 } 1716 1717 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(path, 1718 stroke, 1719 target, 1720 drawType, 1721 stencilSupport); 1722 1723 if (NULL == pr && allowSW) { 1724 if (NULL == fSoftwarePathRenderer) { 1725 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this)); 1726 } 1727 pr = fSoftwarePathRenderer; 1728 } 1729 1730 return pr; 1731} 1732 1733//////////////////////////////////////////////////////////////////////////////// 1734 1735void GrContext::setRenderTarget(GrRenderTarget* target) { 1736 ASSERT_OWNED_RESOURCE(target); 1737 fDrawState->setRenderTarget(target); 1738} 1739 1740GrRenderTarget* GrContext::getRenderTarget() { 1741 return fDrawState->getRenderTarget(); 1742} 1743 1744const GrRenderTarget* GrContext::getRenderTarget() const { 1745 return fDrawState->getRenderTarget(); 1746} 1747 1748bool GrContext::isConfigRenderable(GrPixelConfig config) const { 1749 return fGpu->isConfigRenderable(config); 1750} 1751 1752const SkMatrix& GrContext::getMatrix() const { 1753 return fDrawState->getViewMatrix(); 1754} 1755 1756void GrContext::setMatrix(const SkMatrix& m) { 1757 fDrawState->setViewMatrix(m); 1758} 1759 1760void GrContext::setIdentityMatrix() { 1761 fDrawState->viewMatrix()->reset(); 1762} 1763 1764void GrContext::concatMatrix(const SkMatrix& m) const { 1765 fDrawState->preConcatViewMatrix(m); 1766} 1767 1768static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { 1769 intptr_t mask = 1 << shift; 1770 if (pred) { 1771 bits |= mask; 1772 } else { 1773 bits &= ~mask; 1774 } 1775 return bits; 1776} 1777 1778void GrContext::setupDrawBuffer() { 1779 1780 GrAssert(NULL == fDrawBuffer); 1781 GrAssert(NULL == fDrawBufferVBAllocPool); 1782 GrAssert(NULL == fDrawBufferIBAllocPool); 1783 1784 fDrawBufferVBAllocPool = 1785 SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false, 1786 DRAW_BUFFER_VBPOOL_BUFFER_SIZE, 1787 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS)); 1788 fDrawBufferIBAllocPool = 1789 SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false, 1790 DRAW_BUFFER_IBPOOL_BUFFER_SIZE, 1791 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS)); 1792 1793 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu, 1794 fDrawBufferVBAllocPool, 1795 fDrawBufferIBAllocPool)); 1796 1797 fDrawBuffer->setDrawState(fDrawState); 1798} 1799 1800GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { 1801 return this->prepareToDraw(&paint, BUFFERED_DRAW); 1802} 1803 1804const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { 1805 return fGpu->getQuadIndexBuffer(); 1806} 1807 1808namespace { 1809void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { 1810 GrConfigConversionEffect::PMConversion pmToUPM; 1811 GrConfigConversionEffect::PMConversion upmToPM; 1812 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM); 1813 *pmToUPMValue = pmToUPM; 1814 *upmToPMValue = upmToPM; 1815} 1816} 1817 1818const GrEffectRef* GrContext::createPMToUPMEffect(GrTexture* texture, 1819 bool swapRAndB, 1820 const SkMatrix& matrix) { 1821 if (!fDidTestPMConversions) { 1822 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); 1823 fDidTestPMConversions = true; 1824 } 1825 GrConfigConversionEffect::PMConversion pmToUPM = 1826 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); 1827 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { 1828 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix); 1829 } else { 1830 return NULL; 1831 } 1832} 1833 1834const GrEffectRef* GrContext::createUPMToPMEffect(GrTexture* texture, 1835 bool swapRAndB, 1836 const SkMatrix& matrix) { 1837 if (!fDidTestPMConversions) { 1838 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); 1839 fDidTestPMConversions = true; 1840 } 1841 GrConfigConversionEffect::PMConversion upmToPM = 1842 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); 1843 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { 1844 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix); 1845 } else { 1846 return NULL; 1847 } 1848} 1849 1850GrTexture* GrContext::gaussianBlur(GrTexture* srcTexture, 1851 bool canClobberSrc, 1852 const SkRect& rect, 1853 float sigmaX, float sigmaY) { 1854 ASSERT_OWNED_RESOURCE(srcTexture); 1855 1856 AutoRenderTarget art(this); 1857 1858 AutoMatrix am; 1859 am.setIdentity(this); 1860 1861 SkIRect clearRect; 1862 int scaleFactorX, radiusX; 1863 int scaleFactorY, radiusY; 1864 sigmaX = adjust_sigma(sigmaX, &scaleFactorX, &radiusX); 1865 sigmaY = adjust_sigma(sigmaY, &scaleFactorY, &radiusY); 1866 1867 SkRect srcRect(rect); 1868 scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); 1869 srcRect.roundOut(); 1870 scale_rect(&srcRect, static_cast<float>(scaleFactorX), 1871 static_cast<float>(scaleFactorY)); 1872 1873 AutoClip acs(this, srcRect); 1874 1875 GrAssert(kBGRA_8888_GrPixelConfig == srcTexture->config() || 1876 kRGBA_8888_GrPixelConfig == srcTexture->config() || 1877 kAlpha_8_GrPixelConfig == srcTexture->config()); 1878 1879 GrTextureDesc desc; 1880 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 1881 desc.fWidth = SkScalarFloorToInt(srcRect.width()); 1882 desc.fHeight = SkScalarFloorToInt(srcRect.height()); 1883 desc.fConfig = srcTexture->config(); 1884 1885 GrAutoScratchTexture temp1, temp2; 1886 GrTexture* dstTexture = temp1.set(this, desc); 1887 GrTexture* tempTexture = canClobberSrc ? srcTexture : temp2.set(this, desc); 1888 if (NULL == dstTexture || NULL == tempTexture) { 1889 return NULL; 1890 } 1891 1892 GrPaint paint; 1893 paint.reset(); 1894 1895 for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { 1896 SkMatrix matrix; 1897 matrix.setIDiv(srcTexture->width(), srcTexture->height()); 1898 this->setRenderTarget(dstTexture->asRenderTarget()); 1899 SkRect dstRect(srcRect); 1900 scale_rect(&dstRect, i < scaleFactorX ? 0.5f : 1.0f, 1901 i < scaleFactorY ? 0.5f : 1.0f); 1902 1903 paint.colorStage(0)->setEffect(GrSimpleTextureEffect::Create(srcTexture, 1904 matrix, 1905 true))->unref(); 1906 this->drawRectToRect(paint, dstRect, srcRect); 1907 srcRect = dstRect; 1908 srcTexture = dstTexture; 1909 SkTSwap(dstTexture, tempTexture); 1910 } 1911 1912 SkIRect srcIRect; 1913 srcRect.roundOut(&srcIRect); 1914 1915 if (sigmaX > 0.0f) { 1916 if (scaleFactorX > 1) { 1917 // Clear out a radius to the right of the srcRect to prevent the 1918 // X convolution from reading garbage. 1919 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1920 radiusX, srcIRect.height()); 1921 this->clear(&clearRect, 0x0); 1922 } 1923 1924 this->setRenderTarget(dstTexture->asRenderTarget()); 1925 GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW); 1926 convolve_gaussian(target, srcTexture, srcRect, sigmaX, radiusX, 1927 Gr1DKernelEffect::kX_Direction); 1928 srcTexture = dstTexture; 1929 SkTSwap(dstTexture, tempTexture); 1930 } 1931 1932 if (sigmaY > 0.0f) { 1933 if (scaleFactorY > 1 || sigmaX > 0.0f) { 1934 // Clear out a radius below the srcRect to prevent the Y 1935 // convolution from reading garbage. 1936 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, 1937 srcIRect.width(), radiusY); 1938 this->clear(&clearRect, 0x0); 1939 } 1940 1941 this->setRenderTarget(dstTexture->asRenderTarget()); 1942 GrDrawTarget* target = this->prepareToDraw(NULL, BUFFERED_DRAW); 1943 convolve_gaussian(target, srcTexture, srcRect, sigmaY, radiusY, 1944 Gr1DKernelEffect::kY_Direction); 1945 srcTexture = dstTexture; 1946 SkTSwap(dstTexture, tempTexture); 1947 } 1948 1949 if (scaleFactorX > 1 || scaleFactorY > 1) { 1950 // Clear one pixel to the right and below, to accommodate bilinear 1951 // upsampling. 1952 clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom, 1953 srcIRect.width() + 1, 1); 1954 this->clear(&clearRect, 0x0); 1955 clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop, 1956 1, srcIRect.height()); 1957 this->clear(&clearRect, 0x0); 1958 SkMatrix matrix; 1959 // FIXME: This should be mitchell, not bilinear. 1960 matrix.setIDiv(srcTexture->width(), srcTexture->height()); 1961 this->setRenderTarget(dstTexture->asRenderTarget()); 1962 paint.colorStage(0)->setEffect(GrSimpleTextureEffect::Create(srcTexture, 1963 matrix, 1964 true))->unref(); 1965 SkRect dstRect(srcRect); 1966 scale_rect(&dstRect, (float) scaleFactorX, (float) scaleFactorY); 1967 this->drawRectToRect(paint, dstRect, srcRect); 1968 srcRect = dstRect; 1969 srcTexture = dstTexture; 1970 SkTSwap(dstTexture, tempTexture); 1971 } 1972 if (srcTexture == temp1.texture()) { 1973 return temp1.detach(); 1974 } else if (srcTexture == temp2.texture()) { 1975 return temp2.detach(); 1976 } else { 1977 srcTexture->ref(); 1978 return srcTexture; 1979 } 1980} 1981 1982/////////////////////////////////////////////////////////////////////////////// 1983#if GR_CACHE_STATS 1984void GrContext::printCacheStats() const { 1985 fTextureCache->printStats(); 1986} 1987#endif 1988