tu: Split out viewport faking from per-view viewports

For VK_VALVE_fragment_density_map_layered, we need to split out whether
to enable per-view viewports and whether viewport 0 should be splatted
to all viewports. We also have to split this out for
VK_QCOM_multiview_per_view_viewport, where the splatting needs to be
disabled. To avoid conflicts between them, plumb through
"fake_single_viewport" which will be needed for the former extension and
needs to be modified for the latter extension.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35594>
This commit is contained in:
Connor Abbott
2025-01-28 14:37:32 -05:00
committed by Marge Bot
parent c65017f746
commit 5a653d8dd4
4 changed files with 36 additions and 7 deletions
+4 -1
View File
@@ -4491,8 +4491,11 @@ tu_CmdBindPipeline(VkCommandBuffer commandBuffer,
pipeline->shaders[MESA_SHADER_FRAGMENT]->fs.has_fdm;
}
if (pipeline->program.per_view_viewport != cmd->state.per_view_viewport) {
if (pipeline->program.per_view_viewport != cmd->state.per_view_viewport ||
pipeline->program.fake_single_viewport != cmd->state.fake_single_viewport) {
cmd->state.per_view_viewport = pipeline->program.per_view_viewport;
cmd->state.fake_single_viewport =
pipeline->program.fake_single_viewport;
cmd->state.dirty |= TU_CMD_DIRTY_PER_VIEW_VIEWPORT;
}
+10
View File
@@ -289,6 +289,13 @@ struct tu_render_pass_state
bool has_zpass_done_sample_count_write_in_rp;
bool disable_gmem;
bool sysmem_single_prim_mode;
/* This is set if, at any point in the render pass, we were not able to
* duplicate the viewport per-view due to the user using multiple viewports
* and instead we used the state from view 0 to transform each viewport. If
* this happens at any point then all views must contain the same FDM
* fragment size.
*/
bool shared_viewport;
/* Track whether conditional predicate for COND_REG_EXEC is changed in draw_cs */
@@ -447,7 +454,10 @@ struct tu_cmd_state
uint32_t max_vbs_bound;
bool has_fdm;
/* See tu_pipeline::per_view_viewport */
bool per_view_viewport;
/* See tu_pipeline::fake_single_viewport */
bool fake_single_viewport;
/* saved states to re-emit in TU_CMD_DIRTY_DRAW_STATE case */
struct tu_draw_state dynamic_state[TU_DYNAMIC_STATE_COUNT];
+11 -6
View File
@@ -2321,6 +2321,7 @@ tu_emit_program_state(struct tu_cs *sub_cs,
!last_shader->writes_viewport &&
shaders[MESA_SHADER_FRAGMENT]->fs.has_fdm &&
dev->physical_device->info->a6xx.has_per_view_viewport;
prog->fake_single_viewport = prog->per_view_viewport;
prog->writes_shading_rate = last_shader->writes_shading_rate;
prog->reads_shading_rate = fs->reads_shading_rate;
prog->accesses_smask = fs->reads_smask || fs->writes_smask;
@@ -2552,7 +2553,10 @@ tu6_emit_viewport(struct tu_cs *cs,
struct apply_viewport_state {
struct vk_viewport_state vp;
struct vk_rasterization_state rs;
/* See tu_render_pass_state::shared_viewport */
bool share_scale;
/* See tu_pipeline::fake_single_viewport */
bool fake_single_viewport;
};
/* It's a hardware restriction that the window offset (i.e. common_bin_offset)
@@ -2609,15 +2613,14 @@ fdm_apply_viewports(struct tu_cmd_buffer *cmd, struct tu_cs *cs, void *data,
* same across all views, we can pick any view. However the number
* of viewports and number of views is not guaranteed the same, so we
* need to pick the 0'th view which always exists to be safe.
*
* Conversly, if we're not using shared scaling then the rasterizer in
* the original pipeline is using only the first viewport, so we need to
* replicate it across all viewports.
*/
VkExtent2D frag_area = state->share_scale ? frag_areas[0] : frag_areas[i];
VkRect2D bin = state->share_scale ? bins[0] : bins[i];
/* Implement fake_single_viewport by replicating viewport 0 across all
* views.
*/
VkViewport viewport =
state->share_scale ? state->vp.viewports[i] : state->vp.viewports[0];
state->fake_single_viewport ? state->vp.viewports[0] : state->vp.viewports[i];
if (frag_area.width == 1 && frag_area.height == 1 &&
common_bin_offset.x == bin.offset.x &&
common_bin_offset.y == bin.offset.y) {
@@ -2653,6 +2656,7 @@ tu6_emit_viewport_fdm(struct tu_cs *cs, struct tu_cmd_buffer *cmd,
.vp = *vp,
.rs = *rs,
.share_scale = !cmd->state.per_view_viewport,
.fake_single_viewport = cmd->state.fake_single_viewport,
};
if (!state.share_scale)
state.vp.viewport_count = num_views;
@@ -2722,7 +2726,7 @@ fdm_apply_scissors(struct tu_cmd_buffer *cmd, struct tu_cs *cs, void *data,
VkExtent2D frag_area = state->share_scale ? frag_areas[0] : frag_areas[i];
VkRect2D bin = state->share_scale ? bins[0] : bins[i];
VkRect2D scissor =
state->share_scale ? state->vp.scissors[i] : state->vp.scissors[0];
state->fake_single_viewport ? state->vp.scissors[0] : state->vp.scissors[i];
/* Transform the scissor following the viewport. It's unclear how this
* is supposed to handle cases where the scissor isn't aligned to the
@@ -2765,6 +2769,7 @@ tu6_emit_scissor_fdm(struct tu_cs *cs, struct tu_cmd_buffer *cmd,
struct apply_viewport_state state = {
.vp = *vp,
.share_scale = !cmd->state.per_view_viewport,
.fake_single_viewport = cmd->state.fake_single_viewport,
};
if (!state.share_scale)
state.vp.scissor_count = num_views;
+11
View File
@@ -109,7 +109,18 @@ struct tu_program_state
unsigned dynamic_descriptor_offsets[MAX_SETS];
/* Whether the per-view-viewport feature should be enabled in HW. This
* implicitly adds gl_ViewIndex to gl_ViewportIndex so that from a HW
* point of view (but not necessarily the user's point of view!) there
* is a viewport per view.
*/
bool per_view_viewport;
/* If per_view_viewport is true and this is true, the app has provided
* a single viewport and we need to fake it by duplicating the viewport
* across views before transforming each viewport separately using FDM
* state.
*/
bool fake_single_viewport;
bool writes_shading_rate;
bool reads_shading_rate;
bool accesses_smask;