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.
This commit is contained in:
PixelyIon 2021-11-12 20:15:32 +05:30
parent 662935c35d
commit 01eb16e59a
6 changed files with 92 additions and 1 deletions

View File

@ -479,5 +479,57 @@ namespace skyline::gpu::interconnect {
void SetDepthBiasSlopeFactor(float factor) { void SetDepthBiasSlopeFactor(float factor) {
rasterizerState.get<vk::PipelineRasterizationStateCreateInfo>().depthBiasSlopeFactor = factor; rasterizerState.get<vk::PipelineRasterizationStateCreateInfo>().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;
}
}();
}
}; };
} }

View File

@ -4,7 +4,7 @@
#include "quirk_manager.h" #include "quirk_manager.h"
namespace skyline { namespace skyline {
QuirkManager::QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features, const std::vector<vk::ExtensionProperties> &extensions) { QuirkManager::QuirkManager(vk::PhysicalDeviceProperties properties, vk::PhysicalDeviceFeatures2 features2, const std::vector<vk::ExtensionProperties> &extensions) {
for (auto &extension : extensions) { for (auto &extension : extensions) {
#define EXT_SET(name, property) \ #define EXT_SET(name, property) \
case util::Hash(name): \ case util::Hash(name): \
@ -27,5 +27,7 @@ namespace skyline {
#undef EXT_SET #undef EXT_SET
#undef EXT_SET_V #undef EXT_SET_V
} }
supportsLogicOp = features2.features.logicOp;
} }
} }

View File

@ -13,6 +13,7 @@ namespace skyline {
class QuirkManager { class QuirkManager {
public: public:
bool supportsLastProvokingVertex{}; //!< If the device supports setting the last vertex as the provoking vertex (with VK_EXT_provoking_vertex) 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; QuirkManager() = default;

View File

@ -540,6 +540,28 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type {
}; };
static_assert(sizeof(SemaphoreInfo) == sizeof(u32)); 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 constexpr static size_t StageCount{6}; //!< Amount of pipeline stages on Maxwell 3D
/** /**

View File

@ -237,6 +237,14 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
context.SetDepthClampEnabled(!viewVolumeClipControl.depthClampDisable); 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) \ #define SET_SHADER_ENABLE_CALLBACK(z, index, data) \
MAXWELL3D_ARRAY_STRUCT_CASE(setProgram, index, info, { \ MAXWELL3D_ARRAY_STRUCT_CASE(setProgram, index, info, { \
context.SetShaderEnabled(info.stage, info.enable); \ context.SetShaderEnabled(info.stage, info.enable); \

View File

@ -219,6 +219,12 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
}; };
Register<0x6C0, Semaphore> semaphore; Register<0x6C0, Semaphore> semaphore;
struct ColorLogicOp {
u32 enable;
type::ColorLogicOp type;
};
Register<0x671, ColorLogicOp> colorLogicOp;
Register<0x780, std::array<type::Blend, type::RenderTargetCount>> independentBlend; Register<0x780, std::array<type::Blend, type::RenderTargetCount>> independentBlend;
Register<0x800, std::array<type::SetProgramInfo, type::StageCount>> setProgram; Register<0x800, std::array<type::SetProgramInfo, type::StageCount>> setProgram;