summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.ci/scripts/linux/upload.sh25
-rwxr-xr-x.ci/scripts/windows/docker.sh1
-rw-r--r--.ci/scripts/windows/upload.ps14
-rw-r--r--.ci/templates/build-msvc.yml2
-rw-r--r--.ci/yuzu-patreon-step2.yml25
-rw-r--r--.github/workflows/verify.yml2
-rw-r--r--CMakeLists.txt12
-rw-r--r--src/audio_core/audio_in_manager.cpp2
-rw-r--r--src/audio_core/audio_out_manager.cpp2
-rw-r--r--src/audio_core/renderer/audio_device.cpp34
-rw-r--r--src/audio_core/renderer/audio_device.h22
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/settings.h1
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/hle/service/audio/audout_u.cpp3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp4
-rw-r--r--src/yuzu/CMakeLists.txt10
-rw-r--r--src/yuzu/applets/qt_controller.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp6
-rw-r--r--src/yuzu/configuration/config.h4
-rw-r--r--src/yuzu/configuration/configure_debug.cpp21
-rw-r--r--src/yuzu/configuration/configure_debug.h2
-rw-r--r--src/yuzu/configuration/configure_debug.ui122
-rw-r--r--src/yuzu/configuration/configure_input.cpp2
-rw-r--r--src/yuzu/configuration/configure_per_game.cpp3
-rw-r--r--src/yuzu/configuration/input_profiles.cpp9
-rw-r--r--src/yuzu/configuration/input_profiles.h4
-rw-r--r--src/yuzu/main.cpp34
-rw-r--r--src/yuzu/main.h2
-rw-r--r--src/yuzu/mini_dump.cpp202
-rw-r--r--src/yuzu/mini_dump.h19
-rw-r--r--src/yuzu/startup_checks.cpp29
-rw-r--r--src/yuzu/startup_checks.h5
-rw-r--r--vcpkg.json4
34 files changed, 492 insertions, 139 deletions
diff --git a/.ci/scripts/linux/upload.sh b/.ci/scripts/linux/upload.sh
index 8173c5728..e0f336427 100755
--- a/.ci/scripts/linux/upload.sh
+++ b/.ci/scripts/linux/upload.sh
@@ -5,21 +5,24 @@
5 5
6. .ci/scripts/common/pre-upload.sh 6. .ci/scripts/common/pre-upload.sh
7 7
8APPIMAGE_NAME="yuzu-${GITDATE}-${GITREV}.AppImage" 8APPIMAGE_NAME="yuzu-${RELEASE_NAME}-${GITDATE}-${GITREV}.AppImage"
9REV_NAME="yuzu-linux-${GITDATE}-${GITREV}" 9BASE_NAME="yuzu-linux"
10REV_NAME="${BASE_NAME}-${GITDATE}-${GITREV}"
10ARCHIVE_NAME="${REV_NAME}.tar.xz" 11ARCHIVE_NAME="${REV_NAME}.tar.xz"
11COMPRESSION_FLAGS="-cJvf" 12COMPRESSION_FLAGS="-cJvf"
12 13
13if [ "${RELEASE_NAME}" = "mainline" ]; then 14if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then
14 DIR_NAME="${REV_NAME}" 15 DIR_NAME="${BASE_NAME}-${RELEASE_NAME}"
15else 16else
16 DIR_NAME="${REV_NAME}_${RELEASE_NAME}" 17 DIR_NAME="${REV_NAME}-${RELEASE_NAME}"
17fi 18fi
18 19
19mkdir "$DIR_NAME" 20mkdir "$DIR_NAME"
20 21
21cp build/bin/yuzu-cmd "$DIR_NAME" 22cp build/bin/yuzu-cmd "$DIR_NAME"
22cp build/bin/yuzu "$DIR_NAME" 23if [ "${RELEASE_NAME}" != "early-access" ] && [ "${RELEASE_NAME}" != "mainline" ]; then
24 cp build/bin/yuzu "$DIR_NAME"
25fi
23 26
24# Build an AppImage 27# Build an AppImage
25cd build 28cd build
@@ -32,6 +35,11 @@ if ! ./appimagetool-x86_64.AppImage --version; then
32 export APPIMAGE_EXTRACT_AND_RUN=1 35 export APPIMAGE_EXTRACT_AND_RUN=1
33fi 36fi
34 37
38# Don't let AppImageLauncher ask to integrate EA
39if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then
40 echo "X-AppImage-Integrate=false" >> AppDir/org.yuzu_emu.yuzu.desktop
41fi
42
35if [ "${RELEASE_NAME}" = "mainline" ]; then 43if [ "${RELEASE_NAME}" = "mainline" ]; then
36 # Generate update information if releasing to mainline 44 # Generate update information if releasing to mainline
37 ./appimagetool-x86_64.AppImage -u "gh-releases-zsync|yuzu-emu|yuzu-${RELEASE_NAME}|latest|yuzu-*.AppImage.zsync" AppDir "${APPIMAGE_NAME}" 45 ./appimagetool-x86_64.AppImage -u "gh-releases-zsync|yuzu-emu|yuzu-${RELEASE_NAME}|latest|yuzu-*.AppImage.zsync" AppDir "${APPIMAGE_NAME}"
@@ -46,4 +54,9 @@ if [ -f "build/${APPIMAGE_NAME}.zsync" ]; then
46 cp "build/${APPIMAGE_NAME}.zsync" "${ARTIFACTS_DIR}/" 54 cp "build/${APPIMAGE_NAME}.zsync" "${ARTIFACTS_DIR}/"
47fi 55fi
48 56
57# Copy the AppImage to the general release directory and remove git revision info
58if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then
59 cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage"
60fi
61
49. .ci/scripts/common/post-upload.sh 62. .ci/scripts/common/post-upload.sh
diff --git a/.ci/scripts/windows/docker.sh b/.ci/scripts/windows/docker.sh
index 790ba8218..6f522feed 100755
--- a/.ci/scripts/windows/docker.sh
+++ b/.ci/scripts/windows/docker.sh
@@ -21,6 +21,7 @@ cmake .. \
21 -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \ 21 -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON \
22 -DENABLE_QT_TRANSLATION=ON \ 22 -DENABLE_QT_TRANSLATION=ON \
23 -DUSE_CCACHE=ON \ 23 -DUSE_CCACHE=ON \
24 -DYUZU_CRASH_DUMPS=ON \
24 -DYUZU_USE_BUNDLED_SDL2=OFF \ 25 -DYUZU_USE_BUNDLED_SDL2=OFF \
25 -DYUZU_USE_EXTERNAL_SDL2=OFF \ 26 -DYUZU_USE_EXTERNAL_SDL2=OFF \
26 -DYUZU_TESTS=OFF \ 27 -DYUZU_TESTS=OFF \
diff --git a/.ci/scripts/windows/upload.ps1 b/.ci/scripts/windows/upload.ps1
index d463281de..21abcd752 100644
--- a/.ci/scripts/windows/upload.ps1
+++ b/.ci/scripts/windows/upload.ps1
@@ -65,8 +65,8 @@ if ("$env:GITHUB_ACTIONS" -eq "true") {
65 # None of the other GHA builds are including source, so commenting out today 65 # None of the other GHA builds are including source, so commenting out today
66 #Copy-Item $MSVC_SOURCE_TARXZ -Destination "artifacts" 66 #Copy-Item $MSVC_SOURCE_TARXZ -Destination "artifacts"
67 67
68 # Are debug symbols important? 68 # Debugging symbols
69 # cp .\build\bin\yuzu*.pdb .\pdb\ 69 cp .\build\bin\yuzu*.pdb .\artifacts\
70 70
71 # Write out a tag BUILD_TAG to environment for the Upload step 71 # Write out a tag BUILD_TAG to environment for the Upload step
72 # We're getting ${{ github.event.number }} as $env:PR_NUMBER" 72 # We're getting ${{ github.event.number }} as $env:PR_NUMBER"
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml
index a2ee71bd8..ea405e5dc 100644
--- a/.ci/templates/build-msvc.yml
+++ b/.ci/templates/build-msvc.yml
@@ -9,7 +9,7 @@ parameters:
9steps: 9steps:
10- script: choco install vulkan-sdk 10- script: choco install vulkan-sdk
11 displayName: 'Install vulkan-sdk' 11 displayName: 'Install vulkan-sdk'
12- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd .. 12- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release -DYUZU_CRASH_DUMPS=ON .. && cd ..
13 displayName: 'Configure CMake' 13 displayName: 'Configure CMake'
14- task: MSBuild@1 14- task: MSBuild@1
15 displayName: 'Build' 15 displayName: 'Build'
diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml
index 5d5b140fd..71a23ebe6 100644
--- a/.ci/yuzu-patreon-step2.yml
+++ b/.ci/yuzu-patreon-step2.yml
@@ -11,9 +11,30 @@ stages:
11- stage: build 11- stage: build
12 displayName: 'build' 12 displayName: 'build'
13 jobs: 13 jobs:
14 - job: build 14 - job: linux
15 timeoutInMinutes: 120 15 timeoutInMinutes: 120
16 displayName: 'windows-msvc' 16 displayName: 'linux'
17 pool:
18 vmImage: ubuntu-latest
19 strategy:
20 maxParallel: 10
21 matrix:
22 linux:
23 BuildSuffix: 'linux'
24 ScriptFolder: 'linux'
25 steps:
26 - template: ./templates/sync-source.yml
27 parameters:
28 artifactSource: $(parameters.artifactSource)
29 needSubmodules: 'true'
30 - template: ./templates/build-single.yml
31 parameters:
32 artifactSource: 'false'
33 cache: $(parameters.cache)
34 version: $(DisplayVersion)
35 - job: msvc
36 timeoutInMinutes: 120
37 displayName: 'windows'
17 pool: 38 pool:
18 vmImage: windows-2022 39 vmImage: windows-2022
19 steps: 40 steps:
diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml
index 733a52764..7cde8380b 100644
--- a/.github/workflows/verify.yml
+++ b/.github/workflows/verify.yml
@@ -104,7 +104,7 @@ jobs:
104 run: | 104 run: |
105 glslangValidator --version 105 glslangValidator --version
106 mkdir build 106 mkdir build
107 cmake . -B build -GNinja -DCMAKE_TOOLCHAIN_FILE="CMakeModules/MSVCCache.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DGIT_BRANCH=pr-verify 107 cmake . -B build -GNinja -DCMAKE_TOOLCHAIN_FILE="CMakeModules/MSVCCache.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DCMAKE_BUILD_TYPE=Release -DGIT_BRANCH=pr-verify -DYUZU_CRASH_DUMPS=ON
108 - name: Build 108 - name: Build
109 run: cmake --build build 109 run: cmake --build build
110 - name: Cache Summary 110 - name: Cache Summary
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2ab0ea589..20dd1383f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,6 +38,8 @@ option(YUZU_USE_BUNDLED_OPUS "Compile bundled opus" ON)
38 38
39option(YUZU_TESTS "Compile tests" ON) 39option(YUZU_TESTS "Compile tests" ON)
40 40
41CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF)
42
41option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") 43option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}")
42 44
43option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON) 45option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON)
@@ -46,6 +48,9 @@ if (YUZU_USE_BUNDLED_VCPKG)
46 if (YUZU_TESTS) 48 if (YUZU_TESTS)
47 list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests") 49 list(APPEND VCPKG_MANIFEST_FEATURES "yuzu-tests")
48 endif() 50 endif()
51 if (YUZU_CRASH_DUMPS)
52 list(APPEND VCPKG_MANIFEST_FEATURES "dbghelp")
53 endif()
49 54
50 include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake) 55 include(${CMAKE_SOURCE_DIR}/externals/vcpkg/scripts/buildsystems/vcpkg.cmake)
51elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "") 56elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "")
@@ -447,6 +452,13 @@ elseif (WIN32)
447 # PSAPI is the Process Status API 452 # PSAPI is the Process Status API
448 set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version) 453 set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
449 endif() 454 endif()
455
456 if (YUZU_CRASH_DUMPS)
457 find_library(DBGHELP_LIBRARY dbghelp)
458 if ("${DBGHELP_LIBRARY}" STREQUAL "DBGHELP_LIBRARY-NOTFOUND")
459 message(FATAL_ERROR "YUZU_CRASH_DUMPS enabled but dbghelp library not found")
460 endif()
461 endif()
450elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") 462elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$")
451 set(PLATFORM_LIBRARIES rt) 463 set(PLATFORM_LIBRARIES rt)
452endif() 464endif()
diff --git a/src/audio_core/audio_in_manager.cpp b/src/audio_core/audio_in_manager.cpp
index 4aadb7fd6..f39fb4002 100644
--- a/src/audio_core/audio_in_manager.cpp
+++ b/src/audio_core/audio_in_manager.cpp
@@ -82,7 +82,7 @@ u32 Manager::GetDeviceNames(std::vector<AudioRenderer::AudioDevice::AudioDeviceN
82 82
83 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)}; 83 auto input_devices{Sink::GetDeviceListForSink(Settings::values.sink_id.GetValue(), true)};
84 if (input_devices.size() > 1) { 84 if (input_devices.size() > 1) {
85 names.push_back(AudioRenderer::AudioDevice::AudioDeviceName("Uac")); 85 names.emplace_back("Uac");
86 return 1; 86 return 1;
87 } 87 }
88 return 0; 88 return 0;
diff --git a/src/audio_core/audio_out_manager.cpp b/src/audio_core/audio_out_manager.cpp
index 71d67de64..1766efde1 100644
--- a/src/audio_core/audio_out_manager.cpp
+++ b/src/audio_core/audio_out_manager.cpp
@@ -74,7 +74,7 @@ void Manager::BufferReleaseAndRegister() {
74 74
75u32 Manager::GetAudioOutDeviceNames( 75u32 Manager::GetAudioOutDeviceNames(
76 std::vector<AudioRenderer::AudioDevice::AudioDeviceName>& names) const { 76 std::vector<AudioRenderer::AudioDevice::AudioDeviceName>& names) const {
77 names.push_back({"DeviceOut"}); 77 names.emplace_back("DeviceOut");
78 return 1; 78 return 1;
79} 79}
80 80
diff --git a/src/audio_core/renderer/audio_device.cpp b/src/audio_core/renderer/audio_device.cpp
index d5886e55e..0d9d8f6ce 100644
--- a/src/audio_core/renderer/audio_device.cpp
+++ b/src/audio_core/renderer/audio_device.cpp
@@ -1,6 +1,9 @@
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 <array>
5#include <span>
6
4#include "audio_core/audio_core.h" 7#include "audio_core/audio_core.h"
5#include "audio_core/common/feature_support.h" 8#include "audio_core/common/feature_support.h"
6#include "audio_core/renderer/audio_device.h" 9#include "audio_core/renderer/audio_device.h"
@@ -9,14 +12,33 @@
9 12
10namespace AudioCore::AudioRenderer { 13namespace AudioCore::AudioRenderer {
11 14
15constexpr std::array usb_device_names{
16 AudioDevice::AudioDeviceName{"AudioStereoJackOutput"},
17 AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"},
18 AudioDevice::AudioDeviceName{"AudioTvOutput"},
19 AudioDevice::AudioDeviceName{"AudioUsbDeviceOutput"},
20};
21
22constexpr std::array device_names{
23 AudioDevice::AudioDeviceName{"AudioStereoJackOutput"},
24 AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"},
25 AudioDevice::AudioDeviceName{"AudioTvOutput"},
26};
27
28constexpr std::array output_device_names{
29 AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"},
30 AudioDevice::AudioDeviceName{"AudioTvOutput"},
31 AudioDevice::AudioDeviceName{"AudioExternalOutput"},
32};
33
12AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id_, 34AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id_,
13 const u32 revision) 35 const u32 revision)
14 : output_sink{system.AudioCore().GetOutputSink()}, 36 : output_sink{system.AudioCore().GetOutputSink()},
15 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {} 37 applet_resource_user_id{applet_resource_user_id_}, user_revision{revision} {}
16 38
17u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, 39u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
18 const size_t max_count) { 40 const size_t max_count) const {
19 std::span<AudioDeviceName> names{}; 41 std::span<const AudioDeviceName> names{};
20 42
21 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) { 43 if (CheckFeatureSupported(SupportTags::AudioUsbDeviceOutput, user_revision)) {
22 names = usb_device_names; 44 names = usb_device_names;
@@ -24,7 +46,7 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
24 names = device_names; 46 names = device_names;
25 } 47 }
26 48
27 u32 out_count{static_cast<u32>(std::min(max_count, names.size()))}; 49 const u32 out_count{static_cast<u32>(std::min(max_count, names.size()))};
28 for (u32 i = 0; i < out_count; i++) { 50 for (u32 i = 0; i < out_count; i++) {
29 out_buffer.push_back(names[i]); 51 out_buffer.push_back(names[i]);
30 } 52 }
@@ -32,8 +54,8 @@ u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer,
32} 54}
33 55
34u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, 56u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer,
35 const size_t max_count) { 57 const size_t max_count) const {
36 u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))}; 58 const u32 out_count{static_cast<u32>(std::min(max_count, output_device_names.size()))};
37 59
38 for (u32 i = 0; i < out_count; i++) { 60 for (u32 i = 0; i < out_count; i++) {
39 out_buffer.push_back(output_device_names[i]); 61 out_buffer.push_back(output_device_names[i]);
@@ -45,7 +67,7 @@ void AudioDevice::SetDeviceVolumes(const f32 volume) {
45 output_sink.SetDeviceVolume(volume); 67 output_sink.SetDeviceVolume(volume);
46} 68}
47 69
48f32 AudioDevice::GetDeviceVolume([[maybe_unused]] std::string_view name) { 70f32 AudioDevice::GetDeviceVolume([[maybe_unused]] std::string_view name) const {
49 return output_sink.GetDeviceVolume(); 71 return output_sink.GetDeviceVolume();
50} 72}
51 73
diff --git a/src/audio_core/renderer/audio_device.h b/src/audio_core/renderer/audio_device.h
index 1f449f261..dd6be70ee 100644
--- a/src/audio_core/renderer/audio_device.h
+++ b/src/audio_core/renderer/audio_device.h
@@ -3,7 +3,7 @@
3 3
4#pragma once 4#pragma once
5 5
6#include <span> 6#include <string_view>
7 7
8#include "audio_core/audio_render_manager.h" 8#include "audio_core/audio_render_manager.h"
9 9
@@ -23,21 +23,13 @@ namespace AudioRenderer {
23class AudioDevice { 23class AudioDevice {
24public: 24public:
25 struct AudioDeviceName { 25 struct AudioDeviceName {
26 std::array<char, 0x100> name; 26 std::array<char, 0x100> name{};
27 27
28 AudioDeviceName(const char* name_) { 28 constexpr AudioDeviceName(std::string_view name_) {
29 std::strncpy(name.data(), name_, name.size()); 29 name_.copy(name.data(), name.size() - 1);
30 } 30 }
31 }; 31 };
32 32
33 std::array<AudioDeviceName, 4> usb_device_names{"AudioStereoJackOutput",
34 "AudioBuiltInSpeakerOutput", "AudioTvOutput",
35 "AudioUsbDeviceOutput"};
36 std::array<AudioDeviceName, 3> device_names{"AudioStereoJackOutput",
37 "AudioBuiltInSpeakerOutput", "AudioTvOutput"};
38 std::array<AudioDeviceName, 3> output_device_names{"AudioBuiltInSpeakerOutput", "AudioTvOutput",
39 "AudioExternalOutput"};
40
41 explicit AudioDevice(Core::System& system, u64 applet_resource_user_id, u32 revision); 33 explicit AudioDevice(Core::System& system, u64 applet_resource_user_id, u32 revision);
42 34
43 /** 35 /**
@@ -47,7 +39,7 @@ public:
47 * @param max_count - Maximum number of devices to write (count of out_buffer). 39 * @param max_count - Maximum number of devices to write (count of out_buffer).
48 * @return Number of device names written. 40 * @return Number of device names written.
49 */ 41 */
50 u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count); 42 u32 ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
51 43
52 /** 44 /**
53 * Get a list of the available output devices. 45 * Get a list of the available output devices.
@@ -57,7 +49,7 @@ public:
57 * @param max_count - Maximum number of devices to write (count of out_buffer). 49 * @param max_count - Maximum number of devices to write (count of out_buffer).
58 * @return Number of device names written. 50 * @return Number of device names written.
59 */ 51 */
60 u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count); 52 u32 ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, size_t max_count) const;
61 53
62 /** 54 /**
63 * Set the volume of all streams in the backend sink. 55 * Set the volume of all streams in the backend sink.
@@ -73,7 +65,7 @@ public:
73 * @param name - Name of the device to check. Unused. 65 * @param name - Name of the device to check. Unused.
74 * @return Volume of the device. 66 * @return Volume of the device.
75 */ 67 */
76 f32 GetDeviceVolume(std::string_view name); 68 f32 GetDeviceVolume(std::string_view name) const;
77 69
78private: 70private:
79 /// Backend output sink for the device 71 /// Backend output sink for the device
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index b1e0ba6cc..68436a4bc 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -19,7 +19,7 @@ find_package(Git QUIET)
19 19
20add_custom_command(OUTPUT scm_rev.cpp 20add_custom_command(OUTPUT scm_rev.cpp
21 COMMAND ${CMAKE_COMMAND} 21 COMMAND ${CMAKE_COMMAND}
22 -DSRC_DIR=${CMAKE_SOURCE_DIR} 22 -DSRC_DIR=${PROJECT_SOURCE_DIR}
23 -DBUILD_REPOSITORY=${BUILD_REPOSITORY} 23 -DBUILD_REPOSITORY=${BUILD_REPOSITORY}
24 -DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE} 24 -DTITLE_BAR_FORMAT_IDLE=${TITLE_BAR_FORMAT_IDLE}
25 -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING} 25 -DTITLE_BAR_FORMAT_RUNNING=${TITLE_BAR_FORMAT_RUNNING}
@@ -31,13 +31,13 @@ add_custom_command(OUTPUT scm_rev.cpp
31 -DGIT_BRANCH=${GIT_BRANCH} 31 -DGIT_BRANCH=${GIT_BRANCH}
32 -DBUILD_FULLNAME=${BUILD_FULLNAME} 32 -DBUILD_FULLNAME=${BUILD_FULLNAME}
33 -DGIT_EXECUTABLE=${GIT_EXECUTABLE} 33 -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
34 -P ${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake 34 -P ${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake
35 DEPENDS 35 DEPENDS
36 # Check that the scm_rev files haven't changed 36 # Check that the scm_rev files haven't changed
37 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" 37 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in"
38 "${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.h" 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 39 # technically we should regenerate if the git version changed, but its not worth the effort imo
40 "${CMAKE_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake" 40 "${PROJECT_SOURCE_DIR}/CMakeModules/GenerateSCMRev.cmake"
41 VERBATIM 41 VERBATIM
42) 42)
43 43
diff --git a/src/common/settings.h b/src/common/settings.h
index 13651de57..851812f28 100644
--- a/src/common/settings.h
+++ b/src/common/settings.h
@@ -530,6 +530,7 @@ struct Values {
530 Setting<bool> use_debug_asserts{false, "use_debug_asserts"}; 530 Setting<bool> use_debug_asserts{false, "use_debug_asserts"};
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 534
534 // Miscellaneous 535 // Miscellaneous
535 Setting<std::string> log_filter{"*:Info", "log_filter"}; 536 Setting<std::string> log_filter{"*:Info", "log_filter"};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 806e7ff6c..405a2f993 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,12 +4,6 @@
4add_library(core STATIC 4add_library(core STATIC
5 arm/arm_interface.h 5 arm/arm_interface.h
6 arm/arm_interface.cpp 6 arm/arm_interface.cpp
7 arm/dynarmic/arm_dynarmic_32.cpp
8 arm/dynarmic/arm_dynarmic_32.h
9 arm/dynarmic/arm_dynarmic_64.cpp
10 arm/dynarmic/arm_dynarmic_64.h
11 arm/dynarmic/arm_dynarmic_cp15.cpp
12 arm/dynarmic/arm_dynarmic_cp15.h
13 arm/dynarmic/arm_exclusive_monitor.cpp 7 arm/dynarmic/arm_exclusive_monitor.cpp
14 arm/dynarmic/arm_exclusive_monitor.h 8 arm/dynarmic/arm_exclusive_monitor.h
15 arm/exclusive_monitor.cpp 9 arm/exclusive_monitor.cpp
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index a44dd842a..49c092301 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -246,9 +246,8 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) {
246 const auto write_count = 246 const auto write_count =
247 static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); 247 static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName));
248 std::vector<AudioDevice::AudioDeviceName> device_names{}; 248 std::vector<AudioDevice::AudioDeviceName> device_names{};
249 std::string print_names{};
250 if (write_count > 0) { 249 if (write_count > 0) {
251 device_names.push_back(AudioDevice::AudioDeviceName("DeviceOut")); 250 device_names.emplace_back("DeviceOut");
252 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); 251 LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut");
253 } else { 252 } else {
254 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); 253 LOG_DEBUG(Service_Audio, "called. Empty buffer passed in.");
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index bc69117c6..6fb07c37d 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -252,7 +252,7 @@ private:
252 252
253 std::vector<AudioDevice::AudioDeviceName> out_names{}; 253 std::vector<AudioDevice::AudioDeviceName> out_names{};
254 254
255 u32 out_count = impl->ListAudioDeviceName(out_names, in_count); 255 const u32 out_count = impl->ListAudioDeviceName(out_names, in_count);
256 256
257 std::string out{}; 257 std::string out{};
258 for (u32 i = 0; i < out_count; i++) { 258 for (u32 i = 0; i < out_count; i++) {
@@ -365,7 +365,7 @@ private:
365 365
366 std::vector<AudioDevice::AudioDeviceName> out_names{}; 366 std::vector<AudioDevice::AudioDeviceName> out_names{};
367 367
368 u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); 368 const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count);
369 369
370 std::string out{}; 370 std::string out{};
371 for (u32 i = 0; i < out_count; i++) { 371 for (u32 i = 0; i < out_count; i++) {
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 50007338f..29d506c47 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -208,6 +208,16 @@ add_executable(yuzu
208 yuzu.rc 208 yuzu.rc
209) 209)
210 210
211if (WIN32 AND YUZU_CRASH_DUMPS)
212 target_sources(yuzu PRIVATE
213 mini_dump.cpp
214 mini_dump.h
215 )
216
217 target_link_libraries(yuzu PRIVATE ${DBGHELP_LIBRARY})
218 target_compile_definitions(yuzu PRIVATE -DYUZU_DBGHELP)
219endif()
220
211file(GLOB COMPAT_LIST 221file(GLOB COMPAT_LIST
212 ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc 222 ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
213 ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json) 223 ${PROJECT_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp
index 8be311fcb..1d8072243 100644
--- a/src/yuzu/applets/qt_controller.cpp
+++ b/src/yuzu/applets/qt_controller.cpp
@@ -63,7 +63,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
63 InputCommon::InputSubsystem* input_subsystem_, Core::System& system_) 63 InputCommon::InputSubsystem* input_subsystem_, Core::System& system_)
64 : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()), 64 : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
65 parameters(std::move(parameters_)), input_subsystem{input_subsystem_}, 65 parameters(std::move(parameters_)), input_subsystem{input_subsystem_},
66 input_profiles(std::make_unique<InputProfiles>(system_)), system{system_} { 66 input_profiles(std::make_unique<InputProfiles>()), system{system_} {
67 ui->setupUi(this); 67 ui->setupUi(this);
68 68
69 player_widgets = { 69 player_widgets = {
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 8ecd87150..a4ed68422 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -15,8 +15,7 @@
15 15
16namespace FS = Common::FS; 16namespace FS = Common::FS;
17 17
18Config::Config(Core::System& system_, const std::string& config_name, ConfigType config_type) 18Config::Config(const std::string& config_name, ConfigType config_type) : type(config_type) {
19 : type(config_type), system{system_} {
20 global = config_type == ConfigType::GlobalConfig; 19 global = config_type == ConfigType::GlobalConfig;
21 20
22 Initialize(config_name); 21 Initialize(config_name);
@@ -546,6 +545,7 @@ void Config::ReadDebuggingValues() {
546 ReadBasicSetting(Settings::values.use_debug_asserts); 545 ReadBasicSetting(Settings::values.use_debug_asserts);
547 ReadBasicSetting(Settings::values.use_auto_stub); 546 ReadBasicSetting(Settings::values.use_auto_stub);
548 ReadBasicSetting(Settings::values.enable_all_controllers); 547 ReadBasicSetting(Settings::values.enable_all_controllers);
548 ReadBasicSetting(Settings::values.create_crash_dumps);
549 549
550 qt_config->endGroup(); 550 qt_config->endGroup();
551} 551}
@@ -1161,6 +1161,7 @@ void Config::SaveDebuggingValues() {
1161 WriteBasicSetting(Settings::values.use_debug_asserts); 1161 WriteBasicSetting(Settings::values.use_debug_asserts);
1162 WriteBasicSetting(Settings::values.disable_macro_jit); 1162 WriteBasicSetting(Settings::values.disable_macro_jit);
1163 WriteBasicSetting(Settings::values.enable_all_controllers); 1163 WriteBasicSetting(Settings::values.enable_all_controllers);
1164 WriteBasicSetting(Settings::values.create_crash_dumps);
1164 1165
1165 qt_config->endGroup(); 1166 qt_config->endGroup();
1166} 1167}
@@ -1547,7 +1548,6 @@ void Config::Reload() {
1547 ReadValues(); 1548 ReadValues();
1548 // To apply default value changes 1549 // To apply default value changes
1549 SaveValues(); 1550 SaveValues();
1550 system.ApplySettings();
1551} 1551}
1552 1552
1553void Config::Save() { 1553void Config::Save() {
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 486ceea94..06fa7d2d0 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -25,7 +25,7 @@ public:
25 InputProfile, 25 InputProfile,
26 }; 26 };
27 27
28 explicit Config(Core::System& system_, const std::string& config_name = "qt-config", 28 explicit Config(const std::string& config_name = "qt-config",
29 ConfigType config_type = ConfigType::GlobalConfig); 29 ConfigType config_type = ConfigType::GlobalConfig);
30 ~Config(); 30 ~Config();
31 31
@@ -194,8 +194,6 @@ private:
194 std::unique_ptr<QSettings> qt_config; 194 std::unique_ptr<QSettings> qt_config;
195 std::string qt_config_loc; 195 std::string qt_config_loc;
196 bool global; 196 bool global;
197
198 Core::System& system;
199}; 197};
200 198
201// These metatype declarations cannot be in common/settings.h because core is devoid of QT 199// These metatype declarations cannot be in common/settings.h because core is devoid of QT
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp
index 04d397750..622808e94 100644
--- a/src/yuzu/configuration/configure_debug.cpp
+++ b/src/yuzu/configuration/configure_debug.cpp
@@ -2,6 +2,7 @@
2// SPDX-License-Identifier: GPL-2.0-or-later 2// SPDX-License-Identifier: GPL-2.0-or-later
3 3
4#include <QDesktopServices> 4#include <QDesktopServices>
5#include <QMessageBox>
5#include <QUrl> 6#include <QUrl>
6#include "common/fs/path_util.h" 7#include "common/fs/path_util.h"
7#include "common/logging/backend.h" 8#include "common/logging/backend.h"
@@ -26,6 +27,16 @@ ConfigureDebug::ConfigureDebug(const Core::System& system_, QWidget* parent)
26 27
27 connect(ui->toggle_gdbstub, &QCheckBox::toggled, 28 connect(ui->toggle_gdbstub, &QCheckBox::toggled,
28 [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); }); 29 [&]() { ui->gdbport_spinbox->setEnabled(ui->toggle_gdbstub->isChecked()); });
30
31 connect(ui->create_crash_dumps, &QCheckBox::stateChanged, [&](int) {
32 if (crash_dump_warning_shown) {
33 return;
34 }
35 QMessageBox::warning(this, tr("Restart Required"),
36 tr("yuzu is required to restart in order to apply this setting."),
37 QMessageBox::Ok, QMessageBox::Ok);
38 crash_dump_warning_shown = true;
39 });
29} 40}
30 41
31ConfigureDebug::~ConfigureDebug() = default; 42ConfigureDebug::~ConfigureDebug() = default;
@@ -71,7 +82,14 @@ void ConfigureDebug::SetConfiguration() {
71 ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue()); 82 ui->disable_web_applet->setChecked(UISettings::values.disable_web_applet.GetValue());
72#else 83#else
73 ui->disable_web_applet->setEnabled(false); 84 ui->disable_web_applet->setEnabled(false);
74 ui->disable_web_applet->setText(QString::fromUtf8("Web applet not compiled")); 85 ui->disable_web_applet->setText(tr("Web applet not compiled"));
86#endif
87
88#ifdef YUZU_DBGHELP
89 ui->create_crash_dumps->setChecked(Settings::values.create_crash_dumps.GetValue());
90#else
91 ui->create_crash_dumps->setEnabled(false);
92 ui->create_crash_dumps->setText(tr("MiniDump creation not compiled"));
75#endif 93#endif
76} 94}
77 95
@@ -84,6 +102,7 @@ void ConfigureDebug::ApplyConfiguration() {
84 Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked(); 102 Settings::values.enable_fs_access_log = ui->fs_access_log->isChecked();
85 Settings::values.reporting_services = ui->reporting_services->isChecked(); 103 Settings::values.reporting_services = ui->reporting_services->isChecked();
86 Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked(); 104 Settings::values.dump_audio_commands = ui->dump_audio_commands->isChecked();
105 Settings::values.create_crash_dumps = ui->create_crash_dumps->isChecked();
87 Settings::values.quest_flag = ui->quest_flag->isChecked(); 106 Settings::values.quest_flag = ui->quest_flag->isChecked();
88 Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked(); 107 Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
89 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked(); 108 Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
diff --git a/src/yuzu/configuration/configure_debug.h b/src/yuzu/configuration/configure_debug.h
index 42d30f170..030a0b7f7 100644
--- a/src/yuzu/configuration/configure_debug.h
+++ b/src/yuzu/configuration/configure_debug.h
@@ -32,4 +32,6 @@ private:
32 std::unique_ptr<Ui::ConfigureDebug> ui; 32 std::unique_ptr<Ui::ConfigureDebug> ui;
33 33
34 const Core::System& system; 34 const Core::System& system;
35
36 bool crash_dump_warning_shown{false};
35}; 37};
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 47b8b80f1..314d47af5 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -7,60 +7,60 @@
7 </property> 7 </property>
8 <widget class="QWidget"> 8 <widget class="QWidget">
9 <layout class="QVBoxLayout" name="verticalLayout_1"> 9 <layout class="QVBoxLayout" name="verticalLayout_1">
10 <item> 10 <item>
11 <layout class="QVBoxLayout" name="verticalLayout_2"> 11 <layout class="QVBoxLayout" name="verticalLayout_2">
12 <item> 12 <item>
13 <widget class="QGroupBox" name="groupBox"> 13 <widget class="QGroupBox" name="groupBox">
14 <property name="title"> 14 <property name="title">
15 <string>Debugger</string> 15 <string>Debugger</string>
16 </property> 16 </property>
17 <layout class="QVBoxLayout" name="verticalLayout_3"> 17 <layout class="QVBoxLayout" name="verticalLayout_3">
18 <item>
19 <layout class="QHBoxLayout" name="horizontalLayout_11">
20 <item>
21 <widget class="QCheckBox" name="toggle_gdbstub">
22 <property name="text">
23 <string>Enable GDB Stub</string>
24 </property>
25 </widget>
26 </item>
27 <item>
28 <spacer name="horizontalSpacer">
29 <property name="orientation">
30 <enum>Qt::Horizontal</enum>
31 </property>
32 <property name="sizeHint" stdset="0">
33 <size>
34 <width>40</width>
35 <height>20</height>
36 </size>
37 </property>
38 </spacer>
39 </item>
40 <item>
41 <widget class="QLabel" name="label_11">
42 <property name="text">
43 <string>Port:</string>
44 </property>
45 </widget>
46 </item>
18 <item> 47 <item>
19 <layout class="QHBoxLayout" name="horizontalLayout_11"> 48 <widget class="QSpinBox" name="gdbport_spinbox">
20 <item> 49 <property name="minimum">
21 <widget class="QCheckBox" name="toggle_gdbstub"> 50 <number>1024</number>
22 <property name="text"> 51 </property>
23 <string>Enable GDB Stub</string> 52 <property name="maximum">
24 </property> 53 <number>65535</number>
25 </widget> 54 </property>
26 </item> 55 </widget>
27 <item>
28 <spacer name="horizontalSpacer">
29 <property name="orientation">
30 <enum>Qt::Horizontal</enum>
31 </property>
32 <property name="sizeHint" stdset="0">
33 <size>
34 <width>40</width>
35 <height>20</height>
36 </size>
37 </property>
38 </spacer>
39 </item>
40 <item>
41 <widget class="QLabel" name="label_11">
42 <property name="text">
43 <string>Port:</string>
44 </property>
45 </widget>
46 </item>
47 <item>
48 <widget class="QSpinBox" name="gdbport_spinbox">
49 <property name="minimum">
50 <number>1024</number>
51 </property>
52 <property name="maximum">
53 <number>65535</number>
54 </property>
55 </widget>
56 </item>
57 </layout>
58 </item> 56 </item>
59 </layout> 57 </layout>
60 </widget> 58 </item>
61 </item> 59 </layout>
62 </layout> 60 </widget>
63 </item> 61 </item>
62 </layout>
63 </item>
64 <item> 64 <item>
65 <widget class="QGroupBox" name="groupBox_2"> 65 <widget class="QGroupBox" name="groupBox_2">
66 <property name="title"> 66 <property name="title">
@@ -231,6 +231,13 @@
231 <string>Debugging</string> 231 <string>Debugging</string>
232 </property> 232 </property>
233 <layout class="QGridLayout" name="gridLayout_3"> 233 <layout class="QGridLayout" name="gridLayout_3">
234 <item row="2" column="0">
235 <widget class="QCheckBox" name="reporting_services">
236 <property name="text">
237 <string>Enable Verbose Reporting Services**</string>
238 </property>
239 </widget>
240 </item>
234 <item row="0" column="0"> 241 <item row="0" column="0">
235 <widget class="QCheckBox" name="fs_access_log"> 242 <widget class="QCheckBox" name="fs_access_log">
236 <property name="text"> 243 <property name="text">
@@ -238,20 +245,20 @@
238 </property> 245 </property>
239 </widget> 246 </widget>
240 </item> 247 </item>
241 <item row="1" column="0"> 248 <item row="0" column="1">
242 <widget class="QCheckBox" name="dump_audio_commands"> 249 <widget class="QCheckBox" name="dump_audio_commands">
243 <property name="text">
244 <string>Dump Audio Commands To Console**</string>
245 </property>
246 <property name="toolTip"> 250 <property name="toolTip">
247 <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string> 251 <string>Enable this to output the latest generated audio command list to the console. Only affects games using the audio renderer.</string>
248 </property> 252 </property>
253 <property name="text">
254 <string>Dump Audio Commands To Console**</string>
255 </property>
249 </widget> 256 </widget>
250 </item> 257 </item>
251 <item row="2" column="0"> 258 <item row="2" column="1">
252 <widget class="QCheckBox" name="reporting_services"> 259 <widget class="QCheckBox" name="create_crash_dumps">
253 <property name="text"> 260 <property name="text">
254 <string>Enable Verbose Reporting Services**</string> 261 <string>Create Minidump After Crash</string>
255 </property> 262 </property>
256 </widget> 263 </widget>
257 </item> 264 </item>
@@ -340,7 +347,6 @@
340 <tabstop>disable_loop_safety_checks</tabstop> 347 <tabstop>disable_loop_safety_checks</tabstop>
341 <tabstop>fs_access_log</tabstop> 348 <tabstop>fs_access_log</tabstop>
342 <tabstop>reporting_services</tabstop> 349 <tabstop>reporting_services</tabstop>
343 <tabstop>dump_audio_commands</tabstop>
344 <tabstop>quest_flag</tabstop> 350 <tabstop>quest_flag</tabstop>
345 <tabstop>enable_cpu_debugging</tabstop> 351 <tabstop>enable_cpu_debugging</tabstop>
346 <tabstop>use_debug_asserts</tabstop> 352 <tabstop>use_debug_asserts</tabstop>
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp
index 16fba3deb..cb55472c9 100644
--- a/src/yuzu/configuration/configure_input.cpp
+++ b/src/yuzu/configuration/configure_input.cpp
@@ -65,7 +65,7 @@ void OnDockedModeChanged(bool last_state, bool new_state, Core::System& system)
65 65
66ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) 66ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent)
67 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()), 67 : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
68 profiles(std::make_unique<InputProfiles>(system_)), system{system_} { 68 profiles(std::make_unique<InputProfiles>()), system{system_} {
69 ui->setupUi(this); 69 ui->setupUi(this);
70} 70}
71 71
diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp
index af8343b2e..c3cb8f61d 100644
--- a/src/yuzu/configuration/configure_per_game.cpp
+++ b/src/yuzu/configuration/configure_per_game.cpp
@@ -42,8 +42,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st
42 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); 42 const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name));
43 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) 43 const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename())
44 : fmt::format("{:016X}", title_id); 44 : fmt::format("{:016X}", title_id);
45 game_config = 45 game_config = std::make_unique<Config>(config_file_name, Config::ConfigType::PerGameConfig);
46 std::make_unique<Config>(system, config_file_name, Config::ConfigType::PerGameConfig);
47 46
48 addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this); 47 addons_tab = std::make_unique<ConfigurePerGameAddons>(system_, this);
49 audio_tab = std::make_unique<ConfigureAudio>(system_, this); 48 audio_tab = std::make_unique<ConfigureAudio>(system_, this);
diff --git a/src/yuzu/configuration/input_profiles.cpp b/src/yuzu/configuration/input_profiles.cpp
index 20b22e7de..807afbeb2 100644
--- a/src/yuzu/configuration/input_profiles.cpp
+++ b/src/yuzu/configuration/input_profiles.cpp
@@ -27,7 +27,7 @@ std::filesystem::path GetNameWithoutExtension(std::filesystem::path filename) {
27 27
28} // namespace 28} // namespace
29 29
30InputProfiles::InputProfiles(Core::System& system_) : system{system_} { 30InputProfiles::InputProfiles() {
31 const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input"; 31 const auto input_profile_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "input";
32 32
33 if (!FS::IsDir(input_profile_loc)) { 33 if (!FS::IsDir(input_profile_loc)) {
@@ -43,8 +43,8 @@ InputProfiles::InputProfiles(Core::System& system_) : system{system_} {
43 43
44 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) { 44 if (IsINI(filename) && IsProfileNameValid(name_without_ext)) {
45 map_profiles.insert_or_assign( 45 map_profiles.insert_or_assign(
46 name_without_ext, std::make_unique<Config>(system, name_without_ext, 46 name_without_ext,
47 Config::ConfigType::InputProfile)); 47 std::make_unique<Config>(name_without_ext, Config::ConfigType::InputProfile));
48 } 48 }
49 49
50 return true; 50 return true;
@@ -80,8 +80,7 @@ bool InputProfiles::CreateProfile(const std::string& profile_name, std::size_t p
80 } 80 }
81 81
82 map_profiles.insert_or_assign( 82 map_profiles.insert_or_assign(
83 profile_name, 83 profile_name, std::make_unique<Config>(profile_name, Config::ConfigType::InputProfile));
84 std::make_unique<Config>(system, profile_name, Config::ConfigType::InputProfile));
85 84
86 return SaveProfile(profile_name, player_index); 85 return SaveProfile(profile_name, player_index);
87} 86}
diff --git a/src/yuzu/configuration/input_profiles.h b/src/yuzu/configuration/input_profiles.h
index 65fc9e62c..2bf3e4250 100644
--- a/src/yuzu/configuration/input_profiles.h
+++ b/src/yuzu/configuration/input_profiles.h
@@ -15,7 +15,7 @@ class Config;
15class InputProfiles { 15class InputProfiles {
16 16
17public: 17public:
18 explicit InputProfiles(Core::System& system_); 18 explicit InputProfiles();
19 virtual ~InputProfiles(); 19 virtual ~InputProfiles();
20 20
21 std::vector<std::string> GetInputProfileNames(); 21 std::vector<std::string> GetInputProfileNames();
@@ -31,6 +31,4 @@ private:
31 bool ProfileExistsInMap(const std::string& profile_name) const; 31 bool ProfileExistsInMap(const std::string& profile_name) const;
32 32
33 std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles; 33 std::unordered_map<std::string, std::unique_ptr<Config>> map_profiles;
34
35 Core::System& system;
36}; 34};
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a85adc072..bda9986e1 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -138,6 +138,10 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
138#include "yuzu/uisettings.h" 138#include "yuzu/uisettings.h"
139#include "yuzu/util/clickable_label.h" 139#include "yuzu/util/clickable_label.h"
140 140
141#ifdef YUZU_DBGHELP
142#include "yuzu/mini_dump.h"
143#endif
144
141using namespace Common::Literals; 145using namespace Common::Literals;
142 146
143#ifdef USE_DISCORD_PRESENCE 147#ifdef USE_DISCORD_PRESENCE
@@ -269,10 +273,9 @@ bool GMainWindow::CheckDarkMode() {
269#endif // __linux__ 273#endif // __linux__
270} 274}
271 275
272GMainWindow::GMainWindow(bool has_broken_vulkan) 276GMainWindow::GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan)
273 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()}, 277 : ui{std::make_unique<Ui::MainWindow>()}, system{std::make_unique<Core::System>()},
274 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, 278 input_subsystem{std::make_shared<InputCommon::InputSubsystem>()}, config{std::move(config_)},
275 config{std::make_unique<Config>(*system)},
276 vfs{std::make_shared<FileSys::RealVfsFilesystem>()}, 279 vfs{std::make_shared<FileSys::RealVfsFilesystem>()},
277 provider{std::make_unique<FileSys::ManualContentProvider>()} { 280 provider{std::make_unique<FileSys::ManualContentProvider>()} {
278#ifdef __linux__ 281#ifdef __linux__
@@ -1637,7 +1640,8 @@ void GMainWindow::BootGame(const QString& filename, u64 program_id, std::size_t
1637 const auto config_file_name = title_id == 0 1640 const auto config_file_name = title_id == 0
1638 ? Common::FS::PathToUTF8String(file_path.filename()) 1641 ? Common::FS::PathToUTF8String(file_path.filename())
1639 : fmt::format("{:016X}", title_id); 1642 : fmt::format("{:016X}", title_id);
1640 Config per_game_config(*system, config_file_name, Config::ConfigType::PerGameConfig); 1643 Config per_game_config(config_file_name, Config::ConfigType::PerGameConfig);
1644 system->ApplySettings();
1641 } 1645 }
1642 1646
1643 // Save configurations 1647 // Save configurations
@@ -2981,7 +2985,7 @@ void GMainWindow::OnConfigure() {
2981 2985
2982 Settings::values.disabled_addons.clear(); 2986 Settings::values.disabled_addons.clear();
2983 2987
2984 config = std::make_unique<Config>(*system); 2988 config = std::make_unique<Config>();
2985 UISettings::values.reset_to_defaults = false; 2989 UISettings::values.reset_to_defaults = false;
2986 2990
2987 UISettings::values.game_dirs = std::move(old_game_dirs); 2991 UISettings::values.game_dirs = std::move(old_game_dirs);
@@ -3042,6 +3046,7 @@ void GMainWindow::OnConfigure() {
3042 3046
3043 UpdateStatusButtons(); 3047 UpdateStatusButtons();
3044 controller_dialog->refreshConfiguration(); 3048 controller_dialog->refreshConfiguration();
3049 system->ApplySettings();
3045} 3050}
3046 3051
3047void GMainWindow::OnConfigureTas() { 3052void GMainWindow::OnConfigureTas() {
@@ -4082,7 +4087,24 @@ void GMainWindow::changeEvent(QEvent* event) {
4082#endif 4087#endif
4083 4088
4084int main(int argc, char* argv[]) { 4089int main(int argc, char* argv[]) {
4090 std::unique_ptr<Config> config = std::make_unique<Config>();
4085 bool has_broken_vulkan = false; 4091 bool has_broken_vulkan = false;
4092 bool is_child = false;
4093 if (CheckEnvVars(&is_child)) {
4094 return 0;
4095 }
4096
4097#ifdef YUZU_DBGHELP
4098 PROCESS_INFORMATION pi;
4099 if (!is_child && Settings::values.create_crash_dumps.GetValue() &&
4100 MiniDump::SpawnDebuggee(argv[0], pi)) {
4101 // Delete the config object so that it doesn't save when the program exits
4102 config.reset(nullptr);
4103 MiniDump::DebugDebuggee(pi);
4104 return 0;
4105 }
4106#endif
4107
4086 if (StartupChecks(argv[0], &has_broken_vulkan)) { 4108 if (StartupChecks(argv[0], &has_broken_vulkan)) {
4087 return 0; 4109 return 0;
4088 } 4110 }
@@ -4135,7 +4157,7 @@ int main(int argc, char* argv[]) {
4135 // generating shaders 4157 // generating shaders
4136 setlocale(LC_ALL, "C"); 4158 setlocale(LC_ALL, "C");
4137 4159
4138 GMainWindow main_window{has_broken_vulkan}; 4160 GMainWindow main_window{std::move(config), has_broken_vulkan};
4139 // After settings have been loaded by GMainWindow, apply the filter 4161 // After settings have been loaded by GMainWindow, apply the filter
4140 main_window.show(); 4162 main_window.show();
4141 4163
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1ae2b93d9..716aef063 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -120,7 +120,7 @@ class GMainWindow : public QMainWindow {
120public: 120public:
121 void filterBarSetChecked(bool state); 121 void filterBarSetChecked(bool state);
122 void UpdateUITheme(); 122 void UpdateUITheme();
123 explicit GMainWindow(bool has_broken_vulkan); 123 explicit GMainWindow(std::unique_ptr<Config> config_, bool has_broken_vulkan);
124 ~GMainWindow() override; 124 ~GMainWindow() override;
125 125
126 bool DropAction(QDropEvent* event); 126 bool DropAction(QDropEvent* event);
diff --git a/src/yuzu/mini_dump.cpp b/src/yuzu/mini_dump.cpp
new file mode 100644
index 000000000..a34dc6a9c
--- /dev/null
+++ b/src/yuzu/mini_dump.cpp
@@ -0,0 +1,202 @@
1// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <cstdio>
5#include <cstring>
6#include <ctime>
7#include <filesystem>
8#include <fmt/format.h>
9#include <windows.h>
10#include "yuzu/mini_dump.h"
11#include "yuzu/startup_checks.h"
12
13// dbghelp.h must be included after windows.h
14#include <dbghelp.h>
15
16namespace MiniDump {
17
18void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
19 EXCEPTION_POINTERS* pep) {
20 char file_name[255];
21 const std::time_t the_time = std::time(nullptr);
22 std::strftime(file_name, 255, "yuzu-crash-%Y%m%d%H%M%S.dmp", std::localtime(&the_time));
23
24 // Open the file
25 HANDLE file_handle = CreateFileA(file_name, GENERIC_READ | GENERIC_WRITE, 0, nullptr,
26 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
27
28 if (file_handle == nullptr || file_handle == INVALID_HANDLE_VALUE) {
29 fmt::print(stderr, "CreateFileA failed. Error: {}", GetLastError());
30 return;
31 }
32
33 // Create the minidump
34 const MINIDUMP_TYPE dump_type = MiniDumpNormal;
35
36 const bool write_dump_status = MiniDumpWriteDump(process_handle, process_id, file_handle,
37 dump_type, (pep != 0) ? info : 0, 0, 0);
38
39 if (write_dump_status) {
40 fmt::print(stderr, "MiniDump created: {}", file_name);
41 } else {
42 fmt::print(stderr, "MiniDumpWriteDump failed. Error: {}", GetLastError());
43 }
44
45 // Close the file
46 CloseHandle(file_handle);
47}
48
49void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi) {
50 EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
51
52 HANDLE thread_handle = OpenThread(THREAD_GET_CONTEXT, false, deb_ev.dwThreadId);
53 if (thread_handle == nullptr) {
54 fmt::print(stderr, "OpenThread failed ({})", GetLastError());
55 return;
56 }
57
58 // Get child process context
59 CONTEXT context = {};
60 context.ContextFlags = CONTEXT_ALL;
61 if (!GetThreadContext(thread_handle, &context)) {
62 fmt::print(stderr, "GetThreadContext failed ({})", GetLastError());
63 return;
64 }
65
66 // Create exception pointers for minidump
67 EXCEPTION_POINTERS ep;
68 ep.ExceptionRecord = &record;
69 ep.ContextRecord = &context;
70
71 MINIDUMP_EXCEPTION_INFORMATION info;
72 info.ThreadId = deb_ev.dwThreadId;
73 info.ExceptionPointers = &ep;
74 info.ClientPointers = false;
75
76 CreateMiniDump(pi.hProcess, pi.dwProcessId, &info, &ep);
77
78 if (CloseHandle(thread_handle) == 0) {
79 fmt::print(stderr, "error: CloseHandle(thread_handle) failed ({})", GetLastError());
80 }
81}
82
83bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi) {
84 std::memset(&pi, 0, sizeof(pi));
85
86 // Don't debug if we are already being debugged
87 if (IsDebuggerPresent()) {
88 return false;
89 }
90
91 if (!SpawnChild(arg0, &pi, 0)) {
92 fmt::print(stderr, "warning: continuing without crash dumps");
93 return false;
94 }
95
96 const bool can_debug = DebugActiveProcess(pi.dwProcessId);
97 if (!can_debug) {
98 fmt::print(stderr,
99 "warning: DebugActiveProcess failed ({}), continuing without crash dumps",
100 GetLastError());
101 return false;
102 }
103
104 return true;
105}
106
107static const char* ExceptionName(DWORD exception) {
108 switch (exception) {
109 case EXCEPTION_ACCESS_VIOLATION:
110 return "EXCEPTION_ACCESS_VIOLATION";
111 case EXCEPTION_DATATYPE_MISALIGNMENT:
112 return "EXCEPTION_DATATYPE_MISALIGNMENT";
113 case EXCEPTION_BREAKPOINT:
114 return "EXCEPTION_BREAKPOINT";
115 case EXCEPTION_SINGLE_STEP:
116 return "EXCEPTION_SINGLE_STEP";
117 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
118 return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
119 case EXCEPTION_FLT_DENORMAL_OPERAND:
120 return "EXCEPTION_FLT_DENORMAL_OPERAND";
121 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
122 return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
123 case EXCEPTION_FLT_INEXACT_RESULT:
124 return "EXCEPTION_FLT_INEXACT_RESULT";
125 case EXCEPTION_FLT_INVALID_OPERATION:
126 return "EXCEPTION_FLT_INVALID_OPERATION";
127 case EXCEPTION_FLT_OVERFLOW:
128 return "EXCEPTION_FLT_OVERFLOW";
129 case EXCEPTION_FLT_STACK_CHECK:
130 return "EXCEPTION_FLT_STACK_CHECK";
131 case EXCEPTION_FLT_UNDERFLOW:
132 return "EXCEPTION_FLT_UNDERFLOW";
133 case EXCEPTION_INT_DIVIDE_BY_ZERO:
134 return "EXCEPTION_INT_DIVIDE_BY_ZERO";
135 case EXCEPTION_INT_OVERFLOW:
136 return "EXCEPTION_INT_OVERFLOW";
137 case EXCEPTION_PRIV_INSTRUCTION:
138 return "EXCEPTION_PRIV_INSTRUCTION";
139 case EXCEPTION_IN_PAGE_ERROR:
140 return "EXCEPTION_IN_PAGE_ERROR";
141 case EXCEPTION_ILLEGAL_INSTRUCTION:
142 return "EXCEPTION_ILLEGAL_INSTRUCTION";
143 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
144 return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
145 case EXCEPTION_STACK_OVERFLOW:
146 return "EXCEPTION_STACK_OVERFLOW";
147 case EXCEPTION_INVALID_DISPOSITION:
148 return "EXCEPTION_INVALID_DISPOSITION";
149 case EXCEPTION_GUARD_PAGE:
150 return "EXCEPTION_GUARD_PAGE";
151 case EXCEPTION_INVALID_HANDLE:
152 return "EXCEPTION_INVALID_HANDLE";
153 default:
154 return "unknown exception type";
155 }
156}
157
158void DebugDebuggee(PROCESS_INFORMATION& pi) {
159 DEBUG_EVENT deb_ev = {};
160
161 while (deb_ev.dwDebugEventCode != EXIT_PROCESS_DEBUG_EVENT) {
162 const bool wait_success = WaitForDebugEvent(&deb_ev, INFINITE);
163 if (!wait_success) {
164 fmt::print(stderr, "error: WaitForDebugEvent failed ({})", GetLastError());
165 return;
166 }
167
168 switch (deb_ev.dwDebugEventCode) {
169 case OUTPUT_DEBUG_STRING_EVENT:
170 case CREATE_PROCESS_DEBUG_EVENT:
171 case CREATE_THREAD_DEBUG_EVENT:
172 case EXIT_PROCESS_DEBUG_EVENT:
173 case EXIT_THREAD_DEBUG_EVENT:
174 case LOAD_DLL_DEBUG_EVENT:
175 case RIP_EVENT:
176 case UNLOAD_DLL_DEBUG_EVENT:
177 // Continue on all other debug events
178 ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_CONTINUE);
179 break;
180 case EXCEPTION_DEBUG_EVENT:
181 EXCEPTION_RECORD& record = deb_ev.u.Exception.ExceptionRecord;
182
183 // We want to generate a crash dump if we are seeing the same exception again.
184 if (!deb_ev.u.Exception.dwFirstChance) {
185 fmt::print(stderr, "Creating MiniDump on ExceptionCode: 0x{:08x} {}\n",
186 record.ExceptionCode, ExceptionName(record.ExceptionCode));
187 DumpFromDebugEvent(deb_ev, pi);
188 }
189
190 // Continue without handling the exception.
191 // Lets the debuggee use its own exception handler.
192 // - If one does not exist, we will see the exception once more where we make a minidump
193 // for. Then when it reaches here again, yuzu will probably crash.
194 // - DBG_CONTINUE on an exception that the debuggee does not handle can set us up for an
195 // infinite loop of exceptions.
196 ContinueDebugEvent(deb_ev.dwProcessId, deb_ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED);
197 break;
198 }
199 }
200}
201
202} // namespace MiniDump
diff --git a/src/yuzu/mini_dump.h b/src/yuzu/mini_dump.h
new file mode 100644
index 000000000..d6b6cca84
--- /dev/null
+++ b/src/yuzu/mini_dump.h
@@ -0,0 +1,19 @@
1// SPDX-FileCopyrightText: 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <windows.h>
7
8#include <dbghelp.h>
9
10namespace MiniDump {
11
12void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info,
13 EXCEPTION_POINTERS* pep);
14
15void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi);
16bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi);
17void DebugDebuggee(PROCESS_INFORMATION& pi);
18
19} // namespace MiniDump
diff --git a/src/yuzu/startup_checks.cpp b/src/yuzu/startup_checks.cpp
index 8421280bf..29b87da05 100644
--- a/src/yuzu/startup_checks.cpp
+++ b/src/yuzu/startup_checks.cpp
@@ -31,19 +31,36 @@ void CheckVulkan() {
31 } 31 }
32} 32}
33 33
34bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { 34bool CheckEnvVars(bool* is_child) {
35#ifdef _WIN32 35#ifdef _WIN32
36 // Check environment variable to see if we are the child 36 // Check environment variable to see if we are the child
37 char variable_contents[8]; 37 char variable_contents[8];
38 const DWORD startup_check_var = 38 const DWORD startup_check_var =
39 GetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, variable_contents, 8); 39 GetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, variable_contents, 8);
40 if (startup_check_var > 0 && std::strncmp(variable_contents, "ON", 8) == 0) { 40 if (startup_check_var > 0 && std::strncmp(variable_contents, ENV_VAR_ENABLED_TEXT, 8) == 0) {
41 CheckVulkan(); 41 CheckVulkan();
42 return true; 42 return true;
43 } 43 }
44 44
45 // Don't perform startup checks if we are a child process
46 char is_child_s[8];
47 const DWORD is_child_len = GetEnvironmentVariableA(IS_CHILD_ENV_VAR, is_child_s, 8);
48 if (is_child_len > 0 && std::strncmp(is_child_s, ENV_VAR_ENABLED_TEXT, 8) == 0) {
49 *is_child = true;
50 return false;
51 } else if (!SetEnvironmentVariableA(IS_CHILD_ENV_VAR, ENV_VAR_ENABLED_TEXT)) {
52 std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
53 IS_CHILD_ENV_VAR, GetLastError());
54 return true;
55 }
56#endif
57 return false;
58}
59
60bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
61#ifdef _WIN32
45 // Set the startup variable for child processes 62 // Set the startup variable for child processes
46 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, "ON"); 63 const bool env_var_set = SetEnvironmentVariableA(STARTUP_CHECK_ENV_VAR, ENV_VAR_ENABLED_TEXT);
47 if (!env_var_set) { 64 if (!env_var_set) {
48 std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n", 65 std::fprintf(stderr, "SetEnvironmentVariableA failed to set %s with error %d\n",
49 STARTUP_CHECK_ENV_VAR, GetLastError()); 66 STARTUP_CHECK_ENV_VAR, GetLastError());
@@ -53,7 +70,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
53 PROCESS_INFORMATION process_info; 70 PROCESS_INFORMATION process_info;
54 std::memset(&process_info, '\0', sizeof(process_info)); 71 std::memset(&process_info, '\0', sizeof(process_info));
55 72
56 if (!SpawnChild(arg0, &process_info)) { 73 if (!SpawnChild(arg0, &process_info, 0)) {
57 return false; 74 return false;
58 } 75 }
59 76
@@ -106,7 +123,7 @@ bool StartupChecks(const char* arg0, bool* has_broken_vulkan) {
106} 123}
107 124
108#ifdef _WIN32 125#ifdef _WIN32
109bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) { 126bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags) {
110 STARTUPINFOA startup_info; 127 STARTUPINFOA startup_info;
111 128
112 std::memset(&startup_info, '\0', sizeof(startup_info)); 129 std::memset(&startup_info, '\0', sizeof(startup_info));
@@ -120,7 +137,7 @@ bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) {
120 nullptr, // lpProcessAttributes 137 nullptr, // lpProcessAttributes
121 nullptr, // lpThreadAttributes 138 nullptr, // lpThreadAttributes
122 false, // bInheritHandles 139 false, // bInheritHandles
123 0, // dwCreationFlags 140 flags, // dwCreationFlags
124 nullptr, // lpEnvironment 141 nullptr, // lpEnvironment
125 nullptr, // lpCurrentDirectory 142 nullptr, // lpCurrentDirectory
126 &startup_info, // lpStartupInfo 143 &startup_info, // lpStartupInfo
diff --git a/src/yuzu/startup_checks.h b/src/yuzu/startup_checks.h
index 096dd54a8..f2fc2d9d4 100644
--- a/src/yuzu/startup_checks.h
+++ b/src/yuzu/startup_checks.h
@@ -7,11 +7,14 @@
7#include <windows.h> 7#include <windows.h>
8#endif 8#endif
9 9
10constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD";
10constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS"; 11constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS";
12constexpr char ENV_VAR_ENABLED_TEXT[] = "ON";
11 13
12void CheckVulkan(); 14void CheckVulkan();
15bool CheckEnvVars(bool* is_child);
13bool StartupChecks(const char* arg0, bool* has_broken_vulkan); 16bool StartupChecks(const char* arg0, bool* has_broken_vulkan);
14 17
15#ifdef _WIN32 18#ifdef _WIN32
16bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi); 19bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi, int flags);
17#endif 20#endif
diff --git a/vcpkg.json b/vcpkg.json
index c4413e22a..3c92510d6 100644
--- a/vcpkg.json
+++ b/vcpkg.json
@@ -31,6 +31,10 @@
31 "yuzu-tests": { 31 "yuzu-tests": {
32 "description": "Compile tests", 32 "description": "Compile tests",
33 "dependencies": [ "catch2" ] 33 "dependencies": [ "catch2" ]
34 },
35 "dbghelp": {
36 "description": "Compile Windows crash dump (Minidump) support",
37 "dependencies": [ "dbghelp" ]
34 } 38 }
35 }, 39 },
36 "overrides": [ 40 "overrides": [