fixed_pipeline_state: Pack blending state

Reduce FixedPipelineState's size to 364 bytes.
merge-requests/60/head
ReinUsesLisp 2020-04-18 05:41:56 +07:00
parent 548dd27f45
commit b571c92dfd
3 changed files with 227 additions and 98 deletions

@ -95,71 +95,58 @@ void FixedPipelineState::Rasterizer::Fill(const Maxwell& regs) noexcept {
std::memcpy(&point_size, &regs.point_size, sizeof(point_size)); // TODO: C++20 std::bit_cast
}
namespace {
constexpr FixedPipelineState::BlendingAttachment GetBlendingAttachmentState(
const Maxwell& regs, std::size_t render_target) {
const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : render_target];
const std::array components = {mask.R != 0, mask.G != 0, mask.B != 0, mask.A != 0};
const FixedPipelineState::BlendingAttachment default_blending(
false, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One,
Maxwell::Blend::Factor::Zero, Maxwell::Blend::Equation::Add, Maxwell::Blend::Factor::One,
Maxwell::Blend::Factor::Zero, components);
if (render_target >= regs.rt_control.count) {
return default_blending;
void FixedPipelineState::ColorBlending::Fill(const Maxwell& regs) noexcept {
for (std::size_t index = 0; index < std::size(attachments); ++index) {
attachments[index].Fill(regs, index);
}
}
void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size_t index) {
const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : index];
raw = 0;
mask_r.Assign(mask.R);
mask_g.Assign(mask.G);
mask_b.Assign(mask.B);
mask_a.Assign(mask.A);
// TODO: C++20 Use templated lambda to deduplicate code
if (!regs.independent_blend_enable) {
const auto& src = regs.blend;
if (!src.enable[render_target]) {
return default_blending;
if (!src.enable[index]) {
return;
}
return FixedPipelineState::BlendingAttachment(
true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a,
src.factor_source_a, src.factor_dest_a, components);
equation_rgb.Assign(PackBlendEquation(src.equation_rgb));
equation_a.Assign(PackBlendEquation(src.equation_a));
factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb));
factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb));
factor_source_a.Assign(PackBlendFactor(src.factor_source_a));
factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a));
enable.Assign(1);
return;
}
if (!regs.blend.enable[render_target]) {
return default_blending;
if (!regs.blend.enable[index]) {
return;
}
const auto& src = regs.independent_blend[render_target];
return FixedPipelineState::BlendingAttachment(
true, src.equation_rgb, src.factor_source_rgb, src.factor_dest_rgb, src.equation_a,
src.factor_source_a, src.factor_dest_a, components);
const auto& src = regs.independent_blend[index];
equation_rgb.Assign(PackBlendEquation(src.equation_rgb));
equation_a.Assign(PackBlendEquation(src.equation_a));
factor_source_rgb.Assign(PackBlendFactor(src.factor_source_rgb));
factor_dest_rgb.Assign(PackBlendFactor(src.factor_dest_rgb));
factor_source_a.Assign(PackBlendFactor(src.factor_source_a));
factor_dest_a.Assign(PackBlendFactor(src.factor_dest_a));
enable.Assign(1);
}
constexpr FixedPipelineState::ColorBlending GetColorBlendingState(const Maxwell& regs) {
return FixedPipelineState::ColorBlending(
{regs.blend_color.r, regs.blend_color.g, regs.blend_color.b, regs.blend_color.a},
regs.rt_control.count,
{GetBlendingAttachmentState(regs, 0), GetBlendingAttachmentState(regs, 1),
GetBlendingAttachmentState(regs, 2), GetBlendingAttachmentState(regs, 3),
GetBlendingAttachmentState(regs, 4), GetBlendingAttachmentState(regs, 5),
GetBlendingAttachmentState(regs, 6), GetBlendingAttachmentState(regs, 7)});
}
} // Anonymous namespace
std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept {
return static_cast<std::size_t>(enable) ^ (static_cast<std::size_t>(rgb_equation) << 5) ^
(static_cast<std::size_t>(src_rgb_func) << 10) ^
(static_cast<std::size_t>(dst_rgb_func) << 15) ^
(static_cast<std::size_t>(a_equation) << 20) ^
(static_cast<std::size_t>(src_a_func) << 25) ^
(static_cast<std::size_t>(dst_a_func) << 30) ^
(static_cast<std::size_t>(components[0]) << 35) ^
(static_cast<std::size_t>(components[1]) << 36) ^
(static_cast<std::size_t>(components[2]) << 37) ^
(static_cast<std::size_t>(components[3]) << 38);
return raw;
}
bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const
noexcept {
return std::tie(enable, rgb_equation, src_rgb_func, dst_rgb_func, a_equation, src_a_func,
dst_a_func, components) ==
std::tie(rhs.enable, rhs.rgb_equation, rhs.src_rgb_func, rhs.dst_rgb_func,
rhs.a_equation, rhs.src_a_func, rhs.dst_a_func, rhs.components);
return raw == rhs.raw;
}
std::size_t FixedPipelineState::VertexInput::Hash() const noexcept {
@ -190,16 +177,15 @@ bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const
}
std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept {
std::size_t hash = attachments_count << 13;
for (std::size_t rt = 0; rt < static_cast<std::size_t>(attachments_count); ++rt) {
std::size_t hash = 0;
for (std::size_t rt = 0; rt < std::size(attachments); ++rt) {
boost::hash_combine(hash, attachments[rt].Hash());
}
return hash;
}
bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const noexcept {
return std::equal(attachments.begin(), attachments.begin() + attachments_count,
rhs.attachments.begin(), rhs.attachments.begin() + rhs.attachments_count);
return attachments == rhs.attachments;
}
std::size_t FixedPipelineState::Hash() const noexcept {
@ -220,7 +206,7 @@ FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
FixedPipelineState fixed_state;
fixed_state.rasterizer.Fill(regs);
fixed_state.depth_stencil.Fill(regs);
fixed_state.color_blending = GetColorBlendingState(regs);
fixed_state.color_blending.Fill(regs);
return fixed_state;
}
@ -312,4 +298,121 @@ Maxwell::LogicOperation FixedPipelineState::UnpackLogicOp(u32 packed) noexcept {
return static_cast<Maxwell::LogicOperation>(packed + 0x1500);
}
u32 FixedPipelineState::PackBlendEquation(Maxwell::Blend::Equation equation) noexcept {
switch (equation) {
case Maxwell::Blend::Equation::Add:
case Maxwell::Blend::Equation::AddGL:
return 0;
case Maxwell::Blend::Equation::Subtract:
case Maxwell::Blend::Equation::SubtractGL:
return 1;
case Maxwell::Blend::Equation::ReverseSubtract:
case Maxwell::Blend::Equation::ReverseSubtractGL:
return 2;
case Maxwell::Blend::Equation::Min:
case Maxwell::Blend::Equation::MinGL:
return 3;
case Maxwell::Blend::Equation::Max:
case Maxwell::Blend::Equation::MaxGL:
return 4;
}
return 0;
}
Maxwell::Blend::Equation FixedPipelineState::UnpackBlendEquation(u32 packed) noexcept {
static constexpr std::array LUT = {
Maxwell::Blend::Equation::Add, Maxwell::Blend::Equation::Subtract,
Maxwell::Blend::Equation::ReverseSubtract, Maxwell::Blend::Equation::Min,
Maxwell::Blend::Equation::Max};
return LUT[packed];
}
u32 FixedPipelineState::PackBlendFactor(Maxwell::Blend::Factor factor) noexcept {
switch (factor) {
case Maxwell::Blend::Factor::Zero:
case Maxwell::Blend::Factor::ZeroGL:
return 0;
case Maxwell::Blend::Factor::One:
case Maxwell::Blend::Factor::OneGL:
return 1;
case Maxwell::Blend::Factor::SourceColor:
case Maxwell::Blend::Factor::SourceColorGL:
return 2;
case Maxwell::Blend::Factor::OneMinusSourceColor:
case Maxwell::Blend::Factor::OneMinusSourceColorGL:
return 3;
case Maxwell::Blend::Factor::SourceAlpha:
case Maxwell::Blend::Factor::SourceAlphaGL:
return 4;
case Maxwell::Blend::Factor::OneMinusSourceAlpha:
case Maxwell::Blend::Factor::OneMinusSourceAlphaGL:
return 5;
case Maxwell::Blend::Factor::DestAlpha:
case Maxwell::Blend::Factor::DestAlphaGL:
return 6;
case Maxwell::Blend::Factor::OneMinusDestAlpha:
case Maxwell::Blend::Factor::OneMinusDestAlphaGL:
return 7;
case Maxwell::Blend::Factor::DestColor:
case Maxwell::Blend::Factor::DestColorGL:
return 8;
case Maxwell::Blend::Factor::OneMinusDestColor:
case Maxwell::Blend::Factor::OneMinusDestColorGL:
return 9;
case Maxwell::Blend::Factor::SourceAlphaSaturate:
case Maxwell::Blend::Factor::SourceAlphaSaturateGL:
return 10;
case Maxwell::Blend::Factor::Source1Color:
case Maxwell::Blend::Factor::Source1ColorGL:
return 11;
case Maxwell::Blend::Factor::OneMinusSource1Color:
case Maxwell::Blend::Factor::OneMinusSource1ColorGL:
return 12;
case Maxwell::Blend::Factor::Source1Alpha:
case Maxwell::Blend::Factor::Source1AlphaGL:
return 13;
case Maxwell::Blend::Factor::OneMinusSource1Alpha:
case Maxwell::Blend::Factor::OneMinusSource1AlphaGL:
return 14;
case Maxwell::Blend::Factor::ConstantColor:
case Maxwell::Blend::Factor::ConstantColorGL:
return 15;
case Maxwell::Blend::Factor::OneMinusConstantColor:
case Maxwell::Blend::Factor::OneMinusConstantColorGL:
return 16;
case Maxwell::Blend::Factor::ConstantAlpha:
case Maxwell::Blend::Factor::ConstantAlphaGL:
return 17;
case Maxwell::Blend::Factor::OneMinusConstantAlpha:
case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
return 18;
}
return 0;
}
Maxwell::Blend::Factor FixedPipelineState::UnpackBlendFactor(u32 packed) noexcept {
static constexpr std::array LUT = {
Maxwell::Blend::Factor::Zero,
Maxwell::Blend::Factor::One,
Maxwell::Blend::Factor::SourceColor,
Maxwell::Blend::Factor::OneMinusSourceColor,
Maxwell::Blend::Factor::SourceAlpha,
Maxwell::Blend::Factor::OneMinusSourceAlpha,
Maxwell::Blend::Factor::DestAlpha,
Maxwell::Blend::Factor::OneMinusDestAlpha,
Maxwell::Blend::Factor::DestColor,
Maxwell::Blend::Factor::OneMinusDestColor,
Maxwell::Blend::Factor::SourceAlphaSaturate,
Maxwell::Blend::Factor::Source1Color,
Maxwell::Blend::Factor::OneMinusSource1Color,
Maxwell::Blend::Factor::Source1Alpha,
Maxwell::Blend::Factor::OneMinusSource1Alpha,
Maxwell::Blend::Factor::ConstantColor,
Maxwell::Blend::Factor::OneMinusConstantColor,
Maxwell::Blend::Factor::ConstantAlpha,
Maxwell::Blend::Factor::OneMinusConstantAlpha,
};
return LUT[packed];
}
} // namespace Vulkan

@ -42,27 +42,29 @@ struct FixedPipelineState {
static u32 PackLogicOp(Maxwell::LogicOperation op) noexcept;
static Maxwell::LogicOperation UnpackLogicOp(u32 packed) noexcept;
struct BlendingAttachment {
constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation,
Maxwell::Blend::Factor src_rgb_func,
Maxwell::Blend::Factor dst_rgb_func,
Maxwell::Blend::Equation a_equation,
Maxwell::Blend::Factor src_a_func,
Maxwell::Blend::Factor dst_a_func,
std::array<bool, 4> components)
: enable{enable}, rgb_equation{rgb_equation}, src_rgb_func{src_rgb_func},
dst_rgb_func{dst_rgb_func}, a_equation{a_equation}, src_a_func{src_a_func},
dst_a_func{dst_a_func}, components{components} {}
BlendingAttachment() = default;
static u32 PackBlendEquation(Maxwell::Blend::Equation equation) noexcept;
static Maxwell::Blend::Equation UnpackBlendEquation(u32 packed) noexcept;
bool enable;
Maxwell::Blend::Equation rgb_equation;
Maxwell::Blend::Factor src_rgb_func;
Maxwell::Blend::Factor dst_rgb_func;
Maxwell::Blend::Equation a_equation;
Maxwell::Blend::Factor src_a_func;
Maxwell::Blend::Factor dst_a_func;
std::array<bool, 4> components;
static u32 PackBlendFactor(Maxwell::Blend::Factor factor) noexcept;
static Maxwell::Blend::Factor UnpackBlendFactor(u32 packed) noexcept;
struct BlendingAttachment {
union {
u32 raw;
BitField<0, 1, u32> mask_r;
BitField<1, 1, u32> mask_g;
BitField<2, 1, u32> mask_b;
BitField<3, 1, u32> mask_a;
BitField<4, 3, u32> equation_rgb;
BitField<7, 3, u32> equation_a;
BitField<10, 5, u32> factor_source_rgb;
BitField<15, 5, u32> factor_dest_rgb;
BitField<20, 5, u32> factor_source_a;
BitField<25, 5, u32> factor_dest_a;
BitField<30, 1, u32> enable;
};
void Fill(const Maxwell& regs, std::size_t index);
std::size_t Hash() const noexcept;
@ -71,7 +73,36 @@ struct FixedPipelineState {
bool operator!=(const BlendingAttachment& rhs) const noexcept {
return !operator==(rhs);
}
constexpr std::array<bool, 4> Mask() const noexcept {
return {mask_r != 0, mask_g != 0, mask_b != 0, mask_a != 0};
}
Maxwell::Blend::Equation EquationRGB() const noexcept {
return UnpackBlendEquation(equation_rgb.Value());
}
Maxwell::Blend::Equation EquationAlpha() const noexcept {
return UnpackBlendEquation(equation_a.Value());
}
Maxwell::Blend::Factor SourceRGBFactor() const noexcept {
return UnpackBlendFactor(factor_source_rgb.Value());
}
Maxwell::Blend::Factor DestRGBFactor() const noexcept {
return UnpackBlendFactor(factor_dest_rgb.Value());
}
Maxwell::Blend::Factor SourceAlphaFactor() const noexcept {
return UnpackBlendFactor(factor_source_a.Value());
}
Maxwell::Blend::Factor DestAlphaFactor() const noexcept {
return UnpackBlendFactor(factor_dest_a.Value());
}
};
static_assert(IsHashable<BlendingAttachment>);
struct VertexInput {
union Binding {
@ -231,15 +262,10 @@ struct FixedPipelineState {
static_assert(IsHashable<DepthStencil>);
struct ColorBlending {
constexpr ColorBlending(
std::array<float, 4> blend_constants, std::size_t attachments_count,
std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments)
: attachments_count{attachments_count}, attachments{attachments} {}
ColorBlending() = default;
std::size_t attachments_count;
std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments;
void Fill(const Maxwell& regs) noexcept;
std::size_t Hash() const noexcept;
bool operator==(const ColorBlending& rhs) const noexcept;
@ -248,6 +274,7 @@ struct FixedPipelineState {
return !operator==(rhs);
}
};
static_assert(IsHashable<ColorBlending>);
VertexInput vertex_input;
Rasterizer rasterizer;

@ -286,29 +286,28 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
depth_stencil_ci.maxDepthBounds = 0.0f;
std::array<VkPipelineColorBlendAttachmentState, Maxwell::NumRenderTargets> cb_attachments;
const std::size_t num_attachments =
std::min(cd.attachments_count, renderpass_params.color_attachments.size());
for (std::size_t i = 0; i < num_attachments; ++i) {
static constexpr std::array component_table = {
const std::size_t num_attachments = renderpass_params.color_attachments.size();
for (std::size_t index = 0; index < num_attachments; ++index) {
static constexpr std::array COMPONENT_TABLE = {
VK_COLOR_COMPONENT_R_BIT, VK_COLOR_COMPONENT_G_BIT, VK_COLOR_COMPONENT_B_BIT,
VK_COLOR_COMPONENT_A_BIT};
const auto& blend = cd.attachments[i];
const auto& blend = cd.attachments[index];
VkColorComponentFlags color_components = 0;
for (std::size_t j = 0; j < component_table.size(); ++j) {
if (blend.components[j]) {
color_components |= component_table[j];
for (std::size_t i = 0; i < COMPONENT_TABLE.size(); ++i) {
if (blend.Mask()[i]) {
color_components |= COMPONENT_TABLE[i];
}
}
VkPipelineColorBlendAttachmentState& attachment = cb_attachments[i];
attachment.blendEnable = blend.enable;
attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.src_rgb_func);
attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.dst_rgb_func);
attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.rgb_equation);
attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.src_a_func);
attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.dst_a_func);
attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.a_equation);
VkPipelineColorBlendAttachmentState& attachment = cb_attachments[index];
attachment.blendEnable = blend.enable != 0;
attachment.srcColorBlendFactor = MaxwellToVK::BlendFactor(blend.SourceRGBFactor());
attachment.dstColorBlendFactor = MaxwellToVK::BlendFactor(blend.DestRGBFactor());
attachment.colorBlendOp = MaxwellToVK::BlendEquation(blend.EquationRGB());
attachment.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.SourceAlphaFactor());
attachment.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(blend.DestAlphaFactor());
attachment.alphaBlendOp = MaxwellToVK::BlendEquation(blend.EquationAlpha());
attachment.colorWriteMask = color_components;
}