diff --git a/.gitignore b/.gitignore
index ad32797a1f..cb1af7b298 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@
*.exp
*.qdact
controls.ini
+desktop.ini
Debug
Release
Windows/.vs
diff --git a/.travis.sh b/.travis.sh
index bee6b0930b..5e6afecd23 100644
--- a/.travis.sh
+++ b/.travis.sh
@@ -4,6 +4,7 @@ export USE_CCACHE=1
export NDK_CCACHE=ccache
export HOMEBREW_NO_INSTALL_CLEANUP=1
export HOMEBREW_NO_AUTO_UPDATE=1
+export HOMEBREW_NO_ANALYTICS=1
NDK_VER=android-ndk-r18b
download_extract() {
@@ -20,26 +21,61 @@ download_extract_zip() {
unzip $2 2>&1 | pv > /dev/null
}
+brew_make_bottle() {
+ echo "Rebuilding $1 as bottle..."
+ brew uninstall -f --ignore-dependencies $1 && brew install --ignore-dependencies --build-bottle $1 || true
+ brew bottle $1 && brew postinstall $1 || true
+ rm $HOME/Library/Caches/Homebrew/$1-*.bottle.*.tar.gz || true
+ mv ./$1-*.bottle.*.tar.gz $HOME/Library/Caches/Homebrew/ || true
+}
+
travis_before_install() {
git submodule update --init --recursive
if [ "$TRAVIS_OS_NAME" = osx ]; then
# Depends on Python, wastes time updating...
- brew uninstall -f mercurial
+ brew uninstall -f mercurial || true
- for PKG in openssl@1.1 readline pkg-config gdbm sqlite xz python sdl2; do
- if [ -f $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz ]; then
- brew upgrade $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz || brew install -f $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz || true
+ # To check version numbers, we want jq. Try to cache this too.
+ for PKG in automake oniguruma; do
+ if ! brew info --json $PKG | grep built_as_bottle > /dev/null; then
+ if [ -f $HOME/Library/Caches/Homebrew/$PKG*.bottle.*.tar.gz ]; then
+ brew install -f $HOME/Library/Caches/Homebrew/$PKG*.bottle.*.tar.gz || true
+ else
+ brew_make_bottle $PKG
+ fi
+ fi
+ done
+ brew install jq || true
+
+ # Try to install as many at once as possible.
+ TO_UPGRADE=""
+ TO_UNINSTALL=""
+ for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do
+ PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`"
+ if [ -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then
+ TO_UPGRADE="$TO_UPGRADE $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz"
+ TO_UNINSTALL="$TO_UNINSTALL $PKG"
fi
done
- for PKG in openssl@1.1 readline pkg-config gdbm sqlite xz python sdl2; do
- if [ ! -f $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz ]; then
- echo "Rebuilding $PKG as bottle..."
- brew uninstall -f --ignore-dependencies $PKG && brew install --build-bottle $PKG || true
- brew bottle $PKG && brew postinstall $PKG || true
- rm $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz || true
- mv ./$PKG-*.bottle.*.tar.gz $HOME/Library/Caches/Homebrew/ || true
+ for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do
+ PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`"
+ if [ ! -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then
+ brew_make_bottle $PKG
+ fi
+ done
+
+ if [ "$TO_UPGRADE" != "" ]; then
+ brew uninstall -f --ignore-dependencies $TO_UNINSTALL
+ brew install -f --ignore-dependencies $TO_UPGRADE || true
+ fi
+
+ # In case there were issues with all at once, now let's try installing any others from cache.
+ for PKG in ccache openssl@1.1 pyenv pkg-config readline gdbm sqlite xz python sdl2; do
+ PKG_VER="`brew info $PKG --json | jq '.[0].versions.stable' | tr -d '"'`"
+ if [ -f $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz ]; then
+ brew upgrade $HOME/Library/Caches/Homebrew/$PKG--$PKG_VER*.bottle.*.tar.gz || brew install -f $HOME/Library/Caches/Homebrew/$PKG-*.bottle.*.tar.gz || true
fi
done
fi
diff --git a/.travis.yml b/.travis.yml
index 28e548611e..b5fc79998f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,8 @@
# https://travis-ci.org
-sudo: required
-
language: cpp
+os: linux
dist: xenial
addons:
@@ -25,8 +24,6 @@ addons:
- sourceline: 'ppa:ubuntu-sdk-team/ppa'
homebrew:
update: true
- packages:
- - ccache
cache:
apt: true
@@ -47,7 +44,7 @@ notifications:
template:
- "%{repository_slug}:%{branch} - %{message} %{build_url}"
-matrix:
+jobs:
include:
- os: linux
compiler: "gcc"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a8c6a028e6..89fe32dbcc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1590,6 +1590,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/HLE/sceKernelAlarm.h
Core/HLE/sceKernelEventFlag.cpp
Core/HLE/sceKernelEventFlag.h
+ Core/HLE/sceKernelHeap.cpp
+ Core/HLE/sceKernelHeap.h
Core/HLE/sceKernelInterrupt.cpp
Core/HLE/sceKernelInterrupt.h
Core/HLE/sceKernelMbx.cpp
@@ -2063,6 +2065,7 @@ if(IOS)
add_custom_command(TARGET PPSSPP POST_BUILD
COMMAND mkdir -p \"${APP_DIR_NAME}\"
COMMAND tar -c -C ${CMAKE_CURRENT_BINARY_DIR} --exclude .DS_Store --exclude .git assets *.png | tar -x -C \"${APP_DIR_NAME}\"
+ COMMAND /bin/bash "${CMAKE_SOURCE_DIR}/ios/macbundle.sh" \"${APP_DIR_NAME}\"
)
set(MACOSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET})
set_target_properties(${TargetBin} PROPERTIES
diff --git a/Common/ColorConv.cpp b/Common/ColorConv.cpp
index bf4276f1e3..6206847d2e 100644
--- a/Common/ColorConv.cpp
+++ b/Common/ColorConv.cpp
@@ -308,7 +308,7 @@ void ConvertRGBA565ToRGBA8888(u32 *dst32, const u16 *src, u32 numPixels) {
b = _mm_or_si128(_mm_slli_epi16(b, 3), _mm_srli_epi16(b, 2));
b = _mm_and_si128(b, mask8);
- // Always set to 00FF 00FF.
+ // Always set alpha to 00FF 00FF.
__m128i a = _mm_slli_epi16(mask8, 8);
// Now combine them, RRGG RRGG and BBAA BBAA, and then interleave.
@@ -472,36 +472,36 @@ void ConvertRGBA4444ToBGRA8888(u32 *dst32, const u16 *src, u32 numPixels) {
u8 *dst = (u8 *)dst32;
for (u32 x = 0; x < numPixels; x++) {
u16 c = src[x];
- u32 r = c & 0x000f;
- u32 g = (c >> 4) & 0x000f;
- u32 b = (c >> 8) & 0x000f;
- u32 a = (c >> 12) & 0x000f;
+ u32 r = Convert4To8(c & 0x000f);
+ u32 g = Convert4To8((c >> 4) & 0x000f);
+ u32 b = Convert4To8((c >> 8) & 0x000f);
+ u32 a = Convert4To8((c >> 12) & 0x000f);
- dst[x] = (r << (16 + 4)) | (g << (8 + 4)) | (b << 4) | (a << (24 + 4));
+ dst[x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
void ConvertRGBA5551ToBGRA8888(u32 *dst, const u16 *src, u32 numPixels) {
for (u32 x = 0; x < numPixels; x++) {
u16 c = src[x];
- u32 r = c & 0x001f;
- u32 g = (c >> 5) & 0x001f;
- u32 b = (c >> 10) & 0x001f;
+ u32 r = Convert5To8(c & 0x001f);
+ u32 g = Convert6To8((c >> 5) & 0x001f);
+ u32 b = Convert5To8((c >> 10) & 0x001f);
// We force an arithmetic shift to get the sign bits/
u32 a = ((s32)(s16)c) & 0xff000000;
- dst[x] = (r << (16 + 3)) | (g << (8 + 3)) | (b << 3) | a;
+ dst[x] = a | (r << 16) | (g << 8) | b;
}
}
void ConvertRGB565ToBGRA8888(u32 *dst, const u16 *src, u32 numPixels) {
for (u32 x = 0; x < numPixels; x++) {
u16 c = src[x];
- u32 r = c & 0x001f;
- u32 g = (c >> 5) & 0x003f;
- u32 b = (c >> 11) & 0x001f;
+ u32 r = Convert5To8(c & 0x001f);
+ u32 g = Convert6To8((c >> 5) & 0x003f);
+ u32 b = Convert5To8((c >> 11) & 0x001f);
- dst[x] = (r << (16 + 3)) | (g << (8 + 2)) | (b << 3) | 0xFF000000;
+ dst[x] = 0xFF000000 | (r << 16) | (g << 8) | b;
}
}
diff --git a/Common/Vulkan/VulkanImage.h b/Common/Vulkan/VulkanImage.h
index 4fd06e21c0..2c809b2bdb 100644
--- a/Common/Vulkan/VulkanImage.h
+++ b/Common/Vulkan/VulkanImage.h
@@ -5,7 +5,7 @@
class VulkanDeviceAllocator;
// Wrapper around what you need to use a texture.
-// Not very optimal - if you have many small textures you should use other strategies.
+// ALWAYS use an allocator when calling CreateDirect.
class VulkanTexture {
public:
VulkanTexture(VulkanContext *vulkan)
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 1c422c1593..5b675bd729 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -371,6 +371,7 @@
+
@@ -899,6 +900,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 19698164c2..c95b6aa41f 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -740,6 +740,9 @@
HW
+
+ HLE\Kernel
+
@@ -1373,10 +1376,13 @@
HW
+
+ HLE\Kernel
+
-
\ No newline at end of file
+
diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h
index 39599d408f..01124ea157 100644
--- a/Core/HLE/FunctionWrappers.h
+++ b/Core/HLE/FunctionWrappers.h
@@ -134,6 +134,11 @@ template void WrapI_CIIIII
RETURN(retval);
}
+template void WrapI_IIIC() {
+ u32 retval = func(PARAM(0), PARAM(1), PARAM(2), Memory::GetCharPointer(PARAM(3)));
+ RETURN(retval);
+}
+
// Hm, do so many params get passed in registers?
template void WrapI_IIIIIIU() {
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp
index c62a564b7f..b4f0636f77 100644
--- a/Core/HLE/HLETables.cpp
+++ b/Core/HLE/HLETables.cpp
@@ -40,6 +40,7 @@
#include "sceJpeg.h"
#include "sceKernel.h"
#include "sceKernelEventFlag.h"
+#include "sceKernelHeap.h"
#include "sceKernelMemory.h"
#include "sceKernelInterrupt.h"
#include "sceKernelModule.h"
diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp
index ad571355ef..520295f2d9 100644
--- a/Core/HLE/sceKernel.cpp
+++ b/Core/HLE/sceKernel.cpp
@@ -50,6 +50,7 @@
#include "sceJpeg.h"
#include "sceKernel.h"
#include "sceKernelAlarm.h"
+#include "sceKernelHeap.h"
#include "sceKernelInterrupt.h"
#include "sceKernelThread.h"
#include "sceKernelMemory.h"
diff --git a/Core/HLE/sceKernel.h b/Core/HLE/sceKernel.h
index fa5928584b..96e94cb760 100644
--- a/Core/HLE/sceKernel.h
+++ b/Core/HLE/sceKernel.h
@@ -340,6 +340,7 @@ enum TMIDPurpose
PPSSPP_KERNEL_TMID_PMB = 0x100002,
PPSSPP_KERNEL_TMID_File = 0x100003,
PPSSPP_KERNEL_TMID_DirList = 0x100004,
+ PPSSPP_KERNEL_TMID_Heap = 0x100005,
};
typedef int SceUID;
diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp
new file mode 100644
index 0000000000..7b99eca184
--- /dev/null
+++ b/Core/HLE/sceKernelHeap.cpp
@@ -0,0 +1,94 @@
+#include
+
+#include "Common/ChunkFile.h"
+#include "Core/HLE/HLE.h"
+#include "Core/HLE/FunctionWrappers.h"
+#include "Core/HLE/sceKernel.h"
+#include "Core/HLE/sceKernelHeap.h"
+#include "Core/HLE/sceKernelMemory.h"
+#include "Core/Util/BlockAllocator.h"
+
+static const u32 HEAP_BLOCK_HEADER_SIZE = 8;
+static const bool g_fromBottom = false;
+
+struct Heap : public KernelObject {
+ int uid = 0;
+ int partitionId = 0;
+ u32 size = 0;
+ int flags = 0;
+ u32 address = 0;
+ std::string name;
+ BlockAllocator alloc;
+
+ static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_UID; }
+ static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_Heap; }
+ int GetIDType() const override { return PPSSPP_KERNEL_TMID_Heap; }
+
+ void DoState(PointerWrap &p) override {
+ p.Do(uid);
+ p.Do(partitionId);
+ p.Do(size);
+ p.Do(flags);
+ p.Do(address);
+ p.Do(name);
+ p.Do(alloc);
+ }
+};
+
+static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) {
+ u32 allocSize = (size + 3) & ~3;
+
+ // TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever...
+ u32 addr = userMemory.Alloc(allocSize, g_fromBottom, "SysMemForKernel-Heap");
+ if (addr == (u32)-1) {
+ ERROR_LOG(HLE, "sceKernelCreateHeap(partitionId=%d): Failed to allocate %d bytes memory", partitionId, size);
+ return SCE_KERNEL_ERROR_NO_MEMORY; // Blind guess
+ }
+
+ Heap *heap = new Heap();
+ SceUID uid = kernelObjects.Create(heap);
+
+ heap->partitionId = partitionId;
+ heap->flags = flags;
+ heap->name = Name ? Name : ""; // Not sure if this needs validation.
+ heap->size = allocSize;
+ heap->address = addr;
+ heap->alloc.Init(heap->address + 128, heap->size - 128);
+ heap->uid = uid;
+ return hleLogSuccessInfoX(SCEKERNEL, uid);
+}
+
+static int sceKernelAllocHeapMemory(int heapId, int size) {
+ u32 error;
+ Heap *heap = kernelObjects.Get(heapId, error);
+ if (heap) {
+ // There's 8 bytes at the end of every block, reserved.
+ u32 memSize = HEAP_BLOCK_HEADER_SIZE + size;
+ u32 addr = heap->alloc.Alloc(memSize, true);
+ return hleLogSuccessInfoX(SCEKERNEL, addr);
+ } else {
+ return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId);
+ }
+}
+
+static int sceKernelDeleteHeap(int heapId) {
+ u32 error;
+ Heap *heap = kernelObjects.Get(heapId, error);
+ if (heap) {
+ userMemory.Free(heap->address);
+ kernelObjects.Destroy(heap->uid);
+ return hleLogSuccessInfoX(SCEKERNEL, 0);
+ } else {
+ return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId);
+ }
+}
+
+const HLEFunction SysMemForKernel[] = {
+ { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'x', "ii" },
+ { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'i', "i" },
+ { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'i', "iixs" },
+};
+
+void Register_SysMemForKernel() {
+ RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
+}
diff --git a/Core/HLE/sceKernelHeap.h b/Core/HLE/sceKernelHeap.h
new file mode 100644
index 0000000000..1279c74962
--- /dev/null
+++ b/Core/HLE/sceKernelHeap.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void Register_SysMemForKernel();
diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp
index 46e5375397..40cccaa03d 100644
--- a/Core/HLE/sceKernelMemory.cpp
+++ b/Core/HLE/sceKernelMemory.cpp
@@ -2287,16 +2287,6 @@ const HLEFunction SysMemUserForUser[] = {
{0XD8DE5C1E, &WrapU_V, "SysMemUserForUser_D8DE5C1E", 'x', "" },
};
-const HLEFunction SysMemForKernel[] = {
- {0x636C953B, nullptr, "SysMemForKernel_636c953b", '?', "" },
- {0xC9805775, nullptr, "SysMemForKernel_c9805775", '?', "" },
- {0x1C1FBFE7, nullptr, "SysMemForKernel_1c1fbfe7", '?', "" },
-};
-
-void Register_SysMemForKernel() {
- RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel);
-}
-
void Register_SysMemUserForUser() {
RegisterModule("SysMemUserForUser", ARRAY_SIZE(SysMemUserForUser), SysMemUserForUser);
}
diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h
index 2396792436..dce6df77e0 100644
--- a/Core/HLE/sceKernelMemory.h
+++ b/Core/HLE/sceKernelMemory.h
@@ -66,5 +66,4 @@ int sceKernelGetTlsAddr(SceUID uid);
int sceKernelFreeTlspl(SceUID uid);
int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr);
-void Register_SysMemForKernel();
void Register_SysMemUserForUser();
diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp
index 94fe679b68..8b0fe61a37 100644
--- a/Core/Util/PPGeDraw.cpp
+++ b/Core/Util/PPGeDraw.cpp
@@ -162,18 +162,18 @@ static void BeginVertexData() {
vertexStart = dataWritePtr;
}
-static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color = 0xFFFFFFFF, float off = -0.5f) {
+static void Vertex(float x, float y, float u, float v, int tw, int th, u32 color = 0xFFFFFFFF) {
if (g_RemasterMode) {
PPGeRemasterVertex vtx;
- vtx.x = x + off; vtx.y = y + off; vtx.z = 0;
- vtx.u = u * tw + off; vtx.v = v * th + off;
+ vtx.x = x; vtx.y = y; vtx.z = 0;
+ vtx.u = u * tw; vtx.v = v * th;
vtx.color = color;
Memory::WriteStruct(dataWritePtr, &vtx);
dataWritePtr += sizeof(vtx);
} else {
PPGeVertex vtx;
- vtx.x = x + off; vtx.y = y + off; vtx.z = 0;
- vtx.u = u * tw + off; vtx.v = v * th + off;
+ vtx.x = x; vtx.y = y; vtx.z = 0;
+ vtx.u = u * tw; vtx.v = v * th;
vtx.color = color;
Memory::WriteStruct(dataWritePtr, &vtx);
dataWritePtr += sizeof(vtx);
@@ -871,8 +871,8 @@ static void PPGeDrawTextImage(PPGeTextDrawerImage im, float x, float y, int alig
BeginVertexData();
float u1 = (float)im.entry.width / (1 << wp2);
float v1 = (float)im.entry.height / (1 << hp2);
- Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, color, 0.0f);
- Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, color, 0.0f);
+ Vertex(x, y, 0, 0, 1 << wp2, 1 << hp2, color);
+ Vertex(x + w, y + h, u1, v1, 1 << wp2, 1 << hp2, color);
EndVertexDataAndDraw(GE_PRIM_RECTANGLES);
PPGeSetDefaultTexture();
diff --git a/Core/WebServer.cpp b/Core/WebServer.cpp
index 8ab773fd1f..eab106add0 100644
--- a/Core/WebServer.cpp
+++ b/Core/WebServer.cpp
@@ -37,6 +37,7 @@ enum class ServerStatus {
STARTING,
RUNNING,
STOPPING,
+ FINISHED,
};
static const char *REPORT_HOSTNAME = "report.ppsspp.org";
@@ -248,7 +249,7 @@ static void ExecuteWebServer() {
if (!http->Listen(g_Config.iRemoteISOPort)) {
if (!http->Listen(0)) {
ERROR_LOG(FILESYS, "Unable to listen on any port");
- UpdateStatus(ServerStatus::STOPPED);
+ UpdateStatus(ServerStatus::FINISHED);
return;
}
}
@@ -271,7 +272,7 @@ static void ExecuteWebServer() {
StopAllDebuggers();
delete http;
- UpdateStatus(ServerStatus::STOPPED);
+ UpdateStatus(ServerStatus::FINISHED);
}
bool StartWebServer(WebServerFlags flags) {
@@ -284,6 +285,9 @@ bool StartWebServer(WebServerFlags flags) {
serverFlags |= (int)flags;
return true;
+ case ServerStatus::FINISHED:
+ serverThread.join();
+ // Intentional fallthrough.
case ServerStatus::STOPPED:
serverStatus = ServerStatus::STARTING;
serverFlags = (int)flags;
@@ -318,11 +322,13 @@ bool WebServerStopped(WebServerFlags flags) {
if (serverStatus == ServerStatus::RUNNING) {
return (serverFlags & (int)flags) == 0;
}
- return serverStatus == ServerStatus::STOPPED;
+ return serverStatus == ServerStatus::STOPPED || serverStatus == ServerStatus::FINISHED;
}
void ShutdownWebServer() {
StopWebServer(WebServerFlags::ALL);
- if (serverThread.joinable())
+
+ if (serverStatus != ServerStatus::STOPPED)
serverThread.join();
+ serverStatus = ServerStatus::STOPPED;
}
diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp
index 4f0bf889d4..aea0c82a4e 100644
--- a/GPU/Common/FramebufferCommon.cpp
+++ b/GPU/Common/FramebufferCommon.cpp
@@ -801,7 +801,7 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
// Might've changed if the shader was just changed to Off.
if (usePostShader_) {
PostShaderUniforms uniforms{};
- CalculatePostShaderUniforms(480, 272, renderWidth_, renderHeight_, &uniforms);
+ CalculatePostShaderUniforms(512, 272, renderWidth_, renderHeight_, &uniforms);
BindPostShader(uniforms);
} else {
Bind2DShader();
@@ -1017,7 +1017,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
SetViewport2D(0, 0, fbo_w, fbo_h);
draw_->SetScissorRect(0, 0, fbo_w, fbo_h);
PostShaderUniforms uniforms{};
- CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, renderWidth_, renderHeight_, &uniforms);
+ int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
+ int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
+ CalculatePostShaderUniforms(actualWidth, actualHeight, renderWidth_, renderHeight_, &uniforms);
BindPostShader(uniforms);
DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
DrawActiveTexture(0, 0, fbo_w, fbo_h, fbo_w, fbo_h, 0.0f, 0.0f, 1.0f, 1.0f, ROTATION_LOCKED_HORIZONTAL, flags);
@@ -1066,7 +1068,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
flags = flags | DRAWTEX_TO_BACKBUFFER;
PostShaderUniforms uniforms{};
- CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, vfb->renderWidth, vfb->renderHeight, &uniforms);
+ int actualWidth = (vfb->bufferWidth * vfb->renderWidth) / vfb->width;
+ int actualHeight = (vfb->bufferHeight * vfb->renderHeight) / vfb->height;
+ CalculatePostShaderUniforms(actualWidth, actualHeight, vfb->renderWidth, vfb->renderHeight, &uniforms);
BindPostShader(uniforms);
if (g_Config.bEnableCardboardVR) {
// Left Eye Image
@@ -1214,7 +1218,7 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
}
}
-// This is called from detected memcopies only. Not block transfers.
+// This is called from detected memcopies and framebuffer initialization from VRAM. Not block transfers.
// MotoGP goes this path so we need to catch those copies here.
bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, bool isMemset, u32 skipDrawReason) {
if (size == 0) {
@@ -1837,15 +1841,15 @@ void FramebufferManagerCommon::Resized() {
}
void FramebufferManagerCommon::CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight, PostShaderUniforms *uniforms) {
- float u_delta = 1.0f / renderWidth;
- float v_delta = 1.0f / renderHeight;
- float u_pixel_delta = u_delta;
- float v_pixel_delta = v_delta;
+ float u_delta = 1.0f / bufferWidth;
+ float v_delta = 1.0f / bufferHeight;
+ float u_pixel_delta = 1.0 / renderWidth;
+ float v_pixel_delta = 1.0 / renderHeight;
if (postShaderAtOutputResolution_) {
float x, y, w, h;
CenterDisplayOutputRect(&x, &y, &w, &h, 480.0f, 272.0f, (float)pixelWidth_, (float)pixelHeight_, ROTATION_LOCKED_HORIZONTAL);
- u_pixel_delta = (1.0f / w) * (480.0f / bufferWidth);
- v_pixel_delta = (1.0f / h) * (272.0f / bufferHeight);
+ u_pixel_delta = 1.0f / w;
+ v_pixel_delta = 1.0f / h;
}
int flipCount = __DisplayGetFlipCount();
int vCount = __DisplayGetVCount();
diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp
index c16e734313..e87d5a940a 100644
--- a/GPU/Common/SoftwareTransformCommon.cpp
+++ b/GPU/Common/SoftwareTransformCommon.cpp
@@ -15,6 +15,7 @@
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
+#include
#include
#include "math/math_util.h"
#include "gfx_es2/gpu_features.h"
@@ -155,15 +156,9 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) {
return 0;
}
-// NOTE: The viewport must be up to date!
-void SoftwareTransform(
- int prim, int vertexCount, u32 vertType, u16 *&inds, int indexType,
- const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer, int &numTrans, bool &drawIndexed, const SoftwareTransformParams *params, SoftwareTransformResult *result) {
- u8 *decoded = params->decoded;
- FramebufferManagerCommon *fbman = params->fbman;
- TextureCacheCommon *texCache = params->texCache;
- TransformedVertex *transformed = params->transformed;
- TransformedVertex *transformedExpanded = params->transformedExpanded;
+void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result) {
+ u8 *decoded = params_.decoded;
+ TransformedVertex *transformed = params_.transformed;
bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
bool lmode = gstate.isUsingSecondaryColor() && gstate.isLightingEnabled();
@@ -194,7 +189,7 @@ void SoftwareTransform(
}
int provokeIndOffset = 0;
- if (params->provokeFlatFirst) {
+ if (params_.provokeFlatFirst) {
provokeIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear());
}
@@ -329,12 +324,8 @@ void SoftwareTransform(
}
}
} else {
- if (reader.hasColor0()) {
- for (int j = 0; j < 4; j++) {
- c0[j] = unlitColor[j];
- }
- } else {
- c0 = Vec4f::FromRGBA(gstate.getMaterialAmbientRGBA());
+ for (int j = 0; j < 4; j++) {
+ c0[j] = unlitColor[j];
}
if (lmode) {
// c1 is already 0.
@@ -450,7 +441,7 @@ void SoftwareTransform(
// TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not.
// TODO: Allow creating a depth clear and a color draw.
bool reallyAClear = false;
- if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear() && params->allowClear) {
+ if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear() && params_.allowClear) {
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2);
@@ -459,7 +450,7 @@ 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();
- bool matchingComponents = 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;
@@ -470,53 +461,86 @@ void SoftwareTransform(
return;
}
}
+}
- // This means we're using a framebuffer (and one that isn't big enough.)
+// Also, this assumes SetTexture() has already figured out the actual texture height.
+void SoftwareTransform::DetectOffsetTexture(int maxIndex) {
+ TransformedVertex *transformed = params_.transformed;
+
+ const int w = gstate.getTextureWidth(0);
+ const int h = gstate.getTextureHeight(0);
+ float widthFactor = (float)w / (float)gstate_c.curTextureWidth;
+ float heightFactor = (float)h / (float)gstate_c.curTextureHeight;
+
+ // Breath of Fire 3 does some interesting rendering here, probably from being a port.
+ // It draws at 384x240 to two buffers in VRAM, one right after the other.
+ // We end up creating separate framebuffers, and rendering to each.
+ // But the game then stretches this to the screen - and reads from a single 512 tall texture.
+ // We initially use the first framebuffer. This code detects the read from the second.
+ //
+ // First Vs: 12, 228 - second Vs: 252, 468 - estimated fb height: 272
+
+ // If curTextureHeight is < h, it must be a framebuffer that wasn't full height.
if (gstate_c.curTextureHeight < (u32)h && maxIndex >= 2) {
- // Even if not rectangles, this will detect if either of the first two are outside the framebuffer.
- // HACK: Adding one pixel margin to this detection fixes issues in Assassin's Creed : Bloodlines,
- // while still keeping BOF working (see below).
+ // This is the max V that will still land within the framebuffer (since it's shorter.)
+ // We already adjusted V to the framebuffer above.
+ const float maxAvailableV = 1.0f;
+ // This is the max V that would've been inside the original texture size.
+ const float maxValidV = heightFactor;
+
+ // Apparently, Assassin's Creed: Bloodlines accesses just outside.
const float invTexH = 1.0f / gstate_c.curTextureHeight; // size of one texel.
- bool tlOutside;
- bool tlAlmostOutside;
- bool brOutside;
- // If we're outside heightFactor, then v must be wrapping or clamping. Avoid this workaround.
- // If we're <= 1.0f, we're inside the framebuffer (workaround not needed.)
- // We buffer that 1.0f a little more with a texel to avoid some false positives.
- tlOutside = transformed[0].v <= heightFactor && transformed[0].v > 1.0f + invTexH;
- brOutside = transformed[1].v <= heightFactor && transformed[1].v > 1.0f + invTexH;
- // Careful: if br is outside, but tl is well inside, this workaround still doesn't make sense.
- // We go with halfway, since we overestimate framebuffer heights sometimes but not by much.
- tlAlmostOutside = transformed[0].v <= heightFactor && transformed[0].v >= 0.5f;
+
+ // Are either TL or BR inside the texture but outside the framebuffer?
+ const bool tlOutside = transformed[0].v > maxAvailableV + invTexH && transformed[0].v <= maxValidV;
+ const bool brOutside = transformed[1].v > maxAvailableV + invTexH && transformed[1].v <= maxValidV;
+
+ // If TL isn't outside, is it at least near the end?
+ // We check this because some games do 0-512 from a 272 tall framebuf.
+ const bool tlAlmostOutside = transformed[0].v > maxAvailableV * 0.5f && transformed[0].v <= maxValidV;
+
if (tlOutside || (brOutside && tlAlmostOutside)) {
- // Okay, so we're texturing from outside the framebuffer, but inside the texture height.
- // Breath of Fire 3 does this to access a render surface at an offset.
- const u32 bpp = fbman->GetTargetFormat() == GE_FORMAT_8888 ? 4 : 2;
- const u32 prevH = texCache->AttachedDrawingHeight();
- const u32 fb_size = bpp * fbman->GetTargetStride() * prevH;
+ const u32 prevXOffset = gstate_c.curTextureXOffset;
const u32 prevYOffset = gstate_c.curTextureYOffset;
- if (texCache->SetOffsetTexture(fb_size)) {
+
+ // This is how far the nearest coord is, so that's where we'll look for the next framebuf.
+ const u32 yOffset = (int)(gstate_c.curTextureHeight * std::min(transformed[0].v, transformed[1].v));
+ if (params_.texCache->SetOffsetTexture(yOffset)) {
const float oldWidthFactor = widthFactor;
const float oldHeightFactor = heightFactor;
- widthFactor = (float) w / (float) gstate_c.curTextureWidth;
- heightFactor = (float) h / (float) gstate_c.curTextureHeight;
+ widthFactor = (float)w / (float)gstate_c.curTextureWidth;
+ heightFactor = (float)h / (float)gstate_c.curTextureHeight;
+
+ // We need to subtract this offset from the UVs to address the new framebuf.
+ const float adjustedYOffset = yOffset + prevYOffset - gstate_c.curTextureYOffset;
+ const float yDiff = (float)adjustedYOffset / (float)h;
+ const float adjustedXOffset = prevXOffset - gstate_c.curTextureXOffset;
+ const float xDiff = (float)adjustedXOffset / (float)w;
- // We've already baked in the old gstate_c.curTextureYOffset, so correct.
- const float yDiff = (float) (prevH + prevYOffset - gstate_c.curTextureYOffset) / (float) h;
for (int index = 0; index < maxIndex; ++index) {
- transformed[index].u *= widthFactor / oldWidthFactor;
- // Inverse it back to scale to the new FBO, and add 1.0f to account for old FBO.
+ transformed[index].u = (transformed[index].u / oldWidthFactor - xDiff) * widthFactor;
transformed[index].v = (transformed[index].v / oldHeightFactor - yDiff) * heightFactor;
}
+
+ // We undid the offset, so reset. This avoids a different shader.
+ gstate_c.curTextureXOffset = prevXOffset;
+ gstate_c.curTextureYOffset = prevYOffset;
}
}
}
+}
+
+// NOTE: The viewport must be up to date!
+void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result) {
+ TransformedVertex *transformed = params_.transformed;
+ TransformedVertex *transformedExpanded = params_.transformedExpanded;
+ bool throughmode = (vertType & GE_VTYPE_THROUGH_MASK) != 0;
// Step 2: expand rectangles.
- drawBuffer = transformed;
- numTrans = 0;
- drawIndexed = false;
+ result->drawBuffer = transformed;
+ int numTrans = 0;
+ FramebufferManagerCommon *fbman = params_.fbman;
bool useBufferedRendering = fbman->UseBufferedRendering();
bool flippedY = g_Config.iGPUBackend == (int)GPUBackend::OPENGL && !useBufferedRendering;
@@ -524,7 +548,7 @@ void SoftwareTransform(
if (prim != GE_PRIM_RECTANGLES) {
// We can simply draw the unexpanded buffer.
numTrans = vertexCount;
- drawIndexed = true;
+ result->drawIndexed = true;
} else {
// Pretty bad hackery where we re-do the transform (in RotateUV) to see if the vertices are flipped in screen space.
// Since we've already got API-specific assumptions (Y direction, etc) baked into the projMatrix (which we arguably shouldn't),
@@ -553,7 +577,7 @@ void SoftwareTransform(
//rectangles always need 2 vertices, disregard the last one if there's an odd number
vertexCount = vertexCount & ~1;
numTrans = 0;
- drawBuffer = transformedExpanded;
+ result->drawBuffer = transformedExpanded;
TransformedVertex *trans = &transformedExpanded[0];
const u16 *indsIn = (const u16 *)inds;
u16 *newInds = inds + vertexCount;
@@ -606,7 +630,7 @@ void SoftwareTransform(
numTrans += 6;
}
inds = newInds;
- drawIndexed = true;
+ result->drawIndexed = true;
// We don't know the color until here, so we have to do it now, instead of in StateMapping.
// Might want to reconsider the order of things later...
@@ -628,4 +652,5 @@ void SoftwareTransform(
}
result->action = SW_DRAW_PRIMITIVES;
+ result->drawNumTrans = numTrans;
}
diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h
index a7efc396c9..c93e12b58d 100644
--- a/GPU/Common/SoftwareTransformCommon.h
+++ b/GPU/Common/SoftwareTransformCommon.h
@@ -25,6 +25,7 @@ class FramebufferManagerCommon;
class TextureCacheCommon;
enum SoftwareTransformAction {
+ SW_NOT_READY,
SW_DRAW_PRIMITIVES,
SW_CLEAR,
};
@@ -36,6 +37,10 @@ struct SoftwareTransformResult {
bool setStencil;
u8 stencilValue;
+
+ TransformedVertex *drawBuffer;
+ int drawNumTrans;
+ bool drawIndexed;
};
struct SoftwareTransformParams {
@@ -49,5 +54,15 @@ struct SoftwareTransformParams {
bool provokeFlatFirst;
};
-void SoftwareTransform(int prim, int vertexCount, u32 vertexType, u16 *&inds, int indexType, const DecVtxFormat &decVtxFormat, int &maxIndex, TransformedVertex *&drawBuffer,
- int &numTrans, bool &drawIndexed, const SoftwareTransformParams *params, SoftwareTransformResult *result);
+class SoftwareTransform {
+public:
+ SoftwareTransform(SoftwareTransformParams ¶ms) : params_(params) {
+ }
+
+ void Decode(int prim, u32 vertexType, const DecVtxFormat &decVtxFormat, int maxIndex, SoftwareTransformResult *result);
+ void DetectOffsetTexture(int maxIndex);
+ void BuildDrawingParams(int prim, int vertexCount, u32 vertType, u16 *&inds, int &maxIndex, SoftwareTransformResult *result);
+
+protected:
+ const SoftwareTransformParams ¶ms_;
+};
diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp
index 3a9a15dba0..6de1af21b9 100644
--- a/GPU/Common/TextureCacheCommon.cpp
+++ b/GPU/Common/TextureCacheCommon.cpp
@@ -30,8 +30,9 @@
#include "GPU/Common/ShaderId.h"
#include "GPU/Common/GPUStateUtils.h"
#include "GPU/Debugger/Debugger.h"
-#include "GPU/GPUState.h"
+#include "GPU/GPUCommon.h"
#include "GPU/GPUInterface.h"
+#include "GPU/GPUState.h"
#if defined(_M_SSE)
#include
@@ -909,17 +910,22 @@ void TextureCacheCommon::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFram
nextNeedsRebuild_ = false;
}
-bool TextureCacheCommon::SetOffsetTexture(u32 offset) {
+bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) {
if (!framebufferManager_->UseBufferedRendering()) {
return false;
}
+
u32 texaddr = gstate.getTextureAddress(0);
- if (!Memory::IsValidAddress(texaddr) || !Memory::IsValidAddress(texaddr + offset)) {
+ GETextureFormat fmt = gstate.getTextureFormat();
+ const u32 bpp = fmt == GE_FORMAT_8888 ? 4 : 2;
+ const u32 texaddrOffset = yOffset * gstate.getTextureWidth(0) * bpp;
+
+ if (!Memory::IsValidAddress(texaddr) || !Memory::IsValidAddress(texaddr + texaddrOffset)) {
return false;
}
const u16 dim = gstate.getTextureDimension(0);
- u64 cachekey = TexCacheEntry::CacheKey(texaddr, gstate.getTextureFormat(), dim, 0);
+ u64 cachekey = TexCacheEntry::CacheKey(texaddr, fmt, dim, 0);
TexCache::iterator iter = cache_.find(cachekey);
if (iter == cache_.end()) {
return false;
@@ -929,7 +935,7 @@ bool TextureCacheCommon::SetOffsetTexture(u32 offset) {
bool success = false;
for (size_t i = 0, n = fbCache_.size(); i < n; ++i) {
auto framebuffer = fbCache_[i];
- if (AttachFramebuffer(entry, framebuffer->fb_address, framebuffer, offset)) {
+ if (AttachFramebuffer(entry, framebuffer->fb_address, framebuffer, texaddrOffset)) {
success = true;
}
}
diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h
index 7f8c2ffa70..095fd12240 100644
--- a/GPU/Common/TextureCacheCommon.h
+++ b/GPU/Common/TextureCacheCommon.h
@@ -187,7 +187,7 @@ public:
void SetTexture(bool force = false);
void ApplyTexture();
- bool SetOffsetTexture(u32 offset);
+ bool SetOffsetTexture(u32 yOffset);
void Invalidate(u32 addr, int size, GPUInvalidationType type);
void InvalidateAll(GPUInvalidationType type);
void ClearNextFrame();
diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp
index 6337b412c0..fde2dd0102 100644
--- a/GPU/D3D11/DrawEngineD3D11.cpp
+++ b/GPU/D3D11/DrawEngineD3D11.cpp
@@ -570,10 +570,7 @@ rotateVBO:
prim = GE_PRIM_TRIANGLES;
VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount());
- int numTrans = 0;
- bool drawIndexed = false;
u16 *inds = decIndex;
- TransformedVertex *drawBuffer = NULL;
SoftwareTransformResult result{};
SoftwareTransformParams params{};
params.decoded = decoded;
@@ -586,10 +583,12 @@ rotateVBO:
params.provokeFlatFirst = true;
int maxIndex = indexGen.MaxIndex();
- SoftwareTransform(
- prim, indexGen.VertexCount(),
- dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
- maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result);
+ SoftwareTransform swTransform(params);
+ swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
+ if (result.action == SW_NOT_READY) {
+ swTransform.DetectOffsetTexture(maxIndex);
+ swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
+ }
if (result.action == SW_DRAW_PRIMITIVES) {
const int vertexSize = sizeof(transformed[0]);
@@ -619,20 +618,20 @@ rotateVBO:
UINT vOffset = 0;
int vSize = maxIndex * stride;
uint8_t *vptr = pushVerts_->BeginPush(context_, &vOffset, vSize);
- memcpy(vptr, drawBuffer, vSize);
+ memcpy(vptr, result.drawBuffer, vSize);
pushVerts_->EndPush(context_);
ID3D11Buffer *buf = pushVerts_->Buf();
context_->IASetVertexBuffers(0, 1, &buf, &stride, &vOffset);
- if (drawIndexed) {
+ if (result.drawIndexed) {
UINT iOffset;
- int iSize = sizeof(uint16_t) * numTrans;
+ int iSize = sizeof(uint16_t) * result.drawNumTrans;
uint8_t *iptr = pushInds_->BeginPush(context_, &iOffset, iSize);
memcpy(iptr, inds, iSize);
pushInds_->EndPush(context_);
context_->IASetIndexBuffer(pushInds_->Buf(), DXGI_FORMAT_R16_UINT, iOffset);
- context_->DrawIndexed(numTrans, 0, 0);
+ context_->DrawIndexed(result.drawNumTrans, 0, 0);
} else {
- context_->Draw(numTrans, 0);
+ context_->Draw(result.drawNumTrans, 0);
}
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp
index 4af81be893..207cc52f5d 100644
--- a/GPU/D3D11/GPU_D3D11.cpp
+++ b/GPU/D3D11/GPU_D3D11.cpp
@@ -132,12 +132,10 @@ void GPU_D3D11::CheckGPUFeatures() {
features |= GPU_SUPPORTS_BLEND_MINMAX;
features |= GPU_PREFER_CPU_DOWNLOAD;
- // Accurate depth is required on AMD/nVidia (for reverse Z) so we ignore the compat flag to disable it on those. See #9545
- auto vendor = draw_->GetDeviceCaps().vendor;
-
- if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || vendor == Draw::GPUVendor::VENDOR_AMD || vendor == Draw::GPUVendor::VENDOR_NVIDIA) {
- features |= GPU_SUPPORTS_ACCURATE_DEPTH; // Breaks text in PaRappa for some reason.
- }
+ // Accurate depth is required because the Direct3D API does not support inverse Z.
+ // So we cannot incorrectly use the viewport transform as the depth range on Direct3D.
+ // TODO: Breaks text in PaRappa for some reason?
+ features |= GPU_SUPPORTS_ACCURATE_DEPTH;
#ifndef _M_ARM
// TODO: Do proper feature detection
diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp
index e399aa84ec..15f9e745d0 100644
--- a/GPU/D3D11/TextureCacheD3D11.cpp
+++ b/GPU/D3D11/TextureCacheD3D11.cpp
@@ -399,6 +399,8 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra
shaderApply.ApplyBounds(gstate_c.vertBounds, gstate_c.curTextureXOffset, gstate_c.curTextureYOffset, xoff, yoff);
shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout());
+ ID3D11ShaderResourceView *nullTexture = nullptr;
+ context_->PSSetShaderResources(0, 1, &nullTexture); // In case the target was used in the last draw call. Happens in Sega Rally.
draw_->BindFramebufferAsRenderTarget(depalFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
context_->PSSetShaderResources(3, 1, &clutTexture);
context_->PSSetSamplers(3, 1, &stockD3D11.samplerPoint2DWrap);
diff --git a/GPU/Directx9/DrawEngineDX9.cpp b/GPU/Directx9/DrawEngineDX9.cpp
index 5fc686dcd9..a39d48f986 100644
--- a/GPU/Directx9/DrawEngineDX9.cpp
+++ b/GPU/Directx9/DrawEngineDX9.cpp
@@ -530,10 +530,7 @@ rotateVBO:
prim = GE_PRIM_TRIANGLES;
VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount());
- int numTrans = 0;
- bool drawIndexed = false;
u16 *inds = decIndex;
- TransformedVertex *drawBuffer = NULL;
SoftwareTransformResult result{};
SoftwareTransformParams params{};
params.decoded = decoded;
@@ -546,10 +543,12 @@ rotateVBO:
params.provokeFlatFirst = true;
int maxIndex = indexGen.MaxIndex();
- SoftwareTransform(
- prim, indexGen.VertexCount(),
- dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
- maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result);
+ SoftwareTransform swTransform(params);
+ swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
+ if (result.action == SW_NOT_READY) {
+ swTransform.DetectOffsetTexture(maxIndex);
+ swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
+ }
ApplyDrawStateLate();
vshader = shaderManager_->ApplyShader(false, false, lastVType_);
@@ -566,10 +565,10 @@ rotateVBO:
const int vertexSize = sizeof(transformed[0]);
device_->SetVertexDeclaration(transformedVertexDecl_);
- if (drawIndexed) {
- device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, maxIndex, D3DPrimCount(d3d_prim[prim], numTrans), inds, D3DFMT_INDEX16, drawBuffer, sizeof(TransformedVertex));
+ if (result.drawIndexed) {
+ device_->DrawIndexedPrimitiveUP(d3d_prim[prim], 0, maxIndex, D3DPrimCount(d3d_prim[prim], result.drawNumTrans), inds, D3DFMT_INDEX16, result.drawBuffer, sizeof(TransformedVertex));
} else {
- device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], numTrans), drawBuffer, sizeof(TransformedVertex));
+ device_->DrawPrimitiveUP(d3d_prim[prim], D3DPrimCount(d3d_prim[prim], result.drawNumTrans), result.drawBuffer, sizeof(TransformedVertex));
}
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp
index e25afe304b..162e7ed71e 100644
--- a/GPU/Directx9/GPU_DX9.cpp
+++ b/GPU/Directx9/GPU_DX9.cpp
@@ -167,12 +167,12 @@ void GPU_DX9::CheckGPUFeatures() {
features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL;
features |= GPU_PREFER_CPU_DOWNLOAD;
- auto vendor = draw_->GetDeviceCaps().vendor;
- // Accurate depth is required on AMD/nVidia (for reverse Z) so we ignore the compat flag to disable it on those. See #9545
- if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || vendor == Draw::GPUVendor::VENDOR_AMD || vendor == Draw::GPUVendor::VENDOR_NVIDIA) {
- features |= GPU_SUPPORTS_ACCURATE_DEPTH;
- }
+ // Accurate depth is required because the Direct3D API does not support inverse Z.
+ // So we cannot incorrectly use the viewport transform as the depth range on Direct3D.
+ // TODO: Breaks text in PaRappa for some reason?
+ features |= GPU_SUPPORTS_ACCURATE_DEPTH;
+ auto vendor = draw_->GetDeviceCaps().vendor;
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.
diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp
index 70abe87bef..5587c93b54 100644
--- a/GPU/GLES/DrawEngineGLES.cpp
+++ b/GPU/GLES/DrawEngineGLES.cpp
@@ -538,9 +538,6 @@ rotateVBO:
if (prim == GE_PRIM_TRIANGLE_STRIP)
prim = GE_PRIM_TRIANGLES;
- TransformedVertex *drawBuffer = NULL;
- int numTrans;
- bool drawIndexed = false;
u16 *inds = decIndex;
SoftwareTransformResult result{};
// TODO: Keep this static? Faster than repopulating?
@@ -563,16 +560,19 @@ rotateVBO:
vertexCount = 0x10000 / 3;
#endif
+ SoftwareTransform swTransform(params);
+ swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
+ if (result.action == SW_NOT_READY)
+ swTransform.DetectOffsetTexture(maxIndex);
+
if (textureNeedsApply)
textureCache_->ApplyTexture();
// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.
ApplyDrawState(prim);
- SoftwareTransform(
- prim, vertexCount,
- dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
- maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result);
+ if (result.action == SW_NOT_READY)
+ swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result);
ApplyDrawStateLate(result.setStencil, result.stencilValue);
@@ -583,16 +583,16 @@ rotateVBO:
bool doTextureProjection = gstate.getUVGenMode() == GE_TEXMAP_TEXTURE_MATRIX;
- if (drawIndexed) {
- vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(drawBuffer, maxIndex * sizeof(TransformedVertex), &vertexBuffer);
- indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * numTrans, &indexBuffer);
+ if (result.drawIndexed) {
+ vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), &vertexBuffer);
+ indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawNumTrans, &indexBuffer);
render_->BindVertexBuffer(softwareInputLayout_, vertexBuffer, vertexBufferOffset);
render_->BindIndexBuffer(indexBuffer);
- render_->DrawIndexed(glprim[prim], numTrans, GL_UNSIGNED_SHORT, (void *)(intptr_t)indexBufferOffset);
+ render_->DrawIndexed(glprim[prim], result.drawNumTrans, GL_UNSIGNED_SHORT, (void *)(intptr_t)indexBufferOffset);
} else {
- vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(drawBuffer, numTrans * sizeof(TransformedVertex), &vertexBuffer);
+ vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), &vertexBuffer);
render_->BindVertexBuffer(softwareInputLayout_, vertexBuffer, vertexBufferOffset);
- render_->Draw(glprim[prim], 0, numTrans);
+ render_->Draw(glprim[prim], 0, result.drawNumTrans);
}
} else if (result.action == SW_CLEAR) {
u32 clearColor = result.color;
diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp
index d92e1b80ff..62305dd14a 100644
--- a/GPU/Vulkan/DrawEngineVulkan.cpp
+++ b/GPU/Vulkan/DrawEngineVulkan.cpp
@@ -880,10 +880,7 @@ void DrawEngineVulkan::DoFlush() {
prim = GE_PRIM_TRIANGLES;
VERBOSE_LOG(G3D, "Flush prim %i SW! %i verts in one go", prim, indexGen.VertexCount());
- int numTrans = 0;
- bool drawIndexed = false;
u16 *inds = decIndex;
- TransformedVertex *drawBuffer = nullptr;
SoftwareTransformResult result{};
SoftwareTransformParams params{};
params.decoded = decoded;
@@ -906,10 +903,12 @@ void DrawEngineVulkan::DoFlush() {
}
int maxIndex = indexGen.MaxIndex();
- SoftwareTransform(
- prim, indexGen.VertexCount(),
- dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(),
- maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result);
+ SoftwareTransform swTransform(params);
+ swTransform.Decode(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), maxIndex, &result);
+ if (result.action == SW_NOT_READY) {
+ swTransform.DetectOffsetTexture(maxIndex);
+ swTransform.BuildDrawingParams(prim, indexGen.VertexCount(), dec_->VertexType(), inds, maxIndex, &result);
+ }
// Only here, where we know whether to clear or to draw primitives, should we actually set the current framebuffer! Because that gives use the opportunity
// to use a "pre-clear" render pass, for high efficiency on tilers.
@@ -965,17 +964,17 @@ void DrawEngineVulkan::DoFlush() {
PROFILE_THIS_SCOPE("renderman_q");
- if (drawIndexed) {
+ if (result.drawIndexed) {
VkBuffer vbuf, ibuf;
- vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
- ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * numTrans, &ibuf);
+ vbOffset = (uint32_t)frame->pushVertex->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), &vbuf);
+ ibOffset = (uint32_t)frame->pushIndex->Push(inds, sizeof(short) * result.drawNumTrans, &ibuf);
VkDeviceSize offsets[1] = { vbOffset };
- renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, numTrans, 1, VK_INDEX_TYPE_UINT16);
+ renderManager->DrawIndexed(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1, VK_INDEX_TYPE_UINT16);
} else {
VkBuffer vbuf;
- vbOffset = (uint32_t)frame->pushVertex->Push(drawBuffer, numTrans * sizeof(TransformedVertex), &vbuf);
+ vbOffset = (uint32_t)frame->pushVertex->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), &vbuf);
VkDeviceSize offsets[1] = { vbOffset };
- renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, numTrans);
+ renderManager->Draw(pipelineLayout_, ds, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans);
}
} else if (result.action == SW_CLEAR) {
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp
index 532c00dfb8..0d27a97b77 100644
--- a/GPU/Vulkan/FramebufferVulkan.cpp
+++ b/GPU/Vulkan/FramebufferVulkan.cpp
@@ -85,7 +85,7 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
FramebufferManagerCommon(draw),
vulkan_(vulkan) {
- InitDeviceObjects();
+ DeviceRestore(vulkan, draw);
// After a blit we do need to rebind for the VulkanRenderManager to know what to do.
needGLESRebinds_ = true;
@@ -94,7 +94,7 @@ FramebufferManagerVulkan::FramebufferManagerVulkan(Draw::DrawContext *draw, Vulk
FramebufferManagerVulkan::~FramebufferManagerVulkan() {
delete[] convBuf_;
- DestroyDeviceObjects();
+ DeviceLost();
}
void FramebufferManagerVulkan::SetTextureCache(TextureCacheVulkan *tc) {
@@ -207,9 +207,12 @@ 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.
+ // OR NOT! Hot Shot Golf (#12355) does tons of these in a frame in some situations! So actually,
+ // we do use an allocator. In fact, I've now banned allocator-less textures.
+
drawPixelsTex_ = new VulkanTexture(vulkan_);
drawPixelsTex_->SetTag("DrawPixels");
- 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)) {
+ if (!drawPixelsTex_->CreateDirect(initCmd, allocator_, 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;
@@ -493,8 +496,10 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
h -= srcY + h - src->bufferHeight;
}
- if (w == 0 || h == 0)
+ if (w <= 0 || h <= 0) {
+ // The whole rectangle got clipped.
return;
+ }
float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth;
float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight;
@@ -549,12 +554,27 @@ void FramebufferManagerVulkan::EndFrame() {
void FramebufferManagerVulkan::DeviceLost() {
DestroyAllFBOs();
DestroyDeviceObjects();
+
+ if (allocator_) {
+ allocator_->Destroy();
+
+ // We have to delete on queue, so this can free its queued deletions.
+ vulkan_->Delete().QueueCallback([](void *ptr) {
+ auto allocator = static_cast(ptr);
+ delete allocator;
+ }, allocator_);
+ allocator_ = nullptr;
+ }
}
void FramebufferManagerVulkan::DeviceRestore(VulkanContext *vulkan, Draw::DrawContext *draw) {
vulkan_ = vulkan;
draw_ = draw;
+ _assert_(!allocator_);
+
+ allocator_ = new VulkanDeviceAllocator(vulkan_, 1 * 1024 * 1024, 8 * 1024 * 1024);
+
InitDeviceObjects();
}
diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h
index e7a7fa670d..e7bceb16ef 100644
--- a/GPU/Vulkan/FramebufferVulkan.h
+++ b/GPU/Vulkan/FramebufferVulkan.h
@@ -99,6 +99,7 @@ private:
TextureCacheVulkan *textureCacheVulkan_ = nullptr;
ShaderManagerVulkan *shaderManagerVulkan_ = nullptr;
DrawEngineVulkan *drawEngineVulkan_ = nullptr;
+ VulkanDeviceAllocator *allocator_ = nullptr;
VulkanPushBuffer *push_;
enum {
diff --git a/Qt/macbundle.sh b/Qt/macbundle.sh
index f906e0d77f..989cde3d17 100644
--- a/Qt/macbundle.sh
+++ b/Qt/macbundle.sh
@@ -15,4 +15,15 @@ plutil -replace NSLocationWhenInUseUsageDescription -string "Your location may b
plutil -replace NSCameraUsageDescription -string "Your camera may be used to emulate Go!Cam, a camera accessory" ${PPSSPP}/Contents/Info.plist
plutil -replace NSMicrophoneUsageDescription -string "Your microphone may be used to emulate Go!Cam/Talkman, a microphone accessory" ${PPSSPP}/Contents/Info.plist
+GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " "$(dirname "${0}")/../git-version.cpp")
+SHORT_VERSION_MATCH='.*"v([0-9\.]+(-[0-9]+)?).*";'
+LONG_VERSION_MATCH='.*"v(.*)";'
+if [[ "${GIT_VERSION_LINE}" =~ ^${SHORT_VERSION_MATCH}$ ]]; then
+ plutil -replace CFBundleShortVersionString -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${SHORT_VERSION_MATCH}/\$1/g") ${PPSSPP}/Contents/Info.plist
+ plutil -replace CFBundleVersion -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${LONG_VERSION_MATCH}/\$1/g") ${PPSSPP}/Contents/Info.plist
+else
+ plutil -replace CFBundleShortVersionString -string "" ${PPSSPP}/Contents/Info.plist
+ plutil -replace CFBundleVersion -string "" ${PPSSPP}/Contents/Info.plist
+fi
+
# TODO: install SDL and Qt frameworks
diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp
index 5d0d6beed8..35a4b2e278 100644
--- a/Qt/mainwindow.cpp
+++ b/Qt/mainwindow.cpp
@@ -11,6 +11,7 @@
#include "base/NativeApp.h"
#include "Core/MIPS/MIPSDebugInterface.h"
#include "Core/Debugger/SymbolMap.h"
+#include "Core/HLE/sceUmd.h"
#include "Core/SaveState.h"
#include "Core/System.h"
#include "GPU/GPUInterface.h"
@@ -78,21 +79,24 @@ void MainWindow::newFrame()
}
}
+void MainWindow::updateMenuGroupInt(QActionGroup *group, int value) {
+ foreach (QAction *action, group->actions()) {
+ action->setChecked(action->data().toInt() == value);
+ }
+}
+
void MainWindow::updateMenus()
{
- foreach(QAction * action, saveStateGroup->actions()) {
- if (g_Config.iCurrentStateSlot == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, displayRotationGroup->actions()) {
- if (g_Config.iInternalScreenRotation == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
+ updateMenuGroupInt(saveStateGroup, g_Config.iCurrentStateSlot);
+ updateMenuGroupInt(displayRotationGroup, g_Config.iInternalScreenRotation);
+ updateMenuGroupInt(renderingResolutionGroup, g_Config.iInternalResolution);
+ updateMenuGroupInt(renderingModeGroup, g_Config.iRenderingMode);
+ updateMenuGroupInt(frameSkippingGroup, g_Config.iFrameSkip);
+ updateMenuGroupInt(frameSkippingTypeGroup, g_Config.iFrameSkipType);
+ updateMenuGroupInt(textureFilteringGroup, g_Config.iTexFiltering);
+ updateMenuGroupInt(screenScalingFilterGroup, g_Config.iBufFilter);
+ updateMenuGroupInt(textureScalingLevelGroup, g_Config.iTexScalingLevel);
+ updateMenuGroupInt(textureScalingTypeGroup, g_Config.iTexScalingType);
foreach(QAction * action, windowGroup->actions()) {
int width = (g_Config.IsPortrait() ? 272 : 480) * action->data().toInt();
@@ -102,62 +106,6 @@ void MainWindow::updateMenus()
break;
}
}
-
- foreach(QAction * action, renderingResolutionGroup->actions()) {
- if (g_Config.iInternalResolution == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, renderingModeGroup->actions()) {
- if (g_Config.iRenderingMode == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, frameSkippingGroup->actions()) {
- if (g_Config.iFrameSkip == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, frameSkippingTypeGroup->actions()) {
- if (g_Config.iFrameSkipType == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, textureFilteringGroup->actions()) {
- if (g_Config.iTexFiltering == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, screenScalingFilterGroup->actions()) {
- if (g_Config.iBufFilter == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, textureScalingLevelGroup->actions()) {
- if (g_Config.iTexScalingLevel == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
-
- foreach(QAction * action, textureScalingTypeGroup->actions()) {
- if (g_Config.iTexScalingType == action->data().toInt()) {
- action->setChecked(true);
- break;
- }
- }
emit updateMenu();
}
@@ -194,7 +142,7 @@ void MainWindow::closeAct()
void MainWindow::openmsAct()
{
QString confighome = getenv("XDG_CONFIG_HOME");
- QString memorystick = confighome + "/ppsspp/PSP";
+ QString memorystick = confighome + "/ppsspp";
QDesktopServices::openUrl(QUrl(memorystick));
}
@@ -302,6 +250,17 @@ void MainWindow::resetAct()
NativeMessageReceived("reset", "");
}
+void MainWindow::switchUMDAct()
+{
+ QString filename = QFileDialog::getOpenFileName(NULL, "Switch UMD", g_Config.currentDirectory.c_str(), "PSP ROMs (*.pbp *.elf *.iso *.cso *.prx)");
+ if (QFile::exists(filename))
+ {
+ QFileInfo info(filename);
+ g_Config.currentDirectory = info.absolutePath().toStdString();
+ __UmdReplace(filename.toStdString().c_str());
+ }
+}
+
void MainWindow::breakonloadAct()
{
g_Config.bAutoRun = !g_Config.bAutoRun;
@@ -587,6 +546,8 @@ void MainWindow::createMenus()
->addEnableState(UISTATE_INGAME);
emuMenu->add(new MenuAction(this, SLOT(resetAct()), QT_TR_NOOP("R&eset"), Qt::CTRL + Qt::Key_B))
->addEnableState(UISTATE_INGAME);
+ emuMenu->add(new MenuAction(this, SLOT(switchUMDAct()), QT_TR_NOOP("Switch UMD"), Qt::CTRL + Qt::Key_U))
+ ->addEnableState(UISTATE_INGAME);
MenuTree* displayRotationMenu = new MenuTree(this, emuMenu, QT_TR_NOOP("Display rotation"));
displayRotationGroup = new MenuActionGroup(this, displayRotationMenu, SLOT(displayRotationGroup_triggered(QAction *)),
QStringList() << "Landscape" << "Portrait" << "Landscape reversed" << "Portrait reversed",
diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h
index 49112cd10d..150fc53471 100644
--- a/Qt/mainwindow.h
+++ b/Qt/mainwindow.h
@@ -41,6 +41,8 @@ public:
CoreState GetNextState() { return nextState; }
+ void updateMenuGroupInt(QActionGroup *group, int value);
+
void updateMenus();
void Notify(MainWindowMsg msg) {
@@ -93,6 +95,7 @@ private slots:
void pauseAct();
void stopAct();
void resetAct();
+ void switchUMDAct();
void displayRotationGroup_triggered(QAction *action) { g_Config.iInternalScreenRotation = action->data().toInt(); }
// Debug
diff --git a/SDL/macbundle.sh b/SDL/macbundle.sh
index efe190c1ce..423c9b09c7 100755
--- a/SDL/macbundle.sh
+++ b/SDL/macbundle.sh
@@ -25,3 +25,14 @@ SDLNAME=$(basename "${SDL}")
mkdir -p "${PPSSPP}/Contents/Frameworks" || exit 0
cp -r "$SDL" "${PPSSPP}/Contents/Frameworks" || exit 0
install_name_tool -change "${SDL}" "@executable_path/../Frameworks/${SDLNAME}" "${PPSSPPSDL}" || exit 0
+
+GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " "$(dirname "${0}")/../git-version.cpp")
+SHORT_VERSION_MATCH='.*"v([0-9\.]+(-[0-9]+)?).*";'
+LONG_VERSION_MATCH='.*"v(.*)";'
+if [[ "${GIT_VERSION_LINE}" =~ ^${SHORT_VERSION_MATCH}$ ]]; then
+ plutil -replace CFBundleShortVersionString -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${SHORT_VERSION_MATCH}/\$1/g") ${PPSSPP}/Contents/Info.plist
+ plutil -replace CFBundleVersion -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${LONG_VERSION_MATCH}/\$1/g") ${PPSSPP}/Contents/Info.plist
+else
+ plutil -replace CFBundleShortVersionString -string "" ${PPSSPP}/Contents/Info.plist
+ plutil -replace CFBundleVersion -string "" ${PPSSPP}/Contents/Info.plist
+fi
diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp
index 65dc2f0743..0652c656f3 100644
--- a/UI/ControlMappingScreen.cpp
+++ b/UI/ControlMappingScreen.cpp
@@ -636,6 +636,25 @@ void TouchTestScreen::CreateViews() {
root_ = new LinearLayout(ORIENT_VERTICAL);
LinearLayout *theTwo = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(1.0f));
root_->Add(theTwo);
+
+#if !PPSSPP_PLATFORM(UWP)
+ static const char *renderingBackend[] = { "OpenGL", "Direct3D 9", "Direct3D 11", "Vulkan" };
+ PopupMultiChoice *renderingBackendChoice = root_->Add(new PopupMultiChoice(&g_Config.iGPUBackend, gr->T("Backend"), renderingBackend, (int)GPUBackend::OPENGL, ARRAY_SIZE(renderingBackend), gr->GetName(), screenManager()));
+ renderingBackendChoice->OnChoice.Handle(this, &TouchTestScreen::OnRenderingBackend);
+
+ if (!g_Config.IsBackendEnabled(GPUBackend::OPENGL))
+ renderingBackendChoice->HideChoice((int)GPUBackend::OPENGL);
+ if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D9))
+ renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D9);
+ if (!g_Config.IsBackendEnabled(GPUBackend::DIRECT3D11))
+ renderingBackendChoice->HideChoice((int)GPUBackend::DIRECT3D11);
+ if (!g_Config.IsBackendEnabled(GPUBackend::VULKAN))
+ renderingBackendChoice->HideChoice((int)GPUBackend::VULKAN);
+#endif
+
+#if PPSSPP_PLATFORM(ANDROID)
+ root_->Add(new Choice(gr->T("Recreate Activity")))->OnClick.Handle(this, &TouchTestScreen::OnRecreateActivity);
+#endif
root_->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &TouchTestScreen::OnImmersiveModeChange);
root_->Add(new Button(di->T("Back")))->OnClick.Handle(this, &UIScreen::OnBack);
}
@@ -687,7 +706,7 @@ void TouchTestScreen::render() {
g_dpi_scale_x, g_dpi_scale_y,
g_dpi_scale_real_x, g_dpi_scale_real_y);
- ui_context->DrawTextShadow(buffer, bounds.x + 20.0f, dp_yres / 2.0f, 0xFFFFFFFF, ALIGN_VCENTER | FLAG_DYNAMIC_ASCII);
+ ui_context->DrawTextShadow(buffer, bounds.x + 20.0f, bounds.y + 20.0f, 0xFFFFFFFF, FLAG_DYNAMIC_ASCII);
ui_context->Flush();
}
@@ -700,3 +719,14 @@ UI::EventReturn TouchTestScreen::OnImmersiveModeChange(UI::EventParams &e) {
}
return UI::EVENT_DONE;
}
+
+UI::EventReturn TouchTestScreen::OnRenderingBackend(UI::EventParams &e) {
+ g_Config.Save("GameSettingsScreen::RenderingBackend");
+ System_SendMessage("graphics_restart", "--touchscreentest");
+ return UI::EVENT_DONE;
+}
+
+UI::EventReturn TouchTestScreen::OnRecreateActivity(UI::EventParams &e) {
+ RecreateActivity();
+ return UI::EVENT_DONE;
+}
diff --git a/UI/ControlMappingScreen.h b/UI/ControlMappingScreen.h
index 130596ee05..3d7b6879e5 100644
--- a/UI/ControlMappingScreen.h
+++ b/UI/ControlMappingScreen.h
@@ -132,6 +132,9 @@ protected:
};
TrackedTouch touches_[MAX_TOUCH_POINTS]{};
- virtual void CreateViews() override;
+ void CreateViews() override;
+
UI::EventReturn OnImmersiveModeChange(UI::EventParams &e);
+ UI::EventReturn OnRenderingBackend(UI::EventParams &e);
+ UI::EventReturn OnRecreateActivity(UI::EventParams &e);
};
diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp
index d99e1f52cc..db8acfddcd 100644
--- a/UI/GameSettingsScreen.cpp
+++ b/UI/GameSettingsScreen.cpp
@@ -1262,14 +1262,25 @@ void GameSettingsScreen::CallbackMemstickFolder(bool yes) {
}
#endif
+void GameSettingsScreen::TriggerRestart(const char *why) {
+ // 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(why);
+ std::string param = "--gamesettings";
+ if (editThenRestore_) {
+ // We won't pass the gameID, so don't resume back into settings.
+ param = "";
+ } else if (!gamePath_.empty()) {
+ param += " \"" + ReplaceAll(ReplaceAll(gamePath_, "\\", "\\\\"), "\"", "\\\"") + "\"";
+ }
+ System_SendMessage("graphics_restart", param.c_str());
+}
+
void GameSettingsScreen::CallbackRenderingBackend(bool yes) {
// If the user ends up deciding not to restart, set the config back to the current backend
// so it doesn't get switched by accident.
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("GameSettingsScreen::RenderingBackendYes");
- System_SendMessage("graphics_restart", "");
+ TriggerRestart("GameSettingsScreen::RenderingBackendYes");
} else {
g_Config.iGPUBackend = (int)GetGPUBackend();
}
@@ -1279,10 +1290,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) {
// If the user ends up deciding not to restart, set the config back to the current backend
// so it doesn't get switched by accident.
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("GameSettingsScreen::RenderingDeviceYes");
- System_SendMessage("graphics_restart", "");
+ TriggerRestart("GameSettingsScreen::RenderingDeviceYes");
} else {
std::string *deviceNameSetting = GPUDeviceNameSetting();
if (deviceNameSetting)
@@ -1294,8 +1302,7 @@ void GameSettingsScreen::CallbackRenderingDevice(bool yes) {
void GameSettingsScreen::CallbackInflightFrames(bool yes) {
if (yes) {
- g_Config.Save("GameSettingsScreen::InflightFramesYes");
- System_SendMessage("graphics_restart", "");
+ TriggerRestart("GameSettingsScreen::InflightFramesYes");
} else {
g_Config.iInflightFrames = prevInflightFrames_;
}
diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h
index 096c13e136..997a9e011a 100644
--- a/UI/GameSettingsScreen.h
+++ b/UI/GameSettingsScreen.h
@@ -48,6 +48,8 @@ protected:
bool UseVerticalLayout() const;
private:
+ void TriggerRestart(const char *why);
+
std::string gameID_;
bool lastVertical_;
UI::CheckBox *enableReportsCheckbox_;
diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp
index b49b523ae5..55c9b4e3cc 100644
--- a/UI/MiscScreens.cpp
+++ b/UI/MiscScreens.cpp
@@ -420,7 +420,14 @@ void NewLanguageScreen::OnCompleted(DialogResult result) {
void LogoScreen::Next() {
if (!switched_) {
switched_ = true;
- if (boot_filename.size()) {
+ if (gotoGameSettings_) {
+ if (boot_filename.size()) {
+ screenManager()->switchScreen(new EmuScreen(boot_filename));
+ } else {
+ screenManager()->switchScreen(new MainScreen());
+ }
+ screenManager()->push(new GameSettingsScreen(boot_filename));
+ } else if (boot_filename.size()) {
screenManager()->switchScreen(new EmuScreen(boot_filename));
} else {
screenManager()->switchScreen(new MainScreen());
@@ -564,7 +571,7 @@ UI::EventReturn CreditsScreen::OnForums(UI::EventParams &e) {
UI::EventReturn CreditsScreen::OnShare(UI::EventParams &e) {
auto cr = GetI18NCategory("PSPCredits");
- System_SendMessage("sharetext", cr->T("CheckOutPPSSPP", "Check out PPSSPP, the awesome PSP emulator: http://www.ppsspp.org/"));
+ System_SendMessage("sharetext", cr->T("CheckOutPPSSPP", "Check out PPSSPP, the awesome PSP emulator: https://www.ppsspp.org/"));
return UI::EVENT_DONE;
}
diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h
index 4c08772a0a..2609be6dfc 100644
--- a/UI/MiscScreens.h
+++ b/UI/MiscScreens.h
@@ -114,8 +114,8 @@ private:
class LogoScreen : public UIScreen {
public:
- LogoScreen()
- : frames_(0), switched_(false) {}
+ LogoScreen(bool gotoGameSettings = false)
+ : gotoGameSettings_(gotoGameSettings) {}
bool key(const KeyInput &key) override;
bool touch(const TouchInput &touch) override;
void update() override;
@@ -125,8 +125,9 @@ public:
private:
void Next();
- int frames_;
- bool switched_;
+ int frames_ = 0;
+ bool switched_ = false;
+ bool gotoGameSettings_ = false;
};
class CreditsScreen : public UIDialogScreenWithBackground {
diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp
index a74197b85b..a0da9229c7 100644
--- a/UI/NativeApp.cpp
+++ b/UI/NativeApp.cpp
@@ -92,17 +92,18 @@
#include "Core/WebServer.h"
#include "GPU/GPUInterface.h"
+#include "UI/BackgroundAudio.h"
+#include "UI/ControlMappingScreen.h"
+#include "UI/DiscordIntegration.h"
#include "UI/EmuScreen.h"
#include "UI/GameInfoCache.h"
+#include "UI/GPUDriverTestScreen.h"
#include "UI/HostTypes.h"
-#include "UI/OnScreenDisplay.h"
#include "UI/MiscScreens.h"
+#include "UI/OnScreenDisplay.h"
#include "UI/RemoteISOScreen.h"
#include "UI/TiltEventProcessor.h"
-#include "UI/BackgroundAudio.h"
#include "UI/TextureUtil.h"
-#include "UI/DiscordIntegration.h"
-#include "UI/GPUDriverTestScreen.h"
#if !defined(MOBILE_DEVICE)
#include "Common/KeyMap.h"
@@ -551,6 +552,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
const char *stateToLoad = 0;
bool gotBootFilename = false;
+ bool gotoGameSettings = false;
+ bool gotoTouchScreenTest = false;
boot_filename = "";
// Parse command line
@@ -593,6 +596,10 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
g_Config.bPauseMenuExitsEmulator = true;
if (!strcmp(argv[i], "--fullscreen"))
g_Config.bFullScreen = true;
+ if (!strcmp(argv[i], "--touchscreentest"))
+ gotoTouchScreenTest = true;
+ if (!strcmp(argv[i], "--gamesettings"))
+ gotoGameSettings = true;
break;
}
} else {
@@ -628,7 +635,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
std::unique_ptr fileLoader(ConstructFileLoader(boot_filename));
if (!fileLoader->Exists()) {
fprintf(stderr, "File not found: %s\n", boot_filename.c_str());
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__ANDROID__)
// Ignore and proceed.
#else
// Bail.
@@ -638,7 +645,7 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
} else {
fprintf(stderr, "Can only boot one file");
-#ifdef _WIN32
+#if defined(_WIN32) || defined(__ANDROID__)
// Ignore and proceed.
#else
// Bail.
@@ -711,7 +718,12 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
}
screenManager = new ScreenManager();
- if (skipLogo) {
+ if (gotoGameSettings) {
+ screenManager->switchScreen(new LogoScreen(true));
+ } else if (gotoTouchScreenTest) {
+ screenManager->switchScreen(new MainScreen());
+ screenManager->push(new TouchTestScreen());
+ } else if (skipLogo) {
screenManager->switchScreen(new EmuScreen(boot_filename));
} else {
screenManager->switchScreen(new LogoScreen());
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 814930607b..0bbac0c46e 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -466,6 +466,7 @@
+
@@ -678,6 +679,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 07d1e09371..7afcc97e71 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -368,6 +368,9 @@
HLE
+
+ HLE
+
HLE
@@ -968,6 +971,9 @@
HLE
+
+ HLE
+
HLE
@@ -1298,4 +1304,4 @@
HW
-
\ No newline at end of file
+
diff --git a/Windows/GPU/WindowsGLContext.cpp b/Windows/GPU/WindowsGLContext.cpp
index f0aa0ba45a..71e215c0bc 100644
--- a/Windows/GPU/WindowsGLContext.cpp
+++ b/Windows/GPU/WindowsGLContext.cpp
@@ -290,6 +290,9 @@ bool WindowsGLContext::InitFromRenderThread(std::string *error_message) {
// Unfortunately, glew will generate an invalid enum error, ignore.
glGetError();
+ // Reset in case we're in a backend switch.
+ ResetGLExtensions();
+
int contextFlags = g_Config.bGfxDebugOutput ? WGL_CONTEXT_DEBUG_BIT_ARB : 0;
HGLRC m_hrc = nullptr;
diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp
index 85040cdf94..cd6077f0a3 100644
--- a/Windows/MainWindowMenu.cpp
+++ b/Windows/MainWindowMenu.cpp
@@ -453,7 +453,7 @@ namespace MainWindow {
filter[i] = '\0';
}
- if (W32Util::BrowseForFileName(true, GetHWND(), L"Switch Umd", 0, ConvertUTF8ToWString(filter).c_str(), L"*.pbp;*.elf;*.iso;*.cso;", fn)) {
+ if (W32Util::BrowseForFileName(true, GetHWND(), L"Switch UMD", 0, ConvertUTF8ToWString(filter).c_str(), L"*.pbp;*.elf;*.iso;*.cso;", fn)) {
fn = ReplaceAll(fn, "\\", "/");
__UmdReplace(fn);
}
@@ -764,8 +764,10 @@ namespace MainWindow {
case ID_OPTIONS_FRAMESKIP_AUTO:
g_Config.bAutoFrameSkip = !g_Config.bAutoFrameSkip;
- if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE)
+ if (g_Config.bAutoFrameSkip && g_Config.iRenderingMode == FB_NON_BUFFERED_MODE) {
g_Config.iRenderingMode = FB_BUFFERED_MODE;
+ NativeMessageReceived("gpu_resized", "");
+ }
break;
case ID_TEXTURESCALING_AUTO: setTexScalingMultiplier(TEXSCALING_AUTO); break;
diff --git a/Windows/PPSSPP.vcxproj b/Windows/PPSSPP.vcxproj
index 1792fb969b..56ab76c30e 100644
--- a/Windows/PPSSPP.vcxproj
+++ b/Windows/PPSSPP.vcxproj
@@ -238,7 +238,7 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h;Common/DbgNew.h
MultiThreadedDebug
StreamingSIMDExtensions2
@@ -249,7 +249,8 @@
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/x86/lib
true
Windows
MachineX86
@@ -275,7 +276,7 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h;Common/DbgNew.h
MultiThreadedDebug
false
@@ -287,7 +288,8 @@
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/x86_64/lib
true
$(OutDir)$(ProjectName).pdb
true
@@ -309,7 +311,7 @@
Use
Level3
ProgramDatabase
- ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h;Common/DbgNew.h
MultiThreadedDebug
false
@@ -321,7 +323,8 @@
$(EXTERNAL_COMPILE_OPTIONS)
- oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\aarch64\lib\avcodec.lib;..\ffmpeg\Windows\aarch64\lib\avformat.lib;..\ffmpeg\Windows\aarch64\lib\avutil.lib;..\ffmpeg\Windows\aarch64\lib\swresample.lib;..\ffmpeg\Windows\aarch64\lib\swscale.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/aarch64/lib
true
$(OutDir)$(ProjectName).pdb
true
@@ -342,7 +345,7 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h
MultiThreadedDebug
false
@@ -354,7 +357,8 @@
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/arm/lib
true
$(OutDir)$(ProjectName).pdb
true
@@ -382,7 +386,7 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h
stdafx.h
true
@@ -390,9 +394,9 @@
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/x86/lib;%(AdditionalLibraryDirectories)
$(OutDir)$(TargetName)$(TargetExt)
- %(AdditionalLibraryDirectories)
true
Windows
true
@@ -431,15 +435,15 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h
true
false
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)
- %(AdditionalLibraryDirectories)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/x86_64/lib;%(AdditionalLibraryDirectories)
true
Windows
true
@@ -473,15 +477,15 @@
Use
Level3
ProgramDatabase
- ../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h
true
false
$(EXTERNAL_COMPILE_OPTIONS)
- oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\aarch64\lib\avcodec.lib;..\ffmpeg\Windows\aarch64\lib\avformat.lib;..\ffmpeg\Windows\aarch64\lib\avutil.lib;..\ffmpeg\Windows\aarch64\lib\swresample.lib;..\ffmpeg\Windows\aarch64\lib\swscale.lib;%(AdditionalDependencies)
- %(AdditionalLibraryDirectories)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/aarch64/lib;%(AdditionalLibraryDirectories)
true
Windows
true
@@ -514,15 +518,15 @@
Use
Level3
ProgramDatabase
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
stdafx.h
true
false
$(EXTERNAL_COMPILE_OPTIONS)
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)
- %(AdditionalLibraryDirectories)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;%(AdditionalDependencies)
+ ../ffmpeg/Windows/arm/lib;%(AdditionalLibraryDirectories)
true
Windows
true
diff --git a/Windows/W32Util/Misc.cpp b/Windows/W32Util/Misc.cpp
index ca26ad7a4b..3bb86f6bf6 100644
--- a/Windows/W32Util/Misc.cpp
+++ b/Windows/W32Util/Misc.cpp
@@ -153,13 +153,20 @@ namespace W32Util
moduleFilename.resize(sz);
}
- void ExitAndRestart() {
+ void ExitAndRestart(bool overrideArgs, const std::string &args) {
// This preserves arguments (for example, config file) and working directory.
std::wstring workingDirectory;
std::wstring moduleFilename;
GetSelfExecuteParams(workingDirectory, moduleFilename);
- const wchar_t *cmdline = RemoveExecutableFromCommandLine(GetCommandLineW());
+ const wchar_t *cmdline;
+ std::wstring wargs;
+ if (overrideArgs) {
+ wargs = ConvertUTF8ToWString(args);
+ cmdline = wargs.c_str();
+ } else {
+ cmdline = RemoveExecutableFromCommandLine(GetCommandLineW());
+ }
ShellExecute(nullptr, nullptr, moduleFilename.c_str(), cmdline, workingDirectory.c_str(), SW_SHOW);
ExitProcess(0);
diff --git a/Windows/W32Util/Misc.h b/Windows/W32Util/Misc.h
index 680a48c62e..623de73233 100644
--- a/Windows/W32Util/Misc.h
+++ b/Windows/W32Util/Misc.h
@@ -11,7 +11,7 @@ namespace W32Util
BOOL CopyTextToClipboard(HWND hwnd, const char *text);
BOOL CopyTextToClipboard(HWND hwnd, const std::wstring &wtext);
void MakeTopMost(HWND hwnd, bool topMost);
- void ExitAndRestart();
+ void ExitAndRestart(bool overrideArgs = false, const std::string &args = "");
void GetSelfExecuteParams(std::wstring &workingDirectory, std::wstring &moduleFilename);
}
diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp
index 22c584bbb5..3b04029bf8 100644
--- a/Windows/WASAPIStream.cpp
+++ b/Windows/WASAPIStream.cpp
@@ -46,7 +46,9 @@ public:
if (currentDevice_)
CoTaskMemFree(currentDevice_);
- device->GetId(¤tDevice_);
+ if (!device || FAILED(device->GetId(¤tDevice_))) {
+ currentDevice_ = nullptr;
+ }
deviceChanged_ = false;
}
@@ -75,7 +77,7 @@ public:
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
} else {
- *ppvInterface = NULL;
+ *ppvInterface = nullptr;
return E_NOINTERFACE;
}
return S_OK;
@@ -92,7 +94,11 @@ public:
}
// pwstrDeviceId can be null. We consider that a new device, I think?
- if (pwstrDeviceId && !wcscmp(currentDevice_, pwstrDeviceId)) {
+ bool same = currentDevice_ == pwstrDeviceId;
+ if (!same && currentDevice_ && pwstrDeviceId) {
+ same = !wcscmp(currentDevice_, pwstrDeviceId);
+ }
+ if (same) {
// Already the current device, nothing to do.
return S_OK;
}
@@ -226,12 +232,14 @@ WASAPIAudioThread::~WASAPIAudioThread() {
}
bool WASAPIAudioThread::ActivateDefaultDevice() {
+ assert(device_ == nullptr);
HRESULT hresult = deviceEnumerator_->GetDefaultAudioEndpoint(eRender, eMultimedia, &device_);
- if (FAILED(hresult))
+ if (FAILED(hresult) || device_ == nullptr)
return false;
- hresult = device_->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audioInterface_);
- if (FAILED(hresult))
+ assert(audioInterface_ == nullptr);
+ hresult = device_->Activate(IID_IAudioClient, CLSCTX_ALL, nullptr, (void **)&audioInterface_);
+ if (FAILED(hresult) || audioInterface_ == nullptr)
return false;
return true;
@@ -239,15 +247,23 @@ bool WASAPIAudioThread::ActivateDefaultDevice() {
bool WASAPIAudioThread::InitAudioDevice() {
REFERENCE_TIME hnsBufferDuration = REFTIMES_PER_SEC;
+ assert(deviceFormat_ == nullptr);
HRESULT hresult = audioInterface_->GetMixFormat((WAVEFORMATEX **)&deviceFormat_);
- hresult = audioInterface_->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &deviceFormat_->Format, nullptr);
- hresult = audioInterface_->GetService(IID_IAudioRenderClient, (void **)&renderClient_);
- if (FAILED(hresult))
+ if (FAILED(hresult) || !deviceFormat_)
return false;
- hresult = audioInterface_->GetBufferSize(&numBufferFrames);
+ hresult = audioInterface_->Initialize(AUDCLNT_SHAREMODE_SHARED, 0, hnsBufferDuration, 0, &deviceFormat_->Format, nullptr);
if (FAILED(hresult))
return false;
+ assert(renderClient_ == nullptr);
+ hresult = audioInterface_->GetService(IID_IAudioRenderClient, (void **)&renderClient_);
+ if (FAILED(hresult) || !renderClient_)
+ return false;
+
+ numBufferFrames = 0;
+ hresult = audioInterface_->GetBufferSize(&numBufferFrames);
+ if (FAILED(hresult) || numBufferFrames == 0)
+ return false;
sampleRate_ = deviceFormat_->Format.nSamplesPerSec;
@@ -291,17 +307,23 @@ bool WASAPIAudioThread::DetectFormat() {
return false;
}
- BYTE *pData;
+ BYTE *pData = nullptr;
HRESULT hresult = renderClient_->GetBuffer(numBufferFrames, &pData);
+ if (FAILED(hresult) || !pData)
+ return false;
+
const int numSamples = numBufferFrames * deviceFormat_->Format.nChannels;
if (format_ == Format::IEEE_FLOAT) {
memset(pData, 0, sizeof(float) * numSamples);
- shortBuf_ = new short[numBufferFrames * deviceFormat_->Format.nChannels];
+ shortBuf_ = new short[numSamples];
} else if (format_ == Format::PCM16) {
memset(pData, 0, sizeof(short) * numSamples);
}
hresult = renderClient_->ReleaseBuffer(numBufferFrames, 0);
+ if (FAILED(hresult))
+ return false;
+
actualDuration_ = (REFERENCE_TIME)((double)REFTIMES_PER_SEC * numBufferFrames / deviceFormat_->Format.nSamplesPerSec);
return true;
}
@@ -309,10 +331,11 @@ bool WASAPIAudioThread::DetectFormat() {
void WASAPIAudioThread::Run() {
// Adapted from http://msdn.microsoft.com/en-us/library/windows/desktop/dd316756(v=vs.85).aspx
+ assert(deviceEnumerator_ == nullptr);
HRESULT hresult = CoCreateInstance(CLSID_MMDeviceEnumerator,
nullptr, /* Object is not created as the part of the aggregate */
CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&deviceEnumerator_);
- if (FAILED(hresult))
+ if (FAILED(hresult) || deviceEnumerator_ == nullptr)
return;
if (!ActivateDefaultDevice()) {
@@ -339,12 +362,16 @@ void WASAPIAudioThread::Run() {
}
hresult = audioInterface_->Start();
+ if (FAILED(hresult)) {
+ ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream");
+ return;
+ }
DWORD flags = 0;
while (flags != AUDCLNT_BUFFERFLAGS_SILENT) {
Sleep((DWORD)(actualDuration_ / REFTIMES_PER_MILLISEC / 2));
- uint32_t pNumPaddingFrames;
+ uint32_t pNumPaddingFrames = 0;
hresult = audioInterface_->GetCurrentPadding(&pNumPaddingFrames);
if (FAILED(hresult)) {
// What to do?
@@ -352,9 +379,9 @@ void WASAPIAudioThread::Run() {
}
uint32_t pNumAvFrames = numBufferFrames - pNumPaddingFrames;
- BYTE *pData;
+ BYTE *pData = nullptr;
hresult = renderClient_->GetBuffer(pNumAvFrames, &pData);
- if (FAILED(hresult)) {
+ if (FAILED(hresult) || pData == nullptr) {
// What to do?
} else if (pNumAvFrames) {
switch (format_) {
@@ -382,9 +409,11 @@ void WASAPIAudioThread::Run() {
flags = AUDCLNT_BUFFERFLAGS_SILENT;
}
- hresult = renderClient_->ReleaseBuffer(pNumAvFrames, flags);
- if (FAILED(hresult)) {
- // Not much to do here either...
+ if (!FAILED(hresult) && pData) {
+ hresult = renderClient_->ReleaseBuffer(pNumAvFrames, flags);
+ if (FAILED(hresult)) {
+ // Not much to do here either...
+ }
}
// Check if we should use a new device.
@@ -407,6 +436,10 @@ void WASAPIAudioThread::Run() {
}
hresult = audioInterface_->Start();
+ if (FAILED(hresult)) {
+ ERROR_LOG(SCEAUDIO, "WASAPI: Failed to start audio stream");
+ return;
+ }
}
}
@@ -414,6 +447,9 @@ void WASAPIAudioThread::Run() {
Sleep((DWORD)(actualDuration_ / REFTIMES_PER_MILLISEC / 2));
hresult = audioInterface_->Stop();
+ if (FAILED(hresult)) {
+ ERROR_LOG(SCEAUDIO, "WASAPI: Failed to stop audio stream");
+ }
}
int WASAPIAudioBackend::RunThread() {
diff --git a/Windows/main.cpp b/Windows/main.cpp
index 73938e6093..3795597e26 100644
--- a/Windows/main.cpp
+++ b/Windows/main.cpp
@@ -96,6 +96,8 @@ static std::string langRegion;
static std::string osName;
static std::string gpuDriverVersion;
+static std::string restartArgs;
+
HMENU g_hPopupMenus;
int g_activeWindow = 0;
@@ -283,6 +285,7 @@ void System_SendMessage(const char *command, const char *parameter) {
PostMessage(MainWindow::GetHWND(), WM_CLOSE, 0, 0);
}
} else if (!strcmp(command, "graphics_restart")) {
+ restartArgs = parameter == nullptr ? "" : parameter;
if (IsDebuggerPresent()) {
PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_RESTART_EMUTHREAD, 0, 0);
} else {
@@ -415,7 +418,14 @@ static bool DetectVulkanInExternalProcess() {
std::vector GetWideCmdLine() {
wchar_t **wargv;
int wargc = -1;
- wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
+ // This is used for the WM_USER_RESTART_EMUTHREAD path.
+ if (!restartArgs.empty()) {
+ std::wstring wargs = ConvertUTF8ToWString("PPSSPP " + restartArgs);
+ wargv = CommandLineToArgvW(wargs.c_str(), &wargc);
+ restartArgs.clear();
+ } else {
+ wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
+ }
std::vector wideArgs(wargv, wargv + wargc);
LocalFree(wargv);
@@ -447,12 +457,12 @@ static void WinMainInit() {
}
static void WinMainCleanup() {
- if (g_Config.bRestartRequired) {
- W32Util::ExitAndRestart();
- }
-
net::Shutdown();
CoUninitialize();
+
+ if (g_Config.bRestartRequired) {
+ W32Util::ExitAndRestart(!restartArgs.empty(), restartArgs);
+ }
}
int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow) {
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index bd0ce81ff0..3c5a48a78a 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -54,6 +54,7 @@
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index d334324cf8..6f23ada75f 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -360,6 +360,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceKernel.cpp \
$(SRC)/Core/HLE/sceKernelAlarm.cpp \
$(SRC)/Core/HLE/sceKernelEventFlag.cpp \
+ $(SRC)/Core/HLE/sceKernelHeap.cpp \
$(SRC)/Core/HLE/sceKernelInterrupt.cpp \
$(SRC)/Core/HLE/sceKernelMemory.cpp \
$(SRC)/Core/HLE/sceKernelModule.cpp \
diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp
index 88b66a00e9..086371085d 100644
--- a/android/jni/app-android.cpp
+++ b/android/jni/app-android.cpp
@@ -14,9 +14,40 @@
#include
#include
+#ifndef _MSC_VER
#include
#include
#include
+#elif !defined(JNIEXPORT)
+// Just for better highlighting in MSVC if opening this file.
+// Not having types makes it get confused and say everything is wrong.
+struct JavaVM;
+typedef void *jmethodID;
+typedef void *jfieldID;
+
+typedef uint8_t jboolean;
+typedef int8_t jbyte;
+typedef int16_t jshort;
+typedef int32_t jint;
+typedef int64_t jlong;
+typedef jint jsize;
+typedef float jfloat;
+typedef double jdouble;
+
+class _jobject {};
+class _jclass : public _jobject {};
+typedef _jobject *jobject;
+typedef _jclass *jclass;
+typedef jobject jstring;
+typedef jobject jbyteArray;
+
+struct JNIEnv {};
+
+#define JNIEXPORT
+#define JNICALL
+// Just a random value to make MSVC highlighting happy.
+#define JNI_VERSION_1_6 16
+#endif
#include "base/basictypes.h"
#include "base/stringutil.h"
@@ -399,6 +430,64 @@ extern "C" jstring Java_org_ppsspp_ppsspp_NativeApp_queryConfig
return jresult;
}
+static void parse_args(std::vector &args, const std::string value) {
+ // Simple argument parser so we can take args from extra params.
+ const char *p = value.c_str();
+
+ while (*p != '\0') {
+ while (isspace(*p)) {
+ p++;
+ }
+ if (*p == '\0') {
+ break;
+ }
+
+ bool done = false;
+ bool quote = false;
+ std::string arg;
+
+ while (!done) {
+ size_t sz = strcspn(p, "\"\\ \r\n\t");
+ arg += std::string(p, sz);
+ p += sz;
+
+ switch (*p) {
+ case '"':
+ quote = !quote;
+ p++;
+ break;
+
+ case '\\':
+ p++;
+ arg += std::string(p, 1);
+ p++;
+ break;
+
+ case '\0':
+ done = true;
+ break;
+
+ default:
+ // If it's not the above, it's whitespace.
+ if (!quote) {
+ done = true;
+ } else {
+ sz = strspn(p, " \r\n\t");
+ arg += std::string(p, sz);
+ p += sz;
+ }
+ break;
+ }
+ }
+
+ args.push_back(arg);
+
+ while (isspace(*p)) {
+ p++;
+ }
+ }
+}
+
extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
(JNIEnv *env, jclass, jstring jmodel, jint jdeviceType, jstring jlangRegion, jstring japkpath,
jstring jdataDir, jstring jexternalDir, jstring jlibraryDir, jstring jcacheDir, jstring jshortcutParam,
@@ -455,18 +544,22 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
NativeGetAppInfo(&app_name, &app_nice_name, &landscape, &version);
- // If shortcut_param is not empty, pass it as additional varargs argument to NativeInit() method.
+ // If shortcut_param is not empty, pass it as additional arguments to the NativeInit() method.
// NativeInit() is expected to treat extra argument as boot_filename, which in turn will start game immediately.
// NOTE: Will only work if ppsspp started from Activity.onCreate(). Won't work if ppsspp app start from onResume().
- if (shortcut_param.empty()) {
- const char *argv[2] = {app_name.c_str(), 0};
- NativeInit(1, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
- } else {
- const char *argv[3] = {app_name.c_str(), shortcut_param.c_str(), 0};
- NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
+ std::vector args;
+ std::vector temp;
+ args.push_back(app_name.c_str());
+ if (!shortcut_param.empty()) {
+ parse_args(temp, shortcut_param);
+ for (const auto &arg : temp) {
+ args.push_back(arg.c_str());
+ }
}
+ NativeInit((int)args.size(), &args[0], user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
+
retry:
// Now that we've loaded config, set javaGL.
javaGL = NativeQueryConfig("androidJavaGL") == "true";
@@ -968,14 +1061,21 @@ void getDesiredBackbufferSize(int &sz_x, int &sz_y) {
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_setDisplayParameters(JNIEnv *, jclass, jint xres, jint yres, jint dpi, jfloat refreshRate) {
ILOG("NativeApp.setDisplayParameters(%d x %d, dpi=%d, refresh=%0.2f)", xres, yres, dpi, refreshRate);
- display_xres = xres;
- display_yres = yres;
- display_dpi_x = dpi;
- display_dpi_y = dpi;
- display_hz = refreshRate;
+ bool changed = false;
+ changed = changed || display_xres != xres || display_yres != yres;
+ changed = changed || display_dpi_x != dpi || display_dpi_y != dpi;
+ changed = changed || display_hz != refreshRate;
- recalculateDpi();
- NativeResized();
+ if (changed) {
+ display_xres = xres;
+ display_yres = yres;
+ display_dpi_x = dpi;
+ display_dpi_y = dpi;
+ display_hz = refreshRate;
+
+ recalculateDpi();
+ NativeResized();
+ }
}
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeApp_computeDesiredBackbufferDimensions() {
diff --git a/android/res/drawable-xhdpi/ouya_icon.png b/android/res/drawable-xhdpi/ouya_icon.png
new file mode 100644
index 0000000000..4c294e4ea0
Binary files /dev/null and b/android/res/drawable-xhdpi/ouya_icon.png differ
diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java
index 09205d17fe..2b6f2d4890 100644
--- a/android/src/org/ppsspp/ppsspp/NativeActivity.java
+++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java
@@ -28,25 +28,17 @@ import android.os.PowerManager;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.text.InputType;
-import android.util.DisplayMetrics;
import android.util.Log;
-import android.view.Display;
-import android.view.DisplayCutout;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
-import android.view.OrientationEventListener;
import android.view.Surface;
-import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
-import android.view.View.OnSystemUiVisibilityChangeListener;
-import android.view.ViewGroup;
import android.view.Window;
-import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -59,7 +51,7 @@ import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-public abstract class NativeActivity extends Activity implements SurfaceHolder.Callback {
+public abstract class NativeActivity extends Activity {
// Remember to loadLibrary your JNI .so in a static {} block
// Adjust these as necessary
@@ -81,6 +73,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
protected NativeRenderer nativeRenderer;
private String shortcutParam = "";
+ private static String overrideShortcutParam = null;
public static String runCommand;
public static String commandParameter;
@@ -91,7 +84,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
private boolean sustainedPerfSupported;
- private boolean navigationHidden;
private View navigationCallbackView = null;
// audioFocusChangeListener to listen to changes in audio state
@@ -116,20 +108,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
private String inputPlayerADesc;
private PowerSaveModeReceiver mPowerSaveModeReceiver = null;
-
+ private SizeManager sizeManager = null;
private static LocationHelper mLocationHelper;
private static CameraHelper mCameraHelper;
- private float densityDpi;
- private float refreshRate;
- private int pixelWidth;
- private int pixelHeight;
-
- private int safeInsetLeft = 0;
- private int safeInsetRight = 0;
- private int safeInsetTop = 0;
- private int safeInsetBottom = 0;
-
private static final String[] permissionsForStorage = {
Manifest.permission.WRITE_EXTERNAL_STORAGE,
};
@@ -319,9 +301,11 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
String model = Build.MANUFACTURER + ":" + Build.MODEL;
String languageRegion = Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry();
+ String shortcut = overrideShortcutParam == null ? shortcutParam : overrideShortcutParam;
+ overrideShortcutParam = null;
NativeApp.audioConfig(optimalFramesPerBuffer, optimalSampleRate);
- NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcutParam, Build.VERSION.SDK_INT, Build.BOARD);
+ NativeApp.init(model, deviceType, languageRegion, apkFilePath, dataDir, externalStorageDir, libraryDir, cacheDir, shortcut, Build.VERSION.SDK_INT, Build.BOARD);
// Allow C++ to tell us to use JavaGL or not.
javaGL = "true".equalsIgnoreCase(NativeApp.queryConfig("androidJavaGL"));
@@ -437,7 +421,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
} else {
Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring for now");
}
- updateDisplayMeasurements();
+ sizeManager.checkDisplayMeasurements();
}
// Need API 11 to check for existence of a vibrator? Zany.
@@ -467,48 +451,10 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
// Tells the render loop thread to exit, so we can restart it.
public native void exitEGLRenderLoop();
- public void getDesiredBackbufferSize(Point sz) {
- NativeApp.computeDesiredBackbufferDimensions();
- sz.x = NativeApp.getDesiredBackbufferWidth();
- sz.y = NativeApp.getDesiredBackbufferHeight();
- }
-
- private SurfaceView getSurfaceView() {
- if (mGLSurfaceView != null) {
- return mGLSurfaceView;
- } else {
- return mSurfaceView;
- }
- }
-
- @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
- public void updateDisplayMeasurements() {
- Display display = getWindowManager().getDefaultDisplay();
-
- // Early in startup, we don't have a view to query. Do our best to get some kind of size
- // that can be used by config default heuristics, and so on.
- DisplayMetrics metrics = new DisplayMetrics();
- if (navigationHidden && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- display.getRealMetrics(metrics);
- } else {
- display.getMetrics(metrics);
- }
-
- // Later on, we have the exact pixel size so let's just use it.
- SurfaceView view = getSurfaceView();
- if (view != null) {
- metrics.widthPixels = view.getWidth();
- metrics.heightPixels = view.getHeight();
- }
- densityDpi = metrics.densityDpi;
- refreshRate = display.getRefreshRate();
-
- NativeApp.setDisplayParameters(metrics.widthPixels, metrics.heightPixels, (int) densityDpi, refreshRate);
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ sizeManager = new SizeManager(this);
TextRenderer.init(this);
shuttingDown = false;
registerCallbacks();
@@ -516,7 +462,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
// This calls NativeApp.setDisplayParameters. Make sure that's done early in order
// to be able to set defaults when loading config for the first time. Like figuring out
// whether to start at 1x or 2x.
- updateDisplayMeasurements();
+ sizeManager.updateDisplayMeasurements();
if (!initialized) {
Initialize();
@@ -540,7 +486,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
mGLSurfaceView = new NativeGLView(this);
nativeRenderer = new NativeRenderer(this);
mGLSurfaceView.setEGLContextClientVersion(2);
- mGLSurfaceView.getHolder().addCallback(NativeActivity.this);
+ sizeManager.setSurfaceView(mGLSurfaceView);
// Setup the GLSurface and ask android for the correct
// Number of bits for r, g, b, a, depth and stencil components
@@ -572,93 +518,28 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
}
mGLSurfaceView.setRenderer(nativeRenderer);
setContentView(mGLSurfaceView);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- mGLSurfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
- @Override
- public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
- checkInsets(windowInsets);
- return windowInsets;
- }
- });
- }
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
updateSystemUiVisibility();
}
mSurfaceView = new NativeSurfaceView(NativeActivity.this);
- mSurfaceView.getHolder().addCallback(NativeActivity.this);
+ sizeManager.setSurfaceView(mSurfaceView);
Log.i(TAG, "setcontentview before");
setContentView(mSurfaceView);
Log.i(TAG, "setcontentview after");
ensureRenderLoop();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- mSurfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
- @Override
- public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
- checkInsets(windowInsets);
- return windowInsets;
- }
- });
- }
}
}
- private Point desiredSize = new Point();
- private int badOrientationCount = 0;
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- pixelWidth = holder.getSurfaceFrame().width();
- pixelHeight = holder.getSurfaceFrame().height();
-
- // Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
- int requestedOr = getRequestedOrientation();
- boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
- boolean detectedPortrait = pixelHeight > pixelWidth;
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && badOrientationCount < 3 && requestedPortrait != detectedPortrait && requestedOr != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
- Log.e(TAG, "Bad orientation detected (w=" + pixelWidth + " h=" + pixelHeight + "! Recreating activity.");
- badOrientationCount++;
- recreate();
- return;
- } else if (requestedPortrait == detectedPortrait) {
- Log.i(TAG, "Correct orientation detected, resetting orientation counter.");
- badOrientationCount = 0;
- } else {
- Log.i(TAG, "Bad orientation detected but ignored" + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? " (sdk version)" : ""));
- }
-
- Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr);
- NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int) densityDpi, refreshRate);
- getDesiredBackbufferSize(desiredSize);
-
- // Note that desiredSize might be 0,0 here - but that's fine when calling setFixedSize! It means auto.
- Log.d(TAG, "Setting fixed size " + desiredSize.x + " x " + desiredSize.y);
- holder.setFixedSize(desiredSize.x, desiredSize.y);
- }
-
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
updateSustainedPerformanceMode();
}
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.v(TAG, "surfaceChanged: isCreating:" + holder.isCreating() + " holder: " + holder.toString());
- if (holder.isCreating() && desiredSize.x > 0 && desiredSize.y > 0) {
- // We have called setFixedSize which will trigger another surfaceChanged after the initial
- // one. This one is the original one and we don't care about it.
- Log.w(TAG, "holder.isCreating = true, ignoring. width=" + width + " height=" + height + " desWidth=" + desiredSize.x + " desHeight=" + desiredSize.y);
- return;
- }
- Log.w(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
- // The window size might have changed (immersive mode, native fullscreen on some devices)
- NativeApp.backbufferResize(width, height, format);
- updateDisplayMeasurements();
- mSurface = holder.getSurface();
+ public void notifySurface(Surface surface) {
+ mSurface = surface;
if (!javaGL) {
// If we got a surface, this starts the thread. If not, it doesn't.
if (mSurface == null) {
@@ -670,17 +551,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
updateSustainedPerformanceMode();
}
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- mSurface = null;
- Log.w(TAG, "Surface destroyed.");
- if (!javaGL) {
- joinRenderLoopThread();
- }
- // Autosize the next created surface.
- holder.setSizeFromLayout();
- }
-
// Invariants: After this, mRenderLoopThread will be set, and the thread will be running.
protected synchronized void ensureRenderLoop() {
if (javaGL) {
@@ -728,20 +598,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
return;
}
- decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- // Called when the system UI's visibility changes, regardless of
- // whether it's because of our or system actions.
- // We will try to force it to follow our preference but will not stupidly
- // act as if it's visible if it's not.
- navigationHidden = ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0);
- // TODO: Check here if it's the state we want.
- Log.i(TAG, "SystemUiVisibilityChange! visibility=" + visibility + " navigationHidden: " + navigationHidden);
- Log.i(TAG, "decorView: " + decorView.getWidth() + "x" + decorView.getHeight());
- updateDisplayMeasurements();
- }
- });
+ sizeManager.setupSystemUiCallback(decorView);
navigationCallbackView = decorView;
}
@@ -776,6 +633,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
mSurfaceView.onDestroy();
mSurfaceView = null;
}
+ sizeManager.setSurfaceView(null);
if (mPowerSaveModeReceiver != null) {
mPowerSaveModeReceiver.destroy(this);
mPowerSaveModeReceiver = null;
@@ -864,29 +722,6 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
}
}
- private void checkInsets(WindowInsets insets) {
- if (insets == null) {
- return;
- }
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
- DisplayCutout cutout = insets.getDisplayCutout();
- if (cutout != null) {
- safeInsetLeft = cutout.getSafeInsetLeft();
- safeInsetRight = cutout.getSafeInsetRight();
- safeInsetTop = cutout.getSafeInsetTop();
- safeInsetBottom = cutout.getSafeInsetBottom();
- Log.i(TAG, "Safe insets: left: " + safeInsetLeft + " right: " + safeInsetRight + " top: " + safeInsetTop + " bottom: " + safeInsetBottom);
- } else {
- Log.i(TAG, "Cutout was null");
- safeInsetLeft = 0;
- safeInsetRight = 0;
- safeInsetTop = 0;
- safeInsetBottom = 0;
- }
- NativeApp.sendMessage("safe_insets", safeInsetLeft + ":" + safeInsetRight + ":" + safeInsetTop + ":" + safeInsetBottom);
- }
- }
-
@Override
public void onAttachedToWindow() {
Log.i(TAG, "onAttachedToWindow");
@@ -905,7 +740,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
updateSystemUiVisibility();
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- densityDpi = (float)newConfig.densityDpi;
+ sizeManager.updateDpi((float)newConfig.densityDpi);
}
}
@@ -914,7 +749,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
// onConfigurationChanged not called on multi-window change
Log.i(TAG, "onMultiWindowModeChanged: isInMultiWindowMode = " + isInMultiWindowMode);
super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig);
- updateDisplayMeasurements();
+ sizeManager.checkDisplayMeasurements();
}
// keep this static so we can call this even if we don't
@@ -1307,7 +1142,8 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
sendIntent.setType("text/plain");
sendIntent.putExtra(Intent.EXTRA_TEXT, params);
sendIntent.setAction(Intent.ACTION_SEND);
- startActivity(sendIntent);
+ Intent shareIntent = Intent.createChooser(sendIntent, null);
+ startActivity(shareIntent);
return true;
} catch (Exception e) { // For example, android.content.ActivityNotFoundException
Log.e(TAG, e.toString());
@@ -1419,6 +1255,9 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
recreate();
} else if (command.equals("graphics_restart")) {
Log.i(TAG, "graphics_restart");
+ if (params != null && !params.equals("")) {
+ overrideShortcutParam = params;
+ }
shuttingDown = true;
recreate();
} else if (command.equals("ask_permission") && params.equals("storage")) {
@@ -1455,6 +1294,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C
if (params.equals("ingame")) {
// Keep the screen bright - very annoying if it goes dark when tilting away
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ updateSustainedPerformanceMode();
} else {
// Only keep the screen bright ingame.
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
diff --git a/android/src/org/ppsspp/ppsspp/PpssppActivity.java b/android/src/org/ppsspp/ppsspp/PpssppActivity.java
index f6496168b8..4269f7f98b 100644
--- a/android/src/org/ppsspp/ppsspp/PpssppActivity.java
+++ b/android/src/org/ppsspp/ppsspp/PpssppActivity.java
@@ -12,6 +12,8 @@ public class PpssppActivity extends NativeActivity {
private static final String TAG = "PpssppActivity";
// Key used by shortcut.
public static final String SHORTCUT_EXTRA_KEY = "org.ppsspp.ppsspp.Shortcuts";
+ // Key used for debugging.
+ public static final String ARGS_EXTRA_KEY = "org.ppsspp.ppsspp.Args";
private static boolean m_hasUnsupportedABI = false;
private static boolean m_hasNoNativeBinary = false;
@@ -78,14 +80,18 @@ public class PpssppActivity extends NativeActivity {
if (data != null) {
String path = intent.getData().getPath();
Log.i(TAG, "Found Shortcut Parameter in data: " + path);
- super.setShortcutParam(path);
+ super.setShortcutParam("\"" + path.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
// Toast.makeText(getApplicationContext(), path, Toast.LENGTH_SHORT).show();
} else {
String param = getIntent().getStringExtra(SHORTCUT_EXTRA_KEY);
+ String args = getIntent().getStringExtra(ARGS_EXTRA_KEY);
Log.e(TAG, "Got ACTION_VIEW without a valid uri, trying param");
if (param != null) {
Log.i(TAG, "Found Shortcut Parameter in extra-data: " + param);
- super.setShortcutParam(getIntent().getStringExtra(SHORTCUT_EXTRA_KEY));
+ super.setShortcutParam("\"" + param.replace("\\", "\\\\").replace("\"", "\\\"") + "\"");
+ } else if (args != null) {
+ Log.i(TAG, "Found args parameter in extra-data: " + args);
+ super.setShortcutParam(args);
} else {
Log.e(TAG, "Shortcut missing parameter!");
super.setShortcutParam("");
diff --git a/android/src/org/ppsspp/ppsspp/SizeManager.java b/android/src/org/ppsspp/ppsspp/SizeManager.java
new file mode 100644
index 0000000000..d5977e974a
--- /dev/null
+++ b/android/src/org/ppsspp/ppsspp/SizeManager.java
@@ -0,0 +1,214 @@
+package org.ppsspp.ppsspp;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.pm.ActivityInfo;
+import android.graphics.Point;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.DisplayCutout;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowInsets;
+import java.lang.Runnable;
+
+public class SizeManager implements SurfaceHolder.Callback {
+ private static String TAG = "PPSSPPSizeManager";
+
+ final NativeActivity activity;
+ SurfaceView surfaceView = null;
+
+ private int safeInsetLeft = 0;
+ private int safeInsetRight = 0;
+ private int safeInsetTop = 0;
+ private int safeInsetBottom = 0;
+
+ private float densityDpi;
+ private float refreshRate;
+ private int pixelWidth;
+ private int pixelHeight;
+
+ private boolean navigationHidden = false;
+ private boolean displayUpdatePending = false;
+
+ private Point desiredSize = new Point();
+ private int badOrientationCount = 0;
+
+ public SizeManager(final NativeActivity a) {
+ activity = a;
+ }
+
+ @TargetApi(Build.VERSION_CODES.P)
+ public void setSurfaceView(SurfaceView view) {
+ surfaceView = view;
+ if (surfaceView == null)
+ return;
+
+ surfaceView.getHolder().addCallback(this);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ surfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
+ updateInsets(windowInsets);
+ return windowInsets;
+ }
+ });
+ }
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder) {
+ pixelWidth = holder.getSurfaceFrame().width();
+ pixelHeight = holder.getSurfaceFrame().height();
+
+ // Workaround for terrible bug when locking and unlocking the screen in landscape mode on Nexus 5X.
+ int requestedOr = activity.getRequestedOrientation();
+ boolean requestedPortrait = requestedOr == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || requestedOr == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
+ boolean detectedPortrait = pixelHeight > pixelWidth;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT && badOrientationCount < 3 && requestedPortrait != detectedPortrait && requestedOr != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
+ Log.e(TAG, "Bad orientation detected (w=" + pixelWidth + " h=" + pixelHeight + "! Recreating activity.");
+ badOrientationCount++;
+ activity.recreate();
+ return;
+ } else if (requestedPortrait == detectedPortrait) {
+ Log.i(TAG, "Correct orientation detected, resetting orientation counter.");
+ badOrientationCount = 0;
+ } else {
+ Log.i(TAG, "Bad orientation detected but ignored" + (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT ? " (sdk version)" : ""));
+ }
+
+ Log.d(TAG, "Surface created. pixelWidth=" + pixelWidth + ", pixelHeight=" + pixelHeight + " holder: " + holder.toString() + " or: " + requestedOr);
+ NativeApp.setDisplayParameters(pixelWidth, pixelHeight, (int)densityDpi, refreshRate);
+ getDesiredBackbufferSize(desiredSize);
+
+ // Note that desiredSize might be 0,0 here - but that's fine when calling setFixedSize! It means auto.
+ Log.d(TAG, "Setting fixed size " + desiredSize.x + " x " + desiredSize.y);
+ holder.setFixedSize(desiredSize.x, desiredSize.y);
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+ Log.v(TAG, "surfaceChanged: isCreating:" + holder.isCreating() + " holder: " + holder.toString());
+ if (holder.isCreating() && desiredSize.x > 0 && desiredSize.y > 0) {
+ // We have called setFixedSize which will trigger another surfaceChanged after the initial
+ // one. This one is the original one and we don't care about it.
+ Log.w(TAG, "holder.isCreating = true, ignoring. width=" + width + " height=" + height + " desWidth=" + desiredSize.x + " desHeight=" + desiredSize.y);
+ return;
+ }
+
+ Log.w(TAG, "Surface changed. Resolution: " + width + "x" + height + " Format: " + format);
+ // The window size might have changed (immersive mode, native fullscreen on some devices)
+ NativeApp.backbufferResize(width, height, format);
+ updateDisplayMeasurements();
+
+ activity.notifySurface(holder.getSurface());
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ activity.notifySurface(null);
+
+ // Autosize the next created surface.
+ holder.setSizeFromLayout();
+ }
+
+ public void checkDisplayMeasurements() {
+ if (displayUpdatePending) {
+ return;
+ }
+ displayUpdatePending = true;
+
+ final Runnable updater = new Runnable() {
+ public void run() {
+ Log.d(TAG, "checkDisplayMeasurements: checking now");
+ updateDisplayMeasurements();
+ }
+ };
+
+ final Handler handler = new Handler(Looper.getMainLooper());
+ handler.postDelayed(updater, 10);
+ }
+
+ @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+ public void updateDisplayMeasurements() {
+ displayUpdatePending = false;
+
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ // Early in startup, we don't have a view to query. Do our best to get some kind of size
+ // that can be used by config default heuristics, and so on.
+ DisplayMetrics metrics = new DisplayMetrics();
+ if (navigationHidden && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ display.getRealMetrics(metrics);
+ } else {
+ display.getMetrics(metrics);
+ }
+
+ // Later on, we have the exact pixel size so let's just use it.
+ if (surfaceView != null) {
+ metrics.widthPixels = surfaceView.getWidth();
+ metrics.heightPixels = surfaceView.getHeight();
+ }
+ densityDpi = metrics.densityDpi;
+ refreshRate = display.getRefreshRate();
+
+ NativeApp.setDisplayParameters(metrics.widthPixels, metrics.heightPixels, (int)densityDpi, refreshRate);
+ }
+
+ @TargetApi(Build.VERSION_CODES.KITKAT)
+ public void setupSystemUiCallback(final View view) {
+ view.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int visibility) {
+ // Called when the system UI's visibility changes, regardless of
+ // whether it's because of our or system actions.
+ // We will try to force it to follow our preference but will not stupidly
+ // act as if it's visible if it's not.
+ navigationHidden = ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0);
+ // TODO: Check here if it's the state we want.
+ Log.i(TAG, "SystemUiVisibilityChange! visibility=" + visibility + " navigationHidden: " + navigationHidden);
+ Log.i(TAG, "decorView: " + view.getWidth() + "x" + view.getHeight());
+ checkDisplayMeasurements();
+ }
+ });
+ }
+
+ public void updateDpi(float dpi) {
+ densityDpi = dpi;
+ }
+
+ private void getDesiredBackbufferSize(Point sz) {
+ NativeApp.computeDesiredBackbufferDimensions();
+ sz.x = NativeApp.getDesiredBackbufferWidth();
+ sz.y = NativeApp.getDesiredBackbufferHeight();
+ }
+
+ @TargetApi(Build.VERSION_CODES.P)
+ private void updateInsets(WindowInsets insets) {
+ if (insets == null) {
+ return;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ DisplayCutout cutout = insets.getDisplayCutout();
+ if (cutout != null) {
+ safeInsetLeft = cutout.getSafeInsetLeft();
+ safeInsetRight = cutout.getSafeInsetRight();
+ safeInsetTop = cutout.getSafeInsetTop();
+ safeInsetBottom = cutout.getSafeInsetBottom();
+ Log.i(TAG, "Safe insets: left: " + safeInsetLeft + " right: " + safeInsetRight + " top: " + safeInsetTop + " bottom: " + safeInsetBottom);
+ } else {
+ Log.i(TAG, "Safe insets: Cutout was null");
+ safeInsetLeft = 0;
+ safeInsetRight = 0;
+ safeInsetTop = 0;
+ safeInsetBottom = 0;
+ }
+ NativeApp.sendMessage("safe_insets", safeInsetLeft + ":" + safeInsetRight + ":" + safeInsetTop + ":" + safeInsetBottom);
+ }
+ }
+}
diff --git a/assets/compat.ini b/assets/compat.ini
index 6e3bd07d34..21b9db4bbb 100644
--- a/assets/compat.ini
+++ b/assets/compat.ini
@@ -602,7 +602,8 @@ NPEH00065 = true # Ys Seven
NPJH50350 = true # Ys Seven
ULJM08041 = true # Ys Seven
-[YugiohSaveFix]
+# Note! This whole flag is disabled temporarily by appending "Disabled" to its name). See 7914
+[YugiohSaveFixDisabled]
# 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
@@ -652,6 +653,15 @@ UCJS10019 = true
NPEZ00219 = true
NPUZ00114 = true
+# Innocent Life (see issue #2830)
+UCAS40079 = true
+ULUS10219 = true
+ULES00658 = true
+UCAS40187 = true
+ULJS00119 = true
+ULKS46167 = true
+NPJH50017 = true
+
[ForceMax60FPS]
# The GOW games are very heavy and render as fast as they can. They benefit greatly from
# capping the framerate at 60fps.
@@ -726,6 +736,19 @@ NPHG00025 = true
UCKS45137 = true
UCUS98740 = true
+# Mumbo Jumbo games (see issue #12857)
+ULUS10287 = true # Super Collapse 3
+ULES01027 = true # Super Collapse 3
+ULUS10203 = true # Platypus
+ULES01029 = true # Platypus
+ULUS10201 = true # Luxor: The Wrath of Set
+ULUS10227 = true # 7 Wonders of the Ancient World
+ULES01037 = true # 7 Wonders of the Ancient World
+
+# Super Monkey Ball Adventures also benefits from this (#7674).
+ULES00364 = true
+ULUS10132 = true
+
[JitInvalidationHack]
# This is an absolutely awful hack that somehow prevents issues when clearing the JIT,
# if the game has copied code with EmuHack opcodes or something. Hopefully will be able
diff --git a/build.gradle b/build.gradle
index 40261aa712..8e0dd83012 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.6.2'
+ classpath 'com.android.tools.build:gradle:3.6.3'
}
}
diff --git a/ext/native/gfx_es2/draw_text_android.cpp b/ext/native/gfx_es2/draw_text_android.cpp
index fe9cd14fdd..608d0cfa0d 100644
--- a/ext/native/gfx_es2/draw_text_android.cpp
+++ b/ext/native/gfx_es2/draw_text_android.cpp
@@ -16,13 +16,13 @@
#include
TextDrawerAndroid::TextDrawerAndroid(Draw::DrawContext *draw) : TextDrawer(draw) {
- env_ = getEnv();
+ auto env = getEnv();
const char *textRendererClassName = "org/ppsspp/ppsspp/TextRenderer";
jclass localClass = findClass(textRendererClassName);
- cls_textRenderer = reinterpret_cast(env_->NewGlobalRef(localClass));
+ cls_textRenderer = reinterpret_cast(env->NewGlobalRef(localClass));
if (cls_textRenderer) {
- method_measureText = env_->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;D)I");
- method_renderText = env_->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;D)[I");
+ method_measureText = env->GetStaticMethodID(cls_textRenderer, "measureText", "(Ljava/lang/String;D)I");
+ method_renderText = env->GetStaticMethodID(cls_textRenderer, "renderText", "(Ljava/lang/String;D)[I");
} else {
ELOG("Failed to find class: '%s'", textRendererClassName);
}
@@ -91,9 +91,10 @@ void TextDrawerAndroid::MeasureString(const char *str, size_t len, float *w, flo
ELOG("Missing font");
}
std::string text(NormalizeString(std::string(str, len)));
- jstring jstr = env_->NewStringUTF(text.c_str());
- uint32_t size = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize);
- env_->DeleteLocalRef(jstr);
+ auto env = getEnv();
+ jstring jstr = env->NewStringUTF(text.c_str());
+ uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize);
+ env->DeleteLocalRef(jstr);
entry = new TextMeasureEntry();
entry->width = (size >> 16);
@@ -121,6 +122,7 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou
WrapString(toMeasure, toMeasure.c_str(), rotated ? bounds.h : bounds.w, wrap);
}
+ auto env = getEnv();
std::vector lines;
SplitString(toMeasure, '\n', lines);
float total_w = 0.0f;
@@ -134,9 +136,9 @@ void TextDrawerAndroid::MeasureStringRect(const char *str, size_t len, const Bou
entry = iter->second.get();
} else {
std::string text(NormalizeString(lines[i]));
- jstring jstr = env_->NewStringUTF(text.c_str());
- uint32_t size = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize);
- env_->DeleteLocalRef(jstr);
+ jstring jstr = env->NewStringUTF(text.c_str());
+ uint32_t size = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, scaledSize);
+ env->DeleteLocalRef(jstr);
int sizecx = size >> 16;
int sizecy = size & 0xFFFF;
entry = new TextMeasureEntry();
@@ -169,8 +171,9 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS
ELOG("Missing font");
}
- jstring jstr = env_->NewStringUTF(str);
- uint32_t textSize = env_->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, size);
+ auto env = getEnv();
+ jstring jstr = env->NewStringUTF(str);
+ uint32_t textSize = env->CallStaticIntMethod(cls_textRenderer, method_measureText, jstr, size);
int imageWidth = (short)(textSize >> 16);
int imageHeight = (short)(textSize & 0xFFFF);
if (imageWidth <= 0)
@@ -178,8 +181,8 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS
if (imageHeight <= 0)
imageHeight = 1;
- jintArray imageData = (jintArray)env_->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, size);
- env_->DeleteLocalRef(jstr);
+ jintArray imageData = (jintArray)env->CallStaticObjectMethod(cls_textRenderer, method_renderText, jstr, size);
+ env->DeleteLocalRef(jstr);
entry.texture = nullptr;
entry.bmWidth = imageWidth;
@@ -188,8 +191,8 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS
entry.height = imageHeight;
entry.lastUsedFrame = frameCount_;
- jint *jimage = env_->GetIntArrayElements(imageData, nullptr);
- assert(env_->GetArrayLength(imageData) == imageWidth * imageHeight);
+ jint *jimage = env->GetIntArrayElements(imageData, nullptr);
+ assert(env->GetArrayLength(imageData) == imageWidth * imageHeight);
if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16 || texFormat == Draw::DataFormat::R4G4B4A4_UNORM_PACK16) {
bitmapData.resize(entry.bmWidth * entry.bmHeight * sizeof(uint16_t));
uint16_t *bitmapData16 = (uint16_t *)&bitmapData[0];
@@ -213,8 +216,8 @@ void TextDrawerAndroid::DrawStringBitmap(std::vector &bitmapData, TextS
ELOG("Bad TextDrawer format");
assert(false);
}
- env_->ReleaseIntArrayElements(imageData, jimage, 0);
- env_->DeleteLocalRef(imageData);
+ env->ReleaseIntArrayElements(imageData, jimage, 0);
+ env->DeleteLocalRef(imageData);
}
void TextDrawerAndroid::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) {
diff --git a/ext/native/gfx_es2/draw_text_android.h b/ext/native/gfx_es2/draw_text_android.h
index dff54dade4..51e5a3ab82 100644
--- a/ext/native/gfx_es2/draw_text_android.h
+++ b/ext/native/gfx_es2/draw_text_android.h
@@ -35,7 +35,6 @@ private:
std::string NormalizeString(std::string str);
// JNI functions
- JNIEnv *env_;
jclass cls_textRenderer;
jmethodID method_measureText;
jmethodID method_renderText;
diff --git a/ext/native/gfx_es2/gpu_features.cpp b/ext/native/gfx_es2/gpu_features.cpp
index 757ccb43f3..ca4df8c26a 100644
--- a/ext/native/gfx_es2/gpu_features.cpp
+++ b/ext/native/gfx_es2/gpu_features.cpp
@@ -38,9 +38,9 @@ PFNGLISVERTEXARRAYOESPROC glIsVertexArrayOES;
GLExtensions gl_extensions;
std::string g_all_gl_extensions;
-std::set g_set_gl_extensions;
+static std::set g_set_gl_extensions;
std::string g_all_egl_extensions;
-std::set g_set_egl_extensions;
+static std::set g_set_egl_extensions;
static bool extensionsDone = false;
static bool useCoreContext = false;
@@ -564,6 +564,15 @@ void SetGLCoreContext(bool flag) {
gl_extensions.IsCoreContext = useCoreContext;
}
+void ResetGLExtensions() {
+ extensionsDone = false;
+
+ gl_extensions = {};
+ gl_extensions.IsCoreContext = useCoreContext;
+ g_all_gl_extensions.clear();
+ g_all_egl_extensions.clear();
+}
+
static const char *glsl_fragment_prelude =
"#ifdef GL_ES\n"
"precision mediump float;\n"
diff --git a/ext/native/gfx_es2/gpu_features.h b/ext/native/gfx_es2/gpu_features.h
index 95a57f095b..4617e544a4 100644
--- a/ext/native/gfx_es2/gpu_features.h
+++ b/ext/native/gfx_es2/gpu_features.h
@@ -120,5 +120,6 @@ extern std::string g_all_egl_extensions;
void CheckGLExtensions();
void SetGLCoreContext(bool flag);
+void ResetGLExtensions();
std::string ApplyGLSLPrelude(const std::string &source, uint32_t stage);
diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp
index 77c1c603f5..df2d386255 100644
--- a/ext/native/thin3d/VulkanQueueRunner.cpp
+++ b/ext/native/thin3d/VulkanQueueRunner.cpp
@@ -776,7 +776,10 @@ void VulkanQueueRunner::ApplyRenderPassMerge(std::vector &steps) {
if (steps[j]->dependencies.contains(touchedFramebuffers)) {
goto done_fb;
}
- if (steps[j]->render.framebuffer == fb) {
+ if (steps[j]->render.framebuffer == fb &&
+ steps[j]->render.color != VKRRenderPassAction::CLEAR &&
+ steps[j]->render.depth != VKRRenderPassAction::CLEAR &&
+ steps[j]->render.stencil != VKRRenderPassAction::CLEAR) {
// ok. Now, if it's a render, slurp up all the commands
// and kill the step.
// Also slurp up any pretransitions.
diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp
index 9b164ec2ab..ee06060b98 100644
--- a/ext/native/thin3d/thin3d_gl.cpp
+++ b/ext/native/thin3d/thin3d_gl.cpp
@@ -572,7 +572,11 @@ OpenGLContext::OpenGLContext() {
}
}
- if (caps_.vendor == GPUVendor::VENDOR_VIVANTE || caps_.vendor == GPUVendor::VENDOR_BROADCOM) {
+ // Try to detect old Tegra chips by checking for sub 3.0 GL versions. Like Vivante and Broadcom,
+ // those can't handle NaN values in conditionals.
+ if (caps_.vendor == GPUVendor::VENDOR_VIVANTE ||
+ caps_.vendor == GPUVendor::VENDOR_BROADCOM ||
+ (caps_.vendor == GPUVendor::VENDOR_NVIDIA && !gl_extensions.VersionGEThan(3, 0, 0))) {
bugs_.Infest(Bugs::BROKEN_NAN_IN_CONDITIONAL);
}
diff --git a/ext/native/ui/screen.cpp b/ext/native/ui/screen.cpp
index a5e105aa56..958c1d70c3 100644
--- a/ext/native/ui/screen.cpp
+++ b/ext/native/ui/screen.cpp
@@ -8,7 +8,6 @@
#include "ui/view.h"
ScreenManager::ScreenManager() {
- nextScreen_ = 0;
uiContext_ = 0;
dialogFinished_ = 0;
}
@@ -18,7 +17,7 @@ ScreenManager::~ScreenManager() {
}
void ScreenManager::switchScreen(Screen *screen) {
- if (screen == nextScreen_) {
+ if (!nextStack_.empty() && screen == nextStack_.front().screen) {
ELOG("Already switching to this screen");
return;
}
@@ -26,23 +25,23 @@ void ScreenManager::switchScreen(Screen *screen) {
// will only become apparent if the dialog is closed. The previous screen will stick around
// until that switch.
// TODO: is this still true?
- if (nextScreen_ != 0) {
- ELOG("Already had a nextScreen_! Asynchronous open while doing something? Deleting the new screen.");
+ if (!nextStack_.empty()) {
+ ELOG("Already had a nextStack_! Asynchronous open while doing something? Deleting the new screen.");
delete screen;
return;
}
- if (screen == 0) {
+ if (screen == nullptr) {
WLOG("Swiching to a zero screen, this can't be good");
}
if (stack_.empty() || screen != stack_.back().screen) {
- nextScreen_ = screen;
- nextScreen_->setScreenManager(this);
+ screen->setScreenManager(this);
+ nextStack_.push_back({ screen, 0 });
}
}
void ScreenManager::update() {
std::lock_guard guard(inputLock_);
- if (nextScreen_) {
+ if (!nextStack_.empty()) {
switchToNext();
}
@@ -53,22 +52,25 @@ void ScreenManager::update() {
void ScreenManager::switchToNext() {
std::lock_guard guard(inputLock_);
- if (!nextScreen_) {
- ELOG("switchToNext: No nextScreen_!");
+ if (nextStack_.empty()) {
+ ELOG("switchToNext: No nextStack_!");
}
- Layer temp = {0, 0};
+ Layer temp = {nullptr, 0};
if (!stack_.empty()) {
temp = stack_.back();
stack_.pop_back();
}
- Layer newLayer = {nextScreen_, 0};
- stack_.push_back(newLayer);
+ stack_.push_back(nextStack_.front());
if (temp.screen) {
delete temp.screen;
}
- nextScreen_ = 0;
- UI::SetFocusedView(0);
+ UI::SetFocusedView(nullptr);
+
+ for (size_t i = 1; i < nextStack_.size(); ++i) {
+ stack_.push_back(nextStack_[i]);
+ }
+ nextStack_.clear();
}
bool ScreenManager::touch(const TouchInput &touch) {
@@ -197,19 +199,16 @@ Screen *ScreenManager::topScreen() const {
void ScreenManager::shutdown() {
std::lock_guard guard(inputLock_);
- for (auto x = stack_.begin(); x != stack_.end(); x++)
- delete x->screen;
+ for (auto layer : stack_)
+ delete layer.screen;
stack_.clear();
- delete nextScreen_;
- nextScreen_ = nullptr;
+ for (auto layer : nextStack_)
+ delete layer.screen;
+ nextStack_.clear();
}
void ScreenManager::push(Screen *screen, int layerFlags) {
std::lock_guard guard(inputLock_);
- if (nextScreen_ && stack_.empty()) {
- // we're during init, this is OK
- switchToNext();
- }
screen->setScreenManager(this);
if (screen->isTransparent()) {
layerFlags |= LAYER_TRANSPARENT;
@@ -224,7 +223,10 @@ void ScreenManager::push(Screen *screen, int layerFlags) {
touch(input);
Layer layer = {screen, layerFlags};
- stack_.push_back(layer);
+ if (nextStack_.empty())
+ stack_.push_back(layer);
+ else
+ nextStack_.push_back(layer);
}
void ScreenManager::pop() {
diff --git a/ext/native/ui/screen.h b/ext/native/ui/screen.h
index abca7f9769..0b97108afd 100644
--- a/ext/native/ui/screen.h
+++ b/ext/native/ui/screen.h
@@ -147,7 +147,6 @@ private:
void switchToNext();
void processFinishDialog();
- Screen *nextScreen_;
UIContext *uiContext_;
Draw::DrawContext *thin3DContext_;
@@ -166,4 +165,5 @@ private:
// Dialog stack. These are shown "on top" of base screens and the Android back button works as expected.
// Used for options, in-game menus and other things you expect to be able to back out from onto something.
std::vector stack_;
+ std::vector nextStack_;
};
diff --git a/headless/Headless.vcxproj b/headless/Headless.vcxproj
index 94c6d72c8a..7ad31e3578 100644
--- a/headless/Headless.vcxproj
+++ b/headless/Headless.vcxproj
@@ -176,7 +176,7 @@
NotUsing
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS
- ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
EnableFastChecks
StreamingSIMDExtensions2
Precise
@@ -190,11 +190,12 @@
Console
true
- Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;xinput.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
0x00400000
false
true
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/x86/lib
../Windows/git-version-gen.cmd
@@ -208,7 +209,7 @@
NotUsing
Level3
_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
+ ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
NotSet
Precise
false
@@ -222,11 +223,12 @@
Console
true
- Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;d3dx9d.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
0x00400000
false
true
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/x86_64/lib
../Windows/git-version-gen.cmd
@@ -240,7 +242,7 @@
NotUsing
Level3
_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
+ ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
NotSet
Precise
false
@@ -254,8 +256,9 @@
Console
true
- Winmm.lib;Ws2_32.lib;dsound.lib;..\ffmpeg\Windows\aarch64\lib\avcodec.lib;..\ffmpeg\Windows\aarch64\lib\avformat.lib;..\ffmpeg\Windows\aarch64\lib\avutil.lib;..\ffmpeg\Windows\aarch64\lib\swresample.lib;..\ffmpeg\Windows\aarch64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/aarch64/lib
../Windows/git-version-gen.cmd
@@ -269,7 +272,7 @@
NotUsing
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
NotSet
Precise
false
@@ -284,8 +287,9 @@
Console
true
- shell32.lib;advapi32.lib;gdi32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;shell32.lib;advapi32.lib;gdi32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/arm/lib
../Windows/git-version-gen.cmd
@@ -301,7 +305,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/x86/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
false
StreamingSIMDExtensions2
Precise
@@ -316,11 +320,12 @@
true
true
true
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
0x00400000
false
true
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/x86/lib
../Windows/git-version-gen.cmd
@@ -336,7 +341,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/x86_64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
false
NotSet
Precise
@@ -353,11 +358,12 @@
true
true
true
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;d3dx9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
0x00400000
false
true
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/x86_64/lib
../Windows/git-version-gen.cmd
@@ -373,7 +379,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/aarch64/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
false
NotSet
Precise
@@ -390,8 +396,9 @@
true
true
true
- Winmm.lib;Ws2_32.lib;dsound.lib;..\ffmpeg\Windows\aarch64\lib\avcodec.lib;..\ffmpeg\Windows\aarch64\lib\avformat.lib;..\ffmpeg\Windows\aarch64\lib\avutil.lib;..\ffmpeg\Windows\aarch64\lib\swresample.lib;..\ffmpeg\Windows\aarch64\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/aarch64/lib
../Windows/git-version-gen.cmd
@@ -407,7 +414,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_CONSOLE;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
+ ../ffmpeg/Windows/arm/include;../dx9sdk/Include/DX11;../Common;..;../Core;../ext/glew;../ext/native
false
NotSet
Precise
@@ -424,8 +431,9 @@
true
true
true
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;shell32.lib;advapi32.lib;gdi32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;shell32.lib;advapi32.lib;gdi32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/arm/lib
../Windows/git-version-gen.cmd
diff --git a/ios/AppDelegate.mm b/ios/AppDelegate.mm
index 289db7f942..ab79d0be07 100644
--- a/ios/AppDelegate.mm
+++ b/ios/AppDelegate.mm
@@ -72,6 +72,22 @@
}
-(BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+ int argc = 1;
+ char *argv[3] = { 0 };
+ NSURL* nsUrl = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey];
+
+ if (nsUrl != nullptr && nsUrl.isFileURL) {
+ NSString *nsString = nsUrl.path;
+ const char *string = nsString.UTF8String;
+ argv[argc++] = (char*)string;
+ }
+
+ NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+ NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"];
+ NativeInit(argc, (const char**)argv, documentsPath.UTF8String, bundlePath.UTF8String, NULL);
+
+
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.viewController = [[ViewController alloc] init];
diff --git a/ios/PPSSPP-Info.plist b/ios/PPSSPP-Info.plist
index 74234337c8..55d219357c 100644
--- a/ios/PPSSPP-Info.plist
+++ b/ios/PPSSPP-Info.plist
@@ -68,5 +68,139 @@
UILaunchStoryboardName
Launch Screen
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeIconFiles
+
+ CFBundleTypeName
+ ISO File
+ LSHandlerRank
+ Owner
+ LSItemContentTypes
+
+ ppsspp.iso
+
+
+
+ CFBundleTypeIconFiles
+
+ CFBundleTypeName
+ CSO File
+ LSHandlerRank
+ Owner
+ LSItemContentTypes
+
+ ppsspp.cso
+
+
+
+ CFBundleTypeIconFiles
+
+ CFBundleTypeName
+ ELF File
+ LSHandlerRank
+ Owner
+ LSItemContentTypes
+
+ ppsspp.elf
+
+
+
+ CFBundleTypeIconFiles
+
+ CFBundleTypeName
+ PBP File
+ LSHandlerRank
+ Owner
+ LSItemContentTypes
+
+ ppsspp.pbp
+
+
+
+ UTExportedTypeDeclarations
+
+
+ UTTypeConformsTo
+
+ public.data
+ public.iso-image
+
+ UTTypeDescription
+ ISO File
+ UTTypeIconFiles
+
+ UTTypeIdentifier
+ ppsspp.iso
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ iso
+
+
+
+
+ UTTypeConformsTo
+
+ public.data
+ dyn.ah62d4rv4ge80g65t
+
+ UTTypeDescription
+ CSO File
+ UTTypeIconFiles
+
+ UTTypeIdentifier
+ ppsspp.cso
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ cso
+
+
+
+
+ UTTypeConformsTo
+
+ public.data
+ dyn.ah62d4rv4ge80n5dg
+
+ UTTypeDescription
+ ELF File
+ UTTypeIconFiles
+
+ UTTypeIdentifier
+ ppsspp.elf
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ elf
+
+
+
+
+ UTTypeConformsTo
+
+ public.data
+ dyn.ah62d4rv4ge81a2xu
+
+ UTTypeDescription
+ PBP File
+ UTTypeIconFiles
+
+ UTTypeIdentifier
+ ppsspp.pbp
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ pbp
+
+
+
+
diff --git a/ios/ViewController.h b/ios/ViewController.h
index 340ea79a79..d64d973c77 100644
--- a/ios/ViewController.h
+++ b/ios/ViewController.h
@@ -12,6 +12,7 @@
@interface ViewController : GLKViewController
+- (void)shareText:(NSString *)text;
- (void)shutdown;
@end
diff --git a/ios/ViewController.mm b/ios/ViewController.mm
index 81c1960aee..73fd05c7fd 100644
--- a/ios/ViewController.mm
+++ b/ios/ViewController.mm
@@ -148,6 +148,14 @@ static LocationHelper *locationHelper;
- (void)subtleVolume:(SubtleVolume *)volumeView didChange:(CGFloat)value {
}
+- (void)shareText:(NSString *)text {
+ NSArray *items = @[text];
+ UIActivityViewController * viewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:nil];
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self presentViewController:viewController animated:YES completion:nil];
+ });
+}
+
- (void)viewSafeAreaInsetsDidChange {
if (@available(iOS 11.0, *)) {
[super viewSafeAreaInsetsDidChange];
diff --git a/ios/macbundle.sh b/ios/macbundle.sh
new file mode 100644
index 0000000000..eed70114e9
--- /dev/null
+++ b/ios/macbundle.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+PPSSPP="${1}"
+PPSSPPiOS="${PPSSPP}/PPSSPP"
+
+if [ ! -f "${PPSSPPiOS}" ]; then
+ echo "No such file: ${PPSSPPiOS}!"
+ exit 0
+fi
+
+GIT_VERSION_LINE=$(grep "PPSSPP_GIT_VERSION = " "$(dirname "${0}")/../git-version.cpp")
+SHORT_VERSION_MATCH='.*"v([0-9\.]+(-[0-9]+)?).*";'
+LONG_VERSION_MATCH='.*"v(.*)";'
+if [[ "${GIT_VERSION_LINE}" =~ ^${SHORT_VERSION_MATCH}$ ]]; then
+ plutil -replace CFBundleShortVersionString -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${SHORT_VERSION_MATCH}/\$1/g") ${PPSSPP}/Info.plist
+ plutil -replace CFBundleVersion -string $(echo ${GIT_VERSION_LINE} | perl -pe "s/${LONG_VERSION_MATCH}/\$1/g") ${PPSSPP}/Info.plist
+else
+ plutil -replace CFBundleShortVersionString -string "" ${PPSSPP}/Info.plist
+ plutil -replace CFBundleVersion -string "" ${PPSSPP}/Info.plist
+fi
diff --git a/ios/main.mm b/ios/main.mm
index 7d755013bd..4c9f004c5f 100644
--- a/ios/main.mm
+++ b/ios/main.mm
@@ -114,6 +114,9 @@ void System_SendMessage(const char *command, const char *parameter) {
// [sharedViewController shutdown];
// exit(0);
// });
+ } else if (!strcmp(command, "sharetext")) {
+ NSString *text = [NSString stringWithUTF8String:parameter];
+ [sharedViewController shareText:text];
} else if (!strcmp(command, "camera_command")) {
if (!strncmp(parameter, "startVideo", 10)) {
int width = 0, height = 0;
@@ -215,11 +218,6 @@ int main(int argc, char *argv[])
PROFILE_INIT();
@autoreleasepool {
- NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
- NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingString:@"/assets/"];
-
- NativeInit(argc, (const char**)argv, documentsPath.UTF8String, bundlePath.UTF8String, NULL);
-
return UIApplicationMain(argc, argv, NSStringFromClass([PPSSPPUIApplication class]), NSStringFromClass([AppDelegate class]));
}
}
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index d909df3ada..b1fd51bdb6 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -389,6 +389,7 @@ SOURCES_CXX += $(NATIVEDIR)/math/dataconv.cpp \
$(COREDIR)/HLE/sceKernel.cpp \
$(COREDIR)/HLE/sceKernelAlarm.cpp \
$(COREDIR)/HLE/sceKernelEventFlag.cpp \
+ $(COREDIR)/HLE/sceKernelHeap.cpp \
$(COREDIR)/HLE/sceKernelInterrupt.cpp \
$(COREDIR)/HLE/sceKernelMbx.cpp \
$(COREDIR)/HLE/sceKernelMemory.cpp \
diff --git a/unittest/UnitTests.vcxproj b/unittest/UnitTests.vcxproj
index 5e3c5629a5..86caf65925 100644
--- a/unittest/UnitTests.vcxproj
+++ b/unittest/UnitTests.vcxproj
@@ -169,7 +169,7 @@
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
true
false
false
@@ -180,9 +180,9 @@
Console
true
- Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\x86\lib
+ ../ffmpeg/Windows/x86/lib
@@ -191,7 +191,7 @@
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
true
false
false
@@ -203,9 +203,9 @@
Console
true
- Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\x86_64\lib
+ ../ffmpeg/Windows/x86_64/lib
@@ -214,7 +214,7 @@
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
true
false
false
@@ -226,9 +226,9 @@
Console
true
- Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\aarch64\lib
+ ../ffmpeg/Windows/aarch64/lib
@@ -237,7 +237,7 @@
Level3
_CRTDBG_MAP_ALLOC;USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
true
false
false
@@ -250,9 +250,9 @@
Console
true
- Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\arm\lib
+ ../ffmpeg/Windows/arm/lib
@@ -264,7 +264,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
false
Size
true
@@ -277,9 +277,9 @@
true
true
true
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\x86\lib
+ ../ffmpeg/Windows/x86/lib
@@ -291,7 +291,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/x86_64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
false
true
false
@@ -306,9 +306,9 @@
true
true
true
- mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;opengl32.lib;dsound.lib;glu32.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;opengl32.lib;glu32.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\x86_64\lib
+ ../ffmpeg/Windows/x86_64/lib
@@ -320,36 +320,7 @@
true
true
USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_64=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
- false
- true
- false
- MultiThreaded
- true
- Size
- false
- ProgramDatabase
-
-
- Console
- true
- true
- true
- Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
- /ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\aarch64\lib
-
-
-
-
- Level3
-
-
- MaxSpeed
- true
- true
- USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
- ..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ ../ffmpeg/Windows/aarch64/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
false
true
false
@@ -366,7 +337,36 @@
true
mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
/ignore:4049 /ignore:4217 %(AdditionalOptions)
- ..\ffmpeg\Windows\arm\lib
+ ../ffmpeg/Windows/aarch64/lib
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ USING_WIN_UI;GLEW_STATIC;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_ARCH_32=1;_WINDOWS;_UNICODE;UNICODE;%(PreprocessorDefinitions)
+ ../ffmpeg/Windows/arm/include;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib
+ false
+ true
+ false
+ MultiThreaded
+ true
+ Size
+ false
+ ProgramDatabase
+
+
+ Console
+ true
+ true
+ true
+ mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Ws2_32.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;dsound.lib;avcodec.lib;avformat.lib;avutil.lib;swresample.lib;swscale.lib;comctl32.lib;d3d9.lib;dxguid.lib;%(AdditionalDependencies)
+ /ignore:4049 /ignore:4217 %(AdditionalOptions)
+ ../ffmpeg/Windows/arm/lib