From 5a3b0ce461247a3164c6c58df1d6a701db1baa83 Mon Sep 17 00:00:00 2001 From: Zan Dobersek Date: Thu, 15 Jan 2026 09:50:36 +0100 Subject: [PATCH] tu: avoid incorrect pipeline draw state for disabled depth/stencil attachments Pipeline creation can generate draw state that will, depending on creation state, assume enabled depth and stencil attachments. Later on, the pipeline can be used in a render pass that disables those attachments, while the draw state will still be emitting as if those attachments are present and usable. Specifically, this affects pairings of depth attachments and TU_DYNAMIC_STATE_RB_DEPTH_CNTL, and of stencil attachments and TU_DYNAMIC_STATE_DS. When a pipeline is bound, ignore its set depth/stencil state if that state was enabled and the pipeline is either bound outside of a render pass or inside a render pass that disables the relevant attachment. This way the depth/stencil state will be treated as dynamic and will be recomputed and emitted during the draw state emission, taking into account the available attachments inside the render pass. Fixes: dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil Signed-off-by: Zan Dobersek Part-of: --- src/freedreno/ci/freedreno-a618-fails.txt | 2 -- src/freedreno/ci/freedreno-a660-fails.txt | 3 --- src/freedreno/ci/freedreno-a750-fails.txt | 1 - src/freedreno/vulkan/tu_cmd_buffer.cc | 23 +++++++++++++++++------ src/freedreno/vulkan/tu_pipeline.cc | 9 +++++++++ 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/freedreno/ci/freedreno-a618-fails.txt b/src/freedreno/ci/freedreno-a618-fails.txt index db3973de6d1..fdf5e76a2b2 100644 --- a/src/freedreno/ci/freedreno-a618-fails.txt +++ b/src/freedreno/ci/freedreno-a618-fails.txt @@ -300,7 +300,6 @@ dEQP-VK.renderpasses.dynamic_rendering.partial_secondary_cmd_buff.fragment_densi dEQP-VK.renderpasses.dynamic_rendering.partial_secondary_cmd_buff.fragment_density_map.offset.oversized_fdm.vert_offset_negative,Fail dEQP-VK.renderpasses.dynamic_rendering.partial_secondary_cmd_buff.fragment_density_map.offset.oversized_fdm.vert_offset_negative_suspend_resume_extra_large,Fail dEQP-VK.renderpasses.dynamic_rendering.partial_secondary_cmd_buff.fragment_density_map.offset.oversized_fdm.vert_offset_negative_suspend_resume,Fail -dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.fragment_density_map.offset.clamp_to_edge.hor_offset_negative,Fail dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.fragment_density_map.offset.clamp_to_edge.hor_offset_negative_multiview,Fail dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.fragment_density_map.offset.clamp_to_edge.hor_offset_negative_multiview_suspend_resume,Fail @@ -341,7 +340,6 @@ dEQP-VK.renderpasses.renderpass2.fragment_density_map.offset.oversized_fdm.hor_o dEQP-VK.renderpasses.renderpass2.fragment_density_map.offset.oversized_fdm.vert_offset_negative_extra_large,Fail dEQP-VK.renderpasses.renderpass2.fragment_density_map.offset.oversized_fdm.vert_offset_negative,Fail dEQP-VK.tessellation.misc_draw.tess_factor_barrier_bug,Crash -bypass-dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail gmem-dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency_and_usage,Fail gmem-dEQP-VK.renderpasses.dynamic_rendering.complete_secondary_cmd_buff.fragment_density_map.offset.clamp_to_edge.vert_offset_negative,Fail gmem-dEQP-VK.renderpasses.dynamic_rendering.complete_secondary_cmd_buff.fragment_density_map.offset.oversized_fdm.vert_offset_negative_suspend_resume,Fail diff --git a/src/freedreno/ci/freedreno-a660-fails.txt b/src/freedreno/ci/freedreno-a660-fails.txt index 4b96e7fdd06..96367a60fbb 100644 --- a/src/freedreno/ci/freedreno-a660-fails.txt +++ b/src/freedreno/ci/freedreno-a660-fails.txt @@ -47,10 +47,7 @@ nobin-dEQP-VK.transform_feedback.simple.draw_indirect_multiview_counter_offset_1 dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency_and_usage,Fail dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency,Fail dEQP-VK.pipeline.monolithic.misc.identically_defined_layout,Fail -dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail dEQP-VK.tessellation.misc_draw.tess_factor_barrier_bug,Crash -bypass-dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail -gmem-dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail gmem-dEQP-VK.transform_feedback.simple.draw_indirect_counter_offset_16,Fail gmem-dEQP-VK.transform_feedback.simple.draw_indirect_multiview_counter_offset_508,Fail gmem-dEQP-VK.transform_feedback.simple_fast_gpl.draw_indirect_counter_offset_244,Fail diff --git a/src/freedreno/ci/freedreno-a750-fails.txt b/src/freedreno/ci/freedreno-a750-fails.txt index 30bb5758c80..47978471174 100644 --- a/src/freedreno/ci/freedreno-a750-fails.txt +++ b/src/freedreno/ci/freedreno-a750-fails.txt @@ -32,7 +32,6 @@ dynamic-dEQP-VK.renderpass2.depth_stencil_resolve.image_2d_32_32.samples_2.d32_s dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency_and_usage,Fail dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency,Fail dEQP-VK.pipeline.monolithic.misc.identically_defined_layout,Fail -dEQP-VK.renderpasses.dynamic_rendering.primary_cmd_buff.basic.partial_binding_depth_stencil,Fail gmem-dEQP-VK.binding_model.descriptor_buffer.traditional_buffer.capture_replay.sparse_buffer_descriptor_data_consistency_and_usage,Fail diff --git a/src/freedreno/vulkan/tu_cmd_buffer.cc b/src/freedreno/vulkan/tu_cmd_buffer.cc index 4ef66a0dfd4..9541da96060 100644 --- a/src/freedreno/vulkan/tu_cmd_buffer.cc +++ b/src/freedreno/vulkan/tu_cmd_buffer.cc @@ -5575,15 +5575,26 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer, cmd->state.bandwidth = pipeline->bandwidth; cmd->state.pipeline_bandwidth = pipeline->bandwidth.valid; - struct tu_cs *cs = &cmd->draw_cs; + /* Ignore pipeline's enabled depth/stencil state if render pass doesn't provide + * depth/stencil attachments, or if pipeline was bound outside of renderpass. + * That way the correct state can be computed based on the presence of the + * relevant attachments. + */ + uint32_t set_state_mask = pipeline->set_state_mask; + if (cmd->vk.dynamic_graphics_state.ds.depth.test_enable && + (!cmd->state.pass || !(cmd->state.vk_rp.attachments & MESA_VK_RP_ATTACHMENT_DEPTH_BIT))) + set_state_mask &= ~(1u << TU_DYNAMIC_STATE_RB_DEPTH_CNTL); + if (cmd->vk.dynamic_graphics_state.ds.stencil.test_enable && + (!cmd->state.pass || !(cmd->state.vk_rp.attachments & MESA_VK_RP_ATTACHMENT_STENCIL_BIT))) + set_state_mask &= ~(1u << TU_DYNAMIC_STATE_DS); /* note: this also avoids emitting draw states before renderpass clears, * which may use the 3D clear path (for MSAA cases) */ if (!(cmd->state.dirty & TU_CMD_DIRTY_DRAW_STATE)) { - uint32_t mask = pipeline->set_state_mask; + struct tu_cs *cs = &cmd->draw_cs; - tu_cs_emit_pkt7(cs, CP_SET_DRAW_STATE, 3 * (10 + util_bitcount(mask))); + tu_cs_emit_pkt7(cs, CP_SET_DRAW_STATE, 3 * (10 + util_bitcount(set_state_mask))); tu_cs_emit_draw_state(cs, TU_DRAW_STATE_PROGRAM_CONFIG, pipeline->program.config_state); tu_cs_emit_draw_state(cs, TU_DRAW_STATE_VS, pipeline->program.vs_state); tu_cs_emit_draw_state(cs, TU_DRAW_STATE_VS_BINNING, pipeline->program.vs_binning_state); @@ -5595,12 +5606,12 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer, tu_cs_emit_draw_state(cs, TU_DRAW_STATE_VPC, pipeline->program.vpc_state); tu_cs_emit_draw_state(cs, TU_DRAW_STATE_PRIM_MODE_GMEM, pipeline->prim_order.state_gmem); - u_foreach_bit(i, mask) + u_foreach_bit(i, set_state_mask) tu_cs_emit_draw_state(cs, TU_DRAW_STATE_DYNAMIC + i, pipeline->dynamic_state[i]); } - cmd->state.pipeline_draw_states = pipeline->set_state_mask; - u_foreach_bit(i, pipeline->set_state_mask) + cmd->state.pipeline_draw_states = set_state_mask; + u_foreach_bit(i, set_state_mask) cmd->state.dynamic_state[i] = pipeline->dynamic_state[i]; if (pipeline->shaders[MESA_SHADER_FRAGMENT]->fs.has_fdm != diff --git a/src/freedreno/vulkan/tu_pipeline.cc b/src/freedreno/vulkan/tu_pipeline.cc index 89d2f27a816..d9ac10dd9b2 100644 --- a/src/freedreno/vulkan/tu_pipeline.cc +++ b/src/freedreno/vulkan/tu_pipeline.cc @@ -4045,6 +4045,15 @@ tu_pipeline_builder_emit_state(struct tu_pipeline_builder *builder, /* Vertex buffer state needs to know the max valid binding */ BITSET_SET(keep, MESA_VK_DYNAMIC_VI_BINDINGS_VALID); + /* We might re-emit TU_DYNAMIC_STATE_DS or TU_DYNAMIC_STATE_RB_DEPTH_CNTL + * depending on render pass attachments. Some of these overlap with the + * state needed by LRZ above. + */ + for (unsigned i = 0; i < ARRAY_SIZE(tu_ds_state); i++) + BITSET_SET(keep, tu_ds_state[i]); + for (unsigned i = 0; i < ARRAY_SIZE(tu_rb_depth_cntl_state); i++) + BITSET_SET(keep, tu_rb_depth_cntl_state[i]); + /* Remove state which has been emitted and we no longer need to set when * binding the pipeline by making it "dynamic". */