Add Jon/Bob/Raf for detail review.
-----Original Message----- From: Cheng, Yao Sent: Saturday, November 22, 2014 3:09 To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel.vetter@ffwll.ch; Kelley, Sean V; Chehab, John Cc: Jiang, Fei; dh.herrmann@gmail.com; jani.nikula@linux.intel.com; emil.l.velikov@gmail.com; ville.syrjala@linux.intel.com; jbarnes@virtuousgeek.org; daniel@fooishbar.org; Cheng, Yao Subject: [RFC PATCH v3 3/4] ipvr: user mode helper for ipvr drm driver
add usermode helper for the ipvr kernel driver. test_ioctl: test kernel driver by directly ioctl
v2: take Emil's comments
- correctly align ipvr_drm.h
v3: take Daniel Vetter and Daniel Stone's comments, and implement PRIME
- correctly align ipvr_drm.h
- use __u32 family in ipvr_drm.h
- rip out explicit fence from libdrm_ipvr
- implemented PRIME support
- add relocation fixup implementation
Signed-off-by: Yao Cheng yao.cheng@intel.com
Makefile.am | 6 +- Makefile.sources | 1 + configure.ac | 26 +- include/drm/ipvr_drm.h | 278 +++++++++++ ipvr/Makefile.am | 57 +++ ipvr/Makefile.sources | 5 + ipvr/ipvr_bufmgr.h | 149 ++++++ ipvr/ipvr_bufmgr_gem.c | 1200 ++++++++++++++++++++++++++++++++++++++++++++++++ ipvr/libdrm_ipvr.pc.in | 11 + ipvr/test_ioctl.c | 423 +++++++++++++++++ 10 files changed, 2154 insertions(+), 2 deletions(-) create mode 100644 include/drm/ipvr_drm.h create mode 100644 ipvr/Makefile.am create mode 100644 ipvr/Makefile.sources create mode 100644 ipvr/ipvr_bufmgr.h create mode 100644 ipvr/ipvr_bufmgr_gem.c create mode 100644 ipvr/libdrm_ipvr.pc.in create mode 100644 ipvr/test_ioctl.c
diff --git a/Makefile.am b/Makefile.am index 3952a88..2227add 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,10 @@ if HAVE_INTEL INTEL_SUBDIR = intel endif
+if HAVE_IPVR +IPVR_SUBDIR = ipvr +endif
if HAVE_NOUVEAU NOUVEAU_SUBDIR = nouveau endif @@ -53,7 +57,7 @@ if HAVE_FREEDRENO FREEDRENO_SUBDIR = freedreno endif
-SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(FREEDRENO_SUBDIR) tests man +SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(IPVR_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(FREEDRENO_SUBDIR) tests man
libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) diff --git a/Makefile.sources b/Makefile.sources index d86fb2a..96f8c60 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -18,6 +18,7 @@ LIBDRM_INCLUDE_H_FILES := \ include/drm/drm_mode.h \ include/drm/drm_sarea.h \ include/drm/i915_drm.h \
- include/drm/ipvr_drm.h \ include/drm/mach64_drm.h \ include/drm/mga_drm.h \ include/drm/nouveau_drm.h \
diff --git a/configure.ac b/configure.ac index ee59b03..6dcf1b2 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,11 @@ AC_ARG_ENABLE(intel, [Enable support for intel's KMS API (default: auto)]), [INTEL=$enableval], [INTEL=auto])
+AC_ARG_ENABLE(ipvr,
AS_HELP_STRING([--disable-ipvr],
[Enable support for baytrail's hardware VP8 decode (default:
auto)]),
[IPVR=$enableval], [IPVR=auto])
AC_ARG_ENABLE(radeon, AS_HELP_STRING([--disable-radeon], [Enable support for radeon's KMS API (default: auto)]), @@ -204,7 +209,7 @@ if test "x$drm_cv_atomic_primitives" = "xlibatomic- ops"; then AC_DEFINE(HAVE_LIB_ATOMIC_OPS, 1, [Enable if you have libatomic-ops-dev installed]) fi
-if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno"; then +if test "x$INTEL" != "xno" -o "x$IPVR" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno"; then if test "x$drm_cv_atomic_primitives" = "xnone"; then if test "x$INTEL" != "xauto"; then if test "x$INTEL" != "xno"; then @@ -214,6 +219,14 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno"; then AC_MSG_WARN([Disabling libdrm_intel. It depends on atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package.]) INTEL=no fi
if test "x$IPVR" != "xauto"; then
if test "x$IPVR" != "xno"; then
AC_MSG_ERROR([libdrm_ipvr depends upon
atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package, or, failing both of those, disable support for Baytrail VP8 by passing --disable-ipvr to ./configure])
fi
else
AC_MSG_WARN([Disabling libdrm_ipvr. It depends
on atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package.])
INTEL=no
if test "x$RADEON" != "xauto"; then if test "x$RADEON" != "xno"; then AC_MSG_ERROR([libdrm_radeon dependsfi
upon atomic operations, which were not found for your compiler/cpu. Try compiling with -march=native, or install the libatomics-op-dev package, or, failing both of those, disable support for Radeon GPUs by passing --disable- radeon to ./configure]) @@ -237,6 +250,9 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno"; then *) INTEL=no ;; esac fi
if test "x$IPVR" != "xno"; then
IPVR=yes
if test "x$RADEON" != "xno"; then RADEON=yes fifi
@@ -274,6 +290,11 @@ if test "x$INTEL" = xyes; then AC_DEFINE(HAVE_INTEL, 1, [Have intel support]) fi
+AM_CONDITIONAL(HAVE_IPVR, [test "x$IPVR" = xyes]) +if test "x$IPVR" = xyes; then
- AC_DEFINE(HAVE_PVR, 1, [Have ipvr support])
+fi
AM_CONDITIONAL(HAVE_VMWGFX, [test "x$VMWGFX" = xyes]) if test "x$VMWGFX" = xyes; then AC_DEFINE(HAVE_VMWGFX, 1, [Have vmwgfx kernel headers]) @@ -393,6 +414,8 @@ AC_CONFIG_FILES([ libkms/libkms.pc intel/Makefile intel/libdrm_intel.pc
- ipvr/Makefile
- ipvr/libdrm_ipvr.pc radeon/Makefile radeon/libdrm_radeon.pc nouveau/Makefile
@@ -419,6 +442,7 @@ echo "$PACKAGE_STRING will be compiled with:" echo "" echo " libkms $LIBKMS" echo " Intel API $INTEL" +echo " Ipvr API $IPVR" echo " vmwgfx API $VMWGFX" echo " Radeon API $RADEON" echo " Nouveau API $NOUVEAU" diff --git a/include/drm/ipvr_drm.h b/include/drm/ipvr_drm.h new file mode 100644 index 0000000..d1916fa --- /dev/null +++ b/include/drm/ipvr_drm.h @@ -0,0 +1,278 @@ +/*********************************************************
- ipvr_drm.h: IPVR header file exported to user space
- Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
- All Rights Reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
- more details.
- You should have received a copy of the GNU General Public License along
with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- Authors:
- Fei Jiang fei.jiang@intel.com
- Yao Cheng yao.cheng@intel.com
****************/
+/* this file only define structs and macro which need export to user space */ +#ifndef _IPVR_DRM_H_ +#define _IPVR_DRM_H_
+#include <drm/drm.h> +struct drm_ipvr_context_create {
- /* passed ctx_info, including codec, profile info */
+#define IPVR_CONTEXT_TYPE_VED (0x1)
- __u32 ctx_type;
- /* returned back ctx_id */
- __u32 ctx_id;
- /*
* following tiling strides for VED are supported:
* stride 0: 512 for scheme 0, 1024 for scheme 1
* stride 1: 1024 for scheme 0, 2048 for scheme 1
* stride 2: 2048 for scheme 0, 4096 for scheme 1
* stride 3: 4096 for scheme 0
*/
- __u32 tiling_stride;
- /*
* scheme 0: tile is 256x16, while minimal tile stride is 512
* scheme 1: tile is 512x8, while minimal tile stride is 1024
*/
- __u32 tiling_scheme;
+};
+struct drm_ipvr_context_destroy {
- __u32 ctx_id;
- __u32 pad64;
+};
+enum drm_ipvr_misc_key {
- IPVR_DEVICE_INFO,
- IPVR_UPDATE_TILING,
- IPVR_SET_DISPLAYING_FRAME,
- IPVR_GET_DISPLAYING_FRAME,
- IPVR_QUERY_ENTRY
+};
+/*
- different context maybe has different tiling stride,
- then tiling info need be bound with ctx
- */
+struct drm_ipvr_update_tiling {
- __u32 ctx_id;
- __u32 tiling_stride;
- __u32 tiling_scheme;
- __u32 pad64;
+};
+/* Ioctl to set/get misc params:
- */
+struct drm_ipvr_misc {
- __u64 key;
- __u64 arg; /* argument pointer */
- __u64 value; /* feed back pointer */
+};
+struct drm_ipvr_gem_relocation_entry {
- /**
* Handle of the buffer being pointed to by this relocation entry.
*
* It's appealing to make this be an index into the mm_validate_entry
* list to refer to the buffer, but this allows the driver to create
* a relocation list for state buffers and not re-write it per
* exec using the buffer.
*/
- __u32 target_handle;
- /**
* Value to be added to the offset of the target buffer to make up
* the relocation entry.
*/
- __u32 delta;
- /** Offset in the buffer the relocation entry will be written into */
- __u64 offset;
- /**
* Offset value of the target buffer that the relocation entry was last
* written as.
*
* If the buffer has the same offset as last time, we can skip syncing
* and writing the relocation. This value is written back out by
* the execbuffer ioctl when the relocation is written.
*/
- __u64 presumed_offset;
- /**
* Target memory domains read by this operation.
*/
- __u32 read_domains;
- /**
* Target memory domains written by this operation.
*
* Note that only one domain may be written by the whole
* execbuffer operation, so that where there are conflicts,
* the application will get -EINVAL back.
*/
- __u32 write_domain;
+};
+struct drm_ipvr_gem_exec_object {
- /**
* User's handle for a buffer to be bound into the MMU for this
* operation.
*/
- __u32 handle;
- /** Number of relocations to be performed on this buffer */
- __u32 relocation_count;
- /**
* Pointer to array of struct drm_i915_gem_relocation_entry
containing
* the relocations to be performed in this buffer.
*/
- __u64 relocs_ptr;
- /** Required alignment in graphics aperture */
- __u64 alignment;
- /**
* Returned value of the updated offset of the object, for future
* presumed_offset writes.
*/
- __u64 offset;
+#define IPVR_EXEC_OBJECT_NEED_FENCE (1 << 0) +#define IPVR_EXEC_OBJECT_SUBMIT (1 << 1)
- __u64 flags;
- __u64 rsvd1;
- __u64 rsvd2;
+};
+struct drm_ipvr_gem_execbuffer {
- /**
* List of gem_exec_object2 structs
*/
- __u64 buffers_ptr;
- __u32 buffer_count;
- /** Offset in the batchbuffer to start execution from. */
- __u32 exec_start_offset;
- /** Bytes used in batchbuffer from batch_start_offset */
- __u32 exec_len;
- /**
* ID of hardware context.
*/
- __u32 ctx_id;
- __u64 flags;
- __u64 rsvd1;
- __u64 rsvd2;
+};
+enum ipvr_cache_level +{
- IPVR_CACHE_NOACCESS,
- IPVR_CACHE_UNCACHED,
- IPVR_CACHE_WRITEBACK,
- IPVR_CACHE_WRITECOMBINE,
- IPVR_CACHE_MAX,
+};
+struct drm_ipvr_gem_create {
- /*
* Requested size for the object.
* The (page-aligned) allocated size for the object will be returned.
*/
- __u64 size;
- __u64 rounded_size;
- __u64 mmu_offset;
- /*
* Returned handle for the object.
* Object handles are nonzero.
*/
- __u32 handle;
- __u32 tiling;
- __u32 cache_level;
- __u32 pad64;
- /*
* Handle used for user to mmap BO
*/
- __u64 map_offset;
+};
+struct drm_ipvr_gem_busy {
- /* Handle of the buffer to check for busy */
- __u32 handle;
- /*
* Return busy status (1 if busy, 0 if idle).
* The high word is used to indicate on which rings the object
* currently resides:
* 16:31 - busy (r or r/w) rings (16 render, 17 bsd, 18 blt, etc)
*/
- __u32 busy;
+};
+struct drm_ipvr_gem_mmap_offset {
- /** Handle for the object being mapped. */
- __u32 handle;
- __u32 pad64;
- /**
* Fake offset to use for subsequent mmap call
*
* This is a fixed-size type for 32/64 compatibility.
*/
- __u64 offset;
+};
+struct drm_ipvr_gem_wait {
- /* Handle of BO we shall wait on */
- __u32 handle;
- __u32 flags;
- /** Number of nanoseconds to wait, Returns time remaining. */
- __s64 timeout_ns;
+};
+/*
- IPVR GEM specific ioctls
- */
+#define DRM_IPVR_CONTEXT_CREATE 0x00 +#define DRM_IPVR_CONTEXT_DESTROY 0x01 +#define DRM_IPVR_MISC 0x02 +#define DRM_IPVR_GEM_EXECBUFFER 0x03 +#define DRM_IPVR_GEM_BUSY 0x04 +#define DRM_IPVR_GEM_CREATE 0x05 +#define DRM_IPVR_GEM_WAIT 0x06 +#define DRM_IPVR_GEM_MMAP_OFFSET 0x07
+#define DRM_IOCTL_IPVR_CONTEXT_CREATE \
- DRM_IOWR(DRM_COMMAND_BASE +
DRM_IPVR_CONTEXT_CREATE, struct drm_ipvr_context_create) +#define DRM_IOCTL_IPVR_CONTEXT_DESTROY \
- DRM_IOW(DRM_COMMAND_BASE +
DRM_IPVR_CONTEXT_DESTROY, struct drm_ipvr_context_destroy) +#define DRM_IOCTL_IPVR_MISC \
- DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_MISC, struct
drm_ipvr_misc) +#define DRM_IOCTL_IPVR_GEM_EXECBUFFER \
- DRM_IOWR(DRM_COMMAND_BASE +
DRM_IPVR_GEM_EXECBUFFER, struct drm_ipvr_gem_execbuffer) +#define DRM_IOCTL_IPVR_GEM_BUSY \
- DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_BUSY,
struct drm_ipvr_gem_busy) +#define DRM_IOCTL_IPVR_GEM_CREATE \
- DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_CREATE,
struct drm_ipvr_gem_create) +#define DRM_IOCTL_IPVR_GEM_WAIT \
- DRM_IOWR(DRM_COMMAND_BASE + DRM_IPVR_GEM_WAIT,
struct drm_ipvr_gem_wait) +#define DRM_IOCTL_IPVR_GEM_MMAP_OFFSET \
- DRM_IOWR(DRM_COMMAND_BASE +
DRM_IPVR_GEM_MMAP_OFFSET, struct drm_ipvr_gem_mmap_offset)
+#endif diff --git a/ipvr/Makefile.am b/ipvr/Makefile.am new file mode 100644 index 0000000..60cbb36 --- /dev/null +++ b/ipvr/Makefile.am @@ -0,0 +1,57 @@ +# Copyright © 2014 Intel Corporation +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice (including the next +# paragraph) shall be included in all copies or substantial portions of the +# Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# Authors: +# Yao Cheng yao.cheng@intel.com
+include Makefile.sources
+AM_CFLAGS = \
- $(WARN_CFLAGS) \
- $(VISIBILITY_CFLAGS) \
- -I$(top_srcdir) \
- -I$(top_srcdir)/ipvr \
- $(PTHREADSTUBS_CFLAGS) \
- $(PCIACCESS_CFLAGS) \
- $(VALGRIND_CFLAGS) \
- -I$(top_srcdir)/include/drm
+libdrm_ipvr_la_LTLIBRARIES = libdrm_ipvr.la +libdrm_ipvr_ladir = $(libdir) +libdrm_ipvr_la_LDFLAGS = -version-number 0:1:0 -no-undefined +libdrm_ipvr_la_LIBADD = ../libdrm.la \
- @PTHREADSTUBS_LIBS@ \
- @PCIACCESS_LIBS@ \
- @CLOCK_LIB@
+libdrm_ipvr_la_SOURCES = $(LIBDRM_IPVR_FILES)
+ipvr_bufmgr_gem_o_CFLAGS = $(AM_CFLAGS) -c99
+libdrm_ipvrincludedir = ${includedir}/libdrm +libdrm_ipvrinclude_HEADERS = $(LIBDRM_IPVR_H_FILES)
+# This may be interesting even outside of "make check", due to the -dump option. +noinst_PROGRAMS = test_ioctl
+test_ioctl_LDADD = libdrm_ipvr.la ../libdrm.la ../intel/libdrm_intel.la
+pkgconfig_DATA = libdrm_ipvr.pc diff --git a/ipvr/Makefile.sources b/ipvr/Makefile.sources new file mode 100644 index 0000000..5103a02 --- /dev/null +++ b/ipvr/Makefile.sources @@ -0,0 +1,5 @@ +LIBDRM_IPVR_FILES := \
- ipvr_bufmgr_gem.c
+LIBDRM_IPVR_H_FILES := \
- ipvr_bufmgr.h
diff --git a/ipvr/ipvr_bufmgr.h b/ipvr/ipvr_bufmgr.h new file mode 100644 index 0000000..31df82f --- /dev/null +++ b/ipvr/ipvr_bufmgr.h @@ -0,0 +1,149 @@ +/*
- Copyright 2014 Intel Corporation
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
"Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom the
- Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice (including the next
- paragraph) shall be included in all copies or substantial portions of the
- Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS
- IN THE SOFTWARE.
- Authors:
- Yao Cheng yao.cheng@intel.com
- */
+#ifndef IPVR_BUFMGR_H +#define IPVR_BUFMGR_H +#include <stdio.h> +#include <stdint.h> +#include <stdio.h>
+typedef struct _drm_ipvr_bo drm_ipvr_bo; +typedef struct _drm_ipvr_bufmgr drm_ipvr_bufmgr; +typedef struct _drm_ipvr_context drm_ipvr_context;
+struct _drm_ipvr_bo {
- /**
* Size in bytes of the buffer object.
*
* The size may be larger than the size originally requested for the
* allocation, such as being aligned to page size.
*/
- size_t size;
- /** rounded up size of actual allocation */
- size_t alloc_size;
- /** GEM handle of the BO */
- uint32_t handle;
- /**
* several buffers may share one BO (camera/RAR), and use offset to
distinguish it
*/
- uint64_t buffer_ofs;
- /**
* Last seen card virtual address (offset from the beginning of the
* aperture) for the object. This should be used to fill relocation
* entries when calling drm_ipvr_gem_bo_emit_reloc()
*/
- uint64_t offset;
- /**
* Virtual address for accessing the buffer data. Only valid while
* mapped.
*/
- void *virt;
- /**
* Generic external buffer info e.g. gfx handle on Android
*/
- uint64_t ext_handle;
- /** Indicates the BO can be re-used or not after being recycled */
- int reusable;
- /** Buffer manager context associated with this buffer object */
- drm_ipvr_bufmgr *bufmgr;
+};
+struct _drm_ipvr_bufmgr {
- int debug;
+};
+struct _drm_ipvr_context +{
- uint32_t ctx_id;
- uint32_t ctx_type;
- drm_ipvr_bufmgr *bufmgr;
+};
+drm_ipvr_bufmgr * +drm_ipvr_gem_bufmgr_init(int fd, int batch_size);
+void drm_ipvr_gem_bufmgr_destroy(drm_ipvr_bufmgr *bufmgr);
+int drm_ipvr_gem_bufmgr_get_device_info(drm_ipvr_bufmgr *bufmgr, uint16_t *dev_id, uint16_t *caps);
+/*void drm_ipvr_gem_bufmgr_trace_all_bos(drm_ipvr_bufmgr *bufmgr);*/
+drm_ipvr_bo * +drm_ipvr_gem_bo_alloc(drm_ipvr_bufmgr *bufmgr, drm_ipvr_context *ctx,
const char *name, size_t size,
uint8_t tiling, uint8_t cache_level, uint8_t reusable);
+void drm_ipvr_gem_bo_reference(drm_ipvr_bo *bo);
+void drm_ipvr_gem_bo_unreference(drm_ipvr_bo *bo);
+int drm_ipvr_gem_bo_map(drm_ipvr_bo *bo, unsigned long offset, size_t size, int write_enable);
+int drm_ipvr_gem_bo_unmap(drm_ipvr_bo *bo);
+void drm_ipvr_gem_bo_wait(drm_ipvr_bo *bo);
+int drm_ipvr_gem_bo_emit_reloc(drm_ipvr_bo *bo, unsigned long offset,
drm_ipvr_bo *target_bo, unsigned long target_offset, uint32_t
skip_fence);
+int drm_ipvr_gem_bo_exec(drm_ipvr_bo *bo, unsigned long offset, size_t len,
int fence_in, int *fence_out);
+drm_ipvr_bo * +drm_ipvr_gem_bo_create_from_name(drm_ipvr_bufmgr *bufmgr, drm_ipvr_context *ctx,
const char *name, uint32_t handle);
+int drm_ipvr_gem_bo_flink(drm_ipvr_bo *bo, uint32_t * name);
+int drm_ipvr_gem_bo_export_to_prime(drm_ipvr_bo *bo, int *prime_fd);
+drm_ipvr_bo *drm_ipvr_gem_bo_create_from_prime(drm_ipvr_bufmgr *bufmgr,
int prime_fd, int size);
+int drm_ipvr_gem_bo_busy(drm_ipvr_bo *bo);
+int drm_ipvr_gem_bo_references(drm_ipvr_bo *bo, drm_ipvr_bo *target_bo);
+void drm_ipvr_gem_bo_remove_relocs(drm_ipvr_bo *bo, uint8_t recursive);
+/*int drm_ipvr_gem_bo_get_MB_error(drm_ipvr_bo *bo);*/
+drm_ipvr_context * +drm_ipvr_gem_context_create(drm_ipvr_bufmgr *bufmgr, uint32_t ctx_type, uint32_t tiling_stride, uint32_t tiling_mode);
+void +drm_ipvr_gem_context_destroy(drm_ipvr_context *ctx);
+#endif diff --git a/ipvr/ipvr_bufmgr_gem.c b/ipvr/ipvr_bufmgr_gem.c new file mode 100644 index 0000000..1f6e7c5 --- /dev/null +++ b/ipvr/ipvr_bufmgr_gem.c @@ -0,0 +1,1200 @@ +/*********************************************************
- Copyright 2014 Intel Corporation
- All Rights Reserved.
- Permission is hereby granted, free of charge, to any person obtaining a
- copy of this software and associated documentation files (the
- "Software"), to deal in the Software without restriction, including
- without limitation the rights to use, copy, modify, merge, publish,
- distribute, sub license, and/or sell copies of the Software, and to
- permit persons to whom the Software is furnished to do so, subject to
- the following conditions:
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO
EVENT SHALL
- THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE
FOR ANY CLAIM,
- DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR
- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE
- USE OR OTHER DEALINGS IN THE SOFTWARE.
- The above copyright notice and this permission notice (including the
- next paragraph) shall be included in all copies or substantial portions
- of the Software.
****************/ +/*
- Authors: Yao Cheng yao.cheng@intel.com
- */
+#include <assert.h> +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <xf86drm.h> +#include <xf86atomic.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <assert.h> +#include <pthread.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <stdbool.h> +#include <sys/time.h> +#include "errno.h" +#include "libdrm.h" +#include "libdrm_lists.h" +#include "ipvr_bufmgr.h" +#include "string.h" +#include "ipvr_drm.h" +#ifdef ANDROID +#include <utils/Timers.h> +#endif
+static int debug_level = 3;
+typedef uint64_t nsecs_t; +#define VERB(fmt, ...) _DBGPRINT(0, fmt, ##__VA_ARGS__) +#define DBG(fmt, ...) _DBGPRINT(1, fmt, ##__VA_ARGS__) +#define INFO(fmt, ...) _DBGPRINT(2, fmt, ##__VA_ARGS__) +#define WARN(fmt, ...) _DBGPRINT(3, fmt, ##__VA_ARGS__) +#define ERR(fmt, ...) _DBGPRINT(4, fmt, ##__VA_ARGS__) +#define _DBGPRINT(level, fmt, ...) \
- do { \
if (debug_level <= level) { \
fprintf(stderr, fmt, ##__VA_ARGS__); \
} \
- } while (false);
+#define MAX_SELECT_TIMEOUT (10 * 1000) // 10 msec for 1MB BO +#define COUNT_BEFORE_SELECT (5)
+#define IPVR_TIMEOUT_USEC 990000LL
+typedef struct _drm_ipvr_bo_gem drm_ipvr_bo_gem;
+typedef struct _drm_ipvr_reloc_target_info {
- drm_ipvr_bo *bo;
- uint64_t flags;
+} drm_ipvr_reloc_target;
+struct drm_ipvr_cache_bucket {
- unsigned long size;
- drmMMListHead head;
- size_t count;
- size_t limit;
+};
+typedef struct _drm_ipvr_bufmgr_gem +{
- drm_ipvr_bufmgr base;
- int fd;
- pthread_mutex_t lock;
- pthread_mutex_t list_lock;
- struct drm_ipvr_gem_exec_object *exec_objs;
- drm_ipvr_bo **exec_bos;
- int exec_size;
- int exec_count;
- time_t time;
- int max_relocs;
- /* cache bucket of power-of-two */
- int cache_bucket_size;
- /* only cache linear BOs */
- struct drm_ipvr_cache_bucket *cache_buckets;
- /* seqno used to check BO's last operation oldness */
- int exec_seq;
+} drm_ipvr_bufmgr_gem;
+typedef struct _drm_ipvr_bo_gem +{
- drm_ipvr_bo base;
- const char *name;
- /**
* Kenel-assigned global name for this object
*/
- unsigned int global_name;
- atomic_t refcount;
- uint32_t tiling;
- uint32_t caching;
- unsigned long stride;
- atomic_t mapcount;
- struct drm_ipvr_gem_relocation_entry *relocs;
- /*
* Handle for mmap
*/
- uint64_t map_offset;
- /**
* Array of info structs corresponding to relocs[i].target_handle etc
*/
- drm_ipvr_reloc_target *reloc_target_info;
- /** Number of entries in relocs */
- int reloc_count;
- /**
* Index of the buffer within the validation list while preparing a
* batchbuffer execution.
*/
- int validate_index;
- /**
* Boolean of whether this buffer has been used as a relocation
* target and had its size accounted for, and thus can't have any
* further relocations added to it.
*/
- bool used_as_reloc_target;
- /*bool is_vmap;*/
- bool is_prime_imported;
- /*void *user_virt;*/
- /** BO cache list */
- drmMMListHead cache_head;
- drm_ipvr_context *ctx;
- int exec_seq;
+} drm_ipvr_bo_gem;
+static nsecs_t get_time_ns(void) +{ +#ifdef ANDROID
- return systemTime(SYSTEM_TIME_MONOTONIC);
+#else
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000000000LL + tv.tv_usec * 1000LL;
+#endif +}
+static struct drm_ipvr_cache_bucket * +drm__ipvr_cache_bucket_for_size(drm_ipvr_bufmgr *bufmgr,
size_t size, uint8_t tiling)
+{
- int i;
- drm_ipvr_bufmgr_gem *bufmgr_gem =
(drm_ipvr_bufmgr_gem*)bufmgr;
- assert(tiling == 0);
- for (i = 0; i < bufmgr_gem->cache_bucket_size; i++) {
struct drm_ipvr_cache_bucket *bucket =
&bufmgr_gem->cache_buckets[i];
if (bucket->size >= size) {
return bucket;
}
- }
- return NULL;
+}
+static int +drm__ipvr_gem_bo_free(drm_ipvr_bo *bo) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*) bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- struct drm_gem_close arg;
- int ret;
- bool fence_destroyed = false;
- /* Close this object */
- arg.handle = bo->handle;
- ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &arg);
- if (ret != 0) {
ERR("%s: DRM_IOCTL_GEM_CLOSE \"%s\" handle 0x%x offset 0x%lx
failed: %s\n",
__FUNCTION__, bo_gem->name,
bo->handle, bo->offset, strerror(errno));
- }
- if (bo_gem->relocs)
free(bo_gem->relocs);
- if (bo_gem->reloc_target_info)
free(bo_gem->reloc_target_info);
- DBG("%s: freed buf khandle "%s" hnd %x, offset 0x%lx, %s\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset,
(fence_destroyed? "fence is destroyed": "no fence to destroy"));
- memset(bo_gem, 0, sizeof(*bo_gem));
- free(bo_gem);
- return 0;
+}
+drm_public int +drm_ipvr_gem_bo_map(drm_ipvr_bo *bo, unsigned long offset, size_t size, int write_enable); +drm_public int +drm_ipvr_gem_bo_unmap(drm_ipvr_bo *bo);
+drm_public drm_ipvr_bo * +drm_ipvr_gem_bo_alloc(drm_ipvr_bufmgr *bufmgr, drm_ipvr_context *ctx,
const char *name, size_t size,
uint8_t tiling, uint8_t cache_level, uint8_t reusable)
+{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*)
bufmgr;
- drm_ipvr_bo_gem *allocated_bo_gem = NULL;
- int ret;
- struct drm_ipvr_gem_create arg;
- bool alloc_from_cache = false;
- size_t alloc_size = size;
- struct drm_ipvr_cache_bucket *bucket = NULL;
- int bo_movings = 0;
- int bucket_free_before, bucket_free_after;
- nsecs_t begin_ns, end_ns;
- nsecs_t time_wait, time_bo_moving, time_fence_destroy,
time_kernel_alloc;
- nsecs_t now;
- time_wait = time_bo_moving = time_fence_destroy = time_kernel_alloc
= 0;
- bucket_free_before = bucket_free_after = 0;
- begin_ns = get_time_ns();
- if (reusable)
bucket = drm__ipvr_cache_bucket_for_size(&bufmgr_gem->base, size,
tiling);
- if (reusable && !bucket) {
reusable = false;
WARN("%s size %zu cannot fit into any cache bucket, set as non-
reusable\n",
__FUNCTION__, size);
- }
- if (reusable && bucket) {
/**
* only expand size when it's reusable
*/
alloc_size = bucket->size;
- }
- if (reusable && bucket && !DRMLISTEMPTY(&bucket->head)) {
VERB("%s searching cached BOs in fast mode: free_list\n",
__FUNCTION__);
now = get_time_ns();
pthread_mutex_lock(&bufmgr_gem->list_lock);
allocated_bo_gem = DRMLISTENTRY(drm_ipvr_bo_gem,
bucket->head.next, cache_head);
if (bufmgr_gem->exec_seq - allocated_bo_gem->exec_seq < 5) {
alloc_from_cache = false;
allocated_bo_gem = NULL;
}
else if (!drm_ipvr_gem_bo_busy(&allocated_bo_gem->base)) {
alloc_from_cache = true;
DRMLISTDELINIT(&allocated_bo_gem->cache_head);
bucket->count--;
}
else {
drm_ipvr_gem_bo_wait(&allocated_bo_gem->base);
alloc_from_cache = true;
DRMLISTDELINIT(&allocated_bo_gem->cache_head);
bucket->count--;
}
pthread_mutex_unlock(&bufmgr_gem->list_lock);
time_wait += get_time_ns() - now;
VERB("%s got free BO from cache\n", __FUNCTION__);
- }
- else {
VERB("%s empty free_list, alloc_from kernel\n", __FUNCTION__);
alloc_from_cache = false;
- }
- if (!alloc_from_cache) {
allocated_bo_gem = calloc(1, sizeof(*allocated_bo_gem));
if (!allocated_bo_gem) {
ERR("%s: calloc failed: %s\n", __FUNCTION__, strerror(errno));
return NULL;
}
if (reusable)
arg.size = alloc_size;
else
arg.size = size;
arg.tiling = tiling;
arg.cache_level = cache_level;
now = get_time_ns();
ret = drmCommandWriteRead(bufmgr_gem->fd,
DRM_IPVR_GEM_CREATE,
&arg, sizeof(arg));
if (ret != 0) {
ERR("%s: IOCTL GEM_CREATE failed: %d\n",
__FUNCTION__, ret);
free(allocated_bo_gem);
allocated_bo_gem = NULL;
return NULL;
}
time_kernel_alloc = get_time_ns() - now;
allocated_bo_gem->base.bufmgr = bufmgr;
allocated_bo_gem->base.handle = arg.handle;
allocated_bo_gem->tiling = arg.tiling;
allocated_bo_gem->caching = arg.cache_level;
allocated_bo_gem->stride = 0; /* FIXME: does ipvr_drv_video maintain
stride/sliceHeight itself? */
allocated_bo_gem->base.offset = arg.mmu_offset;
allocated_bo_gem->base.alloc_size = arg.rounded_size;
allocated_bo_gem->base.size = size;
allocated_bo_gem->name = name;
allocated_bo_gem->base.virt = NULL;
allocated_bo_gem->map_offset = arg.map_offset;
allocated_bo_gem->is_prime_imported = false;
atomic_set(&allocated_bo_gem->mapcount, 0);
DBG("%s: allocated buf handle 0x%x from kernel, "
"offset 0x%lx, name \"%s\" size %lu (%lu), tiling %u, cache_level %u,
bufmgr %p\n",
__FUNCTION__,
allocated_bo_gem->base.handle, allocated_bo_gem->base.offset,
allocated_bo_gem->name,
allocated_bo_gem->base.size, allocated_bo_gem->base.alloc_size,
allocated_bo_gem->tiling, allocated_bo_gem->caching, bufmgr);
- }
- else {
assert(allocated_bo_gem);
DBG("%s: allocated buf handle 0x%x from userspace cache, "
"offset 0x%lx, name \"%s\" size %lu (%lu), tiling %u, cache_level %u,
bufmgr %p\n",
__FUNCTION__,
allocated_bo_gem->base.handle, allocated_bo_gem->base.offset,
allocated_bo_gem->name,
allocated_bo_gem->base.size, allocated_bo_gem->base.alloc_size,
allocated_bo_gem->tiling, allocated_bo_gem->caching, bufmgr);
- }
- allocated_bo_gem->name = name;
- allocated_bo_gem->base.size = size;
- allocated_bo_gem->validate_index = -1;
- allocated_bo_gem->ctx = ctx;
- allocated_bo_gem->base.reusable = reusable;
- allocated_bo_gem->exec_seq = -1;
- atomic_set(&allocated_bo_gem->refcount, 1);
- end_ns = get_time_ns();
- if (bucket) {
bucket_free_after = bucket->count;
- }
- assert(atomic_read(&allocated_bo_gem->mapcount) == 0);
- if (end_ns - begin_ns > 2 * 1000 * 1000) {
DBG("%s got from %s: \"%s\" hnd %u offset 0x%lx size %lu took %.2f
ms, "
"(wait %.2f, "
"bo_moving %.2f, kernel_alloc %.2f), "
"bucket (%d/%zu)=>(%d/%zu)\n",
__FUNCTION__, (alloc_from_cache? "CACHE": "KERNEL"),
allocated_bo_gem->name, allocated_bo_gem->base.handle,
allocated_bo_gem->base.offset,
allocated_bo_gem->base.alloc_size, (end_ns - begin_ns)/1000000.0,
time_wait/1000000.0,
bo_movings/1000000.0, time_kernel_alloc/1000000.0,
bucket_free_before, (bucket? bucket->limit: 0),
bucket_free_after, (bucket? bucket->limit: 0));
- }
- return &allocated_bo_gem->base;
+}
+drm_public void drm_ipvr_gem_bo_unreference(drm_ipvr_bo *bo);
+static void +drm__ipvr_gem_bo_remove_relocs(drm_ipvr_bo *bo, int depth, bool recursive) +{
- int i;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem*)bo;
- drm_ipvr_bo_gem *target_bo_gem;
- for (i = 0; i < bo_gem->reloc_count; i++) {
if (bo_gem->reloc_target_info[i].bo != bo) {
target_bo_gem = (drm_ipvr_bo_gem*)bo_gem-
reloc_target_info[i].bo;
VERB("%s (depth: %d) remove \"%s\" hnd %x off 0x%lx => \"%s\"
hnd %x off 0x%lx\n",
__FUNCTION__, depth, bo_gem->name, bo_gem->base.handle,
bo->offset,
target_bo_gem->name, target_bo_gem->base.handle,
target_bo_gem->base.offset);
if (recursive)
drm__ipvr_gem_bo_remove_relocs(bo_gem-
reloc_target_info[i].bo, depth + 1, true);
drm_ipvr_gem_bo_unreference(bo_gem->reloc_target_info[i].bo);
}
bo_gem->reloc_target_info[i].bo = NULL;
memset(&bo_gem->relocs[i], 0, sizeof(bo_gem->relocs[i]));
- }
- bo_gem->reloc_count = 0;
+}
+drm_public void +drm_ipvr_gem_bo_remove_relocs(drm_ipvr_bo *bo, uint8_t recursive) +{
- drm__ipvr_gem_bo_remove_relocs(bo, 0, recursive);
+}
+drm_public void +drm_ipvr_gem_bo_reference(drm_ipvr_bo *bo) +{
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *)bo;
- atomic_inc(&bo_gem->refcount);
- VERB("%s "%s" hnd 0x%x offset 0x%lx, refcount became %d\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset,
atomic_read(&bo_gem->refcount)); +}
+static void +drm__ipvr_gem_bo_finalize(drm_ipvr_bo *bo) +{
- struct drm_ipvr_cache_bucket *bucket;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem*)bo;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*)bo-
bufmgr;
- int mapcount;
- /* add lock? */
- /* Automatically unreference all the target buffers */
- drm_ipvr_gem_bo_remove_relocs(bo, false);
- mapcount = atomic_read(&bo_gem->mapcount);
- if (mapcount != 0)
WARN("%s BO is finalized with mapcount %d\n", __FUNCTION__,
mapcount);
- assert(atomic_read(&bo_gem->mapcount) == 0);
- bo_gem->validate_index = -1;
- bucket = drm__ipvr_cache_bucket_for_size(bo->bufmgr, bo->size,
bo_gem->tiling);
- /* Put the buffer into our internal cache for reuse if we can. */
- if (bo->reusable && bucket != NULL) {
bo_gem->validate_index = -1;
DBG("%s adding bo \"%s\" hnd %x (offset 0x%lx) to internal cache\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset);
pthread_mutex_lock(&bufmgr_gem->list_lock);
DRMLISTADDTAIL(&bo_gem->cache_head, &bucket->head);
bucket->count++;
pthread_mutex_unlock(&bufmgr_gem->list_lock);
- } else {
VERB("%s freeing bo \"%s\" hnd %x (offset 0x%lx)\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset);
drm__ipvr_gem_bo_free(bo);
- }
+}
+drm_public void +drm_ipvr_gem_bo_unreference(drm_ipvr_bo *bo) +{
- drm_ipvr_bo_gem * bo_gem = (drm_ipvr_bo_gem*)bo;
- assert(atomic_read(&bo_gem->refcount) > 0);
- if (atomic_dec_and_test(&bo_gem->refcount)) {
drm__ipvr_gem_bo_finalize(bo);
- } else {
VERB("%s \"%s\" handle 0x%x offset 0x%lx, refcount became %d\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset,
atomic_read(&bo_gem->refcount));
- }
+}
+drm_public int +drm_ipvr_gem_bo_map(drm_ipvr_bo *bo, unsigned long offset,
size_t size, int write_enable)
+{
- int ret;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *)bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem*)bo;
- struct drm_ipvr_gem_mmap_offset arg;
- assert(atomic_read(&bo_gem->mapcount) >= 0);
- /* maintain userspace mapping cache, to avoid unnecessary IOCTLs */
- if (atomic_read(&bo_gem->mapcount) == 0 && !bo->virt) {
/* no need to call synccpu-grab, kernel do it automatically */
VERB("Calling GEM_MMAP with handle %u offset 0x%"PRIx64",
size %"PRIu64"\n",
bo->handle, offset, bo->size);
if (!bo_gem->map_offset) {
memset(&arg, 0, sizeof(arg));
arg.handle = bo->handle;
ret = drmCommandWriteRead(bufmgr_gem->fd,
DRM_IPVR_GEM_MMAP_OFFSET,
&arg, sizeof(arg));
if (ret < 0) {
ERR("%s: failed to get mmap offset at bo \"%s\" 0x%x: %d (%s)\n",
__FUNCTION__, bo_gem->name, bo->handle, ret, strerror(ret));
return ret;
}
}
bo->virt = drm_mmap(0, bo->alloc_size, PROT_READ | PROT_WRITE,
MAP_SHARED, bufmgr_gem->fd, bo_gem->map_offset);
if (bo->virt == MAP_FAILED) {
bo->virt = NULL;
return -errno;
}
VERB("%s: map for first time, \"%s\" hnd 0x%x (offset 0x%lx) (%s) -
%p\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset, bo_gem-
name, bo->virt);
- }
- else {
VERB("%s: already mapped, \"%s\" hnd 0x%x (offset 0x%lx) (%s) -
%p\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset, bo_gem-
name, bo->virt);
- }
- atomic_inc(&bo_gem->mapcount);
- assert(bo->virt);
- VERB("%s: map_count became %d\n",
__FUNCTION__, atomic_read(&bo_gem->mapcount));
- return 0;
+}
+drm_public int +drm_ipvr_gem_bo_unmap(drm_ipvr_bo *bo) +{
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem*)bo;
- int mapcount;
- mapcount = atomic_read(&bo_gem->mapcount);
- if (mapcount <= 0) {
VERB("%s: unexpected unmap() when mapcount is %d, ignore it\n",
__FUNCTION__, mapcount);
- }
- else if (atomic_dec_and_test(&bo_gem->mapcount)) {
if (bo->virt)
drm_munmap(bo->virt, bo->size);
bo->virt = NULL;
- }
- VERB("%s: "%s" hnd 0x%x offset 0x%lx map_count became %d\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset,
atomic_read(&bo_gem->mapcount));
- return 0;
+}
+drm_public void +drm_ipvr_gem_bo_wait(drm_ipvr_bo *bo) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*) bo-
bufmgr;
- drm_ipvr_bo_gem * bo_gem = (drm_ipvr_bo_gem*)bo;
- struct drm_ipvr_gem_wait arg;
- int ret;
- VERB("%s: wait "%s" hnd 0x%x offset 0x%lx\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset);
- arg.handle = bo->handle;
- arg.flags = 0;
- ret = drmCommandWriteRead(bufmgr_gem->fd, DRM_IPVR_GEM_WAIT,
&arg, sizeof(arg));
- if (ret < 0) {
ERR("%s \"%s\" hnd %u offset 0x%lx failed, %d (%s)\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset, ret,
strerror(ret));
- }
+}
+static unsigned +drm__ipvr_time_diff(struct timeval *now, struct timeval *then) +{
- long long val;
- val = now->tv_sec - then->tv_sec;
- val *= 1000000LL;
- val += now->tv_usec;
- val -= then->tv_usec;
- if (val < 1LL)
val = 1LL;
- return (unsigned) val;
+}
+static int +drm__ipvr_setup_reloc_list(drm_ipvr_bo *bo) +{
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *) bo-
bufmgr;
- unsigned int max_relocs = bufmgr_gem->max_relocs;
- if (bo->size / 4 < max_relocs)
max_relocs = bo->size / 4;
- bo_gem->relocs = malloc(max_relocs *
sizeof(struct drm_ipvr_gem_relocation_entry));
- bo_gem->reloc_target_info = malloc(max_relocs *
sizeof(drm_ipvr_reloc_target));
- if (bo_gem->relocs == NULL || bo_gem->reloc_target_info == NULL) {
ERR("%s: failed to alloc relocs and reloc_target_info\n",
__FUNCTION__);
free (bo_gem->relocs);
bo_gem->relocs = NULL;
free (bo_gem->reloc_target_info);
bo_gem->reloc_target_info = NULL;
return 1;
- }
- return 0;
+}
+drm_public int +drm_ipvr_gem_bo_emit_reloc(drm_ipvr_bo *bo, unsigned long offset,
drm_ipvr_bo *target_bo, unsigned long target_offset, uint32_t
skip_fence) +{
- int ret;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *) bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- drm_ipvr_bo_gem *target_bo_gem = (drm_ipvr_bo_gem *) target_bo;
- VERB("%s::%d\n", __func__, __LINE__);
- /* Create a new relocation list if needed */
- if (bo_gem->relocs == NULL) {
ret = drm__ipvr_setup_reloc_list(bo);
if (ret) {
ERR("%s failed: relocs = %p, setup_reloc_list returns %d (%s)\n",
__FUNCTION__, bo_gem->relocs, ret, strerror(ret));
return -ENOMEM;
}
- }
- /* Check overflow */
- assert(bo_gem->reloc_count < bufmgr_gem->max_relocs);
- /* Check args */
- assert(offset <= bo->size - 4);
- /* Make sure that we're not adding a reloc to something whose size has
* already been accounted for.
*/
- if (target_bo_gem != bo_gem) {
/* todo: check it */
- }
- /* An object needing a fence is a tiled buffer, so it won't have
* relocs to other buffers.
*/
- bo_gem->relocs[bo_gem->reloc_count].offset = offset;
- bo_gem->relocs[bo_gem->reloc_count].delta = target_offset;
- bo_gem->relocs[bo_gem->reloc_count].target_handle =
target_bo_gem->base.handle;
- bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo-
offset;
- bo_gem->reloc_target_info[bo_gem->reloc_count].bo = target_bo;
- if (target_bo != bo)
drm_ipvr_gem_bo_reference(target_bo);
- bo_gem->reloc_target_info[bo_gem->reloc_count].flags = skip_fence?
0: IPVR_EXEC_OBJECT_NEED_FENCE;
- bo_gem->reloc_count++;
- VERB("%s emitted reloc: "%s" hnd %x (0x%lx) => "%s" hnd %x (0x%lx
= 0x%lx+0x%lx)\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset,
target_bo_gem->name, target_bo->handle,
target_bo->offset + target_offset, target_bo->offset, target_offset);
- return 0;
+}
+drm_public drm_ipvr_bo * +drm_ipvr_gem_bo_create_from_name(drm_ipvr_bufmgr *bufmgr, drm_ipvr_context *ctx,
const char *name, uint32_t handle)
+{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *)
bufmgr;
- drm_ipvr_bo_gem *bo_gem;
- int ret;
- struct drm_gem_open open_arg;
- open_arg.name = handle;
- ret = drmIoctl(bufmgr_gem->fd,
DRM_IOCTL_GEM_OPEN,
&open_arg);
- if (ret) {
ERR("Couldn't reference %s handle 0x%08x: %s\n",
name, handle, strerror(errno));
return NULL;
- }
- bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem)
return NULL;
- bo_gem->base.size = open_arg.size;
- bo_gem->base.offset = 0;
- bo_gem->base.bufmgr = bufmgr;
- bo_gem->name = name;
- atomic_set(&bo_gem->refcount, 1);
- atomic_set(&bo_gem->mapcount, 0);
- bo_gem->validate_index = -1;
- bo_gem->base.handle = open_arg.handle;
- bo_gem->global_name = handle;
- bo_gem->base.reusable = false;
- DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
- return &bo_gem->base;
+}
+drm_public int +drm_ipvr_gem_bo_flink(drm_ipvr_bo *bo, uint32_t * name) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *) bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- int ret;
- struct drm_gem_flink flink;
- if (!bo_gem->global_name) {
flink.handle = bo_gem->base.handle;
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink);
if (ret != 0)
return -errno;
bo_gem->global_name = flink.name;
bo_gem->base.reusable = false;
- }
- *name = bo_gem->global_name;
- return 0;
+}
+drm_public int +drm_ipvr_gem_bo_export_to_prime(drm_ipvr_bo *bo, int *prime_fd) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *) bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- int ret;
- ret = drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->base.handle,
DRM_CLOEXEC, prime_fd);
- if (ret) {
ERR("%s: failed calling drmPrimeHandleToFD: %d (%s)\n",
__FUNCTION__, ret, strerror(ret))
return ret;
- }
- bo_gem->base.reusable = false;
- return 0;
+}
+drm_public drm_ipvr_bo* +drm_ipvr_gem_bo_create_from_prime(drm_ipvr_bufmgr *bufmgr,
int prime_fd, int size)
+{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem *)
bufmgr;
- int ret;
- uint32_t handle;
- drm_ipvr_bo_gem *bo_gem;
- ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle);
- if (ret) {
ERR("%s: failed calling drmPrimeFDToHandle: %d (%s)\n",
__FUNCTION__, ret, strerror(ret))
return NULL;
- }
- /*
* See if the kernel has already returned this buffer to us. Just as
* for named buffers, we must not create two bo's pointing at the same
* kernel object
*/
- pthread_mutex_lock(&bufmgr_gem->lock);
- bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem) {
pthread_mutex_unlock(&bufmgr_gem->lock);
return NULL;
- }
- /* Determine size of bo. The fd-to-handle ioctl really should
* return the size, but it doesn't. If we have kernel 3.12 or
* later, we can lseek on the prime fd to get the size. Older
* kernels will just fail, in which case we fall back to the
* provided (estimated or guess size). */
- ret = lseek(prime_fd, 0, SEEK_END);
- if (ret != -1) {
bo_gem->base.size = ret;
bo_gem->base.alloc_size = ret;
- }
- else {
bo_gem->base.size = size;
bo_gem->base.alloc_size = size;
- }
- bo_gem->base.bufmgr = bufmgr;
- bo_gem->base.handle = handle;
- bo_gem->tiling = 0;
- bo_gem->caching = 0;
- bo_gem->stride = 0; /* FIXME: does ipvr_drv_video maintain
stride/sliceHeight itself? */
- bo_gem->name = "prime";
- bo_gem->base.virt = NULL;
- bo_gem->map_offset = 0;
- atomic_set(&bo_gem->mapcount, 0);
- atomic_set(&bo_gem->refcount, 1);
- bo_gem->validate_index = -1;
- bo_gem->ctx = NULL;
- bo_gem->base.reusable = false;
- bo_gem->exec_seq = -1;
- bo_gem->is_prime_imported = true;
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return &bo_gem->base;
+}
+static int +drm__ipvr_add_validate_buffer(drm_ipvr_bo *bo, uint64_t flags) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = NULL;
- drm_ipvr_bo_gem *bo_gem = NULL;
- int index;
- if (!bo) {
ERR("%s, invalid bo %p\n", __FUNCTION__, bo);
return -EINVAL;
- }
- bo_gem = (drm_ipvr_bo_gem *) bo;
- if (!(bo->bufmgr)) {
ERR("%s, invalid bo bufmgr %p for bo \"%s\" hnd %x (off 0x%lx)\n",
__FUNCTION__, bo->bufmgr, bo_gem->name, bo->handle, bo-
offset);
return -EINVAL;
- }
- bufmgr_gem = (drm_ipvr_bufmgr_gem *)bo->bufmgr;
- if (bo_gem->validate_index != -1) {
if (!(bufmgr_gem->exec_objs[bo_gem->validate_index].flags &
IPVR_EXEC_OBJECT_NEED_FENCE)
&& (flags & IPVR_EXEC_OBJECT_NEED_FENCE)) {
VERB("%s: already has validate_index %d, update flags: 0x%llx-
0x%llx\n",
__FUNCTION__, bo_gem->validate_index,
bufmgr_gem->exec_objs[bo_gem->validate_index].flags,
IPVR_EXEC_OBJECT_NEED_FENCE | bufmgr_gem-
exec_objs[bo_gem->validate_index].flags);
bufmgr_gem->exec_objs[bo_gem->validate_index].flags |=
IPVR_EXEC_OBJECT_NEED_FENCE;
}
return 0;
- }
- /* Extend the array of validation entries as necessary. */
- if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) {
int new_size = bufmgr_gem->exec_size * 2;
if (new_size == 0)
new_size = 10;
bufmgr_gem->exec_objs =
realloc(bufmgr_gem->exec_objs,
sizeof(*bufmgr_gem->exec_objs) * new_size);
bufmgr_gem->exec_bos =
realloc(bufmgr_gem->exec_bos,
sizeof(*bufmgr_gem->exec_bos) * new_size);
bufmgr_gem->exec_size = new_size;
- }
- if (!bufmgr_gem->exec_objs || !bufmgr_gem->exec_bos) {
ERR("%s val_args = %p and exec_bos = %p\n",
__FUNCTION__, bufmgr_gem->exec_objs, bufmgr_gem->exec_bos);
return -ENOMEM;
- }
- index = bufmgr_gem->exec_count;
- bo_gem->validate_index = index;
- /* Fill in array entry */
- if (bufmgr_gem->exec_objs && bufmgr_gem->exec_bos) {
bufmgr_gem->exec_objs[index].offset = bo->offset;
bufmgr_gem->exec_objs[index].handle = bo_gem->base.handle;
bufmgr_gem->exec_objs[index].flags = flags;
bufmgr_gem->exec_objs[index].relocs_ptr = (uintptr_t)bo_gem-
relocs;
bufmgr_gem->exec_objs[index].relocation_count = bo_gem-
reloc_count;
bufmgr_gem->exec_bos[index] = bo;
VERB("%s added validate buffer \"%s\" hnd %x (off 0x%lx) at [%d]\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset, index);
bufmgr_gem->exec_count++;
- }
- return 0;
+}
+static int +drm__ipvr_bo_process_reloc(drm_ipvr_bo *bo, uint64_t flags) +{
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *)bo;
- int i;
- int ret = 0;
- /* Add the target to the validate list */
- ret = drm__ipvr_add_validate_buffer(bo, flags);
- if (ret != 0)
return ret;
- if (bo_gem->relocs == NULL)
return 0;
- for (i = 0; i < bo_gem->reloc_count; i++) {
drm_ipvr_bo *target_bo = bo_gem->reloc_target_info[i].bo;
uint64_t target_flags = bo_gem->reloc_target_info[i].flags;
if (target_bo == bo)
continue;
/* Continue walking the tree depth-first. */
ret = drm__ipvr_bo_process_reloc(target_bo, target_flags);
if (ret != 0)
return ret;
- }
- return ret;
+}
+drm_public int +drm_ipvr_gem_bo_exec(drm_ipvr_bo *bo, unsigned long offset, size_t len,
int fence_in, int *fence_out)
+{
- int ret;
- int i;
- struct timeval then, now;
- bool have_then = false;
- struct drm_ipvr_gem_execbuffer exec_arg;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *)bo;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*)bo-
bufmgr;
- pthread_mutex_lock(&bufmgr_gem->lock);
- ret = drm__ipvr_bo_process_reloc(bo,
IPVR_EXEC_OBJECT_NEED_FENCE | IPVR_EXEC_OBJECT_SUBMIT);
- if (ret != 0) {
ERR("%s bo_process_reloc2 failed: %d (%s)\n",
__FUNCTION__, ret, strerror(ret));
pthread_mutex_unlock(&bufmgr_gem->lock);
return ret;
- }
- VERB("%s finished the reloc/validate processing. exec_count=%d\n",
__FUNCTION__, bufmgr_gem->exec_count);
- exec_arg.exec_start_offset = offset;
- exec_arg.exec_len = len;
- exec_arg.buffers_ptr = (uintptr_t)bufmgr_gem->exec_objs;
- exec_arg.buffer_count = bufmgr_gem->exec_count;
- exec_arg.ctx_id = bo_gem->ctx->ctx_id;
- VERB("%s sending EXEC IOCTL to kernel with: cmdbuf_handle %x (0x%lx),
size %zu, "
"buffer_list_count %u, ctx_id 0x%08x\n", __FUNCTION__, bo->handle,
bo->offset, len,
exec_arg.buffer_count, exec_arg.ctx_id);
- bufmgr_gem->exec_seq ++;
- do {
ret = drmCommandWriteRead(bufmgr_gem->fd,
DRM_IPVR_GEM_EXECBUFFER,
&exec_arg, sizeof(exec_arg));
if (ret == EAGAIN) {
if (!have_then) {
if (gettimeofday(&then, NULL)) {
ERR("%s have no then, gettimeofday error.\n", __FUNCTION__);
break;
}
have_then = true;
}
if (gettimeofday(&now, NULL)) {
ERR("%s: Gettimeofday error.\n", __FUNCTION__);
break;
}
}
- } while ((ret == EAGAIN) && (drm__ipvr_time_diff(&now, &then) <
IPVR_TIMEOUT_USEC));
- if (ret) {
WARN("%s: command write return is %d\n", __FUNCTION__, ret);
goto out;
- }
- /* update the presumed_mmu_offsets
* in case we support eviction in IPVR driver later */
- for (i = 0; i < bufmgr_gem->exec_count; i++) {
drm_ipvr_bo *bo = bufmgr_gem->exec_bos[i];
drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *)bo;
/* Update the buffer offset to accelerate future exec */
if (bufmgr_gem->exec_objs[i].offset != bo->offset) {
VERB("BO \"%s\" hnd %x migrated: 0x%"PRIx64" -> 0x%llx\n",
bo_gem->name, bo->handle, bo->offset,
bufmgr_gem->exec_objs[i].offset);
bo->offset = bufmgr_gem->exec_objs[i].offset;
}
bo_gem->exec_seq = bufmgr_gem->exec_seq;
- }
- VERB("%s EXECBUFFER IOCTL succeeded\n", __FUNCTION__);
+out:
- for (i = 0; i < bufmgr_gem->exec_count; i++) {
drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem*)bufmgr_gem-
exec_bos[i];
/* Disconnect the buffer from the validate list */
bo_gem->validate_index = -1;
bufmgr_gem->exec_bos[i] = NULL;
- }
- /* autmatically decrease all bo's refcount in the reloc tree.
* VA created bo will be cached if unreferencing in vaRenderPicture.
* execbuf/mtxmsg/surface/colocated_buffer's refcount will become 1.
*/
- drm_ipvr_gem_bo_remove_relocs(bo, 1);
- bufmgr_gem->exec_count = 0;
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return 0;
+}
+drm_public int +drm_ipvr_gem_bo_busy(drm_ipvr_bo *bo) +{
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*)bo-
bufmgr;
- drm_ipvr_bo_gem *bo_gem = (drm_ipvr_bo_gem *) bo;
- struct drm_ipvr_gem_busy arg;
- int ret;
- arg.handle = bo->handle;
- ret = drmCommandWriteRead(bufmgr_gem->fd, DRM_IPVR_GEM_BUSY,
&arg, sizeof(arg));
- if (ret == -EBUSY || (ret == 0 && arg.busy)) {
VERB("%s returns %d: buffer \"%s\" hnd %x (offset 0x%lx) param is
busy".\n",
__FUNCTION__, ret, bo_gem->name, bo->handle, bo->offset);
return 1;
- }
- else if (!ret && !arg.busy){
VERB("%s: buffer \"%s\" hnd %x (offset 0x%lx) param is free\".\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset);
return 0;
- }
- else {
WARN("%s: checking buffer busy \"%s\" hnd %u (offset 0x%lx) "
"got unexpected result: %d (%s), busy state=%d, view it as free.\n",
__FUNCTION__, bo_gem->name, bo->handle, bo->offset, ret,
strerror(ret), arg.busy);
return 0;
- }
+}
+drm_public void +drm_ipvr_gem_bufmgr_destroy(drm_ipvr_bufmgr *bufmgr) +{
- int j;
- drm_ipvr_bufmgr_gem *bufmgr_gem =
(drm_ipvr_bufmgr_gem*)bufmgr;
- if (bufmgr_gem->exec_bos)
free(bufmgr_gem->exec_bos);
- if (bufmgr_gem->exec_objs)
free(bufmgr_gem->exec_objs);
- if (bufmgr_gem->cache_buckets) {
for (j = 0; j < bufmgr_gem->cache_bucket_size; j++) {
struct drm_ipvr_cache_bucket *bucket =
&bufmgr_gem->cache_buckets[j];
while (!DRMLISTEMPTY(&bucket->head)) {
drm_ipvr_bo_gem *bo_gem;
bo_gem = DRMLISTENTRY(drm_ipvr_bo_gem,
bucket->head.next, cache_head);
DRMLISTDELINIT(&bo_gem->cache_head);
bucket->count--;
assert(bo_gem->reloc_count == 0);
drm__ipvr_gem_bo_free(&bo_gem->base);
}
}
free(bufmgr_gem->cache_buckets);
- }
- pthread_mutex_destroy(&bufmgr_gem->lock);
- free(bufmgr_gem);
+}
+drm_public int +drm_ipvr_gem_bo_references(drm_ipvr_bo *bo, drm_ipvr_bo *target_bo) +{
- return -1;
+}
+drm_public void +drm_ipvr_gem_context_destroy(drm_ipvr_context *ctx) +{
- int ret;
- drm_ipvr_bufmgr_gem *bufmgr_gem = (drm_ipvr_bufmgr_gem*)ctx-
bufmgr;
- struct drm_ipvr_context_destroy arg;
- arg.ctx_id = ctx->ctx_id;
- ret = drmCommandWriteRead(bufmgr_gem->fd,
DRM_IPVR_CONTEXT_DESTROY, &arg, sizeof(arg));
- if (ret != 0) {
ERR("%s: Error destroying context %u: %s .\n",
__FUNCTION__, ctx->ctx_id, strerror(ret));
- }
- pthread_mutex_destroy(&bufmgr_gem->lock);
- pthread_mutex_destroy(&bufmgr_gem->list_lock);
- free(ctx);
+}
+drm_public drm_ipvr_context* +drm_ipvr_gem_context_create(drm_ipvr_bufmgr *bufmgr, uint32_t ctx_type,
uint32_t tiling_stride, uint32_t tiling_mode)
+{
- int ret;
- drm_ipvr_bufmgr_gem *bufmgr_gem =
(drm_ipvr_bufmgr_gem*)bufmgr;
- struct drm_ipvr_context_create arg;
- drm_ipvr_context *ctx = calloc(1, sizeof(drm_ipvr_context));
- arg.ctx_type = ctx_type;
- arg.tiling_stride = tiling_stride;
- arg.tiling_scheme = tiling_mode;
- ret = drmCommandWriteRead(bufmgr_gem->fd,
DRM_IPVR_CONTEXT_CREATE, &arg, sizeof(arg));
- if (ret != 0) {
ERR("%s: Error creating context %d: %s. tiling stride=%u,
scheme=%u\n",
__FUNCTION__, ctx_type, strerror(ret),
arg.tiling_stride, arg.tiling_scheme);
free(ctx);
return NULL;
- }
- ctx->ctx_id = arg.ctx_id;
- ctx->ctx_type = ctx_type;
- ctx->bufmgr = bufmgr;
- DBG("%s: successfully create drm context: id=%x, tiling stride=%u,
scheme=%u\n",
__FUNCTION__, ctx->ctx_id, arg.tiling_stride, arg.tiling_scheme);
- return ctx;
+}
+drm_public int +drm_ipvr_gem_bufmgr_get_device_info(drm_ipvr_bufmgr *bufmgr, uint16_t *dev_id, uint16_t *caps) +{
- struct drm_ipvr_misc arg;
- int ret;
- drm_ipvr_bufmgr_gem *bufmgr_gem =
(drm_ipvr_bufmgr_gem*)bufmgr;
- unsigned long info;
- arg.key = IPVR_DEVICE_INFO;
- arg.value = (uint64_t)((unsigned long)&info);
- ret = drmCommandWriteRead(bufmgr_gem->fd, DRM_IPVR_MISC, &arg,
sizeof(arg));
- if (ret != 0) {
ERR("%s: Error getting device info: %s .\n",
__FUNCTION__, strerror(ret));
return ret;
- }
- *dev_id = (info >> 16) & 0xffff;
- *caps = info & 0xffff;
- return 0;
+}
+drm_public drm_ipvr_bufmgr * +drm_ipvr_gem_bufmgr_init(int fd, int batch_size) +{
- drm_ipvr_bufmgr_gem * bufmgr_gem = NULL;
- int j;
- bufmgr_gem = calloc(1, sizeof(*bufmgr_gem));
- if (bufmgr_gem == NULL) {
ERR("bufmgr init: calloc failed: %s\n", strerror(errno));
return NULL;
- }
- bufmgr_gem->fd = fd;
- if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) {
ERR("bufmgr init: mutex init failed: %s\n", strerror(errno));
free(bufmgr_gem);
bufmgr_gem = NULL;
return NULL;
- }
- if (pthread_mutex_init(&bufmgr_gem->list_lock, NULL) != 0) {
ERR("bufmgr init: mutex init failed: %s\n", strerror(errno));
free(bufmgr_gem);
bufmgr_gem = NULL;
return NULL;
- }
- /* Hard code one.
*/
- bufmgr_gem->max_relocs = 32;
- bufmgr_gem->exec_seq = -1;
- /* init cache buckets */
- /* 4KB, 8KB, 16KB, 32KB, 64KB, 128KB, 256KB, 512KB, 1MB, 2MB, 4MB,
8MB, 16MB, 32MB */
- bufmgr_gem->cache_bucket_size = 14;
- bufmgr_gem->cache_buckets = calloc(bufmgr_gem->cache_bucket_size,
sizeof(struct drm_ipvr_cache_bucket));
- if (!bufmgr_gem->cache_buckets) {
ERR("%s failed to allocate cache buckets\n", __FUNCTION__);
return NULL;
- }
- for (j = 0; j < bufmgr_gem->cache_bucket_size; ++j) {
DRMINITLISTHEAD(&bufmgr_gem->cache_buckets[j].head);
bufmgr_gem->cache_buckets[j].size = 0x1000 << j;
bufmgr_gem->cache_buckets[j].limit = 2 << ((14 - j)/2);
bufmgr_gem->cache_buckets[j].count = 0;
- }
- DBG("%s created bufmgr %p with cache_bucket_size %u\n",
__FUNCTION__, &bufmgr_gem->base, bufmgr_gem-
cache_bucket_size);
- return &bufmgr_gem->base;
+} diff --git a/ipvr/libdrm_ipvr.pc.in b/ipvr/libdrm_ipvr.pc.in new file mode 100644 index 0000000..2fe9ab6 --- /dev/null +++ b/ipvr/libdrm_ipvr.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@
+Name: libdrm_ipvr +Description: Userspace interface to VP8 hardware decoder on baytrail +Version: @PACKAGE_VERSION@ +Requires: libdrm +Libs: -L${libdir} -ldrm_ipvr +Cflags: -I${includedir} -I${includedir}/libdrm diff --git a/ipvr/test_ioctl.c b/ipvr/test_ioctl.c new file mode 100644 index 0000000..976c244 --- /dev/null +++ b/ipvr/test_ioctl.c @@ -0,0 +1,423 @@ +/*********************************************************
- test_ioctl.c: it is gem ioctl unit test
- Copyright (c) 2014 Intel Corporation, Hillsboro, OR, USA
- All Rights Reserved.
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for
- more details.
- You should have received a copy of the GNU General Public License along
with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- Authors:
- Yao Cheng yao.cheng@intel.com
****************/ +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <fcntl.h> +#include <inttypes.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <stdint.h> +#include <sys/ioctl.h> +#include "ipvr_drm.h" +#include "i915_drm.h" +#include "../intel/intel_bufmgr.h" +#include <xf86drm.h> +#include <sys/time.h> +#include <time.h> +#include <errno.h> +#include <libdrm.h>
+#define exiterr(ret, fmt, ...) \
- do { \
fprintf(stderr, fmt, ##__VA_ARGS__); \
exit(ret); \
- } while (0);
+#define check_ret(ret) \
- do { \
if (ret) { \
exiterr(ret, "failed at %s::%d: %d (%s)\n", __FILE__, __LINE__, ret,
strerror(ret)); \
} \
- } while (0);
+#define check_addr(addr) \
- do { \
if (!addr) { \
exiterr(-1, "failed at %s::%d: NULL address\n", __FILE__, __LINE__); \
} \
- } while (0);
+static unsigned char msg_data[] = {
0x14,0x81,0x80,0x01,0x11,0x49,0x85,0x00,0x00,0xd0,0x5b,0x00,0x95,0x70,0x ee,0x31,
- 0x00,0x10,0x21,0x04
+};
+static void basic_test(int fd) +{
- struct drm_ipvr_gem_create create_arg;
- struct drm_gem_close close_arg;
- struct drm_gem_flink flink_arg;
- struct drm_gem_open open_arg;
- struct drm_ipvr_gem_mmap_offset map_offset_arg;
- int i915_fd, export_fd, i915_export_fd;
- dri_bufmgr *i915_bufmgr;
- dri_bo *i915_bo;
- uint32_t global_name;
- uint32_t *vaddr;
- uint32_t import_handle;
- int ret;
- printf("\nTesting gem create.\n");
- /* create bo iotcl*/
- memset(&create_arg, 0, sizeof(create_arg));
- create_arg.size = 16 * 1024;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_CREATE,
&create_arg, sizeof(create_arg));
- check_ret(ret);
- printf("\nTest mmap.\n");
- /* mmap bo ioctl*/
- if (!create_arg.map_offset) {
printf("didn't get valid map_offset during BO creation. call
MMAP_OFFSET\n");
map_offset_arg.handle = create_arg.handle;
ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_MMAP_OFFSET,
&map_offset_arg, sizeof(map_offset_arg));
check_ret(ret);
- }
- vaddr = drm_mmap(NULL, create_arg.rounded_size, PROT_READ |
PROT_WRITE,
MAP_SHARED, fd, create_arg.map_offset);
- if (vaddr) {
printf("succeed to call drm_mmap, addr_ptr is %p, writting"
" 0xa5a5a5a5 0xb6b6b6b6 0xc7c7c7c7 0xd8d8d8d8 into it.\n", vaddr);
*vaddr++ = 0xa5a5a5a5;
*vaddr++ = 0xb6b6b6b6;
*vaddr++ = 0xc7c7c7c7;
*vaddr++ = 0xd8d8d8d8;
- } else
exiterr(-1, "failed to call DRM_IOCTL_IPVR_GEM_MMAP ioctl: %d
(%s).\n", ret, strerror(ret));
- drm_munmap(vaddr, create_arg.rounded_size);
- printf("\nTest opening flinked BOs.\n");
- {
/* flink the bo */
flink_arg.handle = create_arg.handle;
flink_arg.name = 0;
ret = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink_arg);
check_ret(ret);
global_name = flink_arg.name;
/* open from flink name */
open_arg.name = global_name;
ret = drmIoctl(fd, DRM_IOCTL_GEM_OPEN, &open_arg);
check_ret(ret);
if (open_arg.size != create_arg.rounded_size)
exiterr(-1, "opened size %llu not consistent with created size %llu\n",
open_arg.size, create_arg.rounded_size);
/* mmap and verify the bo content */
map_offset_arg.handle = open_arg.handle;
ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_MMAP_OFFSET,
&map_offset_arg, sizeof(map_offset_arg));
check_ret(ret);
/* mmap bo ioctl*/
vaddr = drm_mmap(NULL, open_arg.size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, map_offset_arg.offset);
check_addr(vaddr);
printf("succeed to call drm_mmap, addr_ptr is %p, readding got "
"0x%08x 0x%08x 0x%08x 0x%08x.\n", vaddr,
*vaddr, *(vaddr+1), *(vaddr+2), *(vaddr+3));
if (*vaddr == 0xa5a5a5a5 &&
*(vaddr+1) == 0xb6b6b6b6 &&
*(vaddr+2) == 0xc7c7c7c7 &&
*(vaddr+3) == 0xd8d8d8d8) {
printf("succeed to verify opened BO content.\n");
}
else {
drm_munmap(vaddr, create_arg.rounded_size);
exiterr(-1, "failed to call DRM_IOCTL_IPVR_GEM_MMAP ioctl: %d
(%s).\n", ret, strerror(ret));
}
drm_munmap(vaddr, create_arg.rounded_size);
/* close opened bo ioctl*/
close_arg.handle = open_arg.handle;
ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
check_ret(ret);
- }
- printf("\nTest importing i915 prime BOs.\n");
- i915_fd = open("/dev/dri/card0", O_RDWR);
- i915_bufmgr = drm_intel_bufmgr_gem_init(i915_fd, 4096);
- /* test prime import */
- {
i915_bo = dri_bo_alloc(i915_bufmgr, "to-be-exported", 4096, 0x1000);
check_addr(i915_bo);
ret = dri_bo_map(i915_bo, 1);
check_ret(ret);
check_addr(i915_bo->virtual);
vaddr = i915_bo->virtual;
printf("mapped i915 BO to %p and write"
" 0xd8d8d8d8 0xc7c7c7c7 0xb6b6b6b6 0xa5a5a5a5 into it.\n", vaddr);
*vaddr++ = 0xd8d8d8d8;
*vaddr++ = 0xc7c7c7c7;
*vaddr++ = 0xb6b6b6b6;
*vaddr++ = 0xa5a5a5a5;
ret = dri_bo_unmap(i915_bo);
check_ret(ret);
ret = drm_intel_bo_gem_export_to_prime(i915_bo, &i915_export_fd);
check_ret(ret);
ret = drmPrimeFDToHandle(fd, i915_export_fd, &import_handle);
map_offset_arg.handle = import_handle;
ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_MMAP_OFFSET,
&map_offset_arg, sizeof(map_offset_arg));
check_ret(ret);
vaddr = drm_mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, map_offset_arg.offset);
check_addr(vaddr);
printf("succeed mapping the imported BO to %p, content is "
"0x%08x 0x%08x 0x%08x 0x%08x.\n", vaddr,
*vaddr, *(vaddr+1), *(vaddr+2), *(vaddr+3));
if (*vaddr == 0xd8d8d8d8 &&
*(vaddr+1) == 0xc7c7c7c7 &&
*(vaddr+2) == 0xb6b6b6b6 &&
*(vaddr+3) == 0xa5a5a5a5) {
printf("succeeded verifying imported i915 prime BO content.\n");
}
else
exiterr(-1, "failed to verify imported i915 prime BO content\n");
ret = drm_munmap(vaddr, 4096);
check_ret(ret);
close_arg.handle = import_handle;
ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
check_ret(ret);
close(i915_export_fd);
dri_bo_unreference(i915_bo);
- }
- printf("\nTest exporting prime BO and import with i915.\n");
- /* test prime export */
- {
ret = drmPrimeHandleToFD(fd, create_arg.handle, 0, &export_fd);
check_ret(ret);
i915_bo = drm_intel_bo_gem_create_from_prime(i915_bufmgr,
export_fd, create_arg.rounded_size);
check_addr(i915_bo);
ret = drm_intel_gem_bo_map_gtt(i915_bo);
check_ret(ret);
check_addr (i915_bo->virtual);
vaddr = i915_bo->virtual;
printf("succeed to import with i915 and mapping to %p, content is "
"0x%08x 0x%08x 0x%08x 0x%08x.\n", vaddr,
*vaddr, *(vaddr+1), *(vaddr+2), *(vaddr+3));
if (*vaddr == 0xa5a5a5a5 &&
*(vaddr+1) == 0xb6b6b6b6 &&
*(vaddr+2) == 0xc7c7c7c7 &&
*(vaddr+3) == 0xd8d8d8d8) {
printf("succeed to verify exported prime BO content.\n");
}
else
exiterr(-1, "failed to verify exported prime BO content.\n");
ret = dri_bo_unmap(i915_bo);
check_ret(ret);
dri_bo_unreference(i915_bo);
close(export_fd);
- }
- dri_bufmgr_destroy(i915_bufmgr);
- close(i915_fd);
- /* close bo ioctl*/
- close_arg.handle = create_arg.handle;
- ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
- check_ret(ret);
- printf("\nExit gem basic test.\n");
+}
+static void exec_test(int fd) +{
- struct drm_ipvr_context_create ctx_create_arg;
- struct drm_ipvr_context_destroy ctx_destroy_arg;
- struct drm_ipvr_gem_create create_arg;
- struct drm_ipvr_gem_execbuffer exec_arg;
- struct drm_ipvr_gem_wait wait_arg;
- struct drm_ipvr_gem_busy busy_arg;
- struct drm_gem_close close_arg;
- struct drm_ipvr_gem_relocation_entry reloc_entries[3];
- struct drm_ipvr_gem_exec_object *exec_objs;
- struct drm_ipvr_gem_exec_object *arg;
- int i915_fd, i915_export_fd;
- dri_bufmgr *i915_bufmgr;
- dri_bo *i915_bo;
- uint32_t import_handle;
- uint32_t *dword;
- uint32_t *vaddr;
- int i, ret, buffer_count, cmdbuf_size, ctx_type;
- printf("\nTest simple exec ioctl.\n");
- i915_fd = open("/dev/dri/card0", O_RDWR);
- i915_bufmgr = drm_intel_bufmgr_gem_init(i915_fd, 4096);
- /* create a ctx_context, which is needed for exec ioctl */
- memset(&ctx_create_arg, 0, sizeof(ctx_create_arg));
- ctx_type = IPVR_CONTEXT_TYPE_VED;
- ctx_create_arg.ctx_type = ctx_type;
- ctx_create_arg.tiling_scheme = 0;
- ctx_create_arg.tiling_stride = 0;
- ret = drmCommandWriteRead(fd, DRM_IPVR_CONTEXT_CREATE,
&ctx_create_arg, sizeof(ctx_create_arg));
- check_ret(ret);
- buffer_count = 4;
- dword = msg_data;
- exec_objs = calloc(1, sizeof(struct drm_ipvr_gem_exec_object) *
buffer_count);
- /* create 1 bo with correct mmu offset */
- arg = &exec_objs[0];
- memset(&create_arg, 0, sizeof(create_arg));
- create_arg.size = 16 * 1024;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_CREATE,
&create_arg, sizeof(create_arg));
- check_ret(ret);
- arg->handle = create_arg.handle;
- arg->offset = create_arg.mmu_offset;
- arg->flags |= IPVR_EXEC_OBJECT_NEED_FENCE;
- arg->relocation_count = 0;
- arg->relocs_ptr = (uintptr_t)NULL;
- reloc_entries[0].delta = 0;
- reloc_entries[0].offset = 8;
- reloc_entries[0].presumed_offset = create_arg.mmu_offset;
- reloc_entries[0].target_handle = create_arg.handle;
- /* create 1 bo with wrong mmu offset */
- arg = &exec_objs[1];
- memset(&create_arg, 0, sizeof(create_arg));
- create_arg.size = 16 * 1024;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_CREATE,
&create_arg, sizeof(create_arg));
- check_ret(ret);
- arg->handle = create_arg.handle;
- arg->offset = create_arg.mmu_offset;
- arg->flags |= IPVR_EXEC_OBJECT_NEED_FENCE;
- arg->relocation_count = 0;
- arg->relocs_ptr = (uintptr_t)NULL;
- reloc_entries[1].delta = 0;
- reloc_entries[1].offset = 12;
- reloc_entries[1].presumed_offset = dword[reloc_entries[1].offset/4];
- arg->offset = reloc_entries[1].presumed_offset;
- reloc_entries[1].target_handle = create_arg.handle;
- /* import a i915 bo */
- i915_bo = dri_bo_alloc(i915_bufmgr, "to-be-exported", 16 * 1024,
0x1000);
- check_addr(i915_bo);
- ret = drm_intel_bo_gem_export_to_prime(i915_bo, &i915_export_fd);
- check_ret(ret);
- ret = drmPrimeFDToHandle(fd, i915_export_fd, &import_handle);
- check_ret(ret);
- arg = &exec_objs[2];
- arg->handle = import_handle;
- arg->offset = 0; /* we don't know the mmu offset */
- arg->flags |= IPVR_EXEC_OBJECT_NEED_FENCE;
- arg->relocation_count = 0;
- arg->relocs_ptr = (uintptr_t)NULL;
- reloc_entries[2].delta = 0;
- reloc_entries[2].offset = 16;
- reloc_entries[2].presumed_offset = 0;
- reloc_entries[2].target_handle = import_handle;
- /* create a cmd bo with 1 page */
- memset(&create_arg, 0, sizeof(create_arg));
- cmdbuf_size = 4 * 1024;
- create_arg.size = cmdbuf_size;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_CREATE,
&create_arg, sizeof(create_arg));
- check_ret(ret);
- vaddr = drm_mmap(NULL, create_arg.rounded_size, PROT_READ |
PROT_WRITE,
MAP_SHARED, fd, create_arg.map_offset);
- if (vaddr) {
printf("succeed to map CMD BO, addr_ptr is %p.\n", vaddr);
memcpy((void *)vaddr, msg_data, sizeof(msg_data));
- } else
exiterr(-1, "failed to map CMD BO.\n");
- drm_munmap(vaddr, create_arg.rounded_size);
- arg = &exec_objs[3];
- arg->handle = create_arg.handle;
- arg->offset = create_arg.mmu_offset;
- arg->flags |= IPVR_EXEC_OBJECT_NEED_FENCE |
IPVR_EXEC_OBJECT_SUBMIT;
- arg->relocation_count = 3;
- arg->relocs_ptr = (uintptr_t)reloc_entries;
- /* run execbuffer ioctl */
- memset(&exec_arg, 0, sizeof(exec_arg));
- exec_arg.buffer_count = buffer_count;
- exec_arg.buffers_ptr = (uintptr_t)exec_objs;
- exec_arg.exec_start_offset = 0;
- exec_arg.exec_len = 20;
- exec_arg.ctx_id = ctx_create_arg.ctx_id;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_EXECBUFFER,
&exec_arg, sizeof(exec_arg));
- check_ret(ret);
- /*check busy ioctl*/
- memset(&busy_arg, 0, sizeof(busy_arg));
- busy_arg.handle = create_arg.handle;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_BUSY, &busy_arg,
sizeof(busy_arg));
- if (ret != 0 && ret != -EBUSY)
exiterr(ret, "failed calling DRM_IPVR_GEM_BUSY: %d (%s)\n", ret,
strerror(ret));
- /*wait for finish*/
- memset(&wait_arg, 0, sizeof(wait_arg));
- wait_arg.handle = create_arg.handle;
- ret = drmCommandWriteRead(fd, DRM_IPVR_GEM_WAIT, &wait_arg,
sizeof(wait_arg));
- /* the random command causes PANIC */
- check_ret(!(ret == 0) && !(ret == -EDEADLK));
- /* close val bo and cmd bo */
- memset(&close_arg, 0, sizeof(close_arg));
- for (i = 0; i < buffer_count; i++) {
close_arg.handle = exec_objs[i].handle;
ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close_arg);
if (ret == 0)
printf("succeed to call DRM_IOCTL_GEM_CLOSE ioctl.\n");
else
exiterr(-1, "failed to call DRM_IOCTL_GEM_CLOSE ioctl.\n");
- }
- /* clean up i915 */
- close(i915_export_fd);
- dri_bo_unreference(i915_bo);
- dri_bufmgr_destroy(i915_bufmgr);
- close(i915_fd);
- /* destroy the ctx_context */
- memset(&ctx_destroy_arg, 0, sizeof(ctx_destroy_arg));
- ctx_destroy_arg.ctx_id = ctx_create_arg.ctx_id;
- ret = drmCommandWriteRead(fd, DRM_IPVR_CONTEXT_DESTROY,
&ctx_destroy_arg, sizeof(ctx_destroy_arg));
- check_ret(ret);
- return;
+}
+int main(int argc, char **argv) +{
- int fd;
- fd = open("/dev/dri/card1", O_RDWR);
- /* test bo create, mmap, close */
- basic_test(fd);
- /* simulate exec ioctl */
- exec_test(fd);
- close(fd);
- return 0;
+}
2.1.0