From 3577ca3144ef8e44a909a14dffad802a4a9eeca3 Mon Sep 17 00:00:00 2001 From: Tatsuyuki Ishi Date: Tue, 17 May 2022 20:58:51 +0900 Subject: [PATCH] vkd3d: Introduce transfer batches. Transfer batches buffers CopyTextureRegion calls for batching. The flushes needs to happen in a few places: 1. ResourceBarrier: This is where the transition from COPY_DEST to other might happen, at which point the writes must be visible. This might also transition away from COPY_SRC which invalidates the precondition. 2. Copy operations. Copies to the same resource are implicitly ordered. 3. Draws and dispatches. These are not strictly necessary, but we don't want too much command reordering so flushing here seems good. 4. Close. So that we don't throw commands into the void. Signed-off-by: Tatsuyuki Ishi --- libs/vkd3d/command.c | 69 ++++++++++++++++++++++++++++++++------ libs/vkd3d/vkd3d_private.h | 20 +++++++++++ 2 files changed, 79 insertions(+), 10 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 60058fef..05cd2f8b 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -65,6 +65,8 @@ static VkImageLayout d3d12_command_list_get_depth_stencil_resource_layout(const static void d3d12_command_list_decay_optimal_dsv_resource(struct d3d12_command_list *list, const struct d3d12_resource *resource, uint32_t plane_optimal_mask, struct d3d12_command_list_barrier_batch *batch); +static void d3d12_command_list_end_transfer_batch(struct d3d12_command_list *list); +static inline void d3d12_command_list_ensure_transfer_batch(struct d3d12_command_list *list, enum vkd3d_batch_type type); static HRESULT vkd3d_create_binary_semaphore(struct d3d12_device *device, VkSemaphore *vk_semaphore) { @@ -4091,6 +4093,7 @@ static HRESULT STDMETHODCALLTYPE d3d12_command_list_Close(d3d12_command_list_ifa } d3d12_command_list_end_current_render_pass(list, false); + d3d12_command_list_end_transfer_batch(list); if (list->predicate_enabled) VK_CALL(vkCmdEndConditionalRenderingEXT(list->vk_command_buffer)); @@ -5326,6 +5329,8 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list return true; } + d3d12_command_list_end_transfer_batch(list); + if (!(list->rendering_info.state_flags & VKD3D_RENDERING_SUSPENDED)) d3d12_command_list_emit_render_pass_transition(list, VKD3D_RENDER_PASS_TRANSITION_MODE_BEGIN); @@ -5546,6 +5551,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_Dispatch(d3d12_command_list_ifa return; } + d3d12_command_list_end_transfer_batch(list); + if (!d3d12_command_list_update_compute_state(list)) { WARN("Failed to update compute state, ignoring dispatch.\n"); @@ -5587,6 +5594,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyBufferRegion(d3d12_command_ d3d12_command_list_track_resource_usage(list, src_resource, true); d3d12_command_list_end_current_render_pass(list, true); + d3d12_command_list_end_transfer_batch(list); buffer_copy.sType = VK_STRUCTURE_TYPE_BUFFER_COPY_2_KHR; buffer_copy.pNext = NULL; @@ -6134,6 +6142,7 @@ static bool d3d12_command_list_init_copy_texture_region(struct d3d12_command_lis out->copy.buffer_image.bufferOffset += dst_resource->mem.offset; out->src_layout = d3d12_resource_pick_layout(src_resource, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + out->batch_type = VKD3D_BATCH_TYPE_COPY_IMAGE_TO_BUFFER; } else if (src->Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT && dst->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) { @@ -6160,6 +6169,7 @@ static bool d3d12_command_list_init_copy_texture_region(struct d3d12_command_lis out->dst_layout = d3d12_resource_pick_layout(dst_resource, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); out->writes_full_subresource = d3d12_image_copy_writes_full_subresource(dst_resource, &out->copy.buffer_image.imageExtent, &out->copy.buffer_image.imageSubresource); + out->batch_type = VKD3D_BATCH_TYPE_COPY_BUFFER_TO_IMAGE; } else if (src->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX && dst->Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) { @@ -6189,6 +6199,7 @@ static bool d3d12_command_list_init_copy_texture_region(struct d3d12_command_lis out->writes_full_subresource = d3d12_image_copy_writes_full_subresource(dst_resource, &out->copy.image.extent, &out->copy.image.dstSubresource); + out->batch_type = VKD3D_BATCH_TYPE_COPY_IMAGE; } else { @@ -6209,7 +6220,7 @@ static void d3d12_command_list_before_copy_texture_region(struct d3d12_command_l d3d12_command_list_track_resource_usage(list, src_resource, true); - if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT) + if (info->batch_type == VKD3D_BATCH_TYPE_COPY_IMAGE_TO_BUFFER) { d3d12_command_list_track_resource_usage(list, dst_resource, true); @@ -6224,7 +6235,7 @@ static void d3d12_command_list_before_copy_texture_region(struct d3d12_command_l src_resource->common_layout, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_READ_BIT, info->src_layout, global_transfer_access, global_transfer_access); } - else if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) + else if (info->batch_type == VKD3D_BATCH_TYPE_COPY_BUFFER_TO_IMAGE) { d3d12_command_list_track_resource_usage(list, dst_resource, !info->writes_full_subresource); @@ -6233,7 +6244,7 @@ static void d3d12_command_list_before_copy_texture_region(struct d3d12_command_l info->writes_full_subresource ? VK_IMAGE_LAYOUT_UNDEFINED : dst_resource->common_layout, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, info->dst_layout); } - else if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) + else if (info->batch_type == VKD3D_BATCH_TYPE_COPY_IMAGE) { d3d12_command_list_track_resource_usage(list, dst_resource, !info->writes_full_subresource); } @@ -6251,7 +6262,7 @@ static void d3d12_command_list_copy_texture_region(struct d3d12_command_list *li dst_resource = impl_from_ID3D12Resource(info->dst.pResource); src_resource = impl_from_ID3D12Resource(info->src.pResource); - if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT) + if (info->batch_type == VKD3D_BATCH_TYPE_COPY_IMAGE_TO_BUFFER) { VkCopyImageToBufferInfo2KHR copy_info; @@ -6272,7 +6283,7 @@ static void d3d12_command_list_copy_texture_region(struct d3d12_command_list *li info->src_layout, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, src_resource->common_layout, global_transfer_access, global_transfer_access); } - else if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) + else if (info->batch_type == VKD3D_BATCH_TYPE_COPY_BUFFER_TO_IMAGE) { VkCopyBufferToImageInfo2KHR copy_info; @@ -6291,7 +6302,7 @@ static void d3d12_command_list_copy_texture_region(struct d3d12_command_list *li VK_ACCESS_TRANSFER_WRITE_BIT, info->dst_layout, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, dst_resource->common_layout); } - else if (info->src.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX && info->dst.Type == D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX) + else if (info->batch_type == VKD3D_BATCH_TYPE_COPY_IMAGE) { d3d12_command_list_copy_image(list, dst_resource, info->dst_format, src_resource, info->src_format, &info->copy.image, info->writes_full_subresource, false); @@ -6314,12 +6325,11 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyTextureRegion(d3d12_command return; } - d3d12_command_list_end_current_render_pass(list, false); - if (!d3d12_command_list_init_copy_texture_region(list, dst, dst_x, dst_y, dst_z, src, src_box, ©_info)) return; - d3d12_command_list_before_copy_texture_region(list, ©_info); - d3d12_command_list_copy_texture_region(list, ©_info); + + d3d12_command_list_ensure_transfer_batch(list, copy_info.batch_type); + list->transfer_batch.batch[list->transfer_batch.batch_len++] = copy_info; VKD3D_BREADCRUMB_COMMAND(COPY); } @@ -6347,6 +6357,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(d3d12_command_list d3d12_command_list_track_resource_usage(list, src_resource, true); d3d12_command_list_end_current_render_pass(list, false); + d3d12_command_list_end_transfer_batch(list); if (d3d12_resource_is_buffer(dst_resource)) { @@ -6397,6 +6408,40 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyResource(d3d12_command_list VKD3D_BREADCRUMB_COMMAND(COPY); } +static void d3d12_command_list_end_transfer_batch(struct d3d12_command_list *list) +{ + size_t i; + switch (list->transfer_batch.batch_type) + { + case VKD3D_BATCH_TYPE_NONE: + return; + case VKD3D_BATCH_TYPE_COPY_BUFFER_TO_IMAGE: + case VKD3D_BATCH_TYPE_COPY_IMAGE_TO_BUFFER: + case VKD3D_BATCH_TYPE_COPY_IMAGE: + d3d12_command_list_end_current_render_pass(list, false); + /* TODO: once we check for aliasing and it's safe to batch things, transpose the loop. */ + for (i = 0; i < list->transfer_batch.batch_len; i++) + { + d3d12_command_list_before_copy_texture_region(list, &list->transfer_batch.batch[i]); + d3d12_command_list_copy_texture_region(list, &list->transfer_batch.batch[i]); + } + list->transfer_batch.batch_len = 0; + break; + default: + break; + } + list->transfer_batch.batch_type = VKD3D_BATCH_TYPE_NONE; +} + +static void d3d12_command_list_ensure_transfer_batch(struct d3d12_command_list *list, enum vkd3d_batch_type type) +{ + if (list->transfer_batch.batch_type != type || list->transfer_batch.batch_len == ARRAY_SIZE(list->transfer_batch.batch)) + { + d3d12_command_list_end_transfer_batch(list); + list->transfer_batch.batch_type = type; + } +} + static unsigned int vkd3d_get_tile_index_from_region(const struct d3d12_sparse_info *sparse, const D3D12_TILED_RESOURCE_COORDINATE *coord, const D3D12_TILE_REGION_SIZE *size, unsigned int tile_index_in_region); @@ -6424,6 +6469,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_CopyTiles(d3d12_command_list_if buffer, buffer_offset, flags); d3d12_command_list_end_current_render_pass(list, true); + d3d12_command_list_end_transfer_batch(list); tiled_res = impl_from_ID3D12Resource(tiled_resource); linear_res = impl_from_ID3D12Resource(buffer); @@ -6603,6 +6649,7 @@ static void d3d12_command_list_resolve_subresource(struct d3d12_command_list *li device = list->device; vk_procs = &device->vk_procs; d3d12_command_list_end_current_render_pass(list, false); + d3d12_command_list_end_transfer_batch(list); if (dst_resource->format->type == VKD3D_FORMAT_TYPE_TYPELESS || src_resource->format->type == VKD3D_FORMAT_TYPE_TYPELESS) { @@ -7138,6 +7185,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(d3d12_command_l TRACE("iface %p, barrier_count %u, barriers %p.\n", iface, barrier_count, barriers); d3d12_command_list_end_current_render_pass(list, false); + d3d12_command_list_end_transfer_batch(list); d3d12_command_list_barrier_batch_init(&batch); for (i = 0; i < barrier_count; ++i) @@ -9503,6 +9551,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ExecuteIndirect(d3d12_command_l scratch.va = d3d12_resource_get_va(arg_impl, arg_buffer_offset); } + d3d12_command_list_end_transfer_batch(list); switch (arg_desc->Type) { case D3D12_INDIRECT_ARGUMENT_TYPE_DRAW: diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h index ca1e65a4..1ce187a5 100644 --- a/libs/vkd3d/vkd3d_private.h +++ b/libs/vkd3d/vkd3d_private.h @@ -2052,10 +2052,19 @@ struct d3d12_buffer_copy_tracked_buffer VkDeviceSize hazard_end; }; +enum vkd3d_batch_type +{ + VKD3D_BATCH_TYPE_NONE, + VKD3D_BATCH_TYPE_COPY_BUFFER_TO_IMAGE, + VKD3D_BATCH_TYPE_COPY_IMAGE_TO_BUFFER, + VKD3D_BATCH_TYPE_COPY_IMAGE, +}; + struct vkd3d_image_copy_info { D3D12_TEXTURE_COPY_LOCATION src, dst; const struct vkd3d_format *src_format, *dst_format; + enum vkd3d_batch_type batch_type; union { VkBufferImageCopy2KHR buffer_image; @@ -2067,6 +2076,15 @@ struct vkd3d_image_copy_info VkImageLayout dst_layout; }; +#define VKD3D_COPY_TEXTURE_REGION_MAX_BATCH_SIZE 16 + +struct d3d12_transfer_batch_state +{ + enum vkd3d_batch_type batch_type; + struct vkd3d_image_copy_info batch[VKD3D_COPY_TEXTURE_REGION_MAX_BATCH_SIZE]; + size_t batch_len; +}; + struct d3d12_command_list { d3d12_command_list_iface ID3D12GraphicsCommandList_iface; @@ -2153,6 +2171,8 @@ struct d3d12_command_list struct d3d12_buffer_copy_tracked_buffer tracked_copy_buffers[VKD3D_BUFFER_COPY_TRACKING_BUFFER_COUNT]; unsigned int tracked_copy_buffer_count; + struct d3d12_transfer_batch_state transfer_batch; + struct vkd3d_private_store private_store; #ifdef VKD3D_ENABLE_BREADCRUMBS