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