diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 49d34581f3..b8fddd1a76 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -121,22 +121,22 @@ jobs: extra: android cc: clang cxx: clang++ - args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a + args: cd android && ./ab.sh -j2 APP_ABI=arm64-v8a UNITTEST=1 HEADLESS=1 - os: ubuntu-latest extra: android cc: clang cxx: clang++ - args: cd android && ./ab.sh -j2 APP_ABI=armeabi-v7a + args: cd android && ./ab.sh -j2 APP_ABI=armeabi-v7a UNITTEST=1 HEADLESS=1 - os: ubuntu-latest extra: android cc: clang cxx: clang++ - args: cd android && ./ab.sh -j2 APP_ABI=x86 + args: cd android && ./ab.sh -j2 APP_ABI=x86 UNITTEST=1 HEADLESS=1 - os: ubuntu-latest extra: android cc: clang cxx: clang++ - args: cd android && ./ab.sh -j2 APP_ABI=x86_64 + args: cd android && ./ab.sh -j2 APP_ABI=x86_64 UNITTEST=1 HEADLESS=1 - os: ubuntu-latest extra: android cc: clang @@ -215,6 +215,7 @@ jobs: cp -r build*/PPSSPPSDL.app ppsspp/ elif [ -e build*/PPSSPPSDL ]; then cp build*/PPSSPPSDL ppsspp/ + cp -r assets ppsspp/assets fi if [ -e build*/$BUILD_CONFIGURATION/PPSSPPHeadless ]; then cp build*/$BUILD_CONFIGURATION/PPSSPPHeadless ppsspp/ diff --git a/Common/Net/HTTPClient.cpp b/Common/Net/HTTPClient.cpp index 7193582fa5..1c13d95f90 100644 --- a/Common/Net/HTTPClient.cpp +++ b/Common/Net/HTTPClient.cpp @@ -4,13 +4,18 @@ #include "Common/StringUtils.h" #ifndef _WIN32 +#include #include #include #include #include +#include #include #define closesocket close #else +#ifndef NOMINMAX +#define NOMINMAX +#endif #include #include #include diff --git a/Common/Net/HTTPClient.h b/Common/Net/HTTPClient.h index 731ff75dd5..d76e57d1b9 100644 --- a/Common/Net/HTTPClient.h +++ b/Common/Net/HTTPClient.h @@ -7,19 +7,6 @@ #include "Common/Net/Resolve.h" -#ifdef _WIN32 -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#include -#else -#include -#include -#include -#include -#endif - #include "Common/Buffer.h" namespace net { diff --git a/Common/Net/URL.cpp b/Common/Net/URL.cpp index 681fc45ff2..1183022ed7 100644 --- a/Common/Net/URL.cpp +++ b/Common/Net/URL.cpp @@ -126,7 +126,7 @@ std::string UriDecode(const std::string & sSrc) const unsigned char * const SRC_END = pSrc + SRC_LEN; const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' - char * const pStart = new char[SRC_LEN]; + char * const pStart = new char[SRC_LEN]; // Output will be shorter. char * pEnd = pStart; while (pSrc < SRC_LAST_DEC) diff --git a/Common/System/System.h b/Common/System/System.h index 7bfe71828f..a713616a10 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -59,6 +59,7 @@ enum SystemProperty { // Need hacky solutions to get at this. SYSPROP_HAS_ADDITIONAL_STORAGE, SYSPROP_ADDITIONAL_STORAGE_DIRS, + SYSPROP_TEMP_DIRS, SYSPROP_HAS_FILE_BROWSER, SYSPROP_HAS_FOLDER_BROWSER, diff --git a/Common/UI/View.h b/Common/UI/View.h index 97c5c10513..4f779fa1f4 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -527,6 +527,9 @@ public: paddingW_ = w; paddingH_ = h; } + void SetImageID(ImageID imageID) { + imageID_ = imageID; + } // Needed an extra small button... void SetScale(float f) { diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index d68abaa9b5..8361adbc3e 100755 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -149,11 +149,11 @@ int PSPMsgDialog::Init(unsigned int paramAddr) { void PSPMsgDialog::FormatErrorCode(uint32_t code) { - auto di = GetI18NCategory("Dialog"); + auto err = GetI18NCategory("Dialog"); switch (code) { case SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN: - snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataDataBroken", "Save data was corrupt."), code); + snprintf(msgText, 512, "%s (%08x)", err->T("MsgErrorSavedataDataBroken", "Save data was corrupt."), code); break; case SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_MS: @@ -161,23 +161,23 @@ void PSPMsgDialog::FormatErrorCode(uint32_t code) { case SCE_UTILITY_SAVEDATA_ERROR_SAVE_NO_MS: case SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_MS: case SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_MS: - snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataNoMS", "Memory stick not inserted."), code); + snprintf(msgText, 512, "%s (%08x)", err->T("MsgErrorSavedataNoMS", "Memory stick not inserted."), code); break; case SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA: case SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA: case SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA: case SCE_UTILITY_SAVEDATA_ERROR_SIZES_NO_DATA: - snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataNoData", "Warning: no save data was found."), code); + snprintf(msgText, 512, "%s (%08x)", err->T("MsgErrorSavedataNoData", "Warning: no save data was found."), code); break; case SCE_UTILITY_SAVEDATA_ERROR_RW_MEMSTICK_FULL: case SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE: - snprintf(msgText, 512, "%s (%08x)", di->T("MsgErrorSavedataMSFull", "Memory stick full. Check your storage space."), code); + snprintf(msgText, 512, "%s (%08x)", err->T("MsgErrorSavedataMSFull", "Memory stick full. Check your storage space."), code); break; default: - snprintf(msgText, 512, "%s %08x", di->T("MsgErrorCode", "Error code:"), code); + snprintf(msgText, 512, "%s %08x", err->T("MsgErrorCode", "Error code:"), code); } } diff --git a/Core/Dialog/PSPNetconfDialog.cpp b/Core/Dialog/PSPNetconfDialog.cpp index 4e3fe9ae1c..b7126d3348 100644 --- a/Core/Dialog/PSPNetconfDialog.cpp +++ b/Core/Dialog/PSPNetconfDialog.cpp @@ -347,7 +347,7 @@ int PSPNetconfDialog::Update(int animSpeed) { if (g_Config.iWlanAdhocChannel == PSP_SYSTEMPARAM_ADHOC_CHANNEL_AUTOMATIC) channel = "Automatic"; - DisplayMessage(di->T("ConnectingPleaseWait", "Connecting.\nPlease wait..."), di->T("Channel") + std::string(" ") + di->T(channel)); + DisplayMessage(di->T("ConnectingPleaseWait", "Connecting.\nPlease wait..."), di->T("Channel:") + std::string(" ") + di->T(channel)); // Only Join mode is showing Cancel button on KHBBS and the button will fade out before the dialog is fading out, probably because it's already connected thus can't be canceled anymore if (request.netAction == NETCONF_JOIN_ADHOC) diff --git a/Core/HLE/proAdhoc.cpp b/Core/HLE/proAdhoc.cpp index 9e13eecf23..5a0ec169a7 100644 --- a/Core/HLE/proAdhoc.cpp +++ b/Core/HLE/proAdhoc.cpp @@ -1203,18 +1203,24 @@ void notifyAdhocctlHandlers(u32 flag, u32 error) { // Note: Must not lock peerlock within this function to prevent race-condition with other thread whos owning peerlock and trying to lock context->eventlock owned by this thread void notifyMatchingHandler(SceNetAdhocMatchingContext * context, ThreadMessage * msg, void * opt, u32_le &bufAddr, u32_le &bufLen, u32_le * args) { // Don't share buffer address space with other mipscall in the queue since mipscalls aren't immediately executed - MatchingArgs argsNew; + MatchingArgs argsNew = { 0 }; u32_le dataBufLen = msg->optlen + 8; //max(bufLen, msg->optlen + 8); u32_le dataBufAddr = userMemory.Alloc(dataBufLen); // We will free this memory after returning from mipscall uint8_t * dataPtr = Memory::GetPointer(dataBufAddr); - memcpy(dataPtr, &msg->mac, sizeof(msg->mac)); - if (msg->optlen > 0) - memcpy(dataPtr + 8, opt, msg->optlen); - argsNew.data[0] = context->id; - argsNew.data[1] = msg->opcode; - argsNew.data[2] = dataBufAddr; - argsNew.data[3] = msg->optlen; - argsNew.data[4] = dataBufAddr + 8; // OptData Addr + if (dataPtr) { + memcpy(dataPtr, &msg->mac, sizeof(msg->mac)); + if (msg->optlen > 0) + memcpy(dataPtr + 8, opt, msg->optlen); + + argsNew.data[1] = msg->opcode; + argsNew.data[2] = dataBufAddr; + argsNew.data[3] = msg->optlen; + argsNew.data[4] = dataBufAddr + 8; // OptData Addr + } + else { + argsNew.data[1] = PSP_ADHOC_MATCHING_EVENT_ERROR; // not sure where to put the error code for EVENT_ERROR tho + } + argsNew.data[0] = context->id; argsNew.data[5] = context->handler.entryPoint; //not part of callback argument, just borrowing a space to store callback address so i don't need to search the context first later // ScheduleEvent_Threadsafe_Immediate seems to get mixed up with interrupt (returning from mipscall inside an interrupt) and getting invalid address before returning from interrupt diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index 72ef4f0dc9..ebf72e35df 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -103,6 +103,7 @@ u32_le matchingThreadCode[3]; int matchingEventThread(int matchingId); int matchingInputThread(int matchingId); +void sendBulkDataPacket(SceNetAdhocMatchingContext* context, SceNetEtherAddr* mac, int datalen, void* data); int AcceptPtpSocket(int ptpId, int newsocket, sockaddr_in& peeraddr, SceNetEtherAddr* addr, u16_le* port); int PollAdhocSocket(SceNetAdhocPollSd* sds, int count, int timeout, int nonblock); int FlushPtpSocket(int socketId); @@ -5279,7 +5280,7 @@ int sceNetAdhocMatchingSendData(int matchingId, const char *mac, int dataLen, u3 peer->sending = 1; // Send Data to Peer - sendBulkData(context, peer, dataLen, data); + sendBulkDataPacket(context, &peer->mac, dataLen, data); // Return Success return 0; @@ -5518,7 +5519,7 @@ void __NetMatchingCallbacks() //(int matchingId) after->SetData(args[0], args[1], args[2]); hleEnqueueCall(args[5], 5, args, after); matchingEvents.pop_front(); - delayus = (adhocMatchingEventDelay + adhocExtraDelay); // Added an extra delay to prevent I/O Timing method from causing disconnection + delayus = adhocMatchingEventDelay; // Add extra delay to prevent I/O Timing method from causing disconnection, but delaying too long may cause matchingEvents to pile up } // Must be delayed long enough whenever there is a pending callback. Should it be 10-100ms for Matching Events? or Not Less than the delays on sceNetAdhocMatching HLE? diff --git a/Core/MIPS/ARM/ArmCompALU.cpp b/Core/MIPS/ARM/ArmCompALU.cpp index 471b3e0dc2..6088454fad 100644 --- a/Core/MIPS/ARM/ArmCompALU.cpp +++ b/Core/MIPS/ARM/ArmCompALU.cpp @@ -44,7 +44,7 @@ using namespace MIPSAnalyst; // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } diff --git a/Core/MIPS/ARM/ArmCompFPU.cpp b/Core/MIPS/ARM/ArmCompFPU.cpp index cc49148d61..f2cc37e3b1 100644 --- a/Core/MIPS/ARM/ArmCompFPU.cpp +++ b/Core/MIPS/ARM/ArmCompFPU.cpp @@ -43,7 +43,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index 96c8f7133b..667c0ece44 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -41,7 +41,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } diff --git a/Core/MIPS/IR/IRCompALU.cpp b/Core/MIPS/IR/IRCompALU.cpp index 2622ea1b9d..72f9a1ff42 100644 --- a/Core/MIPS/IR/IRCompALU.cpp +++ b/Core/MIPS/IR/IRCompALU.cpp @@ -37,7 +37,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } diff --git a/Core/MIPS/IR/IRCompFPU.cpp b/Core/MIPS/IR/IRCompFPU.cpp index 0392fb2795..c0aac3f3f1 100644 --- a/Core/MIPS/IR/IRCompFPU.cpp +++ b/Core/MIPS/IR/IRCompFPU.cpp @@ -48,7 +48,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } diff --git a/Core/MIPS/IR/IRCompLoadStore.cpp b/Core/MIPS/IR/IRCompLoadStore.cpp index ec2fc33aaf..cb1892d3d2 100644 --- a/Core/MIPS/IR/IRCompLoadStore.cpp +++ b/Core/MIPS/IR/IRCompLoadStore.cpp @@ -38,7 +38,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 054594f4c5..5226e57fd1 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -36,7 +36,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (opts.disableFlags & (uint32_t)JitDisable::flag) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } #define INVALIDOP { Comp_Generic(op); return; } @@ -993,7 +993,7 @@ namespace MIPSComp { ir.Write(IROp::AndConst, IRTEMP_0, rt, ir.AddConstant(mask)); ir.Write(IROp::SetCtrlVFPUReg, imm - 128, IRTEMP_0); } else { - ir.Write(IROp::SetCtrlVFPU, imm - 128, rt); + ir.Write(IROp::SetCtrlVFPUReg, imm - 128, rt); } } diff --git a/Core/MIPS/IR/IRInst.cpp b/Core/MIPS/IR/IRInst.cpp index 300487e0ba..b8339896e7 100644 --- a/Core/MIPS/IR/IRInst.cpp +++ b/Core/MIPS/IR/IRInst.cpp @@ -114,11 +114,11 @@ static const IRMeta irMeta[] = { { IROp::FpCondToReg, "FpCondToReg", "G" }, { IROp::VfpuCtrlToReg, "VfpuCtrlToReg", "GI" }, { IROp::SetCtrlVFPU, "SetCtrlVFPU", "TC" }, - { IROp::SetCtrlVFPUReg, "SetCtrlVFPUReg", "TC" }, + { IROp::SetCtrlVFPUReg, "SetCtrlVFPUReg", "TG" }, { IROp::SetCtrlVFPUFReg, "SetCtrlVFPUFReg", "TF" }, { IROp::FCmovVfpuCC, "FCmovVfpuCC", "FFI" }, { IROp::FCmpVfpuBit, "FCmpVfpuBit", "IFF" }, - { IROp::FCmpVfpuAggregate, "FCmpVfpuAggregate", "" }, + { IROp::FCmpVfpuAggregate, "FCmpVfpuAggregate", "I" }, { IROp::Vec4Init, "Vec4Init", "Vv" }, { IROp::Vec4Shuffle, "Vec4Shuffle", "VVs" }, { IROp::Vec4Mov, "Vec4Mov", "VV" }, diff --git a/Core/MIPS/IR/IRPassSimplify.cpp b/Core/MIPS/IR/IRPassSimplify.cpp index d7f8195c98..ee65084a60 100644 --- a/Core/MIPS/IR/IRPassSimplify.cpp +++ b/Core/MIPS/IR/IRPassSimplify.cpp @@ -8,6 +8,10 @@ #include "Core/MIPS/IR/IRPassSimplify.h" #include "Core/MIPS/IR/IRRegCache.h" +// #define CONDITIONAL_DISABLE { for (IRInst inst : in.GetInstructions()) { out.Write(inst); } return false; } +#define CONDITIONAL_DISABLE +#define DISABLE { for (IRInst inst : in.GetInstructions()) { out.Write(inst); } return false; } + u32 Evaluate(u32 a, u32 b, IROp op) { switch (op) { case IROp::Add: case IROp::AddConst: return a + b; @@ -101,8 +105,11 @@ bool IRApplyPasses(const IRPassFunc *passes, size_t c, const IRWriter &in, IRWri } bool OptimizeFPMoves(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + bool logBlocks = false; IRInst prev{ IROp::Nop }; + for (int i = 0; i < (int)in.GetInstructions().size(); i++) { IRInst inst = in.GetInstructions()[i]; switch (inst.op) { @@ -151,6 +158,8 @@ bool OptimizeFPMoves(const IRWriter &in, IRWriter &out, const IROptions &opts) { // Might be useful later on x86. bool ThreeOpToTwoOp(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + bool logBlocks = false; for (int i = 0; i < (int)in.GetInstructions().size(); i++) { IRInst inst = in.GetInstructions()[i]; @@ -201,6 +210,8 @@ bool ThreeOpToTwoOp(const IRWriter &in, IRWriter &out, const IROptions &opts) { } bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + bool logBlocks = false; for (int i = 0, n = (int)in.GetInstructions().size(); i < n; ++i) { const IRInst &inst = in.GetInstructions()[i]; @@ -366,6 +377,7 @@ bool RemoveLoadStoreLeftRight(const IRWriter &in, IRWriter &out, const IROptions } bool PropagateConstants(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; IRRegCache gpr(&out); bool logBlocks = false; @@ -784,6 +796,7 @@ bool IRMutatesDestGPR(const IRInst &inst, int reg) { } bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; std::vector insts; insts.reserve(in.GetInstructions().size()); @@ -822,6 +835,8 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { insts[check.index] = IRReplaceDestGPR(insts[check.index], check.reg, inst.dest); lastWrittenTo[inst.dest] = check.index; check.reg = inst.dest; + // Update the read by exit flag to match the new reg. + check.readByExit = inst.dest < IRTEMP_0 || inst.dest > IRTEMP_LR_SHIFT; // And swap the args for this mov, since we changed the other dest. We'll optimize this out later. std::swap(inst.dest, inst.src1); } else { @@ -903,6 +918,7 @@ bool PurgeTemps(const IRWriter &in, IRWriter &out, const IROptions &opts) { } bool ReduceLoads(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; // This tells us to skip an AND op that has been optimized out. // Maybe we could skip multiple, but that'd slow things down and is pretty uncommon. int nextSkip = -1; @@ -1039,6 +1055,8 @@ static std::vector ReorderLoadStoreOps(std::vector &ops) { } bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + bool logBlocks = false; enum class RegState : u8 { @@ -1234,6 +1252,8 @@ bool ReorderLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts) } bool MergeLoadStore(const IRWriter &in, IRWriter &out, const IROptions &opts) { + CONDITIONAL_DISABLE; + bool logBlocks = false; auto opsCompatible = [&](const IRInst &a, const IRInst &b, int dist) { diff --git a/Core/MIPS/x86/CompFPU.cpp b/Core/MIPS/x86/CompFPU.cpp index cb1d7be5ed..135af332a1 100644 --- a/Core/MIPS/x86/CompFPU.cpp +++ b/Core/MIPS/x86/CompFPU.cpp @@ -41,7 +41,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } diff --git a/Core/MIPS/x86/CompLoadStore.cpp b/Core/MIPS/x86/CompLoadStore.cpp index f094684417..403f613f33 100644 --- a/Core/MIPS/x86/CompLoadStore.cpp +++ b/Core/MIPS/x86/CompLoadStore.cpp @@ -41,7 +41,7 @@ // All functions should have CONDITIONAL_DISABLE, so we can narrow things down to a file quickly. // Currently known non working ones should have DISABLE. -// #define CONDITIONAL_DISABLE { Comp_Generic(op); return; } +// #define CONDITIONAL_DISABLE(flag) { Comp_Generic(op); return; } #define CONDITIONAL_DISABLE(flag) if (jo.Disabled(JitDisable::flag)) { Comp_Generic(op); return; } #define DISABLE { Comp_Generic(op); return; } diff --git a/Core/System.cpp b/Core/System.cpp index 2be0a5f9f0..16ae2808de 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -493,7 +493,7 @@ void PSP_Shutdown() { // Make sure things know right away that PSP memory, etc. is going away. pspIsQuitting = true; if (coreState == CORE_RUNNING) - Core_UpdateState(CORE_POWERDOWN); + Core_Stop(); #ifndef MOBILE_DEVICE if (g_Config.bFuncHashMap) { diff --git a/Core/Util/GameManager.cpp b/Core/Util/GameManager.cpp index 17b2e75751..3e0c618b0e 100644 --- a/Core/Util/GameManager.cpp +++ b/Core/Util/GameManager.cpp @@ -28,6 +28,9 @@ #else #include "ext/libzip/zip.h" #endif +#ifdef _WIN32 +#include "Common/CommonWindows.h" +#endif #include "Common/Data/Encoding/Utf8.h" #include "Common/Data/Format/IniFile.h" #include "Common/Log.h" diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index a5c18aa1de..e1097ff210 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -61,7 +61,7 @@ std::string VertexShaderDesc(const VShaderID &id) { return desc.str(); } -void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation) { +void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { bool isModeThrough = (vertType & GE_VTYPE_THROUGH) != 0; bool doTexture = gstate.isTextureMapEnabled() && !gstate.isModeClear(); bool doShadeMapping = doTexture && (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP); @@ -112,7 +112,7 @@ void ComputeVertexShaderID(VShaderID *id_out, u32 vertType, bool useHWTransform, id.SetBits(VS_BIT_BONES, 3, TranslateNumBones(vertTypeGetNumBoneWeights(vertType)) - 1); // 2 bits. We should probably send in the weight scalefactor as a uniform instead, // or simply preconvert all weights to floats. - id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT); + id.SetBits(VS_BIT_WEIGHT_FMTSCALE, 2, weightsAsFloat ? 0 : (vertType & GE_VTYPE_WEIGHT_MASK) >> GE_VTYPE_WEIGHT_SHIFT); } if (gstate.isLightingEnabled()) { diff --git a/GPU/Common/ShaderId.h b/GPU/Common/ShaderId.h index c98a914be6..d2e49d0e9e 100644 --- a/GPU/Common/ShaderId.h +++ b/GPU/Common/ShaderId.h @@ -225,7 +225,7 @@ class Bugs; } -void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation); +void ComputeVertexShaderID(VShaderID *id, uint32_t vertexType, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); // Generates a compact string that describes the shader. Useful in a list to get an overview // of the current flora of shaders. std::string VertexShaderDesc(const VShaderID &id); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index c1e7a9e39a..b0d5cb6463 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -822,9 +822,9 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag // Uncomment this to screw up bone shaders to check the vertex shader software fallback // WRITE(p, "THIS SHOULD ERROR! #error"); if (numBoneWeights == 1 && ShaderLanguageIsOpenGL(compat.shaderLanguage)) - WRITE(p, " %s skinMatrix = w1 * u_bone0", boneMatrix); + WRITE(p, " %s skinMatrix = mul(w1, u_bone0)", boneMatrix); else - WRITE(p, " %s skinMatrix = w1.x * u_bone0", boneMatrix); + WRITE(p, " %s skinMatrix = mul(w1.x, u_bone0)", boneMatrix); for (int i = 1; i < numBoneWeights; i++) { const char *weightAttr = boneWeightAttr[i]; // workaround for "cant do .x of scalar" issue. @@ -832,7 +832,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (numBoneWeights == 1 && i == 0) weightAttr = "w1"; if (numBoneWeights == 5 && i == 4) weightAttr = "w2"; } - WRITE(p, " + %s * u_bone%i", weightAttr, i); + WRITE(p, " + mul(%s, u_bone%i)", weightAttr, i); } WRITE(p, ";\n"); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 8c10d6fe73..05537d2eea 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -523,7 +523,7 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform, useHWTessellation_); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, useHWTransform, useHWTessellation_, decOptions_.expandAllWeightsToFloat); ID3D11InputLayout *inputLayout = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); @@ -609,7 +609,7 @@ rotateVBO: D3D11VertexShader *vshader; D3D11FragmentShader *fshader; - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false); + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false, decOptions_.expandAllWeightsToFloat); context_->PSSetShader(fshader->GetShader(), nullptr, 0); context_->VSSetShader(vshader->GetShader(), nullptr, 0); shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering()); diff --git a/GPU/D3D11/ShaderManagerD3D11.cpp b/GPU/D3D11/ShaderManagerD3D11.cpp index ddcbc814d5..8d612e2fc9 100644 --- a/GPU/D3D11/ShaderManagerD3D11.cpp +++ b/GPU/D3D11/ShaderManagerD3D11.cpp @@ -177,13 +177,13 @@ void ShaderManagerD3D11::BindUniforms() { context_->PSSetConstantBuffers(0, 1, ps_cbs); } -void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform, bool useHWTessellation) { +void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { VShaderID VSID; FShaderID FSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); } else { VSID = lastVSID_; } diff --git a/GPU/D3D11/ShaderManagerD3D11.h b/GPU/D3D11/ShaderManagerD3D11.h index fe21710ad9..e0ac257283 100644 --- a/GPU/D3D11/ShaderManagerD3D11.h +++ b/GPU/D3D11/ShaderManagerD3D11.h @@ -85,7 +85,7 @@ public: ShaderManagerD3D11(Draw::DrawContext *draw, ID3D11Device *device, ID3D11DeviceContext *context, D3D_FEATURE_LEVEL featureLevel); ~ShaderManagerD3D11(); - void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform, bool useHWTessellation); + void GetShaders(int prim, u32 vertType, D3D11VertexShader **vshader, D3D11FragmentShader **fshader, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); void ClearShaders(); void DirtyLastShader() override; diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp index c464652318..0f7603e8de 100644 --- a/GPU/Directx9/DrawEngineDX9.cpp +++ b/GPU/Directx9/DrawEngineDX9.cpp @@ -324,7 +324,7 @@ void DrawEngineDX9::DoFlush() { GEPrimitiveType prim = prevPrim_; ApplyDrawState(prim); - VSShader *vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_); + VSShader *vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat); if (vshader->UseHWTransform()) { LPDIRECT3DVERTEXBUFFER9 vb_ = NULL; @@ -505,7 +505,7 @@ rotateVBO: } ApplyDrawStateLate(); - vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_); + vshader = shaderManager_->ApplyShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat); IDirect3DVertexDeclaration9 *pHardwareVertexDecl = SetupDecFmtForDraw(vshader, dec_->GetDecVtxFmt(), dec_->VertexType()); if (pHardwareVertexDecl) { @@ -568,7 +568,7 @@ rotateVBO: framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight); ApplyDrawStateLate(); - vshader = shaderManager_->ApplyShader(false, false, lastVType_); + vshader = shaderManager_->ApplyShader(false, false, lastVType_, decOptions_.expandAllWeightsToFloat); if (result.action == SW_DRAW_PRIMITIVES) { if (result.setStencil) { diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index 37c0bec628..3aa52d2b72 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -541,7 +541,7 @@ void ShaderManagerDX9::DirtyLastShader() { // disables vertex arrays lastPShader_ = nullptr; } -VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType) { +VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat) { // Always use software for flat shading to fix the provoking index. bool tess = gstate_c.submitType == SubmitType::HW_BEZIER || gstate_c.submitType == SubmitType::HW_SPLINE; useHWTransform = useHWTransform && (tess || gstate.getShadeMode() != GE_SHADE_FLAT); @@ -549,7 +549,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); } else { VSID = lastVSID_; } @@ -598,7 +598,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat } delete vs; - ComputeVertexShaderID(&VSID, vertType, false, false); + ComputeVertexShaderID(&VSID, vertType, false, false, weightsAsFloat); // TODO: Look for existing shader with the appropriate ID, use that instead of generating a new one - however, need to make sure // that that shader ID is not used when computing the linked shader ID below, because then IDs won't match diff --git a/GPU/Directx9/ShaderManagerDX9.h b/GPU/Directx9/ShaderManagerDX9.h index d8062ef881..a524912d50 100644 --- a/GPU/Directx9/ShaderManagerDX9.h +++ b/GPU/Directx9/ShaderManagerDX9.h @@ -80,7 +80,7 @@ public: ~ShaderManagerDX9(); void ClearCache(bool deleteThem); // TODO: deleteThem currently not respected - VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType); + VSShader *ApplyShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat); void DirtyShader(); void DirtyLastShader() override; diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 740e287e47..a15a179244 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -333,7 +333,7 @@ void DrawEngineGLES::DoFlush() { GEPrimitiveType prim = prevPrim_; VShaderID vsid; - Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, &vsid); + Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, lastVType_, decOptions_.expandAllWeightsToFloat, &vsid); GLRBuffer *vertexBuffer = nullptr; GLRBuffer *indexBuffer = nullptr; diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index 250757cb06..f6914aecc4 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -656,10 +656,10 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) { return new Shader(render_, codeBuffer_, desc, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask); } -Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, VShaderID *VSID) { +Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID) { if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation); + ComputeVertexShaderID(VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); } else { *VSID = lastVSID_; } @@ -690,7 +690,7 @@ Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTess // Can still work with software transform. VShaderID vsidTemp; - ComputeVertexShaderID(&vsidTemp, vertType, false, false); + ComputeVertexShaderID(&vsidTemp, vertType, false, false, weightsAsFloat); vs = CompileVertexShader(vsidTemp); } diff --git a/GPU/GLES/ShaderManagerGLES.h b/GPU/GLES/ShaderManagerGLES.h index f93c9a4d24..bdaf73a367 100644 --- a/GPU/GLES/ShaderManagerGLES.h +++ b/GPU/GLES/ShaderManagerGLES.h @@ -146,7 +146,7 @@ public: // This is the old ApplyShader split into two parts, because of annoying information dependencies. // If you call ApplyVertexShader, you MUST call ApplyFragmentShader soon afterwards. - Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, VShaderID *VSID); + Shader *ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID); LinkedShader *ApplyFragmentShader(VShaderID VSID, Shader *vs, u32 vertType, bool useBufferedRendering); void DeviceLost(); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index f30e357d30..12897153a9 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -818,7 +818,7 @@ void DrawEngineVulkan::DoFlush() { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); } - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true, useHWTessellation_); // usehwtransform + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, true, useHWTessellation_, decOptions_.expandAllWeightsToFloat); // usehwtransform _dbg_assert_msg_(vshader->UseHWTransform(), "Bad vshader"); Draw::NativeObject object = framebufferManager_->UseBufferedRendering() ? Draw::NativeObject::FRAMEBUFFER_RENDERPASS : Draw::NativeObject::BACKBUFFER_RENDERPASS; @@ -939,7 +939,7 @@ void DrawEngineVulkan::DoFlush() { sampler = nullSampler_; } if (!lastPipeline_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE) || prim != lastPrim_) { - shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false); // usehwtransform + shaderManager_->GetShaders(prim, lastVType_, &vshader, &fshader, false, false, decOptions_.expandAllWeightsToFloat); // usehwtransform _dbg_assert_msg_(!vshader->UseHWTransform(), "Bad vshader"); if (prim != lastPrim_ || gstate_c.IsDirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE)) { ConvertStateToVulkanKey(*framebufferManager_, shaderManager_, prim, pipelineKey_, dynState_); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index 965f066a23..9151e9299b 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -228,11 +228,11 @@ uint64_t ShaderManagerVulkan::UpdateUniforms(bool useBufferedRendering) { return dirty; } -void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, bool useHWTransform, bool useHWTessellation) { +void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat) { VShaderID VSID; if (gstate_c.IsDirty(DIRTY_VERTEXSHADER_STATE)) { gstate_c.Clean(DIRTY_VERTEXSHADER_STATE); - ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation); + ComputeVertexShaderID(&VSID, vertType, useHWTransform, useHWTessellation, weightsAsFloat); } else { VSID = lastVSID_; } diff --git a/GPU/Vulkan/ShaderManagerVulkan.h b/GPU/Vulkan/ShaderManagerVulkan.h index e35a07a103..c7d036ce21 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.h +++ b/GPU/Vulkan/ShaderManagerVulkan.h @@ -88,7 +88,7 @@ public: void DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw); - void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, bool useHWTransform, bool useHWTessellation); + void GetShaders(int prim, u32 vertType, VulkanVertexShader **vshader, VulkanFragmentShader **fshader, bool useHWTransform, bool useHWTessellation, bool weightsAsFloat); void ClearShaders(); void DirtyShader(); void DirtyLastShader() override; diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 32ae76e6c6..5be0cefa01 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -150,9 +150,19 @@ std::string System_GetProperty(SystemProperty prop) { } std::vector System_GetPropertyStringVec(SystemProperty prop) { + std::vector result; switch (prop) { + case SYSPROP_TEMP_DIRS: + if (getenv("TMPDIR") && strlen(getenv("TMPDIR")) != 0) + result.push_back(getenv("TMPDIR")); + if (getenv("TMP") && strlen(getenv("TMP")) != 0) + result.push_back(getenv("TMP")); + if (getenv("TEMP") && strlen(getenv("TEMP")) != 0) + result.push_back(getenv("TEMP")); + return result; + default: - return std::vector(); + return result; } } diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index c65f583fc6..98b56fe912 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -326,9 +326,20 @@ std::string System_GetProperty(SystemProperty prop) { } std::vector System_GetPropertyStringVec(SystemProperty prop) { + std::vector result; + switch (prop) { + case SYSPROP_TEMP_DIRS: + if (getenv("TMPDIR") && strlen(getenv("TMPDIR")) != 0) + result.push_back(getenv("TMPDIR")); + if (getenv("TMP") && strlen(getenv("TMP")) != 0) + result.push_back(getenv("TMP")); + if (getenv("TEMP") && strlen(getenv("TEMP")) != 0) + result.push_back(getenv("TEMP")); + return result; + default: - return std::vector(); + return result; } } diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index a84de656d7..bb5a62492e 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -420,6 +420,8 @@ void EmuScreen::sendMessage(const char *message, const char *value) { PSP_Shutdown(); bootPending_ = true; gamePath_ = value; + // Don't leave it on CORE_POWERDOWN, we'll sometimes aggressively bail. + Core_UpdateState(CORE_POWERUP); } } else if (!strcmp(message, "config_loaded")) { // In case we need to position touch controls differently. diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 417d17da45..0d13f0428a 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -766,7 +766,7 @@ void GameSettingsScreen::CreateViews() { networkingSettingsScroll->Add(networkingSettings); tabHolder->AddTab(ms->T("Networking"), networkingSettingsScroll); - networkingSettings->Add(new ItemHeader(n->T("Networking"))); + networkingSettings->Add(new ItemHeader(ms->T("Networking"))); networkingSettings->Add(new Choice(n->T("Adhoc Multiplayer forum")))->OnClick.Handle(this, &GameSettingsScreen::OnAdhocGuides); diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 643c0540af..ca870ab8ff 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -15,8 +15,9 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include #include +#include +#include #include "ppsspp_config.h" @@ -33,6 +34,7 @@ #include "Common/Data/Encoding/Utf8.h" #include "Common/File/PathBrowser.h" #include "Common/Math/curves.h" +#include "Common/Net/URL.h" #include "Common/File/FileUtil.h" #include "Common/TimeUtil.h" #include "Common/StringUtils.h" @@ -63,13 +65,6 @@ #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceUmd.h" -#ifdef _WIN32 -// Unfortunate, for undef DrawText... -#include "Common/CommonWindows.h" -#endif - -#include - bool MainScreen::showHomebrewTab = false; bool LaunchFile(ScreenManager *screenManager, std::string path) { @@ -96,8 +91,13 @@ bool LaunchFile(ScreenManager *screenManager, std::string path) { static bool IsTempPath(const std::string &str) { std::string item = str; +#ifdef _WIN32 + // Normalize slashes. + item = ReplaceAll(str, "/", "\\"); +#endif - const auto testPath = [&](std::string temp) { + std::vector tempPaths = System_GetPropertyStringVec(SYSPROP_TEMP_DIRS); + for (auto temp : tempPaths) { #ifdef _WIN32 temp = ReplaceAll(temp, "/", "\\"); if (!temp.empty() && temp[temp.size() - 1] != '\\') @@ -106,37 +106,9 @@ static bool IsTempPath(const std::string &str) { if (!temp.empty() && temp[temp.size() - 1] != '/') temp += "/"; #endif - return startsWith(item, temp); - }; - - const auto testCPath = [&](const char *temp) { - if (temp && temp[0]) - return testPath(temp); - return false; - }; - -#ifdef _WIN32 - // Normalize slashes. - item = ReplaceAll(str, "/", "\\"); - - std::wstring tempPath(MAX_PATH, '\0'); - size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); - if (sz >= tempPath.size()) { - tempPath.resize(sz); - sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); + if (startsWith(item, temp)) + return true; } - // Need to resize off the null terminator either way. - tempPath.resize(sz); - if (testPath(ConvertWStringToUTF8(tempPath))) - return true; -#endif - - if (testCPath(getenv("TMPDIR"))) - return true; - if (testCPath(getenv("TMP"))) - return true; - if (testCPath(getenv("TEMP"))) - return true; return false; } @@ -1091,17 +1063,18 @@ void MainScreen::CreateViews() { char versionString[256]; sprintf(versionString, "%s", PPSSPP_GIT_VERSION); rightColumnItems->SetSpacing(0.0f); - LinearLayout *logos = new LinearLayout(ORIENT_HORIZONTAL); + AnchorLayout *logos = new AnchorLayout(new AnchorLayoutParams(FILL_PARENT, 60.0f, false)); if (System_GetPropertyBool(SYSPROP_APP_GOLD)) { - logos->Add(new ImageView(ImageID("I_ICONGOLD"), IS_DEFAULT, new AnchorLayoutParams(64, 64, 10, 10, NONE, NONE, false))); + logos->Add(new ImageView(ImageID("I_ICONGOLD"), IS_DEFAULT, new AnchorLayoutParams(64, 64, 0, 0, NONE, NONE, false))); } else { - logos->Add(new ImageView(ImageID("I_ICON"), IS_DEFAULT, new AnchorLayoutParams(64, 64, 10, 10, NONE, NONE, false))); + logos->Add(new ImageView(ImageID("I_ICON"), IS_DEFAULT, new AnchorLayoutParams(64, 64, 0, 0, NONE, NONE, false))); } - logos->Add(new ImageView(ImageID("I_LOGO"), IS_DEFAULT, new LinearLayoutParams(Margins(-12, 0, 0, 0)))); + logos->Add(new ImageView(ImageID("I_LOGO"), IS_DEFAULT, new AnchorLayoutParams(180, 64, 64, -5.0f, NONE, NONE, false))); -#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) +#if !defined(MOBILE_DEVICE) if (!g_Config.bFullScreen) { - logos->Add(new ImageView(ImageID("I_FULLSCREEN"), IS_DEFAULT, new AnchorLayoutParams(64, 64, NONE, 0, 0, NONE, false))); + fullscreenButton_ = logos->Add(new Button(ImageID(g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN"), new AnchorLayoutParams(48, 48, NONE, 0, 0, NONE, false))); + fullscreenButton_->OnClick.Handle(this, &MainScreen::OnFullScreenToggle); } #endif @@ -1109,9 +1082,10 @@ void MainScreen::CreateViews() { TextView *ver = rightColumnItems->Add(new TextView(versionString, new LinearLayoutParams(Margins(70, -6, 0, 0)))); ver->SetSmall(true); ver->SetClip(false); -#if defined(USING_WIN_UI) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) - rightColumnItems->Add(new Choice(mm->T("Load","Load...")))->OnClick.Handle(this, &MainScreen::OnLoadFile); -#endif + + if (System_GetPropertyBool(SYSPROP_HAS_FILE_BROWSER)) { + rightColumnItems->Add(new Choice(mm->T("Load", "Load...")))->OnClick.Handle(this, &MainScreen::OnLoadFile); + } rightColumnItems->Add(new Choice(mm->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings); rightColumnItems->Add(new Choice(mm->T("Credits")))->OnClick.Handle(this, &MainScreen::OnCredits); rightColumnItems->Add(new Choice(mm->T("www.ppsspp.org")))->OnClick.Handle(this, &MainScreen::OnPPSSPPOrg); @@ -1210,9 +1184,38 @@ void MainScreen::sendMessage(const char *message, const char *value) { LaunchFile(screenManager(), std::string(value)); } if (!strcmp(message, "browse_folderSelect")) { + std::string filename; +#if PPSSPP_PLATFORM(ANDROID) + // Hacky way to get a normal path from a Android Storage Framework path. + // Is not gonna work forever, but ship-hack for 1.11. + std::string url = value; + const char *prefix = "content://com.android.externalstorage.documents/tree/"; + const char *primaryPrefix = "/storage/primary/"; + if (startsWith(url, prefix)) { + url = UriDecode(url.substr(strlen(prefix))); + size_t colonPos = url.find(":"); + if (colonPos != std::string::npos) { + url[colonPos] = '/'; + } + url = "/storage/" + url; + if (startsWith(url, primaryPrefix)) { + url = g_Config.memStickDirectory + url.substr(strlen(primaryPrefix)); + } + INFO_LOG(SYSTEM, "Translated '%s' into '%s'", value, url.c_str()); + } else { + // It's not gonna work. + // TODO: Show an error message? + INFO_LOG(SYSTEM, "Failed to parse content string: '%s'", value); + return; + } + filename = url; +#else + filename = value; +#endif + INFO_LOG(SYSTEM, "Got folder: '%s'", filename.c_str()); int tab = tabHolder_->GetCurrentTab(); if (tab >= 0 && tab < (int)gameBrowsers_.size()) { - gameBrowsers_[tab]->SetPath(value); + gameBrowsers_[tab]->SetPath(filename); } } } @@ -1245,6 +1248,17 @@ UI::EventReturn MainScreen::OnLoadFile(UI::EventParams &e) { return UI::EVENT_DONE; } +UI::EventReturn MainScreen::OnFullScreenToggle(UI::EventParams &e) { + if (fullscreenButton_) { + fullscreenButton_->SetImageID(ImageID(!g_Config.bFullScreen ? "I_RESTORE" : "I_FULLSCREEN")); + } +#if !defined(MOBILE_DEVICE) + g_Config.bFullScreen = !g_Config.bFullScreen; + System_SendMessage("toggle_fullscreen", ""); +#endif + return UI::EVENT_DONE; +} + void MainScreen::DrawBackground(UIContext &dc) { UIScreenWithBackground::DrawBackground(dc); if (highlightedGamePath_.empty() && prevHighlightedGamePath_.empty()) { diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 86c22dd529..2bc2572533 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -125,9 +125,11 @@ protected: UI::EventReturn OnDownloadUpgrade(UI::EventParams &e); UI::EventReturn OnDismissUpgrade(UI::EventParams &e); UI::EventReturn OnAllowStorage(UI::EventParams &e); + UI::EventReturn OnFullScreenToggle(UI::EventParams &e); UI::LinearLayout *upgradeBar_ = nullptr; UI::TabHolder *tabHolder_ = nullptr; + UI::Button *fullscreenButton_ = nullptr; std::string restoreFocusGamePath_; std::vector gameBrowsers_; diff --git a/UWP/PPSSPP_UWPMain.cpp b/UWP/PPSSPP_UWPMain.cpp index 60a73f8695..0ba7fac4b6 100644 --- a/UWP/PPSSPP_UWPMain.cpp +++ b/UWP/PPSSPP_UWPMain.cpp @@ -357,9 +357,31 @@ std::string System_GetProperty(SystemProperty prop) { } std::vector System_GetPropertyStringVec(SystemProperty prop) { + std::vector result; switch (prop) { + case SYSPROP_TEMP_DIRS: + { + std::wstring tempPath(MAX_PATH, '\0'); + size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); + if (sz >= tempPath.size()) { + tempPath.resize(sz); + sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); + } + // Need to resize off the null terminator either way. + tempPath.resize(sz); + result.push_back(ConvertWStringToUTF8(tempPath)); + + if (getenv("TMPDIR") && strlen(getenv("TMPDIR")) != 0) + result.push_back(getenv("TMPDIR")); + if (getenv("TMP") && strlen(getenv("TMP")) != 0) + result.push_back(getenv("TMP")); + if (getenv("TEMP") && strlen(getenv("TEMP")) != 0) + result.push_back(getenv("TEMP")); + return result; + } + default: - return std::vector(); + return result; } } @@ -447,11 +469,16 @@ void System_SendMessage(const char *command, const char *parameter) { }); } else if (!strcmp(command, "toggle_fullscreen")) { auto view = Windows::UI::ViewManagement::ApplicationView::GetForCurrentView(); + bool flag = !view->IsFullScreenMode; if (strcmp(parameter, "0") == 0) { - view->ExitFullScreenMode(); + flag = false; + } else if (strcmp(parameter, "1") == 0){ + flag = true; } - else if (strcmp(parameter, "1") == 0){ + if (flag) { view->TryEnterFullScreenMode(); + } else { + view->ExitFullScreenMode(); } } } diff --git a/Windows/MainWindow.cpp b/Windows/MainWindow.cpp index 7ef4340741..170470094a 100644 --- a/Windows/MainWindow.cpp +++ b/Windows/MainWindow.cpp @@ -132,6 +132,7 @@ namespace MainWindow static bool inFullscreenResize = false; static bool inResizeMove = false; static bool hasFocus = true; + static bool g_isFullscreen = false; // gross hack bool noFocusPause = false; // TOGGLE_PAUSE state to override pause on lost focus @@ -355,6 +356,7 @@ namespace MainWindow ::SetMenu(hWnd, goingFullscreen ? NULL : menu); g_Config.bFullScreen = goingFullscreen; + g_isFullscreen = goingFullscreen; g_IgnoreWM_SIZE = false; @@ -1029,4 +1031,8 @@ namespace MainWindow PostMessage(hwndMain, WM_USER_TOGGLE_FULLSCREEN, fullscreen, 0); } + bool IsFullscreen() { + return g_isFullscreen; + } + } // namespace diff --git a/Windows/MainWindow.h b/Windows/MainWindow.h index c0bb7a8f84..618d904fcd 100644 --- a/Windows/MainWindow.h +++ b/Windows/MainWindow.h @@ -76,6 +76,7 @@ namespace MainWindow void ToggleFullscreen(HWND hWnd, bool goingFullscreen); void Minimize(); void SendToggleFullscreen(bool fullscreen); // To be used off-thread + bool IsFullscreen(); void ToggleDebugConsoleVisibility(); void SetInternalResolution(int res = -1); void SetWindowSize(int zoom); diff --git a/Windows/main.cpp b/Windows/main.cpp index c7e9dc9fd6..4d948cfe5b 100644 --- a/Windows/main.cpp +++ b/Windows/main.cpp @@ -217,9 +217,31 @@ std::string System_GetProperty(SystemProperty prop) { } std::vector System_GetPropertyStringVec(SystemProperty prop) { + std::vector result; switch (prop) { + case SYSPROP_TEMP_DIRS: + { + std::wstring tempPath(MAX_PATH, '\0'); + size_t sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); + if (sz >= tempPath.size()) { + tempPath.resize(sz); + sz = GetTempPath((DWORD)tempPath.size(), &tempPath[0]); + } + // Need to resize off the null terminator either way. + tempPath.resize(sz); + result.push_back(ConvertWStringToUTF8(tempPath)); + + if (getenv("TMPDIR") && strlen(getenv("TMPDIR")) != 0) + result.push_back(getenv("TMPDIR")); + if (getenv("TMP") && strlen(getenv("TMP")) != 0) + result.push_back(getenv("TMP")); + if (getenv("TEMP") && strlen(getenv("TEMP")) != 0) + result.push_back(getenv("TEMP")); + return result; + } + default: - return std::vector(); + return result; } } @@ -330,7 +352,7 @@ void System_SendMessage(const char *command, const char *parameter) { } else if (!strcmp(command, "bgImage_browse")) { MainWindow::BrowseBackground(); } else if (!strcmp(command, "toggle_fullscreen")) { - bool flag = !g_Config.bFullScreen; + bool flag = !MainWindow::IsFullscreen(); if (strcmp(parameter, "0") == 0) { flag = false; } else if (strcmp(parameter, "1") == 0) { diff --git a/android/jni/Android.mk b/android/jni/Android.mk index c527ea2524..4579fd9b77 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -17,6 +17,7 @@ ARCH_FILES := \ $(SRC)/Common/x64Emitter.cpp \ $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ + $(SRC)/Common/Math/fast/fast_matrix_sse.c \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ $(SRC)/Core/MIPS/x86/CompBranch.cpp \ @@ -39,6 +40,7 @@ ARCH_FILES := \ $(SRC)/Common/x64Emitter.cpp \ $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ + $(SRC)/Common/Math/fast/fast_matrix_sse.c \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ $(SRC)/Core/MIPS/x86/CompBranch.cpp \ @@ -62,6 +64,7 @@ ARCH_FILES := \ $(SRC)/Common/ArmEmitter.cpp \ $(SRC)/Common/ArmCPUDetect.cpp \ $(SRC)/Common/ColorConvNEON.cpp.neon \ + $(SRC)/Common/Math/fast/fast_matrix_neon.S.neon \ $(SRC)/Core/MIPS/ARM/ArmCompALU.cpp \ $(SRC)/Core/MIPS/ARM/ArmCompBranch.cpp \ $(SRC)/Core/MIPS/ARM/ArmCompFPU.cpp \ @@ -76,6 +79,9 @@ ARCH_FILES := \ $(SRC)/Core/MIPS/ARM/ArmRegCacheFPU.cpp \ $(SRC)/GPU/Common/VertexDecoderArm.cpp \ $(SRC)/ext/disarm.cpp \ + $(SRC)/ext/libpng17/arm/arm_init.c \ + $(SRC)/ext/libpng17/arm/filter_neon_intrinsics.c \ + $(SRC)/ext/libpng17/arm/filter_neon.S.neon \ ArmEmitterTest.cpp endif @@ -620,18 +626,6 @@ LOCAL_SRC_FILES := \ ifeq ($(findstring armeabi-v7a,$(TARGET_ARCH_ABI)),armeabi-v7a) LOCAL_CFLAGS := $(LOCAL_CFLAGS) -DARM -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - $(SRC)/Common/Math/fast/fast_matrix_neon.S.neon \ - $(SRC)/ext/libpng17/arm/arm_init.c \ - $(SRC)/ext/libpng17/arm/filter_neon_intrinsics.c \ - $(SRC)/ext/libpng17/arm/filter_neon.S.neon - -else ifeq ($(TARGET_ARCH_ABI),x86) -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - $(SRC)/Common/Math/fast/fast_matrix_sse.c -else ifeq ($(TARGET_ARCH_ABI),x86_64) -LOCAL_SRC_FILES := $(LOCAL_SRC_FILES) \ - $(SRC)/Common/Math/fast/fast_matrix_sse.c endif ifneq ($(SKIPAPP),1) @@ -684,6 +678,7 @@ ifeq ($(UNITTEST),1) LOCAL_MODULE := ppsspp_unittest LOCAL_SRC_FILES := \ $(SRC)/unittest/JitHarness.cpp \ + $(SRC)/unittest/TestShaderGenerators.cpp \ $(SRC)/unittest/TestVertexJit.cpp \ $(TESTARMEMITTER_FILE) \ $(SRC)/unittest/UnitTest.cpp diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 6b64d49693..a5a1724325 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -372,6 +372,8 @@ std::vector System_GetPropertyStringVec(SystemProperty prop) { switch (prop) { case SYSPROP_ADDITIONAL_STORAGE_DIRS: return g_additionalStorageDirs; + + case SYSPROP_TEMP_DIRS: default: return std::vector(); } @@ -429,6 +431,11 @@ bool System_GetPropertyBool(SystemProperty prop) { return true; case SYSPROP_HAS_IMAGE_BROWSER: return true; + case SYSPROP_HAS_FILE_BROWSER: + return false; // We kind of have but needs more work. + case SYSPROP_HAS_FOLDER_BROWSER: + // Uses OPEN_DOCUMENT_TREE to let you select a folder. + return androidVersion >= 21; case SYSPROP_APP_GOLD: #ifdef GOLD return true; diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 1262b88e99..598bd3849f 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.PowerManager; import android.os.Vibrator; +import android.provider.DocumentsContract; import android.provider.MediaStore; import android.text.InputType; import android.util.Log; @@ -99,7 +100,10 @@ public abstract class NativeActivity extends Activity { // This is to avoid losing the game/menu state etc when we are just // switched-away from or rotated etc. private boolean shuttingDown; + private static final int RESULT_LOAD_IMAGE = 1; + private static final int RESULT_BROWSE_FILE = 2; + private static final int RESULT_OPEN_DOCUMENT_TREE = 3; // Allow for multiple connected gamepads but just consider them the same for now. // Actually this is not entirely true, see the code. @@ -257,14 +261,27 @@ public abstract class NativeActivity extends Activity { String removableStoragePath; list = new ArrayList(); File fileList[] = new File("/storage/").listFiles(); - for (File file : fileList) { - if (!file.getAbsolutePath().equalsIgnoreCase(Environment.getExternalStorageDirectory().getAbsolutePath()) && file.isDirectory() && file.canRead()) { - list.add(file.getAbsolutePath()); + if (fileList != null) { + for (File file : fileList) { + if (!file.getAbsolutePath().equalsIgnoreCase(Environment.getExternalStorageDirectory().getAbsolutePath()) && file.isDirectory() && file.canRead()) { + list.add(file.getAbsolutePath()); + } } } } - // TODO: On older devices, try System.getenv(“EXTERNAL_SDCARD_STORAGE”) + if (list == null) { + String[] varNames = { "EXTERNAL_SDCARD_STORAGE", "SECONDARY_STORAGE" }; + for (String var : varNames) { + Log.i(TAG, "getSdCardPaths: Checking env " + var); + String secStore = System.getenv("SECONDARY_STORAGE"); + if (secStore != null && secStore.length() > 0) { + list = new ArrayList(); + list.add(secStore); + break; + } + } + } if (list == null) { return new ArrayList(); @@ -273,9 +290,6 @@ public abstract class NativeActivity extends Activity { } } - /** - * returns a list of all available sd cards paths, or null if not found. - */ @TargetApi(Build.VERSION_CODES.KITKAT) private static ArrayList getSdCardPaths19(final Context context) { @@ -300,8 +314,12 @@ public abstract class NativeActivity extends Activity { if (file == null) continue; final String storageState = Environment.getStorageState(file); - if (Environment.MEDIA_MOUNTED.equals(storageState)) - result.add(getRootOfInnerSdCardFolder(externalCacheDirs[i])); + if (Environment.MEDIA_MOUNTED.equals(storageState)) { + String root = getRootOfInnerSdCardFolder(externalCacheDirs[i]); + if (root != null) { + result.add(root); + } + } } if (result.isEmpty()) return null; @@ -314,6 +332,9 @@ public abstract class NativeActivity extends Activity { if (file == null) return null; final long totalSpace = file.getTotalSpace(); + if (totalSpace <= 0) { + return null; + } while (true) { final File parentFile = file.getParentFile(); if (parentFile == null || !parentFile.canRead()) { @@ -384,19 +405,25 @@ public abstract class NativeActivity extends Activity { Log.i(TAG, "Ext storage: " + extStorageState + " " + extStorageDir); - ArrayList sdCards = getSdCardPaths(this); + String additionalStorageDirs = ""; + try { + ArrayList sdCards = getSdCardPaths(this); - // String.join doesn't exist on old devices (???). - StringBuilder s = new StringBuilder(); - for (int i = 0; i < sdCards.size(); i++) { - String sdCard = sdCards.get(i); - Log.i(TAG, "SD card: " + sdCard); - s.append(sdCard); - if (i != sdCards.size() - 1) { - s.append(":"); + // String.join doesn't exist on old devices (???). + StringBuilder s = new StringBuilder(); + for (int i = 0; i < sdCards.size(); i++) { + String sdCard = sdCards.get(i); + Log.i(TAG, "SD card: " + sdCard); + s.append(sdCard); + if (i != sdCards.size() - 1) { + s.append(":"); + } } + additionalStorageDirs = s.toString(); + } + catch (Exception e) { + Log.e(TAG, "Failed to get SD storage dirs: " + e.toString()); } - String additionalStorageDirs = s.toString(); Log.i(TAG, "End of storage paths"); @@ -1098,7 +1125,10 @@ public abstract class NativeActivity extends Activity { @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) { + if (resultCode != RESULT_OK || data == null) { + return; + } + if (requestCode == RESULT_LOAD_IMAGE) { Uri selectedImage = data.getData(); if (selectedImage != null) { String[] filePathColumn = {MediaStore.Images.Media.DATA}; @@ -1109,6 +1139,20 @@ public abstract class NativeActivity extends Activity { cursor.close(); NativeApp.sendMessage("bgImage_updated", picturePath); } + } else if (requestCode == RESULT_BROWSE_FILE) { + Uri selectedFile = data.getData(); + if (selectedFile != null) { + // NativeApp.sendMessage("br"); + Log.i(TAG, "Browse file finished:" + selectedFile.toString()); + } + } else if (requestCode == RESULT_OPEN_DOCUMENT_TREE) { + Uri selectedFile = data.getData(); + if (selectedFile != null) { + // Convert URI to normal path. (This might not be possible in Android 12+) + String path = selectedFile.toString(); + Log.i(TAG, "Browse folder finished: " + path); + NativeApp.sendMessage("browse_folderSelect", path); + } } } @@ -1240,6 +1284,30 @@ public abstract class NativeActivity extends Activity { Log.e(TAG, e.toString()); return false; } + } else if (command.equals("browse_file")) { + try { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("application/octet-stream"); + //intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri); + startActivityForResult(intent, RESULT_BROWSE_FILE); + } catch (Exception e) { + Log.e(TAG, e.toString()); + return false; + } + } else if (command.equals("browse_folder")) { + try { + Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); + intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); // not yet used properly + intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); // Only allow local folders. + startActivityForResult(intent, RESULT_OPEN_DOCUMENT_TREE); + return true; + } catch (Exception e) { + Log.e(TAG, e.toString()); + return false; + } } else if (command.equals("sharejpeg")) { try { Intent share = new Intent(Intent.ACTION_SEND); diff --git a/assets/compat.ini b/assets/compat.ini index 56ae1970a7..89f506aa40 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -804,6 +804,18 @@ ULUS10132 = true # Homebrew Kurok (we don't normally add homebrew here but it has a distinctive GameID) KURO00767 = true +# Scooby-Doo! Who's Watching Who? +ULUS10168 = true +ULES00571 = true + +# Tron Evolution +ULUS10548 = true +ULES01494 = true +ULES01495 = true + +# Atari Classics Evolved +ULUS10325 = true + [JitInvalidationHack] # This is an absolutely awful hack that somehow prevents issues when clearing the JIT, # if the game has copied code with EmuHack opcodes or something. Hopefully will be able diff --git a/assets/flash0/font/jpn0.pgf b/assets/flash0/font/jpn0.pgf index db594b6c5e..aaa56273f4 100644 Binary files a/assets/flash0/font/jpn0.pgf and b/assets/flash0/font/jpn0.pgf differ diff --git a/assets/flash0/font/ltn0.pgf b/assets/flash0/font/ltn0.pgf index 4de80003c8..8ededb5b97 100644 Binary files a/assets/flash0/font/ltn0.pgf and b/assets/flash0/font/ltn0.pgf differ diff --git a/assets/flash0/font/ltn1.pgf b/assets/flash0/font/ltn1.pgf index 866bd102e2..bc28ad28e8 100644 Binary files a/assets/flash0/font/ltn1.pgf and b/assets/flash0/font/ltn1.pgf differ diff --git a/assets/flash0/font/ltn10.pgf b/assets/flash0/font/ltn10.pgf index 406960c329..742c4ebf0a 100644 Binary files a/assets/flash0/font/ltn10.pgf and b/assets/flash0/font/ltn10.pgf differ diff --git a/assets/flash0/font/ltn11.pgf b/assets/flash0/font/ltn11.pgf index 4ef50a0a42..1f718a4f75 100644 Binary files a/assets/flash0/font/ltn11.pgf and b/assets/flash0/font/ltn11.pgf differ diff --git a/assets/flash0/font/ltn12.pgf b/assets/flash0/font/ltn12.pgf index 5d134bab99..0b8b2424cd 100644 Binary files a/assets/flash0/font/ltn12.pgf and b/assets/flash0/font/ltn12.pgf differ diff --git a/assets/flash0/font/ltn13.pgf b/assets/flash0/font/ltn13.pgf index 6421f56420..125d50d08d 100644 Binary files a/assets/flash0/font/ltn13.pgf and b/assets/flash0/font/ltn13.pgf differ diff --git a/assets/flash0/font/ltn14.pgf b/assets/flash0/font/ltn14.pgf index 9d099a91ec..6da9a3e214 100644 Binary files a/assets/flash0/font/ltn14.pgf and b/assets/flash0/font/ltn14.pgf differ diff --git a/assets/flash0/font/ltn15.pgf b/assets/flash0/font/ltn15.pgf index 63fcb15100..4b26ef5db0 100644 Binary files a/assets/flash0/font/ltn15.pgf and b/assets/flash0/font/ltn15.pgf differ diff --git a/assets/flash0/font/ltn2.pgf b/assets/flash0/font/ltn2.pgf index e493d57f43..8dcf9c4e5a 100644 Binary files a/assets/flash0/font/ltn2.pgf and b/assets/flash0/font/ltn2.pgf differ diff --git a/assets/flash0/font/ltn3.pgf b/assets/flash0/font/ltn3.pgf index 089fb1f721..d8d070f2c8 100644 Binary files a/assets/flash0/font/ltn3.pgf and b/assets/flash0/font/ltn3.pgf differ diff --git a/assets/flash0/font/ltn4.pgf b/assets/flash0/font/ltn4.pgf index 395340d2fc..d6d625f6cf 100644 Binary files a/assets/flash0/font/ltn4.pgf and b/assets/flash0/font/ltn4.pgf differ diff --git a/assets/flash0/font/ltn5.pgf b/assets/flash0/font/ltn5.pgf index f15c6b7380..944b2b7c61 100644 Binary files a/assets/flash0/font/ltn5.pgf and b/assets/flash0/font/ltn5.pgf differ diff --git a/assets/flash0/font/ltn6.pgf b/assets/flash0/font/ltn6.pgf index 4c09094fdd..fd4c27d129 100644 Binary files a/assets/flash0/font/ltn6.pgf and b/assets/flash0/font/ltn6.pgf differ diff --git a/assets/flash0/font/ltn7.pgf b/assets/flash0/font/ltn7.pgf index 64e3eedaf7..8ce77b3579 100644 Binary files a/assets/flash0/font/ltn7.pgf and b/assets/flash0/font/ltn7.pgf differ diff --git a/assets/flash0/font/ltn8.pgf b/assets/flash0/font/ltn8.pgf index ad4c48dd7e..4a55fdd32e 100644 Binary files a/assets/flash0/font/ltn8.pgf and b/assets/flash0/font/ltn8.pgf differ diff --git a/assets/flash0/font/ltn9.pgf b/assets/flash0/font/ltn9.pgf index f0d14f62fa..e444c250ab 100644 Binary files a/assets/flash0/font/ltn9.pgf and b/assets/flash0/font/ltn9.pgf differ diff --git a/headless/Headless.cpp b/headless/Headless.cpp index bbabad7710..52331451ae 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -2,10 +2,11 @@ // See headless.txt. // To build on non-windows systems, just run CMake in the SDL directory, it will build both a normal ppsspp and the headless version. +#include "ppsspp_config.h" #include #include #include -#if defined(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) #include #endif @@ -38,7 +39,7 @@ #include "SDLHeadlessHost.h" #endif -#if defined(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) JNIEnv *getEnv() { return nullptr; } @@ -46,6 +47,9 @@ JNIEnv *getEnv() { jclass findClass(const char *name) { return nullptr; } + +bool audioRecording_Available() { return false; } +bool audioRecording_State() { return false; } #endif class PrintfLogger : public LogListener { diff --git a/ios/main.mm b/ios/main.mm index 8082584933..4b3e768d5c 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -66,6 +66,7 @@ std::string System_GetProperty(SystemProperty prop) { std::vector System_GetPropertyStringVec(SystemProperty prop) { switch (prop) { + case SYSPROP_TEMP_DIRS: default: return std::vector(); } diff --git a/pspautotests b/pspautotests index 7e4a1e7509..879e7959eb 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 7e4a1e750997e95df8a1f04f9a6396801adf7113 +Subproject commit 879e7959eb3251133fcc4ccf26b0ef35d9d43f8e diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index a68c8247ba..81d74558a4 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -1,3 +1,4 @@ +#include "ppsspp_config.h" #include #include "Common/StringUtils.h" @@ -13,11 +14,13 @@ #include "GPU/Common/VertexShaderGenerator.h" #include "GPU/Common/ReinterpretFramebuffer.h" +#if PPSSPP_PLATFORM(WINDOWS) #include "GPU/D3D11/D3D11Util.h" #include "GPU/D3D11/D3D11Loader.h" #include "GPU/D3D9/D3DCompilerLoader.h" #include "GPU/D3D9/D3D9ShaderCompiler.h" +#endif bool GenerateFShader(FShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bugs, std::string *errorString) { uint64_t uniformMask; @@ -89,6 +92,7 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std::string *errorMessage) { std::vector spirv; switch (lang) { +#if PPSSPP_PLATFORM(WINDOWS) case ShaderLanguage::HLSL_D3D11: { auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0); @@ -104,6 +108,7 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std return false; } } +#endif case ShaderLanguage::GLSL_VULKAN: return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage); @@ -352,9 +357,13 @@ bool TestFragmentShaders() { } bool TestShaderGenerators() { +#if PPSSPP_PLATFORM(WINDOWS) LoadD3D11(); init_glslang(); LoadD3DCompilerDynamic(); +#else + init_glslang(); +#endif if (!TestFragmentShaders()) { return false; diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 7e5bd98b97..6547be7ea6 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -27,17 +27,17 @@ // To use, set command line parameter to one or more of the tests below, or "all". // Search for "availableTests". +#include "ppsspp_config.h" #include #include #include #include #include #include -#if defined(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) #include #endif -#include "ppsspp_config.h" #include "Common/System/NativeApp.h" #include "Common/System/System.h" #include "Common/Input/InputState.h" @@ -72,7 +72,7 @@ bool System_GetPropertyBool(SystemProperty prop) { return false; } -#if defined(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) JNIEnv *getEnv() { return nullptr; } @@ -80,6 +80,9 @@ JNIEnv *getEnv() { jclass findClass(const char *name) { return nullptr; } + +bool audioRecording_Available() { return false; } +bool audioRecording_State() { return false; } #endif #ifndef M_PI_2