summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp143
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h73
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.cpp142
-rw-r--r--src/video_core/renderer_vulkan/vk_stream_buffer.h44
4 files changed, 340 insertions, 62 deletions
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
index c36ede898..1ba544943 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -1,3 +1,146 @@
1// Copyright 2019 yuzu Emulator Project 1// Copyright 2019 yuzu Emulator Project
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <cstring>
7#include <memory>
8#include <optional>
9#include <tuple>
10
11#include "common/assert.h"
12#include "common/bit_util.h"
13#include "core/core.h"
14#include "video_core/renderer_vulkan/declarations.h"
15#include "video_core/renderer_vulkan/vk_buffer_cache.h"
16#include "video_core/renderer_vulkan/vk_device.h"
17#include "video_core/renderer_vulkan/vk_scheduler.h"
18#include "video_core/renderer_vulkan/vk_stream_buffer.h"
19
20namespace Vulkan {
21
22namespace {
23
24const auto BufferUsage =
25 vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
26 vk::BufferUsageFlagBits::eUniformBuffer | vk::BufferUsageFlagBits::eStorageBuffer;
27
28const auto UploadPipelineStage =
29 vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eVertexInput |
30 vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader |
31 vk::PipelineStageFlagBits::eComputeShader;
32
33const auto UploadAccessBarriers =
34 vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eShaderRead |
35 vk::AccessFlagBits::eUniformRead | vk::AccessFlagBits::eVertexAttributeRead |
36 vk::AccessFlagBits::eIndexRead;
37
38auto CreateStreamBuffer(const VKDevice& device, VKScheduler& scheduler) {
39 return std::make_unique<VKStreamBuffer>(device, scheduler, BufferUsage);
40}
41
42} // Anonymous namespace
43
44CachedBufferBlock::CachedBufferBlock(const VKDevice& device, VKMemoryManager& memory_manager,
45 CacheAddr cache_addr, std::size_t size)
46 : VideoCommon::BufferBlock{cache_addr, size} {
47 const vk::BufferCreateInfo buffer_ci({}, static_cast<vk::DeviceSize>(size),
48 BufferUsage | vk::BufferUsageFlagBits::eTransferSrc |
49 vk::BufferUsageFlagBits::eTransferDst,
50 vk::SharingMode::eExclusive, 0, nullptr);
51
52 const auto& dld{device.GetDispatchLoader()};
53 const auto dev{device.GetLogical()};
54 buffer.handle = dev.createBufferUnique(buffer_ci, nullptr, dld);
55 buffer.commit = memory_manager.Commit(*buffer.handle, false);
56}
57
58CachedBufferBlock::~CachedBufferBlock() = default;
59
60VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
61 const VKDevice& device, VKMemoryManager& memory_manager,
62 VKScheduler& scheduler, VKStagingBufferPool& staging_pool)
63 : VideoCommon::BufferCache<Buffer, vk::Buffer, VKStreamBuffer>{rasterizer, system,
64 CreateStreamBuffer(device,
65 scheduler)},
66 device{device}, memory_manager{memory_manager}, scheduler{scheduler}, staging_pool{
67 staging_pool} {}
68
69VKBufferCache::~VKBufferCache() = default;
70
71Buffer VKBufferCache::CreateBlock(CacheAddr cache_addr, std::size_t size) {
72 return std::make_shared<CachedBufferBlock>(device, memory_manager, cache_addr, size);
73}
74
75const vk::Buffer* VKBufferCache::ToHandle(const Buffer& buffer) {
76 return buffer->GetHandle();
77}
78
79const vk::Buffer* VKBufferCache::GetEmptyBuffer(std::size_t size) {
80 size = std::max(size, std::size_t(4));
81 const auto& empty = staging_pool.GetUnusedBuffer(size, false);
82 scheduler.RequestOutsideRenderPassOperationContext();
83 scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf, auto& dld) {
84 cmdbuf.fillBuffer(buffer, 0, size, 0, dld);
85 });
86 return &*empty.handle;
87}
88
89void VKBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
90 const u8* data) {
91 const auto& staging = staging_pool.GetUnusedBuffer(size, true);
92 std::memcpy(staging.commit->Map(size), data, size);
93
94 scheduler.RequestOutsideRenderPassOperationContext();
95 scheduler.Record([staging = *staging.handle, buffer = *buffer->GetHandle(), offset,
96 size](auto cmdbuf, auto& dld) {
97 cmdbuf.copyBuffer(staging, buffer, {{0, offset, size}}, dld);
98 cmdbuf.pipelineBarrier(
99 vk::PipelineStageFlagBits::eTransfer, UploadPipelineStage, {}, {},
100 {vk::BufferMemoryBarrier(vk::AccessFlagBits::eTransferWrite, UploadAccessBarriers,
101 VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, buffer,
102 offset, size)},
103 {}, dld);
104 });
105}
106
107void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
108 u8* data) {
109 const auto& staging = staging_pool.GetUnusedBuffer(size, true);
110 scheduler.RequestOutsideRenderPassOperationContext();
111 scheduler.Record([staging = *staging.handle, buffer = *buffer->GetHandle(), offset,
112 size](auto cmdbuf, auto& dld) {
113 cmdbuf.pipelineBarrier(
114 vk::PipelineStageFlagBits::eVertexShader | vk::PipelineStageFlagBits::eFragmentShader |
115 vk::PipelineStageFlagBits::eComputeShader,
116 vk::PipelineStageFlagBits::eTransfer, {}, {},
117 {vk::BufferMemoryBarrier(vk::AccessFlagBits::eShaderWrite,
118 vk::AccessFlagBits::eTransferRead, VK_QUEUE_FAMILY_IGNORED,
119 VK_QUEUE_FAMILY_IGNORED, buffer, offset, size)},
120 {}, dld);
121 cmdbuf.copyBuffer(buffer, staging, {{offset, 0, size}}, dld);
122 });
123 scheduler.Finish();
124
125 std::memcpy(data, staging.commit->Map(size), size);
126}
127
128void VKBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
129 std::size_t dst_offset, std::size_t size) {
130 scheduler.RequestOutsideRenderPassOperationContext();
131 scheduler.Record([src_buffer = *src->GetHandle(), dst_buffer = *dst->GetHandle(), src_offset,
132 dst_offset, size](auto cmdbuf, auto& dld) {
133 cmdbuf.copyBuffer(src_buffer, dst_buffer, {{src_offset, dst_offset, size}}, dld);
134 cmdbuf.pipelineBarrier(
135 vk::PipelineStageFlagBits::eTransfer, UploadPipelineStage, {}, {},
136 {vk::BufferMemoryBarrier(vk::AccessFlagBits::eTransferRead,
137 vk::AccessFlagBits::eShaderWrite, VK_QUEUE_FAMILY_IGNORED,
138 VK_QUEUE_FAMILY_IGNORED, src_buffer, src_offset, size),
139 vk::BufferMemoryBarrier(vk::AccessFlagBits::eTransferWrite, UploadAccessBarriers,
140 VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, dst_buffer,
141 dst_offset, size)},
142 {}, dld);
143 });
144}
145
146} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
index bc6e584cf..3f38eed0c 100644
--- a/src/video_core/renderer_vulkan/vk_buffer_cache.h
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -3,3 +3,76 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6
7#include <memory>
8#include <unordered_map>
9#include <vector>
10
11#include "common/common_types.h"
12#include "video_core/buffer_cache/buffer_cache.h"
13#include "video_core/rasterizer_cache.h"
14#include "video_core/renderer_vulkan/declarations.h"
15#include "video_core/renderer_vulkan/vk_memory_manager.h"
16#include "video_core/renderer_vulkan/vk_resource_manager.h"
17#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
18#include "video_core/renderer_vulkan/vk_stream_buffer.h"
19
20namespace Core {
21class System;
22}
23
24namespace Vulkan {
25
26class VKDevice;
27class VKMemoryManager;
28class VKScheduler;
29
30class CachedBufferBlock final : public VideoCommon::BufferBlock {
31public:
32 explicit CachedBufferBlock(const VKDevice& device, VKMemoryManager& memory_manager,
33 CacheAddr cache_addr, std::size_t size);
34 ~CachedBufferBlock();
35
36 const vk::Buffer* GetHandle() const {
37 return &*buffer.handle;
38 }
39
40private:
41 VKBuffer buffer;
42};
43
44using Buffer = std::shared_ptr<CachedBufferBlock>;
45
46class VKBufferCache final : public VideoCommon::BufferCache<Buffer, vk::Buffer, VKStreamBuffer> {
47public:
48 explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
49 const VKDevice& device, VKMemoryManager& memory_manager,
50 VKScheduler& scheduler, VKStagingBufferPool& staging_pool);
51 ~VKBufferCache();
52
53 const vk::Buffer* GetEmptyBuffer(std::size_t size) override;
54
55protected:
56 void WriteBarrier() override {}
57
58 Buffer CreateBlock(CacheAddr cache_addr, std::size_t size) override;
59
60 const vk::Buffer* ToHandle(const Buffer& buffer) override;
61
62 void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
63 const u8* data) override;
64
65 void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
66 u8* data) override;
67
68 void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
69 std::size_t dst_offset, std::size_t size) override;
70
71private:
72 const VKDevice& device;
73 VKMemoryManager& memory_manager;
74 VKScheduler& scheduler;
75 VKStagingBufferPool& staging_pool;
76};
77
78} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
index 62f1427f5..d48d3b44c 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.cpp
@@ -3,86 +3,144 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <memory>
7#include <optional> 6#include <optional>
7#include <tuple>
8#include <vector> 8#include <vector>
9 9
10#include "common/alignment.h"
10#include "common/assert.h" 11#include "common/assert.h"
11#include "video_core/renderer_vulkan/declarations.h" 12#include "video_core/renderer_vulkan/declarations.h"
12#include "video_core/renderer_vulkan/vk_device.h" 13#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" 14#include "video_core/renderer_vulkan/vk_resource_manager.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h" 15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_stream_buffer.h" 16#include "video_core/renderer_vulkan/vk_stream_buffer.h"
17 17
18namespace Vulkan { 18namespace Vulkan {
19 19
20namespace {
21
20constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000; 22constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
21constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000; 23constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
22 24
23VKStreamBuffer::VKStreamBuffer(const VKDevice& device, VKMemoryManager& memory_manager, 25constexpr u64 STREAM_BUFFER_SIZE = 256 * 1024 * 1024;
24 VKScheduler& scheduler, u64 size, vk::BufferUsageFlags usage, 26
25 vk::AccessFlags access, vk::PipelineStageFlags pipeline_stage) 27std::optional<u32> FindMemoryType(const VKDevice& device, u32 filter,
26 : device{device}, scheduler{scheduler}, buffer_size{size}, access{access}, pipeline_stage{ 28 vk::MemoryPropertyFlags wanted) {
27 pipeline_stage} { 29 const auto properties = device.GetPhysical().getMemoryProperties(device.GetDispatchLoader());
28 CreateBuffers(memory_manager, usage); 30 for (u32 i = 0; i < properties.memoryTypeCount; i++) {
29 ReserveWatches(WATCHES_INITIAL_RESERVE); 31 if (!(filter & (1 << i))) {
32 continue;
33 }
34 if ((properties.memoryTypes[i].propertyFlags & wanted) == wanted) {
35 return i;
36 }
37 }
38 return {};
39}
40
41} // Anonymous namespace
42
43VKStreamBuffer::VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler,
44 vk::BufferUsageFlags usage)
45 : device{device}, scheduler{scheduler} {
46 CreateBuffers(usage);
47 ReserveWatches(current_watches, WATCHES_INITIAL_RESERVE);
48 ReserveWatches(previous_watches, WATCHES_INITIAL_RESERVE);
30} 49}
31 50
32VKStreamBuffer::~VKStreamBuffer() = default; 51VKStreamBuffer::~VKStreamBuffer() = default;
33 52
34std::tuple<u8*, u64, bool> VKStreamBuffer::Reserve(u64 size) { 53std::tuple<u8*, u64, bool> VKStreamBuffer::Map(u64 size, u64 alignment) {
35 ASSERT(size <= buffer_size); 54 ASSERT(size <= STREAM_BUFFER_SIZE);
36 mapped_size = size; 55 mapped_size = size;
37 56
38 if (offset + size > buffer_size) { 57 if (alignment > 0) {
39 // The buffer would overflow, save the amount of used buffers, signal an invalidation and 58 offset = Common::AlignUp(offset, alignment);
40 // reset the state. 59 }
41 invalidation_mark = used_watches; 60
42 used_watches = 0; 61 WaitPendingOperations(offset);
62
63 bool invalidated = false;
64 if (offset + size > STREAM_BUFFER_SIZE) {
65 // The buffer would overflow, save the amount of used watches and reset the state.
66 invalidation_mark = current_watch_cursor;
67 current_watch_cursor = 0;
43 offset = 0; 68 offset = 0;
69
70 // Swap watches and reset waiting cursors.
71 std::swap(previous_watches, current_watches);
72 wait_cursor = 0;
73 wait_bound = 0;
74
75 // Ensure that we don't wait for uncommitted fences.
76 scheduler.Flush();
77
78 invalidated = true;
44 } 79 }
45 80
46 return {mapped_pointer + offset, offset, invalidation_mark.has_value()}; 81 const auto dev = device.GetLogical();
82 const auto& dld = device.GetDispatchLoader();
83 const auto pointer = reinterpret_cast<u8*>(dev.mapMemory(*memory, offset, size, {}, dld));
84 return {pointer, offset, invalidated};
47} 85}
48 86
49void VKStreamBuffer::Send(u64 size) { 87void VKStreamBuffer::Unmap(u64 size) {
50 ASSERT_MSG(size <= mapped_size, "Reserved size is too small"); 88 ASSERT_MSG(size <= mapped_size, "Reserved size is too small");
51 89
52 if (invalidation_mark) { 90 const auto dev = device.GetLogical();
53 // TODO(Rodrigo): Find a better way to invalidate than waiting for all watches to finish. 91 dev.unmapMemory(*memory, device.GetDispatchLoader());
54 scheduler.Flush(); 92
55 std::for_each(watches.begin(), watches.begin() + *invalidation_mark, 93 offset += size;
56 [&](auto& resource) { resource->Wait(); });
57 invalidation_mark = std::nullopt;
58 }
59 94
60 if (used_watches + 1 >= watches.size()) { 95 if (current_watch_cursor + 1 >= current_watches.size()) {
61 // Ensure that there are enough watches. 96 // Ensure that there are enough watches.
62 ReserveWatches(WATCHES_RESERVE_CHUNK); 97 ReserveWatches(current_watches, WATCHES_RESERVE_CHUNK);
63 } 98 }
64 // Add a watch for this allocation. 99 auto& watch = current_watches[current_watch_cursor++];
65 watches[used_watches++]->Watch(scheduler.GetFence()); 100 watch.upper_bound = offset;
66 101 watch.fence.Watch(scheduler.GetFence());
67 offset += size;
68} 102}
69 103
70void VKStreamBuffer::CreateBuffers(VKMemoryManager& memory_manager, vk::BufferUsageFlags usage) { 104void VKStreamBuffer::CreateBuffers(vk::BufferUsageFlags usage) {
71 const vk::BufferCreateInfo buffer_ci({}, buffer_size, usage, vk::SharingMode::eExclusive, 0, 105 const vk::BufferCreateInfo buffer_ci({}, STREAM_BUFFER_SIZE, usage, vk::SharingMode::eExclusive,
72 nullptr); 106 0, nullptr);
73
74 const auto dev = device.GetLogical(); 107 const auto dev = device.GetLogical();
75 const auto& dld = device.GetDispatchLoader(); 108 const auto& dld = device.GetDispatchLoader();
76 buffer = dev.createBufferUnique(buffer_ci, nullptr, dld); 109 buffer = dev.createBufferUnique(buffer_ci, nullptr, dld);
77 commit = memory_manager.Commit(*buffer, true); 110
78 mapped_pointer = commit->GetData(); 111 const auto requirements = dev.getBufferMemoryRequirements(*buffer, dld);
112 // Prefer device local host visible allocations (this should hit AMD's pinned memory).
113 auto type = FindMemoryType(device, requirements.memoryTypeBits,
114 vk::MemoryPropertyFlagBits::eHostVisible |
115 vk::MemoryPropertyFlagBits::eHostCoherent |
116 vk::MemoryPropertyFlagBits::eDeviceLocal);
117 if (!type) {
118 // Otherwise search for a host visible allocation.
119 type = FindMemoryType(device, requirements.memoryTypeBits,
120 vk::MemoryPropertyFlagBits::eHostVisible |
121 vk::MemoryPropertyFlagBits::eHostCoherent);
122 ASSERT_MSG(type, "No host visible and coherent memory type found");
123 }
124 const vk::MemoryAllocateInfo alloc_ci(requirements.size, *type);
125 memory = dev.allocateMemoryUnique(alloc_ci, nullptr, dld);
126
127 dev.bindBufferMemory(*buffer, *memory, 0, dld);
79} 128}
80 129
81void VKStreamBuffer::ReserveWatches(std::size_t grow_size) { 130void VKStreamBuffer::ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size) {
82 const std::size_t previous_size = watches.size(); 131 watches.resize(watches.size() + grow_size);
83 watches.resize(previous_size + grow_size); 132}
84 std::generate(watches.begin() + previous_size, watches.end(), 133
85 []() { return std::make_unique<VKFenceWatch>(); }); 134void VKStreamBuffer::WaitPendingOperations(u64 requested_upper_bound) {
135 if (!invalidation_mark) {
136 return;
137 }
138 while (requested_upper_bound < wait_bound && wait_cursor < *invalidation_mark) {
139 auto& watch = previous_watches[wait_cursor];
140 wait_bound = watch.upper_bound;
141 watch.fence.Wait();
142 ++wait_cursor;
143 }
86} 144}
87 145
88} // namespace Vulkan 146} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_stream_buffer.h b/src/video_core/renderer_vulkan/vk_stream_buffer.h
index 842e54162..187c0c612 100644
--- a/src/video_core/renderer_vulkan/vk_stream_buffer.h
+++ b/src/video_core/renderer_vulkan/vk_stream_buffer.h
@@ -4,28 +4,24 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <optional> 7#include <optional>
9#include <tuple> 8#include <tuple>
10#include <vector> 9#include <vector>
11 10
12#include "common/common_types.h" 11#include "common/common_types.h"
13#include "video_core/renderer_vulkan/declarations.h" 12#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_memory_manager.h"
15 13
16namespace Vulkan { 14namespace Vulkan {
17 15
18class VKDevice; 16class VKDevice;
19class VKFence; 17class VKFence;
20class VKFenceWatch; 18class VKFenceWatch;
21class VKResourceManager;
22class VKScheduler; 19class VKScheduler;
23 20
24class VKStreamBuffer { 21class VKStreamBuffer final {
25public: 22public:
26 explicit VKStreamBuffer(const VKDevice& device, VKMemoryManager& memory_manager, 23 explicit VKStreamBuffer(const VKDevice& device, VKScheduler& scheduler,
27 VKScheduler& scheduler, u64 size, vk::BufferUsageFlags usage, 24 vk::BufferUsageFlags usage);
28 vk::AccessFlags access, vk::PipelineStageFlags pipeline_stage);
29 ~VKStreamBuffer(); 25 ~VKStreamBuffer();
30 26
31 /** 27 /**
@@ -34,39 +30,47 @@ public:
34 * @returns A tuple in the following order: Raw memory pointer (with offset added), buffer 30 * @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. 31 * offset and a boolean that's true when buffer has been invalidated.
36 */ 32 */
37 std::tuple<u8*, u64, bool> Reserve(u64 size); 33 std::tuple<u8*, u64, bool> Map(u64 size, u64 alignment);
38 34
39 /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy. 35 /// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
40 void Send(u64 size); 36 void Unmap(u64 size);
41 37
42 vk::Buffer GetBuffer() const { 38 vk::Buffer GetHandle() const {
43 return *buffer; 39 return *buffer;
44 } 40 }
45 41
46private: 42private:
43 struct Watch final {
44 VKFenceWatch fence;
45 u64 upper_bound{};
46 };
47
47 /// Creates Vulkan buffer handles committing the required the required memory. 48 /// Creates Vulkan buffer handles committing the required the required memory.
48 void CreateBuffers(VKMemoryManager& memory_manager, vk::BufferUsageFlags usage); 49 void CreateBuffers(vk::BufferUsageFlags usage);
49 50
50 /// Increases the amount of watches available. 51 /// Increases the amount of watches available.
51 void ReserveWatches(std::size_t grow_size); 52 void ReserveWatches(std::vector<Watch>& watches, std::size_t grow_size);
53
54 void WaitPendingOperations(u64 requested_upper_bound);
52 55
53 const VKDevice& device; ///< Vulkan device manager. 56 const VKDevice& device; ///< Vulkan device manager.
54 VKScheduler& scheduler; ///< Command scheduler. 57 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. 58 const vk::AccessFlags access; ///< Access usage of this stream buffer.
57 const vk::PipelineStageFlags pipeline_stage; ///< Pipeline usage of this stream buffer. 59 const vk::PipelineStageFlags pipeline_stage; ///< Pipeline usage of this stream buffer.
58 60
59 UniqueBuffer buffer; ///< Mapped buffer. 61 UniqueBuffer buffer; ///< Mapped buffer.
60 VKMemoryCommit commit; ///< Memory commit. 62 UniqueDeviceMemory memory; ///< Memory allocation.
61 u8* mapped_pointer{}; ///< Pointer to the host visible commit
62 63
63 u64 offset{}; ///< Buffer iterator. 64 u64 offset{}; ///< Buffer iterator.
64 u64 mapped_size{}; ///< Size reserved for the current copy. 65 u64 mapped_size{}; ///< Size reserved for the current copy.
65 66
66 std::vector<std::unique_ptr<VKFenceWatch>> watches; ///< Total watches 67 std::vector<Watch> current_watches; ///< Watches recorded in the current iteration.
67 std::size_t used_watches{}; ///< Count of watches, reset on invalidation. 68 std::size_t current_watch_cursor{}; ///< Count of watches, reset on invalidation.
68 std::optional<std::size_t> 69 std::optional<std::size_t> invalidation_mark; ///< Number of watches used in the previous cycle.
69 invalidation_mark{}; ///< Number of watches used in the current invalidation. 70
71 std::vector<Watch> previous_watches; ///< Watches used in the previous iteration.
72 std::size_t wait_cursor{}; ///< Last watch being waited for completion.
73 u64 wait_bound{}; ///< Highest offset being watched for completion.
70}; 74};
71 75
72} // namespace Vulkan 76} // namespace Vulkan