v3dv/cmd_buffer: emit Scissor packets
authorAlejandro Piñeiro <apinheiro@igalia.com>
Sat, 28 Dec 2019 10:42:53 +0000 (11:42 +0100)
committerMarge Bot <eric+marge@anholt.net>
Tue, 13 Oct 2020 21:21:26 +0000 (21:21 +0000)
As this is done as part of CmdDraw, we also add the initial stub of
such function here

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>

src/broadcom/vulkan/v3dv_cmd_buffer.c

index b82b1ff..852c51b 100644 (file)
@@ -413,13 +413,25 @@ v3dv_CmdBeginRenderPass(VkCommandBuffer commandBuffer,
     */
    cl_emit(&cmd_buffer->bcl, START_TILE_BINNING, bin);
 
-   /* FIXME: might want to merge actual scissor rect here if possible */
    /* FIXME: probably need to align the render area to tile boundaries since
     *        the tile clears will render full tiles anyway.
     *        See vkGetRenderAreaGranularity().
     */
    state->render_area = pRenderPassBegin->renderArea;
-   emit_clip_window(cmd_buffer, &state->render_area);
+
+   /* If we don't have a scissor or viewport defined let's just use the render
+    * area as clip_window, as that would be required for a clear in any
+    * case. If we have that, it would be emitted as part of the pipeline
+    * dynamic state flush
+    *
+    * FIXME: this is mostly just needed for clear. radv has dedicated paths
+    * for them, so we could get that idea. In any case, need to revisit if
+    * this is the place to emit the clip window.
+    */
+   if (cmd_buffer->state.dynamic.scissor.count == 0 &&
+       cmd_buffer->state.dynamic.viewport.count == 0) {
+      emit_clip_window(cmd_buffer, &state->render_area);
+   }
 
    /* Setup for first subpass */
    state->subpass_idx = 0;
@@ -1020,3 +1032,110 @@ v3dv_CmdSetScissor(VkCommandBuffer commandBuffer,
 
    cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DYNAMIC_SCISSOR;
 }
+
+
+/* FIXME: C&P from radv. tu has similar code. Perhaps common place? */
+static void
+get_viewport_xform(const VkViewport *viewport,
+                   float scale[3],
+                   float translate[3])
+{
+   float x = viewport->x;
+   float y = viewport->y;
+   float half_width = 0.5f * viewport->width;
+   float half_height = 0.5f * viewport->height;
+   double n = viewport->minDepth;
+   double f = viewport->maxDepth;
+
+   scale[0] = half_width;
+   translate[0] = half_width + x;
+   scale[1] = half_height;
+   translate[1] = half_height + y;
+
+   scale[2] = (f - n);
+   translate[2] = n;
+}
+
+static void
+emit_scissor(struct v3dv_cmd_buffer *cmd_buffer)
+{
+   struct v3dv_dynamic_state *dynamic = &cmd_buffer->state.dynamic;
+   float vptranslate[3];
+   float vpscale[3];
+
+   /* FIXME: right now we only support one viewport. viewporst[0] would work
+    * now, but would need to change if we allow multiple viewports.
+    */
+   get_viewport_xform(&dynamic->viewport.viewports[0],
+                      vpscale, vptranslate);
+
+   float vp_minx = -fabsf(vpscale[0]) + vptranslate[0];
+   float vp_maxx = fabsf(vpscale[0]) + vptranslate[0];
+   float vp_miny = -fabsf(vpscale[1]) + vptranslate[1];
+   float vp_maxy = fabsf(vpscale[1]) + vptranslate[1];
+
+   /* Quoting from v3dx_emit:
+    * "Clip to the scissor if it's enabled, but still clip to the
+    * drawable regardless since that controls where the binner
+    * tries to put things.
+    *
+    * Additionally, always clip the rendering to the viewport,
+    * since the hardware does guardband clipping, meaning
+    * primitives would rasterize outside of the view volume."
+    */
+
+   VkRect2D clip_window;
+   uint32_t minx, miny, maxx, maxy;
+   if (dynamic->scissor.count == 0) {
+      minx = MAX2(vp_minx, 0);
+      miny = MAX2(vp_miny, 0);
+      maxx = MIN2(vp_maxx, cmd_buffer->state.render_area.extent.width);
+      maxy = MIN2(vp_maxy, cmd_buffer->state.render_area.extent.height);
+   } else {
+      /* FIXME: right now we only allow one scissor. Below would need to be
+       * updated if we support more
+       */
+      VkRect2D *scissor = &dynamic->scissor.scissors[0];
+
+      minx = MAX2(vp_minx, scissor->offset.x);
+      miny = MAX2(vp_miny, scissor->offset.y);
+      maxx = MIN2(vp_maxx, scissor->offset.x + scissor->extent.width);
+      maxy = MIN2(vp_maxy, scissor->offset.y + scissor->extent.height);
+   }
+
+   clip_window.offset.x = minx;
+   clip_window.offset.y = miny;
+   clip_window.extent.width = maxx - minx;
+   clip_window.extent.height = maxy - miny;
+
+   emit_clip_window(cmd_buffer, &clip_window);
+}
+
+static void
+cmd_buffer_emit_state(struct v3dv_cmd_buffer *cmd_buffer)
+{
+   /* FIXME: likely to be filtered by really needed states */
+   uint32_t states = cmd_buffer->state.dirty;
+   struct v3dv_dynamic_state *dynamic = &cmd_buffer->state.dynamic;
+
+   /* Emit(flush) dynamic state */
+   if (states & (V3DV_CMD_DIRTY_DYNAMIC_VIEWPORT | V3DV_CMD_DIRTY_DYNAMIC_SCISSOR)) {
+      assert(dynamic->scissor.count > 0 || dynamic->viewport.count > 0);
+
+      emit_scissor(cmd_buffer);
+   }
+
+   cmd_buffer->state.dirty &= ~states;
+}
+
+void
+v3dv_CmdDraw(VkCommandBuffer commandBuffer,
+             uint32_t vertexCount,
+             uint32_t instanceCount,
+             uint32_t firstVertex,
+             uint32_t firstInstance)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+
+   cmd_buffer_emit_state(cmd_buffer);
+}