radv: fix non-indexed draws with primitive restart enable
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run

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 <samuel.pitoiset@gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34996>
This commit is contained in:
Samuel Pitoiset 2025-05-15 12:56:54 +02:00 committed by Marge Bot
parent 7ce7009ee4
commit 4d1fcd75f9
2 changed files with 82 additions and 63 deletions

View file

@ -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;
}
/*

View file

@ -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;