diff --git a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp index eda3b1c4b..ca6af28cc 100644 --- a/src/graphics/host_gpu/renderer/depthRenderTarget.cpp +++ b/src/graphics/host_gpu/renderer/depthRenderTarget.cpp @@ -38,7 +38,10 @@ namespace Libs::Graphics { EXIT("unsupported render state; details were printed above\n"); } -static vk::StencilOp ConvertStencilOp(uint8_t value) { +static vk::StencilOp ConvertStencilOp(uint8_t value, uint8_t write_mask, uint8_t op_value) { + if (write_mask == 0) { + return vk::StencilOp::eKeep; + } switch (static_cast(value)) { case Prospero::StencilOp::kKeep: return vk::StencilOp::eKeep; case Prospero::StencilOp::kZero: return vk::StencilOp::eZero; @@ -49,7 +52,17 @@ static vk::StencilOp ConvertStencilOp(uint8_t value) { case Prospero::StencilOp::kInvert: return vk::StencilOp::eInvert; case Prospero::StencilOp::kAddWrap: return vk::StencilOp::eIncrementAndWrap; case Prospero::StencilOp::kSubWrap: return vk::StencilOp::eDecrementAndWrap; - default: DepthFatal("unsupported stencil operation"); + case Prospero::StencilOp::kXor: + if ((write_mask & op_value) == 0) { + return vk::StencilOp::eKeep; + } + if ((write_mask & ~op_value) != 0) { + DepthFatal("unsupported stencil XOR operands: write mask=0x%02" PRIx8 + ", operation value=0x%02" PRIx8, + write_mask, op_value); + } + return vk::StencilOp::eInvert; + default: DepthFatal("unsupported stencil operation: 0x%02" PRIx8, value); } } @@ -283,6 +296,8 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB r.stencil_clear_value = hw.GetStencilClearValue(); r.stencil_test_enable = has_stencil && dc.stencil_enable; if (r.stencil_test_enable) { + const uint8_t front_write_mask = rc.stencil_clear_enable ? 0 : sm.stencil_writemask; + const uint8_t back_write_mask = rc.stencil_clear_enable ? 0 : sm.stencil_writemask_bf; if (dc.stencilfunc > static_cast(vk::CompareOp::eAlways) || (dc.backface_enable && dc.stencilfunc_bf > static_cast(vk::CompareOp::eAlways)) || @@ -294,19 +309,18 @@ void RenderExecutor::ResolveRenderDepthTarget(uint64_t submit_id, RenderCommandB DepthFatal("unsupported stencil compare or replacement state"); } r.stencil_static_front = { - ConvertStencilOp(sc.stencil_fail), ConvertStencilOp(sc.stencil_zpass), - ConvertStencilOp(sc.stencil_zfail), static_cast(dc.stencilfunc)}; - r.stencil_dynamic_front = {sm.stencil_mask, - rc.stencil_clear_enable ? 0u : sm.stencil_writemask, - sm.stencil_testval}; + ConvertStencilOp(sc.stencil_fail, front_write_mask, sm.stencil_opval), + ConvertStencilOp(sc.stencil_zpass, front_write_mask, sm.stencil_opval), + ConvertStencilOp(sc.stencil_zfail, front_write_mask, sm.stencil_opval), + static_cast(dc.stencilfunc)}; + r.stencil_dynamic_front = {sm.stencil_mask, front_write_mask, sm.stencil_testval}; if (dc.backface_enable) { - r.stencil_static_back = {ConvertStencilOp(sc.stencil_fail_bf), - ConvertStencilOp(sc.stencil_zpass_bf), - ConvertStencilOp(sc.stencil_zfail_bf), - static_cast(dc.stencilfunc_bf)}; - r.stencil_dynamic_back = {sm.stencil_mask_bf, - rc.stencil_clear_enable ? 0u : sm.stencil_writemask_bf, - sm.stencil_testval_bf}; + r.stencil_static_back = { + ConvertStencilOp(sc.stencil_fail_bf, back_write_mask, sm.stencil_opval_bf), + ConvertStencilOp(sc.stencil_zpass_bf, back_write_mask, sm.stencil_opval_bf), + ConvertStencilOp(sc.stencil_zfail_bf, back_write_mask, sm.stencil_opval_bf), + static_cast(dc.stencilfunc_bf)}; + r.stencil_dynamic_back = {sm.stencil_mask_bf, back_write_mask, sm.stencil_testval_bf}; } else { r.stencil_static_back = r.stencil_static_front; r.stencil_dynamic_back = r.stencil_dynamic_front;