mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Merge branch 'main' into android
This commit is contained in:
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: "Install system dependencies"
|
||||
run: |
|
||||
sudo apt update -qq
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libudev-dev nasm ninja-build
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libudev-dev nasm ninja-build libbluetooth-dev
|
||||
|
||||
- name: "Setup cmake"
|
||||
uses: jwlawson/actions-setup-cmake@v2
|
||||
@@ -96,7 +96,7 @@ jobs:
|
||||
- name: "Install system dependencies"
|
||||
run: |
|
||||
sudo apt update -qq
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build appstream
|
||||
sudo apt install -y clang-15 cmake freeglut3-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev nasm ninja-build appstream libbluetooth-dev
|
||||
|
||||
- name: "Build AppImage"
|
||||
run: |
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
name: Deploy experimental release
|
||||
name: Deploy release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
next_version_minor: ${{ needs.calculate-version.outputs.next_version_minor }}
|
||||
android_build_type: ${{ inputs.android_build_type }}
|
||||
deploy:
|
||||
name: Deploy experimental release
|
||||
name: Deploy release
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [call-release-build, calculate-version]
|
||||
steps:
|
||||
@@ -1,85 +0,0 @@
|
||||
name: Create new release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
PlaceholderInput:
|
||||
description: PlaceholderInput
|
||||
required: false
|
||||
jobs:
|
||||
call-release-build:
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
deploymode: release
|
||||
deploy:
|
||||
name: Deploy release
|
||||
runs-on: ubuntu-20.04
|
||||
needs: call-release-build
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
path: cemu-bin-linux-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
path: cemu-appimage-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
path: cemu-bin-windows-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: cemu-bin-macos-x64
|
||||
path: cemu-bin-macos-x64
|
||||
|
||||
- name: Initialize
|
||||
run: |
|
||||
mkdir upload
|
||||
sudo apt update -qq
|
||||
sudo apt install -y zip
|
||||
|
||||
- name: Get Cemu release version
|
||||
run: |
|
||||
gcc -o getversion .github/getversion.cpp
|
||||
echo "Cemu CI version: $(./getversion)"
|
||||
echo "CEMU_FOLDER_NAME=Cemu_$(./getversion)" >> $GITHUB_ENV
|
||||
echo "CEMU_VERSION=$(./getversion)" >> $GITHUB_ENV
|
||||
|
||||
- name: Create release from windows-bin
|
||||
run: |
|
||||
ls ./
|
||||
ls ./bin/
|
||||
cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }}
|
||||
mv cemu-bin-windows-x64/Cemu.exe ./${{ env.CEMU_FOLDER_NAME }}/Cemu.exe
|
||||
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-windows-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
||||
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
||||
|
||||
- name: Create appimage
|
||||
run: |
|
||||
VERSION=${{ env.CEMU_VERSION }}
|
||||
echo "Cemu Version is $VERSION"
|
||||
ls cemu-appimage-x64
|
||||
mv cemu-appimage-x64/Cemu-*-x86_64.AppImage upload/Cemu-$VERSION-x86_64.AppImage
|
||||
|
||||
- name: Create release from ubuntu-bin
|
||||
run: |
|
||||
ls ./
|
||||
ls ./bin/
|
||||
cp -R ./bin ./${{ env.CEMU_FOLDER_NAME }}
|
||||
mv cemu-bin-linux-x64/Cemu ./${{ env.CEMU_FOLDER_NAME }}/Cemu
|
||||
zip -9 -r upload/cemu-${{ env.CEMU_VERSION }}-ubuntu-20.04-x64.zip ${{ env.CEMU_FOLDER_NAME }}
|
||||
rm -r ./${{ env.CEMU_FOLDER_NAME }}
|
||||
|
||||
- name: Create release from macos-bin
|
||||
run: cp cemu-bin-macos-x64/Cemu.dmg upload/cemu-${{ env.CEMU_VERSION }}-macos-12-x64.dmg
|
||||
|
||||
- name: Create release
|
||||
run: |
|
||||
wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.15.0/ghr_v0.15.0_linux_amd64.tar.gz
|
||||
tar xvzf ghr.tar.gz; rm ghr.tar.gz
|
||||
ghr_v0.15.0_linux_amd64/ghr -t ${{ secrets.GITHUB_TOKEN }} -n "Cemu ${{ env.CEMU_VERSION }}" -b "Changelog:" v${{ env.CEMU_VERSION }} ./upload
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
-o cemu.pot
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: POT file
|
||||
path: ./cemu.pot
|
||||
|
||||
@@ -47,10 +47,10 @@ To compile Cemu, a recent enough compiler and STL with C++20 support is required
|
||||
### Dependencies
|
||||
|
||||
#### For Arch and derivatives:
|
||||
`sudo pacman -S --needed base-devel clang cmake freeglut git glm gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip`
|
||||
`sudo pacman -S --needed base-devel bluez-libs clang cmake freeglut git glm gtk3 libgcrypt libpulse libsecret linux-headers llvm nasm ninja systemd unzip zip`
|
||||
|
||||
#### For Debian, Ubuntu and derivatives:
|
||||
`sudo apt install -y cmake curl clang-15 freeglut3-dev git libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libtool nasm ninja-build`
|
||||
`sudo apt install -y cmake curl clang-15 freeglut3-dev git libbluetooth-dev libgcrypt20-dev libglm-dev libgtk-3-dev libpulse-dev libsecret-1-dev libsystemd-dev libtool nasm ninja-build`
|
||||
|
||||
You may also need to install `libusb-1.0-0-dev` as a workaround for an issue with the vcpkg hidapi package.
|
||||
|
||||
@@ -58,7 +58,7 @@ At Step 3 in [Build Cemu using cmake and clang](#build-cemu-using-cmake-and-clan
|
||||
`cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_C_COMPILER=/usr/bin/clang-15 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-15 -G Ninja -DCMAKE_MAKE_PROGRAM=/usr/bin/ninja`
|
||||
|
||||
#### For Fedora and derivatives:
|
||||
`sudo dnf install clang cmake cubeb-devel freeglut-devel git glm-devel gtk3-devel kernel-headers libgcrypt-devel libsecret-devel libtool libusb1-devel llvm nasm ninja-build perl-core systemd-devel zlib-devel zlib-static`
|
||||
`sudo dnf install bluez-libs-devel clang cmake cubeb-devel freeglut-devel git glm-devel gtk3-devel kernel-headers libgcrypt-devel libsecret-devel libtool libusb1-devel llvm nasm ninja-build perl-core systemd-devel wayland-protocols-devel zlib-devel zlib-static`
|
||||
|
||||
### Build Cemu
|
||||
|
||||
@@ -121,6 +121,9 @@ This section refers to running `cmake -S...` (truncated).
|
||||
* Compiling failed during rebuild after `git pull` with an error that mentions RPATH
|
||||
* Add the following and try running the command again:
|
||||
* `-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON`
|
||||
* Environment variable `VCPKG_FORCE_SYSTEM_BINARIES` must be set.
|
||||
* Execute the folowing and then try running the command again:
|
||||
* `export VCPKG_FORCE_SYSTEM_BINARIES=1`
|
||||
* If you are getting a random error, read the [package-name-and-platform]-out.log and [package-name-and-platform]-err.log for the actual reason to see if you might be lacking the headers from a dependency.
|
||||
|
||||
|
||||
@@ -200,3 +203,41 @@ Instructions:
|
||||
|
||||
If CMake complains about Cemu already being compiled or another similar error, try deleting the `CMakeCache.txt` file inside the `build` folder and retry building.
|
||||
|
||||
## CMake configure flags
|
||||
Some flags can be passed during CMake configure to customise which features are enabled on build.
|
||||
|
||||
Example usage: `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DENABLE_SDL=ON -DENABLE_VULKAN=OFF`
|
||||
|
||||
### All platforms
|
||||
| Flag | | Description | Default | Note |
|
||||
|--------------------|:--|-----------------------------------------------------------------------------|---------|--------------------|
|
||||
| ALLOW_PORTABLE | | Allow Cemu to use the `portable` directory to store configs and data | ON | |
|
||||
| CEMU_CXX_FLAGS | | Flags passed straight to the compiler, e.g. `-march=native`, `-Wall`, `/W3` | "" | |
|
||||
| ENABLE_CUBEB | | Enable cubeb audio backend | ON | |
|
||||
| ENABLE_DISCORD_RPC | | Enable Discord Rich presence support | ON | |
|
||||
| ENABLE_OPENGL | | Enable OpenGL graphics backend | ON | Currently required |
|
||||
| ENABLE_HIDAPI | | Enable HIDAPI (used for Wiimote controller API) | ON | |
|
||||
| ENABLE_SDL | | Enable SDLController controller API | ON | Currently required |
|
||||
| ENABLE_VCPKG | | Use VCPKG package manager to obtain dependencies | ON | |
|
||||
| ENABLE_VULKAN | | Enable the Vulkan graphics backend | ON | |
|
||||
| ENABLE_WXWIDGETS | | Enable wxWidgets UI | ON | Currently required |
|
||||
|
||||
### Windows
|
||||
| Flag | Description | Default | Note |
|
||||
|--------------------|-----------------------------------|---------|--------------------|
|
||||
| ENABLE_DIRECTAUDIO | Enable DirectAudio audio backend | ON | Currently required |
|
||||
| ENABLE_DIRECTINPUT | Enable DirectInput controller API | ON | Currently required |
|
||||
| ENABLE_XAUDIO | Enable XAudio audio backend | ON | |
|
||||
| ENABLE_XINPUT | Enable XInput controller API | ON | |
|
||||
|
||||
### Linux
|
||||
| Flag | Description | Default |
|
||||
|-----------------------|----------------------------------------------------|---------|
|
||||
| ENABLE_BLUEZ | Build with Bluez (used for Wiimote controller API) | ON |
|
||||
| ENABLE_FERAL_GAMEMODE | Enable Feral Interactive GameMode support | ON |
|
||||
| ENABLE_WAYLAND | Enable Wayland support | ON |
|
||||
|
||||
### macOS
|
||||
| Flag | Description | Default |
|
||||
|--------------|------------------------------------------------|---------|
|
||||
| MACOS_BUNDLE | MacOS executable will be an application bundle | OFF |
|
||||
|
||||
+8
-17
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.21.1)
|
||||
|
||||
option(ENABLE_VCPKG "Enable the vcpkg package manager" ON)
|
||||
option(MACOS_BUNDLE "The executable when built on macOS will be created as an application bundle" OFF)
|
||||
option(ALLOW_PORTABLE "Allow Cemu to be run in portable mode" ON)
|
||||
|
||||
# used by CI script to set version:
|
||||
set(EMULATOR_VERSION_MAJOR "0" CACHE STRING "")
|
||||
@@ -107,6 +108,7 @@ endif()
|
||||
if (UNIX AND NOT APPLE)
|
||||
option(ENABLE_WAYLAND "Build with Wayland support" ON)
|
||||
option(ENABLE_FERAL_GAMEMODE "Enables Feral Interactive GameMode Support" ON)
|
||||
option(ENABLE_BLUEZ "Build with Bluez support" ON)
|
||||
endif()
|
||||
|
||||
option(ENABLE_OPENGL "Enables the OpenGL backend" ON)
|
||||
@@ -131,23 +133,6 @@ if (WIN32)
|
||||
endif()
|
||||
option(ENABLE_CUBEB "Enabled cubeb backend" ON)
|
||||
|
||||
# usb hid backends
|
||||
if (WIN32)
|
||||
option(ENABLE_NSYSHID_WINDOWS_HID "Enables the native Windows HID backend for nsyshid" ON)
|
||||
endif ()
|
||||
# libusb and windows hid backends shouldn't be active at the same time; otherwise we'd see all devices twice!
|
||||
if (NOT ENABLE_NSYSHID_WINDOWS_HID)
|
||||
option(ENABLE_NSYSHID_LIBUSB "Enables the libusb backend for nsyshid" ON)
|
||||
else ()
|
||||
set(ENABLE_NSYSHID_LIBUSB OFF CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
if (ENABLE_NSYSHID_WINDOWS_HID)
|
||||
add_compile_definitions(NSYSHID_ENABLE_BACKEND_WINDOWS_HID)
|
||||
endif ()
|
||||
if (ENABLE_NSYSHID_LIBUSB)
|
||||
add_compile_definitions(NSYSHID_ENABLE_BACKEND_LIBUSB)
|
||||
endif ()
|
||||
|
||||
option(ENABLE_WXWIDGETS "Build with wxWidgets UI (Currently required)" ON)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG true)
|
||||
@@ -194,6 +179,12 @@ if (UNIX AND NOT APPLE AND NOT ANDROID)
|
||||
endif()
|
||||
find_package(GTK3 REQUIRED)
|
||||
|
||||
if(ENABLE_BLUEZ)
|
||||
find_package(bluez REQUIRED)
|
||||
set(ENABLE_WIIMOTE ON)
|
||||
add_compile_definitions(HAS_BLUEZ)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
if (ENABLE_VULKAN)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
# SPDX-FileCopyrightText: 2022 Andrea Pappacoda <andrea@pappacoda.it>
|
||||
# SPDX-License-Identifier: ISC
|
||||
|
||||
find_package(bluez CONFIG)
|
||||
if (NOT bluez_FOUND)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(bluez IMPORTED_TARGET GLOBAL bluez-1.0 bluez)
|
||||
if (bluez_FOUND)
|
||||
add_library(bluez::bluez ALIAS PkgConfig::bluez)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
find_package_handle_standard_args(bluez
|
||||
REQUIRED_VARS
|
||||
bluez_LINK_LIBRARIES
|
||||
bluez_FOUND
|
||||
VERSION_VAR bluez_VERSION
|
||||
)
|
||||
+10
-4
@@ -94,8 +94,8 @@ if (MACOS_BUNDLE)
|
||||
set(MACOSX_BUNDLE_ICON_FILE "cemu.icns")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "info.cemu.Cemu")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "Cemu")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${CMAKE_PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION ${CMAKE_PROJECT_VERSION})
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2024 Cemu Project")
|
||||
|
||||
set(MACOSX_BUNDLE_CATEGORY "public.app-category.games")
|
||||
@@ -113,12 +113,18 @@ if (MACOS_BUNDLE)
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory "${CMAKE_SOURCE_DIR}/bin/${folder}" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/SharedSupport/${folder}")
|
||||
endforeach(folder)
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/debug/lib/libusb-1.0.0.dylib")
|
||||
else()
|
||||
set(LIBUSB_PATH "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib")
|
||||
endif()
|
||||
|
||||
add_custom_command (TARGET CemuBin POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "/usr/local/lib/libMoltenVK.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libMoltenVK.dylib"
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_BINARY_DIR}/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib"
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${LIBUSB_PATH}" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/Frameworks/libusb-1.0.0.dylib"
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_SOURCE_DIR}/src/resource/update.sh" "${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/update.sh"
|
||||
COMMAND bash -c "install_name_tool -add_rpath @executable_path/../Frameworks ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}"
|
||||
COMMAND bash -c "install_name_tool -change /Users/runner/work/Cemu/Cemu/build/vcpkg_installed/x64-osx/lib/libusb-1.0.0.dylib @executable_path/../Frameworks/libusb-1.0.0.dylib ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}")
|
||||
COMMAND bash -c "install_name_tool -change ${LIBUSB_PATH} @executable_path/../Frameworks/libusb-1.0.0.dylib ${CMAKE_SOURCE_DIR}/bin/${OUTPUT_NAME}.app/Contents/MacOS/${OUTPUT_NAME}")
|
||||
endif()
|
||||
|
||||
set_target_properties(CemuBin PROPERTIES
|
||||
|
||||
+19
-12
@@ -461,8 +461,8 @@ add_library(CemuCafe
|
||||
OS/libs/nsyshid/BackendEmulated.h
|
||||
OS/libs/nsyshid/BackendLibusb.cpp
|
||||
OS/libs/nsyshid/BackendLibusb.h
|
||||
OS/libs/nsyshid/BackendWindowsHID.cpp
|
||||
OS/libs/nsyshid/BackendWindowsHID.h
|
||||
OS/libs/nsyshid/Dimensions.cpp
|
||||
OS/libs/nsyshid/Dimensions.h
|
||||
OS/libs/nsyshid/Infinity.cpp
|
||||
OS/libs/nsyshid/Infinity.h
|
||||
OS/libs/nsyshid/Skylander.cpp
|
||||
@@ -557,6 +557,12 @@ set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CON
|
||||
|
||||
target_include_directories(CemuCafe PUBLIC "../")
|
||||
|
||||
if (glslang_VERSION VERSION_LESS "15.0.0")
|
||||
set(glslang_target "glslang::SPIRV")
|
||||
else()
|
||||
set(glslang_target "glslang")
|
||||
endif()
|
||||
|
||||
target_link_libraries(CemuCafe PRIVATE
|
||||
CemuAsm
|
||||
CemuAudio
|
||||
@@ -571,7 +577,7 @@ target_link_libraries(CemuCafe PRIVATE
|
||||
Boost::nowide
|
||||
CURL::libcurl
|
||||
fmt::fmt
|
||||
glslang::SPIRV
|
||||
${glslang_target}
|
||||
ih264d
|
||||
OpenSSL::Crypto
|
||||
OpenSSL::SSL
|
||||
@@ -587,15 +593,16 @@ if (ENABLE_WAYLAND)
|
||||
target_link_libraries(CemuCafe PUBLIC Wayland::Client)
|
||||
endif()
|
||||
|
||||
if (ENABLE_NSYSHID_LIBUSB)
|
||||
if (ENABLE_VCPKG)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)
|
||||
target_link_libraries(CemuCafe PRIVATE PkgConfig::libusb)
|
||||
else ()
|
||||
find_package(libusb MODULE REQUIRED)
|
||||
target_link_libraries(CemuCafe PRIVATE libusb::libusb)
|
||||
endif ()
|
||||
if (ENABLE_VCPKG)
|
||||
if(WIN32)
|
||||
set(PKG_CONFIG_EXECUTABLE "${VCPKG_INSTALLED_DIR}/x64-windows/tools/pkgconf/pkgconf.exe")
|
||||
endif()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0)
|
||||
target_link_libraries(CemuCafe PRIVATE PkgConfig::libusb)
|
||||
else ()
|
||||
find_package(libusb MODULE REQUIRED)
|
||||
target_link_libraries(CemuCafe PRIVATE libusb::libusb)
|
||||
endif ()
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(aarch64)|(AARCH64)")
|
||||
|
||||
+23
-22
@@ -8,6 +8,7 @@
|
||||
#include "audio/IAudioAPI.h"
|
||||
#include "audio/IAudioInputAPI.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "config/LaunchSettings.h"
|
||||
#include "Cafe/TitleList/GameInfo.h"
|
||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||
#include "util/helpers/SystemException.h"
|
||||
@@ -656,40 +657,40 @@ namespace CafeSystem
|
||||
fsc_unmount("/cemuBossStorage/", FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
STATUS_CODE LoadAndMountForegroundTitle(TitleId titleId)
|
||||
PREPARE_STATUS_CODE LoadAndMountForegroundTitle(TitleId titleId)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting title {:016x}", (uint64)titleId);
|
||||
sGameInfo_ForegroundTitle = CafeTitleList::GetGameInfo(titleId);
|
||||
if (!sGameInfo_ForegroundTitle.IsValid())
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting failed: Game meta information is either missing, inaccessible or not valid (missing or invalid .xml files in code and meta folder)");
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
}
|
||||
// check base
|
||||
TitleInfo& titleBase = sGameInfo_ForegroundTitle.GetBase();
|
||||
if (!titleBase.IsValid())
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
if(!titleBase.ParseXmlInfo())
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
cemuLog_log(LogType::Force, "Base: {}", titleBase.GetPrintPath());
|
||||
// mount base
|
||||
if (!titleBase.Mount("/vol/content", "content", FSC_PRIORITY_BASE) || !titleBase.Mount(GetInternalVirtualCodeFolder(), "code", FSC_PRIORITY_BASE))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting failed");
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
}
|
||||
// check update
|
||||
TitleInfo& titleUpdate = sGameInfo_ForegroundTitle.GetUpdate();
|
||||
if (titleUpdate.IsValid())
|
||||
{
|
||||
if (!titleUpdate.ParseXmlInfo())
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
cemuLog_log(LogType::Force, "Update: {}", titleUpdate.GetPrintPath());
|
||||
// mount update
|
||||
if (!titleUpdate.Mount("/vol/content", "content", FSC_PRIORITY_PATCH) || !titleUpdate.Mount(GetInternalVirtualCodeFolder(), "code", FSC_PRIORITY_PATCH))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting failed");
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -701,20 +702,20 @@ namespace CafeSystem
|
||||
// todo - support for multi-title AOC
|
||||
TitleInfo& titleAOC = aocList[0];
|
||||
if (!titleAOC.ParseXmlInfo())
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
cemu_assert_debug(titleAOC.IsValid());
|
||||
cemuLog_log(LogType::Force, "DLC: {}", titleAOC.GetPrintPath());
|
||||
// mount AOC
|
||||
if (!titleAOC.Mount(fmt::format("/vol/aoc{:016x}", titleAOC.GetAppTitleId()), "content", FSC_PRIORITY_PATCH))
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting failed");
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
}
|
||||
}
|
||||
else
|
||||
cemuLog_log(LogType::Force, "DLC: Not present");
|
||||
sForegroundTitleId = titleId;
|
||||
return STATUS_CODE::SUCCESS;
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
void UnmountForegroundTitle()
|
||||
@@ -742,7 +743,7 @@ namespace CafeSystem
|
||||
}
|
||||
}
|
||||
|
||||
STATUS_CODE SetupExecutable()
|
||||
PREPARE_STATUS_CODE SetupExecutable()
|
||||
{
|
||||
// set rpx path from cos.xml if available
|
||||
_pathToBaseExecutable = _pathToExecutable;
|
||||
@@ -774,7 +775,7 @@ namespace CafeSystem
|
||||
}
|
||||
}
|
||||
LoadMainExecutable();
|
||||
return STATUS_CODE::SUCCESS;
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
void SetupMemorySpace()
|
||||
@@ -788,7 +789,7 @@ namespace CafeSystem
|
||||
memory_unmapForCurrentTitle();
|
||||
}
|
||||
|
||||
STATUS_CODE PrepareForegroundTitle(TitleId titleId)
|
||||
PREPARE_STATUS_CODE PrepareForegroundTitle(TitleId titleId)
|
||||
{
|
||||
CafeTitleList::WaitForMandatoryScan();
|
||||
sLaunchModeIsStandalone = false;
|
||||
@@ -799,21 +800,21 @@ namespace CafeSystem
|
||||
// mount mlc storage
|
||||
MountBaseDirectories();
|
||||
// mount title folders
|
||||
STATUS_CODE r = LoadAndMountForegroundTitle(titleId);
|
||||
if (r != STATUS_CODE::SUCCESS)
|
||||
PREPARE_STATUS_CODE r = LoadAndMountForegroundTitle(titleId);
|
||||
if (r != PREPARE_STATUS_CODE::SUCCESS)
|
||||
return r;
|
||||
gameProfile_load();
|
||||
// setup memory space and PPC recompiler
|
||||
SetupMemorySpace();
|
||||
PPCRecompiler_init();
|
||||
r = SetupExecutable(); // load RPX
|
||||
if (r != STATUS_CODE::SUCCESS)
|
||||
if (r != PREPARE_STATUS_CODE::SUCCESS)
|
||||
return r;
|
||||
InitVirtualMlcStorage();
|
||||
return STATUS_CODE::SUCCESS;
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path)
|
||||
PREPARE_STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path)
|
||||
{
|
||||
sLaunchModeIsStandalone = true;
|
||||
cemuLog_log(LogType::Force, "Launching executable in standalone mode due to incorrect layout or missing meta files");
|
||||
@@ -831,7 +832,7 @@ namespace CafeSystem
|
||||
if (!r)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Failed to mount {}", _pathToUtf8(contentPath));
|
||||
return STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
return PREPARE_STATUS_CODE::UNABLE_TO_MOUNT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -843,7 +844,7 @@ namespace CafeSystem
|
||||
// since a lot of systems (including save folder location) rely on a TitleId, we derive a placeholder id from the executable hash
|
||||
auto execData = fsc_extractFile(_pathToExecutable.c_str());
|
||||
if (!execData)
|
||||
return STATUS_CODE::INVALID_RPX;
|
||||
return PREPARE_STATUS_CODE::INVALID_RPX;
|
||||
uint32 h = generateHashFromRawRPXData(execData->data(), execData->size());
|
||||
sForegroundTitleId = 0xFFFFFFFF00000000ULL | (uint64)h;
|
||||
cemuLog_log(LogType::Force, "Generated placeholder TitleId: {:016x}", sForegroundTitleId);
|
||||
@@ -853,7 +854,7 @@ namespace CafeSystem
|
||||
// load executable
|
||||
SetupExecutable();
|
||||
InitVirtualMlcStorage();
|
||||
return STATUS_CODE::SUCCESS;
|
||||
return PREPARE_STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
void _LaunchTitleThread()
|
||||
@@ -862,7 +863,7 @@ namespace CafeSystem
|
||||
module->TitleStart();
|
||||
cemu_initForGame();
|
||||
// enter scheduler
|
||||
if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler)
|
||||
if (ActiveSettings::GetCPUMode() == CPUMode::MulticoreRecompiler && !LaunchSettings::ForceInterpreter())
|
||||
coreinit::OSSchedulerBegin(3);
|
||||
else
|
||||
coreinit::OSSchedulerBegin(1);
|
||||
|
||||
@@ -15,12 +15,11 @@ namespace CafeSystem
|
||||
virtual void CafeRecreateCanvas() = 0;
|
||||
};
|
||||
|
||||
enum class STATUS_CODE
|
||||
enum class PREPARE_STATUS_CODE
|
||||
{
|
||||
SUCCESS,
|
||||
INVALID_RPX,
|
||||
UNABLE_TO_MOUNT, // failed to mount through TitleInfo (most likely caused by an invalid or outdated path)
|
||||
//BAD_META_DATA, - the title list only stores titles with valid meta, so this error code is impossible
|
||||
};
|
||||
|
||||
class CafeSystemCallbacks
|
||||
@@ -38,8 +37,8 @@ namespace CafeSystem
|
||||
void SetImplementation(SystemImplementation* impl);
|
||||
void Shutdown();
|
||||
|
||||
STATUS_CODE PrepareForegroundTitle(TitleId titleId);
|
||||
STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path);
|
||||
PREPARE_STATUS_CODE PrepareForegroundTitle(TitleId titleId);
|
||||
PREPARE_STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path);
|
||||
void LaunchForegroundTitle();
|
||||
bool IsTitleRunning();
|
||||
|
||||
|
||||
+268
-111
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "openssl/evp.h"
|
||||
|
||||
struct FSTFileHandle
|
||||
{
|
||||
@@ -45,6 +46,7 @@ public:
|
||||
~FSTVolume();
|
||||
|
||||
uint32 GetFileCount() const;
|
||||
bool HasCorruption() const { return m_detectedCorruption; }
|
||||
|
||||
bool OpenFile(std::string_view path, FSTFileHandle& fileHandleOut, bool openOnlyFiles = false);
|
||||
|
||||
@@ -86,15 +88,25 @@ private:
|
||||
enum class ClusterHashMode : uint8
|
||||
{
|
||||
RAW = 0, // raw data + encryption, no hashing?
|
||||
RAW2 = 1, // raw data + encryption, with hash stored in tmd?
|
||||
RAW_STREAM = 1, // raw data + encryption, with hash stored in tmd?
|
||||
HASH_INTERLEAVED = 2, // hashes + raw interleaved in 0x10000 blocks (0x400 bytes of hashes at the beginning, followed by 0xFC00 bytes of data)
|
||||
};
|
||||
|
||||
struct FSTCluster
|
||||
{
|
||||
FSTCluster() : singleHashCtx(nullptr, &EVP_MD_CTX_free) {}
|
||||
|
||||
uint32 offset;
|
||||
uint32 size;
|
||||
ClusterHashMode hashMode;
|
||||
// extra data if TMD is available
|
||||
bool hasContentHash;
|
||||
uint8 contentHash32[32];
|
||||
bool contentHashIsSHA1; // if true then it's SHA1 (with extra bytes zeroed out), otherwise it's SHA256
|
||||
uint64 contentSize; // size of the content (in blocks)
|
||||
// hash context for single hash mode (content hash must be available)
|
||||
std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)> singleHashCtx; // unique_ptr to make this move-only
|
||||
uint32 singleHashNumBlocksHashed{0};
|
||||
};
|
||||
|
||||
struct FSTEntry
|
||||
@@ -164,17 +176,30 @@ private:
|
||||
bool m_sourceIsOwned{};
|
||||
uint32 m_sectorSize{}; // for cluster offsets
|
||||
uint32 m_offsetFactor{}; // for file offsets
|
||||
bool m_hashIsDisabled{}; // disables hash verification (for all clusters of this volume?)
|
||||
std::vector<FSTCluster> m_cluster;
|
||||
std::vector<FSTEntry> m_entries;
|
||||
std::vector<char> m_nameStringTable;
|
||||
NCrypto::AesKey m_partitionTitlekey;
|
||||
bool m_detectedCorruption{false};
|
||||
|
||||
/* Cache for decrypted hashed blocks */
|
||||
bool HashIsDisabled() const
|
||||
{
|
||||
return m_hashIsDisabled;
|
||||
}
|
||||
|
||||
/* Cache for decrypted raw and hashed blocks */
|
||||
std::unordered_map<uint64, struct FSTCachedRawBlock*> m_cacheDecryptedRawBlocks;
|
||||
std::unordered_map<uint64, struct FSTCachedHashedBlock*> m_cacheDecryptedHashedBlocks;
|
||||
uint64 m_cacheAccessCounter{};
|
||||
|
||||
void DetermineUnhashedBlockIV(uint32 clusterIndex, uint32 blockIndex, uint8 ivOut[16]);
|
||||
|
||||
struct FSTCachedRawBlock* GetDecryptedRawBlock(uint32 clusterIndex, uint32 blockIndex);
|
||||
struct FSTCachedHashedBlock* GetDecryptedHashedBlock(uint32 clusterIndex, uint32 blockIndex);
|
||||
|
||||
void TrimCacheIfRequired(struct FSTCachedRawBlock** droppedRawBlock, struct FSTCachedHashedBlock** droppedHashedBlock);
|
||||
|
||||
/* File reading */
|
||||
uint32 ReadFile_HashModeRaw(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut);
|
||||
uint32 ReadFile_HashModeHashed(uint32 clusterIndex, FSTEntry& entry, uint32 readOffset, uint32 readSize, void* dataOut);
|
||||
@@ -185,7 +210,10 @@ private:
|
||||
/* +0x00 */ uint32be magic;
|
||||
/* +0x04 */ uint32be offsetFactor;
|
||||
/* +0x08 */ uint32be numCluster;
|
||||
/* +0x0C */ uint32be ukn0C;
|
||||
/* +0x0C */ uint8be hashIsDisabled;
|
||||
/* +0x0D */ uint8be ukn0D;
|
||||
/* +0x0E */ uint8be ukn0E;
|
||||
/* +0x0F */ uint8be ukn0F;
|
||||
/* +0x10 */ uint32be ukn10;
|
||||
/* +0x14 */ uint32be ukn14;
|
||||
/* +0x18 */ uint32be ukn18;
|
||||
@@ -262,8 +290,8 @@ private:
|
||||
|
||||
static_assert(sizeof(FSTHeader_FileEntry) == 0x10);
|
||||
|
||||
static FSTVolume* OpenFST(FSTDataSource* dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode);
|
||||
static FSTVolume* OpenFST(std::unique_ptr<FSTDataSource> dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode);
|
||||
static FSTVolume* OpenFST(FSTDataSource* dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD);
|
||||
static FSTVolume* OpenFST(std::unique_ptr<FSTDataSource> dataSource, uint64 fstOffset, uint32 fstSize, NCrypto::AesKey* partitionTitleKey, ClusterHashMode fstHashMode, NCrypto::TMDParser* optionalTMD);
|
||||
static bool ProcessFST(FSTHeader_FileEntry* fileTable, uint32 numFileEntries, uint32 numCluster, std::vector<char>& nameStringTable, std::vector<FSTEntry>& fstEntries);
|
||||
|
||||
bool MatchFSTEntryName(FSTEntry& entry, std::string_view comparedName)
|
||||
|
||||
@@ -140,7 +140,7 @@ bool gameProfile_loadEnumOption(IniParser& iniParser, const char* optionName, T&
|
||||
for(const T& v : T())
|
||||
{
|
||||
// test integer option
|
||||
if (boost::iequals(fmt::format("{}", static_cast<typename std::underlying_type<T>::type>(v)), *option_value))
|
||||
if (boost::iequals(fmt::format("{}", fmt::underlying(v)), *option_value))
|
||||
{
|
||||
option = v;
|
||||
return true;
|
||||
|
||||
@@ -345,7 +345,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
const auto preset_name = rules.FindOption("name");
|
||||
if (!preset_name)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": Preset in line {} skipped because it has no name option defined", m_name, rules.GetCurrentSectionLineNumber());
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": Preset in line {} skipped because it has no name option defined", GetNormalizedPathString(), rules.GetCurrentSectionLineNumber());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -369,7 +369,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
}
|
||||
catch (const std::exception & ex)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": Can't parse preset \"{}\": {}", m_name, *preset_name, ex.what());
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": Can't parse preset \"{}\": {}", GetNormalizedPathString(), *preset_name, ex.what());
|
||||
}
|
||||
}
|
||||
else if (boost::iequals(currentSectionName, "RAM"))
|
||||
@@ -383,7 +383,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
{
|
||||
if (m_version <= 5)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": [RAM] options are only available for graphic pack version 6 or higher", m_name, optionNameBuf);
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": [RAM] options are only available for graphic pack version 6 or higher", GetNormalizedPathString(), optionNameBuf);
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
@@ -393,12 +393,12 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
{
|
||||
if (addrEnd <= addrStart)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": start address (0x{:08x}) must be greater than end address (0x{:08x}) for {}", m_name, addrStart, addrEnd, optionNameBuf);
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": start address (0x{:08x}) must be greater than end address (0x{:08x}) for {}", GetNormalizedPathString(), addrStart, addrEnd, optionNameBuf);
|
||||
throw std::exception();
|
||||
}
|
||||
else if ((addrStart & 0xFFF) != 0 || (addrEnd & 0xFFF) != 0)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": addresses for %s are not aligned to 0x1000", m_name, optionNameBuf);
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": addresses for %s are not aligned to 0x1000", GetNormalizedPathString(), optionNameBuf);
|
||||
throw std::exception();
|
||||
}
|
||||
else
|
||||
@@ -408,7 +408,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
}
|
||||
else
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": has invalid syntax for option {}", m_name, optionNameBuf);
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\": has invalid syntax for option {}", GetNormalizedPathString(), optionNameBuf);
|
||||
throw std::exception();
|
||||
}
|
||||
}
|
||||
@@ -422,24 +422,32 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
std::unordered_map<std::string, std::vector<PresetPtr>> tmp_map;
|
||||
|
||||
// all vars must be defined in the default preset vars before
|
||||
for (const auto& entry : m_presets)
|
||||
std::vector<std::pair<std::string, std::string>> mismatchingPresetVars;
|
||||
for (const auto& presetEntry : m_presets)
|
||||
{
|
||||
tmp_map[entry->category].emplace_back(entry);
|
||||
tmp_map[presetEntry->category].emplace_back(presetEntry);
|
||||
|
||||
for (auto& kv : entry->variables)
|
||||
for (auto& presetVar : presetEntry->variables)
|
||||
{
|
||||
const auto it = m_preset_vars.find(kv.first);
|
||||
const auto it = m_preset_vars.find(presetVar.first);
|
||||
if (it == m_preset_vars.cend())
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" contains preset variables which are not defined in the default section", m_name);
|
||||
throw std::exception();
|
||||
mismatchingPresetVars.emplace_back(presetEntry->name, presetVar.first);
|
||||
continue;
|
||||
}
|
||||
|
||||
// overwrite var type with default var type
|
||||
kv.second.first = it->second.first;
|
||||
presetVar.second.first = it->second.first;
|
||||
}
|
||||
}
|
||||
|
||||
if(!mismatchingPresetVars.empty())
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack \"{}\" contains preset variables which are not defined in the [Default] section:", GetNormalizedPathString());
|
||||
for (const auto& [presetName, varName] : mismatchingPresetVars)
|
||||
cemuLog_log(LogType::Force, "Preset: {} Variable: {}", presetName, varName);
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
// have first entry be default active for every category if no default= is set
|
||||
for(auto entry : get_values(tmp_map))
|
||||
{
|
||||
@@ -469,7 +477,7 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
auto& p2 = kv.second[i + 1];
|
||||
if (p1->variables.size() != p2->variables.size())
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" contains inconsistent preset variables", m_name);
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" contains inconsistent preset variables", GetNormalizedPathString());
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
@@ -477,14 +485,14 @@ GraphicPack2::GraphicPack2(fs::path rulesPath, IniParser& rules)
|
||||
std::set<std::string> keys2(get_keys(p2->variables).begin(), get_keys(p2->variables).end());
|
||||
if (keys1 != keys2)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" contains inconsistent preset variables", m_name);
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" contains inconsistent preset variables", GetNormalizedPathString());
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
if(p1->is_default)
|
||||
{
|
||||
if(has_default)
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" has more than one preset with the default key set for the same category \"{}\"", m_name, p1->name);
|
||||
cemuLog_log(LogType::Force, "Graphic pack: \"{}\" has more than one preset with the default key set for the same category \"{}\"", GetNormalizedPathString(), p1->name);
|
||||
p1->active = true;
|
||||
has_default = true;
|
||||
}
|
||||
@@ -960,7 +968,7 @@ bool GraphicPack2::Activate()
|
||||
auto option_upscale = rules.FindOption("upscaleMagFilter");
|
||||
if(option_upscale && boost::iequals(*option_upscale, "NearestNeighbor"))
|
||||
m_output_settings.upscale_filter = LatteTextureView::MagFilter::kNearestNeighbor;
|
||||
auto option_downscale = rules.FindOption("NearestNeighbor");
|
||||
auto option_downscale = rules.FindOption("downscaleMinFilter");
|
||||
if (option_downscale && boost::iequals(*option_downscale, "NearestNeighbor"))
|
||||
m_output_settings.downscale_filter = LatteTextureView::MagFilter::kNearestNeighbor;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Cafe/HW/Espresso/Recompiler/PPCRecompiler.h"
|
||||
#include "Cemu/ExpressionParser/ExpressionParser.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <Windows.h>
|
||||
@@ -148,11 +149,6 @@ void debugger_createCodeBreakpoint(uint32 address, uint8 bpType)
|
||||
debugger_updateExecutionBreakpoint(address);
|
||||
}
|
||||
|
||||
void debugger_createExecuteBreakpoint(uint32 address)
|
||||
{
|
||||
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);
|
||||
}
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
std::vector<std::thread::native_handle_type>& OSGetSchedulerThreads();
|
||||
@@ -306,8 +302,23 @@ void debugger_toggleExecuteBreakpoint(uint32 address)
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new breakpoint
|
||||
debugger_createExecuteBreakpoint(address);
|
||||
// create new execution breakpoint
|
||||
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void debugger_toggleLoggingBreakpoint(uint32 address)
|
||||
{
|
||||
auto existingBP = debugger_getFirstBP(address, DEBUGGER_BP_T_LOGGING);
|
||||
if (existingBP)
|
||||
{
|
||||
// delete existing breakpoint
|
||||
debugger_deleteBreakpoint(existingBP);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create new logging breakpoint
|
||||
debugger_createCodeBreakpoint(address, DEBUGGER_BP_T_LOGGING);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +472,34 @@ bool debugger_hasPatch(uint32 address)
|
||||
return false;
|
||||
}
|
||||
|
||||
void debugger_removePatch(uint32 address)
|
||||
{
|
||||
for (sint32 i = 0; i < debuggerState.patches.size(); i++)
|
||||
{
|
||||
auto& patch = debuggerState.patches[i];
|
||||
if (address < patch->address || address >= (patch->address + patch->length))
|
||||
continue;
|
||||
MPTR startAddress = patch->address;
|
||||
MPTR endAddress = patch->address + patch->length;
|
||||
// remove any breakpoints overlapping with the patch
|
||||
for (auto& bp : debuggerState.breakpoints)
|
||||
{
|
||||
if (bp->address + 4 > startAddress && bp->address < endAddress)
|
||||
{
|
||||
bp->enabled = false;
|
||||
debugger_updateExecutionBreakpoint(bp->address);
|
||||
}
|
||||
}
|
||||
// restore original data
|
||||
memcpy(MEMPTR<void>(startAddress).GetPtr(), patch->origData.data(), patch->length);
|
||||
PPCRecompiler_invalidateRange(startAddress, endAddress);
|
||||
// remove patch
|
||||
delete patch;
|
||||
debuggerState.patches.erase(debuggerState.patches.begin() + i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void debugger_stepInto(PPCInterpreter_t* hCPU, bool updateDebuggerWindow = true)
|
||||
{
|
||||
bool isRecEnabled = ppcRecompilerEnabled;
|
||||
@@ -526,7 +565,48 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
if (bp->bpType == DEBUGGER_BP_T_LOGGING && bp->enabled)
|
||||
{
|
||||
std::string logName = !bp->comment.empty() ? "Breakpoint '"+boost::nowide::narrow(bp->comment)+"'" : fmt::format("Breakpoint at 0x{:08X} (no comment)", bp->address);
|
||||
std::string comment = !bp->comment.empty() ? boost::nowide::narrow(bp->comment) : fmt::format("Breakpoint at 0x{:08X} (no comment)", bp->address);
|
||||
|
||||
auto replacePlaceholders = [&](const std::string& prefix, const auto& formatFunc)
|
||||
{
|
||||
size_t pos = 0;
|
||||
while ((pos = comment.find(prefix, pos)) != std::string::npos)
|
||||
{
|
||||
size_t endPos = comment.find('}', pos);
|
||||
if (endPos == std::string::npos)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
if (int regNum = ConvertString<int>(comment.substr(pos + prefix.length(), endPos - pos - prefix.length())); regNum >= 0 && regNum < 32)
|
||||
{
|
||||
std::string replacement = formatFunc(regNum);
|
||||
comment.replace(pos, endPos - pos + 1, replacement);
|
||||
pos += replacement.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = endPos + 1;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
pos = endPos + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Replace integer register placeholders {rX}
|
||||
replacePlaceholders("{r", [&](int regNum) {
|
||||
return fmt::format("0x{:08X}", hCPU->gpr[regNum]);
|
||||
});
|
||||
|
||||
// Replace floating point register placeholders {fX}
|
||||
replacePlaceholders("{f", [&](int regNum) {
|
||||
return fmt::format("{}", hCPU->fpr[regNum].fpr);
|
||||
});
|
||||
|
||||
std::string logName = "Breakpoint '" + comment + "'";
|
||||
std::string logContext = fmt::format("Thread: {:08x} LR: 0x{:08x}", MEMPTR<OSThread_t>(coreinit::OSGetCurrentThread()).GetMPTR(), hCPU->spr.LR, cemuLog_advancedPPCLoggingEnabled() ? " Stack Trace:" : "");
|
||||
cemuLog_log(LogType::Force, "[Debugger] {} was executed! {}", logName, logContext);
|
||||
if (cemuLog_advancedPPCLoggingEnabled())
|
||||
@@ -566,7 +646,7 @@ void debugger_enterTW(PPCInterpreter_t* hCPU)
|
||||
debuggerState.debugSession.stepInto = false;
|
||||
debuggerState.debugSession.stepOver = false;
|
||||
debuggerState.debugSession.run = false;
|
||||
while (true)
|
||||
while (debuggerState.debugSession.isTrapped)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
// check for step commands
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user