diff --git a/idd/LGIdd/CEdid.cpp b/idd/LGIdd/CEdid.cpp index 993353d6..3cdd6a8f 100644 --- a/idd/LGIdd/CEdid.cpp +++ b/idd/LGIdd/CEdid.cpp @@ -123,7 +123,7 @@ void CEdid::Build(const CSettings::DisplayModes& modes) base[17] = 36; // 1990 + 36 = 2026 base[18] = 1; base[19] = 4; - base[20] = 0xa5; // digital input, 10-bit capable + base[20] = 0xb2; // digital input, 10-bit HDMI-A base[21] = 52; base[22] = 29; base[23] = 0x78; // gamma 2.2 @@ -163,19 +163,42 @@ void CEdid::Build(const CSettings::DisplayModes& modes) cta[1] = 0x03; UINT dataOffset = 4; - // CTA extended colorimetry data block: advertise BT.2020 colorimetry. + // CTA HDR Static Metadata data block: HDR, PQ and HLG with type 1 metadata and luminance data. + cta[dataOffset++] = (7 << 5) | 6; + cta[dataOffset++] = 0x06; + cta[dataOffset++] = 0x0d; + cta[dataOffset++] = 0x01; + cta[dataOffset++] = 0xa2; + cta[dataOffset++] = 0xa2; + cta[dataOffset++] = 0x10; + + // CTA extended colorimetry data block: advertise BT.2020 and DCI-P3 colorimetry. cta[dataOffset++] = (7 << 5) | 3; cta[dataOffset++] = 0x05; - cta[dataOffset++] = 0xe0; + cta[dataOffset++] = 0xd8; cta[dataOffset++] = 0x00; - // CTA HDR Static Metadata data block: SDR, traditional HDR, PQ and HLG with type 1 metadata. - cta[dataOffset++] = (7 << 5) | 4; - cta[dataOffset++] = 0x06; - cta[dataOffset++] = 0x0f; + // HDMI Forum vendor-specific data block. + cta[dataOffset++] = (3 << 5) | 7; + cta[dataOffset++] = 0xd8; + cta[dataOffset++] = 0x5d; + cta[dataOffset++] = 0xc4; cta[dataOffset++] = 0x01; + cta[dataOffset++] = 0x6e; + cta[dataOffset++] = 0x80; cta[dataOffset++] = 0x00; + // HDMI vendor-specific data block. + cta[dataOffset++] = (3 << 5) | 8; + cta[dataOffset++] = 0x03; + cta[dataOffset++] = 0x0c; + cta[dataOffset++] = 0x00; + cta[dataOffset++] = 0x00; + cta[dataOffset++] = 0x00; + cta[dataOffset++] = 0x30; + cta[dataOffset++] = 0x00; + cta[dataOffset++] = 0x0b; + UINT ctaDtdOffset = dataOffset; if (ctaDtdOffset < 4) ctaDtdOffset = 4; diff --git a/idd/LGIdd/CIndirectDeviceContext.cpp b/idd/LGIdd/CIndirectDeviceContext.cpp index 9c28a7c5..d940fcdc 100644 --- a/idd/LGIdd/CIndirectDeviceContext.cpp +++ b/idd/LGIdd/CIndirectDeviceContext.cpp @@ -43,6 +43,59 @@ static const struct LGMPQueueConfig POINTER_QUEUE_CONFIG = 1000 //subTimeout }; +static const UINT IDDCX_VERSION_1_10 = 0x1A00; + +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) +static inline IDDCX_WIRE_BITS_PER_COMPONENT GetWireBitsPerComponent(bool hdr) +{ + IDDCX_WIRE_BITS_PER_COMPONENT bits = {}; + bits.Rgb = IDDCX_BITS_PER_COMPONENT_8; + if (hdr) + bits.Rgb = (IDDCX_BITS_PER_COMPONENT)(bits.Rgb | IDDCX_BITS_PER_COMPONENT_10); + bits.YCbCr444 = IDDCX_BITS_PER_COMPONENT_NONE; + bits.YCbCr422 = IDDCX_BITS_PER_COMPONENT_NONE; + bits.YCbCr420 = IDDCX_BITS_PER_COMPONENT_NONE; + return bits; +} +#endif + +void CIndirectDeviceContext::QueryIddCxCapabilities() +{ + IDARG_OUT_GETVERSION ver = {}; + NTSTATUS status = IddCxGetVersion(&ver); + if (!NT_SUCCESS(status)) + { + m_iddCxVersion = 0; + m_canProcessFP16 = false; + DEBUG_ERROR_HR(status, "IddCxGetVersion Failed"); + return; + } + + m_iddCxVersion = ver.IddCxVersion; + +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + const bool hasIddCx110DDIs = + !!IDD_IS_FUNCTION_AVAILABLE(IddCxSwapChainReleaseAndAcquireBuffer2) && + !!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorQueryHardwareCursor3) && + !!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorUpdateModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterQueryTargetInfo) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterCommitModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxParseMonitorDescription2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorQueryTargetModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetDefaultHdrMetaData) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetGammaRamp); +#else + const bool hasIddCx110DDIs = false; +#endif + + m_canProcessFP16 = m_iddCxVersion >= IDDCX_VERSION_1_10 && hasIddCx110DDIs; + + DEBUG_INFO("IddCx version: 0x%04x", m_iddCxVersion); + DEBUG_INFO("IddCx 1.10 HDR/WCG DDIs: %s", m_canProcessFP16 ? "available" : "unavailable"); +} + void CIndirectDeviceContext::PopulateDefaultModes() { g_settings.LoadModes(); @@ -60,6 +113,7 @@ void CIndirectDeviceContext::InitAdapter() if (!m_ivshmem.Init() || !m_ivshmem.Open()) return; + QueryIddCxCapabilities(); PopulateDefaultModes(); IDDCX_ADAPTER_CAPS caps = {}; @@ -72,6 +126,11 @@ void CIndirectDeviceContext::InitAdapter() * driver will not work. This behaviour is not documented by Microsoft. */ caps.Flags = IDDCX_ADAPTER_FLAGS_USE_SMALLEST_MODE; +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + if (CanUseIddCx110DDIs()) + caps.Flags |= IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16; +#endif caps.MaxMonitorsSupported = 1; @@ -99,6 +158,17 @@ void CIndirectDeviceContext::InitAdapter() IDARG_OUT_ADAPTER_INIT initOut; NTSTATUS status = IddCxAdapterInitAsync(&init, &initOut); + if (!NT_SUCCESS(status) && CanUseIddCx110DDIs()) + { + DEBUG_WARN( + "IddCxAdapterInitAsync rejected FP16 adapter capabilities (0x%08x), retrying without HDR/WCG", + status); + m_canProcessFP16 = false; + caps.Flags = (IDDCX_ADAPTER_FLAGS)(caps.Flags & ~IDDCX_ADAPTER_FLAGS_CAN_PROCESS_FP16); + ZeroMemory(&initOut, sizeof(initOut)); + status = IddCxAdapterInitAsync(&init, &initOut); + } + if (!NT_SUCCESS(status)) { DEBUG_ERROR_HR(status, "IddCxAdapterInitAsync Failed"); @@ -237,6 +307,7 @@ NTSTATUS CIndirectDeviceContext::ParseMonitorDescription( IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs) { outArgs->MonitorModeBufferOutputCount = (UINT)m_displayModes.size(); + outArgs->PreferredMonitorModeIdx = 0; if (inArgs->MonitorModeBufferInputCount < (UINT)m_displayModes.size()) return (inArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; @@ -260,6 +331,7 @@ NTSTATUS CIndirectDeviceContext::MonitorGetDefaultModes( IDARG_OUT_GETDEFAULTDESCRIPTIONMODES* outArgs) { outArgs->DefaultMonitorModeBufferOutputCount = (UINT)m_displayModes.size(); + outArgs->PreferredMonitorModeIdx = 0; if (inArgs->DefaultMonitorModeBufferInputCount < (UINT)m_displayModes.size()) return (inArgs->DefaultMonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; @@ -296,6 +368,59 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes( return STATUS_SUCCESS; } + +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) +NTSTATUS CIndirectDeviceContext::ParseMonitorDescription2( + const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs, + IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs) +{ + outArgs->MonitorModeBufferOutputCount = (UINT)m_displayModes.size(); + outArgs->PreferredMonitorModeIdx = 0; + if (inArgs->MonitorModeBufferInputCount < (UINT)m_displayModes.size()) + return (inArgs->MonitorModeBufferInputCount > 0) ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS; + + auto * mode = inArgs->pMonitorModes; + for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode) + { + ZeroMemory(mode, sizeof(*mode)); + mode->Size = sizeof(IDDCX_MONITOR_MODE2); + mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR; + FillSignalInfo(mode->MonitorVideoSignalInfo, it->width, it->height, it->refresh, true); + mode->BitsPerComponent = GetWireBitsPerComponent(CanUseIddCx110DDIs()); + + if (it->preferred) + outArgs->PreferredMonitorModeIdx = + (UINT)std::distance(m_displayModes.cbegin(), it); + } + + return STATUS_SUCCESS; +} + +NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes2( + const IDARG_IN_QUERYTARGETMODES2* inArgs, + IDARG_OUT_QUERYTARGETMODES* outArgs) +{ + outArgs->TargetModeBufferOutputCount = (UINT)m_displayModes.size(); + if (inArgs->TargetModeBufferInputCount < (UINT)m_displayModes.size()) + return STATUS_SUCCESS; + + if (!inArgs->pTargetModes) + return STATUS_INVALID_PARAMETER; + + auto* mode = inArgs->pTargetModes; + for (auto it = m_displayModes.cbegin(); it != m_displayModes.cend(); ++it, ++mode) + { + ZeroMemory(mode, sizeof(*mode)); + mode->Size = sizeof(IDDCX_TARGET_MODE2); + FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, false); + mode->BitsPerComponent = GetWireBitsPerComponent(CanUseIddCx110DDIs()); + } + + return STATUS_SUCCESS; +} +#endif + void CIndirectDeviceContext::SetResolution(int width, int height) { m_setMode.width = width; diff --git a/idd/LGIdd/CIndirectDeviceContext.h b/idd/LGIdd/CIndirectDeviceContext.h index 1dcaf5e6..468ca933 100644 --- a/idd/LGIdd/CIndirectDeviceContext.h +++ b/idd/LGIdd/CIndirectDeviceContext.h @@ -85,6 +85,12 @@ private: DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN; bool m_hasFrame = false; + UINT m_iddCxVersion = 0; + bool m_canProcessFP16 = false; + + void QueryIddCxCapabilities(); + bool CanUseIddCx110DDIs() const { return m_canProcessFP16; } + void DeInitLGMP(); void LGMPTimer(); void ResendCursor(); @@ -118,10 +124,19 @@ public: NTSTATUS MonitorQueryTargetModes( const IDARG_IN_QUERYTARGETMODES* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs); +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + NTSTATUS ParseMonitorDescription2( + const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs, IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs); + NTSTATUS MonitorQueryTargetModes2( + const IDARG_IN_QUERYTARGETMODES2* inArgs, IDARG_OUT_QUERYTARGETMODES* outArgs); +#endif + void SetResolution(int width, int height); - size_t GetAlignSize() { return m_alignSize; } - size_t GetMaxFrameSize() { return m_maxFrameSize; } + size_t GetAlignSize() { return m_alignSize; } + size_t GetMaxFrameSize() { return m_maxFrameSize; } + bool CanProcessFP16() const { return m_canProcessFP16; } struct PreparedFrameBuffer { diff --git a/idd/LGIdd/CSwapChainProcessor.cpp b/idd/LGIdd/CSwapChainProcessor.cpp index 91a7c422..510c0a86 100644 --- a/idd/LGIdd/CSwapChainProcessor.cpp +++ b/idd/LGIdd/CSwapChainProcessor.cpp @@ -130,9 +130,40 @@ void CSwapChainProcessor::SwapChainThreadCore() UINT lastFrameNumber = 0; for (;;) { - IDARG_OUT_RELEASEANDACQUIREBUFFER buffer = {}; + UINT frameNumber = 0; + ComPtr surface; + +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + if (m_devContext->CanProcessFP16()) + { + IDARG_IN_RELEASEANDACQUIREBUFFER2 acquireIn = {}; + acquireIn.Size = sizeof(acquireIn); + acquireIn.AcquireSystemMemoryBuffer = FALSE; + + IDARG_OUT_RELEASEANDACQUIREBUFFER2 buffer = {}; + buffer.MetaData.Size = sizeof(buffer.MetaData); + + hr = IddCxSwapChainReleaseAndAcquireBuffer2(m_hSwapChain, &acquireIn, &buffer); + if (SUCCEEDED(hr)) + { + frameNumber = buffer.MetaData.PresentationFrameNumber; + surface = buffer.MetaData.pSurface; + } + } + else +#endif + { + IDARG_OUT_RELEASEANDACQUIREBUFFER buffer = {}; + + hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer); + if (SUCCEEDED(hr)) + { + frameNumber = buffer.MetaData.PresentationFrameNumber; + surface = buffer.MetaData.pSurface; + } + } - hr = IddCxSwapChainReleaseAndAcquireBuffer(m_hSwapChain, &buffer); if (hr == E_PENDING) { HANDLE waitHandles[] = @@ -153,10 +184,10 @@ void CSwapChainProcessor::SwapChainThreadCore() } else if (SUCCEEDED(hr)) { - if (buffer.MetaData.PresentationFrameNumber != lastFrameNumber) + if (frameNumber != lastFrameNumber) { - lastFrameNumber = buffer.MetaData.PresentationFrameNumber; - SwapChainNewFrame(buffer.MetaData.pSurface); + lastFrameNumber = frameNumber; + SwapChainNewFrame(surface); // report that all GPU processing for this frame has been queued hr = IddCxSwapChainFinishedProcessingFrame(m_hSwapChain); @@ -296,7 +327,25 @@ bool CSwapChainProcessor::QueryHWCursor() in.ShapeBufferSizeInBytes = 512 * 512 * 4; IDARG_OUT_QUERY_HWCURSOR out = {}; - NTSTATUS status = IddCxMonitorQueryHardwareCursor(m_monitor, &in, &out); + NTSTATUS status; +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + if (m_devContext->CanProcessFP16()) + { + IDARG_OUT_QUERY_HWCURSOR3 out3 = {}; + status = IddCxMonitorQueryHardwareCursor3(m_monitor, &in, &out3); + out.IsCursorVisible = out3.IsCursorVisible; + out.X = out3.X; + out.Y = out3.Y; + out.IsCursorShapeUpdated = out3.IsCursorShapeUpdated; + out.CursorShapeInfo = out3.CursorShapeInfo; + } + else +#endif + { + status = IddCxMonitorQueryHardwareCursor(m_monitor, &in, &out); + } + if (FAILED(status)) { // this occurs if the display went away (ie, screen blanking or disabled) diff --git a/idd/LGIdd/Device.cpp b/idd/LGIdd/Device.cpp index b17c580c..f20753de 100644 --- a/idd/LGIdd/Device.cpp +++ b/idd/LGIdd/Device.cpp @@ -36,6 +36,28 @@ WDFDEVICE l_wdfDevice = nullptr; +static const UINT IDDCX_VERSION_1_10 = 0x1A00; + +static bool LGIddCanUseIddCx110DDIs(UINT iddCxVersion) +{ +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + return iddCxVersion >= IDDCX_VERSION_1_10 && + !!IDD_IS_FUNCTION_AVAILABLE(IddCxSwapChainReleaseAndAcquireBuffer2) && + !!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorQueryHardwareCursor3) && + !!IDD_IS_FUNCTION_AVAILABLE(IddCxMonitorUpdateModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterQueryTargetInfo) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxAdapterCommitModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxParseMonitorDescription2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorQueryTargetModes2) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetDefaultHdrMetaData) && + IDD_IS_FIELD_AVAILABLE(IDD_CX_CLIENT_CONFIG, EvtIddCxMonitorSetGammaRamp); +#else + UNREFERENCED_PARAMETER(iddCxVersion); + return false; +#endif +} + NTSTATUS LGIddDeviceD0Entry(WDFDEVICE device, WDF_POWER_DEVICE_STATE previousState) { UNREFERENCED_PARAMETER(previousState); @@ -104,6 +126,65 @@ NTSTATUS LGIddMonitorQueryTargetModes(IDDCX_MONITOR monitor, const IDARG_IN_QUER return wrapper->context->GetDeviceContext()->MonitorQueryTargetModes(inArgs, outArgs); } + +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) +NTSTATUS LGIddParseMonitorDescription2(const IDARG_IN_PARSEMONITORDESCRIPTION2* inArgs, + IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs) +{ + if (!l_wdfDevice) + return STATUS_INVALID_PARAMETER; + + auto* wrapper = WdfObjectGet_CIndirectDeviceContextWrapper(l_wdfDevice); + return wrapper->context->ParseMonitorDescription2(inArgs, outArgs); +} + +NTSTATUS LGIddAdapterQueryTargetInfo(IDDCX_ADAPTER adapter, + IDARG_IN_QUERYTARGET_INFO* inArgs, IDARG_OUT_QUERYTARGET_INFO* outArgs) +{ + UNREFERENCED_PARAMETER(adapter); + UNREFERENCED_PARAMETER(inArgs); + + outArgs->TargetCaps = + (IDDCX_TARGET_CAPS)(IDDCX_TARGET_CAPS_WIDE_COLOR_SPACE | IDDCX_TARGET_CAPS_HIGH_COLOR_SPACE); + outArgs->DitheringSupport.Rgb = + (IDDCX_BITS_PER_COMPONENT)(IDDCX_BITS_PER_COMPONENT_8 | IDDCX_BITS_PER_COMPONENT_10); + outArgs->DitheringSupport.YCbCr444 = IDDCX_BITS_PER_COMPONENT_NONE; + outArgs->DitheringSupport.YCbCr422 = IDDCX_BITS_PER_COMPONENT_NONE; + outArgs->DitheringSupport.YCbCr420 = IDDCX_BITS_PER_COMPONENT_NONE; + return STATUS_SUCCESS; +} + +NTSTATUS LGIddAdapterCommitModes2(IDDCX_ADAPTER adapter, const IDARG_IN_COMMITMODES2* args) +{ + UNREFERENCED_PARAMETER(adapter); + UNREFERENCED_PARAMETER(args); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorSetDefaultHdrMetadata(IDDCX_MONITOR monitor, + const IDARG_IN_MONITOR_SET_DEFAULT_HDR_METADATA* inArgs) +{ + UNREFERENCED_PARAMETER(monitor); + UNREFERENCED_PARAMETER(inArgs); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorSetGammaRamp(IDDCX_MONITOR monitor, const IDARG_IN_SET_GAMMARAMP* inArgs) +{ + UNREFERENCED_PARAMETER(monitor); + UNREFERENCED_PARAMETER(inArgs); + return STATUS_SUCCESS; +} + +NTSTATUS LGIddMonitorQueryTargetModes2(IDDCX_MONITOR monitor, const IDARG_IN_QUERYTARGETMODES2* inArgs, + IDARG_OUT_QUERYTARGETMODES* outArgs) +{ + auto* wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor); + return wrapper->context->GetDeviceContext()->MonitorQueryTargetModes2(inArgs, outArgs); +} +#endif + NTSTATUS LGIddMonitorAssignSwapChain(IDDCX_MONITOR monitor, const IDARG_IN_SETSWAPCHAIN* inArgs) { auto * wrapper = WdfObjectGet_CIndirectMonitorContextWrapper(monitor); @@ -131,7 +212,9 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit) DEBUG_ERROR("IddCxGetVersion Failed"); return status; } + const bool hasIddCx110DDIs = LGIddCanUseIddCx110DDIs(ver.IddCxVersion); DEBUG_INFO("Version: 0x%04x", ver.IddCxVersion); + DEBUG_INFO("IddCx 1.10 HDR/WCG DDIs: %s", hasIddCx110DDIs ? "available" : "unavailable"); WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); @@ -141,13 +224,29 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit) IDD_CX_CLIENT_CONFIG config; IDD_CX_CLIENT_CONFIG_INIT(&config); config.EvtIddCxAdapterInitFinished = LGIddAdapterInitFinished; - config.EvtIddCxAdapterCommitModes = LGIddAdapterCommitModes; - config.EvtIddCxParseMonitorDescription = LGIddParseMonitorDescription; config.EvtIddCxMonitorGetDefaultDescriptionModes = LGIddMonitorGetDefaultModes; - config.EvtIddCxMonitorQueryTargetModes = LGIddMonitorQueryTargetModes; config.EvtIddCxMonitorAssignSwapChain = LGIddMonitorAssignSwapChain; config.EvtIddCxMonitorUnassignSwapChain = LGIddMonitorUnassignSwapChain; +#if defined(IDDCX_VERSION_MAJOR) && defined(IDDCX_VERSION_MINOR) && \ + (IDDCX_VERSION_MAJOR > 1 || (IDDCX_VERSION_MAJOR == 1 && IDDCX_VERSION_MINOR >= 10)) + if (hasIddCx110DDIs) + { + config.EvtIddCxParseMonitorDescription2 = LGIddParseMonitorDescription2; + config.EvtIddCxMonitorQueryTargetModes2 = LGIddMonitorQueryTargetModes2; + config.EvtIddCxAdapterCommitModes2 = LGIddAdapterCommitModes2; + config.EvtIddCxAdapterQueryTargetInfo = LGIddAdapterQueryTargetInfo; + config.EvtIddCxMonitorSetDefaultHdrMetaData = LGIddMonitorSetDefaultHdrMetadata; + config.EvtIddCxMonitorSetGammaRamp = LGIddMonitorSetGammaRamp; + } + else +#endif + { + config.EvtIddCxAdapterCommitModes = LGIddAdapterCommitModes; + config.EvtIddCxParseMonitorDescription = LGIddParseMonitorDescription; + config.EvtIddCxMonitorQueryTargetModes = LGIddMonitorQueryTargetModes; + } + status = IddCxDeviceInitConfig(deviceInit, &config); if (!NT_SUCCESS(status)) return status; @@ -168,9 +267,8 @@ NTSTATUS LGIddCreateDevice(_Inout_ PWDFDEVICE_INIT deviceInit) return status; /* - * Because we are limited to IddCx 1.5 to retain Windows 10 support we have - * no way of getting the device context in `LGIdddapterCommitModes`, as such - * we need to store this for later. + * Keep the WDF device cached so callbacks that do not provide an adapter or + * monitor context can still reach the device context on down-level IddCx. */ l_wdfDevice = device; diff --git a/idd/LGIdd/LGIdd.vcxproj b/idd/LGIdd/LGIdd.vcxproj index 71451aaa..abc81a08 100644 --- a/idd/LGIdd/LGIdd.vcxproj +++ b/idd/LGIdd/LGIdd.vcxproj @@ -104,7 +104,7 @@ Spectre true 1 - 9 + 10 25 25 <_NT_TARGET_VERSION>0xA000005 @@ -116,7 +116,7 @@ Spectre true 1 - 9 + 10 25 25 <_NT_TARGET_VERSION>0xA000005 @@ -175,7 +175,7 @@ true true trace.h - /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=9 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) $(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories) @@ -190,7 +190,7 @@ true true trace.h - /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=9 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) $(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories) @@ -205,7 +205,7 @@ true true trace.h - /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=9 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) $(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories) @@ -220,7 +220,7 @@ true true trace.h - /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=9 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) + /EHsc /D_ATL_NO_WIN_SUPPORT /DIDDCX_VERSION_MAJOR=1 /DIDDCX_VERSION_MINOR=10 /DIDDCX_MINIMUM_VERSION_REQUIRED=4 %(AdditionalOptions) $(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories)