From 4841dc0b745389fb03edbf900f25511bee4b3d88 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 3 Feb 2024 22:51:04 +0100 Subject: VideoCore: Move Slot Vector to Common --- src/common/CMakeLists.txt | 1 + src/common/slot_vector.h | 227 +++++++++++++++++++++ src/video_core/CMakeLists.txt | 1 - src/video_core/buffer_cache/buffer_cache_base.h | 6 +- src/video_core/query_cache.h | 6 +- src/video_core/renderer_opengl/gl_buffer_cache.h | 2 +- src/video_core/renderer_opengl/gl_texture_cache.h | 2 +- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 2 +- src/video_core/renderer_vulkan/vk_buffer_cache.h | 2 +- src/video_core/renderer_vulkan/vk_texture_cache.h | 2 +- src/video_core/texture_cache/slot_vector.h | 227 --------------------- src/video_core/texture_cache/texture_cache_base.h | 18 +- src/video_core/texture_cache/types.h | 16 +- 13 files changed, 256 insertions(+), 256 deletions(-) create mode 100644 src/common/slot_vector.h delete mode 100644 src/video_core/texture_cache/slot_vector.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 85926fc8f..bf3f3b781 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -121,6 +121,7 @@ add_library(common STATIC settings_input.cpp settings_input.h settings_setting.h + slot_vector.h socket_types.h spin_lock.cpp spin_lock.h diff --git a/src/common/slot_vector.h b/src/common/slot_vector.h new file mode 100644 index 000000000..34ff7de94 --- /dev/null +++ b/src/common/slot_vector.h @@ -0,0 +1,227 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "common/assert.h" +#include "common/common_types.h" +#include "common/polyfill_ranges.h" + +namespace Common { + +struct SlotId { + static constexpr u32 INVALID_INDEX = std::numeric_limits::max(); + + constexpr auto operator<=>(const SlotId&) const noexcept = default; + + constexpr explicit operator bool() const noexcept { + return index != INVALID_INDEX; + } + + u32 index = INVALID_INDEX; +}; + +template + requires std::is_nothrow_move_assignable_v && std::is_nothrow_move_constructible_v +class SlotVector { +public: + class Iterator { + friend SlotVector; + + public: + constexpr Iterator() = default; + + Iterator& operator++() noexcept { + const u64* const bitset = slot_vector->stored_bitset.data(); + const u32 size = static_cast(slot_vector->stored_bitset.size()) * 64; + if (id.index < size) { + do { + ++id.index; + } while (id.index < size && !IsValid(bitset)); + if (id.index == size) { + id.index = SlotId::INVALID_INDEX; + } + } + return *this; + } + + Iterator operator++(int) noexcept { + const Iterator copy{*this}; + ++*this; + return copy; + } + + bool operator==(const Iterator& other) const noexcept { + return id.index == other.id.index; + } + + bool operator!=(const Iterator& other) const noexcept { + return id.index != other.id.index; + } + + std::pair operator*() const noexcept { + return {id, std::addressof((*slot_vector)[id])}; + } + + T* operator->() const noexcept { + return std::addressof((*slot_vector)[id]); + } + + private: + Iterator(SlotVector* slot_vector_, SlotId id_) noexcept + : slot_vector{slot_vector_}, id{id_} {} + + bool IsValid(const u64* bitset) const noexcept { + return ((bitset[id.index / 64] >> (id.index % 64)) & 1) != 0; + } + + SlotVector* slot_vector; + SlotId id; + }; + + ~SlotVector() noexcept { + size_t index = 0; + for (u64 bits : stored_bitset) { + for (size_t bit = 0; bits; ++bit, bits >>= 1) { + if ((bits & 1) != 0) { + values[index + bit].object.~T(); + } + } + index += 64; + } + delete[] values; + } + + [[nodiscard]] T& operator[](SlotId id) noexcept { + ValidateIndex(id); + return values[id.index].object; + } + + [[nodiscard]] const T& operator[](SlotId id) const noexcept { + ValidateIndex(id); + return values[id.index].object; + } + + template + [[nodiscard]] SlotId insert(Args&&... args) noexcept { + const u32 index = FreeValueIndex(); + new (&values[index].object) T(std::forward(args)...); + SetStorageBit(index); + + return SlotId{index}; + } + + void erase(SlotId id) noexcept { + values[id.index].object.~T(); + free_list.push_back(id.index); + ResetStorageBit(id.index); + } + + [[nodiscard]] Iterator begin() noexcept { + const auto it = std::ranges::find_if(stored_bitset, [](u64 value) { return value != 0; }); + if (it == stored_bitset.end()) { + return end(); + } + const u32 word_index = static_cast(std::distance(it, stored_bitset.begin())); + const SlotId first_id{word_index * 64 + static_cast(std::countr_zero(*it))}; + return Iterator(this, first_id); + } + + [[nodiscard]] Iterator end() noexcept { + return Iterator(this, SlotId{SlotId::INVALID_INDEX}); + } + + [[nodiscard]] size_t size() const noexcept { + return values_capacity - free_list.size(); + } + +private: + struct NonTrivialDummy { + NonTrivialDummy() noexcept {} + }; + + union Entry { + Entry() noexcept : dummy{} {} + ~Entry() noexcept {} + + NonTrivialDummy dummy; + T object; + }; + + void SetStorageBit(u32 index) noexcept { + stored_bitset[index / 64] |= u64(1) << (index % 64); + } + + void ResetStorageBit(u32 index) noexcept { + stored_bitset[index / 64] &= ~(u64(1) << (index % 64)); + } + + bool ReadStorageBit(u32 index) noexcept { + return ((stored_bitset[index / 64] >> (index % 64)) & 1) != 0; + } + + void ValidateIndex(SlotId id) const noexcept { + DEBUG_ASSERT(id); + DEBUG_ASSERT(id.index / 64 < stored_bitset.size()); + DEBUG_ASSERT(((stored_bitset[id.index / 64] >> (id.index % 64)) & 1) != 0); + } + + [[nodiscard]] u32 FreeValueIndex() noexcept { + if (free_list.empty()) { + Reserve(values_capacity ? (values_capacity << 1) : 1); + } + const u32 free_index = free_list.back(); + free_list.pop_back(); + return free_index; + } + + void Reserve(size_t new_capacity) noexcept { + Entry* const new_values = new Entry[new_capacity]; + size_t index = 0; + for (u64 bits : stored_bitset) { + for (size_t bit = 0; bits; ++bit, bits >>= 1) { + const size_t i = index + bit; + if ((bits & 1) == 0) { + continue; + } + T& old_value = values[i].object; + new (&new_values[i].object) T(std::move(old_value)); + old_value.~T(); + } + index += 64; + } + + stored_bitset.resize((new_capacity + 63) / 64); + + const size_t old_free_size = free_list.size(); + free_list.resize(old_free_size + (new_capacity - values_capacity)); + std::iota(free_list.begin() + old_free_size, free_list.end(), + static_cast(values_capacity)); + + delete[] values; + values = new_values; + values_capacity = new_capacity; + } + + Entry* values = nullptr; + size_t values_capacity = 0; + + std::vector stored_bitset; + std::vector free_list; +}; + +} // namespace Common + +template <> +struct std::hash { + size_t operator()(const Common::SlotId& id) const noexcept { + return std::hash{}(id.index); + } +}; diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 16c905db9..55180f4b5 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -274,7 +274,6 @@ add_library(video_core STATIC texture_cache/image_view_info.h texture_cache/render_targets.h texture_cache/samples_helper.h - texture_cache/slot_vector.h texture_cache/texture_cache.cpp texture_cache/texture_cache.h texture_cache/texture_cache_base.h diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 80dbb81e7..59124458d 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -41,7 +41,7 @@ #include "video_core/engines/maxwell_3d.h" #include "video_core/memory_manager.h" #include "video_core/surface.h" -#include "video_core/texture_cache/slot_vector.h" +#include "common/slot_vector.h" #include "video_core/texture_cache/types.h" namespace boost { @@ -55,7 +55,7 @@ MICROPROFILE_DECLARE(GPU_PrepareBuffers); MICROPROFILE_DECLARE(GPU_BindUploadBuffers); MICROPROFILE_DECLARE(GPU_DownloadMemory); -using BufferId = SlotId; +using BufferId = Common::SlotId; using VideoCore::Surface::PixelFormat; using namespace Common::Literals; @@ -559,7 +559,7 @@ private: Tegra::MaxwellDeviceMemoryManager& device_memory; - SlotVector slot_buffers; + Common::SlotVector slot_buffers; DelayedDestructionRing delayed_destruction_ring; const Tegra::Engines::DrawManager::IndirectParams* current_draw_indirect{}; diff --git a/src/video_core/query_cache.h b/src/video_core/query_cache.h index 4861b123a..e1019f228 100644 --- a/src/video_core/query_cache.h +++ b/src/video_core/query_cache.h @@ -18,12 +18,12 @@ #include "common/assert.h" #include "common/settings.h" +#include "common/slot_vector.h" #include "video_core/control/channel_state_cache.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/host1x/gpu_device_memory_manager.h" #include "video_core/memory_manager.h" #include "video_core/rasterizer_interface.h" -#include "video_core/texture_cache/slot_vector.h" namespace VideoCore { enum class QueryType { @@ -37,7 +37,7 @@ constexpr std::size_t NumQueryTypes = static_cast(QueryType::Count); namespace VideoCommon { -using AsyncJobId = SlotId; +using AsyncJobId = Common::SlotId; static constexpr AsyncJobId NULL_ASYNC_JOB_ID{0}; @@ -341,7 +341,7 @@ private: static constexpr std::uintptr_t YUZU_PAGESIZE = 4096; static constexpr unsigned YUZU_PAGEBITS = 12; - SlotVector slot_async_jobs; + Common::SlotVector slot_async_jobs; VideoCore::RasterizerInterface& rasterizer; Tegra::MaxwellDeviceMemoryManager& device_memory; diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index af34c272b..022275fd6 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h @@ -90,7 +90,7 @@ public: void PostCopyBarrier(); void Finish(); - void TickFrame(VideoCommon::SlotVector&) noexcept {} + void TickFrame(Common::SlotVector&) noexcept {} void ClearBuffer(Buffer& dest_buffer, u32 offset, size_t size, u32 value); diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 3e54edcc2..d4165d8e4 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -30,13 +30,13 @@ class Image; class ImageView; class Sampler; +using Common::SlotVector; using VideoCommon::ImageId; using VideoCommon::ImageViewId; using VideoCommon::ImageViewType; using VideoCommon::NUM_RT; using VideoCommon::Region2D; using VideoCommon::RenderTargets; -using VideoCommon::SlotVector; struct FormatProperties { GLenum compatibility_class; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 31001d142..e5e1e3ab6 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -368,7 +368,7 @@ u32 BufferCacheRuntime::GetStorageBufferAlignment() const { return static_cast(device.GetStorageBufferAlignment()); } -void BufferCacheRuntime::TickFrame(VideoCommon::SlotVector& slot_buffers) noexcept { +void BufferCacheRuntime::TickFrame(Common::SlotVector& slot_buffers) noexcept { for (auto it = slot_buffers.begin(); it != slot_buffers.end(); it++) { it->ResetUsageTracking(); } diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index e273f4988..ac14c9f86 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -81,7 +81,7 @@ public: ComputePassDescriptorQueue& compute_pass_descriptor_queue, DescriptorPool& descriptor_pool); - void TickFrame(VideoCommon::SlotVector& slot_buffers) noexcept; + void TickFrame(Common::SlotVector& slot_buffers) noexcept; void Finish(); diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 0dbde65d6..aaeb5ef93 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -20,11 +20,11 @@ struct ResolutionScalingInfo; namespace Vulkan { +using Common::SlotVector; using VideoCommon::ImageId; using VideoCommon::NUM_RT; using VideoCommon::Region2D; using VideoCommon::RenderTargets; -using VideoCommon::SlotVector; using VideoCore::Surface::PixelFormat; class BlitImageHelper; diff --git a/src/video_core/texture_cache/slot_vector.h b/src/video_core/texture_cache/slot_vector.h deleted file mode 100644 index 3ffa2a661..000000000 --- a/src/video_core/texture_cache/slot_vector.h +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "common/assert.h" -#include "common/common_types.h" -#include "common/polyfill_ranges.h" - -namespace VideoCommon { - -struct SlotId { - static constexpr u32 INVALID_INDEX = std::numeric_limits::max(); - - constexpr auto operator<=>(const SlotId&) const noexcept = default; - - constexpr explicit operator bool() const noexcept { - return index != INVALID_INDEX; - } - - u32 index = INVALID_INDEX; -}; - -template - requires std::is_nothrow_move_assignable_v && std::is_nothrow_move_constructible_v -class SlotVector { -public: - class Iterator { - friend SlotVector; - - public: - constexpr Iterator() = default; - - Iterator& operator++() noexcept { - const u64* const bitset = slot_vector->stored_bitset.data(); - const u32 size = static_cast(slot_vector->stored_bitset.size()) * 64; - if (id.index < size) { - do { - ++id.index; - } while (id.index < size && !IsValid(bitset)); - if (id.index == size) { - id.index = SlotId::INVALID_INDEX; - } - } - return *this; - } - - Iterator operator++(int) noexcept { - const Iterator copy{*this}; - ++*this; - return copy; - } - - bool operator==(const Iterator& other) const noexcept { - return id.index == other.id.index; - } - - bool operator!=(const Iterator& other) const noexcept { - return id.index != other.id.index; - } - - std::pair operator*() const noexcept { - return {id, std::addressof((*slot_vector)[id])}; - } - - T* operator->() const noexcept { - return std::addressof((*slot_vector)[id]); - } - - private: - Iterator(SlotVector* slot_vector_, SlotId id_) noexcept - : slot_vector{slot_vector_}, id{id_} {} - - bool IsValid(const u64* bitset) const noexcept { - return ((bitset[id.index / 64] >> (id.index % 64)) & 1) != 0; - } - - SlotVector* slot_vector; - SlotId id; - }; - - ~SlotVector() noexcept { - size_t index = 0; - for (u64 bits : stored_bitset) { - for (size_t bit = 0; bits; ++bit, bits >>= 1) { - if ((bits & 1) != 0) { - values[index + bit].object.~T(); - } - } - index += 64; - } - delete[] values; - } - - [[nodiscard]] T& operator[](SlotId id) noexcept { - ValidateIndex(id); - return values[id.index].object; - } - - [[nodiscard]] const T& operator[](SlotId id) const noexcept { - ValidateIndex(id); - return values[id.index].object; - } - - template - [[nodiscard]] SlotId insert(Args&&... args) noexcept { - const u32 index = FreeValueIndex(); - new (&values[index].object) T(std::forward(args)...); - SetStorageBit(index); - - return SlotId{index}; - } - - void erase(SlotId id) noexcept { - values[id.index].object.~T(); - free_list.push_back(id.index); - ResetStorageBit(id.index); - } - - [[nodiscard]] Iterator begin() noexcept { - const auto it = std::ranges::find_if(stored_bitset, [](u64 value) { return value != 0; }); - if (it == stored_bitset.end()) { - return end(); - } - const u32 word_index = static_cast(std::distance(it, stored_bitset.begin())); - const SlotId first_id{word_index * 64 + static_cast(std::countr_zero(*it))}; - return Iterator(this, first_id); - } - - [[nodiscard]] Iterator end() noexcept { - return Iterator(this, SlotId{SlotId::INVALID_INDEX}); - } - - [[nodiscard]] size_t size() const noexcept { - return values_capacity - free_list.size(); - } - -private: - struct NonTrivialDummy { - NonTrivialDummy() noexcept {} - }; - - union Entry { - Entry() noexcept : dummy{} {} - ~Entry() noexcept {} - - NonTrivialDummy dummy; - T object; - }; - - void SetStorageBit(u32 index) noexcept { - stored_bitset[index / 64] |= u64(1) << (index % 64); - } - - void ResetStorageBit(u32 index) noexcept { - stored_bitset[index / 64] &= ~(u64(1) << (index % 64)); - } - - bool ReadStorageBit(u32 index) noexcept { - return ((stored_bitset[index / 64] >> (index % 64)) & 1) != 0; - } - - void ValidateIndex(SlotId id) const noexcept { - DEBUG_ASSERT(id); - DEBUG_ASSERT(id.index / 64 < stored_bitset.size()); - DEBUG_ASSERT(((stored_bitset[id.index / 64] >> (id.index % 64)) & 1) != 0); - } - - [[nodiscard]] u32 FreeValueIndex() noexcept { - if (free_list.empty()) { - Reserve(values_capacity ? (values_capacity << 1) : 1); - } - const u32 free_index = free_list.back(); - free_list.pop_back(); - return free_index; - } - - void Reserve(size_t new_capacity) noexcept { - Entry* const new_values = new Entry[new_capacity]; - size_t index = 0; - for (u64 bits : stored_bitset) { - for (size_t bit = 0; bits; ++bit, bits >>= 1) { - const size_t i = index + bit; - if ((bits & 1) == 0) { - continue; - } - T& old_value = values[i].object; - new (&new_values[i].object) T(std::move(old_value)); - old_value.~T(); - } - index += 64; - } - - stored_bitset.resize((new_capacity + 63) / 64); - - const size_t old_free_size = free_list.size(); - free_list.resize(old_free_size + (new_capacity - values_capacity)); - std::iota(free_list.begin() + old_free_size, free_list.end(), - static_cast(values_capacity)); - - delete[] values; - values = new_values; - values_capacity = new_capacity; - } - - Entry* values = nullptr; - size_t values_capacity = 0; - - std::vector stored_bitset; - std::vector free_list; -}; - -} // namespace VideoCommon - -template <> -struct std::hash { - size_t operator()(const VideoCommon::SlotId& id) const noexcept { - return std::hash{}(id.index); - } -}; diff --git a/src/video_core/texture_cache/texture_cache_base.h b/src/video_core/texture_cache/texture_cache_base.h index e7b910121..da98a634b 100644 --- a/src/video_core/texture_cache/texture_cache_base.h +++ b/src/video_core/texture_cache/texture_cache_base.h @@ -21,6 +21,7 @@ #include "common/lru_cache.h" #include "common/polyfill_ranges.h" #include "common/scratch_buffer.h" +#include "common/slot_vector.h" #include "common/thread_worker.h" #include "video_core/compatible_formats.h" #include "video_core/control/channel_state_cache.h" @@ -32,7 +33,6 @@ #include "video_core/texture_cache/image_info.h" #include "video_core/texture_cache/image_view_base.h" #include "video_core/texture_cache/render_targets.h" -#include "video_core/texture_cache/slot_vector.h" #include "video_core/texture_cache/types.h" #include "video_core/textures/texture.h" @@ -451,16 +451,16 @@ private: struct PendingDownload { bool is_swizzle; size_t async_buffer_id; - SlotId object_id; + Common::SlotId object_id; }; - SlotVector slot_images; - SlotVector slot_map_views; - SlotVector slot_image_views; - SlotVector slot_image_allocs; - SlotVector slot_samplers; - SlotVector slot_framebuffers; - SlotVector slot_buffer_downloads; + Common::SlotVector slot_images; + Common::SlotVector slot_map_views; + Common::SlotVector slot_image_views; + Common::SlotVector slot_image_allocs; + Common::SlotVector slot_samplers; + Common::SlotVector slot_framebuffers; + Common::SlotVector slot_buffer_downloads; // TODO: This data structure is not optimal and it should be reworked diff --git a/src/video_core/texture_cache/types.h b/src/video_core/texture_cache/types.h index 0453456b4..07c304386 100644 --- a/src/video_core/texture_cache/types.h +++ b/src/video_core/texture_cache/types.h @@ -5,21 +5,21 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "video_core/texture_cache/slot_vector.h" +#include "common/slot_vector.h" namespace VideoCommon { constexpr size_t NUM_RT = 8; constexpr size_t MAX_MIP_LEVELS = 14; -constexpr SlotId CORRUPT_ID{0xfffffffe}; +constexpr Common::SlotId CORRUPT_ID{0xfffffffe}; -using ImageId = SlotId; -using ImageMapId = SlotId; -using ImageViewId = SlotId; -using ImageAllocId = SlotId; -using SamplerId = SlotId; -using FramebufferId = SlotId; +using ImageId = Common::SlotId; +using ImageMapId = Common::SlotId; +using ImageViewId = Common::SlotId; +using ImageAllocId = Common::SlotId; +using SamplerId = Common::SlotId; +using FramebufferId = Common::SlotId; /// Fake image ID for null image views constexpr ImageId NULL_IMAGE_ID{0}; -- cgit v1.2.3