From 5770418fb348fb6a2f5c9ada3e5e20e683fb309b Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 6 Nov 2019 01:39:41 -0300 Subject: [PATCH 1/3] maxwell_3d: Add depth bounds registers --- src/video_core/engines/maxwell_3d.h | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index dbb4e597f3..2bd10cee5a 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -707,13 +707,15 @@ public: u32 color_mask_common; - INSERT_UNION_PADDING_WORDS(0x6); - - u32 rt_separate_frag_data; + INSERT_UNION_PADDING_WORDS(0x2); f32 depth_bounds[2]; - INSERT_UNION_PADDING_WORDS(0xA); + INSERT_UNION_PADDING_WORDS(0x2); + + u32 rt_separate_frag_data; + + INSERT_UNION_PADDING_WORDS(0xC); struct { u32 address_high; @@ -1030,7 +1032,12 @@ public: BitField<4, 1, u32> depth_clamp_far; } view_volume_clip_control; - INSERT_UNION_PADDING_WORDS(0x21); + INSERT_UNION_PADDING_WORDS(0x1F); + + u32 depth_bounds_enable; + + INSERT_UNION_PADDING_WORDS(1); + struct { u32 enable; LogicOperation operation; @@ -1439,7 +1446,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D6); ASSERT_REG_POSITION(stencil_back_mask, 0x3D7); ASSERT_REG_POSITION(color_mask_common, 0x3E4); ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); -ASSERT_REG_POSITION(depth_bounds, 0x3EC); +ASSERT_REG_POSITION(depth_bounds, 0x3E7); ASSERT_REG_POSITION(zeta, 0x3F8); ASSERT_REG_POSITION(clear_flags, 0x43E); ASSERT_REG_POSITION(vertex_attrib_format, 0x458); @@ -1495,6 +1502,7 @@ ASSERT_REG_POSITION(cull, 0x646); ASSERT_REG_POSITION(pixel_center_integer, 0x649); ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); ASSERT_REG_POSITION(view_volume_clip_control, 0x64F); +ASSERT_REG_POSITION(depth_bounds_enable, 0x66F); ASSERT_REG_POSITION(logic_op, 0x671); ASSERT_REG_POSITION(clear_buffers, 0x674); ASSERT_REG_POSITION(color_mask, 0x680); From 4a3026b16b0be26d80f5a7429755e19ee8d494a4 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 22 Dec 2019 22:48:43 -0300 Subject: [PATCH 2/3] fixed_pipeline_state: Define structure and loaders The intention behind this hasheable structure is to describe the state of fixed function pipeline state that gets compiled to a single graphics pipeline state object. This is all dynamic state in OpenGL but Vulkan wants it in an immutable state, even if hardware can edit it freely. In this commit the structure is defined in an optimized state (it uses booleans, has paddings and many data entries that can be packed to single integers). This is intentional as an initial implementation that is easier to debug, implement and review. It will be optimized in later stages, or it might change if Vulkan gets more dynamic states. --- src/video_core/CMakeLists.txt | 2 + .../renderer_vulkan/fixed_pipeline_state.cpp | 295 ++++++++++++++++++ .../renderer_vulkan/fixed_pipeline_state.h | 231 ++++++++++++++ 3 files changed, 528 insertions(+) create mode 100644 src/video_core/renderer_vulkan/fixed_pipeline_state.cpp create mode 100644 src/video_core/renderer_vulkan/fixed_pipeline_state.h diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 3b20c7d349..e615b238ed 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -151,6 +151,8 @@ add_library(video_core STATIC if (ENABLE_VULKAN) target_sources(video_core PRIVATE renderer_vulkan/declarations.h + renderer_vulkan/fixed_pipeline_state.cpp + renderer_vulkan/fixed_pipeline_state.h renderer_vulkan/maxwell_to_vk.cpp renderer_vulkan/maxwell_to_vk.h renderer_vulkan/vk_buffer_cache.cpp diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp new file mode 100644 index 0000000000..f75c348fe1 --- /dev/null +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -0,0 +1,295 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include + +#include "common/common_types.h" +#include "video_core/renderer_vulkan/fixed_pipeline_state.h" + +namespace Vulkan { + +namespace { + +constexpr FixedPipelineState::DepthStencil GetDepthStencilState(const Maxwell& regs) { + const FixedPipelineState::StencilFace front_stencil( + regs.stencil_front_op_fail, regs.stencil_front_op_zfail, regs.stencil_front_op_zpass, + regs.stencil_front_func_func); + const FixedPipelineState::StencilFace back_stencil = + regs.stencil_two_side_enable + ? FixedPipelineState::StencilFace(regs.stencil_back_op_fail, regs.stencil_back_op_zfail, + regs.stencil_back_op_zpass, + regs.stencil_back_func_func) + : front_stencil; + return FixedPipelineState::DepthStencil( + regs.depth_test_enable == 1, regs.depth_write_enabled == 1, regs.depth_bounds_enable == 1, + regs.stencil_enable == 1, regs.depth_test_func, front_stencil, back_stencil); +} + +constexpr FixedPipelineState::InputAssembly GetInputAssemblyState(const Maxwell& regs) { + return FixedPipelineState::InputAssembly( + regs.draw.topology, regs.primitive_restart.enabled, + regs.draw.topology == Maxwell::PrimitiveTopology::Points ? regs.point_size : 0.0f); +} + +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; + } + + if (!regs.independent_blend_enable) { + const auto& src = regs.blend; + if (!src.enable[render_target]) { + return default_blending; + } + 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); + } + + if (!regs.blend.enable[render_target]) { + return default_blending; + } + 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); +} + +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)}); +} + +constexpr FixedPipelineState::Tessellation GetTessellationState(const Maxwell& regs) { + return FixedPipelineState::Tessellation(regs.patch_vertices, regs.tess_mode.prim, + regs.tess_mode.spacing, regs.tess_mode.cw != 0); +} + +constexpr std::size_t Point = 0; +constexpr std::size_t Line = 1; +constexpr std::size_t Polygon = 2; +constexpr std::array PolygonOffsetEnableLUT = { + Point, // Points + Line, // Lines + Line, // LineLoop + Line, // LineStrip + Polygon, // Triangles + Polygon, // TriangleStrip + Polygon, // TriangleFan + Polygon, // Quads + Polygon, // QuadStrip + Polygon, // Polygon + Line, // LinesAdjacency + Line, // LineStripAdjacency + Polygon, // TrianglesAdjacency + Polygon, // TriangleStripAdjacency + Polygon, // Patches +}; + +constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs) { + const std::array enabled_lut = {regs.polygon_offset_point_enable, + regs.polygon_offset_line_enable, + regs.polygon_offset_fill_enable}; + const auto topology = static_cast(regs.draw.topology.Value()); + const bool depth_bias_enabled = enabled_lut[PolygonOffsetEnableLUT[topology]]; + + Maxwell::Cull::FrontFace front_face = regs.cull.front_face; + if (regs.screen_y_control.triangle_rast_flip != 0 && + regs.viewport_transform[0].scale_y > 0.0f) { + if (front_face == Maxwell::Cull::FrontFace::CounterClockWise) + front_face = Maxwell::Cull::FrontFace::ClockWise; + else if (front_face == Maxwell::Cull::FrontFace::ClockWise) + front_face = Maxwell::Cull::FrontFace::CounterClockWise; + } + + const bool gl_ndc = regs.depth_mode == Maxwell::DepthMode::MinusOneToOne; + return FixedPipelineState::Rasterizer(regs.cull.enabled, depth_bias_enabled, gl_ndc, + regs.cull.cull_face, front_face); +} + +} // Anonymous namespace + +std::size_t FixedPipelineState::VertexBinding::Hash() const { + return (index << stride) ^ divisor; +} + +bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const { + return std::tie(index, stride, divisor) == std::tie(rhs.index, rhs.stride, rhs.divisor); +} + +std::size_t FixedPipelineState::VertexAttribute::Hash() const { + return static_cast(index) ^ (static_cast(buffer) << 13) ^ + (static_cast(type) << 22) ^ (static_cast(size) << 31) ^ + (static_cast(offset) << 36); +} + +bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const { + return std::tie(index, buffer, type, size, offset) == + std::tie(rhs.index, rhs.buffer, rhs.type, rhs.size, rhs.offset); +} + +std::size_t FixedPipelineState::StencilFace::Hash() const { + return static_cast(action_stencil_fail) ^ + (static_cast(action_depth_fail) << 4) ^ + (static_cast(action_depth_fail) << 20) ^ + (static_cast(action_depth_pass) << 36); +} + +bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const { + 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 { + return static_cast(enable) ^ (static_cast(rgb_equation) << 5) ^ + (static_cast(src_rgb_func) << 10) ^ + (static_cast(dst_rgb_func) << 15) ^ + (static_cast(a_equation) << 20) ^ + (static_cast(src_a_func) << 25) ^ + (static_cast(dst_a_func) << 30) ^ + (static_cast(components[0]) << 35) ^ + (static_cast(components[1]) << 36) ^ + (static_cast(components[2]) << 37) ^ + (static_cast(components[3]) << 38); +} + +bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const { + 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); +} + +std::size_t FixedPipelineState::VertexInput::Hash() const { + std::size_t hash = num_bindings ^ (num_attributes << 32); + for (std::size_t i = 0; i < num_bindings; ++i) { + boost::hash_combine(hash, bindings[i].Hash()); + } + for (std::size_t i = 0; i < num_attributes; ++i) { + boost::hash_combine(hash, attributes[i].Hash()); + } + return hash; +} + +bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const { + return std::equal(bindings.begin(), bindings.begin() + num_bindings, rhs.bindings.begin(), + rhs.bindings.begin() + rhs.num_bindings) && + std::equal(attributes.begin(), attributes.begin() + num_attributes, + rhs.attributes.begin(), rhs.attributes.begin() + rhs.num_attributes); +} + +std::size_t FixedPipelineState::InputAssembly::Hash() const { + std::size_t point_size_int = 0; + std::memcpy(&point_size_int, &point_size, sizeof(point_size)); + return (static_cast(topology) << 24) ^ (point_size_int << 32) ^ + static_cast(primitive_restart_enable); +} + +bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const { + return std::tie(topology, primitive_restart_enable, point_size) == + std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size); +} + +std::size_t FixedPipelineState::Tessellation::Hash() const { + return static_cast(patch_control_points) ^ + (static_cast(primitive) << 6) ^ (static_cast(spacing) << 8) ^ + (static_cast(clockwise) << 10); +} + +bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const { + return std::tie(patch_control_points, primitive, spacing, clockwise) == + std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise); +} + +std::size_t FixedPipelineState::Rasterizer::Hash() const { + return static_cast(cull_enable) ^ + (static_cast(depth_bias_enable) << 1) ^ + (static_cast(ndc_minus_one_to_one) << 2) ^ + (static_cast(cull_face) << 24) ^ + (static_cast(front_face) << 48); +} + +bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const { + return std::tie(cull_enable, depth_bias_enable, ndc_minus_one_to_one, cull_face, front_face) == + std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.ndc_minus_one_to_one, rhs.cull_face, + rhs.front_face); +} + +std::size_t FixedPipelineState::DepthStencil::Hash() const { + std::size_t hash = static_cast(depth_test_enable) ^ + (static_cast(depth_write_enable) << 1) ^ + (static_cast(depth_bounds_enable) << 2) ^ + (static_cast(stencil_enable) << 3) ^ + (static_cast(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 { + return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, + 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 { + std::size_t hash = attachments_count << 13; + for (std::size_t rt = 0; rt < static_cast(attachments_count); ++rt) { + boost::hash_combine(hash, attachments[rt].Hash()); + } + return hash; +} + +bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const { + return std::equal(attachments.begin(), attachments.begin() + attachments_count, + rhs.attachments.begin(), rhs.attachments.begin() + rhs.attachments_count); +} + +std::size_t FixedPipelineState::Hash() const noexcept { + std::size_t hash = 0; + boost::hash_combine(hash, vertex_input.Hash()); + boost::hash_combine(hash, input_assembly.Hash()); + boost::hash_combine(hash, tessellation.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, input_assembly, tessellation, rasterizer, depth_stencil, + color_blending) == std::tie(rhs.vertex_input, rhs.input_assembly, + rhs.tessellation, rhs.rasterizer, rhs.depth_stencil, + rhs.color_blending); +} + +FixedPipelineState GetFixedPipelineState(const Maxwell& regs) { + FixedPipelineState fixed_state; + fixed_state.input_assembly = GetInputAssemblyState(regs); + fixed_state.tessellation = GetTessellationState(regs); + fixed_state.rasterizer = GetRasterizerState(regs); + fixed_state.depth_stencil = GetDepthStencilState(regs); + fixed_state.color_blending = GetColorBlendingState(regs); + return fixed_state; +} + +} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h new file mode 100644 index 0000000000..01f82be68d --- /dev/null +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -0,0 +1,231 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "common/common_types.h" + +#include "video_core/engines/maxwell_3d.h" +#include "video_core/surface.h" + +namespace Vulkan { + +using Maxwell = Tegra::Engines::Maxwell3D::Regs; + +// TODO(Rodrigo): Optimize this structure. + +struct FixedPipelineState { + using PixelFormat = VideoCore::Surface::PixelFormat; + + struct VertexBinding { + constexpr VertexBinding(u32 index, u32 stride, u32 divisor) + : index{index}, stride{stride}, divisor{divisor} {} + VertexBinding() = default; + + u32 index; + u32 stride; + u32 divisor; + + std::size_t Hash() const; + bool operator==(const VertexBinding& rhs) const; + }; + + struct VertexAttribute { + constexpr VertexAttribute(u32 index, u32 buffer, Maxwell::VertexAttribute::Type type, + Maxwell::VertexAttribute::Size size, u32 offset) + : index{index}, buffer{buffer}, type{type}, size{size}, offset{offset} {} + VertexAttribute() = default; + + u32 index; + u32 buffer; + Maxwell::VertexAttribute::Type type; + Maxwell::VertexAttribute::Size size; + u32 offset; + + std::size_t Hash() const; + bool operator==(const VertexAttribute& rhs) const; + }; + + struct StencilFace { + constexpr StencilFace(Maxwell::StencilOp action_stencil_fail, + 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; + Maxwell::StencilOp action_depth_fail; + Maxwell::StencilOp action_depth_pass; + Maxwell::ComparisonOp test_func; + + std::size_t Hash() const; + bool operator==(const StencilFace& rhs) const; + }; + + 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 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; + + 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 components; + + std::size_t Hash() const; + bool operator==(const BlendingAttachment& rhs) const; + }; + + struct VertexInput { + std::size_t num_bindings = 0; + std::size_t num_attributes = 0; + std::array bindings; + std::array attributes; + + std::size_t Hash() const; + bool operator==(const VertexInput& rhs) const; + }; + + struct InputAssembly { + constexpr InputAssembly(Maxwell::PrimitiveTopology topology, bool primitive_restart_enable, + float point_size) + : topology{topology}, primitive_restart_enable{primitive_restart_enable}, + point_size{point_size} {} + InputAssembly() = default; + + Maxwell::PrimitiveTopology topology; + bool primitive_restart_enable; + float point_size; + + std::size_t Hash() const; + bool operator==(const InputAssembly& rhs) const; + }; + + struct Tessellation { + constexpr Tessellation(u32 patch_control_points, Maxwell::TessellationPrimitive primitive, + Maxwell::TessellationSpacing spacing, bool clockwise) + : patch_control_points{patch_control_points}, primitive{primitive}, spacing{spacing}, + clockwise{clockwise} {} + Tessellation() = default; + + u32 patch_control_points; + Maxwell::TessellationPrimitive primitive; + Maxwell::TessellationSpacing spacing; + bool clockwise; + + std::size_t Hash() const; + bool operator==(const Tessellation& rhs) const; + }; + + struct Rasterizer { + constexpr Rasterizer(bool cull_enable, bool depth_bias_enable, bool ndc_minus_one_to_one, + Maxwell::Cull::CullFace cull_face, Maxwell::Cull::FrontFace front_face) + : cull_enable{cull_enable}, depth_bias_enable{depth_bias_enable}, + ndc_minus_one_to_one{ndc_minus_one_to_one}, cull_face{cull_face}, front_face{ + front_face} {} + Rasterizer() = default; + + bool cull_enable; + bool depth_bias_enable; + bool ndc_minus_one_to_one; + Maxwell::Cull::CullFace cull_face; + Maxwell::Cull::FrontFace front_face; + + std::size_t Hash() const; + bool operator==(const Rasterizer& rhs) const; + }; + + struct DepthStencil { + constexpr DepthStencil(bool depth_test_enable, bool depth_write_enable, + bool depth_bounds_enable, bool stencil_enable, + Maxwell::ComparisonOp depth_test_function, StencilFace front_stencil, + StencilFace back_stencil) + : depth_test_enable{depth_test_enable}, depth_write_enable{depth_write_enable}, + depth_bounds_enable{depth_bounds_enable}, stencil_enable{stencil_enable}, + depth_test_function{depth_test_function}, front_stencil{front_stencil}, + back_stencil{back_stencil} {} + DepthStencil() = default; + + bool depth_test_enable; + bool depth_write_enable; + bool depth_bounds_enable; + bool stencil_enable; + Maxwell::ComparisonOp depth_test_function; + StencilFace front_stencil; + StencilFace back_stencil; + + std::size_t Hash() const; + bool operator==(const DepthStencil& rhs) const; + }; + + struct ColorBlending { + constexpr ColorBlending( + std::array blend_constants, std::size_t attachments_count, + std::array attachments) + : attachments_count{attachments_count}, attachments{attachments} {} + ColorBlending() = default; + + std::size_t attachments_count; + std::array attachments; + + std::size_t Hash() const; + bool operator==(const ColorBlending& rhs) const; + }; + + std::size_t Hash() const noexcept; + bool operator==(const FixedPipelineState& rhs) const noexcept; + + bool operator!=(const FixedPipelineState& rhs) const noexcept { + 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); +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::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); + +FixedPipelineState GetFixedPipelineState(const Maxwell& regs); + +} // namespace Vulkan + +namespace std { + +template <> +struct hash { + std::size_t operator()(const Vulkan::FixedPipelineState& k) const noexcept { + return k.Hash(); + } +}; + +} // namespace std From b9e3f5eb36318f269257ab60f446b72a63aecc3c Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Tue, 24 Dec 2019 17:11:08 -0300 Subject: [PATCH 3/3] fixed_pipeline_state: Define symetric operator!= and mark as noexcept Marks as noexcept Hash, operator== and operator!= for consistency. --- .../renderer_vulkan/fixed_pipeline_state.cpp | 41 +++++---- .../renderer_vulkan/fixed_pipeline_state.h | 91 +++++++++++++++---- 2 files changed, 92 insertions(+), 40 deletions(-) diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp index f75c348fe1..5a490f6efb 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp @@ -125,39 +125,39 @@ constexpr FixedPipelineState::Rasterizer GetRasterizerState(const Maxwell& regs) } // Anonymous namespace -std::size_t FixedPipelineState::VertexBinding::Hash() const { +std::size_t FixedPipelineState::VertexBinding::Hash() const noexcept { return (index << stride) ^ divisor; } -bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const { +bool FixedPipelineState::VertexBinding::operator==(const VertexBinding& rhs) const noexcept { return std::tie(index, stride, divisor) == std::tie(rhs.index, rhs.stride, rhs.divisor); } -std::size_t FixedPipelineState::VertexAttribute::Hash() const { +std::size_t FixedPipelineState::VertexAttribute::Hash() const noexcept { return static_cast(index) ^ (static_cast(buffer) << 13) ^ (static_cast(type) << 22) ^ (static_cast(size) << 31) ^ (static_cast(offset) << 36); } -bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const { +bool FixedPipelineState::VertexAttribute::operator==(const VertexAttribute& rhs) const noexcept { return std::tie(index, buffer, type, size, offset) == std::tie(rhs.index, rhs.buffer, rhs.type, rhs.size, rhs.offset); } -std::size_t FixedPipelineState::StencilFace::Hash() const { +std::size_t FixedPipelineState::StencilFace::Hash() const noexcept { return static_cast(action_stencil_fail) ^ (static_cast(action_depth_fail) << 4) ^ (static_cast(action_depth_fail) << 20) ^ (static_cast(action_depth_pass) << 36); } -bool FixedPipelineState::StencilFace::operator==(const StencilFace& rhs) const { +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 { +std::size_t FixedPipelineState::BlendingAttachment::Hash() const noexcept { return static_cast(enable) ^ (static_cast(rgb_equation) << 5) ^ (static_cast(src_rgb_func) << 10) ^ (static_cast(dst_rgb_func) << 15) ^ @@ -170,14 +170,15 @@ std::size_t FixedPipelineState::BlendingAttachment::Hash() const { (static_cast(components[3]) << 38); } -bool FixedPipelineState::BlendingAttachment::operator==(const BlendingAttachment& rhs) const { +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); } -std::size_t FixedPipelineState::VertexInput::Hash() const { +std::size_t FixedPipelineState::VertexInput::Hash() const noexcept { std::size_t hash = num_bindings ^ (num_attributes << 32); for (std::size_t i = 0; i < num_bindings; ++i) { boost::hash_combine(hash, bindings[i].Hash()); @@ -188,37 +189,37 @@ std::size_t FixedPipelineState::VertexInput::Hash() const { return hash; } -bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const { +bool FixedPipelineState::VertexInput::operator==(const VertexInput& rhs) const noexcept { return std::equal(bindings.begin(), bindings.begin() + num_bindings, rhs.bindings.begin(), rhs.bindings.begin() + rhs.num_bindings) && std::equal(attributes.begin(), attributes.begin() + num_attributes, rhs.attributes.begin(), rhs.attributes.begin() + rhs.num_attributes); } -std::size_t FixedPipelineState::InputAssembly::Hash() const { +std::size_t FixedPipelineState::InputAssembly::Hash() const noexcept { std::size_t point_size_int = 0; std::memcpy(&point_size_int, &point_size, sizeof(point_size)); return (static_cast(topology) << 24) ^ (point_size_int << 32) ^ static_cast(primitive_restart_enable); } -bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const { +bool FixedPipelineState::InputAssembly::operator==(const InputAssembly& rhs) const noexcept { return std::tie(topology, primitive_restart_enable, point_size) == std::tie(rhs.topology, rhs.primitive_restart_enable, rhs.point_size); } -std::size_t FixedPipelineState::Tessellation::Hash() const { +std::size_t FixedPipelineState::Tessellation::Hash() const noexcept { return static_cast(patch_control_points) ^ (static_cast(primitive) << 6) ^ (static_cast(spacing) << 8) ^ (static_cast(clockwise) << 10); } -bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const { +bool FixedPipelineState::Tessellation::operator==(const Tessellation& rhs) const noexcept { return std::tie(patch_control_points, primitive, spacing, clockwise) == std::tie(rhs.patch_control_points, rhs.primitive, rhs.spacing, rhs.clockwise); } -std::size_t FixedPipelineState::Rasterizer::Hash() const { +std::size_t FixedPipelineState::Rasterizer::Hash() const noexcept { return static_cast(cull_enable) ^ (static_cast(depth_bias_enable) << 1) ^ (static_cast(ndc_minus_one_to_one) << 2) ^ @@ -226,13 +227,13 @@ std::size_t FixedPipelineState::Rasterizer::Hash() const { (static_cast(front_face) << 48); } -bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const { +bool FixedPipelineState::Rasterizer::operator==(const Rasterizer& rhs) const noexcept { return std::tie(cull_enable, depth_bias_enable, ndc_minus_one_to_one, cull_face, front_face) == std::tie(rhs.cull_enable, rhs.depth_bias_enable, rhs.ndc_minus_one_to_one, rhs.cull_face, rhs.front_face); } -std::size_t FixedPipelineState::DepthStencil::Hash() const { +std::size_t FixedPipelineState::DepthStencil::Hash() const noexcept { std::size_t hash = static_cast(depth_test_enable) ^ (static_cast(depth_write_enable) << 1) ^ (static_cast(depth_bounds_enable) << 2) ^ @@ -243,7 +244,7 @@ std::size_t FixedPipelineState::DepthStencil::Hash() const { return hash; } -bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const { +bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const noexcept { return std::tie(depth_test_enable, depth_write_enable, depth_bounds_enable, depth_test_function, stencil_enable, front_stencil, back_stencil) == std::tie(rhs.depth_test_enable, rhs.depth_write_enable, rhs.depth_bounds_enable, @@ -251,7 +252,7 @@ bool FixedPipelineState::DepthStencil::operator==(const DepthStencil& rhs) const rhs.back_stencil); } -std::size_t FixedPipelineState::ColorBlending::Hash() 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(attachments_count); ++rt) { boost::hash_combine(hash, attachments[rt].Hash()); @@ -259,7 +260,7 @@ std::size_t FixedPipelineState::ColorBlending::Hash() const { return hash; } -bool FixedPipelineState::ColorBlending::operator==(const ColorBlending& rhs) const { +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); } diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.h b/src/video_core/renderer_vulkan/fixed_pipeline_state.h index 01f82be68d..04152c0d4e 100644 --- a/src/video_core/renderer_vulkan/fixed_pipeline_state.h +++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.h @@ -30,8 +30,13 @@ struct FixedPipelineState { u32 stride; u32 divisor; - std::size_t Hash() const; - bool operator==(const VertexBinding& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const VertexBinding& rhs) const noexcept; + + bool operator!=(const VertexBinding& rhs) const noexcept { + return !operator==(rhs); + } }; struct VertexAttribute { @@ -46,8 +51,13 @@ struct FixedPipelineState { Maxwell::VertexAttribute::Size size; u32 offset; - std::size_t Hash() const; - bool operator==(const VertexAttribute& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const VertexAttribute& rhs) const noexcept; + + bool operator!=(const VertexAttribute& rhs) const noexcept { + return !operator==(rhs); + } }; struct StencilFace { @@ -63,8 +73,13 @@ struct FixedPipelineState { Maxwell::StencilOp action_depth_pass; Maxwell::ComparisonOp test_func; - std::size_t Hash() const; - bool operator==(const StencilFace& rhs) const; + 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 { @@ -89,8 +104,13 @@ struct FixedPipelineState { Maxwell::Blend::Factor dst_a_func; std::array components; - std::size_t Hash() const; - bool operator==(const BlendingAttachment& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const BlendingAttachment& rhs) const noexcept; + + bool operator!=(const BlendingAttachment& rhs) const noexcept { + return !operator==(rhs); + } }; struct VertexInput { @@ -99,8 +119,13 @@ struct FixedPipelineState { std::array bindings; std::array attributes; - std::size_t Hash() const; - bool operator==(const VertexInput& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const VertexInput& rhs) const noexcept; + + bool operator!=(const VertexInput& rhs) const noexcept { + return !operator==(rhs); + } }; struct InputAssembly { @@ -114,8 +139,13 @@ struct FixedPipelineState { bool primitive_restart_enable; float point_size; - std::size_t Hash() const; - bool operator==(const InputAssembly& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const InputAssembly& rhs) const noexcept; + + bool operator!=(const InputAssembly& rhs) const noexcept { + return !operator==(rhs); + } }; struct Tessellation { @@ -130,8 +160,13 @@ struct FixedPipelineState { Maxwell::TessellationSpacing spacing; bool clockwise; - std::size_t Hash() const; - bool operator==(const Tessellation& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const Tessellation& rhs) const noexcept; + + bool operator!=(const Tessellation& rhs) const noexcept { + return !operator==(rhs); + } }; struct Rasterizer { @@ -148,8 +183,13 @@ struct FixedPipelineState { Maxwell::Cull::CullFace cull_face; Maxwell::Cull::FrontFace front_face; - std::size_t Hash() const; - bool operator==(const Rasterizer& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const Rasterizer& rhs) const noexcept; + + bool operator!=(const Rasterizer& rhs) const noexcept { + return !operator==(rhs); + } }; struct DepthStencil { @@ -171,8 +211,13 @@ struct FixedPipelineState { StencilFace front_stencil; StencilFace back_stencil; - std::size_t Hash() const; - bool operator==(const DepthStencil& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const DepthStencil& rhs) const noexcept; + + bool operator!=(const DepthStencil& rhs) const noexcept { + return !operator==(rhs); + } }; struct ColorBlending { @@ -185,11 +230,17 @@ struct FixedPipelineState { std::size_t attachments_count; std::array attachments; - std::size_t Hash() const; - bool operator==(const ColorBlending& rhs) const; + std::size_t Hash() const noexcept; + + bool operator==(const ColorBlending& rhs) const noexcept; + + bool operator!=(const ColorBlending& rhs) const noexcept { + return !operator==(rhs); + } }; std::size_t Hash() const noexcept; + bool operator==(const FixedPipelineState& rhs) const noexcept; bool operator!=(const FixedPipelineState& rhs) const noexcept {