radeonsi: support for external buffers (ext_external_objects)

So far, the callback to create a resource from a memory object had code
for importing textures only. Modified it to allow importing buffers too.

Fixes the following piglit tests:
- ext_external_objects/vk-buf-exchange
- ext_external_objects/vk-pix-buf-update-errors
- ext_external_objects/vk-vert-buf-update-errors
- ext_external_objects/vk-vert-buf-reuse

v2: Used si_alloc_buffer_struct instead of CALLOC
v3: Fixed indentation issue, removed free in case of unsuccessful
allocation, joined two if conditions together

Signed-off-by: Eleni Maria Stea <estea@igalia.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6364>
diff --git a/src/gallium/drivers/radeonsi/si_buffer.c b/src/gallium/drivers/radeonsi/si_buffer.c
index 1237074..31f1318 100644
--- a/src/gallium/drivers/radeonsi/si_buffer.c
+++ b/src/gallium/drivers/radeonsi/si_buffer.c
@@ -731,6 +731,39 @@
    return &buf->b.b;
 }
 
+struct pipe_resource *si_buffer_from_winsys_buffer(struct pipe_screen *screen,
+                                                   const struct pipe_resource *templ,
+                                                   struct pb_buffer *imported_buf,
+                                                   bool dedicated)
+{
+   struct si_screen *sscreen = (struct si_screen *)screen;
+   struct si_resource *res = si_alloc_buffer_struct(screen, templ);
+
+   if (!res)
+      return 0;
+
+   res->buf = imported_buf;
+   res->gpu_address = sscreen->ws->buffer_get_virtual_address(res->buf);
+   res->bo_size = imported_buf->size;
+   res->bo_alignment = imported_buf->alignment;
+   res->domains = sscreen->ws->buffer_get_initial_domain(res->buf);
+
+   if (res->domains & RADEON_DOMAIN_VRAM)
+      res->vram_usage = res->bo_size;
+   else if (res->domains & RADEON_DOMAIN_GTT)
+      res->gart_usage = res->bo_size;
+
+   if (sscreen->ws->buffer_get_flags)
+      res->flags = sscreen->ws->buffer_get_flags(res->buf);
+
+   if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE) {
+      res->b.b.flags |= SI_RESOURCE_FLAG_UNMAPPABLE;
+      res->flags |= RADEON_FLAG_SPARSE;
+   }
+
+   return &res->b.b;
+}
+
 static struct pipe_resource *si_resource_create(struct pipe_screen *screen,
                                                 const struct pipe_resource *templ)
 {
diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h
index 7db1650..6cadec8 100644
--- a/src/gallium/drivers/radeonsi/si_pipe.h
+++ b/src/gallium/drivers/radeonsi/si_pipe.h
@@ -1926,4 +1926,9 @@
 #define PRINT_ERR(fmt, args...)                                                                    \
    fprintf(stderr, "EE %s:%d %s - " fmt, __FILE__, __LINE__, __func__, ##args)
 
+struct pipe_resource *si_buffer_from_winsys_buffer(struct pipe_screen *screen,
+                                                   const struct pipe_resource *templ,
+                                                   struct pb_buffer *imported_buf,
+                                                   bool dedicated);
+
 #endif
diff --git a/src/gallium/drivers/radeonsi/si_texture.c b/src/gallium/drivers/radeonsi/si_texture.c
index 93e52e7..25b6c38 100644
--- a/src/gallium/drivers/radeonsi/si_texture.c
+++ b/src/gallium/drivers/radeonsi/si_texture.c
@@ -2271,17 +2271,26 @@
    free(memobj);
 }
 
-static struct pipe_resource *si_texture_from_memobj(struct pipe_screen *screen,
+static struct pipe_resource *si_resource_from_memobj(struct pipe_screen *screen,
                                                     const struct pipe_resource *templ,
                                                     struct pipe_memory_object *_memobj,
                                                     uint64_t offset)
 {
    struct si_screen *sscreen = (struct si_screen *)screen;
    struct si_memory_object *memobj = (struct si_memory_object *)_memobj;
-   struct pipe_resource *tex = si_texture_from_winsys_buffer(
-      sscreen, templ, memobj->buf, memobj->stride, offset,
-      PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE | PIPE_HANDLE_USAGE_SHADER_WRITE, memobj->b.dedicated);
-   if (!tex)
+   struct pipe_resource *res;
+
+   if (templ->target == PIPE_BUFFER)
+      res = si_buffer_from_winsys_buffer(screen, templ, memobj->buf,
+                                         memobj->b.dedicated);
+   else
+      res = si_texture_from_winsys_buffer(sscreen, templ, memobj->buf,
+                                          memobj->stride,
+                                          offset,
+                                          PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE | PIPE_HANDLE_USAGE_SHADER_WRITE,
+                                          memobj->b.dedicated);
+
+   if (!res)
       return NULL;
 
    /* si_texture_from_winsys_buffer doesn't increment refcount of
@@ -2289,7 +2298,7 @@
     */
    struct pb_buffer *buf = NULL;
    pb_reference(&buf, memobj->buf);
-   return tex;
+   return res;
 }
 
 static bool si_check_resource_capability(struct pipe_screen *screen, struct pipe_resource *resource,
@@ -2317,7 +2326,7 @@
    sscreen->b.resource_get_handle = si_texture_get_handle;
    sscreen->b.resource_get_param = si_resource_get_param;
    sscreen->b.resource_get_info = si_texture_get_info;
-   sscreen->b.resource_from_memobj = si_texture_from_memobj;
+   sscreen->b.resource_from_memobj = si_resource_from_memobj;
    sscreen->b.memobj_create_from_handle = si_memobj_from_handle;
    sscreen->b.memobj_destroy = si_memobj_destroy;
    sscreen->b.check_resource_capability = si_check_resource_capability;