From 4cac8468d439a0cadb952a4a1801cd5cc2969a8e Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Fri, 14 Jun 2024 14:58:33 +0300 Subject: [PATCH] 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: --- src/egl/drivers/dri2/platform_wayland.c | 80 ++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 560380e4f32..0c2f7d1faad 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -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