From 00684a4bb92d0b674bffea46d49100de3021084d Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sat, 18 Apr 2020 02:46:11 +0300 Subject: [PATCH 01/59] Improve code readability --- Qt/mainwindow.cpp | 85 +++++++++-------------------------------------- Qt/mainwindow.h | 2 ++ 2 files changed, 18 insertions(+), 69 deletions(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index 5d0d6beed8..e40a912e24 100644 --- a/Qt/mainwindow.cpp +++ b/Qt/mainwindow.cpp @@ -78,21 +78,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 +105,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(); } diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 49112cd10d..2c5fa4836c 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) { From bbc6337263b6c2b09a88f72c14192d37be3e5b4e Mon Sep 17 00:00:00 2001 From: TotalCaesar659 <14265316+TotalCaesar659@users.noreply.github.com> Date: Sat, 18 Apr 2020 21:08:20 +0300 Subject: [PATCH 02/59] Add "Switch UMD" menu point to Linux version --- Qt/mainwindow.cpp | 16 +++++++++++++++- Qt/mainwindow.h | 1 + Windows/MainWindowMenu.cpp | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Qt/mainwindow.cpp b/Qt/mainwindow.cpp index e40a912e24..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" @@ -141,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)); } @@ -249,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; @@ -534,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 2c5fa4836c..150fc53471 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -95,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/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 3b5e7e6c35..6fdaeb742b 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -438,7 +438,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); } From 4c5ed9f6aa757b7d76ad6881313f024b5d06985a Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 18 Apr 2020 22:32:48 -0700 Subject: [PATCH 03/59] Windows: Send resize when adjusting render mode. If we flip this because of frameskip, we need to actually process. --- Windows/MainWindowMenu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Windows/MainWindowMenu.cpp b/Windows/MainWindowMenu.cpp index 3b5e7e6c35..42050c0b6d 100644 --- a/Windows/MainWindowMenu.cpp +++ b/Windows/MainWindowMenu.cpp @@ -749,8 +749,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; From 4ea5d165f5c98d99040ea5dd7c42ae16d2d5311e Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 18 Apr 2020 22:34:33 -0700 Subject: [PATCH 04/59] D3D11: Always use accurate depth. The Direct3D APIs use a "min" and "max" value, and it's required that min must be less than or equal to max. If this requirement is not met, the viewport parameters are not updated. We forced accurate depth on for NVIDIA and AMD, but this just meant Intel was still broken and less people were reporting bugs about it. Although the PSP GE has depth viewport transform, this is not used for clipping and is not actually the depth range. The minz and maxz GE registers are the depth range, and minz must be less than or equal to maxz for drawing to occur. --- GPU/D3D11/GPU_D3D11.cpp | 10 ++++------ GPU/Directx9/GPU_DX9.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 11 deletions(-) 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/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. From 7c92b1abdaefa3d210c7a6bc808b275d51d4def7 Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Sun, 19 Apr 2020 09:14:02 +0300 Subject: [PATCH 05/59] update VS projects --- Windows/PPSSPP.vcxproj | 44 +++++++++-------- headless/Headless.vcxproj | 40 +++++++++------- unittest/UnitTests.vcxproj | 98 +++++++++++++++++++------------------- 3 files changed, 97 insertions(+), 85 deletions(-) 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/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/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 From e62c669f1062340a921a14ed8d1763a03b9fa6df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 19 Apr 2020 18:43:20 +0200 Subject: [PATCH 06/59] GLES: Disable range culling on old Tegras, they seem to misbehave (see issue #12838). This is a blind fix - couldn't find my old Shield Portable :( --- ext/native/thin3d/thin3d_gl.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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); } From 91bb48dcd7bce196f803be7f168590b7aaccc19b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 19 Apr 2020 20:51:47 +0200 Subject: [PATCH 07/59] Update gradle again --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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' } } From 418e881f14d23c786683302229349df907864d8f Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 19 Apr 2020 15:40:48 -0700 Subject: [PATCH 08/59] Android: Don't cache env in text drawer. For PPGe, the thread is changing on lost, so we can't use the cached env. --- ext/native/gfx_es2/draw_text_android.cpp | 39 +++++++++++++----------- ext/native/gfx_es2/draw_text_android.h | 1 - 2 files changed, 21 insertions(+), 19 deletions(-) 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; From 0e921ae7a64faef7f37c0ad8be3fd54cb82d24cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 21 Apr 2020 00:20:58 +0200 Subject: [PATCH 09/59] "Unify" the credits screen. Fixes #12844. --- UI/MiscScreens.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index 76f7a0aca5..ffe61126a0 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -531,14 +531,12 @@ void CreditsScreen::CreateViews() { rightYOffset = 74; } root_->Add(new Button(cr->T("PPSSPP Forums"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 158, false)))->OnClick.Handle(this, &CreditsScreen::OnForums); -#if (PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(LINUX)) && !PPSSPP_PLATFORM(ANDROID) root_->Add(new Button(cr->T("Discord"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 232, false)))->OnClick.Handle(this, &CreditsScreen::OnDiscord); -#endif root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg); root_->Add(new Button(cr->T("Privacy Policy"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnPrivacy); -#ifdef __ANDROID__ - root_->Add(new Button(cr->T("Share PPSSPP"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 84, false)))->OnClick.Handle(this, &CreditsScreen::OnShare); - root_->Add(new Button(cr->T("Twitter @PPSSPP_emu"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 158, false)))->OnClick.Handle(this, &CreditsScreen::OnTwitter); + root_->Add(new Button(cr->T("Twitter @PPSSPP_emu"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 84, false)))->OnClick.Handle(this, &CreditsScreen::OnTwitter); +#if PPSSPP_PLATFORM(ANDROID) + root_->Add(new Button(cr->T("Share PPSSPP"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 158, false)))->OnClick.Handle(this, &CreditsScreen::OnShare); #endif if (System_GetPropertyBool(SYSPROP_APP_GOLD)) { root_->Add(new ImageView(ImageID("I_ICONGOLD"), IS_DEFAULT, new AnchorLayoutParams(100, 64, 10, 10, NONE, NONE, false))); From 07b3b5071f89f76d68371d1fa40f4fe601ad9948 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 22 Apr 2020 21:18:39 -0700 Subject: [PATCH 10/59] http: Fix thread join on enable/disable. --- Core/WebServer.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) 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; } From e4abfd54089fbd1866944db683dcdce2db8f2806 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 22 Apr 2020 21:19:34 -0700 Subject: [PATCH 11/59] PPGe: Remove half-pixel offset. This made the background misaligned, causing a black border on the right and bottom edges. --- Core/Util/PPGeDraw.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/Util/PPGeDraw.cpp b/Core/Util/PPGeDraw.cpp index 895a1b7425..43381a4b3b 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(); From 4cb30a4bce94e326ebb3a103bfa30e493fa5f0b5 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 24 Apr 2020 09:26:35 -0700 Subject: [PATCH 12/59] Travis: Handle new package versions better. We don't necessarily need the latest packages, but brew really wants to update them. --- .travis.sh | 58 +++++++++++++++++++++++++++++++++++++++++++---------- .travis.yml | 7 ++----- 2 files changed, 49 insertions(+), 16 deletions(-) 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" From 1ccde0427ec37b4ed388024a7a210d14943ecd95 Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Sat, 25 Apr 2020 10:07:35 +0300 Subject: [PATCH 13/59] iOS Share PPSSPP --- UI/MiscScreens.cpp | 2 +- ios/ViewController.h | 1 + ios/ViewController.mm | 8 ++++++++ ios/main.mm | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index ffe61126a0..f170edaf67 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -535,7 +535,7 @@ void CreditsScreen::CreateViews() { root_->Add(new Button("www.ppsspp.org", new AnchorLayoutParams(260, 64, 10, NONE, NONE, 10, false)))->OnClick.Handle(this, &CreditsScreen::OnPPSSPPOrg); root_->Add(new Button(cr->T("Privacy Policy"), new AnchorLayoutParams(260, 64, 10, NONE, NONE, 84, false)))->OnClick.Handle(this, &CreditsScreen::OnPrivacy); root_->Add(new Button(cr->T("Twitter @PPSSPP_emu"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 84, false)))->OnClick.Handle(this, &CreditsScreen::OnTwitter); -#if PPSSPP_PLATFORM(ANDROID) +#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) root_->Add(new Button(cr->T("Share PPSSPP"), new AnchorLayoutParams(260, 64, NONE, NONE, 10, rightYOffset + 158, false)))->OnClick.Handle(this, &CreditsScreen::OnShare); #endif if (System_GetPropertyBool(SYSPROP_APP_GOLD)) { 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/main.mm b/ios/main.mm index 7d755013bd..b01e784113 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; From 4640d3981c61d032f81f57235f331eb2289b33ce Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Sat, 25 Apr 2020 00:37:15 +0300 Subject: [PATCH 14/59] Update dialog on Android 10 --- .gitignore | 1 + UI/MiscScreens.cpp | 2 +- android/src/org/ppsspp/ppsspp/NativeActivity.java | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index c60be9a5f9..b9d8b302da 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ *.exp *.qdact controls.ini +desktop.ini Debug Release Windows/.vs diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index ffe61126a0..c35cee1795 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -585,7 +585,7 @@ UI::EventReturn CreditsScreen::OnDiscord(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/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 09205d17fe..2a2b986702 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1307,7 +1307,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()); From 043ef8c9d45ab90cc6d6011ab77cd31c9d34aacb Mon Sep 17 00:00:00 2001 From: sum2012 Date: Sun, 13 Sep 2015 22:31:56 +0800 Subject: [PATCH 15/59] Wrap some SysMemForKernel's nids #7960 --- Core/HLE/FunctionWrappers.h | 5 +++++ Core/HLE/sceKernel.cpp | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+) 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/sceKernel.cpp b/Core/HLE/sceKernel.cpp index ad571355ef..f2efb41ad0 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -904,6 +904,28 @@ void Register_LoadExecForKernel() RegisterModule("LoadExecForKernel", ARRAY_SIZE(LoadExecForKernel), LoadExecForKernel); } +static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + +static int sceKernelAllocHeapMemory(int heapId, int size) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + +static int sceKernelDeleteHeap(int heapId) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + +const HLEFunction SysMemForKernel[] = +{ + {0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, + {0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "ii" }, + {0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, +}; + const HLEFunction ExceptionManagerForKernel[] = { {0X3FB264FC, nullptr, "sceKernelRegisterExceptionHandler", '?', "" }, From 8d8ba3e9637d65eda2c53267faadc60a17aedd8a Mon Sep 17 00:00:00 2001 From: sum2012 Date: Mon, 14 Sep 2015 06:05:12 +0800 Subject: [PATCH 16/59] oop --- Core/HLE/sceKernel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index f2efb41ad0..c5c9f23b80 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -922,7 +922,7 @@ static int sceKernelDeleteHeap(int heapId) const HLEFunction SysMemForKernel[] = { {0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, - {0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "ii" }, + {0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, {0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, }; From a8c2c02b828923ef320592e67ff79043f7eb77ef Mon Sep 17 00:00:00 2001 From: sum2012 Date: Tue, 15 Sep 2015 22:09:08 +0800 Subject: [PATCH 17/59] Move SysMemForKernel to sceKernelMemory As SysMemForUser in there --- Core/HLE/sceKernel.cpp | 5 +++++ Core/HLE/sceKernelMemory.cpp | 30 ++++++++++++++++++++++++++++++ Core/HLE/sceKernelMemory.h | 2 ++ 3 files changed, 37 insertions(+) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index c5c9f23b80..824c951492 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -976,3 +976,8 @@ void Register_ThreadManForKernel() { RegisterModule("ThreadManForKernel", ARRAY_SIZE(ThreadManForKernel), ThreadManForKernel); } + +void Register_LoadExecForKernel() +{ + RegisterModule("LoadExecForKernel", ARRAY_SIZE(LoadExecForKernel), LoadExecForKernel); +} diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 46e5375397..bacbd2220c 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2300,3 +2300,33 @@ void Register_SysMemForKernel() { void Register_SysMemUserForUser() { RegisterModule("SysMemUserForUser", ARRAY_SIZE(SysMemUserForUser), SysMemUserForUser); } + + +static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + + +static int sceKernelAllocHeapMemory(int heapId, int size) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + +static int sceKernelDeleteHeap(int heapId) +{ + return hleLogError(SCEKERNEL, 0, ""); +} + +const HLEFunction SysMemForKernel[] = +{ + { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, + { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, + { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, +}; + +void Register_SysMemForKernel() +{ + RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel); +} + diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h index 2396792436..96de13e23e 100644 --- a/Core/HLE/sceKernelMemory.h +++ b/Core/HLE/sceKernelMemory.h @@ -68,3 +68,5 @@ int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr); void Register_SysMemForKernel(); void Register_SysMemUserForUser(); +void Register_SysMemForKernel(); + From fed2b42c5fabbd3638bd029284ce0d55e99062cd Mon Sep 17 00:00:00 2001 From: sum2012 Date: Thu, 17 Sep 2015 06:35:52 +0800 Subject: [PATCH 18/59] Try to Implement SysMemForKernel --- Core/HLE/sceKernelMemory.cpp | 68 ++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index bacbd2220c..d5c2fa1240 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2302,19 +2302,83 @@ void Register_SysMemUserForUser() { } +struct HeapInformation : public KernelObject { + //HeapInformation() :alloc(0) {} + HeapInformation() {} + int uid; + int partitionId; + u32 size; + int flags; + u32 address; + std::string name; + BlockAllocator alloc; + static int GetStaticIDType() { return SCE_KERNEL_TMID_Fpl; }// wrong + int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; }// wrong +}; + +std::map heapList; + +static HeapInformation *getHeap(u32 heapId) { + auto found = heapList.find(heapId); + if (found == heapList.end()) { + return NULL; + } + return found->second; +} + +const u32 HEAP_BLOCK_HEADER_SIZE = 8; +const bool frombottom = false; + static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) { - return hleLogError(SCEKERNEL, 0, ""); + HeapInformation *heap = new HeapInformation; + heap->partitionId = partitionId; + heap->flags = flags; + heap->name = *Name; + int allocSize = (size + 3) & ~3; + heap->size = allocSize; + u32 addr = userMemory.Alloc(heap->size, frombottom, "SysMemForKernel-Heap"); + if (addr == (u32)-1) { + ERROR_LOG(HLE, "sceKernelCreateHeap(): Failed to allocate %i bytes memory", size); + heap->uid = -1; + delete heap; + } + heap->address = addr; + heap->alloc.Init(heap->address + 128, heap->size - 128); + SceUID uid = kernelObjects.Create(heap); + heap->uid = uid; + heapList[uid] = heap; + + + return hleLogError(SCEKERNEL, uid, ""); } static int sceKernelAllocHeapMemory(int heapId, int size) { - return hleLogError(SCEKERNEL, 0, ""); + HeapInformation *heap = getHeap(heapId); + if (!heap) { + ERROR_LOG(HLE, "sceKernelAllocHeapMemory cannot find heapId", heapId); + return 0; + } + + // 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 hleLogError(SCEKERNEL, addr, ""); } static int sceKernelDeleteHeap(int heapId) { + HeapInformation *heap = getHeap(heapId); + if (!heap) { + ERROR_LOG(HLE, "sceKernelDeleteHeap(%i): invalid heapId", heapId); + return -1; + } + userMemory.Free(heap->address); + kernelObjects.Destroy(heap->uid); + heapList.erase(heapId); + delete heap; return hleLogError(SCEKERNEL, 0, ""); } From 6c4043b9de1a72ca6b62f640e017f1c818fe1bcd Mon Sep 17 00:00:00 2001 From: sum2012 Date: Thu, 17 Sep 2015 06:37:01 +0800 Subject: [PATCH 19/59] remove comment --- Core/HLE/sceKernelMemory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index d5c2fa1240..50c881ffb7 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2303,7 +2303,6 @@ void Register_SysMemUserForUser() { struct HeapInformation : public KernelObject { - //HeapInformation() :alloc(0) {} HeapInformation() {} int uid; int partitionId; From 52138f8ce83c6428430e032d84dff75a3b7b53cb Mon Sep 17 00:00:00 2001 From: sum2012 Date: Thu, 17 Sep 2015 21:33:36 +0800 Subject: [PATCH 20/59] Attempt to build fix non-windows --- Core/HLE/sceKernelMemory.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 50c881ffb7..f08b2cf25a 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2315,11 +2315,11 @@ struct HeapInformation : public KernelObject { int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; }// wrong }; -std::map heapList; +std::map heapInformationList; static HeapInformation *getHeap(u32 heapId) { - auto found = heapList.find(heapId); - if (found == heapList.end()) { + auto found = heapInformationList.find(heapId); + if (found == heapInformationList.end()) { return NULL; } return found->second; @@ -2346,7 +2346,7 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char heap->alloc.Init(heap->address + 128, heap->size - 128); SceUID uid = kernelObjects.Create(heap); heap->uid = uid; - heapList[uid] = heap; + heapInformationList[uid] = heap; return hleLogError(SCEKERNEL, uid, ""); @@ -2376,7 +2376,7 @@ static int sceKernelDeleteHeap(int heapId) } userMemory.Free(heap->address); kernelObjects.Destroy(heap->uid); - heapList.erase(heapId); + heapInformationList.erase(heapId); delete heap; return hleLogError(SCEKERNEL, 0, ""); } From e1ce6c061eeb2092e66a5c2f090cb960ce2977d1 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Fri, 18 Sep 2015 19:17:27 +0800 Subject: [PATCH 21/59] Fix crash in sceKernelDeleteHeap --- Core/HLE/sceKernelMemory.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index f08b2cf25a..44c193851c 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2377,7 +2377,6 @@ static int sceKernelDeleteHeap(int heapId) userMemory.Free(heap->address); kernelObjects.Destroy(heap->uid); heapInformationList.erase(heapId); - delete heap; return hleLogError(SCEKERNEL, 0, ""); } From b12fbb9d3e1b7d25ed9ea5286bc19b34c0941196 Mon Sep 17 00:00:00 2001 From: sum2012 Date: Fri, 18 Sep 2015 19:45:23 +0800 Subject: [PATCH 22/59] Attempt to make save status --- Core/HLE/sceKernelMemory.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 44c193851c..4af7629cd6 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2313,10 +2313,30 @@ struct HeapInformation : public KernelObject { BlockAllocator alloc; static int GetStaticIDType() { return SCE_KERNEL_TMID_Fpl; }// wrong int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; }// wrong + + void DoState(PointerWrap &p) { + p.Do(uid); + p.Do(partitionId); + p.Do(size); + p.Do(flags); + p.Do(address); + p.Do(name); + p.Do(alloc); + } }; std::map heapInformationList; +void __HeapInformationDoState(PointerWrap &p) { + auto s = p.Section("kernelHeap", 1); + if (!s) + return; + + if (s >= 1) { + p.Do(heapInformationList); + } +} + static HeapInformation *getHeap(u32 heapId) { auto found = heapInformationList.find(heapId); if (found == heapInformationList.end()) { From 3604a92beee1a3f0e3dad6bca8217f855ca79cdd Mon Sep 17 00:00:00 2001 From: sum2012 Date: Fri, 18 Sep 2015 19:50:20 +0800 Subject: [PATCH 23/59] Change to info log As this commit is work (tested on Tales of Phantasia with Chinese patch) --- Core/HLE/sceKernelMemory.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 4af7629cd6..436e31c16a 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2369,7 +2369,7 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char heapInformationList[uid] = heap; - return hleLogError(SCEKERNEL, uid, ""); + return hleLogSuccessInfoX(SCEKERNEL, uid, ""); } @@ -2384,7 +2384,7 @@ static int sceKernelAllocHeapMemory(int heapId, int size) // 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 hleLogError(SCEKERNEL, addr, ""); + return hleLogSuccessInfoX(SCEKERNEL, addr, ""); } static int sceKernelDeleteHeap(int heapId) @@ -2397,7 +2397,7 @@ static int sceKernelDeleteHeap(int heapId) userMemory.Free(heap->address); kernelObjects.Destroy(heap->uid); heapInformationList.erase(heapId); - return hleLogError(SCEKERNEL, 0, ""); + return hleLogSuccessInfoX(SCEKERNEL, 0, ""); } const HLEFunction SysMemForKernel[] = From bf73d3d6639d36fd44c8e03ea3056b74c3faf45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Aug 2019 17:13:47 +0200 Subject: [PATCH 24/59] Address Unknown's feedback https://github.com/hrydgard/ppsspp/pull/7965/files --- CMakeLists.txt | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 8 +- Core/HLE/sceKernel.cpp | 27 ------ Core/HLE/sceKernel.h | 1 + Core/HLE/sceKernelHeap.cpp | 115 ++++++++++++++++++++++++++ Core/HLE/sceKernelHeap.h | 5 ++ Core/HLE/sceKernelMemory.cpp | 122 ---------------------------- Core/HLE/sceKernelMemory.h | 2 - Core/HLE/sceKernelThread.h | 4 + UWP/CoreUWP/CoreUWP.vcxproj | 2 + UWP/CoreUWP/CoreUWP.vcxproj.filters | 8 +- android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 14 files changed, 147 insertions(+), 153 deletions(-) create mode 100644 Core/HLE/sceKernelHeap.cpp create mode 100644 Core/HLE/sceKernelHeap.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b5d256c210..50cd7b5356 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 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/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 824c951492..ad571355ef 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -904,28 +904,6 @@ void Register_LoadExecForKernel() RegisterModule("LoadExecForKernel", ARRAY_SIZE(LoadExecForKernel), LoadExecForKernel); } -static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) -{ - return hleLogError(SCEKERNEL, 0, ""); -} - -static int sceKernelAllocHeapMemory(int heapId, int size) -{ - return hleLogError(SCEKERNEL, 0, ""); -} - -static int sceKernelDeleteHeap(int heapId) -{ - return hleLogError(SCEKERNEL, 0, ""); -} - -const HLEFunction SysMemForKernel[] = -{ - {0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, - {0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, - {0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, -}; - const HLEFunction ExceptionManagerForKernel[] = { {0X3FB264FC, nullptr, "sceKernelRegisterExceptionHandler", '?', "" }, @@ -976,8 +954,3 @@ void Register_ThreadManForKernel() { RegisterModule("ThreadManForKernel", ARRAY_SIZE(ThreadManForKernel), ThreadManForKernel); } - -void Register_LoadExecForKernel() -{ - RegisterModule("LoadExecForKernel", ARRAY_SIZE(LoadExecForKernel), LoadExecForKernel); -} 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..fa146a93ee --- /dev/null +++ b/Core/HLE/sceKernelHeap.cpp @@ -0,0 +1,115 @@ +#pragma once + +#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" + +struct HeapInformation : 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) { + p.Do(uid); + p.Do(partitionId); + p.Do(size); + p.Do(flags); + p.Do(address); + p.Do(name); + p.Do(alloc); + } +}; + +std::map heapInformationList; + +void __HeapInformationDoState(PointerWrap &p) { + auto s = p.Section("kernelHeap", 1); + if (!s) + return; + + if (s >= 1) { + p.Do(heapInformationList); + } +} + +static HeapInformation *getHeap(u32 heapId) { + auto found = heapInformationList.find(heapId); + if (found == heapInformationList.end()) { + return NULL; + } + return found->second; +} + +const u32 HEAP_BLOCK_HEADER_SIZE = 8; +const bool frombottom = false; + +static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) { + HeapInformation *heap = new HeapInformation; + heap->partitionId = partitionId; + heap->flags = flags; + heap->name = *Name; + int allocSize = (size + 3) & ~3; + heap->size = allocSize; + u32 addr = userMemory.Alloc(heap->size, frombottom, "SysMemForKernel-Heap"); + if (addr == (u32)-1) { + ERROR_LOG(HLE, "sceKernelCreateHeap(): Failed to allocate %i bytes memory", size); + heap->uid = -1; + delete heap; + } + heap->address = addr; + heap->alloc.Init(heap->address + 128, heap->size - 128); + SceUID uid = kernelObjects.Create(heap); + heap->uid = uid; + heapInformationList[uid] = heap; + return hleLogSuccessInfoX(SCEKERNEL, uid, ""); +} + +static int sceKernelAllocHeapMemory(int heapId, int size) { + HeapInformation *heap = getHeap(heapId); + if (!heap) { + ERROR_LOG(HLE, "sceKernelAllocHeapMemory cannot find heapId", heapId); + return 0; + } + + // 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, ""); +} + +static int sceKernelDeleteHeap(int heapId) { + HeapInformation *heap = getHeap(heapId); + if (!heap) { + ERROR_LOG(HLE, "sceKernelDeleteHeap(%i): invalid heapId", heapId); + return -1; + } + userMemory.Free(heap->address); + kernelObjects.Destroy(heap->uid); + heapInformationList.erase(heapId); + return hleLogSuccessInfoX(SCEKERNEL, 0, ""); +} + +const HLEFunction SysMemForKernel[] = +{ + { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, + { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, + { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, +}; + +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..a880601a44 --- /dev/null +++ b/Core/HLE/sceKernelHeap.h @@ -0,0 +1,5 @@ +#pragma once + +int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name); +int sceKernelAllocHeapMemory(int heapId, int size); +int sceKernelDeleteHeap(int heapId); diff --git a/Core/HLE/sceKernelMemory.cpp b/Core/HLE/sceKernelMemory.cpp index 436e31c16a..40cccaa03d 100644 --- a/Core/HLE/sceKernelMemory.cpp +++ b/Core/HLE/sceKernelMemory.cpp @@ -2287,128 +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); } - - -struct HeapInformation : public KernelObject { - HeapInformation() {} - int uid; - int partitionId; - u32 size; - int flags; - u32 address; - std::string name; - BlockAllocator alloc; - static int GetStaticIDType() { return SCE_KERNEL_TMID_Fpl; }// wrong - int GetIDType() const override { return SCE_KERNEL_TMID_Fpl; }// wrong - - void DoState(PointerWrap &p) { - p.Do(uid); - p.Do(partitionId); - p.Do(size); - p.Do(flags); - p.Do(address); - p.Do(name); - p.Do(alloc); - } -}; - -std::map heapInformationList; - -void __HeapInformationDoState(PointerWrap &p) { - auto s = p.Section("kernelHeap", 1); - if (!s) - return; - - if (s >= 1) { - p.Do(heapInformationList); - } -} - -static HeapInformation *getHeap(u32 heapId) { - auto found = heapInformationList.find(heapId); - if (found == heapInformationList.end()) { - return NULL; - } - return found->second; -} - -const u32 HEAP_BLOCK_HEADER_SIZE = 8; -const bool frombottom = false; - -static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) -{ - HeapInformation *heap = new HeapInformation; - heap->partitionId = partitionId; - heap->flags = flags; - heap->name = *Name; - int allocSize = (size + 3) & ~3; - heap->size = allocSize; - u32 addr = userMemory.Alloc(heap->size, frombottom, "SysMemForKernel-Heap"); - if (addr == (u32)-1) { - ERROR_LOG(HLE, "sceKernelCreateHeap(): Failed to allocate %i bytes memory", size); - heap->uid = -1; - delete heap; - } - heap->address = addr; - heap->alloc.Init(heap->address + 128, heap->size - 128); - SceUID uid = kernelObjects.Create(heap); - heap->uid = uid; - heapInformationList[uid] = heap; - - - return hleLogSuccessInfoX(SCEKERNEL, uid, ""); -} - - -static int sceKernelAllocHeapMemory(int heapId, int size) -{ - HeapInformation *heap = getHeap(heapId); - if (!heap) { - ERROR_LOG(HLE, "sceKernelAllocHeapMemory cannot find heapId", heapId); - return 0; - } - - // 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, ""); -} - -static int sceKernelDeleteHeap(int heapId) -{ - HeapInformation *heap = getHeap(heapId); - if (!heap) { - ERROR_LOG(HLE, "sceKernelDeleteHeap(%i): invalid heapId", heapId); - return -1; - } - userMemory.Free(heap->address); - kernelObjects.Destroy(heap->uid); - heapInformationList.erase(heapId); - return hleLogSuccessInfoX(SCEKERNEL, 0, ""); -} - -const HLEFunction SysMemForKernel[] = -{ - { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, - { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, - { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, -}; - -void Register_SysMemForKernel() -{ - RegisterModule("SysMemForKernel", ARRAY_SIZE(SysMemForKernel), SysMemForKernel); -} - diff --git a/Core/HLE/sceKernelMemory.h b/Core/HLE/sceKernelMemory.h index 96de13e23e..2396792436 100644 --- a/Core/HLE/sceKernelMemory.h +++ b/Core/HLE/sceKernelMemory.h @@ -68,5 +68,3 @@ int sceKernelReferTlsplStatus(SceUID uid, u32 infoPtr); void Register_SysMemForKernel(); void Register_SysMemUserForUser(); -void Register_SysMemForKernel(); - diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 73ba3474ba..14cc1fde78 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -330,3 +330,7 @@ KernelObject *__KernelThreadEventHandlerObject(); SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg); int sceKernelReleaseThreadEventHandler(SceUID uid); int sceKernelReferThreadEventHandlerStatus(SceUID uid, u32 infoPtr); + +int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name); +int sceKernelAllocHeapMemory(int heapId, int size); +int sceKernelDeleteHeap(int heapId); 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/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/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 \ From e0614b7ce28c604c57d39a5374ddb264b3631d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Aug 2019 17:23:41 +0200 Subject: [PATCH 25/59] Use PPSSPP's kernel interface to retrieve Heap objects Allows us to get rid of DoState and the map<>. --- Core/HLE/sceKernel.cpp | 1 + Core/HLE/sceKernelHeap.cpp | 71 ++++++++++++++------------------------ Core/HLE/sceKernelHeap.h | 2 ++ 3 files changed, 29 insertions(+), 45 deletions(-) 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/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index fa146a93ee..8baa81a0ab 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -10,7 +10,10 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/Util/BlockAllocator.h" -struct HeapInformation : public KernelObject { +const u32 HEAP_BLOCK_HEADER_SIZE = 8; +const bool frombottom = false; + +struct Heap : public KernelObject { int uid = 0; int partitionId = 0; u32 size = 0; @@ -34,31 +37,9 @@ struct HeapInformation : public KernelObject { } }; -std::map heapInformationList; - -void __HeapInformationDoState(PointerWrap &p) { - auto s = p.Section("kernelHeap", 1); - if (!s) - return; - - if (s >= 1) { - p.Do(heapInformationList); - } -} - -static HeapInformation *getHeap(u32 heapId) { - auto found = heapInformationList.find(heapId); - if (found == heapInformationList.end()) { - return NULL; - } - return found->second; -} - -const u32 HEAP_BLOCK_HEADER_SIZE = 8; -const bool frombottom = false; - static int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name) { - HeapInformation *heap = new HeapInformation; + Heap *heap = new Heap(); + SceUID uid = kernelObjects.Create(heap); heap->partitionId = partitionId; heap->flags = flags; heap->name = *Name; @@ -72,42 +53,42 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char } heap->address = addr; heap->alloc.Init(heap->address + 128, heap->size - 128); - SceUID uid = kernelObjects.Create(heap); heap->uid = uid; - heapInformationList[uid] = heap; return hleLogSuccessInfoX(SCEKERNEL, uid, ""); } static int sceKernelAllocHeapMemory(int heapId, int size) { - HeapInformation *heap = getHeap(heapId); - if (!heap) { + 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 { ERROR_LOG(HLE, "sceKernelAllocHeapMemory cannot find heapId", heapId); - return 0; + return error; } - - // 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, ""); } static int sceKernelDeleteHeap(int heapId) { - HeapInformation *heap = getHeap(heapId); - if (!heap) { + u32 error; + Heap *heap = kernelObjects.Get(heapId, error); + if (heap) { + userMemory.Free(heap->address); + kernelObjects.Destroy(heap->uid); + return hleLogSuccessInfoX(SCEKERNEL, 0, ""); + } else { ERROR_LOG(HLE, "sceKernelDeleteHeap(%i): invalid heapId", heapId); - return -1; + return error; } - userMemory.Free(heap->address); - kernelObjects.Destroy(heap->uid); - heapInformationList.erase(heapId); - return hleLogSuccessInfoX(SCEKERNEL, 0, ""); } const HLEFunction SysMemForKernel[] = { - { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, - { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, - { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, + { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, + { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, + { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, }; void Register_SysMemForKernel() { diff --git a/Core/HLE/sceKernelHeap.h b/Core/HLE/sceKernelHeap.h index a880601a44..7b43021ac6 100644 --- a/Core/HLE/sceKernelHeap.h +++ b/Core/HLE/sceKernelHeap.h @@ -1,5 +1,7 @@ #pragma once +#include "Common/ChunkFile.h" + int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name); int sceKernelAllocHeapMemory(int heapId, int size); int sceKernelDeleteHeap(int heapId); From e3aa2f5e4c84669b9c1ff409f5b733d141e489f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 8 Aug 2019 19:00:27 +0200 Subject: [PATCH 26/59] Assorted fixes (build and crash) --- Core/HLE/HLETables.cpp | 1 + Core/HLE/sceKernelHeap.cpp | 25 +++++++++++++------------ Core/HLE/sceKernelHeap.h | 6 +----- Core/HLE/sceKernelMemory.h | 1 - 4 files changed, 15 insertions(+), 18 deletions(-) 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/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 8baa81a0ab..5aec59e873 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -1,5 +1,3 @@ -#pragma once - #include #include "Common/ChunkFile.h" @@ -26,7 +24,7 @@ struct Heap : public KernelObject { static int GetStaticIDType() { return PPSSPP_KERNEL_TMID_Heap; } int GetIDType() const override { return PPSSPP_KERNEL_TMID_Heap; } - void DoState(PointerWrap &p) { + void DoState(PointerWrap &p) override { p.Do(uid); p.Do(partitionId); p.Do(size); @@ -38,19 +36,22 @@ struct Heap : public KernelObject { }; 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, 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; - int allocSize = (size + 3) & ~3; heap->size = allocSize; - u32 addr = userMemory.Alloc(heap->size, frombottom, "SysMemForKernel-Heap"); - if (addr == (u32)-1) { - ERROR_LOG(HLE, "sceKernelCreateHeap(): Failed to allocate %i bytes memory", size); - heap->uid = -1; - delete heap; - } heap->address = addr; heap->alloc.Init(heap->address + 128, heap->size - 128); heap->uid = uid; @@ -66,7 +67,7 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { u32 addr = heap->alloc.Alloc(memSize, true); return hleLogSuccessInfoX(SCEKERNEL, addr, ""); } else { - ERROR_LOG(HLE, "sceKernelAllocHeapMemory cannot find heapId", heapId); + ERROR_LOG(HLE, "sceKernelAllocHeapMemory(%d): cannot find heapId", heapId); return error; } } @@ -79,7 +80,7 @@ static int sceKernelDeleteHeap(int heapId) { kernelObjects.Destroy(heap->uid); return hleLogSuccessInfoX(SCEKERNEL, 0, ""); } else { - ERROR_LOG(HLE, "sceKernelDeleteHeap(%i): invalid heapId", heapId); + ERROR_LOG(HLE, "sceKernelDeleteHeap(%d): invalid heapId", heapId); return error; } } diff --git a/Core/HLE/sceKernelHeap.h b/Core/HLE/sceKernelHeap.h index 7b43021ac6..1279c74962 100644 --- a/Core/HLE/sceKernelHeap.h +++ b/Core/HLE/sceKernelHeap.h @@ -1,7 +1,3 @@ #pragma once -#include "Common/ChunkFile.h" - -int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name); -int sceKernelAllocHeapMemory(int heapId, int size); -int sceKernelDeleteHeap(int heapId); +void Register_SysMemForKernel(); 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(); From 34ae4cc5a9b20c5426ad6eec596dd1b4997215a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Apr 2020 11:34:17 +0200 Subject: [PATCH 27/59] Address additional feedback from Unknown, finally --- Core/HLE/sceKernelHeap.cpp | 29 +++++++++++++---------------- Core/HLE/sceKernelThread.h | 4 ---- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/Core/HLE/sceKernelHeap.cpp b/Core/HLE/sceKernelHeap.cpp index 5aec59e873..7b99eca184 100644 --- a/Core/HLE/sceKernelHeap.cpp +++ b/Core/HLE/sceKernelHeap.cpp @@ -8,8 +8,8 @@ #include "Core/HLE/sceKernelMemory.h" #include "Core/Util/BlockAllocator.h" -const u32 HEAP_BLOCK_HEADER_SIZE = 8; -const bool frombottom = false; +static const u32 HEAP_BLOCK_HEADER_SIZE = 8; +static const bool g_fromBottom = false; struct Heap : public KernelObject { int uid = 0; @@ -39,7 +39,7 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char u32 allocSize = (size + 3) & ~3; // TODO: partitionId should probably decide if we allocate from userMemory or kernel or whatever... - u32 addr = userMemory.Alloc(allocSize, frombottom, "SysMemForKernel-Heap"); + 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 @@ -50,12 +50,12 @@ static int sceKernelCreateHeap(int partitionId, int size, int flags, const char heap->partitionId = partitionId; heap->flags = flags; - heap->name = *Name; + 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, ""); + return hleLogSuccessInfoX(SCEKERNEL, uid); } static int sceKernelAllocHeapMemory(int heapId, int size) { @@ -65,10 +65,9 @@ static int sceKernelAllocHeapMemory(int heapId, int size) { // 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, ""); + return hleLogSuccessInfoX(SCEKERNEL, addr); } else { - ERROR_LOG(HLE, "sceKernelAllocHeapMemory(%d): cannot find heapId", heapId); - return error; + return hleLogError(SCEKERNEL, error, "sceKernelAllocHeapMemory(%d): invalid heapId", heapId); } } @@ -78,18 +77,16 @@ static int sceKernelDeleteHeap(int heapId) { if (heap) { userMemory.Free(heap->address); kernelObjects.Destroy(heap->uid); - return hleLogSuccessInfoX(SCEKERNEL, 0, ""); + return hleLogSuccessInfoX(SCEKERNEL, 0); } else { - ERROR_LOG(HLE, "sceKernelDeleteHeap(%d): invalid heapId", heapId); - return error; + return hleLogError(SCEKERNEL, error, "sceKernelDeleteHeap(%d): invalid heapId", heapId); } } -const HLEFunction SysMemForKernel[] = -{ - { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'I', "ii" }, - { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'I', "i" }, - { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'I', "iiis" }, +const HLEFunction SysMemForKernel[] = { + { 0X636C953B, &WrapI_II, "sceKernelAllocHeapMemory", 'x', "ii" }, + { 0XC9805775, &WrapI_I, "sceKernelDeleteHeap", 'i', "i" }, + { 0X1C1FBFE7, &WrapI_IIIC, "sceKernelCreateHeap", 'i', "iixs" }, }; void Register_SysMemForKernel() { diff --git a/Core/HLE/sceKernelThread.h b/Core/HLE/sceKernelThread.h index 14cc1fde78..73ba3474ba 100644 --- a/Core/HLE/sceKernelThread.h +++ b/Core/HLE/sceKernelThread.h @@ -330,7 +330,3 @@ KernelObject *__KernelThreadEventHandlerObject(); SceUID sceKernelRegisterThreadEventHandler(const char *name, SceUID threadID, u32 mask, u32 handlerPtr, u32 commonArg); int sceKernelReleaseThreadEventHandler(SceUID uid); int sceKernelReferThreadEventHandlerStatus(SceUID uid, u32 infoPtr); - -int sceKernelCreateHeap(int partitionId, int size, int flags, const char *Name); -int sceKernelAllocHeapMemory(int heapId, int size); -int sceKernelDeleteHeap(int heapId); From 5508bfb596226f439218160024abb74ee4ac6520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 26 Apr 2020 12:44:11 +0200 Subject: [PATCH 28/59] Vulkan: Discard negative width/height framebuffer blits. Will likely help #12531. --- GPU/Vulkan/FramebufferVulkan.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 532c00dfb8..9989b7056c 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -493,8 +493,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; From 9c98bbabf2132256279610722a956e53f617b798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 27 Apr 2020 09:43:14 +0200 Subject: [PATCH 29/59] Enable ForceMax60FPS for games published by MumboJumbo. See issue #12857 --- assets/compat.ini | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/assets/compat.ini b/assets/compat.ini index 8cac87f90e..c4072f180e 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -610,6 +610,13 @@ 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 + [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 From 1b8e3d97382bde76ca5f722c973d48203027bf1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 27 Apr 2020 10:22:54 +0200 Subject: [PATCH 30/59] And another mumbo jumbo game (#12857) --- assets/compat.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/assets/compat.ini b/assets/compat.ini index c4072f180e..71d993b64f 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -610,12 +610,14 @@ NPHG00025 = true UCKS45137 = true UCUS98740 = true -# mumbo jumbo games (see issue #12857) +# 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 [JitInvalidationHack] # This is an absolutely awful hack that somehow prevents issues when clearing the JIT, From 34d629ff794811fbe611cff2c87e7e2961b09dfc Mon Sep 17 00:00:00 2001 From: Christian Weiske Date: Mon, 27 Apr 2020 22:48:27 +0200 Subject: [PATCH 31/59] Make PPSSPP visible in OUYA launcher Reference: https://github.com/ouya/docs/blob/master/setup.md --- android/AndroidManifest.xml | 1 + android/res/drawable-xhdpi/ouya_icon.png | Bin 0 -> 27261 bytes 2 files changed, 1 insertion(+) create mode 100644 android/res/drawable-xhdpi/ouya_icon.png 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/res/drawable-xhdpi/ouya_icon.png b/android/res/drawable-xhdpi/ouya_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4c294e4ea0eb98a808eafd25b15ddc9f10b6d28e GIT binary patch literal 27261 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 +>dcQ3a?@>k$95jB>{3`2db~>xnczvEmov@ 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 Date: Tue, 28 Apr 2020 10:06:08 +0200 Subject: [PATCH 32/59] compat.ini: Set ForceMax60FPS for Super Monkey Ball Adventures. See #7674. --- assets/compat.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/compat.ini b/assets/compat.ini index 71d993b64f..6aff20ee88 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -619,6 +619,10 @@ 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 From 4bebdb30c6347f9c9b23e3b4c574920db9ca9ff3 Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Tue, 28 Apr 2020 00:19:20 +0300 Subject: [PATCH 33/59] iOS : File association --- ios/AppDelegate.mm | 16 +++++ ios/PPSSPP-Info.plist | 134 ++++++++++++++++++++++++++++++++++++++++++ ios/main.mm | 5 -- 3 files changed, 150 insertions(+), 5 deletions(-) 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/main.mm b/ios/main.mm index b01e784113..4c9f004c5f 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -218,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])); } } From bc948b9b943df847557e740e98ea74044b993702 Mon Sep 17 00:00:00 2001 From: Florin9doi Date: Thu, 30 Apr 2020 20:06:03 +0300 Subject: [PATCH 34/59] iOS/macOS : set bundle version --- CMakeLists.txt | 1 + Qt/macbundle.sh | 11 +++++++++++ SDL/macbundle.sh | 11 +++++++++++ ios/macbundle.sh | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+) create mode 100644 ios/macbundle.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index 50cd7b5356..7e695825b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2065,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/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/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/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 From 31b1993a696fa03961c5a9c0ee872c3499f207fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 3 May 2020 15:27:53 +0200 Subject: [PATCH 35/59] compat.ini: Turn on ForceUMDDelay for Innocent Life. See issue #2830. --- assets/compat.ini | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/assets/compat.ini b/assets/compat.ini index 6aff20ee88..7c7ae1df97 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -536,6 +536,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. From f9f568d2664cdd136ace7355583c87e67a45035f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 6 May 2020 22:21:22 +0200 Subject: [PATCH 36/59] Vulkan: Framebuffer manager: Use an allocator for "MakePixelTexture" images. Fixes #12355 (or at a minimum, will improve it). --- Common/Vulkan/VulkanImage.h | 2 +- GPU/Vulkan/FramebufferVulkan.cpp | 24 +++++++++++++++++++++--- GPU/Vulkan/FramebufferVulkan.h | 1 + 3 files changed, 23 insertions(+), 4 deletions(-) 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/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 9989b7056c..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; @@ -551,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 { From 48980d8786e2db3f74b65f8cc709fade31e98450 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 7 May 2020 23:00:54 -0700 Subject: [PATCH 37/59] GLES: Simplify the framebuf offset detection. It's clearly not been understood well as changes were made, so let's dump a bunch of comments on it. --- GPU/Common/SoftwareTransformCommon.cpp | 63 +++++++++++++++----------- GPU/Common/SoftwareTransformCommon.h | 1 + GPU/Common/TextureCacheCommon.cpp | 14 ++++-- GPU/Common/TextureCacheCommon.h | 4 +- GPU/GLES/DrawEngineGLES.cpp | 4 ++ 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index c16e734313..de62a5f933 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" @@ -156,6 +157,7 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { } // NOTE: The viewport must be up to date! +// Also, this assumes SetTexture() has already figured out the actual texture height. 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) { @@ -471,43 +473,50 @@ void SoftwareTransform( } } - // This means we're using a framebuffer (and one that isn't big enough.) + // 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; + + // Apaprently, 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? + 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 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 (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've already baked in the old gstate_c.curTextureYOffset, so correct. - const float yDiff = (float) (prevH + prevYOffset - gstate_c.curTextureYOffset) / (float) h; + // We need to subtract this offset from the Vs to address the new framebuf. + // Note: SetOffsetTexture() will account for any overshoot in yOffset. + const float yDiff = (float)yOffset / (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].v = (transformed[index].v / oldHeightFactor - yDiff) * heightFactor; } + + result->textureChanged = true; } } } diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index a7efc396c9..bdc63deda2 100644 --- a/GPU/Common/SoftwareTransformCommon.h +++ b/GPU/Common/SoftwareTransformCommon.h @@ -35,6 +35,7 @@ struct SoftwareTransformResult { float depth; bool setStencil; + bool textureChanged; u8 stencilValue; }; diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 50964d88e5..ed3f904a67 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -29,8 +29,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 @@ -750,11 +751,14 @@ void TextureCacheCommon::DetachFramebuffer(TexCacheEntry *entry, u32 address, Vi } } -bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset) { +bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 yOffset) { static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32; AttachedFramebufferInfo fbInfo = { 0 }; + const u32 bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2; + const u32 texaddrOffset = yOffset * framebuffer->fb_stride * bpp; + const u32 mirrorMask = 0x00600000; u32 addr = address & 0x3FFFFFFF; u32 texaddr = entry->addr + texaddrOffset; @@ -908,12 +912,12 @@ 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)) { + if (!Memory::IsValidAddress(texaddr)) { return false; } @@ -928,7 +932,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, yOffset)) { success = true; } } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index b349a475a2..8af38798ff 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(); @@ -248,7 +248,7 @@ protected: void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); // Used by D3D11 and Vulkan. void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); - bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); + bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 yOffset = 0); void AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); void AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer); diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 70abe87bef..417153fae3 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -574,6 +574,10 @@ rotateVBO: dec_->VertexType(), inds, GE_VTYPE_IDX_16BIT, dec_->GetDecVtxFmt(), maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); + // We have an offset texture to apply. + if (result.textureChanged) + textureCache_->ApplyTexture(); + ApplyDrawStateLate(result.setStencil, result.stencilValue); LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, lastVType_, framebufferManager_->UseBufferedRendering()); From 4d11256807895c6153ddfccbf3bb8df34272f196 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 7 May 2020 23:13:18 -0700 Subject: [PATCH 38/59] GPU: Avoid a texture offset change in sw transform. If we do it this late, it changes the shader, but that is tricky to handle for all the backends. --- GPU/Common/SoftwareTransformCommon.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index de62a5f933..6cb750583e 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -501,6 +501,8 @@ void SoftwareTransform( if (tlOutside || (brOutside && tlAlmostOutside)) { // This is how far the nearest coord is, so that's where we'll look for the next framebuf. + const u32 prevXOffset = gstate_c.curTextureXOffset; + const u32 prevYOffset = gstate_c.curTextureYOffset; const u32 yOffset = (int)(gstate_c.curTextureHeight * std::min(transformed[0].v, transformed[1].v)); if (texCache->SetOffsetTexture(yOffset)) { const float oldWidthFactor = widthFactor; @@ -509,13 +511,19 @@ void SoftwareTransform( heightFactor = (float)h / (float)gstate_c.curTextureHeight; // We need to subtract this offset from the Vs to address the new framebuf. - // Note: SetOffsetTexture() will account for any overshoot in yOffset. - const float yDiff = (float)yOffset / (float)h; + 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; + for (int index = 0; index < maxIndex; ++index) { - transformed[index].u *= widthFactor / oldWidthFactor; + 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; result->textureChanged = true; } } From 16e47f63336ba0b7466d80f02ca060e74723be86 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 7 May 2020 23:22:51 -0700 Subject: [PATCH 39/59] GPU: Calc framebuf offset with right params. It has nothing to do with the target or source framebuf, oops. --- GPU/Common/TextureCacheCommon.cpp | 16 +++++++++------- GPU/Common/TextureCacheCommon.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index ed3f904a67..a75072b3a1 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -751,14 +751,11 @@ void TextureCacheCommon::DetachFramebuffer(TexCacheEntry *entry, u32 address, Vi } } -bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 yOffset) { +bool TextureCacheCommon::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset) { static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32; AttachedFramebufferInfo fbInfo = { 0 }; - const u32 bpp = framebuffer->format == GE_FORMAT_8888 ? 4 : 2; - const u32 texaddrOffset = yOffset * framebuffer->fb_stride * bpp; - const u32 mirrorMask = 0x00600000; u32 addr = address & 0x3FFFFFFF; u32 texaddr = entry->addr + texaddrOffset; @@ -916,13 +913,18 @@ bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) { if (!framebufferManager_->UseBufferedRendering()) { return false; } + u32 texaddr = gstate.getTextureAddress(0); - if (!Memory::IsValidAddress(texaddr)) { + 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; @@ -932,7 +934,7 @@ bool TextureCacheCommon::SetOffsetTexture(u32 yOffset) { 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, yOffset)) { + if (AttachFramebuffer(entry, framebuffer->fb_address, framebuffer, texaddrOffset)) { success = true; } } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 8af38798ff..13bfa647e6 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -248,7 +248,7 @@ protected: void UpdateSamplingParams(TexCacheEntry &entry, SamplerCacheKey &key); // Used by D3D11 and Vulkan. void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); - bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 yOffset = 0); + bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); void AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); void AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer); From b413a589452795ba0f9bcd919c26fa0a22f34061 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 7 May 2020 23:30:17 -0700 Subject: [PATCH 40/59] GLES: Add safety handling for offset depal. Just in case... --- GPU/GLES/DrawEngineGLES.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index 417153fae3..afada31f5e 100644 --- a/GPU/GLES/DrawEngineGLES.cpp +++ b/GPU/GLES/DrawEngineGLES.cpp @@ -575,8 +575,11 @@ rotateVBO: maxIndex, drawBuffer, numTrans, drawIndexed, ¶ms, &result); // We have an offset texture to apply. - if (result.textureChanged) + if (result.textureChanged) { textureCache_->ApplyTexture(); + // Apply again in case of depal. + ApplyDrawState(prim); + } ApplyDrawStateLate(result.setStencil, result.stencilValue); From b3b86bc2c2bef58b17364ee14987477ecc05f637 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 8 May 2020 00:55:21 -0700 Subject: [PATCH 41/59] Windows: Add safety checks to WASAPI code. Seems to be crashing for some users. --- Windows/WASAPIStream.cpp | 74 +++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 19 deletions(-) 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() { From ef43ec5f33ece266aeb29b036bbdb54a99917e3d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 8 May 2020 00:26:41 -0700 Subject: [PATCH 42/59] GPU: Split up software transform into phases. --- GPU/Common/SoftwareTransformCommon.cpp | 60 +++++++++++++++----------- GPU/Common/SoftwareTransformCommon.h | 20 +++++++-- GPU/D3D11/DrawEngineD3D11.cpp | 23 +++++----- GPU/Directx9/DrawEngineDX9.cpp | 19 ++++---- GPU/GLES/DrawEngineGLES.cpp | 33 ++++++-------- GPU/Vulkan/DrawEngineVulkan.cpp | 25 ++++++----- 6 files changed, 98 insertions(+), 82 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 6cb750583e..12b0e1bde2 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -156,16 +156,9 @@ static int ColorIndexOffset(int prim, GEShadeMode shadeMode, bool clearMode) { return 0; } -// NOTE: The viewport must be up to date! -// Also, this assumes SetTexture() has already figured out the actual texture height. -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(); @@ -196,7 +189,7 @@ void SoftwareTransform( } int provokeIndOffset = 0; - if (params->provokeFlatFirst) { + if (params_.provokeFlatFirst) { provokeIndOffset = ColorIndexOffset(prim, gstate.getShadeMode(), gstate.isModeClear()); } @@ -452,7 +445,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); @@ -461,7 +454,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; @@ -472,6 +465,16 @@ void SoftwareTransform( return; } } +} + +// 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. @@ -489,7 +492,7 @@ void SoftwareTransform( // This is the max V that would've been inside the original texture size. const float maxValidV = heightFactor; - // Apaprently, Assassin's Creed: Bloodlines accesses just outside. + // Apparently, Assassin's Creed: Bloodlines accesses just outside. const float invTexH = 1.0f / gstate_c.curTextureHeight; // size of one texel. // Are either TL or BR inside the texture but outside the framebuffer? @@ -497,20 +500,22 @@ void SoftwareTransform( 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)) { - // This is how far the nearest coord is, so that's where we'll look for the next framebuf. const u32 prevXOffset = gstate_c.curTextureXOffset; const u32 prevYOffset = gstate_c.curTextureYOffset; + + // 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 (texCache->SetOffsetTexture(yOffset)) { + 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; - // We need to subtract this offset from the Vs to address the new framebuf. + // 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; @@ -524,16 +529,22 @@ void SoftwareTransform( // We undid the offset, so reset. This avoids a different shader. gstate_c.curTextureXOffset = prevXOffset; gstate_c.curTextureYOffset = prevYOffset; - result->textureChanged = true; } } } +} + +// 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; @@ -541,7 +552,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), @@ -570,7 +581,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; @@ -623,7 +634,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... @@ -645,4 +656,5 @@ void SoftwareTransform( } result->action = SW_DRAW_PRIMITIVES; + result->drawNumTrans = numTrans; } diff --git a/GPU/Common/SoftwareTransformCommon.h b/GPU/Common/SoftwareTransformCommon.h index bdc63deda2..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, }; @@ -35,8 +36,11 @@ struct SoftwareTransformResult { float depth; bool setStencil; - bool textureChanged; u8 stencilValue; + + TransformedVertex *drawBuffer; + int drawNumTrans; + bool drawIndexed; }; struct SoftwareTransformParams { @@ -50,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/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/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/GLES/DrawEngineGLES.cpp b/GPU/GLES/DrawEngineGLES.cpp index afada31f5e..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,23 +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); - - // We have an offset texture to apply. - if (result.textureChanged) { - textureCache_->ApplyTexture(); - // Apply again in case of depal. - ApplyDrawState(prim); - } + if (result.action == SW_NOT_READY) + swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, maxIndex, &result); ApplyDrawStateLate(result.setStencil, result.stencilValue); @@ -590,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. From ba566ef26a8e07023b34bea0638f142dd3cb5888 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 8 May 2020 23:05:17 -0700 Subject: [PATCH 43/59] GPU: Minor lighting cleanup in software transform. In this case, unlitColor is already materialAmbient. --- GPU/Common/SoftwareTransformCommon.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 12b0e1bde2..e87d5a940a 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -324,12 +324,8 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt } } } 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. From 581a288852c428382ee1a12bb7ecb3ac22707708 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 11:10:04 -0700 Subject: [PATCH 44/59] Android: Refactor size maintenance to own class. --- .../src/org/ppsspp/ppsspp/NativeActivity.java | 160 ++--------------- .../src/org/ppsspp/ppsspp/SizeManager.java | 165 ++++++++++++++++++ 2 files changed, 175 insertions(+), 150 deletions(-) create mode 100644 android/src/org/ppsspp/ppsspp/SizeManager.java diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 2a2b986702..dfd429d326 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -28,10 +28,8 @@ 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; @@ -40,13 +38,9 @@ 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 +53,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 @@ -116,20 +110,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, }; @@ -467,12 +451,6 @@ 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; @@ -481,34 +459,15 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C } } - @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); + sizeManager.updateDisplayMeasurements(display, getSurfaceView(), navigationHidden); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + sizeManager = new SizeManager(this); TextRenderer.init(this); shuttingDown = false; registerCallbacks(); @@ -540,7 +499,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.setupSurfaceView(mGLSurfaceView); // Setup the GLSurface and ask android for the correct // Number of bits for r, g, b, a, depth and stencil components @@ -572,93 +531,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.setupSurfaceView(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 +564,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,7 +611,7 @@ public abstract class NativeActivity extends Activity implements SurfaceHolder.C return; } - decorView.setOnSystemUiVisibilityChangeListener(new OnSystemUiVisibilityChangeListener() { + decorView.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { // Called when the system UI's visibility changes, regardless of @@ -864,29 +747,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 +765,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); } } diff --git a/android/src/org/ppsspp/ppsspp/SizeManager.java b/android/src/org/ppsspp/ppsspp/SizeManager.java new file mode 100644 index 0000000000..646231d59b --- /dev/null +++ b/android/src/org/ppsspp/ppsspp/SizeManager.java @@ -0,0 +1,165 @@ +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.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; + +public class SizeManager implements SurfaceHolder.Callback { + private static String TAG = "PPSSPPSizeManager"; + + final NativeActivity activity; + + 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 Point desiredSize = new Point(); + private int badOrientationCount = 0; + + public SizeManager(final NativeActivity a) { + activity = a; + } + + @TargetApi(Build.VERSION_CODES.P) + public void setupSurfaceView(SurfaceView surfaceView) { + 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); + + activity.updateDisplayMeasurements(); + activity.notifySurface(holder.getSurface()); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + activity.notifySurface(null); + + // Autosize the next created surface. + holder.setSizeFromLayout(); + } + + @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) + public void updateDisplayMeasurements(Display display, SurfaceView view, boolean navigationHidden) { + // 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 (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); + } + + 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); + } + } +} From 040ba2b3ff316daa12242c6289d2b1d306cb9c02 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 11:10:48 -0700 Subject: [PATCH 45/59] Android: Reassert sustained perf when going ingame. --- android/src/org/ppsspp/ppsspp/NativeActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index dfd429d326..97c36606ff 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -1316,6 +1316,7 @@ public abstract class NativeActivity extends Activity { 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); From f60d80b24e831ca0f37806bc878eb8e302845056 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 11:22:44 -0700 Subject: [PATCH 46/59] Android: Move a bit more size handling. --- .../src/org/ppsspp/ppsspp/NativeActivity.java | 40 ++++--------------- .../src/org/ppsspp/ppsspp/SizeManager.java | 38 +++++++++++++++--- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 97c36606ff..9bfc178cd9 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -85,7 +85,6 @@ public abstract class NativeActivity extends Activity { private boolean sustainedPerfSupported; - private boolean navigationHidden; private View navigationCallbackView = null; // audioFocusChangeListener to listen to changes in audio state @@ -421,7 +420,7 @@ public abstract class NativeActivity extends Activity { } else { Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring for now"); } - updateDisplayMeasurements(); + sizeManager.updateDisplayMeasurements(); } // Need API 11 to check for existence of a vibrator? Zany. @@ -451,19 +450,6 @@ public abstract class NativeActivity extends Activity { // Tells the render loop thread to exit, so we can restart it. public native void exitEGLRenderLoop(); - private SurfaceView getSurfaceView() { - if (mGLSurfaceView != null) { - return mGLSurfaceView; - } else { - return mSurfaceView; - } - } - - public void updateDisplayMeasurements() { - Display display = getWindowManager().getDefaultDisplay(); - sizeManager.updateDisplayMeasurements(display, getSurfaceView(), navigationHidden); - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -475,7 +461,7 @@ public abstract class NativeActivity extends Activity { // 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(); @@ -499,7 +485,7 @@ public abstract class NativeActivity extends Activity { mGLSurfaceView = new NativeGLView(this); nativeRenderer = new NativeRenderer(this); mGLSurfaceView.setEGLContextClientVersion(2); - sizeManager.setupSurfaceView(mGLSurfaceView); + sizeManager.setSurfaceView(mGLSurfaceView); // Setup the GLSurface and ask android for the correct // Number of bits for r, g, b, a, depth and stencil components @@ -537,7 +523,7 @@ public abstract class NativeActivity extends Activity { } mSurfaceView = new NativeSurfaceView(NativeActivity.this); - sizeManager.setupSurfaceView(mSurfaceView); + sizeManager.setSurfaceView(mSurfaceView); Log.i(TAG, "setcontentview before"); setContentView(mSurfaceView); Log.i(TAG, "setcontentview after"); @@ -611,20 +597,7 @@ public abstract class NativeActivity extends Activity { return; } - decorView.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: " + decorView.getWidth() + "x" + decorView.getHeight()); - updateDisplayMeasurements(); - } - }); + sizeManager.setupSystemUiCallback(decorView); navigationCallbackView = decorView; } @@ -659,6 +632,7 @@ public abstract class NativeActivity extends Activity { mSurfaceView.onDestroy(); mSurfaceView = null; } + sizeManager.setSurfaceView(null); if (mPowerSaveModeReceiver != null) { mPowerSaveModeReceiver.destroy(this); mPowerSaveModeReceiver = null; @@ -774,7 +748,7 @@ public abstract class NativeActivity extends Activity { // onConfigurationChanged not called on multi-window change Log.i(TAG, "onMultiWindowModeChanged: isInMultiWindowMode = " + isInMultiWindowMode); super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig); - updateDisplayMeasurements(); + sizeManager.updateDisplayMeasurements(); } // keep this static so we can call this even if we don't diff --git a/android/src/org/ppsspp/ppsspp/SizeManager.java b/android/src/org/ppsspp/ppsspp/SizeManager.java index 646231d59b..def28237a6 100644 --- a/android/src/org/ppsspp/ppsspp/SizeManager.java +++ b/android/src/org/ppsspp/ppsspp/SizeManager.java @@ -18,6 +18,7 @@ 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; @@ -29,6 +30,8 @@ public class SizeManager implements SurfaceHolder.Callback { private int pixelWidth; private int pixelHeight; + private boolean navigationHidden = false; + private Point desiredSize = new Point(); private int badOrientationCount = 0; @@ -37,7 +40,11 @@ public class SizeManager implements SurfaceHolder.Callback { } @TargetApi(Build.VERSION_CODES.P) - public void setupSurfaceView(SurfaceView surfaceView) { + public void setSurfaceView(SurfaceView view) { + surfaceView = view; + if (surfaceView == null) + return; + surfaceView.getHolder().addCallback(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { @@ -94,8 +101,8 @@ public class SizeManager implements SurfaceHolder.Callback { 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.updateDisplayMeasurements(); activity.notifySurface(holder.getSurface()); } @@ -108,7 +115,8 @@ public class SizeManager implements SurfaceHolder.Callback { } @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - public void updateDisplayMeasurements(Display display, SurfaceView view, boolean navigationHidden) { + public void updateDisplayMeasurements() { + 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(); @@ -119,9 +127,9 @@ public class SizeManager implements SurfaceHolder.Callback { } // Later on, we have the exact pixel size so let's just use it. - if (view != null) { - metrics.widthPixels = view.getWidth(); - metrics.heightPixels = view.getHeight(); + if (surfaceView != null) { + metrics.widthPixels = surfaceView.getWidth(); + metrics.heightPixels = surfaceView.getHeight(); } densityDpi = metrics.densityDpi; refreshRate = display.getRefreshRate(); @@ -129,6 +137,24 @@ public class SizeManager implements SurfaceHolder.Callback { 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()); + updateDisplayMeasurements(); + } + }); + } + public void updateDpi(float dpi) { densityDpi = dpi; } From dddaa57392027227e666daa4796bf83cfc931955 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 12:20:42 -0700 Subject: [PATCH 47/59] Windows: Fix GL reinit on backend switch. --- Windows/GPU/WindowsGLContext.cpp | 3 +++ ext/native/gfx_es2/gpu_features.cpp | 13 +++++++++++-- ext/native/gfx_es2/gpu_features.h | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) 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/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); From 03fc86a1475851ae315224c0b4704e3fb48b9661 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 13:52:04 -0700 Subject: [PATCH 48/59] UI: Return to game settings after restart. This is more convenient. Also restarts the game if needed. Added a way to pass args to Android here as well, and fixed displaying an error if the shortcut file doesn't exist on Android (like if you deleted it after creating the shortcut.) --- UI/GameSettingsScreen.cpp | 27 ++++--- UI/GameSettingsScreen.h | 2 + UI/MiscScreens.cpp | 9 ++- UI/MiscScreens.h | 9 +-- UI/NativeApp.cpp | 26 +++++-- Windows/W32Util/Misc.cpp | 11 ++- Windows/W32Util/Misc.h | 2 +- Windows/main.cpp | 20 ++++-- android/jni/app-android.cpp | 72 +++++++++++++++++-- .../src/org/ppsspp/ppsspp/NativeActivity.java | 8 ++- .../src/org/ppsspp/ppsspp/PpssppActivity.java | 10 ++- ext/native/ui/screen.cpp | 50 ++++++------- ext/native/ui/screen.h | 2 +- 13 files changed, 183 insertions(+), 65 deletions(-) diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c597a68394..f11be70585 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -1195,14 +1195,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(); } @@ -1212,10 +1223,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) @@ -1227,8 +1235,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 2cf38a3a36..cfcd7fae27 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 8888df4b55..27fadc85fd 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()); diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index 34b0e0f40b..459974de48 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 b71f30a90f..3c29f900b2 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/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/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/jni/app-android.cpp b/android/jni/app-android.cpp index 88b66a00e9..94105f01cd 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -399,6 +399,60 @@ 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; + } + 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 +509,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"; diff --git a/android/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index 9bfc178cd9..be62d9abdd 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -75,6 +75,7 @@ public abstract class NativeActivity extends Activity { protected NativeRenderer nativeRenderer; private String shortcutParam = ""; + private static String overrideShortcutParam = null; public static String runCommand; public static String commandParameter; @@ -302,9 +303,11 @@ public abstract class NativeActivity extends Activity { 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")); @@ -1254,6 +1257,9 @@ public abstract class NativeActivity extends Activity { 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")) { 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/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_; }; From d328e161d7fd5a40e1a1f6c75f12e911e51e3a99 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 14:06:54 -0700 Subject: [PATCH 49/59] UI: Add more options to touch test screen. --- UI/ControlMappingScreen.cpp | 32 +++++++++++++++++++++++++++++++- UI/ControlMappingScreen.h | 5 ++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 8dac4ccae6..2008c19f50 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); }; From ccc7ae54af9f2cb229b3248d17c922c5954f14ec Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 May 2020 14:44:07 -0700 Subject: [PATCH 50/59] Android: Avoid multiple resizes in a row. This was sometimes happening when ui callbacks etc. would trigger in certain patterns of using the app. Might have been related to sizing problems. Delaying the resize by 10ms when the surface is unchanged seems okay. --- android/jni/app-android.cpp | 21 ++++++++++------ .../src/org/ppsspp/ppsspp/NativeActivity.java | 6 ++--- .../src/org/ppsspp/ppsspp/SizeManager.java | 25 ++++++++++++++++++- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 94105f01cd..649ecade8a 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1026,14 +1026,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/src/org/ppsspp/ppsspp/NativeActivity.java b/android/src/org/ppsspp/ppsspp/NativeActivity.java index be62d9abdd..2b6f2d4890 100644 --- a/android/src/org/ppsspp/ppsspp/NativeActivity.java +++ b/android/src/org/ppsspp/ppsspp/NativeActivity.java @@ -29,14 +29,12 @@ import android.os.Vibrator; import android.provider.MediaStore; import android.text.InputType; import android.util.Log; -import android.view.Display; 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.SurfaceView; import android.view.View; @@ -423,7 +421,7 @@ public abstract class NativeActivity extends Activity { } else { Log.e(TAG, "updateSystemUiVisibility: decor view not yet created, ignoring for now"); } - sizeManager.updateDisplayMeasurements(); + sizeManager.checkDisplayMeasurements(); } // Need API 11 to check for existence of a vibrator? Zany. @@ -751,7 +749,7 @@ public abstract class NativeActivity extends Activity { // onConfigurationChanged not called on multi-window change Log.i(TAG, "onMultiWindowModeChanged: isInMultiWindowMode = " + isInMultiWindowMode); super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig); - sizeManager.updateDisplayMeasurements(); + sizeManager.checkDisplayMeasurements(); } // keep this static so we can call this even if we don't diff --git a/android/src/org/ppsspp/ppsspp/SizeManager.java b/android/src/org/ppsspp/ppsspp/SizeManager.java index def28237a6..d5977e974a 100644 --- a/android/src/org/ppsspp/ppsspp/SizeManager.java +++ b/android/src/org/ppsspp/ppsspp/SizeManager.java @@ -5,6 +5,8 @@ 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; @@ -13,6 +15,7 @@ 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"; @@ -31,6 +34,7 @@ public class SizeManager implements SurfaceHolder.Callback { private int pixelHeight; private boolean navigationHidden = false; + private boolean displayUpdatePending = false; private Point desiredSize = new Point(); private int badOrientationCount = 0; @@ -114,8 +118,27 @@ public class SizeManager implements SurfaceHolder.Callback { 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. @@ -150,7 +173,7 @@ public class SizeManager implements SurfaceHolder.Callback { // 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()); - updateDisplayMeasurements(); + checkDisplayMeasurements(); } }); } From a34c773b13e399a9d5da867efc0959792637939b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 May 2020 23:09:49 +0200 Subject: [PATCH 51/59] Vulkan: Don't merge render passes where the second one begins with a clear. God of War optimization survives this check, thankfully. Force Unleashed doesn't, but meh, it's not as bad there anyway. --- ext/native/thin3d/VulkanQueueRunner.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) 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. From b0a163ba2e0717e77a9f4a439ce1c5ad702940aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 May 2020 23:07:44 +0200 Subject: [PATCH 52/59] ColorConv: Fix a few conversions that missed the lower bits of each component. --- Common/ColorConv.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) 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; } } From 73c253e2ac96effee8edb85f10cda802b58bc09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 May 2020 23:09:01 +0200 Subject: [PATCH 53/59] D3D11: Fix a bind ordering issue in depal (only a problem with debug layer enabled) --- GPU/D3D11/TextureCacheD3D11.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index cb593d7873..f9adc53017 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -399,10 +399,11 @@ 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; + framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); 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); - framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap); shaderApply.Shade(); From f708396bda666549133e29cda337adeffa5b3618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 May 2020 23:09:40 +0200 Subject: [PATCH 54/59] Fix a comment --- GPU/Common/FramebufferCommon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 8853b2a262..0bd3f03985 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -1212,7 +1212,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) { From c1d32e8b3e885280846e7d7577c91767828a5721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 10 May 2020 23:42:32 +0200 Subject: [PATCH 55/59] D3D11: Better set current texture to null first, otherwise we can run into another issue. --- GPU/D3D11/TextureCacheD3D11.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index f9adc53017..568343bdd8 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -400,10 +400,11 @@ void TextureCacheD3D11::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFra shaderApply.Use(depalShaderCache_->GetDepalettizeVertexShader(), depalShaderCache_->GetInputLayout()); ID3D11ShaderResourceView *nullTexture = nullptr; - framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); + 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); + framebufferManagerD3D11_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_SKIP_COPY | BINDFBCOLOR_FORCE_SELF); context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DWrap); shaderApply.Shade(); From 0e5957e67e13181496dc5d1071d95c4c0393e1f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 12 May 2020 23:24:55 +0200 Subject: [PATCH 56/59] Temporarily disable YuGiOh save fix (experiment in issue #7914) --- assets/compat.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/compat.ini b/assets/compat.ini index 7c7ae1df97..49a228e5ed 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -486,7 +486,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 From b1ae90dd0362b3473a87edae0300e368ea97ab4d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 12 May 2020 21:20:13 -0700 Subject: [PATCH 57/59] Global: Add some defs for MSVC highlighting. Just want this file not to be a sea of errors. Before it said ifs etc. were wrong too, because it didn't think things were functions. --- android/jni/app-android.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 649ecade8a..e5b7e8e911 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" From 54896432dfb4ddc354079d288b3f2ce83e424896 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 12 May 2020 21:21:22 -0700 Subject: [PATCH 58/59] Android: Oops, fix start with space in filename. --- android/jni/app-android.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index e5b7e8e911..086371085d 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -471,6 +471,10 @@ static void parse_args(std::vector &args, const std::string value) // 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; } From a2b99e23d26dbf9ee8073402fbb262cce86b4f52 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 13 May 2020 08:39:50 -0700 Subject: [PATCH 59/59] GPU: Handle buffer overhead in postshader uniforms. Framebuffers may be temporarily larger than the estimated width, because we estimate different sizes for them and resizing is expensive. This moves accounting for that to texelDelta instead of pixelDelta. --- GPU/Common/FramebufferCommon.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 0bd3f03985..15af360342 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -799,7 +799,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(); @@ -1015,7 +1015,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); @@ -1064,7 +1066,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 @@ -1835,15 +1839,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();