From 212f1ab40ea5945919a92926fd9b2aa085fed661 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Wed, 27 May 2020 16:29:06 +0200 Subject: [PATCH] nvc0: support PIPE_CAP_RESOURCE_FROM_USER_MEMORY_COMPUTE_ONLY v2: rework by adding a new buffer status Signed-off-by: Karol Herbst Part-of: --- src/gallium/drivers/nouveau/nouveau_buffer.c | 81 ++++++++++++++++++- src/gallium/drivers/nouveau/nouveau_buffer.h | 8 ++ .../drivers/nouveau/nvc0/nvc0_resource.c | 14 ++++ 3 files changed, 101 insertions(+), 2 deletions(-) diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.c b/src/gallium/drivers/nouveau/nouveau_buffer.c index abb4105099a..acc0e8c8d29 100644 --- a/src/gallium/drivers/nouveau/nouveau_buffer.c +++ b/src/gallium/drivers/nouveau/nouveau_buffer.c @@ -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; diff --git a/src/gallium/drivers/nouveau/nouveau_buffer.h b/src/gallium/drivers/nouveau/nouveau_buffer.h index 3a33fae9ce2..b43db81d298 100644 --- a/src/gallium/drivers/nouveau/nouveau_buffer.h +++ b/src/gallium/drivers/nouveau/nouveau_buffer.h @@ -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); diff --git a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c index d73ecf71624..622cfd4b9e1 100644 --- a/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c +++ b/src/gallium/drivers/nouveau/nvc0/nvc0_resource.c @@ -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; } -- 2.30.2