From 1130512db5b696ae4e4491d11704ba12dd5a7060 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Thu, 17 Aug 2023 23:30:37 +0100 Subject: [PATCH] [dxgi] Add global HDR interop interface for NVAPI/AGS --- src/dxgi/dxgi_factory.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/dxgi/dxgi_factory.h | 19 ++++++++++++++++++- src/dxgi/dxgi_interfaces.h | 16 ++++++++++++++++ src/dxgi/dxgi_swapchain.cpp | 26 ++++++++++++++++++++++++++ src/dxgi/dxgi_swapchain.h | 4 ++++ 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp index 877cef19..84b3d404 100644 --- a/src/dxgi/dxgi_factory.cpp +++ b/src/dxgi/dxgi_factory.cpp @@ -11,6 +11,9 @@ namespace dxvk { Singleton g_dxvkInstance; + std::mutex s_globalHDRStateMutex; + DXVK_VK_GLOBAL_HDR_STATE s_globalHDRState{}; + DxgiVkFactory::DxgiVkFactory(DxgiFactory* pFactory) : m_factory(pFactory) { @@ -47,6 +50,32 @@ namespace dxvk { } + HRESULT STDMETHODCALLTYPE DxgiVkFactory::GetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + DXGI_HDR_METADATA_HDR10 *pOutMetadata) { + std::unique_lock lock(s_globalHDRStateMutex); + if (!s_globalHDRState.Serial) + return S_FALSE; + + *pOutColorSpace = s_globalHDRState.ColorSpace; + *pOutMetadata = s_globalHDRState.Metadata.HDR10; + return S_OK; + } + + + HRESULT STDMETHODCALLTYPE DxgiVkFactory::SetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE ColorSpace, + const DXGI_HDR_METADATA_HDR10 *pMetadata) { + std::unique_lock lock(s_globalHDRStateMutex); + static uint32_t s_GlobalHDRStateSerial = 0; + + s_globalHDRState.Serial = ++s_GlobalHDRStateSerial; + s_globalHDRState.ColorSpace = ColorSpace; + s_globalHDRState.Metadata.Type = DXGI_HDR_METADATA_TYPE_HDR10; + s_globalHDRState.Metadata.HDR10 = *pMetadata; + + return S_OK; + } DxgiFactory::DxgiFactory(UINT Flags) @@ -127,7 +156,8 @@ namespace dxvk { return S_OK; } - if (riid == __uuidof(IDXGIVkInteropFactory)) { + if (riid == __uuidof(IDXGIVkInteropFactory) + || riid == __uuidof(IDXGIVkInteropFactory1)) { *ppvObject = ref(&m_interop); return S_OK; } @@ -519,4 +549,9 @@ namespace dxvk { } + DXVK_VK_GLOBAL_HDR_STATE DxgiFactory::GlobalHDRState() { + std::unique_lock lock(s_globalHDRStateMutex); + return s_globalHDRState; + } + } diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h index 81b51143..96a4410c 100644 --- a/src/dxgi/dxgi_factory.h +++ b/src/dxgi/dxgi_factory.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "dxgi_adapter.h" #include "dxgi_monitor.h" @@ -12,7 +13,13 @@ namespace dxvk { class DxgiFactory; - class DxgiVkFactory : public IDXGIVkInteropFactory { + struct DXVK_VK_GLOBAL_HDR_STATE { + uint32_t Serial; + DXGI_COLOR_SPACE_TYPE ColorSpace; + DXGI_VK_HDR_METADATA Metadata; + }; + + class DxgiVkFactory : public IDXGIVkInteropFactory1 { public: @@ -30,6 +37,14 @@ namespace dxvk { VkInstance* pInstance, PFN_vkGetInstanceProcAddr* ppfnVkGetInstanceProcAddr); + HRESULT STDMETHODCALLTYPE GetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + DXGI_HDR_METADATA_HDR10 *pOutMetadata); + + HRESULT STDMETHODCALLTYPE SetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE ColorSpace, + const DXGI_HDR_METADATA_HDR10 *pMetadata); + private: DxgiFactory* m_factory; @@ -173,6 +188,8 @@ namespace dxvk { DxgiMonitorInfo* GetMonitorInfo() { return &m_monitorInfo; } + + DXVK_VK_GLOBAL_HDR_STATE GlobalHDRState(); private: diff --git a/src/dxgi/dxgi_interfaces.h b/src/dxgi/dxgi_interfaces.h index e1fc1250..3735447f 100644 --- a/src/dxgi/dxgi_interfaces.h +++ b/src/dxgi/dxgi_interfaces.h @@ -443,12 +443,27 @@ IDXGIVkInteropFactory : public IUnknown { PFN_vkGetInstanceProcAddr* ppfnVkGetInstanceProcAddr) = 0; }; +/** + * \brief DXGI factory interface for Vulkan interop + */ +MIDL_INTERFACE("2a289dbd-2d0a-4a51-89f7-f2adce465cd6") +IDXGIVkInteropFactory1 : public IDXGIVkInteropFactory { + virtual HRESULT STDMETHODCALLTYPE GetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + DXGI_HDR_METADATA_HDR10 *ppOutMetadata) = 0; + + virtual HRESULT STDMETHODCALLTYPE SetGlobalHDRState( + DXGI_COLOR_SPACE_TYPE ColorSpace, + const DXGI_HDR_METADATA_HDR10 *pMetadata) = 0; +}; + #ifdef _MSC_VER struct __declspec(uuid("907bf281-ea3c-43b4-a8e4-9f231107b4ff")) IDXGIDXVKAdapter; struct __declspec(uuid("92a5d77b-b6e1-420a-b260-fdd701272827")) IDXGIDXVKDevice; struct __declspec(uuid("c06a236f-5be3-448a-8943-89c611c0c2c1")) IDXGIVkMonitorInfo; struct __declspec(uuid("4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408")) IDXGIVkInteropFactory; +struct __declspec(uuid("2a289dbd-2d0a-4a51-89f7-f2adce465cd6")) IDXGIVkInteropFactory1; struct __declspec(uuid("3a6d8f2c-b0e8-4ab4-b4dc-4fd24891bfa5")) IDXGIVkInteropAdapter; struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09323")) IDXGIVkInteropDevice; struct __declspec(uuid("e2ef5fa5-dc21-4af7-90c4-f67ef6a09324")) IDXGIVkInteropDevice1; @@ -462,6 +477,7 @@ __CRT_UUID_DECL(IDXGIDXVKAdapter, 0x907bf281,0xea3c,0x43b4,0xa8,0xe4,0x __CRT_UUID_DECL(IDXGIDXVKDevice, 0x92a5d77b,0xb6e1,0x420a,0xb2,0x60,0xfd,0xf7,0x01,0x27,0x28,0x27); __CRT_UUID_DECL(IDXGIVkMonitorInfo, 0xc06a236f,0x5be3,0x448a,0x89,0x43,0x89,0xc6,0x11,0xc0,0xc2,0xc1); __CRT_UUID_DECL(IDXGIVkInteropFactory, 0x4c5e1b0d,0xb0c8,0x4131,0xbf,0xd8,0x9b,0x24,0x76,0xf7,0xf4,0x08); +__CRT_UUID_DECL(IDXGIVkInteropFactory1, 0x2a289dbd,0x2d0a,0x4a51,0x89,0xf7,0xf2,0xad,0xce,0x46,0x5c,0xd6); __CRT_UUID_DECL(IDXGIVkInteropAdapter, 0x3a6d8f2c,0xb0e8,0x4ab4,0xb4,0xdc,0x4f,0xd2,0x48,0x91,0xbf,0xa5); __CRT_UUID_DECL(IDXGIVkInteropDevice, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x23); __CRT_UUID_DECL(IDXGIVkInteropDevice1, 0xe2ef5fa5,0xdc21,0x4af7,0x90,0xc4,0xf6,0x7e,0xf6,0xa0,0x93,0x24); diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index fee7cf7b..ba65a86a 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -312,6 +312,8 @@ namespace dxvk { if (SyncInterval > 4) return DXGI_ERROR_INVALID_CALL; + UpdateGlobalHDRState(); + std::lock_guard lockWin(m_lockWindow); HRESULT hr = S_OK; @@ -862,4 +864,28 @@ namespace dxvk { m_monitorInfo->ReleaseMonitorData(); } + void DxgiSwapChain::UpdateGlobalHDRState() { + // Update the global HDR state if called from the legacy NVAPI + // interfaces, etc. + + auto state = m_factory->GlobalHDRState(); + if (m_globalHDRStateSerial != state.Serial) { + SetColorSpace1(state.ColorSpace); + + switch (state.Metadata.Type) { + case DXGI_HDR_METADATA_TYPE_NONE: + SetHDRMetaData(DXGI_HDR_METADATA_TYPE_NONE, 0, nullptr); + break; + case DXGI_HDR_METADATA_TYPE_HDR10: + SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10, sizeof(state.Metadata.HDR10), reinterpret_cast(&state.Metadata.HDR10)); + break; + default: + Logger::err(str::format("DXGI: Unsupported HDR metadata type (global): ", state.Metadata.Type)); + break; + } + + m_globalHDRStateSerial = state.Serial; + } + } + } diff --git a/src/dxgi/dxgi_swapchain.h b/src/dxgi/dxgi_swapchain.h index b87b71e4..7702f879 100644 --- a/src/dxgi/dxgi_swapchain.h +++ b/src/dxgi/dxgi_swapchain.h @@ -192,6 +192,8 @@ namespace dxvk { bool m_monitorHasOutput = true; bool m_frameStatisticsDisjoint = true; wsi::DxvkWindowState m_windowState; + + uint32_t m_globalHDRStateSerial = 0; HRESULT EnterFullscreenMode( IDXGIOutput1 *pTarget); @@ -219,6 +221,8 @@ namespace dxvk { void ReleaseMonitorData(); + void UpdateGlobalHDRState(); + }; }