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.
This commit is contained in:
PixelyIon 2021-11-15 23:52:47 +05:30
parent 2ceb6465e8
commit 92809f8a78
4 changed files with 349 additions and 87 deletions

View File

@ -482,7 +482,11 @@ namespace skyline::gpu::interconnect {
/* Color Blending */
private:
vk::PipelineColorBlendStateCreateInfo blendState{};
std::array<vk::PipelineColorBlendAttachmentState, maxwell3d::RenderTargetCount> 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;
}
};
}

View File

@ -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;

View File

@ -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); \

View File

@ -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<type::VertexAttribute, 0x20>> 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<float, type::BlendColorChannelCount>> 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<u32, 8> enable; // 0x4D8 For each render target
u32 enable; // 0x4D7
};
Register<0x4CF, BlendState> blendState;
Register<0x4CF, BlendStateCommon> blendStateCommon;
Register<0x4D8, std::array<u32, type::RenderTargetCount>> 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<type::Blend, type::RenderTargetCount>> 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, type::RenderTargetCount>> independentBlend;
Register<0x800, std::array<type::SetProgramInfo, type::StageCount>> setProgram;