OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #include "GrContext.h" | 10 #include "GrContext.h" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
63 static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMI
T * 1024 * 1024; | 63 static const size_t MAX_RESOURCE_CACHE_BYTES = GR_DEFAULT_RESOURCE_CACHE_MB_LIMI
T * 1024 * 1024; |
64 | 64 |
65 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15; | 65 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15; |
66 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; | 66 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4; |
67 | 67 |
68 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11; | 68 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11; |
69 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; | 69 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4; |
70 | 70 |
71 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) | 71 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) |
72 | 72 |
| 73 GrTexture* GrAutoScratchTexture::detach() { |
| 74 if (NULL == fTexture) { |
| 75 return NULL; |
| 76 } |
| 77 GrTexture* texture = fTexture; |
| 78 fTexture = NULL; |
| 79 |
| 80 // This GrAutoScratchTexture has a ref from lockAndRefScratchTexture, which
we give up now. |
| 81 // The cache also has a ref which we are lending to the caller of detach().
When the caller |
| 82 // lets go of the ref and the ref count goes to 0 internal_dispose will see
this flag is |
| 83 // set and re-ref the texture, thereby restoring the cache's ref. |
| 84 SkASSERT(!texture->unique()); |
| 85 texture->texturePriv().setFlag((GrTextureFlags) GrTexture::kReturnToCache_Fl
agBit); |
| 86 texture->unref(); |
| 87 SkASSERT(texture->getCacheEntry()); |
| 88 |
| 89 return texture; |
| 90 } |
| 91 |
73 // Glorified typedef to avoid including GrDrawState.h in GrContext.h | 92 // Glorified typedef to avoid including GrDrawState.h in GrContext.h |
74 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; | 93 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; |
75 | 94 |
76 class GrContext::AutoCheckFlush { | 95 class GrContext::AutoCheckFlush { |
77 public: | 96 public: |
78 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | 97 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} |
79 | 98 |
80 ~AutoCheckFlush() { | 99 ~AutoCheckFlush() { |
81 if (fContext->fFlushToReduceCacheSize) { | 100 if (fContext->fFlushToReduceCacheSize) { |
82 fContext->flush(); | 101 fContext->flush(); |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
433 fResourceCache->addResource(resourceKey, texture); | 452 fResourceCache->addResource(resourceKey, texture); |
434 | 453 |
435 if (cacheKey) { | 454 if (cacheKey) { |
436 *cacheKey = resourceKey; | 455 *cacheKey = resourceKey; |
437 } | 456 } |
438 } | 457 } |
439 | 458 |
440 return texture; | 459 return texture; |
441 } | 460 } |
442 | 461 |
443 bool GrContext::createNewScratchTexture(const GrTextureDesc& desc) { | 462 static GrTexture* create_scratch_texture(GrGpu* gpu, |
444 SkAutoTUnref<GrTexture> texture(fGpu->createTexture(desc, NULL, 0)); | 463 GrResourceCache* resourceCache, |
445 if (!texture) { | 464 const GrTextureDesc& desc) { |
446 return false; | 465 GrTexture* texture = gpu->createTexture(desc, NULL, 0); |
| 466 if (texture) { |
| 467 GrResourceKey key = GrTexturePriv::ComputeScratchKey(texture->desc()); |
| 468 // Adding a resource could put us overbudget. Try to free up the |
| 469 // necessary space before adding it. |
| 470 resourceCache->purgeAsNeeded(1, texture->gpuMemorySize()); |
| 471 // Make the resource exclusive so future 'find' calls don't return it |
| 472 resourceCache->addResource(key, texture, GrResourceCache::kHide_Ownershi
pFlag); |
447 } | 473 } |
448 fResourceCache->addResource(texture->getScratchKey(), texture); | 474 return texture; |
449 texture->fIsScratch = GrIORef::kYes_IsScratch; | |
450 return true; | |
451 } | 475 } |
452 | 476 |
453 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
tchTexMatch match) { | 477 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
tchTexMatch match) { |
454 | 478 |
455 // kNoStencil has no meaning if kRT isn't set. | |
456 SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || | 479 SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
457 !(inDesc.fFlags & kNoStencil_GrTextureFlagBit)); | 480 !(inDesc.fFlags & kNoStencil_GrTextureFlagBit)); |
458 | 481 |
459 // Make sure caller has checked for renderability if kRT is set. | 482 // Renderable A8 targets are not universally supported (e.g., not on ANGLE) |
460 SkASSERT(!(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || | 483 SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt
> 0) || |
461 this->isConfigRenderable(inDesc.fConfig, inDesc.fSampleCnt > 0)); | 484 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
| 485 (inDesc.fConfig != kAlpha_8_GrPixelConfig)); |
462 | 486 |
463 SkTCopyOnFirstWrite<GrTextureDesc> desc(inDesc); | 487 if (!fGpu->caps()->reuseScratchTextures() && |
| 488 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) { |
| 489 // If we're never recycling this texture we can always make it the right
size |
| 490 return create_scratch_texture(fGpu, fResourceCache, inDesc); |
| 491 } |
464 | 492 |
465 // There is a regression here in that when reuseScratchTextures is false, th
e texture won't be | 493 GrTextureDesc desc = inDesc; |
466 // freed when its ref and io counts reach zero. TODO: Make GrResourceCache2
free scratch | 494 |
467 // resources immediately after it is the sole owner and reuseScratchTextures
is false. | 495 if (kApprox_ScratchTexMatch == match) { |
468 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_Gr
TextureFlagBit)) { | 496 // bin by pow2 with a reasonable min |
469 GrTextureFlags origFlags = desc->fFlags; | 497 static const int MIN_SIZE = 16; |
470 if (kApprox_ScratchTexMatch == match) { | 498 desc.fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc.fWidth)); |
471 // bin by pow2 with a reasonable min | 499 desc.fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc.fHeight)); |
472 static const int MIN_SIZE = 16; | 500 } |
473 GrTextureDesc* wdesc = desc.writable(); | 501 |
474 wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth)); | 502 GrGpuResource* resource = NULL; |
475 wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight)); | 503 int origWidth = desc.fWidth; |
| 504 int origHeight = desc.fHeight; |
| 505 |
| 506 do { |
| 507 GrResourceKey key = GrTexturePriv::ComputeScratchKey(desc); |
| 508 // Ensure we have exclusive access to the texture so future 'find' calls
don't return it |
| 509 resource = fResourceCache->find(key, GrResourceCache::kHide_OwnershipFla
g); |
| 510 if (resource) { |
| 511 resource->ref(); |
| 512 break; |
| 513 } |
| 514 if (kExact_ScratchTexMatch == match) { |
| 515 break; |
| 516 } |
| 517 // We had a cache miss and we are in approx mode, relax the fit of the f
lags. |
| 518 |
| 519 // We no longer try to reuse textures that were previously used as rende
r targets in |
| 520 // situations where no RT is needed; doing otherwise can confuse the vid
eo driver and |
| 521 // cause significant performance problems in some cases. |
| 522 if (desc.fFlags & kNoStencil_GrTextureFlagBit) { |
| 523 desc.fFlags = desc.fFlags & ~kNoStencil_GrTextureFlagBit; |
| 524 } else { |
| 525 break; |
476 } | 526 } |
477 | 527 |
478 do { | 528 } while (true); |
479 GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); | |
480 GrGpuResource* resource = fResourceCache2->findAndRefScratchResource
(key); | |
481 if (resource) { | |
482 fResourceCache->makeResourceMRU(resource); | |
483 return static_cast<GrTexture*>(resource); | |
484 } | |
485 | 529 |
486 if (kExact_ScratchTexMatch == match) { | 530 if (NULL == resource) { |
487 break; | 531 desc.fFlags = inDesc.fFlags; |
488 } | 532 desc.fWidth = origWidth; |
489 // We had a cache miss and we are in approx mode, relax the fit of t
he flags. | 533 desc.fHeight = origHeight; |
490 | 534 resource = create_scratch_texture(fGpu, fResourceCache, desc); |
491 // We no longer try to reuse textures that were previously used as r
ender targets in | |
492 // situations where no RT is needed; doing otherwise can confuse the
video driver and | |
493 // cause significant performance problems in some cases. | |
494 if (desc->fFlags & kNoStencil_GrTextureFlagBit) { | |
495 desc.writable()->fFlags = desc->fFlags & ~kNoStencil_GrTextureFl
agBit; | |
496 } else { | |
497 break; | |
498 } | |
499 | |
500 } while (true); | |
501 | |
502 desc.writable()->fFlags = origFlags; | |
503 } | 535 } |
504 | 536 |
505 if (!this->createNewScratchTexture(*desc)) { | |
506 return NULL; | |
507 } | |
508 | |
509 // If we got here then we didn't find a cached texture, but we just added on
e. | |
510 GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); | |
511 GrGpuResource* resource = fResourceCache2->findAndRefScratchResource(key); | |
512 SkASSERT(resource); | |
513 return static_cast<GrTexture*>(resource); | 537 return static_cast<GrTexture*>(resource); |
514 } | 538 } |
515 | 539 |
| 540 void GrContext::addExistingTextureToCache(GrTexture* texture) { |
| 541 |
| 542 if (NULL == texture) { |
| 543 return; |
| 544 } |
| 545 |
| 546 // This texture should already have a cache entry since it was once |
| 547 // attached |
| 548 SkASSERT(texture->getCacheEntry()); |
| 549 |
| 550 // Conceptually, the cache entry is going to assume responsibility |
| 551 // for the creation ref. Assert refcnt == 1. |
| 552 // Except that this also gets called when the texture is prematurely |
| 553 // abandoned. In that case the ref count may be > 1. |
| 554 // SkASSERT(texture->unique()); |
| 555 |
| 556 if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) { |
| 557 // Since this texture came from an AutoScratchTexture it should |
| 558 // still be in the exclusive pile. Recycle it. |
| 559 fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
| 560 this->purgeCache(); |
| 561 } else { |
| 562 // When we aren't reusing textures we know this scratch texture |
| 563 // will never be reused and would be just wasting time in the cache |
| 564 fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
| 565 fResourceCache->deleteResource(texture->getCacheEntry()); |
| 566 } |
| 567 } |
| 568 |
| 569 void GrContext::unlockScratchTexture(GrTexture* texture) { |
| 570 if (texture->wasDestroyed()) { |
| 571 if (texture->getCacheEntry()->key().isScratch()) { |
| 572 // This texture was detached from the cache but the cache still had
a ref to it but |
| 573 // not a pointer to it. This will unref the texture and delete its r
esource cache |
| 574 // entry. |
| 575 delete texture->getCacheEntry(); |
| 576 } |
| 577 return; |
| 578 } |
| 579 |
| 580 ASSERT_OWNED_RESOURCE(texture); |
| 581 SkASSERT(texture->getCacheEntry()); |
| 582 |
| 583 // If this is a scratch texture we detached it from the cache |
| 584 // while it was locked (to avoid two callers simultaneously getting |
| 585 // the same texture). |
| 586 if (texture->getCacheEntry()->key().isScratch()) { |
| 587 if (fGpu->caps()->reuseScratchTextures() || texture->asRenderTarget()) { |
| 588 fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
| 589 this->purgeCache(); |
| 590 } else if (texture->unique()) { |
| 591 // Only the cache now knows about this texture. Since we're never |
| 592 // reusing scratch textures (in this code path) it would just be |
| 593 // wasting time sitting in the cache. |
| 594 fResourceCache->makeNonExclusive(texture->getCacheEntry()); |
| 595 fResourceCache->deleteResource(texture->getCacheEntry()); |
| 596 } else { |
| 597 // In this case (there is still a non-cache ref) but we don't really |
| 598 // want to readd it to the cache (since it will never be reused). |
| 599 // Instead, give up the cache's ref and leave the decision up to |
| 600 // addExistingTextureToCache once its ref count reaches 0. For |
| 601 // this to work we need to leave it in the exclusive list. |
| 602 texture->texturePriv().setFlag((GrTextureFlags) GrTexture::kReturnTo
Cache_FlagBit); |
| 603 // Give up the cache's ref to the texture |
| 604 texture->unref(); |
| 605 } |
| 606 } |
| 607 } |
| 608 |
| 609 void GrContext::purgeCache() { |
| 610 if (fResourceCache) { |
| 611 fResourceCache->purgeAsNeeded(); |
| 612 } |
| 613 } |
| 614 |
516 bool GrContext::OverbudgetCB(void* data) { | 615 bool GrContext::OverbudgetCB(void* data) { |
517 SkASSERT(data); | 616 SkASSERT(data); |
518 | 617 |
519 GrContext* context = reinterpret_cast<GrContext*>(data); | 618 GrContext* context = reinterpret_cast<GrContext*>(data); |
520 | 619 |
521 // Flush the InOrderDrawBuffer to possibly free up some textures | 620 // Flush the InOrderDrawBuffer to possibly free up some textures |
522 context->fFlushToReduceCacheSize = true; | 621 context->fFlushToReduceCacheSize = true; |
523 | 622 |
524 return true; | 623 return true; |
525 } | 624 } |
(...skipping 1329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1855 fResourceCache->printStats(); | 1954 fResourceCache->printStats(); |
1856 } | 1955 } |
1857 #endif | 1956 #endif |
1858 | 1957 |
1859 #if GR_GPU_STATS | 1958 #if GR_GPU_STATS |
1860 const GrContext::GPUStats* GrContext::gpuStats() const { | 1959 const GrContext::GPUStats* GrContext::gpuStats() const { |
1861 return fGpu->gpuStats(); | 1960 return fGpu->gpuStats(); |
1862 } | 1961 } |
1863 #endif | 1962 #endif |
1864 | 1963 |
OLD | NEW |