diff --git a/packages/emulators/standalone/duckstation-sa/config/RK3566/settings.ini b/packages/emulators/standalone/duckstation-sa/config/RK3566/settings.ini new file mode 100644 index 000000000..40e43a8b2 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/config/RK3566/settings.ini @@ -0,0 +1,229 @@ +[Main] +SettingsVersion = 3 +StartFullscreen = true +EmulationSpeed = 1.000000 +FastForwardSpeed = 0.000000 +TurboSpeed = 0.000000 +SyncToHostRefreshRate = false +IncreaseTimerResolution = true +InhibitScreensaver = true +StartPaused = false +PauseOnFocusLoss = false +PauseOnMenu = true +SaveStateOnExit = true +ConfirmPowerOff = true +LoadDevicesFromSaveStates = false +ApplyGameSettings = true +AutoLoadCheats = true +DisableAllEnhancements = false +RewindEnable = false +RewindFrequency = 10.000000 +RewindSaveSlots = 10 +RunaheadFrameCount = 0 + + +[BIOS] +SearchDirectory = /storage/roms/bios +PathNTSCU = +PathNTSCJ = +PathPAL = +PatchTTYEnable = false +PatchFastBoot = true + + +[GPU] +Renderer = Software +Adapter = +ResolutionScale = 1 +Multisamples = 1 +UseDebugDevice = false +PerSampleShading = false +UseThread = true +ThreadedPresentation = true +UseSoftwareRendererForReadbacks = false +TrueColor = false +ScaledDithering = false +TextureFilter = Nearest +DownsampleMode = Disabled +DisableInterlacing = false +ForceNTSCTimings = false +WidescreenHack = false +ChromaSmoothing24Bit = false +PGXPEnable = false +PGXPCulling = true +PGXPTextureCorrection = true +PGXPVertexCache = false +PGXPCPU = false +PGXPPreserveProjFP = false +PGXPTolerance = -1.000000 +PGXPDepthBuffer = false +PGXPDepthClearThreshold = 300.000000 + + +[Display] +CropMode = Overscan +ActiveStartOffset = 0 +ActiveEndOffset = 0 +LineStartOffset = 0 +LineEndOffset = 0 +Force4_3For24Bit = false +AspectRatio = 4:3 +CustomAspectRatioNumerator = 4 +LinearFiltering = true +IntegerScaling = false +Stretch = false +PostProcessing = false +ShowOSDMessages = true +ShowFPS = false +ShowVPS = false +ShowSpeed = false +ShowResolution = false +ShowStatusIndicators = true +ShowEnhancements = false +DisplayAllFrames = true +VSync = false +MaxFPS = 0.000000 + + +[Hotkeys] + + +[Logging] +LogLevel = Error +LogFilter = +LogToConsole = false +LogToDebug = false +LogToWindow = false +LogToFile = false + + +[Controller1] +Type = AnalogController +ButtonUp = Controller0/Button11 +ButtonDown = Controller0/Button12 +ButtonLeft = Controller0/Button13 +ButtonRight = Controller0/Button14 +ButtonSelect = Controller0/Button4 +ButtonStart = Controller0/Button6 +ButtonTriangle = Controller0/Button2 +ButtonCross = Controller0/Button1 +ButtonSquare = Controller0/Button3 +ButtonCircle = Controller0/Button0 +ButtonL1 = Controller0/Button9 +ButtonL2 = Controller0/+Axis4 +ButtonR1 = Controller0/Button10 +ButtonR2 = Controller0/+Axis5 +AxisLeftX = Controller0/Axis0 +AxisLeftY = Controller0/Axis1 +ButtonL3 = Controller0/Button7 +ButtonR3 = Controller0/Button8 +AxisRightX = Controller0/Axis2 +AxisRightY = Controller0/Axis3 +AnalogDPadInDigitalMode = false + + +[GameList] +RecursivePaths = /storage/roms/psx + + +[MemoryCards] +UsePlaylistTitle = true +Directory = /storage/roms/psx +Card1Type = PerGameTitle +Card2Type = None + + +[Console] +Region = Auto +Enable8MBRAM = false + + +[CPU] +ExecutionMode = Recompiler +OverclockEnable = false +OverclockNumerator = 1 +OverclockDenominator = 1 +RecompilerMemoryExceptions = false +RecompilerBlockLinking = true +RecompilerICache = false +FastmemMode = MMap + + +[CDROM] +ReadaheadSectors = 8 +RegionCheck = false +LoadImageToRAM = false +MuteCDAudio = false +ReadSpeedup = 1 +SeekSpeedup = 1 + + +[Audio] +Backend = SDL +OutputVolume = 100 +FastForwardVolume = 100 +BufferSize = 2048 +Resampling = true +OutputMuted = false +Sync = true +DumpOnBoot = false + + +[Hacks] +DMAMaxSliceTicks = 1000 +DMAHaltTicks = 100 +GPUFIFOSize = 16 +GPUMaxRunAhead = 128 + + +[Controller2] +Type = None + + +[Controller3] +Type = None + + +[Controller4] +Type = None + + +[Controller5] +Type = None + + +[Controller6] +Type = None + + +[Controller7] +Type = None + + +[Controller8] +Type = None + + +[ControllerPorts] +MultitapMode = Disabled + + +[Debug] +ShowVRAM = false +DumpCPUToVRAMCopies = false +DumpVRAMToCPUCopies = false +ShowGPUState = false +ShowCDROMState = false +ShowSPUState = false +ShowTimersState = false +ShowMDECState = false +ShowDMAState = false + + +[TextureReplacements] +EnableVRAMWriteReplacements = false +PreloadTextures = false +DumpVRAMWrites = false +DumpVRAMWriteForceAlphaChannel = true +DumpVRAMWriteWidthThreshold = 128 +DumpVRAMWriteHeightThreshold = 128 diff --git a/packages/emulators/standalone/duckstation-sa/package.mk b/packages/emulators/standalone/duckstation-sa/package.mk index 9f26d67e6..8c9c4190b 100644 --- a/packages/emulators/standalone/duckstation-sa/package.mk +++ b/packages/emulators/standalone/duckstation-sa/package.mk @@ -3,13 +3,23 @@ PKG_NAME="duckstation-sa" PKG_LICENSE="GPLv3" -PKG_VERSION="5fee6f5abee7f3aad65da5523e57896e10e2a53a" PKG_DEPENDS_TARGET="toolchain SDL2 nasm:host pulseaudio openssl libidn2 nghttp2 zlib curl libevdev ecm" PKG_SITE="https://github.com/stenzek/duckstation" PKG_URL="${PKG_SITE}.git" PKG_SHORTDESC="Fast PlayStation 1 emulator for x86-64/AArch32/AArch64 " PKG_TOOLCHAIN="cmake" -PKG_PATCH_DIRS+="wayland" + +case ${DEVICE} in + RK3566) + PKG_VERSION="5ab5070d73f1acc51e064bd96be4ba6ce3c06f5c" + PKG_PATCH_DIRS+=" legacy" + PKG_CMAKE_OPTS_TARGET+=" -DUSE_DRMKMS=ON -DENABLE_EGL=ON -DUSE_MALI=OFF" + ;; + *) + PKG_VERSION="991f7312b25ee9d3dc98b39d1944314db026f954" + PKG_PATCH_DIRS+=" wayland" + ;; +esac if [ ! "${OPENGL}" = "no" ]; then PKG_DEPENDS_TARGET+=" ${OPENGL} glu libglvnd" diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/000-fix-cmake.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/000-fix-cmake.patch new file mode 100755 index 000000000..62c283a58 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/000-fix-cmake.patch @@ -0,0 +1,129 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index a02270e7..dbb48953 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -40,6 +40,7 @@ if(SUPPORTS_WAYLAND) + endif() + if((LINUX OR FREEBSD) OR ANDROID) + option(USE_EGL "Support EGL OpenGL context creation" ON) ++ option(USE_MALI "Link with libmali for EGL support" OFF) + endif() + if((LINUX OR FREEBSD) AND NOT ANDROID) + option(USE_DRMKMS "Support DRM/KMS OpenGL contexts" OFF) +@@ -232,7 +233,7 @@ elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86" OR ${CMAKE_SYSTEM_PROCESSOR} STR + elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64") + set(CPU_ARCH "aarch64") + elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a" OR +- ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l") ++ ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7l" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv8l") + set(CPU_ARCH "aarch32") + if(ANDROID) + # Force ARM mode, since apparently ANDROID_ARM_MODE isn't working.. +@@ -240,8 +241,13 @@ elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm" OR ${CMAKE_SYSTEM_PROCESSOR} STR + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm") + else() + # Enable NEON. +- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm -march=armv7-a") +- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm -march=armv7-a") ++ if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv8l") ++ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm -mtune=cortex-a55") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm -mtune=cortex-a55") ++ else() ++ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -marm -march=armv7-a") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm -march=armv7-a") ++ endif() + endif() + else() + message(FATAL_ERROR "Unknown system processor: " ${CMAKE_SYSTEM_PROCESSOR}) +diff -u -r /home/romain/duckstation/CMakeModules/FindEGL.cmake ./CMakeModules/FindEGL.cmake +--- /home/romain/duckstation/CMakeModules/FindEGL.cmake 2021-02-13 00:29:48.693304818 +0100 ++++ ./CMakeModules/FindEGL.cmake 2021-02-13 00:45:35.564462969 +0100 +@@ -86,6 +86,17 @@ + ${PKG_EGL_LIBRARY_DIRS} + ) + ++if(USE_MALI) ++pkg_check_modules(PKG_MALI QUIET mali) ++find_library(MALI_LIBRARY ++ NAMES ++ mali ++ HINTS ++ ${PKG_MALI_LIBRARY_DIRS} ++) ++endif() ++ ++ + # NB: We do *not* use the version information from pkg-config, as that + # is the implementation version (eg: the Mesa version) + if(EGL_INCLUDE_DIR) +@@ -117,7 +128,11 @@ + + cmake_push_check_state(RESET) + list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}") ++if(USE_MALI) ++list(APPEND CMAKE_REQUIRED_LIBRARIES "${MALI_LIBRARY}") ++endif() + list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}") ++list(APPEND CMAKE_REQUIRED_DEFINITIONS "-DEGL_NO_X11 -DUSE_X11=NO") + + check_cxx_source_compiles(" + #include +@@ -161,7 +176,11 @@ + mark_as_advanced(EGL_LIBRARY EGL_INCLUDE_DIR HAVE_EGL) + + # compatibility variables ++if (USE_MALI) ++set(EGL_LIBRARIES ${EGL_LIBRARY} ${MALI_LIBRARY}) ++else() + set(EGL_LIBRARIES ${EGL_LIBRARY}) ++endif() + set(EGL_INCLUDE_DIRS ${EGL_INCLUDE_DIR}) + set(EGL_VERSION_STRING ${EGL_VERSION}) + +Seulement dans ./CMakeModules: FindEGL.cmake.orig +diff -u -r /home/romain/duckstation/dep/glad/CMakeLists.txt ./dep/glad/CMakeLists.txt +--- /home/romain/duckstation/dep/glad/CMakeLists.txt 2021-02-13 00:29:48.765302377 +0100 ++++ ./dep/glad/CMakeLists.txt 2021-02-13 00:42:20.848512028 +0100 +@@ -17,8 +17,9 @@ + target_sources(glad PRIVATE src/glad_wgl.c) + else() + if(USE_EGL) ++ target_compile_definitions(glad PRIVATE -DEGL_NO_X11) + target_sources(glad PRIVATE src/glad_egl.c) +- target_link_libraries(glad PRIVATE EGL::EGL) ++ target_link_libraries(glad PRIVATE EGL) + endif() + if(USE_X11) + target_sources(glad PRIVATE src/glad_glx.c) +diff -u -r /home/romain/duckstation/src/common/CMakeLists.txt ./src/common/CMakeLists.txt +--- /home/romain/duckstation/src/common/CMakeLists.txt 2021-02-13 00:29:48.885298307 +0100 ++++ ./src/common/CMakeLists.txt 2021-02-13 00:42:20.848512028 +0100 +@@ -175,12 +175,13 @@ + ) + endif() + if(USE_DRMKMS) ++ target_compile_definitions(common PRIVATE "-DEGL_NO_X11=1") + target_compile_definitions(common PRIVATE "-DUSE_GBM=1") + target_sources(common PRIVATE + gl/context_egl_gbm.cpp + gl/context_egl_gbm.h + ) +- target_link_libraries(common PUBLIC GBM::GBM) ++ target_link_libraries(common PUBLIC gbm EGL) + endif() + endif() + +diff -u -r /home/romain/duckstation/src/duckstation-nogui/CMakeLists.txt ./src/duckstation-nogui/CMakeLists.txt +--- /home/romain/duckstation/src/duckstation-nogui/CMakeLists.txt 2021-02-13 00:29:48.901297765 +0100 ++++ ./src/duckstation-nogui/CMakeLists.txt 2021-02-13 00:56:19.913224314 +0100 +@@ -29,6 +29,10 @@ + target_compile_definitions(duckstation-nogui PRIVATE "-DUSE_LIBEVDEV=1") + target_include_directories(duckstation-nogui PRIVATE ${LIBEVDEV_INCLUDE_DIRS}) + target_link_libraries(duckstation-nogui PRIVATE ${LIBEVDEV_LIBRARIES}) ++if (USE_MALI) ++ target_link_libraries(duckstation-nogui PRIVATE ${MALI_LIBRARY}) ++endif() ++ + endif() + + if(WIN32) diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/001-path-program.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/001-path-program.patch new file mode 100755 index 000000000..8ba945eba --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/001-path-program.patch @@ -0,0 +1,22 @@ +diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp +index 6a24732..a287703 100644 +--- a/src/common/file_system.cpp ++++ b/src/common/file_system.cpp +@@ -1179,6 +1179,8 @@ bool FileSystem::DeleteDirectory(const char* Path, bool Recursive) + + std::string GetProgramPath() + { ++ return "/storage/.config/duckstation"; ++ + std::wstring buffer; + buffer.resize(MAX_PATH); + +@@ -1549,6 +1551,8 @@ bool DeleteDirectory(const char* Path, bool Recursive) + + std::string GetProgramPath() + { ++ return "/storage/.config/duckstation"; ++ + #if defined(__linux__) + static const char* exeFileName = "/proc/self/exe"; + diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/002-path-getdirectory.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/002-path-getdirectory.patch new file mode 100755 index 000000000..8e99340b8 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/002-path-getdirectory.patch @@ -0,0 +1,14 @@ +diff --git a/src/common/file_system.cpp b/src/common/file_system.cpp +index ceb2f08..0fa5a04 100644 +--- a/src/common/file_system.cpp ++++ b/src/common/file_system.cpp +@@ -683,6 +683,9 @@ std::string GetDisplayNameFromPath(const std::string_view& path) + + std::string_view GetPathDirectory(const std::string_view& path) + { ++ ++ return "/storage/.config/duckstation"; ++ + std::string::size_type pos = GetLastSeperatorPosition(path, false); + if (pos == std::string_view::npos) + return {}; diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/003-path-language.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/003-path-language.patch new file mode 100755 index 000000000..83c814630 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/003-path-language.patch @@ -0,0 +1,13 @@ +diff --git a/src/duckstation-qt/qthostinterface.cpp b/src/duckstation-qt/qthostinterface.cpp +index 8052278..4f338d7 100644 +--- a/src/duckstation-qt/qthostinterface.cpp ++++ b/src/duckstation-qt/qthostinterface.cpp +@@ -137,7 +137,7 @@ void QtHostInterface::installTranslator() + const QString language(QString::fromStdString(GetStringSettingValue("Main", "Language", "en"))); + + // install the base qt translation first +- const QString base_dir(QStringLiteral("%1/translations").arg(qApp->applicationDirPath())); ++ const QString base_dir(QStringLiteral("%1/translations").arg("/storage/.config/duckstation")); + const QString base_path(QStringLiteral("%1/qtbase_%2.qm").arg(base_dir).arg(language)); + if (QFile::exists(base_path)) + { diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/004-add-rotation.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/004-add-rotation.patch new file mode 100755 index 000000000..ea2506f40 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/004-add-rotation.patch @@ -0,0 +1,389 @@ +diff --git a/src/common/gl/program.h b/src/common/gl/program.h +index d877a462..3fa9a7a7 100644 +--- a/src/common/gl/program.h ++++ b/src/common/gl/program.h +@@ -40,6 +40,7 @@ public: + void Destroy(); + + int RegisterUniform(const char* name); ++ GLint GetUniformLocation(int index) const { return m_uniform_locations[index]; } + void Uniform1ui(int index, u32 x) const; + void Uniform2ui(int index, u32 x, u32 y) const; + void Uniform3ui(int index, u32 x, u32 y, u32 z) const; +@@ -97,6 +98,6 @@ private: + GLuint m_fragment_shader_id = 0; + + std::vector m_uniform_locations; +-}; ++}; // namespace GL + + } // namespace GL +\ No newline at end of file +diff --git a/src/core/host_display.cpp b/src/core/host_display.cpp +index d0469fd3..790be30f 100644 +--- a/src/core/host_display.cpp ++++ b/src/core/host_display.cpp +@@ -103,6 +103,11 @@ bool HostDisplay::GetHostRefreshRate(float* refresh_rate) + return WindowInfo::QueryRefreshRateForWindow(m_window_info, refresh_rate); + } + ++bool HostDisplay::SetDisplayRotation(Rotation rotation) ++{ ++ return false; ++} ++ + void HostDisplay::SetSoftwareCursor(std::unique_ptr texture, float scale /*= 1.0f*/) + { + m_cursor_texture = std::move(texture); +diff --git a/src/core/host_display.h b/src/core/host_display.h +index ea01f846..b5a3563e 100644 +--- a/src/core/host_display.h ++++ b/src/core/host_display.h +@@ -60,6 +60,15 @@ public: + std::vector fullscreen_modes; + }; + ++ enum class Rotation ++ { ++ None, ++ R90Degrees, ++ R180Degrees, ++ R270Degrees, ++ Count ++ }; ++ + virtual ~HostDisplay(); + + ALWAYS_INLINE const WindowInfo& GetWindowInfo() const { return m_window_info; } +@@ -201,6 +210,7 @@ public: + virtual bool SetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, const void* buffer, u32 pitch); + + virtual bool GetHostRefreshRate(float* refresh_rate); ++ virtual bool SetDisplayRotation(Rotation rotation); + + void SetDisplayLinearFiltering(bool enabled) { m_display_linear_filtering = enabled; } + void SetDisplayTopMargin(s32 height) { m_display_top_margin = height; } +@@ -283,6 +293,7 @@ protected: + + s32 m_display_top_margin = 0; + Alignment m_display_alignment = Alignment::Center; ++ Rotation m_display_rotation = Rotation::None; + + std::unique_ptr m_cursor_texture; + float m_cursor_texture_scale = 1.0f; +diff --git a/src/core/settings.cpp b/src/core/settings.cpp +index 833b6b9f..4381b848 100644 +--- a/src/core/settings.cpp ++++ b/src/core/settings.cpp +@@ -230,6 +230,7 @@ void Settings::Load(SettingsInterface& si) + display_line_start_offset = static_cast(si.GetIntValue("Display", "LineStartOffset", 0)); + display_line_end_offset = static_cast(si.GetIntValue("Display", "LineEndOffset", 0)); + display_linear_filtering = si.GetBoolValue("Display", "LinearFiltering", true); ++ display_rotate = static_cast(si.GetIntValue("Display", "Rotate", 0)); + display_integer_scaling = si.GetBoolValue("Display", "IntegerScaling", false); + display_stretch = si.GetBoolValue("Display", "Stretch", false); + display_post_processing = si.GetBoolValue("Display", "PostProcessing", false); +diff --git a/src/core/settings.h b/src/core/settings.h +index e837f8b2..199ecac7 100644 +--- a/src/core/settings.h ++++ b/src/core/settings.h +@@ -136,6 +136,7 @@ struct Settings + s16 display_active_end_offset = 0; + s8 display_line_start_offset = 0; + s8 display_line_end_offset = 0; ++ s8 display_rotate = 0; + bool display_force_4_3_for_24bit = false; + bool gpu_24bit_chroma_smoothing = false; + bool display_linear_filtering = true; +diff --git a/src/duckstation-nogui/nogui_host_interface.cpp b/src/duckstation-nogui/nogui_host_interface.cpp +index 638af4ea..6cef355a 100644 +--- a/src/duckstation-nogui/nogui_host_interface.cpp ++++ b/src/duckstation-nogui/nogui_host_interface.cpp +@@ -136,6 +136,15 @@ bool NoGUIHostInterface::CreateDisplay(bool fullscreen) + return false; + } + ++ switch(g_settings.display_rotate & 3) ++ { ++ case 1: m_display->SetDisplayRotation(HostDisplay::Rotation::R90Degrees); ++ case 2: m_display->SetDisplayRotation(HostDisplay::Rotation::R180Degrees); ++ case 3: m_display->SetDisplayRotation(HostDisplay::Rotation::R270Degrees); ++ case 0: ++ default: break; ++ } ++ + if (fullscreen) + SetFullscreen(true); + +diff --git a/src/frontend-common/opengl_host_display.cpp b/src/frontend-common/opengl_host_display.cpp +index 7092b455..ff1c7939 100644 +--- a/src/frontend-common/opengl_host_display.cpp ++++ b/src/frontend-common/opengl_host_display.cpp +@@ -203,6 +203,77 @@ void OpenGLHostDisplay::UpdateDisplayPixelsTextureFilter() + m_display_texture_is_linear_filtered = m_display_linear_filtering; + } + ++bool OpenGLHostDisplay::SetDisplayRotation(Rotation rotation) ++{ ++ m_display_rotation = rotation; ++ UpdateDisplayRotationFramebuffer(); ++ return true; ++} ++ ++void OpenGLHostDisplay::UpdateDisplayRotationFramebuffer() ++{ ++ m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); ++ m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); ++ ++ if (m_display_rotation_framebuffer_fbo != 0) ++ { ++ glDeleteFramebuffers(1, &m_display_rotation_framebuffer_fbo); ++ m_display_rotation_framebuffer_fbo = 0; ++ glDeleteTextures(1, &m_display_rotation_framebuffer_texture); ++ m_display_rotation_framebuffer_texture = 0; ++ } ++ ++ if (m_display_rotation != Rotation::None) ++ { ++ if (m_display_rotation_framebuffer_texture == 0) ++ glGenTextures(1, &m_display_rotation_framebuffer_texture); ++ if (m_display_rotation_framebuffer_fbo == 0) ++ glGenFramebuffers(1, &m_display_rotation_framebuffer_fbo); ++ ++ if (m_display_rotation == Rotation::R90Degrees || m_display_rotation == Rotation::R270Degrees) ++ std::swap(m_window_info.surface_width, m_window_info.surface_height); ++ ++ GLint old_texture; ++ glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_texture); ++ ++ glBindTexture(GL_TEXTURE_2D, m_display_rotation_framebuffer_texture); ++ ++ if (GLAD_GL_ARB_texture_storage || GLAD_GL_ES_VERSION_3_1) ++ { ++ glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, m_window_info.surface_width, m_window_info.surface_height); ++ } ++ else ++ { ++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_window_info.surface_width, m_window_info.surface_height, 0, GL_RGBA, ++ GL_UNSIGNED_BYTE, nullptr); ++ } ++ ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); ++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); ++ ++ const GLenum framebuffer_binding = m_use_gles2_draw_path ? GL_FRAMEBUFFER : GL_DRAW_FRAMEBUFFER; ++ GLint old_framebuffer; ++ glGetIntegerv(m_use_gles2_draw_path ? GL_FRAMEBUFFER_BINDING : GL_DRAW_FRAMEBUFFER_BINDING, &old_framebuffer); ++ ++ glBindFramebuffer(framebuffer_binding, m_display_rotation_framebuffer_fbo); ++ glFramebufferTexture2D(framebuffer_binding, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ++ m_display_rotation_framebuffer_texture, 0); ++ Assert(glCheckFramebufferStatus(framebuffer_binding) == GL_FRAMEBUFFER_COMPLETE); ++ ++ glBindFramebuffer(framebuffer_binding, old_framebuffer); ++ glBindTexture(GL_TEXTURE_2D, old_texture); ++ } ++ ++ if (ImGui::GetCurrentContext()) ++ { ++ ImGui::GetIO().DisplaySize = ++ ImVec2(static_cast(m_window_info.surface_width), static_cast(m_window_info.surface_height)); ++ } ++} ++ + bool OpenGLHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const + { + const auto [gl_internal_format, gl_format, gl_type] = GetPixelFormatMapping(m_gl_context->IsGLES(), format); +@@ -435,7 +506,7 @@ bool OpenGLHostDisplay::InitializeRenderDevice(std::string_view shader_cache_dir + glDebugMessageCallback(GLDebugCallback, nullptr); + + glEnable(GL_DEBUG_OUTPUT); +- // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); ++ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + } + + if (!CreateResources()) +@@ -484,7 +555,17 @@ bool OpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi) + return false; + } + +- m_window_info = m_gl_context->GetWindowInfo(); ++ m_window_info = new_wi; ++ m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); ++ m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); ++ ++ if (ImGui::GetCurrentContext()) ++ { ++ ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); ++ ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); ++ } ++ ++ UpdateDisplayRotationFramebuffer(); + return true; + } + +@@ -494,7 +575,16 @@ void OpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_ + return; + + m_gl_context->ResizeSurface(static_cast(new_window_width), static_cast(new_window_height)); +- m_window_info = m_gl_context->GetWindowInfo(); ++ m_window_info.surface_width = m_gl_context->GetSurfaceWidth(); ++ m_window_info.surface_height = m_gl_context->GetSurfaceHeight(); ++ ++ if (ImGui::GetCurrentContext()) ++ { ++ ImGui::GetIO().DisplaySize.x = static_cast(m_window_info.surface_width); ++ ImGui::GetIO().DisplaySize.y = static_cast(m_window_info.surface_height); ++ } ++ ++ UpdateDisplayRotationFramebuffer(); + } + + bool OpenGLHostDisplay::SupportsFullscreen() const +@@ -560,12 +650,17 @@ bool OpenGLHostDisplay::CreateResources() + { + static constexpr char fullscreen_quad_vertex_shader[] = R"( + uniform vec4 u_src_rect; ++uniform mat2 u_rotation_matrix; + out vec2 v_tex0; + + void main() + { + vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2)); +- v_tex0 = u_src_rect.xy + pos * u_src_rect.zw; ++ v_tex0 = (u_src_rect.xy + pos * u_src_rect.zw); ++ ++ vec2 center = vec2(0.5, 0.5); ++ v_tex0 = center + (u_rotation_matrix * (v_tex0 - center)); ++ + gl_Position = vec4(pos * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f); + } + )"; +@@ -617,12 +712,14 @@ void main() + + m_display_program.Bind(); + m_display_program.RegisterUniform("u_src_rect"); ++ m_display_program.RegisterUniform("u_rotation_matrix"); + m_display_program.RegisterUniform("samp0"); +- m_display_program.Uniform1i(1, 0); ++ m_display_program.Uniform1i(2, 0); + m_cursor_program.Bind(); + m_cursor_program.RegisterUniform("u_src_rect"); ++ m_cursor_program.RegisterUniform("u_rotation_matrix"); + m_cursor_program.RegisterUniform("samp0"); +- m_cursor_program.Uniform1i(1, 0); ++ m_cursor_program.Uniform1i(2, 0); + + glGenVertexArrays(1, &m_display_vao); + +@@ -749,7 +846,7 @@ bool OpenGLHostDisplay::Render() + } + + glDisable(GL_SCISSOR_TEST); +- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); ++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_display_rotation_framebuffer_fbo); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + +@@ -760,6 +857,12 @@ bool OpenGLHostDisplay::Render() + + RenderSoftwareCursor(); + ++ if (m_display_rotation_framebuffer_fbo != 0) ++ { ++ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); ++ RenderRotatedFramebuffer(); ++ } ++ + m_gl_context->SwapBuffers(); + return true; + } +@@ -833,6 +936,13 @@ void OpenGLHostDisplay::RenderDisplay() + m_display_texture_view_width, m_display_texture_view_height, m_display_linear_filtering); + } + ++static const std::array, static_cast(HostDisplay::Rotation::Count)> s_rotation_matrices = {{ ++ {{1.0f, 0.0f, 0.0f, 1.0f}}, ++ {{0.0f, 1.0f, 1.0f, 0.0f}}, ++ {{-1.0f, 0.0f, 0.0f, 1.0f}}, ++ {{0.0f, -1.0f, -1.0f, 0.0f}}, ++}}; ++ + static void DrawFullscreenQuadES2(s32 tex_view_x, s32 tex_view_y, s32 tex_view_width, s32 tex_view_height, + s32 tex_width, s32 tex_height) + { +@@ -879,6 +989,8 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh + (static_cast(texture_view_y) + (position_adjust * flip_adjust)) / static_cast(texture_height), + (static_cast(texture_view_width) - size_adjust) / static_cast(texture_width), + (static_cast(texture_view_height) - (size_adjust * flip_adjust)) / static_cast(texture_height)); ++ glUniformMatrix2fv(m_display_program.GetUniformLocation(1), 1, GL_TRUE, ++ s_rotation_matrices[static_cast(HostDisplay::Rotation::None)].data()); + glBindSampler(0, linear_filter ? m_display_linear_sampler : m_display_nearest_sampler); + glBindVertexArray(m_display_vao); + glDrawArrays(GL_TRIANGLES, 0, 3); +@@ -894,6 +1006,30 @@ void OpenGLHostDisplay::RenderDisplay(s32 left, s32 bottom, s32 width, s32 heigh + } + } + ++void OpenGLHostDisplay::RenderRotatedFramebuffer() ++{ ++ const u32 width = m_gl_context->GetSurfaceWidth(); ++ const u32 height = m_gl_context->GetSurfaceHeight(); ++ ++ glViewport(0, 0, width, height); ++ glDisable(GL_BLEND); ++ glDisable(GL_CULL_FACE); ++ glDisable(GL_DEPTH_TEST); ++ glDisable(GL_SCISSOR_TEST); ++ glDepthMask(GL_FALSE); ++ ++ glClear(GL_COLOR_BUFFER_BIT); ++ ++ m_display_program.Bind(); ++ m_display_program.Uniform4f(0, 0.0f, 0.0f, 1.0f, 1.0f); ++ glUniformMatrix2fv(m_display_program.GetUniformLocation(1), 1, GL_TRUE, ++ s_rotation_matrices[static_cast(m_display_rotation)].data()); ++ glBindTexture(GL_TEXTURE_2D, m_display_rotation_framebuffer_texture); ++ ++ glBindVertexArray(m_display_vao); ++ glDrawArrays(GL_TRIANGLES, 0, 3); ++} ++ + void OpenGLHostDisplay::RenderSoftwareCursor() + { + if (!HasSoftwareCursor()) +diff --git a/src/frontend-common/opengl_host_display.h b/src/frontend-common/opengl_host_display.h +index 23e8d700..585ab4b5 100644 +--- a/src/frontend-common/opengl_host_display.h ++++ b/src/frontend-common/opengl_host_display.h +@@ -51,6 +51,8 @@ public: + + bool SetPostProcessingChain(const std::string_view& config) override; + ++ bool SetDisplayRotation(Rotation rotation) override; ++ + std::unique_ptr CreateTexture(u32 width, u32 height, u32 layers, u32 levels, u32 samples, + HostDisplayPixelFormat format, const void* data, u32 data_stride, + bool dynamic = false) override; +@@ -83,6 +85,8 @@ protected: + + void BindDisplayPixelsTexture(); + void UpdateDisplayPixelsTextureFilter(); ++ void UpdateDisplayRotationFramebuffer(); ++ void RenderRotatedFramebuffer(); + + void RenderDisplay(); + void RenderImGui(); +@@ -121,6 +125,9 @@ protected: + u32 m_display_pixels_texture_pbo_map_size = 0; + std::vector m_gles_pixels_repack_buffer; + ++ GLuint m_display_rotation_framebuffer_texture = 0; ++ GLuint m_display_rotation_framebuffer_fbo = 0; ++ + PostProcessingChain m_post_processing_chain; + GL::Texture m_post_processing_input_texture; + std::unique_ptr m_post_processing_ubo; diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/005-add-hotkeys.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/005-add-hotkeys.patch new file mode 100755 index 000000000..4ad1c30ac --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/005-add-hotkeys.patch @@ -0,0 +1,110 @@ +diff --git a/src/frontend-common/sdl_controller_interface.cpp b/src/frontend-common/sdl_controller_interface.cpp +index 20e81daf..1deac2ce 100644 +--- a/src/frontend-common/sdl_controller_interface.cpp ++++ b/src/frontend-common/sdl_controller_interface.cpp +@@ -6,6 +6,7 @@ + #include "core/host_interface.h" + #include "core/system.h" + #include "sdl_initializer.h" ++#include "fullscreen_ui.h" + #include + #include + Log_SetChannel(SDLControllerInterface); +@@ -93,6 +94,8 @@ void SDLControllerInterface::PollEvents() + + bool SDLControllerInterface::ProcessSDLEvent(const SDL_Event* event) + { ++ if (m_slots < 0) { m_host_interface->AddOSDMessage("State Slot set to #0", 5.f); m_slots = 0; } ++ + switch (event->type) + { + case SDL_CONTROLLERDEVICEADDED: +@@ -204,6 +207,7 @@ bool SDLControllerInterface::OpenGameController(int index) + cd.joystick_id = joystick_id; + cd.haptic_left_right_effect = -1; + cd.game_controller = gcontroller; ++ cd.hotkey_down = false; + + #if SDL_VERSION_ATLEAST(2, 0, 9) + cd.use_game_controller_rumble = (SDL_GameControllerRumble(gcontroller, 0, 0, 0) == 0); +@@ -712,15 +716,59 @@ bool SDLControllerInterface::HandleControllerButtonEvent(const SDL_ControllerBut + m_host_interface->SetControllerNavigationButtonState(nav_button_mapping[ev->button], pressed); + } + ++ if (ev->button >= MAX_NUM_BUTTONS) ++ return false; ++ ++ //------ Mimic Retroarch ++ if (ev->button == SDL_CONTROLLER_BUTTON_GUIDE || ev->button == SDL_CONTROLLER_BUTTON_BACK) it->hotkey_down = pressed; ++ else if (it->hotkey_down) ++ { ++ if (!pressed) ++ switch(ev->button) ++ { ++ case SDL_CONTROLLER_BUTTON_A : m_host_interface->SaveScreenshot(); break; ++ case SDL_CONTROLLER_BUTTON_B : m_host_interface->ResetSystem(); break; ++ case SDL_CONTROLLER_BUTTON_X : if (FullscreenUI::HasActiveWindow()) FullscreenUI::CloseQuickMenu(); else FullscreenUI::OpenQuickMenu(); break; ++ case SDL_CONTROLLER_BUTTON_Y : m_host_interface->ToggleWidescreen(); break; ++ case SDL_CONTROLLER_BUTTON_START : ++ case SDL_CONTROLLER_BUTTON_LEFTSTICK : ++ case SDL_CONTROLLER_BUTTON_RIGHTSTICK : break; ++ case SDL_CONTROLLER_BUTTON_LEFTSHOULDER : m_host_interface->LoadState(false, m_slots); break; ++ case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: m_host_interface->SaveState(false, m_slots); break; ++ case SDL_CONTROLLER_BUTTON_DPAD_UP : m_slots = ++m_slots % 10; m_host_interface->AddOSDMessage(std::string("State Slot set to #") + (char)(0x30 + m_slots), 5.f); break; ++ case SDL_CONTROLLER_BUTTON_DPAD_DOWN : m_slots = (m_slots + 9) % 10; m_host_interface->AddOSDMessage(std::string("State Slot set to #") + (char)(0x30 + m_slots), 5.f); break; ++ case SDL_CONTROLLER_BUTTON_DPAD_LEFT : m_host_interface->SetRewindState(!System::IsRewinding()); break; ++ case SDL_CONTROLLER_BUTTON_DPAD_RIGHT : m_host_interface->SetFastForwardEnabled(!m_host_interface->IsFastForwardEnabled()); break; ++ default: break; ++ } ++ else ++ switch(ev->button) ++ { ++ case SDL_CONTROLLER_BUTTON_START : m_host_interface->RequestExit(); break; ++ case SDL_CONTROLLER_BUTTON_A : ++ case SDL_CONTROLLER_BUTTON_B : ++ case SDL_CONTROLLER_BUTTON_X : ++ case SDL_CONTROLLER_BUTTON_Y : ++ case SDL_CONTROLLER_BUTTON_LEFTSTICK : ++ case SDL_CONTROLLER_BUTTON_RIGHTSTICK : ++ case SDL_CONTROLLER_BUTTON_LEFTSHOULDER : ++ case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: ++ case SDL_CONTROLLER_BUTTON_DPAD_UP : ++ case SDL_CONTROLLER_BUTTON_DPAD_DOWN : ++ case SDL_CONTROLLER_BUTTON_DPAD_LEFT : ++ case SDL_CONTROLLER_BUTTON_DPAD_RIGHT : ++ default: break; ++ } ++ ++ return true; ++ } ++ + if (m_host_interface->IsControllerNavigationActive()) + { + // UI consumed the event + return true; + } + +- if (ev->button >= MAX_NUM_BUTTONS) +- return false; +- + const ButtonCallback& cb = it->button_mapping[ev->button]; + if (cb) + { +diff --git a/src/frontend-common/sdl_controller_interface.h b/src/frontend-common/sdl_controller_interface.h +index 06963a5c..ffc2ffac 100644 +--- a/src/frontend-common/sdl_controller_interface.h ++++ b/src/frontend-common/sdl_controller_interface.h +@@ -57,6 +57,7 @@ private: + int joystick_id; + int player_id; + bool use_game_controller_rumble; ++ bool hotkey_down; + + float deadzone = 0.25f; + +@@ -93,4 +94,5 @@ private: + Hook::Callback m_event_intercept_callback; + + bool m_sdl_subsystem_initialized = false; ++ int m_slots = -1; + }; diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/006-maxbuttons.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/006-maxbuttons.patch new file mode 100755 index 000000000..7d6082305 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/006-maxbuttons.patch @@ -0,0 +1,13 @@ +diff --git a/src/frontend-common/controller_interface.h b/src/frontend-common/controller_interface.h +index f97d0f6..563b5f4 100644 +--- a/src/frontend-common/sdl_controller_interface.h ++++ b/src/frontend-common/sdl_controller_interface.h +@@ -46,7 +46,7 @@ + enum : int + { + MAX_NUM_AXES = 7, +- MAX_NUM_BUTTONS = 16, ++ MAX_NUM_BUTTONS = 256, + }; + + struct ControllerData diff --git a/packages/emulators/standalone/duckstation-sa/patches/legacy/007-inhibit-vulkan.patch b/packages/emulators/standalone/duckstation-sa/patches/legacy/007-inhibit-vulkan.patch new file mode 100755 index 000000000..17ed4dca7 --- /dev/null +++ b/packages/emulators/standalone/duckstation-sa/patches/legacy/007-inhibit-vulkan.patch @@ -0,0 +1,17 @@ +diff --git a/src/duckstation-nogui/nogui_host_interface.cpp b/src/duckstation-nogui/nogui_host_interface.cpp +index a8e4ddf2..eda7baa3 100644 +--- a/src/duckstation-nogui/nogui_host_interface.cpp ++++ b/src/duckstation-nogui/nogui_host_interface.cpp +@@ -105,10 +105,10 @@ bool NoGUIHostInterface::CreateDisplay(bool fullscreen) + Assert(!m_display); + switch (g_settings.gpu_renderer) + { +- case GPURenderer::HardwareVulkan: ++/* case GPURenderer::HardwareVulkan: + m_display = std::make_unique(); + break; +- ++*/ + case GPURenderer::HardwareOpenGL: + #ifndef _WIN32 + default: diff --git a/packages/emulators/standalone/duckstation-sa/patches/002-fix-evdev-compile.patch b/packages/emulators/standalone/duckstation-sa/patches/wayland/004-fix-evdev-compile.patch similarity index 100% rename from packages/emulators/standalone/duckstation-sa/patches/002-fix-evdev-compile.patch rename to packages/emulators/standalone/duckstation-sa/patches/wayland/004-fix-evdev-compile.patch diff --git a/packages/virtual/emulators/package.mk b/packages/virtual/emulators/package.mk index 014b01d72..97765ac00 100644 --- a/packages/virtual/emulators/package.mk +++ b/packages/virtual/emulators/package.mk @@ -7,7 +7,8 @@ PKG_SITE="www.jelos.org" PKG_SECTION="virtual" PKG_LONGDESC="Emulation metapackage." -PKG_EMUS="flycast-sa hatarisa hypseus-singe hypseus-singe moonlight openbor pico-8 ppsspp-sa scummvmsa vice-sa" +PKG_EMUS="duckstation-sa flycast-sa hatarisa hypseus-singe hypseus-singe moonlight openbor pico-8 ppsspp-sa + scummvmsa vice-sa" PKG_RETROARCH="core-info libretro-database retroarch retroarch-assets retroarch-joypads retroarch-overlays \ slang-shaders" @@ -31,14 +32,14 @@ LIBRETRO_CORES="2048-lr 81-lr a5200-lr atari800-lr beetle-gba-lr beetle-lynx-lr case "${DEVICE}" in AMD64) [ "${ENABLE_32BIT}" == "true" ] && EMUS_32BIT="lutris-wine" - PKG_EMUS+=" duckstation-sa dolphin-sa cemu-sa citra-sa melonds-sa minivmacsa mupen64plus-sa pcsx2-sa \ - primehack rpcs3-sa ryujinx-sa xemu-sa yuzu-sa" + PKG_EMUS+=" dolphin-sa cemu-sa citra-sa melonds-sa minivmacsa mupen64plus-sa pcsx2-sa primehack rpcs3-sa \ + ryujinx-sa xemu-sa yuzu-sa" LIBRETRO_CORES+=" beetle-psx-lr bsnes-hd-lr citra-lr desmume-lr dolphin-lr lrps2-lr mame-lr minivmac-lr \ play-lr" ;; RK3588) [ "${ENABLE_32BIT}" == "true" ] && EMUS_32BIT="box86 flycast-lr pcsx_rearmed-lr" - PKG_EMUS+=" aethersx2-sa duckstation-sa pcsx_rearmed-lr box64 yabasanshiro-sa" + PKG_EMUS+=" aethersx2-sa pcsx_rearmed-lr box64 yabasanshiro-sa" LIBRETRO_CORES+=" beetle-psx-lr bsnes-hd-lr citra-lr dolphin-lr mame-lr box64" PKG_RETROARCH+=" retropie-shaders" ;; @@ -50,7 +51,7 @@ case "${DEVICE}" in ;; S922X) [ "${ENABLE_32BIT}" == "true" ] && EMUS_32BIT="box86 flycast-lr pcsx_rearmed-lr" - PKG_EMUS+=" aethersx2-sa dolphin-sa drastic-sa duckstation-sa mupen64plus-sa yabasanshiro-sa box64" + PKG_EMUS+=" aethersx2-sa drastic-sa duckstation-sa mupen64plus-sa yabasanshiro-sa box64" LIBRETRO_CORES+=" beetle-psx-lr bsnes-hd-lr flycast-lr dolphin-lr yabasanshiro-sa" PKG_RETROARCH+=" retropie-shaders" esac