From: Conor McCarthy cmccarthy@codeweavers.com
--- libs/vkd3d/command.c | 131 ++++++++++++++++++++++++++++++++++++- libs/vkd3d/resource.c | 17 +++++ libs/vkd3d/vkd3d_private.h | 8 +++ tests/d3d12.c | 1 - 4 files changed, 155 insertions(+), 2 deletions(-)
diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 38934a5d6..ec306cd04 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -6501,6 +6501,27 @@ done: return max_tile_count - tile_count; }
+static void d3d12_resource_update_buffer_tile_mappings(struct d3d12_resource *resource, + const VkSparseMemoryBind *memory_bind) +{ + struct vkd3d_subresource_tile_mapping *mappings = resource->tiles.subresources[0].mappings; + VkDeviceSize offset = memory_bind->memoryOffset; + unsigned int i, end; + + vkd3d_mutex_lock(&resource->tiles.mutex); + + i = memory_bind->resourceOffset / D3D12_TILE_SIZE; + end = i + memory_bind->size / D3D12_TILE_SIZE; + for (; i < end; ++i) + { + mappings[i].vk_memory = memory_bind->memory; + mappings[i].byte_offset = offset; + offset += D3D12_TILE_SIZE; + } + + vkd3d_mutex_unlock(&resource->tiles.mutex); +} + static void deaggregate_sparse_memory_bind(VkSparseBufferMemoryBindInfo *buffer_bind_info, const VkSparseMemoryBind *src, unsigned int tile_count, struct d3d12_resource *resource) { @@ -6600,6 +6621,8 @@ static unsigned int d3d12_command_queue_bind_sparse_block(struct d3d12_command_q memory_bind.memoryOffset = memory_offset * D3D12_TILE_SIZE; memory_bind.flags = 0;
+ d3d12_resource_update_buffer_tile_mappings(resource, &memory_bind); + buffer_bind_info.buffer = resource->u.vk_buffer; /* A bug in NVIDIA drivers (older ones at least) requires one tile per struct to workaround. This * could be skipped on other hardware by checking physical_device_info->properties2.properties.vendorID. */ @@ -6779,6 +6802,109 @@ static void d3d12_command_queue_update_tile_mappings(struct d3d12_command_queue vkd3d_queue_release(command_queue->vkd3d_queue); }
+static void vkd3d_copy_vk_tile_mapping_region(const struct d3d12_command_queue *command_queue, + const struct vkd3d_resource_tile_coordinate *dst_base, D3D12_TILED_RESOURCE_COORDINATE *dst_loc, + const D3D12_TILE_REGION_SIZE *dst_extent, struct d3d12_resource *dst_resource, + const struct vkd3d_resource_tile_coordinate *src_base, D3D12_TILED_RESOURCE_COORDINATE *src_loc, + const D3D12_TILE_REGION_SIZE *src_extent, const struct d3d12_resource *src_resource) +{ + const struct vkd3d_subresource_tile_info *src_info = &src_resource->tiles.subresources[src_loc->Subresource]; + const struct vkd3d_vk_device_procs *vk_procs = &dst_resource->device->vk_procs; + struct vkd3d_queue *vkd3d_queue = command_queue->vkd3d_queue; + const struct vkd3d_subresource_tile_mapping *src_mapping; + VkSparseBufferMemoryBindInfo buffer_bind_info; + VkSparseMemoryBind *memory_bind; + VkBindSparseInfo sparse_info; + unsigned int i, src_idx; + VkResult vr; + + src_mapping = src_info->mappings; + + memset(&sparse_info, 0, sizeof(sparse_info)); + sparse_info.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; + + if (d3d12_resource_is_buffer(dst_resource)) + { + sparse_info.bufferBindCount = 1; + sparse_info.pBufferBinds = &buffer_bind_info; + memory_bind = dst_resource->tiles.bind_buffer; + buffer_bind_info.buffer = dst_resource->u.vk_buffer; + buffer_bind_info.bindCount = src_extent->NumTiles; + buffer_bind_info.pBinds = memory_bind; + + src_idx = src_loc->X; + for (i = 0; i < src_extent->NumTiles; ++i, ++src_idx) + { + memory_bind[i].resourceOffset = dst_loc->X * dst_resource->tiles.tile_extent.width; + memory_bind[i].size = dst_resource->tiles.tile_extent.width; + memory_bind[i].memory = src_mapping[src_idx].vk_memory; + memory_bind[i].memoryOffset = src_mapping[src_idx].byte_offset; + memory_bind[i].flags = 0; + ++dst_loc->X; + } + + for (i = 0; i < src_extent->NumTiles; ++i) + d3d12_resource_update_buffer_tile_mappings(dst_resource, &memory_bind[i]); + } + else + { + vkd3d_unreachable(); + } + + sparse_info.pSignalSemaphores = &vkd3d_queue->tiled_binding_semaphore; + sparse_info.signalSemaphoreCount = 1; + if ((vr = VK_CALL(vkQueueBindSparse(vkd3d_queue->vk_queue, 1, &sparse_info, VK_NULL_HANDLE))) < 0) + ERR("Failed to submit sparse image bind, vr %d.\n", vr); + if (vkd3d_queue_submit_wait_acquired(vkd3d_queue, vkd3d_queue->tiled_binding_semaphore, command_queue->device) < 0) + ERR("Failed to submit queue wait, vr %d.\n", vr); +} + +static void d3d12_command_queue_copy_tile_mappings(struct d3d12_command_queue *command_queue, + struct d3d12_resource *dst_resource, + const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate, + struct d3d12_resource *src_resource, + const D3D12_TILED_RESOURCE_COORDINATE *src_region_start_coordinate, + const D3D12_TILE_REGION_SIZE *region_size, + D3D12_TILE_MAPPING_FLAGS flags) +{ + struct vkd3d_resource_tile_coordinate dst_base, src_base; + D3D12_TILED_RESOURCE_COORDINATE dst_loc, src_loc; + D3D12_TILE_REGION_SIZE dst_extent, src_extent; + VkQueue vk_queue; + + if (d3d12_resource_is_texture(dst_resource) || d3d12_resource_is_texture(src_resource)) + { + FIXME("Not implemented for textures.\n"); + return; + } + + dst_loc = *dst_region_start_coordinate; + src_loc = *src_region_start_coordinate; + if (!vkd3d_initialise_tile_region(&dst_base, &dst_extent, &dst_loc, region_size, dst_resource) + || !vkd3d_initialise_tile_region(&src_base, &src_extent, &src_loc, region_size, src_resource)) + { + WARN("Invalid tile region.\n"); + return; + } + + if (!src_extent.NumTiles || (dst_resource == src_resource + && dst_loc.X == src_loc.X + && dst_loc.Y == src_loc.Y + && dst_loc.Z == src_loc.Z && dst_loc.Subresource == src_loc.Subresource)) + return; + + if (!(vk_queue = vkd3d_queue_acquire(command_queue->vkd3d_queue))) + { + ERR("Failed to acquire queue %p.\n", command_queue->vkd3d_queue); + return; + } + + vkd3d_copy_vk_tile_mapping_region(command_queue, &dst_base, &dst_loc, &dst_extent, dst_resource, + &src_base, &src_loc, &src_extent, src_resource); + + vkd3d_queue_release(command_queue->vkd3d_queue); +} + static void STDMETHODCALLTYPE d3d12_command_queue_CopyTileMappings(ID3D12CommandQueue *iface, ID3D12Resource *dst_resource, const D3D12_TILED_RESOURCE_COORDINATE *dst_region_start_coordinate, @@ -7577,7 +7703,10 @@ static HRESULT d3d12_command_queue_flush_ops_locked(struct d3d12_command_queue * break;
case VKD3D_CS_OP_COPY_MAPPINGS: - FIXME("Tiled resource mapping copying is not supported yet.\n"); + d3d12_command_queue_copy_tile_mappings(queue, op->u.copy_mappings.dst_resource, + &op->u.copy_mappings.dst_region_start_coordinate, op->u.copy_mappings.src_resource, + &op->u.copy_mappings.src_region_start_coordinate, &op->u.copy_mappings.region_size, + op->u.copy_mappings.flags); break;
default: diff --git a/libs/vkd3d/resource.c b/libs/vkd3d/resource.c index fc5c30242..8d3d3a7fb 100644 --- a/libs/vkd3d/resource.c +++ b/libs/vkd3d/resource.c @@ -979,14 +979,19 @@ 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; + unsigned int i;
if (!resource->tiles.subresources) return;
+ vkd3d_mutex_destroy(&resource->tiles.mutex); + VK_CALL(vkFreeMemory(resource->device->vk_device, resource->tiles.mip_tail_memory, NULL));
vkd3d_free(resource->tiles.bind_buffer);
+ for (i = 0; i < resource->tiles.subresource_count; ++i) + vkd3d_free(resource->tiles.subresources[i].mappings); vkd3d_free(resource->tiles.subresources); }
@@ -1234,6 +1239,8 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 return false; }
+ vkd3d_mutex_init(&resource->tiles.mutex); + if (d3d12_resource_is_buffer(resource)) { tile_info = &resource->tiles.subresources[0]; @@ -1256,6 +1263,11 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 ERR("Failed to allocate binding buffer.\n"); goto error; } + if (!(tile_info->mappings = vkd3d_calloc(resource->tiles.total_count, sizeof(*tile_info->mappings)))) + { + ERR("Failed to allocate mapping buffer.\n"); + goto error; + } } else { @@ -1298,6 +1310,11 @@ static bool d3d12_resource_init_tiles(struct d3d12_resource *resource, struct d3 { tile_count = tile_info->extent.width * tile_info->extent.height * tile_info->extent.depth; start_idx += tile_count; + if (!(tile_info->mappings = vkd3d_calloc(tile_count, sizeof(*tile_info->mappings)))) + { + ERR("Failed to allocate mapping buffer.\n"); + goto error; + } tile_info->count = tile_count; } else if (miplevel_idx == resource->tiles.standard_mip_count) diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index 53aa1d102..c999ef79e 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -680,11 +680,18 @@ struct vkd3d_tiled_region_extent unsigned int depth; };
+struct vkd3d_subresource_tile_mapping +{ + VkDeviceMemory vk_memory; + VkDeviceSize byte_offset; +}; + struct vkd3d_subresource_tile_info { unsigned int offset; unsigned int count; struct vkd3d_tiled_region_extent extent; + struct vkd3d_subresource_tile_mapping *mappings; };
struct d3d12_resource_tile_info @@ -695,6 +702,7 @@ struct d3d12_resource_tile_info unsigned int packed_mip_tile_count; unsigned int subresource_count; bool single_mip_tail; + struct vkd3d_mutex mutex; struct vkd3d_subresource_tile_info *subresources; VkDeviceMemory mip_tail_memory; void *bind_buffer; diff --git a/tests/d3d12.c b/tests/d3d12.c index 0b9cadf74..b1e68fa1f 100644 --- a/tests/d3d12.c +++ b/tests/d3d12.c @@ -37163,7 +37163,6 @@ static void test_update_tile_mappings(void) for (i = 0; i < ARRAY_SIZE(buffer_region_tiles); i++) { set_box(&box, i, 0, 0, i + 1, 1, 1); - todo_if(i >= region_offsets[0].X && i < region_offsets[0].X + region_sizes[0].NumTiles) check_readback_data_uint(&rb.rb, &box, buffer_region_tiles[i], 0); }