GrContext.cpp revision 838e866289480b6384de95264382012d55100e99
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 "GrBufferAllocPool.h" 13#include "GrClipIterator.h" 14#include "GrGpu.h" 15#include "GrIndexBuffer.h" 16#include "GrInOrderDrawBuffer.h" 17#include "GrPathRenderer.h" 18#include "GrPathUtils.h" 19#include "GrResourceCache.h" 20#include "GrStencilBuffer.h" 21#include "GrTextStrike.h" 22#include "SkTLazy.h" 23#include "SkTrace.h" 24 25// Using MSAA seems to be slower for some yet unknown reason. 26#define PREFER_MSAA_OFFSCREEN_AA 0 27#define OFFSCREEN_SSAA_SCALE 4 // super sample at 4x4 28 29#define DEFER_TEXT_RENDERING 1 30 31#define BATCH_RECT_TO_RECT (1 && !GR_STATIC_RECT_VB) 32 33// When we're using coverage AA but the blend is incompatible (given gpu 34// limitations) should we disable AA or draw wrong? 35#define DISABLE_COVERAGE_AA_FOR_BLEND 1 36 37static const size_t MAX_TEXTURE_CACHE_COUNT = 256; 38static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024; 39 40static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18; 41static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; 42 43// We are currently only batching Text and drawRectToRect, both 44// of which use the quad index buffer. 45static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; 46static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; 47 48#define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this) 49 50GrContext* GrContext::Create(GrEngine engine, 51 GrPlatform3DContext context3D) { 52 GrContext* ctx = NULL; 53 GrGpu* fGpu = GrGpu::Create(engine, context3D); 54 if (NULL != fGpu) { 55 ctx = new GrContext(fGpu); 56 fGpu->unref(); 57 } 58 return ctx; 59} 60 61GrContext::~GrContext() { 62 this->flush(); 63 delete fTextureCache; 64 delete fFontCache; 65 delete fDrawBuffer; 66 delete fDrawBufferVBAllocPool; 67 delete fDrawBufferIBAllocPool; 68 69 GrSafeUnref(fAAFillRectIndexBuffer); 70 GrSafeUnref(fAAStrokeRectIndexBuffer); 71 fGpu->unref(); 72 GrSafeUnref(fPathRendererChain); 73} 74 75void GrContext::contextLost() { 76 contextDestroyed(); 77 this->setupDrawBuffer(); 78} 79 80void GrContext::contextDestroyed() { 81 // abandon first to so destructors 82 // don't try to free the resources in the API. 83 fGpu->abandonResources(); 84 85 // a path renderer may be holding onto resources that 86 // are now unusable 87 GrSafeSetNull(fPathRendererChain); 88 89 delete fDrawBuffer; 90 fDrawBuffer = NULL; 91 92 delete fDrawBufferVBAllocPool; 93 fDrawBufferVBAllocPool = NULL; 94 95 delete fDrawBufferIBAllocPool; 96 fDrawBufferIBAllocPool = NULL; 97 98 GrSafeSetNull(fAAFillRectIndexBuffer); 99 GrSafeSetNull(fAAStrokeRectIndexBuffer); 100 101 fTextureCache->removeAll(); 102 fFontCache->freeAll(); 103 fGpu->markContextDirty(); 104} 105 106void GrContext::resetContext() { 107 fGpu->markContextDirty(); 108} 109 110void GrContext::freeGpuResources() { 111 this->flush(); 112 fTextureCache->removeAll(); 113 fFontCache->freeAll(); 114 // a path renderer may be holding onto resources 115 GrSafeSetNull(fPathRendererChain); 116} 117 118//////////////////////////////////////////////////////////////////////////////// 119 120int GrContext::PaintStageVertexLayoutBits( 121 const GrPaint& paint, 122 const bool hasTexCoords[GrPaint::kTotalStages]) { 123 int stageMask = paint.getActiveStageMask(); 124 int layout = 0; 125 for (int i = 0; i < GrPaint::kTotalStages; ++i) { 126 if ((1 << i) & stageMask) { 127 if (NULL != hasTexCoords && hasTexCoords[i]) { 128 layout |= GrDrawTarget::StageTexCoordVertexLayoutBit(i, i); 129 } else { 130 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(i); 131 } 132 } 133 } 134 return layout; 135} 136 137 138//////////////////////////////////////////////////////////////////////////////// 139 140enum { 141 // flags for textures 142 kNPOTBit = 0x1, 143 kFilterBit = 0x2, 144 kScratchBit = 0x4, 145 146 // resource type 147 kTextureBit = 0x8, 148 kStencilBufferBit = 0x10 149}; 150 151GrTexture* GrContext::TextureCacheEntry::texture() const { 152 if (NULL == fEntry) { 153 return NULL; 154 } else { 155 return (GrTexture*) fEntry->resource(); 156 } 157} 158 159namespace { 160// returns true if this is a "special" texture because of gpu NPOT limitations 161bool gen_texture_key_values(const GrGpu* gpu, 162 const GrSamplerState* sampler, 163 GrContext::TextureKey clientKey, 164 int width, 165 int height, 166 bool scratch, 167 uint32_t v[4]) { 168 GR_STATIC_ASSERT(sizeof(GrContext::TextureKey) == sizeof(uint64_t)); 169 // we assume we only need 16 bits of width and height 170 // assert that texture creation will fail anyway if this assumption 171 // would cause key collisions. 172 GrAssert(gpu->getCaps().fMaxTextureSize <= SK_MaxU16); 173 v[0] = clientKey & 0xffffffffUL; 174 v[1] = (clientKey >> 32) & 0xffffffffUL; 175 v[2] = width | (height << 16); 176 177 v[3] = 0; 178 if (!gpu->getCaps().fNPOTTextureTileSupport) { 179 bool isPow2 = GrIsPow2(width) && GrIsPow2(height); 180 181 bool tiled = NULL != sampler && 182 ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) || 183 (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode)); 184 185 if (tiled && !isPow2) { 186 v[3] |= kNPOTBit; 187 if (GrSamplerState::kNearest_Filter != sampler->getFilter()) { 188 v[3] |= kFilterBit; 189 } 190 } 191 } 192 193 if (scratch) { 194 v[3] |= kScratchBit; 195 } 196 197 v[3] |= kTextureBit; 198 199 return v[3] & kNPOTBit; 200} 201 202// we should never have more than one stencil buffer with same combo of 203// (width,height,samplecount) 204void gen_stencil_key_values(int width, int height, 205 int sampleCnt, uint32_t v[4]) { 206 v[0] = width; 207 v[1] = height; 208 v[2] = sampleCnt; 209 v[3] = kStencilBufferBit; 210} 211 212void gen_stencil_key_values(const GrStencilBuffer* sb, 213 uint32_t v[4]) { 214 gen_stencil_key_values(sb->width(), sb->height(), 215 sb->numSamples(), v); 216} 217 218// This should be subsumed by a future version of GrDrawState 219// It does not reset stage textures/samplers or per-vertex-edge-aa state since 220// they aren't used unless the vertex layout references them. 221// It also doesn't set the render target. 222void reset_draw_state(GrDrawState* drawState){ 223 224 drawState->setViewMatrix(GrMatrix::I()); 225 drawState->setColorFilter(0, SkXfermode::kDst_Mode); 226 drawState->resetStateFlags(); 227 drawState->setEdgeAAData(NULL, 0); 228 drawState->disableStencil(); 229 drawState->setAlpha(0xFF); 230 drawState->setBlendFunc(kOne_BlendCoeff, 231 kZero_BlendCoeff); 232 drawState->setFirstCoverageStage(GrDrawState::kNumStages); 233 drawState->setDrawFace(GrDrawState::kBoth_DrawFace); 234} 235} 236 237GrContext::TextureCacheEntry GrContext::findAndLockTexture( 238 TextureKey key, 239 int width, 240 int height, 241 const GrSamplerState* sampler) { 242 uint32_t v[4]; 243 gen_texture_key_values(fGpu, sampler, key, width, height, false, v); 244 GrResourceKey resourceKey(v); 245 return TextureCacheEntry(fTextureCache->findAndLock(resourceKey, 246 GrResourceCache::kNested_LockType)); 247} 248 249bool GrContext::isTextureInCache(TextureKey key, 250 int width, 251 int height, 252 const GrSamplerState* sampler) const { 253 uint32_t v[4]; 254 gen_texture_key_values(fGpu, sampler, key, width, height, false, v); 255 GrResourceKey resourceKey(v); 256 return fTextureCache->hasKey(resourceKey); 257} 258 259GrResourceEntry* GrContext::addAndLockStencilBuffer(GrStencilBuffer* sb) { 260 ASSERT_OWNED_RESOURCE(sb); 261 uint32_t v[4]; 262 gen_stencil_key_values(sb, v); 263 GrResourceKey resourceKey(v); 264 return fTextureCache->createAndLock(resourceKey, sb); 265} 266 267GrStencilBuffer* GrContext::findStencilBuffer(int width, int height, 268 int sampleCnt) { 269 uint32_t v[4]; 270 gen_stencil_key_values(width, height, sampleCnt, v); 271 GrResourceKey resourceKey(v); 272 GrResourceEntry* entry = fTextureCache->findAndLock(resourceKey, 273 GrResourceCache::kSingle_LockType); 274 if (NULL != entry) { 275 GrStencilBuffer* sb = (GrStencilBuffer*) entry->resource(); 276 return sb; 277 } else { 278 return NULL; 279 } 280} 281 282void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) { 283 ASSERT_OWNED_RESOURCE(sbEntry->resource()); 284 fTextureCache->unlock(sbEntry); 285} 286 287static void stretchImage(void* dst, 288 int dstW, 289 int dstH, 290 void* src, 291 int srcW, 292 int srcH, 293 int bpp) { 294 GrFixed dx = (srcW << 16) / dstW; 295 GrFixed dy = (srcH << 16) / dstH; 296 297 GrFixed y = dy >> 1; 298 299 int dstXLimit = dstW*bpp; 300 for (int j = 0; j < dstH; ++j) { 301 GrFixed x = dx >> 1; 302 void* srcRow = (uint8_t*)src + (y>>16)*srcW*bpp; 303 void* dstRow = (uint8_t*)dst + j*dstW*bpp; 304 for (int i = 0; i < dstXLimit; i += bpp) { 305 memcpy((uint8_t*) dstRow + i, 306 (uint8_t*) srcRow + (x>>16)*bpp, 307 bpp); 308 x += dx; 309 } 310 y += dy; 311 } 312} 313 314GrContext::TextureCacheEntry GrContext::createAndLockTexture( 315 TextureKey key, 316 const GrSamplerState* sampler, 317 const GrTextureDesc& desc, 318 void* srcData, 319 size_t rowBytes) { 320 SK_TRACE_EVENT0("GrContext::createAndLockTexture"); 321 322#if GR_DUMP_TEXTURE_UPLOAD 323 GrPrintf("GrContext::createAndLockTexture [%d %d]\n", desc.fWidth, desc.fHeight); 324#endif 325 326 TextureCacheEntry entry; 327 uint32_t v[4]; 328 bool special = gen_texture_key_values(fGpu, sampler, key, 329 desc.fWidth, desc.fHeight, false, v); 330 GrResourceKey resourceKey(v); 331 332 if (special) { 333 GrAssert(NULL != sampler); 334 TextureCacheEntry clampEntry = this->findAndLockTexture(key, 335 desc.fWidth, 336 desc.fHeight, 337 NULL); 338 339 if (NULL == clampEntry.texture()) { 340 clampEntry = this->createAndLockTexture(key, NULL, desc, 341 srcData, rowBytes); 342 GrAssert(NULL != clampEntry.texture()); 343 if (NULL == clampEntry.texture()) { 344 return entry; 345 } 346 } 347 GrTextureDesc rtDesc = desc; 348 rtDesc.fFlags = rtDesc.fFlags | 349 kRenderTarget_GrTextureFlagBit | 350 kNoStencil_GrTextureFlagBit; 351 rtDesc.fWidth = GrNextPow2(GrMax(desc.fWidth, 64)); 352 rtDesc.fHeight = GrNextPow2(GrMax(desc.fHeight, 64)); 353 354 GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0); 355 356 if (NULL != texture) { 357 GrDrawTarget::AutoStateRestore asr(fGpu); 358 GrDrawState* drawState = fGpu->drawState(); 359 reset_draw_state(drawState); 360 drawState->setRenderTarget(texture->asRenderTarget()); 361 drawState->setTexture(0, clampEntry.texture()); 362 363 GrSamplerState::Filter filter; 364 // if filtering is not desired then we want to ensure all 365 // texels in the resampled image are copies of texels from 366 // the original. 367 if (GrSamplerState::kNearest_Filter == sampler->getFilter()) { 368 filter = GrSamplerState::kNearest_Filter; 369 } else { 370 filter = GrSamplerState::kBilinear_Filter; 371 } 372 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 373 filter); 374 375 static const GrVertexLayout layout = 376 GrDrawTarget::StageTexCoordVertexLayoutBit(0,0); 377 GrDrawTarget::AutoReleaseGeometry arg(fGpu, layout, 4, 0); 378 379 if (arg.succeeded()) { 380 GrPoint* verts = (GrPoint*) arg.vertices(); 381 verts[0].setIRectFan(0, 0, 382 texture->width(), 383 texture->height(), 384 2*sizeof(GrPoint)); 385 verts[1].setIRectFan(0, 0, 1, 1, 2*sizeof(GrPoint)); 386 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 387 0, 4); 388 entry.set(fTextureCache->createAndLock(resourceKey, texture)); 389 } 390 texture->releaseRenderTarget(); 391 } else { 392 // TODO: Our CPU stretch doesn't filter. But we create separate 393 // stretched textures when the sampler state is either filtered or 394 // not. Either implement filtered stretch blit on CPU or just create 395 // one when FBO case fails. 396 397 rtDesc.fFlags = kNone_GrTextureFlags; 398 // no longer need to clamp at min RT size. 399 rtDesc.fWidth = GrNextPow2(desc.fWidth); 400 rtDesc.fHeight = GrNextPow2(desc.fHeight); 401 int bpp = GrBytesPerPixel(desc.fConfig); 402 SkAutoSMalloc<128*128*4> stretchedPixels(bpp * 403 rtDesc.fWidth * 404 rtDesc.fHeight); 405 stretchImage(stretchedPixels.get(), rtDesc.fWidth, rtDesc.fHeight, 406 srcData, desc.fWidth, desc.fHeight, bpp); 407 408 size_t stretchedRowBytes = rtDesc.fWidth * bpp; 409 410 GrTexture* texture = fGpu->createTexture(rtDesc, 411 stretchedPixels.get(), 412 stretchedRowBytes); 413 GrAssert(NULL != texture); 414 entry.set(fTextureCache->createAndLock(resourceKey, texture)); 415 } 416 fTextureCache->unlock(clampEntry.cacheEntry()); 417 418 } else { 419 GrTexture* texture = fGpu->createTexture(desc, srcData, rowBytes); 420 if (NULL != texture) { 421 entry.set(fTextureCache->createAndLock(resourceKey, texture)); 422 } 423 } 424 return entry; 425} 426 427namespace { 428inline void gen_scratch_tex_key_values(const GrGpu* gpu, 429 const GrTextureDesc& desc, 430 uint32_t v[4]) { 431 // Instead of a client-provided key of the texture contents 432 // we create a key of from the descriptor. 433 GrContext::TextureKey descKey = desc.fAALevel | 434 (desc.fFlags << 8) | 435 ((uint64_t) desc.fConfig << 32); 436 // this code path isn't friendly to tiling with NPOT restricitons 437 // We just pass ClampNoFilter() 438 gen_texture_key_values(gpu, NULL, descKey, desc.fWidth, 439 desc.fHeight, true, v); 440} 441} 442 443GrContext::TextureCacheEntry GrContext::lockScratchTexture( 444 const GrTextureDesc& inDesc, 445 ScratchTexMatch match) { 446 447 GrTextureDesc desc = inDesc; 448 if (kExact_ScratchTexMatch != match) { 449 // bin by pow2 with a reasonable min 450 static const int MIN_SIZE = 256; 451 desc.fWidth = GrMax(MIN_SIZE, GrNextPow2(desc.fWidth)); 452 desc.fHeight = GrMax(MIN_SIZE, GrNextPow2(desc.fHeight)); 453 } 454 455 uint32_t p0 = desc.fConfig; 456 uint32_t p1 = (desc.fAALevel << 16) | desc.fFlags; 457 458 GrResourceEntry* entry; 459 int origWidth = desc.fWidth; 460 int origHeight = desc.fHeight; 461 bool doubledW = false; 462 bool doubledH = false; 463 464 do { 465 uint32_t v[4]; 466 gen_scratch_tex_key_values(fGpu, desc, v); 467 GrResourceKey key(v); 468 entry = fTextureCache->findAndLock(key, 469 GrResourceCache::kNested_LockType); 470 // if we miss, relax the fit of the flags... 471 // then try doubling width... then height. 472 if (NULL != entry || kExact_ScratchTexMatch == match) { 473 break; 474 } 475 if (!(desc.fFlags & kRenderTarget_GrTextureFlagBit)) { 476 desc.fFlags = desc.fFlags | kRenderTarget_GrTextureFlagBit; 477 } else if (desc.fFlags & kNoStencil_GrTextureFlagBit) { 478 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit; 479 } else if (!doubledW) { 480 desc.fFlags = inDesc.fFlags; 481 desc.fWidth *= 2; 482 doubledW = true; 483 } else if (!doubledH) { 484 desc.fFlags = inDesc.fFlags; 485 desc.fWidth = origWidth; 486 desc.fHeight *= 2; 487 doubledH = true; 488 } else { 489 break; 490 } 491 492 } while (true); 493 494 if (NULL == entry) { 495 desc.fFlags = inDesc.fFlags; 496 desc.fWidth = origWidth; 497 desc.fHeight = origHeight; 498 GrTexture* texture = fGpu->createTexture(desc, NULL, 0); 499 if (NULL != texture) { 500 uint32_t v[4]; 501 gen_scratch_tex_key_values(fGpu, desc, v); 502 GrResourceKey key(v); 503 entry = fTextureCache->createAndLock(key, texture); 504 } 505 } 506 507 // If the caller gives us the same desc/sampler twice we don't want 508 // to return the same texture the second time (unless it was previously 509 // released). So we detach the entry from the cache and reattach at release. 510 if (NULL != entry) { 511 fTextureCache->detach(entry); 512 } 513 return TextureCacheEntry(entry); 514} 515 516void GrContext::unlockTexture(TextureCacheEntry entry) { 517 ASSERT_OWNED_RESOURCE(entry.texture()); 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 (kScratchBit & entry.cacheEntry()->key().getValue32(3)) { 522 fTextureCache->reattachAndUnlock(entry.cacheEntry()); 523 } else { 524 fTextureCache->unlock(entry.cacheEntry()); 525 } 526} 527 528GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc, 529 void* srcData, 530 size_t rowBytes) { 531 return fGpu->createTexture(desc, srcData, rowBytes); 532} 533 534void GrContext::getTextureCacheLimits(int* maxTextures, 535 size_t* maxTextureBytes) const { 536 fTextureCache->getLimits(maxTextures, maxTextureBytes); 537} 538 539void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { 540 fTextureCache->setLimits(maxTextures, maxTextureBytes); 541} 542 543int GrContext::getMaxTextureSize() const { 544 return fGpu->getCaps().fMaxTextureSize; 545} 546 547int GrContext::getMaxRenderTargetSize() const { 548 return fGpu->getCaps().fMaxRenderTargetSize; 549} 550 551/////////////////////////////////////////////////////////////////////////////// 552 553GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) { 554 return fGpu->createPlatformTexture(desc); 555} 556 557GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { 558 return fGpu->createPlatformRenderTarget(desc); 559} 560 561GrResource* GrContext::createPlatformSurface(const GrPlatformSurfaceDesc& desc) { 562 // validate flags here so that GrGpu subclasses don't have to check 563 if (kTexture_GrPlatformSurfaceType == desc.fSurfaceType && 564 0 != desc.fRenderTargetFlags) { 565 return NULL; 566 } 567 if (desc.fSampleCnt && 568 (kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) { 569 return NULL; 570 } 571 if (kTextureRenderTarget_GrPlatformSurfaceType == desc.fSurfaceType && 572 desc.fSampleCnt && 573 !(kGrCanResolve_GrPlatformRenderTargetFlagBit & desc.fRenderTargetFlags)) { 574 return NULL; 575 } 576 return fGpu->createPlatformSurface(desc); 577} 578 579/////////////////////////////////////////////////////////////////////////////// 580 581bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler, 582 int width, int height) const { 583 const GrDrawTarget::Caps& caps = fGpu->getCaps(); 584 if (!caps.f8BitPaletteSupport) { 585 return false; 586 } 587 588 bool isPow2 = GrIsPow2(width) && GrIsPow2(height); 589 590 if (!isPow2) { 591 bool tiled = NULL != sampler && 592 (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode || 593 sampler->getWrapY() != GrSamplerState::kClamp_WrapMode); 594 if (tiled && !caps.fNPOTTextureTileSupport) { 595 return false; 596 } 597 } 598 return true; 599} 600 601//////////////////////////////////////////////////////////////////////////////// 602 603const GrClip& GrContext::getClip() const { return fGpu->getClip(); } 604 605void GrContext::setClip(const GrClip& clip) { 606 fGpu->setClip(clip); 607 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit); 608} 609 610void GrContext::setClip(const GrIRect& rect) { 611 GrClip clip; 612 clip.setFromIRect(rect); 613 fGpu->setClip(clip); 614} 615 616//////////////////////////////////////////////////////////////////////////////// 617 618void GrContext::clear(const GrIRect* rect, const GrColor color) { 619 this->flush(); 620 fGpu->clear(rect, color); 621} 622 623void GrContext::drawPaint(const GrPaint& paint) { 624 // set rect to be big enough to fill the space, but not super-huge, so we 625 // don't overflow fixed-point implementations 626 GrRect r; 627 r.setLTRB(0, 0, 628 GrIntToScalar(getRenderTarget()->width()), 629 GrIntToScalar(getRenderTarget()->height())); 630 GrMatrix inverse; 631 SkTLazy<GrPaint> tmpPaint; 632 const GrPaint* p = &paint; 633 GrDrawState* drawState = fGpu->drawState(); 634 GrAutoMatrix am; 635 636 // We attempt to map r by the inverse matrix and draw that. mapRect will 637 // map the four corners and bound them with a new rect. This will not 638 // produce a correct result for some perspective matrices. 639 if (!this->getMatrix().hasPerspective()) { 640 if (!drawState->getViewInverse(&inverse)) { 641 GrPrintf("Could not invert matrix"); 642 return; 643 } 644 inverse.mapRect(&r); 645 } else { 646 if (paint.getActiveMaskStageMask() || paint.getActiveStageMask()) { 647 if (!drawState->getViewInverse(&inverse)) { 648 GrPrintf("Could not invert matrix"); 649 return; 650 } 651 tmpPaint.set(paint); 652 tmpPaint.get()->preConcatActiveSamplerMatrices(inverse); 653 p = tmpPaint.get(); 654 } 655 am.set(this, GrMatrix::I()); 656 } 657 // by definition this fills the entire clip, no need for AA 658 if (paint.fAntiAlias) { 659 if (!tmpPaint.isValid()) { 660 tmpPaint.set(paint); 661 p = tmpPaint.get(); 662 } 663 GrAssert(p == tmpPaint.get()); 664 tmpPaint.get()->fAntiAlias = false; 665 } 666 this->drawRect(*p, r); 667} 668 669//////////////////////////////////////////////////////////////////////////////// 670 671namespace { 672inline bool disable_coverage_aa_for_blend(GrDrawTarget* target) { 673 return DISABLE_COVERAGE_AA_FOR_BLEND && !target->canApplyCoverage(); 674} 675} 676 677struct GrContext::OffscreenRecord { 678 enum Downsample { 679 k4x4TwoPass_Downsample, 680 k4x4SinglePass_Downsample, 681 kFSAA_Downsample 682 } fDownsample; 683 int fTileSizeX; 684 int fTileSizeY; 685 int fTileCountX; 686 int fTileCountY; 687 int fScale; 688 GrAutoScratchTexture fOffscreen0; 689 GrAutoScratchTexture fOffscreen1; 690 GrDrawTarget::SavedDrawState fSavedState; 691 GrClip fClip; 692}; 693 694bool GrContext::doOffscreenAA(GrDrawTarget* target, 695 bool isHairLines) const { 696#if !GR_USE_OFFSCREEN_AA 697 return false; 698#else 699 // Line primitves are always rasterized as 1 pixel wide. 700 // Super-sampling would make them too thin but MSAA would be OK. 701 if (isHairLines && 702 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) { 703 return false; 704 } 705 if (target->getDrawState().getRenderTarget()->isMultisampled()) { 706 return false; 707 } 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 } 714 return true; 715#endif 716} 717 718bool GrContext::prepareForOffscreenAA(GrDrawTarget* target, 719 bool requireStencil, 720 const GrIRect& boundRect, 721 GrPathRenderer* pr, 722 OffscreenRecord* record) { 723 724 GrAssert(GR_USE_OFFSCREEN_AA); 725 726 GrAssert(NULL == record->fOffscreen0.texture()); 727 GrAssert(NULL == record->fOffscreen1.texture()); 728 GrAssert(!boundRect.isEmpty()); 729 730 int boundW = boundRect.width(); 731 int boundH = boundRect.height(); 732 733 GrTextureDesc desc; 734 735 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW); 736 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH); 737 738 if (requireStencil) { 739 desc.fFlags = kRenderTarget_GrTextureFlagBit; 740 } else { 741 desc.fFlags = kRenderTarget_GrTextureFlagBit | 742 kNoStencil_GrTextureFlagBit; 743 } 744 745 desc.fConfig = kRGBA_8888_PM_GrPixelConfig; 746 747 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) { 748 record->fDownsample = OffscreenRecord::kFSAA_Downsample; 749 record->fScale = 1; 750 desc.fAALevel = kMed_GrAALevel; 751 } else { 752 record->fDownsample = fGpu->getCaps().fShaderSupport ? 753 OffscreenRecord::k4x4SinglePass_Downsample : 754 OffscreenRecord::k4x4TwoPass_Downsample; 755 record->fScale = OFFSCREEN_SSAA_SCALE; 756 // both downsample paths assume this 757 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE); 758 desc.fAALevel = kNone_GrAALevel; 759 } 760 761 desc.fWidth *= record->fScale; 762 desc.fHeight *= record->fScale; 763 record->fOffscreen0.set(this, desc); 764 if (NULL == record->fOffscreen0.texture()) { 765 return false; 766 } 767 // the approximate lookup might have given us some slop space, might as well 768 // use it when computing the tiles size. 769 // these are scale values, will adjust after considering 770 // the possible second offscreen. 771 record->fTileSizeX = record->fOffscreen0.texture()->width(); 772 record->fTileSizeY = record->fOffscreen0.texture()->height(); 773 774 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { 775 desc.fWidth /= 2; 776 desc.fHeight /= 2; 777 record->fOffscreen1.set(this, desc); 778 if (NULL == record->fOffscreen1.texture()) { 779 return false; 780 } 781 record->fTileSizeX = GrMin(record->fTileSizeX, 782 2 * record->fOffscreen0.texture()->width()); 783 record->fTileSizeY = GrMin(record->fTileSizeY, 784 2 * record->fOffscreen0.texture()->height()); 785 } 786 record->fTileSizeX /= record->fScale; 787 record->fTileSizeY /= record->fScale; 788 789 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX); 790 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY); 791 792 record->fClip = target->getClip(); 793 794 target->saveCurrentDrawState(&record->fSavedState); 795 return true; 796} 797 798void GrContext::setupOffscreenAAPass1(GrDrawTarget* target, 799 const GrIRect& boundRect, 800 int tileX, int tileY, 801 OffscreenRecord* record) { 802 803 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget(); 804 GrAssert(NULL != offRT0); 805 806 GrPaint tempPaint; 807 tempPaint.reset(); 808 this->setPaint(tempPaint, target); 809 GrDrawState* drawState = target->drawState(); 810 drawState->setRenderTarget(offRT0); 811#if PREFER_MSAA_OFFSCREEN_AA 812 target->enableState(GrDrawState::kHWAntialias_StateBit); 813#endif 814 815 GrMatrix transM; 816 int left = boundRect.fLeft + tileX * record->fTileSizeX; 817 int top = boundRect.fTop + tileY * record->fTileSizeY; 818 transM.setTranslate(-left * GR_Scalar1, -top * GR_Scalar1); 819 drawState->viewMatrix()->postConcat(transM); 820 GrMatrix scaleM; 821 scaleM.setScale(record->fScale * GR_Scalar1, record->fScale * GR_Scalar1); 822 drawState->viewMatrix()->postConcat(scaleM); 823 824 int w = (tileX == record->fTileCountX-1) ? boundRect.fRight - left : 825 record->fTileSizeX; 826 int h = (tileY == record->fTileCountY-1) ? boundRect.fBottom - top : 827 record->fTileSizeY; 828 GrIRect clear = SkIRect::MakeWH(record->fScale * w, 829 record->fScale * h); 830 target->setClip(GrClip(clear)); 831#if 0 832 // visualize tile boundaries by setting edges of offscreen to white 833 // and interior to tranparent. black. 834 target->clear(&clear, 0xffffffff); 835 836 static const int gOffset = 2; 837 GrIRect clear2 = SkIRect::MakeLTRB(gOffset, gOffset, 838 record->fScale * w - gOffset, 839 record->fScale * h - gOffset); 840 target->clear(&clear2, 0x0); 841#else 842 target->clear(&clear, 0x0); 843#endif 844} 845 846void GrContext::doOffscreenAAPass2(GrDrawTarget* target, 847 const GrPaint& paint, 848 const GrIRect& boundRect, 849 int tileX, int tileY, 850 OffscreenRecord* record) { 851 SK_TRACE_EVENT0("GrContext::doOffscreenAAPass2"); 852 GrAssert(NULL != record->fOffscreen0.texture()); 853 GrDrawTarget::AutoGeometryPush agp(target); 854 GrIRect tileRect; 855 tileRect.fLeft = boundRect.fLeft + tileX * record->fTileSizeX; 856 tileRect.fTop = boundRect.fTop + tileY * record->fTileSizeY, 857 tileRect.fRight = (tileX == record->fTileCountX-1) ? 858 boundRect.fRight : 859 tileRect.fLeft + record->fTileSizeX; 860 tileRect.fBottom = (tileY == record->fTileCountY-1) ? 861 boundRect.fBottom : 862 tileRect.fTop + record->fTileSizeY; 863 864 GrSamplerState::Filter filter; 865 if (OffscreenRecord::k4x4SinglePass_Downsample == record->fDownsample) { 866 filter = GrSamplerState::k4x4Downsample_Filter; 867 } else { 868 filter = GrSamplerState::kBilinear_Filter; 869 } 870 871 GrTexture* src = record->fOffscreen0.texture(); 872 int scale; 873 874 enum { 875 kOffscreenStage = GrPaint::kTotalStages, 876 }; 877 878 GrDrawState* drawState = target->drawState(); 879 880 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { 881 GrAssert(NULL != record->fOffscreen1.texture()); 882 scale = 2; 883 GrRenderTarget* dst = record->fOffscreen1.texture()->asRenderTarget(); 884 885 // Do 2x2 downsample from first to second 886 drawState->setTexture(kOffscreenStage, src); 887 drawState->setRenderTarget(dst); 888 drawState->setViewMatrix(GrMatrix::I()); 889 GrSamplerState* sampler = drawState->sampler(kOffscreenStage); 890 sampler->reset(GrSamplerState::kClamp_WrapMode, filter); 891 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(), 892 scale * GR_Scalar1 / src->height()); 893 GrRect rect = SkRect::MakeWH(SkIntToScalar(scale * tileRect.width()), 894 SkIntToScalar(scale * tileRect.height())); 895 target->drawSimpleRect(rect, NULL, 1 << kOffscreenStage); 896 897 src = record->fOffscreen1.texture(); 898 } else if (OffscreenRecord::kFSAA_Downsample == record->fDownsample) { 899 scale = 1; 900 GrIRect rect = SkIRect::MakeWH(tileRect.width(), tileRect.height()); 901 src->asRenderTarget()->overrideResolveRect(rect); 902 } else { 903 GrAssert(OffscreenRecord::k4x4SinglePass_Downsample == 904 record->fDownsample); 905 scale = 4; 906 } 907 908 // setup for draw back to main RT, we use the original 909 // draw state setup by the caller plus an additional coverage 910 // stage to handle the AA resolve. Also, we use an identity 911 // view matrix and so pre-concat sampler matrices with view inv. 912 int stageMask = paint.getActiveStageMask(); 913 914 target->restoreDrawState(record->fSavedState); 915 target->setClip(record->fClip); 916 917 if (stageMask) { 918 GrMatrix invVM; 919 if (drawState->getViewInverse(&invVM)) { 920 drawState->preConcatSamplerMatrices(stageMask, invVM); 921 } 922 } 923 // This is important when tiling, otherwise second tile's 924 // pass 1 view matrix will be incorrect. 925 GrDrawState::AutoViewMatrixRestore avmr(drawState, GrMatrix::I()); 926 927 drawState->setTexture(kOffscreenStage, src); 928 GrSamplerState* sampler = drawState->sampler(kOffscreenStage); 929 sampler->reset(GrSamplerState::kClamp_WrapMode, filter); 930 sampler->matrix()->setScale(scale * GR_Scalar1 / src->width(), 931 scale * GR_Scalar1 / src->height()); 932 sampler->matrix()->preTranslate(SkIntToScalar(-tileRect.fLeft), 933 SkIntToScalar(-tileRect.fTop)); 934 935 GrRect dstRect; 936 int stages = (1 << kOffscreenStage) | stageMask; 937 dstRect.set(tileRect); 938 target->drawSimpleRect(dstRect, NULL, stages); 939} 940 941void GrContext::cleanupOffscreenAA(GrDrawTarget* target, 942 GrPathRenderer* pr, 943 OffscreenRecord* record) { 944 target->restoreDrawState(record->fSavedState); 945} 946 947//////////////////////////////////////////////////////////////////////////////// 948 949/* create a triangle strip that strokes the specified triangle. There are 8 950 unique vertices, but we repreat the last 2 to close up. Alternatively we 951 could use an indices array, and then only send 8 verts, but not sure that 952 would be faster. 953 */ 954static void setStrokeRectStrip(GrPoint verts[10], GrRect rect, 955 GrScalar width) { 956 const GrScalar rad = GrScalarHalf(width); 957 rect.sort(); 958 959 verts[0].set(rect.fLeft + rad, rect.fTop + rad); 960 verts[1].set(rect.fLeft - rad, rect.fTop - rad); 961 verts[2].set(rect.fRight - rad, rect.fTop + rad); 962 verts[3].set(rect.fRight + rad, rect.fTop - rad); 963 verts[4].set(rect.fRight - rad, rect.fBottom - rad); 964 verts[5].set(rect.fRight + rad, rect.fBottom + rad); 965 verts[6].set(rect.fLeft + rad, rect.fBottom - rad); 966 verts[7].set(rect.fLeft - rad, rect.fBottom + rad); 967 verts[8] = verts[0]; 968 verts[9] = verts[1]; 969} 970 971static void setInsetFan(GrPoint* pts, size_t stride, 972 const GrRect& r, GrScalar dx, GrScalar dy) { 973 pts->setRectFan(r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride); 974} 975 976static const uint16_t gFillAARectIdx[] = { 977 0, 1, 5, 5, 4, 0, 978 1, 2, 6, 6, 5, 1, 979 2, 3, 7, 7, 6, 2, 980 3, 0, 4, 4, 7, 3, 981 4, 5, 6, 6, 7, 4, 982}; 983 984int GrContext::aaFillRectIndexCount() const { 985 return GR_ARRAY_COUNT(gFillAARectIdx); 986} 987 988GrIndexBuffer* GrContext::aaFillRectIndexBuffer() { 989 if (NULL == fAAFillRectIndexBuffer) { 990 fAAFillRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gFillAARectIdx), 991 false); 992 if (NULL != fAAFillRectIndexBuffer) { 993 #if GR_DEBUG 994 bool updated = 995 #endif 996 fAAFillRectIndexBuffer->updateData(gFillAARectIdx, 997 sizeof(gFillAARectIdx)); 998 GR_DEBUGASSERT(updated); 999 } 1000 } 1001 return fAAFillRectIndexBuffer; 1002} 1003 1004static const uint16_t gStrokeAARectIdx[] = { 1005 0 + 0, 1 + 0, 5 + 0, 5 + 0, 4 + 0, 0 + 0, 1006 1 + 0, 2 + 0, 6 + 0, 6 + 0, 5 + 0, 1 + 0, 1007 2 + 0, 3 + 0, 7 + 0, 7 + 0, 6 + 0, 2 + 0, 1008 3 + 0, 0 + 0, 4 + 0, 4 + 0, 7 + 0, 3 + 0, 1009 1010 0 + 4, 1 + 4, 5 + 4, 5 + 4, 4 + 4, 0 + 4, 1011 1 + 4, 2 + 4, 6 + 4, 6 + 4, 5 + 4, 1 + 4, 1012 2 + 4, 3 + 4, 7 + 4, 7 + 4, 6 + 4, 2 + 4, 1013 3 + 4, 0 + 4, 4 + 4, 4 + 4, 7 + 4, 3 + 4, 1014 1015 0 + 8, 1 + 8, 5 + 8, 5 + 8, 4 + 8, 0 + 8, 1016 1 + 8, 2 + 8, 6 + 8, 6 + 8, 5 + 8, 1 + 8, 1017 2 + 8, 3 + 8, 7 + 8, 7 + 8, 6 + 8, 2 + 8, 1018 3 + 8, 0 + 8, 4 + 8, 4 + 8, 7 + 8, 3 + 8, 1019}; 1020 1021int GrContext::aaStrokeRectIndexCount() const { 1022 return GR_ARRAY_COUNT(gStrokeAARectIdx); 1023} 1024 1025GrIndexBuffer* GrContext::aaStrokeRectIndexBuffer() { 1026 if (NULL == fAAStrokeRectIndexBuffer) { 1027 fAAStrokeRectIndexBuffer = fGpu->createIndexBuffer(sizeof(gStrokeAARectIdx), 1028 false); 1029 if (NULL != fAAStrokeRectIndexBuffer) { 1030 #if GR_DEBUG 1031 bool updated = 1032 #endif 1033 fAAStrokeRectIndexBuffer->updateData(gStrokeAARectIdx, 1034 sizeof(gStrokeAARectIdx)); 1035 GR_DEBUGASSERT(updated); 1036 } 1037 } 1038 return fAAStrokeRectIndexBuffer; 1039} 1040 1041static GrVertexLayout aa_rect_layout(const GrDrawTarget* target, 1042 bool useCoverage) { 1043 GrVertexLayout layout = 0; 1044 for (int s = 0; s < GrDrawState::kNumStages; ++s) { 1045 if (NULL != target->getDrawState().getTexture(s)) { 1046 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); 1047 } 1048 } 1049 if (useCoverage) { 1050 layout |= GrDrawTarget::kCoverage_VertexLayoutBit; 1051 } else { 1052 layout |= GrDrawTarget::kColor_VertexLayoutBit; 1053 } 1054 return layout; 1055} 1056 1057void GrContext::fillAARect(GrDrawTarget* target, 1058 const GrRect& devRect, 1059 bool useVertexCoverage) { 1060 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage); 1061 1062 size_t vsize = GrDrawTarget::VertexSize(layout); 1063 1064 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 8, 0); 1065 if (!geo.succeeded()) { 1066 GrPrintf("Failed to get space for vertices!\n"); 1067 return; 1068 } 1069 GrIndexBuffer* indexBuffer = this->aaFillRectIndexBuffer(); 1070 if (NULL == indexBuffer) { 1071 GrPrintf("Failed to create index buffer!\n"); 1072 return; 1073 } 1074 1075 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 1076 1077 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 1078 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 1079 1080 setInsetFan(fan0Pos, vsize, devRect, -GR_ScalarHalf, -GR_ScalarHalf); 1081 setInsetFan(fan1Pos, vsize, devRect, GR_ScalarHalf, GR_ScalarHalf); 1082 1083 verts += sizeof(GrPoint); 1084 for (int i = 0; i < 4; ++i) { 1085 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 1086 } 1087 1088 GrColor innerColor; 1089 if (useVertexCoverage) { 1090 innerColor = 0xffffffff; 1091 } else { 1092 innerColor = target->getDrawState().getColor(); 1093 } 1094 1095 verts += 4 * vsize; 1096 for (int i = 0; i < 4; ++i) { 1097 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 1098 } 1099 1100 target->setIndexSourceToBuffer(indexBuffer); 1101 1102 target->drawIndexed(kTriangles_PrimitiveType, 0, 1103 0, 8, this->aaFillRectIndexCount()); 1104} 1105 1106void GrContext::strokeAARect(GrDrawTarget* target, 1107 const GrRect& devRect, 1108 const GrVec& devStrokeSize, 1109 bool useVertexCoverage) { 1110 const GrScalar& dx = devStrokeSize.fX; 1111 const GrScalar& dy = devStrokeSize.fY; 1112 const GrScalar rx = GrMul(dx, GR_ScalarHalf); 1113 const GrScalar ry = GrMul(dy, GR_ScalarHalf); 1114 1115 GrScalar spare; 1116 { 1117 GrScalar w = devRect.width() - dx; 1118 GrScalar h = devRect.height() - dy; 1119 spare = GrMin(w, h); 1120 } 1121 1122 if (spare <= 0) { 1123 GrRect r(devRect); 1124 r.inset(-rx, -ry); 1125 fillAARect(target, r, useVertexCoverage); 1126 return; 1127 } 1128 GrVertexLayout layout = aa_rect_layout(target, useVertexCoverage); 1129 size_t vsize = GrDrawTarget::VertexSize(layout); 1130 1131 GrDrawTarget::AutoReleaseGeometry geo(target, layout, 16, 0); 1132 if (!geo.succeeded()) { 1133 GrPrintf("Failed to get space for vertices!\n"); 1134 return; 1135 } 1136 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(); 1137 if (NULL == indexBuffer) { 1138 GrPrintf("Failed to create index buffer!\n"); 1139 return; 1140 } 1141 1142 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); 1143 1144 GrPoint* fan0Pos = reinterpret_cast<GrPoint*>(verts); 1145 GrPoint* fan1Pos = reinterpret_cast<GrPoint*>(verts + 4 * vsize); 1146 GrPoint* fan2Pos = reinterpret_cast<GrPoint*>(verts + 8 * vsize); 1147 GrPoint* fan3Pos = reinterpret_cast<GrPoint*>(verts + 12 * vsize); 1148 1149 setInsetFan(fan0Pos, vsize, devRect, -rx - GR_ScalarHalf, -ry - GR_ScalarHalf); 1150 setInsetFan(fan1Pos, vsize, devRect, -rx + GR_ScalarHalf, -ry + GR_ScalarHalf); 1151 setInsetFan(fan2Pos, vsize, devRect, rx - GR_ScalarHalf, ry - GR_ScalarHalf); 1152 setInsetFan(fan3Pos, vsize, devRect, rx + GR_ScalarHalf, ry + GR_ScalarHalf); 1153 1154 verts += sizeof(GrPoint); 1155 for (int i = 0; i < 4; ++i) { 1156 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 1157 } 1158 1159 GrColor innerColor; 1160 if (useVertexCoverage) { 1161 innerColor = 0xffffffff; 1162 } else { 1163 innerColor = target->getDrawState().getColor(); 1164 } 1165 verts += 4 * vsize; 1166 for (int i = 0; i < 8; ++i) { 1167 *reinterpret_cast<GrColor*>(verts + i * vsize) = innerColor; 1168 } 1169 1170 verts += 8 * vsize; 1171 for (int i = 0; i < 8; ++i) { 1172 *reinterpret_cast<GrColor*>(verts + i * vsize) = 0; 1173 } 1174 1175 target->setIndexSourceToBuffer(indexBuffer); 1176 target->drawIndexed(kTriangles_PrimitiveType, 1177 0, 0, 16, aaStrokeRectIndexCount()); 1178} 1179 1180/** 1181 * Returns true if the rects edges are integer-aligned. 1182 */ 1183static bool isIRect(const GrRect& r) { 1184 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) && 1185 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom); 1186} 1187 1188static bool apply_aa_to_rect(GrDrawTarget* target, 1189 const GrRect& rect, 1190 GrScalar width, 1191 const GrMatrix* matrix, 1192 GrMatrix* combinedMatrix, 1193 GrRect* devRect, 1194 bool* useVertexCoverage) { 1195 // we use a simple alpha ramp to do aa on axis-aligned rects 1196 // do AA with alpha ramp if the caller requested AA, the rect 1197 // will be axis-aligned, and the rect won't land on integer coords. 1198 1199 // we are keeping around the "tweak the alpha" trick because 1200 // it is our only hope for the fixed-pipe implementation. 1201 // In a shader implementation we can give a separate coverage input 1202 // TODO: remove this ugliness when we drop the fixed-pipe impl 1203 *useVertexCoverage = false; 1204 if (!target->canTweakAlphaForCoverage()) { 1205 if (target->getCaps().fSupportPerVertexCoverage) { 1206 if (disable_coverage_aa_for_blend(target)) { 1207#if GR_DEBUG 1208 //GrPrintf("Turning off AA to correctly apply blend.\n"); 1209#endif 1210 return false; 1211 } else { 1212 *useVertexCoverage = true; 1213 } 1214 } else { 1215 GrPrintf("Rect AA dropped because no support for coverage.\n"); 1216 return false; 1217 } 1218 } 1219 const GrDrawState& drawState = target->getDrawState(); 1220 if (drawState.getRenderTarget()->isMultisampled()) { 1221 return false; 1222 } 1223 1224 if (0 == width && target->willUseHWAALines()) { 1225 return false; 1226 } 1227 1228 if (!drawState.getViewMatrix().preservesAxisAlignment()) { 1229 return false; 1230 } 1231 1232 if (NULL != matrix && 1233 !matrix->preservesAxisAlignment()) { 1234 return false; 1235 } 1236 1237 *combinedMatrix = drawState.getViewMatrix(); 1238 if (NULL != matrix) { 1239 combinedMatrix->preConcat(*matrix); 1240 GrAssert(combinedMatrix->preservesAxisAlignment()); 1241 } 1242 1243 combinedMatrix->mapRect(devRect, rect); 1244 devRect->sort(); 1245 1246 if (width < 0) { 1247 return !isIRect(*devRect); 1248 } else { 1249 return true; 1250 } 1251} 1252 1253void GrContext::drawRect(const GrPaint& paint, 1254 const GrRect& rect, 1255 GrScalar width, 1256 const GrMatrix* matrix) { 1257 SK_TRACE_EVENT0("GrContext::drawRect"); 1258 1259 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1260 int stageMask = paint.getActiveStageMask(); 1261 1262 GrRect devRect = rect; 1263 GrMatrix combinedMatrix; 1264 bool useVertexCoverage; 1265 bool needAA = paint.fAntiAlias && 1266 !this->getRenderTarget()->isMultisampled(); 1267 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, 1268 &combinedMatrix, &devRect, 1269 &useVertexCoverage); 1270 1271 if (doAA) { 1272 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask); 1273 if (width >= 0) { 1274 GrVec strokeSize;; 1275 if (width > 0) { 1276 strokeSize.set(width, width); 1277 combinedMatrix.mapVectors(&strokeSize, 1); 1278 strokeSize.setAbs(strokeSize); 1279 } else { 1280 strokeSize.set(GR_Scalar1, GR_Scalar1); 1281 } 1282 strokeAARect(target, devRect, strokeSize, useVertexCoverage); 1283 } else { 1284 fillAARect(target, devRect, useVertexCoverage); 1285 } 1286 return; 1287 } 1288 1289 if (width >= 0) { 1290 // TODO: consider making static vertex buffers for these cases. 1291 // Hairline could be done by just adding closing vertex to 1292 // unitSquareVertexBuffer() 1293 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1294 1295 static const int worstCaseVertCount = 10; 1296 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); 1297 1298 if (!geo.succeeded()) { 1299 GrPrintf("Failed to get space for vertices!\n"); 1300 return; 1301 } 1302 1303 GrPrimitiveType primType; 1304 int vertCount; 1305 GrPoint* vertex = geo.positions(); 1306 1307 if (width > 0) { 1308 vertCount = 10; 1309 primType = kTriangleStrip_PrimitiveType; 1310 setStrokeRectStrip(vertex, rect, width); 1311 } else { 1312 // hairline 1313 vertCount = 5; 1314 primType = kLineStrip_PrimitiveType; 1315 vertex[0].set(rect.fLeft, rect.fTop); 1316 vertex[1].set(rect.fRight, rect.fTop); 1317 vertex[2].set(rect.fRight, rect.fBottom); 1318 vertex[3].set(rect.fLeft, rect.fBottom); 1319 vertex[4].set(rect.fLeft, rect.fTop); 1320 } 1321 1322 GrDrawState::AutoViewMatrixRestore avmr; 1323 if (NULL != matrix) { 1324 GrDrawState* drawState = target->drawState(); 1325 avmr.set(drawState); 1326 drawState->preConcatViewMatrix(*matrix); 1327 drawState->preConcatSamplerMatrices(stageMask, *matrix); 1328 } 1329 1330 target->drawNonIndexed(primType, 0, vertCount); 1331 } else { 1332#if GR_STATIC_RECT_VB 1333 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1334 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 1335 if (NULL == sqVB) { 1336 GrPrintf("Failed to create static rect vb.\n"); 1337 return; 1338 } 1339 target->setVertexSourceToBuffer(layout, sqVB); 1340 GrDrawState* drawState = target->drawState(); 1341 GrDrawState::AutoViewMatrixRestore avmr(drawState); 1342 GrMatrix m; 1343 m.setAll(rect.width(), 0, rect.fLeft, 1344 0, rect.height(), rect.fTop, 1345 0, 0, GrMatrix::I()[8]); 1346 1347 if (NULL != matrix) { 1348 m.postConcat(*matrix); 1349 } 1350 drawState->preConcatViewMatrix(m); 1351 drawState->preConcatSamplerMatrices(stageMask, m); 1352 1353 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1354#else 1355 target->drawSimpleRect(rect, matrix, stageMask); 1356#endif 1357 } 1358} 1359 1360void GrContext::drawRectToRect(const GrPaint& paint, 1361 const GrRect& dstRect, 1362 const GrRect& srcRect, 1363 const GrMatrix* dstMatrix, 1364 const GrMatrix* srcMatrix) { 1365 SK_TRACE_EVENT0("GrContext::drawRectToRect"); 1366 1367 // srcRect refers to paint's first texture 1368 if (NULL == paint.getTexture(0)) { 1369 drawRect(paint, dstRect, -1, dstMatrix); 1370 return; 1371 } 1372 1373 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB); 1374 1375#if GR_STATIC_RECT_VB 1376 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1377 GrDrawState* drawState = target->drawState(); 1378 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1379 GrDrawState::AutoViewMatrixRestore avmr(drawState); 1380 1381 GrMatrix m; 1382 1383 m.setAll(dstRect.width(), 0, dstRect.fLeft, 1384 0, dstRect.height(), dstRect.fTop, 1385 0, 0, GrMatrix::I()[8]); 1386 if (NULL != dstMatrix) { 1387 m.postConcat(*dstMatrix); 1388 } 1389 drawState->preConcatViewMatrix(m); 1390 1391 // srcRect refers to first stage 1392 int otherStageMask = paint.getActiveStageMask() & 1393 (~(1 << GrPaint::kFirstTextureStage)); 1394 if (otherStageMask) { 1395 drawState->preConcatSamplerMatrices(otherStageMask, m); 1396 } 1397 1398 m.setAll(srcRect.width(), 0, srcRect.fLeft, 1399 0, srcRect.height(), srcRect.fTop, 1400 0, 0, GrMatrix::I()[8]); 1401 if (NULL != srcMatrix) { 1402 m.postConcat(*srcMatrix); 1403 } 1404 drawState->sampler(GrPaint::kFirstTextureStage)->preConcatMatrix(m); 1405 1406 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 1407 if (NULL == sqVB) { 1408 GrPrintf("Failed to create static rect vb.\n"); 1409 return; 1410 } 1411 target->setVertexSourceToBuffer(layout, sqVB); 1412 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1413#else 1414 1415 GrDrawTarget* target; 1416#if BATCH_RECT_TO_RECT 1417 target = this->prepareToDraw(paint, kBuffered_DrawCategory); 1418#else 1419 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1420#endif 1421 1422 const GrRect* srcRects[GrDrawState::kNumStages] = {NULL}; 1423 const GrMatrix* srcMatrices[GrDrawState::kNumStages] = {NULL}; 1424 srcRects[0] = &srcRect; 1425 srcMatrices[0] = srcMatrix; 1426 1427 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices); 1428#endif 1429} 1430 1431void GrContext::drawVertices(const GrPaint& paint, 1432 GrPrimitiveType primitiveType, 1433 int vertexCount, 1434 const GrPoint positions[], 1435 const GrPoint texCoords[], 1436 const GrColor colors[], 1437 const uint16_t indices[], 1438 int indexCount) { 1439 SK_TRACE_EVENT0("GrContext::drawVertices"); 1440 1441 GrDrawTarget::AutoReleaseGeometry geo; 1442 1443 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1444 1445 bool hasTexCoords[GrPaint::kTotalStages] = { 1446 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords 1447 0 // remaining stages use positions 1448 }; 1449 1450 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords); 1451 1452 if (NULL != colors) { 1453 layout |= GrDrawTarget::kColor_VertexLayoutBit; 1454 } 1455 int vertexSize = GrDrawTarget::VertexSize(layout); 1456 1457 if (sizeof(GrPoint) != vertexSize) { 1458 if (!geo.set(target, layout, vertexCount, 0)) { 1459 GrPrintf("Failed to get space for vertices!\n"); 1460 return; 1461 } 1462 int texOffsets[GrDrawState::kMaxTexCoords]; 1463 int colorOffset; 1464 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout, 1465 texOffsets, 1466 &colorOffset, 1467 NULL, 1468 NULL); 1469 void* curVertex = geo.vertices(); 1470 1471 for (int i = 0; i < vertexCount; ++i) { 1472 *((GrPoint*)curVertex) = positions[i]; 1473 1474 if (texOffsets[0] > 0) { 1475 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i]; 1476 } 1477 if (colorOffset > 0) { 1478 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i]; 1479 } 1480 curVertex = (void*)((intptr_t)curVertex + vertexSize); 1481 } 1482 } else { 1483 target->setVertexSourceToArray(layout, positions, vertexCount); 1484 } 1485 1486 // we don't currently apply offscreen AA to this path. Need improved 1487 // management of GrDrawTarget's geometry to avoid copying points per-tile. 1488 1489 if (NULL != indices) { 1490 target->setIndexSourceToArray(indices, indexCount); 1491 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); 1492 } else { 1493 target->drawNonIndexed(primitiveType, 0, vertexCount); 1494 } 1495} 1496 1497/////////////////////////////////////////////////////////////////////////////// 1498 1499void GrContext::drawPath(const GrPaint& paint, const GrPath& path, 1500 GrPathFill fill, const GrPoint* translate) { 1501 1502 if (path.isEmpty()) { 1503 if (GrIsFillInverted(fill)) { 1504 this->drawPaint(paint); 1505 } 1506 return; 1507 } 1508 1509 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1510 1511 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled(); 1512 1513 // An Assumption here is that path renderer would use some form of tweaking 1514 // the src color (either the input alpha or in the frag shader) to implement 1515 // aa. If we have some future driver-mojo path AA that can do the right 1516 // thing WRT to the blend then we'll need some query on the PR. 1517 if (disable_coverage_aa_for_blend(target)) { 1518#if GR_DEBUG 1519 //GrPrintf("Turning off AA to correctly apply blend.\n"); 1520#endif 1521 prAA = false; 1522 } 1523 1524 bool doOSAA = false; 1525 GrPathRenderer* pr = NULL; 1526 if (prAA) { 1527 pr = this->getPathRenderer(path, fill, true); 1528 if (NULL == pr) { 1529 prAA = false; 1530 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill); 1531 pr = this->getPathRenderer(path, fill, false); 1532 } 1533 } else { 1534 pr = this->getPathRenderer(path, fill, false); 1535 } 1536 1537 if (NULL == pr) { 1538#if GR_DEBUG 1539 GrPrintf("Unable to find path renderer compatible with path.\n"); 1540#endif 1541 return; 1542 } 1543 1544 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate); 1545 GrDrawState::StageMask stageMask = paint.getActiveStageMask(); 1546 1547 if (doOSAA) { 1548 bool needsStencil = pr->requiresStencilPass(target, path, fill); 1549 const GrRenderTarget* rt = target->getDrawState().getRenderTarget(); 1550 // compute bounds as intersection of rt size, clip, and path 1551 GrIRect bound = SkIRect::MakeWH(rt->width(), rt->height()); 1552 GrIRect clipIBounds; 1553 if (target->getClip().hasConservativeBounds()) { 1554 target->getClip().getConservativeBounds().roundOut(&clipIBounds); 1555 if (!bound.intersect(clipIBounds)) { 1556 return; 1557 } 1558 } 1559 GrRect pathBounds = path.getBounds(); 1560 if (!pathBounds.isEmpty()) { 1561 if (NULL != translate) { 1562 pathBounds.offset(*translate); 1563 } 1564 target->getDrawState().getViewMatrix().mapRect(&pathBounds, 1565 pathBounds); 1566 GrIRect pathIBounds; 1567 pathBounds.roundOut(&pathIBounds); 1568 if (!bound.intersect(pathIBounds)) { 1569 return; 1570 } 1571 } 1572 OffscreenRecord record; 1573 if (this->prepareForOffscreenAA(target, needsStencil, bound, 1574 pr, &record)) { 1575 for (int tx = 0; tx < record.fTileCountX; ++tx) { 1576 for (int ty = 0; ty < record.fTileCountY; ++ty) { 1577 this->setupOffscreenAAPass1(target, bound, tx, ty, &record); 1578 pr->drawPath(0); 1579 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record); 1580 } 1581 } 1582 this->cleanupOffscreenAA(target, pr, &record); 1583 if (GrIsFillInverted(fill) && bound != clipIBounds) { 1584 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask); 1585 GrRect rect; 1586 if (clipIBounds.fTop < bound.fTop) { 1587 rect.iset(clipIBounds.fLeft, clipIBounds.fTop, 1588 clipIBounds.fRight, bound.fTop); 1589 target->drawSimpleRect(rect, NULL, stageMask); 1590 } 1591 if (clipIBounds.fLeft < bound.fLeft) { 1592 rect.iset(clipIBounds.fLeft, bound.fTop, 1593 bound.fLeft, bound.fBottom); 1594 target->drawSimpleRect(rect, NULL, stageMask); 1595 } 1596 if (clipIBounds.fRight > bound.fRight) { 1597 rect.iset(bound.fRight, bound.fTop, 1598 clipIBounds.fRight, bound.fBottom); 1599 target->drawSimpleRect(rect, NULL, stageMask); 1600 } 1601 if (clipIBounds.fBottom > bound.fBottom) { 1602 rect.iset(clipIBounds.fLeft, bound.fBottom, 1603 clipIBounds.fRight, clipIBounds.fBottom); 1604 target->drawSimpleRect(rect, NULL, stageMask); 1605 } 1606 } 1607 return; 1608 } 1609 } 1610 pr->drawPath(stageMask); 1611} 1612 1613//////////////////////////////////////////////////////////////////////////////// 1614 1615bool GrContext::supportsShaders() const { 1616 return fGpu->getCaps().fShaderSupport; 1617} 1618 1619void GrContext::flush(int flagsBitfield) { 1620 if (kDiscard_FlushBit & flagsBitfield) { 1621 fDrawBuffer->reset(); 1622 } else { 1623 this->flushDrawBuffer(); 1624 } 1625 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) { 1626 fGpu->forceRenderTargetFlush(); 1627 } 1628} 1629 1630void GrContext::flushText() { 1631 if (kText_DrawCategory == fLastDrawCategory) { 1632 flushDrawBuffer(); 1633 } 1634} 1635 1636void GrContext::flushDrawBuffer() { 1637#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING 1638 if (fDrawBuffer) { 1639 fDrawBuffer->playback(fGpu); 1640 fDrawBuffer->reset(); 1641 } 1642#endif 1643} 1644 1645void GrContext::internalWriteTexturePixels(GrTexture* texture, 1646 int left, int top, 1647 int width, int height, 1648 GrPixelConfig config, 1649 const void* buffer, 1650 size_t rowBytes, 1651 uint32_t flags) { 1652 SK_TRACE_EVENT0("GrContext::writeTexturePixels"); 1653 ASSERT_OWNED_RESOURCE(texture); 1654 1655 if (!(kDontFlush_PixelOpsFlag & flags)) { 1656 this->flush(); 1657 } 1658 // TODO: use scratch texture to perform conversion 1659 if (GrPixelConfigIsUnpremultiplied(texture->config()) != 1660 GrPixelConfigIsUnpremultiplied(config)) { 1661 return; 1662 } 1663 1664 fGpu->writeTexturePixels(texture, left, top, width, height, 1665 config, buffer, rowBytes); 1666} 1667 1668bool GrContext::internalReadTexturePixels(GrTexture* texture, 1669 int left, int top, 1670 int width, int height, 1671 GrPixelConfig config, 1672 void* buffer, 1673 size_t rowBytes, 1674 uint32_t flags) { 1675 SK_TRACE_EVENT0("GrContext::readTexturePixels"); 1676 ASSERT_OWNED_RESOURCE(texture); 1677 1678 // TODO: code read pixels for textures that aren't also rendertargets 1679 GrRenderTarget* target = texture->asRenderTarget(); 1680 if (NULL != target) { 1681 return this->internalReadRenderTargetPixels(target, 1682 left, top, width, height, 1683 config, buffer, rowBytes, 1684 flags); 1685 } else { 1686 return false; 1687 } 1688} 1689 1690bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target, 1691 int left, int top, 1692 int width, int height, 1693 GrPixelConfig config, 1694 void* buffer, 1695 size_t rowBytes, 1696 uint32_t flags) { 1697 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels"); 1698 ASSERT_OWNED_RESOURCE(target); 1699 1700 if (NULL == target) { 1701 target = fGpu->drawState()->getRenderTarget(); 1702 if (NULL == target) { 1703 return false; 1704 } 1705 } 1706 1707 // PM <-> UPM conversion requires a draw. Currently we only support drawing 1708 // into a UPM target, not reading from a UPM texture. Thus, UPM->PM is not 1709 // not supported at this time. 1710 if (GrPixelConfigIsUnpremultiplied(target->config()) && 1711 !GrPixelConfigIsUnpremultiplied(config)) { 1712 return false; 1713 } 1714 1715 if (!(kDontFlush_PixelOpsFlag & flags)) { 1716 this->flush(); 1717 } 1718 1719 GrTexture* src = target->asTexture(); 1720 bool swapRAndB = NULL != src && 1721 fGpu->preferredReadPixelsConfig(config) == 1722 GrPixelConfigSwapRAndB(config); 1723 1724 bool flipY = NULL != src && 1725 fGpu->readPixelsWillPayForYFlip(target, left, top, 1726 width, height, config, 1727 rowBytes); 1728 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) && 1729 GrPixelConfigIsUnpremultiplied(config)); 1730 1731 if (NULL == src && alphaConversion) { 1732 // we should fallback to cpu conversion here. This could happen when 1733 // we were given an external render target by the client that is not 1734 // also a texture (e.g. FBO 0 in GL) 1735 return false; 1736 } 1737 // we draw to a scratch texture if any of these conversion are applied 1738 GrAutoScratchTexture ast; 1739 if (flipY || swapRAndB || alphaConversion) { 1740 GrAssert(NULL != src); 1741 if (swapRAndB) { 1742 config = GrPixelConfigSwapRAndB(config); 1743 GrAssert(kUnknown_GrPixelConfig != config); 1744 } 1745 // Make the scratch a render target because we don't have a robust 1746 // readTexturePixels as of yet (it calls this function). 1747 const GrTextureDesc desc = { 1748 kRenderTarget_GrTextureFlagBit, 1749 kNone_GrAALevel, 1750 width, height, 1751 config 1752 }; 1753 1754 // When a full readback is faster than a partial we could always make 1755 // the scratch exactly match the passed rect. However, if we see many 1756 // different size rectangles we will trash our texture cache and pay the 1757 // cost of creating and destroying many textures. So, we only request 1758 // an exact match when the caller is reading an entire RT. 1759 ScratchTexMatch match = kApprox_ScratchTexMatch; 1760 if (0 == left && 1761 0 == top && 1762 target->width() == width && 1763 target->height() == height && 1764 fGpu->fullReadPixelsIsFasterThanPartial()) { 1765 match = kExact_ScratchTexMatch; 1766 } 1767 ast.set(this, desc, match); 1768 GrTexture* texture = ast.texture(); 1769 if (!texture) { 1770 return false; 1771 } 1772 target = texture->asRenderTarget(); 1773 GrAssert(NULL != target); 1774 1775 GrDrawTarget::AutoStateRestore asr(fGpu); 1776 GrDrawState* drawState = fGpu->drawState(); 1777 reset_draw_state(drawState); 1778 drawState->setRenderTarget(target); 1779 1780 GrMatrix matrix; 1781 if (flipY) { 1782 matrix.setTranslate(SK_Scalar1 * left, 1783 SK_Scalar1 * (top + height)); 1784 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1); 1785 } else { 1786 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); 1787 } 1788 matrix.postIDiv(src->width(), src->height()); 1789 drawState->sampler(0)->reset(matrix); 1790 drawState->sampler(0)->setRAndBSwap(swapRAndB); 1791 drawState->setTexture(0, src); 1792 GrRect rect; 1793 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height); 1794 fGpu->drawSimpleRect(rect, NULL, 0x1); 1795 left = 0; 1796 top = 0; 1797 } 1798 return fGpu->readPixels(target, 1799 left, top, width, height, 1800 config, buffer, rowBytes, flipY); 1801} 1802 1803void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) { 1804 if (NULL == src || NULL == dst) { 1805 return; 1806 } 1807 ASSERT_OWNED_RESOURCE(src); 1808 1809 GrDrawTarget::AutoStateRestore asr(fGpu); 1810 GrDrawState* drawState = fGpu->drawState(); 1811 reset_draw_state(drawState); 1812 drawState->setRenderTarget(dst); 1813 GrMatrix sampleM; 1814 sampleM.setIDiv(src->width(), src->height()); 1815 drawState->setTexture(0, src); 1816 drawState->sampler(0)->reset(sampleM); 1817 SkRect rect = SkRect::MakeXYWH(0, 0, src->width(), src->height()); 1818 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 1819} 1820 1821void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target, 1822 int left, int top, 1823 int width, int height, 1824 GrPixelConfig config, 1825 const void* buffer, 1826 size_t rowBytes, 1827 uint32_t flags) { 1828 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels"); 1829 ASSERT_OWNED_RESOURCE(target); 1830 1831 if (NULL == target) { 1832 target = fGpu->drawState()->getRenderTarget(); 1833 if (NULL == target) { 1834 return; 1835 } 1836 } 1837 1838 // TODO: when underlying api has a direct way to do this we should use it 1839 // (e.g. glDrawPixels on desktop GL). 1840 1841 // If the RT is also a texture and we don't have to do PM/UPM conversion 1842 // then take the texture path, which we expect to be at least as fast or 1843 // faster since it doesn't use an intermediate texture as we do below. 1844 1845#if !GR_MAC_BUILD 1846 // At least some drivers on the Mac get confused when glTexImage2D is called 1847 // on a texture attached to an FBO. The FBO still sees the old image. TODO: 1848 // determine what OS versions and/or HW is affected. 1849 if (NULL != target->asTexture() && 1850 GrPixelConfigIsUnpremultiplied(target->config()) == 1851 GrPixelConfigIsUnpremultiplied(config)) { 1852 1853 this->internalWriteTexturePixels(target->asTexture(), 1854 left, top, width, height, 1855 config, buffer, rowBytes, flags); 1856 return; 1857 } 1858#endif 1859 1860 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) == 1861 GrPixelConfigSwapRAndB(config); 1862 if (swapRAndB) { 1863 config = GrPixelConfigSwapRAndB(config); 1864 } 1865 1866 const GrTextureDesc desc = { 1867 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config 1868 }; 1869 GrAutoScratchTexture ast(this, desc); 1870 GrTexture* texture = ast.texture(); 1871 if (NULL == texture) { 1872 return; 1873 } 1874 this->internalWriteTexturePixels(texture, 0, 0, width, height, 1875 config, buffer, rowBytes, flags); 1876 1877 GrDrawTarget::AutoStateRestore asr(fGpu); 1878 GrDrawState* drawState = fGpu->drawState(); 1879 reset_draw_state(drawState); 1880 1881 GrMatrix matrix; 1882 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); 1883 drawState->setViewMatrix(matrix); 1884 drawState->setRenderTarget(target); 1885 drawState->setTexture(0, texture); 1886 1887 matrix.setIDiv(texture->width(), texture->height()); 1888 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 1889 GrSamplerState::kNearest_Filter, 1890 matrix); 1891 drawState->sampler(0)->setRAndBSwap(swapRAndB); 1892 1893 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); 1894 static const int VCOUNT = 4; 1895 // TODO: Use GrGpu::drawRect here 1896 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0); 1897 if (!geo.succeeded()) { 1898 GrPrintf("Failed to get space for vertices!\n"); 1899 return; 1900 } 1901 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height); 1902 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT); 1903} 1904//////////////////////////////////////////////////////////////////////////////// 1905 1906void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) { 1907 GrDrawState* drawState = target->drawState(); 1908 1909 for (int i = 0; i < GrPaint::kMaxTextures; ++i) { 1910 int s = i + GrPaint::kFirstTextureStage; 1911 drawState->setTexture(s, paint.getTexture(i)); 1912 ASSERT_OWNED_RESOURCE(paint.getTexture(i)); 1913 if (paint.getTexture(i)) { 1914 *drawState->sampler(s) = paint.getTextureSampler(i); 1915 } 1916 } 1917 1918 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage); 1919 1920 for (int i = 0; i < GrPaint::kMaxMasks; ++i) { 1921 int s = i + GrPaint::kFirstMaskStage; 1922 drawState->setTexture(s, paint.getMask(i)); 1923 ASSERT_OWNED_RESOURCE(paint.getMask(i)); 1924 if (paint.getMask(i)) { 1925 *drawState->sampler(s) = paint.getMaskSampler(i); 1926 } 1927 } 1928 1929 drawState->setColor(paint.fColor); 1930 1931 if (paint.fDither) { 1932 drawState->enableState(GrDrawState::kDither_StateBit); 1933 } else { 1934 drawState->disableState(GrDrawState::kDither_StateBit); 1935 } 1936 if (paint.fAntiAlias) { 1937 drawState->enableState(GrDrawState::kHWAntialias_StateBit); 1938 } else { 1939 drawState->disableState(GrDrawState::kHWAntialias_StateBit); 1940 } 1941 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); 1942 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); 1943 1944 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) { 1945 GrPrintf("Partial pixel coverage will be incorrectly blended.\n"); 1946 } 1947} 1948 1949GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, 1950 DrawCategory category) { 1951 if (category != fLastDrawCategory) { 1952 flushDrawBuffer(); 1953 fLastDrawCategory = category; 1954 } 1955 this->setPaint(paint, fGpu); 1956 GrDrawTarget* target = fGpu; 1957 switch (category) { 1958 case kText_DrawCategory: 1959#if DEFER_TEXT_RENDERING 1960 target = fDrawBuffer; 1961 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1962#else 1963 target = fGpu; 1964#endif 1965 break; 1966 case kUnbuffered_DrawCategory: 1967 target = fGpu; 1968 break; 1969 case kBuffered_DrawCategory: 1970 target = fDrawBuffer; 1971 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1972 break; 1973 } 1974 return target; 1975} 1976 1977GrPathRenderer* GrContext::getPathRenderer(const GrPath& path, 1978 GrPathFill fill, 1979 bool antiAlias) { 1980 if (NULL == fPathRendererChain) { 1981 fPathRendererChain = 1982 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag); 1983 } 1984 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path, 1985 fill, antiAlias); 1986} 1987 1988//////////////////////////////////////////////////////////////////////////////// 1989 1990void GrContext::setRenderTarget(GrRenderTarget* target) { 1991 ASSERT_OWNED_RESOURCE(target); 1992 this->flush(false); 1993 fGpu->drawState()->setRenderTarget(target); 1994} 1995 1996GrRenderTarget* GrContext::getRenderTarget() { 1997 return fGpu->drawState()->getRenderTarget(); 1998} 1999 2000const GrRenderTarget* GrContext::getRenderTarget() const { 2001 return fGpu->getDrawState().getRenderTarget(); 2002} 2003 2004const GrMatrix& GrContext::getMatrix() const { 2005 return fGpu->getDrawState().getViewMatrix(); 2006} 2007 2008void GrContext::setMatrix(const GrMatrix& m) { 2009 fGpu->drawState()->setViewMatrix(m); 2010} 2011 2012void GrContext::concatMatrix(const GrMatrix& m) const { 2013 fGpu->drawState()->preConcatViewMatrix(m); 2014} 2015 2016static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { 2017 intptr_t mask = 1 << shift; 2018 if (pred) { 2019 bits |= mask; 2020 } else { 2021 bits &= ~mask; 2022 } 2023 return bits; 2024} 2025 2026void GrContext::resetStats() { 2027 fGpu->resetStats(); 2028} 2029 2030const GrGpuStats& GrContext::getStats() const { 2031 return fGpu->getStats(); 2032} 2033 2034void GrContext::printStats() const { 2035 fGpu->printStats(); 2036} 2037 2038GrContext::GrContext(GrGpu* gpu) { 2039 fGpu = gpu; 2040 fGpu->ref(); 2041 fGpu->setContext(this); 2042 2043 fPathRendererChain = NULL; 2044 2045 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT, 2046 MAX_TEXTURE_CACHE_BYTES); 2047 fFontCache = new GrFontCache(fGpu); 2048 2049 fLastDrawCategory = kUnbuffered_DrawCategory; 2050 2051 fDrawBuffer = NULL; 2052 fDrawBufferVBAllocPool = NULL; 2053 fDrawBufferIBAllocPool = NULL; 2054 2055 fAAFillRectIndexBuffer = NULL; 2056 fAAStrokeRectIndexBuffer = NULL; 2057 2058 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize; 2059 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) { 2060 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE; 2061 } 2062 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen); 2063 2064 this->setupDrawBuffer(); 2065} 2066 2067void GrContext::setupDrawBuffer() { 2068 2069 GrAssert(NULL == fDrawBuffer); 2070 GrAssert(NULL == fDrawBufferVBAllocPool); 2071 GrAssert(NULL == fDrawBufferIBAllocPool); 2072 2073#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT 2074 fDrawBufferVBAllocPool = 2075 new GrVertexBufferAllocPool(fGpu, false, 2076 DRAW_BUFFER_VBPOOL_BUFFER_SIZE, 2077 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS); 2078 fDrawBufferIBAllocPool = 2079 new GrIndexBufferAllocPool(fGpu, false, 2080 DRAW_BUFFER_IBPOOL_BUFFER_SIZE, 2081 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS); 2082 2083 fDrawBuffer = new GrInOrderDrawBuffer(fGpu, 2084 fDrawBufferVBAllocPool, 2085 fDrawBufferIBAllocPool); 2086#endif 2087 2088#if BATCH_RECT_TO_RECT 2089 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer()); 2090#endif 2091} 2092 2093GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { 2094 GrDrawTarget* target; 2095#if DEFER_TEXT_RENDERING 2096 target = prepareToDraw(paint, kText_DrawCategory); 2097#else 2098 target = prepareToDraw(paint, kUnbuffered_DrawCategory); 2099#endif 2100 this->setPaint(paint, target); 2101 return target; 2102} 2103 2104const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { 2105 return fGpu->getQuadIndexBuffer(); 2106} 2107 2108void GrContext::convolveInX(GrTexture* texture, 2109 const SkRect& rect, 2110 const float* kernel, 2111 int kernelWidth) { 2112 ASSERT_OWNED_RESOURCE(texture); 2113 2114 float imageIncrement[2] = {1.0f / texture->width(), 0.0f}; 2115 convolve(texture, rect, imageIncrement, kernel, kernelWidth); 2116} 2117 2118void GrContext::convolveInY(GrTexture* texture, 2119 const SkRect& rect, 2120 const float* kernel, 2121 int kernelWidth) { 2122 ASSERT_OWNED_RESOURCE(texture); 2123 2124 float imageIncrement[2] = {0.0f, 1.0f / texture->height()}; 2125 convolve(texture, rect, imageIncrement, kernel, kernelWidth); 2126} 2127 2128void GrContext::convolve(GrTexture* texture, 2129 const SkRect& rect, 2130 float imageIncrement[2], 2131 const float* kernel, 2132 int kernelWidth) { 2133 ASSERT_OWNED_RESOURCE(texture); 2134 2135 GrDrawTarget::AutoStateRestore asr(fGpu); 2136 GrDrawState* drawState = fGpu->drawState(); 2137 GrMatrix sampleM; 2138 sampleM.setIDiv(texture->width(), texture->height()); 2139 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 2140 GrSamplerState::kConvolution_Filter, 2141 sampleM); 2142 drawState->sampler(0)->setConvolutionParams(kernelWidth, 2143 kernel, 2144 imageIncrement); 2145 2146 drawState->setViewMatrix(GrMatrix::I()); 2147 drawState->setTexture(0, texture); 2148 drawState->setAlpha(0xFF); 2149 drawState->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff); 2150 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 2151} 2152 2153/////////////////////////////////////////////////////////////////////////////// 2154