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 | |
92 // Glorified typedef to avoid including GrDrawState.h in GrContext.h | 73 // Glorified typedef to avoid including GrDrawState.h in GrContext.h |
93 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; | 74 class GrContext::AutoRestoreEffects : public GrDrawState::AutoRestoreEffects {}; |
94 | 75 |
95 class GrContext::AutoCheckFlush { | 76 class GrContext::AutoCheckFlush { |
96 public: | 77 public: |
97 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | 78 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} |
98 | 79 |
99 ~AutoCheckFlush() { | 80 ~AutoCheckFlush() { |
100 if (fContext->fFlushToReduceCacheSize) { | 81 if (fContext->fFlushToReduceCacheSize) { |
101 fContext->flush(); | 82 fContext->flush(); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 SkASSERT(NULL == fGpu); | 127 SkASSERT(NULL == fGpu); |
147 | 128 |
148 fGpu = GrGpu::Create(backend, backendContext, this); | 129 fGpu = GrGpu::Create(backend, backendContext, this); |
149 if (NULL == fGpu) { | 130 if (NULL == fGpu) { |
150 return false; | 131 return false; |
151 } | 132 } |
152 | 133 |
153 fDrawState = SkNEW(GrDrawState); | 134 fDrawState = SkNEW(GrDrawState); |
154 fGpu->setDrawState(fDrawState); | 135 fGpu->setDrawState(fDrawState); |
155 | 136 |
156 fResourceCache = SkNEW_ARGS(GrResourceCache, (MAX_RESOURCE_CACHE_COUNT, | 137 fResourceCache = SkNEW_ARGS(GrResourceCache, (fGpu->caps(), |
| 138 MAX_RESOURCE_CACHE_COUNT, |
157 MAX_RESOURCE_CACHE_BYTES)); | 139 MAX_RESOURCE_CACHE_BYTES)); |
158 fResourceCache->setOverbudgetCallback(OverbudgetCB, this); | 140 fResourceCache->setOverbudgetCallback(OverbudgetCB, this); |
159 fResourceCache2 = SkNEW(GrResourceCache2); | 141 fResourceCache2 = SkNEW(GrResourceCache2); |
160 | 142 |
161 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu)); | 143 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu)); |
162 | 144 |
163 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); | 145 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this))); |
164 | 146 |
165 fLastDrawWasBuffered = kNo_BufferedDraw; | 147 fLastDrawWasBuffered = kNo_BufferedDraw; |
166 | 148 |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); | 421 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig)); |
440 | 422 |
441 texture = this->createResizedTexture(desc, cacheID, | 423 texture = this->createResizedTexture(desc, cacheID, |
442 srcData, rowBytes, | 424 srcData, rowBytes, |
443 GrTexturePriv::NeedsBilerp(resource
Key)); | 425 GrTexturePriv::NeedsBilerp(resource
Key)); |
444 } else { | 426 } else { |
445 texture = fGpu->createTexture(desc, srcData, rowBytes); | 427 texture = fGpu->createTexture(desc, srcData, rowBytes); |
446 } | 428 } |
447 | 429 |
448 if (texture) { | 430 if (texture) { |
449 // Adding a resource could put us overbudget. Try to free up the | |
450 // necessary space before adding it. | |
451 fResourceCache->purgeAsNeeded(1, texture->gpuMemorySize()); | |
452 fResourceCache->addResource(resourceKey, texture); | 431 fResourceCache->addResource(resourceKey, texture); |
453 | 432 |
454 if (cacheKey) { | 433 if (cacheKey) { |
455 *cacheKey = resourceKey; | 434 *cacheKey = resourceKey; |
456 } | 435 } |
457 } | 436 } |
458 | 437 |
459 return texture; | 438 return texture; |
460 } | 439 } |
461 | 440 |
462 static GrTexture* create_scratch_texture(GrGpu* gpu, | 441 GrTexture* GrContext::createNewScratchTexture(const GrTextureDesc& desc) { |
463 GrResourceCache* resourceCache, | 442 GrTexture* texture = fGpu->createTexture(desc, NULL, 0); |
464 const GrTextureDesc& desc) { | 443 if (!texture) { |
465 GrTexture* texture = gpu->createTexture(desc, NULL, 0); | 444 return NULL; |
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); | |
473 } | 445 } |
| 446 fResourceCache->addResource(texture->getScratchKey(), texture); |
| 447 texture->fIsScratch = GrGpuResource::kYes_IsScratch; |
474 return texture; | 448 return texture; |
475 } | 449 } |
476 | 450 |
477 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
tchTexMatch match) { | 451 GrTexture* GrContext::lockAndRefScratchTexture(const GrTextureDesc& inDesc, Scra
tchTexMatch match, |
| 452 bool calledDuringFlush) { |
478 | 453 |
| 454 // kNoStencil has no meaning if kRT isn't set. |
479 SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || | 455 SkASSERT((inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
480 !(inDesc.fFlags & kNoStencil_GrTextureFlagBit)); | 456 !(inDesc.fFlags & kNoStencil_GrTextureFlagBit)); |
481 | 457 |
482 // Renderable A8 targets are not universally supported (e.g., not on ANGLE) | 458 // Make sure caller has checked for renderability if kRT is set. |
483 SkASSERT(this->isConfigRenderable(kAlpha_8_GrPixelConfig, inDesc.fSampleCnt
> 0) || | 459 SkASSERT(!(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || |
484 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit) || | 460 this->isConfigRenderable(inDesc.fConfig, inDesc.fSampleCnt > 0)); |
485 (inDesc.fConfig != kAlpha_8_GrPixelConfig)); | |
486 | 461 |
487 if (!fGpu->caps()->reuseScratchTextures() && | 462 SkTCopyOnFirstWrite<GrTextureDesc> desc(inDesc); |
488 !(inDesc.fFlags & kRenderTarget_GrTextureFlagBit)) { | 463 |
489 // If we're never recycling this texture we can always make it the right
size | 464 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_Gr
TextureFlagBit)) { |
490 return create_scratch_texture(fGpu, fResourceCache, inDesc); | 465 GrTextureFlags origFlags = desc->fFlags; |
| 466 if (kApprox_ScratchTexMatch == match) { |
| 467 // bin by pow2 with a reasonable min |
| 468 static const int MIN_SIZE = 16; |
| 469 GrTextureDesc* wdesc = desc.writable(); |
| 470 wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth)); |
| 471 wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight)); |
| 472 } |
| 473 |
| 474 do { |
| 475 GrResourceKey key = GrTexturePriv::ComputeScratchKey(*desc); |
| 476 GrGpuResource* resource = fResourceCache2->findAndRefScratchResource
(key, |
| 477
calledDuringFlush); |
| 478 if (resource) { |
| 479 fResourceCache->makeResourceMRU(resource); |
| 480 return static_cast<GrTexture*>(resource); |
| 481 } |
| 482 |
| 483 if (kExact_ScratchTexMatch == match) { |
| 484 break; |
| 485 } |
| 486 // We had a cache miss and we are in approx mode, relax the fit of t
he flags. |
| 487 |
| 488 // We no longer try to reuse textures that were previously used as r
ender targets in |
| 489 // situations where no RT is needed; doing otherwise can confuse the
video driver and |
| 490 // cause significant performance problems in some cases. |
| 491 if (desc->fFlags & kNoStencil_GrTextureFlagBit) { |
| 492 desc.writable()->fFlags = desc->fFlags & ~kNoStencil_GrTextureFl
agBit; |
| 493 } else { |
| 494 break; |
| 495 } |
| 496 |
| 497 } while (true); |
| 498 |
| 499 desc.writable()->fFlags = origFlags; |
491 } | 500 } |
492 | 501 |
493 GrTextureDesc desc = inDesc; | 502 GrTexture* texture = this->createNewScratchTexture(*desc); |
494 | 503 SkASSERT(NULL == texture || |
495 if (kApprox_ScratchTexMatch == match) { | 504 texture->getScratchKey() == GrTexturePriv::ComputeScratchKey(*desc)
); |
496 // bin by pow2 with a reasonable min | 505 return texture; |
497 static const int MIN_SIZE = 16; | |
498 desc.fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc.fWidth)); | |
499 desc.fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc.fHeight)); | |
500 } | |
501 | |
502 GrGpuResource* resource = NULL; | |
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; | |
526 } | |
527 | |
528 } while (true); | |
529 | |
530 if (NULL == resource) { | |
531 desc.fFlags = inDesc.fFlags; | |
532 desc.fWidth = origWidth; | |
533 desc.fHeight = origHeight; | |
534 resource = create_scratch_texture(fGpu, fResourceCache, desc); | |
535 } | |
536 | |
537 return static_cast<GrTexture*>(resource); | |
538 } | |
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 } | 506 } |
614 | 507 |
615 bool GrContext::OverbudgetCB(void* data) { | 508 bool GrContext::OverbudgetCB(void* data) { |
616 SkASSERT(data); | 509 SkASSERT(data); |
617 | 510 |
618 GrContext* context = reinterpret_cast<GrContext*>(data); | 511 GrContext* context = reinterpret_cast<GrContext*>(data); |
619 | 512 |
620 // Flush the InOrderDrawBuffer to possibly free up some textures | 513 // Flush the InOrderDrawBuffer to possibly free up some textures |
621 context->fFlushToReduceCacheSize = true; | 514 context->fFlushToReduceCacheSize = true; |
622 | 515 |
(...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1342 void GrContext::flush(int flagsBitfield) { | 1235 void GrContext::flush(int flagsBitfield) { |
1343 if (NULL == fDrawBuffer) { | 1236 if (NULL == fDrawBuffer) { |
1344 return; | 1237 return; |
1345 } | 1238 } |
1346 | 1239 |
1347 if (kDiscard_FlushBit & flagsBitfield) { | 1240 if (kDiscard_FlushBit & flagsBitfield) { |
1348 fDrawBuffer->reset(); | 1241 fDrawBuffer->reset(); |
1349 } else { | 1242 } else { |
1350 fDrawBuffer->flush(); | 1243 fDrawBuffer->flush(); |
1351 } | 1244 } |
| 1245 fResourceCache->purgeAsNeeded(); |
1352 fFlushToReduceCacheSize = false; | 1246 fFlushToReduceCacheSize = false; |
1353 } | 1247 } |
1354 | 1248 |
1355 bool GrContext::writeTexturePixels(GrTexture* texture, | 1249 bool GrContext::writeTexturePixels(GrTexture* texture, |
1356 int left, int top, int width, int height, | 1250 int left, int top, int width, int height, |
1357 GrPixelConfig config, const void* buffer, siz
e_t rowBytes, | 1251 GrPixelConfig config, const void* buffer, siz
e_t rowBytes, |
1358 uint32_t flags) { | 1252 uint32_t flags) { |
1359 ASSERT_OWNED_RESOURCE(texture); | 1253 ASSERT_OWNED_RESOURCE(texture); |
1360 | 1254 |
1361 if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture
, config)) { | 1255 if ((kUnpremul_PixelOpsFlag & flags) || !fGpu->canWriteTexturePixels(texture
, config)) { |
(...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1934 GrConfigConversionEffect::PMConversion upmToPM = | 1828 GrConfigConversionEffect::PMConversion upmToPM = |
1935 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); | 1829 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); |
1936 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { | 1830 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { |
1937 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, mat
rix); | 1831 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, mat
rix); |
1938 } else { | 1832 } else { |
1939 return NULL; | 1833 return NULL; |
1940 } | 1834 } |
1941 } | 1835 } |
1942 | 1836 |
1943 void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResour
ce* resource) { | 1837 void GrContext::addResourceToCache(const GrResourceKey& resourceKey, GrGpuResour
ce* resource) { |
1944 fResourceCache->purgeAsNeeded(1, resource->gpuMemorySize()); | |
1945 fResourceCache->addResource(resourceKey, resource); | 1838 fResourceCache->addResource(resourceKey, resource); |
1946 } | 1839 } |
1947 | 1840 |
1948 GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resource
Key) { | 1841 GrGpuResource* GrContext::findAndRefCachedResource(const GrResourceKey& resource
Key) { |
1949 GrGpuResource* resource = fResourceCache->find(resourceKey); | 1842 GrGpuResource* resource = fResourceCache->find(resourceKey); |
1950 SkSafeRef(resource); | 1843 SkSafeRef(resource); |
1951 return resource; | 1844 return resource; |
1952 } | 1845 } |
1953 | 1846 |
1954 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { | 1847 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) { |
(...skipping 16 matching lines...) Expand all Loading... |
1971 fResourceCache->printStats(); | 1864 fResourceCache->printStats(); |
1972 } | 1865 } |
1973 #endif | 1866 #endif |
1974 | 1867 |
1975 #if GR_GPU_STATS | 1868 #if GR_GPU_STATS |
1976 const GrContext::GPUStats* GrContext::gpuStats() const { | 1869 const GrContext::GPUStats* GrContext::gpuStats() const { |
1977 return fGpu->gpuStats(); | 1870 return fGpu->gpuStats(); |
1978 } | 1871 } |
1979 #endif | 1872 #endif |
1980 | 1873 |
OLD | NEW |