[Mesa-dev] loader_dri3: Handle mismatched depth 30 formats for Prime renderoffload.

Eric Engestrom eric.engestrom at intel.com
Wed Aug 1 11:30:10 UTC 2018


On Thursday, 2018-06-14 06:04:24 +0200, Mario Kleiner wrote:
> Detect if the display (X-Server) gpu and Prime renderoffload gpu prefer
> different channel ordering for color depth 30 formats ([X/A]BGR2101010
> vs. [X/A]RGB2101010) and perform format conversion during the blitImage()
> detiling op from tiled backbuffer -> linear buffer.
> 
> For this we need to find the visual (= red channel mask) for the
> X-Drawable used to display on the server gpu. We use the same proven
> logic for finding that visual as in commit "egl/x11: Handle both depth
> 30 formats for eglCreateImage()".
> 
> This is mostly to allow "NVidia Optimus" at depth 30, as Intel/AMD
> gpu's prefer xRGB2101010 ordering, whereas NVidia gpu's prefer
> xBGR2101010 ordering, so we can offload to nouveau without getting
> funky colors.
> 
> Tested on Intel single gpu, NVidia single gpu, Intel + NVidia prime
> offload with DRI3/Present.
> 
> Note: An unintended but pleasant surprise of this patch is that it also
> seems to make the modesetting-ddx of server 1.20.0 work at depth 30
> on nouveau, at least with unredirected "classic" X rendering, and
> with redirected desktop compositing under XRender accel, and with OpenGL
> compositing under GLX. Only X11 compositing via OpenGL + EGL still gives
> funky colors. modesetting-ddx + glamor are not yet ready to deal with
> nouveau's ABGR2101010 format, and treat it as ARGB2101010, also exposing
> X-visuals with ARGB2101010 style channel masks. Seems somehow this triggers
> the logic in this patch on modesetting-ddx + depth 30 + DRI3 buffer sharing
> and does the "wrong" channel swizzling that then cancels out the "wrong"
> swizzling of glamor and we end up with the proper pixel formatting in
> the scanout buffer :). This so far tested on a NVA5 Tesla card under KDE5
> Plasma as shipping with Ubuntu 16.04.4 LTS.
> 
> Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com>
> Cc: Ilia Mirkin <imirkin at alum.mit.edu>
> Cc: Eric Engestrom <eric.engestrom at intel.com>

Reviewed-by: Eric Engestrom <eric.engestrom at intel.com>

> ---
>  src/loader/loader_dri3_helper.c | 83 ++++++++++++++++++++++++++++++++-
>  src/loader/loader_dri3_helper.h |  1 +
>  2 files changed, 83 insertions(+), 1 deletion(-)
> 
> diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
> index f0ff2f07bd..a9a18921ce 100644
> --- a/src/loader/loader_dri3_helper.c
> +++ b/src/loader/loader_dri3_helper.c
> @@ -64,6 +64,55 @@ dri3_flush_present_events(struct loader_dri3_drawable *draw);
>  static struct loader_dri3_buffer *
>  dri3_find_back_alloc(struct loader_dri3_drawable *draw);
>  
> +static xcb_screen_t *
> +get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
> +{
> +   xcb_screen_iterator_t screen_iter =
> +   xcb_setup_roots_iterator(xcb_get_setup(conn));
> +
> +   for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
> +      if (screen_iter.data->root == root)
> +         return screen_iter.data;
> +   }
> +
> +   return NULL;
> +}
> +
> +static xcb_visualtype_t *
> +get_xcb_visualtype_for_depth(struct loader_dri3_drawable *draw, int depth)
> +{
> +   xcb_visualtype_iterator_t visual_iter;
> +   xcb_screen_t *screen = draw->screen;
> +   xcb_depth_iterator_t depth_iter;
> +
> +   if (!screen)
> +      return NULL;
> +
> +   depth_iter = xcb_screen_allowed_depths_iterator(screen);
> +   for (; depth_iter.rem; xcb_depth_next(&depth_iter)) {
> +      if (depth_iter.data->depth != depth)
> +         continue;
> +
> +      visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
> +      if (visual_iter.rem)
> +         return visual_iter.data;
> +   }
> +
> +   return NULL;
> +}
> +
> +/* Get red channel mask for given drawable at given depth. */
> +static unsigned int
> +dri3_get_red_mask_for_depth(struct loader_dri3_drawable *draw, int depth)
> +{
> +   xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(draw, depth);
> +
> +   if (visual)
> +      return visual->red_mask;
> +
> +   return 0;
> +}
> +
>  /**
>   * Do we have blit functionality in the image blit extension?
>   *
> @@ -323,6 +372,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
>        return 1;
>     }
>  
> +   draw->screen = get_screen_for_root(draw->conn, reply->root);
>     draw->width = reply->width;
>     draw->height = reply->height;
>     draw->depth = reply->depth;
> @@ -1030,6 +1080,36 @@ dri3_cpp_for_format(uint32_t format) {
>     }
>  }
>  
> +/* Map format of render buffer to corresponding format for the linear_buffer
> + * used for sharing with the display gpu of a Prime setup (== is_different_gpu).
> + * Usually linear_format == format, except for depth >= 30 formats, where
> + * different gpu vendors have different preferences wrt. color channel ordering.
> + */
> +static uint32_t
> +dri3_linear_format_for_format(struct loader_dri3_drawable *draw, uint32_t format)
> +{
> +   switch (format) {
> +      case  __DRI_IMAGE_FORMAT_XRGB2101010:
> +      case  __DRI_IMAGE_FORMAT_XBGR2101010:
> +         /* Different preferred formats for different hw */
> +         if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff)
> +            return __DRI_IMAGE_FORMAT_XBGR2101010;
> +         else
> +            return __DRI_IMAGE_FORMAT_XRGB2101010;
> +
> +      case  __DRI_IMAGE_FORMAT_ARGB2101010:
> +      case  __DRI_IMAGE_FORMAT_ABGR2101010:
> +         /* Different preferred formats for different hw */
> +         if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff)
> +            return __DRI_IMAGE_FORMAT_ABGR2101010;
> +         else
> +            return __DRI_IMAGE_FORMAT_ARGB2101010;
> +
> +      default:
> +         return format;
> +   }
> +}
> +
>  /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while
>   * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid
>   * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and
> @@ -1227,7 +1307,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format,
>  
>        buffer->linear_buffer =
>          draw->ext->image->createImage(draw->dri_screen,
> -                                      width, height, format,
> +                                      width, height,
> +                                      dri3_linear_format_for_format(draw, format),
>                                        __DRI_IMAGE_USE_SHARE |
>                                        __DRI_IMAGE_USE_LINEAR |
>                                        __DRI_IMAGE_USE_BACKBUFFER,
> diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
> index 7e3d82947b..705e71f9bf 100644
> --- a/src/loader/loader_dri3_helper.h
> +++ b/src/loader/loader_dri3_helper.h
> @@ -112,6 +112,7 @@ struct loader_dri3_vtable {
>  
>  struct loader_dri3_drawable {
>     xcb_connection_t *conn;
> +   xcb_screen_t *screen;
>     __DRIdrawable *dri_drawable;
>     xcb_drawable_t drawable;
>     int width;


More information about the mesa-dev mailing list