Allow creating VA surfaces with userptr allocated buffers. This requires
a recent enough version of libdrm (>= 2.4.57), but also a kernel (>= 3.16)
which contains appropriate fixes for userptr.

Signed-off-by: Gwenole Beauchesne <gwenole.beauche...@intel.com>
---
 configure.ac         | 19 ++++++++++++
 src/i965_drv_video.c | 81 +++++++++++++++++++++++++++++++++++++++++-----------
 src/i965_drv_video.h |  1 +
 src/intel_driver.h   |  1 +
 src/intel_memman.c   | 71 ++++++++++++++++++++++++++++++++++++++++++++-
 src/intel_memman.h   |  7 +++++
 6 files changed, 163 insertions(+), 17 deletions(-)

diff --git a/configure.ac b/configure.ac
index d71a3cc..3c19cd2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,25 @@ LIBDRM_VERSION=libdrm_version
 PKG_CHECK_MODULES([DRM], [libdrm >= $LIBDRM_VERSION])
 AC_SUBST(LIBDRM_VERSION)
 
+AC_CACHE_CHECK([whether libdrm supports userptr allocations],
+    [ac_cv_libdrm_has_userptr],
+    [saved_CPPFLAGS="$CPPFLAGS"
+     saved_CFLAGS="$CFLAGS"
+     CPPFLAGS="$CPPFLAGS $DRM_CFLAGS"
+     LIBS="$LIBS $DRM_LIBS -ldrm_intel"
+     AC_TRY_LINK(
+         [#include <intel_bufmgr.h>],
+         [drm_intel_bo_alloc_userptr(NULL, NULL, NULL, 0, 0, 0, 0)],
+         [ac_cv_libdrm_has_userptr="yes"],
+         [ac_cv_libdrm_has_userptr="no"])
+     CPPFLAGS="$saved_CPPFLAGS"
+     LIBS="$saved_LIBS"]
+)
+if test "$ac_cv_libdrm_has_userptr" = "yes"; then
+    AC_DEFINE([HAVE_DRM_INTEL_USERPTR], [1],
+        [Defined to 1 if libdrm supports userptr allocations])
+fi
+
 dnl Check for gen4asm
 PKG_CHECK_MODULES(GEN4ASM, [intel-gen4asm >= 1.9], [gen4asm=yes], [gen4asm=no])
 AC_PATH_PROG([GEN4ASM], [intel-gen4asm])
diff --git a/src/i965_drv_video.c b/src/i965_drv_video.c
index 799ebad..0e4ccb7 100644
--- a/src/i965_drv_video.c
+++ b/src/i965_drv_video.c
@@ -992,24 +992,18 @@ i965_surface_native_memory(VADriverContextP ctx,
 
     return VA_STATUS_SUCCESS;
 }
-    
+
 static VAStatus
-i965_suface_external_memory(VADriverContextP ctx,
-                            struct object_surface *obj_surface,
-                            int external_memory_type,
-                            VASurfaceAttribExternalBuffers *memory_attibute,
-                            int index)
+set_surface_info_from_extbuf(VADriverContextP tx,
+    struct object_surface *obj_surface,
+    VASurfaceAttribExternalBuffers *memory_attibute)
 {
-    struct i965_driver_data *i965 = i965_driver_data(ctx);
-
-    if (!memory_attibute ||
-        !memory_attibute->buffers ||
-        index >= memory_attibute->num_buffers)
-        return VA_STATUS_ERROR_INVALID_PARAMETER;
-
-    ASSERT_RET(obj_surface->orig_width == memory_attibute->width, 
VA_STATUS_ERROR_INVALID_PARAMETER);
-    ASSERT_RET(obj_surface->orig_height == memory_attibute->height, 
VA_STATUS_ERROR_INVALID_PARAMETER);
-    ASSERT_RET(memory_attibute->num_planes >= 1, 
VA_STATUS_ERROR_INVALID_PARAMETER);
+    ASSERT_RET(obj_surface->orig_width == memory_attibute->width,
+        VA_STATUS_ERROR_INVALID_PARAMETER);
+    ASSERT_RET(obj_surface->orig_height == memory_attibute->height,
+        VA_STATUS_ERROR_INVALID_PARAMETER);
+    ASSERT_RET(memory_attibute->num_planes >= 1,
+        VA_STATUS_ERROR_INVALID_PARAMETER);
 
     obj_surface->fourcc = memory_attibute->pixel_format;
     obj_surface->width = memory_attibute->pitches[0];
@@ -1175,6 +1169,27 @@ i965_suface_external_memory(VADriverContextP ctx,
 
         return VA_STATUS_ERROR_INVALID_PARAMETER;
     }
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+i965_suface_external_memory(VADriverContextP ctx,
+                            struct object_surface *obj_surface,
+                            int external_memory_type,
+                            VASurfaceAttribExternalBuffers *memory_attibute,
+                            int index)
+{
+    struct i965_driver_data *i965 = i965_driver_data(ctx);
+    VAStatus status;
+
+    if (!memory_attibute ||
+        !memory_attibute->buffers ||
+        index >= memory_attibute->num_buffers)
+        return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+    status = set_surface_info_from_extbuf(ctx, obj_surface, memory_attibute);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
 
     if (external_memory_type == I965_SURFACE_MEM_GEM_FLINK)
         obj_surface->bo = drm_intel_bo_gem_create_from_name(i965->intel.bufmgr,
@@ -1191,6 +1206,32 @@ i965_suface_external_memory(VADriverContextP ctx,
     return VA_STATUS_SUCCESS;
 }
 
+static VAStatus
+i965_surface_from_userptr(VADriverContextP ctx,
+    struct object_surface *obj_surface,
+    VASurfaceAttribExternalBuffers *memory_attribute, int index)
+{
+    struct i965_driver_data * const i965 = i965_driver_data(ctx);
+    VAStatus status;
+
+    if (!memory_attribute || !memory_attribute->buffers)
+        return VA_STATUS_ERROR_INVALID_PARAMETER;
+    if (index >= memory_attribute->num_buffers)
+        return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
+
+    status = set_surface_info_from_extbuf(ctx, obj_surface, memory_attribute);
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    obj_surface->bo = intel_memman_import_userptr(&i965->intel,
+        "vaapi surface (userptr)", (void *)memory_attribute->buffers[index],
+        obj_surface->size, memory_attribute->flags);
+    if (!obj_surface->bo)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+    return VA_STATUS_SUCCESS;
+}
+
 /* byte-per-pixel of the first plane */
 static int
 bpp_1stplane_by_fourcc(unsigned int fourcc)
@@ -1240,6 +1281,10 @@ i965_CreateSurfaces2(
                 memory_type = I965_SURFACE_MEM_DRM_PRIME; /* drm prime fd */
             else if (attrib_list[i].value.value.i == 
VA_SURFACE_ATTRIB_MEM_TYPE_VA)
                 memory_type = I965_SURFACE_MEM_NATIVE; /* va native memory, to 
be allocated */
+#ifdef HAVE_DRM_INTEL_USERPTR
+            else if (attrib_list[i].value.value.i == 
VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR)
+                memory_type = I965_SURFACE_MEM_USERPTR;
+#endif
             else
                 memory_type = 0;
         }
@@ -1345,6 +1390,10 @@ i965_CreateSurfaces2(
                                         memory_attibute,
                                         i);
             break;
+        case I965_SURFACE_MEM_USERPTR:
+            vaStatus = i965_surface_from_userptr(ctx, obj_surface,
+                memory_attibute, i);
+            break;
         }
     }
 
diff --git a/src/i965_drv_video.h b/src/i965_drv_video.h
index c39d53b..d63c9c1 100644
--- a/src/i965_drv_video.h
+++ b/src/i965_drv_video.h
@@ -509,6 +509,7 @@ enum {
     I965_SURFACE_MEM_NATIVE = 1,
     I965_SURFACE_MEM_GEM_FLINK,
     I965_SURFACE_MEM_DRM_PRIME,
+    I965_SURFACE_MEM_USERPTR,
 };
 
 void
diff --git a/src/intel_driver.h b/src/intel_driver.h
index 3c20ce4..4a0bdd4 100644
--- a/src/intel_driver.h
+++ b/src/intel_driver.h
@@ -152,6 +152,7 @@ struct intel_driver_data
 
     dri_bufmgr *bufmgr;
 
+    unsigned int userptr_disabled;
     unsigned int has_exec2  : 1; /* Flag: has execbuffer2? */
     unsigned int has_bsd    : 1; /* Flag: has bitstream decoder for H.264? */
     unsigned int has_blt    : 1; /* Flag: has BLT unit? */
diff --git a/src/intel_memman.c b/src/intel_memman.c
index 03ed216..5021c34 100644
--- a/src/intel_memman.c
+++ b/src/intel_memman.c
@@ -27,9 +27,12 @@
  *
  */
 
+#include "config.h"
 #include <assert.h>
-
+#include <stdlib.h>
+#include <unistd.h>
 #include "intel_driver.h"
+#include "intel_memman.h"
 
 Bool 
 intel_memman_init(struct intel_driver_data *intel)
@@ -44,6 +47,8 @@ intel_memman_init(struct intel_driver_data *intel)
        drm_intel_bufmgr_gem_set_aub_dump(intel->bufmgr, 1);
     }
 
+    /* Only check for userptr when needed, through intel_memman_has_userptr() 
*/
+    intel->userptr_disabled = 2;
     return True;
 }
 
@@ -53,3 +58,67 @@ intel_memman_terminate(struct intel_driver_data *intel)
     drm_intel_bufmgr_destroy(intel->bufmgr);
     return True;
 }
+
+drm_intel_bo *
+do_import_userptr(struct intel_driver_data *intel, const char *name,
+    void *data, size_t data_size, uint32_t va_flags)
+{
+#ifdef HAVE_DRM_INTEL_USERPTR
+    uint32_t page_size, tiling_mode, flags = 0;
+    drm_intel_bo *bo;
+
+    /* XXX: userptr is only supported for page-aligned allocations */
+    page_size = getpagesize();
+    if ((uintptr_t)data & (page_size - 1))
+        return NULL;
+
+    tiling_mode = (va_flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING) ?
+        I915_TILING_Y : I915_TILING_NONE;
+
+    flags |= I915_USERPTR_UNSYNCHRONIZED;
+    bo = drm_intel_bo_alloc_userptr(intel->bufmgr, name, data, tiling_mode, 0,
+        data_size, flags);
+    if (bo)
+        return bo;
+
+    flags &= ~I915_USERPTR_UNSYNCHRONIZED;
+    bo = drm_intel_bo_alloc_userptr(intel->bufmgr, name, data, tiling_mode, 0,
+        data_size, flags);
+    if (bo)
+        return bo;
+#endif
+    return NULL;
+}
+
+drm_intel_bo *
+intel_memman_import_userptr(struct intel_driver_data *intel, const char *name,
+    void *data, size_t data_size, uint32_t va_flags)
+{
+    if (!intel_memman_has_userptr(intel))
+        return NULL;
+    return do_import_userptr(intel, name, data, data_size, va_flags);
+}
+
+bool
+intel_memman_has_userptr(struct intel_driver_data *intel)
+{
+    drm_intel_bo *bo;
+    size_t page_size;
+    void *page;
+
+    if (intel->userptr_disabled > 1) {
+        intel->userptr_disabled = 1;
+
+        page_size = getpagesize();
+        if (posix_memalign(&page, page_size, page_size) == 0) {
+            bo = do_import_userptr(intel, "userptr test buffer",
+                page, page_size, 0);
+            if (bo) {
+                drm_intel_bo_unreference(bo);
+                intel->userptr_disabled  = 0;
+            }
+            free(page);
+        }
+    }
+    return !intel->userptr_disabled;
+}
diff --git a/src/intel_memman.h b/src/intel_memman.h
index 4e516e5..3a1235d 100644
--- a/src/intel_memman.h
+++ b/src/intel_memman.h
@@ -4,4 +4,11 @@
 Bool intel_memman_init(struct intel_driver_data *intel);
 Bool intel_memman_terminate(struct intel_driver_data *intel);
 
+bool
+intel_memman_has_userptr(struct intel_driver_data *intel);
+
+drm_intel_bo *
+intel_memman_import_userptr(struct intel_driver_data *intel, const char *name,
+    void *data, size_t data_size, uint32_t va_flags);
+
 #endif /* _INTEL_MEMMAN_H_ */
-- 
1.9.1

_______________________________________________
Libva mailing list
Libva@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libva

Reply via email to