Details
Description
EGL implementations are supposed to provide a list of valid EGLConfig's which are
used for rendering. These configs define information such as what types of
surfaces the config can be used to render to (windows, pixmaps, pbuffers), what
the pixel format is, whether a depth/stencil buffer is present, etc. One of
the attributes of an EGL config is a native visual which can be used to create
compatible native windows for the specified config. So an EGL app is supposed
to select an EGLConfig and then create an X window using the visual ID
suggested by the config.
In some cases the EGL implementation may not provide an EGLConfig that exactly matches the characteristics being requested. Some drivers return a default visual adaptable to multiple configuration parameters expecting the EGL application to use the visual without a careful examination of its characteristics. QT correctly rejects these incompatible configs and then trys to figure out an appropriate visual on its own by querying the driver via xrender. In general QT's fallback approach described above should be fine. However QT's logic neglects to trim the list of possible visuals down to only those visuals available on the current screen. It simply picks the first visual that appears to be compatible without checking which screen it's tied to, and uses that. When the application is running on the secondary screen this selection process may result in QT picking a visual from the primary screen (Screen 0). QT will then use that visual to try to create its new window. However when the window being created is on Screen 1 instead, X rejects the window creation (invalid visual for screen). QT does not notice that window creation failed (its X error handler prints the contents of the X error raised, but performs no recovery) and submits subsequent X11 operations referencing the non-existent window. Ultimately it performs a XGetWindowAttributes() call (which returns a bogus window attribute structure since the window does not exist), pulls a bogus visual out of that garbage structure, and tries to pass that to XVisualIDFromVisual. Since the visual structure is garbage, this finally results in a segfault for the client process.
This issue was found in MeeGo using the meego-ux-* components on a platform with an IMG technology driver for a PVR core. It is reported as https://bugs.meego.com/show_bug.cgi?id=18914
One of the QT experts should take a look, but it is possible the fix should go in
QEgl::getCompatibleVisualId() (in gui/egl/qegl_x11.cpp). There's a place
partway down the function that says "If EGL didn't give us a valid visual ID,
try XRender." That goes on to generate a list of all TrueColor visuals and
then walk through the list until it finds one where all of the the color
component sizes match. As soon as it finds one where all of the color
components look good, it breaks out of the loop and just uses that visual.
However just matching colors isn't enough...it should also be making sure the
visual is appropriate for the screen.
I think something like this would do the trick (completely untested):
— gui/egl/qegl_x11.cpp.orig 2011-06-16 15:33:27.000000000 -0700
+++ gui/egl/qegl_x11.cpp 2011-06-16 15:32:47.000000000 -0700
@@ -240,11 +240,12 @@
memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
visualInfoTemplate.c_class = TrueColor;
+ visualInfoTemplate.screen = DefaultScreen(X11->display);
XVisualInfo *matchingVisuals;
int matchingCount = 0;
matchingVisuals = XGetVisualInfo(X11->display,
- VisualClassMask,
+ VisualClassMask | VisualScreenMask,
&visualInfoTemplate,
&matchingCount);
farther down the function there's yet another fallback for the case where
XRender isn't available or fails to select a valid visual. Technically that
case should also be updated in the same way to filter on screen number,
although my diff above doesn't cover that.