1*8975f5c5SAndroid Build Coastguard Worker // 2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2017 The ANGLE Project Authors. All rights reserved. 3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker // 6*8975f5c5SAndroid Build Coastguard Worker // ResourceMap: 7*8975f5c5SAndroid Build Coastguard Worker // An optimized resource map which packs the first set of allocated objects into a 8*8975f5c5SAndroid Build Coastguard Worker // flat array, and then falls back to an unordered map for the higher handle values. 9*8975f5c5SAndroid Build Coastguard Worker // 10*8975f5c5SAndroid Build Coastguard Worker 11*8975f5c5SAndroid Build Coastguard Worker #ifndef LIBANGLE_RESOURCE_MAP_H_ 12*8975f5c5SAndroid Build Coastguard Worker #define LIBANGLE_RESOURCE_MAP_H_ 13*8975f5c5SAndroid Build Coastguard Worker 14*8975f5c5SAndroid Build Coastguard Worker #include <mutex> 15*8975f5c5SAndroid Build Coastguard Worker #include <type_traits> 16*8975f5c5SAndroid Build Coastguard Worker 17*8975f5c5SAndroid Build Coastguard Worker #include "common/SimpleMutex.h" 18*8975f5c5SAndroid Build Coastguard Worker #include "common/hash_containers.h" 19*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/angletypes.h" 20*8975f5c5SAndroid Build Coastguard Worker 21*8975f5c5SAndroid Build Coastguard Worker namespace gl 22*8975f5c5SAndroid Build Coastguard Worker { 23*8975f5c5SAndroid Build Coastguard Worker // The resource map needs to be internally synchronized for maps that are placed in the share group 24*8975f5c5SAndroid Build Coastguard Worker // (as opposed to being private to the context) and that are accessed without holding the share 25*8975f5c5SAndroid Build Coastguard Worker // group lock. 26*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_ENABLE_SHARE_CONTEXT_LOCK) 27*8975f5c5SAndroid Build Coastguard Worker using ResourceMapMutex = angle::SimpleMutex; 28*8975f5c5SAndroid Build Coastguard Worker #else 29*8975f5c5SAndroid Build Coastguard Worker using ResourceMapMutex = angle::NoOpMutex; 30*8975f5c5SAndroid Build Coastguard Worker #endif 31*8975f5c5SAndroid Build Coastguard Worker 32*8975f5c5SAndroid Build Coastguard Worker template <bool NeedsLock = true> 33*8975f5c5SAndroid Build Coastguard Worker struct SelectResourceMapMutex 34*8975f5c5SAndroid Build Coastguard Worker { 35*8975f5c5SAndroid Build Coastguard Worker using type = ResourceMapMutex; 36*8975f5c5SAndroid Build Coastguard Worker }; 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker template <> 39*8975f5c5SAndroid Build Coastguard Worker struct SelectResourceMapMutex<false> 40*8975f5c5SAndroid Build Coastguard Worker { 41*8975f5c5SAndroid Build Coastguard Worker using type = angle::NoOpMutex; 42*8975f5c5SAndroid Build Coastguard Worker }; 43*8975f5c5SAndroid Build Coastguard Worker 44*8975f5c5SAndroid Build Coastguard Worker // Analysis of ANGLE's traces as well as Chrome usage reveals the following: 45*8975f5c5SAndroid Build Coastguard Worker // 46*8975f5c5SAndroid Build Coastguard Worker // - Buffers: Typical applications use no more than 4000 ids. Very few use over 6000. 47*8975f5c5SAndroid Build Coastguard Worker // - Textures: Typical applications use no more than 1200 ids. Very few use over 2000. 48*8975f5c5SAndroid Build Coastguard Worker // - Samplers: Typical applications use no more than 50 ids. Very few use over 100. 49*8975f5c5SAndroid Build Coastguard Worker // - Shaders and Programs: Typical applications use no more than 500. Very few use over 700. 50*8975f5c5SAndroid Build Coastguard Worker // - Sync objects: Typical applications use no more than 500. Very few use over 1500. 51*8975f5c5SAndroid Build Coastguard Worker // 52*8975f5c5SAndroid Build Coastguard Worker // For all the other shared types, the maximum used id is small (under 100). For 53*8975f5c5SAndroid Build Coastguard Worker // context-private parts (such as vertex arrays and queries), the id count can be in the 54*8975f5c5SAndroid Build Coastguard Worker // thousands. 55*8975f5c5SAndroid Build Coastguard Worker // 56*8975f5c5SAndroid Build Coastguard Worker // The initial size of the flat resource map is based on the above, rounded up to a multiple of 57*8975f5c5SAndroid Build Coastguard Worker // 1536. Resource maps that need a lock (kNeedsLock == true) have the maximum flat size identical 58*8975f5c5SAndroid Build Coastguard Worker // to initial flat size to avoid reallocation. For others, the maps start small and can grow. 59*8975f5c5SAndroid Build Coastguard Worker template <typename IDType> 60*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams 61*8975f5c5SAndroid Build Coastguard Worker { 62*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 192; 63*8975f5c5SAndroid Build Coastguard Worker 64*8975f5c5SAndroid Build Coastguard Worker // The following are private to the context and don't need a lock: 65*8975f5c5SAndroid Build Coastguard Worker // 66*8975f5c5SAndroid Build Coastguard Worker // - Vertex Array Objects 67*8975f5c5SAndroid Build Coastguard Worker // - Framebuffer Objects 68*8975f5c5SAndroid Build Coastguard Worker // - Transform Feedback Objects 69*8975f5c5SAndroid Build Coastguard Worker // - Query Objects 70*8975f5c5SAndroid Build Coastguard Worker // 71*8975f5c5SAndroid Build Coastguard Worker // The rest of the maps need a lock. However, only a select few are currently locked as API 72*8975f5c5SAndroid Build Coastguard Worker // relevant to the rest of the types are protected by the share group lock. As the share group 73*8975f5c5SAndroid Build Coastguard Worker // lock is removed from more types, the resource map lock needs to be enabled for them. 74*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = false; 75*8975f5c5SAndroid Build Coastguard Worker }; 76*8975f5c5SAndroid Build Coastguard Worker template <> 77*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams<BufferID> 78*8975f5c5SAndroid Build Coastguard Worker { 79*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 6144; 80*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = true; 81*8975f5c5SAndroid Build Coastguard Worker }; 82*8975f5c5SAndroid Build Coastguard Worker template <> 83*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams<TextureID> 84*8975f5c5SAndroid Build Coastguard Worker { 85*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 1536; 86*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = false; 87*8975f5c5SAndroid Build Coastguard Worker }; 88*8975f5c5SAndroid Build Coastguard Worker template <> 89*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams<ShaderProgramID> 90*8975f5c5SAndroid Build Coastguard Worker { 91*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 1536; 92*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = false; 93*8975f5c5SAndroid Build Coastguard Worker }; 94*8975f5c5SAndroid Build Coastguard Worker template <> 95*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams<SyncID> 96*8975f5c5SAndroid Build Coastguard Worker { 97*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 1536; 98*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = false; 99*8975f5c5SAndroid Build Coastguard Worker }; 100*8975f5c5SAndroid Build Coastguard Worker // For the purpose of unit testing, |int| is considered private (not needing lock), and 101*8975f5c5SAndroid Build Coastguard Worker // |unsigned int| is considered shared (needing lock). 102*8975f5c5SAndroid Build Coastguard Worker template <> 103*8975f5c5SAndroid Build Coastguard Worker struct ResourceMapParams<unsigned int> 104*8975f5c5SAndroid Build Coastguard Worker { 105*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 192; 106*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = true; 107*8975f5c5SAndroid Build Coastguard Worker }; 108*8975f5c5SAndroid Build Coastguard Worker 109*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 110*8975f5c5SAndroid Build Coastguard Worker class ResourceMap final : angle::NonCopyable 111*8975f5c5SAndroid Build Coastguard Worker { 112*8975f5c5SAndroid Build Coastguard Worker public: 113*8975f5c5SAndroid Build Coastguard Worker ResourceMap(); 114*8975f5c5SAndroid Build Coastguard Worker ~ResourceMap(); 115*8975f5c5SAndroid Build Coastguard Worker 116*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE ResourceType *query(IDType id) const 117*8975f5c5SAndroid Build Coastguard Worker { 118*8975f5c5SAndroid Build Coastguard Worker GLuint handle = GetIDValue(id); 119*8975f5c5SAndroid Build Coastguard Worker // No need for a lock when accessing the flat map. Either the flat map is static, or 120*8975f5c5SAndroid Build Coastguard Worker // locking is not needed. 121*8975f5c5SAndroid Build Coastguard Worker static_assert(!kNeedsLock || kInitialFlatResourcesSize == kFlatResourcesLimit); 122*8975f5c5SAndroid Build Coastguard Worker 123*8975f5c5SAndroid Build Coastguard Worker if (handle < mFlatResourcesSize) 124*8975f5c5SAndroid Build Coastguard Worker { 125*8975f5c5SAndroid Build Coastguard Worker ResourceType *value = mFlatResources[handle]; 126*8975f5c5SAndroid Build Coastguard Worker return (value == InvalidPointer() ? nullptr : value); 127*8975f5c5SAndroid Build Coastguard Worker } 128*8975f5c5SAndroid Build Coastguard Worker 129*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<Mutex> lock(mMutex); 130*8975f5c5SAndroid Build Coastguard Worker 131*8975f5c5SAndroid Build Coastguard Worker auto it = mHashedResources.find(handle); 132*8975f5c5SAndroid Build Coastguard Worker return (it == mHashedResources.end() ? nullptr : it->second); 133*8975f5c5SAndroid Build Coastguard Worker } 134*8975f5c5SAndroid Build Coastguard Worker 135*8975f5c5SAndroid Build Coastguard Worker // Returns true if the handle was reserved. Not necessarily if the resource is created. 136*8975f5c5SAndroid Build Coastguard Worker bool contains(IDType id) const; 137*8975f5c5SAndroid Build Coastguard Worker 138*8975f5c5SAndroid Build Coastguard Worker // Returns the element that was at this location. 139*8975f5c5SAndroid Build Coastguard Worker bool erase(IDType id, ResourceType **resourceOut); 140*8975f5c5SAndroid Build Coastguard Worker 141*8975f5c5SAndroid Build Coastguard Worker void assign(IDType id, ResourceType *resource); 142*8975f5c5SAndroid Build Coastguard Worker 143*8975f5c5SAndroid Build Coastguard Worker // Clears the map. 144*8975f5c5SAndroid Build Coastguard Worker void clear(); 145*8975f5c5SAndroid Build Coastguard Worker 146*8975f5c5SAndroid Build Coastguard Worker using IndexAndResource = std::pair<GLuint, ResourceType *>; 147*8975f5c5SAndroid Build Coastguard Worker using HashMap = angle::HashMap<GLuint, ResourceType *>; 148*8975f5c5SAndroid Build Coastguard Worker 149*8975f5c5SAndroid Build Coastguard Worker class Iterator final 150*8975f5c5SAndroid Build Coastguard Worker { 151*8975f5c5SAndroid Build Coastguard Worker public: 152*8975f5c5SAndroid Build Coastguard Worker bool operator==(const Iterator &other) const; 153*8975f5c5SAndroid Build Coastguard Worker bool operator!=(const Iterator &other) const; 154*8975f5c5SAndroid Build Coastguard Worker Iterator &operator++(); 155*8975f5c5SAndroid Build Coastguard Worker const IndexAndResource *operator->() const; 156*8975f5c5SAndroid Build Coastguard Worker const IndexAndResource &operator*() const; 157*8975f5c5SAndroid Build Coastguard Worker 158*8975f5c5SAndroid Build Coastguard Worker private: 159*8975f5c5SAndroid Build Coastguard Worker friend class ResourceMap; 160*8975f5c5SAndroid Build Coastguard Worker Iterator(const ResourceMap &origin, 161*8975f5c5SAndroid Build Coastguard Worker GLuint flatIndex, 162*8975f5c5SAndroid Build Coastguard Worker typename HashMap::const_iterator hashIndex, 163*8975f5c5SAndroid Build Coastguard Worker bool skipNulls); 164*8975f5c5SAndroid Build Coastguard Worker void updateValue(); 165*8975f5c5SAndroid Build Coastguard Worker 166*8975f5c5SAndroid Build Coastguard Worker const ResourceMap &mOrigin; 167*8975f5c5SAndroid Build Coastguard Worker GLuint mFlatIndex; 168*8975f5c5SAndroid Build Coastguard Worker typename HashMap::const_iterator mHashIndex; 169*8975f5c5SAndroid Build Coastguard Worker IndexAndResource mValue; 170*8975f5c5SAndroid Build Coastguard Worker bool mSkipNulls; 171*8975f5c5SAndroid Build Coastguard Worker }; 172*8975f5c5SAndroid Build Coastguard Worker 173*8975f5c5SAndroid Build Coastguard Worker private: 174*8975f5c5SAndroid Build Coastguard Worker friend class Iterator; 175*8975f5c5SAndroid Build Coastguard Worker template <typename SameResourceType, typename SameIDType> 176*8975f5c5SAndroid Build Coastguard Worker friend class UnsafeResourceMapIter; 177*8975f5c5SAndroid Build Coastguard Worker 178*8975f5c5SAndroid Build Coastguard Worker // null values represent reserved handles. 179*8975f5c5SAndroid Build Coastguard Worker Iterator begin() const; 180*8975f5c5SAndroid Build Coastguard Worker Iterator end() const; 181*8975f5c5SAndroid Build Coastguard Worker 182*8975f5c5SAndroid Build Coastguard Worker Iterator beginWithNull() const; 183*8975f5c5SAndroid Build Coastguard Worker Iterator endWithNull() const; 184*8975f5c5SAndroid Build Coastguard Worker 185*8975f5c5SAndroid Build Coastguard Worker // Used by iterators and related functions only (due to lack of thread safety). 186*8975f5c5SAndroid Build Coastguard Worker GLuint nextResource(size_t flatIndex, bool skipNulls) const; 187*8975f5c5SAndroid Build Coastguard Worker 188*8975f5c5SAndroid Build Coastguard Worker // constexpr methods cannot contain reinterpret_cast, so we need a static method. 189*8975f5c5SAndroid Build Coastguard Worker static ResourceType *InvalidPointer(); 190*8975f5c5SAndroid Build Coastguard Worker static constexpr intptr_t kInvalidPointer = static_cast<intptr_t>(-1); 191*8975f5c5SAndroid Build Coastguard Worker 192*8975f5c5SAndroid Build Coastguard Worker static constexpr bool kNeedsLock = ResourceMapParams<IDType>::kNeedsLock; 193*8975f5c5SAndroid Build Coastguard Worker using Mutex = typename SelectResourceMapMutex<kNeedsLock>::type; 194*8975f5c5SAndroid Build Coastguard Worker 195*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kInitialFlatResourcesSize = 196*8975f5c5SAndroid Build Coastguard Worker ResourceMapParams<IDType>::kInitialFlatResourcesSize; 197*8975f5c5SAndroid Build Coastguard Worker 198*8975f5c5SAndroid Build Coastguard Worker // Experimental testing suggests that ~10k is a reasonable upper limit. 199*8975f5c5SAndroid Build Coastguard Worker static constexpr size_t kFlatResourcesLimit = kNeedsLock ? kInitialFlatResourcesSize : 0x3000; 200*8975f5c5SAndroid Build Coastguard Worker // Due to the way assign() is implemented, kFlatResourcesLimit / kInitialFlatResourcesSize must 201*8975f5c5SAndroid Build Coastguard Worker // be a power of 2. 202*8975f5c5SAndroid Build Coastguard Worker static_assert(kFlatResourcesLimit % kInitialFlatResourcesSize == 0); 203*8975f5c5SAndroid Build Coastguard Worker static_assert(((kFlatResourcesLimit / kInitialFlatResourcesSize) & 204*8975f5c5SAndroid Build Coastguard Worker (kFlatResourcesLimit / kInitialFlatResourcesSize - 1)) == 0); 205*8975f5c5SAndroid Build Coastguard Worker 206*8975f5c5SAndroid Build Coastguard Worker size_t mFlatResourcesSize; 207*8975f5c5SAndroid Build Coastguard Worker ResourceType **mFlatResources; 208*8975f5c5SAndroid Build Coastguard Worker 209*8975f5c5SAndroid Build Coastguard Worker // A map of GL objects indexed by object ID. 210*8975f5c5SAndroid Build Coastguard Worker HashMap mHashedResources; 211*8975f5c5SAndroid Build Coastguard Worker 212*8975f5c5SAndroid Build Coastguard Worker // mFlatResources is allocated at object creation time, with a default size of 213*8975f5c5SAndroid Build Coastguard Worker // |kInitialFlatResourcesSize|. This is thread safe, because the allocation is done by the 214*8975f5c5SAndroid Build Coastguard Worker // first context in the share group. The flat map is allowed to grow up to 215*8975f5c5SAndroid Build Coastguard Worker // |kFlatResourcesLimit|, but only for maps that don't need a lock (kNeedsLock == false). 216*8975f5c5SAndroid Build Coastguard Worker // 217*8975f5c5SAndroid Build Coastguard Worker // For maps that don't need a lock, this mutex is a no-op. For those that do, the mutex is 218*8975f5c5SAndroid Build Coastguard Worker // taken when allocating / deleting objects, as well as when accessing |mHashedResources|. 219*8975f5c5SAndroid Build Coastguard Worker // Otherwise, access to the flat map (which never gets reallocated due to 220*8975f5c5SAndroid Build Coastguard Worker // |kInitialFlatResourcesSize == kFlatResourcesLimit|) is lockless. This latter is possible 221*8975f5c5SAndroid Build Coastguard Worker // because the application is not allowed to gen/delete and bind the same ID in different 222*8975f5c5SAndroid Build Coastguard Worker // threads at the same time. 223*8975f5c5SAndroid Build Coastguard Worker // 224*8975f5c5SAndroid Build Coastguard Worker // Note that because HandleAllocator is not yet thread-safe, glGen* and glDelete* functions 225*8975f5c5SAndroid Build Coastguard Worker // cannot be free of the share group mutex yet. To remove the share group mutex from those 226*8975f5c5SAndroid Build Coastguard Worker // functions, likely the HandleAllocator class should be merged with this class, and the 227*8975f5c5SAndroid Build Coastguard Worker // necessary insert/erase operations done under this same lock. 228*8975f5c5SAndroid Build Coastguard Worker mutable Mutex mMutex; 229*8975f5c5SAndroid Build Coastguard Worker }; 230*8975f5c5SAndroid Build Coastguard Worker 231*8975f5c5SAndroid Build Coastguard Worker // A helper to retrieve the resource map iterators while being explicit that this is not thread 232*8975f5c5SAndroid Build Coastguard Worker // safe. Usage of iterators are limited to clean up on destruction and capture/replay, neither of 233*8975f5c5SAndroid Build Coastguard Worker // which can race with other threads in their access to the resource map. 234*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 235*8975f5c5SAndroid Build Coastguard Worker class UnsafeResourceMapIter 236*8975f5c5SAndroid Build Coastguard Worker { 237*8975f5c5SAndroid Build Coastguard Worker public: 238*8975f5c5SAndroid Build Coastguard Worker using ResMap = ResourceMap<ResourceType, IDType>; 239*8975f5c5SAndroid Build Coastguard Worker 240*8975f5c5SAndroid Build Coastguard Worker UnsafeResourceMapIter(const ResMap &resourceMap) : mResourceMap(resourceMap) {} 241*8975f5c5SAndroid Build Coastguard Worker 242*8975f5c5SAndroid Build Coastguard Worker typename ResMap::Iterator begin() const { return mResourceMap.begin(); } 243*8975f5c5SAndroid Build Coastguard Worker typename ResMap::Iterator end() const { return mResourceMap.end(); } 244*8975f5c5SAndroid Build Coastguard Worker 245*8975f5c5SAndroid Build Coastguard Worker typename ResMap::Iterator beginWithNull() const { return mResourceMap.beginWithNull(); } 246*8975f5c5SAndroid Build Coastguard Worker typename ResMap::Iterator endWithNull() const { return mResourceMap.endWithNull(); } 247*8975f5c5SAndroid Build Coastguard Worker 248*8975f5c5SAndroid Build Coastguard Worker // Not a constant-time operation, should only be used for verification. 249*8975f5c5SAndroid Build Coastguard Worker bool empty() const; 250*8975f5c5SAndroid Build Coastguard Worker 251*8975f5c5SAndroid Build Coastguard Worker private: 252*8975f5c5SAndroid Build Coastguard Worker const ResMap &mResourceMap; 253*8975f5c5SAndroid Build Coastguard Worker }; 254*8975f5c5SAndroid Build Coastguard Worker 255*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 256*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::ResourceMap() 257*8975f5c5SAndroid Build Coastguard Worker : mFlatResourcesSize(kInitialFlatResourcesSize), 258*8975f5c5SAndroid Build Coastguard Worker mFlatResources(new ResourceType *[kInitialFlatResourcesSize]) 259*8975f5c5SAndroid Build Coastguard Worker { 260*8975f5c5SAndroid Build Coastguard Worker memset(mFlatResources, kInvalidPointer, mFlatResourcesSize * sizeof(mFlatResources[0])); 261*8975f5c5SAndroid Build Coastguard Worker } 262*8975f5c5SAndroid Build Coastguard Worker 263*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 264*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::~ResourceMap() 265*8975f5c5SAndroid Build Coastguard Worker { 266*8975f5c5SAndroid Build Coastguard Worker ASSERT(begin() == end()); 267*8975f5c5SAndroid Build Coastguard Worker delete[] mFlatResources; 268*8975f5c5SAndroid Build Coastguard Worker } 269*8975f5c5SAndroid Build Coastguard Worker 270*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 271*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE bool ResourceMap<ResourceType, IDType>::contains(IDType id) const 272*8975f5c5SAndroid Build Coastguard Worker { 273*8975f5c5SAndroid Build Coastguard Worker GLuint handle = GetIDValue(id); 274*8975f5c5SAndroid Build Coastguard Worker if (handle < mFlatResourcesSize) 275*8975f5c5SAndroid Build Coastguard Worker { 276*8975f5c5SAndroid Build Coastguard Worker return mFlatResources[handle] != InvalidPointer(); 277*8975f5c5SAndroid Build Coastguard Worker } 278*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<Mutex> lock(mMutex); 279*8975f5c5SAndroid Build Coastguard Worker return mHashedResources.find(handle) != mHashedResources.end(); 280*8975f5c5SAndroid Build Coastguard Worker } 281*8975f5c5SAndroid Build Coastguard Worker 282*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 283*8975f5c5SAndroid Build Coastguard Worker bool ResourceMap<ResourceType, IDType>::erase(IDType id, ResourceType **resourceOut) 284*8975f5c5SAndroid Build Coastguard Worker { 285*8975f5c5SAndroid Build Coastguard Worker GLuint handle = GetIDValue(id); 286*8975f5c5SAndroid Build Coastguard Worker if (handle < mFlatResourcesSize) 287*8975f5c5SAndroid Build Coastguard Worker { 288*8975f5c5SAndroid Build Coastguard Worker auto &value = mFlatResources[handle]; 289*8975f5c5SAndroid Build Coastguard Worker if (value == InvalidPointer()) 290*8975f5c5SAndroid Build Coastguard Worker { 291*8975f5c5SAndroid Build Coastguard Worker return false; 292*8975f5c5SAndroid Build Coastguard Worker } 293*8975f5c5SAndroid Build Coastguard Worker *resourceOut = value; 294*8975f5c5SAndroid Build Coastguard Worker value = InvalidPointer(); 295*8975f5c5SAndroid Build Coastguard Worker } 296*8975f5c5SAndroid Build Coastguard Worker else 297*8975f5c5SAndroid Build Coastguard Worker { 298*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<Mutex> lock(mMutex); 299*8975f5c5SAndroid Build Coastguard Worker 300*8975f5c5SAndroid Build Coastguard Worker auto it = mHashedResources.find(handle); 301*8975f5c5SAndroid Build Coastguard Worker if (it == mHashedResources.end()) 302*8975f5c5SAndroid Build Coastguard Worker { 303*8975f5c5SAndroid Build Coastguard Worker return false; 304*8975f5c5SAndroid Build Coastguard Worker } 305*8975f5c5SAndroid Build Coastguard Worker *resourceOut = it->second; 306*8975f5c5SAndroid Build Coastguard Worker mHashedResources.erase(it); 307*8975f5c5SAndroid Build Coastguard Worker } 308*8975f5c5SAndroid Build Coastguard Worker return true; 309*8975f5c5SAndroid Build Coastguard Worker } 310*8975f5c5SAndroid Build Coastguard Worker 311*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 312*8975f5c5SAndroid Build Coastguard Worker void ResourceMap<ResourceType, IDType>::assign(IDType id, ResourceType *resource) 313*8975f5c5SAndroid Build Coastguard Worker { 314*8975f5c5SAndroid Build Coastguard Worker GLuint handle = GetIDValue(id); 315*8975f5c5SAndroid Build Coastguard Worker if (handle < kFlatResourcesLimit) 316*8975f5c5SAndroid Build Coastguard Worker { 317*8975f5c5SAndroid Build Coastguard Worker if (handle >= mFlatResourcesSize) 318*8975f5c5SAndroid Build Coastguard Worker { 319*8975f5c5SAndroid Build Coastguard Worker // No need for a lock as the flat map never grows when locking is needed. 320*8975f5c5SAndroid Build Coastguard Worker static_assert(!kNeedsLock || kInitialFlatResourcesSize == kFlatResourcesLimit); 321*8975f5c5SAndroid Build Coastguard Worker 322*8975f5c5SAndroid Build Coastguard Worker // Use power-of-two. 323*8975f5c5SAndroid Build Coastguard Worker size_t newSize = mFlatResourcesSize; 324*8975f5c5SAndroid Build Coastguard Worker while (newSize <= handle) 325*8975f5c5SAndroid Build Coastguard Worker { 326*8975f5c5SAndroid Build Coastguard Worker newSize *= 2; 327*8975f5c5SAndroid Build Coastguard Worker } 328*8975f5c5SAndroid Build Coastguard Worker 329*8975f5c5SAndroid Build Coastguard Worker ResourceType **oldResources = mFlatResources; 330*8975f5c5SAndroid Build Coastguard Worker 331*8975f5c5SAndroid Build Coastguard Worker mFlatResources = new ResourceType *[newSize]; 332*8975f5c5SAndroid Build Coastguard Worker memset(&mFlatResources[mFlatResourcesSize], kInvalidPointer, 333*8975f5c5SAndroid Build Coastguard Worker (newSize - mFlatResourcesSize) * sizeof(mFlatResources[0])); 334*8975f5c5SAndroid Build Coastguard Worker memcpy(mFlatResources, oldResources, mFlatResourcesSize * sizeof(mFlatResources[0])); 335*8975f5c5SAndroid Build Coastguard Worker mFlatResourcesSize = newSize; 336*8975f5c5SAndroid Build Coastguard Worker delete[] oldResources; 337*8975f5c5SAndroid Build Coastguard Worker } 338*8975f5c5SAndroid Build Coastguard Worker ASSERT(mFlatResourcesSize > handle); 339*8975f5c5SAndroid Build Coastguard Worker mFlatResources[handle] = resource; 340*8975f5c5SAndroid Build Coastguard Worker } 341*8975f5c5SAndroid Build Coastguard Worker else 342*8975f5c5SAndroid Build Coastguard Worker { 343*8975f5c5SAndroid Build Coastguard Worker std::lock_guard<Mutex> lock(mMutex); 344*8975f5c5SAndroid Build Coastguard Worker mHashedResources[handle] = resource; 345*8975f5c5SAndroid Build Coastguard Worker } 346*8975f5c5SAndroid Build Coastguard Worker } 347*8975f5c5SAndroid Build Coastguard Worker 348*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 349*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::Iterator ResourceMap<ResourceType, IDType>::begin() 350*8975f5c5SAndroid Build Coastguard Worker const 351*8975f5c5SAndroid Build Coastguard Worker { 352*8975f5c5SAndroid Build Coastguard Worker return Iterator(*this, nextResource(0, true), mHashedResources.begin(), true); 353*8975f5c5SAndroid Build Coastguard Worker } 354*8975f5c5SAndroid Build Coastguard Worker 355*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 356*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::Iterator ResourceMap<ResourceType, IDType>::end() const 357*8975f5c5SAndroid Build Coastguard Worker { 358*8975f5c5SAndroid Build Coastguard Worker return Iterator(*this, static_cast<GLuint>(mFlatResourcesSize), mHashedResources.end(), true); 359*8975f5c5SAndroid Build Coastguard Worker } 360*8975f5c5SAndroid Build Coastguard Worker 361*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 362*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::Iterator 363*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::beginWithNull() const 364*8975f5c5SAndroid Build Coastguard Worker { 365*8975f5c5SAndroid Build Coastguard Worker return Iterator(*this, nextResource(0, false), mHashedResources.begin(), false); 366*8975f5c5SAndroid Build Coastguard Worker } 367*8975f5c5SAndroid Build Coastguard Worker 368*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 369*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::Iterator 370*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::endWithNull() const 371*8975f5c5SAndroid Build Coastguard Worker { 372*8975f5c5SAndroid Build Coastguard Worker return Iterator(*this, static_cast<GLuint>(mFlatResourcesSize), mHashedResources.end(), false); 373*8975f5c5SAndroid Build Coastguard Worker } 374*8975f5c5SAndroid Build Coastguard Worker 375*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 376*8975f5c5SAndroid Build Coastguard Worker bool UnsafeResourceMapIter<ResourceType, IDType>::empty() const 377*8975f5c5SAndroid Build Coastguard Worker { 378*8975f5c5SAndroid Build Coastguard Worker return begin() == end(); 379*8975f5c5SAndroid Build Coastguard Worker } 380*8975f5c5SAndroid Build Coastguard Worker 381*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 382*8975f5c5SAndroid Build Coastguard Worker void ResourceMap<ResourceType, IDType>::clear() 383*8975f5c5SAndroid Build Coastguard Worker { 384*8975f5c5SAndroid Build Coastguard Worker // No need for a lock as this is only called on destruction. 385*8975f5c5SAndroid Build Coastguard Worker memset(mFlatResources, kInvalidPointer, kInitialFlatResourcesSize * sizeof(mFlatResources[0])); 386*8975f5c5SAndroid Build Coastguard Worker mFlatResourcesSize = kInitialFlatResourcesSize; 387*8975f5c5SAndroid Build Coastguard Worker mHashedResources.clear(); 388*8975f5c5SAndroid Build Coastguard Worker } 389*8975f5c5SAndroid Build Coastguard Worker 390*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 391*8975f5c5SAndroid Build Coastguard Worker GLuint ResourceMap<ResourceType, IDType>::nextResource(size_t flatIndex, bool skipNulls) const 392*8975f5c5SAndroid Build Coastguard Worker { 393*8975f5c5SAndroid Build Coastguard Worker // This function is only used by the iterators, access to which is marked by 394*8975f5c5SAndroid Build Coastguard Worker // UnsafeResourceMapIter. Locking is the responsibility of the caller. 395*8975f5c5SAndroid Build Coastguard Worker for (size_t index = flatIndex; index < mFlatResourcesSize; index++) 396*8975f5c5SAndroid Build Coastguard Worker { 397*8975f5c5SAndroid Build Coastguard Worker if ((mFlatResources[index] != nullptr || !skipNulls) && 398*8975f5c5SAndroid Build Coastguard Worker mFlatResources[index] != InvalidPointer()) 399*8975f5c5SAndroid Build Coastguard Worker { 400*8975f5c5SAndroid Build Coastguard Worker return static_cast<GLuint>(index); 401*8975f5c5SAndroid Build Coastguard Worker } 402*8975f5c5SAndroid Build Coastguard Worker } 403*8975f5c5SAndroid Build Coastguard Worker return static_cast<GLuint>(mFlatResourcesSize); 404*8975f5c5SAndroid Build Coastguard Worker } 405*8975f5c5SAndroid Build Coastguard Worker 406*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 407*8975f5c5SAndroid Build Coastguard Worker // static 408*8975f5c5SAndroid Build Coastguard Worker ResourceType *ResourceMap<ResourceType, IDType>::InvalidPointer() 409*8975f5c5SAndroid Build Coastguard Worker { 410*8975f5c5SAndroid Build Coastguard Worker return reinterpret_cast<ResourceType *>(kInvalidPointer); 411*8975f5c5SAndroid Build Coastguard Worker } 412*8975f5c5SAndroid Build Coastguard Worker 413*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 414*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::Iterator::Iterator( 415*8975f5c5SAndroid Build Coastguard Worker const ResourceMap &origin, 416*8975f5c5SAndroid Build Coastguard Worker GLuint flatIndex, 417*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::HashMap::const_iterator hashIndex, 418*8975f5c5SAndroid Build Coastguard Worker bool skipNulls) 419*8975f5c5SAndroid Build Coastguard Worker : mOrigin(origin), mFlatIndex(flatIndex), mHashIndex(hashIndex), mSkipNulls(skipNulls) 420*8975f5c5SAndroid Build Coastguard Worker { 421*8975f5c5SAndroid Build Coastguard Worker updateValue(); 422*8975f5c5SAndroid Build Coastguard Worker } 423*8975f5c5SAndroid Build Coastguard Worker 424*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 425*8975f5c5SAndroid Build Coastguard Worker bool ResourceMap<ResourceType, IDType>::Iterator::operator==(const Iterator &other) const 426*8975f5c5SAndroid Build Coastguard Worker { 427*8975f5c5SAndroid Build Coastguard Worker return (mFlatIndex == other.mFlatIndex && mHashIndex == other.mHashIndex); 428*8975f5c5SAndroid Build Coastguard Worker } 429*8975f5c5SAndroid Build Coastguard Worker 430*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 431*8975f5c5SAndroid Build Coastguard Worker bool ResourceMap<ResourceType, IDType>::Iterator::operator!=(const Iterator &other) const 432*8975f5c5SAndroid Build Coastguard Worker { 433*8975f5c5SAndroid Build Coastguard Worker return !(*this == other); 434*8975f5c5SAndroid Build Coastguard Worker } 435*8975f5c5SAndroid Build Coastguard Worker 436*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 437*8975f5c5SAndroid Build Coastguard Worker typename ResourceMap<ResourceType, IDType>::Iterator & 438*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::Iterator::operator++() 439*8975f5c5SAndroid Build Coastguard Worker { 440*8975f5c5SAndroid Build Coastguard Worker if (mFlatIndex < static_cast<GLuint>(mOrigin.mFlatResourcesSize)) 441*8975f5c5SAndroid Build Coastguard Worker { 442*8975f5c5SAndroid Build Coastguard Worker mFlatIndex = mOrigin.nextResource(mFlatIndex + 1, mSkipNulls); 443*8975f5c5SAndroid Build Coastguard Worker } 444*8975f5c5SAndroid Build Coastguard Worker else 445*8975f5c5SAndroid Build Coastguard Worker { 446*8975f5c5SAndroid Build Coastguard Worker mHashIndex++; 447*8975f5c5SAndroid Build Coastguard Worker } 448*8975f5c5SAndroid Build Coastguard Worker updateValue(); 449*8975f5c5SAndroid Build Coastguard Worker return *this; 450*8975f5c5SAndroid Build Coastguard Worker } 451*8975f5c5SAndroid Build Coastguard Worker 452*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 453*8975f5c5SAndroid Build Coastguard Worker const typename ResourceMap<ResourceType, IDType>::IndexAndResource * 454*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::Iterator::operator->() const 455*8975f5c5SAndroid Build Coastguard Worker { 456*8975f5c5SAndroid Build Coastguard Worker return &mValue; 457*8975f5c5SAndroid Build Coastguard Worker } 458*8975f5c5SAndroid Build Coastguard Worker 459*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 460*8975f5c5SAndroid Build Coastguard Worker const typename ResourceMap<ResourceType, IDType>::IndexAndResource & 461*8975f5c5SAndroid Build Coastguard Worker ResourceMap<ResourceType, IDType>::Iterator::operator*() const 462*8975f5c5SAndroid Build Coastguard Worker { 463*8975f5c5SAndroid Build Coastguard Worker return mValue; 464*8975f5c5SAndroid Build Coastguard Worker } 465*8975f5c5SAndroid Build Coastguard Worker 466*8975f5c5SAndroid Build Coastguard Worker template <typename ResourceType, typename IDType> 467*8975f5c5SAndroid Build Coastguard Worker void ResourceMap<ResourceType, IDType>::Iterator::updateValue() 468*8975f5c5SAndroid Build Coastguard Worker { 469*8975f5c5SAndroid Build Coastguard Worker if (mFlatIndex < static_cast<GLuint>(mOrigin.mFlatResourcesSize)) 470*8975f5c5SAndroid Build Coastguard Worker { 471*8975f5c5SAndroid Build Coastguard Worker mValue.first = mFlatIndex; 472*8975f5c5SAndroid Build Coastguard Worker mValue.second = mOrigin.mFlatResources[mFlatIndex]; 473*8975f5c5SAndroid Build Coastguard Worker } 474*8975f5c5SAndroid Build Coastguard Worker else if (mHashIndex != mOrigin.mHashedResources.end()) 475*8975f5c5SAndroid Build Coastguard Worker { 476*8975f5c5SAndroid Build Coastguard Worker mValue.first = mHashIndex->first; 477*8975f5c5SAndroid Build Coastguard Worker mValue.second = mHashIndex->second; 478*8975f5c5SAndroid Build Coastguard Worker } 479*8975f5c5SAndroid Build Coastguard Worker } 480*8975f5c5SAndroid Build Coastguard Worker 481*8975f5c5SAndroid Build Coastguard Worker } // namespace gl 482*8975f5c5SAndroid Build Coastguard Worker 483*8975f5c5SAndroid Build Coastguard Worker #endif // LIBANGLE_RESOURCE_MAP_H_ 484