asahi: Make resource creation code modifier-aware
authorAsahi Lina <lina@asahilina.net>
Tue, 8 Nov 2022 21:17:36 +0000 (16:17 -0500)
committerMarge Bot <emma+marge@anholt.net>
Thu, 17 Nov 2022 02:47:10 +0000 (02:47 +0000)
Needed for WSI.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19606>

src/gallium/drivers/asahi/agx_pipe.c

index 7d2734a..0bedba6 100644 (file)
@@ -259,9 +259,6 @@ agx_resource_get_handle(struct pipe_screen *pscreen,
    return true;
 }
 
-/* Linear textures require specifying their strides explicitly, which only
- * works for 2D textures. Rectangle textures are a special case of 2D.
- */
 
 static bool
 agx_resource_get_param(struct pipe_screen *pscreen,
@@ -303,24 +300,78 @@ agx_is_2d(enum pipe_texture_target target)
    return (target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_RECT);
 }
 
+static bool
+agx_linear_allowed(const struct agx_resource *pres)
+{
+   /* Mipmapping not allowed with linear */
+   if (pres->base.last_level != 0)
+      return false;
+
+   switch (pres->base.target) {
+   /* 1D is always linear */
+   case PIPE_BUFFER:
+   case PIPE_TEXTURE_1D:
+
+   /* Linear textures require specifying their strides explicitly, which only
+    * works for 2D textures. Rectangle textures are a special case of 2D.
+    */
+   case PIPE_TEXTURE_2D:
+   case PIPE_TEXTURE_RECT:
+      break;
+
+   /* No other texture type can specify a stride */
+   default:
+      return false;
+   }
+
+   return true;
+}
+
+static bool
+agx_twiddled_allowed(const struct agx_resource *pres)
+{
+   /* Certain binds force linear */
+   if (pres->base.bind & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_LINEAR))
+      return false;
+
+   /* Buffers must be linear, and it does not make sense to twiddle 1D */
+   if (pres->base.target == PIPE_BUFFER || pres->base.target == PIPE_TEXTURE_1D)
+      return false;
+
+   /* Anything else may be twiddled */
+   return true;
+}
+
 static uint64_t
-agx_select_modifier(const struct agx_resource *pres)
+agx_select_modifier_from_list(const struct agx_resource *pres,
+                              const uint64_t *modifiers, int count)
 {
-   /* Buffers are always linear */
-   if (pres->base.target == PIPE_BUFFER)
-      return DRM_FORMAT_MOD_LINEAR;
+   if (agx_twiddled_allowed(pres) &&
+       drm_find_modifier(DRM_FORMAT_MOD_APPLE_TWIDDLED, modifiers, count))
+      return DRM_FORMAT_MOD_APPLE_TWIDDLED;
 
-   /* Optimize streaming textures */
-   if (pres->base.usage == PIPE_USAGE_STREAM && agx_is_2d(pres->base.target))
+   if (agx_linear_allowed(pres) &&
+       drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count))
       return DRM_FORMAT_MOD_LINEAR;
 
-   /* Default to tiled */
-   return DRM_FORMAT_MOD_APPLE_TWIDDLED;
+   /* We didn't find anything */
+   return DRM_FORMAT_MOD_INVALID;
+}
+
+static uint64_t
+agx_select_best_modifier(const struct agx_resource *pres)
+{
+   if (agx_twiddled_allowed(pres))
+      return DRM_FORMAT_MOD_APPLE_TWIDDLED;
+
+   assert(agx_linear_allowed(pres));
+   return DRM_FORMAT_MOD_LINEAR;
 }
 
 static struct pipe_resource *
-agx_resource_create(struct pipe_screen *screen,
-                    const struct pipe_resource *templ)
+agx_resource_create_with_modifiers(struct pipe_screen *screen,
+                                   const struct pipe_resource *templ,
+                                   const uint64_t *modifiers, int count)
 {
    struct agx_device *dev = agx_device(screen);
    struct agx_resource *nresource;
@@ -332,30 +383,73 @@ agx_resource_create(struct pipe_screen *screen,
    nresource->base = *templ;
    nresource->base.screen = screen;
 
-   nresource->modifier = agx_select_modifier(nresource);
+   if (modifiers) {
+      nresource->modifier = agx_select_modifier_from_list(nresource, modifiers, count);
+
+      /* There may not be a matching modifier, bail if so */
+      if (nresource->modifier == DRM_FORMAT_MOD_INVALID)
+         return NULL;
+   } else {
+      nresource->modifier = agx_select_best_modifier(nresource);
+
+      assert(nresource->modifier != DRM_FORMAT_MOD_INVALID);
+   }
+
    nresource->mipmapped = (templ->last_level > 0);
 
    assert(templ->format != PIPE_FORMAT_Z24X8_UNORM &&
           templ->format != PIPE_FORMAT_Z24_UNORM_S8_UINT &&
           "u_transfer_helper should have lowered");
 
-   nresource->layout = (struct ail_layout) {
-      .tiling = (nresource->modifier == DRM_FORMAT_MOD_LINEAR) ?
-                AIL_TILING_LINEAR : AIL_TILING_TWIDDLED,
-      .format = templ->format,
-      .width_px = templ->width0,
-      .height_px = templ->height0,
-      .depth_px = templ->depth0 * templ->array_size,
-      .levels = templ->last_level + 1
-   };
+   agx_resource_setup(dev, nresource);
 
    pipe_reference_init(&nresource->base.reference, 1);
 
    struct sw_winsys *winsys = ((struct agx_screen *) screen)->winsys;
 
-   if (templ->bind & (PIPE_BIND_DISPLAY_TARGET |
-                      PIPE_BIND_SCANOUT |
-                      PIPE_BIND_SHARED)) {
+   ail_make_miptree(&nresource->layout);
+
+   if (dev->ro && (templ->bind & PIPE_BIND_SCANOUT)) {
+      struct winsys_handle handle;
+      assert(util_format_get_blockwidth(templ->format) == 1);
+      assert(util_format_get_blockheight(templ->format) == 1);
+
+      unsigned width = templ->width0;
+      unsigned stride = templ->width0 * util_format_get_blocksize(templ->format);
+      unsigned size = nresource->layout.size_B;
+      unsigned effective_rows = DIV_ROUND_UP(size, stride);
+
+      struct pipe_resource scanout_tmpl = {
+            .target = nresource->base.target,
+            .format = templ->format,
+            .width0 = width,
+            .height0 = effective_rows,
+            .depth0 = 1,
+            .array_size = 1,
+      };
+
+      nresource->scanout = renderonly_scanout_for_resource(&scanout_tmpl,
+                                                   dev->ro,
+                                                   &handle);
+
+      if (!nresource->scanout) {
+            fprintf(stderr, "Failed to create scanout resource\n");
+            free(nresource);
+            return NULL;
+      }
+      assert(handle.type == WINSYS_HANDLE_TYPE_FD);
+      nresource->bo = agx_bo_import(dev, handle.handle);
+      close(handle.handle);
+
+      if (!nresource->bo) {
+            free(nresource);
+            return NULL;
+      }
+
+      return &nresource->base;
+   }
+
+   if (winsys && templ->bind & PIPE_BIND_DISPLAY_TARGET) {
       unsigned width = templ->width0;
       unsigned height = templ->height0;
 
@@ -382,7 +476,6 @@ agx_resource_create(struct pipe_screen *screen,
       }
    }
 
-   ail_make_miptree(&nresource->layout);
    nresource->bo = agx_bo_create(dev, nresource->layout.size_B, AGX_MEMORY_TYPE_FRAMEBUFFER);
 
    if (!nresource->bo) {
@@ -393,6 +486,13 @@ agx_resource_create(struct pipe_screen *screen,
    return &nresource->base;
 }
 
+static struct pipe_resource *
+agx_resource_create(struct pipe_screen *screen,
+                    const struct pipe_resource *templ)
+{
+   return agx_resource_create_with_modifiers(screen, templ, NULL, 0);
+}
+
 static void
 agx_resource_destroy(struct pipe_screen *screen,
                      struct pipe_resource *prsrc)
@@ -1418,6 +1518,8 @@ agx_screen_create(int fd, struct renderonly *ro, struct sw_winsys *winsys)
    screen->context_create = agx_create_context;
    screen->resource_from_handle = agx_resource_from_handle;
    screen->resource_get_handle = agx_resource_get_handle;
+   screen->resource_get_param = agx_resource_get_param;
+   screen->resource_create_with_modifiers = agx_resource_create_with_modifiers;
    screen->flush_frontbuffer = agx_flush_frontbuffer;
    screen->get_timestamp = u_default_get_timestamp;
    screen->fence_reference = agx_fence_reference;