diff --git a/libs/vkd3d/device.c b/libs/vkd3d/device.c index 530abe38..0b3c4a66 100644 --- a/libs/vkd3d/device.c +++ b/libs/vkd3d/device.c @@ -2529,6 +2529,7 @@ static void d3d12_device_destroy(struct d3d12_device *device) vkd3d_private_store_destroy(&device->private_store); vkd3d_cleanup_format_info(device); + vkd3d_memory_info_cleanup(&device->memory_info, device); vkd3d_shader_debug_ring_cleanup(&device->debug_ring, device); d3d12_device_global_pipeline_cache_cleanup(device); vkd3d_sampler_state_cleanup(&device->sampler_state, device); @@ -5229,7 +5230,7 @@ static HRESULT d3d12_device_init(struct d3d12_device *device, goto out_cleanup_format_info; if (FAILED(hr = vkd3d_bindless_state_init(&device->bindless_state, device))) - goto out_cleanup_format_info; + goto out_cleanup_memory_info; if (FAILED(hr = vkd3d_view_map_init(&device->sampler_map))) goto out_cleanup_bindless_state; @@ -5273,6 +5274,8 @@ out_cleanup_view_map: vkd3d_view_map_destroy(&device->sampler_map, device); out_cleanup_bindless_state: vkd3d_bindless_state_cleanup(&device->bindless_state, device); +out_cleanup_memory_info: + vkd3d_memory_info_cleanup(&device->memory_info, device); out_cleanup_format_info: vkd3d_cleanup_format_info(device); out_free_memory_allocator: diff --git a/libs/vkd3d/memory.c b/libs/vkd3d/memory.c index 0c4c1bbb..c2f0a04a 100644 --- a/libs/vkd3d/memory.c +++ b/libs/vkd3d/memory.c @@ -143,17 +143,34 @@ static HRESULT vkd3d_create_global_buffer(struct d3d12_device *device, VkDeviceS void vkd3d_free_device_memory(struct d3d12_device *device, const struct vkd3d_device_memory_allocation *allocation) { const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + VkDeviceSize *type_current; + bool budget_sensitive; + VK_CALL(vkFreeMemory(device->vk_device, allocation->vk_memory, NULL)); + budget_sensitive = !!(device->memory_info.budget_sensitive_mask & (1u << allocation->vk_memory_type)); + if (budget_sensitive) + { + type_current = &device->memory_info.type_current[allocation->vk_memory_type]; + pthread_mutex_lock(&device->memory_info.budget_lock); + assert(*type_current >= allocation->size); + *type_current -= allocation->size; + pthread_mutex_unlock(&device->memory_info.budget_lock); + } } static HRESULT vkd3d_try_allocate_device_memory(struct d3d12_device *device, VkDeviceSize size, VkMemoryPropertyFlags type_flags, uint32_t type_mask, void *pNext, struct vkd3d_device_memory_allocation *allocation) { + const VkPhysicalDeviceMemoryProperties *memory_props = &device->memory_properties; const VkMemoryPropertyFlags optional_flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - const VkPhysicalDeviceMemoryProperties *memory_info = &device->memory_properties; const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs; + struct vkd3d_memory_info *memory_info = &device->memory_info; VkMemoryAllocateInfo allocate_info; + VkDeviceSize *type_current; + VkDeviceSize *type_budget; + bool budget_sensitive; + VkResult vr; /* buffer_mask / sampled_mask etc will generally take care of this, * but for certain fallback scenarios where we select other memory @@ -168,12 +185,36 @@ static HRESULT vkd3d_try_allocate_device_memory(struct d3d12_device *device, { uint32_t type_index = vkd3d_bitmask_iter32(&type_mask); - if ((memory_info->memoryTypes[type_index].propertyFlags & type_flags) != type_flags) + if ((memory_props->memoryTypes[type_index].propertyFlags & type_flags) != type_flags) continue; allocate_info.memoryTypeIndex = type_index; - if (VK_CALL(vkAllocateMemory(device->vk_device, &allocate_info, NULL, &allocation->vk_memory)) == VK_SUCCESS) + budget_sensitive = !!(device->memory_info.budget_sensitive_mask & (1u << type_index)); + if (budget_sensitive) + { + type_budget = &memory_info->type_budget[type_index]; + type_current = &memory_info->type_current[type_index]; + pthread_mutex_lock(&memory_info->budget_lock); + if (*type_current + size > *type_budget) + { + WARN("Attempting to allocate from memory type %u, but exceeding fixed budget: %"PRIu64" + %"PRIu64" > %"PRIu64".\n", + type_index, *type_current, size, *type_budget); + pthread_mutex_unlock(&memory_info->budget_lock); + continue; + } + } + + vr = VK_CALL(vkAllocateMemory(device->vk_device, &allocate_info, NULL, &allocation->vk_memory)); + + if (budget_sensitive) + { + if (vr == VK_SUCCESS) + *type_current += size; + pthread_mutex_unlock(&memory_info->budget_lock); + } + + if (vr == VK_SUCCESS) { allocation->vk_memory_type = type_index; allocation->size = size; diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index 087167d4..fc471e5c 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -5971,6 +5971,12 @@ static uint32_t vkd3d_memory_info_find_global_mask(struct d3d12_device *device) return ~mask; } +void vkd3d_memory_info_cleanup(struct vkd3d_memory_info *info, + struct d3d12_device *device) +{ + pthread_mutex_destroy(&info->budget_lock); +} + HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info, struct d3d12_device *device) { @@ -5991,6 +5997,9 @@ HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info, info->global_mask = vkd3d_memory_info_find_global_mask(device); + if (pthread_mutex_init(&info->budget_lock, NULL) != 0) + return E_OUTOFMEMORY; + memset(&buffer_info, 0, sizeof(buffer_info)); buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; buffer_info.size = 65536; diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 9c882ad0..f4f5752c 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -2226,6 +2226,11 @@ struct vkd3d_memory_info_domain uint32_t buffer_type_mask; uint32_t sampled_type_mask; uint32_t rt_ds_type_mask; + + uint32_t budget_sensitive_mask; + VkDeviceSize type_budget[VK_MAX_MEMORY_TYPES]; + VkDeviceSize type_current[VK_MAX_MEMORY_TYPES]; + pthread_mutex_t budget_lock; }; struct vkd3d_memory_info @@ -2245,6 +2250,8 @@ struct vkd3d_memory_info HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info, struct d3d12_device *device); +void vkd3d_memory_info_cleanup(struct vkd3d_memory_info *info, + struct d3d12_device *device); /* meta operations */ struct vkd3d_clear_uav_args