GrGpuResource.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /*
  2. * Copyright 2011 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/core/SkTraceMemoryDump.h"
  8. #include "include/gpu/GrContext.h"
  9. #include "include/gpu/GrGpuResource.h"
  10. #include "src/gpu/GrContextPriv.h"
  11. #include "src/gpu/GrGpu.h"
  12. #include "src/gpu/GrGpuResourcePriv.h"
  13. #include "src/gpu/GrResourceCache.h"
  14. #include <atomic>
  15. static inline GrResourceCache* get_resource_cache(GrGpu* gpu) {
  16. SkASSERT(gpu);
  17. SkASSERT(gpu->getContext());
  18. SkASSERT(gpu->getContext()->priv().getResourceCache());
  19. return gpu->getContext()->priv().getResourceCache();
  20. }
  21. GrGpuResource::GrGpuResource(GrGpu* gpu) : fGpu(gpu), fUniqueID(CreateUniqueID()) {
  22. SkDEBUGCODE(fCacheArrayIndex = -1);
  23. }
  24. void GrGpuResource::registerWithCache(SkBudgeted budgeted) {
  25. SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
  26. fBudgetedType = budgeted == SkBudgeted::kYes ? GrBudgetedType::kBudgeted
  27. : GrBudgetedType::kUnbudgetedUncacheable;
  28. this->computeScratchKey(&fScratchKey);
  29. get_resource_cache(fGpu)->resourceAccess().insertResource(this);
  30. }
  31. void GrGpuResource::registerWithCacheWrapped(GrWrapCacheable wrapType) {
  32. SkASSERT(fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable);
  33. // Resources referencing wrapped objects are never budgeted. They may be cached or uncached.
  34. fBudgetedType = wrapType == GrWrapCacheable::kNo ? GrBudgetedType::kUnbudgetedUncacheable
  35. : GrBudgetedType::kUnbudgetedCacheable;
  36. fRefsWrappedObjects = true;
  37. get_resource_cache(fGpu)->resourceAccess().insertResource(this);
  38. }
  39. GrGpuResource::~GrGpuResource() {
  40. // The cache should have released or destroyed this resource.
  41. SkASSERT(this->wasDestroyed());
  42. }
  43. void GrGpuResource::release() {
  44. SkASSERT(fGpu);
  45. this->onRelease();
  46. get_resource_cache(fGpu)->resourceAccess().removeResource(this);
  47. fGpu = nullptr;
  48. fGpuMemorySize = 0;
  49. }
  50. void GrGpuResource::abandon() {
  51. if (this->wasDestroyed()) {
  52. return;
  53. }
  54. SkASSERT(fGpu);
  55. this->onAbandon();
  56. get_resource_cache(fGpu)->resourceAccess().removeResource(this);
  57. fGpu = nullptr;
  58. fGpuMemorySize = 0;
  59. }
  60. void GrGpuResource::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
  61. if (this->fRefsWrappedObjects && !traceMemoryDump->shouldDumpWrappedObjects()) {
  62. return;
  63. }
  64. this->dumpMemoryStatisticsPriv(traceMemoryDump, this->getResourceName(),
  65. this->getResourceType(), this->gpuMemorySize());
  66. }
  67. void GrGpuResource::dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump,
  68. const SkString& resourceName,
  69. const char* type, size_t size) const {
  70. const char* tag = "Scratch";
  71. if (fUniqueKey.isValid()) {
  72. tag = (fUniqueKey.tag() != nullptr) ? fUniqueKey.tag() : "Other";
  73. }
  74. traceMemoryDump->dumpNumericValue(resourceName.c_str(), "size", "bytes", size);
  75. traceMemoryDump->dumpStringValue(resourceName.c_str(), "type", type);
  76. traceMemoryDump->dumpStringValue(resourceName.c_str(), "category", tag);
  77. if (this->isPurgeable()) {
  78. traceMemoryDump->dumpNumericValue(resourceName.c_str(), "purgeable_size", "bytes", size);
  79. }
  80. this->setMemoryBacking(traceMemoryDump, resourceName);
  81. }
  82. bool GrGpuResource::isPurgeable() const {
  83. // Resources in the kUnbudgetedCacheable state are never purgeable when they have a unique
  84. // key. The key must be removed/invalidated to make them purgeable.
  85. return !this->hasRefOrPendingIO() &&
  86. !(fBudgetedType == GrBudgetedType::kUnbudgetedCacheable && fUniqueKey.isValid());
  87. }
  88. bool GrGpuResource::hasRefOrPendingIO() const {
  89. return this->internalHasRef() || this->internalHasPendingIO();
  90. }
  91. bool GrGpuResource::hasRef() const { return this->internalHasRef(); }
  92. SkString GrGpuResource::getResourceName() const {
  93. // Dump resource as "skia/gpu_resources/resource_#".
  94. SkString resourceName("skia/gpu_resources/resource_");
  95. resourceName.appendU32(this->uniqueID().asUInt());
  96. return resourceName;
  97. }
  98. const GrContext* GrGpuResource::getContext() const {
  99. if (fGpu) {
  100. return fGpu->getContext();
  101. } else {
  102. return nullptr;
  103. }
  104. }
  105. GrContext* GrGpuResource::getContext() {
  106. if (fGpu) {
  107. return fGpu->getContext();
  108. } else {
  109. return nullptr;
  110. }
  111. }
  112. void GrGpuResource::removeUniqueKey() {
  113. if (this->wasDestroyed()) {
  114. return;
  115. }
  116. SkASSERT(fUniqueKey.isValid());
  117. get_resource_cache(fGpu)->resourceAccess().removeUniqueKey(this);
  118. }
  119. void GrGpuResource::setUniqueKey(const GrUniqueKey& key) {
  120. SkASSERT(this->internalHasRef());
  121. SkASSERT(key.isValid());
  122. // Uncached resources can never have a unique key, unless they're wrapped resources. Wrapped
  123. // resources are a special case: the unique keys give us a weak ref so that we can reuse the
  124. // same resource (rather than re-wrapping). When a wrapped resource is no longer referenced,
  125. // it will always be released - it is never converted to a scratch resource.
  126. if (this->resourcePriv().budgetedType() != GrBudgetedType::kBudgeted &&
  127. !this->fRefsWrappedObjects) {
  128. return;
  129. }
  130. if (this->wasDestroyed()) {
  131. return;
  132. }
  133. get_resource_cache(fGpu)->resourceAccess().changeUniqueKey(this, key);
  134. }
  135. void GrGpuResource::notifyAllCntsWillBeZero() const {
  136. GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
  137. mutableThis->willRemoveLastRefOrPendingIO();
  138. }
  139. void GrGpuResource::notifyAllCntsAreZero(CntType lastCntTypeToReachZero) const {
  140. if (this->wasDestroyed()) {
  141. // We've already been removed from the cache. Goodbye cruel world!
  142. delete this;
  143. return;
  144. }
  145. // We should have already handled this fully in notifyRefCntIsZero().
  146. SkASSERT(kRef_CntType != lastCntTypeToReachZero);
  147. static const uint32_t kFlag =
  148. GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
  149. GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
  150. get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, kFlag);
  151. }
  152. bool GrGpuResource::notifyRefCountIsZero() const {
  153. if (this->wasDestroyed()) {
  154. // handle this in notifyAllCntsAreZero().
  155. return true;
  156. }
  157. GrGpuResource* mutableThis = const_cast<GrGpuResource*>(this);
  158. uint32_t flags = GrResourceCache::ResourceAccess::kRefCntReachedZero_RefNotificationFlag;
  159. if (!this->internalHasPendingIO()) {
  160. flags |= GrResourceCache::ResourceAccess::kAllCntsReachedZero_RefNotificationFlag;
  161. }
  162. get_resource_cache(fGpu)->resourceAccess().notifyCntReachedZero(mutableThis, flags);
  163. // There is no need to call our notifyAllCntsAreZero function at this point since we already
  164. // told the cache about the state of cnts.
  165. return false;
  166. }
  167. void GrGpuResource::removeScratchKey() {
  168. if (!this->wasDestroyed() && fScratchKey.isValid()) {
  169. get_resource_cache(fGpu)->resourceAccess().willRemoveScratchKey(this);
  170. fScratchKey.reset();
  171. }
  172. }
  173. void GrGpuResource::makeBudgeted() {
  174. // We should never make a wrapped resource budgeted.
  175. SkASSERT(!fRefsWrappedObjects);
  176. // Only wrapped resources can be in the kUnbudgetedCacheable state.
  177. SkASSERT(fBudgetedType != GrBudgetedType::kUnbudgetedCacheable);
  178. if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kUnbudgetedUncacheable) {
  179. // Currently resources referencing wrapped objects are not budgeted.
  180. fBudgetedType = GrBudgetedType::kBudgeted;
  181. get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
  182. }
  183. }
  184. void GrGpuResource::makeUnbudgeted() {
  185. if (!this->wasDestroyed() && fBudgetedType == GrBudgetedType::kBudgeted &&
  186. !fUniqueKey.isValid()) {
  187. fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
  188. get_resource_cache(fGpu)->resourceAccess().didChangeBudgetStatus(this);
  189. }
  190. }
  191. uint32_t GrGpuResource::CreateUniqueID() {
  192. static std::atomic<uint32_t> nextID{1};
  193. uint32_t id;
  194. do {
  195. id = nextID++;
  196. } while (id == SK_InvalidUniqueID);
  197. return id;
  198. }
  199. //////////////////////////////////////////////////////////////////////////////
  200. void GrGpuResource::ProxyAccess::ref(GrResourceCache* cache) {
  201. SkASSERT(cache == fResource->getContext()->priv().getResourceCache());
  202. cache->resourceAccess().refResource(fResource);
  203. }