.scissor = {
.count = 0,
},
+ .stencil_compare_mask =
+ {
+ .front = ~0u,
+ .back = ~0u,
+ },
+ .stencil_write_mask =
+ {
+ .front = ~0u,
+ .back = ~0u,
+ },
+ .stencil_reference =
+ {
+ .front = 0u,
+ .back = 0u,
+ },
};
void
}
}
+ 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;
}
}
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;
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);
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;
+}
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");
}
}
}
+ 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;
}
}
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)
*
* 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;
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);
}
}
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
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,
};
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;