winsys/radeon: add user pointer support
authorChristian König <christian.koenig@amd.com>
Thu, 5 Feb 2015 17:34:51 +0000 (18:34 +0100)
committerMarek Olšák <marek.olsak@amd.com>
Tue, 17 Feb 2015 16:31:48 +0000 (17:31 +0100)
Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/winsys/radeon/drm/radeon_drm_bo.c
src/gallium/winsys/radeon/drm/radeon_winsys.h

index 1ebec10dafc8f1884cbb5ba3c8b24632d842141a..2605ca6238fc323cae2ac49487332970170987c6 100644 (file)
 #include <fcntl.h>
 #include <stdio.h>
 
+#ifndef DRM_RADEON_GEM_USERPTR
+
+#define DRM_RADEON_GEM_USERPTR         0x2d
+
+#define RADEON_GEM_USERPTR_READONLY    (1 << 0)
+#define RADEON_GEM_USERPTR_ANONONLY    (1 << 1)
+#define RADEON_GEM_USERPTR_VALIDATE    (1 << 2)
+#define RADEON_GEM_USERPTR_REGISTER    (1 << 3)
+
+struct drm_radeon_gem_userptr {
+       uint64_t                addr;
+       uint64_t                size;
+       uint32_t                flags;
+       uint32_t                handle;
+};
+
+#endif
+
 extern const struct pb_vtbl radeon_bo_vtbl;
 
 static INLINE struct radeon_bo *radeon_bo(struct pb_buffer *bo)
@@ -846,6 +864,89 @@ radeon_winsys_bo_create(struct radeon_winsys *rws,
     return (struct pb_buffer*)buffer;
 }
 
+static struct pb_buffer *radeon_winsys_bo_from_ptr(struct radeon_winsys *rws,
+                                                   void *pointer, unsigned size)
+{
+    struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
+    struct radeon_bomgr *mgr = radeon_bomgr(ws->kman);
+    struct drm_radeon_gem_userptr args;
+    struct radeon_bo *bo;
+    int r;
+
+    bo = CALLOC_STRUCT(radeon_bo);
+    if (!bo)
+        return NULL;
+
+    memset(&args, 0, sizeof(args));
+    args.addr = (uintptr_t)pointer;
+    args.size = size;
+    args.flags = RADEON_GEM_USERPTR_ANONONLY |
+        RADEON_GEM_USERPTR_VALIDATE |
+        RADEON_GEM_USERPTR_REGISTER;
+    if (drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_USERPTR,
+                            &args, sizeof(args))) {
+        FREE(bo);
+        return NULL;
+    }
+
+    pipe_mutex_lock(mgr->bo_handles_mutex);
+
+    /* Initialize it. */
+    pipe_reference_init(&bo->base.reference, 1);
+    bo->handle = args.handle;
+    bo->base.alignment = 0;
+    bo->base.usage = PB_USAGE_GPU_WRITE | PB_USAGE_GPU_READ;
+    bo->base.size = size;
+    bo->base.vtbl = &radeon_bo_vtbl;
+    bo->mgr = mgr;
+    bo->rws = mgr->rws;
+    bo->va = 0;
+    bo->initial_domain = RADEON_DOMAIN_GTT;
+    pipe_mutex_init(bo->map_mutex);
+
+    util_hash_table_set(mgr->bo_handles, (void*)(uintptr_t)bo->handle, bo);
+
+    pipe_mutex_unlock(mgr->bo_handles_mutex);
+
+    if (mgr->va) {
+        struct drm_radeon_gem_va va;
+
+        bo->va = radeon_bomgr_find_va(mgr, bo->base.size, 1 << 20);
+
+        va.handle = bo->handle;
+        va.operation = RADEON_VA_MAP;
+        va.vm_id = 0;
+        va.offset = bo->va;
+        va.flags = RADEON_VM_PAGE_READABLE |
+                   RADEON_VM_PAGE_WRITEABLE |
+                   RADEON_VM_PAGE_SNOOPED;
+        va.offset = bo->va;
+        r = drmCommandWriteRead(ws->fd, DRM_RADEON_GEM_VA, &va, sizeof(va));
+        if (r && va.operation == RADEON_VA_RESULT_ERROR) {
+            fprintf(stderr, "radeon: Failed to assign virtual address space\n");
+            radeon_bo_destroy(&bo->base);
+            return NULL;
+        }
+        pipe_mutex_lock(mgr->bo_handles_mutex);
+        if (va.operation == RADEON_VA_RESULT_VA_EXIST) {
+            struct pb_buffer *b = &bo->base;
+            struct radeon_bo *old_bo =
+                util_hash_table_get(mgr->bo_vas, (void*)(uintptr_t)va.offset);
+
+            pipe_mutex_unlock(mgr->bo_handles_mutex);
+            pb_reference(&b, &old_bo->base);
+            return b;
+        }
+
+        util_hash_table_set(mgr->bo_vas, (void*)(uintptr_t)bo->va, bo);
+        pipe_mutex_unlock(mgr->bo_handles_mutex);
+    }
+
+    ws->allocated_gtt += align(bo->base.size, 4096);
+
+    return (struct pb_buffer*)bo;
+}
+
 static struct pb_buffer *radeon_winsys_bo_from_handle(struct radeon_winsys *rws,
                                                       struct winsys_handle *whandle,
                                                       unsigned *stride)
@@ -1040,6 +1141,7 @@ void radeon_bomgr_init_functions(struct radeon_drm_winsys *ws)
     ws->base.buffer_is_busy = radeon_bo_is_busy;
     ws->base.buffer_create = radeon_winsys_bo_create;
     ws->base.buffer_from_handle = radeon_winsys_bo_from_handle;
+    ws->base.buffer_from_ptr = radeon_winsys_bo_from_ptr;
     ws->base.buffer_get_handle = radeon_winsys_bo_get_handle;
     ws->base.buffer_get_virtual_address = radeon_winsys_bo_va;
     ws->base.buffer_get_initial_domain = radeon_bo_get_initial_domain;
index 5dc9313ce0513d445753de9374b9120a9509a45b..d9fa1ab7878891b9e42a87c174eca4b3efc3a077 100644 (file)
@@ -393,6 +393,17 @@ struct radeon_winsys {
                                             struct winsys_handle *whandle,
                                             unsigned *stride);
 
+    /**
+     * Get a winsys buffer from a user pointer. The resulting buffer can't be
+     * mapped or exported. Both pointer and size must be page aligned.
+     *
+     * \param ws        The winsys this function is called from.
+     * \param pointer   User pointer to turn into a buffer object.
+     * \param Size      Size in bytes for the new buffer.
+     */
+    struct pb_buffer *(*buffer_from_ptr)(struct radeon_winsys *ws,
+                                         void *pointer, unsigned size);
+
     /**
      * Get a winsys handle from a winsys buffer. The internal structure
      * of the handle is platform-specific and only a winsys should access it.