@@ -62,6 +62,38 @@ extern bool g_vulkanDeviceHasUnifiedMemory;
6262template <class T >
6363class AcceleratorBuffer ;
6464
65+ // /@brief Levels of memory pressure
66+ enum class MemoryPressureLevel
67+ {
68+ // /@brief A memory allocation has failed and we need to free memory immediately to continue execution
69+ Hard,
70+
71+ /* *
72+ @brief Free memory has reached a warning threshold.
73+
74+ We should trim caches or otherwise try to make space but don't need to be too aggressive about it.
75+
76+ This level is only available if we have VK_EXT_memory_budget; without this extension we do not know about
77+ memory pressure until a hard allocation failure occurs.
78+ */
79+ Soft
80+ };
81+
82+ // /@brief Types of memory pressure
83+ enum class MemoryPressureType
84+ {
85+ // /@brief Pinned CPU-side memory
86+ Host,
87+
88+ // /@brief GPU-side memory
89+ Device
90+ };
91+
92+ // /@brief Memory pressure handler type, called when free memory reaches a warning level or a Vulkan allocation fails
93+ typedef bool (*MemoryPressureHandler)(MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize);
94+
95+ bool OnMemoryPressure (MemoryPressureLevel level, MemoryPressureType type, size_t requestedSize);
96+
6597template <class T >
6698class AcceleratorBufferIterator
6799{
@@ -1263,9 +1295,43 @@ class AcceleratorBuffer
12631295 // (may be rounded up from what we asked for)
12641296 auto req = m_gpuBuffer->getMemoryRequirements ();
12651297
1266- // For now, always use local memory
1298+ // Try to allocate the memory
12671299 vk::MemoryAllocateInfo info (req.size , g_vkLocalMemoryType);
1268- m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1300+ try
1301+ {
1302+ // For now, always use local memory
1303+ m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1304+ }
1305+
1306+ // Fallback path in case of low memory
1307+ catch (vk::OutOfDeviceMemoryError& ex)
1308+ {
1309+ bool ok = false ;
1310+ while (!ok)
1311+ {
1312+ // Attempt to free memory and stop if we couldn't free more
1313+ if (!OnMemoryPressure (MemoryPressureLevel::Hard, MemoryPressureType::Device, req.size ))
1314+ break ;
1315+
1316+ // /Retry the allocation
1317+ try
1318+ {
1319+ m_gpuPhysMem = std::make_unique<vk::raii::DeviceMemory>(*g_vkComputeDevice, info);
1320+ ok = true ;
1321+ }
1322+ catch (vk::OutOfDeviceMemoryError& ex2)
1323+ {
1324+ LogDebug (" Allocation failed again\n " );
1325+ }
1326+ }
1327+
1328+ // If we get here, we couldn't allocate no matter what
1329+ LogError (
1330+ " Failed to allocate %s of GPU memory despite our best efforts to reclaim space\n "
1331+ " This is unrecoverable (for now).\n " ,
1332+ Unit (Unit::UNIT_BYTES).PrettyPrint (req.size ).c_str ());
1333+ exit (1 );
1334+ }
12691335 m_gpuMemoryType = MEM_TYPE_GPU_ONLY;
12701336
12711337 m_gpuBuffer->bindMemory (**m_gpuPhysMem, 0 );
@@ -1348,4 +1414,6 @@ class AcceleratorBuffer
13481414
13491415};
13501416
1417+ extern std::set<MemoryPressureHandler> g_memoryPressureHandlers;
1418+
13511419#endif
0 commit comments