llvmpipe: add support for memory allocation APIs

This adds llvmpipe driver support for the vulkan split memory/resource API
and the the don't overallocate flag.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6082>
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.c b/src/gallium/drivers/llvmpipe/lp_texture.c
index efcfbed..e93b8a6 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.c
+++ b/src/gallium/drivers/llvmpipe/lp_texture.c
@@ -171,6 +171,7 @@
    lpr->sample_stride = total_size;
    total_size *= num_samples;
 
+   lpr->size_required = total_size;
    if (allocate) {
       lpr->tex_data = align_malloc(total_size, mip_align);
       if (!lpr->tex_data) {
@@ -242,9 +243,9 @@
 
 
 static struct pipe_resource *
-llvmpipe_resource_create_front(struct pipe_screen *_screen,
-                               const struct pipe_resource *templat,
-                               const void *map_front_private)
+llvmpipe_resource_create_all(struct pipe_screen *_screen,
+                             const struct pipe_resource *templat,
+                             const void *map_front_private, bool alloc_backing)
 {
    struct llvmpipe_screen *screen = llvmpipe_screen(_screen);
    struct llvmpipe_resource *lpr = CALLOC_STRUCT(llvmpipe_resource);
@@ -267,7 +268,7 @@
       }
       else {
          /* texture map */
-         if (!llvmpipe_texture_layout(screen, lpr, true))
+         if (!llvmpipe_texture_layout(screen, lpr, alloc_backing))
             goto fail;
       }
    }
@@ -283,17 +284,24 @@
        * read/write always LP_RASTER_BLOCK_SIZE pixels, but the element
        * offset doesn't need to be aligned to LP_RASTER_BLOCK_SIZE.
        */
-      lpr->data = align_malloc(bytes + (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float), 64);
-
       /*
        * buffers don't really have stride but it's probably safer
        * (for code doing same calculations for buffers and textures)
        * to put something sane in there.
        */
       lpr->row_stride[0] = bytes;
-      if (!lpr->data)
-         goto fail;
-      memset(lpr->data, 0, bytes);
+
+      lpr->size_required = bytes;
+      if (!(templat->flags & PIPE_RESOURCE_FLAG_DONT_OVER_ALLOCATE))
+         lpr->size_required += (LP_RASTER_BLOCK_SIZE - 1) * 4 * sizeof(float);
+
+      if (alloc_backing) {
+         lpr->data = align_malloc(lpr->size_required, 64);
+
+         if (!lpr->data)
+            goto fail;
+         memset(lpr->data, 0, bytes);
+      }
    }
 
    lpr->id = id_counter++;
@@ -309,6 +317,13 @@
    return NULL;
 }
 
+static struct pipe_resource *
+llvmpipe_resource_create_front(struct pipe_screen *_screen,
+                               const struct pipe_resource *templat,
+                               const void *map_front_private)
+{
+   return llvmpipe_resource_create_all(_screen, templat, map_front_private, true);
+}
 
 static struct pipe_resource *
 llvmpipe_resource_create(struct pipe_screen *_screen,
@@ -317,6 +332,21 @@
    return llvmpipe_resource_create_front(_screen, templat, NULL);
 }
 
+static struct pipe_resource *
+llvmpipe_resource_create_unbacked(struct pipe_screen *_screen,
+                                  const struct pipe_resource *templat,
+                                  uint64_t *size_required)
+{
+   struct pipe_resource *pt;
+   struct llvmpipe_resource *lpr;
+   pt = llvmpipe_resource_create_all(_screen, templat, NULL, false);
+   if (!pt)
+      return pt;
+   lpr = llvmpipe_resource(pt);
+   lpr->backable = true;
+   *size_required = lpr->size_required;
+   return pt;
+}
 
 static void
 llvmpipe_resource_destroy(struct pipe_screen *pscreen,
@@ -325,23 +355,24 @@
    struct llvmpipe_screen *screen = llvmpipe_screen(pscreen);
    struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
 
-   if (lpr->dt) {
-      /* display target */
-      struct sw_winsys *winsys = screen->winsys;
-      winsys->displaytarget_destroy(winsys, lpr->dt);
-   }
-   else if (llvmpipe_resource_is_texture(pt)) {
-      /* free linear image data */
-      if (lpr->tex_data) {
-         align_free(lpr->tex_data);
-         lpr->tex_data = NULL;
+   if (!lpr->backable) {
+      if (lpr->dt) {
+         /* display target */
+         struct sw_winsys *winsys = screen->winsys;
+         winsys->displaytarget_destroy(winsys, lpr->dt);
+      }
+      else if (llvmpipe_resource_is_texture(pt)) {
+         /* free linear image data */
+         if (lpr->tex_data) {
+            align_free(lpr->tex_data);
+            lpr->tex_data = NULL;
+         }
+      }
+      else if (!lpr->userBuffer) {
+         if (lpr->data)
+            align_free(lpr->data);
       }
    }
-   else if (!lpr->userBuffer) {
-      assert(lpr->data);
-      align_free(lpr->data);
-   }
-
 #ifdef DEBUG
    if (lpr->next)
       remove_from_list(lpr);
@@ -793,6 +824,45 @@
    llvmpipe_finish(pipe, "barrier");
 }
 
+static struct pipe_memory_allocation *llvmpipe_allocate_memory(struct pipe_screen *screen, uint64_t size)
+{
+   return os_malloc_aligned(size, 256);
+}
+
+static void llvmpipe_free_memory(struct pipe_screen *screen,
+                                 struct pipe_memory_allocation *pmem)
+{
+   os_free_aligned(pmem);
+}
+
+static void llvmpipe_resource_bind_backing(struct pipe_screen *screen,
+                                           struct pipe_resource *pt,
+                                           struct pipe_memory_allocation *pmem,
+                                           uint64_t offset)
+{
+   struct llvmpipe_resource *lpr = llvmpipe_resource(pt);
+
+   if (!lpr->backable)
+      return;
+
+   if (llvmpipe_resource_is_texture(&lpr->base))
+      lpr->tex_data = (char *)pmem + offset;
+   else
+      lpr->data = (char *)pmem + offset;
+   lpr->backing_offset = offset;
+}
+
+static void *llvmpipe_map_memory(struct pipe_screen *screen,
+                                 struct pipe_memory_allocation *pmem)
+{
+   return pmem;
+}
+
+static void llvmpipe_unmap_memory(struct pipe_screen *screen,
+                                  struct pipe_memory_allocation *pmem)
+{
+}
+
 #ifdef DEBUG
 void
 llvmpipe_print_resources(void)
@@ -814,6 +884,17 @@
 }
 #endif
 
+static void
+llvmpipe_get_resource_info(struct pipe_screen *screen,
+			   struct pipe_resource *resource,
+			   unsigned *stride,
+			   unsigned *offset)
+{
+   struct llvmpipe_resource *lpr = llvmpipe_resource(resource);
+
+   *stride = lpr->row_stride[0];
+   *offset = 0;
+}
 
 void
 llvmpipe_init_screen_resource_funcs(struct pipe_screen *screen)
@@ -836,6 +917,16 @@
    screen->resource_from_handle = llvmpipe_resource_from_handle;
    screen->resource_get_handle = llvmpipe_resource_get_handle;
    screen->can_create_resource = llvmpipe_can_create_resource;
+
+   screen->resource_create_unbacked = llvmpipe_resource_create_unbacked;
+
+   screen->resource_get_info = llvmpipe_get_resource_info;
+   screen->allocate_memory = llvmpipe_allocate_memory;
+   screen->free_memory = llvmpipe_free_memory;
+   screen->map_memory = llvmpipe_map_memory;
+   screen->unmap_memory = llvmpipe_unmap_memory;
+
+   screen->resource_bind_backing = llvmpipe_resource_bind_backing;
 }
 
 
diff --git a/src/gallium/drivers/llvmpipe/lp_texture.h b/src/gallium/drivers/llvmpipe/lp_texture.h
index 5965ef8..ba2cdff 100644
--- a/src/gallium/drivers/llvmpipe/lp_texture.h
+++ b/src/gallium/drivers/llvmpipe/lp_texture.h
@@ -91,6 +91,10 @@
    unsigned id;  /**< temporary, for debugging */
 
    unsigned sample_stride;
+
+   uint64_t size_required;
+   uint64_t backing_offset;
+   bool backable;
 #ifdef DEBUG
    /** for linked list */
    struct llvmpipe_resource *prev, *next;