Skip to content

Commit

Permalink
Custom Edid Support
Browse files Browse the repository at this point in the history
- Added custom edid support
- Toggle edid in xml or master in registry
- Live edid modification to easily identify emulated displays
- Checksum checks to make sure data isn't corrupt
- Converted edid to static vector instead to allow custom edid
  • Loading branch information
bud3699 committed Oct 15, 2024
1 parent 2bfbb0e commit 2d37496
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 6 deletions.
210 changes: 205 additions & 5 deletions Virtual Display Driver (HDR)/MttVDD/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ wstring confpath = L"C:\\VirtualDisplayDriver";
bool logsEnabled = false;
bool debugLogs;
bool HDRPlus = false;
bool customEdid = false;


vector<unsigned char> Microsoft::IndirectDisp::IndirectDeviceContext::s_KnownMonitorEdid; //Changed to support static vector

struct IndirectDeviceContextWrapper
{
Expand Down Expand Up @@ -454,6 +455,108 @@ bool HDRPLUSEnabledQuery() {
return xmlHDRvalue;
}


bool CustomEdidEnabledQuery() {
wstring settingsname = confpath + L"\\vdd_settings.xml";
HKEY hKey;
DWORD dwValue;
DWORD dwBufferSize = sizeof(dwValue);
LONG lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\MikeTheTech\\VirtualDisplayDriver", 0, KEY_READ, &hKey);

if (lResult == ERROR_SUCCESS) {
vddlog("d", "Get CustomEdid - Successfully opened registry key.");

lResult = RegQueryValueExW(hKey, L"CUSTOMEDID", NULL, NULL, (LPBYTE)&dwValue, &dwBufferSize);
if (lResult == ERROR_SUCCESS) {
RegCloseKey(hKey);
vddlog("d", "Get CustomEdid - CustomEdid value retrieved from registry.");

if (dwValue == 1) {
vddlog("d", "Get CustomEdid - CustomEdid is enabled (value = 1).");
return true;
}
else if (dwValue == 0) {
vddlog("d", "Get CustomEdid - CustomEdid is disabled (value = 0). Checking XML settings.");
goto check_xml;
}
}
else {
vddlog("e", "Get CustomEdid - Failed to retrieve CustomEdid value from registry. Attempting to read as string.");
wchar_t path[MAX_PATH];
dwBufferSize = sizeof(path);
lResult = RegQueryValueExW(hKey, L"CUSTOMEDID", NULL, NULL, (LPBYTE)path, &dwBufferSize);

if (lResult == ERROR_SUCCESS) {
wstring CustomEdidValue(path);
RegCloseKey(hKey);
vddlog("d", "Get CustomEdid - CustomEdid string value retrieved from registry. ");

if (CustomEdidValue == L"true" || CustomEdidValue == L"1") {
vddlog("d", "Get CustomEdid - CustomEdid is enabled (string value).");
return true;
}
else if (CustomEdidValue == L"false" || CustomEdidValue == L"0") {
vddlog("d", " Get CustomEdid - CustomEdid is disabled (string value). Checking XML settings.");
goto check_xml;
}
}
RegCloseKey(hKey);
vddlog("e", " Get CustomEdid - Failed to retrieve CustomEdid string value from registry.");
}
}
else {
vddlog("e", "Get CustomEdid - Failed to open registry key for CustomEdid.");
}

check_xml:
CComPtr<IStream> pFileStream;
HRESULT hr = SHCreateStreamOnFileEx(settingsname.c_str(), STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &pFileStream);

if (FAILED(hr)) {
vddlog("e", "Get CustomEdid - Failed to create file stream for XML settings.");
return false;
}
vddlog("d", "Get CustomEdid - File stream created for XML settings.");

CComPtr<IXmlReader> pReader;
hr = CreateXmlReader(__uuidof(IXmlReader), (void**)&pReader, nullptr);

if (FAILED(hr)) {
vddlog("e", "Get CustomEdid - Failed to create XML reader.");
return false;
}
vddlog("d", "Get CustomEdid - XML reader created.");

hr = pReader->SetInput(pFileStream);
if (FAILED(hr)) {
vddlog("e", "Get CustomEdid - Failed to set input for XML reader.");
return false;
}
vddlog("d", "Get CustomEdid - Input set for XML reader.");

XmlNodeType nodeType;
const wchar_t* pwszLocalName;
bool xmlCustomEdidvalue = false;

while (S_OK == pReader->Read(&nodeType)) {
if (nodeType == XmlNodeType_Element) {
pReader->GetLocalName(&pwszLocalName, nullptr);
if (wcscmp(pwszLocalName, L"CustomEdid") == 0) {
pReader->Read(&nodeType);
if (nodeType == XmlNodeType_Text) {
const wchar_t* pwszValue;
pReader->GetValue(&pwszValue, nullptr);
xmlCustomEdidvalue = (wcscmp(pwszValue, L"true") == 0);
vddlog("i", xmlCustomEdidvalue ? "CustomEdid is enabled." : "CustomEdid is disabled.");
break;
}
}
}
}

return xmlCustomEdidvalue;
}

void LogIddCxVersion() {
IDARG_OUT_GETVERSION outArgs;
NTSTATUS status = IddCxGetVersion(&outArgs);
Expand Down Expand Up @@ -911,6 +1014,7 @@ extern "C" NTSTATUS DriverEntry(
initpath();
logsEnabled = LogEnabledQuery();
HDRPlus = HDRPLUSEnabledQuery();
customEdid = CustomEdidEnabledQuery();
vddlog("i", "Driver Starting");
string utf8_confpath = WStringToString(confpath);
string logtext = "VDD Path: " + utf8_confpath;
Expand Down Expand Up @@ -1702,8 +1806,7 @@ constexpr DISPLAYCONFIG_VIDEO_SIGNAL_INFO dispinfo(UINT32 h, UINT32 v, UINT32 r)
};
}

// This is a sample monitor EDID - FOR SAMPLE PURPOSES ONLY
const BYTE IndirectDeviceContext::s_KnownMonitorEdid[] =
vector<BYTE> hardcodedEdid =
{
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x36, 0x94, 0x37, 0x13, 0xe7, 0x1e, 0xe7, 0x1e,
0x1c, 0x22, 0x01, 0x03, 0x80, 0x32, 0x1f, 0x78, 0x07, 0xee, 0x95, 0xa3, 0x54, 0x4c, 0x99, 0x26,
Expand All @@ -1723,6 +1826,85 @@ const BYTE IndirectDeviceContext::s_KnownMonitorEdid[] =
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c
};


void modifyEdid(vector<BYTE>& edid) {
if (edid.size() < 12) {
return;
}

edid[8] = 0x36;
edid[9] = 0x94;
edid[10] = 0x37;
edid[11] = 0x13;
}



BYTE calculateChecksum(const std::vector<BYTE>& edid) {
int sum = 0;
for (int i = 0; i < 127; ++i) {
sum += edid[i];
}
sum %= 256;
if (sum != 0) {
sum = 256 - sum;
}
return static_cast<BYTE>(sum);
// check sum calculations. We dont need to include old checksum in calculation, so we only read up to the byte before.
// Anything after the checksum bytes arent part of the checksum - a flaw with edid managment, not with us
}

vector<BYTE> loadEdid(const string& filePath) {
if (customEdid) {
vddlog("i", "Attempting to use user Edid");
}
else {
vddlog("i", "Using hardcoded edid");
return hardcodedEdid;
}


ifstream file(filePath, ios::binary | ios::ate);
if (!file) {
vddlog("i", "No custom edid found");
vddlog("i", "Using hardcoded edid");
return hardcodedEdid;
}

streamsize size = file.tellg();
file.seekg(0, ios::beg);

vector<BYTE> buffer(size);
if (file.read((char*)buffer.data(), size)) {
//calculate checksum and compare it to 127 byte, if false then return hardcoded if true then return buffer to prevent loading borked edid.
BYTE calculatedChecksum = calculateChecksum(buffer);
if (calculatedChecksum != buffer[127]) {
vddlog("e", "Custom edid failed due to invalid checksum");
vddlog("i", "Using hardcoded edid");
return hardcodedEdid;
}
vddlog("i", "Using custom edid");
return buffer;
}
else {
vddlog("i", "Using hardcoded edid");
return hardcodedEdid;
}
}

int maincalc() {
vector<BYTE> edid = loadEdid(WStringToString(confpath) + "\\user_edid.bin");

modifyEdid(edid);
BYTE checksum = calculateChecksum(edid);
edid[127] = checksum;
// Setting this variable is depricated, hardcoded edid is either returned or custom in loading edid function
IndirectDeviceContext::s_KnownMonitorEdid = edid;
return 0;
}



IndirectDeviceContext::IndirectDeviceContext(_In_ WDFDEVICE WdfDevice) :
m_WdfDevice(WdfDevice)
{
Expand All @@ -1747,6 +1929,7 @@ IndirectDeviceContext::~IndirectDeviceContext()

void IndirectDeviceContext::InitAdapter()
{
maincalc();
stringstream logStream;

// ==============================
Expand Down Expand Up @@ -1864,8 +2047,25 @@ void IndirectDeviceContext::CreateMonitor(unsigned int index) {
MonitorInfo.ConnectorIndex = index;
MonitorInfo.MonitorDescription.Size = sizeof(MonitorInfo.MonitorDescription);
MonitorInfo.MonitorDescription.Type = IDDCX_MONITOR_DESCRIPTION_TYPE_EDID;
MonitorInfo.MonitorDescription.DataSize = sizeof(s_KnownMonitorEdid);
MonitorInfo.MonitorDescription.pData = const_cast<BYTE*>(s_KnownMonitorEdid);
//MonitorInfo.MonitorDescription.DataSize = sizeof(s_KnownMonitorEdid); can no longer use size of as converted to vector
if (s_KnownMonitorEdid.size() > UINT_MAX)
{
vddlog("e", "Edid size passes UINT_Max, escape to prevent loading borked display");
}
else
{
MonitorInfo.MonitorDescription.DataSize = static_cast<UINT>(s_KnownMonitorEdid.size());
}
//MonitorInfo.MonitorDescription.pData = const_cast<BYTE*>(s_KnownMonitorEdid);
// Changed from using const_cast to data() to safely access the EDID data.
// This improves type safety and code readability, as it eliminates the need for casting
// and ensures we are directly working with the underlying container of known monitor EDID data.
MonitorInfo.MonitorDescription.pData = IndirectDeviceContext::s_KnownMonitorEdid.data();






// ==============================
// TODO: The monitor's container ID should be distinct from "this" device's container ID if the monitor is not
Expand Down
2 changes: 1 addition & 1 deletion Virtual Display Driver (HDR)/MttVDD/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ namespace Microsoft

public:
static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[];
static const BYTE s_KnownMonitorEdid[];
static std::vector<BYTE> s_KnownMonitorEdid;
};
}
}
1 change: 1 addition & 0 deletions Virtual Display Driver (HDR)/vdd_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@

</resolutions>
<options>
<CustomEdid>false</CustomEdid> <!-- Custom Edid should be named "user_edid.bin"! This does not support emulating resolutions!-->
<HDRPlus>false</HDRPlus>
<logging>false</logging>
<!-- DEBUG LOGGING FOR EXPERTS ONLY!-->
Expand Down

0 comments on commit 2d37496

Please sign in to comment.