From 92809f8a784b18e40270b9ed8d95b86a4a90d20e Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Mon, 15 Nov 2021 23:52:47 +0530 Subject: [PATCH] Implement Maxwell3D Independent/Common Color Blending Maxwell3D supports independent blending which has different blending per-RT and common blending which has the same blending for all RTs. There is a register determining which mode to utilize and we simply have two arrays of `VkPipelineColorBlendAttachmentState` for the RTs that we toggle between to make the transition between them extremely cheap. --- .../gpu/interconnect/graphics_context.h | 192 +++++++++++++++++- .../skyline/soc/gm20b/engines/maxwell/types.h | 120 +++++------ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 78 ++++++- .../skyline/soc/gm20b/engines/maxwell_3d.h | 46 +++-- 4 files changed, 349 insertions(+), 87 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 7aaba6e6..08d1536b 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -482,7 +482,11 @@ namespace skyline::gpu::interconnect { /* Color Blending */ private: - vk::PipelineColorBlendStateCreateInfo blendState{}; + std::array commonRtBlendState{}, independentRtBlendState{}; //!< Per-RT blending state for common/independent blending for trivial toggling behavior + vk::PipelineColorBlendStateCreateInfo blendState{ + .pAttachments = commonRtBlendState.data(), + .attachmentCount = maxwell3d::RenderTargetCount, + }; public: void SetBlendLogicOpEnable(bool enabled) { @@ -532,9 +536,193 @@ namespace skyline::gpu::interconnect { }(); } - void SetAlphaTestEnable(bool enable) { + void SetAlphaTestEnabled(bool enable) { if (enable) Logger::Warn("Cannot enable alpha testing due to Vulkan constraints"); } + + vk::BlendOp ConvertBlendOp(maxwell3d::BlendOp op) { + switch (op) { + case maxwell3d::BlendOp::Add: + case maxwell3d::BlendOp::AddGL: + return vk::BlendOp::eAdd; + + case maxwell3d::BlendOp::Subtract: + case maxwell3d::BlendOp::SubtractGL: + return vk::BlendOp::eSubtract; + + case maxwell3d::BlendOp::ReverseSubtract: + case maxwell3d::BlendOp::ReverseSubtractGL: + return vk::BlendOp::eReverseSubtract; + + case maxwell3d::BlendOp::Minimum: + case maxwell3d::BlendOp::MinimumGL: + return vk::BlendOp::eMin; + + case maxwell3d::BlendOp::Maximum: + case maxwell3d::BlendOp::MaximumGL: + return vk::BlendOp::eMax; + } + } + + vk::BlendFactor ConvertBlendFactor(maxwell3d::BlendFactor factor) { + switch (factor) { + case maxwell3d::BlendFactor::Zero: + case maxwell3d::BlendFactor::ZeroGL: + return vk::BlendFactor::eZero; + + case maxwell3d::BlendFactor::One: + case maxwell3d::BlendFactor::OneGL: + return vk::BlendFactor::eOne; + + case maxwell3d::BlendFactor::SourceColor: + case maxwell3d::BlendFactor::SourceColorGL: + return vk::BlendFactor::eSrcColor; + + case maxwell3d::BlendFactor::OneMinusSourceColor: + case maxwell3d::BlendFactor::OneMinusSourceColorGL: + return vk::BlendFactor::eOneMinusSrcColor; + + case maxwell3d::BlendFactor::SourceAlpha: + case maxwell3d::BlendFactor::SourceAlphaGL: + return vk::BlendFactor::eSrcAlpha; + + case maxwell3d::BlendFactor::OneMinusSourceAlpha: + case maxwell3d::BlendFactor::OneMinusSourceAlphaGL: + return vk::BlendFactor::eOneMinusSrcColor; + + case maxwell3d::BlendFactor::DestAlpha: + case maxwell3d::BlendFactor::DestAlphaGL: + return vk::BlendFactor::eDstAlpha; + + case maxwell3d::BlendFactor::OneMinusDestAlpha: + case maxwell3d::BlendFactor::OneMinusDestAlphaGL: + return vk::BlendFactor::eOneMinusDstAlpha; + + case maxwell3d::BlendFactor::DestColor: + case maxwell3d::BlendFactor::DestColorGL: + return vk::BlendFactor::eDstColor; + + case maxwell3d::BlendFactor::OneMinusDestColor: + case maxwell3d::BlendFactor::OneMinusDestColorGL: + return vk::BlendFactor::eOneMinusDstColor; + + case maxwell3d::BlendFactor::SourceAlphaSaturate: + case maxwell3d::BlendFactor::SourceAlphaSaturateGL: + return vk::BlendFactor::eSrcAlphaSaturate; + + case maxwell3d::BlendFactor::Source1Color: + case maxwell3d::BlendFactor::Source1ColorGL: + return vk::BlendFactor::eSrc1Color; + + case maxwell3d::BlendFactor::OneMinusSource1Color: + case maxwell3d::BlendFactor::OneMinusSource1ColorGL: + return vk::BlendFactor::eOneMinusSrc1Color; + + case maxwell3d::BlendFactor::Source1Alpha: + case maxwell3d::BlendFactor::Source1AlphaGL: + return vk::BlendFactor::eSrc1Alpha; + + case maxwell3d::BlendFactor::OneMinusSource1Alpha: + case maxwell3d::BlendFactor::OneMinusSource1AlphaGL: + return vk::BlendFactor::eOneMinusSrc1Alpha; + + case maxwell3d::BlendFactor::ConstantColor: + case maxwell3d::BlendFactor::ConstantColorGL: + return vk::BlendFactor::eConstantColor; + + case maxwell3d::BlendFactor::OneMinusConstantColor: + case maxwell3d::BlendFactor::OneMinusConstantColorGL: + return vk::BlendFactor::eOneMinusConstantColor; + + case maxwell3d::BlendFactor::ConstantAlpha: + case maxwell3d::BlendFactor::ConstantAlphaGL: + return vk::BlendFactor::eConstantAlpha; + + case maxwell3d::BlendFactor::OneMinusConstantAlpha: + case maxwell3d::BlendFactor::OneMinusConstantAlphaGL: + return vk::BlendFactor::eOneMinusConstantAlpha; + } + } + + void SetIndependentBlendingEnabled(bool enable) { + if (enable) + blendState.pAttachments = independentRtBlendState.data(); + else + blendState.pAttachments = commonRtBlendState.data(); + } + + void SetColorBlendEnabled(bool enable) { + for (auto &blend : commonRtBlendState) + blend.blendEnable = enable; + } + + void SetColorBlendOp(maxwell3d::BlendOp op) { + auto vkOp{ConvertBlendOp(op)}; + for (auto &blend : commonRtBlendState) + blend.colorBlendOp = vkOp; + } + + void SetSrcColorBlendFactor(maxwell3d::BlendFactor factor) { + auto vkFactor{ConvertBlendFactor(factor)}; + for (auto &blend : commonRtBlendState) + blend.srcColorBlendFactor = vkFactor; + } + + void SetDstColorBlendFactor(maxwell3d::BlendFactor factor) { + auto vkFactor{ConvertBlendFactor(factor)}; + for (auto &blend : commonRtBlendState) + blend.dstColorBlendFactor = vkFactor; + } + + void SetAlphaBlendOp(maxwell3d::BlendOp op) { + auto vkOp{ConvertBlendOp(op)}; + for (auto &blend : commonRtBlendState) + blend.alphaBlendOp = vkOp; + } + + void SetSrcAlphaBlendFactor(maxwell3d::BlendFactor factor) { + auto vkFactor{ConvertBlendFactor(factor)}; + for (auto &blend : commonRtBlendState) + blend.srcAlphaBlendFactor = vkFactor; + } + + void SetDstAlphaBlendFactor(maxwell3d::BlendFactor factor) { + auto vkFactor{ConvertBlendFactor(factor)}; + for (auto &blend : commonRtBlendState) + blend.dstAlphaBlendFactor = vkFactor; + } + + void SetColorBlendEnabled(u32 index, bool enable) { + independentRtBlendState[index].blendEnable = enable; + } + + void SetColorBlendOp(u32 index, maxwell3d::BlendOp op) { + independentRtBlendState[index].colorBlendOp = ConvertBlendOp(op); + } + + void SetSrcColorBlendFactor(u32 index, maxwell3d::BlendFactor factor) { + independentRtBlendState[index].srcColorBlendFactor = ConvertBlendFactor(factor); + } + + void SetDstColorBlendFactor(u32 index, maxwell3d::BlendFactor factor) { + independentRtBlendState[index].dstColorBlendFactor = ConvertBlendFactor(factor); + } + + void SetAlphaBlendOp(u32 index, maxwell3d::BlendOp op) { + independentRtBlendState[index].alphaBlendOp = ConvertBlendOp(op); + } + + void SetSrcAlphaBlendFactor(u32 index, maxwell3d::BlendFactor factor) { + independentRtBlendState[index].srcAlphaBlendFactor = ConvertBlendFactor(factor); + } + + void SetDstAlphaBlendFactor(u32 index, maxwell3d::BlendFactor factor) { + independentRtBlendState[index].dstAlphaBlendFactor = ConvertBlendFactor(factor); + } + + void SetColorBlendConstant(u32 index, float constant) { + blendState.blendConstants[index] = constant; + } }; } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index f6d59ecf..be6a3c41 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -302,75 +302,63 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { AlwaysGL = 0x207, }; - struct Blend { - enum class Op : u32 { - Add = 1, - Subtract = 2, - ReverseSubtract = 3, - Minimum = 4, - Maximum = 5, + constexpr static size_t BlendColorChannelCount{4}; //!< The amount of color channels in operations such as blending - AddGL = 0x8006, - SubtractGL = 0x8007, - ReverseSubtractGL = 0x8008, - MinimumGL = 0x800A, - MaximumGL = 0x800B, - }; + enum class BlendOp : u32 { + Add = 1, + Subtract = 2, + ReverseSubtract = 3, + Minimum = 4, + Maximum = 5, - enum class Factor : u32 { - Zero = 0x1, - One = 0x2, - SourceColor = 0x3, - OneMinusSourceColor = 0x4, - SourceAlpha = 0x5, - OneMinusSourceAlpha = 0x6, - DestAlpha = 0x7, - OneMinusDestAlpha = 0x8, - DestColor = 0x9, - OneMinusDestColor = 0xA, - SourceAlphaSaturate = 0xB, - Source1Color = 0x10, - OneMinusSource1Color = 0x11, - Source1Alpha = 0x12, - OneMinusSource1Alpha = 0x13, - ConstantColor = 0x61, - OneMinusConstantColor = 0x62, - ConstantAlpha = 0x63, - OneMinusConstantAlpha = 0x64, - - ZeroGL = 0x4000, - OneGL = 0x4001, - SourceColorGL = 0x4300, - OneMinusSourceColorGL = 0x4301, - SourceAlphaGL = 0x4302, - OneMinusSourceAlphaGL = 0x4303, - DestAlphaGL = 0x4304, - OneMinusDestAlphaGL = 0x4305, - DestColorGL = 0x4306, - OneMinusDestColorGL = 0x4307, - SourceAlphaSaturateGL = 0x4308, - ConstantColorGL = 0xC001, - OneMinusConstantColorGL = 0xC002, - ConstantAlphaGL = 0xC003, - OneMinusConstantAlphaGL = 0xC004, - Source1ColorGL = 0xC900, - OneMinusSource1ColorGL = 0xC901, - Source1AlphaGL = 0xC902, - OneMinusSource1AlphaGL = 0xC903, - }; - - struct { - u32 seperateAlpha; - Op colorOp; - Factor colorSrcFactor; - Factor colorDestFactor; - Op alphaOp; - Factor alphaSrcFactor; - Factor alphaDestFactor; - u32 _pad_; - }; + AddGL = 0x8006, + SubtractGL = 0x8007, + ReverseSubtractGL = 0x8008, + MinimumGL = 0x800A, + MaximumGL = 0x800B, + }; + + enum class BlendFactor : u32 { + Zero = 0x1, + One = 0x2, + SourceColor = 0x3, + OneMinusSourceColor = 0x4, + SourceAlpha = 0x5, + OneMinusSourceAlpha = 0x6, + DestAlpha = 0x7, + OneMinusDestAlpha = 0x8, + DestColor = 0x9, + OneMinusDestColor = 0xA, + SourceAlphaSaturate = 0xB, + Source1Color = 0x10, + OneMinusSource1Color = 0x11, + Source1Alpha = 0x12, + OneMinusSource1Alpha = 0x13, + ConstantColor = 0x61, + OneMinusConstantColor = 0x62, + ConstantAlpha = 0x63, + OneMinusConstantAlpha = 0x64, + + ZeroGL = 0x4000, + OneGL = 0x4001, + SourceColorGL = 0x4300, + OneMinusSourceColorGL = 0x4301, + SourceAlphaGL = 0x4302, + OneMinusSourceAlphaGL = 0x4303, + DestAlphaGL = 0x4304, + OneMinusDestAlphaGL = 0x4305, + DestColorGL = 0x4306, + OneMinusDestColorGL = 0x4307, + SourceAlphaSaturateGL = 0x4308, + ConstantColorGL = 0xC001, + OneMinusConstantColorGL = 0xC002, + ConstantAlphaGL = 0xC003, + OneMinusConstantAlphaGL = 0xC004, + Source1ColorGL = 0xC900, + OneMinusSource1ColorGL = 0xC901, + Source1AlphaGL = 0xC902, + OneMinusSource1AlphaGL = 0xC903, }; - static_assert(sizeof(Blend) == (sizeof(u32) * 8)); struct MultisampleControl { bool alphaToCoverage : 1; 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 c31ebdd6..ffc5737b 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 @@ -183,10 +183,60 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.UpdateRenderTargetControl(renderTargetControl); }) - MAXWELL3D_CASE(alphaTestEnable, { - context.SetAlphaTestEnable(alphaTestEnable); + MAXWELL3D_CASE(independentBlendEnable, { + context.SetIndependentBlendingEnabled(independentBlendEnable); }) + MAXWELL3D_CASE(alphaTestEnable, { + context.SetAlphaTestEnabled(alphaTestEnable); + }) + + #define SET_COLOR_BLEND_CONSTANT_CALLBACK(z, index, data) \ + MAXWELL3D_ARRAY_CASE(blendConstant, index, { \ + context.SetColorBlendConstant(index, blendConstant); \ + }) + + BOOST_PP_REPEAT(4, SET_COLOR_BLEND_CONSTANT_CALLBACK, 0) + static_assert(type::BlendColorChannelCount == 4 && type::BlendColorChannelCount < BOOST_PP_LIMIT_REPEAT); + #undef SET_COLOR_BLEND_CONSTANT_CALLBACK + + MAXWELL3D_STRUCT_CASE(blendStateCommon, colorOp, { + context.SetColorBlendOp(colorOp); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, colorSrcFactor, { + context.SetSrcColorBlendFactor(colorSrcFactor); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, colorDstFactor, { + context.SetDstColorBlendFactor(colorDstFactor); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, alphaOp, { + context.SetAlphaBlendOp(alphaOp); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, alphaSrcFactor, { + context.SetSrcAlphaBlendFactor(alphaSrcFactor); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, alphaDstFactor, { + context.SetDstAlphaBlendFactor(alphaDstFactor); + }) + + MAXWELL3D_STRUCT_CASE(blendStateCommon, enable, { + context.SetColorBlendEnabled(enable); + }) + + #define SET_COLOR_BLEND_ENABLE_CALLBACK(z, index, data) \ + MAXWELL3D_ARRAY_CASE(rtBlendEnable, index, { \ + context.SetColorBlendEnabled(index, rtBlendEnable); \ + }) + + BOOST_PP_REPEAT(8, SET_COLOR_BLEND_ENABLE_CALLBACK, 0) + static_assert(type::RenderTargetCount == 8 && type::RenderTargetCount < BOOST_PP_LIMIT_REPEAT); + #undef SET_COLOR_BLEND_ENABLE_CALLBACK + MAXWELL3D_CASE(lineWidthSmooth, { if (*registers.lineSmoothEnable) context.SetLineWidth(lineWidthSmooth); @@ -249,6 +299,30 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetBlendLogicOpType(type); }) + #define SET_INDEPENDENT_COLOR_BLEND_CALLBACKS(z, index, data) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorOp, { \ + context.SetColorBlendOp(index, colorOp); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorSrcFactor, { \ + context.SetSrcColorBlendFactor(index, colorSrcFactor); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, colorDstFactor, { \ + context.SetDstColorBlendFactor(index, colorDstFactor); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, alphaOp, { \ + context.SetAlphaBlendOp(index, alphaOp); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, alphaSrcFactor, { \ + context.SetSrcAlphaBlendFactor(index, alphaSrcFactor); \ + }) \ + MAXWELL3D_ARRAY_STRUCT_CASE(independentBlend, index, alphaDstFactor, { \ + context.SetDstAlphaBlendFactor(index, alphaDstFactor); \ + }) + + BOOST_PP_REPEAT(8, SET_INDEPENDENT_COLOR_BLEND_CALLBACKS, 0) + static_assert(type::RenderTargetCount == 8 && type::RenderTargetCount < BOOST_PP_LIMIT_REPEAT); + #undef SET_COLOR_BLEND_ENABLE_CALLBACK + #define SET_SHADER_ENABLE_CALLBACK(z, index, data) \ MAXWELL3D_ARRAY_STRUCT_CASE(setProgram, index, info, { \ context.SetShaderEnabled(info.stage, info.enable); \ 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 b196fde9..dc51e54a 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 @@ -45,7 +45,6 @@ namespace skyline::soc::gm20b::engine::maxwell3d { /** * @url https://github.com/devkitPro/deko3d/blob/master/source/maxwell/engine_3d.def - * @note To ease the extension of this structure, padding may follow both _padN_ and _padN_M_ formats */ #pragma pack(push, 1) union Registers { @@ -108,6 +107,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x3EB, u32> rtSeparateFragData; Register<0x458, std::array> vertexAttributeState; Register<0x487, type::RenderTargetControl> renderTargetControl; + Register<0x4B9, u32> independentBlendEnable; Register<0x4BB, u32> alphaTestEnable; Register<0x4C3, type::CompareOp> depthTestFunc; Register<0x4C4, float> alphaTestRef; @@ -115,26 +115,28 @@ namespace skyline::soc::gm20b::engine::maxwell3d { Register<0x4C6, u32> drawTFBStride; struct BlendConstant { - float r; // 0x4C7 - float g; // 0x4C8 - float b; // 0x4C9 - float a; // 0x4CA + float red; // 0x4C7 + float green; // 0x4C8 + float blue; // 0x4C9 + float alpha; // 0x4CA }; - Register<0x4C7, BlendConstant> blendConstant; + Register<0x4C7, std::array> blendConstant; - struct BlendState { + struct BlendStateCommon { u32 seperateAlpha; // 0x4CF - type::Blend::Op colorOp; // 0x4D0 - type::Blend::Factor colorSrcFactor; // 0x4D1 - type::Blend::Factor colorDestFactor; // 0x4D2 - type::Blend::Op alphaOp; // 0x4D3 - type::Blend::Factor alphaSrcFactor; // 0x4D4 - type::Blend::Factor alphaDestFactor; // 0x4D6 + type::BlendOp colorOp; // 0x4D0 + type::BlendFactor colorSrcFactor; // 0x4D1 + type::BlendFactor colorDstFactor; // 0x4D2 + type::BlendOp alphaOp; // 0x4D3 + type::BlendFactor alphaSrcFactor; // 0x4D4 + u32 pad; // 0x4D5 + type::BlendFactor alphaDstFactor; // 0x4D6 - u32 enableCommon; // 0x4D7 - std::array enable; // 0x4D8 For each render target + u32 enable; // 0x4D7 }; - Register<0x4CF, BlendState> blendState; + Register<0x4CF, BlendStateCommon> blendStateCommon; + + Register<0x4D8, std::array> rtBlendEnable; Register<0x4E0, u32> stencilEnable; struct StencilFront { @@ -226,7 +228,17 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x671, ColorLogicOp> colorLogicOp; - Register<0x780, std::array> independentBlend; + struct IndependentBlend { + u32 seperateAlpha; + type::BlendOp colorOp; + type::BlendFactor colorSrcFactor; + type::BlendFactor colorDstFactor; + type::BlendOp alphaOp; + type::BlendFactor alphaSrcFactor; + type::BlendFactor alphaDstFactor; + u32 _pad_; + }; + Register<0x780, std::array> independentBlend; Register<0x800, std::array> setProgram;