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)