Skip to content

Commit faf324d

Browse files
committed
Add Video Super Resolution for Windows x64 and ARM, Linux and MacOS
This commit introduces video super-resolution and upscaling support across Windows, Linux and macOS platforms. DirectX 12 Upscaling Pipeline - Added a full D3D12 renderer to enable advanced GPU upscaling features. - Works on Windows for AMD, NVIDIA, and Intel GPUs, and on macOS (ARM) using Metal. - Supports SDR, HDR, and YUV 4:4:4 pipelines. - Uses vendor-specific driver upscalers by default (e.g., AMD AMF), with automatic fallback to a shader-based solution (typically FSR1) when unsupported or unreliable on older hardware (e.g., NVIDIA GTX). - Automatic algorithm selection based on vendor, GPU model, and available features. - Optimized for low-end GPUs (such as Intel UHD) by combining GPU upscaling with RCAS shader operations. - Uses FFmpeg DX12 hardware decoding by default; includes fallback to DX11 decoding with DX11–DX12 interop in cases where DX12 decoding causes stutters on some AMD GPUs. Rendering remains fully D3D12. - Added detailed upscaler information to the on-screen statistics overlay. - Add Shader FSR1 for Linux macOS Upscaling - Integrated MetalFX upscaler for macOS platforms. Tested Hardware - NVIDIA RTX 4070 Ti (Windows & Linux) - NVIDIA GTX 1050 (Windows & Linux) - AMD Radeon RX 7600 (Windows) - AMD Ryzen 7 780M iGPU (Windows) - Intel Arc A380 (Windows) - Intel UHD Graphics (16 EU, N95 CPU) (Windows) - Snapdragon 7c (Windows ARM) - Apple M1 Pro (macOS) - Apple M3 (macOS)
1 parent 0e50a9d commit faf324d

File tree

138 files changed

+54477
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

138 files changed

+54477
-79
lines changed

.gitignore

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,31 @@
11
*pro.user
2-
2+
.qtcreator/
33

44
**/.vs/
55
.vscode/
66
build/
77
config.tests/*/.qmake.stash
88
config.tests/*/Makefile
9+
10+
third-party/**
11+
!third-party/
12+
13+
# Submodules
14+
!third-party/AMF/
15+
!third-party/DirectX-Headers/
16+
!third-party/FidelityFX-FSR/
17+
!third-party/NVIDIAImageScaling/
18+
!third-party/libvpl/
19+
20+
# Bundled SDKs
21+
!third-party/DirectXShaderCompiler/
22+
!third-party/DirectXShaderCompiler/**
23+
!third-party/RTX_Video_SDK/
24+
!third-party/RTX_Video_SDK/**
25+
!third-party/IntelVPL/
26+
!third-party/IntelVPL/**/
27+
!third-party/IntelVPL/*/lib/**
28+
!third-party/IntelVPL/*/include/**
29+
!third-party/IntelVPL/*/bin/libvpl.dll
30+
!third-party/stb_image/
31+
!third-party/stb_image/**

.gitmodules

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,41 @@
11
[submodule "moonlight-common-c/moonlight-common-c"]
22
path = moonlight-common-c/moonlight-common-c
33
url = https://github.com/moonlight-stream/moonlight-common-c.git
4+
ignore = all
45
[submodule "qmdnsengine/qmdnsengine"]
56
path = qmdnsengine/qmdnsengine
67
url = https://github.com/cgutman/qmdnsengine.git
8+
ignore = all
79
[submodule "app/SDL_GameControllerDB"]
810
path = app/SDL_GameControllerDB
911
url = https://github.com/gabomdq/SDL_GameControllerDB.git
12+
ignore = all
1013
[submodule "h264bitstream/h264bitstream"]
1114
path = h264bitstream/h264bitstream
1215
url = https://github.com/aizvorski/h264bitstream.git
16+
ignore = all
1317
[submodule "libs"]
1418
path = libs
1519
url = https://github.com/cgutman/moonlight-qt-prebuilts.git
20+
ignore = all
1621
shallow = true
22+
[submodule "third-party/AMF"]
23+
path = third-party/AMF
24+
url = https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git
25+
ignore = all
26+
[submodule "third-party/FidelityFX-FSR"]
27+
path = third-party/FidelityFX-FSR
28+
url = https://github.com/GPUOpen-Effects/FidelityFX-FSR.git
29+
ignore = all
30+
[submodule "third-party/NVIDIAImageScaling"]
31+
path = third-party/NVIDIAImageScaling
32+
url = https://github.com/NVIDIAGameWorks/NVIDIAImageScaling.git
33+
ignore = all
34+
[submodule "third-party/DirectX-Headers"]
35+
path = third-party/DirectX-Headers
36+
url = https://github.com/microsoft/DirectX-Headers.git
37+
ignore = all
38+
[submodule "third-party/libvpl"]
39+
path = third-party/libvpl
40+
url = https://github.com/intel/libvpl.git
41+
ignore = all

app/app.pro

Lines changed: 137 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
QT += core quick network quickcontrols2 svg
1+
QT += core quick network quickcontrols2 svg concurrent
22
CONFIG += c++17
33

44
unix:!macx {
@@ -141,7 +141,7 @@ unix:if(!macx|disable-prebuilts) {
141141
}
142142
}
143143
win32 {
144-
LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lswscale -lopus -ldxgi -ld3d11 -llibplacebo
144+
LIBS += -llibssl -llibcrypto -lSDL2 -lSDL2_ttf -lavcodec -lavutil -lswscale -lopus -ldxgi -ld3d11 -ld3d12 -ldxguid -llibplacebo -ld3dcompiler -ldxcompiler
145145
CONFIG += ffmpeg libplacebo
146146
}
147147
win32:!winrt {
@@ -153,7 +153,7 @@ macx {
153153
CONFIG += discord-rpc
154154
}
155155

156-
LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal -framework QuartzCore
156+
LIBS += -lobjc -framework VideoToolbox -framework AVFoundation -framework CoreVideo -framework CoreGraphics -framework CoreMedia -framework AppKit -framework Metal -framework MetalFx -framework MetalPerformanceShaders -framework QuartzCore
157157
CONFIG += ffmpeg
158158
}
159159

@@ -196,6 +196,7 @@ SOURCES += \
196196
gui/sdlgamepadkeynavigation.cpp \
197197
streaming/video/overlaymanager.cpp \
198198
backend/systemproperties.cpp \
199+
streaming/video/videoenhancement.cpp \
199200
wm.cpp
200201

201202
HEADERS += \
@@ -233,7 +234,8 @@ HEADERS += \
233234
settings/mappingmanager.h \
234235
gui/sdlgamepadkeynavigation.h \
235236
streaming/video/overlaymanager.h \
236-
backend/systemproperties.h
237+
backend/systemproperties.h \
238+
streaming/video/videoenhancement.h
237239

238240
# Platform-specific renderers and decoders
239241
ffmpeg {
@@ -379,18 +381,148 @@ config_SL {
379381
win32 {
380382
HEADERS += streaming/video/ffmpeg-renderers/dxutil.h
381383
}
384+
385+
win32:!winrt {
386+
message(NVIDIA VSR and TrueHDR technologies)
387+
388+
# Required by NVIDIA RTX Video SDK; compilation fails without these linker flags
389+
# as the SDK is compiled to work with Visual Studio initially
390+
# Note: '/guard:ehcont,no' disables some EH checks
391+
# For a standalone application without external modules, this poses virtually no risk
392+
QMAKE_LFLAGS += /guard:ehcont,no
393+
394+
LIBS += -ladvapi32
395+
396+
OS_ARCHI = x64
397+
contains(QT_ARCH, arm64) {
398+
OS_ARCHI = arm64
399+
}
400+
401+
NGX_DLL_PATH_VSR = "$$PWD/../third-party/RTX_Video_SDK/bin/Windows/$${OS_ARCHI}/rel/nvngx_vsr.dll"
402+
NGX_DLL_PATH_HDR = "$$PWD/../third-party/RTX_Video_SDK/bin/Windows/$${OS_ARCHI}/rel/nvngx_truehdr.dll"
403+
404+
CONFIG(debug, debug|release) {
405+
# Debug
406+
copy_vsr.commands = $$quote(copy /Y $$shell_path($$NGX_DLL_PATH_VSR) $$shell_path("$$OUT_PWD/debug"))
407+
copy_hdr.commands = $$quote(copy /Y $$shell_path($$NGX_DLL_PATH_HDR) $$shell_path("$$OUT_PWD/debug"))
408+
LIBS += -L$$PWD/../third-party/RTX_Video_SDK/lib/Windows/$${OS_ARCHI} -lnvsdk_ngx_d_dbg
409+
}
410+
411+
CONFIG(release, debug|release) {
412+
# Release
413+
copy_vsr.commands = $$quote(copy /Y $$shell_path($$NGX_DLL_PATH_VSR) $$shell_path("$$OUT_PWD/release"))
414+
copy_hdr.commands = $$quote(copy /Y $$shell_path($$NGX_DLL_PATH_HDR) $$shell_path("$$OUT_PWD/release"))
415+
LIBS += -L$$PWD/../third-party/RTX_Video_SDK/lib/Windows/$${OS_ARCHI} -lnvsdk_ngx_d
416+
}
417+
418+
QMAKE_POST_LINK += $$copy_vsr.commands & $$copy_hdr.commands
419+
420+
INCLUDEPATH += $$PWD/../third-party/RTX_Video_SDK/include
421+
}
422+
423+
win32:!winrt {
424+
message(AMD Upscaling technologies)
425+
426+
SOURCES += \
427+
../third-party/AMF/amf/public/common/AMFFactory.cpp \
428+
../third-party/AMF/amf/public/common/AMFSTL.cpp \
429+
../third-party/AMF/amf/public/common/Thread.cpp \
430+
../third-party/AMF/amf/public/common/TraceAdapter.cpp \
431+
../third-party/AMF/amf/public/common/Windows/ThreadWindows.cpp
432+
433+
INCLUDEPATH += \
434+
$$PWD/../third-party/AMF/amf \
435+
$$PWD/shaders/enhancer/AMD
436+
}
437+
382438
win32:!winrt {
383-
message(DXVA2 and D3D11VA renderers selected)
439+
message(Intel VPL Upscaling technologies)
440+
441+
# IntelVPL already exists and is compiled for x64 architecture.
442+
# Uncomment if you need to rebuild IntelVPL locally.
443+
# Important: MSVC Build Tools for ARM64 and WinGet (https://github.com/microsoft/winget-cli/releases) are required,
444+
445+
# # Compile x64 architecture
446+
# vpl_build_x64.commands = \
447+
# cd $$shell_path($$PWD/../third-party/libvpl) && \
448+
# script\\bootstrap.bat && \
449+
# cmake -B _build_x64 -DCMAKE_INSTALL_PREFIX="$$PWD/../third-party/IntelVPL/x64" && \
450+
# cmake --build _build_x64 --config Release && \
451+
# cmake --install _build_x64 --config Release
452+
# vpl_build_x64.CONFIG += no_link
453+
# QMAKE_EXTRA_TARGETS += vpl_build_x64
454+
# PRE_TARGETDEPS += vpl_build_x64
455+
456+
# # Compile arm64 architecture
457+
# # Note: Intel does not provide a arm64 version of its library,
458+
# # but we need to compile it to avoid a build error, even if it is not used
459+
# vpl_build_arm64.commands = \
460+
# cd $$shell_path($$PWD/../third-party/libvpl) && \
461+
# script\\bootstrap.bat && \
462+
# cmake -B _build_arm64 -A ARM64 -T host=x64 -DCMAKE_INSTALL_PREFIX="$$PWD/../third-party/IntelVPL/arm64" && \
463+
# cmake --build _build_arm64 --config Release && \
464+
# cmake --install _build_arm64 --config Release
465+
# vpl_build_arm64.CONFIG += no_link
466+
# QMAKE_EXTRA_TARGETS += vpl_build_arm64
467+
# PRE_TARGETDEPS += vpl_build_arm64
468+
469+
OS_ARCHI = x64
470+
contains(QT_ARCH, arm64) {
471+
OS_ARCHI = arm64
472+
}
473+
474+
INCLUDEPATH += $$PWD/../third-party/IntelVPL/$${OS_ARCHI}/include
475+
LIBS += -L$$PWD/../third-party/IntelVPL/$${OS_ARCHI}/lib -lvpl
476+
477+
VPL_DLL_PATH = "$$PWD/../third-party/IntelVPL/$${OS_ARCHI}/bin/libvpl.dll"
478+
479+
CONFIG(debug, debug|release) {
480+
# Debug
481+
copy_vpl.commands = $$quote(copy /Y $$shell_path($$VPL_DLL_PATH) $$shell_path("$$OUT_PWD/debug"))
482+
}
483+
484+
CONFIG(release, debug|release) {
485+
# Release
486+
copy_vpl.commands = $$quote(copy /Y $$shell_path($$VPL_DLL_PATH) $$shell_path("$$OUT_PWD/release"))
487+
}
488+
489+
QMAKE_POST_LINK += & $$copy_vpl.commands
490+
491+
# IntelVPL is only available for the architecture x64
492+
contains(QT_ARCH, x86_64) {
493+
DEFINES += HAVE_INTEL_VPL
494+
}
495+
}
496+
win32:!winrt {
497+
message(NVIDIA Image Scaling)
498+
499+
INCLUDEPATH += $$PWD/../third-party/NVIDIAImageScaling/NIS
500+
}
501+
win32:!winrt {
502+
message(Direct3D 12 headers)
503+
504+
INCLUDEPATH += $$PWD/../third-party/DirectX-Headers/include
505+
}
506+
win32:!winrt {
507+
message("DXVA2, D3D11renderers and D3D12renderers selected")
384508

385509
SOURCES += \
386510
streaming/video/ffmpeg-renderers/dxva2.cpp \
387511
streaming/video/ffmpeg-renderers/d3d11va.cpp \
512+
streaming/video/ffmpeg-renderers/d3d12va.cpp \
513+
streaming/video/ffmpeg-renderers/d3d12va_shaders.cpp \
388514
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.cpp
389515

390516
HEADERS += \
391517
streaming/video/ffmpeg-renderers/dxva2.h \
392518
streaming/video/ffmpeg-renderers/d3d11va.h \
519+
streaming/video/ffmpeg-renderers/d3d12va.h \
520+
streaming/video/ffmpeg-renderers/d3d12va_shaders.h \
393521
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.h
522+
523+
CONFIG(debug, debug|release) {
524+
INCLUDEPATH += $$PWD/../third-party/stb_image
525+
}
394526
}
395527
macx {
396528
message(VideoToolbox renderer selected)

app/backend/systemproperties.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "streaming/session.h"
88
#include "streaming/streamutils.h"
9+
#include "streaming/video/videoenhancement.h"
910

1011
#ifdef Q_OS_WIN32
1112
#define WIN32_LEAN_AND_MEAN
@@ -268,3 +269,31 @@ void SystemProperties::refreshDisplays()
268269

269270
SDL_QuitSubSystem(SDL_INIT_VIDEO);
270271
}
272+
273+
/**
274+
* \brief Inform if the menu is selectable (DEBUG mode)
275+
*
276+
* For Debugging purpose only, we allow the dropdown menu visible to test other algorithms
277+
*
278+
* \return bool Returns true if in debug mode
279+
*/
280+
bool SystemProperties::isVideoEnhancementSwitchable()
281+
{
282+
#if defined(QT_DEBUG) && defined(Q_OS_WIN)
283+
return true;
284+
#else
285+
return false;
286+
#endif
287+
}
288+
289+
/**
290+
* \brief Inform if the GPU is capable of Video enhancement
291+
*
292+
* Check if either Video Super-Resolution features can be used by the GPU.
293+
*
294+
* \return bool Returns true if the GPU is capable
295+
*/
296+
bool SystemProperties::isVideoEnhancementAvailable()
297+
{
298+
return VideoEnhancement::getInstance().isAvailable();
299+
}

app/backend/systemproperties.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ class SystemProperties : public QObject
3737
Q_INVOKABLE QRect getNativeResolution(int displayIndex);
3838
Q_INVOKABLE QRect getSafeAreaResolution(int displayIndex);
3939
Q_INVOKABLE int getRefreshRate(int displayIndex);
40+
Q_INVOKABLE bool isVideoEnhancementSwitchable();
41+
Q_INVOKABLE bool isVideoEnhancementAvailable();
4042

4143
Q_INVOKABLE void startAsyncLoad();
4244
Q_INVOKABLE void waitForAsyncLoad();

app/cli/commandlineparser.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ StreamCommandLineParser::StreamCommandLineParser()
305305
{"5.1-surround", StreamingPreferences::AC_51_SURROUND},
306306
{"7.1-surround", StreamingPreferences::AC_71_SURROUND},
307307
};
308+
m_SuperResolutionModeMap = {
309+
{"auto", StreamingPreferences::SRM_00},
310+
{"driver", StreamingPreferences::SRM_01},
311+
{"video-processor", StreamingPreferences::SRM_02},
312+
{"fsr1-upscaler", StreamingPreferences::SRM_03},
313+
{"nis-upscaler", StreamingPreferences::SRM_04},
314+
{"sgsr1-upscaler", StreamingPreferences::SRM_05},
315+
{"rcas-sharpener", StreamingPreferences::SRM_06},
316+
{"nis-sharpener", StreamingPreferences::SRM_07},
317+
};
308318
m_VideoCodecMap = {
309319
{"auto", StreamingPreferences::VCC_AUTO},
310320
{"H.264", StreamingPreferences::VCC_FORCE_H264},
@@ -352,6 +362,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
352362
parser.addValueOption("packet-size", "video packet size");
353363
parser.addChoiceOption("display-mode", "display mode", m_WindowModeMap.keys());
354364
parser.addChoiceOption("audio-config", "audio config", m_AudioConfigMap.keys());
365+
parser.addChoiceOption("super-resolution-mode", "super resolution mode", m_SuperResolutionModeMap.keys());
355366
parser.addToggleOption("multi-controller", "multiple controller support");
356367
parser.addToggleOption("quit-after", "quit app after session");
357368
parser.addToggleOption("absolute-mouse", "remote desktop optimized mouse control");
@@ -360,6 +371,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
360371
parser.addToggleOption("game-optimization", "game optimizations");
361372
parser.addToggleOption("audio-on-host", "audio on host PC");
362373
parser.addToggleOption("frame-pacing", "frame pacing");
374+
parser.addToggleOption("video-enhancement", "Enhance video with AI");
363375
parser.addToggleOption("mute-on-focus-loss", "mute audio when Moonlight window loses focus");
364376
parser.addToggleOption("background-gamepad", "background gamepad input");
365377
parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction");
@@ -443,6 +455,11 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
443455
preferences->audioConfig = mapValue(m_AudioConfigMap, parser.getChoiceOptionValue("audio-config"));
444456
}
445457

458+
// Resolve --super-resolution-config option
459+
if (parser.isSet("super-resolution-mode")) {
460+
preferences->superResolutionMode = mapValue(m_SuperResolutionModeMap, parser.getChoiceOptionValue("super-resolution-mode"));
461+
}
462+
446463
// Resolve --multi-controller and --no-multi-controller options
447464
preferences->multiController = parser.getToggleOptionValue("multi-controller", preferences->multiController);
448465

@@ -467,6 +484,9 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
467484
// Resolve --frame-pacing and --no-frame-pacing options
468485
preferences->framePacing = parser.getToggleOptionValue("frame-pacing", preferences->framePacing);
469486

487+
// Resolve --video-enhancement and --no-video-enhancement options
488+
preferences->videoEnhancing = parser.getToggleOptionValue("video-enhancement", preferences->videoEnhancing);
489+
470490
// Resolve --mute-on-focus-loss and --no-mute-on-focus-loss options
471491
preferences->muteOnFocusLoss = parser.getToggleOptionValue("mute-on-focus-loss", preferences->muteOnFocusLoss);
472492

app/cli/commandlineparser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class StreamCommandLineParser
6969
QString m_AppName;
7070
QMap<QString, StreamingPreferences::WindowMode> m_WindowModeMap;
7171
QMap<QString, StreamingPreferences::AudioConfig> m_AudioConfigMap;
72+
QMap<QString, StreamingPreferences::SuperResolutionMode> m_SuperResolutionModeMap;
7273
QMap<QString, StreamingPreferences::VideoCodecConfig> m_VideoCodecMap;
7374
QMap<QString, StreamingPreferences::VideoDecoderSelection> m_VideoDecoderMap;
7475
QMap<QString, StreamingPreferences::CaptureSysKeysMode> m_CaptureSysKeysModeMap;

0 commit comments

Comments
 (0)