yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
ba8132345
master
1#include "slang-test-device-cache.h" 2 3#include <algorithm> 4 5// Static member accessor functions (Meyer's singleton pattern) 6// This ensures proper destruction order - function-local statics are destroyed 7// in reverse order of first access, avoiding the static destruction order fiasco 8std::mutex & DeviceCache ::getMutex () 9{ 10static std::mutex instance ; 11return instance ; 12} 13 14std::unordered_map < 15DeviceCache ::DeviceCacheKey , 16DeviceCache ::CachedDevice , 17DeviceCache ::DeviceCacheKeyHash >& 18DeviceCache ::getDeviceCache () 19{ 20static std::unordered_map < DeviceCacheKey ,CachedDevice ,DeviceCacheKeyHash > instance ; 21return instance ; 22} 23 24uint64_t & DeviceCache ::getNextCreationOrder () 25{ 26static uint64_t instance = 0 ; 27return instance ; 28} 29 30bool DeviceCache ::DeviceCacheKey ::operator== (const DeviceCacheKey & other )const 31{ 32return deviceType == other .deviceType && enableValidation == other .enableValidation && 33enableRayTracingValidation == other .enableRayTracingValidation && 34profileName == other .profileName && requiredFeatures == other .requiredFeatures ; 35} 36 37std::size_t DeviceCache ::DeviceCacheKeyHash ::operator()(const DeviceCacheKey & key )const 38{ 39 std::size_t h1 = std::hash < int > {}(static_cast < int > (key .deviceType )); 40 std::size_t h2 = std::hash < bool > {}(key .enableValidation ); 41 std::size_t h3 = std::hash < bool > {}(key .enableRayTracingValidation ); 42 std::size_t h4 = std::hash < std::string > {}(key .profileName ); 43 44 std::size_t h5 = 0 ; 45for (const auto & feature :key .requiredFeatures ) 46 { 47h5 ^= std::hash < std::string > {}(feature )+ 0x9e3779b9 + (h5 <<6 )+ (h5 >>2 ); 48 } 49 50return h1 ^ (h2 <<1 ) ^ (h3 <<2 ) ^ (h4 <<3 ) ^ (h5 <<4 ); 51} 52 53DeviceCache ::CachedDevice ::CachedDevice () 54 :creationOrder (0 ) 55{ 56} 57 58void DeviceCache ::evictOldestDeviceIfNeeded () 59{ 60auto & deviceCache = getDeviceCache (); 61if (deviceCache .size ()< MAX_CACHED_DEVICES ) 62return ; 63 64// Find the oldest device to evict 65auto oldestIt = deviceCache .end (); 66uint64_t oldestCreationOrder = UINT64_MAX ; 67 68for (auto it = deviceCache .begin ();it != deviceCache .end ();++ it ) 69 { 70if (it -> second .creationOrder < oldestCreationOrder ) 71 { 72oldestCreationOrder = it -> second .creationOrder ; 73oldestIt = it ; 74 } 75 } 76 77// Remove the oldest device - ComPtr will handle the actual device release 78if (oldestIt != deviceCache .end ()) 79 { 80deviceCache .erase (oldestIt ); 81 } 82} 83 84SlangResult DeviceCache ::acquireDevice (const rhi::DeviceDesc & desc , rhi::IDevice ** outDevice ) 85{ 86if (!outDevice ) 87return SLANG_E_INVALID_ARG ; 88 89* outDevice = nullptr ; 90 91// Skip caching for CUDA devices due to crashes 92if (desc .deviceType == rhi::DeviceType ::CUDA ) 93 { 94return rhi::getRHI ()-> createDevice (desc ,outDevice ); 95 } 96 97 std::lock_guard < std::mutex > lock (getMutex ()); 98auto & deviceCache = getDeviceCache (); 99auto & nextCreationOrder = getNextCreationOrder (); 100 101// Create cache key 102DeviceCacheKey key ; 103key .deviceType = desc .deviceType ; 104key .enableValidation = desc .enableValidation ; 105key .enableRayTracingValidation = desc .enableRayTracingValidation ; 106key .profileName = desc .slang .targetProfile ?desc .slang .targetProfile :"Unknown" ; 107 108// Add required features to key 109for (int i = 0 ;i < desc .requiredFeatureCount ;++ i ) 110 { 111key .requiredFeatures .push_back (desc .requiredFeatures [i ]); 112 } 113 std::sort (key .requiredFeatures .begin (),key .requiredFeatures .end ()); 114 115// Evict oldest device if we've reached the limit 116evictOldestDeviceIfNeeded (); 117 118// Check if we have a cached device 119auto it = deviceCache .find (key ); 120if (it != deviceCache .end ()) 121 { 122// Return the cached device - COM reference counting handles the references 123* outDevice = it -> second .device .get (); 124if (* outDevice ) 125 { 126 (* outDevice )-> addRef (); 127return SLANG_OK ; 128 } 129 } 130 131// Create new device 132Slang ::ComPtr < rhi::IDevice > device ; 133auto result = rhi::getRHI ()-> createDevice (desc ,device .writeRef ()); 134if (SLANG_FAILED (result )) 135 { 136return result ; 137 } 138 139// Cache the device 140CachedDevice & cached = deviceCache [key ]; 141cached .device = device ; 142cached .creationOrder = nextCreationOrder ++ ; 143 144// Return the device with proper reference counting 145* outDevice = device .get (); 146if (* outDevice ) 147 { 148 (* outDevice )-> addRef (); 149 } 150 151return SLANG_OK ; 152} 153 154 155void DeviceCache ::cleanCache () 156{ 157 std::lock_guard < std::mutex > lock (getMutex ()); 158auto & deviceCache = getDeviceCache (); 159deviceCache .clear (); 160}