From cb9c75e2caebd493fce819dd78cc512cece3e1da 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 (cherry picked from commit d00965651a4e22ba75d30464325a2c35d6bbe5e8) Part-of: --- .pick_status.json | 2 +- src/nouveau/vulkan/nvk_cmd_draw.c | 42 ++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 14d2a5fa212..fb816c88a41 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -6264,7 +6264,7 @@ "description": "nvk: Broacast viewport0 and scissor0 in case of FSR on Turing", "nominated": true, "nomination_type": 2, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": "2fb4aed9d8b51b741fde7bb6a9c8c263a7be5fdd", "notes": null diff --git a/src/nouveau/vulkan/nvk_cmd_draw.c b/src/nouveau/vulkan/nvk_cmd_draw.c index 8e7c034a77f..6b384e135f3 100644 --- a/src/nouveau/vulkan/nvk_cmd_draw.c +++ b/src/nouveau/vulkan/nvk_cmd_draw.c @@ -2122,16 +2122,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); } } @@ -2143,14 +2167,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); } }