[PATCH 1/6] wined3d: Implement shader_spirv_select().

Henri Verbeet hverbeet at codeweavers.com
Tue May 19 14:32:26 CDT 2020


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

Signed-off-by: Henri Verbeet <hverbeet at codeweavers.com>
---
 dlls/wined3d/context_vk.c      |  16 +++
 dlls/wined3d/shader_spirv.c    | 226 ++++++++++++++++++++++++++++++++-
 dlls/wined3d/wined3d_private.h |   2 +
 3 files changed, 237 insertions(+), 7 deletions(-)

diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index f5902bbd65a..08ce3db7ccc 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -1893,6 +1893,7 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c
     struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
     const struct wined3d_vk_info *vk_info = context_vk->vk_info;
     struct wined3d_rendertarget_view *dsv;
+    VkSampleCountFlagBits sample_count;
     VkCommandBuffer vk_command_buffer;
     unsigned int i;
 
@@ -1908,6 +1909,7 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c
     if (wined3d_context_is_graphics_state_dirty(&context_vk->c, STATE_SHADER(WINED3D_SHADER_TYPE_DOMAIN)))
         context_vk->c.shader_update_mask |= (1u << WINED3D_SHADER_TYPE_DOMAIN);
 
+    context_vk->sample_count = 0;
     for (i = 0; i < ARRAY_SIZE(state->fb.render_targets); ++i)
     {
         struct wined3d_rendertarget_view *rtv;
@@ -1924,6 +1926,12 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c
         {
             wined3d_rendertarget_view_prepare_location(rtv, &context_vk->c, rtv->resource->draw_binding);
         }
+
+        sample_count = max(1, wined3d_resource_get_sample_count(rtv->resource));
+        if (!context_vk->sample_count)
+            context_vk->sample_count = sample_count;
+        else if (context_vk->sample_count != sample_count)
+            FIXME("Inconsistent sample counts (%u != %u).\n", context_vk->sample_count, sample_count);
     }
 
     if ((dsv = state->fb.depth_stencil))
@@ -1934,8 +1942,16 @@ VkCommandBuffer wined3d_context_vk_apply_draw_state(struct wined3d_context_vk *c
             wined3d_rendertarget_view_prepare_location(dsv, &context_vk->c, dsv->resource->draw_binding);
         if (state->render_states[WINED3D_RS_ZWRITEENABLE])
             wined3d_rendertarget_view_invalidate_location(dsv, ~dsv->resource->draw_binding);
+
+        sample_count = max(1, wined3d_resource_get_sample_count(dsv->resource));
+        if (!context_vk->sample_count)
+            context_vk->sample_count = sample_count;
+        else if (context_vk->sample_count != sample_count)
+            FIXME("Inconsistent sample counts (%u != %u).\n", context_vk->sample_count, sample_count);
     }
 
+    if (!context_vk->sample_count)
+        context_vk->sample_count = VK_SAMPLE_COUNT_1_BIT;
     if (context_vk->c.shader_update_mask & ~(1u << WINED3D_SHADER_TYPE_COMPUTE))
     {
         device_vk->d.shader_backend->shader_select(device_vk->d.shader_priv, &context_vk->c, state);
diff --git a/dlls/wined3d/shader_spirv.c b/dlls/wined3d/shader_spirv.c
index 2dc07b14f1d..07b9a5202bc 100644
--- a/dlls/wined3d/shader_spirv.c
+++ b/dlls/wined3d/shader_spirv.c
@@ -30,6 +30,8 @@ struct shader_spirv_resource_bindings
 {
     VkDescriptorSetLayoutBinding *vk_bindings;
     SIZE_T vk_bindings_size, vk_binding_count;
+
+    size_t binding_base[WINED3D_SHADER_TYPE_COUNT];
 };
 
 struct shader_spirv_priv
@@ -41,6 +43,38 @@ struct shader_spirv_priv
     struct shader_spirv_resource_bindings bindings;
 };
 
+struct shader_spirv_compile_arguments
+{
+    union
+    {
+        struct
+        {
+            uint32_t alpha_swizzle;
+            unsigned int sample_count;
+        } fs;
+
+        struct
+        {
+            enum wined3d_tessellator_output_primitive output_primitive;
+            enum wined3d_tessellator_partitioning partitioning;
+        } tes;
+    } u;
+};
+
+struct shader_spirv_graphics_program_variant_vk
+{
+    struct shader_spirv_compile_arguments compile_args;
+    size_t binding_base;
+
+    VkShaderModule vk_module;
+};
+
+struct shader_spirv_graphics_program_vk
+{
+    struct shader_spirv_graphics_program_variant_vk *variants;
+    SIZE_T variants_size, variant_count;
+};
+
 struct shader_spirv_compute_program_vk
 {
     VkShaderModule vk_module;
@@ -53,14 +87,95 @@ static void shader_spirv_handle_instruction(const struct wined3d_shader_instruct
 {
 }
 
+static void shader_spirv_compile_arguments_init(struct shader_spirv_compile_arguments *args,
+        const struct wined3d_context *context, const struct wined3d_shader *shader,
+        const struct wined3d_state *state, unsigned int sample_count)
+{
+    const struct wined3d_shader *hull_shader;
+    struct wined3d_rendertarget_view *rtv;
+    unsigned int i;
+
+    memset(args, 0, sizeof(*args));
+
+    switch (shader->reg_maps.shader_version.type)
+    {
+        case WINED3D_SHADER_TYPE_DOMAIN:
+            hull_shader = state->shader[WINED3D_SHADER_TYPE_HULL];
+            args->u.tes.output_primitive = hull_shader->u.hs.tessellator_output_primitive;
+            if (args->u.tes.output_primitive == WINED3D_TESSELLATOR_OUTPUT_TRIANGLE_CW)
+                args->u.tes.output_primitive = WINED3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW;
+            else if (args->u.tes.output_primitive == WINED3D_TESSELLATOR_OUTPUT_TRIANGLE_CCW)
+                args->u.tes.output_primitive = WINED3D_TESSELLATOR_OUTPUT_TRIANGLE_CW;
+            args->u.tes.partitioning = hull_shader->u.hs.tessellator_partitioning;
+            break;
+
+        case WINED3D_SHADER_TYPE_PIXEL:
+            for (i = 0; i < ARRAY_SIZE(state->fb.render_targets); ++i)
+            {
+                if (!(rtv = state->fb.render_targets[i]) || rtv->format->id == WINED3DFMT_NULL)
+                    continue;
+                if (rtv->format->id == WINED3DFMT_A8_UNORM && !is_identity_fixup(rtv->format->color_fixup))
+                    args->u.fs.alpha_swizzle |= 1u << i;
+            }
+            args->u.fs.sample_count = sample_count;
+            break;
+
+        default:
+            break;
+    }
+}
+
 static VkShaderModule shader_spirv_compile(struct wined3d_context_vk *context_vk,
-        struct wined3d_shader *shader, const struct shader_spirv_resource_bindings *bindings)
+        struct wined3d_shader *shader, const struct shader_spirv_compile_arguments *args,
+        const struct shader_spirv_resource_bindings *bindings)
 {
     FIXME("Not implemented.\n");
 
     return VK_NULL_HANDLE;
 }
 
+static struct shader_spirv_graphics_program_variant_vk *shader_spirv_find_graphics_program_variant_vk(
+        struct shader_spirv_priv *priv, struct wined3d_context_vk *context_vk, struct wined3d_shader *shader,
+        const struct wined3d_state *state, const struct shader_spirv_resource_bindings *bindings)
+{
+    size_t binding_base = bindings->binding_base[shader->reg_maps.shader_version.type];
+    struct shader_spirv_graphics_program_variant_vk *variant_vk;
+    struct shader_spirv_graphics_program_vk *program_vk;
+    struct shader_spirv_compile_arguments args;
+    size_t variant_count, i;
+
+    shader_spirv_compile_arguments_init(&args, &context_vk->c, shader, state, context_vk->sample_count);
+
+    if (!(program_vk = shader->backend_data))
+    {
+        if (!(program_vk = heap_alloc_zero(sizeof(*program_vk))))
+            return NULL;
+        shader->backend_data = program_vk;
+    }
+
+    variant_count = program_vk->variant_count;
+    for (i = 0; i < variant_count; ++i)
+    {
+        variant_vk = &program_vk->variants[i];
+        if (variant_vk->binding_base == binding_base
+                && !memcmp(&variant_vk->compile_args, &args, sizeof(args)))
+            return variant_vk;
+    }
+
+    if (!wined3d_array_reserve((void **)&program_vk->variants, &program_vk->variants_size,
+            variant_count + 1, sizeof(*program_vk->variants)))
+        return NULL;
+
+    variant_vk = &program_vk->variants[variant_count];
+    variant_vk->compile_args = args;
+    variant_vk->binding_base = binding_base;
+    if (!(variant_vk->vk_module = shader_spirv_compile(context_vk, shader, &args, bindings)))
+        return NULL;
+    ++program_vk->variant_count;
+
+    return variant_vk;
+}
+
 static struct shader_spirv_compute_program_vk *shader_spirv_find_compute_program_vk(struct shader_spirv_priv *priv,
         struct wined3d_context_vk *context_vk, struct wined3d_shader *shader,
         const struct shader_spirv_resource_bindings *bindings)
@@ -78,7 +193,7 @@ static struct shader_spirv_compute_program_vk *shader_spirv_find_compute_program
     if (!(program = heap_alloc(sizeof(*program))))
         return NULL;
 
-    if (!(program->vk_module = shader_spirv_compile(context_vk, shader, bindings)))
+    if (!(program->vk_module = shader_spirv_compile(context_vk, shader, NULL, bindings)))
     {
         heap_free(program);
         return NULL;
@@ -191,6 +306,8 @@ static bool shader_spirv_resource_bindings_init(struct shader_spirv_resource_bin
 
     for (shader_type = 0; shader_type < WINED3D_SHADER_TYPE_COUNT; ++shader_type)
     {
+        bindings->binding_base[shader_type] = bindings->vk_binding_count;
+
         if (!(shader_mask & (1u << shader_type)) || !(shader = state->shader[shader_type]))
             continue;
 
@@ -295,10 +412,53 @@ static void shader_spirv_precompile(void *shader_priv, struct wined3d_shader *sh
 static void shader_spirv_select(void *shader_priv, struct wined3d_context *context,
         const struct wined3d_state *state)
 {
+    struct wined3d_context_vk *context_vk = wined3d_context_vk(context);
+    struct shader_spirv_graphics_program_variant_vk *variant_vk;
+    struct shader_spirv_resource_bindings *bindings;
+    size_t binding_base[WINED3D_SHADER_TYPE_COUNT];
+    struct wined3d_pipeline_layout_vk *layout_vk;
     struct shader_spirv_priv *priv = shader_priv;
+    enum wined3d_shader_type shader_type;
+    struct wined3d_shader *shader;
 
     priv->vertex_pipe->vp_enable(context, !use_vs(state));
     priv->fragment_pipe->fp_enable(context, !use_ps(state));
+
+    bindings = &priv->bindings;
+    memcpy(binding_base, bindings->binding_base, sizeof(bindings));
+    if (!shader_spirv_resource_bindings_init(bindings, &context_vk->graphics.bindings,
+            state, ~(1u << WINED3D_SHADER_TYPE_COMPUTE)))
+    {
+        ERR("Failed to initialise shader resource bindings.\n");
+        goto fail;
+    }
+
+    layout_vk = wined3d_context_vk_get_pipeline_layout(context_vk, bindings->vk_bindings, bindings->vk_binding_count);
+    context_vk->graphics.vk_set_layout = layout_vk->vk_set_layout;
+    context_vk->graphics.vk_pipeline_layout = layout_vk->vk_pipeline_layout;
+
+    for (shader_type = 0; shader_type < ARRAY_SIZE(context_vk->graphics.vk_modules); ++shader_type)
+    {
+        if (!(context->shader_update_mask & (1u << shader_type)) && (!context_vk->graphics.vk_modules[shader_type]
+                || binding_base[shader_type] == bindings->binding_base[shader_type]))
+            continue;
+
+        if (!(shader = state->shader[shader_type]))
+        {
+            context_vk->graphics.vk_modules[shader_type] = VK_NULL_HANDLE;
+            continue;
+        }
+
+        if (!(variant_vk = shader_spirv_find_graphics_program_variant_vk(priv, context_vk, shader, state, bindings)))
+            goto fail;
+        context_vk->graphics.vk_modules[shader_type] = variant_vk->vk_module;
+    }
+
+    return;
+
+fail:
+    context_vk->graphics.vk_set_layout = VK_NULL_HANDLE;
+    context_vk->graphics.vk_pipeline_layout = VK_NULL_HANDLE;
 }
 
 static void shader_spirv_select_compute(void *shader_priv,
@@ -386,14 +546,37 @@ static void shader_spirv_invalidate_contexts_compute_program(struct wined3d_devi
     }
 }
 
-static void shader_spirv_destroy(struct wined3d_shader *shader)
+static void shader_spirv_invalidate_graphics_program_variant(struct wined3d_context_vk *context_vk,
+        const struct shader_spirv_graphics_program_variant_vk *variant)
+{
+    enum wined3d_shader_type shader_type;
+
+    for (shader_type = 0; shader_type < WINED3D_SHADER_TYPE_GRAPHICS_COUNT; ++shader_type)
+    {
+        if (context_vk->graphics.vk_modules[shader_type] != variant->vk_module)
+            continue;
+
+        context_vk->graphics.vk_modules[shader_type] = VK_NULL_HANDLE;
+        context_vk->c.shader_update_mask |= (1u << shader_type);
+    }
+}
+
+static void shader_spirv_invalidate_contexts_graphics_program_variant(struct wined3d_device *device,
+        const struct shader_spirv_graphics_program_variant_vk *variant)
+{
+    unsigned int i;
+
+    for (i = 0; i < device->context_count; ++i)
+    {
+        shader_spirv_invalidate_graphics_program_variant(wined3d_context_vk(device->contexts[i]), variant);
+    }
+}
+
+static void shader_spirv_destroy_compute_vk(struct wined3d_shader *shader)
 {
     struct wined3d_device_vk *device_vk = wined3d_device_vk(shader->device);
+    struct shader_spirv_compute_program_vk *program = shader->backend_data;
     struct wined3d_vk_info *vk_info = &device_vk->vk_info;
-    struct shader_spirv_compute_program_vk *program;
-
-    if (!(program = shader->backend_data))
-        return;
 
     shader_spirv_invalidate_contexts_compute_program(&device_vk->d, program);
     VK_CALL(vkDestroyPipeline(device_vk->vk_device, program->vk_pipeline, NULL));
@@ -402,6 +585,35 @@ static void shader_spirv_destroy(struct wined3d_shader *shader)
     heap_free(program);
 }
 
+static void shader_spirv_destroy(struct wined3d_shader *shader)
+{
+    struct wined3d_device_vk *device_vk = wined3d_device_vk(shader->device);
+    struct shader_spirv_graphics_program_variant_vk *variant_vk;
+    struct wined3d_vk_info *vk_info = &device_vk->vk_info;
+    struct shader_spirv_graphics_program_vk *program_vk;
+    size_t i;
+
+    if (!shader->backend_data)
+        return;
+
+    if (shader->reg_maps.shader_version.type == WINED3D_SHADER_TYPE_COMPUTE)
+    {
+        shader_spirv_destroy_compute_vk(shader);
+        return;
+    }
+
+    program_vk = shader->backend_data;
+    for (i = 0; i < program_vk->variant_count; ++i)
+    {
+        variant_vk = &program_vk->variants[i];
+        shader_spirv_invalidate_contexts_graphics_program_variant(&device_vk->d, variant_vk);
+        VK_CALL(vkDestroyShaderModule(device_vk->vk_device, variant_vk->vk_module, NULL));
+    }
+
+    shader->backend_data = NULL;
+    heap_free(program_vk);
+}
+
 static HRESULT shader_spirv_alloc(struct wined3d_device *device,
         const struct wined3d_vertex_pipe_ops *vertex_pipe, const struct wined3d_fragment_pipe_ops *fragment_pipe)
 {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index ef82fd7b0c1..a56d1f59ecc 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2394,6 +2394,8 @@ struct wined3d_context_vk
     VkRenderPass vk_render_pass;
     VkDescriptorPool vk_descriptor_pool;
 
+    VkSampleCountFlagBits sample_count;
+
     struct wined3d_retired_objects_vk retired;
     struct wine_rb_tree render_passes;
     struct wine_rb_tree pipeline_layouts;
-- 
2.20.1




More information about the wine-devel mailing list