v3dv: implement dynamic stencil states
authorIago Toral Quiroga <itoral@igalia.com>
Tue, 4 Feb 2020 16:43:49 +0000 (17:43 +0100)
committerMarge Bot <eric+marge@anholt.net>
Tue, 13 Oct 2020 21:21:27 +0000 (21:21 +0000)
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6766>

src/broadcom/vulkan/v3dv_cmd_buffer.c
src/broadcom/vulkan/v3dv_pipeline.c
src/broadcom/vulkan/v3dv_private.h

index cda9254..52ccb1c 100644 (file)
@@ -33,6 +33,21 @@ const struct v3dv_dynamic_state default_dynamic_state = {
    .scissor = {
       .count = 0,
    },
+   .stencil_compare_mask =
+   {
+     .front = ~0u,
+     .back = ~0u,
+   },
+   .stencil_write_mask =
+   {
+     .front = ~0u,
+     .back = ~0u,
+   },
+   .stencil_reference =
+   {
+     .front = 0u,
+     .back = 0u,
+   },
 };
 
 void
@@ -1412,6 +1427,30 @@ bind_dynamic_state(struct v3dv_cmd_buffer *cmd_buffer,
       }
    }
 
+   if (copy_mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK) {
+      if (memcmp(&dest->stencil_compare_mask, &src->stencil_compare_mask,
+                 sizeof(src->stencil_compare_mask))) {
+         dest->stencil_compare_mask = src->stencil_compare_mask;
+         dest_mask |= V3DV_DYNAMIC_STENCIL_COMPARE_MASK;
+      }
+   }
+
+   if (copy_mask & V3DV_DYNAMIC_STENCIL_WRITE_MASK) {
+      if (memcmp(&dest->stencil_write_mask, &src->stencil_write_mask,
+                 sizeof(src->stencil_write_mask))) {
+         dest->stencil_write_mask = src->stencil_write_mask;
+         dest_mask |= V3DV_DYNAMIC_STENCIL_WRITE_MASK;
+      }
+   }
+
+   if (copy_mask & V3DV_DYNAMIC_STENCIL_REFERENCE) {
+      if (memcmp(&dest->stencil_reference, &src->stencil_reference,
+                 sizeof(src->stencil_reference))) {
+         dest->stencil_reference = src->stencil_reference;
+         dest_mask |= V3DV_DYNAMIC_STENCIL_REFERENCE;
+      }
+   }
+
    cmd_buffer->state.dirty |= dest_mask;
 }
 
@@ -1687,6 +1726,51 @@ emit_viewport(struct v3dv_cmd_buffer *cmd_buffer)
 }
 
 static void
+emit_stencil(struct v3dv_cmd_buffer *cmd_buffer)
+{
+   struct v3dv_job *job = cmd_buffer->state.job;
+   assert(job);
+
+   struct v3dv_pipeline *pipeline = cmd_buffer->state.pipeline;
+   struct v3dv_dynamic_state *dynamic_state = &cmd_buffer->state.dynamic;
+
+   const uint32_t dynamic_stencil_states = V3DV_DYNAMIC_STENCIL_COMPARE_MASK |
+                                           V3DV_DYNAMIC_STENCIL_WRITE_MASK |
+                                           V3DV_DYNAMIC_STENCIL_REFERENCE;
+
+   for (uint32_t i = 0; i < 2; i++) {
+      if (pipeline->emit_stencil_cfg[i]) {
+         /* Our dynamic state bits signal whether a particular state is
+          * taken from the static pipeline definition (so it is not dynamic).
+          */
+         if (!(dynamic_state->mask & dynamic_stencil_states)) {
+            /* At least one of the stencil states is dynamic */
+            cl_emit_with_prepacked(&job->bcl, STENCIL_CFG,
+                                   pipeline->stencil_cfg[i], config) {
+               if (!(dynamic_state->mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK)) {
+                  config.stencil_test_mask =
+                     i == 0 ? dynamic_state->stencil_compare_mask.front :
+                              dynamic_state->stencil_compare_mask.back;
+               }
+               if (!(dynamic_state->mask & V3DV_DYNAMIC_STENCIL_WRITE_MASK)) {
+                  config.stencil_write_mask =
+                     i == 0 ? dynamic_state->stencil_write_mask.front :
+                              dynamic_state->stencil_write_mask.back;
+               }
+               if (!(dynamic_state->mask & V3DV_DYNAMIC_STENCIL_REFERENCE)) {
+                  config.stencil_ref_value =
+                     i == 0 ? dynamic_state->stencil_reference.front :
+                              dynamic_state->stencil_reference.back;
+               }
+            }
+         } else {
+            cl_emit_prepacked(&job->bcl, &pipeline->stencil_cfg[i]);
+         }
+      }
+   }
+}
+
+static void
 cmd_buffer_emit_graphics_pipeline(struct v3dv_cmd_buffer *cmd_buffer)
 {
    struct v3dv_job *job = cmd_buffer->state.job;
@@ -1821,11 +1905,7 @@ cmd_buffer_emit_graphics_pipeline(struct v3dv_cmd_buffer *cmd_buffer)
       config.early_z_updates_enable = job->ez_state != VC5_EZ_DISABLED;
    }
 
-   if (pipeline->emit_stencil_cfg[0]) {
-      cl_emit_prepacked(&job->bcl, &pipeline->stencil_cfg[0]);
-      if (pipeline->emit_stencil_cfg[1])
-         cl_emit_prepacked(&job->bcl, &pipeline->stencil_cfg[1]);
-   }
+   emit_stencil(cmd_buffer);
 
    /* FIXME: hardcoded values */
    cl_emit(&job->bcl, ZERO_ALL_FLAT_SHADE_FLAGS, flags);
@@ -1980,3 +2060,48 @@ v3dv_CmdBindVertexBuffers(VkCommandBuffer commandBuffer,
 
    cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_VERTEX_BUFFER;
 }
+
+void
+v3dv_CmdSetStencilCompareMask(VkCommandBuffer commandBuffer,
+                              VkStencilFaceFlags faceMask,
+                              uint32_t compareMask)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+
+   if (faceMask & VK_STENCIL_FACE_FRONT_BIT)
+      cmd_buffer->state.dynamic.stencil_compare_mask.front = compareMask & 0xff;
+   if (faceMask & VK_STENCIL_FACE_BACK_BIT)
+      cmd_buffer->state.dynamic.stencil_compare_mask.back = compareMask & 0xff;
+
+   cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK;
+}
+
+void
+v3dv_CmdSetStencilWriteMask(VkCommandBuffer commandBuffer,
+                            VkStencilFaceFlags faceMask,
+                            uint32_t writeMask)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+
+   if (faceMask & VK_STENCIL_FACE_FRONT_BIT)
+      cmd_buffer->state.dynamic.stencil_write_mask.front = writeMask & 0xff;
+   if (faceMask & VK_STENCIL_FACE_BACK_BIT)
+      cmd_buffer->state.dynamic.stencil_write_mask.back = writeMask & 0xff;
+
+   cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DYNAMIC_STENCIL_WRITE_MASK;
+}
+
+void
+v3dv_CmdSetStencilReference(VkCommandBuffer commandBuffer,
+                            VkStencilFaceFlags faceMask,
+                            uint32_t reference)
+{
+   V3DV_FROM_HANDLE(v3dv_cmd_buffer, cmd_buffer, commandBuffer);
+
+   if (faceMask & VK_STENCIL_FACE_FRONT_BIT)
+      cmd_buffer->state.dynamic.stencil_reference.front = reference & 0xff;
+   if (faceMask & VK_STENCIL_FACE_BACK_BIT)
+      cmd_buffer->state.dynamic.stencil_reference.back = reference & 0xff;
+
+   cmd_buffer->state.dirty |= V3DV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE;
+}
index 3f0dc07..069ca7f 100644 (file)
@@ -870,6 +870,12 @@ v3dv_dynamic_state_mask(VkDynamicState state)
       return V3DV_DYNAMIC_VIEWPORT;
    case VK_DYNAMIC_STATE_SCISSOR:
       return V3DV_DYNAMIC_SCISSOR;
+   case VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK:
+      return V3DV_DYNAMIC_STENCIL_COMPARE_MASK;
+   case VK_DYNAMIC_STATE_STENCIL_WRITE_MASK:
+      return V3DV_DYNAMIC_STENCIL_WRITE_MASK;
+   case VK_DYNAMIC_STATE_STENCIL_REFERENCE:
+      return V3DV_DYNAMIC_STENCIL_REFERENCE;
    default:
       unreachable("Unhandled dynamic state");
    }
@@ -936,6 +942,27 @@ pipeline_init_dynamic_state(struct v3dv_pipeline *pipeline,
       }
    }
 
+   if (needed_states & V3DV_DYNAMIC_STENCIL_COMPARE_MASK) {
+      dynamic->stencil_compare_mask.front =
+         pCreateInfo->pDepthStencilState->front.compareMask;
+      dynamic->stencil_compare_mask.back =
+         pCreateInfo->pDepthStencilState->back.compareMask;
+   }
+
+   if (needed_states & V3DV_DYNAMIC_STENCIL_WRITE_MASK) {
+      dynamic->stencil_write_mask.front =
+         pCreateInfo->pDepthStencilState->front.writeMask;
+      dynamic->stencil_write_mask.back =
+         pCreateInfo->pDepthStencilState->back.writeMask;
+   }
+
+   if (needed_states & V3DV_DYNAMIC_STENCIL_REFERENCE) {
+      dynamic->stencil_reference.front =
+         pCreateInfo->pDepthStencilState->front.reference;
+      dynamic->stencil_reference.back =
+         pCreateInfo->pDepthStencilState->back.reference;
+   }
+
    pipeline->dynamic_state.mask = states;
 }
 
@@ -1022,7 +1049,8 @@ translate_stencil_op(enum pipe_stencil_op op)
 }
 
 static void
-pack_single_stencil_cfg(uint8_t *stencil_cfg,
+pack_single_stencil_cfg(struct v3dv_pipeline *pipeline,
+                        uint8_t *stencil_cfg,
                         bool is_front,
                         bool is_back,
                         const VkStencilOpState *stencil_state)
@@ -1037,10 +1065,22 @@ pack_single_stencil_cfg(uint8_t *stencil_cfg,
     *
     * In our case, 's' is always 8, so we clamp to that to prevent our packing
     * functions to assert in debug mode if they see larger values.
+    *
+    * If we have dynamic state we need to make sure we set the corresponding
+    * state bits to 0, since cl_emit_with_prepacked ORs the new value with
+    * the old.
     */
-   const uint8_t write_mask = stencil_state->writeMask & 0xff;
-   const uint8_t compare_mask = stencil_state->compareMask & 0xff;
-   const uint8_t reference = stencil_state->reference & 0xff;
+   const uint8_t write_mask =
+      pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_WRITE_MASK ?
+         stencil_state->writeMask & 0xff : 0;
+
+   const uint8_t compare_mask =
+      pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK ?
+         stencil_state->compareMask & 0xff : 0;
+
+   const uint8_t reference =
+      pipeline->dynamic_state.mask & V3DV_DYNAMIC_STENCIL_COMPARE_MASK ?
+         stencil_state->reference & 0xff : 0;
 
    v3dv_pack(stencil_cfg, STENCIL_CFG, config) {
       config.front_config = is_front;
@@ -1064,18 +1104,31 @@ pack_stencil_cfg(struct v3dv_pipeline *pipeline,
    if (!ds_info || !ds_info->stencilTestEnable)
       return;
 
+   const uint32_t dynamic_stencil_states = V3DV_DYNAMIC_STENCIL_COMPARE_MASK |
+                                           V3DV_DYNAMIC_STENCIL_WRITE_MASK |
+                                           V3DV_DYNAMIC_STENCIL_REFERENCE;
+
+
+   /* If front != back or we have dynamic stencil state we can't emit a single
+    * packet for both faces.
+    */
+   bool needs_front_and_back = false;
+   if (!(pipeline->dynamic_state.mask & dynamic_stencil_states) ||
+       memcmp(&ds_info->front, &ds_info->back, sizeof(ds_info->front)))
+      needs_front_and_back = true;
+
    /* If the front and back configurations are the same we can emit both with
     * a single packet.
     */
    pipeline->emit_stencil_cfg[0] = true;
-   if (memcmp(&ds_info->front, &ds_info->back, sizeof(ds_info->front)) == 0) {
-      pack_single_stencil_cfg(pipeline->stencil_cfg[0],
+   if (!needs_front_and_back) {
+      pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[0],
                               true, true, &ds_info->front);
    } else {
       pipeline->emit_stencil_cfg[1] = true;
-      pack_single_stencil_cfg(pipeline->stencil_cfg[0],
+      pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[0],
                               true, false, &ds_info->front);
-      pack_single_stencil_cfg(pipeline->stencil_cfg[1],
+      pack_single_stencil_cfg(pipeline, pipeline->stencil_cfg[1],
                               false, true, &ds_info->back);
    }
 }
index f5f63c2..9b1a607 100644 (file)
@@ -434,7 +434,10 @@ struct v3dv_scissor_state {
 enum v3dv_dynamic_state_bits {
    V3DV_DYNAMIC_VIEWPORT                  = 1 << 0,
    V3DV_DYNAMIC_SCISSOR                   = 1 << 1,
-   V3DV_DYNAMIC_ALL                       = (1 << 2) - 1,
+   V3DV_DYNAMIC_STENCIL_COMPARE_MASK      = 1 << 2,
+   V3DV_DYNAMIC_STENCIL_WRITE_MASK        = 1 << 3,
+   V3DV_DYNAMIC_STENCIL_REFERENCE         = 1 << 4,
+   V3DV_DYNAMIC_ALL                       = (1 << 5) - 1,
 };
 
 /* To track which cmd buffer elements are "dirty" so would need an
@@ -444,9 +447,13 @@ enum v3dv_dynamic_state_bits {
 enum v3dv_cmd_dirty_bits {
    V3DV_CMD_DIRTY_DYNAMIC_VIEWPORT                  = 1 << 0,
    V3DV_CMD_DIRTY_DYNAMIC_SCISSOR                   = 1 << 1,
-   V3DV_CMD_DIRTY_DYNAMIC_ALL                       = (1 << 2) - 1,
-   V3DV_CMD_DIRTY_PIPELINE                          = 1 << 2,
-   V3DV_CMD_DIRTY_VERTEX_BUFFER                     = 1 << 3,
+   V3DV_CMD_DIRTY_DYNAMIC_STENCIL_COMPARE_MASK      = 1 << 2,
+   V3DV_CMD_DIRTY_DYNAMIC_STENCIL_WRITE_MASK        = 1 << 3,
+   V3DV_CMD_DIRTY_DYNAMIC_STENCIL_REFERENCE         = 1 << 4,
+   V3DV_CMD_DIRTY_DYNAMIC_ALL                       = (1 << 5) - 1,
+
+   V3DV_CMD_DIRTY_PIPELINE                          = 1 << 5,
+   V3DV_CMD_DIRTY_VERTEX_BUFFER                     = 1 << 6,
 };
 
 
@@ -460,6 +467,21 @@ struct v3dv_dynamic_state {
    struct v3dv_viewport_state viewport;
 
    struct v3dv_scissor_state scissor;
+
+   struct {
+      uint32_t front;
+      uint32_t back;
+   } stencil_compare_mask;
+
+   struct {
+      uint32_t front;
+      uint32_t back;
+   } stencil_write_mask;
+
+   struct {
+      uint32_t front;
+      uint32_t back;
+   } stencil_reference;
 };
 
 extern const struct v3dv_dynamic_state default_dynamic_state;