From 0377e571e1fb2d0374e4ce43ee3ef4840f3c4501 Mon Sep 17 00:00:00 2001 From: Joshua Ashton Date: Sat, 26 Aug 2023 15:02:15 +0100 Subject: [PATCH] amd_ags_x64: Implement agsSetDisplayMode Gets HDR working with Elden Ring. Signed-off-by: Joshua Ashton --- dlls/amd_ags_x64/amd_ags_x64_main.c | 85 +++++++++++++++++++++++++++- dlls/amd_ags_x64/dxvk_interfaces.idl | 36 ++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/dlls/amd_ags_x64/amd_ags_x64_main.c b/dlls/amd_ags_x64/amd_ags_x64_main.c index 4ea7fa88a439..d12fd2417d25 100644 --- a/dlls/amd_ags_x64/amd_ags_x64_main.c +++ b/dlls/amd_ags_x64/amd_ags_x64_main.c @@ -136,6 +136,7 @@ struct AGSContext VkPhysicalDeviceProperties *properties; VkPhysicalDeviceMemoryProperties *memory_properties; IDXGIFactory1 *dxgi_factory; + IDXGIVkInteropFactory1 *dxgi_interop; ID3D11DeviceContext *d3d11_context; AGSDX11ExtensionsSupported_600 extensions; }; @@ -538,6 +539,12 @@ static AGSReturnCode init_ags_context(AGSContext *context) return AGS_DX_FAILURE; } + if (FAILED(IDXGIFactory1_QueryInterface(context->dxgi_factory, &IID_IDXGIVkInteropFactory1, (void**)&context->dxgi_interop))) + { + ERR("Failed to get IDXGIVkInteropFactory1.\n"); + return AGS_DX_FAILURE; + } + context->version = determine_ags_version(); ret = vk_get_physical_device_properties(&context->device_count, &context->properties, &context->memory_properties); @@ -711,6 +718,11 @@ AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) if (!context) return AGS_SUCCESS; + if (context->dxgi_interop) + { + IDXGIVkInteropFactory1_Release(context->dxgi_interop); + context->dxgi_interop = NULL; + } if (context->dxgi_factory) { IDXGIFactory1_Release(context->dxgi_factory); @@ -735,14 +747,85 @@ AGSReturnCode WINAPI agsDeInitialize(AGSContext *context) return AGS_SUCCESS; } +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_506(AGSDisplaySettings_Mode_506 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d\n", mode); + /* fallthrough */ + case Mode_506_SDR: + TRACE("Setting Mode_506_SDR!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_506_PQ: + TRACE("Setting Mode_506_PQ!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_506_scRGB: + TRACE("Setting Mode_506_scRGB!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_COLOR_SPACE_TYPE convert_ags_colorspace_600(AGSDisplaySettings_Mode_600 mode) +{ + switch (mode) + { + default: + ERR("Unknown color space in AGS: %d\n", mode); + /* fallthrough */ + case Mode_600_SDR: + TRACE("Setting Mode_600_SDR!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; + case Mode_600_HDR10_PQ: + TRACE("Setting Mode_600_HDR10_PQ!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020; + case Mode_600_HDR10_scRGB: + TRACE("Setting Mode_600_HDR10_scRGB!\n"); + return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; + } +} + +static DXGI_HDR_METADATA_HDR10 convert_ags_metadata(const AGSDisplaySettings_600 *settings) +{ + DXGI_HDR_METADATA_HDR10 metadata; + metadata.RedPrimary[0] = settings->chromaticityRedX * 50000; + metadata.RedPrimary[1] = settings->chromaticityRedY * 50000; + metadata.GreenPrimary[0] = settings->chromaticityGreenX * 50000; + metadata.GreenPrimary[1] = settings->chromaticityGreenY * 50000; + metadata.BluePrimary[0] = settings->chromaticityBlueX * 50000; + metadata.BluePrimary[1] = settings->chromaticityBlueY * 50000; + metadata.WhitePoint[0] = settings->chromaticityWhitePointX * 50000; + metadata.WhitePoint[1] = settings->chromaticityWhitePointY * 50000; + metadata.MaxMasteringLuminance = settings->maxLuminance; + metadata.MinMasteringLuminance = settings->minLuminance / 0.0001f; + metadata.MaxContentLightLevel = settings->maxContentLightLevel; + metadata.MaxFrameAverageLightLevel = settings->maxFrameAverageLightLevel; + return metadata; +} + AGSReturnCode WINAPI agsSetDisplayMode(AGSContext *context, int device_index, int display_index, const AGSDisplaySettings *settings) { - FIXME("context %p device_index %d display_index %d settings %p stub!\n", context, device_index, + const AGSDisplaySettings_506 *settings506 = &settings->agsDisplaySettings506; + const AGSDisplaySettings_600 *settings600 = &settings->agsDisplaySettings600; + DXGI_COLOR_SPACE_TYPE colorspace; + DXGI_HDR_METADATA_HDR10 metadata; + + TRACE("context %p device_index %d display_index %d settings %p\n", context, device_index, display_index, settings); if (!context) return AGS_INVALID_ARGS; + colorspace = context->version < AMD_AGS_VERSION_5_1_1 + ? convert_ags_colorspace_506(settings506->mode) + : convert_ags_colorspace_600(settings600->mode); + /* Settings 506, 511 and 600 are identical aside from enum order + use + * of bitfield flags we do not use. */ + metadata = convert_ags_metadata(settings600); + + if (FAILED(IDXGIVkInteropFactory1_SetGlobalHDRState(context->dxgi_interop, colorspace, &metadata))) + return AGS_DX_FAILURE; + return AGS_SUCCESS; } diff --git a/dlls/amd_ags_x64/dxvk_interfaces.idl b/dlls/amd_ags_x64/dxvk_interfaces.idl index c632d926fb2d..208dd3e66d12 100644 --- a/dlls/amd_ags_x64/dxvk_interfaces.idl +++ b/dlls/amd_ags_x64/dxvk_interfaces.idl @@ -17,6 +17,11 @@ */ import "d3d11.idl"; +import "dxgi1_6.idl"; + +typedef struct VkInstance_T *VkInstance; +typedef void (__stdcall *PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction (__stdcall *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); typedef enum D3D11_VK_EXTENSION { @@ -114,3 +119,34 @@ interface ID3D11VkExtContext1 : ID3D11VkExtContext [in] const void *params, [in] UINT32 param_size, [in] void * const *read_resources, [in] UINT32 read_resource_count, [in] void* const *write_resources, [in] UINT32 write_resources_count); } + +[ + object, + uuid(4c5e1b0d-b0c8-4131-bfd8-9b2476f7f408), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory : IUnknown +{ + void GetVulkanInstance( + [out] VkInstance *pInstance, + [out] PFN_vkGetInstanceProcAddr *ppfnVkGetInstanceProcAddr); +} + +[ + object, + uuid(2a289dbd-2d0a-4a51-89f7-f2adce465cd6), + local, + pointer_default(unique) +] +interface IDXGIVkInteropFactory1 : IDXGIVkInteropFactory +{ + HRESULT GetGlobalHDRState( + [out] DXGI_COLOR_SPACE_TYPE *pOutColorSpace, + [out] DXGI_HDR_METADATA_HDR10 *ppOutMetadata) = 0; + + HRESULT SetGlobalHDRState( + [in] DXGI_COLOR_SPACE_TYPE ColorSpace, + [in] const DXGI_HDR_METADATA_HDR10 *pMetadata) = 0; +} +