Use dynamic stencil state

This commit is contained in:
nmzik
2026-09-14 16:19:22 +04:00
parent fe26c1de17
commit bce8924dd6
8 changed files with 78 additions and 105 deletions
@@ -71,19 +71,19 @@ static vk::StencilOp ConvertStencilOp(uint8_t value, uint8_t write_mask, uint8_t
}
}
static PipelineStencilStaticState ConvertStencilState(
static vk::StencilOpState ConvertStencilState(
uint8_t compare, const std::array<uint8_t, 3>& operations, uint8_t op_value,
PipelineStencilDynamicState& dynamic) {
const auto test_value = dynamic.reference;
const vk::StencilOpState& state) {
const auto test_value = state.reference;
auto reference = test_value;
auto required_bits = dynamic.compareMask;
auto required_bits = state.compareMask;
if (compare == static_cast<uint8_t>(vk::CompareOp::eAlways) ||
compare == static_cast<uint8_t>(vk::CompareOp::eNever)) {
required_bits = 0;
}
std::array<vk::StencilOp, 3> converted {};
for (size_t i = 0; i < operations.size(); i++) {
converted[i] = ConvertStencilOp(operations[i], dynamic.writeMask, op_value);
converted[i] = ConvertStencilOp(operations[i], state.writeMask, op_value);
if (converted[i] != vk::StencilOp::eReplace) {
continue;
}
@@ -91,18 +91,18 @@ static PipelineStencilStaticState ConvertStencilState(
if (static_cast<Prospero::StencilOp>(operations[i]) == Prospero::StencilOp::kReplaceOp) {
replacement = op_value;
}
if (((reference ^ replacement) & required_bits & dynamic.writeMask) != 0) {
if (((reference ^ replacement) & required_bits & state.writeMask) != 0) {
DepthFatal("unsupported stencil replacement: compare=%u, compare mask=0x%02" PRIx32
", write mask=0x%02" PRIx32 ", operation value=0x%02" PRIx8
", test value=0x%02" PRIx32,
compare, dynamic.compareMask, dynamic.writeMask, op_value, test_value);
compare, state.compareMask, state.writeMask, op_value, test_value);
}
// Vulkan shares one reference between comparison and every replacement on this face.
reference = (reference & ~dynamic.writeMask) | (replacement & dynamic.writeMask);
required_bits |= dynamic.writeMask;
reference = (reference & ~state.writeMask) | (replacement & state.writeMask);
required_bits |= state.writeMask;
}
dynamic.reference = reference;
return {converted[0], converted[1], converted[2], static_cast<vk::CompareOp>(compare)};
return {converted[0], converted[1], converted[2], static_cast<vk::CompareOp>(compare),
state.compareMask, state.writeMask, reference};
}
[[nodiscard]] static vk::Format ResolveHostDepthAttachmentFormat(const CommandBuffer& buffer,
@@ -333,18 +333,17 @@ void RenderExecutor::ResolveRenderDepthTarget(CommandBuffer& buffer, RenderDepth
dc.stencilfunc_bf > static_cast<uint8_t>(vk::CompareOp::eAlways))) {
DepthFatal("unsupported stencil compare state");
}
r.stencil_dynamic_front = {sm.stencil_mask, front_write_mask, sm.stencil_testval};
r.stencil_static_front = ConvertStencilState(
r.stencil_front = ConvertStencilState(
dc.stencilfunc, {sc.stencil_fail, sc.stencil_zpass, sc.stencil_zfail},
sm.stencil_opval, r.stencil_dynamic_front);
sm.stencil_opval, {.compareMask = sm.stencil_mask, .writeMask = front_write_mask,
.reference = sm.stencil_testval});
if (dc.backface_enable) {
r.stencil_dynamic_back = {sm.stencil_mask_bf, back_write_mask, sm.stencil_testval_bf};
r.stencil_static_back = ConvertStencilState(
r.stencil_back = ConvertStencilState(
dc.stencilfunc_bf, {sc.stencil_fail_bf, sc.stencil_zpass_bf, sc.stencil_zfail_bf},
sm.stencil_opval_bf, r.stencil_dynamic_back);
sm.stencil_opval_bf, {.compareMask = sm.stencil_mask_bf, .writeMask = back_write_mask,
.reference = sm.stencil_testval_bf});
} else {
r.stencil_static_back = r.stencil_static_front;
r.stencil_dynamic_back = r.stencil_dynamic_front;
r.stencil_back = r.stencil_front;
}
}
auto& cache = m_context.GetTextureCache();
@@ -430,14 +429,13 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
return writes;
}
const auto face_writes = [&](const PipelineStencilStaticState& state,
const PipelineStencilDynamicState& dynamic) {
if (dynamic.writeMask == 0) {
const auto face_writes = [&](const vk::StencilOpState& state) {
if (state.writeMask == 0) {
return false;
}
bool can_pass = state.compareOp != vk::CompareOp::eNever;
bool can_fail = state.compareOp != vk::CompareOp::eAlways;
if (dynamic.compareMask == 0) {
if (state.compareMask == 0) {
switch (state.compareOp) {
case vk::CompareOp::eEqual:
case vk::CompareOp::eLessOrEqual:
@@ -463,8 +461,7 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
(can_pass && depth_fail && state.depthFailOp != vk::StencilOp::eKeep);
};
if (stencil_clear_enable ||
(stencil_test_enable && (face_writes(stencil_static_front, stencil_dynamic_front) ||
face_writes(stencil_static_back, stencil_dynamic_back)))) {
(stencil_test_enable && (face_writes(stencil_front) || face_writes(stencil_back)))) {
writes |= vk::ImageAspectFlagBits::eStencil;
}
return writes;