1 /* 2 * Copyright 2014 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 8 #ifndef GrGpuResourceCacheAccess_DEFINED 9 #define GrGpuResourceCacheAccess_DEFINED 10 11 #include "src/gpu/GrGpuResource.h" 12 #include "src/gpu/GrGpuResourcePriv.h" 13 14 namespace skiatest { 15 class Reporter; 16 } // namespace skiatest 17 IsValidAddress(GrGpuResource * ptr)18static inline bool IsValidAddress(GrGpuResource* ptr) 19 { 20 #if defined(__aarch64__) 21 static constexpr uint64_t HWASAN_HEADER = 0xFF00000000000000u; 22 static constexpr uint64_t HIGH_BOUND = 0x8000000000u; 23 static constexpr uint64_t LOW_BOUND = 0x1000u; 24 uint64_t memory = reinterpret_cast<uint64_t>(ptr); 25 uint64_t real = (memory & ~HWASAN_HEADER); 26 return (LOW_BOUND < real) && (real < HIGH_BOUND) && ptr->checkMagic(); 27 #else 28 return true; 29 #endif 30 } 31 32 /** 33 * This class allows GrResourceCache increased privileged access to GrGpuResource objects. 34 */ 35 class GrGpuResource::CacheAccess { 36 private: 37 /** The cache is allowed to go from no refs to 1 ref. */ ref()38 void ref() 39 { 40 if (IsValidAddress(fResource)) fResource->addInitialRef(); 41 } 42 43 /** 44 * Is the resource currently cached as scratch? This means it is cached, has a valid scratch 45 * key, and does not have a unique key. 46 */ isScratch()47 bool isScratch() const { 48 return IsValidAddress(fResource) && !fResource->getUniqueKey().isValid() && fResource->fScratchKey.isValid() && 49 GrBudgetedType::kBudgeted == fResource->resourcePriv().budgetedType(); 50 } 51 isUsableAsScratch()52 bool isUsableAsScratch() const { 53 return this->isScratch() && !fResource->internalHasRef(); 54 } 55 56 /** 57 * Called by the cache to delete the resource under normal circumstances. 58 */ release()59 void release() { 60 if (!IsValidAddress(fResource)) { 61 return; 62 } 63 fResource->release(); 64 if (!fResource->hasRef() && fResource->hasNoCommandBufferUsages()) { 65 if (!IsValidAddress(fResource)) { 66 return; 67 } 68 delete fResource; 69 fResource = nullptr; 70 } 71 } 72 73 /** 74 * Called by the cache to delete the resource when the backend 3D context is no longer valid. 75 */ abandon()76 void abandon() { 77 if (!IsValidAddress(fResource)) { 78 return; 79 } 80 fResource->abandon(); 81 if (!fResource->hasRef() && fResource->hasNoCommandBufferUsages()) { 82 if (!IsValidAddress(fResource)) { 83 return; 84 } 85 delete fResource; 86 } 87 } 88 89 /** Called by the cache to assign a new unique key. */ setUniqueKey(const GrUniqueKey & key)90 void setUniqueKey(const GrUniqueKey& key) 91 { 92 if (IsValidAddress(fResource)) fResource->fUniqueKey = key; 93 } 94 95 /** Is the resource ref'ed */ hasRef()96 bool hasRef() const { return IsValidAddress(fResource) && fResource->hasRef(); } hasRefOrCommandBufferUsage()97 bool hasRefOrCommandBufferUsage() const { 98 return this->hasRef() || (IsValidAddress(fResource) && !fResource->hasNoCommandBufferUsages()); 99 } 100 101 /** Called by the cache to make the unique key invalid. */ removeUniqueKey()102 void removeUniqueKey() 103 { 104 if (IsValidAddress(fResource)) fResource->fUniqueKey.reset(); 105 } 106 timestamp()107 uint32_t timestamp() const { return IsValidAddress(fResource) ? fResource->fTimestamp : 0; } setTimestamp(uint32_t ts)108 void setTimestamp(uint32_t ts) 109 { 110 if (IsValidAddress(fResource)) fResource->fTimestamp = ts; 111 } 112 setTimeWhenResourceBecomePurgeable()113 void setTimeWhenResourceBecomePurgeable() { 114 SkASSERT(fResource->isPurgeable()); 115 if (IsValidAddress(fResource)) { 116 fResource->fTimeWhenBecamePurgeable = GrStdSteadyClock::now(); 117 } 118 } 119 /** 120 * Called by the cache to determine whether this resource should be purged based on the length 121 * of time it has been available for purging. 122 */ timeWhenResourceBecamePurgeable()123 GrStdSteadyClock::time_point timeWhenResourceBecamePurgeable() { 124 SkASSERT(fResource->isPurgeable()); 125 return IsValidAddress(fResource) ? fResource->fTimeWhenBecamePurgeable : GrStdSteadyClock::now(); 126 } 127 accessCacheIndex()128 int* accessCacheIndex() const 129 { 130 thread_local int IN_VALID_INDEX = 0; 131 return IsValidAddress(fResource) ? &fResource->fCacheArrayIndex : &IN_VALID_INDEX; 132 } 133 CacheAccess(GrGpuResource * resource)134 CacheAccess(GrGpuResource* resource) : fResource(resource) {} CacheAccess(const CacheAccess & that)135 CacheAccess(const CacheAccess& that) : fResource(that.fResource) {} 136 CacheAccess& operator=(const CacheAccess&) = delete; 137 138 // No taking addresses of this type. 139 const CacheAccess* operator&() const = delete; 140 CacheAccess* operator&() = delete; 141 142 GrGpuResource* fResource; 143 144 friend class GrGpuResource; // to construct/copy this type. 145 friend class GrResourceCache; // to use this type 146 friend void test_unbudgeted_to_scratch(skiatest::Reporter* reporter); // for unit testing 147 }; 148 cacheAccess()149inline GrGpuResource::CacheAccess GrGpuResource::cacheAccess() { return CacheAccess(this); } 150 cacheAccess()151inline const GrGpuResource::CacheAccess GrGpuResource::cacheAccess() const { // NOLINT(readability-const-return-type) 152 return CacheAccess(const_cast<GrGpuResource*>(this)); 153 } 154 155 #endif 156