Merge branch 'main' into metal

This commit is contained in:
SamoZ256 2024-08-30 08:59:37 +02:00 committed by GitHub
commit 41ee2e75ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 469 additions and 203 deletions

View file

@ -525,7 +525,7 @@ void LatteSHRC_UpdateGSBaseHash(uint8* geometryShaderPtr, uint32 geometryShaderS
// update hash from geometry shader data
uint64 gsHash1 = 0;
uint64 gsHash2 = 0;
_calculateShaderProgramHash((uint32*)geometryShaderPtr, geometryShaderSize, &hashCacheVS, &gsHash1, &gsHash2);
_calculateShaderProgramHash((uint32*)geometryShaderPtr, geometryShaderSize, &hashCacheGS, &gsHash1, &gsHash2);
// get geometry shader
uint64 gsHash = gsHash1 + gsHash2;
gsHash += (uint64)_activeVertexShader->ringParameterCount;

View file

@ -12,9 +12,9 @@ uint32 RendererShader::GeneratePrecompiledCacheId()
v += (uint32)(*s);
s++;
}
v += (EMULATOR_VERSION_LEAD * 1000000u);
v += (EMULATOR_VERSION_MAJOR * 10000u);
v += (EMULATOR_VERSION_MINOR * 100u);
v += (EMULATOR_VERSION_MAJOR * 1000000u);
v += (EMULATOR_VERSION_MINOR * 10000u);
v += (EMULATOR_VERSION_PATCH * 100u);
// settings that can influence shaders
v += (uint32)g_current_game_profile->GetAccurateShaderMul() * 133;

View file

@ -125,7 +125,7 @@ std::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = EMULATOR_NAME;
app_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_LEAD, EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR);
app_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH);
app_info.pEngineName = EMULATOR_NAME;
app_info.engineVersion = app_info.applicationVersion;
app_info.apiVersion = apiVersion;
@ -339,7 +339,7 @@ VulkanRenderer::VulkanRenderer()
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
app_info.pApplicationName = EMULATOR_NAME;
app_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_LEAD, EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR);
app_info.applicationVersion = VK_MAKE_VERSION(EMULATOR_VERSION_MAJOR, EMULATOR_VERSION_MINOR, EMULATOR_VERSION_PATCH);
app_info.pEngineName = EMULATOR_NAME;
app_info.engineVersion = app_info.applicationVersion;
app_info.apiVersion = apiVersion;

View file

@ -511,6 +511,8 @@ namespace iosu
return CallHandler_GetBlackList(fpdClient, vecIn, numVecIn, vecOut, numVecOut);
case FPD_REQUEST_ID::GetFriendListEx:
return CallHandler_GetFriendListEx(fpdClient, vecIn, numVecIn, vecOut, numVecOut);
case FPD_REQUEST_ID::UpdateCommentAsync:
return CallHandler_UpdateCommentAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);
case FPD_REQUEST_ID::UpdatePreferenceAsync:
return CallHandler_UpdatePreferenceAsync(fpdClient, vecIn, numVecIn, vecOut, numVecOut);
case FPD_REQUEST_ID::AddFriendRequestByPlayRecordAsync:
@ -719,18 +721,23 @@ namespace iosu
nnResult CallHandler_GetMyComment(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)
{
static constexpr uint32 MY_COMMENT_LENGTH = 0x12; // are comments utf16? Buffer length is 0x24
if(numVecIn != 0 || numVecOut != 1)
return FPResult_InvalidIPCParam;
if(vecOut->size != MY_COMMENT_LENGTH*sizeof(uint16be))
{
cemuLog_log(LogType::Force, "GetMyComment: Unexpected output size");
return FPResult_InvalidIPCParam;
}
std::basic_string<uint16be> myComment;
myComment.resize(MY_COMMENT_LENGTH);
memcpy(vecOut->basePhys.GetPtr(), myComment.data(), MY_COMMENT_LENGTH*sizeof(uint16be));
return 0;
if(g_fpd.nexFriendSession)
{
if(vecOut->size != MY_COMMENT_LENGTH * sizeof(uint16be))
{
cemuLog_log(LogType::Force, "GetMyComment: Unexpected output size");
return FPResult_InvalidIPCParam;
}
nexComment myNexComment;
g_fpd.nexFriendSession->getMyComment(myNexComment);
myComment = StringHelpers::FromUtf8(myNexComment.commentString);
}
myComment.insert(0, 1, '\0');
memcpy(vecOut->basePhys.GetPtr(), myComment.c_str(), MY_COMMENT_LENGTH * sizeof(uint16be));
return FPResult_Ok;
}
nnResult CallHandler_GetMyPreference(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)
@ -1143,6 +1150,36 @@ namespace iosu
return FPResult_Ok;
}
nnResult CallHandler_UpdateCommentAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)
{
std::unique_lock _l(g_fpd.mtxFriendSession);
if (numVecIn != 1 || numVecOut != 0)
return FPResult_InvalidIPCParam;
if (!g_fpd.nexFriendSession)
return FPResult_RequestFailed;
uint32 messageLength = vecIn[0].size / sizeof(uint16be);
DeclareInputPtr(newComment, uint16be, messageLength, 0);
if (messageLength == 0 || newComment[messageLength-1] != 0)
{
cemuLog_log(LogType::Force, "UpdateCommentAsync: Message must contain at least a null-termination character");
return FPResult_InvalidIPCParam;
}
IPCCommandBody* cmd = ServiceCallDelayCurrentResponse();
auto utf8_comment = StringHelpers::ToUtf8(newComment, messageLength);
nexComment temporaryComment;
temporaryComment.ukn0 = 0;
temporaryComment.commentString = utf8_comment;
temporaryComment.ukn1 = 0;
g_fpd.nexFriendSession->updateCommentAsync(temporaryComment, [cmd](NexFriends::RpcErrorCode result) {
if (result != NexFriends::ERR_NONE)
return ServiceCallAsyncRespond(cmd, FPResult_RequestFailed);
ServiceCallAsyncRespond(cmd, FPResult_Ok);
});
return FPResult_Ok;
}
nnResult CallHandler_UpdatePreferenceAsync(FPDClient* fpdClient, IPCIoctlVector* vecIn, uint32 numVecIn, IPCIoctlVector* vecOut, uint32 numVecOut)
{
std::unique_lock _l(g_fpd.mtxFriendSession);

View file

@ -212,6 +212,7 @@ namespace iosu
static const int RELATIONSHIP_FRIEND = 3;
static const int GAMEMODE_MAX_MESSAGE_LENGTH = 0x80; // limit includes null-terminator character, so only 0x7F actual characters can be used
static const int MY_COMMENT_LENGTH = 0x12;
enum class FPD_REQUEST_ID
{
@ -245,6 +246,7 @@ namespace iosu
CheckSettingStatusAsync = 0x7596,
GetFriendListEx = 0x75F9,
GetFriendRequestListEx = 0x76C1,
UpdateCommentAsync = 0x7726,
UpdatePreferenceAsync = 0x7727,
RemoveFriendAsync = 0x7789,
DeleteFriendFlagsAsync = 0x778A,

View file

@ -140,7 +140,7 @@ namespace coreinit
// we are in single-core mode and the lock will never be released unless we let other threads resume work
// to avoid an infinite loop we have no choice but to yield the thread even it is in an uninterruptible state
if( !OSIsInterruptEnabled() )
cemuLog_log(LogType::APIErrors, "OSUninterruptibleSpinLock_Acquire(): Lock is occupied which requires a wait but current thread is already in an uninterruptible state (Avoid cascaded OSDisableInterrupts and/or OSUninterruptibleSpinLock)");
cemuLog_logOnce(LogType::APIErrors, "OSUninterruptibleSpinLock_Acquire(): Lock is occupied which requires a wait but current thread is already in an uninterruptible state (Avoid cascaded OSDisableInterrupts and/or OSUninterruptibleSpinLock)");
while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread))
{
OSYieldThread();

View file

@ -464,6 +464,14 @@ namespace nn
return ipcCtx->Submit(std::move(ipcCtx));
}
nnResult GetMyPlayingGame(iosu::fpd::GameKey* myPlayingGame)
{
FP_API_BASE();
auto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyPlayingGame);
ipcCtx->AddOutput(myPlayingGame, sizeof(iosu::fpd::GameKey));
return ipcCtx->Submit(std::move(ipcCtx));
}
nnResult GetMyPreference(iosu::fpd::FPDPreference* myPreference)
{
FP_API_BASE();
@ -472,6 +480,14 @@ namespace nn
return ipcCtx->Submit(std::move(ipcCtx));
}
nnResult GetMyComment(uint16be* myComment)
{
FP_API_BASE();
auto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::GetMyComment);
ipcCtx->AddOutput(myComment, iosu::fpd::MY_COMMENT_LENGTH * sizeof(uint16be));
return ipcCtx->Submit(std::move(ipcCtx));
}
nnResult GetMyMii(FFLData_t* fflData)
{
FP_API_BASE();
@ -607,6 +623,20 @@ namespace nn
return resultBuf != 0 ? 1 : 0;
}
nnResult UpdateCommentAsync(uint16be* newComment, void* funcPtr, void* customParam)
{
FP_API_BASE();
auto ipcCtx = std::make_unique<FPIpcContext>(iosu::fpd::FPD_REQUEST_ID::UpdateCommentAsync);
uint32 commentLen = CafeStringHelpers::Length(newComment, iosu::fpd::MY_COMMENT_LENGTH-1);
if (commentLen >= iosu::fpd::MY_COMMENT_LENGTH-1)
{
cemuLog_log(LogType::Force, "UpdateCommentAsync: message too long");
return FPResult_InvalidIPCParam;
}
ipcCtx->AddInput(newComment, sizeof(uint16be) * commentLen + 2);
return ipcCtx->SubmitAsync(std::move(ipcCtx), funcPtr, customParam);
}
nnResult UpdatePreferenceAsync(iosu::fpd::FPDPreference* newPreference, void* funcPtr, void* customParam)
{
FP_API_BASE();
@ -763,7 +793,9 @@ namespace nn
cafeExportRegisterFunc(GetMyAccountId, "nn_fp", "GetMyAccountId__Q2_2nn2fpFPc", LogType::NN_FP);
cafeExportRegisterFunc(GetMyScreenName, "nn_fp", "GetMyScreenName__Q2_2nn2fpFPw", LogType::NN_FP);
cafeExportRegisterFunc(GetMyMii, "nn_fp", "GetMyMii__Q2_2nn2fpFP12FFLStoreData", LogType::NN_FP);
cafeExportRegisterFunc(GetMyPlayingGame, "nn_fp", "GetMyPlayingGame__Q2_2nn2fpFPQ3_2nn2fp7GameKey", LogType::NN_FP);
cafeExportRegisterFunc(GetMyPreference, "nn_fp", "GetMyPreference__Q2_2nn2fpFPQ3_2nn2fp10Preference", LogType::NN_FP);
cafeExportRegisterFunc(GetMyComment, "nn_fp", "GetMyComment__Q2_2nn2fpFPQ3_2nn2fp7Comment", LogType::NN_FP);
cafeExportRegisterFunc(GetFriendAccountId, "nn_fp", "GetFriendAccountId__Q2_2nn2fpFPA17_cPCUiUi", LogType::NN_FP);
cafeExportRegisterFunc(GetFriendScreenName, "nn_fp", "GetFriendScreenName__Q2_2nn2fpFPA11_wPCUiUibPUc", LogType::NN_FP);
@ -774,6 +806,7 @@ namespace nn
cafeExportRegisterFunc(CheckSettingStatusAsync, "nn_fp", "CheckSettingStatusAsync__Q2_2nn2fpFPUcPFQ2_2nn6ResultPv_vPv", LogType::NN_FP);
cafeExportRegisterFunc(IsPreferenceValid, "nn_fp", "IsPreferenceValid__Q2_2nn2fpFv", LogType::NN_FP);
cafeExportRegisterFunc(UpdateCommentAsync, "nn_fp", "UpdateCommentAsync__Q2_2nn2fpFPCwPFQ2_2nn6ResultPv_vPv", LogType::NN_FP);
cafeExportRegisterFunc(UpdatePreferenceAsync, "nn_fp", "UpdatePreferenceAsync__Q2_2nn2fpFPCQ3_2nn2fp10PreferencePFQ2_2nn6ResultPv_vPv", LogType::NN_FP);
cafeExportRegisterFunc(GetRequestBlockSettingAsync, "nn_fp", "GetRequestBlockSettingAsync__Q2_2nn2fpFPUcPCUiUiPFQ2_2nn6ResultPv_vPv", LogType::NN_FP);

View file

@ -12,6 +12,7 @@
enum class KPAD_ERROR : sint32
{
NONE = 0,
NO_SAMPLE_DATA = -1,
NO_CONTROLLER = -2,
NOT_INITIALIZED = -5,
};
@ -106,6 +107,9 @@ void padscoreExport_WPADProbe(PPCInterpreter_t* hCPU)
}
else
{
if(type)
*type = 253;
osLib_returnFromFunction(hCPU, WPAD_ERR_NO_CONTROLLER);
}
}
@ -420,9 +424,12 @@ void padscoreExport_KPADSetConnectCallback(PPCInterpreter_t* hCPU)
osLib_returnFromFunction(hCPU, old_callback.GetMPTR());
}
uint64 g_kpadLastRead[InputManager::kMaxWPADControllers] = {0};
bool g_kpadIsInited = true;
sint32 _KPADRead(uint32 channel, KPADStatus_t* samplingBufs, uint32 length, betype<KPAD_ERROR>* errResult)
{
if (channel >= InputManager::kMaxWPADControllers)
{
debugBreakpoint();
@ -446,6 +453,19 @@ sint32 _KPADRead(uint32 channel, KPADStatus_t* samplingBufs, uint32 length, bety
return 0;
}
// On console new input samples are only received every few ms and calling KPADRead(Ex) clears the internal queue regardless of length value
// thus calling KPADRead(Ex) again too soon on the same channel will result in no data being returned
// Games that depend on this: Affordable Space Adventures
uint64 currentTime = coreinit::OSGetTime();
uint64 timeDif = currentTime - g_kpadLastRead[channel];
if(length == 0 || timeDif < coreinit::EspressoTime::ConvertNsToTimerTicks(1000000))
{
if (errResult)
*errResult = KPAD_ERROR::NO_SAMPLE_DATA;
return 0;
}
g_kpadLastRead[channel] = currentTime;
memset(samplingBufs, 0x00, sizeof(KPADStatus_t));
samplingBufs->wpadErr = WPAD_ERR_NONE;
samplingBufs->data_format = controller->get_data_format();
@ -474,7 +494,6 @@ void padscoreExport_KPADReadEx(PPCInterpreter_t* hCPU)
osLib_returnFromFunction(hCPU, samplesRead);
}
bool debugUseDRC1 = true;
void padscoreExport_KPADRead(PPCInterpreter_t* hCPU)
{
ppcDefineParamU32(channel, 0);
@ -726,7 +745,8 @@ namespace padscore
// call sampling callback
for (auto i = 0; i < InputManager::kMaxWPADControllers; ++i)
{
if (g_padscore.controller_data[i].sampling_callback) {
if (g_padscore.controller_data[i].sampling_callback)
{
if (const auto controller = instance.get_wpad_controller(i))
{
cemuLog_log(LogType::InputAPI, "Calling WPADsamplingCallback({})", i);
@ -741,7 +761,7 @@ namespace padscore
{
OSCreateAlarm(&g_padscore.alarm);
const uint64 start_tick = coreinit::coreinit_getOSTime();
const uint64 period_tick = coreinit::EspressoTime::GetTimerClock(); // once a second
const uint64 period_tick = coreinit::EspressoTime::GetTimerClock() / 200; // every 5ms
MPTR handler = PPCInterpreter_makeCallableExportDepr(TickFunction);
OSSetPeriodicAlarm(&g_padscore.alarm, start_tick, period_tick, handler);
}

View file

@ -50,7 +50,6 @@
extern bool isLaunchTypeELF;
bool debugUseDRC = true;
VPADDir g_vpadGyroDirOverwrite[VPAD_MAX_CONTROLLERS] =
{
{{1.0f,0.0f,0.0f}, {0.0f,1.0f,0.0f}, {0.0f, 0.0f, 0.1f}},
@ -240,19 +239,20 @@ namespace vpad
status->tpProcessed2.validity = VPAD_TP_VALIDITY_INVALID_XY;
const auto controller = InputManager::instance().get_vpad_controller(channel);
if (!controller || debugUseDRC == false)
if (!controller)
{
// no controller
// most games expect the Wii U GamePad to be connected, so even if the user has not set it up we should still return empty samples for channel 0
if(channel != 0)
{
if (error)
*error = VPAD_READ_ERR_NO_CONTROLLER;
if (length > 0)
status->vpadErr = -1;
return 0;
}
if (error)
*error = VPAD_READ_ERR_NONE; // VPAD_READ_ERR_NO_DATA; // VPAD_READ_ERR_NO_CONTROLLER;
*error = VPAD_READ_ERR_NONE;
return 1;
//osLib_returnFromFunction(hCPU, 1); return;
}
if (channel != 0)
{
debugBreakpoint();
}
const bool vpadDelayEnabled = ActiveSettings::VPADDelayEnabled();
@ -274,9 +274,7 @@ namespace vpad
// not ready yet
if (error)
*error = VPAD_READ_ERR_NONE;
return 0;
//osLib_returnFromFunction(hCPU, 0); return;
}
else if (dif <= ESPRESSO_TIMER_CLOCK)
{