gallium/radeon: do not reallocate user memory buffers
authorNicolai Hähnle <nicolai.haehnle@amd.com>
Tue, 12 Jan 2016 14:29:18 +0000 (09:29 -0500)
committerNicolai Hähnle <nicolai.haehnle@amd.com>
Thu, 14 Jan 2016 14:41:24 +0000 (09:41 -0500)
The whole point of AMD_pinned_memory is that applications don't have to map
buffers via OpenGL - but they're still allowed to, so make sure we don't break
the link between buffer object and user memory unless explicitly instructed
to.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
src/gallium/drivers/radeon/r600_buffer_common.c
src/gallium/drivers/radeon/radeon_winsys.h
src/gallium/winsys/amdgpu/drm/amdgpu_bo.c
src/gallium/winsys/radeon/drm/radeon_drm_bo.c

index 09755e0..6592c5b 100644 (file)
@@ -209,11 +209,15 @@ static void r600_buffer_destroy(struct pipe_screen *screen,
        FREE(rbuffer);
 }
 
-void r600_invalidate_resource(struct pipe_context *ctx,
-                             struct pipe_resource *resource)
+static bool
+r600_do_invalidate_resource(struct r600_common_context *rctx,
+                           struct r600_resource *rbuffer)
 {
-       struct r600_common_context *rctx = (struct r600_common_context*)ctx;
-        struct r600_resource *rbuffer = r600_resource(resource);
+       /* In AMD_pinned_memory, the user pointer association only gets
+        * broken when the buffer is explicitly re-allocated.
+        */
+       if (rctx->ws->buffer_is_user_ptr(rbuffer->buf))
+               return false;
 
        /* Check if mapping this buffer would cause waiting for the GPU. */
        if (r600_rings_is_buffer_referenced(rctx, rbuffer->buf, RADEON_USAGE_READWRITE) ||
@@ -222,6 +226,17 @@ void r600_invalidate_resource(struct pipe_context *ctx,
        } else {
                util_range_set_empty(&rbuffer->valid_buffer_range);
        }
+
+       return true;
+}
+
+void r600_invalidate_resource(struct pipe_context *ctx,
+                             struct pipe_resource *resource)
+{
+       struct r600_common_context *rctx = (struct r600_common_context*)ctx;
+       struct r600_resource *rbuffer = r600_resource(resource);
+
+       (void)r600_do_invalidate_resource(rctx, rbuffer);
 }
 
 static void *r600_buffer_get_transfer(struct pipe_context *ctx,
@@ -291,10 +306,10 @@ static void *r600_buffer_transfer_map(struct pipe_context *ctx,
            !(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) {
                assert(usage & PIPE_TRANSFER_WRITE);
 
-               r600_invalidate_resource(ctx, resource);
-
-               /* At this point, the buffer is always idle. */
-               usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
+               if (r600_do_invalidate_resource(rctx, rbuffer)) {
+                       /* At this point, the buffer is always idle. */
+                       usage |= PIPE_TRANSFER_UNSYNCHRONIZED;
+               }
        }
        else if ((usage & PIPE_TRANSFER_DISCARD_RANGE) &&
                 !(usage & PIPE_TRANSFER_UNSYNCHRONIZED) &&
index 4af6a18..ad30474 100644 (file)
@@ -530,6 +530,14 @@ struct radeon_winsys {
                                          void *pointer, unsigned size);
 
     /**
+     * Whether the buffer was created from a user pointer.
+     *
+     * \param buf       A winsys buffer object
+     * \return          whether \p buf was created via buffer_from_ptr
+     */
+    bool (*buffer_is_user_ptr)(struct pb_buffer *buf);
+
+    /**
      * Get a winsys handle from a winsys buffer. The internal structure
      * of the handle is platform-specific and only a winsys should access it.
      *
index a844773..82c803b 100644 (file)
@@ -686,6 +686,11 @@ error:
     return NULL;
 }
 
+static bool amdgpu_bo_is_user_ptr(struct pb_buffer *buf)
+{
+   return ((struct amdgpu_winsys_bo*)buf)->user_ptr != NULL;
+}
+
 static uint64_t amdgpu_bo_get_va(struct pb_buffer *buf)
 {
    return ((struct amdgpu_winsys_bo*)buf)->va;
@@ -701,6 +706,7 @@ void amdgpu_bo_init_functions(struct amdgpu_winsys *ws)
    ws->base.buffer_create = amdgpu_bo_create;
    ws->base.buffer_from_handle = amdgpu_bo_from_handle;
    ws->base.buffer_from_ptr = amdgpu_bo_from_ptr;
+   ws->base.buffer_is_user_ptr = amdgpu_bo_is_user_ptr;
    ws->base.buffer_get_handle = amdgpu_bo_get_handle;
    ws->base.buffer_get_virtual_address = amdgpu_bo_get_va;
    ws->base.buffer_get_initial_domain = amdgpu_bo_get_initial_domain;
index e35d280..3ec6a06 100644 (file)
@@ -1052,6 +1052,11 @@ static boolean radeon_winsys_bo_get_handle(struct pb_buffer *buffer,
     return TRUE;
 }
 
+static bool radeon_winsys_bo_is_user_ptr(struct pb_buffer *buf)
+{
+   return ((struct radeon_bo*)buf)->user_ptr != NULL;
+}
+
 static uint64_t radeon_winsys_bo_va(struct pb_buffer *buf)
 {
     return ((struct radeon_bo*)buf)->va;
@@ -1067,6 +1072,7 @@ void radeon_drm_bo_init_functions(struct radeon_drm_winsys *ws)
     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_is_user_ptr = radeon_winsys_bo_is_user_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;