This MR uses the existing compositor side surface scaling in the driver (through wp_viewporter, currently used for Hi-DPI scaling) to emulate display mode changes. This works wonderfully in coordination with fullscreen since the compositor is required non only to scale the surface, but also to position it properly and provide opaque surroundings (note: some compositors don't implement the last two features properly!).
Since: 1. Wayland doesn't allow clients to change the actual display configuration, and 2. there is no queryable service that holds the display information in a consistent manner (à la xrandr), the MR uses the win32 device settings as the source of truth for the current display mode. We let win32u handle the display mode change in the default manner (i.e., just updating the registry settings), and provide access to the current mode when updating the display devices through a new `gdi_display_manager.get_adapter()` function.
In order to be able to consistently (across all processes) associate an adapter device with its corresponding `wl_output` the MR introduces per-adapter driver data.
Note for people trying this out: many modern games don't change the hardware display settings, but rather scale themselves in right way to achieve the visual effect of a mode change (similarly to how this MR works, but they do it on the application side). To exercise most of the functionality in this MR you need an application that actually uses the `ChangeDisplaySettings` win32 API.
Thanks!
From: Alexandros Frantzis alexandros.frantzis@collabora.com
The reporting of non-current wl_output modes is deprecated, and most compositors now report only the current display mode.
Since Wayland doesn't allow clients to directly change the hardware display mode, we can safely make some common display modes available to applications. --- dlls/winewayland.drv/wayland_output.c | 94 ++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 9 deletions(-)
diff --git a/dlls/winewayland.drv/wayland_output.c b/dlls/winewayland.drv/wayland_output.c index f5941c10f6f..0dfc1d974e4 100644 --- a/dlls/winewayland.drv/wayland_output.c +++ b/dlls/winewayland.drv/wayland_output.c @@ -40,6 +40,54 @@ static uint32_t next_output_id = 0; #define WAYLAND_OUTPUT_CHANGED_LOGICAL_XY 0x04 #define WAYLAND_OUTPUT_CHANGED_LOGICAL_WH 0x08
+static const struct { int32_t width; int32_t height; } common_modes[] = { + { 320, 200}, /* CGA 16:10 */ + { 320, 240}, /* QVGA 4:3 */ + { 400, 300}, /* qSVGA 4:3 */ + { 480, 320}, /* HVGA 3:2 */ + { 512, 384}, /* MAC 4:3 */ + { 640, 360}, /* nHD 16:9 */ + { 640, 400}, /* VESA-0100h 16:10 */ + { 640, 480}, /* VGA 4:3 */ + { 720, 480}, /* WVGA 3:2 */ + { 720, 576}, /* PAL 5:4 */ + { 768, 480}, /* WVGA 16:10 */ + { 768, 576}, /* PAL* 4:3 */ + { 800, 600}, /* SVGA 4:3 */ + { 854, 480}, /* FWVGA 16:9 */ + { 960, 540}, /* qHD 16:9 */ + { 960, 640}, /* DVGA 3:2 */ + {1024, 576}, /* WSVGA 16:9 */ + {1024, 640}, /* WSVGA 16:10 */ + {1024, 768}, /* XGA 4:3 */ + {1152, 864}, /* XGA+ 4:3 */ + {1280, 720}, /* HD 16:9 */ + {1280, 768}, /* WXGA 5:3 */ + {1280, 800}, /* WXGA 16:10 */ + {1280, 960}, /* SXGA- 4:3 */ + {1280, 1024}, /* SXGA 5:4 */ + {1366, 768}, /* FWXGA 16:9 */ + {1400, 1050}, /* SXGA+ 4:3 */ + {1440, 900}, /* WSXGA 16:10 */ + {1600, 900}, /* HD+ 16:9 */ + {1600, 1200}, /* UXGA 4:3 */ + {1680, 1050}, /* WSXGA+ 16:10 */ + {1920, 1080}, /* FHD 16:9 */ + {1920, 1200}, /* WUXGA 16:10 */ + {2048, 1152}, /* QWXGA 16:9 */ + {2048, 1536}, /* QXGA 4:3 */ + {2560, 1440}, /* QHD 16:9 */ + {2560, 1600}, /* WQXGA 16:10 */ + {2560, 2048}, /* QSXGA 5:4 */ + {2880, 1620}, /* 3K 16:9 */ + {3200, 1800}, /* QHD+ 16:9 */ + {3200, 2400}, /* QUXGA 4:3 */ + {3840, 2160}, /* 4K 16:9 */ + {3840, 2400}, /* WQUXGA 16:10 */ + {5120, 2880}, /* 5K 16:9 */ + {7680, 4320}, /* 8K 16:9 */ +}; + /********************************************************************** * Output handling */ @@ -102,6 +150,31 @@ static void wayland_output_state_add_mode(struct wayland_output_state *state, if (current) state->current_mode = mode; }
+static void wayland_output_state_add_common_modes(struct wayland_output_state *state) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(common_modes); i++) + { + int32_t width = common_modes[i].width; + int32_t height = common_modes[i].height; + + /* Skip if this mode is larger than the current (native) mode. */ + if (width > state->current_mode->width || + height > state->current_mode->height) + { + TRACE("Skipping mode %dx%d (current: %dx%d)\n", + width, height, state->current_mode->width, + state->current_mode->height); + continue; + } + + wayland_output_state_add_mode(state, width, height, + state->current_mode->refresh, + FALSE); + } +} + static void maybe_init_display_devices(void) { DWORD desktop_pid = 0; @@ -136,14 +209,15 @@ static void wayland_output_done(struct wayland_output *output)
if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_MODES) { - RB_FOR_EACH_ENTRY(mode, &output->pending.modes, struct wayland_output_mode, entry) - { - wayland_output_state_add_mode(&output->current, - mode->width, mode->height, mode->refresh, - mode == output->pending.current_mode); - } - rb_destroy(&output->pending.modes, wayland_output_mode_free_rb, NULL); + rb_destroy(&output->current.modes, wayland_output_mode_free_rb, NULL); + output->current.modes = output->pending.modes; + output->current.current_mode = output->pending.current_mode; + if (!output->current.current_mode) + WARN("No current mode reported by compositor\n"); + else + wayland_output_state_add_common_modes(&output->current); rb_init(&output->pending.modes, wayland_output_mode_cmp_rb); + output->pending.current_mode = NULL; }
if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_NAME) @@ -206,11 +280,13 @@ static void output_handle_mode(void *data, struct wl_output *wl_output, { struct wayland_output *output = data;
+ /* Non-current mode information is deprecated. */ + if (!(flags & WL_OUTPUT_MODE_CURRENT)) return; + /* Windows apps don't expect a zero refresh rate, so use a default value. */ if (refresh == 0) refresh = default_refresh;
- wayland_output_state_add_mode(&output->pending, width, height, refresh, - (flags & WL_OUTPUT_MODE_CURRENT)); + wayland_output_state_add_mode(&output->pending, width, height, refresh, TRUE);
output->pending_flags |= WAYLAND_OUTPUT_CHANGED_MODES; }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
--- dlls/winewayland.drv/display.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index ebe151ffab0..a8fcaf2a2f5 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -246,13 +246,14 @@ static void wayland_add_device_monitor(const struct gdi_device_manager *device_m device_manager->add_monitor(&monitor, param); }
-static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW *mode) +static void populate_devmode(struct wayland_output_mode *output_mode, DWORD bpp, + DEVMODEW *mode) { mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY; mode->dmDisplayOrientation = DMDO_DEFAULT; mode->dmDisplayFlags = 0; - mode->dmBitsPerPel = 32; + mode->dmBitsPerPel = bpp; mode->dmPelsWidth = output_mode->width; mode->dmPelsHeight = output_mode->height; mode->dmDisplayFrequency = output_mode->refresh / 1000; @@ -261,21 +262,28 @@ static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW * static void wayland_add_device_modes(const struct gdi_device_manager *device_manager, void *param, struct output_info *output_info) { + static const DWORD bpps[] = {32, 16, 8}; struct wayland_output_mode *output_mode; + int i;
RB_FOR_EACH_ENTRY(output_mode, &output_info->output->modes, struct wayland_output_mode, entry) { - DEVMODEW mode = {.dmSize = sizeof(mode)}; - BOOL mode_is_current = output_mode == output_info->output->current_mode; - populate_devmode(output_mode, &mode); - if (mode_is_current) + for (i = 0; i < ARRAY_SIZE(bpps); i++) { - mode.dmFields |= DM_POSITION; - mode.dmPosition.x = output_info->x; - mode.dmPosition.y = output_info->y; + DEVMODEW mode = {.dmSize = sizeof(mode)}; + BOOL mode_is_current = output_mode == output_info->output->current_mode && + bpps[i] == 32; + + populate_devmode(output_mode, bpps[i], &mode); + if (mode_is_current) + { + mode.dmFields |= DM_POSITION; + mode.dmPosition.x = output_info->x; + mode.dmPosition.y = output_info->y; + } + device_manager->add_mode(&mode, mode_is_current, param); } - device_manager->add_mode(&mode, mode_is_current, param); } }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Refactor output_info to dissociate the current display mode from the Wayland native display mode, in preparation for handling display mode changes. --- dlls/winewayland.drv/display.c | 36 ++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index a8fcaf2a2f5..888c6e5aabb 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -51,6 +51,8 @@ struct output_info { int x, y; struct wayland_output_state *output; + struct wayland_output_mode *mode; + UINT bpp; };
static int output_info_cmp_primary_x_y(const void *va, const void *vb) @@ -71,10 +73,10 @@ static int output_info_cmp_primary_x_y(const void *va, const void *vb)
static inline BOOL output_info_overlap(struct output_info *a, struct output_info *b) { - return b->x < a->x + a->output->current_mode->width && - b->x + b->output->current_mode->width > a->x && - b->y < a->y + a->output->current_mode->height && - b->y + b->output->current_mode->height > a->y; + return b->x < a->x + a->mode->width && + b->x + b->mode->width > a->x && + b->y < a->y + a->mode->height && + b->y + b->mode->height > a->y; }
/* Map a point to one of the four quadrants of our 2d coordinate space: @@ -156,16 +158,16 @@ static BOOL output_info_array_resolve_overlaps(struct wl_array *output_info_arra rel_x = (move->output->logical_x - anchor->output->logical_x + (x_use_end ? move->output->logical_w : 0)) / (double)anchor->output->logical_w; - move->x = anchor->x + anchor->output->current_mode->width * rel_x - - (x_use_end ? move->output->current_mode->width : 0); + move->x = anchor->x + anchor->mode->width * rel_x - + (x_use_end ? move->mode->width : 0);
/* Similarly for the Y axis. */ y_use_end = move->output->logical_y < anchor->output->logical_y; rel_y = (move->output->logical_y - anchor->output->logical_y + (y_use_end ? move->output->logical_h : 0)) / (double)anchor->output->logical_h; - move->y = anchor->y + anchor->output->current_mode->height * rel_y - - (y_use_end ? move->output->current_mode->height : 0); + move->y = anchor->y + anchor->mode->height * rel_y - + (y_use_end ? move->mode->height : 0); } }
@@ -231,8 +233,8 @@ static void wayland_add_device_monitor(const struct gdi_device_manager *device_m struct gdi_monitor monitor = {0};
SetRect(&monitor.rc_monitor, output_info->x, output_info->y, - output_info->x + output_info->output->current_mode->width, - output_info->y + output_info->output->current_mode->height); + output_info->x + output_info->mode->width, + output_info->y + output_info->mode->height);
/* We don't have a direct way to get the work area in Wayland. */ monitor.rc_work = monitor.rc_monitor; @@ -272,8 +274,8 @@ static void wayland_add_device_modes(const struct gdi_device_manager *device_man for (i = 0; i < ARRAY_SIZE(bpps); i++) { DEVMODEW mode = {.dmSize = sizeof(mode)}; - BOOL mode_is_current = output_mode == output_info->output->current_mode && - bpps[i] == 32; + BOOL mode_is_current = output_mode == output_info->mode && + bpps[i] == output_info->bpp;
populate_devmode(output_mode, bpps[i], &mode); if (mode_is_current) @@ -287,6 +289,14 @@ static void wayland_add_device_modes(const struct gdi_device_manager *device_man } }
+static void output_info_init(struct output_info *output_info, + struct wayland_output *output) +{ + output_info->output = &output->current; + output_info->mode = output->current.current_mode; + output_info->bpp = 32; +} + /*********************************************************************** * UpdateDisplayDevices (WAYLAND.@) */ @@ -312,7 +322,7 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage { if (!output->current.current_mode) continue; output_info = wl_array_add(&output_info_array, sizeof(*output_info)); - if (output_info) output_info->output = &output->current; + if (output_info) output_info_init(output_info, output); else ERR("Failed to allocate space for output_info\n"); }
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Since Wayland doesn't support mode changes, we let win32u handle them by just recording them in the registry, and we use that information as the authoritative source for the current mode when updating the devices. --- dlls/win32u/sysparams.c | 29 ++++++++++++++++++++- dlls/winewayland.drv/display.c | 47 +++++++++++++++++++++++++++++++--- include/wine/gdi_driver.h | 1 + 3 files changed, 72 insertions(+), 5 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index e2c5b10da9e..694c41cb317 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -1253,8 +1253,8 @@ static void add_gpu( const struct gdi_gpu *gpu, void *param ) { ctx->mutex = get_display_device_init_mutex(); pthread_mutex_lock( &display_lock ); - prepare_devices(); } + if (gpu_index == 0) prepare_devices();
sprintf( buffer, "PCI\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\%08X", gpu->vendor_id, gpu->device_id, gpu->subsys_id, gpu->revision_id, gpu_index ); @@ -1634,12 +1634,33 @@ static void add_mode( const DEVMODEW *mode, BOOL current, void *param ) } }
+static struct display_device *find_adapter_device_by_id( UINT index ); + +static BOOL get_adapter( UINT adapter_idx, DEVMODEW *mode, void *param ) +{ + struct device_manager_ctx *ctx = param; + struct display_device *device; + struct adapter *adapter = NULL; + + if (!ctx->mutex) + { + ctx->mutex = get_display_device_init_mutex(); + pthread_mutex_lock( &display_lock ); + } + + if (!(device = find_adapter_device_by_id( adapter_idx ))) return FALSE; + adapter = CONTAINING_RECORD( device, struct adapter, dev ); + + return adapter_get_current_settings( adapter, mode ); +} + static const struct gdi_device_manager device_manager = { add_gpu, add_adapter, add_monitor, add_mode, + get_adapter, };
static void reset_display_manager_ctx( struct device_manager_ctx *ctx ) @@ -1899,12 +1920,18 @@ static void desktop_add_mode( const DEVMODEW *mode, BOOL current, void *param ) } }
+static BOOL desktop_get_adapter( UINT id, DEVMODEW *mode, void *param ) +{ + return FALSE; +} + static const struct gdi_device_manager desktop_device_manager = { desktop_add_gpu, desktop_add_adapter, desktop_add_monitor, desktop_add_mode, + desktop_get_adapter, };
static BOOL desktop_update_display_devices( BOOL force, struct device_manager_ctx *ctx ) diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index 888c6e5aabb..584732a73db 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -289,12 +289,47 @@ static void wayland_add_device_modes(const struct gdi_device_manager *device_man } }
+static struct wayland_output_mode *get_matching_output_mode(struct wayland_output *output, + DEVMODEW *devmode) +{ + struct wayland_output_mode *output_mode; + + RB_FOR_EACH_ENTRY(output_mode, &output->current.modes, + struct wayland_output_mode, entry) + { + if (devmode->dmPelsWidth == output_mode->width && + devmode->dmPelsHeight == output_mode->height && + output_mode->refresh / 1000 == devmode->dmDisplayFrequency) + { + return output_mode; + } + } + + return NULL; +} + static void output_info_init(struct output_info *output_info, - struct wayland_output *output) + struct wayland_output *output, + int adapter_id, + const struct gdi_device_manager *device_manager, + void *param) { + DEVMODEW devmode = {.dmSize = sizeof(devmode)}; + struct wayland_output_mode *mode; + output_info->output = &output->current; - output_info->mode = output->current.current_mode; - output_info->bpp = 32; + + if (device_manager->get_adapter(adapter_id, &devmode, param) && + (mode = get_matching_output_mode(output, &devmode))) + { + output_info->mode = mode; + output_info->bpp = devmode.dmBitsPerPel; + } + else + { + output_info->mode = output->current.current_mode; + output_info->bpp = 32; + } }
/*********************************************************************** @@ -322,8 +357,11 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage { if (!output->current.current_mode) continue; output_info = wl_array_add(&output_info_array, sizeof(*output_info)); - if (output_info) output_info_init(output_info, output); + /* TODO: Don't assume that the order of devices matches the order + * of the outputs in the list. */ + if (output_info) output_info_init(output_info, output, output_id, device_manager, param); else ERR("Failed to allocate space for output_info\n"); + output_id++; }
output_info_array_arrange_physical_coords(&output_info_array); @@ -331,6 +369,7 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage /* Populate GDI devices. */ wayland_add_device_gpu(device_manager, param);
+ output_id = 0; wl_array_for_each(output_info, &output_info_array) { wayland_add_device_adapter(device_manager, param, output_id); diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index bd827c31cb1..d3679377344 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -275,6 +275,7 @@ struct gdi_device_manager void (*add_adapter)( const struct gdi_adapter *adapter, void *param ); void (*add_monitor)( const struct gdi_monitor *monitor, void *param ); void (*add_mode)( const DEVMODEW *mode, BOOL current, void *param ); + BOOL (*get_adapter)( UINT id, DEVMODEW *mode, void *param ); };
#define WINE_DM_UNSUPPORTED 0x80000000
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Introduce and use driver data for GDI adapters to associate each adapter with its corresponding Wayland output.
Use this association to ensure we get the proper current display mode for each output, when updating the display devices. --- dlls/win32u/sysparams.c | 36 +++++++++++++++++++++++--- dlls/winewayland.drv/display.c | 47 +++++++++++++++++++++++----------- include/wine/gdi_driver.h | 4 ++- 3 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 694c41cb317..9b01c3c1513 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -183,6 +183,7 @@ static const WCHAR linkedW[] = {'L','i','n','k','e','d',0}; static const WCHAR symbolic_link_valueW[] = {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0}; static const WCHAR state_flagsW[] = {'S','t','a','t','e','F','l','a','g','s',0}; +static const WCHAR driver_dataW[] = {'D','r','i','v','e','r','D','a','t','a',0}; static const WCHAR gpu_idW[] = {'G','P','U','I','D',0}; static const WCHAR hardware_idW[] = {'H','a','r','d','w','a','r','e','I','D',0}; static const WCHAR device_descW[] = {'D','e','v','i','c','e','D','e','s','c',0}; @@ -243,6 +244,8 @@ struct adapter const WCHAR *config_key; unsigned int mode_count; DEVMODEW *modes; + unsigned char *driver_data; + UINT driver_data_len; };
#define MONITOR_INFO_HAS_MONITOR_ID 0x00000001 @@ -476,6 +479,7 @@ static void adapter_release( struct adapter *adapter ) if (!InterlockedDecrement( &adapter->refcount )) { free( adapter->modes ); + free( adapter->driver_data ); free( adapter ); } } @@ -760,6 +764,21 @@ static BOOL read_display_adapter_settings( unsigned int index, struct adapter *i if (query_reg_value( hkey, state_flagsW, value, sizeof(buffer) ) && value->Type == REG_DWORD) info->dev.state_flags = *(const DWORD *)value->Data;
+ /* DriverData */ + if (query_reg_value( hkey, driver_dataW, value, sizeof(buffer) ) && value->Type == REG_BINARY) + { + info->driver_data = malloc( value->DataLength ); + if (info->driver_data) + { + memcpy( info->driver_data, value->Data, value->DataLength ); + info->driver_data_len = value->DataLength; + } + else + { + info->driver_data_len = 0; + } + } + /* Interface name */ info->dev.interface_name[0] = 0;
@@ -1479,6 +1498,11 @@ static void add_adapter( const struct gdi_adapter *adapter, void *param ) (lstrlenW( ctx->gpuid ) + 1) * sizeof(WCHAR) ); set_reg_value( ctx->adapter_key, state_flagsW, REG_DWORD, &adapter->state_flags, sizeof(adapter->state_flags) ); + if (adapter->driver_data && adapter->driver_data_len) + { + set_reg_value( ctx->adapter_key, driver_dataW, REG_BINARY, + adapter->driver_data, adapter->driver_data_len ); + } }
static void add_monitor( const struct gdi_monitor *monitor, void *param ) @@ -1636,7 +1660,7 @@ static void add_mode( const DEVMODEW *mode, BOOL current, void *param )
static struct display_device *find_adapter_device_by_id( UINT index );
-static BOOL get_adapter( UINT adapter_idx, DEVMODEW *mode, void *param ) +static BOOL get_adapter( UINT adapter_idx, DEVMODEW *mode, void *data, UINT *data_len, void *param ) { struct device_manager_ctx *ctx = param; struct display_device *device; @@ -1651,7 +1675,13 @@ static BOOL get_adapter( UINT adapter_idx, DEVMODEW *mode, void *param ) if (!(device = find_adapter_device_by_id( adapter_idx ))) return FALSE; adapter = CONTAINING_RECORD( device, struct adapter, dev );
- return adapter_get_current_settings( adapter, mode ); + if (!adapter_get_current_settings( adapter, mode )) return FALSE; + + *data_len = min( *data_len, adapter->driver_data_len ); + if (data && adapter->driver_data) + memcpy( data, adapter->driver_data, *data_len ); + + return TRUE; }
static const struct gdi_device_manager device_manager = @@ -1920,7 +1950,7 @@ static void desktop_add_mode( const DEVMODEW *mode, BOOL current, void *param ) } }
-static BOOL desktop_get_adapter( UINT id, DEVMODEW *mode, void *param ) +static BOOL desktop_get_adapter( UINT id, DEVMODEW *mode, void *data, UINT *data_len, void *param ) { return FALSE; } diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index 584732a73db..ab7f7599659 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -47,6 +47,11 @@ void wayland_init_display_devices(BOOL force) NtUserGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &num_path, &num_mode); }
+struct wayland_adapter_data +{ + char output_name[64]; +}; + struct output_info { int x, y; @@ -213,14 +218,21 @@ static void wayland_add_device_gpu(const struct gdi_device_manager *device_manag }
static void wayland_add_device_adapter(const struct gdi_device_manager *device_manager, - void *param, INT output_id) + void *param, INT output_id, + struct output_info *output_info) { struct gdi_adapter adapter; + struct wayland_adapter_data data; + adapter.id = output_id; adapter.state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP; if (output_id == 0) adapter.state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
+ lstrcpynA(data.output_name, output_info->output->name, sizeof(data.output_name)); + adapter.driver_data = &data; + adapter.driver_data_len = sizeof(data); + TRACE("id=0x%s state_flags=0x%x\n", wine_dbgstr_longlong(adapter.id), (UINT)adapter.state_flags);
@@ -310,25 +322,32 @@ static struct wayland_output_mode *get_matching_output_mode(struct wayland_outpu
static void output_info_init(struct output_info *output_info, struct wayland_output *output, - int adapter_id, const struct gdi_device_manager *device_manager, void *param) { DEVMODEW devmode = {.dmSize = sizeof(devmode)}; struct wayland_output_mode *mode; + struct wayland_adapter_data data; + UINT data_len = sizeof(data); + UINT id = 0;
output_info->output = &output->current; + output_info->mode = output->current.current_mode; + output_info->bpp = 32;
- if (device_manager->get_adapter(adapter_id, &devmode, param) && - (mode = get_matching_output_mode(output, &devmode))) - { - output_info->mode = mode; - output_info->bpp = devmode.dmBitsPerPel; - } - else + while (device_manager->get_adapter(id, &devmode, &data, &data_len, param)) { - output_info->mode = output->current.current_mode; - output_info->bpp = 32; + if (data_len == sizeof(data) && + !strcmp(output->current.name, data.output_name)) + { + if ((mode = get_matching_output_mode(output, &devmode))) + { + output_info->mode = mode; + output_info->bpp = devmode.dmBitsPerPel; + } + } + data_len = sizeof(data); + ++id; } }
@@ -359,9 +378,8 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage output_info = wl_array_add(&output_info_array, sizeof(*output_info)); /* TODO: Don't assume that the order of devices matches the order * of the outputs in the list. */ - if (output_info) output_info_init(output_info, output, output_id, device_manager, param); + if (output_info) output_info_init(output_info, output, device_manager, param); else ERR("Failed to allocate space for output_info\n"); - output_id++; }
output_info_array_arrange_physical_coords(&output_info_array); @@ -369,10 +387,9 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage /* Populate GDI devices. */ wayland_add_device_gpu(device_manager, param);
- output_id = 0; wl_array_for_each(output_info, &output_info_array) { - wayland_add_device_adapter(device_manager, param, output_id); + wayland_add_device_adapter(device_manager, param, output_id, output_info); wayland_add_device_monitor(device_manager, param, output_info); wayland_add_device_modes(device_manager, param, output_info); output_id++; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index d3679377344..202a164d070 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -258,6 +258,8 @@ struct gdi_adapter { ULONG_PTR id; DWORD state_flags; + void *driver_data; + UINT driver_data_len; };
struct gdi_monitor @@ -275,7 +277,7 @@ struct gdi_device_manager void (*add_adapter)( const struct gdi_adapter *adapter, void *param ); void (*add_monitor)( const struct gdi_monitor *monitor, void *param ); void (*add_mode)( const DEVMODEW *mode, BOOL current, void *param ); - BOOL (*get_adapter)( UINT id, DEVMODEW *mode, void *param ); + BOOL (*get_adapter)( UINT id, DEVMODEW *mode, void *data, UINT *data_len, void *param ); };
#define WINE_DM_UNSUPPORTED 0x80000000
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Emulate the visual effect of a display mode change, by scaling the window according to the ratios of the native vs current mode.
We provide the adapter scaling information to the driver as part of the adapter driver data so it's consistent across all processes. --- dlls/win32u/main.c | 6 ++++++ dlls/win32u/sysparams.c | 17 +++++++++++++++++ dlls/win32u/win32syscalls.h | 14 ++++++++------ dlls/win32u/win32u.spec | 1 + dlls/winewayland.drv/display.c | 9 ++++----- dlls/winewayland.drv/waylanddrv.h | 7 +++++++ dlls/winewayland.drv/window.c | 17 +++++++++++++++++ dlls/wow64win/user.c | 6 ++++++ include/ntuser.h | 1 + 9 files changed, 67 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 2dc66e5df11..432f3fa892a 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -2140,6 +2140,12 @@ HWND SYSCALL_API NtUserWindowFromPoint( LONG x, LONG y ) __ASM_SYSCALL_FUNC( __id_NtUserWindowFromPoint ); }
+BOOL SYSCALL_API __wine_get_adapter_driver_data( UNICODE_STRING *devname, + void *data, UINT *data_len ) +{ + __ASM_SYSCALL_FUNC( __id___wine_get_adapter_driver_data ); +} + BOOL SYSCALL_API __wine_get_file_outline_text_metric( const WCHAR *path, TEXTMETRICW *otm, UINT *em_square, WCHAR *face_name ) { diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 9b01c3c1513..65437801970 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6631,3 +6631,20 @@ NTSTATUS WINAPI NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEAD return STATUS_INVALID_PARAMETER; } } + +void WINAPI __wine_get_adapter_driver_data( UNICODE_STRING *devname, void *data, UINT *data_len ) +{ + struct adapter *adapter; + + if ((adapter = find_adapter( devname ))) + { + *data_len = min( *data_len, adapter->driver_data_len ); + if (data && adapter->driver_data) + memcpy( data, adapter->driver_data, *data_len ); + adapter_release( adapter ); + } + else + { + *data_len = 0; + } +} diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h index 543583356d9..3772dd61ef2 100644 --- a/dlls/win32u/win32syscalls.h +++ b/dlls/win32u/win32syscalls.h @@ -399,9 +399,10 @@ SYSCALL_ENTRY( 0x018b, NtUserWaitMessage, 0 ) \ SYSCALL_ENTRY( 0x018c, NtUserWindowFromDC, 4 ) \ SYSCALL_ENTRY( 0x018d, NtUserWindowFromPoint, 8 ) \ - SYSCALL_ENTRY( 0x018e, __wine_get_file_outline_text_metric, 16 ) \ - SYSCALL_ENTRY( 0x018f, __wine_get_icm_profile, 16 ) \ - SYSCALL_ENTRY( 0x0190, __wine_send_input, 12 ) + SYSCALL_ENTRY( 0x018e, __wine_get_adapter_driver_data, 12 ) \ + SYSCALL_ENTRY( 0x018f, __wine_get_file_outline_text_metric, 16 ) \ + SYSCALL_ENTRY( 0x0190, __wine_get_icm_profile, 16 ) \ + SYSCALL_ENTRY( 0x0191, __wine_send_input, 12 )
#define ALL_SYSCALLS64 \ SYSCALL_ENTRY( 0x0000, NtGdiAbortDoc, 8 ) \ @@ -802,6 +803,7 @@ SYSCALL_ENTRY( 0x018b, NtUserWaitMessage, 0 ) \ SYSCALL_ENTRY( 0x018c, NtUserWindowFromDC, 8 ) \ SYSCALL_ENTRY( 0x018d, NtUserWindowFromPoint, 16 ) \ - SYSCALL_ENTRY( 0x018e, __wine_get_file_outline_text_metric, 32 ) \ - SYSCALL_ENTRY( 0x018f, __wine_get_icm_profile, 32 ) \ - SYSCALL_ENTRY( 0x0190, __wine_send_input, 24 ) + SYSCALL_ENTRY( 0x018e, __wine_get_adapter_driver_data, 24 ) \ + SYSCALL_ENTRY( 0x018f, __wine_get_file_outline_text_metric, 32 ) \ + SYSCALL_ENTRY( 0x0190, __wine_get_icm_profile, 32 ) \ + SYSCALL_ENTRY( 0x0191, __wine_send_input, 24 ) diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 24dccb6ec1d..18c973941e1 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1323,3 +1323,4 @@ @ stdcall -syscall __wine_get_icm_profile(long long ptr ptr) @ stdcall -syscall __wine_get_file_outline_text_metric(wstr ptr ptr ptr) @ stdcall -syscall __wine_send_input(long ptr ptr) +@ stdcall -syscall __wine_get_adapter_driver_data(ptr ptr ptr) diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index ab7f7599659..eba592a585e 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -47,11 +47,6 @@ void wayland_init_display_devices(BOOL force) NtUserGetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &num_path, &num_mode); }
-struct wayland_adapter_data -{ - char output_name[64]; -}; - struct output_info { int x, y; @@ -230,6 +225,10 @@ static void wayland_add_device_adapter(const struct gdi_device_manager *device_m adapter.state_flags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
lstrcpynA(data.output_name, output_info->output->name, sizeof(data.output_name)); + data.scale_width = ((double)output_info->output->current_mode->width) / + output_info->mode->width; + data.scale_height = ((double)output_info->output->current_mode->height) / + output_info->mode->height; adapter.driver_data = &data; adapter.driver_data_len = sizeof(data);
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 0883c43f1ff..48de2fb8c3f 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -215,6 +215,13 @@ struct wayland_shm_buffer HRGN damage_region; };
+struct wayland_adapter_data +{ + char output_name[64]; + /* How much larger the native mode is compared to current mode. */ + double scale_width, scale_height; +}; + /********************************************************************** * Wayland initialization */ diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index ac5da371e5c..ae63b66b83e 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -162,6 +162,8 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, struct wayland_window_config *conf) { enum wayland_surface_config_state window_state = 0; + MONITORINFOEXW mi = {.cbSize = sizeof(mi)}; + HMONITOR hmon; DWORD style;
conf->rect = data->window_rect; @@ -187,6 +189,21 @@ static void wayland_win_data_get_config(struct wayland_win_data *data, conf->scale = NtUserGetDpiForWindow(data->hwnd) / 96.0; conf->visible = (style & WS_VISIBLE) == WS_VISIBLE; conf->managed = data->managed; + + /* Adjust the window scale for the current display mode. */ + if ((hmon = NtUserMonitorFromWindow(data->hwnd, MONITOR_DEFAULTTOPRIMARY)) && + NtUserGetMonitorInfo(hmon, (MONITORINFO *)&mi)) + { + struct wayland_adapter_data adapter_data; + UINT adapter_data_len = sizeof(adapter_data); + UNICODE_STRING dev; + + RtlInitUnicodeString(&dev, mi.szDevice); + __wine_get_adapter_driver_data(&dev, &adapter_data, &adapter_data_len); + + if (adapter_data_len == sizeof(adapter_data)) + conf->scale /= min(adapter_data.scale_width, adapter_data.scale_height); + } }
static void wayland_win_data_update_wayland_surface(struct wayland_win_data *data) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 2dd811578f5..446856eecce 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -4874,3 +4874,9 @@ NTSTATUS WINAPI wow64___wine_send_input( UINT *args ) ERR( "not supported\n" ); return 0; } + +NTSTATUS WINAPI wow64___wine_get_adapter_driver_data( UINT *args ) +{ + ERR( "not supported\n" ); + return 0; +} diff --git a/include/ntuser.h b/include/ntuser.h index 31b93ef36e9..70f46bf14b6 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -1406,5 +1406,6 @@ static inline BOOL NtUserShowOwnedPopups( HWND hwnd, BOOL show )
/* Wine extensions */ W32KAPI BOOL WINAPI __wine_send_input( HWND hwnd, const INPUT *input, const RAWINPUT *rawinput ); +W32KAPI void WINAPI __wine_get_adapter_driver_data( UNICODE_STRING *devname, void *data, UINT *data_len );
#endif /* _NTUSER_ */
From: Alexandros Frantzis alexandros.frantzis@collabora.com
Since a display reconfiguration may affect the compositor side scaling which we apply to a surface, instruct all surfaces to refresh themselves by committing an updated state based on the latest window state. --- dlls/winewayland.drv/display.c | 5 +++++ dlls/winewayland.drv/waylanddrv.h | 1 + dlls/winewayland.drv/window.c | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+)
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c index eba592a585e..3eb60354081 100644 --- a/dlls/winewayland.drv/display.c +++ b/dlls/winewayland.drv/display.c @@ -398,5 +398,10 @@ BOOL WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
pthread_mutex_unlock(&process_wayland.output_mutex);
+ /* Refresh all windows to ensure they have been committed with proper + * scaling applied. */ + if (process_wayland.initialized) + NtUserPostMessage(HWND_BROADCAST, WM_WAYLAND_REFRESH, 0, 0); + return TRUE; } diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h index 48de2fb8c3f..ae423047240 100644 --- a/dlls/winewayland.drv/waylanddrv.h +++ b/dlls/winewayland.drv/waylanddrv.h @@ -62,6 +62,7 @@ enum wayland_window_message WM_WAYLAND_INIT_DISPLAY_DEVICES = WM_WINE_FIRST_DRIVER_MSG, WM_WAYLAND_CONFIGURE, WM_WAYLAND_SET_FOREGROUND, + WM_WAYLAND_REFRESH, };
enum wayland_surface_config_state diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c index ae63b66b83e..6695e3e3830 100644 --- a/dlls/winewayland.drv/window.c +++ b/dlls/winewayland.drv/window.c @@ -631,6 +631,24 @@ static void wayland_configure_window(HWND hwnd) NtUserSetWindowPos(hwnd, 0, 0, 0, window_width, window_height, flags); }
+static void wayland_refresh_window(HWND hwnd) +{ + struct wayland_win_data *data; + + if (!(data = wayland_win_data_get(hwnd))) return; + + if (data->wayland_surface) + { + pthread_mutex_lock(&data->wayland_surface->mutex); + wayland_win_data_get_config(data, &data->wayland_surface->window); + if (wayland_surface_reconfigure(data->wayland_surface)) + wl_surface_commit(data->wayland_surface->wl_surface); + pthread_mutex_unlock(&data->wayland_surface->mutex); + } + + wayland_win_data_release(data); +} + /********************************************************************** * WAYLAND_WindowMessage */ @@ -648,6 +666,9 @@ LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) case WM_WAYLAND_SET_FOREGROUND: NtUserSetForegroundWindow(hwnd); return 0; + case WM_WAYLAND_REFRESH: + wayland_refresh_window(hwnd); + return 0; default: FIXME("got window msg %x hwnd %p wp %lx lp %lx\n", msg, hwnd, (long)wp, lp); return 0;
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/wayland_output.c:
#define WAYLAND_OUTPUT_CHANGED_LOGICAL_XY 0x04 #define WAYLAND_OUTPUT_CHANGED_LOGICAL_WH 0x08
+static const struct { int32_t width; int32_t height; } common_modes[] = {
- { 320, 200}, /* CGA 16:10 */
- { 320, 240}, /* QVGA 4:3 */
- { 400, 300}, /* qSVGA 4:3 */
- { 480, 320}, /* HVGA 3:2 */
- { 512, 384}, /* MAC 4:3 */
- { 640, 360}, /* nHD 16:9 */
- { 640, 400}, /* VESA-0100h 16:10 */
Instead of reporting every possible resolution you should instead make it more like the resolutions Windows reports.
I don't think for instance that modern Windows reports resolution below 640x480 (or maybe even below 800x600), and for the record I believe that it *always* reports 800x600 and 1024x768 (and perhaps 640x480) even if the adapter wouldn't normally on Linux.
Note that Proton fshack also showed that some games don't like having too many resolutions (Spellforce for instance is capped at 16 modes, Nier Automata, Dark Souls 3 and Sekiro are capped at 32 modes), and this list feels quite too long.
Rémi Bernon (@rbernon) commented about dlls/winewayland.drv/wayland_output.c:
if (output->pending_flags & WAYLAND_OUTPUT_CHANGED_MODES) {
RB_FOR_EACH_ENTRY(mode, &output->pending.modes, struct wayland_output_mode, entry)
{
wayland_output_state_add_mode(&output->current,
mode->width, mode->height, mode->refresh,
mode == output->pending.current_mode);
}
rb_destroy(&output->pending.modes, wayland_output_mode_free_rb, NULL);
rb_destroy(&output->current.modes, wayland_output_mode_free_rb, NULL);
You don't really need a rb_tree anymore as you're using a hardcoded and already sorted mode list.
Then I don't like very much commits 8b38be18592fb0538efee64a46e4de9a7321d34b and later, as I feel they are introducing a convoluted driver-specific mechanism for a feature that IMO would be nice to have common. The changes are not so large, *but* still I feel it's not going in the right direction, and having something that works early might make later refactoring more complicated.
What I think instead, though I haven't really explored it, is that this should be built upon, extending and perhaps even superseding, the virtual desktop mode:
- It lives in win32u and is usable by any driver (although for the moment only winex11 still implements the necessary dedicated desktop windows). - It already implements fake modes enumeration over host current modes. - Is already enumerates host gpus / adapters / monitors and should be able to keep a separate list and map the virtual monitors / modes to the hosts ones without an additional callback.
The virtual desktop mode is also currently diverging from how Windows behaves [*], and evolving it to emulate monitors instead could fix that.
I can imagine that instead of emulating desktops displayed separately, we could have a feature that would emulate and virtualize monitors. Eventually displaying some in separate windows, themselves possibly windowed or fullscreen with virtual modesetting. or mapping them to host monitors directly with direct modesetting, or backend scaling or whatever the driver decides to do for best results.
This is of course a much larger feature to implement, and it will require changes in win32u and elsewhere, but IMO it is better and would benefit all drivers.
So my advice here, is to start instead by implementing the necessary things for virtual desktop mode to work with winewayland, which could help users get something usable more quickly (could even perhaps provide a fix for window positioning assuming you would then have more control over them, if they can be made a child of the virtual desktop windows).
[*] https://gitlab.winehq.org/wine/wine/-/merge_requests/4786 for instance shows one of the broken assumption: on Windows all the desktops of the same windowstation expect to have the same adapters and monitors, on Wine with virtual desktop mode this is not true, and additional desktops may see the host monitors instead.
Not sure if entirely related, but can you check my last comment on this ? https://bugs.winehq.org/show_bug.cgi?id=55336
On Wed Jan 31 12:21:14 2024 +0000, Rémi Bernon wrote:
Then I don't like very much commits 8b38be18592fb0538efee64a46e4de9a7321d34b and later, as I feel they are introducing a convoluted driver-specific mechanism for a feature that IMO would be nice to have common. The changes are not so large, *but* still I feel it's not going in the right direction, and having something that works early might make later refactoring more complicated. What I think instead, though I haven't really explored it, is that this should be built upon, extending and perhaps even superseding, the virtual desktop mode:
- It lives in win32u and is usable by any driver (although for the
moment only winex11 still implements the necessary dedicated desktop windows).
- It already implements fake modes enumeration over host current modes.
- Is already enumerates host gpus / adapters / monitors and should be
able to keep a separate list and map the virtual monitors / modes to the hosts ones without an additional callback. The virtual desktop mode is also currently diverging from how Windows behaves [*], and evolving it to emulate monitors instead could fix that. I can imagine that instead of emulating desktops displayed separately, we could have a feature that would emulate and virtualize monitors. Eventually displaying some in separate windows, themselves possibly windowed or fullscreen with virtual modesetting. or mapping them to host monitors directly with direct modesetting, or backend scaling or whatever the driver decides to do for best results. This is of course a much larger feature to implement, and it will require changes in win32u and elsewhere, but IMO it is better and would benefit all drivers. So my advice here, is to start instead by implementing the necessary things for virtual desktop mode to work with winewayland, which could help users get something usable more quickly (could even perhaps provide a fix for window positioning assuming you would then have more control over them, if they can be made a child of the virtual desktop windows). [*] https://gitlab.winehq.org/wine/wine/-/merge_requests/4786 for instance shows one of the broken assumption: on Windows all the desktops of the same windowstation expect to have the same adapters and monitors, on Wine with virtual desktop mode this is not true, and additional desktops may see the host monitors instead.
Thanks for the feedback!
I am trying to imagine, very roughly and at high level, how such a virtualized monitor approach would work:
1. win32u requests the host monitor information (i.e., `UpdateDisplayDevices`) 2. win32u uses the host information and the current virtualized configuration to synthesize the new virtualized configuration, with some extra input from the driver and/or registry options (e.g., to decide the mapping to host monitors or windows). Perhaps we want the driver to have complete control over the final virtualized configuration? 3. win32u notifies all processes of the new virtualized configuration. This includes the mapping to host monitors or windows, and/or we will provide a way to query such information.
A ChangeDisplaySettings call would update the current virtualized configuration internally and notify about the update (i.e., steps (2)-(3)).
Is the above in the direction you are envisioning?
So my advice here, is to start instead by implementing the necessary things for virtual desktop mode to work with winewayland, which could help users get something usable more quickly (could even perhaps provide a fix for window positioning assuming you would then have more control over them, if they can be made a child of the virtual desktop windows).
Unfortunately, implementing a (rooted) virtual desktop mode is not possible with the current set of Wayland protocols. The root/desktop wl_surface would be owned by the desktop process and other processes would not be able to refer to it to establish a wl_subsurface relationship (which is what would allow relative positioning), since all Wayland client objects are per-connection.
Note that there is the xdg-foreign protocol which allows a limited form of cross-process relationships, but only in the xdg_toplevel parent/child sense, so it's inadequate for our needs.
Is the above in the direction you are envisioning?
More or less something like that though I haven't really thought about it a lot. IMO win32u should be the authority and only tell drivers what to do (create/destroy a monitor window, map a monitor window or a portion of the host screen to a given virtual screen area, etc).
Basically moving toward a custom compositing engine, because we'll likely need that at some point (think implementing DirectComposition [1] for instance).
However this is a very long road, and to begin with there's already some issues that need to be solved in winex11 and other drivers. Neither winemac nor winewayland or wineandroid support virtual desktop mode at the moment.
On the other hand, in winex11, the virtual desktop mode is still very strongly rooted in its core, and the driver expects a unique desktop window per process (the `root_window`), using it pretty much everywhere.
Drivers also probably expect a unique host surface per HWND, which would also need to be broken up somehow, as the desktop window would then need to span over multiple monitors.
[1] https://learn.microsoft.com/en-us/windows/win32/directcomp/directcomposition...
Unfortunately, implementing a (rooted) virtual desktop mode is not possible with the current set of Wayland protocols.
Ugh. Didn't I read somewhere that you had some plan to implement some kind of cross-process rendering? How would that even work then?
Ugh. Didn't I read somewhere that you had some plan to implement some kind of cross-process rendering? How would that even work then?
That cross-process rendering refers only to one process providing the (complete) contents to a window (and backing wl_surface) owned by another process, but doesn't involve interacting with the wl_surface in any other manner. Although that's also not directly possible in Wayland, it's not extremely hard to export and send the rendered buffer to any other process/hwnd for presentation, which then attaches it and commits it on the corresponding wl_surface. The experimental branch achieved this by using driver window messages (I am skipping a lot of details, but that's the basic idea).
In the virtual desktop case the straightforward way to implement this would be to create relationships between wl_surfaces belonging to different process but Wayland doesn't support that at the moment.
Thinking aloud: If we really, really wanted to get this working, the desktop process would need to create and manage wl_surfaces for all the windows (handling both input and output). The other processes would have to render off-screen and then send the buffers to the desktop process for presentation. The desktop process would also need to forward Wayland events to the other processes for handling. We would be trying to meld the multiple processes into one. So, I guess me saying "is not possible" was not entirely accurate, but I think the complexity of such a solution is extreme enough to effectively make it "not possible". But perhaps there is workable approach that escapes me?
Thinking aloud: If we really, really wanted to get this working, the desktop process would need to create and manage wl_surfaces for all the windows (handling both input and output). The other processes would have to render off-screen and then send the buffers to the desktop process for presentation.
This is pretty much what I expect we would need to achieve at some point, if we want things like DirectComposition, and cross process rendering like applications can do on Windows. Though ideally we would want to keep a fast and direct path for the most common case where applications are simply drawing their surfaces.
That would also depend on the backend capabilities, and I think it's not much of an issue with X11 as you can just create children surfaces of another process window if you like. Then if Wayland doesn't allow that it would have to use the indirect path all the time.
The desktop process would also need to forward Wayland events to the other processes for handling. We would be trying to meld the multiple processes into one.
I'm not sure to understand that very well, the idea is more to move the boundaries of the Windows world a little bit further and have a dedicated compositor which would be the interface with the host instead of every single process. I'm not sure why host events would have to be forwarded at all with this architecture.
So, I guess me saying "is not possible" was not entirely accurate, but I think the complexity of such a solution is extreme enough to effectively make it "not possible". But perhaps there is workable approach that escapes me?
Well... like I said, this is a long road. Doesn't look much more impossible than what we usually do :sweat_smile:.
On Wed Jan 31 17:16:52 2024 +0000, Rémi Bernon wrote:
Thinking aloud: If we really, really wanted to get this working, the
desktop process would need to create and manage wl_surfaces for all the windows (handling both input and output). The other processes would have to render off-screen and then send the buffers to the desktop process for presentation. This is pretty much what I expect we would need to achieve at some point, if we want things like DirectComposition, and cross process rendering like applications can do on Windows. Though ideally we would want to keep a fast and direct path for the most common case where applications are simply drawing their surfaces. That would also depend on the backend capabilities, and I think it's not much of an issue with X11 as you can just create children surfaces of another process window if you like. Then if Wayland doesn't allow that it would have to use the indirect path all the time.
The desktop process would also need to forward Wayland events to the
other processes for handling. We would be trying to meld the multiple processes into one. I'm not sure to understand that very well, the idea is more to move the boundaries of the Windows world a little bit further and have a dedicated compositor which would be the interface with the host instead of every single process. I'm not sure why host events would have to be forwarded at all with this architecture.
So, I guess me saying "is not possible" was not entirely accurate, but
I think the complexity of such a solution is extreme enough to effectively make it "not possible". But perhaps there is workable approach that escapes me? Well... like I said, this is a long road. Doesn't look much more impossible than what we usually do :sweat_smile:.
With that said, it may be possible to find some early steps in that direction, that would also fit your needs for winewayland.
For instance, enabling the virtual desktop mode by default (even though you don't and can't have a root window for the moment), would let you use its display mode emulation.
Then extending the virtual desktop host modes enumeration to expose host gpus and adapters, implement virtual to host monitor mapping, etc, while keeping it working for drivers that are yet incapable of having more than one virtual monitor.
I'm not sure why host events would have to be forwarded at all with this architecture.
I am thinking that the process that owns the wl_surface (the desktop process in the design described above) is the one that receives all input and must handle all output for it and all this involves some per-process state. So, either the desktop process handles all that state, making the processes owning the HWND much leaner, or we somehow forward that state to the HWND process to handle (BTW, this seems quite painful, would not recommend).
Of course, there is the ideal scenario in which Wayland gains a protocol for (securely) implementing cross-process subsurfaces and presentation. From what I can tell, such a feature wouldn't go against basic Wayland philosophy (as long as it's secure, so no arbitrary access to foreign surfaces), so I don't expect it to be blocked on such grounds, but I expect there will be difficult technical/semantic considerations to resolve.
For DirectComposition would the idea be that the host system handles the composition completely (through host child surfaces), or do you expect that Wine would also grow a full-fledged compositor (performing full input handling at the "root" level, compositing to a final surface that is the handed to the host etc)?
With that said, it may be possible to find some early steps in that direction, that would also fit your needs for winewayland. ...
Ack. This sounds like a reasonable way to proceed, I will start exploring this avenue. There are several unknowns at this point for me (esp. in terms of how we would like this to evolve going forward), so I expect this will take a few iterations until we reach a solution that we like, but I am hopeful :)
I am thinking that the process that owns the wl_surface (the desktop process in the design described above) is the one that receives all input and must handle all output for it and all this involves some per-process state. So, either the desktop process handles all that state, making the processes owning the HWND much leaner, or we somehow forward that state to the HWND process to handle (BTW, this seems quite painful, would not recommend).
In any case, Wine has to dispatch input sometimes differently from where it is received from the host point of view. We use the host window mostly as a hint, and I think we try to not send input to another window unless necessary but in the end it doesn't make much different which window really received it, and the receiver -if that's a dedicated process- could simply hint wineserver about the target HWND.
For DirectComposition would the idea be that the host system handles the composition completely (through host child surfaces), or do you expect that Wine would also grow a full-fledged compositor (performing full input handling at the "root" level, compositing to a final surface that is the handed to the host etc)?
I don't really know what it would involve. I hope that we can always keep a fast path where a process can render and present its client surface directly.
On Thu Feb 1 09:24:02 2024 +0000, Rémi Bernon wrote:
I am thinking that the process that owns the wl_surface (the desktop
process in the design described above) is the one that receives all input and must handle all output for it and all this involves some per-process state. So, either the desktop process handles all that state, making the processes owning the HWND much leaner, or we somehow forward that state to the HWND process to handle (BTW, this seems quite painful, would not recommend). In any case, Wine has to dispatch input sometimes differently from where it is received from the host point of view. We use the host window mostly as a hint, and I think we try to not send input to another window unless necessary but in the end it doesn't make much different which window really received it, and the receiver -if that's a dedicated process- could simply hint wineserver about the target HWND.
For DirectComposition would the idea be that the host system handles
the composition completely (through host child surfaces), or do you expect that Wine would also grow a full-fledged compositor (performing full input handling at the "root" level, compositing to a final surface that is the handed to the host etc)? I don't really know what it would involve. I hope that we can always keep a fast path where a process can render and present its client surface directly.
I’m not as familiar with X11, Wayland, DWM, or Wine as either of you but it sounds like what’s being described is something similar to XWayland but with four back-ends: X11, Wayland, Android, macOS.
XWayland is obviously a complicated effort all by itself and that’s _just_ a backwards compatibility layer for running X11 clients on Wayland. That’s despite the fact that XWayland has the advantage of having some integration with the host Wayland compositor. I can only imagine how much more complicated it would be to come up a common front-end for a DWM compatibility layer that connects two (to four) backends that use very dissimilar protocols ans can work as a normal Wayland client.
Obviously that doesn’t mean a common frontend shouldn’t be pursued. I’m just wondering if it’s maybe too early in the development of winewayland to try to find commonalities between it and winex11. Considering that the virtual desktop mode only works on winex11 right now and its possible future as a multi-back-end nested compositor is only in the idea phases, maybe some “convoluted driver specific mechanisms” (CDSM) should be allowed for now so that all the intricate little problems of adapting DWM to Wayland can be better understood first. From there, the process of creating a common front-end might be easier to figure out. As you said about this specific CDSM, the changes aren’t that large anyway so it’s not like it’s adding a bunch of code that’s going to be difficult to work around, change, or remove later on.
About the idea of one virtual monitor for each real monitor, here’s what I can imagine would happen if an application tries to change the display resolution:
**X11**
The Wine app changes the actual display’s resolution. All applications on that monitor, Wine or native, will run at that resolution. If the app doesn’t change the resolution back, the user can set it back with their display settings. There's no real difference from how it works now except that Wine would also have to keep the virtual monitor resolutions in sync with the real monitors.
**Wayland with winewayland**
The Wine app only changes the virtual monitor’s resolution. Due to the mismatch between virtual and physical monitor resolutions, Wine apps on that monitor would think they’re working at a different screen resolution than native apps and probably be scaled up to emulate the mode change. If the app doesn’t change the virtual resolution back, the user would need to use a Windows app to set it back since winewayland wouldn't be synced with the display resolution anyway.
**Wayland with winex11**
The wine compositor would be running within XWayland. Winex11 would try to change the virtual resolution and make a request from XWayland to change the display resolution. XWayland can’t change the display resolution so it does whatever it does to safely ignore that request. Right now if you change resolution with winex11 in XWayland, nothing happens. There’s no scaling or anything, it’s just as if the button doesn’t work. I’m not sure how that would change if virtual monitors and another nested compositor get introduced though. It may actually end up with a worse result, assuming you'd want to support use under XWayland at all at that point.
On Fri Feb 2 04:53:23 2024 +0000, myownfriend wrote:
I’m not as familiar with X11, Wayland, DWM, or Wine as either of you but it sounds like what’s being described is something similar to XWayland but with four back-ends: X11, Wayland, Android, macOS. XWayland is obviously a complicated effort all by itself and that’s _just_ a backwards compatibility layer for running X11 clients on Wayland. That’s despite the fact that XWayland has the advantage of having some integration with the host Wayland compositor. I can only imagine how much more complicated it would be to come up a common front-end for a DWM compatibility layer that connects two (to four) backends that use very dissimilar protocols ans can work as a normal Wayland client. Obviously that doesn’t mean a common frontend shouldn’t be pursued. I’m just wondering if it’s maybe too early in the development of winewayland to try to find commonalities between it and winex11. Considering that the virtual desktop mode only works on winex11 right now and its possible future as a multi-back-end nested compositor is only in the idea phases, maybe some “convoluted driver specific mechanisms” (CDSM) should be allowed for now so that all the intricate little problems of adapting DWM to Wayland can be better understood first. From there, the process of creating a common front-end might be easier to figure out. As you said about this specific CDSM, the changes aren’t that large anyway so it’s not like it’s adding a bunch of code that’s going to be difficult to work around, change, or remove later on. About the idea of one virtual monitor for each real monitor, here’s what I can imagine would happen if an application tries to change the display resolution: **X11** The Wine app changes the actual display’s resolution. All applications on that monitor, Wine or native, will run at that resolution. If the app doesn’t change the resolution back, the user can set it back with their display settings. There's no real difference from how it works now except that Wine would also have to keep the virtual monitor resolutions in sync with the real monitors. **Wayland with winewayland** The Wine app only changes the virtual monitor’s resolution. Due to the mismatch between virtual and physical monitor resolutions, Wine apps on that monitor would think they’re working at a different screen resolution than native apps and probably be scaled up to emulate the mode change. If the app doesn’t change the virtual resolution back, the user would need to use a Windows app to set it back since winewayland wouldn't be synced with the display resolution anyway. **Wayland with winex11** The wine compositor would be running within XWayland. Winex11 would try to change the virtual resolution and make a request from XWayland to change the display resolution. XWayland can’t change the display resolution so it does whatever it does to safely ignore that request. Right now if you change resolution with winex11 in XWayland, nothing happens. There’s no scaling or anything, it’s just as if the button doesn’t work. I’m not sure how that would change if virtual monitors and another nested compositor get introduced though. It may actually end up with a worse result, assuming you'd want to support use under XWayland at all at that point.
Well, just to make it clear I only gave my view of how this should be going, it's always possible that someone else feels differently and feels like reviewing this and approve as it is. Alexandre will in the end also decides what he feels would be best.
Then my opinion is based on the time I spent moving virtualized display modes *out* of winex11, in the hope that other drivers could build upon it, and as it's been merged I can only assume Alexandre thought the same. Adding back virtualized modes in a different driver simply feels like going backwards that's all.
On Fri Feb 2 06:05:41 2024 +0000, Rémi Bernon wrote:
Well, just to make it clear I only gave my view of how this should be going, it's always possible that someone else feels differently and feels like reviewing this and approve as it is. Alexandre will in the end also decides what he feels would be best. Then my opinion is based on the time I spent moving virtualized display modes *out* of winex11, in the hope that other drivers could build upon it, and as it's been merged I can only assume Alexandre thought the same. Adding back virtualized modes in a different driver simply feels like going backwards that's all.
I mean, if XWayland can't do it, I don't see why Wine's driver has to, considering it's even less integrated and just a "normal" app to the compositor unlike XWayland.
Ultimately, whether we do this in the DWM (wine's "compositor") layer or driver layer still means we have to basically implement compositing ourselves since we can't rely on *the actual compositor* to do it. Fun.
Maybe if we have generic impl upstream we can finally drop the fullscreen hack from Proton and have one less thing to worry about, considering it's been a source of rebase bugs. If we allow VDs to scale, that is. Unless I'm misunderstanding how it's supposed to work…?
Then my opinion is based on the time I spent moving virtualized display modes *out* of winex11, in the hope that other drivers could build upon it, and as it's been merged I can only assume Alexandre thought the same. Adding back virtualized modes in a different driver simply feels like going backwards that's all.
Oh I agree in the aspect that code for virtualized modes should be shared by drivers as much as possible. Obviously the easiest stuff to share would be a list of display modes as is evident by this MR and sysparams having similar lists. I was under the impression that you were suggesting that this whole MR is a CDSM. That's my fault because you did specify that it was only from commits 8b38be18 and later.
I'm still pretty confused as to what's being proposed with this compositor idea though. I was initially under the impression that it would somehow work like a rootless XWayland. That felt like it would be un-managable to do in a way that supports four backends without becoming very messy. Upon re-reading everything, it sounds like you're suggesting that the future VDM would still create a monitor in a window but it can more than one monitor and each can be full-screened. Is that right? You guys are talking about supporting the current virtual desktop mode on top of winewayland while discussing what the future one could work like and I think I'm just getting the conversations crossed.
If you ARE talking about something that works like the current one but expanded to allow multiple monitors and scaling then I feel like implementing the current VDM onto other drivers would be a waste of time because the implementation for each back-end would be highly dependent on the back-end work. For example, my understanding is that, like Wayland, macOS also can't have applications within another application window so Wayland isn't the odd one out there.
I personally feel like implementing VDM as a full-on nested compositor would really be the only correct way to do it for two big reasons. The first is that, it could potentially run as the host compositor, a Wayland client, an X11 client, etc. with a vast majority of it's code being back-end agnostic. The second is that it would also be able to use any protocol it wants so it could just use a custom protocol that understands WDM natively to maximize compatibility. It wouldn't be of any obvious benefit outside of VDM besides sharing some virtual monitor state stuff, but I feel like the level of compatibility it would provide and the ways that it could run would make it far more useful and interesting.
Obviously like you said you'd want a fast path where the host compositor handles the composition, and that's what I'd prefer most of the time, but I feel that's always gonna be a very separate, driver-specific path. I feel like the goal outside of VDM (lets call it host mode or HM) should be to make Wine apps feel as much like native apps as possible and not always expect maximum compatibility. Wayland is still in active development so while it may never be ideal to translate WDM to, it's going to get new protocols which will likely make things a little more compatible over time. In the meantime Windows applications might get forced to work a little more like Wayland apps but that might not always be a bad thing.
I'm thinking of it kind of like video game console emulators. They generally have an interpreter which is slow but very compatible and portable. When they bring the emulator to a new platform, this is always the first thing they get running. That's VDM. Then they have their fast back-ends, the dynamic re-compilers that are very quick but are less likely to be completely accurate and require separate backends for each host architecture. That's each HM driver.
Of course like I said, I don't know anywhere near as much about this stuff as you guys do so feel free to tell me if what I'm saying is dumb or misinformed. I won't take offense. I just wanted to chime in lol
Hey, I found a few issues when using [Pocket Mirror](https://astralshiftpro.itch.io/pocket-mirror-classic)
First, it scales the window when using the KDE Display Scale, I don't think X11 Wine was ever affected by KDE scaling. Is that intentional?
Second, it causes massive flickering when pressing ALT-Enter to go fullscreen. When having KDE Display scaling, then it cuts off part of the game, which definetly shouldn't happen. Not sure what exactly is going wrong here, but would you mind taking a look?
Two short videos showing the issues:
![scaled](/uploads/95c9495f7acffe5c941a60eb7b6a6285/scaled.mp4)
![unscaled](/uploads/1e8c6378d02110c5f2ea0f86ce91c8be/unscaled.mp4)
I'm running Arch Linux, with KDE Plasma.
On Tue Feb 6 00:07:24 2024 +0000, Fabian Maurer wrote:
Hey, I found a few issues when using [Pocket Mirror](https://astralshiftpro.itch.io/pocket-mirror-classic) First, it scales the window when using the KDE Display Scale, I don't think X11 Wine was ever affected by KDE scaling. Is that intentional? Second, it causes massive flickering when pressing ALT-Enter to go fullscreen. When having KDE Display scaling, then it cuts off part of the game, which definetly shouldn't happen. Not sure what exactly is going wrong here, but would you mind taking a look? Two short videos showing the issues: ![scaled](/uploads/95c9495f7acffe5c941a60eb7b6a6285/scaled.mp4) ![unscaled](/uploads/1e8c6378d02110c5f2ea0f86ce91c8be/unscaled.mp4) I'm running Arch Linux, with KDE Plasma.
How did it act before this patch? Alexandros mentioned that some compositors don't properly follow the Wayland spec and scale, center, and add bars to full-screen Wayland surfaces that don't match the screen's aspect ratio. [According to a comment I saw in the code for SDL3](https://github.com/libsdl-org/SDL/blob/c1f97c8e07d4ea4c1c2e86ae1f9749b3c2a73...), KDE is one of the compositors.
On Tue Feb 6 00:07:24 2024 +0000, myownfriend wrote:
How did it act before this patch? Alexandros mentioned that some compositors don't properly follow the Wayland spec and scale, center, and add bars to full-screen Wayland surfaces that don't match the screen's aspect ratio. [According to a comment I saw in the code for SDL3](https://github.com/libsdl-org/SDL/blob/c1f97c8e07d4ea4c1c2e86ae1f9749b3c2a73...), KDE is one of the compositors.
@DarkShadow44 This MR has nothing to do with your problem! I run about 10 games with this MR, including Steam games, and there are no problems in full screen mode. The whole reason is that you have a floating window and not a full screen one. At the moment, the wayland driver only works correctly in full screen mode. There is no support for floating windows!
On Tue Feb 6 04:57:08 2024 +0000, Grigory Vasilyev wrote:
@DarkShadow44 This MR has nothing to do with your problem! I run about 10 games with this MR, including Steam games, and there are no problems in full screen mode. The whole reason is that you have a floating window and not a full screen one. At the moment, the wayland driver only works correctly in full screen mode. There is no support for floating windows!
It's scaled by the KDE display scale before the patch as well. Alt-enter simply prints an error `0024:err:system:NtUserChangeDisplaySettings Changing L"\\.\DISPLAY1" display settings returned -2.`
This MR has nothing to do with your problem! I run about 10 games with this MR, including Steam games, and there are no problems in full screen mode.
Just because a bunch of programs work, doesn't mean this one will as well... This MR adds fullscreen scaling, and it doesn't work for this program. Or does the game I linked works for you without issues?
Not sure what you mean by floating window, of course it's just a window before I press alt-enter to make it go fullscreen?
On Tue Feb 6 18:15:14 2024 +0000, Fabian Maurer wrote:
It's scaled by the KDE display scale before the patch as well. Alt-enter simply prints an error `0024:err:system:NtUserChangeDisplaySettings Changing L"\\.\DISPLAY1" display settings returned -2.`
This MR has nothing to do with your problem! I run about 10 games with
this MR, including Steam games, and there are no problems in full screen mode. Just because a bunch of programs work, doesn't mean this one will as well... This MR adds fullscreen scaling, and it doesn't work for this program. Or does the game I linked works for you without issues? Not sure what you mean by floating window, of course it's just a window before I press alt-enter to make it go fullscreen?
@DarkShadow44 In order for some aspects of window presentation (esp. fullscreen) to work properly in scaled outputs, the wine dpi settings (change in winecfg) must match the scaling factor of the output (e.g., 2x => 2 * 96 = 192 dpi). That should help with contents being cut off in scaled outputs.
Concerning the flickering, it would help to see a log with: `WAYLAND_DEBUG=1 WINEDEBUG=+pid,+tid,+timestamp,+waylanddrv,+system,+win,+vulkan`. Are you able to try with another compositor, e.g., GNOME/mutter, to check if you get the same behavior?
Alt-enter simply prints an error `0024:err:system:NtUserChangeDisplaySettings Changing L"\\.\DISPLAY1" display settings returned -2.`
Is this error printed only without this patch?
In order for some aspects of window presentation (esp. fullscreen) to work properly in scaled outputs, the wine dpi settings (change in winecfg) must match the scaling factor of the output (e.g., 2x => 2 * 96 = 192 dpi). That should help with contents being cut off in scaled outputs.
Ah, thanks. It doesn't clip with 144dpi, although it's a bit counter intuitive that the window gets smaller when I increase the DPI - everything else gets bigger.
Concerning the flickering, it would help to see a log with: `WAYLAND_DEBUG=1 WINEDEBUG=+pid,+tid,+timestamp,+waylanddrv,+system,+win,+vulkan`. Are you able to try with another compositor, e.g., GNOME/mutter, to check if you get the same behavior?
Please see [flickering-log.zip](/uploads/807bc2b1b11f055f6abc0d02c07a6bcf/flickering-log.zip) The flickering is also present on Gnome.
Is this error printed only without this patch?
Yeah, only without this patch.
Ehrm... after having had a brief [exchange](https://gitlab.freedesktop.org/mesa/mesa/-/issues/11359#note_2479687) with stefan I'd like to interject for a moment if you will.
I can see why "modern design" would want everything composited and nothing really in control of the hardware.. but I can still totally see use cases for the opposite too (on top of the fact I'm not sure how nutty reinventing yet another wheel may be for you)
Wayland itself (just like with tearing and fullscreen unredirect) is backtracking from its far too smoothed ideals, and both [color](https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/14) and [mode](https://gitlab.freedesktop.org/wayland/weston/-/issues/866) controls are actually on the table.
Need for Speed Underground relies on all of its hardcoded 4:3 display modes (640x480, 800x600, 1024x768 and 1280x960) being present for the output (and segfaults if the particular mode the game wants to select isn't present) and also depends on being able to enter fullscreen with them in the unmodified game (I have a mod installed that allows the game to run in windowed mode which removes that part)
So this MR (in some form or another) will definitely be helpful to make that game work without crashing :frog:
Hey, I would love to have wayland as the default in wine, I remember when the first PR for Wayland was made, @afrantzis did a great Job and made many PRs to extend Wayland support. But latly i have the feeling Wayland development really slowed down, Why?.
On Mon Oct 14 16:24:43 2024 +0000, Snowiiii wrote:
Hey, I would love to have wayland as the default in wine, I remember when the first PR for Wayland was made, @afrantzis did a great Job and made many PRs to extend Wayland support. But latly i have the feeling Wayland development really slowed down, Why?.
There's still been work done on the winewayland backend outside of this series of patches, just not neatly labeled "part 13, 14..." etc.
On Mon Oct 14 16:24:43 2024 +0000, llyyr wrote:
There's still been work done on the winewayland backend outside of this series of patches, just not neatly labeled "part 13, 14..." etc.
To be a bit more on topic, what is the state of the display mode emulation currently? Is it actually close to working or something is still missing for it in the wayland driver?
On Mon Oct 14 16:26:22 2024 +0000, Shmerl wrote:
To be a bit more on topic, what is the state of the display mode emulation currently? Is it actually close to working or something is still missing for it in the wayland driver?
It's still missing support for mapping coordinates to/from virtualized screen rectangles. This needs to be done in a way that works with all the backends and I'm working on winex11 to make it possible.
It's not too far from working, but I'm also using the opportunity to refactor and cleanup some old code (for instance drag'n'drop, which will be useful for winewayland anyway), so it takes time.
On Mon Oct 14 16:39:22 2024 +0000, Rémi Bernon wrote:
It's still missing support for mapping coordinates to/from virtualized screen rectangles. This needs to be done in a way that works with all the backends and I'm working on winex11 to make it possible. It's not too far from working, but I'm also using the opportunity to refactor and cleanup some old code (for instance drag'n'drop, which will be useful for winewayland anyway), so it takes time.
Thanks for the update and working on it!
On Mon Oct 14 16:41:41 2024 +0000, Shmerl wrote:
Thanks for the update and working on it!
Btw, is clipboard support in winewayland dependent on that refactor too or it's something separate?
On Sun Oct 20 04:53:55 2024 +0000, Shmerl wrote:
Btw, is clipboard support in winewayland dependent on that refactor too or it's something separate?
It's only dependent in a way that we would prefer not to duplicate the driver code but other than that I don't have any plan to implement it myself.
On Sun Oct 20 08:24:47 2024 +0000, Rémi Bernon wrote:
It's only dependent in a way that we would prefer not to duplicate the driver code but other than that I don't have any plan to implement it myself.
I see, thanks. @afrantzis: Do you plan to update / upstream your not yet upstreamed clipboard support after these refactors are complete?
On Sun Oct 27 19:57:39 2024 +0000, Shmerl wrote:
I see, thanks. @afrantzis: Do you plan to update / upstream your not yet upstreamed clipboard support after these refactors are complete?
Hi!
@shmerl Yes, that's my plan/hope.
@rbernon Do you think it makes sense for me to start doing some preparatory work or is the driver interface still expected to change significantly? Are there significant refactorings also planned for copy/paste?
On Tue Oct 29 07:57:49 2024 +0000, Alexandros Frantzis wrote:
Hi! @shmerl Yes, that's my plan/hope. @rbernon Do you think it makes sense for me to start doing some preparatory work or is the driver interface still expected to change significantly? Are there significant refactorings also planned for copy/paste?
I'm pretty much done with DND, and don't have any plan for copy paste changes, though I haven't really looked at it. Maybe it would benefit from factoring things in win32u as well but that could be part of your changes if you feel like it.
After reading through the discussion, it occurs to me that a wine driver could be written to connect directly to the Xwayland socket and act like Xorg and reuse all the Xwayland infrastructure. There was a reason the Xorg approach was used, and Wine faces many of the same complications which led down that path. It would also simplify rootless and rootful operation.
On Mon Nov 18 17:16:27 2024 +0000, Steven Newbury wrote:
After reading through the discussion, it occurs to me that a wine driver could be written to connect directly to the Xwayland socket and act like Xorg and reuse all the Xwayland infrastructure. There was a reason the Xorg approach was used, and Wine faces many of the same complications which led down that path. It would also simplify rootless and rootful operation.
This would introduce a hard dependency on xwayland of which is not guaranteed on wayland desktops. It's very common, but not ubiquitous
This merge request was closed by Rémi Bernon.
I think this is implemented now with the wayland driver, so closing this.
On Tue Oct 29 08:39:13 2024 +0000, Rémi Bernon wrote:
I'm pretty much done with DND, and don't have any plan for copy paste changes, though I haven't really looked at it. Maybe it would benefit from factoring things in win32u as well but that could be part of your changes if you feel like it.
@afrantzis Maybe you can't tell because of NDA, but it would be interesting to know: In your [XDC 2023 presentation](https://indico.freedesktop.org/event/4/contributions/199/attachments/145/207...) you thanked Google, so I guess you were sponsored by them to work on the Wine Wayland driver to be used in ChromeOS. Now that Google seems to move [ChromeOS to Android](https://www.androidauthority.com/chrome-os-becoming-android-3500661/), could it be that they lost interest in Wine Wayland?
I'm going to test some older games, but one question, is it supposed to work with wined3d running over OpenGL? I'm trying Vampire: The Masquerade Redeption that uses some low resolution videos, but it simply fails to start in Wayland mode (the game is using directdraw / dx7 so can't go through Vulkan).
It fails like this:
``` 011c:err:winediag:nodrv_CreateWindow Application tried to create a window, but no driver could be loaded. 011c:err:winediag:nodrv_CreateWindow L"The explorer process failed to start." ```
It does work in xwayland / winex11 mode. If it's something unexpected, I can open a bug.
OK, my problem was unrelated (bad mangohud GL hooks), but now that it works, it still has an issue with setting resolutions in latest Wine version. I'll open a bug.