v3dv: use correct number of layers for multiview
authorIago Toral Quiroga <itoral@igalia.com>
Thu, 22 Jul 2021 11:50:16 +0000 (13:50 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 27 Jul 2021 07:31:31 +0000 (07:31 +0000)
The Vulkan spec states that when multiview is enabled the number of
layers in the framebuffer is set to one and that each attachment
must then have at least as many layers as referenced by view masks
in the subpasses in which is used.

Reviewed-by: Alejandro PiƱeiro <apinheiro@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12034>

src/broadcom/vulkan/v3dv_cmd_buffer.c
src/broadcom/vulkan/v3dv_uniforms.c
src/broadcom/vulkan/v3dvx_cmd_buffer.c

index 36cf6eb..194ddc0 100644 (file)
@@ -1504,10 +1504,26 @@ cmd_buffer_subpass_create_job(struct v3dv_cmd_buffer *cmd_buffer,
       v3dv_X(job->device, framebuffer_compute_internal_bpp_msaa)
          (framebuffer, subpass, &internal_bpp, &msaa);
 
+      /* From the Vulkan spec:
+       *
+       *    "If the render pass uses multiview, then layers must be one and
+       *     each attachment requires a number of layers that is greater than
+       *     the maximum bit index set in the view mask in the subpasses in
+       *     which it is used."
+       *
+       * So when multiview is enabled, we take the number of layers from the
+       * last bit set in the view mask.
+       */
+      uint32_t layers = framebuffer->layers;
+      if (subpass->view_mask != 0) {
+         assert(framebuffer->layers == 1);
+         layers = util_last_bit(subpass->view_mask);
+      }
+
       v3dv_job_start_frame(job,
                            framebuffer->width,
                            framebuffer->height,
-                           framebuffer->layers,
+                           layers,
                            true,
                            subpass->color_count,
                            internal_bpp,
index dd91510..bf25e64 100644 (file)
@@ -506,10 +506,23 @@ v3dv_write_uniforms_wg_offsets(struct v3dv_cmd_buffer *cmd_buffer,
        * is only for sanityzing the shader and it only affects the specific case
        * of secondary command buffers without framebuffer info available it
        * might not be worth the trouble.
+       *
+       * With multiview the number of layers is dictated by the view mask
+       * and not by the framebuffer layers. We do set the job's frame tiling
+       * information correctly from the view mask in that case, however,
+       * secondary command buffers may not have valid frame tiling data,
+       * so when multiview is enabled, we always set the number of layers
+       * from the subpass view mask.
        */
       case QUNIFORM_FB_LAYERS: {
+         const struct v3dv_cmd_buffer_state *state = &job->cmd_buffer->state;
+         const uint32_t view_mask =
+            state->pass->subpasses[state->subpass_idx].view_mask;
+
          uint32_t num_layers;
-         if (job->frame_tiling.layers != 0) {
+         if (view_mask != 0) {
+            num_layers = util_last_bit(view_mask);
+         } else if (job->frame_tiling.layers != 0) {
             num_layers = job->frame_tiling.layers;
          } else if (cmd_buffer->state.framebuffer) {
             num_layers = cmd_buffer->state.framebuffer->layers;
index 0f17700..8f8cf73 100644 (file)
@@ -764,7 +764,8 @@ v3dX(cmd_buffer_emit_render_pass_rcl)(struct v3dv_cmd_buffer *cmd_buffer)
 
    const struct v3dv_frame_tiling *tiling = &job->frame_tiling;
 
-   const uint32_t fb_layers = framebuffer->layers;
+   const uint32_t fb_layers = job->frame_tiling.layers;
+
    v3dv_cl_ensure_space_with_branch(&job->rcl, 200 +
                                     MAX2(fb_layers, 1) * 256 *
                                     cl_packet_length(SUPERTILE_COORDINATES));
@@ -948,8 +949,10 @@ v3dX(cmd_buffer_emit_render_pass_rcl)(struct v3dv_cmd_buffer *cmd_buffer)
          TILE_ALLOCATION_BLOCK_SIZE_64B;
    }
 
-   for (int layer = 0; layer < MAX2(1, fb_layers); layer++)
-      cmd_buffer_emit_render_pass_layer_rcl(cmd_buffer, layer);
+   /* FIXME: skip layers not in the view mask */
+   for (int layer = 0; layer < MAX2(1, fb_layers); layer++) {
+         cmd_buffer_emit_render_pass_layer_rcl(cmd_buffer, layer);
+   }
 
    cl_emit(rcl, END_OF_RENDERING, end);
 }