From 01eb16e59afcc0ddce608f91251837877da30854 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Fri, 12 Nov 2021 20:15:32 +0530 Subject: [PATCH] Implement Maxwell3D Color Logic Operations Implements a basic part of Vulkan blending state which are color logic operations applied on the framebuffer after running the fragment shader. It is an optional feature in Vulkan and not supported on any mobile GPU vendor aside from ImgTec/NVIDIA by default. --- .../gpu/interconnect/graphics_context.h | 52 +++++++++++++++++++ .../main/cpp/skyline/gpu/quirk_manager.cpp | 4 +- app/src/main/cpp/skyline/gpu/quirk_manager.h | 1 + .../skyline/soc/gm20b/engines/maxwell/types.h | 22 ++++++++ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 8 +++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 6 +++ 6 files changed, 92 insertions(+), 1 deletion(-) 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 c35d6242..ebdab4b7 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -479,5 +479,57 @@ namespace skyline::gpu::interconnect { void SetDepthBiasSlopeFactor(float factor) { rasterizerState.get().depthBiasSlopeFactor = factor; } + + /* Color Blending */ + private: + vk::PipelineColorBlendStateCreateInfo blendState{}; + + public: + void SetBlendLogicOpEnable(bool enabled) { + if (!gpu.quirks.supportsLogicOp && enabled) { + Logger::Warn("Cannot enable framebuffer logical operation without host GPU support"); + return; + } + blendState.logicOpEnable = enabled; + } + + void SetBlendLogicOpType(maxwell3d::ColorLogicOp logicOp) { + blendState.logicOp = [logicOp]() { + switch (logicOp) { + case maxwell3d::ColorLogicOp::Clear: + return vk::LogicOp::eClear; + case maxwell3d::ColorLogicOp::And: + return vk::LogicOp::eAnd; + case maxwell3d::ColorLogicOp::AndReverse: + return vk::LogicOp::eAndReverse; + case maxwell3d::ColorLogicOp::Copy: + return vk::LogicOp::eCopy; + case maxwell3d::ColorLogicOp::AndInverted: + return vk::LogicOp::eAndInverted; + case maxwell3d::ColorLogicOp::Noop: + return vk::LogicOp::eNoOp; + case maxwell3d::ColorLogicOp::Xor: + return vk::LogicOp::eXor; + case maxwell3d::ColorLogicOp::Or: + return vk::LogicOp::eOr; + case maxwell3d::ColorLogicOp::Nor: + return vk::LogicOp::eNor; + case maxwell3d::ColorLogicOp::Equiv: + return vk::LogicOp::eEquivalent; + case maxwell3d::ColorLogicOp::Invert: + return vk::LogicOp::eInvert; + case maxwell3d::ColorLogicOp::OrReverse: + return vk::LogicOp::eOrReverse; + case maxwell3d::ColorLogicOp::CopyInverted: + return vk::LogicOp::eCopyInverted; + case maxwell3d::ColorLogicOp::OrInverted: + return vk::LogicOp::eOrInverted; + case maxwell3d::ColorLogicOp::Nand: + return vk::LogicOp::eNand; + case maxwell3d::ColorLogicOp::Set: + return vk::LogicOp::eSet; + } + }(); + } }; } diff --git a/app/src/main/cpp/skyline/gpu/quirk_manager.cpp b/app/src/main/cpp/skyline/gpu/quirk_manager.cpp index f19a4966..528d74e0 100644 --- a/app/src/main/cpp/skyline/gpu/quirk_manager.cpp +++ b/app/src/main/cpp/skyline/gpu/quirk_manager.cpp @@ -4,7 +4,7 @@ #include "quirk_manager.h" namespace skyline { - QuirkManager::QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features, const std::vector &extensions) { + QuirkManager::QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features2, const std::vector &extensions) { for (auto &extension : extensions) { #define EXT_SET(name, property) \ case util::Hash(name): \ @@ -27,5 +27,7 @@ namespace skyline { #undef EXT_SET #undef EXT_SET_V } + + supportsLogicOp = features2.features.logicOp; } } diff --git a/app/src/main/cpp/skyline/gpu/quirk_manager.h b/app/src/main/cpp/skyline/gpu/quirk_manager.h index d1133b1d..404e70fd 100644 --- a/app/src/main/cpp/skyline/gpu/quirk_manager.h +++ b/app/src/main/cpp/skyline/gpu/quirk_manager.h @@ -13,6 +13,7 @@ namespace skyline { class QuirkManager { public: bool supportsLastProvokingVertex{}; //!< If the device supports setting the last vertex as the provoking vertex (with VK_EXT_provoking_vertex) + bool supportsLogicOp{}; //!< If the device supports framebuffer logical operations during blending QuirkManager() = default; 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 182c02f0..f6d59ecf 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 @@ -540,6 +540,28 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { }; static_assert(sizeof(SemaphoreInfo) == sizeof(u32)); + /** + * @brief The logical operations that can be performed on the framebuffer after the fragment shader + */ + enum class ColorLogicOp : u32 { + Clear = 0x1500, + And = 0x1501, + AndReverse = 0x1502, + Copy = 0x1503, + AndInverted = 0x1504, + Noop = 0x1505, + Xor = 0x1506, + Or = 0x1507, + Nor = 0x1508, + Equiv = 0x1509, + Invert = 0x150A, + OrReverse = 0x150B, + CopyInverted = 0x150C, + OrInverted = 0x150D, + Nand = 0x150E, + Set = 0x150F, + }; + constexpr static size_t StageCount{6}; //!< Amount of pipeline stages on Maxwell 3D /** 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 e4d6361b..725bbf45 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 @@ -237,6 +237,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetDepthClampEnabled(!viewVolumeClipControl.depthClampDisable); }) + MAXWELL3D_STRUCT_CASE(colorLogicOp, enable, { + context.SetBlendLogicOpEnable(enable); + }) + + MAXWELL3D_STRUCT_CASE(colorLogicOp, type, { + context.SetBlendLogicOpType(type); + }) + #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 e749b0b7..d5af0ee8 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 @@ -219,6 +219,12 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x6C0, Semaphore> semaphore; + struct ColorLogicOp { + u32 enable; + type::ColorLogicOp type; + }; + Register<0x671, ColorLogicOp> colorLogicOp; + Register<0x780, std::array> independentBlend; Register<0x800, std::array> setProgram;