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:
@@ -11,13 +11,13 @@ assignees: ''
|
||||
Please keep in mind Cemu is EXPERIMENTAL SOFTWARE.
|
||||
|
||||
Please read the FAQ:
|
||||
https://cemu.info/faq.html/
|
||||
https://cemu.info/faq.html
|
||||
|
||||
THIS IS NOT A SUPPORT FORUM, FOR SUPPORT GO TO:
|
||||
https://discord.com/invite/5psYsup/
|
||||
https://discord.com/invite/5psYsup
|
||||
|
||||
If the FAQ does not answer your question, please go to:
|
||||
https://discord.com/invite/5psYsup/
|
||||
https://discord.com/invite/5psYsup
|
||||
|
||||
When submitting an issue, please check the following:
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ bin/debugger/*
|
||||
bin/sdcard/*
|
||||
bin/screenshots/*
|
||||
bin/dump/*
|
||||
bin/cafeLibs/*
|
||||
|
||||
!bin/shaderCache/info.txt
|
||||
bin/shaderCache/*
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
# Mario Kart 8 (JPN)
|
||||
|
||||
[CPU]
|
||||
cpuMode = Singlecore-Recompiler
|
||||
# Mario Kart 8 (JPN)
|
||||
@@ -1,4 +1 @@
|
||||
# Mario Kart 8 (USA)
|
||||
|
||||
[CPU]
|
||||
cpuMode = Singlecore-Recompiler
|
||||
# Mario Kart 8 (USA)
|
||||
@@ -1,4 +1 @@
|
||||
# Mario Kart 8 (EUR)
|
||||
|
||||
[CPU]
|
||||
cpuMode = Singlecore-Recompiler
|
||||
# Mario Kart 8 (EUR)
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "Account.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"
|
||||
#include "Common/FileStream.h"
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
|
||||
#include <random>
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
|
||||
std::vector<Account> Account::s_account_list;
|
||||
|
||||
@@ -460,15 +461,14 @@ OnlineValidator Account::ValidateOnlineFiles() const
|
||||
|
||||
void Account::ParseFile(class FileStream* file)
|
||||
{
|
||||
std::vector<std::string> buffer;
|
||||
|
||||
std::string tmp;
|
||||
while (file->readLine(tmp))
|
||||
buffer.emplace_back(tmp);
|
||||
for (const auto& s : buffer)
|
||||
std::vector<uint8> buffer;
|
||||
buffer.resize(file->GetSize());
|
||||
if( file->readData(buffer.data(), buffer.size()) != buffer.size())
|
||||
throw std::system_error(AccountErrc::ParseError);
|
||||
for (const auto& s : StringHelpers::StringLineIterator(buffer))
|
||||
{
|
||||
std::string_view view = s;
|
||||
const auto find = view.find(L'=');
|
||||
const auto find = view.find('=');
|
||||
if (find == std::string_view::npos)
|
||||
continue;
|
||||
|
||||
|
||||
+16
-2
@@ -240,6 +240,8 @@ add_library(CemuCafe
|
||||
IOSU/nn/iosu_nn_service.h
|
||||
IOSU/PDM/iosu_pdm.cpp
|
||||
IOSU/PDM/iosu_pdm.h
|
||||
IOSU/ODM/iosu_odm.cpp
|
||||
IOSU/ODM/iosu_odm.h
|
||||
OS/common/OSCommon.cpp
|
||||
OS/common/OSCommon.h
|
||||
OS/common/OSUtil.h
|
||||
@@ -399,6 +401,8 @@ add_library(CemuCafe
|
||||
OS/libs/nn_idbe/nn_idbe.h
|
||||
OS/libs/nn_ndm/nn_ndm.cpp
|
||||
OS/libs/nn_ndm/nn_ndm.h
|
||||
OS/libs/nn_spm/nn_spm.cpp
|
||||
OS/libs/nn_spm/nn_spm.h
|
||||
OS/libs/nn_nfp/AmiiboCrypto.h
|
||||
OS/libs/nn_nfp/nn_nfp.cpp
|
||||
OS/libs/nn_nfp/nn_nfp.h
|
||||
@@ -406,6 +410,18 @@ add_library(CemuCafe
|
||||
OS/libs/nn_nim/nn_nim.h
|
||||
OS/libs/nn_olv/nn_olv.cpp
|
||||
OS/libs/nn_olv/nn_olv.h
|
||||
OS/libs/nn_olv/nn_olv_Common.cpp
|
||||
OS/libs/nn_olv/nn_olv_Common.h
|
||||
OS/libs/nn_olv/nn_olv_InitializeTypes.cpp
|
||||
OS/libs/nn_olv/nn_olv_InitializeTypes.h
|
||||
OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.cpp
|
||||
OS/libs/nn_olv/nn_olv_DownloadCommunityTypes.h
|
||||
OS/libs/nn_olv/nn_olv_UploadCommunityTypes.cpp
|
||||
OS/libs/nn_olv/nn_olv_UploadCommunityTypes.h
|
||||
OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.cpp
|
||||
OS/libs/nn_olv/nn_olv_UploadFavoriteTypes.h
|
||||
OS/libs/nn_olv/nn_olv_PostTypes.cpp
|
||||
OS/libs/nn_olv/nn_olv_PostTypes.h
|
||||
OS/libs/nn_pdm/nn_pdm.cpp
|
||||
OS/libs/nn_pdm/nn_pdm.h
|
||||
OS/libs/nn_save/nn_save.cpp
|
||||
@@ -454,8 +470,6 @@ add_library(CemuCafe
|
||||
OS/RPL/rpl_structs.h
|
||||
OS/RPL/rpl_symbol_storage.cpp
|
||||
OS/RPL/rpl_symbol_storage.h
|
||||
TitleList/BaseInfo.cpp
|
||||
TitleList/BaseInfo.h
|
||||
TitleList/GameInfo.h
|
||||
TitleList/ParsedMetaXml.h
|
||||
TitleList/SaveInfo.cpp
|
||||
|
||||
+168
-68
@@ -44,8 +44,9 @@
|
||||
// IOSU initializer functions
|
||||
#include "Cafe/IOSU/kernel/iosu_kernel.h"
|
||||
#include "Cafe/IOSU/fsa/iosu_fsa.h"
|
||||
#include "Cafe/IOSU/ODM/iosu_odm.h"
|
||||
|
||||
// Cafe OS initializer functions
|
||||
// Cafe OS initializer and shutdown functions
|
||||
#include "Cafe/OS/libs/avm/avm.h"
|
||||
#include "Cafe/OS/libs/drmapp/drmapp.h"
|
||||
#include "Cafe/OS/libs/TCL/TCL.h"
|
||||
@@ -60,6 +61,7 @@
|
||||
#include "Cafe/OS/libs/nn_cmpt/nn_cmpt.h"
|
||||
#include "Cafe/OS/libs/nn_ccr/nn_ccr.h"
|
||||
#include "Cafe/OS/libs/nn_temp/nn_temp.h"
|
||||
#include "Cafe/OS/libs/nn_save/nn_save.h"
|
||||
|
||||
// HW interfaces
|
||||
#include "Cafe/HW/SI/si.h"
|
||||
@@ -280,7 +282,7 @@ struct
|
||||
|
||||
static_assert(sizeof(SharedDataEntry) == 0x1C);
|
||||
|
||||
uint32 loadSharedData()
|
||||
uint32 LoadSharedData()
|
||||
{
|
||||
// check if font files are dumped
|
||||
bool hasAllShareddataFiles = true;
|
||||
@@ -419,25 +421,6 @@ void cemu_initForGame()
|
||||
coreinit::OSRunThread(initialThread, PPCInterpreter_makeCallableExportDepr(coreinit_start), 0, nullptr);
|
||||
// init AX and start AX I/O thread
|
||||
snd_core::AXOut_init();
|
||||
// init ppc recompiler
|
||||
PPCRecompiler_init();
|
||||
}
|
||||
|
||||
void cemu_deinitForGame()
|
||||
{
|
||||
// reset audio
|
||||
snd_core::AXOut_reset();
|
||||
snd_core::reset();
|
||||
// reset alarms
|
||||
coreinit::OSAlarm_resetAll();
|
||||
// delete all threads
|
||||
PPCCore_deleteAllThreads();
|
||||
// reset mount paths
|
||||
fsc_unmountAll();
|
||||
// reset RPL loader
|
||||
RPLLoader_ResetState();
|
||||
// reset GX2
|
||||
GX2::_GX2DriverReset();
|
||||
}
|
||||
|
||||
namespace CafeSystem
|
||||
@@ -458,24 +441,34 @@ namespace CafeSystem
|
||||
|
||||
void InitVirtualMlcStorage();
|
||||
void MlcStorageMountTitle(TitleInfo& titleInfo);
|
||||
void MlcStorageUnmountAllTitles();
|
||||
|
||||
bool sLaunchModeIsStandalone = false;
|
||||
static bool s_initialized = false;
|
||||
static SystemImplementation* s_implementation{nullptr};
|
||||
bool sLaunchModeIsStandalone = false;
|
||||
std::optional<std::vector<std::string>> s_overrideArgs;
|
||||
|
||||
bool sSystemRunning = false;
|
||||
TitleId sForegroundTitleId = 0;
|
||||
|
||||
GameInfo2 sGameInfo_ForegroundTitle;
|
||||
|
||||
// initialize all subsystems which are persistent and don't depend on a game running
|
||||
void Initialize()
|
||||
{
|
||||
static bool s_initialized = false;
|
||||
if (s_initialized)
|
||||
return;
|
||||
s_initialized = true;
|
||||
// init core systems
|
||||
fsc_init();
|
||||
memory_init();
|
||||
PPCCore_init();
|
||||
RPLLoader_InitState();
|
||||
// allocate memory for all SysAllocators
|
||||
// must happen before all COS modules, but also before iosu::kernel::Init()
|
||||
// must happen before COS module init, but also before iosu::kernel::Initialize()
|
||||
SysAllocatorContainer::GetInstance().Initialize();
|
||||
// init IOSU
|
||||
iosuCrypto_init();
|
||||
iosu::kernel::Initialize();
|
||||
iosu::fsa::Initialize();
|
||||
iosuIoctl_init();
|
||||
@@ -488,6 +481,7 @@ namespace CafeSystem
|
||||
iosu::boss_init();
|
||||
iosu::nim::Initialize();
|
||||
iosu::pdm::Initialize();
|
||||
iosu::odm::Initialize();
|
||||
// init Cafe OS
|
||||
avm::Initialize();
|
||||
drmapp::Initialize();
|
||||
@@ -505,14 +499,46 @@ namespace CafeSystem
|
||||
HW_SI::Initialize();
|
||||
}
|
||||
|
||||
void SetImplementation(SystemImplementation* impl)
|
||||
{
|
||||
s_implementation = impl;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
cemu_assert_debug(s_initialized);
|
||||
// if a title is running, shut it down
|
||||
if (sSystemRunning)
|
||||
ShutdownTitle();
|
||||
// shutdown persistent subsystems
|
||||
iosu::odm::Shutdown();
|
||||
iosu::act::Stop();
|
||||
iosu::mcp::Shutdown();
|
||||
iosu::fsa::Shutdown();
|
||||
s_initialized = false;
|
||||
}
|
||||
|
||||
std::string GetInternalVirtualCodeFolder()
|
||||
{
|
||||
return "/internal/current_title/code/";
|
||||
}
|
||||
|
||||
void MountBaseDirectories()
|
||||
{
|
||||
const auto mlc = ActiveSettings::GetMlcPath();
|
||||
FSCDeviceHostFS_Mount("/cemuBossStorage/", _pathToUtf8(mlc / "usr/boss/"), FSC_PRIORITY_BASE);
|
||||
FSCDeviceHostFS_Mount("/vol/storage_mlc01/", _pathToUtf8(mlc / ""), FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
void UnmountBaseDirectories()
|
||||
{
|
||||
fsc_unmount("/vol/storage_mlc01/", FSC_PRIORITY_BASE);
|
||||
fsc_unmount("/cemuBossStorage/", FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
STATUS_CODE LoadAndMountForegroundTitle(TitleId titleId)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Mounting title {:016x}", (uint64)titleId);
|
||||
cemuLog_log(LogType::Force, "Mounting title {:016x}", (uint64)titleId);
|
||||
sGameInfo_ForegroundTitle = CafeTitleList::GetGameInfo(titleId);
|
||||
if (!sGameInfo_ForegroundTitle.IsValid())
|
||||
{
|
||||
@@ -571,10 +597,33 @@ namespace CafeSystem
|
||||
return STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
void UnmountForegroundTitle()
|
||||
{
|
||||
if(sLaunchModeIsStandalone)
|
||||
return;
|
||||
cemu_assert_debug(sGameInfo_ForegroundTitle.IsValid()); // unmounting title which was never mounted?
|
||||
if (!sGameInfo_ForegroundTitle.IsValid())
|
||||
return;
|
||||
sGameInfo_ForegroundTitle.GetBase().Unmount("/vol/content");
|
||||
sGameInfo_ForegroundTitle.GetBase().Unmount(GetInternalVirtualCodeFolder());
|
||||
if (sGameInfo_ForegroundTitle.HasUpdate())
|
||||
{
|
||||
if(auto& update = sGameInfo_ForegroundTitle.GetUpdate(); update.IsValid())
|
||||
{
|
||||
update.Unmount("/vol/content");
|
||||
update.Unmount(GetInternalVirtualCodeFolder());
|
||||
}
|
||||
}
|
||||
auto aocList = sGameInfo_ForegroundTitle.GetAOC();
|
||||
if (!aocList.empty())
|
||||
{
|
||||
TitleInfo& titleAOC = aocList[0];
|
||||
titleAOC.Unmount(fmt::format("/vol/aoc{:016x}", titleAOC.GetAppTitleId()));
|
||||
}
|
||||
}
|
||||
|
||||
STATUS_CODE SetupExecutable()
|
||||
{
|
||||
// mount mlc directories
|
||||
fscDeviceHostFS_mapBaseDirectories_deprecated();
|
||||
// set rpx path from cos.xml if available
|
||||
_pathToBaseExecutable = _pathToExecutable;
|
||||
if (!sLaunchModeIsStandalone)
|
||||
@@ -609,26 +658,37 @@ namespace CafeSystem
|
||||
return STATUS_CODE::SUCCESS;
|
||||
}
|
||||
|
||||
void SetupMemorySpace()
|
||||
{
|
||||
memory_mapForCurrentTitle();
|
||||
LoadSharedData();
|
||||
}
|
||||
|
||||
void DestroyMemorySpace()
|
||||
{
|
||||
memory_unmapForCurrentTitle();
|
||||
}
|
||||
|
||||
STATUS_CODE PrepareForegroundTitle(TitleId titleId)
|
||||
{
|
||||
CafeTitleList::WaitForMandatoryScan();
|
||||
sLaunchModeIsStandalone = false;
|
||||
_pathToExecutable.clear();
|
||||
TitleIdParser tip(titleId);
|
||||
if (tip.GetType() == TitleIdParser::TITLE_TYPE::AOC || tip.GetType() == TitleIdParser::TITLE_TYPE::BASE_TITLE_UPDATE)
|
||||
cemuLog_log(LogType::Force, "Launched titleId is not the base of a title");
|
||||
|
||||
// mount title folders
|
||||
// mount mlc storage
|
||||
MountBaseDirectories();
|
||||
// mount title folders
|
||||
STATUS_CODE r = LoadAndMountForegroundTitle(titleId);
|
||||
if (r != STATUS_CODE::SUCCESS)
|
||||
return r;
|
||||
// map memory
|
||||
memory_mapForCurrentTitle();
|
||||
// load RPX
|
||||
r = SetupExecutable();
|
||||
// setup memory space and PPC recompiler
|
||||
SetupMemorySpace();
|
||||
PPCRecompiler_init();
|
||||
r = SetupExecutable(); // load RPX
|
||||
if (r != STATUS_CODE::SUCCESS)
|
||||
return r;
|
||||
|
||||
loadSharedData();
|
||||
InitVirtualMlcStorage();
|
||||
return STATUS_CODE::SUCCESS;
|
||||
}
|
||||
@@ -667,10 +727,11 @@ namespace CafeSystem
|
||||
uint32 h = generateHashFromRawRPXData(execData->data(), execData->size());
|
||||
sForegroundTitleId = 0xFFFFFFFF00000000ULL | (uint64)h;
|
||||
cemuLog_log(LogType::Force, "Generated placeholder TitleId: {:016x}", sForegroundTitleId);
|
||||
// load executable
|
||||
memory_mapForCurrentTitle();
|
||||
SetupExecutable();
|
||||
loadSharedData();
|
||||
// setup memory space and ppc recompiler
|
||||
SetupMemorySpace();
|
||||
PPCRecompiler_init();
|
||||
// load executable
|
||||
SetupExecutable();
|
||||
InitVirtualMlcStorage();
|
||||
return STATUS_CODE::SUCCESS;
|
||||
}
|
||||
@@ -717,6 +778,13 @@ namespace CafeSystem
|
||||
return sGameInfo_ForegroundTitle.GetVersion();
|
||||
}
|
||||
|
||||
uint32 GetForegroundTitleSDKVersion()
|
||||
{
|
||||
if (sLaunchModeIsStandalone)
|
||||
return 999999;
|
||||
return sGameInfo_ForegroundTitle.GetSDKVersion();
|
||||
}
|
||||
|
||||
CafeConsoleRegion GetForegroundTitleRegion()
|
||||
{
|
||||
if (sLaunchModeIsStandalone)
|
||||
@@ -737,6 +805,13 @@ namespace CafeSystem
|
||||
return applicationName;
|
||||
}
|
||||
|
||||
uint32 GetForegroundTitleOlvAccesskey()
|
||||
{
|
||||
if (sLaunchModeIsStandalone)
|
||||
return -1;
|
||||
return sGameInfo_ForegroundTitle.GetBase().GetMetaInfo()->GetOlvAccesskey();
|
||||
}
|
||||
|
||||
std::string GetForegroundTitleArgStr()
|
||||
{
|
||||
if (sLaunchModeIsStandalone)
|
||||
@@ -747,6 +822,26 @@ namespace CafeSystem
|
||||
return sGameInfo_ForegroundTitle.GetBase().GetArgStr();
|
||||
}
|
||||
|
||||
// when switching titles custom parameters can be passed, returns true if override args are used
|
||||
bool GetOverrideArgStr(std::vector<std::string>& args)
|
||||
{
|
||||
args.clear();
|
||||
if(!s_overrideArgs)
|
||||
return false;
|
||||
args = *s_overrideArgs;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetOverrideArgs(std::span<std::string> args)
|
||||
{
|
||||
s_overrideArgs = std::vector<std::string>(args.begin(), args.end());
|
||||
}
|
||||
|
||||
void UnsetOverrideArgs()
|
||||
{
|
||||
s_overrideArgs = std::nullopt;
|
||||
}
|
||||
|
||||
// pick platform region based on title region
|
||||
CafeConsoleRegion GetPlatformRegion()
|
||||
{
|
||||
@@ -763,39 +858,32 @@ namespace CafeSystem
|
||||
|
||||
void UnmountCurrentTitle()
|
||||
{
|
||||
TitleInfo& titleBase = sGameInfo_ForegroundTitle.GetBase();
|
||||
if (titleBase.IsValid())
|
||||
titleBase.UnmountAll();
|
||||
if (sGameInfo_ForegroundTitle.HasUpdate())
|
||||
{
|
||||
TitleInfo& titleUpdate = sGameInfo_ForegroundTitle.GetUpdate();
|
||||
if (titleUpdate.IsValid())
|
||||
titleUpdate.UnmountAll();
|
||||
}
|
||||
if (sGameInfo_ForegroundTitle.HasAOC())
|
||||
{
|
||||
auto titleInfoList = sGameInfo_ForegroundTitle.GetAOC();
|
||||
for(auto& it : titleInfoList)
|
||||
{
|
||||
if (it.IsValid())
|
||||
it.UnmountAll();
|
||||
}
|
||||
}
|
||||
fsc_unmount("/internal/code/", FSC_PRIORITY_BASE);
|
||||
UnmountForegroundTitle();
|
||||
fsc_unmount("/internal/code/", FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
void ShutdownTitle()
|
||||
{
|
||||
if(!sSystemRunning)
|
||||
return;
|
||||
coreinit::OSSchedulerEnd();
|
||||
Latte_Stop();
|
||||
coreinit::OSSchedulerEnd();
|
||||
Latte_Stop();
|
||||
// reset Cafe OS userspace modules
|
||||
snd_core::reset();
|
||||
coreinit::OSAlarm_Shutdown();
|
||||
GX2::_GX2DriverReset();
|
||||
nn::save::ResetToDefaultState();
|
||||
coreinit::__OSDeleteAllActivePPCThreads();
|
||||
RPLLoader_ResetState();
|
||||
// stop time tracking
|
||||
iosu::pdm::Stop();
|
||||
iosu::act::Stop();
|
||||
iosu::mcp::Shutdown();
|
||||
iosu::fsa::Shutdown();
|
||||
GraphicPack2::Reset();
|
||||
UnmountCurrentTitle();
|
||||
// reset Cemu subsystems
|
||||
PPCRecompiler_Shutdown();
|
||||
GraphicPack2::Reset();
|
||||
UnmountCurrentTitle();
|
||||
MlcStorageUnmountAllTitles();
|
||||
UnmountBaseDirectories();
|
||||
DestroyMemorySpace();
|
||||
sSystemRunning = false;
|
||||
}
|
||||
|
||||
@@ -845,10 +933,7 @@ namespace CafeSystem
|
||||
}
|
||||
TitleId titleId = titleInfo.GetAppTitleId();
|
||||
if (m_mlcMountedTitles.find(titleId) != m_mlcMountedTitles.end())
|
||||
{
|
||||
cemu_assert_suspicious(); // already mounted
|
||||
return;
|
||||
}
|
||||
std::string mlcStoragePath = GetMlcStoragePath(titleId);
|
||||
TitleInfo* mountTitleInfo = new TitleInfo(titleInfo);
|
||||
if (!mountTitleInfo->Mount(mlcStoragePath, "", FSC_PRIORITY_BASE))
|
||||
@@ -875,6 +960,16 @@ namespace CafeSystem
|
||||
MlcStorageMountTitle(it);
|
||||
}
|
||||
|
||||
void MlcStorageUnmountAllTitles()
|
||||
{
|
||||
for(auto& it : m_mlcMountedTitles)
|
||||
{
|
||||
std::string mlcStoragePath = GetMlcStoragePath(it.first);
|
||||
it.second->Unmount(mlcStoragePath);
|
||||
}
|
||||
m_mlcMountedTitles.clear();
|
||||
}
|
||||
|
||||
uint32 GetRPXHashBase()
|
||||
{
|
||||
return currentBaseApplicationHash;
|
||||
@@ -885,4 +980,9 @@ namespace CafeSystem
|
||||
return currentUpdatedApplicationHash;
|
||||
}
|
||||
|
||||
void RequestRecreateCanvas()
|
||||
{
|
||||
s_implementation->CafeRecreateCanvas();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,12 @@
|
||||
|
||||
namespace CafeSystem
|
||||
{
|
||||
class SystemImplementation
|
||||
{
|
||||
public:
|
||||
virtual void CafeRecreateCanvas() = 0;
|
||||
};
|
||||
|
||||
enum class STATUS_CODE
|
||||
{
|
||||
SUCCESS,
|
||||
@@ -26,17 +32,26 @@ namespace CafeSystem
|
||||
CafeSystemCallbacks* getCafeSystemCallbacks();
|
||||
|
||||
void Initialize();
|
||||
void SetImplementation(SystemImplementation* impl);
|
||||
void Shutdown();
|
||||
|
||||
STATUS_CODE PrepareForegroundTitle(TitleId titleId);
|
||||
STATUS_CODE PrepareForegroundTitleFromStandaloneRPX(const fs::path& path);
|
||||
void LaunchForegroundTitle();
|
||||
bool IsTitleRunning();
|
||||
|
||||
bool GetOverrideArgStr(std::vector<std::string>& args);
|
||||
void SetOverrideArgs(std::span<std::string> args);
|
||||
void UnsetOverrideArgs();
|
||||
|
||||
TitleId GetForegroundTitleId();
|
||||
uint16 GetForegroundTitleVersion();
|
||||
uint32 GetForegroundTitleSDKVersion();
|
||||
CafeConsoleRegion GetForegroundTitleRegion();
|
||||
CafeConsoleRegion GetPlatformRegion();
|
||||
std::string GetForegroundTitleName();
|
||||
std::string GetForegroundTitleArgStr();
|
||||
uint32 GetForegroundTitleOlvAccesskey();
|
||||
|
||||
void ShutdownTitle();
|
||||
|
||||
@@ -47,6 +62,8 @@ namespace CafeSystem
|
||||
|
||||
uint32 GetRPXHashBase();
|
||||
uint32 GetRPXHashUpdated();
|
||||
|
||||
void RequestRecreateCanvas();
|
||||
};
|
||||
|
||||
extern RPLModule* applicationRPX;
|
||||
|
||||
+39
-10
@@ -6,7 +6,7 @@ struct FSCMountPathNode
|
||||
std::string path;
|
||||
std::vector<FSCMountPathNode*> subnodes;
|
||||
FSCMountPathNode* parent;
|
||||
// device target and path (if subnodes is empty)
|
||||
// associated device target and path
|
||||
fscDeviceC* device{ nullptr };
|
||||
void* ctx{ nullptr };
|
||||
std::string deviceTargetPath; // the destination base path for the device, utf8
|
||||
@@ -17,6 +17,25 @@ struct FSCMountPathNode
|
||||
{
|
||||
}
|
||||
|
||||
void AssignDevice(fscDeviceC* device, void* ctx, std::string_view deviceBasePath)
|
||||
{
|
||||
this->device = device;
|
||||
this->ctx = ctx;
|
||||
this->deviceTargetPath = deviceBasePath;
|
||||
}
|
||||
|
||||
void UnassignDevice()
|
||||
{
|
||||
this->device = nullptr;
|
||||
this->ctx = nullptr;
|
||||
this->deviceTargetPath.clear();
|
||||
}
|
||||
|
||||
bool IsRootNode() const
|
||||
{
|
||||
return !parent;
|
||||
}
|
||||
|
||||
~FSCMountPathNode()
|
||||
{
|
||||
for (auto& itr : subnodes)
|
||||
@@ -141,9 +160,7 @@ sint32 fsc_mount(std::string_view mountPath, std::string_view targetPath, fscDev
|
||||
fscLeave();
|
||||
return FSC_STATUS_INVALID_PATH;
|
||||
}
|
||||
node->device = fscDevice;
|
||||
node->ctx = ctx;
|
||||
node->deviceTargetPath = std::move(targetPathWithSlash);
|
||||
node->AssignDevice(fscDevice, ctx, targetPathWithSlash);
|
||||
fscLeave();
|
||||
return FSC_STATUS_OK;
|
||||
}
|
||||
@@ -160,14 +177,13 @@ bool fsc_unmount(std::string_view mountPath, sint32 priority)
|
||||
}
|
||||
cemu_assert(mountPathNode->priority == priority);
|
||||
cemu_assert(mountPathNode->device);
|
||||
// delete node
|
||||
while (mountPathNode && mountPathNode->parent)
|
||||
// unassign device
|
||||
mountPathNode->UnassignDevice();
|
||||
// prune empty branch
|
||||
while (mountPathNode && !mountPathNode->IsRootNode() && mountPathNode->subnodes.empty() && !mountPathNode->device)
|
||||
{
|
||||
FSCMountPathNode* parent = mountPathNode->parent;
|
||||
cemu_assert(!(!mountPathNode->subnodes.empty() && mountPathNode->device));
|
||||
if (!mountPathNode->subnodes.empty())
|
||||
break;
|
||||
parent->subnodes.erase(std::find(parent->subnodes.begin(), parent->subnodes.end(), mountPathNode));
|
||||
std::erase(parent->subnodes, mountPathNode);
|
||||
delete mountPathNode;
|
||||
mountPathNode = parent;
|
||||
}
|
||||
@@ -302,6 +318,15 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fscRewindDir() override
|
||||
{
|
||||
if (!dirIterator)
|
||||
return true;
|
||||
|
||||
dirIterator->index = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void addUniqueDirEntry(const FSCDirEntry& dirEntry)
|
||||
{
|
||||
// skip if already in list
|
||||
@@ -378,6 +403,7 @@ FSCVirtualFile* fsc_open(const char* path, FSC_ACCESS_FLAG accessFlags, sint32*
|
||||
{
|
||||
// return first found file
|
||||
cemu_assert_debug(HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE));
|
||||
fscVirtualFile->m_isAppend = HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::IS_APPEND);
|
||||
fscLeave();
|
||||
return fscVirtualFile;
|
||||
}
|
||||
@@ -598,6 +624,9 @@ uint32 fsc_writeFile(FSCVirtualFile* fscFile, void* buffer, uint32 size)
|
||||
fscLeave();
|
||||
return 0;
|
||||
}
|
||||
if (fscFile->m_isAppend)
|
||||
fsc_setFileSeek(fscFile, fsc_getFileSize(fscFile));
|
||||
|
||||
uint32 fscStatus = fscFile->fscWriteData(buffer, size);
|
||||
fscLeave();
|
||||
return fscStatus;
|
||||
|
||||
@@ -24,7 +24,10 @@ enum class FSC_ACCESS_FLAG : uint8
|
||||
// which types can be opened
|
||||
// invalid operation if neither is set
|
||||
OPEN_DIR = (1 << 4),
|
||||
OPEN_FILE = (1 << 5)
|
||||
OPEN_FILE = (1 << 5),
|
||||
|
||||
// Writing seeks to the end of the file if set
|
||||
IS_APPEND = (1 << 6)
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(FSC_ACCESS_FLAG);
|
||||
|
||||
@@ -149,7 +152,15 @@ struct FSCVirtualFile
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool fscRewindDir()
|
||||
{
|
||||
cemu_assert_unimplemented();
|
||||
return false;
|
||||
}
|
||||
|
||||
FSCDirIteratorState* dirIterator{};
|
||||
|
||||
bool m_isAppend{ false };
|
||||
};
|
||||
|
||||
#define FSC_PRIORITY_BASE (0)
|
||||
@@ -194,7 +205,6 @@ bool FSCDeviceWUD_Mount(std::string_view mountPath, std::string_view destination
|
||||
bool FSCDeviceWUA_Mount(std::string_view mountPath, std::string_view destinationBaseDir, class ZArchiveReader* archive, sint32 priority);
|
||||
|
||||
// hostFS device
|
||||
void fscDeviceHostFS_mapBaseDirectories_deprecated();
|
||||
bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority);
|
||||
|
||||
// redirect device
|
||||
|
||||
@@ -289,13 +289,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void fscDeviceHostFS_mapBaseDirectories_deprecated()
|
||||
{
|
||||
const auto mlc = ActiveSettings::GetMlcPath();
|
||||
fsc_mount("/cemuBossStorage/", _pathToUtf8(mlc / "usr/boss/"), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
|
||||
fsc_mount("/vol/storage_mlc01/", _pathToUtf8(mlc / ""), &fscDeviceHostFSC::instance(), NULL, FSC_PRIORITY_BASE);
|
||||
}
|
||||
|
||||
bool FSCDeviceHostFS_Mount(std::string_view mountPath, std::string_view hostTargetPath, sint32 priority)
|
||||
{
|
||||
return fsc_mount(mountPath, hostTargetPath, &fscDeviceHostFSC::instance(), nullptr, priority) == FSC_STATUS_OK;
|
||||
|
||||
@@ -100,11 +100,6 @@ PPCInterpreter_t* PPCCore_executeCallbackInternal(uint32 functionMPTR)
|
||||
return hCPU;
|
||||
}
|
||||
|
||||
void PPCCore_deleteAllThreads()
|
||||
{
|
||||
assert_dbg();
|
||||
}
|
||||
|
||||
void PPCCore_init()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -236,7 +236,6 @@ HLECALL PPCInterpreter_getHLECall(HLEIDX funcIndex);
|
||||
|
||||
// HLE scheduler
|
||||
|
||||
void PPCCore_deleteAllThreads();
|
||||
void PPCInterpreter_relinquishTimeslice();
|
||||
|
||||
void PPCCore_boostQuantum(sint32 numCycles);
|
||||
|
||||
@@ -289,11 +289,16 @@ void PPCRecompiler_recompileAtAddress(uint32 address)
|
||||
bool r = PPCRecompiler_makeRecompiledFunctionActive(address, range, func, functionEntryPoints);
|
||||
}
|
||||
|
||||
std::thread s_threadRecompiler;
|
||||
std::atomic_bool s_recompilerThreadStopSignal{false};
|
||||
|
||||
void PPCRecompiler_thread()
|
||||
{
|
||||
SetThreadName("PPCRecompiler_thread");
|
||||
while (true)
|
||||
{
|
||||
if(s_recompilerThreadStopSignal)
|
||||
return;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
// asynchronous recompilation:
|
||||
// 1) take address from queue
|
||||
@@ -326,7 +331,12 @@ void PPCRecompiler_thread()
|
||||
|
||||
#define PPC_REC_ALLOC_BLOCK_SIZE (4*1024*1024) // 4MB
|
||||
|
||||
std::bitset<(MEMORY_CODEAREA_ADDR + MEMORY_CODEAREA_SIZE) / PPC_REC_ALLOC_BLOCK_SIZE> ppcRecompiler_reservedBlockMask;
|
||||
constexpr uint32 PPCRecompiler_GetNumAddressSpaceBlocks()
|
||||
{
|
||||
return (MEMORY_CODEAREA_ADDR + MEMORY_CODEAREA_SIZE + PPC_REC_ALLOC_BLOCK_SIZE - 1) / PPC_REC_ALLOC_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
std::bitset<PPCRecompiler_GetNumAddressSpaceBlocks()> ppcRecompiler_reservedBlockMask;
|
||||
|
||||
void PPCRecompiler_reserveLookupTableBlock(uint32 offset)
|
||||
{
|
||||
@@ -496,16 +506,9 @@ void PPCRecompiler_init()
|
||||
MemMapper::AllocateMemory(&(ppcRecompilerInstanceData->_x64XMM_xorNegateMaskBottom), sizeof(PPCRecompilerInstanceData_t) - offsetof(PPCRecompilerInstanceData_t, _x64XMM_xorNegateMaskBottom), MemMapper::PAGE_PERMISSION::P_RW, true);
|
||||
PPCRecompilerX64Gen_generateRecompilerInterfaceFunctions();
|
||||
|
||||
uint32 codeRegionEnd = RPLLoader_GetMaxCodeOffset();
|
||||
codeRegionEnd = (codeRegionEnd + PPC_REC_ALLOC_BLOCK_SIZE - 1) & ~(PPC_REC_ALLOC_BLOCK_SIZE - 1);
|
||||
|
||||
uint32 codeRegionSize = codeRegionEnd - PPC_REC_CODE_AREA_START;
|
||||
cemuLog_logDebug(LogType::Force, "Allocating recompiler tables for range 0x{:08x}-0x{:08x}", PPC_REC_CODE_AREA_START, codeRegionEnd);
|
||||
|
||||
for (uint32 i = 0; i < codeRegionSize; i += PPC_REC_ALLOC_BLOCK_SIZE)
|
||||
{
|
||||
PPCRecompiler_reserveLookupTableBlock(i);
|
||||
}
|
||||
PPCRecompiler_allocateRange(0, 0x1000); // the first entry is used for fallback to interpreter
|
||||
PPCRecompiler_allocateRange(mmuRange_TRAMPOLINE_AREA.getBase(), mmuRange_TRAMPOLINE_AREA.getSize());
|
||||
PPCRecompiler_allocateRange(mmuRange_CODECAVE.getBase(), mmuRange_CODECAVE.getSize());
|
||||
|
||||
// init x64 recompiler instance data
|
||||
ppcRecompilerInstanceData->_x64XMM_xorNegateMaskBottom[0] = 1ULL << 63ULL;
|
||||
@@ -589,6 +592,33 @@ void PPCRecompiler_init()
|
||||
ppcRecompilerEnabled = true;
|
||||
|
||||
// launch recompilation thread
|
||||
std::thread t_recompiler(PPCRecompiler_thread);
|
||||
t_recompiler.detach();
|
||||
s_recompilerThreadStopSignal = false;
|
||||
s_threadRecompiler = std::thread(PPCRecompiler_thread);
|
||||
}
|
||||
|
||||
void PPCRecompiler_Shutdown()
|
||||
{
|
||||
// shut down recompiler thread
|
||||
s_recompilerThreadStopSignal = true;
|
||||
if(s_threadRecompiler.joinable())
|
||||
s_threadRecompiler.join();
|
||||
// clean up queues
|
||||
while(!PPCRecompilerState.targetQueue.empty())
|
||||
PPCRecompilerState.targetQueue.pop();
|
||||
PPCRecompilerState.invalidationRanges.clear();
|
||||
// clean range store
|
||||
rangeStore_ppcRanges.clear();
|
||||
// clean up memory
|
||||
uint32 numBlocks = PPCRecompiler_GetNumAddressSpaceBlocks();
|
||||
for(uint32 i=0; i<numBlocks; i++)
|
||||
{
|
||||
if(!ppcRecompiler_reservedBlockMask[i])
|
||||
continue;
|
||||
// deallocate
|
||||
uint64 offset = i * PPC_REC_ALLOC_BLOCK_SIZE;
|
||||
MemMapper::FreeMemory(&(ppcRecompilerInstanceData->ppcRecompilerFuncTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), true);
|
||||
MemMapper::FreeMemory(&(ppcRecompilerInstanceData->ppcRecompilerDirectJumpTable[offset/4]), (PPC_REC_ALLOC_BLOCK_SIZE/4)*sizeof(void*), true);
|
||||
// mark as unmapped
|
||||
ppcRecompiler_reservedBlockMask[i] = false;
|
||||
}
|
||||
}
|
||||
@@ -373,6 +373,7 @@ extern PPCRecompilerInstanceData_t* ppcRecompilerInstanceData;
|
||||
extern bool ppcRecompilerEnabled;
|
||||
|
||||
void PPCRecompiler_init();
|
||||
void PPCRecompiler_Shutdown();
|
||||
|
||||
void PPCRecompiler_allocateRange(uint32 startAddress, uint32 size);
|
||||
|
||||
|
||||
@@ -173,4 +173,5 @@ void LatteRenderTarget_updateViewport();
|
||||
// Latte emulation control
|
||||
void Latte_Start();
|
||||
void Latte_Stop();
|
||||
bool Latte_IsActive();
|
||||
bool Latte_GetStopSignal(); // returns true if stop was requested or if in stopped state
|
||||
void LatteThread_Exit();
|
||||
@@ -96,7 +96,7 @@ void LatteAsyncCommands_waitUntilAllProcessed()
|
||||
void LatteAsyncCommands_checkAndExecute()
|
||||
{
|
||||
// quick check if queue is empty (requires no lock)
|
||||
if (!Latte_IsActive())
|
||||
if (Latte_GetStopSignal())
|
||||
LatteThread_Exit();
|
||||
if (LatteAsyncCommandQueue.empty())
|
||||
return;
|
||||
|
||||
@@ -257,6 +257,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return m_map.empty();
|
||||
}
|
||||
|
||||
const std::map<InternalRange, TNodeObject*>& getAll() const { return m_map; };
|
||||
};
|
||||
|
||||
@@ -455,48 +460,6 @@ public:
|
||||
}
|
||||
if(m_invalidationRangeEnd <= m_invalidationRangeBegin)
|
||||
m_hasInvalidation = false;
|
||||
|
||||
//if (resRangeBegin <= m_invalidationRangeBegin)
|
||||
//{
|
||||
// // shrink/replace invalidation range from the bottom
|
||||
// uint32 uploadBegin = m_invalidationRangeBegin;//std::max(m_invalidationRangeBegin, resRangeBegin);
|
||||
// uint32 uploadEnd = std::min(resRangeEnd, m_invalidationRangeEnd);
|
||||
// cemu_assert_debug(uploadEnd >= uploadBegin);
|
||||
// if (uploadBegin != uploadEnd)
|
||||
// checkAndSyncModifications(uploadBegin, uploadEnd, true);
|
||||
// m_invalidationRangeBegin = uploadEnd;
|
||||
// cemu_assert_debug(m_invalidationRangeBegin <= m_invalidationRangeEnd);
|
||||
// if (m_invalidationRangeBegin >= m_invalidationRangeEnd)
|
||||
// m_hasInvalidation = false;
|
||||
//}
|
||||
//else if (resRangeEnd >= m_invalidationRangeEnd)
|
||||
//{
|
||||
// // shrink/replace invalidation range from the top
|
||||
// uint32 uploadBegin = std::max(m_invalidationRangeBegin, resRangeBegin);
|
||||
// uint32 uploadEnd = m_invalidationRangeEnd;// std::min(resRangeEnd, m_invalidationRangeEnd);
|
||||
// cemu_assert_debug(uploadEnd >= uploadBegin);
|
||||
// if (uploadBegin != uploadEnd)
|
||||
// checkAndSyncModifications(uploadBegin, uploadEnd, true);
|
||||
// m_invalidationRangeEnd = uploadBegin;
|
||||
// cemu_assert_debug(m_invalidationRangeBegin <= m_invalidationRangeEnd);
|
||||
// if (m_invalidationRangeBegin >= m_invalidationRangeEnd)
|
||||
// m_hasInvalidation = false;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// // since we cant cut holes into the range upload it in it's entirety
|
||||
// cemu_assert_debug(m_invalidationRangeEnd <= m_rangeEnd);
|
||||
// cemu_assert_debug(m_invalidationRangeBegin >= m_rangeBegin);
|
||||
// cemu_assert_debug(m_invalidationRangeBegin < m_invalidationRangeEnd);
|
||||
// checkAndSyncModifications(m_invalidationRangeBegin, m_invalidationRangeEnd, true);
|
||||
// m_hasInvalidation = false;
|
||||
//}
|
||||
|
||||
|
||||
|
||||
// todo - dont re-upload the whole range immediately
|
||||
// under ideal circumstances we would only upload the data range requested for the current draw call
|
||||
// but this is a hot path so we can't check
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,6 +790,21 @@ private:
|
||||
static std::vector<uint32> g_deallocateQueue;
|
||||
|
||||
public:
|
||||
static void UnloadAll()
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i < s_allCacheNodes.size())
|
||||
{
|
||||
BufferCacheNode* node = s_allCacheNodes[i];
|
||||
node->ReleaseCacheMemoryImmediately();
|
||||
LatteBufferCache_removeSingleNodeFromTree(node);
|
||||
delete node;
|
||||
}
|
||||
for(auto& it : s_allCacheNodes)
|
||||
delete it;
|
||||
s_allCacheNodes.clear();
|
||||
g_deallocateQueue.clear();
|
||||
}
|
||||
|
||||
static void ProcessDeallocations()
|
||||
{
|
||||
@@ -931,7 +909,6 @@ public:
|
||||
};
|
||||
|
||||
std::vector<uint32> BufferCacheNode::g_deallocateQueue;
|
||||
|
||||
IntervalTree2<MPTR, BufferCacheNode> g_gpuBufferCache;
|
||||
|
||||
void LatteBufferCache_removeSingleNodeFromTree(BufferCacheNode* node)
|
||||
@@ -1009,10 +986,16 @@ void LatteBufferCache_processDeallocations()
|
||||
|
||||
void LatteBufferCache_init(size_t bufferSize)
|
||||
{
|
||||
cemu_assert_debug(g_gpuBufferCache.empty());
|
||||
g_gpuBufferHeap.reset(new VHeap(nullptr, (uint32)bufferSize));
|
||||
g_renderer->bufferCache_init((uint32)bufferSize);
|
||||
}
|
||||
|
||||
void LatteBufferCache_UnloadAll()
|
||||
{
|
||||
BufferCacheNode::UnloadAll();
|
||||
}
|
||||
|
||||
void LatteBufferCache_getStats(uint32& heapSize, uint32& allocationSize, uint32& allocNum)
|
||||
{
|
||||
g_gpuBufferHeap->getStats(heapSize, allocationSize, allocNum);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
void LatteBufferCache_init(size_t bufferSize);
|
||||
void LatteBufferCache_UnloadAll();
|
||||
|
||||
uint32 LatteBufferCache_retrieveDataInCache(MPTR physAddress, uint32 size);
|
||||
void LatteBufferCache_copyStreamoutDataToCache(MPTR physAddress, uint32 size, uint32 streamoutBufferOffset);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user