fixed_pipeline_state: Pack depth stencil state

Reduce FixedPipelineState's size to 632 bytes.
merge-requests/60/head
ReinUsesLisp 2020-04-18 00:05:41 +07:00
parent ab6704f20c
commit 7790144a55
3 changed files with 139 additions and 96 deletions

@ -12,23 +12,32 @@
namespace Vulkan { namespace Vulkan {
namespace { void FixedPipelineState::DepthStencil::Fill(const Maxwell& regs) noexcept {
raw = 0;
constexpr FixedPipelineState::DepthStencil GetDepthStencilState(const Maxwell& regs) { front.action_stencil_fail.Assign(PackStencilOp(regs.stencil_front_op_fail));
const FixedPipelineState::StencilFace front_stencil( front.action_depth_fail.Assign(PackStencilOp(regs.stencil_front_op_zfail));
regs.stencil_front_op_fail, regs.stencil_front_op_zfail, regs.stencil_front_op_zpass, front.action_depth_pass.Assign(PackStencilOp(regs.stencil_front_op_zpass));
regs.stencil_front_func_func); front.test_func.Assign(PackComparisonOp(regs.stencil_front_func_func));
const FixedPipelineState::StencilFace back_stencil = if (regs.stencil_two_side_enable) {
regs.stencil_two_side_enable back.action_stencil_fail.Assign(PackStencilOp(regs.stencil_back_op_fail));
? FixedPipelineState::StencilFace(regs.stencil_back_op_fail, regs.stencil_back_op_zfail, back.action_depth_fail.Assign(PackStencilOp(regs.stencil_back_op_zfail));
regs.stencil_back_op_zpass, back.action_depth_pass.Assign(PackStencilOp(regs.stencil_back_op_zpass));
regs.stencil_back_func_func) back.test_func.Assign(PackComparisonOp(regs.stencil_back_func_func));
: front_stencil; } else {
return FixedPipelineState::DepthStencil( back.action_stencil_fail.Assign(front.action_stencil_fail);
regs.depth_test_enable == 1, regs.depth_write_enabled == 1, regs.depth_bounds_enable == 1, back.action_depth_fail.Assign(front.action_depth_fail);
regs.stencil_enable == 1, regs.depth_test_func, front_stencil, back_stencil); back.action_depth_pass.Assign(front.action_depth_pass);
back.test_func.Assign(front.test_func);
}
depth_test_enable.Assign(regs.depth_test_enable);
depth_write_enable.Assign(regs.depth_write_enabled);
depth_bounds_enable.Assign(regs.depth_bounds_enable);
stencil_enable.Assign(regs.stencil_enable);
depth_test_func.Assign(PackComparisonOp(regs.depth_test_func));
} }
namespace {
constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) {
return FixedPipelineState::InputAssembly( return FixedPipelineState::InputAssembly(
regs.draw.topology, regs.primitive_restart.enabled, regs.draw.topology, regs.primitive_restart.enabled,
@ -129,19 +138,6 @@ constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs)
} // Anonymous namespace } // Anonymous namespace
std::size_t FixedPipelineState::StencilFace::Hash() const noexcept {
return static_cast<std::size_t>(action_stencil_fail) ^
(static_cast<std::size_t>(action_depth_fail) << 4) ^
(static_cast<std::size_t>(action_depth_fail) << 20) ^
(static_cast<std::size_t>(action_depth_pass) << 36);
}
bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const noexcept {
return std::tie(action_stencil_fail, action_depth_fail, action_depth_pass, test_func) ==
std::tie(rhs.action_stencil_fail, rhs.action_depth_fail, rhs.action_depth_pass,
rhs.test_func);
}
std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept {
return static_cast<std::size_t>(enable) ^ (static_cast<std::size_t>(rgb_equation) << 5) ^ 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>(src_rgb_func) << 10) ^
@ -212,22 +208,11 @@ bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noe
} }
std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept {
std::size_t hash = static_cast<std::size_t>(depth_test_enable) ^ return raw;
(static_cast<std::size_t>(depth_write_enable) << 1) ^
(static_cast<std::size_t>(depth_bounds_enable) << 2) ^
(static_cast<std::size_t>(stencil_enable) << 3) ^
(static_cast<std::size_t>(depth_test_function) << 4);
boost::hash_combine(hash, front_stencil.Hash());
boost::hash_combine(hash, back_stencil.Hash());
return hash;
} }
bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept { bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept {
return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, return raw == rhs.raw;
stencil_enable, front_stencil, back_stencil) ==
std::tie(rhs.depth_test_enable, rhs.depth_write_enable, rhs.depth_bounds_enable,
rhs.depth_test_function, rhs.stencil_enable, rhs.front_stencil,
rhs.back_stencil);
} }
std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept { std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept {
@ -266,9 +251,60 @@ FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
fixed_state.input_assembly = GetInputAssemblyState(regs); fixed_state.input_assembly = GetInputAssemblyState(regs);
fixed_state.tessellation = GetTessellationState(regs); fixed_state.tessellation = GetTessellationState(regs);
fixed_state.rasterizer = GetRasterizerState(regs); fixed_state.rasterizer = GetRasterizerState(regs);
fixed_state.depth_stencil = GetDepthStencilState(regs); fixed_state.depth_stencil.Fill(regs);
fixed_state.color_blending = GetColorBlendingState(regs); fixed_state.color_blending = GetColorBlendingState(regs);
return fixed_state; return fixed_state;
} }
u32 FixedPipelineState::PackComparisonOp(Maxwell::ComparisonOp op) noexcept {
// OpenGL enums go from 0x200 to 0x207 and the others from 1 to 8
// If we substract 0x200 to OpenGL enums and 1 to the others we get a 0-7 range.
// Perfect for a hash.
const u32 value = static_cast<u32>(op);
return value - (value >= 0x200 ? 0x200 : 1);
}
Maxwell::ComparisonOp FixedPipelineState::UnpackComparisonOp(u32 packed) noexcept {
// Read PackComparisonOp for the logic behind this.
return static_cast<Maxwell::ComparisonOp>(packed + 1);
}
u32 FixedPipelineState::PackStencilOp(Maxwell::StencilOp op) noexcept {
switch (op) {
case Maxwell::StencilOp::Keep:
case Maxwell::StencilOp::KeepOGL:
return 0;
case Maxwell::StencilOp::Zero:
case Maxwell::StencilOp::ZeroOGL:
return 1;
case Maxwell::StencilOp::Replace:
case Maxwell::StencilOp::ReplaceOGL:
return 2;
case Maxwell::StencilOp::Incr:
case Maxwell::StencilOp::IncrOGL:
return 3;
case Maxwell::StencilOp::Decr:
case Maxwell::StencilOp::DecrOGL:
return 4;
case Maxwell::StencilOp::Invert:
case Maxwell::StencilOp::InvertOGL:
return 5;
case Maxwell::StencilOp::IncrWrap:
case Maxwell::StencilOp::IncrWrapOGL:
return 6;
case Maxwell::StencilOp::DecrWrap:
case Maxwell::StencilOp::DecrWrapOGL:
return 7;
}
return 0;
}
Maxwell::StencilOp FixedPipelineState::UnpackStencilOp(u32 packed) noexcept {
static constexpr std::array LUT = {Maxwell::StencilOp::Keep, Maxwell::StencilOp::Zero,
Maxwell::StencilOp::Replace, Maxwell::StencilOp::Incr,
Maxwell::StencilOp::Decr, Maxwell::StencilOp::Invert,
Maxwell::StencilOp::IncrWrap, Maxwell::StencilOp::DecrWrap};
return LUT[packed];
}
} // namespace Vulkan } // namespace Vulkan

@ -24,27 +24,11 @@ inline constexpr bool IsHashable = std::has_unique_object_representations_v<T>&&
std::is_trivially_copyable_v<T>&& std::is_trivially_constructible_v<T>; std::is_trivially_copyable_v<T>&& std::is_trivially_constructible_v<T>;
struct FixedPipelineState { struct FixedPipelineState {
struct StencilFace { static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept;
constexpr StencilFace(Maxwell::StencilOp action_stencil_fail, static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept;
Maxwell::StencilOp action_depth_fail,
Maxwell::StencilOp action_depth_pass, Maxwell::ComparisonOp test_func)
: action_stencil_fail{action_stencil_fail}, action_depth_fail{action_depth_fail},
action_depth_pass{action_depth_pass}, test_func{test_func} {}
StencilFace() = default;
Maxwell::StencilOp action_stencil_fail; static u32 PackStencilOp(Maxwell::StencilOp op) noexcept;
Maxwell::StencilOp action_depth_fail; static Maxwell::StencilOp UnpackStencilOp(u32 packed) noexcept;
Maxwell::StencilOp action_depth_pass;
Maxwell::ComparisonOp test_func;
std::size_t Hash() const noexcept;
bool operator==(const StencilFace& rhs) const noexcept;
bool operator!=(const StencilFace& rhs) const noexcept {
return !operator==(rhs);
}
};
struct BlendingAttachment { struct BlendingAttachment {
constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation, constexpr BlendingAttachment(bool enable, Maxwell::Blend::Equation rgb_equation,
@ -202,23 +186,42 @@ struct FixedPipelineState {
}; };
struct DepthStencil { struct DepthStencil {
constexpr DepthStencil(bool depth_test_enable, bool depth_write_enable, template <std::size_t Position>
bool depth_bounds_enable, bool stencil_enable, union StencilFace {
Maxwell::ComparisonOp depth_test_function, StencilFace front_stencil, BitField<Position + 0, 3, u32> action_stencil_fail;
StencilFace back_stencil) BitField<Position + 3, 3, u32> action_depth_fail;
: depth_test_enable{depth_test_enable}, depth_write_enable{depth_write_enable}, BitField<Position + 6, 3, u32> action_depth_pass;
depth_bounds_enable{depth_bounds_enable}, stencil_enable{stencil_enable}, BitField<Position + 9, 3, u32> test_func;
depth_test_function{depth_test_function}, front_stencil{front_stencil},
back_stencil{back_stencil} {}
DepthStencil() = default;
bool depth_test_enable; Maxwell::StencilOp ActionStencilFail() const noexcept {
bool depth_write_enable; return UnpackStencilOp(action_stencil_fail);
bool depth_bounds_enable; }
bool stencil_enable;
Maxwell::ComparisonOp depth_test_function; Maxwell::StencilOp ActionDepthFail() const noexcept {
StencilFace front_stencil; return UnpackStencilOp(action_depth_fail);
StencilFace back_stencil; }
Maxwell::StencilOp ActionDepthPass() const noexcept {
return UnpackStencilOp(action_depth_pass);
}
Maxwell::ComparisonOp TestFunc() const noexcept {
return UnpackComparisonOp(test_func);
}
};
union {
u32 raw;
StencilFace<0> front;
StencilFace<12> back;
BitField<24, 1, u32> depth_test_enable;
BitField<25, 1, u32> depth_write_enable;
BitField<26, 1, u32> depth_bounds_enable;
BitField<27, 1, u32> stencil_enable;
BitField<28, 3, u32> depth_test_func;
};
void Fill(const Maxwell& regs) noexcept;
std::size_t Hash() const noexcept; std::size_t Hash() const noexcept;
@ -227,7 +230,12 @@ struct FixedPipelineState {
bool operator!=(const DepthStencil& rhs) const noexcept { bool operator!=(const DepthStencil& rhs) const noexcept {
return !operator==(rhs); return !operator==(rhs);
} }
Maxwell::ComparisonOp DepthTestFunc() const noexcept {
return UnpackComparisonOp(depth_test_func);
}
}; };
static_assert(IsHashable<DepthStencil>);
struct ColorBlending { struct ColorBlending {
constexpr ColorBlending( constexpr ColorBlending(
@ -248,6 +256,13 @@ struct FixedPipelineState {
} }
}; };
VertexInput vertex_input;
InputAssembly input_assembly;
Tessellation tessellation;
Rasterizer rasterizer;
DepthStencil depth_stencil;
ColorBlending color_blending;
std::size_t Hash() const noexcept; std::size_t Hash() const noexcept;
bool operator==(const FixedPipelineState& rhs) const noexcept; bool operator==(const FixedPipelineState& rhs) const noexcept;
@ -255,15 +270,7 @@ struct FixedPipelineState {
bool operator!=(const FixedPipelineState& rhs) const noexcept { bool operator!=(const FixedPipelineState& rhs) const noexcept {
return !operator==(rhs); return !operator==(rhs);
} }
VertexInput vertex_input;
InputAssembly input_assembly;
Tessellation tessellation;
Rasterizer rasterizer;
DepthStencil depth_stencil;
ColorBlending color_blending;
}; };
static_assert(std::is_trivially_copyable_v<FixedPipelineState::StencilFace>);
static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>); static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>);
static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>); static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>);
static_assert(std::is_trivially_copyable_v<FixedPipelineState::InputAssembly>); static_assert(std::is_trivially_copyable_v<FixedPipelineState::InputAssembly>);

@ -26,12 +26,13 @@ MICROPROFILE_DECLARE(Vulkan_PipelineCache);
namespace { namespace {
VkStencilOpState GetStencilFaceState(const FixedPipelineState::StencilFace& face) { template <class StencilFace>
VkStencilOpState GetStencilFaceState(const StencilFace& face) {
VkStencilOpState state; VkStencilOpState state;
state.failOp = MaxwellToVK::StencilOp(face.action_stencil_fail); state.failOp = MaxwellToVK::StencilOp(face.ActionStencilFail());
state.passOp = MaxwellToVK::StencilOp(face.action_depth_pass); state.passOp = MaxwellToVK::StencilOp(face.ActionDepthPass());
state.depthFailOp = MaxwellToVK::StencilOp(face.action_depth_fail); state.depthFailOp = MaxwellToVK::StencilOp(face.ActionDepthFail());
state.compareOp = MaxwellToVK::ComparisonOp(face.test_func); state.compareOp = MaxwellToVK::ComparisonOp(face.TestFunc());
state.compareMask = 0; state.compareMask = 0;
state.writeMask = 0; state.writeMask = 0;
state.reference = 0; state.reference = 0;
@ -277,13 +278,12 @@ vk::Pipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& renderpa
depth_stencil_ci.flags = 0; depth_stencil_ci.flags = 0;
depth_stencil_ci.depthTestEnable = ds.depth_test_enable; depth_stencil_ci.depthTestEnable = ds.depth_test_enable;
depth_stencil_ci.depthWriteEnable = ds.depth_write_enable; depth_stencil_ci.depthWriteEnable = ds.depth_write_enable;
depth_stencil_ci.depthCompareOp = ds.depth_test_enable depth_stencil_ci.depthCompareOp =
? MaxwellToVK::ComparisonOp(ds.depth_test_function) ds.depth_test_enable ? MaxwellToVK::ComparisonOp(ds.DepthTestFunc()) : VK_COMPARE_OP_ALWAYS;
: VK_COMPARE_OP_ALWAYS;
depth_stencil_ci.depthBoundsTestEnable = ds.depth_bounds_enable; depth_stencil_ci.depthBoundsTestEnable = ds.depth_bounds_enable;
depth_stencil_ci.stencilTestEnable = ds.stencil_enable; depth_stencil_ci.stencilTestEnable = ds.stencil_enable;
depth_stencil_ci.front = GetStencilFaceState(ds.front_stencil); depth_stencil_ci.front = GetStencilFaceState(ds.front);
depth_stencil_ci.back = GetStencilFaceState(ds.back_stencil); depth_stencil_ci.back = GetStencilFaceState(ds.back);
depth_stencil_ci.minDepthBounds = 0.0f; depth_stencil_ci.minDepthBounds = 0.0f;
depth_stencil_ci.maxDepthBounds = 0.0f; depth_stencil_ci.maxDepthBounds = 0.0f;