summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2023-04-14 22:53:37 -0400
committerGravatar Liam2023-04-14 22:53:37 -0400
commite3fb9b5e0049b87a25c551219d4b009550af5f6d (patch)
tree3529e92f967aa5196e656020c300652f7fa59cc5 /src
parentMerge pull request #10030 from Wollnashorn/botw-amd-fix (diff)
downloadyuzu-e3fb9b5e0049b87a25c551219d4b009550af5f6d.tar.gz
yuzu-e3fb9b5e0049b87a25c551219d4b009550af5f6d.tar.xz
yuzu-e3fb9b5e0049b87a25c551219d4b009550af5f6d.zip
vulkan: use plain fences when timeline semaphores are not available
Diffstat (limited to 'src')
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.cpp139
-rw-r--r--src/video_core/renderer_vulkan/vk_master_semaphore.h48
-rw-r--r--src/video_core/renderer_vulkan/vk_scheduler.cpp36
-rw-r--r--src/video_core/vulkan_common/vulkan_device.h6
4 files changed, 161 insertions, 68 deletions
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
index 8aa07ef9d..47c74e4d8 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.cpp
@@ -10,7 +10,14 @@
10 10
11namespace Vulkan { 11namespace Vulkan {
12 12
13MasterSemaphore::MasterSemaphore(const Device& device) { 13MasterSemaphore::MasterSemaphore(const Device& device_) : device(device_) {
14 if (!device.HasTimelineSemaphore()) {
15 static constexpr VkFenceCreateInfo fence_ci{
16 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, .pNext = nullptr, .flags = 0};
17 fence = device.GetLogical().CreateFence(fence_ci);
18 return;
19 }
20
14 static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{ 21 static constexpr VkSemaphoreTypeCreateInfo semaphore_type_ci{
15 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, 22 .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
16 .pNext = nullptr, 23 .pNext = nullptr,
@@ -42,4 +49,134 @@ MasterSemaphore::MasterSemaphore(const Device& device) {
42 49
43MasterSemaphore::~MasterSemaphore() = default; 50MasterSemaphore::~MasterSemaphore() = default;
44 51
52void MasterSemaphore::Refresh() {
53 if (!semaphore) {
54 // If we don't support timeline semaphores, there's nothing to refresh
55 return;
56 }
57
58 u64 this_tick{};
59 u64 counter{};
60 do {
61 this_tick = gpu_tick.load(std::memory_order_acquire);
62 counter = semaphore.GetCounter();
63 if (counter < this_tick) {
64 return;
65 }
66 } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release,
67 std::memory_order_relaxed));
68}
69
70void MasterSemaphore::Wait(u64 tick) {
71 if (!semaphore) {
72 // If we don't support timeline semaphores, use an atomic wait
73 while (true) {
74 u64 current_value = gpu_tick.load(std::memory_order_relaxed);
75 if (current_value >= tick) {
76 return;
77 }
78 gpu_tick.wait(current_value);
79 }
80
81 return;
82 }
83
84 // No need to wait if the GPU is ahead of the tick
85 if (IsFree(tick)) {
86 return;
87 }
88
89 // Update the GPU tick and try again
90 Refresh();
91
92 if (IsFree(tick)) {
93 return;
94 }
95
96 // If none of the above is hit, fallback to a regular wait
97 while (!semaphore.Wait(tick)) {
98 }
99
100 Refresh();
101}
102
103VkResult MasterSemaphore::SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
104 VkSemaphore wait_semaphore, u64 host_tick) {
105 if (semaphore) {
106 return SubmitQueueTimeline(cmdbuf, signal_semaphore, wait_semaphore, host_tick);
107 } else {
108 return SubmitQueueFence(cmdbuf, signal_semaphore, wait_semaphore, host_tick);
109 }
110}
111
112static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
113 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
114 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
115};
116
117VkResult MasterSemaphore::SubmitQueueTimeline(vk::CommandBuffer& cmdbuf,
118 VkSemaphore signal_semaphore,
119 VkSemaphore wait_semaphore, u64 host_tick) {
120 const VkSemaphore timeline_semaphore = *semaphore;
121
122 const u32 num_signal_semaphores = signal_semaphore ? 2 : 1;
123 const std::array signal_values{host_tick, u64(0)};
124 const std::array signal_semaphores{timeline_semaphore, signal_semaphore};
125
126 const u32 num_wait_semaphores = wait_semaphore ? 2 : 1;
127 const std::array wait_values{host_tick - 1, u64(1)};
128 const std::array wait_semaphores{timeline_semaphore, wait_semaphore};
129
130 const VkTimelineSemaphoreSubmitInfo timeline_si{
131 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
132 .pNext = nullptr,
133 .waitSemaphoreValueCount = num_wait_semaphores,
134 .pWaitSemaphoreValues = wait_values.data(),
135 .signalSemaphoreValueCount = num_signal_semaphores,
136 .pSignalSemaphoreValues = signal_values.data(),
137 };
138 const VkSubmitInfo submit_info{
139 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
140 .pNext = &timeline_si,
141 .waitSemaphoreCount = num_wait_semaphores,
142 .pWaitSemaphores = wait_semaphores.data(),
143 .pWaitDstStageMask = wait_stage_masks.data(),
144 .commandBufferCount = 1,
145 .pCommandBuffers = cmdbuf.address(),
146 .signalSemaphoreCount = num_signal_semaphores,
147 .pSignalSemaphores = signal_semaphores.data(),
148 };
149
150 return device.GetGraphicsQueue().Submit(submit_info);
151}
152
153VkResult MasterSemaphore::SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
154 VkSemaphore wait_semaphore, u64 host_tick) {
155 const u32 num_signal_semaphores = signal_semaphore ? 1 : 0;
156 const u32 num_wait_semaphores = wait_semaphore ? 1 : 0;
157
158 const VkSubmitInfo submit_info{
159 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
160 .pNext = nullptr,
161 .waitSemaphoreCount = num_wait_semaphores,
162 .pWaitSemaphores = &wait_semaphore,
163 .pWaitDstStageMask = wait_stage_masks.data(),
164 .commandBufferCount = 1,
165 .pCommandBuffers = cmdbuf.address(),
166 .signalSemaphoreCount = num_signal_semaphores,
167 .pSignalSemaphores = &signal_semaphore,
168 };
169
170 auto result = device.GetGraphicsQueue().Submit(submit_info, *fence);
171
172 if (result == VK_SUCCESS) {
173 fence.Wait();
174 fence.Reset();
175 gpu_tick.store(host_tick);
176 gpu_tick.notify_all();
177 }
178
179 return result;
180}
181
45} // namespace Vulkan 182} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_master_semaphore.h b/src/video_core/renderer_vulkan/vk_master_semaphore.h
index 689f02ea5..f2f61f781 100644
--- a/src/video_core/renderer_vulkan/vk_master_semaphore.h
+++ b/src/video_core/renderer_vulkan/vk_master_semaphore.h
@@ -4,6 +4,8 @@
4#pragma once 4#pragma once
5 5
6#include <atomic> 6#include <atomic>
7#include <condition_variable>
8#include <mutex>
7#include <thread> 9#include <thread>
8 10
9#include "common/common_types.h" 11#include "common/common_types.h"
@@ -29,11 +31,6 @@ public:
29 return gpu_tick.load(std::memory_order_acquire); 31 return gpu_tick.load(std::memory_order_acquire);
30 } 32 }
31 33
32 /// Returns the timeline semaphore handle.
33 [[nodiscard]] VkSemaphore Handle() const noexcept {
34 return *semaphore;
35 }
36
37 /// Returns true when a tick has been hit by the GPU. 34 /// Returns true when a tick has been hit by the GPU.
38 [[nodiscard]] bool IsFree(u64 tick) const noexcept { 35 [[nodiscard]] bool IsFree(u64 tick) const noexcept {
39 return KnownGpuTick() >= tick; 36 return KnownGpuTick() >= tick;
@@ -45,37 +42,24 @@ public:
45 } 42 }
46 43
47 /// Refresh the known GPU tick 44 /// Refresh the known GPU tick
48 void Refresh() { 45 void Refresh();
49 u64 this_tick{};
50 u64 counter{};
51 do {
52 this_tick = gpu_tick.load(std::memory_order_acquire);
53 counter = semaphore.GetCounter();
54 if (counter < this_tick) {
55 return;
56 }
57 } while (!gpu_tick.compare_exchange_weak(this_tick, counter, std::memory_order_release,
58 std::memory_order_relaxed));
59 }
60 46
61 /// Waits for a tick to be hit on the GPU 47 /// Waits for a tick to be hit on the GPU
62 void Wait(u64 tick) { 48 void Wait(u64 tick);
63 // No need to wait if the GPU is ahead of the tick 49
64 if (IsFree(tick)) { 50 /// Submits the device graphics queue, updating the tick as necessary
65 return; 51 VkResult SubmitQueue(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
66 } 52 VkSemaphore wait_semaphore, u64 host_tick);
67 // Update the GPU tick and try again 53
68 Refresh(); 54private:
69 if (IsFree(tick)) { 55 VkResult SubmitQueueTimeline(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
70 return; 56 VkSemaphore wait_semaphore, u64 host_tick);
71 } 57 VkResult SubmitQueueFence(vk::CommandBuffer& cmdbuf, VkSemaphore signal_semaphore,
72 // If none of the above is hit, fallback to a regular wait 58 VkSemaphore wait_semaphore, u64 host_tick);
73 while (!semaphore.Wait(tick)) {
74 }
75 Refresh();
76 }
77 59
78private: 60private:
61 const Device& device; ///< Device.
62 vk::Fence fence; ///< Fence.
79 vk::Semaphore semaphore; ///< Timeline semaphore. 63 vk::Semaphore semaphore; ///< Timeline semaphore.
80 std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick. 64 std::atomic<u64> gpu_tick{0}; ///< Current known GPU tick.
81 std::atomic<u64> current_tick{1}; ///< Current logical tick. 65 std::atomic<u64> current_tick{1}; ///< Current logical tick.
diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp
index b264e6ada..057e16967 100644
--- a/src/video_core/renderer_vulkan/vk_scheduler.cpp
+++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp
@@ -212,45 +212,13 @@ void Scheduler::SubmitExecution(VkSemaphore signal_semaphore, VkSemaphore wait_s
212 const u64 signal_value = master_semaphore->NextTick(); 212 const u64 signal_value = master_semaphore->NextTick();
213 Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) { 213 Record([signal_semaphore, wait_semaphore, signal_value, this](vk::CommandBuffer cmdbuf) {
214 cmdbuf.End(); 214 cmdbuf.End();
215 const VkSemaphore timeline_semaphore = master_semaphore->Handle();
216
217 const u32 num_signal_semaphores = signal_semaphore ? 2U : 1U;
218 const std::array signal_values{signal_value, u64(0)};
219 const std::array signal_semaphores{timeline_semaphore, signal_semaphore};
220
221 const u32 num_wait_semaphores = wait_semaphore ? 2U : 1U;
222 const std::array wait_values{signal_value - 1, u64(1)};
223 const std::array wait_semaphores{timeline_semaphore, wait_semaphore};
224 static constexpr std::array<VkPipelineStageFlags, 2> wait_stage_masks{
225 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
226 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
227 };
228
229 const VkTimelineSemaphoreSubmitInfo timeline_si{
230 .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO,
231 .pNext = nullptr,
232 .waitSemaphoreValueCount = num_wait_semaphores,
233 .pWaitSemaphoreValues = wait_values.data(),
234 .signalSemaphoreValueCount = num_signal_semaphores,
235 .pSignalSemaphoreValues = signal_values.data(),
236 };
237 const VkSubmitInfo submit_info{
238 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
239 .pNext = &timeline_si,
240 .waitSemaphoreCount = num_wait_semaphores,
241 .pWaitSemaphores = wait_semaphores.data(),
242 .pWaitDstStageMask = wait_stage_masks.data(),
243 .commandBufferCount = 1,
244 .pCommandBuffers = cmdbuf.address(),
245 .signalSemaphoreCount = num_signal_semaphores,
246 .pSignalSemaphores = signal_semaphores.data(),
247 };
248 215
249 if (on_submit) { 216 if (on_submit) {
250 on_submit(); 217 on_submit();
251 } 218 }
252 219
253 switch (const VkResult result = device.GetGraphicsQueue().Submit(submit_info)) { 220 switch (const VkResult result = master_semaphore->SubmitQueue(
221 cmdbuf, signal_semaphore, wait_semaphore, signal_value)) {
254 case VK_SUCCESS: 222 case VK_SUCCESS:
255 break; 223 break;
256 case VK_ERROR_DEVICE_LOST: 224 case VK_ERROR_DEVICE_LOST:
diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h
index 41b5da18a..7d5018151 100644
--- a/src/video_core/vulkan_common/vulkan_device.h
+++ b/src/video_core/vulkan_common/vulkan_device.h
@@ -145,7 +145,6 @@
145 FEATURE_NAME(robustness2, robustImageAccess2) \ 145 FEATURE_NAME(robustness2, robustImageAccess2) \
146 FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \ 146 FEATURE_NAME(shader_demote_to_helper_invocation, shaderDemoteToHelperInvocation) \
147 FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \ 147 FEATURE_NAME(shader_draw_parameters, shaderDrawParameters) \
148 FEATURE_NAME(timeline_semaphore, timelineSemaphore) \
149 FEATURE_NAME(variable_pointer, variablePointers) \ 148 FEATURE_NAME(variable_pointer, variablePointers) \
150 FEATURE_NAME(variable_pointer, variablePointersStorageBuffer) 149 FEATURE_NAME(variable_pointer, variablePointersStorageBuffer)
151 150
@@ -158,6 +157,7 @@
158 FEATURE_NAME(provoking_vertex, provokingVertexLast) \ 157 FEATURE_NAME(provoking_vertex, provokingVertexLast) \
159 FEATURE_NAME(shader_float16_int8, shaderFloat16) \ 158 FEATURE_NAME(shader_float16_int8, shaderFloat16) \
160 FEATURE_NAME(shader_float16_int8, shaderInt8) \ 159 FEATURE_NAME(shader_float16_int8, shaderInt8) \
160 FEATURE_NAME(timeline_semaphore, timelineSemaphore) \
161 FEATURE_NAME(transform_feedback, transformFeedback) \ 161 FEATURE_NAME(transform_feedback, transformFeedback) \
162 FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \ 162 FEATURE_NAME(uniform_buffer_standard_layout, uniformBufferStandardLayout) \
163 FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState) 163 FEATURE_NAME(vertex_input_dynamic_state, vertexInputDynamicState)
@@ -493,6 +493,10 @@ public:
493 return extensions.shader_atomic_int64; 493 return extensions.shader_atomic_int64;
494 } 494 }
495 495
496 bool HasTimelineSemaphore() const {
497 return features.timeline_semaphore.timelineSemaphore;
498 }
499
496 /// Returns the minimum supported version of SPIR-V. 500 /// Returns the minimum supported version of SPIR-V.
497 u32 SupportedSpirvVersion() const { 501 u32 SupportedSpirvVersion() const {
498 if (instance_version >= VK_API_VERSION_1_3) { 502 if (instance_version >= VK_API_VERSION_1_3) {