diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.cpp | 12 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_resource_manager.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_stream_buffer.cpp | 90 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_stream_buffer.h | 72 |
5 files changed, 172 insertions, 8 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 6036d6ed3..60529323e 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -111,7 +111,9 @@ if (ENABLE_VULKAN) | |||
| 111 | renderer_vulkan/vk_resource_manager.cpp | 111 | renderer_vulkan/vk_resource_manager.cpp |
| 112 | renderer_vulkan/vk_resource_manager.h | 112 | renderer_vulkan/vk_resource_manager.h |
| 113 | renderer_vulkan/vk_scheduler.cpp | 113 | renderer_vulkan/vk_scheduler.cpp |
| 114 | renderer_vulkan/vk_scheduler.h) | 114 | renderer_vulkan/vk_scheduler.h |
| 115 | renderer_vulkan/vk_stream_buffer.cpp | ||
| 116 | renderer_vulkan/vk_stream_buffer.h) | ||
| 115 | 117 | ||
| 116 | target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) | 118 | target_include_directories(video_core PRIVATE ../../externals/Vulkan-Headers/include) |
| 117 | target_compile_definitions(video_core PRIVATE HAS_VULKAN) | 119 | target_compile_definitions(video_core PRIVATE HAS_VULKAN) |
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.cpp b/src/video_core/renderer_vulkan/vk_resource_manager.cpp index 1678463c7..a1e117443 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_resource_manager.cpp | |||
| @@ -125,11 +125,12 @@ void VKFence::Protect(VKResource* resource) { | |||
| 125 | protected_resources.push_back(resource); | 125 | protected_resources.push_back(resource); |
| 126 | } | 126 | } |
| 127 | 127 | ||
| 128 | void VKFence::Unprotect(const VKResource* resource) { | 128 | void VKFence::Unprotect(VKResource* resource) { |
| 129 | const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource); | 129 | const auto it = std::find(protected_resources.begin(), protected_resources.end(), resource); |
| 130 | if (it != protected_resources.end()) { | 130 | ASSERT(it != protected_resources.end()); |
| 131 | protected_resources.erase(it); | 131 | |
| 132 | } | 132 | resource->OnFenceRemoval(this); |
| 133 | protected_resources.erase(it); | ||
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | VKFenceWatch::VKFenceWatch() = default; | 136 | VKFenceWatch::VKFenceWatch() = default; |
| @@ -141,12 +142,11 @@ VKFenceWatch::~VKFenceWatch() { | |||
| 141 | } | 142 | } |
| 142 | 143 | ||
| 143 | void VKFenceWatch::Wait() { | 144 | void VKFenceWatch::Wait() { |
| 144 | if (!fence) { | 145 | if (fence == nullptr) { |
| 145 | return; | 146 | return; |
| 146 | } | 147 | } |
| 147 | fence->Wait(); | 148 | fence->Wait(); |
| 148 | fence->Unprotect(this); | 149 | fence->Unprotect(this); |
| 149 | fence = nullptr; | ||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | void VKFenceWatch::Watch(VKFence& new_fence) { | 152 | void VKFenceWatch::Watch(VKFence& new_fence) { |
diff --git a/src/video_core/renderer_vulkan/vk_resource_manager.h b/src/video_core/renderer_vulkan/vk_resource_manager.h index 5018dfa44..5bfe4cead 100644 --- a/src/video_core/renderer_vulkan/vk_resource_manager.h +++ b/src/video_core/renderer_vulkan/vk_resource_manager.h | |||
| @@ -63,7 +63,7 @@ public: | |||
| 63 | void Protect(VKResource* resource); | 63 | void Protect(VKResource* resource); |
| 64 | 64 | ||
| 65 | /// Removes protection for a resource. | 65 | /// Removes protection for a resource. |
| 66 | void Unprotect(const VKResource* resource); | 66 | void Unprotect(VKResource* resource); |
| 67 | 67 | ||
| 68 | /// Retreives the fence. | 68 | /// Retreives the fence. |
| 69 | operator vk::Fence() const { | 69 | operator vk::Fence() const { |
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp new file mode 100644 index 000000000..58ffa42f2 --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp | |||
| @@ -0,0 +1,90 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <memory> | ||
| 7 | #include <optional> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 12 | #include "video_core/renderer_vulkan/vk_device.h" | ||
| 13 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_resource_manager.h" | ||
| 15 | #include "video_core/renderer_vulkan/vk_scheduler.h" | ||
| 16 | #include "video_core/renderer_vulkan/vk_stream_buffer.h" | ||
| 17 | |||
| 18 | namespace Vulkan { | ||
| 19 | |||
| 20 | constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; | ||
| 21 | constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; | ||
| 22 | |||
| 23 | VKStreamBuffer::VKStreamBuffer(const VKDevice& device, VKMemoryManager& memory_manager, | ||
| 24 | VKScheduler& scheduler, u64 size, vk::BufferUsageFlags usage, | ||
| 25 | vk::AccessFlags access, vk::PipelineStageFlags pipeline_stage) | ||
| 26 | : device{device}, scheduler{scheduler}, buffer_size{size}, access{access}, pipeline_stage{ | ||
| 27 | pipeline_stage} { | ||
| 28 | CreateBuffers(memory_manager, usage); | ||
| 29 | ReserveWatches(WATCHES_INITIAL_RESERVE); | ||
| 30 | } | ||
| 31 | |||
| 32 | VKStreamBuffer::~VKStreamBuffer() = default; | ||
| 33 | |||
| 34 | std::tuple<u8*, u64, bool> VKStreamBuffer::Reserve(u64 size) { | ||
| 35 | ASSERT(size <= buffer_size); | ||
| 36 | mapped_size = size; | ||
| 37 | |||
| 38 | if (offset + size > buffer_size) { | ||
| 39 | // The buffer would overflow, save the amount of used buffers, signal an invalidation and | ||
| 40 | // reset the state. | ||
| 41 | invalidation_mark = used_watches; | ||
| 42 | used_watches = 0; | ||
| 43 | offset = 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | return {mapped_pointer + offset, offset, invalidation_mark.has_value()}; | ||
| 47 | } | ||
| 48 | |||
| 49 | VKExecutionContext VKStreamBuffer::Send(VKExecutionContext exctx, u64 size) { | ||
| 50 | ASSERT_MSG(size <= mapped_size, "Reserved size is too small"); | ||
| 51 | |||
| 52 | if (invalidation_mark) { | ||
| 53 | // TODO(Rodrigo): Find a better way to invalidate than waiting for all watches to finish. | ||
| 54 | exctx = scheduler.Flush(); | ||
| 55 | std::for_each(watches.begin(), watches.begin() + *invalidation_mark, | ||
| 56 | [&](auto& resource) { resource->Wait(); }); | ||
| 57 | invalidation_mark = std::nullopt; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (used_watches + 1 >= watches.size()) { | ||
| 61 | // Ensure that there are enough watches. | ||
| 62 | ReserveWatches(WATCHES_RESERVE_CHUNK); | ||
| 63 | } | ||
| 64 | // Add a watch for this allocation. | ||
| 65 | watches[used_watches++]->Watch(exctx.GetFence()); | ||
| 66 | |||
| 67 | offset += size; | ||
| 68 | |||
| 69 | return exctx; | ||
| 70 | } | ||
| 71 | |||
| 72 | void VKStreamBuffer::CreateBuffers(VKMemoryManager& memory_manager, vk::BufferUsageFlags usage) { | ||
| 73 | const vk::BufferCreateInfo buffer_ci({}, buffer_size, usage, vk::SharingMode::eExclusive, 0, | ||
| 74 | nullptr); | ||
| 75 | |||
| 76 | const auto dev = device.GetLogical(); | ||
| 77 | const auto& dld = device.GetDispatchLoader(); | ||
| 78 | buffer = dev.createBufferUnique(buffer_ci, nullptr, dld); | ||
| 79 | commit = memory_manager.Commit(*buffer, true); | ||
| 80 | mapped_pointer = commit->GetData(); | ||
| 81 | } | ||
| 82 | |||
| 83 | void VKStreamBuffer::ReserveWatches(std::size_t grow_size) { | ||
| 84 | const std::size_t previous_size = watches.size(); | ||
| 85 | watches.resize(previous_size + grow_size); | ||
| 86 | std::generate(watches.begin() + previous_size, watches.end(), | ||
| 87 | []() { return std::make_unique<VKFenceWatch>(); }); | ||
| 88 | } | ||
| 89 | |||
| 90 | } // namespace Vulkan | ||
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h new file mode 100644 index 000000000..69d036ccd --- /dev/null +++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <optional> | ||
| 9 | #include <tuple> | ||
| 10 | #include <vector> | ||
| 11 | |||
| 12 | #include "common/common_types.h" | ||
| 13 | #include "video_core/renderer_vulkan/declarations.h" | ||
| 14 | #include "video_core/renderer_vulkan/vk_memory_manager.h" | ||
| 15 | |||
| 16 | namespace Vulkan { | ||
| 17 | |||
| 18 | class VKDevice; | ||
| 19 | class VKFence; | ||
| 20 | class VKFenceWatch; | ||
| 21 | class VKResourceManager; | ||
| 22 | class VKScheduler; | ||
| 23 | |||
| 24 | class VKStreamBuffer { | ||
| 25 | public: | ||
| 26 | explicit VKStreamBuffer(const VKDevice& device, VKMemoryManager& memory_manager, | ||
| 27 | VKScheduler& scheduler, u64 size, vk::BufferUsageFlags usage, | ||
| 28 | vk::AccessFlags access, vk::PipelineStageFlags pipeline_stage); | ||
| 29 | ~VKStreamBuffer(); | ||
| 30 | |||
| 31 | /** | ||
| 32 | * Reserves a region of memory from the stream buffer. | ||
| 33 | * @param size Size to reserve. | ||
| 34 | * @returns A tuple in the following order: Raw memory pointer (with offset added), buffer | ||
| 35 | * offset and a boolean that's true when buffer has been invalidated. | ||
| 36 | */ | ||
| 37 | std::tuple<u8*, u64, bool> Reserve(u64 size); | ||
| 38 | |||
| 39 | /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. | ||
| 40 | [[nodiscard]] VKExecutionContext Send(VKExecutionContext exctx, u64 size); | ||
| 41 | |||
| 42 | vk::Buffer GetBuffer() const { | ||
| 43 | return *buffer; | ||
| 44 | } | ||
| 45 | |||
| 46 | private: | ||
| 47 | /// Creates Vulkan buffer handles committing the required the required memory. | ||
| 48 | void CreateBuffers(VKMemoryManager& memory_manager, vk::BufferUsageFlags usage); | ||
| 49 | |||
| 50 | /// Increases the amount of watches available. | ||
| 51 | void ReserveWatches(std::size_t grow_size); | ||
| 52 | |||
| 53 | const VKDevice& device; ///< Vulkan device manager. | ||
| 54 | VKScheduler& scheduler; ///< Command scheduler. | ||
| 55 | const u64 buffer_size; ///< Total size of the stream buffer. | ||
| 56 | const vk::AccessFlags access; ///< Access usage of this stream buffer. | ||
| 57 | const vk::PipelineStageFlags pipeline_stage; ///< Pipeline usage of this stream buffer. | ||
| 58 | |||
| 59 | UniqueBuffer buffer; ///< Mapped buffer. | ||
| 60 | VKMemoryCommit commit; ///< Memory commit. | ||
| 61 | u8* mapped_pointer{}; ///< Pointer to the host visible commit | ||
| 62 | |||
| 63 | u64 offset{}; ///< Buffer iterator. | ||
| 64 | u64 mapped_size{}; ///< Size reserved for the current copy. | ||
| 65 | |||
| 66 | std::vector<std::unique_ptr<VKFenceWatch>> watches; ///< Total watches | ||
| 67 | std::size_t used_watches{}; ///< Count of watches, reset on invalidation. | ||
| 68 | std::optional<std::size_t> | ||
| 69 | invalidation_mark{}; ///< Number of watches used in the current invalidation. | ||
| 70 | }; | ||
| 71 | |||
| 72 | } // namespace Vulkan | ||