Skip to content

Commit 17b7f7d

Browse files
GLTF Resource Manager: replace mutex with shared_mutex for improved concurrency
1 parent cda6998 commit 17b7f7d

File tree

2 files changed

+271
-86
lines changed

2 files changed

+271
-86
lines changed

AssetLoader/interface/GLTFResourceManager.hpp

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
/// \file
3131
/// Defines Diligent::ResourceManager class implementing GLTF resource manager.
3232

33-
#include <mutex>
33+
#include <shared_mutex>
3434
#include <vector>
3535
#include <unordered_map>
3636
#include <atomic>
@@ -100,10 +100,6 @@ class ResourceManager final : public ObjectBase<IObject>
100100
{
101101
return Elements != rhs.Elements;
102102
}
103-
explicit operator bool() const
104-
{
105-
return Elements.empty();
106-
}
107103

108104
struct Hasher
109105
{
@@ -178,16 +174,25 @@ class ResourceManager final : public ObjectBase<IObject>
178174
/// If the texture atlas for the given format does not exist and if the default
179175
/// atlas description allows creating new atlases (Desc.Type != Diligent::RESOURCE_DIM_UNDEFINED),
180176
/// new atlas will be added. Otherwise, the function will return null.
177+
///
178+
/// The function is thread-safe and can be called from multiple threads simultaneously and
179+
/// in parallel with other thread-safe class methods.
181180
RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt,
182181
Uint32 Width,
183182
Uint32 Height,
184183
const char* CacheId = nullptr,
185184
IObject* pUserData = nullptr);
186185

187186
/// Finds texture allocation in the texture atlas that matches the specified cache ID.
187+
///
188+
/// The function is thread-safe and can be called from multiple threads simultaneously and
189+
/// in parallel with other thread-safe class methods.
188190
RefCntAutoPtr<ITextureAtlasSuballocation> FindTextureAllocation(const char* CacheId);
189191

190192
/// Allocates indices in the index buffer.
193+
///
194+
/// The function is thread-safe and can be called from multiple threads simultaneously and
195+
/// in parallel with other thread-safe class methods.
191196
RefCntAutoPtr<IBufferSuballocation> AllocateIndices(Uint32 Size, Uint32 Alignment = 4);
192197

193198
/// Allocates vertices in the vertex pool that matches the specified layout.
@@ -205,35 +210,65 @@ class ResourceManager final : public ObjectBase<IObject>
205210
/// If no pull exists for the given key and the default
206211
/// pool description does not allow creating new pools
207212
/// (VertexCount == 0), the function returns null.
213+
///
214+
/// The function is thread-safe and can be called from multiple threads simultaneously and
215+
/// in parallel with other thread-safe class methods.
208216
RefCntAutoPtr<IVertexPoolAllocation> AllocateVertices(const VertexLayoutKey& LayoutKey, Uint32 VertexCount);
209217

210218

211219
/// Returns the combined texture atlas version, i.e. the sum of the texture versions of all
212220
/// atlases.
221+
///
222+
/// The function is thread-safe and can be called from multiple threads simultaneously and
223+
/// in parallel with other thread-safe class methods.
213224
Uint32 GetTextureVersion() const;
214225

215226
/// Returns the index buffer version.
227+
///
228+
/// The function is thread-safe and can be called from multiple threads simultaneously and
229+
/// in parallel with other thread-safe class methods.
216230
Uint32 GetIndexBufferVersion() const;
217231

218232
/// Returns the combined vertex pool version, i.e. the sum all vertex pool versions.
233+
///
234+
/// The function is thread-safe and can be called from multiple threads simultaneously and
235+
/// in parallel with other thread-safe class methods.
219236
Uint32 GetVertexPoolsVersion() const;
220237

221238
/// Updates the index buffer, if necessary.
239+
///
240+
/// The function is not thread-safe, but can be called in parallel
241+
/// with other thread-safe class methods.
222242
IBuffer* UpdateIndexBuffer(IRenderDevice* pDevice, IDeviceContext* pContext, Uint32 Index = 0);
223243

224244
/// Updates all index buffers.
245+
///
246+
/// The function is not thread-safe, but can be called in parallel
247+
/// with other thread-safe class methods.
225248
void UpdateIndexBuffers(IRenderDevice* pDevice, IDeviceContext* pContext);
226249

227250
/// Returns the number of index buffers.
251+
///
252+
/// The function is thread-safe and can be called from multiple threads simultaneously and
253+
/// in parallel with other thread-safe class methods.
228254
size_t GetIndexBufferCount() const;
229255

230256
/// Returns the index allocator index.
257+
///
258+
/// The function is thread-safe and can be called from multiple threads simultaneously and
259+
/// in parallel with other thread-safe class methods.
231260
Uint32 GetIndexAllocatorIndex(IBufferSuballocator* pAllocator) const;
232261

233262
/// Updates the vertex buffers, if necessary.
263+
///
264+
/// The function is not thread-safe, but can be called in parallel
265+
/// with other thread-safe class methods.
234266
void UpdateVertexBuffers(IRenderDevice* pDevice, IDeviceContext* pContext);
235267

236268
/// Returns a pointer to the index buffer.
269+
///
270+
/// The function is thread-safe and can be called from multiple threads simultaneously and
271+
/// in parallel with other thread-safe class methods.
237272
IBuffer* GetIndexBuffer(Uint32 Index = 0) const;
238273

239274
/// Returns a pointer to the vertex pool for the given key and index.
@@ -242,54 +277,94 @@ class ResourceManager final : public ObjectBase<IObject>
242277
/// If multiple vertex pools with the same key may exist,
243278
/// an application can use the GetVertexPools() method to
244279
/// get all pools for the given key.
280+
///
281+
/// The function is thread-safe and can be called from multiple threads simultaneously and
282+
/// in parallel with other thread-safe class methods.
245283
IVertexPool* GetVertexPool(const VertexLayoutKey& Key, Uint32 Index = 0);
246284

247285
/// Returns the number of vertex pools for the given key.
286+
///
287+
/// The function is thread-safe and can be called from multiple threads simultaneously and
288+
/// in parallel with other thread-safe class methods.
248289
size_t GetVertexPoolCount(const VertexLayoutKey& Key) const;
249290

250291
/// Returns all vertex pools for the given key.
292+
///
293+
/// The function is thread-safe and can be called from multiple threads simultaneously and
294+
/// in parallel with other thread-safe class methods.
251295
std::vector<IVertexPool*> GetVertexPools(const VertexLayoutKey& Key) const;
252296

253297
/// Returns index of the vertex pool with the give key.
254298
/// If the pool does not exist, InvalidIndex (0xFFFFFFFF) is returned.
299+
///
300+
/// The function is thread-safe and can be called from multiple threads simultaneously and
301+
/// in parallel with other thread-safe class methods.
255302
Uint32 GetVertexPoolIndex(const VertexLayoutKey& Key, IVertexPool* pPool) const;
256303

257304
/// Updates the atlas texture for the given format.
258305
/// If the atlas does not exist, null is returned.
306+
///
307+
/// The function is not thread-safe, but can be called in parallel
308+
/// with other thread-safe class methods.
259309
ITexture* UpdateTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext);
260310

261311
/// Updates all atlas textures.
312+
///
313+
/// The function is not thread-safe, but can be called in parallel
314+
/// with other thread-safe class methods.
262315
void UpdateTextures(IRenderDevice* pDevice, IDeviceContext* pContext);
263316

264317
/// Returns the atlas texture for the given format.
265318
/// If the atlas does not exist, null is returned.
319+
///
320+
/// The function is thread-safe and can be called from multiple threads simultaneously and
321+
/// in parallel with other thread-safe class methods.
266322
ITexture* GetTexture(TEXTURE_FORMAT Fmt) const;
267323

268324
/// Updates all vertex buffers, index buffer and atlas textures.
269325
///
270326
/// This method is equivalent to calling UpdateIndexBuffer(),
271327
/// UpdateVertexBuffers() and UpdateTextures().
328+
///
329+
/// The function is not thread-safe, but can be called in parallel
330+
/// with other thread-safe class methods.
272331
void UpdateAllResources(IRenderDevice* pDevice, IDeviceContext* pContext);
273332

333+
/// Returns the texture atlas description for the given format.
274334
// NB: can't return reference here!
335+
///
336+
/// The function is thread-safe and can be called from multiple threads simultaneously and
337+
/// in parallel with other thread-safe class methods.
275338
TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt);
276339

277340
/// Returns the texture atlas allocation alignment for the given format.
341+
///
342+
/// The function is thread-safe and can be called from multiple threads simultaneously and
343+
/// in parallel with other thread-safe class methods.
278344
Uint32 GetAllocationAlignment(TEXTURE_FORMAT Fmt, Uint32 Width, Uint32 Height);
279345

280346
/// Returns the index buffer usage stats.
347+
///
348+
/// The function is thread-safe and can be called from multiple threads simultaneously and
349+
/// in parallel with other thread-safe class methods.
281350
BufferSuballocatorUsageStats GetIndexBufferUsageStats();
282351

283352
/// Returns the texture atlas usage stats.
284353

285354
/// If `fmt` is not Diligent::TEX_FORMAT_UNKNOWN, returns the stats for the atlas matching the specified format.
286355
/// Otherwise, returns the net usage stats for all atlases.
356+
///
357+
/// The function is thread-safe and can be called from multiple threads simultaneously and
358+
/// in parallel with other thread-safe class methods.
287359
DynamicTextureAtlasUsageStats GetAtlasUsageStats(TEXTURE_FORMAT Fmt = TEX_FORMAT_UNKNOWN);
288360

289361
/// Returns the vertex pool usage stats.
290362

291363
/// If the key is not equal the default key, returns the stats for the vertex pool matching the key.
292364
/// Otherwise, returns the net usage stats for all pools.
365+
///
366+
/// The function is thread-safe and can be called from multiple threads simultaneously and
367+
/// in parallel with other thread-safe class methods.
293368
VertexPoolUsageStats GetVertexPoolUsageStats(const VertexLayoutKey& Key = VertexLayoutKey{});
294369

295370
/// Parameters of the TransitionResourceStates() method.
@@ -362,10 +437,13 @@ class ResourceManager final : public ObjectBase<IObject>
362437
/// \param[in] pContext - Pointer to the device context.
363438
/// \param[in] Info - Resource state transition info, see Diligent::ResourceManager::TransitionResourceStatesInfo.
364439
///
365-
/// \remarks This function is thread-safe.
440+
/// This function is not thread-safe, but can be called in parallel with other thread-safe class methods.
366441
void TransitionResourceStates(IRenderDevice* pDevice, IDeviceContext* pContext, const TransitionResourceStatesInfo& Info);
367442

368443
/// Returns the formats of the allocated texture atlases.
444+
///
445+
/// The function is thread-safe and can be called from multiple threads simultaneously and
446+
/// in parallel with other thread-safe class methods.
369447
std::vector<TEXTURE_FORMAT> GetAllocatedAtlasFormats() const;
370448

371449
private:
@@ -390,21 +468,24 @@ class ResourceManager final : public ObjectBase<IObject>
390468

391469
const BufferSuballocatorCreateInfo m_IndexAllocatorCI;
392470

393-
mutable std::mutex m_IndexAllocatorsMtx;
471+
mutable std::shared_mutex m_IndexAllocatorsMtx;
394472
std::vector<RefCntAutoPtr<IBufferSuballocator>> m_IndexAllocators;
395473

396474
std::unordered_map<VertexLayoutKey, VertexPoolCreateInfoX, VertexLayoutKey::Hasher> m_VertexPoolCIs;
397475

398476
using VertexPoolsHashMapType = std::unordered_map<VertexLayoutKey, std::vector<RefCntAutoPtr<IVertexPool>>, VertexLayoutKey::Hasher>;
399-
mutable std::mutex m_VertexPoolsMtx;
400-
VertexPoolsHashMapType m_VertexPools;
477+
mutable std::shared_mutex m_VertexPoolsMtx;
478+
VertexPoolsHashMapType m_VertexPools;
401479

402480
using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>;
403-
mutable std::mutex m_AtlasesMtx;
404-
AtlasesHashMapType m_Atlases;
481+
mutable std::shared_mutex m_AtlasesMtx;
482+
AtlasesHashMapType m_Atlases;
483+
484+
std::vector<IDynamicTextureAtlas*> m_TmpAtlasList;
485+
std::vector<IVertexPool*> m_TmpVertexPoolList;
405486

406487
using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>;
407-
std::mutex m_TexAllocationsMtx;
488+
std::shared_mutex m_TexAllocationsMtx;
408489
TexAllocationsHashMapType m_TexAllocations;
409490

410491
std::vector<StateTransitionDesc> m_Barriers;

0 commit comments

Comments
 (0)