diff --git a/packages/games/emulators/dolphinsa/package.mk b/packages/games/emulators/dolphinsa/package.mk index 3de7bea1f..15fb73ab3 100755 --- a/packages/games/emulators/dolphinsa/package.mk +++ b/packages/games/emulators/dolphinsa/package.mk @@ -20,7 +20,7 @@ if [ "${OPENGLES_SUPPORT}" = yes ]; then fi if [ "${DISPLAYSERVER}" = "wl" ]; then - PKG_DEPENDS_TARGET+=" wayland ${WINDOWMANAGER}" + PKG_DEPENDS_TARGET+=" wayland ${WINDOWMANAGER} xorg-server xrandr libXi" PKG_CONFIGURE_OPTS_TARGET+=" -DENABLE_X11=ON" fi diff --git a/packages/games/emulators/duckstationsa/patches/handheld/000-fix-cmake.patch b/packages/games/emulators/duckstationsa/patches/handheld/000-fix-cmake.patch new file mode 100644 index 000000000..b67b4e7e4 --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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-a72") ++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -marm -mtune=cortex-a72") ++ 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/games/emulators/duckstationsa/patches/handheld/001-path-program.patch b/packages/games/emulators/duckstationsa/patches/handheld/001-path-program.patch new file mode 100644 index 000000000..8ba945eba --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/games/emulators/duckstationsa/patches/handheld/002-path-getdirectory.patch b/packages/games/emulators/duckstationsa/patches/handheld/002-path-getdirectory.patch new file mode 100644 index 000000000..8e99340b8 --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/games/emulators/duckstationsa/patches/handheld/003-path-language.patch b/packages/games/emulators/duckstationsa/patches/handheld/003-path-language.patch new file mode 100644 index 000000000..83c814630 --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/games/emulators/duckstationsa/patches/handheld/004-add-rotation.patch b/packages/games/emulators/duckstationsa/patches/handheld/004-add-rotation.patch new file mode 100644 index 000000000..ea2506f40 --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/games/emulators/duckstationsa/patches/handheld/005-add-hotkeys.patch b/packages/games/emulators/duckstationsa/patches/handheld/005-add-hotkeys.patch new file mode 100644 index 000000000..4ad1c30ac --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/games/emulators/duckstationsa/patches/handheld/006-maxbuttons.patch b/packages/games/emulators/duckstationsa/patches/handheld/006-maxbuttons.patch new file mode 100644 index 000000000..7d6082305 --- /dev/null +++ b/packages/games/emulators/duckstationsa/patches/handheld/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/x11/xserver/xorg-server/patches/xorg-server-100.03-render-fix-build-with-gcc12.patch b/packages/x11/xserver/xorg-server/patches/xorg-server-100.03-render-fix-build-with-gcc12.patch deleted file mode 100644 index 907c18bb7..000000000 --- a/packages/x11/xserver/xorg-server/patches/xorg-server-100.03-render-fix-build-with-gcc12.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 53173fdab492f0f638f6616fcf01af0b9ea6338d Mon Sep 17 00:00:00 2001 -From: Olivier Fourdan -Date: Thu, 20 Jan 2022 10:20:38 +0100 -Subject: [PATCH] render: Fix build with gcc 12 -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The xserver fails to compile with the latest gcc 12: - - render/picture.c: In function ‘CreateSolidPicture’: - render/picture.c:874:26: error: array subscript ‘union _SourcePict[0]’ is partly outside array bounds of ‘unsigned char[16]’ [-Werror=array-bounds] - 874 | pPicture->pSourcePict->type = SourcePictTypeSolidFill; - | ^~ - render/picture.c:868:45: note: object of size 16 allocated by ‘malloc’ - 868 | pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictSolidFill)); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - render/picture.c: In function ‘CreateLinearGradientPicture’: - render/picture.c:906:26: error: array subscript ‘union _SourcePict[0]’ is partly outside array bounds of ‘unsigned char[32]’ [-Werror=array-bounds] - 906 | pPicture->pSourcePict->linear.type = SourcePictTypeLinear; - | ^~ - render/picture.c:899:45: note: object of size 32 allocated by ‘malloc’ - 899 | pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictLinearGradient)); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - render/picture.c: In function ‘CreateConicalGradientPicture’: - render/picture.c:989:26: error: array subscript ‘union _SourcePict[0]’ is partly outside array bounds of ‘unsigned char[32]’ [-Werror=array-bounds] - 989 | pPicture->pSourcePict->conical.type = SourcePictTypeConical; - | ^~ - render/picture.c:982:45: note: object of size 32 allocated by ‘malloc’ - 982 | pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictConicalGradient)); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - cc1: some warnings being treated as errors - ninja: build stopped: subcommand failed. - -This is because gcc 12 has become stricter and raises a warning now. - -Fix the warning/error by allocating enough memory to store the union -struct. - -Signed-off-by: Olivier Fourdan -Acked-by: Michel Dänzer -Closes: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1256 -(cherry picked from commit c6b0dcb82d4db07a2f32c09a8c09c85a5f57248e) ---- - render/picture.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/render/picture.c b/render/picture.c -index afa0d258f..2be4b1954 100644 ---- a/render/picture.c -+++ b/render/picture.c -@@ -865,7 +865,7 @@ CreateSolidPicture(Picture pid, xRenderColor * color, int *error) - } - - pPicture->id = pid; -- pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictSolidFill)); -+ pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(SourcePict)); - if (!pPicture->pSourcePict) { - *error = BadAlloc; - free(pPicture); -@@ -896,7 +896,7 @@ CreateLinearGradientPicture(Picture pid, xPointFixed * p1, xPointFixed * p2, - } - - pPicture->id = pid; -- pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictLinearGradient)); -+ pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(SourcePict)); - if (!pPicture->pSourcePict) { - *error = BadAlloc; - free(pPicture); -@@ -936,7 +936,7 @@ CreateRadialGradientPicture(Picture pid, xPointFixed * inner, - } - - pPicture->id = pid; -- pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictRadialGradient)); -+ pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(SourcePict)); - if (!pPicture->pSourcePict) { - *error = BadAlloc; - free(pPicture); -@@ -979,7 +979,7 @@ CreateConicalGradientPicture(Picture pid, xPointFixed * center, xFixed angle, - } - - pPicture->id = pid; -- pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(PictConicalGradient)); -+ pPicture->pSourcePict = (SourcePictPtr) malloc(sizeof(SourcePict)); - if (!pPicture->pSourcePict) { - *error = BadAlloc; - free(pPicture); --- -GitLab -