libdrm: add etnaviv drm support
Add the libdrm_etnaviv helper library to encapsulate etnaviv-specific interfaces to the DRM. Signed-off-by: Christian Gmeiner <christian.gmeiner@gmail.com> Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Tested-by: Rob Herring <robh@kernel.org>main
parent
2d00869599
commit
95e2cc6a80
|
@ -57,6 +57,7 @@ libdrm_exynos.pc
|
||||||
libdrm_freedreno.pc
|
libdrm_freedreno.pc
|
||||||
libdrm_amdgpu.pc
|
libdrm_amdgpu.pc
|
||||||
libdrm_vc4.pc
|
libdrm_vc4.pc
|
||||||
|
libdrm_etnaviv.pc
|
||||||
libkms.pc
|
libkms.pc
|
||||||
libtool
|
libtool
|
||||||
ltmain.sh
|
ltmain.sh
|
||||||
|
|
|
@ -36,6 +36,7 @@ AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
--enable-freedreno \
|
--enable-freedreno \
|
||||||
--enable-freedreno-kgsl\
|
--enable-freedreno-kgsl\
|
||||||
--enable-tegra-experimental-api \
|
--enable-tegra-experimental-api \
|
||||||
|
--enable-etnaviv-experimental-api \
|
||||||
--enable-install-test-programs \
|
--enable-install-test-programs \
|
||||||
--enable-cairo-tests \
|
--enable-cairo-tests \
|
||||||
--enable-manpages \
|
--enable-manpages \
|
||||||
|
@ -84,6 +85,10 @@ if HAVE_VC4
|
||||||
VC4_SUBDIR = vc4
|
VC4_SUBDIR = vc4
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if HAVE_ETNAVIV
|
||||||
|
ETNAVIV_SUBDIR = etnaviv
|
||||||
|
endif
|
||||||
|
|
||||||
if BUILD_MANPAGES
|
if BUILD_MANPAGES
|
||||||
if HAVE_MANPAGES_STYLESHEET
|
if HAVE_MANPAGES_STYLESHEET
|
||||||
MAN_SUBDIR = man
|
MAN_SUBDIR = man
|
||||||
|
@ -102,6 +107,7 @@ SUBDIRS = \
|
||||||
$(FREEDRENO_SUBDIR) \
|
$(FREEDRENO_SUBDIR) \
|
||||||
$(TEGRA_SUBDIR) \
|
$(TEGRA_SUBDIR) \
|
||||||
$(VC4_SUBDIR) \
|
$(VC4_SUBDIR) \
|
||||||
|
$(ETNAVIV_SUBDIR) \
|
||||||
tests \
|
tests \
|
||||||
$(MAN_SUBDIR)
|
$(MAN_SUBDIR)
|
||||||
|
|
||||||
|
|
16
configure.ac
16
configure.ac
|
@ -132,6 +132,11 @@ AC_ARG_ENABLE(vc4,
|
||||||
[Enable support for vc4's API (default: auto, enabled on arm)]),
|
[Enable support for vc4's API (default: auto, enabled on arm)]),
|
||||||
[VC4=$enableval], [VC4=auto])
|
[VC4=$enableval], [VC4=auto])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(etnaviv-experimental-api,
|
||||||
|
AS_HELP_STRING([--enable-etnaviv-experimental-api],
|
||||||
|
[Enable support for etnaviv's experimental API (default: disabled)]),
|
||||||
|
[ETNAVIV=$enableval], [ETNAVIV=no])
|
||||||
|
|
||||||
AC_ARG_ENABLE(install-test-programs,
|
AC_ARG_ENABLE(install-test-programs,
|
||||||
AS_HELP_STRING([--enable-install-test-programs],
|
AS_HELP_STRING([--enable-install-test-programs],
|
||||||
[Install test programs (default: no)]),
|
[Install test programs (default: no)]),
|
||||||
|
@ -274,6 +279,9 @@ if test "x$drm_cv_atomic_primitives" = "xnone"; then
|
||||||
|
|
||||||
LIBDRM_ATOMICS_NOT_FOUND_MSG($TEGRA, tegra, NVIDIA Tegra, tegra-experimental-api)
|
LIBDRM_ATOMICS_NOT_FOUND_MSG($TEGRA, tegra, NVIDIA Tegra, tegra-experimental-api)
|
||||||
TEGRA=no
|
TEGRA=no
|
||||||
|
|
||||||
|
LIBDRM_ATOMICS_NOT_FOUND_MSG($ETNAVIV, etnaviv, Vivante, etnaviv-experimental-api)
|
||||||
|
ETNAVIV=no
|
||||||
else
|
else
|
||||||
if test "x$INTEL" = xauto; then
|
if test "x$INTEL" = xauto; then
|
||||||
case $host_cpu in
|
case $host_cpu in
|
||||||
|
@ -413,6 +421,11 @@ if test "x$VC4" = xyes; then
|
||||||
AC_DEFINE(HAVE_VC4, 1, [Have VC4 support])
|
AC_DEFINE(HAVE_VC4, 1, [Have VC4 support])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AM_CONDITIONAL(HAVE_ETNAVIV, [test "x$ETNAVIV" = xyes])
|
||||||
|
if test "x$ETNAVIV" = xyes; then
|
||||||
|
AC_DEFINE(HAVE_ETNAVIV, 1, [Have etnaviv support])
|
||||||
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL(HAVE_INSTALL_TESTS, [test "x$INSTALL_TESTS" = xyes])
|
AM_CONDITIONAL(HAVE_INSTALL_TESTS, [test "x$INSTALL_TESTS" = xyes])
|
||||||
if test "x$INSTALL_TESTS" = xyes; then
|
if test "x$INSTALL_TESTS" = xyes; then
|
||||||
AC_DEFINE(HAVE_INSTALL_TESTS, 1, [Install test programs])
|
AC_DEFINE(HAVE_INSTALL_TESTS, 1, [Install test programs])
|
||||||
|
@ -524,6 +537,8 @@ AC_CONFIG_FILES([
|
||||||
tegra/libdrm_tegra.pc
|
tegra/libdrm_tegra.pc
|
||||||
vc4/Makefile
|
vc4/Makefile
|
||||||
vc4/libdrm_vc4.pc
|
vc4/libdrm_vc4.pc
|
||||||
|
etnaviv/Makefile
|
||||||
|
etnaviv/libdrm_etnaviv.pc
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
tests/modeprint/Makefile
|
tests/modeprint/Makefile
|
||||||
tests/modetest/Makefile
|
tests/modetest/Makefile
|
||||||
|
@ -555,4 +570,5 @@ echo " EXYNOS API $EXYNOS"
|
||||||
echo " Freedreno API $FREEDRENO (kgsl: $FREEDRENO_KGSL)"
|
echo " Freedreno API $FREEDRENO (kgsl: $FREEDRENO_KGSL)"
|
||||||
echo " Tegra API $TEGRA"
|
echo " Tegra API $TEGRA"
|
||||||
echo " VC4 API $VC4"
|
echo " VC4 API $VC4"
|
||||||
|
echo " Etnaviv API $ETNAVIV"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
# Import variables LIBDRM_ETNAVIV_FILES, LIBDRM_ETNAVIV_H_FILES
|
||||||
|
include $(LOCAL_PATH)/Makefile.sources
|
||||||
|
|
||||||
|
LOCAL_MODULE := libdrm_etnaviv
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := libdrm
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(patsubst %.h, , $(LIBDRM_ETNAVIV_FILES))
|
||||||
|
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
|
||||||
|
|
||||||
|
LOCAL_CFLAGS := \
|
||||||
|
-DHAVE_LIBDRM_ATOMIC_PRIMITIVES=1
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
|
@ -0,0 +1,26 @@
|
||||||
|
include Makefile.sources
|
||||||
|
|
||||||
|
AM_CFLAGS = \
|
||||||
|
$(WARN_CFLAGS) \
|
||||||
|
-I$(top_srcdir) \
|
||||||
|
$(PTHREADSTUBS_CFLAGS) \
|
||||||
|
-I$(top_srcdir)/include/drm
|
||||||
|
|
||||||
|
libdrm_etnaviv_ladir = $(libdir)
|
||||||
|
libdrm_etnaviv_la_LTLIBRARIES = libdrm_etnaviv.la
|
||||||
|
libdrm_etnaviv_la_LDFLAGS = -version-number 1:0:0 -no-undefined
|
||||||
|
libdrm_etnaviv_la_LIBADD = \
|
||||||
|
../libdrm.la \
|
||||||
|
@PTHREADSTUBS_LIBS@ \
|
||||||
|
@CLOCK_LIB@
|
||||||
|
|
||||||
|
libdrm_etnaviv_la_SOURCES = $(LIBDRM_ETNAVIV_FILES)
|
||||||
|
|
||||||
|
libdrm_etnavivincludedir = ${includedir}/libdrm
|
||||||
|
libdrm_etnavivinclude_HEADERS = $(LIBDRM_ETNAVIV_H_FILES)
|
||||||
|
|
||||||
|
pkgconfigdir = @pkgconfigdir@
|
||||||
|
pkgconfig_DATA = libdrm_etnaviv.pc
|
||||||
|
|
||||||
|
TESTS = etnaviv-symbol-check
|
||||||
|
EXTRA_DIST = $(TESTS)
|
|
@ -0,0 +1,12 @@
|
||||||
|
LIBDRM_ETNAVIV_FILES := \
|
||||||
|
etnaviv_device.c \
|
||||||
|
etnaviv_gpu.c \
|
||||||
|
etnaviv_bo.c \
|
||||||
|
etnaviv_bo_cache.c \
|
||||||
|
etnaviv_pipe.c \
|
||||||
|
etnaviv_cmd_stream.c \
|
||||||
|
etnaviv_drm.h \
|
||||||
|
etnaviv_priv.h
|
||||||
|
|
||||||
|
LIBDRM_ETNAVIV_H_FILES := \
|
||||||
|
etnaviv_drmif.h
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# The following symbols (past the first five) are taken from the public headers.
|
||||||
|
# A list of the latter should be available Makefile.sources/LIBDRM_ETNAVIV_H_FILES
|
||||||
|
|
||||||
|
FUNCS=$(nm -D --format=bsd --defined-only ${1-.libs/libdrm_etnaviv.so} | awk '{print $3}'| while read func; do
|
||||||
|
( grep -q "^$func$" || echo $func ) <<EOF
|
||||||
|
__bss_start
|
||||||
|
_edata
|
||||||
|
_end
|
||||||
|
_fini
|
||||||
|
_init
|
||||||
|
etna_device_new
|
||||||
|
etna_device_ref
|
||||||
|
etna_device_del
|
||||||
|
etna_gpu_new
|
||||||
|
etna_gpu_del
|
||||||
|
etna_gpu_get_param
|
||||||
|
etna_pipe_new
|
||||||
|
etna_pipe_del
|
||||||
|
etna_pipe_wait
|
||||||
|
etna_bo_new
|
||||||
|
etna_bo_from_handle
|
||||||
|
etna_bo_from_name
|
||||||
|
etna_bo_from_dmabuf
|
||||||
|
etna_bo_ref
|
||||||
|
etna_bo_del
|
||||||
|
etna_bo_get_name
|
||||||
|
etna_bo_handle
|
||||||
|
etna_bo_dmabuf
|
||||||
|
etna_bo_size
|
||||||
|
etna_bo_map
|
||||||
|
etna_bo_cpu_prep
|
||||||
|
etna_bo_cpu_fini
|
||||||
|
etna_cmd_stream_new
|
||||||
|
etna_cmd_stream_del
|
||||||
|
etna_cmd_stream_timestamp
|
||||||
|
etna_cmd_stream_flush
|
||||||
|
etna_cmd_stream_finish
|
||||||
|
etna_cmd_stream_reloc
|
||||||
|
EOF
|
||||||
|
done)
|
||||||
|
|
||||||
|
test ! -n "$FUNCS" || echo $FUNCS
|
||||||
|
test ! -n "$FUNCS"
|
|
@ -0,0 +1,347 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
|
||||||
|
drm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
drm_private void bo_del(struct etna_bo *bo);
|
||||||
|
|
||||||
|
/* set buffer name, and add to table, call w/ table_lock held: */
|
||||||
|
static void set_name(struct etna_bo *bo, uint32_t name)
|
||||||
|
{
|
||||||
|
bo->name = name;
|
||||||
|
/* add ourself into the name table: */
|
||||||
|
drmHashInsert(bo->dev->name_table, name, bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called under table_lock */
|
||||||
|
drm_private void bo_del(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
if (bo->map)
|
||||||
|
drm_munmap(bo->map, bo->size);
|
||||||
|
|
||||||
|
if (bo->name)
|
||||||
|
drmHashDelete(bo->dev->name_table, bo->name);
|
||||||
|
|
||||||
|
if (bo->handle) {
|
||||||
|
struct drm_gem_close req = {
|
||||||
|
.handle = bo->handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
drmHashDelete(bo->dev->handle_table, bo->handle);
|
||||||
|
drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lookup a buffer from it's handle, call w/ table_lock held: */
|
||||||
|
static struct etna_bo *lookup_bo(void *tbl, uint32_t handle)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo = NULL;
|
||||||
|
|
||||||
|
if (!drmHashLookup(tbl, handle, (void **)&bo)) {
|
||||||
|
/* found, incr refcnt and return: */
|
||||||
|
bo = etna_bo_ref(bo);
|
||||||
|
|
||||||
|
/* don't break the bucket if this bo was found in one */
|
||||||
|
list_delinit(&bo->list);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a new buffer object, call w/ table_lock held */
|
||||||
|
static struct etna_bo *bo_from_handle(struct etna_device *dev,
|
||||||
|
uint32_t size, uint32_t handle, uint32_t flags)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo = calloc(sizeof(*bo), 1);
|
||||||
|
|
||||||
|
if (!bo) {
|
||||||
|
struct drm_gem_close req = {
|
||||||
|
.handle = handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo->dev = etna_device_ref(dev);
|
||||||
|
bo->size = size;
|
||||||
|
bo->handle = handle;
|
||||||
|
bo->flags = flags;
|
||||||
|
atomic_set(&bo->refcnt, 1);
|
||||||
|
list_inithead(&bo->list);
|
||||||
|
/* add ourselves to the handle table: */
|
||||||
|
drmHashInsert(dev->handle_table, handle, bo);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a new (un-tiled) buffer object */
|
||||||
|
struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo;
|
||||||
|
int ret;
|
||||||
|
struct drm_etnaviv_gem_new req = {
|
||||||
|
.flags = flags,
|
||||||
|
};
|
||||||
|
|
||||||
|
bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags);
|
||||||
|
if (bo)
|
||||||
|
return bo;
|
||||||
|
|
||||||
|
req.size = size;
|
||||||
|
ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW,
|
||||||
|
&req, sizeof(req));
|
||||||
|
if (ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
bo = bo_from_handle(dev, size, req.handle, flags);
|
||||||
|
bo->reuse = 1;
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_bo *etna_bo_ref(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
atomic_inc(&bo->refcnt);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get buffer info */
|
||||||
|
static int get_buffer_info(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct drm_etnaviv_gem_info req = {
|
||||||
|
.handle = bo->handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO,
|
||||||
|
&req, sizeof(req));
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* really all we need for now is mmap offset */
|
||||||
|
bo->offset = req.offset;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* import a buffer object from DRI2 name */
|
||||||
|
struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo;
|
||||||
|
struct drm_gem_open req = {
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
|
||||||
|
/* check name table first, to see if bo is already open: */
|
||||||
|
bo = lookup_bo(dev->name_table, req.handle);
|
||||||
|
if (bo)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
|
||||||
|
ERROR_MSG("gem-open failed: %s", strerror(errno));
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo = lookup_bo(dev->handle_table, req.handle);
|
||||||
|
if (bo)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
bo = bo_from_handle(dev, req.size, req.handle, 0);
|
||||||
|
if (bo)
|
||||||
|
set_name(bo, name);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* import a buffer from dmabuf fd, does not take ownership of the
|
||||||
|
* fd so caller should close() the fd when it is otherwise done
|
||||||
|
* with it (even if it is still using the 'struct etna_bo *')
|
||||||
|
*/
|
||||||
|
struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo;
|
||||||
|
int ret, size;
|
||||||
|
uint32_t handle;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
|
||||||
|
ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
|
||||||
|
if (ret) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo = lookup_bo(dev->handle_table, handle);
|
||||||
|
if (bo)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
/* lseek() to get bo size */
|
||||||
|
size = lseek(fd, 0, SEEK_END);
|
||||||
|
lseek(fd, 0, SEEK_CUR);
|
||||||
|
|
||||||
|
bo = bo_from_handle(dev, size, handle, 0);
|
||||||
|
|
||||||
|
out_unlock:
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* destroy a buffer object */
|
||||||
|
void etna_bo_del(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
struct etna_device *dev = bo->dev;
|
||||||
|
|
||||||
|
if (!bo)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!atomic_dec_and_test(&bo->refcnt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
|
||||||
|
if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
bo_del(bo);
|
||||||
|
etna_device_del_locked(dev);
|
||||||
|
out:
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get the global flink/DRI2 buffer name */
|
||||||
|
int etna_bo_get_name(struct etna_bo *bo, uint32_t *name)
|
||||||
|
{
|
||||||
|
if (!bo->name) {
|
||||||
|
struct drm_gem_flink req = {
|
||||||
|
.handle = bo->handle,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
set_name(bo, req.name);
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
bo->reuse = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*name = bo->name;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t etna_bo_handle(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
return bo->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* caller owns the dmabuf fd that is returned and is responsible
|
||||||
|
* to close() it when done
|
||||||
|
*/
|
||||||
|
int etna_bo_dmabuf(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
int ret, prime_fd;
|
||||||
|
|
||||||
|
ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC,
|
||||||
|
&prime_fd);
|
||||||
|
if (ret) {
|
||||||
|
ERROR_MSG("failed to get dmabuf fd: %d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo->reuse = 0;
|
||||||
|
|
||||||
|
return prime_fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t etna_bo_size(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
return bo->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *etna_bo_map(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
if (!bo->map) {
|
||||||
|
if (!bo->offset) {
|
||||||
|
get_buffer_info(bo);
|
||||||
|
}
|
||||||
|
|
||||||
|
bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, bo->dev->fd, bo->offset);
|
||||||
|
if (bo->map == MAP_FAILED) {
|
||||||
|
ERROR_MSG("mmap failed: %s", strerror(errno));
|
||||||
|
bo->map = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bo->map;
|
||||||
|
}
|
||||||
|
|
||||||
|
int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op)
|
||||||
|
{
|
||||||
|
struct drm_etnaviv_gem_cpu_prep req = {
|
||||||
|
.handle = bo->handle,
|
||||||
|
.op = op,
|
||||||
|
};
|
||||||
|
|
||||||
|
get_abs_timeout(&req.timeout, 5000);
|
||||||
|
|
||||||
|
return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP,
|
||||||
|
&req, sizeof(req));
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_bo_cpu_fini(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
struct drm_etnaviv_gem_cpu_fini req = {
|
||||||
|
.handle = bo->handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI,
|
||||||
|
&req, sizeof(req));
|
||||||
|
}
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
|
||||||
|
drm_private void bo_del(struct etna_bo *bo);
|
||||||
|
drm_private extern pthread_mutex_t table_lock;
|
||||||
|
|
||||||
|
static void add_bucket(struct etna_bo_cache *cache, int size)
|
||||||
|
{
|
||||||
|
unsigned i = cache->num_buckets;
|
||||||
|
|
||||||
|
assert(i < ARRAY_SIZE(cache->cache_bucket));
|
||||||
|
|
||||||
|
list_inithead(&cache->cache_bucket[i].list);
|
||||||
|
cache->cache_bucket[i].size = size;
|
||||||
|
cache->num_buckets++;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_private void etna_bo_cache_init(struct etna_bo_cache *cache)
|
||||||
|
{
|
||||||
|
unsigned long size, cache_max_size = 64 * 1024 * 1024;
|
||||||
|
|
||||||
|
/* OK, so power of two buckets was too wasteful of memory.
|
||||||
|
* Give 3 other sizes between each power of two, to hopefully
|
||||||
|
* cover things accurately enough. (The alternative is
|
||||||
|
* probably to just go for exact matching of sizes, and assume
|
||||||
|
* that for things like composited window resize the tiled
|
||||||
|
* width/height alignment and rounding of sizes to pages will
|
||||||
|
* get us useful cache hit rates anyway)
|
||||||
|
*/
|
||||||
|
add_bucket(cache, 4096);
|
||||||
|
add_bucket(cache, 4096 * 2);
|
||||||
|
add_bucket(cache, 4096 * 3);
|
||||||
|
|
||||||
|
/* Initialize the linked lists for BO reuse cache. */
|
||||||
|
for (size = 4 * 4096; size <= cache_max_size; size *= 2) {
|
||||||
|
add_bucket(cache, size);
|
||||||
|
add_bucket(cache, size + size * 1 / 4);
|
||||||
|
add_bucket(cache, size + size * 2 / 4);
|
||||||
|
add_bucket(cache, size + size * 3 / 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Frees older cached buffers. Called under table_lock */
|
||||||
|
drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (cache->time == time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (i = 0; i < cache->num_buckets; i++) {
|
||||||
|
struct etna_bo_bucket *bucket = &cache->cache_bucket[i];
|
||||||
|
struct etna_bo *bo;
|
||||||
|
|
||||||
|
while (!LIST_IS_EMPTY(&bucket->list)) {
|
||||||
|
bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list);
|
||||||
|
|
||||||
|
/* keep things in cache for at least 1 second: */
|
||||||
|
if (time && ((time - bo->free_time) <= 1))
|
||||||
|
break;
|
||||||
|
|
||||||
|
list_del(&bo->list);
|
||||||
|
bo_del(bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache->time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct etna_bo_bucket *get_bucket(struct etna_bo_cache *cache, uint32_t size)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
/* hmm, this is what intel does, but I suppose we could calculate our
|
||||||
|
* way to the correct bucket size rather than looping..
|
||||||
|
*/
|
||||||
|
for (i = 0; i < cache->num_buckets; i++) {
|
||||||
|
struct etna_bo_bucket *bucket = &cache->cache_bucket[i];
|
||||||
|
if (bucket->size >= size) {
|
||||||
|
return bucket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int is_idle(struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
return etna_bo_cpu_prep(bo,
|
||||||
|
DRM_ETNA_PREP_READ |
|
||||||
|
DRM_ETNA_PREP_WRITE |
|
||||||
|
DRM_ETNA_PREP_NOSYNC) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct etna_bo *find_in_bucket(struct etna_bo_bucket *bucket, uint32_t flags)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo = NULL;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
while (!LIST_IS_EMPTY(&bucket->list)) {
|
||||||
|
bo = LIST_ENTRY(struct etna_bo, bucket->list.next, list);
|
||||||
|
|
||||||
|
if (bo->flags == flags && is_idle(bo)) {
|
||||||
|
list_del(&bo->list);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bo = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate a new (un-tiled) buffer object
|
||||||
|
*
|
||||||
|
* NOTE: size is potentially rounded up to bucket size
|
||||||
|
*/
|
||||||
|
drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache, uint32_t *size,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct etna_bo *bo;
|
||||||
|
struct etna_bo_bucket *bucket;
|
||||||
|
|
||||||
|
*size = ALIGN(*size, 4096);
|
||||||
|
bucket = get_bucket(cache, *size);
|
||||||
|
|
||||||
|
/* see if we can be green and recycle: */
|
||||||
|
if (bucket) {
|
||||||
|
*size = bucket->size;
|
||||||
|
bo = find_in_bucket(bucket, flags);
|
||||||
|
if (bo) {
|
||||||
|
atomic_set(&bo->refcnt, 1);
|
||||||
|
etna_device_ref(bo->dev);
|
||||||
|
return bo;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
struct etna_bo_bucket *bucket = get_bucket(cache, bo->size);
|
||||||
|
|
||||||
|
/* see if we can be green and recycle: */
|
||||||
|
if (bucket) {
|
||||||
|
struct timespec time;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &time);
|
||||||
|
|
||||||
|
bo->free_time = time.tv_sec;
|
||||||
|
list_addtail(&bo->list, &bucket->list);
|
||||||
|
etna_bo_cache_cleanup(cache, time.tv_sec);
|
||||||
|
|
||||||
|
/* bo's in the bucket cache don't have a ref and
|
||||||
|
* don't hold a ref to the dev:
|
||||||
|
*/
|
||||||
|
etna_device_del_locked(bo->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t idx_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static void *grow(void *ptr, uint32_t nr, uint32_t *max, uint32_t sz)
|
||||||
|
{
|
||||||
|
if ((nr + 1) > *max) {
|
||||||
|
if ((*max * 2) < (nr + 1))
|
||||||
|
*max = nr + 5;
|
||||||
|
else
|
||||||
|
*max = *max * 2;
|
||||||
|
ptr = realloc(ptr, *max * sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define APPEND(x, name) ({ \
|
||||||
|
(x)->name = grow((x)->name, (x)->nr_ ## name, &(x)->max_ ## name, sizeof((x)->name[0])); \
|
||||||
|
(x)->nr_ ## name ++; \
|
||||||
|
})
|
||||||
|
|
||||||
|
static inline struct etna_cmd_stream_priv *
|
||||||
|
etna_cmd_stream_priv(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
return (struct etna_cmd_stream_priv *)stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size,
|
||||||
|
void (*reset_notify)(struct etna_cmd_stream *stream, void *priv),
|
||||||
|
void *priv)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *stream = NULL;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
ERROR_MSG("invalid size of 0");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = calloc(1, sizeof(*stream));
|
||||||
|
if (!stream) {
|
||||||
|
ERROR_MSG("allocation failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate even number of 32-bit words */
|
||||||
|
size = ALIGN(size, 2);
|
||||||
|
|
||||||
|
stream->base.buffer = malloc(size * sizeof(uint32_t));
|
||||||
|
if (!stream->base.buffer) {
|
||||||
|
ERROR_MSG("allocation failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->base.size = size;
|
||||||
|
stream->pipe = pipe;
|
||||||
|
stream->reset_notify = reset_notify;
|
||||||
|
stream->reset_notify_priv = priv;
|
||||||
|
|
||||||
|
return &stream->base;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (stream)
|
||||||
|
etna_cmd_stream_del(&stream->base);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_cmd_stream_del(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
|
||||||
|
free(stream->buffer);
|
||||||
|
free(priv->submit.relocs);
|
||||||
|
free(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void reset_buffer(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
|
||||||
|
stream->offset = 0;
|
||||||
|
priv->submit.nr_bos = 0;
|
||||||
|
priv->submit.nr_relocs = 0;
|
||||||
|
priv->nr_bos = 0;
|
||||||
|
|
||||||
|
if (priv->reset_notify)
|
||||||
|
priv->reset_notify(stream, priv->reset_notify_priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
return etna_cmd_stream_priv(stream)->last_timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t append_bo(struct etna_cmd_stream *stream, struct etna_bo *bo)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
idx = APPEND(&priv->submit, bos);
|
||||||
|
idx = APPEND(priv, bos);
|
||||||
|
|
||||||
|
priv->submit.bos[idx].flags = 0;
|
||||||
|
priv->submit.bos[idx].handle = bo->handle;
|
||||||
|
|
||||||
|
priv->bos[idx] = etna_bo_ref(bo);
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add (if needed) bo, return idx: */
|
||||||
|
static uint32_t bo2idx(struct etna_cmd_stream *stream, struct etna_bo *bo,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&idx_lock);
|
||||||
|
|
||||||
|
if (!bo->current_stream) {
|
||||||
|
idx = append_bo(stream, bo);
|
||||||
|
bo->current_stream = stream;
|
||||||
|
bo->idx = idx;
|
||||||
|
} else if (bo->current_stream == stream) {
|
||||||
|
idx = bo->idx;
|
||||||
|
} else {
|
||||||
|
/* slow-path: */
|
||||||
|
for (idx = 0; idx < priv->nr_bos; idx++)
|
||||||
|
if (priv->bos[idx] == bo)
|
||||||
|
break;
|
||||||
|
if (idx == priv->nr_bos) {
|
||||||
|
/* not found */
|
||||||
|
idx = append_bo(stream, bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&idx_lock);
|
||||||
|
|
||||||
|
if (flags & ETNA_RELOC_READ)
|
||||||
|
priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_READ;
|
||||||
|
if (flags & ETNA_RELOC_WRITE)
|
||||||
|
priv->submit.bos[idx].flags |= ETNA_SUBMIT_BO_WRITE;
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
int ret, id = priv->pipe->id;
|
||||||
|
struct etna_gpu *gpu = priv->pipe->gpu;
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_submit req = {
|
||||||
|
.pipe = gpu->core,
|
||||||
|
.exec_state = id,
|
||||||
|
.bos = VOID2U64(priv->submit.bos),
|
||||||
|
.nr_bos = priv->submit.nr_bos,
|
||||||
|
.relocs = VOID2U64(priv->submit.relocs),
|
||||||
|
.nr_relocs = priv->submit.nr_relocs,
|
||||||
|
.stream = VOID2U64(stream->buffer),
|
||||||
|
.stream_size = stream->offset * 4, /* in bytes */
|
||||||
|
};
|
||||||
|
|
||||||
|
ret = drmCommandWriteRead(gpu->dev->fd, DRM_ETNAVIV_GEM_SUBMIT,
|
||||||
|
&req, sizeof(req));
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
ERROR_MSG("submit failed: %d (%s)", ret, strerror(errno));
|
||||||
|
else
|
||||||
|
priv->last_timestamp = req.fence;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < priv->nr_bos; i++) {
|
||||||
|
struct etna_bo *bo = priv->bos[i];
|
||||||
|
|
||||||
|
bo->current_stream = NULL;
|
||||||
|
etna_bo_del(bo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_cmd_stream_flush(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
flush(stream);
|
||||||
|
reset_buffer(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_cmd_stream_finish(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
|
||||||
|
flush(stream);
|
||||||
|
etna_pipe_wait(priv->pipe, priv->last_timestamp, 5000);
|
||||||
|
reset_buffer(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r)
|
||||||
|
{
|
||||||
|
struct etna_cmd_stream_priv *priv = etna_cmd_stream_priv(stream);
|
||||||
|
struct drm_etnaviv_gem_submit_reloc *reloc;
|
||||||
|
uint32_t idx = APPEND(&priv->submit, relocs);
|
||||||
|
uint32_t addr = 0;
|
||||||
|
|
||||||
|
reloc = &priv->submit.relocs[idx];
|
||||||
|
|
||||||
|
reloc->reloc_idx = bo2idx(stream, r->bo, r->flags);
|
||||||
|
reloc->reloc_offset = r->offset;
|
||||||
|
reloc->submit_offset = stream->offset * 4; /* in bytes */
|
||||||
|
reloc->flags = 0;
|
||||||
|
|
||||||
|
etna_cmd_stream_emit(stream, addr);
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <linux/stddef.h>
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <xf86atomic.h>
|
||||||
|
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
struct etna_device *etna_device_new(int fd)
|
||||||
|
{
|
||||||
|
struct etna_device *dev = calloc(sizeof(*dev), 1);
|
||||||
|
|
||||||
|
if (!dev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
atomic_set(&dev->refcnt, 1);
|
||||||
|
dev->fd = fd;
|
||||||
|
dev->handle_table = drmHashCreate();
|
||||||
|
dev->name_table = drmHashCreate();
|
||||||
|
etna_bo_cache_init(&dev->bo_cache);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_device *etna_device_ref(struct etna_device *dev)
|
||||||
|
{
|
||||||
|
atomic_inc(&dev->refcnt);
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void etna_device_del_impl(struct etna_device *dev)
|
||||||
|
{
|
||||||
|
etna_bo_cache_cleanup(&dev->bo_cache, 0);
|
||||||
|
drmHashDestroy(dev->handle_table);
|
||||||
|
drmHashDestroy(dev->name_table);
|
||||||
|
|
||||||
|
free(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
drm_private void etna_device_del_locked(struct etna_device *dev)
|
||||||
|
{
|
||||||
|
if (!atomic_dec_and_test(&dev->refcnt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
etna_device_del_impl(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_device_del(struct etna_device *dev)
|
||||||
|
{
|
||||||
|
if (!atomic_dec_and_test(&dev->refcnt))
|
||||||
|
return;
|
||||||
|
|
||||||
|
pthread_mutex_lock(&table_lock);
|
||||||
|
etna_device_del_impl(dev);
|
||||||
|
pthread_mutex_unlock(&table_lock);
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ETNAVIV_DRM_H__
|
||||||
|
#define __ETNAVIV_DRM_H__
|
||||||
|
|
||||||
|
#include "drm.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Please note that modifications to all structs defined here are
|
||||||
|
* subject to backwards-compatibility constraints:
|
||||||
|
* 1) Do not use pointers, use __u64 instead for 32 bit / 64 bit
|
||||||
|
* user/kernel compatibility
|
||||||
|
* 2) Keep fields aligned to their size
|
||||||
|
* 3) Because of how drm_ioctl() works, we can add new fields at
|
||||||
|
* the end of an ioctl if some care is taken: drm_ioctl() will
|
||||||
|
* zero out the new fields at the tail of the ioctl, so a zero
|
||||||
|
* value should have a backwards compatible meaning. And for
|
||||||
|
* output params, userspace won't see the newly added output
|
||||||
|
* fields.. so that has to be somehow ok.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* timeouts are specified in clock-monotonic absolute times (to simplify
|
||||||
|
* restarting interrupted ioctls). The following struct is logically the
|
||||||
|
* same as 'struct timespec' but 32/64b ABI safe.
|
||||||
|
*/
|
||||||
|
struct drm_etnaviv_timespec {
|
||||||
|
__s64 tv_sec; /* seconds */
|
||||||
|
__s64 tv_nsec; /* nanoseconds */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ETNAVIV_PARAM_GPU_MODEL 0x01
|
||||||
|
#define ETNAVIV_PARAM_GPU_REVISION 0x02
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_0 0x03
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_1 0x04
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_2 0x05
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_3 0x06
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_4 0x07
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_5 0x08
|
||||||
|
#define ETNAVIV_PARAM_GPU_FEATURES_6 0x09
|
||||||
|
|
||||||
|
#define ETNAVIV_PARAM_GPU_STREAM_COUNT 0x10
|
||||||
|
#define ETNAVIV_PARAM_GPU_REGISTER_MAX 0x11
|
||||||
|
#define ETNAVIV_PARAM_GPU_THREAD_COUNT 0x12
|
||||||
|
#define ETNAVIV_PARAM_GPU_VERTEX_CACHE_SIZE 0x13
|
||||||
|
#define ETNAVIV_PARAM_GPU_SHADER_CORE_COUNT 0x14
|
||||||
|
#define ETNAVIV_PARAM_GPU_PIXEL_PIPES 0x15
|
||||||
|
#define ETNAVIV_PARAM_GPU_VERTEX_OUTPUT_BUFFER_SIZE 0x16
|
||||||
|
#define ETNAVIV_PARAM_GPU_BUFFER_SIZE 0x17
|
||||||
|
#define ETNAVIV_PARAM_GPU_INSTRUCTION_COUNT 0x18
|
||||||
|
#define ETNAVIV_PARAM_GPU_NUM_CONSTANTS 0x19
|
||||||
|
#define ETNAVIV_PARAM_GPU_NUM_VARYINGS 0x1a
|
||||||
|
|
||||||
|
#define ETNA_MAX_PIPES 4
|
||||||
|
|
||||||
|
struct drm_etnaviv_param {
|
||||||
|
__u32 pipe; /* in */
|
||||||
|
__u32 param; /* in, ETNAVIV_PARAM_x */
|
||||||
|
__u64 value; /* out (get_param) or in (set_param) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GEM buffers:
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ETNA_BO_CACHE_MASK 0x000f0000
|
||||||
|
/* cache modes */
|
||||||
|
#define ETNA_BO_CACHED 0x00010000
|
||||||
|
#define ETNA_BO_WC 0x00020000
|
||||||
|
#define ETNA_BO_UNCACHED 0x00040000
|
||||||
|
/* map flags */
|
||||||
|
#define ETNA_BO_FORCE_MMU 0x00100000
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_new {
|
||||||
|
__u64 size; /* in */
|
||||||
|
__u32 flags; /* in, mask of ETNA_BO_x */
|
||||||
|
__u32 handle; /* out */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_info {
|
||||||
|
__u32 handle; /* in */
|
||||||
|
__u32 pad;
|
||||||
|
__u64 offset; /* out, offset to pass to mmap() */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ETNA_PREP_READ 0x01
|
||||||
|
#define ETNA_PREP_WRITE 0x02
|
||||||
|
#define ETNA_PREP_NOSYNC 0x04
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_cpu_prep {
|
||||||
|
__u32 handle; /* in */
|
||||||
|
__u32 op; /* in, mask of ETNA_PREP_x */
|
||||||
|
struct drm_etnaviv_timespec timeout; /* in */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_cpu_fini {
|
||||||
|
__u32 handle; /* in */
|
||||||
|
__u32 flags; /* in, placeholder for now, no defined values */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cmdstream Submission:
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The value written into the cmdstream is logically:
|
||||||
|
* relocbuf->gpuaddr + reloc_offset
|
||||||
|
*
|
||||||
|
* NOTE that reloc's must be sorted by order of increasing submit_offset,
|
||||||
|
* otherwise EINVAL.
|
||||||
|
*/
|
||||||
|
struct drm_etnaviv_gem_submit_reloc {
|
||||||
|
__u32 submit_offset; /* in, offset from submit_bo */
|
||||||
|
__u32 reloc_idx; /* in, index of reloc_bo buffer */
|
||||||
|
__u64 reloc_offset; /* in, offset from start of reloc_bo */
|
||||||
|
__u32 flags; /* in, placeholder for now, no defined values */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Each buffer referenced elsewhere in the cmdstream submit (ie. the
|
||||||
|
* cmdstream buffer(s) themselves or reloc entries) has one (and only
|
||||||
|
* one) entry in the submit->bos[] table.
|
||||||
|
*
|
||||||
|
* As a optimization, the current buffer (gpu virtual address) can be
|
||||||
|
* passed back through the 'presumed' field. If on a subsequent reloc,
|
||||||
|
* userspace passes back a 'presumed' address that is still valid,
|
||||||
|
* then patching the cmdstream for this entry is skipped. This can
|
||||||
|
* avoid kernel needing to map/access the cmdstream bo in the common
|
||||||
|
* case.
|
||||||
|
*/
|
||||||
|
#define ETNA_SUBMIT_BO_READ 0x0001
|
||||||
|
#define ETNA_SUBMIT_BO_WRITE 0x0002
|
||||||
|
struct drm_etnaviv_gem_submit_bo {
|
||||||
|
__u32 flags; /* in, mask of ETNA_SUBMIT_BO_x */
|
||||||
|
__u32 handle; /* in, GEM handle */
|
||||||
|
__u64 presumed; /* in/out, presumed buffer address */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Each cmdstream submit consists of a table of buffers involved, and
|
||||||
|
* one or more cmdstream buffers. This allows for conditional execution
|
||||||
|
* (context-restore), and IB buffers needed for per tile/bin draw cmds.
|
||||||
|
*/
|
||||||
|
#define ETNA_PIPE_3D 0x00
|
||||||
|
#define ETNA_PIPE_2D 0x01
|
||||||
|
#define ETNA_PIPE_VG 0x02
|
||||||
|
struct drm_etnaviv_gem_submit {
|
||||||
|
__u32 fence; /* out */
|
||||||
|
__u32 pipe; /* in */
|
||||||
|
__u32 exec_state; /* in, initial execution state (ETNA_PIPE_x) */
|
||||||
|
__u32 nr_bos; /* in, number of submit_bo's */
|
||||||
|
__u32 nr_relocs; /* in, number of submit_reloc's */
|
||||||
|
__u32 stream_size; /* in, cmdstream size */
|
||||||
|
__u64 bos; /* in, ptr to array of submit_bo's */
|
||||||
|
__u64 relocs; /* in, ptr to array of submit_reloc's */
|
||||||
|
__u64 stream; /* in, ptr to cmdstream */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The normal way to synchronize with the GPU is just to CPU_PREP on
|
||||||
|
* a buffer if you need to access it from the CPU (other cmdstream
|
||||||
|
* submission from same or other contexts, PAGE_FLIP ioctl, etc, all
|
||||||
|
* handle the required synchronization under the hood). This ioctl
|
||||||
|
* mainly just exists as a way to implement the gallium pipe_fence
|
||||||
|
* APIs without requiring a dummy bo to synchronize on.
|
||||||
|
*/
|
||||||
|
#define ETNA_WAIT_NONBLOCK 0x01
|
||||||
|
struct drm_etnaviv_wait_fence {
|
||||||
|
__u32 pipe; /* in */
|
||||||
|
__u32 fence; /* in */
|
||||||
|
__u32 flags; /* in, mask of ETNA_WAIT_x */
|
||||||
|
__u32 pad;
|
||||||
|
struct drm_etnaviv_timespec timeout; /* in */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ETNA_USERPTR_READ 0x01
|
||||||
|
#define ETNA_USERPTR_WRITE 0x02
|
||||||
|
struct drm_etnaviv_gem_userptr {
|
||||||
|
__u64 user_ptr; /* in, page aligned user pointer */
|
||||||
|
__u64 user_size; /* in, page aligned user size */
|
||||||
|
__u32 flags; /* in, flags */
|
||||||
|
__u32 handle; /* out, non-zero handle */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct drm_etnaviv_gem_wait {
|
||||||
|
__u32 pipe; /* in */
|
||||||
|
__u32 handle; /* in, bo to be waited for */
|
||||||
|
__u32 flags; /* in, mask of ETNA_WAIT_x */
|
||||||
|
__u32 pad;
|
||||||
|
struct drm_etnaviv_timespec timeout; /* in */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DRM_ETNAVIV_GET_PARAM 0x00
|
||||||
|
/* placeholder:
|
||||||
|
#define DRM_ETNAVIV_SET_PARAM 0x01
|
||||||
|
*/
|
||||||
|
#define DRM_ETNAVIV_GEM_NEW 0x02
|
||||||
|
#define DRM_ETNAVIV_GEM_INFO 0x03
|
||||||
|
#define DRM_ETNAVIV_GEM_CPU_PREP 0x04
|
||||||
|
#define DRM_ETNAVIV_GEM_CPU_FINI 0x05
|
||||||
|
#define DRM_ETNAVIV_GEM_SUBMIT 0x06
|
||||||
|
#define DRM_ETNAVIV_WAIT_FENCE 0x07
|
||||||
|
#define DRM_ETNAVIV_GEM_USERPTR 0x08
|
||||||
|
#define DRM_ETNAVIV_GEM_WAIT 0x09
|
||||||
|
#define DRM_ETNAVIV_NUM_IOCTLS 0x0a
|
||||||
|
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM, struct drm_etnaviv_param)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW, struct drm_etnaviv_gem_new)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO, struct drm_etnaviv_gem_info)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_CPU_PREP DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_PREP, struct drm_etnaviv_gem_cpu_prep)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_CPU_FINI DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_CPU_FINI, struct drm_etnaviv_gem_cpu_fini)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_SUBMIT DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT, struct drm_etnaviv_gem_submit)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_WAIT_FENCE DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE, struct drm_etnaviv_wait_fence)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_USERPTR, struct drm_etnaviv_gem_userptr)
|
||||||
|
#define DRM_IOCTL_ETNAVIV_GEM_WAIT DRM_IOW(DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_WAIT, struct drm_etnaviv_gem_wait)
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __ETNAVIV_DRM_H__ */
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ETNAVIV_DRMIF_H_
|
||||||
|
#define ETNAVIV_DRMIF_H_
|
||||||
|
|
||||||
|
#include <xf86drm.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
struct etna_bo;
|
||||||
|
struct etna_pipe;
|
||||||
|
struct etna_gpu;
|
||||||
|
struct etna_device;
|
||||||
|
struct etna_cmd_stream;
|
||||||
|
|
||||||
|
enum etna_pipe_id {
|
||||||
|
ETNA_PIPE_3D = 0,
|
||||||
|
ETNA_PIPE_2D = 1,
|
||||||
|
ETNA_PIPE_VG = 2,
|
||||||
|
ETNA_PIPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum etna_param_id {
|
||||||
|
ETNA_GPU_MODEL = 0x1,
|
||||||
|
ETNA_GPU_REVISION = 0x2,
|
||||||
|
ETNA_GPU_FEATURES_0 = 0x3,
|
||||||
|
ETNA_GPU_FEATURES_1 = 0x4,
|
||||||
|
ETNA_GPU_FEATURES_2 = 0x5,
|
||||||
|
ETNA_GPU_FEATURES_3 = 0x6,
|
||||||
|
ETNA_GPU_FEATURES_4 = 0x7,
|
||||||
|
ETNA_GPU_FEATURES_5 = 0x8,
|
||||||
|
ETNA_GPU_FEATURES_6 = 0x9,
|
||||||
|
|
||||||
|
ETNA_GPU_STREAM_COUNT = 0x10,
|
||||||
|
ETNA_GPU_REGISTER_MAX = 0x11,
|
||||||
|
ETNA_GPU_THREAD_COUNT = 0x12,
|
||||||
|
ETNA_GPU_VERTEX_CACHE_SIZE = 0x13,
|
||||||
|
ETNA_GPU_SHADER_CORE_COUNT = 0x14,
|
||||||
|
ETNA_GPU_PIXEL_PIPES = 0x15,
|
||||||
|
ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE = 0x16,
|
||||||
|
ETNA_GPU_BUFFER_SIZE = 0x17,
|
||||||
|
ETNA_GPU_INSTRUCTION_COUNT = 0x18,
|
||||||
|
ETNA_GPU_NUM_CONSTANTS = 0x19,
|
||||||
|
ETNA_GPU_NUM_VARYINGS = 0x1a
|
||||||
|
};
|
||||||
|
|
||||||
|
/* bo flags: */
|
||||||
|
#define DRM_ETNA_GEM_CACHE_CACHED 0x00010000
|
||||||
|
#define DRM_ETNA_GEM_CACHE_WC 0x00020000
|
||||||
|
#define DRM_ETNA_GEM_CACHE_UNCACHED 0x00040000
|
||||||
|
#define DRM_ETNA_GEM_CACHE_MASK 0x000f0000
|
||||||
|
/* map flags */
|
||||||
|
#define DRM_ETNA_GEM_FORCE_MMU 0x00100000
|
||||||
|
|
||||||
|
/* bo access flags: (keep aligned to ETNA_PREP_x) */
|
||||||
|
#define DRM_ETNA_PREP_READ 0x01
|
||||||
|
#define DRM_ETNA_PREP_WRITE 0x02
|
||||||
|
#define DRM_ETNA_PREP_NOSYNC 0x04
|
||||||
|
|
||||||
|
/* device functions:
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct etna_device *etna_device_new(int fd);
|
||||||
|
struct etna_device *etna_device_ref(struct etna_device *dev);
|
||||||
|
void etna_device_del(struct etna_device *dev);
|
||||||
|
|
||||||
|
/* gpu functions:
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core);
|
||||||
|
void etna_gpu_del(struct etna_gpu *gpu);
|
||||||
|
int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
|
||||||
|
uint64_t *value);
|
||||||
|
|
||||||
|
|
||||||
|
/* pipe functions:
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id);
|
||||||
|
void etna_pipe_del(struct etna_pipe *pipe);
|
||||||
|
int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms);
|
||||||
|
|
||||||
|
|
||||||
|
/* buffer-object functions:
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct etna_bo *etna_bo_new(struct etna_device *dev,
|
||||||
|
uint32_t size, uint32_t flags);
|
||||||
|
struct etna_bo *etna_bo_from_handle(struct etna_device *dev,
|
||||||
|
uint32_t handle, uint32_t size);
|
||||||
|
struct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name);
|
||||||
|
struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd);
|
||||||
|
struct etna_bo *etna_bo_ref(struct etna_bo *bo);
|
||||||
|
void etna_bo_del(struct etna_bo *bo);
|
||||||
|
int etna_bo_get_name(struct etna_bo *bo, uint32_t *name);
|
||||||
|
uint32_t etna_bo_handle(struct etna_bo *bo);
|
||||||
|
int etna_bo_dmabuf(struct etna_bo *bo);
|
||||||
|
uint32_t etna_bo_size(struct etna_bo *bo);
|
||||||
|
void * etna_bo_map(struct etna_bo *bo);
|
||||||
|
int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op);
|
||||||
|
void etna_bo_cpu_fini(struct etna_bo *bo);
|
||||||
|
|
||||||
|
|
||||||
|
/* cmd stream functions:
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct etna_cmd_stream {
|
||||||
|
uint32_t *buffer;
|
||||||
|
uint32_t offset; /* in 32-bit words */
|
||||||
|
uint32_t size; /* in 32-bit words */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_cmd_stream *etna_cmd_stream_new(struct etna_pipe *pipe, uint32_t size,
|
||||||
|
void (*reset_notify)(struct etna_cmd_stream *stream, void *priv),
|
||||||
|
void *priv);
|
||||||
|
void etna_cmd_stream_del(struct etna_cmd_stream *stream);
|
||||||
|
uint32_t etna_cmd_stream_timestamp(struct etna_cmd_stream *stream);
|
||||||
|
void etna_cmd_stream_flush(struct etna_cmd_stream *stream);
|
||||||
|
void etna_cmd_stream_finish(struct etna_cmd_stream *stream);
|
||||||
|
|
||||||
|
static inline uint32_t etna_cmd_stream_avail(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
static const uint32_t END_CLEARANCE = 2; /* LINK op code */
|
||||||
|
|
||||||
|
return stream->size - stream->offset - END_CLEARANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void etna_cmd_stream_reserve(struct etna_cmd_stream *stream, size_t n)
|
||||||
|
{
|
||||||
|
if (etna_cmd_stream_avail(stream) < n)
|
||||||
|
etna_cmd_stream_flush(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void etna_cmd_stream_emit(struct etna_cmd_stream *stream, uint32_t data)
|
||||||
|
{
|
||||||
|
stream->buffer[stream->offset++] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t etna_cmd_stream_get(struct etna_cmd_stream *stream, uint32_t offset)
|
||||||
|
{
|
||||||
|
return stream->buffer[offset];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void etna_cmd_stream_set(struct etna_cmd_stream *stream, uint32_t offset,
|
||||||
|
uint32_t data)
|
||||||
|
{
|
||||||
|
stream->buffer[offset] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t etna_cmd_stream_offset(struct etna_cmd_stream *stream)
|
||||||
|
{
|
||||||
|
return stream->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_reloc {
|
||||||
|
struct etna_bo *bo;
|
||||||
|
#define ETNA_RELOC_READ 0x0001
|
||||||
|
#define ETNA_RELOC_WRITE 0x0002
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
void etna_cmd_stream_reloc(struct etna_cmd_stream *stream, const struct etna_reloc *r);
|
||||||
|
|
||||||
|
#endif /* ETNAVIV_DRMIF_H_ */
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
|
||||||
|
static uint64_t get_param(struct etna_device *dev, uint32_t core, uint32_t param)
|
||||||
|
{
|
||||||
|
struct drm_etnaviv_param req = {
|
||||||
|
.pipe = core,
|
||||||
|
.param = param,
|
||||||
|
};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GET_PARAM, &req, sizeof(req));
|
||||||
|
if (ret) {
|
||||||
|
ERROR_MSG("get-param (%x) failed! %d (%s)", param, ret, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return req.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_gpu *etna_gpu_new(struct etna_device *dev, unsigned int core)
|
||||||
|
{
|
||||||
|
struct etna_gpu *gpu;
|
||||||
|
|
||||||
|
gpu = calloc(1, sizeof(*gpu));
|
||||||
|
if (!gpu) {
|
||||||
|
ERROR_MSG("allocation failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu->dev = dev;
|
||||||
|
gpu->core = core;
|
||||||
|
|
||||||
|
/* get specs from kernel space */
|
||||||
|
gpu->specs.model = get_param(dev, core, ETNAVIV_PARAM_GPU_MODEL);
|
||||||
|
gpu->specs.revision = get_param(dev, core, ETNAVIV_PARAM_GPU_REVISION);
|
||||||
|
gpu->specs.features[0] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_0);
|
||||||
|
gpu->specs.features[1] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_1);
|
||||||
|
gpu->specs.features[2] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_2);
|
||||||
|
gpu->specs.features[3] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_3);
|
||||||
|
gpu->specs.features[4] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_4);
|
||||||
|
gpu->specs.features[5] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_5);
|
||||||
|
gpu->specs.features[6] = get_param(dev, core, ETNAVIV_PARAM_GPU_FEATURES_6);
|
||||||
|
gpu->specs.stream_count = get_param(dev, core, ETNA_GPU_STREAM_COUNT);
|
||||||
|
gpu->specs.register_max = get_param(dev, core, ETNA_GPU_REGISTER_MAX);
|
||||||
|
gpu->specs.thread_count = get_param(dev, core, ETNA_GPU_THREAD_COUNT);
|
||||||
|
gpu->specs.vertex_cache_size = get_param(dev, core, ETNA_GPU_VERTEX_CACHE_SIZE);
|
||||||
|
gpu->specs.shader_core_count = get_param(dev, core, ETNA_GPU_SHADER_CORE_COUNT);
|
||||||
|
gpu->specs.pixel_pipes = get_param(dev, core, ETNA_GPU_PIXEL_PIPES);
|
||||||
|
gpu->specs.vertex_output_buffer_size = get_param(dev, core, ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE);
|
||||||
|
gpu->specs.buffer_size = get_param(dev, core, ETNA_GPU_BUFFER_SIZE);
|
||||||
|
gpu->specs.instruction_count = get_param(dev, core, ETNA_GPU_INSTRUCTION_COUNT);
|
||||||
|
gpu->specs.num_constants = get_param(dev, core, ETNA_GPU_NUM_CONSTANTS);
|
||||||
|
gpu->specs.num_varyings = get_param(dev, core, ETNA_GPU_NUM_VARYINGS);
|
||||||
|
|
||||||
|
if (!gpu->specs.model)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
INFO_MSG(" GPU model: 0x%x (rev %x)", gpu->specs.model, gpu->specs.revision);
|
||||||
|
|
||||||
|
return gpu;
|
||||||
|
fail:
|
||||||
|
if (gpu)
|
||||||
|
etna_gpu_del(gpu);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_gpu_del(struct etna_gpu *gpu)
|
||||||
|
{
|
||||||
|
free(gpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
int etna_gpu_get_param(struct etna_gpu *gpu, enum etna_param_id param,
|
||||||
|
uint64_t *value)
|
||||||
|
{
|
||||||
|
switch(param) {
|
||||||
|
case ETNA_GPU_MODEL:
|
||||||
|
*value = gpu->specs.model;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_REVISION:
|
||||||
|
*value = gpu->specs.revision;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_0:
|
||||||
|
*value = gpu->specs.features[0];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_1:
|
||||||
|
*value = gpu->specs.features[1];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_2:
|
||||||
|
*value = gpu->specs.features[2];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_3:
|
||||||
|
*value = gpu->specs.features[3];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_4:
|
||||||
|
*value = gpu->specs.features[4];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_5:
|
||||||
|
*value = gpu->specs.features[5];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_FEATURES_6:
|
||||||
|
*value = gpu->specs.features[6];
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_STREAM_COUNT:
|
||||||
|
*value = gpu->specs.stream_count;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_REGISTER_MAX:
|
||||||
|
*value = gpu->specs.register_max;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_THREAD_COUNT:
|
||||||
|
*value = gpu->specs.thread_count;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_VERTEX_CACHE_SIZE:
|
||||||
|
*value = gpu->specs.vertex_cache_size;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_SHADER_CORE_COUNT:
|
||||||
|
*value = gpu->specs.shader_core_count;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_PIXEL_PIPES:
|
||||||
|
*value = gpu->specs.pixel_pipes;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_VERTEX_OUTPUT_BUFFER_SIZE:
|
||||||
|
*value = gpu->specs.vertex_output_buffer_size;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_BUFFER_SIZE:
|
||||||
|
*value = gpu->specs.buffer_size;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_INSTRUCTION_COUNT:
|
||||||
|
*value = gpu->specs.instruction_count;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_NUM_CONSTANTS:
|
||||||
|
*value = gpu->specs.num_constants;
|
||||||
|
return 0;
|
||||||
|
case ETNA_GPU_NUM_VARYINGS:
|
||||||
|
*value = gpu->specs.num_varyings;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
default:
|
||||||
|
ERROR_MSG("invalid param id: %d", param);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "etnaviv_priv.h"
|
||||||
|
|
||||||
|
int etna_pipe_wait(struct etna_pipe *pipe, uint32_t timestamp, uint32_t ms)
|
||||||
|
{
|
||||||
|
struct etna_device *dev = pipe->gpu->dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
struct drm_etnaviv_wait_fence req = {
|
||||||
|
.pipe = pipe->gpu->core,
|
||||||
|
.fence = timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ms == 0)
|
||||||
|
req.flags |= ETNA_WAIT_NONBLOCK;
|
||||||
|
|
||||||
|
get_abs_timeout(&req.timeout, ms);
|
||||||
|
|
||||||
|
ret = drmCommandWrite(dev->fd, DRM_ETNAVIV_WAIT_FENCE, &req, sizeof(req));
|
||||||
|
if (ret) {
|
||||||
|
ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void etna_pipe_del(struct etna_pipe *pipe)
|
||||||
|
{
|
||||||
|
free(pipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct etna_pipe *etna_pipe_new(struct etna_gpu *gpu, enum etna_pipe_id id)
|
||||||
|
{
|
||||||
|
struct etna_pipe *pipe;
|
||||||
|
|
||||||
|
pipe = calloc(1, sizeof(*pipe));
|
||||||
|
if (!pipe) {
|
||||||
|
ERROR_MSG("allocation failed");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipe->id = id;
|
||||||
|
pipe->gpu = gpu;
|
||||||
|
|
||||||
|
return pipe;
|
||||||
|
fail:
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014-2015 Etnaviv Project
|
||||||
|
*
|
||||||
|
* 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:
|
||||||
|
* Christian Gmeiner <christian.gmeiner@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ETNAVIV_PRIV_H_
|
||||||
|
#define ETNAVIV_PRIV_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "libdrm_macros.h"
|
||||||
|
#include "xf86drm.h"
|
||||||
|
#include "xf86atomic.h"
|
||||||
|
|
||||||
|
#include "util_double_list.h"
|
||||||
|
|
||||||
|
#include "etnaviv_drmif.h"
|
||||||
|
#include "etnaviv_drm.h"
|
||||||
|
|
||||||
|
#define VIV_FEATURES_WORD_COUNT 7
|
||||||
|
|
||||||
|
struct etna_specs {
|
||||||
|
uint32_t model;
|
||||||
|
uint32_t revision;
|
||||||
|
uint32_t features[VIV_FEATURES_WORD_COUNT];
|
||||||
|
uint32_t stream_count;
|
||||||
|
uint32_t register_max;
|
||||||
|
uint32_t thread_count;
|
||||||
|
uint32_t shader_core_count;
|
||||||
|
uint32_t vertex_cache_size;
|
||||||
|
uint32_t vertex_output_buffer_size;
|
||||||
|
uint32_t pixel_pipes;
|
||||||
|
uint32_t instruction_count;
|
||||||
|
uint32_t num_constants;
|
||||||
|
uint32_t num_varyings;
|
||||||
|
uint32_t buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_bo_bucket {
|
||||||
|
uint32_t size;
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_bo_cache {
|
||||||
|
struct etna_bo_bucket cache_bucket[14 * 4];
|
||||||
|
unsigned num_buckets;
|
||||||
|
time_t time;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_device {
|
||||||
|
int fd;
|
||||||
|
atomic_t refcnt;
|
||||||
|
|
||||||
|
/* tables to keep track of bo's, to avoid "evil-twin" etna_bo objects:
|
||||||
|
*
|
||||||
|
* handle_table: maps handle to etna_bo
|
||||||
|
* name_table: maps flink name to etna_bo
|
||||||
|
*
|
||||||
|
* We end up needing two tables, because DRM_IOCTL_GEM_OPEN always
|
||||||
|
* returns a new handle. So we need to figure out if the bo is already
|
||||||
|
* open in the process first, before calling gem-open.
|
||||||
|
*/
|
||||||
|
void *handle_table, *name_table;
|
||||||
|
|
||||||
|
struct etna_bo_cache bo_cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
drm_private void etna_bo_cache_init(struct etna_bo_cache *cache);
|
||||||
|
drm_private void etna_bo_cache_cleanup(struct etna_bo_cache *cache, time_t time);
|
||||||
|
drm_private struct etna_bo *etna_bo_cache_alloc(struct etna_bo_cache *cache,
|
||||||
|
uint32_t *size, uint32_t flags);
|
||||||
|
drm_private int etna_bo_cache_free(struct etna_bo_cache *cache, struct etna_bo *bo);
|
||||||
|
|
||||||
|
/* for where @table_lock is already held: */
|
||||||
|
drm_private void etna_device_del_locked(struct etna_device *dev);
|
||||||
|
|
||||||
|
/* a GEM buffer object allocated from the DRM device */
|
||||||
|
struct etna_bo {
|
||||||
|
struct etna_device *dev;
|
||||||
|
void *map; /* userspace mmap'ing (if there is one) */
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t handle;
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t name; /* flink global handle (DRI2 name) */
|
||||||
|
uint64_t offset; /* offset to mmap() */
|
||||||
|
atomic_t refcnt;
|
||||||
|
|
||||||
|
/* in the common case, a bo won't be referenced by more than a single
|
||||||
|
* command stream. So to avoid looping over all the bo's in the
|
||||||
|
* reloc table to find the idx of a bo that might already be in the
|
||||||
|
* table, we cache the idx in the bo. But in order to detect the
|
||||||
|
* slow-path where bo is ref'd in multiple streams, we also must track
|
||||||
|
* the current_stream for which the idx is valid. See bo2idx().
|
||||||
|
*/
|
||||||
|
struct etna_cmd_stream *current_stream;
|
||||||
|
uint32_t idx;
|
||||||
|
|
||||||
|
int reuse;
|
||||||
|
struct list_head list; /* bucket-list entry */
|
||||||
|
time_t free_time; /* time when added to bucket-list */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_gpu {
|
||||||
|
struct etna_device *dev;
|
||||||
|
struct etna_specs specs;
|
||||||
|
uint32_t core;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_pipe {
|
||||||
|
enum etna_pipe_id id;
|
||||||
|
struct etna_gpu *gpu;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct etna_cmd_stream_priv {
|
||||||
|
struct etna_cmd_stream base;
|
||||||
|
struct etna_pipe *pipe;
|
||||||
|
|
||||||
|
uint32_t last_timestamp;
|
||||||
|
|
||||||
|
/* submit ioctl related tables: */
|
||||||
|
struct {
|
||||||
|
/* bo's table: */
|
||||||
|
struct drm_etnaviv_gem_submit_bo *bos;
|
||||||
|
uint32_t nr_bos, max_bos;
|
||||||
|
|
||||||
|
/* reloc's table: */
|
||||||
|
struct drm_etnaviv_gem_submit_reloc *relocs;
|
||||||
|
uint32_t nr_relocs, max_relocs;
|
||||||
|
} submit;
|
||||||
|
|
||||||
|
/* should have matching entries in submit.bos: */
|
||||||
|
struct etna_bo **bos;
|
||||||
|
uint32_t nr_bos, max_bos;
|
||||||
|
|
||||||
|
/* notify callback if buffer reset happend */
|
||||||
|
void (*reset_notify)(struct etna_cmd_stream *stream, void *priv);
|
||||||
|
void *reset_notify_priv;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
|
||||||
|
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
|
#define enable_debug 1 /* TODO make dynamic */
|
||||||
|
|
||||||
|
#define INFO_MSG(fmt, ...) \
|
||||||
|
do { drmMsg("[I] "fmt " (%s:%d)\n", \
|
||||||
|
##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
|
||||||
|
#define DEBUG_MSG(fmt, ...) \
|
||||||
|
do if (enable_debug) { drmMsg("[D] "fmt " (%s:%d)\n", \
|
||||||
|
##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
|
||||||
|
#define WARN_MSG(fmt, ...) \
|
||||||
|
do { drmMsg("[W] "fmt " (%s:%d)\n", \
|
||||||
|
##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
|
||||||
|
#define ERROR_MSG(fmt, ...) \
|
||||||
|
do { drmMsg("[E] " fmt " (%s:%d)\n", \
|
||||||
|
##__VA_ARGS__, __FUNCTION__, __LINE__); } while (0)
|
||||||
|
|
||||||
|
#define VOID2U64(x) ((uint64_t)(unsigned long)(x))
|
||||||
|
|
||||||
|
static inline void get_abs_timeout(struct drm_etnaviv_timespec *tv, uint32_t ms)
|
||||||
|
{
|
||||||
|
struct timespec t;
|
||||||
|
uint32_t s = ms / 1000;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &t);
|
||||||
|
tv->tv_sec = t.tv_sec + s;
|
||||||
|
tv->tv_nsec = t.tv_nsec + ((ms - (s * 1000)) * 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ETNAVIV_PRIV_H_ */
|
|
@ -0,0 +1,11 @@
|
||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: libdrm_etnaviv
|
||||||
|
Description: Userspace interface to etnaviv kernel DRM services
|
||||||
|
Version: @PACKAGE_VERSION@
|
||||||
|
Libs: -L${libdir} -ldrm_etnaviv
|
||||||
|
Cflags: -I${includedir} -I${includedir}/libdrm
|
||||||
|
Requires.private: libdrm
|
Loading…
Reference in New Issue