mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-01-28 13:05:02 -08:00
libs/vkd3d: Allocate GPU virtual addresses for resources.
Direct3D 12 resources, buffers in particular, are bound to the pipeline by their GPU virtual address. In Vulkan, these addresses are not visible to the application. We previously handled this by returning the VkBuffer handle as virtual address, but this can't work when the application binds anything other than the resource's base GPU VA. Instead, we allocate ranges of GPU address space and associate resources with it. This uses the (naive) approach of simply allocating subsequent ranges, and never reclaiming them. Eventually we'll have to revisit that.
This commit is contained in:
parent
1acd3d44b1
commit
605a02274e
@ -2379,14 +2379,16 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetGraphicsRootConstantBufferVi
|
||||
const struct vkd3d_vk_device_procs *vk_procs;
|
||||
struct VkWriteDescriptorSet descriptor_write;
|
||||
struct VkDescriptorBufferInfo buffer_info;
|
||||
struct d3d12_resource *resource;
|
||||
|
||||
TRACE("iface %p, root_parameter_index %u, address %#"PRIx64".\n",
|
||||
iface, root_parameter_index, address);
|
||||
|
||||
vk_procs = &list->device->vk_procs;
|
||||
|
||||
buffer_info.buffer = (VkBuffer)address;
|
||||
buffer_info.offset = 0;
|
||||
resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, address);
|
||||
buffer_info.buffer = resource->u.vk_buffer;
|
||||
buffer_info.offset = address - resource->gpu_address;
|
||||
buffer_info.range = VK_WHOLE_SIZE;
|
||||
|
||||
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
@ -2435,6 +2437,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12Graphics
|
||||
{
|
||||
struct d3d12_command_list *list = impl_from_ID3D12GraphicsCommandList(iface);
|
||||
const struct vkd3d_vk_device_procs *vk_procs;
|
||||
struct d3d12_resource *resource;
|
||||
enum VkIndexType index_type;
|
||||
|
||||
TRACE("iface %p, view %p.\n", iface, view);
|
||||
@ -2454,7 +2457,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetIndexBuffer(ID3D12Graphics
|
||||
return;
|
||||
}
|
||||
|
||||
VK_CALL(vkCmdBindIndexBuffer(list->vk_command_buffer, (VkBuffer)view->BufferLocation, 0, index_type));
|
||||
resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, view->BufferLocation);
|
||||
VK_CALL(vkCmdBindIndexBuffer(list->vk_command_buffer, resource->u.vk_buffer,
|
||||
view->BufferLocation - resource->gpu_address, index_type));
|
||||
}
|
||||
|
||||
static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12GraphicsCommandList *iface,
|
||||
@ -2464,6 +2469,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12Graphi
|
||||
VkDeviceSize offsets[ARRAY_SIZE(list->strides)];
|
||||
const struct vkd3d_vk_device_procs *vk_procs;
|
||||
VkBuffer buffers[ARRAY_SIZE(list->strides)];
|
||||
struct d3d12_resource *resource;
|
||||
unsigned int i;
|
||||
|
||||
TRACE("iface %p, start_slot %u, view_count %u, views %p.\n", iface, start_slot, view_count, views);
|
||||
@ -2478,8 +2484,9 @@ static void STDMETHODCALLTYPE d3d12_command_list_IASetVertexBuffers(ID3D12Graphi
|
||||
|
||||
for (i = 0; i < view_count; ++i)
|
||||
{
|
||||
offsets[i] = 0;
|
||||
buffers[i] = (VkBuffer)views[i].BufferLocation;
|
||||
resource = vkd3d_gpu_va_allocator_dereference(&list->device->gpu_va_allocator, views[i].BufferLocation);
|
||||
offsets[i] = views[i].BufferLocation - resource->gpu_address;
|
||||
buffers[i] = resource->u.vk_buffer;
|
||||
list->strides[start_slot + i] = views[i].StrideInBytes;
|
||||
}
|
||||
|
||||
|
@ -480,6 +480,75 @@ static HRESULT vkd3d_create_vk_device(struct d3d12_device *device)
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
|
||||
size_t size, void *ptr)
|
||||
{
|
||||
D3D12_GPU_VIRTUAL_ADDRESS ceiling = ~(D3D12_GPU_VIRTUAL_ADDRESS)0;
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!vkd3d_array_reserve((void **)&allocator->allocations, &allocator->allocations_size,
|
||||
allocator->allocation_count + 1, sizeof(*allocator->allocations)))
|
||||
return 0;
|
||||
|
||||
if (size > ceiling || ceiling - size < allocator->floor)
|
||||
return 0;
|
||||
|
||||
allocation = &allocator->allocations[allocator->allocation_count++];
|
||||
allocation->base = allocator->floor;
|
||||
allocation->size = size;
|
||||
allocation->ptr = ptr;
|
||||
|
||||
allocator->floor += size;
|
||||
|
||||
return allocation->base;
|
||||
}
|
||||
|
||||
static int vkd3d_gpu_va_allocation_compare(const void *k, const void *e)
|
||||
{
|
||||
const struct vkd3d_gpu_va_allocation *allocation = e;
|
||||
const D3D12_GPU_VIRTUAL_ADDRESS *address = k;
|
||||
|
||||
if (*address < allocation->base)
|
||||
return -1;
|
||||
if (*address - allocation->base >= allocation->size)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address)
|
||||
{
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!(allocation = bsearch(&address, allocator->allocations, allocator->allocation_count,
|
||||
sizeof(*allocation), vkd3d_gpu_va_allocation_compare)))
|
||||
return NULL;
|
||||
|
||||
return allocation->ptr;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator, D3D12_GPU_VIRTUAL_ADDRESS address)
|
||||
{
|
||||
struct vkd3d_gpu_va_allocation *allocation;
|
||||
|
||||
if (!(allocation = bsearch(&address, allocator->allocations, allocator->allocation_count,
|
||||
sizeof(*allocation), vkd3d_gpu_va_allocation_compare)))
|
||||
return;
|
||||
|
||||
if (allocation->base == address)
|
||||
allocation->ptr = NULL;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_init(struct vkd3d_gpu_va_allocator *allocator)
|
||||
{
|
||||
memset(allocator, 0, sizeof(*allocator));
|
||||
allocator->floor = 0x1000;
|
||||
}
|
||||
|
||||
void vkd3d_gpu_va_allocator_cleanup(struct vkd3d_gpu_va_allocator *allocator)
|
||||
{
|
||||
vkd3d_free(allocator->allocations);
|
||||
}
|
||||
|
||||
/* ID3D12Device */
|
||||
static inline struct d3d12_device *impl_from_ID3D12Device(ID3D12Device *iface)
|
||||
{
|
||||
@ -527,6 +596,7 @@ static ULONG STDMETHODCALLTYPE d3d12_device_Release(ID3D12Device *iface)
|
||||
{
|
||||
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
|
||||
|
||||
vkd3d_gpu_va_allocator_cleanup(&device->gpu_va_allocator);
|
||||
vkd3d_fence_worker_stop(&device->fence_worker);
|
||||
VK_CALL(vkDestroyDevice(device->vk_device, NULL));
|
||||
vkd3d_instance_destroy(&device->vkd3d_instance);
|
||||
@ -1270,6 +1340,8 @@ static HRESULT d3d12_device_init(struct d3d12_device *device,
|
||||
return hr;
|
||||
}
|
||||
|
||||
vkd3d_gpu_va_allocator_init(&device->gpu_va_allocator);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -276,10 +276,20 @@ static HRESULT vkd3d_allocate_buffer_memory(struct d3d12_resource *resource, str
|
||||
if (FAILED(hr = vkd3d_allocate_device_memory(device, heap_properties, heap_flags,
|
||||
&memory_requirements, &resource->vk_memory)))
|
||||
return hr;
|
||||
if (!(resource->gpu_address = vkd3d_gpu_va_allocator_allocate(&device->gpu_va_allocator,
|
||||
memory_requirements.size, resource)))
|
||||
{
|
||||
ERR("Failed to allocate GPU VA.\n");
|
||||
VK_CALL(vkFreeMemory(device->vk_device, resource->vk_memory, NULL));
|
||||
resource->vk_memory = VK_NULL_HANDLE;
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if ((vr = VK_CALL(vkBindBufferMemory(device->vk_device, resource->u.vk_buffer, resource->vk_memory, 0))) < 0)
|
||||
{
|
||||
WARN("Failed to bind memory, vr %d.\n", vr);
|
||||
vkd3d_gpu_va_allocator_free(&device->gpu_va_allocator, resource->gpu_address);
|
||||
resource->gpu_address = 0;
|
||||
VK_CALL(vkFreeMemory(device->vk_device, resource->vk_memory, NULL));
|
||||
resource->vk_memory = VK_NULL_HANDLE;
|
||||
return hresult_from_vk_result(vr);
|
||||
@ -322,6 +332,9 @@ static void d3d12_resource_destroy(struct d3d12_resource *resource, struct d3d12
|
||||
if (resource->flags & VKD3D_RESOURCE_EXTERNAL)
|
||||
return;
|
||||
|
||||
if (resource->gpu_address)
|
||||
vkd3d_gpu_va_allocator_free(&device->gpu_va_allocator, resource->gpu_address);
|
||||
|
||||
if (d3d12_resource_is_buffer(resource))
|
||||
VK_CALL(vkDestroyBuffer(device->vk_device, resource->u.vk_buffer, NULL));
|
||||
else
|
||||
@ -531,13 +544,7 @@ static D3D12_GPU_VIRTUAL_ADDRESS STDMETHODCALLTYPE d3d12_resource_GetGPUVirtualA
|
||||
|
||||
TRACE("iface %p.\n", iface);
|
||||
|
||||
if (!d3d12_resource_is_buffer(resource))
|
||||
{
|
||||
WARN("GPU virtual address for textures is always 0.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return resource->u.gpu_address;
|
||||
return resource->gpu_address;
|
||||
}
|
||||
|
||||
static HRESULT STDMETHODCALLTYPE d3d12_resource_WriteToSubresource(ID3D12Resource *iface,
|
||||
@ -649,6 +656,7 @@ static HRESULT d3d12_committed_resource_init(struct d3d12_resource *resource, st
|
||||
if (optimized_clear_value)
|
||||
FIXME("Ignoring optimized clear value.\n");
|
||||
|
||||
resource->gpu_address = 0;
|
||||
resource->flags = 0;
|
||||
|
||||
switch (desc->Dimension)
|
||||
|
@ -92,6 +92,29 @@ HRESULT vkd3d_fence_worker_start(struct vkd3d_fence_worker *worker,
|
||||
struct d3d12_device *device) DECLSPEC_HIDDEN;
|
||||
HRESULT vkd3d_fence_worker_stop(struct vkd3d_fence_worker *worker) DECLSPEC_HIDDEN;
|
||||
|
||||
struct vkd3d_gpu_va_allocator
|
||||
{
|
||||
D3D12_GPU_VIRTUAL_ADDRESS floor;
|
||||
|
||||
struct vkd3d_gpu_va_allocation
|
||||
{
|
||||
D3D12_GPU_VIRTUAL_ADDRESS base;
|
||||
SIZE_T size;
|
||||
void *ptr;
|
||||
} *allocations;
|
||||
size_t allocations_size;
|
||||
size_t allocation_count;
|
||||
};
|
||||
|
||||
D3D12_GPU_VIRTUAL_ADDRESS vkd3d_gpu_va_allocator_allocate(struct vkd3d_gpu_va_allocator *allocator,
|
||||
size_t size, void *ptr) DECLSPEC_HIDDEN;
|
||||
void vkd3d_gpu_va_allocator_cleanup(struct vkd3d_gpu_va_allocator *allocator) DECLSPEC_HIDDEN;
|
||||
void *vkd3d_gpu_va_allocator_dereference(struct vkd3d_gpu_va_allocator *allocator,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS address) DECLSPEC_HIDDEN;
|
||||
void vkd3d_gpu_va_allocator_free(struct vkd3d_gpu_va_allocator *allocator,
|
||||
D3D12_GPU_VIRTUAL_ADDRESS address) DECLSPEC_HIDDEN;
|
||||
void vkd3d_gpu_va_allocator_init(struct vkd3d_gpu_va_allocator *allocator) DECLSPEC_HIDDEN;
|
||||
|
||||
/* ID3D12Fence */
|
||||
struct d3d12_fence
|
||||
{
|
||||
@ -127,9 +150,9 @@ struct d3d12_resource
|
||||
|
||||
D3D12_RESOURCE_DESC desc;
|
||||
|
||||
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
||||
union
|
||||
{
|
||||
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
|
||||
VkBuffer vk_buffer;
|
||||
VkImage vk_image;
|
||||
} u;
|
||||
@ -427,6 +450,7 @@ struct d3d12_device
|
||||
struct vkd3d_vk_device_procs vk_procs;
|
||||
vkd3d_signal_event_pfn signal_event;
|
||||
|
||||
struct vkd3d_gpu_va_allocator gpu_va_allocator;
|
||||
struct vkd3d_fence_worker fence_worker;
|
||||
|
||||
unsigned int direct_queue_family_index;
|
||||
|
Loading…
x
Reference in New Issue
Block a user