vkd3d: Add new functions to create and destroy resources.

Signed-off-by: Philip Rebohle <philip.rebohle@tu-dortmund.de>
This commit is contained in:
Philip Rebohle 2021-02-03 12:15:40 +01:00 committed by Hans-Kristian Arntzen
parent fee47ef695
commit ba632148d7
2 changed files with 365 additions and 6 deletions

View File

@ -3181,6 +3181,347 @@ static HRESULT d3d12_resource_init(struct d3d12_resource *resource, struct d3d12
return S_OK;
}
static void d3d12_resource_destroy_2(struct d3d12_resource *resource, struct d3d12_device *device)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
vkd3d_view_map_destroy(&resource->view_map, resource->device);
#ifdef VKD3D_ENABLE_DESCRIPTOR_QA
vkd3d_descriptor_debug_unregister_cookie(resource->cookie);
#endif
if (resource->flags & VKD3D_RESOURCE_EXTERNAL)
return;
if (resource->flags & VKD3D_RESOURCE_SPARSE)
{
VK_CALL(vkFreeMemory(device->vk_device, resource->sparse.vk_metadata_memory, NULL));
vkd3d_free(resource->sparse.tiles);
vkd3d_free(resource->sparse.tilings);
if (resource->res.va)
{
vkd3d_va_map_remove(&device->memory_allocator.va_map, &resource->res);
if (!device->device_info.buffer_device_address_features.bufferDeviceAddress)
vkd3d_va_map_free_fake_va(&device->memory_allocator.va_map, resource->res.va, resource->res.size);
}
}
if (d3d12_resource_is_texture(resource))
VK_CALL(vkDestroyImage(device->vk_device, resource->vk_image, NULL));
else if (resource->flags & VKD3D_RESOURCE_SPARSE)
VK_CALL(vkDestroyBuffer(device->vk_device, resource->vk_buffer, NULL));
if ((resource->flags & VKD3D_RESOURCE_ALLOCATION) && resource->mem.vk_memory)
vkd3d_free_memory_2(device, &device->memory_allocator, &resource->mem);
vkd3d_private_store_destroy(&resource->private_store);
d3d12_device_release(resource->device);
vkd3d_free(resource);
}
static HRESULT d3d12_resource_create_vk_resource(struct d3d12_resource *resource, struct d3d12_device *device)
{
const D3D12_HEAP_PROPERTIES *heap_properties;
HRESULT hr;
heap_properties = resource->flags & VKD3D_RESOURCE_SPARSE
? NULL : &resource->heap_properties;
if (resource->desc.Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
{
if (FAILED(hr = vkd3d_create_buffer(device, heap_properties,
D3D12_HEAP_FLAG_NONE, &resource->desc, &resource->vk_buffer)))
return hr;
}
else
{
resource->initial_layout_transition = 1;
if (!resource->desc.MipLevels)
resource->desc.MipLevels = max_miplevel_count(&resource->desc);
if (FAILED(hr = vkd3d_create_image(device, heap_properties,
D3D12_HEAP_FLAG_NONE, &resource->desc, resource, &resource->vk_image)))
return hr;
}
return S_OK;
}
static HRESULT d3d12_resource_create_2(struct d3d12_device *device, uint32_t flags,
const D3D12_RESOURCE_DESC *desc, const D3D12_HEAP_PROPERTIES *heap_properties,
D3D12_RESOURCE_STATES initial_state, const D3D12_CLEAR_VALUE *optimized_clear_value,
struct d3d12_resource **resource)
{
struct d3d12_resource *object;
HRESULT hr;
if (FAILED(hr = d3d12_resource_validate_create_info(desc,
heap_properties, initial_state, optimized_clear_value, device)))
return hr;
if (!(object = vkd3d_malloc(sizeof(*object))))
return E_OUTOFMEMORY;
memset(object, 0, sizeof(*object));
object->ID3D12Resource_iface.lpVtbl = &d3d12_resource_vtbl;
if (FAILED(hr = vkd3d_view_map_init(&object->view_map)))
{
vkd3d_free(object);
return hr;
}
if (FAILED(hr = vkd3d_private_store_init(&object->private_store)))
{
vkd3d_view_map_destroy(&object->view_map, device);
vkd3d_free(object);
return hr;
}
object->refcount = 1;
object->internal_refcount = 1;
object->desc = *desc;
object->device = device;
object->flags = flags;
object->cookie = InterlockedIncrement64(&global_cookie_counter);
object->format = vkd3d_format_from_d3d12_resource_desc(device, desc, 0);
if (heap_properties)
object->heap_properties = *heap_properties;
d3d12_device_add_ref(device);
#ifdef VKD3D_ENABLE_DESCRIPTOR_QA
vkd3d_descriptor_debug_register_resource_cookie(object->cookie, desc);
#endif
*resource = object;
return S_OK;
}
HRESULT d3d12_resource_create_committed_2(struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
{
struct d3d12_resource *object;
HRESULT hr;
if (FAILED(hr = d3d12_resource_create_2(device, VKD3D_RESOURCE_COMMITTED | VKD3D_RESOURCE_ALLOCATION,
desc, heap_properties, initial_state, optimized_clear_value, &object)))
return hr;
if (d3d12_resource_is_texture(object))
{
struct vkd3d_allocate_resource_memory_info allocate_info;
if (FAILED(hr = d3d12_resource_create_vk_resource(object, device)))
goto fail;
memset(&allocate_info, 0, sizeof(allocate_info));
allocate_info.heap_properties = *heap_properties;
allocate_info.heap_flags = heap_flags;
if (desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
allocate_info.heap_flags |= D3D12_HEAP_FLAG_ALLOW_ONLY_RT_DS_TEXTURES;
else
allocate_info.heap_flags |= D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS_TEXTURES;
allocate_info.vk_image = object->vk_image;
if (FAILED(hr = vkd3d_allocate_resource_memory_2(device,
&device->memory_allocator, &allocate_info, &object->mem)))
goto fail;
object->heap_offset = object->mem.offset;
}
else
{
struct vkd3d_allocate_heap_memory_info allocate_info;
memset(&allocate_info, 0, sizeof(allocate_info));
allocate_info.heap_desc.Properties = *heap_properties;
allocate_info.heap_desc.Alignment = desc->Alignment ? desc->Alignment : D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;
allocate_info.heap_desc.SizeInBytes = align(desc->Width, allocate_info.heap_desc.Alignment);
allocate_info.heap_desc.Flags = heap_flags | D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS;
if (FAILED(hr = vkd3d_allocate_heap_memory_2(device,
&device->memory_allocator, &allocate_info, &object->mem)))
goto fail;
object->vk_buffer = object->mem.resource.vk_buffer;
object->gpu_address = object->mem.resource.va;
object->heap_offset = object->mem.offset;
}
*resource = object;
return S_OK;
fail:
d3d12_resource_destroy_2(object, device);
return hr;
}
static HRESULT d3d12_resource_bind_image_memory_2(struct d3d12_resource *resource, struct d3d12_device *device)
{
const struct vkd3d_vk_device_procs *vk_procs = &device->vk_procs;
VkMemoryRequirements memory_requirements;
VkResult vr;
HRESULT hr;
VK_CALL(vkGetImageMemoryRequirements(device->vk_device, resource->vk_image, &memory_requirements));
/* TODO implement sparse fallback instead to enforce alignment */
if (resource->heap_offset & (memory_requirements.alignment - 1))
{
struct vkd3d_allocate_heap_memory_info allocate_info;
FIXME("Cannot allocate image %p with alignment %#"PRIx64" at heap offset %#"PRIx64", allocating device memory.\n",
resource->vk_image, memory_requirements.alignment, resource->heap_offset);
memset(&allocate_info, 0, sizeof(allocate_info));
allocate_info.heap_desc.Properties = resource->heap_2->desc.Properties;
allocate_info.heap_desc.SizeInBytes = memory_requirements.size;
allocate_info.heap_desc.Alignment = memory_requirements.alignment;
allocate_info.heap_desc.Flags = resource->heap_2->desc.Flags | D3D12_HEAP_FLAG_DENY_BUFFERS;
if (FAILED(hr = vkd3d_allocate_heap_memory_2(device,
&device->memory_allocator, &allocate_info, &resource->mem)))
return hr;
resource->flags |= VKD3D_RESOURCE_ALLOCATION;
resource->heap_offset = resource->mem.offset;
}
if ((vr = VK_CALL(vkBindImageMemory(device->vk_device, resource->vk_image,
resource->mem.vk_memory, resource->heap_offset)) < 0))
{
ERR("Failed to bind image memory, vr %d.\n", vr);
return hresult_from_vk_result(vr);
}
return S_OK;
}
static HRESULT d3d12_resource_validate_heap(const D3D12_RESOURCE_DESC *resource_desc, struct d3d12_heap_2 *heap)
{
D3D12_HEAP_FLAGS deny_flag;
if (resource_desc->Dimension == D3D12_RESOURCE_DIMENSION_BUFFER)
deny_flag = D3D12_HEAP_FLAG_DENY_BUFFERS;
else if (resource_desc->Flags & (D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL))
deny_flag = D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES;
else
deny_flag = D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES;
if (heap->desc.Flags & deny_flag)
{
WARN("Cannot create placed resource on heap that denies resource category %#x.\n", deny_flag);
return E_INVALIDARG;
}
if ((heap->desc.Flags & D3D12_HEAP_FLAG_SHARED_CROSS_ADAPTER) &&
!(resource_desc->Flags & D3D12_RESOURCE_FLAG_ALLOW_CROSS_ADAPTER))
{
ERR("Must declare ALLOW_CROSS_ADAPTER resource flag when heap is cross adapter.\n");
return E_INVALIDARG;
}
return S_OK;
}
HRESULT d3d12_resource_create_placed_2(struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc,
struct d3d12_heap_2 *heap, uint64_t heap_offset, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
{
struct d3d12_resource *object;
HRESULT hr;
if (FAILED(hr = d3d12_resource_validate_heap(desc, heap)))
return hr;
if (FAILED(hr = d3d12_resource_create_2(device, VKD3D_RESOURCE_PLACED,
desc, &heap->desc.Properties, initial_state, optimized_clear_value, &object)))
return hr;
object->heap_2 = heap;
/* The exact allocation size is not important here since the
* resource does not own the allocation, so just set it to 0. */
vkd3d_memory_allocation_slice(&object->mem, &heap->allocation, heap_offset, 0);
object->heap_offset = object->mem.offset;
if (d3d12_resource_is_texture(object))
{
if (FAILED(hr = d3d12_resource_create_vk_resource(object, device)))
goto fail;
if (FAILED(hr = d3d12_resource_bind_image_memory_2(object, device)))
goto fail;
}
else
{
object->vk_buffer = object->mem.resource.vk_buffer;
object->gpu_address = object->mem.resource.va;
}
*resource = object;
return S_OK;
fail:
d3d12_resource_destroy_2(object, device);
return hr;
}
HRESULT d3d12_resource_create_reserved_2(struct d3d12_device *device,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource)
{
struct d3d12_resource *object;
HRESULT hr;
if (FAILED(hr = d3d12_resource_create_2(device, VKD3D_RESOURCE_SPARSE,
desc, NULL, initial_state, optimized_clear_value, &object)))
return hr;
if (FAILED(hr = d3d12_resource_create_vk_resource(object, device)))
goto fail;
if (FAILED(hr = d3d12_resource_init_sparse_info(object, device, &object->sparse)))
goto fail;
if (d3d12_resource_is_buffer(object))
{
object->res.vk_buffer = object->vk_buffer;
object->res.cookie = object->cookie;
object->res.size = object->desc.Width;
if (device->device_info.buffer_device_address_features.bufferDeviceAddress)
object->res.va = vkd3d_get_buffer_device_address(device, object->vk_buffer);
else
object->res.va = vkd3d_va_map_alloc_fake_va(&device->memory_allocator.va_map, object->res.size);
if (!object->res.va)
{
ERR("Failed to get VA for sparse resource.\n");
return E_FAIL;
}
object->gpu_address = object->res.va;
vkd3d_va_map_insert(&device->memory_allocator.va_map, &object->res);
}
*resource = object;
return S_OK;
fail:
d3d12_resource_destroy_2(object, device);
return hr;
}
static HRESULT d3d12_resource_create(struct d3d12_device *device,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,

View File

@ -632,11 +632,17 @@ HRESULT d3d12_heap_create_2(struct d3d12_device *device, const D3D12_HEAP_DESC *
void *host_address, struct d3d12_heap_2 **heap);
struct d3d12_heap_2 *unsafe_impl_from_ID3D12Heap_2(ID3D12Heap *iface);
#define VKD3D_RESOURCE_EXTERNAL 0x00000004
#define VKD3D_RESOURCE_DEDICATED_HEAP 0x00000008
#define VKD3D_RESOURCE_LINEAR_TILING 0x00000010
#define VKD3D_RESOURCE_PLACED_BUFFER 0x00000020
#define VKD3D_RESOURCE_SPARSE 0x00000040
enum vkd3d_resource_flag
{
VKD3D_RESOURCE_COMMITTED = (1u << 0),
VKD3D_RESOURCE_PLACED = (1u << 1),
VKD3D_RESOURCE_SPARSE = (1u << 2),
VKD3D_RESOURCE_ALLOCATION = (1u << 3),
VKD3D_RESOURCE_LINEAR_TILING = (1u << 4),
VKD3D_RESOURCE_EXTERNAL = (1u << 5),
VKD3D_RESOURCE_DEDICATED_HEAP = (1u << 6),
VKD3D_RESOURCE_PLACED_BUFFER = (1u << 7),
};
struct d3d12_sparse_image_region
{
@ -697,8 +703,10 @@ struct d3d12_resource
uint64_t cookie;
D3D12_RESOURCE_DESC desc;
D3D12_HEAP_PROPERTIES heap_properties;
D3D12_GPU_VIRTUAL_ADDRESS gpu_address;
struct vkd3d_memory_allocation mem;
struct vkd3d_unique_resource res;
union
{
VkBuffer vk_buffer;
@ -706,6 +714,7 @@ struct d3d12_resource
};
struct d3d12_heap *heap;
struct d3d12_heap_2 *heap_2;
uint64_t heap_offset;
uint32_t flags;
@ -755,6 +764,15 @@ HRESULT d3d12_placed_resource_create(struct d3d12_device *device, struct d3d12_h
HRESULT d3d12_reserved_resource_create(struct d3d12_device *device,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource);
HRESULT d3d12_resource_create_committed_2(struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc,
const D3D12_HEAP_PROPERTIES *heap_properties, D3D12_HEAP_FLAGS heap_flags, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource);
HRESULT d3d12_resource_create_placed_2(struct d3d12_device *device, const D3D12_RESOURCE_DESC *desc,
struct d3d12_heap_2 *heap, uint64_t heap_offset, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource);
HRESULT d3d12_resource_create_reserved_2(struct d3d12_device *device,
const D3D12_RESOURCE_DESC *desc, D3D12_RESOURCE_STATES initial_state,
const D3D12_CLEAR_VALUE *optimized_clear_value, struct d3d12_resource **resource);
struct d3d12_resource *unsafe_impl_from_ID3D12Resource(ID3D12Resource *iface);
HRESULT vkd3d_allocate_buffer_memory(struct d3d12_device *device, VkBuffer vk_buffer, void *host_memory,