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