asahi: Make agx_flush_resource reallocate non-shareable resources
authorAsahi Lina <lina@asahilina.net>
Sun, 26 Feb 2023 06:00:45 +0000 (15:00 +0900)
committerMarge Bot <emma+marge@anholt.net>
Thu, 16 Mar 2023 20:42:01 +0000 (20:42 +0000)
It's not legal to share a resource that isn't PIPE_BIND_SHARED, but
flush_resource needs to prepare a resource for potential sharing.
Let's allocate a new resource and blit it over when this happens.

See also:
https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/13154

Signed-off-by: Asahi Lina <lina@asahilina.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21620>

src/gallium/drivers/asahi/agx_pipe.c

index 5d825e6..5556c69 100644 (file)
@@ -940,9 +940,64 @@ agx_clear(struct pipe_context *pctx, unsigned buffers,
 }
 
 static void
-agx_flush_resource(struct pipe_context *ctx, struct pipe_resource *resource)
+agx_flush_resource(struct pipe_context *pctx, struct pipe_resource *pres)
 {
-   agx_flush_writer(agx_context(ctx), agx_resource(resource), "flush_resource");
+   struct agx_resource *rsrc = agx_resource(pres);
+
+   /* flush_resource is used to prepare resources for sharing, so if this is not
+    * already a shareabe resource, make it so
+    */
+   struct agx_bo *old = rsrc->bo;
+   if (!(old->flags & AGX_BO_SHAREABLE)) {
+      assert(rsrc->layout.levels == 1 &&
+             "Shared resources must not be mipmapped");
+      assert(rsrc->layout.sample_count_sa == 1 &&
+             "Shared resources must not be multisampled");
+      assert(rsrc->bo);
+      assert(!(pres->bind & PIPE_BIND_SHARED));
+
+      struct pipe_resource templ = *pres;
+      templ.bind |= PIPE_BIND_SHARED;
+
+      /* Create a new shareable resource */
+      struct agx_resource *new_res =
+         agx_resource(pctx->screen->resource_create(pctx->screen, &templ));
+
+      assert(new_res);
+
+      /* Blit it over */
+      struct pipe_blit_info blit = {0};
+
+      u_box_3d(0, 0, 0, rsrc->layout.width_px, rsrc->layout.height_px,
+               rsrc->layout.depth_px, &blit.dst.box);
+      blit.src.box = blit.dst.box;
+
+      blit.dst.resource = &new_res->base;
+      blit.dst.format = new_res->base.format;
+      blit.dst.level = 0;
+      blit.src.resource = pres;
+      blit.src.format = pres->format;
+      blit.src.level = 0;
+      blit.mask = util_format_get_mask(blit.src.format);
+      blit.filter = PIPE_TEX_FILTER_NEAREST;
+      agx_blit(pctx, &blit);
+
+      /* Flush the blit out, to make sure the old resource is no longer used */
+      agx_flush_writer(agx_context(pctx), new_res, "flush_resource");
+
+      /* Copy the bind flags and swap the BOs */
+      rsrc->base.bind = new_res->base.bind;
+      rsrc->bo = new_res->bo;
+      new_res->bo = old;
+
+      /* Free the new resource, which now owns the old BO */
+      pipe_resource_reference((struct pipe_resource **)&new_res, NULL);
+   } else {
+      /* Otherwise just claim it's already shared */
+      pres->bind |= PIPE_BIND_SHARED;
+      agx_flush_writer(agx_context(pctx), rsrc, "flush_resource");
+   }
+
 }
 
 /*