diff options
50 files changed, 523 insertions, 170 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 | ||
| 8 | APPIMAGE_NAME="yuzu-${GITDATE}-${GITREV}.AppImage" | 8 | APPIMAGE_NAME="yuzu-${RELEASE_NAME}-${GITDATE}-${GITREV}.AppImage" |
| 9 | REV_NAME="yuzu-linux-${GITDATE}-${GITREV}" | 9 | BASE_NAME="yuzu-linux" |
| 10 | REV_NAME="${BASE_NAME}-${GITDATE}-${GITREV}" | ||
| 10 | ARCHIVE_NAME="${REV_NAME}.tar.xz" | 11 | ARCHIVE_NAME="${REV_NAME}.tar.xz" |
| 11 | COMPRESSION_FLAGS="-cJvf" | 12 | COMPRESSION_FLAGS="-cJvf" |
| 12 | 13 | ||
| 13 | if [ "${RELEASE_NAME}" = "mainline" ]; then | 14 | if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then |
| 14 | DIR_NAME="${REV_NAME}" | 15 | DIR_NAME="${BASE_NAME}-${RELEASE_NAME}" |
| 15 | else | 16 | else |
| 16 | DIR_NAME="${REV_NAME}_${RELEASE_NAME}" | 17 | DIR_NAME="${REV_NAME}-${RELEASE_NAME}" |
| 17 | fi | 18 | fi |
| 18 | 19 | ||
| 19 | mkdir "$DIR_NAME" | 20 | mkdir "$DIR_NAME" |
| 20 | 21 | ||
| 21 | cp build/bin/yuzu-cmd "$DIR_NAME" | 22 | cp build/bin/yuzu-cmd "$DIR_NAME" |
| 22 | cp build/bin/yuzu "$DIR_NAME" | 23 | if [ "${RELEASE_NAME}" != "early-access" ] && [ "${RELEASE_NAME}" != "mainline" ]; then |
| 24 | cp build/bin/yuzu "$DIR_NAME" | ||
| 25 | fi | ||
| 23 | 26 | ||
| 24 | # Build an AppImage | 27 | # Build an AppImage |
| 25 | cd build | 28 | cd 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 |
| 33 | fi | 36 | fi |
| 34 | 37 | ||
| 38 | # Don't let AppImageLauncher ask to integrate EA | ||
| 39 | if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then | ||
| 40 | echo "X-AppImage-Integrate=false" >> AppDir/org.yuzu_emu.yuzu.desktop | ||
| 41 | fi | ||
| 42 | |||
| 35 | if [ "${RELEASE_NAME}" = "mainline" ]; then | 43 | if [ "${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}/" |
| 47 | fi | 55 | fi |
| 48 | 56 | ||
| 57 | # Copy the AppImage to the general release directory and remove git revision info | ||
| 58 | if [ "${RELEASE_NAME}" = "mainline" ] || [ "${RELEASE_NAME}" = "early-access" ]; then | ||
| 59 | cp "build/${APPIMAGE_NAME}" "${DIR_NAME}/yuzu-${RELEASE_NAME}.AppImage" | ||
| 60 | fi | ||
| 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: | |||
| 9 | steps: | 9 | steps: |
| 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/.gitignore b/.gitignore index cdf37962a..a5f7248c7 100644 --- a/.gitignore +++ b/.gitignore | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # SPDX-License-Identifier: GPL-2.0-or-later | 2 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | # Build directory | 4 | # Build directory |
| 5 | [Bb]uild/ | 5 | [Bb]uild*/ |
| 6 | doc-build/ | 6 | doc-build/ |
| 7 | 7 | ||
| 8 | # Generated source files | 8 | # Generated source files |
diff --git a/.reuse/dep5 b/.reuse/dep5 index 5ba017494..9a90f9eb6 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 | |||
| @@ -52,6 +52,8 @@ Files: dist/qt_themes/colorful/icons/16x16/lock.png | |||
| 52 | dist/qt_themes/colorful/icons/48x48/chip.png | 52 | dist/qt_themes/colorful/icons/48x48/chip.png |
| 53 | dist/qt_themes/colorful/icons/48x48/folder.png | 53 | dist/qt_themes/colorful/icons/48x48/folder.png |
| 54 | dist/qt_themes/colorful_dark/icons/16x16/lock.png | 54 | dist/qt_themes/colorful_dark/icons/16x16/lock.png |
| 55 | dist/qt_themes/colorful/icons/16x16/info.png | ||
| 56 | dist/qt_themes/colorful/icons/16x16/sync.png | ||
| 55 | Copyright: Icons8 | 57 | Copyright: Icons8 |
| 56 | License: MIT | 58 | License: MIT |
| 57 | Comment: https://github.com/icons8/flat-color-icons | 59 | Comment: https://github.com/icons8/flat-color-icons |
| @@ -68,8 +70,8 @@ Copyright: Ionic (http://ionic.io/) | |||
| 68 | License: MIT | 70 | License: MIT |
| 69 | 71 | ||
| 70 | Files: dist/qt_themes/colorful/icons/48x48/star.png | 72 | Files: dist/qt_themes/colorful/icons/48x48/star.png |
| 71 | dist/qt_themes/default/icons/16x16/checked.png | 73 | dist/qt_themes/colorful/icons/16x16/checked.png |
| 72 | dist/qt_themes/default/icons/16x16/failed.png | 74 | dist/qt_themes/colorful/icons/16x16/failed.png |
| 73 | Copyright: SVG Repo | 75 | Copyright: SVG Repo |
| 74 | License: CC0-1.0 | 76 | License: CC0-1.0 |
| 75 | 77 | ||
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 | ||
| 39 | option(YUZU_TESTS "Compile tests" ON) | 39 | option(YUZU_TESTS "Compile tests" ON) |
| 40 | 40 | ||
| 41 | CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile Windows crash dump (Minidump) support" OFF "WIN32" OFF) | ||
| 42 | |||
| 41 | option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") | 43 | option(YUZU_USE_BUNDLED_VCPKG "Use vcpkg for yuzu dependencies" "${MSVC}") |
| 42 | 44 | ||
| 43 | option(YUZU_CHECK_SUBMODULES "Check if submodules are present" ON) | 45 | option(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) |
| 51 | elseif(NOT "$ENV{VCPKG_TOOLCHAIN_FILE}" STREQUAL "") | 56 | elseif(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() | ||
| 450 | elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") | 462 | elseif (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU|SunOS)$") |
| 451 | set(PLATFORM_LIBRARIES rt) | 463 | set(PLATFORM_LIBRARIES rt) |
| 452 | endif() | 464 | endif() |
diff --git a/dist/qt_themes/default/icons/16x16/checked.png b/dist/qt_themes/colorful/icons/16x16/checked.png index b9e64e9e0..b9e64e9e0 100644 --- a/dist/qt_themes/default/icons/16x16/checked.png +++ b/dist/qt_themes/colorful/icons/16x16/checked.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/default/icons/16x16/failed.png b/dist/qt_themes/colorful/icons/16x16/failed.png index a1872835d..a1872835d 100644 --- a/dist/qt_themes/default/icons/16x16/failed.png +++ b/dist/qt_themes/colorful/icons/16x16/failed.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/colorful/icons/16x16/info.png b/dist/qt_themes/colorful/icons/16x16/info.png new file mode 100644 index 000000000..8b9330f4c --- /dev/null +++ b/dist/qt_themes/colorful/icons/16x16/info.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/colorful/icons/16x16/sync.png b/dist/qt_themes/colorful/icons/16x16/sync.png new file mode 100644 index 000000000..0d57789c3 --- /dev/null +++ b/dist/qt_themes/colorful/icons/16x16/sync.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/default/icons/16x16/view-refresh.png b/dist/qt_themes/colorful/icons/16x16/view-refresh.png index 69f9474ac..69f9474ac 100644 --- a/dist/qt_themes/default/icons/16x16/view-refresh.png +++ b/dist/qt_themes/colorful/icons/16x16/view-refresh.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/default/icons/48x48/no_avatar.png b/dist/qt_themes/colorful/icons/48x48/no_avatar.png index 76f812349..76f812349 100644 --- a/dist/qt_themes/default/icons/48x48/no_avatar.png +++ b/dist/qt_themes/colorful/icons/48x48/no_avatar.png | |||
| Binary files differ | |||
diff --git a/dist/qt_themes/colorful/icons/index.theme b/dist/qt_themes/colorful/icons/index.theme index b452aca16..6eb3c6949 100644 --- a/dist/qt_themes/colorful/icons/index.theme +++ b/dist/qt_themes/colorful/icons/index.theme | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | [Icon Theme] | 1 | [Icon Theme] |
| 2 | Name=colorful | 2 | Name=colorful |
| 3 | Comment=Colorful theme | 3 | Comment=Colorful theme |
| 4 | Inherits=default | ||
| 5 | Directories=16x16,48x48,256x256 | 4 | Directories=16x16,48x48,256x256 |
| 6 | 5 | ||
| 7 | [16x16] | 6 | [16x16] |
diff --git a/dist/qt_themes/colorful/style.qrc b/dist/qt_themes/colorful/style.qrc index 507e0e58b..82cd367be 100644 --- a/dist/qt_themes/colorful/style.qrc +++ b/dist/qt_themes/colorful/style.qrc | |||
| @@ -6,14 +6,20 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||
| 6 | <RCC> | 6 | <RCC> |
| 7 | <qresource prefix="icons/colorful"> | 7 | <qresource prefix="icons/colorful"> |
| 8 | <file alias="index.theme">icons/index.theme</file> | 8 | <file alias="index.theme">icons/index.theme</file> |
| 9 | <file alias="16x16/checked.png">icons/16x16/checked.png</file> | ||
| 9 | <file alias="16x16/connected.png">icons/16x16/connected.png</file> | 10 | <file alias="16x16/connected.png">icons/16x16/connected.png</file> |
| 10 | <file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file> | 11 | <file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file> |
| 11 | <file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file> | 12 | <file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file> |
| 13 | <file alias="16x16/failed.png">icons/16x16/failed.png</file> | ||
| 14 | <file alias="16x16/info.png">icons/16x16/info.png</file> | ||
| 12 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> | 15 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> |
| 16 | <file alias="16x16/sync.png">icons/16x16/sync.png</file> | ||
| 17 | <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file> | ||
| 13 | <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> | 18 | <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> |
| 14 | <file alias="48x48/chip.png">icons/48x48/chip.png</file> | 19 | <file alias="48x48/chip.png">icons/48x48/chip.png</file> |
| 15 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 20 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 16 | <file alias="48x48/list-add.png">icons/48x48/list-add.png</file> | 21 | <file alias="48x48/list-add.png">icons/48x48/list-add.png</file> |
| 22 | <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> | ||
| 17 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 23 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 18 | <file alias="48x48/star.png">icons/48x48/star.png</file> | 24 | <file alias="48x48/star.png">icons/48x48/star.png</file> |
| 19 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 25 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
diff --git a/dist/qt_themes/colorful_dark/style.qrc b/dist/qt_themes/colorful_dark/style.qrc index 9853fd438..72451ef02 100644 --- a/dist/qt_themes/colorful_dark/style.qrc +++ b/dist/qt_themes/colorful_dark/style.qrc | |||
| @@ -5,19 +5,9 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||
| 5 | 5 | ||
| 6 | <RCC> | 6 | <RCC> |
| 7 | <qresource prefix="icons/colorful_dark"> | 7 | <qresource prefix="icons/colorful_dark"> |
| 8 | <file alias="16x16/connected.png">../colorful/icons/16x16/connected.png</file> | ||
| 9 | <file alias="16x16/connected_notification.png">../colorful/icons/16x16/connected_notification.png</file> | ||
| 10 | <file alias="16x16/disconnected.png">../colorful/icons/16x16/disconnected.png</file> | ||
| 11 | <file alias="index.theme">icons/index.theme</file> | 8 | <file alias="index.theme">icons/index.theme</file> |
| 12 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> | 9 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> |
| 13 | <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file> | 10 | <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file> |
| 14 | <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file> | ||
| 15 | <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file> | ||
| 16 | <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file> | ||
| 17 | <file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file> | ||
| 18 | <file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file> | ||
| 19 | <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file> | ||
| 20 | <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file> | ||
| 21 | </qresource> | 11 | </qresource> |
| 22 | 12 | ||
| 23 | <qresource prefix="qss_icons"> | 13 | <qresource prefix="qss_icons"> |
diff --git a/dist/qt_themes/default/default.qrc b/dist/qt_themes/default/default.qrc index a07f2a9c1..2e01a3434 100644 --- a/dist/qt_themes/default/default.qrc +++ b/dist/qt_themes/default/default.qrc | |||
| @@ -5,23 +5,20 @@ SPDX-License-Identifier: GPL-2.0-or-later | |||
| 5 | 5 | ||
| 6 | <RCC> | 6 | <RCC> |
| 7 | <qresource prefix="icons/default"> | 7 | <qresource prefix="icons/default"> |
| 8 | <!-- "colorful" is now the default theme, add new icons there --> | ||
| 8 | <file alias="index.theme">icons/index.theme</file> | 9 | <file alias="index.theme">icons/index.theme</file> |
| 9 | <file alias="16x16/checked.png">icons/16x16/checked.png</file> | ||
| 10 | <file alias="16x16/failed.png">icons/16x16/failed.png</file> | ||
| 11 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> | ||
| 12 | <file alias="16x16/connected.png">icons/16x16/connected.png</file> | 10 | <file alias="16x16/connected.png">icons/16x16/connected.png</file> |
| 13 | <file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file> | ||
| 14 | <file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file> | 11 | <file alias="16x16/connected_notification.png">icons/16x16/connected_notification.png</file> |
| 15 | <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file> | 12 | <file alias="16x16/disconnected.png">icons/16x16/disconnected.png</file> |
| 13 | <file alias="16x16/lock.png">icons/16x16/lock.png</file> | ||
| 16 | <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> | 14 | <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file> |
| 17 | <file alias="48x48/chip.png">icons/48x48/chip.png</file> | 15 | <file alias="48x48/chip.png">icons/48x48/chip.png</file> |
| 18 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> | 16 | <file alias="48x48/folder.png">icons/48x48/folder.png</file> |
| 19 | <file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file> | ||
| 20 | <file alias="48x48/list-add.png">icons/48x48/list-add.png</file> | 17 | <file alias="48x48/list-add.png">icons/48x48/list-add.png</file> |
| 21 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> | 18 | <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file> |
| 22 | <file alias="48x48/star.png">icons/48x48/star.png</file> | 19 | <file alias="48x48/star.png">icons/48x48/star.png</file> |
| 23 | <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file> | ||
| 24 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> | 20 | <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file> |
| 21 | <file alias="256x256/yuzu.png">icons/256x256/yuzu.png</file> | ||
| 25 | </qresource> | 22 | </qresource> |
| 26 | <qresource prefix="default"> | 23 | <qresource prefix="default"> |
| 27 | <file>style.qss</file> | 24 | <file>style.qss</file> |
diff --git a/dist/qt_themes/default/icons/index.theme b/dist/qt_themes/default/icons/index.theme index 1edbe6408..21b35e3e3 100644 --- a/dist/qt_themes/default/icons/index.theme +++ b/dist/qt_themes/default/icons/index.theme | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | [Icon Theme] | 1 | [Icon Theme] |
| 2 | Name=default | 2 | Name=default |
| 3 | Comment=default theme | 3 | Comment=default theme |
| 4 | Inherits=colorful | ||
| 4 | Directories=16x16,48x48,256x256 | 5 | Directories=16x16,48x48,256x256 |
| 5 | 6 | ||
| 6 | [16x16] | 7 | [16x16] |
| @@ -10,4 +11,4 @@ Size=16 | |||
| 10 | Size=48 | 11 | Size=48 |
| 11 | 12 | ||
| 12 | [256x256] | 13 | [256x256] |
| 13 | Size=256 \ No newline at end of file | 14 | Size=256 |
diff --git a/dist/qt_themes/qdarkstyle/icons/index.theme b/dist/qt_themes/qdarkstyle/icons/index.theme index d1e12f3ef..502717617 100644 --- a/dist/qt_themes/qdarkstyle/icons/index.theme +++ b/dist/qt_themes/qdarkstyle/icons/index.theme | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | [Icon Theme] | 1 | [Icon Theme] |
| 2 | Name=qdarkstyle | 2 | Name=qdarkstyle |
| 3 | Comment=dark theme | 3 | Comment=dark theme |
| 4 | Inherits=default | 4 | Inherits=colorful |
| 5 | Directories=16x16,48x48,256x256 | 5 | Directories=16x16,48x48,256x256 |
| 6 | 6 | ||
| 7 | [16x16] | 7 | [16x16] |
| @@ -11,4 +11,4 @@ Size=16 | |||
| 11 | Size=48 | 11 | Size=48 |
| 12 | 12 | ||
| 13 | [256x256] | 13 | [256x256] |
| 14 | Size=256 \ No newline at end of file | 14 | Size=256 |
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme index 447a6c8be..20f9f6d63 100644 --- a/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme +++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | [Icon Theme] | 1 | [Icon Theme] |
| 2 | Name=qdarkstyle_midnight_blue | 2 | Name=qdarkstyle_midnight_blue |
| 3 | Comment=dark theme | 3 | Comment=dark theme |
| 4 | Inherits=default | 4 | Inherits=colorful |
| 5 | Directories=16x16,48x48,256x256 | 5 | Directories=16x16,48x48,256x256 |
| 6 | 6 | ||
| 7 | [16x16] | 7 | [16x16] |
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 | ||
| 75 | u32 Manager::GetAudioOutDeviceNames( | 75 | u32 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 b2d34e45a..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 | ||
| 10 | namespace AudioCore::AudioRenderer { | 13 | namespace AudioCore::AudioRenderer { |
| 11 | 14 | ||
| 15 | constexpr std::array usb_device_names{ | ||
| 16 | AudioDevice::AudioDeviceName{"AudioStereoJackOutput"}, | ||
| 17 | AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"}, | ||
| 18 | AudioDevice::AudioDeviceName{"AudioTvOutput"}, | ||
| 19 | AudioDevice::AudioDeviceName{"AudioUsbDeviceOutput"}, | ||
| 20 | }; | ||
| 21 | |||
| 22 | constexpr std::array device_names{ | ||
| 23 | AudioDevice::AudioDeviceName{"AudioStereoJackOutput"}, | ||
| 24 | AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"}, | ||
| 25 | AudioDevice::AudioDeviceName{"AudioTvOutput"}, | ||
| 26 | }; | ||
| 27 | |||
| 28 | constexpr std::array output_device_names{ | ||
| 29 | AudioDevice::AudioDeviceName{"AudioBuiltInSpeakerOutput"}, | ||
| 30 | AudioDevice::AudioDeviceName{"AudioTvOutput"}, | ||
| 31 | AudioDevice::AudioDeviceName{"AudioExternalOutput"}, | ||
| 32 | }; | ||
| 33 | |||
| 12 | AudioDevice::AudioDevice(Core::System& system, const u64 applet_resource_user_id_, | 34 | AudioDevice::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 | ||
| 17 | u32 AudioDevice::ListAudioDeviceName(std::vector<AudioDeviceName>& out_buffer, | 39 | u32 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 | ||
| 34 | u32 AudioDevice::ListAudioOutputDeviceName(std::vector<AudioDeviceName>& out_buffer, | 56 | u32 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]); |
diff --git a/src/audio_core/renderer/audio_device.h b/src/audio_core/renderer/audio_device.h index 16522ad2f..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 { | |||
| 23 | class AudioDevice { | 23 | class AudioDevice { |
| 24 | public: | 24 | public: |
| 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. |
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 | ||
| 20 | add_custom_command(OUTPUT scm_rev.cpp | 20 | add_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 @@ | |||
| 4 | add_library(core STATIC | 4 | add_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 | ||
| 211 | if (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) | ||
| 219 | endif() | ||
| 220 | |||
| 211 | file(GLOB COMPAT_LIST | 221 | file(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 | ||
| 16 | namespace FS = Common::FS; | 16 | namespace FS = Common::FS; |
| 17 | 17 | ||
| 18 | Config::Config(Core::System& system_, const std::string& config_name, ConfigType config_type) | 18 | Config::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 | ||
| 1553 | void Config::Save() { | 1553 | void 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 | ||
| 31 | ConfigureDebug::~ConfigureDebug() = default; | 42 | ConfigureDebug::~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 | ||
| 66 | ConfigureInput::ConfigureInput(Core::System& system_, QWidget* parent) | 66 | ConfigureInput::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/configure_web.cpp b/src/yuzu/configuration/configure_web.cpp index d668c992b..ab526e4ca 100644 --- a/src/yuzu/configuration/configure_web.cpp +++ b/src/yuzu/configuration/configure_web.cpp | |||
| @@ -128,20 +128,25 @@ void ConfigureWeb::RefreshTelemetryID() { | |||
| 128 | void ConfigureWeb::OnLoginChanged() { | 128 | void ConfigureWeb::OnLoginChanged() { |
| 129 | if (ui->edit_token->text().isEmpty()) { | 129 | if (ui->edit_token->text().isEmpty()) { |
| 130 | user_verified = true; | 130 | user_verified = true; |
| 131 | 131 | // Empty = no icon | |
| 132 | const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16); | 132 | ui->label_token_verified->setPixmap(QPixmap()); |
| 133 | ui->label_token_verified->setPixmap(pixmap); | 133 | ui->label_token_verified->setToolTip(QString()); |
| 134 | } else { | 134 | } else { |
| 135 | user_verified = false; | 135 | user_verified = false; |
| 136 | 136 | ||
| 137 | const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16); | 137 | // Show an info icon if it's been changed, clearer than showing failure |
| 138 | const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("info")).pixmap(16); | ||
| 138 | ui->label_token_verified->setPixmap(pixmap); | 139 | ui->label_token_verified->setPixmap(pixmap); |
| 140 | ui->label_token_verified->setToolTip( | ||
| 141 | tr("Unverified, please click Verify before saving configuration", "Tooltip")); | ||
| 139 | } | 142 | } |
| 140 | } | 143 | } |
| 141 | 144 | ||
| 142 | void ConfigureWeb::VerifyLogin() { | 145 | void ConfigureWeb::VerifyLogin() { |
| 143 | ui->button_verify_login->setDisabled(true); | 146 | ui->button_verify_login->setDisabled(true); |
| 144 | ui->button_verify_login->setText(tr("Verifying...")); | 147 | ui->button_verify_login->setText(tr("Verifying...")); |
| 148 | ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("sync")).pixmap(16)); | ||
| 149 | ui->label_token_verified->setToolTip(tr("Verifying...")); | ||
| 145 | verify_watcher.setFuture(QtConcurrent::run( | 150 | verify_watcher.setFuture(QtConcurrent::run( |
| 146 | [username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), | 151 | [username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), |
| 147 | token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] { | 152 | token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] { |
| @@ -155,13 +160,13 @@ void ConfigureWeb::OnLoginVerified() { | |||
| 155 | if (verify_watcher.result()) { | 160 | if (verify_watcher.result()) { |
| 156 | user_verified = true; | 161 | user_verified = true; |
| 157 | 162 | ||
| 158 | const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16); | 163 | ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("checked")).pixmap(16)); |
| 159 | ui->label_token_verified->setPixmap(pixmap); | 164 | ui->label_token_verified->setToolTip(tr("Verified", "Tooltip")); |
| 160 | ui->username->setText( | 165 | ui->username->setText( |
| 161 | QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString()))); | 166 | QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString()))); |
| 162 | } else { | 167 | } else { |
| 163 | const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16); | 168 | ui->label_token_verified->setPixmap(QIcon::fromTheme(QStringLiteral("failed")).pixmap(16)); |
| 164 | ui->label_token_verified->setPixmap(pixmap); | 169 | ui->label_token_verified->setToolTip(tr("Verification failed", "Tooltip")); |
| 165 | ui->username->setText(tr("Unspecified")); | 170 | ui->username->setText(tr("Unspecified")); |
| 166 | QMessageBox::critical(this, tr("Verification failed"), | 171 | QMessageBox::critical(this, tr("Verification failed"), |
| 167 | tr("Verification failed. Check that you have entered your token " | 172 | tr("Verification failed. Check that you have entered your token " |
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 | ||
| 30 | InputProfiles::InputProfiles(Core::System& system_) : system{system_} { | 30 | InputProfiles::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; | |||
| 15 | class InputProfiles { | 15 | class InputProfiles { |
| 16 | 16 | ||
| 17 | public: | 17 | public: |
| 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 | |||
| 141 | using namespace Common::Literals; | 145 | using 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 | ||
| 272 | GMainWindow::GMainWindow(bool has_broken_vulkan) | 276 | GMainWindow::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 | ||
| 3047 | void GMainWindow::OnConfigureTas() { | 3052 | void GMainWindow::OnConfigureTas() { |
| @@ -4082,7 +4087,24 @@ void GMainWindow::changeEvent(QEvent* event) { | |||
| 4082 | #endif | 4087 | #endif |
| 4083 | 4088 | ||
| 4084 | int main(int argc, char* argv[]) { | 4089 | int 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 { | |||
| 120 | public: | 120 | public: |
| 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 | |||
| 16 | namespace MiniDump { | ||
| 17 | |||
| 18 | void 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 | |||
| 49 | void 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 | |||
| 83 | bool 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 | |||
| 107 | static 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 | |||
| 158 | void 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 | |||
| 10 | namespace MiniDump { | ||
| 11 | |||
| 12 | void CreateMiniDump(HANDLE process_handle, DWORD process_id, MINIDUMP_EXCEPTION_INFORMATION* info, | ||
| 13 | EXCEPTION_POINTERS* pep); | ||
| 14 | |||
| 15 | void DumpFromDebugEvent(DEBUG_EVENT& deb_ev, PROCESS_INFORMATION& pi); | ||
| 16 | bool SpawnDebuggee(const char* arg0, PROCESS_INFORMATION& pi); | ||
| 17 | void 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 | ||
| 34 | bool StartupChecks(const char* arg0, bool* has_broken_vulkan) { | 34 | bool 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 | |||
| 60 | bool 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 |
| 109 | bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi) { | 126 | bool 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 | ||
| 10 | constexpr char IS_CHILD_ENV_VAR[] = "YUZU_IS_CHILD"; | ||
| 10 | constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS"; | 11 | constexpr char STARTUP_CHECK_ENV_VAR[] = "YUZU_DO_STARTUP_CHECKS"; |
| 12 | constexpr char ENV_VAR_ENABLED_TEXT[] = "ON"; | ||
| 11 | 13 | ||
| 12 | void CheckVulkan(); | 14 | void CheckVulkan(); |
| 15 | bool CheckEnvVars(bool* is_child); | ||
| 13 | bool StartupChecks(const char* arg0, bool* has_broken_vulkan); | 16 | bool StartupChecks(const char* arg0, bool* has_broken_vulkan); |
| 14 | 17 | ||
| 15 | #ifdef _WIN32 | 18 | #ifdef _WIN32 |
| 16 | bool SpawnChild(const char* arg0, PROCESS_INFORMATION* pi); | 19 | bool 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": [ |