From 2875332df54a0c4d794a1f5e6f5075c56fc070e4 Mon Sep 17 00:00:00 2001 From: Danylo Piliaiev Date: Thu, 7 Nov 2024 18:15:38 +0100 Subject: [PATCH] tu: Allocate consts for driver params as early as possible Indirect draw calls upload VS params themselves, if indirect draw call has zero instances GPU seem to still try to upload consts, however with zer instances it doesn't apply draw state. Without the draw state the the HLSQ_VS_CNTL values is stale, so less constants may be specified than draw call expects. It is found that if CP_DRAW_INDIRECT_MULTI_1_DST_OFF is less than 0x3f - GPU is happy even if the constlen is less than that. As a workaround we allocate driver params first and ensure that VS constlen always has the minimum size which is enough to upload driver params. Fixes one of the GPU hangs in "Disney Epic Mickey: Rebrushed" on a750. Signed-off-by: Danylo Piliaiev Part-of: --- src/freedreno/ir3/ir3_compiler_nir.c | 4 ++++ src/freedreno/ir3/ir3_nir.c | 15 +++++++++------ src/freedreno/vulkan/tu_cmd_buffer.cc | 8 ++++++++ src/freedreno/vulkan/tu_shader.cc | 18 ++++++++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/freedreno/ir3/ir3_compiler_nir.c b/src/freedreno/ir3/ir3_compiler_nir.c index 09ce0a4c37f..4c4a7b7ba6f 100644 --- a/src/freedreno/ir3/ir3_compiler_nir.c +++ b/src/freedreno/ir3/ir3_compiler_nir.c @@ -5966,6 +5966,10 @@ ir3_compile_shader_nir(struct ir3_compiler *compiler, so->constlen = MAX2(so->constlen, 4); } + if (ctx->so->type == MESA_SHADER_VERTEX && ctx->compiler->gen >= 6) { + so->constlen = MAX2(so->constlen, 8); + } + if (gl_shader_stage_is_compute(so->type)) { so->cs.local_invocation_id = ir3_find_sysval_regid(so, SYSTEM_VALUE_LOCAL_INVOCATION_ID); diff --git a/src/freedreno/ir3/ir3_nir.c b/src/freedreno/ir3/ir3_nir.c index 5240e8e61a7..d0991fca1ad 100644 --- a/src/freedreno/ir3/ir3_nir.c +++ b/src/freedreno/ir3/ir3_nir.c @@ -1242,12 +1242,12 @@ ir3_get_driver_param_info(const nir_shader *shader, nir_intrinsic_instr *intr, param_info->offset = IR3_DP_CS(local_group_size_x); break; case nir_intrinsic_load_subgroup_size: - assert(shader->info.stage == MESA_SHADER_COMPUTE || - shader->info.stage == MESA_SHADER_FRAGMENT); if (shader->info.stage == MESA_SHADER_COMPUTE) { param_info->offset = IR3_DP_CS(subgroup_size); - } else { + } else if (shader->info.stage == MESA_SHADER_FRAGMENT) { param_info->offset = IR3_DP_FS(subgroup_size); + } else { + return false; } break; case nir_intrinsic_load_subgroup_id_shift_ir3: @@ -1476,9 +1476,12 @@ ir3_setup_const_state(nir_shader *nir, struct ir3_shader_variant *v, assert((const_state->ubo_state.size % 16) == 0); - ir3_alloc_driver_params(&const_state->allocs, - &const_state->num_driver_params, compiler, - v->type); + /* IR3_CONST_ALLOC_DRIVER_PARAMS could have been allocated earlier. */ + if (const_state->allocs.consts[IR3_CONST_ALLOC_DRIVER_PARAMS].size_vec4 == 0) { + ir3_alloc_driver_params(&const_state->allocs, + &const_state->num_driver_params, compiler, + v->type); + } if (const_state->image_dims.count > 0) { ir3_const_reserve_space(&const_state->allocs, IR3_CONST_ALLOC_IMAGE_DIMS, diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index 0b114be1ec5..f46a9384f35 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -1474,6 +1474,14 @@ tu6_init_static_regs(struct tu_device *dev, struct tu_cs *cs) if (phys_dev->info->a6xx.has_early_preamble) { tu_cs_emit_regs(cs, A6XX_SP_FS_CTRL_REG0()); } + + /* Workaround for draw state with constlen not being applied for + * zero-instance draw calls. See IR3_CONST_ALLOC_DRIVER_PARAMS allocation + * for more info. + */ + tu_cs_emit_pkt4( + cs, CHIP == A6XX ? REG_A6XX_HLSQ_VS_CNTL : REG_A7XX_HLSQ_VS_CNTL, 1); + tu_cs_emit(cs, A6XX_HLSQ_VS_CNTL_CONSTLEN(8) | A6XX_HLSQ_VS_CNTL_ENABLED); } /* Set always-identical registers used specifically for GMEM */ diff --git a/src/freedreno/vulkan/tu_shader.cc b/src/freedreno/vulkan/tu_shader.cc index ca7a6da65ca..6cae345c44e 100644 --- a/src/freedreno/vulkan/tu_shader.cc +++ b/src/freedreno/vulkan/tu_shader.cc @@ -836,6 +836,24 @@ tu_lower_io(nir_shader *shader, struct tu_device *dev, bool dynamic_renderpass, struct ir3_const_allocations *const_allocs) { + /* Allocate driver params as early as possible as a workaround for the + * following case: + * - CP_DRAW_INDIRECT_MULTI_1_DST_OFF apparently tries to upload consts + * even when there are 0 instances. + * - With zero instances, the draw state for VS constlen is not applied. + * - constlen therefor uses stale value and if + * CP_DRAW_INDIRECT_MULTI_1_DST_OFF is higher than 0x3f - GPU hangs. + * + * To not rely on undefined behaviour, we will always allocate enough space + * to upload driver params. + */ + if (shader->info.stage == MESA_SHADER_VERTEX) { + uint32_t num_driver_params = + ir3_nir_scan_driver_consts(dev->compiler, shader, nullptr); + ir3_alloc_driver_params(const_allocs, &num_driver_params, dev->compiler, + shader->info.stage); + } + struct tu_const_state *const_state = &tu_shader->const_state; const_state->push_consts = (struct tu_push_constant_range) { .lo_dwords = 0,