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