From a0f738a67327ca1315bacdf543c28cc3046989dc Mon Sep 17 00:00:00 2001 From: brian Date: Thu, 2 May 2019 16:25:50 -0500 Subject: [PATCH 01/38] Fixed ioperm calls in hwEnableIO --- hw/xfree86/os-support/linux/lnx_video.c | 32 ++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/hw/xfree86/os-support/linux/lnx_video.c b/hw/xfree86/os-support/linux/lnx_video.c index 04e45092a..a24fce37b 100644 --- a/hw/xfree86/os-support/linux/lnx_video.c +++ b/hw/xfree86/os-support/linux/lnx_video.c @@ -116,16 +116,36 @@ hwDisableIO(void) static Bool hwEnableIO(void) { - if (ioperm(0, 1024, 1) || iopl(3)) { - ErrorF("xf86EnableIOPorts: failed to set IOPL for I/O (%s)\n", + short i; + size_t n=0; + int begin, end; + char *buf=NULL, target[4]; + FILE *fp; + + if (ioperm(0, 1024, 1)) { + ErrorF("xf86EnableIO: failed to enable I/O ports 0000-03ff (%s)\n", strerror(errno)); return FALSE; } + #if !defined(__alpha__) - /* XXX: this is actually not trapping anything because of iopl(3) - * above */ - ioperm(0x40, 4, 0); /* trap access to the timer chip */ - ioperm(0x60, 4, 0); /* trap access to the keyboard controller */ + /* trap access to the keyboard controller(s) and timer chip(s) */ + fp = fopen("/proc/ioports", "r"); + while (getline(&buf, &n, fp) != -1) { + if ((strstr(buf, "keyboard") != NULL) || (strstr(buf, "timer") != NULL)) { + for (i=0; i<4; i++) + target[i] = buf[i+2]; + begin = atoi(target); + + for (i=0; i<4; i++) + target[i] = buf[i+7]; + end = atoi(target); + + ioperm(begin, end-begin+1, 0); + } + } + free(buf); + fclose(fp); #endif return TRUE; From 2aec5c3c812ffe4a85b5e62452b244819a812dd6 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 14 May 2019 12:39:23 -0400 Subject: [PATCH 02/38] glx: Fix potential crashes in glXWait{GL,X} glxc->drawPriv will be NULL if the context is direct, or if it is current but without a bound drawable. Mesa's libGL won't normally emit protocol for direct contexts for these calls, but a malign client could still crash the server. --- glx/glxcmds.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/glx/glxcmds.c b/glx/glxcmds.c index 54d452e58..6af050940 100644 --- a/glx/glxcmds.c +++ b/glx/glxcmds.c @@ -765,7 +765,7 @@ __glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc) glFinish(); } - if (glxc && glxc->drawPriv->waitGL) + if (glxc && glxc->drawPriv && glxc->drawPriv->waitGL) (*glxc->drawPriv->waitGL) (glxc->drawPriv); return Success; @@ -789,7 +789,7 @@ __glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc) return error; } - if (glxc && glxc->drawPriv->waitX) + if (glxc && glxc->drawPriv && glxc->drawPriv->waitX) (*glxc->drawPriv->waitX) (glxc->drawPriv); return Success; From 37a36a6b5b887d5c5a17a6931ceba8ad5d1bb6d5 Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Thu, 19 Oct 2017 15:14:51 -0600 Subject: [PATCH 03/38] GLX: Add a per-client vendor mapping. Each client now has its own (screen, vendor) mapping. Currently, it's just a copy of the global mapping, but later changes will allow it to change. Signed-off-by: Aaron Plattner Reviewed-by: Aaron Plattner Reviewed-by: Adam Jackson --- glx/vndext.c | 11 ++++++++++- glx/vndserver.h | 5 +++++ glx/vndservermapping.c | 19 +++++++++++++++---- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/glx/vndext.c b/glx/vndext.c index d7936467b..20c0648cc 100644 --- a/glx/vndext.c +++ b/glx/vndext.c @@ -139,8 +139,17 @@ GlxGetClientData(ClientPtr client) { GlxClientPriv *cl = xglvGetClientPrivate(client); if (cl == NULL) { - cl = calloc(1, sizeof(GlxClientPriv)); + cl = calloc(1, sizeof(GlxClientPriv) + + screenInfo.numScreens * sizeof(GlxServerVendor *)); if (cl != NULL) { + int i; + + cl->vendors = (GlxServerVendor **) (cl + 1); + for (i=0; ivendors[i] = GlxGetVendorForScreen(NULL, screenInfo.screens[i]); + } + xglvSetClientPrivate(client, cl); } } diff --git a/glx/vndserver.h b/glx/vndserver.h index a175656ae..78246d212 100644 --- a/glx/vndserver.h +++ b/glx/vndserver.h @@ -57,6 +57,11 @@ typedef struct GlxContextTagInfoRec { typedef struct GlxClientPrivRec { GlxContextTagInfo *contextTags; unsigned int contextTagCount; + + /** + * The vendor handles for each screen. + */ + GlxServerVendor **vendors; } GlxClientPriv; extern int GlxErrorBase; diff --git a/glx/vndservermapping.c b/glx/vndservermapping.c index fd3be92d9..778656bb6 100644 --- a/glx/vndservermapping.c +++ b/glx/vndservermapping.c @@ -187,10 +187,21 @@ Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor) GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen) { - GlxScreenPriv *priv = GlxGetScreen(screen); - if (priv != NULL) { - return priv->vendor; + // Note that the client won't be sending GPU screen numbers, so we don't + // need per-client mappings for them. + if (client != NULL && !screen->isGPU) { + GlxClientPriv *cl = GlxGetClientData(client); + if (cl != NULL) { + return cl->vendors[screen->myNum]; + } else { + return NULL; + } } else { - return NULL; + GlxScreenPriv *priv = GlxGetScreen(screen); + if (priv != NULL) { + return priv->vendor; + } else { + return NULL; + } } } From 8b67ec7cc6fda243480a5a8ca118b66242f3eb2c Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Wed, 8 May 2019 08:44:54 -0600 Subject: [PATCH 04/38] GLX: Use the sending client for looking up XID's When GlxGetXIDMap looks up an unknown XID, it will now look up a vendor based on the screen number for the XID and the client that sent the current request. In GlxGetXIDMap, if the XID is for a regular X window, then it won't be in the (XID -> vendor) mapping, so we have to look up a vendor by screen number. With this change, GlxGetXIDMap will use the (screen -> vendor) map for whichever client sent the current request, instead of using the global (screen -> vendor) map. Since GlxGetXIDMap doesn't take a ClientPtr argument, GlxDispatchRequest will store the client for the current request in a global variable. That way, the ABI for GLXVND doesn't need to change. v2: Fix an error check in GlxDispatchRequest. Signed-off-by: Aaron Plattner Reviewed-by: Aaron Plattner Reviewed-by: Adam Jackson --- glx/vndcmds.c | 13 +++++++++++-- glx/vndserver.h | 7 +++++++ glx/vndservermapping.c | 12 ++++++++---- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/glx/vndcmds.c b/glx/vndcmds.c index f0779d14a..21c6fef9e 100644 --- a/glx/vndcmds.c +++ b/glx/vndcmds.c @@ -468,15 +468,24 @@ void GlxDispatchReset(void) int GlxDispatchRequest(ClientPtr client) { REQUEST(xReq); + int result; + if (GlxExtensionEntry->base == 0) return BadRequest; + + GlxSetRequestClient(client); + if (stuff->data < OPCODE_ARRAY_LEN) { if (dispatchFuncs[stuff->data] == NULL) { // Try to find a dispatch stub. dispatchFuncs[stuff->data] = GetVendorDispatchFunc(stuff->data, 0); } - return dispatchFuncs[stuff->data](client); + result = dispatchFuncs[stuff->data](client); } else { - return dispatch_GLXSingle(client); + result = dispatch_GLXSingle(client); } + + GlxSetRequestClient(NULL); + + return result; } diff --git a/glx/vndserver.h b/glx/vndserver.h index 78246d212..613fef0fe 100644 --- a/glx/vndserver.h +++ b/glx/vndserver.h @@ -95,6 +95,13 @@ Bool GlxAddXIDMap(XID id, GlxServerVendor *vendor); GlxServerVendor * GlxGetXIDMap(XID id); void GlxRemoveXIDMap(XID id); +/** + * Records the client that sent the current request. This is needed in + * GlxGetXIDMap to know which client's (screen -> vendor) mapping to use for a + * regular X window. + */ +void GlxSetRequestClient(ClientPtr client); + GlxContextTagInfo *GlxAllocContextTag(ClientPtr client, GlxServerVendor *vendor); GlxContextTagInfo *GlxLookupContextTag(ClientPtr client, GLXContextTag tag); void GlxFreeContextTag(GlxContextTagInfo *tagInfo); diff --git a/glx/vndservermapping.c b/glx/vndservermapping.c index 778656bb6..4efab8b81 100644 --- a/glx/vndservermapping.c +++ b/glx/vndservermapping.c @@ -33,6 +33,13 @@ #include "vndservervendor.h" +static ClientPtr requestClient = NULL; + +void GlxSetRequestClient(ClientPtr client) +{ + requestClient = client; +} + static GlxServerVendor *LookupXIDMapResource(XID id) { void *ptr = NULL; @@ -59,10 +66,7 @@ GlxServerVendor *GlxGetXIDMap(XID id) DixGetAttrAccess); if (rv == Success && ptr != NULL) { DrawablePtr draw = (DrawablePtr) ptr; - GlxScreenPriv *screenPriv = GlxGetScreen(draw->pScreen); - if (screenPriv != NULL) { - vendor = screenPriv->vendor; - } + vendor = GlxGetVendorForScreen(requestClient, draw->pScreen); } } return vendor; From 56c0a71fdd94a008e5d746261f70a713c4767f93 Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Thu, 2 May 2019 07:17:21 -0600 Subject: [PATCH 05/38] GLX: Add a function to change a clients vendor list. Add a new function, GlxServerExports::setClientScreenVendor, which will change the vendor that handles GLX requests for a screen, but only for requests from a specific client. v2: Increment the GLXVND minor version number. v3: Note the GLXVND version requirement for setClientScreenVendor. Signed-off-by: Aaron Plattner Reviewed-by: Aaron Plattner Reviewed-by: Adam Jackson --- glx/vndext.c | 1 + glx/vndserver.h | 1 + glx/vndservermapping.c | 21 +++++++++++++++++++++ include/glxvndabi.h | 13 ++++++++++++- 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/glx/vndext.c b/glx/vndext.c index 20c0648cc..582e60b6e 100644 --- a/glx/vndext.c +++ b/glx/vndext.c @@ -324,6 +324,7 @@ _X_EXPORT const GlxServerExports glxServer = { .getContextTagPrivate = GlxGetContextTagPrivate, .getVendorForScreen = GlxGetVendorForScreen, .forwardRequest = GlxForwardRequest, + .setClientScreenVendor = GlxSetClientScreenVendor, }; const GlxServerExports * diff --git a/glx/vndserver.h b/glx/vndserver.h index 613fef0fe..772b458a1 100644 --- a/glx/vndserver.h +++ b/glx/vndserver.h @@ -107,6 +107,7 @@ GlxContextTagInfo *GlxLookupContextTag(ClientPtr client, GLXContextTag tag); void GlxFreeContextTag(GlxContextTagInfo *tagInfo); Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor); +Bool GlxSetClientScreenVendor(ClientPtr client, ScreenPtr screen, GlxServerVendor *vendor); GlxScreenPriv *GlxGetScreen(ScreenPtr pScreen); GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen); diff --git a/glx/vndservermapping.c b/glx/vndservermapping.c index 4efab8b81..04788ffbd 100644 --- a/glx/vndservermapping.c +++ b/glx/vndservermapping.c @@ -189,6 +189,27 @@ Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor) return TRUE; } +Bool GlxSetClientScreenVendor(ClientPtr client, ScreenPtr screen, GlxServerVendor *vendor) +{ + GlxClientPriv *cl; + + if (screen == NULL || screen->isGPU) { + return FALSE; + } + + cl = GlxGetClientData(client); + if (cl == NULL) { + return FALSE; + } + + if (vendor != NULL) { + cl->vendors[screen->myNum] = vendor; + } else { + cl->vendors[screen->myNum] = GlxGetVendorForScreen(NULL, screen); + } + return TRUE; +} + GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen) { // Note that the client won't be sending GPU screen numbers, so we don't diff --git a/include/glxvndabi.h b/include/glxvndabi.h index b78306d23..71f36e722 100644 --- a/include/glxvndabi.h +++ b/include/glxvndabi.h @@ -75,7 +75,7 @@ * will still work. */ #define GLXSERVER_VENDOR_ABI_MAJOR_VERSION 0 -#define GLXSERVER_VENDOR_ABI_MINOR_VERSION 0 +#define GLXSERVER_VENDOR_ABI_MINOR_VERSION 1 #if defined(__cplusplus) extern "C" { @@ -236,6 +236,17 @@ typedef struct GlxServerExportsRec { * \param client The client. */ int (* forwardRequest) (GlxServerVendor *vendor, ClientPtr client); + + /** + * Sets the vendor library to use for a screen for a specific client. + * + * This function changes which vendor should handle GLX requests for a + * screen. Unlike \c setScreenVendor, this function can be called at any + * time, and only applies to requests from a single client. + * + * This function is available in GLXVND version 0.1 or later. + */ + Bool (* setClientScreenVendor) (ClientPtr client, ScreenPtr screen, GlxServerVendor *vendor); } GlxServerExports; extern _X_EXPORT const GlxServerExports glxServer; From 246b729df87e94e405a8b257f34a22fa2719d30c Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 28 Jul 2016 14:26:38 +0100 Subject: [PATCH 06/38] configure: Force --disable-input-thread for MinGW I don't think an input thread can ever be useful on Windows. There is a pthread emulation, so having the thread itself isn't much of a problem. However, there is no device to wait on for Windows events, and even if we were to replace select() with WFMO, Windows wants to send events for a window to the thread which created that window. So, disable input thread by default for MinGW v2: Also add similar to meson.build --- configure.ac | 5 +++++ include/meson.build | 3 +++ 2 files changed, 8 insertions(+) diff --git a/configure.ac b/configure.ac index 5055d271d..215dd64fe 100644 --- a/configure.ac +++ b/configure.ac @@ -791,6 +791,11 @@ if test "x$HAVE_RECURSIVE_MUTEX" = "xyes" ; then THREAD_DEFAULT=yes fi +case $host_os in + mingw*) THREAD_DEFAULT=no ;; + *) +esac + AC_ARG_ENABLE(input-thread, AS_HELP_STRING([--enable-input-thread], [Enable input threads]), [INPUTTHREAD=$enableval], [INPUTTHREAD=$THREAD_DEFAULT]) diff --git a/include/meson.build b/include/meson.build index 65781b7a0..527025b24 100644 --- a/include/meson.build +++ b/include/meson.build @@ -60,6 +60,9 @@ else if not enable_input_thread and get_option('input_thread') == 'true' error('Input thread enabled and PTHREAD_MUTEX_RECURSIVE not found') endif + if host_machine.system() == 'windows' and get_option('input_thread') == 'auto' + enable_input_thread = false + endif endif conf_data.set('HAVE_INPUTTHREAD', enable_input_thread) From 6c5d048095379a85f1862429b9049edc1c82e167 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 28 Jul 2016 14:09:51 +0100 Subject: [PATCH 07/38] os: Fix build of xserver_poll.c on MinGW Include winsock.h for definition of fd_set type and select() Future work: Maybe this also needs some error checking for fd > FD_SETSIZE? --- os/xserver_poll.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/os/xserver_poll.c b/os/xserver_poll.c index f152cda21..1927dfa10 100644 --- a/os/xserver_poll.c +++ b/os/xserver_poll.c @@ -84,6 +84,10 @@ #include /* string functions */ #include "xserver_poll.h" +#if defined(WIN32) && !defined(__CYGWIN__) +#include +#endif + /*---------------------------------------------------------------------------*\ Macros \*---------------------------------------------------------------------------*/ From 7b4b030df8f9c994f3dc60cf85e74d234464af28 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 28 Jul 2016 14:46:15 +0100 Subject: [PATCH 08/38] configure: Check for sigprocmask MinGW defines SIG_BLOCK, but doesn't have signal masks, so rather than checking for SIG_BLOCK, add a configure check for sigprocmask. v2: Also add check to meson.build --- configure.ac | 3 ++- include/dix-config.h.in | 3 +++ include/meson.build | 1 + os/inputthread.c | 4 ++++ os/utils.c | 8 ++++---- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 215dd64fe..23c0ac285 100644 --- a/configure.ac +++ b/configure.ac @@ -159,7 +159,8 @@ dnl Checks for library functions. AC_CHECK_FUNCS([backtrace geteuid getuid issetugid getresuid \ getdtablesize getifaddrs getpeereid getpeerucred getprogname getzoneid \ mmap posix_fallocate seteuid shmctl64 strncasecmp vasprintf vsnprintf \ - walkcontext setitimer poll epoll_create1 mkostemp memfd_create]) + walkcontext setitimer poll epoll_create1 mkostemp memfd_create \ + sigprocmask]) AC_CONFIG_LIBOBJ_DIR([os]) AC_REPLACE_FUNCS([reallocarray strcasecmp strcasestr strlcat strlcpy strndup\ timingsafe_memcmp]) diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 9eb1a924e..b463a17f3 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -512,4 +512,7 @@ /* Have header */ #undef HAVE_SYS_SYSMACROS_H +/* Have sigprocmask */ +#undef HAVE_SIGPROCMASK + #endif /* _DIX_CONFIG_H_ */ diff --git a/include/meson.build b/include/meson.build index 527025b24..2c1b49e06 100644 --- a/include/meson.build +++ b/include/meson.build @@ -155,6 +155,7 @@ conf_data.set('HAVE_SETEUID', cc.has_function('seteuid')) conf_data.set('HAVE_SETITIMER', cc.has_function('setitimer')) conf_data.set('HAVE_SHMCTL64', cc.has_function('shmctl64')) conf_data.set('HAVE_SIGACTION', cc.has_function('sigaction')) +conf_data.set('HAVE_SIGPROCMASK', cc.has_function('sigprocmask')) conf_data.set('HAVE_STRCASECMP', cc.has_function('strcasecmp')) conf_data.set('HAVE_STRCASESTR', cc.has_function('strcasestr')) conf_data.set('HAVE_STRLCAT', cc.has_function('strlcat', dependencies: libbsd_dep)) diff --git a/os/inputthread.c b/os/inputthread.c index e6694afda..361d96efa 100644 --- a/os/inputthread.c +++ b/os/inputthread.c @@ -558,7 +558,11 @@ extern int InputThreadUnregisterDev(int fd) int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) { +#ifdef HAVE_SIGPROCMASK return sigprocmask(how, set, oldset); +#else + return 0; +#endif } #endif diff --git a/os/utils.c b/os/utils.c index f04bf8045..d1cd07ccc 100644 --- a/os/utils.c +++ b/os/utils.c @@ -1281,7 +1281,7 @@ SmartScheduleInit(void) #endif } -#ifdef SIG_BLOCK +#ifdef HAVE_SIGPROCMASK static sigset_t PreviousSignalMask; static int BlockedSignalCount; #endif @@ -1289,7 +1289,7 @@ static int BlockedSignalCount; void OsBlockSignals(void) { -#ifdef SIG_BLOCK +#ifdef HAVE_SIGPROCMASK if (BlockedSignalCount++ == 0) { sigset_t set; @@ -1311,7 +1311,7 @@ OsBlockSignals(void) void OsReleaseSignals(void) { -#ifdef SIG_BLOCK +#ifdef HAVE_SIGPROCMASK if (--BlockedSignalCount == 0) { xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0); } @@ -1321,7 +1321,7 @@ OsReleaseSignals(void) void OsResetSignals(void) { -#ifdef SIG_BLOCK +#ifdef HAVE_SIGPROCMASK while (BlockedSignalCount > 0) OsReleaseSignals(); input_force_unlock(); From a838c840a3f8c55157615f072b9a3c3a4b476b37 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 25 Apr 2019 22:44:49 +0100 Subject: [PATCH 09/38] os: Ensure sigset_t is provided when compiling for MinGW Only _sigset_t is defined by MinGW's signal.h --- include/os.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/os.h b/include/os.h index a1835cd6a..bb3348b18 100644 --- a/include/os.h +++ b/include/os.h @@ -721,6 +721,10 @@ os_move_fd(int fd); #include +#if defined(WIN32) && !defined(__CYGWIN__) +typedef _sigset_t sigset_t; +#endif + extern _X_EXPORT int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldest); From 965eda947d4c847c6e520317b57024b4586507ec Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 25 Apr 2019 23:11:08 +0100 Subject: [PATCH 10/38] mi: Provide ffs when compiling using MinGW I don't know how I feel about the promise made in 2e7f790b :) --- mi/mibitblt.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mi/mibitblt.c b/mi/mibitblt.c index 4f7e29170..84f8da65a 100644 --- a/mi/mibitblt.c +++ b/mi/mibitblt.c @@ -62,6 +62,10 @@ SOFTWARE. #include #include "servermd.h" +#ifdef __MINGW32__ +#define ffs __builtin_ffs +#endif + /* MICOPYAREA -- public entry for the CopyArea request * For each rectangle in the source region * get the pixels with GetSpans From 0a07446318f248b65fcbc8ab8a73ead51153f09e Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Thu, 9 May 2019 10:36:19 +0200 Subject: [PATCH 11/38] xwayland: Avoid a crash on pointer enter with a grab On pointer enter notification, Xwayland checks for an existing pointer warp with a `NULL` sprite. In turn, `xwl_pointer_warp_emulator_maybe_lock()` checks for an existing grab and the destination window using `XYToWindow()` which does not check for the actual sprite not being `NULL`. So, in some cases, when the pointer enters the surface and there is an existing X11 grab which is not an ownerEvents grab, Xwayland would crash trying to dereference the `NULL` sprite pointer: #0 __GI_raise () #1 __GI_abort () at abort.c:79 #2 OsAbort () at utils.c:1351 #3 AbortServer () at log.c:879 #4 FatalError () at log.c:1017 #5 OsSigHandler () at osinit.c:156 #6 OsSigHandler () at osinit.c:110 #7 #8 XYToWindow (pSprite=0x0, x=0, y=0) at events.c:2880 #9 xwl_pointer_warp_emulator_maybe_lock () at xwayland-input.c:2673 #10 pointer_handle_enter () at xwayland-input.c:434 Avoid the crash by simply checking for the sprite being not `NULL` in `xwl_pointer_warp_emulator_maybe_lock()` Signed-off-by: Olivier Fourdan Bugzilla: https://bugzilla.redhat.com/1708119 --- hw/xwayland/xwayland-input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xwayland/xwayland-input.c b/hw/xwayland/xwayland-input.c index 15fc989bd..2c3482763 100644 --- a/hw/xwayland/xwayland-input.c +++ b/hw/xwayland/xwayland-input.c @@ -2661,6 +2661,7 @@ xwl_pointer_warp_emulator_maybe_lock(struct xwl_pointer_warp_emulator *warp_emul */ if (pointer_grab && !pointer_grab->ownerEvents && + sprite && XYToWindow(sprite, x, y) != xwl_seat->focus_window->window) return; From b4231d69028adc8123801a7552b40a15ea928d1b Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Tue, 21 May 2019 10:50:42 -0700 Subject: [PATCH 12/38] GLX: Set GlxServerExports::{major,minor}Version Commit 56c0a71fdd94a008e5d746261f70a713c4767f93 incremented the GLXSERVER_VENDOR_ABI_MINOR_VERSION define, but this define was not actually being used to set glxServer.minorVersion. Update the initializer for glxServer to use the correct version numbers. Signed-off-by: Aaron Plattner --- glx/vndext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/glx/vndext.c b/glx/vndext.c index 582e60b6e..0513733b6 100644 --- a/glx/vndext.c +++ b/glx/vndext.c @@ -304,8 +304,8 @@ GlxFreeServerImports(GlxServerImports *imports) } _X_EXPORT const GlxServerExports glxServer = { - .majorVersion = 0, - .minorVersion = 0, + .majorVersion = GLXSERVER_VENDOR_ABI_MAJOR_VERSION, + .minorVersion = GLXSERVER_VENDOR_ABI_MINOR_VERSION, .extensionInitCallback = &vndInitCallbackListPtr, From 8469241592b94b002a975274a596ca0dcdd9563f Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 8 May 2019 14:09:00 -0400 Subject: [PATCH 13/38] xwayland: Add EGL-backed GLX provider Without this we're using driswrast to set up GLX visuals. This is unfortunate because llvmpipe does not expose multisample configs, so various apps that expect them will fail. With this we just query the capabilities of the EGL that's backing glamor, and reflect that to the GLX clients. This also paves the way for xserver to stop being a DRI driver loader, which is nice. Fixes: xorg/xserver#640 Fixes: xorg/xserver#643 Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=98272 Reviewed-by: Olivier Fourdan Signed-off-by: Adam Jackson --- hw/xwayland/Makefile.am | 4 + hw/xwayland/meson.build | 10 +- hw/xwayland/xwayland-glamor.c | 7 + hw/xwayland/xwayland-glx.c | 344 ++++++++++++++++++++++++++++++++++ hw/xwayland/xwayland.h | 5 + 5 files changed, 369 insertions(+), 1 deletion(-) create mode 100644 hw/xwayland/xwayland-glx.c diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am index 502879e2a..282da58f9 100644 --- a/hw/xwayland/Makefile.am +++ b/hw/xwayland/Makefile.am @@ -22,6 +22,10 @@ Xwayland_SOURCES = \ $(top_srcdir)/mi/miinitext.c if GLX +Xwayland_SOURCES += \ + xwayland-glx.c +Xwayland_CFLAGS += \ + -I$(top_srcdir)/glx GLXVND_LIB = $(top_builddir)/glx/libglxvnd.la endif diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build index 36bf2133a..c8746e591 100644 --- a/hw/xwayland/meson.build +++ b/hw/xwayland/meson.build @@ -54,6 +54,9 @@ xwayland_glamor = [] eglstream_srcs = [] if build_glamor srcs += 'xwayland-glamor.c' + if build_glx + srcs += 'xwayland-glx.c' + endif if gbm_dep.found() srcs += 'xwayland-glamor-gbm.c' endif @@ -80,10 +83,15 @@ if build_glamor xwayland_glamor += glamor endif +wayland_inc = [ inc, ] +if build_glx + wayland_inc += glx_inc +endif + executable( 'Xwayland', srcs, - include_directories: inc, + include_directories: wayland_inc, dependencies: [ common_dep, xwayland_dep, diff --git a/hw/xwayland/xwayland-glamor.c b/hw/xwayland/xwayland-glamor.c index f4bd561ea..dc07f7933 100644 --- a/hw/xwayland/xwayland-glamor.c +++ b/hw/xwayland/xwayland-glamor.c @@ -30,6 +30,9 @@ #include #include +#ifdef GLXEXT +#include "glx_extinit.h" +#endif static void glamor_egl_make_current(struct glamor_context *glamor_ctx) @@ -264,5 +267,9 @@ xwl_glamor_init(struct xwl_screen *xwl_screen) ErrorF("Failed to initialize glamor Xv extension\n"); #endif +#ifdef GLXEXT + GlxPushProvider(&glamor_provider); +#endif + return TRUE; } diff --git a/hw/xwayland/xwayland-glx.c b/hw/xwayland/xwayland-glx.c new file mode 100644 index 000000000..71c9aad23 --- /dev/null +++ b/hw/xwayland/xwayland-glx.c @@ -0,0 +1,344 @@ +/* + * Copyright © 2019 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Adam Jackson + */ + +/* + * Sets up GLX capabilities based on the EGL capabilities of the glamor + * renderer for the screen. Without this you will get whatever swrast + * can do, which often does not include things like multisample visuals. + */ + +#include +#include "xwayland.h" +#define MESA_EGL_NO_X11_HEADERS +// #include +#include +#include "glxserver.h" +#include "glxutil.h" +#include "compint.h" +#include +#include "glamor_context.h" +#include "glamor.h" + +/* Can't get these from since it pulls in client headers */ +#define GLX_RGBA_BIT 0x00000001 +#define GLX_WINDOW_BIT 0x00000001 +#define GLX_PIXMAP_BIT 0x00000002 +#define GLX_PBUFFER_BIT 0x00000004 +#define GLX_NONE 0x8000 +#define GLX_SLOW_CONFIG 0x8001 +#define GLX_TRUE_COLOR 0x8002 +#define GLX_DIRECT_COLOR 0x8003 +#define GLX_NON_CONFORMANT_CONFIG 0x800D +#define GLX_DONT_CARE 0xFFFFFFFF +#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004 +#define GLX_SWAP_UNDEFINED_OML 0x8063 + +struct egl_config { + __GLXconfig base; + EGLConfig config; +}; + +struct egl_screen { + __GLXscreen base; + EGLDisplay display; + EGLConfig *configs; +}; + +static void +egl_screen_destroy(__GLXscreen *_screen) +{ + struct egl_screen *screen = (struct egl_screen *)_screen; + + /* XXX do we leak the fbconfig list? */ + + free(screen->configs); + __glXScreenDestroy(_screen); + free(_screen); +} + +static void +egl_drawable_destroy(__GLXdrawable *draw) +{ + free(draw); +} + +static GLboolean +egl_drawable_swap_buffers(ClientPtr client, __GLXdrawable *draw) +{ + return GL_FALSE; +} + +static void +egl_drawable_copy_sub_buffer(__GLXdrawable *draw, int x, int y, int w, int h) +{ +} + +static void +egl_drawable_wait_x(__GLXdrawable *draw) +{ + glamor_block_handler(draw->pDraw->pScreen); +} + +static void +egl_drawable_wait_gl(__GLXdrawable *draw) +{ +} + +static __GLXdrawable * +egl_create_glx_drawable(ClientPtr client, __GLXscreen *screen, + DrawablePtr draw, XID drawid, int type, + XID glxdrawid, __GLXconfig *modes) +{ + __GLXdrawable *ret; + + ret = calloc(1, sizeof *ret); + if (!ret) + return NULL; + + if (!__glXDrawableInit(ret, screen, draw, type, glxdrawid, modes)) { + free(ret); + return NULL; + } + + ret->destroy = egl_drawable_destroy; + ret->swapBuffers = egl_drawable_swap_buffers; + ret->copySubBuffer = egl_drawable_copy_sub_buffer; + ret->waitX = egl_drawable_wait_x; + ret->waitGL = egl_drawable_wait_gl; + + return ret; +} + +/* + * TODO: + * + * - figure out sRGB + * - bindToTextureTargets is suspicious + * - better channel mask setup + * - drawable type masks is suspicious + */ +static struct egl_config * +translate_eglconfig(struct egl_screen *screen, EGLConfig hc, + struct egl_config *chain, Bool direct_color, + Bool double_buffer) +{ + EGLint value; + struct egl_config *c = calloc(1, sizeof *c); + + if (!c) + return chain; + + /* constants. changing these requires (at least) new EGL extensions */ + c->base.stereoMode = GL_FALSE; + c->base.numAuxBuffers = 0; + c->base.level = 0; + c->base.transparentAlpha = 0; + c->base.transparentIndex = 0; + c->base.transparentPixel = GLX_NONE; + c->base.visualSelectGroup = 0; + c->base.indexBits = 0; + c->base.optimalPbufferWidth = 0; + c->base.optimalPbufferHeight = 0; + c->base.bindToMipmapTexture = 0; + c->base.bindToTextureTargets = GLX_DONT_CARE; + c->base.sRGBCapable = 0; + c->base.swapMethod = GLX_SWAP_UNDEFINED_OML; + + /* this is... suspect */ + c->base.drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT | GLX_PBUFFER_BIT; + + /* hmm */ + c->base.bindToTextureRgb = GL_TRUE; + c->base.bindToTextureRgba = GL_TRUE; + + /* + * glx conformance failure: there's no such thing as accumulation + * buffers in EGL. they should be emulable with shaders and fbos, + * but i'm pretty sure nobody's using this feature since it's + * entirely software. note that glx conformance merely requires + * that an accum buffer _exist_, not a minimum bitness. + */ + c->base.accumRedBits = 0; + c->base.accumGreenBits = 0; + c->base.accumBlueBits = 0; + c->base.accumAlphaBits = 0; + + /* parametric state */ + if (direct_color) + c->base.visualType = GLX_DIRECT_COLOR; + else + c->base.visualType = GLX_TRUE_COLOR; + + if (double_buffer) + c->base.doubleBufferMode = GL_TRUE; + else + c->base.doubleBufferMode = GL_FALSE; + + /* direct-mapped state */ +#define GET(attr, slot) \ + eglGetConfigAttrib(screen->display, hc, attr, &c->base.slot) + GET(EGL_RED_SIZE, redBits); + GET(EGL_GREEN_SIZE, greenBits); + GET(EGL_BLUE_SIZE, blueBits); + GET(EGL_ALPHA_SIZE, alphaBits); + GET(EGL_BUFFER_SIZE, rgbBits); + GET(EGL_DEPTH_SIZE, depthBits); + GET(EGL_STENCIL_SIZE, stencilBits); + GET(EGL_TRANSPARENT_RED_VALUE, transparentRed); + GET(EGL_TRANSPARENT_GREEN_VALUE, transparentGreen); + GET(EGL_TRANSPARENT_BLUE_VALUE, transparentBlue); + GET(EGL_SAMPLE_BUFFERS, sampleBuffers); + GET(EGL_SAMPLES, samples); + if (c->base.renderType & GLX_PBUFFER_BIT) { + GET(EGL_MAX_PBUFFER_WIDTH, maxPbufferWidth); + GET(EGL_MAX_PBUFFER_HEIGHT, maxPbufferHeight); + GET(EGL_MAX_PBUFFER_PIXELS, maxPbufferPixels); + } +#undef GET + + /* derived state: config caveats */ + eglGetConfigAttrib(screen->display, hc, EGL_CONFIG_CAVEAT, &value); + if (value == EGL_NONE) + c->base.visualRating = GLX_NONE; + else if (value == EGL_SLOW_CONFIG) + c->base.visualRating = GLX_SLOW_CONFIG; + else if (value == EGL_NON_CONFORMANT_CONFIG) + c->base.visualRating = GLX_NON_CONFORMANT_CONFIG; + /* else panic */ + + /* derived state: float configs */ + c->base.renderType = GLX_RGBA_BIT; + if (eglGetConfigAttrib(screen->display, hc, EGL_COLOR_COMPONENT_TYPE_EXT, + &value) == EGL_TRUE) { + if (value == EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT) { + c->base.renderType = GLX_RGBA_FLOAT_BIT_ARB; + } + /* else panic */ + } + + /* map to the backend's config */ + c->config = hc; + + /* + * XXX do something less ugly + */ + if (c->base.renderType == GLX_RGBA_BIT) { + if (c->base.rgbBits == 24 || c->base.rgbBits == 32) { + c->base.redMask = 0xff0000; + c->base.greenMask = 0x00ff00; + c->base.blueMask = 0x0000ff; + if (c->base.alphaBits) + /* assume all remaining bits are alpha */ + c->base.alphaMask = 0xff000000; + } + } + + c->base.next = chain ? &chain->base : NULL; + return c; +} + +static __GLXconfig * +egl_mirror_configs(ScreenPtr pScreen, struct egl_screen *screen) +{ + int i, j, k, nconfigs; + struct egl_config *c = NULL; + EGLConfig *host_configs = NULL; + Bool offon[] = { FALSE, TRUE }; + + eglGetConfigs(screen->display, NULL, 0, &nconfigs); + if (!(host_configs = calloc(nconfigs, sizeof *host_configs))) + return NULL; + + eglGetConfigs(screen->display, host_configs, nconfigs, &nconfigs); + + /* We walk the EGL configs backwards to make building the + * ->next chain easier. + */ + for (i = nconfigs - 1; i > 0; i--) + for (j = 0; j < 2; j++) /* direct_color */ + for (k = 0; k < 2; k++) /* direct_color */ + c = translate_eglconfig(screen, host_configs[i], c, + /* direct_color */ offon[j], + /* double_buffer */ offon[k] + ); + + screen->configs = host_configs; + return c ? &c->base : NULL; +} + +static __GLXscreen * +egl_screen_probe(ScreenPtr pScreen) +{ + struct egl_screen *screen; + struct xwl_screen *xwl_screen = xwl_screen_get(pScreen); + __GLXscreen *base; + + if (enableIndirectGLX) + return NULL; /* not implemented */ + + if (!(screen = calloc(1, sizeof *screen))) + return NULL; + + base = &screen->base; + base->destroy = egl_screen_destroy; + base->createDrawable = egl_create_glx_drawable; + /* base.swapInterval = NULL; */ + + screen->display = xwl_screen->glamor_ctx->display; + + __glXInitExtensionEnableBits(screen->base.glx_enable_bits); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_context_flush_control"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_no_error"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_create_context_robustness"); + __glXEnableExtension(base->glx_enable_bits, "GLX_ARB_fbconfig_float"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_create_context_es2_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_create_context_es_profile"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_fbconfig_packed_float"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_framebuffer_sRGB"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_no_config_context"); + __glXEnableExtension(base->glx_enable_bits, "GLX_EXT_texture_from_pixmap"); + __glXEnableExtension(base->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); + // __glXEnableExtension(base->glx_enable_bits, "GLX_SGI_swap_control"); + + base->fbconfigs = egl_mirror_configs(pScreen, screen); + if (!base->fbconfigs) { + free(screen); + return NULL; + } + + __glXScreenInit(base, pScreen); + __glXsetGetProcAddress(eglGetProcAddress); + + return base; +} + +__GLXprovider glamor_provider = { + egl_screen_probe, + "glamor", + NULL +}; diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h index 92664e812..85691d9d4 100644 --- a/hw/xwayland/xwayland.h +++ b/hw/xwayland/xwayland.h @@ -485,4 +485,9 @@ static inline void xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen) } #endif +#ifdef GLXEXT +#include "glx_extinit.h" +extern __GLXprovider glamor_provider; +#endif + #endif From 766bf01b21306ec6bcf5ca884c0af15bdcde25f6 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 16 May 2019 15:48:14 -0400 Subject: [PATCH 14/38] glamor: Fix more fallback paths with non-GXcopy rop with GLES Desktop GL can handle arbitrary rops here, GLES can't. The switch statement attempts to optimize some cases that GLES can still handle if we precompute the right pixel value, but we were then throwing that pixel value away and using gc->fgPixel anyway. Fix this, and now xts-render passes against glamor+gles. --- glamor/glamor_transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glamor/glamor_transform.c b/glamor/glamor_transform.c index 348d00be1..11a08f7f6 100644 --- a/glamor/glamor_transform.c +++ b/glamor/glamor_transform.c @@ -158,7 +158,7 @@ glamor_set_solid(PixmapPtr pixmap, return FALSE; } } - glamor_set_color(pixmap, gc->fgPixel, uniform); + glamor_set_color(pixmap, pixel, uniform); return TRUE; } From fc6380a11be4c6202ed72f241dd9ee8c7c24671d Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 12 Mar 2019 15:38:03 +0100 Subject: [PATCH 15/38] xwayland: Check status in GBM pixmap creation The current code in `xwl_glamor_gbm_create_pixmap_for_bo()` may fail in several cases that are not checked for: - `eglCreateImageKHR()` may have failed to create the image, - `glEGLImageTargetTexture2DOES()` may fail and set an error, - `glamor_set_pixmap_texture()` may fail for very large pixmaps because the corresponding FBO could not be created. Trying to upload content to a pixmap with no texture will crash Mesa, glamor and Xwayland, e.g.: XXX fail to create fbo. (EE) (EE) Backtrace: (EE) 0: Xwayland (OsSigHandler+0x29) (EE) 1: libpthread.so.0 (funlockfile+0x50) (EE) 2: libc.so.6 (__memmove_avx_unaligned_erms+0x215) (EE) 3: dri/i965_dri.so (_mesa_format_convert+0xab3) (EE) 4: dri/i965_dri.so (_mesa_texstore+0x205) (EE) 5: dri/i965_dri.so (store_texsubimage+0x28c) (EE) 6: dri/i965_dri.so (intel_upload_tex+0x13b) (EE) 7: dri/i965_dri.so (texture_sub_image+0x134) (EE) 8: dri/i965_dri.so (texsubimage_err+0x150) (EE) 9: dri/i965_dri.so (_mesa_TexSubImage2D+0x48) (EE) 10: Xwayland (glamor_upload_boxes+0x246) (EE) 11: Xwayland (glamor_copy+0x4d1) (EE) 12: Xwayland (miCopyRegion+0x96) (EE) 13: Xwayland (miDoCopy+0x43c) (EE) 14: Xwayland (glamor_copy_area+0x24) (EE) 15: Xwayland (damageCopyArea+0xba) (EE) 16: Xwayland (compCopyWindow+0x31c) (EE) 17: Xwayland (damageCopyWindow+0xd3) (EE) 18: Xwayland (miResizeWindow+0x7b7) (EE) 19: Xwayland (compResizeWindow+0x3a) (EE) 20: Xwayland (ConfigureWindow+0xa96) (EE) 21: Xwayland (ProcConfigureWindow+0x7d) (EE) 22: Xwayland (Dispatch+0x320) (EE) 23: Xwayland (dix_main+0x366) (EE) 24: libc.so.6 (__libc_start_main+0xf3) (EE) 25: Xwayland (_start+0x2e) (EE) Fatal server error: (EE) Caught signal 11 (Segmentation fault). Server aborting (EE) Check for the possible cases of failure above and fallback to the regular glamor pixmap creation when an error is detected. Signed-off-by: Olivier Fourdan Closes: https://gitlab.freedesktop.org/xorg/xserver/issues/661 --- hw/xwayland/xwayland-glamor-gbm.c | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index a211e0915..80146ab6e 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -169,6 +169,8 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, xwl_screen->egl_context, EGL_NATIVE_PIXMAP_KHR, xwl_pixmap->bo, NULL); + if (xwl_pixmap->image == EGL_NO_IMAGE_KHR) + goto error; glGenTextures(1, &xwl_pixmap->texture); glBindTexture(GL_TEXTURE_2D, xwl_pixmap->texture); @@ -176,14 +178,31 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, xwl_pixmap->image); + if (eglGetError() != EGL_SUCCESS) + goto error; + glBindTexture(GL_TEXTURE_2D, 0); + glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture); + /* `set_pixmap_texture()` may fail silently if the FBO creation failed, + * so we check again the texture to be sure it worked. + */ + if (!glamor_get_pixmap_texture(pixmap)) + goto error; + + glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); xwl_pixmap_set_private(pixmap, xwl_pixmap); - glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture); - glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); - return pixmap; + +error: + if (xwl_pixmap->image != EGL_NO_IMAGE_KHR) + eglDestroyImageKHR(xwl_screen->egl_display, xwl_pixmap->image); + if (pixmap) + glamor_destroy_pixmap(pixmap); + free(xwl_pixmap); + + return NULL; } static PixmapPtr @@ -194,6 +213,7 @@ xwl_glamor_gbm_create_pixmap(ScreenPtr screen, struct xwl_screen *xwl_screen = xwl_screen_get(screen); struct xwl_gbm_private *xwl_gbm = xwl_gbm_get(xwl_screen); struct gbm_bo *bo; + PixmapPtr pixmap = NULL; if (width > 0 && height > 0 && depth >= 15 && (hint == 0 || @@ -219,10 +239,16 @@ xwl_glamor_gbm_create_pixmap(ScreenPtr screen, } if (bo) - return xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth); + pixmap = xwl_glamor_gbm_create_pixmap_for_bo(screen, bo, depth); + + if (!pixmap) + gbm_bo_destroy(bo); } - return glamor_create_pixmap(screen, width, height, depth, hint); + if (!pixmap) + pixmap = glamor_create_pixmap(screen, width, height, depth, hint); + + return pixmap; } static Bool From 9e37e41fa78a33b95fd78e92b74b961086ab712b Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 12 Mar 2019 17:15:10 +0100 Subject: [PATCH 16/38] glamor: return status from `glamor_set_pixmap_texture()` Chnage the API for `glamor_set_pixmap_texture()` to return a status, so that the caller can know whether it succeeded or not. Signed-off-by: Olivier Fourdan --- glamor/glamor.c | 6 ++++-- glamor/glamor.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/glamor/glamor.c b/glamor/glamor.c index eee44c25d..4b935de59 100644 --- a/glamor/glamor.c +++ b/glamor/glamor.c @@ -99,7 +99,7 @@ glamor_set_pixmap_type(PixmapPtr pixmap, glamor_pixmap_type_t type) glamor_init_pixmap_private_small(pixmap, pixmap_priv); } -_X_EXPORT void +_X_EXPORT Bool glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex) { ScreenPtr screen = pixmap->drawable.pScreen; @@ -121,10 +121,12 @@ glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex) if (fbo == NULL) { ErrorF("XXX fail to create fbo.\n"); - return; + return FALSE; } glamor_pixmap_attach_fbo(pixmap, fbo); + + return TRUE; } uint32_t diff --git a/glamor/glamor.h b/glamor/glamor.h index 8d79597e2..c972694e3 100644 --- a/glamor/glamor.h +++ b/glamor/glamor.h @@ -110,7 +110,7 @@ extern _X_EXPORT Bool glamor_close_screen(ScreenPtr screen); extern _X_EXPORT uint32_t glamor_get_pixmap_texture(PixmapPtr pixmap); -extern _X_EXPORT void glamor_set_pixmap_texture(PixmapPtr pixmap, +extern _X_EXPORT Bool glamor_set_pixmap_texture(PixmapPtr pixmap, unsigned int tex); extern _X_EXPORT void glamor_set_pixmap_type(PixmapPtr pixmap, From 48f4ab750955106cd650bb5d3fb1c44d7696aafa Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 12 Mar 2019 17:25:41 +0100 Subject: [PATCH 17/38] xwayland: check `glamor_set_pixmap_texture()` status With `glamor_set_pixmap_texture()` returning its status, remove the hack and use the return value. Signed-off-by: Olivier Fourdan --- hw/xwayland/xwayland-glamor-gbm.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/hw/xwayland/xwayland-glamor-gbm.c b/hw/xwayland/xwayland-glamor-gbm.c index 80146ab6e..538e6204e 100644 --- a/hw/xwayland/xwayland-glamor-gbm.c +++ b/hw/xwayland/xwayland-glamor-gbm.c @@ -183,11 +183,7 @@ xwl_glamor_gbm_create_pixmap_for_bo(ScreenPtr screen, struct gbm_bo *bo, glBindTexture(GL_TEXTURE_2D, 0); - glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture); - /* `set_pixmap_texture()` may fail silently if the FBO creation failed, - * so we check again the texture to be sure it worked. - */ - if (!glamor_get_pixmap_texture(pixmap)) + if (!glamor_set_pixmap_texture(pixmap, xwl_pixmap->texture)) goto error; glamor_set_pixmap_type(pixmap, GLAMOR_TEXTURE_DRM); From 26fe29f4fa53cbb7d51892e2cf397c084093812f Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Fri, 26 Apr 2019 13:37:09 +0200 Subject: [PATCH 18/38] glamor: Make pixmap exportable from `gbm_bo_from_pixmap()` If a pixmap is not exportable, `glamor_gbm_bo_from_pixmap()` would fail and the modesettings driver would consequently fail to do its page flip, which both prevents Present from working and also fill up the logs with error messages such as: (EE) modeset(0): Failed to get GBM bo for flip to new front. (EE) modeset(0): present flip failed Refactor the code so that `glamor_gbm_bo_from_pixmap()` takes care of making the pixmap exportable. Signed-off-by: Olivier Fourdan Signed-off-by: Yuxuan Shui yshui@hadean.com See-also: https://gitlab.freedesktop.org/xorg/xserver/merge_requests/131 Closes: https://gitlab.freedesktop.org/xorg/xserver/issues/68 Fixes: 86b2d8740a "glamor: Reallocate pixmap storage without modifiers if necessary" --- glamor/glamor_egl.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/glamor/glamor_egl.c b/glamor/glamor_egl.c index 69844d4e2..693bee6cf 100644 --- a/glamor/glamor_egl.c +++ b/glamor/glamor_egl.c @@ -367,8 +367,8 @@ glamor_make_pixmap_exportable(PixmapPtr pixmap, Bool modifiers_ok) return TRUE; } -struct gbm_bo * -glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) +static struct gbm_bo * +glamor_gbm_bo_from_pixmap_internal(ScreenPtr screen, PixmapPtr pixmap) { struct glamor_egl_screen_private *glamor_egl = glamor_egl_get_screen_private(xf86ScreenToScrn(screen)); @@ -382,6 +382,15 @@ glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) pixmap_priv->image, 0); } +struct gbm_bo * +glamor_gbm_bo_from_pixmap(ScreenPtr screen, PixmapPtr pixmap) +{ + if (!glamor_make_pixmap_exportable(pixmap, TRUE)) + return NULL; + + return glamor_gbm_bo_from_pixmap_internal(screen, pixmap); +} + int glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, uint32_t *strides, uint32_t *offsets, @@ -397,7 +406,7 @@ glamor_egl_fds_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, int *fds, if (!glamor_make_pixmap_exportable(pixmap, TRUE)) return 0; - bo = glamor_gbm_bo_from_pixmap(screen, pixmap); + bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); if (!bo) return 0; @@ -435,7 +444,7 @@ glamor_egl_fd_from_pixmap(ScreenPtr screen, PixmapPtr pixmap, if (!glamor_make_pixmap_exportable(pixmap, FALSE)) return -1; - bo = glamor_gbm_bo_from_pixmap(screen, pixmap); + bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); if (!bo) return -1; @@ -464,7 +473,7 @@ glamor_egl_fd_name_from_pixmap(ScreenPtr screen, if (!glamor_make_pixmap_exportable(pixmap, FALSE)) goto failure; - bo = glamor_gbm_bo_from_pixmap(screen, pixmap); + bo = glamor_gbm_bo_from_pixmap_internal(screen, pixmap); if (!bo) goto failure; From dea4a74621294391ce5901bb3339e1b8e7151efc Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 22 May 2019 17:51:04 +0200 Subject: [PATCH 19/38] xwayland: Reset scheduled frames after hiding tablet cursor Hiding the tablet tool cursor results in it being hidden forever after. This is due to the stale frame callback that will neither be disposed or replaced. This can be reproduced in krita (X11) as the pointer cursor is hidden while over the canvas. Clearing the frame callback ensures the correct behavior in future xwl_tablet_tool_set_cursor() calls (i.e. a new cursor surface being displayed, and a new frame callback created), and is 1:1 with xwl_seat_set_cursor() for pointers. Signed-off-by: Carlos Garnacho --- hw/xwayland/xwayland-cursor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/xwayland/xwayland-cursor.c b/hw/xwayland/xwayland-cursor.c index cf8395f1d..66720bcc0 100644 --- a/hw/xwayland/xwayland-cursor.c +++ b/hw/xwayland/xwayland-cursor.c @@ -188,6 +188,8 @@ xwl_tablet_tool_set_cursor(struct xwl_tablet_tool *xwl_tablet_tool) zwp_tablet_tool_v2_set_cursor(xwl_tablet_tool->tool, xwl_tablet_tool->proximity_in_serial, NULL, 0, 0); + clear_cursor_frame_callback(xwl_cursor); + xwl_cursor->needs_update = FALSE; return; } From f4cdbf640b6440df4af784ca35e1b1340965cc10 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 29 May 2019 16:19:55 +1000 Subject: [PATCH 20/38] Xi: return AlreadyGrabbed for key grabs > 255 We can't have high keycodes because everything in XKB relies on 8 bits. XI2's API allows for 32-bit keycodes so we have to take those but nothing in the server is really ready for this. The effect of this right now is that any high keycode grab is clipped to 255 and thus ends up grabbing a different key instead. https://bugzilla.redhat.com/show_bug.cgi?id=1697804 Signed-off-by: Peter Hutterer --- Xi/xipassivegrab.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Xi/xipassivegrab.c b/Xi/xipassivegrab.c index 65d5870f6..d30f51f3c 100644 --- a/Xi/xipassivegrab.c +++ b/Xi/xipassivegrab.c @@ -203,8 +203,14 @@ ProcXIPassiveGrabDevice(ClientPtr client) ¶m, XI2, &mask); break; case XIGrabtypeKeycode: - status = GrabKey(client, dev, mod_dev, stuff->detail, - ¶m, XI2, &mask); + /* XI2 allows 32-bit keycodes but thanks to XKB we can never + * implement this. Just return an error for all keycodes that + * cannot work anyway */ + if (stuff->detail > 255) + status = XIAlreadyGrabbed; + else + status = GrabKey(client, dev, mod_dev, stuff->detail, + ¶m, XI2, &mask); break; case XIGrabtypeEnter: case XIGrabtypeFocusIn: From 065f73353bfa5667e0fb4f42e338978b40e86652 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 3 Aug 2015 11:39:36 +0100 Subject: [PATCH 21/38] hw/xwin: Align winBltExposedRegionsShadowGDI with winTopLevelWindowProc's WM_PAINT Make winBltExposedRegionsShadowGDI() do the same stuff that winTopLevelWindowProc()'s WM_PAINT handler does. Note that winBltExposedRegionsShadowGDI() is currently used 1) in windowed mode when the GDI engine is selected, and 2) in multiwindow mode when "Hide Root Window" is off. --- hw/xwin/winshadgdi.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index 6d7ebce07..53a4700a4 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -750,6 +750,12 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) /* BeginPaint gives us an hdc that clips to the invalidated region */ hdcUpdate = BeginPaint(pScreenPriv->hwndScreen, &ps); + /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */ + if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && + ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { + EndPaint(pScreenPriv->hwndScreen, &ps); + return 0; + } /* Realize the palette, if we have one */ if (pScreenPriv->pcmapInstalled != NULL) { @@ -759,11 +765,30 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) RealizePalette(hdcUpdate); } - /* Our BitBlt will be clipped to the invalidated region */ - BitBlt(hdcUpdate, - 0, 0, - pScreenInfo->dwWidth, pScreenInfo->dwHeight, - pScreenPriv->hdcShadow, 0, 0, SRCCOPY); + /* Try to copy from the shadow buffer to the invalidated region */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + pScreenPriv->hdcShadow, + ps.rcPaint.left, + ps.rcPaint.top, + SRCCOPY)) { + LPVOID lpMsgBuf; + + /* Display an error message */ + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + + ErrorF("winBltExposedRegionsShadowGDI - BitBlt failed: %s\n", + (LPSTR) lpMsgBuf); + LocalFree(lpMsgBuf); + } /* EndPaint frees the DC */ EndPaint(pScreenPriv->hwndScreen, &ps); From adebc376b9fbda53d234a27f11eea9a0b945b50e Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 3 Aug 2015 15:59:40 +0100 Subject: [PATCH 22/38] hw/xwin: Push multiwindow wndproc WM_PAINT down into drawing engine Push the multiwindow wndproc WM_PAINT handling down into the drawing engine. Only the GDI engine is supported in multiwindow mode currently, so we only need to do this in the GDI engine. --- hw/xwin/win.h | 3 ++ hw/xwin/winmultiwindowwndproc.c | 42 ++++-------------------- hw/xwin/winshadddnl.c | 1 + hw/xwin/winshadgdi.c | 57 +++++++++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 36 deletions(-) diff --git a/hw/xwin/win.h b/hw/xwin/win.h index 27505caad..18f918d29 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -268,6 +268,8 @@ typedef Bool (*winFinishScreenInitProcPtr) (int, ScreenPtr, int, char **); typedef Bool (*winBltExposedRegionsProcPtr) (ScreenPtr); +typedef Bool (*winBltExposedWindowRegionProcPtr) (ScreenPtr, WindowPtr); + typedef Bool (*winActivateAppProcPtr) (ScreenPtr); typedef Bool (*winRedrawScreenProcPtr) (ScreenPtr pScreen); @@ -479,6 +481,7 @@ typedef struct _winPrivScreenRec { winCreateBoundingWindowProcPtr pwinCreateBoundingWindow; winFinishScreenInitProcPtr pwinFinishScreenInit; winBltExposedRegionsProcPtr pwinBltExposedRegions; + winBltExposedWindowRegionProcPtr pwinBltExposedWindowRegion; winActivateAppProcPtr pwinActivateApp; winRedrawScreenProcPtr pwinRedrawScreen; winRealizeInstalledPaletteProcPtr pwinRealizeInstalledPalette; diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c index 3f47fec65..1cac4a9f4 100644 --- a/hw/xwin/winmultiwindowwndproc.c +++ b/hw/xwin/winmultiwindowwndproc.c @@ -302,7 +302,6 @@ LRESULT CALLBACK winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { POINT ptMouse; - HDC hdcUpdate; PAINTSTRUCT ps; WindowPtr pWin = NULL; winPrivWinPtr pWinPriv = NULL; @@ -457,18 +456,9 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_PAINT: /* Only paint if our window handle is valid */ - if (hwndScreen == NULL) + if (hwnd == NULL) break; - /* BeginPaint gives us an hdc that clips to the invalidated region */ - hdcUpdate = BeginPaint(hwnd, &ps); - /* Avoid the BitBlt's if the PAINTSTRUCT is bogus */ - if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && - ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { - EndPaint(hwnd, &ps); - return 0; - } - #ifdef XWIN_GLX_WINDOWS if (pWinPriv->fWglUsed) { /* @@ -478,36 +468,16 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) XXX: For now, just leave it alone, but ideally we want to send an expose event to the window so it really redraws the affected region... */ + BeginPaint(hwnd, &ps); ValidateRect(hwnd, &(ps.rcPaint)); + EndPaint(hwnd, &ps); } else #endif - /* Try to copy from the shadow buffer */ - if (!BitBlt(hdcUpdate, - ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right - ps.rcPaint.left, - ps.rcPaint.bottom - ps.rcPaint.top, - s_pScreenPriv->hdcShadow, - ps.rcPaint.left + pWin->drawable.x, - ps.rcPaint.top + pWin->drawable.y, SRCCOPY)) { - LPVOID lpMsgBuf; + /* Call the engine dependent repainter */ + if (*s_pScreenPriv->pwinBltExposedWindowRegion) + (*s_pScreenPriv->pwinBltExposedWindowRegion) (s_pScreen, pWin); - /* Display a fancy error message */ - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &lpMsgBuf, 0, NULL); - - ErrorF("winTopLevelWindowProc - BitBlt failed: %s\n", - (LPSTR) lpMsgBuf); - LocalFree(lpMsgBuf); - } - - /* EndPaint frees the DC */ - EndPaint(hwnd, &ps); return 0; case WM_MOUSEMOVE: diff --git a/hw/xwin/winshadddnl.c b/hw/xwin/winshadddnl.c index 4e1fbd15c..290176920 100644 --- a/hw/xwin/winshadddnl.c +++ b/hw/xwin/winshadddnl.c @@ -1201,6 +1201,7 @@ winSetEngineFunctionsShadowDDNL(ScreenPtr pScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowDDNL; + pScreenPriv->pwinBltExposedWindowRegion = NULL; pScreenPriv->pwinActivateApp = winActivateAppShadowDDNL; pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowDDNL; pScreenPriv->pwinRealizeInstalledPalette diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index 53a4700a4..7c3e880dc 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -59,6 +59,9 @@ static Bool static Bool winBltExposedRegionsShadowGDI(ScreenPtr pScreen); +static Bool + winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin); + static Bool winActivateAppShadowGDI(ScreenPtr pScreen); @@ -801,6 +804,59 @@ winBltExposedRegionsShadowGDI(ScreenPtr pScreen) return TRUE; } +/* + * Blt exposed region to the given HWND + */ + +static Bool +winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) +{ + winScreenPriv(pScreen); + winPrivWinPtr pWinPriv = winGetWindowPriv(pWin); + + HWND hWnd = pWinPriv->hWnd; + HDC hdcUpdate; + PAINTSTRUCT ps; + + hdcUpdate = BeginPaint(hWnd, &ps); + /* Avoid the BitBlt if the PAINTSTRUCT region is bogus */ + if (ps.rcPaint.right == 0 && ps.rcPaint.bottom == 0 && + ps.rcPaint.left == 0 && ps.rcPaint.top == 0) { + EndPaint(hWnd, &ps); + return 0; + } + + /* Try to copy from the shadow buffer to the invalidated region */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + pScreenPriv->hdcShadow, + ps.rcPaint.left + pWin->drawable.x, + ps.rcPaint.top + pWin->drawable.y, + SRCCOPY)) { + LPVOID lpMsgBuf; + + /* Display an error message */ + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + + ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: %s\n", + (LPSTR) lpMsgBuf); + LocalFree(lpMsgBuf); + } + + /* EndPaint frees the DC */ + EndPaint(hWnd, &ps); + + return TRUE; +} + /* * Do any engine-specific appliation-activation processing */ @@ -1144,6 +1200,7 @@ winSetEngineFunctionsShadowGDI(ScreenPtr pScreen) pScreenPriv->pwinCreateBoundingWindow = winCreateBoundingWindowWindowed; pScreenPriv->pwinFinishScreenInit = winFinishScreenInitFB; pScreenPriv->pwinBltExposedRegions = winBltExposedRegionsShadowGDI; + pScreenPriv->pwinBltExposedWindowRegion = winBltExposedWindowRegionShadowGDI; pScreenPriv->pwinActivateApp = winActivateAppShadowGDI; pScreenPriv->pwinRedrawScreen = winRedrawScreenShadowGDI; pScreenPriv->pwinRealizeInstalledPalette = From ebcea16e71cd9c037351f2dc4527ca696346c8a6 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 3 Aug 2015 16:47:38 +0100 Subject: [PATCH 23/38] hw/xwin: A simpleminded attempt at composition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than drawing the window contents from the shadow framebuffer, use Composite extension redirection to cause the server to maintain a bitmap image of each top-level X window, and draw the window contents from that, so that window contents which are occluded in the framebuffer show correctly in the task bar and task switcher previews. v2: Fix incorrect use of memset() found by gcc5 hw/xwin/winshadgdi.c: In function ‘winBltExposedWindowRegionShadowGDI’: hw/xwin/winshadgdi.c:861:9: warning: ‘memset’ used with constant zero length parameter; this could be due to transposed parameters [-Wmemset-transposed-args] v3: Turn on -compositewm by default v4: Ignore -swcursor if -compositewm -swcursor is not compatible with -compositewm (because the window contents are drawn from an off-screen pixmap, not from the screen pixmap, where the software cursor will be drawn). v5: Update meson.build also Add -compositewm option to help output Update CI to install prerequisites --- .appveyor.yml | 1 + configure.ac | 2 +- hw/xwin/InitOutput.c | 5 +++ hw/xwin/man/XWin.man | 7 ++++ hw/xwin/meson.build | 1 + hw/xwin/win.h | 1 + hw/xwin/winmultiwindowwm.c | 50 ++++++++++++++++++++++++++--- hw/xwin/winprocarg.c | 20 ++++++++++++ hw/xwin/winscrinit.c | 8 ++++- hw/xwin/winshadgdi.c | 65 ++++++++++++++++++++++++++++++++++++++ hw/xwin/winvalargs.c | 8 +++++ hw/xwin/winwindow.h | 2 +- 12 files changed, 162 insertions(+), 8 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index dd244b8db..50072acd4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -50,6 +50,7 @@ libXmu-devel,\ libXpm-devel,\ libXrender-devel,\ libXtst-devel,\ +libxcb-composite-devel,\ libxcb-ewmh-devel,\ libxcb-icccm-devel,\ libxcb-image-devel,\ diff --git a/configure.ac b/configure.ac index 23c0ac285..55bb6942a 100644 --- a/configure.ac +++ b/configure.ac @@ -2081,7 +2081,7 @@ if test "x$XWIN" = xyes; then AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) AC_CHECK_TOOL(WINDRES, windres) - PKG_CHECK_MODULES([XWINMODULES],[x11 xdmcp xau xfixes x11-xcb xcb-aux xcb-image xcb-ewmh xcb-icccm]) + PKG_CHECK_MODULES([XWINMODULES],[x11 xau xdmcp xfixes x11-xcb xcb-aux xcb-composite xcb-image xcb-ewmh xcb-icccm]) if test "x$WINDOWSDRI" = xauto; then PKG_CHECK_EXISTS([windowsdriproto], [WINDOWSDRI=yes], [WINDOWSDRI=no]) diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index ddbf04253..00053beb0 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -716,6 +716,11 @@ winUseMsg(void) "\tthe updated region when num_boxes, or more, are in the\n" "\tupdated region.\n"); + ErrorF("-[no]compositewm\n" + "\tUse the Composite extension to keep a bitmap image of each top-level\n" + "\tX window, so window contents which are occluded show correctly in\n" + "\ttask bar and task switcher previews.\n"); + #ifdef XWIN_XF86CONFIG ErrorF("-config\n" "\tSpecify a configuration file.\n"); diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man index 2401f9f09..e61589e8e 100644 --- a/hw/xwin/man/XWin.man +++ b/hw/xwin/man/XWin.man @@ -170,6 +170,12 @@ on its own is equivalent to \fB\-resize=randr\fP Add the host name to the window title for X applications which are running on remote hosts, when that information is available and it's useful to do so. The default is enabled. +.TP 8 +.B \-[no]compositewm +Use Composite extension redirection to maintain a bitmap image of each top-level +X window, so window contents which are occluded show correctly in task bar and +task switcher previews. +The default is enabled. .SH OPTIONS CONTROLLING WINDOWS INTEGRATION .TP 8 @@ -206,6 +212,7 @@ The default is enabled. .TP 8 .B \-swcursor Disable the usage of the \fIWindows\fP cursor and use the X11 software cursor instead. +This option is ignored if \fB-compositewm\fP is also enabled. .TP 8 .B \-[no]trayicon Do not create a tray icon. Default is to create one diff --git a/hw/xwin/meson.build b/hw/xwin/meson.build index 3ec809fef..3462c396d 100644 --- a/hw/xwin/meson.build +++ b/hw/xwin/meson.build @@ -137,6 +137,7 @@ xwin_dep = [ dependency('xcb-image'), dependency('xcb-ewmh'), dependency('xcb-icccm'), + dependency('xcb-composite'), ] executable( diff --git a/hw/xwin/win.h b/hw/xwin/win.h index 18f918d29..b667ceb66 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -391,6 +391,7 @@ typedef struct { Bool fDecoration; Bool fRootless; Bool fMultiWindow; + Bool fCompositeWM; Bool fMultiMonitorOverride; Bool fMultipleMonitors; Bool fLessPointer; diff --git a/hw/xwin/winmultiwindowwm.c b/hw/xwin/winmultiwindowwm.c index 32bc722e2..0734006fc 100644 --- a/hw/xwin/winmultiwindowwm.c +++ b/hw/xwin/winmultiwindowwm.c @@ -49,6 +49,7 @@ #include #include #include +#include #include @@ -116,6 +117,7 @@ typedef struct _WMInfo { xcb_atom_t atmUtf8String; xcb_atom_t atmNetWmName; xcb_ewmh_connection_t ewmh; + Bool fCompositeWM; } WMInfoRec, *WMInfoPtr; typedef struct _WMProcArgRec { @@ -1038,6 +1040,8 @@ winMultiWindowXMsgProc(void *pArg) xcb_atom_t atmWindowState, atmMotifWmHints, atmWindowType, atmNormalHints; int iReturn; xcb_auth_info_t *auth_info; + xcb_screen_t *root_screen; + xcb_window_t root_window_id; winDebug("winMultiWindowXMsgProc - Hello\n"); @@ -1110,11 +1114,11 @@ winMultiWindowXMsgProc(void *pArg) pthread_exit(NULL); } - { - /* Get root window id */ - xcb_screen_t *root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); - xcb_window_t root_window_id = root_screen->root; + /* Get root window id */ + root_screen = xcb_aux_get_screen(pProcArg->conn, pProcArg->dwScreen); + root_window_id = root_screen->root; + { /* Set WM_ICON_SIZE property indicating desired icon sizes */ typedef struct { uint32_t min_width, min_height; @@ -1152,6 +1156,41 @@ winMultiWindowXMsgProc(void *pArg) */ intern_atom(pProcArg->conn, "WM_STATE"); + /* + Enable Composite extension and redirect subwindows of the root window + */ + if (pProcArg->pWMInfo->fCompositeWM) { + const char *extension_name = "Composite"; + xcb_query_extension_cookie_t cookie; + xcb_query_extension_reply_t *reply; + + cookie = xcb_query_extension(pProcArg->conn, strlen(extension_name), extension_name); + reply = xcb_query_extension_reply(pProcArg->conn, cookie, NULL); + + if (reply && (reply->present)) { + xcb_composite_redirect_subwindows(pProcArg->conn, + root_window_id, + XCB_COMPOSITE_REDIRECT_AUTOMATIC); + + /* + We use automatic updating of the root window for two + reasons: + + 1) redirected window contents are mirrored to the root + window so that the root window draws correctly when shown. + + 2) updating the root window causes damage against the + shadow framebuffer, which ultimately causes WM_PAINT to be + sent to the affected window(s) to cause the damage regions + to be redrawn. + */ + + ErrorF("Using Composite redirection\n"); + + free(reply); + } + } + /* Loop until we explicitly break out */ while (1) { xcb_generic_event_t *event; @@ -1351,7 +1390,7 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen) + int dwScreen, HWND hwndScreen, Bool compositeWM) { WMProcArgPtr pArg = malloc(sizeof(WMProcArgRec)); WMInfoPtr pWMInfo = malloc(sizeof(WMInfoRec)); @@ -1373,6 +1412,7 @@ winInitWM(void **ppWMInfo, /* Set a return pointer to the Window Manager info structure */ *ppWMInfo = pWMInfo; + pWMInfo->fCompositeWM = compositeWM; /* Setup the argument structure for the thread function */ pArg->dwScreen = dwScreen; diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c index 5dd878c30..e849cbc97 100644 --- a/hw/xwin/winprocarg.c +++ b/hw/xwin/winprocarg.c @@ -128,6 +128,7 @@ winInitializeScreenDefaults(void) defaultScreenInfo.fDecoration = TRUE; defaultScreenInfo.fRootless = FALSE; defaultScreenInfo.fMultiWindow = FALSE; + defaultScreenInfo.fCompositeWM = TRUE; defaultScreenInfo.fMultiMonitorOverride = FALSE; defaultScreenInfo.fMultipleMonitors = FALSE; defaultScreenInfo.fLessPointer = FALSE; @@ -571,6 +572,25 @@ ddxProcessArgument(int argc, char *argv[], int i) return 1; } + /* + * Look for the '-compositewm' argument + */ + if (IS_OPTION("-compositewm")) { + screenInfoPtr->fCompositeWM = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + /* + * Look for the '-nocompositewm' argument + */ + if (IS_OPTION("-nocompositewm")) { + screenInfoPtr->fCompositeWM = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + /* * Look for the '-multiplemonitors' argument */ diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c index d6a1fedc7..fdaa1d6b3 100644 --- a/hw/xwin/winscrinit.c +++ b/hw/xwin/winscrinit.c @@ -461,6 +461,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) if (pScreenInfo->fMultiWindow) { + if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { + ErrorF("-compositewm disabled due to 8bpp depth\n"); + pScreenInfo->fCompositeWM = FALSE; + } + #if CYGDEBUG || YES winDebug("winFinishScreenInitFB - Calling winInitWM.\n"); #endif @@ -471,7 +476,8 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) &pScreenPriv->ptXMsgProc, &pScreenPriv->pmServerStarted, pScreenInfo->dwScreen, - (HWND) &pScreenPriv->hwndScreen)) { + (HWND) &pScreenPriv->hwndScreen, + pScreenInfo->fCompositeWM)) { ErrorF("winFinishScreenInitFB - winInitWM () failed.\n"); return FALSE; } diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index 7c3e880dc..0235d1b2c 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -826,6 +826,70 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) return 0; } +#ifdef COMPOSITE + if (pWin->redirectDraw != RedirectDrawNone) { + HBITMAP hBitmap; + HDC hdcPixmap; + PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); + + /* + This is kind of clunky, and possibly not very efficient. + + Would it be more efficient to only create the DIB bitmap when the + composite bitmap is realloced and store it in a window private? + + But we still end up copying and converting all the bits from the + window pixmap into a DDB for every update. + + Perhaps better still would be to wrap the screen CreatePixmap routine + so it uses CreateDIBSection()? + */ + + BITMAPV4HEADER bmih; + memset(&bmih, 0, sizeof(bmih)); + bmih.bV4Size = sizeof(BITMAPV4HEADER); + bmih.bV4Width = pPixmap->drawable.width; + bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */ + bmih.bV4Planes = 1; + bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel; + bmih.bV4SizeImage = 0; + /* window pixmap format is the same as the screen pixmap */ + assert(pPixmap->drawable.bitsPerPixel > 8); + bmih.bV4V4Compression = BI_BITFIELDS; + bmih.bV4RedMask = pScreenPriv->dwRedMask; + bmih.bV4GreenMask = pScreenPriv->dwGreenMask; + bmih.bV4BlueMask = pScreenPriv->dwBlueMask; + bmih.bV4AlphaMask = 0; + + /* Create the window bitmap from the pixmap */ + hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen, + (BITMAPINFOHEADER *)&bmih, CBM_INIT, + pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih, + DIB_RGB_COLORS); + + /* Select the window bitmap into a screen-compatible DC */ + hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen); + SelectObject(hdcPixmap, hBitmap); + + /* Blt from the window bitmap to the invalidated region */ + if (!BitBlt(hdcUpdate, + ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - ps.rcPaint.top, + hdcPixmap, + ps.rcPaint.left + pWin->borderWidth, + ps.rcPaint.top + pWin->borderWidth, + SRCCOPY)) + ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n", + GetLastError()); + + /* Release */ + DeleteDC(hdcPixmap); + DeleteObject(hBitmap); + } + else +#endif + { /* Try to copy from the shadow buffer to the invalidated region */ if (!BitBlt(hdcUpdate, ps.rcPaint.left, ps.rcPaint.top, @@ -850,6 +914,7 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) (LPSTR) lpMsgBuf); LocalFree(lpMsgBuf); } + } /* EndPaint frees the DC */ EndPaint(hWnd, &ps); diff --git a/hw/xwin/winvalargs.c b/hw/xwin/winvalargs.c index 585544eab..008c111a6 100644 --- a/hw/xwin/winvalargs.c +++ b/hw/xwin/winvalargs.c @@ -155,6 +155,14 @@ winValidateArgs(void) "-scrollbars, -resize, -nodecoration, or -lesspointer.\n"); return FALSE; } + + /* Ignore -swcursor if -multiwindow -compositewm is requested */ + if (g_ScreenInfo[i].fMultiWindow && g_ScreenInfo[i].fCompositeWM) { + if (g_fSoftwareCursor) { + g_fSoftwareCursor = FALSE; + winMsg(X_WARNING, "Ignoring -swcursor due to -compositewm\n"); + } + } } winDebug("winValidateArgs - Returning.\n"); diff --git a/hw/xwin/winwindow.h b/hw/xwin/winwindow.h index 959ce152a..402b9e63c 100644 --- a/hw/xwin/winwindow.h +++ b/hw/xwin/winwindow.h @@ -144,7 +144,7 @@ winInitWM(void **ppWMInfo, pthread_t * ptWMProc, pthread_t * ptXMsgProc, pthread_mutex_t * ppmServerStarted, - int dwScreen, HWND hwndScreen); + int dwScreen, HWND hwndScreen, Bool compositeWM); void winDeinitMultiWindowWM(void); From 6865fe71477206d989f982235fc32be4ff164ccd Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Mon, 10 Aug 2015 20:16:16 +0100 Subject: [PATCH 24/38] hw/xwin: Avoid artefacts when resizing a window Fill the area outside the current window size with black, rather than leaking framebuffer contents or leaving it undrawn. --- hw/xwin/winshadgdi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index 0235d1b2c..24fff71f3 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -916,6 +916,30 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) } } + /* If part of the invalidated region is outside the window (which can happen + if the native window is being re-sized), fill that area with black */ + if (ps.rcPaint.right > ps.rcPaint.left + pWin->drawable.width) { + BitBlt(hdcUpdate, + ps.rcPaint.left + pWin->drawable.width, + ps.rcPaint.top, + ps.rcPaint.right - (ps.rcPaint.left + pWin->drawable.width), + ps.rcPaint.bottom - ps.rcPaint.top, + NULL, + 0, 0, + BLACKNESS); + } + + if (ps.rcPaint.bottom > ps.rcPaint.top + pWin->drawable.height) { + BitBlt(hdcUpdate, + ps.rcPaint.left, + ps.rcPaint.top + pWin->drawable.height, + ps.rcPaint.right - ps.rcPaint.left, + ps.rcPaint.bottom - (ps.rcPaint.top + pWin->drawable.height), + NULL, + 0, 0, + BLACKNESS); + } + /* EndPaint frees the DC */ EndPaint(hWnd, &ps); From f67918353a14dad8aa75c965e036d106e7d2d1a4 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Sat, 7 Nov 2015 19:44:09 +0000 Subject: [PATCH 25/38] hw/xwin: Improve performance of -compositewm I think that a major cost in the current implementation is doing a CreateDIBSection()/DestroyObject() on every refresh. So provide our own CreatePixmap() instead, which does the CreateDIBSection(), once. Testcase: glxgears or foobillard with direct swrast Testcase: scrolling in a full-screen xterm v2: Fix handling of RENDER Scratch Pixmaps (A problem easily shown with gitk or emacs) v3: Note that we don't own screen pixmap to release in DestroyPixmap Log if unimplemented slow-path ever gets hit --- hw/xwin/win.h | 19 ++- hw/xwin/winmultiwindowwindow.c | 256 +++++++++++++++++++++++++++++++++ hw/xwin/winscrinit.c | 17 ++- hw/xwin/winshadgdi.c | 46 ++---- 4 files changed, 297 insertions(+), 41 deletions(-) diff --git a/hw/xwin/win.h b/hw/xwin/win.h index b667ceb66..8eabeae31 100644 --- a/hw/xwin/win.h +++ b/hw/xwin/win.h @@ -296,11 +296,10 @@ typedef Bool (*winCreateScreenResourcesProc) (ScreenPtr); */ typedef struct { - HDC hdcSelected; HBITMAP hBitmap; - BYTE *pbBits; - DWORD dwScanlineBytes; + void *pbBits; BITMAPINFOHEADER *pbmih; + BOOL owned; } winPrivPixmapRec, *winPrivPixmapPtr; /* @@ -511,6 +510,7 @@ typedef struct _winPrivScreenRec { ResizeWindowProcPtr ResizeWindow; MoveWindowProcPtr MoveWindow; SetShapeProcPtr SetShape; + ModifyPixmapHeaderProcPtr ModifyPixmapHeader; winCursorRec cursor; @@ -946,6 +946,19 @@ void winCopyWindowMultiWindow(WindowPtr pWin, DDXPointRec oldpt, RegionPtr oldRegion); +PixmapPtr +winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint); +Bool +winDestroyPixmapMultiwindow(PixmapPtr pPixmap); + +Bool +winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, int devKind, void *pPixData); + XID winGetWindowID(WindowPtr pWin); diff --git a/hw/xwin/winmultiwindowwindow.c b/hw/xwin/winmultiwindowwindow.c index 4ec5634af..4eec72be2 100644 --- a/hw/xwin/winmultiwindowwindow.c +++ b/hw/xwin/winmultiwindowwindow.c @@ -960,3 +960,259 @@ winAdjustXWindow(WindowPtr pWin, HWND hwnd) #undef WIDTH #undef HEIGHT } + +/* + Helper function for creating a DIB to back a pixmap + */ +static HBITMAP winCreateDIB(ScreenPtr pScreen, int width, int height, int bpp, void **ppvBits, BITMAPINFOHEADER **ppbmih) +{ + winScreenPriv(pScreen); + BITMAPV4HEADER *pbmih = NULL; + HBITMAP hBitmap = NULL; + + /* Allocate bitmap info header */ + pbmih = malloc(sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD)); + if (pbmih == NULL) { + ErrorF("winCreateDIB: malloc() failed\n"); + return NULL; + } + memset(pbmih, 0, sizeof(BITMAPV4HEADER) + 256 * sizeof(RGBQUAD)); + + /* Describe bitmap to be created */ + pbmih->bV4Size = sizeof(BITMAPV4HEADER); + pbmih->bV4Width = width; + pbmih->bV4Height = -height; /* top-down bitmap */ + pbmih->bV4Planes = 1; + pbmih->bV4BitCount = bpp; + if (bpp == 1) { + RGBQUAD *bmiColors = (RGBQUAD *)((char *)pbmih + sizeof(BITMAPV4HEADER)); + pbmih->bV4V4Compression = BI_RGB; + bmiColors[1].rgbBlue = 255; + bmiColors[1].rgbGreen = 255; + bmiColors[1].rgbRed = 255; + } + else if (bpp == 8) { + pbmih->bV4V4Compression = BI_RGB; + pbmih->bV4ClrUsed = 0; + } + else if (bpp == 16) { + pbmih->bV4V4Compression = BI_RGB; + pbmih->bV4ClrUsed = 0; + } + else if (bpp == 32) { + pbmih->bV4V4Compression = BI_BITFIELDS; + pbmih->bV4RedMask = pScreenPriv->dwRedMask; + pbmih->bV4GreenMask = pScreenPriv->dwGreenMask; + pbmih->bV4BlueMask = pScreenPriv->dwBlueMask; + pbmih->bV4AlphaMask = 0; + } + else { + ErrorF("winCreateDIB: %d bpp unhandled\n", bpp); + } + + /* Create a DIB with a bit pointer */ + hBitmap = CreateDIBSection(NULL, + (BITMAPINFO *) pbmih, + DIB_RGB_COLORS, ppvBits, NULL, 0); + if (hBitmap == NULL) { + ErrorF("winCreateDIB: CreateDIBSection() failed\n"); + return NULL; + } + + /* Store the address of the BMIH in the ppbmih parameter */ + *ppbmih = (BITMAPINFOHEADER *)pbmih; + + winDebug("winCreateDIB: HBITMAP %p pBMIH %p pBits %p\n", hBitmap, pbmih, *ppvBits); + + return hBitmap; +} + + +/* + * CreatePixmap - See Porting Layer Definition + */ +PixmapPtr +winCreatePixmapMultiwindow(ScreenPtr pScreen, int width, int height, int depth, + unsigned usage_hint) +{ + winPrivPixmapPtr pPixmapPriv = NULL; + PixmapPtr pPixmap = NULL; + int bpp, paddedwidth; + + /* allocate Pixmap header and privates */ + pPixmap = AllocatePixmap(pScreen, 0); + if (!pPixmap) + return NullPixmap; + + bpp = BitsPerPixel(depth); + /* + DIBs have 4-byte aligned rows + + paddedwidth is the width in bytes, padded to align + + i.e. round up the number of bits used by a row so it is a multiple of 32, + then convert to bytes + */ + paddedwidth = (((bpp * width) + 31) & ~31)/8; + + /* setup Pixmap header */ + pPixmap->drawable.type = DRAWABLE_PIXMAP; + pPixmap->drawable.class = 0; + pPixmap->drawable.pScreen = pScreen; + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bpp; + pPixmap->drawable.id = 0; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = paddedwidth; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = NULL; // later set to pbBits + pPixmap->master_pixmap = NULL; +#ifdef COMPOSITE + pPixmap->screen_x = 0; + pPixmap->screen_y = 0; +#endif + pPixmap->usage_hint = usage_hint; + + /* Check for zero width or height pixmaps */ + if (width == 0 || height == 0) { + /* DIBs with a dimension of 0 aren't permitted, so don't try to allocate + a DIB, just set fields and return */ + return pPixmap; + } + + /* Initialize pixmap privates */ + pPixmapPriv = winGetPixmapPriv(pPixmap); + pPixmapPriv->hBitmap = NULL; + pPixmapPriv->pbBits = NULL; + pPixmapPriv->pbmih = NULL; + + /* Create a DIB for the pixmap */ + pPixmapPriv->hBitmap = winCreateDIB(pScreen, width, height, bpp, &pPixmapPriv->pbBits, &pPixmapPriv->pbmih); + pPixmapPriv->owned = TRUE; + + winDebug("winCreatePixmap: pPixmap %p HBITMAP %p pBMIH %p pBits %p\n", pPixmap, pPixmapPriv->hBitmap, pPixmapPriv->pbmih, pPixmapPriv->pbBits); + /* XXX: so why do we need this in privates ??? */ + pPixmap->devPrivate.ptr = pPixmapPriv->pbBits; + + return pPixmap; +} + +/* + * DestroyPixmap - See Porting Layer Definition + */ +Bool +winDestroyPixmapMultiwindow(PixmapPtr pPixmap) +{ + winPrivPixmapPtr pPixmapPriv = NULL; + + /* Bail early if there is not a pixmap to destroy */ + if (pPixmap == NULL) { + return TRUE; + } + + /* Decrement reference count, return if nonzero */ + --pPixmap->refcnt; + if (pPixmap->refcnt != 0) + return TRUE; + + winDebug("winDestroyPixmap: pPixmap %p\n", pPixmap); + + /* Get a handle to the pixmap privates */ + pPixmapPriv = winGetPixmapPriv(pPixmap); + + /* Nothing to do if we don't own the DIB */ + if (!pPixmapPriv->owned) + return TRUE; + + /* Free GDI bitmap */ + if (pPixmapPriv->hBitmap) + DeleteObject(pPixmapPriv->hBitmap); + + /* Free the bitmap info header memory */ + free(pPixmapPriv->pbmih); + pPixmapPriv->pbmih = NULL; + + /* Free the pixmap memory */ + free(pPixmap); + pPixmap = NULL; + + return TRUE; +} + +/* + * ModifyPixmapHeader - See Porting Layer Definition + */ +Bool +winModifyPixmapHeaderMultiwindow(PixmapPtr pPixmap, + int width, + int height, + int depth, + int bitsPerPixel, int devKind, void *pPixData) +{ + int i; + winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap); + Bool fResult; + + /* reinitialize everything */ + pPixmap->drawable.depth = depth; + pPixmap->drawable.bitsPerPixel = bitsPerPixel; + pPixmap->drawable.id = 0; + pPixmap->drawable.x = 0; + pPixmap->drawable.y = 0; + pPixmap->drawable.width = width; + pPixmap->drawable.height = height; + pPixmap->devKind = devKind; + pPixmap->refcnt = 1; + pPixmap->devPrivate.ptr = pPixData; + pPixmap->drawable.serialNumber = NEXT_SERIAL_NUMBER; + + /* + This can be used for some out-of-order initialization on the screen + pixmap, which is the only case we can properly support. + */ + + /* Look for which screen this pixmap corresponds to */ + for (i = 0; i < screenInfo.numScreens; i++) { + ScreenPtr pScreen = screenInfo.screens[i]; + winScreenPriv(pScreen); + winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; + + if (pScreenInfo->pfb == pPixData) + { + /* and initialize pixmap privates from screen privates */ + pPixmapPriv->hBitmap = pScreenPriv->hbmpShadow; + pPixmapPriv->pbBits = pScreenInfo->pfb; + pPixmapPriv->pbmih = pScreenPriv->pbmih; + + /* mark these not to get released by DestroyPixmap */ + pPixmapPriv->owned = FALSE; + + return TRUE; + } + } + + /* Otherwise, since creating a DIBSection from arbitrary memory is not + * possible, fallback to normal. If needed, we can create a DIBSection with + * a copy of the bits later (see comment about a potential slow-path in + * winBltExposedWindowRegionShadowGDI()). */ + pPixmapPriv->hBitmap = 0; + pPixmapPriv->pbBits = 0; + pPixmapPriv->pbmih = 0; + pPixmapPriv->owned = FALSE; + + winDebug("winModifyPixmapHeaderMultiwindow: falling back\n"); + + { + ScreenPtr pScreen = pPixmap->drawable.pScreen; + winScreenPriv(pScreen); + WIN_UNWRAP(ModifyPixmapHeader); + fResult = (*pScreen->ModifyPixmapHeader) (pPixmap, width, height, depth, bitsPerPixel, devKind, pPixData); + WIN_WRAP(ModifyPixmapHeader, winModifyPixmapHeaderMultiwindow); + } + + return fResult; +} diff --git a/hw/xwin/winscrinit.c b/hw/xwin/winscrinit.c index fdaa1d6b3..9c0473019 100644 --- a/hw/xwin/winscrinit.c +++ b/hw/xwin/winscrinit.c @@ -258,6 +258,11 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) return FALSE; } + if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { + ErrorF("-compositewm disabled due to 8bpp depth\n"); + pScreenInfo->fCompositeWM = FALSE; + } + /* Apparently we need this for the render extension */ miSetPixmapDepths(); @@ -417,6 +422,7 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) WRAP(MoveWindow); WRAP(CopyWindow); WRAP(SetShape); + WRAP(ModifyPixmapHeader); /* Assign multi-window window procedures to be top level procedures */ pScreen->CreateWindow = winCreateWindowMultiWindow; @@ -432,6 +438,12 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) pScreen->CopyWindow = winCopyWindowMultiWindow; pScreen->SetShape = winSetShapeMultiWindow; + if (pScreenInfo->fCompositeWM) { + pScreen->CreatePixmap = winCreatePixmapMultiwindow; + pScreen->DestroyPixmap = winDestroyPixmapMultiwindow; + pScreen->ModifyPixmapHeader = winModifyPixmapHeaderMultiwindow; + } + /* Undefine the WRAP macro, as it is not needed elsewhere */ #undef WRAP } @@ -461,11 +473,6 @@ winFinishScreenInitFB(int i, ScreenPtr pScreen, int argc, char **argv) if (pScreenInfo->fMultiWindow) { - if ((pScreenInfo->dwBPP == 8) && (pScreenInfo->fCompositeWM)) { - ErrorF("-compositewm disabled due to 8bpp depth\n"); - pScreenInfo->fCompositeWM = FALSE; - } - #if CYGDEBUG || YES winDebug("winFinishScreenInitFB - Calling winInitWM.\n"); #endif diff --git a/hw/xwin/winshadgdi.c b/hw/xwin/winshadgdi.c index 24fff71f3..65678962b 100644 --- a/hw/xwin/winshadgdi.c +++ b/hw/xwin/winshadgdi.c @@ -831,41 +831,22 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) HBITMAP hBitmap; HDC hdcPixmap; PixmapPtr pPixmap = (*pScreen->GetWindowPixmap) (pWin); + winPrivPixmapPtr pPixmapPriv = winGetPixmapPriv(pPixmap); - /* - This is kind of clunky, and possibly not very efficient. - - Would it be more efficient to only create the DIB bitmap when the - composite bitmap is realloced and store it in a window private? - - But we still end up copying and converting all the bits from the - window pixmap into a DDB for every update. - - Perhaps better still would be to wrap the screen CreatePixmap routine - so it uses CreateDIBSection()? - */ - - BITMAPV4HEADER bmih; - memset(&bmih, 0, sizeof(bmih)); - bmih.bV4Size = sizeof(BITMAPV4HEADER); - bmih.bV4Width = pPixmap->drawable.width; - bmih.bV4Height = -pPixmap->drawable.height; /* top-down bitmap */ - bmih.bV4Planes = 1; - bmih.bV4BitCount = pPixmap->drawable.bitsPerPixel; - bmih.bV4SizeImage = 0; /* window pixmap format is the same as the screen pixmap */ assert(pPixmap->drawable.bitsPerPixel > 8); - bmih.bV4V4Compression = BI_BITFIELDS; - bmih.bV4RedMask = pScreenPriv->dwRedMask; - bmih.bV4GreenMask = pScreenPriv->dwGreenMask; - bmih.bV4BlueMask = pScreenPriv->dwBlueMask; - bmih.bV4AlphaMask = 0; - /* Create the window bitmap from the pixmap */ - hBitmap = CreateDIBitmap(pScreenPriv->hdcScreen, - (BITMAPINFOHEADER *)&bmih, CBM_INIT, - pPixmap->devPrivate.ptr, (BITMAPINFO *)&bmih, - DIB_RGB_COLORS); + /* Get the window bitmap from the pixmap */ + hBitmap = pPixmapPriv->hBitmap; + + /* XXX: There may be a need for a slow-path here: If hBitmap is NULL + (because we couldn't back the pixmap with a Windows DIB), we should + fall-back to creating a Windows DIB from the pixmap, then deleting it + after the BitBlt (as this this code did before the fast-path was + added). */ + if (!hBitmap) { + ErrorF("winBltExposedWindowRegionShadowGDI - slow path unimplemented\n"); + } /* Select the window bitmap into a screen-compatible DC */ hdcPixmap = CreateCompatibleDC(pScreenPriv->hdcScreen); @@ -883,9 +864,8 @@ winBltExposedWindowRegionShadowGDI(ScreenPtr pScreen, WindowPtr pWin) ErrorF("winBltExposedWindowRegionShadowGDI - BitBlt failed: 0x%08x\n", GetLastError()); - /* Release */ + /* Release DC */ DeleteDC(hdcPixmap); - DeleteObject(hBitmap); } else #endif From 2e1bc743734cc1e1043c8f2c9497a5a172507bc9 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Tue, 1 Dec 2015 19:33:38 +0000 Subject: [PATCH 26/38] hw/xwin: Set convenience variables for WM_CREATE as well Set convenience variables in winTopLevelWindowProc() for WM_CREATE as well. --- hw/xwin/winmultiwindowwndproc.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c index 1cac4a9f4..48e9f9dd8 100644 --- a/hw/xwin/winmultiwindowwndproc.c +++ b/hw/xwin/winmultiwindowwndproc.c @@ -322,6 +322,20 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) lParam); #endif + /* + If this is WM_CREATE, set up the Windows window properties which point to + X window information, before we populate local convenience variables... + */ + if (message == WM_CREATE) { + SetProp(hwnd, + WIN_WINDOW_PROP, + (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams); + SetProp(hwnd, + WIN_WID_PROP, + (HANDLE) (INT_PTR)winGetWindowID(((LPCREATESTRUCT) lParam)-> + lpCreateParams)); + } + /* Check if the Windows window property for our X window pointer is valid */ if ((pWin = GetProp(hwnd, WIN_WINDOW_PROP)) != NULL) { /* Our X window pointer is valid */ @@ -382,18 +396,6 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Branch on message type */ switch (message) { case WM_CREATE: - - /* */ - SetProp(hwnd, - WIN_WINDOW_PROP, - (HANDLE) ((LPCREATESTRUCT) lParam)->lpCreateParams); - - /* */ - SetProp(hwnd, - WIN_WID_PROP, - (HANDLE) (INT_PTR) winGetWindowID(((LPCREATESTRUCT) lParam)-> - lpCreateParams)); - /* * Make X windows' Z orders sync with Windows windows because * there can be AlwaysOnTop windows overlapped on the window From 2afee831a439add6cca5b7fa8c76a9de4326b2b7 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 5 Jan 2017 13:17:59 +0000 Subject: [PATCH 27/38] hw/xwin: Add an option to use alpha channel in multiwindow mode Add an option to turn on the use of the X window's alpha channel in multiwindow mode, i.e. this uses the X window's alpha channel for compositing into the native desktop. This works on W7/Vista (using DwmEnableBlurBehindWindow()), and Windows 10 (using the undocumented SetWindowCompositionAttribute()), but not on Windows 8/8.1 -compositewm must be enabled for this to be useful, as we only have a pixmap with an alpha channel for the X window in that case. The framebuffer/root window doesn't have one (unless perhaps you are using the rootless extension, maybe...). v2: Update meson.build Future work: A window property to control use of alpha? Option to turn off blur on W7/Vista Implement _NET_WM_WINDOW_OPACITY --- doc/c-extensions | 2 +- hw/xwin/InitOutput.c | 4 +- hw/xwin/Makefile.am | 2 +- hw/xwin/man/XWin.man | 9 +++ hw/xwin/meson.build | 2 +- hw/xwin/winglobals.c | 1 + hw/xwin/winglobals.h | 1 + hw/xwin/winmultiwindowwndproc.c | 121 ++++++++++++++++++++++++++++++++ hw/xwin/winprocarg.c | 19 +++++ 9 files changed, 157 insertions(+), 4 deletions(-) diff --git a/doc/c-extensions b/doc/c-extensions index e5fde3440..7dc58a215 100644 --- a/doc/c-extensions +++ b/doc/c-extensions @@ -62,7 +62,7 @@ TODO: Solaris. TODO: *BSD. -Windows-dependent code assumes at least NT 5.1. +Windows-dependent code assumes at least NT 6.0. OSX support is generally limited to the most recent version. Currently that means 10.5. diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index 00053beb0..250051425 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -716,6 +716,8 @@ winUseMsg(void) "\tthe updated region when num_boxes, or more, are in the\n" "\tupdated region.\n"); + ErrorF("-[no]compositealpha\n" + "\tX windows with per-pixel alpha are composited into the Windows desktop.\n"); ErrorF("-[no]compositewm\n" "\tUse the Composite extension to keep a bitmap image of each top-level\n" "\tX window, so window contents which are occluded show correctly in\n" @@ -803,7 +805,7 @@ winUseMsg(void) "\tSpecify an optional refresh rate to use in fullscreen mode\n" "\twith a DirectDraw engine.\n"); - ErrorF("-resize=none|scrollbars|randr" + ErrorF("-resize=none|scrollbars|randr\n" "\tIn windowed mode, [don't] allow resizing of the window. 'scrollbars'\n" "\tmode gives the window scrollbars as needed, 'randr' mode uses the RANR\n" "\textension to resize the X screen. 'randr' is the default.\n"); diff --git a/hw/xwin/Makefile.am b/hw/xwin/Makefile.am index 42fc9dd68..6ef89196a 100644 --- a/hw/xwin/Makefile.am +++ b/hw/xwin/Makefile.am @@ -27,7 +27,7 @@ SRCS_MULTIWINDOW = \ winmultiwindowwndproc.c \ propertystore.h \ winSetAppUserModelID.c -MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32 +MULTIWINDOW_SYS_LIBS = -lshlwapi -lole32 -ldwmapi SRCS_RANDR = \ winrandr.c diff --git a/hw/xwin/man/XWin.man b/hw/xwin/man/XWin.man index e61589e8e..f9305f592 100644 --- a/hw/xwin/man/XWin.man +++ b/hw/xwin/man/XWin.man @@ -176,6 +176,15 @@ Use Composite extension redirection to maintain a bitmap image of each top-level X window, so window contents which are occluded show correctly in task bar and task switcher previews. The default is enabled. +.TP 8 +.B \-[no]compositealpha +X windows with per-pixel alpha are composited into the \fIWindows\fP desktop +(i.e. a \fIWindows\fP window can be seen through any transparency in an X window +placed over it). + +This option has no effect on Windows 8 and 8.1. +This option has no effect if \fB-compositewm\fP is disabled. +The default is disabled. .SH OPTIONS CONTROLLING WINDOWS INTEGRATION .TP 8 diff --git a/hw/xwin/meson.build b/hw/xwin/meson.build index 3462c396d..c1a2917b8 100644 --- a/hw/xwin/meson.build +++ b/hw/xwin/meson.build @@ -44,7 +44,7 @@ srcs_windows += [ 'propertystore.h', 'winSetAppUserModelID.c', ] -xwin_sys_libs += ['-lshlwapi', '-lole32'] +xwin_sys_libs += ['-lshlwapi', '-lole32', '-ldwmapi'] srcs_windows += [ 'winrandr.c', diff --git a/hw/xwin/winglobals.c b/hw/xwin/winglobals.c index d1a0d4587..3212c6beb 100644 --- a/hw/xwin/winglobals.c +++ b/hw/xwin/winglobals.c @@ -59,6 +59,7 @@ HWND g_hDlgAbout = NULL; const char *g_pszQueryHost = NULL; Bool g_fXdmcpEnabled = FALSE; Bool g_fAuthEnabled = FALSE; +Bool g_fCompositeAlpha = FALSE; HICON g_hIconX = NULL; HICON g_hSmallIconX = NULL; diff --git a/hw/xwin/winglobals.h b/hw/xwin/winglobals.h index 82fc1c5ec..77af6125a 100644 --- a/hw/xwin/winglobals.h +++ b/hw/xwin/winglobals.h @@ -50,6 +50,7 @@ extern Bool g_fLogInited; extern Bool g_fAuthEnabled; extern Bool g_fXdmcpEnabled; +extern Bool g_fCompositeAlpha; extern Bool g_fNoHelpMessageBox; extern Bool g_fNativeGl; diff --git a/hw/xwin/winmultiwindowwndproc.c b/hw/xwin/winmultiwindowwndproc.c index 48e9f9dd8..587884d11 100644 --- a/hw/xwin/winmultiwindowwndproc.c +++ b/hw/xwin/winmultiwindowwndproc.c @@ -35,12 +35,18 @@ #ifdef HAVE_XWIN_CONFIG_H #include #endif + #include "win.h" #include "dixevents.h" #include "winmultiwindowclass.h" #include "winprefs.h" #include "winmsg.h" #include "inputstr.h" +#include + +#ifndef WM_DWMCOMPOSITIONCHANGED +#define WM_DWMCOMPOSITIONCHANGED 0x031e +#endif extern void winUpdateWindowPosition(HWND hWnd, HWND * zstyle); @@ -294,6 +300,113 @@ winStartMousePolling(winPrivScreenPtr s_pScreenPriv) MOUSE_POLLING_INTERVAL, NULL); } +/* Undocumented */ +typedef struct _ACCENTPOLICY +{ + ULONG AccentState; + ULONG AccentFlags; + ULONG GradientColor; + ULONG AnimationId; +} ACCENTPOLICY; + +#define ACCENT_ENABLE_BLURBEHIND 3 + +typedef struct _WINCOMPATTR +{ + DWORD attribute; + PVOID pData; + ULONG dataSize; +} WINCOMPATTR; + +#define WCA_ACCENT_POLICY 19 + +typedef WINBOOL WINAPI (*PFNSETWINDOWCOMPOSITIONATTRIBUTE)(HWND, WINCOMPATTR *); + +static void +CheckForAlpha(HWND hWnd, WindowPtr pWin, winScreenInfo *pScreenInfo) +{ + /* Check (once) which API we should use */ + static Bool doOnce = TRUE; + static PFNSETWINDOWCOMPOSITIONATTRIBUTE pSetWindowCompositionAttribute = NULL; + static Bool useDwmEnableBlurBehindWindow = FALSE; + + if (doOnce) + { + OSVERSIONINFOEX osvi = {0}; + osvi.dwOSVersionInfoSize = sizeof(osvi); + GetVersionEx((LPOSVERSIONINFO)&osvi); + + /* SetWindowCompositionAttribute() exists on Windows 7 and later, + but doesn't work for this purpose, so first check for Windows 10 + or later */ + if (osvi.dwMajorVersion >= 10) + { + HMODULE hUser32 = GetModuleHandle("user32"); + + if (hUser32) + pSetWindowCompositionAttribute = (PFNSETWINDOWCOMPOSITIONATTRIBUTE) GetProcAddress(hUser32, "SetWindowCompositionAttribute"); + winDebug("SetWindowCompositionAttribute %s\n", pSetWindowCompositionAttribute ? "found" : "not found"); + } + /* On Windows 7 and Windows Vista, use DwmEnableBlurBehindWindow() */ + else if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion <= 1)) + { + useDwmEnableBlurBehindWindow = TRUE; + } + /* On Windows 8 and Windows 8.1, using the alpha channel on those + seems near impossible, so we don't do anything. */ + + doOnce = FALSE; + } + + /* alpha-channel use is wanted */ + if (!g_fCompositeAlpha || !pScreenInfo->fCompositeWM) + return; + + /* Image has alpha ... */ + if (pWin->drawable.depth != 32) + return; + + /* ... and we can do something useful with it? */ + if (pSetWindowCompositionAttribute) + { + WINBOOL rc; + /* Use the (undocumented) SetWindowCompositionAttribute, if + available, to turn on alpha channel use on Windows 10. */ + ACCENTPOLICY policy = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 } ; + WINCOMPATTR data = { WCA_ACCENT_POLICY, &policy, sizeof(ACCENTPOLICY) }; + + /* This turns on DWM looking at the alpha-channel of this window */ + winDebug("enabling alpha for XID %08x hWnd %p, using SetWindowCompositionAttribute()\n", (unsigned int)pWin->drawable.id, hWnd); + rc = pSetWindowCompositionAttribute(hWnd, &data); + if (!rc) + ErrorF("SetWindowCompositionAttribute failed: %d\n", (int)GetLastError()); + } + else if (useDwmEnableBlurBehindWindow) + { + HRESULT rc; + WINBOOL enabled; + + rc = DwmIsCompositionEnabled(&enabled); + if ((rc == S_OK) && enabled) + { + /* Use DwmEnableBlurBehindWindow, to turn on alpha channel + use on Windows Vista and Windows 7 */ + DWM_BLURBEHIND bbh; + bbh.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION | DWM_BB_TRANSITIONONMAXIMIZED; + bbh.fEnable = TRUE; + bbh.hRgnBlur = NULL; + bbh.fTransitionOnMaximized = TRUE; /* What does this do ??? */ + + /* This terribly-named function actually controls if DWM + looks at the alpha channel of this window */ + winDebug("enabling alpha for XID %08x hWnd %p, using DwmEnableBlurBehindWindow()\n", (unsigned int)pWin->drawable.id, hWnd); + rc = DwmEnableBlurBehindWindow(hWnd, &bbh); + if (rc != S_OK) + ErrorF("DwmEnableBlurBehindWindow failed: %x, %d\n", (int)rc, (int)GetLastError()); + } + } +} + /* * winTopLevelWindowProc - Window procedure for all top-level Windows windows. */ @@ -416,6 +529,8 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) XMING_SIGNATURE); + CheckForAlpha(hwnd, pWin, s_pScreenInfo); + return 0; case WM_INIT_SYS_MENU: @@ -1114,6 +1229,12 @@ winTopLevelWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; + + case WM_DWMCOMPOSITIONCHANGED: + /* This message is only sent on Vista/W7 */ + CheckForAlpha(hwnd, pWin, s_pScreenInfo); + + return 0; default: break; } diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c index e849cbc97..29e91abc8 100644 --- a/hw/xwin/winprocarg.c +++ b/hw/xwin/winprocarg.c @@ -591,6 +591,25 @@ ddxProcessArgument(int argc, char *argv[], int i) return 1; } + /* + * Look for the '-compositealpha' argument + */ + if (IS_OPTION("-compositealpha")) { + g_fCompositeAlpha = TRUE; + + /* Indicate that we have processed this argument */ + return 1; + } + /* + * Look for the '-nocompositealpha' argument + */ + if (IS_OPTION("-nocompositealpha")) { + g_fCompositeAlpha = FALSE; + + /* Indicate that we have processed this argument */ + return 1; + } + /* * Look for the '-multiplemonitors' argument */ From 0dc0cef4959dfb16d8334f235150733e634e2ba9 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 18 Jun 2019 14:52:04 -0400 Subject: [PATCH 28/38] xwayland-glx: Fix GLX visual mask setup a2rgb10 configs would end up with channel masks corresponding to argb8888. This would confuse the GLX core code into matching an a2rgb10 config to the root window visual, and that would make things look wrong and bad. Fix this by handling more cases. We're still not fully general here, and this could still be wrong on big-endian. The XXX comment about doing something less ugly still applies, ideally we would get this information out of EGL instead of making lucky guesses. Still, better than it was. Fixes: xorg/xserver#824 --- hw/xwayland/xwayland-glx.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/hw/xwayland/xwayland-glx.c b/hw/xwayland/xwayland-glx.c index 71c9aad23..abf48f71c 100644 --- a/hw/xwayland/xwayland-glx.c +++ b/hw/xwayland/xwayland-glx.c @@ -246,14 +246,37 @@ translate_eglconfig(struct egl_screen *screen, EGLConfig hc, * XXX do something less ugly */ if (c->base.renderType == GLX_RGBA_BIT) { - if (c->base.rgbBits == 24 || c->base.rgbBits == 32) { - c->base.redMask = 0xff0000; - c->base.greenMask = 0x00ff00; - c->base.blueMask = 0x0000ff; + if (c->base.redBits == 5 && + (c->base.rgbBits == 15 || c->base.rgbBits == 16)) { + c->base.blueMask = 0x0000001f; + if (c->base.alphaBits) { + c->base.greenMask = 0x000003e0; + c->base.redMask = 0x00007c00; + c->base.alphaMask = 0x00008000; + } else { + c->base.greenMask = 0x000007e0; + c->base.redMask = 0x0000f800; + c->base.alphaMask = 0x00000000; + } + } + else if (c->base.redBits == 8 && + (c->base.rgbBits == 24 || c->base.rgbBits == 32)) { + c->base.blueMask = 0x000000ff; + c->base.greenMask = 0x0000ff00; + c->base.redMask = 0x00ff0000; if (c->base.alphaBits) /* assume all remaining bits are alpha */ c->base.alphaMask = 0xff000000; } + else if (c->base.redBits == 10 && + (c->base.rgbBits == 30 || c->base.rgbBits == 32)) { + c->base.blueMask = 0x000003ff; + c->base.greenMask = 0x000ffc00; + c->base.redMask = 0x3ff00000; + if (c->base.alphaBits) + /* assume all remaining bits are alpha */ + c->base.alphaMask = 0xc000000; + } } c->base.next = chain ? &chain->base : NULL; From 4a287cc2b6d849c29b43af07d93fa0048d8d6e90 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 18 Jun 2019 10:41:02 +0200 Subject: [PATCH 29/38] xwayland: Allow for regular transport types for listen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Xwayland uses the command line option “-listen” to pass file descriptors from the Wayland compositor. That breaks the traditional, documented behavior of the “-listen” command line option which is to enable a transport type. Checks if the given option starts with a digit, otherwise treat it as a regular transport type. Closes: https://gitlab.freedesktop.org/xorg/xserver/issues/817 Suggested-by: Rodrigo Exterckötter Tjäder Signed-off-by: Olivier Fourdan --- hw/xwayland/xwayland.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 739f86cf1..72b2be1b6 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -115,6 +115,10 @@ ddxProcessArgument(int argc, char *argv[], int i) else if (strcmp(argv[i], "-listen") == 0) { CHECK_FOR_REQUIRED_ARGUMENTS(1); + /* Not an FD */ + if (!isdigit(*argv[i + 1])) + return 0; + NoListenAll = TRUE; if (listen_fd_count == ARRAY_SIZE(listen_fds)) FatalError("Too many -listen arguments given, max is %zu\n", From b3f3d65ed302baf78befe45eed458e666e1ff143 Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Wed, 19 Jun 2019 09:19:24 +0200 Subject: [PATCH 30/38] xwayland: Add "-listenfd" option Using the existing command line option "-listen" for passing file descriptors between the Wayland compositor and Xwayland is misleading, Xwayland should add is own command line option for that specific use. As XWayland is spawned by the Wayland compositor, we cannot just change the option, as that would break all existing Wayland compositors using Xwayland, so we add a new options "-listenfd" and mark the previous one as deprecated and log a warning, but it still works for backward compatibility. Signed-off-by: Olivier Fourdan https://gitlab.freedesktop.org/xorg/xserver/merge_requests/214 --- hw/xwayland/xwayland.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c index 72b2be1b6..fe8b1abdc 100644 --- a/hw/xwayland/xwayland.c +++ b/hw/xwayland/xwayland.c @@ -98,7 +98,8 @@ ddxUseMsg(void) { ErrorF("-rootless run rootless, requires wm support\n"); ErrorF("-wm fd create X client for wm on given fd\n"); - ErrorF("-listen fd add give fd as a listen socket\n"); + ErrorF("-listenfd fd add give fd as a listen socket\n"); + ErrorF("-listen fd deprecated, use \"-listenfd\" instead\n"); ErrorF("-eglstream use eglstream backend for nvidia GPUs\n"); } @@ -106,6 +107,17 @@ static int wm_fd = -1; static int listen_fds[5] = { -1, -1, -1, -1, -1 }; static int listen_fd_count = 0; +static void +xwl_add_listen_fd(int argc, char *argv[], int i) +{ + NoListenAll = TRUE; + if (listen_fd_count == ARRAY_SIZE(listen_fds)) + FatalError("Too many -listen arguments given, max is %zu\n", + ARRAY_SIZE(listen_fds)); + + listen_fds[listen_fd_count++] = atoi(argv[i + 1]); +} + int ddxProcessArgument(int argc, char *argv[], int i) { @@ -119,12 +131,16 @@ ddxProcessArgument(int argc, char *argv[], int i) if (!isdigit(*argv[i + 1])) return 0; - NoListenAll = TRUE; - if (listen_fd_count == ARRAY_SIZE(listen_fds)) - FatalError("Too many -listen arguments given, max is %zu\n", - ARRAY_SIZE(listen_fds)); + LogMessage(X_WARNING, "Option \"-listen\" for file descriptors is deprecated\n" + "Please use \"-listenfd\" instead.\n"); - listen_fds[listen_fd_count++] = atoi(argv[i + 1]); + xwl_add_listen_fd (argc, argv, i); + return 2; + } + else if (strcmp(argv[i], "-listenfd") == 0) { + CHECK_FOR_REQUIRED_ARGUMENTS(1); + + xwl_add_listen_fd (argc, argv, i); return 2; } else if (strcmp(argv[i], "-wm") == 0) { From 9acff309434a8029bcce1b22530043459bb71791 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Wed, 19 Jun 2019 14:23:56 -0400 Subject: [PATCH 31/38] linux: Fix platform device PCI detection for complex bus topologies Suppose you're in a Hyper-V guest and are trying to use PCI passthrough. The ID_PATH that udev will construct for that looks something like "acpi-VMBUS:00-pci-b8c8:00:00.0", and obviously looking for "pci-" in the first four characters of that is going to not work. Instead, strstr. I suppose it's possible you could have _multiple_ PCI buses in the path, in which case you'd want strrstr, if that were a thing. --- config/udev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/udev.c b/config/udev.c index 314acba6c..6e11aa3b8 100644 --- a/config/udev.c +++ b/config/udev.c @@ -474,7 +474,7 @@ config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path config_odev_probe_proc_ptr probe_callback) { struct OdevAttributes *attribs = config_odev_allocate_attributes(); - const char *value; + const char *value, *str; attribs->path = XNFstrdup(path); attribs->syspath = XNFstrdup(syspath); @@ -482,8 +482,8 @@ config_udev_odev_setup_attribs(struct udev_device *udev_device, const char *path attribs->minor = minor; value = udev_device_get_property_value(udev_device, "ID_PATH"); - if (value && !strncmp(value, "pci-", 4)) { - attribs->busid = XNFstrdup(value); + if (value && (str = strstr(value, "pci-"))) { + attribs->busid = XNFstrdup(str); attribs->busid[3] = ':'; } From e39dc0f5b7c88c9ba670383658846a1f658cbc47 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Thu, 20 Jun 2019 12:15:31 -0400 Subject: [PATCH 32/38] present: Require presentproto 1.2 The PresentOptionSuboptimal support code is not optional (once you've enabled building Present at all), so require a protocol package version that defines what we need. Fixes: xorg/xserver#821 --- configure.ac | 2 +- present/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 55bb6942a..9148b94f4 100644 --- a/configure.ac +++ b/configure.ac @@ -754,7 +754,7 @@ DAMAGEPROTO="damageproto >= 1.1" XCMISCPROTO="xcmiscproto >= 1.2.0" BIGREQSPROTO="bigreqsproto >= 1.1.0" XTRANS="xtrans >= 1.3.5" -PRESENTPROTO="presentproto >= 1.1" +PRESENTPROTO="presentproto >= 1.2" dnl List of libraries that require a specific version LIBAPPLEWM="applewm >= 1.4" diff --git a/present/meson.build b/present/meson.build index e316af20d..3dc1fc04b 100644 --- a/present/meson.build +++ b/present/meson.build @@ -22,7 +22,7 @@ libxserver_present = static_library('libxserver_present', include_directories: inc, dependencies: [ common_dep, - dependency('presentproto', version: '>= 1.1') + dependency('presentproto', version: '>= 1.2') ], c_args: '-DHAVE_XORG_CONFIG_H' ) From 188f461463fcc60432f9d7a76ad69ec97631db5d Mon Sep 17 00:00:00 2001 From: Colin Harrison Date: Thu, 22 Feb 2018 13:18:42 +0000 Subject: [PATCH 33/38] hw/xwin: Add Russian keyboard layout --- hw/xwin/winlayouts.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xwin/winlayouts.h b/hw/xwin/winlayouts.h index c7905e3c2..0b02fa446 100644 --- a/hw/xwin/winlayouts.h +++ b/hw/xwin/winlayouts.h @@ -82,6 +82,7 @@ WinKBLayoutRec winKBLayouts[] = { {0x00000416, -1, "pc105", "br", NULL, NULL, "Portuguese (Brazil,ABNT)"}, {0x00010416, -1, "abnt2", "br", NULL, NULL, "Portuguese (Brazil,ABNT2)"}, {0x00000816, -1, "pc105", "pt", NULL, NULL, "Portuguese (Portugal)"}, + {0x00000419, -1, "pc105", "ru", NULL, NULL, "Russian"}, {0x0000041a, -1, "pc105", "hr", NULL, NULL, "Croatian"}, {0x0000041d, -1, "pc105", "se", NULL, NULL, "Swedish (Sweden)"}, {0x0000041f, -1, "pc105", "tr", NULL, NULL, "Turkish (Q)"}, From bfcaaecc552c7a3d85f6309b8079eb8e6fda8779 Mon Sep 17 00:00:00 2001 From: Colin Harrison Date: Sat, 30 Jun 2018 13:43:11 +0100 Subject: [PATCH 34/38] hw/xwin: Add the Belgian (Comma) keyboard layout --- hw/xwin/winlayouts.h | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/xwin/winlayouts.h b/hw/xwin/winlayouts.h index 0b02fa446..904410a2d 100644 --- a/hw/xwin/winlayouts.h +++ b/hw/xwin/winlayouts.h @@ -65,6 +65,7 @@ WinKBLayoutRec winKBLayouts[] = { {0x0000040b, -1, "pc105", "fi", NULL, NULL, "Finnish"}, {0x0000040c, -1, "pc105", "fr", NULL, NULL, "French (Standard)"}, {0x0000080c, -1, "pc105", "be", NULL, NULL, "French (Belgian)"}, + {0x0001080c, -1, "pc105", "be", NULL, NULL, "Belgian (Comma)"}, {0x00000c0c, -1, "pc105", "ca", "fr-legacy", NULL, "French (Canada, Legacy)"}, {0x0000100c, -1, "pc105", "ch", "fr", NULL, "French (Switzerland)"}, From 8f7e4b56d2e0abd09526c7d0eeee15bfb754e557 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Sun, 8 Oct 2017 22:17:40 +0100 Subject: [PATCH 35/38] hw/xwin: Fix transposed RaiseVolume and LowerVolume scan codes --- hw/xwin/winkeynames.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/xwin/winkeynames.h b/hw/xwin/winkeynames.h index bfed9d427..6159f623e 100644 --- a/hw/xwin/winkeynames.h +++ b/hw/xwin/winkeynames.h @@ -191,8 +191,8 @@ #define KEY_BSlash2 /* \ _ 0xcb */ 203 #define KEY_Mute /* Audio Mute */ 152 -#define KEY_AudioLower /* Audio Lower */ 168 -#define KEY_AudioRaise /* Audio Raise */ 166 +#define KEY_AudioLower /* Audio Lower */ 166 +#define KEY_AudioRaise /* Audio Raise */ 168 #define KEY_NEXTSONG /* Media next */ 145 #define KEY_PLAYPAUSE /* Media play/pause toggle */ 154 From b078e03410f5f2a004ab9732eb6e5ed24da3edcf Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Wed, 19 Apr 2017 14:50:38 +0100 Subject: [PATCH 36/38] hw/xwin: Make QueryMonitor() slightly less insane Make QueryMonitor() slightly less insane, making it return TRUE if the specified monitor exists, rather than always returning TRUE (which we are uselessly checking, and then also checking if the specified monitor exists) (Note that EnumDisplayMonitors() doesn't seem to have meaningful way to return errors, see 5940580f) Also: Spamming the long UseMsg() after "Invalid monitor number" isn't very helpful. Also: If we are exiting in ddxProcessArgument() due to an error in options, use a non-zero exit status. --- hw/xwin/InitOutput.c | 3 +-- hw/xwin/winmonitors.c | 4 ++-- hw/xwin/winprocarg.c | 29 ++++++----------------------- hw/xwin/winwndproc.c | 2 -- 4 files changed, 9 insertions(+), 29 deletions(-) diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c index 250051425..c336820df 100644 --- a/hw/xwin/InitOutput.c +++ b/hw/xwin/InitOutput.c @@ -981,8 +981,7 @@ InitOutput(ScreenInfo * pScreenInfo, int argc, char *argv[]) for (iMonitor = 1; ; iMonitor++) { struct GetMonitorInfoData data; - QueryMonitor(iMonitor, &data); - if (data.bMonitorSpecifiedExists) + if (QueryMonitor(iMonitor, &data)) { MONITORINFO mi; mi.cbSize = sizeof(MONITORINFO); diff --git a/hw/xwin/winmonitors.c b/hw/xwin/winmonitors.c index 955fb9214..5ff565308 100644 --- a/hw/xwin/winmonitors.c +++ b/hw/xwin/winmonitors.c @@ -39,7 +39,7 @@ from The Open Group. */ static - wBOOL CALLBACK +WINBOOL CALLBACK getMonitorInfo(HMONITOR hMonitor, HDC hdc, LPRECT rect, LPARAM _data) { struct GetMonitorInfoData *data = (struct GetMonitorInfoData *) _data; @@ -70,5 +70,5 @@ QueryMonitor(int i, struct GetMonitorInfoData *data) /* query information */ EnumDisplayMonitors(NULL, NULL, getMonitorInfo, (LPARAM) data); - return TRUE; + return data->bMonitorSpecifiedExists; } diff --git a/hw/xwin/winprocarg.c b/hw/xwin/winprocarg.c index 29e91abc8..cb03b00e0 100644 --- a/hw/xwin/winprocarg.c +++ b/hw/xwin/winprocarg.c @@ -309,11 +309,7 @@ ddxProcessArgument(int argc, char *argv[], int i) if (i + 2 < argc && 1 == sscanf(argv[i + 2], "@%d", (int *) &iMonitor)) { struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) { - ErrorF - ("ddxProcessArgument - screen - Querying monitors failed\n"); - } - else if (data.bMonitorSpecifiedExists == TRUE) { + if (QueryMonitor(iMonitor, &data)) { winErrorFVerb(2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); @@ -334,8 +330,7 @@ ddxProcessArgument(int argc, char *argv[], int i) ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); - UseMsg(); - exit(0); + exit(1); return 0; } } @@ -366,11 +361,7 @@ ddxProcessArgument(int argc, char *argv[], int i) (int *) &iMonitor)) { struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) { - ErrorF - ("ddxProcessArgument - screen - Querying monitors failed\n"); - } - else if (data.bMonitorSpecifiedExists == TRUE) { + if (QueryMonitor(iMonitor, &data)) { g_ScreenInfo[nScreenNum].iMonitor = iMonitor; g_ScreenInfo[nScreenNum].hMonitor = data.monitorHandle; g_ScreenInfo[nScreenNum].dwInitialX += @@ -383,11 +374,9 @@ ddxProcessArgument(int argc, char *argv[], int i) ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); - UseMsg(); - exit(0); + exit(1); return 0; } - } } @@ -395,11 +384,7 @@ ddxProcessArgument(int argc, char *argv[], int i) else if (1 == sscanf(argv[i + 2], "%*dx%*d@%d", (int *) &iMonitor)) { struct GetMonitorInfoData data; - if (!QueryMonitor(iMonitor, &data)) { - ErrorF - ("ddxProcessArgument - screen - Querying monitors failed\n"); - } - else if (data.bMonitorSpecifiedExists == TRUE) { + if (QueryMonitor(iMonitor, &data)) { winErrorFVerb(2, "ddxProcessArgument - screen - Found Valid ``@Monitor'' = %d arg\n", iMonitor); @@ -414,11 +399,9 @@ ddxProcessArgument(int argc, char *argv[], int i) ErrorF ("ddxProcessArgument - screen - Invalid monitor number %d\n", iMonitor); - UseMsg(); - exit(0); + exit(1); return 0; } - } } else if (i + 3 < argc && 1 == sscanf(argv[i + 2], "%d", (int *) &iWidth) diff --git a/hw/xwin/winwndproc.c b/hw/xwin/winwndproc.c index 16b5f0565..e375be9c1 100644 --- a/hw/xwin/winwndproc.c +++ b/hw/xwin/winwndproc.c @@ -238,7 +238,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) struct GetMonitorInfoData data; if (QueryMonitor(s_pScreenInfo->iMonitor, &data)) { - if (data.bMonitorSpecifiedExists == TRUE) { dwWidth = data.monitorWidth; dwHeight = data.monitorHeight; /* @@ -250,7 +249,6 @@ winWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) ErrorF("Monitor number %d no longer exists!\n", s_pScreenInfo->iMonitor); } - } } /* From 2549ab2065ad293139d4e82e5d5a5ea13f7257c9 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Fri, 9 Mar 2018 14:16:01 +0000 Subject: [PATCH 37/38] hw/xwin: Always keep RANDR fake mode information up to date The rrGetInfo hook is not called for all RANDR requests (e.g. RRGetOutputInfo), so we must always keep the fake mode information up to date, rather than doing it lazily in the rrGetInfo hook) Because we are so bad, most GTK+3 versions treat the output name 'default' specially, and don't try to use RANDR with it. But versions 3.21.6 to 3.22.24, don't do this, and get badly confused by a CRTC with size 0x0. See: https://bugzilla.gnome.org/show_bug.cgi?id=771033 https://bugzilla.gnome.org/show_bug.cgi?id=780101 Future work: Rather than reporting a single fake CRTC with a mode matching the entire virtual display, the fake CRTCs we report should match our 'pseudo-xinerama' monitors --- hw/xwin/winrandr.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/xwin/winrandr.c b/hw/xwin/winrandr.c index 16caea742..30b7c5f6b 100644 --- a/hw/xwin/winrandr.c +++ b/hw/xwin/winrandr.c @@ -42,17 +42,17 @@ static Bool winRandRGetInfo(ScreenPtr pScreen, Rotation * pRotations) { - rrScrPrivPtr pRRScrPriv; - RROutputPtr output; - - pRRScrPriv = rrGetScrPriv(pScreen); - output = pRRScrPriv->outputs[0]; - winDebug("winRandRGetInfo ()\n"); /* Don't support rotations */ *pRotations = RR_Rotate_0; + return TRUE; +} + +static void +winRandRUpdateMode(ScreenPtr pScreen, RROutputPtr output) +{ /* Delete previous mode */ if (output->modes[0]) { @@ -83,8 +83,6 @@ winRandRGetInfo(ScreenPtr pScreen, Rotation * pRotations) mode = RRModeGet(&modeInfo, name); output->crtc->mode = mode; } - - return TRUE; } /* @@ -95,6 +93,7 @@ winDoRandRScreenSetSize(ScreenPtr pScreen, CARD16 width, CARD16 height, CARD32 mmWidth, CARD32 mmHeight) { + rrScrPrivPtr pRRScrPriv; winScreenPriv(pScreen); winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo; WindowPtr pRoot = pScreen->root; @@ -136,6 +135,10 @@ winDoRandRScreenSetSize(ScreenPtr pScreen, // and arrange for it to be repainted pScreen->PaintWindow(pRoot, &pRoot->borderClip, PW_BACKGROUND); + // Set mode to current display size + pRRScrPriv = rrGetScrPriv(pScreen); + winRandRUpdateMode(pScreen, pRRScrPriv->primaryOutput); + /* Indicate that a screen size change took place */ RRScreenSizeNotify(pScreen); } @@ -270,6 +273,9 @@ winRandRInit(ScreenPtr pScreen) /* Ensure we have space for exactly one mode */ output->modes = malloc(sizeof(RRModePtr)); output->modes[0] = NULL; + + /* Set mode to current display size */ + winRandRUpdateMode(pScreen, output); } /* From ff6b771eeea763c19d057e8741a2cadb37db9b68 Mon Sep 17 00:00:00 2001 From: Jon Turney Date: Thu, 8 Mar 2018 14:25:54 +0000 Subject: [PATCH 38/38] hw/xwin: Improve data returned for RANDR queries Set a linear gamma ramp. This avoids the xrandr command always warning 'Failed to get size of gamma for output default' (perhaps we should be using GDI GetDeviceGammaRamp(), if possible?) Make CRTC report non-zero physical dimensions initially --- hw/xwin/winrandr.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hw/xwin/winrandr.c b/hw/xwin/winrandr.c index 30b7c5f6b..038d63bde 100644 --- a/hw/xwin/winrandr.c +++ b/hw/xwin/winrandr.c @@ -276,6 +276,21 @@ winRandRInit(ScreenPtr pScreen) /* Set mode to current display size */ winRandRUpdateMode(pScreen, output); + + /* Make up some physical dimensions */ + output->mmWidth = (pScreen->width * 25.4)/monitorResolution; + output->mmHeight = (pScreen->height * 25.4)/monitorResolution; + + /* Allocate and make up a (fixed, linear) gamma ramp */ + { + int i; + RRCrtcGammaSetSize(crtc, 256); + for (i = 0; i < crtc->gammaSize; i++) { + crtc->gammaRed[i] = i << 8; + crtc->gammaBlue[i] = i << 8; + crtc->gammaGreen[i] = i << 8; + } + } } /*