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