If this was specified and a non-NULL display was passed to eglGetPlatformDisplay, we would ignore the attribute and instead use whatever xcb thought the default screen would be.
To fix this, store a copy of the attribute list in the _EGLDisplay, and use that to look up any non-default screen number if we need it. --- src/egl/drivers/dri2/platform_x11.c | 28 ++++++++-- src/egl/main/eglapi.c | 2 +- src/egl/main/egldisplay.c | 85 +++++++++++++++++++++++------ src/egl/main/egldisplay.h | 4 +- 4 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index c8c676d2f00..7b95634e77c 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -1276,24 +1276,44 @@ static const __DRIextension *swrast_loader_extensions[] = { NULL, }; +static int +dri2_find_screen_for_display(Display *dpy, _EGLDisplay *disp) +{ + int screen = -1; + const EGLAttrib *attr; + + if (dpy) + screen = DefaultScreen(dpy); + + for (attr = disp->Options.Attribs; attr; attr += 2) { + if (attr[0] == EGL_PLATFORM_X11_SCREEN_EXT) { + screen = attr[1]; + break; + } + if (attr[0] == EGL_NONE) + break; + } + + return screen; +} + static EGLBoolean dri2_get_xcb_connection(_EGLDriver *drv, _EGLDisplay *disp, struct dri2_egl_display *dri2_dpy) { xcb_screen_iterator_t s; - int screen = (uintptr_t)disp->Options.Platform; + int screen; const char *msg; disp->DriverData = (void *) dri2_dpy; if (disp->PlatformDisplay == NULL) { - dri2_dpy->conn = xcb_connect(NULL, &screen); + dri2_dpy->conn = xcb_connect(NULL, NULL); dri2_dpy->own_device = true; } else { Display *dpy = disp->PlatformDisplay; - dri2_dpy->conn = XGetXCBConnection(dpy); - screen = DefaultScreen(dpy); } + screen = dri2_find_screen_for_display(disp->PlatformDisplay, disp); if (!dri2_dpy->conn || xcb_connection_has_error(dri2_dpy->conn)) { msg = "xcb_connect failed"; diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 588c6a5f1eb..4696eca8f82 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -379,7 +379,7 @@ eglGetDisplay(EGLNativeDisplayType nativeDisplay) native_display_ptr = (void*) nativeDisplay; plat = _eglGetNativePlatform(native_display_ptr); - disp = _eglFindDisplay(plat, native_display_ptr); + disp = _eglFindDisplay(plat, native_display_ptr, NULL); return _eglGetDisplayHandle(disp); } diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index b26a9575087..8aae6900f09 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -202,20 +202,64 @@ _eglFiniDisplay(void) } } + free(disp->Options.Attribs); free(disp); } _eglGlobal.DisplayList = NULL; } +static int +_eglNumAttribs(const EGLAttrib *attrib_list) +{ + int ret = 0; + const EGLAttrib *attr; + + for (attr = attrib_list; attr; attr++) { + ret++; + if ((ret % 2 == 1) && (*attr == EGL_NONE)) + break; + } + + return ret; +} + +static int +_eglSameAttribs(const EGLAttrib *a, const EGLAttrib *b) +{ + int na = _eglNumAttribs(a); + int nb = _eglNumAttribs(b); + + /* different numbers of attributes must be different */ + if (na != nb) + return 0; + + /* both lists NULL are the same */ + if (!a && !b) + return 1; + + /* otherwise, compare the lists */ + return memcmp(a, b, na) == 0; +} /** * Find the display corresponding to the specified native display, or create a - * new one. + * new one. EGL 1.5 says: + * + * Multiple calls made to eglGetPlatformDisplay with the same parameters + * will return the same EGLDisplay handle. + * + * We read this extremely strictly, and treat a call with NULL attribs as + * different from a call with attribs only equal to { EGL_NONE }. Similarly + * we do not sort the attribute list, so even if all attribute _values_ are + * identical, different attribute orders will be considered different + * parameters. */ _EGLDisplay * -_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) +_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy, + const EGLAttrib *attrib_list) { _EGLDisplay *disp; + int num_attribs = _eglNumAttribs(attrib_list); if (plat == _EGL_INVALID_PLATFORM) return NULL; @@ -225,7 +269,8 @@ _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) /* search the display list first */ disp = _eglGlobal.DisplayList; while (disp) { - if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy) + if (disp->Platform == plat && disp->PlatformDisplay == plat_dpy && + _eglSameAttribs(disp->Options.Attribs, attrib_list)) break; disp = disp->Next; } @@ -237,6 +282,16 @@ _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) mtx_init(&disp->Mutex, mtx_plain); disp->Platform = plat; disp->PlatformDisplay = plat_dpy; + if (num_attribs) { + disp->Options.Attribs = calloc(num_attribs, sizeof(EGLAttrib)); + if (disp->Options.Attribs) { + memcpy(disp->Options.Attribs, attrib_list, + num_attribs * sizeof(EGLAttrib)); + } else { + free(disp); + goto out; + } + } /* add to the display list */ disp->Next = _eglGlobal.DisplayList; @@ -244,6 +299,7 @@ _eglFindDisplay(_EGLPlatformType plat, void *plat_dpy) } } +out: mtx_unlock(_eglGlobal.Mutex); return disp; @@ -456,17 +512,12 @@ _eglParseX11DisplayAttribList(_EGLDisplay *display, return EGL_TRUE; } + /* EGL_EXT_platform_x11 recognizes exactly one attribute, + * EGL_PLATFORM_X11_SCREEN_EXT, which is optional. + */ for (i = 0; attrib_list[i] != EGL_NONE; i += 2) { - EGLAttrib attrib = attrib_list[i]; - EGLAttrib value = attrib_list[i + 1]; - - /* EGL_EXT_platform_x11 recognizes exactly one attribute, - * EGL_PLATFORM_X11_SCREEN_EXT, which is optional. - */ - if (attrib != EGL_PLATFORM_X11_SCREEN_EXT) + if (attrib_list[i] != EGL_PLATFORM_X11_SCREEN_EXT) return _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); - - display->Options.Platform = (void *)(uintptr_t)value; } return EGL_TRUE; @@ -477,7 +528,8 @@ _eglGetX11Display(Display *native_display, const EGLAttrib *attrib_list) { _EGLDisplay *display = _eglFindDisplay(_EGL_PLATFORM_X11, - native_display); + native_display, + attrib_list); if (!display) { _eglError(EGL_BAD_ALLOC, "eglGetPlatformDisplay"); @@ -503,7 +555,7 @@ _eglGetGbmDisplay(struct gbm_device *native_display, return NULL; } - return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display); + return _eglFindDisplay(_EGL_PLATFORM_DRM, native_display, attrib_list); } #endif /* HAVE_DRM_PLATFORM */ @@ -518,7 +570,7 @@ _eglGetWaylandDisplay(struct wl_display *native_display, return NULL; } - return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display); + return _eglFindDisplay(_EGL_PLATFORM_WAYLAND, native_display, attrib_list); } #endif /* HAVE_WAYLAND_PLATFORM */ @@ -539,6 +591,7 @@ _eglGetSurfacelessDisplay(void *native_display, return NULL; } - return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display); + return _eglFindDisplay(_EGL_PLATFORM_SURFACELESS, native_display, + attrib_list); } #endif /* HAVE_SURFACELESS_PLATFORM */ diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index cfd0ff66d64..9bd6bf76556 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -167,7 +167,7 @@ struct _egl_display /* options that affect how the driver initializes the display */ struct { EGLBoolean ForceSoftware; /**< Use software path only */ - void *Platform; /**< Platform-specific options */ + EGLAttrib *Attribs; /**< Platform-specific options */ } Options; /* these fields are set by the driver during init */ @@ -202,7 +202,7 @@ _eglFiniDisplay(void); extern _EGLDisplay * -_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy); +_eglFindDisplay(_EGLPlatformType plat, void *plat_dpy, const EGLAttrib *attr); extern void -- 2.20.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev