[PATCH v2] vkd3d: Add support for multiplanar depth/stencil state transitions.

Conor McCarthy cmccarthy at codeweavers.com
Thu Oct 24 07:20:49 CDT 2019


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 <cmccarthy at codeweavers.com>
---
v2: Fix unsafe sizeof().
---
 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 59ea482..4338cd4 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 = &current->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,
-- 
2.23.0




More information about the wine-devel mailing list