Skip to content

Commit

Permalink
Add HDR support for Desktop Duplication & Graphics Capture
Browse files Browse the repository at this point in the history
- Add optional R16G16B16A16_FLOAT texture handling to Desktop Duplication, using DuplicateOutput1 interface
- Add DPWinRT_SetHDREnabled() to control texture format used by Graphics Capture
- Add setting to toggle HDR mirroring
- Mark dashboard app as PerMonitorHighDPIAware (confusingly necessary for DuplicateOutput1 to work)
- Remove unused overlay texture shader resource view
  • Loading branch information
elvissteinjr committed Nov 20, 2024
1 parent 41c783e commit aa4bf18
Show file tree
Hide file tree
Showing 17 changed files with 202 additions and 54 deletions.
4 changes: 3 additions & 1 deletion assets/lang/de.ini
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,10 @@ tstr_SettingsPerformanceUpdateLimiterOverrideTip=Wenn mehrere Überschreibungen
tstr_SettingsPerformanceUpdateLimiterModeOverride=Überschreibe Updatelimiter
tstr_SettingsPerformanceRapidUpdates=Verringere Laserpointer-Latenz
tstr_SettingsPerformanceRapidUpdatesTip=Verringere die Latenz von Laserpointer-Eingaben auf Kosten zusätzlicher CPU-Last, solange auf ein Overlay gezeigt wird
tstr_SettingsPerformanceSingleDesktopMirror=Einzelne Desktopspiegellung
tstr_SettingsPerformanceSingleDesktopMirror=Einzelne Desktopspiegelung
tstr_SettingsPerformanceSingleDesktopMirrorTip=Spiegele individuelle Desktops, wenn zu ihnen gewechselt wird, anstatt vom gesamten Desktop zuzuschneiden.\nSolange diese Einstellung aktiv ist, werden alle Overlays den selben Desktop zeigen.
tstr_SettingsPerformanceUseHDR=HDR-Spiegelung
tstr_SettingsPerformanceUseHDRTip=Verwende beim Spiegeln von Desktops und Fenstern Texturen mit höherer Bittiefe, zur HDR-Unterstützung.\nKann die Leistung beeinträchtigen, falls nicht erforderlich, und erhöht VRAM-Verbrauch.
tstr_SettingsPerformanceShowFPS=Zeige FPS in Floating UI
tstr_SettingsWarningsHidden=Versteckte Warnungen:
Expand Down
2 changes: 2 additions & 0 deletions assets/lang/en.ini
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,8 @@ tstr_SettingsPerformanceRapidUpdates=Reduce Laser Pointer Latency
tstr_SettingsPerformanceRapidUpdatesTip=Reduce latency of laser pointer input at the cost of additional CPU load while pointing at an overlay
tstr_SettingsPerformanceSingleDesktopMirror=Single Desktop Mirroring
tstr_SettingsPerformanceSingleDesktopMirrorTip=Mirror individual desktops when switching to them instead of cropping from the combined desktop.\nWhen this is active, all overlays will be showing the same desktop.
tstr_SettingsPerformanceUseHDR=HDR Mirroring
tstr_SettingsPerformanceUseHDRTip=Mirror desktops and windows using higher bit-depth textures, supporting HDR output.\nMay negatively impact performance when not required and increases VRAM usage.
tstr_SettingsPerformanceShowFPS=Show FPS in Floating UI

tstr_SettingsWarningsHidden=Warnings Hidden:
Expand Down
5 changes: 4 additions & 1 deletion src/DesktopPlus/DesktopPlus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,8 +766,11 @@ DWORD WINAPI CaptureThreadEntry(_In_ void* Param)
goto Exit;
}

D3D11_TEXTURE2D_DESC SharedSurfDesc;
SharedSurf->GetDesc(&SharedSurfDesc);

// Make duplication manager
Ret = DuplMgr.InitDupl(TData->DxRes.Device, TData->Output, TData->WMRIgnoreVScreens);
Ret = DuplMgr.InitDupl(TData->DxRes.Device, TData->Output, TData->WMRIgnoreVScreens, SharedSurfDesc.Format != DXGI_FORMAT_B8G8R8A8_UNORM);
if (Ret != DUPL_RETURN_SUCCESS)
{
goto Exit;
Expand Down
4 changes: 2 additions & 2 deletions src/DesktopPlus/DesktopPlus.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)Shared;$(OutputPath)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>true</EnableDpiAwareness>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<AssemblyIdentity>"DesktopPlus_$([System.DateTime]::Now.ToFileTime()), version=1"</AssemblyIdentity>
</Manifest>
</ItemDefinitionGroup>
Expand Down Expand Up @@ -99,7 +99,7 @@
<AdditionalLibraryDirectories>$(SolutionDir)Shared;$(OutputPath)</AdditionalLibraryDirectories>
</Link>
<Manifest>
<EnableDpiAwareness>true</EnableDpiAwareness>
<EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>
<AssemblyIdentity>"DesktopPlus_$([System.DateTime]::Now.ToFileTime()), version=1"</AssemblyIdentity>
</Manifest>
</ItemDefinitionGroup>
Expand Down
67 changes: 54 additions & 13 deletions src/DesktopPlus/DuplicationManager.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
#include "DuplicationManager.h"
#include <wrl/client.h>

#include <sdkddkver.h>

//Keep building with 10.0.17763.0 / 1809 SDK optional
#ifdef NTDDI_WIN10_RS5
#include <dxgi1_5.h>
#else
#define DPLUS_DUP_NO_HDR
#endif

//
// Constructor sets up references / variables
//
Expand Down Expand Up @@ -47,10 +56,14 @@ DUPLICATIONMANAGER::~DUPLICATIONMANAGER()
//
// Initialize duplication interfaces
//
DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, UINT Output, bool WMRIgnoreVScreens)
DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, UINT Output, bool WMRIgnoreVScreens, bool UseHDR)
{
m_OutputNumber = Output;

#ifdef DPLUS_DUP_NO_HDR
UseHDR = false;
#endif

// Take a reference on the device
m_Device = Device;
m_Device->AddRef();
Expand Down Expand Up @@ -119,23 +132,51 @@ DUPL_RETURN DUPLICATIONMANAGER::InitDupl(_In_ ID3D11Device* Device, UINT Output,

DxgiOutput->GetDesc(&m_OutputDesc);

Microsoft::WRL::ComPtr<IDXGIOutput1> DxgiOutput1;
hr = DxgiOutput.As(&DxgiOutput1);
if (FAILED(hr))
//Create desktop duplication
if (!UseHDR)
{
return ProcessFailure(nullptr, L"Failed to get output as DxgiOutput1", L"Desktop+ Error", hr);
}
Microsoft::WRL::ComPtr<IDXGIOutput1> DxgiOutput1;
hr = DxgiOutput.As(&DxgiOutput1);
if (FAILED(hr))
{
return ProcessFailure(nullptr, L"Failed to get output as DxgiOutput1", L"Desktop+ Error", hr);
}

//Create desktop duplication
hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl);
if (FAILED(hr))
hr = DxgiOutput1->DuplicateOutput(m_Device, &m_DeskDupl);
if (FAILED(hr))
{
if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
{
ProcessFailure(m_Device, L"There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again", L"Desktop+ Error", hr);
return DUPL_RETURN_ERROR_UNEXPECTED;
}
return ProcessFailure(m_Device, L"Failed to get duplicate output", L"Desktop+ Error", hr, CreateDuplicationExpectedErrors);
}
}
else
{
if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
#ifndef DPLUS_DUP_NO_HDR

Microsoft::WRL::ComPtr<IDXGIOutput5> DxgiOutput5;
hr = DxgiOutput.As(&DxgiOutput5);
if (FAILED(hr))
{
ProcessFailure(m_Device, L"There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again", L"Desktop+ Error", hr);
return DUPL_RETURN_ERROR_UNEXPECTED;
return ProcessFailure(nullptr, L"Failed to get output as DxgiOutput5", L"Desktop+ Error", hr);
}
return ProcessFailure(m_Device, L"Failed to get duplicate output", L"Desktop+ Error", hr, CreateDuplicationExpectedErrors);

const DXGI_FORMAT supported_formats[] = {DXGI_FORMAT_R16G16B16A16_FLOAT};
hr = DxgiOutput5->DuplicateOutput1(m_Device, 0, 1, supported_formats, &m_DeskDupl);
if (FAILED(hr))
{
if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE)
{
ProcessFailure(m_Device, L"There is already the maximum number of applications using the Desktop Duplication API running, please close one of those applications and then try again", L"Desktop+ Error", hr);
return DUPL_RETURN_ERROR_UNEXPECTED;
}
return ProcessFailure(m_Device, L"Failed to get duplicate output", L"Desktop+ Error", hr, CreateDuplicationExpectedErrors);
}

#endif
}

return DUPL_RETURN_SUCCESS;
Expand Down
2 changes: 1 addition & 1 deletion src/DesktopPlus/DuplicationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class DUPLICATIONMANAGER
~DUPLICATIONMANAGER();
_Success_(*Timeout == false && return == DUPL_RETURN_SUCCESS) DUPL_RETURN GetFrame(_Out_ FRAME_DATA* Data, _Out_ bool* Timeout);
DUPL_RETURN DoneWithFrame();
DUPL_RETURN InitDupl(_In_ ID3D11Device* Device, UINT Output, bool WMRIgnoreVScreens);
DUPL_RETURN InitDupl(_In_ ID3D11Device* Device, UINT Output, bool WMRIgnoreVScreens, bool UseHDR);
DUPL_RETURN GetMouse(_Inout_ PTR_INFO* PtrInfo, _In_ DXGI_OUTDUPL_FRAME_INFO* FrameInfo, INT OffsetX, INT OffsetY);
void GetOutputDesc(_Out_ DXGI_OUTPUT_DESC* DescPtr);

Expand Down
85 changes: 59 additions & 26 deletions src/DesktopPlus/OutputManager.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
#include "OutputManager.h"

//Keep building with 10.0.17763.0 / 1809 SDK optional
#ifdef NTDDI_WIN10_RS5
#include <dxgi1_5.h>
#else
#define DPLUS_DUP_NO_HDR
#endif

#include <dwmapi.h>
#include <windowsx.h>
#include <ShlDisp.h>
Expand Down Expand Up @@ -58,6 +65,7 @@ OutputManager::OutputManager(HANDLE PauseDuplicationEvent, HANDLE ResumeDuplicat
m_MaxActiveRefreshDelay(16),
m_OutputPendingSkippedFrame(false),
m_OutputPendingFullRefresh(false),
m_OutputHDRAvailable(false),
m_OutputInvalid(false),
m_OutputPendingDirtyRect{-1, -1, -1, -1},
m_OutputAlphaCheckFailed(false),
Expand All @@ -67,7 +75,6 @@ OutputManager::OutputManager(HANDLE PauseDuplicationEvent, HANDLE ResumeDuplicat
m_OvrlHandleDesktopTexture(vr::k_ulOverlayHandleInvalid),
m_OvrlTex(nullptr),
m_OvrlRTV(nullptr),
m_OvrlShaderResView(nullptr),
m_OvrlActiveCount(0),
m_OvrlDesktopDuplActiveCount(0),
m_OvrlDashboardActive(false),
Expand Down Expand Up @@ -215,12 +222,6 @@ void OutputManager::CleanRefs()
m_OvrlRTV = nullptr;
}

if (m_OvrlShaderResView)
{
m_OvrlShaderResView->Release();
m_OvrlShaderResView = nullptr;
}

if (m_MouseTex)
{
m_MouseTex->Release();
Expand Down Expand Up @@ -368,10 +369,6 @@ DUPL_RETURN OutputManager::InitOutput(HWND Window, _Out_ INT& SingleOutput, _Out
}
}
}
else
{
adapter_ptr_preferred = nullptr;
}

if (FAILED(hr))
{
Expand All @@ -394,6 +391,33 @@ DUPL_RETURN OutputManager::InitOutput(HWND Window, _Out_ INT& SingleOutput, _Out
LOG_F(INFO, "Using cross-GPU copy");
}

//Check Desktop Duplication HDR support
m_OutputHDRAvailable = false;

#ifndef DPLUS_DUP_NO_HDR
{
Microsoft::WRL::ComPtr<IDXGIOutput> DxgiOutput;
hr = adapter_ptr_preferred->EnumOutputs(0, &DxgiOutput);
if (SUCCEEDED(hr))
{
Microsoft::WRL::ComPtr<IDXGIOutput5> DxgiOutput5;
hr = DxgiOutput.As(&DxgiOutput5);
m_OutputHDRAvailable = SUCCEEDED(hr);
}

if (m_OutputHDRAvailable)
{
LOG_F(INFO, "Desktop Duplication HDR mirroring is supported");
}
else
{
LOG_F(INFO, "Desktop Duplication HDR mirroring is not supported");
}
}
#else
LOG_F(INFO, "Desktop+ was not built with Desktop Duplication HDR support");
#endif

// Create shared texture
DUPL_RETURN Return = CreateTextures(SingleOutput, OutCount, DeskBounds);
if (Return != DUPL_RETURN_SUCCESS)
Expand Down Expand Up @@ -1539,6 +1563,12 @@ bool OutputManager::HandleIPCMessage(const MSG& msg)
reset_mirroring = true;
break;
}
case configid_bool_performance_hdr_mirroring:
{
reset_mirroring = true;
DPWinRT_SetHDREnabled(msg.lParam);
break;
}
case configid_bool_input_mouse_render_cursor:
{
m_OutputPendingFullRefresh = true;
Expand Down Expand Up @@ -3100,24 +3130,18 @@ DUPL_RETURN OutputManager::ProcessMonoMask(bool IsMono, _Inout_ PTR_INFO* PtrInf
//
DUPL_RETURN OutputManager::MakeRTV()
{
// Create render target for overlay texture
D3D11_RENDER_TARGET_VIEW_DESC ovrl_tex_rtv_desc;
D3D11_SHADER_RESOURCE_VIEW_DESC ovrl_tex_shader_res_view_desc;
D3D11_TEXTURE2D_DESC desc_ovrl_tex;
m_OvrlTex->GetDesc(&desc_ovrl_tex);

ovrl_tex_rtv_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
//Create render target view for overlay texture
D3D11_RENDER_TARGET_VIEW_DESC ovrl_tex_rtv_desc = {};

ovrl_tex_rtv_desc.Format = desc_ovrl_tex.Format;
ovrl_tex_rtv_desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
ovrl_tex_rtv_desc.Texture2D.MipSlice = 0;

m_Device->CreateRenderTargetView(m_OvrlTex, &ovrl_tex_rtv_desc, &m_OvrlRTV);

// Create the shader resource view for overlay texture while we're at it
ovrl_tex_shader_res_view_desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
ovrl_tex_shader_res_view_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
ovrl_tex_shader_res_view_desc.Texture2D.MostDetailedMip = 0;
ovrl_tex_shader_res_view_desc.Texture2D.MipLevels = 1;

m_Device->CreateShaderResourceView(m_OvrlTex, &ovrl_tex_shader_res_view_desc, &m_OvrlShaderResView);

return DUPL_RETURN_SUCCESS;
}

Expand Down Expand Up @@ -3256,7 +3280,7 @@ DUPL_RETURN OutputManager::CreateTextures(INT SingleOutput, _Out_ UINT* OutCount
TexD.Height = m_DesktopHeight;
TexD.MipLevels = 1;
TexD.ArraySize = 1;
TexD.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
TexD.Format = ((m_OutputHDRAvailable) && (ConfigManager::GetValue(configid_bool_performance_hdr_mirroring))) ? DXGI_FORMAT_R16G16B16A16_FLOAT : DXGI_FORMAT_B8G8R8A8_UNORM;
TexD.SampleDesc.Count = 1;
TexD.Usage = D3D11_USAGE_DEFAULT;
TexD.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
Expand Down Expand Up @@ -3614,7 +3638,7 @@ DUPL_RETURN_UPD OutputManager::RefreshOpenVROverlayTexture(DPRect& DirtyRectTota
{
vr::Texture_t vrtex;
vrtex.eType = vr::TextureType_DirectX;
vrtex.eColorSpace = vr::ColorSpace_Gamma;
vrtex.eColorSpace = ((m_OutputHDRAvailable) && (ConfigManager::GetValue(configid_bool_performance_hdr_mirroring))) ? vr::ColorSpace_Linear : vr::ColorSpace_Gamma;
vrtex.handle = m_OvrlTex;

//The intermediate texture can be assumed to be not complete when a full copy is forced, so redraw that
Expand Down Expand Up @@ -3773,7 +3797,7 @@ bool OutputManager::DesktopTextureAlphaCheck()
desc.Height = 1;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
desc.Format = desc_ovrl_tex.Format;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_STAGING;
Expand Down Expand Up @@ -5517,6 +5541,8 @@ void OutputManager::ApplySetting3DMode()
void OutputManager::ApplySettingTransform()
{
Overlay& overlay = OverlayManager::Get().GetCurrentOverlay();
const OverlayConfigData& data = OverlayManager::Get().GetCurrentConfigData();

vr::VROverlayHandle_t ovrl_handle = overlay.GetHandle();

//Fixup overlay visibility if needed
Expand Down Expand Up @@ -5742,6 +5768,13 @@ void OutputManager::ApplySettingTransform()
//Update Brightness
//We use the logarithmic counterpart since the changes in higher steps are barely visible while the lower range can really use those additional steps
float brightness = lin2log(ConfigManager::Get().GetValue(configid_float_overlay_brightness));

//Apply HDR brightness multiplier if needed
if ((ConfigManager::GetValue(configid_bool_performance_hdr_mirroring)) && (data.ConfigInt[configid_int_overlay_capture_source] == ovrl_capsource_winrt_capture))
{
brightness *= DPLUSWINRT_HDR_BRIGHTNESS_ADJUST;
}

vr::VROverlay()->SetOverlayColor(ovrl_handle, brightness, brightness, brightness);

//Set last tick for dashboard dummy delayed update
Expand Down
2 changes: 1 addition & 1 deletion src/DesktopPlus/OutputManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ class OutputManager
std::vector<DPRect> m_DesktopRects; //Cached position and size of available desktops
DPRect m_DesktopRectTotal; //Total rect of all available desktops (may not be the same as above Desktop Duplication rect if that's not using the combined desktop)
DWORD m_MaxActiveRefreshDelay;
bool m_OutputHDRAvailable; //False if OS doesn't support the required interface, regardless of hardware connected
bool m_OutputInvalid;
bool m_OutputPendingSkippedFrame;
bool m_OutputPendingFullRefresh;
Expand All @@ -207,7 +208,6 @@ class OutputManager
vr::VROverlayHandle_t m_OvrlHandleDesktopTexture;
ID3D11Texture2D* m_OvrlTex;
ID3D11RenderTargetView* m_OvrlRTV;
ID3D11ShaderResourceView* m_OvrlShaderResView;
int m_OvrlActiveCount;
int m_OvrlDesktopDuplActiveCount;
bool m_OvrlDashboardActive;
Expand Down
2 changes: 2 additions & 0 deletions src/DesktopPlusUI/TranslationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ const char* TranslationManager::s_StringIDNames[tstr_MAX] =
"tstr_SettingsPerformanceRapidUpdatesTip",
"tstr_SettingsPerformanceSingleDesktopMirror",
"tstr_SettingsPerformanceSingleDesktopMirrorTip",
"tstr_SettingsPerformanceUseHDR",
"tstr_SettingsPerformanceUseHDRTip",
"tstr_SettingsPerformanceShowFPS",
"tstr_SettingsWarningsHidden",
"tstr_SettingsWarningsReset",
Expand Down
2 changes: 2 additions & 0 deletions src/DesktopPlusUI/TranslationManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,8 @@ enum TRMGRStrID
tstr_SettingsPerformanceRapidUpdatesTip,
tstr_SettingsPerformanceSingleDesktopMirror,
tstr_SettingsPerformanceSingleDesktopMirrorTip,
tstr_SettingsPerformanceUseHDR,
tstr_SettingsPerformanceUseHDRTip,
tstr_SettingsPerformanceShowFPS,
tstr_SettingsWarningsHidden,
tstr_SettingsWarningsReset,
Expand Down
Loading

0 comments on commit aa4bf18

Please sign in to comment.