diff options
Diffstat (limited to 'src')
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 @@ namespace AudioCore { -AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>(system)} { +AudioCore::AudioCore(Core::System& system) : audio_manager{std::make_unique<AudioManager>()} { CreateSinks(); // Must be created after the sinks 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 @@ // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "audio_core/audio_in_manager.h" #include "audio_core/audio_manager.h" -#include "audio_core/audio_out_manager.h" #include "core/core.h" +#include "core/hle/service/audio/errors.h" namespace AudioCore { -AudioManager::AudioManager(Core::System& system_) : system{system_} { +AudioManager::AudioManager() { thread = std::jthread([this]() { ThreadFunc(); }); } @@ -27,7 +26,7 @@ Result AudioManager::SetOutManager(BufferEventFunc buffer_func) { const auto index{events.GetManagerIndex(Event::Type::AudioOutManager)}; if (buffer_events[index] == nullptr) { - buffer_events[index] = buffer_func; + buffer_events[index] = std::move(buffer_func); needs_update = true; events.SetAudioEvent(Event::Type::AudioOutManager, true); } @@ -43,7 +42,7 @@ Result AudioManager::SetInManager(BufferEventFunc buffer_func) { const auto index{events.GetManagerIndex(Event::Type::AudioInManager)}; if (buffer_events[index] == nullptr) { - buffer_events[index] = buffer_func; + buffer_events[index] = std::move(buffer_func); needs_update = true; events.SetAudioEvent(Event::Type::AudioInManager, true); } @@ -60,19 +59,21 @@ void AudioManager::ThreadFunc() { running = true; while (running) { - auto timed_out{events.Wait(l, std::chrono::seconds(2))}; + const auto timed_out{events.Wait(l, std::chrono::seconds(2))}; if (events.CheckAudioEventSet(Event::Type::Max)) { break; } for (size_t i = 0; i < buffer_events.size(); i++) { - if (events.CheckAudioEventSet(Event::Type(i)) || timed_out) { + const auto event_type = static_cast<Event::Type>(i); + + if (events.CheckAudioEventSet(event_type) || timed_out) { if (buffer_events[i]) { buffer_events[i](); } } - events.SetAudioEvent(Event::Type(i), false); + events.SetAudioEvent(event_type, false); } } } 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 @@ #include <thread> #include "audio_core/audio_event.h" -#include "core/hle/service/audio/errors.h" -namespace Core { -class System; -} +union Result; namespace AudioCore { -namespace AudioOut { -class Manager; -} - -namespace AudioIn { -class Manager; -} - /** * The AudioManager's main purpose is to wait for buffer events for the audio in and out managers, * and call an associated callback to release buffers. @@ -43,7 +32,7 @@ class AudioManager { using BufferEventFunc = std::function<void()>; public: - explicit AudioManager(Core::System& system); + explicit AudioManager(); /** * Shutdown the audio manager. @@ -80,10 +69,6 @@ private: */ void ThreadFunc(); - /// Core system - Core::System& system; - /// Have sessions started palying? - bool sessions_started{}; /// Is the main thread running? std::atomic<bool> running{}; /// 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() { return msg; } -CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const s32 session_id) { +CommandBuffer& AudioRenderer_Mailbox::GetCommandBuffer(const u32 session_id) { return command_buffers[session_id]; } 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: * @param session_id - The session id to get (0 or 1). * @return The command buffer. */ - CommandBuffer& GetCommandBuffer(s32 session_id); + CommandBuffer& GetCommandBuffer(u32 session_id); /** * 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 // video play out without attempting to stall. // Can hopefully remove this later with a more complete NVDEC implementation. const auto nvdec_active{system.AudioCore().IsNVDECActive()}; - if (!nvdec_active && queued_buffers > max_queue_size) { + + // Core timing cannot be paused in single-core mode, so Stall ends up being called over and over + // and never recovers to a normal state, so just skip attempting to sync things on single-core. + if (system.IsMulticore() && !nvdec_active && queued_buffers > max_queue_size) { Stall(); + } else if (system.IsMulticore() && queued_buffers <= max_queue_size) { + Unstall(); } while (frames_written < num_frames) { @@ -255,7 +260,7 @@ void SinkStream::ProcessAudioOutAndRender(std::span<s16> output_buffer, std::siz std::memcpy(&last_frame[0], &output_buffer[(frames_written - 1) * frame_size], frame_size_bytes); - if (stalled && queued_buffers <= max_queue_size) { + if (system.IsMulticore() && queued_buffers <= max_queue_size) { Unstall(); } } 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 { Setting<bool> use_auto_stub{false, "use_auto_stub"}; Setting<bool> enable_all_controllers{false, "enable_all_controllers"}; Setting<bool> create_crash_dumps{false, "create_crash_dumps"}; + Setting<bool> perform_vulkan_check{true, "perform_vulkan_check"}; // Miscellaneous 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) { GetWorkBufferSize(ctx); } +void HwOpus::GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx) { + OpusMultiStreamParametersEx param; + std::memcpy(¶m, ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); + + const auto sample_rate = param.sample_rate; + const auto channel_count = param.channel_count; + const auto number_streams = param.number_streams; + const auto number_stereo_streams = param.number_stereo_streams; + + LOG_DEBUG( + Audio, + "called with sample_rate={}, channel_count={}, number_streams={}, number_stereo_streams={}", + sample_rate, channel_count, number_streams, number_stereo_streams); + + ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || + sample_rate == 12000 || sample_rate == 8000, + "Invalid sample rate"); + + const u32 worker_buffer_sz = + static_cast<u32>(opus_multistream_decoder_get_size(number_streams, number_stereo_streams)); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(worker_buffer_sz); +} + void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto sample_rate = rp.Pop<u32>(); @@ -335,7 +361,7 @@ HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} { {4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"}, {5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"}, {6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"}, - {7, nullptr, "GetWorkBufferSizeForMultiStreamEx"}, + {7, &HwOpus::GetWorkBufferSizeForMultiStreamEx, "GetWorkBufferSizeForMultiStreamEx"}, }; RegisterHandlers(functions); } 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; namespace Service::Audio { +struct OpusMultiStreamParametersEx { + u32 sample_rate; + u32 channel_count; + u32 number_streams; + u32 number_stereo_streams; + u32 use_large_frame_size; + u32 padding; + std::array<u32, 64> channel_mappings; +}; + class HwOpus final : public ServiceFramework<HwOpus> { public: explicit HwOpus(Core::System& system_); @@ -21,6 +31,7 @@ private: void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx); void GetWorkBufferSize(Kernel::HLERequestContext& ctx); void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx); + void GetWorkBufferSizeForMultiStreamEx(Kernel::HLERequestContext& ctx); }; } // 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() { // Return to the start of the file if (!amiibo_file.Seek(0)) { - LOG_ERROR(Service_NFP, "Error writting to file"); + LOG_ERROR(Service_NFP, "Error writing to file"); return ErrCodes::WriteAmiiboFailed; } if (!amiibo_file.Write(encrypted_tag_data)) { - LOG_ERROR(Service_NFP, "Error writting to file"); + LOG_ERROR(Service_NFP, "Error writing to file"); return ErrCodes::WriteAmiiboFailed; } 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) proxy_packet_received = room_member->BindOnProxyPacketReceived( [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); }); } else { - LOG_ERROR(Service, "Network isn't initalized"); + LOG_ERROR(Service, "Network isn't initialized"); } } 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) { std::vector<WSAPOLLFD> host_pollfds(pollfds.size()); std::transform(pollfds.begin(), pollfds.end(), host_pollfds.begin(), [](PollFD fd) { WSAPOLLFD result; - result.fd = fd.socket->fd; + result.fd = fd.socket->GetFD(); result.events = TranslatePollEvents(fd.events); result.revents = 0; return result; @@ -430,12 +430,12 @@ std::pair<SocketBase::AcceptResult, Errno> Socket::Accept() { return {AcceptResult{}, GetAndLogLastError()}; } - AcceptResult result; - result.socket = std::make_unique<Socket>(); - result.socket->fd = new_socket; - ASSERT(addrlen == sizeof(sockaddr_in)); - result.sockaddr_in = TranslateToSockAddrIn(addr); + + AcceptResult result{ + .socket = std::make_unique<Socket>(new_socket), + .sockaddr_in = TranslateToSockAddrIn(addr), + }; return {std::move(result), Errno::SUCCESS}; } 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: std::unique_ptr<SocketBase> socket; SockAddrIn sockaddr_in; }; + + SocketBase() = default; + explicit SocketBase(SOCKET fd_) : fd{fd_} {} + virtual ~SocketBase() = default; virtual SocketBase& operator=(const SocketBase&) = delete; @@ -89,12 +93,19 @@ public: virtual void HandleProxyPacket(const ProxyPacket& packet) = 0; + [[nodiscard]] SOCKET GetFD() const { + return fd; + } + +protected: SOCKET fd = INVALID_SOCKET; }; class Socket : public SocketBase { public: Socket() = default; + explicit Socket(SOCKET fd_) : SocketBase{fd_} {} + ~Socket() override; 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() { bool RoomNetwork::Init() { if (enet_initialize() != 0) { - LOG_ERROR(Network, "Error initalizing ENet"); + LOG_ERROR(Network, "Error initializing ENet"); return false; } 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) { } void PrecolorInst(IR::Inst& phi) { - // Insert phi moves before references to avoid overwritting other phis + // Insert phi moves before references to avoid overwriting other phis const size_t num_args{phi.NumArgs()}; for (size_t i = 0; i < num_args; ++i) { 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) { } void PrecolorInst(IR::Inst& phi) { - // Insert phi moves before references to avoid overwritting other phis + // Insert phi moves before references to avoid overwriting other phis const size_t num_args{phi.NumArgs()}; for (size_t i = 0; i < num_args; ++i) { 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 @@ #include <boost/container/static_vector.hpp> +#include "common/alignment.h" #include "common/common_types.h" +#include "common/thread_worker.h" #include "video_core/textures/astc.h" class InputBitStream { @@ -1650,29 +1652,41 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth, uint32_t block_width, uint32_t block_height, std::span<uint8_t> output) { - u32 block_index = 0; - std::size_t depth_offset = 0; - for (u32 z = 0; z < depth; z++) { - for (u32 y = 0; y < height; y += block_height) { - for (u32 x = 0; x < width; x += block_width) { - const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)}; - - // Blocks can be at most 12x12 - std::array<u32, 12 * 12> uncompData; - DecompressBlock(blockPtr, block_width, block_height, uncompData); - - u32 decompWidth = std::min(block_width, width - x); - u32 decompHeight = std::min(block_height, height - y); - - const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4); - for (u32 jj = 0; jj < decompHeight; jj++) { - std::memcpy(outRow.data() + jj * width * 4, - uncompData.data() + jj * block_width, decompWidth * 4); + const u32 rows = Common::DivideUp(height, block_height); + const u32 cols = Common::DivideUp(width, block_width); + + Common::ThreadWorker workers{std::max(std::thread::hardware_concurrency(), 2U) / 2, + "yuzu:ASTCDecompress"}; + + for (u32 z = 0; z < depth; ++z) { + const u32 depth_offset = z * height * width * 4; + for (u32 y_index = 0; y_index < rows; ++y_index) { + auto decompress_stride = [data, width, height, depth, block_width, block_height, output, + rows, cols, z, depth_offset, y_index] { + const u32 y = y_index * block_height; + for (u32 x_index = 0; x_index < cols; ++x_index) { + const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index; + const u32 x = x_index * block_width; + + const std::span<const u8, 16> blockPtr{data.subspan(block_index * 16, 16)}; + + // Blocks can be at most 12x12 + std::array<u32, 12 * 12> uncompData; + DecompressBlock(blockPtr, block_width, block_height, uncompData); + + u32 decompWidth = std::min(block_width, width - x); + u32 decompHeight = std::min(block_height, height - y); + + const std::span<u8> outRow = output.subspan(depth_offset + (y * width + x) * 4); + for (u32 h = 0; h < decompHeight; ++h) { + std::memcpy(outRow.data() + h * width * 4, + uncompData.data() + h * block_width, decompWidth * 4); + } } - ++block_index; - } + }; + workers.QueueWork(std::move(decompress_stride)); } - depth_offset += height * width * 4; + workers.WaitForRequests(); } } 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() { ReadBasicSetting(Settings::values.use_auto_stub); ReadBasicSetting(Settings::values.enable_all_controllers); ReadBasicSetting(Settings::values.create_crash_dumps); + ReadBasicSetting(Settings::values.perform_vulkan_check); qt_config->endGroup(); } @@ -1162,6 +1163,7 @@ void Config::SaveDebuggingValues() { WriteBasicSetting(Settings::values.disable_macro_jit); WriteBasicSetting(Settings::values.enable_all_controllers); WriteBasicSetting(Settings::values.create_crash_dumps); + WriteBasicSetting(Settings::values.perform_vulkan_check); qt_config->endGroup(); } 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() { ui->disable_loop_safety_checks->setChecked( Settings::values.disable_shader_loop_safety_checks.GetValue()); ui->extended_logging->setChecked(Settings::values.extended_logging.GetValue()); + ui->perform_vulkan_check->setChecked(Settings::values.perform_vulkan_check.GetValue()); #ifdef YUZU_USE_QT_WEB_ENGINE ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue()); @@ -117,6 +118,7 @@ void ConfigureDebug::ApplyConfiguration() { ui->disable_loop_safety_checks->isChecked(); Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); Settings::values.extended_logging = ui->extended_logging->isChecked(); + Settings::values.perform_vulkan_check = ui->perform_vulkan_check->isChecked(); UISettings::values.disable_web_applet = ui->disable_web_applet->isChecked(); Debugger::ToggleConsole(); 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 @@ </property> </widget> </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="perform_vulkan_check"> + <property name="toolTip"> + <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> + </property> + <property name="text"> + <string>Perform Startup Vulkan Check</string> + </property> + </widget> + </item> </layout> </widget> </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() { profile_names.push_back(profile_name); } + std::stable_sort(profile_names.begin(), profile_names.end()); + return profile_names; } 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[]) { } #endif - if (StartupChecks(argv[0], &has_broken_vulkan)) { + if (StartupChecks(argv[0], &has_broken_vulkan, + Settings::values.perform_vulkan_check.GetValue())) { return 0; } 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) { return false; } -bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { +bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check) { #ifdef _WIN32 // Set the startup variable for child processes 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) { return false; } - PROCESS_INFORMATION process_info; - std::memset(&process_info, '\0', sizeof(process_info)); - - if (!SpawnChild(arg0, &process_info, 0)) { - return false; - } - - // Wait until the processs exits and get exit code from it - WaitForSingleObject(process_info.hProcess, INFINITE); - DWORD exit_code = STILL_ACTIVE; - const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); - if (err == 0) { - std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); - } - - // Vulkan is broken if the child crashed (return value is not zero) - *has_broken_vulkan = (exit_code != 0); - - if (CloseHandle(process_info.hProcess) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); - } - if (CloseHandle(process_info.hThread) == 0) { - std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); + if (perform_vulkan_check) { + // Spawn child process that performs Vulkan check + PROCESS_INFORMATION process_info; + std::memset(&process_info, '\0', sizeof(process_info)); + + if (!SpawnChild(arg0, &process_info, 0)) { + return false; + } + + // Wait until the processs exits and get exit code from it + WaitForSingleObject(process_info.hProcess, INFINITE); + DWORD exit_code = STILL_ACTIVE; + const int err = GetExitCodeProcess(process_info.hProcess, &exit_code); + if (err == 0) { + std::fprintf(stderr, "GetExitCodeProcess failed with error %d\n", GetLastError()); + } + + // Vulkan is broken if the child crashed (return value is not zero) + *has_broken_vulkan = (exit_code != 0); + + if (CloseHandle(process_info.hProcess) == 0) { + std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); + } + if (CloseHandle(process_info.hThread) == 0) { + std::fprintf(stderr, "CloseHandle failed with error %d\n", GetLastError()); + } } if (!SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, nullptr)) { @@ -98,26 +101,28 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { } #elif defined(YUZU_UNIX) - const pid_t pid = fork(); - if (pid == 0) { - CheckVulkan(); - return true; - } else if (pid == -1) { - const int err = errno; - std::fprintf(stderr, "fork failed with error %d\n", err); - return false; - } - - // Get exit code from child process - int status; - const int r_val = wait(&status); - if (r_val == -1) { - const int err = errno; - std::fprintf(stderr, "wait failed with error %d\n", err); - return false; + if (perform_vulkan_check) { + const pid_t pid = fork(); + if (pid == 0) { + CheckVulkan(); + return true; + } else if (pid == -1) { + const int err = errno; + std::fprintf(stderr, "fork failed with error %d\n", err); + return false; + } + + // Get exit code from child process + int status; + const int r_val = wait(&status); + if (r_val == -1) { + const int err = errno; + std::fprintf(stderr, "wait failed with error %d\n", err); + return false; + } + // Vulkan is broken if the child crashed (return value is not zero) + *has_broken_vulkan = (status != 0); } - // Vulkan is broken if the child crashed (return value is not zero) - *has_broken_vulkan = (status != 0); #endif return false; } 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"; void CheckVulkan(); bool CheckEnvVars(bool* is_child); -bool StartupChecks(const char* arg0, bool* has_broken_vulkan); +bool StartupChecks(const char* arg0, bool* has_broken_vulkan, bool perform_vulkan_check); #ifdef _WIN32 bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags); |