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 <mary@mary.zone>
Fixes: 2fb4aed9 ("nvk: Advertise VK_KHR_fragment_shading_rate")
Reviewed-by: Mel Henning <mhenning@darkrefraction.com>
(cherry picked from commit d00965651a)

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/40752>
This commit is contained in:
Mary Guillemard 2026-03-13 17:19:27 +01:00 committed by Eric Engestrom
parent fbebd62932
commit cb9c75e2ca
2 changed files with 34 additions and 10 deletions

View file

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

View file

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