From d62f57cf5af7f329be618c0766d59ded55ff53b3 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sat, 18 Apr 2020 05:55:49 -0300 Subject: [PATCH] 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. --- .../renderer_vulkan/fixed_pipeline_state.cpp | 60 ++----------------- .../renderer_vulkan/fixed_pipeline_state.h | 54 ++--------------- 2 files changed, 9 insertions(+), 105 deletions(-) diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index 2b053ea74a..be1c319780 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -140,66 +140,13 @@ void FixedPipelineState::BlendingAttachment::Fill(const Maxwell& regs, std::size enable.Assign(1); } -std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { - return raw; -} - -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(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(raw) << 32; - std::memcpy(&hash, &point_size, sizeof(u32)); +std::size_t FixedPipelineState::Hash() const noexcept { + const u64 hash = Common::CityHash64(reinterpret_cast(this), sizeof *this); return static_cast(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 { - return std::tie(vertex_input, rasterizer, depth_stencil, color_blending) == - std::tie(rhs.vertex_input, rhs.rasterizer, rhs.depth_stencil, rhs.color_blending); + return std::memcmp(this, &rhs, sizeof *this) == 0; } FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { @@ -207,6 +154,7 @@ FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { fixed_state.rasterizer.Fill(regs); fixed_state.depth_stencil.Fill(regs); fixed_state.color_blending.Fill(regs); + fixed_state.padding = {}; return fixed_state; } diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 9393cb24ca..9fe6bdbf9b 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -17,13 +17,7 @@ namespace Vulkan { using Maxwell = Tegra::Engines::Maxwell3D::Regs; -// TODO(Rodrigo): Optimize this structure. - -template -inline constexpr bool IsHashable = std::has_unique_object_representations_v&& - std::is_trivially_copyable_v&& std::is_trivially_constructible_v; - -struct FixedPipelineState { +struct alignas(32) FixedPipelineState { static u32 PackComparisonOp(Maxwell::ComparisonOp op) noexcept; static Maxwell::ComparisonOp UnpackComparisonOp(u32 packed) noexcept; @@ -102,7 +96,6 @@ struct FixedPipelineState { return UnpackBlendFactor(factor_dest_a.Value()); } }; - static_assert(IsHashable); struct VertexInput { union Binding { @@ -151,16 +144,7 @@ struct FixedPipelineState { attribute.type.Assign(static_cast(type)); attribute.size.Assign(static_cast(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); struct Rasterizer { union { @@ -187,14 +171,6 @@ struct FixedPipelineState { 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 { return static_cast(topology.Value()); } @@ -207,7 +183,6 @@ struct FixedPipelineState { return UnpackFrontFace(front_face.Value()); } }; - static_assert(IsHashable); struct DepthStencil { template @@ -247,39 +222,22 @@ struct FixedPipelineState { 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 { return UnpackComparisonOp(depth_test_func); } }; - static_assert(IsHashable); struct ColorBlending { std::array attachments; 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); VertexInput vertex_input; Rasterizer rasterizer; DepthStencil depth_stencil; ColorBlending color_blending; + std::array padding; std::size_t Hash() const noexcept; @@ -289,12 +247,10 @@ struct FixedPipelineState { return !operator==(rhs); } }; -static_assert(std::is_trivially_copyable_v); -static_assert(std::is_trivially_copyable_v); -static_assert(std::is_trivially_copyable_v); -static_assert(std::is_trivially_copyable_v); -static_assert(std::is_trivially_copyable_v); +static_assert(std::has_unique_object_representations_v); static_assert(std::is_trivially_copyable_v); +static_assert(std::is_trivially_constructible_v); +static_assert(sizeof(FixedPipelineState) % 32 == 0, "Size is not aligned"); FixedPipelineState GetFixedPipelineState(const Maxwell& regs);