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. Signed-off-by: Mario Kleiner <mario.kleiner...@gmail.com> Cc: Daniel Stone <dani...@collabora.com> --- src/egl/drivers/dri2/platform_wayland.c | 67 ++++++++++++++++++++++++++++----- 1 file changed, 58 insertions(+), 9 deletions(-) diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 89a7f90118..fb364a6233 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -68,49 +68,50 @@ static const struct dri2_wl_visual { uint32_t wl_drm_format; uint32_t wl_shm_format; int dri_image_format; + 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 } }, }; @@ -450,15 +451,23 @@ 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; + + assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE); + /* 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); @@ -505,7 +514,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); @@ -514,7 +523,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); @@ -1278,8 +1287,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; @@ -1292,6 +1304,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, j, k; + + /* No match for config. Try if we can blitImage convert to a visual */ + j = dri2_wl_visual_idx_from_config(dri2_dpy, + dri2_dpy->driver_configs[i]); + + if (j == -1) + continue; + + /* Find optimal target visual for blitImage conversion, if any. */ + alt_dri_image_format = dri2_wl_visuals[j].alt_dri_image_format; + k = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format); + + if (k == -1 || !(dri2_dpy->formats & (1 << k))) + continue; + + /* Visual k works for the Wayland server, and j can be converted into k + * by our client gpu during PRIME blitImage conversion to a linear + * wl_buffer, so add visual j 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[j].rgba_masks); + if (dri2_conf) { + if (dri2_conf->base.ConfigID == count + 1) + count++; + format_count[j]++; + if (format_count[j] == 1) + _eglLog(_EGL_DEBUG, "Client format %s to server format %s via " + "PRIME blitImage.", dri2_wl_visuals[j].format_name, + dri2_wl_visuals[k].format_name); } } } -- 2.13.0.rc1.294.g07d810a77f _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev