From d00965651a4e22ba75d30464325a2c35d6bbe5e8 Mon Sep 17 00:00:00 2001 From: Mary Guillemard Date: Fri, 13 Mar 2026 17:19:27 +0100 Subject: [PATCH] nvk: Broacast viewport0 and scissor0 in case of FSR on Turing On Turing, the hardware rely on the viewport index for FSR. If not all viewports are defined, we will end up not rendering anything when selecting the primitive shading rate. This patch makes it that we now broadcast the viewport and scissor 0 likes the proprietary driver. This fixes "dEQP-VK.mesh_shader.ext.builtin.primitive_shading_rate_*" on Turing. Signed-off-by: Mary Guillemard Fixes: 2fb4aed9 ("nvk: Advertise VK_KHR_fragment_shading_rate") Reviewed-by: Mel Henning Part-of: --- src/nouveau/vulkan/nvk_cmd_draw.c | 42 ++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/src/nouveau/vulkan/nvk_cmd_draw.c b/src/nouveau/vulkan/nvk_cmd_draw.c index ac889bb7b4f..ed81e6bd4c3 100644 --- a/src/nouveau/vulkan/nvk_cmd_draw.c +++ b/src/nouveau/vulkan/nvk_cmd_draw.c @@ -2490,16 +2490,40 @@ nvk_flush_vp_state(struct nvk_cmd_buffer *cmd) const struct vk_dynamic_graphics_state *dyn = &cmd->vk.dynamic_graphics_state; + /* From the Vulkan 1.4.341 spec: + * + * "If the pipeline requires pre-rasterization shader state and the + * primitiveFragmentShadingRateWithMultipleViewports limit is not + * supported VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT is not included in + * pDynamicState->pDynamicStates, and + * VkPipelineViewportStateCreateInfo::viewportCount is greater than 1, + * entry points specified in pStages must not write to the + * PrimitiveShadingRateKHR built-in" + * + * This means that, in Turing case of FSR, we expect only one viewport to be + * present. Therefore, to handle FSR, we need to replicate viewport and + * scissor 0. + */ + const bool vp_broadcast_dirty = BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_FSR) && + nvk_cmd_buffer_3d_cls(cmd) == TURING_A; + const bool need_turing_vp_broadcast = nvk_cmd_buffer_3d_cls(cmd) == TURING_A && + !vk_fragment_shading_rate_is_disabled(&dyn->fsr); + const uint8_t viewport_count = need_turing_vp_broadcast ? NVK_MAX_VIEWPORTS : + dyn->vp.viewport_count; + const uint8_t scissor_count = need_turing_vp_broadcast ? NVK_MAX_VIEWPORTS : + dyn->vp.scissor_count; + struct nv_push *p = - nvk_cmd_buffer_push(cmd, 18 * dyn->vp.viewport_count + 4 * NVK_MAX_VIEWPORTS); + nvk_cmd_buffer_push(cmd, 18 * viewport_count + 4 * NVK_MAX_VIEWPORTS); /* Nothing to do for MESA_VK_DYNAMIC_VP_VIEWPORT_COUNT */ if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_VIEWPORTS) || BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE) || - BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_DEPTH_CLAMP_RANGE)) { - for (uint32_t i = 0; i < dyn->vp.viewport_count; i++) { - const VkViewport *vp = &dyn->vp.viewports[i]; + BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_DEPTH_CLAMP_RANGE) || + vp_broadcast_dirty) { + for (uint32_t i = 0; i < viewport_count; i++) { + const VkViewport *vp = &dyn->vp.viewports[need_turing_vp_broadcast ? 0 : i]; nvk_emit_viewport(cmd, p, vp, i); } } @@ -2511,14 +2535,14 @@ nvk_flush_vp_state(struct nvk_cmd_buffer *cmd) RANGE_ZERO_TO_POSITIVE_W); } - if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSOR_COUNT)) { - for (unsigned i = dyn->vp.scissor_count; i < NVK_MAX_VIEWPORTS; i++) + if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSOR_COUNT) || vp_broadcast_dirty) { + for (unsigned i = scissor_count; i < NVK_MAX_VIEWPORTS; i++) P_IMMD(p, NV9097, SET_SCISSOR_ENABLE(i), V_FALSE); } - if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSORS)) { - for (unsigned i = 0; i < dyn->vp.scissor_count; i++) { - const VkRect2D *s = &dyn->vp.scissors[i]; + if (BITSET_TEST(dyn->dirty, MESA_VK_DYNAMIC_VP_SCISSORS) || vp_broadcast_dirty) { + for (unsigned i = 0; i < scissor_count; i++) { + const VkRect2D *s = &dyn->vp.scissors[need_turing_vp_broadcast ? 0 : i]; nvk_emit_scissor(cmd, p, s, i); } }