Compare commits

..
1 Commits
Author SHA1 Message Date
Cameron Gutman 60fadcbf36 Add Qt EGLFS plugin to AppImage 2023-11-07 00:55:21 -06:00
189 changed files with 8257 additions and 22086 deletions

No files matched your search

+3 -4
View File
@@ -37,13 +37,12 @@ List the games you've tried that exhibit the issue. To see if the issue is game-
- OS: [e.g. Windows 10 1809] - OS: [e.g. Windows 10 1809]
- Moonlight Version: [e.g. v0.9.0] - Moonlight Version: [e.g. v0.9.0]
- GPU: [e.g. Intel HD Graphics 520] - GPU: [e.g. Intel HD Graphics 520]
- Linux package type (if applicable): [e.g. Flatpak]
**Server PC details (please complete the following information)** **Server PC details (please complete the following information)**
- OS: [e.g. Windows 10 1809] - OS: [e.g. Windows 10 1809]
- Sunshine or GeForce Experience version: [e.g. Sunshine v0.21.0] - GeForce Experience version: [e.g. 3.16.0.140]
- GPU: [e.g. AMD Radeon RX 7900 XT] - Nvidia GPU driver: [e.g. 417.35]
- GPU driver: [e.g. 24.1.1] - Antivirus and firewall software: [e.g. Windows Defender and Windows Firewall]
**Moonlight Logs (please attach)** **Moonlight Logs (please attach)**
- On Windows, `Moonlight-###.log` files can be found in `%TEMP%`. Simply type that into the File Explorer path field to navigate there. - On Windows, `Moonlight-###.log` files can be found in `%TEMP%`. Simply type that into the File Explorer path field to navigate there.
+11
View File
@@ -158,6 +158,17 @@ private:
L"EZFRD32.dll", L"EZFRD32.dll",
L"EZFRD64.dll", L"EZFRD64.dll",
// These are the newer dList DLLs for Optimus hybrid graphics DDI.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/hybrid-system-ddi
//
// We forcefully block them from loading because Optimus has a bug that
// deadlocks DXVA2 when we present with D3DPRESENT_DONOTWAIT. This will prevent
// Optimus from ever using the dGPU even if the user has requested it.
// https://github.com/moonlight-stream/moonlight-qt/issues/240
// https://github.com/moonlight-stream/moonlight-qt/issues/235
L"nvdlist.dll",
L"nvdlistx.dll",
// These are the older dList/AppInit DLLs for Optimus hybrid graphics DDI. // These are the older dList/AppInit DLLs for Optimus hybrid graphics DDI.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/display/hybrid-system-ddi // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/hybrid-system-ddi
// //
+13 -24
View File
@@ -13,7 +13,6 @@ You can follow development on our [Discord server](https://moonlight-stream.org/
## Features ## Features
- Hardware accelerated video decoding on Windows, Mac, and Linux - Hardware accelerated video decoding on Windows, Mac, and Linux
- H.264, HEVC, and AV1 codec support (AV1 requires Sunshine and a supported host GPU) - H.264, HEVC, and AV1 codec support (AV1 requires Sunshine and a supported host GPU)
- YUV 4:4:4 support (Sunshine only)
- HDR streaming support - HDR streaming support
- 7.1 surround sound audio support - 7.1 surround sound audio support
- 10-point multitouch support (Sunshine only) - 10-point multitouch support (Sunshine only)
@@ -26,9 +25,9 @@ You can follow development on our [Discord server](https://moonlight-stream.org/
- [Snap (for Ubuntu-based Linux distros)](https://snapcraft.io/moonlight) - [Snap (for Ubuntu-based Linux distros)](https://snapcraft.io/moonlight)
- [Flatpak (for other Linux distros)](https://flathub.org/apps/details/com.moonlight_stream.Moonlight) - [Flatpak (for other Linux distros)](https://flathub.org/apps/details/com.moonlight_stream.Moonlight)
- [AppImage](https://github.com/moonlight-stream/moonlight-qt/releases) - [AppImage](https://github.com/moonlight-stream/moonlight-qt/releases)
- [Raspberry Pi 4 and 5](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4) - [Raspberry Pi 4](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Raspberry-Pi-4)
- [Generic ARM 32-bit and 64-bit Debian packages](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-ARM%E2%80%90based-Single-Board-Computers) (not for Raspberry Pi) - [Generic ARM SBC packages for Debian](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-ARM%E2%80%90based-Single-Board-Computers) (not for Raspberry Pi)
- [Experimental RISC-V Debian packages](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-RISC%E2%80%90V-Single-Board-Computers) - [Experimental RISC-V SBC packages for Debian](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-RISC%E2%80%90V-Single-Board-Computers)
- [NVIDIA Jetson and Nintendo Switch (Ubuntu L4T)](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Linux4Tegra-(L4T)-Ubuntu) - [NVIDIA Jetson and Nintendo Switch (Ubuntu L4T)](https://github.com/moonlight-stream/moonlight-docs/wiki/Installing-Moonlight-Qt-on-Linux4Tegra-(L4T)-Ubuntu)
#### Special Thanks #### Special Thanks
@@ -40,33 +39,23 @@ Hosting for Moonlight's Debian and L4T package repositories is graciously provid
## Building ## Building
### Windows Build Requirements ### Windows Build Requirements
* Qt 6.7 SDK or later (earlier versions may work but are not officially supported) * Qt 5.15 SDK or later. Qt 6 is also supported for x64 and ARM64 builds.
* [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) (Community edition is fine) * [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) (Community edition is fine)
* Select **MSVC** option during Qt installation. MinGW is not supported. * Select **MSVC** option during Qt installation. MinGW is not supported.
* [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs) * [7-Zip](https://www.7-zip.org/) (only if building installers for non-development PCs)
* Graphics Tools (only if running debug builds)
* Install "Graphics Tools" in the Optional Features page of the Windows Settings app.
* Alternatively, run `dism /online /add-capability /capabilityname:Tools.Graphics.DirectX~~~~0.0.1.0` and reboot.
### macOS Build Requirements ### macOS Build Requirements
* Qt 6.7 SDK or later (earlier versions may work but are not officially supported) * Qt 6.4 SDK or later
* Xcode 14 or later (earlier versions may work but are not officially supported) * Xcode 13 or later
* [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs) * [create-dmg](https://github.com/sindresorhus/create-dmg) (only if building DMGs for use on non-development Macs)
### Linux/Unix Build Requirements ### Linux/Unix Build Requirements
* Qt 6 is recommended, but Qt 5.9 or later is also supported (replace `qmake6` with `qmake` when using Qt 5). * Qt 5.9 SDK or later. Qt 6 is also supported.
* GCC or Clang * GCC or Clang
* FFmpeg 4.0 or later
* Install the required packages: * Install the required packages:
* Debian/Ubuntu: * Debian/Ubuntu: `libegl1-mesa-dev libgl1-mesa-dev libopus-dev libqt5svg5-dev libsdl2-dev libsdl2-ttf-dev libssl-dev libavcodec-dev libva-dev libvdpau-dev libxkbcommon-dev qtwayland5 qt5-qmake qtbase5-dev qtdeclarative5-dev qtquickcontrols2-5-dev wayland-protocols qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qtquick-window2 qml-module-qtquick2`
* Base Requirements: `libegl1-mesa-dev libgl1-mesa-dev libopus-dev libsdl2-dev libsdl2-ttf-dev libssl-dev libavcodec-dev libavformat-dev libswscale-dev libva-dev libvdpau-dev libxkbcommon-dev wayland-protocols libdrm-dev` * RedHat/Fedora: `openssl-devel SDL2-devel SDL2_ttf-devel ffmpeg-devel qt5-qtsvg-devel qt5-qtquickcontrols2-devel libva-devel libvdpau-devel opus-devel pulseaudio-libs-devel alsa-lib-devel`
* Qt 6 (Recommended): `qt6-base-dev qt6-declarative-dev libqt6svg6-dev qml6-module-qtquick-controls qml6-module-qtquick-templates qml6-module-qtquick-layouts qml6-module-qtqml-workerscript qml6-module-qtquick-window qml6-module-qtquick` * FFmpeg 4.0 or later is required to build. If your distro doesn't package FFmpeg 4.0 or later, you can build and install it from source on https://ffmpeg.org/
* Qt 5: `qtbase5-dev qt5-qmake qtdeclarative5-dev qtquickcontrols2-5-dev qml-module-qtquick-controls2 qml-module-qtquick-layouts qml-module-qtquick-window2 qml-module-qtquick2 qtwayland5`
* RedHat/Fedora (RPM Fusion repo required):
* Base Requirements: `openssl-devel SDL2-devel SDL2_ttf-devel ffmpeg-devel libva-devel libvdpau-devel opus-devel pulseaudio-libs-devel alsa-lib-devel libdrm-devel`
* Qt 6 (Recommended): `qt6-qtsvg-devel qt6-qtdeclarative-devel`
* Qt 5: `qt5-qtsvg-devel qt5-qtquickcontrols2-devel`
* Building the Vulkan renderer requires a `libplacebo-dev`/`libplacebo-devel` version of at least v7.349.0 and FFmpeg 6.1 or later.
### Steam Link Build Requirements ### Steam Link Build Requirements
* [Steam Link SDK](https://github.com/ValveSoftware/steamlink-sdk) cloned on your build system * [Steam Link SDK](https://github.com/ValveSoftware/steamlink-sdk) cloned on your build system
@@ -83,10 +72,10 @@ Hosting for Moonlight's Debian and L4T package repositories is graciously provid
* For Windows builds, use `scripts\build-arch.bat` and `scripts\generate-bundle.bat`. Execute these scripts from the root of the repository within a Qt command prompt. Ensure 7-Zip binary directory is on your `%PATH%`. * For Windows builds, use `scripts\build-arch.bat` and `scripts\generate-bundle.bat`. Execute these scripts from the root of the repository within a Qt command prompt. Ensure 7-Zip binary directory is on your `%PATH%`.
* For macOS builds, use `scripts/generate-dmg.sh`. Execute this script from the root of the repository and ensure Qt's `bin` folder is in your `$PATH`. * For macOS builds, use `scripts/generate-dmg.sh`. Execute this script from the root of the repository and ensure Qt's `bin` folder is in your `$PATH`.
* For Steam Link builds, run `scripts/build-steamlink-app.sh` from the root of the repository. * For Steam Link builds, run `scripts/build-steamlink-app.sh` from the root of the repository.
* To build from the command line for development use on macOS or Linux, run `qmake6 moonlight-qt.pro` then `make debug` or `make release` * To build from the command line for development use on macOS or Linux, run `qmake moonlight-qt.pro` then `make debug` or `make release`
* To create an embedded build for a single-purpose device, use `qmake6 "CONFIG+=embedded" moonlight-qt.pro` and build normally. * To create an embedded build for a single-purpose device, use `qmake "CONFIG+=embedded" moonlight-qt.pro` and build normally.
* This build will lack windowed mode, Discord/Help links, and other features that don't make sense on an embedded device. * This build will lack windowed mode, Discord/Help links, and other features that don't make sense on an embedded device.
* For platforms with poor GPU performance, add `"CONFIG+=gpuslow"` to prefer direct KMSDRM rendering over GL/Vulkan renderers. Direct KMSDRM rendering can use dedicated YUV/RGB conversion and scaling hardware rather than slower GPU shaders for these operations. * For platforms with poor GL performance, add `"CONFIG+=glslow"` to prefer direct KMSDRM rendering over EGL/GLES renderers. Direct KMSDRM rendering can use dedicated YUV/RGB conversion and scaling hardware rather than slower GPU shaders for these operations.
## Contribute ## Contribute
1. Fork us 1. Fork us
+3 -3
View File
@@ -17,7 +17,7 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>11.0.0</string> <string>10.14</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string>NSApplication</string> <string>NSApplication</string>
<key>NSSupportsAutomaticGraphicsSwitching</key> <key>NSSupportsAutomaticGraphicsSwitching</key>
@@ -31,13 +31,13 @@
</array> </array>
<key>GCSupportsControllerUserInteraction</key> <key>GCSupportsControllerUserInteraction</key>
<true/> <true/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>NSAppTransportSecurity</key> <key>NSAppTransportSecurity</key>
<dict> <dict>
<key>NSAllowsArbitraryLoads</key> <key>NSAllowsArbitraryLoads</key>
<true/> <true/>
</dict> </dict>
<key>NSLocalNetworkUsageDescription</key>
<string>Moonlight uses the local network to connect to your gaming PC for streaming.</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>VERSION</string> <string>VERSION</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
-320
View File
@@ -1,320 +0,0 @@
#include "SDL_compat.h"
#include <SDL_syswm.h>
void* SDLC_Win32_GetHwnd(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_WINDOWS
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return NULL;
}
if (info.subsystem == SDL_SYSWM_WINDOWS) {
return info.info.win.window;
}
#else
(void)window;
#endif
return NULL;
}
void* SDLC_MacOS_GetWindow(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_COCOA
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return NULL;
}
if (info.subsystem == SDL_SYSWM_COCOA) {
return info.info.cocoa.window;
}
#else
(void)window;
#endif
return NULL;
}
void* SDLC_X11_GetDisplay(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_X11
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return NULL;
}
if (info.subsystem == SDL_SYSWM_X11) {
return info.info.x11.display;
}
#else
(void)window;
#endif
return NULL;
}
unsigned long SDLC_X11_GetWindow(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_X11
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return 0;
}
if (info.subsystem == SDL_SYSWM_X11) {
return info.info.x11.window;
}
#else
(void)window;
#endif
return 0;
}
void* SDLC_Wayland_GetDisplay(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_WAYLAND
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return NULL;
}
if (info.subsystem == SDL_SYSWM_WAYLAND) {
return info.info.wl.display;
}
#else
(void)window;
#endif
return NULL;
}
void* SDLC_Wayland_GetSurface(SDL_Window* window)
{
#ifdef SDL_VIDEO_DRIVER_WAYLAND
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return NULL;
}
if (info.subsystem == SDL_SYSWM_WAYLAND) {
return info.info.wl.surface;
}
#else
(void)window;
#endif
return NULL;
}
int SDLC_KMSDRM_GetFd(SDL_Window* window)
{
#if defined(SDL_VIDEO_DRIVER_KMSDRM) && SDL_VERSION_ATLEAST(2, 0, 15)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return -1;
}
if (info.subsystem == SDL_SYSWM_KMSDRM) {
return info.info.kmsdrm.drm_fd;
}
#else
(void)window;
#endif
return -1;
}
int SDLC_KMSDRM_GetDevIndex(SDL_Window* window)
{
#if defined(SDL_VIDEO_DRIVER_KMSDRM) && SDL_VERSION_ATLEAST(2, 0, 15)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (!SDL_GetWindowWMInfo(window, &info)) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_GetWindowWMInfo() failed: %s",
SDL_GetError());
return -1;
}
if (info.subsystem == SDL_SYSWM_KMSDRM) {
return info.info.kmsdrm.dev_index;
}
#else
(void)window;
#endif
return -1;
}
SDLC_VideoDriver SDLC_GetVideoDriver(void)
{
#if defined(SDL_VIDEO_DRIVER_WINDOWS)
return SDLC_VIDEO_WIN32;
#elif defined(SDL_VIDEO_DRIVER_COCOA)
return SDLC_VIDEO_MACOS;
#else
const char* videoDriver = SDL_GetCurrentVideoDriver();
if (SDL_strcmp(videoDriver, "x11") == 0) {
return SDLC_VIDEO_X11;
}
else if (SDL_strcmp(videoDriver, "wayland") == 0) {
return SDLC_VIDEO_WAYLAND;
}
else if (SDL_strcmp(videoDriver, "kmsdrm") == 0) {
return SDLC_VIDEO_KMSDRM;
}
else {
SDL_assert(0);
return SDLC_VIDEO_UNKNOWN;
}
#endif
}
bool SDLC_IsFullscreen(SDL_Window* window)
{
return !!(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN);
}
bool SDLC_IsFullscreenExclusive(SDL_Window* window)
{
return (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN;
}
bool SDLC_IsFullscreenDesktop(SDL_Window* window)
{
return (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP;
}
void SDLC_EnterFullscreen(SDL_Window* window, bool exclusive)
{
SDL_SetWindowFullscreen(window, exclusive ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP);
}
void SDLC_LeaveFullscreen(SDL_Window* window)
{
SDL_SetWindowFullscreen(window, 0);
}
SDL_Window* SDLC_CreateWindowWithFallback(const char *title,
int x, int y, int w, int h,
Uint32 requiredFlags,
Uint32 optionalFlags)
{
SDL_Window* window = SDL_CreateWindow(title, x, y, w, h, requiredFlags | optionalFlags);
if (!window) {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create window with optional flags: %s",
SDL_GetError());
// Try the fallback flags now
window = SDL_CreateWindow(title, x, y, w, h, requiredFlags);
}
return window;
}
void SDLC_FlushWindowEvents(void)
{
SDL_FlushEvent(SDL_WINDOWEVENT);
}
SDL_JoystickID* SDL_GetGamepads(int *count)
{
int numJoysticks = SDL_NumJoysticks();
SDL_JoystickID* ids = SDL_calloc(numJoysticks + 1, sizeof(SDL_JoystickID));
int numGamepads = 0;
for (int i = 0; i < numJoysticks; i++) {
if (SDL_IsGameController(i)) {
ids[numGamepads++] = i;
}
}
if (count != NULL) {
*count = numGamepads;
}
return ids;
}
SDL_JoystickID* SDL_GetJoysticks(int *count)
{
int numJoysticks = SDL_NumJoysticks();
SDL_JoystickID* ids = SDL_calloc(numJoysticks + 1, sizeof(SDL_JoystickID));
for (int i = 0; i < numJoysticks; i++) {
ids[i] = i;
}
if (count != NULL) {
*count = numJoysticks;
}
return ids;
}
SDL_DisplayID * SDL_GetDisplays(int *count)
{
int numDisplays = SDL_GetNumVideoDisplays();
SDL_DisplayID* ids = SDL_calloc(numDisplays + 1, sizeof(SDL_DisplayID));
for (int i = 0; i < numDisplays; i++) {
ids[i] = i;
}
if (count != NULL) {
*count = numDisplays;
}
return ids;
}
const SDL_DisplayMode * SDL_GetWindowFullscreenMode(SDL_Window *window)
{
static SDL_DisplayMode mode;
if (SDL_GetWindowDisplayMode(window, &mode) == 0) {
return &mode;
}
else {
return NULL;
}
}
-303
View File
@@ -1,303 +0,0 @@
//
// Compatibility header for older versions of SDL.
// Include this instead of SDL.h directly.
//
#pragma once
#include <SDL.h>
#include <stdbool.h>
// This is a pure C header for compatibility with SDL.h
#ifdef __cplusplus
extern "C" {
#endif
// These SLDC_* functions and constants are special SDL-like things
// used to abstract certain SDL2 vs SDL3 differences.
void* SDLC_Win32_GetHwnd(SDL_Window* window);
void* SDLC_MacOS_GetWindow(SDL_Window* window);
void* SDLC_X11_GetDisplay(SDL_Window* window);
unsigned long SDLC_X11_GetWindow(SDL_Window* window);
void* SDLC_Wayland_GetDisplay(SDL_Window* window);
void* SDLC_Wayland_GetSurface(SDL_Window* window);
int SDLC_KMSDRM_GetFd(SDL_Window* window);
int SDLC_KMSDRM_GetDevIndex(SDL_Window* window);
typedef enum {
SDLC_VIDEO_UNKNOWN,
SDLC_VIDEO_WIN32,
SDLC_VIDEO_MACOS,
SDLC_VIDEO_X11,
SDLC_VIDEO_WAYLAND,
SDLC_VIDEO_KMSDRM,
} SDLC_VideoDriver;
SDLC_VideoDriver SDLC_GetVideoDriver();
bool SDLC_IsFullscreen(SDL_Window* window);
bool SDLC_IsFullscreenExclusive(SDL_Window* window);
bool SDLC_IsFullscreenDesktop(SDL_Window* window);
void SDLC_EnterFullscreen(SDL_Window* window, bool exclusive);
void SDLC_LeaveFullscreen(SDL_Window* window);
SDL_Window* SDLC_CreateWindowWithFallback(const char *title,
int x, int y, int w, int h,
Uint32 requiredFlags,
Uint32 optionalFlags);
void SDLC_FlushWindowEvents();
#define SDLC_SUCCESS(x) ((x) == 0)
#define SDLC_FAILURE(x) ((x) != 0)
// SDL_FRect wasn't added until 2.0.10
#if !SDL_VERSION_ATLEAST(2, 0, 10)
typedef struct SDL_FRect
{
float x;
float y;
float w;
float h;
} SDL_FRect;
#endif
#ifndef SDL_THREAD_PRIORITY_TIME_CRITICAL
#define SDL_THREAD_PRIORITY_TIME_CRITICAL SDL_THREAD_PRIORITY_HIGH
#endif
#ifndef SDL_HINT_VIDEO_X11_FORCE_EGL
#define SDL_HINT_VIDEO_X11_FORCE_EGL "SDL_VIDEO_X11_FORCE_EGL"
#endif
#ifndef SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER
#define SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER "SDL_KMSDRM_REQUIRE_DRM_MASTER"
#endif
#ifndef SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED
#define SDL_HINT_ALLOW_ALT_TAB_WHILE_GRABBED "SDL_ALLOW_ALT_TAB_WHILE_GRABBED"
#endif
#ifndef SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE
#define SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE "SDL_JOYSTICK_HIDAPI_PS4_RUMBLE"
#endif
#ifndef SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE
#define SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE "SDL_JOYSTICK_HIDAPI_PS5_RUMBLE"
#endif
#ifndef SDL_HINT_WINDOWS_USE_D3D9EX
#define SDL_HINT_WINDOWS_USE_D3D9EX "SDL_WINDOWS_USE_D3D9EX"
#endif
#ifndef SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS
#define SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS "SDL_GAMECONTROLLER_USE_BUTTON_LABELS"
#endif
#ifndef SDL_HINT_MOUSE_RELATIVE_SCALING
#define SDL_HINT_MOUSE_RELATIVE_SCALING "SDL_MOUSE_RELATIVE_SCALING"
#endif
#ifndef SDL_HINT_AUDIO_DEVICE_APP_NAME
#define SDL_HINT_AUDIO_DEVICE_APP_NAME "SDL_AUDIO_DEVICE_APP_NAME"
#endif
#ifndef SDL_HINT_APP_NAME
#define SDL_HINT_APP_NAME "SDL_APP_NAME"
#endif
#ifndef SDL_HINT_MOUSE_AUTO_CAPTURE
#define SDL_HINT_MOUSE_AUTO_CAPTURE "SDL_MOUSE_AUTO_CAPTURE"
#endif
#ifndef SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP
#define SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP "SDL_VIDEO_WAYLAND_EMULATE_MOUSE_WARP"
#endif
// SDL3 renamed hints
#define SDL_HINT_VIDEO_FORCE_EGL SDL_HINT_VIDEO_X11_FORCE_EGL
// Events
#define SDL_EVENT_QUIT SDL_QUIT
#define SDL_EVENT_CLIPBOARD_UPDATE SDL_CLIPBOARDUPDATE
#define SDL_EVENT_GAMEPAD_ADDED SDL_CONTROLLERDEVICEADDED
#define SDL_EVENT_GAMEPAD_REMAPPED SDL_CONTROLLERDEVICEREMAPPED
#define SDL_EVENT_GAMEPAD_REMOVED SDL_CONTROLLERDEVICEREMOVED
#define SDL_EVENT_GAMEPAD_SENSOR_UPDATE SDL_CONTROLLERSENSORUPDATE
#define SDL_EVENT_GAMEPAD_BUTTON_DOWN SDL_CONTROLLERBUTTONDOWN
#define SDL_EVENT_GAMEPAD_BUTTON_UP SDL_CONTROLLERBUTTONUP
#define SDL_EVENT_GAMEPAD_AXIS_MOTION SDL_CONTROLLERAXISMOTION
#define SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN SDL_CONTROLLERTOUCHPADDOWN
#define SDL_EVENT_GAMEPAD_TOUCHPAD_UP SDL_CONTROLLERTOUCHPADUP
#define SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION SDL_CONTROLLERTOUCHPADMOTION
#define SDL_EVENT_JOYSTICK_ADDED SDL_JOYDEVICEADDED
#define SDL_EVENT_JOYSTICK_REMOVED SDL_JOYDEVICEREMOVED
#define SDL_EVENT_JOYSTICK_BATTERY_UPDATED SDL_JOYBATTERYUPDATED
#define SDL_EVENT_FINGER_DOWN SDL_FINGERDOWN
#define SDL_EVENT_FINGER_MOTION SDL_FINGERMOTION
#define SDL_EVENT_FINGER_UP SDL_FINGERUP
#define SDL_EVENT_KEY_DOWN SDL_KEYDOWN
#define SDL_EVENT_KEY_UP SDL_KEYUP
#define SDL_EVENT_MOUSE_BUTTON_DOWN SDL_MOUSEBUTTONDOWN
#define SDL_EVENT_MOUSE_BUTTON_UP SDL_MOUSEBUTTONUP
#define SDL_EVENT_MOUSE_MOTION SDL_MOUSEMOTION
#define SDL_EVENT_MOUSE_WHEEL SDL_MOUSEWHEEL
#define SDL_EVENT_RENDER_DEVICE_RESET SDL_RENDER_DEVICE_RESET
#define SDL_EVENT_RENDER_TARGETS_RESET SDL_RENDER_TARGETS_RESET
#define SDL_EVENT_USER SDL_USEREVENT
#define SDL_EVENT_WINDOW_FOCUS_GAINED SDL_WINDOWEVENT_FOCUS_GAINED
#define SDL_EVENT_WINDOW_FOCUS_LOST SDL_WINDOWEVENT_FOCUS_LOST
#define SDL_EVENT_WINDOW_MOUSE_ENTER SDL_WINDOWEVENT_ENTER
#define SDL_EVENT_WINDOW_MOUSE_LEAVE SDL_WINDOWEVENT_LEAVE
#define SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED SDL_WINDOWEVENT_SIZE_CHANGED
#define SDL_EVENT_WINDOW_SHOWN SDL_WINDOWEVENT_SHOWN
#define SDL_EVENT_WINDOW_DISPLAY_CHANGED SDL_WINDOWEVENT_DISPLAY_CHANGED
#define SDL_BUTTON_MASK(x) SDL_BUTTON(x)
#define gbutton cbutton
#define gaxis caxis
#define gdevice cdevice
#define gsensor csensor
#define gtouchpad ctouchpad
#define fingerID fingerId
#define touchID touchId
#define KEY_DOWN(x) ((x)->state == SDL_PRESSED)
#define KEY_KEY(x) ((x)->keysym.sym)
#define KEY_MOD(x) ((x)->keysym.mod)
#define KEY_SCANCODE(x) ((x)->keysym.scancode)
// Gamepad
#define SDL_INIT_GAMEPAD SDL_INIT_GAMECONTROLLER
#define SDL_GAMEPAD_BUTTON_SOUTH SDL_CONTROLLER_BUTTON_A
#define SDL_GAMEPAD_BUTTON_EAST SDL_CONTROLLER_BUTTON_B
#define SDL_GAMEPAD_BUTTON_WEST SDL_CONTROLLER_BUTTON_X
#define SDL_GAMEPAD_BUTTON_NORTH SDL_CONTROLLER_BUTTON_Y
#define SDL_GAMEPAD_BUTTON_LEFT_SHOULDER SDL_CONTROLLER_BUTTON_LEFTSHOULDER
#define SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER SDL_CONTROLLER_BUTTON_RIGHTSHOULDER
#define SDL_GAMEPAD_BUTTON_DPAD_UP SDL_CONTROLLER_BUTTON_DPAD_UP
#define SDL_GAMEPAD_BUTTON_DPAD_DOWN SDL_CONTROLLER_BUTTON_DPAD_DOWN
#define SDL_GAMEPAD_BUTTON_DPAD_LEFT SDL_CONTROLLER_BUTTON_DPAD_LEFT
#define SDL_GAMEPAD_BUTTON_DPAD_RIGHT SDL_CONTROLLER_BUTTON_DPAD_RIGHT
#define SDL_GAMEPAD_BUTTON_START SDL_CONTROLLER_BUTTON_START
#define SDL_GAMEPAD_BUTTON_TOUCHPAD SDL_CONTROLLER_BUTTON_TOUCHPAD
#define SDL_GAMEPAD_BINDTYPE_AXIS SDL_CONTROLLER_BINDTYPE_AXIS
#define SDL_GAMEPAD_BINDTYPE_BUTTON SDL_CONTROLLER_BINDTYPE_BUTTON
#define SDL_GAMEPAD_BINDTYPE_HAT SDL_CONTROLLER_BINDTYPE_HAT
#define SDL_GAMEPAD_BINDTYPE_NONE SDL_CONTROLLER_BINDTYPE_NONE
#define SDL_GAMEPAD_AXIS_LEFTX SDL_CONTROLLER_AXIS_LEFTX
#define SDL_GAMEPAD_AXIS_LEFTY SDL_CONTROLLER_AXIS_LEFTY
#define SDL_GAMEPAD_AXIS_RIGHTX SDL_CONTROLLER_AXIS_RIGHTX
#define SDL_GAMEPAD_AXIS_RIGHTY SDL_CONTROLLER_AXIS_RIGHTY
#define SDL_GAMEPAD_AXIS_LEFT_TRIGGER SDL_CONTROLLER_AXIS_TRIGGERLEFT
#define SDL_GAMEPAD_AXIS_RIGHT_TRIGGER SDL_CONTROLLER_AXIS_TRIGGERRIGHT
// SDL_OpenGamepad() not defined due to differing semantics
SDL_JoystickID* SDL_GetGamepads(int *count);
#define SDL_OpenGamepad(x) SDL_GameControllerOpen(x)
#define SDL_CloseGamepad(x) SDL_GameControllerClose(x)
#define SDL_GetGamepadMapping(x) SDL_GameControllerMapping(x)
#define SDL_GetGamepadName(x) SDL_GameControllerName(x)
#define SDL_GetGamepadVendor(x) SDL_GameControllerGetVendor(x)
#define SDL_GetGamepadProduct(x) SDL_GameControllerGetProduct(x)
#define SDL_GetGamepadJoystick(x) SDL_GameControllerGetJoystick(x)
#define SDL_GamepadHasButton(x, y) SDL_GameControllerHasButton(x, y)
#define SDL_GamepadHasSensor(x, y) SDL_GameControllerHasSensor(x, y)
#define SDL_SetGamepadPlayerIndex(x, y) SDL_GameControllerSetPlayerIndex(x, y)
#define SDL_GamepadSensorEnabled(x, y) SDL_GameControllerIsSensorEnabled(x, y)
#define SDL_SetGamepadSensorEnabled(x, y, z) SDL_GameControllerSetSensorEnabled(x, y, z)
#define SDL_GetNumGamepadTouchpads(x) SDL_GameControllerGetNumTouchpads(x)
#define SDL_SetGamepadLED(x, r, g, b) SDL_GameControllerSetLED(x, r, g, b)
#define SDL_RumbleGamepad(x, y, z, w) SDL_GameControllerRumble(x, y, z, w)
#define SDL_RumbleGamepadTriggers(x, y, z, w) SDL_GameControllerRumbleTriggers(x, y, z, w)
#define SDL_GetGamepadAxis(x, y) SDL_GameControllerGetAxis(x, y)
#define SDL_GetGamepadType(x) SDL_GameControllerGetType(x)
#define SDL_IsGamepad(x) SDL_IsGameController(x)
#define SDL_GAMEPAD_TYPE_STANDARD SDL_CONTROLLER_TYPE_UNKNOWN
#define SDL_GAMEPAD_TYPE_VIRTUAL SDL_CONTROLLER_TYPE_VIRTUAL
#define SDL_GAMEPAD_TYPE_XBOX360 SDL_CONTROLLER_TYPE_XBOX360
#define SDL_GAMEPAD_TYPE_XBOXONE SDL_CONTROLLER_TYPE_XBOXONE
#define SDL_GAMEPAD_TYPE_PS3 SDL_CONTROLLER_TYPE_PS3
#define SDL_GAMEPAD_TYPE_PS4 SDL_CONTROLLER_TYPE_PS4
#define SDL_GAMEPAD_TYPE_PS5 SDL_CONTROLLER_TYPE_PS5
#define SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT
#define SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
#define SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT
#define SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO
// SDL_OpenGamepad() not defined due to differing semantics
SDL_JoystickID* SDL_GetJoysticks(int *count);
#define SDL_OpenJoystick(x) SDL_JoystickOpen(x)
#define SDL_CloseJoystick(x) SDL_JoystickClose(x)
#define SDL_GetJoystickID(x) SDL_JoystickInstanceID(x)
#define SDL_GetJoystickGUID(x) SDL_JoystickGetGUID(x)
#define SDL_GetJoystickPowerLevel(x) SDL_JoystickCurrentPowerLevel(x)
#define SDL_GetNumJoystickAxes(x) SDL_JoystickNumAxes(x)
#define SDL_GetNumJoystickBalls(x) SDL_JoystickNumBalls(x)
#define SDL_GetNumJoystickButtons(x) SDL_JoystickNumButtons(x)
#define SDL_GetNumJoystickHats(x) SDL_JoystickNumHats(x)
#define SDL_GetJoystickGUIDForID(x) SDL_JoystickGetDeviceGUID(x)
typedef SDL_ControllerAxisEvent SDL_GamepadAxisEvent;
typedef SDL_ControllerButtonEvent SDL_GamepadButtonEvent;
typedef SDL_ControllerSensorEvent SDL_GamepadSensorEvent;
typedef SDL_ControllerTouchpadEvent SDL_GamepadTouchpadEvent;
typedef SDL_ControllerDeviceEvent SDL_GamepadDeviceEvent;
typedef SDL_GameController SDL_Gamepad;
typedef SDL_GameControllerButton SDL_GamepadButton;
// Audio
#define SDL_AUDIO_F32 AUDIO_F32SYS
#define SDL_ResumeAudioDevice(x) SDL_PauseAudioDevice(x, 0)
// Atomics
#define SDL_GetAtomicInt(x) SDL_AtomicGet(x)
#define SDL_SetAtomicInt(x, y) SDL_AtomicSet(x, y)
#define SDL_GetAtomicPointer(x) SDL_AtomicGetPtr(x)
#define SDL_SetAtomicPointer(x, y) SDL_AtomicSetPtr(x, y)
#define SDL_LockSpinlock(x) SDL_AtomicLock(x)
#define SDL_TryLockSpinlock(x) SDL_AtomicTryLock(x)
#define SDL_UnlockSpinlock(x) SDL_AtomicUnlock(x)
typedef SDL_atomic_t SDL_AtomicInt;
// Video
#define SDL_KMOD_CTRL KMOD_CTRL
#define SDL_KMOD_ALT KMOD_ALT
#define SDL_KMOD_SHIFT KMOD_SHIFT
#define SDL_KMOD_GUI KMOD_GUI
#define SDL_WINDOW_HIGH_PIXEL_DENSITY SDL_WINDOW_ALLOW_HIGHDPI
#define SDL_SetWindowFullscreenMode(x, y) SDL_SetWindowDisplayMode(x, y)
#define SDL_GetDisplayForWindow(x) SDL_GetWindowDisplayIndex(x)
#define SDL_GetRenderViewport(x, y) SDL_RenderGetViewport(x, y)
#define SDL_DestroySurface(x) SDL_FreeSurface(x)
#define SDL_RenderTexture(x, y, z, w) SDL_RenderCopy(x, y, z, w)
#define SDL_GetPrimaryDisplay() (0)
#define SDL_CreateSurfaceFrom(w, h, fmt, pixels, pitch) SDL_CreateRGBSurfaceWithFormatFrom(pixels, w, h, SDL_BITSPERPIXEL(fmt), pitch, fmt)
#define SDLC_DEFAULT_RENDER_DRIVER -1
typedef int SDL_DisplayID;
SDL_DisplayID * SDL_GetDisplays(int *count);
const SDL_DisplayMode * SDL_GetWindowFullscreenMode(SDL_Window *window);
// Misc
#define SDL_GetNumLogicalCPUCores() SDL_GetCPUCount()
#define SDL_IOFromConstMem(x, y) SDL_RWFromConstMem(x, y)
#define SDL_SetCurrentThreadPriority(x) SDL_SetThreadPriority(x)
#define SDL_GUIDToString(x, y, z) SDL_JoystickGetGUIDString(x, y, z)
#ifdef __cplusplus
}
#endif
+21 -80
View File
@@ -12,13 +12,10 @@ include(../globaldefs.pri)
# Precompile QML files to avoid writing qmlcache on portable versions. # Precompile QML files to avoid writing qmlcache on portable versions.
# Since this binds the app against the Qt runtime version, we will only # Since this binds the app against the Qt runtime version, we will only
# do this for Windows and Mac (when disable-prebuilts is not defined), # do this for Windows and Mac, since they ship with the Qt runtime.
# since they always ship with the matching build of the Qt runtime. win32|macx {
!disable-prebuilts { CONFIG(release, debug|release) {
win32|macx { CONFIG += qtquickcompiler
CONFIG(release, debug|release) {
CONFIG += qtquickcompiler
}
} }
} }
@@ -55,7 +52,7 @@ win32 {
# Work around a conflict with math.h inclusion between SDL and Qt 6 # Work around a conflict with math.h inclusion between SDL and Qt 6
DEFINES += _USE_MATH_DEFINES DEFINES += _USE_MATH_DEFINES
} }
macx:!disable-prebuilts { macx {
INCLUDEPATH += $$PWD/../libs/mac/include INCLUDEPATH += $$PWD/../libs/mac/include
INCLUDEPATH += $$PWD/../libs/mac/Frameworks/SDL2.framework/Versions/A/Headers INCLUDEPATH += $$PWD/../libs/mac/Frameworks/SDL2.framework/Versions/A/Headers
INCLUDEPATH += $$PWD/../libs/mac/Frameworks/SDL2_ttf.framework/Versions/A/Headers INCLUDEPATH += $$PWD/../libs/mac/Frameworks/SDL2_ttf.framework/Versions/A/Headers
@@ -67,18 +64,13 @@ macx:!disable-prebuilts {
QMAKE_OBJECTIVE_CFLAGS += -F$$PWD/../libs/mac/Frameworks QMAKE_OBJECTIVE_CFLAGS += -F$$PWD/../libs/mac/Frameworks
} }
unix:if(!macx|disable-prebuilts) { unix:!macx {
CONFIG += link_pkgconfig CONFIG += link_pkgconfig
PKGCONFIG += openssl sdl2 SDL2_ttf PKGCONFIG += openssl sdl2 SDL2_ttf opus
# We have our own optimized libopus.a for Steam Link
if(!config_SL|disable-prebuilts) {
PKGCONFIG += opus
}
!disable-ffmpeg { !disable-ffmpeg {
packagesExist(libavcodec) { packagesExist(libavcodec) {
PKGCONFIG += libavcodec libavutil libswscale PKGCONFIG += libavcodec libavutil
CONFIG += ffmpeg CONFIG += ffmpeg
!disable-libva { !disable-libva {
@@ -128,13 +120,6 @@ unix:if(!macx|disable-prebuilts) {
CONFIG += cuda CONFIG += cuda
} }
} }
!disable-libplacebo {
packagesExist(libplacebo) {
PKGCONFIG += libplacebo
CONFIG += libplacebo
}
}
} }
!disable-wayland { !disable-wayland {
@@ -153,28 +138,23 @@ unix:if(!macx|disable-prebuilts) {
} }
} }
win32 { win32 {
LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lswscale -lopus -ldxgi -ld3d11 -llibplacebo LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lopus -ldxgi -ld3d11
CONFIG += ffmpeg libplacebo CONFIG += ffmpeg
} }
win32:!winrt { win32:!winrt {
CONFIG += soundio discord-rpc CONFIG += soundio discord-rpc
} }
macx { macx {
!disable-prebuilts { LIBS += -lssl -lcrypto -lavcodec.60 -lavutil.58 -lopus -framework SDL2 -framework SDL2_ttf
LIBS += -lssl.3 -lcrypto.3 -lavcodec.61 -lavutil.59 -lswscale.8 -lopus -framework SDL2 -framework SDL2_ttf LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal
CONFIG += discord-rpc
}
LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal -framework QuartzCore
# For libsoundio # For libsoundio
LIBS += -framework CoreAudio -framework AudioUnit LIBS += -framework CoreAudio -framework AudioUnit
CONFIG += ffmpeg soundio CONFIG += ffmpeg soundio discord-rpc
} }
SOURCES += \ SOURCES += \
SDL_compat.c \
backend/nvaddress.cpp \ backend/nvaddress.cpp \
backend/nvapp.cpp \ backend/nvapp.cpp \
cli/pair.cpp \ cli/pair.cpp \
@@ -215,7 +195,6 @@ SOURCES += \
wm.cpp wm.cpp
HEADERS += \ HEADERS += \
SDL_compat.h \
backend/nvaddress.h \ backend/nvaddress.h \
backend/nvapp.h \ backend/nvapp.h \
cli/pair.h \ cli/pair.h \
@@ -257,7 +236,6 @@ ffmpeg {
DEFINES += HAVE_FFMPEG DEFINES += HAVE_FFMPEG
SOURCES += \ SOURCES += \
streaming/video/ffmpeg.cpp \ streaming/video/ffmpeg.cpp \
streaming/video/ffmpeg-renderers/genhwaccel.cpp \
streaming/video/ffmpeg-renderers/sdlvid.cpp \ streaming/video/ffmpeg-renderers/sdlvid.cpp \
streaming/video/ffmpeg-renderers/swframemapper.cpp \ streaming/video/ffmpeg-renderers/swframemapper.cpp \
streaming/video/ffmpeg-renderers/pacer/pacer.cpp streaming/video/ffmpeg-renderers/pacer/pacer.cpp
@@ -265,7 +243,6 @@ ffmpeg {
HEADERS += \ HEADERS += \
streaming/video/ffmpeg.h \ streaming/video/ffmpeg.h \
streaming/video/ffmpeg-renderers/renderer.h \ streaming/video/ffmpeg-renderers/renderer.h \
streaming/video/ffmpeg-renderers/genhwaccel.h \
streaming/video/ffmpeg-renderers/sdlvid.h \ streaming/video/ffmpeg-renderers/sdlvid.h \
streaming/video/ffmpeg-renderers/swframemapper.h \ streaming/video/ffmpeg-renderers/swframemapper.h \
streaming/video/ffmpeg-renderers/pacer/pacer.h streaming/video/ffmpeg-renderers/pacer/pacer.h
@@ -314,7 +291,7 @@ mmal {
# significantly better performance than EGL on the Pi. Setting # significantly better performance than EGL on the Pi. Setting
# this option allows EGL usage even if built with MMAL support. # this option allows EGL usage even if built with MMAL support.
# #
# It is highly recommended to also build with 'gpuslow' to avoid # It is highly recommended to also build with 'glslow' to avoid
# EGL being preferred if direct DRM rendering is available. # EGL being preferred if direct DRM rendering is available.
allow-egl-with-mmal { allow-egl-with-mmal {
message(Allowing EGL usage with MMAL enabled) message(Allowing EGL usage with MMAL enabled)
@@ -345,16 +322,6 @@ cuda {
# ffnvcodec uses libdl in cuda_load_functions()/cuda_free_functions() # ffnvcodec uses libdl in cuda_load_functions()/cuda_free_functions()
LIBS += -ldl LIBS += -ldl
} }
libplacebo {
message(Vulkan support enabled via libplacebo)
DEFINES += HAVE_LIBPLACEBO_VULKAN
SOURCES += \
streaming/video/ffmpeg-renderers/plvk.cpp \
streaming/video/ffmpeg-renderers/plvk_c.c
HEADERS += \
streaming/video/ffmpeg-renderers/plvk.h
}
config_EGL { config_EGL {
message(EGL renderer selected) message(EGL renderer selected)
@@ -371,13 +338,6 @@ config_EGL {
config_SL { config_SL {
message(Steam Link build configuration selected) message(Steam Link build configuration selected)
!disable-prebuilts {
# Link against our NEON-optimized libopus build
LIBS += -L$$PWD/../libs/steamlink/lib
INCLUDEPATH += $$PWD/../libs/steamlink/include
LIBS += -lopus -larmasm -lNE10
}
DEFINES += EMBEDDED_BUILD STEAM_LINK HAVE_SLVIDEO HAVE_SLAUDIO DEFINES += EMBEDDED_BUILD STEAM_LINK HAVE_SLVIDEO HAVE_SLAUDIO
LIBS += -lSLVideo -lSLAudio LIBS += -lSLVideo -lSLAudio
@@ -408,9 +368,7 @@ macx {
message(VideoToolbox renderer selected) message(VideoToolbox renderer selected)
SOURCES += \ SOURCES += \
streaming/video/ffmpeg-renderers/vt_base.mm \ streaming/video/ffmpeg-renderers/vt.mm
streaming/video/ffmpeg-renderers/vt_avsamplelayer.mm \
streaming/video/ffmpeg-renderers/vt_metal.mm
HEADERS += \ HEADERS += \
streaming/video/ffmpeg-renderers/vt.h streaming/video/ffmpeg-renderers/vt.h
@@ -438,16 +396,6 @@ glslow {
DEFINES += GL_IS_SLOW DEFINES += GL_IS_SLOW
} }
vkslow {
message(Vulkan slow build)
DEFINES += VULKAN_IS_SLOW
}
gpuslow {
message(GPU slow build)
DEFINES += GL_IS_SLOW VULKAN_IS_SLOW
}
wayland { wayland {
message(Wayland extensions enabled) message(Wayland extensions enabled)
@@ -484,10 +432,7 @@ TRANSLATIONS += \
languages/qml_pt_BR.ts \ languages/qml_pt_BR.ts \
languages/qml_pl.ts \ languages/qml_pl.ts \
languages/qml_cs.ts \ languages/qml_cs.ts \
languages/qml_he.ts \ languages/qml_he.ts
languages/qml_ckb.ts \
languages/qml_lt.ts \
languages/qml_et.ts
# Additional import path used to resolve QML modules in Qt Creator's code model # Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH = QML_IMPORT_PATH =
@@ -576,19 +521,15 @@ macx {
APP_BUNDLE_RESOURCES.files = moonlight.icns APP_BUNDLE_RESOURCES.files = moonlight.icns
APP_BUNDLE_RESOURCES.path = Contents/Resources APP_BUNDLE_RESOURCES.path = Contents/Resources
APP_BUNDLE_FRAMEWORKS.files = $$files(../libs/mac/Frameworks/*.framework, true) $$files(../libs/mac/lib/*.dylib, true)
APP_BUNDLE_FRAMEWORKS.path = Contents/Frameworks
APP_BUNDLE_PLIST.files = $$OUT_PWD/Info.plist APP_BUNDLE_PLIST.files = $$OUT_PWD/Info.plist
APP_BUNDLE_PLIST.path = Contents APP_BUNDLE_PLIST.path = Contents
QMAKE_BUNDLE_DATA += APP_BUNDLE_RESOURCES APP_BUNDLE_PLIST QMAKE_BUNDLE_DATA += APP_BUNDLE_RESOURCES APP_BUNDLE_FRAMEWORKS APP_BUNDLE_PLIST
!disable-prebuilts { QMAKE_RPATHDIR += @executable_path/../Frameworks
APP_BUNDLE_FRAMEWORKS.files = $$files(../libs/mac/Frameworks/*.framework, true) $$files(../libs/mac/lib/*.dylib, true)
APP_BUNDLE_FRAMEWORKS.path = Contents/Frameworks
QMAKE_BUNDLE_DATA += APP_BUNDLE_FRAMEWORKS
QMAKE_RPATHDIR += @executable_path/../Frameworks
}
} }
VERSION = "$$cat(version.txt)" VERSION = "$$cat(version.txt)"
+9 -6
View File
@@ -1,7 +1,7 @@
#include "computermanager.h" #include "computermanager.h"
#include "boxartmanager.h" #include "boxartmanager.h"
#include "nvhttp.h" #include "nvhttp.h"
#include "nvpairingmanager.h" #include "settings/streamingpreferences.h"
#include <Limelight.h> #include <Limelight.h>
#include <QtEndian> #include <QtEndian>
@@ -144,8 +144,8 @@ private:
NvComputer* m_Computer; NvComputer* m_Computer;
}; };
ComputerManager::ComputerManager(StreamingPreferences* prefs) ComputerManager::ComputerManager(QObject *parent)
: m_Prefs(prefs), : QObject(parent),
m_PollingRef(0), m_PollingRef(0),
m_MdnsBrowser(nullptr), m_MdnsBrowser(nullptr),
m_CompatFetcher(nullptr), m_CompatFetcher(nullptr),
@@ -352,7 +352,9 @@ void ComputerManager::startPolling()
return; return;
} }
if (m_Prefs->enableMdns) { StreamingPreferences prefs;
if (prefs.enableMdns) {
// Start an MDNS query for GameStream hosts // Start an MDNS query for GameStream hosts
m_MdnsServer.reset(new QMdnsEngine::Server()); m_MdnsServer.reset(new QMdnsEngine::Server());
m_MdnsBrowser = new QMdnsEngine::Browser(m_MdnsServer.data(), "_nvstream._tcp.local."); m_MdnsBrowser = new QMdnsEngine::Browser(m_MdnsServer.data(), "_nvstream._tcp.local.");
@@ -782,9 +784,10 @@ private:
return serverInfo; return serverInfo;
} catch (...) { } catch (...) {
if (!m_Mdns) { if (!m_Mdns) {
unsigned int portTestResult; StreamingPreferences prefs;
int portTestResult;
if (m_ComputerManager->m_Prefs->detectNetworkBlocking) { if (prefs.detectNetworkBlocking) {
// We failed to connect to the specified PC. Let's test to make sure this network // We failed to connect to the specified PC. Let's test to make sure this network
// isn't blocking Moonlight, so we can tell the user about it. // isn't blocking Moonlight, so we can tell the user about it.
portTestResult = LiTestClientConnectivity("qt.conntest.moonlight-stream.org", 443, portTestResult = LiTestClientConnectivity("qt.conntest.moonlight-stream.org", 443,
+6 -20
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "nvcomputer.h" #include "nvcomputer.h"
#include "settings/streamingpreferences.h" #include "nvpairingmanager.h"
#include "settings/compatfetcher.h" #include "settings/compatfetcher.h"
#include <qmdnsengine/server.h> #include <qmdnsengine/server.h>
@@ -72,15 +72,9 @@ private slots:
void handleResolvedTimeout() void handleResolvedTimeout()
{ {
if (m_Addresses.isEmpty()) { if (m_Addresses.isEmpty()) {
if (m_Retries-- > 0) { // Try again
// Try again qInfo() << "Resolving" << hostname() << "timed out. Retrying...";
qInfo() << "Resolving" << hostname() << "timed out. Retrying..."; resolve();
resolve();
}
else {
qWarning() << "Giving up on resolving" << hostname() << "after repeated failures";
cleanup();
}
} }
else { else {
Q_ASSERT(!m_Addresses.isEmpty()); Q_ASSERT(!m_Addresses.isEmpty());
@@ -98,7 +92,7 @@ signals:
void resolvedHost(MdnsPendingComputer*,QVector<QHostAddress>&); void resolvedHost(MdnsPendingComputer*,QVector<QHostAddress>&);
private: private:
void cleanup() void resolve()
{ {
// Delete our resolver, so we're guaranteed that nothing is referencing m_Server. // Delete our resolver, so we're guaranteed that nothing is referencing m_Server.
delete m_Resolver; delete m_Resolver;
@@ -107,12 +101,6 @@ private:
// Now delete our strong reference that we held on behalf of m_Resolver. // Now delete our strong reference that we held on behalf of m_Resolver.
// The server may be destroyed after we make this call. // The server may be destroyed after we make this call.
m_Server.reset(); m_Server.reset();
}
void resolve()
{
// Clean up any existing resolver object and server references
cleanup();
// Re-acquire a strong reference if the server still exists. // Re-acquire a strong reference if the server still exists.
m_Server = m_ServerWeak.toStrongRef(); m_Server = m_ServerWeak.toStrongRef();
@@ -132,7 +120,6 @@ private:
QSharedPointer<QMdnsEngine::Server> m_Server; QSharedPointer<QMdnsEngine::Server> m_Server;
QMdnsEngine::Resolver* m_Resolver; QMdnsEngine::Resolver* m_Resolver;
QVector<QHostAddress> m_Addresses; QVector<QHostAddress> m_Addresses;
int m_Retries = 10;
}; };
class ComputerPollingEntry class ComputerPollingEntry
@@ -218,7 +205,7 @@ class ComputerManager : public QObject
friend class DelayedFlushThread; friend class DelayedFlushThread;
public: public:
explicit ComputerManager(StreamingPreferences* prefs); explicit ComputerManager(QObject *parent = nullptr);
virtual ~ComputerManager(); virtual ~ComputerManager();
@@ -270,7 +257,6 @@ private:
void startPollingComputer(NvComputer* computer); void startPollingComputer(NvComputer* computer);
StreamingPreferences* m_Prefs;
int m_PollingRef; int m_PollingRef;
QReadWriteLock m_Lock; QReadWriteLock m_Lock;
QMap<QString, NvComputer*> m_KnownHosts; QMap<QString, NvComputer*> m_KnownHosts;
-7
View File
@@ -6,13 +6,6 @@ ComputerSeeker::ComputerSeeker(ComputerManager *manager, QString computerName, Q
: QObject(parent), m_ComputerManager(manager), m_ComputerName(computerName), : QObject(parent), m_ComputerManager(manager), m_ComputerName(computerName),
m_TimeoutTimer(new QTimer(this)) m_TimeoutTimer(new QTimer(this))
{ {
// If we know this computer, send a WOL packet to wake it up in case it is asleep.
for (NvComputer * computer: m_ComputerManager->getComputers()) {
if (this->matchComputer(computer)) {
computer->wake();
}
}
m_TimeoutTimer->setSingleShot(true); m_TimeoutTimer->setSingleShot(true);
connect(m_TimeoutTimer, &QTimer::timeout, connect(m_TimeoutTimer, &QTimer::timeout,
this, &ComputerSeeker::onTimeout); this, &ComputerSeeker::onTimeout);
+2 -10
View File
@@ -95,14 +95,6 @@ void IdentityManager::createCredentials(QSettings& settings)
BIO_free(biokey); BIO_free(biokey);
BIO_free(biocert); BIO_free(biocert);
// Check that the new keypair is valid before persisting it
if (getSslCertificate().isNull()) {
qFatal("Newly generated certificate is unreadable");
}
if (getSslKey().isNull()) {
qFatal("Newly generated private key is unreadable");
}
settings.setValue(SER_CERT, m_CachedPemCert); settings.setValue(SER_CERT, m_CachedPemCert);
settings.setValue(SER_KEY, m_CachedPrivateKey); settings.setValue(SER_KEY, m_CachedPrivateKey);
@@ -131,10 +123,10 @@ IdentityManager::IdentityManager()
// We should have valid credentials now. If not, we're screwed // We should have valid credentials now. If not, we're screwed
if (getSslCertificate().isNull()) { if (getSslCertificate().isNull()) {
qFatal("Certificate is unreadable"); qFatal("Newly generated certificate is unreadable");
} }
if (getSslKey().isNull()) { if (getSslKey().isNull()) {
qFatal("Private key is unreadable"); qFatal("Newly generated private key is unreadable");
} }
} }
+2 -16
View File
@@ -373,7 +373,6 @@ NvComputer::ReachabilityType NvComputer::getActiveAddressReachability() const
s.connectToHost(copyOfActiveAddress.address(), copyOfActiveAddress.port()); s.connectToHost(copyOfActiveAddress.address(), copyOfActiveAddress.port());
if (s.waitForConnected(3000)) { if (s.waitForConnected(3000)) {
Q_ASSERT(!s.localAddress().isNull()); Q_ASSERT(!s.localAddress().isNull());
Q_ASSERT(!s.peerAddress().isNull());
for (const QNetworkInterface& nic : QNetworkInterface::allInterfaces()) { for (const QNetworkInterface& nic : QNetworkInterface::allInterfaces()) {
// Ensure the interface is up // Ensure the interface is up
@@ -407,19 +406,6 @@ NvComputer::ReachabilityType NvComputer::getActiveAddressReachability() const
return ReachabilityType::RI_VPN; return ReachabilityType::RI_VPN;
} }
#ifdef Q_OS_WINDOWS
if (nic.name().startsWith("iftype53_") || nic.name().startsWith("iftype131_")) {
// Match by NDIS interface type. These values are Microsoft's recommended values for VPN connections:
// https://learn.microsoft.com/en-US/troubleshoot/windows-client/networking/windows-connection-manager-disconnects-wlan#more-information
//
// The following VPNs use IF_TYPE_PROP_VIRTUAL under Windows:
// - WireguardNT VPNs
// - All WinTun-based VPNs (such as Slack Nebula)
// - OpenVPN with tap-windows6
return ReachabilityType::RI_VPN;
}
#endif
if (nic.hardwareAddress().startsWith("00:FF", Qt::CaseInsensitive)) { if (nic.hardwareAddress().startsWith("00:FF", Qt::CaseInsensitive)) {
// OpenVPN TAP interfaces have a MAC address starting with 00:FF on Windows // OpenVPN TAP interfaces have a MAC address starting with 00:FF on Windows
return ReachabilityType::RI_VPN; return ReachabilityType::RI_VPN;
@@ -435,9 +421,9 @@ NvComputer::ReachabilityType NvComputer::getActiveAddressReachability() const
return ReachabilityType::RI_VPN; return ReachabilityType::RI_VPN;
} }
// Didn't meet any of our VPN heuristics. Let's see if the peer address is on-link. // Didn't meet any of our VPN heuristics. Let's see if it's on-link.
Q_ASSERT(addr.prefixLength() >= 0); Q_ASSERT(addr.prefixLength() >= 0);
if (addr.prefixLength() >= 0 && s.localAddress().isInSubnet(s.peerAddress(), addr.prefixLength())) { if (addr.prefixLength() >= 0 && s.localAddress().isInSubnet(addr.ip(), addr.prefixLength())) {
return ReachabilityType::RI_LAN; return ReachabilityType::RI_LAN;
} }
+1 -2
View File
@@ -223,8 +223,7 @@ NvHTTP::startApp(QString verb,
"&surroundAudioInfo="+QString::number(SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(streamConfig->audioConfiguration))+ "&surroundAudioInfo="+QString::number(SURROUNDAUDIOINFO_FROM_AUDIO_CONFIGURATION(streamConfig->audioConfiguration))+
"&remoteControllersBitmap="+QString::number(gamepadMask)+ "&remoteControllersBitmap="+QString::number(gamepadMask)+
"&gcmap="+QString::number(gamepadMask)+ "&gcmap="+QString::number(gamepadMask)+
"&gcpersist="+QString::number(persistGameControllersOnDisconnect ? 1 : 0)+ "&gcpersist="+QString::number(persistGameControllersOnDisconnect ? 1 : 0),
LiGetLaunchUrlQueryParameters(),
LAUNCH_TIMEOUT_MS); LAUNCH_TIMEOUT_MS);
qInfo() << "Launch response:" << response; qInfo() << "Launch response:" << response;
+2 -2
View File
@@ -298,8 +298,8 @@ NvPairingManager::pair(QString appVersion, QString pin, QSslCertificate& serverC
} }
QByteArray pairingSecret = NvHTTP::getXmlStringFromHex(respXml, "pairingsecret"); QByteArray pairingSecret = NvHTTP::getXmlStringFromHex(respXml, "pairingsecret");
QByteArray serverSecret = pairingSecret.left(16); QByteArray serverSecret = QByteArray(pairingSecret.data(), 16);
QByteArray serverSignature = pairingSecret.mid(16); QByteArray serverSignature = QByteArray(&pairingSecret.data()[16], 256);
if (!verifySignature(serverSecret, if (!verifySignature(serverSecret,
serverSignature, serverSignature,
+21 -29
View File
@@ -74,7 +74,6 @@ SystemProperties::SystemProperties()
Q_ASSERT(!monitorRefreshRates.isEmpty()); Q_ASSERT(!monitorRefreshRates.isEmpty());
Q_ASSERT(!monitorNativeResolutions.isEmpty()); Q_ASSERT(!monitorNativeResolutions.isEmpty());
Q_ASSERT(!monitorSafeAreaResolutions.isEmpty());
} }
QRect SystemProperties::getNativeResolution(int displayIndex) QRect SystemProperties::getNativeResolution(int displayIndex)
@@ -83,12 +82,6 @@ QRect SystemProperties::getNativeResolution(int displayIndex)
return monitorNativeResolutions.value(displayIndex); return monitorNativeResolutions.value(displayIndex);
} }
QRect SystemProperties::getSafeAreaResolution(int displayIndex)
{
// Returns default constructed QRect if out of bounds
return monitorSafeAreaResolutions.value(displayIndex);
}
int SystemProperties::getRefreshRate(int displayIndex) int SystemProperties::getRefreshRate(int displayIndex)
{ {
// Returns 0 if out of bounds // Returns 0 if out of bounds
@@ -128,7 +121,7 @@ void SystemProperties::querySdlVideoInfoInternal()
{ {
hasHardwareAcceleration = false; hasHardwareAcceleration = false;
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_VIDEO))) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s", "SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
SDL_GetError()); SDL_GetError());
@@ -139,15 +132,21 @@ void SystemProperties::querySdlVideoInfoInternal()
// We call the internal variant because we're already in a safe thread context. // We call the internal variant because we're already in a safe thread context.
refreshDisplaysInternal(); refreshDisplaysInternal();
SDL_Window* testWindow = SDLC_CreateWindowWithFallback("", 0, 0, 1280, 720, SDL_Window* testWindow = SDL_CreateWindow("", 0, 0, 1280, 720,
SDL_WINDOW_HIDDEN, SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags());
StreamUtils::getPlatformWindowFlags());
if (!testWindow) { if (!testWindow) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create window for hardware decode test: %s", "Failed to create test window with platform flags: %s",
SDL_GetError()); SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return; testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
if (!testWindow) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to create window for hardware decode test: %s",
SDL_GetError());
SDL_QuitSubSystem(SDL_INIT_VIDEO);
return;
}
} }
Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, supportsHdr, maximumResolution); Session::getDecoderInfo(testWindow, hasHardwareAcceleration, rendererAlwaysFullScreen, supportsHdr, maximumResolution);
@@ -188,7 +187,7 @@ void SystemProperties::refreshDisplays()
void SystemProperties::refreshDisplaysInternal() void SystemProperties::refreshDisplaysInternal()
{ {
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_VIDEO))) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s", "SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
SDL_GetError()); SDL_GetError());
@@ -197,18 +196,13 @@ void SystemProperties::refreshDisplaysInternal()
monitorNativeResolutions.clear(); monitorNativeResolutions.clear();
int numDisplays = 0;
SDL_DisplayID *displays = SDL_GetDisplays(&numDisplays);
SDL_DisplayMode bestMode; SDL_DisplayMode bestMode;
for (int i = 0; i < numDisplays; i++) { for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
SDL_DisplayMode desktopMode; SDL_DisplayMode desktopMode;
SDL_Rect safeArea;
if (StreamUtils::getNativeDesktopMode(displays[i], &desktopMode, &safeArea)) { if (StreamUtils::getNativeDesktopMode(displayIndex, &desktopMode)) {
if (desktopMode.w <= 8192 && desktopMode.h <= 8192) { if (desktopMode.w <= 8192 && desktopMode.h <= 8192) {
monitorNativeResolutions.insert(i, QRect(0, 0, desktopMode.w, desktopMode.h)); monitorNativeResolutions.insert(displayIndex, QRect(0, 0, desktopMode.w, desktopMode.h));
monitorSafeAreaResolutions.insert(i, QRect(0, 0, safeArea.w, safeArea.h));
} }
else { else {
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
@@ -218,10 +212,9 @@ void SystemProperties::refreshDisplaysInternal()
// Start at desktop mode and work our way up // Start at desktop mode and work our way up
bestMode = desktopMode; bestMode = desktopMode;
int numDisplayModes = SDL_GetNumDisplayModes(displays[i]); for (int i = 0; i < SDL_GetNumDisplayModes(displayIndex); i++) {
for (int i = 0; i < numDisplayModes; i++) {
SDL_DisplayMode mode; SDL_DisplayMode mode;
if (SDL_GetDisplayMode(displays[i], i, &mode) == 0) { if (SDL_GetDisplayMode(displayIndex, i, &mode) == 0) {
if (mode.w == desktopMode.w && mode.h == desktopMode.h) { if (mode.w == desktopMode.w && mode.h == desktopMode.h) {
if (mode.refresh_rate > bestMode.refresh_rate) { if (mode.refresh_rate > bestMode.refresh_rate) {
bestMode = mode; bestMode = mode;
@@ -244,6 +237,5 @@ void SystemProperties::refreshDisplaysInternal()
} }
} }
SDL_free(displays);
SDL_QuitSubSystem(SDL_INIT_VIDEO); SDL_QuitSubSystem(SDL_INIT_VIDEO);
} }
-2
View File
@@ -30,7 +30,6 @@ public:
Q_INVOKABLE void refreshDisplays(); Q_INVOKABLE void refreshDisplays();
Q_INVOKABLE QRect getNativeResolution(int displayIndex); Q_INVOKABLE QRect getNativeResolution(int displayIndex);
Q_INVOKABLE QRect getSafeAreaResolution(int displayIndex);
Q_INVOKABLE int getRefreshRate(int displayIndex); Q_INVOKABLE int getRefreshRate(int displayIndex);
signals: signals:
@@ -53,7 +52,6 @@ private:
QString unmappedGamepads; QString unmappedGamepads;
QSize maximumResolution; QSize maximumResolution;
QList<QRect> monitorNativeResolutions; QList<QRect> monitorNativeResolutions;
QList<QRect> monitorSafeAreaResolutions;
QList<int> monitorRefreshRates; QList<int> monitorRefreshRates;
QString versionString; QString versionString;
bool supportsHdr; bool supportsHdr;
+5 -18
View File
@@ -316,7 +316,6 @@ StreamCommandLineParser::StreamCommandLineParser()
{"auto", StreamingPreferences::VCC_AUTO}, {"auto", StreamingPreferences::VCC_AUTO},
{"H.264", StreamingPreferences::VCC_FORCE_H264}, {"H.264", StreamingPreferences::VCC_FORCE_H264},
{"HEVC", StreamingPreferences::VCC_FORCE_HEVC}, {"HEVC", StreamingPreferences::VCC_FORCE_HEVC},
{"AV1", StreamingPreferences::VCC_FORCE_AV1},
}; };
m_VideoDecoderMap = { m_VideoDecoderMap = {
{"auto", StreamingPreferences::VDS_AUTO}, {"auto", StreamingPreferences::VDS_AUTO},
@@ -372,9 +371,6 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction"); parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction");
parser.addToggleOption("swap-gamepad-buttons", "swap A/B and X/Y gamepad buttons (Nintendo-style)"); parser.addToggleOption("swap-gamepad-buttons", "swap A/B and X/Y gamepad buttons (Nintendo-style)");
parser.addToggleOption("keep-awake", "prevent display sleep while streaming"); parser.addToggleOption("keep-awake", "prevent display sleep while streaming");
parser.addToggleOption("performance-overlay", "show performance overlay");
parser.addToggleOption("hdr", "HDR streaming");
parser.addToggleOption("yuv444", "YUV 4:4:4 sampling, if supported");
parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys()); parser.addChoiceOption("capture-system-keys", "capture system key combos", m_CaptureSysKeysModeMap.keys());
parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys()); parser.addChoiceOption("video-codec", "video codec", m_VideoCodecMap.keys());
parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys()); parser.addChoiceOption("video-decoder", "video decoder", m_VideoDecoderMap.keys());
@@ -413,20 +409,20 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
// Resolve --fps option // Resolve --fps option
if (parser.isSet("fps")) { if (parser.isSet("fps")) {
preferences->fps = parser.getIntOption("fps"); preferences->fps = parser.getIntOption("fps");
if (!inRange(preferences->fps, 10, 480)) { if (!inRange(preferences->fps, 30, 240)) {
fprintf(stderr, "Warning: FPS is out of the supported range (10 - 480 FPS). Performance may suffer!\n"); parser.showError("FPS must be in range: 30 - 240");
} }
} }
// Resolve --bitrate option // Resolve --bitrate option
if (parser.isSet("bitrate")) { if (parser.isSet("bitrate")) {
preferences->bitrateKbps = parser.getIntOption("bitrate"); preferences->bitrateKbps = parser.getIntOption("bitrate");
if (!inRange(preferences->bitrateKbps, 500, 500000)) { if (!inRange(preferences->bitrateKbps, 500, 150000)) {
fprintf(stderr, "Warning: Bitrate is out of the supported range (500 - 500000 Kbps). Performance may suffer!\n"); parser.showError("Bitrate must be in range: 500 - 150000");
} }
} else if (displaySet || parser.isSet("fps")) { } else if (displaySet || parser.isSet("fps")) {
preferences->bitrateKbps = preferences->getDefaultBitrate( preferences->bitrateKbps = preferences->getDefaultBitrate(
preferences->width, preferences->height, preferences->fps, preferences->enableYUV444); preferences->width, preferences->height, preferences->fps);
} }
// Resolve --packet-size option // Resolve --packet-size option
@@ -489,15 +485,6 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
// Resolve --keep-awake and --no-keep-awake options // Resolve --keep-awake and --no-keep-awake options
preferences->keepAwake = parser.getToggleOptionValue("keep-awake", preferences->keepAwake); preferences->keepAwake = parser.getToggleOptionValue("keep-awake", preferences->keepAwake);
// Resolve --performance-overlay and --no-performance-overlay options
preferences->showPerformanceOverlay = parser.getToggleOptionValue("performance-overlay", preferences->showPerformanceOverlay);
// Resolve --hdr and --no-hdr options
preferences->enableHdr = parser.getToggleOptionValue("hdr", preferences->enableHdr);
// Resolve --yuv444 and --no-yuv444 options
preferences->enableYUV444 = parser.getToggleOptionValue("yuv444", preferences->enableYUV444);
// Resolve --capture-system-keys option // Resolve --capture-system-keys option
if (parser.isSet("capture-system-keys")) { if (parser.isSet("capture-system-keys")) {
preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys")); preferences->captureSysKeysMode = mapValue(m_CaptureSysKeysModeMap, parser.getChoiceOptionValue("capture-system-keys"));
+1 -1
View File
@@ -7,7 +7,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QTimer> #include <QTimer>
#define COMPUTER_SEEK_TIMEOUT 30000 #define COMPUTER_SEEK_TIMEOUT 10000
#define APP_SEEK_TIMEOUT 10000 #define APP_SEEK_TIMEOUT 10000
namespace CliListApps namespace CliListApps
+1 -1
View File
@@ -6,7 +6,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QTimer> #include <QTimer>
#define COMPUTER_SEEK_TIMEOUT 30000 #define COMPUTER_SEEK_TIMEOUT 10000
#define APP_SEEK_TIMEOUT 10000 #define APP_SEEK_TIMEOUT 10000
namespace CliStartStream namespace CliStartStream
@@ -1,40 +0,0 @@
From 78261eb6e2fe728fa5d3843b5b8962b1ca559b7e Mon Sep 17 00:00:00 2001
From: David Rosca <nowrep@gmail.com>
Date: Sat, 16 Dec 2023 14:52:01 +0100
Subject: [PATCH] Vulkan: Don't try to reuse old swapchain
---
src/vulkan/swapchain.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/src/vulkan/swapchain.c b/src/vulkan/swapchain.c
index 0646e57c..c0b07ce4 100644
--- a/src/vulkan/swapchain.c
+++ b/src/vulkan/swapchain.c
@@ -612,13 +612,21 @@ static bool vk_sw_recreate(pl_swapchain sw, int w, int h)
}
#endif
+ {
+ pl_gpu_flush(gpu);
+ vk_wait_idle(vk);
+ for (int i = 0; i < vk->pool_graphics->num_queues; i++)
+ vk->QueueWaitIdle(vk->pool_graphics->queues[i]);
+ vk->DestroySwapchainKHR(vk->dev, p->swapchain, PL_VK_ALLOC);
+ }
+
// Calling `vkCreateSwapchainKHR` puts sinfo.oldSwapchain into a retired
// state whether the call succeeds or not, so we always need to garbage
// collect it afterwards - asynchronously as it may still be in use
- sinfo.oldSwapchain = p->swapchain;
+ /* sinfo.oldSwapchain = p->swapchain; */
p->swapchain = VK_NULL_HANDLE;
VkResult res = vk->CreateSwapchainKHR(vk->dev, &sinfo, PL_VK_ALLOC, &p->swapchain);
- vk_dev_callback(vk, VK_CB_FUNC(destroy_swapchain), vk, vk_wrap_handle(sinfo.oldSwapchain));
+ /* vk_dev_callback(vk, VK_CB_FUNC(destroy_swapchain), vk, vk_wrap_handle(sinfo.oldSwapchain)); */
PL_VK_ASSERT(res, "vk->CreateSwapchainKHR(...)");
// Get the new swapchain images
--
2.43.0
@@ -34,78 +34,6 @@
</screenshots> </screenshots>
<releases> <releases>
<release version="6.1.0" date="2024-09-16">
<description>
<p>New features:</p>
<ul>
<li>Experimental YUV 4:4:4 support for improved text clarity during remote desktop usage</li>
<li>HDR is now supported with software decoding (requires GPU with Vulkan support)</li>
<li>Bitrate limit can now be increased to 500 Mbps</li>
<li>Audio decoding now uses 32-bit floating point format</li>
</ul>
<p>Bugfixes:</p>
<ul>
<li>Fixed incorrect color range when streaming with AV1 from a host with an AMD GPU</li>
<li>Updated community-contributed translations from Weblate</li>
</ul>
</description>
</release>
<release version="6.0.1" date="2024-06-30">
<description>
<p>New features:</p>
<ul>
<li>HDR to SDR tonemapping is now supported by the Vulkan renderer on Linux</li>
</ul>
<p>Behavior Changes:</p>
<ul>
<li>More time is now provided for PCs to wake up before displaying an error when starting a stream from the CLI</li>
<li>Moonlight will no longer try to guess VA driver names when running libva 2.20 or later</li>
</ul>
<p>Bugfixes:</p>
<ul>
<li>Fixed crash when the Vulkan renderer executed on a system with no Vulkan devices</li>
<li>Updated community-contributed translations from Weblate</li>
</ul>
</description>
</release>
<release version="6.0.0" date="2024-06-06">
<description>
<p>New features:</p>
<ul>
<li>HDR is now supported on Steam Deck and other HDR-capable Linux systems using a new Vulkan-based renderer</li>
<li>Vulkan Video decoding of H.264, HEVC, and AV1 is now supported using the new Vulkan renderer</li>
<li>Full E2E stream encryption is now supported when streaming from Sunshine v0.22 or later</li>
<li>Initiating a stream via the command-line will now automatically wake the target machine if it is sleeping</li>
<li>Error codes are now displayed in the connection termination dialog</li>
<li>Detailed PC state information is now available via the new "View Details" context menu option (similar to the Android client)</li>
<li>The performance overlay can now be configured to be shown by default when starting a stream</li>
</ul>
<p>Behavior Changes:</p>
<ul>
<li>The selected bitrate is no longer silently adjusted by Moonlight based upon the video codec or HDR mode</li>
<li>The selected mouse mode when starting a stream no longer influences the acceleration curve when the mouse mode is toggled using the Ctrl+Alt+Shift+M key combo while streaming</li>
<li>Hardcoded fallback paths for VAAPI and VDPAU drivers are no longer used</li>
<li>Per-session keys (rikey and rikeyid values) are now automatically stripped from logs</li>
<li>Log messages will now be logged to stderr rather than stdout</li>
<li>EGL is now always used instead of GLX for loading OpenGL in X11 environments on non-x86 platforms</li>
</ul>
<p>Bugfixes:</p>
<ul>
<li>Improved reliability of streaming during momentary drops of WiFi connections</li>
<li>Improved performance with high polling rate mice</li>
<li>Improved input latency when a gamepad is connected</li>
<li>Added missing command-line options to control HDR and AV1 codec usage</li>
<li>Fixed instant connection termination error when streaming over the Internet behind certain Carrier-Grade NAT devices</li>
<li>Fixed incorrect MTU detection when streaming over the Internet without a VPN</li>
<li>Fixed recovery of audio when no audio output device is present when the stream starts</li>
<li>Fixed merging of gamepad state when multi-controller mode is disabled</li>
<li>Fixed indefinitely resending mDNS queries when a host could not be resolved</li>
<li>Fixed inability to pair when the host is not using a RSA-2048 key</li>
<li>Updated included gamepad mappings</li>
<li>Updated community-contributed translations from Weblate</li>
</ul>
</description>
</release>
<release version="5.0.1" date="2023-11-02"> <release version="5.0.1" date="2023-11-02">
<description> <description>
<p>Bugfixes:</p> <p>Bugfixes:</p>
+1 -5
View File
@@ -5,13 +5,9 @@
# pairing data will be lost each reboot. # pairing data will be lost each reboot.
HOME=/usr/local/moonlight HOME=/usr/local/moonlight
# Enable Steam Controller detection in SDL
# https://github.com/moonlight-stream/moonlight-qt/issues/697
export SDL_ENABLE_STEAM_CONTROLLERS=1
# Renice PE_Single_CPU which seems to host A/V stuff # Renice PE_Single_CPU which seems to host A/V stuff
renice -10 -p $(pidof PE_Single_CPU) renice -10 -p $(pidof PE_Single_CPU)
# Renice Moonlight itself to avoid preemption by background tasks # Renice Moonlight itself to avoid preemption by background tasks
# Write output to a logfile in /tmp # Write output to a logfile in /tmp
exec nice -n -10 ./bin/moonlight > /tmp/moonlight.log 2>&1 exec nice -n -10 ./bin/moonlight > /tmp/moonlight.log
+2 -2
View File
@@ -256,7 +256,7 @@ CenteredGridView {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.RightButton; acceptedButtons: Qt.RightButton;
onClicked: { onClicked: {
parent.pressAndHold() parent.onPressAndHold()
} }
} }
@@ -350,7 +350,7 @@ CenteredGridView {
function quitApp() { function quitApp() {
var component = Qt.createComponent("QuitSegue.qml") var component = Qt.createComponent("QuitSegue.qml")
var params = {"appName": appName, "quitRunningAppFn": function() { appModel.quitRunningApp() }} var params = {"appName": appName, "quitRunningAppFn": appModel.quitRunningApp}
if (segueToStream) { if (segueToStream) {
// Store the session and app name if we're going to stream after // Store the session and app name if we're going to stream after
// successfully quitting the old app. // successfully quitting the old app.
+5
View File
@@ -2,6 +2,7 @@ import QtQuick 2.0
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import ComputerManager 1.0 import ComputerManager 1.0
import SdlGamepadKeyNavigation 1.0
Item { Item {
function onSearchingComputer() { function onSearchingComputer() {
@@ -38,6 +39,10 @@ Item {
if (!launcher.isExecuted()) { if (!launcher.isExecuted()) {
toolBar.visible = false toolBar.visible = false
// Normally this is enabled by PcView, but we will won't
// load PcView when streaming from the command-line.
SdlGamepadKeyNavigation.enable()
launcher.searchingComputer.connect(onSearchingComputer) launcher.searchingComputer.connect(onSearchingComputer)
launcher.pairing.connect(onPairing) launcher.pairing.connect(onPairing)
launcher.failed.connect(onFailed) launcher.failed.connect(onFailed)
+6 -1
View File
@@ -2,6 +2,7 @@ import QtQuick 2.0
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import ComputerManager 1.0 import ComputerManager 1.0
import SdlGamepadKeyNavigation 1.0
Item { Item {
function onSearchingComputer() { function onSearchingComputer() {
@@ -37,6 +38,10 @@ Item {
if (!launcher.isExecuted()) { if (!launcher.isExecuted()) {
toolBar.visible = false toolBar.visible = false
// Normally this is enabled by PcView, but we will won't
// load PcView when streaming from the command-line.
SdlGamepadKeyNavigation.enable()
launcher.searchingComputer.connect(onSearchingComputer) launcher.searchingComputer.connect(onSearchingComputer)
launcher.searchingApp.connect(onSearchingApp) launcher.searchingApp.connect(onSearchingApp)
launcher.sessionCreated.connect(onSessionCreated) launcher.sessionCreated.connect(onSessionCreated)
@@ -80,7 +85,7 @@ Item {
function quitApp() { function quitApp() {
var component = Qt.createComponent("QuitSegue.qml") var component = Qt.createComponent("QuitSegue.qml")
var params = {"appName": appName, "quitRunningAppFn": function() { launcher.quitRunningApp() }} var params = {"appName": appName, "quitRunningAppFn": launcher.quitRunningApp}
stackView.push(component.createObject(stackView, params)) stackView.push(component.createObject(stackView, params))
} }
+6 -18
View File
@@ -6,7 +6,6 @@ import ComputerModel 1.0
import ComputerManager 1.0 import ComputerManager 1.0
import StreamingPreferences 1.0 import StreamingPreferences 1.0
import SystemProperties 1.0
import SdlGamepadKeyNavigation 1.0 import SdlGamepadKeyNavigation 1.0
CenteredGridView { CenteredGridView {
@@ -34,6 +33,11 @@ CenteredGridView {
// Setup signals on CM // Setup signals on CM
ComputerManager.computerAddCompleted.connect(addComplete) ComputerManager.computerAddCompleted.connect(addComplete)
// This is a bit of a hack to do this here as opposed to main.qml, but
// we need it enabled before calling getConnectedGamepads() and PcView
// is never destroyed, so it should be okay.
SdlGamepadKeyNavigation.enable()
// Highlight the first item if a gamepad is connected // Highlight the first item if a gamepad is connected
if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) { if (currentIndex == -1 && SdlGamepadKeyNavigation.getConnectedGamepads() > 0) {
currentIndex = 0 currentIndex = 0
@@ -211,14 +215,6 @@ CenteredGridView {
deletePcDialog.open() deletePcDialog.open()
} }
} }
NavigableMenuItem {
parentMenu: pcContextMenu
text: qsTr("View Details")
onTriggered: {
showPcDetailsDialog.pcDetails = model.details
showPcDetailsDialog.open()
}
}
} }
} }
@@ -266,7 +262,7 @@ CenteredGridView {
anchors.fill: parent anchors.fill: parent
acceptedButtons: Qt.RightButton; acceptedButtons: Qt.RightButton;
onClicked: { onClicked: {
parent.pressAndHold() parent.onPressAndHold()
} }
} }
@@ -399,13 +395,5 @@ CenteredGridView {
} }
} }
NavigableMessageDialog {
id: showPcDetailsDialog
property string pcDetails : "";
text: showPcDetailsDialog.pcDetails
imageSrc: "qrc:/res/baseline-help_outline-24px.svg"
standardButtons: Dialog.Ok
}
ScrollBar.vertical: ScrollBar {} ScrollBar.vertical: ScrollBar {}
} }
+114 -163
View File
@@ -133,45 +133,15 @@ Flickable {
AutoResizingComboBox { AutoResizingComboBox {
property int lastIndexValue property int lastIndexValue
function addDetectedResolution(friendlyNamePrefix, rect) {
var indexToAdd = 0
for (var j = 0; j < resolutionComboBox.count; j++) {
var existing_width = parseInt(resolutionListModel.get(j).video_width);
var existing_height = parseInt(resolutionListModel.get(j).video_height);
if (rect.width === existing_width && rect.height === existing_height) {
// Duplicate entry, skip
indexToAdd = -1
break
}
else if (rect.width * rect.height > existing_width * existing_height) {
// Candidate entrypoint after this entry
indexToAdd = j + 1
}
}
// Insert this display's resolution if it's not a duplicate
if (indexToAdd >= 0) {
resolutionListModel.insert(indexToAdd,
{
"text": friendlyNamePrefix+" ("+rect.width+"x"+rect.height+")",
"video_width": ""+rect.width,
"video_height": ""+rect.height,
"is_custom": false
})
}
}
// ignore setting the index at first, and actually set it when the component is loaded // ignore setting the index at first, and actually set it when the component is loaded
Component.onCompleted: { Component.onCompleted: {
// Refresh display data before using it to build the list // Refresh display data before using it to build the list
SystemProperties.refreshDisplays() SystemProperties.refreshDisplays()
// Add native and safe area resolutions for all attached displays // Add native resolutions for all attached displays
var done = false var done = false
for (var displayIndex = 0; !done; displayIndex++) { for (var displayIndex = 0; !done; displayIndex++) {
var screenRect = SystemProperties.getNativeResolution(displayIndex); var screenRect = SystemProperties.getNativeResolution(displayIndex);
var safeAreaRect = SystemProperties.getSafeAreaResolution(displayIndex);
if (screenRect.width === 0) { if (screenRect.width === 0) {
// Exceeded max count of displays // Exceeded max count of displays
@@ -179,8 +149,32 @@ Flickable {
break break
} }
addDetectedResolution(qsTr("Native"), screenRect) var indexToAdd = 0
addDetectedResolution(qsTr("Native (Excluding Notch)"), safeAreaRect) for (var j = 0; j < resolutionComboBox.count; j++) {
var existing_width = parseInt(resolutionListModel.get(j).video_width);
var existing_height = parseInt(resolutionListModel.get(j).video_height);
if (screenRect.width === existing_width && screenRect.height === existing_height) {
// Duplicate entry, skip
indexToAdd = -1
break
}
else if (screenRect.width * screenRect.height > existing_width * existing_height) {
// Candidate entrypoint after this entry
indexToAdd = j + 1
}
}
// Insert this display's resolution if it's not a duplicate
if (indexToAdd >= 0) {
resolutionListModel.insert(indexToAdd,
{
"text": "Native ("+screenRect.width+"x"+screenRect.height+")",
"video_width": ""+screenRect.width,
"video_height": ""+screenRect.height,
"is_custom": false
})
}
} }
// Prune resolutions that are over the decoder's maximum // Prune resolutions that are over the decoder's maximum
@@ -216,7 +210,7 @@ Flickable {
if (!index_set) { if (!index_set) {
// We did not find a match. This must be a custom resolution. // We did not find a match. This must be a custom resolution.
resolutionListModel.append({ resolutionListModel.append({
"text": qsTr("Custom")+" ("+StreamingPreferences.width+"x"+StreamingPreferences.height+")", "text": "Custom ("+StreamingPreferences.width+"x"+StreamingPreferences.height+")",
"video_width": ""+StreamingPreferences.width, "video_width": ""+StreamingPreferences.width,
"video_height": ""+StreamingPreferences.height, "video_height": ""+StreamingPreferences.height,
"is_custom": true "is_custom": true
@@ -225,7 +219,7 @@ Flickable {
} }
else { else {
resolutionListModel.append({ resolutionListModel.append({
"text": qsTr("Custom"), "text": "Custom",
"video_width": "", "video_width": "",
"video_height": "", "video_height": "",
"is_custom": true "is_custom": true
@@ -283,8 +277,7 @@ Flickable {
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width, StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height, StreamingPreferences.height,
StreamingPreferences.fps, StreamingPreferences.fps);
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps slider.value = StreamingPreferences.bitrateKbps
} }
@@ -449,8 +442,7 @@ Flickable {
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width, StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height, StreamingPreferences.height,
StreamingPreferences.fps, StreamingPreferences.fps);
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps slider.value = StreamingPreferences.bitrateKbps
} }
@@ -685,7 +677,7 @@ Flickable {
stepSize: 500 stepSize: 500
from : 500 from : 500
to: StreamingPreferences.unlockBitrate ? 500000 : 150000 to: 150000
snapMode: "SnapOnRelease" snapMode: "SnapOnRelease"
width: Math.min(bitrateDesc.implicitWidth, parent.width) width: Math.min(bitrateDesc.implicitWidth, parent.width)
@@ -697,7 +689,7 @@ Flickable {
Component.onCompleted: { Component.onCompleted: {
// Refresh the text after translations change // Refresh the text after translations change
languageChanged.connect(valueChanged) languageChanged.connect(onValueChanged)
} }
} }
@@ -917,46 +909,6 @@ Flickable {
} }
} }
GroupBox {
id: hostSettingsGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding))
padding: 12
title: "<font color=\"skyblue\">" + qsTr("Host Settings") + "</font>"
font.pointSize: 12
Column {
anchors.fill: parent
spacing: 5
CheckBox {
id: optimizeGameSettingsCheck
width: parent.width
text: qsTr("Optimize game settings for streaming")
font.pointSize: 12
checked: StreamingPreferences.gameOptimizations
onCheckedChanged: {
StreamingPreferences.gameOptimizations = checked
}
}
CheckBox {
id: quitAppAfter
width: parent.width
text: qsTr("Quit app on host PC after ending stream")
font.pointSize: 12
checked: StreamingPreferences.quitAppAfter
onCheckedChanged: {
StreamingPreferences.quitAppAfter = checked
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!")
}
}
}
GroupBox { GroupBox {
id: uiSettingsGroupBox id: uiSettingsGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding)) width: (parent.width - (parent.leftPadding + parent.rightPadding))
@@ -1044,10 +996,10 @@ Flickable {
text: "한국어" // Korean text: "한국어" // Korean
val: StreamingPreferences.LANG_KO val: StreamingPreferences.LANG_KO
} }
ListElement { /* ListElement {
text: "Magyar" // Hungarian text: "Magyar" // Hungarian
val: StreamingPreferences.LANG_HU val: StreamingPreferences.LANG_HU
} } */
ListElement { ListElement {
text: "Nederlands" // Dutch text: "Nederlands" // Dutch
val: StreamingPreferences.LANG_NL val: StreamingPreferences.LANG_NL
@@ -1056,10 +1008,10 @@ Flickable {
text: "Svenska" // Swedish text: "Svenska" // Swedish
val: StreamingPreferences.LANG_SV val: StreamingPreferences.LANG_SV
} }
ListElement { /* ListElement {
text: "Türkçe" // Turkish text: "Türkçe" // Turkish
val: StreamingPreferences.LANG_TR val: StreamingPreferences.LANG_TR
} } */
/* ListElement { /* ListElement {
text: "Українська" // Ukrainian text: "Українська" // Ukrainian
val: StreamingPreferences.LANG_UK val: StreamingPreferences.LANG_UK
@@ -1100,18 +1052,6 @@ Flickable {
text: "עִבְרִית" // Hebrew text: "עִבְרִית" // Hebrew
val: StreamingPreferences.LANG_HE val: StreamingPreferences.LANG_HE
} */ } */
/* ListElement {
text: "کرمانجیی خواروو" // Central Kurdish
val: StreamingPreferences.LANG_CKB
} */
/* ListElement {
text: "Lietuvių kalba" // Lithuanian
val: StreamingPreferences.LANG_LT
} */
/* ListElement {
text: "Eesti" // Estonian
val: StreamingPreferences.LANG_ET
} */
} }
// ::onActivated must be used, as it only listens for when the index is changed by a human // ::onActivated must be used, as it only listens for when the index is changed by a human
onActivated : { onActivated : {
@@ -1409,7 +1349,15 @@ Flickable {
font.pointSize: 12 font.pointSize: 12
checked: StreamingPreferences.swapFaceButtons checked: StreamingPreferences.swapFaceButtons
onCheckedChanged: { onCheckedChanged: {
StreamingPreferences.swapFaceButtons = checked // Check if the value changed (this is called on init too)
if (StreamingPreferences.swapFaceButtons !== checked) {
StreamingPreferences.swapFaceButtons = checked
// Save and restart SdlGamepadKeyNavigation so it can pull the new value
StreamingPreferences.save()
SdlGamepadKeyNavigation.disable()
SdlGamepadKeyNavigation.enable()
}
} }
ToolTip.delay: 1000 ToolTip.delay: 1000
@@ -1466,6 +1414,46 @@ Flickable {
} }
} }
GroupBox {
id: hostSettingsGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding))
padding: 12
title: "<font color=\"skyblue\">" + qsTr("Host Settings") + "</font>"
font.pointSize: 12
Column {
anchors.fill: parent
spacing: 5
CheckBox {
id: optimizeGameSettingsCheck
width: parent.width
text: qsTr("Optimize game settings for streaming")
font.pointSize: 12
checked: StreamingPreferences.gameOptimizations
onCheckedChanged: {
StreamingPreferences.gameOptimizations = checked
}
}
CheckBox {
id: quitAppAfter
width: parent.width
text: qsTr("Quit app on host PC after ending stream")
font.pointSize: 12
checked: StreamingPreferences.quitAppAfter
onCheckedChanged: {
StreamingPreferences.quitAppAfter = checked
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("This will close the app or game you are streaming when you end your stream. You will lose any unsaved progress!")
}
}
}
GroupBox { GroupBox {
id: advancedSettingsGroupBox id: advancedSettingsGroupBox
width: (parent.width - (parent.leftPadding + parent.rightPadding)) width: (parent.width - (parent.leftPadding + parent.rightPadding))
@@ -1502,6 +1490,7 @@ Flickable {
id: decoderComboBox id: decoderComboBox
textRole: "text" textRole: "text"
enabled: !enableHdr.checked
model: ListModel { model: ListModel {
id: decoderListModel id: decoderListModel
ListElement { ListElement {
@@ -1523,6 +1512,21 @@ Flickable {
StreamingPreferences.videoDecoderSelection = decoderListModel.get(currentIndex).val StreamingPreferences.videoDecoderSelection = decoderListModel.get(currentIndex).val
} }
} }
// This handles the state of the enableHdr checkbox changing
onEnabledChanged: {
if (enabled) {
StreamingPreferences.videoDecoderSelection = decoderListModel.get(currentIndex).val
}
else {
StreamingPreferences.videoDecoderSelection = StreamingPreferences.VDS_AUTO
}
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered && !enabled
ToolTip.text: qsTr("Enabling HDR overrides manual decoder selections.")
} }
Label { Label {
@@ -1605,53 +1609,6 @@ Flickable {
qsTr("HDR streaming is not supported on this PC.") qsTr("HDR streaming is not supported on this PC.")
} }
CheckBox {
id: enableYUV444
width: parent.width
text: qsTr("Enable YUV 4:4:4 (Experimental)")
font.pointSize: 12
checked: StreamingPreferences.enableYUV444
onCheckedChanged: {
// This is called on init, so only reset to default bitrate when checked state changes.
if (StreamingPreferences.enableYUV444 != checked) {
StreamingPreferences.enableYUV444 = checked
StreamingPreferences.bitrateKbps = StreamingPreferences.getDefaultBitrate(StreamingPreferences.width,
StreamingPreferences.height,
StreamingPreferences.fps,
StreamingPreferences.enableYUV444);
slider.value = StreamingPreferences.bitrateKbps
}
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: enabled ?
qsTr("Good for streaming desktop and text-heavy games, but not recommended for fast-paced games.")
:
qsTr("YUV 4:4:4 is not supported on this PC.")
}
CheckBox {
id: unlockBitrate
width: parent.width
text: qsTr("Unlock bitrate limit (Experimental)")
font.pointSize: 12
checked: StreamingPreferences.unlockBitrate
onCheckedChanged: {
StreamingPreferences.unlockBitrate = checked
StreamingPreferences.bitrateKbps = Math.min(StreamingPreferences.bitrateKbps, slider.to)
slider.value = StreamingPreferences.bitrateKbps
}
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("This unlocks extremely high video bitrates for use with Sunshine hosts. It should only be used when streaming over an Ethernet LAN connection.")
}
CheckBox { CheckBox {
id: enableMdns id: enableMdns
width: parent.width width: parent.width
@@ -1664,6 +1621,10 @@ Flickable {
if (StreamingPreferences.enableMdns != checked) { if (StreamingPreferences.enableMdns != checked) {
StreamingPreferences.enableMdns = checked StreamingPreferences.enableMdns = checked
// We must save the updated preference to ensure
// ComputerManager can observe the change internally.
StreamingPreferences.save()
// Restart polling so the mDNS change takes effect // Restart polling so the mDNS change takes effect
if (window.pollingActive) { if (window.pollingActive) {
ComputerManager.stopPollingAsync() ComputerManager.stopPollingAsync()
@@ -1680,26 +1641,16 @@ Flickable {
font.pointSize: 12 font.pointSize: 12
checked: StreamingPreferences.detectNetworkBlocking checked: StreamingPreferences.detectNetworkBlocking
onCheckedChanged: { onCheckedChanged: {
StreamingPreferences.detectNetworkBlocking = checked // This is called on init, so only do the work if we've
} // actually changed the value.
} if (StreamingPreferences.detectNetworkBlocking != checked) {
StreamingPreferences.detectNetworkBlocking = checked
CheckBox { // We must save the updated preference to ensure
id: showPerformanceOverlay // ComputerManager can observe the change internally.
width: parent.width StreamingPreferences.save()
text: qsTr("Show performance stats while streaming") }
font.pointSize: 12
checked: StreamingPreferences.showPerformanceOverlay
onCheckedChanged: {
StreamingPreferences.showPerformanceOverlay = checked
} }
ToolTip.delay: 1000
ToolTip.timeout: 5000
ToolTip.visible: hovered
ToolTip.text: qsTr("Display real-time stream performance information while streaming.") + "\n\n" +
qsTr("You can toggle it at any time while streaming using Ctrl+Alt+Shift+S or Select+L1+R1+X.") + "\n\n" +
qsTr("The performance overlay is not supported on Steam Link or Raspberry Pi.")
} }
} }
} }
+3 -3
View File
@@ -76,7 +76,7 @@ Item {
streamSegueErrorDialog.text += "\n\n" + qsTr("This PC's Internet connection is blocking Moonlight. Streaming over the Internet may not work while connected to this network.") streamSegueErrorDialog.text += "\n\n" + qsTr("This PC's Internet connection is blocking Moonlight. Streaming over the Internet may not work while connected to this network.")
} }
// Re-enable GUI gamepad usage now // Enable GUI gamepad usage now
SdlGamepadKeyNavigation.enable() SdlGamepadKeyNavigation.enable()
if (quitAfter) { if (quitAfter) {
@@ -119,7 +119,7 @@ Item {
// Show the toolbar again when popped off the stack // Show the toolbar again when popped off the stack
toolBar.visible = true toolBar.visible = true
// Re-enable GUI gamepad usage now // Enable GUI gamepad usage now
SdlGamepadKeyNavigation.enable() SdlGamepadKeyNavigation.enable()
} }
@@ -176,7 +176,7 @@ Item {
gc() gc()
// Run the streaming session to completion // Run the streaming session to completion
session.exec(Window.window) session.exec(Screen.virtualX, Screen.virtualY)
} }
sourceComponent: Item {} sourceComponent: Item {}
-41
View File
@@ -42,46 +42,6 @@ QVariant ComputerModel::data(const QModelIndex& index, int role) const
return computer->state == NvComputer::CS_UNKNOWN; return computer->state == NvComputer::CS_UNKNOWN;
case ServerSupportedRole: case ServerSupportedRole:
return computer->isSupportedServerVersion; return computer->isSupportedServerVersion;
case DetailsRole: {
QString state, pairState;
switch (computer->state) {
case NvComputer::CS_ONLINE:
state = tr("Online");
break;
case NvComputer::CS_OFFLINE:
state = tr("Offline");
break;
default:
state = tr("Unknown");
break;
}
switch (computer->pairState) {
case NvComputer::PS_PAIRED:
pairState = tr("Paired");
break;
case NvComputer::PS_NOT_PAIRED:
pairState = tr("Unpaired");
break;
default:
pairState = tr("Unknown");
break;
}
return tr("Name: %1").arg(computer->name) + '\n' +
tr("Status: %1").arg(state) + '\n' +
tr("Active Address: %1").arg(computer->activeAddress.toString()) + '\n' +
tr("UUID: %1").arg(computer->uuid) + '\n' +
tr("Local Address: %1").arg(computer->localAddress.toString()) + '\n' +
tr("Remote Address: %1").arg(computer->remoteAddress.toString()) + '\n' +
tr("IPv6 Address: %1").arg(computer->ipv6Address.toString()) + '\n' +
tr("Manual Address: %1").arg(computer->manualAddress.toString()) + '\n' +
tr("MAC Address: %1").arg(computer->macAddress.isEmpty() ? tr("Unknown") : QString(computer->macAddress.toHex(':'))) + '\n' +
tr("Pair State: %1").arg(pairState) + '\n' +
tr("Running Game ID: %1").arg(computer->state == NvComputer::CS_ONLINE ? QString::number(computer->currentGameId) : tr("Unknown")) + '\n' +
tr("HTTPS Port: %1").arg(computer->state == NvComputer::CS_ONLINE ? QString::number(computer->activeHttpsPort) : tr("Unknown"));
}
default: default:
return QVariant(); return QVariant();
} }
@@ -109,7 +69,6 @@ QHash<int, QByteArray> ComputerModel::roleNames() const
names[WakeableRole] = "wakeable"; names[WakeableRole] = "wakeable";
names[StatusUnknownRole] = "statusUnknown"; names[StatusUnknownRole] = "statusUnknown";
names[ServerSupportedRole] = "serverSupported"; names[ServerSupportedRole] = "serverSupported";
names[DetailsRole] = "details";
return names; return names;
} }
+1 -2
View File
@@ -15,8 +15,7 @@ class ComputerModel : public QAbstractListModel
BusyRole, BusyRole,
WakeableRole, WakeableRole,
StatusUnknownRole, StatusUnknownRole,
ServerSupportedRole, ServerSupportedRole
DetailsRole
}; };
public: public:
+46 -50
View File
@@ -19,53 +19,26 @@ ApplicationWindow {
property bool clearOnBack: false property bool clearOnBack: false
id: window id: window
visible: true
width: 1280 width: 1280
height: 600 height: 600
// This function runs prior to creation of the initial StackView item // Override the background color to Material 2 colors for Qt 6.5+
function doEarlyInit() { // in order to improve contrast between GFE's placeholder box art
// Override the background color to Material 2 colors for Qt 6.5+ // and the background of the app grid.
// in order to improve contrast between GFE's placeholder box art Component.onCompleted: {
// and the background of the app grid.
if (SystemProperties.usesMaterial3Theme) { if (SystemProperties.usesMaterial3Theme) {
Material.background = "#303030" Material.background = "#303030"
} }
SdlGamepadKeyNavigation.enable()
} }
Component.onCompleted: { visibility: {
// Show the window according to the user's preferences
if (SystemProperties.hasDesktopEnvironment) { if (SystemProperties.hasDesktopEnvironment) {
if (StreamingPreferences.uiDisplayMode == StreamingPreferences.UI_MAXIMIZED) { if (StreamingPreferences.uiDisplayMode == StreamingPreferences.UI_WINDOWED) return "Windowed"
window.showMaximized() else if (StreamingPreferences.uiDisplayMode == StreamingPreferences.UI_MAXIMIZED) return "Maximized"
} else if (StreamingPreferences.uiDisplayMode == StreamingPreferences.UI_FULLSCREEN) return "FullScreen"
else if (StreamingPreferences.uiDisplayMode == StreamingPreferences.UI_FULLSCREEN) {
window.showFullScreen()
}
else {
window.show()
}
} else { } else {
window.showFullScreen() return "FullScreen"
}
// Display any modal dialogs for configuration warnings
if (SystemProperties.isWow64) {
wow64Dialog.open()
}
else if (!SystemProperties.hasHardwareAcceleration) {
if (SystemProperties.isRunningXWayland) {
xWaylandDialog.open()
}
else {
noHwDecoderDialog.open()
}
}
if (SystemProperties.unmappedGamepads) {
unmappedGamepadDialog.unmappedGamepads = SystemProperties.unmappedGamepads
unmappedGamepadDialog.open()
} }
} }
@@ -86,16 +59,10 @@ ApplicationWindow {
StackView { StackView {
id: stackView id: stackView
initialItem: initialView
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Component.onCompleted: {
// Perform our early initialization before constructing
// the initial view and pushing it to the StackView
doEarlyInit()
push(initialView)
}
onCurrentItemChanged: { onCurrentItemChanged: {
// Ensure focus travels to the next view when going back // Ensure focus travels to the next view when going back
if (currentItem) { if (currentItem) {
@@ -169,9 +136,6 @@ ApplicationWindow {
pollingActive = true pollingActive = true
} }
} }
// Poll for gamepad input only when the window is in focus
SdlGamepadKeyNavigation.notifyWindowFocus(visible && active)
} }
onActiveChanged: { onActiveChanged: {
@@ -190,9 +154,41 @@ ApplicationWindow {
// if focus does not return within a few minutes. // if focus does not return within a few minutes.
inactivityTimer.restart() inactivityTimer.restart()
} }
}
// Poll for gamepad input only when the window is in focus property bool initialized: false
SdlGamepadKeyNavigation.notifyWindowFocus(visible && active)
// BUG: Using onAfterSynchronizing: here causes very strange
// failures on Linux. Many shaders fail to compile and we
// eventually segfault deep inside the Qt OpenGL code.
onAfterRendering: {
// We use this callback to trigger dialog display because
// it only happens once the window is fully constructed.
// Doing it earlier can lead to the dialog appearing behind
// the window or otherwise without input focus.
if (!initialized) {
// Set initialized before calling anything else, because
// pumping the event loop can cause us to get another
// onAfterRendering call and potentially reenter this code.
initialized = true;
if (SystemProperties.isWow64) {
wow64Dialog.open()
}
else if (!SystemProperties.hasHardwareAcceleration) {
if (SystemProperties.isRunningXWayland) {
xWaylandDialog.open()
}
else {
noHwDecoderDialog.open()
}
}
if (SystemProperties.unmappedGamepads) {
unmappedGamepadDialog.unmappedGamepads = SystemProperties.unmappedGamepads
unmappedGamepadDialog.open()
}
}
} }
// Workaround for lack of instanceof in Qt 5.9. // Workaround for lack of instanceof in Qt 5.9.
@@ -287,7 +283,7 @@ ApplicationWindow {
visible: SystemProperties.hasBrowser && visible: SystemProperties.hasBrowser &&
qmltypeof(stackView.currentItem, "SettingsView") qmltypeof(stackView.currentItem, "SettingsView")
iconSource: "qrc:/res/discord.svg" iconSource: "qrc:/res/Discord-Logo-White.svg"
ToolTip.delay: 1000 ToolTip.delay: 1000
ToolTip.timeout: 3000 ToolTip.timeout: 3000
+60 -81
View File
@@ -4,16 +4,15 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QWindow> #include <QWindow>
#include "settings/streamingpreferences.h"
#include "settings/mappingmanager.h" #include "settings/mappingmanager.h"
#define AXIS_NAVIGATION_REPEAT_DELAY 150 #define AXIS_NAVIGATION_REPEAT_DELAY 150
SdlGamepadKeyNavigation::SdlGamepadKeyNavigation(StreamingPreferences* prefs) SdlGamepadKeyNavigation::SdlGamepadKeyNavigation()
: m_Prefs(prefs), : m_Enabled(false),
m_Enabled(false),
m_UiNavMode(false), m_UiNavMode(false),
m_FirstPoll(false), m_FirstPoll(false),
m_HasFocus(false),
m_LastAxisNavigationEventTime(0) m_LastAxisNavigationEventTime(0)
{ {
m_PollingTimer = new QTimer(this); m_PollingTimer = new QTimer(this);
@@ -37,7 +36,7 @@ void SdlGamepadKeyNavigation::enable()
// arrival events. Additionally, there's a race condition between // arrival events. Additionally, there's a race condition between
// our QML objects being destroyed and SDL being deinitialized that // our QML objects being destroyed and SDL being deinitialized that
// this solves too. // this solves too.
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_GAMEPAD))) { if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s", "SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) failed: %s",
SDL_GetError()); SDL_GetError());
@@ -52,23 +51,25 @@ void SdlGamepadKeyNavigation::enable()
// overlapping lifetimes of SdlGamepadKeyNavigation instances, so we // overlapping lifetimes of SdlGamepadKeyNavigation instances, so we
// will attach ourselves. // will attach ourselves.
SDL_PumpEvents(); SDL_PumpEvents();
SDL_FlushEvent(SDL_EVENT_GAMEPAD_ADDED); SDL_FlushEvent(SDL_CONTROLLERDEVICEADDED);
// Open all currently attached game controllers // Open all currently attached game controllers
int numGamepads = 0; for (int i = 0; i < SDL_NumJoysticks(); i++) {
SDL_JoystickID* gamepads = SDL_GetGamepads(&numGamepads); if (SDL_IsGameController(i)) {
for (int i = 0; i < numGamepads; i++) { SDL_GameController* gc = SDL_GameControllerOpen(i);
SDL_Gamepad * gc = SDL_OpenGamepad(i); if (gc != nullptr) {
if (gc != nullptr) { m_Gamepads.append(gc);
m_Gamepads.append(gc); }
} }
} }
SDL_free(gamepads);
// Flush events on the first poll
m_FirstPoll = true;
// Poll every 50 ms for a new joystick event
m_PollingTimer->start(50);
m_Enabled = true; m_Enabled = true;
// Start the polling timer if the window is focused
updateTimerState();
} }
void SdlGamepadKeyNavigation::disable() void SdlGamepadKeyNavigation::disable()
@@ -77,73 +78,68 @@ void SdlGamepadKeyNavigation::disable()
return; return;
} }
m_Enabled = false; m_PollingTimer->stop();
updateTimerState();
Q_ASSERT(!m_PollingTimer->isActive());
while (!m_Gamepads.isEmpty()) { while (!m_Gamepads.isEmpty()) {
SDL_CloseGamepad(m_Gamepads[0]); SDL_GameControllerClose(m_Gamepads[0]);
m_Gamepads.removeAt(0); m_Gamepads.removeAt(0);
} }
SDL_QuitSubSystem(SDL_INIT_GAMEPAD); SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
}
void SdlGamepadKeyNavigation::notifyWindowFocus(bool hasFocus) m_Enabled = false;
{
m_HasFocus = hasFocus;
updateTimerState();
} }
void SdlGamepadKeyNavigation::onPollingTimerFired() void SdlGamepadKeyNavigation::onPollingTimerFired()
{ {
SDL_Event event; SDL_Event event;
StreamingPreferences prefs;
// Discard any pending button events on the first poll to avoid picking up // Discard any pending button events on the first poll to avoid picking up
// stale input data from the stream session (like the quit combo). // stale input data from the stream session (like the quit combo).
if (m_FirstPoll) { if (m_FirstPoll) {
SDL_PumpEvents(); SDL_PumpEvents();
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_DOWN); SDL_FlushEvent(SDL_CONTROLLERBUTTONDOWN);
SDL_FlushEvent(SDL_EVENT_GAMEPAD_BUTTON_UP); SDL_FlushEvent(SDL_CONTROLLERBUTTONUP);
m_FirstPoll = false; m_FirstPoll = false;
} }
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_EVENT_QUIT : case SDL_QUIT:
// SDL may send us a quit event since we initialize // SDL may send us a quit event since we initialize
// the video subsystem on startup. If we get one, // the video subsystem on startup. If we get one,
// forward it on for Qt to take care of. // forward it on for Qt to take care of.
QCoreApplication::instance()->quit(); QCoreApplication::instance()->quit();
break; break;
case SDL_EVENT_GAMEPAD_BUTTON_DOWN : case SDL_CONTROLLERBUTTONDOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP : case SDL_CONTROLLERBUTTONUP:
{ {
QEvent::Type type = QEvent::Type type =
event.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ? event.type == SDL_CONTROLLERBUTTONDOWN ?
QEvent::Type::KeyPress : QEvent::Type::KeyRelease; QEvent::Type::KeyPress : QEvent::Type::KeyRelease;
// Swap face buttons if needed // Swap face buttons if needed
if (m_Prefs->swapFaceButtons) { if (prefs.swapFaceButtons) {
switch (event.gbutton.button) { switch (event.cbutton.button) {
case SDL_GAMEPAD_BUTTON_SOUTH : case SDL_CONTROLLER_BUTTON_A:
event.gbutton.button = SDL_GAMEPAD_BUTTON_EAST; event.cbutton.button = SDL_CONTROLLER_BUTTON_B;
break; break;
case SDL_GAMEPAD_BUTTON_EAST : case SDL_CONTROLLER_BUTTON_B:
event.gbutton.button = SDL_GAMEPAD_BUTTON_SOUTH; event.cbutton.button = SDL_CONTROLLER_BUTTON_A;
break; break;
case SDL_GAMEPAD_BUTTON_WEST : case SDL_CONTROLLER_BUTTON_X:
event.gbutton.button = SDL_GAMEPAD_BUTTON_NORTH; event.cbutton.button = SDL_CONTROLLER_BUTTON_Y;
break; break;
case SDL_GAMEPAD_BUTTON_NORTH : case SDL_CONTROLLER_BUTTON_Y:
event.gbutton.button = SDL_GAMEPAD_BUTTON_WEST; event.cbutton.button = SDL_CONTROLLER_BUTTON_X;
break; break;
} }
} }
switch (event.gbutton.button) { switch (event.cbutton.button) {
case SDL_GAMEPAD_BUTTON_DPAD_UP : case SDL_CONTROLLER_BUTTON_DPAD_UP:
if (m_UiNavMode) { if (m_UiNavMode) {
// Back-tab // Back-tab
sendKey(type, Qt::Key_Tab, Qt::ShiftModifier); sendKey(type, Qt::Key_Tab, Qt::ShiftModifier);
@@ -152,7 +148,7 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Up); sendKey(type, Qt::Key_Up);
} }
break; break;
case SDL_GAMEPAD_BUTTON_DPAD_DOWN : case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
if (m_UiNavMode) { if (m_UiNavMode) {
sendKey(type, Qt::Key_Tab); sendKey(type, Qt::Key_Tab);
} }
@@ -160,13 +156,13 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Down); sendKey(type, Qt::Key_Down);
} }
break; break;
case SDL_GAMEPAD_BUTTON_DPAD_LEFT : case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
sendKey(type, Qt::Key_Left); sendKey(type, Qt::Key_Left);
break; break;
case SDL_GAMEPAD_BUTTON_DPAD_RIGHT : case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
sendKey(type, Qt::Key_Right); sendKey(type, Qt::Key_Right);
break; break;
case SDL_GAMEPAD_BUTTON_SOUTH : case SDL_CONTROLLER_BUTTON_A:
if (m_UiNavMode) { if (m_UiNavMode) {
sendKey(type, Qt::Key_Space); sendKey(type, Qt::Key_Space);
} }
@@ -174,14 +170,14 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
sendKey(type, Qt::Key_Return); sendKey(type, Qt::Key_Return);
} }
break; break;
case SDL_GAMEPAD_BUTTON_EAST : case SDL_CONTROLLER_BUTTON_B:
sendKey(type, Qt::Key_Escape); sendKey(type, Qt::Key_Escape);
break; break;
case SDL_GAMEPAD_BUTTON_WEST : case SDL_CONTROLLER_BUTTON_X:
sendKey(type, Qt::Key_Menu); sendKey(type, Qt::Key_Menu);
break; break;
case SDL_GAMEPAD_BUTTON_NORTH : case SDL_CONTROLLER_BUTTON_Y:
case SDL_GAMEPAD_BUTTON_START : case SDL_CONTROLLER_BUTTON_START:
// HACK: We use this keycode to inform main.qml // HACK: We use this keycode to inform main.qml
// to show the settings when Key_Menu is handled // to show the settings when Key_Menu is handled
// by the control in focus. // by the control in focus.
@@ -192,18 +188,11 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
} }
break; break;
} }
case SDL_EVENT_GAMEPAD_ADDED : case SDL_CONTROLLERDEVICEADDED:
#if SDL_VERSION_ATLEAST(3, 0, 0) SDL_GameController* gc = SDL_GameControllerOpen(event.cdevice.which);
SDL_Gamepad* gc = SDL_OpenGamepad(event.gdevice.which);
if (gc != nullptr) {
SDL_assert(!m_Gamepads.contains(gc));
m_Gamepads.append(gc);
}
#else
SDL_Gamepad* gc = SDL_GameControllerOpen(event.cdevice.which);
if (gc != nullptr) { if (gc != nullptr) {
// SDL_CONTROLLERDEVICEADDED can be reported multiple times for the same // SDL_CONTROLLERDEVICEADDED can be reported multiple times for the same
// gamepad in rare cases, because SDL2 doesn't fixup the device index in // gamepad in rare cases, because SDL doesn't fixup the device index in
// the SDL_CONTROLLERDEVICEADDED event if an unopened gamepad disappears // the SDL_CONTROLLERDEVICEADDED event if an unopened gamepad disappears
// before we've processed the add event. // before we've processed the add event.
if (!m_Gamepads.contains(gc)) { if (!m_Gamepads.contains(gc)) {
@@ -211,18 +200,17 @@ void SdlGamepadKeyNavigation::onPollingTimerFired()
} }
else { else {
// We already have this game controller open // We already have this game controller open
SDL_CloseGamepad(gc); SDL_GameControllerClose(gc);
} }
} }
#endif
break; break;
} }
} }
// Handle analog sticks by polling // Handle analog sticks by polling
for (auto gc : m_Gamepads) { for (auto gc : m_Gamepads) {
short leftX = SDL_GetGamepadAxis(gc, SDL_GAMEPAD_AXIS_LEFTX); short leftX = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTX);
short leftY = SDL_GetGamepadAxis(gc, SDL_GAMEPAD_AXIS_LEFTY); short leftY = SDL_GameControllerGetAxis(gc, SDL_CONTROLLER_AXIS_LEFTY);
if (SDL_GetTicks() - m_LastAxisNavigationEventTime < AXIS_NAVIGATION_REPEAT_DELAY) { if (SDL_GetTicks() - m_LastAxisNavigationEventTime < AXIS_NAVIGATION_REPEAT_DELAY) {
// Do nothing // Do nothing
} }
@@ -274,20 +262,6 @@ void SdlGamepadKeyNavigation::sendKey(QEvent::Type type, Qt::Key key, Qt::Keyboa
} }
} }
void SdlGamepadKeyNavigation::updateTimerState()
{
if (m_PollingTimer->isActive() && (!m_HasFocus || !m_Enabled)) {
m_PollingTimer->stop();
}
else if (!m_PollingTimer->isActive() && m_HasFocus && m_Enabled) {
// Flush events on the first poll
m_FirstPoll = true;
// Poll every 50 ms for a new joystick event
m_PollingTimer->start(50);
}
}
void SdlGamepadKeyNavigation::setUiNavMode(bool uiNavMode) void SdlGamepadKeyNavigation::setUiNavMode(bool uiNavMode)
{ {
m_UiNavMode = uiNavMode; m_UiNavMode = uiNavMode;
@@ -298,6 +272,11 @@ int SdlGamepadKeyNavigation::getConnectedGamepads()
Q_ASSERT(m_Enabled); Q_ASSERT(m_Enabled);
int count = 0; int count = 0;
SDL_free(SDL_GetGamepads(&count)); for (int i = 0; i < SDL_NumJoysticks(); i++) {
if (SDL_IsGameController(i)) {
count++;
}
}
return count; return count;
} }
+3 -11
View File
@@ -3,16 +3,14 @@
#include <QTimer> #include <QTimer>
#include <QEvent> #include <QEvent>
#include "SDL_compat.h" #include <SDL.h>
#include "settings/streamingpreferences.h"
class SdlGamepadKeyNavigation : public QObject class SdlGamepadKeyNavigation : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
SdlGamepadKeyNavigation(StreamingPreferences* prefs); SdlGamepadKeyNavigation();
~SdlGamepadKeyNavigation(); ~SdlGamepadKeyNavigation();
@@ -20,8 +18,6 @@ public:
Q_INVOKABLE void disable(); Q_INVOKABLE void disable();
Q_INVOKABLE void notifyWindowFocus(bool hasFocus);
Q_INVOKABLE void setUiNavMode(bool settingsMode); Q_INVOKABLE void setUiNavMode(bool settingsMode);
Q_INVOKABLE int getConnectedGamepads(); Q_INVOKABLE int getConnectedGamepads();
@@ -29,18 +25,14 @@ public:
private: private:
void sendKey(QEvent::Type type, Qt::Key key, Qt::KeyboardModifiers modifiers = Qt::NoModifier); void sendKey(QEvent::Type type, Qt::Key key, Qt::KeyboardModifiers modifiers = Qt::NoModifier);
void updateTimerState();
private slots: private slots:
void onPollingTimerFired(); void onPollingTimerFired();
private: private:
StreamingPreferences* m_Prefs;
QTimer* m_PollingTimer; QTimer* m_PollingTimer;
QList<SDL_Gamepad*> m_Gamepads; QList<SDL_GameController*> m_Gamepads;
bool m_Enabled; bool m_Enabled;
bool m_UiNavMode; bool m_UiNavMode;
bool m_FirstPoll; bool m_FirstPoll;
bool m_HasFocus;
Uint32 m_LastAxisNavigationEventTime; Uint32 m_LastAxisNavigationEventTime;
}; };
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+268 -451
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+193 -372
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
+219 -402
View File
File diff suppressed because it is too large. Load diff
+189 -364
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+189 -364
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+184 -367
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+245 -428
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
File diff suppressed because it is too large. Load diff
Binary file not shown.
+186 -365
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+195 -370
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+237 -420
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+305 -484
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+494 -677
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+197 -376
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+196 -379
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+183 -366
View File
File diff suppressed because it is too large. Load diff
+66 -159
View File
@@ -10,14 +10,13 @@
#include <QFont> #include <QFont>
#include <QCursor> #include <QCursor>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QTemporaryFile> #include <QFile>
#include <QRegularExpression>
// Don't let SDL hook our main function, since Qt is already // Don't let SDL hook our main function, since Qt is already
// doing the same thing. This needs to be before any headers // doing the same thing. This needs to be before any headers
// that might include SDL.h themselves. // that might include SDL.h themselves.
#define SDL_MAIN_HANDLED #define SDL_MAIN_HANDLED
#include "SDL_compat.h" #include <SDL.h>
#ifdef HAVE_FFMPEG #ifdef HAVE_FFMPEG
#include "streaming/video/ffmpeg.h" #include "streaming/video/ffmpeg.h"
@@ -25,9 +24,6 @@
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
#include "antihookingprotection.h" #include "antihookingprotection.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
#include <openssl/ssl.h> #include <openssl/ssl.h>
#endif #endif
@@ -48,87 +44,59 @@
#include "settings/streamingpreferences.h" #include "settings/streamingpreferences.h"
#include "gui/sdlgamepadkeynavigation.h" #include "gui/sdlgamepadkeynavigation.h"
#if defined(Q_OS_WIN32) #if !defined(QT_DEBUG) && defined(Q_OS_WIN32)
#define IS_UNSPECIFIED_HANDLE(x) ((x) == INVALID_HANDLE_VALUE || (x) == NULL) // Log to file for release Windows builds
#define USE_CUSTOM_LOGGER
// Log to file or console dynamically for Windows builds
#define LOG_TO_FILE #define LOG_TO_FILE
#elif defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
// Use stdout logger on all Linux/BSD builds
#define USE_CUSTOM_LOGGER
#elif !defined(QT_DEBUG) && defined(Q_OS_DARWIN) #elif !defined(QT_DEBUG) && defined(Q_OS_DARWIN)
// Log to file for release Mac builds // Log to file for release Mac builds
#define USE_CUSTOM_LOGGER
#define LOG_TO_FILE #define LOG_TO_FILE
#else #else
// Log to console for debug Mac builds // For debug Windows and Mac builds, use default logger
#endif #endif
#ifdef USE_CUSTOM_LOGGER
static QElapsedTimer s_LoggerTime; static QElapsedTimer s_LoggerTime;
static QTextStream s_LoggerStream(stderr); static QTextStream s_LoggerStream(stdout);
static QThreadPool s_LoggerThread; static QMutex s_LoggerLock;
static bool s_SuppressVerboseOutput; static bool s_SuppressVerboseOutput;
static QRegularExpression k_RikeyRegex("&rikey=\\w+");
static QRegularExpression k_RikeyIdRegex("&rikeyid=[\\d-]+");
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
// Max log file size of 10 MB // Max log file size of 10 MB
static const uint64_t k_MaxLogSizeBytes = 10 * 1024 * 1024; #define MAX_LOG_SIZE_BYTES (10 * 1024 * 1024)
static QAtomicInteger<uint64_t> s_LogBytesWritten = 0; static int s_LogBytesWritten = 0;
static bool s_LogLimitReached = false;
static QFile* s_LoggerFile; static QFile* s_LoggerFile;
#endif #endif
class LoggerTask : public QRunnable
{
public:
LoggerTask(const QString& msg) : m_Msg(msg)
{
setAutoDelete(true);
}
void run() override
{
s_LoggerStream << m_Msg;
s_LoggerStream.flush();
}
private:
QString m_Msg;
};
void logToLoggerStream(QString& message) void logToLoggerStream(QString& message)
{ {
#if defined(QT_DEBUG) && defined(Q_OS_WIN32) QMutexLocker lock(&s_LoggerLock);
// Output log messages to a debugger if attached
if (IsDebuggerPresent()) {
static QString lineBuffer;
lineBuffer += message;
if (message.endsWith('\n')) {
OutputDebugStringW(lineBuffer.toStdWString().c_str());
lineBuffer.clear();
}
}
#endif
// Strip session encryption keys and IVs from the logs
message.replace(k_RikeyRegex, "&rikey=REDACTED");
message.replace(k_RikeyIdRegex, "&rikeyid=REDACTED");
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
auto oldLogSize = s_LogBytesWritten.fetchAndAddRelaxed(message.size()); if (s_LogLimitReached) {
if (oldLogSize >= k_MaxLogSizeBytes) {
return; return;
} }
else if (oldLogSize >= k_MaxLogSizeBytes - message.size()) { else if (s_LogBytesWritten >= MAX_LOG_SIZE_BYTES) {
s_LoggerThread.waitForDone();
s_LoggerStream << "Log size limit reached!"; s_LoggerStream << "Log size limit reached!";
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
s_LoggerStream << Qt::endl; s_LoggerStream << Qt::endl;
#else #else
s_LoggerStream << endl; s_LoggerStream << endl;
#endif #endif
s_LoggerStream.flush(); s_LogLimitReached = true;
return; return;
} }
else {
s_LogBytesWritten += message.size();
}
#endif #endif
// Queue the log message to be written asynchronously s_LoggerStream << message;
s_LoggerThread.start(new LoggerTask(message)); s_LoggerStream.flush();
} }
void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message) void sdlLogToDiskHandler(void*, int category, SDL_LogPriority priority, const char* message)
@@ -248,6 +216,8 @@ void ffmpegLogToDiskHandler(void* ptr, int level, const char* fmt, va_list vl)
#endif #endif
#endif
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
@@ -336,31 +306,16 @@ int main(int argc, char *argv[])
qputenv("QML_DISK_CACHE_PATH", Path::getQmlCacheDir().toUtf8()); qputenv("QML_DISK_CACHE_PATH", Path::getQmlCacheDir().toUtf8());
} }
#ifdef Q_OS_WIN32 #ifdef USE_CUSTOM_LOGGER
// Grab the original std handles before we potentially redirect them later
HANDLE oldConOut = GetStdHandle(STD_OUTPUT_HANDLE);
HANDLE oldConErr = GetStdHandle(STD_ERROR_HANDLE);
#endif
#ifdef LOG_TO_FILE #ifdef LOG_TO_FILE
QDir tempDir(Path::getLogDir()); QDir tempDir(Path::getLogDir());
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
#ifdef Q_OS_WIN32 if (s_LoggerFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
// Only log to a file if the user didn't redirect stderr somewhere else QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
if (IS_UNSPECIFIED_HANDLE(oldConErr)) s_LoggerStream.setDevice(s_LoggerFile);
#endif
{
s_LoggerFile = new QFile(tempDir.filePath(QString("Moonlight-%1.log").arg(QDateTime::currentSecsSinceEpoch())));
if (s_LoggerFile->open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream(stderr) << "Redirecting log output to " << s_LoggerFile->fileName() << Qt::endl;
s_LoggerStream.setDevice(s_LoggerFile);
}
} }
#endif #endif
// Serialize log messages on a single thread
s_LoggerThread.setMaxThreadCount(1);
s_LoggerTime.start(); s_LoggerTime.start();
qInstallMessageHandler(qtLogToDiskHandler); qInstallMessageHandler(qtLogToDiskHandler);
SDL_LogSetOutputFunction(sdlLogToDiskHandler, nullptr); SDL_LogSetOutputFunction(sdlLogToDiskHandler, nullptr);
@@ -369,6 +324,8 @@ int main(int argc, char *argv[])
av_log_set_callback(ffmpegLogToDiskHandler); av_log_set_callback(ffmpegLogToDiskHandler);
#endif #endif
#endif
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
// Create a crash dump when we crash on Windows // Create a crash dump when we crash on Windows
SetUnhandledExceptionFilter(UnhandledExceptionHandler); SetUnhandledExceptionFilter(UnhandledExceptionHandler);
@@ -394,11 +351,6 @@ int main(int argc, char *argv[])
SSL_free(nullptr); SSL_free(nullptr);
#endif #endif
// We keep this at function scope to ensure it stays around while we're running,
// becaue the Qt QPA will need to read it. Since the temporary file is only
// created when open() is called, this doesn't do any harm for other platforms.
QTemporaryFile eglfsConfigFile("eglfs_override_XXXXXX.conf");
// Avoid using High DPI on EGLFS. It breaks font rendering. // Avoid using High DPI on EGLFS. It breaks font rendering.
// https://bugreports.qt.io/browse/QTBUG-64377 // https://bugreports.qt.io/browse/QTBUG-64377
// //
@@ -432,17 +384,6 @@ int main(int argc, char *argv[])
qWarning() << "Unable to find a KMSDRM display device!"; qWarning() << "Unable to find a KMSDRM display device!";
qWarning() << "On the Raspberry Pi, you must enable the 'fake KMS' driver in raspi-config to use Moonlight outside of the GUI environment."; qWarning() << "On the Raspberry Pi, you must enable the 'fake KMS' driver in raspi-config to use Moonlight outside of the GUI environment.";
} }
else if (!qEnvironmentVariableIsSet("QT_QPA_EGLFS_KMS_CONFIG")) {
// HACK: Remove this when Qt is fixed to properly check for display support before picking a card
QString cardOverride = WMUtils::getDrmCardOverride();
if (!cardOverride.isEmpty()) {
if (eglfsConfigFile.open()) {
qInfo() << "Overriding default Qt EGLFS card selection to" << cardOverride;
QTextStream(&eglfsConfigFile) << "{ \"device\": \"" << cardOverride << "\" }";
qputenv("QT_QPA_EGLFS_KMS_CONFIG", eglfsConfigFile.fileName().toUtf8());
}
}
}
} }
// EGLFS uses OpenGLES 2.0, so we will too. Some embedded platforms may not // EGLFS uses OpenGLES 2.0, so we will too. Some embedded platforms may not
@@ -452,18 +393,9 @@ int main(int argc, char *argv[])
#endif #endif
} }
#ifndef Q_PROCESSOR_X86
// Some ARM and RISC-V embedded devices don't have working GLX which can cause
// SDL to fail to find a working OpenGL implementation at all. Let's force EGL
// on non-x86 platforms, since GLX is deprecated anyway.
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
#endif
#ifdef Q_OS_MACOS
// This avoids using the default keychain for SSL, which may cause // This avoids using the default keychain for SSL, which may cause
// password prompts on macOS. // password prompts on macOS.
qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1"); qputenv("QT_SSL_USE_TEMPORARY_KEYCHAIN", "1");
#endif
#if defined(Q_OS_WIN32) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #if defined(Q_OS_WIN32) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
if (!qEnvironmentVariableIsSet("QT_OPENGL")) { if (!qEnvironmentVariableIsSet("QT_OPENGL")) {
@@ -486,12 +418,6 @@ int main(int argc, char *argv[])
qputenv("QSG_RENDER_LOOP", "basic"); qputenv("QSG_RENDER_LOOP", "basic");
#endif #endif
#if defined(Q_OS_DARWIN) && defined(QT_DEBUG)
// Enable Metal valiation for debug builds
qputenv("MTL_DEBUG_LAYER", "1");
qputenv("MTL_SHADER_VALIDATION", "1");
#endif
// We don't want system proxies to apply to us // We don't want system proxies to apply to us
QNetworkProxyFactory::setUseSystemConfiguration(false); QNetworkProxyFactory::setUseSystemConfiguration(false);
@@ -507,15 +433,21 @@ int main(int argc, char *argv[])
// initializing the SDL video subsystem to have any effect. // initializing the SDL video subsystem to have any effect.
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1"); SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
// For SDL backends that support it, use double buffering instead of triple buffering
// to save a frame of latency. This doesn't matter for MMAL or DRM renderers since they
// are drawing directly to the screen without involving SDL, but it may matter for other
// future KMSDRM platforms that use SDL for rendering.
SDL_SetHint(SDL_HINT_VIDEO_DOUBLE_BUFFER, "1");
// We use MMAL to render on Raspberry Pi, so we do not require DRM master. // We use MMAL to render on Raspberry Pi, so we do not require DRM master.
SDL_SetHint(SDL_HINT_KMSDRM_REQUIRE_DRM_MASTER, "0"); SDL_SetHint("SDL_KMSDRM_REQUIRE_DRM_MASTER", "0");
// Use Direct3D 9Ex to avoid a deadlock caused by the D3D device being reset when // Use Direct3D 9Ex to avoid a deadlock caused by the D3D device being reset when
// the user triggers a UAC prompt. This option controls the software/SDL renderer. // the user triggers a UAC prompt. This option controls the software/SDL renderer.
// The DXVA2 renderer uses Direct3D 9Ex itself directly. // The DXVA2 renderer uses Direct3D 9Ex itself directly.
SDL_SetHint(SDL_HINT_WINDOWS_USE_D3D9EX, "1"); SDL_SetHint("SDL_WINDOWS_USE_D3D9EX", "1");
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_TIMER))) { if (SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_TIMER) failed: %s", "SDL_InitSubSystem(SDL_INIT_TIMER) failed: %s",
SDL_GetError()); SDL_GetError());
@@ -525,7 +457,7 @@ int main(int argc, char *argv[])
#ifdef STEAM_LINK #ifdef STEAM_LINK
// Steam Link requires that we initialize video before creating our // Steam Link requires that we initialize video before creating our
// QGuiApplication in order to configure the framebuffer correctly. // QGuiApplication in order to configure the framebuffer correctly.
if (SDLC_FAILURE(SDL_InitSubSystem(SDL_INIT_VIDEO)) { if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s", "SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
SDL_GetError()); SDL_GetError());
@@ -548,28 +480,21 @@ int main(int argc, char *argv[])
// SDL 2.0.12 changes the default behavior to use the button label rather than the button // SDL 2.0.12 changes the default behavior to use the button label rather than the button
// position as most other software does. Set this back to 0 to stay consistent with prior // position as most other software does. Set this back to 0 to stay consistent with prior
// releases of Moonlight. // releases of Moonlight.
SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); SDL_SetHint("SDL_GAMECONTROLLER_USE_BUTTON_LABELS", "0");
// Disable relative mouse scaling to renderer size or logical DPI. We want to send // Disable relative mouse scaling to renderer size or logical DPI. We want to send
// the mouse motion exactly how it was given to us. // the mouse motion exactly how it was given to us.
SDL_SetHint(SDL_HINT_MOUSE_RELATIVE_SCALING, "0"); SDL_SetHint("SDL_MOUSE_RELATIVE_SCALING", "0");
// Set our app name for SDL to use with PulseAudio and PipeWire. This matches what we // Set our app name for SDL to use with PulseAudio and PipeWire. This matches what we
// provide as our app name to libsoundio too. On SDL 2.0.18+, SDL_APP_NAME is also used // provide as our app name to libsoundio too. On SDL 2.0.18+, SDL_APP_NAME is also used
// for screensaver inhibitor reporting. // for screensaver inhibitor reporting.
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Moonlight"); SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "Moonlight");
SDL_SetHint(SDL_HINT_APP_NAME, "Moonlight"); SDL_SetHint("SDL_APP_NAME", "Moonlight");
// We handle capturing the mouse ourselves when it leaves the window, so we don't need // We handle capturing the mouse ourselves when it leaves the window, so we don't need
// SDL doing it for us behind our backs. // SDL doing it for us behind our backs.
SDL_SetHint(SDL_HINT_MOUSE_AUTO_CAPTURE, "0"); SDL_SetHint("SDL_MOUSE_AUTO_CAPTURE", "0");
// SDL will try to lock the mouse cursor on Wayland if it's not visible in order to
// support applications that assume they can warp the cursor (which isn't possible
// on Wayland). We don't want this behavior because it interferes with seamless mouse
// mode when toggling between windowed and fullscreen modes by unexpectedly locking
// the mouse cursor.
SDL_SetHint(SDL_HINT_VIDEO_WAYLAND_EMULATE_MOUSE_WARP, "0");
#ifdef QT_DEBUG #ifdef QT_DEBUG
// Allow thread naming using exceptions on debug builds. SDL doesn't use SEH // Allow thread naming using exceptions on debug builds. SDL doesn't use SEH
@@ -580,34 +505,25 @@ int main(int argc, char *argv[])
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
#ifndef STEAM_LINK
// Force use of the KMSDRM backend for SDL when using Qt platform plugins
// that directly draw to the display without a windowing system.
if (QGuiApplication::platformName() == "eglfs" || QGuiApplication::platformName() == "linuxfb") {
qputenv("SDL_VIDEODRIVER", "kmsdrm");
}
#endif
GlobalCommandLineParser parser; GlobalCommandLineParser parser;
GlobalCommandLineParser::ParseResult commandLineParserResult = parser.parse(app.arguments()); GlobalCommandLineParser::ParseResult commandLineParserResult = parser.parse(app.arguments());
switch (commandLineParserResult) { switch (commandLineParserResult) {
case GlobalCommandLineParser::ListRequested: case GlobalCommandLineParser::ListRequested:
#ifdef USE_CUSTOM_LOGGER
// Don't log to the console since it will jumble the command output // Don't log to the console since it will jumble the command output
s_SuppressVerboseOutput = true; s_SuppressVerboseOutput = true;
#endif
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
// If we don't have stdout or stderr handles (which will normally be the case // Attach to the console to be able to print output.
// since we're a /SUBSYSTEM:WINDOWS app), attach to our parent console and use // Since we're a /SUBSYSTEM:WINDOWS app, we won't be attached by default.
// that for stdout and stderr.
//
// If we do have stdout or stderr handles, that means the user has used standard
// handle redirection. In that case, we don't want to override those handles.
if (AttachConsole(ATTACH_PARENT_PROCESS)) { if (AttachConsole(ATTACH_PARENT_PROCESS)) {
// If we didn't have an old stdout/stderr handle, use the new CONOUT$ handle HANDLE conOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (IS_UNSPECIFIED_HANDLE(oldConOut)) { if (conOut != INVALID_HANDLE_VALUE && conOut != NULL) {
freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stdout);
setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stdout, NULL, _IONBF, 0);
} }
if (IS_UNSPECIFIED_HANDLE(oldConErr)) { HANDLE conErr = GetStdHandle(STD_ERROR_HANDLE);
if (conErr != INVALID_HANDLE_VALUE && conErr != NULL) {
freopen("CONOUT$", "w", stderr); freopen("CONOUT$", "w", stderr);
setvbuf(stderr, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0);
} }
@@ -631,7 +547,8 @@ int main(int argc, char *argv[])
runtimeVersion.major, runtimeVersion.minor, runtimeVersion.patch); runtimeVersion.major, runtimeVersion.minor, runtimeVersion.patch);
// Apply the initial translation based on user preference // Apply the initial translation based on user preference
StreamingPreferences::get()->retranslate(); StreamingPreferences prefs;
prefs.retranslate();
// Trickily declare the translation for dialog buttons // Trickily declare the translation for dialog buttons
QCoreApplication::translate("QPlatformTheme", "&Yes"); QCoreApplication::translate("QPlatformTheme", "&Yes");
@@ -696,8 +613,8 @@ int main(int argc, char *argv[])
qmlRegisterUncreatableType<Session>("Session", 1, 0, "Session", "Session cannot be created from QML"); qmlRegisterUncreatableType<Session>("Session", 1, 0, "Session", "Session cannot be created from QML");
qmlRegisterSingletonType<ComputerManager>("ComputerManager", 1, 0, qmlRegisterSingletonType<ComputerManager>("ComputerManager", 1, 0,
"ComputerManager", "ComputerManager",
[](QQmlEngine* qmlEngine, QJSEngine*) -> QObject* { [](QQmlEngine*, QJSEngine*) -> QObject* {
return new ComputerManager(StreamingPreferences::get(qmlEngine)); return new ComputerManager();
}); });
qmlRegisterSingletonType<AutoUpdateChecker>("AutoUpdateChecker", 1, 0, qmlRegisterSingletonType<AutoUpdateChecker>("AutoUpdateChecker", 1, 0,
"AutoUpdateChecker", "AutoUpdateChecker",
@@ -711,13 +628,13 @@ int main(int argc, char *argv[])
}); });
qmlRegisterSingletonType<SdlGamepadKeyNavigation>("SdlGamepadKeyNavigation", 1, 0, qmlRegisterSingletonType<SdlGamepadKeyNavigation>("SdlGamepadKeyNavigation", 1, 0,
"SdlGamepadKeyNavigation", "SdlGamepadKeyNavigation",
[](QQmlEngine* qmlEngine, QJSEngine*) -> QObject* { [](QQmlEngine*, QJSEngine*) -> QObject* {
return new SdlGamepadKeyNavigation(StreamingPreferences::get(qmlEngine)); return new SdlGamepadKeyNavigation();
}); });
qmlRegisterSingletonType<StreamingPreferences>("StreamingPreferences", 1, 0, qmlRegisterSingletonType<StreamingPreferences>("StreamingPreferences", 1, 0,
"StreamingPreferences", "StreamingPreferences",
[](QQmlEngine* qmlEngine, QJSEngine*) -> QObject* { [](QQmlEngine* qmlEngine, QJSEngine*) -> QObject* {
return StreamingPreferences::get(qmlEngine); return new StreamingPreferences(qmlEngine);
}); });
// Create the identity manager on the main thread // Create the identity manager on the main thread
@@ -748,7 +665,7 @@ int main(int argc, char *argv[])
case GlobalCommandLineParser::StreamRequested: case GlobalCommandLineParser::StreamRequested:
{ {
initialView = "qrc:/gui/CliStartStreamSegue.qml"; initialView = "qrc:/gui/CliStartStreamSegue.qml";
StreamingPreferences* preferences = StreamingPreferences::get(); StreamingPreferences* preferences = new StreamingPreferences(&app);
StreamCommandLineParser streamParser; StreamCommandLineParser streamParser;
streamParser.parse(app.arguments(), preferences); streamParser.parse(app.arguments(), preferences);
QString host = streamParser.getHost(); QString host = streamParser.getHost();
@@ -780,7 +697,7 @@ int main(int argc, char *argv[])
ListCommandLineParser listParser; ListCommandLineParser listParser;
listParser.parse(app.arguments()); listParser.parse(app.arguments());
auto launcher = new CliListApps::Launcher(listParser.getHost(), listParser, &app); auto launcher = new CliListApps::Launcher(listParser.getHost(), listParser, &app);
launcher->execute(new ComputerManager(StreamingPreferences::get())); launcher->execute(new ComputerManager(&app));
hasGUI = false; hasGUI = false;
break; break;
} }
@@ -801,15 +718,5 @@ int main(int argc, char *argv[])
// sometimes freezing and blocking process exit. // sometimes freezing and blocking process exit.
QThreadPool::globalInstance()->waitForDone(30000); QThreadPool::globalInstance()->waitForDone(30000);
// Wait for pending log messages to be printed
s_LoggerThread.waitForDone();
#ifdef Q_OS_WIN32
// Without an explicit flush, console redirection for the list command
// doesn't work reliably (sometimes the target file contains no text).
fflush(stderr);
fflush(stdout);
#endif
return err; return err;
} }
+15 -83
View File
@@ -15,12 +15,10 @@
// redirection that happens when _FILE_OFFSET_BITS=64! // redirection that happens when _FILE_OFFSET_BITS=64!
// See masterhook_internal.c for details. // See masterhook_internal.c for details.
#include "SDL_compat.h" #include <SDL.h>
#include <stdlib.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <xf86drm.h> #include <xf86drm.h>
@@ -38,13 +36,8 @@
int g_QtDrmMasterFd = -1; int g_QtDrmMasterFd = -1;
struct stat g_DrmMasterStat; struct stat g_DrmMasterStat;
// Last CRTC state for us to restore later // The DRM master FD created for SDL
drmModeCrtcPtr g_QtCrtcState; int g_SdlDrmMasterFd = -1;
uint32_t* g_QtCrtcConnectors;
int g_QtCrtcConnectorCount;
bool removeSdlFd(int fd);
int takeMasterFromSdlFd(void);
int drmIsMaster(int fd) int drmIsMaster(int fd)
{ {
@@ -69,41 +62,7 @@ int drmModeSetCrtc(int fd, uint32_t crtcId, uint32_t bufferId,
} }
// Call into the real thing // Call into the real thing
int err = ((typeof(drmModeSetCrtc)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtcId, bufferId, x, y, connectors, count, mode); return ((typeof(drmModeSetCrtc)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtcId, bufferId, x, y, connectors, count, mode);
if (err == 0 && fd == g_QtDrmMasterFd) {
// Free old CRTC state (if any)
if (g_QtCrtcState) {
drmModeFreeCrtc(g_QtCrtcState);
}
if (g_QtCrtcConnectors) {
free(g_QtCrtcConnectors);
}
// Store the CRTC configuration so we can restore it later
g_QtCrtcState = drmModeGetCrtc(fd, crtcId);
g_QtCrtcConnectors = calloc(count, sizeof(*g_QtCrtcConnectors));
memcpy(g_QtCrtcConnectors, connectors, count * sizeof(*connectors));
g_QtCrtcConnectorCount = count;
}
return err;
}
// This hook will temporarily retake DRM master to allow Qt to render while SDL has a DRM FD open
int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, uint32_t flags, void *user_data)
{
// Call into the real thing
int err = ((typeof(drmModePageFlip)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtc_id, fb_id, flags, user_data);
if (err == -EACCES && fd == g_QtDrmMasterFd) {
// If SDL took master from us, try to grab it back temporarily
int oldMasterFd = takeMasterFromSdlFd();
drmSetMaster(fd);
err = ((typeof(drmModePageFlip)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, crtc_id, fb_id, flags, user_data);
drmDropMaster(fd);
if (oldMasterFd != -1) {
drmSetMaster(oldMasterFd);
}
}
return err;
} }
// This hook will handle atomic DRM rendering // This hook will handle atomic DRM rendering
@@ -121,18 +80,7 @@ int drmModeAtomicCommit(int fd, drmModeAtomicReqPtr req,
} }
// Call into the real thing // Call into the real thing
int err = ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data); return ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data);
if (err == -EACCES && fd == g_QtDrmMasterFd) {
// If SDL took master from us, try to grab it back temporarily
int oldMasterFd = takeMasterFromSdlFd();
drmSetMaster(fd);
err = ((typeof(drmModeAtomicCommit)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd, req, flags, user_data);
drmDropMaster(fd);
if (oldMasterFd != -1) {
drmSetMaster(oldMasterFd);
}
}
return err;
} }
// This hook will handle SDL's open() on the DRM device. We just need to // This hook will handle SDL's open() on the DRM device. We just need to
@@ -163,39 +111,23 @@ int open64(const char *pathname, int flags, ...)
// after SDL closes its DRM FD. // after SDL closes its DRM FD.
int close(int fd) int close(int fd)
{ {
// Remove this entry from the SDL FD table
bool lastSdlFd = removeSdlFd(fd);
// Call the real thing // Call the real thing
int ret = ((typeof(close)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd); int ret = ((typeof(close)*)dlsym(RTLD_NEXT, __FUNCTION__))(fd);
if (ret == 0) {
// If we closed the last SDL FD, restore master to the Qt FD // If we just closed the SDL DRM master FD, restore master
if (ret == 0 && lastSdlFd) { // to the Qt DRM FD. This works because the Qt DRM master FD
if (drmSetMaster(g_QtDrmMasterFd) < 0) { // was master once before, so we can set it as master again
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, // using drmSetMaster() without CAP_SYS_ADMIN.
"Failed to restore master to Qt DRM FD: %d", if (g_SdlDrmMasterFd != -1 && fd == g_SdlDrmMasterFd) {
errno); if (drmSetMaster(g_QtDrmMasterFd) < 0) {
}
// Reset the CRTC state to how Qt configured it
if (g_QtCrtcState) {
int err = ((typeof(drmModeSetCrtc)*)dlsym(RTLD_NEXT, "drmModeSetCrtc"))(g_QtDrmMasterFd,
g_QtCrtcState->crtc_id,
g_QtCrtcState->buffer_id,
g_QtCrtcState->x,
g_QtCrtcState->y,
g_QtCrtcConnectors,
g_QtCrtcConnectorCount,
g_QtCrtcState->mode_valid ?
&g_QtCrtcState->mode : NULL);
if (err < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to restore CRTC state to Qt DRM FD: %d", "Failed to restore master to Qt DRM FD: %d",
errno); errno);
} }
g_SdlDrmMasterFd = -1;
} }
} }
return ret; return ret;
} }
+18 -120
View File
@@ -4,12 +4,11 @@
#define _GNU_SOURCE #define _GNU_SOURCE
#include "SDL_compat.h" #include <SDL.h>
#include <dlfcn.h> #include <dlfcn.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <xf86drm.h> #include <xf86drm.h>
@@ -29,73 +28,7 @@
extern int g_QtDrmMasterFd; extern int g_QtDrmMasterFd;
extern struct stat g_DrmMasterStat; extern struct stat g_DrmMasterStat;
extern int g_SdlDrmMasterFd;
#define MAX_SDL_FD_COUNT 8
int g_SdlDrmMasterFds[MAX_SDL_FD_COUNT];
int g_SdlDrmMasterFdCount = 0;
SDL_SpinLock g_FdTableLock = 0;
// Caller must hold g_FdTableLock
int getSdlFdEntryIndex(bool unused)
{
for (int i = 0; i < MAX_SDL_FD_COUNT; i++) {
// We slightly bend the FD rules here by treating 0
// as invalid since that's our global default value.
if (unused && g_SdlDrmMasterFds[i] <= 0) {
return i;
}
else if (!unused && g_SdlDrmMasterFds[i] > 0) {
return i;
}
}
return -1;
}
// Returns true if the final SDL FD was removed
bool removeSdlFd(int fd)
{
SDL_LockSpinlock(&g_FdTableLock);
if (g_SdlDrmMasterFdCount != 0) {
// Clear the entry for this fd from the table
for (int i = 0; i < MAX_SDL_FD_COUNT; i++) {
if (fd == g_SdlDrmMasterFds[i]) {
g_SdlDrmMasterFds[i] = -1;
g_SdlDrmMasterFdCount--;
break;
}
}
if (g_SdlDrmMasterFdCount == 0) {
SDL_UnlockSpinlock(&g_FdTableLock);
return true;
}
}
SDL_UnlockSpinlock(&g_FdTableLock);
return false;
}
// Returns the previous master FD or -1 if none
int takeMasterFromSdlFd()
{
int fd = -1;
// Since all SDL FDs are actually dups of each other
// we can take master from any one of them.
SDL_LockSpinlock(&g_FdTableLock);
int fdIndex = getSdlFdEntryIndex(false);
if (fdIndex != -1) {
fd = g_SdlDrmMasterFds[fdIndex];
}
SDL_UnlockSpinlock(&g_FdTableLock);
if (fd >= 0 && drmDropMaster(fd) == 0) {
return fd;
}
else {
return -1;
}
}
int openHook(const char *funcname, const char *pathname, int flags, va_list va) int openHook(const char *funcname, const char *pathname, int flags, va_list va)
{ {
@@ -122,67 +55,32 @@ int openHook(const char *funcname, const char *pathname, int flags, va_list va)
fstat(fd, &fdstat); fstat(fd, &fdstat);
if (g_DrmMasterStat.st_dev == fdstat.st_dev && if (g_DrmMasterStat.st_dev == fdstat.st_dev &&
g_DrmMasterStat.st_ino == fdstat.st_ino) { g_DrmMasterStat.st_ino == fdstat.st_ino) {
int freeFdIndex;
int allocatedFdIndex;
// It is our device. Time to do the magic! // It is our device. Time to do the magic!
SDL_LockSpinlock(&g_FdTableLock);
// Get a free index for us to put the new entry // This code assumes SDL only ever opens a single FD
freeFdIndex = getSdlFdEntryIndex(true); // for a given DRM device.
if (freeFdIndex < 0) { SDL_assert(g_SdlDrmMasterFd == -1);
SDL_UnlockSpinlock(&g_FdTableLock);
SDL_assert(freeFdIndex >= 0); // Drop master on Qt's FD so we can pick it up for SDL.
if (drmDropMaster(g_QtDrmMasterFd) < 0) {
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"No unused SDL FD table entries!"); "Failed to drop master on Qt DRM FD: %d",
errno);
// Hope for the best // Hope for the best
return fd; return fd;
} }
// Check if we have an allocated entry already // We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN,
allocatedFdIndex = getSdlFdEntryIndex(false); // but since we just dropped the master, we can become master by
if (allocatedFdIndex >= 0) { // simply creating a new FD. Let's do it.
// Close fd that we opened earlier (skipping our close() hook) close(fd);
((typeof(close)*)dlsym(RTLD_NEXT, "close"))(fd); if (__OPEN_NEEDS_MODE(flags)) {
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode);
// dup() an existing FD into the unused slot
fd = dup(g_SdlDrmMasterFds[allocatedFdIndex]);
} }
else { else {
// Drop master on Qt's FD so we can pick it up for SDL. fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags);
if (drmDropMaster(g_QtDrmMasterFd) < 0) {
SDL_UnlockSpinlock(&g_FdTableLock);
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
"Failed to drop master on Qt DRM FD: %d",
errno);
// Hope for the best
return fd;
}
// Close fd that we opened earlier (skipping our close() hook)
((typeof(close)*)dlsym(RTLD_NEXT, "close"))(fd);
// We are not allowed to call drmSetMaster() without CAP_SYS_ADMIN,
// but since we just dropped the master, we can become master by
// simply creating a new FD. Let's do it.
if (__OPEN_NEEDS_MODE(flags)) {
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags, mode);
}
else {
fd = ((typeof(open)*)dlsym(RTLD_NEXT, funcname))(pathname, flags);
}
} }
g_SdlDrmMasterFd = fd;
if (fd >= 0) {
// Start with DRM master on the new FD
drmSetMaster(fd);
// Insert the FD into the table
g_SdlDrmMasterFds[freeFdIndex] = fd;
g_SdlDrmMasterFdCount++;
}
SDL_UnlockSpinlock(&g_FdTableLock);
} }
} }
} }
+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 245 240" fill="white"><path class="st0" d="M104.4 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1.1-6.1-4.5-11.1-10.2-11.1zM140.9 103.9c-5.7 0-10.2 5-10.2 11.1s4.6 11.1 10.2 11.1c5.7 0 10.2-5 10.2-11.1s-4.5-11.1-10.2-11.1z"/><path class="st0" d="M189.5 20h-134C44.2 20 35 29.2 35 40.6v135.2c0 11.4 9.2 20.6 20.5 20.6h113.4l-5.3-18.5 12.8 11.9 12.1 11.2 21.5 19V40.6c0-11.4-9.2-20.6-20.5-20.6zm-38.6 130.6s-3.6-4.3-6.6-8.1c13.1-3.7 18.1-11.9 18.1-11.9-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.5-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.7-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.3-1.8-1-2.8-1.7-2.8-1.7s4.8 8 17.5 11.8c-3 3.8-6.7 8.3-6.7 8.3-22.1-.7-30.5-15.2-30.5-15.2 0-32.2 14.4-58.3 14.4-58.3 14.4-10.8 28.1-10.5 28.1-10.5l1 1.2c-18 5.2-26.3 13.1-26.3 13.1s2.2-1.2 5.9-2.9c10.7-4.7 19.2-6 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.6 0 0-7.9-7.5-24.9-12.7l1.4-1.6s13.7-.3 28.1 10.5c0 0 14.4 26.1 14.4 58.3 0 0-8.5 14.5-30.6 15.2z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

-1
View File
@@ -1 +0,0 @@
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="white"><path d="M20.317 4.3698a19.7913 19.7913 0 0 0-4.8851-1.5152.0741.0741 0 0 0-.0785.0371c-.211.3753-.4447.8648-.6083 1.2495-1.8447-.2762-3.68-.2762-5.4868 0-.1636-.3933-.4058-.8742-.6177-1.2495a.077.077 0 0 0-.0785-.037 19.7363 19.7363 0 0 0-4.8852 1.515.0699.0699 0 0 0-.0321.0277C.5334 9.0458-.319 13.5799.0992 18.0578a.0824.0824 0 0 0 .0312.0561c2.0528 1.5076 4.0413 2.4228 5.9929 3.0294a.0777.0777 0 0 0 .0842-.0276c.4616-.6304.8731-1.2952 1.226-1.9942a.076.076 0 0 0-.0416-.1057c-.6528-.2476-1.2743-.5495-1.8722-.8923a.077.077 0 0 1-.0076-.1277c.1258-.0943.2517-.1923.3718-.2914a.0743.0743 0 0 1 .0776-.0105c3.9278 1.7933 8.18 1.7933 12.0614 0a.0739.0739 0 0 1 .0785.0095c.1202.099.246.1981.3728.2924a.077.077 0 0 1-.0066.1276 12.2986 12.2986 0 0 1-1.873.8914.0766.0766 0 0 0-.0407.1067c.3604.698.7719 1.3628 1.225 1.9932a.076.076 0 0 0 .0842.0286c1.961-.6067 3.9495-1.5219 6.0023-3.0294a.077.077 0 0 0 .0313-.0552c.5004-5.177-.8382-9.6739-3.5485-13.6604a.061.061 0 0 0-.0312-.0286zM8.02 15.3312c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9555-2.4189 2.157-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.9555 2.4189-2.1569 2.4189zm7.9748 0c-1.1825 0-2.1569-1.0857-2.1569-2.419 0-1.3332.9554-2.4189 2.1569-2.4189 1.2108 0 2.1757 1.0952 2.1568 2.419 0 1.3332-.946 2.4189-2.1568 2.4189Z"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

+1 -10
View File
@@ -17,7 +17,7 @@
<file>res/baseline-help_outline-24px.svg</file> <file>res/baseline-help_outline-24px.svg</file>
<file>res/baseline-error_outline-24px.svg</file> <file>res/baseline-error_outline-24px.svg</file>
<file>res/baseline-check_circle_outline-24px.svg</file> <file>res/baseline-check_circle_outline-24px.svg</file>
<file>res/discord.svg</file> <file>res/Discord-Logo-White.svg</file>
<file>languages/qml_de.ts</file> <file>languages/qml_de.ts</file>
<file>languages/qml_de.qm</file> <file>languages/qml_de.qm</file>
<file>languages/qml_fr.ts</file> <file>languages/qml_fr.ts</file>
@@ -64,12 +64,6 @@
<file>languages/qml_cs.qm</file> <file>languages/qml_cs.qm</file>
<file>languages/qml_he.ts</file> <file>languages/qml_he.ts</file>
<file>languages/qml_he.qm</file> <file>languages/qml_he.qm</file>
<file>languages/qml_ckb.ts</file>
<file>languages/qml_ckb.qm</file>
<file>languages/qml_lt.ts</file>
<file>languages/qml_lt.qm</file>
<file>languages/qml_et.ts</file>
<file>languages/qml_et.qm</file>
<!-- Don't include pt_BR until it is more complete --> <!-- Don't include pt_BR until it is more complete -->
<!--file>languages/qml_pt_BR.qm</file--> <!--file>languages/qml_pt_BR.qm</file-->
<!--file>languages/qml_pt_BR.ts</file--> <!--file>languages/qml_pt_BR.ts</file-->
@@ -88,8 +82,5 @@
<file alias="d3d11_genyuv_pixel.fxc">shaders/d3d11_genyuv_pixel.fxc</file> <file alias="d3d11_genyuv_pixel.fxc">shaders/d3d11_genyuv_pixel.fxc</file>
<file alias="d3d11_bt601lim_pixel.fxc">shaders/d3d11_bt601lim_pixel.fxc</file> <file alias="d3d11_bt601lim_pixel.fxc">shaders/d3d11_bt601lim_pixel.fxc</file>
<file alias="d3d11_bt2020lim_pixel.fxc">shaders/d3d11_bt2020lim_pixel.fxc</file> <file alias="d3d11_bt2020lim_pixel.fxc">shaders/d3d11_bt2020lim_pixel.fxc</file>
<file alias="d3d11_ayuv_pixel.fxc">shaders/d3d11_ayuv_pixel.fxc</file>
<file alias="d3d11_y410_pixel.fxc">shaders/d3d11_y410_pixel.fxc</file>
<file alias="vt_renderer.metal">shaders/vt_renderer.metal</file>
</qresource> </qresource>
</RCC> </RCC>
+1 -1
View File
@@ -3,7 +3,7 @@
#include <QDir> #include <QDir>
#include "SDL_compat.h" #include <SDL.h>
#define SER_GAMEPADMAPPING "gcmapping" #define SER_GAMEPADMAPPING "gcmapping"
+9 -62
View File
@@ -5,7 +5,6 @@
#include <QTranslator> #include <QTranslator>
#include <QCoreApplication> #include <QCoreApplication>
#include <QLocale> #include <QLocale>
#include <QReadWriteLock>
#include <QtMath> #include <QtMath>
#include <QtDebug> #include <QtDebug>
@@ -15,7 +14,6 @@
#define SER_HEIGHT "height" #define SER_HEIGHT "height"
#define SER_FPS "fps" #define SER_FPS "fps"
#define SER_BITRATE "bitrate" #define SER_BITRATE "bitrate"
#define SER_UNLOCK_BITRATE "unlockbitrate"
#define SER_FULLSCREEN "fullscreen" #define SER_FULLSCREEN "fullscreen"
#define SER_VSYNC "vsync" #define SER_VSYNC "vsync"
#define SER_GAMEOPTS "gameopts" #define SER_GAMEOPTS "gameopts"
@@ -24,7 +22,6 @@
#define SER_AUDIOCFG "audiocfg" #define SER_AUDIOCFG "audiocfg"
#define SER_VIDEOCFG "videocfg" #define SER_VIDEOCFG "videocfg"
#define SER_HDR "hdr" #define SER_HDR "hdr"
#define SER_YUV444 "yuv444"
#define SER_VIDEODEC "videodec" #define SER_VIDEODEC "videodec"
#define SER_WINDOWMODE "windowmode" #define SER_WINDOWMODE "windowmode"
#define SER_MDNS "mdns" #define SER_MDNS "mdns"
@@ -40,7 +37,6 @@
#define SER_DEFAULTVER "defaultver" #define SER_DEFAULTVER "defaultver"
#define SER_PACKETSIZE "packetsize" #define SER_PACKETSIZE "packetsize"
#define SER_DETECTNETBLOCKING "detectnetblocking" #define SER_DETECTNETBLOCKING "detectnetblocking"
#define SER_SHOWPERFOVERLAY "showperfoverlay"
#define SER_SWAPMOUSEBUTTONS "swapmousebuttons" #define SER_SWAPMOUSEBUTTONS "swapmousebuttons"
#define SER_MUTEONFOCUSLOSS "muteonfocusloss" #define SER_MUTEONFOCUSLOSS "muteonfocusloss"
#define SER_BACKGROUNDGAMEPAD "backgroundgamepad" #define SER_BACKGROUNDGAMEPAD "backgroundgamepad"
@@ -52,50 +48,18 @@
#define CURRENT_DEFAULT_VER 2 #define CURRENT_DEFAULT_VER 2
static StreamingPreferences* s_GlobalPrefs; StreamingPreferences::StreamingPreferences(QObject *parent)
static QReadWriteLock s_GlobalPrefsLock; : QObject(parent),
m_QmlEngine(nullptr)
StreamingPreferences::StreamingPreferences(QQmlEngine *qmlEngine)
: m_QmlEngine(qmlEngine)
{ {
reload(); reload();
} }
StreamingPreferences* StreamingPreferences::get(QQmlEngine *qmlEngine) StreamingPreferences::StreamingPreferences(QQmlEngine *qmlEngine, QObject *parent)
: QObject(parent),
m_QmlEngine(qmlEngine)
{ {
{ reload();
QReadLocker readGuard(&s_GlobalPrefsLock);
// If we have a preference object and it's associated with a QML engine or
// if the caller didn't specify a QML engine, return the existing object.
if (s_GlobalPrefs && (s_GlobalPrefs->m_QmlEngine || !qmlEngine)) {
// The lifetime logic here relies on the QML engine also being a singleton.
Q_ASSERT(!qmlEngine || s_GlobalPrefs->m_QmlEngine == qmlEngine);
return s_GlobalPrefs;
}
}
{
QWriteLocker writeGuard(&s_GlobalPrefsLock);
// If we already have an preference object but the QML engine is now available,
// associate the QML engine with the preferences.
if (s_GlobalPrefs) {
if (!s_GlobalPrefs->m_QmlEngine) {
s_GlobalPrefs->m_QmlEngine = qmlEngine;
}
else {
// We could reach this codepath if another thread raced with us
// and created the object while we were outside the pref lock.
Q_ASSERT(!qmlEngine || s_GlobalPrefs->m_QmlEngine == qmlEngine);
}
}
else {
s_GlobalPrefs = new StreamingPreferences(qmlEngine);
}
return s_GlobalPrefs;
}
} }
void StreamingPreferences::reload() void StreamingPreferences::reload()
@@ -119,9 +83,7 @@ void StreamingPreferences::reload()
width = settings.value(SER_WIDTH, 1280).toInt(); width = settings.value(SER_WIDTH, 1280).toInt();
height = settings.value(SER_HEIGHT, 720).toInt(); height = settings.value(SER_HEIGHT, 720).toInt();
fps = settings.value(SER_FPS, 60).toInt(); fps = settings.value(SER_FPS, 60).toInt();
enableYUV444 = settings.value(SER_YUV444, false).toBool(); bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps)).toInt();
bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps, enableYUV444)).toInt();
unlockBitrate = settings.value(SER_UNLOCK_BITRATE, false).toBool();
enableVsync = settings.value(SER_VSYNC, true).toBool(); enableVsync = settings.value(SER_VSYNC, true).toBool();
gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool(); gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool();
playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool(); playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool();
@@ -135,7 +97,6 @@ void StreamingPreferences::reload()
richPresence = settings.value(SER_RICHPRESENCE, true).toBool(); richPresence = settings.value(SER_RICHPRESENCE, true).toBool();
gamepadMouse = settings.value(SER_GAMEPADMOUSE, true).toBool(); gamepadMouse = settings.value(SER_GAMEPADMOUSE, true).toBool();
detectNetworkBlocking = settings.value(SER_DETECTNETBLOCKING, true).toBool(); detectNetworkBlocking = settings.value(SER_DETECTNETBLOCKING, true).toBool();
showPerformanceOverlay = settings.value(SER_SHOWPERFOVERLAY, false).toBool();
packetSize = settings.value(SER_PACKETSIZE, 0).toInt(); packetSize = settings.value(SER_PACKETSIZE, 0).toInt();
swapMouseButtons = settings.value(SER_SWAPMOUSEBUTTONS, false).toBool(); swapMouseButtons = settings.value(SER_SWAPMOUSEBUTTONS, false).toBool();
muteOnFocusLoss = settings.value(SER_MUTEONFOCUSLOSS, false).toBool(); muteOnFocusLoss = settings.value(SER_MUTEONFOCUSLOSS, false).toBool();
@@ -291,12 +252,6 @@ QString StreamingPreferences::getSuffixFromLanguage(StreamingPreferences::Langua
return "cs"; return "cs";
case LANG_HE: case LANG_HE:
return "he"; return "he";
case LANG_CKB:
return "ckb";
case LANG_LT:
return "lt";
case LANG_ET:
return "et";
case LANG_AUTO: case LANG_AUTO:
default: default:
return QLocale::system().name(); return QLocale::system().name();
@@ -311,7 +266,6 @@ void StreamingPreferences::save()
settings.setValue(SER_HEIGHT, height); settings.setValue(SER_HEIGHT, height);
settings.setValue(SER_FPS, fps); settings.setValue(SER_FPS, fps);
settings.setValue(SER_BITRATE, bitrateKbps); settings.setValue(SER_BITRATE, bitrateKbps);
settings.setValue(SER_UNLOCK_BITRATE, unlockBitrate);
settings.setValue(SER_VSYNC, enableVsync); settings.setValue(SER_VSYNC, enableVsync);
settings.setValue(SER_GAMEOPTS, gameOptimizations); settings.setValue(SER_GAMEOPTS, gameOptimizations);
settings.setValue(SER_HOSTAUDIO, playAudioOnHost); settings.setValue(SER_HOSTAUDIO, playAudioOnHost);
@@ -326,10 +280,8 @@ void StreamingPreferences::save()
settings.setValue(SER_GAMEPADMOUSE, gamepadMouse); settings.setValue(SER_GAMEPADMOUSE, gamepadMouse);
settings.setValue(SER_PACKETSIZE, packetSize); settings.setValue(SER_PACKETSIZE, packetSize);
settings.setValue(SER_DETECTNETBLOCKING, detectNetworkBlocking); settings.setValue(SER_DETECTNETBLOCKING, detectNetworkBlocking);
settings.setValue(SER_SHOWPERFOVERLAY, showPerformanceOverlay);
settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig)); settings.setValue(SER_AUDIOCFG, static_cast<int>(audioConfig));
settings.setValue(SER_HDR, enableHdr); settings.setValue(SER_HDR, enableHdr);
settings.setValue(SER_YUV444, enableYUV444);
settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig)); settings.setValue(SER_VIDEOCFG, static_cast<int>(videoCodecConfig));
settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection)); settings.setValue(SER_VIDEODEC, static_cast<int>(videoDecoderSelection));
settings.setValue(SER_WINDOWMODE, static_cast<int>(windowMode)); settings.setValue(SER_WINDOWMODE, static_cast<int>(windowMode));
@@ -345,7 +297,7 @@ void StreamingPreferences::save()
settings.setValue(SER_KEEPAWAKE, keepAwake); settings.setValue(SER_KEEPAWAKE, keepAwake);
} }
int StreamingPreferences::getDefaultBitrate(int width, int height, int fps, bool yuv444) int StreamingPreferences::getDefaultBitrate(int width, int height, int fps)
{ {
// Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear // Don't scale bitrate linearly beyond 60 FPS. It's definitely not a linear
// bitrate increase for frame rate once we get to values that high. // bitrate increase for frame rate once we get to values that high.
@@ -393,10 +345,5 @@ int StreamingPreferences::getDefaultBitrate(int width, int height, int fps, bool
} }
} }
if (yuv444) {
// This is rough estimation based on the fact that 4:4:4 doubles the amount of raw YUV data compared to 4:2:0
resolutionFactor *= 2;
}
return qRound(resolutionFactor * frameRateFactor) * 1000; return qRound(resolutionFactor * frameRateFactor) * 1000;
} }
+3 -16
View File
@@ -9,10 +9,11 @@ class StreamingPreferences : public QObject
Q_OBJECT Q_OBJECT
public: public:
static StreamingPreferences* get(QQmlEngine *qmlEngine = nullptr); StreamingPreferences(QObject *parent = nullptr);
StreamingPreferences(QQmlEngine *qmlEngine, QObject *parent = nullptr);
Q_INVOKABLE static int Q_INVOKABLE static int
getDefaultBitrate(int width, int height, int fps, bool yuv444); getDefaultBitrate(int width, int height, int fps);
Q_INVOKABLE void save(); Q_INVOKABLE void save();
@@ -91,9 +92,6 @@ public:
LANG_PL, LANG_PL,
LANG_CS, LANG_CS,
LANG_HE, LANG_HE,
LANG_CKB,
LANG_LT,
LANG_ET,
}; };
Q_ENUM(Language); Q_ENUM(Language);
@@ -109,7 +107,6 @@ public:
Q_PROPERTY(int height MEMBER height NOTIFY displayModeChanged) Q_PROPERTY(int height MEMBER height NOTIFY displayModeChanged)
Q_PROPERTY(int fps MEMBER fps NOTIFY displayModeChanged) Q_PROPERTY(int fps MEMBER fps NOTIFY displayModeChanged)
Q_PROPERTY(int bitrateKbps MEMBER bitrateKbps NOTIFY bitrateChanged) Q_PROPERTY(int bitrateKbps MEMBER bitrateKbps NOTIFY bitrateChanged)
Q_PROPERTY(bool unlockBitrate MEMBER unlockBitrate NOTIFY unlockBitrateChanged)
Q_PROPERTY(bool enableVsync MEMBER enableVsync NOTIFY enableVsyncChanged) Q_PROPERTY(bool enableVsync MEMBER enableVsync NOTIFY enableVsyncChanged)
Q_PROPERTY(bool gameOptimizations MEMBER gameOptimizations NOTIFY gameOptimizationsChanged) Q_PROPERTY(bool gameOptimizations MEMBER gameOptimizations NOTIFY gameOptimizationsChanged)
Q_PROPERTY(bool playAudioOnHost MEMBER playAudioOnHost NOTIFY playAudioOnHostChanged) Q_PROPERTY(bool playAudioOnHost MEMBER playAudioOnHost NOTIFY playAudioOnHostChanged)
@@ -123,11 +120,9 @@ public:
Q_PROPERTY(bool richPresence MEMBER richPresence NOTIFY richPresenceChanged) Q_PROPERTY(bool richPresence MEMBER richPresence NOTIFY richPresenceChanged)
Q_PROPERTY(bool gamepadMouse MEMBER gamepadMouse NOTIFY gamepadMouseChanged) Q_PROPERTY(bool gamepadMouse MEMBER gamepadMouse NOTIFY gamepadMouseChanged)
Q_PROPERTY(bool detectNetworkBlocking MEMBER detectNetworkBlocking NOTIFY detectNetworkBlockingChanged) Q_PROPERTY(bool detectNetworkBlocking MEMBER detectNetworkBlocking NOTIFY detectNetworkBlockingChanged)
Q_PROPERTY(bool showPerformanceOverlay MEMBER showPerformanceOverlay NOTIFY showPerformanceOverlayChanged)
Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged) Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged)
Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged) Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged)
Q_PROPERTY(bool enableHdr MEMBER enableHdr NOTIFY enableHdrChanged) Q_PROPERTY(bool enableHdr MEMBER enableHdr NOTIFY enableHdrChanged)
Q_PROPERTY(bool enableYUV444 MEMBER enableYUV444 NOTIFY enableYUV444Changed)
Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged) Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged)
Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged) Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged)
Q_PROPERTY(WindowMode recommendedFullScreenMode MEMBER recommendedFullScreenMode CONSTANT) Q_PROPERTY(WindowMode recommendedFullScreenMode MEMBER recommendedFullScreenMode CONSTANT)
@@ -148,7 +143,6 @@ public:
int height; int height;
int fps; int fps;
int bitrateKbps; int bitrateKbps;
bool unlockBitrate;
bool enableVsync; bool enableVsync;
bool gameOptimizations; bool gameOptimizations;
bool playAudioOnHost; bool playAudioOnHost;
@@ -162,7 +156,6 @@ public:
bool richPresence; bool richPresence;
bool gamepadMouse; bool gamepadMouse;
bool detectNetworkBlocking; bool detectNetworkBlocking;
bool showPerformanceOverlay;
bool swapMouseButtons; bool swapMouseButtons;
bool muteOnFocusLoss; bool muteOnFocusLoss;
bool backgroundGamepad; bool backgroundGamepad;
@@ -173,7 +166,6 @@ public:
AudioConfig audioConfig; AudioConfig audioConfig;
VideoCodecConfig videoCodecConfig; VideoCodecConfig videoCodecConfig;
bool enableHdr; bool enableHdr;
bool enableYUV444;
VideoDecoderSelection videoDecoderSelection; VideoDecoderSelection videoDecoderSelection;
WindowMode windowMode; WindowMode windowMode;
WindowMode recommendedFullScreenMode; WindowMode recommendedFullScreenMode;
@@ -184,7 +176,6 @@ public:
signals: signals:
void displayModeChanged(); void displayModeChanged();
void bitrateChanged(); void bitrateChanged();
void unlockBitrateChanged();
void enableVsyncChanged(); void enableVsyncChanged();
void gameOptimizationsChanged(); void gameOptimizationsChanged();
void playAudioOnHostChanged(); void playAudioOnHostChanged();
@@ -197,7 +188,6 @@ signals:
void audioConfigChanged(); void audioConfigChanged();
void videoCodecConfigChanged(); void videoCodecConfigChanged();
void enableHdrChanged(); void enableHdrChanged();
void enableYUV444Changed();
void videoDecoderSelectionChanged(); void videoDecoderSelectionChanged();
void uiDisplayModeChanged(); void uiDisplayModeChanged();
void windowModeChanged(); void windowModeChanged();
@@ -206,7 +196,6 @@ signals:
void richPresenceChanged(); void richPresenceChanged();
void gamepadMouseChanged(); void gamepadMouseChanged();
void detectNetworkBlockingChanged(); void detectNetworkBlockingChanged();
void showPerformanceOverlayChanged();
void mouseButtonsChanged(); void mouseButtonsChanged();
void muteOnFocusLossChanged(); void muteOnFocusLossChanged();
void backgroundGamepadChanged(); void backgroundGamepadChanged();
@@ -217,8 +206,6 @@ signals:
void languageChanged(); void languageChanged();
private: private:
explicit StreamingPreferences(QQmlEngine *qmlEngine);
QString getSuffixFromLanguage(Language lang); QString getSuffixFromLanguage(Language lang);
QQmlEngine* m_QmlEngine; QQmlEngine* m_QmlEngine;
+1 -3
View File
@@ -3,6 +3,4 @@ fxc /T vs_4_0_level_9_3 /Fo d3d11_vertex.fxc d3d11_vertex.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_overlay_pixel.fxc d3d11_overlay_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_overlay_pixel.fxc d3d11_overlay_pixel.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_genyuv_pixel.fxc d3d11_genyuv_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_genyuv_pixel.fxc d3d11_genyuv_pixel.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_bt601lim_pixel.fxc d3d11_bt601lim_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_bt601lim_pixel.fxc d3d11_bt601lim_pixel.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_bt2020lim_pixel.fxc d3d11_bt2020lim_pixel.hlsl fxc /T ps_4_0_level_9_3 /Fo d3d11_bt2020lim_pixel.fxc d3d11_bt2020lim_pixel.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_ayuv_pixel.fxc d3d11_ayuv_pixel.hlsl
fxc /T ps_4_0_level_9_3 /Fo d3d11_y410_pixel.fxc d3d11_y410_pixel.hlsl
Binary file not shown.
-9
View File
@@ -1,9 +0,0 @@
#include "d3d11_yuv444_pixel_start.hlsli"
min16float3 swizzle(min16float3 input)
{
// AYUV SRVs are in VUYA order
return input.bgr;
}
#include "d3d11_yuv444_pixel_end.hlsli"
Binary file not shown.
Loaded 100 of 189 files, more files were not shown because too many files have changed in this diff. Show more