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