nvc0: support PIPE_CAP_RESOURCE_FROM_USER_MEMORY_COMPUTE_ONLY

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>
This commit is contained in:
Karol Herbst 2020-05-27 16:29:06 +02:00 committed by Marge Bot
parent c0f7f833eb
commit 212f1ab40e
3 changed files with 101 additions and 2 deletions

View 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;

View 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);

View 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;
}