summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam2022-12-19 19:29:58 -0500
committerGravatar Liam2023-01-04 22:22:01 -0500
commit301e9bbc03821ef7943d84b24b32c8b732a39f6a (patch)
tree3afaf56153ba07f4a8ec083bac4b59d119ed2723 /src
parentMerge pull request #9501 from FernandoS27/yfc-rel-2 (diff)
downloadyuzu-301e9bbc03821ef7943d84b24b32c8b732a39f6a.tar.gz
yuzu-301e9bbc03821ef7943d84b24b32c8b732a39f6a.tar.xz
yuzu-301e9bbc03821ef7943d84b24b32c8b732a39f6a.zip
vulkan: implement 'turbo mode' clock booster
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/host_shaders/CMakeLists.txt1
-rw-r--r--src/video_core/host_shaders/vulkan_turbo_mode.comp29
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.cpp4
-rw-r--r--src/video_core/renderer_vulkan/renderer_vulkan.h5
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.cpp205
-rw-r--r--src/video_core/renderer_vulkan/vk_turbo_mode.h26
-rw-r--r--src/video_core/vulkan_common/vulkan_device.cpp2
8 files changed, 272 insertions, 2 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index aa271a377..537451b02 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -190,6 +190,8 @@ add_library(video_core STATIC
190 renderer_vulkan/vk_texture_cache.cpp 190 renderer_vulkan/vk_texture_cache.cpp
191 renderer_vulkan/vk_texture_cache.h 191 renderer_vulkan/vk_texture_cache.h
192 renderer_vulkan/vk_texture_cache_base.cpp 192 renderer_vulkan/vk_texture_cache_base.cpp
193 renderer_vulkan/vk_turbo_mode.cpp
194 renderer_vulkan/vk_turbo_mode.h
193 renderer_vulkan/vk_update_descriptor.cpp 195 renderer_vulkan/vk_update_descriptor.cpp
194 renderer_vulkan/vk_update_descriptor.h 196 renderer_vulkan/vk_update_descriptor.h
195 shader_cache.cpp 197 shader_cache.cpp
diff --git a/src/video_core/host_shaders/CMakeLists.txt b/src/video_core/host_shaders/CMakeLists.txt
index e6dc24f22..f275b2aa9 100644
--- a/src/video_core/host_shaders/CMakeLists.txt
+++ b/src/video_core/host_shaders/CMakeLists.txt
@@ -47,6 +47,7 @@ set(SHADER_FILES
47 vulkan_present_scaleforce_fp16.frag 47 vulkan_present_scaleforce_fp16.frag
48 vulkan_present_scaleforce_fp32.frag 48 vulkan_present_scaleforce_fp32.frag
49 vulkan_quad_indexed.comp 49 vulkan_quad_indexed.comp
50 vulkan_turbo_mode.comp
50 vulkan_uint8.comp 51 vulkan_uint8.comp
51) 52)
52 53
diff --git a/src/video_core/host_shaders/vulkan_turbo_mode.comp b/src/video_core/host_shaders/vulkan_turbo_mode.comp
new file mode 100644
index 000000000..d651001d9
--- /dev/null
+++ b/src/video_core/host_shaders/vulkan_turbo_mode.comp
@@ -0,0 +1,29 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#version 460 core
5
6layout (local_size_x = 16, local_size_y = 8, local_size_z = 1) in;
7
8layout (binding = 0) buffer ThreadData {
9 uint data[];
10};
11
12uint xorshift32(uint x) {
13 x ^= x << 13;
14 x ^= x >> 17;
15 x ^= x << 5;
16 return x;
17}
18
19uint getGlobalIndex() {
20 return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * gl_WorkGroupSize.y * gl_NumWorkGroups.y;
21}
22
23void main() {
24 uint myIndex = xorshift32(getGlobalIndex());
25 uint otherIndex = xorshift32(myIndex);
26
27 uint otherValue = atomicAdd(data[otherIndex % data.length()], 0) + 1;
28 atomicAdd(data[myIndex % data.length()], otherValue);
29}
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
index f502a7d09..e5802b40c 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp
@@ -78,6 +78,8 @@ std::string BuildCommaSeparatedExtensions(std::vector<std::string> available_ext
78 return separated_extensions; 78 return separated_extensions;
79} 79}
80 80
81} // Anonymous namespace
82
81Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld, 83Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
82 VkSurfaceKHR surface) { 84 VkSurfaceKHR surface) {
83 const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices(); 85 const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
@@ -89,7 +91,6 @@ Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dl
89 const vk::PhysicalDevice physical_device(devices[device_index], dld); 91 const vk::PhysicalDevice physical_device(devices[device_index], dld);
90 return Device(*instance, physical_device, surface, dld); 92 return Device(*instance, physical_device, surface, dld);
91} 93}
92} // Anonymous namespace
93 94
94RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_, 95RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
95 Core::Frontend::EmuWindow& emu_window, 96 Core::Frontend::EmuWindow& emu_window,
@@ -109,6 +110,7 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
109 screen_info), 110 screen_info),
110 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator, 111 rasterizer(render_window, gpu, cpu_memory, screen_info, device, memory_allocator,
111 state_tracker, scheduler) { 112 state_tracker, scheduler) {
113 turbo_mode.emplace(instance, dld);
112 Report(); 114 Report();
113} catch (const vk::Exception& exception) { 115} catch (const vk::Exception& exception) {
114 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what()); 116 LOG_ERROR(Render_Vulkan, "Vulkan initialization failed with error: {}", exception.what());
diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h
index e7bfecb20..009e75e0d 100644
--- a/src/video_core/renderer_vulkan/renderer_vulkan.h
+++ b/src/video_core/renderer_vulkan/renderer_vulkan.h
@@ -13,6 +13,7 @@
13#include "video_core/renderer_vulkan/vk_scheduler.h" 13#include "video_core/renderer_vulkan/vk_scheduler.h"
14#include "video_core/renderer_vulkan/vk_state_tracker.h" 14#include "video_core/renderer_vulkan/vk_state_tracker.h"
15#include "video_core/renderer_vulkan/vk_swapchain.h" 15#include "video_core/renderer_vulkan/vk_swapchain.h"
16#include "video_core/renderer_vulkan/vk_turbo_mode.h"
16#include "video_core/vulkan_common/vulkan_device.h" 17#include "video_core/vulkan_common/vulkan_device.h"
17#include "video_core/vulkan_common/vulkan_memory_allocator.h" 18#include "video_core/vulkan_common/vulkan_memory_allocator.h"
18#include "video_core/vulkan_common/vulkan_wrapper.h" 19#include "video_core/vulkan_common/vulkan_wrapper.h"
@@ -31,6 +32,9 @@ class GPU;
31 32
32namespace Vulkan { 33namespace Vulkan {
33 34
35Device CreateDevice(const vk::Instance& instance, const vk::InstanceDispatch& dld,
36 VkSurfaceKHR surface);
37
34class RendererVulkan final : public VideoCore::RendererBase { 38class RendererVulkan final : public VideoCore::RendererBase {
35public: 39public:
36 explicit RendererVulkan(Core::TelemetrySession& telemtry_session, 40 explicit RendererVulkan(Core::TelemetrySession& telemtry_session,
@@ -74,6 +78,7 @@ private:
74 Swapchain swapchain; 78 Swapchain swapchain;
75 BlitScreen blit_screen; 79 BlitScreen blit_screen;
76 RasterizerVulkan rasterizer; 80 RasterizerVulkan rasterizer;
81 std::optional<TurboMode> turbo_mode;
77}; 82};
78 83
79} // namespace Vulkan 84} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.cpp b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
new file mode 100644
index 000000000..852b86f84
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.cpp
@@ -0,0 +1,205 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "common/literals.h"
5#include "video_core/host_shaders/vulkan_turbo_mode_comp_spv.h"
6#include "video_core/renderer_vulkan/renderer_vulkan.h"
7#include "video_core/renderer_vulkan/vk_shader_util.h"
8#include "video_core/renderer_vulkan/vk_turbo_mode.h"
9#include "video_core/vulkan_common/vulkan_device.h"
10
11namespace Vulkan {
12
13using namespace Common::Literals;
14
15TurboMode::TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld)
16 : m_device{CreateDevice(instance, dld, VK_NULL_HANDLE)}, m_allocator{m_device, false} {
17 m_thread = std::jthread([&](auto stop_token) { Run(stop_token); });
18}
19
20TurboMode::~TurboMode() = default;
21
22void TurboMode::Run(std::stop_token stop_token) {
23 auto& dld = m_device.GetLogical();
24
25 // Allocate buffer. 2MiB should be sufficient.
26 auto buffer = dld.CreateBuffer(VkBufferCreateInfo{
27 .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
28 .pNext = nullptr,
29 .flags = 0,
30 .size = 2_MiB,
31 .usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
32 .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
33 .queueFamilyIndexCount = 0,
34 .pQueueFamilyIndices = nullptr,
35 });
36
37 // Commit some device local memory for the buffer.
38 auto commit = m_allocator.Commit(buffer, MemoryUsage::DeviceLocal);
39
40 // Create the descriptor pool to contain our descriptor.
41 constexpr VkDescriptorPoolSize pool_size{
42 .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
43 .descriptorCount = 1,
44 };
45
46 auto descriptor_pool = dld.CreateDescriptorPool(VkDescriptorPoolCreateInfo{
47 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
48 .pNext = nullptr,
49 .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT,
50 .maxSets = 1,
51 .poolSizeCount = 1,
52 .pPoolSizes = &pool_size,
53 });
54
55 // Create the descriptor set layout from the pool.
56 constexpr VkDescriptorSetLayoutBinding layout_binding{
57 .binding = 0,
58 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
59 .descriptorCount = 1,
60 .stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
61 .pImmutableSamplers = nullptr,
62 };
63
64 auto descriptor_set_layout = dld.CreateDescriptorSetLayout(VkDescriptorSetLayoutCreateInfo{
65 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
66 .pNext = nullptr,
67 .flags = 0,
68 .bindingCount = 1,
69 .pBindings = &layout_binding,
70 });
71
72 // Actually create the descriptor set.
73 auto descriptor_set = descriptor_pool.Allocate(VkDescriptorSetAllocateInfo{
74 .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
75 .pNext = nullptr,
76 .descriptorPool = *descriptor_pool,
77 .descriptorSetCount = 1,
78 .pSetLayouts = descriptor_set_layout.address(),
79 });
80
81 // Create the shader.
82 auto shader = BuildShader(m_device, VULKAN_TURBO_MODE_COMP_SPV);
83
84 // Create the pipeline layout.
85 auto pipeline_layout = dld.CreatePipelineLayout(VkPipelineLayoutCreateInfo{
86 .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
87 .pNext = nullptr,
88 .flags = 0,
89 .setLayoutCount = 1,
90 .pSetLayouts = descriptor_set_layout.address(),
91 .pushConstantRangeCount = 0,
92 .pPushConstantRanges = nullptr,
93 });
94
95 // Actually create the pipeline.
96 const VkPipelineShaderStageCreateInfo shader_stage{
97 .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
98 .pNext = nullptr,
99 .flags = 0,
100 .stage = VK_SHADER_STAGE_COMPUTE_BIT,
101 .module = *shader,
102 .pName = "main",
103 .pSpecializationInfo = nullptr,
104 };
105
106 auto pipeline = dld.CreateComputePipeline(VkComputePipelineCreateInfo{
107 .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
108 .pNext = nullptr,
109 .flags = 0,
110 .stage = shader_stage,
111 .layout = *pipeline_layout,
112 .basePipelineHandle = VK_NULL_HANDLE,
113 .basePipelineIndex = 0,
114 });
115
116 // Create a fence to wait on.
117 auto fence = dld.CreateFence(VkFenceCreateInfo{
118 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
119 .pNext = nullptr,
120 .flags = 0,
121 });
122
123 // Create a command pool to allocate a command buffer from.
124 auto command_pool = dld.CreateCommandPool(VkCommandPoolCreateInfo{
125 .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
126 .pNext = nullptr,
127 .flags =
128 VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
129 .queueFamilyIndex = m_device.GetGraphicsFamily(),
130 });
131
132 // Create a single command buffer.
133 auto cmdbufs = command_pool.Allocate(1, VK_COMMAND_BUFFER_LEVEL_PRIMARY);
134 auto cmdbuf = vk::CommandBuffer{cmdbufs[0], m_device.GetDispatchLoader()};
135
136 while (!stop_token.stop_requested()) {
137 // Reset the fence.
138 fence.Reset();
139
140 // Update descriptor set.
141 const VkDescriptorBufferInfo buffer_info{
142 .buffer = *buffer,
143 .offset = 0,
144 .range = VK_WHOLE_SIZE,
145 };
146
147 const VkWriteDescriptorSet buffer_write{
148 .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
149 .pNext = nullptr,
150 .dstSet = descriptor_set[0],
151 .dstBinding = 0,
152 .dstArrayElement = 0,
153 .descriptorCount = 1,
154 .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
155 .pImageInfo = nullptr,
156 .pBufferInfo = &buffer_info,
157 .pTexelBufferView = nullptr,
158 };
159
160 dld.UpdateDescriptorSets(std::array{buffer_write}, {});
161
162 // Set up the command buffer.
163 cmdbuf.Begin(VkCommandBufferBeginInfo{
164 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
165 .pNext = nullptr,
166 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
167 .pInheritanceInfo = nullptr,
168 });
169
170 // Clear the buffer.
171 cmdbuf.FillBuffer(*buffer, 0, VK_WHOLE_SIZE, 0);
172
173 // Bind descriptor set.
174 cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0,
175 descriptor_set, {});
176
177 // Bind the pipeline.
178 cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
179
180 // Dispatch.
181 cmdbuf.Dispatch(64, 64, 1);
182
183 // Finish.
184 cmdbuf.End();
185
186 const VkSubmitInfo submit_info{
187 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
188 .pNext = nullptr,
189 .waitSemaphoreCount = 0,
190 .pWaitSemaphores = nullptr,
191 .pWaitDstStageMask = nullptr,
192 .commandBufferCount = 1,
193 .pCommandBuffers = cmdbuf.address(),
194 .signalSemaphoreCount = 0,
195 .pSignalSemaphores = nullptr,
196 };
197
198 m_device.GetGraphicsQueue().Submit(std::array{submit_info}, *fence);
199
200 // Wait for completion.
201 fence.Wait();
202 }
203}
204
205} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_turbo_mode.h b/src/video_core/renderer_vulkan/vk_turbo_mode.h
new file mode 100644
index 000000000..2060e2395
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_turbo_mode.h
@@ -0,0 +1,26 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "common/polyfill_thread.h"
7#include "video_core/vulkan_common/vulkan_device.h"
8#include "video_core/vulkan_common/vulkan_memory_allocator.h"
9#include "video_core/vulkan_common/vulkan_wrapper.h"
10
11namespace Vulkan {
12
13class TurboMode {
14public:
15 explicit TurboMode(const vk::Instance& instance, const vk::InstanceDispatch& dld);
16 ~TurboMode();
17
18private:
19 void Run(std::stop_token stop_token);
20
21 Device m_device;
22 MemoryAllocator m_allocator;
23 std::jthread m_thread;
24};
25
26} // namespace Vulkan
diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp
index 5c5bfa18d..3d1109b30 100644
--- a/src/video_core/vulkan_common/vulkan_device.cpp
+++ b/src/video_core/vulkan_common/vulkan_device.cpp
@@ -1472,7 +1472,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
1472 is_patch_list_restart_supported = 1472 is_patch_list_restart_supported =
1473 primitive_topology_list_restart.primitiveTopologyPatchListRestart; 1473 primitive_topology_list_restart.primitiveTopologyPatchListRestart;
1474 } 1474 }
1475 if (has_khr_image_format_list && has_khr_swapchain_mutable_format) { 1475 if (requires_surface && has_khr_image_format_list && has_khr_swapchain_mutable_format) {
1476 extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); 1476 extensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME);
1477 extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME); 1477 extensions.push_back(VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME);
1478 khr_swapchain_mutable_format = true; 1478 khr_swapchain_mutable_format = true;