vkd3d: Add a memory budget per memory type.
For resizable BAR, we don't want to endlessly promote UPLOAD heaps to BAR since VRAM is precious. The aim is to set a fixed budget where we can keep allocating until full, at which point we fall back to plain HOST. Signed-off-by: Hans-Kristian Arntzen <post@arntzen-software.no>
This commit is contained in:
parent
e0451bb541
commit
abdaeb136d
|
@ -2529,6 +2529,7 @@ static void d3d12_device_destroy(struct d3d12_device *device)
|
||||||
vkd3d_private_store_destroy(&device->private_store);
|
vkd3d_private_store_destroy(&device->private_store);
|
||||||
|
|
||||||
vkd3d_cleanup_format_info(device);
|
vkd3d_cleanup_format_info(device);
|
||||||
|
vkd3d_memory_info_cleanup(&device->memory_info, device);
|
||||||
vkd3d_shader_debug_ring_cleanup(&device->debug_ring, device);
|
vkd3d_shader_debug_ring_cleanup(&device->debug_ring, device);
|
||||||
d3d12_device_global_pipeline_cache_cleanup(device);
|
d3d12_device_global_pipeline_cache_cleanup(device);
|
||||||
vkd3d_sampler_state_cleanup(&device->sampler_state, 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;
|
goto out_cleanup_format_info;
|
||||||
|
|
||||||
if (FAILED(hr = vkd3d_bindless_state_init(&device->bindless_state, device)))
|
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)))
|
if (FAILED(hr = vkd3d_view_map_init(&device->sampler_map)))
|
||||||
goto out_cleanup_bindless_state;
|
goto out_cleanup_bindless_state;
|
||||||
|
@ -5273,6 +5274,8 @@ out_cleanup_view_map:
|
||||||
vkd3d_view_map_destroy(&device->sampler_map, device);
|
vkd3d_view_map_destroy(&device->sampler_map, device);
|
||||||
out_cleanup_bindless_state:
|
out_cleanup_bindless_state:
|
||||||
vkd3d_bindless_state_cleanup(&device->bindless_state, device);
|
vkd3d_bindless_state_cleanup(&device->bindless_state, device);
|
||||||
|
out_cleanup_memory_info:
|
||||||
|
vkd3d_memory_info_cleanup(&device->memory_info, device);
|
||||||
out_cleanup_format_info:
|
out_cleanup_format_info:
|
||||||
vkd3d_cleanup_format_info(device);
|
vkd3d_cleanup_format_info(device);
|
||||||
out_free_memory_allocator:
|
out_free_memory_allocator:
|
||||||
|
|
|
@ -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)
|
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;
|
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));
|
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,
|
static HRESULT vkd3d_try_allocate_device_memory(struct d3d12_device *device,
|
||||||
VkDeviceSize size, VkMemoryPropertyFlags type_flags, uint32_t type_mask,
|
VkDeviceSize size, VkMemoryPropertyFlags type_flags, uint32_t type_mask,
|
||||||
void *pNext, struct vkd3d_device_memory_allocation *allocation)
|
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 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;
|
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||||
|
struct vkd3d_memory_info *memory_info = &device->memory_info;
|
||||||
VkMemoryAllocateInfo allocate_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,
|
/* buffer_mask / sampled_mask etc will generally take care of this,
|
||||||
* but for certain fallback scenarios where we select other memory
|
* 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);
|
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;
|
continue;
|
||||||
|
|
||||||
allocate_info.memoryTypeIndex = type_index;
|
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->vk_memory_type = type_index;
|
||||||
allocation->size = size;
|
allocation->size = size;
|
||||||
|
|
|
@ -5971,6 +5971,12 @@ static uint32_t vkd3d_memory_info_find_global_mask(struct d3d12_device *device)
|
||||||
return ~mask;
|
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,
|
HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info,
|
||||||
struct d3d12_device *device)
|
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);
|
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));
|
memset(&buffer_info, 0, sizeof(buffer_info));
|
||||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
buffer_info.size = 65536;
|
buffer_info.size = 65536;
|
||||||
|
|
|
@ -2226,6 +2226,11 @@ struct vkd3d_memory_info_domain
|
||||||
uint32_t buffer_type_mask;
|
uint32_t buffer_type_mask;
|
||||||
uint32_t sampled_type_mask;
|
uint32_t sampled_type_mask;
|
||||||
uint32_t rt_ds_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
|
struct vkd3d_memory_info
|
||||||
|
@ -2245,6 +2250,8 @@ struct vkd3d_memory_info
|
||||||
|
|
||||||
HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info,
|
HRESULT vkd3d_memory_info_init(struct vkd3d_memory_info *info,
|
||||||
struct d3d12_device *device);
|
struct d3d12_device *device);
|
||||||
|
void vkd3d_memory_info_cleanup(struct vkd3d_memory_info *info,
|
||||||
|
struct d3d12_device *device);
|
||||||
|
|
||||||
/* meta operations */
|
/* meta operations */
|
||||||
struct vkd3d_clear_uav_args
|
struct vkd3d_clear_uav_args
|
||||||
|
|
Loading…
Reference in New Issue