diff --git a/.gitignore b/.gitignore index e391987ab1..89dd7f9292 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ assets/flash0 UWP/icph UWP/.vs .vs +.vscode # For Mac .DS_Store diff --git a/.travis.yml b/.travis.yml index 58fd835d41..e227de6e95 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,7 +58,7 @@ matrix: env: PPSSPP_BUILD_TYPE=Android APP_ABI=x86_64 - os: linux - compiler: "clang linux" + compiler: "clang" env: PPSSPP_BUILD_TYPE=Linux - os: linux compiler: "gcc" diff --git a/CMakeLists.txt b/CMakeLists.txt index 55d9eb146a..8b214f676d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,7 +108,7 @@ option(USING_EGL "Set to ON if target environment uses EGL" ${USING_EGL}) option(USING_FBDEV "Set to ON if target environment uses fbdev (eg. Pandora)" ${USING_FBDEV}) option(USING_GLES2 "Set to ON if target device uses OpenGL ES 2.0" ${USING_GLES2}) option(USING_X11_VULKAN "Set to OFF if target environment doesn't use X11 for Vulkan" ON) -option(USE_WAYLAND_WSI "Enable or disable Wayland WSI support for Vulkan" ON) +option(USE_WAYLAND_WSI "Enable or disable Wayland WSI support for Vulkan" ${USE_WAYLAND_WSI}) # :: Frontends option(USING_QT_UI "Set to ON if you wish to use the Qt frontend wrapper" ${USING_QT_UI}) option(MOBILE_DEVICE "Set to ON when targeting a mobile device" ${MOBILE_DEVICE}) @@ -270,8 +270,6 @@ if(NOT MSVC) add_compile_options(-fno-strict-aliasing) if(${CMAKE_C_COMPILER_ID} STREQUAL "Intel") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -parallel -fopenmp") - else() - add_compile_options(-ffast-math) endif() if(X86 OR X86_64) @@ -1992,6 +1990,9 @@ if(TargetBin) add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource} "ios/Launch Screen.storyboard") else() add_executable(${TargetBin} MACOSX_BUNDLE ${ICON_PATH_ABS} ${NativeAssets} ${SHADER_FILES} ${FLASH0_FILES} ${LANG_FILES} ${NativeAppSource}) + if(TARGET SDL2::SDL2) + add_custom_command(TARGET ${TargetBin} POST_BUILD COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/SDL/macbundle.sh" "${CMAKE_BINARY_DIR}/PPSSPPSDL.app") + endif() endif() elseif(WIN32) add_executable(${TargetBin} WIN32 ${NativeAppSource}) diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 5f4fa1688e..6200675522 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -76,7 +76,7 @@ MultiThreadedDebug ../ext/native;../ext/snappy;.. StreamingSIMDExtensions2 - Fast + Precise true false false @@ -103,7 +103,7 @@ _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) ../ext/native;../ext/snappy;.. NotSet - Fast + Precise false true false @@ -133,7 +133,7 @@ stdafx.h false StreamingSIMDExtensions2 - Fast + Precise ../ext/native;../ext/snappy;.. Speed true @@ -166,7 +166,7 @@ ../ext/native;../ext/snappy;.. false NotSet - Fast + Precise Speed false true diff --git a/Common/FileUtil.cpp b/Common/FileUtil.cpp index c6fbd73eff..69504428eb 100644 --- a/Common/FileUtil.cpp +++ b/Common/FileUtil.cpp @@ -133,6 +133,7 @@ std::string ResolvePath(const std::string &path) { int result = getFinalPathNameByHandleW(hFile, buf, BUF_SIZE - 1, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); if (result >= BUF_SIZE || result == 0) wcscpy_s(buf, BUF_SIZE - 1, input.c_str()); + CloseHandle(hFile); } } else { wchar_t *longBuf = new wchar_t[BUF_SIZE]; @@ -829,7 +830,7 @@ const std::string &GetExeDirectory() uint32_t program_path_size = sizeof(program_path) - 1; #if defined(__linux__) - if (readlink("/proc/self/exe", program_path, 4095) > 0) + if (readlink("/proc/self/exe", program_path, program_path_size) > 0) #elif defined(__APPLE__) && !defined(IOS) if (_NSGetExecutablePath(program_path, &program_path_size) == 0) #elif defined(KERN_PROC_PATHNAME) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 4c4d2fcff1..5c5e513948 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -30,7 +30,7 @@ static bool IsDepthStencilFormat(VkFormat format) { } } -bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { +bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *allocator, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage, const VkComponentMapping *mapping) { Wipe(); width_ = w; @@ -75,7 +75,8 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, bool dedicatedAllocation = false; vulkan_->GetImageMemoryRequirements(image_, &mem_reqs, &dedicatedAllocation); - if (allocator_ && !dedicatedAllocation) { + if (allocator && !dedicatedAllocation) { + allocator_ = allocator; offset_ = allocator_->Allocate(mem_reqs, &mem_, Tag()); if (offset_ == VulkanDeviceAllocator::ALLOCATE_FAILED) { ELOG("Image memory allocation failed (mem_reqs.size=%d, typebits=%08x", (int)mem_reqs.size, (int)mem_reqs.memoryTypeBits); @@ -231,10 +232,13 @@ void VulkanTexture::Destroy() { if (image_ != VK_NULL_HANDLE) { vulkan_->Delete().QueueDeleteImage(image_); } - if (mem_ != VK_NULL_HANDLE && !allocator_) { - vulkan_->Delete().QueueDeleteDeviceMemory(mem_); - } else if (mem_ != VK_NULL_HANDLE) { - allocator_->Free(mem_, offset_); - mem_ = VK_NULL_HANDLE; + if (mem_ != VK_NULL_HANDLE) { + if (allocator_) { + allocator_->Free(mem_, offset_); + mem_ = VK_NULL_HANDLE; + allocator_ = nullptr; + } else { + vulkan_->Delete().QueueDeleteDeviceMemory(mem_); + } } } diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h index 9a23d91784..64f84a8997 100644 --- a/Common/Vulkan/VulkanImage.h +++ b/Common/Vulkan/VulkanImage.h @@ -8,8 +8,8 @@ class VulkanDeviceAllocator; // Not very optimal - if you have many small textures you should use other strategies. class VulkanTexture { public: - VulkanTexture(VulkanContext *vulkan, VulkanDeviceAllocator *allocator) - : vulkan_(vulkan), allocator_(allocator) { + VulkanTexture(VulkanContext *vulkan) + : vulkan_(vulkan) { } ~VulkanTexture() { Destroy(); @@ -18,7 +18,7 @@ public: // Fast uploads from buffer. Mipmaps supported. // Usage must at least include VK_IMAGE_USAGE_TRANSFER_DST_BIT in order to use UploadMip. // When using UploadMip, initialLayout should be VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. - bool CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); + bool CreateDirect(VkCommandBuffer cmd, VulkanDeviceAllocator *allocator, int w, int h, int numMips, VkFormat format, VkImageLayout initialLayout, VkImageUsageFlags usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, const VkComponentMapping *mapping = nullptr); void UploadMip(VkCommandBuffer cmd, int mip, int mipWidth, int mipHeight, VkBuffer buffer, uint32_t offset, size_t rowLength); // rowLength is in pixels void GenerateMip(VkCommandBuffer cmd, int mip); void EndCreate(VkCommandBuffer cmd, bool vertexTexture = false); @@ -55,7 +55,7 @@ private: int32_t height_ = 0; int32_t numMips_ = 1; VkFormat format_ = VK_FORMAT_UNDEFINED; - VulkanDeviceAllocator *allocator_; + VulkanDeviceAllocator *allocator_ = nullptr; // If set, memory is from this allocator. size_t offset_ = 0; std::string tag_; }; diff --git a/Common/Vulkan/VulkanMemory.cpp b/Common/Vulkan/VulkanMemory.cpp index 2b13be2e01..8edae36aca 100644 --- a/Common/Vulkan/VulkanMemory.cpp +++ b/Common/Vulkan/VulkanMemory.cpp @@ -23,9 +23,8 @@ #include "base/timeutil.h" #include "math/math_util.h" -VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size) : device_(vulkan->GetDevice()), buf_(0), offset_(0), size_(size), writePtr_(nullptr) { - vulkan->MemoryTypeFromProperties(0xFFFFFFFF, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &memoryTypeIndex_); - +VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage) + : vulkan_(vulkan), size_(size), usage_(usage) { bool res = AddBuffer(); assert(res); } @@ -36,43 +35,42 @@ VulkanPushBuffer::~VulkanPushBuffer() { bool VulkanPushBuffer::AddBuffer() { BufInfo info; + VkDevice device = vulkan_->GetDevice(); VkBufferCreateInfo b{ VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; b.size = size_; b.flags = 0; - b.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + b.usage = usage_; b.sharingMode = VK_SHARING_MODE_EXCLUSIVE; b.queueFamilyIndexCount = 0; b.pQueueFamilyIndices = nullptr; - VkResult res = vkCreateBuffer(device_, &b, nullptr, &info.buffer); + VkResult res = vkCreateBuffer(device, &b, nullptr, &info.buffer); if (VK_SUCCESS != res) { _assert_msg_(G3D, false, "vkCreateBuffer failed! result=%d", (int)res); return false; } - // Make validation happy. + // Get the buffer memory requirements. None of this can be cached! VkMemoryRequirements reqs; - vkGetBufferMemoryRequirements(device_, info.buffer, &reqs); - // TODO: We really should use memoryTypeIndex here.. + vkGetBufferMemoryRequirements(device, info.buffer, &reqs); // Okay, that's the buffer. Now let's allocate some memory for it. VkMemoryAllocateInfo alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; - // TODO: Should check here that memoryTypeIndex_ matches reqs.memoryTypeBits. - alloc.memoryTypeIndex = memoryTypeIndex_; alloc.allocationSize = reqs.size; + vulkan_->MemoryTypeFromProperties(reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &alloc.memoryTypeIndex); - res = vkAllocateMemory(device_, &alloc, nullptr, &info.deviceMemory); + res = vkAllocateMemory(device, &alloc, nullptr, &info.deviceMemory); if (VK_SUCCESS != res) { _assert_msg_(G3D, false, "vkAllocateMemory failed! size=%d result=%d", (int)reqs.size, (int)res); - vkDestroyBuffer(device_, info.buffer, nullptr); + vkDestroyBuffer(device, info.buffer, nullptr); return false; } - res = vkBindBufferMemory(device_, info.buffer, info.deviceMemory, 0); + res = vkBindBufferMemory(device, info.buffer, info.deviceMemory, 0); if (VK_SUCCESS != res) { ELOG("vkBindBufferMemory failed! result=%d", (int)res); - vkFreeMemory(device_, info.deviceMemory, nullptr); - vkDestroyBuffer(device_, info.buffer, nullptr); + vkFreeMemory(device, info.deviceMemory, nullptr); + vkDestroyBuffer(device, info.buffer, nullptr); return false; } @@ -137,7 +135,7 @@ size_t VulkanPushBuffer::GetTotalSize() const { void VulkanPushBuffer::Map() { _dbg_assert_(G3D, !writePtr_); - VkResult res = vkMapMemory(device_, buffers_[buf_].deviceMemory, 0, size_, 0, (void **)(&writePtr_)); + VkResult res = vkMapMemory(vulkan_->GetDevice(), buffers_[buf_].deviceMemory, 0, size_, 0, (void **)(&writePtr_)); _dbg_assert_(G3D, writePtr_); assert(VK_SUCCESS == res); } @@ -152,7 +150,7 @@ void VulkanPushBuffer::Unmap() { range.memory = buffers_[buf_].deviceMemory; vkFlushMappedMemoryRanges(device_, 1, &range); */ - vkUnmapMemory(device_, buffers_[buf_].deviceMemory); + vkUnmapMemory(vulkan_->GetDevice(), buffers_[buf_].deviceMemory); writePtr_ = nullptr; } diff --git a/Common/Vulkan/VulkanMemory.h b/Common/Vulkan/VulkanMemory.h index ef14de80ed..50e7017eb9 100644 --- a/Common/Vulkan/VulkanMemory.h +++ b/Common/Vulkan/VulkanMemory.h @@ -22,7 +22,7 @@ class VulkanPushBuffer { }; public: - VulkanPushBuffer(VulkanContext *vulkan, size_t size); + VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage); ~VulkanPushBuffer(); void Destroy(VulkanContext *vulkan); @@ -108,13 +108,13 @@ private: void NextBuffer(size_t minSize); void Defragment(VulkanContext *vulkan); - VkDevice device_; + VulkanContext *vulkan_; std::vector buffers_; - size_t buf_; - size_t offset_; - size_t size_; - uint32_t memoryTypeIndex_; - uint8_t *writePtr_; + size_t buf_ = 0; + size_t offset_ = 0; + size_t size_ = 0; + uint8_t *writePtr_ = nullptr; + VkBufferUsageFlags usage_; }; // VulkanDeviceAllocator diff --git a/Core/Compatibility.cpp b/Core/Compatibility.cpp index f9de4e41c5..8d5374d305 100644 --- a/Core/Compatibility.cpp +++ b/Core/Compatibility.cpp @@ -73,6 +73,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) { CheckSetting(iniFile, gameID, "YugiohSaveFix", &flags_.YugiohSaveFix); CheckSetting(iniFile, gameID, "ForceUMDDelay", &flags_.ForceUMDDelay); CheckSetting(iniFile, gameID, "ForceMax60FPS", &flags_.ForceMax60FPS); + CheckSetting(iniFile, gameID, "JitInvalidationHack", &flags_.JitInvalidationHack); } void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) { diff --git a/Core/Compatibility.h b/Core/Compatibility.h index 65c89b637d..fd641b4604 100644 --- a/Core/Compatibility.h +++ b/Core/Compatibility.h @@ -73,6 +73,7 @@ struct CompatFlags { bool YugiohSaveFix; bool ForceUMDDelay; bool ForceMax60FPS; + bool JitInvalidationHack; }; class IniFile; diff --git a/Core/Config.cpp b/Core/Config.cpp index 041abd7aa2..be9dcf77a7 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -400,7 +400,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("SimpleFrameStats", &g_Config.bSimpleFrameStats, false), ConfigSetting("CheckForNewVersion", &g_Config.bCheckForNewVersion, false), ConfigSetting("Language", &g_Config.sLanguageIni, &DefaultLangRegion), - ConfigSetting("ForceLagSync", &g_Config.bForceLagSync, false, true, true), + ConfigSetting("ForceLagSync2", &g_Config.bForceLagSync, false, true, true), ConfigSetting("DiscordPresence", &g_Config.bDiscordPresence, false, false, false), // Or maybe it makes sense to have it per-game? Race conditions abound... ReportedConfigSetting("NumWorkerThreads", &g_Config.iNumWorkerThreads, &DefaultNumWorkers, true, true), @@ -437,7 +437,7 @@ static ConfigSetting generalSettings[] = { ConfigSetting("RemoteDebuggerOnStartup", &g_Config.bRemoteDebuggerOnStartup, false), #ifdef __ANDROID__ - ConfigSetting("ScreenRotation", &g_Config.iScreenRotation, ROTATION_LOCKED_HORIZONTAL), + ConfigSetting("ScreenRotation", &g_Config.iScreenRotation, ROTATION_AUTO_HORIZONTAL), #endif ConfigSetting("InternalScreenRotation", &g_Config.iInternalScreenRotation, ROTATION_LOCKED_HORIZONTAL), @@ -1120,7 +1120,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) { } } -void Config::Save() { +void Config::Save(const char *saveReason) { if (jitForcedOff) { // if JIT has been forced off, we don't want to screw up the user's ppsspp.ini g_Config.iCpuCore = (int)CPUCore::JIT; @@ -1173,11 +1173,11 @@ void Config::Save() { LogManager::GetInstance()->SaveConfig(log); if (!iniFile.Save(iniFilename_.c_str())) { - ERROR_LOG(LOADER, "Error saving config - can't write ini '%s'", iniFilename_.c_str()); + ERROR_LOG(LOADER, "Error saving config (%s)- can't write ini '%s'", saveReason, iniFilename_.c_str()); System_SendMessage("toast", "Failed to save settings!\nCheck permissions, or try to restart the device."); return; } - INFO_LOG(LOADER, "Config saved: '%s'", iniFilename_.c_str()); + INFO_LOG(LOADER, "Config saved (%s): '%s'", saveReason, iniFilename_.c_str()); if (!bGameSpecific) //otherwise we already did this in saveGameConfig() { @@ -1364,7 +1364,7 @@ bool Config::hasGameConfig(const std::string &pGameId) { } void Config::changeGameSpecific(const std::string &pGameId) { - Save(); + Save("changeGameSpecific"); gameId_ = pGameId; bGameSpecific = !pGameId.empty(); } diff --git a/Core/Config.h b/Core/Config.h index f77e6b41b8..66a0d4694e 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -421,7 +421,7 @@ public: std::string dismissedVersion; void Load(const char *iniFileName = nullptr, const char *controllerIniFilename = nullptr); - void Save(); + void Save(const char *saveReason); void RestoreDefaults(); //per game config managment, should maybe be in it's own class diff --git a/Core/ConfigValues.h b/Core/ConfigValues.h index e714fa9b0c..73e5063de3 100644 --- a/Core/ConfigValues.h +++ b/Core/ConfigValues.h @@ -37,6 +37,7 @@ enum { ROTATION_LOCKED_VERTICAL = 2, ROTATION_LOCKED_HORIZONTAL180 = 3, ROTATION_LOCKED_VERTICAL180 = 4, + ROTATION_AUTO_HORIZONTAL = 5, }; enum BufferFilter { diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 34d117cf66..51af34e22f 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -73,7 +73,7 @@ ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) StreamingSIMDExtensions2 - Fast + Precise true false false @@ -95,7 +95,7 @@ ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_64=1;_M_X64=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) NotSet - Fast + Precise false true false @@ -121,7 +121,7 @@ ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext false StreamingSIMDExtensions2 - Fast + Precise USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;USE_FFMPEG;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) Speed MultiThreaded @@ -150,7 +150,7 @@ true ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext NotSet - Fast + Precise false false Speed diff --git a/Core/CwCheat.cpp b/Core/CwCheat.cpp index 5722145ef5..8c62c42e3a 100644 --- a/Core/CwCheat.cpp +++ b/Core/CwCheat.cpp @@ -237,6 +237,21 @@ static void __CheatStart() { cheatsEnabled = true; } +static int GetRefreshMs() { + int refresh = g_Config.iCwCheatRefreshRate; + + if (!cheatsEnabled) + refresh = 1000; + + // Horrible hack for Tony Hawk - Underground 2. See #3854. Avoids crashing somehow + // but still causes regular JIT invalidations which causes stutters. + if (PSP_CoreParameter().compat.flags().JitInvalidationHack) { + refresh = 2; + } + + return refresh; +} + void __CheatInit() { // Always register the event, want savestates to be compatible whether cheats on or off. CheatEvent = CoreTiming::RegisterEvent("CheatEvent", &hleCheat); @@ -245,10 +260,8 @@ void __CheatInit() { __CheatStart(); } - int refresh = g_Config.iCwCheatRefreshRate; - // Only check once a second for cheats to be enabled. - CoreTiming::ScheduleEvent(msToCycles(cheatsEnabled ? refresh : 1000), CheatEvent, 0); + CoreTiming::ScheduleEvent(msToCycles(GetRefreshMs()), CheatEvent, 0); } void __CheatShutdown() { @@ -264,13 +277,11 @@ void __CheatDoState(PointerWrap &p) { p.Do(CheatEvent); CoreTiming::RestoreRegisterEvent(CheatEvent, "CheatEvent", &hleCheat); - int refresh = g_Config.iCwCheatRefreshRate; - if (s < 2) { // Before this we didn't have a checkpoint, so reset didn't work. // Let's just force one in. CoreTiming::RemoveEvent(CheatEvent); - CoreTiming::ScheduleEvent(msToCycles(cheatsEnabled ? refresh : 1000), CheatEvent, 0); + CoreTiming::ScheduleEvent(msToCycles(GetRefreshMs()), CheatEvent, 0); } } @@ -284,14 +295,30 @@ void hleCheat(u64 userdata, int cyclesLate) { } } - int refresh = g_Config.iCwCheatRefreshRate; + // Check periodically for cheats. + CoreTiming::ScheduleEvent(msToCycles(GetRefreshMs()), CheatEvent, 0); - // Only check once a second for cheats to be enabled. - CoreTiming::ScheduleEvent(msToCycles(cheatsEnabled ? refresh : 1000), CheatEvent, 0); + if (PSP_CoreParameter().compat.flags().JitInvalidationHack) { + std::string gameTitle = g_paramSFO.GetValueString("DISC_ID"); + + // Horrible hack for Tony Hawk - Underground 2. See #3854. Avoids crashing somehow + // but still causes regular JIT invalidations which causes stutters. + if (gameTitle == "ULUS10014") { + cheatEngine->InvalidateICache(0x08865600, 72); + cheatEngine->InvalidateICache(0x08865690, 4); + } else if (gameTitle == "ULES00033" || gameTitle == "ULES00034" || gameTitle == "ULES00035") { // euro, also 34 and 35 + cheatEngine->InvalidateICache(0x088655D8, 72); + cheatEngine->InvalidateICache(0x08865668, 4); + } else if (gameTitle == "ULUS10138") { // MTX MotoTrax. No hack for ULES00581 known. + cheatEngine->InvalidateICache(0x0886DCC0, 72); + cheatEngine->InvalidateICache(0x0886DC20, 4); + cheatEngine->InvalidateICache(0x0886DD40, 4); + } + } if (!cheatEngine || !cheatsEnabled) return; - + if (g_Config.bReloadCheats) { //Checks if the "reload cheats" button has been pressed. cheatEngine->ParseCheats(); g_Config.bReloadCheats = false; diff --git a/Core/CwCheat.h b/Core/CwCheat.h index cef0002289..882093db3d 100644 --- a/Core/CwCheat.h +++ b/Core/CwCheat.h @@ -45,8 +45,8 @@ public: void Run(); bool HasCheats(); -private: void InvalidateICache(u32 addr, int size); +private: u32 GetAddress(u32 value); CheatOperation InterpretNextOp(const CheatCode &cheat, size_t &i); diff --git a/Core/Dialog/PSPMsgDialog.cpp b/Core/Dialog/PSPMsgDialog.cpp index 302113b3b5..ca9e283f3e 100755 --- a/Core/Dialog/PSPMsgDialog.cpp +++ b/Core/Dialog/PSPMsgDialog.cpp @@ -146,7 +146,7 @@ void PSPMsgDialog::DisplayMessage(std::string text, bool hasYesNo, bool hasOK) float WRAP_WIDTH = 300.0f; if (UTF8StringNonASCIICount(text.c_str()) > 3) WRAP_WIDTH = 372.0f; - + float y = 140.0f; float h, sy ,ey; int n; diff --git a/Core/Dialog/PSPSaveDialog.cpp b/Core/Dialog/PSPSaveDialog.cpp index c06a436152..d078382897 100755 --- a/Core/Dialog/PSPSaveDialog.cpp +++ b/Core/Dialog/PSPSaveDialog.cpp @@ -403,7 +403,7 @@ void PSPSaveDialog::DisplaySaveDataInfo1() char saveDetail[1024]; char am_pm[] = "AM"; - char hour_time[10] ; + char hour_time[32]; int hour = param.GetFileInfo(currentSelectedSave).modif_time.tm_hour; int min = param.GetFileInfo(currentSelectedSave).modif_time.tm_min; switch (g_Config.iTimeFormat) { @@ -412,17 +412,17 @@ void PSPSaveDialog::DisplaySaveDataInfo1() strcpy(am_pm, "PM"); hour -= 12; } - snprintf(hour_time,10,"%02d:%02d %s", hour, min, am_pm); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); break; case 2: - snprintf(hour_time,10,"%02d:%02d", hour, min); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d", hour, min); break; default: if (hour > 12) { strcpy(am_pm, "PM"); hour -= 12; } - snprintf(hour_time,10,"%02d:%02d %s", hour, min, am_pm); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); } snprintf(title, sizeof(title), "%s", param.GetFileInfo(currentSelectedSave).title); @@ -485,7 +485,7 @@ void PSPSaveDialog::DisplaySaveDataInfo2(bool showNewData) { char date[256]; char am_pm[] = "AM"; - char hour_time[10] ; + char hour_time[32]; int hour = modif_time.tm_hour; int min = modif_time.tm_min; switch (g_Config.iTimeFormat) { @@ -494,17 +494,17 @@ void PSPSaveDialog::DisplaySaveDataInfo2(bool showNewData) { strcpy(am_pm, "PM"); hour -= 12; } - snprintf(hour_time, 10, "%02d:%02d %s", hour, min, am_pm); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); break; case 2: - snprintf(hour_time, 10, "%02d:%02d", hour, min); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d", hour, min); break; default: if (hour > 12) { strcpy(am_pm, "PM"); hour -= 12; } - snprintf(hour_time, 10, "%02d:%02d %s", hour, min, am_pm); + snprintf(hour_time, sizeof(hour_time), "%02d:%02d %s", hour, min, am_pm); } int day = modif_time.tm_mday; diff --git a/Core/FileLoaders/LocalFileLoader.cpp b/Core/FileLoaders/LocalFileLoader.cpp index a537ee0211..c373e4dac6 100644 --- a/Core/FileLoaders/LocalFileLoader.cpp +++ b/Core/FileLoaders/LocalFileLoader.cpp @@ -16,6 +16,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include + #include "ppsspp_config.h" #include "util/text/utf8.h" #include "file/file_util.h" @@ -30,7 +31,10 @@ LocalFileLoader::LocalFileLoader(const std::string &filename) : filesize_(0), filename_(filename) { - + if (filename.empty()) { + ERROR_LOG(FILESYS, "LocalFileLoader can't load empty filenames"); + return; + } #ifndef _WIN32 fd_ = open(filename.c_str(), O_RDONLY | O_CLOEXEC); @@ -47,7 +51,7 @@ LocalFileLoader::LocalFileLoader(const std::string &filename) lseek(fd_, 0, SEEK_SET); #endif -#else // !_WIN32 +#else // _WIN32 const DWORD access = GENERIC_READ, share = FILE_SHARE_READ, mode = OPEN_EXISTING, flags = FILE_ATTRIBUTE_NORMAL; #if PPSSPP_PLATFORM(UWP) @@ -60,14 +64,15 @@ LocalFileLoader::LocalFileLoader(const std::string &filename) } LARGE_INTEGER end_offset; const LARGE_INTEGER zero = { 0 }; - if(SetFilePointerEx(handle_, zero, &end_offset, FILE_END) == 0) { + if (SetFilePointerEx(handle_, zero, &end_offset, FILE_END) == 0) { + // Couldn't seek in the file. Close it and give up? This should never happen. + CloseHandle(handle_); + handle_ = INVALID_HANDLE_VALUE; return; } filesize_ = end_offset.QuadPart; SetFilePointerEx(handle_, zero, nullptr, FILE_BEGIN); - -#endif // !_WIN32 - +#endif // _WIN32 } LocalFileLoader::~LocalFileLoader() { diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index 40810d1fae..cb7cffd1c7 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -154,6 +154,10 @@ DirectoryFileSystem::DirectoryFileSystem(IHandleAllocator *_hAlloc, std::string hAlloc = _hAlloc; } +DirectoryFileSystem::~DirectoryFileSystem() { + CloseAll(); +} + std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath) { if (localpath.empty()) @@ -445,16 +449,12 @@ void DirectoryFileHandle::Close() void DirectoryFileSystem::CloseAll() { for (auto iter = entries.begin(); iter != entries.end(); ++iter) { + INFO_LOG(FILESYS, "DirectoryFileSystem::CloseAll(): Force closing %d (%s)", (int)iter->first, iter->second.guestFilename.c_str()); iter->second.hFile.Close(); } - entries.clear(); } -DirectoryFileSystem::~DirectoryFileSystem() { - CloseAll(); -} - std::string DirectoryFileSystem::GetLocalPath(std::string localpath) { if (localpath.empty()) return basePath; diff --git a/Core/HLE/KUBridge.cpp b/Core/HLE/KUBridge.cpp index d9fce045b7..dd643c5896 100644 --- a/Core/HLE/KUBridge.cpp +++ b/Core/HLE/KUBridge.cpp @@ -38,7 +38,7 @@ static int kuKernelGetModel() { const HLEFunction KUBridge[] = { - { 0x4C25EA72, &WrapI_CUU, "kuKernelLoadModule", 'i', "cuu" }, + { 0x4C25EA72, &WrapI_CUU, "kuKernelLoadModule", 'i', "sxx" }, { 0x24331850, &WrapI_V, "kuKernelGetModel", 'i', "" }, }; diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 1b552a4191..6074b1601f 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -1,4 +1,3 @@ - // Copyright (c) 2012- PPSSPP Project. // This program is free software: you can redistribute it and/or modify @@ -509,7 +508,7 @@ static void __CtrlWriteUserLatch(CtrlLatch *userLatch, int bufs) { userLatch->btnMake &= CTRL_MASK_USER; userLatch->btnPress &= CTRL_MASK_USER; if (bufs > 0) { - userLatch->btnRelease |= CTRL_MASK_USER; + userLatch->btnRelease |= ~CTRL_MASK_USER; } } diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index 1402a908ef..8a4ee5ed92 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -436,7 +436,9 @@ public: } u32 args[2] = { params_.userDataAddr, (u32)handle_ }; // TODO: The return value of this is leaking. - __KernelDirectMipsCall(params_.freeFuncAddr, 0, args, 2, false); + if (handle_) { // Avoid calling free-callback on double-free + __KernelDirectMipsCall(params_.freeFuncAddr, 0, args, 2, false); + } handle_ = 0; fonts_.clear(); isfontopen_.clear(); diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index 55366beef4..36241fece3 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -1934,7 +1934,8 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret if (module->nm.module_start_func != 0 && module->nm.module_start_func != (u32)-1) { entryAddr = module->nm.module_start_func; - attribute = module->nm.module_start_thread_attr; + if (module->nm.module_start_thread_attr != 0) + attribute = module->nm.module_start_thread_attr; } else if ((entryAddr == (u32)-1) || entryAddr == module->memoryBlockAddr - 1) { @@ -1967,7 +1968,7 @@ static void sceKernelStartModule(u32 moduleId, u32 argsize, u32 argAddr, u32 ret stacksize = module->nm.module_start_thread_stacksize; } - SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0); + SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, entryAddr, priority, stacksize, attribute, 0, (module->nm.attribute & 0x1000) != 0); __KernelStartThreadValidate(threadID, argsize, argAddr); __KernelSetThreadRA(threadID, NID_MODULERETURN); __KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "started module"); @@ -2049,7 +2050,7 @@ static u32 sceKernelStopModule(u32 moduleId, u32 argSize, u32 argAddr, u32 retur if (Memory::IsValidAddress(stopFunc)) { - SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, stopFunc, priority, stacksize, attr, 0); + SceUID threadID = __KernelCreateThread(module->nm.name, moduleId, stopFunc, priority, stacksize, attr, 0, (module->nm.attribute & 0x1000) != 0); __KernelStartThreadValidate(threadID, argSize, argAddr); __KernelSetThreadRA(threadID, NID_MODULERETURN); __KernelWaitCurThread(WAITTYPE_MODULE, moduleId, 1, 0, false, "stopped module"); @@ -2132,7 +2133,7 @@ u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, } if (Memory::IsValidAddress(stopFunc)) { - SceUID threadID = __KernelCreateThread(module->nm.name, moduleID, stopFunc, priority, stacksize, attr, 0); + SceUID threadID = __KernelCreateThread(module->nm.name, moduleID, stopFunc, priority, stacksize, attr, 0, (module->nm.attribute & 0x1000) != 0); __KernelStartThreadValidate(threadID, argSize, argp); __KernelSetThreadRA(threadID, NID_MODULERETURN); __KernelWaitCurThread(WAITTYPE_MODULE, moduleID, 1, 0, false, "unloadstopped module"); diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index 858090883a..c0c718bddc 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -1944,7 +1944,7 @@ SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 return id; } -int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr) { +int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr, bool allowKernel) { if (threadName == nullptr) return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ERROR, "NULL thread name"); @@ -1961,7 +1961,7 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 if (entry != 0) return hleReportError(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "invalid thread entry %08x", entry); } - if ((attr & ~PSP_THREAD_ATTR_USER_MASK) != 0) + if ((attr & ~PSP_THREAD_ATTR_USER_MASK) != 0 && !allowKernel) return hleReportWarning(SCEKERNEL, SCE_KERNEL_ERROR_ILLEGAL_ATTR, "illegal thread attributes %08x", attr); if ((attr & ~PSP_THREAD_ATTR_SUPPORTED) != 0) @@ -1997,7 +1997,9 @@ 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) { - return __KernelCreateThread(threadName, __KernelGetCurThreadModuleId(), entry, prio, stacksize, attr, optionAddr); + Thread *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) { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 6216fc02ec..a7a127f638 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -31,7 +31,7 @@ class DebugInterface; int sceKernelChangeThreadPriority(SceUID threadID, int priority); SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr); -int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr); +int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr, bool allowKernel); int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr); int sceKernelDelayThread(u32 usec); int sceKernelDelayThreadCB(u32 usec); diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index a76a216fa4..43f30b9ce6 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -318,12 +318,12 @@ static void AnalyzeMpeg(u8 *buffer, u32 validSize, MpegContext *ctx) { ctx->audioFrameCount = 0; ctx->endOfAudioReached = false; ctx->endOfVideoReached = false; - + // Sanity Check ctx->mpegFirstTimestamp if (ctx->mpegFirstTimestamp != 90000) { WARN_LOG_REPORT(ME, "Unexpected mpeg first timestamp: %llx / %lld", ctx->mpegFirstTimestamp, ctx->mpegFirstTimestamp); } - + if (ctx->mpegMagic != PSMF_MAGIC || ctx->mpegVersion < 0 || (ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) { // mpeg header is invalid! @@ -511,7 +511,7 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr Memory::Write_U32(ringbufferAddr, mpegHandle + 16); Memory::Write_U32(ringbuffer->dataUpperBound, mpegHandle + 20); } - MpegContext *ctx = new MpegContext; + MpegContext *ctx = new MpegContext(); if (mpegMap.find(mpegHandle) != mpegMap.end()) { WARN_LOG_REPORT(HLE, "Replacing existing mpeg context at %08x", mpegAddr); // Otherwise, it would leak. @@ -532,6 +532,8 @@ static u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr ctx->ignorePcm = false; ctx->ignoreAvc = false; ctx->defaultFrameWidth = frameWidth; + ctx->mpegStreamSize = 0; + ctx->mpegOffset = 0; for (int i = 0; i < MPEG_DATA_ES_BUFFERS; i++) { ctx->esBuffers[i] = false; } diff --git a/Core/HLE/sceNetAdhoc.cpp b/Core/HLE/sceNetAdhoc.cpp index afae658852..f1e6e8ffbe 100644 --- a/Core/HLE/sceNetAdhoc.cpp +++ b/Core/HLE/sceNetAdhoc.cpp @@ -174,7 +174,7 @@ u32 sceNetAdhocInit() { // 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); + threadAdhocID = __KernelCreateThread("AdhocThread", __KernelGetCurThreadModuleId(), dummyThreadHackAddr, 0x10, 0x1000, 0, 0, false); if (threadAdhocID > 0) { __KernelStartThread(threadAdhocID, 0, 0); } diff --git a/Core/MIPS/ARM/ArmCompLoadStore.cpp b/Core/MIPS/ARM/ArmCompLoadStore.cpp index bc81e33116..3dfcae2e61 100644 --- a/Core/MIPS/ARM/ArmCompLoadStore.cpp +++ b/Core/MIPS/ARM/ArmCompLoadStore.cpp @@ -179,8 +179,17 @@ namespace MIPSComp return; } - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); - load ? gpr.MapDirtyIn(rt, rs, false) : gpr.MapInIn(rt, rs); + // This gets hit in a few games, as a result of never-taken delay slots (some branch types + // conditionally execute the delay slot instructions). Ignore in those cases. + if (!js.inDelaySlot) { + _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); + } + + if (load) { + gpr.MapDirtyIn(rt, rs, false); + } else { + gpr.MapInIn(rt, rs); + } if (!g_Config.bFastMemory && rs != MIPS_REG_SP) { SetCCAndR0ForSafeAddress(rs, offset, SCRATCHREG2, true); diff --git a/Core/MIPS/ARM/ArmCompVFPU.cpp b/Core/MIPS/ARM/ArmCompVFPU.cpp index 9d2bcfe611..089ace124c 100644 --- a/Core/MIPS/ARM/ArmCompVFPU.cpp +++ b/Core/MIPS/ARM/ArmCompVFPU.cpp @@ -2301,10 +2301,16 @@ namespace MIPSComp VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; - // Actually, not sure that this instruction accepts an S prefix. We don't apply it in the - // interpreter. But whatever. + // This is a hack that modifies prefixes. We eat them later, so just overwrite. + // S prefix forces the negate flags. + js.prefixS |= 0x000F0000; + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + js.prefixT = (js.prefixT & ~0x000000FF) | 0x00000055 | 0x0000F000; + + u8 sregs[4], tregs[4], dregs[4]; GetVectorRegsPrefixS(sregs, sz, _VS); + GetVectorRegsPrefixT(tregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); MIPSReg tempregs[4]; @@ -2316,10 +2322,9 @@ namespace MIPSComp } } - MOVI2F(S0, 1.0f, SCRATCHREG1); for (int i = 0; i < n; ++i) { - fpr.MapDirtyInV(tempregs[i], sregs[i]); - VSUB(fpr.V(tempregs[i]), S0, fpr.V(sregs[i])); + fpr.MapDirtyInInV(tempregs[i], sregs[i], tregs[i]); + VADD(fpr.V(tempregs[i]), fpr.V(tregs[i]), fpr.V(sregs[i])); } for (int i = 0; i < n; ++i) { diff --git a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp index 945d993849..1b5ebbe939 100644 --- a/Core/MIPS/ARM/ArmCompVFPUNEON.cpp +++ b/Core/MIPS/ARM/ArmCompVFPUNEON.cpp @@ -1433,12 +1433,21 @@ void ArmJit::CompNEON_Vocp(MIPSOpcode op) { DISABLE; } + // TODO: Handle T prefix. Right now it uses 1.0f always. + + // This is a hack that modifies prefixes. We eat them later, so just overwrite. + // S prefix forces the negate flags. + js.prefixS |= 0x000F0000; + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + js.prefixT = (js.prefixT & ~0x000000FF) | 0x00000055 | 0x0000F000; + VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); MappedRegs regs = NEONMapDirtyIn(op, sz, sz); MOVI2F_neon(Q0, 1.0f, R0); - VSUB(F_32, regs.vd, Q0, regs.vs); + VADD(F_32, regs.vd, Q0, regs.vs); NEONApplyPrefixD(regs.vd); fpr.ReleaseSpillLocksAndDiscardTemps(); diff --git a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp index f28074c2e9..e322d4a9a7 100644 --- a/Core/MIPS/ARM64/Arm64CompLoadStore.cpp +++ b/Core/MIPS/ARM64/Arm64CompLoadStore.cpp @@ -172,7 +172,7 @@ namespace MIPSComp { return; } - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); + _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); if (load) { gpr.MapDirtyIn(rt, rs, false); } else { @@ -364,13 +364,19 @@ namespace MIPSComp { addrReg = SCRATCH1; } } else { - // This actually gets hit in micro machines! rs = ZR rt = ZR. Probably a bug. - // Leaving this a debug assert for future investigation. - _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address? CPU bug?"); + // This gets hit in a few games, as a result of never-taken delay slots (some branch types + // conditionally execute the delay slot instructions). Ignore in those cases. + if (!js.inDelaySlot) { + _dbg_assert_msg_(JIT, !gpr.IsImm(rs), "Invalid immediate address %08x? CPU bug?", iaddr); + } // If we already have a targetReg, we optimized an imm, and rs is already mapped. if (targetReg == INVALID_REG) { - load ? gpr.MapDirtyIn(rt, rs) : gpr.MapInIn(rt, rs); + if (load) { + gpr.MapDirtyIn(rt, rs); + } else { + gpr.MapInIn(rt, rs); + } targetReg = gpr.R(rt); } @@ -413,9 +419,9 @@ namespace MIPSComp { } void Arm64Jit::Comp_Cache(MIPSOpcode op) { -// int imm = (s16)(op & 0xFFFF); -// int rs = _RS; -// int addr = R(rs) + imm; + // int imm = (s16)(op & 0xFFFF); + // int rs = _RS; + // int addr = R(rs) + imm; int func = (op >> 16) & 0x1F; // It appears that a cache line is 0x40 (64) bytes, loops in games diff --git a/Core/MIPS/ARM64/Arm64CompVFPU.cpp b/Core/MIPS/ARM64/Arm64CompVFPU.cpp index 88ba5df94a..871c7e99ea 100644 --- a/Core/MIPS/ARM64/Arm64CompVFPU.cpp +++ b/Core/MIPS/ARM64/Arm64CompVFPU.cpp @@ -1952,10 +1952,16 @@ namespace MIPSComp { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; - // Actually, not sure that this instruction accepts an S prefix. We don't apply it in the - // interpreter. But whatever. + // This is a hack that modifies prefixes. We eat them later, so just overwrite. + // S prefix forces the negate flags. + js.prefixS |= 0x000F0000; + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + js.prefixT = (js.prefixT & ~0x000000FF) | 0x00000055 | 0x0000F000; + + u8 sregs[4], tregs[4], dregs[4]; GetVectorRegsPrefixS(sregs, sz, _VS); + GetVectorRegsPrefixT(tregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); MIPSReg tempregs[4]; @@ -1969,8 +1975,8 @@ namespace MIPSComp { fp.MOVI2F(S0, 1.0f, SCRATCH1); for (int i = 0; i < n; ++i) { - fpr.MapDirtyInV(tempregs[i], sregs[i]); - fp.FSUB(fpr.V(tempregs[i]), S0, fpr.V(sregs[i])); + fpr.MapDirtyInInV(tempregs[i], sregs[i], tregs[i]); + fp.FADD(fpr.V(tempregs[i]), fpr.V(tregs[i]), fpr.V(sregs[i])); } for (int i = 0; i < n; ++i) { diff --git a/Core/MIPS/IR/IRCompVFPU.cpp b/Core/MIPS/IR/IRCompVFPU.cpp index 0b61953b3c..6393fff4a9 100644 --- a/Core/MIPS/IR/IRCompVFPU.cpp +++ b/Core/MIPS/IR/IRCompVFPU.cpp @@ -1174,9 +1174,14 @@ namespace MIPSComp { // Many more instructions to interpret. void IRFrontend::Comp_Vmmul(MIPSOpcode op) { CONDITIONAL_DISABLE(VFPU_MTX); + if (!js.HasNoPrefix()) { + DISABLE; + } - // Matrix multiply (no prefixes) - // D[0 .. N,0 .. M] = S[0 .. N, 0 .. M] * T[0 .. N,0 .. M] + // Matrix multiply (wierd prefixes) + // D[0 .. N, 0 .. M] = S[0 .. N, 0 .. M]' * T[0 .. N, 0 .. M] + // Note: Behaves as if it's implemented through a series of vdots. + // Important: this is a matrix multiply with a pre-transposed S. MatrixSize sz = GetMtxSize(op); int n = GetMatrixSide(sz); @@ -1229,7 +1234,7 @@ namespace MIPSComp { // TODO: Skip this and resort to method one and transpose the output? for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { - ir.Write(IROp::Vec4Dot, s0 + i, sregs[i], tregs[j * 4]); + ir.Write(IROp::Vec4Dot, s0 + i, sregs[i * 4], tregs[j * 4]); } ir.Write(IROp::Vec4Mov, dregs[j * 4], s0); } @@ -1840,27 +1845,36 @@ namespace MIPSComp { DISABLE; } + // Vector one's complement + // d[N] = 1.0 - s[N] + VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; - // Actually, not sure that this instruction accepts an S prefix. We don't apply it in the - // interpreter. But whatever. + // This is a hack that modifies prefixes. We eat them later, so just overwrite. + // S prefix forces the negate flags. + js.prefixS |= 0x000F0000; + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + js.prefixT = (js.prefixT & ~0x000000FF) | 0x00000055 | 0x0000F000; + + u8 sregs[4], tregs[4], dregs[4]; GetVectorRegsPrefixS(sregs, sz, _VS); + // There's no bits for t, so just reuse s. It'll be constants only. + GetVectorRegsPrefixT(tregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); u8 tempregs[4]; for (int i = 0; i < n; ++i) { if (!IsOverlapSafe(dregs[i], n, sregs)) { - tempregs[i] = IRVTEMP_PFX_T + i; // using IRTEMP0 for other things + tempregs[i] = IRVTEMP_0 + i; } else { tempregs[i] = dregs[i]; } } - ir.Write(IROp::SetConstF, IRVTEMP_0, ir.AddConstantFloat(1.0f)); for (int i = 0; i < n; ++i) { - ir.Write(IROp::FSub, tempregs[i], IRVTEMP_0, sregs[i]); + ir.Write(IROp::FAdd, tempregs[i], tregs[i], sregs[i]); } for (int i = 0; i < n; ++i) { if (dregs[i] != tempregs[i]) { diff --git a/Core/MIPS/MIPSIntVFPU.cpp b/Core/MIPS/MIPSIntVFPU.cpp index 174b211400..012579299e 100644 --- a/Core/MIPS/MIPSIntVFPU.cpp +++ b/Core/MIPS/MIPSIntVFPU.cpp @@ -544,15 +544,24 @@ namespace MIPSInt void Int_Vocp(MIPSOpcode op) { - float s[4], d[4]; + float s[4], t[4], d[4]; int vd = _VD; int vs = _VS; VectorSize sz = GetVecSize(op); ReadVector(s, sz, vs); - for (int i = 0; i < GetNumVectorElements(sz); i++) - { - // Always positive NaN. - d[i] = my_isnan(s[i]) ? fabsf(s[i]) : 1.0f - s[i]; + + // S prefix forces the negate flags. + u32 sprefix = currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX]; + ApplyPrefixST(s, sprefix | 0x000F0000, sz); + + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + u32 tprefix = currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX]; + ApplyPrefixST(t, (tprefix & ~0x000000FF) | 0x00000055 | 0x0000F000, sz); + + for (int i = 0; i < GetNumVectorElements(sz); i++) { + // Always positive NaN. Note that s is always negated from the registers. + d[i] = my_isnan(s[i]) ? fabsf(s[i]) : t[i] + s[i]; } ApplyPrefixD(d, sz); WriteVector(d, sz, vd); @@ -562,22 +571,32 @@ namespace MIPSInt void Int_Vsocp(MIPSOpcode op) { - float s[4], d[4]; + float s[4], t[4], d[4]; int vd = _VD; int vs = _VS; VectorSize sz = GetVecSize(op); + VectorSize outSize = GetDoubleVectorSize(sz); ReadVector(s, sz, vs); + + // S prefix forces negate in even/odd and xxyy swizzle. + // abs works, and applies to final position (not source.) + u32 sprefix = currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX]; + ApplyPrefixST(s, (sprefix & ~0x000F00FF) | 0x00000050 | 0x00050000, outSize); + + // T prefix forces constants on and regnum to 0, 1, 0, 1. + // That means negate still works, and abs activates a different constant. + u32 tprefix = currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX]; + ApplyPrefixST(t, (tprefix & ~0x000000FF) | 0x00000011 | 0x0000F000, outSize); + int n = GetNumVectorElements(sz); - float x = s[0]; - d[0] = nanclamp(1.0f - x, 0.0f, 1.0f); - d[1] = nanclamp(x, 0.0f, 1.0f); - VectorSize outSize = V_Pair; - if (n > 1) { - float y = s[1]; - d[2] = nanclamp(1.0f - y, 0.0f, 1.0f); - d[3] = nanclamp(y, 0.0f, 1.0f); - outSize = V_Quad; - } + // Essentially D prefix saturation is forced. + d[0] = nanclamp(t[0] + s[0], 0.0f, 1.0f); + d[1] = nanclamp(t[1] + s[1], 0.0f, 1.0f); + if (outSize == V_Quad) { + d[2] = nanclamp(t[2] + s[2], 0.0f, 1.0f); + d[3] = nanclamp(t[3] + s[3], 0.0f, 1.0f); + } + ApplyPrefixD(d, sz); WriteVector(d, outSize, vd); PC += 4; EatPrefixes(); @@ -1801,11 +1820,33 @@ bad: void Int_Vlgb(MIPSOpcode op) { - // S & D valid - Reporting::ReportMessage("vlgb not implemented"); - if (!PSP_CoreParameter().headLess) { - _dbg_assert_msg_(CPU,0,"vlgb not implemented"); + // Vector log binary (extract exponent) + int vd = _VD; + int vs = _VS; + VectorSize sz = GetVecSize(op); + + FloatBits d; + FloatBits s; + + ReadVector(s.f, sz, vs); + // TODO: Test swizzle, t? + ApplySwizzleS(s.f, sz); + + if (sz != V_Single) { + ERROR_LOG_REPORT(CPU, "vlgb not implemented for size %d", GetNumVectorElements(sz)); } + for (int i = 0; i < GetNumVectorElements(sz); ++i) { + int exp = (s.u[i] & 0x7F800000) >> 23; + if (exp == 0xFF) { + d.f[i] = s.f[i]; + } else if (exp == 0) { + d.f[i] = -INFINITY; + } else { + d.f[i] = (float)(exp - 127); + } + } + ApplyPrefixD(d.f, sz); + WriteVector(d.f, sz, vd); PC += 4; EatPrefixes(); } @@ -1886,10 +1927,31 @@ bad: void Int_Vsbz(MIPSOpcode op) { - Reporting::ReportMessage("vsbz not implemented"); - if (!PSP_CoreParameter().headLess) { - _dbg_assert_msg_(CPU,0,"vsbz not implemented"); + // Vector scale by zero (set exp to 0 to extract mantissa) + int vd = _VD; + int vs = _VS; + VectorSize sz = GetVecSize(op); + + FloatBits d; + FloatBits s; + + ReadVector(s.f, sz, vs); + // TODO: Test swizzle, t? + ApplySwizzleS(s.f, sz); + + if (sz != V_Single) { + ERROR_LOG_REPORT(CPU, "vsbz not implemented for size %d", GetNumVectorElements(sz)); } + for (int i = 0; i < GetNumVectorElements(sz); ++i) { + // NAN and denormals pass through. + if (my_isnan(s.f[i]) || (s.u[i] & 0x7F800000) == 0) { + d.u[i] = s.u[i]; + } else { + d.u[i] = (127 << 23) | (s.u[i] & 0x007FFFFF); + } + } + ApplyPrefixD(d.f, sz); + WriteVector(d.f, sz, vd); PC += 4; EatPrefixes(); } diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 3dffeea518..69e5d28afa 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -524,8 +524,8 @@ const MIPSInstruction tableVFPU0[8] = // 011000 xxx ....... . ....... . ....... { INSTR("vadd", JITFUNC(Comp_VecDo3), Dis_VectorSet3, Int_VecDo3, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vsub", JITFUNC(Comp_VecDo3), Dis_VectorSet3, Int_VecDo3, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vsbn", JITFUNC(Comp_Generic), Dis_VectorSet3, Int_Vsbn, IN_OTHER|OUT_OTHER|IS_VFPU), + // TODO: Disasm is wrong. + INSTR("vsbn", JITFUNC(Comp_Generic), Dis_VectorSet3, Int_Vsbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INVALID, INVALID, INVALID, INVALID, INSTR("vdiv", JITFUNC(Comp_VecDo3), Dis_VectorSet3, Int_VecDo3, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), @@ -577,20 +577,18 @@ const MIPSInstruction tableVFPU4Jump[32] = // 110100 xxxxx ..... . ....... . ... INVALID, INVALID, //24 - 110100 11 ........ . ....... . ....... - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), - INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vwbn.s", JITFUNC(Comp_Generic), Dis_Vwbn, Int_Vwbn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), }; const MIPSInstruction tableVFPU7[32] = // 110100 00001 xxxxx . ....... . ....... { - // TODO disasm INSTR("vrnds", JITFUNC(Comp_Generic), Dis_Vrnds, Int_Vrnds, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vrndi", JITFUNC(Comp_Generic), Dis_VrndX, Int_VrndX, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vrndf1", JITFUNC(Comp_Generic), Dis_VrndX, Int_VrndX, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), @@ -599,9 +597,7 @@ const MIPSInstruction tableVFPU7[32] = // 110100 00001 xxxxx . ....... . ....... INVALID, INVALID, INVALID, INVALID, //8 INVALID, INVALID, INVALID, INVALID, - // TODO: Flags may not be correct (prefixes, etc.) Is this the correct encoding? Others say 10110. - INSTR("vsbz", JITFUNC(Comp_Generic), Dis_Generic, Int_Vsbz, IN_OTHER|OUT_OTHER|IS_VFPU), - INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, //16 INVALID, INVALID, @@ -610,9 +606,8 @@ const MIPSInstruction tableVFPU7[32] = // 110100 00001 xxxxx . ....... . ....... INVALID, INVALID, - INVALID, - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vlgb", JITFUNC(Comp_Generic), Dis_Generic, Int_Vlgb, IN_OTHER|OUT_OTHER|IS_VFPU), + INSTR("vsbz", JITFUNC(Comp_Generic), Dis_Generic, Int_Vsbz, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vlgb", JITFUNC(Comp_Generic), Dis_Generic, Int_Vlgb, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), //24 INSTR("vuc2i", JITFUNC(Comp_Vx2i), Dis_Vs2i, Int_Vx2i, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), // Seen in BraveStory, initialization 110100 00001110000 000 0001 0000 0000 INSTR("vc2i", JITFUNC(Comp_Vx2i), Dis_Vs2i, Int_Vx2i, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), @@ -731,23 +726,18 @@ const MIPSInstruction tableVFPUMatrixSet1[16] = // 111100 11100 .xxxx . ....... const MIPSInstruction tableVFPU9[32] = // 110100 00010 xxxxx . ....... . ....... { - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vsrt1", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt1, IN_OTHER|OUT_OTHER|IS_VFPU), - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vsrt2", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt2, IN_OTHER|OUT_OTHER|IS_VFPU), + INSTR("vsrt1", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt1, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsrt2", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt2, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vbfy1", JITFUNC(Comp_Vbfy), Dis_Vbfy, Int_Vbfy, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vbfy2", JITFUNC(Comp_Vbfy), Dis_Vbfy, Int_Vbfy, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), //4 INSTR("vocp", JITFUNC(Comp_Vocp), Dis_Vbfy, Int_Vocp, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), // one's complement INSTR("vsocp", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsocp, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vfad", JITFUNC(Comp_Vhoriz), Dis_Vfad, Int_Vfad, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vavg", JITFUNC(Comp_Vhoriz), Dis_Vfad, Int_Vavg, IN_OTHER|OUT_OTHER|IS_VFPU), + INSTR("vavg", JITFUNC(Comp_Vhoriz), Dis_Vfad, Int_Vavg, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), //8 - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vsrt3", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt3, IN_OTHER|OUT_OTHER|IS_VFPU), - // TODO: Flags may not be correct (prefixes, etc.) - INSTR("vsrt4", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt4, IN_OTHER|OUT_OTHER|IS_VFPU), + INSTR("vsrt3", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt3, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), + INSTR("vsrt4", JITFUNC(Comp_Generic), Dis_Vbfy, Int_Vsrt4, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INSTR("vsgn", JITFUNC(Comp_Vsgn), Dis_Vbfy, Int_Vsgn, IN_OTHER|OUT_OTHER|IS_VFPU|OUT_EAT_PREFIX), INVALID, //12 @@ -757,9 +747,7 @@ const MIPSInstruction tableVFPU9[32] = // 110100 00010 xxxxx . ....... . ....... INVALID, //16 - // TODO: Flags may not be correct (prefixes, etc.) INSTR("vmfvc", JITFUNC(Comp_Vmfvc), Dis_Vmftvc, Int_Vmfvc, IN_OTHER|IN_VFPU_CC|OUT_OTHER|IS_VFPU), - // TODO: Flags may not be correct (prefixes, etc.) INSTR("vmtvc", JITFUNC(Comp_Vmtvc), Dis_Vmftvc, Int_Vmtvc, IN_OTHER|OUT_VFPU_CC|OUT_OTHER|IS_VFPU), INVALID, INVALID, diff --git a/Core/MIPS/x86/CompVFPU.cpp b/Core/MIPS/x86/CompVFPU.cpp index d74a1f8e3a..10a1e6e9bc 100644 --- a/Core/MIPS/x86/CompVFPU.cpp +++ b/Core/MIPS/x86/CompVFPU.cpp @@ -2026,12 +2026,24 @@ void Jit::Comp_Vocp(MIPSOpcode op) { VectorSize sz = GetVecSize(op); int n = GetNumVectorElements(sz); - u8 sregs[4], dregs[4]; + // This is a hack that modifies prefixes. We eat them later, so just overwrite. + // S prefix forces the negate flags. + js.prefixS |= 0x000F0000; + // T prefix forces constants on and regnum to 1. + // That means negate still works, and abs activates a different constant. + js.prefixT = (js.prefixT & ~0x000000FF) | 0x00000055 | 0x0000F000; + + u8 sregs[4], tregs[4], dregs[4]; + // Actually uses the T prefixes (despite being VS.) GetVectorRegsPrefixS(sregs, sz, _VS); + if (js.prefixT != 0x0000F055) + GetVectorRegsPrefixT(tregs, sz, _VS); GetVectorRegsPrefixD(dregs, sz, _VD); // Flush SIMD. fpr.SimpleRegsV(sregs, sz, 0); + if (js.prefixT != 0x0000F055) + fpr.SimpleRegsV(tregs, sz, 0); fpr.SimpleRegsV(dregs, sz, MAP_NOINIT | MAP_DIRTY); X64Reg tempxregs[4]; @@ -2048,11 +2060,17 @@ void Jit::Comp_Vocp(MIPSOpcode op) { } } - MOV(PTRBITS, R(TEMPREG), ImmPtr(&one)); - MOVSS(XMM1, MatR(TEMPREG)); + if (js.prefixT == 0x0000F055) { + MOV(PTRBITS, R(TEMPREG), ImmPtr(&one)); + MOVSS(XMM1, MatR(TEMPREG)); + } for (int i = 0; i < n; ++i) { - MOVSS(XMM0, R(XMM1)); - SUBSS(XMM0, fpr.V(sregs[i])); + if (js.prefixT == 0x0000F055) { + MOVSS(XMM0, R(XMM1)); + } else { + MOVSS(XMM0, fpr.V(tregs[i])); + } + ADDSS(XMM0, fpr.V(sregs[i])); MOVSS(tempxregs[i], R(XMM0)); } diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index 74dc3baa8d..d0bd9ae4c7 100644 --- a/Core/Util/PPGeDraw.cpp +++ b/Core/Util/PPGeDraw.cpp @@ -477,7 +477,7 @@ static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, utfWord = utfPrev; finished = true; break; - } + } } } ++numChars; @@ -549,7 +549,7 @@ static AtlasTextMetrics BreakLines(const char *text, const AtlasFont &atlasfont, } lineWidth += nextWidth; - u32 cval = utf.next(); + u32 cval = utf.end() ? 0 : utf.next(); if (spaceWidth > 0) { if (!dryRun) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 70b8de50b8..7987068d7b 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -1865,7 +1865,8 @@ Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u } textureCache_->ForgetLastTexture(); - Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, false, depth }); + bool z_stencil = reason == TempFBO::STENCIL; + Draw::Framebuffer *fbo = draw_->CreateFramebuffer({ w, h, 1, 1, z_stencil, depth }); if (!fbo) return fbo; diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 9a954c1975..04d94388ce 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -162,6 +162,8 @@ enum class TempFBO { BLIT, // For copies of framebuffers (e.g. shader blending.) COPY, + // Used to copy stencil data, means we need a stencil backing. + STENCIL, }; inline Draw::DataFormat GEFormatToThin3D(int geFormat) { diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 445414a078..142193a329 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1344,7 +1344,7 @@ void ConvertStencilFuncState(GenericStencilFuncState &state) { return; // The PSP's mask is reversed (bits not to write.) - state.writeMask = (~gstate.pmska) & 0xFF; + state.writeMask = (~gstate.getStencilWriteMask()) & 0xFF; state.sFail = gstate.getStencilOpSFail(); state.zFail = gstate.getStencilOpZFail(); diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 862ba286c6..0b5ffa11a5 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -324,6 +324,9 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade // Set some options. spirv_cross::CompilerGLSL::Options options; options.version = gl_extensions.GLSLVersion(); + // macOS OpenGL 4.1 implementation does not support GL_ARB_shading_language_420pack. + // Prevent explicit binding location emission enabled in SPIRV-Cross by default. + options.enable_420pack_extension = gl_extensions.ARB_shading_language_420pack; glsl.set_common_options(options); // Compile to GLSL, ready to give to GL driver. *dest = glsl.compile(); diff --git a/GPU/Common/ShaderUniforms.cpp b/GPU/Common/ShaderUniforms.cpp index f549f53af4..ccf5c4f5e4 100644 --- a/GPU/Common/ShaderUniforms.cpp +++ b/GPU/Common/ShaderUniforms.cpp @@ -30,16 +30,18 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo // Account for the projection viewport adjustment when viewport is too large. auto reverseViewportX = [](float x) { float pspViewport = (x - gstate.getViewportXCenter()) * (1.0f / gstate.getViewportXScale()); - return (pspViewport - gstate_c.vpXOffset) * gstate_c.vpWidthScale; + return (pspViewport * gstate_c.vpWidthScale) - gstate_c.vpXOffset; }; auto reverseViewportY = [flipViewport](float y) { float heightScale = gstate_c.vpHeightScale; + float yOffset = gstate_c.vpYOffset; if (flipViewport) { // For D3D11 and GLES non-buffered. heightScale = -heightScale; + yOffset = -yOffset; } float pspViewport = (y - gstate.getViewportYCenter()) * (1.0f / gstate.getViewportYScale()); - return (pspViewport - gstate_c.vpYOffset) * heightScale; + return (pspViewport * heightScale) - yOffset; }; auto reverseViewportZ = [hasNegZ](float z) { float vpZScale = gstate.getViewportZScale(); diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 4a77731f00..21d45951f7 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -457,7 +457,9 @@ void SoftwareTransform( // If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this. bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask(); bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask(); - if (params->allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil)) { + bool matchingComponents = params->allowSeparateAlphaClear || (alphaMatchesColor && depthMatchesStencil); + bool stencilNotMasked = !gstate.isClearModeAlphaMask() || gstate.getStencilWriteMask() == 0x00; + if (matchingComponents && stencilNotMasked) { result->color = transformed[1].color0_32; // Need to rescale from a [0, 1] float. This is the final transformed value. result->depth = ToScaledDepthFromIntegerScale((int)(transformed[1].z * 65535.0f)); diff --git a/GPU/Common/TextureDecoder.cpp b/GPU/Common/TextureDecoder.cpp index 9e896872fe..b4bf87adfa 100644 --- a/GPU/Common/TextureDecoder.cpp +++ b/GPU/Common/TextureDecoder.cpp @@ -89,7 +89,7 @@ static const u32 textureAlignMask16[16] = { u32 GetTextureBufw(int level, u32 texaddr, GETextureFormat format) { // This is a hack to allow for us to draw the huge PPGe texture, which is always in kernel ram. - if (texaddr < PSP_GetKernelMemoryEnd()) + if (texaddr >= PSP_GetKernelMemoryBase() && texaddr < PSP_GetKernelMemoryEnd()) return gstate.texbufwidth[level] & 0x1FFF; u32 bufw = gstate.texbufwidth[level] & textureAlignMask16[format]; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index e0ee48ef05..9f2c4474e9 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -127,7 +127,9 @@ GPU_D3D11::~GPU_D3D11() { void GPU_D3D11::CheckGPUFeatures() { u32 features = 0; - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + if (!PSP_CoreParameter().compat.flags().DepthRangeHack) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } features |= GPU_SUPPORTS_BLEND_MINMAX; features |= GPU_PREFER_CPU_DOWNLOAD; diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 0dc7a74e4b..9048330af4 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -330,7 +330,8 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { // A normal clear will be 2 points, the second point has the color. // We override this value in the pipeline from software transform for clear rectangles. dynState_.stencilRef = 0xFF; - keys_.depthStencil.stencilWriteMask = 0xFF; + // But we still apply the stencil write mask. + keys_.depthStencil.stencilWriteMask = (~gstate.getStencilWriteMask()) & 0xFF; } else { keys_.depthStencil.stencilTestEnable = false; dynState_.useStencil = false; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 62b3caf1c2..2a2d3ecda0 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -176,21 +176,23 @@ void GPU_DX9::CheckGPUFeatures() { features |= GPU_SUPPORTS_ACCURATE_DEPTH; } - // VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel. - // Also causes problems on old NVIDIA. - switch (vendor) { - case Draw::GPUVendor::VENDOR_INTEL: - break; - case Draw::GPUVendor::VENDOR_NVIDIA: - // Older NVIDIAs don't seem to like NaNs in their DX9 vertex shaders. - // No idea if KEPLER is the right cutoff, but let's go with it. - if (NVIDIAGetDeviceGeneration(draw_->GetDeviceCaps().deviceID) >= NV_KEPLER) { + if (!PSP_CoreParameter().compat.flags().DepthRangeHack) { + // VS range culling (killing triangles in the vertex shader using NaN) causes problems on Intel. + // Also causes problems on old NVIDIA. + switch (vendor) { + case Draw::GPUVendor::VENDOR_INTEL: + break; + case Draw::GPUVendor::VENDOR_NVIDIA: + // Older NVIDIAs don't seem to like NaNs in their DX9 vertex shaders. + // No idea if KEPLER is the right cutoff, but let's go with it. + if (NVIDIAGetDeviceGeneration(draw_->GetDeviceCaps().deviceID) >= NV_KEPLER) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } + break; + default: features |= GPU_SUPPORTS_VS_RANGE_CULLING; + break; } - break; - default: - features |= GPU_SUPPORTS_VS_RANGE_CULLING; - break; } D3DCAPS9 caps; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 4e46ecdff4..9afb204704 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -233,7 +233,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { dxstate.stencilTest.enable(); dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE); dxstate.stencilFunc.set(D3DCMP_ALWAYS, 255, 0xFF); - dxstate.stencilMask.set(0xFF); + dxstate.stencilMask.set((~gstate.getStencilWriteMask()) & 0xFF); } else { dxstate.stencilTest.disable(); } diff --git a/GPU/GLES/FragmentShaderGeneratorGLES.cpp b/GPU/GLES/FragmentShaderGeneratorGLES.cpp index e130c1a7e2..f86c608105 100644 --- a/GPU/GLES/FragmentShaderGeneratorGLES.cpp +++ b/GPU/GLES/FragmentShaderGeneratorGLES.cpp @@ -312,8 +312,13 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform // TODO: Not sure the right way to do this for projection. // This path destroys resolution on older PowerVR no matter what I do if projection is needed, // so we disable it on SGX 540 and lesser, and live with the consequences. - bool badPrecision = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_TERRIBLE) != 0; - if (needShaderTexClamp && !(doTextureProjection && badPrecision)) { + bool terriblePrecision = (gl_extensions.bugs & BUG_PVR_SHADER_PRECISION_TERRIBLE) != 0; + bool clampDisabled = doTextureProjection && terriblePrecision; + // Also with terrible precision we can't do wrapping without destroying the image. See #9189 + if (terriblePrecision && (!id.Bit(FS_BIT_CLAMP_S) || !id.Bit(FS_BIT_CLAMP_T))) { + clampDisabled = true; + } + if (needShaderTexClamp && !clampDisabled) { // We may be clamping inside a larger surface (tex = 64x64, buffer=480x272). // We may also be wrapping in such a surface, or either one in a too-small surface. // Obviously, clamping to a smaller surface won't work. But better to clamp to something. @@ -356,6 +361,7 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, uint64_t *uniform } else { if (doTextureProjection) { // We don't use textureProj because we need better control and it's probably not much of a savings anyway. + // However it is good for precision on older hardware like PowerVR. WRITE(p, " vec2 uv = %s.xy/%s.z;\n vec2 uv_round;\n", texcoord, texcoord); } else { WRITE(p, " vec2 uv = %s.xy;\n vec2 uv_round;\n", texcoord); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index bb54322f7f..967aaf6709 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -149,7 +149,9 @@ void GPU_GLES::CheckGPUFeatures() { features |= GPU_SUPPORTS_16BIT_FORMATS; if (!draw_->GetBugs().Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) { - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + if (!PSP_CoreParameter().compat.flags().DepthRangeHack) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } } if (gl_extensions.ARB_blend_func_extended || gl_extensions.EXT_blend_func_extended) { diff --git a/GPU/GLES/ShaderManagerGLES.cpp b/GPU/GLES/ShaderManagerGLES.cpp index ffafcaa362..fc62801499 100644 --- a/GPU/GLES/ShaderManagerGLES.cpp +++ b/GPU/GLES/ShaderManagerGLES.cpp @@ -828,7 +828,7 @@ std::string ShaderManagerGLES::DebugGetShaderString(std::string id, DebugShaderT // as sometimes these features might have an effect on the ID bits. #define CACHE_HEADER_MAGIC 0x83277592 -#define CACHE_VERSION 13 +#define CACHE_VERSION 14 struct CacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index e6636b87e2..a630a5d6ef 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -277,7 +277,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { framebufferManager_->SetDepthUpdated(); } renderManager->SetStencilFunc(gstate.isClearModeAlphaMask(), GL_ALWAYS, 0xFF, 0xFF); - renderManager->SetStencilOp(0xFF, GL_REPLACE, GL_REPLACE, GL_REPLACE); + renderManager->SetStencilOp((~gstate.getStencilWriteMask()) & 0xFF, GL_REPLACE, GL_REPLACE, GL_REPLACE); renderManager->SetDepth(true, gstate.isClearModeDepthMask() ? true : false, GL_ALWAYS); } else { // Depth Test diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 2e13c35885..76239b5282 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -168,7 +168,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, bool skipZe Draw::Framebuffer *blitFBO = nullptr; if (useBlit) { - blitFBO = GetTempFBO(TempFBO::COPY, w, h, Draw::FBO_8888); + blitFBO = GetTempFBO(TempFBO::STENCIL, w, h, Draw::FBO_8888); draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }); } else if (dstBuffer->fbo) { draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }); diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 13264c837c..9354e28bc5 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -88,7 +88,7 @@ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; _CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions) StreamingSIMDExtensions2 - Fast + Precise true false false @@ -109,7 +109,7 @@ Level3 ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; NotSet - Fast + Precise false true false @@ -136,7 +136,7 @@ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; false StreamingSIMDExtensions2 - Fast + Precise USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_M_IX86=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions) Speed true @@ -162,7 +162,7 @@ ..\dx9sdk\Include\DX11;../common;..;../ext;../ext/native;../ext/glew;../ext/snappy; false NotSet - Fast + Precise Speed false true @@ -390,4 +390,4 @@ - \ No newline at end of file + diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index ce64220294..0d0b9189bb 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -562,7 +562,8 @@ static inline Vec4 GetTextureFunctionOutput(const Vec4& prim_color, co const __m128 b = _mm_mul_ps(p, t); if (gstate.isColorDoublingEnabled()) { // We double right here, only for modulate. Other tex funcs do not color double. - out_rgb.ivec = _mm_cvtps_epi32(_mm_mul_ps(b, _mm_set_ps1(2.0f / 255.0f))); + const __m128 doubleColor = _mm_setr_ps(2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f, 1.0f / 255.0f); + out_rgb.ivec = _mm_cvtps_epi32(_mm_mul_ps(b, doubleColor)); } else { out_rgb.ivec = _mm_cvtps_epi32(_mm_mul_ps(b, _mm_set_ps1(1.0f / 255.0f))); } diff --git a/GPU/Vulkan/DepalettizeShaderVulkan.cpp b/GPU/Vulkan/DepalettizeShaderVulkan.cpp index 57e61fef65..b759882ad7 100644 --- a/GPU/Vulkan/DepalettizeShaderVulkan.cpp +++ b/GPU/Vulkan/DepalettizeShaderVulkan.cpp @@ -129,16 +129,18 @@ VulkanTexture *DepalShaderCacheVulkan::GetClutTexture(GEPaletteFormat clutFormat VkFormat destFormat = GetClutDestFormat(clutFormat, &componentMapping); int texturePixels = clutFormat == GE_CMODE_32BIT_ABGR8888 ? 256 : 512; + VulkanTexture *vktex = new VulkanTexture(vulkan_); + vktex->SetTag("DepalClut"); + VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); + if (!vktex->CreateDirect(cmd, alloc_, texturePixels, 1, 1, destFormat, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) { + ERROR_LOG(G3D, "Failed to create texture for CLUT"); + return nullptr; + } + VkBuffer pushBuffer; uint32_t pushOffset = push_->PushAligned(rawClut, 1024, 4, &pushBuffer); - VulkanTexture *vktex = new VulkanTexture(vulkan_, alloc_); - vktex->SetTag("DepalClut"); - VkCommandBuffer cmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); - if (!vktex->CreateDirect(cmd, texturePixels, 1, 1, destFormat, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, &componentMapping)) { - Crash(); - } vktex->UploadMip(cmd, 0, texturePixels, 1, pushBuffer, pushOffset, texturePixels); vktex->EndCreate(cmd); diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index a2a9737a31..82c2656c84 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -148,9 +148,11 @@ void DrawEngineVulkan::InitDeviceObjects() { // if creating and updating them turns out to be expensive. for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { // We now create descriptor pools on demand, so removed from here. - frame_[i].pushUBO = new VulkanPushBuffer(vulkan_, 8 * 1024 * 1024); - frame_[i].pushVertex = new VulkanPushBuffer(vulkan_, 2 * 1024 * 1024); - frame_[i].pushIndex = new VulkanPushBuffer(vulkan_, 1 * 1024 * 1024); + // Note that pushUBO is also used for tessellation data (search for SetPushBuffer), and to upload + // the null texture. This should be cleaned up... + frame_[i].pushUBO = new VulkanPushBuffer(vulkan_, 8 * 1024 * 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT); + frame_[i].pushVertex = new VulkanPushBuffer(vulkan_, 2 * 1024 * 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + frame_[i].pushIndex = new VulkanPushBuffer(vulkan_, 1 * 1024 * 1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); } VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; @@ -174,7 +176,7 @@ void DrawEngineVulkan::InitDeviceObjects() { res = vkCreateSampler(device, &samp, nullptr, &nullSampler_); assert(VK_SUCCESS == res); - vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE); + vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan_); tessDataTransfer = tessDataTransferVulkan; @@ -276,7 +278,7 @@ void DrawEngineVulkan::BeginFrame() { if (vertexCache_->GetTotalSize() > VERTEX_CACHE_SIZE) { vertexCache_->Destroy(vulkan_); delete vertexCache_; // orphans the buffers, they'll get deleted once no longer used by an in-flight frame. - vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE); + vertexCache_ = new VulkanPushBuffer(vulkan_, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); vai_.Clear(); } diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 2e87b65390..3282a812b9 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -195,9 +195,9 @@ void FramebufferManagerVulkan::MakePixelTexture(const u8 *srcPixels, GEBufferFor VkCommandBuffer initCmd = (VkCommandBuffer)draw_->GetNativeObject(Draw::NativeObject::INIT_COMMANDBUFFER); // There's only ever a few of these alive, don't need to stress the allocator with these big ones. - drawPixelsTex_ = new VulkanTexture(vulkan_, nullptr); + drawPixelsTex_ = new VulkanTexture(vulkan_); drawPixelsTex_->SetTag("DrawPixels"); - if (!drawPixelsTex_->CreateDirect(initCmd, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) { + if (!drawPixelsTex_->CreateDirect(initCmd, nullptr, width, height, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)) { // out of memory? delete drawPixelsTex_; drawPixelsTex_ = nullptr; diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp index 5ad07c0ca4..18f6c1b6c0 100644 --- a/GPU/Vulkan/GPU_Vulkan.cpp +++ b/GPU/Vulkan/GPU_Vulkan.cpp @@ -181,13 +181,19 @@ GPU_Vulkan::~GPU_Vulkan() { void GPU_Vulkan::CheckGPUFeatures() { uint32_t features = 0; - features |= GPU_SUPPORTS_VS_RANGE_CULLING; + if (!PSP_CoreParameter().compat.flags().DepthRangeHack) { + features |= GPU_SUPPORTS_VS_RANGE_CULLING; + } switch (vulkan_->GetPhysicalDeviceProperties().properties.vendorID) { case VULKAN_VENDOR_AMD: // Accurate depth is required on AMD (due to reverse-Z driver bug) so we ignore the compat flag to disable it on those. See #9545 features |= GPU_SUPPORTS_ACCURATE_DEPTH; break; + case VULKAN_VENDOR_QUALCOMM: + // Accurate depth is required on Adreno too (seems to also have a reverse-Z driver bug). + features |= GPU_SUPPORTS_ACCURATE_DEPTH; + break; case VULKAN_VENDOR_ARM: // Also required on older ARM Mali drivers, like the one on many Galaxy S7. if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || @@ -457,7 +463,8 @@ void GPU_Vulkan::InitDeviceObjects() { // Initialize framedata for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { assert(!frameData_[i].push_); - frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024); + VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + frameData_[i].push_ = new VulkanPushBuffer(vulkan_, 64 * 1024, usage); } VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); diff --git a/GPU/Vulkan/PipelineManagerVulkan.cpp b/GPU/Vulkan/PipelineManagerVulkan.cpp index 27d513aa2c..278ea2f9e1 100644 --- a/GPU/Vulkan/PipelineManagerVulkan.cpp +++ b/GPU/Vulkan/PipelineManagerVulkan.cpp @@ -135,7 +135,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip PROFILE_THIS_SCOPE("pipelinebuild"); bool useBlendConstant = false; - VkPipelineColorBlendAttachmentState blend0 = {}; + VkPipelineColorBlendAttachmentState blend0{}; blend0.blendEnable = key.blendEnable; if (key.blendEnable) { blend0.colorBlendOp = (VkBlendOp)key.blendOpColor; @@ -174,7 +174,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip dss.depthWriteEnable = key.depthWriteEnable; } - VkDynamicState dynamicStates[8]; + VkDynamicState dynamicStates[8]{}; int numDyn = 0; if (key.blendEnable && (UsesBlendConstant(key.srcAlpha) || UsesBlendConstant(key.srcColor) || UsesBlendConstant(key.destAlpha) || UsesBlendConstant(key.destColor))) { @@ -208,16 +208,14 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip ms.pSampleMask = nullptr; ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - VkPipelineShaderStageCreateInfo ss[2]; + VkPipelineShaderStageCreateInfo ss[2]{}; ss[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - ss[0].pNext = nullptr; ss[0].stage = VK_SHADER_STAGE_VERTEX_BIT; ss[0].pSpecializationInfo = nullptr; ss[0].module = vs->GetModule(); ss[0].pName = "main"; ss[0].flags = 0; ss[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - ss[1].pNext = nullptr; ss[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; ss[1].pSpecializationInfo = nullptr; ss[1].module = fs->GetModule(); @@ -252,7 +250,7 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip vertexStride = 36; } - VkVertexInputBindingDescription ibd; + VkVertexInputBindingDescription ibd{}; ibd.binding = 0; ibd.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; ibd.stride = vertexStride; @@ -297,7 +295,12 @@ static VulkanPipeline *CreateVulkanPipeline(VkDevice device, VkPipelineCache pip VkPipeline pipeline; VkResult result = vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipe, nullptr, &pipeline); if (result != VK_SUCCESS) { - _assert_msg_(G3D, false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + if (result == VK_INCOMPLETE) { + // Bad return value seen on Adreno in Burnout :( Try to ignore? + // TODO: Log all the information we can here! + } else { + _dbg_assert_msg_(G3D, false, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); + } ERROR_LOG(G3D, "Failed creating graphics pipeline! result='%s'", VulkanResultToString(result)); // Create a placeholder to avoid creating over and over if something is broken. VulkanPipeline *nullPipeline = new VulkanPipeline(); diff --git a/GPU/Vulkan/ShaderManagerVulkan.cpp b/GPU/Vulkan/ShaderManagerVulkan.cpp index e7c8e61631..d405a80b7a 100644 --- a/GPU/Vulkan/ShaderManagerVulkan.cpp +++ b/GPU/Vulkan/ShaderManagerVulkan.cpp @@ -361,7 +361,7 @@ VulkanFragmentShader *ShaderManagerVulkan::GetFragmentShaderFromModule(VkShaderM // instantaneous. #define CACHE_HEADER_MAGIC 0xff51f420 -#define CACHE_VERSION 16 +#define CACHE_VERSION 17 struct VulkanCacheHeader { uint32_t magic; uint32_t version; diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index 3fef920fca..7249cce10e 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -294,7 +294,8 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag // A normal clear will be 2 points, the second point has the color. // We override this value in the pipeline from software transform for clear rectangles. dynState.stencilRef = 0xFF; - dynState.stencilWriteMask = 0xFF; + // But we still apply the stencil write mask. + dynState.stencilWriteMask = (~gstate.getStencilWriteMask()) & 0xFF; } else { key.stencilTestEnable = false; key.stencilCompareOp = VK_COMPARE_OP_ALWAYS; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index c41d214b28..c191127bc7 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -351,7 +351,7 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFr depalShaderCache_->SetPushBuffer(drawEngine_->GetPushBufferForTextureData()); const GEPaletteFormat clutFormat = gstate.getClutPaletteFormat(); VulkanTexture *clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_); - drawEngine_->SetDepalTexture(clutTexture->GetImageView()); + drawEngine_->SetDepalTexture(clutTexture ? clutTexture->GetImageView() : VK_NULL_HANDLE); // Only point filtering enabled. samplerKey.magFilt = false; samplerKey.minFilt = false; @@ -604,7 +604,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { { delete entry->vkTex; - entry->vkTex = new VulkanTexture(vulkan_, allocator_); + entry->vkTex = new VulkanTexture(vulkan_); VulkanTexture *image = entry->vkTex; const VkComponentMapping *mapping; @@ -630,7 +630,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { snprintf(texName, sizeof(texName), "Texture%08x", entry->addr); image->SetTag(texName); - bool allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + bool allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); if (!allocSuccess && !lowMemoryMode_) { WARN_LOG_REPORT(G3D, "Texture cache ran out of GPU memory; switching to low memory mode"); lowMemoryMode_ = true; @@ -649,7 +649,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { scaleFactor = 1; actualFmt = dstFmt; - allocSuccess = image->CreateDirect(cmdInit, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); + allocSuccess = image->CreateDirect(cmdInit, allocator_, w * scaleFactor, h * scaleFactor, maxLevel + 1, actualFmt, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, mapping); } if (!allocSuccess) { diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 32129d42dd..e6e311f0e0 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -119,6 +119,9 @@ void System_SendMessage(const char *command, const char *parameter) { QCoreApplication::postEvent(emugl, new QEvent((QEvent::Type)browseFileEvent)); } else if (!strcmp(command, "browse_folder")) { QCoreApplication::postEvent(emugl, new QEvent((QEvent::Type)browseFolderEvent)); + } else if (!strcmp(command, "graphics_restart")) { + // Should find a way to properly restart the app. + qApp->exit(0); } } @@ -402,7 +405,7 @@ bool MainUI::event(QEvent *e) { if (QFile::exists(fileName)) { QDir newPath; g_Config.currentDirectory = newPath.filePath(fileName).toStdString(); - g_Config.Save(); + g_Config.Save("browseFileEvent"); NativeMessageReceived("boot", fileName.toStdString().c_str()); } diff --git a/README.md b/README.md index d9c00dc8d8..7e3ab26e2c 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,36 @@ No BIOS file required to play, PPSSPP is an "HLE" emulator. Default settings ba Also includes a really awful hack for MOHH2 multiplayer(MOHH1 works fine without it;p). ~ LunaMoo +What's new in 1.8.0 +------------------- +* Avoid crash when starting PPSSPP due to bad AMD Vulkan drivers (#11802) +* PowerVR Vulkan display corruption fixed (#11744, #11747) +* Naruto Shippuden 3 hang fixed (#11780) +* Fixes to various lighting bugs (#11567, #11574, #11577) +* Fix control issue in Sonic Rivals and Rock Band (#11878, #11798, #11879) +* Significant performance improvement in Earth Defense Force 2 (#11172) +* Fix "real clock sync" setting (helps with latency for music games - #11813) +* More speed in FF4 effects and other generated curves (#11425) +* Support for resizing Vulkan on Linux (#11451) +* Improved support for GLES on Linux/IoT (#11507, #11537, #11541, #11632, #11746, #11806, #11845) +* Percentage based frameskipping (#11523) +* DXT accuracy improved, fixing thick white line in Gran Turismo sky (#11530) +* Fix Motorstorm freeze on non-Windows (#11618) +* Faster block transfer in some games like Digimon Adventures (#11531, #11553, #11776) +* Blending optimizations and improvements (#11543, #11620) +* Improve D3D11 rendering issues (#11584) +* Change default graphics backend to D3D11 or OpenGL (#11621, #11658) +* Remove some outdated settings (#11665, #11666, #11667) +* Fix remote disc streaming with ipv6 (#11689, #11700) +* Vulkan: Workarounds for some driver bugs for 5xx series Qualcomm GPUs (#11691, #11694) +* Fix some Qt port issues with recent performance improvements (#11720, #11807, #11808) +* UWP Xbox One: fix X/Back button confusion (#11740) +* Fix Formula 1 2006 timing issue (#11767) +* Fixes and workarounds for some vertex range culling bugs that broke a few games (#11785, #11859), and disable it on older GPUs (#11712, #11773, #11787) +* Android: Allow putting PSP storage on custom paths like SD cards (#11812) +* Corrected vocp instruction, fixing models in Artdink games (#11822, #11835) +* Bundle SDL in binary for macOS builds (#11831) +* Prevent keeping games open on Windows (#11842) What's new in 1.7.3/1.7.4/1.7.5 ------------------- diff --git a/SDL/SDLGLGraphicsContext.cpp b/SDL/SDLGLGraphicsContext.cpp index 42ed9a261b..12d43f790b 100644 --- a/SDL/SDLGLGraphicsContext.cpp +++ b/SDL/SDLGLGraphicsContext.cpp @@ -27,10 +27,9 @@ static Display* g_Display = NULL; #endif static NativeWindowType g_Window = (NativeWindowType)NULL; -int8_t CheckEGLErrors(const std::string& file, uint16_t line) { +int CheckEGLErrors(const char *file, int line) { EGLenum error; - std::string errortext; - + const char *errortext = "unknown"; error = eglGetError(); switch (error) { @@ -50,7 +49,7 @@ int8_t CheckEGLErrors(const std::string& file, uint16_t line) { case EGL_BAD_NATIVE_WINDOW: errortext = "EGL_BAD_NATIVE_WINDOW"; break; default: errortext = "unknown"; break; } - printf( "ERROR: EGL Error detected in file %s at line %d: %s (0x%X)\n", file.c_str(), line, errortext.c_str(), error ); + printf( "ERROR: EGL Error %s detected in file %s at line %d (0x%X)\n", errortext, file, line, error ); return 1; } @@ -108,8 +107,13 @@ EGLConfig EGL_FindConfig(int *contextVersion) { return val; }; - int colorScore = readConfig(EGL_RED_SIZE) + readConfig(EGL_BLUE_SIZE) + readConfig(EGL_GREEN_SIZE); - int alphaScore = readConfig(EGL_ALPHA_SIZE); + // We don't want HDR modes with more than 8 bits per component. + auto readConfigMax = [&](EGLint attr, EGLint m) -> EGLint { + EGLint val = readConfig(attr); + return val > m ? 1 : val; // why not 0? + }; + int colorScore = readConfigMax(EGL_RED_SIZE, 8) + readConfigMax(EGL_BLUE_SIZE, 8) + readConfigMax(EGL_GREEN_SIZE, 8); + int alphaScore = readConfigMax(EGL_ALPHA_SIZE, 8); int depthScore = readConfig(EGL_DEPTH_SIZE); int levelScore = readConfig(EGL_LEVEL) == 0 ? 100 : 0; int samplesScore = readConfig(EGL_SAMPLES) == 0 ? 100 : 0; @@ -120,6 +124,11 @@ EGLConfig EGL_FindConfig(int *contextVersion) { EGLint caveat = readConfig(EGL_CONFIG_CAVEAT); int caveatScore = caveat == EGL_NONE ? 100 : (caveat == EGL_NON_CONFORMANT_CONFIG ? 50 : 0); +#ifndef USING_FBDEV + EGLint surfaceType = readConfig(EGL_SURFACE_TYPE); + int surfaceScore = (surfaceType & EGL_WINDOW_BIT) ? 100 : 0; +#endif + EGLint renderable = readConfig(EGL_RENDERABLE_TYPE); bool renderableGLES3 = (renderable & EGL_OPENGL_ES3_BIT_KHR) != 0; bool renderableGLES2 = (renderable & EGL_OPENGL_ES2_BIT) != 0; @@ -138,11 +147,15 @@ EGLConfig EGL_FindConfig(int *contextVersion) { int score = 0; // Here's a good place to play with the weights to pick a better config. - score += (colorScore + alphaScore) * 10; + score += colorScore * 10 + alphaScore * 2; score += depthScore * 5 + stencilScore; score += levelScore + samplesScore + sampleBufferScore + transparentScore; score += caveatScore + renderableScoreGLES + renderableScoreGL; +#ifndef USING_FBDEV + score += surfaceScore; +#endif + if (score > bestScore) { bestScore = score; best = config; @@ -154,11 +167,12 @@ EGLConfig EGL_FindConfig(int *contextVersion) { return best; } -int8_t EGL_Init() { +int8_t EGL_Init(SDL_Window *window) { int contextVersion = 0; EGLConfig eglConfig = EGL_FindConfig(&contextVersion); if (!eglConfig) { EGL_ERROR("Unable to find a usable EGL config.", true); + return 1; } EGLint contextAttributes[] = { @@ -172,22 +186,28 @@ int8_t EGL_Init() { g_eglContext = eglCreateContext(g_eglDisplay, eglConfig, nullptr, contextAttributes); if (g_eglContext == EGL_NO_CONTEXT) { EGL_ERROR("Unable to create GLES context!", true); + return 1; } #if !defined(USING_FBDEV) && !defined(__APPLE__) - //Get the SDL window handle + // Get the SDL window handle SDL_SysWMinfo sysInfo; //Will hold our Window information SDL_VERSION(&sysInfo.version); //Set SDL version + SDL_GetWindowWMInfo(window, &sysInfo); g_Window = (NativeWindowType)sysInfo.info.x11.window; #else g_Window = (NativeWindowType)NULL; #endif g_eglSurface = eglCreateWindowSurface(g_eglDisplay, eglConfig, g_Window, nullptr); - if (g_eglSurface == EGL_NO_SURFACE) + if (g_eglSurface == EGL_NO_SURFACE) { EGL_ERROR("Unable to create EGL surface!", true); + return 1; + } - if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext) != EGL_TRUE) + if (eglMakeCurrent(g_eglDisplay, g_eglSurface, g_eglSurface, g_eglContext) != EGL_TRUE) { EGL_ERROR("Unable to make GLES context current.", true); + return 1; + } return 0; } @@ -296,7 +316,10 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: SDL_ShowWindow(window); #ifdef USING_EGL - EGL_Init(); + if (EGL_Init(window) != 0) { + printf("EGL_Init() failed\n"); + return 1; + } #endif #ifndef USING_GLES2 diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 3f07c9fb6a..bab2d1bb5d 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -1,6 +1,5 @@ // SDL/EGL implementation of the framework. // This is quite messy due to platform-specific implementations and #ifdef's. -// Note: SDL1.2 implementation is deprecated and will soon be replaced by SDL2.0. // If your platform is not supported, it is suggested to use Qt instead. #include @@ -116,6 +115,9 @@ void System_SendMessage(const char *command, const char *parameter) { } else if (!strcmp(command, "finish")) { // Do a clean exit g_QuitRequested = true; + } else if (!strcmp(command, "graphics_restart")) { + // Not sure how we best do this, but do a clean exit, better than being stuck in a bad state. + g_QuitRequested = true; } } @@ -348,9 +350,9 @@ int main(int argc, char *argv[]) { SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); if (VulkanMayBeAvailable()) { - printf("Vulkan might be available.\n"); + printf("DEBUG: Vulkan might be available.\n"); } else { - printf("Vulkan is not available.\n"); + printf("DEBUG: Vulkan is not available, not using Vulkan.\n"); } int set_xres = -1; @@ -618,7 +620,7 @@ int main(int argc, char *argv[]) { #if !defined(MOBILE_DEVICE) case SDL_WINDOWEVENT: switch (event.window.event) { - case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: // better than RESIZED, more general { Uint32 window_flags = SDL_GetWindowFlags(window); bool fullscreen = (window_flags & SDL_WINDOW_FULLSCREEN); diff --git a/SDL/SDLVulkanGraphicsContext.h b/SDL/SDLVulkanGraphicsContext.h index 42883b6700..5a29e6c3df 100644 --- a/SDL/SDLVulkanGraphicsContext.h +++ b/SDL/SDLVulkanGraphicsContext.h @@ -25,16 +25,11 @@ public: } void Resize() override { - /* draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); vulkan_->DestroyObjects(); - // TODO: Take from real window dimensions - int width = 1024; - int height = 768; - vulkan_->ReinitSurface(width, height); + vulkan_->ReinitSurface(); vulkan_->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - */ } void SwapInterval(int interval) override { diff --git a/SDL/macbundle.sh b/SDL/macbundle.sh new file mode 100755 index 0000000000..53bf39ce90 --- /dev/null +++ b/SDL/macbundle.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +PPSSPP="${1}" +PPSSPPSDL="${PPSSPP}/Contents/MacOS/PPSSPPSDL" + +if [ ! -f "${PPSSPPSDL}" ]; then + echo "No such file: ${PPSSPPSDL}!" + exit 1 +fi + +SDL=$(otool -L "${PPSSPPSDL}" | grep -v @executable_path | grep -Eo /.+libSDL.+dylib) +if [ "${SDL}" = "" ]; then + echo "SDL is already bundled/unused." + exit 0 +fi + +if [ ! -f "${SDL}" ]; then + echo "Cannot locate SDL: ${SDL}!" + exit 1 +fi + +echo "Installing SDL from ${SDL}..." + +SDLNAME=$(basename "${SDL}") +mkdir -p "${PPSSPP}/Contents/Frameworks" || exit 1 +cp -r "$SDL" "${PPSSPP}/Contents/Frameworks" || exit 1 +install_name_tool -change "${SDL}" "@executable_path/../Frameworks/${SDLNAME}" "${PPSSPPSDL}" || exit 1 diff --git a/UI/ComboKeyMappingScreen.cpp b/UI/ComboKeyMappingScreen.cpp index a32d480f76..7860a49710 100644 --- a/UI/ComboKeyMappingScreen.cpp +++ b/UI/ComboKeyMappingScreen.cpp @@ -44,7 +44,7 @@ void Combo_keyScreen::CreateViews() { static const int comboKeyImages[5] = { I_1, I_2, I_3, I_4, I_5, }; - + comboselect = new ChoiceStrip(ORIENT_VERTICAL, new AnchorLayoutParams(10, 10, NONE, NONE)); comboselect->SetSpacing(10); for (int i = 0; i < 5; i++) { @@ -169,7 +169,7 @@ void Combo_keyScreen::onFinish(DialogResult result) { g_Config.iCombokey4 = arrayToInt(array); break; } - g_Config.Save(); + g_Config.Save("Combo_keyScreen::onFInish"); } UI::EventReturn Combo_keyScreen::ChoiceEventHandler::onChoiceClick(UI::EventParams &e){ diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 75dd0ed64b..058e8cda67 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -431,8 +431,8 @@ class JoystickHistoryView : public UI::InertView { public: JoystickHistoryView(int xAxis, int xDevice, int xDir, int yAxis, int yDevice, int yDir, UI::LayoutParams *layoutParams = nullptr) : UI::InertView(layoutParams), - xAxis_(xAxis), xDevice_(xDevice), xDir_(xDir), - yAxis_(yAxis), yDevice_(yDevice), yDir_(yDir), + xAxis_(xAxis), xDir_(xDir), + yAxis_(yAxis), yDir_(yDir), curX_(0.0f), curY_(0.0f), maxCount_(500) {} void Draw(UIContext &dc) override; @@ -455,10 +455,8 @@ private: }; int xAxis_; - int xDevice_; int xDir_; int yAxis_; - int yDevice_; int yDir_; float curX_; diff --git a/UI/DisplayLayoutScreen.cpp b/UI/DisplayLayoutScreen.cpp index 0ba1901811..3f5f14ef13 100644 --- a/UI/DisplayLayoutScreen.cpp +++ b/UI/DisplayLayoutScreen.cpp @@ -173,7 +173,7 @@ void DisplayLayoutScreen::resized() { } void DisplayLayoutScreen::onFinish(DialogResult reason) { - g_Config.Save(); + g_Config.Save("DisplayLayoutScreen::onFinish"); } UI::EventReturn DisplayLayoutScreen::OnCenter(UI::EventParams &e) { diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 3b921164bf..328610ac18 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -381,10 +381,7 @@ static void AfterStateBoot(SaveState::Status status, const std::string &message, void EmuScreen::sendMessage(const char *message, const char *value) { // External commands, like from the Windows UI. if (!strcmp(message, "pause") && screenManager()->topScreen() == this) { - releaseButtons(); screenManager()->push(new GamePauseScreen(gamePath_)); - } else if (!strcmp(message, "lost_focus")) { - releaseButtons(); } else if (!strcmp(message, "stop")) { // We will push MainScreen in update(). PSP_Shutdown(); @@ -420,15 +417,12 @@ void EmuScreen::sendMessage(const char *message, const char *value) { RecreateViews(); } else if (!strcmp(message, "control mapping") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - releaseButtons(); screenManager()->push(new ControlMappingScreen()); } else if (!strcmp(message, "display layout editor") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - releaseButtons(); screenManager()->push(new DisplayLayoutScreen()); } else if (!strcmp(message, "settings") && screenManager()->topScreen() == this) { UpdateUIState(UISTATE_PAUSEMENU); - releaseButtons(); screenManager()->push(new GameSettingsScreen(gamePath_)); } else if (!strcmp(message, "gpu dump next frame")) { if (gpu) @@ -1023,7 +1017,6 @@ void EmuScreen::CreateViews() { } UI::EventReturn EmuScreen::OnDevTools(UI::EventParams ¶ms) { - releaseButtons(); I18NCategory *dev = GetI18NCategory("Developer"); DevMenu *devMenu = new DevMenu(dev); if (params.v) @@ -1062,8 +1055,8 @@ void EmuScreen::update() { return; } I18NCategory *err = GetI18NCategory("Error"); - std::string errLoadingFile = err->T("Error loading file", "Could not load game"); - + std::string errLoadingFile = gamePath_ + "\n"; + errLoadingFile.append(err->T("Error loading file", "Could not load game")); errLoadingFile.append(" "); errLoadingFile.append(err->T(errorMessage_.c_str())); @@ -1082,7 +1075,6 @@ void EmuScreen::update() { // This is here to support the iOS on screen back button. if (pauseTrigger_) { pauseTrigger_ = false; - releaseButtons(); screenManager()->push(new GamePauseScreen(gamePath_)); } @@ -1394,15 +1386,6 @@ void EmuScreen::autoLoad() { } } -// TODO: Add generic loss-of-focus handling for Screens, use this. -void EmuScreen::releaseButtons() { - TouchInput input; - input.flags = TOUCH_RELEASE_ALL; - input.timestamp = time_now_d(); - input.id = 0; - touch(input); -} - void EmuScreen::resized() { RecreateViews(); } diff --git a/UI/EmuScreen.h b/UI/EmuScreen.h index 0ac62e76e7..6951afad11 100644 --- a/UI/EmuScreen.h +++ b/UI/EmuScreen.h @@ -66,8 +66,6 @@ private: void setVKeyAnalogX(int stick, int virtualKeyMin, int virtualKeyMax); void setVKeyAnalogY(int stick, int virtualKeyMin, int virtualKeyMax); - void releaseButtons(); - void autoLoad(); void checkPowerDown(); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index c1f263c71f..7070139a4c 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -88,6 +88,7 @@ bool GameInfo::Delete() { case IdentifiedFileType::ARCHIVE_RAR: case IdentifiedFileType::ARCHIVE_ZIP: case IdentifiedFileType::ARCHIVE_7Z: + case IdentifiedFileType::PPSSPP_GE_DUMP: { const std::string &fileToRemove = filePath_; File::Delete(fileToRemove); @@ -110,27 +111,11 @@ bool GameInfo::Delete() { } } -static int64_t GetDirectoryRecursiveSize(const std::string &path) { - std::vector fileInfo; - getFilesInDir(path.c_str(), &fileInfo); - int64_t sizeSum = 0; - // Note: getFileInDir does not fill in fileSize properly. - for (size_t i = 0; i < fileInfo.size(); i++) { - FileInfo finfo; - getFileInfo(fileInfo[i].fullName.c_str(), &finfo); - if (!finfo.isDirectory) - sizeSum += finfo.size; - else - sizeSum += GetDirectoryRecursiveSize(finfo.fullName); - } - return sizeSum; -} - u64 GameInfo::GetGameSizeInBytes() { switch (fileType) { case IdentifiedFileType::PSP_PBP_DIRECTORY: case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: - return GetDirectoryRecursiveSize(ResolvePBPDirectory(filePath_)); + return getDirectoryRecursiveSize(ResolvePBPDirectory(filePath_), nullptr, GETFILES_GETHIDDEN); default: return GetFileLoader()->FileSize(); @@ -229,6 +214,11 @@ bool GameInfo::LoadFromPath(const std::string &gamePath) { } std::shared_ptr GameInfo::GetFileLoader() { + if (filePath_.empty()) { + // Happens when workqueue tries to figure out priorities in PrioritizedWorkQueue::Pop(), + // because priority() calls GetFileLoader()... gnarly. + return fileLoader; + } if (!fileLoader) { fileLoader.reset(ConstructFileLoader(filePath_)); } diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index ccad4ba683..90419444fd 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -146,6 +146,7 @@ protected: // Note: this can change while loading, use GetTitle(). std::string title; + // TODO: Get rid of this shared_ptr and managae lifetime better instead. std::shared_ptr fileLoader; std::string filePath_; diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index b4c3885e1d..1653296d12 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1142,7 +1142,7 @@ void GameSettingsScreen::onFinish(DialogResult result) { Reporting::Enable(enableReports_, "report.ppsspp.org"); Reporting::UpdateConfig(); - g_Config.Save(); + g_Config.Save("GameSettingsScreen::onFinish"); if (editThenRestore_) { g_Config.unloadGameConfig(); } @@ -1215,7 +1215,7 @@ void GameSettingsScreen::CallbackMemstickFolder(bool yes) { writeDataToFile(true, pendingMemstickFolder_.c_str(), pendingMemstickFolder_.size(), memstickDirFile.c_str()); // Save so the settings, at least, are transferred. g_Config.memStickDirectory = pendingMemstickFolder_ + "/"; - g_Config.Save(); + g_Config.Save("MemstickPathChanged"); screenManager()->RecreateAllViews(); } } @@ -1227,7 +1227,7 @@ void GameSettingsScreen::CallbackRenderingBackend(bool yes) { if (yes) { // Extra save here to make sure the choice really gets saved even if there are shutdown bugs in // the GPU backend code. - g_Config.Save(); + g_Config.Save("GameSettingsScreen::RenderingBackendYes"); System_SendMessage("graphics_restart", ""); } else { g_Config.iGPUBackend = (int)GetGPUBackend(); @@ -1240,7 +1240,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) { if (yes) { // Extra save here to make sure the choice really gets saved even if there are shutdown bugs in // the GPU backend code. - g_Config.Save(); + g_Config.Save("GameSettingsScreen::RenderingDeviceYes"); System_SendMessage("graphics_restart", ""); } else { std::string *deviceNameSetting = GPUDeviceNameSetting(); @@ -1473,7 +1473,7 @@ void DeveloperToolsScreen::CreateViews() { } void DeveloperToolsScreen::onFinish(DialogResult result) { - g_Config.Save(); + g_Config.Save("DeveloperToolsScreen::onFinish"); } diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 17efb30f8d..ae7482341b 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -114,8 +114,8 @@ static bool IsTempPath(const std::string &str) { class GameButton : public UI::Clickable { public: - GameButton(const std::string &gamePath, bool gridStyle, UI::LayoutParams *layoutParams = 0) - : UI::Clickable(layoutParams), gridStyle_(gridStyle), gamePath_(gamePath), holdStart_(0), holdEnabled_(true) {} + GameButton(const std::string &gamePath, bool gridStyle, UI::LayoutParams *layoutParams = 0) + : UI::Clickable(layoutParams), gridStyle_(gridStyle), gamePath_(gamePath) {} void Draw(UIContext &dc) override; void GetContentDimensions(const UIContext &dc, float &w, float &h) const override { @@ -157,8 +157,12 @@ public: } } else if (hovering_ && key.deviceId == DEVICE_ID_MOUSE && key.keyCode == NKCODE_EXT_MOUSEBUTTON_2) { // If it's the right mouse button, and it's not otherwise mapped, show the info also. - if (key.flags & KEY_UP) { + if (key.flags & KEY_DOWN) { + showInfoPressed_ = true; + } + if ((key.flags & KEY_UP) && showInfoPressed_) { showInfo = true; + showInfoPressed_ = false; } } @@ -206,9 +210,10 @@ private: std::string gamePath_; std::string title_; - double holdStart_; - bool holdEnabled_; - bool hovering_; + double holdStart_ = 0.0; + bool holdEnabled_ = true; + bool showInfoPressed_ = false; + bool hovering_ = false; }; void GameButton::Draw(UIContext &dc) { @@ -404,7 +409,7 @@ void DirButton::Draw(UIContext &dc) { if (text == "..") { image = I_UP_DIRECTORY; } - + float tw, th; dc.MeasureText(dc.GetFontStyle(), 1.0f, 1.0f, text.c_str(), &tw, &th, 0); @@ -802,10 +807,10 @@ void MainScreen::CreateViews() { scrollHomebrew->SetTag("MainScreenHomebrew"); GameBrowser *tabAllGames = new GameBrowser(g_Config.currentDirectory, true, &g_Config.bGridView2, - mm->T("How to get games"), "http://www.ppsspp.org/getgames.html", 0, + mm->T("How to get games"), "https://www.ppsspp.org/getgames.html", 0, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); GameBrowser *tabHomebrew = new GameBrowser(GetSysDirectory(DIRECTORY_GAME), false, &g_Config.bGridView3, - mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "http://www.ppsspp.org/gethomebrew.html", + mm->T("How to get homebrew & demos", "How to get homebrew && demos"), "https://www.ppsspp.org/gethomebrew.html", FLAG_HOMEBREWSTOREBUTTON, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); @@ -904,7 +909,7 @@ 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) +#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 rightColumnItems->Add(new Choice(mm->T("Game Settings", "Settings")))->OnClick.Handle(this, &MainScreen::OnGameSettings); @@ -1203,7 +1208,7 @@ UI::EventReturn MainScreen::OnExit(UI::EventParams &e) { System_SendMessage("finish", ""); // However, let's make sure the config was saved, since it may not have been. - g_Config.Save(); + g_Config.Save("MainScreen::OnExit"); #ifdef __ANDROID__ #ifdef ANDROID_NDK_PROFILER @@ -1271,7 +1276,7 @@ void UmdReplaceScreen::CreateViews() { scrollAllGames->SetTag("UmdReplaceAllGames"); GameBrowser *tabAllGames = new GameBrowser(g_Config.currentDirectory, true, &g_Config.bGridView2, - mm->T("How to get games"), "http://www.ppsspp.org/getgames.html", 0, + mm->T("How to get games"), "https://www.ppsspp.org/getgames.html", 0, new LinearLayoutParams(FILL_PARENT, FILL_PARENT)); scrollAllGames->Add(tabAllGames); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 5ec61c052f..c615bc83d0 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -507,7 +507,7 @@ void LogoScreen::render() { int ppsspp_org_y = yres / 2 + 130; dc.DrawText("www.ppsspp.org", bounds.centerX(), ppsspp_org_y, textColor, ALIGN_CENTER); -#if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(ANDROID) +#if (defined(_WIN32) && !PPSSPP_PLATFORM(UWP)) || PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX) // Draw the graphics API, except on UWP where it's always D3D11 std::string apiName = screenManager()->getDrawContext()->GetInfoString(InfoField::APINAME); dc.DrawText(gr->T(apiName), bounds.centerX(), ppsspp_org_y + 50, textColor, ALIGN_CENTER); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index 472e11b462..0faa21db32 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -401,7 +401,7 @@ static void CheckFailedGPUBackends() { writeStringToFile(true, g_Config.sFailedGPUBackends, cache.c_str()); } else { // Just save immediately, since we have storage. - g_Config.Save(); + g_Config.Save("got storage permission"); } } @@ -415,7 +415,7 @@ static void ClearFailedGPUBackends() { if (System_GetPropertyBool(SYSPROP_SUPPORTS_PERMISSIONS)) { File::Delete(GetSysDirectory(DIRECTORY_APP_CACHE) + "/FailedGraphicsBackends.txt"); } else { - g_Config.Save(); + g_Config.Save("clearFailedGPUBackends"); } } @@ -1298,7 +1298,7 @@ void NativeShutdown() { delete host; host = nullptr; #endif - g_Config.Save(); + g_Config.Save("NativeShutdown"); // Avoid shutting this down when restarting core. if (!restarting) diff --git a/UI/ReportScreen.cpp b/UI/ReportScreen.cpp index ae10ed1660..43c50959ed 100644 --- a/UI/ReportScreen.cpp +++ b/UI/ReportScreen.cpp @@ -330,7 +330,7 @@ EventReturn ReportScreen::HandleSubmit(EventParams &e) { if (Reporting::Enable(enableReporting_, "report.ppsspp.org")) { Reporting::UpdateConfig(); - g_Config.Save(); + g_Config.Save("ReportScreen::HandleSubmit"); } std::string filename = includeScreenshot_ ? screenshotFilename_ : ""; @@ -341,7 +341,7 @@ EventReturn ReportScreen::HandleSubmit(EventParams &e) { } EventReturn ReportScreen::HandleBrowser(EventParams &e) { - const std::string url = "http://" + Reporting::ServerHost() + "/"; + const std::string url = "https://" + Reporting::ServerHost() + "/"; LaunchBrowser(url.c_str()); return EVENT_DONE; } @@ -458,7 +458,7 @@ void ReportFinishScreen::ShowSuggestions() { } UI::EventReturn ReportFinishScreen::HandleViewFeedback(UI::EventParams &e) { - const std::string url = "http://" + Reporting::ServerHost() + "/game/" + Reporting::CurrentGameID(); + const std::string url = "https://" + Reporting::ServerHost() + "/game/" + Reporting::CurrentGameID(); LaunchBrowser(url.c_str()); return EVENT_DONE; } diff --git a/UI/SavedataScreen.cpp b/UI/SavedataScreen.cpp index a017aa540d..735b57d5ed 100644 --- a/UI/SavedataScreen.cpp +++ b/UI/SavedataScreen.cpp @@ -132,8 +132,9 @@ public: : UI::LinearLayout(orientation, layoutParams) { } - void SetCompare(CompareFunc lessFunc, DoneFunc) { + void SetCompare(CompareFunc lessFunc, DoneFunc doneFunc) { lessFunc_ = lessFunc; + doneFunc_ = doneFunc; } void Update() override; @@ -336,43 +337,56 @@ bool SavedataBrowser::ByFilename(const UI::View *v1, const UI::View *v2) { return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } +static time_t GetTotalSize(const SavedataButton *b) { + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); + tm datetm; + bool success; + switch (Identify_File(fileLoader.get())) { + case IdentifiedFileType::PSP_PBP_DIRECTORY: + case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY: + return getDirectoryRecursiveSize(ResolvePBPDirectory(b->GamePath()), nullptr, GETFILES_GETHIDDEN); + + default: + return fileLoader->FileSize(); + } +} + bool SavedataBrowser::BySize(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); - std::shared_ptr g1info = g_gameInfoCache->GetInfo(nullptr, b1->GamePath(), GAMEINFO_WANTSIZE); - std::shared_ptr g2info = g_gameInfoCache->GetInfo(nullptr, b2->GamePath(), GAMEINFO_WANTSIZE); + if (GetTotalSize(b1) > GetTotalSize(b2)) + return true; + return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; +} - // They might be zero, but that's fine. - return g1info->gameSize > g2info->gameSize; +static time_t GetDateSeconds(const SavedataButton *b) { + auto fileLoader = std::unique_ptr(ConstructFileLoader(b->GamePath())); + tm datetm; + bool success; + if (Identify_File(fileLoader.get()) == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { + success = File::GetModifTime(b->GamePath() + "/PARAM.SFO", datetm); + } else { + success = File::GetModifTime(b->GamePath(), datetm); + } + + if (success) { + return mktime(&datetm); + } + return (time_t)0; } bool SavedataBrowser::ByDate(const UI::View *v1, const UI::View *v2) { const SavedataButton *b1 = static_cast(v1); const SavedataButton *b2 = static_cast(v2); - auto getDateSeconds = [&](const SavedataButton *b) { - std::shared_ptr ginfo = g_gameInfoCache->GetInfo(nullptr, b->GamePath(), 0); - tm datetm; - bool success; - if (ginfo && ginfo->fileType == IdentifiedFileType::PSP_SAVEDATA_DIRECTORY) { - success = File::GetModifTime(b->GamePath() + "/PARAM.SFO", datetm); - } else { - success = File::GetModifTime(b->GamePath(), datetm); - } - - if (success) { - return mktime(&datetm); - } - return (time_t)0; - }; - - return getDateSeconds(b1) > getDateSeconds(b2); + if (GetDateSeconds(b1) > GetDateSeconds(b2)) + return true; + return strcmp(b1->GamePath().c_str(), b2->GamePath().c_str()) < 0; } bool SavedataBrowser::SortDone() { - PrioritizedWorkQueue *wq = g_gameInfoCache->WorkQueue(); - return wq->Done(); + return true; } void SavedataBrowser::Refresh() { diff --git a/UI/TouchControlLayoutScreen.cpp b/UI/TouchControlLayoutScreen.cpp index 77ca20d956..f75332be81 100644 --- a/UI/TouchControlLayoutScreen.cpp +++ b/UI/TouchControlLayoutScreen.cpp @@ -286,7 +286,7 @@ void TouchControlLayoutScreen::resized() { } void TouchControlLayoutScreen::onFinish(DialogResult reason) { - g_Config.Save(); + g_Config.Save("TouchControlLayoutScreen::onFinish"); } UI::EventReturn TouchControlLayoutScreen::OnVisibility(UI::EventParams &e) { diff --git a/UI/TouchControlVisibilityScreen.cpp b/UI/TouchControlVisibilityScreen.cpp index 4e67d1cc5c..20c0407c8b 100644 --- a/UI/TouchControlVisibilityScreen.cpp +++ b/UI/TouchControlVisibilityScreen.cpp @@ -106,14 +106,14 @@ void TouchControlVisibilityScreen::CreateViews() { } choice->SetCentered(true); - + row->Add(choice); grid->Add(row); } } void TouchControlVisibilityScreen::onFinish(DialogResult result) { - g_Config.Save(); + g_Config.Save("TouchControlVisibilityScreen::onFinish"); } UI::EventReturn TouchControlVisibilityScreen::OnToggleAll(UI::EventParams &e) { diff --git a/UWP/Content/compat.ini b/UWP/Content/compat.ini index 00adc21e42..620f55b170 100644 --- a/UWP/Content/compat.ini +++ b/UWP/Content/compat.ini @@ -31,15 +31,31 @@ [VertexDepthRounding] # Phantasy Star Portable needs depth rounding to 16-bit precision for text to show up. # It's enough to do it at the vertex granularity. #3777 +# Phantasy Star Portable ULJM05309 = true ULUS10410 = true ULES01218 = true ULJM08023 = true ULES01218 = true -# Phantasy Star Portable 2 JP (missing text) +# Phantasy Star Portable 1 Demo +NPUH90023 = true +# Phantasy Star Portable 2 +ULES01439 = true +ULUS10529 = true ULJM05493 = true NPJH50043 = true ULJM08030 = true +NPUH90023 = true +ULJM91014 = true +NPJH90002 = true +ULJM05732 = true +NPJH50332 = true +# Phantasy Star Portable 2 JP Demo +ULJM91018 = true +NPJH90062 = true +# Phantasy Star Portable Infinity Demo +NPJH90157 = true # Infinity demo + # Puyo Puyo Fever 2 #3663 (layering) ULJM05058 = true # NBA 2K13 #6603 (menu glitches) @@ -48,6 +64,7 @@ ULJS00551 = true NPJH50713 = true ULJS00596 = true ULES01578 = true +ULUS10598 = true # Power Stone Collection #6257 (map arrow) ULES00496 = true ULUS10171 = true @@ -70,47 +87,83 @@ ULJS00454 = true # Heroes Phantasia Limited Edition Disc requires pixel depth rounding. ULJS00455 = true # Phantasy Star games flickering -# Phantasy Star Portable 1 +# Phantasy Star Portable ULJM05309 = true ULUS10410 = true ULES01218 = true ULJM08023 = true ULES01218 = true -# Phantasy Star Portable 2 JP +# Phantasy Star Portable 1 Demo +NPUH90023 = true +# Phantasy Star Portable 2 +ULES01439 = true +ULUS10529 = true ULJM05493 = true NPJH50043 = true ULJM08030 = true -# Phantasy Star Portable 1 Demo NPUH90023 = true ULJM91014 = true NPJH90002 = true +ULJM05732 = true +NPJH50332 = true # Phantasy Star Portable 2 JP Demo ULJM91018 = true NPJH90062 = true +# Phantasy Star Portable Infinity Demo +NPJH90157 = true # Infinity demo [DepthRangeHack] # Phantasy Star Portable 2 and Infinity both use viewport depth outside [0, 1]. # This gets clamped in our current implementation, but attempts to fix it run into # Other bugs, so we've restored this hack for now. +# Phantasy Star Portable +ULJM05309 = true +ULUS10410 = true +ULES01218 = true +ULJM08023 = true +ULES01218 = true +# Phantasy Star Portable 1 Demo +NPUH90023 = true +# Phantasy Star Portable 2 +ULES01439 = true +ULUS10529 = true ULJM05493 = true NPJH50043 = true ULJM08030 = true -ULES01439 = true -ULUS10529 = true -ULJM91018 = true # Infinity demo disc? -NPJH90157 = true # Infinity demo +NPUH90023 = true +ULJM91014 = true +NPJH90002 = true ULJM05732 = true NPJH50332 = true +# Phantasy Star Portable 2 JP Demo +ULJM91018 = true +NPJH90062 = true +# Phantasy Star Portable Infinity Demo +NPJH90157 = true # Infinity demo [ClearToRAM] # SOCOM Navy Seals games require this. See issue #8973. -# Navy Seals -UCUS98615 = true -ULES00038 = true -UCKS45021 = true -# Fireteam Bravo 3 -UCJS10102 = true +# Navy Seals : Tactical Strike +UCES00855 = true +UCUS98649 = true NPJG00035 = true +NPJG90068 = true +UCJS10102 = true +# Tactical Strike demo +NPUG70003 = true +# Fireteam Bravo +UCKS45021 = true +UCUS98615 = true +UCES00038 = true +ULES00038 = true +# Fireteam Bravo 2 +UCES00543 = true +UCUS98645 = true +# Fireteam Bravo 2 Demo +UCUS98677 = true +UCUS98691 = true +# Fireteam Bravo 3 +NPHG00032 = true UCUS98716 = true UCES01242 = true @@ -130,15 +183,25 @@ UCKS45022 = true ULJS19009 = true NPJH50141 = true +[DisableReadbacks] +# MotoGP copies the framebuffer to RAM every frame. We have a hack to display it directly, +# which means we don't also need a readback. +ULJS00078 = true +ULUS10153 = true +UCES00373 = true [DrawSyncEatCycles] # This replaced Crash Tag Team Racing hack to also fix Gundam games # It makes sceGeDrawSync eat a lot of cycles which can affect timing in lots of games, # might be negative for others, but happens to fix games below. # Crash Tag Team Racing needs it to pass checking memory stick screen. -ULUS10044 = true ULES00168 = true +ULES00169 = true +ULES00170 = true +ULES00171 = true +ULES00172 = true ULJM05036 = true +ULUS10044 = true # Gundam Battle Royale might need it to avoid crashes when certain Ace enemies shows up ULJS00083 = true ULKS46104 = true @@ -153,6 +216,14 @@ ULKS46183 = true ULJS00260 = true ULJS19041 = true NPJH50843 = true +# Helps with Jeanne d'Arc weird 40/40 fps problem #5154 +UCAS40129 = true +UCJS10048 = true +UCKS45033 = true +UCJS18014 = true +UCUS98700 = true +NPJG00032 = true +UCJX90019 = true [FakeMipmapChange] # This hacks separates each mipmap to independent textures to display wrong-size mipmaps. @@ -162,3 +233,321 @@ NPJH50843 = true ULJM05753 = true NPJH50348 = true ULJM06009 = true + +[RequireBufferedRendering] +# Warn the user that the game will not work and have issue, if buffered rendering is not enabled. +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true +# Midnight Club 3 : DUB edition +ULUS10021 = true +ULES00108 = true +# GTA : VCS +ULUS10160 = true +ULES00502 = true +ULJM05297 = true +ULJM05395 = true +ULJM05884 = true +NPJH50827 = true +# GTA : LCS +ULUS10041 = true +ULES00151 = true +ULJM05255 = true +ULJM05359 = true +ULJM05885 = true +NPJH50825 = true +# GOW : JP/Korean +UCJS10114 = true +UCKS45084 = true +# GOW : Ghost of Sparta +UCUS98737 = true +UCAS40323 = true +NPHG00092 = true +NPEG00044 = true +NPEG00045 = true +NPJG00120 = true +NPUG80508 = true +UCJS10114 = true +UCES01401 = true +UCES01473 = true +# GOW : Ghost of Sparta Demo +NPJG90095 = true +NPEG90035 = true +NPUG70125 = true +# GOW : Chains Of Olympus +UCAS40198 = true +UCUS98653 = true +UCES00842 = true +ULJM05438 = true +ULJM05348 = true +UCKS45084 = true +NPUG80325 = true +NPEG00023 = true +NPHG00027 = true +NPHG00028 = true +NPJH50170 = true +UCET00844 = true +# GOW: Chains of Olympus Demo +UCUS98705 = true +UCED00971 = true +UCUS98713 = true +# Daxter +UCUS98618 = true +UCES00044 = true +NPUG80329 = true +NPEG00025 = true +# Ys Seven +ULUS10551 = true +ULJM05475 = true +NPEH00065 = true +NPJH50350 = true +ULJM08041 = true +NPEH00065 = true +# The Legend of Heroes: Trails in the Sky +ULUS10540 = true +ULUS10578 = true +ULES01556 = true +ULJM05170 = true +ULJM08033 = true +NPJH50373 = true +# Grand Knights History +ULJS00394 = true +ULJS19068 = true +NPJH50518 = true +# Tactics Ogre +ULUS10565 = true +ULES01500 = true +ULJM05753 = true +NPJH50348 = true +ULJM06009 = true +UCKS45164 = true +# Metal Gear Solid : Peace Walker +ULUS10509 = true +ULES01372 = true +ULJM08038 = true +NPJH50045 = true +ULJM05630 = true +# Star Ocean : Second Evolution +ULUS10375 = true +ULES01187 = true +ULJM05591 = true +ULJM05325 = true +UCAS40203 = true +# Driver 76 +ULUS10235 = true +ULES00740 = true +# Chili Con Carnage +ULUS10216 = true +ULES00629 = true +# TODO: There are many more. + +[RequireBlockTransfer] +# Warn the user that the game will have issue graphic, if simulate block transfer is not enabled. +# Ys Seven need it to fix minimap. See issues #2928 +ULUS10551 = true +ULJM05475 = true +NPEH00065 = true +NPJH50350 = true +ULJM08041 = true +NPEH00065 = true +# The Legend of Heroes: Trails in the Sky need it to fix graphical glitch in menu screen. See issues #8053 +ULUS10540 = true +ULUS10578 = true +ULES01556 = true +ULJM05170 = true +ULJM08033 = true +NPJH50373 = true +NPUH10191 = true +NPUH10197 = true +# Grand Knights History need it to fix blackboxes on characters and flickering texture . See issues #2135 , #6099 +ULJS00394 = true +ULJS19068 = true +NPJH50518 = true +# TODO: Will add some games in the future +NPJH50686 = true # Digimon Adventures (JP, and English patches...) +ULJS00078 = true # MotoGP +ULUS10153 = true # MotoGP +UCES00373 = true # MotoGP +ULUS10551 = true # Ys Seven +ULJM05475 = true # Ys Seven JP +ULUS10549 = true # Ys Seven +NPEH00065 = true # Ys Seven +NPJH50350 = true # Ys Seven +ULJM08041 = true # Ys Seven + +[DisableAccurateDepth] +# Midnight Club: LA Remix +ULUS10383 = true +ULES01144 = true +ULJS00180 = true +ULJS00267 = true +ULJM05904 = true +NPJH50440 = true +# Midnight Club 3 : DUB edition +ULUS10021 = true +ULES00108 = true + +# Shadow of Destiny (#9545) +ULUS10459 = true +NPJH50036 = true + +# Burnout games have problems with this on Mali, and have no use for it +# Legends +ULES00125 = true +ULUS10025 = true +ULJM05228 = true +NPJH50305 = true +ULJM05049 = true +ULKS46027 = true +ULAS42019 = true + +# Dominator +ULUS10236 = true +ULES00750 = true +ULJM05242 = true +ULJM05371 = true +NPJH50304 = true +ULES00703 = true +ULAS42095 = true + +[RequireDefaultCPUClock] +# GOW : Ghost of Sparta +UCUS98737 = true +UCAS40323 = true +NPHG00092 = true +NPEG00044 = true +NPEG00045 = true +NPJG00120 = true +NPUG80508 = true +UCJS10114 = true +UCES01401 = true +UCES01473 = true +# GOW : Ghost of Sparta Demo +NPJG90095 = true +NPEG90035 = true +NPUG70125 = true + +[MGS2AcidHack] +ULES00008 = true +ULES00284 = true +ULJM05047 = true +ULKS46065 = true +ULJM08001 = true +ULJM05001 = true +ULAS42007 = true +ULUS10006 = true +ULUS10077 = true + +[SonicRivalsHack] +ULES00622 = true # SR1 +ULUS10195 = true # SR1 +ULUS10323 = true # SR2 +ULES00940 = true # SR2 +ULET00958 = true + +[BlockTransferAllowCreateFB] +NPJH50686 = true # Digimon Adventures (JP, and English patches...) +ULJS00078 = true # MotoGP +ULUS10153 = true # MotoGP +UCES00373 = true # MotoGP +ULUS10551 = true # Ys Seven +ULJM05475 = true # Ys Seven JP +ULUS10549 = true # Ys Seven +NPEH00065 = true # Ys Seven +NPJH50350 = true # Ys Seven +ULJM08041 = true # Ys Seven + +[YugiohSaveFix] +# The cause of Yu-gi-oh series 's bad save (cannot save) are load "save status" and use cwcheat, +# but the real cause still unknown. #7914 + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force +ULJM05151 = true +ULES00600 = true +ULUS10136 = true + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force 2 +ULUS10302 = true +ULJM05260 = true +ULES00925 = true +ULES00926 = true + +# Yu-Gi-Oh! Duel Monsters GX: Tag Force 3 +ULES01183 = true +ULJM05373 = true + +# Yu-Gi-Oh! 5D's Tag Force 4 +ULUS10481 = true +ULJM05479 = true +ULES01362 = true + +# Yu-Gi-Oh! 5D's Tag Force 5 +ULUS10555 = true +ULJM05734 = true +ULES01474 = true + +# Yu-Gi-Oh! 5D's Tag Force 6 +ULJM05940 = true +NPJH50794 = true + +# Yu-Gi-Oh! 5D's Tag Force +ULJM05940 = true + +# Yu-Gi-Oh! ARC-V Tag Force Special +NPJH00142 = true + +[ForceUMDDelay] +# F1 2006 won't boot at all with our standard unrealistically fast timing. +UCES00238 = true +UCJS10045 = true +# F1 2005, japan only? +UCJS10019 = true + +[ForceMax60FPS] +# The GOW games are very heavy and render as fast as they can. They benefit greatly from +# capping the framerate at 60fps. + +UCJS10114 = true +UCKS45084 = true +# GOW : Ghost of Sparta +UCUS98737 = true +UCAS40323 = true +NPHG00092 = true +NPEG00044 = true +NPEG00045 = true +NPJG00120 = true +NPUG80508 = true +UCJS10114 = true +UCES01401 = true +UCES01473 = true +# GOW : Ghost of Sparta Demo +NPEG90035 = true +NPUG70125 = true +NPJG90095 = true +# GOW : Chains Of Olympus +UCAS40198 = true +UCUS98653 = true +UCES00842 = true +ULJM05438 = true +ULJM05348 = true +UCKS45084 = true +NPUG80325 = true +NPEG00023 = true +NPHG00027 = true +NPHG00028 = true +NPJH50170 = true +UCET00844 = true +# GOW: Chains of Olympus Demo +UCUS98705 = true +UCED00971 = true +UCUS98713 = true + +# F1 2006 has extremely long loading times if we don't limit the framerate. +UCES00238 = true +UCJS10045 = true +# F1 2005, japan only? +UCJS10019 = true diff --git a/UWP/Content/gamecontrollerdb.txt b/UWP/Content/gamecontrollerdb.txt index 6f6e6363b5..ce914ffbaa 100644 --- a/UWP/Content/gamecontrollerdb.txt +++ b/UWP/Content/gamecontrollerdb.txt @@ -153,3 +153,4 @@ d814000000000000cecf000000000000,MC Cthulhu,platform:Mac OS X,leftx:,lefty:,righ 05000000380700006652000025010000,Mad Catz C.T.R.L.R ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, 03000000380700008532000010010000,MadCatz Madcatz Fightpad,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:b5,righttrigger:b7, 030000000d0f0000ee00000011010000,HORI CO.,LTD. HORIPAD mini4,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000000d0f0000c100000011010000,HORI CO.,LTD. HORIPAD S,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index 93d4ed6178..71fea8b4ac 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -21,6 +21,7 @@ #include "Common/CommonWindows.h" #include "util/text/utf8.h" #include "ext/xxhash.h" +#include "base/display.h" #include #include @@ -154,17 +155,21 @@ CtrlDisAsmView::CtrlDisAsmView(HWND _wnd) wnd=_wnd; SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this); SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL); - SetScrollRange(wnd, SB_VERT, -1,1,TRUE); + SetScrollRange(wnd, SB_VERT, -1, 1, TRUE); - charWidth = g_Config.iFontWidth; - rowHeight = g_Config.iFontHeight+2; + const float fontScale = 1.0f / g_dpi_scale_real_y; + charWidth = g_Config.iFontWidth * fontScale; + rowHeight = (g_Config.iFontHeight + 2) * fontScale; + int scaledFontHeight = g_Config.iFontHeight * fontScale; + font = CreateFont(scaledFontHeight, charWidth, 0, 0, + FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + L"Lucida Console"); + boldfont = CreateFont(scaledFontHeight, charWidth, 0, 0, + FW_DEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + L"Lucida Console"); - font = CreateFont(rowHeight-2,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, - L"Lucida Console"); - boldfont = CreateFont(rowHeight-2,charWidth,0,0,FW_DEMIBOLD,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH, - L"Lucida Console"); - curAddress=0; - showHex=false; + curAddress = 0; + showHex = false; hasFocus = false; dontRedraw = false; keyTaken = false; @@ -974,8 +979,8 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) std::string newname; truncate_cpy(name, g_symbolMap->GetLabelString(funcBegin).c_str()); if (InputBox_GetString(MainWindow::GetHInstance(), MainWindow::GetHWND(), L"New function name", name, newname)) { - g_symbolMap->SetLabelName(newname.c_str(),funcBegin); - u32 funcSize = g_symbolMap->GetFunctionSize(curAddress); + g_symbolMap->SetLabelName(newname.c_str(), funcBegin); + u32 funcSize = g_symbolMap->GetFunctionSize(funcBegin); MIPSAnalyst::RegisterFunction(funcBegin, funcSize, newname.c_str()); MIPSAnalyst::UpdateHashMap(); MIPSAnalyst::ApplyHashMap(); diff --git a/Windows/Debugger/CtrlMemView.cpp b/Windows/Debugger/CtrlMemView.cpp index ff28e1b99d..331126a00e 100644 --- a/Windows/Debugger/CtrlMemView.cpp +++ b/Windows/Debugger/CtrlMemView.cpp @@ -4,12 +4,13 @@ #include #include "Core/Config.h" -#include "../resource.h" -#include "../../Core/MemMap.h" -#include "../W32Util/Misc.h" +#include "Windows/resource.h" +#include "Core/MemMap.h" +#include "Windows/W32Util/Misc.h" #include "Windows/InputBox.h" -#include "../Main.h" -#include "../../Core/Debugger/SymbolMap.h" +#include "Windows/main.h" +#include "Core/Debugger/SymbolMap.h" +#include "base/display.h" #include "Debugger_Disasm.h" #include "DebuggerShared.h" @@ -26,19 +27,20 @@ CtrlMemView::CtrlMemView(HWND _wnd) SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL); SetScrollRange(wnd, SB_VERT, -1,1,TRUE); - rowHeight = g_Config.iFontHeight; - charWidth = g_Config.iFontWidth; - offsetPositionY = offsetLine*rowHeight; + const float fontScale = 1.0f / g_dpi_scale_real_y; + rowHeight = g_Config.iFontHeight * fontScale; + charWidth = g_Config.iFontWidth * fontScale; + offsetPositionY = offsetLine * rowHeight; - font = - CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); - underlineFont = - CreateFont(rowHeight,charWidth,0,0,FW_DONTCARE,FALSE,TRUE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); - curAddress=0; + font = CreateFont(rowHeight, charWidth, 0, 0, + FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + L"Lucida Console"); + underlineFont = CreateFont(rowHeight, charWidth, 0, 0, + FW_DONTCARE, FALSE, TRUE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + L"Lucida Console"); + curAddress = 0; debugger = 0; - + searchQuery = ""; matchAddress = -1; searching = false; diff --git a/Windows/Debugger/CtrlRegisterList.cpp b/Windows/Debugger/CtrlRegisterList.cpp index 6a9241be81..563a2b47f1 100644 --- a/Windows/Debugger/CtrlRegisterList.cpp +++ b/Windows/Debugger/CtrlRegisterList.cpp @@ -3,11 +3,12 @@ #include #include +#include "base/display.h" #include "util/text/utf8.h" -#include "../resource.h" +#include "Windows/resource.h" #include "Core/MemMap.h" -#include "../W32Util/Misc.h" -#include "../InputBox.h" +#include "Windows/W32Util/Misc.h" +#include "Windows/InputBox.h" #include "CtrlRegisterList.h" #include "Debugger_MemoryDlg.h" @@ -16,11 +17,10 @@ #include "Debugger_Disasm.h" #include "DebuggerShared.h" -#include "../main.h" +#include "Windows/main.h" static const int numCPUs = 1; -//#include "DbgHelp.h" extern HMENU g_hPopupMenus; enum { REGISTER_PC = 32, REGISTER_HI, REGISTER_LO, REGISTERS_END }; @@ -29,23 +29,22 @@ TCHAR CtrlRegisterList::szClassName[] = _T("CtrlRegisterList"); void CtrlRegisterList::init() { - WNDCLASSEX wc; - - wc.cbSize = sizeof(wc); - wc.lpszClassName = szClassName; - wc.hInstance = GetModuleHandle(0); - wc.lpfnWndProc = CtrlRegisterList::wndProc; - wc.hCursor = LoadCursor (NULL, IDC_ARROW); - wc.hIcon = 0; - wc.lpszMenuName = 0; - wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); - wc.style = CS_DBLCLKS; - wc.cbClsExtra = 0; - wc.cbWndExtra = sizeof( CtrlRegisterList * ); - wc.hIconSm = 0; - - - RegisterClassEx(&wc); + WNDCLASSEX wc; + + wc.cbSize = sizeof(wc); + wc.lpszClassName = szClassName; + wc.hInstance = GetModuleHandle(0); + wc.lpfnWndProc = CtrlRegisterList::wndProc; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hIcon = 0; + wc.lpszMenuName = 0; + wc.hbrBackground = (HBRUSH)GetSysColorBrush(COLOR_WINDOW); + wc.style = CS_DBLCLKS; + wc.cbClsExtra = 0; + wc.cbWndExtra = sizeof(CtrlRegisterList *); + wc.hIconSm = 0; + + RegisterClassEx(&wc); } void CtrlRegisterList::deinit() @@ -53,8 +52,6 @@ void CtrlRegisterList::deinit() //UnregisterClass(szClassName, hInst) } - - LRESULT CALLBACK CtrlRegisterList::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { CtrlRegisterList *ccp = CtrlRegisterList::getFrom(hwnd); @@ -109,44 +106,30 @@ LRESULT CALLBACK CtrlRegisterList::wndProc(HWND hwnd, UINT msg, WPARAM wParam, L break; case WM_GETDLGCODE: // want chars so that we can return 0 on key press and supress the beeping sound return DLGC_WANTARROWS|DLGC_WANTCHARS; - default: - break; - } - - return DefWindowProc(hwnd, msg, wParam, lParam); -} + default: + break; + } + return DefWindowProc(hwnd, msg, wParam, lParam); +} CtrlRegisterList *CtrlRegisterList::getFrom(HWND hwnd) { - return (CtrlRegisterList *)GetWindowLongPtr(hwnd, GWLP_USERDATA); + return (CtrlRegisterList *)GetWindowLongPtr(hwnd, GWLP_USERDATA); } - - - CtrlRegisterList::CtrlRegisterList(HWND _wnd) -{ - wnd=_wnd; + : wnd(_wnd) { SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)this); - //SetWindowLong(wnd, GWL_STYLE, GetWindowLong(wnd,GWL_STYLE) | WS_VSCROLL); - //SetScrollRange(wnd, SB_VERT, -1,1,TRUE); - - rowHeight=g_Config.iFontHeight; - font = CreateFont(rowHeight,g_Config.iFontWidth,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, - DEFAULT_QUALITY,DEFAULT_PITCH,L"Lucida Console"); - selecting=false; - selection=0; - category=0; - showHex=false; - cpu=0; - lastPC = 0; - lastCat0Values = NULL; - changedCat0Regs = NULL; + const float fontScale = 1.0f / g_dpi_scale_real_y; + rowHeight = g_Config.iFontHeight * fontScale; + int charWidth = g_Config.iFontWidth * fontScale; + font = CreateFont(rowHeight, charWidth, 0, 0, + FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, + L"Lucida Console"); } - CtrlRegisterList::~CtrlRegisterList() { DeleteObject(font); diff --git a/Windows/Debugger/CtrlRegisterList.h b/Windows/Debugger/CtrlRegisterList.h index fcaa78967e..123e8e0713 100644 --- a/Windows/Debugger/CtrlRegisterList.h +++ b/Windows/Debugger/CtrlRegisterList.h @@ -27,23 +27,23 @@ class CtrlRegisterList RECT rect; int rowHeight; - int selection; - int marker; - int category; + int selection = 0; + int marker = 0; + int category = 0; - int oldSelection; + int oldSelection = 0; - bool selectionChanged; - bool selecting; - bool hasFocus; - bool showHex; - DebugInterface *cpu; + bool selectionChanged = false; + bool selecting = false; + bool hasFocus = false; + bool showHex = false; + DebugInterface *cpu = nullptr; static TCHAR szClassName[]; - u32 lastPC; - u32 *lastCat0Values; - bool *changedCat0Regs; - bool ctrlDown; + u32 lastPC = 0; + u32 *lastCat0Values = nullptr; + bool *changedCat0Regs = nullptr; + bool ctrlDown = false; u32 getSelectedRegValue(char *out, size_t size); void copyRegisterValue(); @@ -79,4 +79,4 @@ public: { return cpu; } -}; \ No newline at end of file +}; diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 5a81b5ceb8..3e310bf7cb 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -159,7 +159,7 @@ void MainThreadFunc() { if (performingRestart) { // Okay, switching graphics didn't work out. Probably a driver bug - fallback to restart. // This happens on NVIDIA when switching OpenGL -> Vulkan. - g_Config.Save(); + g_Config.Save("switch_graphics_failed"); W32Util::ExitAndRestart(); } @@ -196,7 +196,7 @@ void MainThreadFunc() { g_Config.iGPUBackend = (int)nextBackend; // Clear this to ensure we try their selection. g_Config.sFailedGPUBackends.clear(); - g_Config.Save(); + g_Config.Save("save_graphics_fallback"); W32Util::ExitAndRestart(); } else { diff --git a/Windows/GPU/D3D11Context.cpp b/Windows/GPU/D3D11Context.cpp index 183a3d0529..2841c00387 100644 --- a/Windows/GPU/D3D11Context.cpp +++ b/Windows/GPU/D3D11Context.cpp @@ -145,10 +145,10 @@ bool D3D11Context::Init(HINSTANCE hInst, HWND wnd, std::string *error_message) { std::wstring title = ConvertUTF8ToWString(err->T("D3D11InitializationError", "Direct3D 11 initialization error")); bool yes = IDYES == MessageBox(hWnd_, error.c_str(), title.c_str(), MB_ICONERROR | MB_YESNO); if (yes) { - // Change the config to D3D and restart. + // Change the config to D3D9 and restart. g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9; g_Config.sFailedGPUBackends.clear(); - g_Config.Save(); + g_Config.Save("save_d3d9_fallback"); W32Util::ExitAndRestart(); } diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp index 0701ffa4aa..97540ec629 100644 --- a/Windows/GPU/WindowsGLContext.cpp +++ b/Windows/GPU/WindowsGLContext.cpp @@ -255,7 +255,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { const char *defaultError = "Insufficient OpenGL driver support detected!\n\n" "Your GPU reports that it does not support OpenGL 2.0. Would you like to try using DirectX instead?\n\n" "DirectX is currently compatible with less games, but on your GPU it may be the only choice.\n\n" - "Visit the forums at http://forums.ppsspp.org for more information.\n\n"; + "Visit the forums at https://forums.ppsspp.org for more information.\n\n"; std::wstring versionDetected = ConvertUTF8ToWString(glVersion + "\n\n"); std::wstring error = ConvertUTF8ToWString(err->T("InsufficientOpenGLDriver", defaultError)); @@ -271,7 +271,7 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) { bool d3d9 = IDYES == MessageBox(hWnd_, whichD3D9.c_str(), title.c_str(), MB_YESNO); g_Config.iGPUBackend = d3d9 ? (int)GPUBackend::DIRECT3D9 : (int)GPUBackend::DIRECT3D11; g_Config.sFailedGPUBackends.clear(); - g_Config.Save(); + g_Config.Save("save_d3d11_fallback"); W32Util::ExitAndRestart(); } diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index fbbf1ce12d..59ca85f76e 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -127,9 +127,9 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m if (g_Vulkan->DeviceExtensions().EXT_debug_utils) { int bits = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + // We're intentionally skipping VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT and + // VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, just too spammy. g_Vulkan->InitDebugUtilsCallback(&VulkanDebugUtilsCallback, bits, &g_LogOptions); } else { int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 1cdaafd629..47ef6b0aa1 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -821,25 +821,25 @@ namespace MainWindow { case ID_OPTIONS_DIRECT3D9: g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D9; - g_Config.Save(); + g_Config.Save("gpu_choice"); RestartApp(); break; case ID_OPTIONS_DIRECT3D11: g_Config.iGPUBackend = (int)GPUBackend::DIRECT3D11; - g_Config.Save(); + g_Config.Save("gpu_choice"); RestartApp(); break; case ID_OPTIONS_OPENGL: g_Config.iGPUBackend = (int)GPUBackend::OPENGL; - g_Config.Save(); + g_Config.Save("gpu_choice"); RestartApp(); break; case ID_OPTIONS_VULKAN: g_Config.iGPUBackend = (int)GPUBackend::VULKAN; - g_Config.Save(); + g_Config.Save("gpu_choice"); RestartApp(); break; @@ -1051,15 +1051,15 @@ namespace MainWindow { break; case ID_HELP_OPENWEBSITE: - ShellExecute(NULL, L"open", L"http://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", L"https://www.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_BUYGOLD: - ShellExecute(NULL, L"open", L"http://central.ppsspp.org/buygold", NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", L"https://central.ppsspp.org/buygold", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_OPENFORUM: - ShellExecute(NULL, L"open", L"http://forums.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); + ShellExecute(NULL, L"open", L"https://forums.ppsspp.org/", NULL, NULL, SW_SHOWNORMAL); break; case ID_HELP_GITHUB: diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj index 9945c91e62..27a423df46 100644 --- a/Windows/PPSSPP.vcxproj +++ b/Windows/PPSSPP.vcxproj @@ -130,7 +130,7 @@ stdafx.h;Common/DbgNew.h MultiThreadedDebug StreamingSIMDExtensions2 - Fast + Precise true false Disabled @@ -168,7 +168,7 @@ MultiThreadedDebug false NotSet - Fast + Precise true false Disabled @@ -199,7 +199,7 @@ MultiThreaded false StreamingSIMDExtensions2 - Fast + Precise Use Level3 ProgramDatabase @@ -248,7 +248,7 @@ MultiThreaded false NotSet - Fast + Precise Use Level3 ProgramDatabase @@ -587,4 +587,4 @@ - \ No newline at end of file + diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index c9e9cf2050..07237cd121 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="18000000" + android:versionName="1.8.0.0"> diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 2180522782..e638d7e2a8 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -882,11 +882,6 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) { sz_x = 0; sz_y = 0; } - // Round the size up to the nearest multiple of 4. While this may cause a tiny aspect ratio distortion, - // there's some hope that #11151 is a driver bug that might be worked around this way. If this fixes it, - // it'll be worth trying to round to a multiple of 2 instead. - sz_x = (sz_x + 3) & ~3; - sz_y = (sz_y + 3) & ~3; } extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) { diff --git a/android/jni/native-audio-so.cpp b/android/jni/native-audio-so.cpp index 4fbb492d28..607142f022 100644 --- a/android/jni/native-audio-so.cpp +++ b/android/jni/native-audio-so.cpp @@ -23,10 +23,6 @@ AudioContext::AudioContext(AndroidAudioCallback cb, int _FramesPerBuffer, int _S framesPerBuffer = 4096; sampleRate = _SampleRate; - if (sampleRate != 44100 && sampleRate != 48000) { - ELOG("Invalid sample rate %i - choosing 44100", sampleRate); - sampleRate = 44100; - } } // This callback handler is called every time a buffer finishes playing. @@ -84,10 +80,8 @@ bool OpenSLContext::Init() { result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); - SLuint32 sr = SL_SAMPLINGRATE_44_1; - if (sampleRate == 48000) { - sr = SL_SAMPLINGRATE_48; - } // Don't allow any other sample rates. + // The constants, such as SL_SAMPLINGRATE_44_1, are just 44100000. + SLuint32 sr = (SLuint32)sampleRate * 1000; SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2}; SLDataFormat_PCM format_pcm = { diff --git a/assets/compat.ini b/assets/compat.ini index d09d36147a..abad5142a2 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -460,6 +460,16 @@ ULJS00394 = true ULJS19068 = true NPJH50518 = true # TODO: Will add some games in the future +NPJH50686 = true # Digimon Adventures (JP, and English patches...) +ULJS00078 = true # MotoGP +ULUS10153 = true # MotoGP +UCES00373 = true # MotoGP +ULUS10551 = true # Ys Seven +ULJM05475 = true # Ys Seven JP +ULUS10549 = true # Ys Seven +NPEH00065 = true # Ys Seven +NPJH50350 = true # Ys Seven +ULJM08041 = true # Ys Seven [DisableAccurateDepth] # Midnight Club: LA Remix @@ -512,6 +522,9 @@ UCES01473 = true NPJG90095 = true NPEG90035 = true NPUG70125 = true +# Tekken 6 +ULES01376 = true +ULUS10466 = true [MGS2AcidHack] ULES00008 = true @@ -639,3 +652,20 @@ UCES00238 = true UCJS10045 = true # F1 2005, japan only? UCJS10019 = true + +# Tekken 6 +ULES01376 = true +ULUS10466 = 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 +# to remove this in the future. +# See #3854. +# Tony Hawk's Underground +ULUS10014 = true +ULES00033 = true +ULES00034 = true +ULES00035 = true +# MTX MotoTrax +ULUS10138 = true diff --git a/assets/gamecontrollerdb.txt b/assets/gamecontrollerdb.txt index 885bb1c744..a4a6c7e528 100644 --- a/assets/gamecontrollerdb.txt +++ b/assets/gamecontrollerdb.txt @@ -191,3 +191,4 @@ bd1200000000000015d0000000000000,Tomee SNES USB Controller,x:b3,a:b2,b:b1,y:b0,b 05000000c82d00000161000000010000,8Bitdo SN30 Pro,platform:Linux,a:b1,b:b0,x:b4,y:b3,back:b10,guide:b2,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, 03000000380700008532000010010000,MadCatz Madcatz Fightpad,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:b5,righttrigger:b7, 030000000d0f0000ee00000011010000,HORI CO.,LTD. HORIPAD mini4,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000000d0f0000c100000011010000,HORI CO.,LTD. HORIPAD S,platform:Linux,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, diff --git a/b.sh b/b.sh index fc0d02d50e..1812333e88 100755 --- a/b.sh +++ b/b.sh @@ -16,6 +16,12 @@ do --ios) CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/ios.cmake ${CMAKE_ARGS}" TARGET_OS=iOS ;; + --rpi-armv6) + CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/raspberry.armv6.cmake ${CMAKE_ARGS}" + ;; + --rpi) + CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=cmake/Toolchains/raspberry.armv7.cmake ${CMAKE_ARGS}" + ;; --android) CMAKE_ARGS="-DCMAKE_TOOLCHAIN_FILE=android/android.toolchain.cmake ${CMAKE_ARGS}" TARGET_OS=Android PACKAGE=1 diff --git a/build.gradle b/build.gradle index 62ec80d1ce..7b7c94e172 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.3.1' + classpath 'com.android.tools.build:gradle:3.3.2' } } diff --git a/cmake/Toolchains/raspberry.armv6.cmake b/cmake/Toolchains/raspberry.armv6.cmake index 3d93462dab..6167d90f73 100644 --- a/cmake/Toolchains/raspberry.armv6.cmake +++ b/cmake/Toolchains/raspberry.armv6.cmake @@ -23,4 +23,4 @@ set(OPENGL_LIBRARIES brcmGLESv2 bcm_host) set(EGL_LIBRARIES brcmEGL) set(USING_GLES2 ON) set(USING_FBDEV ON) - +set(USE_WAYLAND_WSI OFF) diff --git a/cmake/Toolchains/raspberry.armv7.cmake b/cmake/Toolchains/raspberry.armv7.cmake index eaff3d479d..31b8b77c96 100644 --- a/cmake/Toolchains/raspberry.armv7.cmake +++ b/cmake/Toolchains/raspberry.armv7.cmake @@ -25,3 +25,4 @@ set(EGL_LIBRARIES brcmEGL) set(USING_GLES2 ON) set(USING_FBDEV ON) set(ARMV7 ON) +set(USE_WAYLAND_WSI OFF) diff --git a/ext/glew/CMakeLists.txt b/ext/glew/CMakeLists.txt index 60b1c69b08..f147939a92 100644 --- a/ext/glew/CMakeLists.txt +++ b/ext/glew/CMakeLists.txt @@ -1,5 +1,5 @@ find_package(GLEW) -if(GLEW_FOUND) +if(NOT APPLE AND GLEW_FOUND) add_library(system_glew INTERFACE) add_library(Ext::GLEW ALIAS system_glew) target_link_libraries(system_glew INTERFACE GLEW::GLEW) diff --git a/ext/libkirk/libkirk.vcxproj b/ext/libkirk/libkirk.vcxproj index bdaa0b01c3..c26a53464b 100644 --- a/ext/libkirk/libkirk.vcxproj +++ b/ext/libkirk/libkirk.vcxproj @@ -107,7 +107,7 @@ true false StreamingSIMDExtensions2 - Fast + Precise _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS Speed true @@ -160,4 +160,4 @@ - \ No newline at end of file + diff --git a/ext/native/file/file_util.cpp b/ext/native/file/file_util.cpp index 0882213e9b..2d6c6df33c 100644 --- a/ext/native/file/file_util.cpp +++ b/ext/native/file/file_util.cpp @@ -297,6 +297,22 @@ size_t getFilesInDir(const char *directory, std::vector *files, const return foundEntries; } +int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter, int flags) { + std::vector fileInfo; + getFilesInDir(path.c_str(), &fileInfo, filter, flags); + int64_t sizeSum = 0; + // Note: getFileInDir does not fill in fileSize properly. + for (size_t i = 0; i < fileInfo.size(); i++) { + FileInfo finfo; + getFileInfo(fileInfo[i].fullName.c_str(), &finfo); + if (!finfo.isDirectory) + sizeSum += finfo.size; + else + sizeSum += getDirectoryRecursiveSize(finfo.fullName, filter, flags); + } + return sizeSum; +} + #ifdef _WIN32 // Returns a vector with the device names std::vector getWindowsDrives() diff --git a/ext/native/file/file_util.h b/ext/native/file/file_util.h index 587b7b93fc..b6c414139b 100644 --- a/ext/native/file/file_util.h +++ b/ext/native/file/file_util.h @@ -34,7 +34,8 @@ FILE *openCFile(const std::string &filename, const char *mode); enum { GETFILES_GETHIDDEN = 1 }; -size_t getFilesInDir(const char *directory, std::vector *files, const char *filter = 0, int flags = 0); +size_t getFilesInDir(const char *directory, std::vector *files, const char *filter = nullptr, int flags = 0); +int64_t getDirectoryRecursiveSize(const std::string &path, const char *filter = nullptr, int flags = 0); #ifdef _WIN32 std::vector getWindowsDrives(); diff --git a/ext/native/file/path.h b/ext/native/file/path.h index 42a291b032..b54e9be494 100644 --- a/ext/native/file/path.h +++ b/ext/native/file/path.h @@ -25,7 +25,7 @@ public: else return ""; } - std::string GetFriendlyPath() { + std::string GetFriendlyPath() const { std::string str = GetPath(); #if defined(__ANDROID__) // Do nothing diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp index 3d81f59287..3f8a56b014 100644 --- a/ext/native/gfx_es2/gpu_features.cpp +++ b/ext/native/gfx_es2/gpu_features.cpp @@ -99,7 +99,10 @@ void ProcessGPUFeatures() { DLOG("Checking for GL driver bugs... vendor=%i model='%s'", (int)gl_extensions.gpuVendor, gl_extensions.model); if (gl_extensions.gpuVendor == GPU_VENDOR_IMGTEC) { - if (!strcmp(gl_extensions.model, "PowerVR SGX 543") || + if (!strcmp(gl_extensions.model, "PowerVR SGX 545") || + !strcmp(gl_extensions.model, "PowerVR SGX 544") || + !strcmp(gl_extensions.model, "PowerVR SGX 544MP2") || + !strcmp(gl_extensions.model, "PowerVR SGX 543") || !strcmp(gl_extensions.model, "PowerVR SGX 540") || !strcmp(gl_extensions.model, "PowerVR SGX 530") || !strcmp(gl_extensions.model, "PowerVR SGX 520") ) { @@ -335,6 +338,7 @@ void CheckGLExtensions() { gl_extensions.EXT_blend_func_extended = g_set_gl_extensions.count("GL_EXT_blend_func_extended") != 0; gl_extensions.ARB_conservative_depth = g_set_gl_extensions.count("GL_ARB_conservative_depth") != 0; gl_extensions.ARB_shader_image_load_store = (g_set_gl_extensions.count("GL_ARB_shader_image_load_store") != 0) || (g_set_gl_extensions.count("GL_EXT_shader_image_load_store") != 0); + gl_extensions.ARB_shading_language_420pack = (g_set_gl_extensions.count("GL_ARB_shading_language_420pack") != 0); gl_extensions.EXT_bgra = g_set_gl_extensions.count("GL_EXT_bgra") != 0; gl_extensions.EXT_gpu_shader4 = g_set_gl_extensions.count("GL_EXT_gpu_shader4") != 0; gl_extensions.NV_framebuffer_blit = g_set_gl_extensions.count("GL_NV_framebuffer_blit") != 0; diff --git a/ext/native/gfx_es2/gpu_features.h b/ext/native/gfx_es2/gpu_features.h index 94ba18912a..95a57f095b 100644 --- a/ext/native/gfx_es2/gpu_features.h +++ b/ext/native/gfx_es2/gpu_features.h @@ -57,6 +57,7 @@ struct GLExtensions { bool ARB_blend_func_extended; // dual source blending bool EXT_blend_func_extended; // dual source blending (GLES, new 2015) bool ARB_shader_image_load_store; + bool ARB_shading_language_420pack; bool ARB_conservative_depth; bool ARB_copy_image; bool ARB_vertex_array_object; diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index 405888b732..ba5a926d8b 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -131,7 +131,7 @@ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); StreamingSIMDExtensions2 - Fast + Precise true false MultiThreaded @@ -158,7 +158,7 @@ _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) ..\..\ext;..\..;..\..\dx9sdk\Include;..\..\dx9sdk\Include\DX11;..\zlib;..\ext\zlib;..\native;..\RollerballGL;..\glew;..\SDL\include;..\native\ext;%(AdditionalIncludeDirectories); NotSet - Fast + Precise true false MultiThreaded @@ -337,9 +337,9 @@ Speed false StreamingSIMDExtensions2 - Fast + Precise StreamingSIMDExtensions2 - Fast + Precise MaxSpeed MaxSpeed Default @@ -773,4 +773,4 @@ - \ No newline at end of file + diff --git a/ext/native/net/sinks.cpp b/ext/native/net/sinks.cpp index e011f33453..d9bf32d9d0 100644 --- a/ext/native/net/sinks.cpp +++ b/ext/native/net/sinks.cpp @@ -25,6 +25,11 @@ #include "net/sinks.h" #include "file/fd_util.h" +#ifndef MSG_NOSIGNAL +// Default value to 0x00 (do nothing) in systems where it's not supported +#define MSG_NOSIGNAL 0 +#endif + namespace net { InputSink::InputSink(size_t fd) : fd_(fd), read_(0), write_(0), valid_(0) { @@ -243,7 +248,7 @@ size_t OutputSink::PushAtMost(const char *buf, size_t bytes) { if (valid_ == 0 && bytes > PRESSURE) { // Special case for pushing larger buffers: let's try to send directly. - int sentBytes = send(fd_, buf, (int)bytes, 0); + int sentBytes = send(fd_, buf, (int)bytes, MSG_NOSIGNAL); // If it was 0 or EWOULDBLOCK, that's fine, we'll enqueue as we can. if (sentBytes > 0) { return sentBytes; @@ -325,7 +330,7 @@ bool OutputSink::Flush(bool allowBlock) { while (valid_ > 0) { size_t avail = std::min(BUFFER_SIZE - read_, valid_); - int bytes = send(fd_, buf_ + read_, (int)avail, 0); + int bytes = send(fd_, buf_ + read_, (int)avail, MSG_NOSIGNAL); AccountDrain(bytes); if (bytes == 0) { @@ -353,7 +358,7 @@ void OutputSink::Drain() { // Let's just do contiguous valid. size_t avail = std::min(BUFFER_SIZE - read_, valid_); - int bytes = send(fd_, buf_ + read_, (int)avail, 0); + int bytes = send(fd_, buf_ + read_, (int)avail, MSG_NOSIGNAL); AccountDrain(bytes); } } diff --git a/ext/native/net/url.cpp b/ext/native/net/url.cpp index a2735cf124..32311c4354 100644 --- a/ext/native/net/url.cpp +++ b/ext/native/net/url.cpp @@ -83,8 +83,8 @@ std::string UriDecode(const std::string & sSrc) if (*pSrc == '%') { char dec1, dec2; - if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)]) - && -1 != (dec2 = HEX2DEC[*(pSrc + 2)])) + if (N1 != (dec1 = HEX2DEC[*(pSrc + 1)]) + && N1 != (dec2 = HEX2DEC[*(pSrc + 2)])) { *pEnd++ = (dec1 << 4) + dec2; pSrc += 3; diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 4de46705be..9ca8d67efc 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -249,6 +249,9 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { VkSubpassDependency deps[2]{}; int numDeps = 0; switch (key.prevColorLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + // No need to specify stage or access. + break; case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: // Already the right color layout. Unclear that we need to do a lot here.. break; @@ -275,6 +278,9 @@ VkRenderPass VulkanQueueRunner::GetRenderPass(const RPKey &key) { } switch (key.prevDepthLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + // No need to specify stage or access. + break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: // Already the right depth layout. Unclear that we need to do a lot here.. break; diff --git a/ext/native/thin3d/VulkanRenderManager.cpp b/ext/native/thin3d/VulkanRenderManager.cpp index dc76d4f32d..ddf44c0ebb 100644 --- a/ext/native/thin3d/VulkanRenderManager.cpp +++ b/ext/native/thin3d/VulkanRenderManager.cpp @@ -868,7 +868,9 @@ void VulkanRenderManager::BeginSubmitFrame(int frame) { VkResult res = vkAcquireNextImageKHR(vulkan_->GetDevice(), vulkan_->GetSwapchain(), UINT64_MAX, acquireSemaphore_, (VkFence)VK_NULL_HANDLE, &frameData.curSwapchainImage); if (res == VK_SUBOPTIMAL_KHR) { // Hopefully the resize will happen shortly. Ignore - one frame might look bad or something. + WLOG("VK_SUBOPTIMAL_KHR returned - ignoring"); } else if (res == VK_ERROR_OUT_OF_DATE_KHR) { + WLOG("VK_ERROR_OUT_OF_DATE_KHR returned - not presenting"); frameData.skipSwap = true; } else { _assert_msg_(G3D, res == VK_SUCCESS, "vkAcquireNextImageKHR failed! result=%s", VulkanResultToString(res)); diff --git a/ext/native/thin3d/VulkanRenderManager.h b/ext/native/thin3d/VulkanRenderManager.h index a01482b69e..cfac32d75c 100644 --- a/ext/native/thin3d/VulkanRenderManager.h +++ b/ext/native/thin3d/VulkanRenderManager.h @@ -118,6 +118,7 @@ public: void SetViewport(const VkViewport &vp) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(G3D, (int)vp.width >= 0); VkRenderData data{ VKRRenderCommand::VIEWPORT }; data.viewport.vp.x = vp.x; data.viewport.vp.y = vp.y; @@ -132,6 +133,8 @@ public: void SetScissor(const VkRect2D &rc) { _dbg_assert_(G3D, curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); + _dbg_assert_(G3D, (int)rc.extent.width >= 0); + _dbg_assert_(G3D, (int)rc.extent.height >= 0); VkRenderData data{ VKRRenderCommand::SCISSOR }; data.scissor.scissor = rc; curRenderStep_->commands.push_back(data); diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 1ff74d1d5a..1479a7367b 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -630,11 +630,11 @@ static inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode VulkanTexture *VKContext::GetNullTexture() { if (!nullTexture_) { VkCommandBuffer cmdInit = renderManager_.GetInitCmd(); - nullTexture_ = new VulkanTexture(vulkan_, allocator_); + nullTexture_ = new VulkanTexture(vulkan_); nullTexture_->SetTag("Null"); int w = 8; int h = 8; - nullTexture_->CreateDirect(cmdInit, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + nullTexture_->CreateDirect(cmdInit, allocator_, w, h, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); uint32_t bindOffset; VkBuffer bindBuf; @@ -713,7 +713,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur width_ = desc.width; height_ = desc.height; depth_ = desc.depth; - vkTex_ = new VulkanTexture(vulkan_, alloc); + vkTex_ = new VulkanTexture(vulkan_); vkTex_->SetTag(desc.tag); VkFormat vulkanFormat = DataFormatToVulkan(format_); int bpp = GetBpp(vulkanFormat); @@ -723,7 +723,7 @@ bool VKTexture::Create(VkCommandBuffer cmd, VulkanPushBuffer *push, const Textur // Gonna have to generate some, which requires TRANSFER_SRC usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } - if (!vkTex_->CreateDirect(cmd, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) { + if (!vkTex_->CreateDirect(cmd, alloc, width_, height_, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits)) { ELOG("Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_); return false; } @@ -814,7 +814,8 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) p.queueFamilyIndex = vulkan->GetGraphicsQueueFamilyIndex(); for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) { - frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024); + VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024, usage); VkResult res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[i].descriptorPool); _assert_(res == VK_SUCCESS); } diff --git a/ext/native/ui/screen.cpp b/ext/native/ui/screen.cpp index 9f88c02bb1..8d86f10a6b 100644 --- a/ext/native/ui/screen.cpp +++ b/ext/native/ui/screen.cpp @@ -1,5 +1,6 @@ #include "base/display.h" #include "base/logging.h" +#include "base/timeutil.h" #include "input/input_state.h" #include "ui/screen.h" #include "ui/ui.h" @@ -71,30 +72,46 @@ void ScreenManager::switchToNext() { bool ScreenManager::touch(const TouchInput &touch) { std::lock_guard guard(inputLock_); - if (!stack_.empty()) { + bool result = false; + // Send release all events to every screen layer. + if (touch.flags & TOUCH_RELEASE_ALL) { + for (auto &layer : stack_) { + Screen *screen = layer.screen; + result = layer.screen->touch(screen->transformTouch(touch)); + } + } else if (!stack_.empty()) { Screen *screen = stack_.back().screen; - return screen->touch(screen->transformTouch(touch)); - } else { - return false; + result = stack_.back().screen->touch(screen->transformTouch(touch)); } + return result; } bool ScreenManager::key(const KeyInput &key) { std::lock_guard guard(inputLock_); - if (!stack_.empty()) { - return stack_.back().screen->key(key); - } else { - return false; + bool result = false; + // Send key up to every screen layer. + if (key.flags & KEY_UP) { + for (auto &layer : stack_) { + result = layer.screen->key(key); + } + } else if (!stack_.empty()) { + result = stack_.back().screen->key(key); } + return result; } bool ScreenManager::axis(const AxisInput &axis) { std::lock_guard guard(inputLock_); - if (!stack_.empty()) { - return stack_.back().screen->axis(axis); - } else { - return false; + bool result = false; + // Send center axis to every screen layer. + if (axis.value == 0) { + for (auto &layer : stack_) { + result = layer.screen->axis(axis); + } + } else if (!stack_.empty()) { + result = stack_.back().screen->axis(axis); } + return result; } void ScreenManager::deviceLost() { @@ -158,6 +175,13 @@ void ScreenManager::render() { void ScreenManager::sendMessage(const char *msg, const char *value) { if (!strcmp(msg, "recreateviews")) RecreateAllViews(); + if (!strcmp(msg, "lost_focus")) { + TouchInput input; + input.flags = TOUCH_RELEASE_ALL; + input.timestamp = time_now_d(); + input.id = 0; + touch(input); + } if (!stack_.empty()) stack_.back().screen->sendMessage(msg, value); } @@ -188,7 +212,15 @@ void ScreenManager::push(Screen *screen, int layerFlags) { if (screen->isTransparent()) { layerFlags |= LAYER_TRANSPARENT; } - UI::SetFocusedView(0); + + // Release touches and unfocus. + UI::SetFocusedView(nullptr); + TouchInput input; + input.flags = TOUCH_RELEASE_ALL; + input.timestamp = time_now_d(); + input.id = 0; + touch(input); + Layer layer = {screen, layerFlags}; stack_.push_back(layer); } diff --git a/ext/native/ui/ui_context.cpp b/ext/native/ui/ui_context.cpp index 0106888ec4..b5f7ba204f 100644 --- a/ext/native/ui/ui_context.cpp +++ b/ext/native/ui/ui_context.cpp @@ -1,4 +1,7 @@ #include "ppsspp_config.h" + +#include + #include "base/display.h" #include "ui/ui.h" #include "ui/view.h" @@ -111,8 +114,8 @@ void UIContext::ActivateTopScissor() { bounds = scissorStack_.back(); int x = floorf(scale_x * bounds.x); int y = floorf(scale_y * bounds.y); - int w = ceilf(scale_x * bounds.w); - int h = ceilf(scale_y * bounds.h); + int w = std::max(0.0f, ceilf(scale_x * bounds.w)); + int h = std::max(0.0f, ceilf(scale_y * bounds.h)); draw_->SetScissorRect(x, y, w, h); } else { // Avoid rounding errors diff --git a/ext/zlib/zlib.vcxproj b/ext/zlib/zlib.vcxproj index 81d64dcaae..6595864711 100644 --- a/ext/zlib/zlib.vcxproj +++ b/ext/zlib/zlib.vcxproj @@ -105,7 +105,7 @@ Level3 _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) StreamingSIMDExtensions2 - Fast + Precise Default true false @@ -127,7 +127,7 @@ _CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) false NotSet - Fast + Precise Default true false @@ -152,7 +152,7 @@ _CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) StreamingSIMDExtensions2 false - Fast + Precise Speed AnySuitable true @@ -180,7 +180,7 @@ Speed false NotSet - Fast + Precise true false MultiThreaded @@ -196,4 +196,4 @@ - \ No newline at end of file + diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj index 5be939c78c..f2c47e75ad 100644 --- a/headless/Headless.vcxproj +++ b/headless/Headless.vcxproj @@ -96,7 +96,7 @@ ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native EnableFastChecks StreamingSIMDExtensions2 - Fast + Precise true false false @@ -127,7 +127,7 @@ _CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions) ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native NotSet - Fast + Precise false true false @@ -162,7 +162,7 @@ ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native false StreamingSIMDExtensions2 - Fast + Precise Speed true false @@ -196,7 +196,7 @@ ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native false NotSet - Fast + Precise Speed false true @@ -281,4 +281,4 @@ - \ No newline at end of file + diff --git a/libretro/jni/Android.mk b/libretro/jni/Android.mk index 5e4ae68400..e9b773c024 100644 --- a/libretro/jni/Android.mk +++ b/libretro/jni/Android.mk @@ -74,7 +74,7 @@ include $(CORE_DIR)/libretro/Makefile.common COREFLAGS += -DINLINE="inline" -DPPSSPP -DUSE_FFMPEG -DMOBILE_DEVICE -DBAKE_IN_GIT -DDYNAREC -D__LIBRETRO__ -DUSING_GLES2 -D__STDC_CONSTANT_MACROS -DGLEW_NO_GLU $(INCFLAGS) LOCAL_SRC_FILES = $(SOURCES_CXX) $(SOURCES_C) $(ASMFILES) LOCAL_CPPFLAGS := -Wall -std=gnu++11 $(COREFLAGS) -DSPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS -LOCAL_CFLAGS := -O2 -ffast-math -DANDROID $(COREFLAGS) +LOCAL_CFLAGS := -O2 -DANDROID $(COREFLAGS) LOCAL_LDLIBS += -lz -llog -lGLESv2 -lEGL -latomic LOCAL_STATIC_LIBRARIES += $(FFMPEGLIBS)