[idd] hdr: correct virtual monitor capabilities
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled

This commit is contained in:
Geoffrey McRae
2026-07-19 22:26:44 +10:00
parent 7353e8766f
commit 23e394fd57
5 changed files with 162 additions and 200 deletions

View File

@@ -36,7 +36,7 @@ static const UINT CTA_DATA_BLOCK_MAX_PAYLOAD_SIZE = 31;
static const BYTE EDID_HEADER[8] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 };
static const WORD EDID_MANUFACTURER_ID_LGD = 0xe430;
static const WORD EDID_MANUFACTURER_ID_LGD = 0x30e4;
static const WORD EDID_PRODUCT_CODE = 0x1ddd;
static const BYTE EDID_SERIAL_NUMBER[4] = { 0x01, 0x00, 0x00, 0x00 };
@@ -45,35 +45,29 @@ static const BYTE EDID_MANUFACTURE_YEAR_2026 = 36; // 1990 + 36 = 2026
static const BYTE EDID_VERSION = 1;
static const BYTE EDID_REVISION = 4;
static const BYTE EDID_VIDEO_INPUT_DIGITAL_8BPC_HDMI_A = 0xa2;
static const BYTE EDID_VIDEO_INPUT_DIGITAL_10BPC_HDMI_A = 0xb2;
static const BYTE EDID_HORIZONTAL_SIZE_CM = 52;
static const BYTE EDID_VERTICAL_SIZE_CM = 29;
static const BYTE EDID_DISPLAY_GAMMA_2_2 = 0x78;
static const BYTE EDID_FEATURES_PREFERRED_TIMING_RGB = 0x0a;
static const BYTE EDID_VIDEO_INPUT_DIGITAL_8BPC = 0xa0;
static const BYTE EDID_VIDEO_INPUT_DIGITAL_10BPC = 0xb0;
static const BYTE EDID_DISPLAY_GAMMA_2_2 = 0x78;
static const BYTE EDID_FEATURES_PREFERRED_TIMING_RGB = 0x0a;
static const BYTE EDID_FEATURES_PREFERRED_TIMING_SRGB = 0x0e;
static const BYTE EDID_STANDARD_TIMING_UNUSED_X = 0x01;
static const BYTE EDID_STANDARD_TIMING_UNUSED_AR_REFRESH = 0x01;
static const DWORD EDID_IMAGE_WIDTH_MM = 520;
static const DWORD EDID_IMAGE_HEIGHT_MM = 290;
static const BYTE EDID_DESCRIPTOR_MONITOR_NAME = 0xfc;
static const BYTE EDID_DTD_FLAGS_DIGITAL_SEPARATE_SYNC_POSITIVE = 0x1e;
static const BYTE CTA_EXTENSION_TAG = 0x02;
static const BYTE CTA_REVISION = 0x03;
static const BYTE CTA_DATA_BLOCK_TAG_VENDOR_SPECIFIC = 0x03;
static const BYTE CTA_DATA_BLOCK_TAG_EXTENDED = 0x07;
static const BYTE CTA_DATA_BLOCK_LENGTH_MASK = 0x1f;
static const BYTE CTA_DATA_BLOCK_TAG_EXTENDED = 0x07;
static const BYTE CTA_DATA_BLOCK_LENGTH_MASK = 0x1f;
static const BYTE CTA_EXTENDED_TAG_COLORIMETRY = 0x05;
static const BYTE CTA_EXTENDED_TAG_HDR_STATIC_METADATA = 0x06;
static const BYTE CTA_HDR_EOTF_TRADITIONAL_SDR = (BYTE)(1 << 0);
static const BYTE CTA_HDR_EOTF_SMPTE_ST_2084 = (BYTE)(1 << 2);
static const BYTE CTA_HDR_EOTF_HLG = (BYTE)(1 << 3);
static const BYTE CTA_HDR_STATIC_METADATA_TYPE_1 = (BYTE)(1 << 0);
// The virtual display is a transport rather than a physical light-emitting
// device. Advertise the complete PQ range so Windows preserves HDR content
@@ -85,24 +79,7 @@ static const BYTE CTA_HDR_DESIRED_MAX_LUMINANCE = 245;
static const BYTE CTA_HDR_DESIRED_MAX_FRAME_AVG_LUMINANCE = 245;
static const BYTE CTA_HDR_DESIRED_MIN_LUMINANCE = 0;
static const BYTE CTA_COLORIMETRY_OPYCC_601 = (BYTE)(1 << 3);
static const BYTE CTA_COLORIMETRY_OPRGB = (BYTE)(1 << 4);
static const BYTE CTA_COLORIMETRY_BT2020_YCC = (BYTE)(1 << 6);
static const BYTE CTA_COLORIMETRY_BT2020_RGB = (BYTE)(1 << 7);
static const BYTE CTA_COLORIMETRY_DCI_P3 = (BYTE)(1 << 7);
static const BYTE CTA_HDMI_FORUM_OUI [3] = { 0xd8, 0x5d, 0xc4 };
static const BYTE CTA_HDMI_LICENSING_OUI[3] = { 0x03, 0x0c, 0x00 };
static const BYTE CTA_HDMI_FORUM_VERSION_1 = 0x01;
static const BYTE CTA_HDMI_FORUM_MAX_TMDS_CHARACTER_RATE = 0x6e;
static const BYTE CTA_HDMI_FORUM_SCDC_PRESENT = 0x80;
static const BYTE CTA_HDMI_PHYSICAL_ADDRESS_A_B = 0x00;
static const BYTE CTA_HDMI_PHYSICAL_ADDRESS_C_D = 0x00;
static const BYTE CTA_HDMI_DEEP_COLOR_30_36 = 0x30;
static const BYTE CTA_HDMI_MAX_TMDS_CLOCK_UNSPECIFIED = 0x00;
static const BYTE CTA_HDMI_LATENCY_FIELDS_NONE = 0x0b;
#pragma pack(push, 1)
struct EdidLe16
@@ -111,6 +88,12 @@ struct EdidLe16
BYTE hi;
};
struct EdidBe16
{
BYTE hi;
BYTE lo;
};
struct EdidStandardTiming
{
BYTE horizontalActivePixels;
@@ -163,7 +146,7 @@ struct EdidBaseBlock
{
BYTE header[8];
EdidLe16 manufacturerId;
EdidBe16 manufacturerId;
EdidLe16 productCode;
BYTE serialNumber[4];
@@ -222,29 +205,10 @@ struct CtaColorimetryDataBlock
BYTE metadataAndAdditionalColorimetry;
};
struct CtaHdmiForumVendorSpecificDataBlock
{
CtaDataBlockHeader header;
BYTE ieeeOui[3];
BYTE version;
BYTE maxTmdsCharacterRate;
BYTE flags;
BYTE reserved;
};
struct CtaHdmiVendorSpecificDataBlock
{
CtaDataBlockHeader header;
BYTE ieeeOui[3];
BYTE physicalAddressAB;
BYTE physicalAddressCD;
BYTE flags;
BYTE maxTmdsClock;
BYTE latencyFields;
};
#pragma pack(pop)
static_assert(sizeof(EdidLe16) == 2, "Unexpected EDID little-endian word size");
static_assert(sizeof(EdidBe16) == 2, "Unexpected EDID big-endian word size");
static_assert(sizeof(EdidStandardTiming) == 2, "Unexpected EDID standard timing size");
static_assert(sizeof(EdidDetailedTimingDescriptor) == EDID_DTD_SIZE,
"Unexpected EDID detailed timing descriptor size");
@@ -261,17 +225,17 @@ static_assert(sizeof(CtaHdrStaticMetadataDataBlock) == 7,
"Unexpected HDR static metadata data block size");
static_assert(sizeof(CtaColorimetryDataBlock) == 4,
"Unexpected colorimetry data block size");
static_assert(sizeof(CtaHdmiForumVendorSpecificDataBlock) == 8,
"Unexpected HDMI Forum VSDB size");
static_assert(sizeof(CtaHdmiVendorSpecificDataBlock) == 9,
"Unexpected HDMI VSDB size");
static_assert(CTA_HEADER_SIZE +
sizeof(CtaHdrStaticMetadataDataBlock) +
sizeof(CtaColorimetryDataBlock) +
sizeof(CtaHdmiForumVendorSpecificDataBlock) +
sizeof(CtaHdmiVendorSpecificDataBlock) <= EDID_BLOCK_SIZE - 1,
sizeof(CtaColorimetryDataBlock) <= EDID_BLOCK_SIZE - 1,
"CTA data blocks exceed extension block space");
static void SetBe16(EdidBe16& dst, DWORD value)
{
dst.hi = (BYTE)((value >> 8) & 0xff);
dst.lo = (BYTE)(value & 0xff);
}
static void SetLe16(EdidLe16& dst, DWORD value)
{
dst.lo = (BYTE)(value & 0xff);
@@ -316,11 +280,9 @@ static EdidStandardTiming MakeUnusedStandardTiming()
return timing;
}
#include <algorithm> // Ensure this header is included for std::min and std::max
static WORD EdidChromaticity(double value)
{
return (WORD)min(1023.0, max(0.0, value * 1024.0 + 0.5));
return (WORD)min(1023.0, max(0.0, value * 1024.0 + 0.5));
}
static void SetChromaticityCoordinates(BYTE coordinates[10], bool hdr)
@@ -350,27 +312,36 @@ static void SetChromaticityCoordinates(BYTE coordinates[10], bool hdr)
coordinates[9] = (BYTE)(wy >> 2);
}
static BYTE GetVideoInputDefinition(bool hdr)
{
return hdr ?
EDID_VIDEO_INPUT_DIGITAL_10BPC :
EDID_VIDEO_INPUT_DIGITAL_8BPC;
}
static void InitEdidBaseBlock(EdidBaseBlock& base, bool hdr)
{
memcpy(base.header, EDID_HEADER, sizeof(base.header));
// Manufacturer ID: LGD, product/serial values are arbitrary.
SetLe16(base.manufacturerId, EDID_MANUFACTURER_ID_LGD);
SetLe16(base.productCode, EDID_PRODUCT_CODE);
memcpy(base.serialNumber, EDID_SERIAL_NUMBER, sizeof(base.serialNumber));
// Manufacturer ID: LGD, product/serial values identify the virtual monitor.
SetBe16(base.manufacturerId, EDID_MANUFACTURER_ID_LGD);
SetLe16(base.productCode , EDID_PRODUCT_CODE);
memcpy (base.serialNumber , EDID_SERIAL_NUMBER, sizeof(base.serialNumber));
base.manufactureWeek = EDID_MANUFACTURE_WEEK;
base.manufactureYear = EDID_MANUFACTURE_YEAR_2026;
base.version = EDID_VERSION;
base.revision = EDID_REVISION;
base.videoInputDefinition = hdr ?
EDID_VIDEO_INPUT_DIGITAL_10BPC_HDMI_A :
EDID_VIDEO_INPUT_DIGITAL_8BPC_HDMI_A;
base.horizontalSizeCm = EDID_HORIZONTAL_SIZE_CM;
base.verticalSizeCm = EDID_VERTICAL_SIZE_CM;
base.displayGamma = EDID_DISPLAY_GAMMA_2_2;
base.supportedFeatures = EDID_FEATURES_PREFERRED_TIMING_RGB;
base.videoInputDefinition = GetVideoInputDefinition(hdr);
// This is a transport endpoint rather than a physical panel, so leave its
// physical dimensions unspecified instead of imposing a false DPI/aspect.
base.horizontalSizeCm = 0;
base.verticalSizeCm = 0;
base.displayGamma = EDID_DISPLAY_GAMMA_2_2;
base.supportedFeatures = hdr ?
EDID_FEATURES_PREFERRED_TIMING_RGB :
EDID_FEATURES_PREFERRED_TIMING_SRGB;
SetChromaticityCoordinates(base.chromaticityCoordinates, hdr);
for (UINT i = 0; i < EDID_STANDARD_TIMING_COUNT; ++i)
@@ -379,68 +350,84 @@ static void InitEdidBaseBlock(EdidBaseBlock& base, bool hdr)
base.extensionBlockCount = 1;
}
static bool MakeDetailedTiming(
EdidDetailedTimingDescriptor& timing,
const CSettings::DisplayMode& mode)
bool CEdid::GetTiming(Timing& timing, const CSettings::DisplayMode& mode)
{
memset(&timing, 0, sizeof(timing));
timing = {};
const DWORD hActive = mode.width;
const DWORD vActive = mode.height;
const DWORD refresh = mode.refresh;
timing.hActive = mode.width;
timing.vActive = mode.height;
if (hActive == 0 || vActive == 0 || refresh == 0 ||
hActive > 4095 || vActive > 4095)
if (timing.hActive == 0 || timing.vActive == 0 || mode.refresh == 0)
return false;
DWORD hBlank = std::max<DWORD>(160, ((hActive / 20) + 7) & ~7UL);
DWORD vBlank = std::max<DWORD>(30, vActive / 20);
if (hBlank > 4095 || vBlank > 4095)
return false;
timing.hBlank = std::max<DWORD>(160,
((timing.hActive / 20) + 7) & ~7UL);
timing.vBlank = std::max<DWORD>(30, timing.vActive / 20);
DWORD hSync = std::max<DWORD>(32, hActive / 100);
hSync = (hSync + 7) & ~7UL;
timing.hSync = std::max<DWORD>(32, timing.hActive / 100);
timing.hSync = (timing.hSync + 7) & ~7UL;
DWORD hFront = std::max<DWORD>(48, hBlank / 3);
hFront = (hFront + 7) & ~7UL;
timing.hFront = std::max<DWORD>(48, timing.hBlank / 3);
timing.hFront = (timing.hFront + 7) & ~7UL;
if (hFront + hSync >= hBlank)
if (timing.hFront + timing.hSync >= timing.hBlank)
{
hFront = 48;
hSync = 32;
timing.hFront = 48;
timing.hSync = 32;
}
const DWORD vFront = 3;
const DWORD vSync = 5;
if (vFront + vSync >= vBlank)
timing.vFront = 3;
timing.vSync = 5;
if (timing.vFront + timing.vSync >= timing.vBlank)
return false;
const UINT64 pixelClock = (UINT64)(hActive + hBlank) *
(UINT64)(vActive + vBlank) * (UINT64)refresh;
const UINT64 pixelClock =
(UINT64)(timing.hActive + timing.hBlank) *
(UINT64)(timing.vActive + timing.vBlank) *
(UINT64)mode.refresh;
const UINT64 pixelClock10KHz = (pixelClock + 5000) / 10000;
timing.pixelClock = pixelClock10KHz * 10000;
return timing.pixelClock != 0;
}
static bool MakeDetailedTiming(
EdidDetailedTimingDescriptor& descriptor,
const CSettings::DisplayMode& mode)
{
memset(&descriptor, 0, sizeof(descriptor));
CEdid::Timing timing;
if (!CEdid::GetTiming(timing, mode) ||
timing.hActive > 4095 || timing.vActive > 4095 ||
timing.hBlank > 4095 || timing.vBlank > 4095)
return false;
const UINT64 pixelClock10KHz = timing.pixelClock / 10000;
if (pixelClock10KHz == 0 || pixelClock10KHz > 0xffff)
return false;
SetLe16(timing.pixelClock10KHz, (DWORD)pixelClock10KHz);
SetLe16(descriptor.pixelClock10KHz, (DWORD)pixelClock10KHz);
timing.hActiveLo = Lo8(hActive);
timing.hBlankLo = Lo8(hBlank);
timing.hActiveBlankHi = PackMsbNibbles(hActive, hBlank);
descriptor.hActiveLo = Lo8(timing.hActive);
descriptor.hBlankLo = Lo8(timing.hBlank);
descriptor.hActiveBlankHi = PackMsbNibbles(timing.hActive, timing.hBlank);
timing.vActiveLo = Lo8(vActive);
timing.vBlankLo = Lo8(vBlank);
timing.vActiveBlankHi = PackMsbNibbles(vActive, vBlank);
descriptor.vActiveLo = Lo8(timing.vActive);
descriptor.vBlankLo = Lo8(timing.vBlank);
descriptor.vActiveBlankHi = PackMsbNibbles(timing.vActive, timing.vBlank);
timing.hFrontPorchLo = Lo8(hFront);
timing.hSyncPulseWidthLo = Lo8(hSync);
timing.vFrontPorchSyncPulseWidthLo = PackLowNibbles(vFront, vSync);
timing.syncPorchPulseWidthHi = PackSyncPorchPulseWidthHi(hFront, hSync, vFront, vSync);
descriptor.hFrontPorchLo = Lo8(timing.hFront);
descriptor.hSyncPulseWidthLo = Lo8(timing.hSync);
descriptor.vFrontPorchSyncPulseWidthLo =
PackLowNibbles(timing.vFront, timing.vSync);
descriptor.syncPorchPulseWidthHi = PackSyncPorchPulseWidthHi(
timing.hFront, timing.hSync, timing.vFront, timing.vSync);
timing.imageWidthMmLo = Lo8(EDID_IMAGE_WIDTH_MM);
timing.imageHeightMmLo = Lo8(EDID_IMAGE_HEIGHT_MM);
timing.imageSizeMmHi = PackMsbNibbles(EDID_IMAGE_WIDTH_MM, EDID_IMAGE_HEIGHT_MM);
descriptor.imageWidthMmLo = 0;
descriptor.imageHeightMmLo = 0;
descriptor.imageSizeMmHi = 0;
timing.flags = EDID_DTD_FLAGS_DIGITAL_SEPARATE_SYNC_POSITIVE;
descriptor.flags = EDID_DTD_FLAGS_DIGITAL_SEPARATE_SYNC_POSITIVE;
return true;
}
@@ -499,8 +486,7 @@ static CtaHdrStaticMetadataDataBlock MakeCtaHdrStaticMetadataDataBlock()
block.extendedTag = CTA_EXTENDED_TAG_HDR_STATIC_METADATA;
block.eotf = (BYTE)(
CTA_HDR_EOTF_TRADITIONAL_SDR |
CTA_HDR_EOTF_SMPTE_ST_2084 |
CTA_HDR_EOTF_HLG);
CTA_HDR_EOTF_SMPTE_ST_2084);
block.staticMetadataDescriptor = CTA_HDR_STATIC_METADATA_TYPE_1;
block.desiredContentMaxLuminance = CTA_HDR_DESIRED_MAX_LUMINANCE;
@@ -515,41 +501,9 @@ static CtaColorimetryDataBlock MakeCtaColorimetryDataBlock()
block.header = MakeCtaDataBlockHeader(CTA_DATA_BLOCK_TAG_EXTENDED,
(UINT)(sizeof(block) - sizeof(block.header)));
block.extendedTag = CTA_EXTENDED_TAG_COLORIMETRY;
block.colorimetry = (BYTE)(CTA_COLORIMETRY_OPYCC_601 |
CTA_COLORIMETRY_OPRGB |
CTA_COLORIMETRY_BT2020_YCC |
CTA_COLORIMETRY_BT2020_RGB);
block.metadataAndAdditionalColorimetry = CTA_COLORIMETRY_DCI_P3;
return block;
}
static CtaHdmiForumVendorSpecificDataBlock MakeCtaHdmiForumVendorSpecificDataBlock()
{
CtaHdmiForumVendorSpecificDataBlock block = {};
block.header = MakeCtaDataBlockHeader(CTA_DATA_BLOCK_TAG_VENDOR_SPECIFIC,
(UINT)(sizeof(block) - sizeof(block.header)));
memcpy(block.ieeeOui, CTA_HDMI_FORUM_OUI, sizeof(block.ieeeOui));
block.version = CTA_HDMI_FORUM_VERSION_1;
block.maxTmdsCharacterRate = CTA_HDMI_FORUM_MAX_TMDS_CHARACTER_RATE;
block.flags = CTA_HDMI_FORUM_SCDC_PRESENT;
block.reserved = 0x00;
return block;
}
static CtaHdmiVendorSpecificDataBlock MakeCtaHdmiVendorSpecificDataBlock()
{
CtaHdmiVendorSpecificDataBlock block = {};
block.header = MakeCtaDataBlockHeader(CTA_DATA_BLOCK_TAG_VENDOR_SPECIFIC,
(UINT)(sizeof(block) - sizeof(block.header)));
memcpy(block.ieeeOui, CTA_HDMI_LICENSING_OUI, sizeof(block.ieeeOui));
block.physicalAddressAB = CTA_HDMI_PHYSICAL_ADDRESS_A_B;
block.physicalAddressCD = CTA_HDMI_PHYSICAL_ADDRESS_C_D;
block.flags = CTA_HDMI_DEEP_COLOR_30_36;
block.maxTmdsClock = CTA_HDMI_MAX_TMDS_CLOCK_UNSPECIFIED;
block.latencyFields = CTA_HDMI_LATENCY_FIELDS_NONE;
block.extendedTag = CTA_EXTENDED_TAG_COLORIMETRY;
block.colorimetry = CTA_COLORIMETRY_BT2020_RGB;
block.metadataAndAdditionalColorimetry = 0;
return block;
}
@@ -582,7 +536,10 @@ bool CEdid::WriteDetailedTiming(BYTE* dtd, const CSettings::DisplayMode& mode)
void CEdid::Build(const CSettings::DisplayModes& modes, bool hdr)
{
m_data.assign(static_cast<std::vector<BYTE, std::allocator<BYTE>>::size_type>(EDID_BLOCK_SIZE) * 2, 0);
m_data.assign(
static_cast<std::vector<BYTE, std::allocator<BYTE>>::size_type>(
EDID_BLOCK_SIZE) * 2,
0);
EdidBaseBlock baseBlock = {};
InitEdidBaseBlock(baseBlock, hdr);
@@ -637,8 +594,6 @@ void CEdid::Build(const CSettings::DisplayModes& modes, bool hdr)
{
AppendCtaDataBlock(cta, dataOffset, MakeCtaHdrStaticMetadataDataBlock ());
AppendCtaDataBlock(cta, dataOffset, MakeCtaColorimetryDataBlock ());
AppendCtaDataBlock(cta, dataOffset, MakeCtaHdmiForumVendorSpecificDataBlock());
AppendCtaDataBlock(cta, dataOffset, MakeCtaHdmiVendorSpecificDataBlock ());
}
ctaBlock.dtdOffset = (BYTE)dataOffset;

View File

@@ -29,8 +29,24 @@
class CEdid
{
public:
struct Timing
{
DWORD hActive;
DWORD hBlank;
DWORD hFront;
DWORD hSync;
DWORD vActive;
DWORD vBlank;
DWORD vFront;
DWORD vSync;
UINT64 pixelClock;
};
void Build(const CSettings::DisplayModes& modes, bool hdr);
static bool GetTiming(Timing& timing,
const CSettings::DisplayMode& mode);
const BYTE* Data() const { return m_data.empty() ? nullptr : m_data.data(); }
UINT Size() const { return (UINT)m_data.size(); }

View File

@@ -50,10 +50,13 @@ static const UINT IDDCX_VERSION_1_10 = 0x1A00;
static inline IDDCX_WIRE_BITS_PER_COMPONENT GetWireBitsPerComponent(bool hdr)
{
IDDCX_WIRE_BITS_PER_COMPONENT bits = {};
// This describes the virtual monitor wire, not the swap-chain format.
// HDR uses a 10-bpc PQ wire while CAN_PROCESS_FP16 requests the FP16/scRGB
// source surface that Looking Glass converts for transport.
bits.Rgb = IDDCX_BITS_PER_COMPONENT_8;
if (hdr)
bits.Rgb = (IDDCX_BITS_PER_COMPONENT)(bits.Rgb |
IDDCX_BITS_PER_COMPONENT_10 | IDDCX_BITS_PER_COMPONENT_16);
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;
@@ -586,21 +589,28 @@ void CIndirectDeviceContext::OnSwapChainReady()
g_pipe.SetDisplayMode(mode.width, mode.height, mode.refresh);
}
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD width, DWORD height, DWORD vsync, bool monitorMode)
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO& signal,
const CSettings::DisplayMode& mode, bool monitorMode)
{
mode.totalSize.cx = mode.activeSize.cx = width;
mode.totalSize.cy = mode.activeSize.cy = height;
CEdid::Timing timing;
if (!CEdid::GetTiming(timing, mode))
return;
mode.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
mode.AdditionalSignalInfo.videoStandard = 255;
signal.activeSize.cx = timing.hActive;
signal.activeSize.cy = timing.vActive;
signal.totalSize.cx = timing.hActive + timing.hBlank;
signal.totalSize.cy = timing.vActive + timing.vBlank;
mode.vSyncFreq.Numerator = vsync;
mode.vSyncFreq.Denominator = 1;
mode.hSyncFreq.Numerator = vsync * height;
mode.hSyncFreq.Denominator = 1;
signal.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
signal.AdditionalSignalInfo.videoStandard = 255;
mode.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
mode.pixelRate = ((UINT64)vsync) * ((UINT64)width) * ((UINT64)height);
signal.vSyncFreq.Numerator = mode.refresh;
signal.vSyncFreq.Denominator = 1;
signal.hSyncFreq.Numerator = mode.refresh * signal.totalSize.cy;
signal.hSyncFreq.Denominator = 1;
signal.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
signal.pixelRate = timing.pixelClock;
}
NTSTATUS CIndirectDeviceContext::ParseMonitorDescription(
@@ -620,9 +630,9 @@ NTSTATUS CIndirectDeviceContext::ParseMonitorDescription(
auto * mode = inArgs->pMonitorModes;
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
{
mode->Size = sizeof(IDDCX_MONITOR_MODE);
mode->Size = sizeof(IDDCX_MONITOR_MODE);
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR;
FillSignalInfo(mode->MonitorVideoSignalInfo, it->width, it->height, it->refresh, true);
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
if (it->preferred)
outArgs->PreferredMonitorModeIdx =
@@ -649,9 +659,9 @@ NTSTATUS CIndirectDeviceContext::MonitorGetDefaultModes(
auto* mode = inArgs->pDefaultMonitorModes;
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
{
mode->Size = sizeof(IDDCX_MONITOR_MODE);
mode->Size = sizeof(IDDCX_MONITOR_MODE);
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_DRIVER;
FillSignalInfo(mode->MonitorVideoSignalInfo, it->width, it->height, it->refresh, true);
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
if (it->preferred)
outArgs->PreferredMonitorModeIdx =
@@ -678,7 +688,7 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes(
for (auto it = modes.cbegin(); it != modes.cend(); ++it, ++mode)
{
mode->Size = sizeof(IDDCX_TARGET_MODE);
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, false);
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, *it, false);
}
return STATUS_SUCCESS;
@@ -704,9 +714,9 @@ NTSTATUS CIndirectDeviceContext::ParseMonitorDescription2(
for (auto it = modes.cbegin(); it != modes.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->Size = sizeof(IDDCX_MONITOR_MODE2);
mode->Origin = IDDCX_MONITOR_MODE_ORIGIN_MONITORDESCRIPTOR;
FillSignalInfo(mode->MonitorVideoSignalInfo, *it, true);
mode->BitsPerComponent = GetWireBitsPerComponent(CanProcessFP16());
if (it->preferred)
@@ -738,7 +748,7 @@ NTSTATUS CIndirectDeviceContext::MonitorQueryTargetModes2(
{
ZeroMemory(mode, sizeof(*mode));
mode->Size = sizeof(IDDCX_TARGET_MODE2);
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, it->width, it->height, it->refresh, false);
FillSignalInfo(mode->TargetVideoSignalInfo.targetVideoSignalInfo, *it, false);
mode->BitsPerComponent = GetWireBitsPerComponent(CanProcessFP16());
}

View File

@@ -589,12 +589,12 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
// No per-content metadata is active. Use reasonable internal defaults
// without publishing the virtual monitor metadata downstream.
// BT.709/sRGB primaries (in 0.00002 units):
srcFormat.displayPrimary[0][0] = 13250; // Rx
srcFormat.displayPrimary[0][1] = 34500; // Ry
srcFormat.displayPrimary[1][0] = 7500; // Gx
srcFormat.displayPrimary[0][0] = 32000; // Rx
srcFormat.displayPrimary[0][1] = 16500; // Ry
srcFormat.displayPrimary[1][0] = 15000; // Gx
srcFormat.displayPrimary[1][1] = 30000; // Gy
srcFormat.displayPrimary[2][0] = 34000; // Bx
srcFormat.displayPrimary[2][1] = 16000; // By
srcFormat.displayPrimary[2][0] = 7500; // Bx
srcFormat.displayPrimary[2][1] = 3000; // By
// D65 white point (in 0.00002 units):
srcFormat.whitePoint[0] = 15635;
srcFormat.whitePoint[1] = 16450;

View File

@@ -104,23 +104,6 @@ NTSTATUS LGIddAdapterCommitModes(IDDCX_ADAPTER adapter, const IDARG_IN_COMMITMOD
return STATUS_SUCCESS;
}
static inline void FillSignalInfo(DISPLAYCONFIG_VIDEO_SIGNAL_INFO & mode, DWORD width, DWORD height, DWORD vsync, bool monitorMode)
{
mode.totalSize.cx = mode.activeSize.cx = width;
mode.totalSize.cy = mode.activeSize.cy = height;
mode.AdditionalSignalInfo.vSyncFreqDivider = monitorMode ? 0 : 1;
mode.AdditionalSignalInfo.videoStandard = 255;
mode.vSyncFreq.Numerator = vsync;
mode.vSyncFreq.Denominator = 1;
mode.hSyncFreq.Numerator = vsync * height;
mode.hSyncFreq.Denominator = 1;
mode.scanLineOrdering = DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE;
mode.pixelRate = ((UINT64)vsync) * ((UINT64)width) * ((UINT64)height);
}
NTSTATUS LGIddParseMonitorDescription(const IDARG_IN_PARSEMONITORDESCRIPTION* inArgs,
IDARG_OUT_PARSEMONITORDESCRIPTION* outArgs)
{
@@ -170,10 +153,8 @@ NTSTATUS LGIddAdapterQueryTargetInfo(IDDCX_ADAPTER adapter,
(IDDCX_TARGET_CAPS)(IDDCX_TARGET_CAPS_WIDE_COLOR_SPACE |
IDDCX_TARGET_CAPS_HIGH_COLOR_SPACE) :
(IDDCX_TARGET_CAPS)0;
outArgs->DitheringSupport.Rgb = hdr ?
(IDDCX_BITS_PER_COMPONENT)(IDDCX_BITS_PER_COMPONENT_8 |
IDDCX_BITS_PER_COMPONENT_10) :
IDDCX_BITS_PER_COMPONENT_8;
outArgs->DitheringSupport.Rgb = IDDCX_BITS_PER_COMPONENT_NONE;
outArgs->DitheringSupport.YCbCr444 = IDDCX_BITS_PER_COMPONENT_NONE;
outArgs->DitheringSupport.YCbCr422 = IDDCX_BITS_PER_COMPONENT_NONE;
outArgs->DitheringSupport.YCbCr420 = IDDCX_BITS_PER_COMPONENT_NONE;