From f4e0ca21992db6cb40bad8120e258c05c6072e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B3zef=20Kucia?= Date: Wed, 20 May 2020 00:02:26 +0430 Subject: [PATCH] wined3d: Implement shader_spirv_select(). Signed-off-by: Henri Verbeet Signed-off-by: Alexandre Julliard --- 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;