aboutsummaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nouveau
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/nouveau')
-rw-r--r--src/gallium/drivers/nouveau/nouveau_buffer.c81
-rw-r--r--src/gallium/drivers/nouveau/nouveau_buffer.h8
-rw-r--r--src/gallium/drivers/nouveau/nvc0/nvc0_resource.c14
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
@@ -92,6 +95,11 @@ 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;
}