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, uint8_t compare, const std::array<uint8_t, 3>& operations, uint8_t op_value,
PipelineStencilDynamicState& dynamic) { const vk::StencilOpState& state) {
const auto test_value = dynamic.reference; const auto test_value = state.reference;
auto reference = test_value; auto reference = test_value;
auto required_bits = dynamic.compareMask; auto required_bits = state.compareMask;
if (compare == static_cast<uint8_t>(vk::CompareOp::eAlways) || if (compare == static_cast<uint8_t>(vk::CompareOp::eAlways) ||
compare == static_cast<uint8_t>(vk::CompareOp::eNever)) { compare == static_cast<uint8_t>(vk::CompareOp::eNever)) {
required_bits = 0; required_bits = 0;
} }
std::array<vk::StencilOp, 3> converted {}; std::array<vk::StencilOp, 3> converted {};
for (size_t i = 0; i < operations.size(); i++) { 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) { if (converted[i] != vk::StencilOp::eReplace) {
continue; continue;
} }
@@ -91,18 +91,18 @@ static PipelineStencilStaticState ConvertStencilState(
if (static_cast<Prospero::StencilOp>(operations[i]) == Prospero::StencilOp::kReplaceOp) { if (static_cast<Prospero::StencilOp>(operations[i]) == Prospero::StencilOp::kReplaceOp) {
replacement = op_value; 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 DepthFatal("unsupported stencil replacement: compare=%u, compare mask=0x%02" PRIx32
", write mask=0x%02" PRIx32 ", operation value=0x%02" PRIx8 ", write mask=0x%02" PRIx32 ", operation value=0x%02" PRIx8
", test value=0x%02" PRIx32, ", 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. // Vulkan shares one reference between comparison and every replacement on this face.
reference = (reference & ~dynamic.writeMask) | (replacement & dynamic.writeMask); reference = (reference & ~state.writeMask) | (replacement & state.writeMask);
required_bits |= dynamic.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, [[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))) { dc.stencilfunc_bf > static_cast<uint8_t>(vk::CompareOp::eAlways))) {
DepthFatal("unsupported stencil compare state"); DepthFatal("unsupported stencil compare state");
} }
r.stencil_dynamic_front = {sm.stencil_mask, front_write_mask, sm.stencil_testval}; r.stencil_front = ConvertStencilState(
r.stencil_static_front = ConvertStencilState(
dc.stencilfunc, {sc.stencil_fail, sc.stencil_zpass, sc.stencil_zfail}, 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) { if (dc.backface_enable) {
r.stencil_dynamic_back = {sm.stencil_mask_bf, back_write_mask, sm.stencil_testval_bf}; r.stencil_back = ConvertStencilState(
r.stencil_static_back = ConvertStencilState(
dc.stencilfunc_bf, {sc.stencil_fail_bf, sc.stencil_zpass_bf, sc.stencil_zfail_bf}, 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 { } else {
r.stencil_static_back = r.stencil_static_front; r.stencil_back = r.stencil_front;
r.stencil_dynamic_back = r.stencil_dynamic_front;
} }
} }
auto& cache = m_context.GetTextureCache(); auto& cache = m_context.GetTextureCache();
@@ -430,14 +429,13 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
return writes; return writes;
} }
const auto face_writes = [&](const PipelineStencilStaticState& state, const auto face_writes = [&](const vk::StencilOpState& state) {
const PipelineStencilDynamicState& dynamic) { if (state.writeMask == 0) {
if (dynamic.writeMask == 0) {
return false; return false;
} }
bool can_pass = state.compareOp != vk::CompareOp::eNever; bool can_pass = state.compareOp != vk::CompareOp::eNever;
bool can_fail = state.compareOp != vk::CompareOp::eAlways; bool can_fail = state.compareOp != vk::CompareOp::eAlways;
if (dynamic.compareMask == 0) { if (state.compareMask == 0) {
switch (state.compareOp) { switch (state.compareOp) {
case vk::CompareOp::eEqual: case vk::CompareOp::eEqual:
case vk::CompareOp::eLessOrEqual: case vk::CompareOp::eLessOrEqual:
@@ -463,8 +461,7 @@ vk::ImageAspectFlags RenderDepthInfo::AttachmentWriteAspects() const {
(can_pass && depth_fail && state.depthFailOp != vk::StencilOp::eKeep); (can_pass && depth_fail && state.depthFailOp != vk::StencilOp::eKeep);
}; };
if (stencil_clear_enable || if (stencil_clear_enable ||
(stencil_test_enable && (face_writes(stencil_static_front, stencil_dynamic_front) || (stencil_test_enable && (face_writes(stencil_front) || face_writes(stencil_back)))) {
face_writes(stencil_static_back, stencil_dynamic_back)))) {
writes |= vk::ImageAspectFlagBits::eStencil; writes |= vk::ImageAspectFlagBits::eStencil;
} }
return writes; return writes;
@@ -34,10 +34,8 @@ struct RenderDepthInfo {
bool stencil_clear_enable = false; bool stencil_clear_enable = false;
uint8_t stencil_clear_value = 0; uint8_t stencil_clear_value = 0;
bool stencil_test_enable = false; bool stencil_test_enable = false;
PipelineStencilStaticState stencil_static_front; vk::StencilOpState stencil_front;
PipelineStencilStaticState stencil_static_back; vk::StencilOpState stencil_back;
PipelineStencilDynamicState stencil_dynamic_front;
PipelineStencilDynamicState stencil_dynamic_back;
ImageId image_id; ImageId image_id;
[[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const; [[nodiscard]] vk::ImageAspectFlags AttachmentWriteAspects() const;
@@ -742,9 +742,6 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable; static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
static_params.depth_min_bounds = depth.depth_min_bounds; static_params.depth_min_bounds = depth.depth_min_bounds;
static_params.depth_max_bounds = depth.depth_max_bounds; static_params.depth_max_bounds = depth.depth_max_bounds;
static_params.stencil_test_enable = depth.stencil_test_enable;
static_params.stencil_front = depth.stencil_static_front;
static_params.stencil_back = depth.stencil_static_back;
const bool rect_list = const bool rect_list =
command.GetUserConfig().GetPrimType() == Prospero::PrimitiveType::kRectList; command.GetUserConfig().GetPrimType() == Prospero::PrimitiveType::kRectList;
static_params.cull_back = !rect_list && mc.cull_back; static_params.cull_back = !rect_list && mc.cull_back;
@@ -42,9 +42,6 @@ struct PipelineStaticParameters {
bool depth_bounds_test_enable = false; bool depth_bounds_test_enable = false;
float depth_min_bounds = 0.0f; float depth_min_bounds = 0.0f;
float depth_max_bounds = 0.0f; float depth_max_bounds = 0.0f;
bool stencil_test_enable = false;
PipelineStencilStaticState stencil_front;
PipelineStencilStaticState stencil_back;
uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {}; uint32_t color_mask[RENDER_COLOR_ATTACHMENTS_MAX] = {};
bool cull_front = false; bool cull_front = false;
bool cull_back = false; bool cull_back = false;
@@ -68,7 +65,7 @@ struct PipelineStaticParameters {
static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>); static_assert(std::is_trivially_copyable_v<PipelineStaticParameters>);
static_assert(std::is_standard_layout_v<PipelineStaticParameters>); static_assert(std::is_standard_layout_v<PipelineStaticParameters>);
static_assert(alignof(PipelineStaticParameters) == 1); static_assert(alignof(PipelineStaticParameters) == 1);
static_assert(sizeof(PipelineStaticParameters) == 158); static_assert(sizeof(PipelineStaticParameters) == 125);
struct PipelineRenderingState { struct PipelineRenderingState {
std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {}; std::array<vk::Format, RENDER_COLOR_ATTACHMENTS_MAX> color_formats {};
@@ -477,15 +477,6 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
#else #else
(static_params.depth_bounds_test_enable ? VK_TRUE : VK_FALSE); (static_params.depth_bounds_test_enable ? VK_TRUE : VK_FALSE);
#endif #endif
depth_stencil_info.stencilTestEnable = (static_params.stencil_test_enable ? VK_TRUE : VK_FALSE);
depth_stencil_info.front.failOp = static_params.stencil_front.failOp;
depth_stencil_info.front.passOp = static_params.stencil_front.passOp;
depth_stencil_info.front.depthFailOp = static_params.stencil_front.depthFailOp;
depth_stencil_info.front.compareOp = static_params.stencil_front.compareOp;
depth_stencil_info.back.failOp = static_params.stencil_back.failOp;
depth_stencil_info.back.passOp = static_params.stencil_back.passOp;
depth_stencil_info.back.depthFailOp = static_params.stencil_back.depthFailOp;
depth_stencil_info.back.compareOp = static_params.stencil_back.compareOp;
depth_stencil_info.minDepthBounds = static_params.depth_min_bounds; depth_stencil_info.minDepthBounds = static_params.depth_min_bounds;
depth_stencil_info.maxDepthBounds = static_params.depth_max_bounds; depth_stencil_info.maxDepthBounds = static_params.depth_max_bounds;
@@ -498,6 +489,8 @@ void CreatePipelineInternal(GraphicContext& graphics, PipelineCache::Pipeline& p
vk::DynamicState::eDepthCompareOp, vk::DynamicState::eDepthCompareOp,
vk::DynamicState::eDepthBiasEnable, vk::DynamicState::eDepthBiasEnable,
vk::DynamicState::eDepthBias, vk::DynamicState::eDepthBias,
vk::DynamicState::eStencilTestEnable,
vk::DynamicState::eStencilOp,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilCompareMask,
vk::DynamicState::eStencilReference, vk::DynamicState::eStencilReference,
vk::DynamicState::eStencilWriteMask, vk::DynamicState::eStencilWriteMask,
+9 -12
View File
@@ -403,19 +403,16 @@ static void SetGraphicsDynamicParams(const CommandBuffer& buffer, vk::CommandBuf
vk_buffer.setDepthBias(constant_factor, poly_offset.clamp, slope_factor); vk_buffer.setDepthBias(constant_factor, poly_offset.clamp, slope_factor);
} }
vk_buffer.setStencilTestEnable(depth.stencil_test_enable ? VK_TRUE : VK_FALSE);
if (depth.stencil_test_enable) { if (depth.stencil_test_enable) {
vk_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eFront, const auto set_stencil = [&](vk::StencilFaceFlagBits face, const vk::StencilOpState& state) {
depth.stencil_dynamic_front.compareMask); vk_buffer.setStencilOp(face, state.failOp, state.passOp, state.depthFailOp, state.compareOp);
vk_buffer.setStencilCompareMask(vk::StencilFaceFlagBits::eBack, vk_buffer.setStencilCompareMask(face, state.compareMask);
depth.stencil_dynamic_back.compareMask); vk_buffer.setStencilWriteMask(face, state.writeMask);
vk_buffer.setStencilWriteMask(vk::StencilFaceFlagBits::eFront, vk_buffer.setStencilReference(face, state.reference);
depth.stencil_dynamic_front.writeMask); };
vk_buffer.setStencilWriteMask(vk::StencilFaceFlagBits::eBack, set_stencil(vk::StencilFaceFlagBits::eFront, depth.stencil_front);
depth.stencil_dynamic_back.writeMask); set_stencil(vk::StencilFaceFlagBits::eBack, depth.stencil_back);
vk_buffer.setStencilReference(vk::StencilFaceFlagBits::eFront,
depth.stencil_dynamic_front.reference);
vk_buffer.setStencilReference(vk::StencilFaceFlagBits::eBack,
depth.stencil_dynamic_back.reference);
} }
#if defined(__APPLE__) #if defined(__APPLE__)
@@ -5,7 +5,6 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <type_traits>
namespace Libs::Graphics { namespace Libs::Graphics {
@@ -67,33 +66,6 @@ inline constexpr TargetViewInfo ResolveTargetViewInfo(uint32_t base_layer, uint3
base_layer, last_layer - base_layer + 1u, last_layer + 1u}; base_layer, last_layer - base_layer + 1u, last_layer + 1u};
} }
#pragma pack(push, 1)
struct PipelineStencilStaticState {
vk::StencilOp failOp = vk::StencilOp::eKeep;
vk::StencilOp passOp = vk::StencilOp::eKeep;
vk::StencilOp depthFailOp = vk::StencilOp::eKeep;
vk::CompareOp compareOp = vk::CompareOp::eNever;
};
struct PipelineStencilDynamicState {
uint32_t compareMask = 0;
uint32_t writeMask = 0;
uint32_t reference = 0;
};
#pragma pack(pop)
static_assert(std::is_trivially_copyable_v<PipelineStencilStaticState>);
static_assert(std::is_standard_layout_v<PipelineStencilStaticState>);
static_assert(alignof(PipelineStencilStaticState) == 1);
static_assert(sizeof(PipelineStencilStaticState) ==
sizeof(vk::StencilOp) * 3 + sizeof(vk::CompareOp));
static_assert(std::is_trivially_copyable_v<PipelineStencilDynamicState>);
static_assert(std::is_standard_layout_v<PipelineStencilDynamicState>);
static_assert(alignof(PipelineStencilDynamicState) == 1);
static_assert(sizeof(PipelineStencilDynamicState) == sizeof(uint32_t) * 3);
} // namespace Libs::Graphics } // namespace Libs::Graphics
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERTARGET_H_ #endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_RENDERTARGET_H_
+42 -20
View File
@@ -10275,9 +10275,9 @@ public:
!read_only_depth.depth_write_enable && !read_only_depth.depth_write_enable &&
!read_only_depth.stencil_clear_enable && !read_only_depth.stencil_clear_enable &&
read_only_depth.stencil_test_enable && read_only_depth.stencil_test_enable &&
read_only_depth.stencil_dynamic_front.writeMask == 0 && read_only_depth.stencil_front.writeMask == 0 &&
read_only_depth.stencil_dynamic_back.writeMask == 0 && read_only_depth.stencil_back.writeMask == 0 &&
read_only_depth.stencil_static_front.passOp == read_only_depth.stencil_front.passOp ==
vk::StencilOp::eKeep && vk::StencilOp::eKeep &&
!read_only_depth.AttachmentWriteAspects() && !read_only_depth.AttachmentWriteAspects() &&
depth_attachment_layout(read_only_depth) == depth_attachment_layout(read_only_depth) ==
@@ -12501,15 +12501,18 @@ public:
cmd.setDepthWriteEnable(depth.depth_write_enable); cmd.setDepthWriteEnable(depth.depth_write_enable);
cmd.setDepthCompareOp(depth.depth_compare_op); cmd.setDepthCompareOp(depth.depth_compare_op);
cmd.setDepthBiasEnable(false); cmd.setDepthBiasEnable(false);
cmd.setStencilTestEnable(depth.stencil_test_enable);
if (depth.stencil_test_enable) { if (depth.stencil_test_enable) {
const auto set_stencil = [&](vk::StencilFaceFlagBits face, const auto set_stencil = [&](vk::StencilFaceFlagBits face,
const PipelineStencilDynamicState &state) { const vk::StencilOpState &state) {
cmd.setStencilOp(face, state.failOp, state.passOp, state.depthFailOp,
state.compareOp);
cmd.setStencilCompareMask(face, state.compareMask); cmd.setStencilCompareMask(face, state.compareMask);
cmd.setStencilWriteMask(face, state.writeMask); cmd.setStencilWriteMask(face, state.writeMask);
cmd.setStencilReference(face, state.reference); cmd.setStencilReference(face, state.reference);
}; };
set_stencil(vk::StencilFaceFlagBits::eFront, depth.stencil_dynamic_front); set_stencil(vk::StencilFaceFlagBits::eFront, depth.stencil_front);
set_stencil(vk::StencilFaceFlagBits::eBack, depth.stencil_dynamic_back); set_stencil(vk::StencilFaceFlagBits::eBack, depth.stencil_back);
} }
const vk::Bool32 write = true; const vk::Bool32 write = true;
cmd.setColorWriteEnableEXT(1, &write); cmd.setColorWriteEnableEXT(1, &write);
@@ -12624,6 +12627,9 @@ public:
static_cast<uint16_t>(extent - 1), true}; static_cast<uint16_t>(extent - 1), true};
registers.SetDepthRenderTarget(stencil_target); registers.SetDepthRenderTarget(stencil_target);
HW::DepthControl stencil_control{}; HW::DepthControl stencil_control{};
// Keep the same depth/stencil attachment active when stencil testing is disabled.
stencil_control.z_enable = true;
stencil_control.zfunc = static_cast<uint8_t>(vk::CompareOp::eAlways);
stencil_control.stencil_enable = stencil_control.backface_enable = true; stencil_control.stencil_enable = stencil_control.backface_enable = true;
stencil_control.stencilfunc = stencil_control.stencilfunc_bf = stencil_control.stencilfunc = stencil_control.stencilfunc_bf =
static_cast<uint8_t>(vk::CompareOp::eAlways); static_cast<uint8_t>(vk::CompareOp::eAlways);
@@ -12651,6 +12657,9 @@ public:
scheduler.Finish(); scheduler.Finish();
return ReadBuffer(name, stencil_readback, extent * extent / 4); return ReadBuffer(name, stencil_readback, extent * extent / 4);
}; };
const std::array stencil_pipelines{
pipeline(true, 2, 2, false, true).pipeline,
pipeline(true, 2, 2, false, false).pipeline};
const auto check_stencil = [&](const char *label, bool back_face, const auto check_stencil = [&](const char *label, bool back_face,
uint8_t initial, uint8_t written) { uint8_t initial, uint8_t written) {
vk::ClearValue clear{}; vk::ClearValue clear{};
@@ -12658,7 +12667,11 @@ public:
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), depth.image_id, TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), depth.image_id,
{vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, {vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
0, 1, 0, 1}, clear); 0, 1, 0, 1}, clear);
draw(pipeline(true, 2, 2, false, !back_face)); const auto &selected = pipeline(true, 2, 2, false, !back_face);
Require(name, "dynamic stencil pipeline reuse",
selected.pipeline == stencil_pipelines[back_face],
"stencil enable, operations or references changed the graphics pipeline");
draw(selected);
const auto result = read_stencil(); const auto result = read_stencil();
const auto *stencil_bytes = reinterpret_cast<const uint8_t *>(result.data()); const auto *stencil_bytes = reinterpret_cast<const uint8_t *>(result.data());
for (uint32_t texel = 0; texel < extent * extent; ++texel) { for (uint32_t texel = 0; texel < extent * extent; ++texel) {
@@ -12671,6 +12684,17 @@ public:
check_stencil("front-face ReplaceTest", false, 0x35, 0xb5); check_stencil("front-face ReplaceTest", false, 0x35, 0xb5);
check_stencil("back-face masked ReplaceOp", true, 0xb5, 0x35); check_stencil("back-face masked ReplaceOp", true, 0xb5, 0x35);
stencil_control.stencil_enable = false;
registers.SetDepthControl(stencil_control);
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
check_stencil("disabled front stencil", false, 0x35, 0x35);
check_stencil("disabled back stencil", true, 0xb5, 0xb5);
stencil_control.stencil_enable = true;
registers.SetDepthControl(stencil_control);
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
check_stencil("re-enabled front stencil", false, 0x35, 0xb5);
check_stencil("re-enabled back stencil", true, 0xb5, 0x35);
// Frame 6115 uses separate test/op replacement values with Always comparisons. // Frame 6115 uses separate test/op replacement values with Always comparisons.
stencil_control.z_enable = stencil_control.z_write_enable = true; stencil_control.z_enable = stencil_control.z_write_enable = true;
stencil_control.zfunc = static_cast<uint8_t>(vk::CompareOp::eLessOrEqual); stencil_control.zfunc = static_cast<uint8_t>(vk::CompareOp::eLessOrEqual);
@@ -12679,8 +12703,8 @@ public:
registers.SetStencilMask({8, 0xff, 0xff, 1, 8, 0xff, 0xff, 1}); registers.SetStencilMask({8, 0xff, 0xff, 1, 8, 0xff, 0xff, 1});
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth); RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
Require(name, "independent stencil references", Require(name, "independent stencil references",
depth.stencil_dynamic_front.reference == 8 && depth.stencil_front.reference == 8 &&
depth.stencil_dynamic_back.reference == 1, depth.stencil_back.reference == 1,
"always-pass faces must preserve their distinct replacement values"); "always-pass faces must preserve their distinct replacement values");
check_stencil("front test-value replacement", false, 0x35, 8); check_stencil("front test-value replacement", false, 0x35, 8);
check_stencil("back operation-value replacement", true, 0x35, 1); check_stencil("back operation-value replacement", true, 0x35, 1);
@@ -12700,8 +12724,8 @@ public:
registers.SetStencilMask({8, 8, 1, 1, 8, 8, 1, 1}); registers.SetStencilMask({8, 8, 1, 1, 8, 8, 1, 1});
RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth); RenderExecutorTestAccess::ResolveRenderDepthTarget(executor, scheduler.Current(), depth);
Require(name, "masked compare and replace reference", Require(name, "masked compare and replace reference",
depth.stencil_dynamic_front.reference == 9 && depth.stencil_front.reference == 9 &&
depth.stencil_dynamic_back.reference == 9, depth.stencil_back.reference == 9,
"disjoint comparison and replacement bits must combine into one reference"); "disjoint comparison and replacement bits must combine into one reference");
check_stencil("masked compare passes", false, 0xb8, 0xb9); check_stencil("masked compare passes", false, 0xb8, 0xb9);
check_stencil("masked compare fails", false, 0xb0, 0xb0); check_stencil("masked compare fails", false, 0xb0, 0xb0);
@@ -28499,27 +28523,25 @@ void CheckDepthAttachmentWrites() {
target.depth_load_clear_enable = false; target.depth_load_clear_enable = false;
target.stencil_test_enable = true; target.stencil_test_enable = true;
target.stencil_dynamic_front = {0xff, 0xff, 0}; target.stencil_front = {vk::StencilOp::eKeep, vk::StencilOp::eKeep,
target.stencil_dynamic_back = target.stencil_dynamic_front; vk::StencilOp::eKeep, vk::CompareOp::eAlways, 0xff, 0xff, 0};
target.stencil_static_front = {vk::StencilOp::eKeep, vk::StencilOp::eKeep, target.stencil_back = target.stencil_front;
vk::StencilOp::eKeep, vk::CompareOp::eAlways};
target.stencil_static_back = target.stencil_static_front;
Require("DepthAttachmentWrites", "stencil keep", Require("DepthAttachmentWrites", "stencil keep",
!target.AttachmentWriteAspects(), !target.AttachmentWriteAspects(),
"KEEP-only stencil state claimed a stencil write"); "KEEP-only stencil state claimed a stencil write");
target.stencil_static_front.failOp = vk::StencilOp::eZero; target.stencil_front.failOp = vk::StencilOp::eZero;
Require("DepthAttachmentWrites", "unreachable stencil fail", Require("DepthAttachmentWrites", "unreachable stencil fail",
!target.AttachmentWriteAspects(), !target.AttachmentWriteAspects(),
"ALWAYS comparison claimed an unreachable fail operation"); "ALWAYS comparison claimed an unreachable fail operation");
target.stencil_static_front.failOp = vk::StencilOp::eKeep; target.stencil_front.failOp = vk::StencilOp::eKeep;
target.stencil_static_front.passOp = vk::StencilOp::eReplace; target.stencil_front.passOp = vk::StencilOp::eReplace;
Require("DepthAttachmentWrites", "stencil pass write", Require("DepthAttachmentWrites", "stencil pass write",
target.AttachmentWriteAspects() == vk::ImageAspectFlagBits::eStencil, target.AttachmentWriteAspects() == vk::ImageAspectFlagBits::eStencil,
"write-capable stencil pass did not claim stencil"); "write-capable stencil pass did not claim stencil");
target.stencil_dynamic_front.writeMask = 0; target.stencil_front.writeMask = 0;
Require("DepthAttachmentWrites", "back-face keep", Require("DepthAttachmentWrites", "back-face keep",
!target.AttachmentWriteAspects(), !target.AttachmentWriteAspects(),
"masked front write or KEEP-only back face claimed stencil"); "masked front write or KEEP-only back face claimed stencil");