From a76fcebfc00df371cbf45a48c7e6385c2bda2c75 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Mon, 4 Mar 2024 14:36:08 +0100 Subject: [PATCH] tu: Fix dynamic state not always being emitted We precompile static state and count it as dynamic, so we have to manually clear bitset that tells which dynamic state is set, in order to make sure that future dynamic state will be emitted. The issue is that framework remembers only a past REAL dynamic state and compares a new dynamic state against it, and not against our static state masquaraded as dynamic. Example: - Set dynamic state S with value A - Bind pipeline with dynamic state S - Draw - Bind pipeline with static state S with value B - Draw - Set dynamic state S with value A - Bind pipeline with dynamic state S - Draw Previously, at the last draw the dynamic state S was not dirty and current dynamic state was equal to the past dynamic state, so it was not emitted, while GPU used value B from static pipeline. This fix, at the point of static pipeline binding, clears the bitset which tells that dynamic state S was previously set. This forces the next dynamic state to be re-emitted. Fixes broken rendering in Arma 3, and probably some other games running through DXVK. Fixes: 97da0a7734188f4b666bc38833bfadc8b4c53f84 ("tu: Rewrite to use common Vulkan dynamic state") Signed-off-by: Danylo Piliaiev Part-of: --- src/freedreno/vulkan/tu_cmd_buffer.cc | 11 +++++++++++ src/freedreno/vulkan/tu_pipeline.cc | 6 ++++++ src/freedreno/vulkan/tu_pipeline.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index a6effd93f4d..5df86b87cdf 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -3159,6 +3159,17 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer, tu_bind_gs(cmd, pipeline->shaders[MESA_SHADER_GEOMETRY]); tu_bind_fs(cmd, pipeline->shaders[MESA_SHADER_FRAGMENT]); + /* We precompile static state and count it as dynamic, so we have to + * manually clear bitset that tells which dynamic state is set, in order to + * make sure that future dynamic state will be emitted. The issue is that + * framework remembers only a past REAL dynamic state and compares a new + * dynamic state against it, and not against our static state masquaraded + * as dynamic. + */ + BITSET_ANDNOT(cmd->vk.dynamic_graphics_state.set, + cmd->vk.dynamic_graphics_state.set, + pipeline->static_state_mask); + vk_cmd_set_dynamic_graphics_state(&cmd->vk, &gfx_pipeline->dynamic_state); cmd->state.program = pipeline->program; diff --git a/src/freedreno/vulkan/tu_pipeline.cc b/src/freedreno/vulkan/tu_pipeline.cc index e1c0616d698..6ef11a907a4 100644 --- a/src/freedreno/vulkan/tu_pipeline.cc +++ b/src/freedreno/vulkan/tu_pipeline.cc @@ -2057,6 +2057,9 @@ tu_pipeline_builder_parse_libraries(struct tu_pipeline_builder *builder, } } + BITSET_OR(pipeline->static_state_mask, pipeline->static_state_mask, + library->base.static_state_mask); + vk_graphics_pipeline_state_merge(&builder->graphics_state, &library->graphics_state); } @@ -3367,6 +3370,9 @@ tu_pipeline_builder_emit_state(struct tu_pipeline_builder *builder, * binding the pipeline by making it "dynamic". */ BITSET_ANDNOT(remove, remove, keep); + + BITSET_OR(pipeline->static_state_mask, pipeline->static_state_mask, remove); + BITSET_OR(builder->graphics_state.dynamic, builder->graphics_state.dynamic, remove); } diff --git a/src/freedreno/vulkan/tu_pipeline.h b/src/freedreno/vulkan/tu_pipeline.h index 0a932131e6b..fde929728e8 100644 --- a/src/freedreno/vulkan/tu_pipeline.h +++ b/src/freedreno/vulkan/tu_pipeline.h @@ -136,6 +136,8 @@ struct tu_pipeline uint32_t set_state_mask; struct tu_draw_state dynamic_state[TU_DYNAMIC_STATE_COUNT]; + BITSET_DECLARE(static_state_mask, MESA_VK_DYNAMIC_GRAPHICS_STATE_ENUM_MAX); + struct { bool raster_order_attachment_access; } ds;