Eduard Permyakov : winex11.drv: Add 'EDID' registry key to every monitor device.

Alexandre Julliard julliard at winehq.org
Tue Sep 14 16:00:13 CDT 2021


Module: wine
Branch: master
Commit: dedda40e5d7b5a3bcf67eea95145810da283d7d9
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=dedda40e5d7b5a3bcf67eea95145810da283d7d9

Author: Eduard Permyakov <epermyakov at codeweavers.com>
Date:   Tue Sep 14 21:48:25 2021 +0800

winex11.drv: Add 'EDID' registry key to every monitor device.

Extended display identification data (EDID) is a set of data that
is provided by a display to describe its capabilities to a graphics
adapter. EDID data allows a computer to detect the type of monitor
that is connected to it. EDID data includes the manufacturer name,
the product type, the timings that are supported by the display, the
display size, as well as other display characteristics. EDID is
defined by a standard published by the Video Electronics Standards
Association (VESA).

In Windows, every display device has an associated 'EDID' registry
key containing this data. Applications can read and parse it to get
the display capabilities. In Linux, we can get each monitor's EDID
using the RANDR X extension.

This patch fixes, for example, monitor detection in the UE-based game
'Industries of Titan'.

Signed-off-by: Eduard Permyakov <epermyakov at codeweavers.com>
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/winex11.drv/desktop.c     |  4 +++-
 dlls/winex11.drv/display.c     | 15 ++++++++++++---
 dlls/winex11.drv/x11drv.h      |  6 +++++-
 dlls/winex11.drv/x11drv_main.c |  1 +
 dlls/winex11.drv/xinerama.c    |  4 +++-
 dlls/winex11.drv/xrandr.c      | 38 +++++++++++++++++++++++++++++++++++++-
 6 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c
index b517e44e150..71b3a0a5a27 100644
--- a/dlls/winex11.drv/desktop.c
+++ b/dlls/winex11.drv/desktop.c
@@ -265,6 +265,8 @@ static BOOL X11DRV_desktop_get_monitors( ULONG_PTR adapter_id, struct x11drv_mon
     SetRect( &monitor->rc_work, 0, 0, desktop_width, desktop_height );
     query_desktop_work_area( &monitor->rc_work );
     monitor->state_flags = DISPLAY_DEVICE_ATTACHED;
+    monitor->edid_len = 0;
+    monitor->edid = NULL;
     if (desktop_width && desktop_height)
         monitor->state_flags |= DISPLAY_DEVICE_ACTIVE;
 
@@ -273,7 +275,7 @@ static BOOL X11DRV_desktop_get_monitors( ULONG_PTR adapter_id, struct x11drv_mon
     return TRUE;
 }
 
-static void X11DRV_desktop_free_monitors( struct x11drv_monitor *monitors )
+static void X11DRV_desktop_free_monitors( struct x11drv_monitor *monitors, int count )
 {
     heap_free( monitors );
 }
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index b3ff213ae89..ca81f169f9f 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -109,6 +109,8 @@ static const WCHAR monitor_hardware_idW[] = {
     'M','O','N','I','T','O','R','\\',
     'D','e','f','a','u','l','t','_','M','o','n','i','t','o','r',0,0};
 static const WCHAR driver_date_fmtW[] = {'%','u','-','%','u','-','%','u',0};
+static const WCHAR edidW[] = {'E','D','I','D',0};
+static const WCHAR bad_edidW[] = {'B','A','D','_','E','D','I','D',0};
 
 static struct x11drv_display_device_handler host_handler;
 struct x11drv_display_device_handler desktop_handler;
@@ -257,7 +259,7 @@ RECT get_host_primary_monitor_rect(void)
 
     if (gpus) host_handler.free_gpus(gpus);
     if (adapters) host_handler.free_adapters(adapters);
-    if (monitors) host_handler.free_monitors(monitors);
+    if (monitors) host_handler.free_monitors(monitors, monitor_count);
     return rect;
 }
 
@@ -611,6 +613,13 @@ static BOOL X11DRV_InitMonitor(HDEVINFO devinfo, const struct x11drv_monitor *mo
                                    DEVPROP_TYPE_UINT32, (const BYTE *)&output_id, sizeof(output_id), 0))
         goto done;
 
+    hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, NULL, NULL);
+    if (monitor->edid)
+        RegSetValueExW(hkey, edidW, 0, REG_BINARY, monitor->edid, monitor->edid_len);
+    else
+        RegSetValueExW(hkey, bad_edidW, 0, REG_BINARY, NULL, 0);
+    RegCloseKey(hkey);
+
     /* Create driver key */
     hkey = SetupDiCreateDevRegKeyW(devinfo, &device_data, DICS_FLAG_GLOBAL, 0, DIREG_DRV, NULL, NULL);
     RegCloseKey(hkey);
@@ -768,7 +777,7 @@ void X11DRV_DisplayDevices_Init(BOOL force)
                     goto done;
             }
 
-            handler->free_monitors(monitors);
+            handler->free_monitors(monitors, monitor_count);
             monitors = NULL;
             video_index++;
         }
@@ -788,5 +797,5 @@ done:
     if (adapters)
         handler->free_adapters(adapters);
     if (monitors)
-        handler->free_monitors(monitors);
+        handler->free_monitors(monitors, monitor_count);
 }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index afa06561aaa..5ed2fcf73fb 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -413,6 +413,7 @@ enum x11drv_atoms
     FIRST_XATOM = XA_LAST_PREDEFINED + 1,
     XATOM_CLIPBOARD = FIRST_XATOM,
     XATOM_COMPOUND_TEXT,
+    XATOM_EDID,
     XATOM_INCR,
     XATOM_MANAGER,
     XATOM_MULTIPLE,
@@ -751,6 +752,9 @@ struct x11drv_monitor
     RECT rc_work;
     /* StateFlags in DISPLAY_DEVICE struct */
     DWORD state_flags;
+    /* Extended Device Identification Data */
+    unsigned long edid_len;
+    unsigned char *edid;
 };
 
 /* Required functions for display device registry initialization */
@@ -786,7 +790,7 @@ struct x11drv_display_device_handler
     void (*free_adapters)(struct x11drv_adapter *adapters);
 
     /* free_monitors will be called to free a monitor list from get_monitors */
-    void (*free_monitors)(struct x11drv_monitor *monitors);
+    void (*free_monitors)(struct x11drv_monitor *monitors, int count);
 
     /* register_event_handlers will be called to register event handlers.
      * This function pointer is optional and can be NULL when driver doesn't support it */
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 2fac560556b..e8b273d055e 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -138,6 +138,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
 {
     "CLIPBOARD",
     "COMPOUND_TEXT",
+    "EDID",
     "INCR",
     "MANAGER",
     "MULTIPLE",
diff --git a/dlls/winex11.drv/xinerama.c b/dlls/winex11.drv/xinerama.c
index c9863482534..0e1e07669c2 100644
--- a/dlls/winex11.drv/xinerama.c
+++ b/dlls/winex11.drv/xinerama.c
@@ -244,6 +244,8 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor *
             monitor[index].rc_work = monitors[i].rcWork;
             /* Xinerama only reports monitors already attached */
             monitor[index].state_flags = DISPLAY_DEVICE_ATTACHED;
+            monitor[index].edid_len = 0;
+            monitor[index].edid = NULL;
             if (!IsRectEmpty( &monitors[i].rcMonitor ))
                 monitor[index].state_flags |= DISPLAY_DEVICE_ACTIVE;
 
@@ -256,7 +258,7 @@ static BOOL xinerama_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor *
     return TRUE;
 }
 
-static void xinerama_free_monitors( struct x11drv_monitor *monitors )
+static void xinerama_free_monitors( struct x11drv_monitor *monitors, int count )
 {
     heap_free( monitors );
 }
diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c
index e7adcec0f2e..8faece9023a 100644
--- a/dlls/winex11.drv/xrandr.c
+++ b/dlls/winex11.drv/xrandr.c
@@ -68,6 +68,7 @@ MAKE_FUNCPTR(XRRFreeOutputInfo)
 MAKE_FUNCPTR(XRRFreeScreenResources)
 MAKE_FUNCPTR(XRRGetCrtcInfo)
 MAKE_FUNCPTR(XRRGetOutputInfo)
+MAKE_FUNCPTR(XRRGetOutputProperty)
 MAKE_FUNCPTR(XRRGetScreenResources)
 MAKE_FUNCPTR(XRRGetScreenResourcesCurrent)
 MAKE_FUNCPTR(XRRGetScreenSizeRange)
@@ -112,6 +113,7 @@ static int load_xrandr(void)
         LOAD_FUNCPTR(XRRFreeScreenResources);
         LOAD_FUNCPTR(XRRGetCrtcInfo);
         LOAD_FUNCPTR(XRRGetOutputInfo);
+        LOAD_FUNCPTR(XRRGetOutputProperty);
         LOAD_FUNCPTR(XRRGetScreenResources);
         LOAD_FUNCPTR(XRRGetScreenResourcesCurrent);
         LOAD_FUNCPTR(XRRGetScreenSizeRange);
@@ -466,6 +468,24 @@ static void get_screen_size( XRRScreenResources *resources, unsigned int *width,
     }
 }
 
+static void get_edid( RROutput output, unsigned char **prop, unsigned long *len )
+{
+    int result, actual_format;
+    unsigned long bytes_after;
+    Atom actual_type;
+
+    result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
+                                    AnyPropertyType, &actual_type, &actual_format, len,
+                                    &bytes_after, prop );
+
+    if (result != Success)
+    {
+        WARN("Could not retrieve EDID property for output %#lx.\n", output);
+        *prop = NULL;
+        *len = 0;
+    }
+}
+
 static void set_screen_size( int width, int height )
 {
     int screen = default_visual.screen;
@@ -1036,6 +1056,7 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor *
     {
         lstrcpyW( monitors[monitor_count].name, generic_nonpnp_monitorW );
         monitors[monitor_count].state_flags = DISPLAY_DEVICE_ATTACHED;
+        get_edid( adapter_id, &monitors[monitor_count].edid, &monitors[monitor_count].edid_len );
         monitor_count = 1;
     }
     /* Active monitors, need to find other monitors with the same coordinates as mirrored */
@@ -1091,6 +1112,9 @@ static BOOL xrandr14_get_monitors( ULONG_PTR adapter_id, struct x11drv_monitor *
 
                     if (is_crtc_primary( primary_rect, crtc_info ))
                         primary_index = monitor_count;
+
+                    get_edid( screen_resources->outputs[i], &monitors[monitor_count].edid,
+                              &monitors[monitor_count].edid_len );
                     monitor_count++;
                 }
 
@@ -1131,14 +1155,26 @@ done:
         pXRRFreeOutputInfo( enum_output_info );
     if (!ret)
     {
+        for (i = 0; i < monitor_count; i++)
+        {
+            if (monitors[i].edid)
+                XFree( monitors[i].edid );
+        }
         heap_free( monitors );
         ERR("Failed to get monitors\n");
     }
     return ret;
 }
 
-static void xrandr14_free_monitors( struct x11drv_monitor *monitors )
+static void xrandr14_free_monitors( struct x11drv_monitor *monitors, int count )
 {
+    int i;
+
+    for (i = 0; i < count; i++)
+    {
+        if (monitors[i].edid)
+            XFree( monitors[i].edid );
+    }
     heap_free( monitors );
 }
 




More information about the wine-cvs mailing list