Skip to content

Commit f359c5f

Browse files
committed
Add Video Super Resolution for Windows, 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) - Apple M1 Pro (macOS) - Apple M3 (macOS)
1 parent 2e9fbec commit f359c5f

133 files changed

Lines changed: 53687 additions & 82 deletions

File tree

Some content is hidden

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

.gitignore

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,30 @@
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/stb_image/
30+
!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: 123 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,134 @@ 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+
438+
win32:!winrt {
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+
# IntelVPL is only available for the architecture x64
478+
contains(QT_ARCH, x86_64) {
479+
DEFINES += HAVE_INTEL_VPL
480+
}
481+
}
382482
win32:!winrt {
383-
message(DXVA2 and D3D11VA renderers selected)
483+
message(NVIDIA Image Scaling)
484+
485+
INCLUDEPATH += $$PWD/../third-party/NVIDIAImageScaling/NIS
486+
}
487+
win32:!winrt {
488+
message(Direct3D 12 headers)
489+
490+
INCLUDEPATH += $$PWD/../third-party/DirectX-Headers/include
491+
}
492+
win32:!winrt {
493+
message("DXVA2, D3D11renderers and D3D12renderers selected")
384494

385495
SOURCES += \
386496
streaming/video/ffmpeg-renderers/dxva2.cpp \
387497
streaming/video/ffmpeg-renderers/d3d11va.cpp \
498+
streaming/video/ffmpeg-renderers/d3d12va.cpp \
499+
streaming/video/ffmpeg-renderers/d3d12va_shaders.cpp \
388500
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.cpp
389501

390502
HEADERS += \
391503
streaming/video/ffmpeg-renderers/dxva2.h \
392504
streaming/video/ffmpeg-renderers/d3d11va.h \
505+
streaming/video/ffmpeg-renderers/d3d12va.h \
506+
streaming/video/ffmpeg-renderers/d3d12va_shaders.h \
393507
streaming/video/ffmpeg-renderers/pacer/dxvsyncsource.h
508+
509+
CONFIG(debug, debug|release) {
510+
INCLUDEPATH += $$PWD/../third-party/stb_image
511+
}
394512
}
395513
macx {
396514
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
@@ -271,3 +272,31 @@ void SystemProperties::refreshDisplays()
271272

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

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: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,15 @@ 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+
{"rcas-sharpener", StreamingPreferences::SRM_05},
315+
{"nis-sharpener", StreamingPreferences::SRM_06},
316+
};
308317
m_VideoCodecMap = {
309318
{"auto", StreamingPreferences::VCC_AUTO},
310319
{"H.264", StreamingPreferences::VCC_FORCE_H264},
@@ -352,6 +361,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
352361
parser.addValueOption("packet-size", "video packet size");
353362
parser.addChoiceOption("display-mode", "display mode", m_WindowModeMap.keys());
354363
parser.addChoiceOption("audio-config", "audio config", m_AudioConfigMap.keys());
364+
parser.addChoiceOption("super-resolution-mode", "super resolution mode", m_SuperResolutionModeMap.keys());
355365
parser.addToggleOption("multi-controller", "multiple controller support");
356366
parser.addToggleOption("quit-after", "quit app after session");
357367
parser.addToggleOption("absolute-mouse", "remote desktop optimized mouse control");
@@ -360,6 +370,7 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
360370
parser.addToggleOption("game-optimization", "game optimizations");
361371
parser.addToggleOption("audio-on-host", "audio on host PC");
362372
parser.addToggleOption("frame-pacing", "frame pacing");
373+
parser.addToggleOption("video-enhancement", "Enhance video with AI");
363374
parser.addToggleOption("mute-on-focus-loss", "mute audio when Moonlight window loses focus");
364375
parser.addToggleOption("background-gamepad", "background gamepad input");
365376
parser.addToggleOption("reverse-scroll-direction", "inverted scroll direction");
@@ -443,6 +454,11 @@ void StreamCommandLineParser::parse(const QStringList &args, StreamingPreference
443454
preferences->audioConfig = mapValue(m_AudioConfigMap, parser.getChoiceOptionValue("audio-config"));
444455
}
445456

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

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

486+
// Resolve --video-enhancement and --no-video-enhancement options
487+
preferences->videoEnhancing = parser.getToggleOptionValue("video-enhancement", preferences->videoEnhancing);
488+
470489
// Resolve --mute-on-focus-loss and --no-mute-on-focus-loss options
471490
preferences->muteOnFocusLoss = parser.getToggleOptionValue("mute-on-focus-loss", preferences->muteOnFocusLoss);
472491

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)