egl/wayland: Fail EGL surface creation if opaque format is unsupported

When using the EGL_EXT_present_opaque extension we create wayland
buffers with the opaque variant of the surface format, while the
underlying image is created with the normal surface format. However,
there is no guarantee that the compositor supports that opaque format,
or that we can use that format with all the modifiers of the surface
format.

Since this is completely out of the control of the application, and the
compositor will disconnect the client with an error if the format is not
supported, this commit:

1. Fails EGL surface creation if it determines that the opaque format
   cannot be used, either because it's not present at all, or because
   it shares no modifier with the non-opaque format.
2. When creating the DRI image ensures that we use a modifier that's
   also supported by the opaque format.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28153>
This commit is contained in:
Alexandros Frantzis
2024-06-14 14:58:33 +03:00
committed by Marge Bot
parent a271a34d59
commit 4cac8468d4
+71 -9
View File
@@ -622,6 +622,29 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener
.done = surface_dmabuf_feedback_done,
};
static bool
dri2_wl_modifiers_have_common(struct u_vector *modifiers1,
struct u_vector *modifiers2)
{
uint64_t *mod1, *mod2;
/* If both modifier vectors are empty, assume there is a compatible
* implicit modifier. */
if (u_vector_length(modifiers1) == 0 && u_vector_length(modifiers2) == 0)
return true;
u_vector_foreach(mod1, modifiers1)
{
u_vector_foreach(mod2, modifiers2)
{
if (*mod1 == *mod2)
return true;
}
}
return false;
}
/**
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
*/
@@ -680,6 +703,20 @@ dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
dri2_surf->format = dri2_wl_shm_format_from_visual_idx(visual_idx);
}
if (dri2_surf->base.PresentOpaque) {
uint32_t opaque_fourcc =
dri2_wl_visuals[visual_idx].opaque_wl_drm_format;
int opaque_visual_idx = dri2_wl_visual_idx_from_fourcc(opaque_fourcc);
if (!server_supports_format(&dri2_dpy->formats, opaque_visual_idx) ||
!dri2_wl_modifiers_have_common(
&dri2_dpy->formats.modifiers[visual_idx],
&dri2_dpy->formats.modifiers[opaque_visual_idx])) {
_eglError(EGL_BAD_MATCH, "Unsupported opaque format");
goto cleanup_surf;
}
}
dri2_surf->wl_queue = wl_display_create_queue_with_name(dri2_dpy->wl_dpy,
"mesa egl surface queue");
if (!dri2_surf->wl_queue) {
@@ -973,26 +1010,47 @@ create_dri_image(struct dri2_egl_surface *dri2_surf,
dri2_egl_display(dri2_surf->base.Resource.Display);
int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
struct u_vector modifiers_subset;
struct u_vector modifiers_subset_opaque;
uint64_t *modifiers;
unsigned int num_modifiers;
struct u_vector *modifiers_set;
struct u_vector *modifiers_present;
assert(visual_idx != -1);
if (!BITSET_TEST(formats->formats_bitmap, visual_idx))
return;
if (dri2_surf->base.PresentOpaque) {
uint32_t opaque_fourcc =
dri2_wl_visuals[visual_idx].opaque_wl_drm_format;
int opaque_visual_idx = dri2_wl_visual_idx_from_fourcc(opaque_fourcc);
struct u_vector *modifiers_dpy = &dri2_dpy->formats.modifiers[visual_idx];
/* Surface creation would have failed if we didn't support the matching
* opaque format. */
assert(opaque_visual_idx != -1);
modifiers_set = &formats->modifiers[visual_idx];
if (!BITSET_TEST(formats->formats_bitmap, opaque_visual_idx))
return;
if (!intersect_modifiers(&modifiers_subset_opaque,
&formats->modifiers[opaque_visual_idx],
u_vector_tail(modifiers_dpy),
u_vector_length(modifiers_dpy)))
return;
modifiers_present = &modifiers_subset_opaque;
} else {
if (!BITSET_TEST(formats->formats_bitmap, visual_idx))
return;
modifiers_present = &formats->modifiers[visual_idx];
}
if (surf_modifiers_count > 0) {
if (!intersect_modifiers(&modifiers_subset, modifiers_set, surf_modifiers,
surf_modifiers_count))
return;
if (!intersect_modifiers(&modifiers_subset, modifiers_present,
surf_modifiers, surf_modifiers_count))
goto cleanup_present;
modifiers = u_vector_tail(&modifiers_subset);
num_modifiers = u_vector_length(&modifiers_subset);
} else {
modifiers = u_vector_tail(modifiers_set);
num_modifiers = u_vector_length(modifiers_set);
modifiers = u_vector_tail(modifiers_present);
num_modifiers = u_vector_length(modifiers_present);
}
/* For the purposes of this function, an INVALID modifier on
@@ -1013,6 +1071,10 @@ create_dri_image(struct dri2_egl_surface *dri2_surf,
u_vector_finish(&modifiers_subset);
update_surface(dri2_surf, dri2_surf->back->dri_image);
}
cleanup_present:
if (modifiers_present == &modifiers_subset_opaque)
u_vector_finish(&modifiers_subset_opaque);
}
static void