Initial support for title switching + better Wii U menu compatibility (#907)

This commit is contained in:
Exzap
2023-07-21 13:54:07 +02:00
committed by GitHub
parent bfbeeae6f6
commit 2200cc0ddf
95 changed files with 2549 additions and 746 deletions
+8 -8
View File
@@ -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;
+6 -2
View File
@@ -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
@@ -416,6 +420,8 @@ add_library(CemuCafe
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
@@ -464,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
+161 -68
View File
@@ -45,8 +45,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"
@@ -61,6 +62,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"
@@ -284,7 +286,7 @@ struct
static_assert(sizeof(SharedDataEntry) == 0x1C);
uint32 loadSharedData()
uint32 LoadSharedData()
{
// check if font files are dumped
bool hasAllShareddataFiles = true;
@@ -421,49 +423,40 @@ 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
{
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();
@@ -476,6 +469,7 @@ namespace CafeSystem
iosu::boss_init();
iosu::nim::Initialize();
iosu::pdm::Initialize();
iosu::odm::Initialize();
// init Cafe OS
avm::Initialize();
drmapp::Initialize();
@@ -493,14 +487,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())
{
@@ -559,10 +585,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)
@@ -597,26 +646,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;
}
@@ -655,10 +715,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;
}
@@ -703,6 +764,13 @@ namespace CafeSystem
return sGameInfo_ForegroundTitle.GetVersion();
}
uint32 GetForegroundTitleSDKVersion()
{
if (sLaunchModeIsStandalone)
return 999999;
return sGameInfo_ForegroundTitle.GetSDKVersion();
}
CafeConsoleRegion GetForegroundTitleRegion()
{
if (sLaunchModeIsStandalone)
@@ -740,6 +808,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()
{
@@ -756,39 +844,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;
}
@@ -838,10 +919,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))
@@ -868,6 +946,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;
@@ -878,4 +966,9 @@ namespace CafeSystem
return currentUpdatedApplicationHash;
}
void RequestRecreateCanvas()
{
s_implementation->CafeRecreateCanvas();
}
}
+16
View File
@@ -6,6 +6,12 @@
namespace CafeSystem
{
class SystemImplementation
{
public:
virtual void CafeRecreateCanvas() = 0;
};
enum class STATUS_CODE
{
SUCCESS,
@@ -15,13 +21,21 @@ namespace CafeSystem
};
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();
@@ -37,6 +51,8 @@ namespace CafeSystem
uint32 GetRPXHashBase();
uint32 GetRPXHashUpdated();
void RequestRecreateCanvas();
};
extern RPLModule* applicationRPX;
+26 -10
View File
@@ -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;
}
-1
View File
@@ -205,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
-7
View File
@@ -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;
-5
View File
@@ -100,11 +100,6 @@ PPCInterpreter_t* PPCCore_executeCallbackInternal(uint32 functionMPTR)
return hCPU;
}
void PPCCore_deleteAllThreads()
{
assert_dbg();
}
void PPCCore_init()
{
}
-1
View File
@@ -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);
+2 -1
View File
@@ -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;
+26 -43
View File
@@ -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);
@@ -125,7 +125,7 @@ uint32 LatteCP_readU32Deprc()
readDistance = (sint32)(gxRingBufferWritePtr - gxRingBufferReadPtr);
if (readDistance != 0)
break;
if (!Latte_IsActive())
if (Latte_GetStopSignal())
LatteThread_Exit();
// still no command data available, do some other tasks
@@ -172,7 +172,7 @@ void LatteCP_waitForNWords(uint32 numWords)
if (readDistance >= waitDistance)
break;
if (!Latte_IsActive())
if (Latte_GetStopSignal())
LatteThread_Exit();
// still no command data available, do some other tasks
@@ -373,6 +373,7 @@ uint8 LatteMRT::GetActiveColorBufferMask(const LatteDecompilerShader* pixelShade
if ((colorBufferWidth < (sint32)scissorAccessWidth) ||
(colorBufferHeight < (sint32)scissorAccessHeight))
{
// log this?
colorBufferMask &= ~(1<<i);
}
+23 -6
View File
@@ -144,7 +144,7 @@ LatteShaderPSInputTable* LatteSHRC_GetPSInputTable()
return &_activePSImportTable;
}
bool LatteSHRC_RemoveFromCache(LatteDecompilerShader* shader)
void LatteSHRC_RemoveFromCache(LatteDecompilerShader* shader)
{
bool removed = false;
auto& cache = LatteSHRC_GetCacheByType(shader->shaderType);
@@ -156,10 +156,14 @@ bool LatteSHRC_RemoveFromCache(LatteDecompilerShader* shader)
}
else if (baseIt->second == shader)
{
if (baseIt->second->next)
cache.emplace(shader->baseHash, baseIt->second->next);
else
cache.erase(baseIt);
cemu_assert_debug(baseIt->second == shader);
cache.erase(baseIt);
if (shader->next)
{
cemu_assert_debug(shader->baseHash == shader->next->baseHash);
cache.emplace(shader->baseHash, shader->next);
}
shader->next = 0;
removed = true;
}
else
@@ -176,7 +180,7 @@ bool LatteSHRC_RemoveFromCache(LatteDecompilerShader* shader)
}
}
}
return removed;
cemu_assert(removed);
}
void LatteSHRC_RemoveFromCacheByHash(uint64 shader_base_hash, uint64 shader_aux_hash, LatteConst::ShaderType type)
@@ -1009,3 +1013,16 @@ void LatteSHRC_Init()
cemu_assert_debug(sGeometryShaders.empty());
cemu_assert_debug(sPixelShaders.empty());
}
void LatteSHRC_UnloadAll()
{
while(!sVertexShaders.empty())
LatteShader_free(sVertexShaders.begin()->second);
cemu_assert_debug(sVertexShaders.empty());
while(!sGeometryShaders.empty())
LatteShader_free(sGeometryShaders.begin()->second);
cemu_assert_debug(sGeometryShaders.empty());
while(!sPixelShaders.empty())
LatteShader_free(sPixelShaders.begin()->second);
cemu_assert_debug(sPixelShaders.empty());
}
+4 -2
View File
@@ -3,6 +3,7 @@
#include "Cafe/HW/Latte/ISA/RegDefines.h"
void LatteSHRC_Init();
void LatteSHRC_UnloadAll();
void LatteSHRC_ResetCachedShaderHash();
void LatteShaderSHRC_UpdateFetchShader();
@@ -117,11 +118,12 @@ void LatteShader_DumpShader(uint64 baseHash, uint64 auxHash, LatteDecompilerShad
void LatteShader_DumpRawShader(uint64 baseHash, uint64 auxHash, uint32 type, uint8* programCode, uint32 programLen);
// shader cache file
void LatteShaderCache_load();
void LatteShaderCache_Load();
void LatteShaderCache_Close();
void LatteShaderCache_writeSeparableVertexShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* fetchShader, uint32 fetchShaderSize, uint8* vertexShader, uint32 vertexShaderSize, uint32* contextRegisters, bool usesGeometryShader);
void LatteShaderCache_writeSeparableGeometryShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* geometryShader, uint32 geometryShaderSize, uint8* gsCopyShader, uint32 gsCopyShaderSize, uint32* contextRegisters, uint32* hleSpecialState, uint32 vsRingParameterCount);
void LatteShaderCache_writeSeparablePixelShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* pixelShader, uint32 pixelShaderSize, uint32* contextRegisters, bool usesGeometryShader);
// todo - sort this
// todo - refactor this
sint32 LatteDecompiler_getTextureSamplerBaseIndex(LatteConst::ShaderType shaderType);
+42 -21
View File
@@ -53,7 +53,7 @@ struct
sint32 pipelineFileCount;
}g_shaderCacheLoaderState;
FileCache* fc_shaderCacheGeneric = nullptr; // contains hardware and Cemu version independent shader information
FileCache* s_shaderCacheGeneric = nullptr; // contains hardware and version independent shader information
#define SHADER_CACHE_GENERIC_EXTRA_VERSION 2 // changing this constant will invalidate all hardware-independent cache files
@@ -62,7 +62,7 @@ FileCache* fc_shaderCacheGeneric = nullptr; // contains hardware and Cemu versio
#define SHADER_CACHE_TYPE_PIXEL (2)
bool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderInfoSize);
void LatteShaderCache_loadVulkanPipelineCache(uint64 cacheTitleId);
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId);
bool LatteShaderCache_updatePipelineLoadingProgress();
void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateFunc, bool isPipelines);
@@ -216,7 +216,7 @@ void LatteShaderCache_drawBackgroundImage(ImTextureID texture, int width, int he
ImGui::PopStyleVar(2);
}
void LatteShaderCache_load()
void LatteShaderCache_Load()
{
shaderCacheScreenStats.compiledShaderCount = 0;
shaderCacheScreenStats.vertexShaderCount = 0;
@@ -251,21 +251,21 @@ void LatteShaderCache_load()
LatteShaderCache_handleDeprecatedCacheFiles(pathGeneric, pathGenericPre1_25_0, pathGenericPre1_16_0);
// calculate extraVersion for transferable and precompiled shader cache
uint32 transferableExtraVersion = SHADER_CACHE_GENERIC_EXTRA_VERSION;
fc_shaderCacheGeneric = FileCache::Open(pathGeneric.generic_wstring(), false, transferableExtraVersion); // legacy extra version (1.25.0 - 1.25.1b)
if(!fc_shaderCacheGeneric)
fc_shaderCacheGeneric = FileCache::Open(pathGeneric.generic_wstring(), true, LatteShaderCache_getShaderCacheExtraVersion(cacheTitleId));
if(!fc_shaderCacheGeneric)
s_shaderCacheGeneric = FileCache::Open(pathGeneric, false, transferableExtraVersion); // legacy extra version (1.25.0 - 1.25.1b)
if(!s_shaderCacheGeneric)
s_shaderCacheGeneric = FileCache::Open(pathGeneric, true, LatteShaderCache_getShaderCacheExtraVersion(cacheTitleId));
if(!s_shaderCacheGeneric)
{
// no shader cache available yet
cemuLog_log(LogType::Force, "Unable to open or create shader cache file \"{}\"", _pathToUtf8(pathGeneric));
LatteShaderCache_finish();
return;
}
fc_shaderCacheGeneric->UseCompression(false);
s_shaderCacheGeneric->UseCompression(false);
// load/compile cached shaders
sint32 entryCount = fc_shaderCacheGeneric->GetMaximumFileIndex();
g_shaderCacheLoaderState.shaderFileCount = fc_shaderCacheGeneric->GetFileCount();
sint32 entryCount = s_shaderCacheGeneric->GetMaximumFileIndex();
g_shaderCacheLoaderState.shaderFileCount = s_shaderCacheGeneric->GetFileCount();
g_shaderCacheLoaderState.loadedShaderFiles = 0;
// get game background loading image
@@ -304,13 +304,13 @@ void LatteShaderCache_load()
auto LoadShadersUpdate = [&]() -> bool
{
if (loadIndex >= (uint32)fc_shaderCacheGeneric->GetMaximumFileIndex())
if (loadIndex >= (uint32)s_shaderCacheGeneric->GetMaximumFileIndex())
return false;
LatteShaderCache_updateCompileQueue(SHADER_CACHE_COMPILE_QUEUE_SIZE - 2);
uint64 name1;
uint64 name2;
std::vector<uint8> fileData;
if (!fc_shaderCacheGeneric->GetFileByIndex(loadIndex, &name1, &name2, fileData))
if (!s_shaderCacheGeneric->GetFileByIndex(loadIndex, &name1, &name2, fileData))
{
loadIndex++;
return true;
@@ -320,7 +320,7 @@ void LatteShaderCache_load()
{
// something is wrong with the stored shader, remove entry from shader cache files
cemuLog_log(LogType::Force, "Shader cache entry {} invalid, deleting...", loadIndex);
fc_shaderCacheGeneric->DeleteFile({ name1, name2 });
s_shaderCacheGeneric->DeleteFile({name1, name2 });
}
numLoadedShaders++;
loadIndex++;
@@ -343,7 +343,7 @@ void LatteShaderCache_load()
LatteShaderCache_finish();
// if Vulkan then also load pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan)
LatteShaderCache_loadVulkanPipelineCache(cacheTitleId);
LatteShaderCache_LoadVulkanPipelineCache(cacheTitleId);
g_renderer->BeginFrame(true);
@@ -376,6 +376,8 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
while (true)
{
if (Latte_GetStopSignal())
break; // thread stop requested, cancel shader loading
bool r = loadUpdateFunc();
if (!r)
break;
@@ -496,13 +498,15 @@ void LatteShaderCache_ShowProgress(const std::function <bool(void)>& loadUpdateF
}
}
void LatteShaderCache_loadVulkanPipelineCache(uint64 cacheTitleId)
void LatteShaderCache_LoadVulkanPipelineCache(uint64 cacheTitleId)
{
auto& pipelineCache = VulkanPipelineStableCache::GetInstance();
g_shaderCacheLoaderState.pipelineFileCount = pipelineCache.BeginLoading(cacheTitleId);
g_shaderCacheLoaderState.loadedPipelines = 0;
LatteShaderCache_ShowProgress(LatteShaderCache_updatePipelineLoadingProgress, true);
pipelineCache.EndLoading();
if(Latte_GetStopSignal())
LatteThread_Exit();
}
bool LatteShaderCache_updatePipelineLoadingProgress()
@@ -520,7 +524,7 @@ uint64 LatteShaderCache_getShaderNameInTransferableCache(uint64 baseHash, uint32
void LatteShaderCache_writeSeparableVertexShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* fetchShader, uint32 fetchShaderSize, uint8* vertexShader, uint32 vertexShaderSize, uint32* contextRegisters, bool usesGeometryShader)
{
if (!fc_shaderCacheGeneric)
if (!s_shaderCacheGeneric)
return;
MemStreamWriter streamWriter(128 * 1024);
// header
@@ -539,12 +543,12 @@ void LatteShaderCache_writeSeparableVertexShader(uint64 shaderBaseHash, uint64 s
// write to cache
uint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_VERTEX);
std::span<uint8> dataBlob = streamWriter.getResult();
fc_shaderCacheGeneric->AddFileAsync({ shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
s_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
}
void LatteShaderCache_writeSeparableGeometryShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* geometryShader, uint32 geometryShaderSize, uint8* gsCopyShader, uint32 gsCopyShaderSize, uint32* contextRegisters, uint32* hleSpecialState, uint32 vsRingParameterCount)
{
if (!fc_shaderCacheGeneric)
if (!s_shaderCacheGeneric)
return;
MemStreamWriter streamWriter(128 * 1024);
// header
@@ -564,12 +568,12 @@ void LatteShaderCache_writeSeparableGeometryShader(uint64 shaderBaseHash, uint64
// write to cache
uint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_GEOMETRY);
std::span<uint8> dataBlob = streamWriter.getResult();
fc_shaderCacheGeneric->AddFileAsync({ shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
s_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
}
void LatteShaderCache_writeSeparablePixelShader(uint64 shaderBaseHash, uint64 shaderAuxHash, uint8* pixelShader, uint32 pixelShaderSize, uint32* contextRegisters, bool usesGeometryShader)
{
if (!fc_shaderCacheGeneric)
if (!s_shaderCacheGeneric)
return;
MemStreamWriter streamWriter(128 * 1024);
streamWriter.writeBE<uint8>(1 | (SHADER_CACHE_TYPE_PIXEL << 4)); // version and type (shared field)
@@ -585,7 +589,7 @@ void LatteShaderCache_writeSeparablePixelShader(uint64 shaderBaseHash, uint64 sh
// write to cache
uint64 shaderCacheName = LatteShaderCache_getShaderNameInTransferableCache(shaderBaseHash, SHADER_CACHE_TYPE_PIXEL);
std::span<uint8> dataBlob = streamWriter.getResult();
fc_shaderCacheGeneric->AddFileAsync({ shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
s_shaderCacheGeneric->AddFileAsync({shaderCacheName, shaderAuxHash }, dataBlob.data(), dataBlob.size());
}
void LatteShaderCache_loadOrCompileSeparableShader(LatteDecompilerShader* shader, uint64 shaderBaseHash, uint64 shaderAuxHash)
@@ -759,6 +763,23 @@ bool LatteShaderCache_readSeparableShader(uint8* shaderInfoData, sint32 shaderIn
return false;
}
void LatteShaderCache_Close()
{
if(s_shaderCacheGeneric)
{
delete s_shaderCacheGeneric;
s_shaderCacheGeneric = nullptr;
}
if (g_renderer->GetType() == RendererAPI::Vulkan)
RendererShaderVk::ShaderCacheLoading_Close();
else if (g_renderer->GetType() == RendererAPI::OpenGL)
RendererShaderGL::ShaderCacheLoading_Close();
// if Vulkan then also close pipeline cache
if (g_renderer->GetType() == RendererAPI::Vulkan)
VulkanPipelineStableCache::GetInstance().Close();
}
#include <wx/msgdlg.h>
void LatteShaderCache_handleDeprecatedCacheFiles(fs::path pathGeneric, fs::path pathGenericPre1_25_0, fs::path pathGenericPre1_16_0)

Some files were not shown because too many files have changed in this diff Show More