nvc0: support PIPE_CAP_RESOURCE_FROM_USER_MEMORY_COMPUTE_ONLY
authorKarol Herbst <kherbst@redhat.com>
Wed, 27 May 2020 14:29:06 +0000 (16:29 +0200)
committerMarge Bot <eric+marge@anholt.net>
Tue, 14 Jul 2020 19:59:12 +0000 (19:59 +0000)
v2: rework by adding a new buffer status

Signed-off-by: Karol Herbst <kherbst@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5906>

src/gallium/drivers/nouveau/nouveau_buffer.c
src/gallium/drivers/nouveau/nouveau_buffer.h
src/gallium/drivers/nouveau/nvc0/nvc0_resource.c

index abb4105099a165861edc80e20f4c012c64f8ee85..acc0e8c8d2988844a20e9fb90cbeba61f46b2a13 100644 (file)
@@ -78,6 +78,8 @@ release_allocation(struct nouveau_mm_allocation **mm,
 inline void
 nouveau_buffer_release_gpu_storage(struct nv04_resource *buf)
 {
+   assert(!(buf->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+
    if (buf->fence && buf->fence->state < NOUVEAU_FENCE_STATE_FLUSHED) {
       nouveau_fence_work(buf->fence, nouveau_fence_unref_bo, buf->bo);
       buf->bo = NULL;
@@ -566,6 +568,9 @@ nouveau_copy_buffer(struct nouveau_context *nv,
 {
    assert(dst->base.target == PIPE_BUFFER && src->base.target == PIPE_BUFFER);
 
+   assert(!(dst->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+   assert(!(src->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+
    if (likely(dst->domain) && likely(src->domain)) {
       nv->copy_data(nv,
                     dst->bo, dst->offset + dstx, dst->domain,
@@ -599,7 +604,8 @@ nouveau_resource_map_offset(struct nouveau_context *nv,
                             struct nv04_resource *res, uint32_t offset,
                             uint32_t flags)
 {
-   if (unlikely(res->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY))
+   if (unlikely(res->status & NOUVEAU_BUFFER_STATUS_USER_MEMORY) ||
+       unlikely(res->status & NOUVEAU_BUFFER_STATUS_USER_PTR))
       return res->data + offset;
 
    if (res->domain == NOUVEAU_BO_VRAM) {
@@ -622,7 +628,6 @@ nouveau_resource_map_offset(struct nouveau_context *nv,
    return (uint8_t *)res->bo->map + res->offset + offset;
 }
 
-
 const struct u_resource_vtbl nouveau_buffer_vtbl =
 {
    u_default_resource_get_handle,     /* get_handle */
@@ -632,6 +637,46 @@ const struct u_resource_vtbl nouveau_buffer_vtbl =
    nouveau_buffer_transfer_unmap,        /* transfer_unmap */
 };
 
+static void
+nouveau_user_ptr_destroy(struct pipe_screen *pscreen,
+                         struct pipe_resource *presource)
+{
+   struct nv04_resource *res = nv04_resource(presource);
+   FREE(res);
+}
+
+static void *
+nouveau_user_ptr_transfer_map(struct pipe_context *pipe,
+                              struct pipe_resource *resource,
+                              unsigned level, unsigned usage,
+                              const struct pipe_box *box,
+                              struct pipe_transfer **ptransfer)
+{
+   struct nouveau_transfer *tx = MALLOC_STRUCT(nouveau_transfer);
+   if (!tx)
+      return NULL;
+   nouveau_buffer_transfer_init(tx, resource, box, usage);
+   *ptransfer = &tx->base;
+   return nv04_resource(resource)->data;
+}
+
+static void
+nouveau_user_ptr_transfer_unmap(struct pipe_context *pipe,
+                                struct pipe_transfer *transfer)
+{
+   struct nouveau_transfer *tx = nouveau_transfer(transfer);
+   FREE(tx);
+}
+
+const struct u_resource_vtbl nouveau_user_ptr_buffer_vtbl =
+{
+   u_default_resource_get_handle,   /* get_handle */
+   nouveau_user_ptr_destroy,        /* resource_destroy */
+   nouveau_user_ptr_transfer_map,   /* transfer_map */
+   u_default_transfer_flush_region, /* transfer_flush_region */
+   nouveau_user_ptr_transfer_unmap, /* transfer_unmap */
+};
+
 struct pipe_resource *
 nouveau_buffer_create(struct pipe_screen *pscreen,
                       const struct pipe_resource *templ)
@@ -700,6 +745,32 @@ fail:
    return NULL;
 }
 
+struct pipe_resource *
+nouveau_buffer_create_from_user(struct pipe_screen *pscreen,
+                                const struct pipe_resource *templ,
+                                void *user_ptr)
+{
+   struct nv04_resource *buffer;
+
+   buffer = CALLOC_STRUCT(nv04_resource);
+   if (!buffer)
+      return NULL;
+
+   buffer->base = *templ;
+   buffer->vtbl = &nouveau_user_ptr_buffer_vtbl;
+   /* set address and data to the same thing for higher compatibility with
+    * existing code. It's correct nonetheless as the same pointer is equally
+    * valid on the CPU and the GPU.
+    */
+   buffer->address = (uint64_t)user_ptr;
+   buffer->data = user_ptr;
+   buffer->status = NOUVEAU_BUFFER_STATUS_USER_PTR;
+   buffer->base.screen = pscreen;
+
+   pipe_reference_init(&buffer->base.reference, 1);
+
+   return &buffer->base;
+}
 
 struct pipe_resource *
 nouveau_user_buffer_create(struct pipe_screen *pscreen, void *ptr,
@@ -747,6 +818,8 @@ bool
 nouveau_buffer_migrate(struct nouveau_context *nv,
                        struct nv04_resource *buf, const unsigned new_domain)
 {
+   assert(!(buf->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+
    struct nouveau_screen *screen = nv->screen;
    struct nouveau_bo *bo;
    const unsigned old_domain = buf->domain;
@@ -818,6 +891,8 @@ nouveau_user_buffer_upload(struct nouveau_context *nv,
                            struct nv04_resource *buf,
                            unsigned base, unsigned size)
 {
+   assert(!(buf->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+
    struct nouveau_screen *screen = nouveau_screen(buf->base.screen);
    int ret;
 
@@ -846,6 +921,8 @@ nouveau_buffer_invalidate(struct pipe_context *pipe,
    struct nv04_resource *buf = nv04_resource(resource);
    int ref = buf->base.reference.count - 1;
 
+   assert(!(buf->status & NOUVEAU_BUFFER_STATUS_USER_PTR));
+
    /* Shared buffers shouldn't get reallocated */
    if (unlikely(buf->base.bind & PIPE_BIND_SHARED))
       return;
index 3a33fae9ce2fa3fd668d52f9010945aca4fef60a..b43db81d29840919155445384dd9a174edb65919 100644 (file)
@@ -14,10 +14,13 @@ struct nouveau_bo;
  *
  * USER_MEMORY: resource->data is a pointer to client memory and may change
  *  between GL calls
+ *
+ * USER_PTR: bo is backed by user memory mapped into the GPUs VM
  */
 #define NOUVEAU_BUFFER_STATUS_GPU_READING (1 << 0)
 #define NOUVEAU_BUFFER_STATUS_GPU_WRITING (1 << 1)
 #define NOUVEAU_BUFFER_STATUS_DIRTY       (1 << 2)
+#define NOUVEAU_BUFFER_STATUS_USER_PTR    (1 << 6)
 #define NOUVEAU_BUFFER_STATUS_USER_MEMORY (1 << 7)
 
 #define NOUVEAU_BUFFER_STATUS_REALLOC_MASK NOUVEAU_BUFFER_STATUS_USER_MEMORY
@@ -91,6 +94,11 @@ struct pipe_resource *
 nouveau_buffer_create(struct pipe_screen *pscreen,
                       const struct pipe_resource *templ);
 
+struct pipe_resource *
+nouveau_buffer_create_from_user(struct pipe_screen *pscreen,
+                                const struct pipe_resource *templ,
+                                void *user_ptr);
+
 struct pipe_resource *
 nouveau_user_buffer_create(struct pipe_screen *screen, void *ptr,
                            unsigned bytes, unsigned usage);
index d73ecf71624c6ff2ee0e5db20cb3259e0a21f0b9..622cfd4b9e1539c104389e97f5dd4b222d3321eb 100644 (file)
@@ -98,6 +98,19 @@ nvc0_surface_create(struct pipe_context *pipe,
    return nvc0_miptree_surface_new(pipe, pres, templ);
 }
 
+static struct pipe_resource *
+nvc0_resource_from_user_memory(struct pipe_screen *pipe,
+                               const struct pipe_resource *templ,
+                               void *user_memory)
+{
+   struct nouveau_screen *screen = nouveau_screen(pipe);
+
+   assert(screen->has_svm);
+   assert(templ->target == PIPE_BUFFER);
+
+   return nouveau_buffer_create_from_user(pipe, templ, user_memory);
+}
+
 void
 nvc0_init_resource_functions(struct pipe_context *pcontext)
 {
@@ -120,4 +133,5 @@ nvc0_screen_init_resource_functions(struct pipe_screen *pscreen)
    pscreen->resource_from_handle = nvc0_resource_from_handle;
    pscreen->resource_get_handle = u_resource_get_handle_vtbl;
    pscreen->resource_destroy = u_resource_destroy_vtbl;
+   pscreen->resource_from_user_memory = nvc0_resource_from_user_memory;
 }