From 8fb2c72ca1781279bd7a6d9e6f98d13e9587616b Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 17 Feb 2024 13:18:40 -0600 Subject: [PATCH 01/18] Update moonlight-common-c with RTSP encryption --- third_party/moonlight-common-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/moonlight-common-c b/third_party/moonlight-common-c index a517f7cb..ec171fd7 160000 --- a/third_party/moonlight-common-c +++ b/third_party/moonlight-common-c @@ -1 +1 @@ -Subproject commit a517f7cbcaf37ae0003979382d4e6348f37b8b2d +Subproject commit ec171fd7cab4cb8b7eb6416f1ad9ad62e339efb2 From 8125d2194bb1d441203cbb254dbb4a7998cb29e2 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 17 Feb 2024 13:23:06 -0600 Subject: [PATCH 02/18] Fix __builtin_cpu_supports(aes) on GCC 9 and earlier --- CMakeLists.txt | 5 +++++ src/util.c | 6 +----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2f0ae10..ffefef28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,6 +98,11 @@ if (HAVE_GETAUXVAL) list(APPEND MOONLIGHT_DEFINITIONS HAVE_GETAUXVAL) endif() +check_c_source_compiles("int main(void) { return __builtin_cpu_supports(\"aes\"); }" HAVE_BICS_AES) +if (HAVE_BICS_AES) + list(APPEND MOONLIGHT_DEFINITIONS HAVE_BICS_AES) +endif() + if (CEC_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC) list(APPEND MOONLIGHT_OPTIONS CEC) diff --git a/src/util.c b/src/util.c index cb90f195..f9dd8e3e 100644 --- a/src/util.c +++ b/src/util.c @@ -113,10 +113,6 @@ bool ensure_buf_size(void **buf, size_t *buf_size, size_t required_size) { } bool has_fast_aes() { -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - #if defined(HAVE_GETAUXVAL) && (defined(__arm__) || defined(__aarch64__)) #if defined(__arm__) && defined(HWCAP2_AES) return !!(getauxval(AT_HWCAP2) & HWCAP2_AES); @@ -125,7 +121,7 @@ bool has_fast_aes() { #else return false; #endif -#elif __has_builtin(__builtin_cpu_supports) && (defined(__i386__) || defined(__x86_64__)) +#elif defined(HAVE_BICS_AES) return __builtin_cpu_supports("aes"); #elif defined(__BUILTIN_CPU_SUPPORTS__) && defined(__powerpc__) return __builtin_cpu_supports("vcrypto"); From d89bd8d20f5f45de623512fcd192b2090df88032 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 17 Feb 2024 23:56:23 -0600 Subject: [PATCH 03/18] Update SDL_GameControllerDB --- third_party/SDL_GameControllerDB | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/SDL_GameControllerDB b/third_party/SDL_GameControllerDB index dbcf31a6..ae51c994 160000 --- a/third_party/SDL_GameControllerDB +++ b/third_party/SDL_GameControllerDB @@ -1 +1 @@ -Subproject commit dbcf31a6709ec8354b5963b1bb411721e07bd846 +Subproject commit ae51c9942f0d985b2161d6b22986f041fc98ce5c From b533c52edd5b63135ad90556ff45c7a4f98d1c93 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 00:18:41 -0600 Subject: [PATCH 04/18] Add missing CMake include --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ffefef28..4ac37273 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,12 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.6) project(moonlight-embedded VERSION 2.6.2 LANGUAGES C) SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") SET(CMAKE_C_STANDARD 99) include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake) include(${CMAKE_SOURCE_DIR}/cmake/generate_version_header.cmake) +include(CheckCSourceCompiles) + add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-pointer-sign -Wno-sign-compare -Wno-switch) aux_source_directory(./src SRC_LIST) From 3b1b2ab51dfcb155dc25ad078650c0ea367f6d94 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 00:25:53 -0600 Subject: [PATCH 05/18] Replace FindLibUUID.cmake with modified version from CMake project --- cmake/FindLibUUID.cmake | 122 +++++++++++++++++++++-------------- libgamestream/CMakeLists.txt | 4 +- 2 files changed, 76 insertions(+), 50 deletions(-) diff --git a/cmake/FindLibUUID.cmake b/cmake/FindLibUUID.cmake index ab564b77..7c2ad79e 100644 --- a/cmake/FindLibUUID.cmake +++ b/cmake/FindLibUUID.cmake @@ -1,51 +1,77 @@ -# - Try to find LIBUUID -# Find LIBUUID headers, libraries and the answer to all questions. +# CMake - Cross Platform Makefile Generator +# Copyright 2000-2024 Kitware, Inc. and Contributors +# All rights reserved. # -# LIBUUID_FOUND True if libuuid got found -# LIBUUID_INCLUDE_DIRS Location of libuuid headers -# LIBUUID_LIBRARIES List of libraries to use libuuid -# -# Copyright (c) 2008 Bjoern Ricks -# -# Redistribution and use is allowed according to the terms of the New -# BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# Distributed under the OSI-approved BSD 3-Clause License. See +# https://cmake.org/licensing for details. # +#[=======================================================================[.rst: +FindLibUUID +------------ + +Find LibUUID include directory and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +An :ref:`imported target ` named +``LibUUID::LibUUID`` is provided if LibUUID has been found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module defines the following variables: + +``LibUUID_FOUND`` + True if LibUUID was found, false otherwise. +``LibUUID_INCLUDE_DIRS`` + Include directories needed to include LibUUID headers. +``LibUUID_LIBRARIES`` + Libraries needed to link to LibUUID. + +Cache Variables +^^^^^^^^^^^^^^^ + +This module uses the following cache variables: + +``LibUUID_LIBRARY`` + The location of the LibUUID library file. +``LibUUID_INCLUDE_DIR`` + The location of the LibUUID include directory containing ``uuid/uuid.h``. + +The cache variables should not be used by project code. +They may be set by end users to point at LibUUID components. +#]=======================================================================] + +#----------------------------------------------------------------------------- +find_library(LibUUID_LIBRARY + NAMES uuid + ) +mark_as_advanced(LibUUID_LIBRARY) + +find_path(LibUUID_INCLUDE_DIR + NAMES uuid/uuid.h + ) +mark_as_advanced(LibUUID_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibUUID + FOUND_VAR LibUUID_FOUND + REQUIRED_VARS LibUUID_LIBRARY LibUUID_INCLUDE_DIR + ) +set(LIBUUID_FOUND ${LibUUID_FOUND}) -INCLUDE( FindPkgConfig ) - -IF ( LibUuid_FIND_REQUIRED ) - SET( _pkgconfig_REQUIRED "REQUIRED" ) -ELSE( LibUuid_FIND_REQUIRED ) - SET( _pkgconfig_REQUIRED "" ) -ENDIF ( LibUuid_FIND_REQUIRED ) - -IF ( LIBUUID_MIN_VERSION ) - PKG_SEARCH_MODULE( LIBUUID ${_pkgconfig_REQUIRED} uuid>=${LIBUUID_MIN_VERSION} ) -ELSE ( LIBUUID_MIN_VERSION ) - PKG_SEARCH_MODULE( LIBUUID ${_pkgconfig_REQUIRED} uuid ) -ENDIF ( LIBUUID_MIN_VERSION ) - - -IF( NOT LIBUUID_FOUND AND NOT PKG_CONFIG_FOUND ) - FIND_PATH( LIBUUID_INCLUDE_DIRS uuid/uuid.h ) - FIND_LIBRARY( LIBUUID_LIBRARIES uuid) - - # Report results - IF ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS ) - SET( LIBUUID_FOUND 1 ) - IF ( NOT LIBUUID_FIND_QUIETLY ) - MESSAGE( STATUS "Found libuuid: ${LIBUUID_LIBRARIES}" ) - ENDIF ( NOT LIBUUID_FIND_QUIETLY ) - ELSE ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS ) - IF ( LIBUUID_FIND_REQUIRED ) - MESSAGE( SEND_ERROR "Could NOT find libuuid" ) - ELSE ( LIBUUID_FIND_REQUIRED ) - IF ( NOT LIBUUID_FIND_QUIETLY ) - MESSAGE( STATUS "Could NOT find libuuid" ) - ENDIF ( NOT LIBUUID_FIND_QUIETLY ) - ENDIF ( LIBUUID_FIND_REQUIRED ) - ENDIF ( LIBUUID_LIBRARIES AND LIBUUID_INCLUDE_DIRS ) -ENDIF( NOT LIBUUID_FOUND AND NOT PKG_CONFIG_FOUND ) - -MARK_AS_ADVANCED( LIBUUID_LIBRARIES LIBUUID_INCLUDE_DIRS ) +#----------------------------------------------------------------------------- +# Provide documented result variables and targets. +if(LibUUID_FOUND) + set(LibUUID_INCLUDE_DIRS ${LibUUID_INCLUDE_DIR}) + set(LibUUID_LIBRARIES ${LibUUID_LIBRARY}) + if(NOT TARGET LibUUID::LibUUID) + add_library(LibUUID::LibUUID UNKNOWN IMPORTED) + set_target_properties(LibUUID::LibUUID PROPERTIES + IMPORTED_LOCATION "${LibUUID_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LibUUID_INCLUDE_DIRS}" + ) + endif() +endif() diff --git a/libgamestream/CMakeLists.txt b/libgamestream/CMakeLists.txt index 72776f1d..3b026ded 100644 --- a/libgamestream/CMakeLists.txt +++ b/libgamestream/CMakeLists.txt @@ -23,9 +23,9 @@ target_link_libraries(gamestream moonlight-common) set_target_properties(gamestream PROPERTIES SOVERSION ${SO_VERSION} VERSION ${PROJECT_VERSION}) set_target_properties(moonlight-common PROPERTIES SOVERSION ${SO_VERSION} VERSION ${PROJECT_VERSION}) -target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c/src ../third_party/h264bitstream ${AVAHI_INCLUDE_DIRS} ${LIBUUID_INCLUDE_DIRS}) +target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c/src ../third_party/h264bitstream ${AVAHI_INCLUDE_DIRS} ${LibUUID_INCLUDE_DIRS}) target_include_directories(moonlight-common PRIVATE ../third_party/moonlight-common-c/reedsolomon ../third_party/moonlight-common-c/enet/include) -target_link_libraries(gamestream ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${LIBUUID_LIBRARIES}) +target_link_libraries(gamestream ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${LibUUID_LIBRARIES}) target_link_libraries(gamestream ${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS}) From ca4c517510d64870f8759330c8a6012572af64e3 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 00:48:26 -0600 Subject: [PATCH 06/18] Update moonlight-common-c --- third_party/moonlight-common-c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/moonlight-common-c b/third_party/moonlight-common-c index ec171fd7..8af4562a 160000 --- a/third_party/moonlight-common-c +++ b/third_party/moonlight-common-c @@ -1 +1 @@ -Subproject commit ec171fd7cab4cb8b7eb6416f1ad9ad62e339efb2 +Subproject commit 8af4562af672dd6b9ed28553ead172984fd9a683 From a9d6f17d5e104d33e4da64919e3ff2fd557caffd Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 14:30:59 -0600 Subject: [PATCH 07/18] Replace ioctl() retry loops with drmIoctl() --- src/video/rk.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/video/rk.c b/src/video/rk.c index 6caf75c7..b013c3df 100644 --- a/src/video/rk.c +++ b/src/video/rk.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -248,9 +247,7 @@ void *frame_thread(void *param) { dmcd.bpp = 8; // hor_stride is already adjusted for 10 vs 8 bit dmcd.width = hor_stride; dmcd.height = ver_stride * 2; // documentation say not v*2/3 but v*2 (additional info included) - do { - ret = ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd); assert(!ret); assert(dmcd.pitch == dmcd.width); assert(dmcd.size == dmcd.pitch * dmcd.height); @@ -260,9 +257,7 @@ void *frame_thread(void *param) { struct drm_prime_handle dph = {0}; dph.handle = dmcd.handle; dph.fd = -1; - do { - ret = ioctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph); assert(!ret); MppBufferInfo info = {0}; info.type = MPP_BUFFER_TYPE_DRM; @@ -587,9 +582,7 @@ void rk_cleanup() { assert(!ret); struct drm_mode_destroy_dumb dmdd = {0}; dmdd.handle = frame_to_drm[i].handle; - do { - ret = ioctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd); - } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); + ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd); assert(!ret); } } From d6c9650a32c9549a4f22b572e9d21ebbb5d0d2d0 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 14:48:13 -0600 Subject: [PATCH 08/18] Add rotation support for Rockchip Fixes #878 --- src/main.c | 2 +- src/video/rk.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index d2744b73..ac210828 100644 --- a/src/main.c +++ b/src/main.c @@ -195,7 +195,7 @@ static void help() { printf("\t-4k\t\t\tUse 3840x2160 resolution\n"); printf("\t-width \t\tHorizontal resolution (default 1280)\n"); printf("\t-height \tVertical resolution (default 720)\n"); - #if defined(HAVE_PI) | defined(HAVE_MMAL) + #ifdef HAVE_EMBEDDED printf("\t-rotate \tRotate display: 0/90/180/270 (default 0)\n"); #endif printf("\t-fps \t\tSpecify the fps to use (default 60)\n"); diff --git a/src/video/rk.c b/src/video/rk.c index b013c3df..b38fd43b 100644 --- a/src/video/rk.c +++ b/src/video/rk.c @@ -502,6 +502,24 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte } assert(plane_id); + // DRM defines rotation in degrees counter-clockwise while we define + // rotation in degrees clockwise, so we swap the 90 and 270 cases + int displayRotation = drFlags & DISPLAY_ROTATE_MASK; + switch (displayRotation) { + case DISPLAY_ROTATE_90: + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_270); + break; + case DISPLAY_ROTATE_180: + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_180); + break; + case DISPLAY_ROTATE_270: + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_90); + break; + default: + set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "rotation", DRM_MODE_ROTATE_0); + break; + } + // hide cursor by move in left lower corner drmModeMoveCursor(fd, crtc_id, 0, crtc_height); From fc904d2dac36b265e028962d2414852b90aa3f6f Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 18 Feb 2024 14:56:57 -0600 Subject: [PATCH 09/18] Treat devices as gamepads if they have a hat instead of an analog stick Fixes #880 --- src/input/evdev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index ea302a45..1f567b26 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -836,8 +836,10 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose, in libevdev_has_event_code(evdev, EV_ABS, ABS_RZ))) && !libevdev_has_event_type(evdev, EV_KEY); bool is_gamepad = - libevdev_has_event_code(evdev, EV_ABS, ABS_X) && - libevdev_has_event_code(evdev, EV_ABS, ABS_Y) && + ((libevdev_has_event_code(evdev, EV_ABS, ABS_X) && + libevdev_has_event_code(evdev, EV_ABS, ABS_Y)) || + (libevdev_has_event_code(evdev, EV_ABS, ABS_HAT0X) && + libevdev_has_event_code(evdev, EV_ABS, ABS_HAT0Y))) && (libevdev_has_event_code(evdev, EV_KEY, BTN_TRIGGER) || libevdev_has_event_code(evdev, EV_KEY, BTN_A) || libevdev_has_event_code(evdev, EV_KEY, BTN_1) || From 2f03600baeca7f24a04a61803a8833fc7e7d23db Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 15:45:17 -0600 Subject: [PATCH 10/18] Ignore CRCs in SDL mappings --- src/input/mapping.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/input/mapping.c b/src/input/mapping.c index d5549065..232943ee 100644 --- a/src/input/mapping.c +++ b/src/input/mapping.c @@ -152,6 +152,8 @@ struct mapping* mapping_parse(char* mapping) { map->hat_dpdown = int_value; map->hat_dir_dpdown = direction_value; } + } else if (strcmp("crc", key) == 0) { + /* CRC is not supported */ } else fprintf(stderr, "Can't map (%s)\n", option); } else if (ret == 0 && option[0] != '\n') From 454f67b0ed94c563bbb1963f43e756ac4c64900e Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 15:56:32 -0600 Subject: [PATCH 11/18] Move CPU detection code into a separate file --- src/config.c | 19 +++----- src/cpu.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/cpu.h | 21 +++++++++ src/util.c | 81 ---------------------------------- 4 files changed, 147 insertions(+), 94 deletions(-) create mode 100644 src/cpu.c create mode 100644 src/cpu.h diff --git a/src/config.c b/src/config.c index 8bd8d2af..c6ff242a 100644 --- a/src/config.c +++ b/src/config.c @@ -20,6 +20,7 @@ #include "platform.h" #include "config.h" #include "util.h" +#include "cpu.h" #include "input/evdev.h" #include "audio/audio.h" @@ -353,23 +354,15 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) { if (has_fast_aes()) { config->stream.encryptionFlags = ENCFLG_ALL; } + else if (has_slow_aes()) { + // For extremely slow CPUs, opt out of audio encryption + config->stream.encryptionFlags = ENCFLG_NONE; + printf("Disabling encryption on low performance CPU\n"); + } else { config->stream.encryptionFlags = ENCFLG_AUDIO; } -#ifdef __arm__ - char cpuinfo[4096] = {}; - if (read_file("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo) - 1) > 0) { - // If this is a ARMv6 CPU (like the Pi 1), we'll assume it's not - // powerful enough to handle audio encryption. The Pi 1 could - // barely handle Opus decoding alone. - if (strstr(cpuinfo, "ARMv6")) { - config->stream.encryptionFlags = ENCFLG_NONE; - printf("Disabling encryption on low performance CPU\n"); - } - } -#endif - config->debug_level = 0; config->platform = "auto"; config->app = "Steam"; diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 00000000..914ceaf0 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,120 @@ +/* + * This file is part of Moonlight Embedded. + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include "cpu.h" +#include "util.h" + +#include +#include +#include + +#ifdef HAVE_GETAUXVAL +#include + +#ifndef HWCAP2_AES +#define HWCAP2_AES (1 << 0) +#endif +#endif + +#if defined(__linux__) && defined(__riscv) +#if __has_include() +#include +#else +#include + +#if __has_include() +#include +#include +#else +#define __NR_riscv_hwprobe 258 +struct riscv_hwprobe { + int64_t key; + uint64_t value; +}; +#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 +#endif + +// RISC-V Scalar AES [E]ncryption and [D]ecryption +#ifndef RISCV_HWPROBE_EXT_ZKND +#define RISCV_HWPROBE_EXT_ZKND (1 << 11) +#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) +#endif + +// RISC-V Vector AES +#ifndef RISCV_HWPROBE_EXT_ZVKNED +#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) +#endif + +static int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, + unsigned int flags) +{ + return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags); +} + +#endif +#endif + +bool has_fast_aes() { +#if defined(HAVE_GETAUXVAL) && (defined(__arm__) || defined(__aarch64__)) + #if defined(__arm__) && defined(HWCAP2_AES) + return !!(getauxval(AT_HWCAP2) & HWCAP2_AES); + #elif defined(__aarch64__) + return !!(getauxval(AT_HWCAP) & HWCAP_AES); + #else + return false; + #endif +#elif defined(HAVE_BICS_AES) + return __builtin_cpu_supports("aes"); +#elif defined(__BUILTIN_CPU_SUPPORTS__) && defined(__powerpc__) + return __builtin_cpu_supports("vcrypto"); +#elif defined(__linux__) && defined(__riscv) + struct riscv_hwprobe pairs[1] = { + { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 }, + }; + + // If this syscall is not implemented, we'll get -ENOSYS + // and the value field will remain zero. + __riscv_hwprobe(pairs, sizeof(pairs) / sizeof(struct riscv_hwprobe), 0, NULL, 0); + + return (pairs[0].value & (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND)) == + (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND) || + (pairs[0].value & RISCV_HWPROBE_EXT_ZVKNED); +#elif __SIZEOF_SIZE_T__ == 4 + #warning Unknown 32-bit platform. Assuming AES is slow on this CPU. + return false; +#else + #warning Unknown 64-bit platform. Assuming AES is fast on this CPU. + return true; +#endif +} + +bool has_slow_aes() { +#ifdef __arm__ + char cpuinfo[4096] = {}; + if (read_file("/proc/cpuinfo", cpuinfo, sizeof(cpuinfo) - 1) > 0) { + // If this is a ARMv6 CPU (like the Pi 1), we'll assume it's not + // powerful enough to handle audio encryption. The Pi 1 could + // barely handle Opus decoding alone. + if (strstr(cpuinfo, "ARMv6")) { + return true; + } + } +#endif + + return false; +} \ No newline at end of file diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 00000000..8e00ba6d --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,21 @@ +/* + * This file is part of Moonlight Embedded. + * + * Moonlight is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Moonlight is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Moonlight; if not, see . + */ + +#include + +bool has_fast_aes(void); +bool has_slow_aes(void); diff --git a/src/util.c b/src/util.c index f9dd8e3e..04c4b965 100644 --- a/src/util.c +++ b/src/util.c @@ -26,53 +26,6 @@ #include #include -#ifdef HAVE_GETAUXVAL -#include - -#ifndef HWCAP2_AES -#define HWCAP2_AES (1 << 0) -#endif -#endif - -#if defined(__linux__) && defined(__riscv) -#if __has_include() -#include -#else -#include - -#if __has_include() -#include -#include -#else -#define __NR_riscv_hwprobe 258 -struct riscv_hwprobe { - int64_t key; - uint64_t value; -}; -#define RISCV_HWPROBE_KEY_IMA_EXT_0 4 -#endif - -// RISC-V Scalar AES [E]ncryption and [D]ecryption -#ifndef RISCV_HWPROBE_EXT_ZKND -#define RISCV_HWPROBE_EXT_ZKND (1 << 11) -#define RISCV_HWPROBE_EXT_ZKNE (1 << 12) -#endif - -// RISC-V Vector AES -#ifndef RISCV_HWPROBE_EXT_ZVKNED -#define RISCV_HWPROBE_EXT_ZVKNED (1 << 21) -#endif - -static int __riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, - unsigned int flags) -{ - return syscall(__NR_riscv_hwprobe, pairs, pair_count, cpu_count, cpus, flags); -} - -#endif -#endif - int write_bool(char *path, bool val) { int fd = open(path, O_RDWR); @@ -111,37 +64,3 @@ bool ensure_buf_size(void **buf, size_t *buf_size, size_t required_size) { return true; } - -bool has_fast_aes() { -#if defined(HAVE_GETAUXVAL) && (defined(__arm__) || defined(__aarch64__)) - #if defined(__arm__) && defined(HWCAP2_AES) - return !!(getauxval(AT_HWCAP2) & HWCAP2_AES); - #elif defined(__aarch64__) - return !!(getauxval(AT_HWCAP) & HWCAP_AES); - #else - return false; - #endif -#elif defined(HAVE_BICS_AES) - return __builtin_cpu_supports("aes"); -#elif defined(__BUILTIN_CPU_SUPPORTS__) && defined(__powerpc__) - return __builtin_cpu_supports("vcrypto"); -#elif defined(__linux__) && defined(__riscv) - struct riscv_hwprobe pairs[1] = { - { RISCV_HWPROBE_KEY_IMA_EXT_0, 0 }, - }; - - // If this syscall is not implemented, we'll get -ENOSYS - // and the value field will remain zero. - __riscv_hwprobe(pairs, sizeof(pairs) / sizeof(struct riscv_hwprobe), 0, NULL, 0); - - return (pairs[0].value & (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND)) == - (RISCV_HWPROBE_EXT_ZKNE | RISCV_HWPROBE_EXT_ZKND) || - (pairs[0].value & RISCV_HWPROBE_EXT_ZVKNED); -#elif __SIZEOF_SIZE_T__ == 4 - #warning Unknown 32-bit platform. Assuming AES is slow on this CPU. - return false; -#else - #warning Unknown 64-bit platform. Assuming AES is fast on this CPU. - return true; -#endif -} \ No newline at end of file From 55b49221d837db2ef8a956f1be0b96803bd3001d Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 15:58:32 -0600 Subject: [PATCH 12/18] Link util.c into the platform libraries --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ac37273..e677c3e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ endif() if(AMLOGIC_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_AML) list(APPEND MOONLIGHT_OPTIONS AML) - add_library(moonlight-aml SHARED ./src/video/aml.c ${ILCLIENT_SRC_LIST}) + add_library(moonlight-aml SHARED ./src/video/aml.c ./src/util.c ${ILCLIENT_SRC_LIST}) target_include_directories(moonlight-aml PRIVATE ${AMLOGIC_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR}) target_link_libraries(moonlight-aml gamestream ${AMLOGIC_LIBRARIES}) set_property(TARGET moonlight-aml PROPERTY COMPILE_DEFINITIONS ${AMLOGIC_DEFINITIONS}) @@ -127,7 +127,7 @@ if(BROADCOM-OMX_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_PI) list(APPEND MOONLIGHT_OPTIONS PI) aux_source_directory(./third_party/ilclient ILCLIENT_SRC_LIST) - add_library(moonlight-pi SHARED ./src/video/pi.c ./src/audio/omx.c ${ILCLIENT_SRC_LIST}) + add_library(moonlight-pi SHARED ./src/video/pi.c ./src/audio/omx.c ./src/util.c ${ILCLIENT_SRC_LIST}) target_include_directories(moonlight-pi PRIVATE ./third_party/ilclient ${BROADCOM_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR} ${OPUS_INCLUDE_DIRS}) target_link_libraries(moonlight-pi gamestream ${BROADCOM_OMX_LIBRARIES} ${OPUS_LIBRARY}) set_property(TARGET moonlight-pi PROPERTY COMPILE_DEFINITIONS ${BROADCOM_OMX_DEFINITIONS}) @@ -137,7 +137,7 @@ endif() if(MMAL_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_MMAL) list(APPEND MOONLIGHT_OPTIONS MMAL) - add_library(moonlight-mmal SHARED ./src/video/mmal.c) + add_library(moonlight-mmal SHARED ./src/video/mmal.c ./src/util.c) target_include_directories(moonlight-mmal PRIVATE ${MMAL_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR}) target_link_libraries(moonlight-mmal gamestream ${MMAL_LINK_LIBRARIES}) install(TARGETS moonlight-mmal DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -146,7 +146,7 @@ endif() if(FREESCALE_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_IMX) list(APPEND MOONLIGHT_OPTIONS IMX) - add_library(moonlight-imx SHARED ./src/video/imx.c ./src/video/imx_vpu.c) + add_library(moonlight-imx SHARED ./src/video/imx.c ./src/video/imx_vpu.c ./src/util.c) target_include_directories(moonlight-imx PRIVATE ${FREESCALE_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR}) target_link_libraries(moonlight-imx gamestream ${FREESCALE_LIBRARIES}) install(TARGETS moonlight-imx DESTINATION ${CMAKE_INSTALL_LIBDIR}) @@ -155,7 +155,7 @@ endif() if(ROCKCHIP_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_ROCKCHIP) list(APPEND MOONLIGHT_OPTIONS ROCKCHIP) - add_library(moonlight-rk SHARED ./src/video/rk.c) + add_library(moonlight-rk SHARED ./src/video/rk.c ./src/util.c) target_include_directories(moonlight-rk PRIVATE ${ROCKCHIP_INCLUDE_DIRS} ${GAMESTREAM_INCLUDE_DIR} ${MOONLIGHT_COMMON_INCLUDE_DIR}) target_link_libraries(moonlight-rk gamestream ${ROCKCHIP_LIBRARIES}) set_property(TARGET moonlight-rk PROPERTY COMPILE_DEFINITIONS ${ROCKCHIP_DEFINITIONS}) From 883498d6424142a2942069d468b4fe780b3c1f96 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 16:16:02 -0600 Subject: [PATCH 13/18] Replace SDL key handling with Moonlight Qt code The existing code had a bunch of incorrectly mapped keys and was using keysym instead of scancode which causes issues with non-US keyboards. --- src/input/sdl.c | 284 ++++++++++++++++++++++++++++++++++++++++-------- src/input/sdl.h | 77 ------------- 2 files changed, 239 insertions(+), 122 deletions(-) diff --git a/src/input/sdl.c b/src/input/sdl.c index 9f4f5686..72a2a3ee 100644 --- a/src/input/sdl.c +++ b/src/input/sdl.c @@ -59,11 +59,232 @@ typedef struct _GAMEPAD_STATE { static GAMEPAD_STATE gamepads[MAX_GAMEPADS]; -static int keyboard_modifiers; static int activeGamepadMask = 0; int sdl_gamepads = 0; +#define VK_0 0x30 +#define VK_A 0x41 + +// These are real Windows VK_* codes +#ifndef VK_F1 +#define VK_F1 0x70 +#define VK_F13 0x7C +#define VK_NUMPAD0 0x60 +#endif + +int vk_for_sdl_scancode(SDL_Scancode scancode) { + // Set keycode. We explicitly use scancode here because GFE will try to correct + // for AZERTY layouts on the host but it depends on receiving VK_ values matching + // a QWERTY layout to work. + if (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_9) { + // SDL defines SDL_SCANCODE_0 > SDL_SCANCODE_9, so we need to handle that manually + return (scancode - SDL_SCANCODE_1) + VK_0 + 1; + } + else if (scancode >= SDL_SCANCODE_A && scancode <= SDL_SCANCODE_Z) { + return (scancode - SDL_SCANCODE_A) + VK_A; + } + else if (scancode >= SDL_SCANCODE_F1 && scancode <= SDL_SCANCODE_F12) { + return (scancode - SDL_SCANCODE_F1) + VK_F1; + } + else if (scancode >= SDL_SCANCODE_F13 && scancode <= SDL_SCANCODE_F24) { + return (scancode - SDL_SCANCODE_F13) + VK_F13; + } + else if (scancode >= SDL_SCANCODE_KP_1 && scancode <= SDL_SCANCODE_KP_9) { + // SDL defines SDL_SCANCODE_KP_0 > SDL_SCANCODE_KP_9, so we need to handle that manually + return (scancode - SDL_SCANCODE_KP_1) + VK_NUMPAD0 + 1; + } + else { + switch (scancode) { + case SDL_SCANCODE_BACKSPACE: + return 0x08; + + case SDL_SCANCODE_TAB: + return 0x09; + + case SDL_SCANCODE_CLEAR: + return 0x0C; + + case SDL_SCANCODE_KP_ENTER: + case SDL_SCANCODE_RETURN: + return 0x0D; + + case SDL_SCANCODE_PAUSE: + return 0x13; + + case SDL_SCANCODE_CAPSLOCK: + return 0x14; + + case SDL_SCANCODE_ESCAPE: + return 0x1B; + + case SDL_SCANCODE_SPACE: + return 0x20; + + case SDL_SCANCODE_PAGEUP: + return 0x21; + + case SDL_SCANCODE_PAGEDOWN: + return 0x22; + + case SDL_SCANCODE_END: + return 0x23; + + case SDL_SCANCODE_HOME: + return 0x24; + + case SDL_SCANCODE_LEFT: + return 0x25; + + case SDL_SCANCODE_UP: + return 0x26; + + case SDL_SCANCODE_RIGHT: + return 0x27; + + case SDL_SCANCODE_DOWN: + return 0x28; + + case SDL_SCANCODE_SELECT: + return 0x29; + + case SDL_SCANCODE_EXECUTE: + return 0x2B; + + case SDL_SCANCODE_PRINTSCREEN: + return 0x2C; + + case SDL_SCANCODE_INSERT: + return 0x2D; + + case SDL_SCANCODE_DELETE: + return 0x2E; + + case SDL_SCANCODE_HELP: + return 0x2F; + + case SDL_SCANCODE_KP_0: + // See comment above about why we only handle SDL_SCANCODE_KP_0 here + return VK_NUMPAD0; + + case SDL_SCANCODE_0: + // See comment above about why we only handle SDL_SCANCODE_0 here + return VK_0; + + case SDL_SCANCODE_KP_MULTIPLY: + return 0x6A; + + case SDL_SCANCODE_KP_PLUS: + return 0x6B; + + case SDL_SCANCODE_KP_COMMA: + return 0x6C; + + case SDL_SCANCODE_KP_MINUS: + return 0x6D; + + case SDL_SCANCODE_KP_PERIOD: + return 0x6E; + + case SDL_SCANCODE_KP_DIVIDE: + return 0x6F; + + case SDL_SCANCODE_NUMLOCKCLEAR: + return 0x90; + + case SDL_SCANCODE_SCROLLLOCK: + return 0x91; + + case SDL_SCANCODE_LSHIFT: + return 0xA0; + + case SDL_SCANCODE_RSHIFT: + return 0xA1; + + case SDL_SCANCODE_LCTRL: + return 0xA2; + + case SDL_SCANCODE_RCTRL: + return 0xA3; + + case SDL_SCANCODE_LALT: + return 0xA4; + + case SDL_SCANCODE_RALT: + return 0xA5; + + case SDL_SCANCODE_LGUI: + return 0x5B; + + case SDL_SCANCODE_RGUI: + return 0x5C; + + case SDL_SCANCODE_APPLICATION: + return 0x5D; + + case SDL_SCANCODE_AC_BACK: + return 0xA6; + + case SDL_SCANCODE_AC_FORWARD: + return 0xA7; + + case SDL_SCANCODE_AC_REFRESH: + return 0xA8; + + case SDL_SCANCODE_AC_STOP: + return 0xA9; + + case SDL_SCANCODE_AC_SEARCH: + return 0xAA; + + case SDL_SCANCODE_AC_BOOKMARKS: + return 0xAB; + + case SDL_SCANCODE_AC_HOME: + return 0xAC; + + case SDL_SCANCODE_SEMICOLON: + return 0xBA; + + case SDL_SCANCODE_EQUALS: + return 0xBB; + + case SDL_SCANCODE_COMMA: + return 0xBC; + + case SDL_SCANCODE_MINUS: + return 0xBD; + + case SDL_SCANCODE_PERIOD: + return 0xBE; + + case SDL_SCANCODE_SLASH: + return 0xBF; + + case SDL_SCANCODE_GRAVE: + return 0xC0; + + case SDL_SCANCODE_LEFTBRACKET: + return 0xDB; + + case SDL_SCANCODE_BACKSLASH: + return 0xDC; + + case SDL_SCANCODE_RIGHTBRACKET: + return 0xDD; + + case SDL_SCANCODE_APOSTROPHE: + return 0xDE; + + case SDL_SCANCODE_NONUSBACKSLASH: + return 0xE2; + + default: + return 0; + } + } +} + static void send_controller_arrival(PGAMEPAD_STATE state) { #if SDL_VERSION_ATLEAST(2, 0, 18) unsigned int supportedButtonFlags = 0; @@ -274,57 +495,30 @@ int sdlinput_handle_event(SDL_Window* window, SDL_Event* event) { return 0; case SDL_KEYDOWN: case SDL_KEYUP: - button = event->key.keysym.sym; - if (button >= 0x21 && button <= 0x2f) - button = keyCodes1[button - 0x21]; - else if (button >= 0x3a && button <= 0x40) - button = keyCodes2[button - 0x3a]; - else if (button >= 0x5b && button <= 0x60) - button = keyCodes3[button - 0x5b]; - else if (button >= 0x40000039 && button < 0x40000039 + sizeof(keyCodes4)) - button = keyCodes4[button - 0x40000039]; - else if (button >= 0x400000E0 && button <= 0x400000E7) - button = keyCodes5[button - 0x400000E0]; - else if (button >= 0x61 && button <= 0x7a) - button -= 0x20; - else if (button == 0x7f) - button = 0x2e; - - int modifier = 0; - switch (event->key.keysym.sym) { - case SDLK_RSHIFT: - case SDLK_LSHIFT: - modifier = MODIFIER_SHIFT; - break; - case SDLK_RALT: - case SDLK_LALT: - modifier = MODIFIER_ALT; - break; - case SDLK_RCTRL: - case SDLK_LCTRL: - modifier = MODIFIER_CTRL; - break; - case SDLK_RGUI: - case SDLK_LGUI: - modifier = MODIFIER_META; - break; - } + button = vk_for_sdl_scancode(event->key.keysym.scancode); - if (modifier != 0) { - if (event->type==SDL_KEYDOWN) - keyboard_modifiers |= modifier; - else - keyboard_modifiers &= ~modifier; + int modifiers = 0; + if (event->key.keysym.mod & KMOD_CTRL) { + modifiers |= MODIFIER_CTRL; + } + if (event->key.keysym.mod & KMOD_ALT) { + modifiers |= MODIFIER_ALT; + } + if (event->key.keysym.mod & KMOD_SHIFT) { + modifiers |= MODIFIER_SHIFT; + } + if (event->key.keysym.mod & KMOD_GUI) { + modifiers |= MODIFIER_META; } - LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, keyboard_modifiers); + LiSendKeyboardEvent(0x80 << 8 | button, event->type==SDL_KEYDOWN?KEY_ACTION_DOWN:KEY_ACTION_UP, modifiers); // Quit the stream if all the required quit keys are down - if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP) + if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == QUIT_KEY && event->type==SDL_KEYUP) return SDL_QUIT_APPLICATION; - else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP) + else if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == FULLSCREEN_KEY && event->type==SDL_KEYUP) return SDL_TOGGLE_FULLSCREEN; - else if ((keyboard_modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_KEY && event->type==SDL_KEYUP) + else if ((modifiers & ACTION_MODIFIERS) == ACTION_MODIFIERS && event->key.keysym.sym == UNGRAB_KEY && event->type==SDL_KEYUP) return SDL_GetRelativeMouseMode() ? SDL_MOUSE_UNGRAB : SDL_MOUSE_GRAB; break; case SDL_FINGERDOWN: diff --git a/src/input/sdl.h b/src/input/sdl.h index 6928e355..ef0abde2 100644 --- a/src/input/sdl.h +++ b/src/input/sdl.h @@ -22,83 +22,6 @@ extern int sdl_gamepads; -static const short keyCodes1[] = { - 0, //SDLK_EXCLAIM - 0, //SDLK_QUOTEDBL - 0, //SDLK_HASH - 0, //SDLK_DOLLAR - 0, //SDLK_PERCENT - 0, //SDLK_AMPERSAND - 0xDE, //SDLK_QUOTE - 0, //SDLK_LEFTPAREN - 0, //SDLK_RIGHTPAREN - 0, //SDLK_ASTERISK - 0, //SDLK_PLUS - 0xBC, //SDLK_COMMA - 0xBD, //SDLK_MINUS - 0xBE, //SDLK_PERIOD - 0xBF, //SDLK_SLASH -}; - -static const short keyCodes2[] = { - 0, //SDLK_COLON - 0xBA, //SDLK_SEMICOLON - 0, //SDLK_LESS - 0xBB, //SDLK_EQUALS - 0, //SDLK_GREATER - 0, //SDLK_QUESTION - 0, //SDLK_AT -}; - -static const short keyCodes3[] = { - 0xDB, //SDLK_LEFTBRACKET - 0xDC, //SDLK_BACKSLASH - 0xDD, //SDLK_RIGHTBRACKET - 0, //SDLK_CARET - 0, //SDLK_UNDERSCORE - 0xC0, //SDLK_BACKQUOTE -}; - -static const short keyCodes4[] = { - 0x14, //SDLK_CAPSLOCK - 0x70, //SDLK_F1 - 0x71, //SDLK_F2 - 0x72, //SDLK_F3 - 0x73, //SDLK_F4 - 0x74, //SDLK_F5 - 0x75, //SDLK_F6 - 0x76, //SDLK_F7 - 0x77, //SDLK_F8 - 0x78, //SDLK_F9 - 0x79, //SDLK_F10 - 0x7A, //SDLK_F11 - 0x7B, //SDLK_F12 - 0, //SDLK_PRINTSCREEN - 0x91, //SDLK_SCROLLLOCK - 0x13, //SDLK_PAUSE - 0x2D, //SDLK_INSERT - 0x24, //SDLK_HOME - 0x21, //SDLK_PAGEUP - 0, //Not used - 0x23, //SDLK_END - 0x22, //SDLK_PAGEDOWN - 0x27, //SDLK_RIGHT - 0x25, //SDLK_LEFT - 0x28, //SDLK_DOWN - 0x26, //SDLK_UP -}; - -static const short keyCodes5[] = { - 0xA2, //SDLK_LCTRL - 0xA0, //SDLK_LSHIFT - 0xA4, //SDLK_LALT - 0x5B, //SDLK_LGUI - 0xA3, //SDLK_RCTRL - 0xA1, //SDLK_RSHIFT - 0xA5, //SDLK_RALT - 0x5C, //SDLK_RGUI -}; - void sdlinput_init(char* mappings); int sdlinput_handle_event(SDL_Window* window, SDL_Event* event); void sdlinput_rumble(unsigned short controller_id, unsigned short low_freq_motor, unsigned short high_freq_motor); From 0e1228231151a9e3a13e939c6f32fc60c9bd46a7 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 20:49:25 -0600 Subject: [PATCH 14/18] Remove a bunch of useless asserts --- src/video/rk.c | 53 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 36 deletions(-) diff --git a/src/video/rk.c b/src/video/rk.c index b38fd43b..2e04a9f8 100644 --- a/src/video/rk.c +++ b/src/video/rk.c @@ -158,22 +158,18 @@ void *display_thread(void *param) { while (!frm_eos) { int _fb_id; - ret = pthread_mutex_lock(&mutex); - assert(!ret); + pthread_mutex_lock(&mutex); while (fb_id == 0) { pthread_cond_wait(&cond, &mutex); - assert(!ret); if (fb_id == 0 && frm_eos) { - ret = pthread_mutex_unlock(&mutex); - assert(!ret); + pthread_mutex_unlock(&mutex); return NULL; } } _fb_id = fb_id; fb_id = 0; - ret = pthread_mutex_unlock(&mutex); - assert(!ret); + pthread_mutex_unlock(&mutex); if (atomic) { // We may need to modeset to apply colorspace changes when toggling HDR @@ -313,14 +309,10 @@ void *frame_thread(void *param) { } assert(i != MAX_FRAMES); // send DRM FB to display thread - ret = pthread_mutex_lock(&mutex); - assert(!ret); + pthread_mutex_lock(&mutex); fb_id = frame_to_drm[i].fb_id; - ret = pthread_cond_signal(&cond); - assert(!ret); - ret = pthread_mutex_unlock(&mutex); - assert(!ret); - + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); } else { fprintf(stderr, "Frame no buff\n"); } @@ -551,15 +543,11 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte ret = mpi_api->control(mpi_ctx, MPP_SET_OUTPUT_BLOCK, ¶m); assert(!ret); - ret = pthread_mutex_init(&mutex, NULL); - assert(!ret); - ret = pthread_cond_init(&cond, NULL); - assert(!ret); + pthread_mutex_init(&mutex, NULL); + pthread_cond_init(&cond, NULL); - ret = pthread_create(&tid_frame, NULL, frame_thread, NULL); - assert(!ret); - ret = pthread_create(&tid_display, NULL, display_thread, NULL); - assert(!ret); + pthread_create(&tid_frame, NULL, frame_thread, NULL); + pthread_create(&tid_display, NULL, display_thread, NULL); return 0; } @@ -570,26 +558,19 @@ void rk_cleanup() { int ret; frm_eos = 1; - ret = pthread_mutex_lock(&mutex); - assert(!ret); - ret = pthread_cond_signal(&cond); - assert(!ret); - ret = pthread_mutex_unlock(&mutex); - assert(!ret); + pthread_mutex_lock(&mutex); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&mutex); - ret = pthread_join(tid_display, NULL); - assert(!ret); + pthread_join(tid_display, NULL); - ret = pthread_cond_destroy(&cond); - assert(!ret); - ret = pthread_mutex_destroy(&mutex); - assert(!ret); + pthread_cond_destroy(&cond); + pthread_mutex_destroy(&mutex); ret = mpi_api->reset(mpi_ctx); assert(!ret); - ret = pthread_join(tid_frame, NULL); - assert(!ret); + pthread_join(tid_frame, NULL); if (mpi_frm_grp) { ret = mpp_buffer_group_put(mpi_frm_grp); From bac5360494775545091c566880d2200aad81d8f7 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 20:56:55 -0600 Subject: [PATCH 15/18] Provide better errors when RK renderer fails --- src/video/rk.c | 66 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/src/video/rk.c b/src/video/rk.c index 2e04a9f8..94ffc1c6 100644 --- a/src/video/rk.c +++ b/src/video/rk.c @@ -175,12 +175,17 @@ void *display_thread(void *param) { // We may need to modeset to apply colorspace changes when toggling HDR set_property(plane_id, DRM_MODE_OBJECT_PLANE, plane_props, "FB_ID", _fb_id); ret = drmModeAtomicCommit(fd, drm_request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); + if (ret) { + perror("drmModeAtomicCommit"); + } } else { ret = drmModeSetPlane(fd, plane_id, crtc_id, _fb_id, 0, fb_x, fb_y, fb_width, fb_height, 0, 0, frm_width << 16, frm_height << 16); + if (ret) { + perror("drmModeSetPlane"); + } } - assert(!ret); } return NULL; @@ -244,7 +249,10 @@ void *frame_thread(void *param) { dmcd.width = hor_stride; dmcd.height = ver_stride * 2; // documentation say not v*2/3 but v*2 (additional info included) ret = drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &dmcd); - assert(!ret); + if (ret) { + perror("drmIoctl(DRM_IOCTL_MODE_CREATE_DUMB)"); + exit(EXIT_FAILURE); + } assert(dmcd.pitch == dmcd.width); assert(dmcd.size == dmcd.pitch * dmcd.height); frame_to_drm[i].handle = dmcd.handle; @@ -254,7 +262,10 @@ void *frame_thread(void *param) { dph.handle = dmcd.handle; dph.fd = -1; ret = drmIoctl(fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &dph); - assert(!ret); + if (ret) { + perror("drmIoctl(DRM_IOCTL_PRIME_HANDLE_TO_FD)"); + exit(EXIT_FAILURE); + } MppBufferInfo info = {0}; info.type = MPP_BUFFER_TYPE_DRM; info.size = dmcd.width * dmcd.height; @@ -272,7 +283,10 @@ void *frame_thread(void *param) { offsets[1] = pitches[0] * ver_stride; pitches[1] = dmcd.pitch; ret = drmModeAddFB2(fd, frm_width, frm_height, pixel_format, handles, pitches, offsets, &frame_to_drm[i].fb_id, 0); - assert(!ret); + if (ret) { + perror("drmModeAddFB2"); + exit(EXIT_FAILURE); + } } // register external frame group ret = mpi_api->control(mpi_ctx, MPP_DEC_SET_EXT_BUF_GROUP, mpi_frm_grp); @@ -369,7 +383,10 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte } resources = drmModeGetResources(fd); - assert(resources); + if (!resources) { + perror("drmModeGetResources"); + return -1; + } // find active monitor for (i = 0; i < resources->count_connectors; ++i) { @@ -417,7 +434,10 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte for (i = 0; i < resources->count_crtcs; ++i) { if (resources->crtcs[i] == encoder->crtc_id) { crtc = drmModeGetCrtc(fd, resources->crtcs[i]); - assert(crtc); + if (!crtc) { + perror("drmModeGetCrtc"); + continue; + } break; } } @@ -428,15 +448,25 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte uint32_t crtc_bit = (1 << i); ret = drmSetClientCap(fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); - assert(!ret); + if (ret) { + perror("drmSetClientCap(DRM_CLIENT_CAP_UNIVERSAL_PLANES)"); + } if (atomic) { ret = drmSetClientCap(fd, DRM_CLIENT_CAP_ATOMIC, 1); - assert(!ret); - drm_request = drmModeAtomicAlloc(); - assert(drm_request); + if (ret) { + perror("drmSetClientCap(DRM_CLIENT_CAP_ATOMIC)"); + atomic = false; + } + else { + drm_request = drmModeAtomicAlloc(); + assert(drm_request); + } } plane_resources = drmModeGetPlaneResources(fd); - assert(plane_resources); + if (!plane_resources) { + perror("drmModeGetPlaneResources"); + return -1; + } // search for OVERLAY (for active connector, unused, NV12 support) for (i = 0; i < plane_resources->count_planes; i++) { @@ -492,7 +522,11 @@ int rk_setup(int videoFormat, int width, int height, int redrawRate, void* conte } drmModeFreePlane(ovr); } - assert(plane_id); + + if (!plane_id) { + fprintf(stderr, "Unable to find suitable plane\n"); + return -1; + } // DRM defines rotation in degrees counter-clockwise while we define // rotation in degrees clockwise, so we swap the 90 and 270 cases @@ -578,11 +612,15 @@ void rk_cleanup() { mpi_frm_grp = NULL; for (i = 0; i < MAX_FRAMES; i++) { ret = drmModeRmFB(fd, frame_to_drm[i].fb_id); - assert(!ret); + if (ret) { + perror("drmModeRmFB"); + } struct drm_mode_destroy_dumb dmdd = {0}; dmdd.handle = frame_to_drm[i].handle; ret = drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dmdd); - assert(!ret); + if (ret) { + perror("drmIoctl(DRM_IOCTL_MODE_DESTROY_DUMB)"); + } } } From eb4a2023587748ae41905c29f3f6f224878aeb03 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 21:29:05 -0600 Subject: [PATCH 16/18] Version 2.7.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e677c3e8..e7247215 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.6) -project(moonlight-embedded VERSION 2.6.2 LANGUAGES C) +project(moonlight-embedded VERSION 2.7.0 LANGUAGES C) SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") SET(CMAKE_C_STANDARD 99) include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake) From 014af6739724ab1f2d524510bb59a524c4ee2547 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 19 Feb 2024 22:01:31 -0600 Subject: [PATCH 17/18] Fix build warnings --- libgamestream/client.c | 3 ++- src/cpu.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libgamestream/client.c b/libgamestream/client.c index bb9f5e68..3039e0f3 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -435,6 +435,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { char* pairing_secret = NULL; char* client_pairing_secret = NULL; char* client_pairing_secret_hex = NULL; + PHTTP_DATA data = NULL; if (server->paired) { gs_error = "Already paired"; @@ -450,7 +451,7 @@ int gs_pair(PSERVER_DATA server, char* pin) { uuid_generate_random(uuid); uuid_unparse(uuid, uuid_str); snprintf(url, url_max_len, "http://%s:%u/pair?uniqueid=%s&uuid=%s&devicename=roth&updateState=1&phrase=getservercert&salt=%s&clientcert=%s", server->serverInfo.address, server->httpPort, unique_id, uuid_str, salt_hex, cert_hex); - PHTTP_DATA data = http_create_data(); + data = http_create_data(); if (data == NULL) return GS_OUT_OF_MEMORY; else if ((ret = http_request(url, data)) != GS_OK) diff --git a/src/cpu.c b/src/cpu.c index 914ceaf0..fb6d6b56 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef HAVE_GETAUXVAL #include From 274d3db34da764344a7a402ee74e6080350ac0cd Mon Sep 17 00:00:00 2001 From: Mingjie Shen Date: Sat, 23 Mar 2024 22:03:02 -0400 Subject: [PATCH 18/18] fix unbounded write of sprintf Buffer write operations that do not control the length of data written may overflow. Fix by replacing sprintf() with snprintf(). --- libgamestream/http.c | 4 ++-- src/config.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libgamestream/http.c b/libgamestream/http.c index 795fb0d8..0ca97f05 100644 --- a/libgamestream/http.c +++ b/libgamestream/http.c @@ -51,10 +51,10 @@ int http_init(const char* keyDirectory, int logLevel) { return GS_FAILED; char certificateFilePath[4096]; - sprintf(certificateFilePath, "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME); + snprintf(certificateFilePath, sizeof(certificateFilePath), "%s/%s", keyDirectory, CERTIFICATE_FILE_NAME); char keyFilePath[4096]; - sprintf(&keyFilePath[0], "%s/%s", keyDirectory, KEY_FILE_NAME); + snprintf(keyFilePath, sizeof(keyFilePath), "%s/%s", keyDirectory, KEY_FILE_NAME); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1L); diff --git a/src/config.c b/src/config.c index c6ff242a..91f20615 100644 --- a/src/config.c +++ b/src/config.c @@ -411,11 +411,11 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) { struct passwd *pw = getpwuid(getuid()); const char *dir; if ((dir = getenv("XDG_CACHE_DIR")) != NULL) - sprintf(config->key_dir, "%s" MOONLIGHT_PATH, dir); + snprintf(config->key_dir, sizeof(config->key_dir), "%s" MOONLIGHT_PATH, dir); else if ((dir = getenv("HOME")) != NULL) - sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir); + snprintf(config->key_dir, sizeof(config->key_dir), "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir); else - sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir); + snprintf(config->key_dir, sizeof(config->key_dir), "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir); } if (config->stream.bitrate == -1) {