[PATCH v2 1/3] winex11.drv: Add 'EDID' registry key to every monitor device.

Zhiyi Zhang zzhang at codeweavers.com
Mon Sep 6 05:20:27 CDT 2021



On 9/3/21 8:30 PM, Eduard Permyakov wrote:
> 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>
> ---
>  dlls/winex11.drv/desktop.c     |  4 +++-
>  dlls/winex11.drv/display.c     | 15 +++++++++---
>  dlls/winex11.drv/x11drv.h      |  6 ++++-
>  dlls/winex11.drv/x11drv_main.c |  3 ++-
>  dlls/winex11.drv/xinerama.c    |  4 +++-
>  dlls/winex11.drv/xrandr.c      | 42 +++++++++++++++++++++++++++++++++-
>  6 files changed, 66 insertions(+), 8 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 e14e131d819..2b0f7be589f 100644
> --- a/dlls/winex11.drv/x11drv.h
> +++ b/dlls/winex11.drv/x11drv.h
> @@ -497,6 +497,7 @@ enum x11drv_atoms
>      XATOM_text_rtf,
>      XATOM_text_richtext,
>      XATOM_text_uri_list,
> +    XATOM_EDID,
>      NB_XATOMS
>  };
>  
> @@ -752,6 +753,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 */
> @@ -787,7 +791,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..6e7cb91c5c7 100644
> --- a/dlls/winex11.drv/x11drv_main.c
> +++ b/dlls/winex11.drv/x11drv_main.c
> @@ -220,7 +220,8 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
>      "text/plain",
>      "text/rtf",
>      "text/richtext",
> -    "text/uri-list"
> +    "text/uri-list",
> +    "EDID"
>  };
>  
>  /***********************************************************************
> 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..eb2f7021ba6 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,37 @@ static void get_screen_size( XRRScreenResources *resources, unsigned int *width,
>      }
>  }
>  
> +static void get_edid(RROutput output, unsigned char **prop, unsigned long *len)
> +{
> +    int result;
> +    Atom actual_type;
> +    int actual_format;
> +    unsigned long bytes_after;
> +
> +    result = pXRRGetOutputProperty(
> +        gdi_display,
> +        output,
> +        x11drv_atom(EDID),
> +        0,
> +        128,
> +        FALSE,
> +        FALSE,
> +        AnyPropertyType,
> +        &actual_type,
> +        &actual_format,
> +        len,
> +        &bytes_after,
> +        prop
> +    );

I know it can be frustrating at first. Usually, when the coding style in the same c file/function is consistent,
you should use the same style when adding new code. In this case, put a space after the function declaration
so it becomes the following

static void get_edid( RROutput output, unsigned char **prop, unsigned long *len )

and the pXRRGetOutputProperty call would be:

result = pXRRGetOutputProperty( gdi_display, output, x11drv_atom(EDID), 0, 128, FALSE, FALSE,
                                AnyPropertyType, &actual_type, &actual_format, len,
                                &bytes_after, prop );
(AnyProperyType and &bytes_after should be aligned vertically with the first parameter gdi_display)

> +
> +    if (result != Success)
> +    {
> +        WARN("Could not retrieve EDID property.\n");
> +        *prop = NULL;
> +        *len = 0;
> +    }
> +}
> +
>  static void set_screen_size( int width, int height )
>  {
>      int screen = default_visual.screen;
> @@ -1036,6 +1069,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 +1125,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++;
>                  }
>  
> @@ -1137,8 +1174,11 @@ done:
>      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++)
> +        XFree( monitors[i].edid );
>      heap_free( monitors );
>  }
>  

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20210906/2e32661a/attachment-0001.htm>


More information about the wine-devel mailing list