From 043be4d8f7053cef49f7818172511d316f95b0c7 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Sat, 22 Jan 2022 05:12:48 +0530 Subject: [PATCH] Implement Maxwell3D Two-Side Stencil Toggle Stencil operations are configurable to be the same for both sides or have independent stencil state for both sides. It is controlled via the previously unimplemented `stencilTwoSideEnable`. --- .../gpu/interconnect/graphics_context.h | 54 ++++++++++++++++--- .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 4 ++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 4 +- 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index b859c293..c3831eac 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -2111,6 +2111,8 @@ namespace skyline::gpu::interconnect { /* Depth */ vk::PipelineDepthStencilStateCreateInfo depthState{}; + bool twoSideStencilEnabled{}; //!< If both sides of the stencil have different state + vk::StencilOpState stencilBack{}; //!< The back of the stencil when two-side stencil is enabled void SetDepthTestEnabled(bool enabled) { depthState.depthTestEnable = enabled; @@ -2178,6 +2180,16 @@ namespace skyline::gpu::interconnect { depthState.stencilTestEnable = enabled; } + void SetStencilTwoSideEnabled(bool enabled) { + if (twoSideStencilEnabled == enabled) { + if (enabled) + depthState.back = stencilBack; + else + depthState.back = depthState.front; + twoSideStencilEnabled = enabled; + } + } + vk::StencilOp ConvertStencilOp(maxwell3d::StencilOp op) { using MaxwellOp = maxwell3d::StencilOp; using VkOp = vk::StencilOp; @@ -2203,58 +2215,86 @@ namespace skyline::gpu::interconnect { void SetStencilFrontFailOp(maxwell3d::StencilOp op) { depthState.front.failOp = ConvertStencilOp(op); + if (!twoSideStencilEnabled) + depthState.back.failOp = depthState.front.failOp; } void SetStencilBackFailOp(maxwell3d::StencilOp op) { - depthState.back.failOp = ConvertStencilOp(op); + stencilBack.failOp = ConvertStencilOp(op); + if (twoSideStencilEnabled) + depthState.back.failOp = stencilBack.failOp; } void SetStencilFrontPassOp(maxwell3d::StencilOp op) { depthState.front.passOp = ConvertStencilOp(op); + if (!twoSideStencilEnabled) + depthState.back.passOp = depthState.front.passOp; } void SetStencilBackPassOp(maxwell3d::StencilOp op) { - depthState.back.passOp = ConvertStencilOp(op); + stencilBack.passOp = ConvertStencilOp(op); + if (twoSideStencilEnabled) + depthState.back.passOp = stencilBack.passOp; } void SetStencilFrontDepthFailOp(maxwell3d::StencilOp op) { depthState.front.depthFailOp = ConvertStencilOp(op); + if (!twoSideStencilEnabled) + depthState.back.depthFailOp = depthState.front.depthFailOp; } void SetStencilBackDepthFailOp(maxwell3d::StencilOp op) { - depthState.back.depthFailOp = ConvertStencilOp(op); + stencilBack.depthFailOp = ConvertStencilOp(op); + if (twoSideStencilEnabled) + depthState.back.depthFailOp = stencilBack.depthFailOp; } void SetStencilFrontCompareOp(maxwell3d::CompareOp op) { depthState.front.compareOp = ConvertCompareOp(op); + if (!twoSideStencilEnabled) + depthState.back.compareOp = depthState.front.compareOp; } void SetStencilBackCompareOp(maxwell3d::CompareOp op) { - depthState.back.compareOp = ConvertCompareOp(op); + stencilBack.compareOp = ConvertCompareOp(op); + if (twoSideStencilEnabled) + depthState.back.compareOp = stencilBack.compareOp; } void SetStencilFrontCompareMask(u32 mask) { depthState.front.compareMask = mask; + if (!twoSideStencilEnabled) + depthState.back.compareMask = depthState.front.compareMask; } void SetStencilBackCompareMask(u32 mask) { - depthState.back.compareMask = mask; + stencilBack.compareMask = mask; + if (twoSideStencilEnabled) + depthState.back.compareMask = stencilBack.compareMask; } void SetStencilFrontWriteMask(u32 mask) { depthState.front.writeMask = mask; + if (!twoSideStencilEnabled) + depthState.back.writeMask = depthState.front.writeMask; } void SetStencilBackWriteMask(u32 mask) { - depthState.back.writeMask = mask; + stencilBack.writeMask = mask; + if (twoSideStencilEnabled) + depthState.back.writeMask = stencilBack.writeMask; } void SetStencilFrontReference(u32 reference) { depthState.front.reference = reference; + if (!twoSideStencilEnabled) + depthState.back.reference = depthState.front.reference; } void SetStencilBackReference(u32 reference) { - depthState.back.reference = reference; + stencilBack.reference = reference; + if (twoSideStencilEnabled) + depthState.back.reference = stencilBack.reference; } /* Multisampling */ diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 3a502dc3..5f3bbb7d 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -278,6 +278,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetStencilFrontWriteMask(writeMask); }) + MAXWELL3D_CASE(stencilTwoSideEnable, { + context.SetStencilTwoSideEnabled(stencilTwoSideEnable); + }) + MAXWELL3D_STRUCT_CASE(stencilBack, failOp, { context.SetStencilBackFailOp(failOp); }) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 6a407995..e3b4a125 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -205,7 +205,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x55D, TexturePool> texturePool; - Register<0x565, u32> stencilTwoSideEnable; + Register<0x565, u32> stencilTwoSideEnable; //!< Determines if the back-facing stencil state uses the front facing stencil state or independent stencil state struct StencilBack { type::StencilOp failOp; // 0x566 @@ -227,7 +227,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x5F2, type::IndexBuffer> indexBuffer; - Register<0x5F7, u32> drawIndexFirst; //!< The the first element in the index buffer to draw + Register<0x5F7, u32> drawIndexFirst; //!< The first element in the index buffer to draw Register<0x5F8, u32> drawIndexCount; //!< The amount of elements to draw, calling this method triggers indexed drawing Register<0x61F, float> depthBiasClamp;