mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-07-20 14:22:00 +00:00
[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
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:
@@ -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;
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user