From 4d1fcd75f91708a041b690e66d06d8ba70bdba2b Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Thu, 15 May 2025 12:56:54 +0200 Subject: [PATCH] radv: fix non-indexed draws with primitive restart enable On GFX11+, DISABLE_FOR_AUTO_INDEX=1 automatically disables primitive restart enable for non-indexed draws. On GFX10-GFX10.3 the hw considers primitive restart enable for non-indexed draws and the driver must disable it explicitly. GFX9 and older gens aren't affected but applying the change for them simplifies the implementation. To fix that, move emitting primitive restart enable at draw time because it needs to know if the draw is indexed or not. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/13037 Cc: mesa-stable Signed-off-by: Samuel Pitoiset Part-of: --- src/amd/vulkan/radv_cmd_buffer.c | 141 +++++++++++++++++-------------- src/amd/vulkan/radv_cmd_buffer.h | 4 + 2 files changed, 82 insertions(+), 63 deletions(-) diff --git a/src/amd/vulkan/radv_cmd_buffer.c b/src/amd/vulkan/radv_cmd_buffer.c index 5fc845db8fa..3ac2ab38010 100644 --- a/src/amd/vulkan/radv_cmd_buffer.c +++ b/src/amd/vulkan/radv_cmd_buffer.c @@ -3443,48 +3443,6 @@ radv_get_primitive_reset_index(const struct radv_cmd_buffer *cmd_buffer) } } -static void -radv_emit_primitive_restart_enable(struct radv_cmd_buffer *cmd_buffer) -{ - struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); - const struct radv_physical_device *pdev = radv_device_physical(device); - const enum amd_gfx_level gfx_level = pdev->info.gfx_level; - const struct radv_dynamic_state *const d = &cmd_buffer->state.dynamic; - struct radeon_cmdbuf *cs = cmd_buffer->cs; - const bool en = d->vk.ia.primitive_restart_enable; - - radeon_begin(cs); - - if (pdev->info.has_prim_restart_sync_bug) { - radeon_event_write(V_028A90_SQ_NON_EVENT); - } - - if (gfx_level >= GFX11) { - radeon_set_uconfig_reg(R_03092C_GE_MULTI_PRIM_IB_RESET_EN, S_03092C_RESET_EN(en) | - /* This disables primitive restart for non-indexed - * draws. By keeping this set, we don't have to - * unset RESET_EN for non-indexed draws. */ - S_03092C_DISABLE_FOR_AUTO_INDEX(1)); - } else if (gfx_level >= GFX9) { - radeon_set_uconfig_reg(R_03092C_VGT_MULTI_PRIM_IB_RESET_EN, en); - } else { - radeon_set_context_reg(R_028A94_VGT_MULTI_PRIM_IB_RESET_EN, en); - - /* GFX6-7: All 32 bits are compared. - * GFX8: Only index type bits are compared. - * GFX9+: Default is same as GFX8, MATCH_ALL_BITS=1 selects GFX6-7 behavior - */ - if (en && gfx_level <= GFX7) { - const uint32_t primitive_reset_index = radv_get_primitive_reset_index(cmd_buffer); - - radeon_opt_set_context_reg(cmd_buffer, R_02840C_VGT_MULTI_PRIM_IB_RESET_INDX, - RADV_TRACKED_VGT_MULTI_PRIM_IB_RESET_INDX, primitive_reset_index); - } - } - - radeon_end(); -} - static void radv_emit_logic_op(struct radv_cmd_buffer *cmd_buffer) { @@ -5516,9 +5474,6 @@ radv_cmd_buffer_flush_dynamic_state(struct radv_cmd_buffer *cmd_buffer, const ui if (states & RADV_DYNAMIC_FRAGMENT_SHADING_RATE) radv_emit_fragment_shading_rate(cmd_buffer); - if (states & RADV_DYNAMIC_PRIMITIVE_RESTART_ENABLE) - radv_emit_primitive_restart_enable(cmd_buffer); - if (states & (RADV_DYNAMIC_LOGIC_OP | RADV_DYNAMIC_LOGIC_OP_ENABLE | RADV_DYNAMIC_COLOR_WRITE_MASK | RADV_DYNAMIC_COLOR_BLEND_EQUATION)) radv_emit_logic_op(cmd_buffer); @@ -6410,11 +6365,55 @@ gfx10_emit_ge_cntl(struct radv_cmd_buffer *cmd_buffer) } } +static void +radv_emit_primitive_restart(struct radv_cmd_buffer *cmd_buffer, bool enable) +{ + struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); + const struct radv_physical_device *pdev = radv_device_physical(device); + const enum amd_gfx_level gfx_level = pdev->info.gfx_level; + struct radeon_cmdbuf *cs = cmd_buffer->cs; + + radeon_begin(cs); + + if (pdev->info.has_prim_restart_sync_bug) { + radeon_event_write(V_028A90_SQ_NON_EVENT); + } + + if (gfx_level >= GFX11) { + radeon_set_uconfig_reg(R_03092C_GE_MULTI_PRIM_IB_RESET_EN, S_03092C_RESET_EN(enable) | + /* This disables primitive restart for non-indexed + * draws. By keeping this set, we don't have to + * unset RESET_EN for non-indexed draws. */ + S_03092C_DISABLE_FOR_AUTO_INDEX(1)); + } else if (gfx_level >= GFX9) { + radeon_set_uconfig_reg(R_03092C_VGT_MULTI_PRIM_IB_RESET_EN, enable); + } else { + radeon_set_context_reg(R_028A94_VGT_MULTI_PRIM_IB_RESET_EN, enable); + + /* GFX6-7: All 32 bits are compared. + * GFX8: Only index type bits are compared. + * GFX9+: Default is same as GFX8, MATCH_ALL_BITS=1 selects GFX6-7 behavior + */ + if (enable && gfx_level <= GFX7) { + const uint32_t primitive_reset_index = radv_get_primitive_reset_index(cmd_buffer); + + radeon_opt_set_context_reg(cmd_buffer, R_02840C_VGT_MULTI_PRIM_IB_RESET_INDX, + RADV_TRACKED_VGT_MULTI_PRIM_IB_RESET_INDX, primitive_reset_index); + } + } + + radeon_end(); +} + static void radv_emit_draw_registers(struct radv_cmd_buffer *cmd_buffer, const struct radv_draw_info *draw_info) { struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); const struct radv_physical_device *pdev = radv_device_physical(device); + const struct radv_dynamic_state *d = &cmd_buffer->state.dynamic; + const bool primitive_restart_en = + (draw_info->indexed || pdev->info.gfx_level >= GFX11) && d->vk.ia.primitive_restart_enable; + const uint32_t primitive_reset_index = radv_get_primitive_reset_index(cmd_buffer); const struct radeon_info *gpu_info = &pdev->info; struct radv_cmd_state *state = &cmd_buffer->state; struct radeon_cmdbuf *cs = cmd_buffer->cs; @@ -6459,6 +6458,13 @@ radv_emit_draw_registers(struct radv_cmd_buffer *cmd_buffer, const struct radv_d state->last_index_type = index_type; } + + if (primitive_restart_en != state->last_primitive_restart_en || + (pdev->info.gfx_level <= GFX7 && primitive_reset_index != state->last_primitive_reset_index)) { + radv_emit_primitive_restart(cmd_buffer, primitive_restart_en); + state->last_primitive_restart_en = primitive_restart_en; + state->last_primitive_reset_index = primitive_reset_index; + } } static void @@ -6835,6 +6841,7 @@ radv_BeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBegi memset(&cmd_buffer->state, 0, sizeof(cmd_buffer->state)); cmd_buffer->state.last_index_type = -1; + cmd_buffer->state.last_primitive_restart_en = pdev->info.gfx_level >= GFX11 ? false : -1; cmd_buffer->state.last_num_instances = -1; cmd_buffer->state.last_vertex_offset_valid = false; cmd_buffer->state.last_first_instance = -1; @@ -7069,10 +7076,6 @@ radv_CmdBindIndexBuffer2(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDevic } cmd_buffer->state.dirty |= RADV_CMD_DIRTY_INDEX_BUFFER; - - /* Primitive restart state depends on the index type. */ - if (cmd_buffer->state.dynamic.vk.ia.primitive_restart_enable) - cmd_buffer->state.dirty_dynamic |= RADV_DYNAMIC_PRIMITIVE_RESTART_ENABLE; } static void @@ -9057,6 +9060,14 @@ radv_CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCou primary->state.last_index_type = secondary->state.last_index_type; } + if (secondary->state.last_primitive_restart_en != -1) { + primary->state.last_primitive_restart_en = secondary->state.last_primitive_restart_en; + } + + if (secondary->state.last_primitive_reset_index) { + primary->state.last_primitive_reset_index = secondary->state.last_primitive_reset_index; + } + primary->state.last_vrs_rates = secondary->state.last_vrs_rates; primary->state.last_force_vrs_rates_offset = secondary->state.last_force_vrs_rates_offset; @@ -10263,24 +10274,28 @@ radv_get_needed_dynamic_states(struct radv_cmd_buffer *cmd_buffer) { struct radv_device *device = radv_cmd_buffer_device(cmd_buffer); const struct radv_physical_device *pdev = radv_device_physical(device); - uint64_t dynamic_states = RADV_DYNAMIC_ALL; + uint64_t dynamic_states; - if (cmd_buffer->state.graphics_pipeline) - return cmd_buffer->state.graphics_pipeline->needed_dynamic_state; - - /* Clear unnecessary dynamic states for shader objects. */ - if (!cmd_buffer->state.shaders[MESA_SHADER_TESS_CTRL]) - dynamic_states &= ~(RADV_DYNAMIC_PATCH_CONTROL_POINTS | RADV_DYNAMIC_TESS_DOMAIN_ORIGIN); - - if (pdev->info.gfx_level >= GFX10_3) { - if (cmd_buffer->state.shaders[MESA_SHADER_MESH]) - dynamic_states &= ~(RADV_DYNAMIC_VERTEX_INPUT | RADV_DYNAMIC_VERTEX_INPUT_BINDING_STRIDE | - RADV_DYNAMIC_PRIMITIVE_RESTART_ENABLE | RADV_DYNAMIC_PRIMITIVE_TOPOLOGY); + if (cmd_buffer->state.graphics_pipeline) { + dynamic_states = cmd_buffer->state.graphics_pipeline->needed_dynamic_state; } else { - dynamic_states &= ~RADV_DYNAMIC_FRAGMENT_SHADING_RATE; + dynamic_states = RADV_DYNAMIC_ALL; + + /* Clear unnecessary dynamic states for shader objects. */ + if (!cmd_buffer->state.shaders[MESA_SHADER_TESS_CTRL]) + dynamic_states &= ~(RADV_DYNAMIC_PATCH_CONTROL_POINTS | RADV_DYNAMIC_TESS_DOMAIN_ORIGIN); + + if (pdev->info.gfx_level >= GFX10_3) { + if (cmd_buffer->state.shaders[MESA_SHADER_MESH]) + dynamic_states &= ~(RADV_DYNAMIC_VERTEX_INPUT | RADV_DYNAMIC_VERTEX_INPUT_BINDING_STRIDE | + RADV_DYNAMIC_PRIMITIVE_TOPOLOGY); + } else { + dynamic_states &= ~RADV_DYNAMIC_FRAGMENT_SHADING_RATE; + } } - return dynamic_states; + /* Primitive restart enable is emitted as part of the draw registers. */ + return dynamic_states & ~RADV_DYNAMIC_PRIMITIVE_RESTART_ENABLE; } /* diff --git a/src/amd/vulkan/radv_cmd_buffer.h b/src/amd/vulkan/radv_cmd_buffer.h index 82eaf398aff..f55fd7e9a0d 100644 --- a/src/amd/vulkan/radv_cmd_buffer.h +++ b/src/amd/vulkan/radv_cmd_buffer.h @@ -391,6 +391,10 @@ struct radv_cmd_state { uint64_t index_va; int32_t last_index_type; + /* Primitive restart */ + int32_t last_primitive_restart_en; + uint32_t last_primitive_reset_index; + enum radv_cmd_flush_bits flush_bits; unsigned active_occlusion_queries; bool perfect_occlusion_queries_enabled;