Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "third_party/imgui"]
path = third_party/imgui
url = https://github.com/ocornut/imgui.git
[submodule "third_party/NVIDIAImageScaling"]
path = third_party/NVIDIAImageScaling
url = https://github.com/NVIDIAGameWorks/NVIDIAImageScaling.git
17 changes: 17 additions & 0 deletions Assets/Shader/build_nis.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@echo off
setlocal
pushd "%~dp0" || exit /b 1
set "HLSL=..\..\third_party\NVIDIAImageScaling\NIS\NIS_Main.hlsl"
set "EXIT_CODE=0"
fxc /T cs_5_0 /E main /O3 /D NIS_SCALER=1 /D NIS_HDR_MODE=0 /D NIS_BLOCK_WIDTH=32 /D NIS_BLOCK_HEIGHT=32 /D NIS_THREAD_GROUP_SIZE=128 /D NIS_USE_HALF_PRECISION=1 /Fo "nis_sdr_fp16.cso" "%HLSL%" || goto :fail
fxc /T cs_5_0 /E main /O3 /D NIS_SCALER=1 /D NIS_HDR_MODE=2 /D NIS_BLOCK_WIDTH=32 /D NIS_BLOCK_HEIGHT=32 /D NIS_THREAD_GROUP_SIZE=128 /D NIS_USE_HALF_PRECISION=1 /Fo "nis_hdr_fp16.cso" "%HLSL%" || goto :fail
fxc /T cs_5_0 /E main /O3 /D NIS_SCALER=1 /D NIS_HDR_MODE=0 /D NIS_BLOCK_WIDTH=32 /D NIS_BLOCK_HEIGHT=24 /D NIS_THREAD_GROUP_SIZE=128 /D NIS_USE_HALF_PRECISION=0 /Fo "nis_sdr_fp32.cso" "%HLSL%" || goto :fail
fxc /T cs_5_0 /E main /O3 /D NIS_SCALER=1 /D NIS_HDR_MODE=2 /D NIS_BLOCK_WIDTH=32 /D NIS_BLOCK_HEIGHT=24 /D NIS_THREAD_GROUP_SIZE=128 /D NIS_USE_HALF_PRECISION=0 /Fo "nis_hdr_fp32.cso" "%HLSL%" || goto :fail
goto :cleanup

:fail
set "EXIT_CODE=%ERRORLEVEL%"

:cleanup
popd
endlocal & exit /b %EXIT_CODE%
Binary file added Assets/Shader/nis_hdr_fp16.cso
Binary file not shown.
Binary file added Assets/Shader/nis_hdr_fp32.cso
Binary file not shown.
Binary file added Assets/Shader/nis_sdr_fp16.cso
Binary file not shown.
Binary file added Assets/Shader/nis_sdr_fp32.cso
Binary file not shown.
1 change: 1 addition & 0 deletions Pages/AppPage.xaml.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ void AppPage::Connect(int appId) {
config->audioConfig = host->AudioConfig;
config->videoCodec = host->VideoCodec;
config->playAudioOnPC = host->PlayAudioOnPC;
config->videoSuperResolution = host->VideoSuperResolution;
config->enableHDR = host->EnableHDR;
config->enableSOPS = host->EnableSOPS;
config->framePacing = host->FramePacing;
Expand Down
51 changes: 27 additions & 24 deletions Pages/HostSettingsPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0">Resolution</TextBlock>
<ComboBox x:Name="ResolutionSelector" SelectionChanged="ResolutionSelector_SelectionChanged" SelectedIndex="{x:Bind CurrentResolutionIndex,Mode=TwoWay}" Grid.Row="0" Grid.Column="1" ItemsSource="{x:Bind AvailableResolutions}">
Expand All @@ -57,58 +58,60 @@
<ComboBox x:Name="FPSSelector" SelectionChanged="FPSSelector_SelectionChanged" SelectedItem="{x:Bind Host.FPS,Mode=OneWay}" Grid.Row="1" Grid.Column="1" ItemsSource="{x:Bind AvailableFPS}"></ComboBox>
<TextBlock Grid.Row="2" Grid.Column="0">Bitrate (Kbps)</TextBlock>
<Slider Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Value="{x:Bind Host.Bitrate}" x:DefaultBindMode="TwoWay" Minimum="5000" Maximum="500000" SmallChange="10000" TickFrequency="50000" StepFrequency="50000" />
<TextBlock Grid.Row="3" Grid.Column="0">Audio Configuration</TextBlock>
<ComboBox ItemsSource="{x:Bind AvailableAudioConfigs}" SelectedItem="{x:Bind Host.AudioConfig,Mode=TwoWay}" Grid.Row="3" Grid.Column="1"></ComboBox>
<TextBlock Grid.Row="4" Grid.Column="0">Play Audio on Host PC</TextBlock>
<CheckBox Grid.Row="4" Grid.Column="1" IsChecked="{x:Bind Host.PlayAudioOnPC, Mode=TwoWay}"></CheckBox>
<TextBlock Grid.Row="5" Grid.Column="0">Autostart</TextBlock>
<ComboBox Grid.Row="5" Grid.Column="1" SelectedIndex="{x:Bind CurrentAppIndex,Mode=TwoWay}" Name="AutoStartSelector" SelectionChanged="AutoStartSelector_SelectionChanged">
<TextBlock Grid.Row="3" Grid.Column="0">Video Super Resolution</TextBlock>
<CheckBox Grid.Row="3" Grid.Column="1" IsChecked="{x:Bind Host.VideoSuperResolution, Mode=TwoWay}"></CheckBox>
<TextBlock Grid.Row="4" Grid.Column="0">Audio Configuration</TextBlock>
<ComboBox ItemsSource="{x:Bind AvailableAudioConfigs}" SelectedItem="{x:Bind Host.AudioConfig,Mode=TwoWay}" Grid.Row="4" Grid.Column="1"></ComboBox>
<TextBlock Grid.Row="5" Grid.Column="0">Play Audio on Host PC</TextBlock>
<CheckBox Grid.Row="5" Grid.Column="1" IsChecked="{x:Bind Host.PlayAudioOnPC, Mode=TwoWay}"></CheckBox>
<TextBlock Grid.Row="6" Grid.Column="0">Autostart</TextBlock>
<ComboBox Grid.Row="6" Grid.Column="1" SelectedIndex="{x:Bind CurrentAppIndex,Mode=TwoWay}" Name="AutoStartSelector" SelectionChanged="AutoStartSelector_SelectionChanged">
</ComboBox>
<TextBlock Grid.Row="6" Grid.Column="0">Video Codecs</TextBlock>
<ComboBox Name="CodecComboBox" ItemsSource="{x:Bind AvailableVideoCodecs}" SelectedItem="{x:Bind Host.VideoCodec,Mode=TwoWay}" Grid.Row="6" Grid.Column="1"></ComboBox>
<TextBlock Grid.Row="7" Grid.Column="0">Video Codecs</TextBlock>
<ComboBox Name="CodecComboBox" ItemsSource="{x:Bind AvailableVideoCodecs}" SelectedItem="{x:Bind Host.VideoCodec,Mode=TwoWay}" Grid.Row="7" Grid.Column="1"></ComboBox>

<TextBlock Grid.Row="7" Grid.Column="0" >Enable HDR:</TextBlock>
<TextBlock Grid.Row="8" Grid.Column="0" >Enable HDR:</TextBlock>
<CheckBox
Name="EnableHDRCheckbox" Grid.Row="7" Grid.Column="1"
Name="EnableHDRCheckbox" Grid.Row="8" Grid.Column="1"
IsChecked="{x:Bind Host.EnableHDR,Mode=TwoWay}" />
<TextBlock
Name="HDR4KNote" Grid.Row="7" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
Name="HDR4KNote" Grid.Row="8" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
HDR requires Xbox system resolution set to 4K.
</TextBlock>

<TextBlock Grid.Row="8" Grid.Column="0" >Optimize host resolution:</TextBlock>
<CheckBox Name="EnableSOPSCheckbox" Grid.Row="8" Grid.Column="1" IsChecked="{x:Bind Host.EnableSOPS,Mode=TwoWay}"></CheckBox>
<TextBlock Grid.Row="9" Grid.Column="0" >Optimize host resolution:</TextBlock>
<CheckBox Name="EnableSOPSCheckbox" Grid.Row="9" Grid.Column="1" IsChecked="{x:Bind Host.EnableSOPS,Mode=TwoWay}"></CheckBox>

<TextBlock Grid.Row="9" Grid.Column="0">Frame Pacing:</TextBlock>
<ComboBox Name="FramePacingComboBox" ItemsSource="{x:Bind AvailableFramePacing}" SelectedItem="{x:Bind Host.FramePacing,Mode=TwoWay}" SelectionChanged="FramePacing_SelectionChanged" Grid.Row="9" Grid.Column="1"></ComboBox>
<TextBlock Grid.Row="10" Grid.Column="0">Frame Pacing:</TextBlock>
<ComboBox Name="FramePacingComboBox" ItemsSource="{x:Bind AvailableFramePacing}" SelectedItem="{x:Bind Host.FramePacing,Mode=TwoWay}" SelectionChanged="FramePacing_SelectionChanged" Grid.Row="10" Grid.Column="1"></ComboBox>
<TextBlock
Name="FramePacingImmediateDesc" Grid.Row="9" Grid.Column="2" Visibility="Collapsed">
Name="FramePacingImmediateDesc" Grid.Row="10" Grid.Column="2" Visibility="Collapsed">
Best for Xbox Series. Lowest latency. Renders frames at the incoming frame rate.
</TextBlock>
<TextBlock
Name="FramePacingDisplayLockedDesc" Grid.Row="9" Grid.Column="2" Visibility="Collapsed">
Name="FramePacingDisplayLockedDesc" Grid.Row="10" Grid.Column="2" Visibility="Collapsed">
Best for Xbox One. Locks rendering frame rate to refresh rate and evenly spaces frames.
</TextBlock>

<TextBlock Grid.Row="10" Grid.Column="0">Show performance stats:</TextBlock>
<TextBlock Grid.Row="11" Grid.Column="0">Show performance stats:</TextBlock>
<CheckBox
Grid.Row="10" Grid.Column="1"
Grid.Row="11" Grid.Column="1"
x:Name="EnableStatsCheckbox"
IsChecked="{x:Bind Host.EnableStats, Mode=TwoWay}" />

<TextBlock Grid.Row="11" Grid.Column="0" >Show performance graphs:</TextBlock>
<TextBlock Grid.Row="12" Grid.Column="0" >Show performance graphs:</TextBlock>
<CheckBox
Grid.Row="11" Grid.Column="1"
Grid.Row="12" Grid.Column="1"
x:Name="EnableGraphsCheckbox"
IsEnabled="{x:Bind Host.EnableStats, Mode=OneWay}"
IsChecked="{x:Bind Host.EnableGraphs, Mode=TwoWay}" />
<TextBlock
Name="XboxOneGraphsNote" Grid.Row="11" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
Name="XboxOneGraphsNote" Grid.Row="12" Grid.Column="1" Grid.ColumnSpan="2" Visibility="Collapsed">
Graphs are unavailable on Xbox One when system resolution is set to 4K.
</TextBlock>

<TextBlock Grid.Row="12" Grid.Column="0">Other:</TextBlock>
<Button Grid.Row="12" Grid.Column="1" x:Name="GlobalSettingsOption" Click="GlobalSettingsOption_Click">Open Global Settings</Button>
<TextBlock Grid.Row="13" Grid.Column="0">Other:</TextBlock>
<Button Grid.Row="13" Grid.Column="1" x:Name="GlobalSettingsOption" Click="GlobalSettingsOption_Click">Open Global Settings</Button>
</Grid>
</StackPanel>
</ScrollViewer>
Expand Down
2 changes: 2 additions & 0 deletions State/ApplicationState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Concurrency::task<void> moonlight_xbox_dx::ApplicationState::Init()
if (a.contains("autoStartID"))h->AutostartID = a["autoStartID"];
if (a.contains("computername")) h->ComputerName = Utils::StringFromStdString(a["computername"].get<std::string>());
if (a.contains("playaudioonpc")) h->PlayAudioOnPC = a["playaudioonpc"].get<bool>();
if (a.contains("video_super_resolution")) h->VideoSuperResolution = a["video_super_resolution"].get<bool>();
if (a.contains("enable_hdr")) h->EnableHDR = a["enable_hdr"].get<bool>();
if (a.contains("enable_sops")) h->EnableSOPS = a["enable_sops"].get<bool>();
if (a.contains("enable_stats")) h->EnableStats = a["enable_stats"].get<bool>();
Expand Down Expand Up @@ -104,6 +105,7 @@ Concurrency::task<void> moonlight_xbox_dx::ApplicationState::UpdateFile()
hostJson["framePacing"] = Utils::PlatformStringToStdString(host->FramePacing);
hostJson["autoStartID"] = host->AutostartID;
hostJson["playaudioonpc"] = host->PlayAudioOnPC;
hostJson["video_super_resolution"] = host->VideoSuperResolution;
hostJson["enable_hdr"] = host->EnableHDR;
hostJson["enable_sops"] = host->EnableSOPS;
hostJson["enable_stats"] = host->EnableStats;
Expand Down
10 changes: 10 additions & 0 deletions State/MoonlightHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ namespace moonlight_xbox_dx {
bool loading = true;
bool wolPolling = false;
bool playAudioOnPC = false;
bool videoSuperResolution = false;
MoonlightClient* client;
int currentlyRunningAppId;
int bitrate = 20000;
Expand Down Expand Up @@ -249,6 +250,15 @@ namespace moonlight_xbox_dx {
}
}

property bool VideoSuperResolution
{
bool get() { return this->videoSuperResolution; }
void set(bool value) {
this->videoSuperResolution = value;
OnPropertyChanged("VideoSuperResolution");
}
}

property bool EnableHDR
{
bool get() { return this->enableHDR; }
Expand Down
58 changes: 45 additions & 13 deletions State/Stats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Utils.hpp"
#include "../Plot/ImGuiPlots.h"
#include "../Streaming/FFMpegDecoder.h"
#include "../State/StreamConfiguration.h"

using namespace moonlight_xbox_dx;

Expand Down Expand Up @@ -45,7 +46,12 @@ bool Stats::ShouldUpdateDisplay(DX::StepTimer const& timer, bool isVisible, char

// Move this window into the last window slot and clear it for next window
memcpy(&m_LastWndVideoStats, &m_ActiveWndVideoStats, sizeof(VIDEO_STATS));

// Preserve the scaleRatio which is set directly by the renderer and doesn't accumulate
float currentScaleRatio = m_ActiveWndVideoStats.scaleRatio;
ZeroMemory(&m_ActiveWndVideoStats, sizeof(VIDEO_STATS));
m_ActiveWndVideoStats.scaleRatio = currentScaleRatio;

m_ActiveWndVideoStats.measurementStartTimestamp = timer.GetTotalSeconds();
}

Expand Down Expand Up @@ -149,6 +155,11 @@ void Stats::SubmitRenderStats(double preWaitTimeMs, double renderTimeMs, double
m_ActiveWndVideoStats.totalPresentTimeUs += static_cast<uint64_t>(presentTimeMs * 1000);
}

void Stats::SubmitScaleRatio(float scaleRatio) {
std::lock_guard<std::mutex> lock(m_mutex);
m_ActiveWndVideoStats.scaleRatio = scaleRatio;
}

/// private methods

void Stats::addVideoStats(DX::StepTimer const& timer, VIDEO_STATS& src, VIDEO_STATS& dst) {
Expand All @@ -167,6 +178,7 @@ void Stats::addVideoStats(DX::StepTimer const& timer, VIDEO_STATS& src, VIDEO_ST
dst.totalPreWaitTimeUs += src.totalPreWaitTimeUs;
dst.totalPresentTimeUs += src.totalPresentTimeUs;
dst.totalPresentDisplayMs += src.totalPresentDisplayMs;
dst.scaleRatio = src.scaleRatio;

if (dst.minHostProcessingLatency == 0) {
dst.minHostProcessingLatency = src.minHostProcessingLatency;
Expand Down Expand Up @@ -299,19 +311,39 @@ void Stats::formatVideoStats(DX::StepTimer const& timer, VIDEO_STATS& stats, cha
double avgVideoMbps = m_bwTracker.GetAverageMbps();
double peakVideoMbps = m_bwTracker.GetPeakMbps();

ret = snprintf(&output[offset],
length - offset,
"Bitrate: %.1f Mbps, Peak (%us): %.1f\n"
"Incoming frame rate from network: %.2f FPS\n"
"Decoding frame rate: %.2f FPS\n"
"Rendering frame rate: %.2f FPS (%s)\n",
avgVideoMbps,
m_bwTracker.GetWindowSeconds(),
peakVideoMbps,
stats.receivedFps,
stats.decodedFps,
stats.renderedFps,
Pacer::instance().getPacingImmediate() ? "immediate" : "display-locked");
bool isVSREnabled = GetStreamConfig() != nullptr && GetStreamConfig()->videoSuperResolution;

if (isVSREnabled) {
ret = snprintf(&output[offset],
length - offset,
"Bitrate: %.1f Mbps, Peak (%us): %.1f\n"
"Video Enhancement: (x%.2f) NIS Shader\n"
"Incoming frame rate from network: %.2f FPS\n"
"Decoding frame rate: %.2f FPS\n"
"Rendering frame rate: %.2f FPS (%s)\n",
avgVideoMbps,
m_bwTracker.GetWindowSeconds(),
peakVideoMbps,
stats.scaleRatio,
stats.receivedFps,
stats.decodedFps,
stats.renderedFps,
Pacer::instance().getPacingImmediate() ? "immediate" : "display-locked");
} else {
ret = snprintf(&output[offset],
length - offset,
"Bitrate: %.1f Mbps, Peak (%us): %.1f\n"
"Incoming frame rate from network: %.2f FPS\n"
"Decoding frame rate: %.2f FPS\n"
"Rendering frame rate: %.2f FPS (%s)\n",
avgVideoMbps,
m_bwTracker.GetWindowSeconds(),
peakVideoMbps,
stats.receivedFps,
stats.decodedFps,
stats.renderedFps,
Pacer::instance().getPacingImmediate() ? "immediate" : "display-locked");
}
if (ret < 0 || (size_t)ret >= (length - offset)) {
Utils::Log("Error: stringifyVideoStats length overflow\n");
return;
Expand Down
2 changes: 2 additions & 0 deletions State/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ typedef struct _VIDEO_STATS {
double decodedFps;
double renderedFps;
double measurementStartTimestamp;
float scaleRatio;
} VIDEO_STATS, *PVIDEO_STATS;

namespace moonlight_xbox_dx
Expand All @@ -64,6 +65,7 @@ namespace moonlight_xbox_dx
void SubmitPacerTime(int64_t pacerTimeQpc);
void SubmitPresentPacing(double presentDisplayMs);
void SubmitRenderStats(double preWaitTimeMs, double renderTimeMs, double presentTimeMs, bool hitDeadline);
void SubmitScaleRatio(float scaleRatio);

private:
void addVideoStats(DX::StepTimer const& timer, VIDEO_STATS& src, VIDEO_STATS& dst);
Expand Down
1 change: 1 addition & 0 deletions State/StreamConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace moonlight_xbox_dx
property Platform::String^ framePacing;
property bool enableHDR;
property bool playAudioOnPC;
property bool videoSuperResolution;
property bool enableVsync;
property bool enableSOPS;
property bool enableStats;
Expand Down
11 changes: 7 additions & 4 deletions Streaming/StatsRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "../Plot/PlotDesc.h"
#include "FFMpegDecoder.h"
#include "Utils.hpp"
#include "../State/StreamConfiguration.h"

using namespace DirectX;
using namespace moonlight_xbox_dx;
Expand Down Expand Up @@ -187,17 +188,19 @@ void StatsRenderer::CreateWindowSizeDependentResources() {
int right = m_displayWidth / 3;
int bottom = 0;

// 13 lines of text
// Check if Video Super Resolution is enabled to allocate space for 14 lines instead of 13
bool isVSREnabled = GetStreamConfig() != nullptr && GetStreamConfig()->videoSuperResolution;

if (m_displayHeight >= 2160) { // 24pt font
left = 20;
right = m_displayWidth / 2;
bottom = 448;
bottom = isVSREnabled ? 483 : 448; // 14 lines (483) vs 13 lines (448)
} else if (m_displayHeight >= 1440) { // 12pt font
left = 14;
bottom = 224;
bottom = isVSREnabled ? 242 : 224; // 14 lines (242) vs 13 lines (224)
} else {
left = 10;
bottom = 224;
bottom = isVSREnabled ? 242 : 224; // 14 lines (242) vs 13 lines (224)
}

#if defined(_DEBUG)
Expand Down
Loading