[PATCH 4/6] winex11.drv: Migrate XVidMode display settings handler to a new interface.

Zhiyi Zhang zzhang at codeweavers.com
Mon Jul 27 03:01:38 CDT 2020


Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
 dlls/winex11.drv/xvidmode.c | 267 +++++++++++++++++++++++-------------
 1 file changed, 173 insertions(+), 94 deletions(-)

diff --git a/dlls/winex11.drv/xvidmode.c b/dlls/winex11.drv/xvidmode.c
index a5884543163..c449157f6b3 100644
--- a/dlls/winex11.drv/xvidmode.c
+++ b/dlls/winex11.drv/xvidmode.c
@@ -2,6 +2,7 @@
  * DirectDraw XVidMode interface
  *
  * Copyright 2001 TransGaming Technologies, Inc.
+ * Copyright 2020 Zhiyi Zhang for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,10 +22,14 @@
 #include "config.h"
 #include "wine/port.h"
 
+#include <assert.h>
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
 
+#define NONAMELESSSTRUCT
+#define NONAMELESSUNION
+
 #include "x11drv.h"
 
 #ifdef HAVE_X11_EXTENSIONS_XF86VMODE_H
@@ -38,6 +43,7 @@
 #include "wingdi.h"
 #include "wine/debug.h"
 #include "wine/heap.h"
+#include "wine/unicode.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(xvidmode);
 
@@ -52,11 +58,6 @@ static int xf86vm_gammaramp_size;
 static BOOL xf86vm_use_gammaramp;
 #endif /* X_XF86VidModeSetGammaRamp */
 
-static struct x11drv_mode_info *dd_modes;
-static unsigned int dd_mode_count;
-static XF86VidModeModeInfo** real_xf86vm_modes;
-static unsigned int real_xf86vm_mode_count;
-
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f;
 MAKE_FUNCPTR(XF86VidModeGetAllModeLines)
 MAKE_FUNCPTR(XF86VidModeGetModeLine)
@@ -76,86 +77,182 @@ MAKE_FUNCPTR(XF86VidModeSetGammaRamp)
 #endif
 #undef MAKE_FUNCPTR
 
-
-static void convert_modeinfo( const XF86VidModeModeInfo *mode)
-{
-  int rate;
-  if (mode->htotal!=0 && mode->vtotal!=0)
-      rate = mode->dotclock * 1000 / (mode->htotal * mode->vtotal);
-  else
-      rate = 0;
-  X11DRV_Settings_AddOneMode(mode->hdisplay, mode->vdisplay, 0, rate);
-}
-
-static void convert_modeline(int dotclock, const XF86VidModeModeLine *mode,
-                             struct x11drv_mode_info *info, unsigned int bpp)
-{
-  info->width   = mode->hdisplay;
-  info->height  = mode->vdisplay;
-  if (mode->htotal!=0 && mode->vtotal!=0)
-      info->refresh_rate = dotclock * 1000 / (mode->htotal * mode->vtotal);
-  else
-      info->refresh_rate = 0;
-  TRACE(" width=%d, height=%d, refresh=%d\n",
-        info->width, info->height, info->refresh_rate);
-  info->bpp     = bpp;
-}
-
 static int XVidModeErrorHandler(Display *dpy, XErrorEvent *event, void *arg)
 {
     return 1;
 }
 
-static int X11DRV_XF86VM_GetCurrentMode(void)
+/* XF86VidMode display settings handler */
+static BOOL xf86vm_get_id(const WCHAR *device_name, ULONG_PTR *id)
 {
-  XF86VidModeModeLine line;
-  int dotclock;
-  unsigned int i;
-  struct x11drv_mode_info cmode;
-  DWORD dwBpp = screen_bpp;
+    WCHAR primary_adapter[CCHDEVICENAME];
 
-  TRACE("Querying XVidMode current mode\n");
-  pXF86VidModeGetModeLine(gdi_display, DefaultScreen(gdi_display), &dotclock, &line);
-  convert_modeline(dotclock, &line, &cmode, dwBpp);
-  for (i=0; i<dd_mode_count; i++)
-    if (memcmp(&dd_modes[i], &cmode, sizeof(cmode)) == 0) {
-      TRACE("mode=%d\n", i);
-      return i;
+    if (!get_primary_adapter( primary_adapter ))
+        return FALSE;
+
+    /* XVidMode only supports changing the primary adapter settings.
+     * For non-primary adapters, an id is still provided but getting
+     * and changing non-primary adapters' settings will be ignored. */
+    *id = !lstrcmpiW( device_name, primary_adapter ) ? 1 : 0;
+    return TRUE;
+}
+
+static void add_xf86vm_mode(DEVMODEW *mode, DWORD depth, const XF86VidModeModeInfo *mode_info)
+{
+    mode->dmSize = sizeof(*mode);
+    mode->dmDriverExtra = sizeof(mode_info);
+    mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS;
+    if (mode_info->htotal && mode_info->vtotal)
+    {
+        mode->dmFields |= DM_DISPLAYFREQUENCY;
+        mode->dmDisplayFrequency = mode_info->dotclock * 1000 / (mode_info->htotal * mode_info->vtotal);
     }
-  ERR("In unknown mode, returning default\n");
-  return 0;
+    mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
+    mode->dmBitsPerPel = depth;
+    mode->dmPelsWidth = mode_info->hdisplay;
+    mode->dmPelsHeight = mode_info->vdisplay;
+    mode->u2.dmDisplayFlags = 0;
+    memcpy((BYTE *)mode + sizeof(*mode), &mode_info, sizeof(mode_info));
 }
 
-static LONG X11DRV_XF86VM_SetCurrentMode(int mode)
+static BOOL xf86vm_get_modes(ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count)
 {
-  DWORD dwBpp = screen_bpp;
-  /* only set modes from the original color depth */
-  if (dwBpp != dd_modes[mode].bpp)
-  {
-      FIXME("Cannot change screen BPP from %d to %d\n", dwBpp, dd_modes[mode].bpp);
-  }
-  mode = mode % real_xf86vm_mode_count;
+    INT xf86vm_mode_idx, xf86vm_mode_count;
+    XF86VidModeModeInfo **xf86vm_modes;
+    UINT depth_idx, mode_idx = 0;
+    DEVMODEW *modes, *mode;
+    SIZE_T size;
+    BYTE *ptr;
+    Bool ret;
 
-  TRACE("Resizing X display to %dx%d\n", 
-        real_xf86vm_modes[mode]->hdisplay, real_xf86vm_modes[mode]->vdisplay);
-  pXF86VidModeSwitchToMode(gdi_display, DefaultScreen(gdi_display), real_xf86vm_modes[mode]);
-#if 0 /* it is said that SetViewPort causes problems with some X servers */
-  pXF86VidModeSetViewPort(gdi_display, DefaultScreen(gdi_display), 0, 0);
-#else
-  XWarpPointer(gdi_display, None, DefaultRootWindow(gdi_display), 0, 0, 0, 0, 0, 0);
-#endif
-  XSync(gdi_display, False);
-  X11DRV_DisplayDevices_Update( TRUE );
-  return DISP_CHANGE_SUCCESSFUL;
+    X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+    ret = pXF86VidModeGetAllModeLines(gdi_display, DefaultScreen(gdi_display), &xf86vm_mode_count, &xf86vm_modes);
+    if (X11DRV_check_error() || !ret || !xf86vm_mode_count)
+        return FALSE;
+
+    /* Put a XF86VidModeModeInfo ** at the start to store the XF86VidMode modes pointer */
+    size = sizeof(XF86VidModeModeInfo **);
+    /* Display modes in different color depth, with a XF86VidModeModeInfo * at the end of each
+     * DEVMODEW as driver private data */
+    size += (xf86vm_mode_count * DEPTH_COUNT) * (sizeof(DEVMODEW) + sizeof(XF86VidModeModeInfo *));
+    ptr = heap_alloc_zero(size);
+    if (!ptr)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    memcpy(ptr, &xf86vm_modes, sizeof(xf86vm_modes));
+    modes = (DEVMODEW *)(ptr + sizeof(xf86vm_modes));
+
+    for (depth_idx = 0; depth_idx < DEPTH_COUNT; ++depth_idx)
+    {
+        for (xf86vm_mode_idx = 0; xf86vm_mode_idx < xf86vm_mode_count; ++xf86vm_mode_idx)
+        {
+            mode = (DEVMODEW *)((BYTE *)modes + (sizeof(DEVMODEW) + sizeof(XF86VidModeModeInfo *)) * mode_idx++);
+            add_xf86vm_mode(mode, depths[depth_idx], xf86vm_modes[xf86vm_mode_idx]);
+        }
+    }
+
+    *new_modes = modes;
+    *mode_count = mode_idx;
+    return TRUE;
 }
 
+static void xf86vm_free_modes(DEVMODEW *modes)
+{
+    XF86VidModeModeInfo **xf86vm_modes;
+
+    if (modes)
+    {
+        assert(modes[0].dmDriverExtra == sizeof(XF86VidModeModeInfo *));
+        memcpy(&xf86vm_modes, (BYTE *)modes - sizeof(xf86vm_modes), sizeof(xf86vm_modes));
+        XFree(xf86vm_modes);
+    }
+    heap_free(modes);
+}
+
+static BOOL xf86vm_get_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+    XF86VidModeModeLine xf86vm_mode;
+    INT dotclock;
+    Bool ret;
+
+    mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+                     DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
+    mode->u1.s2.dmDisplayOrientation = DMDO_DEFAULT;
+    mode->u2.dmDisplayFlags = 0;
+    mode->u1.s2.dmPosition.x = 0;
+    mode->u1.s2.dmPosition.y = 0;
+
+    if (id != 1)
+    {
+        FIXME("Non-primary adapters are unsupported.\n");
+        mode->dmBitsPerPel = 0;
+        mode->dmPelsWidth = 0;
+        mode->dmPelsHeight = 0;
+        mode->dmDisplayFrequency = 0;
+        return TRUE;
+    }
+
+    X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+    ret = pXF86VidModeGetModeLine(gdi_display, DefaultScreen(gdi_display), &dotclock, &xf86vm_mode);
+    if (X11DRV_check_error() || !ret)
+        return FALSE;
+
+    mode->dmBitsPerPel = screen_bpp;
+    mode->dmPelsWidth = xf86vm_mode.hdisplay;
+    mode->dmPelsHeight = xf86vm_mode.vdisplay;
+    if (xf86vm_mode.htotal && xf86vm_mode.vtotal)
+        mode->dmDisplayFrequency = dotclock * 1000 / (xf86vm_mode.htotal * xf86vm_mode.vtotal);
+    else
+        mode->dmDisplayFrequency = 0;
+
+    if (xf86vm_mode.privsize)
+        XFree(xf86vm_mode.private);
+    return TRUE;
+}
+
+static LONG xf86vm_set_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+    XF86VidModeModeInfo *xf86vm_mode;
+    Bool ret;
+
+    if (id != 1)
+    {
+        FIXME("Non-primary adapters are unsupported.\n");
+        return DISP_CHANGE_SUCCESSFUL;
+    }
+
+    if (is_detached_mode(mode))
+    {
+        FIXME("Detaching adapters is unsupported.\n");
+        return DISP_CHANGE_SUCCESSFUL;
+    }
+
+    if (mode->dmFields & DM_BITSPERPEL && mode->dmBitsPerPel != screen_bpp)
+        WARN("Cannot change screen bit depth from %dbits to %dbits!\n", screen_bpp, mode->dmBitsPerPel);
+
+    assert(mode->dmDriverExtra == sizeof(XF86VidModeModeInfo *));
+    memcpy(&xf86vm_mode, (BYTE *)mode + sizeof(*mode), sizeof(xf86vm_mode));
+    X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
+    ret = pXF86VidModeSwitchToMode(gdi_display, DefaultScreen(gdi_display), xf86vm_mode);
+    if (X11DRV_check_error() || !ret)
+        return DISP_CHANGE_FAILED;
+#if 0 /* it is said that SetViewPort causes problems with some X servers */
+    pXF86VidModeSetViewPort(gdi_display, DefaultScreen(gdi_display), 0, 0);
+#else
+    XWarpPointer(gdi_display, None, DefaultRootWindow(gdi_display), 0, 0, 0, 0, 0, 0);
+#endif
+    XFlush(gdi_display);
+    return DISP_CHANGE_SUCCESSFUL;
+}
 
 void X11DRV_XF86VM_Init(void)
 {
+  struct x11drv_settings_handler xf86vm_handler;
   void *xvidmode_handle;
   Bool ok;
-  int nmodes;
-  unsigned int i;
 
   if (xf86vm_major) return; /* already initialized? */
 
@@ -207,35 +304,17 @@ void X11DRV_XF86VM_Init(void)
   }
 #endif /* X_XF86VidModeSetGammaRamp */
 
-  /* retrieve modes */
-  if (usexvidmode && !is_virtual_desktop())
-  {
-      X11DRV_expect_error(gdi_display, XVidModeErrorHandler, NULL);
-      ok = pXF86VidModeGetAllModeLines(gdi_display, DefaultScreen(gdi_display), &nmodes, &real_xf86vm_modes);
-      if (X11DRV_check_error() || !ok) return;
-  }
-  else return; /* In desktop mode, do not switch resolution... But still use the Gamma ramp stuff */
+  if (!usexvidmode)
+    return;
 
-  TRACE("XVidMode modes: count=%d\n", nmodes);
-
-  real_xf86vm_mode_count = nmodes;
-
-  dd_modes = X11DRV_Settings_SetHandlers("XF86VidMode", 
-                                         X11DRV_XF86VM_GetCurrentMode, 
-                                         X11DRV_XF86VM_SetCurrentMode, 
-                                         nmodes, 1);
-
-  /* convert modes to x11drv_mode_info format */
-  for (i=0; i<real_xf86vm_mode_count; i++)
-  {
-      convert_modeinfo(real_xf86vm_modes[i]);
-  }
-  /* add modes for different color depths */
-  X11DRV_Settings_AddDepthModes();
-  dd_mode_count = X11DRV_Settings_GetModeCount();
-
-  TRACE("Available DD modes: count=%d\n", dd_mode_count);
-  TRACE("Enabling XVidMode\n");
+  xf86vm_handler.name = "XF86VidMode";
+  xf86vm_handler.priority = 100;
+  xf86vm_handler.get_id = xf86vm_get_id;
+  xf86vm_handler.get_modes = xf86vm_get_modes;
+  xf86vm_handler.free_modes = xf86vm_free_modes;
+  xf86vm_handler.get_current_mode = xf86vm_get_current_mode;
+  xf86vm_handler.set_current_mode = xf86vm_set_current_mode;
+  X11DRV_Settings_SetHandler(&xf86vm_handler);
   return;
 
 sym_not_found:
-- 
2.25.1




More information about the wine-devel mailing list