fixed_pipeline_state: Hash and compare the whole structure
Pad FixedPipelineState's size to 384 bytes to be a multiple of 16. Compare the whole struct with std::memcmp and hash with CityHash. Using CityHash instead of a naive hash should reduce the number of collisions. Improve used type traits to ensure this operation is safe. With these changes the improvements to the hashable pipeline state are: Optimized structure Hash: 89 ns Comparison: 103 ns Construction*: 164 ns Struct size: 384 bytes Original structure Hash: 148 ns Equal: 174 ns Construction*: 281 ns Size: 1384 bytes * Attribute state initialization is not measured These measures are averages taken with std::chrono::high_accuracy_clock on MSVC shipped on Visual Studio 16.6.0 Preview 2.1.
This commit is contained in:
parent
b571c92dfd
commit
d62f57cf5a
|
@ -140,66 +140,13 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size
|
||||||
enable.Assign(1);
|
enable.Assign(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept {
|
std::size_t FixedPipelineState::Hash() const noexcept {
|
||||||
return raw;
|
const u64 hash = Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this);
|
||||||
}
|
|
||||||
|
|
||||||
bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const
|
|
||||||
noexcept {
|
|
||||||
return raw == rhs.raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t FixedPipelineState::VertexInput::Hash() const noexcept {
|
|
||||||
// TODO(Rodrigo): Replace this
|
|
||||||
return Common::CityHash64(reinterpret_cast<const char*>(this), sizeof *this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const noexcept {
|
|
||||||
return std::memcmp(this, &rhs, sizeof *this) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept {
|
|
||||||
u64 hash = static_cast<u64>(raw) << 32;
|
|
||||||
std::memcpy(&hash, &point_size, sizeof(u32));
|
|
||||||
return static_cast<std::size_t>(hash);
|
return static_cast<std::size_t>(hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept {
|
|
||||||
return raw == rhs.raw && point_size == rhs.point_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept {
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept {
|
|
||||||
return raw == rhs.raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t FixedPipelineState::ColorBlending::Hash() const noexcept {
|
|
||||||
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 attachments == rhs.attachments;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t FixedPipelineState::Hash() const noexcept {
|
|
||||||
std::size_t hash = 0;
|
|
||||||
boost::hash_combine(hash, vertex_input.Hash());
|
|
||||||
boost::hash_combine(hash, rasterizer.Hash());
|
|
||||||
boost::hash_combine(hash, depth_stencil.Hash());
|
|
||||||
boost::hash_combine(hash, color_blending.Hash());
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept {
|
bool FixedPipelineState::operator==(const FixedPipelineState& rhs) const noexcept {
|
||||||
return std::tie(vertex_input, rasterizer, depth_stencil, color_blending) ==
|
return std::memcmp(this, &rhs, sizeof *this) == 0;
|
||||||
std::tie(rhs.vertex_input, rhs.rasterizer, rhs.depth_stencil, rhs.color_blending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
|
FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
|
||||||
|
@ -207,6 +154,7 @@ FixedPipelineState GetFixedPipelineState(const Maxwell& regs) {
|
||||||
fixed_state.rasterizer.Fill(regs);
|
fixed_state.rasterizer.Fill(regs);
|
||||||
fixed_state.depth_stencil.Fill(regs);
|
fixed_state.depth_stencil.Fill(regs);
|
||||||
fixed_state.color_blending.Fill(regs);
|
fixed_state.color_blending.Fill(regs);
|
||||||
|
fixed_state.padding = {};
|
||||||
return fixed_state;
|
return fixed_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,13 +17,7 @@ namespace Vulkan {
|
||||||
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
// TODO(Rodrigo): Optimize this structure.
|
struct alignas(32) FixedPipelineState {
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline constexpr bool IsHashable = std::has_unique_object_representations_v<T>&&
|
|
||||||
std::is_trivially_copyable_v<T>&& std::is_trivially_constructible_v<T>;
|
|
||||||
|
|
||||||
struct FixedPipelineState {
|
|
||||||
static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept;
|
static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept;
|
||||||
static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept;
|
static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept;
|
||||||
|
|
||||||
|
@ -102,7 +96,6 @@ struct FixedPipelineState {
|
||||||
return UnpackBlendFactor(factor_dest_a.Value());
|
return UnpackBlendFactor(factor_dest_a.Value());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(IsHashable<BlendingAttachment>);
|
|
||||||
|
|
||||||
struct VertexInput {
|
struct VertexInput {
|
||||||
union Binding {
|
union Binding {
|
||||||
|
@ -151,16 +144,7 @@ struct FixedPipelineState {
|
||||||
attribute.type.Assign(static_cast<u32>(type));
|
attribute.type.Assign(static_cast<u32>(type));
|
||||||
attribute.size.Assign(static_cast<u32>(size));
|
attribute.size.Assign(static_cast<u32>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t Hash() const noexcept;
|
|
||||||
|
|
||||||
bool operator==(const VertexInput& rhs) const noexcept;
|
|
||||||
|
|
||||||
bool operator!=(const VertexInput& rhs) const noexcept {
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static_assert(IsHashable<VertexInput>);
|
|
||||||
|
|
||||||
struct Rasterizer {
|
struct Rasterizer {
|
||||||
union {
|
union {
|
||||||
|
@ -187,14 +171,6 @@ struct FixedPipelineState {
|
||||||
|
|
||||||
void Fill(const Maxwell& regs) noexcept;
|
void Fill(const Maxwell& regs) noexcept;
|
||||||
|
|
||||||
std::size_t Hash() const noexcept;
|
|
||||||
|
|
||||||
bool operator==(const Rasterizer& rhs) const noexcept;
|
|
||||||
|
|
||||||
bool operator!=(const Rasterizer& rhs) const noexcept {
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
|
constexpr Maxwell::PrimitiveTopology Topology() const noexcept {
|
||||||
return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
|
return static_cast<Maxwell::PrimitiveTopology>(topology.Value());
|
||||||
}
|
}
|
||||||
|
@ -207,7 +183,6 @@ struct FixedPipelineState {
|
||||||
return UnpackFrontFace(front_face.Value());
|
return UnpackFrontFace(front_face.Value());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(IsHashable<Rasterizer>);
|
|
||||||
|
|
||||||
struct DepthStencil {
|
struct DepthStencil {
|
||||||
template <std::size_t Position>
|
template <std::size_t Position>
|
||||||
|
@ -247,39 +222,22 @@ struct FixedPipelineState {
|
||||||
|
|
||||||
void Fill(const Maxwell& regs) noexcept;
|
void Fill(const Maxwell& regs) noexcept;
|
||||||
|
|
||||||
std::size_t Hash() const noexcept;
|
|
||||||
|
|
||||||
bool operator==(const DepthStencil& rhs) const noexcept;
|
|
||||||
|
|
||||||
bool operator!=(const DepthStencil& rhs) const noexcept {
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
Maxwell::ComparisonOp DepthTestFunc() const noexcept {
|
Maxwell::ComparisonOp DepthTestFunc() const noexcept {
|
||||||
return UnpackComparisonOp(depth_test_func);
|
return UnpackComparisonOp(depth_test_func);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(IsHashable<DepthStencil>);
|
|
||||||
|
|
||||||
struct ColorBlending {
|
struct ColorBlending {
|
||||||
std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments;
|
std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments;
|
||||||
|
|
||||||
void Fill(const Maxwell& regs) noexcept;
|
void Fill(const Maxwell& regs) noexcept;
|
||||||
|
|
||||||
std::size_t Hash() const noexcept;
|
|
||||||
|
|
||||||
bool operator==(const ColorBlending& rhs) const noexcept;
|
|
||||||
|
|
||||||
bool operator!=(const ColorBlending& rhs) const noexcept {
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
static_assert(IsHashable<ColorBlending>);
|
|
||||||
|
|
||||||
VertexInput vertex_input;
|
VertexInput vertex_input;
|
||||||
Rasterizer rasterizer;
|
Rasterizer rasterizer;
|
||||||
DepthStencil depth_stencil;
|
DepthStencil depth_stencil;
|
||||||
ColorBlending color_blending;
|
ColorBlending color_blending;
|
||||||
|
std::array<u8, 20> padding;
|
||||||
|
|
||||||
std::size_t Hash() const noexcept;
|
std::size_t Hash() const noexcept;
|
||||||
|
|
||||||
|
@ -289,12 +247,10 @@ struct FixedPipelineState {
|
||||||
return !operator==(rhs);
|
return !operator==(rhs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState::BlendingAttachment>);
|
static_assert(std::has_unique_object_representations_v<FixedPipelineState>);
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState::VertexInput>);
|
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState::Rasterizer>);
|
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState::DepthStencil>);
|
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState::ColorBlending>);
|
|
||||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState>);
|
static_assert(std::is_trivially_copyable_v<FixedPipelineState>);
|
||||||
|
static_assert(std::is_trivially_constructible_v<FixedPipelineState>);
|
||||||
|
static_assert(sizeof(FixedPipelineState) % 32 == 0, "Size is not aligned");
|
||||||
|
|
||||||
FixedPipelineState GetFixedPipelineState(const Maxwell& regs);
|
FixedPipelineState GetFixedPipelineState(const Maxwell& regs);
|
||||||
|
|
||||||
|
|
Reference in New Issue