From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d/resource.c | 101 +++++++++++++++++++++++++++++++++++++ libs/vkd3d/vkd3d_private.h | 3 ++ tests/d3d12.c | 4 +- 3 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index a6e76f197..86b8cd268 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -974,6 +974,15 @@ HRESULT vkd3d_get_image_allocation_info(struct d3d12_device *device,
static void d3d12_resource_tile_info_cleanup(struct d3d12_resource *resource) { + const struct vkd3d_vk_device_procs *vk_procs = &resource->device->vk_procs; + + if (!resource->tiles.subresources) + return; + + VK_CALL(vkFreeMemory(resource->device->vk_device, resource->tiles.mip_tail_memory, NULL)); + + vkd3d_free(resource->tiles.bind_buffer); + vkd3d_free(resource->tiles.subresources); }
@@ -1138,6 +1147,65 @@ void d3d12_resource_get_tiling(struct d3d12_device *device, const struct d3d12_r *subresource_tiling_count = i; }
+static void d3d12_resource_bind_sparse_mip_tail(struct d3d12_resource *resource, + VkSparseImageMemoryRequirements *sparse_requirements) +{ + const struct vkd3d_vk_device_procs *vk_procs = &resource->device->vk_procs; + VkSparseMemoryBind *memory_bind = resource->tiles.bind_buffer; + VkSparseImageOpaqueMemoryBindInfo opaque_bind_info; + struct d3d12_device *device = resource->device; + struct vkd3d_queue *vkd3d_queue; + VkBindSparseInfo sparse_info; + unsigned int i, layer_count; + VkDeviceSize memory_offset; + VkQueue vk_queue; + VkResult vr; + + if (!resource->tiles.packed_mip_tile_count) + return; + + vkd3d_queue = device->direct_queue; + if (!(vkd3d_queue->vk_queue_flags & VK_QUEUE_SPARSE_BINDING_BIT)) + { + FIXME("Direct queue does not support sparse binding.\n"); + return; + } + + opaque_bind_info.image = resource->u.vk_image; + opaque_bind_info.bindCount = 1; + opaque_bind_info.pBinds = memory_bind; + + layer_count = resource->tiles.single_mip_tail ? 1 : d3d12_resource_desc_get_layer_count(&resource->desc); + + for (i = 0, memory_offset = 0; i < layer_count; ++i) + { + memory_bind->resourceOffset = sparse_requirements->imageMipTailOffset + + i * sparse_requirements->imageMipTailStride; + memory_bind->size = sparse_requirements->imageMipTailSize; + memory_bind->memory = resource->tiles.mip_tail_memory; + memory_bind->memoryOffset = memory_offset; + memory_bind->flags = VK_SPARSE_MEMORY_BIND_METADATA_BIT; + memory_offset += memory_bind->size; + } + + memset(&sparse_info, 0, sizeof(sparse_info)); + sparse_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; + sparse_info.imageOpaqueBindCount = 1; + sparse_info.pImageOpaqueBinds = &opaque_bind_info; + + if (!(vk_queue = vkd3d_queue_acquire(vkd3d_queue))) + { + ERR("Failed to acquire queue %p.\n", vkd3d_queue); + return; + } + + if ((vr = VK_CALL(vkQueueBindSparse(vk_queue, 1, &sparse_info, VK_NULL_HANDLE))) < 0) + ERR("Failed to submit sparse image bind, vr %d.\n", vr); + /* TODO: wait on a semaphore when binding commands are implemented. */ + + vkd3d_queue_release(vkd3d_queue); +} + static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3d12_device *device) { unsigned int i, start_idx, subresource_count, tile_count, miplevel_idx; @@ -1145,9 +1213,11 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 VkSparseImageMemoryRequirements sparse_requirements_buf[3]; VkSparseImageMemoryRequirements sparse_requirements; struct vkd3d_subresource_tile_info *tile_info; + D3D12_HEAP_PROPERTIES heap_properties; VkMemoryRequirements requirements; const VkExtent3D *tile_extent; uint32_t requirement_count; + HRESULT hr;
subresource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc);
@@ -1193,6 +1263,8 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 }
resource->tiles.tile_extent = sparse_requirements.formatProperties.imageGranularity; + resource->tiles.single_mip_tail = !!(sparse_requirements.formatProperties.flags + & VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT); resource->tiles.subresource_count = subresource_count; resource->tiles.standard_mip_count = sparse_requirements.imageMipTailSize ? sparse_requirements.imageMipTailFirstLod : resource->desc.MipLevels; @@ -1222,9 +1294,38 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 } } resource->tiles.total_count = start_idx; + + if (resource->tiles.packed_mip_tile_count) + { + memset(&heap_properties, 0, sizeof(heap_properties)); + heap_properties.Type = D3D12_HEAP_TYPE_DEFAULT; + requirements.size = sparse_requirements.imageMipTailSize; + if (!resource->tiles.single_mip_tail) + requirements.size *= d3d12_resource_desc_get_layer_count(&resource->desc); + if (FAILED(hr = vkd3d_allocate_device_memory(device, &heap_properties, 0, &requirements, NULL, + &resource->tiles.mip_tail_memory, NULL))) + { + ERR("Failed to allocate device memory for mip tail, hr %#x.\n", hr); + goto error; + } + } + + if (!(resource->tiles.bind_buffer = vkd3d_malloc(start_idx * max(sizeof(VkSparseImageMemoryBind), + sizeof(VkBufferImageCopy))))) + { + ERR("Failed to allocate binding buffer.\n"); + goto error; + } + + /* Vulkan requires mip tails to be always bound, while D3D12 does not, so bind them now. */ + d3d12_resource_bind_sparse_mip_tail(resource, &sparse_requirements); }
return true; + +error: + d3d12_resource_tile_info_cleanup(resource); + return false; }
/* ID3D12Resource */ diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 859844684..563cb4bb9 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -693,7 +693,10 @@ struct d3d12_resource_tile_info unsigned int standard_mip_count; unsigned int packed_mip_tile_count; unsigned int subresource_count; + bool single_mip_tail; struct vkd3d_subresource_tile_info *subresources; + VkDeviceMemory mip_tail_memory; + void *bind_buffer; };
#define D3D12_TILE_SIZE 0x10000u diff --git a/tests/d3d12.c b/tests/d3d12.c index b51bd34e4..65b6c0123 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -37270,7 +37270,7 @@ static void test_update_tile_mappings(void) for (i = 0; i < j; i++) { set_box(&box, i, 0, 0, i + 1, 1, 1); - todo check_readback_data_uint(&rb.rb, &box, i + 1, 0); + todo_if(i < packed_mip_info.StartTileIndexInOverallResource) check_readback_data_uint(&rb.rb, &box, i + 1, 0); }
release_resource_readback(&rb); @@ -37367,7 +37367,7 @@ static void test_update_tile_mappings(void) for (i = 0; i < j; i++) { set_box(&box, i, 0, 0, i + 1, 1, 1); - todo_if(texture_region_tiles[i]) + todo_if(i < packed_mip_info.StartTileIndexInOverallResource && texture_region_tiles[i]) check_readback_data_uint(&rb.rb, &box, texture_region_tiles[i], 0); }