From 2155748c418e862a906c8c43ead382f30dd40de1 Mon Sep 17 00:00:00 2001 From: Conor McCarthy Date: Thu, 24 Oct 2019 22:20:49 +1000 Subject: [PATCH] vkd3d: Add support for multiplanar depth/stencil state transitions. If separate transitions of the depth and stencil plane occur in the same array of barriers, they will be consolidated into one Vulkan layout transition. This can only be supported for combinations of depth read and depth write states, or identical states. Signed-off-by: Conor McCarthy Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- libs/vkd3d/command.c | 118 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 12 deletions(-) diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c index 59ea4829..4338cd4e 100644 --- a/libs/vkd3d/command.c +++ b/libs/vkd3d/command.c @@ -1872,7 +1872,7 @@ static void d3d12_command_list_invalidate_bindings(struct d3d12_command_list *li } } -static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, +static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, unsigned int stencil_state, const struct d3d12_resource *resource, VkQueueFlags vk_queue_flags, const struct vkd3d_vulkan_info *vk_info, VkAccessFlags *access_mask, VkPipelineStageFlags *stage_flags, VkImageLayout *image_layout) { @@ -1911,7 +1911,7 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, } else if (resource->present_state != D3D12_RESOURCE_STATE_COMMON) { - vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, + vk_barrier_parameters_from_d3d12_resource_state(resource->present_state, 0, resource, vk_queue_flags, vk_info, access_mask, stage_flags, image_layout); return true; } @@ -1945,7 +1945,12 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, *stage_flags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; if (image_layout) - *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + { + if (!stencil_state || (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE)) + *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + else + *image_layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL; + } return true; case D3D12_RESOURCE_STATE_COPY_DEST: @@ -1975,7 +1980,17 @@ static bool vk_barrier_parameters_from_d3d12_resource_state(unsigned int state, *access_mask = 0; *stage_flags = 0; if (image_layout) - *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + { + if (stencil_state & D3D12_RESOURCE_STATE_DEPTH_WRITE) + { + *image_layout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + *access_mask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + } + else + { + *image_layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + } break; case D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE: @@ -2096,7 +2111,7 @@ static void d3d12_command_list_transition_resource_to_initial_state(struct d3d12 barrier.oldLayout = d3d12_resource_is_cpu_accessible(resource) ? VK_IMAGE_LAYOUT_PREINITIALIZED : VK_IMAGE_LAYOUT_UNDEFINED; - if (!vk_barrier_parameters_from_d3d12_resource_state(resource->initial_state, + if (!vk_barrier_parameters_from_d3d12_resource_state(resource->initial_state, 0, resource, list->vk_queue_flags, vk_info, &barrier.dstAccessMask, &dst_stage_mask, &barrier.newLayout)) { FIXME("Unhandled state %#x.\n", resource->initial_state); @@ -3710,6 +3725,44 @@ static void STDMETHODCALLTYPE d3d12_command_list_SetPipelineState(ID3D12Graphics list->state = state; } +static bool is_ds_multiplanar_resolvable(unsigned int first_state, unsigned int second_state) +{ + /* Only combinations of depth/stencil read/write are supported. */ + return first_state == second_state + || ((first_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE)) + && (second_state & (D3D12_RESOURCE_STATE_DEPTH_READ | D3D12_RESOURCE_STATE_DEPTH_WRITE))); +} + +static unsigned int d3d12_find_ds_multiplanar_transition(const D3D12_RESOURCE_BARRIER *barriers, + unsigned int i, unsigned int barrier_count, unsigned int sub_resource_count) +{ + unsigned int sub_resource_idx = barriers[i].u.Transition.Subresource; + unsigned int j; + + for (j = i + 1; j < barrier_count; ++j) + { + if (barriers[j].Type == D3D12_RESOURCE_BARRIER_TYPE_TRANSITION + && barriers[j].u.Transition.pResource == barriers[i].u.Transition.pResource + && sub_resource_idx % sub_resource_count == barriers[j].u.Transition.Subresource % sub_resource_count) + { + /* Second barrier must be for a different plane. */ + if (barriers[j].u.Transition.Subresource == sub_resource_idx) + return 0; + + /* Validate the second barrier and check if the combination of two states is supported. */ + if (!is_valid_resource_state(barriers[j].u.Transition.StateBefore) + || !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateBefore, barriers[j].u.Transition.StateBefore) + || !is_valid_resource_state(barriers[j].u.Transition.StateAfter) + || !is_ds_multiplanar_resolvable(barriers[i].u.Transition.StateAfter, barriers[j].u.Transition.StateAfter) + || barriers[j].u.Transition.Subresource >= sub_resource_count * 2u) + return 0; + + return j; + } + } + return 0; +} + static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsCommandList1 *iface, UINT barrier_count, const D3D12_RESOURCE_BARRIER *barriers) { @@ -3717,6 +3770,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC bool have_aliasing_barriers = false, have_split_barriers = false; const struct vkd3d_vk_device_procs *vk_procs; const struct vkd3d_vulkan_info *vk_info; + bool *multiplanar_handled = NULL; unsigned int i; TRACE("iface %p, barrier_count %u, barriers %p.\n", iface, barrier_count, barriers); @@ -3746,6 +3800,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC { case D3D12_RESOURCE_BARRIER_TYPE_TRANSITION: { + unsigned int state_before, state_after, stencil_state_before = 0, stencil_state_after = 0; const D3D12_RESOURCE_TRANSITION_BARRIER *transition = ¤t->u.Transition; if (!is_valid_resource_state(transition->StateBefore)) @@ -3767,18 +3822,55 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC continue; } + if (multiplanar_handled && multiplanar_handled[i]) + continue; + + state_before = transition->StateBefore; + state_after = transition->StateAfter; + sub_resource_idx = transition->Subresource; - if (!vk_barrier_parameters_from_d3d12_resource_state(transition->StateBefore, + if (sub_resource_idx != D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES + && (resource->desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) + { + unsigned int sub_resource_count = d3d12_resource_desc_get_sub_resource_count(&resource->desc); + unsigned int j = d3d12_find_ds_multiplanar_transition(barriers, i, barrier_count, sub_resource_count); + if (j && (multiplanar_handled || (multiplanar_handled = vkd3d_calloc(barrier_count, sizeof(*multiplanar_handled))))) + { + multiplanar_handled[j] = true; + if (sub_resource_idx >= sub_resource_count) + { + sub_resource_idx -= sub_resource_count; + /* The stencil barrier is at i, depth at j. */ + state_before = barriers[j].u.Transition.StateBefore; + state_after = barriers[j].u.Transition.StateAfter; + stencil_state_before = transition->StateBefore; + stencil_state_after = transition->StateAfter; + } + else + { + /* Depth at i, stencil at j. */ + stencil_state_before = barriers[j].u.Transition.StateBefore; + stencil_state_after = barriers[j].u.Transition.StateAfter; + } + } + else if (sub_resource_idx >= sub_resource_count) + { + FIXME_ONCE("Unhandled sub-resource idx %u.\n", sub_resource_idx); + continue; + } + } + + if (!vk_barrier_parameters_from_d3d12_resource_state(state_before, stencil_state_before, resource, list->vk_queue_flags, vk_info, &src_access_mask, &src_stage_mask, &layout_before)) { - FIXME("Unhandled state %#x.\n", transition->StateBefore); + FIXME("Unhandled state %#x.\n", state_before); continue; } - if (!vk_barrier_parameters_from_d3d12_resource_state(transition->StateAfter, + if (!vk_barrier_parameters_from_d3d12_resource_state(state_after, stencil_state_after, resource, list->vk_queue_flags, vk_info, &dst_access_mask, &dst_stage_mask, &layout_after)) { - FIXME("Unhandled state %#x.\n", transition->StateAfter); + FIXME("Unhandled state %#x.\n", state_after); continue; } @@ -3795,7 +3887,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC VkAccessFlags access_mask; resource = unsafe_impl_from_ID3D12Resource(uav->pResource); - vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0, resource, list->vk_queue_flags, vk_info, &access_mask, &stage_mask, &image_layout); src_access_mask = dst_access_mask = access_mask; src_stage_mask = dst_stage_mask = stage_mask; @@ -3894,6 +3986,8 @@ static void STDMETHODCALLTYPE d3d12_command_list_ResourceBarrier(ID3D12GraphicsC } } + vkd3d_free(multiplanar_handled); + if (have_aliasing_barriers) FIXME_ONCE("Aliasing barriers not implemented yet.\n"); @@ -4737,7 +4831,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID buffer_barrier.offset = cpu_descriptor->uav.buffer.offset; buffer_barrier.size = cpu_descriptor->uav.buffer.size; - vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0, resource_impl, list->vk_queue_flags, vk_info, &buffer_barrier.dstAccessMask, &stage_mask, NULL); VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer, @@ -4770,7 +4864,7 @@ static void STDMETHODCALLTYPE d3d12_command_list_ClearUnorderedAccessViewUint(ID image_barrier.image = resource_impl->u.vk_image; image_barrier.subresourceRange = range; - vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, + vk_barrier_parameters_from_d3d12_resource_state(D3D12_RESOURCE_STATE_UNORDERED_ACCESS, 0, resource_impl, list->vk_queue_flags, vk_info, &image_barrier.dstAccessMask, &stage_mask, NULL); VK_CALL(vkCmdPipelineBarrier(list->vk_command_buffer,