diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f91a430bc..e169448af3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,7 @@ if(NOT MSVC) # Disable some warnings add_definitions(-Wno-multichar) add_definitions(-Wno-deprecated-register) + add_definitions(-Wno-tautological-pointer-compare) # Don't compile with strict aliasing, we're not 100% aliasing-safe add_compile_options(-fno-strict-aliasing) diff --git a/Common/GL/GLInterface/EGLSwitch.cpp b/Common/GL/GLInterface/EGLSwitch.cpp new file mode 100644 index 0000000000..4cd670c678 --- /dev/null +++ b/Common/GL/GLInterface/EGLSwitch.cpp @@ -0,0 +1,21 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "ppsspp_config.h" +#if PPSSPP_PLATFORM(SWITCH) +#include +#include "Common/Log.h" +#include "Common/GL/GLInterface/EGLSwitch.h" + +EGLDisplay cInterfaceEGLSwitch::OpenDisplay() { + return eglGetDisplay(EGL_DEFAULT_DISPLAY); +} + +EGLNativeWindowType cInterfaceEGLSwitch::InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) { + return nwindowGetDefault(); +} + +void cInterfaceEGLSwitch::ShutdownPlatform() { +} +#endif diff --git a/Common/GL/GLInterface/EGLSwitch.h b/Common/GL/GLInterface/EGLSwitch.h new file mode 100644 index 0000000000..b313158429 --- /dev/null +++ b/Common/GL/GLInterface/EGLSwitch.h @@ -0,0 +1,24 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/GL/GLInterface/EGL.h" + +class cInterfaceEGLSwitch : public cInterfaceEGL { +public: + cInterfaceEGLSwitch() {} +protected: + EGLDisplay OpenDisplay() override; + EGLNativeWindowType InitializePlatform(EGLNativeWindowType host_window, EGLConfig config) override; + void ShutdownPlatform() override; + void OverrideBackbufferDimensions(int internalWidth, int internalHeight) override { + internalWidth_ = internalWidth; + internalHeight_ = internalHeight; + } + +private: + int internalWidth_ = 0; + int internalHeight_ = 0; +}; diff --git a/Common/GL/GLInterface/GLInterface.cpp b/Common/GL/GLInterface/GLInterface.cpp index 6a8202aaf1..389f650ae7 100644 --- a/Common/GL/GLInterface/GLInterface.cpp +++ b/Common/GL/GLInterface/GLInterface.cpp @@ -2,10 +2,13 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include "ppsspp_config.h" #include "Common/GL/GLInterfaceBase.h" #ifdef __ANDROID__ #include "Common/GL/GLInterface/EGLAndroid.h" +#elif PPSSPP_PLATFORM(SWITCH) +#include "Common/GL/GLInterface/EGLSwitch.h" #elif defined(__APPLE__) #include "Common/GL/GLInterface/AGL.h" #elif defined(_WIN32) @@ -23,6 +26,8 @@ cInterfaceBase* HostGL_CreateGLInterface(){ #ifdef __ANDROID__ return new cInterfaceEGLAndroid; + #elif if PPSSPP_PLATFORM(SWITCH) + return new cInterfaceEGLSwitch; #elif defined(__APPLE__) return new cInterfaceAGL; #elif defined(_WIN32) diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index a523ab4968..c748696c2c 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -236,6 +236,7 @@ bool g_vulkanMayBeAvailable = false; static const char *device_name_blacklist[] = { "NVIDIA:SHIELD Tablet K1", + "SDL:Horizon", }; static const char *so_names[] = { diff --git a/Core/Config.cpp b/Core/Config.cpp index 9a4e54743a..b20b7f62e6 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -776,6 +776,7 @@ static ConfigSetting graphicsSettings[] = { ConfigSetting("LogFrameDrops", &g_Config.bLogFrameDrops, false, true, false), ConfigSetting("InflightFrames", &g_Config.iInflightFrames, 3, true, false), + ConfigSetting("RenderDuplicateFrames", &g_Config.bRenderDuplicateFrames, false, true, true), ConfigSetting(false), }; @@ -968,7 +969,7 @@ static ConfigSetting systemParamSettings[] = { ReportedConfigSetting("ButtonPreference", &g_Config.iButtonPreference, PSP_SYSTEMPARAM_BUTTON_CROSS, true, true), ConfigSetting("LockParentalLevel", &g_Config.iLockParentalLevel, 0, true, true), ConfigSetting("WlanAdhocChannel", &g_Config.iWlanAdhocChannel, PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC, true, true), -#if defined(USING_WIN_UI) +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) ConfigSetting("BypassOSKWithKeyboard", &g_Config.bBypassOSKWithKeyboard, false, true, true), #endif ConfigSetting("WlanPowerSave", &g_Config.bWlanPowerSave, (bool) PSP_SYSTEMPARAM_WLAN_POWERSAVE_OFF, true, true), diff --git a/Core/Config.h b/Core/Config.h index 4e354639bc..d8a52cccde 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -207,6 +207,7 @@ public: bool bGfxDebugOutput; bool bGfxDebugSplitSubmit; int iInflightFrames; + bool bRenderDuplicateFrames; // Sound bool bEnableSound; @@ -410,7 +411,6 @@ public: int iPSPModel; int iFirmwareVersion; - // TODO: Make this work with your platform, too! bool bBypassOSKWithKeyboard; // Debugger diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 9d7a37fc49..a5c278bf06 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -28,9 +28,14 @@ #define NETCONF_CONNECT_APNET 0 #define NETCONF_STATUS_APNET 1 #define NETCONF_CONNECT_ADHOC 2 +#define NETCONF_CONNECT_APNET_LAST 3 #define NETCONF_CREATE_ADHOC 4 #define NETCONF_JOIN_ADHOC 5 +// Needs testing. +const static int NET_INIT_DELAY_US = 300000; +const static int NET_SHUTDOWN_DELAY_US = 26000; + PSPNetconfDialog::PSPNetconfDialog() { } @@ -39,7 +44,7 @@ PSPNetconfDialog::~PSPNetconfDialog() { int PSPNetconfDialog::Init(u32 paramAddr) { // Already running - if (status != SCE_UTILITY_STATUS_NONE && status != SCE_UTILITY_STATUS_SHUTDOWN) + if (status != SCE_UTILITY_STATUS_NONE) return SCE_ERROR_UTILITY_INVALID_STATUS; int size = Memory::Read_U32(paramAddr); @@ -47,7 +52,7 @@ int PSPNetconfDialog::Init(u32 paramAddr) { // Only copy the right size to support different request format Memory::Memcpy(&request, paramAddr, size); - status = SCE_UTILITY_STATUS_INITIALIZE; + ChangeStatusInit(NET_INIT_DELAY_US); // Eat any keys pressed before the dialog inited. UpdateButtons(); @@ -67,6 +72,10 @@ void PSPNetconfDialog::DrawBanner() { } int PSPNetconfDialog::Update(int animSpeed) { + if (GetStatus() != SCE_UTILITY_STATUS_RUNNING) { + return SCE_ERROR_UTILITY_INVALID_STATUS; + } + UpdateButtons(); auto di = GetI18NCategory("Dialog"); auto err = GetI18NCategory("Error"); @@ -74,9 +83,7 @@ int PSPNetconfDialog::Update(int animSpeed) { const ImageID confirmBtnImage = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? ImageID("I_CROSS") : ImageID("I_CIRCLE"); const int confirmBtn = g_Config.iButtonPreference == PSP_SYSTEMPARAM_BUTTON_CROSS ? CTRL_CROSS : CTRL_CIRCLE; - if (status == SCE_UTILITY_STATUS_INITIALIZE) { - status = SCE_UTILITY_STATUS_RUNNING; - } else if (status == SCE_UTILITY_STATUS_RUNNING && (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET)) { + if (request.netAction == NETCONF_CONNECT_APNET || request.netAction == NETCONF_STATUS_APNET || request.netAction == NETCONF_CONNECT_APNET_LAST) { UpdateFade(animSpeed); StartDraw(); DrawBanner(); @@ -87,26 +94,24 @@ int PSPNetconfDialog::Update(int animSpeed) { if (IsButtonPressed(confirmBtn)) { StartFade(false); - status = SCE_UTILITY_STATUS_FINISHED; + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); // TODO: When the dialog is aborted, does it really set the result to this? // It seems to make Phantasy Star Portable 2 happy, so it should be okay for now. request.common.result = SCE_UTILITY_DIALOG_RESULT_ABORT; } - - } else if (status == SCE_UTILITY_STATUS_RUNNING && (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC)) { - if (request.NetconfData != NULL) { + + EndDraw(); + } else if (request.netAction == NETCONF_CONNECT_ADHOC || request.netAction == NETCONF_CREATE_ADHOC || request.netAction == NETCONF_JOIN_ADHOC) { + if (request.NetconfData.IsValid()) { Shutdown(true); if (sceNetAdhocctlCreate(request.NetconfData->groupName) == 0) { - status = SCE_UTILITY_STATUS_FINISHED; + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); return 0; } return -1; } - } else if (status == SCE_UTILITY_STATUS_FINISHED) { - status = SCE_UTILITY_STATUS_SHUTDOWN; } - EndDraw(); return 0; } @@ -114,7 +119,12 @@ int PSPNetconfDialog::Shutdown(bool force) { if (status != SCE_UTILITY_STATUS_FINISHED && !force) return SCE_ERROR_UTILITY_INVALID_STATUS; - return PSPDialog::Shutdown(force); + PSPDialog::Shutdown(force); + if (!force) { + ChangeStatusShutdown(NET_SHUTDOWN_DELAY_US); + } + + return 0; } void PSPNetconfDialog::DoState(PointerWrap &p) { diff --git a/Core/Dialog/PSPNetconfDialog.h b/Core/Dialog/PSPNetconfDialog.h index cdb0e5686e..c3f891efd2 100644 --- a/Core/Dialog/PSPNetconfDialog.h +++ b/Core/Dialog/PSPNetconfDialog.h @@ -44,6 +44,11 @@ public: virtual int Shutdown(bool force = false) override; virtual void DoState(PointerWrap &p) override; +protected: + bool UseAutoStatus() override { + return false; + } + private: void DrawBanner(); SceUtilityNetconfParam request; diff --git a/Core/Dialog/PSPOskDialog.cpp b/Core/Dialog/PSPOskDialog.cpp index 85b2ad3342..b97eae0eb7 100755 --- a/Core/Dialog/PSPOskDialog.cpp +++ b/Core/Dialog/PSPOskDialog.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include "base/NativeApp.h" #include "i18n/i18n.h" #include "math/math_util.h" #include "util/text/utf8.h" @@ -30,10 +31,6 @@ #include "Common/ChunkFile.h" #include "GPU/GPUState.h" -#if defined(USING_WIN_UI) -#include "base/NativeApp.h" -#endif - #ifndef _WIN32 #include #include @@ -332,6 +329,9 @@ int PSPOskDialog::Init(u32 oskPtr) { // Eat any keys pressed before the dialog inited. UpdateButtons(); + std::lock_guard guard(nativeMutex_); + nativeStatus_ = PSPOskNativeStatus::IDLE; + StartFade(true); return 0; } @@ -837,7 +837,6 @@ void PSPOskDialog::RenderKeyboard() } } -#if defined(USING_WIN_UI) // TODO: Why does this have a 2 button press lag/delay when // re-opening the dialog box? I don't get it. int PSPOskDialog::NativeKeyboard() { @@ -845,28 +844,51 @@ int PSPOskDialog::NativeKeyboard() { return SCE_ERROR_UTILITY_INVALID_STATUS; } - std::wstring titleText; - GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc); +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) + bool beginInputBox = false; + if (nativeStatus_ == PSPOskNativeStatus::IDLE) { + std::lock_guard guard(nativeMutex_); + if (nativeStatus_ == PSPOskNativeStatus::IDLE) { + nativeStatus_ = PSPOskNativeStatus::WAITING; + beginInputBox = true; + } + } - std::wstring defaultText; - GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext); + if (beginInputBox) { + std::wstring titleText; + GetWideStringFromPSPPointer(titleText, oskParams->fields[0].desc); - if (defaultText.empty()) - defaultText.assign(L"VALUE"); + std::wstring defaultText; + GetWideStringFromPSPPointer(defaultText, oskParams->fields[0].intext); - // TODO: This is USING_WIN_UI only, so we rely on it being synchronous... - // But we should really have this set some state that is checked each time NativeKeyboard is called. - System_InputBoxGetString(ConvertWStringToUTF8(titleText), ConvertWStringToUTF8(defaultText), [&](bool result, const std::string &value) { - if (result) { - inputChars = ConvertUTF8ToWString(value); - u32 maxLength = FieldMaxLength(); - if (inputChars.length() > maxLength) { - ERROR_LOG(SCEUTILITY, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); - inputChars.erase(maxLength, std::string::npos); + if (defaultText.empty()) + defaultText.assign(L"VALUE"); + + System_InputBoxGetString(ConvertWStringToUTF8(titleText), ConvertWStringToUTF8(defaultText), [&](bool result, const std::string &value) { + std::lock_guard guard(nativeMutex_); + if (nativeStatus_ != PSPOskNativeStatus::WAITING) { + return; } + + nativeValue_ = value; + nativeStatus_ = result ? PSPOskNativeStatus::SUCCESS : PSPOskNativeStatus::FAILURE; + }); + } else if (nativeStatus_ == PSPOskNativeStatus::SUCCESS) { + inputChars = ConvertUTF8ToWString(nativeValue_); + nativeValue_.clear(); + + u32 maxLength = FieldMaxLength(); + if (inputChars.length() > maxLength) { + ERROR_LOG(SCEUTILITY, "NativeKeyboard: input text too long(%d characters/glyphs max), truncating to game-requested length.", maxLength); + inputChars.erase(maxLength, std::string::npos); } ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); - }); + nativeStatus_ = PSPOskNativeStatus::DONE; + } else if (nativeStatus_ == PSPOskNativeStatus::FAILURE) { + ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0); + nativeStatus_ = PSPOskNativeStatus::DONE; + } +#endif u16_le *outText = oskParams->fields[0].outtext; @@ -886,7 +908,6 @@ int PSPOskDialog::NativeKeyboard() { return 0; } -#endif int PSPOskDialog::Update(int animSpeed) { if (GetStatus() != SCE_UTILITY_STATUS_RUNNING) { @@ -908,12 +929,10 @@ int PSPOskDialog::Update(int animSpeed) { int selectedRow = selectedChar / numKeyCols[currentKeyboard]; int selectedExtra = selectedChar % numKeyCols[currentKeyboard]; - // TODO: Add your platforms here when you have a NativeKeyboard func. - -#if defined(USING_WIN_UI) +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) // Windows: Fall back to the OSK/continue normally if we're in fullscreen. // The dialog box doesn't work right if in fullscreen. - if(g_Config.bBypassOSKWithKeyboard && !g_Config.bFullScreen) + if (g_Config.bBypassOSKWithKeyboard && !g_Config.bFullScreen) return NativeKeyboard(); #endif @@ -1095,6 +1114,7 @@ int PSPOskDialog::Shutdown(bool force) if (!force) { ChangeStatusShutdown(OSK_SHUTDOWN_DELAY_US); } + nativeStatus_ = PSPOskNativeStatus::IDLE; return 0; } @@ -1113,6 +1133,7 @@ void PSPOskDialog::DoState(PointerWrap &p) p.Do(oskOuttext); p.Do(selectedChar); p.Do(inputChars); + // Don't need to save state native status or value. } pspUtilityDialogCommon *PSPOskDialog::GetCommonParam() diff --git a/Core/Dialog/PSPOskDialog.h b/Core/Dialog/PSPOskDialog.h index cac1358f71..fc57bcf2e4 100644 --- a/Core/Dialog/PSPOskDialog.h +++ b/Core/Dialog/PSPOskDialog.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include "Core/Dialog/PSPDialog.h" @@ -202,6 +203,14 @@ static const std::string OskKeyboardNames[] = "English Full-width", }; +enum class PSPOskNativeStatus { + IDLE, + DONE, + WAITING, + SUCCESS, + FAILURE, +}; + class PSPOskDialog: public PSPDialog { public: PSPOskDialog(); @@ -222,9 +231,7 @@ private: void ConvertUCS2ToUTF8(std::string& _string, const PSPPointer& em_address); void ConvertUCS2ToUTF8(std::string& _string, const wchar_t *input); void RenderKeyboard(); -#if defined(USING_WIN_UI) int NativeKeyboard(); -#endif std::wstring CombinationString(bool isInput); // for Japanese, Korean std::wstring CombinationKorean(bool isInput); // for Korea @@ -244,6 +251,10 @@ private: OskKeyboardLanguage currentKeyboardLanguage; bool isCombinated; + std::mutex nativeMutex_; + PSPOskNativeStatus nativeStatus_ = PSPOskNativeStatus::IDLE; + std::string nativeValue_; + int i_level; // for Korean Keyboard support int i_value[3]; // for Korean Keyboard support }; diff --git a/Core/HLE/KernelThreadDebugInterface.h b/Core/HLE/KernelThreadDebugInterface.h index 012a93fc37..55ead24e65 100644 --- a/Core/HLE/KernelThreadDebugInterface.h +++ b/Core/HLE/KernelThreadDebugInterface.h @@ -21,7 +21,7 @@ class KernelThreadDebugInterface : public MIPSDebugInterface { public: - KernelThreadDebugInterface(MIPSState *c, ThreadContext &t) : MIPSDebugInterface(c), ctx(t) { + KernelThreadDebugInterface(MIPSState *c, PSPThreadContext &t) : MIPSDebugInterface(c), ctx(t) { } unsigned int getPC() override { return ctx.pc; } @@ -86,5 +86,5 @@ public: } protected: - ThreadContext &ctx; + PSPThreadContext &ctx; }; diff --git a/Core/HLE/proAdhoc.h b/Core/HLE/proAdhoc.h index d868dd6559..dedf1d6992 100644 --- a/Core/HLE/proAdhoc.h +++ b/Core/HLE/proAdhoc.h @@ -764,10 +764,10 @@ typedef struct { #pragma pack(pop) #endif -class AfterMatchingMipsCall : public Action { +class AfterMatchingMipsCall : public PSPAction { public: AfterMatchingMipsCall() {} - static Action *Create() { return new AfterMatchingMipsCall(); } + static PSPAction *Create() { return new AfterMatchingMipsCall(); } void DoState(PointerWrap &p) override { auto s = p.Section("AfterMatchingMipsCall", 1, 2); if (!s) diff --git a/Core/HLE/sceDisplay.cpp b/Core/HLE/sceDisplay.cpp index 883cc7a587..09e6a8f985 100644 --- a/Core/HLE/sceDisplay.cpp +++ b/Core/HLE/sceDisplay.cpp @@ -49,6 +49,7 @@ #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" #include "Core/HLE/sceKernelInterrupt.h" +#include "Core/Util/PPGeDraw.h" #include "GPU/GPU.h" #include "GPU/GPUState.h" @@ -753,9 +754,11 @@ void __DisplayFlip(int cyclesLate) { // Also let's always flip for animated shaders. const ShaderInfo *shaderInfo = g_Config.sPostShaderName == "Off" ? nullptr : GetPostShaderInfo(g_Config.sPostShaderName); bool postEffectRequiresFlip = false; + // postEffectRequiresFlip is not compatible with frameskip unthrottling, see #12325. if (shaderInfo && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) - postEffectRequiresFlip = shaderInfo->requires60fps; + postEffectRequiresFlip = (shaderInfo->requires60fps || g_Config.bRenderDuplicateFrames) && !(g_Config.bFrameSkipUnthrottle && !FrameTimingThrottled()); const bool fbDirty = gpu->FramebufferDirty(); + if (fbDirty || noRecentFlip || postEffectRequiresFlip) { int frameSleepPos = frameTimeHistoryPos; CalculateFPS(); @@ -832,6 +835,7 @@ void __DisplayFlip(int cyclesLate) { void hleAfterFlip(u64 userdata, int cyclesLate) { gpu->BeginFrame(); // doesn't really matter if begin or end of frame. + PPGeNotifyFrame(); // This seems like as good a time as any to check if the config changed. if (lagSyncScheduled != g_Config.bForceLagSync) { diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 284cafc78c..e47f7c6667 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -349,10 +349,10 @@ private: DISALLOW_COPY_AND_ASSIGN(LoadedFont); }; -class PostAllocCallback : public Action { +class PostAllocCallback : public PSPAction { public: PostAllocCallback() {} - static Action *Create() { return new PostAllocCallback(); } + static PSPAction *Create() { return new PostAllocCallback(); } void DoState(PointerWrap &p) override { auto s = p.Section("PostAllocCallback", 1, 2); if (!s) @@ -371,10 +371,10 @@ private: u32 errorCodePtr_; }; -class PostOpenCallback : public Action { +class PostOpenCallback : public PSPAction { public: PostOpenCallback() {} - static Action *Create() { return new PostOpenCallback(); } + static PSPAction *Create() { return new PostOpenCallback(); } void DoState(PointerWrap &p) override { auto s = p.Section("PostOpenCallback", 1); if (!s) diff --git a/Core/HLE/sceIo.cpp b/Core/HLE/sceIo.cpp index a27b35e6d1..55e214958c 100644 --- a/Core/HLE/sceIo.cpp +++ b/Core/HLE/sceIo.cpp @@ -2731,7 +2731,7 @@ static int IoAsyncFinish(int id) { break; default: - ERROR_LOG_REPORT(SCEIO, "Unknown async op %d", params.op); + ERROR_LOG_REPORT(SCEIO, "Unknown async op %d", (int)params.op); us = 0; break; } diff --git a/Core/HLE/sceKernelAlarm.cpp b/Core/HLE/sceKernelAlarm.cpp index bed6e58e08..de9c5435ff 100644 --- a/Core/HLE/sceKernelAlarm.cpp +++ b/Core/HLE/sceKernelAlarm.cpp @@ -37,16 +37,14 @@ struct NativeAlarm u32_le commonPtr; }; -struct Alarm : public KernelObject -{ +struct PSPAlarm : public KernelObject { const char *GetName() override {return "[Alarm]";} const char *GetTypeName() override {return "Alarm";} static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_ALMID; } static int GetStaticIDType() { return SCE_KERNEL_TMID_Alarm; } int GetIDType() const override { return SCE_KERNEL_TMID_Alarm; } - void DoState(PointerWrap &p) override - { + void DoState(PointerWrap &p) override { auto s = p.Section("Alarm", 1); if (!s) return; @@ -57,7 +55,7 @@ struct Alarm : public KernelObject NativeAlarm alm; }; -void __KernelScheduleAlarm(Alarm *alarm, u64 micro); +void __KernelScheduleAlarm(PSPAlarm *alarm, u64 micro); class AlarmIntrHandler : public IntrHandler { @@ -69,7 +67,7 @@ public: u32 error; int alarmID = triggeredAlarm.front(); - Alarm *alarm = kernelObjects.Get(alarmID, error); + PSPAlarm *alarm = kernelObjects.Get(alarmID, error); if (error) { WARN_LOG(SCEKERNEL, "Ignoring deleted alarm %08x", alarmID); @@ -95,7 +93,7 @@ public: { DEBUG_LOG(SCEKERNEL, "Rescheduling alarm %08x for +%dms", alarmID, result); u32 error; - Alarm *alarm = kernelObjects.Get(alarmID, error); + PSPAlarm *alarm = kernelObjects.Get(alarmID, error); __KernelScheduleAlarm(alarm, result); } else @@ -106,21 +104,19 @@ public: DEBUG_LOG(SCEKERNEL, "Finished alarm %08x", alarmID); // Delete the alarm if it's not rescheduled. - kernelObjects.Destroy(alarmID); + kernelObjects.Destroy(alarmID); } } }; static int alarmTimer = -1; -static void __KernelTriggerAlarm(u64 userdata, int cyclesLate) -{ +static void __KernelTriggerAlarm(u64 userdata, int cyclesLate) { int uid = (int) userdata; u32 error; - Alarm *alarm = kernelObjects.Get(uid, error); - if (alarm) - { + PSPAlarm *alarm = kernelObjects.Get(uid, error); + if (alarm) { triggeredAlarm.push_back(uid); __TriggerInterrupt(PSP_INTR_IMMEDIATE, PSP_SYSTIMER0_INTR); } @@ -144,14 +140,12 @@ void __KernelAlarmDoState(PointerWrap &p) CoreTiming::RestoreRegisterEvent(alarmTimer, "Alarm", __KernelTriggerAlarm); } -KernelObject *__KernelAlarmObject() -{ +KernelObject *__KernelAlarmObject() { // Default object to load from state. - return new Alarm; + return new PSPAlarm; } -void __KernelScheduleAlarm(Alarm *alarm, u64 micro) -{ +void __KernelScheduleAlarm(PSPAlarm *alarm, u64 micro) { alarm->alm.schedule = CoreTiming::GetGlobalTimeUs() + micro; CoreTiming::ScheduleEvent(usToCycles(micro), alarmTimer, alarm->GetUID()); } @@ -161,7 +155,7 @@ static SceUID __KernelSetAlarm(u64 micro, u32 handlerPtr, u32 commonPtr) if (!Memory::IsValidAddress(handlerPtr)) return SCE_KERNEL_ERROR_ILLEGAL_ADDR; - Alarm *alarm = new Alarm; + PSPAlarm *alarm = new PSPAlarm(); SceUID uid = kernelObjects.Create(alarm); alarm->alm.size = NATIVEALARM_SIZE; @@ -197,13 +191,13 @@ int sceKernelCancelAlarm(SceUID uid) CoreTiming::UnscheduleEvent(alarmTimer, uid); - return kernelObjects.Destroy(uid); + return kernelObjects.Destroy(uid); } int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr) { u32 error; - Alarm *alarm = kernelObjects.Get(uid, error); + PSPAlarm *alarm = kernelObjects.Get(uid, error); if (!alarm) { ERROR_LOG(SCEKERNEL, "sceKernelReferAlarmStatus(%08x, %08x): invalid alarm", uid, infoPtr); @@ -228,4 +222,4 @@ int sceKernelReferAlarmStatus(SceUID uid, u32 infoPtr) Memory::Write_U32(alarm->alm.commonPtr, infoPtr + 16); return 0; -} \ No newline at end of file +} diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 2674a7b2fa..6ec86f99af 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -48,15 +48,13 @@ static const u32 PSP_NUMBER_SUBINTERRUPTS = 32; // INTERRUPT MANAGEMENT ////////////////////////////////////////////////////////////////////////// -class InterruptState -{ +class InterruptState { public: void save(); void restore(); void clear(); - void DoState(PointerWrap &p) - { + void DoState(PointerWrap &p) { auto s = p.Section("InterruptState", 1); if (!s) return; @@ -64,7 +62,7 @@ public: p.Do(savedCpu); } - ThreadContext savedCpu; + PSPThreadContext savedCpu; }; // STATE diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 90fff3aec7..1d37b3c802 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -155,8 +155,8 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting); void ExportFuncSymbol(const FuncSymbolExport &func); void UnexportFuncSymbol(const FuncSymbolExport &func); -class Module; -static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr, bool reimporting = false); +class PSPModule; +static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, bool reimporting = false); struct NativeModule { u32_le next; @@ -228,10 +228,10 @@ enum NativeModuleStatus { MODULE_STATUS_UNLOADING = 8, }; -class Module : public KernelObject { +class PSPModule : public KernelObject { public: - Module() : textStart(0), textEnd(0), libstub(0), libstubend(0), memoryBlockAddr(0), isFake(false) {} - ~Module() { + PSPModule() : textStart(0), textEnd(0), libstub(0), libstubend(0), memoryBlockAddr(0), isFake(false) {} + ~PSPModule() { if (memoryBlockAddr) { // If it's either below user memory, or using a high kernel bit, it's in kernel. if (memoryBlockAddr < PSP_GetUserMemoryBase() || memoryBlockAddr > PSP_GetUserMemoryEnd()) { @@ -421,10 +421,10 @@ public: KernelObject *__KernelModuleObject() { - return new Module; + return new PSPModule; } -class AfterModuleEntryCall : public Action { +class AfterModuleEntryCall : public PSPAction { public: AfterModuleEntryCall() {} SceUID moduleID_; @@ -438,7 +438,7 @@ public: p.Do(moduleID_); p.Do(retValAddr); } - static Action *Create() { + static PSPAction *Create() { return new AfterModuleEntryCall; } }; @@ -507,7 +507,7 @@ void __KernelModuleDoState(PointerWrap &p) u32 error; // We process these late, since they depend on loadedModules for interlinking. for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (module && module->libstub != 0) { if (!KernelImportModuleFuncs(module, nullptr, true)) { ERROR_LOG(LOADER, "Something went wrong loading imports on load state"); @@ -655,7 +655,7 @@ void ImportVarSymbol(const VarSymbolImport &var) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) { continue; } @@ -676,7 +676,7 @@ void ImportVarSymbol(const VarSymbolImport &var) { void ExportVarSymbol(const VarSymbolExport &var) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) { continue; } @@ -694,7 +694,7 @@ void ExportVarSymbol(const VarSymbolExport &var) { void UnexportVarSymbol(const VarSymbolExport &var) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(var.moduleName)) { continue; } @@ -724,7 +724,7 @@ void ImportFuncSymbol(const FuncSymbolImport &func, bool reimporting) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { continue; } @@ -765,7 +765,7 @@ void ExportFuncSymbol(const FuncSymbolExport &func) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { continue; } @@ -790,7 +790,7 @@ void UnexportFuncSymbol(const FuncSymbolExport &func) { u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { continue; } @@ -806,7 +806,7 @@ void UnexportFuncSymbol(const FuncSymbolExport &func) { } } -void Module::Cleanup() { +void PSPModule::Cleanup() { MIPSAnalyst::ForgetFunctions(textStart, textEnd); loadedModules.erase(GetUID()); @@ -909,7 +909,7 @@ static bool IsHLEVersionedModule(const char *name) { return false; } -static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr, bool reimporting) { +static bool KernelImportModuleFuncs(PSPModule *module, u32 *firstImportStubAddr, bool reimporting) { struct PspLibStubEntry { u32_le name; u16_le version; @@ -1090,8 +1090,8 @@ static int gzipDecompress(u8 *OutBuffer, int OutBufferLength, u8 *InBuffer) { return stream.total_out; } -static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { - Module *module = new Module; +static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) { + PSPModule *module = new PSPModule(); kernelObjects.Create(module); loadedModules.insert(module->GetUID()); memset(&module->nm, 0, sizeof(module->nm)); @@ -1133,7 +1133,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd if (size > elfSize) { *error_string = StringFromFormat("ELF/PRX truncated: %d > %d", (int)size, (int)elfSize); module->Cleanup(); - kernelObjects.Destroy(module->GetUID()); + kernelObjects.Destroy(module->GetUID()); return nullptr; } const auto maxElfSize = std::max(head->elf_size, head->psp_size); @@ -1166,7 +1166,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd if (addr == (u32)-1) { error = SCE_KERNEL_ERROR_MEMBLOCK_ALLOC_FAILED; module->Cleanup(); - kernelObjects.Destroy(module->GetUID()); + kernelObjects.Destroy(module->GetUID()); } else { error = 0; module->memoryBlockAddr = addr; @@ -1207,7 +1207,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd if (newptr) delete [] newptr; module->Cleanup(); - kernelObjects.Destroy(module->GetUID()); + kernelObjects.Destroy(module->GetUID()); error = SCE_KERNEL_ERROR_UNSUPPORTED_PRX_TYPE; return nullptr; } @@ -1221,7 +1221,7 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd if (newptr) delete [] newptr; module->Cleanup(); - kernelObjects.Destroy(module->GetUID()); + kernelObjects.Destroy(module->GetUID()); error = result; return nullptr; } @@ -1536,8 +1536,8 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 loadAdd return module; } -static Module *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOption *options, std::string *error_string) { - Module *module = 0; +static PSPModule *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOption *options, std::string *error_string) { + PSPModule *module = nullptr; // Check for PBP if (memcmp(fileptr, "\0PBP", 4) == 0) { // PBP! @@ -1583,8 +1583,7 @@ static Module *__KernelLoadModule(u8 *fileptr, size_t fileSize, SceKernelLMOptio return module; } -static void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOption *options) -{ +static void __KernelStartModule(PSPModule *m, int args, const char *argp, SceKernelSMOption *options) { m->nm.status = MODULE_STATUS_STARTED; if (m->nm.module_start_func != 0 && m->nm.module_start_func != (u32)-1) { @@ -1599,16 +1598,12 @@ static void __KernelStartModule(Module *m, int args, const char *argp, SceKernel } -u32 __KernelGetModuleGP(SceUID uid) -{ +u32 __KernelGetModuleGP(SceUID uid) { u32 error; - Module *module = kernelObjects.Get(uid, error); - if (module) - { + PSPModule *module = kernelObjects.Get(uid, error); + if (module) { return module->nm.gp_value; - } - else - { + } else { return 0; } } @@ -1619,7 +1614,7 @@ void __KernelLoadReset() { u32 error; while (!loadedModules.empty()) { SceUID moduleID = *loadedModules.begin(); - Module *module = kernelObjects.Get(moduleID, error); + PSPModule *module = kernelObjects.Get(moduleID, error); if (module) { module->Cleanup(); } else { @@ -1686,12 +1681,12 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str pspFileSystem.ReadFile(handle, temp, (size_t)info.size); PSP_SetLoading("Loading modules..."); - Module *module = __KernelLoadModule(temp, (size_t)info.size, 0, error_string); + PSPModule *module = __KernelLoadModule(temp, (size_t)info.size, 0, error_string); if (!module || module->isFake) { if (module) { module->Cleanup(); - kernelObjects.Destroy(module->GetUID()); + kernelObjects.Destroy(module->GetUID()); } ERROR_LOG(LOADER, "Failed to load module %s", filename); *error_string = "Failed to load executable: " + *error_string; @@ -1770,7 +1765,7 @@ bool __KernelLoadGEDump(const std::string &base_filename, std::string *error_str Memory::WriteUnchecked_U32(runDumpCode[i], mipsr4k.pc + (int)i * sizeof(u32_le)); } - Module *module = new Module; + PSPModule *module = new PSPModule(); kernelObjects.Create(module); loadedModules.insert(module->GetUID()); memset(&module->nm, 0, sizeof(module->nm)); @@ -1847,7 +1842,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { for (size_t i = 0; i < ARRAY_SIZE(lieAboutSuccessModules); i++) { if (!strcmp(name, lieAboutSuccessModules[i])) { - Module *module = new Module; + PSPModule *module = new PSPModule(); kernelObjects.Create(module); loadedModules.insert(module->GetUID()); memset(&module->nm, 0, sizeof(module->nm)); @@ -1898,7 +1893,7 @@ u32 sceKernelLoadModule(const char *name, u32 flags, u32 optionAddr) { WARN_LOG_REPORT(LOADER, "sceKernelLoadModule: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); } - Module *module = 0; + PSPModule *module = nullptr; u8 *temp = new u8[(int)size]; u32 handle = pspFileSystem.OpenFile(name, FILEACCESS_READ); pspFileSystem.ReadFile(handle, temp, (size_t)size); @@ -1961,7 +1956,7 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret Memory::ReadStruct(optionAddr, &smoption); } u32 error; - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) { INFO_LOG(SCEMODULE, "sceKernelStartModule(%d,asize=%08x,aptr=%08x,retptr=%08x,%08x): error %08x", moduleId, argsize, argAddr, returnValueAddr, optionAddr, error); RETURN(error); @@ -2060,7 +2055,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur // TODO: In a lot of cases (even for errors), this should resched. Needs testing. u32 error; - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) { ERROR_LOG(SCEMODULE, "sceKernelStopModule(%08x, %08x, %08x, %08x, %08x): invalid module id", moduleId, argSize, argAddr, returnValueAddr, optionAddr); @@ -2133,12 +2128,12 @@ static u32 sceKernelUnloadModule(u32 moduleId) { INFO_LOG(SCEMODULE,"sceKernelUnloadModule(%i)", moduleId); u32 error; - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module) return hleDelayResult(error, "module unloaded", 150); module->Cleanup(); - kernelObjects.Destroy(moduleId); + kernelObjects.Destroy(moduleId); return hleDelayResult(moduleId, "module unloaded", 500); } @@ -2155,7 +2150,7 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, // TODO: In a lot of cases (even for errors), this should resched. Needs testing. u32 error; - Module *module = kernelObjects.Get(moduleID, error); + PSPModule *module = kernelObjects.Get(moduleID, error); if (!module) { if (WithStatus) ERROR_LOG(SCEMODULE, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): invalid module id", exitCode, argSize, argp, statusAddr, optionAddr); @@ -2204,7 +2199,7 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, INFO_LOG(SCEMODULE, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): no stop func", exitCode, argSize, argp); sceKernelExitDeleteThread(exitCode); module->Cleanup(); - kernelObjects.Destroy(moduleID); + kernelObjects.Destroy(moduleID); } else { if (WithStatus) ERROR_LOG_REPORT(SCEMODULE, "sceKernelStopUnloadSelfModuleWithStatus(%08x, %08x, %08x, %08x, %08x): bad stop func address", exitCode, argSize, argp, statusAddr, optionAddr); @@ -2212,7 +2207,7 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, ERROR_LOG_REPORT(SCEMODULE, "sceKernelSelfStopUnloadModule(%08x, %08x, %08x): bad stop func address", exitCode, argSize, argp); sceKernelExitDeleteThread(exitCode); module->Cleanup(); - kernelObjects.Destroy(moduleID); + kernelObjects.Destroy(moduleID); } } else { if (WithStatus) @@ -2248,7 +2243,7 @@ void __KernelReturnFromModuleFunc() sceKernelDeleteThread(leftThreadID); u32 error; - Module *module = kernelObjects.Get(leftModuleID, error); + PSPModule *module = kernelObjects.Get(leftModuleID, error); if (!module) { ERROR_LOG_REPORT(SCEMODULE, "Returned from deleted module start/stop func"); return; @@ -2278,7 +2273,7 @@ void __KernelReturnFromModuleFunc() if (module->nm.status == MODULE_STATUS_UNLOADING) { // TODO: Delete the waiting thread? module->Cleanup(); - kernelObjects.Destroy(leftModuleID); + kernelObjects.Destroy(leftModuleID); } } @@ -2288,11 +2283,9 @@ struct GetModuleIdByAddressArg SceUID result; }; -static bool __GetModuleIdByAddressIterator(Module *module, GetModuleIdByAddressArg *state) -{ +static bool __GetModuleIdByAddressIterator(PSPModule *module, GetModuleIdByAddressArg *state) { const u32 start = module->memoryBlockAddr, size = module->memoryBlockSize; - if (start != 0 && start <= state->addr && start + size > state->addr) - { + if (start != 0 && start <= state->addr && start + size > state->addr) { state->result = module->GetUID(); return false; } @@ -2351,7 +2344,7 @@ static u32 sceKernelLoadModuleByID(u32 id, u32 flags, u32 lmoptionPtr) size_t size = pspFileSystem.SeekFile(handle, 0, FILEMOVE_END); std::string error_string; pspFileSystem.SeekFile(handle, pos, FILEMOVE_BEGIN); - Module *module = 0; + PSPModule *module = nullptr; u8 *temp = new u8[size - pos]; pspFileSystem.ReadFile(handle, temp, size - pos); u32 magic; @@ -2409,7 +2402,7 @@ static SceUID sceKernelLoadModuleBufferUsbWlan(u32 size, u32 bufPtr, u32 flags, WARN_LOG_REPORT(LOADER, "sceKernelLoadModuleBufferUsbWlan: unsupported options size=%08x, flags=%08x, pos=%d, access=%d, data=%d, text=%d", lmoption->size, lmoption->flags, lmoption->position, lmoption->access, lmoption->mpiddata, lmoption->mpidtext); } std::string error_string; - Module *module = 0; + PSPModule *module = nullptr; u32 magic; u32 error; module = __KernelLoadELFFromPtr(Memory::GetPointer(bufPtr), size, 0, lmoption ? lmoption->position == PSP_SMEM_High : false, &error_string, &magic, error); @@ -2451,7 +2444,7 @@ static u32 sceKernelQueryModuleInfo(u32 uid, u32 infoAddr) { INFO_LOG(SCEMODULE, "sceKernelQueryModuleInfo(%i, %08x)", uid, infoAddr); u32 error; - Module *module = kernelObjects.Get(uid, error); + PSPModule *module = kernelObjects.Get(uid, error); if (!module) return error; if (!Memory::IsValidAddress(infoAddr)) { @@ -2492,7 +2485,7 @@ static u32 sceKernelGetModuleIdList(u32 resultBuffer, u32 resultBufferSize, u32 u32 error; for (SceUID moduleId : loadedModules) { - Module *module = kernelObjects.Get(moduleId, error); + PSPModule *module = kernelObjects.Get(moduleId, error); if (!module->isFake) { if (resultBufferOffset < resultBufferSize) { Memory::Write_U32(module->GetUID(), resultBuffer + resultBufferOffset); diff --git a/Core/HLE/sceKernelMutex.cpp b/Core/HLE/sceKernelMutex.cpp index 39e20fd952..38b4583c9b 100644 --- a/Core/HLE/sceKernelMutex.cpp +++ b/Core/HLE/sceKernelMutex.cpp @@ -62,7 +62,7 @@ struct NativeMutex s32_le numWaitThreads; }; -struct Mutex : public KernelObject +struct PSPMutex : public KernelObject { const char *GetName() override { return nm.name; } const char *GetTypeName() override { return "Mutex"; } @@ -189,7 +189,7 @@ void __KernelMutexDoState(PointerWrap &p) KernelObject *__KernelMutexObject() { - return new Mutex; + return new PSPMutex; } KernelObject *__KernelLwMutexObject() @@ -202,8 +202,7 @@ void __KernelMutexShutdown() mutexHeldLocks.clear(); } -static void __KernelMutexAcquireLock(Mutex *mutex, int count, SceUID thread) -{ +static void __KernelMutexAcquireLock(PSPMutex *mutex, int count, SceUID thread) { #if defined(_DEBUG) auto locked = mutexHeldLocks.equal_range(thread); for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) @@ -216,13 +215,11 @@ static void __KernelMutexAcquireLock(Mutex *mutex, int count, SceUID thread) mutex->nm.lockThread = thread; } -static void __KernelMutexAcquireLock(Mutex *mutex, int count) -{ +static void __KernelMutexAcquireLock(PSPMutex *mutex, int count) { __KernelMutexAcquireLock(mutex, count, __KernelGetCurThread()); } -static void __KernelMutexEraseLock(Mutex *mutex) -{ +static void __KernelMutexEraseLock(PSPMutex *mutex) { if (mutex->nm.lockThread != -1) { SceUID id = mutex->GetUID(); @@ -259,8 +256,7 @@ static std::vector::iterator __KernelMutexFindPriority(std::vectorGetUID())) return false; @@ -283,8 +279,7 @@ static bool __KernelUnlockMutexForThread(Mutex *mutex, SceUID threadID, u32 &err return true; } -static bool __KernelUnlockMutexForThreadCheck(Mutex *mutex, SceUID threadID, u32 &error, int result, bool &wokeThreads) -{ +static bool __KernelUnlockMutexForThreadCheck(PSPMutex *mutex, SceUID threadID, u32 &error, int result, bool &wokeThreads) { if (mutex->nm.lockThread == -1 && __KernelUnlockMutexForThread(mutex, threadID, error, 0)) return true; return false; @@ -292,7 +287,7 @@ static bool __KernelUnlockMutexForThreadCheck(Mutex *mutex, SceUID threadID, u32 void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mutexWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, mutexWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Suspending lock wait for callback"); else @@ -301,7 +296,7 @@ void __KernelMutexBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelMutexEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mutexWaitTimer, __KernelUnlockMutexForThreadCheck); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, mutexWaitTimer, __KernelUnlockMutexForThreadCheck); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB: Resuming lock wait for callback"); } @@ -324,7 +319,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio if ((attr & PSP_MUTEX_ATTR_ALLOW_RECURSIVE) == 0 && initialCount > 1) return SCE_KERNEL_ERROR_ILLEGAL_COUNT; - Mutex *mutex = new Mutex(); + PSPMutex *mutex = new PSPMutex(); SceUID id = kernelObjects.Create(mutex); mutex->nm.size = sizeof(mutex->nm); @@ -357,7 +352,7 @@ int sceKernelCreateMutex(const char *name, u32 attr, int initialCount, u32 optio int sceKernelDeleteMutex(SceUID id) { u32 error; - Mutex *mutex = kernelObjects.Get(id, error); + PSPMutex *mutex = kernelObjects.Get(id, error); if (mutex) { DEBUG_LOG(SCEKERNEL, "sceKernelDeleteMutex(%i)", id); @@ -373,7 +368,7 @@ int sceKernelDeleteMutex(SceUID id) if (wokeThreads) hleReSchedule("mutex deleted"); - return kernelObjects.Destroy(id); + return kernelObjects.Destroy(id); } else { @@ -382,8 +377,7 @@ int sceKernelDeleteMutex(SceUID id) } } -static bool __KernelLockMutexCheck(Mutex *mutex, int count, u32 &error) -{ +static bool __KernelLockMutexCheck(PSPMutex *mutex, int count, u32 &error) { if (error) return false; @@ -411,8 +405,7 @@ static bool __KernelLockMutexCheck(Mutex *mutex, int count, u32 &error) return false; } -static bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) -{ +static bool __KernelLockMutex(PSPMutex *mutex, int count, u32 &error) { if (!__KernelLockMutexCheck(mutex, count, error)) return false; @@ -433,8 +426,7 @@ static bool __KernelLockMutex(Mutex *mutex, int count, u32 &error) return false; } -static bool __KernelUnlockMutex(Mutex *mutex, u32 &error) -{ +static bool __KernelUnlockMutex(PSPMutex *mutex, u32 &error) { __KernelMutexEraseLock(mutex); bool wokeThreads = false; @@ -459,7 +451,7 @@ static bool __KernelUnlockMutex(Mutex *mutex, u32 &error) void __KernelMutexTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID)userdata; - HLEKernel::WaitExecTimeout(threadID); + HLEKernel::WaitExecTimeout(threadID); } void __KernelMutexThreadEnd(SceUID threadID) @@ -470,7 +462,7 @@ void __KernelMutexThreadEnd(SceUID threadID) SceUID waitingMutexID = __KernelGetWaitID(threadID, WAITTYPE_MUTEX, error); if (waitingMutexID) { - Mutex *mutex = kernelObjects.Get(waitingMutexID, error); + PSPMutex *mutex = kernelObjects.Get(waitingMutexID, error); if (mutex) HLEKernel::RemoveWaitingThread(mutex->waitingThreads, threadID); } @@ -481,7 +473,7 @@ void __KernelMutexThreadEnd(SceUID threadID) { // Need to increment early so erase() doesn't invalidate. SceUID mutexID = (*iter++).second; - Mutex *mutex = kernelObjects.Get(mutexID, error); + PSPMutex *mutex = kernelObjects.Get(mutexID, error); if (mutex) { @@ -491,8 +483,7 @@ void __KernelMutexThreadEnd(SceUID threadID) } } -static void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr) -{ +static void __KernelWaitMutex(PSPMutex *mutex, u32 timeoutPtr) { if (timeoutPtr == 0 || mutexWaitTimer == -1) return; @@ -511,7 +502,7 @@ static void __KernelWaitMutex(Mutex *mutex, u32 timeoutPtr) int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr) { u32 error; - Mutex *mutex = kernelObjects.Get(uid, error); + PSPMutex *mutex = kernelObjects.Get(uid, error); if (mutex) { bool lockable = count <= 0 || __KernelLockMutexCheck(mutex, count, error); @@ -566,7 +557,7 @@ int sceKernelLockMutex(SceUID id, int count, u32 timeoutPtr) { DEBUG_LOG(SCEKERNEL, "sceKernelLockMutex(%i, %i, %08x)", id, count, timeoutPtr); u32 error; - Mutex *mutex = kernelObjects.Get(id, error); + PSPMutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) return 0; @@ -591,7 +582,7 @@ int sceKernelLockMutexCB(SceUID id, int count, u32 timeoutPtr) { DEBUG_LOG(SCEKERNEL, "sceKernelLockMutexCB(%i, %i, %08x)", id, count, timeoutPtr); u32 error; - Mutex *mutex = kernelObjects.Get(id, error); + PSPMutex *mutex = kernelObjects.Get(id, error); if (!__KernelLockMutexCheck(mutex, count, error)) { @@ -630,7 +621,7 @@ int sceKernelTryLockMutex(SceUID id, int count) { DEBUG_LOG(SCEKERNEL, "sceKernelTryLockMutex(%i, %i)", id, count); u32 error; - Mutex *mutex = kernelObjects.Get(id, error); + PSPMutex *mutex = kernelObjects.Get(id, error); if (__KernelLockMutex(mutex, count, error)) return 0; @@ -645,7 +636,7 @@ int sceKernelUnlockMutex(SceUID id, int count) { DEBUG_LOG(SCEKERNEL, "sceKernelUnlockMutex(%i, %i)", id, count); u32 error; - Mutex *mutex = kernelObjects.Get(id, error); + PSPMutex *mutex = kernelObjects.Get(id, error); if (error) return error; @@ -672,7 +663,7 @@ int sceKernelUnlockMutex(SceUID id, int count) int sceKernelReferMutexStatus(SceUID id, u32 infoAddr) { u32 error; - Mutex *m = kernelObjects.Get(id, error); + PSPMutex *m = kernelObjects.Get(id, error); if (!m) { ERROR_LOG(SCEKERNEL, "sceKernelReferMutexStatus(%i, %08x): invalid mutex id", id, infoAddr); @@ -1136,4 +1127,4 @@ int sceKernelReferLwMutexStatus(u32 workareaPtr, u32 infoPtr) ERROR_LOG(SCEKERNEL, "%08x=sceKernelReferLwMutexStatus(%08x, %08x)", error, workareaPtr, infoPtr); return error; } -} \ No newline at end of file +} diff --git a/Core/HLE/sceKernelSemaphore.cpp b/Core/HLE/sceKernelSemaphore.cpp index 8037fdcc12..6d96dec8e8 100644 --- a/Core/HLE/sceKernelSemaphore.cpp +++ b/Core/HLE/sceKernelSemaphore.cpp @@ -53,8 +53,7 @@ struct NativeSemaphore }; -struct Semaphore : public KernelObject -{ +struct PSPSemaphore : public KernelObject { const char *GetName() override { return ns.name; } const char *GetTypeName() override { return "Semaphore"; } @@ -103,12 +102,11 @@ void __KernelSemaDoState(PointerWrap &p) KernelObject *__KernelSemaphoreObject() { - return new Semaphore; + return new PSPSemaphore; } // Returns whether the thread should be removed. -static bool __KernelUnlockSemaForThread(Semaphore *s, SceUID threadID, u32 &error, int result, bool &wokeThreads) -{ +static bool __KernelUnlockSemaForThread(PSPSemaphore *s, SceUID threadID, u32 &error, int result, bool &wokeThreads) { if (!HLEKernel::VerifyWait(threadID, WAITTYPE_SEMA, s->GetUID())) return true; @@ -139,7 +137,7 @@ static bool __KernelUnlockSemaForThread(Semaphore *s, SceUID threadID, u32 &erro void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, semaWaitTimer); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, semaWaitTimer); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelWaitSemaCB: Suspending sema wait for callback"); else @@ -148,15 +146,14 @@ void __KernelSemaBeginCallback(SceUID threadID, SceUID prevCallbackId) void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, semaWaitTimer, __KernelUnlockSemaForThread); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, semaWaitTimer, __KernelUnlockSemaForThread); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(SCEKERNEL, "sceKernelWaitSemaCB: Resuming sema wait for callback"); } // Resume all waiting threads (for delete / cancel.) // Returns true if it woke any threads. -static bool __KernelClearSemaThreads(Semaphore *s, int reason) -{ +static bool __KernelClearSemaThreads(PSPSemaphore *s, int reason) { u32 error; bool wokeThreads = false; std::vector::iterator iter, end; @@ -170,7 +167,7 @@ static bool __KernelClearSemaThreads(Semaphore *s, int reason) int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr) { u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { if (newCount > s->ns.maxCount) @@ -215,7 +212,7 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 return SCE_KERNEL_ERROR_ILLEGAL_ATTR; } - Semaphore *s = new Semaphore; + PSPSemaphore *s = new PSPSemaphore(); SceUID id = kernelObjects.Create(s); s->ns.size = sizeof(NativeSemaphore); @@ -244,7 +241,7 @@ int sceKernelCreateSema(const char* name, u32 attr, int initVal, int maxVal, u32 int sceKernelDeleteSema(SceUID id) { u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { DEBUG_LOG(SCEKERNEL, "sceKernelDeleteSema(%i)", id); @@ -253,7 +250,7 @@ int sceKernelDeleteSema(SceUID id) if (wokeThreads) hleReSchedule("semaphore deleted"); - return kernelObjects.Destroy(id); + return kernelObjects.Destroy(id); } else { @@ -265,7 +262,7 @@ int sceKernelDeleteSema(SceUID id) int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) { u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { DEBUG_LOG(SCEKERNEL, "sceKernelReferSemaStatus(%i, %08x)", id, infoPtr); @@ -290,7 +287,7 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr) int sceKernelSignalSema(SceUID id, int signal) { u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { if (s->ns.currentCount + signal - (int) s->waitingThreads.size() > s->ns.maxCount) @@ -336,10 +333,10 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) u32 error; SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error); - HLEKernel::WaitExecTimeout(threadID); + HLEKernel::WaitExecTimeout(threadID); // If in FIFO mode, that may have cleared another thread to wake up. - Semaphore *s = kernelObjects.Get(uid, error); + PSPSemaphore *s = kernelObjects.Get(uid, error); if (s && (s->ns.attr & PSP_SEMA_ATTR_PRIORITY) == PSP_SEMA_ATTR_FIFO) { bool wokeThreads; std::vector::iterator iter = s->waitingThreads.begin(); @@ -351,8 +348,7 @@ void __KernelSemaTimeout(u64 userdata, int cycleslate) } } -static void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr) -{ +static void __KernelSetSemaTimeout(PSPSemaphore *s, u32 timeoutPtr) { if (timeoutPtr == 0 || semaWaitTimer == -1) return; @@ -378,7 +374,7 @@ static int __KernelWaitSema(SceUID id, int wantedCount, u32 timeoutPtr, bool pro hleEatCycles(500); u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { if (wantedCount > s->ns.maxCount) @@ -438,7 +434,7 @@ int sceKernelPollSema(SceUID id, int wantedCount) } u32 error; - Semaphore *s = kernelObjects.Get(id, error); + PSPSemaphore *s = kernelObjects.Get(id, error); if (s) { if (s->ns.currentCount >= wantedCount && s->waitingThreads.size() == 0) diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 70ffb4fb11..fb50b295ca 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -134,22 +134,19 @@ struct NativeCallback s32_le notifyArg; }; -class Callback : public KernelObject -{ +class PSPCallback : public KernelObject { public: const char *GetName() override { return nc.name; } const char *GetTypeName() override { return "CallBack"; } - void GetQuickInfo(char *ptr, int size) override - { + void GetQuickInfo(char *ptr, int size) override { sprintf(ptr, "thread=%i, argument= %08x", //hackAddress, nc.threadId, nc.commonArgument); } - ~Callback() - { + ~PSPCallback() { } static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_CBID; } @@ -267,9 +264,9 @@ public: types_[actionType] = creator; } - Action *createActionByType(int actionType) { + PSPAction *createActionByType(int actionType) { if (actionType < (int) types_.size() && types_[actionType] != NULL) { - Action *a = types_[actionType](); + PSPAction *a = types_[actionType](); a->actionTypeID = actionType; return a; } @@ -292,7 +289,7 @@ private: u32 idGen_; }; -class ActionAfterMipsCall : public Action +class ActionAfterMipsCall : public PSPAction { ActionAfterMipsCall() { @@ -302,8 +299,7 @@ class ActionAfterMipsCall : public Action public: void run(MipsCall &call) override; - static Action *Create() - { + static PSPAction *Create() { return new ActionAfterMipsCall(); } @@ -344,17 +340,16 @@ public: bool isProcessingCallbacks; SceUID currentCallbackId; - Action *chainedAction; + PSPAction *chainedAction; }; -class ActionAfterCallback : public Action +class ActionAfterCallback : public PSPAction { public: ActionAfterCallback() {} void run(MipsCall &call) override; - static Action *Create() - { + static PSPAction *Create() { return new ActionAfterCallback; } @@ -375,8 +370,7 @@ public: SceUID cbId; }; -class Thread : public KernelObject -{ +class PSPThread : public KernelObject { public: const char *GetName() override { return nt.name; } const char *GetTypeName() override { return "Thread"; } @@ -497,8 +491,7 @@ public: return true; } - Thread() : debug(currentMIPS, context) - { + PSPThread() : debug(currentMIPS, context) { currentStack.start = 0; } @@ -507,7 +500,7 @@ public: { // Callbacks are automatically deleted when their owning thread is deleted. for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it) - kernelObjects.Destroy(*it); + kernelObjects.Destroy(*it); if (pushedStacks.size() != 0) { @@ -589,7 +582,7 @@ public: u32 currentMipscallId; SceUID currentCallbackId; - ThreadContext context; + PSPThreadContext context; KernelThreadDebugInterface debug; std::vector callbacks; @@ -620,11 +613,11 @@ struct WaitTypeFuncs bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter); -Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr); -void __KernelResetThread(Thread *t, int lowestPriority); +PSPThread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr); +void __KernelResetThread(PSPThread *t, int lowestPriority); void __KernelCancelWakeup(SceUID threadID); void __KernelCancelThreadEndTimeout(SceUID threadID); -bool __KernelCheckThreadCallbacks(Thread *thread, bool force); +bool __KernelCheckThreadCallbacks(PSPThread *thread, bool force); ////////////////////////////////////////////////////////////////////////// //STATE BEGIN @@ -634,7 +627,7 @@ int g_inCbCount = 0; SceUID currentCallbackThreadID = 0; int readyCallbacksCount = 0; SceUID currentThread; -Thread *currentThreadPtr; +PSPThread *currentThreadPtr; u32 idleThreadHackAddr; u32 threadReturnHackAddr; u32 cbReturnHackAddr; @@ -689,7 +682,7 @@ void __KernelRestoreActionType(int actionType, ActionCreator creator) mipsCalls.restoreActionType(actionType, creator); } -Action *__KernelCreateAction(int actionType) +PSPAction *__KernelCreateAction(int actionType) { return mipsCalls.createActionByType(actionType); } @@ -739,11 +732,11 @@ void MipsCall::setReturnValue(u64 value) savedV1 = (value >> 32) & 0xFFFFFFFF; } -inline Thread *__GetCurrentThread() { +inline PSPThread *__GetCurrentThread() { return currentThreadPtr; } -inline void __SetCurrentThread(Thread *thread, SceUID threadID, const char *name) { +inline void __SetCurrentThread(PSPThread *thread, SceUID threadID, const char *name) { currentThread = threadID; currentThreadPtr = thread; hleCurrentThreadName = name; @@ -804,7 +797,7 @@ static void __KernelSleepBeginCallback(SceUID threadID, SceUID prevCallbackId) { static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (!thread) { // This probably should not happen. WARN_LOG_REPORT(SCEKERNEL, "sceKernelSleepThreadCB: thread deleted?"); @@ -824,7 +817,7 @@ static void __KernelSleepEndCallback(SceUID threadID, SceUID prevCallbackId) { static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventThreadEndTimeout); + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, eventThreadEndTimeout); if (result == HLEKernel::WAIT_CB_SUCCESS) DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB: Suspending wait for callback"); else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) @@ -833,13 +826,11 @@ static void __KernelThreadEndBeginCallback(SceUID threadID, SceUID prevCallbackI WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitThreadEndCB: beginning callback with bad wait id?"); } -static bool __KernelCheckResumeThreadEnd(Thread *t, SceUID waitingThreadID, u32 &error, int result, bool &wokeThreads) -{ +static bool __KernelCheckResumeThreadEnd(PSPThread *t, SceUID waitingThreadID, u32 &error, int result, bool &wokeThreads) { if (!HLEKernel::VerifyWait(waitingThreadID, WAITTYPE_THREADEND, t->GetUID())) return true; - if (t->nt.status == THREADSTATUS_DORMANT) - { + if (t->nt.status == THREADSTATUS_DORMANT) { u32 timeoutPtr = __KernelGetWaitTimeoutPtr(waitingThreadID, error); s64 cyclesLeft = CoreTiming::UnscheduleEvent(eventThreadEndTimeout, waitingThreadID); if (timeoutPtr != 0) @@ -854,7 +845,7 @@ static bool __KernelCheckResumeThreadEnd(Thread *t, SceUID waitingThreadID, u32 static void __KernelThreadEndEndCallback(SceUID threadID, SceUID prevCallbackId) { - auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventThreadEndTimeout, __KernelCheckResumeThreadEnd); + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, eventThreadEndTimeout, __KernelCheckResumeThreadEnd); if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) DEBUG_LOG(SCEKERNEL, "sceKernelWaitThreadEndCB: Resuming wait from callback"); } @@ -877,7 +868,7 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid) else { u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (!thread) return error; @@ -995,7 +986,7 @@ void __KernelThreadingDoState(PointerWrap &p) p.Do(pausedDelays); - __SetCurrentThread(kernelObjects.GetFast(currentThread), currentThread, __KernelGetThreadName(currentThread)); + __SetCurrentThread(kernelObjects.GetFast(currentThread), currentThread, __KernelGetThreadName(currentThread)); lastSwitchCycles = CoreTiming::GetTicks(); if (s >= 2) @@ -1013,12 +1004,12 @@ void __KernelThreadingDoStateLate(PointerWrap &p) KernelObject *__KernelThreadObject() { - return new Thread; + return new PSPThread; } KernelObject *__KernelCallbackObject() { - return new Callback; + return new PSPCallback; } void __KernelListenThreadEnd(ThreadCallback callback) @@ -1036,8 +1027,7 @@ static void __KernelFireThreadEnd(SceUID threadID) } // TODO: Use __KernelChangeThreadState instead? It has other affects... -static void __KernelChangeReadyState(Thread *thread, SceUID threadID, bool ready) -{ +static void __KernelChangeReadyState(PSPThread *thread, SceUID threadID, bool ready) { // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc. _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == threadID, "Incorrect threadID"); int prio = thread->nt.currentPriority; @@ -1060,7 +1050,7 @@ static void __KernelChangeReadyState(Thread *thread, SceUID threadID, bool ready static void __KernelChangeReadyState(SceUID threadID, bool ready) { u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (thread) __KernelChangeReadyState(thread, threadID, ready); else @@ -1072,7 +1062,7 @@ void __KernelStartIdleThreads(SceUID moduleId) for (int i = 0; i < 2; i++) { u32 error; - Thread *t = kernelObjects.Get(threadIdleID[i], error); + PSPThread *t = kernelObjects.Get(threadIdleID[i], error); t->nt.gpreg = __KernelGetModuleGP(moduleId); t->context.r[MIPS_REG_GP] = t->nt.gpreg; //t->context.pc += 4; // ADJUSTPC @@ -1090,12 +1080,12 @@ bool __KernelSwitchOffThread(const char *reason) if (threadID != threadIdleID[0] && threadID != threadIdleID[1]) { - Thread *current = __GetCurrentThread(); + PSPThread *current = __GetCurrentThread(); if (current && current->isRunning()) __KernelChangeReadyState(current, threadID, true); // Idle 0 chosen entirely arbitrarily. - Thread *t = kernelObjects.GetFast(threadIdleID[0]); + PSPThread *t = kernelObjects.GetFast(threadIdleID[0]); if (t) { hleSkipDeadbeef(); @@ -1124,7 +1114,7 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason) return false; u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { ERROR_LOG_REPORT(SCEKERNEL, "__KernelSwitchToThread: %x doesn't exist", threadID); @@ -1132,7 +1122,7 @@ bool __KernelSwitchToThread(SceUID threadID, const char *reason) } else if (t->isReady() || t->isRunning()) { - Thread *current = __GetCurrentThread(); + PSPThread *current = __GetCurrentThread(); if (current && current->isRunning()) __KernelChangeReadyState(current, currentThread, true); @@ -1178,7 +1168,7 @@ void __KernelThreadingShutdown() { const char *__KernelGetThreadName(SceUID threadID) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) return t->nt.name; return "ERROR"; @@ -1186,61 +1176,47 @@ const char *__KernelGetThreadName(SceUID threadID) bool KernelIsThreadDormant(SceUID threadID) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) return (t->nt.status & (THREADSTATUS_DEAD | THREADSTATUS_DORMANT)) != 0; return 0; } -u32 __KernelGetWaitValue(SceUID threadID, u32 &error) -{ - Thread *t = kernelObjects.Get(threadID, error); - if (t) - { +u32 __KernelGetWaitValue(SceUID threadID, u32 &error) { + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) { return t->getWaitInfo().waitValue; - } - else - { + } else { ERROR_LOG(SCEKERNEL, "__KernelGetWaitValue ERROR: thread %i", threadID); return 0; } } -u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error) -{ - Thread *t = kernelObjects.Get(threadID, error); - if (t) - { +u32 __KernelGetWaitTimeoutPtr(SceUID threadID, u32 &error) { + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) { return t->getWaitInfo().timeoutPtr; - } - else - { + } else { ERROR_LOG(SCEKERNEL, "__KernelGetWaitTimeoutPtr ERROR: thread %i", threadID); return 0; } } -SceUID __KernelGetWaitID(SceUID threadID, WaitType type, u32 &error) -{ - Thread *t = kernelObjects.Get(threadID, error); - if (t) - { +SceUID __KernelGetWaitID(SceUID threadID, WaitType type, u32 &error) { + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) { return t->getWaitID(type); - } - else - { + } else { ERROR_LOG(SCEKERNEL, "__KernelGetWaitID ERROR: thread %i", threadID); return -1; } } -SceUID __KernelGetCurrentCallbackID(SceUID threadID, u32 &error) -{ - Thread *t = kernelObjects.Get(threadID, error); - if (t) +SceUID __KernelGetCurrentCallbackID(SceUID threadID, u32 &error) { + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) { return t->currentCallbackId; - else - { + } else { ERROR_LOG(SCEKERNEL, "__KernelGetCurrentCallbackID ERROR: thread %i", threadID); return 0; } @@ -1255,7 +1231,7 @@ u32 sceKernelReferThreadStatus(u32 threadID, u32 statusPtr) threadID = __KernelGetCurThread(); u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { hleEatCycles(700); hleReSchedule("refer thread status"); @@ -1296,7 +1272,7 @@ u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr) threadID = __KernelGetCurThread(); u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (!t) { ERROR_LOG(SCEKERNEL,"sceKernelReferThreadRunStatus Error %08x", error); @@ -1327,7 +1303,7 @@ u32 sceKernelReferThreadRunStatus(u32 threadID, u32 statusPtr) int sceKernelGetThreadExitStatus(SceUID threadID) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->nt.status == THREADSTATUS_DORMANT) // TODO: can be dormant before starting, too, need to avoid that @@ -1365,19 +1341,19 @@ u32 sceKernelGetThreadmanIdType(u32 uid) { } } -static bool __ThreadmanIdListIsSleeping(const Thread *t) { +static bool __ThreadmanIdListIsSleeping(const PSPThread *t) { return t->isWaitingFor(WAITTYPE_SLEEP, 0); } -static bool __ThreadmanIdListIsDelayed(const Thread *t) { +static bool __ThreadmanIdListIsDelayed(const PSPThread *t) { return t->isWaitingFor(WAITTYPE_DELAY, t->GetUID()); } -static bool __ThreadmanIdListIsSuspended(const Thread *t) { +static bool __ThreadmanIdListIsSuspended(const PSPThread *t) { return t->isSuspended(); } -static bool __ThreadmanIdListIsDormant(const Thread *t) { +static bool __ThreadmanIdListIsDormant(const PSPThread *t) { return t->isStopped(); } @@ -1400,7 +1376,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i DEBUG_LOG(SCEKERNEL, "sceKernelGetThreadmanIdList(%i, %08x, %i, %08x)", type, readBufPtr, readBufSize, idCountPtr); total = kernelObjects.ListIDType(type, uids, readBufSize); } else if (type >= SCE_KERNEL_TMID_SleepThread && type <= SCE_KERNEL_TMID_DormantThread) { - bool (*checkFunc)(const Thread *t) = NULL; + bool (*checkFunc)(const PSPThread *t) = nullptr; switch (type) { case SCE_KERNEL_TMID_SleepThread: checkFunc = &__ThreadmanIdListIsSleeping; @@ -1423,7 +1399,7 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i } for (size_t i = 0; i < threadqueue.size(); i++) { - const Thread *t = kernelObjects.Get(threadqueue[i], error); + const PSPThread *t = kernelObjects.Get(threadqueue[i], error); if (checkFunc(t)) { if (total < readBufSize) { *uids++ = threadqueue[i]; @@ -1443,13 +1419,11 @@ u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 i } // Saves the current CPU context -void __KernelSaveContext(ThreadContext *ctx, bool vfpuEnabled) -{ +void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled) { // r and f are immediately next to each other and must be. memcpy((void *)ctx->r, (void *)currentMIPS->r, sizeof(ctx->r) + sizeof(ctx->f)); - if (vfpuEnabled) - { + if (vfpuEnabled) { memcpy(ctx->v, currentMIPS->v, sizeof(ctx->v)); memcpy(ctx->vfpuCtrl, currentMIPS->vfpuCtrl, sizeof(ctx->vfpuCtrl)); } @@ -1458,13 +1432,11 @@ void __KernelSaveContext(ThreadContext *ctx, bool vfpuEnabled) } // Loads a CPU context -void __KernelLoadContext(ThreadContext *ctx, bool vfpuEnabled) -{ +void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled) { // r and f are immediately next to each other and must be. memcpy((void *)currentMIPS->r, (void *)ctx->r, sizeof(ctx->r) + sizeof(ctx->f)); - if (vfpuEnabled) - { + if (vfpuEnabled) { memcpy(currentMIPS->v, ctx->v, sizeof(ctx->v)); memcpy(currentMIPS->vfpuCtrl, ctx->vfpuCtrl, sizeof(ctx->vfpuCtrl)); } @@ -1482,7 +1454,7 @@ void __KernelLoadContext(ThreadContext *ctx, bool vfpuEnabled) u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { t->resumeFromWait(); @@ -1499,7 +1471,7 @@ u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval) u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { t->resumeFromWait(); @@ -1522,7 +1494,7 @@ void __KernelWaitCurThread(WaitType type, SceUID waitID, u32 waitValue, u32 time return; } - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1545,7 +1517,7 @@ void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue, return; } - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); thread->nt.waitID = waitID; thread->nt.waitType = type; __KernelChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->nt.status & THREADSTATUS_SUSPEND))); @@ -1582,7 +1554,7 @@ void __KernelCancelWakeup(SceUID threadID) void hleThreadEndTimeout(u64 userdata, int cyclesLate) { SceUID threadID = (SceUID) userdata; - HLEKernel::WaitExecTimeout(threadID); + HLEKernel::WaitExecTimeout(threadID); } static void __KernelScheduleThreadEndTimeout(SceUID threadID, SceUID waitForID, s64 usFromNow) @@ -1609,7 +1581,7 @@ static void __KernelRemoveFromThreadQueue(SceUID threadID) { void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason) { u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { __KernelChangeReadyState(t, threadID, false); @@ -1653,12 +1625,12 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason) } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { for (auto it = t->callbacks.begin(), end = t->callbacks.end(); it != end; ++it) { - Callback *callback = kernelObjects.Get(*it, error); + PSPCallback *callback = kernelObjects.Get(*it, error); if (callback && callback->nc.notifyCount != 0) readyCallbacksCount--; } @@ -1674,7 +1646,7 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason) pendingDeleteThreads.push_back(threadID); return 0; } else { - return kernelObjects.Destroy(threadID); + return kernelObjects.Destroy(threadID); } } else { RETURN(error); @@ -1686,8 +1658,8 @@ static void __ReportThreadQueueEmpty() { // We failed to find a thread to schedule. // This means something horrible happened to the idle threads. u32 error; - Thread *idleThread0 = kernelObjects.Get(threadIdleID[0], error); - Thread *idleThread1 = kernelObjects.Get(threadIdleID[1], error); + PSPThread *idleThread0 = kernelObjects.Get(threadIdleID[0], error); + PSPThread *idleThread1 = kernelObjects.Get(threadIdleID[1], error); char idleDescription0[256]; int idleStatus0 = -1; @@ -1713,11 +1685,11 @@ static void __ReportThreadQueueEmpty() { } // Returns NULL if the current thread is fine. -static Thread *__KernelNextThread() { +static PSPThread *__KernelNextThread() { SceUID bestThread; // If the current thread is running, it's a valid candidate. - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); if (cur && cur->isRunning()) { bestThread = threadReadyQueue.pop_first_better(cur->nt.currentPriority); if (bestThread != 0) @@ -1736,7 +1708,7 @@ static Thread *__KernelNextThread() { // Assume threadReadyQueue has not become corrupt. if (bestThread != 0) - return kernelObjects.GetFast(bestThread); + return kernelObjects.GetFast(bestThread); else return 0; } @@ -1755,7 +1727,7 @@ void __KernelReSchedule(const char *reason) return; } - Thread *nextThread = __KernelNextThread(); + PSPThread *nextThread = __KernelNextThread(); if (nextThread) { __KernelSwitchContext(nextThread, reason); } @@ -1764,7 +1736,7 @@ void __KernelReSchedule(const char *reason) void __KernelReSchedule(bool doCallbacks, const char *reason) { - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (doCallbacks && thread != nullptr) { thread->isProcessingCallbacks = doCallbacks; } @@ -1781,7 +1753,7 @@ void __KernelReSchedule(bool doCallbacks, const char *reason) int sceKernelCheckThreadStack() { u32 error; - Thread *t = kernelObjects.Get(__KernelGetCurThread(), error); + PSPThread *t = kernelObjects.Get(__KernelGetCurThread(), error); if (t) { u32 diff = labs((long)((s64)currentMIPS->r[MIPS_REG_SP] - (s64)t->currentStack.start)); DEBUG_LOG(SCEKERNEL, "%i=sceKernelCheckThreadStack()", diff); @@ -1792,20 +1764,16 @@ int sceKernelCheckThreadStack() } } -void ThreadContext::reset() -{ - for (int i = 0; i<32; i++) - { +void PSPThreadContext::reset() { + for (int i = 0; i<32; i++) { r[i] = 0xDEADBEEF; fi[i] = 0x7f800001; } r[0] = 0; - for (int i = 0; i<128; i++) - { + for (int i = 0; i<128; i++) { vi[i] = 0x7f800001; } - for (int i = 0; i<15; i++) - { + for (int i = 0; i<15; i++) { vfpuCtrl[i] = 0x00000000; } vfpuCtrl[VFPU_CTRL_SPREFIX] = 0xe4; // neutral @@ -1830,8 +1798,7 @@ void ThreadContext::reset() other[5] = 0; } -void __KernelResetThread(Thread *t, int lowestPriority) -{ +void __KernelResetThread(PSPThread *t, int lowestPriority) { t->context.reset(); t->context.pc = t->nt.entrypoint; @@ -1859,10 +1826,10 @@ void __KernelResetThread(Thread *t, int lowestPriority) ERROR_LOG_REPORT(SCEKERNEL, "Resetting thread with threads waiting on end?"); } -Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr) { +PSPThread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr) { std::lock_guard guard(threadqueueLock); - Thread *t = new Thread; + PSPThread *t = new PSPThread(); id = kernelObjects.Create(t); threadqueue.push_back(id); @@ -1909,12 +1876,12 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int { //grab mips regs SceUID id; - Thread *thread = __KernelCreateThread(id, moduleID, "root", currentMIPS->pc, prio, stacksize, attr); + PSPThread *thread = __KernelCreateThread(id, moduleID, "root", currentMIPS->pc, prio, stacksize, attr); if (thread->currentStack.start == 0) ERROR_LOG_REPORT(SCEKERNEL, "Unable to allocate stack for root thread."); __KernelResetThread(thread, 0); - Thread *prevThread = __GetCurrentThread(); + PSPThread *prevThread = __GetCurrentThread(); if (prevThread && prevThread->isRunning()) __KernelChangeReadyState(currentThread, true); __SetCurrentThread(thread, id, "root"); @@ -1938,7 +1905,7 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr) { SceUID id; - Thread *newThread = __KernelCreateThread(id, moduleID, threadName, entry, prio, stacksize, attr); + PSPThread *newThread = __KernelCreateThread(id, moduleID, threadName, entry, prio, stacksize, attr); if (newThread->currentStack.start == 0) return SCE_KERNEL_ERROR_NO_MEMORY; @@ -1998,18 +1965,18 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 } int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); bool allowKernel = cur ? (cur->nt.attr & PSP_THREAD_ATTR_KERNEL) != 0 : false; return __KernelCreateThread(threadName, __KernelGetCurThreadModuleId(), entry, prio, stacksize, attr, optionAddr, allowKernel); } int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs) { u32 error; - Thread *startThread = kernelObjects.Get(threadToStartID, error); + PSPThread *startThread = kernelObjects.Get(threadToStartID, error); if (startThread == 0) return error; - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); __KernelResetThread(startThread, cur ? cur->nt.currentPriority : 0); u32 &sp = startThread->context.r[MIPS_REG_SP]; @@ -2072,7 +2039,7 @@ int __KernelStartThreadValidate(SceUID threadToStartID, int argSize, u32 argBloc return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "bad thread argument pointer/length %08x / %08x", argSize, argBlockPtr); u32 error = 0; - Thread *startThread = kernelObjects.Get(threadToStartID, error); + PSPThread *startThread = kernelObjects.Get(threadToStartID, error); if (startThread == 0) return hleLogError(SCEKERNEL, error, "thread does not exist"); @@ -2096,9 +2063,8 @@ int sceKernelGetThreadStackFreeSize(SceUID threadID) threadID = __KernelGetCurThread(); u32 error; - Thread *thread = kernelObjects.Get(threadID, error); - if (thread == 0) - { + PSPThread *thread = kernelObjects.Get(threadID, error); + if (thread == nullptr) { ERROR_LOG(SCEKERNEL, "sceKernelGetThreadStackFreeSize: invalid thread id %i", threadID); return error; } @@ -2121,7 +2087,7 @@ void __KernelReturnFromThread() hleSkipDeadbeef(); int exitStatus = currentMIPS->r[MIPS_REG_V0]; - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(SCEKERNEL, thread != NULL, "Returned from a NULL thread."); DEBUG_LOG(SCEKERNEL, "__KernelReturnFromThread: %d", exitStatus); @@ -2135,9 +2101,8 @@ void __KernelReturnFromThread() // The stack will be deallocated when the thread is deleted. } -void sceKernelExitThread(int exitStatus) -{ - Thread *thread = __GetCurrentThread(); +void sceKernelExitThread(int exitStatus) { + PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(SCEKERNEL, thread != NULL, "Exited from a NULL thread."); INFO_LOG(SCEKERNEL, "sceKernelExitThread(%d)", exitStatus); @@ -2151,9 +2116,8 @@ void sceKernelExitThread(int exitStatus) // The stack will be deallocated when the thread is deleted. } -void _sceKernelExitThread(int exitStatus) -{ - Thread *thread = __GetCurrentThread(); +void _sceKernelExitThread(int exitStatus) { + PSPThread *thread = __GetCurrentThread(); _dbg_assert_msg_(SCEKERNEL, thread != NULL, "_Exited from a NULL thread."); ERROR_LOG_REPORT(SCEKERNEL, "_sceKernelExitThread(%d): should not be called directly", exitStatus); @@ -2167,9 +2131,8 @@ void _sceKernelExitThread(int exitStatus) // The stack will be deallocated when the thread is deleted. } -void sceKernelExitDeleteThread(int exitStatus) -{ - Thread *thread = __GetCurrentThread(); +void sceKernelExitDeleteThread(int exitStatus) { + PSPThread *thread = __GetCurrentThread(); if (thread) { INFO_LOG(SCEKERNEL,"sceKernelExitDeleteThread(%d)", exitStatus); @@ -2229,7 +2192,7 @@ int sceKernelRotateThreadReadyQueue(int priority) { VERBOSE_LOG(SCEKERNEL, "sceKernelRotateThreadReadyQueue(%x)", priority); - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); // 0 is special, it means "my current priority." if (priority == 0) @@ -2256,29 +2219,23 @@ int sceKernelRotateThreadReadyQueue(int priority) return 0; } -int sceKernelDeleteThread(int threadID) -{ - if (threadID == 0 || threadID == currentThread) - { +int sceKernelDeleteThread(int threadID) { + if (threadID == 0 || threadID == currentThread) { ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): cannot delete current thread", threadID); return SCE_KERNEL_ERROR_NOT_DORMANT; } u32 error; - Thread *t = kernelObjects.Get(threadID, error); - if (t) - { - if (!t->isStopped()) - { + PSPThread *t = kernelObjects.Get(threadID, error); + if (t) { + if (!t->isStopped()) { ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): thread not dormant", threadID); return SCE_KERNEL_ERROR_NOT_DORMANT; } DEBUG_LOG(SCEKERNEL, "sceKernelDeleteThread(%i)", threadID); return __KernelDeleteThread(threadID, SCE_KERNEL_ERROR_THREAD_TERMINATED, "thread deleted"); - } - else - { + } else { ERROR_LOG(SCEKERNEL, "sceKernelDeleteThread(%i): thread doesn't exist", threadID); return error; } @@ -2293,7 +2250,7 @@ int sceKernelTerminateDeleteThread(int threadID) } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { bool wasStopped = t->isStopped(); @@ -2327,7 +2284,7 @@ int sceKernelTerminateThread(SceUID threadID) { } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->isStopped()) { return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_DORMANT, "already stopped"); @@ -2355,31 +2312,28 @@ SceUID __KernelGetCurThread() } int KernelCurThreadPriority() { - Thread *t = __GetCurrentThread(); + PSPThread *t = __GetCurrentThread(); if (t) return t->nt.currentPriority; return 0; } -SceUID __KernelGetCurThreadModuleId() -{ - Thread *t = __GetCurrentThread(); +SceUID __KernelGetCurThreadModuleId() { + PSPThread *t = __GetCurrentThread(); if (t) return t->moduleId; return 0; } -u32 __KernelGetCurThreadStack() -{ - Thread *t = __GetCurrentThread(); +u32 __KernelGetCurThreadStack() { + PSPThread *t = __GetCurrentThread(); if (t) return t->currentStack.end; return 0; } -u32 __KernelGetCurThreadStackStart() -{ - Thread *t = __GetCurrentThread(); +u32 __KernelGetCurThreadStackStart() { + PSPThread *t = __GetCurrentThread(); if (t) return t->currentStack.start; return 0; @@ -2403,7 +2357,7 @@ int sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) { return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "invalid attr"); } - Thread *t = __GetCurrentThread(); + PSPThread *t = __GetCurrentThread(); if (!t) return hleReportError(SCEKERNEL, -1, "no current thread"); @@ -2414,7 +2368,7 @@ int sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) { // Assumes validated parameters. bool KernelChangeThreadPriority(SceUID threadID, int priority) { u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (thread) { int old = thread->nt.currentPriority; threadReadyQueue.remove(old, threadID); @@ -2440,7 +2394,7 @@ int sceKernelChangeThreadPriority(SceUID threadID, int priority) { // 0 means the current (running) thread's priority, not target's. if (priority == 0) { - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); if (!cur) { ERROR_LOG_REPORT(SCEKERNEL, "sceKernelChangeThreadPriority(%i, %i): no current thread?", threadID, priority); } else { @@ -2449,7 +2403,7 @@ int sceKernelChangeThreadPriority(SceUID threadID, int priority) { } u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (thread) { if (thread->isStopped()) { return hleLogError(SCEKERNEL, SCE_KERNEL_ERROR_DORMANT, "thread is dormant"); @@ -2545,10 +2499,9 @@ int sceKernelDelaySysClockThread(u32 sysclockAddr) { return hleLogSuccessI(SCEKERNEL, 0, "delaying %lld usecs", delayUs); } -u32 __KernelGetThreadPrio(SceUID id) -{ +u32 __KernelGetThreadPrio(SceUID id) { u32 error; - Thread *thread = kernelObjects.Get(id, error); + PSPThread *thread = kernelObjects.Get(id, error); if (thread) return thread->nt.currentPriority; return 0; @@ -2568,7 +2521,7 @@ int sceKernelWakeupThread(SceUID uid) { } u32 error; - Thread *t = kernelObjects.Get(uid, error); + PSPThread *t = kernelObjects.Get(uid, error); if (t) { if (!t->isWaitingFor(WAITTYPE_SLEEP, 0)) { t->nt.wakeupCount++; @@ -2589,7 +2542,7 @@ int sceKernelCancelWakeupThread(SceUID uid) { } u32 error; - Thread *t = kernelObjects.Get(uid, error); + PSPThread *t = kernelObjects.Get(uid, error); if (t) { int wCount = t->nt.wakeupCount; t->nt.wakeupCount = 0; @@ -2600,7 +2553,7 @@ int sceKernelCancelWakeupThread(SceUID uid) { } static int __KernelSleepThread(bool doCallbacks) { - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (!thread) { ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSleepThread*(): bad current thread"); return -1; @@ -2637,7 +2590,7 @@ int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr) return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->nt.status != THREADSTATUS_DORMANT) @@ -2670,7 +2623,7 @@ int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr) return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT; u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->nt.status != THREADSTATUS_DORMANT) @@ -2703,7 +2656,7 @@ int sceKernelReleaseWaitThread(SceUID threadID) return SCE_KERNEL_ERROR_ILLEGAL_THID; u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (!t->isWaiting()) @@ -2740,7 +2693,7 @@ int sceKernelSuspendThread(SceUID threadID) } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (t->isStopped()) @@ -2777,7 +2730,7 @@ int sceKernelResumeThread(SceUID threadID) } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { if (!t->isSuspended()) @@ -2813,7 +2766,7 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) if (entrypoint & 0xF0000000) return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid func"); - Callback *cb = new Callback; + PSPCallback *cb = new PSPCallback(); SceUID id = kernelObjects.Create(cb); strncpy(cb->nc.name, name, KERNELOBJECT_MAX_NAME_LENGTH); @@ -2825,7 +2778,7 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) cb->nc.notifyCount = 0; cb->nc.notifyArg = 0; - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (thread) thread->callbacks.push_back(id); @@ -2835,16 +2788,16 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg) int sceKernelDeleteCallback(SceUID cbId) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { - Thread *thread = kernelObjects.Get(cb->nc.threadId, error); + PSPThread *thread = kernelObjects.Get(cb->nc.threadId, error); if (thread) thread->callbacks.erase(std::remove(thread->callbacks.begin(), thread->callbacks.end(), cbId), thread->callbacks.end()); if (cb->nc.notifyCount != 0) readyCallbacksCount--; - return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy(cbId)); + return hleLogSuccessI(SCEKERNEL, kernelObjects.Destroy(cbId)); } else { return hleLogError(SCEKERNEL, error, "bad cbId"); } @@ -2854,7 +2807,7 @@ int sceKernelDeleteCallback(SceUID cbId) int sceKernelNotifyCallback(SceUID cbId, int notifyArg) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { __KernelNotifyCallback(cbId, notifyArg); return hleLogSuccessI(SCEKERNEL, 0); @@ -2866,7 +2819,7 @@ int sceKernelNotifyCallback(SceUID cbId, int notifyArg) int sceKernelCancelCallback(SceUID cbId) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { // This just resets the notify count. cb->nc.notifyArg = 0; @@ -2879,7 +2832,7 @@ int sceKernelCancelCallback(SceUID cbId) int sceKernelGetCallbackCount(SceUID cbId) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (cb) { return hleLogSuccessVerboseI(SCEKERNEL, cb->nc.notifyCount); } else { @@ -2890,7 +2843,7 @@ int sceKernelGetCallbackCount(SceUID cbId) int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr) { u32 error; - Callback *c = kernelObjects.Get(cbId, error); + PSPCallback *c = kernelObjects.Get(cbId, error); if (c) { if (Memory::IsValidAddress(statusAddr) && Memory::Read_U32(statusAddr) != 0) { Memory::WriteStruct(statusAddr, &c->nc); @@ -2908,7 +2861,7 @@ u32 sceKernelExtendThreadStack(u32 size, u32 entryAddr, u32 entryParameter) if (size < 512) return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_STACK_SIZE, "xxx", "stack size too small"); - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (!thread) return hleReportError(SCEKERNEL, -1, "xxx", "not on a thread?"); @@ -2936,7 +2889,7 @@ void __KernelReturnFromExtendStack() { hleSkipDeadbeef(); - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (!thread) { ERROR_LOG_REPORT(SCEKERNEL, "__KernelReturnFromExtendStack() - not on a thread?"); @@ -2964,7 +2917,7 @@ void __KernelReturnFromExtendStack() void ActionAfterMipsCall::run(MipsCall &call) { u32 error; - Thread *thread = kernelObjects.Get(threadID, error); + PSPThread *thread = kernelObjects.Get(threadID, error); if (thread) { // Resume waiting after a callback, but not from terminate/delete. if ((thread->nt.status & (THREADSTATUS_DEAD | THREADSTATUS_DORMANT)) == 0) { @@ -2984,8 +2937,7 @@ void ActionAfterMipsCall::run(MipsCall &call) { } } -void Thread::setReturnValue(u32 retval) -{ +void PSPThread::setReturnValue(u32 retval) { if (GetUID() == currentThread) { currentMIPS->r[MIPS_REG_V0] = retval; } else { @@ -2993,8 +2945,7 @@ void Thread::setReturnValue(u32 retval) } } -void Thread::setReturnValue(u64 retval) -{ +void PSPThread::setReturnValue(u64 retval) { if (GetUID() == currentThread) { currentMIPS->r[MIPS_REG_V0] = retval & 0xFFFFFFFF; currentMIPS->r[MIPS_REG_V1] = (retval >> 32) & 0xFFFFFFFF; @@ -3004,8 +2955,7 @@ void Thread::setReturnValue(u64 retval) } } -void Thread::resumeFromWait() -{ +void PSPThread::resumeFromWait() { nt.status &= ~THREADSTATUS_WAIT; if (!(nt.status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) __KernelChangeReadyState(this, GetUID(), true); @@ -3014,32 +2964,28 @@ void Thread::resumeFromWait() isProcessingCallbacks = false; } -bool Thread::isWaitingFor(WaitType type, int id) const -{ +bool PSPThread::isWaitingFor(WaitType type, int id) const { if (nt.status & THREADSTATUS_WAIT) return nt.waitType == type && nt.waitID == id; return false; } -int Thread::getWaitID(WaitType type) const -{ +int PSPThread::getWaitID(WaitType type) const { if (nt.waitType == type) return nt.waitID; return 0; } -ThreadWaitInfo Thread::getWaitInfo() const -{ +ThreadWaitInfo PSPThread::getWaitInfo() const { return waitInfo; } -void __KernelSwitchContext(Thread *target, const char *reason) -{ +void __KernelSwitchContext(PSPThread *target, const char *reason) { u32 oldPC = 0; SceUID oldUID = 0; const char *oldName = hleCurrentThreadName != NULL ? hleCurrentThreadName : "(none)"; - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); if (cur) // It might just have been deleted. { __KernelSaveContext(&cur->context, (cur->nt.attr & PSP_THREAD_ATTR_VFPU) != 0); @@ -3099,7 +3045,7 @@ void __KernelSwitchContext(Thread *target, const char *reason) } } -void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) { +void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus) { if (!thread || thread->nt.status == newStatus) return; @@ -3124,12 +3070,12 @@ void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus) { } -static bool __CanExecuteCallbackNow(Thread *thread) { + +static bool __CanExecuteCallbackNow(PSPThread *thread) { return currentCallbackThreadID == 0 && g_inCbCount == 0; } -void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId) -{ +void __KernelCallAddress(PSPThread *thread, u32 entryPoint, PSPAction *afterAction, const u32 args[], int numargs, bool reschedAfter, SceUID cbId) { if (!thread || thread->isStopped()) { WARN_LOG_REPORT(SCEKERNEL, "Running mipscall on dormant thread"); } @@ -3197,8 +3143,7 @@ void __KernelCallAddress(Thread *thread, u32 entryPoint, Action *afterAction, co } } -void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, u32 args[], int numargs, bool reschedAfter) -{ +void __KernelDirectMipsCall(u32 entryPoint, PSPAction *afterAction, u32 args[], int numargs, bool reschedAfter) { __KernelCallAddress(__GetCurrentThread(), entryPoint, afterAction, args, numargs, reschedAfter, 0); } @@ -3206,7 +3151,7 @@ bool __KernelExecuteMipsCallOnCurrentThread(u32 callId, bool reschedAfter) { hleSkipDeadbeef(); - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); if (cur == nullptr) { ERROR_LOG(SCEKERNEL, "__KernelExecuteMipsCallOnCurrentThread(): Bad current thread"); return false; @@ -3260,7 +3205,7 @@ void __KernelReturnFromMipsCall() { hleSkipDeadbeef(); - Thread *cur = __GetCurrentThread(); + PSPThread *cur = __GetCurrentThread(); if (cur == NULL) { ERROR_LOG(SCEKERNEL, "__KernelReturnFromMipsCall(): Bad current thread"); @@ -3322,7 +3267,7 @@ void __KernelReturnFromMipsCall() // Now seems like a good time to clear out any pending deletes. for (SceUID delThread : pendingDeleteThreads) { - kernelObjects.Destroy(delThread); + kernelObjects.Destroy(delThread); } pendingDeleteThreads.clear(); } @@ -3331,8 +3276,7 @@ void __KernelReturnFromMipsCall() } // First arg must be current thread, passed to avoid perf cost of a lookup. -bool __KernelExecutePendingMipsCalls(Thread *thread, bool reschedAfter) -{ +bool __KernelExecutePendingMipsCalls(PSPThread *thread, bool reschedAfter) { _dbg_assert_msg_(SCEKERNEL, thread->GetUID() == __KernelGetCurThread(), "__KernelExecutePendingMipsCalls() should be called only with the current thread."); if (thread->pendingMipsCalls.empty()) { @@ -3353,10 +3297,9 @@ bool __KernelExecutePendingMipsCalls(Thread *thread, bool reschedAfter) } // Executes the callback, when it next is context switched to. -static void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool reschedAfter) -{ +static void __KernelRunCallbackOnThread(SceUID cbId, PSPThread *thread, bool reschedAfter) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { ERROR_LOG(SCEKERNEL, "__KernelRunCallbackOnThread: Bad cbId %i", cbId); return; @@ -3385,22 +3328,19 @@ static void __KernelRunCallbackOnThread(SceUID cbId, Thread *thread, bool resche void ActionAfterCallback::run(MipsCall &call) { if (cbId != -1) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); - if (cb) - { - Thread *t = kernelObjects.Get(cb->nc.threadId, error); - if (t) - { + PSPCallback *cb = kernelObjects.Get(cbId, error); + if (cb) { + PSPThread *t = kernelObjects.Get(cb->nc.threadId, error); + if (t) { // Check for other callbacks to run (including ones this callback scheduled.) __KernelCheckThreadCallbacks(t, true); } DEBUG_LOG(SCEKERNEL, "Left callback %i - %s", cbId, cb->nc.name); // Callbacks that don't return 0 are deleted. But should this be done here? - if (currentMIPS->r[MIPS_REG_V0] != 0) - { + if (currentMIPS->r[MIPS_REG_V0] != 0) { DEBUG_LOG(SCEKERNEL, "ActionAfterCallback::run(): Callback returned non-zero, gets deleted!"); - kernelObjects.Destroy(cbId); + kernelObjects.Destroy(cbId); } } } @@ -3411,10 +3351,10 @@ bool __KernelCurHasReadyCallbacks() { return false; } - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); u32 error; for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) { - Callback *callback = kernelObjects.Get(*it, error); + PSPCallback *callback = kernelObjects.Get(*it, error); if (callback && callback->nc.notifyCount != 0) { return true; } @@ -3424,7 +3364,7 @@ bool __KernelCurHasReadyCallbacks() { // Check callbacks on the current thread only. // Returns true if any callbacks were processed on the current thread. -bool __KernelCheckThreadCallbacks(Thread *thread, bool force) { +bool __KernelCheckThreadCallbacks(PSPThread *thread, bool force) { if (!thread || (!thread->isProcessingCallbacks && !force)) { return false; } @@ -3432,7 +3372,7 @@ bool __KernelCheckThreadCallbacks(Thread *thread, bool force) { if (!thread->callbacks.empty()) { u32 error; for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) { - Callback *callback = kernelObjects.Get(*it, error); + PSPCallback *callback = kernelObjects.Get(*it, error); if (callback && callback->nc.notifyCount != 0) { __KernelRunCallbackOnThread(callback->GetUID(), thread, !force); readyCallbacksCount--; @@ -3463,7 +3403,7 @@ bool __KernelCheckCallbacks() { u32 error; for (auto iter = threadqueue.begin(); iter != threadqueue.end(); ++iter) { - Thread *thread = kernelObjects.Get(*iter, error); + PSPThread *thread = kernelObjects.Get(*iter, error); if (thread && __KernelCheckThreadCallbacks(thread, false)) { processed = true; } @@ -3485,7 +3425,7 @@ bool __KernelForceCallbacks() ERROR_LOG_REPORT(SCEKERNEL, "readyCallbacksCount became negative: %i", readyCallbacksCount); } - Thread *curThread = __GetCurrentThread(); + PSPThread *curThread = __GetCurrentThread(); bool callbacksProcessed = __KernelCheckThreadCallbacks(curThread, true); if (callbacksProcessed) @@ -3520,7 +3460,7 @@ void __KernelNotifyCallback(SceUID cbId, int notifyArg) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { // Yeah, we're screwed, this shouldn't happen. ERROR_LOG(SCEKERNEL, "__KernelNotifyCallback - invalid callback %08x", cbId); @@ -3545,7 +3485,7 @@ std::vector GetThreadsInfo() { u32 error; for (const auto uid : threadqueue) { - Thread *t = kernelObjects.Get(uid, error); + PSPThread *t = kernelObjects.Get(uid, error); if (!t) continue; @@ -3576,7 +3516,7 @@ DebugInterface *KernelDebugThread(SceUID threadID) { } u32 error; - Thread *t = kernelObjects.Get(threadID, error); + PSPThread *t = kernelObjects.Get(threadID, error); if (t) { return &t->debug; } @@ -3584,10 +3524,9 @@ DebugInterface *KernelDebugThread(SceUID threadID) { return nullptr; } -void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) -{ +void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) { u32 error; - Thread *t = kernelObjects.Get(threadId, error); + PSPThread *t = kernelObjects.Get(threadId, error); if (!t) return; @@ -3597,7 +3536,7 @@ void __KernelChangeThreadState(SceUID threadId, ThreadStatus newStatus) int sceKernelRegisterExitCallback(SceUID cbId) { u32 error; - Callback *cb = kernelObjects.Get(cbId, error); + PSPCallback *cb = kernelObjects.Get(cbId, error); if (!cb) { WARN_LOG(SCEKERNEL, "sceKernelRegisterExitCallback(%i): invalid callback id", cbId); @@ -3615,7 +3554,7 @@ int LoadExecForUser_362A956B() { WARN_LOG_REPORT(SCEKERNEL, "LoadExecForUser_362A956B()"); u32 error; - Callback *cb = kernelObjects.Get(registeredExitCbId, error); + PSPCallback *cb = kernelObjects.Get(registeredExitCbId, error); if (!cb) { WARN_LOG(SCEKERNEL, "LoadExecForUser_362A956B() : registeredExitCbId not found 0x%x", registeredExitCbId); return SCE_KERNEL_ERROR_UNKNOWN_CBID; @@ -3681,10 +3620,10 @@ KernelObject *__KernelThreadEventHandlerObject() { } bool __KernelThreadTriggerEvent(const ThreadEventHandlerList &handlers, SceUID threadID, ThreadEventType type) { - Thread *thread = __GetCurrentThread(); + PSPThread *thread = __GetCurrentThread(); if (!thread || thread->isStopped()) { SceUID nextThreadID = threadReadyQueue.peek_first(); - thread = kernelObjects.GetFast(nextThreadID); + thread = kernelObjects.GetFast(nextThreadID); } bool hadHandlers = false; @@ -3737,7 +3676,7 @@ SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u3 } } u32 error; - if (kernelObjects.Get(threadID, error) == NULL && threadID != SCE_TE_THREADID_ALL_USER) { + if (kernelObjects.Get(threadID, error) == NULL && threadID != SCE_TE_THREADID_ALL_USER) { return hleReportError(SCEKERNEL, error, "bad thread id"); } if ((mask & ~THREADEVENT_SUPPORTED) != 0) { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 8b95396b97..6ceb402074 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -26,7 +26,7 @@ // There's a good description of the thread scheduling rules in: // http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java -class Thread; +class PSPThread; class DebugInterface; int sceKernelChangeThreadPriority(SceUID threadID, int priority); @@ -119,8 +119,7 @@ typedef void (* WaitEndCallbackFunc)(SceUID threadID, SceUID prevCallbackId); void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc); -struct ThreadContext -{ +struct PSPThreadContext { void reset(); // r must be followed by f. @@ -168,8 +167,8 @@ u32 __KernelGetCurThreadStackStart(); const char *__KernelGetThreadName(SceUID threadID); bool KernelIsThreadDormant(SceUID threadID); -void __KernelSaveContext(ThreadContext *ctx, bool vfpuEnabled); -void __KernelLoadContext(ThreadContext *ctx, bool vfpuEnabled); +void __KernelSaveContext(PSPThreadContext *ctx, bool vfpuEnabled); +void __KernelLoadContext(PSPThreadContext *ctx, bool vfpuEnabled); u32 __KernelResumeThreadFromWait(SceUID threadID, u32 retval); // can return an error value u32 __KernelResumeThreadFromWait(SceUID threadID, u64 retval); @@ -216,10 +215,10 @@ int sceKernelGetCallbackCount(SceUID cbId); void sceKernelCheckCallback(); int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr); -class Action; +class PSPAction; // Not an official Callback object, just calls a mips function on the current thread. -void __KernelDirectMipsCall(u32 entryPoint, Action *afterAction, u32 args[], int numargs, bool reschedAfter); +void __KernelDirectMipsCall(u32 entryPoint, PSPAction *afterAction, u32 args[], int numargs, bool reschedAfter); void __KernelReturnFromMipsCall(); // Called as HLE function bool __KernelInCallback(); @@ -228,8 +227,8 @@ bool __KernelInCallback(); bool __KernelCheckCallbacks(); bool __KernelForceCallbacks(); bool __KernelCurHasReadyCallbacks(); -void __KernelSwitchContext(Thread *target, const char *reason); -bool __KernelExecutePendingMipsCalls(Thread *currentThread, bool reschedAfter); +void __KernelSwitchContext(PSPThread *target, const char *reason); +bool __KernelExecutePendingMipsCalls(PSPThread *currentThread, bool reschedAfter); void __KernelNotifyCallback(SceUID cbId, int notifyArg); // Switch to an idle / non-user thread, if not already on one. @@ -243,8 +242,8 @@ u32 __KernelSetThreadRA(SceUID threadID, u32 nid); // A call into game code. These can be pending on a thread. // Similar to Callback-s (NOT CallbackInfos) in JPCSP. -typedef Action *(*ActionCreator)(); -Action *__KernelCreateAction(int actionType); +typedef PSPAction *(*ActionCreator)(); +PSPAction *__KernelCreateAction(int actionType); int __KernelRegisterActionType(ActionCreator creator); void __KernelRestoreActionType(int actionType, ActionCreator creator); @@ -258,7 +257,7 @@ struct MipsCall { u32 cbId; u32 args[6]; int numArgs; - Action *doAfter; + PSPAction *doAfter; u32 savedPc; u32 savedV0; u32 savedV1; @@ -279,10 +278,10 @@ struct MipsCall { } }; -class Action +class PSPAction { public: - virtual ~Action() {} + virtual ~PSPAction() {} virtual void run(MipsCall &call) = 0; virtual void DoState(PointerWrap &p) = 0; int actionTypeID; @@ -300,7 +299,7 @@ enum ThreadStatus THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND }; -void __KernelChangeThreadState(Thread *thread, ThreadStatus newStatus); +void __KernelChangeThreadState(PSPThread *thread, ThreadStatus newStatus); typedef void (*ThreadCallback)(SceUID threadID); void __KernelListenThreadEnd(ThreadCallback callback); diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index c84d6abc3c..686bee8423 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -355,11 +355,11 @@ static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) { INFO_LOG(ME, "First timestamp: %lld, Last timestamp: %lld", ctx->mpegFirstTimestamp, ctx->mpegLastTimestamp); } -class PostPutAction : public Action { +class PostPutAction : public PSPAction { public: PostPutAction() {} void setRingAddr(u32 ringAddr) { ringAddr_ = ringAddr; } - static Action *Create() { return new PostPutAction; } + static PSPAction *Create() { return new PostPutAction; } void DoState(PointerWrap &p) override { auto s = p.Section("PostPutAction", 1); if (!s) diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index d2f4d0c131..3bf1a70cbc 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -21,6 +21,7 @@ #include "Common/ChunkFile.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/sceKernelMemory.h" #include "Core/MIPS/MIPS.h" #include "Core/Config.h" #include "Core/MemMapHelpers.h" @@ -40,6 +41,9 @@ static bool netInetInited; static bool netApctlInited; u32 netDropRate = 0; u32 netDropDuration = 0; +u32 netPoolAddr = 0; +u32 netThread1Addr = 0; +u32 netThread2Addr = 0; static struct SceNetMallocStat netMallocStat; @@ -78,7 +82,7 @@ static void __UpdateApctlHandlers(int oldState, int newState, int flag, int erro // This feels like a dubious proposition, mostly... void __NetDoState(PointerWrap &p) { - auto s = p.Section("sceNet", 1, 2); + auto s = p.Section("sceNet", 1, 3); if (!s) return; @@ -94,6 +98,28 @@ void __NetDoState(PointerWrap &p) { p.Do(netDropRate); p.Do(netDropDuration); } + if (s < 3) { + netPoolAddr = 0; + netThread1Addr = 0; + netThread2Addr = 0; + } else { + p.Do(netPoolAddr); + p.Do(netThread1Addr); + p.Do(netThread2Addr); + } +} + +static inline u32 AllocUser(u32 size, bool fromTop, const char *name) { + u32 addr = userMemory.Alloc(size, true, "netstack1"); + if (addr == -1) + return 0; + return addr; +} + +static inline void FreeUser(u32 &addr) { + if (addr != 0) + userMemory.Free(addr); + addr = 0; } static u32 sceNetTerm() { @@ -103,35 +129,73 @@ static u32 sceNetTerm() { WARN_LOG(SCENET, "sceNetTerm()"); netInited = false; + FreeUser(netPoolAddr); + FreeUser(netThread1Addr); + FreeUser(netThread2Addr); return 0; } // TODO: should that struct actually be initialized here? -static u32 sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netinitPri, u32 netinitStack) { - // May need to Terminate old one first since the game (ie. GTA:VCS) might not called sceNetTerm before the next sceNetInit and behave strangely - if (netInited) +static int sceNetInit(u32 poolSize, u32 calloutPri, u32 calloutStack, u32 netinitPri, u32 netinitStack) { + // TODO: The correct behavior is actually to allocate more and leak the other threads/pool. + // But we reset here for historic reasons (GTA:VCS potentially triggers this.) + if (netInited) sceNetTerm(); + if (poolSize == 0) { + return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_MEMSIZE, "invalid pool size"); + } else if (calloutPri < 0x08 || calloutPri > 0x77) { + return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid callout thread priority"); + } else if (netinitPri < 0x08 || netinitPri > 0x77) { + return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_PRIORITY, "invalid init thread priority"); + } + + // TODO: Should also start the threads, probably? For now, let's just allocate. + // TODO: Respect the stack size if firmware set to 1.50? + u32 stackSize = 4096; + netThread1Addr = AllocUser(stackSize, true, "netstack1"); + if (netThread1Addr == 0) { + return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); + } + netThread2Addr = AllocUser(stackSize, true, "netstack2"); + if (netThread2Addr == 0) { + FreeUser(netThread1Addr); + return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate thread"); + } + + netPoolAddr = AllocUser(poolSize, false, "netpool"); + if (netPoolAddr == 0) { + FreeUser(netThread1Addr); + FreeUser(netThread2Addr); + return hleLogError(SCENET, SCE_KERNEL_ERROR_NO_MEMORY, "unable to allocate pool"); + } + WARN_LOG(SCENET, "sceNetInit(poolsize=%d, calloutpri=%i, calloutstack=%d, netintrpri=%i, netintrstack=%d) at %08x", poolSize, calloutPri, calloutStack, netinitPri, netinitStack, currentMIPS->pc); netInited = true; netMallocStat.maximum = poolSize; netMallocStat.free = poolSize; netMallocStat.pool = 0; - return 0; + return hleLogSuccessI(SCENET, 0); } static u32 sceWlanGetEtherAddr(u32 addrAddr) { - // Read MAC Address from config - uint8_t mac[6] = {0}; - if (!ParseMacAddress(g_Config.sMACAddress.c_str(), mac)) { - ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); + if (!Memory::IsValidRange(addrAddr, 6)) { + // More correctly, it should crash. + return hleLogError(SCENET, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address"); } - DEBUG_LOG(SCENET, "sceWlanGetEtherAddr(%08x)", addrAddr); - for (int i = 0; i < 6; i++) - Memory::Write_U8(mac[i], addrAddr + i); - return 0; + + u8 *addr = Memory::GetPointer(addrAddr); + // Read MAC Address from config + if (!ParseMacAddress(g_Config.sMACAddress.c_str(), addr)) { + ERROR_LOG(SCENET, "Error parsing mac address %s", g_Config.sMACAddress.c_str()); + Memory::Memset(addrAddr, 0, 6); + } else { + CBreakPoints::ExecMemCheck(addrAddr, true, 6, currentMIPS->pc); + } + + return hleLogSuccessI(SCENET, hleDelayResult(0, "get ether mac", 200)); } static u32 sceNetGetLocalEtherAddr(u32 addrAddr) { @@ -139,13 +203,11 @@ static u32 sceNetGetLocalEtherAddr(u32 addrAddr) { } static u32 sceWlanDevIsPowerOn() { - DEBUG_LOG(SCENET, "UNTESTED sceWlanDevIsPowerOn()"); - return g_Config.bEnableWlan ? 1 : 0; + return hleLogSuccessVerboseI(SCENET, g_Config.bEnableWlan ? 1 : 0); } static u32 sceWlanGetSwitchState() { - VERBOSE_LOG(SCENET, "sceWlanGetSwitchState()"); - return g_Config.bEnableWlan ? 1 : 0; + return hleLogSuccessVerboseI(SCENET, g_Config.bEnableWlan ? 1 : 0); } // Probably a void function, but often returns a useful value. @@ -468,7 +530,7 @@ static int sceNetSetDropRate(u32 dropRate, u32 dropDuration) } const HLEFunction sceNet[] = { - {0X39AF39A6, &WrapU_UUUUU, "sceNetInit", 'x', "xxxxx"}, + {0X39AF39A6, &WrapI_UUUUU, "sceNetInit", 'i', "xxxxx"}, {0X281928A9, &WrapU_V, "sceNetTerm", 'x', "" }, {0X89360950, &WrapI_UU, "sceNetEtherNtostr", 'i', "xx" }, {0XD27961C9, &WrapI_UU, "sceNetEtherStrton", 'i', "xx" }, diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 6e66350b50..6786b123dc 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -160,8 +160,6 @@ void __NetAdhocInit() { } u32 sceNetAdhocInit() { - // Library uninitialized - INFO_LOG(SCENET, "sceNetAdhocInit() at %08x", currentMIPS->pc); if (!netAdhocInited) { // Clear Translator Memory memset(&pdp, 0, sizeof(pdp)); @@ -173,17 +171,17 @@ u32 sceNetAdhocInit() { // Create fake PSP Thread for callback // TODO: Should use a separated threads for friendFinder, matchingEvent, and matchingInput and created on AdhocctlInit & AdhocMatchingStart instead of here #define PSP_THREAD_ATTR_KERNEL 0x00001000 // PSP_THREAD_ATTR_KERNEL is located in sceKernelThread.cpp instead of sceKernelThread.h :( - //threadAdhocID = __KernelCreateThreadInternal("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x30, 4096, PSP_THREAD_ATTR_KERNEL); - threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, 0, 0, false); + // TODO: This should probably be a user thread, but maybe from sceNetAdhocctlInit? + threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, PSP_THREAD_ATTR_KERNEL, 0, true); if (threadAdhocID > 0) { __KernelStartThread(threadAdhocID, 0, 0); } // Return Success - return 0; + return hleLogSuccessInfoI(SCENET, 0, "at %08x", currentMIPS->pc); } // Already initialized - return ERROR_NET_ADHOC_ALREADY_INITIALIZED; + return hleLogWarning(SCENET, ERROR_NET_ADHOC_ALREADY_INITIALIZED, "already initialized"); } static u32 sceNetAdhocctlInit(int stackSize, int prio, u32 productAddr) { @@ -1419,7 +1417,6 @@ int sceNetAdhocctlCreateEnterGameModeMin(const char *group_name, int game_type, } int sceNetAdhocTerm() { - INFO_LOG(SCENET, "sceNetAdhocTerm()"); // WLAN might be disabled in the middle of successfull multiplayer, but we still need to cleanup all the sockets right? if (netAdhocctlInited) sceNetAdhocctlTerm(); @@ -1448,10 +1445,11 @@ int sceNetAdhocTerm() { // if (_manage_modules != 0) sceUtilityUnloadModule(PSP_MODULE_NET_INET); // Library shutdown netAdhocInited = false; - return 0; + return hleLogSuccessInfoI(SCENET, 0); } else { - // Seems to return this when called a second time after being terminated without another initialisation - return SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND; + // TODO: Reportedly returns SCE_KERNEL_ERROR_LWMUTEX_NOT_FOUND in some cases? + // Only seen returning 0 in tests. + return hleLogWarning(SCENET, 0, "already uninitialized"); } } diff --git a/Core/HLE/sceRtc.cpp b/Core/HLE/sceRtc.cpp index 1809430d1c..75e9e3ef3b 100644 --- a/Core/HLE/sceRtc.cpp +++ b/Core/HLE/sceRtc.cpp @@ -37,6 +37,13 @@ #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceRtc.h" +#ifdef HAVE_LIBNX +// I guess that works... +#define setenv(x, y, z) (void*)0 +#define tzset() (void*)0 +#define unsetenv(x) (void*)0 +#endif // HAVE_LIBNX + // This is a base time that everything is relative to. // This way, time doesn't move strangely with savestates, turbo speed, etc. static PSPTimeval rtcBaseTime; @@ -494,7 +501,7 @@ static int sceRtcConvertLocalTimeToUTC(u32 tickLocalPtr,u32 tickUTCPtr) long timezone_val; _get_timezone(&timezone_val); srcTick -= -timezone_val * 1000000ULL; -#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) +#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) && !defined(HAVE_LIBNX) time_t timezone = 0; tm *time = localtime(&timezone); srcTick -= time->tm_gmtoff*1000000ULL; @@ -519,7 +526,7 @@ static int sceRtcConvertUtcToLocalTime(u32 tickUTCPtr,u32 tickLocalPtr) long timezone_val; _get_timezone(&timezone_val); srcTick += -timezone_val * 1000000ULL; -#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) +#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) && !defined(HAVE_LIBNX) time_t timezone = 0; tm *time = localtime(&timezone); srcTick += time->tm_gmtoff*1000000ULL; @@ -1054,7 +1061,7 @@ static int sceRtcFormatRFC2822LocalTime(u32 outPtr, u32 srcTickPtr) long timezone_val; _get_timezone(&timezone_val); tz_seconds = -timezone_val; -#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) +#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) && !defined(HAVE_LIBNX) time_t timezone = 0; tm *time = localtime(&timezone); tz_seconds = time->tm_gmtoff; @@ -1091,7 +1098,7 @@ static int sceRtcFormatRFC3339LocalTime(u32 outPtr, u32 srcTickPtr) long timezone_val; _get_timezone(&timezone_val); tz_seconds = -timezone_val; -#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) +#elif !defined(_AIX) && !defined(__sgi) && !defined(__hpux) && !defined(HAVE_LIBNX) time_t timezone = 0; tm *time = localtime(&timezone); tz_seconds = time->tm_gmtoff; diff --git a/Core/HLE/sceUtility.cpp b/Core/HLE/sceUtility.cpp index 3eb751436b..42ba77e2f6 100644 --- a/Core/HLE/sceUtility.cpp +++ b/Core/HLE/sceUtility.cpp @@ -470,55 +470,46 @@ static int sceUtilityOskGetStatus() } -static int sceUtilityNetconfInitStart(u32 paramsAddr) -{ +static int sceUtilityNetconfInitStart(u32 paramsAddr) { if (currentDialogActive && currentDialogType != UTILITY_DIALOG_NET) { - WARN_LOG(SCEUTILITY, "sceUtilityNetconfInitStart(%08x): wrong dialog type", paramsAddr); - return SCE_ERROR_UTILITY_WRONG_TYPE; + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } oldStatus = 100; currentDialogType = UTILITY_DIALOG_NET; - currentDialogActive = true; - int ret = netDialog.Init(paramsAddr); - INFO_LOG(SCEUTILITY, "%08x=sceUtilityNetconfInitStart(%08x)", ret, paramsAddr); - return ret; + currentDialogActive = true; + return hleLogSuccessInfoI(SCEUTILITY, netDialog.Init(paramsAddr)); } -static int sceUtilityNetconfShutdownStart() -{ +static int sceUtilityNetconfShutdownStart() { if (currentDialogType != UTILITY_DIALOG_NET) { - WARN_LOG(SCEUTILITY, "sceUtilityNetconfShutdownStart(): wrong dialog type"); - return SCE_ERROR_UTILITY_WRONG_TYPE; + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } currentDialogActive = false; - int ret = netDialog.Shutdown(); - DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityNetconfShutdownStart()",ret); - return ret; + return hleLogSuccessI(SCEUTILITY, netDialog.Shutdown()); } -static int sceUtilityNetconfUpdate(int animSpeed) -{ - int ret = netDialog.Update(animSpeed); - ERROR_LOG(SCEUTILITY, "UNIMPL %08x=sceUtilityNetconfUpdate(%i)", ret, animSpeed); - return ret; -} - -static int sceUtilityNetconfGetStatus() -{ - // Spam in Danball Senki BOOST +static int sceUtilityNetconfUpdate(int animSpeed) { if (currentDialogType != UTILITY_DIALOG_NET) { - DEBUG_LOG(SCEUTILITY, "sceUtilityNetconfGetStatus(): wrong dialog type"); - return SCE_ERROR_UTILITY_WRONG_TYPE; + return hleLogWarning(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); + } + + return hleLogSuccessI(SCEUTILITY, netDialog.Update(animSpeed)); +} + +static int sceUtilityNetconfGetStatus() { + if (currentDialogType != UTILITY_DIALOG_NET) { + // Spam in Danball Senki BOOST. + return hleLogDebug(SCEUTILITY, SCE_ERROR_UTILITY_WRONG_TYPE, "wrong dialog type"); } int status = netDialog.GetStatus(); if (oldStatus != status) { oldStatus = status; - DEBUG_LOG(SCEUTILITY, "%08x=sceUtilityNetconfGetStatus()", status); + return hleLogSuccessI(SCEUTILITY, status); } - return status; + return hleLogSuccessVerboseI(SCEUTILITY, status); } static int sceUtilityCheckNetParam(int id) @@ -769,6 +760,18 @@ static u32 sceUtilityUnloadNetModule(u32 module) return 0; } +static int sceUtilityNpSigninInitStart(u32 paramsPtr) { + return hleLogError(SCEUTILITY, 0, "not implemented"); +} + +static int sceUtilityNpSigninUpdate(int animSpeed) { + return hleLogError(SCEUTILITY, 0, "not implemented"); +} + +static int sceUtilityNpSigninGetStatus() { + return hleLogError(SCEUTILITY, 0, "not implemented"); +} + static void sceUtilityInstallInitStart(u32 unknown) { WARN_LOG_REPORT(SCEUTILITY, "UNIMPL sceUtilityInstallInitStart()"); @@ -934,7 +937,7 @@ const HLEFunction sceUtility[] = {0X0251B134, &WrapI_U, "sceUtilityScreenshotInitStart", 'i', "x" }, {0XF9E0008C, &WrapI_V, "sceUtilityScreenshotShutdownStart", 'i', "" }, - {0XAB083EA9, &WrapI_U, "sceUtilityScreenshotUpdate", 'i', "x" }, + {0XAB083EA9, &WrapI_U, "sceUtilityScreenshotUpdate", 'i', "i" }, {0XD81957B7, &WrapI_V, "sceUtilityScreenshotGetStatus", 'i', "" }, {0X86A03A27, &WrapI_U, "sceUtilityScreenshotContStart", 'i', "x" }, @@ -947,10 +950,10 @@ const HLEFunction sceUtility[] = {0XB57E95D9, &WrapI_V, "sceUtilityGamedataInstallGetStatus", 'i', "" }, {0X180F7B62, &WrapI_V, "sceUtilityGamedataInstallAbort", 'i', "" }, - {0X16D02AF0, nullptr, "sceUtilityNpSigninInitStart", '?', "" }, - {0XE19C97D6, nullptr, "sceUtilityNpSigninShutdownStart", '?', "" }, - {0XF3FBC572, nullptr, "sceUtilityNpSigninUpdate", '?', "" }, - {0X86ABDB1B, nullptr, "sceUtilityNpSigninGetStatus", '?', "" }, + {0X16D02AF0, &WrapI_U, "sceUtilityNpSigninInitStart", 'i', "x" }, + {0XE19C97D6, nullptr, "sceUtilityNpSigninShutdownStart", 'i', "" }, + {0XF3FBC572, &WrapI_I, "sceUtilityNpSigninUpdate", 'i', "i" }, + {0X86ABDB1B, &WrapI_V, "sceUtilityNpSigninGetStatus", 'i', "" }, {0X1281DA8E, &WrapV_U, "sceUtilityInstallInitStart", 'v', "x" }, {0X5EF1C24A, nullptr, "sceUtilityInstallShutdownStart", '?', "" }, diff --git a/Core/HW/Camera.cpp b/Core/HW/Camera.cpp index 3c233d8931..d8490d9d5e 100644 --- a/Core/HW/Camera.cpp +++ b/Core/HW/Camera.cpp @@ -338,10 +338,10 @@ int __v4l_startCapture(int ideal_width, int ideal_height) { frmsize.index++; if (frmsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) { INFO_LOG(HLE, "V4L2: frame size supported: %dx%d", frmsize.discrete.width, frmsize.discrete.height); - if (frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height - && fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0 - || frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height - && frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height) { + bool matchesIdeal = frmsize.discrete.width >= ideal_width && frmsize.discrete.height >= ideal_height; + bool zeroPix = fmt.fmt.pix.width == 0 && fmt.fmt.pix.height == 0; + bool pixLarger = frmsize.discrete.width < fmt.fmt.pix.width && frmsize.discrete.height < fmt.fmt.pix.height; + if (matchesIdeal && (zeroPix || pixLarger)) { fmt.fmt.pix.width = frmsize.discrete.width; fmt.fmt.pix.height = frmsize.discrete.height; } diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index 421959b223..bf64fb1725 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -20,6 +20,7 @@ #include "base/stringutil.h" #include "file/vfs.h" #include "gfx/texture_atlas.h" +#include "gfx_es2/draw_text.h" #include "image/zim_load.h" #include "image/png_load.h" #include "util/text/utf8.h" @@ -103,6 +104,41 @@ static AtlasCharLine char_one_line; static AtlasLineArray char_lines; static AtlasTextMetrics char_lines_metrics; +static bool textDrawerInited = false; +static TextDrawer *textDrawer = nullptr; +struct PPGeTextDrawerCacheKey { + bool operator < (const PPGeTextDrawerCacheKey &other) const { + if (align != other.align) + return align < other.align; + if (wrapWidth != other.wrapWidth) + return wrapWidth < other.wrapWidth; + return text < other.text; + } + std::string text; + int align; + float wrapWidth; +}; +struct PPGeTextDrawerImage { + TextStringEntry entry; + u32 ptr; +}; +std::map textDrawerImages; + +// Overwrite the current text lines buffer so it can be drawn later. +void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale, + int WrapType = PPGE_LINE_NONE, int wrapWidth = 0); + +// Get the metrics of the bounding box of the currently stated text. +void PPGeMeasureCurrentText(float *x, float *y, float *w, float *h, int *n); + +// These functions must be called between PPGeBegin and PPGeEnd. + +// Draw currently buffered text using the state from PPGeGetTextBoundingBox() call. +// Clears the buffer and state when done. +void PPGeDrawCurrentText(u32 color = 0xFFFFFFFF); + +void PPGeSetTexture(u32 dataAddr, int width, int height); + //only 0xFFFFFF of data is used static void WriteCmd(u8 cmd, u32 data) { Memory::Write_U32((cmd << 24) | (data & 0xFFFFFF), dlWritePtr); @@ -129,18 +165,18 @@ static void BeginVertexData() { vertexStart = dataWritePtr; } -static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color = 0xFFFFFFFF) { +static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color = 0xFFFFFFFF, float off = -0.5f) { if (g_RemasterMode) { PPGeRemasterVertex vtx; - vtx.x = x - 0.5f; vtx.y = y - 0.5f; vtx.z = 0; - vtx.u = u * tw - 0.5f; vtx.v = v * th - 0.5f; + vtx.x = x + off; vtx.y = y + off; vtx.z = 0; + vtx.u = u * tw + off; vtx.v = v * th + off; vtx.color = color; Memory::WriteStruct(dataWritePtr, &vtx); dataWritePtr += sizeof(vtx); } else { PPGeVertex vtx; - vtx.x = x - 0.5f; vtx.y = y - 0.5f; vtx.z = 0; - vtx.u = u * tw - 0.5f; vtx.v = v * th - 0.5f; + vtx.x = x + off; vtx.y = y + off; vtx.z = 0; + vtx.u = u * tw + off; vtx.v = v * th + off; vtx.color = color; Memory::WriteStruct(dataWritePtr, &vtx); dataWritePtr += sizeof(vtx); @@ -232,13 +268,18 @@ void __PPGeInit() free(imageData[0]); + // We can't create it here, because Android needs it on the right thread. + textDrawerInited = false; + textDrawer = nullptr; + textDrawerImages.clear(); + DEBUG_LOG(SCEGE, "PPGe drawing library initialized. DL: %08x Data: %08x Atlas: %08x (%i) Args: %08x", dlPtr, dataPtr, atlasPtr, atlasSize, listArgs.ptr); } void __PPGeDoState(PointerWrap &p) { - auto s = p.Section("PPGeDraw", 1, 2); + auto s = p.Section("PPGeDraw", 1, 3); if (!s) return; @@ -256,6 +297,30 @@ void __PPGeDoState(PointerWrap &p) p.Do(listArgs); } + if (s >= 3) { + uint32_t sz = (uint32_t)textDrawerImages.size(); + p.Do(sz); + + switch (p.mode) { + case PointerWrap::MODE_READ: + textDrawerImages.clear(); + for (uint32_t i = 0; i < sz; ++i) { + // We only care about the pointers, so we can free them. We'll decimate right away. + PPGeTextDrawerCacheKey key{ StringFromFormat("__savestate__%d", i), -1, -1 }; + textDrawerImages[key] = PPGeTextDrawerImage{}; + p.Do(textDrawerImages[key].ptr); + } + break; + default: + for (const auto &im : textDrawerImages) { + p.Do(im.second.ptr); + } + break; + } + } else { + textDrawerImages.clear(); + } + p.Do(dlPtr); p.Do(dlWritePtr); p.Do(dlSize); @@ -291,6 +356,9 @@ void __PPGeShutdown() dlPtr = 0; savedContextPtr = 0; listArgs = 0; + + delete textDrawer; + textDrawer = nullptr; } void PPGeBegin() @@ -625,9 +693,51 @@ static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, return metrics; } +static bool HasTextDrawer() { + // We create this on first use so it's on the correct thread. + if (textDrawerInited) { + return textDrawer != nullptr; + } + + // TODO: Should we pass a draw_? + textDrawer = TextDrawer::Create(nullptr); + if (textDrawer) { + textDrawer->SetFontScale(1.0f, 1.0f); + textDrawer->SetForcedDPIScale(1.0f); + textDrawer->SetFont(g_Config.sFont.c_str(), 20, 0); + } + textDrawerInited = true; + return textDrawer != nullptr; +} + void PPGeMeasureText(float *w, float *h, int *n, const char *text, float scale, int WrapType, int wrapWidth) { + if (HasTextDrawer()) { + float mw, mh; + textDrawer->SetFontScale(scale, scale); + int dtalign = (WrapType & PPGE_LINE_WRAP_WORD) ? FLAG_WRAP_TEXT : 0; + if (WrapType & PPGE_LINE_USE_ELLIPSIS) + dtalign |= FLAG_ELLIPSIZE_TEXT; + Bounds b(0, 0, wrapWidth <= 0 ? 480.0f : wrapWidth, 272.0f); + textDrawer->MeasureStringRect(text, strlen(text), b, &mw, &mh, dtalign); + + if (w) + *w = mw; + if (h) + *h = mh; + if (n) { + // Cheap way to get the n. + float oneLine, twoLines; + textDrawer->MeasureString("|", 1, &mw, &oneLine); + textDrawer->MeasureStringRect("|\n|", 3, Bounds(0, 0, 480, 272), &mw, &twoLines); + + float lineHeight = twoLines - oneLine; + *n = (int)((mh + (lineHeight - 1)) / lineHeight); + } + return; + } + const AtlasFont &atlasfont = g_ppge_atlas.fonts[0]; AtlasTextMetrics metrics = BreakLines(text, atlasfont, 0, 0, 0, scale, scale, WrapType, wrapWidth, true); if (w) *w = metrics.maxWidth; @@ -683,8 +793,110 @@ void PPGeDrawCurrentText(u32 color) PPGeResetCurrentText(); } -void PPGeDrawText(const char *text, float x, float y, int align, float scale, u32 color) -{ +// Return a value such that (1 << value) >= x +int GetPow2(int x) { +#ifdef __GNUC__ + int ret = 31 - __builtin_clz(x | 1); + if ((1 << ret) < x) +#else + int ret = 0; + while ((1 << ret) < x) +#endif + ret++; + return ret; +} + +static PPGeTextDrawerImage PPGeGetTextImage(const char *text, int align, float scale, float maxWidth, bool wrap) { + int tdalign = (align & PPGE_ALIGN_HCENTER) ? ALIGN_HCENTER : 0; + tdalign |= FLAG_ELLIPSIZE_TEXT; + if (wrap) { + tdalign |= FLAG_WRAP_TEXT; + } + + PPGeTextDrawerCacheKey key{ text, tdalign, maxWidth / scale }; + PPGeTextDrawerImage im; + + auto cacheItem = textDrawerImages.find(key); + if (cacheItem != textDrawerImages.end()) { + im = cacheItem->second; + cacheItem->second.entry.lastUsedFrame = gpuStats.numFlips; + } else { + std::vector bitmapData; + textDrawer->SetFontScale(scale, scale); + Bounds b(0, 0, maxWidth, 272.0f); + std::string cleaned = ReplaceAll(text, "\r", ""); + textDrawer->DrawStringBitmapRect(bitmapData, im.entry, Draw::DataFormat::R8_UNORM, cleaned.c_str(), b, tdalign); + + int bufwBytes = ((im.entry.bmWidth + 31) / 32) * 16; + u32 sz = bufwBytes * (im.entry.bmHeight + 1); + u32 origSz = sz; + im.ptr = __PPGeDoAlloc(sz, true, "PPGeText"); + + if (bitmapData.size() & 1) + bitmapData.resize(bitmapData.size() + 1); + + if (im.ptr) { + int wBytes = (im.entry.bmWidth + 1) / 2; + u8 *ramPtr = (u8 *)Memory::GetPointer(im.ptr); + for (int y = 0; y < im.entry.bmHeight; ++y) { + for (int x = 0; x < wBytes; ++x) { + uint8_t c1 = bitmapData[y * im.entry.bmWidth + x * 2]; + uint8_t c2 = bitmapData[y * im.entry.bmWidth + x * 2 + 1]; + // Convert this to 4-bit palette values. + ramPtr[y * bufwBytes + x] = (c2 & 0xF0) | (c1 >> 4); + } + if (bufwBytes != wBytes) { + memset(ramPtr + y * bufwBytes + wBytes, 0, bufwBytes - wBytes); + } + } + memset(ramPtr + im.entry.bmHeight * bufwBytes, 0, bufwBytes + sz - origSz); + } + + im.entry.lastUsedFrame = gpuStats.numFlips; + textDrawerImages[key] = im; + } + + return im; +} + +static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, int align, float scale, u32 color) { + int bufw = ((im.entry.bmWidth + 31) / 32) * 32; + int wp2 = GetPow2(im.entry.bmWidth); + int hp2 = GetPow2(im.entry.bmHeight); + WriteCmd(GE_CMD_TEXADDR0, im.ptr & 0xFFFFF0); + WriteCmd(GE_CMD_TEXBUFWIDTH0, bufw | ((im.ptr & 0xFF000000) >> 8)); + WriteCmd(GE_CMD_TEXSIZE0, wp2 | (hp2 << 8)); + WriteCmd(GE_CMD_TEXFLUSH, 0); + + float w = im.entry.width * scale; + float h = im.entry.height * scale; + + if (align & PPGE_ALIGN_HCENTER) + x -= w / 2.0f; + else if (align & PPGE_ALIGN_RIGHT) + x -= w; + if (align & PPGE_ALIGN_VCENTER) + y -= h / 2.0f; + else if (align & PPGE_ALIGN_BOTTOM) + y -= h; + + BeginVertexData(); + float u1 = (float)im.entry.width / (1 << wp2); + float v1 = (float)im.entry.height / (1 << hp2); + Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, color, 0.0f); + Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, color, 0.0f); + EndVertexDataAndDraw(GE_PRIM_RECTANGLES); + + PPGeSetDefaultTexture(); +} + +void PPGeDrawText(const char *text, float x, float y, int align, float scale, u32 color) { + if (HasTextDrawer()) { + PPGeTextDrawerImage im = PPGeGetTextImage(text, align, scale, 480.0f - x, false); + PPGeDrawTextImage(im, x, y, align, scale, color); + return; + } + PPGePrepareText(text, x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS); PPGeDrawCurrentText(color); } @@ -718,10 +930,40 @@ void PPGeDrawTextWrapped(const char *text, float x, float y, float wrapWidth, fl s = StripTrailingWhite(s); } - PPGePrepareText(s.c_str(), x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); - int zoom = (PSP_CoreParameter().pixelHeight + 479) / 480; float maxScaleDown = zoom == 1 ? 1.3f : 2.0f; + + if (HasTextDrawer()) { + float actualWidth, actualHeight; + Bounds b(0, 0, wrapWidth <= 0 ? 480.0f - x : wrapWidth, wrapHeight); + int tdalign = (align & PPGE_ALIGN_HCENTER) ? ALIGN_HCENTER : 0; + textDrawer->SetFontScale(scale, scale); + textDrawer->MeasureStringRect(s.c_str(), s.size(), b, &actualWidth, &actualHeight, tdalign | FLAG_WRAP_TEXT); + if (wrapHeight != 0.0f && actualHeight > wrapHeight) { + // Cheap way to get the line height. + float oneLine, twoLines; + textDrawer->MeasureString("|", 1, &actualWidth, &oneLine); + textDrawer->MeasureStringRect("|\n|", 3, Bounds(0, 0, 480, 272), &actualWidth, &twoLines); + + float lineHeight = twoLines - oneLine; + if (actualHeight > wrapHeight * maxScaleDown) { + float maxLines = floor(wrapHeight * maxScaleDown / lineHeight); + actualHeight = (maxLines + 1) * lineHeight; + // Add an ellipsis if it's just too long to be readable. + // On a PSP, it does this without scaling it down. + s = StripTrailingWhite(CropLinesToCount(s, (int)maxLines)) + "\n..."; + } + + scale *= wrapHeight / actualHeight; + } + + PPGeTextDrawerImage im = PPGeGetTextImage(s.c_str(), align, scale, wrapWidth <= 0 ? 480.0f - x : wrapWidth, true); + PPGeDrawTextImage(im, x, y, align, scale, color); + return; + } + + PPGePrepareText(s.c_str(), x, y, align, scale, scale, PPGE_LINE_USE_ELLIPSIS | PPGE_LINE_WRAP_WORD, wrapWidth); + float actualHeight = char_lines_metrics.lineHeight * char_lines_metrics.numLines; if (wrapHeight != 0.0f && actualHeight > wrapHeight) { if (actualHeight > wrapHeight * maxScaleDown) { @@ -837,20 +1079,6 @@ void PPGeDrawImage(float x, float y, float w, float h, float u1, float v1, float EndVertexDataAndDraw(GE_PRIM_RECTANGLES); } -// Return a value such that (1 << value) >= x -int GetPow2(int x) -{ -#ifdef __GNUC__ - int ret = 31 - __builtin_clz(x|1); - if ((1 << ret) < x) -#else - int ret = 0; - while ((1 << ret) < x) -#endif - ret++; - return ret; -} - void PPGeSetDefaultTexture() { WriteCmd(GE_CMD_TEXTUREMAPENABLE, 1); @@ -1004,3 +1232,20 @@ void PPGeImage::SetTexture() { } } +void PPGeNotifyFrame() { + if (textDrawer) { + textDrawer->OncePerFrame(); + } + + // Do this always, in case the platform has no TextDrawer but save state did. + for (auto it = textDrawerImages.begin(); it != textDrawerImages.end(); ) { + if (it->second.entry.lastUsedFrame - gpuStats.numFlips >= 97) { + kernelMemory.Free(it->second.ptr); + it = textDrawerImages.erase(it); + } else { + ++it; + } + } + + PPGeImage::Decimate(); +} diff --git a/Core/Util/PPGeDraw.h b/Core/Util/PPGeDraw.h index a599c45e37..8962fa7f99 100644 --- a/Core/Util/PPGeDraw.h +++ b/Core/Util/PPGeDraw.h @@ -45,10 +45,6 @@ void __PPGeShutdown(); void PPGeBegin(); void PPGeEnd(); -// If you want to draw using this texture but not go through the PSP GE emulation, -// jsut call this. Will bind the texture to unit 0. -void PPGeBindTexture(); - enum { PPGE_ALIGN_LEFT = 0, PPGE_ALIGN_RIGHT = 16, @@ -65,11 +61,6 @@ enum { PPGE_ALIGN_BOTTOMRIGHT = PPGE_ALIGN_BOTTOM | PPGE_ALIGN_RIGHT, }; -enum { - PPGE_ESCAPE_NONE, - PPGE_ESCAPE_BACKSLASHED, -}; - enum { PPGE_LINE_NONE = 0, PPGE_LINE_USE_ELLIPSIS = 1, // use ellipses in too long words @@ -81,19 +72,6 @@ enum { void PPGeMeasureText(float *w, float *h, int *n, const char *text, float scale, int WrapType = PPGE_LINE_NONE, int wrapWidth = 0); -// Overwrite the current text lines buffer so it can be drawn later. -void PPGePrepareText(const char *text, float x, float y, int align, float scale, float lineHeightScale, - int WrapType = PPGE_LINE_NONE, int wrapWidth = 0); - -// Get the metrics of the bounding box of the currently stated text. -void PPGeMeasureCurrentText(float *x, float *y, float *w, float *h, int *n); - -// These functions must be called between PPGeBegin and PPGeEnd. - -// Draw currently buffered text using the state from PPGeGetTextBoundingBox() call. -// Clears the buffer and state when done. -void PPGeDrawCurrentText(u32 color = 0xFFFFFFFF); - // Draws some text using the one font we have. // Clears the text buffer when done. void PPGeDrawText(const char *text, float x, float y, int align, float scale = 1.0f, u32 color = 0xFFFFFFFF); @@ -107,6 +85,8 @@ void PPGeDrawImage(ImageID atlasImage, float x, float y, int align, u32 color = void PPGeDrawImage(ImageID atlasImage, float x, float y, float w, float h, int align, u32 color = 0xFFFFFFFF); void PPGeDrawImage(float x, float y, float w, float h, float u1, float v1, float u2, float v2, int tw, int th, u32 color); +void PPGeNotifyFrame(); + class PPGeImage { public: PPGeImage(const std::string &pspFilename); @@ -132,8 +112,9 @@ public: return height_; } -private: static void Decimate(); + +private: static std::vector loadedTextures_; std::string filename_; @@ -152,6 +133,5 @@ private: void PPGeDrawRect(float x1, float y1, float x2, float y2, u32 color); void PPGeSetDefaultTexture(); -void PPGeSetTexture(u32 dataAddr, int width, int height); void PPGeDisableTexture(); diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index db68a3c9db..97d2081810 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -1439,9 +1439,9 @@ void ClearRectangle(const VertexData &v0, const VertexData &v1) DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0); DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0); minX = std::max(minX, (int)TransformUnit::DrawingToScreen(scissorTL).x); - maxX = std::max(0, std::min(maxX, (int)TransformUnit::DrawingToScreen(scissorBR).x)); + maxX = std::max(0, std::min(maxX, (int)TransformUnit::DrawingToScreen(scissorBR).x + 16)); minY = std::max(minY, (int)TransformUnit::DrawingToScreen(scissorTL).y); - maxY = std::max(0, std::min(maxY, (int)TransformUnit::DrawingToScreen(scissorBR).y)); + maxY = std::max(0, std::min(maxY, (int)TransformUnit::DrawingToScreen(scissorBR).y + 16)); const int w = (maxX - minX) / 16; if (w <= 0) diff --git a/GPU/Software/RasterizerRectangle.cpp b/GPU/Software/RasterizerRectangle.cpp index 3845c355f3..e396d3a16a 100644 --- a/GPU/Software/RasterizerRectangle.cpp +++ b/GPU/Software/RasterizerRectangle.cpp @@ -184,8 +184,8 @@ void DrawSprite(const VertexData& v0, const VertexData& v1) { } } } else { - if (pos1.x > scissorBR.x) pos1.x = scissorBR.x; - if (pos1.y > scissorBR.y) pos1.y = scissorBR.y; + if (pos1.x > scissorBR.x) pos1.x = scissorBR.x + 1; + if (pos1.y > scissorBR.y) pos1.y = scissorBR.y + 1; if (pos0.x < scissorTL.x) pos0.x = scissorTL.x; if (pos0.y < scissorTL.y) pos0.y = scissorTL.y; if (!gstate.isStencilTestEnabled() && diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 9b3345678a..e60cfaf257 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -230,9 +230,9 @@ PermissionStatus System_GetPermissionStatus(SystemPermission permission) { retur void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { QString text = emugl->InputBoxGetQString(QString::fromStdString(title), QString::fromStdString(defaultValue)); if (text.isEmpty()) { - cb(false, ""); + NativeInputBoxReceived(cb, false, ""); } else { - cb(true, text.toStdString()); + NativeInputBoxReceived(cb, true, text.toStdString()); } } diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index ced99103ca..2639a5a23a 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -198,8 +198,9 @@ void OpenDirectory(const char *path) { void LaunchBrowser(const char *url) { #if PPSSPP_PLATFORM(SWITCH) + Uuid uuid = { 0 }; WebWifiConfig conf; - webWifiCreate(&conf, NULL, url, 0, 0); + webWifiCreate(&conf, NULL, url, uuid, 0); webWifiShow(&conf, NULL); #elif defined(MOBILE_DEVICE) ILOG("Would have gone to %s but LaunchBrowser is not implemented on this platform", url); @@ -220,8 +221,9 @@ void LaunchBrowser(const char *url) { void LaunchMarket(const char *url) { #if PPSSPP_PLATFORM(SWITCH) + Uuid uuid = { 0 }; WebWifiConfig conf; - webWifiCreate(&conf, NULL, url, 0, 0); + webWifiCreate(&conf, NULL, url, uuid, 0); webWifiShow(&conf, NULL); #elif defined(MOBILE_DEVICE) ILOG("Would have gone to %s but LaunchMarket is not implemented on this platform", url); @@ -448,6 +450,11 @@ int main(int argc, char *argv[]) { } } +#ifdef HAVE_LIBNX + socketInitializeDefault(); + nxlinkStdio(); +#endif // HAVE_LIBNX + glslang::InitializeProcess(); #if PPSSPP_PLATFORM(RPI) @@ -544,9 +551,9 @@ int main(int argc, char *argv[]) { } // If we're on mobile, don't try for windowed either. -#if defined(MOBILE_DEVICE) +#if defined(MOBILE_DEVICE) && !PPSSPP_PLATFORM(SWITCH) mode |= SDL_WINDOW_FULLSCREEN; -#elif defined(USING_FBDEV) +#elif defined(USING_FBDEV) || PPSSPP_PLATFORM(SWITCH) mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; #else mode |= SDL_WINDOW_RESIZABLE; @@ -592,14 +599,19 @@ int main(int argc, char *argv[]) { // Mac / Linux char path[2048]; +#if PPSSPP_PLATFORM(SWITCH) + strcpy(path, "/switch/ppsspp/"); +#else const char *the_path = getenv("HOME"); if (!the_path) { - struct passwd* pwd = getpwuid(getuid()); + struct passwd *pwd = getpwuid(getuid()); if (pwd) the_path = pwd->pw_dir; } - strcpy(path, the_path); - if (path[strlen(path)-1] != '/') + if (the_path) + strcpy(path, the_path); +#endif + if (strlen(path) > 0 && path[strlen(path) - 1] != '/') strcat(path, "/"); NativeInit(remain_argc, (const char **)remain_argv, path, "/tmp", nullptr); @@ -1139,5 +1151,8 @@ int main(int argc, char *argv[]) { glslang::FinalizeProcess(); ILOG("Leaving main"); +#ifdef HAVE_LIBNX + socketExit(); +#endif return 0; } diff --git a/UI/ChatScreen.cpp b/UI/ChatScreen.cpp index e3b5229e27..ba15f03a94 100644 --- a/UI/ChatScreen.cpp +++ b/UI/ChatScreen.cpp @@ -14,7 +14,6 @@ #include #include "util/text/utf8.h" - void ChatMenu::CreatePopupContents(UI::ViewGroup *parent) { using namespace UI; auto n = GetI18NCategory("Networking"); @@ -34,6 +33,7 @@ void ChatMenu::CreatePopupContents(UI::ViewGroup *parent) { } #endif chatEdit_->OnEnter.Handle(this, &ChatMenu::OnSubmit); + #elif PPSSPP_PLATFORM(ANDROID) bottom->Add(new Button(n->T("Chat Here"),new LayoutParams(FILL_PARENT, WRAP_CONTENT)))->OnClick.Handle(this, &ChatMenu::OnSubmit); bottom->Add(new Button(n->T("Send")))->OnClick.Handle(this, &ChatMenu::OnSubmit); @@ -84,26 +84,31 @@ void ChatMenu::CreateViews() { case 5: box_ = new LinearLayout(ORIENT_VERTICAL, new AnchorLayoutParams(PopupWidth(), FillVertical() ? yres - 30 : WRAP_CONTENT, NONE, 240, 280, NONE, true)); break; + default: + box_ = nullptr; + break; } - root_->Add(box_); - box_->SetBG(UI::Drawable(0x99303030)); - box_->SetHasDropShadow(false); + if (box_) { + root_->Add(box_); + box_->SetBG(UI::Drawable(0x99303030)); + box_->SetHasDropShadow(false); - View *title = new PopupHeader(n->T("Chat")); - box_->Add(title); + View *title = new PopupHeader(n->T("Chat")); + box_->Add(title); - CreatePopupContents(box_); + CreatePopupContents(box_); #if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) - UI::EnableFocusMovement(true); - root_->SetDefaultFocusView(box_); - box_->SubviewFocused(chatEdit_); - root_->SetFocus(); + UI::EnableFocusMovement(true); + root_->SetDefaultFocusView(box_); + box_->SubviewFocused(chatEdit_); + root_->SetFocus(); #else - //root_->SetDefaultFocusView(box_); - //box_->SubviewFocused(scroll_); - //root_->SetFocus(); + //root_->SetDefaultFocusView(box_); + //box_->SubviewFocused(scroll_); + //root_->SetFocus(); #endif + } chatScreenVisible = true; newChat = 0; @@ -129,7 +134,6 @@ UI::EventReturn ChatMenu::OnSubmit(UI::EventParams &e) { return UI::EVENT_DONE; } - UI::EventReturn ChatMenu::OnQuickChat1(UI::EventParams &e) { sendChat(g_Config.sQuickChat0); return UI::EVENT_DONE; @@ -191,7 +195,7 @@ std::vector Split(const std::string& str) void ChatMenu::UpdateChat() { using namespace UI; - if (chatVert_ != NULL) { + if (chatVert_ != nullptr) { chatVert_->Clear(); //read Access violation is proadhoc.cpp use NULL_->Clear() pointer? std::vector chatLog = getChatLog(); for (auto i : chatLog) { @@ -208,11 +212,10 @@ void ChatMenu::UpdateChat() { namecolor = 0xE53935; } - if (i[displayname.length()] != ':') { + if (i.length() <= displayname.length() || i[displayname.length()] != ':') { TextView *v = chatVert_->Add(new TextView(i, FLAG_DYNAMIC_ASCII, true)); v->SetTextColor(0xFF000000 | infocolor); - } - else { + } else { LinearLayout *line = chatVert_->Add(new LinearLayout(ORIENT_HORIZONTAL, new LayoutParams(FILL_PARENT, FILL_PARENT))); TextView *nameView = line->Add(new TextView(displayname, FLAG_DYNAMIC_ASCII, true)); nameView->SetTextColor(0xFF000000 | namecolor); diff --git a/UI/ChatScreen.h b/UI/ChatScreen.h index ecb6d1546e..4470a27acd 100644 --- a/UI/ChatScreen.h +++ b/UI/ChatScreen.h @@ -1,10 +1,12 @@ #pragma once + +#include "ppsspp_config.h" #include "file/file_util.h" #include "ui/ui_screen.h" class ChatMenu : public PopupScreen { public: - ChatMenu() : PopupScreen("Chat") , toBottom_(true) {} + ChatMenu(): PopupScreen("Chat") {} ~ChatMenu(); void CreatePopupContents(UI::ViewGroup *parent) override; void CreateViews() override; @@ -12,7 +14,9 @@ public: bool touch(const TouchInput &touch) override; void update() override; void UpdateChat(); - bool toBottom_; + + bool toBottom_ = true; + private: UI::EventReturn OnSubmit(UI::EventParams &e); UI::EventReturn OnQuickChat1(UI::EventParams &e); @@ -20,8 +24,11 @@ private: UI::EventReturn OnQuickChat3(UI::EventParams &e); UI::EventReturn OnQuickChat4(UI::EventParams &e); UI::EventReturn OnQuickChat5(UI::EventParams &e); - UI::TextEdit *chatEdit_; - UI::ScrollView *scroll_; - UI::LinearLayout *chatVert_; - UI::ViewGroup *box_; -}; \ No newline at end of file + +#if PPSSPP_PLATFORM(WINDOWS) || defined(USING_QT_UI) + UI::TextEdit *chatEdit_ = nullptr; +#endif + UI::ScrollView *scroll_ = nullptr; + UI::LinearLayout *chatVert_ = nullptr; + UI::ViewGroup *box_ = nullptr; +}; diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 2708cd32fd..d56d8dd9a5 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1403,6 +1403,8 @@ void EmuScreen::render() { return; if (hasVisibleUI()) { + // In most cases, this should already be bound and a no-op. + thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::KEEP, RPAction::DONT_CARE, RPAction::DONT_CARE }); cardboardDisableButton_->SetVisibility(g_Config.bEnableCardboardVR ? UI::V_VISIBLE : UI::V_GONE); screenManager()->getUIContext()->BeginFrame(); renderUI(); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 8d9d143b23..10801c1610 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -343,6 +343,11 @@ void GameSettingsScreen::CreateViews() { return UI::EVENT_CONTINUE; }); #endif + CheckBox *frameDuplication = graphicsSettings->Add(new CheckBox(&g_Config.bRenderDuplicateFrames, gr->T("Render duplicate frames to 60hz"))); + frameDuplication->OnClick.Add([=](EventParams &e) { + settingInfo_->Show(gr->T("RenderDuplicateFrames Tip", "Can make framerate smoother in games that run at lower framerates"), e.v); + return UI::EVENT_CONTINUE; + }); if (GetGPUBackend() == GPUBackend::VULKAN || GetGPUBackend() == GPUBackend::OPENGL) { static const char *bufferOptions[] = { "No buffer", "Up to 1", "Up to 2" }; @@ -801,8 +806,8 @@ void GameSettingsScreen::CreateViews() { systemSettings->Add(new CheckBox(&g_Config.bEnableStateUndo, sy->T("Savestate slot backups"))); static const char *autoLoadSaveStateChoices[] = { "Off", "Oldest Save", "Newest Save", "Slot 1", "Slot 2", "Slot 3", "Slot 4", "Slot 5" }; systemSettings->Add(new PopupMultiChoice(&g_Config.iAutoLoadSaveState, sy->T("Auto Load Savestate"), autoLoadSaveStateChoices, 0, ARRAY_SIZE(autoLoadSaveStateChoices), sy->GetName(), screenManager())); -#if defined(USING_WIN_UI) - systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Enable Windows native keyboard", "Enable Windows native keyboard"))); +#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(ANDROID) + systemSettings->Add(new CheckBox(&g_Config.bBypassOSKWithKeyboard, sy->T("Use system native keyboard"))); #endif #if PPSSPP_PLATFORM(ANDROID) auto memstickPath = systemSettings->Add(new ChoiceWithValueDisplay(&g_Config.memStickDirectory, sy->T("Change Memory Stick folder"), (const char *)nullptr)); diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 654be8d6e7..9f0930f77d 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -15,12 +15,20 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "ppsspp_config.h" #include #include #include +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) +#include "Common/CommonWindows.h" +#include +#endif + #include "base/timeutil.h" #include "file/path.h" +// TODO: For text align flags, probably shouldn't be in gfx_es2/... +#include "gfx_es2/draw_buffer.h" #include "i18n/i18n.h" #include "json/json_reader.h" #include "net/http_client.h" @@ -39,6 +47,49 @@ static const int REPORT_PORT = 80; static bool scanCancelled = false; static bool scanAborted = false; +enum class ServerAllowStatus { + NO, + YES, + UNKNOWN, +}; + +static ServerAllowStatus IsServerAllowed(int port) { +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) + INetFwMgr *fwMgr = nullptr; + HRESULT hr = CoCreateInstance(__uuidof(NetFwMgr), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void **)&fwMgr); + if (FAILED(hr)) { + return ServerAllowStatus::UNKNOWN; + } + + std::wstring app; + size_t sz; + do { + app.resize(app.size() + MAX_PATH); + // On failure, this will return the same value as passed in, but success will always be one lower. + sz = GetModuleFileName(nullptr, &app[0], (DWORD)app.size()); + } while (sz >= app.size()); + + VARIANT allowedV, restrictedV; + VariantInit(&allowedV); + VariantInit(&restrictedV); + hr = fwMgr->IsPortAllowed(&app[0], NET_FW_IP_VERSION_ANY, port, nullptr, NET_FW_IP_PROTOCOL_TCP, &allowedV, &restrictedV); + fwMgr->Release(); + + if (FAILED(hr)) { + return ServerAllowStatus::UNKNOWN; + } + + bool allowed = allowedV.vt == VT_BOOL && allowedV.boolVal != VARIANT_FALSE; + bool restricted = restrictedV.vt == VT_BOOL && restrictedV.boolVal != VARIANT_FALSE; + if (!allowed || restricted) { + return ServerAllowStatus::NO; + } + return ServerAllowStatus::YES; +#else + return ServerAllowStatus::UNKNOWN; +#endif +} + static std::string RemoteSubdir() { if (g_Config.bRemoteISOManual) { return g_Config.sRemoteISOSubdir; @@ -47,45 +98,71 @@ static std::string RemoteSubdir() { return "/"; } -static bool FindServer(std::string &resultHost, int &resultPort) { +bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort) { http::Client http; Buffer result; int code = 500; + bool hadTimeouts = false; std::string subdir = RemoteSubdir(); + auto ri = GetI18NCategory("RemoteISO"); + auto SetStatus = [&](const std::string &key, const std::string &host, int port) { + std::string formatted = ReplaceAll(ri->T(key), "[URL]", StringFromFormat("http://%s:%d/", host.c_str(), port)); + + std::lock_guard guard(statusLock_); + statusMessage_ = formatted; + }; + auto TryServer = [&](const std::string &host, int port) { + SetStatus("Resolving [URL]...", host, port); + if (!http.Resolve(host.c_str(), port)) { + SetStatus("Could not resolve [URL]", host, port); + return false; + } + + SetStatus("Connecting to [URL]...", host, port); // Don't wait as long for a connect - we need a good connection for smooth streaming anyway. // This way if it's down, we'll find the right one faster. - if (http.Resolve(host.c_str(), port) && http.Connect(1, 10.0, &scanCancelled)) { - code = http.GET(subdir.c_str(), &result); - http.Disconnect(); + if (!http.Connect(1, 10.0, &scanCancelled)) { + hadTimeouts = true; + SetStatus("Could not connect to [URL]", host, port); + return false; + } - if (code != 200) { - return false; + SetStatus("Loading game list from [URL]...", host, port); + code = http.GET(subdir.c_str(), &result); + http.Disconnect(); + + if (code != 200) { + if (code < 0) { + hadTimeouts = true; } + SetStatus("Game list failed from [URL]", host, port); + return false; + } - // Make sure this isn't just the debugger. If so, move on. - std::string listing; - std::vector items; - result.TakeAll(&listing); - SplitString(listing, '\n', items); + // Make sure this isn't just the debugger. If so, move on. + std::string listing; + std::vector items; + result.TakeAll(&listing); + SplitString(listing, '\n', items); - bool supported = false; - for (const std::string &item : items) { - if (!RemoteISOFileSupported(item)) { - continue; - } - supported = true; - break; + bool supported = false; + for (const std::string &item : items) { + if (!RemoteISOFileSupported(item)) { + continue; } + supported = true; + break; + } - if (supported) { - resultHost = host; - resultPort = port; - NOTICE_LOG(HLE, "RemoteISO found: %s : %d", host.c_str(), port); - return true; - } + if (supported) { + resultHost = host; + resultPort = port; + SetStatus("Connected to [URL]", host, port); + NOTICE_LOG(SYSTEM, "RemoteISO found: %s : %d", host.c_str(), port); + return true; } return false; @@ -104,6 +181,7 @@ static bool FindServer(std::string &resultHost, int &resultPort) { } // Start by requesting a list of recent local ips for this network. + SetStatus("Looking for peers...", "", 0); if (http.Resolve(REPORT_HOSTNAME, REPORT_PORT)) { if (http.Connect(2, 20.0, &scanCancelled)) { code = http.GET("/match/list", &result); @@ -112,6 +190,9 @@ static bool FindServer(std::string &resultHost, int &resultPort) { } if (code != 200 || scanCancelled) { + if (!scanCancelled) { + SetStatus("Could not load peers, retrying soon...", "", 0); + } return false; } @@ -122,11 +203,13 @@ static bool FindServer(std::string &resultHost, int &resultPort) { JsonReader reader(json.c_str(), json.size()); if (!reader.ok()) { + SetStatus("Could not load peers, retrying soon...", "", 0); return false; } const JsonValue entries = reader.rootArray(); if (entries.getTag() != JSON_ARRAY) { + SetStatus("Could not load peers, retrying soon...", "", 0); return false; } @@ -143,7 +226,13 @@ static bool FindServer(std::string &resultHost, int &resultPort) { } } - // None of the local IPs were reachable. + // None of the local IPs were reachable. We'll retry again. + std::lock_guard guard(statusLock_); + if (hadTimeouts) { + statusMessage_ = ri->T("RemoteISOScanningTimeout", "Scanning... check your desktop's firewall settings"); + } else { + statusMessage_ = ri->T("RemoteISOScanning", "Scanning... click Share Games on your desktop"); + } return false; } @@ -163,12 +252,21 @@ static bool LoadGameList(const std::string &url, std::vector &games return !games.empty(); } -RemoteISOScreen::RemoteISOScreen() : serverRunning_(false), serverStopping_(false) { +RemoteISOScreen::RemoteISOScreen() { } void RemoteISOScreen::update() { UIScreenWithBackground::update(); + if (!WebServerStopped(WebServerFlags::DISCS)) { + auto result = IsServerAllowed(g_Config.iRemoteISOPort); + if (result == ServerAllowStatus::NO) { + firewallWarning_->SetVisibility(V_VISIBLE); + } else if (result == ServerAllowStatus::YES) { + firewallWarning_->SetVisibility(V_GONE); + } + } + bool nowRunning = !WebServerStopped(WebServerFlags::DISCS); if (serverStopping_ && !nowRunning) { serverStopping_ = false; @@ -193,6 +291,9 @@ void RemoteISOScreen::CreateViews() { leftColumnItems->Add(new TextView(ri->T("RemoteISODesc", "Games in your recent list will be shared"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); leftColumnItems->Add(new TextView(ri->T("RemoteISOWifi", "Note: Connect both devices to the same wifi"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); + firewallWarning_ = leftColumnItems->Add(new TextView(ri->T("RemoteISOWinFirewall", "WARNING: Windows Firewall is blocking sharing"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); + firewallWarning_->SetTextColor(0xFF0000FF); + firewallWarning_->SetVisibility(V_GONE); rightColumnItems->SetSpacing(0.0f); Choice *browseChoice = new Choice(ri->T("Browse Games")); @@ -250,7 +351,7 @@ UI::EventReturn RemoteISOScreen::HandleSettings(UI::EventParams &e) { return EVENT_DONE; } -RemoteISOConnectScreen::RemoteISOConnectScreen() : status_(ScanStatus::SCANNING), nextRetry_(0.0) { +RemoteISOConnectScreen::RemoteISOConnectScreen() { scanCancelled = false; scanAborted = false; @@ -286,7 +387,7 @@ void RemoteISOConnectScreen::CreateViews() { ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins)); LinearLayout *rightColumnItems = new LinearLayout(ORIENT_VERTICAL); - statusView_ = leftColumnItems->Add(new TextView(ri->T("RemoteISOScanning", "Scanning... click Share Games on your desktop"), new LinearLayoutParams(Margins(12, 5, 0, 5)))); + statusView_ = leftColumnItems->Add(new TextView(ri->T("RemoteISOScanning", "Scanning... click Share Games on your desktop"), FLAG_WRAP_TEXT, false, new LinearLayoutParams(Margins(12, 5, 0, 5)))); rightColumnItems->SetSpacing(0.0f); rightColumnItems->Add(new Choice(di->T("Cancel"), "", false, new AnchorLayoutParams(150, WRAP_CONTENT, 10, NONE, NONE, 10)))->OnClick.Handle(this, &UIScreen::OnBack); @@ -318,13 +419,14 @@ void RemoteISOConnectScreen::update() { if (scanThread_->joinable()) scanThread_->join(); delete scanThread_; + statusMessage_.clear(); scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) { thiz->ExecuteLoad(); }, this); break; case ScanStatus::FAILED: - nextRetry_ = real_time_now() + 30.0; + nextRetry_ = real_time_now() + 15.0; status_ = ScanStatus::RETRY_SCAN; break; @@ -336,6 +438,7 @@ void RemoteISOConnectScreen::update() { if (scanThread_->joinable()) scanThread_->join(); delete scanThread_; + statusMessage_.clear(); scanThread_ = new std::thread([](RemoteISOConnectScreen *thiz) { thiz->ExecuteScan(); }, this); @@ -347,6 +450,11 @@ void RemoteISOConnectScreen::update() { screenManager()->push(new RemoteISOBrowseScreen(url_, games_)); break; } + + std::lock_guard guard(statusLock_); + if (!statusMessage_.empty()) { + statusView_->SetText(statusMessage_); + } } void RemoteISOConnectScreen::ExecuteScan() { diff --git a/UI/RemoteISOScreen.h b/UI/RemoteISOScreen.h index 06f7889a1c..a294969259 100644 --- a/UI/RemoteISOScreen.h +++ b/UI/RemoteISOScreen.h @@ -38,8 +38,9 @@ protected: UI::EventReturn HandleBrowse(UI::EventParams &e); UI::EventReturn HandleSettings(UI::EventParams &e); - bool serverRunning_; - bool serverStopping_; + UI::TextView *firewallWarning_ = nullptr; + bool serverRunning_ = false; + bool serverStopping_ = false; }; enum class ScanStatus { @@ -63,11 +64,13 @@ protected: ScanStatus GetStatus(); void ExecuteScan(); void ExecuteLoad(); + bool FindServer(std::string &resultHost, int &resultPort); UI::TextView *statusView_; - ScanStatus status_; - double nextRetry_; + ScanStatus status_ = ScanStatus::SCANNING; + std::string statusMessage_; + double nextRetry_ = 0.0; std::thread *scanThread_; std::mutex statusLock_; std::string host_; diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index 577fb40e57..fe0988733d 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -17,7 +17,7 @@ #include #include "base/display.h" -// TODO: For text align flags, probably shouldn';t be in gfx_es2/... +// TODO: For text align flags, probably shouldn't be in gfx_es2/... #include "gfx_es2/draw_buffer.h" #include "i18n/i18n.h" #include "thin3d/thin3d.h" diff --git a/Windows/CaptureDevice.h b/Windows/CaptureDevice.h index fe82f02a93..aa0d0dc744 100644 --- a/Windows/CaptureDevice.h +++ b/Windows/CaptureDevice.h @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include diff --git a/Windows/main.cpp b/Windows/main.cpp index 8a8d4e616a..85e63f6cf5 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -341,9 +341,9 @@ void EnableCrashingOnCrashes() { void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { std::string out; if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), ConvertUTF8ToWString(title).c_str(), defaultValue, out)) { - cb(true, out); + NativeInputBoxReceived(cb, true, out); } else { - cb(false, ""); + NativeInputBoxReceived(cb, false, ""); } } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 277fd0776d..be07052534 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1043,32 +1043,32 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J return false; } -retry: + auto tryInit = [&]() { + if (graphicsContext->InitFromRenderThread(wnd, desiredBackbufferSizeX, desiredBackbufferSizeY, backbuffer_format, androidVersion)) { + return true; + } - bool vulkan = g_Config.iGPUBackend == (int)GPUBackend::VULKAN; - - int tries = 0; - - if (!graphicsContext->InitFromRenderThread(wnd, desiredBackbufferSizeX, desiredBackbufferSizeY, backbuffer_format, androidVersion)) { ELOG("Failed to initialize graphics context."); + return false; + }; - if (!exitRenderLoop && (vulkan && tries < 2)) { + bool initSuccess = tryInit(); + if (!initSuccess) { + if (!exitRenderLoop && g_Config.iGPUBackend == (int)GPUBackend::VULKAN) { ILOG("Trying again, this time with OpenGL."); - g_Config.iGPUBackend = (int)GPUBackend::OPENGL; - SetGPUBackend((GPUBackend)g_Config.iGPUBackend); - // If we were still supporting EGL for GL: - // tries++; - // goto retry; + SetGPUBackend(GPUBackend::OPENGL); + g_Config.iGPUBackend = (int)GetGPUBackend(); + + // If we were still supporting EGL for GL, we'd retry here: + //initSuccess = tryInit(); + } + + if (!initSuccess) { delete graphicsContext; graphicsContext = nullptr; renderLoopRunning = false; return false; } - - delete graphicsContext; - graphicsContext = nullptr; - renderLoopRunning = false; - return false; } if (!exitRenderLoop) { diff --git a/ext/native/base/display.cpp b/ext/native/base/display.cpp index c673639551..28a482aa06 100644 --- a/ext/native/base/display.cpp +++ b/ext/native/base/display.cpp @@ -30,7 +30,6 @@ void RotateRectToDisplayImpl(DisplayRect &rect, T curRTWidth, T curRTHeight) // Note that curRTWidth_ and curRTHeight_ are "swapped"! T origX = rect.x; T origY = rect.y; - T rtw = curRTHeight; T rth = curRTWidth; rect.x = clamp_value(rth - rect.h - origY, T{}, curRTHeight); rect.y = origX; @@ -43,7 +42,6 @@ void RotateRectToDisplayImpl(DisplayRect &rect, T curRTWidth, T curRTHeight) T origX = rect.x; T origY = rect.y; T rtw = curRTHeight; - T rth = curRTWidth; rect.x = origY; rect.y = clamp_value(rtw - rect.w - origX, T{}, curRTWidth); T temp = rect.w; diff --git a/ext/native/base/timeutil.cpp b/ext/native/base/timeutil.cpp index f48c87a276..5c70e80053 100644 --- a/ext/native/base/timeutil.cpp +++ b/ext/native/base/timeutil.cpp @@ -11,6 +11,10 @@ #include #endif +#ifdef HAVE_LIBNX +#include +#endif // HAVE_LIBNX + static double curtime = 0; static float curtime_f = 0; @@ -79,6 +83,8 @@ int time_now_ms() { void sleep_ms(int ms) { #ifdef _WIN32 Sleep(ms); +#elif defined(HAVE_LIBNX) + svcSleepThread(ms * 1000000); #else usleep(ms * 1000); #endif diff --git a/ext/native/gfx_es2/draw_buffer.cpp b/ext/native/gfx_es2/draw_buffer.cpp index 78eb6733ab..dbe024fe24 100644 --- a/ext/native/gfx_es2/draw_buffer.cpp +++ b/ext/native/gfx_es2/draw_buffer.cpp @@ -365,7 +365,7 @@ void DrawBuffer::DrawImage2GridH(ImageID atlas_image, float x1, float y1, float class AtlasWordWrapper : public WordWrapper { public: // Note: maxW may be height if rotated. - AtlasWordWrapper(const AtlasFont &atlasfont, float scale, const char *str, float maxW) : WordWrapper(str, maxW), atlasfont_(atlasfont), scale_(scale) { + AtlasWordWrapper(const AtlasFont &atlasfont, float scale, const char *str, float maxW, int flags) : WordWrapper(str, maxW, flags), atlasfont_(atlasfont), scale_(scale) { } protected: @@ -442,14 +442,15 @@ void DrawBuffer::MeasureTextRect(FontID font_id, const char *text, int count, co } std::string toMeasure = std::string(text, count); - if (align & FLAG_WRAP_TEXT) { + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { const AtlasFont *font = atlas->getFont(font_id); if (!font) { *w = 0.0f; *h = 0.0f; return; } - AtlasWordWrapper wrapper(*font, fontscalex, toMeasure.c_str(), bounds.w); + AtlasWordWrapper wrapper(*font, fontscalex, toMeasure.c_str(), bounds.w, wrap); toMeasure = wrapper.Wrapped(); } MeasureTextCount(font_id, toMeasure.c_str(), (int)toMeasure.length(), w, h); @@ -491,8 +492,9 @@ void DrawBuffer::DrawTextRect(FontID font, const char *text, float x, float y, f } std::string toDraw = text; - if (align & FLAG_WRAP_TEXT) { - AtlasWordWrapper wrapper(*atlas->getFont(font), fontscalex, toDraw.c_str(), w); + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { + AtlasWordWrapper wrapper(*atlas->getFont(font), fontscalex, toDraw.c_str(), w, wrap); toDraw = wrapper.Wrapped(); } diff --git a/ext/native/gfx_es2/draw_buffer.h b/ext/native/gfx_es2/draw_buffer.h index 211fc4fb95..a702fd6693 100644 --- a/ext/native/gfx_es2/draw_buffer.h +++ b/ext/native/gfx_es2/draw_buffer.h @@ -39,6 +39,7 @@ enum { FLAG_DYNAMIC_ASCII = 2048, FLAG_NO_PREFIX = 4096, // means to not process ampersands FLAG_WRAP_TEXT = 8192, + FLAG_ELLIPSIZE_TEXT = 16384, }; namespace Draw { diff --git a/ext/native/gfx_es2/draw_text.cpp b/ext/native/gfx_es2/draw_text.cpp index 168f84f151..ce9b51b379 100644 --- a/ext/native/gfx_es2/draw_text.cpp +++ b/ext/native/gfx_es2/draw_text.cpp @@ -24,8 +24,8 @@ float TextDrawerWordWrapper::MeasureWidth(const char *str, size_t bytes) { return w; } -void TextDrawer::WrapString(std::string &out, const char *str, float maxW) { - TextDrawerWordWrapper wrapper(this, str, maxW); +void TextDrawer::WrapString(std::string &out, const char *str, float maxW, int flags) { + TextDrawerWordWrapper wrapper(this, str, maxW, flags); out = wrapper.Wrapped(); } @@ -35,6 +35,8 @@ void TextDrawer::SetFontScale(float xscale, float yscale) { } float TextDrawer::CalculateDPIScale() { + if (ignoreGlobalDpi_) + return dpiScale_; float scale = g_dpi_scale_y; if (scale >= 1.0f) { scale = 1.0f; @@ -42,6 +44,41 @@ float TextDrawer::CalculateDPIScale() { return scale; } +void TextDrawer::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { + float x = bounds.x; + float y = bounds.y; + if (align & ALIGN_HCENTER) { + x = bounds.centerX(); + } else if (align & ALIGN_RIGHT) { + x = bounds.x2(); + } + if (align & ALIGN_VCENTER) { + y = bounds.centerY(); + } else if (align & ALIGN_BOTTOM) { + y = bounds.y2(); + } + + std::string toDraw = str; + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { + bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; + WrapString(toDraw, str, rotated ? bounds.h : bounds.w, wrap); + } + + DrawString(target, toDraw.c_str(), x, y, color, align); +} + +void TextDrawer::DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, const Bounds &bounds, int align) { + std::string toDraw = str; + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { + bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; + WrapString(toDraw, str, rotated ? bounds.h : bounds.w, wrap); + } + + DrawStringBitmap(bitmapData, entry, texFormat, toDraw.c_str(), align); +} + TextDrawer *TextDrawer::Create(Draw::DrawContext *draw) { TextDrawer *drawer = nullptr; #if defined(_WIN32) && !PPSSPP_PLATFORM(UWP) diff --git a/ext/native/gfx_es2/draw_text.h b/ext/native/gfx_es2/draw_text.h index a36db98ad2..f6bf8e3e34 100644 --- a/ext/native/gfx_es2/draw_text.h +++ b/ext/native/gfx_es2/draw_text.h @@ -58,11 +58,17 @@ public: virtual void MeasureString(const char *str, size_t len, float *w, float *h) = 0; virtual void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) = 0; virtual void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) = 0; - virtual void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) = 0; + void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align); + virtual void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) = 0; + void DrawStringBitmapRect(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, const Bounds &bounds, int align); // Use for housekeeping like throwing out old strings. virtual void OncePerFrame() = 0; float CalculateDPIScale(); + void SetForcedDPIScale(float dpi) { + dpiScale_ = dpi; + ignoreGlobalDpi_ = true; + } // Factory function that selects implementation. static TextDrawer *Create(Draw::DrawContext *draw); @@ -72,7 +78,7 @@ protected: Draw::DrawContext *draw_; virtual void ClearCache() = 0; - void WrapString(std::string &out, const char *str, float maxWidth); + void WrapString(std::string &out, const char *str, float maxWidth, int flags); struct CacheKey { bool operator < (const CacheKey &other) const { @@ -86,20 +92,21 @@ protected: uint32_t fontHash; }; - int frameCount_; - float fontScaleX_; - float fontScaleY_; - float dpiScale_; + int frameCount_ = 0; + float fontScaleX_ = 1.0f; + float fontScaleY_ = 1.0f; + float dpiScale_ = 1.0f; + bool ignoreGlobalDpi_ = false; }; class TextDrawerWordWrapper : public WordWrapper { public: - TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW) : WordWrapper(str, maxW), drawer_(drawer) { + TextDrawerWordWrapper(TextDrawer *drawer, const char *str, float maxW, int flags) : WordWrapper(str, maxW, flags), drawer_(drawer) { } protected: float MeasureWidth(const char *str, size_t bytes) override; TextDrawer *drawer_; -}; \ No newline at end of file +}; diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp index b2e15e86e3..f2513b99e3 100644 --- a/ext/native/gfx_es2/draw_text_android.cpp +++ b/ext/native/gfx_es2/draw_text_android.cpp @@ -115,9 +115,10 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou } std::string toMeasure = std::string(str, len); - if (align & FLAG_WRAP_TEXT) { + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w); + WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); } std::vector lines; @@ -154,6 +155,68 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou *h = total_h * dpiScale_; } +void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { + if (!strlen(str)) { + bitmapData.clear(); + return; + } + + double size = 0.0; + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + size = iter->second.size; + } else { + ELOG("Missing font"); + } + + jstring jstr = env_->NewStringUTF(str); + uint32_t textSize = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, size); + int imageWidth = (short)(textSize >> 16); + int imageHeight = (short)(textSize & 0xFFFF); + if (imageWidth <= 0) + imageWidth = 1; + if (imageHeight <= 0) + imageHeight = 1; + + jintArray imageData = (jintArray)env_->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, size); + env_->DeleteLocalRef(jstr); + + entry.texture = nullptr; + entry.bmWidth = imageWidth; + entry.width = imageWidth; + entry.bmHeight = imageHeight; + entry.height = imageHeight; + entry.lastUsedFrame = frameCount_; + + jint *jimage = env_->GetIntArrayElements(imageData, nullptr); + assert(env_->GetArrayLength(imageData) == imageWidth * imageHeight); + if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int x = 0; x < entry.bmWidth; x++) { + for (int y = 0; y < entry.bmHeight; y++) { + uint32_t v = jimage[imageWidth * y + x]; + v = 0xFFF0 | ((v >> 12) & 0xF); // Just grab some bits from the green channel. + bitmapData16[entry.bmWidth * y + x] = (uint16_t)v; + } + } + } else if (texFormat == Draw::DataFormat::R8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight); + for (int x = 0; x < entry.bmWidth; x++) { + for (int y = 0; y < entry.bmHeight; y++) { + uint32_t v = jimage[imageWidth * y + x]; + v = (v >> 12) & 0xF; // Just grab some bits from the green channel. + bitmapData[entry.bmWidth * y + x] = (uint8_t)(v | (v << 4)); + } + } + } else { + ELOG("Bad TextDrawer format"); + assert(false); + } + env_->ReleaseIntArrayElements(imageData, jimage, 0); + env_->DeleteLocalRef(imageData); +} + void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; std::string text(NormalizeString(std::string(str))); @@ -169,66 +232,32 @@ void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; - if (entry->texture) - draw_->BindTexture(0, entry->texture); } else { - double size = 0.0; - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - size = iter->second.size; - } else { - ELOG("Missing font"); - } - - jstring jstr = env_->NewStringUTF(text.c_str()); - uint32_t textSize = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, size); - int imageWidth = (short)(textSize >> 16); - int imageHeight = (short)(textSize & 0xFFFF); - if (imageWidth <= 0) - imageWidth = 1; - if (imageHeight <= 0) - imageHeight = 1; - - jintArray imageData = (jintArray)env_->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, size); - env_->DeleteLocalRef(jstr); + DataFormat texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; entry = new TextStringEntry(); - entry->bmWidth = imageWidth; - entry->width = imageWidth; - entry->bmHeight = imageHeight; - entry->height = imageHeight; - entry->lastUsedFrame = frameCount_; TextureDesc desc{}; + std::vector bitmapData; + DrawStringBitmap(bitmapData, *entry, texFormat, text.c_str(), align); + desc.initData.push_back(&bitmapData[0]); + desc.type = TextureType::LINEAR2D; - desc.format = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; + desc.format = texFormat; desc.width = entry->bmWidth; desc.height = entry->bmHeight; desc.depth = 1; desc.mipLevels = 1; desc.generateMips = false; desc.tag = "TextDrawer"; - - uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; - jint* jimage = env_->GetIntArrayElements(imageData, nullptr); - assert(env_->GetArrayLength(imageData) == imageWidth * imageHeight); - for (int x = 0; x < entry->bmWidth; x++) { - for (int y = 0; y < entry->bmHeight; y++) { - uint32_t v = jimage[imageWidth * y + x]; - v = 0xFFF0 | ((v >> 12) & 0xF); // Just grab some bits from the green channel. - bitmapData[entry->bmWidth * y + x] = (uint16_t)v; - } - } - env_->ReleaseIntArrayElements(imageData, jimage, 0); - env_->DeleteLocalRef(imageData); - desc.initData.push_back((uint8_t *)bitmapData); entry->texture = draw_->CreateTexture(desc); - delete[] bitmapData; cache_[key] = std::unique_ptr(entry); - if (entry->texture) { - draw_->BindTexture(0, entry->texture); - } } + + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } + float w = entry->bmWidth * fontScaleX_ * dpiScale_; float h = entry->bmHeight * fontScaleY_ * dpiScale_; DrawBuffer::DoAlign(align, &x, &y, &w, &h); @@ -247,29 +276,6 @@ void TextDrawerAndroid::ClearCache() { sizeCache_.clear(); } -void TextDrawerAndroid::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { - float x = bounds.x; - float y = bounds.y; - if (align & ALIGN_HCENTER) { - x = bounds.centerX(); - } else if (align & ALIGN_RIGHT) { - x = bounds.x2(); - } - if (align & ALIGN_VCENTER) { - y = bounds.centerY(); - } else if (align & ALIGN_BOTTOM) { - y = bounds.y2(); - } - - std::string toDraw = str; - if (align & FLAG_WRAP_TEXT) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w); - } - - DrawString(target, toDraw.c_str(), x, y, color, align); -} - void TextDrawerAndroid::OncePerFrame() { frameCount_++; // If DPI changed (small-mode, future proper monitor DPI support), drop everything. diff --git a/ext/native/gfx_es2/draw_text_android.h b/ext/native/gfx_es2/draw_text_android.h index 9ed3fdbd22..dff54dade4 100644 --- a/ext/native/gfx_es2/draw_text_android.h +++ b/ext/native/gfx_es2/draw_text_android.h @@ -24,7 +24,7 @@ public: void MeasureString(const char *str, size_t len, float *w, float *h) override; void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) override; + void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; // Use for housekeeping like throwing out old strings. void OncePerFrame() override; diff --git a/ext/native/gfx_es2/draw_text_qt.cpp b/ext/native/gfx_es2/draw_text_qt.cpp index 41d4009d3a..d792f656d8 100644 --- a/ext/native/gfx_es2/draw_text_qt.cpp +++ b/ext/native/gfx_es2/draw_text_qt.cpp @@ -1,3 +1,4 @@ +#include #include "base/display.h" #include "base/logging.h" #include "base/stringutil.h" @@ -33,7 +34,7 @@ uint32_t TextDrawerQt::SetFont(const char *fontName, int size, int flags) { return fontHash; } - QFont* font = fontName ? new QFont(fontName) : new QFont(); + QFont *font = fontName ? new QFont(fontName) : new QFont(); font->setPixelSize(size + 6); fontMap_[fontHash] = font; fontHash_ = fontHash; @@ -41,22 +42,44 @@ uint32_t TextDrawerQt::SetFont(const char *fontName, int size, int flags) { } void TextDrawerQt::SetFont(uint32_t fontHandle) { - + uint32_t fontHash = fontHandle; + auto iter = fontMap_.find(fontHash); + if (iter != fontMap_.end()) { + fontHash_ = fontHandle; + } else { + ELOG("Invalid font handle %08x", fontHandle); + } } void TextDrawerQt::MeasureString(const char *str, size_t len, float *w, float *h) { - QFont* font = fontMap_.find(fontHash_)->second; - QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(str, (int)len)); - *w = (float)size.width() * fontScaleX_; - *h = (float)size.height() * fontScaleY_; + CacheKey key{ std::string(str, len), fontHash_ }; + + TextMeasureEntry *entry; + auto iter = sizeCache_.find(key); + if (iter != sizeCache_.end()) { + entry = iter->second.get(); + } else { + QFont* font = fontMap_.find(fontHash_)->second; + QFontMetrics fm(*font); + QSize size = fm.size(0, QString::fromUtf8(str, (int)len)); + + entry = new TextMeasureEntry(); + entry->width = size.width(); + entry->height = size.height(); + sizeCache_[key] = std::unique_ptr(entry); + } + + entry->lastUsedFrame = frameCount_; + *w = entry->width * fontScaleX_ * dpiScale_; + *h = entry->height * fontScaleY_ * dpiScale_; } void TextDrawerQt::MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align) { std::string toMeasure = std::string(str, len); - if (align & FLAG_WRAP_TEXT) { + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w); + WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); } QFont* font = fontMap_.find(fontHash_)->second; @@ -66,71 +89,102 @@ void TextDrawerQt::MeasureStringRect(const char *str, size_t len, const Bounds & *h = (float)size.height() * fontScaleY_; } +void TextDrawerQt::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { + if (!strlen(str)) { + bitmapData.clear(); + return; + } + + QFont *font = fontMap_.find(fontHash_)->second; + QFontMetrics fm(*font); + QSize size = fm.size(0, QString::fromUtf8(str)); + QImage image((size.width() + 3) & ~3, (size.height() + 3) & ~3, QImage::Format_ARGB32_Premultiplied); + if (image.isNull()) { + bitmapData.clear(); + return; + } + image.fill(0); + + QPainter painter; + painter.begin(&image); + painter.setFont(*font); + painter.setPen(0xFFFFFFFF); + // TODO: Involve ALIGN_HCENTER (bounds etc.) + painter.drawText(image.rect(), Qt::AlignTop | Qt::AlignLeft, QString::fromUtf8(str).replace("&&", "&")); + painter.end(); + + entry.texture = nullptr; + entry.bmWidth = entry.width = image.width(); + entry.bmHeight = entry.height = image.height(); + entry.lastUsedFrame = frameCount_; + + if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int x = 0; x < entry.bmWidth; x++) { + for (int y = 0; y < entry.bmHeight; y++) { + bitmapData16[entry.bmWidth * y + x] = 0xfff0 | (image.pixel(x, y) >> 28); + } + } + } else if (texFormat == Draw::DataFormat::R8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight); + for (int x = 0; x < entry.bmWidth; x++) { + for (int y = 0; y < entry.bmHeight; y++) { + bitmapData[entry.bmWidth * y + x] = image.pixel(x, y) >> 24; + } + } + } else { + ELOG("Bad TextDrawer format"); + assert(false); + } +} + void TextDrawerQt::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; if (!strlen(str)) return; - uint32_t stringHash = hash::Adler32((const uint8_t *)str, strlen(str)); - uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24); - + CacheKey key{ std::string(str), fontHash_ }; target.Flush(true); TextStringEntry *entry; - auto iter = cache_.find(entryHash); + auto iter = cache_.find(key); if (iter != cache_.end()) { entry = iter->second.get(); + entry->lastUsedFrame = frameCount_; } else { - QFont *font = fontMap_.find(fontHash_)->second; - QFontMetrics fm(*font); - QSize size = fm.size(0, QString::fromUtf8(str)); - QImage image((size.width() + 3) & ~3, (size.height() + 3) & ~3, QImage::Format_ARGB32_Premultiplied); - if (image.isNull()) { - return; - } - image.fill(0); - - QPainter painter; - painter.begin(&image); - painter.setFont(*font); - painter.setPen(color); - // TODO: Involve ALIGN_HCENTER (bounds etc.) - painter.drawText(image.rect(), Qt::AlignTop | Qt::AlignLeft, QString::fromUtf8(str).replace("&&", "&")); - painter.end(); + DataFormat texFormat = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; entry = new TextStringEntry(); - entry->bmWidth = entry->width = image.width(); - entry->bmHeight = entry->height = image.height(); TextureDesc desc{}; + std::vector bitmapData; + DrawStringBitmap(bitmapData, *entry, texFormat, str, align); + desc.initData.push_back(&bitmapData[0]); + desc.type = TextureType::LINEAR2D; - desc.format = Draw::DataFormat::R4G4B4A4_UNORM_PACK16; + desc.format = texFormat; desc.width = entry->bmWidth; desc.height = entry->bmHeight; desc.depth = 1; desc.mipLevels = 1; desc.tag = "TextDrawer"; - - uint16_t *bitmapData = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int x = 0; x < entry->bmWidth; x++) { - for (int y = 0; y < entry->bmHeight; y++) { - bitmapData[entry->bmWidth * y + x] = 0xfff0 | image.pixel(x, y) >> 28; - } - } - desc.initData.push_back((uint8_t *)bitmapData); entry->texture = draw_->CreateTexture(desc); - delete[] bitmapData; - cache_[entryHash] = std::unique_ptr(entry); + cache_[key] = std::unique_ptr(entry); } - float w = entry->bmWidth * fontScaleX_; - float h = entry->bmHeight * fontScaleY_; - entry->lastUsedFrame = frameCount_; - draw_->BindTexture(0, entry->texture); + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } + + float w = entry->bmWidth * fontScaleX_ * dpiScale_; + float h = entry->bmHeight * fontScaleY_ * dpiScale_; DrawBuffer::DoAlign(align, &x, &y, &w, &h); - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); - target.Flush(true); + if (entry->texture) { + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, 1.0f, 1.0f, color); + target.Flush(true); + } } void TextDrawerQt::ClearCache() { @@ -148,29 +202,6 @@ void TextDrawerQt::ClearCache() { fontHash_ = 0; } -void TextDrawerQt::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { - float x = bounds.x; - float y = bounds.y; - if (align & ALIGN_HCENTER) { - x = bounds.centerX(); - } else if (align & ALIGN_RIGHT) { - x = bounds.x2(); - } - if (align & ALIGN_VCENTER) { - y = bounds.centerY(); - } else if (align & ALIGN_BOTTOM) { - y = bounds.y2(); - } - - std::string toDraw = str; - if (align & FLAG_WRAP_TEXT) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w); - } - - DrawString(target, toDraw.c_str(), x, y, color, align); -} - void TextDrawerQt::OncePerFrame() { frameCount_++; // If DPI changed (small-mode, future proper monitor DPI support), drop everything. diff --git a/ext/native/gfx_es2/draw_text_qt.h b/ext/native/gfx_es2/draw_text_qt.h index 815a76a13a..c75cd51ca0 100644 --- a/ext/native/gfx_es2/draw_text_qt.h +++ b/ext/native/gfx_es2/draw_text_qt.h @@ -17,7 +17,7 @@ public: void MeasureString(const char *str, size_t len, float *w, float *h) override; void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) override; + void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; // Use for housekeeping like throwing out old strings. void OncePerFrame() override; @@ -27,9 +27,8 @@ protected: uint32_t fontHash_; std::map fontMap_; - // The key is the CityHash of the string xor the fontHash_. - std::map> cache_; - std::map> sizeCache_; + std::map> cache_; + std::map> sizeCache_; }; -#endif \ No newline at end of file +#endif diff --git a/ext/native/gfx_es2/draw_text_win.cpp b/ext/native/gfx_es2/draw_text_win.cpp index f6c1113d5f..2570236feb 100644 --- a/ext/native/gfx_es2/draw_text_win.cpp +++ b/ext/native/gfx_es2/draw_text_win.cpp @@ -1,3 +1,4 @@ +#include #include "base/display.h" #include "base/logging.h" #include "base/stringutil.h" @@ -153,11 +154,15 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound } std::string toMeasure = std::string(str, len); - if (align & FLAG_WRAP_TEXT) { + int wrap = align & (FLAG_WRAP_TEXT | FLAG_ELLIPSIZE_TEXT); + if (wrap) { bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w); + WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap); } + TEXTMETRIC metrics{}; + GetTextMetrics(ctx_->hDC, &metrics); + std::vector lines; SplitString(toMeasure, '\n', lines); float total_w = 0.0f; @@ -184,19 +189,114 @@ void TextDrawerWin32::MeasureStringRect(const char *str, size_t len, const Bound if (total_w < entry->width * fontScaleX_) { total_w = entry->width * fontScaleX_; } - total_h += entry->height * fontScaleY_; + int h = i == lines.size() - 1 ? entry->height : metrics.tmHeight + metrics.tmExternalLeading; + total_h += h * fontScaleY_; } + *w = total_w * dpiScale_; *h = total_h * dpiScale_; } +void TextDrawerWin32::DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align) { + if (!strlen(str)) { + bitmapData.clear(); + return; + } + + std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); + SIZE size; + + auto iter = fontMap_.find(fontHash_); + if (iter != fontMap_.end()) { + SelectObject(ctx_->hDC, iter->second->hFont); + } + // Set text properties + SetTextColor(ctx_->hDC, 0xFFFFFF); + SetBkColor(ctx_->hDC, 0); + SetTextAlign(ctx_->hDC, TA_TOP); + + // This matters for multi-line text - DT_CENTER is horizontal only. + UINT dtAlign = (align & ALIGN_HCENTER) == 0 ? DT_LEFT : DT_CENTER; + + RECT textRect = { 0 }; + DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_HIDEPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); + size.cx = textRect.right; + size.cy = textRect.bottom; + + if (size.cx > MAX_TEXT_WIDTH) + size.cx = MAX_TEXT_WIDTH; + if (size.cy > MAX_TEXT_HEIGHT) + size.cy = MAX_TEXT_HEIGHT; + // Prevent zero-sized textures, which can occur. Not worth to avoid + // creating the texture altogether in this case. One example is a string + // containing only '\r\n', see issue #10764. + if (size.cx == 0) + size.cx = 1; + if (size.cy == 0) + size.cy = 1; + + entry.texture = nullptr; + entry.width = size.cx; + entry.height = size.cy; + entry.bmWidth = (size.cx + 3) & ~3; + entry.bmHeight = (size.cy + 3) & ~3; + entry.lastUsedFrame = frameCount_; + + RECT rc = { 0 }; + rc.right = entry.bmWidth; + rc.bottom = entry.bmHeight; + FillRect(ctx_->hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); + DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX | DT_TOP | dtAlign, 0); + + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format + // because we need white. Well, we could using swizzle, but not all our backends support that. + if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint32_t)); + uint32_t *bitmapData32 = (uint32_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)(ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff); + bitmapData32[entry.bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; + } + } + } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha) | 0xfff0; + } + } + } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { + bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t)); + uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0]; + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); + bitmapData16[entry.bmWidth * y + x] = (bAlpha << 12) | 0x0fff; + } + } + } else if (texFormat == Draw::DataFormat::R8_UNORM) { + bitmapData.resize(entry.bmWidth * entry.bmHeight); + for (int y = 0; y < entry.bmHeight; y++) { + for (int x = 0; x < entry.bmWidth; x++) { + uint8_t bAlpha = ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff; + bitmapData[entry.bmWidth * y + x] = bAlpha; + } + } + } else { + ELOG("Bad TextDrawer format"); + assert(false); + } +} + void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; if (!strlen(str)) return; CacheKey key{ std::string(str), fontHash_ }; - target.Flush(true); TextStringEntry *entry; @@ -206,52 +306,6 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f entry = iter->second.get(); entry->lastUsedFrame = frameCount_; } else { - // Render the string to our bitmap and save to a GL texture. - std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); - SIZE size; - - auto iter = fontMap_.find(fontHash_); - if (iter != fontMap_.end()) { - SelectObject(ctx_->hDC, iter->second->hFont); - } - // Set text properties - SetTextColor(ctx_->hDC, 0xFFFFFF); - SetBkColor(ctx_->hDC, 0); - SetTextAlign(ctx_->hDC, TA_TOP); - - // This matters for multi-line text - DT_CENTER is horizontal only. - UINT dtAlign = (align & ALIGN_HCENTER) == 0 ? DT_LEFT : DT_CENTER; - - RECT textRect = { 0 }; - DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_HIDEPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); - size.cx = textRect.right; - size.cy = textRect.bottom; - - if (size.cx > MAX_TEXT_WIDTH) - size.cx = MAX_TEXT_WIDTH; - if (size.cy > MAX_TEXT_HEIGHT) - size.cy = MAX_TEXT_HEIGHT; - // Prevent zero-sized textures, which can occur. Not worth to avoid - // creating the texture altogether in this case. One example is a string - // containing only '\r\n', see issue #10764. - if (size.cx == 0) - size.cx = 1; - if (size.cy == 0) - size.cy = 1; - - entry = new TextStringEntry(); - entry->width = size.cx; - entry->height = size.cy; - entry->bmWidth = (size.cx + 3) & ~3; - entry->bmHeight = (size.cy + 3) & ~3; - entry->lastUsedFrame = frameCount_; - - RECT rc = { 0 }; - rc.right = entry->bmWidth; - rc.bottom = entry->bmHeight; - FillRect(ctx_->hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); - DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX | DT_TOP | dtAlign, 0); - DataFormat texFormat; // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) @@ -263,39 +317,14 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f else texFormat = Draw::DataFormat::R8G8B8A8_UNORM; + entry = new TextStringEntry(); + // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format // because we need white. Well, we could using swizzle, but not all our backends support that. TextureDesc desc{}; - uint32_t *bitmapData32 = nullptr; - uint16_t *bitmapData16 = nullptr; - if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { - bitmapData32 = new uint32_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)(ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff); - bitmapData32[entry->bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; - } - } - desc.initData.push_back((uint8_t *)bitmapData32); - } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) { - bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); - bitmapData16[entry->bmWidth * y + x] = (bAlpha) | 0xfff0; - } - } - desc.initData.push_back((uint8_t *)bitmapData16); - } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) { - bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; - for (int y = 0; y < entry->bmHeight; y++) { - for (int x = 0; x < entry->bmWidth; x++) { - uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); - bitmapData16[entry->bmWidth * y + x] = (bAlpha << 12) | 0x0fff; - } - } - desc.initData.push_back((uint8_t *)bitmapData16); - } + std::vector bitmapData; + DrawStringBitmap(bitmapData, *entry, texFormat, str, align); + desc.initData.push_back(&bitmapData[0]); desc.type = TextureType::LINEAR2D; desc.format = texFormat; @@ -305,14 +334,12 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f desc.mipLevels = 1; desc.tag = "TextDrawer"; entry->texture = draw_->CreateTexture(desc); - if (bitmapData16) - delete[] bitmapData16; - if (bitmapData32) - delete[] bitmapData32; cache_[key] = std::unique_ptr(entry); } - draw_->BindTexture(0, entry->texture); + if (entry->texture) { + draw_->BindTexture(0, entry->texture); + } // Okay, the texture is bound, let's draw. float w = entry->width * fontScaleX_ * dpiScale_; @@ -320,8 +347,10 @@ void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, f float u = entry->width / (float)entry->bmWidth; float v = entry->height / (float)entry->bmHeight; DrawBuffer::DoAlign(align, &x, &y, &w, &h); - target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); - target.Flush(true); + if (entry->texture) { + target.DrawTexRect(x, y, x + w, y + h, 0.0f, 0.0f, u, v, color); + target.Flush(true); + } } void TextDrawerWin32::RecreateFonts() { @@ -340,29 +369,6 @@ void TextDrawerWin32::ClearCache() { sizeCache_.clear(); } -void TextDrawerWin32::DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) { - float x = bounds.x; - float y = bounds.y; - if (align & ALIGN_HCENTER) { - x = bounds.centerX(); - } else if (align & ALIGN_RIGHT) { - x = bounds.x2(); - } - if (align & ALIGN_VCENTER) { - y = bounds.centerY(); - } else if (align & ALIGN_BOTTOM) { - y = bounds.y2(); - } - - std::string toDraw = str; - if (align & FLAG_WRAP_TEXT) { - bool rotated = (align & (ROTATE_90DEG_LEFT | ROTATE_90DEG_RIGHT)) != 0; - WrapString(toDraw, str, rotated ? bounds.h : bounds.w); - } - - DrawString(target, toDraw.c_str(), x, y, color, align); -} - void TextDrawerWin32::OncePerFrame() { frameCount_++; // If DPI changed (small-mode, future proper monitor DPI support), drop everything. diff --git a/ext/native/gfx_es2/draw_text_win.h b/ext/native/gfx_es2/draw_text_win.h index ec76d3ef2b..41489eefbb 100644 --- a/ext/native/gfx_es2/draw_text_win.h +++ b/ext/native/gfx_es2/draw_text_win.h @@ -24,7 +24,7 @@ public: void MeasureString(const char *str, size_t len, float *w, float *h) override; void MeasureStringRect(const char *str, size_t len, const Bounds &bounds, float *w, float *h, int align = ALIGN_TOPLEFT) override; void DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align = ALIGN_TOPLEFT) override; - void DrawStringRect(DrawBuffer &target, const char *str, const Bounds &bounds, uint32_t color, int align) override; + void DrawStringBitmap(std::vector &bitmapData, TextStringEntry &entry, Draw::DataFormat texFormat, const char *str, int align = ALIGN_TOPLEFT) override; // Use for housekeeping like throwing out old strings. void OncePerFrame() override; @@ -40,4 +40,4 @@ protected: std::map> sizeCache_; }; -#endif \ No newline at end of file +#endif diff --git a/ext/native/i18n/i18n.cpp b/ext/native/i18n/i18n.cpp index 958f162cae..eb823dc2b9 100644 --- a/ext/native/i18n/i18n.cpp +++ b/ext/native/i18n/i18n.cpp @@ -14,6 +14,7 @@ std::string I18NRepo::LanguageID() { } void I18NRepo::Clear() { + std::lock_guard guard(catsLock_); for (auto iter = cats_.begin(); iter != cats_.end(); ++iter) { iter->second.reset(); } @@ -33,6 +34,7 @@ const char *I18NCategory::T(const char *key, const char *def) { // ILOG("translation key found in %s: %s", name_.c_str(), key); return iter->second.text.c_str(); } else { + std::lock_guard guard(missedKeyLock_); if (def) missedKeyLog_[key] = def; else @@ -53,6 +55,7 @@ void I18NCategory::SetMap(const std::map &m) { } std::shared_ptr I18NRepo::GetCategory(const char *category) { + std::lock_guard guard(catsLock_); auto iter = cats_.find(category); if (iter != cats_.end()) { return iter->second; @@ -94,6 +97,7 @@ bool I18NRepo::LoadIni(const std::string &languageID, const std::string &overrid const std::vector §ions = ini.Sections(); + std::lock_guard guard(catsLock_); for (auto iter = sections.begin(); iter != sections.end(); ++iter) { if (iter->name() != "") { cats_[iter->name()].reset(LoadSection(&(*iter), iter->name().c_str())); @@ -116,6 +120,7 @@ I18NCategory *I18NRepo::LoadSection(const IniFile::Section *section, const char void I18NRepo::SaveIni(const std::string &languageID) { IniFile ini; ini.Load(GetIniPath(languageID)); + std::lock_guard guard(catsLock_); for (auto iter = cats_.begin(); iter != cats_.end(); ++iter) { std::string categoryName = iter->first; IniFile::Section *section = ini.GetOrCreateSection(categoryName.c_str()); diff --git a/ext/native/i18n/i18n.h b/ext/native/i18n/i18n.h index 5a527d6646..bc4e3ca4bf 100644 --- a/ext/native/i18n/i18n.h +++ b/ext/native/i18n/i18n.h @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -44,20 +45,22 @@ public: } const std::map &Missed() const { + std::lock_guard guard(missedKeyLock_); return missedKeyLog_; } - void SetMap(const std::map &m); const std::map &GetMap() { return map_; } void ClearMissed() { missedKeyLog_.clear(); } const char *GetName() const { return name_.c_str(); } private: I18NCategory(I18NRepo *repo, const char *name) : name_(name) {} + void SetMap(const std::map &m); std::string name_; std::map map_; + mutable std::mutex missedKeyLock_; std::map missedKeyLog_; // Noone else can create these. @@ -79,6 +82,7 @@ public: std::shared_ptr GetCategory(const char *categoryName); bool HasCategory(const char *categoryName) const { + std::lock_guard guard(catsLock_); return cats_.find(categoryName) != cats_.end(); } const char *T(const char *category, const char *key, const char *def = 0); @@ -89,6 +93,7 @@ private: I18NCategory *LoadSection(const IniFile::Section *section, const char *name); void SaveSection(IniFile &ini, IniFile::Section *section, std::shared_ptr cat); + mutable std::mutex catsLock_; std::map> cats_; std::string languageID_; diff --git a/ext/native/json/json_reader.cpp b/ext/native/json/json_reader.cpp index eaf9d0ae08..1663a915ef 100644 --- a/ext/native/json/json_reader.cpp +++ b/ext/native/json/json_reader.cpp @@ -24,6 +24,7 @@ int JsonGet::numChildren() const { int count = 0; if (value_.getTag() == JSON_OBJECT || value_.getTag() == JSON_ARRAY) { for (auto it : value_) { + (void)it; count++; } } diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp index e42101798b..2ea228fcd3 100644 --- a/ext/native/thin3d/GLQueueRunner.cpp +++ b/ext/native/thin3d/GLQueueRunner.cpp @@ -569,9 +569,13 @@ void GLQueueRunner::RunSteps(const std::vector &steps, bool skipGLCal } } break; + default: + break; } } break; + default: + break; } delete steps[i]; } diff --git a/ext/native/thread/executor.cpp b/ext/native/thread/executor.cpp index e20fac09b1..0ae2b41b64 100644 --- a/ext/native/thread/executor.cpp +++ b/ext/native/thread/executor.cpp @@ -10,13 +10,14 @@ void SameThreadExecutor::Run(std::function func) { } void NewThreadExecutor::Run(std::function func) { - thread_ = std::thread(func); + threads_.push_back(std::thread(func)); } NewThreadExecutor::~NewThreadExecutor() { // If Run was ever called... - if (thread_.joinable()) - thread_.join(); + for (auto &thread : threads_) + thread.join(); + threads_.clear(); } } // namespace threading diff --git a/ext/native/thread/executor.h b/ext/native/thread/executor.h index 6a3122e920..44924952e6 100644 --- a/ext/native/thread/executor.h +++ b/ext/native/thread/executor.h @@ -2,6 +2,7 @@ #include #include +#include namespace threading { @@ -23,7 +24,7 @@ public: void Run(std::function func) override; private: - std::thread thread_; + std::vector threads_; }; } // namespace threading diff --git a/ext/native/util/text/wrap_text.cpp b/ext/native/util/text/wrap_text.cpp index edf3354673..c052056034 100644 --- a/ext/native/util/text/wrap_text.cpp +++ b/ext/native/util/text/wrap_text.cpp @@ -1,4 +1,5 @@ #include +#include "gfx_es2/draw_buffer.h" #include "util/text/utf8.h" #include "util/text/wrap_text.h" @@ -75,39 +76,58 @@ std::string WordWrapper::Wrapped() { } bool WordWrapper::WrapBeforeWord() { - if (x_ + wordWidth_ > maxW_ && out_.size() > 0) { - if (IsShy(out_[out_.size() - 1])) { - // Soft hyphen, replace it with a real hyphen since we wrapped at it. - // TODO: There's an edge case here where the hyphen might not fit. - out_[out_.size() - 1] = '-'; + if (flags_ & FLAG_WRAP_TEXT) { + if (x_ + wordWidth_ > maxW_ && !out_.empty()) { + if (IsShy(out_[out_.size() - 1])) { + // Soft hyphen, replace it with a real hyphen since we wrapped at it. + // TODO: There's an edge case here where the hyphen might not fit. + out_[out_.size() - 1] = '-'; + } + out_ += "\n"; + lastLineStart_ = out_.size(); + x_ = 0.0f; + forceEarlyWrap_ = false; + return true; + } + } + if (flags_ & FLAG_ELLIPSIZE_TEXT) { + if (x_ + wordWidth_ > maxW_) { + if (!out_.empty() && IsSpace(out_[out_.size() - 1])) { + out_[out_.size() - 1] = '.'; + out_ += ".."; + } else { + out_ += "..."; + } + x_ = maxW_; } - out_ += "\n"; - lastLineStart_ = out_.size(); - x_ = 0.0f; - forceEarlyWrap_ = false; - return true; } return false; } void WordWrapper::AppendWord(int endIndex, bool addNewline) { - int nextWordIndex = lastIndex_; + int lastWordStartIndex = lastIndex_; if (WrapBeforeWord()) { // Advance to the first non-whitespace UTF-8 character in the following word (if any) to prevent starting the new line with a whitespace - UTF8 utf8Word(str_, nextWordIndex); - while (nextWordIndex < endIndex) { + UTF8 utf8Word(str_, lastWordStartIndex); + while (lastWordStartIndex < endIndex) { const uint32_t c = utf8Word.next(); if (!IsSpace(c)) { break; } - nextWordIndex = utf8Word.byteIndex(); + lastWordStartIndex = utf8Word.byteIndex(); } } + // This will include the newline. - out_.append(str_ + nextWordIndex, str_ + endIndex); - if (addNewline) { + if (x_ < maxW_) { + out_.append(str_ + lastWordStartIndex, str_ + endIndex); + } else { + scanForNewline_ = true; + } + if (addNewline && (flags_ & FLAG_WRAP_TEXT)) { out_ += "\n"; lastLineStart_ = out_.size(); + scanForNewline_ = false; } else { // We may have appended a newline - check. size_t pos = out_.substr(lastLineStart_).find_last_of("\n"); @@ -129,6 +149,10 @@ void WordWrapper::Wrap() { return; } + if (flags_ & FLAG_ELLIPSIZE_TEXT) { + ellipsisWidth_ = MeasureWidth("...", 3); + } + for (UTF8 utf(str_); !utf.end(); ) { int beforeIndex = utf.byteIndex(); uint32_t c = utf.next(); @@ -142,6 +166,13 @@ void WordWrapper::Wrap() { wordWidth_ = 0.0f; // We wrapped once, so stop forcing. forceEarlyWrap_ = false; + scanForNewline_ = false; + continue; + } + + if (scanForNewline_) { + // We're discarding the rest of the characters until a newline (no wrapping.) + lastIndex_ = afterIndex; continue; } @@ -175,13 +206,33 @@ void WordWrapper::Wrap() { } // Now, add the word so far (without this latest character) and break. AppendWord(beforeIndex, true); - x_ = 0.0f; + if (lastLineStart_ != out_.size()) { + x_ = MeasureWidth(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_); + } else { + x_ = 0.0f; + } wordWidth_ = 0.0f; forceEarlyWrap_ = false; // The current character will be handled as part of the next word. continue; } + if ((flags_ & FLAG_ELLIPSIZE_TEXT) && wordWidth_ > 0.0f && x_ + newWordWidth + ellipsisWidth_ > maxW_) { + if ((flags_ & FLAG_WRAP_TEXT) == 0) { + // Now, add the word so far (without this latest character) and show the ellipsis. + AppendWord(beforeIndex, true); + if (lastLineStart_ != out_.size()) { + x_ = MeasureWidth(out_.c_str() + lastLineStart_, out_.size() - lastLineStart_); + } else { + x_ = 0.0f; + } + wordWidth_ = 0.0f; + forceEarlyWrap_ = false; + // The current character will be handled as part of the next word. + continue; + } + } + wordWidth_ = newWordWidth; // Is this the end of a word via punctuation / CJK? diff --git a/ext/native/util/text/wrap_text.h b/ext/native/util/text/wrap_text.h index 61049bccef..554210e3cf 100644 --- a/ext/native/util/text/wrap_text.h +++ b/ext/native/util/text/wrap_text.h @@ -4,8 +4,8 @@ class WordWrapper { public: - WordWrapper(const char *str, float maxW) - : str_(str), maxW_(maxW) { + WordWrapper(const char *str, float maxW, int flags) + : str_(str), maxW_(maxW), flags_(flags) { } std::string Wrapped(); @@ -23,7 +23,9 @@ protected: const char *const str_; const float maxW_; + const int flags_; std::string out_; + // Index of last output / start of current word. int lastIndex_ = 0; // Index of last line start. @@ -32,6 +34,10 @@ protected: float x_ = 0.0f; // Most recent width of word since last index. float wordWidth_ = 0.0f; + // Width of "..." when flag is set, zero otherwise. + float ellipsisWidth_ = 0.0f; // Force the next word to cut partially and wrap. bool forceEarlyWrap_ = false; + // Skip all characters until the next newline. + bool scanForNewline_ = false; }; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index c0494eaf70..52b0e20900 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -380,6 +380,8 @@ int main(int argc, const char* argv[]) g_Config.bMemStickInserted = true; g_Config.bFragmentTestCache = true; g_Config.iAudioLatency = 1; + g_Config.bEnableWlan = true; + g_Config.sMACAddress = "12:34:56:78:9A:BC"; #ifdef _WIN32 g_Config.internalDataDirectory = ""; diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 9fe93a89b6..d909df3ada 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -427,6 +427,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/HLE/sceNp.cpp \ $(COREDIR)/HLE/scePauth.cpp \ $(COREDIR)/HLE/sceUsbGps.cpp \ + $(COREDIR)/HW/Camera.cpp \ $(COREDIR)/HW/SimpleAudioDec.cpp \ $(COREDIR)/HW/AsyncIOManager.cpp \ $(COREDIR)/HW/MediaEngine.cpp \ @@ -472,7 +473,6 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \ $(COREDIR)/System.cpp \ $(COREDIR)/Util/BlockAllocator.cpp \ $(COREDIR)/Util/PPGeDraw.cpp \ - $(COREDIR)/Util/ppge_atlas.cpp \ $(COREDIR)/Util/AudioFormat.cpp \ $(EXTDIR)/disarm.cpp \ $(CORE_DIR)/UI/TextureUtil.cpp