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/settings.h1
-rw-r--r--src/core/hle/service/audio/hwopus.cpp28
-rw-r--r--src/core/hle/service/audio/hwopus.h11
-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/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/video_core/textures/astc.cpp56
-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
24 files changed, 185 insertions, 109 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/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/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index 4f2ed2d52..8bafc3a98 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -255,6 +255,32 @@ void HwOpus::GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx) {
255 GetWorkBufferSize(ctx); 255 GetWorkBufferSize(ctx);
256} 256}
257 257
258void HwOpus::GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx) {
259 OpusMultiStreamParametersEx param;
260 std::memcpy(&param, ctx.ReadBuffer().data(), ctx.GetReadBufferSize());
261
262 const auto sample_rate = param.sample_rate;
263 const auto channel_count = param.channel_count;
264 const auto number_streams = param.number_streams;
265 const auto number_stereo_streams = param.number_stereo_streams;
266
267 LOG_DEBUG(
268 Audio,
269 "called with sample_rate={}, channel_count={}, number_streams={}, number_stereo_streams={}",
270 sample_rate, channel_count, number_streams, number_stereo_streams);
271
272 ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
273 sample_rate == 12000 || sample_rate == 8000,
274 "Invalid sample rate");
275
276 const u32 worker_buffer_sz =
277 static_cast<u32>(opus_multistream_decoder_get_size(number_streams, number_stereo_streams));
278
279 IPC::ResponseBuilder rb{ctx, 3};
280 rb.Push(ResultSuccess);
281 rb.Push<u32>(worker_buffer_sz);
282}
283
258void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) { 284void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) {
259 IPC::RequestParser rp{ctx}; 285 IPC::RequestParser rp{ctx};
260 const auto sample_rate = rp.Pop<u32>(); 286 const auto sample_rate = rp.Pop<u32>();
@@ -335,7 +361,7 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
335 {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"}, 361 {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
336 {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"}, 362 {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
337 {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"}, 363 {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
338 {7, nullptr, "GetWorkBufferSizeForMultiStreamEx"}, 364 {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"},
339 }; 365 };
340 RegisterHandlers(functions); 366 RegisterHandlers(functions);
341} 367}
diff --git a/src/core/hle/service/audio/hwopus.h b/src/core/hle/service/audio/hwopus.h
index 265dd0cc6..e6092e290 100644
--- a/src/core/hle/service/audio/hwopus.h
+++ b/src/core/hle/service/audio/hwopus.h
@@ -11,6 +11,16 @@ class System;
11 11
12namespace Service::Audio { 12namespace Service::Audio {
13 13
14struct OpusMultiStreamParametersEx {
15 u32 sample_rate;
16 u32 channel_count;
17 u32 number_streams;
18 u32 number_stereo_streams;
19 u32 use_large_frame_size;
20 u32 padding;
21 std::array<u32, 64> channel_mappings;
22};
23
14class HwOpus final : public ServiceFramework<HwOpus> { 24class HwOpus final : public ServiceFramework<HwOpus> {
15public: 25public:
16 explicit HwOpus(Core::System& system_); 26 explicit HwOpus(Core::System& system_);
@@ -21,6 +31,7 @@ private:
21 void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx); 31 void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx);
22 void GetWorkBufferSize(Kernel::HLERequestContext& ctx); 32 void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
23 void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx); 33 void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx);
34 void GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx);
24}; 35};
25 36
26} // namespace Service::Audio 37} // namespace Service::Audio
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/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/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp
index e3f3d3c5d..b159494c5 100644
--- a/src/video_core/textures/astc.cpp
+++ b/src/video_core/textures/astc.cpp
@@ -13,7 +13,9 @@
13 13
14#include <boost/container/static_vector.hpp> 14#include <boost/container/static_vector.hpp>
15 15
16#include "common/alignment.h"
16#include "common/common_types.h" 17#include "common/common_types.h"
18#include "common/thread_worker.h"
17#include "video_core/textures/astc.h" 19#include "video_core/textures/astc.h"
18 20
19class InputBitStream { 21class InputBitStream {
@@ -1650,29 +1652,41 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth,
1650 1652
1651void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, 1653void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
1652 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) { 1654 uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) {
1653 u32 block_index = 0; 1655 const u32 rows = Common::DivideUp(height, block_height);
1654 std::size_t depth_offset = 0; 1656 const u32 cols = Common::DivideUp(width, block_width);
1655 for (u32 z = 0; z < depth; z++) { 1657
1656 for (u32 y = 0; y < height; y += block_height) { 1658 Common::ThreadWorker workers{std::max(std::thread::hardware_concurrency(), 2U) / 2,
1657 for (u32 x = 0; x < width; x += block_width) { 1659 "yuzu:ASTCDecompress"};
1658 const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)}; 1660
1659 1661 for (u32 z = 0; z < depth; ++z) {
1660 // Blocks can be at most 12x12 1662 const u32 depth_offset = z * height * width * 4;
1661 std::array<u32, 12 * 12> uncompData; 1663 for (u32 y_index = 0; y_index < rows; ++y_index) {
1662 DecompressBlock(blockPtr, block_width, block_height, uncompData); 1664 auto decompress_stride = [data, width, height, depth, block_width, block_height, output,
1663 1665 rows, cols, z, depth_offset, y_index] {
1664 u32 decompWidth = std::min(block_width, width - x); 1666 const u32 y = y_index * block_height;
1665 u32 decompHeight = std::min(block_height, height - y); 1667 for (u32 x_index = 0; x_index < cols; ++x_index) {
1666 1668 const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index;
1667 const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4); 1669 const u32 x = x_index * block_width;
1668 for (u32 jj = 0; jj < decompHeight; jj++) { 1670
1669 std::memcpy(outRow.data() + jj * width * 4, 1671 const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)};
1670 uncompData.data() + jj * block_width, decompWidth * 4); 1672
1673 // Blocks can be at most 12x12
1674 std::array<u32, 12 * 12> uncompData;
1675 DecompressBlock(blockPtr, block_width, block_height, uncompData);
1676
1677 u32 decompWidth = std::min(block_width, width - x);
1678 u32 decompHeight = std::min(block_height, height - y);
1679
1680 const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4);
1681 for (u32 h = 0; h < decompHeight; ++h) {
1682 std::memcpy(outRow.data() + h * width * 4,
1683 uncompData.data() + h * block_width, decompWidth * 4);
1684 }
1671 } 1685 }
1672 ++block_index; 1686 };
1673 } 1687 workers.QueueWork(std::move(decompress_stride));
1674 } 1688 }
1675 depth_offset += height * width * 4; 1689 workers.WaitForRequests();
1676 } 1690 }
1677} 1691}
1678 1692
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 3c1bd19db..23245a976 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);