GrContext.cpp revision 289533ada623f2238a83771eec977f204f75994f
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::kHWAntialias_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 // Line primitves are always rasterized as 1 pixel wide. 668 // Super-sampling would make them too thin but MSAA would be OK. 669 if (isHairLines && 670 (!PREFER_MSAA_OFFSCREEN_AA || !fGpu->getCaps().fFSAASupport)) { 671 return false; 672 } 673 if (target->getRenderTarget()->isMultisampled()) { 674 return false; 675 } 676 if (disable_coverage_aa_for_blend(target)) { 677#if GR_DEBUG 678 GrPrintf("Turning off AA to correctly apply blend.\n"); 679#endif 680 return false; 681 } 682 return true; 683#endif 684} 685 686bool GrContext::prepareForOffscreenAA(GrDrawTarget* target, 687 bool requireStencil, 688 const GrIRect& boundRect, 689 GrPathRenderer* pr, 690 OffscreenRecord* record) { 691 692 GrAssert(GR_USE_OFFSCREEN_AA); 693 694 GrAssert(NULL == record->fOffscreen0.texture()); 695 GrAssert(NULL == record->fOffscreen1.texture()); 696 GrAssert(!boundRect.isEmpty()); 697 698 int boundW = boundRect.width(); 699 int boundH = boundRect.height(); 700 701 GrTextureDesc desc; 702 703 desc.fWidth = GrMin(fMaxOffscreenAASize, boundW); 704 desc.fHeight = GrMin(fMaxOffscreenAASize, boundH); 705 706 if (requireStencil) { 707 desc.fFlags = kRenderTarget_GrTextureFlagBit; 708 } else { 709 desc.fFlags = kRenderTarget_GrTextureFlagBit | 710 kNoStencil_GrTextureFlagBit; 711 } 712 713 desc.fFormat = kRGBA_8888_GrPixelConfig; 714 715 if (PREFER_MSAA_OFFSCREEN_AA && fGpu->getCaps().fFSAASupport) { 716 record->fDownsample = OffscreenRecord::kFSAA_Downsample; 717 record->fScale = 1; 718 desc.fAALevel = kMed_GrAALevel; 719 } else { 720 record->fDownsample = fGpu->getCaps().fShaderSupport ? 721 OffscreenRecord::k4x4SinglePass_Downsample : 722 OffscreenRecord::k4x4TwoPass_Downsample; 723 record->fScale = OFFSCREEN_SSAA_SCALE; 724 // both downsample paths assume this 725 GR_STATIC_ASSERT(4 == OFFSCREEN_SSAA_SCALE); 726 desc.fAALevel = kNone_GrAALevel; 727 } 728 729 desc.fWidth *= record->fScale; 730 desc.fHeight *= record->fScale; 731 record->fOffscreen0.set(this, desc); 732 if (NULL == record->fOffscreen0.texture()) { 733 return false; 734 } 735 // the approximate lookup might have given us some slop space, might as well 736 // use it when computing the tiles size. 737 // these are scale values, will adjust after considering 738 // the possible second offscreen. 739 record->fTileSizeX = record->fOffscreen0.texture()->width(); 740 record->fTileSizeY = record->fOffscreen0.texture()->height(); 741 742 if (OffscreenRecord::k4x4TwoPass_Downsample == record->fDownsample) { 743 desc.fWidth /= 2; 744 desc.fHeight /= 2; 745 record->fOffscreen1.set(this, desc); 746 if (NULL == record->fOffscreen1.texture()) { 747 return false; 748 } 749 record->fTileSizeX = GrMin(record->fTileSizeX, 750 2 * record->fOffscreen0.texture()->width()); 751 record->fTileSizeY = GrMin(record->fTileSizeY, 752 2 * record->fOffscreen0.texture()->height()); 753 } 754 record->fTileSizeX /= record->fScale; 755 record->fTileSizeY /= record->fScale; 756 757 record->fTileCountX = GrIDivRoundUp(boundW, record->fTileSizeX); 758 record->fTileCountY = GrIDivRoundUp(boundH, record->fTileSizeY); 759 760 record->fClip = target->getClip(); 761 762 target->saveCurrentDrawState(&record->fSavedState); 763 return true; 764} 765 766void GrContext::setupOffscreenAAPass1(GrDrawTarget* target, 767 const GrIRect& boundRect, 768 int tileX, int tileY, 769 OffscreenRecord* record) { 770 771 GrRenderTarget* offRT0 = record->fOffscreen0.texture()->asRenderTarget(); 772 GrAssert(NULL != offRT0); 773 774 GrPaint tempPaint; 775 tempPaint.reset(); 776 SetPaint(tempPaint, target); 777 target->setRenderTarget(offRT0); 778#if PREFER_MSAA_OFFSCREEN_AA 779 target->enableState(GrDrawTarget::kHWAntialias_StateBit); 780#endif 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, and the rect won't land on integer coords. 1170 1171 // we are keeping around the "tweak the alpha" trick because 1172 // it is our only hope for the fixed-pipe implementation. 1173 // In a shader implementation we can give a separate coverage input 1174 // TODO: remove this ugliness when we drop the fixed-pipe impl 1175 *useVertexCoverage = false; 1176 if (!target->canTweakAlphaForCoverage()) { 1177 if (target->getCaps().fSupportPerVertexCoverage) { 1178 if (disable_coverage_aa_for_blend(target)) { 1179#if GR_DEBUG 1180 GrPrintf("Turning off AA to correctly apply blend.\n"); 1181#endif 1182 return false; 1183 } else { 1184 *useVertexCoverage = true; 1185 } 1186 } else { 1187 GrPrintf("Rect AA dropped because no support for coverage.\n"); 1188 return false; 1189 } 1190 } 1191 1192 if (target->getRenderTarget()->isMultisampled()) { 1193 return false; 1194 } 1195 1196 if (0 == width && target->willUseHWAALines()) { 1197 return false; 1198 } 1199 1200 if (!target->getViewMatrix().preservesAxisAlignment()) { 1201 return false; 1202 } 1203 1204 if (NULL != matrix && 1205 !matrix->preservesAxisAlignment()) { 1206 return false; 1207 } 1208 1209 *combinedMatrix = target->getViewMatrix(); 1210 if (NULL != matrix) { 1211 combinedMatrix->preConcat(*matrix); 1212 GrAssert(combinedMatrix->preservesAxisAlignment()); 1213 } 1214 1215 combinedMatrix->mapRect(devRect, rect); 1216 devRect->sort(); 1217 1218 if (width < 0) { 1219 return !isIRect(*devRect); 1220 } else { 1221 return true; 1222 } 1223} 1224 1225void GrContext::drawRect(const GrPaint& paint, 1226 const GrRect& rect, 1227 GrScalar width, 1228 const GrMatrix* matrix) { 1229 SK_TRACE_EVENT0("GrContext::drawRect"); 1230 1231 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1232 int stageMask = paint.getActiveStageMask(); 1233 1234 GrRect devRect = rect; 1235 GrMatrix combinedMatrix; 1236 bool useVertexCoverage; 1237 bool needAA = paint.fAntiAlias && 1238 !this->getRenderTarget()->isMultisampled(); 1239 bool doAA = needAA && apply_aa_to_rect(target, rect, width, matrix, 1240 &combinedMatrix, &devRect, 1241 &useVertexCoverage); 1242 1243 if (doAA) { 1244 GrDrawTarget::AutoViewMatrixRestore avm(target); 1245 if (stageMask) { 1246 GrMatrix inv; 1247 if (combinedMatrix.invert(&inv)) { 1248 target->preConcatSamplerMatrices(stageMask, inv); 1249 } 1250 } 1251 target->setViewMatrix(GrMatrix::I()); 1252 if (width >= 0) { 1253 GrVec strokeSize;; 1254 if (width > 0) { 1255 strokeSize.set(width, width); 1256 combinedMatrix.mapVectors(&strokeSize, 1); 1257 strokeSize.setAbs(strokeSize); 1258 } else { 1259 strokeSize.set(GR_Scalar1, GR_Scalar1); 1260 } 1261 strokeAARect(target, devRect, strokeSize, useVertexCoverage); 1262 } else { 1263 fillAARect(target, devRect, useVertexCoverage); 1264 } 1265 return; 1266 } 1267 1268 if (width >= 0) { 1269 // TODO: consider making static vertex buffers for these cases. 1270 // Hairline could be done by just adding closing vertex to 1271 // unitSquareVertexBuffer() 1272 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1273 1274 static const int worstCaseVertCount = 10; 1275 GrDrawTarget::AutoReleaseGeometry geo(target, layout, worstCaseVertCount, 0); 1276 1277 if (!geo.succeeded()) { 1278 GrPrintf("Failed to get space for vertices!\n"); 1279 return; 1280 } 1281 1282 GrPrimitiveType primType; 1283 int vertCount; 1284 GrPoint* vertex = geo.positions(); 1285 1286 if (width > 0) { 1287 vertCount = 10; 1288 primType = kTriangleStrip_PrimitiveType; 1289 setStrokeRectStrip(vertex, rect, width); 1290 } else { 1291 // hairline 1292 vertCount = 5; 1293 primType = kLineStrip_PrimitiveType; 1294 vertex[0].set(rect.fLeft, rect.fTop); 1295 vertex[1].set(rect.fRight, rect.fTop); 1296 vertex[2].set(rect.fRight, rect.fBottom); 1297 vertex[3].set(rect.fLeft, rect.fBottom); 1298 vertex[4].set(rect.fLeft, rect.fTop); 1299 } 1300 1301 GrDrawTarget::AutoViewMatrixRestore avmr; 1302 if (NULL != matrix) { 1303 avmr.set(target); 1304 target->preConcatViewMatrix(*matrix); 1305 target->preConcatSamplerMatrices(stageMask, *matrix); 1306 } 1307 1308 target->drawNonIndexed(primType, 0, vertCount); 1309 } else { 1310 #if GR_STATIC_RECT_VB 1311 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1312 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 1313 if (NULL == sqVB) { 1314 GrPrintf("Failed to create static rect vb.\n"); 1315 return; 1316 } 1317 target->setVertexSourceToBuffer(layout, sqVB); 1318 GrDrawTarget::AutoViewMatrixRestore avmr(target); 1319 GrMatrix m; 1320 m.setAll(rect.width(), 0, rect.fLeft, 1321 0, rect.height(), rect.fTop, 1322 0, 0, GrMatrix::I()[8]); 1323 1324 if (NULL != matrix) { 1325 m.postConcat(*matrix); 1326 } 1327 1328 target->preConcatViewMatrix(m); 1329 target->preConcatSamplerMatrices(stageMask, m); 1330 1331 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1332 #else 1333 target->drawSimpleRect(rect, matrix, stageMask); 1334 #endif 1335 } 1336} 1337 1338void GrContext::drawRectToRect(const GrPaint& paint, 1339 const GrRect& dstRect, 1340 const GrRect& srcRect, 1341 const GrMatrix* dstMatrix, 1342 const GrMatrix* srcMatrix) { 1343 SK_TRACE_EVENT0("GrContext::drawRectToRect"); 1344 1345 // srcRect refers to paint's first texture 1346 if (NULL == paint.getTexture(0)) { 1347 drawRect(paint, dstRect, -1, dstMatrix); 1348 return; 1349 } 1350 1351 GR_STATIC_ASSERT(!BATCH_RECT_TO_RECT || !GR_STATIC_RECT_VB); 1352 1353#if GR_STATIC_RECT_VB 1354 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1355 1356 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, NULL); 1357 GrDrawTarget::AutoViewMatrixRestore avmr(target); 1358 1359 GrMatrix m; 1360 1361 m.setAll(dstRect.width(), 0, dstRect.fLeft, 1362 0, dstRect.height(), dstRect.fTop, 1363 0, 0, GrMatrix::I()[8]); 1364 if (NULL != dstMatrix) { 1365 m.postConcat(*dstMatrix); 1366 } 1367 target->preConcatViewMatrix(m); 1368 1369 // srcRect refers to first stage 1370 int otherStageMask = paint.getActiveStageMask() & 1371 (~(1 << GrPaint::kFirstTextureStage)); 1372 if (otherStageMask) { 1373 target->preConcatSamplerMatrices(otherStageMask, m); 1374 } 1375 1376 m.setAll(srcRect.width(), 0, srcRect.fLeft, 1377 0, srcRect.height(), srcRect.fTop, 1378 0, 0, GrMatrix::I()[8]); 1379 if (NULL != srcMatrix) { 1380 m.postConcat(*srcMatrix); 1381 } 1382 target->preConcatSamplerMatrix(GrPaint::kFirstTextureStage, m); 1383 1384 const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer(); 1385 if (NULL == sqVB) { 1386 GrPrintf("Failed to create static rect vb.\n"); 1387 return; 1388 } 1389 target->setVertexSourceToBuffer(layout, sqVB); 1390 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, 4); 1391#else 1392 1393 GrDrawTarget* target; 1394#if BATCH_RECT_TO_RECT 1395 target = this->prepareToDraw(paint, kBuffered_DrawCategory); 1396#else 1397 target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1398#endif 1399 1400 const GrRect* srcRects[GrDrawTarget::kNumStages] = {NULL}; 1401 const GrMatrix* srcMatrices[GrDrawTarget::kNumStages] = {NULL}; 1402 srcRects[0] = &srcRect; 1403 srcMatrices[0] = srcMatrix; 1404 1405 target->drawRect(dstRect, dstMatrix, 1, srcRects, srcMatrices); 1406#endif 1407} 1408 1409void GrContext::drawVertices(const GrPaint& paint, 1410 GrPrimitiveType primitiveType, 1411 int vertexCount, 1412 const GrPoint positions[], 1413 const GrPoint texCoords[], 1414 const GrColor colors[], 1415 const uint16_t indices[], 1416 int indexCount) { 1417 SK_TRACE_EVENT0("GrContext::drawVertices"); 1418 1419 GrDrawTarget::AutoReleaseGeometry geo; 1420 1421 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1422 1423 bool hasTexCoords[GrPaint::kTotalStages] = { 1424 NULL != texCoords, // texCoordSrc provides explicit stage 0 coords 1425 0 // remaining stages use positions 1426 }; 1427 1428 GrVertexLayout layout = PaintStageVertexLayoutBits(paint, hasTexCoords); 1429 1430 if (NULL != colors) { 1431 layout |= GrDrawTarget::kColor_VertexLayoutBit; 1432 } 1433 int vertexSize = GrDrawTarget::VertexSize(layout); 1434 1435 if (sizeof(GrPoint) != vertexSize) { 1436 if (!geo.set(target, layout, vertexCount, 0)) { 1437 GrPrintf("Failed to get space for vertices!\n"); 1438 return; 1439 } 1440 int texOffsets[GrDrawTarget::kMaxTexCoords]; 1441 int colorOffset; 1442 GrDrawTarget::VertexSizeAndOffsetsByIdx(layout, 1443 texOffsets, 1444 &colorOffset, 1445 NULL, 1446 NULL); 1447 void* curVertex = geo.vertices(); 1448 1449 for (int i = 0; i < vertexCount; ++i) { 1450 *((GrPoint*)curVertex) = positions[i]; 1451 1452 if (texOffsets[0] > 0) { 1453 *(GrPoint*)((intptr_t)curVertex + texOffsets[0]) = texCoords[i]; 1454 } 1455 if (colorOffset > 0) { 1456 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i]; 1457 } 1458 curVertex = (void*)((intptr_t)curVertex + vertexSize); 1459 } 1460 } else { 1461 target->setVertexSourceToArray(layout, positions, vertexCount); 1462 } 1463 1464 // we don't currently apply offscreen AA to this path. Need improved 1465 // management of GrDrawTarget's geometry to avoid copying points per-tile. 1466 1467 if (NULL != indices) { 1468 target->setIndexSourceToArray(indices, indexCount); 1469 target->drawIndexed(primitiveType, 0, 0, vertexCount, indexCount); 1470 } else { 1471 target->drawNonIndexed(primitiveType, 0, vertexCount); 1472 } 1473} 1474 1475/////////////////////////////////////////////////////////////////////////////// 1476 1477void GrContext::drawPath(const GrPaint& paint, const GrPath& path, 1478 GrPathFill fill, const GrPoint* translate) { 1479 1480 if (path.isEmpty()) { 1481#if GR_DEBUG 1482 GrPrintf("Empty path should have been caught by canvas.\n"); 1483#endif 1484 if (GrIsFillInverted(fill)) { 1485 this->drawPaint(paint); 1486 } 1487 return; 1488 } 1489 1490 GrDrawTarget* target = this->prepareToDraw(paint, kUnbuffered_DrawCategory); 1491 1492 bool prAA = paint.fAntiAlias && !this->getRenderTarget()->isMultisampled(); 1493 1494 // An Assumption here is that path renderer would use some form of tweaking 1495 // the src color (either the input alpha or in the frag shader) to implement 1496 // aa. If we have some future driver-mojo path AA that can do the right 1497 // thing WRT to the blend then we'll need some query on the PR. 1498 if (disable_coverage_aa_for_blend(target)) { 1499#if GR_DEBUG 1500 GrPrintf("Turning off AA to correctly apply blend.\n"); 1501#endif 1502 prAA = false; 1503 } 1504 1505 bool doOSAA = false; 1506 GrPathRenderer* pr = NULL; 1507 if (prAA) { 1508 pr = this->getPathRenderer(path, fill, true); 1509 if (NULL == pr) { 1510 prAA = false; 1511 doOSAA = this->doOffscreenAA(target, kHairLine_PathFill == fill); 1512 pr = this->getPathRenderer(path, fill, false); 1513 } 1514 } else { 1515 pr = this->getPathRenderer(path, fill, false); 1516 } 1517 1518 if (NULL == pr) { 1519#if GR_DEBUG 1520 GrPrintf("Unable to find path renderer compatible with path.\n"); 1521#endif 1522 return; 1523 } 1524 1525 GrPathRenderer::AutoClearPath arp(pr, target, &path, fill, prAA, translate); 1526 GrDrawTarget::StageBitfield stageMask = paint.getActiveStageMask(); 1527 1528 if (doOSAA) { 1529 bool needsStencil = pr->requiresStencilPass(target, path, fill); 1530 1531 // compute bounds as intersection of rt size, clip, and path 1532 GrIRect bound = SkIRect::MakeWH(target->getRenderTarget()->width(), 1533 target->getRenderTarget()->height()); 1534 GrIRect clipIBounds; 1535 if (target->getClip().hasConservativeBounds()) { 1536 target->getClip().getConservativeBounds().roundOut(&clipIBounds); 1537 if (!bound.intersect(clipIBounds)) { 1538 return; 1539 } 1540 } 1541 1542 GrRect pathBounds = path.getBounds(); 1543 if (!pathBounds.isEmpty()) { 1544 if (NULL != translate) { 1545 pathBounds.offset(*translate); 1546 } 1547 target->getViewMatrix().mapRect(&pathBounds, pathBounds); 1548 GrIRect pathIBounds; 1549 pathBounds.roundOut(&pathIBounds); 1550 if (!bound.intersect(pathIBounds)) { 1551 return; 1552 } 1553 } 1554 OffscreenRecord record; 1555 if (this->prepareForOffscreenAA(target, needsStencil, bound, 1556 pr, &record)) { 1557 for (int tx = 0; tx < record.fTileCountX; ++tx) { 1558 for (int ty = 0; ty < record.fTileCountY; ++ty) { 1559 this->setupOffscreenAAPass1(target, bound, tx, ty, &record); 1560 pr->drawPath(0); 1561 this->doOffscreenAAPass2(target, paint, bound, tx, ty, &record); 1562 } 1563 } 1564 this->cleanupOffscreenAA(target, pr, &record); 1565 if (GrIsFillInverted(fill) && bound != clipIBounds) { 1566 GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask); 1567 GrRect rect; 1568 if (clipIBounds.fTop < bound.fTop) { 1569 rect.iset(clipIBounds.fLeft, clipIBounds.fTop, 1570 clipIBounds.fRight, bound.fTop); 1571 target->drawSimpleRect(rect, NULL, stageMask); 1572 } 1573 if (clipIBounds.fLeft < bound.fLeft) { 1574 rect.iset(clipIBounds.fLeft, bound.fTop, 1575 bound.fLeft, bound.fBottom); 1576 target->drawSimpleRect(rect, NULL, stageMask); 1577 } 1578 if (clipIBounds.fRight > bound.fRight) { 1579 rect.iset(bound.fRight, bound.fTop, 1580 clipIBounds.fRight, bound.fBottom); 1581 target->drawSimpleRect(rect, NULL, stageMask); 1582 } 1583 if (clipIBounds.fBottom > bound.fBottom) { 1584 rect.iset(clipIBounds.fLeft, bound.fBottom, 1585 clipIBounds.fRight, clipIBounds.fBottom); 1586 target->drawSimpleRect(rect, NULL, stageMask); 1587 } 1588 } 1589 return; 1590 } 1591 } 1592 pr->drawPath(stageMask); 1593} 1594 1595//////////////////////////////////////////////////////////////////////////////// 1596 1597bool GrContext::supportsShaders() const { 1598 return fGpu->getCaps().fShaderSupport; 1599} 1600 1601void GrContext::flush(int flagsBitfield) { 1602 if (kDiscard_FlushBit & flagsBitfield) { 1603 fDrawBuffer->reset(); 1604 } else { 1605 flushDrawBuffer(); 1606 } 1607 1608 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) { 1609 fGpu->forceRenderTargetFlush(); 1610 } 1611} 1612 1613void GrContext::flushText() { 1614 if (kText_DrawCategory == fLastDrawCategory) { 1615 flushDrawBuffer(); 1616 } 1617} 1618 1619void GrContext::flushDrawBuffer() { 1620#if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING 1621 if (fDrawBuffer) { 1622 fDrawBuffer->playback(fGpu); 1623 fDrawBuffer->reset(); 1624 } 1625#endif 1626} 1627 1628bool GrContext::readTexturePixels(GrTexture* texture, 1629 int left, int top, int width, int height, 1630 GrPixelConfig config, void* buffer) { 1631 SK_TRACE_EVENT0("GrContext::readTexturePixels"); 1632 1633 // TODO: code read pixels for textures that aren't rendertargets 1634 1635 this->flush(); 1636 GrRenderTarget* target = texture->asRenderTarget(); 1637 if (NULL != target) { 1638 return fGpu->readPixels(target, 1639 left, top, width, height, 1640 config, buffer); 1641 } else { 1642 return false; 1643 } 1644} 1645 1646bool GrContext::readRenderTargetPixels(GrRenderTarget* target, 1647 int left, int top, int width, int height, 1648 GrPixelConfig config, void* buffer) { 1649 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels"); 1650 uint32_t flushFlags = 0; 1651 if (NULL == target) { 1652 flushFlags |= GrContext::kForceCurrentRenderTarget_FlushBit; 1653 } 1654 1655 this->flush(flushFlags); 1656 return fGpu->readPixels(target, 1657 left, top, width, height, 1658 config, buffer); 1659} 1660 1661void GrContext::writePixels(int left, int top, int width, int height, 1662 GrPixelConfig config, const void* buffer, 1663 size_t stride) { 1664 SK_TRACE_EVENT0("GrContext::writePixels"); 1665 1666 // TODO: when underlying api has a direct way to do this we should use it 1667 // (e.g. glDrawPixels on desktop GL). 1668 1669 this->flush(true); 1670 1671 const GrTextureDesc desc = { 1672 kNone_GrTextureFlags, kNone_GrAALevel, width, height, config 1673 }; 1674 GrAutoScratchTexture ast(this, desc); 1675 GrTexture* texture = ast.texture(); 1676 if (NULL == texture) { 1677 return; 1678 } 1679 texture->uploadTextureData(0, 0, width, height, buffer, stride); 1680 1681 GrDrawTarget::AutoStateRestore asr(fGpu); 1682 1683 GrMatrix matrix; 1684 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); 1685 fGpu->setViewMatrix(matrix); 1686 1687 fGpu->setColorFilter(0, SkXfermode::kDst_Mode); 1688 fGpu->disableState(GrDrawTarget::kClip_StateBit); 1689 fGpu->setAlpha(0xFF); 1690 fGpu->setBlendFunc(kOne_BlendCoeff, 1691 kZero_BlendCoeff); 1692 fGpu->setTexture(0, texture); 1693 1694 GrSamplerState sampler; 1695 sampler.setClampNoFilter(); 1696 matrix.setIDiv(texture->width(), texture->height()); 1697 sampler.setMatrix(matrix); 1698 fGpu->setSamplerState(0, sampler); 1699 1700 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); 1701 static const int VCOUNT = 4; 1702 // TODO: Use GrGpu::drawRect here 1703 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0); 1704 if (!geo.succeeded()) { 1705 GrPrintf("Failed to get space for vertices!\n"); 1706 return; 1707 } 1708 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height); 1709 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT); 1710} 1711//////////////////////////////////////////////////////////////////////////////// 1712 1713void GrContext::SetPaint(const GrPaint& paint, GrDrawTarget* target) { 1714 1715 for (int i = 0; i < GrPaint::kMaxTextures; ++i) { 1716 int s = i + GrPaint::kFirstTextureStage; 1717 target->setTexture(s, paint.getTexture(i)); 1718 target->setSamplerState(s, *paint.getTextureSampler(i)); 1719 } 1720 1721 target->setFirstCoverageStage(GrPaint::kFirstMaskStage); 1722 1723 for (int i = 0; i < GrPaint::kMaxMasks; ++i) { 1724 int s = i + GrPaint::kFirstMaskStage; 1725 target->setTexture(s, paint.getMask(i)); 1726 target->setSamplerState(s, *paint.getMaskSampler(i)); 1727 } 1728 1729 target->setColor(paint.fColor); 1730 1731 if (paint.fDither) { 1732 target->enableState(GrDrawTarget::kDither_StateBit); 1733 } else { 1734 target->disableState(GrDrawTarget::kDither_StateBit); 1735 } 1736 if (paint.fAntiAlias) { 1737 target->enableState(GrDrawTarget::kHWAntialias_StateBit); 1738 } else { 1739 target->disableState(GrDrawTarget::kHWAntialias_StateBit); 1740 } 1741 target->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); 1742 target->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); 1743 1744 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) { 1745 GrPrintf("Partial pixel coverage will be incorrectly blended.\n"); 1746 } 1747} 1748 1749GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, 1750 DrawCategory category) { 1751 if (category != fLastDrawCategory) { 1752 flushDrawBuffer(); 1753 fLastDrawCategory = category; 1754 } 1755 SetPaint(paint, fGpu); 1756 GrDrawTarget* target = fGpu; 1757 switch (category) { 1758 case kText_DrawCategory: 1759#if DEFER_TEXT_RENDERING 1760 target = fDrawBuffer; 1761 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1762#else 1763 target = fGpu; 1764#endif 1765 break; 1766 case kUnbuffered_DrawCategory: 1767 target = fGpu; 1768 break; 1769 case kBuffered_DrawCategory: 1770 target = fDrawBuffer; 1771 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1772 break; 1773 } 1774 return target; 1775} 1776 1777GrPathRenderer* GrContext::getPathRenderer(const GrPath& path, 1778 GrPathFill fill, 1779 bool antiAlias) { 1780 if (NULL == fPathRendererChain) { 1781 fPathRendererChain = 1782 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag); 1783 } 1784 return fPathRendererChain->getPathRenderer(fGpu->getCaps(), path, 1785 fill, antiAlias); 1786} 1787 1788//////////////////////////////////////////////////////////////////////////////// 1789 1790void GrContext::setRenderTarget(GrRenderTarget* target) { 1791 this->flush(false); 1792 fGpu->setRenderTarget(target); 1793} 1794 1795GrRenderTarget* GrContext::getRenderTarget() { 1796 return fGpu->getRenderTarget(); 1797} 1798 1799const GrRenderTarget* GrContext::getRenderTarget() const { 1800 return fGpu->getRenderTarget(); 1801} 1802 1803const GrMatrix& GrContext::getMatrix() const { 1804 return fGpu->getViewMatrix(); 1805} 1806 1807void GrContext::setMatrix(const GrMatrix& m) { 1808 fGpu->setViewMatrix(m); 1809} 1810 1811void GrContext::concatMatrix(const GrMatrix& m) const { 1812 fGpu->preConcatViewMatrix(m); 1813} 1814 1815static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { 1816 intptr_t mask = 1 << shift; 1817 if (pred) { 1818 bits |= mask; 1819 } else { 1820 bits &= ~mask; 1821 } 1822 return bits; 1823} 1824 1825void GrContext::resetStats() { 1826 fGpu->resetStats(); 1827} 1828 1829const GrGpuStats& GrContext::getStats() const { 1830 return fGpu->getStats(); 1831} 1832 1833void GrContext::printStats() const { 1834 fGpu->printStats(); 1835} 1836 1837GrContext::GrContext(GrGpu* gpu) { 1838 fGpu = gpu; 1839 fGpu->ref(); 1840 fGpu->setContext(this); 1841 1842 fPathRendererChain = NULL; 1843 1844 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT, 1845 MAX_TEXTURE_CACHE_BYTES); 1846 fFontCache = new GrFontCache(fGpu); 1847 1848 fLastDrawCategory = kUnbuffered_DrawCategory; 1849 1850 fDrawBuffer = NULL; 1851 fDrawBufferVBAllocPool = NULL; 1852 fDrawBufferIBAllocPool = NULL; 1853 1854 fAAFillRectIndexBuffer = NULL; 1855 fAAStrokeRectIndexBuffer = NULL; 1856 1857 int gpuMaxOffscreen = gpu->getCaps().fMaxRenderTargetSize; 1858 if (!PREFER_MSAA_OFFSCREEN_AA || !gpu->getCaps().fFSAASupport) { 1859 gpuMaxOffscreen /= OFFSCREEN_SSAA_SCALE; 1860 } 1861 fMaxOffscreenAASize = GrMin(GR_MAX_OFFSCREEN_AA_SIZE, gpuMaxOffscreen); 1862 1863 this->setupDrawBuffer(); 1864} 1865 1866void GrContext::setupDrawBuffer() { 1867 1868 GrAssert(NULL == fDrawBuffer); 1869 GrAssert(NULL == fDrawBufferVBAllocPool); 1870 GrAssert(NULL == fDrawBufferIBAllocPool); 1871 1872#if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT 1873 fDrawBufferVBAllocPool = 1874 new GrVertexBufferAllocPool(fGpu, false, 1875 DRAW_BUFFER_VBPOOL_BUFFER_SIZE, 1876 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS); 1877 fDrawBufferIBAllocPool = 1878 new GrIndexBufferAllocPool(fGpu, false, 1879 DRAW_BUFFER_IBPOOL_BUFFER_SIZE, 1880 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS); 1881 1882 fDrawBuffer = new GrInOrderDrawBuffer(fGpu, 1883 fDrawBufferVBAllocPool, 1884 fDrawBufferIBAllocPool); 1885#endif 1886 1887#if BATCH_RECT_TO_RECT 1888 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer()); 1889#endif 1890} 1891 1892GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { 1893 GrDrawTarget* target; 1894#if DEFER_TEXT_RENDERING 1895 target = prepareToDraw(paint, kText_DrawCategory); 1896#else 1897 target = prepareToDraw(paint, kUnbuffered_DrawCategory); 1898#endif 1899 SetPaint(paint, target); 1900 return target; 1901} 1902 1903const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { 1904 return fGpu->getQuadIndexBuffer(); 1905} 1906 1907void GrContext::convolveInX(GrTexture* texture, 1908 const SkRect& rect, 1909 const float* kernel, 1910 int kernelWidth) { 1911 float imageIncrement[2] = {1.0f / texture->width(), 0.0f}; 1912 convolve(texture, rect, imageIncrement, kernel, kernelWidth); 1913} 1914 1915void GrContext::convolveInY(GrTexture* texture, 1916 const SkRect& rect, 1917 const float* kernel, 1918 int kernelWidth) { 1919 float imageIncrement[2] = {0.0f, 1.0f / texture->height()}; 1920 convolve(texture, rect, imageIncrement, kernel, kernelWidth); 1921} 1922 1923void GrContext::convolve(GrTexture* texture, 1924 const SkRect& rect, 1925 float imageIncrement[2], 1926 const float* kernel, 1927 int kernelWidth) { 1928 GrDrawTarget::AutoStateRestore asr(fGpu); 1929 GrMatrix sampleM; 1930 GrSamplerState sampler(GrSamplerState::kClamp_WrapMode, 1931 GrSamplerState::kClamp_WrapMode, 1932 GrSamplerState::kConvolution_Filter); 1933 sampler.setConvolutionParams(kernelWidth, kernel, imageIncrement); 1934 sampleM.setScale(GR_Scalar1 / texture->width(), 1935 GR_Scalar1 / texture->height()); 1936 sampler.setMatrix(sampleM); 1937 fGpu->setSamplerState(0, sampler); 1938 fGpu->setViewMatrix(GrMatrix::I()); 1939 fGpu->setTexture(0, texture); 1940 fGpu->setBlendFunc(kOne_BlendCoeff, kZero_BlendCoeff); 1941 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 1942} 1943