summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--src/common/logging/backend.cpp50
-rw-r--r--src/common/logging/backend.h4
-rw-r--r--src/core/hle/service/audio/audren_u.cpp37
-rw-r--r--src/core/hle/service/audio/audren_u.h3
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.cpp116
-rw-r--r--src/video_core/renderer_vulkan/vk_buffer_cache.h87
-rw-r--r--src/web_service/verify_login.h2
-rw-r--r--src/web_service/web_backend.cpp1
-rw-r--r--src/yuzu/compatdb.cpp2
-rw-r--r--src/yuzu/main.cpp5
13 files changed, 269 insertions, 44 deletions
diff --git a/README.md b/README.md
index 1d5ee58cc..fa4233b2a 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ yuzu is an experimental open-source emulator for the Nintendo Switch from the cr
7 7
8It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes. 8It is written in C++ with portability in mind, with builds actively maintained for Windows, Linux and macOS. The emulator is currently only useful for homebrew development and research purposes.
9 9
10yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success, but does not implement any of the necessary GPU features to render 3D graphics. 10yuzu only emulates a subset of Switch hardware and therefore is generally only useful for running/debugging homebrew applications. At this time, yuzu cannot play any commercial games without major problems. yuzu can boot some games, to varying degrees of success.
11 11
12yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. 12yuzu is licensed under the GPLv2 (or any later version). Refer to the license.txt file included.
13 13
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index b369f199f..4462ff3fb 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -39,8 +39,10 @@ public:
39 Impl(Impl const&) = delete; 39 Impl(Impl const&) = delete;
40 const Impl& operator=(Impl const&) = delete; 40 const Impl& operator=(Impl const&) = delete;
41 41
42 void PushEntry(Entry e) { 42 void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
43 message_queue.Push(std::move(e)); 43 const char* function, std::string message) {
44 message_queue.Push(
45 CreateEntry(log_class, log_level, filename, line_num, function, std::move(message)));
44 } 46 }
45 47
46 void AddBackend(std::unique_ptr<Backend> backend) { 48 void AddBackend(std::unique_ptr<Backend> backend) {
@@ -108,11 +110,30 @@ private:
108 backend_thread.join(); 110 backend_thread.join();
109 } 111 }
110 112
113 Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
114 const char* function, std::string message) const {
115 using std::chrono::duration_cast;
116 using std::chrono::steady_clock;
117
118 Entry entry;
119 entry.timestamp =
120 duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
121 entry.log_class = log_class;
122 entry.log_level = log_level;
123 entry.filename = Common::TrimSourcePath(filename);
124 entry.line_num = line_nr;
125 entry.function = function;
126 entry.message = std::move(message);
127
128 return entry;
129 }
130
111 std::mutex writing_mutex; 131 std::mutex writing_mutex;
112 std::thread backend_thread; 132 std::thread backend_thread;
113 std::vector<std::unique_ptr<Backend>> backends; 133 std::vector<std::unique_ptr<Backend>> backends;
114 Common::MPSCQueue<Log::Entry> message_queue; 134 Common::MPSCQueue<Log::Entry> message_queue;
115 Filter filter; 135 Filter filter;
136 std::chrono::steady_clock::time_point time_origin{std::chrono::steady_clock::now()};
116}; 137};
117 138
118void ConsoleBackend::Write(const Entry& entry) { 139void ConsoleBackend::Write(const Entry& entry) {
@@ -271,25 +292,6 @@ const char* GetLevelName(Level log_level) {
271#undef LVL 292#undef LVL
272} 293}
273 294
274Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
275 const char* function, std::string message) {
276 using std::chrono::duration_cast;
277 using std::chrono::steady_clock;
278
279 static steady_clock::time_point time_origin = steady_clock::now();
280
281 Entry entry;
282 entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
283 entry.log_class = log_class;
284 entry.log_level = log_level;
285 entry.filename = Common::TrimSourcePath(filename);
286 entry.line_num = line_nr;
287 entry.function = function;
288 entry.message = std::move(message);
289
290 return entry;
291}
292
293void SetGlobalFilter(const Filter& filter) { 295void SetGlobalFilter(const Filter& filter) {
294 Impl::Instance().SetGlobalFilter(filter); 296 Impl::Instance().SetGlobalFilter(filter);
295} 297}
@@ -314,9 +316,7 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
314 if (!filter.CheckMessage(log_class, log_level)) 316 if (!filter.CheckMessage(log_class, log_level))
315 return; 317 return;
316 318
317 Entry entry = 319 instance.PushEntry(log_class, log_level, filename, line_num, function,
318 CreateEntry(log_class, log_level, filename, line_num, function, fmt::vformat(format, args)); 320 fmt::vformat(format, args));
319
320 instance.PushEntry(std::move(entry));
321} 321}
322} // namespace Log 322} // namespace Log
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index a31ee6968..fca0267a1 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -135,10 +135,6 @@ const char* GetLogClassName(Class log_class);
135 */ 135 */
136const char* GetLevelName(Level log_level); 136const char* GetLevelName(Level log_level);
137 137
138/// Creates a log entry by formatting the given source location, and message.
139Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
140 const char* function, std::string message);
141
142/** 138/**
143 * The global filter will prevent any messages from even being processed if they are filtered. Each 139 * The global filter will prevent any messages from even being processed if they are filtered. Each
144 * backend can have a filter, but if the level is lower than the global filter, the backend will 140 * backend can have a filter, but if the level is lower than the global filter, the backend will
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 49648394c..ea8f9d0bb 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -37,7 +37,7 @@ public:
37 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, 37 {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
38 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, 38 {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
39 {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"}, 39 {10, &IAudioRenderer::RequestUpdateImpl, "RequestUpdateAuto"},
40 {11, nullptr, "ExecuteAudioRendererRendering"}, 40 {11, &IAudioRenderer::ExecuteAudioRendererRendering, "ExecuteAudioRendererRendering"},
41 }; 41 };
42 // clang-format on 42 // clang-format on
43 RegisterHandlers(functions); 43 RegisterHandlers(functions);
@@ -138,6 +138,17 @@ private:
138 rb.Push(rendering_time_limit_percent); 138 rb.Push(rendering_time_limit_percent);
139 } 139 }
140 140
141 void ExecuteAudioRendererRendering(Kernel::HLERequestContext& ctx) {
142 LOG_DEBUG(Service_Audio, "called");
143
144 // This service command currently only reports an unsupported operation
145 // error code, or aborts. Given that, we just always return an error
146 // code in this case.
147
148 IPC::ResponseBuilder rb{ctx, 2};
149 rb.Push(ResultCode{ErrorModule::Audio, 201});
150 }
151
141 Kernel::EventPair system_event; 152 Kernel::EventPair system_event;
142 std::unique_ptr<AudioCore::AudioRenderer> renderer; 153 std::unique_ptr<AudioCore::AudioRenderer> renderer;
143 u32 rendering_time_limit_percent = 100; 154 u32 rendering_time_limit_percent = 100;
@@ -235,7 +246,7 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
235 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"}, 246 {0, &AudRenU::OpenAudioRenderer, "OpenAudioRenderer"},
236 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"}, 247 {1, &AudRenU::GetAudioRendererWorkBufferSize, "GetAudioRendererWorkBufferSize"},
237 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"}, 248 {2, &AudRenU::GetAudioDeviceService, "GetAudioDeviceService"},
238 {3, nullptr, "OpenAudioRendererAuto"}, 249 {3, &AudRenU::OpenAudioRendererAuto, "OpenAudioRendererAuto"},
239 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"}, 250 {4, &AudRenU::GetAudioDeviceServiceWithRevisionInfo, "GetAudioDeviceServiceWithRevisionInfo"},
240 }; 251 };
241 // clang-format on 252 // clang-format on
@@ -248,12 +259,7 @@ AudRenU::~AudRenU() = default;
248void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 259void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
249 LOG_DEBUG(Service_Audio, "called"); 260 LOG_DEBUG(Service_Audio, "called");
250 261
251 IPC::RequestParser rp{ctx}; 262 OpenAudioRendererImpl(ctx);
252 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
253 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
254
255 rb.Push(RESULT_SUCCESS);
256 rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params));
257} 263}
258 264
259void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 265void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
@@ -325,6 +331,12 @@ void AudRenU::GetAudioDeviceService(Kernel::HLERequestContext& ctx) {
325 rb.PushIpcInterface<Audio::IAudioDevice>(); 331 rb.PushIpcInterface<Audio::IAudioDevice>();
326} 332}
327 333
334void AudRenU::OpenAudioRendererAuto(Kernel::HLERequestContext& ctx) {
335 LOG_DEBUG(Service_Audio, "called");
336
337 OpenAudioRendererImpl(ctx);
338}
339
328void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { 340void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) {
329 LOG_WARNING(Service_Audio, "(STUBBED) called"); 341 LOG_WARNING(Service_Audio, "(STUBBED) called");
330 342
@@ -335,6 +347,15 @@ void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& c
335 // based on the current revision 347 // based on the current revision
336} 348}
337 349
350void AudRenU::OpenAudioRendererImpl(Kernel::HLERequestContext& ctx) {
351 IPC::RequestParser rp{ctx};
352 const auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
353 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
354
355 rb.Push(RESULT_SUCCESS);
356 rb.PushIpcInterface<IAudioRenderer>(params);
357}
358
338bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { 359bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const {
339 u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap 360 u32_be version_num = (revision - Common::MakeMagic('R', 'E', 'V', '0')); // Byte swap
340 switch (feature) { 361 switch (feature) {
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index 3d63388fb..e55d25973 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -21,8 +21,11 @@ private:
21 void OpenAudioRenderer(Kernel::HLERequestContext& ctx); 21 void OpenAudioRenderer(Kernel::HLERequestContext& ctx);
22 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx); 22 void GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx);
23 void GetAudioDeviceService(Kernel::HLERequestContext& ctx); 23 void GetAudioDeviceService(Kernel::HLERequestContext& ctx);
24 void OpenAudioRendererAuto(Kernel::HLERequestContext& ctx);
24 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx); 25 void GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx);
25 26
27 void OpenAudioRendererImpl(Kernel::HLERequestContext& ctx);
28
26 enum class AudioFeatures : u32 { 29 enum class AudioFeatures : u32 {
27 Splitter, 30 Splitter,
28 }; 31 };
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 60529323e..3e9d2b3be 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -104,6 +104,8 @@ add_library(video_core STATIC
104if (ENABLE_VULKAN) 104if (ENABLE_VULKAN)
105 target_sources(video_core PRIVATE 105 target_sources(video_core PRIVATE
106 renderer_vulkan/declarations.h 106 renderer_vulkan/declarations.h
107 renderer_vulkan/vk_buffer_cache.cpp
108 renderer_vulkan/vk_buffer_cache.h
107 renderer_vulkan/vk_device.cpp 109 renderer_vulkan/vk_device.cpp
108 renderer_vulkan/vk_device.h 110 renderer_vulkan/vk_device.h
109 renderer_vulkan/vk_memory_manager.cpp 111 renderer_vulkan/vk_memory_manager.cpp
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5fdf1164d..b5a9722f9 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -966,7 +966,7 @@ Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool pre
966 const auto& regs{gpu.regs}; 966 const auto& regs{gpu.regs};
967 967
968 if (!gpu.dirty_flags.color_buffer[index]) { 968 if (!gpu.dirty_flags.color_buffer[index]) {
969 return last_color_buffers[index]; 969 return current_color_buffers[index];
970 } 970 }
971 gpu.dirty_flags.color_buffer.reset(index); 971 gpu.dirty_flags.color_buffer.reset(index);
972 972
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
new file mode 100644
index 000000000..18b7b94a1
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp
@@ -0,0 +1,116 @@
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 <cstring>
6#include <memory>
7#include <optional>
8#include <tuple>
9
10#include "common/alignment.h"
11#include "core/core.h"
12#include "core/memory.h"
13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_buffer_cache.h"
15#include "video_core/renderer_vulkan/vk_scheduler.h"
16#include "video_core/renderer_vulkan/vk_stream_buffer.h"
17
18namespace Vulkan {
19
20VKBufferCache::VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
21 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
22 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size)
23 : RasterizerCache{rasterizer}, tegra_memory_manager{tegra_memory_manager} {
24 const auto usage = vk::BufferUsageFlagBits::eVertexBuffer |
25 vk::BufferUsageFlagBits::eIndexBuffer |
26 vk::BufferUsageFlagBits::eUniformBuffer;
27 const auto access = vk::AccessFlagBits::eVertexAttributeRead | vk::AccessFlagBits::eIndexRead |
28 vk::AccessFlagBits::eUniformRead;
29 stream_buffer =
30 std::make_unique<VKStreamBuffer>(device, memory_manager, scheduler, size, usage, access,
31 vk::PipelineStageFlagBits::eAllCommands);
32 buffer_handle = stream_buffer->GetBuffer();
33}
34
35VKBufferCache::~VKBufferCache() = default;
36
37u64 VKBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, u64 alignment,
38 bool cache) {
39 const auto cpu_addr{tegra_memory_manager.GpuToCpuAddress(gpu_addr)};
40 ASSERT(cpu_addr);
41
42 // Cache management is a big overhead, so only cache entries with a given size.
43 // TODO: Figure out which size is the best for given games.
44 cache &= size >= 2048;
45
46 if (cache) {
47 if (auto entry = TryGet(*cpu_addr); entry) {
48 if (entry->size >= size && entry->alignment == alignment) {
49 return entry->offset;
50 }
51 Unregister(entry);
52 }
53 }
54
55 AlignBuffer(alignment);
56 const u64 uploaded_offset = buffer_offset;
57
58 Memory::ReadBlock(*cpu_addr, buffer_ptr, size);
59
60 buffer_ptr += size;
61 buffer_offset += size;
62
63 if (cache) {
64 auto entry = std::make_shared<CachedBufferEntry>();
65 entry->offset = uploaded_offset;
66 entry->size = size;
67 entry->alignment = alignment;
68 entry->addr = *cpu_addr;
69 Register(entry);
70 }
71
72 return uploaded_offset;
73}
74
75u64 VKBufferCache::UploadHostMemory(const u8* raw_pointer, std::size_t size, u64 alignment) {
76 AlignBuffer(alignment);
77 std::memcpy(buffer_ptr, raw_pointer, size);
78 const u64 uploaded_offset = buffer_offset;
79
80 buffer_ptr += size;
81 buffer_offset += size;
82 return uploaded_offset;
83}
84
85std::tuple<u8*, u64> VKBufferCache::ReserveMemory(std::size_t size, u64 alignment) {
86 AlignBuffer(alignment);
87 u8* const uploaded_ptr = buffer_ptr;
88 const u64 uploaded_offset = buffer_offset;
89
90 buffer_ptr += size;
91 buffer_offset += size;
92 return {uploaded_ptr, uploaded_offset};
93}
94
95void VKBufferCache::Reserve(std::size_t max_size) {
96 bool invalidate;
97 std::tie(buffer_ptr, buffer_offset_base, invalidate) = stream_buffer->Reserve(max_size);
98 buffer_offset = buffer_offset_base;
99
100 if (invalidate) {
101 InvalidateAll();
102 }
103}
104
105VKExecutionContext VKBufferCache::Send(VKExecutionContext exctx) {
106 return stream_buffer->Send(exctx, buffer_offset - buffer_offset_base);
107}
108
109void VKBufferCache::AlignBuffer(std::size_t alignment) {
110 // Align the offset, not the mapped pointer
111 const u64 offset_aligned = Common::AlignUp(buffer_offset, alignment);
112 buffer_ptr += offset_aligned - buffer_offset;
113 buffer_offset = offset_aligned;
114}
115
116} // namespace Vulkan
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h
new file mode 100644
index 000000000..d8e916f31
--- /dev/null
+++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h
@@ -0,0 +1,87 @@
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 <tuple>
9
10#include "common/common_types.h"
11#include "video_core/gpu.h"
12#include "video_core/rasterizer_cache.h"
13#include "video_core/renderer_vulkan/declarations.h"
14#include "video_core/renderer_vulkan/vk_scheduler.h"
15
16namespace Tegra {
17class MemoryManager;
18}
19
20namespace Vulkan {
21
22class VKDevice;
23class VKFence;
24class VKMemoryManager;
25class VKStreamBuffer;
26
27struct CachedBufferEntry final : public RasterizerCacheObject {
28 VAddr GetAddr() const override {
29 return addr;
30 }
31
32 std::size_t GetSizeInBytes() const override {
33 return size;
34 }
35
36 // We do not have to flush this cache as things in it are never modified by us.
37 void Flush() override {}
38
39 VAddr addr;
40 std::size_t size;
41 u64 offset;
42 std::size_t alignment;
43};
44
45class VKBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
46public:
47 explicit VKBufferCache(Tegra::MemoryManager& tegra_memory_manager,
48 VideoCore::RasterizerInterface& rasterizer, const VKDevice& device,
49 VKMemoryManager& memory_manager, VKScheduler& scheduler, u64 size);
50 ~VKBufferCache();
51
52 /// Uploads data from a guest GPU address. Returns host's buffer offset where it's been
53 /// allocated.
54 u64 UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, u64 alignment = 4,
55 bool cache = true);
56
57 /// Uploads from a host memory. Returns host's buffer offset where it's been allocated.
58 u64 UploadHostMemory(const u8* raw_pointer, std::size_t size, u64 alignment = 4);
59
60 /// Reserves memory to be used by host's CPU. Returns mapped address and offset.
61 std::tuple<u8*, u64> ReserveMemory(std::size_t size, u64 alignment = 4);
62
63 /// Reserves a region of memory to be used in subsequent upload/reserve operations.
64 void Reserve(std::size_t max_size);
65
66 /// Ensures that the set data is sent to the device.
67 [[nodiscard]] VKExecutionContext Send(VKExecutionContext exctx);
68
69 /// Returns the buffer cache handle.
70 vk::Buffer GetBuffer() const {
71 return buffer_handle;
72 }
73
74private:
75 void AlignBuffer(std::size_t alignment);
76
77 Tegra::MemoryManager& tegra_memory_manager;
78
79 std::unique_ptr<VKStreamBuffer> stream_buffer;
80 vk::Buffer buffer_handle;
81
82 u8* buffer_ptr = nullptr;
83 u64 buffer_offset = 0;
84 u64 buffer_offset_base = 0;
85};
86
87} // namespace Vulkan
diff --git a/src/web_service/verify_login.h b/src/web_service/verify_login.h
index 39db32dbb..821b345d7 100644
--- a/src/web_service/verify_login.h
+++ b/src/web_service/verify_login.h
@@ -4,8 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <functional>
8#include <future>
9#include <string> 7#include <string>
10 8
11namespace WebService { 9namespace WebService {
diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp
index b7737b615..40da1a4e2 100644
--- a/src/web_service/web_backend.cpp
+++ b/src/web_service/web_backend.cpp
@@ -10,7 +10,6 @@
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/web_result.h" 12#include "common/web_result.h"
13#include "core/settings.h"
14#include "web_service/web_backend.h" 13#include "web_service/web_backend.h"
15 14
16namespace WebService { 15namespace WebService {
diff --git a/src/yuzu/compatdb.cpp b/src/yuzu/compatdb.cpp
index 5f0896f84..c09a06520 100644
--- a/src/yuzu/compatdb.cpp
+++ b/src/yuzu/compatdb.cpp
@@ -61,7 +61,7 @@ void CompatDB::Submit() {
61 button(QWizard::CancelButton)->setVisible(false); 61 button(QWizard::CancelButton)->setVisible(false);
62 62
63 testcase_watcher.setFuture(QtConcurrent::run( 63 testcase_watcher.setFuture(QtConcurrent::run(
64 [this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); })); 64 [] { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
65 break; 65 break;
66 default: 66 default:
67 LOG_ERROR(Frontend, "Unexpected page: {}", currentId()); 67 LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 1d460c189..5ab7896d4 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -561,7 +561,10 @@ void GMainWindow::InitializeHotkeys() {
561 Settings::values.use_frame_limit = !Settings::values.use_frame_limit; 561 Settings::values.use_frame_limit = !Settings::values.use_frame_limit;
562 UpdateStatusBar(); 562 UpdateStatusBar();
563 }); 563 });
564 constexpr u16 SPEED_LIMIT_STEP = 5; 564 // TODO: Remove this comment/static whenever the next major release of
565 // MSVC occurs and we make it a requirement (see:
566 // https://developercommunity.visualstudio.com/content/problem/93922/constexprs-are-trying-to-be-captured-in-lambda-fun.html)
567 static constexpr u16 SPEED_LIMIT_STEP = 5;
565 connect(hotkey_registry.GetHotkey("Main Window", "Increase Speed Limit", this), 568 connect(hotkey_registry.GetHotkey("Main Window", "Increase Speed Limit", this),
566 &QShortcut::activated, this, [&] { 569 &QShortcut::activated, this, [&] {
567 if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { 570 if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) {