@@ -749,25 +749,57 @@ Uint32 Model::AddTexture(IRenderDevice* pDevice,
749749 }
750750 else if (pTextureCache != nullptr )
751751 {
752- std::lock_guard<std::mutex> Lock{pTextureCache-> TexturesMtx } ;
752+ bool TextureExpired = false ;
753753
754- auto it = pTextureCache->Textures .find (CacheId);
755- if (it != pTextureCache->Textures .end ())
754+ // First try with shared lock
756755 {
757- TexInfo.pTexture = it->second .Lock ();
758- if (!TexInfo.pTexture )
756+ std::shared_lock<std::shared_mutex> SharedLock{pTextureCache->TexturesMtx };
757+
758+ auto it = pTextureCache->Textures .find (CacheId);
759+ if (it != pTextureCache->Textures .end ())
759760 {
760- // Image width and height (or pixel_type for dds/ktx) are initialized by LoadImageData()
761- // if the texture is found in the cache.
762- if ((Image.Width > 0 && Image.Height > 0 ) ||
763- (Image.FileFormat == IMAGE_FILE_FORMAT_DDS || Image.FileFormat == IMAGE_FILE_FORMAT_KTX))
761+ TexInfo.pTexture = it->second .Lock ();
762+ if (!TexInfo.pTexture )
764763 {
765- UNEXPECTED (" Stale textures should not be found in the texture cache because we hold strong references. "
766- " This must be an unexpected effect of loading resources from multiple threads or a bug." );
764+ // Image width and height (or pixel_type for dds/ktx) are initialized by LoadImageData()
765+ // if the texture is found in the cache.
766+ if ((Image.Width > 0 && Image.Height > 0 ) ||
767+ (Image.FileFormat == IMAGE_FILE_FORMAT_DDS || Image.FileFormat == IMAGE_FILE_FORMAT_KTX))
768+ {
769+ UNEXPECTED (" Stale textures should not be found in the texture cache because we hold strong references. "
770+ " This must be an unexpected effect of loading resources from multiple threads or a bug." );
771+ }
772+ else
773+ {
774+ TextureExpired = true ;
775+ }
767776 }
768- else
777+ }
778+ }
779+
780+ if (TextureExpired)
781+ {
782+ // Upgrade to exclusive lock to remove the expried reference
783+ std::unique_lock<std::shared_mutex> UniqueLock{pTextureCache->TexturesMtx };
784+
785+ auto it = pTextureCache->Textures .find (CacheId);
786+ if (it != pTextureCache->Textures .end ())
787+ {
788+ TexInfo.pTexture = it->second .Lock ();
789+ if (!TexInfo.pTexture )
769790 {
770- pTextureCache->Textures .erase (it);
791+ // Image width and height (or pixel_type for dds/ktx) are initialized by LoadImageData()
792+ // if the texture is found in the cache.
793+ if ((Image.Width > 0 && Image.Height > 0 ) ||
794+ (Image.FileFormat == IMAGE_FILE_FORMAT_DDS || Image.FileFormat == IMAGE_FILE_FORMAT_KTX))
795+ {
796+ UNEXPECTED (" Stale textures should not be found in the texture cache because we hold strong references. "
797+ " This must be an unexpected effect of loading resources from multiple threads or a bug." );
798+ }
799+ else
800+ {
801+ pTextureCache->Textures .erase (it);
802+ }
771803 }
772804 }
773805 }
@@ -914,7 +946,7 @@ Uint32 Model::AddTexture(IRenderDevice* pDevice,
914946
915947 if (TexInfo.pTexture && pTextureCache != nullptr )
916948 {
917- std::lock_guard <std::mutex> Lock {pTextureCache->TexturesMtx };
949+ std::unique_lock <std::shared_mutex> UniqueLock {pTextureCache->TexturesMtx };
918950 pTextureCache->Textures .emplace (CacheId, TexInfo.pTexture );
919951 }
920952 }
@@ -1672,33 +1704,58 @@ bool LoadImageData(tinygltf::Image* gltf_image,
16721704 {
16731705 TextureCacheType& TexCache = *pLoaderData->pTextureCache ;
16741706
1675- std::lock_guard<std::mutex> Lock{TexCache.TexturesMtx };
1707+ RefCntAutoPtr<ITexture> pTexture;
1708+ bool TextureExpired = false ;
16761709
1677- auto it = TexCache.Textures .find (CacheId);
1678- if (it != TexCache.Textures .end ())
1710+ // Try with shared lock first
16791711 {
1680- if (RefCntAutoPtr<ITexture> pTexture = it->second .Lock ())
1681- {
1682- const TextureDesc& TexDesc = pTexture->GetDesc ();
1683- const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs (TexDesc.Format );
1712+ std::shared_lock<std::shared_mutex> SharedLock{TexCache.TexturesMtx };
16841713
1685- gltf_image->width = TexDesc.Width ;
1686- gltf_image->height = TexDesc.Height ;
1687- gltf_image->component = FmtAttribs.NumComponents ;
1688- gltf_image->bits = FmtAttribs.ComponentSize * 8 ;
1689- gltf_image->pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
1714+ auto it = TexCache.Textures .find (CacheId);
1715+ if (it != TexCache.Textures .end ())
1716+ {
1717+ pTexture = it->second .Lock ();
1718+ if (!pTexture)
1719+ {
1720+ // Texture is stale
1721+ TextureExpired = true ;
1722+ }
1723+ }
1724+ }
16901725
1691- // Keep strong reference to ensure the texture is alive (second time, but that's fine).
1692- pLoaderData->TexturesHold .emplace_back (std::move (pTexture));
1726+ if (TextureExpired)
1727+ {
1728+ // Upgrade to exclusive lock to remove stale texture
1729+ std::unique_lock<std::shared_mutex> UniqueLock{TexCache.TexturesMtx };
16931730
1694- return true ;
1695- }
1696- else
1731+ auto it = TexCache.Textures .find (CacheId);
1732+ if (it != TexCache.Textures .end ())
16971733 {
1698- // Texture is stale - remove it from the cache
1699- TexCache.Textures .erase (it);
1734+ pTexture = it->second .Lock ();
1735+ if (!pTexture)
1736+ {
1737+ // Remove stale texture from the cache
1738+ TexCache.Textures .erase (it);
1739+ }
17001740 }
17011741 }
1742+
1743+ if (pTexture)
1744+ {
1745+ const TextureDesc& TexDesc = pTexture->GetDesc ();
1746+ const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs (TexDesc.Format );
1747+
1748+ gltf_image->width = TexDesc.Width ;
1749+ gltf_image->height = TexDesc.Height ;
1750+ gltf_image->component = FmtAttribs.NumComponents ;
1751+ gltf_image->bits = FmtAttribs.ComponentSize * 8 ;
1752+ gltf_image->pixel_type = TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE;
1753+
1754+ // Keep strong reference to ensure the texture is alive (second time, but that's fine).
1755+ pLoaderData->TexturesHold .emplace_back (std::move (pTexture));
1756+
1757+ return true ;
1758+ }
17021759 }
17031760 }
17041761
@@ -1829,7 +1886,7 @@ bool FileExists(const std::string& abs_filename, void* user_data)
18291886 }
18301887 else if (pLoaderData->pTextureCache != nullptr )
18311888 {
1832- std::lock_guard <std::mutex> Lock {pLoaderData->pTextureCache ->TexturesMtx };
1889+ std::shared_lock <std::shared_mutex> SharedLock {pLoaderData->pTextureCache ->TexturesMtx };
18331890
18341891 auto it = pLoaderData->pTextureCache ->Textures .find (CacheId.c_str ());
18351892 if (it != pLoaderData->pTextureCache ->Textures .end ())
@@ -1868,7 +1925,7 @@ bool ReadWholeFile(std::vector<unsigned char>* out,
18681925 }
18691926 else if (pLoaderData->pTextureCache != nullptr )
18701927 {
1871- std::lock_guard <std::mutex> Lock {pLoaderData->pTextureCache ->TexturesMtx };
1928+ std::shared_lock <std::shared_mutex> SharedLock {pLoaderData->pTextureCache ->TexturesMtx };
18721929
18731930 auto it = pLoaderData->pTextureCache ->Textures .find (CacheId.c_str ());
18741931 if (it != pLoaderData->pTextureCache ->Textures .end ())
0 commit comments