[PATCH vkd3d 3/8] vkd3d: Do not disable depth-stencil tests for PSOs with invalid DSV format.

Józef Kucia joseph.kucia at gmail.com
Wed May 15 06:17:56 CDT 2019


From: Józef Kucia <jkucia at codeweavers.com>

This is invalid usage according to the D3D12 validation layer. However,
Shadow of the Tomb Raider uses PSOs with DSVFormat equal to
DXGI_FORMAT_UNKNOWN and enabled depth-stencil tests. Moreover, the test
in the next commit passes on Windows with AMD, Intel and Nvidia GPUs.

Signed-off-by: Józef Kucia <jkucia at codeweavers.com>
---
 libs/vkd3d/command.c       | 14 +++++--
 libs/vkd3d/state.c         | 78 ++++++++++++++++++++++++++++----------
 libs/vkd3d/vkd3d_private.h |  5 ++-
 3 files changed, 72 insertions(+), 25 deletions(-)

diff --git a/libs/vkd3d/command.c b/libs/vkd3d/command.c
index 8c7057b36340..861c8405c3e6 100644
--- a/libs/vkd3d/command.c
+++ b/libs/vkd3d/command.c
@@ -2251,11 +2251,13 @@ static void d3d12_command_list_reset_state(struct d3d12_command_list *list,
     list->fb_width = 0;
     list->fb_height = 0;
     list->fb_layer_count = 0;
+    list->dsv_format = VK_FORMAT_UNDEFINED;
 
     list->xfb_enabled = false;
 
     list->current_framebuffer = VK_NULL_HANDLE;
     list->current_pipeline = VK_NULL_HANDLE;
+    list->pso_render_pass = VK_NULL_HANDLE;
     list->current_render_pass = VK_NULL_HANDLE;
 
     memset(list->pipeline_bindings, 0, sizeof(list->pipeline_bindings));
@@ -2370,7 +2372,7 @@ static bool d3d12_command_list_update_current_framebuffer(struct d3d12_command_l
     fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
     fb_desc.pNext = NULL;
     fb_desc.flags = 0;
-    fb_desc.renderPass = graphics->render_pass;
+    fb_desc.renderPass = list->pso_render_pass;
     fb_desc.attachmentCount = view_count;
     fb_desc.pAttachments = views;
     d3d12_command_list_get_fb_extent(list, &fb_desc.width, &fb_desc.height, &fb_desc.layers);
@@ -2407,9 +2409,12 @@ static bool d3d12_command_list_update_current_pipeline(struct d3d12_command_list
     }
 
     if (!(vk_pipeline = d3d12_pipeline_state_get_or_create_pipeline(list->state,
-            list->primitive_topology, list->strides)))
+            list->primitive_topology, list->strides, list->dsv_format, &list->pso_render_pass)))
         return false;
 
+    if (!list->pso_render_pass)
+        list->pso_render_pass = list->state->u.graphics.render_pass;
+
     VK_CALL(vkCmdBindPipeline(list->vk_command_buffer, list->state->vk_bind_point, vk_pipeline));
     list->current_pipeline = vk_pipeline;
 
@@ -2797,7 +2802,8 @@ static bool d3d12_command_list_begin_render_pass(struct d3d12_command_list *list
     if (list->current_render_pass != VK_NULL_HANDLE)
         return true;
 
-    vk_render_pass = list->state->u.graphics.render_pass;
+    vk_render_pass = list->pso_render_pass;
+    assert(vk_render_pass);
 
     begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
     begin_desc.pNext = NULL;
@@ -4373,11 +4379,13 @@ static void STDMETHODCALLTYPE d3d12_command_list_OMSetRenderTargets(ID3D12Graphi
             list->fb_width = max(list->fb_width, dsv_desc->width);
             list->fb_height = max(list->fb_height, dsv_desc->height);
             list->fb_layer_count = max(list->fb_layer_count, dsv_desc->layer_count);
+            list->dsv_format = dsv_desc->format;
         }
         else
         {
             WARN("DSV descriptor is not initialized.\n");
             list->views[0] = VK_NULL_HANDLE;
+            list->dsv_format = VK_FORMAT_UNDEFINED;
         }
     }
 
diff --git a/libs/vkd3d/state.c b/libs/vkd3d/state.c
index b1f4ef9acac1..457f3d9bc84b 100644
--- a/libs/vkd3d/state.c
+++ b/libs/vkd3d/state.c
@@ -1236,6 +1236,7 @@ struct vkd3d_pipeline_key
 {
     D3D12_PRIMITIVE_TOPOLOGY topology;
     uint32_t strides[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
+    VkFormat dsv_format;
 };
 
 struct vkd3d_compiled_pipeline
@@ -1243,6 +1244,7 @@ struct vkd3d_compiled_pipeline
     struct list entry;
     struct vkd3d_pipeline_key key;
     VkPipeline vk_pipeline;
+    VkRenderPass vk_render_pass;
 };
 
 /* ID3D12PipelineState */
@@ -2052,7 +2054,8 @@ bool d3d12_pipeline_state_is_render_pass_compatible(const struct d3d12_pipeline_
 STATIC_ASSERT(sizeof(struct vkd3d_shader_transform_feedback_element) == sizeof(D3D12_SO_DECLARATION_ENTRY));
 
 static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
-        struct d3d12_graphics_pipeline_state *graphics, struct d3d12_device *device)
+        struct d3d12_graphics_pipeline_state *graphics, struct d3d12_device *device,
+        VkFormat dynamic_dsv_format, VkRenderPass *vk_render_pass)
 {
     struct vkd3d_render_pass_key key;
     unsigned int i;
@@ -2064,7 +2067,12 @@ static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
         key.stencil_enable = graphics->ds_desc.stencilTestEnable;
         key.depth_stencil_write = graphics->ds_desc.depthWriteEnable
                 || graphics->ds_desc.front.writeMask;
-        key.vk_formats[0] = graphics->dsv_format;
+
+        if (!(key.vk_formats[0] = graphics->dsv_format))
+            key.vk_formats[0] = dynamic_dsv_format;
+
+        if (!key.vk_formats[0])
+            FIXME("Compiling with DXGI_FORMAT_UNKNOWN.\n");
     }
     else
     {
@@ -2082,7 +2090,7 @@ static HRESULT d3d12_graphics_pipeline_state_create_render_pass(
     key.padding = 0;
     key.sample_count = graphics->ms_desc.rasterizationSamples;
 
-    return vkd3d_render_pass_cache_find(&device->render_pass_cache, device, &key, &graphics->render_pass);
+    return vkd3d_render_pass_cache_find(&device->render_pass_cache, device, &key, vk_render_pass);
 }
 
 static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *state,
@@ -2177,26 +2185,29 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
         rt_count = ARRAY_SIZE(graphics->blend_attachments);
     }
 
-    if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN
-            && (desc->DepthStencilState.DepthEnable || desc->DepthStencilState.StencilEnable))
-        FIXME("DSV format is DXGI_FORMAT_UNKNOWN, disabling depth/stencil tests.\n");
-
     graphics->rt_idx = 0;
     graphics->null_attachment_mask = 0;
-    if (desc->DSVFormat != DXGI_FORMAT_UNKNOWN
-            && (desc->DepthStencilState.DepthEnable || desc->DepthStencilState.StencilEnable))
+    if (desc->DepthStencilState.DepthEnable || desc->DepthStencilState.StencilEnable)
     {
-        if (!(format = vkd3d_get_format(device, desc->DSVFormat, true)))
+        if (desc->DSVFormat == DXGI_FORMAT_UNKNOWN)
+        {
+            WARN("DSV format is DXGI_FORMAT_UNKNOWN.\n");
+            graphics->dsv_format = VK_FORMAT_UNDEFINED;
+        }
+        else if ((format = vkd3d_get_format(device, desc->DSVFormat, true)))
+        {
+            if (!(format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))
+                FIXME("Format %#x is not depth/stencil format.\n", format->dxgi_format);
+
+            graphics->dsv_format = format->vk_format;
+        }
+        else
         {
             WARN("Invalid DSV format %#x.\n", desc->DSVFormat);
             hr = E_INVALIDARG;
             goto fail;
         }
 
-        if (!(format->vk_aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)))
-            FIXME("Format %#x is not depth/stencil format.\n", format->dxgi_format);
-
-        graphics->dsv_format = format->vk_format;
         ++graphics->rt_idx;
 
         if (!desc->PS.pShaderBytecode)
@@ -2538,7 +2549,10 @@ static HRESULT d3d12_pipeline_state_init_graphics(struct d3d12_pipeline_state *s
 
     ds_desc_from_d3d12(&graphics->ds_desc, &desc->DepthStencilState);
 
-    if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics, device)))
+    if (graphics->dsv_format == VK_FORMAT_UNDEFINED)
+        graphics->render_pass = VK_NULL_HANDLE;
+    else if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics,
+            device, 0, &graphics->render_pass)))
         goto fail;
 
     graphics->root_signature = root_signature;
@@ -2640,7 +2654,7 @@ static enum VkPrimitiveTopology vk_topology_from_d3d12_topology(D3D12_PRIMITIVE_
 }
 
 static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12_pipeline_state *state,
-        const struct vkd3d_pipeline_key *key)
+        const struct vkd3d_pipeline_key *key, VkRenderPass *vk_render_pass)
 {
     const struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
     struct d3d12_device *device = state->device;
@@ -2648,6 +2662,8 @@ static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12
     struct vkd3d_compiled_pipeline *current;
     int rc;
 
+    *vk_render_pass = VK_NULL_HANDLE;
+
     if (!(rc = pthread_mutex_lock(&device->mutex)))
     {
         LIST_FOR_EACH_ENTRY(current, &graphics->compiled_pipelines, struct vkd3d_compiled_pipeline, entry)
@@ -2655,6 +2671,7 @@ static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12
             if (!memcmp(&current->key, key, sizeof(*key)))
             {
                 vk_pipeline = current->vk_pipeline;
+                *vk_render_pass = current->vk_render_pass;
                 break;
             }
         }
@@ -2669,7 +2686,7 @@ static VkPipeline d3d12_pipeline_state_find_compiled_pipeline(const struct d3d12
 }
 
 static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_state *state,
-        const struct vkd3d_pipeline_key *key, VkPipeline vk_pipeline)
+        const struct vkd3d_pipeline_key *key, VkPipeline vk_pipeline, VkRenderPass vk_render_pass)
 {
     struct d3d12_graphics_pipeline_state *graphics = &state->u.graphics;
     struct vkd3d_compiled_pipeline *compiled_pipeline, *current;
@@ -2681,6 +2698,7 @@ static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_sta
 
     compiled_pipeline->key = *key;
     compiled_pipeline->vk_pipeline = vk_pipeline;
+    compiled_pipeline->vk_render_pass = vk_render_pass;
 
     if ((rc = pthread_mutex_lock(&device->mutex)))
     {
@@ -2707,7 +2725,8 @@ static bool d3d12_pipeline_state_put_pipeline_to_cache(struct d3d12_pipeline_sta
 }
 
 VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
-        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides)
+        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides, VkFormat dsv_format,
+        VkRenderPass *vk_render_pass)
 {
     VkVertexInputBindingDescription bindings[D3D12_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT];
     const struct vkd3d_vk_device_procs *vk_procs = &state->device->vk_procs;
@@ -2725,6 +2744,7 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
     unsigned int i;
     uint32_t mask;
     VkResult vr;
+    HRESULT hr;
 
     static const VkPipelineViewportStateCreateInfo vp_desc =
     {
@@ -2754,6 +2774,8 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
 
     assert(d3d12_pipeline_state_is_graphics(state));
 
+    *vk_render_pass = VK_NULL_HANDLE;
+
     memset(&pipeline_key, 0, sizeof(pipeline_key));
     pipeline_key.topology = topology;
 
@@ -2783,7 +2805,9 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
         ++binding_count;
     }
 
-    if ((vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key)))
+    pipeline_key.dsv_format = dsv_format;
+
+    if ((vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key, vk_render_pass)))
         return vk_pipeline;
 
     input_desc.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
@@ -2846,6 +2870,18 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
     pipeline_desc.subpass = 0;
     pipeline_desc.basePipelineHandle = VK_NULL_HANDLE;
     pipeline_desc.basePipelineIndex = -1;
+
+    /* Create a render pass for pipelines with DXGI_FORMAT_UNKNOWN. */
+    if (!pipeline_desc.renderPass)
+    {
+        TRACE("Compiling %p with DSV format %#x.\n", state, dsv_format);
+        if (FAILED(hr = d3d12_graphics_pipeline_state_create_render_pass(graphics, device, dsv_format,
+                &pipeline_desc.renderPass)))
+            return VK_NULL_HANDLE;
+
+        *vk_render_pass = pipeline_desc.renderPass;
+    }
+
     if ((vr = VK_CALL(vkCreateGraphicsPipelines(device->vk_device, device->vk_pipeline_cache,
             1, &pipeline_desc, NULL, &vk_pipeline))) < 0)
     {
@@ -2853,12 +2889,12 @@ VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_sta
         return VK_NULL_HANDLE;
     }
 
-    if (d3d12_pipeline_state_put_pipeline_to_cache(state, &pipeline_key, vk_pipeline))
+    if (d3d12_pipeline_state_put_pipeline_to_cache(state, &pipeline_key, vk_pipeline, pipeline_desc.renderPass))
         return vk_pipeline;
 
     /* Other thread compiled the pipeline before us. */
     VK_CALL(vkDestroyPipeline(device->vk_device, vk_pipeline, NULL));
-    vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key);
+    vk_pipeline = d3d12_pipeline_state_find_compiled_pipeline(state, &pipeline_key, vk_render_pass);
     if (!vk_pipeline)
         ERR("Could not get the pipeline compiled by other thread from the cache.\n");
     return vk_pipeline;
diff --git a/libs/vkd3d/vkd3d_private.h b/libs/vkd3d/vkd3d_private.h
index 4ae6afe128db..3fd1eacbfc77 100644
--- a/libs/vkd3d/vkd3d_private.h
+++ b/libs/vkd3d/vkd3d_private.h
@@ -741,7 +741,8 @@ HRESULT d3d12_pipeline_state_create_compute(struct d3d12_device *device,
 HRESULT d3d12_pipeline_state_create_graphics(struct d3d12_device *device,
         const D3D12_GRAPHICS_PIPELINE_STATE_DESC *desc, struct d3d12_pipeline_state **state) DECLSPEC_HIDDEN;
 VkPipeline d3d12_pipeline_state_get_or_create_pipeline(struct d3d12_pipeline_state *state,
-        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides) DECLSPEC_HIDDEN;
+        D3D12_PRIMITIVE_TOPOLOGY topology, const uint32_t *strides, VkFormat dsv_format,
+        VkRenderPass *vk_render_pass) DECLSPEC_HIDDEN;
 bool d3d12_pipeline_state_is_render_pass_compatible(const struct d3d12_pipeline_state *state_a,
         const struct d3d12_pipeline_state *state_b) DECLSPEC_HIDDEN;
 struct d3d12_pipeline_state *unsafe_impl_from_ID3D12PipelineState(ID3D12PipelineState *iface) DECLSPEC_HIDDEN;
@@ -861,11 +862,13 @@ struct d3d12_command_list
     unsigned int fb_width;
     unsigned int fb_height;
     unsigned int fb_layer_count;
+    VkFormat dsv_format;
 
     bool xfb_enabled;
 
     VkFramebuffer current_framebuffer;
     VkPipeline current_pipeline;
+    VkRenderPass pso_render_pass;
     VkRenderPass current_render_pass;
     struct vkd3d_pipeline_bindings pipeline_bindings[VK_PIPELINE_BIND_POINT_RANGE_SIZE];
 
-- 
2.21.0




More information about the wine-devel mailing list