mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-07-09 17:14:47 -06:00
Merge branch 'cemu-project:main' into cmake-sign
This commit is contained in:
commit
d4db4ba9c6
@ -64,3 +64,4 @@ SpacesInSquareBrackets: false
|
||||
Standard: Latest
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
LineEnding: LF
|
||||
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
text=auto eol=lf
|
||||
20
.github/workflows/build.yml
vendored
20
.github/workflows/build.yml
vendored
@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: "recursive"
|
||||
fetch-depth: 0
|
||||
@ -80,7 +80,7 @@ jobs:
|
||||
cmake --build build
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cemu-bin-linux-${{ matrix.arch }}
|
||||
path: ./bin/Cemu
|
||||
@ -100,9 +100,9 @@ jobs:
|
||||
needs: build-ubuntu
|
||||
steps:
|
||||
- name: Checkout Upstream Repo
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: cemu-bin-linux-${{ matrix.arch }}
|
||||
path: bin
|
||||
@ -119,7 +119,7 @@ jobs:
|
||||
dist/linux/appimage.sh ${{ runner.arch }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cemu-appimage-${{ matrix.arch }}
|
||||
path: artifacts
|
||||
@ -128,7 +128,7 @@ jobs:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
@ -187,13 +187,13 @@ jobs:
|
||||
makensis /DPRODUCT_VERSION=${{ inputs.next_version_major }}.${{ inputs.next_version_minor }} installer.nsi
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
path: ./bin/Cemu.exe
|
||||
|
||||
- name: Upload NSIS Installer
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cemu-installer-windows-x64
|
||||
path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-x64-installer.exe
|
||||
@ -205,7 +205,7 @@ jobs:
|
||||
arch: [x86_64, arm64]
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
@ -280,7 +280,7 @@ jobs:
|
||||
rm bin/tmp.dmg
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: cemu-bin-macos-${{ matrix.arch }}
|
||||
path: ./bin/Cemu.dmg
|
||||
|
||||
12
.github/workflows/deploy_release.yml
vendored
12
.github/workflows/deploy_release.yml
vendored
@ -58,7 +58,7 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [call-release-build, calculate-version]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
@ -78,27 +78,27 @@ jobs:
|
||||
if [ -n "${{ github.event.inputs.changelog9 }}" ]; then CHANGELOG="$CHANGELOG- ${{ github.event.inputs.changelog9 }}\n"; fi
|
||||
echo -e "$CHANGELOG"
|
||||
echo "RELEASE_BODY=$CHANGELOG" >> $GITHUB_ENV
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: cemu-bin-linux-x64
|
||||
path: cemu-bin-linux-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: cemu-appimage-x64
|
||||
path: cemu-appimage-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: cemu-bin-windows-x64
|
||||
path: cemu-bin-windows-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: cemu-installer-windows-x64
|
||||
path: cemu-installer-windows-x64
|
||||
|
||||
- uses: actions/download-artifact@v4
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: cemu-bin-macos*
|
||||
path: cemu-macos
|
||||
|
||||
@ -23,7 +23,7 @@ jobs:
|
||||
next_version_minor: ${{ steps.calculate_next_version.outputs.next_version_minor }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get all releases
|
||||
id: get_all_releases
|
||||
|
||||
4
.github/workflows/generate_pot.yml
vendored
4
.github/workflows/generate_pot.yml
vendored
@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout repo"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: "Install gettext"
|
||||
run: |
|
||||
@ -36,7 +36,7 @@ jobs:
|
||||
-o cemu.pot
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: POT file
|
||||
path: ./cemu.pot
|
||||
|
||||
31
BUILD.md
31
BUILD.md
@ -149,44 +149,31 @@ If you are getting a different error than any of the errors listed above, you ma
|
||||
|
||||
To compile Cemu, a recent enough compiler and STL with C++20 support is required! LLVM 13 and below
|
||||
don't support the C++20 feature set required, so either install LLVM from Homebrew or make sure that
|
||||
you have a recent enough version of Xcode. Xcode 15 is known to work. The OpenGL graphics API isn't
|
||||
supported on macOS, so Vulkan must be used through the Molten-VK compatibility layer.
|
||||
you have a recent enough version of Xcode. Xcode 15 is known to work.
|
||||
|
||||
### Installing brew
|
||||
|
||||
1. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
|
||||
2. Set up the Homebrew shell environment:
|
||||
1. **On an Intel Mac:** `eval "$(/usr/local/Homebrew/bin/brew shellenv)"`
|
||||
2. **On an Apple Silicon Mac:** eval `"$(/opt/homebrew/bin/brew shellenv)"`
|
||||
- **On an Apple Silicon Mac:** eval `"$(/opt/homebrew/bin/brew shellenv)"`
|
||||
- **On an Intel Mac:** `eval "$(/usr/local/Homebrew/bin/brew shellenv)"`
|
||||
|
||||
### Installing Tool Dependencies
|
||||
### Dependencies
|
||||
|
||||
The native versions of these can be used regardless of what type of Mac you have.
|
||||
|
||||
`brew install git cmake ninja nasm automake libtool`
|
||||
|
||||
### Installing Library Dependencies
|
||||
|
||||
**On Apple Silicon Macs, Rosetta 2 and the x86_64 version of Homebrew must be used to install these dependencies:**
|
||||
1. `softwareupdate --install-rosetta` # Install Rosetta 2 if you don't have it. This only has to be done once
|
||||
2. `arch -x86_64 zsh` # run an x64 shell
|
||||
3. `/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"`
|
||||
4. `eval "$(/usr/local/Homebrew/bin/brew shellenv)"`
|
||||
|
||||
Then install the dependencies:
|
||||
|
||||
`brew install boost molten-vk`
|
||||
`brew install git cmake ninja nasm automake libtool boost molten-vk`
|
||||
|
||||
### Build Cemu using CMake
|
||||
|
||||
1. `git clone --recursive https://github.com/cemu-project/Cemu`
|
||||
2. `cd Cemu`
|
||||
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -DCMAKE_OSX_ARCHITECTURES=x86_64 -G Ninja`
|
||||
3. `cmake -S . -B build -DCMAKE_BUILD_TYPE=release -G Ninja`
|
||||
4. `cmake --build build`
|
||||
5. You should now have a Cemu executable file in the /bin folder, which you can run using `./bin/Cemu_release`.
|
||||
|
||||
#### Troubleshooting steps
|
||||
- If step 3 gives you an error about not being able to find ninja, try appending `-DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja` to the command and running it again.
|
||||
- If step 3 gives you an error about not being able to find ninja, try appending the following to the command and try again:
|
||||
- **On an Apple Silicon Mac:** `-DCMAKE_MAKE_PROGRAM=/opt/homebrew/bin/ninja`
|
||||
- **On an Intel Mac:** `-DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja`
|
||||
|
||||
## FreeBSD
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@ set(EMULATOR_VERSION_MAJOR "0" CACHE STRING "")
|
||||
set(EMULATOR_VERSION_MINOR "0" CACHE STRING "")
|
||||
set(EMULATOR_VERSION_PATCH "0" CACHE STRING "")
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG true) # needs to be set before vcpkg
|
||||
|
||||
execute_process(
|
||||
COMMAND git log --format=%h -1
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
@ -136,7 +138,6 @@ option(ENABLE_CUBEB "Enabled cubeb backend" ON)
|
||||
|
||||
option(ENABLE_WXWIDGETS "Build with wxWidgets UI (Currently required)" ON)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG true)
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(SDL2 REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
|
||||
@ -39,6 +39,15 @@ add_compile_definitions(VK_NO_PROTOTYPES)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
|
||||
# on msvc we can reuse the PCH from CemuCommon, on other platforms it's not straight forward to reuse the PCH so we opt out of it
|
||||
function(cemu_use_precompiled_header target_name)
|
||||
if(MSVC)
|
||||
target_precompile_headers(${target_name} REUSE_FROM CemuCommon)
|
||||
else()
|
||||
target_precompile_headers(${target_name} PRIVATE "${CMAKE_SOURCE_DIR}/src/Common/precompiled.h")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
add_subdirectory(Common)
|
||||
add_subdirectory(gui)
|
||||
add_subdirectory(Cafe)
|
||||
@ -55,6 +64,8 @@ add_executable(CemuBin
|
||||
mainLLE.cpp
|
||||
)
|
||||
|
||||
cemu_use_precompiled_header(CemuBin)
|
||||
|
||||
if(MSVC AND MSVC_VERSION EQUAL 1940)
|
||||
# workaround for an msvc issue on VS 17.10 where generated ILK files are too large
|
||||
# see https://developercommunity.visualstudio.com/t/After-updating-to-VS-1710-the-size-of-/10665511
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#include "Account.h"
|
||||
#include "AccountError.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "util/helpers/SystemException.h"
|
||||
#include "util/helpers/StringHelpers.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_crypto.h"
|
||||
|
||||
@ -1,12 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "AccountError.h"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
enum class OnlineAccountError
|
||||
{
|
||||
|
||||
@ -525,6 +525,7 @@ add_library(CemuCafe
|
||||
OS/RPL/rpl_structs.h
|
||||
OS/RPL/rpl_symbol_storage.cpp
|
||||
OS/RPL/rpl_symbol_storage.h
|
||||
TitleList/GameInfo.cpp
|
||||
TitleList/GameInfo.h
|
||||
TitleList/ParsedMetaXml.h
|
||||
TitleList/SaveInfo.cpp
|
||||
@ -614,6 +615,8 @@ endif()
|
||||
|
||||
set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuCafe)
|
||||
|
||||
target_include_directories(CemuCafe PUBLIC "../")
|
||||
|
||||
if (glslang_VERSION VERSION_LESS "15.0.0")
|
||||
@ -631,6 +634,7 @@ target_link_libraries(CemuCafe PRIVATE
|
||||
ZLIB::ZLIB
|
||||
CURL::libcurl
|
||||
ih264d
|
||||
zstd::zstd
|
||||
${glslang_target}
|
||||
PUBLIC
|
||||
OpenSSL::SSL
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#pragma once
|
||||
#include "Cafe/OS/RPL/rpl.h"
|
||||
#include "util/helpers/Semaphore.h"
|
||||
#include "Cafe/TitleList/TitleId.h"
|
||||
#include "config/CemuConfig.h"
|
||||
|
||||
enum class CosCapabilityBits : uint64;
|
||||
enum class CosCapabilityGroup : uint32;
|
||||
enum class CafeConsoleRegion;
|
||||
|
||||
namespace CafeSystem
|
||||
{
|
||||
|
||||
@ -245,6 +245,10 @@ uint8 botw_crashFuncMask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
|
||||
|
||||
uint8 ffl_floatArrayEndianSwap[] = { 0x7C,0x08,0x02,0xA6,0x94,0x21,0xFF,0xE8,0x93,0xC1,0x00,0x10,0x7C,0x7E,0x1B,0x78,0x93,0xE1,0x00,0x14,0x93,0x81,0x00,0x08,0x7C,0x9F,0x23,0x78,0x93,0xA1,0x00,0x0C,0x90,0x01,0x00,0x1C,0x3B,0xA0,0x00,0x00,0x7C,0x1D,0xF8,0x40,0x40,0x80,0x00,0x20,0x57,0xBC,0x10,0x3A,0x7C,0x3E,0xE4,0x2E };
|
||||
|
||||
// Alternative FFL endian swap signature (Mario Kart 8 and possibly other titles)
|
||||
// Same algorithm as above but with a different compiler-scheduled prologue ordering
|
||||
uint8 ffl_floatArrayEndianSwap_v2[] = { 0x7C,0x08,0x02,0xA6,0x94,0x21,0xFF,0xE8,0x93,0xE1,0x00,0x14,0x93,0xA1,0x00,0x0C,0x7C,0x9F,0x23,0x78,0x93,0x81,0x00,0x08,0x93,0xC1,0x00,0x10,0x90,0x01,0x00,0x1C,0x3B,0xA0,0x00,0x00,0x7C,0x1D,0xF8,0x40,0x7C,0x7E,0x1B,0x78,0x40,0x80,0x00,0x20,0x57,0xBC,0x10,0x3A,0x7C,0x3E,0xE4,0x2E };
|
||||
|
||||
uint8 xcx_enterCriticalSectionSignature[] = { 0x94,0x21,0xFF,0xE0,0xBF,0x41,0x00,0x08,0x7C,0x08,0x02,0xA6,0x90,0x01,0x00,0x24,0x7C,0x7E,0x1B,0x78,0x80,0x1E,0x00,0x08,0x2C,0x00,0x00,0x00,0x41,0x82,0x00,0xC0,0x48,0x01,0xD7,0xA1,0x7C,0x7A,0x1B,0x79,0x41,0x82,0x00,0xB4,0x81,0x3E,0x00,0x04,0x7C,0x09,0xD0,0x40,0x40,0x82,0x00,0x2C,0x7D,0x20,0xF0,0x28,0x7C,0x00,0xF0,0x6C };
|
||||
uint8 xcx_enterCriticalSectionMask[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
|
||||
|
||||
@ -361,11 +365,23 @@ void GamePatch_scan()
|
||||
hleAddr = hle_locate(ffl_floatArrayEndianSwap, NULL, sizeof(ffl_floatArrayEndianSwap));
|
||||
if (hleAddr)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "HLE: Hook FFL float array endian swap function at 0x{:08x}", hleAddr);
|
||||
cemuLog_logDebug(LogType::Force, "HLE: Hook FFL float array endian swap function (v1) at 0x{:08x}", hleAddr);
|
||||
sint32 functionIndex = hleIndex_h000000003;
|
||||
uint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex
|
||||
memory_write<uint32>(hleAddr, opcode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try v2 signature (Mario Kart 8 and possibly other titles with reordered prologue)
|
||||
hleAddr = hle_locate(ffl_floatArrayEndianSwap_v2, NULL, sizeof(ffl_floatArrayEndianSwap_v2));
|
||||
if (hleAddr)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "HLE: Hook FFL float array endian swap function (v2) at 0x{:08x}", hleAddr);
|
||||
sint32 functionIndex = hleIndex_h000000003;
|
||||
uint32 opcode = (1 << 26) | (functionIndex); // opcode for HLE: 0x1000 + FunctionIndex
|
||||
memory_write<uint32>(hleAddr, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
// XCX freeze workaround
|
||||
//hleAddr = hle_locate(xcx_enterCriticalSectionSignature, xcx_enterCriticalSectionMask, sizeof(xcx_enterCriticalSectionSignature));
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include "config/CemuConfig.h"
|
||||
|
||||
struct gameProfileIntegerOption_t
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "Cafe/HW/Latte/Renderer/RendererOuputShader.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "boost/algorithm/string.hpp"
|
||||
#include "util/helpers/MapAdaptor.h"
|
||||
#include "util/helpers/StringParser.h"
|
||||
#include "Cafe/HW/Latte/Core/LatteTiming.h"
|
||||
#include "util/IniParser/IniParser.h"
|
||||
#include "util/helpers/StringHelpers.h"
|
||||
#include "util/IniParser/IniParser.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "HW/Espresso/Debugger/Debugger.h"
|
||||
|
||||
#include "Cafe/HW/Latte/Core/LatteTiming.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
#include "Cafe/HW/Latte/Renderer/RendererOuputShader.h"
|
||||
#include <cinttypes>
|
||||
|
||||
std::vector<GraphicPackPtr> GraphicPack2::s_graphic_packs;
|
||||
@ -21,6 +21,37 @@ std::atomic_bool GraphicPack2::s_isReady;
|
||||
|
||||
#define GP_LEGACY_VERSION (2)
|
||||
|
||||
template<typename T>
|
||||
bool ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* valueOut)
|
||||
{
|
||||
auto optionValue = iniParser.FindOption(option_name);
|
||||
if (optionValue)
|
||||
{
|
||||
*valueOut = parser.Evaluate<T>(*optionValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* optionName)
|
||||
{
|
||||
std::vector<T> result;
|
||||
auto optionText = iniParser.FindOption(optionName);
|
||||
if (!optionText)
|
||||
return result;
|
||||
for (auto& token : Tokenize(*optionText, ','))
|
||||
{
|
||||
try
|
||||
{
|
||||
result.emplace_back(parser.Evaluate<T>(token));
|
||||
}
|
||||
catch (const std::invalid_argument&)
|
||||
{}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void GraphicPack2::LoadGraphicPack(fs::path graphicPackPath)
|
||||
{
|
||||
fs::path rulesPath = graphicPackPath;
|
||||
|
||||
@ -6,10 +6,10 @@
|
||||
#include "util/helpers/Serializer.h"
|
||||
#include "Cafe/OS/RPL/rpl.h"
|
||||
#include "Cemu/PPCAssembler/ppcAssembler.h"
|
||||
#include <variant>
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
#include "GraphicPack2Patches.h"
|
||||
#include "util/IniParser/IniParser.h"
|
||||
|
||||
enum class RendererAPI;
|
||||
enum class GfxVendor;
|
||||
|
||||
class GraphicPack2
|
||||
{
|
||||
@ -26,6 +26,7 @@ public:
|
||||
GFXPACK_VERSION_5 = 5,
|
||||
GFXPACK_VERSION_6 = 6, // added memory extensions
|
||||
GFXPACK_VERSION_7 = 7, // added fine-grained origin control in patch format (no more forced 4 byte alignment), .string directive (an alias to .byte) and support for more than one constant per data directive
|
||||
GFXPACK_VERSION_8 = 8, // (Cemu 2.7) added: titleId and rpx hash wildcards (*), added .callback entry <symbol> to call a function when the main entrypoint is reached
|
||||
};
|
||||
|
||||
struct TextureRule
|
||||
@ -98,7 +99,7 @@ public:
|
||||
};
|
||||
using PresetPtr = std::shared_ptr<Preset>;
|
||||
|
||||
GraphicPack2(fs::path rulesPath, IniParser& rules);
|
||||
GraphicPack2(fs::path rulesPath, class IniParser& rules);
|
||||
|
||||
bool IsEnabled() const { return m_enabled; }
|
||||
bool IsActivated() const { return m_activated; }
|
||||
@ -252,12 +253,6 @@ private:
|
||||
std::string m_output_shader_source, m_upscaling_shader_source, m_downscaling_shader_source;
|
||||
std::unique_ptr<RendererOutputShader> m_output_shader, m_upscaling_shader, m_downscaling_shader, m_output_shader_ud, m_upscaling_shader_ud, m_downscaling_shader_ud;
|
||||
|
||||
template<typename T>
|
||||
bool ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const;
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const;
|
||||
|
||||
std::unordered_map<std::string, PresetVar> ParsePresetVars(IniParser& rules) const;
|
||||
|
||||
std::vector<uint64> ParseTitleIds(IniParser& rules, const char* option_name);
|
||||
@ -306,37 +301,3 @@ public:
|
||||
};
|
||||
|
||||
using GraphicPackPtr = std::shared_ptr<GraphicPack2>;
|
||||
|
||||
template <typename T>
|
||||
bool GraphicPack2::ParseRule(const ExpressionParser& parser, IniParser& iniParser, const char* option_name, T* value_out) const
|
||||
{
|
||||
auto option_value = iniParser.FindOption(option_name);
|
||||
if (option_value)
|
||||
{
|
||||
*value_out = parser.Evaluate<T>(*option_value);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> GraphicPack2::ParseList(const ExpressionParser& parser, IniParser& iniParser, const char* option_name) const
|
||||
{
|
||||
std::vector<T> result;
|
||||
|
||||
auto option_text = iniParser.FindOption(option_name);
|
||||
if (!option_text)
|
||||
return result;
|
||||
|
||||
for(auto& token : Tokenize(*option_text, ','))
|
||||
{
|
||||
try
|
||||
{
|
||||
result.emplace_back(parser.Evaluate<T>(token));
|
||||
}
|
||||
catch (const std::invalid_argument&) {}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -12,6 +12,10 @@
|
||||
#include "Cafe/HW/Espresso/EspressoISA.h"
|
||||
#include "Common/socket.h"
|
||||
|
||||
#if BOOST_OS_UNIX
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#define GET_THREAD_ID(threadPtr) memory_getVirtualOffsetFromPointer(threadPtr)
|
||||
#define GET_THREAD_BY_ID(threadId) (OSThread_t*)memory_getPointerFromPhysicalOffset(threadId)
|
||||
|
||||
@ -985,4 +989,4 @@ void GDBServer::HandleEntryStop(uint32 entryAddress)
|
||||
{
|
||||
this->m_patchedInstructions.try_emplace(entryAddress, entryAddress, BreakpointType::BP_SINGLE, false, "");
|
||||
m_entry_point = entryAddress;
|
||||
}
|
||||
}
|
||||
|
||||
@ -678,7 +678,8 @@ void IMLOptimizerX86_SubstituteCJumpForEflagsJump(IMLOptimizerRegIOAnalysis& reg
|
||||
// we can turn the jump into an eflags jump
|
||||
cjumpInstr.make_x86_eflags_jcc(cond, invertedCondition);
|
||||
|
||||
if (IMLUtil_CountRegisterReadsInRange(seg, cmpInstrIndex, cjmpInstIndex, regCondBool.GetRegID()) > 1 || regIoAnalysis.IsRegisterNeededAtEndOfSegment(seg, regCondBool.GetRegID()))
|
||||
// note: x86_eflags_jcc doesn't count towards cond reg reads, so we have to check > 0 here instead of > 1
|
||||
if (IMLUtil_CountRegisterReadsInRange(seg, cmpInstrIndex, cjmpInstIndex, regCondBool.GetRegID()) > 0 || regIoAnalysis.IsRegisterNeededAtEndOfSegment(seg, regCondBool.GetRegID()))
|
||||
return; // bool register is used beyond the CMP, we can't drop it
|
||||
|
||||
auto& cmpInstr = seg.imlList[cmpInstrIndex];
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
#include "Cafe/HW/Latte/Core/LatteOverlay.h"
|
||||
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
|
||||
#include "WindowSystem.h"
|
||||
|
||||
#include "config/CemuConfig.h"
|
||||
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "WindowSystem.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include "resource/IconsFontAwesome5.h"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
#include "Cafe/HW/Latte/Core/LatteTexture.h"
|
||||
#include "Cafe/HW/Latte/Core/LatteTextureView.h"
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
#include "LatteCachedFBO.h"
|
||||
#include "Cafe/GraphicPack/GraphicPack2.h"
|
||||
|
||||
LatteTextureView::LatteTextureView(LatteTexture* texture, sint32 firstMip, sint32 mipCount, sint32 firstSlice, sint32 sliceCount, Latte::E_DIM dim, Latte::E_GX2SURFFMT format, bool registerView)
|
||||
|
||||
@ -336,6 +336,136 @@ void VulkanRenderer::GetDeviceFeatures()
|
||||
cemuLog_log(LogType::Force, fmt::format("VulkanLimits: UBAlignment {0} nonCoherentAtomSize {1}", prop2.properties.limits.minUniformBufferOffsetAlignment, prop2.properties.limits.nonCoherentAtomSize));
|
||||
}
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
#include <sys/wait.h>
|
||||
#include "resource/IconsFontAwesome5.h"
|
||||
|
||||
int BreathOfTheWildChildProcessMain()
|
||||
{
|
||||
InitializeGlobalVulkan();
|
||||
struct sigaction sa{};
|
||||
sa.sa_handler = [](int unused) { _exit(1); };
|
||||
|
||||
int ret = sigaction(SIGABRT, &sa, nullptr);
|
||||
|
||||
freopen("/dev/null", "w", stderr);
|
||||
|
||||
setenv("RADV_DEBUG", "llvm", 1);
|
||||
|
||||
VkInstanceCreateInfo create_info{};
|
||||
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
if (vkCreateInstance(&create_info, nullptr, &instance) != VK_SUCCESS)
|
||||
return 1;
|
||||
InitializeInstanceVulkan(instance);
|
||||
|
||||
// this function will abort() when LLVM is absent
|
||||
uint32_t count = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
||||
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void LinuxBreathOfTheWildWorkaround(VkInstance& instance, const VkInstanceCreateInfo* create_info)
|
||||
{
|
||||
|
||||
// if the user specified either shader backend, do nothing.
|
||||
// should parse the flag list but there are currently no other flags containing llvm or aco as a substring
|
||||
const char* debugEnvC = getenv("RADV_DEBUG");
|
||||
std::string_view debugEnv = debugEnvC != nullptr ? debugEnvC : "";
|
||||
if (debugEnv.find("aco") != std::string_view::npos || debugEnv.find("llvm") != std::string_view::npos)
|
||||
return;
|
||||
|
||||
uint32_t count = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
||||
|
||||
std::vector<VkPhysicalDevice> physicalDevices{count};
|
||||
vkEnumeratePhysicalDevices(instance, &count, physicalDevices.data());
|
||||
|
||||
// Find the first AMD device using a RADV driver and store its version
|
||||
int version = 0;
|
||||
for (auto& i : physicalDevices)
|
||||
{
|
||||
VkPhysicalDeviceDriverProperties driverProps{};
|
||||
driverProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
|
||||
VkPhysicalDeviceProperties2 prop{};
|
||||
prop.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
prop.pNext = &driverProps;
|
||||
vkGetPhysicalDeviceProperties2(i, &prop);
|
||||
if (prop.properties.vendorID != 0x1002 || driverProps.driverID != VK_DRIVER_ID_MESA_RADV)
|
||||
continue;
|
||||
|
||||
version = prop.properties.driverVersion;
|
||||
break;
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
return;
|
||||
|
||||
|
||||
int major = VK_API_VERSION_MAJOR(version);
|
||||
int minor = VK_API_VERSION_MINOR(version);
|
||||
int patch = VK_API_VERSION_PATCH(version);
|
||||
|
||||
// If the driver is unaffected skip the workaround.
|
||||
// affected drivers:
|
||||
// 25.3.0 - 26.0.4
|
||||
if ((major <= 25 && minor < 3) || (major == 26 && (minor > 0 || patch >= 5)) || major > 26)
|
||||
return;
|
||||
|
||||
// check if running with LLVM would crash because mesa is LLVM-less.
|
||||
int childID = fork();
|
||||
if (childID == 0) // inside this if statement runs in child
|
||||
{
|
||||
setenv("CEMU_DETECT_RADV","1", 1);
|
||||
execl("/proc/self/exe", "/proc/self/exe", nullptr);
|
||||
_exit(2); // exec failed so err on the safe side and signal failure
|
||||
}
|
||||
|
||||
int childStatus = 0;
|
||||
waitpid(childID, &childStatus, 0);
|
||||
|
||||
// if the process didn't exit cleanly or failed to determine LLVM status
|
||||
if (!WIFEXITED(childStatus) || WEXITSTATUS(childStatus) == 2)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "BOTW/RADV workaround not applied because detecting LLVM presence failed unexpectedly");
|
||||
return;
|
||||
}
|
||||
|
||||
if (WEXITSTATUS(childStatus) == 1)
|
||||
cemuLog_log(LogType::Force, "BOTW/RADV workaround not applied because mesa was built without LLVM");
|
||||
|
||||
// only continue if the process exits with code zero, which means it didn't crash
|
||||
if (WEXITSTATUS(childStatus) != 0)
|
||||
return;
|
||||
|
||||
cemuLog_log(LogType::Force, "BOTW/RADV workaround active. Adding \"llvm\" to RADV_DEBUG environment variable");
|
||||
if (debugEnv.empty())
|
||||
{
|
||||
setenv("RADV_DEBUG", "llvm", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string appendedDebugEnv{debugEnv};
|
||||
appendedDebugEnv.append(",llvm");
|
||||
setenv("RADV_DEBUG", appendedDebugEnv.c_str(), 1);
|
||||
}
|
||||
|
||||
// recreate the vulkan instance to update debug setting
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
VkResult err = vkCreateInstance(create_info, nullptr, &instance);
|
||||
// re-check for errors just in case.
|
||||
if (err != VK_SUCCESS)
|
||||
throw std::runtime_error(fmt::format("Unable to re-create a Vulkan instance after RADV/LLVM workaround: {}", err));
|
||||
InitializeInstanceVulkan(instance);
|
||||
|
||||
LatteOverlay_pushNotification(std::string{(const char*)ICON_FA_EXCLAMATION_TRIANGLE} + "RADV_DEBUG=llvm set automatically to avoid crashing due to a driver bug. If possible update mesa to 26.0.5 or newer", 10'000);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VulkanRenderer::VulkanRenderer()
|
||||
{
|
||||
glslang::InitializeProcess();
|
||||
@ -395,6 +525,15 @@ VulkanRenderer::VulkanRenderer()
|
||||
if (!InitializeInstanceVulkan(m_instance))
|
||||
throw std::runtime_error("Unable to load instanced Vulkan functions");
|
||||
|
||||
// Workaround for BOTW + RADV. Runes like Magnesis and the camera cause GPU crashes.
|
||||
#if BOOST_OS_LINUX
|
||||
uint64 currentTitleId = CafeSystem::GetForegroundTitleId();
|
||||
if (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x00050000101c9300)
|
||||
{
|
||||
LinuxBreathOfTheWildWorkaround(m_instance, &create_info);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t device_count = 0;
|
||||
vkEnumeratePhysicalDevices(m_instance, &device_count, nullptr);
|
||||
if (device_count == 0)
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#include "util/helpers/StringHelpers.h"
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/IOSU/nn/iosu_nn_service.h"
|
||||
|
||||
#include "Common/socket.h"
|
||||
#include "Common/CafeString.h"
|
||||
|
||||
std::mutex g_friend_notification_mutex;
|
||||
|
||||
@ -11,6 +11,8 @@
|
||||
#include "Cemu/napi/napi.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
namespace iosu
|
||||
{
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
#include "Cafe/OS/libs/nn_common.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/IOSU/nn/iosu_nn_service.h"
|
||||
@ -9,6 +7,7 @@
|
||||
#include "Cafe/IOSU/legacy/iosu_act.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
|
||||
#include "boss_service.h"
|
||||
#include "boss_common.h"
|
||||
|
||||
@ -1,14 +1,286 @@
|
||||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_MessageQueue.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_OSScreen.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include <pugixml.hpp>
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
sint32 ppc_vcprintf_pad(char* strOut, sint32 maxLength, sint32 padLength, char padChar)
|
||||
{
|
||||
padLength = std::min<sint32>(padLength, maxLength);
|
||||
sint32 paddedLength = padLength;
|
||||
while ( padLength > 0)
|
||||
{
|
||||
*strOut = padChar;
|
||||
strOut++;
|
||||
padLength--;
|
||||
}
|
||||
return paddedLength;
|
||||
}
|
||||
|
||||
// handler for %s
|
||||
sint32 ppc_vcprintf_str(char* strOut, sint32 maxLength, MEMPTR<char> strPointer, std::optional<sint32> width, std::optional<sint32> precision)
|
||||
{
|
||||
if (maxLength <= 0)
|
||||
return 0;
|
||||
const char* stringData = "(null)";
|
||||
if (strPointer)
|
||||
stringData = strPointer.GetPtr();
|
||||
else
|
||||
{
|
||||
if (precision.has_value() && *precision > 6)
|
||||
precision = 6;
|
||||
}
|
||||
// get string length
|
||||
sint32 stringLength = 0;
|
||||
if (precision.has_value())
|
||||
{
|
||||
stringLength = *precision;
|
||||
for (sint32 i=0; i<stringLength; i++)
|
||||
{
|
||||
if (stringData[i] == '\0')
|
||||
{
|
||||
stringLength = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
stringLength = strlen(stringData);
|
||||
if (stringLength < 0)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "ppc_vprintf: String length less than zero");
|
||||
stringLength = 0;
|
||||
}
|
||||
sint32 outputLength = 0;
|
||||
if (width.has_value() && width.value() > 0)
|
||||
{
|
||||
// left padding
|
||||
sint32 paddedLength = *width;
|
||||
paddedLength -= stringLength;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, ' ');
|
||||
strOut += paddedLength;
|
||||
maxLength -= paddedLength;
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
stringLength = std::min<sint32>(stringLength, maxLength);
|
||||
cemu_assert(stringLength >= 0);
|
||||
memcpy(strOut, stringData, stringLength);
|
||||
outputLength += stringLength;
|
||||
if (width.has_value() && width.value() < 0)
|
||||
{
|
||||
sint32 paddedLength = -*width;
|
||||
paddedLength -= stringLength;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength - stringLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut + stringLength, maxLength - stringLength, paddedLength, ' ');
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
// handler for %c
|
||||
sint32 ppc_vcprintf_char(char* strOut, sint32 maxLength, char character, std::optional<sint32> width, std::optional<sint32> precision)
|
||||
{
|
||||
if (maxLength <= 0)
|
||||
return 0;
|
||||
sint32 outputLength = 0;
|
||||
if (width.has_value() && width.value() > 0)
|
||||
{
|
||||
// left padding
|
||||
sint32 paddedLength = *width;
|
||||
paddedLength -= 1;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, ' ');
|
||||
strOut += paddedLength;
|
||||
maxLength -= paddedLength;
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
if (maxLength > 0)
|
||||
{
|
||||
*strOut = character;
|
||||
outputLength++;
|
||||
}
|
||||
if (width.has_value() && width.value() < 0)
|
||||
{
|
||||
sint32 paddedLength = -*width;
|
||||
paddedLength -= 1;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength - 1);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut + 1, maxLength - 1, paddedLength, ' ');
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
char GetHexDigit(uint8 nibble, bool isUppercase)
|
||||
{
|
||||
if (nibble >= 10)
|
||||
{
|
||||
return isUppercase ? (nibble - 10 + 'A') : (nibble - 10 + 'a');
|
||||
}
|
||||
return nibble + '0';
|
||||
}
|
||||
|
||||
// handler for integers
|
||||
sint32 ppc_vcprintf_integer(char* strOut, sint32 maxLength, bool isNegative, uint64 absValue, bool isHex, bool uppercase, bool alternateForm, std::optional<sint32> width, std::optional<sint32> precision, char padChar)
|
||||
{
|
||||
if (maxLength <= 0)
|
||||
return 0;
|
||||
|
||||
// convert to digits string
|
||||
char digitBuf[64];
|
||||
sint32 digitCount = 0;
|
||||
uint64 tmpValue = absValue;
|
||||
if (isHex)
|
||||
{
|
||||
do
|
||||
{
|
||||
digitBuf[digitCount++] = GetHexDigit(tmpValue&0xF, uppercase);
|
||||
tmpValue >>= 4;
|
||||
}
|
||||
while (tmpValue != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
digitBuf[digitCount++] = (char)('0' + (tmpValue % 10));
|
||||
tmpValue /= 10;
|
||||
}
|
||||
while (tmpValue != 0);
|
||||
}
|
||||
|
||||
// handle "%.0d"
|
||||
if (precision.has_value() && *precision == 0 && (!isNegative && absValue == 0))
|
||||
digitCount = 0;
|
||||
|
||||
// precision adds leading zeroes for digits only
|
||||
sint32 precisionZeroes = 0;
|
||||
if (precision.has_value() && *precision > digitCount)
|
||||
precisionZeroes = *precision - digitCount;
|
||||
|
||||
sint32 numberLength = digitCount + precisionZeroes;
|
||||
if (isNegative)
|
||||
numberLength++; // count the sign
|
||||
if (isHex && alternateForm && maxLength >= 2 && absValue != 0)
|
||||
numberLength += 2;
|
||||
|
||||
sint32 outputLength = 0;
|
||||
|
||||
// zero padding is a special case because its between the sign and the number
|
||||
bool widthZeroPad = width.has_value() && *width > 0 && padChar == '0' && !precision.has_value();
|
||||
|
||||
// handle space padding left
|
||||
if (width.has_value() && *width > 0 && !widthZeroPad)
|
||||
{
|
||||
sint32 paddedLength = *width - numberLength;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, ' ');
|
||||
strOut += paddedLength;
|
||||
maxLength -= paddedLength;
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
|
||||
// sign
|
||||
if (isNegative && maxLength > 0)
|
||||
{
|
||||
*strOut = '-';
|
||||
strOut++;
|
||||
maxLength--;
|
||||
outputLength++;
|
||||
}
|
||||
// hex alternate form prefix (0x / 0X)
|
||||
bool hasHexPrefix = false;
|
||||
if (isHex && alternateForm && maxLength >= 2 && absValue != 0)
|
||||
{
|
||||
strOut[0] = '0';
|
||||
if (uppercase)
|
||||
strOut[1] = 'X';
|
||||
else
|
||||
strOut[1] = 'x';
|
||||
strOut += 2;
|
||||
maxLength -= 2;
|
||||
outputLength += 2;
|
||||
hasHexPrefix = true;
|
||||
}
|
||||
// output zero padding after sign
|
||||
if (widthZeroPad)
|
||||
{
|
||||
sint32 paddedLength = *width - (digitCount + (isNegative ? 1 : 0));
|
||||
if (hasHexPrefix)
|
||||
paddedLength -= 2;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, '0');
|
||||
strOut += paddedLength;
|
||||
maxLength -= paddedLength;
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
else if (precisionZeroes > 0)
|
||||
{
|
||||
// precision zeroes
|
||||
sint32 paddedLength = std::min<sint32>(precisionZeroes, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, '0');
|
||||
strOut += paddedLength;
|
||||
maxLength -= paddedLength;
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
|
||||
// digits (the buffer is in reverse order)
|
||||
sint32 writableDigits = std::min<sint32>(digitCount, maxLength);
|
||||
for (sint32 i = 0; i < writableDigits; i++)
|
||||
strOut[i] = digitBuf[digitCount - 1 - i];
|
||||
strOut += writableDigits;
|
||||
maxLength -= writableDigits;
|
||||
outputLength += writableDigits;
|
||||
|
||||
// space padding right
|
||||
if (width.has_value() && *width < 0)
|
||||
{
|
||||
sint32 paddedLength = (-*width) - numberLength;
|
||||
paddedLength = std::min<sint32>(paddedLength, maxLength);
|
||||
if (paddedLength > 0)
|
||||
{
|
||||
ppc_vcprintf_pad(strOut, maxLength, paddedLength, ' ');
|
||||
outputLength += paddedLength;
|
||||
}
|
||||
}
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
// handler for signed decimal integers (64-bit core)
|
||||
sint32 ppc_vcprintf_decimal64(char* strOut, sint32 maxLength, bool isNegative, uint64 absValue, std::optional<sint32> width, std::optional<sint32> precision, char padChar)
|
||||
{
|
||||
return ppc_vcprintf_integer(strOut, maxLength, isNegative, absValue, false, false, false, width, precision, padChar);
|
||||
}
|
||||
|
||||
sint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs)
|
||||
{
|
||||
if (maxLength <= 0)
|
||||
return 0;
|
||||
char tempStr[4096];
|
||||
sint32 writeIndex = 0;
|
||||
while (*formatStr)
|
||||
@ -29,8 +301,9 @@ namespace coreinit
|
||||
continue;
|
||||
}
|
||||
// flags
|
||||
char padChar = ' ';
|
||||
bool alternateForm = false;
|
||||
bool flag_leftJustify = false;
|
||||
bool flag_zeroPadding = false;
|
||||
if (*formatStr == '-')
|
||||
{
|
||||
flag_leftJustify = true;
|
||||
@ -38,114 +311,143 @@ namespace coreinit
|
||||
}
|
||||
if (*formatStr == '+')
|
||||
{
|
||||
// todo
|
||||
formatStr++;
|
||||
}
|
||||
if (*formatStr == ' ')
|
||||
{
|
||||
// todo
|
||||
formatStr++;
|
||||
}
|
||||
if (*formatStr == '#')
|
||||
{
|
||||
// todo
|
||||
alternateForm = true;
|
||||
formatStr++;
|
||||
}
|
||||
if (*formatStr == '0')
|
||||
{
|
||||
flag_zeroPadding = true;
|
||||
padChar = '0';
|
||||
formatStr++;
|
||||
}
|
||||
// width
|
||||
std::optional<sint32> width;
|
||||
if (*formatStr == '*')
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
formatStr++;
|
||||
width = *(sint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
if (flag_leftJustify)
|
||||
width = -abs(*width);
|
||||
}
|
||||
bool widthIsSpecified = false;
|
||||
sint32 width = 0;
|
||||
while (*formatStr >= '0' && *formatStr <= '9')
|
||||
else
|
||||
{
|
||||
width *= 10;
|
||||
width += (*formatStr - '0');
|
||||
formatStr++;
|
||||
widthIsSpecified = true;
|
||||
width = 0;
|
||||
while (*formatStr >= '0' && *formatStr <= '9')
|
||||
{
|
||||
*width *= 10;
|
||||
*width += (*formatStr - '0');
|
||||
formatStr++;
|
||||
}
|
||||
if (flag_leftJustify)
|
||||
width = -*width;
|
||||
}
|
||||
// precision
|
||||
std::optional<sint32> precision;
|
||||
if (*formatStr == '.')
|
||||
{
|
||||
formatStr++;
|
||||
if (*formatStr == '*')
|
||||
{
|
||||
cemu_assert_debug(false);
|
||||
}
|
||||
while (*formatStr >= '0' && *formatStr <= '9')
|
||||
{
|
||||
precision = *(sint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
if (*precision < 0)
|
||||
precision.reset();
|
||||
formatStr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
precision = 0;
|
||||
while (*formatStr >= '0' && *formatStr <= '9')
|
||||
{
|
||||
*precision *= 10;
|
||||
*precision += (*formatStr - '0');
|
||||
formatStr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// length + specifier
|
||||
char tempFormat[64];
|
||||
if (*formatStr == 'X' || *formatStr == 'x' || *formatStr == 'u' || *formatStr == 'd' || *formatStr == 'p' || *formatStr == 'i' ||
|
||||
(formatStr[0] == 'l' && formatStr[1] == 'd'))
|
||||
if (strncmp(formatStr, "lld", 3) == 0 || strncmp(formatStr, "lli", 3) == 0)
|
||||
{
|
||||
// number
|
||||
formatStr++;
|
||||
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
|
||||
if ((formatStr - formatStart) < sizeof(tempFormat))
|
||||
tempFormat[(formatStr - formatStart)] = '\0';
|
||||
// 64bit decimal (signed)
|
||||
formatStr += 3;
|
||||
sint64 v = *(sint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64);
|
||||
if (v >= 0)
|
||||
writeIndex += ppc_vcprintf_decimal64(strOut + writeIndex, maxLength - writeIndex, false, (uint64)v, width, precision, padChar);
|
||||
else
|
||||
tempFormat[sizeof(tempFormat) - 1] = '\0';
|
||||
sint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));
|
||||
for (sint32 i = 0; i < tempLen; i++)
|
||||
{
|
||||
if (writeIndex >= maxLength)
|
||||
break;
|
||||
strOut[writeIndex] = tempStr[i];
|
||||
writeIndex++;
|
||||
}
|
||||
writeIndex += ppc_vcprintf_decimal64(strOut + writeIndex, maxLength - writeIndex, true, ~(uint64)v + 1, width, precision, padChar);
|
||||
}
|
||||
else if (strncmp(formatStr, "llu", 3) == 0)
|
||||
{
|
||||
// 64bit decimal (unsigned)
|
||||
formatStr += 3;
|
||||
uint64 v = *(uint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64);
|
||||
writeIndex += ppc_vcprintf_decimal64(strOut + writeIndex, maxLength - writeIndex, false, v, width, precision, padChar);
|
||||
}
|
||||
else if (*formatStr == 'd' || *formatStr == 'i' || strncmp(formatStr, "ld", 2) == 0 || strncmp(formatStr, "li", 2) == 0)
|
||||
{
|
||||
// 32bit decimal (signed)
|
||||
if (formatStr[0] == 'l')
|
||||
formatStr += 2;
|
||||
else
|
||||
formatStr++;
|
||||
sint32 v = *(sint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
writeIndex += ppc_vcprintf_decimal64(strOut + writeIndex, maxLength - writeIndex, v < 0, (uint64)abs((sint64)v), width, precision, padChar);
|
||||
}
|
||||
else if (*formatStr == 'u' || strncmp(formatStr, "lu", 2) == 0)
|
||||
{
|
||||
// 32bit decimal (unsigned)
|
||||
if (formatStr[0] == 'l')
|
||||
formatStr += 2;
|
||||
else
|
||||
formatStr++;
|
||||
uint32 v = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
writeIndex += ppc_vcprintf_decimal64(strOut + writeIndex, maxLength - writeIndex, false, (uint64)v, width, precision, padChar);
|
||||
}
|
||||
else if (strncmp(formatStr, "llx", 3) == 0 || strncmp(formatStr, "llX", 3) == 0)
|
||||
{
|
||||
// 64bit hexadecimal
|
||||
bool isUppercase = formatStr[2] == 'X';
|
||||
formatStr += 3;
|
||||
uint64 v = *(uint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64);
|
||||
writeIndex += ppc_vcprintf_integer(strOut + writeIndex, maxLength - writeIndex, false, (uint64)v, true, isUppercase, alternateForm, width, precision, padChar);
|
||||
}
|
||||
else if (*formatStr == 'x' || *formatStr == 'X')
|
||||
{
|
||||
// 32bit hexadecimal
|
||||
bool isUppercase = *formatStr == 'X';
|
||||
formatStr++;
|
||||
uint32 v = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
writeIndex += ppc_vcprintf_integer(strOut + writeIndex, maxLength - writeIndex, false, (uint64)v, true, isUppercase, alternateForm, width, precision, padChar);
|
||||
}
|
||||
else if (*formatStr == 'p')
|
||||
{
|
||||
// pointer
|
||||
formatStr++;
|
||||
uint32 v = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
if (!precision.has_value())
|
||||
precision = 8;
|
||||
writeIndex += ppc_vcprintf_integer(strOut + writeIndex, maxLength - writeIndex, false, (uint64)v, true, false, true, width, precision, padChar);
|
||||
}
|
||||
else if (*formatStr == 's')
|
||||
{
|
||||
// string
|
||||
formatStr++;
|
||||
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
|
||||
if ((formatStr - formatStart) < sizeof(tempFormat))
|
||||
tempFormat[(formatStr - formatStart)] = '\0';
|
||||
else
|
||||
tempFormat[sizeof(tempFormat) - 1] = '\0';
|
||||
MPTR strOffset = *(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
sint32 tempLen = 0;
|
||||
if (strOffset == MPTR_NULL)
|
||||
tempLen = sprintf(tempStr, "NULL");
|
||||
else
|
||||
tempLen = sprintf(tempStr, tempFormat, memory_getPointerFromVirtualOffset(strOffset));
|
||||
for (sint32 i = 0; i < tempLen; i++)
|
||||
{
|
||||
if (writeIndex >= maxLength)
|
||||
break;
|
||||
strOut[writeIndex] = tempStr[i];
|
||||
writeIndex++;
|
||||
}
|
||||
strOut[std::min(maxLength - 1, writeIndex)] = '\0';
|
||||
writeIndex += ppc_vcprintf_str(strOut + writeIndex, maxLength - writeIndex, MEMPTR<char>(strOffset), width, precision);
|
||||
}
|
||||
else if (*formatStr == 'c')
|
||||
{
|
||||
// character
|
||||
formatStr++;
|
||||
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
|
||||
if ((formatStr - formatStart) < sizeof(tempFormat))
|
||||
tempFormat[(formatStr - formatStart)] = '\0';
|
||||
else
|
||||
tempFormat[sizeof(tempFormat) - 1] = '\0';
|
||||
sint32 tempLen = sprintf(tempStr, tempFormat, (uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32));
|
||||
for (sint32 i = 0; i < tempLen; i++)
|
||||
{
|
||||
if (writeIndex >= maxLength)
|
||||
break;
|
||||
strOut[writeIndex] = tempStr[i];
|
||||
writeIndex++;
|
||||
}
|
||||
char character = (char)(uint32)*(uint32be*)_ppc_va_arg(vargs, ppc_va_type::INT32);
|
||||
writeIndex += ppc_vcprintf_char(strOut + writeIndex, maxLength - writeIndex, character, width, precision);
|
||||
}
|
||||
else if (*formatStr == 'f' || *formatStr == 'g' || *formatStr == 'G')
|
||||
{
|
||||
@ -182,48 +484,13 @@ namespace coreinit
|
||||
writeIndex++;
|
||||
}
|
||||
}
|
||||
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && (formatStr[2] == 'x' || formatStr[2] == 'X')))
|
||||
{
|
||||
formatStr += 3;
|
||||
// 64bit int
|
||||
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
|
||||
if ((formatStr - formatStart) < sizeof(tempFormat))
|
||||
tempFormat[(formatStr - formatStart)] = '\0';
|
||||
else
|
||||
tempFormat[sizeof(tempFormat) - 1] = '\0';
|
||||
sint32 tempLen = sprintf(tempStr, tempFormat, (uint64)*(uint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));
|
||||
for (sint32 i = 0; i < tempLen; i++)
|
||||
{
|
||||
if (writeIndex >= maxLength)
|
||||
break;
|
||||
strOut[writeIndex] = tempStr[i];
|
||||
writeIndex++;
|
||||
}
|
||||
}
|
||||
else if ((formatStr[0] == 'l' && formatStr[1] == 'l' && formatStr[2] == 'd'))
|
||||
{
|
||||
formatStr += 3;
|
||||
// signed integer (64bit)
|
||||
strncpy(tempFormat, formatStart, std::min((std::ptrdiff_t)sizeof(tempFormat) - 1, formatStr - formatStart));
|
||||
if ((formatStr - formatStart) < sizeof(tempFormat))
|
||||
tempFormat[(formatStr - formatStart)] = '\0';
|
||||
else
|
||||
tempFormat[sizeof(tempFormat) - 1] = '\0';
|
||||
sint32 tempLen = sprintf(tempStr, tempFormat, (sint64)*(sint64be*)_ppc_va_arg(vargs, ppc_va_type::INT64));
|
||||
for (sint32 i = 0; i < tempLen; i++)
|
||||
{
|
||||
if (writeIndex >= maxLength)
|
||||
break;
|
||||
strOut[writeIndex] = tempStr[i];
|
||||
writeIndex++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// unsupported / unknown specifier
|
||||
cemu_assert_debug(false);
|
||||
break;
|
||||
}
|
||||
cemu_assert(writeIndex <= maxLength); // sanity check
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -234,8 +501,9 @@ namespace coreinit
|
||||
formatStr++;
|
||||
}
|
||||
}
|
||||
strOut[std::min(writeIndex, maxLength - 1)] = '\0';
|
||||
return std::min(writeIndex, maxLength - 1);
|
||||
writeIndex = std::min<sint32>(writeIndex, maxLength-1);
|
||||
strOut[writeIndex] = '\0';
|
||||
return writeIndex;
|
||||
}
|
||||
|
||||
/* coreinit logging and string format */
|
||||
@ -351,6 +619,32 @@ namespace coreinit
|
||||
WriteCafeConsole(CafeLogType::OSCONSOLE, strPtr, length);
|
||||
}
|
||||
|
||||
void OSFatal(const char* msg)
|
||||
{
|
||||
// print to log
|
||||
ppc_define_va_list(1, 0);
|
||||
COSVReport(COSReportModule::coreinit, COSReportLevel::Error, msg, &vargs);
|
||||
|
||||
// print to screen
|
||||
OSScreenInit();
|
||||
uint32 tvBufferSize = OSScreenGetBufferSizeEx(OSSCREEN_TV);
|
||||
OSScreenSetBufferEx(OSSCREEN_TV, MEMORY_MEM1_AREA_ADDR);
|
||||
OSScreenSetBufferEx(OSSCREEN_DRC, MEMORY_MEM1_AREA_ADDR + tvBufferSize);
|
||||
OSScreenEnableEx(OSSCREEN_TV, 1);
|
||||
OSScreenEnableEx(OSSCREEN_DRC, 1);
|
||||
|
||||
while ( true )
|
||||
{
|
||||
OSScreenClearBufferEx(OSSCREEN_TV, 0);
|
||||
OSScreenClearBufferEx(OSSCREEN_DRC, 0);
|
||||
OSScreenPutFontEx(OSSCREEN_TV, 0, 0, msg);
|
||||
OSScreenPutFontEx(OSSCREEN_DRC, 0, 0, msg);
|
||||
OSScreenFlipBuffersEx(OSSCREEN_TV);
|
||||
OSScreenFlipBuffersEx(OSSCREEN_DRC);
|
||||
OSSleepTicks(ESPRESSO_TIMER_CLOCK / 30);
|
||||
}
|
||||
}
|
||||
|
||||
/* home button menu */
|
||||
|
||||
bool g_homeButtonMenuEnabled = false;
|
||||
@ -563,6 +857,7 @@ namespace coreinit
|
||||
cafeExportRegister("coreinit", OSVReport, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSLogPrintf, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSConsoleWrite, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSFatal, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("coreinit", OSGetPFID, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSGetUPID, LogType::Placeholder);
|
||||
|
||||
@ -38,6 +38,8 @@ namespace coreinit
|
||||
Info = 2
|
||||
};
|
||||
|
||||
void OSFatal(const char* msg);
|
||||
|
||||
sint32 ppc_vprintf(const char* formatStr, char* strOut, sint32 maxLength, ppc_va_list* vargs);
|
||||
|
||||
void miscInit();
|
||||
|
||||
@ -5,9 +5,6 @@
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_OSScreen_font.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_OSScreen.h"
|
||||
|
||||
#define OSSCREEN_TV (0)
|
||||
#define OSSCREEN_DRC (1)
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
|
||||
@ -39,19 +36,16 @@ namespace coreinit
|
||||
}
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenInit(PPCInterpreter_t* hCPU)
|
||||
void OSScreenInit()
|
||||
{
|
||||
// todo - init VI registers?
|
||||
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenGetBufferSizeEx(PPCInterpreter_t* hCPU)
|
||||
uint32 OSScreenGetBufferSizeEx(uint32 screenIndex)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
cemu_assert(screenIndex < 2);
|
||||
uint32 bufferSize = screenSizes[screenIndex].pitch * screenSizes[screenIndex].y * 4 * 2;
|
||||
osLib_returnFromFunction(hCPU, bufferSize);
|
||||
return bufferSize;
|
||||
}
|
||||
|
||||
void _updateCurrentDrawScreen(sint32 screenIndex)
|
||||
@ -64,59 +58,40 @@ namespace coreinit
|
||||
currentScreenBasePtr[screenIndex] = memory_getPointerFromPhysicalOffset(LatteGPUState.osScreen.screen[screenIndex].physPtr);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenSetBufferEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenSetBufferEx(uint32 screenIndex, uint32 buffer)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
ppcDefineParamU32(buffer, 1);
|
||||
cemu_assert(screenIndex < 2);
|
||||
LatteGPUState.osScreen.screen[screenIndex].physPtr = buffer;
|
||||
_updateCurrentDrawScreen(screenIndex);
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenEnableEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenEnableEx(uint32 screenIndex, uint32 isEnabled)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
ppcDefineParamU32(isEnabled, 1);
|
||||
cemu_assert(screenIndex < 2);
|
||||
LatteGPUState.osScreen.screen[screenIndex].isEnabled = isEnabled != 0;
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenClearBufferEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenClearBufferEx(uint32 screenIndex, uint32 color)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
ppcDefineParamU32(color, 1);
|
||||
cemu_assert(screenIndex < 2);
|
||||
_OSScreen_Clear(screenIndex, color);
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenFlipBuffersEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenFlipBuffersEx(uint32 screenIndex)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
cemu_assert(screenIndex < 2);
|
||||
LatteGPUState.osScreen.screen[screenIndex].flipRequestCount++;
|
||||
_updateCurrentDrawScreen(screenIndex);
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenPutPixelEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenPutPixelEx(uint32 screenIndex, sint32 x, sint32 y, uint32 color)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
ppcDefineParamS32(x, 1);
|
||||
ppcDefineParamS32(y, 2);
|
||||
ppcDefineParamU32(color, 3);
|
||||
if (screenIndex >= 2)
|
||||
{
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
}
|
||||
if (x >= 0 && x < screenSizes[screenIndex].x && y >= 0 && y < screenSizes[screenIndex].y)
|
||||
{
|
||||
*(uint32*)((uint8*)currentScreenBasePtr[screenIndex] + (x + y * screenSizes[screenIndex].pitch) * 4) = _swapEndianS32(color);
|
||||
}
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
const char* osScreenCharset = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
|
||||
@ -135,13 +110,8 @@ namespace coreinit
|
||||
return -1;
|
||||
}
|
||||
|
||||
void coreinitExport_OSScreenPutFontEx(PPCInterpreter_t* hCPU)
|
||||
void OSScreenPutFontEx(uint32 screenIndex, sint32 x, sint32 y, const char* str)
|
||||
{
|
||||
ppcDefineParamU32(screenIndex, 0);
|
||||
ppcDefineParamS32(x, 1);
|
||||
ppcDefineParamS32(y, 2);
|
||||
ppcDefineParamStr(str, 3);
|
||||
|
||||
// characters are:
|
||||
// 16 x 32 (including the margin)
|
||||
// with a margin of 4 x 8
|
||||
@ -149,16 +119,23 @@ namespace coreinit
|
||||
if (y < 0)
|
||||
{
|
||||
debug_printf("OSScreenPutFontEx: y has invalid value\n");
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
sint32 px = x * 16;
|
||||
sint32 py = y * 24;
|
||||
sint32 initialPx = px;
|
||||
|
||||
while (*str)
|
||||
{
|
||||
sint32 charIndex = _getOSScreenFontCharIndex(*str);
|
||||
if (*str == (uint8)'\n')
|
||||
{
|
||||
px = initialPx;
|
||||
py += 24;
|
||||
str++;
|
||||
continue;
|
||||
}
|
||||
if (charIndex >= 0)
|
||||
{
|
||||
const uint8* charBitmap = osscreenBitmapFont + charIndex * 50;
|
||||
@ -175,18 +152,17 @@ namespace coreinit
|
||||
px += 16;
|
||||
str++;
|
||||
}
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
}
|
||||
|
||||
void InitializeOSScreen()
|
||||
{
|
||||
osLib_addFunction("coreinit", "OSScreenInit", coreinitExport_OSScreenInit);
|
||||
osLib_addFunction("coreinit", "OSScreenGetBufferSizeEx", coreinitExport_OSScreenGetBufferSizeEx);
|
||||
osLib_addFunction("coreinit", "OSScreenSetBufferEx", coreinitExport_OSScreenSetBufferEx);
|
||||
osLib_addFunction("coreinit", "OSScreenEnableEx", coreinitExport_OSScreenEnableEx);
|
||||
osLib_addFunction("coreinit", "OSScreenClearBufferEx", coreinitExport_OSScreenClearBufferEx);
|
||||
osLib_addFunction("coreinit", "OSScreenFlipBuffersEx", coreinitExport_OSScreenFlipBuffersEx);
|
||||
osLib_addFunction("coreinit", "OSScreenPutPixelEx", coreinitExport_OSScreenPutPixelEx);
|
||||
osLib_addFunction("coreinit", "OSScreenPutFontEx", coreinitExport_OSScreenPutFontEx);
|
||||
cafeExportRegister("coreinit", OSScreenInit, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenGetBufferSizeEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenSetBufferEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenEnableEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenClearBufferEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenFlipBuffersEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenPutPixelEx, LogType::Placeholder);
|
||||
cafeExportRegister("coreinit", OSScreenPutFontEx, LogType::Placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#define OSSCREEN_TV (0)
|
||||
#define OSSCREEN_DRC (1)
|
||||
|
||||
namespace coreinit
|
||||
{
|
||||
void OSScreenInit();
|
||||
uint32 OSScreenGetBufferSizeEx(uint32 screenIndex);
|
||||
void OSScreenSetBufferEx(uint32 screenIndex, uint32 buffer);
|
||||
void OSScreenEnableEx(uint32 screenIndex, uint32 isEnabled);
|
||||
void OSScreenClearBufferEx(uint32 screenIndex, uint32 color);
|
||||
void OSScreenFlipBuffersEx(uint32 screenIndex);
|
||||
void OSScreenPutPixelEx(uint32 screenIndex, sint32 x, sint32 y, uint32 color);
|
||||
void OSScreenPutFontEx(uint32 screenIndex, sint32 x, sint32 y, const char* str);
|
||||
|
||||
void InitializeOSScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,8 +300,16 @@ namespace coreinit
|
||||
void OSUnlockMutexInternal(OSMutex* mutex)
|
||||
{
|
||||
OSThread_t* currentThread = OSGetCurrentThread();
|
||||
cemu_assert_debug(mutex->owner == currentThread);
|
||||
cemu_assert_debug(mutex->lockCount > 0);
|
||||
if (mutex->lockCount == 0)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "OSUnlockMutex called on a mutex which is not locked");
|
||||
return;
|
||||
}
|
||||
if (mutex->owner != currentThread)
|
||||
{
|
||||
cemuLog_log(LogType::APIErrors, "OSUnlockMutex called by a different thread than the one owning it (owner=0x{:08x} currentThread=0x{:08x})", mutex->owner.GetMPTR(), MEMPTR<void>(currentThread).GetMPTR());
|
||||
return;
|
||||
}
|
||||
mutex->lockCount = mutex->lockCount - 1;
|
||||
if (mutex->lockCount == 0)
|
||||
{
|
||||
|
||||
@ -294,6 +294,8 @@ void gx2Export_GX2SetSemaphore(PPCInterpreter_t* hCPU)
|
||||
}
|
||||
uint32 semaphoreControl = (SEM_SEL << 29);
|
||||
semaphoreControl |= 0x1000; // WAIT_ON_SIGNAL
|
||||
|
||||
GX2::GX2ReserveCmdSpace(3);
|
||||
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_MEM_SEMAPHORE, 2));
|
||||
gx2WriteGather_submitU32AsBE(memory_virtualToPhysical(semaphoreMPTR)); // semaphore physical address
|
||||
gx2WriteGather_submitU32AsBE(semaphoreControl); // control
|
||||
|
||||
@ -56,7 +56,7 @@ namespace GX2
|
||||
|
||||
void GX2DrawIndexedEx2(GX2PrimitiveMode2 primitiveMode, uint32 count, GX2IndexType indexType, void* indexData, uint32 baseVertex, uint32 numInstances, uint32 baseInstance)
|
||||
{
|
||||
GX2ReserveCmdSpace(3 + 3 + 2 + 2 + 6);
|
||||
GX2ReserveCmdSpace(3 + 3 + 3 + 2 + 2 + 6 + 3);
|
||||
gx2WriteGather_submit(
|
||||
// IT_SET_CTL_CONST
|
||||
pm4HeaderType3(IT_SET_CTL_CONST, 2), 0,
|
||||
|
||||
@ -38,7 +38,7 @@ namespace GX2
|
||||
|
||||
void GX2SubmitUserTimeStamp(uint64* timestampOut, uint64 value, GX2PipeEventType eventType, uint32 triggerInterrupt)
|
||||
{
|
||||
GX2ReserveCmdSpace(7);
|
||||
GX2ReserveCmdSpace(11);
|
||||
|
||||
MPTR physTimestampAddr = memory_virtualToPhysical(memory_getVirtualOffsetFromPointer(timestampOut));
|
||||
uint32 valHigh = (uint32)(value >> 32);
|
||||
@ -214,7 +214,7 @@ namespace GX2
|
||||
__OSUnlockScheduler();
|
||||
}
|
||||
|
||||
void GX2DrawDone()
|
||||
bool GX2DrawDone()
|
||||
{
|
||||
// optional force full sync (texture readback and occlusion queries)
|
||||
bool forceFullSync = false;
|
||||
@ -231,7 +231,7 @@ namespace GX2
|
||||
GX2Command_Flush(0x100, true);
|
||||
|
||||
uint64 ts = GX2GetLastSubmittedTimeStamp();
|
||||
GX2WaitTimeStamp(ts);
|
||||
return GX2WaitTimeStamp(ts);
|
||||
}
|
||||
|
||||
void GX2Init_event()
|
||||
|
||||
@ -8,7 +8,7 @@ namespace GX2
|
||||
void GX2EventInit();
|
||||
void GX2WaitForVsync();
|
||||
void GX2WaitForFlip();
|
||||
void GX2DrawDone();
|
||||
bool GX2DrawDone();
|
||||
|
||||
enum class GX2CallbackEventType
|
||||
{
|
||||
|
||||
@ -69,6 +69,7 @@ void gx2Export_GX2SampleBottomGPUCycle(PPCInterpreter_t* hCPU)
|
||||
// Whats a good solution here? Should we implement it correctly and instead rely on graphic pack patches to patch out the dynamic scaling?
|
||||
// some known affected games: Wind Waker HD, Super Mario 3D World
|
||||
|
||||
GX2::GX2ReserveCmdSpace(2);
|
||||
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SAMPLE_TIMER, 1));
|
||||
gx2WriteGather_submitU32AsBE(hCPU->gpr[3]);
|
||||
osLib_returnFromFunction(hCPU, 0);
|
||||
|
||||
@ -648,6 +648,7 @@ namespace GX2
|
||||
else
|
||||
{
|
||||
// legacy style
|
||||
GX2ReserveCmdSpace(3);
|
||||
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_HLE_SPECIAL_STATE, 2));
|
||||
gx2WriteGather_submitU32AsBE((uint32)stateId); // state id
|
||||
gx2WriteGather_submitU32AsBE(isEnabled); // enable/disable bool
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "Cafe/OS/libs/nn_common.h"
|
||||
#include "nn_ac.h"
|
||||
#include "Common/socket.h"
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
#include <iphlpapi.h>
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "util/crypto/aes128.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "Cemu/napi/napi.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
namespace nn
|
||||
{
|
||||
|
||||
@ -8,23 +8,8 @@
|
||||
#include "Common/socket.h"
|
||||
|
||||
#if BOOST_OS_UNIX
|
||||
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAESHUTDOWN ESHUTDOWN
|
||||
#define WSAECONNABORTED ECONNABORTED
|
||||
#define WSAHOST_NOT_FOUND EAI_NONAME
|
||||
#define WSAENOTCONN ENOTCONN
|
||||
|
||||
#define GETLASTERR errno
|
||||
|
||||
#endif // BOOST_OS_UNIX
|
||||
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
#define GETLASTERR WSAGetLastError()
|
||||
|
||||
#endif //BOOST_OS_WINDOWS
|
||||
#include <netinet/tcp.h>
|
||||
#endif
|
||||
|
||||
#define WU_AF_INET 2
|
||||
|
||||
|
||||
@ -134,7 +134,7 @@ void padscoreExport_WPADGetInfoAsync(PPCInterpreter_t* hCPU)
|
||||
ppcDefineParamU32(channel, 0);
|
||||
ppcDefineParamStructPtr(wpadInfo, WPADInfo_t, 1);
|
||||
ppcDefineParamMPTR(callbackFunc, 2);
|
||||
cemuLog_log(LogType::InputAPI, "WPADGetInfoAsync({}, 0x{:08x}, 0x{:08x})", channel, fmt::ptr(wpadInfo), callbackFunc);
|
||||
cemuLog_log(LogType::InputAPI, "WPADGetInfoAsync({}, 0x{:08x}, 0x{:08x})", channel, memory_getVirtualOffsetFromPointer(wpadInfo), callbackFunc);
|
||||
|
||||
if (channel < InputManager::kMaxWPADControllers)
|
||||
{
|
||||
|
||||
7
src/Cafe/TitleList/GameInfo.cpp
Normal file
7
src/Cafe/TitleList/GameInfo.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "GameInfo.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
fs::path GameInfo2::GetSaveFolder()
|
||||
{
|
||||
return ActiveSettings::GetMlcPath(fmt::format("usr/save/{:08x}/{:08x}", (GetBaseTitleId() >> 32), GetBaseTitleId() & 0xFFFFFFFF));
|
||||
}
|
||||
@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "config/CemuConfig.h"
|
||||
#include "TitleInfo.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
class GameInfo2
|
||||
{
|
||||
@ -116,10 +113,7 @@ public:
|
||||
return m_aoc.front().GetAppTitleVersion();
|
||||
}
|
||||
|
||||
fs::path GetSaveFolder()
|
||||
{
|
||||
return ActiveSettings::GetMlcPath(fmt::format("usr/save/{:08x}/{:08x}", (GetBaseTitleId() >> 32), GetBaseTitleId() & 0xFFFFFFFF));
|
||||
}
|
||||
fs::path GetSaveFolder();
|
||||
|
||||
private:
|
||||
bool IsPrioritizedVersionOrFormat(const TitleInfo& currentTitle, const TitleInfo& newTitle)
|
||||
|
||||
@ -8,6 +8,7 @@ add_library(CemuComponents
|
||||
Logging/CemuLogging.h
|
||||
napi/napi_act.cpp
|
||||
napi/napi_ec.cpp
|
||||
napi/napi.cpp
|
||||
napi/napi.h
|
||||
napi/napi_helper.cpp
|
||||
napi/napi_helper.h
|
||||
@ -40,6 +41,8 @@ endif()
|
||||
|
||||
set_property(TARGET CemuComponents PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuComponents)
|
||||
|
||||
target_include_directories(CemuComponents PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuComponents PRIVATE
|
||||
|
||||
@ -22,7 +22,10 @@ namespace shim
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
@ -680,4 +683,4 @@ void DiscordRPCLite::WorkerThread(std::string applicationId)
|
||||
pipe.SendPresenceUpdate({});
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(75));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
12
src/Cemu/napi/napi.cpp
Normal file
12
src/Cemu/napi/napi.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "napi.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "config/NetworkSettings.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
namespace NAPI
|
||||
{
|
||||
NetworkService AuthInfo::GetService() const
|
||||
{
|
||||
return serviceOverwrite.value_or(ActiveSettings::GetNetworkService());
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
#include "config/CemuConfig.h" // for ConsoleLanguage
|
||||
#include "config/NetworkSettings.h" // for NetworkService
|
||||
#include "config/ActiveSettings.h" // for GetNetworkService()
|
||||
|
||||
enum class NetworkService;
|
||||
enum class CafeConsoleRegion;
|
||||
enum class CafeConsoleLanguage;
|
||||
|
||||
enum class NAPI_RESULT
|
||||
{
|
||||
@ -43,10 +44,7 @@ namespace NAPI
|
||||
// service selection, if not set fall back to global setting
|
||||
std::optional<NetworkService> serviceOverwrite;
|
||||
|
||||
NetworkService GetService() const
|
||||
{
|
||||
return serviceOverwrite.value_or(ActiveSettings::GetNetworkService());
|
||||
}
|
||||
NetworkService GetService() const;
|
||||
};
|
||||
|
||||
bool NAPI_MakeAuthInfoFromCurrentAccount(AuthInfo& authInfo); // helper function. Returns false if online credentials/dumped files are not available
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
#include "Common/precompiled.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "napi.h"
|
||||
#include "napi_helper.h"
|
||||
|
||||
#include "curl/curl.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "Cafe/IOSU/legacy/iosu_crypto.h"
|
||||
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "util/helpers/StringHelpers.h"
|
||||
#include "util/highresolutiontimer/HighResolutionTimer.h"
|
||||
#include "config/LaunchSettings.h"
|
||||
|
||||
namespace NAPI
|
||||
{
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#include "Common/precompiled.h"
|
||||
#include "Cemu/ncrypto/ncrypto.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "config/CemuConfig.h"
|
||||
|
||||
#include "openssl/bn.h"
|
||||
#include "openssl/ec.h"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "Common/betype.h"
|
||||
#include "config/CemuConfig.h" // for ConsoleRegion
|
||||
|
||||
enum class CafeConsoleRegion;
|
||||
|
||||
/* OpenSSL forward declarations */
|
||||
typedef struct ec_key_st EC_KEY;
|
||||
|
||||
@ -53,14 +53,11 @@ if(LINUX)
|
||||
)
|
||||
endif()
|
||||
|
||||
# All the targets wanting to use the precompiled.h header
|
||||
# have to link to CemuCommon
|
||||
target_precompile_headers(CemuCommon PUBLIC precompiled.h)
|
||||
# CemuCommon always builts the precompiled header
|
||||
target_precompile_headers(CemuCommon PRIVATE precompiled.h)
|
||||
target_include_directories(CemuCommon PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuCommon PRIVATE
|
||||
Boost::nowide
|
||||
Boost::filesystem
|
||||
glm::glm
|
||||
)
|
||||
|
||||
@ -69,6 +66,12 @@ if (UNIX AND NOT APPLE)
|
||||
endif()
|
||||
|
||||
# PUBLIC because:
|
||||
# - boost/nowide/convert.hpp is included in precompiled.h
|
||||
# - boost/predef/os.h is included in platform.h
|
||||
# - fmt/core.h is included in precompiled.h
|
||||
target_link_libraries(CemuCommon PUBLIC Boost::headers fmt::fmt)
|
||||
target_link_libraries(CemuCommon PUBLIC
|
||||
Threads::Threads # necessary because some targets may need -pthreads
|
||||
Boost::nowide
|
||||
Boost::headers
|
||||
fmt::fmt
|
||||
)
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
#include "Common/FileStream.h"
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
uint16 ELFSymbolTable::FindSection(int type, const std::string_view& name)
|
||||
{
|
||||
@ -33,7 +35,7 @@ ELFSymbolTable::ELFSymbolTable()
|
||||
{
|
||||
// create file handle
|
||||
int fd = open("/proc/self/exe", O_RDONLY);
|
||||
if (!fd)
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
// retrieve file size.
|
||||
|
||||
@ -75,11 +75,11 @@
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <ranges>
|
||||
#include <variant>
|
||||
|
||||
#include <boost/predef.h>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
|
||||
@ -3,14 +3,32 @@
|
||||
#if BOOST_OS_WINDOWS
|
||||
|
||||
#include <WinSock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
typedef int socklen_t;
|
||||
|
||||
#else
|
||||
#define GETLASTERR WSAGetLastError()
|
||||
|
||||
#elif BOOST_OS_UNIX
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#define WSAEWOULDBLOCK EWOULDBLOCK
|
||||
#define WSAEINPROGRESS EINPROGRESS
|
||||
#define WSAESHUTDOWN ESHUTDOWN
|
||||
#define WSAECONNABORTED ECONNABORTED
|
||||
#define WSAHOST_NOT_FOUND EAI_NONAME
|
||||
#define WSAENOTCONN ENOTCONN
|
||||
|
||||
#define GETLASTERR errno
|
||||
|
||||
#define SOCKET int
|
||||
#define closesocket close
|
||||
#define SOCKET_ERROR -1
|
||||
#define INVALID_SOCKET -1
|
||||
|
||||
#endif
|
||||
#endif // BOOST_OS_UNIX
|
||||
|
||||
@ -7,12 +7,10 @@ fs::path findPathCI(const fs::path& path)
|
||||
|
||||
fs::path fName = path.filename();
|
||||
fs::path parentPath = path.parent_path();
|
||||
if (!fs::exists(parentPath))
|
||||
{
|
||||
auto CIParent = findPathCI(parentPath);
|
||||
if (fs::exists(CIParent))
|
||||
return findPathCI(CIParent / fName);
|
||||
}
|
||||
if (parentPath.empty())
|
||||
parentPath = ".";
|
||||
else if (!fs::exists(parentPath))
|
||||
parentPath = findPathCI(parentPath);
|
||||
|
||||
std::error_code listErr;
|
||||
for (auto&& dirEntry : fs::directory_iterator(parentPath, listErr))
|
||||
|
||||
@ -7,6 +7,8 @@ add_library(CemuAudio
|
||||
|
||||
set_property(TARGET CemuAudio PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuAudio)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(CemuAudio PRIVATE
|
||||
DirectSoundAPI.cpp
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#include "Cafe/GameProfile/GameProfile.h"
|
||||
#include "Cafe/IOSU/legacy/iosu_crypto.h"
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "Cemu/Logging/CemuLogging.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "config/LaunchSettings.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "Cafe/HW/Latte/Core/Latte.h"
|
||||
|
||||
void ActiveSettings::SetPaths(bool isPortableMode,
|
||||
const fs::path& executablePath,
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
#include "config/CemuConfig.h"
|
||||
#include "config/NetworkSettings.h"
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@ add_library(CemuConfig
|
||||
|
||||
set_property(TARGET CemuConfig PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuConfig)
|
||||
|
||||
target_include_directories(CemuConfig PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuConfig PRIVATE
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
#include "config/CemuConfig.h"
|
||||
#include "WindowSystem.h"
|
||||
|
||||
#include "util/helpers/helpers.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#include "ActiveSettings.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
|
||||
void CemuConfig::SetMLCPath(fs::path path, bool save)
|
||||
{
|
||||
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
#include "ConfigValue.h"
|
||||
#include "XMLConfig.h"
|
||||
#include "util/math/vector2.h"
|
||||
#include "Cafe/Account/Account.h"
|
||||
|
||||
enum class NetworkService;
|
||||
|
||||
@ -489,7 +487,7 @@ struct CemuConfig
|
||||
// account
|
||||
struct
|
||||
{
|
||||
ConfigValueBounds<uint32> m_persistent_id{ Account::kMinPersistendId, Account::kMinPersistendId, 0xFFFFFFFF };
|
||||
ConfigValueBounds<uint32> m_persistent_id{0x80000001, 0x80000001, 0xFFFFFFFF};
|
||||
ConfigValue<bool> legacy_online_enabled{false};
|
||||
ConfigValue<int> legacy_active_service{0};
|
||||
std::unordered_map<uint32, NetworkService> service_select; // per-account service index. Key is persistentId
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "config/CemuConfig.h"
|
||||
#include "input/api/ControllerState.h"
|
||||
|
||||
namespace WindowSystem
|
||||
|
||||
@ -132,6 +132,8 @@ endif()
|
||||
|
||||
set_property(TARGET CemuWxGui PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuWxGui)
|
||||
|
||||
|
||||
target_include_directories(CemuWxGui PUBLIC "../")
|
||||
# PUBLIC because rapidjson/document.h is included in ChecksumTool.h
|
||||
|
||||
@ -1,14 +1,10 @@
|
||||
#include "wxgui/wxgui.h"
|
||||
#include "wxgui/GameUpdateWindow.h"
|
||||
#include "util/helpers/helpers.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include "util/helpers/SystemException.h"
|
||||
#include "wxgui/CemuApp.h"
|
||||
#include "Cafe/TitleList/GameInfo.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "wxgui/helpers/wxHelpers.h"
|
||||
#include "wxHelper.h"
|
||||
|
||||
wxString _GetTitleIdTypeStr(TitleId titleId)
|
||||
{
|
||||
|
||||
@ -131,7 +131,7 @@ void GraphicPacksWindow2::FillGraphicPackList() const
|
||||
auto tmp_text = m_graphic_pack_tree->GetItemText(node);
|
||||
m_graphic_pack_tree->SetItemText(node, tmp_text + " (may not be compatible with Vulkan)");
|
||||
}
|
||||
else if (p->GetVersion() != 3 && p->GetVersion() != 4 && p->GetVersion() != 5 && p->GetVersion() != 6 && p->GetVersion() != GraphicPack2::GFXPACK_VERSION_7)
|
||||
else if (p->GetVersion() != 3 && p->GetVersion() != 4 && p->GetVersion() != 5 && p->GetVersion() != 6 && p->GetVersion() != GraphicPack2::GFXPACK_VERSION_7 && p->GetVersion() != GraphicPack2::GFXPACK_VERSION_8)
|
||||
{
|
||||
auto tmp_text = m_graphic_pack_tree->GetItemText(node);
|
||||
m_graphic_pack_tree->SetItemText(node, tmp_text + " (Unsupported version)");
|
||||
|
||||
@ -43,7 +43,7 @@ VulkanCanvas::VulkanCanvas(wxWindow* parent, const wxSize& size, bool is_main_wi
|
||||
auto msg = formatWxString(_("Error when initializing Vulkan renderer:\n{}"), ex.what());
|
||||
wxMessageDialog dialog(this, msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
dialog.ShowModal();
|
||||
exit(0);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "config/CemuConfig.h"
|
||||
#include "config/XMLConfig.h"
|
||||
#include "util/math/vector2.h"
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ endif ()
|
||||
|
||||
set_property(TARGET imguiImpl PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(imguiImpl)
|
||||
|
||||
target_include_directories(imguiImpl PUBLIC "../")
|
||||
|
||||
# imgui source files
|
||||
|
||||
@ -43,6 +43,8 @@ add_library(CemuInput
|
||||
|
||||
set_property(TARGET CemuInput PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuInput)
|
||||
|
||||
if(WIN32)
|
||||
# XInput
|
||||
target_sources(CemuInput PRIVATE
|
||||
|
||||
@ -232,7 +232,7 @@ ControllerState NativeWiimoteController::raw_state()
|
||||
for (int i = 0; i < std::numeric_limits<uint64>::digits; i++)
|
||||
{
|
||||
// OR with base buttons
|
||||
if((buttons & (1 << i)))
|
||||
if((buttons & (1ULL << i)))
|
||||
result.buttons.SetButtonState(i, true);
|
||||
}
|
||||
result.axis = classic.left_axis;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "L2CapWiimote.h"
|
||||
#include <bluetooth/l2cap.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
constexpr auto comparator = [](const bdaddr_t& a, const bdaddr_t& b) {
|
||||
return bacmp(&a, &b);
|
||||
@ -145,4 +147,4 @@ bool L2CapWiimote::operator==(const WiimoteDevice& rhs) const
|
||||
if (!mote)
|
||||
return false;
|
||||
return bacmp(&m_addr, &mote->m_addr) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,8 +255,14 @@ int main(int argc, char* argv[])
|
||||
|
||||
#else
|
||||
|
||||
int BreathOfTheWildChildProcessMain();
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#if BOOST_OS_LINUX
|
||||
if (getenv("CEMU_DETECT_RADV") != nullptr)
|
||||
return BreathOfTheWildChildProcessMain();
|
||||
#endif
|
||||
|
||||
#if BOOST_OS_LINUX || BOOST_OS_BSD
|
||||
XInitThreads();
|
||||
#endif
|
||||
|
||||
@ -2,6 +2,8 @@ add_library(CemuResource)
|
||||
|
||||
set_property(TARGET CemuResource PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuResource)
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
# icon resources
|
||||
|
||||
@ -89,6 +89,8 @@ endif()
|
||||
|
||||
set_property(TARGET CemuUtil PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||
|
||||
cemu_use_precompiled_header(CemuUtil)
|
||||
|
||||
target_include_directories(CemuUtil PUBLIC "../")
|
||||
|
||||
target_link_libraries(CemuUtil PRIVATE
|
||||
|
||||
Loading…
Reference in New Issue
Block a user