summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar GPUCode2023-04-08 21:53:13 +0300
committerGravatar GPUCode2023-05-01 23:13:24 +0300
commit50791cb974e462c97dc133a619ddc2066961b526 (patch)
treebf385acd61178b4f07dd220077c8a3ef528a9203 /src
parentrenderer_vulkan: Async presentation (diff)
downloadyuzu-50791cb974e462c97dc133a619ddc2066961b526.tar.gz
yuzu-50791cb974e462c97dc133a619ddc2066961b526.tar.xz
yuzu-50791cb974e462c97dc133a619ddc2066961b526.zip
renderer_vulkan: Fix crashing when updating descriptors
* During pipeline configure the function would acquire some payload space from the descriptor update queue, write the descriptor data on the GPU thread and give the scheduler a pointer to the beginning of said space to update it later. TickFrame resets the payload cursor, used to track acquires, back to the beginning of the buffer. This wasn't a problem before since WaitWorker was called at the end of the frame but now it is. If a frame writes to a cursor before the scheduler catches up, it will crash * To fix this the payload buffer has been increased to account for the in flight frames that are allowed to exist now. TickFrame will switch between the payload spaces instead of resetting
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.cpp11
-rw-r--r--src/video_core/renderer_vulkan/vk_update_descriptor.h10
2 files changed, 17 insertions, 4 deletions
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
index 009dab0b6..0630ebda5 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.cpp
@@ -14,13 +14,18 @@ namespace Vulkan {
14 14
15UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_) 15UpdateDescriptorQueue::UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_)
16 : device{device_}, scheduler{scheduler_} { 16 : device{device_}, scheduler{scheduler_} {
17 payload_start = payload.data();
17 payload_cursor = payload.data(); 18 payload_cursor = payload.data();
18} 19}
19 20
20UpdateDescriptorQueue::~UpdateDescriptorQueue() = default; 21UpdateDescriptorQueue::~UpdateDescriptorQueue() = default;
21 22
22void UpdateDescriptorQueue::TickFrame() { 23void UpdateDescriptorQueue::TickFrame() {
23 payload_cursor = payload.data(); 24 if (++frame_index >= FRAMES_IN_FLIGHT) {
25 frame_index = 0;
26 }
27 payload_start = payload.data() + frame_index * FRAME_PAYLOAD_SIZE;
28 payload_cursor = payload_start;
24} 29}
25 30
26void UpdateDescriptorQueue::Acquire() { 31void UpdateDescriptorQueue::Acquire() {
@@ -28,10 +33,10 @@ void UpdateDescriptorQueue::Acquire() {
28 // This is the maximum number of entries a single draw call might use. 33 // This is the maximum number of entries a single draw call might use.
29 static constexpr size_t MIN_ENTRIES = 0x400; 34 static constexpr size_t MIN_ENTRIES = 0x400;
30 35
31 if (std::distance(payload.data(), payload_cursor) + MIN_ENTRIES >= payload.max_size()) { 36 if (std::distance(payload_start, payload_cursor) + MIN_ENTRIES >= FRAME_PAYLOAD_SIZE) {
32 LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread"); 37 LOG_WARNING(Render_Vulkan, "Payload overflow, waiting for worker thread");
33 scheduler.WaitWorker(); 38 scheduler.WaitWorker();
34 payload_cursor = payload.data(); 39 payload_cursor = payload_start;
35 } 40 }
36 upload_start = payload_cursor; 41 upload_start = payload_cursor;
37} 42}
diff --git a/src/video_core/renderer_vulkan/vk_update_descriptor.h b/src/video_core/renderer_vulkan/vk_update_descriptor.h
index 625bcc809..1c1a7020b 100644
--- a/src/video_core/renderer_vulkan/vk_update_descriptor.h
+++ b/src/video_core/renderer_vulkan/vk_update_descriptor.h
@@ -29,6 +29,12 @@ struct DescriptorUpdateEntry {
29}; 29};
30 30
31class UpdateDescriptorQueue final { 31class UpdateDescriptorQueue final {
32 // This should be plenty for the vast majority of cases. Most desktop platforms only
33 // provide up to 3 swapchain images.
34 static constexpr size_t FRAMES_IN_FLIGHT = 5;
35 static constexpr size_t FRAME_PAYLOAD_SIZE = 0x10000;
36 static constexpr size_t PAYLOAD_SIZE = FRAME_PAYLOAD_SIZE * FRAMES_IN_FLIGHT;
37
32public: 38public:
33 explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_); 39 explicit UpdateDescriptorQueue(const Device& device_, Scheduler& scheduler_);
34 ~UpdateDescriptorQueue(); 40 ~UpdateDescriptorQueue();
@@ -73,9 +79,11 @@ private:
73 const Device& device; 79 const Device& device;
74 Scheduler& scheduler; 80 Scheduler& scheduler;
75 81
82 size_t frame_index{0};
76 DescriptorUpdateEntry* payload_cursor = nullptr; 83 DescriptorUpdateEntry* payload_cursor = nullptr;
84 DescriptorUpdateEntry* payload_start = nullptr;
77 const DescriptorUpdateEntry* upload_start = nullptr; 85 const DescriptorUpdateEntry* upload_start = nullptr;
78 std::array<DescriptorUpdateEntry, 0x10000> payload; 86 std::array<DescriptorUpdateEntry, PAYLOAD_SIZE> payload;
79}; 87};
80 88
81} // namespace Vulkan 89} // namespace Vulkan