diff --git a/CMakeLists.txt b/CMakeLists.txt index fbba0359..4df3db2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -487,8 +487,6 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp src/video_core/renderer_vulkan/vk_scheduler.h src/video_core/renderer_vulkan/vk_shader_util.cpp src/video_core/renderer_vulkan/vk_shader_util.h - src/video_core/renderer_vulkan/vk_stream_buffer.cpp - src/video_core/renderer_vulkan/vk_stream_buffer.h src/video_core/renderer_vulkan/vk_swapchain.cpp src/video_core/renderer_vulkan/vk_swapchain.h src/video_core/texture_cache/image.cpp diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index bc1eb409..97438f80 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -406,7 +406,7 @@ void PatchBufferInstruction(IR::Block& block, IR::Inst& inst, Info& info, .dword_offset = sharp.dword_offset, .length = BufferLength(buffer), .used_types = BufferDataType(inst, buffer.GetNumberFmt()), - .is_storage = true || is_store || buffer.GetSize() > MaxUboSize, + .is_storage = is_store || buffer.GetSize() > MaxUboSize, .is_written = is_store, }); } diff --git a/src/video_core/buffer_cache/memory_tracker_base.h b/src/video_core/buffer_cache/memory_tracker_base.h index 62439447..375701c4 100644 --- a/src/video_core/buffer_cache/memory_tracker_base.h +++ b/src/video_core/buffer_cache/memory_tracker_base.h @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/buffer_cache/word_manager.h b/src/video_core/buffer_cache/word_manager.h index e7aaf207..549d2a9e 100644 --- a/src/video_core/buffer_cache/word_manager.h +++ b/src/video_core/buffer_cache/word_manager.h @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later #pragma once diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index cc519374..3345deb8 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -7,7 +7,6 @@ #include "video_core/renderer_vulkan/vk_compute_pipeline.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_scheduler.h" -#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/texture_cache/texture_cache.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index 752f8c39..16de5635 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -15,7 +15,6 @@ namespace Vulkan { class Instance; class Scheduler; -class StreamBuffer; class ComputePipeline { public: diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d64d382b..5d87a1ca 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -1,6 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#pragma clang optimize off + #include #include #include @@ -12,7 +12,6 @@ #include "video_core/renderer_vulkan/vk_graphics_pipeline.h" #include "video_core/renderer_vulkan/vk_instance.h" #include "video_core/renderer_vulkan/vk_scheduler.h" -#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/texture_cache/texture_cache.h" namespace Vulkan { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h index 2d8d9847..f818d980 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.h @@ -19,7 +19,6 @@ static constexpr u32 MaxShaderStages = 5; class Instance; class Scheduler; -class StreamBuffer; using Liverpool = AmdGpu::Liverpool; diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp deleted file mode 100644 index 116f7896..00000000 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#include -#include "common/alignment.h" -#include "common/assert.h" -#include "video_core/renderer_vulkan/vk_instance.h" -#include "video_core/renderer_vulkan/vk_scheduler.h" -#include "video_core/renderer_vulkan/vk_stream_buffer.h" - -namespace Vulkan { - -namespace { - -std::string_view BufferTypeName(BufferType type) { - switch (type) { - case BufferType::Upload: - return "Upload"; - case BufferType::Download: - return "Download"; - case BufferType::Stream: - return "Stream"; - default: - return "Invalid"; - } -} - -vk::MemoryPropertyFlags MakePropertyFlags(BufferType type) { - switch (type) { - case BufferType::Upload: - return vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent; - case BufferType::Download: - return vk::MemoryPropertyFlagBits::eHostVisible | - vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached; - case BufferType::Stream: - return vk::MemoryPropertyFlagBits::eDeviceLocal | vk::MemoryPropertyFlagBits::eHostVisible | - vk::MemoryPropertyFlagBits::eHostCoherent; - default: - UNREACHABLE_MSG("Unknown buffer type {}", static_cast(type)); - return vk::MemoryPropertyFlagBits::eHostVisible; - } -} - -static std::optional FindMemoryType(const vk::PhysicalDeviceMemoryProperties& properties, - vk::MemoryPropertyFlags wanted) { - for (u32 i = 0; i < properties.memoryTypeCount; ++i) { - const auto flags = properties.memoryTypes[i].propertyFlags; - if ((flags & wanted) == wanted) { - return i; - } - } - return std::nullopt; -} - -/// Get the preferred host visible memory type. -u32 GetMemoryType(const vk::PhysicalDeviceMemoryProperties& properties, BufferType type) { - vk::MemoryPropertyFlags flags = MakePropertyFlags(type); - std::optional preferred_type = FindMemoryType(properties, flags); - - constexpr std::array remove_flags = { - vk::MemoryPropertyFlagBits::eHostCached, - vk::MemoryPropertyFlagBits::eHostCoherent, - }; - - for (u32 i = 0; i < remove_flags.size() && !preferred_type; i++) { - flags &= ~remove_flags[i]; - preferred_type = FindMemoryType(properties, flags); - } - ASSERT_MSG(preferred_type, "No suitable memory type found"); - return preferred_type.value(); -} - -constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; -constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; - -} // Anonymous namespace - -StreamBuffer::StreamBuffer(const Instance& instance_, Scheduler& scheduler_, - vk::BufferUsageFlags usage_, u64 size, BufferType type_) - : instance{instance_}, scheduler{scheduler_}, device{instance.GetDevice()}, - stream_buffer_size{size}, usage{usage_}, type{type_} { - CreateBuffers(size); - ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE); - ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE); -} - -StreamBuffer::~StreamBuffer() { - device.unmapMemory(memory); - device.destroyBuffer(buffer); - device.freeMemory(memory); -} - -std::tuple StreamBuffer::Map(u64 size, u64 alignment) { - if (!is_coherent && type == BufferType::Stream) { - size = Common::AlignUp(size, instance.NonCoherentAtomSize()); - } - - ASSERT(size <= stream_buffer_size); - mapped_size = size; - - if (alignment > 0) { - offset = Common::AlignUp(offset, alignment); - } - - bool invalidate{false}; - if (offset + size > stream_buffer_size) { - // The buffer would overflow, save the amount of used watches and reset the state. - invalidate = true; - invalidation_mark = current_watch_cursor; - current_watch_cursor = 0; - offset = 0; - - // Swap watches and reset waiting cursors. - std::swap(previous_watches, current_watches); - wait_cursor = 0; - wait_bound = 0; - } - - const u64 mapped_upper_bound = offset + size; - WaitPendingOperations(mapped_upper_bound); - - return std::make_tuple(mapped + offset, offset, invalidate); -} - -void StreamBuffer::Commit(u64 size) { - if (!is_coherent && type == BufferType::Stream) { - size = Common::AlignUp(size, instance.NonCoherentAtomSize()); - } - - ASSERT_MSG(size <= mapped_size, "Reserved size {} is too small compared to {}", mapped_size, - size); - - const vk::MappedMemoryRange range = { - .memory = memory, - .offset = offset, - .size = size, - }; - - if (!is_coherent && type == BufferType::Download) { - device.invalidateMappedMemoryRanges(range); - } else if (!is_coherent) { - device.flushMappedMemoryRanges(range); - } - - offset += size; - - if (current_watch_cursor + 1 >= current_watches.size()) { - // Ensure that there are enough watches. - ReserveWatches(current_watches, WATCHES_RESERVE_CHUNK); - } - auto& watch = current_watches[current_watch_cursor++]; - watch.upper_bound = offset; - watch.tick = scheduler.CurrentTick(); -} - -void StreamBuffer::CreateBuffers(u64 prefered_size) { - const vk::Device device = instance.GetDevice(); - const auto memory_properties = instance.GetPhysicalDevice().getMemoryProperties(); - const u32 preferred_type = GetMemoryType(memory_properties, type); - const vk::MemoryType mem_type = memory_properties.memoryTypes[preferred_type]; - const u32 preferred_heap = mem_type.heapIndex; - is_coherent = - static_cast(mem_type.propertyFlags & vk::MemoryPropertyFlagBits::eHostCoherent); - - // Substract from the preferred heap size some bytes to avoid getting out of memory. - const vk::DeviceSize heap_size = memory_properties.memoryHeaps[preferred_heap].size; - // As per DXVK's example, using `heap_size / 2` - const vk::DeviceSize allocable_size = heap_size / 2; - buffer = device.createBuffer({ - .size = std::min(prefered_size, allocable_size), - .usage = usage, - }); - - const auto requirements_chain = - device - .getBufferMemoryRequirements2( - {.buffer = buffer}); - - const auto& requirements = requirements_chain.get(); - const auto& dedicated_requirements = requirements_chain.get(); - - stream_buffer_size = static_cast(requirements.memoryRequirements.size); - - LOG_INFO(Render_Vulkan, "Creating {} buffer with size {} KiB with flags {}", - BufferTypeName(type), stream_buffer_size / 1024, - vk::to_string(mem_type.propertyFlags)); - - if (dedicated_requirements.prefersDedicatedAllocation) { - vk::StructureChain alloc_chain = - {}; - - auto& alloc_info = alloc_chain.get(); - alloc_info.allocationSize = requirements.memoryRequirements.size; - alloc_info.memoryTypeIndex = preferred_type; - - auto& dedicated_alloc_info = alloc_chain.get(); - dedicated_alloc_info.buffer = buffer; - - memory = device.allocateMemory(alloc_chain.get()); - } else { - memory = device.allocateMemory({ - .allocationSize = requirements.memoryRequirements.size, - .memoryTypeIndex = preferred_type, - }); - } - - device.bindBufferMemory(buffer, memory, 0); - mapped = reinterpret_cast(device.mapMemory(memory, 0, VK_WHOLE_SIZE)); - - if (instance.HasDebuggingToolAttached()) { - SetObjectName(device, buffer, "StreamBuffer({}): {} KiB {}", BufferTypeName(type), - stream_buffer_size / 1024, vk::to_string(mem_type.propertyFlags)); - SetObjectName(device, memory, "StreamBufferMemory({}): {} Kib {}", BufferTypeName(type), - stream_buffer_size / 1024, vk::to_string(mem_type.propertyFlags)); - } -} - -void StreamBuffer::ReserveWatches(std::vector& watches, std::size_t grow_size) { - watches.resize(watches.size() + grow_size); -} - -void StreamBuffer::WaitPendingOperations(u64 requested_upper_bound) { - if (!invalidation_mark) { - return; - } - while (requested_upper_bound > wait_bound && wait_cursor < *invalidation_mark) { - auto& watch = previous_watches[wait_cursor]; - wait_bound = watch.upper_bound; - scheduler.Wait(watch.tick); - ++wait_cursor; - } -} - -u64 StreamBuffer::Copy(VAddr src, size_t size, size_t alignment /*= 0*/) { - const auto [data, offset, _] = Map(size, alignment); - std::memcpy(data, reinterpret_cast(src), size); - Commit(size); - return offset; -} - -} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h deleted file mode 100644 index e29728d1..00000000 --- a/src/video_core/renderer_vulkan/vk_stream_buffer.h +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include -#include -#include -#include -#include "common/types.h" -#include "video_core/renderer_vulkan/vk_common.h" - -namespace Vulkan { - -enum class BufferType : u32 { - Upload = 0, - Download = 1, - Stream = 2, -}; - -class Instance; -class Scheduler; - -class StreamBuffer final { -public: - explicit StreamBuffer(const Instance& instance, Scheduler& scheduler, - vk::BufferUsageFlags usage, u64 size, - BufferType type = BufferType::Stream); - ~StreamBuffer(); - - /** - * Reserves a region of memory from the stream buffer. - * @param size Size to reserve. - * @returns A pair of a raw memory pointer (with offset added), and the buffer offset - */ - std::tuple Map(u64 size, u64 alignment = 0); - - /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. - void Commit(u64 size); - - /// Maps and commits a memory region with user provided data - u64 Copy(VAddr src, size_t size, size_t alignment = 0); - - vk::Buffer Handle() const noexcept { - return buffer; - } - -private: - struct Watch { - u64 tick{}; - u64 upper_bound{}; - }; - - /// Creates Vulkan buffer handles committing the required the required memory. - void CreateBuffers(u64 prefered_size); - - /// Increases the amount of watches available. - void ReserveWatches(std::vector& watches, std::size_t grow_size); - - void WaitPendingOperations(u64 requested_upper_bound); - -private: - const Instance& instance; ///< Vulkan instance. - Scheduler& scheduler; ///< Command scheduler. - - vk::Device device; - vk::Buffer buffer; ///< Mapped buffer. - vk::DeviceMemory memory; ///< Memory allocation. - u8* mapped{}; ///< Pointer to the mapped memory - u64 stream_buffer_size{}; ///< Stream buffer size. - vk::BufferUsageFlags usage{}; - BufferType type; - - u64 offset{}; ///< Buffer iterator. - u64 mapped_size{}; ///< Size reserved for the current copy. - bool is_coherent{}; ///< True if the buffer is coherent - - std::vector current_watches; ///< Watches recorded in the current iteration. - std::size_t current_watch_cursor{}; ///< Count of watches, reset on invalidation. - std::optional invalidation_mark; ///< Number of watches used in the previous cycle. - - std::vector previous_watches; ///< Watches used in the previous iteration. - std::size_t wait_cursor{}; ///< Last watch being waited for completion. - u64 wait_bound{}; ///< Highest offset being watched for completion. -}; - -} // namespace Vulkan diff --git a/src/video_core/texture_cache/texture_cache.cpp b/src/video_core/texture_cache/texture_cache.cpp index 0070eb23..53596f8e 100644 --- a/src/video_core/texture_cache/texture_cache.cpp +++ b/src/video_core/texture_cache/texture_cache.cpp @@ -17,8 +17,7 @@ static constexpr u64 PageShift = 12; TextureCache::TextureCache(const Vulkan::Instance& instance_, Vulkan::Scheduler& scheduler_, BufferCache& buffer_cache_, PageManager& tracker_) : instance{instance_}, scheduler{scheduler_}, buffer_cache{buffer_cache_}, tracker{tracker_}, - staging{instance, scheduler, vk::BufferUsageFlagBits::eTransferSrc, StreamBufferSize, - Vulkan::BufferType::Upload}, + staging{instance, scheduler, MemoryUsage::Upload, StreamBufferSize}, tile_manager{instance, scheduler} { ImageInfo info; info.pixel_format = vk::Format::eR8G8B8A8Unorm; @@ -242,10 +241,7 @@ void TextureCache::RefreshImage(Image& image) { buffer = *upload_buffer; } else { // Upload data to the staging buffer. - const auto [data, offset_, _] = staging.Map(image.info.guest_size_bytes, 16); - std::memcpy(data, (void*)image.info.guest_address, image.info.guest_size_bytes); - staging.Commit(image.info.guest_size_bytes); - offset = offset_; + offset = staging.Copy(image.info.guest_address, image.info.guest_size_bytes, 16); } const auto& num_layers = image.info.resources.layers; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 5753907e..17a09898 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -4,13 +4,11 @@ #pragma once #include -#include #include #include "common/slot_vector.h" #include "video_core/amdgpu/resource.h" #include "video_core/multi_level_page_table.h" -#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/texture_cache/image.h" #include "video_core/texture_cache/image_view.h" #include "video_core/texture_cache/sampler.h" @@ -172,13 +170,12 @@ private: Vulkan::Scheduler& scheduler; BufferCache& buffer_cache; PageManager& tracker; - Vulkan::StreamBuffer staging; + StreamBuffer staging; TileManager tile_manager; Common::SlotVector slot_images; Common::SlotVector slot_image_views; tsl::robin_map samplers; PageTable page_table; - boost::icl::interval_map cached_pages; std::mutex mutex; struct MetaDataInfo { diff --git a/src/video_core/texture_cache/tile_manager.h b/src/video_core/texture_cache/tile_manager.h index 542c6bac..00765b1f 100644 --- a/src/video_core/texture_cache/tile_manager.h +++ b/src/video_core/texture_cache/tile_manager.h @@ -5,7 +5,6 @@ #include "common/types.h" #include "video_core/buffer_cache/buffer.h" -#include "video_core/renderer_vulkan/vk_stream_buffer.h" #include "video_core/texture_cache/image.h" namespace VideoCore {