summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_core.cpp2
-rw-r--r--src/audio_core/audio_manager.cpp17
-rw-r--r--src/audio_core/audio_manager.h19
-rw-r--r--src/audio_core/renderer/adsp/audio_renderer.cpp2
-rw-r--r--src/audio_core/renderer/adsp/audio_renderer.h2
-rw-r--r--src/audio_core/sink/sink_stream.cpp9
-rw-r--r--src/common/CMakeLists.txt29
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/hle/service/nfp/nfp.cpp4
-rw-r--r--src/core/hle/service/sockets/bsd.cpp2
-rw-r--r--src/core/internal_network/network.cpp12
-rw-r--r--src/core/internal_network/sockets.h11
-rw-r--r--src/core/loader/loader.cpp4
-rw-r--r--src/network/network.cpp2
-rw-r--r--src/shader_recompiler/backend/glasm/emit_glasm.cpp2
-rw-r--r--src/shader_recompiler/backend/glsl/emit_glsl.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/input_profiles.cpp2
-rw-r--r--src/yuzu/main.cpp3
-rw-r--r--src/yuzu/startup_checks.cpp91
-rw-r--r--src/yuzu/startup_checks.h2
23 files changed, 118 insertions, 114 deletions
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index c845330cd..07a679c32 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -8,7 +8,7 @@
8 8
9namespace AudioCore { 9namespace AudioCore {
10 10
11AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>(system)} { 11AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>()} {
12 CreateSinks(); 12 CreateSinks();
13 // Must be created after the sinks 13 // Must be created after the sinks
14 adsp = std::make_unique<AudioRenderer::ADSP::ADSP>(system, *output_sink); 14 adsp = std::make_unique<AudioRenderer::ADSP::ADSP>(system, *output_sink);
diff --git a/src/audio_core/audio_manager.cpp b/src/audio_core/audio_manager.cpp
index 2f1bba9c3..2acde668e 100644
--- a/src/audio_core/audio_manager.cpp
+++ b/src/audio_core/audio_manager.cpp
@@ -1,14 +1,13 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project 1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include "audio_core/audio_in_manager.h"
5#include "audio_core/audio_manager.h" 4#include "audio_core/audio_manager.h"
6#include "audio_core/audio_out_manager.h"
7#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/service/audio/errors.h"
8 7
9namespace AudioCore { 8namespace AudioCore {
10 9
11AudioManager::AudioManager(Core::System& system_) : system{system_} { 10AudioManager::AudioManager() {
12 thread = std::jthread([this]() { ThreadFunc(); }); 11 thread = std::jthread([this]() { ThreadFunc(); });
13} 12}
14 13
@@ -27,7 +26,7 @@ Result AudioManager::SetOutManager(BufferEventFunc buffer_func) {
27 26
28 const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)}; 27 const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)};
29 if (buffer_events[index] == nullptr) { 28 if (buffer_events[index] == nullptr) {
30 buffer_events[index] = buffer_func; 29 buffer_events[index] = std::move(buffer_func);
31 needs_update = true; 30 needs_update = true;
32 events.SetAudioEvent(Event::Type::AudioOutManager, true); 31 events.SetAudioEvent(Event::Type::AudioOutManager, true);
33 } 32 }
@@ -43,7 +42,7 @@ Result AudioManager::SetInManager(BufferEventFunc buffer_func) {
43 42
44 const auto index{events.GetManagerIndex(Event::Type::AudioInManager)}; 43 const auto index{events.GetManagerIndex(Event::Type::AudioInManager)};
45 if (buffer_events[index] == nullptr) { 44 if (buffer_events[index] == nullptr) {
46 buffer_events[index] = buffer_func; 45 buffer_events[index] = std::move(buffer_func);
47 needs_update = true; 46 needs_update = true;
48 events.SetAudioEvent(Event::Type::AudioInManager, true); 47 events.SetAudioEvent(Event::Type::AudioInManager, true);
49 } 48 }
@@ -60,19 +59,21 @@ void AudioManager::ThreadFunc() {
60 running = true; 59 running = true;
61 60
62 while (running) { 61 while (running) {
63 auto timed_out{events.Wait(l, std::chrono::seconds(2))}; 62 const auto timed_out{events.Wait(l, std::chrono::seconds(2))};
64 63
65 if (events.CheckAudioEventSet(Event::Type::Max)) { 64 if (events.CheckAudioEventSet(Event::Type::Max)) {
66 break; 65 break;
67 } 66 }
68 67
69 for (size_t i = 0; i < buffer_events.size(); i++) { 68 for (size_t i = 0; i < buffer_events.size(); i++) {
70 if (events.CheckAudioEventSet(Event::Type(i)) || timed_out) { 69 const auto event_type = static_cast<Event::Type>(i);
70
71 if (events.CheckAudioEventSet(event_type) || timed_out) {
71 if (buffer_events[i]) { 72 if (buffer_events[i]) {
72 buffer_events[i](); 73 buffer_events[i]();
73 } 74 }
74 } 75 }
75 events.SetAudioEvent(Event::Type(i), false); 76 events.SetAudioEvent(event_type, false);
76 } 77 }
77 } 78 }
78} 79}
diff --git a/src/audio_core/audio_manager.h b/src/audio_core/audio_manager.h
index 8cbd95e22..abf077de4 100644
--- a/src/audio_core/audio_manager.h
+++ b/src/audio_core/audio_manager.h
@@ -10,22 +10,11 @@
10#include <thread> 10#include <thread>
11 11
12#include "audio_core/audio_event.h" 12#include "audio_core/audio_event.h"
13#include "core/hle/service/audio/errors.h"
14 13
15namespace Core { 14union Result;
16class System;
17}
18 15
19namespace AudioCore { 16namespace AudioCore {
20 17
21namespace AudioOut {
22class Manager;
23}
24
25namespace AudioIn {
26class Manager;
27}
28
29/** 18/**
30 * The AudioManager's main purpose is to wait for buffer events for the audio in and out managers, 19 * The AudioManager's main purpose is to wait for buffer events for the audio in and out managers,
31 * and call an associated callback to release buffers. 20 * and call an associated callback to release buffers.
@@ -43,7 +32,7 @@ class AudioManager {
43 using BufferEventFunc = std::function<void()>; 32 using BufferEventFunc = std::function<void()>;
44 33
45public: 34public:
46 explicit AudioManager(Core::System& system); 35 explicit AudioManager();
47 36
48 /** 37 /**
49 * Shutdown the audio manager. 38 * Shutdown the audio manager.
@@ -80,10 +69,6 @@ private:
80 */ 69 */
81 void ThreadFunc(); 70 void ThreadFunc();
82 71
83 /// Core system
84 Core::System& system;
85 /// Have sessions started palying?
86 bool sessions_started{};
87 /// Is the main thread running? 72 /// Is the main thread running?
88 std::atomic<bool> running{}; 73 std::atomic<bool> running{};
89 /// Unused 74 /// Unused
diff --git a/src/audio_core/renderer/adsp/audio_renderer.cpp b/src/audio_core/renderer/adsp/audio_renderer.cpp
index bafe4822a..ab2257bd8 100644
--- a/src/audio_core/renderer/adsp/audio_renderer.cpp
+++ b/src/audio_core/renderer/adsp/audio_renderer.cpp
@@ -47,7 +47,7 @@ RenderMessage AudioRenderer_Mailbox::ADSPWaitMessage() {
47 return msg; 47 return msg;
48} 48}
49 49
50CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const s32 session_id) { 50CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const u32 session_id) {
51 return command_buffers[session_id]; 51 return command_buffers[session_id];
52} 52}
53 53
diff --git a/src/audio_core/renderer/adsp/audio_renderer.h b/src/audio_core/renderer/adsp/audio_renderer.h
index 02e923c84..151f38c1b 100644
--- a/src/audio_core/renderer/adsp/audio_renderer.h
+++ b/src/audio_core/renderer/adsp/audio_renderer.h
@@ -83,7 +83,7 @@ public:
83 * @param session_id - The session id to get (0 or 1). 83 * @param session_id - The session id to get (0 or 1).
84 * @return The command buffer. 84 * @return The command buffer.
85 */ 85 */
86 CommandBuffer& GetCommandBuffer(s32 session_id); 86 CommandBuffer& GetCommandBuffer(u32 session_id);
87 87
88 /** 88 /**
89 * Set the command buffer with the given session id (0 or 1). 89 * Set the command buffer with the given session id (0 or 1).
diff --git a/src/audio_core/sink/sink_stream.cpp b/src/audio_core/sink/sink_stream.cpp
index 37fe725e4..849f862b0 100644
--- a/src/audio_core/sink/sink_stream.cpp
+++ b/src/audio_core/sink/sink_stream.cpp
@@ -214,8 +214,13 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
214 // video play out without attempting to stall. 214 // video play out without attempting to stall.
215 // Can hopefully remove this later with a more complete NVDEC implementation. 215 // Can hopefully remove this later with a more complete NVDEC implementation.
216 const auto nvdec_active{system.AudioCore().IsNVDECActive()}; 216 const auto nvdec_active{system.AudioCore().IsNVDECActive()};
217 if (!nvdec_active && queued_buffers > max_queue_size) { 217
218 // Core timing cannot be paused in single-core mode, so Stall ends up being called over and over
219 // and never recovers to a normal state, so just skip attempting to sync things on single-core.
220 if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) {
218 Stall(); 221 Stall();
222 } else if (system.IsMulticore() && queued_buffers <= max_queue_size) {
223 Unstall();
219 } 224 }
220 225
221 while (frames_written < num_frames) { 226 while (frames_written < num_frames) {
@@ -255,7 +260,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz
255 std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], 260 std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size],
256 frame_size_bytes); 261 frame_size_bytes);
257 262
258 if (stalled && queued_buffers <= max_queue_size) { 263 if (system.IsMulticore() && queued_buffers <= max_queue_size) {
259 Unstall(); 264 Unstall();
260 } 265 }
261} 266}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 68436a4bc..3447fabd8 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -14,32 +14,7 @@ if (DEFINED ENV{DISPLAYVERSION})
14 set(DISPLAY_VERSION $ENV{DISPLAYVERSION}) 14 set(DISPLAY_VERSION $ENV{DISPLAYVERSION})
15endif () 15endif ()
16 16
17# Pass the path to git to the GenerateSCMRev.cmake as well 17include(GenerateSCMRev)
18find_package(Git QUIET)
19
20add_custom_command(OUTPUT scm_rev.cpp
21 COMMAND ${CMAKE_COMMAND}
22 -DSRC_DIR=${PROJECT_SOURCE_DIR}
23 -DBUILD_REPOSITORY=${BUILD_REPOSITORY}
24 -DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE}
25 -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
26 -DBUILD_TAG=${BUILD_TAG}
27 -DBUILD_ID=${DISPLAY_VERSION}
28 -DGIT_REF_SPEC=${GIT_REF_SPEC}
29 -DGIT_REV=${GIT_REV}
30 -DGIT_DESC=${GIT_DESC}
31 -DGIT_BRANCH=${GIT_BRANCH}
32 -DBUILD_FULLNAME=${BUILD_FULLNAME}
33 -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
34 -P ${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
35 DEPENDS
36 # Check that the scm_rev files haven't changed
37 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
38 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h"
39 # technically we should regenerate if the git version changed, but its not worth the effort imo
40 "${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
41 VERBATIM
42)
43 18
44add_library(common STATIC 19add_library(common STATIC
45 algorithm.h 20 algorithm.h
@@ -117,7 +92,7 @@ add_library(common STATIC
117 quaternion.h 92 quaternion.h
118 reader_writer_queue.h 93 reader_writer_queue.h
119 ring_buffer.h 94 ring_buffer.h
120 scm_rev.cpp 95 ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
121 scm_rev.h 96 scm_rev.h
122 scope_exit.h 97 scope_exit.h
123 settings.cpp 98 settings.cpp
diff --git a/src/common/settings.h b/src/common/settings.h
index 851812f28..d2452c93b 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -531,6 +531,7 @@ struct Values {
531 Setting<bool> use_auto_stub{false, "use_auto_stub"}; 531 Setting<bool> use_auto_stub{false, "use_auto_stub"};
532 Setting<bool> enable_all_controllers{false, "enable_all_controllers"}; 532 Setting<bool> enable_all_controllers{false, "enable_all_controllers"};
533 Setting<bool> create_crash_dumps{false, "create_crash_dumps"}; 533 Setting<bool> create_crash_dumps{false, "create_crash_dumps"};
534 Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"};
534 535
535 // Miscellaneous 536 // Miscellaneous
536 Setting<std::string> log_filter{"*:Info", "log_filter"}; 537 Setting<std::string> log_filter{"*:Info", "log_filter"};
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index e0ed3f771..037b86653 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -800,12 +800,12 @@ Result Module::Interface::Flush() {
800 800
801 // Return to the start of the file 801 // Return to the start of the file
802 if (!amiibo_file.Seek(0)) { 802 if (!amiibo_file.Seek(0)) {
803 LOG_ERROR(Service_NFP, "Error writting to file"); 803 LOG_ERROR(Service_NFP, "Error writing to file");
804 return ErrCodes::WriteAmiiboFailed; 804 return ErrCodes::WriteAmiiboFailed;
805 } 805 }
806 806
807 if (!amiibo_file.Write(encrypted_tag_data)) { 807 if (!amiibo_file.Write(encrypted_tag_data)) {
808 LOG_ERROR(Service_NFP, "Error writting to file"); 808 LOG_ERROR(Service_NFP, "Error writing to file");
809 return ErrCodes::WriteAmiiboFailed; 809 return ErrCodes::WriteAmiiboFailed;
810 } 810 }
811 811
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp
index cc679cc81..9e94a462f 100644
--- a/src/core/hle/service/sockets/bsd.cpp
+++ b/src/core/hle/service/sockets/bsd.cpp
@@ -929,7 +929,7 @@ BSD::BSD(Core::System& system_, const char* name)
929 proxy_packet_received = room_member->BindOnProxyPacketReceived( 929 proxy_packet_received = room_member->BindOnProxyPacketReceived(
930 [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); }); 930 [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); });
931 } else { 931 } else {
932 LOG_ERROR(Service, "Network isn't initalized"); 932 LOG_ERROR(Service, "Network isn't initialized");
933 } 933 }
934} 934}
935 935
diff --git a/src/core/internal_network/network.cpp b/src/core/internal_network/network.cpp
index cdf38a2a4..447fbffaa 100644
--- a/src/core/internal_network/network.cpp
+++ b/src/core/internal_network/network.cpp
@@ -364,7 +364,7 @@ std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
364 std::vector<WSAPOLLFD> host_pollfds(pollfds.size()); 364 std::vector<WSAPOLLFD> host_pollfds(pollfds.size());
365 std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) { 365 std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) {
366 WSAPOLLFD result; 366 WSAPOLLFD result;
367 result.fd = fd.socket->fd; 367 result.fd = fd.socket->GetFD();
368 result.events = TranslatePollEvents(fd.events); 368 result.events = TranslatePollEvents(fd.events);
369 result.revents = 0; 369 result.revents = 0;
370 return result; 370 return result;
@@ -430,12 +430,12 @@ std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() {
430 return {AcceptResult{}, GetAndLogLastError()}; 430 return {AcceptResult{}, GetAndLogLastError()};
431 } 431 }
432 432
433 AcceptResult result;
434 result.socket = std::make_unique<Socket>();
435 result.socket->fd = new_socket;
436
437 ASSERT(addrlen == sizeof(sockaddr_in)); 433 ASSERT(addrlen == sizeof(sockaddr_in));
438 result.sockaddr_in = TranslateToSockAddrIn(addr); 434
435 AcceptResult result{
436 .socket = std::make_unique<Socket>(new_socket),
437 .sockaddr_in = TranslateToSockAddrIn(addr),
438 };
439 439
440 return {std::move(result), Errno::SUCCESS}; 440 return {std::move(result), Errno::SUCCESS};
441} 441}
diff --git a/src/core/internal_network/sockets.h b/src/core/internal_network/sockets.h
index a70429b19..2e328c645 100644
--- a/src/core/internal_network/sockets.h
+++ b/src/core/internal_network/sockets.h
@@ -32,6 +32,10 @@ public:
32 std::unique_ptr<SocketBase> socket; 32 std::unique_ptr<SocketBase> socket;
33 SockAddrIn sockaddr_in; 33 SockAddrIn sockaddr_in;
34 }; 34 };
35
36 SocketBase() = default;
37 explicit SocketBase(SOCKET fd_) : fd{fd_} {}
38
35 virtual ~SocketBase() = default; 39 virtual ~SocketBase() = default;
36 40
37 virtual SocketBase& operator=(const SocketBase&) = delete; 41 virtual SocketBase& operator=(const SocketBase&) = delete;
@@ -89,12 +93,19 @@ public:
89 93
90 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; 94 virtual void HandleProxyPacket(const ProxyPacket& packet) = 0;
91 95
96 [[nodiscard]] SOCKET GetFD() const {
97 return fd;
98 }
99
100protected:
92 SOCKET fd = INVALID_SOCKET; 101 SOCKET fd = INVALID_SOCKET;
93}; 102};
94 103
95class Socket : public SocketBase { 104class Socket : public SocketBase {
96public: 105public:
97 Socket() = default; 106 Socket() = default;
107 explicit Socket(SOCKET fd_) : SocketBase{fd_} {}
108
98 ~Socket() override; 109 ~Socket() override;
99 110
100 Socket(const Socket&) = delete; 111 Socket(const Socket&) = delete;
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 104d16efa..f24474ed8 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -244,6 +244,10 @@ static std::unique_ptr<AppLoader> GetFileLoader(Core::System& system, FileSys::V
244 244
245std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file, 245std::unique_ptr<AppLoader> GetLoader(Core::System& system, FileSys::VirtualFile file,
246 u64 program_id, std::size_t program_index) { 246 u64 program_id, std::size_t program_index) {
247 if (!file) {
248 return nullptr;
249 }
250
247 FileType type = IdentifyFile(file); 251 FileType type = IdentifyFile(file);
248 const FileType filename_type = GuessFromFilename(file->GetName()); 252 const FileType filename_type = GuessFromFilename(file->GetName());
249 253
diff --git a/src/network/network.cpp b/src/network/network.cpp
index 0841e4134..6652a186b 100644
--- a/src/network/network.cpp
+++ b/src/network/network.cpp
@@ -15,7 +15,7 @@ RoomNetwork::RoomNetwork() {
15 15
16bool RoomNetwork::Init() { 16bool RoomNetwork::Init() {
17 if (enet_initialize() != 0) { 17 if (enet_initialize() != 0) {
18 LOG_ERROR(Network, "Error initalizing ENet"); 18 LOG_ERROR(Network, "Error initializing ENet");
19 return false; 19 return false;
20 } 20 }
21 m_room = std::make_shared<Room>(); 21 m_room = std::make_shared<Room>();
diff --git a/src/shader_recompiler/backend/glasm/emit_glasm.cpp b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
index 97a6b383b..01f9abc71 100644
--- a/src/shader_recompiler/backend/glasm/emit_glasm.cpp
+++ b/src/shader_recompiler/backend/glasm/emit_glasm.cpp
@@ -175,7 +175,7 @@ bool IsReference(IR::Inst& inst) {
175} 175}
176 176
177void PrecolorInst(IR::Inst& phi) { 177void PrecolorInst(IR::Inst& phi) {
178 // Insert phi moves before references to avoid overwritting other phis 178 // Insert phi moves before references to avoid overwriting other phis
179 const size_t num_args{phi.NumArgs()}; 179 const size_t num_args{phi.NumArgs()};
180 for (size_t i = 0; i < num_args; ++i) { 180 for (size_t i = 0; i < num_args; ++i) {
181 IR::Block& phi_block{*phi.PhiBlock(i)}; 181 IR::Block& phi_block{*phi.PhiBlock(i)};
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl.cpp b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
index 76c18e488..e8a4390f6 100644
--- a/src/shader_recompiler/backend/glsl/emit_glsl.cpp
+++ b/src/shader_recompiler/backend/glsl/emit_glsl.cpp
@@ -101,7 +101,7 @@ bool IsReference(IR::Inst& inst) {
101} 101}
102 102
103void PrecolorInst(IR::Inst& phi) { 103void PrecolorInst(IR::Inst& phi) {
104 // Insert phi moves before references to avoid overwritting other phis 104 // Insert phi moves before references to avoid overwriting other phis
105 const size_t num_args{phi.NumArgs()}; 105 const size_t num_args{phi.NumArgs()};
106 for (size_t i = 0; i < num_args; ++i) { 106 for (size_t i = 0; i < num_args; ++i) {
107 IR::Block& phi_block{*phi.PhiBlock(i)}; 107 IR::Block& phi_block{*phi.PhiBlock(i)};
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index a4ed68422..195074bf2 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -546,6 +546,7 @@ void Config::ReadDebuggingValues() {
546 ReadBasicSetting(Settings::values.use_auto_stub); 546 ReadBasicSetting(Settings::values.use_auto_stub);
547 ReadBasicSetting(Settings::values.enable_all_controllers); 547 ReadBasicSetting(Settings::values.enable_all_controllers);
548 ReadBasicSetting(Settings::values.create_crash_dumps); 548 ReadBasicSetting(Settings::values.create_crash_dumps);
549 ReadBasicSetting(Settings::values.perform_vulkan_check);
549 550
550 qt_config->endGroup(); 551 qt_config->endGroup();
551} 552}
@@ -1162,6 +1163,7 @@ void Config::SaveDebuggingValues() {
1162 WriteBasicSetting(Settings::values.disable_macro_jit); 1163 WriteBasicSetting(Settings::values.disable_macro_jit);
1163 WriteBasicSetting(Settings::values.enable_all_controllers); 1164 WriteBasicSetting(Settings::values.enable_all_controllers);
1164 WriteBasicSetting(Settings::values.create_crash_dumps); 1165 WriteBasicSetting(Settings::values.create_crash_dumps);
1166 WriteBasicSetting(Settings::values.perform_vulkan_check);
1165 1167
1166 qt_config->endGroup(); 1168 qt_config->endGroup();
1167} 1169}
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 622808e94..dacc75a20 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -77,6 +77,7 @@ void ConfigureDebug::SetConfiguration() {
77 ui->disable_loop_safety_checks->setChecked( 77 ui->disable_loop_safety_checks->setChecked(
78 Settings::values.disable_shader_loop_safety_checks.GetValue()); 78 Settings::values.disable_shader_loop_safety_checks.GetValue());
79 ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); 79 ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue());
80 ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue());
80 81
81#ifdef YUZU_USE_QT_WEB_ENGINE 82#ifdef YUZU_USE_QT_WEB_ENGINE
82 ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue()); 83 ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
@@ -117,6 +118,7 @@ void ConfigureDebug::ApplyConfiguration() {
117 ui->disable_loop_safety_checks->isChecked(); 118 ui->disable_loop_safety_checks->isChecked();
118 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); 119 Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
119 Settings::values.extended_logging = ui->extended_logging->isChecked(); 120 Settings::values.extended_logging = ui->extended_logging->isChecked();
121 Settings::values.perform_vulkan_check = ui->perform_vulkan_check->isChecked();
120 UISettings::values.disable_web_applet = ui->disable_web_applet->isChecked(); 122 UISettings::values.disable_web_applet = ui->disable_web_applet->isChecked();
121 Debugger::ToggleConsole(); 123 Debugger::ToggleConsole();
122 Common::Log::Filter filter; 124 Common::Log::Filter filter;
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 314d47af5..102c8c66c 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -313,6 +313,16 @@
313 </property> 313 </property>
314 </widget> 314 </widget>
315 </item> 315 </item>
316 <item row="3" column="0">
317 <widget class="QCheckBox" name="perform_vulkan_check">
318 <property name="toolTip">
319 <string>Enables yuzu to check for a working Vulkan environment when the program starts up. Disable this if this is causing issues with external programs seeing yuzu.</string>
320 </property>
321 <property name="text">
322 <string>Perform Startup Vulkan Check</string>
323 </property>
324 </widget>
325 </item>
316 </layout> 326 </layout>
317 </widget> 327 </widget>
318 </item> 328 </item>
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 807afbeb2..9bb69cab1 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -67,6 +67,8 @@ std::vector<std::string> InputProfiles::GetInputProfileNames() {
67 profile_names.push_back(profile_name); 67 profile_names.push_back(profile_name);
68 } 68 }
69 69
70 std::stable_sort(profile_names.begin(), profile_names.end());
71
70 return profile_names; 72 return profile_names;
71} 73}
72 74
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 8c624427f..e2c2b9292 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -4086,7 +4086,8 @@ int main(int argc, char* argv[]) {
4086 } 4086 }
4087#endif 4087#endif
4088 4088
4089 if (StartupChecks(argv[0], &has_broken_vulkan)) { 4089 if (StartupChecks(argv[0], &has_broken_vulkan,
4090 Settings::values.perform_vulkan_check.GetValue())) {
4090 return 0; 4091 return 0;
4091 } 4092 }
4092 4093
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 29b87da05..fc2693f9d 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -57,7 +57,7 @@ bool CheckEnvVars(bool* is_child) {
57 return false; 57 return false;
58} 58}
59 59
60bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { 60bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check) {
61#ifdef _WIN32 61#ifdef _WIN32
62 // Set the startup variable for child processes 62 // Set the startup variable for child processes
63 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT); 63 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
@@ -67,29 +67,32 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
67 return false; 67 return false;
68 } 68 }
69 69
70 PROCESS_INFORMATION process_info; 70 if (perform_vulkan_check) {
71 std::memset(&process_info, '\0', sizeof(process_info)); 71 // Spawn child process that performs Vulkan check
72 72 PROCESS_INFORMATION process_info;
73 if (!SpawnChild(arg0, &process_info, 0)) { 73 std::memset(&process_info, '\0', sizeof(process_info));
74 return false; 74
75 } 75 if (!SpawnChild(arg0, &process_info, 0)) {
76 76 return false;
77 // Wait until the processs exits and get exit code from it 77 }
78 WaitForSingleObject(process_info.hProcess, INFINITE); 78
79 DWORD exit_code = STILL_ACTIVE; 79 // Wait until the processs exits and get exit code from it
80 const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); 80 WaitForSingleObject(process_info.hProcess, INFINITE);
81 if (err == 0) { 81 DWORD exit_code = STILL_ACTIVE;
82 std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); 82 const int err = GetExitCodeProcess(process_info.hProcess, &exit_code);
83 } 83 if (err == 0) {
84 84 std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError());
85 // Vulkan is broken if the child crashed (return value is not zero) 85 }
86 *has_broken_vulkan = (exit_code != 0); 86
87 87 // Vulkan is broken if the child crashed (return value is not zero)
88 if (CloseHandle(process_info.hProcess) == 0) { 88 *has_broken_vulkan = (exit_code != 0);
89 std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); 89
90 } 90 if (CloseHandle(process_info.hProcess) == 0) {
91 if (CloseHandle(process_info.hThread) == 0) { 91 std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
92 std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); 92 }
93 if (CloseHandle(process_info.hThread) == 0) {
94 std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError());
95 }
93 } 96 }
94 97
95 if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { 98 if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) {
@@ -98,26 +101,28 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
98 } 101 }
99 102
100#elif defined(YUZU_UNIX) 103#elif defined(YUZU_UNIX)
101 const pid_t pid = fork(); 104 if (perform_vulkan_check) {
102 if (pid == 0) { 105 const pid_t pid = fork();
103 CheckVulkan(); 106 if (pid == 0) {
104 return true; 107 CheckVulkan();
105 } else if (pid == -1) { 108 return true;
106 const int err = errno; 109 } else if (pid == -1) {
107 std::fprintf(stderr, "fork failed with error %d\n", err); 110 const int err = errno;
108 return false; 111 std::fprintf(stderr, "fork failed with error %d\n", err);
109 } 112 return false;
110 113 }
111 // Get exit code from child process 114
112 int status; 115 // Get exit code from child process
113 const int r_val = wait(&status); 116 int status;
114 if (r_val == -1) { 117 const int r_val = wait(&status);
115 const int err = errno; 118 if (r_val == -1) {
116 std::fprintf(stderr, "wait failed with error %d\n", err); 119 const int err = errno;
117 return false; 120 std::fprintf(stderr, "wait failed with error %d\n", err);
121 return false;
122 }
123 // Vulkan is broken if the child crashed (return value is not zero)
124 *has_broken_vulkan = (status != 0);
118 } 125 }
119 // Vulkan is broken if the child crashed (return value is not zero)
120 *has_broken_vulkan = (status != 0);
121#endif 126#endif
122 return false; 127 return false;
123} 128}
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h
index f2fc2d9d4..d8e563be6 100644
--- a/src/yuzu/startup_checks.h
+++ b/src/yuzu/startup_checks.h
@@ -13,7 +13,7 @@ constexpr char ENV_VAR_ENABLED_TEXT[] = "ON";
13 13
14void CheckVulkan(); 14void CheckVulkan();
15bool CheckEnvVars(bool* is_child); 15bool CheckEnvVars(bool* is_child);
16bool StartupChecks(const char* arg0, bool* has_broken_vulkan); 16bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check);
17 17
18#ifdef _WIN32 18#ifdef _WIN32
19bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); 19bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);