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 33 static const size_t MAX_TEXTURE_CACHE_COUNT = 256; 34 static const size_t MAX_TEXTURE_CACHE_BYTES = 16 * 1024 * 1024; 35 36 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 18; 37 static 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. 41 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 0; 42 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 0; 43 44 #define ASSERT_OWNED_RESOURCE(R) GrAssert(!(R) || (R)->getContext() == this) 45 46 GrContext* 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 57 GrContext::~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 71 void GrContext::contextLost() { 72 contextDestroyed(); 73 this->setupDrawBuffer(); 74 } 75 76 void 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 102 void GrContext::resetContext() { 103 fGpu->markContextDirty(); 104 } 105 106 void 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 114 size_t GrContext::getGpuTextureCacheBytes() const { 115 return fTextureCache->getCachedResourceBytes(); 116 } 117 118 //////////////////////////////////////////////////////////////////////////////// 119 120 int 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 140 enum { 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 151 GrTexture* GrContext::TextureCacheEntry::texture() const { 152 if (NULL == fEntry) { 153 return NULL; 154 } else { 155 return (GrTexture*) fEntry->resource(); 156 } 157 } 158 159 namespace { 160 // returns true if this is a "special" texture because of gpu NPOT limitations 161 bool 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) 207 void 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 215 void 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 223 GrContext::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 235 bool 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 245 GrResourceEntry* 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 253 GrStencilBuffer* 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 268 void GrContext::unlockStencilBuffer(GrResourceEntry* sbEntry) { 269 ASSERT_OWNED_RESOURCE(sbEntry->resource()); 270 fTextureCache->unlock(sbEntry); 271 } 272 273 static 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 300 GrContext::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 414 namespace { 415 inline 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 429 GrContext::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 499 void 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 511 GrTexture* GrContext::createUncachedTexture(const GrTextureDesc& desc, 512 void* srcData, 513 size_t rowBytes) { 514 return fGpu->createTexture(desc, srcData, rowBytes); 515 } 516 517 void GrContext::getTextureCacheLimits(int* maxTextures, 518 size_t* maxTextureBytes) const { 519 fTextureCache->getLimits(maxTextures, maxTextureBytes); 520 } 521 522 void GrContext::setTextureCacheLimits(int maxTextures, size_t maxTextureBytes) { 523 fTextureCache->setLimits(maxTextures, maxTextureBytes); 524 } 525 526 int GrContext::getMaxTextureSize() const { 527 return fGpu->getCaps().fMaxTextureSize; 528 } 529 530 int GrContext::getMaxRenderTargetSize() const { 531 return fGpu->getCaps().fMaxRenderTargetSize; 532 } 533 534 /////////////////////////////////////////////////////////////////////////////// 535 536 GrTexture* GrContext::createPlatformTexture(const GrPlatformTextureDesc& desc) { 537 return fGpu->createPlatformTexture(desc); 538 } 539 540 GrRenderTarget* GrContext::createPlatformRenderTarget(const GrPlatformRenderTargetDesc& desc) { 541 return fGpu->createPlatformRenderTarget(desc); 542 } 543 544 /////////////////////////////////////////////////////////////////////////////// 545 546 bool 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 568 const GrClip& GrContext::getClip() const { return fGpu->getClip(); } 569 570 void GrContext::setClip(const GrClip& clip) { 571 fGpu->setClip(clip); 572 fGpu->drawState()->enableState(GrDrawState::kClip_StateBit); 573 } 574 575 void GrContext::setClip(const GrIRect& rect) { 576 GrClip clip; 577 clip.setFromIRect(rect); 578 fGpu->setClip(clip); 579 } 580 581 //////////////////////////////////////////////////////////////////////////////// 582 583 void GrContext::clear(const GrIRect* rect, const GrColor color) { 584 this->flush(); 585 fGpu->clear(rect, color); 586 } 587 588 void 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 636 namespace { 637 inline 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 */ 649 static 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 666 static 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 671 static 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 679 int GrContext::aaFillRectIndexCount() const { 680 return GR_ARRAY_COUNT(gFillAARectIdx); 681 } 682 683 GrIndexBuffer* 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 699 static 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 716 int GrContext::aaStrokeRectIndexCount() const { 717 return GR_ARRAY_COUNT(gStrokeAARectIdx); 718 } 719 720 GrIndexBuffer* 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 736 static 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 752 void 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 801 void 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 */ 878 static bool isIRect(const GrRect& r) { 879 return GrScalarIsInt(r.fLeft) && GrScalarIsInt(r.fTop) && 880 GrScalarIsInt(r.fRight) && GrScalarIsInt(r.fBottom); 881 } 882 883 static 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 943 void 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 1050 void 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 1121 void 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 1191 namespace { 1192 1193 SkPath::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. 1212 bool 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 1256 bool 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 1326 void 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 1356 void 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, target, 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, target, 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 pr->drawPath(path, fill, translate, target, stageMask, prAA); 1436 } 1437 1438 //////////////////////////////////////////////////////////////////////////////// 1439 1440 void GrContext::flush(int flagsBitfield) { 1441 if (kDiscard_FlushBit & flagsBitfield) { 1442 fDrawBuffer->reset(); 1443 } else { 1444 this->flushDrawBuffer(); 1445 } 1446 if (kForceCurrentRenderTarget_FlushBit & flagsBitfield) { 1447 fGpu->forceRenderTargetFlush(); 1448 } 1449 } 1450 1451 void GrContext::flushText() { 1452 if (kText_DrawCategory == fLastDrawCategory) { 1453 flushDrawBuffer(); 1454 } 1455 } 1456 1457 void GrContext::flushDrawBuffer() { 1458 #if BATCH_RECT_TO_RECT || DEFER_TEXT_RENDERING 1459 if (fDrawBuffer) { 1460 fDrawBuffer->playback(fGpu); 1461 fDrawBuffer->reset(); 1462 } 1463 #endif 1464 } 1465 1466 void GrContext::internalWriteTexturePixels(GrTexture* texture, 1467 int left, int top, 1468 int width, int height, 1469 GrPixelConfig config, 1470 const void* buffer, 1471 size_t rowBytes, 1472 uint32_t flags) { 1473 SK_TRACE_EVENT0("GrContext::writeTexturePixels"); 1474 ASSERT_OWNED_RESOURCE(texture); 1475 1476 if (!(kDontFlush_PixelOpsFlag & flags)) { 1477 this->flush(); 1478 } 1479 // TODO: use scratch texture to perform conversion 1480 if (GrPixelConfigIsUnpremultiplied(texture->config()) != 1481 GrPixelConfigIsUnpremultiplied(config)) { 1482 return; 1483 } 1484 1485 fGpu->writeTexturePixels(texture, left, top, width, height, 1486 config, buffer, rowBytes); 1487 } 1488 1489 bool GrContext::internalReadTexturePixels(GrTexture* texture, 1490 int left, int top, 1491 int width, int height, 1492 GrPixelConfig config, 1493 void* buffer, 1494 size_t rowBytes, 1495 uint32_t flags) { 1496 SK_TRACE_EVENT0("GrContext::readTexturePixels"); 1497 ASSERT_OWNED_RESOURCE(texture); 1498 1499 // TODO: code read pixels for textures that aren't also rendertargets 1500 GrRenderTarget* target = texture->asRenderTarget(); 1501 if (NULL != target) { 1502 return this->internalReadRenderTargetPixels(target, 1503 left, top, width, height, 1504 config, buffer, rowBytes, 1505 flags); 1506 } else { 1507 return false; 1508 } 1509 } 1510 1511 #include "SkConfig8888.h" 1512 1513 namespace { 1514 /** 1515 * Converts a GrPixelConfig to a SkCanvas::Config8888. Only byte-per-channel 1516 * formats are representable as Config8888 and so the function returns false 1517 * if the GrPixelConfig has no equivalent Config8888. 1518 */ 1519 bool grconfig_to_config8888(GrPixelConfig config, 1520 SkCanvas::Config8888* config8888) { 1521 switch (config) { 1522 case kRGBA_8888_PM_GrPixelConfig: 1523 *config8888 = SkCanvas::kRGBA_Premul_Config8888; 1524 return true; 1525 case kRGBA_8888_UPM_GrPixelConfig: 1526 *config8888 = SkCanvas::kRGBA_Unpremul_Config8888; 1527 return true; 1528 case kBGRA_8888_PM_GrPixelConfig: 1529 *config8888 = SkCanvas::kBGRA_Premul_Config8888; 1530 return true; 1531 case kBGRA_8888_UPM_GrPixelConfig: 1532 *config8888 = SkCanvas::kBGRA_Unpremul_Config8888; 1533 return true; 1534 default: 1535 return false; 1536 } 1537 } 1538 } 1539 1540 bool GrContext::internalReadRenderTargetPixels(GrRenderTarget* target, 1541 int left, int top, 1542 int width, int height, 1543 GrPixelConfig config, 1544 void* buffer, 1545 size_t rowBytes, 1546 uint32_t flags) { 1547 SK_TRACE_EVENT0("GrContext::readRenderTargetPixels"); 1548 ASSERT_OWNED_RESOURCE(target); 1549 1550 if (NULL == target) { 1551 target = fGpu->drawState()->getRenderTarget(); 1552 if (NULL == target) { 1553 return false; 1554 } 1555 } 1556 1557 if (!(kDontFlush_PixelOpsFlag & flags)) { 1558 this->flush(); 1559 } 1560 1561 if (!GrPixelConfigIsUnpremultiplied(target->config()) && 1562 GrPixelConfigIsUnpremultiplied(config) && 1563 !fGpu->canPreserveReadWriteUnpremulPixels()) { 1564 SkCanvas::Config8888 srcConfig8888, dstConfig8888; 1565 if (!grconfig_to_config8888(target->config(), &srcConfig8888) || 1566 !grconfig_to_config8888(config, &dstConfig8888)) { 1567 return false; 1568 } 1569 // do read back using target's own config 1570 this->internalReadRenderTargetPixels(target, 1571 left, top, 1572 width, height, 1573 target->config(), 1574 buffer, rowBytes, 1575 kDontFlush_PixelOpsFlag); 1576 // sw convert the pixels to unpremul config 1577 uint32_t* pixels = reinterpret_cast<uint32_t*>(buffer); 1578 SkConvertConfig8888Pixels(pixels, rowBytes, dstConfig8888, 1579 pixels, rowBytes, srcConfig8888, 1580 width, height); 1581 return true; 1582 } 1583 1584 GrTexture* src = target->asTexture(); 1585 bool swapRAndB = NULL != src && 1586 fGpu->preferredReadPixelsConfig(config) == 1587 GrPixelConfigSwapRAndB(config); 1588 1589 bool flipY = NULL != src && 1590 fGpu->readPixelsWillPayForYFlip(target, left, top, 1591 width, height, config, 1592 rowBytes); 1593 bool alphaConversion = (!GrPixelConfigIsUnpremultiplied(target->config()) && 1594 GrPixelConfigIsUnpremultiplied(config)); 1595 1596 if (NULL == src && alphaConversion) { 1597 // we should fallback to cpu conversion here. This could happen when 1598 // we were given an external render target by the client that is not 1599 // also a texture (e.g. FBO 0 in GL) 1600 return false; 1601 } 1602 // we draw to a scratch texture if any of these conversion are applied 1603 GrAutoScratchTexture ast; 1604 if (flipY || swapRAndB || alphaConversion) { 1605 GrAssert(NULL != src); 1606 if (swapRAndB) { 1607 config = GrPixelConfigSwapRAndB(config); 1608 GrAssert(kUnknown_GrPixelConfig != config); 1609 } 1610 // Make the scratch a render target because we don't have a robust 1611 // readTexturePixels as of yet (it calls this function). 1612 const GrTextureDesc desc = { 1613 kRenderTarget_GrTextureFlagBit, 1614 width, height, 1615 config, 1616 {0}, // samples 1617 }; 1618 1619 // When a full readback is faster than a partial we could always make 1620 // the scratch exactly match the passed rect. However, if we see many 1621 // different size rectangles we will trash our texture cache and pay the 1622 // cost of creating and destroying many textures. So, we only request 1623 // an exact match when the caller is reading an entire RT. 1624 ScratchTexMatch match = kApprox_ScratchTexMatch; 1625 if (0 == left && 1626 0 == top && 1627 target->width() == width && 1628 target->height() == height && 1629 fGpu->fullReadPixelsIsFasterThanPartial()) { 1630 match = kExact_ScratchTexMatch; 1631 } 1632 ast.set(this, desc, match); 1633 GrTexture* texture = ast.texture(); 1634 if (!texture) { 1635 return false; 1636 } 1637 target = texture->asRenderTarget(); 1638 GrAssert(NULL != target); 1639 1640 GrDrawTarget::AutoStateRestore asr(fGpu); 1641 GrDrawState* drawState = fGpu->drawState(); 1642 drawState->reset(); 1643 drawState->setRenderTarget(target); 1644 1645 GrMatrix matrix; 1646 if (flipY) { 1647 matrix.setTranslate(SK_Scalar1 * left, 1648 SK_Scalar1 * (top + height)); 1649 matrix.set(GrMatrix::kMScaleY, -GR_Scalar1); 1650 } else { 1651 matrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top); 1652 } 1653 matrix.postIDiv(src->width(), src->height()); 1654 drawState->sampler(0)->reset(matrix); 1655 drawState->sampler(0)->setRAndBSwap(swapRAndB); 1656 drawState->setTexture(0, src); 1657 GrRect rect; 1658 rect.setXYWH(0, 0, SK_Scalar1 * width, SK_Scalar1 * height); 1659 fGpu->drawSimpleRect(rect, NULL, 0x1); 1660 left = 0; 1661 top = 0; 1662 } 1663 return fGpu->readPixels(target, 1664 left, top, width, height, 1665 config, buffer, rowBytes, flipY); 1666 } 1667 1668 void GrContext::resolveRenderTarget(GrRenderTarget* target) { 1669 GrAssert(target); 1670 ASSERT_OWNED_RESOURCE(target); 1671 // In the future we may track whether there are any pending draws to this 1672 // target. We don't today so we always perform a flush. We don't promise 1673 // this to our clients, though. 1674 this->flush(); 1675 fGpu->resolveRenderTarget(target); 1676 } 1677 1678 void GrContext::copyTexture(GrTexture* src, GrRenderTarget* dst) { 1679 if (NULL == src || NULL == dst) { 1680 return; 1681 } 1682 ASSERT_OWNED_RESOURCE(src); 1683 1684 GrDrawTarget::AutoStateRestore asr(fGpu); 1685 GrDrawState* drawState = fGpu->drawState(); 1686 drawState->reset(); 1687 drawState->setRenderTarget(dst); 1688 GrMatrix sampleM; 1689 sampleM.setIDiv(src->width(), src->height()); 1690 drawState->setTexture(0, src); 1691 drawState->sampler(0)->reset(sampleM); 1692 SkRect rect = SkRect::MakeXYWH(0, 0, 1693 SK_Scalar1 * src->width(), 1694 SK_Scalar1 * src->height()); 1695 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 1696 } 1697 1698 void GrContext::internalWriteRenderTargetPixels(GrRenderTarget* target, 1699 int left, int top, 1700 int width, int height, 1701 GrPixelConfig config, 1702 const void* buffer, 1703 size_t rowBytes, 1704 uint32_t flags) { 1705 SK_TRACE_EVENT0("GrContext::writeRenderTargetPixels"); 1706 ASSERT_OWNED_RESOURCE(target); 1707 1708 if (NULL == target) { 1709 target = fGpu->drawState()->getRenderTarget(); 1710 if (NULL == target) { 1711 return; 1712 } 1713 } 1714 1715 // TODO: when underlying api has a direct way to do this we should use it 1716 // (e.g. glDrawPixels on desktop GL). 1717 1718 // If the RT is also a texture and we don't have to do PM/UPM conversion 1719 // then take the texture path, which we expect to be at least as fast or 1720 // faster since it doesn't use an intermediate texture as we do below. 1721 1722 #if !GR_MAC_BUILD 1723 // At least some drivers on the Mac get confused when glTexImage2D is called 1724 // on a texture attached to an FBO. The FBO still sees the old image. TODO: 1725 // determine what OS versions and/or HW is affected. 1726 if (NULL != target->asTexture() && 1727 GrPixelConfigIsUnpremultiplied(target->config()) == 1728 GrPixelConfigIsUnpremultiplied(config)) { 1729 1730 this->internalWriteTexturePixels(target->asTexture(), 1731 left, top, width, height, 1732 config, buffer, rowBytes, flags); 1733 return; 1734 } 1735 #endif 1736 if (!GrPixelConfigIsUnpremultiplied(target->config()) && 1737 GrPixelConfigIsUnpremultiplied(config) && 1738 !fGpu->canPreserveReadWriteUnpremulPixels()) { 1739 SkCanvas::Config8888 srcConfig8888, dstConfig8888; 1740 if (!grconfig_to_config8888(config, &srcConfig8888) || 1741 !grconfig_to_config8888(target->config(), &dstConfig8888)) { 1742 return; 1743 } 1744 // allocate a tmp buffer and sw convert the pixels to premul 1745 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(width * height); 1746 const uint32_t* src = reinterpret_cast<const uint32_t*>(buffer); 1747 SkConvertConfig8888Pixels(tmpPixels.get(), 4 * width, dstConfig8888, 1748 src, rowBytes, srcConfig8888, 1749 width, height); 1750 // upload the already premul pixels 1751 this->internalWriteRenderTargetPixels(target, 1752 left, top, 1753 width, height, 1754 target->config(), 1755 tmpPixels, 4 * width, flags); 1756 return; 1757 } 1758 1759 bool swapRAndB = fGpu->preferredReadPixelsConfig(config) == 1760 GrPixelConfigSwapRAndB(config); 1761 if (swapRAndB) { 1762 config = GrPixelConfigSwapRAndB(config); 1763 } 1764 1765 const GrTextureDesc desc = { 1766 kNone_GrTextureFlags, width, height, config, {0} 1767 }; 1768 GrAutoScratchTexture ast(this, desc); 1769 GrTexture* texture = ast.texture(); 1770 if (NULL == texture) { 1771 return; 1772 } 1773 this->internalWriteTexturePixels(texture, 0, 0, width, height, 1774 config, buffer, rowBytes, flags); 1775 1776 GrDrawTarget::AutoStateRestore asr(fGpu); 1777 GrDrawState* drawState = fGpu->drawState(); 1778 drawState->reset(); 1779 1780 GrMatrix matrix; 1781 matrix.setTranslate(GrIntToScalar(left), GrIntToScalar(top)); 1782 drawState->setViewMatrix(matrix); 1783 drawState->setRenderTarget(target); 1784 drawState->setTexture(0, texture); 1785 1786 matrix.setIDiv(texture->width(), texture->height()); 1787 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 1788 GrSamplerState::kNearest_Filter, 1789 matrix); 1790 drawState->sampler(0)->setRAndBSwap(swapRAndB); 1791 1792 GrVertexLayout layout = GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(0); 1793 static const int VCOUNT = 4; 1794 // TODO: Use GrGpu::drawRect here 1795 GrDrawTarget::AutoReleaseGeometry geo(fGpu, layout, VCOUNT, 0); 1796 if (!geo.succeeded()) { 1797 GrPrintf("Failed to get space for vertices!\n"); 1798 return; 1799 } 1800 ((GrPoint*)geo.vertices())->setIRectFan(0, 0, width, height); 1801 fGpu->drawNonIndexed(kTriangleFan_PrimitiveType, 0, VCOUNT); 1802 } 1803 //////////////////////////////////////////////////////////////////////////////// 1804 1805 void GrContext::setPaint(const GrPaint& paint, GrDrawTarget* target) { 1806 GrDrawState* drawState = target->drawState(); 1807 1808 for (int i = 0; i < GrPaint::kMaxTextures; ++i) { 1809 int s = i + GrPaint::kFirstTextureStage; 1810 drawState->setTexture(s, paint.getTexture(i)); 1811 ASSERT_OWNED_RESOURCE(paint.getTexture(i)); 1812 if (paint.getTexture(i)) { 1813 *drawState->sampler(s) = paint.getTextureSampler(i); 1814 } 1815 } 1816 1817 drawState->setFirstCoverageStage(GrPaint::kFirstMaskStage); 1818 1819 for (int i = 0; i < GrPaint::kMaxMasks; ++i) { 1820 int s = i + GrPaint::kFirstMaskStage; 1821 drawState->setTexture(s, paint.getMask(i)); 1822 ASSERT_OWNED_RESOURCE(paint.getMask(i)); 1823 if (paint.getMask(i)) { 1824 *drawState->sampler(s) = paint.getMaskSampler(i); 1825 } 1826 } 1827 1828 drawState->setColor(paint.fColor); 1829 1830 if (paint.fDither) { 1831 drawState->enableState(GrDrawState::kDither_StateBit); 1832 } else { 1833 drawState->disableState(GrDrawState::kDither_StateBit); 1834 } 1835 if (paint.fAntiAlias) { 1836 drawState->enableState(GrDrawState::kHWAntialias_StateBit); 1837 } else { 1838 drawState->disableState(GrDrawState::kHWAntialias_StateBit); 1839 } 1840 if (paint.fColorMatrixEnabled) { 1841 drawState->enableState(GrDrawState::kColorMatrix_StateBit); 1842 } else { 1843 drawState->disableState(GrDrawState::kColorMatrix_StateBit); 1844 } 1845 drawState->setBlendFunc(paint.fSrcBlendCoeff, paint.fDstBlendCoeff); 1846 drawState->setColorFilter(paint.fColorFilterColor, paint.fColorFilterXfermode); 1847 drawState->setColorMatrix(paint.fColorMatrix); 1848 drawState->setCoverage(paint.fCoverage); 1849 1850 if (paint.getActiveMaskStageMask() && !target->canApplyCoverage()) { 1851 GrPrintf("Partial pixel coverage will be incorrectly blended.\n"); 1852 } 1853 } 1854 1855 GrDrawTarget* GrContext::prepareToDraw(const GrPaint& paint, 1856 DrawCategory category) { 1857 if (category != fLastDrawCategory) { 1858 flushDrawBuffer(); 1859 fLastDrawCategory = category; 1860 } 1861 this->setPaint(paint, fGpu); 1862 GrDrawTarget* target = fGpu; 1863 switch (category) { 1864 case kText_DrawCategory: 1865 #if DEFER_TEXT_RENDERING 1866 target = fDrawBuffer; 1867 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1868 #else 1869 target = fGpu; 1870 #endif 1871 break; 1872 case kUnbuffered_DrawCategory: 1873 target = fGpu; 1874 break; 1875 case kBuffered_DrawCategory: 1876 target = fDrawBuffer; 1877 fDrawBuffer->initializeDrawStateAndClip(*fGpu); 1878 break; 1879 } 1880 return target; 1881 } 1882 1883 GrPathRenderer* GrContext::getPathRenderer(const GrPath& path, 1884 GrPathFill fill, 1885 const GrDrawTarget* target, 1886 bool antiAlias) { 1887 if (NULL == fPathRendererChain) { 1888 fPathRendererChain = 1889 new GrPathRendererChain(this, GrPathRendererChain::kNone_UsageFlag); 1890 } 1891 return fPathRendererChain->getPathRenderer(path, fill, target, antiAlias); 1892 } 1893 1894 //////////////////////////////////////////////////////////////////////////////// 1895 1896 void GrContext::setRenderTarget(GrRenderTarget* target) { 1897 ASSERT_OWNED_RESOURCE(target); 1898 this->flush(false); 1899 fGpu->drawState()->setRenderTarget(target); 1900 } 1901 1902 GrRenderTarget* GrContext::getRenderTarget() { 1903 return fGpu->drawState()->getRenderTarget(); 1904 } 1905 1906 const GrRenderTarget* GrContext::getRenderTarget() const { 1907 return fGpu->getDrawState().getRenderTarget(); 1908 } 1909 1910 const GrMatrix& GrContext::getMatrix() const { 1911 return fGpu->getDrawState().getViewMatrix(); 1912 } 1913 1914 void GrContext::setMatrix(const GrMatrix& m) { 1915 fGpu->drawState()->setViewMatrix(m); 1916 } 1917 1918 void GrContext::concatMatrix(const GrMatrix& m) const { 1919 fGpu->drawState()->preConcatViewMatrix(m); 1920 } 1921 1922 static inline intptr_t setOrClear(intptr_t bits, int shift, intptr_t pred) { 1923 intptr_t mask = 1 << shift; 1924 if (pred) { 1925 bits |= mask; 1926 } else { 1927 bits &= ~mask; 1928 } 1929 return bits; 1930 } 1931 1932 void GrContext::resetStats() { 1933 fGpu->resetStats(); 1934 } 1935 1936 const GrGpuStats& GrContext::getStats() const { 1937 return fGpu->getStats(); 1938 } 1939 1940 void GrContext::printStats() const { 1941 fGpu->printStats(); 1942 } 1943 1944 GrContext::GrContext(GrGpu* gpu) { 1945 fGpu = gpu; 1946 fGpu->ref(); 1947 fGpu->setContext(this); 1948 1949 fPathRendererChain = NULL; 1950 1951 fTextureCache = new GrResourceCache(MAX_TEXTURE_CACHE_COUNT, 1952 MAX_TEXTURE_CACHE_BYTES); 1953 fFontCache = new GrFontCache(fGpu); 1954 1955 fLastDrawCategory = kUnbuffered_DrawCategory; 1956 1957 fDrawBuffer = NULL; 1958 fDrawBufferVBAllocPool = NULL; 1959 fDrawBufferIBAllocPool = NULL; 1960 1961 fAAFillRectIndexBuffer = NULL; 1962 fAAStrokeRectIndexBuffer = NULL; 1963 1964 this->setupDrawBuffer(); 1965 } 1966 1967 void GrContext::setupDrawBuffer() { 1968 1969 GrAssert(NULL == fDrawBuffer); 1970 GrAssert(NULL == fDrawBufferVBAllocPool); 1971 GrAssert(NULL == fDrawBufferIBAllocPool); 1972 1973 #if DEFER_TEXT_RENDERING || BATCH_RECT_TO_RECT 1974 fDrawBufferVBAllocPool = 1975 new GrVertexBufferAllocPool(fGpu, false, 1976 DRAW_BUFFER_VBPOOL_BUFFER_SIZE, 1977 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS); 1978 fDrawBufferIBAllocPool = 1979 new GrIndexBufferAllocPool(fGpu, false, 1980 DRAW_BUFFER_IBPOOL_BUFFER_SIZE, 1981 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS); 1982 1983 fDrawBuffer = new GrInOrderDrawBuffer(fGpu, 1984 fDrawBufferVBAllocPool, 1985 fDrawBufferIBAllocPool); 1986 #endif 1987 1988 #if BATCH_RECT_TO_RECT 1989 fDrawBuffer->setQuadIndexBuffer(this->getQuadIndexBuffer()); 1990 #endif 1991 } 1992 1993 GrDrawTarget* GrContext::getTextTarget(const GrPaint& paint) { 1994 GrDrawTarget* target; 1995 #if DEFER_TEXT_RENDERING 1996 target = prepareToDraw(paint, kText_DrawCategory); 1997 #else 1998 target = prepareToDraw(paint, kUnbuffered_DrawCategory); 1999 #endif 2000 this->setPaint(paint, target); 2001 return target; 2002 } 2003 2004 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const { 2005 return fGpu->getQuadIndexBuffer(); 2006 } 2007 2008 void GrContext::convolve(GrTexture* texture, 2009 const SkRect& rect, 2010 const float* kernel, 2011 int kernelWidth, 2012 GrSamplerState::FilterDirection direction) { 2013 ASSERT_OWNED_RESOURCE(texture); 2014 2015 GrDrawTarget::AutoStateRestore asr(fGpu); 2016 GrDrawState* drawState = fGpu->drawState(); 2017 GrRenderTarget* target = drawState->getRenderTarget(); 2018 drawState->reset(); 2019 drawState->setRenderTarget(target); 2020 GrMatrix sampleM; 2021 sampleM.setIDiv(texture->width(), texture->height()); 2022 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 2023 GrSamplerState::kConvolution_Filter, 2024 sampleM); 2025 drawState->sampler(0)->setConvolutionParams(kernelWidth, kernel); 2026 drawState->sampler(0)->setFilterDirection(direction); 2027 drawState->setTexture(0, texture); 2028 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 2029 } 2030 2031 void GrContext::applyMorphology(GrTexture* texture, 2032 const SkRect& rect, 2033 int radius, 2034 GrSamplerState::Filter filter, 2035 GrSamplerState::FilterDirection direction) { 2036 ASSERT_OWNED_RESOURCE(texture); 2037 GrAssert(filter == GrSamplerState::kErode_Filter || 2038 filter == GrSamplerState::kDilate_Filter); 2039 2040 GrDrawTarget::AutoStateRestore asr(fGpu); 2041 GrDrawState* drawState = fGpu->drawState(); 2042 GrRenderTarget* target = drawState->getRenderTarget(); 2043 drawState->reset(); 2044 drawState->setRenderTarget(target); 2045 GrMatrix sampleM; 2046 sampleM.setIDiv(texture->width(), texture->height()); 2047 drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode, 2048 filter, 2049 sampleM); 2050 drawState->sampler(0)->setMorphologyRadius(radius); 2051 drawState->sampler(0)->setFilterDirection(direction); 2052 drawState->setTexture(0, texture); 2053 fGpu->drawSimpleRect(rect, NULL, 1 << 0); 2054 } 2055 2056 /////////////////////////////////////////////////////////////////////////////// 2057