From a34b0d68bbf8571e4d858cf4e1176766a50364de Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Wed, 13 Jun 2018 06:04:14 +0200 Subject: egl/wayland: Allow client->server format conversion for PRIME offload. (v2) Support PRIME render offload between a Wayland server gpu and a Wayland client gpu with different channel ordering for their color formats, e.g., between Intel drivers which currently only support ARGB2101010 and XRGB2101010 import/display and nouveau which only supports ABGR2101010 rendering and display on nv-50 and later. In the wl_visuals table, we also store for each format an alternate sibling format which stores colors at the same precision, but with different channel ordering, e.g., ARGB2101010 <-> ABGR2101010. If a given client-gpu renderable format is not supported by the server for import, but the alternate format is supported by the server, expose the client-gpu renderable format as a valid EGLConfig to the client. At eglSwapBuffers time, during the blitImage() detiling blit from the client backbuffer to the linear buffer, the client format is converted to the server supported format. As we have to do a copy for PRIME anyway, this channel swizzling conversion comes essentially for free. Note that even if a server gpu in principle does support sampling from the clients native format, this conversion will be a performance advantage if it allows to convert to the servers preferred format for direct scanout, as the Wayland compositor may then be able to directly page-flip a fullscreen client wl_buffer onto the primary plane, or onto a hardware overlay plane, avoiding an extra data copy for desktop composition. Tested so far under Weston with: nouveau single-gpu, Intel single-gpu, AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia client dGPU for rendering. v2: Implement minor review comments by Eric Engestrom: Add some comment and assert, and some style fixes for clarity. No functional change. Signed-off-by: Mario Kleiner Reviewed-by: Adam Jackson Reviewed-by: Daniel Stone --- 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 34e09d7ec16..872e265f509 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -59,49 +59,57 @@ static const struct dri2_wl_visual { uint32_t wl_drm_format; uint32_t wl_shm_format; int dri_image_format; + /* alt_dri_image_format is a substitute wl_buffer format to use for a + * wl-server unsupported dri_image_format, ie. some other dri_image_format in + * the table, of the same precision but with different channel ordering, or + * __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported. + * The code checks if alt_dri_image_format can be used as a fallback for a + * dri_image_format for a given wl-server implementation. + */ + int alt_dri_image_format; int bpp; unsigned int rgba_masks[4]; } dri2_wl_visuals[] = { { "XRGB2101010", WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010, - __DRI_IMAGE_FORMAT_XRGB2101010, 32, + __DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32, { 0x3ff00000, 0x000ffc00, 0x000003ff, 0x00000000 } }, { "ARGB2101010", WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010, - __DRI_IMAGE_FORMAT_ARGB2101010, 32, + __DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32, { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } }, { "XBGR2101010", WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010, - __DRI_IMAGE_FORMAT_XBGR2101010, 32, + __DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32, { 0x000003ff, 0x000ffc00, 0x3ff00000, 0x00000000 } }, { "ABGR2101010", WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010, - __DRI_IMAGE_FORMAT_ABGR2101010, 32, + __DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32, { 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 } }, { "XRGB8888", WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888, - __DRI_IMAGE_FORMAT_XRGB8888, 32, + __DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32, { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 } }, { "ARGB8888", WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888, - __DRI_IMAGE_FORMAT_ARGB8888, 32, + __DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32, { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 } }, { "RGB565", WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565, - __DRI_IMAGE_FORMAT_RGB565, 16, + __DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16, { 0xf800, 0x07e0, 0x001f, 0x0000 } }, }; @@ -461,15 +469,29 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) int use_flags; int visual_idx; unsigned int dri_image_format; + unsigned int linear_dri_image_format; uint64_t *modifiers; int num_modifiers; visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); assert(visual_idx != -1); dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format; + linear_dri_image_format = dri_image_format; modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]); num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]); + /* Substitute dri image format if server does not support original format */ + if (!(dri2_dpy->formats & (1 << visual_idx))) + linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format; + + /* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and + * the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free + * of bugs. + */ + assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE); + assert(dri2_dpy->formats & + (1 << dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format))); + /* There might be a buffer release already queued that wasn't processed */ wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue); @@ -516,7 +538,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen, dri2_surf->base.Width, dri2_surf->base.Height, - dri_image_format, + linear_dri_image_format, &linear_mod, 1, NULL); @@ -525,7 +547,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) dri2_dpy->image->createImage(dri2_dpy->dri_screen, dri2_surf->base.Width, dri2_surf->base.Height, - dri_image_format, + linear_dri_image_format, use_flags | __DRI_IMAGE_USE_LINEAR, NULL); @@ -1298,8 +1320,11 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 }; unsigned int count = 0; + bool assigned; for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { + assigned = false; + for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) { struct dri2_egl_config *dri2_conf; @@ -1312,6 +1337,43 @@ dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) if (dri2_conf->base.ConfigID == count + 1) count++; format_count[j]++; + assigned = true; + } + } + + if (!assigned && dri2_dpy->is_different_gpu) { + struct dri2_egl_config *dri2_conf; + int alt_dri_image_format, c, s; + + /* No match for config. Try if we can blitImage convert to a visual */ + c = dri2_wl_visual_idx_from_config(dri2_dpy, + dri2_dpy->driver_configs[i]); + + if (c == -1) + continue; + + /* Find optimal target visual for blitImage conversion, if any. */ + alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format; + s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format); + + if (s == -1 || !(dri2_dpy->formats & (1 << s))) + continue; + + /* Visual s works for the Wayland server, and c can be converted into s + * by our client gpu during PRIME blitImage conversion to a linear + * wl_buffer, so add visual c as supported by the client renderer. + */ + dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], + count + 1, EGL_WINDOW_BIT, NULL, + dri2_wl_visuals[c].rgba_masks); + if (dri2_conf) { + if (dri2_conf->base.ConfigID == count + 1) + count++; + format_count[c]++; + if (format_count[c] == 1) + _eglLog(_EGL_DEBUG, "Client format %s to server format %s via " + "PRIME blitImage.", dri2_wl_visuals[c].format_name, + dri2_wl_visuals[s].format_name); } } } -- cgit v1.2.3