|
1 | 1 | /* |
2 | | - * Copyright 2019-2025 Diligent Graphics LLC |
| 2 | + * Copyright 2019-2026 Diligent Graphics LLC |
3 | 3 | * Copyright 2015-2019 Egor Yusov |
4 | 4 | * |
5 | 5 | * Licensed under the Apache License, Version 2.0 (the "License"); |
@@ -62,7 +62,8 @@ ResourceManager::ResourceManager(IReferenceCounters* pRefCounters, |
62 | 62 | m_DefaultVertPoolDesc{CI.DefaultPoolDesc}, |
63 | 63 | m_DefaultAtlasName{CI.DefaultAtlasDesc.Desc.Name != nullptr ? CI.DefaultAtlasDesc.Desc.Name : "GLTF texture atlas"}, |
64 | 64 | m_DefaultAtlasDesc{CI.DefaultAtlasDesc}, |
65 | | - m_IndexAllocatorCI{CI.IndexAllocatorCI} |
| 65 | + m_IndexAllocatorCI{CI.IndexAllocatorCI}, |
| 66 | + m_TexAllocations{CI.NumTextureAllocationShards != 0 ? CI.NumTextureAllocationShards : 1} |
66 | 67 | { |
67 | 68 | m_DefaultVertPoolDesc.Name = m_DefaultVertPoolName.c_str(); |
68 | 69 | m_DefaultAtlasDesc.Desc.Name = m_DefaultAtlasName.c_str(); |
@@ -122,45 +123,75 @@ ResourceManager::ResourceManager(IReferenceCounters* pRefCounters, |
122 | 123 | } |
123 | 124 |
|
124 | 125 |
|
125 | | -RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::FindTextureAllocation(const char* CacheId) |
| 126 | +RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::TexAllocations::Find(const char* CacheId) |
126 | 127 | { |
127 | | - if (CacheId != nullptr && *CacheId != 0) |
| 128 | + if (CacheId == nullptr || *CacheId == 0) |
| 129 | + return {}; |
| 130 | + |
| 131 | + bool AllocationExpired = false; |
| 132 | + |
| 133 | + // First, try to find the allocation with a shared lock |
128 | 134 | { |
129 | | - bool AllocationExpired = false; |
| 135 | + std::shared_lock<std::shared_mutex> SharedLock{m_Mtx}; |
130 | 136 |
|
131 | | - // First, try to find the allocation with a shared lock |
| 137 | + auto it = m_Map.find(CacheId); |
| 138 | + if (it != m_Map.end()) |
132 | 139 | { |
133 | | - std::shared_lock<std::shared_mutex> SharedLock{m_TexAllocationsMtx}; |
134 | | - |
135 | | - auto it = m_TexAllocations.find(CacheId); |
136 | | - if (it != m_TexAllocations.end()) |
137 | | - { |
138 | | - if (RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation = it->second.Lock()) |
139 | | - return pAllocation; |
140 | | - else |
141 | | - AllocationExpired = true; |
142 | | - } |
| 140 | + if (RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation = it->second.Lock()) |
| 141 | + return pAllocation; |
| 142 | + else |
| 143 | + AllocationExpired = true; |
143 | 144 | } |
| 145 | + } |
144 | 146 |
|
145 | | - // If the allocation was found but has expired, acquire a unique lock to erase it |
146 | | - if (AllocationExpired) |
147 | | - { |
148 | | - std::unique_lock<std::shared_mutex> UniqueLock{m_TexAllocationsMtx}; |
| 147 | + // If the allocation was found but has expired, acquire a unique lock to erase it |
| 148 | + if (AllocationExpired) |
| 149 | + { |
| 150 | + std::unique_lock<std::shared_mutex> UniqueLock{m_Mtx}; |
149 | 151 |
|
150 | | - auto it = m_TexAllocations.find(CacheId); |
151 | | - if (it != m_TexAllocations.end()) |
152 | | - { |
153 | | - if (RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation = it->second.Lock()) |
154 | | - return pAllocation; |
155 | | - else |
156 | | - m_TexAllocations.erase(it); |
157 | | - } |
| 152 | + auto it = m_Map.find(CacheId); |
| 153 | + if (it != m_Map.end()) |
| 154 | + { |
| 155 | + if (RefCntAutoPtr<ITextureAtlasSuballocation> pAllocation = it->second.Lock()) |
| 156 | + return pAllocation; |
| 157 | + else |
| 158 | + m_Map.erase(it); |
158 | 159 | } |
159 | 160 | } |
160 | 161 |
|
161 | 162 | return {}; |
162 | 163 | } |
163 | 164 |
|
| 165 | +void ResourceManager::TexAllocations::Add(const char* CacheId, RefCntAutoPtr<ITextureAtlasSuballocation> pSuballocation) |
| 166 | +{ |
| 167 | + if (CacheId == nullptr || *CacheId == 0) |
| 168 | + return; |
| 169 | + |
| 170 | + std::unique_lock<std::shared_mutex> UniqueLock{m_Mtx}; |
| 171 | + // Note that the same allocation may potentially be created by more |
| 172 | + // than one thread if it has not been found in the cache originally |
| 173 | + auto [it, inserted] = m_Map.emplace(CacheId, pSuballocation); |
| 174 | + if (!inserted) |
| 175 | + { |
| 176 | + if (auto pExistingAllocation = it->second.Lock()) |
| 177 | + pSuballocation = pExistingAllocation; |
| 178 | + else |
| 179 | + it->second = pSuballocation; |
| 180 | + } |
| 181 | +} |
| 182 | + |
| 183 | +size_t ResourceManager::TexAllocations::GetShardIndex(const char* CacheId, size_t ShardCount) |
| 184 | +{ |
| 185 | + if (CacheId == nullptr || *CacheId == 0) |
| 186 | + return 0; |
| 187 | + return ShardCount > 1 ? CStringHash<Char>{}(CacheId) % ShardCount : 0; |
| 188 | +} |
| 189 | + |
| 190 | +RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::FindTextureAllocation(const char* CacheId) |
| 191 | +{ |
| 192 | + return m_TexAllocations[TexAllocations::GetShardIndex(CacheId, m_TexAllocations.size())].Find(CacheId); |
| 193 | +} |
| 194 | + |
164 | 195 | RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::AllocateTextureSpace( |
165 | 196 | TEXTURE_FORMAT Fmt, |
166 | 197 | Uint32 Width, |
@@ -232,20 +263,7 @@ RefCntAutoPtr<ITextureAtlasSuballocation> ResourceManager::AllocateTextureSpace( |
232 | 263 | pAllocation->SetUserData(pUserData); |
233 | 264 | } |
234 | 265 |
|
235 | | - if (CacheId != nullptr && *CacheId != 0) |
236 | | - { |
237 | | - std::unique_lock<std::shared_mutex> UniqueLock{m_TexAllocationsMtx}; |
238 | | - // Note that the same allocation may potentially be created by more |
239 | | - // than one thread if it has not been found in the cache originally |
240 | | - auto [it, inserted] = m_TexAllocations.emplace(CacheId, pAllocation); |
241 | | - if (!inserted) |
242 | | - { |
243 | | - if (auto pExistingAllocation = it->second.Lock()) |
244 | | - pAllocation = pExistingAllocation; |
245 | | - else |
246 | | - it->second = pAllocation; |
247 | | - } |
248 | | - } |
| 266 | + m_TexAllocations[TexAllocations::GetShardIndex(CacheId, m_TexAllocations.size())].Add(CacheId, pAllocation); |
249 | 267 |
|
250 | 268 | return pAllocation; |
251 | 269 | } |
|
0 commit comments