egl/gbm: Ensure EGLConfigs match GBM surface format

When we create an EGL window surface on a GBM surface, ensure that the
EGLConfig is compatible with the GBM format, notwithstanding XRGB/ARGB
interchange.

For example, rendering with an XRGB8888 EGLConfig on to an ARGB8888
gbm_surface (and vice-versa) are acceptable, but rendering with an
XRGB2101010 EGLConfig on to an XRGB8888 gbm_surface will now be
rejected.

This was previously allowed through; when 10bpc formats were enabled,
clients which picked a completely random EGL config and hoped/assumed
they were XRGB8888 would break.

If you have bisected a failure to start a GBM/KMS client to this commit,
please look at its EGLConfig selection (e.g. through eglChooseConfigs),
and add an EGL_NATIVE_VISUAL_ID == gbm_surface format match to the
attribs for config selection.

Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Tested-by: Ilia Mirkin <imirkin@alum.mit.edu>
This commit is contained in:
Daniel Stone 2018-02-06 17:59:05 +00:00
parent 8174e5b49e
commit 37a8d907cc
1 changed files with 48 additions and 4 deletions

View File

@ -90,6 +90,44 @@ has_free_buffers(struct gbm_surface *_surf)
return 0;
}
static bool
dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy,
const __DRIconfig *config,
struct gbm_surface *surface)
{
const struct gbm_dri_visual *visual;
unsigned int red, green, blue, alpha;
int i;
/* Check that the EGLConfig being used to render to the surface is
* compatible with the surface format. Since mixing ARGB and XRGB of
* otherwise-compatible formats is relatively common, explicitly allow
* this.
*/
dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_RED_MASK, &red);
dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_GREEN_MASK, &green);
dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_BLUE_MASK, &blue);
dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_MASK, &alpha);
for (i = 0; i < dri2_dpy->gbm_dri->num_visuals; i++) {
visual = &dri2_dpy->gbm_dri->visual_table[i];
if (visual->gbm_format == surface->format)
break;
}
if (i == dri2_dpy->gbm_dri->num_visuals)
return false;
if (red != visual->rgba_masks[0] ||
green != visual->rgba_masks[1] ||
blue != visual->rgba_masks[2] ||
(alpha && visual->rgba_masks[3] && alpha != visual->rgba_masks[3])) {
return false;
}
return true;
}
static _EGLSurface *
dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
_EGLConfig *conf, void *native_surface,
@ -110,18 +148,24 @@ dri2_drm_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
return NULL;
}
if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list, false))
if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
attrib_list, false))
goto cleanup_surf;
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
dri2_surf->base.GLColorspace);
if (!dri2_drm_config_is_compatible(dri2_dpy, config, surface)) {
_eglError(EGL_BAD_MATCH, "EGL config not compatible with GBM format");
goto cleanup_surf;
}
surf = gbm_dri_surface(surface);
dri2_surf->gbm_surf = surf;
dri2_surf->base.Width = surf->base.width;
dri2_surf->base.Height = surf->base.height;
surf->dri_private = dri2_surf;
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
dri2_surf->base.GLColorspace);
if (dri2_dpy->dri2) {
dri2_surf->dri_drawable =
dri2_dpy->dri2->createNewDrawable(dri2_dpy->dri_screen, config,