From 3cdbf66dacf3d179c503e35f4b68ae129e4f8a8a Mon Sep 17 00:00:00 2001 From: DRC Date: Fri, 16 Feb 2024 12:08:05 -0500 Subject: [PATCH] Faker: Various hacks to support Chrome/ANGLE 1. ANGLE provides its own EGL interposer named libEGL.so and uses dlopen() to open the real EGL library, which it expects to be named libEGL.so.1. Thus, it is necessary to modify VirtualGL's dlopen() interposer so that it strictly matches libraries named "libEGL.so.1" instead of all libraries with "libEGL." in the name. With that modification, VGL will intercept the dlopen() call that ANGLE's EGL back end makes to open the real EGL library, but VGL won't interfere with the dlopen() call that the application makes to open ANGLE's EGL front end. The application will call ANGLE, then ANGLE will call VirtualGL. 2. Associate a depth=32 2D X server visual with all EGLConfigs that have an alpha channel. 3. Chrome/ANGLE attempts to reproduce the visual matching algorithm from GTK v3.15.2 through 4.3.1 (refer to 398e941653137443a662bc726d82a04012eb5ea1), but it does so by sending raw GLX requests and replies to the X server. Thus, there is nothing for VirtualGL to interpose, and the "system" and "RGBA" visuals that Chrome picks are based solely on OpenGL rendering attributes assigned to the 2D X server visuals by the 2D X server's GLX implementation, not on OpenGL rendering attributes assigned to the visuals by VirtualGL. As a result, the RGBA visual that Chrome picks is not associated with any EGLConfig or GLXFBConfig that VirtualGL returns. To work around this, hack glxvisual::buildVisAttribTable() so that it picks the same RGBA visual that Chrome does and associates that visual with any 8-bit-per-component alpha-enabled EGLConfigs or GLXFBConfigs. Since this requires making GLX calls against the 2D X server, this hack is only enabled if VGL_PROBEGLX=1, which isn't the default when using an X proxy. --- server/dlfaker.c | 4 ++-- server/faker-egl.cpp | 21 ++++++++++++++++++--- server/glxvisual.cpp | 35 ++++++++++++++++++++++++++++++++--- server/glxvisual.h | 5 ++++- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/server/dlfaker.c b/server/dlfaker.c index 86192223..5fea7f13 100644 --- a/server/dlfaker.c +++ b/server/dlfaker.c @@ -1,5 +1,5 @@ /* Copyright (C)2006 Sun Microsystems, Inc. - * Copyright (C)2009, 2012, 2015, 2017-2021 D. R. Commander + * Copyright (C)2009, 2012, 2015, 2017-2021, 2024 D. R. Commander * Copyright (C)2015 Open Text SA and/or Open Text ULC (in Canada) * * This library is free software and may be redistributed and/or modified under @@ -128,7 +128,7 @@ void *dlopen(const char *filename, int flag) || (!strncmp(filename, "libOpenCL.", 10) && fakeOpenCL) || (strstr(filename, "/libOpenCL.") && fakeOpenCL) #endif - || !strncmp(filename, "libEGL.", 7) || strstr(filename, "/libEGL.") + || !strncmp(filename, "libEGL.so.1", 11) || strstr(filename, "/libEGL.so.1") || !strncmp(filename, "libX11.", 7) || strstr(filename, "/libX11.") || (flag & RTLD_LAZY && (!strncmp(filename, "libopengl.", 10) diff --git a/server/faker-egl.cpp b/server/faker-egl.cpp index c2e9fd92..bf9c854a 100644 --- a/server/faker-egl.cpp +++ b/server/faker-egl.cpp @@ -92,6 +92,7 @@ static INLINE EGLint EGLConfigID(faker::EGLXDisplay *eglxdpy, EGLConfig c) static XVisualInfo *getVisual(Display *dpy, int screen, int depth, int c_class) { XVisualInfo vtemp; int nv = 0; + long vinfo_mask = VisualDepthMask | VisualClassMask | VisualScreenMask; if(!dpy) return NULL; @@ -99,8 +100,18 @@ static XVisualInfo *getVisual(Display *dpy, int screen, int depth, int c_class) vtemp.c_class = c_class; vtemp.screen = screen; - return XGetVisualInfo(dpy, - VisualDepthMask | VisualClassMask | VisualScreenMask, &vtemp, &nv); + if(depth == 32) + { + VisualID vid = + glxvisual::matchVisual2D(dpy, screen, depth, c_class, 8, 0, true); + if(vid) + { + vtemp.visualid = vid; + vinfo_mask = VisualIDMask; + } + } + + return XGetVisualInfo(dpy, vinfo_mask, &vtemp, &nv); } @@ -109,7 +120,7 @@ static XVisualInfo *getVisualFromConfig(faker::EGLXDisplay *eglxdpy, { if(!eglxdpy || !config) return NULL; - EGLint redSize, greenSize, blueSize; + EGLint redSize, greenSize, blueSize, alphaSize; int depth = 24; if(_eglGetConfigAttrib(eglxdpy->edpy, config, EGL_RED_SIZE, &redSize) @@ -118,6 +129,10 @@ static XVisualInfo *getVisualFromConfig(faker::EGLXDisplay *eglxdpy, && redSize == 10 && greenSize == 10 && blueSize == 10) depth = 30; + if(_eglGetConfigAttrib(eglxdpy->edpy, config, EGL_ALPHA_SIZE, &alphaSize) && + alphaSize == 8) + depth = 32; + return getVisual(eglxdpy->x11dpy, eglxdpy->screen, depth, TrueColor); } diff --git a/server/glxvisual.cpp b/server/glxvisual.cpp index 00abdcbe..ed789e07 100644 --- a/server/glxvisual.cpp +++ b/server/glxvisual.cpp @@ -1,6 +1,6 @@ // Copyright (C)2004 Landmark Graphics Corporation // Copyright (C)2005 Sun Microsystems, Inc. -// Copyright (C)2009-2016, 2019-2023 D. R. Commander +// Copyright (C)2009-2016, 2019-2024 D. R. Commander // // This library is free software and may be redistributed and/or modified under // the terms of the wxWindows Library License, Version 3.1 or (at your option) @@ -33,6 +33,7 @@ typedef struct VGLFBConfig config; int depth, c_class, bpc, nVisuals; int isStereo, isDB, isGL; + int score; GLXAttrib glx; } VisAttrib; @@ -248,12 +249,29 @@ static bool buildVisAttribTable(Display *dpy, int screen) va[i].c_class = visuals[i].c_class; va[i].bpc = visuals[i].bits_per_rgb; va[i].nVisuals = nVisuals; + va[i].score = -1; if(clientGLX) { _glXGetConfig(dpy, &visuals[i], GLX_DOUBLEBUFFER, &va[i].isDB); _glXGetConfig(dpy, &visuals[i], GLX_USE_GL, &va[i].isGL); _glXGetConfig(dpy, &visuals[i], GLX_STEREO, &va[i].isStereo); + // Simulate the ARGB visual selection mechanism used in Chrome + if(va[i].depth == 32 && va[i].bpc == 8 && va[i].isDB && + !va[i].isStereo) + { + va[i].score = 0; + int alphaSize = -1, depthSize = -1, stencilSize = -1, + sampleBuffers = -1; + _glXGetConfig(dpy, &visuals[i], GLX_ALPHA_SIZE, &alphaSize); + if(alphaSize > 0) va[i].score++; + _glXGetConfig(dpy, &visuals[i], GLX_DEPTH_SIZE, &depthSize); + _glXGetConfig(dpy, &visuals[i], GLX_STENCIL_SIZE, &stencilSize); + if(depthSize == 0 && stencilSize == 0) va[i].score++; + _glXGetConfig(dpy, &visuals[i], GLX_SAMPLE_BUFFERS_ARB, + &sampleBuffers); + if(sampleBuffers == 0) va[i].score++; + } } va[i].glx.alphaSize = va[i].glx.depthSize = va[i].glx.stencilSize = va[i].glx.samples = -1; @@ -306,7 +324,7 @@ static bool buildVisAttribTable(Display *dpy, int screen) // attributes from the 2D X server, or it caches them if they have not // already been read. -static VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, +VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, int bpc, int stereo, bool strictMatch) { int i, tryStereo; @@ -316,6 +334,12 @@ static VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, GET_VA_TABLE() // Try to find an exact match + int highestScore = -1; + for(i = 0; i < vaEntries; i++) + { + if(va[i].score > highestScore) + highestScore = va[i].score; + } for(tryStereo = 1; tryStereo >= 0; tryStereo--) { for(i = 0; i < vaEntries; i++) @@ -351,6 +375,11 @@ static VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, && va[i].c_class != DirectColor) match = 0; } + if(va[i].depth == 32 && va[i].bpc == 8 && match) + { + if(va[i].score < highestScore) + match = 0; + } if(match) return va[i].visualID; } } @@ -362,7 +391,7 @@ static VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, // This function finds a 2D X server visual that is suitable for use with a // particular 3D X server FB config. -static VisualID matchVisual2D(Display *dpy, int screen, VGLFBConfig config) +VisualID matchVisual2D(Display *dpy, int screen, VGLFBConfig config) { VisualID vid = 0; diff --git a/server/glxvisual.h b/server/glxvisual.h index bd12a98c..39898781 100644 --- a/server/glxvisual.h +++ b/server/glxvisual.h @@ -1,6 +1,6 @@ // Copyright (C)2004 Landmark Graphics Corporation // Copyright (C)2005 Sun Microsystems, Inc. -// Copyright (C)2014, 2019-2021 D. R. Commander +// Copyright (C)2014, 2019-2021, 2024 D. R. Commander // // This library is free software and may be redistributed and/or modified under // the terms of the wxWindows Library License, Version 3.1 or (at your option) @@ -77,6 +77,9 @@ namespace glxvisual // This function returns the default FB config attached to a given visual ID // in the visual attribute table. VGLFBConfig getDefaultFBConfig(Display *dpy, int screen, VisualID vid); + + VisualID matchVisual2D(Display *dpy, int screen, int depth, int c_class, + int bpc, int stereo, bool strictMatch); } -- 2.32.0 (Apple Git-132)