Mesa (master): radeonsi: Add auxiliary plane support.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Nov 13 03:44:46 UTC 2020


Module: Mesa
Branch: master
Commit: 3fa3bc19a28347c67411d494cf286c54b8dedf85
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=3fa3bc19a28347c67411d494cf286c54b8dedf85

Author: Bas Nieuwenhuizen <bas at basnieuwenhuizen.nl>
Date:   Sun Mar 15 14:47:25 2020 +0100

radeonsi: Add auxiliary plane support.

This adds support for multiple DRM planes for a single format plane
and uses that to enable DCC support with modifiers.

With the implicit flush patches we can also enable displayable DCC
both with and without DCC as the X server and compositors know not
to do frontbuffer rendering onto images with multiple DRM planes.

For now we require that the extra planes are essentially fixed though.
We require that the offset/stride are the same as ac_surface computes
and that all planes are in the same buffer. This is mainly for
simplicity and could be somewhat more relaxed in the future given
a strong usecase.

Reviewed-by: Marek Olšák <marek.olsak at amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6176>

---

 src/gallium/drivers/radeonsi/si_texture.c | 144 ++++++++++++++++++++++++++----
 1 file changed, 129 insertions(+), 15 deletions(-)

diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index bc4e259b754..58c0271a985 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -46,6 +46,8 @@ static enum radeon_surf_mode si_choose_tiling(struct si_screen *sscreen,
                                               const struct pipe_resource *templ,
                                               bool tc_compatible_htile);
 
+static bool si_texture_is_aux_plane(const struct pipe_resource *resource);
+
 bool si_prepare_for_dma_blit(struct si_context *sctx, struct si_texture *dst, unsigned dst_level,
                              unsigned dstx, unsigned dsty, unsigned dstz, struct si_texture *src,
                              unsigned src_level, const struct pipe_box *src_box)
@@ -601,8 +603,10 @@ static bool si_resource_get_param(struct pipe_screen *screen, struct pipe_contex
                                   enum pipe_resource_param param, unsigned handle_usage,
                                   uint64_t *value)
 {
-   for (unsigned i = 0; i < plane; i++)
+   while (plane && resource->next && !si_texture_is_aux_plane(resource->next)) {
+      --plane;
       resource = resource->next;
+   }
 
    struct si_screen *sscreen = (struct si_screen *)screen;
    struct si_texture *tex = (struct si_texture *)resource;
@@ -610,26 +614,28 @@ static bool si_resource_get_param(struct pipe_screen *screen, struct pipe_contex
 
    switch (param) {
    case PIPE_RESOURCE_PARAM_NPLANES:
-      *value = resource->target == PIPE_BUFFER ? 1 : tex->num_planes;
+      if (resource->target == PIPE_BUFFER)
+         *value = 1;
+      else if (tex->num_planes > 1)
+         *value = tex->num_planes;
+      else
+         *value = ac_surface_get_nplanes(&tex->surface);
       return true;
 
    case PIPE_RESOURCE_PARAM_STRIDE:
       if (resource->target == PIPE_BUFFER)
          *value = 0;
-      else if (sscreen->info.chip_class >= GFX9)
-         *value = tex->surface.u.gfx9.surf_pitch * tex->surface.bpe;
       else
-         *value = tex->surface.u.legacy.level[0].nblk_x * tex->surface.bpe;
+         *value = ac_surface_get_plane_stride(sscreen->info.chip_class,
+                                              &tex->surface, plane);
       return true;
 
    case PIPE_RESOURCE_PARAM_OFFSET:
       if (resource->target == PIPE_BUFFER)
          *value = 0;
-      else if (sscreen->info.chip_class >= GFX9)
-         *value = tex->surface.u.gfx9.surf_offset + layer * tex->surface.u.gfx9.surf_slice_size;
       else
-         *value = tex->surface.u.legacy.level[0].offset +
-                  layer * (uint64_t)tex->surface.u.legacy.level[0].slice_size_dw * 4;
+         *value = ac_surface_get_plane_offset(sscreen->info.chip_class,
+                                              &tex->surface, plane, layer);
       return true;
 
    case PIPE_RESOURCE_PARAM_MODIFIER:
@@ -692,12 +698,16 @@ static bool si_texture_get_handle(struct pipe_screen *screen, struct pipe_contex
    sctx = (struct si_context *)(ctx ? ctx : sscreen->aux_context);
 
    if (resource->target != PIPE_BUFFER) {
+      unsigned plane = whandle->plane;
+
       /* Individual planes are chained pipe_resource instances. */
-      for (unsigned i = 0; i < whandle->plane; i++) {
+      while (plane && resource->next && !si_texture_is_aux_plane(resource->next)) {
          resource = resource->next;
+         --plane;
+      }
+
          res = si_resource(resource);
          tex = (struct si_texture *)resource;
-      }
 
       /* This is not supported now, but it might be required for OpenCL
        * interop in the future.
@@ -705,6 +715,15 @@ static bool si_texture_get_handle(struct pipe_screen *screen, struct pipe_contex
       if (resource->nr_samples > 1 || tex->is_depth)
          return false;
 
+      if (plane) {
+         whandle->offset = ac_surface_get_plane_offset(sscreen->info.chip_class,
+                                                       &tex->surface, plane, 0);
+         whandle->stride = ac_surface_get_plane_stride(sscreen->info.chip_class,
+                                                       &tex->surface, plane);
+         whandle->modifier = tex->surface.modifier;
+         return sscreen->ws->buffer_get_handle(sscreen->ws, res->buf, whandle);
+      }
+
       /* Move a suballocated texture into a non-suballocated allocation. */
       if (sscreen->ws->buffer_is_suballocated(res->buf) || tex->surface.tile_swizzle ||
           (tex->buffer.flags & RADEON_FLAG_NO_INTERPROCESS_SHARING &&
@@ -1427,12 +1446,11 @@ static void si_query_dmabuf_modifiers(struct pipe_screen *screen,
 
    unsigned ac_mod_count = max;
    ac_get_supported_modifiers(&sscreen->info, &(struct ac_modifier_options) {
-         /* Disable DCC until we have support for auxiliary planes. */
-         .dcc = false,
+         .dcc = !(sscreen->debug_flags & DBG(NO_DCC)),
          /* Do not support DCC with retiling yet. This needs explicit
           * resource flushes, but the app has no way to promise doing
           * flushes with modifiers. */
-         .dcc_retile = false,
+         .dcc_retile = !(sscreen->debug_flags & DBG(NO_DCC)),
       }, format, &ac_mod_count,  max ? modifiers : NULL);
    if (max && external_only) {
       for (unsigned i = 0; i < ac_mod_count; ++i)
@@ -1481,6 +1499,24 @@ si_is_dmabuf_modifier_supported(struct pipe_screen *screen,
    return supported;
 }
 
+static unsigned
+si_get_dmabuf_modifier_planes(struct pipe_screen *pscreen, uint64_t modifier,
+                             enum pipe_format format)
+{
+   unsigned planes = util_format_get_num_planes(format);
+
+   if (IS_AMD_FMT_MOD(modifier) && planes == 1) {
+      if (AMD_FMT_MOD_GET(DCC_RETILE, modifier))
+         return 3;
+      else if (AMD_FMT_MOD_GET(DCC, modifier))
+         return 2;
+      else
+         return 1;
+   }
+
+   return planes;
+}
+
 static struct pipe_resource *
 si_texture_create_with_modifiers(struct pipe_screen *screen,
                                  const struct pipe_resource *templ,
@@ -1527,6 +1563,47 @@ si_texture_create_with_modifiers(struct pipe_screen *screen,
    return si_texture_create_with_modifier(screen, templ, modifier);
 }
 
+/* State trackers create separate textures in a next-chain for extra planes
+ * even if those are planes created purely for modifiers. Because the linking
+ * of the chain happens outside of the driver, and NULL is interpreted as
+ * failure, let's create some dummy texture structs. We could use these
+ * later to use the offsets for linking if we really wanted to.
+ *
+ * For now just create a dummy struct and completely ignore it.
+ *
+ * Potentially in the future we could store stride/offset and use it during
+ * creation, though we might want to change how linking is done first.
+ */
+
+struct si_auxiliary_texture {
+   struct threaded_resource b;
+   struct pb_buffer *buffer;
+   uint32_t offset;
+   uint32_t stride;
+};
+
+static void si_auxiliary_texture_destroy(struct pipe_screen *screen,
+                                         struct pipe_resource *ptex)
+{
+   struct si_auxiliary_texture *tex = (struct si_auxiliary_texture *)ptex;
+
+   pb_reference(&tex->buffer, NULL);
+   FREE(ptex);
+}
+
+static const struct u_resource_vtbl si_auxiliary_texture_vtbl = {
+   NULL,                        /* get_handle */
+   si_auxiliary_texture_destroy,    /* resource_destroy */
+   NULL,                        /* transfer_map */
+   NULL,                        /* transfer_flush_region */
+   NULL,                        /* transfer_unmap */
+};
+
+static bool si_texture_is_aux_plane(const struct pipe_resource *resource)
+{
+   return ((struct threaded_resource*)resource)->vtbl == &si_auxiliary_texture_vtbl;
+}
+
 static struct pipe_resource *si_texture_from_winsys_buffer(struct si_screen *sscreen,
                                                            const struct pipe_resource *templ,
                                                            struct pb_buffer *buf, unsigned stride,
@@ -1588,13 +1665,34 @@ static struct pipe_resource *si_texture_from_winsys_buffer(struct si_screen *ssc
 
    /* Account for multiple planes with lowered yuv import. */
    struct pipe_resource *next_plane = tex->buffer.b.b.next;
-   while(next_plane) {
+   while (next_plane && !si_texture_is_aux_plane(next_plane)) {
       struct si_texture *next_tex = (struct si_texture *)next_plane;
       ++next_tex->num_planes;
       ++tex->num_planes;
       next_plane = next_plane->next;
    }
 
+   unsigned nplanes = ac_surface_get_nplanes(&tex->surface);
+   unsigned plane = 1;
+   while (next_plane) {
+      struct si_auxiliary_texture *ptex = (struct si_auxiliary_texture *)next_plane;
+      if (plane >= nplanes || ptex->buffer != tex->buffer.buf ||
+          ptex->offset != ac_surface_get_plane_offset(sscreen->info.chip_class,
+                                                      &tex->surface, plane, 0) ||
+          ptex->stride != ac_surface_get_plane_stride(sscreen->info.chip_class,
+                                                      &tex->surface, plane)) {
+         si_texture_reference(&tex, NULL);
+         return NULL;
+      }
+      ++plane;
+      next_plane = next_plane->next;
+   }
+
+   if (plane != nplanes && tex->num_planes == 1) {
+      si_texture_reference(&tex, NULL);
+      return NULL;
+   }
+
    if (!ac_surface_set_umd_metadata(&sscreen->info, &tex->surface,
                                     tex->buffer.b.b.nr_storage_samples,
                                     tex->buffer.b.b.last_level + 1,
@@ -1642,6 +1740,21 @@ static struct pipe_resource *si_texture_from_handle(struct pipe_screen *screen,
    if (!buf)
       return NULL;
 
+   if (whandle->plane >= util_format_get_num_planes(whandle->format)) {
+      struct si_auxiliary_texture *tex = CALLOC_STRUCT(si_auxiliary_texture);
+      if (!tex)
+         return NULL;
+      tex->b.b = *templ;
+      tex->b.vtbl = &si_auxiliary_texture_vtbl;
+      tex->stride = whandle->stride;
+      tex->offset = whandle->offset;
+      tex->buffer = buf;
+      pipe_reference_init(&tex->b.b.reference, 1);
+      tex->b.b.screen = screen;
+
+      return &tex->b.b;
+   }
+
    return si_texture_from_winsys_buffer(sscreen, templ, buf, whandle->stride, whandle->offset,
                                         whandle->modifier, usage, true);
 }
@@ -2488,6 +2601,7 @@ void si_init_screen_texture_functions(struct si_screen *sscreen)
    sscreen->b.check_resource_capability = si_check_resource_capability;
    sscreen->b.query_dmabuf_modifiers = si_query_dmabuf_modifiers;
    sscreen->b.is_dmabuf_modifier_supported = si_is_dmabuf_modifier_supported;
+   sscreen->b.get_dmabuf_modifier_planes = si_get_dmabuf_modifier_planes;
 }
 
 void si_init_context_texture_functions(struct si_context *sctx)



More information about the mesa-commit mailing list