From: Boram Park Date: Tue, 21 Aug 2012 09:04:23 +0000 (+0900) Subject: upload tizen2.0 source X-Git-Tag: 2.0_alpha^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;p=framework%2Fuifw%2Fxorg%2Flib%2Flibdrm.git upload tizen2.0 source --- diff --git a/Makefile.am b/Makefile.am index 3846d3a..6e74607 100644 --- a/Makefile.am +++ b/Makefile.am @@ -41,11 +41,19 @@ if HAVE_RADEON RADEON_SUBDIR = radeon endif +if HAVE_OMAP +OMAP_SUBDIR = omap +endif + +if HAVE_EXYNOS +EXYNOS_SUBDIR = exynos +endif + if HAVE_SLP SLP_SUBDIR = slp endif -SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(SLP_SUBDIR) tests include +SUBDIRS = . $(LIBKMS_SUBDIR) $(INTEL_SUBDIR) $(NOUVEAU_SUBDIR) $(RADEON_SUBDIR) $(OMAP_SUBDIR) $(EXYNOS_SUBDIR) $(SLP_SUBDIR) tests include libdrm_la_LTLIBRARIES = libdrm.la libdrm_ladir = $(libdir) diff --git a/autogen.sh b/autogen.sh old mode 100755 new mode 100644 diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..c31e652 --- /dev/null +++ b/build.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +USER=`whoami` +PREFIX=/usr/local/build +KERNEL_DIR=/home/pub/git/party/linux-mobile +CROSS_COMPILER="/opt/toolchains/arm-linux-link/bin/arm-none-linux-gnueabi-" + +if [ "$USER" = "dofmind" ]; then + PREFIX=/usr/local/build + KERNEL_DIR=/home/pub/git/gerrit/linux-2.6 + CROSS_COMPILER="/opt/toolchains/arm-linux-link/bin/arm-none-linux-gnueabi-" +fi +if [ "$USER" = "daeinki" ]; then + PREFIX=/home/daeinki/project/share + KERNEL_DIR=/home/daeinki/project/s5pc210/linux-mobile + CROSS_COMPILER="/usr/local/arm/arm-2009q3-93/bin/arm-none-linux-gnueabi-" +fi + +HOST="`echo $CROSS_COMPILER | sed 's/.*bin\///' | sed 's/-$//'`" + +make distclean +./autogen.sh +./configure --host=$HOST --prefix=$PREFIX --disable-intel --disable-radeon --enable-exynos-experimental-api --with-kernel-source=$KERNEL_DIR + +sudo rm -rf $PREFIX +sudo mkdir -p $PREFIX +sudo chown $USER.$USER $PREFIX + +make +make install + +mkdir $PREFIX/bin +cp -a ./tests/gemtest/.libs/gemtest $PREFIX/bin +cp -a ./tests/kmstest/.libs/kmstest $PREFIX/bin +cp -a ./tests/modeprint/.libs/modeprint $PREFIX/bin +cp -a ./tests/modetest/.libs/modetest $PREFIX/bin +cp -a ./tests/proptest/.libs/proptest $PREFIX/bin +cp -a ./tests/ipptest/.libs/ipptest $PREFIX/bin +cp -a ./tests/g2dtest/.libs/g2dtest $PREFIX/bin +cp -a ./tests/rottest/.libs/rottest $PREFIX/bin + +tar zcvf libdrm.tar.gz $PREFIX diff --git a/configure.ac b/configure.ac index 527d1ad..68d1cdd 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PREREQ([2.63]) AC_INIT([libdrm], - [2.4.29], + [2.4.35], [https://bugs.freedesktop.org/enter_bug.cgi?product=DRI], [libdrm]) @@ -51,10 +51,6 @@ PKG_CHECK_MODULES(PTHREADSTUBS, pthread-stubs) AC_SUBST(PTHREADSTUBS_CFLAGS) AC_SUBST(PTHREADSTUBS_LIBS) -PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10]) -AC_SUBST(PCIACCESS_CFLAGS) -AC_SUBST(PCIACCESS_LIBS) - pkgconfigdir=${libdir}/pkgconfig AC_SUBST(pkgconfigdir) AC_ARG_ENABLE([udev], @@ -77,15 +73,25 @@ AC_ARG_ENABLE(radeon, [Enable support for radeon's KMS API (default: auto)]), [RADEON=$enableval], [RADEON=auto]) +AC_ARG_ENABLE(nouveau, + AS_HELP_STRING([--disable-nouveau], + [Enable support for nouveau's KMS API (default: auto)]), + [NOUVEAU=$enableval], [NOUVEAU=auto]) + AC_ARG_ENABLE(vmwgfx-experimental-api, AS_HELP_STRING([--enable-vmwgfx-experimental-api], [Install vmwgfx's experimental kernel API header (default: disabled)]), [VMWGFX=$enableval], [VMWGFX=no]) -AC_ARG_ENABLE(nouveau-experimental-api, - AS_HELP_STRING([--enable-nouveau-experimental-api], - [Enable support for nouveau's experimental API (default: disabled)]), - [NOUVEAU=$enableval], [NOUVEAU=no]) +AC_ARG_ENABLE(omap-experimental-api, + AS_HELP_STRING([--enable-omap-experimental-api], + [Enable support for OMAP's experimental API (default: disabled)]), + [OMAP=$enableval], [OMAP=no]) + +AC_ARG_ENABLE(exynos-experimental-api, + AS_HELP_STRING([--enable-exynos-experimental-api], + [Enable support for EXYNOS's experimental API (default: disabled)]), + [EXYNOS=$enableval], [EXYNOS=no]) AC_ARG_ENABLE(slp, AS_HELP_STRING([--disable-slp], @@ -126,6 +132,8 @@ AC_CHECK_FUNCS([clock_gettime], [CLOCK_LIB=], [AC_MSG_ERROR([Couldn't find clock_gettime])])]) AC_SUBST([CLOCK_LIB]) +AC_CHECK_FUNCS([open_memstream], [HAVE_OPEN_MEMSTREAM=yes]) + dnl Use lots of warning flags with with gcc and compatible compilers dnl Note: if you change the following variable, the cache is automatically @@ -196,6 +204,16 @@ if test "x$NOUVEAU" = xyes; then AC_DEFINE(HAVE_NOUVEAU, 1, [Have nouveau (nvidia) support]) fi +AM_CONDITIONAL(HAVE_OMAP, [test "x$OMAP" = xyes]) +if test "x$OMAP" = xyes; then + AC_DEFINE(HAVE_OMAP, 1, [Have OMAP support]) +fi + +AM_CONDITIONAL(HAVE_EXYNOS, [test "x$EXYNOS" = xyes]) +if test "x$EXYNOS" = xyes; then + AC_DEFINE(HAVE_EXYNOS, 1, [Have EXYNOS support]) +fi + PKG_CHECK_MODULES(CAIRO, cairo, [HAVE_CAIRO=yes], [HAVE_CAIRO=no]) if test "x$HAVE_CAIRO" = xyes; then AC_DEFINE(HAVE_CAIRO, 1, [Have cairo support]) @@ -209,7 +227,7 @@ if test "x$HAVE_LIBUDEV" = xyes; then fi AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes]) -if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$SLP" != "xno"; then +if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$NOUVEAU" != "xno" -o "x$SLP" != "xno"; then # Check for atomic intrinsics AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives, [ @@ -257,14 +275,27 @@ if test "x$INTEL" != "xno" -o "x$RADEON" != "xno" -o "x$SLP" != "xno"; then AC_MSG_WARN([Disabling libdrm_radeon. 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.]) RADEON=no fi - + if test "x$NOUVEAU" != "xauto"; then + if test "x$NOUVEAU" != "xno"; then + AC_MSG_ERROR([libdrm_nouveau 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 NVIDIA GPUs by passing --disable-nouveau to ./configure]) + fi + else + AC_MSG_WARN([Disabling libdrm_nouveau. 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.]) + NOUVEAU=no + fi else if test "x$INTEL" != "xno"; then - INTEL=yes + case $host_cpu in + i?86|x86_64) INTEL=yes ;; + *) INTEL=no ;; + esac fi if test "x$RADEON" != "xno"; then RADEON=yes fi + if test "x$NOUVEAU" != "xno"; then + NOUVEAU=yes + fi fi fi @@ -272,9 +303,21 @@ if test "x$SLP" != "xno"; then AC_DEFINE(HAVE_SLP, 1, [Have slp]) fi +if test "x$INTEL" != "xno"; then + PKG_CHECK_MODULES(PCIACCESS, [pciaccess >= 0.10]) +fi +AC_SUBST(PCIACCESS_CFLAGS) +AC_SUBST(PCIACCESS_LIBS) + +PKG_CHECK_MODULES(VALGRIND, [valgrind], [have_valgrind=yes], [have_valgrind=no]) +if test "x$have_valgrind" = "xyes"; then + AC_DEFINE([HAVE_VALGRIND], 1, [Use valgrind intrinsics to suppress false warnings]) +fi + AM_CONDITIONAL(HAVE_SLP, [test "x$SLP" != "xno"]) AM_CONDITIONAL(HAVE_INTEL, [test "x$INTEL" != "xno"]) AM_CONDITIONAL(HAVE_RADEON, [test "x$RADEON" != "xno"]) +AM_CONDITIONAL(HAVE_NOUVEAU, [test "x$NOUVEAU" != "xno"]) if test "x$RADEON" = xyes; then AC_DEFINE(HAVE_RADEON, 1, [Have radeon support]) fi @@ -298,14 +341,21 @@ AC_CONFIG_FILES([ radeon/libdrm_radeon.pc nouveau/Makefile nouveau/libdrm_nouveau.pc + omap/Makefile + omap/libdrm_omap.pc + exynos/Makefile + exynos/libdrm_exynos.pc tests/Makefile tests/modeprint/Makefile tests/modetest/Makefile tests/kmstest/Makefile + tests/proptest/Makefile tests/radeon/Makefile tests/vbltest/Makefile tests/gemtest/Makefile - tests/planetest/Makefile + tests/g2dtest/Makefile + tests/ipptest/Makefile + tests/rottest/Makefile include/Makefile include/drm/Makefile libdrm.pc]) @@ -319,6 +369,8 @@ echo " Intel API $INTEL" echo " vmwgfx API $VMWGFX" echo " Radeon API $RADEON" echo " Nouveau API $NOUVEAU" +echo " OMAP API $OMAP" +echo " EXYNOS API $EXYNOS" echo " SLP API $SLP" echo " SLP bufmgr_dir $bufmgr_dir" echo "" diff --git a/debian/changelog b/debian/changelog index 4740b56..58e7c5f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,91 @@ +libdrm (2.4.35-1slp2) unstable; urgency=low + + * upgrade to 2.4.35 + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.35-1slp2 + + -- Boram Park Mon, 11 Jun 2012 18:58:07 +0900 + +libdrm (2.4.33-5slp2) unstable; urgency=low + + * update changelog + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.33-5slp2 + + -- Boram Park Tue, 29 May 2012 20:33:15 +0900 + +libdrm (2.4.33-4slp2) unstable; urgency=low + + * update for cacheflush + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.33-4slp2 + + -- Boram Park Mon, 30 Apr 2012 16:46:47 +0900 + +libdrm (2.4.33-3slp2) unstable; urgency=low + + * fix : wrong condition + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.33-3slp2 + + -- Boram Park Thu, 26 Apr 2012 15:10:55 +0900 + +libdrm (2.4.33-2slp2) unstable; urgency=low + + * update changelog + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.33-2slp2 + + -- Boram Park Thu, 26 Apr 2012 11:06:32 +0900 + +libdrm (2.4.33-1slp2) unstable; urgency=low + + * version upgrade to 2.4.33 + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.33-1slp2 + + -- Boram Park Wed, 25 Apr 2012 11:38:37 +0900 + +libdrm (2.4.27-18slp2) unstable; urgency=low + + * update exynos_drm.h + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.27-18slp2 + + -- Boram Park Thu, 29 Mar 2012 16:58:17 +0900 + +libdrm (2.4.27-17slp2) unstable; urgency=low + + * fix exynos_drm.h + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.27-17slp2 + + -- SooChan Lim Thu, 22 Mar 2012 20:33:18 +0900 + +libdrm (2.4.27-16slp2) unstable; urgency=low + + * update exynos_drm.h + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.27-16slp2 + + -- SooChan Lim Thu, 22 Mar 2012 20:00:05 +0900 + +libdrm (2.4.27-15slp2) unstable; urgency=low + + * update exynos_drm.h + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.27-15slp2 + + -- SooChan Lim Wed, 07 Mar 2012 13:16:38 +0900 + +libdrm (2.4.27-14slp2) unstable; urgency=low + + * update headers for g2d and virtual output + * Git: slp/pkgs/xorg/lib/libdrm + * Tag: libdrm_2.4.27-14slp2 + + -- SooChan Lim Fri, 17 Feb 2012 15:19:47 +0900 + libdrm (2.4.27-13slp2) unstable; urgency=low * patch from kernel : add virtual display for wireless display diff --git a/debian/libdrm-dev.install b/debian/libdrm-dev.install index 0c219ff..0fbec43 100644 --- a/debian/libdrm-dev.install +++ b/debian/libdrm-dev.install @@ -1,6 +1,8 @@ usr/include/* +usr/include/exynos/* usr/lib/lib*.a usr/lib/lib*.la usr/lib/libdrm.so +usr/lib/libdrm_exynos.so usr/lib/libdrm_slp.so usr/lib/pkgconfig/* diff --git a/debian/libdrm2.install b/debian/libdrm2.install index 8383687..7cc185c 100644 --- a/debian/libdrm2.install +++ b/debian/libdrm2.install @@ -1 +1,2 @@ usr/lib/libdrm.so.* /usr/lib +usr/lib/libdrm_exynos.so.* /usr/lib diff --git a/debian/rules b/debian/rules old mode 100755 new mode 100644 index eb4d728..bc5e503 --- a/debian/rules +++ b/debian/rules @@ -38,7 +38,7 @@ confflags += --enable-udev #confflags += --disable-udev confflags += --enable-libkms LIBKMS=yes -confflags += --disable-nouveau-experimental-api +confflags += --disable-nouveau NOUVEAU = no confflags += --disable-radeon RADEON = no @@ -86,7 +86,7 @@ obj-$(DEB_BUILD_GNU_TYPE)/config.status: configure test -d obj-$(DEB_BUILD_GNU_TYPE) || mkdir obj-$(DEB_BUILD_GNU_TYPE) cd obj-$(DEB_BUILD_GNU_TYPE) && \ ../configure --prefix=/usr --mandir=\$${prefix}/share/man \ - --infodir=\$${prefix}/share/info \ + --infodir=\$${prefix}/share/info --enable-exynos-experimental-api \ --enable-static=yes $(confflags) \ CFLAGS="$(CFLAGS)" \ LDFLAGS="$(CFLAGS)" diff --git a/exynos/Makefile.am b/exynos/Makefile.am new file mode 100644 index 0000000..e782d34 --- /dev/null +++ b/exynos/Makefile.am @@ -0,0 +1,22 @@ +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/exynos \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/include/drm + +libdrm_exynos_la_LTLIBRARIES = libdrm_exynos.la +libdrm_exynos_ladir = $(libdir) +libdrm_exynos_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_exynos_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ + +libdrm_exynos_la_SOURCES = exynos_drm.c + +libdrm_exynoscommonincludedir = ${includedir}/exynos +libdrm_exynoscommoninclude_HEADERS = exynos_drm.h + +libdrm_exynosincludedir = ${includedir}/libdrm +libdrm_exynosinclude_HEADERS = exynos_drmif.h + +pkgconfigdir = @pkgconfigdir@ +pkgconfig_DATA = libdrm_exynos.pc diff --git a/exynos/exynos_drm.c b/exynos/exynos_drm.c new file mode 100644 index 0000000..dea4d4a --- /dev/null +++ b/exynos/exynos_drm.c @@ -0,0 +1,427 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * + * 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: + * Inki Dae + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include +#include + +#include + +#include "exynos_drm.h" +#include "exynos_drmif.h" + +/* + * Create exynos drm device object. + * + * @fd: file descriptor to exynos drm driver opened. + * + * if true, return the device object else NULL. + */ +struct exynos_device * exynos_device_create(int fd) +{ + struct exynos_device *dev; + + dev = calloc(sizeof(*dev), 1); + if (!dev) { + fprintf(stderr, "failed to create device[%s].\n", + strerror(errno)); + return NULL; + } + + dev->fd = fd; + + return dev; +} + +/* + * Destroy exynos drm device object + * + * @dev: exynos drm device object. + */ +void exynos_device_destroy(struct exynos_device *dev) +{ + free(dev); +} + +/* + * Create a exynos buffer object to exynos drm device. + * + * @dev: exynos drm device object. + * @size: user-desired size. + * flags: user-desired memory type. + * user can set one or more types among several types to memory + * allocation and cache attribute types. and as default, + * EXYNOS_BO_NONCONTIG and EXYNOS-BO_NONCACHABLE types would + * be used. + * + * if true, return a exynos buffer object else NULL. + */ +struct exynos_bo * exynos_bo_create(struct exynos_device *dev, + size_t size, uint32_t flags) +{ + struct exynos_bo *bo; + struct drm_exynos_gem_create req = { + .size = size, + .flags = flags, + }; + + if (size == 0) { + fprintf(stderr, "invalid size.\n"); + goto fail; + } + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + fprintf(stderr, "failed to create bo[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->dev = dev; + + if (drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_CREATE, &req)){ + fprintf(stderr, "failed to create gem object[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->handle = req.handle; + bo->size = size; + bo->flags = flags; + + return bo; + +err_free_bo: + free(bo); +fail: + return NULL; +} + +/* + * Get information to gem region allocated. + * + * @dev: exynos drm device object. + * @handle: gem handle to request gem info. + * @size: size to gem object and returned by kernel side. + * @flags: gem flags to gem object and returned by kernel side. + * + * with this function call, you can get flags and size to gem handle + * through bo object. + * + * if true, return 0 else negative. + */ +int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, + size_t *size, uint32_t *flags) +{ + int ret; + struct drm_exynos_gem_info req = { + .handle = handle, + }; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_GET, &req); + if (ret < 0) { + fprintf(stderr, "failed to get gem object information[%s].\n", + strerror(errno)); + return ret; + } + + *size = req.size; + *flags = req.flags; + + return 0; +} + +/* + * Destroy a exynos buffer object. + * + * @bo: a exynos buffer object to be destroyed. + */ +void exynos_bo_destroy(struct exynos_bo *bo) +{ + if (!bo) + return; + + if (bo->vaddr) + munmap(bo->vaddr, bo->size); + + if (bo->handle) { + struct drm_gem_close req = { + .handle = bo->handle, + }; + + drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + } + + free(bo); +} + + +/* + * Get a exynos buffer object from a gem global object name. + * + * @dev: a exynos device object. + * @name: a gem global object name exported by another process. + * + * this interface is used to get a exynos buffer object from a gem + * global object name sent by another process for buffer sharing. + * + * if true, return a exynos buffer object else NULL. + * + */ +struct exynos_bo * exynos_bo_from_name(struct exynos_device *dev, uint32_t name) +{ + struct exynos_bo *bo; + struct drm_gem_open req = { + .name = name, + }; + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + fprintf(stderr, "failed to allocate bo[%s].\n", + strerror(errno)); + return NULL; + } + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + fprintf(stderr, "failed to open gem object[%s].\n", + strerror(errno)); + goto err_free_bo; + } + + bo->dev = dev; + bo->name = name; + bo->handle = req.handle; + + return bo; + +err_free_bo: + free(bo); + return NULL; +} + +/* + * Get a gem global object name from a gem object handle. + * + * @bo: a exynos buffer object including gem handle. + * @name: a gem global object name to be got by kernel driver. + * + * this interface is used to get a gem global object name from a gem object + * handle to a buffer that wants to share it with another process. + * + * if true, return 0 else negative. + */ +int exynos_bo_get_name(struct exynos_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) { + fprintf(stderr, "failed to get gem global name[%s].\n", + strerror(errno)); + return ret; + } + + bo->name = req.name; + } + + *name = bo->name; + + return 0; +} + +uint32_t exynos_bo_handle(struct exynos_bo *bo) +{ + return bo->handle; +} + +/* + * Mmap a buffer to user space. + * + * @bo: a exynos buffer object including a gem object handle to be mmapped + * to user space. + * + * if true, user pointer mmaped else NULL. + */ +void *exynos_bo_map(struct exynos_bo *bo) +{ + if (!bo->vaddr) { + struct exynos_device *dev = bo->dev; + struct drm_exynos_gem_mmap req = { + .handle = bo->handle, + .size = bo->size, + }; + int ret; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_MMAP, &req); + if (ret) { + fprintf(stderr, "failed to mmap[%s].\n", + strerror(errno)); + return NULL; + } + + bo->vaddr = req.mapped; + } + + return bo->vaddr; +} + +/* + * Get a gem handle to user address space. + * + * @dev: a exynos device object. + * @vaddr: user space address to be imported into gem. + * @size: size to user space to be imported into gem. + * @handle: gem handle to gem object imported from user address and + * returned by kernel side. + * + * if true, return 0 else negative. + */ +int exynos_userptr(struct exynos_device *dev, uint64_t vaddr, + size_t size, uint32_t *handle) +{ + int ret; + struct drm_exynos_gem_userptr req = { + .userptr = vaddr, + .size = size, + }; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_GEM_USERPTR, &req); + if (ret) { + fprintf(stderr, "failed to mmap[%s].\n", + strerror(errno)); + return ret; + } + + *handle = req.handle; + return 0; +} + +/* + * Export gem object to dmabuf as file descriptor. + * + * @dev: a exynos device object. + * @handle: gem handle to be exported into dmabuf as file descriptor. + * @fd: file descriptor to dmabuf exported from gem handle and + * returned by kernel side. + * + * if true, return 0 else negative. + */ +int exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, + int *fd) +{ + int ret; + struct drm_prime_handle req = { + .handle = handle, + }; + + ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req); + if (ret) { + fprintf(stderr, "failed to mmap[%s].\n", + strerror(errno)); + return ret; + } + + *fd = req.fd; + return 0; +} + +/* + * Import file descriptor into gem handle. + * + * @dev: a exynos device object. + * @fd: file descriptor exported into dmabuf. + * @handle: gem handle to gem object imported from file descriptor + * and returned by kernel side. + * + * if true, return 0 else negative. + */ +int exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, + uint32_t *handle) +{ + int ret; + struct drm_prime_handle req = { + .fd = fd, + }; + + ret = drmIoctl(dev->fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &req); + if (ret) { + fprintf(stderr, "failed to mmap[%s].\n", + strerror(errno)); + return ret; + } + + *handle = req.handle; + return 0; +} + + + +/* + * Request Wireless Display connection or disconnection. + * + * @dev: a exynos device object. + * @connect: indicate whether connectoin or disconnection request. + * @ext: indicate whether edid data includes extentions data or not. + * @edid: a pointer to edid data from Wireless Display device. + * + * this interface is used to request Virtual Display driver connection or + * disconnection. for this, user should get a edid data from the Wireless + * Display device and then send that data to kernel driver with connection + * request + * + * if true, return 0 else negative. + */ +int exynos_vidi_connection(struct exynos_device *dev, uint32_t connect, + uint32_t ext, void *edid) +{ + struct drm_exynos_vidi_connection req = { + .connection = connect, + .extensions = ext, + .edid = edid, + }; + int ret; + + ret = drmIoctl(dev->fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &req); + if (ret) { + fprintf(stderr, "failed to request vidi connection[%s].\n", + strerror(errno)); + return ret; + } + + return 0; +} diff --git a/exynos/exynos_drm.h b/exynos/exynos_drm.h new file mode 100644 index 0000000..580d0b7 --- /dev/null +++ b/exynos/exynos_drm.h @@ -0,0 +1,481 @@ +/* exynos_drm.h + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * Authors: + * Inki Dae + * Joonyoung Shim + * Seung-Woo Kim + * + * 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 + * VA LINUX SYSTEMS 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. + */ + +#ifndef _EXYNOS_DRM_H_ +#define _EXYNOS_DRM_H_ + +#include "drm.h" + +/** + * User-desired buffer creation information structure. + * + * @size: user-desired memory allocation size. + * - this size value would be page-aligned internally. + * @flags: user request for setting memory type or cache attributes. + * @handle: returned a handle to created gem object. + * - this handle will be set by gem module of kernel side. + */ +struct drm_exynos_gem_create { + uint64_t size; + unsigned int flags; + unsigned int handle; +}; + +/** + * A structure for getting buffer offset. + * + * @handle: a pointer to gem object created. + * @pad: just padding to be 64-bit aligned. + * @offset: relatived offset value of the memory region allocated. + * - this value should be set by user. + */ +struct drm_exynos_gem_map_off { + unsigned int handle; + unsigned int pad; + uint64_t offset; +}; + +/** + * A structure for mapping buffer. + * + * @handle: a handle to gem object created. + * @pad: just padding to be 64-bit aligned. + * @size: memory size to be mapped. + * @mapped: having user virtual address mmaped. + * - this variable would be filled by exynos gem module + * of kernel side with user virtual address which is allocated + * by do_mmap(). + */ +struct drm_exynos_gem_mmap { + unsigned int handle; + unsigned int pad; + uint64_t size; + uint64_t mapped; +}; + +/** + * User-requested user space importing structure + * + * @userptr: user space address allocated by malloc. + * @size: size to the buffer allocated by malloc. + * @flags: indicate user-desired cache attribute to map the allocated buffer + * to kernel space. + * @handle: a returned handle to created gem object. + * - this handle will be set by gem module of kernel side. + */ +struct drm_exynos_gem_userptr { + uint64_t userptr; + uint64_t size; + unsigned int flags; + unsigned int handle; +}; + +/** + * A structure to gem information. + * + * @handle: a handle to gem object created. + * @flags: flag value including memory type and cache attribute and + * this value would be set by driver. + * @size: size to memory region allocated by gem and this size would + * be set by driver. + */ +struct drm_exynos_gem_info { + unsigned int handle; + unsigned int flags; + uint64_t size; +}; + +/** + * A structure to userptr limited information. + * + * @userptr_limit: maximum size to userptr buffer. + * the buffer could be allocated by unprivileged user using malloc() + * and the size of the buffer would be limited as userptr_limit value. + * @pad: just padding to be 64-bit aligned. + */ +struct drm_exynos_user_limit { + unsigned int userptr_limit; + unsigned int pad; +}; + +/** + * A structure for user connection request of virtual display. + * + * @connection: indicate whether doing connetion or not by user. + * @extensions: if this value is 1 then the vidi driver would need additional + * 128bytes edid data. + * @edid: the edid data pointer from user side. + */ +struct drm_exynos_vidi_connection { + unsigned int connection; + unsigned int extensions; + uint64_t *edid; +}; + +/** + * A structure for ump. + * + * @gem_handle: a pointer to gem object created. + * @secure_id: ump secure id and this value would be filled + * by kernel side. + */ +struct drm_exynos_gem_ump { + unsigned int gem_handle; + unsigned int secure_id; +}; + + +/* temporary codes for legacy fimc and mfc drivers. */ + +/** + * A structure for getting physical address corresponding to a gem handle. + */ +struct drm_exynos_gem_get_phy { + unsigned int gem_handle; + unsigned int pad; + uint64_t size; + uint64_t phy_addr; +}; + +/** + * A structure for importing physical memory to a gem. + */ +struct drm_exynos_gem_phy_imp { + uint64_t phy_addr; + uint64_t size; + unsigned int gem_handle; + unsigned int pad; +}; + +/* indicate cache units. */ +enum e_drm_exynos_gem_cache_sel { + EXYNOS_DRM_L1_CACHE = 1 << 0, + EXYNOS_DRM_L2_CACHE = 1 << 1, + EXYNOS_DRM_ALL_CORES = 1 << 2, + EXYNOS_DRM_ALL_CACHES = EXYNOS_DRM_L1_CACHE | + EXYNOS_DRM_L2_CACHE, + EXYNOS_DRM_ALL_CACHES_CORES = EXYNOS_DRM_L1_CACHE | + EXYNOS_DRM_L2_CACHE | + EXYNOS_DRM_ALL_CORES, + EXYNOS_DRM_CACHE_SEL_MASK = EXYNOS_DRM_ALL_CACHES_CORES +}; + +/* indicate cache operation types. */ +enum e_drm_exynos_gem_cache_op { + EXYNOS_DRM_CACHE_INV_ALL = 1 << 3, + EXYNOS_DRM_CACHE_INV_RANGE = 1 << 4, + EXYNOS_DRM_CACHE_CLN_ALL = 1 << 5, + EXYNOS_DRM_CACHE_CLN_RANGE = 1 << 6, + EXYNOS_DRM_CACHE_FSH_ALL = EXYNOS_DRM_CACHE_INV_ALL | + EXYNOS_DRM_CACHE_CLN_ALL, + EXYNOS_DRM_CACHE_FSH_RANGE = EXYNOS_DRM_CACHE_INV_RANGE | + EXYNOS_DRM_CACHE_CLN_RANGE, + EXYNOS_DRM_CACHE_OP_MASK = EXYNOS_DRM_CACHE_FSH_ALL | + EXYNOS_DRM_CACHE_FSH_RANGE +}; + +/* memory type definitions. */ +enum e_drm_exynos_gem_mem_type { + /* Physically Continuous memory and used as default. */ + EXYNOS_BO_CONTIG = 0 << 0, + /* Physically Non-Continuous memory. */ + EXYNOS_BO_NONCONTIG = 1 << 0, + /* non-cachable mapping and used as default. */ + EXYNOS_BO_NONCACHABLE = 0 << 1, + /* cachable mapping. */ + EXYNOS_BO_CACHABLE = 1 << 1, + /* write-combine mapping. */ + EXYNOS_BO_WC = 1 << 2, + /* user space memory allocated by malloc. */ + EXYNOS_BO_USERPTR = 1 << 3, + EXYNOS_BO_MASK = EXYNOS_BO_NONCONTIG | EXYNOS_BO_CACHABLE | + EXYNOS_BO_WC | EXYNOS_BO_USERPTR +}; + +/** + * A structure for cache operation. + * + * @usr_addr: user space address. + * P.S. it SHOULD BE user space. + * @size: buffer size for cache operation. + * @flags: select cache unit and cache operation. + * @gem_handle: a handle to a gem object. + * this gem handle is needed for cache range operation to L2 cache. + */ +struct drm_exynos_gem_cache_op { + uint64_t usr_addr; + unsigned int size; + unsigned int flags; + unsigned int gem_handle; +}; + +struct drm_exynos_g2d_get_ver { + __u32 major; + __u32 minor; +}; + +struct drm_exynos_g2d_cmd { + __u32 offset; + __u32 data; +}; + +enum drm_exynos_g2d_event_type { + G2D_EVENT_NOT, + G2D_EVENT_NONSTOP, + G2D_EVENT_STOP, /* not yet */ +}; + +struct drm_exynos_g2d_set_cmdlist { + struct drm_exynos_g2d_cmd *cmd; + struct drm_exynos_g2d_cmd *cmd_gem; + __u32 cmd_nr; + __u32 cmd_gem_nr; + + /* for g2d event */ + __u64 user_data; + __u32 event_type; + __u32 reserved; +}; + +struct drm_exynos_g2d_exec { + __u32 async; + __u32 reserved; +}; + +/* definition of operations types */ +enum drm_exynos_ops_id { + EXYNOS_DRM_OPS_SRC, + EXYNOS_DRM_OPS_DST, + EXYNOS_DRM_OPS_MAX +}; + +/* definition of size */ +struct drm_exynos_sz { + __u32 hsize; + __u32 vsize; +}; + +/* definition of position */ +struct drm_exynos_pos { + __u32 x; + __u32 y; + __u32 w; + __u32 h; +}; + +/* definition of flip */ +enum drm_exynos_flip { + EXYNOS_DRM_FLIP_NONE = (0 << 0), + EXYNOS_DRM_FLIP_VERTICAL = (1 << 0), + EXYNOS_DRM_FLIP_HORIZONTAL = (1 << 1), +}; + +/* definition of rotation degree */ +enum drm_exynos_degree { + EXYNOS_DRM_DEGREE_0, + EXYNOS_DRM_DEGREE_90, + EXYNOS_DRM_DEGREE_180, + EXYNOS_DRM_DEGREE_270, +}; + +/* definition of planar */ +enum drm_exynos_planer { + EXYNOS_DRM_PLANAR_Y, + EXYNOS_DRM_PLANAR_CB, + EXYNOS_DRM_PLANAR_CR, + EXYNOS_DRM_PLANAR_MAX +}; + +/** + * A structure for ipp config. + * + * @ops_id: property of operation directions. + * @flip: property of mirror, flip. + * @degree: property of rotation degree. + * @fmt: property of image format. + * @sz: property of image size. + * @pos: property of image position(src-cropped,dst-scaler). + */ +struct drm_exynos_ipp_config { + enum drm_exynos_ops_id ops_id; + enum drm_exynos_flip flip; + enum drm_exynos_degree degree; + __u32 fmt; + struct drm_exynos_sz sz; + struct drm_exynos_pos pos; +}; + +/** + * A structure for ipp property. + * + * @config: source, destination config. + */ +struct drm_exynos_ipp_property { + struct drm_exynos_ipp_config config[EXYNOS_DRM_OPS_MAX]; +}; + +/* command of ipp operations */ +enum drm_exynos_ipp_cmd { + IPP_CMD_NONE, + IPP_CMD_M2M, + IPP_CMD_WB, + IPP_CMD_OUT, + IPP_CMD_MAX +}; + +/* definition of buffer control */ +enum drm_exynos_ipp_buf_ctrl { + IPP_BUF_CTRL_MAP, + IPP_BUF_CTRL_UNMAP, + IPP_BUF_CTRL_QUEUE, + IPP_BUF_CTRL_DEQUEUE +}; + +/** + * A structure for ipp buffer operations. + * + * @ops_id: operation directions. + * @ctrl: buffer control. + * @id: index of buffer. + * @handle: Y, Cb, Cr each planar handle. + * @user_data: user data. + */ +struct drm_exynos_ipp_buf { + enum drm_exynos_ops_id ops_id; + enum drm_exynos_ipp_buf_ctrl buf_ctrl; + __u32 id; + __u32 handle[EXYNOS_DRM_PLANAR_MAX]; + __u64 user_data; +}; + +/** + * A structure for ipp start/stop operations. + * + * @cmd: command id. + * @use: use ipp device. + */ +struct drm_exynos_ipp_ctrl { + enum drm_exynos_ipp_cmd cmd; + __u32 use; +}; + +#define DRM_EXYNOS_GEM_CREATE 0x00 +#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01 +#define DRM_EXYNOS_GEM_MMAP 0x02 +#define DRM_EXYNOS_GEM_USERPTR 0x03 +#define DRM_EXYNOS_GEM_GET 0x04 +#define DRM_EXYNOS_USER_LIMIT 0x05 +#define DRM_EXYNOS_VIDI_CONNECTION 0x07 + +/* temporary ioctl command. */ +#define DRM_EXYNOS_GEM_EXPORT_UMP 0x10 +#define DRM_EXYNOS_GEM_CACHE_OP 0x12 + +#define DRM_EXYNOS_GEM_GET_PHY 0x13 +#define DRM_EXYNOS_GEM_PHY_IMP 0x14 + +/* G2D */ +#define DRM_EXYNOS_G2D_GET_VER 0x20 +#define DRM_EXYNOS_G2D_SET_CMDLIST 0x21 +#define DRM_EXYNOS_G2D_EXEC 0x22 + +/* IPP - Image Post Processing */ +#define DRM_EXYNOS_IPP_PROPERTY 0x30 +#define DRM_EXYNOS_IPP_BUF 0x31 +#define DRM_EXYNOS_IPP_CTRL 0x32 + +#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) + +#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off) + +#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap) + +#define DRM_IOCTL_EXYNOS_GEM_USERPTR DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_USERPTR, struct drm_exynos_gem_userptr) + +#define DRM_IOCTL_EXYNOS_GEM_GET DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_GET, struct drm_exynos_gem_info) + +#define DRM_IOCTL_EXYNOS_USER_LIMIT DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_USER_LIMIT, struct drm_exynos_user_limit) + +#define DRM_IOCTL_EXYNOS_GEM_EXPORT_UMP DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_EXPORT_UMP, struct drm_exynos_gem_ump) + +#define DRM_IOCTL_EXYNOS_GEM_CACHE_OP DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_CACHE_OP, struct drm_exynos_gem_cache_op) + +/* temporary ioctl command. */ +#define DRM_IOCTL_EXYNOS_GEM_GET_PHY DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_GET_PHY, struct drm_exynos_gem_get_phy) +#define DRM_IOCTL_EXYNOS_GEM_PHY_IMP DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_GEM_PHY_IMP, struct drm_exynos_gem_phy_imp) + +#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) + +#define DRM_IOCTL_EXYNOS_G2D_GET_VER DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_GET_VER, struct drm_exynos_g2d_get_ver) +#define DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_SET_CMDLIST, struct drm_exynos_g2d_set_cmdlist) +#define DRM_IOCTL_EXYNOS_G2D_EXEC DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_G2D_EXEC, struct drm_exynos_g2d_exec) + +#define DRM_IOCTL_EXYNOS_IPP_PROPERTY DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_IPP_PROPERTY, struct drm_exynos_ipp_property) +#define DRM_IOCTL_EXYNOS_IPP_BUF DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_IPP_BUF, struct drm_exynos_ipp_buf) +#define DRM_IOCTL_EXYNOS_IPP_CTRL DRM_IOWR(DRM_COMMAND_BASE + \ + DRM_EXYNOS_IPP_CTRL, struct drm_exynos_ipp_ctrl) + +/* EXYNOS specific events */ +#define DRM_EXYNOS_G2D_EVENT 0x80000000 +#define DRM_EXYNOS_IPP_EVENT 0x80000001 + +struct drm_exynos_g2d_event { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 cmdlist_no; + __u32 reserved; +}; + +struct drm_exynos_ipp_event { + struct drm_event base; + __u64 user_data; + __u32 tv_sec; + __u32 tv_usec; + __u32 buf_idx; + __u32 reserved; +}; + +#endif diff --git a/exynos/exynos_drmif.h b/exynos/exynos_drmif.h new file mode 100644 index 0000000..24d2f64 --- /dev/null +++ b/exynos/exynos_drmif.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co., Ltd. + * + * 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: + * Inki Dae + */ + +#ifndef EXYNOS_DRMIF_H_ +#define EXYNOS_DRMIF_H_ + +#include +#include +#include "exynos_drm.h" + +struct exynos_device { + int fd; +}; + +/* + * Exynos Buffer Object structure. + * + * @dev: exynos device object allocated. + * @handle: a gem handle to gem object created. + * @flags: indicate memory allocation and cache attribute types. + * @fd: file descriptor exported into dmabuf. + * @size: size to the buffer created. + * @vaddr: user space address to a gem buffer mmaped. + * @name: a gem global handle from flink request. + */ +struct exynos_bo { + struct exynos_device *dev; + uint32_t handle; + uint32_t flags; + int fd; + size_t size; + void *vaddr; + uint32_t name; +}; + +/* + * device related functions: + */ +struct exynos_device * exynos_device_create(int fd); +void exynos_device_destroy(struct exynos_device *dev); + +/* + * buffer-object related functions: + */ +struct exynos_bo * exynos_bo_create(struct exynos_device *dev, + size_t size, uint32_t flags); +int exynos_bo_get_info(struct exynos_device *dev, uint32_t handle, + size_t *size, uint32_t *flags); +void exynos_bo_destroy(struct exynos_bo *bo); +struct exynos_bo * exynos_bo_from_name(struct exynos_device *dev, uint32_t name); +int exynos_bo_get_name(struct exynos_bo *bo, uint32_t *name); +uint32_t exynos_bo_handle(struct exynos_bo *bo); +void * exynos_bo_map(struct exynos_bo *bo); +int exynos_userptr(struct exynos_device *dev, uint64_t vaddr, + size_t size, uint32_t *handle); +int exynos_prime_handle_to_fd(struct exynos_device *dev, uint32_t handle, + int *fd); +int exynos_prime_fd_to_handle(struct exynos_device *dev, int fd, + uint32_t *handle); + +/* + * Virtual Display related functions: + */ +int exynos_vidi_connection(struct exynos_device *dev, uint32_t connect, + uint32_t ext, void *edid); + +#endif /* EXYNOS_DRMIF_H_ */ diff --git a/exynos/libdrm_exynos.pc.in b/exynos/libdrm_exynos.pc.in new file mode 100644 index 0000000..5ce9118 --- /dev/null +++ b/exynos/libdrm_exynos.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_exynos +Description: Userspace interface to exynos kernel DRM services +Version: 0.6 +Libs: -L${libdir} -ldrm_exynos +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/exynos +Requires.private: libdrm diff --git a/include/drm/Makefile.am b/include/drm/Makefile.am old mode 100755 new mode 100644 index 965d4e5..2923ab4 --- a/include/drm/Makefile.am +++ b/include/drm/Makefile.am @@ -36,8 +36,8 @@ klibdrminclude_HEADERS = \ savage_drm.h \ sis_drm.h \ via_drm.h \ - mach64_drm.h \ - exynos_drm.h + mach64_drm.h + if HAVE_VMWGFX klibdrminclude_HEADERS += vmwgfx_drm.h diff --git a/include/drm/drm.h b/include/drm/drm.h index 8adb9d5..5e6cd29 100644 --- a/include/drm/drm.h +++ b/include/drm/drm.h @@ -618,6 +618,17 @@ struct drm_get_cap { __u64 value; }; +#define DRM_CLOEXEC O_CLOEXEC +struct drm_prime_handle { + __u32 handle; + + /** Flags.. only applicable for handle->fd */ + __u32 flags; + + /** Returned dmabuf file descriptor */ + __s32 fd; +}; + #include "drm_mode.h" #define DRM_IOCTL_BASE 'd' @@ -686,6 +697,9 @@ struct drm_get_cap { #define DRM_IOCTL_SG_ALLOC DRM_IOWR(0x38, struct drm_scatter_gather) #define DRM_IOCTL_SG_FREE DRM_IOW( 0x39, struct drm_scatter_gather) +#define DRM_IOCTL_PRIME_HANDLE_TO_FD DRM_IOWR(0x2d, struct drm_prime_handle) +#define DRM_IOCTL_PRIME_FD_TO_HANDLE DRM_IOWR(0x2e, struct drm_prime_handle) + #define DRM_IOCTL_WAIT_VBLANK DRM_IOWR(0x3a, union drm_wait_vblank) #define DRM_IOCTL_UPDATE_DRAW DRM_IOW(0x3f, struct drm_update_draw) @@ -717,6 +731,8 @@ struct drm_get_cap { #define DRM_IOCTL_MODE_GETPLANE DRM_IOWR(0xB6, struct drm_mode_get_plane) #define DRM_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct drm_mode_set_plane) #define DRM_IOCTL_MODE_ADDFB2 DRM_IOWR(0xB8, struct drm_mode_fb_cmd2) +#define DRM_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xB9, struct drm_mode_obj_get_properties) +#define DRM_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xBA, struct drm_mode_obj_set_property) /** * Device specific ioctls should only be in their respective headers diff --git a/include/drm/drm_fourcc.h b/include/drm/drm_fourcc.h index b1107cb..85facb0 100644 --- a/include/drm/drm_fourcc.h +++ b/include/drm/drm_fourcc.h @@ -24,10 +24,10 @@ #ifndef DRM_FOURCC_H #define DRM_FOURCC_H -#include +#include -#define fourcc_code(a,b,c,d) ((__u32)(a) | ((__u32)(b) << 8) | \ - ((__u32)(c) << 16) | ((__u32)(d) << 24)) +#define fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ + ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) #define DRM_FORMAT_BIG_ENDIAN (1<<31) /* format is big endian instead of little endian */ diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h old mode 100755 new mode 100644 index 0a76ff9..c3f374d --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -162,6 +162,7 @@ struct drm_mode_get_plane_res { #define DRM_MODE_ENCODER_TMDS 2 #define DRM_MODE_ENCODER_LVDS 3 #define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 struct drm_mode_get_encoder { __u32 encoder_id; @@ -199,6 +200,7 @@ struct drm_mode_get_encoder { #define DRM_MODE_CONNECTOR_HDMIB 12 #define DRM_MODE_CONNECTOR_TV 13 #define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 struct drm_mode_get_connector { @@ -226,6 +228,7 @@ struct drm_mode_get_connector { #define DRM_MODE_PROP_IMMUTABLE (1<<2) #define DRM_MODE_PROP_ENUM (1<<3) /* enumerated type with text strings */ #define DRM_MODE_PROP_BLOB (1<<4) +#define DRM_MODE_PROP_BITMASK (1<<5) /* bitmask of enumerated types */ struct drm_mode_property_enum { __u64 value; @@ -250,6 +253,30 @@ struct drm_mode_connector_set_property { __u32 connector_id; }; +#define DRM_MODE_OBJECT_CRTC 0xcccccccc +#define DRM_MODE_OBJECT_CONNECTOR 0xc0c0c0c0 +#define DRM_MODE_OBJECT_ENCODER 0xe0e0e0e0 +#define DRM_MODE_OBJECT_MODE 0xdededede +#define DRM_MODE_OBJECT_PROPERTY 0xb0b0b0b0 +#define DRM_MODE_OBJECT_FB 0xfbfbfbfb +#define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb +#define DRM_MODE_OBJECT_PLANE 0xeeeeeeee + +struct drm_mode_obj_get_properties { + __u64 props_ptr; + __u64 prop_values_ptr; + __u32 count_props; + __u32 obj_id; + __u32 obj_type; +}; + +struct drm_mode_obj_set_property { + __u64 value; + __u32 prop_id; + __u32 obj_id; + __u32 obj_type; +}; + struct drm_mode_get_blob { __u32 blob_id; __u32 length; @@ -341,7 +368,7 @@ struct drm_mode_mode_cmd { #define DRM_MODE_CURSOR_MOVE (1<<1) /* - * depending on the value in flags different members are used. + * depending on the value in flags diffrent members are used. * * CURSOR_BO uses * crtc @@ -410,31 +437,31 @@ struct drm_mode_crtc_page_flip { /* create a dumb scanout buffer */ struct drm_mode_create_dumb { - uint32_t height; - uint32_t width; - uint32_t bpp; - uint32_t flags; - /* handle, pitch, size will be returned */ - uint32_t handle; - uint32_t pitch; - uint64_t size; + __u32 height; + __u32 width; + __u32 bpp; + __u32 flags; + /* handle, pitch, size will be returned */ + __u32 handle; + __u32 pitch; + __u64 size; }; /* set up for mmap of a dumb scanout buffer */ struct drm_mode_map_dumb { - /** Handle for the object being mapped. */ - __u32 handle; - __u32 pad; - /** - * Fake offset to use for subsequent mmap call - * - * This is a fixed-size type for 32/64 compatibility. - */ - __u64 offset; + /** Handle for the object being mapped. */ + __u32 handle; + __u32 pad; + /** + * Fake offset to use for subsequent mmap call + * + * This is a fixed-size type for 32/64 compatibility. + */ + __u64 offset; }; struct drm_mode_destroy_dumb { - uint32_t handle; + __u32 handle; }; #endif diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h deleted file mode 100755 index 99e64a8..0000000 --- a/include/drm/exynos_drm.h +++ /dev/null @@ -1,204 +0,0 @@ -/* exynos_drm.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Authors: - * Inki Dae - * Joonyoung Shim - * Seung-Woo Kim - * - * 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 - * VA LINUX SYSTEMS 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. - */ - -#ifndef _EXYNOS_DRM_H_ -#define _EXYNOS_DRM_H_ - -/** - * User-desired buffer creation information structure. - * - * @size: user-desired memory allocation size. - * - this size value would be page-aligned internally. - * @flags: user request for setting memory type or cache attributes. - * @handle: returned a handle to created gem object. - * - this handle will be set by gem module of kernel side. - */ -struct drm_exynos_gem_create { - uint64_t size; - unsigned int flags; - unsigned int handle; -}; - -/** - * A structure for getting buffer offset. - * - * @handle: a pointer to gem object created. - * @pad: just padding to be 64-bit aligned. - * @offset: relatived offset value of the memory region allocated. - * - this value should be set by user. - */ -struct drm_exynos_gem_map_off { - unsigned int handle; - unsigned int pad; - uint64_t offset; -}; - -/** - * A structure for mapping buffer. - * - * @handle: a handle to gem object created. - * @pad: just padding to be 64-bit aligned. - * @size: memory size to be mapped. - * @mapped: having user virtual address mmaped. - * - this variable would be filled by exynos gem module - * of kernel side with user virtual address which is allocated - * by do_mmap(). - */ -struct drm_exynos_gem_mmap { - unsigned int handle; - unsigned int pad; - uint64_t size; - uint64_t mapped; -}; - -/** - * A structure for user connection request of virtual display. - * - * @connection: indicate whether doing connetion or not by user. - * @extensions: if this value is 1 then the vidi driver would need additional - * 128bytes edid data. - * @pad: just padding to be 64-bit aligned. - * @edid: the edid data pointer from user side. - */ -struct drm_exynos_vidi_connection { - unsigned int connection; - unsigned int extensions; - unsigned int pad; - void *edid; -}; - -/** - * A structure for ump. - * - * @gem_handle: a pointer to gem object created. - * @secure_id: ump secure id and this value would be filled - * by kernel side. - */ -struct drm_exynos_gem_ump { - unsigned int gem_handle; - unsigned int secure_id; -}; - - -/* temporary codes for legacy fimc and mfc drivers. */ - -/** - * A structure for getting physical address corresponding to a gem handle. - */ -struct drm_exynos_gem_get_phy { - unsigned int gem_handle; - unsigned int pad; - uint64_t size; - uint64_t phy_addr; -}; - -/** - * A structure for importing physical memory to a gem. - */ -struct drm_exynos_gem_phy_imp { - uint64_t phy_addr; - uint64_t size; - unsigned int gem_handle; - unsigned int pad; -}; - -/* indicate cache units. */ -enum e_drm_exynos_gem_cache_sel { - EXYNOS_DRM_L1_CACHE = 1, - EXYNOS_DRM_L2_CACHE = 2, - EXYNOS_DRM_ALL_CACHE = 3 -}; - -/* indicate cache operation types. */ -enum e_drm_exynos_gem_cache_op { - EXYNOS_DRM_CACHE_INV = 4, - EXYNOS_DRM_CACHE_CLN = 8, - EXYNOS_DRM_CACHE_FSH = 0xC -}; - -/** - * A structure for cache operation. - * - * @usr_addr: user space address. - * P.S. it SHOULD BE user space. - * @size: buffer size for cache operation. - * @flags: select cache unit and cache operation. - */ -struct drm_exynos_gem_cache_op { - uint64_t usr_addr; - unsigned int size; - unsigned int flags; -}; - -struct drm_exynos_plane_set_zpos { - __u32 plane_id; - __s32 zpos; -}; - -#define DRM_EXYNOS_GEM_CREATE 0x00 -#define DRM_EXYNOS_GEM_MAP_OFFSET 0x01 -#define DRM_EXYNOS_GEM_MMAP 0x02 -/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ -#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 -#define DRM_EXYNOS_VIDI_CONNECTION 0x07 - -/* temporary ioctl command. */ -#define DRM_EXYNOS_GEM_EXPORT_UMP 0x10 -#define DRM_EXYNOS_GEM_CACHE_OP 0x12 - -#define DRM_EXYNOS_GEM_GET_PHY 0x13 -#define DRM_EXYNOS_GEM_PHY_IMP 0x14 - -#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) - -#define DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_MAP_OFFSET, struct drm_exynos_gem_map_off) - -#define DRM_IOCTL_EXYNOS_GEM_MMAP DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_MMAP, struct drm_exynos_gem_mmap) - -#define DRM_IOCTL_EXYNOS_GEM_EXPORT_UMP DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_EXPORT_UMP, struct drm_exynos_gem_ump) - -#define DRM_IOCTL_EXYNOS_GEM_CACHE_OP DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_CACHE_OP, struct drm_exynos_gem_cache_op) - -/* temporary ioctl command. */ -#define DRM_IOCTL_EXYNOS_GEM_GET_PHY DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_GET_PHY, struct drm_exynos_gem_get_phy) -#define DRM_IOCTL_EXYNOS_GEM_PHY_IMP DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_GEM_PHY_IMP, struct drm_exynos_gem_phy_imp) - -#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos) - -#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \ - DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection) - -#endif diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h index adc2392..4931107 100644 --- a/include/drm/i915_drm.h +++ b/include/drm/i915_drm.h @@ -33,6 +33,7 @@ * subject to backwards-compatibility constraints. */ + /* Each region is a minimum of 16k, and there are at most 255 of them. */ #define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use @@ -189,6 +190,9 @@ typedef struct _drm_i915_sarea { #define DRM_I915_OVERLAY_PUT_IMAGE 0x27 #define DRM_I915_OVERLAY_ATTRS 0x28 #define DRM_I915_GEM_EXECBUFFER2 0x29 +#define DRM_I915_GET_SPRITE_COLORKEY 0x2a +#define DRM_I915_SET_SPRITE_COLORKEY 0x2b +#define DRM_I915_GEM_WAIT 0x2c #define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t) #define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH) @@ -228,8 +232,11 @@ typedef struct _drm_i915_sarea { #define DRM_IOCTL_I915_GEM_GET_APERTURE DRM_IOR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture) #define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_i915_get_pipe_from_crtc_id) #define DRM_IOCTL_I915_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_MADVISE, struct drm_i915_gem_madvise) -#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_IOCTL_I915_OVERLAY_ATTRS, struct drm_intel_overlay_put_image) +#define DRM_IOCTL_I915_OVERLAY_PUT_IMAGE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_OVERLAY_PUT_IMAGE, struct drm_intel_overlay_put_image) #define DRM_IOCTL_I915_OVERLAY_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs) +#define DRM_IOCTL_I915_SET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GET_SPRITE_COLORKEY DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey) +#define DRM_IOCTL_I915_GEM_WAIT DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GEM_WAIT, struct drm_i915_gem_wait) /* Allow drivers to submit batchbuffers directly to hardware, relying * on the security mechanisms provided by hardware. @@ -282,6 +289,10 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_COHERENT_RINGS 13 #define I915_PARAM_HAS_EXEC_CONSTANTS 14 #define I915_PARAM_HAS_RELAXED_DELTA 15 +#define I915_PARAM_HAS_GEN7_SOL_RESET 16 +#define I915_PARAM_HAS_LLC 17 +#define I915_PARAM_HAS_ALIASING_PPGTT 18 +#define I915_PARAM_HAS_WAIT_TIMEOUT 19 typedef struct drm_i915_getparam { int param; @@ -644,6 +655,9 @@ struct drm_i915_gem_execbuffer2 { __u64 rsvd2; }; +/** Resets the SO write offset registers for transform feedback on gen7. */ +#define I915_EXEC_GEN7_SOL_RESET (1<<8) + struct drm_i915_gem_pin { /** Handle of the buffer to be pinned. */ __u32 handle; @@ -835,4 +849,44 @@ struct drm_intel_overlay_attrs { __u32 gamma5; }; +/* + * Intel sprite handling + * + * Color keying works with a min/mask/max tuple. Both source and destination + * color keying is allowed. + * + * Source keying: + * Sprite pixels within the min & max values, masked against the color channels + * specified in the mask field, will be transparent. All other pixels will + * be displayed on top of the primary plane. For RGB surfaces, only the min + * and mask fields will be used; ranged compares are not allowed. + * + * Destination keying: + * Primary plane pixels that match the min value, masked against the color + * channels specified in the mask field, will be replaced by corresponding + * pixels from the sprite plane. + * + * Note that source & destination keying are exclusive; only one can be + * active on a given plane. + */ + +#define I915_SET_COLORKEY_NONE (1<<0) /* disable color key matching */ +#define I915_SET_COLORKEY_DESTINATION (1<<1) +#define I915_SET_COLORKEY_SOURCE (1<<2) +struct drm_intel_sprite_colorkey { + __u32 plane_id; + __u32 min_value; + __u32 channel_mask; + __u32 max_value; + __u32 flags; +}; + +struct drm_i915_gem_wait { + /** Handle of BO we shall wait on */ + __u32 bo_handle; + __u32 flags; + /** Number of nanoseconds to wait, Returns time remaining. */ + __s64 timeout_ns; +}; + #endif /* _I915_DRM_H_ */ diff --git a/include/drm/radeon_drm.h b/include/drm/radeon_drm.h index 3b762d6..00d66b3 100644 --- a/include/drm/radeon_drm.h +++ b/include/drm/radeon_drm.h @@ -802,13 +802,23 @@ struct drm_radeon_gem_create { uint32_t flags; }; -#define RADEON_TILING_MACRO 0x1 -#define RADEON_TILING_MICRO 0x2 -#define RADEON_TILING_SWAP_16BIT 0x4 -#define RADEON_TILING_SWAP_32BIT 0x8 -#define RADEON_TILING_SURFACE 0x10 /* this object requires a surface - * when mapped - i.e. front buffer */ -#define RADEON_TILING_MICRO_SQUARE 0x20 +#define RADEON_TILING_MACRO 0x1 +#define RADEON_TILING_MICRO 0x2 +#define RADEON_TILING_SWAP_16BIT 0x4 +#define RADEON_TILING_SWAP_32BIT 0x8 +/* this object requires a surface when mapped - i.e. front buffer */ +#define RADEON_TILING_SURFACE 0x10 +#define RADEON_TILING_MICRO_SQUARE 0x20 +#define RADEON_TILING_EG_BANKW_SHIFT 8 +#define RADEON_TILING_EG_BANKW_MASK 0xf +#define RADEON_TILING_EG_BANKH_SHIFT 12 +#define RADEON_TILING_EG_BANKH_MASK 0xf +#define RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT 16 +#define RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK 0xf +#define RADEON_TILING_EG_TILE_SPLIT_SHIFT 24 +#define RADEON_TILING_EG_TILE_SPLIT_MASK 0xf +#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT 28 +#define RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK 0xf struct drm_radeon_gem_set_tiling { uint32_t handle; diff --git a/intel/.gitignore b/intel/.gitignore new file mode 100644 index 0000000..528b408 --- /dev/null +++ b/intel/.gitignore @@ -0,0 +1 @@ +test_decode diff --git a/intel/Makefile.am b/intel/Makefile.am index 7a44aaf..dc01a96 100644 --- a/intel/Makefile.am +++ b/intel/Makefile.am @@ -28,24 +28,55 @@ AM_CFLAGS = \ -I$(top_srcdir)/intel \ $(PTHREADSTUBS_CFLAGS) \ $(PCIACCESS_CFLAGS) \ + $(VALGRIND_CFLAGS) \ -I$(top_srcdir)/include/drm libdrm_intel_la_LTLIBRARIES = libdrm_intel.la libdrm_intel_ladir = $(libdir) libdrm_intel_la_LDFLAGS = -version-number 1:0:0 -no-undefined -libdrm_intel_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ @PCIACCESS_LIBS@ @CLOCK_LIB@ +libdrm_intel_la_LIBADD = ../libdrm.la \ + @PTHREADSTUBS_LIBS@ \ + @PCIACCESS_LIBS@ \ + @CLOCK_LIB@ libdrm_intel_la_SOURCES = \ intel_bufmgr.c \ intel_bufmgr_priv.h \ intel_bufmgr_fake.c \ intel_bufmgr_gem.c \ + intel_decode.c \ intel_chipset.h \ mm.c \ mm.h +intel_bufmgr_gem_o_CFLAGS = $(AM_CFLAGS) -c99 + libdrm_intelincludedir = ${includedir}/libdrm libdrm_intelinclude_HEADERS = intel_bufmgr.h \ + intel_aub.h \ intel_debug.h +# This may be interesting even outside of "make check", due to the -dump option. +noinst_PROGRAMS = test_decode + +BATCHES = \ + tests/gen4-3d.batch \ + tests/gm45-3d.batch \ + tests/gen5-3d.batch \ + tests/gen6-3d.batch \ + tests/gen7-2d-copy.batch \ + tests/gen7-3d.batch + +TESTS = \ + $(BATCHES:.batch=.batch.sh) + +EXTRA_DIST = \ + $(BATCHES) \ + $(BATCHES:.batch=.batch.sh) \ + $(BATCHES:.batch=.batch-ref.txt) \ + $(BATCHES:.batch=.batch-ref.txt) \ + tests/test-batch.sh + +test_decode_LDADD = libdrm_intel.la + pkgconfig_DATA = libdrm_intel.pc diff --git a/intel/intel_aub.h b/intel/intel_aub.h new file mode 100644 index 0000000..a36fd53 --- /dev/null +++ b/intel/intel_aub.h @@ -0,0 +1,123 @@ +/* + * Copyright © 2010 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: + * Eric Anholt + * + */ + +/** @file intel_aub.h + * + * The AUB file is a file format used by Intel's internal simulation + * and other validation tools. It can be used at various levels by a + * driver to input state to the simulated hardware or a replaying + * debugger. + * + * We choose to dump AUB files using the trace block format for ease + * of implementation -- dump out the blocks of memory as plain blobs + * and insert ring commands to execute the batchbuffer blob. + */ + +#ifndef _INTEL_AUB_H +#define _INTEL_AUB_H + +#define AUB_MI_NOOP (0) +#define AUB_MI_BATCH_BUFFER_START (0x31 << 23) +#define AUB_PIPE_CONTROL (0x7a000002) + +/* DW0: instruction type. */ + +#define CMD_AUB (7 << 29) + +#define CMD_AUB_HEADER (CMD_AUB | (1 << 23) | (0x05 << 16)) +/* DW1 */ +# define AUB_HEADER_MAJOR_SHIFT 24 +# define AUB_HEADER_MINOR_SHIFT 16 + +#define CMD_AUB_TRACE_HEADER_BLOCK (CMD_AUB | (1 << 23) | (0x41 << 16)) +#define CMD_AUB_DUMP_BMP (CMD_AUB | (1 << 23) | (0x9e << 16)) + +/* DW1 */ +#define AUB_TRACE_OPERATION_MASK 0x000000ff +#define AUB_TRACE_OP_COMMENT 0x00000000 +#define AUB_TRACE_OP_DATA_WRITE 0x00000001 +#define AUB_TRACE_OP_COMMAND_WRITE 0x00000002 +#define AUB_TRACE_OP_MMIO_WRITE 0x00000003 +// operation = TRACE_DATA_WRITE, Type +#define AUB_TRACE_TYPE_MASK 0x0000ff00 +#define AUB_TRACE_TYPE_NOTYPE (0 << 8) +#define AUB_TRACE_TYPE_BATCH (1 << 8) +#define AUB_TRACE_TYPE_VERTEX_BUFFER (5 << 8) +#define AUB_TRACE_TYPE_2D_MAP (6 << 8) +#define AUB_TRACE_TYPE_CUBE_MAP (7 << 8) +#define AUB_TRACE_TYPE_VOLUME_MAP (9 << 8) +#define AUB_TRACE_TYPE_1D_MAP (10 << 8) +#define AUB_TRACE_TYPE_CONSTANT_BUFFER (11 << 8) +#define AUB_TRACE_TYPE_CONSTANT_URB (12 << 8) +#define AUB_TRACE_TYPE_INDEX_BUFFER (13 << 8) +#define AUB_TRACE_TYPE_GENERAL (14 << 8) +#define AUB_TRACE_TYPE_SURFACE (15 << 8) + + +// operation = TRACE_COMMAND_WRITE, Type = +#define AUB_TRACE_TYPE_RING_HWB (1 << 8) +#define AUB_TRACE_TYPE_RING_PRB0 (2 << 8) +#define AUB_TRACE_TYPE_RING_PRB1 (3 << 8) +#define AUB_TRACE_TYPE_RING_PRB2 (4 << 8) + +// Address space +#define AUB_TRACE_ADDRESS_SPACE_MASK 0x00ff0000 +#define AUB_TRACE_MEMTYPE_GTT (0 << 16) +#define AUB_TRACE_MEMTYPE_LOCAL (1 << 16) +#define AUB_TRACE_MEMTYPE_NONLOCAL (2 << 16) +#define AUB_TRACE_MEMTYPE_PCI (3 << 16) +#define AUB_TRACE_MEMTYPE_GTT_ENTRY (4 << 16) + +/* DW2 */ +// operation = TRACE_DATA_WRITE, Type = TRACE_DATA_WRITE_GENERAL_STATE +#define AUB_TRACE_GENERAL_STATE_MASK 0x000000ff + +#define AUB_TRACE_VS_STATE 0x00000001 +#define AUB_TRACE_GS_STATE 0x00000002 +#define AUB_TRACE_CL_STATE 0x00000003 +#define AUB_TRACE_SF_STATE 0x00000004 +#define AUB_TRACE_WM_STATE 0x00000005 +#define AUB_TRACE_CC_STATE 0x00000006 +#define AUB_TRACE_CL_VP 0x00000007 +#define AUB_TRACE_SF_VP 0x00000008 +#define AUB_TRACE_CC_VP 0x00000009 +#define AUB_TRACE_SAMPLER_STATE 0x0000000a +#define AUB_TRACE_KERNEL 0x0000000b +#define AUB_TRACE_SCRATCH 0x0000000c +#define AUB_TRACE_SDC 0x0000000d +#define AUB_TRACE_BLEND_STATE 0x00000016 +#define AUB_TRACE_DEPTH_STENCIL_STATE 0x00000017 + +// operation = TRACE_DATA_WRITE, Type = TRACE_DATA_WRITE_SURFACE_STATE +#define AUB_TRACE_SURFACE_STATE_MASK 0x00000ff00 +#define AUB_TRACE_BINDING_TABLE 0x000000100 +#define AUB_TRACE_SURFACE_STATE 0x000000200 + +/* DW3: address */ +/* DW4: len */ + +#endif /* _INTEL_AUB_H */ diff --git a/intel/intel_bufmgr.h b/intel/intel_bufmgr.h index 808e5df..c197abc 100644 --- a/intel/intel_bufmgr.h +++ b/intel/intel_bufmgr.h @@ -1,5 +1,5 @@ /* - * Copyright © 2008 Intel Corporation + * Copyright © 2008-2012 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -34,7 +34,9 @@ #ifndef INTEL_BUFMGR_H #define INTEL_BUFMGR_H +#include #include +#include struct drm_clip_rect; @@ -83,6 +85,19 @@ struct _drm_intel_bo { int handle; }; +enum aub_dump_bmp_format { + AUB_DUMP_BMP_FORMAT_8BIT = 1, + AUB_DUMP_BMP_FORMAT_ARGB_4444 = 4, + AUB_DUMP_BMP_FORMAT_ARGB_0888 = 6, + AUB_DUMP_BMP_FORMAT_ARGB_8888 = 7, +}; + +typedef struct _drm_intel_aub_annotation { + uint32_t type; + uint32_t subtype; + uint32_t ending_offset; +} drm_intel_aub_annotation; + #define BO_ALLOC_FOR_RENDER (1<<0) drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, @@ -147,15 +162,28 @@ void drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr); void drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr); void drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, int limit); +int drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo); int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo); int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo); + int drm_intel_gem_bo_get_reloc_count(drm_intel_bo *bo); void drm_intel_gem_bo_clear_relocs(drm_intel_bo *bo, int start); void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable); +void drm_intel_bufmgr_gem_set_aub_dump(drm_intel_bufmgr *bufmgr, int enable); +void drm_intel_gem_bo_aub_dump_bmp(drm_intel_bo *bo, + int x1, int y1, int width, int height, + enum aub_dump_bmp_format format, + int pitch, int offset); +void +drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo, + drm_intel_aub_annotation *annotations, + unsigned count); + int drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id); int drm_intel_get_aperture_sizes(int fd, size_t *mappable, size_t *total); +int drm_intel_bufmgr_gem_get_devid(drm_intel_bufmgr *bufmgr); /* drm_intel_bufmgr_fake.c */ drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd, @@ -190,6 +218,19 @@ void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, void drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr); void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr); +struct drm_intel_decode *drm_intel_decode_context_alloc(uint32_t devid); +void drm_intel_decode_context_free(struct drm_intel_decode *ctx); +void drm_intel_decode_set_batch_pointer(struct drm_intel_decode *ctx, + void *data, uint32_t hw_offset, + int count); +void drm_intel_decode_set_dump_past_end(struct drm_intel_decode *ctx, + int dump_past_end); +void drm_intel_decode_set_head_tail(struct drm_intel_decode *ctx, + uint32_t head, uint32_t tail); +void drm_intel_decode_set_output_file(struct drm_intel_decode *ctx, FILE *out); +void drm_intel_decode(struct drm_intel_decode *ctx); + + /** @{ Compatibility defines to keep old code building despite the symbol rename * from dri_* to drm_intel_* */ diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c index 19441f3..b776d2f 100644 --- a/intel/intel_bufmgr_gem.c +++ b/intel/intel_bufmgr_gem.c @@ -1,7 +1,7 @@ /************************************************************************** * * Copyright © 2007 Red Hat Inc. - * Copyright © 2007 Intel Corporation + * Copyright © 2007-2012 Intel Corporation * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA * All Rights Reserved. * @@ -58,10 +58,21 @@ #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" #include "intel_chipset.h" +#include "intel_aub.h" #include "string.h" #include "i915_drm.h" +#ifdef HAVE_VALGRIND +#include +#include +#define VG(x) x +#else +#define VG(x) +#endif + +#define VG_CLEAR(s) VG(memset(&s, 0, sizeof(s))) + #define DBG(...) do { \ if (bufmgr_gem->bufmgr.debug) \ fprintf(stderr, __VA_ARGS__); \ @@ -107,8 +118,13 @@ typedef struct _drm_intel_bufmgr_gem { unsigned int has_bsd : 1; unsigned int has_blt : 1; unsigned int has_relaxed_fencing : 1; + unsigned int has_llc : 1; unsigned int bo_reuse : 1; + unsigned int no_exec : 1; bool fenced_relocs; + + FILE *aub_file; + uint32_t aub_offset; } drm_intel_bufmgr_gem; #define DRM_INTEL_RELOC_FENCE (1<<0) @@ -203,6 +219,11 @@ struct _drm_intel_bo_gem { /** Flags that we may need to do the SW_FINSIH ioctl on unmap. */ bool mapped_cpu_write; + + uint32_t aub_offset; + + drm_intel_aub_annotation *aub_annotations; + unsigned aub_annotation_count; }; static unsigned int @@ -284,7 +305,8 @@ drm_intel_gem_bo_tile_pitch(drm_intel_bufmgr_gem *bufmgr_gem, return ALIGN(pitch, 64); if (*tiling_mode == I915_TILING_X - || (IS_915(bufmgr_gem) && *tiling_mode == I915_TILING_Y)) + || (IS_915(bufmgr_gem->pci_device) + && *tiling_mode == I915_TILING_Y)) tile_width = 512; else tile_width = 128; @@ -537,7 +559,7 @@ drm_intel_gem_bo_busy(drm_intel_bo *bo) struct drm_i915_gem_busy busy; int ret; - memset(&busy, 0, sizeof(busy)); + VG_CLEAR(busy); busy.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); @@ -551,6 +573,7 @@ drm_intel_gem_bo_madvise_internal(drm_intel_bufmgr_gem *bufmgr_gem, { struct drm_i915_gem_madvise madv; + VG_CLEAR(madv); madv.handle = bo_gem->gem_handle; madv.madv = state; madv.retained = 1; @@ -678,7 +701,8 @@ retry: return NULL; bo_gem->bo.size = bo_size; - memset(&create, 0, sizeof(create)); + + VG_CLEAR(create); create.size = bo_size; ret = drmIoctl(bufmgr_gem->fd, @@ -714,6 +738,8 @@ retry: bo_gem->used_as_reloc_target = false; bo_gem->has_error = false; bo_gem->reusable = true; + bo_gem->aub_annotations = NULL; + bo_gem->aub_annotation_count = 0; drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem); @@ -772,10 +798,11 @@ drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name, aligned_y = y; height_alignment = 2; - if (IS_GEN2(bufmgr_gem) && tiling != I915_TILING_NONE) + if ((bufmgr_gem->gen == 2) && tiling != I915_TILING_NONE) height_alignment = 16; else if (tiling == I915_TILING_X - || (IS_915(bufmgr_gem) && tiling == I915_TILING_Y)) + || (IS_915(bufmgr_gem->pci_device) + && tiling == I915_TILING_Y)) height_alignment = 8; else if (tiling == I915_TILING_Y) height_alignment = 32; @@ -833,7 +860,7 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, if (!bo_gem) return NULL; - memset(&open_arg, 0, sizeof(open_arg)); + VG_CLEAR(open_arg); open_arg.name = handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_OPEN, @@ -856,7 +883,7 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, bo_gem->global_name = handle; bo_gem->reusable = false; - memset(&get_tiling, 0, sizeof(get_tiling)); + VG_CLEAR(get_tiling); get_tiling.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_TILING, @@ -887,6 +914,7 @@ drm_intel_gem_bo_free(drm_intel_bo *bo) DRMLISTDEL(&bo_gem->vma_list); if (bo_gem->mem_virtual) { + VG(VALGRIND_FREELIKE_BLOCK(bo_gem->mem_virtual, 0)); munmap(bo_gem->mem_virtual, bo_gem->bo.size); bufmgr_gem->vma_count--; } @@ -896,16 +924,31 @@ drm_intel_gem_bo_free(drm_intel_bo *bo) } /* Close this object */ - memset(&close, 0, sizeof(close)); + VG_CLEAR(close); close.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close); if (ret != 0) { DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n", bo_gem->gem_handle, bo_gem->name, strerror(errno)); } + free(bo_gem->aub_annotations); free(bo); } +static void +drm_intel_gem_bo_mark_mmaps_incoherent(drm_intel_bo *bo) +{ +#if HAVE_VALGRIND + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->mem_virtual) + VALGRIND_MAKE_MEM_NOACCESS(bo_gem->mem_virtual, bo->size); + + if (bo_gem->gtt_virtual) + VALGRIND_MAKE_MEM_NOACCESS(bo_gem->gtt_virtual, bo->size); +#endif +} + /** Frees all cached buffers significantly older than @time. */ static void drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time) @@ -958,7 +1001,7 @@ static void drm_intel_gem_bo_purge_vma_cache(drm_intel_bufmgr_gem *bufmgr_gem) bufmgr_gem->vma_cache.next, vma_list); assert(bo_gem->map_count == 0); - DRMLISTDEL(&bo_gem->vma_list); + DRMLISTDELINIT(&bo_gem->vma_list); if (bo_gem->mem_virtual) { munmap(bo_gem->mem_virtual, bo_gem->bo.size); @@ -1034,6 +1077,7 @@ drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time) DBG("bo freed with non-zero map-count %d\n", bo_gem->map_count); bo_gem->map_count = 0; drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + drm_intel_gem_bo_mark_mmaps_incoherent(bo); } DRMLISTDEL(&bo_gem->name_list); @@ -1101,7 +1145,7 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) DBG("bo_map: %d (%s), map_count=%d\n", bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); - memset(&mmap_arg, 0, sizeof(mmap_arg)); + VG_CLEAR(mmap_arg); mmap_arg.handle = bo_gem->gem_handle; mmap_arg.offset = 0; mmap_arg.size = bo->size; @@ -1118,12 +1162,14 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) pthread_mutex_unlock(&bufmgr_gem->lock); return ret; } + VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1)); bo_gem->mem_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr; } DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, bo_gem->mem_virtual); bo->virtual = bo_gem->mem_virtual; + VG_CLEAR(set_domain); set_domain.handle = bo_gem->gem_handle; set_domain.read_domains = I915_GEM_DOMAIN_CPU; if (write_enable) @@ -1142,20 +1188,20 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) if (write_enable) bo_gem->mapped_cpu_write = true; + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->mem_virtual, bo->size)); pthread_mutex_unlock(&bufmgr_gem->lock); return 0; } -int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) +static int +map_gtt(drm_intel_bo *bo) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; - struct drm_i915_gem_set_domain set_domain; int ret; - pthread_mutex_lock(&bufmgr_gem->lock); - if (bo_gem->map_count++ == 0) drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem); @@ -1166,7 +1212,7 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n", bo_gem->gem_handle, bo_gem->name, bo_gem->map_count); - memset(&mmap_arg, 0, sizeof(mmap_arg)); + VG_CLEAR(mmap_arg); mmap_arg.handle = bo_gem->gem_handle; /* Get the fake offset back... */ @@ -1181,7 +1227,6 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) strerror(errno)); if (--bo_gem->map_count == 0) drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); - pthread_mutex_unlock(&bufmgr_gem->lock); return ret; } @@ -1198,7 +1243,6 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) strerror(errno)); if (--bo_gem->map_count == 0) drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); - pthread_mutex_unlock(&bufmgr_gem->lock); return ret; } } @@ -1208,7 +1252,34 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) DBG("bo_map_gtt: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, bo_gem->gtt_virtual); - /* Now move it to the GTT domain so that the CPU caches are flushed */ + return 0; +} + +int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + struct drm_i915_gem_set_domain set_domain; + int ret; + + pthread_mutex_lock(&bufmgr_gem->lock); + + ret = map_gtt(bo); + if (ret) { + pthread_mutex_unlock(&bufmgr_gem->lock); + return ret; + } + + /* Now move it to the GTT domain so that the GPU and CPU + * caches are flushed and the GPU isn't actively using the + * buffer. + * + * The pagefault handler does this domain change for us when + * it has unbound the BO from the GTT, but it's up to us to + * tell it when we're about to use things if we had done + * rendering and it still happens to be bound to the GTT. + */ + VG_CLEAR(set_domain); set_domain.handle = bo_gem->gem_handle; set_domain.read_domains = I915_GEM_DOMAIN_GTT; set_domain.write_domain = I915_GEM_DOMAIN_GTT; @@ -1221,16 +1292,53 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) strerror(errno)); } + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->gtt_virtual, bo->size)); pthread_mutex_unlock(&bufmgr_gem->lock); return 0; } +/** + * Performs a mapping of the buffer object like the normal GTT + * mapping, but avoids waiting for the GPU to be done reading from or + * rendering to the buffer. + * + * This is used in the implementation of GL_ARB_map_buffer_range: The + * user asks to create a buffer, then does a mapping, fills some + * space, runs a drawing command, then asks to map it again without + * synchronizing because it guarantees that it won't write over the + * data that the GPU is busy using (or, more specifically, that if it + * does write over the data, it acknowledges that rendering is + * undefined). + */ + +int drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + int ret; + + /* If the CPU cache isn't coherent with the GTT, then use a + * regular synchronized mapping. The problem is that we don't + * track where the buffer was last used on the CPU side in + * terms of drm_intel_bo_map vs drm_intel_gem_bo_map_gtt, so + * we would potentially corrupt the buffer even when the user + * does reasonable things. + */ + if (!bufmgr_gem->has_llc) + return drm_intel_gem_bo_map_gtt(bo); + + pthread_mutex_lock(&bufmgr_gem->lock); + ret = map_gtt(bo); + pthread_mutex_unlock(&bufmgr_gem->lock); + + return ret; +} + static int drm_intel_gem_bo_unmap(drm_intel_bo *bo) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; - struct drm_i915_gem_sw_finish sw_finish; int ret = 0; if (bo == NULL) @@ -1248,11 +1356,14 @@ static int drm_intel_gem_bo_unmap(drm_intel_bo *bo) } if (bo_gem->mapped_cpu_write) { + struct drm_i915_gem_sw_finish sw_finish; + /* Cause a flush to happen if the buffer's pinned for * scanout, so the results show up in a timely manner. * Unlike GTT set domains, this only does work if the * buffer should be scanout-related. */ + VG_CLEAR(sw_finish); sw_finish.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SW_FINISH, @@ -1268,6 +1379,7 @@ static int drm_intel_gem_bo_unmap(drm_intel_bo *bo) */ if (--bo_gem->map_count == 0) { drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem); + drm_intel_gem_bo_mark_mmaps_incoherent(bo); bo->virtual = NULL; } pthread_mutex_unlock(&bufmgr_gem->lock); @@ -1289,7 +1401,7 @@ drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset, struct drm_i915_gem_pwrite pwrite; int ret; - memset(&pwrite, 0, sizeof(pwrite)); + VG_CLEAR(pwrite); pwrite.handle = bo_gem->gem_handle; pwrite.offset = offset; pwrite.size = size; @@ -1314,6 +1426,7 @@ drm_intel_gem_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id) struct drm_i915_get_pipe_from_crtc_id get_pipe_from_crtc_id; int ret; + VG_CLEAR(get_pipe_from_crtc_id); get_pipe_from_crtc_id.crtc_id = crtc_id; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, @@ -1340,7 +1453,7 @@ drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, struct drm_i915_gem_pread pread; int ret; - memset(&pread, 0, sizeof(pread)); + VG_CLEAR(pread); pread.handle = bo_gem->gem_handle; pread.offset = offset; pread.size = size; @@ -1380,6 +1493,7 @@ drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable) struct drm_i915_gem_set_domain set_domain; int ret; + VG_CLEAR(set_domain); set_domain.handle = bo_gem->gem_handle; set_domain.read_domains = I915_GEM_DOMAIN_GTT; set_domain.write_domain = write_enable ? I915_GEM_DOMAIN_GTT : 0; @@ -1592,6 +1706,8 @@ drm_intel_gem_bo_process_reloc(drm_intel_bo *bo) if (target_bo == bo) continue; + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + /* Continue walking the tree depth-first. */ drm_intel_gem_bo_process_reloc(target_bo); @@ -1616,6 +1732,8 @@ drm_intel_gem_bo_process_reloc2(drm_intel_bo *bo) if (target_bo == bo) continue; + drm_intel_gem_bo_mark_mmaps_incoherent(bo); + /* Continue walking the tree depth-first. */ drm_intel_gem_bo_process_reloc2(target_bo); @@ -1667,6 +1785,287 @@ drm_intel_update_buffer_offsets2 (drm_intel_bufmgr_gem *bufmgr_gem) } } +static void +aub_out(drm_intel_bufmgr_gem *bufmgr_gem, uint32_t data) +{ + fwrite(&data, 1, 4, bufmgr_gem->aub_file); +} + +static void +aub_out_data(drm_intel_bufmgr_gem *bufmgr_gem, void *data, size_t size) +{ + fwrite(data, 1, size, bufmgr_gem->aub_file); +} + +static void +aub_write_bo_data(drm_intel_bo *bo, uint32_t offset, uint32_t size) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + uint32_t *data; + unsigned int i; + + data = malloc(bo->size); + drm_intel_bo_get_subdata(bo, offset, size, data); + + /* Easy mode: write out bo with no relocations */ + if (!bo_gem->reloc_count) { + aub_out_data(bufmgr_gem, data, size); + free(data); + return; + } + + /* Otherwise, handle the relocations while writing. */ + for (i = 0; i < size / 4; i++) { + int r; + for (r = 0; r < bo_gem->reloc_count; r++) { + struct drm_i915_gem_relocation_entry *reloc; + drm_intel_reloc_target *info; + + reloc = &bo_gem->relocs[r]; + info = &bo_gem->reloc_target_info[r]; + + if (reloc->offset == offset + i * 4) { + drm_intel_bo_gem *target_gem; + uint32_t val; + + target_gem = (drm_intel_bo_gem *)info->bo; + + val = reloc->delta; + val += target_gem->aub_offset; + + aub_out(bufmgr_gem, val); + data[i] = val; + break; + } + } + if (r == bo_gem->reloc_count) { + /* no relocation, just the data */ + aub_out(bufmgr_gem, data[i]); + } + } + + free(data); +} + +static void +aub_bo_get_address(drm_intel_bo *bo) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + /* Give the object a graphics address in the AUB file. We + * don't just use the GEM object address because we do AUB + * dumping before execution -- we want to successfully log + * when the hardware might hang, and we might even want to aub + * capture for a driver trying to execute on a different + * generation of hardware by disabling the actual kernel exec + * call. + */ + bo_gem->aub_offset = bufmgr_gem->aub_offset; + bufmgr_gem->aub_offset += bo->size; + /* XXX: Handle aperture overflow. */ + assert(bufmgr_gem->aub_offset < 256 * 1024 * 1024); +} + +static void +aub_write_trace_block(drm_intel_bo *bo, uint32_t type, uint32_t subtype, + uint32_t offset, uint32_t size) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + aub_out(bufmgr_gem, + CMD_AUB_TRACE_HEADER_BLOCK | + (5 - 2)); + aub_out(bufmgr_gem, + AUB_TRACE_MEMTYPE_GTT | type | AUB_TRACE_OP_DATA_WRITE); + aub_out(bufmgr_gem, subtype); + aub_out(bufmgr_gem, bo_gem->aub_offset + offset); + aub_out(bufmgr_gem, size); + aub_write_bo_data(bo, offset, size); +} + +/** + * Break up large objects into multiple writes. Otherwise a 128kb VBO + * would overflow the 16 bits of size field in the packet header and + * everything goes badly after that. + */ +static void +aub_write_large_trace_block(drm_intel_bo *bo, uint32_t type, uint32_t subtype, + uint32_t offset, uint32_t size) +{ + uint32_t block_size; + uint32_t sub_offset; + + for (sub_offset = 0; sub_offset < size; sub_offset += block_size) { + block_size = size - sub_offset; + + if (block_size > 8 * 4096) + block_size = 8 * 4096; + + aub_write_trace_block(bo, type, subtype, offset + sub_offset, + block_size); + } +} + +static void +aub_write_bo(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + uint32_t offset = 0; + unsigned i; + + aub_bo_get_address(bo); + + /* Write out each annotated section separately. */ + for (i = 0; i < bo_gem->aub_annotation_count; ++i) { + drm_intel_aub_annotation *annotation = + &bo_gem->aub_annotations[i]; + uint32_t ending_offset = annotation->ending_offset; + if (ending_offset > bo->size) + ending_offset = bo->size; + if (ending_offset > offset) { + aub_write_large_trace_block(bo, annotation->type, + annotation->subtype, + offset, + ending_offset - offset); + offset = ending_offset; + } + } + + /* Write out any remaining unannotated data */ + if (offset < bo->size) { + aub_write_large_trace_block(bo, AUB_TRACE_TYPE_NOTYPE, 0, + offset, bo->size - offset); + } +} + +/* + * Make a ringbuffer on fly and dump it + */ +static void +aub_build_dump_ringbuffer(drm_intel_bufmgr_gem *bufmgr_gem, + uint32_t batch_buffer, int ring_flag) +{ + uint32_t ringbuffer[4096]; + int ring = AUB_TRACE_TYPE_RING_PRB0; /* The default ring */ + int ring_count = 0; + + if (ring_flag == I915_EXEC_BSD) + ring = AUB_TRACE_TYPE_RING_PRB1; + + /* Make a ring buffer to execute our batchbuffer. */ + memset(ringbuffer, 0, sizeof(ringbuffer)); + ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START; + ringbuffer[ring_count++] = batch_buffer; + + /* Write out the ring. This appears to trigger execution of + * the ring in the simulator. + */ + aub_out(bufmgr_gem, + CMD_AUB_TRACE_HEADER_BLOCK | + (5 - 2)); + aub_out(bufmgr_gem, + AUB_TRACE_MEMTYPE_GTT | ring | AUB_TRACE_OP_COMMAND_WRITE); + aub_out(bufmgr_gem, 0); /* general/surface subtype */ + aub_out(bufmgr_gem, bufmgr_gem->aub_offset); + aub_out(bufmgr_gem, ring_count * 4); + + /* FIXME: Need some flush operations here? */ + aub_out_data(bufmgr_gem, ringbuffer, ring_count * 4); + + /* Update offset pointer */ + bufmgr_gem->aub_offset += 4096; +} + +void +drm_intel_gem_bo_aub_dump_bmp(drm_intel_bo *bo, + int x1, int y1, int width, int height, + enum aub_dump_bmp_format format, + int pitch, int offset) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + uint32_t cpp; + + switch (format) { + case AUB_DUMP_BMP_FORMAT_8BIT: + cpp = 1; + break; + case AUB_DUMP_BMP_FORMAT_ARGB_4444: + cpp = 2; + break; + case AUB_DUMP_BMP_FORMAT_ARGB_0888: + case AUB_DUMP_BMP_FORMAT_ARGB_8888: + cpp = 4; + break; + default: + printf("Unknown AUB dump format %d\n", format); + return; + } + + if (!bufmgr_gem->aub_file) + return; + + aub_out(bufmgr_gem, CMD_AUB_DUMP_BMP | 4); + aub_out(bufmgr_gem, (y1 << 16) | x1); + aub_out(bufmgr_gem, + (format << 24) | + (cpp << 19) | + pitch / 4); + aub_out(bufmgr_gem, (height << 16) | width); + aub_out(bufmgr_gem, bo_gem->aub_offset + offset); + aub_out(bufmgr_gem, + ((bo_gem->tiling_mode != I915_TILING_NONE) ? (1 << 2) : 0) | + ((bo_gem->tiling_mode == I915_TILING_Y) ? (1 << 3) : 0)); +} + +static void +aub_exec(drm_intel_bo *bo, int ring_flag, int used) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + bool batch_buffer_needs_annotations; + + if (!bufmgr_gem->aub_file) + return; + + /* If batch buffer is not annotated, annotate it the best we + * can. + */ + batch_buffer_needs_annotations = bo_gem->aub_annotation_count == 0; + if (batch_buffer_needs_annotations) { + drm_intel_aub_annotation annotations[2] = { + { AUB_TRACE_TYPE_BATCH, 0, used }, + { AUB_TRACE_TYPE_NOTYPE, 0, bo->size } + }; + drm_intel_bufmgr_gem_set_aub_annotations(bo, annotations, 2); + } + + /* Write out all buffers to AUB memory */ + for (i = 0; i < bufmgr_gem->exec_count; i++) { + aub_write_bo(bufmgr_gem->exec_bos[i]); + } + + /* Remove any annotations we added */ + if (batch_buffer_needs_annotations) + drm_intel_bufmgr_gem_set_aub_annotations(bo, NULL, 0); + + /* Dump ring buffer */ + aub_build_dump_ringbuffer(bufmgr_gem, bo_gem->aub_offset, ring_flag); + + fflush(bufmgr_gem->aub_file); + + /* + * One frame has been dumped. So reset the aub_offset for the next frame. + * + * FIXME: Can we do this? + */ + bufmgr_gem->aub_offset = 0x10000; +} + static int drm_intel_gem_bo_exec(drm_intel_bo *bo, int used, drm_clip_rect_t * cliprects, int num_cliprects, int DR4) @@ -1688,6 +2087,7 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used, */ drm_intel_add_validate_buffer(bo); + VG_CLEAR(execbuf); execbuf.buffers_ptr = (uintptr_t) bufmgr_gem->exec_objects; execbuf.buffer_count = bufmgr_gem->exec_count; execbuf.batch_start_offset = 0; @@ -1740,7 +2140,8 @@ drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used, { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; struct drm_i915_gem_execbuffer2 execbuf; - int ret, i; + int ret = 0; + int i; switch (flags & 0x7) { default: @@ -1767,6 +2168,7 @@ drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used, */ drm_intel_add_validate_buffer2(bo, 0); + VG_CLEAR(execbuf); execbuf.buffers_ptr = (uintptr_t)bufmgr_gem->exec2_objects; execbuf.buffer_count = bufmgr_gem->exec_count; execbuf.batch_start_offset = 0; @@ -1779,6 +2181,11 @@ drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used, execbuf.rsvd1 = 0; execbuf.rsvd2 = 0; + aub_exec(bo, flags, used); + + if (bufmgr_gem->no_exec) + goto skip_execution; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf); @@ -1796,6 +2203,7 @@ drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used, } drm_intel_update_buffer_offsets2(bufmgr_gem); +skip_execution: if (bufmgr_gem->bufmgr.debug) drm_intel_gem_dump_validation_list(bufmgr_gem); @@ -1831,7 +2239,7 @@ drm_intel_gem_bo_pin(drm_intel_bo *bo, uint32_t alignment) struct drm_i915_gem_pin pin; int ret; - memset(&pin, 0, sizeof(pin)); + VG_CLEAR(pin); pin.handle = bo_gem->gem_handle; pin.alignment = alignment; @@ -1853,7 +2261,7 @@ drm_intel_gem_bo_unpin(drm_intel_bo *bo) struct drm_i915_gem_unpin unpin; int ret; - memset(&unpin, 0, sizeof(unpin)); + VG_CLEAR(unpin); unpin.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin); @@ -1939,16 +2347,18 @@ drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; - struct drm_gem_flink flink; int ret; if (!bo_gem->global_name) { - memset(&flink, 0, sizeof(flink)); + struct drm_gem_flink flink; + + VG_CLEAR(flink); flink.handle = bo_gem->gem_handle; ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink); if (ret != 0) return -errno; + bo_gem->global_name = flink.name; bo_gem->reusable = false; @@ -2264,6 +2674,143 @@ drm_intel_bufmgr_gem_set_vma_cache_size(drm_intel_bufmgr *bufmgr, int limit) } /** + * Get the PCI ID for the device. This can be overridden by setting the + * INTEL_DEVID_OVERRIDE environment variable to the desired ID. + */ +static int +get_pci_device_id(drm_intel_bufmgr_gem *bufmgr_gem) +{ + char *devid_override; + int devid; + int ret; + drm_i915_getparam_t gp; + + if (geteuid() == getuid()) { + devid_override = getenv("INTEL_DEVID_OVERRIDE"); + if (devid_override) { + bufmgr_gem->no_exec = true; + return strtod(devid_override, NULL); + } + } + + VG_CLEAR(devid); + VG_CLEAR(gp); + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = &devid; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) { + fprintf(stderr, "get chip id failed: %d [%d]\n", ret, errno); + fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); + } + return devid; +} + +int +drm_intel_bufmgr_gem_get_devid(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + + return bufmgr_gem->pci_device; +} + +/** + * Sets up AUB dumping. + * + * This is a trace file format that can be used with the simulator. + * Packets are emitted in a format somewhat like GPU command packets. + * You can set up a GTT and upload your objects into the referenced + * space, then send off batchbuffers and get BMPs out the other end. + */ +void +drm_intel_bufmgr_gem_set_aub_dump(drm_intel_bufmgr *bufmgr, int enable) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + int entry = 0x200003; + int i; + int gtt_size = 0x10000; + + if (!enable) { + if (bufmgr_gem->aub_file) { + fclose(bufmgr_gem->aub_file); + bufmgr_gem->aub_file = NULL; + } + } + + if (geteuid() != getuid()) + return; + + bufmgr_gem->aub_file = fopen("intel.aub", "w+"); + if (!bufmgr_gem->aub_file) + return; + + /* Start allocating objects from just after the GTT. */ + bufmgr_gem->aub_offset = gtt_size; + + /* Start with a (required) version packet. */ + aub_out(bufmgr_gem, CMD_AUB_HEADER | (13 - 2)); + aub_out(bufmgr_gem, + (4 << AUB_HEADER_MAJOR_SHIFT) | + (0 << AUB_HEADER_MINOR_SHIFT)); + for (i = 0; i < 8; i++) { + aub_out(bufmgr_gem, 0); /* app name */ + } + aub_out(bufmgr_gem, 0); /* timestamp */ + aub_out(bufmgr_gem, 0); /* timestamp */ + aub_out(bufmgr_gem, 0); /* comment len */ + + /* Set up the GTT. The max we can handle is 256M */ + aub_out(bufmgr_gem, CMD_AUB_TRACE_HEADER_BLOCK | (5 - 2)); + aub_out(bufmgr_gem, AUB_TRACE_MEMTYPE_NONLOCAL | 0 | AUB_TRACE_OP_DATA_WRITE); + aub_out(bufmgr_gem, 0); /* subtype */ + aub_out(bufmgr_gem, 0); /* offset */ + aub_out(bufmgr_gem, gtt_size); /* size */ + for (i = 0x000; i < gtt_size; i += 4, entry += 0x1000) { + aub_out(bufmgr_gem, entry); + } +} + +/** + * Annotate the given bo for use in aub dumping. + * + * \param annotations is an array of drm_intel_aub_annotation objects + * describing the type of data in various sections of the bo. Each + * element of the array specifies the type and subtype of a section of + * the bo, and the past-the-end offset of that section. The elements + * of \c annotations must be sorted so that ending_offset is + * increasing. + * + * \param count is the number of elements in the \c annotations array. + * If \c count is zero, then \c annotations will not be dereferenced. + * + * Annotations are copied into a private data structure, so caller may + * re-use the memory pointed to by \c annotations after the call + * returns. + * + * Annotations are stored for the lifetime of the bo; to reset to the + * default state (no annotations), call this function with a \c count + * of zero. + */ +void +drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo, + drm_intel_aub_annotation *annotations, + unsigned count) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + unsigned size = sizeof(*annotations) * count; + drm_intel_aub_annotation *new_annotations = + count > 0 ? realloc(bo_gem->aub_annotations, size) : NULL; + if (new_annotations == NULL) { + free(bo_gem->aub_annotations); + bo_gem->aub_annotations = NULL; + bo_gem->aub_annotation_count = 0; + return; + } + memcpy(new_annotations, annotations, size); + bo_gem->aub_annotations = new_annotations; + bo_gem->aub_annotation_count = count; +} + +/** * Initializes the GEM buffer manager, which uses the kernel to allocate, map, * and manage map buffer objections. * @@ -2305,24 +2852,25 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) (int)bufmgr_gem->gtt_size / 1024); } - gp.param = I915_PARAM_CHIPSET_ID; - gp.value = &bufmgr_gem->pci_device; - ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); - if (ret) { - fprintf(stderr, "get chip id failed: %d [%d]\n", ret, errno); - fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); - } + bufmgr_gem->pci_device = get_pci_device_id(bufmgr_gem); - if (IS_GEN2(bufmgr_gem)) + if (IS_GEN2(bufmgr_gem->pci_device)) bufmgr_gem->gen = 2; - else if (IS_GEN3(bufmgr_gem)) + else if (IS_GEN3(bufmgr_gem->pci_device)) bufmgr_gem->gen = 3; - else if (IS_GEN4(bufmgr_gem)) + else if (IS_GEN4(bufmgr_gem->pci_device)) bufmgr_gem->gen = 4; - else + else if (IS_GEN5(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 5; + else if (IS_GEN6(bufmgr_gem->pci_device)) bufmgr_gem->gen = 6; + else if (IS_GEN7(bufmgr_gem->pci_device)) + bufmgr_gem->gen = 7; + else + assert(0); - if (IS_GEN3(bufmgr_gem) && bufmgr_gem->gtt_size > 256*1024*1024) { + if (IS_GEN3(bufmgr_gem->pci_device) && + bufmgr_gem->gtt_size > 256*1024*1024) { /* The unmappable part of gtt on gen 3 (i.e. above 256MB) can't * be used for tiled blits. To simplify the accounting, just * substract the unmappable part (fixed to 256MB on all known @@ -2330,6 +2878,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem->gtt_size -= 256*1024*1024; } + VG_CLEAR(gp); gp.value = &tmp; gp.param = I915_PARAM_HAS_EXECBUF2; @@ -2349,6 +2898,17 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); bufmgr_gem->has_relaxed_fencing = ret == 0; + gp.param = I915_PARAM_HAS_LLC; + ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret != 0) { + /* Kernel does not supports HAS_LLC query, fallback to GPU + * generation detection and assume that we have LLC on GEN6/7 + */ + bufmgr_gem->has_llc = (IS_GEN6(bufmgr_gem->pci_device) | + IS_GEN7(bufmgr_gem->pci_device)); + } else + bufmgr_gem->has_llc = ret == 0; + if (bufmgr_gem->gen < 4) { gp.param = I915_PARAM_NUM_FENCES_AVAIL; gp.value = &bufmgr_gem->available_fences; diff --git a/intel/intel_chipset.h b/intel/intel_chipset.h index b4e0747..9c1abc8 100644 --- a/intel/intel_chipset.h +++ b/intel/intel_chipset.h @@ -28,22 +28,46 @@ #ifndef _INTEL_CHIPSET_H #define _INTEL_CHIPSET_H -#define IS_830(dev) ((dev)->pci_device == 0x3577) -#define IS_845(dev) ((dev)->pci_device == 0x2562) -#define IS_85X(dev) ((dev)->pci_device == 0x3582) -#define IS_865(dev) ((dev)->pci_device == 0x2572) +#define PCI_CHIP_ILD_G 0x0042 +#define PCI_CHIP_ILM_G 0x0046 + +#define PCI_CHIP_SANDYBRIDGE_GT1 0x0102 /* desktop */ +#define PCI_CHIP_SANDYBRIDGE_GT2 0x0112 +#define PCI_CHIP_SANDYBRIDGE_GT2_PLUS 0x0122 +#define PCI_CHIP_SANDYBRIDGE_M_GT1 0x0106 /* mobile */ +#define PCI_CHIP_SANDYBRIDGE_M_GT2 0x0116 +#define PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS 0x0126 +#define PCI_CHIP_SANDYBRIDGE_S 0x010A /* server */ + +#define PCI_CHIP_IVYBRIDGE_GT1 0x0152 /* desktop */ +#define PCI_CHIP_IVYBRIDGE_GT2 0x0162 +#define PCI_CHIP_IVYBRIDGE_M_GT1 0x0156 /* mobile */ +#define PCI_CHIP_IVYBRIDGE_M_GT2 0x0166 +#define PCI_CHIP_IVYBRIDGE_S 0x015a /* server */ +#define PCI_CHIP_IVYBRIDGE_S_GT2 0x016a /* server */ + +#define PCI_CHIP_HASWELL_GT1 0x0402 /* Desktop */ +#define PCI_CHIP_HASWELL_GT2 0x0412 +#define PCI_CHIP_HASWELL_M_GT1 0x0406 /* Mobile */ +#define PCI_CHIP_HASWELL_M_GT2 0x0416 +#define PCI_CHIP_HASWELL_M_ULT_GT2 0x0A16 /* Mobile ULT */ + +#define IS_830(dev) (dev == 0x3577) +#define IS_845(dev) (dev == 0x2562) +#define IS_85X(dev) (dev == 0x3582) +#define IS_865(dev) (dev == 0x2572) #define IS_GEN2(dev) (IS_830(dev) || \ IS_845(dev) || \ IS_85X(dev) || \ IS_865(dev)) -#define IS_915G(dev) ((dev)->pci_device == 0x2582 || \ - (dev)->pci_device == 0x258a) -#define IS_915GM(dev) ((dev)->pci_device == 0x2592) -#define IS_945G(dev) ((dev)->pci_device == 0x2772) -#define IS_945GM(dev) ((dev)->pci_device == 0x27A2 || \ - (dev)->pci_device == 0x27AE) +#define IS_915G(dev) (dev == 0x2582 || \ + dev == 0x258a) +#define IS_915GM(dev) (dev == 0x2592) +#define IS_945G(dev) (dev == 0x2772) +#define IS_945GM(dev) (dev == 0x27A2 || \ + dev == 0x27AE) #define IS_915(dev) (IS_915G(dev) || \ IS_915GM(dev)) @@ -53,49 +77,81 @@ IS_G33(dev) || \ IS_PINEVIEW(dev)) -#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ - (dev)->pci_device == 0x29B2 || \ - (dev)->pci_device == 0x29D2) +#define IS_G33(dev) (dev == 0x29C2 || \ + dev == 0x29B2 || \ + dev == 0x29D2) -#define IS_PINEVIEW(dev) ((dev)->pci_device == 0xa001 || \ - (dev)->pci_device == 0xa011) +#define IS_PINEVIEW(dev) (dev == 0xa001 || \ + dev == 0xa011) #define IS_GEN3(dev) (IS_915(dev) || \ IS_945(dev) || \ IS_G33(dev) || \ IS_PINEVIEW(dev)) -#define IS_I965GM(dev) ((dev)->pci_device == 0x2A02) - -#define IS_GEN4(dev) ((dev)->pci_device == 0x2972 || \ - (dev)->pci_device == 0x2982 || \ - (dev)->pci_device == 0x2992 || \ - (dev)->pci_device == 0x29A2 || \ - (dev)->pci_device == 0x2A02 || \ - (dev)->pci_device == 0x2A12 || \ - (dev)->pci_device == 0x2A42 || \ - (dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32 || \ - (dev)->pci_device == 0x2E42 || \ - (dev)->pci_device == 0x0042 || \ - (dev)->pci_device == 0x0046 || \ +#define IS_I965GM(dev) (dev == 0x2A02) + +#define IS_GEN4(dev) (dev == 0x2972 || \ + dev == 0x2982 || \ + dev == 0x2992 || \ + dev == 0x29A2 || \ + dev == 0x2A02 || \ + dev == 0x2A12 || \ + dev == 0x2A42 || \ + dev == 0x2E02 || \ + dev == 0x2E12 || \ + dev == 0x2E22 || \ + dev == 0x2E32 || \ + dev == 0x2E42 || \ + dev == 0x0042 || \ + dev == 0x0046 || \ IS_I965GM(dev) || \ IS_G4X(dev)) -#define IS_GM45(dev) ((dev)->pci_device == 0x2A42) +#define IS_GM45(dev) (dev == 0x2A42) + + +#define IS_GEN5(dev) (dev == PCI_CHIP_ILD_G || \ + dev == PCI_CHIP_ILM_G) + +#define IS_GEN6(dev) (dev == PCI_CHIP_SANDYBRIDGE_GT1 || \ + dev == PCI_CHIP_SANDYBRIDGE_GT2 || \ + dev == PCI_CHIP_SANDYBRIDGE_GT2_PLUS || \ + dev == PCI_CHIP_SANDYBRIDGE_M_GT1 || \ + dev == PCI_CHIP_SANDYBRIDGE_M_GT2 || \ + dev == PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS || \ + dev == PCI_CHIP_SANDYBRIDGE_S) + +#define IS_GEN7(devid) (IS_IVYBRIDGE(devid) || \ + IS_HASWELL(devid)) + +#define IS_IVYBRIDGE(dev) (dev == PCI_CHIP_IVYBRIDGE_GT1 || \ + dev == PCI_CHIP_IVYBRIDGE_GT2 || \ + dev == PCI_CHIP_IVYBRIDGE_M_GT1 || \ + dev == PCI_CHIP_IVYBRIDGE_M_GT2 || \ + dev == PCI_CHIP_IVYBRIDGE_S || \ + dev == PCI_CHIP_IVYBRIDGE_S_GT2) + +#define IS_HSW_GT1(devid) (devid == PCI_CHIP_HASWELL_GT1 || \ + devid == PCI_CHIP_HASWELL_M_GT1) +#define IS_HSW_GT2(devid) (devid == PCI_CHIP_HASWELL_GT2 || \ + devid == PCI_CHIP_HASWELL_M_GT2 || \ + devid == PCI_CHIP_HASWELL_M_ULT_GT2) + +#define IS_HASWELL(devid) (IS_HSW_GT1(devid) || \ + IS_HSW_GT2(devid)) -#define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22 || \ - (dev)->pci_device == 0x2E32 || \ - (dev)->pci_device == 0x2E42 || \ +#define IS_G4X(dev) (dev == 0x2E02 || \ + dev == 0x2E12 || \ + dev == 0x2E22 || \ + dev == 0x2E32 || \ + dev == 0x2E42 || \ IS_GM45(dev)) #define IS_9XX(dev) (IS_GEN3(dev) || \ IS_GEN4(dev) || \ IS_GEN5(dev) || \ - IS_GEN6(dev)) + IS_GEN6(dev) || \ + IS_GEN7(dev)) #endif /* _INTEL_CHIPSET_H */ diff --git a/intel/intel_decode.c b/intel/intel_decode.c new file mode 100644 index 0000000..bf23706 --- /dev/null +++ b/intel/intel_decode.c @@ -0,0 +1,3956 @@ +/* + * Copyright © 2009-2011 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "intel_chipset.h" +#include "intel_bufmgr.h" + +/* Struct for tracking drm_intel_decode state. */ +struct drm_intel_decode { + /** stdio file where the output should land. Defaults to stdout. */ + FILE *out; + + /** PCI device ID. */ + uint32_t devid; + + /** + * Shorthand device identifier: 3 is 915, 4 is 965, 5 is + * Ironlake, etc. + */ + int gen; + + /** GPU address of the start of the current packet. */ + uint32_t hw_offset; + /** CPU virtual address of the start of the current packet. */ + uint32_t *data; + /** DWORDs of remaining batchbuffer data starting from the packet. */ + uint32_t count; + + /** GPU address of the start of the batchbuffer data. */ + uint32_t base_hw_offset; + /** CPU Virtual address of the start of the batchbuffer data. */ + uint32_t *base_data; + /** Number of DWORDs of batchbuffer data. */ + uint32_t base_count; + + /** @{ + * GPU head and tail pointers, which will be noted in the dump, or ~0. + */ + uint32_t head, tail; + /** @} */ + + /** + * Whether to dump the dwords after MI_BATCHBUFFER_END. + * + * This sometimes provides clues in corrupted batchbuffers, + * and is used by the intel-gpu-tools. + */ + bool dump_past_end; + + bool overflowed; +}; + +static FILE *out; +static uint32_t saved_s2 = 0, saved_s4 = 0; +static char saved_s2_set = 0, saved_s4_set = 0; +static uint32_t head_offset = 0xffffffff; /* undefined */ +static uint32_t tail_offset = 0xffffffff; /* undefined */ + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) +#endif + +#define BUFFER_FAIL(_count, _len, _name) do { \ + fprintf(out, "Buffer size too small in %s (%d < %d)\n", \ + (_name), (_count), (_len)); \ + return _count; \ +} while (0) + +static float int_as_float(uint32_t intval) +{ + union intfloat { + uint32_t i; + float f; + } uval; + + uval.i = intval; + return uval.f; +} + +static void +instr_out(struct drm_intel_decode *ctx, unsigned int index, + const char *fmt, ...) __attribute__((format(__printf__, 3, 4))); + +static void +instr_out(struct drm_intel_decode *ctx, unsigned int index, + const char *fmt, ...) +{ + va_list va; + const char *parseinfo; + uint32_t offset = ctx->hw_offset + index * 4; + + if (index > ctx->count) { + if (!ctx->overflowed) { + fprintf(out, "ERROR: Decode attempted to continue beyond end of batchbuffer\n"); + ctx->overflowed = true; + } + return; + } + + if (offset == head_offset) + parseinfo = "HEAD"; + else if (offset == tail_offset) + parseinfo = "TAIL"; + else + parseinfo = " "; + + fprintf(out, "0x%08x: %s 0x%08x: %s", offset, parseinfo, + ctx->data[index], index == 0 ? "" : " "); + va_start(va, fmt); + vfprintf(out, fmt, va); + va_end(va); +} + +static int +decode_MI_WAIT_FOR_EVENT(struct drm_intel_decode *ctx) +{ + const char *cc_wait; + int cc_shift = 0; + uint32_t data = ctx->data[0]; + + if (ctx->gen <= 5) + cc_shift = 9; + else + cc_shift = 16; + + switch ((data >> cc_shift) & 0x1f) { + case 1: + cc_wait = ", cc wait 1"; + break; + case 2: + cc_wait = ", cc wait 2"; + break; + case 3: + cc_wait = ", cc wait 3"; + break; + case 4: + cc_wait = ", cc wait 4"; + break; + case 5: + cc_wait = ", cc wait 4"; + break; + default: + cc_wait = ""; + break; + } + + if (ctx->gen <= 5) { + instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + data & (1<<18)? ", pipe B start vblank wait": "", + data & (1<<17)? ", pipe A start vblank wait": "", + data & (1<<16)? ", overlay flip pending wait": "", + data & (1<<14)? ", pipe B hblank wait": "", + data & (1<<13)? ", pipe A hblank wait": "", + cc_wait, + data & (1<<8)? ", plane C pending flip wait": "", + data & (1<<7)? ", pipe B vblank wait": "", + data & (1<<6)? ", plane B pending flip wait": "", + data & (1<<5)? ", pipe B scan line wait": "", + data & (1<<4)? ", fbc idle wait": "", + data & (1<<3)? ", pipe A vblank wait": "", + data & (1<<2)? ", plane A pending flip wait": "", + data & (1<<1)? ", plane A scan line wait": ""); + } else { + instr_out(ctx, 0, "MI_WAIT_FOR_EVENT%s%s%s%s%s%s%s%s%s%s%s%s\n", + data & (1<<20)? ", sprite C pending flip wait": "", /* ivb */ + cc_wait, + data & (1<<13)? ", pipe B hblank wait": "", + data & (1<<11)? ", pipe B vblank wait": "", + data & (1<<10)? ", sprite B pending flip wait": "", + data & (1<<9)? ", plane B pending flip wait": "", + data & (1<<8)? ", plane B scan line wait": "", + data & (1<<5)? ", pipe A hblank wait": "", + data & (1<<3)? ", pipe A vblank wait": "", + data & (1<<2)? ", sprite A pending flip wait": "", + data & (1<<1)? ", plane A pending flip wait": "", + data & (1<<0)? ", plane A scan line wait": ""); + } + + return 1; +} + +static int +decode_mi(struct drm_intel_decode *ctx) +{ + unsigned int opcode, len = -1; + const char *post_sync_op = ""; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + int len_mask; + unsigned int min_len; + unsigned int max_len; + const char *name; + int (*func)(struct drm_intel_decode *ctx); + } opcodes_mi[] = { + { 0x08, 0, 1, 1, "MI_ARB_ON_OFF" }, + { 0x0a, 0, 1, 1, "MI_BATCH_BUFFER_END" }, + { 0x30, 0x3f, 3, 3, "MI_BATCH_BUFFER" }, + { 0x31, 0x3f, 2, 2, "MI_BATCH_BUFFER_START" }, + { 0x14, 0x3f, 3, 3, "MI_DISPLAY_BUFFER_INFO" }, + { 0x04, 0, 1, 1, "MI_FLUSH" }, + { 0x22, 0x1f, 3, 3, "MI_LOAD_REGISTER_IMM" }, + { 0x13, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_EXCL" }, + { 0x12, 0x3f, 2, 2, "MI_LOAD_SCAN_LINES_INCL" }, + { 0x00, 0, 1, 1, "MI_NOOP" }, + { 0x11, 0x3f, 2, 2, "MI_OVERLAY_FLIP" }, + { 0x07, 0, 1, 1, "MI_REPORT_HEAD" }, + { 0x18, 0x3f, 2, 2, "MI_SET_CONTEXT" }, + { 0x20, 0x3f, 3, 4, "MI_STORE_DATA_IMM" }, + { 0x21, 0x3f, 3, 4, "MI_STORE_DATA_INDEX" }, + { 0x24, 0x3f, 3, 3, "MI_STORE_REGISTER_MEM" }, + { 0x02, 0, 1, 1, "MI_USER_INTERRUPT" }, + { 0x03, 0, 1, 1, "MI_WAIT_FOR_EVENT", decode_MI_WAIT_FOR_EVENT }, + { 0x16, 0x7f, 3, 3, "MI_SEMAPHORE_MBOX" }, + { 0x26, 0x1f, 3, 4, "MI_FLUSH_DW" }, + { 0x0b, 0, 1, 1, "MI_SUSPEND_FLUSH"}, + }, *opcode_mi = NULL; + + /* check instruction length */ + for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); + opcode++) { + if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { + len = 1; + if (opcodes_mi[opcode].max_len > 1) { + len = + (data[0] & opcodes_mi[opcode].len_mask) + 2; + if (len < opcodes_mi[opcode].min_len + || len > opcodes_mi[opcode].max_len) { + fprintf(out, + "Bad length (%d) in %s, [%d, %d]\n", + len, opcodes_mi[opcode].name, + opcodes_mi[opcode].min_len, + opcodes_mi[opcode].max_len); + } + } + opcode_mi = &opcodes_mi[opcode]; + break; + } + } + + if (opcode_mi && opcode_mi->func) + return opcode_mi->func(ctx); + + switch ((data[0] & 0x1f800000) >> 23) { + case 0x0a: + instr_out(ctx, 0, "MI_BATCH_BUFFER_END\n"); + return -1; + case 0x16: + instr_out(ctx, 0, "MI_SEMAPHORE_MBOX%s%s%s%s %u\n", + data[0] & (1 << 22) ? " global gtt," : "", + data[0] & (1 << 21) ? " update semaphore," : "", + data[0] & (1 << 20) ? " compare semaphore," : "", + data[0] & (1 << 18) ? " use compare reg" : "", + (data[0] & (0x3 << 16)) >> 16); + instr_out(ctx, 1, "value\n"); + instr_out(ctx, 2, "address\n"); + return len; + case 0x21: + instr_out(ctx, 0, "MI_STORE_DATA_INDEX%s\n", + data[0] & (1 << 21) ? " use per-process HWS," : ""); + instr_out(ctx, 1, "index\n"); + instr_out(ctx, 2, "dword\n"); + if (len == 4) + instr_out(ctx, 3, "upper dword\n"); + return len; + case 0x00: + if (data[0] & (1 << 22)) + instr_out(ctx, 0, + "MI_NOOP write NOPID reg, val=0x%x\n", + data[0] & ((1 << 22) - 1)); + else + instr_out(ctx, 0, "MI_NOOP\n"); + return len; + case 0x26: + switch (data[0] & (0x3 << 14)) { + case (0 << 14): + post_sync_op = "no write"; + break; + case (1 << 14): + post_sync_op = "write data"; + break; + case (2 << 14): + post_sync_op = "reserved"; + break; + case (3 << 14): + post_sync_op = "write TIMESTAMP"; + break; + } + instr_out(ctx, 0, + "MI_FLUSH_DW%s%s%s%s post_sync_op='%s' %s%s\n", + data[0] & (1 << 22) ? + " enable protected mem (BCS-only)," : "", + data[0] & (1 << 21) ? " store in hws," : "", + data[0] & (1 << 18) ? " invalidate tlb," : "", + data[0] & (1 << 17) ? " flush gfdt," : "", + post_sync_op, + data[0] & (1 << 8) ? " enable notify interrupt," : "", + data[0] & (1 << 7) ? + " invalidate video state (BCS-only)," : ""); + if (data[0] & (1 << 21)) + instr_out(ctx, 1, "hws index\n"); + else + instr_out(ctx, 1, "address\n"); + instr_out(ctx, 2, "dword\n"); + if (len == 4) + instr_out(ctx, 3, "upper dword\n"); + return len; + } + + for (opcode = 0; opcode < sizeof(opcodes_mi) / sizeof(opcodes_mi[0]); + opcode++) { + if ((data[0] & 0x1f800000) >> 23 == opcodes_mi[opcode].opcode) { + unsigned int i; + + instr_out(ctx, 0, "%s\n", + opcodes_mi[opcode].name); + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "MI UNKNOWN\n"); + return 1; +} + +static void +decode_2d_br00(struct drm_intel_decode *ctx, const char *cmd) +{ + instr_out(ctx, 0, + "%s (rgb %sabled, alpha %sabled, src tile %d, dst tile %d)\n", + cmd, + (ctx->data[0] & (1 << 20)) ? "en" : "dis", + (ctx->data[0] & (1 << 21)) ? "en" : "dis", + (ctx->data[0] >> 15) & 1, + (ctx->data[0] >> 11) & 1); +} + +static void +decode_2d_br01(struct drm_intel_decode *ctx) +{ + const char *format; + switch ((ctx->data[1] >> 24) & 0x3) { + case 0: + format = "8"; + break; + case 1: + format = "565"; + break; + case 2: + format = "1555"; + break; + case 3: + format = "8888"; + break; + } + + instr_out(ctx, 1, + "format %s, pitch %d, rop 0x%02x, " + "clipping %sabled, %s%s \n", + format, + (short)(ctx->data[1] & 0xffff), + (ctx->data[1] >> 16) & 0xff, + ctx->data[1] & (1 << 30) ? "en" : "dis", + ctx->data[1] & (1 << 31) ? "solid pattern enabled, " : "", + ctx->data[1] & (1 << 31) ? + "mono pattern transparency enabled, " : ""); + +} + +static int +decode_2d(struct drm_intel_decode *ctx) +{ + unsigned int opcode, len; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_2d[] = { + { 0x40, 5, 5, "COLOR_BLT" }, + { 0x43, 6, 6, "SRC_COPY_BLT" }, + { 0x01, 8, 8, "XY_SETUP_BLT" }, + { 0x11, 9, 9, "XY_SETUP_MONO_PATTERN_SL_BLT" }, + { 0x03, 3, 3, "XY_SETUP_CLIP_BLT" }, + { 0x24, 2, 2, "XY_PIXEL_BLT" }, + { 0x25, 3, 3, "XY_SCANLINES_BLT" }, + { 0x26, 4, 4, "Y_TEXT_BLT" }, + { 0x31, 5, 134, "XY_TEXT_IMMEDIATE_BLT" }, + { 0x50, 6, 6, "XY_COLOR_BLT" }, + { 0x51, 6, 6, "XY_PAT_BLT" }, + { 0x76, 8, 8, "XY_PAT_CHROMA_BLT" }, + { 0x72, 7, 135, "XY_PAT_BLT_IMMEDIATE" }, + { 0x77, 9, 137, "XY_PAT_CHROMA_BLT_IMMEDIATE" }, + { 0x52, 9, 9, "XY_MONO_PAT_BLT" }, + { 0x59, 7, 7, "XY_MONO_PAT_FIXED_BLT" }, + { 0x53, 8, 8, "XY_SRC_COPY_BLT" }, + { 0x54, 8, 8, "XY_MONO_SRC_COPY_BLT" }, + { 0x71, 9, 137, "XY_MONO_SRC_COPY_IMMEDIATE_BLT" }, + { 0x55, 9, 9, "XY_FULL_BLT" }, + { 0x55, 9, 137, "XY_FULL_IMMEDIATE_PATTERN_BLT" }, + { 0x56, 9, 9, "XY_FULL_MONO_SRC_BLT" }, + { 0x75, 10, 138, "XY_FULL_MONO_SRC_IMMEDIATE_PATTERN_BLT" }, + { 0x57, 12, 12, "XY_FULL_MONO_PATTERN_BLT" }, + { 0x58, 12, 12, "XY_FULL_MONO_PATTERN_MONO_SRC_BLT"}, + }; + + switch ((data[0] & 0x1fc00000) >> 22) { + case 0x25: + instr_out(ctx, 0, + "XY_SCANLINES_BLT (pattern seed (%d, %d), dst tile %d)\n", + (data[0] >> 12) & 0x8, + (data[0] >> 8) & 0x8, (data[0] >> 11) & 1); + + len = (data[0] & 0x000000ff) + 2; + if (len != 3) + fprintf(out, "Bad count in XY_SCANLINES_BLT\n"); + + instr_out(ctx, 1, "dest (%d,%d)\n", + data[1] & 0xffff, data[1] >> 16); + instr_out(ctx, 2, "dest (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + return len; + case 0x01: + decode_2d_br00(ctx, "XY_SETUP_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 8) + fprintf(out, "Bad count in XY_SETUP_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "cliprect (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "setup dst offset 0x%08x\n", + data[4]); + instr_out(ctx, 5, "setup background color\n"); + instr_out(ctx, 6, "setup foreground color\n"); + instr_out(ctx, 7, "color pattern offset\n"); + return len; + case 0x03: + decode_2d_br00(ctx, "XY_SETUP_CLIP_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 3) + fprintf(out, "Bad count in XY_SETUP_CLIP_BLT\n"); + + instr_out(ctx, 1, "cliprect (%d,%d)\n", + data[1] & 0xffff, data[2] >> 16); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[3] >> 16); + return len; + case 0x11: + decode_2d_br00(ctx, "XY_SETUP_MONO_PATTERN_SL_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 9) + fprintf(out, + "Bad count in XY_SETUP_MONO_PATTERN_SL_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "cliprect (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "cliprect (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "setup dst offset 0x%08x\n", + data[4]); + instr_out(ctx, 5, "setup background color\n"); + instr_out(ctx, 6, "setup foreground color\n"); + instr_out(ctx, 7, "mono pattern dw0\n"); + instr_out(ctx, 8, "mono pattern dw1\n"); + return len; + case 0x50: + decode_2d_br00(ctx, "XY_COLOR_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 6) + fprintf(out, "Bad count in XY_COLOR_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "(%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "offset 0x%08x\n", data[4]); + instr_out(ctx, 5, "color\n"); + return len; + case 0x53: + decode_2d_br00(ctx, "XY_SRC_COPY_BLT"); + + len = (data[0] & 0x000000ff) + 2; + if (len != 8) + fprintf(out, "Bad count in XY_SRC_COPY_BLT\n"); + + decode_2d_br01(ctx); + instr_out(ctx, 2, "dst (%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "dst (%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "dst offset 0x%08x\n", data[4]); + instr_out(ctx, 5, "src (%d,%d)\n", + data[5] & 0xffff, data[5] >> 16); + instr_out(ctx, 6, "src pitch %d\n", + (short)(data[6] & 0xffff)); + instr_out(ctx, 7, "src offset 0x%08x\n", data[7]); + return len; + } + + for (opcode = 0; opcode < sizeof(opcodes_2d) / sizeof(opcodes_2d[0]); + opcode++) { + if ((data[0] & 0x1fc00000) >> 22 == opcodes_2d[opcode].opcode) { + unsigned int i; + + len = 1; + instr_out(ctx, 0, "%s\n", + opcodes_2d[opcode].name); + if (opcodes_2d[opcode].max_len > 1) { + len = (data[0] & 0x000000ff) + 2; + if (len < opcodes_2d[opcode].min_len || + len > opcodes_2d[opcode].max_len) { + fprintf(out, "Bad count in %s\n", + opcodes_2d[opcode].name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "2D UNKNOWN\n"); + return 1; +} + +static int +decode_3d_1c(struct drm_intel_decode *ctx) +{ + uint32_t *data = ctx->data; + uint32_t opcode; + + opcode = (data[0] & 0x00f80000) >> 19; + + switch (opcode) { + case 0x11: + instr_out(ctx, 0, + "3DSTATE_DEPTH_SUBRECTANGLE_DISABLE\n"); + return 1; + case 0x10: + instr_out(ctx, 0, "3DSTATE_SCISSOR_ENABLE %s\n", + data[0] & 1 ? "enabled" : "disabled"); + return 1; + case 0x01: + instr_out(ctx, 0, "3DSTATE_MAP_COORD_SET_I830\n"); + return 1; + case 0x0a: + instr_out(ctx, 0, "3DSTATE_MAP_CUBE_I830\n"); + return 1; + case 0x05: + instr_out(ctx, 0, "3DSTATE_MAP_TEX_STREAM_I830\n"); + return 1; + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_1c opcode = 0x%x\n", + opcode); + return 1; +} + +/** Sets the string dstname to describe the destination of the PS instruction */ +static void +i915_get_instruction_dst(uint32_t *data, int i, char *dstname, int do_mask) +{ + uint32_t a0 = data[i]; + int dst_nr = (a0 >> 14) & 0xf; + char dstmask[8]; + const char *sat; + + if (do_mask) { + if (((a0 >> 10) & 0xf) == 0xf) { + dstmask[0] = 0; + } else { + int dstmask_index = 0; + + dstmask[dstmask_index++] = '.'; + if (a0 & (1 << 10)) + dstmask[dstmask_index++] = 'x'; + if (a0 & (1 << 11)) + dstmask[dstmask_index++] = 'y'; + if (a0 & (1 << 12)) + dstmask[dstmask_index++] = 'z'; + if (a0 & (1 << 13)) + dstmask[dstmask_index++] = 'w'; + dstmask[dstmask_index++] = 0; + } + + if (a0 & (1 << 22)) + sat = ".sat"; + else + sat = ""; + } else { + dstmask[0] = 0; + sat = ""; + } + + switch ((a0 >> 19) & 0x7) { + case 0: + if (dst_nr > 15) + fprintf(out, "bad destination reg R%d\n", dst_nr); + sprintf(dstname, "R%d%s%s", dst_nr, dstmask, sat); + break; + case 4: + if (dst_nr > 0) + fprintf(out, "bad destination reg oC%d\n", dst_nr); + sprintf(dstname, "oC%s%s", dstmask, sat); + break; + case 5: + if (dst_nr > 0) + fprintf(out, "bad destination reg oD%d\n", dst_nr); + sprintf(dstname, "oD%s%s", dstmask, sat); + break; + case 6: + if (dst_nr > 3) + fprintf(out, "bad destination reg U%d\n", dst_nr); + sprintf(dstname, "U%d%s%s", dst_nr, dstmask, sat); + break; + default: + sprintf(dstname, "RESERVED"); + break; + } +} + +static const char * +i915_get_channel_swizzle(uint32_t select) +{ + switch (select & 0x7) { + case 0: + return (select & 8) ? "-x" : "x"; + case 1: + return (select & 8) ? "-y" : "y"; + case 2: + return (select & 8) ? "-z" : "z"; + case 3: + return (select & 8) ? "-w" : "w"; + case 4: + return (select & 8) ? "-0" : "0"; + case 5: + return (select & 8) ? "-1" : "1"; + default: + return (select & 8) ? "-bad" : "bad"; + } +} + +static void +i915_get_instruction_src_name(uint32_t src_type, uint32_t src_nr, char *name) +{ + switch (src_type) { + case 0: + sprintf(name, "R%d", src_nr); + if (src_nr > 15) + fprintf(out, "bad src reg %s\n", name); + break; + case 1: + if (src_nr < 8) + sprintf(name, "T%d", src_nr); + else if (src_nr == 8) + sprintf(name, "DIFFUSE"); + else if (src_nr == 9) + sprintf(name, "SPECULAR"); + else if (src_nr == 10) + sprintf(name, "FOG"); + else { + fprintf(out, "bad src reg T%d\n", src_nr); + sprintf(name, "RESERVED"); + } + break; + case 2: + sprintf(name, "C%d", src_nr); + if (src_nr > 31) + fprintf(out, "bad src reg %s\n", name); + break; + case 4: + sprintf(name, "oC"); + if (src_nr > 0) + fprintf(out, "bad src reg oC%d\n", src_nr); + break; + case 5: + sprintf(name, "oD"); + if (src_nr > 0) + fprintf(out, "bad src reg oD%d\n", src_nr); + break; + case 6: + sprintf(name, "U%d", src_nr); + if (src_nr > 3) + fprintf(out, "bad src reg %s\n", name); + break; + default: + fprintf(out, "bad src reg type %d\n", src_type); + sprintf(name, "RESERVED"); + break; + } +} + +static void i915_get_instruction_src0(uint32_t *data, int i, char *srcname) +{ + uint32_t a0 = data[i]; + uint32_t a1 = data[i + 1]; + int src_nr = (a0 >> 2) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a1 >> 28) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a1 >> 24) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a1 >> 20) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a1 >> 16) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a0 >> 7) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void i915_get_instruction_src1(uint32_t *data, int i, char *srcname) +{ + uint32_t a1 = data[i + 1]; + uint32_t a2 = data[i + 2]; + int src_nr = (a1 >> 8) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a1 >> 4) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a1 >> 0) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a2 >> 28) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a2 >> 24) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a1 >> 13) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void i915_get_instruction_src2(uint32_t *data, int i, char *srcname) +{ + uint32_t a2 = data[i + 2]; + int src_nr = (a2 >> 16) & 0x1f; + const char *swizzle_x = i915_get_channel_swizzle((a2 >> 12) & 0xf); + const char *swizzle_y = i915_get_channel_swizzle((a2 >> 8) & 0xf); + const char *swizzle_z = i915_get_channel_swizzle((a2 >> 4) & 0xf); + const char *swizzle_w = i915_get_channel_swizzle((a2 >> 0) & 0xf); + char swizzle[100]; + + i915_get_instruction_src_name((a2 >> 21) & 0x7, src_nr, srcname); + sprintf(swizzle, ".%s%s%s%s", swizzle_x, swizzle_y, swizzle_z, + swizzle_w); + if (strcmp(swizzle, ".xyzw") != 0) + strcat(srcname, swizzle); +} + +static void +i915_get_instruction_addr(uint32_t src_type, uint32_t src_nr, char *name) +{ + switch (src_type) { + case 0: + sprintf(name, "R%d", src_nr); + if (src_nr > 15) + fprintf(out, "bad src reg %s\n", name); + break; + case 1: + if (src_nr < 8) + sprintf(name, "T%d", src_nr); + else if (src_nr == 8) + sprintf(name, "DIFFUSE"); + else if (src_nr == 9) + sprintf(name, "SPECULAR"); + else if (src_nr == 10) + sprintf(name, "FOG"); + else { + fprintf(out, "bad src reg T%d\n", src_nr); + sprintf(name, "RESERVED"); + } + break; + case 4: + sprintf(name, "oC"); + if (src_nr > 0) + fprintf(out, "bad src reg oC%d\n", src_nr); + break; + case 5: + sprintf(name, "oD"); + if (src_nr > 0) + fprintf(out, "bad src reg oD%d\n", src_nr); + break; + default: + fprintf(out, "bad src reg type %d\n", src_type); + sprintf(name, "RESERVED"); + break; + } +} + +static void +i915_decode_alu1(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + + instr_out(ctx, i++, "%s: %s %s, %s\n", instr_prefix, + op_name, dst, src0); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_alu2(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100], src1[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + i915_get_instruction_src1(ctx->data, i, src1); + + instr_out(ctx, i++, "%s: %s %s, %s, %s\n", instr_prefix, + op_name, dst, src0, src1); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_alu3(struct drm_intel_decode *ctx, + int i, char *instr_prefix, const char *op_name) +{ + char dst[100], src0[100], src1[100], src2[100]; + + i915_get_instruction_dst(ctx->data, i, dst, 1); + i915_get_instruction_src0(ctx->data, i, src0); + i915_get_instruction_src1(ctx->data, i, src1); + i915_get_instruction_src2(ctx->data, i, src2); + + instr_out(ctx, i++, "%s: %s %s, %s, %s, %s\n", instr_prefix, + op_name, dst, src0, src1, src2); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_tex(struct drm_intel_decode *ctx, int i, + const char *instr_prefix, const char *tex_name) +{ + uint32_t t0 = ctx->data[i]; + uint32_t t1 = ctx->data[i + 1]; + char dst_name[100]; + char addr_name[100]; + int sampler_nr; + + i915_get_instruction_dst(ctx->data, i, dst_name, 0); + i915_get_instruction_addr((t1 >> 24) & 0x7, + (t1 >> 17) & 0xf, addr_name); + sampler_nr = t0 & 0xf; + + instr_out(ctx, i++, "%s: %s %s, S%d, %s\n", instr_prefix, + tex_name, dst_name, sampler_nr, addr_name); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); +} + +static void +i915_decode_dcl(struct drm_intel_decode *ctx, int i, char *instr_prefix) +{ + uint32_t d0 = ctx->data[i]; + const char *sampletype; + int dcl_nr = (d0 >> 14) & 0xf; + const char *dcl_x = d0 & (1 << 10) ? "x" : ""; + const char *dcl_y = d0 & (1 << 11) ? "y" : ""; + const char *dcl_z = d0 & (1 << 12) ? "z" : ""; + const char *dcl_w = d0 & (1 << 13) ? "w" : ""; + char dcl_mask[10]; + + switch ((d0 >> 19) & 0x3) { + case 1: + sprintf(dcl_mask, ".%s%s%s%s", dcl_x, dcl_y, dcl_z, dcl_w); + if (strcmp(dcl_mask, ".") == 0) + fprintf(out, "bad (empty) dcl mask\n"); + + if (dcl_nr > 10) + fprintf(out, "bad T%d dcl register number\n", dcl_nr); + if (dcl_nr < 8) { + if (strcmp(dcl_mask, ".x") != 0 && + strcmp(dcl_mask, ".xy") != 0 && + strcmp(dcl_mask, ".xz") != 0 && + strcmp(dcl_mask, ".w") != 0 && + strcmp(dcl_mask, ".xyzw") != 0) { + fprintf(out, "bad T%d.%s dcl mask\n", dcl_nr, + dcl_mask); + } + instr_out(ctx, i++, "%s: DCL T%d%s\n", + instr_prefix, dcl_nr, dcl_mask); + } else { + if (strcmp(dcl_mask, ".xz") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + else if (strcmp(dcl_mask, ".xw") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + else if (strcmp(dcl_mask, ".xzw") == 0) + fprintf(out, "errataed bad dcl mask %s\n", + dcl_mask); + + if (dcl_nr == 8) { + instr_out(ctx, i++, + "%s: DCL DIFFUSE%s\n", instr_prefix, + dcl_mask); + } else if (dcl_nr == 9) { + instr_out(ctx, i++, + "%s: DCL SPECULAR%s\n", instr_prefix, + dcl_mask); + } else if (dcl_nr == 10) { + instr_out(ctx, i++, + "%s: DCL FOG%s\n", instr_prefix, + dcl_mask); + } + } + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + case 3: + switch ((d0 >> 22) & 0x3) { + case 0: + sampletype = "2D"; + break; + case 1: + sampletype = "CUBE"; + break; + case 2: + sampletype = "3D"; + break; + default: + sampletype = "RESERVED"; + break; + } + if (dcl_nr > 15) + fprintf(out, "bad S%d dcl register number\n", dcl_nr); + instr_out(ctx, i++, "%s: DCL S%d %s\n", + instr_prefix, dcl_nr, sampletype); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + default: + instr_out(ctx, i++, "%s: DCL RESERVED%d\n", + instr_prefix, dcl_nr); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + } +} + +static void +i915_decode_instruction(struct drm_intel_decode *ctx, + int i, char *instr_prefix) +{ + switch ((ctx->data[i] >> 24) & 0x1f) { + case 0x0: + instr_out(ctx, i++, "%s: NOP\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + case 0x01: + i915_decode_alu2(ctx, i, instr_prefix, "ADD"); + break; + case 0x02: + i915_decode_alu1(ctx, i, instr_prefix, "MOV"); + break; + case 0x03: + i915_decode_alu2(ctx, i, instr_prefix, "MUL"); + break; + case 0x04: + i915_decode_alu3(ctx, i, instr_prefix, "MAD"); + break; + case 0x05: + i915_decode_alu3(ctx, i, instr_prefix, "DP2ADD"); + break; + case 0x06: + i915_decode_alu2(ctx, i, instr_prefix, "DP3"); + break; + case 0x07: + i915_decode_alu2(ctx, i, instr_prefix, "DP4"); + break; + case 0x08: + i915_decode_alu1(ctx, i, instr_prefix, "FRC"); + break; + case 0x09: + i915_decode_alu1(ctx, i, instr_prefix, "RCP"); + break; + case 0x0a: + i915_decode_alu1(ctx, i, instr_prefix, "RSQ"); + break; + case 0x0b: + i915_decode_alu1(ctx, i, instr_prefix, "EXP"); + break; + case 0x0c: + i915_decode_alu1(ctx, i, instr_prefix, "LOG"); + break; + case 0x0d: + i915_decode_alu2(ctx, i, instr_prefix, "CMP"); + break; + case 0x0e: + i915_decode_alu2(ctx, i, instr_prefix, "MIN"); + break; + case 0x0f: + i915_decode_alu2(ctx, i, instr_prefix, "MAX"); + break; + case 0x10: + i915_decode_alu1(ctx, i, instr_prefix, "FLR"); + break; + case 0x11: + i915_decode_alu1(ctx, i, instr_prefix, "MOD"); + break; + case 0x12: + i915_decode_alu1(ctx, i, instr_prefix, "TRC"); + break; + case 0x13: + i915_decode_alu2(ctx, i, instr_prefix, "SGE"); + break; + case 0x14: + i915_decode_alu2(ctx, i, instr_prefix, "SLT"); + break; + case 0x15: + i915_decode_tex(ctx, i, instr_prefix, "TEXLD"); + break; + case 0x16: + i915_decode_tex(ctx, i, instr_prefix, "TEXLDP"); + break; + case 0x17: + i915_decode_tex(ctx, i, instr_prefix, "TEXLDB"); + break; + case 0x19: + i915_decode_dcl(ctx, i, instr_prefix); + break; + default: + instr_out(ctx, i++, "%s: unknown\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + instr_out(ctx, i++, "%s\n", instr_prefix); + break; + } +} + +static const char * +decode_compare_func(uint32_t op) +{ + switch (op & 0x7) { + case 0: + return "always"; + case 1: + return "never"; + case 2: + return "less"; + case 3: + return "equal"; + case 4: + return "lequal"; + case 5: + return "greater"; + case 6: + return "notequal"; + case 7: + return "gequal"; + } + return ""; +} + +static const char * +decode_stencil_op(uint32_t op) +{ + switch (op & 0x7) { + case 0: + return "keep"; + case 1: + return "zero"; + case 2: + return "replace"; + case 3: + return "incr_sat"; + case 4: + return "decr_sat"; + case 5: + return "greater"; + case 6: + return "incr"; + case 7: + return "decr"; + } + return ""; +} + +#if 0 +static const char * +decode_logic_op(uint32_t op) +{ + switch (op & 0xf) { + case 0: + return "clear"; + case 1: + return "nor"; + case 2: + return "and_inv"; + case 3: + return "copy_inv"; + case 4: + return "and_rvrse"; + case 5: + return "inv"; + case 6: + return "xor"; + case 7: + return "nand"; + case 8: + return "and"; + case 9: + return "equiv"; + case 10: + return "noop"; + case 11: + return "or_inv"; + case 12: + return "copy"; + case 13: + return "or_rvrse"; + case 14: + return "or"; + case 15: + return "set"; + } + return ""; +} +#endif + +static const char * +decode_blend_fact(uint32_t op) +{ + switch (op & 0xf) { + case 1: + return "zero"; + case 2: + return "one"; + case 3: + return "src_colr"; + case 4: + return "inv_src_colr"; + case 5: + return "src_alpha"; + case 6: + return "inv_src_alpha"; + case 7: + return "dst_alpha"; + case 8: + return "inv_dst_alpha"; + case 9: + return "dst_colr"; + case 10: + return "inv_dst_colr"; + case 11: + return "src_alpha_sat"; + case 12: + return "cnst_colr"; + case 13: + return "inv_cnst_colr"; + case 14: + return "cnst_alpha"; + case 15: + return "inv_const_alpha"; + } + return ""; +} + +static const char * +decode_tex_coord_mode(uint32_t mode) +{ + switch (mode & 0x7) { + case 0: + return "wrap"; + case 1: + return "mirror"; + case 2: + return "clamp_edge"; + case 3: + return "cube"; + case 4: + return "clamp_border"; + case 5: + return "mirror_once"; + } + return ""; +} + +static const char * +decode_sample_filter(uint32_t mode) +{ + switch (mode & 0x7) { + case 0: + return "nearest"; + case 1: + return "linear"; + case 2: + return "anisotropic"; + case 3: + return "4x4_1"; + case 4: + return "4x4_2"; + case 5: + return "4x4_flat"; + case 6: + return "6x5_mono"; + } + return ""; +} + +static int +decode_3d_1d(struct drm_intel_decode *ctx) +{ + unsigned int len, i, c, idx, word, map, sampler, instr; + const char *format, *zformat, *type; + uint32_t opcode; + uint32_t *data = ctx->data; + uint32_t devid = ctx->devid; + + struct { + uint32_t opcode; + int i830_only; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d_1d[] = { + { 0x86, 0, 4, 4, "3DSTATE_CHROMA_KEY" }, + { 0x88, 0, 2, 2, "3DSTATE_CONSTANT_BLEND_COLOR" }, + { 0x99, 0, 2, 2, "3DSTATE_DEFAULT_DIFFUSE" }, + { 0x9a, 0, 2, 2, "3DSTATE_DEFAULT_SPECULAR" }, + { 0x98, 0, 2, 2, "3DSTATE_DEFAULT_Z" }, + { 0x97, 0, 2, 2, "3DSTATE_DEPTH_OFFSET_SCALE" }, + { 0x9d, 0, 65, 65, "3DSTATE_FILTER_COEFFICIENTS_4X4" }, + { 0x9e, 0, 4, 4, "3DSTATE_MONO_FILTER" }, + { 0x89, 0, 4, 4, "3DSTATE_FOG_MODE" }, + { 0x8f, 0, 2, 16, "3DSTATE_MAP_PALLETE_LOAD_32" }, + { 0x83, 0, 2, 2, "3DSTATE_SPAN_STIPPLE" }, + { 0x8c, 1, 2, 2, "3DSTATE_MAP_COORD_TRANSFORM_I830" }, + { 0x8b, 1, 2, 2, "3DSTATE_MAP_VERTEX_TRANSFORM_I830" }, + { 0x8d, 1, 3, 3, "3DSTATE_W_STATE_I830" }, + { 0x01, 1, 2, 2, "3DSTATE_COLOR_FACTOR_I830" }, + { 0x02, 1, 2, 2, "3DSTATE_MAP_COORD_SETBIND_I830"}, + }, *opcode_3d_1d; + + opcode = (data[0] & 0x00ff0000) >> 16; + + switch (opcode) { + case 0x07: + /* This instruction is unusual. A 0 length means just + * 1 DWORD instead of 2. The 0 length is specified in + * one place to be unsupported, but stated to be + * required in another, and 0 length LOAD_INDIRECTs + * appear to cause no harm at least. + */ + instr_out(ctx, 0, "3DSTATE_LOAD_INDIRECT\n"); + len = (data[0] & 0x000000ff) + 1; + i = 1; + if (data[0] & (0x01 << 8)) { + instr_out(ctx, i++, "SIS.0\n"); + instr_out(ctx, i++, "SIS.1\n"); + } + if (data[0] & (0x02 << 8)) { + instr_out(ctx, i++, "DIS.0\n"); + } + if (data[0] & (0x04 << 8)) { + instr_out(ctx, i++, "SSB.0\n"); + instr_out(ctx, i++, "SSB.1\n"); + } + if (data[0] & (0x08 << 8)) { + instr_out(ctx, i++, "MSB.0\n"); + instr_out(ctx, i++, "MSB.1\n"); + } + if (data[0] & (0x10 << 8)) { + instr_out(ctx, i++, "PSP.0\n"); + instr_out(ctx, i++, "PSP.1\n"); + } + if (data[0] & (0x20 << 8)) { + instr_out(ctx, i++, "PSC.0\n"); + instr_out(ctx, i++, "PSC.1\n"); + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_LOAD_INDIRECT\n"); + return len; + } + return len; + case 0x04: + instr_out(ctx, 0, + "3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); + len = (data[0] & 0x0000000f) + 2; + i = 1; + for (word = 0; word <= 8; word++) { + if (data[0] & (1 << (4 + word))) { + /* save vertex state for decode */ + if (!IS_GEN2(devid)) { + int tex_num; + + if (word == 2) { + saved_s2_set = 1; + saved_s2 = data[i]; + } + if (word == 4) { + saved_s4_set = 1; + saved_s4 = data[i]; + } + + switch (word) { + case 0: + instr_out(ctx, i, + "S0: vbo offset: 0x%08x%s\n", + data[i] & (~1), + data[i] & 1 ? + ", auto cache invalidate disabled" + : ""); + break; + case 1: + instr_out(ctx, i, + "S1: vertex width: %i, vertex pitch: %i\n", + (data[i] >> 24) & + 0x3f, + (data[i] >> 16) & + 0x3f); + break; + case 2: + instr_out(ctx, i, + "S2: texcoord formats: "); + for (tex_num = 0; + tex_num < 8; tex_num++) { + switch ((data[i] >> + tex_num * + 4) & 0xf) { + case 0: + fprintf(out, + "%i=2D ", + tex_num); + break; + case 1: + fprintf(out, + "%i=3D ", + tex_num); + break; + case 2: + fprintf(out, + "%i=4D ", + tex_num); + break; + case 3: + fprintf(out, + "%i=1D ", + tex_num); + break; + case 4: + fprintf(out, + "%i=2D_16 ", + tex_num); + break; + case 5: + fprintf(out, + "%i=4D_16 ", + tex_num); + break; + case 0xf: + fprintf(out, + "%i=NP ", + tex_num); + break; + } + } + fprintf(out, "\n"); + + break; + case 3: + instr_out(ctx, i, + "S3: not documented\n"); + break; + case 4: + { + const char *cullmode = ""; + const char *vfmt_xyzw = ""; + switch ((data[i] >> 13) + & 0x3) { + case 0: + cullmode = + "both"; + break; + case 1: + cullmode = + "none"; + break; + case 2: + cullmode = "cw"; + break; + case 3: + cullmode = + "ccw"; + break; + } + switch (data[i] & + (7 << 6 | 1 << + 2)) { + case 1 << 6: + vfmt_xyzw = + "XYZ,"; + break; + case 2 << 6: + vfmt_xyzw = + "XYZW,"; + break; + case 3 << 6: + vfmt_xyzw = + "XY,"; + break; + case 4 << 6: + vfmt_xyzw = + "XYW,"; + break; + case 1 << 6 | 1 << 2: + vfmt_xyzw = + "XYZF,"; + break; + case 2 << 6 | 1 << 2: + vfmt_xyzw = + "XYZWF,"; + break; + case 3 << 6 | 1 << 2: + vfmt_xyzw = + "XYF,"; + break; + case 4 << 6 | 1 << 2: + vfmt_xyzw = + "XYWF,"; + break; + } + instr_out(ctx, i, + "S4: point_width=%i, line_width=%.1f," + "%s%s%s%s%s cullmode=%s, vfmt=%s%s%s%s%s%s " + "%s%s%s%s%s\n", + (data[i] >> + 23) & 0x1ff, + ((data[i] >> + 19) & 0xf) / + 2.0, + data[i] & (0xf + << + 15) + ? + " flatshade=" + : "", + data[i] & (1 + << + 18) + ? "Alpha," : + "", + data[i] & (1 + << + 17) + ? "Fog," : "", + data[i] & (1 + << + 16) + ? "Specular," + : "", + data[i] & (1 + << + 15) + ? "Color," : + "", cullmode, + data[i] & (1 + << + 12) + ? + "PointWidth," + : "", + data[i] & (1 + << + 11) + ? "SpecFog," : + "", + data[i] & (1 + << + 10) + ? "Color," : + "", + data[i] & (1 + << + 9) + ? "DepthOfs," + : "", + vfmt_xyzw, + data[i] & (1 + << + 9) + ? "FogParam," + : "", + data[i] & (1 + << + 5) + ? + "force default diffuse, " + : "", + data[i] & (1 + << + 4) + ? + "force default specular, " + : "", + data[i] & (1 + << + 3) + ? + "local depth ofs enable, " + : "", + data[i] & (1 + << + 1) + ? + "point sprite enable, " + : "", + data[i] & (1 + << + 0) + ? + "line AA enable, " + : ""); + break; + } + case 5: + { + instr_out(ctx, i, + "S5:%s%s%s%s%s" + "%s%s%s%s stencil_ref=0x%x, stencil_test=%s, " + "stencil_fail=%s, stencil_pass_z_fail=%s, " + "stencil_pass_z_pass=%s, %s%s%s%s\n", + data[i] & (0xf + << + 28) + ? + " write_disable=" + : "", + data[i] & (1 + << + 31) + ? "Alpha," : + "", + data[i] & (1 + << + 30) + ? "Red," : "", + data[i] & (1 + << + 29) + ? "Green," : + "", + data[i] & (1 + << + 28) + ? "Blue," : + "", + data[i] & (1 + << + 27) + ? + " force default point size," + : "", + data[i] & (1 + << + 26) + ? + " last pixel enable," + : "", + data[i] & (1 + << + 25) + ? + " global depth ofs enable," + : "", + data[i] & (1 + << + 24) + ? + " fog enable," + : "", + (data[i] >> + 16) & 0xff, + decode_compare_func + (data[i] >> + 13), + decode_stencil_op + (data[i] >> + 10), + decode_stencil_op + (data[i] >> + 7), + decode_stencil_op + (data[i] >> + 4), + data[i] & (1 + << + 3) + ? + "stencil write enable, " + : "", + data[i] & (1 + << + 2) + ? + "stencil test enable, " + : "", + data[i] & (1 + << + 1) + ? + "color dither enable, " + : "", + data[i] & (1 + << + 0) + ? + "logicop enable, " + : ""); + } + break; + case 6: + instr_out(ctx, i, + "S6: %salpha_test=%s, alpha_ref=0x%x, " + "depth_test=%s, %ssrc_blnd_fct=%s, dst_blnd_fct=%s, " + "%s%stristrip_provoking_vertex=%i\n", + data[i] & (1 << 31) ? + "alpha test enable, " + : "", + decode_compare_func + (data[i] >> 28), + data[i] & (0xff << + 20), + decode_compare_func + (data[i] >> 16), + data[i] & (1 << 15) ? + "cbuf blend enable, " + : "", + decode_blend_fact(data + [i] + >> + 8), + decode_blend_fact(data + [i] + >> + 4), + data[i] & (1 << 3) ? + "depth write enable, " + : "", + data[i] & (1 << 2) ? + "cbuf write enable, " + : "", + data[i] & (0x3)); + break; + case 7: + instr_out(ctx, i, + "S7: depth offset constant: 0x%08x\n", + data[i]); + break; + } + } else { + instr_out(ctx, i, + "S%d: 0x%08x\n", i, data[i]); + } + i++; + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_1\n"); + } + return len; + case 0x03: + instr_out(ctx, 0, + "3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); + len = (data[0] & 0x0000000f) + 2; + i = 1; + for (word = 6; word <= 14; word++) { + if (data[0] & (1 << word)) { + if (word == 6) + instr_out(ctx, i++, + "TBCF\n"); + else if (word >= 7 && word <= 10) { + instr_out(ctx, i++, + "TB%dC\n", word - 7); + instr_out(ctx, i++, + "TB%dA\n", word - 7); + } else if (word >= 11 && word <= 14) { + instr_out(ctx, i, + "TM%dS0: offset=0x%08x, %s\n", + word - 11, + data[i] & 0xfffffffe, + data[i] & 1 ? "use fence" : + ""); + i++; + instr_out(ctx, i, + "TM%dS1: height=%i, width=%i, %s\n", + word - 11, data[i] >> 21, + (data[i] >> 10) & 0x3ff, + data[i] & 2 ? (data[i] & 1 ? + "y-tiled" : + "x-tiled") : + ""); + i++; + instr_out(ctx, i, + "TM%dS2: pitch=%i, \n", + word - 11, + ((data[i] >> 21) + 1) * 4); + i++; + instr_out(ctx, i++, + "TM%dS3\n", word - 11); + instr_out(ctx, i++, + "TM%dS4: dflt color\n", + word - 11); + } + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_LOAD_STATE_IMMEDIATE_2\n"); + } + return len; + case 0x00: + instr_out(ctx, 0, "3DSTATE_MAP_STATE\n"); + len = (data[0] & 0x0000003f) + 2; + instr_out(ctx, 1, "mask\n"); + + i = 2; + for (map = 0; map <= 15; map++) { + if (data[1] & (1 << map)) { + int width, height, pitch, dword; + const char *tiling; + + dword = data[i]; + instr_out(ctx, i++, + "map %d MS2 %s%s%s\n", map, + dword & (1 << 31) ? + "untrusted surface, " : "", + dword & (1 << 1) ? + "vertical line stride enable, " : "", + dword & (1 << 0) ? + "vertical ofs enable, " : ""); + + dword = data[i]; + width = ((dword >> 10) & ((1 << 11) - 1)) + 1; + height = ((dword >> 21) & ((1 << 11) - 1)) + 1; + + tiling = "none"; + if (dword & (1 << 2)) + tiling = "fenced"; + else if (dword & (1 << 1)) + tiling = dword & (1 << 0) ? "Y" : "X"; + type = " BAD"; + format = "BAD"; + switch ((dword >> 7) & 0x7) { + case 1: + type = "8b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = "I"; + break; + case 1: + format = "L"; + break; + case 4: + format = "A"; + break; + case 5: + format = " mono"; + break; + } + break; + case 2: + type = "16b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " rgb565"; + break; + case 1: + format = " argb1555"; + break; + case 2: + format = " argb4444"; + break; + case 5: + format = " ay88"; + break; + case 6: + format = " bump655"; + break; + case 7: + format = "I"; + break; + case 8: + format = "L"; + break; + case 9: + format = "A"; + break; + } + break; + case 3: + type = "32b"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " argb8888"; + break; + case 1: + format = " abgr8888"; + break; + case 2: + format = " xrgb8888"; + break; + case 3: + format = " xbgr8888"; + break; + case 4: + format = " qwvu8888"; + break; + case 5: + format = " axvu8888"; + break; + case 6: + format = " lxvu8888"; + break; + case 7: + format = " xlvu8888"; + break; + case 8: + format = " argb2101010"; + break; + case 9: + format = " abgr2101010"; + break; + case 10: + format = " awvu2101010"; + break; + case 11: + format = " gr1616"; + break; + case 12: + format = " vu1616"; + break; + case 13: + format = " xI824"; + break; + case 14: + format = " xA824"; + break; + case 15: + format = " xL824"; + break; + } + break; + case 5: + type = "422"; + switch ((dword >> 3) & 0xf) { + case 0: + format = " yuv_swapy"; + break; + case 1: + format = " yuv"; + break; + case 2: + format = " yuv_swapuv"; + break; + case 3: + format = " yuv_swapuvy"; + break; + } + break; + case 6: + type = "compressed"; + switch ((dword >> 3) & 0x7) { + case 0: + format = " dxt1"; + break; + case 1: + format = " dxt2_3"; + break; + case 2: + format = " dxt4_5"; + break; + case 3: + format = " fxt1"; + break; + case 4: + format = " dxt1_rb"; + break; + } + break; + case 7: + type = "4b indexed"; + switch ((dword >> 3) & 0xf) { + case 7: + format = " argb8888"; + break; + } + break; + } + dword = data[i]; + instr_out(ctx, i++, + "map %d MS3 [width=%d, height=%d, format=%s%s, tiling=%s%s]\n", + map, width, height, type, format, + tiling, + dword & (1 << 9) ? " palette select" : + ""); + + dword = data[i]; + pitch = + 4 * (((dword >> 21) & ((1 << 11) - 1)) + 1); + instr_out(ctx, i++, + "map %d MS4 [pitch=%d, max_lod=%i, vol_depth=%i, cube_face_ena=%x, %s]\n", + map, pitch, (dword >> 9) & 0x3f, + dword & 0xff, (dword >> 15) & 0x3f, + dword & (1 << 8) ? "miplayout legacy" + : "miplayout right"); + } + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_MAP_STATE\n"); + return len; + } + return len; + case 0x06: + instr_out(ctx, 0, + "3DSTATE_PIXEL_SHADER_CONSTANTS\n"); + len = (data[0] & 0x000000ff) + 2; + + i = 2; + for (c = 0; c <= 31; c++) { + if (data[1] & (1 << c)) { + instr_out(ctx, i, "C%d.X = %f\n", c, + int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.Y = %f\n", + c, int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.Z = %f\n", + c, int_as_float(data[i])); + i++; + instr_out(ctx, i, "C%d.W = %f\n", + c, int_as_float(data[i])); + i++; + } + } + if (len != i) { + fprintf(out, + "Bad count in 3DSTATE_PIXEL_SHADER_CONSTANTS\n"); + } + return len; + case 0x05: + instr_out(ctx, 0, "3DSTATE_PIXEL_SHADER_PROGRAM\n"); + len = (data[0] & 0x000000ff) + 2; + if ((len - 1) % 3 != 0 || len > 370) { + fprintf(out, + "Bad count in 3DSTATE_PIXEL_SHADER_PROGRAM\n"); + } + i = 1; + for (instr = 0; instr < (len - 1) / 3; instr++) { + char instr_prefix[10]; + + sprintf(instr_prefix, "PS%03d", instr); + i915_decode_instruction(ctx, i, + instr_prefix); + i += 3; + } + return len; + case 0x01: + if (IS_GEN2(devid)) + break; + instr_out(ctx, 0, "3DSTATE_SAMPLER_STATE\n"); + instr_out(ctx, 1, "mask\n"); + len = (data[0] & 0x0000003f) + 2; + i = 2; + for (sampler = 0; sampler <= 15; sampler++) { + if (data[1] & (1 << sampler)) { + uint32_t dword; + const char *mip_filter = ""; + + dword = data[i]; + switch ((dword >> 20) & 0x3) { + case 0: + mip_filter = "none"; + break; + case 1: + mip_filter = "nearest"; + break; + case 3: + mip_filter = "linear"; + break; + } + instr_out(ctx, i++, + "sampler %d SS2:%s%s%s " + "base_mip_level=%i, mip_filter=%s, mag_filter=%s, min_filter=%s " + "lod_bias=%.2f,%s max_aniso=%i, shadow_func=%s\n", + sampler, + dword & (1 << 31) ? " reverse gamma," + : "", + dword & (1 << 30) ? " packed2planar," + : "", + dword & (1 << 29) ? + " colorspace conversion," : "", + (dword >> 22) & 0x1f, mip_filter, + decode_sample_filter(dword >> 17), + decode_sample_filter(dword >> 14), + ((dword >> 5) & 0x1ff) / (0x10 * 1.0), + dword & (1 << 4) ? " shadow," : "", + dword & (1 << 3) ? 4 : 2, + decode_compare_func(dword)); + dword = data[i]; + instr_out(ctx, i++, + "sampler %d SS3: min_lod=%.2f,%s " + "tcmode_x=%s, tcmode_y=%s, tcmode_z=%s,%s texmap_idx=%i,%s\n", + sampler, + ((dword >> 24) & 0xff) / (0x10 * 1.0), + dword & (1 << 17) ? + " kill pixel enable," : "", + decode_tex_coord_mode(dword >> 12), + decode_tex_coord_mode(dword >> 9), + decode_tex_coord_mode(dword >> 6), + dword & (1 << 5) ? + " normalized coords," : "", + (dword >> 1) & 0xf, + dword & (1 << 0) ? " deinterlacer," : + ""); + dword = data[i]; + instr_out(ctx, i++, + "sampler %d SS4: border color\n", + sampler); + } + } + if (len != i) { + fprintf(out, "Bad count in 3DSTATE_SAMPLER_STATE\n"); + } + return len; + case 0x85: + len = (data[0] & 0x0000000f) + 2; + + if (len != 2) + fprintf(out, + "Bad count in 3DSTATE_DEST_BUFFER_VARIABLES\n"); + + instr_out(ctx, 0, + "3DSTATE_DEST_BUFFER_VARIABLES\n"); + + switch ((data[1] >> 8) & 0xf) { + case 0x0: + format = "g8"; + break; + case 0x1: + format = "x1r5g5b5"; + break; + case 0x2: + format = "r5g6b5"; + break; + case 0x3: + format = "a8r8g8b8"; + break; + case 0x4: + format = "ycrcb_swapy"; + break; + case 0x5: + format = "ycrcb_normal"; + break; + case 0x6: + format = "ycrcb_swapuv"; + break; + case 0x7: + format = "ycrcb_swapuvy"; + break; + case 0x8: + format = "a4r4g4b4"; + break; + case 0x9: + format = "a1r5g5b5"; + break; + case 0xa: + format = "a2r10g10b10"; + break; + default: + format = "BAD"; + break; + } + switch ((data[1] >> 2) & 0x3) { + case 0x0: + zformat = "u16"; + break; + case 0x1: + zformat = "f16"; + break; + case 0x2: + zformat = "u24x8"; + break; + default: + zformat = "BAD"; + break; + } + instr_out(ctx, 1, + "%s format, %s depth format, early Z %sabled\n", + format, zformat, + (data[1] & (1 << 31)) ? "en" : "dis"); + return len; + + case 0x8e: + { + const char *name, *tiling; + + len = (data[0] & 0x0000000f) + 2; + if (len != 3) + fprintf(out, + "Bad count in 3DSTATE_BUFFER_INFO\n"); + + switch ((data[1] >> 24) & 0x7) { + case 0x3: + name = "color"; + break; + case 0x7: + name = "depth"; + break; + default: + name = "unknown"; + break; + } + + tiling = "none"; + if (data[1] & (1 << 23)) + tiling = "fenced"; + else if (data[1] & (1 << 22)) + tiling = data[1] & (1 << 21) ? "Y" : "X"; + + instr_out(ctx, 0, "3DSTATE_BUFFER_INFO\n"); + instr_out(ctx, 1, + "%s, tiling = %s, pitch=%d\n", name, tiling, + data[1] & 0xffff); + + instr_out(ctx, 2, "address\n"); + return len; + } + case 0x81: + len = (data[0] & 0x0000000f) + 2; + + if (len != 3) + fprintf(out, + "Bad count in 3DSTATE_SCISSOR_RECTANGLE\n"); + + instr_out(ctx, 0, "3DSTATE_SCISSOR_RECTANGLE\n"); + instr_out(ctx, 1, "(%d,%d)\n", + data[1] & 0xffff, data[1] >> 16); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + + return len; + case 0x80: + len = (data[0] & 0x0000000f) + 2; + + if (len != 5) + fprintf(out, + "Bad count in 3DSTATE_DRAWING_RECTANGLE\n"); + + instr_out(ctx, 0, "3DSTATE_DRAWING_RECTANGLE\n"); + instr_out(ctx, 1, "%s\n", + data[1] & (1 << 30) ? "depth ofs disabled " : ""); + instr_out(ctx, 2, "(%d,%d)\n", + data[2] & 0xffff, data[2] >> 16); + instr_out(ctx, 3, "(%d,%d)\n", + data[3] & 0xffff, data[3] >> 16); + instr_out(ctx, 4, "(%d,%d)\n", + data[4] & 0xffff, data[4] >> 16); + + return len; + case 0x9c: + len = (data[0] & 0x0000000f) + 2; + + if (len != 7) + fprintf(out, "Bad count in 3DSTATE_CLEAR_PARAMETERS\n"); + + instr_out(ctx, 0, "3DSTATE_CLEAR_PARAMETERS\n"); + instr_out(ctx, 1, "prim_type=%s, clear=%s%s%s\n", + data[1] & (1 << 16) ? "CLEAR_RECT" : "ZONE_INIT", + data[1] & (1 << 2) ? "color," : "", + data[1] & (1 << 1) ? "depth," : "", + data[1] & (1 << 0) ? "stencil," : ""); + instr_out(ctx, 2, "clear color\n"); + instr_out(ctx, 3, "clear depth/stencil\n"); + instr_out(ctx, 4, "color value (rgba8888)\n"); + instr_out(ctx, 5, "depth value %f\n", + int_as_float(data[5])); + instr_out(ctx, 6, "clear stencil\n"); + return len; + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d_1d); idx++) { + opcode_3d_1d = &opcodes_3d_1d[idx]; + if (opcode_3d_1d->i830_only && !IS_GEN2(devid)) + continue; + + if (((data[0] & 0x00ff0000) >> 16) == opcode_3d_1d->opcode) { + len = 1; + + instr_out(ctx, 0, "%s\n", + opcode_3d_1d->name); + if (opcode_3d_1d->max_len > 1) { + len = (data[0] & 0x0000ffff) + 2; + if (len < opcode_3d_1d->min_len || + len > opcode_3d_1d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d_1d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_1d opcode = 0x%x\n", + opcode); + return 1; +} + +static int +decode_3d_primitive(struct drm_intel_decode *ctx) +{ + uint32_t *data = ctx->data; + uint32_t count = ctx->count; + char immediate = (data[0] & (1 << 23)) == 0; + unsigned int len, i, j, ret; + const char *primtype; + int original_s2 = saved_s2; + int original_s4 = saved_s4; + + switch ((data[0] >> 18) & 0xf) { + case 0x0: + primtype = "TRILIST"; + break; + case 0x1: + primtype = "TRISTRIP"; + break; + case 0x2: + primtype = "TRISTRIP_REVERSE"; + break; + case 0x3: + primtype = "TRIFAN"; + break; + case 0x4: + primtype = "POLYGON"; + break; + case 0x5: + primtype = "LINELIST"; + break; + case 0x6: + primtype = "LINESTRIP"; + break; + case 0x7: + primtype = "RECTLIST"; + break; + case 0x8: + primtype = "POINTLIST"; + break; + case 0x9: + primtype = "DIB"; + break; + case 0xa: + primtype = "CLEAR_RECT"; + saved_s4 = 3 << 6; + saved_s2 = ~0; + break; + default: + primtype = "unknown"; + break; + } + + /* XXX: 3DPRIM_DIB not supported */ + if (immediate) { + len = (data[0] & 0x0003ffff) + 2; + instr_out(ctx, 0, "3DPRIMITIVE inline %s\n", + primtype); + if (count < len) + BUFFER_FAIL(count, len, "3DPRIMITIVE inline"); + if (!saved_s2_set || !saved_s4_set) { + fprintf(out, "unknown vertex format\n"); + for (i = 1; i < len; i++) { + instr_out(ctx, i, + " vertex data (%f float)\n", + int_as_float(data[i])); + } + } else { + unsigned int vertex = 0; + for (i = 1; i < len;) { + unsigned int tc; + +#define VERTEX_OUT(fmt, ...) do { \ + if (i < len) \ + instr_out(ctx, i, " V%d."fmt"\n", vertex, __VA_ARGS__); \ + else \ + fprintf(out, " missing data in V%d\n", vertex); \ + i++; \ +} while (0) + + VERTEX_OUT("X = %f", int_as_float(data[i])); + VERTEX_OUT("Y = %f", int_as_float(data[i])); + switch (saved_s4 >> 6 & 0x7) { + case 0x1: + VERTEX_OUT("Z = %f", + int_as_float(data[i])); + break; + case 0x2: + VERTEX_OUT("Z = %f", + int_as_float(data[i])); + VERTEX_OUT("W = %f", + int_as_float(data[i])); + break; + case 0x3: + break; + case 0x4: + VERTEX_OUT("W = %f", + int_as_float(data[i])); + break; + default: + fprintf(out, "bad S4 position mask\n"); + } + + if (saved_s4 & (1 << 10)) { + VERTEX_OUT + ("color = (A=0x%02x, R=0x%02x, G=0x%02x, " + "B=0x%02x)", data[i] >> 24, + (data[i] >> 16) & 0xff, + (data[i] >> 8) & 0xff, + data[i] & 0xff); + } + if (saved_s4 & (1 << 11)) { + VERTEX_OUT + ("spec = (A=0x%02x, R=0x%02x, G=0x%02x, " + "B=0x%02x)", data[i] >> 24, + (data[i] >> 16) & 0xff, + (data[i] >> 8) & 0xff, + data[i] & 0xff); + } + if (saved_s4 & (1 << 12)) + VERTEX_OUT("width = 0x%08x)", data[i]); + + for (tc = 0; tc <= 7; tc++) { + switch ((saved_s2 >> (tc * 4)) & 0xf) { + case 0x0: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + break; + case 0x1: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Z = %f", tc, + int_as_float(data + [i])); + break; + case 0x2: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Y = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.Z = %f", tc, + int_as_float(data + [i])); + VERTEX_OUT("T%d.W = %f", tc, + int_as_float(data + [i])); + break; + case 0x3: + VERTEX_OUT("T%d.X = %f", tc, + int_as_float(data + [i])); + break; + case 0x4: + VERTEX_OUT + ("T%d.XY = 0x%08x half-float", + tc, data[i]); + break; + case 0x5: + VERTEX_OUT + ("T%d.XY = 0x%08x half-float", + tc, data[i]); + VERTEX_OUT + ("T%d.ZW = 0x%08x half-float", + tc, data[i]); + break; + case 0xf: + break; + default: + fprintf(out, + "bad S2.T%d format\n", + tc); + } + } + vertex++; + } + } + + ret = len; + } else { + /* indirect vertices */ + len = data[0] & 0x0000ffff; /* index count */ + if (data[0] & (1 << 17)) { + /* random vertex access */ + if (count < (len + 1) / 2 + 1) { + BUFFER_FAIL(count, (len + 1) / 2 + 1, + "3DPRIMITIVE random indirect"); + } + instr_out(ctx, 0, + "3DPRIMITIVE random indirect %s (%d)\n", + primtype, len); + if (len == 0) { + /* vertex indices continue until 0xffff is + * found + */ + for (i = 1; i < count; i++) { + if ((data[i] & 0xffff) == 0xffff) { + instr_out(ctx, i, + " indices: (terminator)\n"); + ret = i; + goto out; + } else if ((data[i] >> 16) == 0xffff) { + instr_out(ctx, i, + " indices: 0x%04x, (terminator)\n", + data[i] & 0xffff); + ret = i; + goto out; + } else { + instr_out(ctx, i, + " indices: 0x%04x, 0x%04x\n", + data[i] & 0xffff, + data[i] >> 16); + } + } + fprintf(out, + "3DPRIMITIVE: no terminator found in index buffer\n"); + ret = count; + goto out; + } else { + /* fixed size vertex index buffer */ + for (j = 1, i = 0; i < len; i += 2, j++) { + if (i * 2 == len - 1) { + instr_out(ctx, j, + " indices: 0x%04x\n", + data[j] & 0xffff); + } else { + instr_out(ctx, j, + " indices: 0x%04x, 0x%04x\n", + data[j] & 0xffff, + data[j] >> 16); + } + } + } + ret = (len + 1) / 2 + 1; + goto out; + } else { + /* sequential vertex access */ + instr_out(ctx, 0, + "3DPRIMITIVE sequential indirect %s, %d starting from " + "%d\n", primtype, len, data[1] & 0xffff); + instr_out(ctx, 1, " start\n"); + ret = 2; + goto out; + } + } + +out: + saved_s2 = original_s2; + saved_s4 = original_s4; + return ret; +} + +static int +decode_3d(struct drm_intel_decode *ctx) +{ + uint32_t opcode; + unsigned int idx; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d[] = { + { 0x06, 1, 1, "3DSTATE_ANTI_ALIASING" }, + { 0x08, 1, 1, "3DSTATE_BACKFACE_STENCIL_OPS" }, + { 0x09, 1, 1, "3DSTATE_BACKFACE_STENCIL_MASKS" }, + { 0x16, 1, 1, "3DSTATE_COORD_SET_BINDINGS" }, + { 0x15, 1, 1, "3DSTATE_FOG_COLOR" }, + { 0x0b, 1, 1, "3DSTATE_INDEPENDENT_ALPHA_BLEND" }, + { 0x0d, 1, 1, "3DSTATE_MODES_4" }, + { 0x0c, 1, 1, "3DSTATE_MODES_5" }, + { 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES"}, + }, *opcode_3d; + + opcode = (data[0] & 0x1f000000) >> 24; + + switch (opcode) { + case 0x1f: + return decode_3d_primitive(ctx); + case 0x1d: + return decode_3d_1d(ctx); + case 0x1c: + return decode_3d_1c(ctx); + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d); idx++) { + opcode_3d = &opcodes_3d[idx]; + if (opcode == opcode_3d->opcode) { + unsigned int len = 1, i; + + instr_out(ctx, 0, "%s\n", opcode_3d->name); + if (opcode_3d->max_len > 1) { + len = (data[0] & 0xff) + 2; + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d opcode = 0x%x\n", opcode); + return 1; +} + +static const char *get_965_surfacetype(unsigned int surfacetype) +{ + switch (surfacetype) { + case 0: + return "1D"; + case 1: + return "2D"; + case 2: + return "3D"; + case 3: + return "CUBE"; + case 4: + return "BUFFER"; + case 7: + return "NULL"; + default: + return "unknown"; + } +} + +static const char *get_965_depthformat(unsigned int depthformat) +{ + switch (depthformat) { + case 0: + return "s8_z24float"; + case 1: + return "z32float"; + case 2: + return "z24s8"; + case 5: + return "z16"; + default: + return "unknown"; + } +} + +static const char *get_965_element_component(uint32_t data, int component) +{ + uint32_t component_control = (data >> (16 + (3 - component) * 4)) & 0x7; + + switch (component_control) { + case 0: + return "nostore"; + case 1: + switch (component) { + case 0: + return "X"; + case 1: + return "Y"; + case 2: + return "Z"; + case 3: + return "W"; + default: + return "fail"; + } + case 2: + return "0.0"; + case 3: + return "1.0"; + case 4: + return "0x1"; + case 5: + return "VID"; + default: + return "fail"; + } +} + +static const char *get_965_prim_type(uint32_t primtype) +{ + switch (primtype) { + case 0x01: + return "point list"; + case 0x02: + return "line list"; + case 0x03: + return "line strip"; + case 0x04: + return "tri list"; + case 0x05: + return "tri strip"; + case 0x06: + return "tri fan"; + case 0x07: + return "quad list"; + case 0x08: + return "quad strip"; + case 0x09: + return "line list adj"; + case 0x0a: + return "line strip adj"; + case 0x0b: + return "tri list adj"; + case 0x0c: + return "tri strip adj"; + case 0x0d: + return "tri strip reverse"; + case 0x0e: + return "polygon"; + case 0x0f: + return "rect list"; + case 0x10: + return "line loop"; + case 0x11: + return "point list bf"; + case 0x12: + return "line strip cont"; + case 0x13: + return "line strip bf"; + case 0x14: + return "line strip cont bf"; + case 0x15: + return "tri fan no stipple"; + default: + return "fail"; + } +} + +static int +i965_decode_urb_fence(struct drm_intel_decode *ctx, int len) +{ + uint32_t vs_fence, clip_fence, gs_fence, sf_fence, vfe_fence, cs_fence; + uint32_t *data = ctx->data; + + if (len != 3) + fprintf(out, "Bad count in URB_FENCE\n"); + + vs_fence = data[1] & 0x3ff; + gs_fence = (data[1] >> 10) & 0x3ff; + clip_fence = (data[1] >> 20) & 0x3ff; + sf_fence = data[2] & 0x3ff; + vfe_fence = (data[2] >> 10) & 0x3ff; + cs_fence = (data[2] >> 20) & 0x7ff; + + instr_out(ctx, 0, "URB_FENCE: %s%s%s%s%s%s\n", + (data[0] >> 13) & 1 ? "cs " : "", + (data[0] >> 12) & 1 ? "vfe " : "", + (data[0] >> 11) & 1 ? "sf " : "", + (data[0] >> 10) & 1 ? "clip " : "", + (data[0] >> 9) & 1 ? "gs " : "", + (data[0] >> 8) & 1 ? "vs " : ""); + instr_out(ctx, 1, + "vs fence: %d, clip_fence: %d, gs_fence: %d\n", + vs_fence, clip_fence, gs_fence); + instr_out(ctx, 2, + "sf fence: %d, vfe_fence: %d, cs_fence: %d\n", + sf_fence, vfe_fence, cs_fence); + if (gs_fence < vs_fence) + fprintf(out, "gs fence < vs fence!\n"); + if (clip_fence < gs_fence) + fprintf(out, "clip fence < gs fence!\n"); + if (sf_fence < clip_fence) + fprintf(out, "sf fence < clip fence!\n"); + if (cs_fence < sf_fence) + fprintf(out, "cs fence < sf fence!\n"); + + return len; +} + +static void +state_base_out(struct drm_intel_decode *ctx, unsigned int index, + const char *name) +{ + if (ctx->data[index] & 1) { + instr_out(ctx, index, + "%s state base address 0x%08x\n", name, + ctx->data[index] & ~1); + } else { + instr_out(ctx, index, "%s state base not updated\n", + name); + } +} + +static void +state_max_out(struct drm_intel_decode *ctx, unsigned int index, + const char *name) +{ + if (ctx->data[index] & 1) { + if (ctx->data[index] == 1) { + instr_out(ctx, index, + "%s state upper bound disabled\n", name); + } else { + instr_out(ctx, index, + "%s state upper bound 0x%08x\n", name, + ctx->data[index] & ~1); + } + } else { + instr_out(ctx, index, + "%s state upper bound not updated\n", name); + } +} + +static int +gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_CC\n"); + instr_out(ctx, 1, "pointer to CC viewport\n"); + + return 2; +} + +static int +gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP\n"); + instr_out(ctx, 1, "pointer to SF_CLIP viewport\n"); + + return 2; +} + +static int +gen7_3DSTATE_BLEND_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_BLEND_STATE_POINTERS\n"); + instr_out(ctx, 1, "pointer to BLEND_STATE at 0x%08x (%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_DEPTH_STENCIL_STATE_POINTERS\n"); + instr_out(ctx, 1, + "pointer to DEPTH_STENCIL_STATE at 0x%08x (%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_HIER_DEPTH_BUFFER(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_HIER_DEPTH_BUFFER\n"); + instr_out(ctx, 1, "pitch %db\n", + (ctx->data[1] & 0x1ffff) + 1); + instr_out(ctx, 2, "pointer to HiZ buffer\n"); + + return 3; +} + +static int +gen6_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); + instr_out(ctx, 1, "blend change %d\n", ctx->data[1] & 1); + instr_out(ctx, 2, "depth stencil change %d\n", + ctx->data[2] & 1); + instr_out(ctx, 3, "cc change %d\n", ctx->data[3] & 1); + + return 4; +} + +static int +gen7_3DSTATE_CC_STATE_POINTERS(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_CC_STATE_POINTERS\n"); + instr_out(ctx, 1, "pointer to COLOR_CALC_STATE at 0x%08x " + "(%s)\n", + ctx->data[1] & ~1, + (ctx->data[1] & 1) ? "changed" : "unchanged"); + + return 2; +} + +static int +gen7_3DSTATE_URB_unit(struct drm_intel_decode *ctx, const char *unit) +{ + int start_kb = ((ctx->data[1] >> 25) & 0x3f) * 8; + /* the field is # of 512-bit rows - 1, we print bytes */ + int entry_size = (((ctx->data[1] >> 16) & 0x1ff) + 1); + int nr_entries = ctx->data[1] & 0xffff; + + instr_out(ctx, 0, "3DSTATE_URB_%s\n", unit); + instr_out(ctx, 1, + "%dKB start, size=%d 64B rows, nr_entries=%d, total size %dB\n", + start_kb, entry_size, nr_entries, nr_entries * 64 * entry_size); + + return 2; +} + +static int +gen7_3DSTATE_URB_VS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "VS"); +} + +static int +gen7_3DSTATE_URB_HS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "HS"); +} + +static int +gen7_3DSTATE_URB_DS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "DS"); +} + +static int +gen7_3DSTATE_URB_GS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_URB_unit(ctx, "GS"); +} + +static int +gen7_3DSTATE_CONSTANT(struct drm_intel_decode *ctx, const char *unit) +{ + int rlen[4]; + + rlen[0] = (ctx->data[1] >> 0) & 0xffff; + rlen[1] = (ctx->data[1] >> 16) & 0xffff; + rlen[2] = (ctx->data[2] >> 0) & 0xffff; + rlen[3] = (ctx->data[2] >> 16) & 0xffff; + + instr_out(ctx, 0, "3DSTATE_CONSTANT_%s\n", unit); + instr_out(ctx, 1, "len 0 = %d, len 1 = %d\n", rlen[0], rlen[1]); + instr_out(ctx, 2, "len 2 = %d, len 3 = %d\n", rlen[2], rlen[3]); + instr_out(ctx, 3, "pointer to constbuf 0\n"); + instr_out(ctx, 4, "pointer to constbuf 1\n"); + instr_out(ctx, 5, "pointer to constbuf 2\n"); + instr_out(ctx, 6, "pointer to constbuf 3\n"); + + return 7; +} + +static int +gen7_3DSTATE_CONSTANT_VS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "VS"); +} + +static int +gen7_3DSTATE_CONSTANT_GS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "GS"); +} + +static int +gen7_3DSTATE_CONSTANT_PS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "PS"); +} + +static int +gen7_3DSTATE_CONSTANT_DS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "DS"); +} + +static int +gen7_3DSTATE_CONSTANT_HS(struct drm_intel_decode *ctx) +{ + return gen7_3DSTATE_CONSTANT(ctx, "HS"); +} + + +static int +gen6_3DSTATE_WM(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, "3DSTATE_WM\n"); + instr_out(ctx, 1, "kernel start pointer 0\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", + (ctx->data[2] >> 31) & 1, + (ctx->data[2] >> 30) & 1, + (ctx->data[2] >> 27) & 7, + (ctx->data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Depth Clear %d, Depth Resolve %d, HiZ Resolve %d, " + "Dispatch GRF start[0] %d, start[1] %d, start[2] %d\n", + (ctx->data[4] & (1 << 30)) != 0, + (ctx->data[4] & (1 << 28)) != 0, + (ctx->data[4] & (1 << 27)) != 0, + (ctx->data[4] >> 16) & 0x7f, + (ctx->data[4] >> 8) & 0x7f, + (ctx->data[4] & 0x7f)); + instr_out(ctx, 5, + "MaxThreads %d, PS KillPixel %d, PS computed Z %d, " + "PS use sourceZ %d, Thread Dispatch %d, PS use sourceW %d, " + "Dispatch32 %d, Dispatch16 %d, Dispatch8 %d\n", + ((ctx->data[5] >> 25) & 0x7f) + 1, + (ctx->data[5] & (1 << 22)) != 0, + (ctx->data[5] & (1 << 21)) != 0, + (ctx->data[5] & (1 << 20)) != 0, + (ctx->data[5] & (1 << 19)) != 0, + (ctx->data[5] & (1 << 8)) != 0, + (ctx->data[5] & (1 << 2)) != 0, + (ctx->data[5] & (1 << 1)) != 0, + (ctx->data[5] & (1 << 0)) != 0); + instr_out(ctx, 6, + "Num SF output %d, Pos XY offset %d, ZW interp mode %d , " + "Barycentric interp mode 0x%x, Point raster rule %d, " + "Multisample mode %d, " + "Multisample Dispatch mode %d\n", + (ctx->data[6] >> 20) & 0x3f, + (ctx->data[6] >> 18) & 3, + (ctx->data[6] >> 16) & 3, + (ctx->data[6] >> 10) & 0x3f, + (ctx->data[6] & (1 << 9)) != 0, + (ctx->data[6] >> 1) & 3, + (ctx->data[6] & 1)); + instr_out(ctx, 7, "kernel start pointer 1\n"); + instr_out(ctx, 8, "kernel start pointer 2\n"); + + return 9; +} + +static int +gen7_3DSTATE_WM(struct drm_intel_decode *ctx) +{ + const char *computed_depth = ""; + const char *early_depth = ""; + const char *zw_interp = ""; + + switch ((ctx->data[1] >> 23) & 0x3) { + case 0: + computed_depth = ""; + break; + case 1: + computed_depth = "computed depth"; + break; + case 2: + computed_depth = "computed depth >="; + break; + case 3: + computed_depth = "computed depth <="; + break; + } + + switch ((ctx->data[1] >> 21) & 0x3) { + case 0: + early_depth = ""; + break; + case 1: + early_depth = ", EDSC_PSEXEC"; + break; + case 2: + early_depth = ", EDSC_PREPS"; + break; + case 3: + early_depth = ", BAD EDSC"; + break; + } + + switch ((ctx->data[1] >> 17) & 0x3) { + case 0: + early_depth = ""; + break; + case 1: + early_depth = ", BAD ZW interp"; + break; + case 2: + early_depth = ", ZW centroid"; + break; + case 3: + early_depth = ", ZW sample"; + break; + } + + instr_out(ctx, 0, "3DSTATE_WM\n"); + instr_out(ctx, 1, "(%s%s%s%s%s%s)%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + (ctx->data[1] & (1 << 11)) ? "PP " : "", + (ctx->data[1] & (1 << 12)) ? "PC " : "", + (ctx->data[1] & (1 << 13)) ? "PS " : "", + (ctx->data[1] & (1 << 14)) ? "NPP " : "", + (ctx->data[1] & (1 << 15)) ? "NPC " : "", + (ctx->data[1] & (1 << 16)) ? "NPS " : "", + (ctx->data[1] & (1 << 30)) ? ", depth clear" : "", + (ctx->data[1] & (1 << 29)) ? "" : ", disabled", + (ctx->data[1] & (1 << 28)) ? ", depth resolve" : "", + (ctx->data[1] & (1 << 27)) ? ", hiz resolve" : "", + (ctx->data[1] & (1 << 25)) ? ", kill" : "", + computed_depth, + early_depth, + zw_interp, + (ctx->data[1] & (1 << 20)) ? ", source depth" : "", + (ctx->data[1] & (1 << 19)) ? ", source W" : "", + (ctx->data[1] & (1 << 10)) ? ", coverage" : "", + (ctx->data[1] & (1 << 4)) ? ", poly stipple" : "", + (ctx->data[1] & (1 << 3)) ? ", line stipple" : "", + (ctx->data[1] & (1 << 2)) ? ", point UL" : ", point UR" + ); + instr_out(ctx, 2, "MS\n"); + + return 3; +} + +static int +gen4_3DPRIMITIVE(struct drm_intel_decode *ctx) +{ + instr_out(ctx, 0, + "3DPRIMITIVE: %s %s\n", + get_965_prim_type((ctx->data[0] >> 10) & 0x1f), + (ctx->data[0] & (1 << 15)) ? "random" : "sequential"); + instr_out(ctx, 1, "vertex count\n"); + instr_out(ctx, 2, "start vertex\n"); + instr_out(ctx, 3, "instance count\n"); + instr_out(ctx, 4, "start instance\n"); + instr_out(ctx, 5, "index bias\n"); + + return 6; +} + +static int +gen7_3DPRIMITIVE(struct drm_intel_decode *ctx) +{ + bool indirect = !!(ctx->data[0] & (1 << 10)); + + instr_out(ctx, 0, + "3DPRIMITIVE: %s%s\n", + indirect ? " indirect" : "", + (ctx->data[0] & (1 << 8)) ? " predicated" : ""); + instr_out(ctx, 1, "%s %s\n", + get_965_prim_type(ctx->data[1] & 0x3f), + (ctx->data[1] & (1 << 8)) ? "random" : "sequential"); + instr_out(ctx, 2, indirect ? "ignored" : "vertex count\n"); + instr_out(ctx, 3, indirect ? "ignored" : "start vertex\n"); + instr_out(ctx, 4, indirect ? "ignored" : "instance count\n"); + instr_out(ctx, 5, indirect ? "ignored" : "start instance\n"); + instr_out(ctx, 6, indirect ? "ignored" : "index bias\n"); + + return 7; +} + +static int +decode_3d_965(struct drm_intel_decode *ctx) +{ + uint32_t opcode; + unsigned int len; + unsigned int i, j, sba_len; + const char *desc1 = NULL; + uint32_t *data = ctx->data; + uint32_t devid = ctx->devid; + + struct { + uint32_t opcode; + uint32_t len_mask; + int unsigned min_len; + int unsigned max_len; + const char *name; + int gen; + int (*func)(struct drm_intel_decode *ctx); + } opcodes_3d[] = { + { 0x6000, 0x00ff, 3, 3, "URB_FENCE" }, + { 0x6001, 0xffff, 2, 2, "CS_URB_STATE" }, + { 0x6002, 0x00ff, 2, 2, "CONSTANT_BUFFER" }, + { 0x6101, 0xffff, 6, 10, "STATE_BASE_ADDRESS" }, + { 0x6102, 0xffff, 2, 2, "STATE_SIP" }, + { 0x6104, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, + { 0x680b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, + { 0x6904, 0xffff, 1, 1, "3DSTATE_PIPELINE_SELECT" }, + { 0x7800, 0xffff, 7, 7, "3DSTATE_PIPELINED_POINTERS" }, + { 0x7801, 0x00ff, 4, 6, "3DSTATE_BINDING_TABLE_POINTERS" }, + { 0x7802, 0x00ff, 4, 4, "3DSTATE_SAMPLER_STATE_POINTERS" }, + { 0x7805, 0x00ff, 7, 7, "3DSTATE_DEPTH_BUFFER", 7 }, + { 0x7805, 0x00ff, 3, 3, "3DSTATE_URB" }, + { 0x7804, 0x00ff, 3, 3, "3DSTATE_CLEAR_PARAMS" }, + { 0x7806, 0x00ff, 3, 3, "3DSTATE_STENCIL_BUFFER" }, + { 0x7807, 0x00ff, 4, 4, "3DSTATE_HIER_DEPTH_BUFFER", 6 }, + { 0x7807, 0x00ff, 3, 3, "3DSTATE_HIER_DEPTH_BUFFER", 7, gen7_3DSTATE_HIER_DEPTH_BUFFER }, + { 0x7808, 0x00ff, 5, 257, "3DSTATE_VERTEX_BUFFERS" }, + { 0x7809, 0x00ff, 3, 256, "3DSTATE_VERTEX_ELEMENTS" }, + { 0x780a, 0x00ff, 3, 3, "3DSTATE_INDEX_BUFFER" }, + { 0x780b, 0xffff, 1, 1, "3DSTATE_VF_STATISTICS" }, + { 0x780d, 0x00ff, 4, 4, "3DSTATE_VIEWPORT_STATE_POINTERS" }, + { 0x780e, 0xffff, 4, 4, NULL, 6, gen6_3DSTATE_CC_STATE_POINTERS }, + { 0x780e, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_CC_STATE_POINTERS }, + { 0x780f, 0x00ff, 2, 2, "3DSTATE_SCISSOR_POINTERS" }, + { 0x7810, 0x00ff, 6, 6, "3DSTATE_VS" }, + { 0x7811, 0x00ff, 7, 7, "3DSTATE_GS" }, + { 0x7812, 0x00ff, 4, 4, "3DSTATE_CLIP" }, + { 0x7813, 0x00ff, 20, 20, "3DSTATE_SF", 6 }, + { 0x7813, 0x00ff, 7, 7, "3DSTATE_SF", 7 }, + { 0x7814, 0x00ff, 3, 3, "3DSTATE_WM", 7, gen7_3DSTATE_WM }, + { 0x7814, 0x00ff, 9, 9, "3DSTATE_WM", 6, gen6_3DSTATE_WM }, + { 0x7815, 0x00ff, 5, 5, "3DSTATE_CONSTANT_VS_STATE", 6 }, + { 0x7815, 0x00ff, 7, 7, "3DSTATE_CONSTANT_VS", 7, gen7_3DSTATE_CONSTANT_VS }, + { 0x7816, 0x00ff, 5, 5, "3DSTATE_CONSTANT_GS_STATE", 6 }, + { 0x7816, 0x00ff, 7, 7, "3DSTATE_CONSTANT_GS", 7, gen7_3DSTATE_CONSTANT_GS }, + { 0x7817, 0x00ff, 5, 5, "3DSTATE_CONSTANT_PS_STATE", 6 }, + { 0x7817, 0x00ff, 7, 7, "3DSTATE_CONSTANT_PS", 7, gen7_3DSTATE_CONSTANT_PS }, + { 0x7818, 0xffff, 2, 2, "3DSTATE_SAMPLE_MASK" }, + { 0x7819, 0x00ff, 7, 7, "3DSTATE_CONSTANT_HS", 7, gen7_3DSTATE_CONSTANT_HS }, + { 0x781a, 0x00ff, 7, 7, "3DSTATE_CONSTANT_DS", 7, gen7_3DSTATE_CONSTANT_DS }, + { 0x781b, 0x00ff, 7, 7, "3DSTATE_HS" }, + { 0x781c, 0x00ff, 4, 4, "3DSTATE_TE" }, + { 0x781d, 0x00ff, 6, 6, "3DSTATE_DS" }, + { 0x781e, 0x00ff, 3, 3, "3DSTATE_STREAMOUT" }, + { 0x781f, 0x00ff, 14, 14, "3DSTATE_SBE" }, + { 0x7820, 0x00ff, 8, 8, "3DSTATE_PS" }, + { 0x7821, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP }, + { 0x7823, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_VIEWPORT_STATE_POINTERS_CC }, + { 0x7824, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_BLEND_STATE_POINTERS }, + { 0x7825, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_DEPTH_STENCIL_STATE_POINTERS }, + { 0x7826, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_VS" }, + { 0x7827, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_HS" }, + { 0x7828, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_DS" }, + { 0x7829, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_GS" }, + { 0x782a, 0x00ff, 2, 2, "3DSTATE_BINDING_TABLE_POINTERS_PS" }, + { 0x782b, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_VS" }, + { 0x782e, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_GS" }, + { 0x782f, 0x00ff, 2, 2, "3DSTATE_SAMPLER_STATE_POINTERS_PS" }, + { 0x7830, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_VS }, + { 0x7831, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_HS }, + { 0x7832, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_DS }, + { 0x7833, 0x00ff, 2, 2, NULL, 7, gen7_3DSTATE_URB_GS }, + { 0x7900, 0xffff, 4, 4, "3DSTATE_DRAWING_RECTANGLE" }, + { 0x7901, 0xffff, 5, 5, "3DSTATE_CONSTANT_COLOR" }, + { 0x7905, 0xffff, 5, 7, "3DSTATE_DEPTH_BUFFER" }, + { 0x7906, 0xffff, 2, 2, "3DSTATE_POLY_STIPPLE_OFFSET" }, + { 0x7907, 0xffff, 33, 33, "3DSTATE_POLY_STIPPLE_PATTERN" }, + { 0x7908, 0xffff, 3, 3, "3DSTATE_LINE_STIPPLE" }, + { 0x7909, 0xffff, 2, 2, "3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP" }, + { 0x7909, 0xffff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, + { 0x790a, 0xffff, 3, 3, "3DSTATE_AA_LINE_PARAMETERS" }, + { 0x790b, 0xffff, 4, 4, "3DSTATE_GS_SVB_INDEX" }, + { 0x790d, 0xffff, 3, 3, "3DSTATE_MULTISAMPLE", 6 }, + { 0x790d, 0xffff, 4, 4, "3DSTATE_MULTISAMPLE", 7 }, + { 0x7910, 0xffff, 2, 2, "3DSTATE_CLEAR_PARAMS" }, + { 0x7912, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_VS" }, + { 0x7916, 0x00ff, 2, 2, "3DSTATE_PUSH_CONSTANT_ALLOC_PS" }, + { 0x7917, 0x00ff, 2, 2+128*2, "3DSTATE_SO_DECL_LIST" }, + { 0x7918, 0x00ff, 4, 4, "3DSTATE_SO_BUFFER" }, + { 0x7a00, 0x00ff, 4, 6, "PIPE_CONTROL" }, + { 0x7b00, 0x00ff, 7, 7, NULL, 7, gen7_3DPRIMITIVE }, + { 0x7b00, 0x00ff, 6, 6, NULL, 0, gen4_3DPRIMITIVE }, + }, *opcode_3d = NULL; + + opcode = (data[0] & 0xffff0000) >> 16; + + for (i = 0; i < ARRAY_SIZE(opcodes_3d); i++) { + if (opcode != opcodes_3d[i].opcode) + continue; + + /* If it's marked as not our gen, skip. */ + if (opcodes_3d[i].gen && opcodes_3d[i].gen != ctx->gen) + continue; + + opcode_3d = &opcodes_3d[i]; + break; + } + + if (opcode_3d) { + if (opcode_3d->max_len == 1) + len = 1; + else + len = (data[0] & opcode_3d->len_mask) + 2; + + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad length %d in %s, expected %d-%d\n", + len, opcode_3d->name, + opcode_3d->min_len, opcode_3d->max_len); + } + } else { + len = (data[0] & 0x0000ffff) + 2; + } + + switch (opcode) { + case 0x6000: + return i965_decode_urb_fence(ctx, len); + case 0x6001: + instr_out(ctx, 0, "CS_URB_STATE\n"); + instr_out(ctx, 1, + "entry_size: %d [%d bytes], n_entries: %d\n", + (data[1] >> 4) & 0x1f, + (((data[1] >> 4) & 0x1f) + 1) * 64, data[1] & 0x7); + return len; + case 0x6002: + instr_out(ctx, 0, "CONSTANT_BUFFER: %s\n", + (data[0] >> 8) & 1 ? "valid" : "invalid"); + instr_out(ctx, 1, + "offset: 0x%08x, length: %d bytes\n", data[1] & ~0x3f, + ((data[1] & 0x3f) + 1) * 64); + return len; + case 0x6101: + i = 0; + instr_out(ctx, 0, "STATE_BASE_ADDRESS\n"); + i++; + + if (IS_GEN6(devid) || IS_GEN7(devid)) + sba_len = 10; + else if (IS_GEN5(devid)) + sba_len = 8; + else + sba_len = 6; + if (len != sba_len) + fprintf(out, "Bad count in STATE_BASE_ADDRESS\n"); + + state_base_out(ctx, i++, "general"); + state_base_out(ctx, i++, "surface"); + if (IS_GEN6(devid) || IS_GEN7(devid)) + state_base_out(ctx, i++, "dynamic"); + state_base_out(ctx, i++, "indirect"); + if (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid)) + state_base_out(ctx, i++, "instruction"); + + state_max_out(ctx, i++, "general"); + if (IS_GEN6(devid) || IS_GEN7(devid)) + state_max_out(ctx, i++, "dynamic"); + state_max_out(ctx, i++, "indirect"); + if (IS_GEN5(devid) || IS_GEN6(devid) || IS_GEN7(devid)) + state_max_out(ctx, i++, "instruction"); + + return len; + case 0x7800: + instr_out(ctx, 0, "3DSTATE_PIPELINED_POINTERS\n"); + instr_out(ctx, 1, "VS state\n"); + instr_out(ctx, 2, "GS state\n"); + instr_out(ctx, 3, "Clip state\n"); + instr_out(ctx, 4, "SF state\n"); + instr_out(ctx, 5, "WM state\n"); + instr_out(ctx, 6, "CC state\n"); + return len; + case 0x7801: + if (len != 6 && len != 4) + fprintf(out, + "Bad count in 3DSTATE_BINDING_TABLE_POINTERS\n"); + if (len == 6) { + instr_out(ctx, 0, + "3DSTATE_BINDING_TABLE_POINTERS\n"); + instr_out(ctx, 1, "VS binding table\n"); + instr_out(ctx, 2, "GS binding table\n"); + instr_out(ctx, 3, "Clip binding table\n"); + instr_out(ctx, 4, "SF binding table\n"); + instr_out(ctx, 5, "WM binding table\n"); + } else { + instr_out(ctx, 0, + "3DSTATE_BINDING_TABLE_POINTERS: VS mod %d, " + "GS mod %d, PS mod %d\n", + (data[0] & (1 << 8)) != 0, + (data[0] & (1 << 9)) != 0, + (data[0] & (1 << 12)) != 0); + instr_out(ctx, 1, "VS binding table\n"); + instr_out(ctx, 2, "GS binding table\n"); + instr_out(ctx, 3, "WM binding table\n"); + } + + return len; + case 0x7802: + instr_out(ctx, 0, + "3DSTATE_SAMPLER_STATE_POINTERS: VS mod %d, " + "GS mod %d, PS mod %d\n", (data[0] & (1 << 8)) != 0, + (data[0] & (1 << 9)) != 0, + (data[0] & (1 << 12)) != 0); + instr_out(ctx, 1, "VS sampler state\n"); + instr_out(ctx, 2, "GS sampler state\n"); + instr_out(ctx, 3, "WM sampler state\n"); + return len; + case 0x7805: + /* Actually 3DSTATE_DEPTH_BUFFER on gen7. */ + if (ctx->gen == 7) + break; + + instr_out(ctx, 0, "3DSTATE_URB\n"); + instr_out(ctx, 1, + "VS entries %d, alloc size %d (1024bit row)\n", + data[1] & 0xffff, ((data[1] >> 16) & 0x07f) + 1); + instr_out(ctx, 2, + "GS entries %d, alloc size %d (1024bit row)\n", + (data[2] >> 8) & 0x3ff, (data[2] & 7) + 1); + return len; + + case 0x7808: + if ((len - 1) % 4 != 0) + fprintf(out, "Bad count in 3DSTATE_VERTEX_BUFFERS\n"); + instr_out(ctx, 0, "3DSTATE_VERTEX_BUFFERS\n"); + + for (i = 1; i < len;) { + int idx, access; + if (IS_GEN6(devid)) { + idx = 26; + access = 20; + } else { + idx = 27; + access = 26; + } + instr_out(ctx, i, + "buffer %d: %s, pitch %db\n", data[i] >> idx, + data[i] & (1 << access) ? "random" : + "sequential", data[i] & 0x07ff); + i++; + instr_out(ctx, i++, "buffer address\n"); + instr_out(ctx, i++, "max index\n"); + instr_out(ctx, i++, "mbz\n"); + } + return len; + + case 0x7809: + if ((len + 1) % 2 != 0) + fprintf(out, "Bad count in 3DSTATE_VERTEX_ELEMENTS\n"); + instr_out(ctx, 0, "3DSTATE_VERTEX_ELEMENTS\n"); + + for (i = 1; i < len;) { + instr_out(ctx, i, + "buffer %d: %svalid, type 0x%04x, " + "src offset 0x%04x bytes\n", + data[i] >> (IS_GEN6(devid) ? 26 : 27), + data[i] & (1 << (IS_GEN6(devid) ? 25 : 26)) ? + "" : "in", (data[i] >> 16) & 0x1ff, + data[i] & 0x07ff); + i++; + instr_out(ctx, i, "(%s, %s, %s, %s), " + "dst offset 0x%02x bytes\n", + get_965_element_component(data[i], 0), + get_965_element_component(data[i], 1), + get_965_element_component(data[i], 2), + get_965_element_component(data[i], 3), + (data[i] & 0xff) * 4); + i++; + } + return len; + + case 0x780d: + instr_out(ctx, 0, + "3DSTATE_VIEWPORT_STATE_POINTERS\n"); + instr_out(ctx, 1, "clip\n"); + instr_out(ctx, 2, "sf\n"); + instr_out(ctx, 3, "cc\n"); + return len; + + case 0x780a: + instr_out(ctx, 0, "3DSTATE_INDEX_BUFFER\n"); + instr_out(ctx, 1, "beginning buffer address\n"); + instr_out(ctx, 2, "ending buffer address\n"); + return len; + + case 0x780f: + instr_out(ctx, 0, "3DSTATE_SCISSOR_POINTERS\n"); + instr_out(ctx, 1, "scissor rect offset\n"); + return len; + + case 0x7810: + instr_out(ctx, 0, "3DSTATE_VS\n"); + instr_out(ctx, 1, "kernel pointer\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", (data[2] >> 31) & 1, + (data[2] >> 30) & 1, (data[2] >> 27) & 7, + (data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Dispatch GRF start %d, VUE read length %d, " + "VUE read offset %d\n", (data[4] >> 20) & 0x1f, + (data[4] >> 11) & 0x3f, (data[4] >> 4) & 0x3f); + instr_out(ctx, 5, + "Max Threads %d, Vertex Cache %sable, " + "VS func %sable\n", ((data[5] >> 25) & 0x7f) + 1, + (data[5] & (1 << 1)) != 0 ? "dis" : "en", + (data[5] & 1) != 0 ? "en" : "dis"); + return len; + + case 0x7811: + instr_out(ctx, 0, "3DSTATE_GS\n"); + instr_out(ctx, 1, "kernel pointer\n"); + instr_out(ctx, 2, + "SPF=%d, VME=%d, Sampler Count %d, " + "Binding table count %d\n", (data[2] >> 31) & 1, + (data[2] >> 30) & 1, (data[2] >> 27) & 7, + (data[2] >> 18) & 0xff); + instr_out(ctx, 3, "scratch offset\n"); + instr_out(ctx, 4, + "Dispatch GRF start %d, VUE read length %d, " + "VUE read offset %d\n", (data[4] & 0xf), + (data[4] >> 11) & 0x3f, (data[4] >> 4) & 0x3f); + instr_out(ctx, 5, + "Max Threads %d, Rendering %sable\n", + ((data[5] >> 25) & 0x7f) + 1, + (data[5] & (1 << 8)) != 0 ? "en" : "dis"); + instr_out(ctx, 6, + "Reorder %sable, Discard Adjaceny %sable, " + "GS %sable\n", + (data[6] & (1 << 30)) != 0 ? "en" : "dis", + (data[6] & (1 << 29)) != 0 ? "en" : "dis", + (data[6] & (1 << 15)) != 0 ? "en" : "dis"); + return len; + + case 0x7812: + instr_out(ctx, 0, "3DSTATE_CLIP\n"); + instr_out(ctx, 1, + "UserClip distance cull test mask 0x%x\n", + data[1] & 0xff); + instr_out(ctx, 2, + "Clip %sable, API mode %s, Viewport XY test %sable, " + "Viewport Z test %sable, Guardband test %sable, Clip mode %d, " + "Perspective Divide %sable, Non-Perspective Barycentric %sable, " + "Tri Provoking %d, Line Provoking %d, Trifan Provoking %d\n", + (data[2] & (1 << 31)) != 0 ? "en" : "dis", + (data[2] & (1 << 30)) != 0 ? "D3D" : "OGL", + (data[2] & (1 << 28)) != 0 ? "en" : "dis", + (data[2] & (1 << 27)) != 0 ? "en" : "dis", + (data[2] & (1 << 26)) != 0 ? "en" : "dis", + (data[2] >> 13) & 7, + (data[2] & (1 << 9)) != 0 ? "dis" : "en", + (data[2] & (1 << 8)) != 0 ? "en" : "dis", + (data[2] >> 4) & 3, (data[2] >> 2) & 3, + (data[2] & 3)); + instr_out(ctx, 3, + "Min PointWidth %d, Max PointWidth %d, " + "Force Zero RTAIndex %sable, Max VPIndex %d\n", + (data[3] >> 17) & 0x7ff, (data[3] >> 6) & 0x7ff, + (data[3] & (1 << 5)) != 0 ? "en" : "dis", + (data[3] & 0xf)); + return len; + + case 0x7813: + if (ctx->gen == 7) + break; + + instr_out(ctx, 0, "3DSTATE_SF\n"); + instr_out(ctx, 1, + "Attrib Out %d, Attrib Swizzle %sable, VUE read length %d, " + "VUE read offset %d\n", (data[1] >> 22) & 0x3f, + (data[1] & (1 << 21)) != 0 ? "en" : "dis", + (data[1] >> 11) & 0x1f, (data[1] >> 4) & 0x3f); + instr_out(ctx, 2, + "Legacy Global DepthBias %sable, FrontFace fill %d, BF fill %d, " + "VP transform %sable, FrontWinding_%s\n", + (data[2] & (1 << 11)) != 0 ? "en" : "dis", + (data[2] >> 5) & 3, (data[2] >> 3) & 3, + (data[2] & (1 << 1)) != 0 ? "en" : "dis", + (data[2] & 1) != 0 ? "CCW" : "CW"); + instr_out(ctx, 3, + "AA %sable, CullMode %d, Scissor %sable, Multisample m ode %d\n", + (data[3] & (1 << 31)) != 0 ? "en" : "dis", + (data[3] >> 29) & 3, + (data[3] & (1 << 11)) != 0 ? "en" : "dis", + (data[3] >> 8) & 3); + instr_out(ctx, 4, + "Last Pixel %sable, SubPixel Precision %d, Use PixelWidth %d\n", + (data[4] & (1 << 31)) != 0 ? "en" : "dis", + (data[4] & (1 << 12)) != 0 ? 4 : 8, + (data[4] & (1 << 11)) != 0); + instr_out(ctx, 5, + "Global Depth Offset Constant %f\n", + *(float *)(&data[5])); + instr_out(ctx, 6, "Global Depth Offset Scale %f\n", + *(float *)(&data[6])); + instr_out(ctx, 7, "Global Depth Offset Clamp %f\n", + *(float *)(&data[7])); + + for (i = 0, j = 0; i < 8; i++, j += 2) + instr_out(ctx, i + 8, + "Attrib %d (Override %s%s%s%s, Const Source %d, Swizzle Select %d, " + "Source %d); Attrib %d (Override %s%s%s%s, Const Source %d, Swizzle Select %d, Source %d)\n", + j + 1, + (data[8 + i] & (1 << 31)) != 0 ? "W" : "", + (data[8 + i] & (1 << 30)) != 0 ? "Z" : "", + (data[8 + i] & (1 << 29)) != 0 ? "Y" : "", + (data[8 + i] & (1 << 28)) != 0 ? "X" : "", + (data[8 + i] >> 25) & 3, + (data[8 + i] >> 22) & 3, + (data[8 + i] >> 16) & 0x1f, j, + (data[8 + i] & (1 << 15)) != 0 ? "W" : "", + (data[8 + i] & (1 << 14)) != 0 ? "Z" : "", + (data[8 + i] & (1 << 13)) != 0 ? "Y" : "", + (data[8 + i] & (1 << 12)) != 0 ? "X" : "", + (data[8 + i] >> 9) & 3, + (data[8 + i] >> 6) & 3, (data[8 + i] & 0x1f)); + instr_out(ctx, 16, + "Point Sprite TexCoord Enable\n"); + instr_out(ctx, 17, "Const Interp Enable\n"); + instr_out(ctx, 18, + "Attrib 7-0 WrapShortest Enable\n"); + instr_out(ctx, 19, + "Attrib 15-8 WrapShortest Enable\n"); + + return len; + + case 0x7900: + instr_out(ctx, 0, "3DSTATE_DRAWING_RECTANGLE\n"); + instr_out(ctx, 1, "top left: %d,%d\n", + data[1] & 0xffff, (data[1] >> 16) & 0xffff); + instr_out(ctx, 2, "bottom right: %d,%d\n", + data[2] & 0xffff, (data[2] >> 16) & 0xffff); + instr_out(ctx, 3, "origin: %d,%d\n", + (int)data[3] & 0xffff, ((int)data[3] >> 16) & 0xffff); + + return len; + + case 0x7905: + instr_out(ctx, 0, "3DSTATE_DEPTH_BUFFER\n"); + if (IS_GEN5(devid) || IS_GEN6(devid)) + instr_out(ctx, 1, + "%s, %s, pitch = %d bytes, %stiled, HiZ %d, Seperate Stencil %d\n", + get_965_surfacetype(data[1] >> 29), + get_965_depthformat((data[1] >> 18) & 0x7), + (data[1] & 0x0001ffff) + 1, + data[1] & (1 << 27) ? "" : "not ", + (data[1] & (1 << 22)) != 0, + (data[1] & (1 << 21)) != 0); + else + instr_out(ctx, 1, + "%s, %s, pitch = %d bytes, %stiled\n", + get_965_surfacetype(data[1] >> 29), + get_965_depthformat((data[1] >> 18) & 0x7), + (data[1] & 0x0001ffff) + 1, + data[1] & (1 << 27) ? "" : "not "); + instr_out(ctx, 2, "depth offset\n"); + instr_out(ctx, 3, "%dx%d\n", + ((data[3] & 0x0007ffc0) >> 6) + 1, + ((data[3] & 0xfff80000) >> 19) + 1); + instr_out(ctx, 4, "volume depth\n"); + if (len >= 6) + instr_out(ctx, 5, "\n"); + if (len >= 7) { + if (IS_GEN6(devid)) + instr_out(ctx, 6, "\n"); + else + instr_out(ctx, 6, + "render target view extent\n"); + } + + return len; + + case 0x7a00: + if (IS_GEN6(devid) || IS_GEN7(devid)) { + unsigned int i; + if (len != 4 && len != 5) + fprintf(out, "Bad count in PIPE_CONTROL\n"); + + switch ((data[1] >> 14) & 0x3) { + case 0: + desc1 = "no write"; + break; + case 1: + desc1 = "qword write"; + break; + case 2: + desc1 = "PS_DEPTH_COUNT write"; + break; + case 3: + desc1 = "TIMESTAMP write"; + break; + } + instr_out(ctx, 0, "PIPE_CONTROL\n"); + instr_out(ctx, 1, + "%s, %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + desc1, + data[1] & (1 << 20) ? "cs stall, " : "", + data[1] & (1 << 19) ? + "global snapshot count reset, " : "", + data[1] & (1 << 18) ? "tlb invalidate, " : "", + data[1] & (1 << 17) ? "gfdt flush, " : "", + data[1] & (1 << 17) ? "media state clear, " : + "", + data[1] & (1 << 13) ? "depth stall, " : "", + data[1] & (1 << 12) ? + "render target cache flush, " : "", + data[1] & (1 << 11) ? + "instruction cache invalidate, " : "", + data[1] & (1 << 10) ? + "texture cache invalidate, " : "", + data[1] & (1 << 9) ? + "indirect state invalidate, " : "", + data[1] & (1 << 8) ? "notify irq, " : "", + data[1] & (1 << 7) ? "PIPE_CONTROL flush, " : + "", + data[1] & (1 << 6) ? "protect mem app_id, " : + "", data[1] & (1 << 5) ? "DC flush, " : "", + data[1] & (1 << 4) ? "vf fetch invalidate, " : + "", + data[1] & (1 << 3) ? + "constant cache invalidate, " : "", + data[1] & (1 << 2) ? + "state cache invalidate, " : "", + data[1] & (1 << 1) ? "stall at scoreboard, " : + "", + data[1] & (1 << 0) ? "depth cache flush, " : + ""); + if (len == 5) { + instr_out(ctx, 2, + "destination address\n"); + instr_out(ctx, 3, + "immediate dword low\n"); + instr_out(ctx, 4, + "immediate dword high\n"); + } else { + for (i = 2; i < len; i++) { + instr_out(ctx, i, "\n"); + } + } + return len; + } else { + if (len != 4) + fprintf(out, "Bad count in PIPE_CONTROL\n"); + + switch ((data[0] >> 14) & 0x3) { + case 0: + desc1 = "no write"; + break; + case 1: + desc1 = "qword write"; + break; + case 2: + desc1 = "PS_DEPTH_COUNT write"; + break; + case 3: + desc1 = "TIMESTAMP write"; + break; + } + instr_out(ctx, 0, + "PIPE_CONTROL: %s, %sdepth stall, %sRC write flush, " + "%sinst flush\n", + desc1, + data[0] & (1 << 13) ? "" : "no ", + data[0] & (1 << 12) ? "" : "no ", + data[0] & (1 << 11) ? "" : "no "); + instr_out(ctx, 1, "destination address\n"); + instr_out(ctx, 2, "immediate dword low\n"); + instr_out(ctx, 3, "immediate dword high\n"); + return len; + } + } + + if (opcode_3d) { + if (opcode_3d->func) { + return opcode_3d->func(ctx); + } else { + unsigned int i; + + instr_out(ctx, 0, "%s\n", opcode_3d->name); + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_965 opcode = 0x%x\n", + opcode); + return 1; +} + +static int +decode_3d_i830(struct drm_intel_decode *ctx) +{ + unsigned int idx; + uint32_t opcode; + uint32_t *data = ctx->data; + + struct { + uint32_t opcode; + unsigned int min_len; + unsigned int max_len; + const char *name; + } opcodes_3d[] = { + { 0x02, 1, 1, "3DSTATE_MODES_3" }, + { 0x03, 1, 1, "3DSTATE_ENABLES_1" }, + { 0x04, 1, 1, "3DSTATE_ENABLES_2" }, + { 0x05, 1, 1, "3DSTATE_VFT0" }, + { 0x06, 1, 1, "3DSTATE_AA" }, + { 0x07, 1, 1, "3DSTATE_RASTERIZATION_RULES" }, + { 0x08, 1, 1, "3DSTATE_MODES_1" }, + { 0x09, 1, 1, "3DSTATE_STENCIL_TEST" }, + { 0x0a, 1, 1, "3DSTATE_VFT1" }, + { 0x0b, 1, 1, "3DSTATE_INDPT_ALPHA_BLEND" }, + { 0x0c, 1, 1, "3DSTATE_MODES_5" }, + { 0x0d, 1, 1, "3DSTATE_MAP_BLEND_OP" }, + { 0x0e, 1, 1, "3DSTATE_MAP_BLEND_ARG" }, + { 0x0f, 1, 1, "3DSTATE_MODES_2" }, + { 0x15, 1, 1, "3DSTATE_FOG_COLOR" }, + { 0x16, 1, 1, "3DSTATE_MODES_4"}, + }, *opcode_3d; + + opcode = (data[0] & 0x1f000000) >> 24; + + switch (opcode) { + case 0x1f: + return decode_3d_primitive(ctx); + case 0x1d: + return decode_3d_1d(ctx); + case 0x1c: + return decode_3d_1c(ctx); + } + + for (idx = 0; idx < ARRAY_SIZE(opcodes_3d); idx++) { + opcode_3d = &opcodes_3d[idx]; + if ((data[0] & 0x1f000000) >> 24 == opcode_3d->opcode) { + unsigned int len = 1, i; + + instr_out(ctx, 0, "%s\n", opcode_3d->name); + if (opcode_3d->max_len > 1) { + len = (data[0] & 0xff) + 2; + if (len < opcode_3d->min_len || + len > opcode_3d->max_len) { + fprintf(out, "Bad count in %s\n", + opcode_3d->name); + } + } + + for (i = 1; i < len; i++) { + instr_out(ctx, i, "dword %d\n", i); + } + return len; + } + } + + instr_out(ctx, 0, "3D UNKNOWN: 3d_i830 opcode = 0x%x\n", + opcode); + return 1; +} + +struct drm_intel_decode * +drm_intel_decode_context_alloc(uint32_t devid) +{ + struct drm_intel_decode *ctx; + + ctx = calloc(1, sizeof(struct drm_intel_decode)); + if (!ctx) + return NULL; + + ctx->devid = devid; + ctx->out = stdout; + + if (IS_GEN7(devid)) + ctx->gen = 7; + else if (IS_GEN6(devid)) + ctx->gen = 6; + else if (IS_GEN5(devid)) + ctx->gen = 5; + else if (IS_GEN4(devid)) + ctx->gen = 4; + else if (IS_9XX(devid)) + ctx->gen = 3; + else { + assert(IS_GEN2(devid)); + ctx->gen = 2; + } + + return ctx; +} + +void +drm_intel_decode_context_free(struct drm_intel_decode *ctx) +{ + free(ctx); +} + +void +drm_intel_decode_set_dump_past_end(struct drm_intel_decode *ctx, + int dump_past_end) +{ + ctx->dump_past_end = !!dump_past_end; +} + +void +drm_intel_decode_set_batch_pointer(struct drm_intel_decode *ctx, + void *data, uint32_t hw_offset, int count) +{ + ctx->base_data = data; + ctx->base_hw_offset = hw_offset; + ctx->base_count = count; +} + +void +drm_intel_decode_set_head_tail(struct drm_intel_decode *ctx, + uint32_t head, uint32_t tail) +{ + ctx->head = head; + ctx->tail = tail; +} + +void +drm_intel_decode_set_output_file(struct drm_intel_decode *ctx, + FILE *out) +{ + ctx->out = out; +} + +/** + * Decodes an i830-i915 batch buffer, writing the output to stdout. + * + * \param data batch buffer contents + * \param count number of DWORDs to decode in the batch buffer + * \param hw_offset hardware address for the buffer + */ +void +drm_intel_decode(struct drm_intel_decode *ctx) +{ + int ret; + unsigned int index = 0; + uint32_t devid; + int size = ctx->base_count * 4; + void *temp; + + if (!ctx) + return; + + /* Put a scratch page full of obviously undefined data after + * the batchbuffer. This lets us avoid a bunch of length + * checking in statically sized packets. + */ + temp = malloc(size + 4096); + memcpy(temp, ctx->base_data, size); + memset((char *)temp + size, 0xd0, 4096); + ctx->data = temp; + + ctx->hw_offset = ctx->base_hw_offset; + ctx->count = ctx->base_count; + + devid = ctx->devid; + head_offset = ctx->head; + tail_offset = ctx->tail; + out = ctx->out; + + saved_s2_set = 0; + saved_s4_set = 1; + + while (ctx->count > 0) { + index = 0; + + switch ((ctx->data[index] & 0xe0000000) >> 29) { + case 0x0: + ret = decode_mi(ctx); + + /* If MI_BATCHBUFFER_END happened, then dump + * the rest of the output in case we some day + * want it in debugging, but don't decode it + * since it'll just confuse in the common + * case. + */ + if (ret == -1) { + if (ctx->dump_past_end) { + index++; + } else { + for (index = index + 1; index < ctx->count; + index++) { + instr_out(ctx, index, "\n"); + } + } + } else + index += ret; + break; + case 0x2: + index += decode_2d(ctx); + break; + case 0x3: + if (IS_9XX(devid) && !IS_GEN3(devid)) { + index += + decode_3d_965(ctx); + } else if (IS_GEN3(devid)) { + index += decode_3d(ctx); + } else { + index += + decode_3d_i830(ctx); + } + break; + default: + instr_out(ctx, index, "UNKNOWN\n"); + index++; + break; + } + fflush(out); + + if (ctx->count < index) + break; + + ctx->count -= index; + ctx->data += index; + ctx->hw_offset += 4 * index; + } + + free(temp); +} diff --git a/intel/test_decode.c b/intel/test_decode.c new file mode 100644 index 0000000..c9ab7ad --- /dev/null +++ b/intel/test_decode.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2011 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "intel_bufmgr.h" +#include "intel_chipset.h" + +#define HW_OFFSET 0x12300000 + +static void +usage(void) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " test_decode \n"); + fprintf(stderr, " test_decode -dump\n"); + exit(1); +} + +static void +read_file(const char *filename, void **ptr, size_t *size) +{ + int fd, ret; + struct stat st; + + fd = open(filename, O_RDONLY); + if (fd == -1) + errx(1, "couldn't open `%s'", filename); + + ret = fstat(fd, &st); + if (ret) + errx(1, "couldn't stat `%s'", filename); + + *size = st.st_size; + *ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (*ptr == MAP_FAILED) + errx(1, "couldn't map `%s'", filename); + + close(fd); +} + +static void +dump_batch(struct drm_intel_decode *ctx, const char *batch_filename) +{ + void *batch_ptr; + size_t batch_size; + + read_file(batch_filename, &batch_ptr, &batch_size); + + drm_intel_decode_set_batch_pointer(ctx, batch_ptr, HW_OFFSET, + batch_size / 4); + drm_intel_decode_set_output_file(ctx, stdout); + + drm_intel_decode(ctx); +} + +static void +compare_batch(struct drm_intel_decode *ctx, const char *batch_filename) +{ + FILE *out = NULL; + void *ptr, *ref_ptr, *batch_ptr; + size_t size, ref_size, batch_size; + const char *ref_suffix = "-ref.txt"; + char *ref_filename; + + ref_filename = malloc(strlen(batch_filename) + strlen(ref_suffix) + 1); + sprintf(ref_filename, "%s%s", batch_filename, ref_suffix); + + /* Read the batch and reference. */ + read_file(batch_filename, &batch_ptr, &batch_size); + read_file(ref_filename, &ref_ptr, &ref_size); + + /* Set up our decode output in memory, because I don't want to + * figure out how to output to a file in a safe and sane way + * inside of an automake project's test infrastructure. + */ +#ifdef HAVE_OPEN_MEMSTREAM + out = open_memstream((char **)&ptr, &size); +#else + fprintf(stderr, "platform lacks open_memstream, skipping.\n"); + exit(77); +#endif + + drm_intel_decode_set_batch_pointer(ctx, batch_ptr, HW_OFFSET, + batch_size / 4); + drm_intel_decode_set_output_file(ctx, out); + + drm_intel_decode(ctx); + + if (strcmp(ref_ptr, ptr) != 0) { + fprintf(stderr, "Decode mismatch with reference `%s'.\n", + ref_filename); + fprintf(stderr, "You can dump the new output using:\n"); + fprintf(stderr, " test_decode \"%s\" -dump\n", batch_filename); + exit(1); + } + + fclose(out); + free(ref_filename); + free(ptr); +} + +static uint16_t +infer_devid(const char *batch_filename) +{ + struct { + const char *name; + uint16_t devid; + } chipsets[] = { + { "830", 0x3577}, + { "855", 0x3582}, + { "945", 0x2772}, + { "gen4", 0x2a02 }, + { "gm45", 0x2a42 }, + { "gen5", PCI_CHIP_ILD_G }, + { "gen6", PCI_CHIP_SANDYBRIDGE_GT2 }, + { "gen7", PCI_CHIP_IVYBRIDGE_GT2 }, + { NULL, 0 }, + }; + int i; + + for (i = 0; chipsets[i].name != NULL; i++) { + if (strstr(batch_filename, chipsets[i].name)) + return chipsets[i].devid; + } + + fprintf(stderr, "Couldn't guess chipset id from batch filename `%s'.\n", + batch_filename); + fprintf(stderr, "Must be contain one of:\n"); + for (i = 0; chipsets[i].name != NULL; i++) { + fprintf(stderr, " %s\n", chipsets[i].name); + } + exit(1); +} + +int +main(int argc, char **argv) +{ + uint16_t devid; + struct drm_intel_decode *ctx; + + if (argc < 2) + usage(); + + + devid = infer_devid(argv[1]); + + ctx = drm_intel_decode_context_alloc(devid); + + if (argc == 3) { + if (strcmp(argv[2], "-dump") == 0) + dump_batch(ctx, argv[1]); + else + usage(); + } else { + compare_batch(ctx, argv[1]); + } + + drm_intel_decode_context_free(ctx); + + return 0; +} diff --git a/intel/tests/.gitignore b/intel/tests/.gitignore new file mode 100644 index 0000000..e9d01ec --- /dev/null +++ b/intel/tests/.gitignore @@ -0,0 +1 @@ +*-new.txt diff --git a/intel/tests/gen4-3d.batch b/intel/tests/gen4-3d.batch new file mode 100644 index 0000000..e6911a4 Binary files /dev/null and b/intel/tests/gen4-3d.batch differ diff --git a/intel/tests/gen4-3d.batch-ref.txt b/intel/tests/gen4-3d.batch-ref.txt new file mode 100644 index 0000000..20aa1d4 --- /dev/null +++ b/intel/tests/gen4-3d.batch-ref.txt @@ -0,0 +1,488 @@ +0x12300000: 0x61040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x780b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010004: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: general state upper bound disabled +0x1230002c: 0x00000001: indirect state upper bound disabled +0x12300030: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300034: 0x00007e20: VS binding table +0x12300038: 0x00000000: GS binding table +0x1230003c: 0x00000000: Clip binding table +0x12300040: 0x00000000: SF binding table +0x12300044: 0x00007e20: WM binding table +0x12300048: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x1230004c: 0x00000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0x00000000: dword 3 +0x12300058: 0x00000000: dword 4 +0x1230005c: 0x79050003: 3DSTATE_DEPTH_BUFFER +0x12300060: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled +0x12300064: 0x00000000: depth offset +0x12300068: 0x09584ac0: 300x300 +0x1230006c: 0x00000000: volume depth +0x12300070: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300074: 0x00007d60: VS state +0x12300078: 0x00000000: GS state +0x1230007c: 0x00007d21: Clip state +0x12300080: 0x00007d80: SF state +0x12300084: 0x00007de0: WM state +0x12300088: 0x00007fc0: CC state +0x1230008c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300090: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300094: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300098: 0x60010000: CS_URB_STATE +0x1230009c: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000a0: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000a4: 0x00000000: top left: 0,0 +0x123000a8: 0x012b012b: bottom right: 299,299 +0x123000ac: 0x00000000: origin: 0,0 +0x123000b0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000b4: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000b8: 0x00000000: buffer address +0x123000bc: 0x00000000: max index +0x123000c0: 0x00000000: mbz +0x123000c4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000c8: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000cc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000d0: 0x60020100: CONSTANT_BUFFER: valid +0x123000d4: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000d8: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000dc: 0x00000004: vertex count +0x123000e0: 0x00000000: start vertex +0x123000e4: 0x00000001: instance count +0x123000e8: 0x00000000: start instance +0x123000ec: 0x00000000: index bias +0x123000f0: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x123000f4: 0x00007b40: VS binding table +0x123000f8: 0x00000000: GS binding table +0x123000fc: 0x00000000: Clip binding table +0x12300100: 0x00000000: SF binding table +0x12300104: 0x00007b40: WM binding table +0x12300108: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230010c: 0x00007aa0: VS state +0x12300110: 0x00007a41: GS state +0x12300114: 0x00007a61: Clip state +0x12300118: 0x00007ac0: SF state +0x1230011c: 0x00007b00: WM state +0x12300120: 0x00007cc0: CC state +0x12300124: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300128: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x1230012c: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300130: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300134: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300138: 0x00000000: buffer address +0x1230013c: 0x00000000: max index +0x12300140: 0x00000000: mbz +0x12300144: 0x60020100: CONSTANT_BUFFER: valid +0x12300148: 0x00000082: offset: 0x00000080, length: 192 bytes +0x1230014c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300150: 0x00000052: vertex count +0x12300154: 0x00000000: start vertex +0x12300158: 0x00000001: instance count +0x1230015c: 0x00000000: start instance +0x12300160: 0x00000000: index bias +0x12300164: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300168: 0x00007aa0: VS state +0x1230016c: 0x00007a21: GS state +0x12300170: 0x00007a61: Clip state +0x12300174: 0x00007ac0: SF state +0x12300178: 0x00007b00: WM state +0x1230017c: 0x00007cc0: CC state +0x12300180: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300184: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300188: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230018c: 0x60020100: CONSTANT_BUFFER: valid +0x12300190: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300194: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300198: 0x00000050: vertex count +0x1230019c: 0x00000052: start vertex +0x123001a0: 0x00000001: instance count +0x123001a4: 0x00000000: start instance +0x123001a8: 0x00000000: index bias +0x123001ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001b0: 0x00007aa0: VS state +0x123001b4: 0x00007a01: GS state +0x123001b8: 0x00007a61: Clip state +0x123001bc: 0x00007ac0: SF state +0x123001c0: 0x00007b00: WM state +0x123001c4: 0x00007cc0: CC state +0x123001c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001cc: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123001d0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123001d4: 0x60020100: CONSTANT_BUFFER: valid +0x123001d8: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123001dc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123001e0: 0x00000052: vertex count +0x123001e4: 0x000000a2: start vertex +0x123001e8: 0x00000001: instance count +0x123001ec: 0x00000000: start instance +0x123001f0: 0x00000000: index bias +0x123001f4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001f8: 0x00007aa0: VS state +0x123001fc: 0x000079e1: GS state +0x12300200: 0x00007a61: Clip state +0x12300204: 0x00007ac0: SF state +0x12300208: 0x00007b00: WM state +0x1230020c: 0x00007cc0: CC state +0x12300210: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300214: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300218: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230021c: 0x60020100: CONSTANT_BUFFER: valid +0x12300220: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300224: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300228: 0x00000050: vertex count +0x1230022c: 0x000000f4: start vertex +0x12300230: 0x00000001: instance count +0x12300234: 0x00000000: start instance +0x12300238: 0x00000000: index bias +0x1230023c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300240: 0x00007aa0: VS state +0x12300244: 0x000079c1: GS state +0x12300248: 0x00007a61: Clip state +0x1230024c: 0x00007ac0: SF state +0x12300250: 0x00007b00: WM state +0x12300254: 0x00007cc0: CC state +0x12300258: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230025c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300260: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300264: 0x60020100: CONSTANT_BUFFER: valid +0x12300268: 0x00000142: offset: 0x00000140, length: 192 bytes +0x1230026c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300270: 0x000079a0: VS state +0x12300274: 0x000079c1: GS state +0x12300278: 0x00007a61: Clip state +0x1230027c: 0x00007ac0: SF state +0x12300280: 0x00007b00: WM state +0x12300284: 0x00007cc0: CC state +0x12300288: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230028c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300290: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300294: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300298: 0x00000018: buffer 0: sequential, pitch 24b +0x1230029c: 0x00000f48: buffer address +0x123002a0: 0x00000000: max index +0x123002a4: 0x00000000: mbz +0x123002a8: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002ac: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002b0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b4: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002b8: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123002bc: 0x60020100: CONSTANT_BUFFER: valid +0x123002c0: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002c4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123002c8: 0x000000a2: vertex count +0x123002cc: 0x00000000: start vertex +0x123002d0: 0x00000001: instance count +0x123002d4: 0x00000000: start instance +0x123002d8: 0x00000000: index bias +0x123002dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002e0: 0x000079a0: VS state +0x123002e4: 0x00000000: GS state +0x123002e8: 0x00007901: Clip state +0x123002ec: 0x00007940: SF state +0x123002f0: 0x00007960: WM state +0x123002f4: 0x00007cc0: CC state +0x123002f8: 0x00000000: MI_NOOP +0x123002fc: 0x00000000: MI_NOOP +0x12300300: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300304: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300308: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230030c: 0x60020100: CONSTANT_BUFFER: valid +0x12300310: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300314: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300318: 0x0000002a: vertex count +0x1230031c: 0x000000a2: start vertex +0x12300320: 0x00000001: instance count +0x12300324: 0x00000000: start instance +0x12300328: 0x00000000: index bias +0x1230032c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300330: 0x00007860: VS state +0x12300334: 0x00007801: GS state +0x12300338: 0x00007821: Clip state +0x1230033c: 0x00007880: SF state +0x12300340: 0x000078a0: WM state +0x12300344: 0x00007cc0: CC state +0x12300348: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230034c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300350: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300354: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300358: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230035c: 0x00002268: buffer address +0x12300360: 0x00000000: max index +0x12300364: 0x00000000: mbz +0x12300368: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230036c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300370: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300374: 0x60020100: CONSTANT_BUFFER: valid +0x12300378: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x1230037c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300380: 0x0000002a: vertex count +0x12300384: 0x00000000: start vertex +0x12300388: 0x00000001: instance count +0x1230038c: 0x00000000: start instance +0x12300390: 0x00000000: index bias +0x12300394: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300398: 0x00007860: VS state +0x1230039c: 0x000077e1: GS state +0x123003a0: 0x00007821: Clip state +0x123003a4: 0x00007880: SF state +0x123003a8: 0x000078a0: WM state +0x123003ac: 0x00007cc0: CC state +0x123003b0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123003b4: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123003b8: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123003bc: 0x60020100: CONSTANT_BUFFER: valid +0x123003c0: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123003c8: 0x00000028: vertex count +0x123003cc: 0x0000002a: start vertex +0x123003d0: 0x00000001: instance count +0x123003d4: 0x00000000: start instance +0x123003d8: 0x00000000: index bias +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077c1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300408: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300414: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300418: 0x0000002a: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300430: 0x00007860: VS state +0x12300434: 0x000077a1: GS state +0x12300438: 0x00007821: Clip state +0x1230043c: 0x00007880: SF state +0x12300440: 0x000078a0: WM state +0x12300444: 0x00007cc0: CC state +0x12300448: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230044c: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300450: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x12300454: 0x60020100: CONSTANT_BUFFER: valid +0x12300458: 0x00000382: offset: 0x00000380, length: 192 bytes +0x1230045c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300460: 0x00000028: vertex count +0x12300464: 0x0000007c: start vertex +0x12300468: 0x00000001: instance count +0x1230046c: 0x00000000: start instance +0x12300470: 0x00000000: index bias +0x12300474: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300478: 0x00007860: VS state +0x1230047c: 0x00007781: GS state +0x12300480: 0x00007821: Clip state +0x12300484: 0x00007880: SF state +0x12300488: 0x000078a0: WM state +0x1230048c: 0x00007cc0: CC state +0x12300490: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300494: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300498: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230049c: 0x60020100: CONSTANT_BUFFER: valid +0x123004a0: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004a8: 0x00007760: VS state +0x123004ac: 0x00007781: GS state +0x123004b0: 0x00007821: Clip state +0x123004b4: 0x00007880: SF state +0x123004b8: 0x000078a0: WM state +0x123004bc: 0x00007cc0: CC state +0x123004c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004c4: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123004c8: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123004cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123004d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123004d4: 0x00002a30: buffer address +0x123004d8: 0x00000000: max index +0x123004dc: 0x00000000: mbz +0x123004e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123004e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123004e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123004ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123004f0: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123004f4: 0x60020100: CONSTANT_BUFFER: valid +0x123004f8: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123004fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300500: 0x00000052: vertex count +0x12300504: 0x00000000: start vertex +0x12300508: 0x00000001: instance count +0x1230050c: 0x00000000: start instance +0x12300510: 0x00000000: index bias +0x12300514: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300518: 0x00007760: VS state +0x1230051c: 0x00000000: GS state +0x12300520: 0x000076c1: Clip state +0x12300524: 0x00007700: SF state +0x12300528: 0x00007720: WM state +0x1230052c: 0x00007cc0: CC state +0x12300530: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300534: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300538: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230053c: 0x60020100: CONSTANT_BUFFER: valid +0x12300540: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300544: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300548: 0x00000016: vertex count +0x1230054c: 0x00000052: start vertex +0x12300550: 0x00000001: instance count +0x12300554: 0x00000000: start instance +0x12300558: 0x00000000: index bias +0x1230055c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300560: 0x00007620: VS state +0x12300564: 0x000075c1: GS state +0x12300568: 0x000075e1: Clip state +0x1230056c: 0x00007640: SF state +0x12300570: 0x00007660: WM state +0x12300574: 0x00007cc0: CC state +0x12300578: 0x00000000: MI_NOOP +0x1230057c: 0x00000000: MI_NOOP +0x12300580: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300584: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300588: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230058c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300590: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300594: 0x000033f0: buffer address +0x12300598: 0x00000000: max index +0x1230059c: 0x00000000: mbz +0x123005a0: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005a4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005a8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005ac: 0x60020100: CONSTANT_BUFFER: valid +0x123005b0: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005b4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005b8: 0x0000002a: vertex count +0x123005bc: 0x00000000: start vertex +0x123005c0: 0x00000001: instance count +0x123005c4: 0x00000000: start instance +0x123005c8: 0x00000000: index bias +0x123005cc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005d0: 0x00007620: VS state +0x123005d4: 0x000075a1: GS state +0x123005d8: 0x000075e1: Clip state +0x123005dc: 0x00007640: SF state +0x123005e0: 0x00007660: WM state +0x123005e4: 0x00007cc0: CC state +0x123005e8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005ec: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123005f0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123005f4: 0x60020100: CONSTANT_BUFFER: valid +0x123005f8: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005fc: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300600: 0x00000028: vertex count +0x12300604: 0x0000002a: start vertex +0x12300608: 0x00000001: instance count +0x1230060c: 0x00000000: start instance +0x12300610: 0x00000000: index bias +0x12300614: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300618: 0x00007620: VS state +0x1230061c: 0x00007581: GS state +0x12300620: 0x000075e1: Clip state +0x12300624: 0x00007640: SF state +0x12300628: 0x00007660: WM state +0x1230062c: 0x00007cc0: CC state +0x12300630: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300634: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300638: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230063c: 0x60020100: CONSTANT_BUFFER: valid +0x12300640: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300644: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300648: 0x0000002a: vertex count +0x1230064c: 0x00000052: start vertex +0x12300650: 0x00000001: instance count +0x12300654: 0x00000000: start instance +0x12300658: 0x00000000: index bias +0x1230065c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300660: 0x00007620: VS state +0x12300664: 0x00007561: GS state +0x12300668: 0x000075e1: Clip state +0x1230066c: 0x00007640: SF state +0x12300670: 0x00007660: WM state +0x12300674: 0x00007cc0: CC state +0x12300678: 0x00000000: MI_NOOP +0x1230067c: 0x00000000: MI_NOOP +0x12300680: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300684: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300688: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230068c: 0x60020100: CONSTANT_BUFFER: valid +0x12300690: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300694: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300698: 0x00000028: vertex count +0x1230069c: 0x0000007c: start vertex +0x123006a0: 0x00000001: instance count +0x123006a4: 0x00000000: start instance +0x123006a8: 0x00000000: index bias +0x123006ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006b0: 0x00007620: VS state +0x123006b4: 0x00007541: GS state +0x123006b8: 0x000075e1: Clip state +0x123006bc: 0x00007640: SF state +0x123006c0: 0x00007660: WM state +0x123006c4: 0x00007cc0: CC state +0x123006c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006cc: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x123006d0: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x123006d4: 0x60020100: CONSTANT_BUFFER: valid +0x123006d8: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006e0: 0x00007520: VS state +0x123006e4: 0x00007541: GS state +0x123006e8: 0x000075e1: Clip state +0x123006ec: 0x00007640: SF state +0x123006f0: 0x00007660: WM state +0x123006f4: 0x00007cc0: CC state +0x123006f8: 0x00000000: MI_NOOP +0x123006fc: 0x00000000: MI_NOOP +0x12300700: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300704: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300708: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230070c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300710: 0x00000018: buffer 0: sequential, pitch 24b +0x12300714: 0x00003bb8: buffer address +0x12300718: 0x00000000: max index +0x1230071c: 0x00000000: mbz +0x12300720: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300724: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300728: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230072c: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300730: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x00000682: offset: 0x00000680, length: 192 bytes +0x1230073c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300740: 0x00000052: vertex count +0x12300744: 0x00000000: start vertex +0x12300748: 0x00000001: instance count +0x1230074c: 0x00000000: start instance +0x12300750: 0x00000000: index bias +0x12300754: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300758: 0x00007520: VS state +0x1230075c: 0x00000000: GS state +0x12300760: 0x00007481: Clip state +0x12300764: 0x000074c0: SF state +0x12300768: 0x000074e0: WM state +0x1230076c: 0x00007cc0: CC state +0x12300770: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300774: 0x0320a020: vs fence: 32, clip_fence: 50, gs_fence: 40 +0x12300778: 0x10000042: sf fence: 66, vfe_fence: 0, cs_fence: 256 +0x1230077c: 0x60020100: CONSTANT_BUFFER: valid +0x12300780: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300784: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300788: 0x00000016: vertex count +0x1230078c: 0x00000052: start vertex +0x12300790: 0x00000001: instance count +0x12300794: 0x00000000: start instance +0x12300798: 0x00000000: index bias +0x1230079c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen4-3d.batch.sh b/intel/tests/gen4-3d.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gen4-3d.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/gen5-3d.batch b/intel/tests/gen5-3d.batch new file mode 100644 index 0000000..cf9d8d8 Binary files /dev/null and b/intel/tests/gen5-3d.batch differ diff --git a/intel/tests/gen5-3d.batch-ref.txt b/intel/tests/gen5-3d.batch-ref.txt new file mode 100644 index 0000000..a0271ab --- /dev/null +++ b/intel/tests/gen5-3d.batch-ref.txt @@ -0,0 +1,512 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010006: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: instruction state base address 0x00000000 +0x1230002c: 0x00000001: general state upper bound disabled +0x12300030: 0x00000001: indirect state upper bound disabled +0x12300034: 0x00000001: instruction state upper bound disabled +0x12300038: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x1230003c: 0x00007e20: VS binding table +0x12300040: 0x00000000: GS binding table +0x12300044: 0x00000000: Clip binding table +0x12300048: 0x00000000: SF binding table +0x1230004c: 0x00007e20: WM binding table +0x12300050: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x12300054: 0x00000000: dword 1 +0x12300058: 0x00000000: dword 2 +0x1230005c: 0x00000000: dword 3 +0x12300060: 0x00000000: dword 4 +0x12300064: 0x79050004: 3DSTATE_DEPTH_BUFFER +0x12300068: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled, HiZ 0, Seperate Stencil 0 +0x1230006c: 0x00000000: depth offset +0x12300070: 0x09584ac0: 300x300 +0x12300074: 0x00000000: volume depth +0x12300078: 0x00000000: +0x1230007c: 0x02000000: MI_FLUSH +0x12300080: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300084: 0x00007d60: VS state +0x12300088: 0x00000000: GS state +0x1230008c: 0x00007d21: Clip state +0x12300090: 0x00007d80: SF state +0x12300094: 0x00007de0: WM state +0x12300098: 0x00007fc0: CC state +0x1230009c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123000a0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123000a4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123000a8: 0x60010000: CS_URB_STATE +0x123000ac: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000b0: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000b4: 0x00000000: top left: 0,0 +0x123000b8: 0x012b012b: bottom right: 299,299 +0x123000bc: 0x00000000: origin: 0,0 +0x123000c0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000c4: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000c8: 0x00000000: buffer address +0x123000cc: 0x0000ffff: max index +0x123000d0: 0x00000000: mbz +0x123000d4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000d8: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000dc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000e0: 0x60020100: CONSTANT_BUFFER: valid +0x123000e4: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000e8: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000ec: 0x00000004: vertex count +0x123000f0: 0x00000000: start vertex +0x123000f4: 0x00000001: instance count +0x123000f8: 0x00000000: start instance +0x123000fc: 0x00000000: index bias +0x12300100: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300104: 0x00007b40: VS binding table +0x12300108: 0x00000000: GS binding table +0x1230010c: 0x00000000: Clip binding table +0x12300110: 0x00000000: SF binding table +0x12300114: 0x00007b40: WM binding table +0x12300118: 0x02000000: MI_FLUSH +0x1230011c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300120: 0x00007aa0: VS state +0x12300124: 0x00007a41: GS state +0x12300128: 0x00007a61: Clip state +0x1230012c: 0x00007ac0: SF state +0x12300130: 0x00007b00: WM state +0x12300134: 0x00007cc0: CC state +0x12300138: 0x00000000: MI_NOOP +0x1230013c: 0x00000000: MI_NOOP +0x12300140: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300144: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300148: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230014c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300150: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300154: 0x00000000: buffer address +0x12300158: 0x00007fff: max index +0x1230015c: 0x00000000: mbz +0x12300160: 0x60020100: CONSTANT_BUFFER: valid +0x12300164: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300168: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x1230016c: 0x00000052: vertex count +0x12300170: 0x00000000: start vertex +0x12300174: 0x00000001: instance count +0x12300178: 0x00000000: start instance +0x1230017c: 0x00000000: index bias +0x12300180: 0x02000000: MI_FLUSH +0x12300184: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300188: 0x00007aa0: VS state +0x1230018c: 0x00007a21: GS state +0x12300190: 0x00007a61: Clip state +0x12300194: 0x00007ac0: SF state +0x12300198: 0x00007b00: WM state +0x1230019c: 0x00007cc0: CC state +0x123001a0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001a4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123001a8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123001ac: 0x60020100: CONSTANT_BUFFER: valid +0x123001b0: 0x00000082: offset: 0x00000080, length: 192 bytes +0x123001b4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123001b8: 0x00000050: vertex count +0x123001bc: 0x00000052: start vertex +0x123001c0: 0x00000001: instance count +0x123001c4: 0x00000000: start instance +0x123001c8: 0x00000000: index bias +0x123001cc: 0x02000000: MI_FLUSH +0x123001d0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001d4: 0x00007aa0: VS state +0x123001d8: 0x00007a01: GS state +0x123001dc: 0x00007a61: Clip state +0x123001e0: 0x00007ac0: SF state +0x123001e4: 0x00007b00: WM state +0x123001e8: 0x00007cc0: CC state +0x123001ec: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001f0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123001f4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123001f8: 0x60020100: CONSTANT_BUFFER: valid +0x123001fc: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300200: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300204: 0x00000052: vertex count +0x12300208: 0x000000a2: start vertex +0x1230020c: 0x00000001: instance count +0x12300210: 0x00000000: start instance +0x12300214: 0x00000000: index bias +0x12300218: 0x02000000: MI_FLUSH +0x1230021c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300220: 0x00007aa0: VS state +0x12300224: 0x000079e1: GS state +0x12300228: 0x00007a61: Clip state +0x1230022c: 0x00007ac0: SF state +0x12300230: 0x00007b00: WM state +0x12300234: 0x00007cc0: CC state +0x12300238: 0x00000000: MI_NOOP +0x1230023c: 0x00000000: MI_NOOP +0x12300240: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300244: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300248: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230024c: 0x60020100: CONSTANT_BUFFER: valid +0x12300250: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300254: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300258: 0x00000050: vertex count +0x1230025c: 0x000000f4: start vertex +0x12300260: 0x00000001: instance count +0x12300264: 0x00000000: start instance +0x12300268: 0x00000000: index bias +0x1230026c: 0x02000000: MI_FLUSH +0x12300270: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300274: 0x00007aa0: VS state +0x12300278: 0x000079c1: GS state +0x1230027c: 0x00007a61: Clip state +0x12300280: 0x00007ac0: SF state +0x12300284: 0x00007b00: WM state +0x12300288: 0x00007cc0: CC state +0x1230028c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300290: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300294: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300298: 0x60020100: CONSTANT_BUFFER: valid +0x1230029c: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123002a0: 0x02000000: MI_FLUSH +0x123002a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002a8: 0x000079a0: VS state +0x123002ac: 0x000079c1: GS state +0x123002b0: 0x00007a61: Clip state +0x123002b4: 0x00007ac0: SF state +0x123002b8: 0x00007b00: WM state +0x123002bc: 0x00007cc0: CC state +0x123002c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123002c4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123002c8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123002cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123002d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123002d4: 0x00000f48: buffer address +0x123002d8: 0x00007fff: max index +0x123002dc: 0x00000000: mbz +0x123002e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002f0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002f4: 0x60020100: CONSTANT_BUFFER: valid +0x123002f8: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300300: 0x000000a2: vertex count +0x12300304: 0x00000000: start vertex +0x12300308: 0x00000001: instance count +0x1230030c: 0x00000000: start instance +0x12300310: 0x00000000: index bias +0x12300314: 0x02000000: MI_FLUSH +0x12300318: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230031c: 0x000079a0: VS state +0x12300320: 0x00000000: GS state +0x12300324: 0x00007901: Clip state +0x12300328: 0x00007940: SF state +0x1230032c: 0x00007960: WM state +0x12300330: 0x00007cc0: CC state +0x12300334: 0x00000000: MI_NOOP +0x12300338: 0x00000000: MI_NOOP +0x1230033c: 0x00000000: MI_NOOP +0x12300340: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300344: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300348: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230034c: 0x60020100: CONSTANT_BUFFER: valid +0x12300350: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300354: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300358: 0x0000002a: vertex count +0x1230035c: 0x000000a2: start vertex +0x12300360: 0x00000001: instance count +0x12300364: 0x00000000: start instance +0x12300368: 0x00000000: index bias +0x1230036c: 0x02000000: MI_FLUSH +0x12300370: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300374: 0x00007860: VS state +0x12300378: 0x00007801: GS state +0x1230037c: 0x00007821: Clip state +0x12300380: 0x00007880: SF state +0x12300384: 0x000078a0: WM state +0x12300388: 0x00007cc0: CC state +0x1230038c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300390: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300394: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300398: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230039c: 0x0000000c: buffer 0: sequential, pitch 12b +0x123003a0: 0x00002268: buffer address +0x123003a4: 0x00007fff: max index +0x123003a8: 0x00000000: mbz +0x123003ac: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123003b0: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123003b4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123003b8: 0x60020100: CONSTANT_BUFFER: valid +0x123003bc: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123003c4: 0x0000002a: vertex count +0x123003c8: 0x00000000: start vertex +0x123003cc: 0x00000001: instance count +0x123003d0: 0x00000000: start instance +0x123003d4: 0x00000000: index bias +0x123003d8: 0x02000000: MI_FLUSH +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077e1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300408: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x12300414: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300418: 0x00000028: vertex count +0x1230041c: 0x0000002a: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x02000000: MI_FLUSH +0x12300430: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300434: 0x00007860: VS state +0x12300438: 0x000077c1: GS state +0x1230043c: 0x00007821: Clip state +0x12300440: 0x00007880: SF state +0x12300444: 0x000078a0: WM state +0x12300448: 0x00007cc0: CC state +0x1230044c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300450: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300454: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300458: 0x60020100: CONSTANT_BUFFER: valid +0x1230045c: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300460: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300464: 0x0000002a: vertex count +0x12300468: 0x00000052: start vertex +0x1230046c: 0x00000001: instance count +0x12300470: 0x00000000: start instance +0x12300474: 0x00000000: index bias +0x12300478: 0x02000000: MI_FLUSH +0x1230047c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300480: 0x00007860: VS state +0x12300484: 0x000077a1: GS state +0x12300488: 0x00007821: Clip state +0x1230048c: 0x00007880: SF state +0x12300490: 0x000078a0: WM state +0x12300494: 0x00007cc0: CC state +0x12300498: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230049c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123004a0: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123004a4: 0x60020100: CONSTANT_BUFFER: valid +0x123004a8: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004ac: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123004b0: 0x00000028: vertex count +0x123004b4: 0x0000007c: start vertex +0x123004b8: 0x00000001: instance count +0x123004bc: 0x00000000: start instance +0x123004c0: 0x00000000: index bias +0x123004c4: 0x02000000: MI_FLUSH +0x123004c8: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004cc: 0x00007860: VS state +0x123004d0: 0x00007781: GS state +0x123004d4: 0x00007821: Clip state +0x123004d8: 0x00007880: SF state +0x123004dc: 0x000078a0: WM state +0x123004e0: 0x00007cc0: CC state +0x123004e4: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004e8: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123004ec: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123004f0: 0x60020100: CONSTANT_BUFFER: valid +0x123004f4: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004f8: 0x02000000: MI_FLUSH +0x123004fc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300500: 0x00007760: VS state +0x12300504: 0x00007781: GS state +0x12300508: 0x00007821: Clip state +0x1230050c: 0x00007880: SF state +0x12300510: 0x000078a0: WM state +0x12300514: 0x00007cc0: CC state +0x12300518: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230051c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300520: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300524: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300528: 0x00000018: buffer 0: sequential, pitch 24b +0x1230052c: 0x00002a30: buffer address +0x12300530: 0x00007fff: max index +0x12300534: 0x00000000: mbz +0x12300538: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x1230053c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300540: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300544: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300548: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230054c: 0x60020100: CONSTANT_BUFFER: valid +0x12300550: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300554: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300558: 0x00000052: vertex count +0x1230055c: 0x00000000: start vertex +0x12300560: 0x00000001: instance count +0x12300564: 0x00000000: start instance +0x12300568: 0x00000000: index bias +0x1230056c: 0x02000000: MI_FLUSH +0x12300570: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300574: 0x00007760: VS state +0x12300578: 0x00000000: GS state +0x1230057c: 0x000076c1: Clip state +0x12300580: 0x00007700: SF state +0x12300584: 0x00007720: WM state +0x12300588: 0x00007cc0: CC state +0x1230058c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300590: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300594: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300598: 0x60020100: CONSTANT_BUFFER: valid +0x1230059c: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123005a0: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x123005a4: 0x00000016: vertex count +0x123005a8: 0x00000052: start vertex +0x123005ac: 0x00000001: instance count +0x123005b0: 0x00000000: start instance +0x123005b4: 0x00000000: index bias +0x123005b8: 0x02000000: MI_FLUSH +0x123005bc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005c0: 0x00007620: VS state +0x123005c4: 0x000075c1: GS state +0x123005c8: 0x000075e1: Clip state +0x123005cc: 0x00007640: SF state +0x123005d0: 0x00007660: WM state +0x123005d4: 0x00007cc0: CC state +0x123005d8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005dc: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123005e0: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123005e4: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123005e8: 0x0000000c: buffer 0: sequential, pitch 12b +0x123005ec: 0x000033f0: buffer address +0x123005f0: 0x00007fff: max index +0x123005f4: 0x00000000: mbz +0x123005f8: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005fc: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300600: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300604: 0x60020100: CONSTANT_BUFFER: valid +0x12300608: 0x00000502: offset: 0x00000500, length: 192 bytes +0x1230060c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300610: 0x0000002a: vertex count +0x12300614: 0x00000000: start vertex +0x12300618: 0x00000001: instance count +0x1230061c: 0x00000000: start instance +0x12300620: 0x00000000: index bias +0x12300624: 0x02000000: MI_FLUSH +0x12300628: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230062c: 0x00007620: VS state +0x12300630: 0x000075a1: GS state +0x12300634: 0x000075e1: Clip state +0x12300638: 0x00007640: SF state +0x1230063c: 0x00007660: WM state +0x12300640: 0x00007cc0: CC state +0x12300644: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300648: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x1230064c: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300650: 0x60020100: CONSTANT_BUFFER: valid +0x12300654: 0x00000502: offset: 0x00000500, length: 192 bytes +0x12300658: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230065c: 0x00000028: vertex count +0x12300660: 0x0000002a: start vertex +0x12300664: 0x00000001: instance count +0x12300668: 0x00000000: start instance +0x1230066c: 0x00000000: index bias +0x12300670: 0x02000000: MI_FLUSH +0x12300674: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300678: 0x00007620: VS state +0x1230067c: 0x00007581: GS state +0x12300680: 0x000075e1: Clip state +0x12300684: 0x00007640: SF state +0x12300688: 0x00007660: WM state +0x1230068c: 0x00007cc0: CC state +0x12300690: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300694: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300698: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x1230069c: 0x60020100: CONSTANT_BUFFER: valid +0x123006a0: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006a4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123006a8: 0x0000002a: vertex count +0x123006ac: 0x00000052: start vertex +0x123006b0: 0x00000001: instance count +0x123006b4: 0x00000000: start instance +0x123006b8: 0x00000000: index bias +0x123006bc: 0x02000000: MI_FLUSH +0x123006c0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006c4: 0x00007620: VS state +0x123006c8: 0x00007561: GS state +0x123006cc: 0x000075e1: Clip state +0x123006d0: 0x00007640: SF state +0x123006d4: 0x00007660: WM state +0x123006d8: 0x00007cc0: CC state +0x123006dc: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006e0: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123006e4: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123006e8: 0x60020100: CONSTANT_BUFFER: valid +0x123006ec: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006f0: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123006f4: 0x00000028: vertex count +0x123006f8: 0x0000007c: start vertex +0x123006fc: 0x00000001: instance count +0x12300700: 0x00000000: start instance +0x12300704: 0x00000000: index bias +0x12300708: 0x02000000: MI_FLUSH +0x1230070c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300710: 0x00007620: VS state +0x12300714: 0x00007541: GS state +0x12300718: 0x000075e1: Clip state +0x1230071c: 0x00007640: SF state +0x12300720: 0x00007660: WM state +0x12300724: 0x00007cc0: CC state +0x12300728: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230072c: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300730: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x1230073c: 0x02000000: MI_FLUSH +0x12300740: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300744: 0x00007520: VS state +0x12300748: 0x00007541: GS state +0x1230074c: 0x000075e1: Clip state +0x12300750: 0x00007640: SF state +0x12300754: 0x00007660: WM state +0x12300758: 0x00007cc0: CC state +0x1230075c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300760: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x12300764: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x12300768: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230076c: 0x00000018: buffer 0: sequential, pitch 24b +0x12300770: 0x00003bb8: buffer address +0x12300774: 0x00007fff: max index +0x12300778: 0x00000000: mbz +0x1230077c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300780: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300784: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300788: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x1230078c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300790: 0x60020100: CONSTANT_BUFFER: valid +0x12300794: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300798: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x1230079c: 0x00000052: vertex count +0x123007a0: 0x00000000: start vertex +0x123007a4: 0x00000001: instance count +0x123007a8: 0x00000000: start instance +0x123007ac: 0x00000000: index bias +0x123007b0: 0x02000000: MI_FLUSH +0x123007b4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123007b8: 0x00007520: VS state +0x123007bc: 0x00000000: GS state +0x123007c0: 0x00007481: Clip state +0x123007c4: 0x000074c0: SF state +0x123007c8: 0x000074e0: WM state +0x123007cc: 0x00007cc0: CC state +0x123007d0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123007d4: 0x12444100: vs fence: 256, clip_fence: 292, gs_fence: 272 +0x123007d8: 0x40000184: sf fence: 388, vfe_fence: 0, cs_fence: 1024 +0x123007dc: 0x60020100: CONSTANT_BUFFER: valid +0x123007e0: 0x00000682: offset: 0x00000680, length: 192 bytes +0x123007e4: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x123007e8: 0x00000016: vertex count +0x123007ec: 0x00000052: start vertex +0x123007f0: 0x00000001: instance count +0x123007f4: 0x00000000: start instance +0x123007f8: 0x00000000: index bias +0x123007fc: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen5-3d.batch.sh b/intel/tests/gen5-3d.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gen5-3d.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/gen6-3d.batch b/intel/tests/gen6-3d.batch new file mode 100644 index 0000000..d57147e Binary files /dev/null and b/intel/tests/gen6-3d.batch differ diff --git a/intel/tests/gen6-3d.batch-ref.txt b/intel/tests/gen6-3d.batch-ref.txt new file mode 100644 index 0000000..9499ed1 --- /dev/null +++ b/intel/tests/gen6-3d.batch-ref.txt @@ -0,0 +1,990 @@ +0x12300000: 0x7a000002: PIPE_CONTROL +0x12300004: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300008: 0x00000000: +0x1230000c: 0x00000000: +0x12300010: 0x7a000002: PIPE_CONTROL +0x12300014: 0x00004000: qword write, +0x12300018: 0x00000000: +0x1230001c: 0x00000000: +0x12300020: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300024: 0x790d0001: 3DSTATE_MULTISAMPLE +0x12300028: 0x00000000: dword 1 +0x1230002c: 0x00000000: dword 2 +0x12300030: 0x78180000: 3DSTATE_SAMPLE_MASK +0x12300034: 0x00000001: dword 1 +0x12300038: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230003c: 0x00000000: dword 1 +0x12300040: 0x00000000: dword 2 +0x12300044: 0xffffffff: dword 3 +0x12300048: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230004c: 0x20000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0xffffffff: dword 3 +0x12300058: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230005c: 0x40000000: dword 1 +0x12300060: 0x00000000: dword 2 +0x12300064: 0xffffffff: dword 3 +0x12300068: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x1230006c: 0x60000000: dword 1 +0x12300070: 0x00000000: dword 2 +0x12300074: 0xffffffff: dword 3 +0x12300078: 0x61020000: STATE_SIP +0x1230007c: 0x00000000: dword 1 +0x12300080: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300084: 0x61010008: STATE_BASE_ADDRESS +0x12300088: 0x00000001: general state base address 0x00000000 +0x1230008c: 0x00000001: surface state base address 0x00000000 +0x12300090: 0x00000001: dynamic state base address 0x00000000 +0x12300094: 0x00000001: indirect state base address 0x00000000 +0x12300098: 0x00000001: instruction state base address 0x00000000 +0x1230009c: 0x00000001: general state upper bound disabled +0x123000a0: 0x00000001: dynamic state upper bound disabled +0x123000a4: 0x00000001: indirect state upper bound disabled +0x123000a8: 0x00000001: instruction state upper bound disabled +0x123000ac: 0x780d1c02: 3DSTATE_VIEWPORT_STATE_POINTERS +0x123000b0: 0x00007fe0: clip +0x123000b4: 0x00007fc0: sf +0x123000b8: 0x00007fa0: cc +0x123000bc: 0x78050001: 3DSTATE_URB +0x123000c0: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123000c4: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123000c8: 0x780e0002: 3DSTATE_CC_STATE_POINTERS +0x123000cc: 0x00007f81: blend change 1 +0x123000d0: 0x00007f01: depth stencil change 1 +0x123000d4: 0x00007f41: cc change 1 +0x123000d8: 0x78021302: 3DSTATE_SAMPLER_STATE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123000dc: 0x00000000: VS sampler state +0x123000e0: 0x00000000: GS sampler state +0x123000e4: 0x00000000: WM sampler state +0x123000e8: 0x78150003: 3DSTATE_CONSTANT_VS_STATE +0x123000ec: 0x00000000: dword 1 +0x123000f0: 0x00000000: dword 2 +0x123000f4: 0x00000000: dword 3 +0x123000f8: 0x00000000: dword 4 +0x123000fc: 0x78100004: 3DSTATE_VS +0x12300100: 0x00000000: kernel pointer +0x12300104: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300108: 0x00000000: scratch offset +0x1230010c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300110: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300114: 0x7a000002: PIPE_CONTROL +0x12300118: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x1230011c: 0x00000000: +0x12300120: 0x00000000: +0x12300124: 0x78160003: 3DSTATE_CONSTANT_GS_STATE +0x12300128: 0x00000000: dword 1 +0x1230012c: 0x00000000: dword 2 +0x12300130: 0x00000000: dword 3 +0x12300134: 0x00000000: dword 4 +0x12300138: 0x78110005: 3DSTATE_GS +0x1230013c: 0x00000000: kernel pointer +0x12300140: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300144: 0x00000000: scratch offset +0x12300148: 0x00000001: Dispatch GRF start 1, VUE read length 0, VUE read offset 0 +0x1230014c: 0x00000500: Max Threads 1, Rendering enable +0x12300150: 0x00000000: Reorder disable, Discard Adjaceny disable, GS disable +0x12300154: 0x78120002: 3DSTATE_CLIP +0x12300158: 0x00000400: UserClip distance cull test mask 0x0 +0x1230015c: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300160: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300164: 0x78130012: 3DSTATE_SF +0x12300168: 0x00200810: Attrib Out 0, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x1230016c: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300170: 0x22000000: AA disable, CullMode 1, Scissor disable, Multisample m ode 0 +0x12300174: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300178: 0x00000000: Global Depth Offset Constant 0.000000 +0x1230017c: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300180: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300184: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300188: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230018c: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300190: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300194: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300198: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230019c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123001a0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123001a4: 0x00000000: Point Sprite TexCoord Enable +0x123001a8: 0x00000000: Const Interp Enable +0x123001ac: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123001b0: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123001b4: 0x78171003: 3DSTATE_CONSTANT_PS_STATE +0x123001b8: 0x00007ee0: dword 1 +0x123001bc: 0x00000000: dword 2 +0x123001c0: 0x00000000: dword 3 +0x123001c4: 0x00000000: dword 4 +0x123001c8: 0x78140007: 3DSTATE_WM +0x123001cc: 0x000000c0: kernel start pointer 0 +0x123001d0: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123001d4: 0x00000000: scratch offset +0x123001d8: 0x80020002: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 2 +0x123001dc: 0x4e084003: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 1 +0x123001e0: 0x00000000: Num SF output 0, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123001e4: 0x00000000: kernel start pointer 1 +0x123001e8: 0x00000140: kernel start pointer 2 +0x123001ec: 0x780f0000: 3DSTATE_SCISSOR_POINTERS +0x123001f0: 0x00007d20: scissor rect offset +0x123001f4: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123001f8: 0x00007d40: VS binding table +0x123001fc: 0x00007d40: GS binding table +0x12300200: 0x00007d40: WM binding table +0x12300204: 0x7a000002: PIPE_CONTROL +0x12300208: 0x00002000: no write, depth stall, +0x1230020c: 0x00000000: +0x12300210: 0x00000000: +0x12300214: 0x7a000002: PIPE_CONTROL +0x12300218: 0x00000001: no write, depth cache flush, +0x1230021c: 0x00000000: +0x12300220: 0x00000000: +0x12300224: 0x7a000002: PIPE_CONTROL +0x12300228: 0x00002000: no write, depth stall, +0x1230022c: 0x00000000: +0x12300230: 0x00000000: +0x12300234: 0x79050005: 3DSTATE_DEPTH_BUFFER +0x12300238: 0x2c6c05ff: 2D, unknown, pitch = 1536 bytes, tiled, HiZ 1, Seperate Stencil 1 +0x1230023c: 0x00000000: depth offset +0x12300240: 0x09584ac0: 300x300 +0x12300244: 0x00000000: volume depth +0x12300248: 0x00000000: +0x1230024c: 0x00000000: +0x12300250: 0x790f0001: 3D UNKNOWN: 3d_965 opcode = 0x790f +0x12300254: 0x000005ff: MI_NOOP +0x12300258: 0x00000000: MI_NOOP +0x1230025c: 0x790e0001: 3D UNKNOWN: 3d_965 opcode = 0x790e +0x12300260: 0x0000027f: MI_NOOP +0x12300264: 0x00000000: MI_NOOP +0x12300268: 0x79100000: 3DSTATE_CLEAR_PARAMS +0x1230026c: 0x00000000: dword 1 +0x12300270: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x12300274: 0x00000000: top left: 0,0 +0x12300278: 0x012b012b: bottom right: 299,299 +0x1230027c: 0x00000000: origin: 0,0 +0x12300280: 0x790b0002: 3DSTATE_GS_SVB_INDEX +0x12300284: 0x00000000: dword 1 +0x12300288: 0x00000000: dword 2 +0x1230028c: 0x00000000: dword 3 +0x12300290: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300294: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300298: 0x00000000: buffer address +0x1230029c: 0x0000ffff: max index +0x123002a0: 0x00000000: mbz +0x123002a4: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123002a8: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002ac: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b0: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123002b4: 0x00000004: vertex count +0x123002b8: 0x00000000: start vertex +0x123002bc: 0x00000001: instance count +0x123002c0: 0x00000000: start instance +0x123002c4: 0x00000000: index bias +0x123002c8: 0x78050001: 3DSTATE_URB +0x123002cc: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123002d0: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123002d4: 0x780e0002: 3DSTATE_CC_STATE_POINTERS +0x123002d8: 0x00007f81: blend change 1 +0x123002dc: 0x00007cc1: depth stencil change 1 +0x123002e0: 0x00007d01: cc change 1 +0x123002e4: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x123002e8: 0x00007b85: dword 1 +0x123002ec: 0x00000000: dword 2 +0x123002f0: 0x00000000: dword 3 +0x123002f4: 0x00000000: dword 4 +0x123002f8: 0x78100004: 3DSTATE_VS +0x123002fc: 0x00000240: kernel pointer +0x12300300: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300304: 0x00000000: scratch offset +0x12300308: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230030c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300310: 0x7a000002: PIPE_CONTROL +0x12300314: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300318: 0x00000000: +0x1230031c: 0x00000000: +0x12300320: 0x7a000002: PIPE_CONTROL +0x12300324: 0x00004000: qword write, +0x12300328: 0x00000000: +0x1230032c: 0x00000000: +0x12300330: 0x7a000002: PIPE_CONTROL +0x12300334: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300338: 0x00000000: +0x1230033c: 0x00000000: +0x12300340: 0x78120002: 3DSTATE_CLIP +0x12300344: 0x00000400: UserClip distance cull test mask 0x0 +0x12300348: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x1230034c: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300350: 0x78130012: 3DSTATE_SF +0x12300354: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300358: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x1230035c: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300360: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300364: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300368: 0x00000000: Global Depth Offset Scale 0.000000 +0x1230036c: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300370: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300374: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300378: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230037c: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300380: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300384: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300388: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230038c: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300390: 0x00000000: Point Sprite TexCoord Enable +0x12300394: 0x00000001: Const Interp Enable +0x12300398: 0x00000000: Attrib 7-0 WrapShortest Enable +0x1230039c: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123003a0: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123003a4: 0x00000000: dword 1 +0x123003a8: 0x00000000: dword 2 +0x123003ac: 0x00000000: dword 3 +0x123003b0: 0x00000000: dword 4 +0x123003b4: 0x78140007: 3DSTATE_WM +0x123003b8: 0x00000500: kernel start pointer 0 +0x123003bc: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123003c0: 0x00000000: scratch offset +0x123003c4: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123003c8: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123003cc: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123003d0: 0x00000000: kernel start pointer 1 +0x123003d4: 0x00000500: kernel start pointer 2 +0x123003d8: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123003dc: 0x00007a00: VS binding table +0x123003e0: 0x00007a00: GS binding table +0x123003e4: 0x00007a00: WM binding table +0x123003e8: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123003ec: 0x0000000c: buffer 0: sequential, pitch 12b +0x123003f0: 0x00000000: buffer address +0x123003f4: 0x00007fff: max index +0x123003f8: 0x00000000: mbz +0x123003fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300400: 0x00000052: vertex count +0x12300404: 0x00000000: start vertex +0x12300408: 0x00000001: instance count +0x1230040c: 0x00000000: start instance +0x12300410: 0x00000000: index bias +0x12300414: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300418: 0x00000050: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300430: 0x000078c5: dword 1 +0x12300434: 0x00000000: dword 2 +0x12300438: 0x00000000: dword 3 +0x1230043c: 0x00000000: dword 4 +0x12300440: 0x78100004: 3DSTATE_VS +0x12300444: 0x00000240: kernel pointer +0x12300448: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x1230044c: 0x00000000: scratch offset +0x12300450: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300454: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300458: 0x7a000002: PIPE_CONTROL +0x1230045c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300460: 0x00000000: +0x12300464: 0x00000000: +0x12300468: 0x7a000002: PIPE_CONTROL +0x1230046c: 0x00004000: qword write, +0x12300470: 0x00000000: +0x12300474: 0x00000000: +0x12300478: 0x7a000002: PIPE_CONTROL +0x1230047c: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300480: 0x00000000: +0x12300484: 0x00000000: +0x12300488: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x1230048c: 0x00000000: dword 1 +0x12300490: 0x00000000: dword 2 +0x12300494: 0x00000000: dword 3 +0x12300498: 0x00000000: dword 4 +0x1230049c: 0x78140007: 3DSTATE_WM +0x123004a0: 0x00000500: kernel start pointer 0 +0x123004a4: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123004a8: 0x00000000: scratch offset +0x123004ac: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123004b0: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123004b4: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123004b8: 0x00000000: kernel start pointer 1 +0x123004bc: 0x00000500: kernel start pointer 2 +0x123004c0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123004c4: 0x00000052: vertex count +0x123004c8: 0x000000a2: start vertex +0x123004cc: 0x00000001: instance count +0x123004d0: 0x00000000: start instance +0x123004d4: 0x00000000: index bias +0x123004d8: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123004dc: 0x00000050: vertex count +0x123004e0: 0x000000f4: start vertex +0x123004e4: 0x00000001: instance count +0x123004e8: 0x00000000: start instance +0x123004ec: 0x00000000: index bias +0x123004f0: 0x78050001: 3DSTATE_URB +0x123004f4: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x123004f8: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x123004fc: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300500: 0x00007785: dword 1 +0x12300504: 0x00000000: dword 2 +0x12300508: 0x00000000: dword 3 +0x1230050c: 0x00000000: dword 4 +0x12300510: 0x78100004: 3DSTATE_VS +0x12300514: 0x00000640: kernel pointer +0x12300518: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x1230051c: 0x00000000: scratch offset +0x12300520: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300524: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300528: 0x7a000002: PIPE_CONTROL +0x1230052c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300530: 0x00000000: +0x12300534: 0x00000000: +0x12300538: 0x7a000002: PIPE_CONTROL +0x1230053c: 0x00004000: qword write, +0x12300540: 0x00000000: +0x12300544: 0x00000000: +0x12300548: 0x7a000002: PIPE_CONTROL +0x1230054c: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300550: 0x00000000: +0x12300554: 0x00000000: +0x12300558: 0x78130012: 3DSTATE_SF +0x1230055c: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300560: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300564: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300568: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x1230056c: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300570: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300574: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300578: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230057c: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300580: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300584: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300588: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230058c: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300590: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300594: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300598: 0x00000000: Point Sprite TexCoord Enable +0x1230059c: 0x00000001: Const Interp Enable +0x123005a0: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123005a4: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123005a8: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123005ac: 0x00007600: VS binding table +0x123005b0: 0x00007600: GS binding table +0x123005b4: 0x00007600: WM binding table +0x123005b8: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123005bc: 0x00000018: buffer 0: sequential, pitch 24b +0x123005c0: 0x00000f48: buffer address +0x123005c4: 0x00007fff: max index +0x123005c8: 0x00000000: mbz +0x123005cc: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123005d0: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005d4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005d8: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123005dc: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005e0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005e4: 0x000000a2: vertex count +0x123005e8: 0x00000000: start vertex +0x123005ec: 0x00000001: instance count +0x123005f0: 0x00000000: start instance +0x123005f4: 0x00000000: index bias +0x123005f8: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x123005fc: 0x000074c5: dword 1 +0x12300600: 0x00000000: dword 2 +0x12300604: 0x00000000: dword 3 +0x12300608: 0x00000000: dword 4 +0x1230060c: 0x78100004: 3DSTATE_VS +0x12300610: 0x00000640: kernel pointer +0x12300614: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300618: 0x00000000: scratch offset +0x1230061c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300620: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300624: 0x7a000002: PIPE_CONTROL +0x12300628: 0x00100002: no write, cs stall, stall at scoreboard, +0x1230062c: 0x00000000: +0x12300630: 0x00000000: +0x12300634: 0x7a000002: PIPE_CONTROL +0x12300638: 0x00004000: qword write, +0x1230063c: 0x00000000: +0x12300640: 0x00000000: +0x12300644: 0x7a000002: PIPE_CONTROL +0x12300648: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x1230064c: 0x00000000: +0x12300650: 0x00000000: +0x12300654: 0x78120002: 3DSTATE_CLIP +0x12300658: 0x00000400: UserClip distance cull test mask 0x0 +0x1230065c: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300660: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300664: 0x78130012: 3DSTATE_SF +0x12300668: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x1230066c: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300670: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300674: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300678: 0x00000000: Global Depth Offset Constant 0.000000 +0x1230067c: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300680: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300684: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300688: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230068c: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300690: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300694: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300698: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x1230069c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123006a0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123006a4: 0x00000000: Point Sprite TexCoord Enable +0x123006a8: 0x00000000: Const Interp Enable +0x123006ac: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123006b0: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123006b4: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123006b8: 0x00000000: dword 1 +0x123006bc: 0x00000000: dword 2 +0x123006c0: 0x00000000: dword 3 +0x123006c4: 0x00000000: dword 4 +0x123006c8: 0x78140007: 3DSTATE_WM +0x123006cc: 0x00000900: kernel start pointer 0 +0x123006d0: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123006d4: 0x00000000: scratch offset +0x123006d8: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x123006dc: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123006e0: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123006e4: 0x00000000: kernel start pointer 1 +0x123006e8: 0x00000900: kernel start pointer 2 +0x123006ec: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123006f0: 0x0000002a: vertex count +0x123006f4: 0x000000a2: start vertex +0x123006f8: 0x00000001: instance count +0x123006fc: 0x00000000: start instance +0x12300700: 0x00000000: index bias +0x12300704: 0x78050001: 3DSTATE_URB +0x12300708: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x1230070c: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300710: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300714: 0x00007385: dword 1 +0x12300718: 0x00000000: dword 2 +0x1230071c: 0x00000000: dword 3 +0x12300720: 0x00000000: dword 4 +0x12300724: 0x78100004: 3DSTATE_VS +0x12300728: 0x00000240: kernel pointer +0x1230072c: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300730: 0x00000000: scratch offset +0x12300734: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300738: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x1230073c: 0x7a000002: PIPE_CONTROL +0x12300740: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300744: 0x00000000: +0x12300748: 0x00000000: +0x1230074c: 0x7a000002: PIPE_CONTROL +0x12300750: 0x00004000: qword write, +0x12300754: 0x00000000: +0x12300758: 0x00000000: +0x1230075c: 0x7a000002: PIPE_CONTROL +0x12300760: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300764: 0x00000000: +0x12300768: 0x00000000: +0x1230076c: 0x78120002: 3DSTATE_CLIP +0x12300770: 0x00000400: UserClip distance cull test mask 0x0 +0x12300774: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300778: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x1230077c: 0x78130012: 3DSTATE_SF +0x12300780: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300784: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300788: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x1230078c: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300790: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300794: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300798: 0x00000000: Global Depth Offset Clamp 0.000000 +0x1230079c: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a0: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a4: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007a8: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007ac: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b0: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b4: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007b8: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123007bc: 0x00000000: Point Sprite TexCoord Enable +0x123007c0: 0x00000001: Const Interp Enable +0x123007c4: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123007c8: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123007cc: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123007d0: 0x00000000: dword 1 +0x123007d4: 0x00000000: dword 2 +0x123007d8: 0x00000000: dword 3 +0x123007dc: 0x00000000: dword 4 +0x123007e0: 0x78140007: 3DSTATE_WM +0x123007e4: 0x00000500: kernel start pointer 0 +0x123007e8: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123007ec: 0x00000000: scratch offset +0x123007f0: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123007f4: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123007f8: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123007fc: 0x00000000: kernel start pointer 1 +0x12300800: 0x00000500: kernel start pointer 2 +0x12300804: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300808: 0x00007200: VS binding table +0x1230080c: 0x00007200: GS binding table +0x12300810: 0x00007200: WM binding table +0x12300814: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300818: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230081c: 0x00002268: buffer address +0x12300820: 0x00007fff: max index +0x12300824: 0x00000000: mbz +0x12300828: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230082c: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300830: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300834: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300838: 0x0000002a: vertex count +0x1230083c: 0x00000000: start vertex +0x12300840: 0x00000001: instance count +0x12300844: 0x00000000: start instance +0x12300848: 0x00000000: index bias +0x1230084c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300850: 0x00000028: vertex count +0x12300854: 0x0000002a: start vertex +0x12300858: 0x00000001: instance count +0x1230085c: 0x00000000: start instance +0x12300860: 0x00000000: index bias +0x12300864: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300868: 0x000070c5: dword 1 +0x1230086c: 0x00000000: dword 2 +0x12300870: 0x00000000: dword 3 +0x12300874: 0x00000000: dword 4 +0x12300878: 0x78100004: 3DSTATE_VS +0x1230087c: 0x00000240: kernel pointer +0x12300880: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300884: 0x00000000: scratch offset +0x12300888: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230088c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300890: 0x7a000002: PIPE_CONTROL +0x12300894: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300898: 0x00000000: +0x1230089c: 0x00000000: +0x123008a0: 0x7a000002: PIPE_CONTROL +0x123008a4: 0x00004000: qword write, +0x123008a8: 0x00000000: +0x123008ac: 0x00000000: +0x123008b0: 0x7a000002: PIPE_CONTROL +0x123008b4: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x123008b8: 0x00000000: +0x123008bc: 0x00000000: +0x123008c0: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x123008c4: 0x00000000: dword 1 +0x123008c8: 0x00000000: dword 2 +0x123008cc: 0x00000000: dword 3 +0x123008d0: 0x00000000: dword 4 +0x123008d4: 0x78140007: 3DSTATE_WM +0x123008d8: 0x00000500: kernel start pointer 0 +0x123008dc: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123008e0: 0x00000000: scratch offset +0x123008e4: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x123008e8: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x123008ec: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x123008f0: 0x00000000: kernel start pointer 1 +0x123008f4: 0x00000500: kernel start pointer 2 +0x123008f8: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123008fc: 0x0000002a: vertex count +0x12300900: 0x00000052: start vertex +0x12300904: 0x00000001: instance count +0x12300908: 0x00000000: start instance +0x1230090c: 0x00000000: index bias +0x12300910: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300914: 0x00000028: vertex count +0x12300918: 0x0000007c: start vertex +0x1230091c: 0x00000001: instance count +0x12300920: 0x00000000: start instance +0x12300924: 0x00000000: index bias +0x12300928: 0x78050001: 3DSTATE_URB +0x1230092c: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300930: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300934: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300938: 0x00006f85: dword 1 +0x1230093c: 0x00000000: dword 2 +0x12300940: 0x00000000: dword 3 +0x12300944: 0x00000000: dword 4 +0x12300948: 0x78100004: 3DSTATE_VS +0x1230094c: 0x00000640: kernel pointer +0x12300950: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300954: 0x00000000: scratch offset +0x12300958: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x1230095c: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300960: 0x7a000002: PIPE_CONTROL +0x12300964: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300968: 0x00000000: +0x1230096c: 0x00000000: +0x12300970: 0x7a000002: PIPE_CONTROL +0x12300974: 0x00004000: qword write, +0x12300978: 0x00000000: +0x1230097c: 0x00000000: +0x12300980: 0x7a000002: PIPE_CONTROL +0x12300984: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300988: 0x00000000: +0x1230098c: 0x00000000: +0x12300990: 0x78130012: 3DSTATE_SF +0x12300994: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300998: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x1230099c: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x123009a0: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x123009a4: 0x00000000: Global Depth Offset Constant 0.000000 +0x123009a8: 0x00000000: Global Depth Offset Scale 0.000000 +0x123009ac: 0x00000000: Global Depth Offset Clamp 0.000000 +0x123009b0: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009b4: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009b8: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009bc: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c0: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c4: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009c8: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009cc: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x123009d0: 0x00000000: Point Sprite TexCoord Enable +0x123009d4: 0x00000001: Const Interp Enable +0x123009d8: 0x00000000: Attrib 7-0 WrapShortest Enable +0x123009dc: 0x00000000: Attrib 15-8 WrapShortest Enable +0x123009e0: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x123009e4: 0x00006e00: VS binding table +0x123009e8: 0x00006e00: GS binding table +0x123009ec: 0x00006e00: WM binding table +0x123009f0: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123009f4: 0x00000018: buffer 0: sequential, pitch 24b +0x123009f8: 0x00002a30: buffer address +0x123009fc: 0x00007fff: max index +0x12300a00: 0x00000000: mbz +0x12300a04: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300a08: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300a0c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300a10: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300a14: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300a18: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300a1c: 0x00000052: vertex count +0x12300a20: 0x00000000: start vertex +0x12300a24: 0x00000001: instance count +0x12300a28: 0x00000000: start instance +0x12300a2c: 0x00000000: index bias +0x12300a30: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300a34: 0x00006cc5: dword 1 +0x12300a38: 0x00000000: dword 2 +0x12300a3c: 0x00000000: dword 3 +0x12300a40: 0x00000000: dword 4 +0x12300a44: 0x78100004: 3DSTATE_VS +0x12300a48: 0x00000640: kernel pointer +0x12300a4c: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300a50: 0x00000000: scratch offset +0x12300a54: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300a58: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300a5c: 0x7a000002: PIPE_CONTROL +0x12300a60: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300a64: 0x00000000: +0x12300a68: 0x00000000: +0x12300a6c: 0x7a000002: PIPE_CONTROL +0x12300a70: 0x00004000: qword write, +0x12300a74: 0x00000000: +0x12300a78: 0x00000000: +0x12300a7c: 0x7a000002: PIPE_CONTROL +0x12300a80: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300a84: 0x00000000: +0x12300a88: 0x00000000: +0x12300a8c: 0x78120002: 3DSTATE_CLIP +0x12300a90: 0x00000400: UserClip distance cull test mask 0x0 +0x12300a94: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300a98: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300a9c: 0x78130012: 3DSTATE_SF +0x12300aa0: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300aa4: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300aa8: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300aac: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ab0: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300ab4: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300ab8: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300abc: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac0: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac4: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ac8: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300acc: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad0: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad4: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ad8: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300adc: 0x00000000: Point Sprite TexCoord Enable +0x12300ae0: 0x00000000: Const Interp Enable +0x12300ae4: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300ae8: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300aec: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300af0: 0x00000000: dword 1 +0x12300af4: 0x00000000: dword 2 +0x12300af8: 0x00000000: dword 3 +0x12300afc: 0x00000000: dword 4 +0x12300b00: 0x78140007: 3DSTATE_WM +0x12300b04: 0x00000900: kernel start pointer 0 +0x12300b08: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300b0c: 0x00000000: scratch offset +0x12300b10: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x12300b14: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300b18: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300b1c: 0x00000000: kernel start pointer 1 +0x12300b20: 0x00000900: kernel start pointer 2 +0x12300b24: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300b28: 0x00000016: vertex count +0x12300b2c: 0x00000052: start vertex +0x12300b30: 0x00000001: instance count +0x12300b34: 0x00000000: start instance +0x12300b38: 0x00000000: index bias +0x12300b3c: 0x78050001: 3DSTATE_URB +0x12300b40: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300b44: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300b48: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300b4c: 0x00006b85: dword 1 +0x12300b50: 0x00000000: dword 2 +0x12300b54: 0x00000000: dword 3 +0x12300b58: 0x00000000: dword 4 +0x12300b5c: 0x78100004: 3DSTATE_VS +0x12300b60: 0x00000240: kernel pointer +0x12300b64: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300b68: 0x00000000: scratch offset +0x12300b6c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300b70: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300b74: 0x7a000002: PIPE_CONTROL +0x12300b78: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300b7c: 0x00000000: +0x12300b80: 0x00000000: +0x12300b84: 0x7a000002: PIPE_CONTROL +0x12300b88: 0x00004000: qword write, +0x12300b8c: 0x00000000: +0x12300b90: 0x00000000: +0x12300b94: 0x7a000002: PIPE_CONTROL +0x12300b98: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300b9c: 0x00000000: +0x12300ba0: 0x00000000: +0x12300ba4: 0x78120002: 3DSTATE_CLIP +0x12300ba8: 0x00000400: UserClip distance cull test mask 0x0 +0x12300bac: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300bb0: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300bb4: 0x78130012: 3DSTATE_SF +0x12300bb8: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300bbc: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300bc0: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300bc4: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300bc8: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300bcc: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300bd0: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300bd4: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bd8: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bdc: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be0: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be4: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300be8: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bec: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bf0: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300bf4: 0x00000000: Point Sprite TexCoord Enable +0x12300bf8: 0x00000001: Const Interp Enable +0x12300bfc: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300c00: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300c04: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300c08: 0x00000000: dword 1 +0x12300c0c: 0x00000000: dword 2 +0x12300c10: 0x00000000: dword 3 +0x12300c14: 0x00000000: dword 4 +0x12300c18: 0x78140007: 3DSTATE_WM +0x12300c1c: 0x00000500: kernel start pointer 0 +0x12300c20: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300c24: 0x00000000: scratch offset +0x12300c28: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x12300c2c: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300c30: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300c34: 0x00000000: kernel start pointer 1 +0x12300c38: 0x00000500: kernel start pointer 2 +0x12300c3c: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300c40: 0x00006a00: VS binding table +0x12300c44: 0x00006a00: GS binding table +0x12300c48: 0x00006a00: WM binding table +0x12300c4c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300c50: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300c54: 0x000033f0: buffer address +0x12300c58: 0x00007fff: max index +0x12300c5c: 0x00000000: mbz +0x12300c60: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x12300c64: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300c68: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300c6c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300c70: 0x0000002a: vertex count +0x12300c74: 0x00000000: start vertex +0x12300c78: 0x00000001: instance count +0x12300c7c: 0x00000000: start instance +0x12300c80: 0x00000000: index bias +0x12300c84: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300c88: 0x00000028: vertex count +0x12300c8c: 0x0000002a: start vertex +0x12300c90: 0x00000001: instance count +0x12300c94: 0x00000000: start instance +0x12300c98: 0x00000000: index bias +0x12300c9c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300ca0: 0x000068c5: dword 1 +0x12300ca4: 0x00000000: dword 2 +0x12300ca8: 0x00000000: dword 3 +0x12300cac: 0x00000000: dword 4 +0x12300cb0: 0x78100004: 3DSTATE_VS +0x12300cb4: 0x00000240: kernel pointer +0x12300cb8: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300cbc: 0x00000000: scratch offset +0x12300cc0: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300cc4: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300cc8: 0x7a000002: PIPE_CONTROL +0x12300ccc: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300cd0: 0x00000000: +0x12300cd4: 0x00000000: +0x12300cd8: 0x7a000002: PIPE_CONTROL +0x12300cdc: 0x00004000: qword write, +0x12300ce0: 0x00000000: +0x12300ce4: 0x00000000: +0x12300ce8: 0x7a000002: PIPE_CONTROL +0x12300cec: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300cf0: 0x00000000: +0x12300cf4: 0x00000000: +0x12300cf8: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300cfc: 0x00000000: dword 1 +0x12300d00: 0x00000000: dword 2 +0x12300d04: 0x00000000: dword 3 +0x12300d08: 0x00000000: dword 4 +0x12300d0c: 0x78140007: 3DSTATE_WM +0x12300d10: 0x00000500: kernel start pointer 0 +0x12300d14: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300d18: 0x00000000: scratch offset +0x12300d1c: 0x80020000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 2, start[1] 0, start[2] 0 +0x12300d20: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300d24: 0x00100000: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x0, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300d28: 0x00000000: kernel start pointer 1 +0x12300d2c: 0x00000500: kernel start pointer 2 +0x12300d30: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300d34: 0x0000002a: vertex count +0x12300d38: 0x00000052: start vertex +0x12300d3c: 0x00000001: instance count +0x12300d40: 0x00000000: start instance +0x12300d44: 0x00000000: index bias +0x12300d48: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300d4c: 0x00000028: vertex count +0x12300d50: 0x0000007c: start vertex +0x12300d54: 0x00000001: instance count +0x12300d58: 0x00000000: start instance +0x12300d5c: 0x00000000: index bias +0x12300d60: 0x78050001: 3DSTATE_URB +0x12300d64: 0x00000100: VS entries 256, alloc size 1 (1024bit row) +0x12300d68: 0x00000000: GS entries 0, alloc size 1 (1024bit row) +0x12300d6c: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300d70: 0x00006785: dword 1 +0x12300d74: 0x00000000: dword 2 +0x12300d78: 0x00000000: dword 3 +0x12300d7c: 0x00000000: dword 4 +0x12300d80: 0x78100004: 3DSTATE_VS +0x12300d84: 0x00000640: kernel pointer +0x12300d88: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300d8c: 0x00000000: scratch offset +0x12300d90: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300d94: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300d98: 0x7a000002: PIPE_CONTROL +0x12300d9c: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300da0: 0x00000000: +0x12300da4: 0x00000000: +0x12300da8: 0x7a000002: PIPE_CONTROL +0x12300dac: 0x00004000: qword write, +0x12300db0: 0x00000000: +0x12300db4: 0x00000000: +0x12300db8: 0x7a000002: PIPE_CONTROL +0x12300dbc: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300dc0: 0x00000000: +0x12300dc4: 0x00000000: +0x12300dc8: 0x78130012: 3DSTATE_SF +0x12300dcc: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300dd0: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300dd4: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300dd8: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ddc: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300de0: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300de4: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300de8: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300dec: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df0: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df4: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300df8: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300dfc: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e00: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e04: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300e08: 0x00000000: Point Sprite TexCoord Enable +0x12300e0c: 0x00000001: Const Interp Enable +0x12300e10: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300e14: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300e18: 0x78011302: 3DSTATE_BINDING_TABLE_POINTERS: VS mod 1, GS mod 1, PS mod 1 +0x12300e1c: 0x00006600: VS binding table +0x12300e20: 0x00006600: GS binding table +0x12300e24: 0x00006600: WM binding table +0x12300e28: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300e2c: 0x00000018: buffer 0: sequential, pitch 24b +0x12300e30: 0x00003bb8: buffer address +0x12300e34: 0x00007fff: max index +0x12300e38: 0x00000000: mbz +0x12300e3c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300e40: 0x02400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300e44: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300e48: 0x0240000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300e4c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300e50: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300e54: 0x00000052: vertex count +0x12300e58: 0x00000000: start vertex +0x12300e5c: 0x00000001: instance count +0x12300e60: 0x00000000: start instance +0x12300e64: 0x00000000: index bias +0x12300e68: 0x78151003: 3DSTATE_CONSTANT_VS_STATE +0x12300e6c: 0x000064c5: dword 1 +0x12300e70: 0x00000000: dword 2 +0x12300e74: 0x00000000: dword 3 +0x12300e78: 0x00000000: dword 4 +0x12300e7c: 0x78100004: 3DSTATE_VS +0x12300e80: 0x00000640: kernel pointer +0x12300e84: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300e88: 0x00000000: scratch offset +0x12300e8c: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x12300e90: 0x76000401: Max Threads 60, Vertex Cache enable, VS func enable +0x12300e94: 0x7a000002: PIPE_CONTROL +0x12300e98: 0x00100002: no write, cs stall, stall at scoreboard, +0x12300e9c: 0x00000000: +0x12300ea0: 0x00000000: +0x12300ea4: 0x7a000002: PIPE_CONTROL +0x12300ea8: 0x00004000: qword write, +0x12300eac: 0x00000000: +0x12300eb0: 0x00000000: +0x12300eb4: 0x7a000002: PIPE_CONTROL +0x12300eb8: 0x00002804: no write, depth stall, instruction cache invalidate, state cache invalidate, +0x12300ebc: 0x00000000: +0x12300ec0: 0x00000000: +0x12300ec4: 0x78120002: 3DSTATE_CLIP +0x12300ec8: 0x00000400: UserClip distance cull test mask 0x0 +0x12300ecc: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x12300ed0: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x12300ed4: 0x78130012: 3DSTATE_SF +0x12300ed8: 0x00600810: Attrib Out 1, Attrib Swizzle enable, VUE read length 1, VUE read offset 1 +0x12300edc: 0x00000403: Legacy Global DepthBias disable, FrontFace fill 0, BF fill 0, VP transform enable, FrontWinding_CCW +0x12300ee0: 0x62000000: AA disable, CullMode 3, Scissor disable, Multisample m ode 0 +0x12300ee4: 0x4c000808: Last Pixel disable, SubPixel Precision 8, Use PixelWidth 1 +0x12300ee8: 0x00000000: Global Depth Offset Constant 0.000000 +0x12300eec: 0x00000000: Global Depth Offset Scale 0.000000 +0x12300ef0: 0x00000000: Global Depth Offset Clamp 0.000000 +0x12300ef4: 0x00000000: Attrib 1 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 0 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300ef8: 0x00000000: Attrib 3 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 2 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300efc: 0x00000000: Attrib 5 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 4 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f00: 0x00000000: Attrib 7 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 6 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f04: 0x00000000: Attrib 9 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 8 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f08: 0x00000000: Attrib 11 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 10 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f0c: 0x00000000: Attrib 13 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 12 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f10: 0x00000000: Attrib 15 (Override , Const Source 0, Swizzle Select 0, Source 0); Attrib 14 (Override , Const Source 0, Swizzle Select 0, Source 0) +0x12300f14: 0x00000000: Point Sprite TexCoord Enable +0x12300f18: 0x00000000: Const Interp Enable +0x12300f1c: 0x00000000: Attrib 7-0 WrapShortest Enable +0x12300f20: 0x00000000: Attrib 15-8 WrapShortest Enable +0x12300f24: 0x78170003: 3DSTATE_CONSTANT_PS_STATE +0x12300f28: 0x00000000: dword 1 +0x12300f2c: 0x00000000: dword 2 +0x12300f30: 0x00000000: dword 3 +0x12300f34: 0x00000000: dword 4 +0x12300f38: 0x78140007: 3DSTATE_WM +0x12300f3c: 0x00000900: kernel start pointer 0 +0x12300f40: 0x00010000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x12300f44: 0x00000000: scratch offset +0x12300f48: 0x80060000: Depth Clear 0, Depth Resolve 0, HiZ Resolve 0, Dispatch GRF start[0] 6, start[1] 0, start[2] 0 +0x12300f4c: 0x4e084002: MaxThreads 40, PS KillPixel 0, PS computed Z 0, PS use sourceZ 0, Thread Dispatch 1, PS use sourceW 0, Dispatch32 0, Dispatch16 1, Dispatch8 0 +0x12300f50: 0x00100400: Num SF output 1, Pos XY offset 0, ZW interp mode 0 , Barycentric interp mode 0x1, Point raster rule 0, Multisample mode 0, Multisample Dispatch mode 0 +0x12300f54: 0x00000000: kernel start pointer 1 +0x12300f58: 0x00000900: kernel start pointer 2 +0x12300f5c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300f60: 0x00000016: vertex count +0x12300f64: 0x00000052: start vertex +0x12300f68: 0x00000001: instance count +0x12300f6c: 0x00000000: start instance +0x12300f70: 0x00000000: index bias +0x12300f74: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen6-3d.batch.sh b/intel/tests/gen6-3d.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gen6-3d.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/gen7-2d-copy.batch b/intel/tests/gen7-2d-copy.batch new file mode 100644 index 0000000..ce7fc29 Binary files /dev/null and b/intel/tests/gen7-2d-copy.batch differ diff --git a/intel/tests/gen7-2d-copy.batch-ref.txt b/intel/tests/gen7-2d-copy.batch-ref.txt new file mode 100644 index 0000000..0d621d3 --- /dev/null +++ b/intel/tests/gen7-2d-copy.batch-ref.txt @@ -0,0 +1,14 @@ +0x12300000: 0x54f08006: XY_SRC_COPY_BLT (rgb enabled, alpha enabled, src tile 1, dst tile 0) +0x12300004: 0x03cc0190: format 8888, pitch 400, rop 0xcc, clipping disabled, +0x12300008: 0x00000000: dst (0,0) +0x1230000c: 0x00640064: dst (100,100) +0x12300010: 0x122e9000: dst offset 0x122e9000 +0x12300014: 0x00000000: src (0,0) +0x12300018: 0x00000080: src pitch 128 +0x1230001c: 0x02ff1000: src offset 0x02ff1000 +0x12300020: 0x13000002: MI_FLUSH_DW post_sync_op='no write' +0x12300024: 0x00000000: address +0x12300028: 0x00000000: dword +0x1230002c: 0x00000000: upper dword +0x12300030: 0x05000000: MI_BATCH_BUFFER_END +0x12300034: 0x00000000: diff --git a/intel/tests/gen7-2d-copy.batch.sh b/intel/tests/gen7-2d-copy.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gen7-2d-copy.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/gen7-3d.batch b/intel/tests/gen7-3d.batch new file mode 100644 index 0000000..328ec88 Binary files /dev/null and b/intel/tests/gen7-3d.batch differ diff --git a/intel/tests/gen7-3d.batch-ref.txt b/intel/tests/gen7-3d.batch-ref.txt new file mode 100644 index 0000000..be3c85e --- /dev/null +++ b/intel/tests/gen7-3d.batch-ref.txt @@ -0,0 +1,212 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x790d0002: 3DSTATE_MULTISAMPLE +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x00000000: dword 2 +0x12300010: 0x00000000: dword 3 +0x12300014: 0x78180000: 3DSTATE_SAMPLE_MASK +0x12300018: 0x00000001: dword 1 +0x1230001c: 0x61020000: STATE_SIP +0x12300020: 0x00000000: dword 1 +0x12300024: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300028: 0x61010008: STATE_BASE_ADDRESS +0x1230002c: 0x00000001: general state base address 0x00000000 +0x12300030: 0x091ba001: surface state base address 0x091ba000 +0x12300034: 0x091ba001: dynamic state base address 0x091ba000 +0x12300038: 0x00000001: indirect state base address 0x00000000 +0x1230003c: 0x091c2001: instruction state base address 0x091c2000 +0x12300040: 0x00000001: general state upper bound disabled +0x12300044: 0x091c2001: dynamic state upper bound 0x091c2000 +0x12300048: 0x00000001: indirect state upper bound disabled +0x1230004c: 0x00000001: instruction state upper bound disabled +0x12300050: 0x78230000: 3DSTATE_VIEWPORT_STATE_POINTERS_CC +0x12300054: 0x00007fe0: pointer to CC viewport +0x12300058: 0x78210000: 3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP +0x1230005c: 0x00007f80: pointer to SF_CLIP viewport +0x12300060: 0x78300000: 3DSTATE_URB_VS +0x12300064: 0x040002c0: 16KB start, size=1 64B rows, nr_entries=704, total size 45056B +0x12300068: 0x78330000: 3DSTATE_URB_GS +0x1230006c: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300070: 0x78310000: 3DSTATE_URB_HS +0x12300074: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300078: 0x78320000: 3DSTATE_URB_DS +0x1230007c: 0x04000000: 16KB start, size=1 64B rows, nr_entries=0, total size 0B +0x12300080: 0x78240000: 3DSTATE_BLEND_STATE_POINTERS +0x12300084: 0x00007f41: pointer to BLEND_STATE at 0x00007f40 (changed) +0x12300088: 0x780e0000: 3DSTATE_CC_STATE_POINTERS +0x1230008c: 0x00007f01: pointer to COLOR_CALC_STATE at 0x00007f00 (changed) +0x12300090: 0x78250000: 3DSTATE_DEPTH_STENCIL_STATE_POINTERS +0x12300094: 0x00007ec1: pointer to DEPTH_STENCIL_STATE at 0x00007ec0 (changed) +0x12300098: 0x78160005: 3DSTATE_CONSTANT_GS +0x1230009c: 0x00000000: len 0 = 0, len 1 = 0 +0x123000a0: 0x00000000: len 2 = 0, len 3 = 0 +0x123000a4: 0x00000000: pointer to constbuf 0 +0x123000a8: 0x00000000: pointer to constbuf 1 +0x123000ac: 0x00000000: pointer to constbuf 2 +0x123000b0: 0x00000000: pointer to constbuf 3 +0x123000b4: 0x78110005: 3DSTATE_GS +0x123000b8: 0x00000000: kernel pointer +0x123000bc: 0x00000000: SPF=0, VME=0, Sampler Count 0, Binding table count 0 +0x123000c0: 0x00000000: scratch offset +0x123000c4: 0x00000401: Dispatch GRF start 1, VUE read length 0, VUE read offset 0 +0x123000c8: 0x00000400: Max Threads 1, Rendering disable +0x123000cc: 0x00000000: Reorder disable, Discard Adjaceny disable, GS disable +0x123000d0: 0x78290000: 3DSTATE_BINDING_TABLE_POINTERS_GS +0x123000d4: 0x00000000: dword 1 +0x123000d8: 0x78190005: 3DSTATE_CONSTANT_HS +0x123000dc: 0x00000000: len 0 = 0, len 1 = 0 +0x123000e0: 0x00000000: len 2 = 0, len 3 = 0 +0x123000e4: 0x00000000: pointer to constbuf 0 +0x123000e8: 0x00000000: pointer to constbuf 1 +0x123000ec: 0x00000000: pointer to constbuf 2 +0x123000f0: 0x00000000: pointer to constbuf 3 +0x123000f4: 0x781b0005: 3DSTATE_HS +0x123000f8: 0x00000000: dword 1 +0x123000fc: 0x00000000: dword 2 +0x12300100: 0x00000000: dword 3 +0x12300104: 0x00000000: dword 4 +0x12300108: 0x00000000: dword 5 +0x1230010c: 0x00000000: dword 6 +0x12300110: 0x78270000: 3DSTATE_BINDING_TABLE_POINTERS_HS +0x12300114: 0x00000000: dword 1 +0x12300118: 0x781c0002: 3DSTATE_TE +0x1230011c: 0x00000000: dword 1 +0x12300120: 0x00000000: dword 2 +0x12300124: 0x00000000: dword 3 +0x12300128: 0x781a0005: 3DSTATE_CONSTANT_DS +0x1230012c: 0x00000000: len 0 = 0, len 1 = 0 +0x12300130: 0x00000000: len 2 = 0, len 3 = 0 +0x12300134: 0x00000000: pointer to constbuf 0 +0x12300138: 0x00000000: pointer to constbuf 1 +0x1230013c: 0x00000000: pointer to constbuf 2 +0x12300140: 0x00000000: pointer to constbuf 3 +0x12300144: 0x781d0004: 3DSTATE_DS +0x12300148: 0x00000000: dword 1 +0x1230014c: 0x00000000: dword 2 +0x12300150: 0x00000000: dword 3 +0x12300154: 0x00000000: dword 4 +0x12300158: 0x00000000: dword 5 +0x1230015c: 0x78280000: 3DSTATE_BINDING_TABLE_POINTERS_DS +0x12300160: 0x00000000: dword 1 +0x12300164: 0x78260000: 3DSTATE_BINDING_TABLE_POINTERS_VS +0x12300168: 0x00007c40: dword 1 +0x1230016c: 0x782b0000: 3DSTATE_SAMPLER_STATE_POINTERS_VS +0x12300170: 0x00007c20: dword 1 +0x12300174: 0x79120000: 3DSTATE_PUSH_CONSTANT_ALLOC_VS +0x12300178: 0x00000008: dword 1 +0x1230017c: 0x78150005: 3DSTATE_CONSTANT_VS +0x12300180: 0x00000002: len 0 = 2, len 1 = 0 +0x12300184: 0x00000000: len 2 = 0, len 3 = 0 +0x12300188: 0x00007e00: pointer to constbuf 0 +0x1230018c: 0x00000000: pointer to constbuf 1 +0x12300190: 0x00000000: pointer to constbuf 2 +0x12300194: 0x00000000: pointer to constbuf 3 +0x12300198: 0x78100004: 3DSTATE_VS +0x1230019c: 0x00000000: kernel pointer +0x123001a0: 0x08000000: SPF=0, VME=0, Sampler Count 1, Binding table count 0 +0x123001a4: 0x00000000: scratch offset +0x123001a8: 0x00100800: Dispatch GRF start 1, VUE read length 1, VUE read offset 0 +0x123001ac: 0xfe000401: Max Threads 128, Vertex Cache enable, VS func enable +0x123001b0: 0x781e0001: 3DSTATE_STREAMOUT +0x123001b4: 0x00000000: dword 1 +0x123001b8: 0x00000000: dword 2 +0x123001bc: 0x78120002: 3DSTATE_CLIP +0x123001c0: 0x00150400: UserClip distance cull test mask 0x0 +0x123001c4: 0x98000026: Clip enable, API mode OGL, Viewport XY test enable, Viewport Z test enable, Guardband test disable, Clip mode 0, Perspective Divide enable, Non-Perspective Barycentric disable, Tri Provoking 2, Line Provoking 1, Trifan Provoking 2 +0x123001c8: 0x0003ffe0: Min PointWidth 1, Max PointWidth 2047, Force Zero RTAIndex enable, Max VPIndex 0 +0x123001cc: 0x781f000c: 3DSTATE_SBE +0x123001d0: 0x00600810: dword 1 +0x123001d4: 0x00000000: dword 2 +0x123001d8: 0x00000000: dword 3 +0x123001dc: 0x00000000: dword 4 +0x123001e0: 0x00000000: dword 5 +0x123001e4: 0x00000000: dword 6 +0x123001e8: 0x00000000: dword 7 +0x123001ec: 0x00000000: dword 8 +0x123001f0: 0x00000000: dword 9 +0x123001f4: 0x00000000: dword 10 +0x123001f8: 0x00000000: dword 11 +0x123001fc: 0x00000000: dword 12 +0x12300200: 0x00000000: dword 13 +0x12300204: 0x78130005: 3DSTATE_SF +0x12300208: 0x00001403: dword 1 +0x1230020c: 0x22000000: dword 2 +0x12300210: 0x4c000808: dword 3 +0x12300214: 0x00000000: dword 4 +0x12300218: 0x00000000: dword 5 +0x1230021c: 0x00000000: dword 6 +0x12300220: 0x78140001: 3DSTATE_WM +0x12300224: 0xa0000840: (PP ), point UR +0x12300228: 0x00000000: MS +0x1230022c: 0x782a0000: 3DSTATE_BINDING_TABLE_POINTERS_PS +0x12300230: 0x00007c40: dword 1 +0x12300234: 0x782f0000: 3DSTATE_SAMPLER_STATE_POINTERS_PS +0x12300238: 0x00007c20: dword 1 +0x1230023c: 0x79160000: 3DSTATE_PUSH_CONSTANT_ALLOC_PS +0x12300240: 0x00080008: dword 1 +0x12300244: 0x78170005: 3DSTATE_CONSTANT_PS +0x12300248: 0x00000000: len 0 = 0, len 1 = 0 +0x1230024c: 0x00000000: len 2 = 0, len 3 = 0 +0x12300250: 0x00000000: pointer to constbuf 0 +0x12300254: 0x00000000: pointer to constbuf 1 +0x12300258: 0x00000000: pointer to constbuf 2 +0x1230025c: 0x00000000: pointer to constbuf 3 +0x12300260: 0x78200006: 3DSTATE_PS +0x12300264: 0x00000140: dword 1 +0x12300268: 0x08000000: dword 2 +0x1230026c: 0x00000000: dword 3 +0x12300270: 0x55000403: dword 4 +0x12300274: 0x00040006: dword 5 +0x12300278: 0x00000000: dword 6 +0x1230027c: 0x00000240: dword 7 +0x12300280: 0x780f0000: 3DSTATE_SCISSOR_POINTERS +0x12300284: 0x00007be0: scissor rect offset +0x12300288: 0x7a000002: PIPE_CONTROL +0x1230028c: 0x00002000: no write, depth stall, +0x12300290: 0x00000000: +0x12300294: 0x00000000: +0x12300298: 0x7a000002: PIPE_CONTROL +0x1230029c: 0x00000001: no write, depth cache flush, +0x123002a0: 0x00000000: +0x123002a4: 0x00000000: +0x123002a8: 0x7a000002: PIPE_CONTROL +0x123002ac: 0x00002000: no write, depth stall, +0x123002b0: 0x00000000: +0x123002b4: 0x00000000: +0x123002b8: 0x78050005: 3DSTATE_DEPTH_BUFFER +0x123002bc: 0xe0040000: dword 1 +0x123002c0: 0x00000000: dword 2 +0x123002c4: 0x00000000: dword 3 +0x123002c8: 0x00000000: dword 4 +0x123002cc: 0x00000000: dword 5 +0x123002d0: 0x00000000: dword 6 +0x123002d4: 0x78070001: 3DSTATE_HIER_DEPTH_BUFFER +0x123002d8: 0x00000000: pitch 1b +0x123002dc: 0x00000000: pointer to HiZ buffer +0x123002e0: 0x78060001: 3DSTATE_STENCIL_BUFFER +0x123002e4: 0x00000000: dword 1 +0x123002e8: 0x00000000: dword 2 +0x123002ec: 0x78040001: 3DSTATE_CLEAR_PARAMS +0x123002f0: 0x00000000: dword 1 +0x123002f4: 0x00000000: dword 2 +0x123002f8: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123002fc: 0x00000000: top left: 0,0 +0x12300300: 0x00130077: bottom right: 119,19 +0x12300304: 0x00000000: origin: 0,0 +0x12300308: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230030c: 0x00004014: buffer 0: sequential, pitch 20b +0x12300310: 0x158b3000: buffer address +0x12300314: 0x158c2fff: max index +0x12300318: 0x00000000: mbz +0x1230031c: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300320: 0x02850000: buffer 0: invalid, type 0x0085, src offset 0x0000 bytes +0x12300324: 0x11230000: (X, Y, 0.0, 1.0), dst offset 0x00 bytes +0x12300328: 0x02400008: buffer 0: invalid, type 0x0040, src offset 0x0008 bytes +0x1230032c: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300330: 0x7b000005: 3DPRIMITIVE: +0x12300334: 0x00000007: quad list sequential +0x12300338: 0x00000004: vertex count +0x1230033c: 0x00000000: start vertex +0x12300340: 0x00000001: instance count +0x12300344: 0x00000000: start instance +0x12300348: 0x00000000: index bias +0x1230034c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gen7-3d.batch.sh b/intel/tests/gen7-3d.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gen7-3d.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/gm45-3d.batch b/intel/tests/gm45-3d.batch new file mode 100644 index 0000000..549608b Binary files /dev/null and b/intel/tests/gm45-3d.batch differ diff --git a/intel/tests/gm45-3d.batch-ref.txt b/intel/tests/gm45-3d.batch-ref.txt new file mode 100644 index 0000000..5a47d77 --- /dev/null +++ b/intel/tests/gm45-3d.batch-ref.txt @@ -0,0 +1,488 @@ +0x12300000: 0x69040000: 3DSTATE_PIPELINE_SELECT +0x12300004: 0x79090000: 3DSTATE_GLOBAL_DEPTH_OFFSET_CLAMP +0x12300008: 0x00000000: dword 1 +0x1230000c: 0x61020000: STATE_SIP +0x12300010: 0x00000000: dword 1 +0x12300014: 0x680b0000: 3DSTATE_VF_STATISTICS +0x12300018: 0x61010004: STATE_BASE_ADDRESS +0x1230001c: 0x00000001: general state base address 0x00000000 +0x12300020: 0x00000001: surface state base address 0x00000000 +0x12300024: 0x00000001: indirect state base address 0x00000000 +0x12300028: 0x00000001: general state upper bound disabled +0x1230002c: 0x00000001: indirect state upper bound disabled +0x12300030: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x12300034: 0x00007e20: VS binding table +0x12300038: 0x00000000: GS binding table +0x1230003c: 0x00000000: Clip binding table +0x12300040: 0x00000000: SF binding table +0x12300044: 0x00007e20: WM binding table +0x12300048: 0x79010003: 3DSTATE_CONSTANT_COLOR +0x1230004c: 0x00000000: dword 1 +0x12300050: 0x00000000: dword 2 +0x12300054: 0x00000000: dword 3 +0x12300058: 0x00000000: dword 4 +0x1230005c: 0x79050004: 3DSTATE_DEPTH_BUFFER +0x12300060: 0x2c0805ff: 2D, z24s8, pitch = 1536 bytes, tiled +0x12300064: 0x00000000: depth offset +0x12300068: 0x09584ac0: 300x300 +0x1230006c: 0x00000000: volume depth +0x12300070: 0x00000000: +0x12300074: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300078: 0x00007d60: VS state +0x1230007c: 0x00000000: GS state +0x12300080: 0x00007d21: Clip state +0x12300084: 0x00007d80: SF state +0x12300088: 0x00007de0: WM state +0x1230008c: 0x00007fc0: CC state +0x12300090: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300094: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300098: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230009c: 0x60010000: CS_URB_STATE +0x123000a0: 0x00000024: entry_size: 2 [192 bytes], n_entries: 4 +0x123000a4: 0x79000002: 3DSTATE_DRAWING_RECTANGLE +0x123000a8: 0x00000000: top left: 0,0 +0x123000ac: 0x012b012b: bottom right: 299,299 +0x123000b0: 0x00000000: origin: 0,0 +0x123000b4: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123000b8: 0x0000000c: buffer 0: sequential, pitch 12b +0x123000bc: 0x00000000: buffer address +0x123000c0: 0x00000000: max index +0x123000c4: 0x00000000: mbz +0x123000c8: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123000cc: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123000d0: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123000d4: 0x60020100: CONSTANT_BUFFER: valid +0x123000d8: 0x00000001: offset: 0x00000000, length: 128 bytes +0x123000dc: 0x7b001804: 3DPRIMITIVE: tri fan sequential +0x123000e0: 0x00000004: vertex count +0x123000e4: 0x00000000: start vertex +0x123000e8: 0x00000001: instance count +0x123000ec: 0x00000000: start instance +0x123000f0: 0x00000000: index bias +0x123000f4: 0x78010004: 3DSTATE_BINDING_TABLE_POINTERS +0x123000f8: 0x00007b40: VS binding table +0x123000fc: 0x00000000: GS binding table +0x12300100: 0x00000000: Clip binding table +0x12300104: 0x00000000: SF binding table +0x12300108: 0x00007b40: WM binding table +0x1230010c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300110: 0x00007aa0: VS state +0x12300114: 0x00007a41: GS state +0x12300118: 0x00007a61: Clip state +0x1230011c: 0x00007ac0: SF state +0x12300120: 0x00007b00: WM state +0x12300124: 0x00007cc0: CC state +0x12300128: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230012c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300130: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300134: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300138: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230013c: 0x00000000: buffer address +0x12300140: 0x00000000: max index +0x12300144: 0x00000000: mbz +0x12300148: 0x60020100: CONSTANT_BUFFER: valid +0x1230014c: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300150: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300154: 0x00000052: vertex count +0x12300158: 0x00000000: start vertex +0x1230015c: 0x00000001: instance count +0x12300160: 0x00000000: start instance +0x12300164: 0x00000000: index bias +0x12300168: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x1230016c: 0x00007aa0: VS state +0x12300170: 0x00007a21: GS state +0x12300174: 0x00007a61: Clip state +0x12300178: 0x00007ac0: SF state +0x1230017c: 0x00007b00: WM state +0x12300180: 0x00007cc0: CC state +0x12300184: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300188: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x1230018c: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300190: 0x60020100: CONSTANT_BUFFER: valid +0x12300194: 0x00000082: offset: 0x00000080, length: 192 bytes +0x12300198: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230019c: 0x00000050: vertex count +0x123001a0: 0x00000052: start vertex +0x123001a4: 0x00000001: instance count +0x123001a8: 0x00000000: start instance +0x123001ac: 0x00000000: index bias +0x123001b0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001b4: 0x00007aa0: VS state +0x123001b8: 0x00007a01: GS state +0x123001bc: 0x00007a61: Clip state +0x123001c0: 0x00007ac0: SF state +0x123001c4: 0x00007b00: WM state +0x123001c8: 0x00007cc0: CC state +0x123001cc: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123001d0: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123001d4: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123001d8: 0x60020100: CONSTANT_BUFFER: valid +0x123001dc: 0x00000142: offset: 0x00000140, length: 192 bytes +0x123001e0: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123001e4: 0x00000052: vertex count +0x123001e8: 0x000000a2: start vertex +0x123001ec: 0x00000001: instance count +0x123001f0: 0x00000000: start instance +0x123001f4: 0x00000000: index bias +0x123001f8: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123001fc: 0x00007aa0: VS state +0x12300200: 0x000079e1: GS state +0x12300204: 0x00007a61: Clip state +0x12300208: 0x00007ac0: SF state +0x1230020c: 0x00007b00: WM state +0x12300210: 0x00007cc0: CC state +0x12300214: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300218: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x1230021c: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300220: 0x60020100: CONSTANT_BUFFER: valid +0x12300224: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300228: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x1230022c: 0x00000050: vertex count +0x12300230: 0x000000f4: start vertex +0x12300234: 0x00000001: instance count +0x12300238: 0x00000000: start instance +0x1230023c: 0x00000000: index bias +0x12300240: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300244: 0x00007aa0: VS state +0x12300248: 0x000079c1: GS state +0x1230024c: 0x00007a61: Clip state +0x12300250: 0x00007ac0: SF state +0x12300254: 0x00007b00: WM state +0x12300258: 0x00007cc0: CC state +0x1230025c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300260: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300264: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300268: 0x60020100: CONSTANT_BUFFER: valid +0x1230026c: 0x00000142: offset: 0x00000140, length: 192 bytes +0x12300270: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300274: 0x000079a0: VS state +0x12300278: 0x000079c1: GS state +0x1230027c: 0x00007a61: Clip state +0x12300280: 0x00007ac0: SF state +0x12300284: 0x00007b00: WM state +0x12300288: 0x00007cc0: CC state +0x1230028c: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300290: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300294: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300298: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x1230029c: 0x00000018: buffer 0: sequential, pitch 24b +0x123002a0: 0x00000f48: buffer address +0x123002a4: 0x00000000: max index +0x123002a8: 0x00000000: mbz +0x123002ac: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123002b0: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123002b4: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123002b8: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123002bc: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123002c0: 0x60020100: CONSTANT_BUFFER: valid +0x123002c4: 0x00000202: offset: 0x00000200, length: 192 bytes +0x123002c8: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123002cc: 0x000000a2: vertex count +0x123002d0: 0x00000000: start vertex +0x123002d4: 0x00000001: instance count +0x123002d8: 0x00000000: start instance +0x123002dc: 0x00000000: index bias +0x123002e0: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123002e4: 0x000079a0: VS state +0x123002e8: 0x00000000: GS state +0x123002ec: 0x00007901: Clip state +0x123002f0: 0x00007940: SF state +0x123002f4: 0x00007960: WM state +0x123002f8: 0x00007cc0: CC state +0x123002fc: 0x00000000: MI_NOOP +0x12300300: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300304: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300308: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230030c: 0x60020100: CONSTANT_BUFFER: valid +0x12300310: 0x00000202: offset: 0x00000200, length: 192 bytes +0x12300314: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300318: 0x0000002a: vertex count +0x1230031c: 0x000000a2: start vertex +0x12300320: 0x00000001: instance count +0x12300324: 0x00000000: start instance +0x12300328: 0x00000000: index bias +0x1230032c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300330: 0x00007860: VS state +0x12300334: 0x00007801: GS state +0x12300338: 0x00007821: Clip state +0x1230033c: 0x00007880: SF state +0x12300340: 0x000078a0: WM state +0x12300344: 0x00007cc0: CC state +0x12300348: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230034c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300350: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300354: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300358: 0x0000000c: buffer 0: sequential, pitch 12b +0x1230035c: 0x00002268: buffer address +0x12300360: 0x00000000: max index +0x12300364: 0x00000000: mbz +0x12300368: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x1230036c: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300370: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x12300374: 0x60020100: CONSTANT_BUFFER: valid +0x12300378: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x1230037c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300380: 0x0000002a: vertex count +0x12300384: 0x00000000: start vertex +0x12300388: 0x00000001: instance count +0x1230038c: 0x00000000: start instance +0x12300390: 0x00000000: index bias +0x12300394: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300398: 0x00007860: VS state +0x1230039c: 0x000077e1: GS state +0x123003a0: 0x00007821: Clip state +0x123003a4: 0x00007880: SF state +0x123003a8: 0x000078a0: WM state +0x123003ac: 0x00007cc0: CC state +0x123003b0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123003b4: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123003b8: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123003bc: 0x60020100: CONSTANT_BUFFER: valid +0x123003c0: 0x000002c2: offset: 0x000002c0, length: 192 bytes +0x123003c4: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x123003c8: 0x00000028: vertex count +0x123003cc: 0x0000002a: start vertex +0x123003d0: 0x00000001: instance count +0x123003d4: 0x00000000: start instance +0x123003d8: 0x00000000: index bias +0x123003dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123003e0: 0x00007860: VS state +0x123003e4: 0x000077c1: GS state +0x123003e8: 0x00007821: Clip state +0x123003ec: 0x00007880: SF state +0x123003f0: 0x000078a0: WM state +0x123003f4: 0x00007cc0: CC state +0x123003f8: 0x00000000: MI_NOOP +0x123003fc: 0x00000000: MI_NOOP +0x12300400: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300404: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300408: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230040c: 0x60020100: CONSTANT_BUFFER: valid +0x12300410: 0x00000382: offset: 0x00000380, length: 192 bytes +0x12300414: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300418: 0x0000002a: vertex count +0x1230041c: 0x00000052: start vertex +0x12300420: 0x00000001: instance count +0x12300424: 0x00000000: start instance +0x12300428: 0x00000000: index bias +0x1230042c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300430: 0x00007860: VS state +0x12300434: 0x000077a1: GS state +0x12300438: 0x00007821: Clip state +0x1230043c: 0x00007880: SF state +0x12300440: 0x000078a0: WM state +0x12300444: 0x00007cc0: CC state +0x12300448: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x1230044c: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300450: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x12300454: 0x60020100: CONSTANT_BUFFER: valid +0x12300458: 0x00000382: offset: 0x00000380, length: 192 bytes +0x1230045c: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300460: 0x00000028: vertex count +0x12300464: 0x0000007c: start vertex +0x12300468: 0x00000001: instance count +0x1230046c: 0x00000000: start instance +0x12300470: 0x00000000: index bias +0x12300474: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300478: 0x00007860: VS state +0x1230047c: 0x00007781: GS state +0x12300480: 0x00007821: Clip state +0x12300484: 0x00007880: SF state +0x12300488: 0x000078a0: WM state +0x1230048c: 0x00007cc0: CC state +0x12300490: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300494: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300498: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230049c: 0x60020100: CONSTANT_BUFFER: valid +0x123004a0: 0x00000382: offset: 0x00000380, length: 192 bytes +0x123004a4: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123004a8: 0x00007760: VS state +0x123004ac: 0x00007781: GS state +0x123004b0: 0x00007821: Clip state +0x123004b4: 0x00007880: SF state +0x123004b8: 0x000078a0: WM state +0x123004bc: 0x00007cc0: CC state +0x123004c0: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123004c4: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123004c8: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123004cc: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x123004d0: 0x00000018: buffer 0: sequential, pitch 24b +0x123004d4: 0x00002a30: buffer address +0x123004d8: 0x00000000: max index +0x123004dc: 0x00000000: mbz +0x123004e0: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x123004e4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123004e8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123004ec: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x123004f0: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x123004f4: 0x60020100: CONSTANT_BUFFER: valid +0x123004f8: 0x00000442: offset: 0x00000440, length: 192 bytes +0x123004fc: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300500: 0x00000052: vertex count +0x12300504: 0x00000000: start vertex +0x12300508: 0x00000001: instance count +0x1230050c: 0x00000000: start instance +0x12300510: 0x00000000: index bias +0x12300514: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300518: 0x00007760: VS state +0x1230051c: 0x00000000: GS state +0x12300520: 0x000076c1: Clip state +0x12300524: 0x00007700: SF state +0x12300528: 0x00007720: WM state +0x1230052c: 0x00007cc0: CC state +0x12300530: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300534: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300538: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230053c: 0x60020100: CONSTANT_BUFFER: valid +0x12300540: 0x00000442: offset: 0x00000440, length: 192 bytes +0x12300544: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300548: 0x00000016: vertex count +0x1230054c: 0x00000052: start vertex +0x12300550: 0x00000001: instance count +0x12300554: 0x00000000: start instance +0x12300558: 0x00000000: index bias +0x1230055c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300560: 0x00007620: VS state +0x12300564: 0x000075c1: GS state +0x12300568: 0x000075e1: Clip state +0x1230056c: 0x00007640: SF state +0x12300570: 0x00007660: WM state +0x12300574: 0x00007cc0: CC state +0x12300578: 0x00000000: MI_NOOP +0x1230057c: 0x00000000: MI_NOOP +0x12300580: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300584: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300588: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230058c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300590: 0x0000000c: buffer 0: sequential, pitch 12b +0x12300594: 0x000033f0: buffer address +0x12300598: 0x00000000: max index +0x1230059c: 0x00000000: mbz +0x123005a0: 0x78090001: 3DSTATE_VERTEX_ELEMENTS +0x123005a4: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x123005a8: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x123005ac: 0x60020100: CONSTANT_BUFFER: valid +0x123005b0: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005b4: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x123005b8: 0x0000002a: vertex count +0x123005bc: 0x00000000: start vertex +0x123005c0: 0x00000001: instance count +0x123005c4: 0x00000000: start instance +0x123005c8: 0x00000000: index bias +0x123005cc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123005d0: 0x00007620: VS state +0x123005d4: 0x000075a1: GS state +0x123005d8: 0x000075e1: Clip state +0x123005dc: 0x00007640: SF state +0x123005e0: 0x00007660: WM state +0x123005e4: 0x00007cc0: CC state +0x123005e8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123005ec: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123005f0: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123005f4: 0x60020100: CONSTANT_BUFFER: valid +0x123005f8: 0x00000502: offset: 0x00000500, length: 192 bytes +0x123005fc: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300600: 0x00000028: vertex count +0x12300604: 0x0000002a: start vertex +0x12300608: 0x00000001: instance count +0x1230060c: 0x00000000: start instance +0x12300610: 0x00000000: index bias +0x12300614: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300618: 0x00007620: VS state +0x1230061c: 0x00007581: GS state +0x12300620: 0x000075e1: Clip state +0x12300624: 0x00007640: SF state +0x12300628: 0x00007660: WM state +0x1230062c: 0x00007cc0: CC state +0x12300630: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300634: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300638: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230063c: 0x60020100: CONSTANT_BUFFER: valid +0x12300640: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300644: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300648: 0x0000002a: vertex count +0x1230064c: 0x00000052: start vertex +0x12300650: 0x00000001: instance count +0x12300654: 0x00000000: start instance +0x12300658: 0x00000000: index bias +0x1230065c: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300660: 0x00007620: VS state +0x12300664: 0x00007561: GS state +0x12300668: 0x000075e1: Clip state +0x1230066c: 0x00007640: SF state +0x12300670: 0x00007660: WM state +0x12300674: 0x00007cc0: CC state +0x12300678: 0x00000000: MI_NOOP +0x1230067c: 0x00000000: MI_NOOP +0x12300680: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300684: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300688: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230068c: 0x60020100: CONSTANT_BUFFER: valid +0x12300690: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x12300694: 0x7b001c04: 3DPRIMITIVE: quad list sequential +0x12300698: 0x00000028: vertex count +0x1230069c: 0x0000007c: start vertex +0x123006a0: 0x00000001: instance count +0x123006a4: 0x00000000: start instance +0x123006a8: 0x00000000: index bias +0x123006ac: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006b0: 0x00007620: VS state +0x123006b4: 0x00007541: GS state +0x123006b8: 0x000075e1: Clip state +0x123006bc: 0x00007640: SF state +0x123006c0: 0x00007660: WM state +0x123006c4: 0x00007cc0: CC state +0x123006c8: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x123006cc: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x123006d0: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x123006d4: 0x60020100: CONSTANT_BUFFER: valid +0x123006d8: 0x000005c2: offset: 0x000005c0, length: 192 bytes +0x123006dc: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x123006e0: 0x00007520: VS state +0x123006e4: 0x00007541: GS state +0x123006e8: 0x000075e1: Clip state +0x123006ec: 0x00007640: SF state +0x123006f0: 0x00007660: WM state +0x123006f4: 0x00007cc0: CC state +0x123006f8: 0x00000000: MI_NOOP +0x123006fc: 0x00000000: MI_NOOP +0x12300700: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300704: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300708: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230070c: 0x78080003: 3DSTATE_VERTEX_BUFFERS +0x12300710: 0x00000018: buffer 0: sequential, pitch 24b +0x12300714: 0x00003bb8: buffer address +0x12300718: 0x00000000: max index +0x1230071c: 0x00000000: mbz +0x12300720: 0x78090003: 3DSTATE_VERTEX_ELEMENTS +0x12300724: 0x04400000: buffer 0: valid, type 0x0040, src offset 0x0000 bytes +0x12300728: 0x11130000: (X, Y, Z, 1.0), dst offset 0x00 bytes +0x1230072c: 0x0440000c: buffer 0: valid, type 0x0040, src offset 0x000c bytes +0x12300730: 0x11130004: (X, Y, Z, 1.0), dst offset 0x10 bytes +0x12300734: 0x60020100: CONSTANT_BUFFER: valid +0x12300738: 0x00000682: offset: 0x00000680, length: 192 bytes +0x1230073c: 0x7b002004: 3DPRIMITIVE: quad strip sequential +0x12300740: 0x00000052: vertex count +0x12300744: 0x00000000: start vertex +0x12300748: 0x00000001: instance count +0x1230074c: 0x00000000: start instance +0x12300750: 0x00000000: index bias +0x12300754: 0x78000005: 3DSTATE_PIPELINED_POINTERS +0x12300758: 0x00007520: VS state +0x1230075c: 0x00000000: GS state +0x12300760: 0x00007481: Clip state +0x12300764: 0x000074c0: SF state +0x12300768: 0x000074e0: WM state +0x1230076c: 0x00007cc0: CC state +0x12300770: 0x60003f01: URB_FENCE: cs vfe sf clip gs vs +0x12300774: 0x05212040: vs fence: 64, clip_fence: 82, gs_fence: 72 +0x12300778: 0x18000062: sf fence: 98, vfe_fence: 0, cs_fence: 384 +0x1230077c: 0x60020100: CONSTANT_BUFFER: valid +0x12300780: 0x00000682: offset: 0x00000680, length: 192 bytes +0x12300784: 0x7b001404: 3DPRIMITIVE: tri strip sequential +0x12300788: 0x00000016: vertex count +0x1230078c: 0x00000052: start vertex +0x12300790: 0x00000001: instance count +0x12300794: 0x00000000: start instance +0x12300798: 0x00000000: index bias +0x1230079c: 0x05000000: MI_BATCH_BUFFER_END diff --git a/intel/tests/gm45-3d.batch.sh b/intel/tests/gm45-3d.batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/gm45-3d.batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/intel/tests/test-batch.sh b/intel/tests/test-batch.sh new file mode 100644 index 0000000..a94057f --- /dev/null +++ b/intel/tests/test-batch.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +TEST_FILENAME=`echo "$0" | sed 's|.sh||'` +./test_decode $TEST_FILENAME + +ret=$? + +# pretty-print a diff showing what happened, and leave the dumped +# around for possibly moving over the ref. +if test $ret = 1; then + REF_FILENAME="$TEST_FILENAME-ref.txt" + NEW_FILENAME="$TEST_FILENAME-new.txt" + ./test_decode $TEST_FILENAME -dump > $NEW_FILENAME + if test $? = 0; then + echo "Differences:" + diff -u $REF_FILENAME $NEW_FILENAME + fi +fi + +exit $ret diff --git a/libdrm.pc.in b/libdrm.pc.in index b46e2a6..fdd911f 100644 --- a/libdrm.pc.in +++ b/libdrm.pc.in @@ -7,4 +7,4 @@ Name: libdrm Description: Userspace interface to kernel DRM services Version: @PACKAGE_VERSION@ Libs: -L${libdir} -ldrm -Cflags: -I${includedir} -I${includedir}/libdrm +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/exynos diff --git a/libdrm_lists.h b/libdrm_lists.h index 6410f57..8926d8d 100644 --- a/libdrm_lists.h +++ b/libdrm_lists.h @@ -78,6 +78,13 @@ typedef struct _drmMMListHead #define DRMLISTEMPTY(__item) ((__item)->next == (__item)) +#define DRMLISTSINGLE(__list) \ + (!DRMLISTEMPTY(__list) && ((__list)->next == (__list)->prev)) + +#define DRMLISTFOREACH(__item, __list) \ + for ((__item) = (__list)->next; \ + (__item) != (__list); (__item) = (__item)->next) + #define DRMLISTFOREACHSAFE(__item, __temp, __list) \ for ((__item) = (__list)->next, (__temp) = (__item)->next; \ (__item) != (__list); \ @@ -87,3 +94,25 @@ typedef struct _drmMMListHead for ((__item) = (__list)->prev, (__temp) = (__item)->prev; \ (__item) != (__list); \ (__item) = (__temp), (__temp) = (__item)->prev) + +#define DRMLISTFOREACHENTRY(__item, __list, __head) \ + for ((__item) = DRMLISTENTRY(typeof(*__item), (__list)->next, __head); \ + &(__item)->__head != (__list); \ + (__item) = DRMLISTENTRY(typeof(*__item), \ + (__item)->__head.next, __head)) + +#define DRMLISTFOREACHENTRYSAFE(__item, __temp, __list, __head) \ + for ((__item) = DRMLISTENTRY(typeof(*__item), (__list)->next, __head), \ + (__temp) = DRMLISTENTRY(typeof(*__item), \ + (__item)->__head.next, __head); \ + &(__item)->__head != (__list); \ + (__item) = (__temp), \ + (__temp) = DRMLISTENTRY(typeof(*__item), \ + (__temp)->__head.next, __head)) + +#define DRMLISTJOIN(__list, __join) if (!DRMLISTEMPTY(__list)) { \ + (__list)->next->prev = (__join); \ + (__list)->prev->next = (__join)->next; \ + (__join)->next->prev = (__list)->prev; \ + (__join)->next = (__list)->next; \ +} diff --git a/libkms/Makefile.am b/libkms/Makefile.am index ad4fd19..df74b7e 100644 --- a/libkms/Makefile.am +++ b/libkms/Makefile.am @@ -33,6 +33,7 @@ endif if HAVE_SLP libkms_la_SOURCES += slp.c +AM_CFLAGS += -I$(top_srcdir)/exynos endif libkmsincludedir = ${includedir}/libkms diff --git a/libkms/dumb.c b/libkms/dumb.c old mode 100755 new mode 100644 diff --git a/libkms/internal.h b/libkms/internal.h index 145b4b2..5e2501e 100644 --- a/libkms/internal.h +++ b/libkms/internal.h @@ -74,6 +74,4 @@ int nouveau_create(int fd, struct kms_driver **out); int radeon_create(int fd, struct kms_driver **out); -int slp_create(int fd, struct kms_driver **out); - #endif diff --git a/libkms/linux.c b/libkms/linux.c index 75b7cfe..fc4f205 100644 --- a/libkms/linux.c +++ b/libkms/linux.c @@ -115,10 +115,6 @@ linux_from_sysfs(int fd, struct kms_driver **out) else if (!strcmp(name, "radeon")) ret = radeon_create(fd, out); #endif -#ifdef HAVE_SLP - else if (!strcmp(name, "exynos-drm")) - ret = slp_create(fd, out); -#endif else ret = -ENOSYS; diff --git a/nouveau/Makefile.am b/nouveau/Makefile.am index 8b89916..206e892 100644 --- a/nouveau/Makefile.am +++ b/nouveau/Makefile.am @@ -3,41 +3,23 @@ AM_CFLAGS = \ -I$(top_srcdir) \ -I$(top_srcdir)/nouveau \ $(PTHREADSTUBS_CFLAGS) \ - -I$(top_srcdir)/include/drm + -I$(top_srcdir)/include/drm \ + -DDEBUG libdrm_nouveau_la_LTLIBRARIES = libdrm_nouveau.la libdrm_nouveau_ladir = $(libdir) -libdrm_nouveau_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_nouveau_la_LDFLAGS = -version-number 2:0:0 -no-undefined libdrm_nouveau_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ -libdrm_nouveau_la_SOURCES = \ - nouveau_device.c \ - nouveau_channel.c \ - nouveau_pushbuf.c \ - nouveau_grobj.c \ - nouveau_notifier.c \ - nouveau_bo.c \ - nouveau_resource.c \ - nouveau_private.h \ - nouveau_reloc.c - -libdrm_nouveaucommonincludedir = ${includedir}/nouveau -libdrm_nouveaucommoninclude_HEADERS = \ - nouveau_device.h \ - nouveau_channel.h \ - nouveau_grobj.h \ - nouveau_notifier.h \ - nouveau_pushbuf.h \ - nv04_pushbuf.h \ - nvc0_pushbuf.h \ - nouveau_bo.h \ - nouveau_resource.h \ - nouveau_reloc.h +libdrm_nouveau_la_SOURCES = nouveau.c \ + pushbuf.c \ + bufctx.c \ + abi16.c \ + private.h libdrm_nouveauincludedir = ${includedir}/libdrm -libdrm_nouveauinclude_HEADERS = \ - nouveau_drmif.h +libdrm_nouveauinclude_HEADERS = nouveau.h pkgconfigdir = @pkgconfigdir@ pkgconfig_DATA = libdrm_nouveau.pc diff --git a/nouveau/abi16.c b/nouveau/abi16.c new file mode 100644 index 0000000..69a0a9b --- /dev/null +++ b/nouveau/abi16.c @@ -0,0 +1,198 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ + +#include +#include + +#include "private.h" + +int +abi16_chan_nv04(struct nouveau_object *obj) +{ + struct nouveau_device *dev = (struct nouveau_device *)obj->parent; + struct drm_nouveau_channel_alloc req; + struct nv04_fifo *nv04 = obj->data; + int ret; + + req.fb_ctxdma_handle = nv04->vram; + req.tt_ctxdma_handle = nv04->gart; + + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_CHANNEL_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + nv04->base.channel = req.channel; + nv04->base.pushbuf = req.pushbuf_domains; + nv04->notify = req.notifier_handle; + nv04->base.object->handle = req.channel; + nv04->base.object->length = sizeof(*nv04); + return 0; +} + +int +abi16_chan_nvc0(struct nouveau_object *obj) +{ + struct nouveau_device *dev = (struct nouveau_device *)obj->parent; + struct drm_nouveau_channel_alloc req = {}; + struct nvc0_fifo *nvc0 = obj->data; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_CHANNEL_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + nvc0->base.channel = req.channel; + nvc0->base.pushbuf = req.pushbuf_domains; + nvc0->notify = req.notifier_handle; + nvc0->base.object->handle = req.channel; + nvc0->base.object->length = sizeof(*nvc0); + return 0; +} + +int +abi16_engobj(struct nouveau_object *obj) +{ + struct drm_nouveau_grobj_alloc req = { + obj->parent->handle, obj->handle, obj->oclass + }; + struct nouveau_device *dev; + int ret; + + dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); + ret = drmCommandWrite(dev->fd, DRM_NOUVEAU_GROBJ_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + obj->length = sizeof(struct nouveau_object *); + return 0; +} + +int +abi16_ntfy(struct nouveau_object *obj) +{ + struct nv04_notify *ntfy = obj->data; + struct drm_nouveau_notifierobj_alloc req = { + obj->parent->handle, ntfy->object->handle, ntfy->length + }; + struct nouveau_device *dev; + int ret; + + dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, + &req, sizeof(req)); + if (ret) + return ret; + + ntfy->offset = req.offset; + ntfy->object->length = sizeof(*ntfy); + return 0; +} + +void +abi16_bo_info(struct nouveau_bo *bo, struct drm_nouveau_gem_info *info) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + + nvbo->map_handle = info->map_handle; + bo->handle = info->handle; + bo->size = info->size; + bo->offset = info->offset; + + bo->flags = 0; + if (info->domain & NOUVEAU_GEM_DOMAIN_VRAM) + bo->flags |= NOUVEAU_BO_VRAM; + if (info->domain & NOUVEAU_GEM_DOMAIN_GART) + bo->flags |= NOUVEAU_BO_GART; + if (!(info->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG)) + bo->flags |= NOUVEAU_BO_CONTIG; + if (nvbo->map_handle) + bo->flags |= NOUVEAU_BO_MAP; + + if (bo->device->chipset >= 0xc0) { + bo->config.nvc0.memtype = (info->tile_flags & 0xff00) >> 8; + bo->config.nvc0.tile_mode = info->tile_mode; + } else + if (bo->device->chipset >= 0x80 || bo->device->chipset == 0x50) { + bo->config.nv50.memtype = (info->tile_flags & 0x07f00) >> 8 | + (info->tile_flags & 0x30000) >> 9; + bo->config.nv50.tile_mode = info->tile_mode << 4; + } else { + bo->config.nv04.surf_flags = info->tile_flags & 7; + bo->config.nv04.surf_pitch = info->tile_mode; + } +} + +int +abi16_bo_init(struct nouveau_bo *bo, uint32_t alignment, + union nouveau_bo_config *config) +{ + struct nouveau_device *dev = bo->device; + struct drm_nouveau_gem_new req = {}; + struct drm_nouveau_gem_info *info = &req.info; + int ret; + + if (bo->flags & NOUVEAU_BO_VRAM) + info->domain |= NOUVEAU_GEM_DOMAIN_VRAM; + if (bo->flags & NOUVEAU_BO_GART) + info->domain |= NOUVEAU_GEM_DOMAIN_GART; + if (!info->domain) + info->domain |= NOUVEAU_GEM_DOMAIN_VRAM | + NOUVEAU_GEM_DOMAIN_GART; + + if (bo->flags & NOUVEAU_BO_MAP) + info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE; + + if (!(bo->flags & NOUVEAU_BO_CONTIG)) + info->tile_flags = NOUVEAU_GEM_TILE_NONCONTIG; + + info->size = bo->size; + req.align = alignment; + + if (config) { + if (dev->chipset >= 0xc0) { + info->tile_flags = (config->nvc0.memtype & 0xff) << 8; + info->tile_mode = config->nvc0.tile_mode; + } else + if (dev->chipset >= 0x80 || dev->chipset == 0x50) { + info->tile_flags = (config->nv50.memtype & 0x07f) << 8 | + (config->nv50.memtype & 0x180) << 9; + info->tile_mode = config->nv50.tile_mode >> 4; + } else { + info->tile_flags = config->nv04.surf_flags & 7; + info->tile_mode = config->nv04.surf_pitch; + } + } + + if (!nouveau_device(dev)->have_bo_usage) + info->tile_flags &= 0x0000ff00; + + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_NEW, + &req, sizeof(req)); + if (ret == 0) + abi16_bo_info(bo, &req.info); + return ret; +} diff --git a/nouveau/bufctx.c b/nouveau/bufctx.c new file mode 100644 index 0000000..23d6f09 --- /dev/null +++ b/nouveau/bufctx.c @@ -0,0 +1,170 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "libdrm_lists.h" + +#include "nouveau.h" +#include "private.h" + +struct nouveau_bufref_priv { + struct nouveau_bufref base; + struct nouveau_bufref_priv *next; + struct nouveau_bufctx *bufctx; +}; + +static inline struct nouveau_bufref_priv * +nouveau_bufref(struct nouveau_bufref *bctx) +{ + return (struct nouveau_bufref_priv *)bctx; +} + +struct nouveau_bufbin_priv { + struct nouveau_bufref_priv *list; + int relocs; +}; + +struct nouveau_bufctx_priv { + struct nouveau_bufctx base; + struct nouveau_bufref_priv *free; + int nr_bins; + struct nouveau_bufbin_priv bins[]; +}; + +static inline struct nouveau_bufctx_priv * +nouveau_bufctx(struct nouveau_bufctx *bctx) +{ + return (struct nouveau_bufctx_priv *)bctx; +} + +int +nouveau_bufctx_new(struct nouveau_client *client, int bins, + struct nouveau_bufctx **pbctx) +{ + struct nouveau_bufctx_priv *priv; + + priv = calloc(1, sizeof(*priv) + sizeof(priv->bins[0]) * bins); + if (priv) { + DRMINITLISTHEAD(&priv->base.head); + DRMINITLISTHEAD(&priv->base.pending); + DRMINITLISTHEAD(&priv->base.current); + priv->base.client = client; + priv->nr_bins = bins; + *pbctx = &priv->base; + return 0; + } + + return -ENOMEM; +} + +void +nouveau_bufctx_del(struct nouveau_bufctx **pbctx) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(*pbctx); + struct nouveau_bufref_priv *pref; + if (pctx) { + while (pctx->nr_bins--) + nouveau_bufctx_reset(&pctx->base, pctx->nr_bins); + while ((pref = pctx->free)) { + pctx->free = pref->next; + free(pref); + } + free(pctx); + *pbctx = NULL; + } +} + +void +nouveau_bufctx_reset(struct nouveau_bufctx *bctx, int bin) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref_priv *pref; + + while ((pref = pbin->list)) { + DRMLISTDELINIT(&pref->base.thead); + pbin->list = pref->next; + pref->next = pctx->free; + pctx->free = pref; + } + + bctx->relocs -= pbin->relocs; + pbin->relocs = 0; +} + +struct nouveau_bufref * +nouveau_bufctx_refn(struct nouveau_bufctx *bctx, int bin, + struct nouveau_bo *bo, uint32_t flags) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref_priv *pref = pctx->free; + + if (!pref) + pref = malloc(sizeof(*pref)); + else + pctx->free = pref->next; + + if (pref) { + pref->base.bo = bo; + pref->base.flags = flags; + pref->base.packet = 0; + + DRMLISTADDTAIL(&pref->base.thead, &bctx->pending); + pref->bufctx = bctx; + pref->next = pbin->list; + pbin->list = pref; + } + + return &pref->base; +} + +struct nouveau_bufref * +nouveau_bufctx_mthd(struct nouveau_bufctx *bctx, int bin, uint32_t packet, + struct nouveau_bo *bo, uint64_t data, uint32_t flags, + uint32_t vor, uint32_t tor) +{ + struct nouveau_bufctx_priv *pctx = nouveau_bufctx(bctx); + struct nouveau_bufbin_priv *pbin = &pctx->bins[bin]; + struct nouveau_bufref *bref = nouveau_bufctx_refn(bctx, bin, bo, flags); + if (bref) { + bref->packet = packet; + bref->data = data; + bref->vor = vor; + bref->tor = tor; + pbin->relocs++; + bctx->relocs++; + } + return bref; +} diff --git a/nouveau/libdrm_nouveau.pc.in b/nouveau/libdrm_nouveau.pc.in index c78a28a..6170613 100644 --- a/nouveau/libdrm_nouveau.pc.in +++ b/nouveau/libdrm_nouveau.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: libdrm_nouveau Description: Userspace interface to nouveau kernel DRM services -Version: 0.6 +Version: 2.4.33 Libs: -L${libdir} -ldrm_nouveau Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/nouveau Requires.private: libdrm diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c new file mode 100644 index 0000000..5aa4107 --- /dev/null +++ b/nouveau/nouveau.c @@ -0,0 +1,492 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "libdrm_lists.h" +#include "nouveau_drm.h" + +#include "nouveau.h" +#include "private.h" + +#ifdef DEBUG +uint32_t nouveau_debug = 0; + +static void +debug_init(char *args) +{ + if (args) { + int n = strtol(args, NULL, 0); + if (n >= 0) + nouveau_debug = n; + } +} +#endif + +/* this is the old libdrm's version of nouveau_device_wrap(), the symbol + * is kept here to prevent AIGLX from crashing if the DDX is linked against + * the new libdrm, but the DRI driver against the old + */ +int +nouveau_device_open_existing(struct nouveau_device **pdev, int close, int fd, + drm_context_t ctx) +{ + return -EACCES; +} + +int +nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev) +{ + struct nouveau_device_priv *nvdev = calloc(1, sizeof(*nvdev)); + struct nouveau_device *dev = &nvdev->base; + uint64_t chipset, vram, gart, bousage; + drmVersionPtr ver; + int ret; + +#ifdef DEBUG + debug_init(getenv("NOUVEAU_LIBDRM_DEBUG")); +#endif + + if (!nvdev) + return -ENOMEM; + nvdev->base.fd = fd; + + ver = drmGetVersion(fd); + if (ver) dev->drm_version = (ver->version_major << 24) | + (ver->version_minor << 8) | + ver->version_patchlevel; + drmFreeVersion(ver); + + if ( dev->drm_version != 0x00000010 && + (dev->drm_version < 0x01000000 || + dev->drm_version >= 0x02000000)) { + nouveau_device_del(&dev); + return -EINVAL; + } + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_CHIPSET_ID, &chipset); + if (ret == 0) + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_FB_SIZE, &vram); + if (ret == 0) + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_AGP_SIZE, &gart); + if (ret) { + nouveau_device_del(&dev); + return ret; + } + + ret = nouveau_getparam(dev, NOUVEAU_GETPARAM_HAS_BO_USAGE, &bousage); + if (ret == 0) + nvdev->have_bo_usage = (bousage != 0); + + nvdev->close = close; + DRMINITLISTHEAD(&nvdev->bo_list); + nvdev->base.object.oclass = NOUVEAU_DEVICE_CLASS; + nvdev->base.lib_version = 0x01000000; + nvdev->base.chipset = chipset; + nvdev->base.vram_size = vram; + nvdev->base.gart_size = gart; + nvdev->base.vram_limit = (nvdev->base.vram_size * 80) / 100; + nvdev->base.gart_limit = (nvdev->base.gart_size * 80) / 100; + + *pdev = &nvdev->base; + return 0; +} + +int +nouveau_device_open(const char *busid, struct nouveau_device **pdev) +{ + int ret = -ENODEV, fd = drmOpen("nouveau", busid); + if (fd >= 0) { + ret = nouveau_device_wrap(fd, 1, pdev); + if (ret) + drmClose(fd); + } + return ret; +} + +void +nouveau_device_del(struct nouveau_device **pdev) +{ + struct nouveau_device_priv *nvdev = nouveau_device(*pdev); + if (nvdev) { + if (nvdev->close) + drmClose(nvdev->base.fd); + free(nvdev->client); + free(nvdev); + *pdev = NULL; + } +} + +int +nouveau_getparam(struct nouveau_device *dev, uint64_t param, uint64_t *value) +{ + struct drm_nouveau_getparam r = { param, 0 }; + int fd = dev->fd, ret = + drmCommandWriteRead(fd, DRM_NOUVEAU_GETPARAM, &r, sizeof(r)); + *value = r.value; + return ret; +} + +int +nouveau_setparam(struct nouveau_device *dev, uint64_t param, uint64_t value) +{ + struct drm_nouveau_setparam r = { param, value }; + return drmCommandWrite(dev->fd, DRM_NOUVEAU_SETPARAM, &r, sizeof(r)); +} + +int +nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct nouveau_client_priv *pcli; + int id = 0, i, ret = -ENOMEM; + uint32_t *clients; + + for (i = 0; i < nvdev->nr_client; i++) { + id = ffs(nvdev->client[i]) - 1; + if (id >= 0) + goto out; + } + + clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1)); + if (!clients) + return ret; + nvdev->client = clients; + nvdev->client[i] = 0; + nvdev->nr_client++; + +out: + pcli = calloc(1, sizeof(*pcli)); + if (pcli) { + nvdev->client[i] |= (1 << id); + pcli->base.device = dev; + pcli->base.id = (i * 32) + id; + ret = 0; + } + + *pclient = &pcli->base; + return ret; +} + +void +nouveau_client_del(struct nouveau_client **pclient) +{ + struct nouveau_client_priv *pcli = nouveau_client(*pclient); + struct nouveau_device_priv *nvdev; + if (pcli) { + int id = pcli->base.id; + nvdev = nouveau_device(pcli->base.device); + nvdev->client[id / 32] &= ~(1 << (id % 32)); + free(pcli->kref); + free(pcli); + } +} + +int +nouveau_object_new(struct nouveau_object *parent, uint64_t handle, + uint32_t oclass, void *data, uint32_t length, + struct nouveau_object **pobj) +{ + struct nouveau_device *dev; + struct nouveau_object *obj; + int ret = -EINVAL; + + if (length == 0) + length = sizeof(struct nouveau_object *); + obj = malloc(sizeof(*obj) + length); + obj->parent = parent; + obj->handle = handle; + obj->oclass = oclass; + obj->length = length; + obj->data = obj + 1; + if (data) + memcpy(obj->data, data, length); + *(struct nouveau_object **)obj->data = obj; + + dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); + switch (parent->oclass) { + case NOUVEAU_DEVICE_CLASS: + switch (obj->oclass) { + case NOUVEAU_FIFO_CHANNEL_CLASS: + { + if (dev->chipset < 0xc0) + ret = abi16_chan_nv04(obj); + else + ret = abi16_chan_nvc0(obj); + } + break; + default: + break; + } + break; + case NOUVEAU_FIFO_CHANNEL_CLASS: + switch (obj->oclass) { + case NOUVEAU_NOTIFIER_CLASS: + ret = abi16_ntfy(obj); + break; + default: + ret = abi16_engobj(obj); + break; + } + default: + break; + } + + if (ret) { + free(obj); + return ret; + } + + *pobj = obj; + return 0; +} + +void +nouveau_object_del(struct nouveau_object **pobj) +{ + struct nouveau_object *obj = *pobj; + struct nouveau_device *dev; + if (obj) { + dev = nouveau_object_find(obj, NOUVEAU_DEVICE_CLASS); + if (obj->oclass == NOUVEAU_FIFO_CHANNEL_CLASS) { + struct drm_nouveau_channel_free req; + req.channel = obj->handle; + drmCommandWrite(dev->fd, DRM_NOUVEAU_CHANNEL_FREE, + &req, sizeof(req)); + } else { + struct drm_nouveau_gpuobj_free req; + req.channel = obj->parent->handle; + req.handle = obj->handle; + drmCommandWrite(dev->fd, DRM_NOUVEAU_GPUOBJ_FREE, + &req, sizeof(req)); + } + } + free(obj); + *pobj = NULL; +} + +void * +nouveau_object_find(struct nouveau_object *obj, uint32_t pclass) +{ + while (obj && obj->oclass != pclass) { + obj = obj->parent; + if (pclass == NOUVEAU_PARENT_CLASS) + break; + } + return obj; +} + +static void +nouveau_bo_del(struct nouveau_bo *bo) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + struct drm_gem_close req = { bo->handle }; + DRMLISTDEL(&nvbo->head); + if (bo->map) + munmap(bo->map, bo->size); + drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req); + free(nvbo); +} + +int +nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align, + uint64_t size, union nouveau_bo_config *config, + struct nouveau_bo **pbo) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct nouveau_bo_priv *nvbo = calloc(1, sizeof(*nvbo)); + struct nouveau_bo *bo = &nvbo->base; + int ret; + + if (!nvbo) + return -ENOMEM; + atomic_set(&nvbo->refcnt, 1); + bo->device = dev; + bo->flags = flags; + bo->size = size; + + ret = abi16_bo_init(bo, align, config); + if (ret) { + free(nvbo); + return ret; + } + + DRMLISTADD(&nvbo->head, &nvdev->bo_list); + + *pbo = bo; + return 0; +} + +int +nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, + struct nouveau_bo **pbo) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct drm_nouveau_gem_info req = { .handle = handle }; + struct nouveau_bo_priv *nvbo; + int ret; + + DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { + if (nvbo->base.handle == handle) { + *pbo = NULL; + nouveau_bo_ref(&nvbo->base, pbo); + return 0; + } + } + + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO, + &req, sizeof(req)); + if (ret) + return ret; + + nvbo = calloc(1, sizeof(*nvbo)); + if (nvbo) { + atomic_set(&nvbo->refcnt, 1); + nvbo->base.device = dev; + abi16_bo_info(&nvbo->base, &req); + DRMLISTADD(&nvbo->head, &nvdev->bo_list); + *pbo = &nvbo->base; + return 0; + } + + return -ENOMEM; +} + +int +nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, + struct nouveau_bo **pbo) +{ + struct nouveau_device_priv *nvdev = nouveau_device(dev); + struct nouveau_bo_priv *nvbo; + struct drm_gem_open req = { .name = name }; + int ret; + + DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) { + if (nvbo->name == name) { + *pbo = NULL; + nouveau_bo_ref(&nvbo->base, pbo); + return 0; + } + } + + ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req); + if (ret == 0) { + ret = nouveau_bo_wrap(dev, req.handle, pbo); + nouveau_bo((*pbo))->name = name; + } + + return ret; +} + +int +nouveau_bo_name_get(struct nouveau_bo *bo, uint32_t *name) +{ + struct drm_gem_flink req = { .handle = bo->handle }; + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + if (!nvbo->name) { + int ret = drmIoctl(bo->device->fd, DRM_IOCTL_GEM_FLINK, &req); + if (ret) + return ret; + nvbo->name = req.name; + } + *name = nvbo->name; + return 0; +} + +void +nouveau_bo_ref(struct nouveau_bo *bo, struct nouveau_bo **pref) +{ + struct nouveau_bo *ref = *pref; + if (bo) { + atomic_inc(&nouveau_bo(bo)->refcnt); + } + if (ref) { + if (atomic_dec_and_test(&nouveau_bo(ref)->refcnt)) + nouveau_bo_del(ref); + } + *pref = bo; +} + +int +nouveau_bo_wait(struct nouveau_bo *bo, uint32_t access, + struct nouveau_client *client) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + struct drm_nouveau_gem_cpu_prep req; + struct nouveau_pushbuf *push; + int ret = 0; + + if (!(access & NOUVEAU_BO_RDWR)) + return 0; + + push = cli_push_get(client, bo); + if (push && push->channel) + nouveau_pushbuf_kick(push, push->channel); + + if (!nvbo->name && !(nvbo->access & NOUVEAU_BO_WR) && + !( access & NOUVEAU_BO_WR)) + return 0; + + req.handle = bo->handle; + req.flags = 0; + if (access & NOUVEAU_BO_WR) + req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE; + if (access & NOUVEAU_BO_NOBLOCK) + req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT; + + ret = drmCommandWrite(bo->device->fd, DRM_NOUVEAU_GEM_CPU_PREP, + &req, sizeof(req)); + if (ret == 0) + nvbo->access = 0; + return ret; +} + +int +nouveau_bo_map(struct nouveau_bo *bo, uint32_t access, + struct nouveau_client *client) +{ + struct nouveau_bo_priv *nvbo = nouveau_bo(bo); + if (bo->map == NULL) { + bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bo->device->fd, nvbo->map_handle); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + return -errno; + } + } + return nouveau_bo_wait(bo, access, client); +} diff --git a/nouveau/nouveau.h b/nouveau/nouveau.h new file mode 100644 index 0000000..51a9598 --- /dev/null +++ b/nouveau/nouveau.h @@ -0,0 +1,212 @@ +#ifndef __NOUVEAU_H__ +#define __NOUVEAU_H__ + +#include +#include + +#define NOUVEAU_DEVICE_CLASS 0x80000000 +#define NOUVEAU_FIFO_CHANNEL_CLASS 0x80000001 +#define NOUVEAU_NOTIFIER_CLASS 0x80000002 +#define NOUVEAU_PARENT_CLASS 0xffffffff + +struct nouveau_list { + struct nouveau_list *prev; + struct nouveau_list *next; +}; + +struct nouveau_object { + struct nouveau_object *parent; + uint64_t handle; + uint32_t oclass; + uint32_t length; + void *data; +}; + +struct nouveau_fifo { + struct nouveau_object *object; + uint32_t channel; + uint32_t pushbuf; + uint64_t unused1[3]; +}; + +struct nv04_fifo { + struct nouveau_fifo base; + uint32_t vram; + uint32_t gart; + uint32_t notify; +}; + +struct nvc0_fifo { + struct nouveau_fifo base; + uint32_t notify; +}; + +struct nv04_notify { + struct nouveau_object *object; + uint32_t offset; + uint32_t length; +}; + +int nouveau_object_new(struct nouveau_object *parent, uint64_t handle, + uint32_t oclass, void *data, uint32_t length, + struct nouveau_object **); +void nouveau_object_del(struct nouveau_object **); +void *nouveau_object_find(struct nouveau_object *, uint32_t parent_class); + +struct nouveau_device { + struct nouveau_object object; + int fd; + uint32_t lib_version; + uint32_t drm_version; + uint32_t chipset; + uint64_t vram_size; + uint64_t gart_size; + uint64_t vram_limit; + uint64_t gart_limit; +}; + +int nouveau_device_wrap(int fd, int close, struct nouveau_device **); +int nouveau_device_open(const char *busid, struct nouveau_device **); +void nouveau_device_del(struct nouveau_device **); +int nouveau_getparam(struct nouveau_device *, uint64_t param, uint64_t *value); +int nouveau_setparam(struct nouveau_device *, uint64_t param, uint64_t value); + +struct nouveau_client { + struct nouveau_device *device; + int id; +}; + +int nouveau_client_new(struct nouveau_device *, struct nouveau_client **); +void nouveau_client_del(struct nouveau_client **); + +union nouveau_bo_config { + struct { +#define NV04_BO_16BPP 0x00000001 +#define NV04_BO_32BPP 0x00000002 +#define NV04_BO_ZETA 0x00000004 + uint32_t surf_flags; + uint32_t surf_pitch; + } nv04; + struct { + uint32_t memtype; + uint32_t tile_mode; + } nv50; + struct { + uint32_t memtype; + uint32_t tile_mode; + } nvc0; + uint32_t data[8]; +}; + +#define NOUVEAU_BO_VRAM 0x00000001 +#define NOUVEAU_BO_GART 0x00000002 +#define NOUVEAU_BO_APER (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART) +#define NOUVEAU_BO_RD 0x00000100 +#define NOUVEAU_BO_WR 0x00000200 +#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR) +#define NOUVEAU_BO_NOBLOCK 0x00000400 +#define NOUVEAU_BO_LOW 0x00001000 +#define NOUVEAU_BO_HIGH 0x00002000 +#define NOUVEAU_BO_OR 0x00004000 +#define NOUVEAU_BO_MAP 0x80000000 +#define NOUVEAU_BO_CONTIG 0x40000000 +#define NOUVEAU_BO_NOSNOOP 0x20000000 + +struct nouveau_bo { + struct nouveau_device *device; + uint32_t handle; + uint64_t size; + uint32_t flags; + uint64_t offset; + void *map; + union nouveau_bo_config config; +}; + +int nouveau_bo_new(struct nouveau_device *, uint32_t flags, uint32_t align, + uint64_t size, union nouveau_bo_config *, + struct nouveau_bo **); +int nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, + struct nouveau_bo **); +int nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name, + struct nouveau_bo **); +int nouveau_bo_name_get(struct nouveau_bo *, uint32_t *name); +void nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **); +int nouveau_bo_map(struct nouveau_bo *, uint32_t access, + struct nouveau_client *); +int nouveau_bo_wait(struct nouveau_bo *, uint32_t access, + struct nouveau_client *); + +struct nouveau_bufref { + struct nouveau_list thead; + struct nouveau_bo *bo; + uint32_t packet; + uint32_t flags; + uint32_t data; + uint32_t vor; + uint32_t tor; + uint32_t priv_data; + void *priv; +}; + +struct nouveau_bufctx { + struct nouveau_client *client; + struct nouveau_list head; + struct nouveau_list pending; + struct nouveau_list current; + int relocs; +}; + +int nouveau_bufctx_new(struct nouveau_client *, int bins, + struct nouveau_bufctx **); +void nouveau_bufctx_del(struct nouveau_bufctx **); +struct nouveau_bufref * +nouveau_bufctx_refn(struct nouveau_bufctx *, int bin, + struct nouveau_bo *, uint32_t flags); +struct nouveau_bufref * +nouveau_bufctx_mthd(struct nouveau_bufctx *, int bin, uint32_t packet, + struct nouveau_bo *, uint64_t data, uint32_t flags, + uint32_t vor, uint32_t tor); +void nouveau_bufctx_reset(struct nouveau_bufctx *, int bin); + +struct nouveau_pushbuf_krec; +struct nouveau_pushbuf { + struct nouveau_client *client; + struct nouveau_object *channel; + struct nouveau_bufctx *bufctx; + void (*kick_notify)(struct nouveau_pushbuf *); + void *user_priv; + uint32_t rsvd_kick; + uint32_t flags; + uint32_t *cur; + uint32_t *end; +}; + +struct nouveau_pushbuf_refn { + struct nouveau_bo *bo; + uint32_t flags; +}; + +int nouveau_pushbuf_new(struct nouveau_client *, struct nouveau_object *channel, + int nr, uint32_t size, bool immediate, + struct nouveau_pushbuf **); +void nouveau_pushbuf_del(struct nouveau_pushbuf **); +int nouveau_pushbuf_space(struct nouveau_pushbuf *, uint32_t dwords, + uint32_t relocs, uint32_t pushes); +void nouveau_pushbuf_data(struct nouveau_pushbuf *, struct nouveau_bo *, + uint64_t offset, uint64_t length); +int nouveau_pushbuf_refn(struct nouveau_pushbuf *, + struct nouveau_pushbuf_refn *, int nr); +/* Emits a reloc into the push buffer at the current position, you *must* + * have previously added the referenced buffer to a buffer context, and + * validated it against the current push buffer. + */ +void nouveau_pushbuf_reloc(struct nouveau_pushbuf *, struct nouveau_bo *, + uint32_t data, uint32_t flags, + uint32_t vor, uint32_t tor); +int nouveau_pushbuf_validate(struct nouveau_pushbuf *); +uint32_t nouveau_pushbuf_refd(struct nouveau_pushbuf *, struct nouveau_bo *); +int nouveau_pushbuf_kick(struct nouveau_pushbuf *, struct nouveau_object *channel); +struct nouveau_bufctx * +nouveau_pushbuf_bufctx(struct nouveau_pushbuf *, struct nouveau_bufctx *); + +#endif diff --git a/nouveau/nouveau_bo.c b/nouveau/nouveau_bo.c deleted file mode 100644 index d6bb22d..0000000 --- a/nouveau/nouveau_bo.c +++ /dev/null @@ -1,549 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif -#include -#include -#include -#include - -#include - -#include "nouveau_private.h" - -int -nouveau_bo_init(struct nouveau_device *dev) -{ - return 0; -} - -void -nouveau_bo_takedown(struct nouveau_device *dev) -{ -} - -static int -nouveau_bo_info(struct nouveau_bo_priv *nvbo, struct drm_nouveau_gem_info *arg) -{ - nvbo->handle = nvbo->base.handle = arg->handle; - nvbo->domain = arg->domain; - nvbo->size = arg->size; - nvbo->offset = arg->offset; - nvbo->map_handle = arg->map_handle; - nvbo->base.tile_mode = arg->tile_mode; - /* XXX - flag inverted for backwards compatibility */ - nvbo->base.tile_flags = arg->tile_flags ^ NOUVEAU_GEM_TILE_NONCONTIG; - return 0; -} - -static int -nouveau_bo_allocated(struct nouveau_bo_priv *nvbo) -{ - if (nvbo->sysmem || nvbo->handle) - return 1; - return 0; -} - -static int -nouveau_bo_ualloc(struct nouveau_bo_priv *nvbo) -{ - if (nvbo->user || nvbo->sysmem) { - assert(nvbo->sysmem); - return 0; - } - - nvbo->sysmem = malloc(nvbo->size); - if (!nvbo->sysmem) - return -ENOMEM; - - return 0; -} - -static void -nouveau_bo_ufree(struct nouveau_bo_priv *nvbo) -{ - if (nvbo->sysmem) { - if (!nvbo->user) - free(nvbo->sysmem); - nvbo->sysmem = NULL; - } -} - -static void -nouveau_bo_kfree(struct nouveau_bo_priv *nvbo) -{ - struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); - struct drm_gem_close req; - - if (!nvbo->handle) - return; - - if (nvbo->map) { - munmap(nvbo->map, nvbo->size); - nvbo->map = NULL; - } - - req.handle = nvbo->handle; - nvbo->handle = 0; - drmIoctl(nvdev->fd, DRM_IOCTL_GEM_CLOSE, &req); -} - -static int -nouveau_bo_kalloc(struct nouveau_bo_priv *nvbo, struct nouveau_channel *chan) -{ - struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); - struct drm_nouveau_gem_new req; - struct drm_nouveau_gem_info *info = &req.info; - int ret; - - if (nvbo->handle) - return 0; - - req.channel_hint = chan ? chan->id : 0; - req.align = nvbo->align; - - - info->size = nvbo->size; - info->domain = 0; - - if (nvbo->flags & NOUVEAU_BO_VRAM) - info->domain |= NOUVEAU_GEM_DOMAIN_VRAM; - if (nvbo->flags & NOUVEAU_BO_GART) - info->domain |= NOUVEAU_GEM_DOMAIN_GART; - if (!info->domain) { - info->domain |= (NOUVEAU_GEM_DOMAIN_VRAM | - NOUVEAU_GEM_DOMAIN_GART); - } - - if (nvbo->flags & NOUVEAU_BO_MAP) - info->domain |= NOUVEAU_GEM_DOMAIN_MAPPABLE; - - info->tile_mode = nvbo->base.tile_mode; - info->tile_flags = nvbo->base.tile_flags; - /* XXX - flag inverted for backwards compatibility */ - info->tile_flags ^= NOUVEAU_GEM_TILE_NONCONTIG; - if (!nvdev->has_bo_usage) - info->tile_flags &= NOUVEAU_GEM_TILE_LAYOUT_MASK; - - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_NEW, - &req, sizeof(req)); - if (ret) - return ret; - - nouveau_bo_info(nvbo, &req.info); - return 0; -} - -static int -nouveau_bo_kmap(struct nouveau_bo_priv *nvbo) -{ - struct nouveau_device_priv *nvdev = nouveau_device(nvbo->base.device); - - if (nvbo->map) - return 0; - - if (!nvbo->map_handle) - return -EINVAL; - - nvbo->map = mmap(0, nvbo->size, PROT_READ | PROT_WRITE, - MAP_SHARED, nvdev->fd, nvbo->map_handle); - if (nvbo->map == MAP_FAILED) { - nvbo->map = NULL; - return -errno; - } - - return 0; -} - -int -nouveau_bo_new_tile(struct nouveau_device *dev, uint32_t flags, int align, - int size, uint32_t tile_mode, uint32_t tile_flags, - struct nouveau_bo **bo) -{ - struct nouveau_bo_priv *nvbo; - int ret; - - if (!dev || !bo || *bo) - return -EINVAL; - - nvbo = calloc(1, sizeof(struct nouveau_bo_priv)); - if (!nvbo) - return -ENOMEM; - nvbo->base.device = dev; - nvbo->base.size = size; - nvbo->base.tile_mode = tile_mode; - nvbo->base.tile_flags = tile_flags; - - nvbo->refcount = 1; - nvbo->flags = flags; - nvbo->size = size; - nvbo->align = align; - - if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) { - ret = nouveau_bo_kalloc(nvbo, NULL); - if (ret) { - nouveau_bo_ref(NULL, (void *)&nvbo); - return ret; - } - } - - *bo = &nvbo->base; - return 0; -} - -int -nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, int align, - int size, struct nouveau_bo **bo) -{ - return nouveau_bo_new_tile(dev, flags, align, size, 0, 0, bo); -} - -int -nouveau_bo_user(struct nouveau_device *dev, void *ptr, int size, - struct nouveau_bo **bo) -{ - struct nouveau_bo_priv *nvbo; - int ret; - - ret = nouveau_bo_new(dev, NOUVEAU_BO_MAP, 0, size, bo); - if (ret) - return ret; - nvbo = nouveau_bo(*bo); - - nvbo->sysmem = ptr; - nvbo->user = 1; - return 0; -} - -int -nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle, - struct nouveau_bo **bo) -{ - struct nouveau_device_priv *nvdev = nouveau_device(dev); - struct drm_nouveau_gem_info req; - struct nouveau_bo_priv *nvbo; - int ret; - - ret = nouveau_bo_new(dev, 0, 0, 0, bo); - if (ret) - return ret; - nvbo = nouveau_bo(*bo); - - req.handle = handle; - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_INFO, - &req, sizeof(req)); - if (ret) { - nouveau_bo_ref(NULL, bo); - return ret; - } - - nouveau_bo_info(nvbo, &req); - nvbo->base.size = nvbo->size; - return 0; -} - -int -nouveau_bo_handle_get(struct nouveau_bo *bo, uint32_t *handle) -{ - struct nouveau_device_priv *nvdev = nouveau_device(bo->device); - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - int ret; - - if (!bo || !handle) - return -EINVAL; - - if (!nvbo->global_handle) { - struct drm_gem_flink req; - - ret = nouveau_bo_kalloc(nvbo, NULL); - if (ret) - return ret; - - req.handle = nvbo->handle; - ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_FLINK, &req); - if (ret) { - nouveau_bo_kfree(nvbo); - return ret; - } - - nvbo->global_handle = req.name; - } - - *handle = nvbo->global_handle; - return 0; -} - -int -nouveau_bo_handle_ref(struct nouveau_device *dev, uint32_t handle, - struct nouveau_bo **bo) -{ - struct nouveau_device_priv *nvdev = nouveau_device(dev); - struct nouveau_bo_priv *nvbo; - struct drm_gem_open req; - int ret; - - req.name = handle; - ret = drmIoctl(nvdev->fd, DRM_IOCTL_GEM_OPEN, &req); - if (ret) { - nouveau_bo_ref(NULL, bo); - return ret; - } - - ret = nouveau_bo_wrap(dev, req.handle, bo); - if (ret) { - nouveau_bo_ref(NULL, bo); - return ret; - } - - nvbo = nouveau_bo(*bo); - nvbo->base.handle = nvbo->handle; - return 0; -} - -static void -nouveau_bo_del(struct nouveau_bo **bo) -{ - struct nouveau_bo_priv *nvbo; - - if (!bo || !*bo) - return; - nvbo = nouveau_bo(*bo); - *bo = NULL; - - if (--nvbo->refcount) - return; - - if (nvbo->pending) { - nvbo->pending = NULL; - nouveau_pushbuf_flush(nvbo->pending_channel, 0); - } - - nouveau_bo_ufree(nvbo); - nouveau_bo_kfree(nvbo); - free(nvbo); -} - -int -nouveau_bo_ref(struct nouveau_bo *ref, struct nouveau_bo **pbo) -{ - if (!pbo) - return -EINVAL; - - if (ref) - nouveau_bo(ref)->refcount++; - - if (*pbo) - nouveau_bo_del(pbo); - - *pbo = ref; - return 0; -} - -static int -nouveau_bo_wait(struct nouveau_bo *bo, int cpu_write, int no_wait, int no_block) -{ - struct nouveau_device_priv *nvdev = nouveau_device(bo->device); - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - struct drm_nouveau_gem_cpu_prep req; - int ret; - - if (!nvbo->global_handle && !nvbo->write_marker && !cpu_write) - return 0; - - if (nvbo->pending && - (nvbo->pending->write_domains || cpu_write)) { - nvbo->pending = NULL; - nouveau_pushbuf_flush(nvbo->pending_channel, 0); - } - - req.handle = nvbo->handle; - req.flags = 0; - if (cpu_write) - req.flags |= NOUVEAU_GEM_CPU_PREP_WRITE; - if (no_wait) - req.flags |= NOUVEAU_GEM_CPU_PREP_NOWAIT; - if (no_block) - req.flags |= NOUVEAU_GEM_CPU_PREP_NOBLOCK; - - do { - ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_PREP, - &req, sizeof(req)); - } while (ret == -EAGAIN); - if (ret) - return ret; - - if (ret == 0) - nvbo->write_marker = 0; - return 0; -} - -int -nouveau_bo_map_range(struct nouveau_bo *bo, uint32_t delta, uint32_t size, - uint32_t flags) -{ - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - int ret; - - if (!nvbo || bo->map) - return -EINVAL; - - if (!nouveau_bo_allocated(nvbo)) { - if (nvbo->flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) { - ret = nouveau_bo_kalloc(nvbo, NULL); - if (ret) - return ret; - } - - if (!nouveau_bo_allocated(nvbo)) { - ret = nouveau_bo_ualloc(nvbo); - if (ret) - return ret; - } - } - - if (nvbo->sysmem) { - bo->map = (char *)nvbo->sysmem + delta; - } else { - ret = nouveau_bo_kmap(nvbo); - if (ret) - return ret; - - if (!(flags & NOUVEAU_BO_NOSYNC)) { - ret = nouveau_bo_wait(bo, (flags & NOUVEAU_BO_WR), - (flags & NOUVEAU_BO_NOWAIT), 0); - if (ret) - return ret; - - nvbo->map_refcnt++; - } - - bo->map = (char *)nvbo->map + delta; - } - - return 0; -} - -void -nouveau_bo_map_flush(struct nouveau_bo *bo, uint32_t delta, uint32_t size) -{ -} - -int -nouveau_bo_map(struct nouveau_bo *bo, uint32_t flags) -{ - return nouveau_bo_map_range(bo, 0, bo->size, flags); -} - -void -nouveau_bo_unmap(struct nouveau_bo *bo) -{ - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - - if (bo->map && !nvbo->sysmem && nvbo->map_refcnt) { - struct nouveau_device_priv *nvdev = nouveau_device(bo->device); - struct drm_nouveau_gem_cpu_fini req; - - req.handle = nvbo->handle; - drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GEM_CPU_FINI, - &req, sizeof(req)); - nvbo->map_refcnt--; - } - - bo->map = NULL; -} - -int -nouveau_bo_busy(struct nouveau_bo *bo, uint32_t access) -{ - return nouveau_bo_wait(bo, (access & NOUVEAU_BO_WR), 1, 1); -} - -uint32_t -nouveau_bo_pending(struct nouveau_bo *bo) -{ - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - uint32_t flags; - - if (!nvbo->pending) - return 0; - - flags = 0; - if (nvbo->pending->read_domains) - flags |= NOUVEAU_BO_RD; - if (nvbo->pending->write_domains) - flags |= NOUVEAU_BO_WR; - - return flags; -} - -struct drm_nouveau_gem_pushbuf_bo * -nouveau_bo_emit_buffer(struct nouveau_channel *chan, struct nouveau_bo *bo) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - struct drm_nouveau_gem_pushbuf_bo *pbbo; - struct nouveau_bo *ref = NULL; - int ret; - - if (nvbo->pending) - return nvbo->pending; - - if (!nvbo->handle) { - ret = nouveau_bo_kalloc(nvbo, chan); - if (ret) - return NULL; - - if (nvbo->sysmem) { - void *sysmem_tmp = nvbo->sysmem; - - nvbo->sysmem = NULL; - ret = nouveau_bo_map(bo, NOUVEAU_BO_WR); - if (ret) - return NULL; - nvbo->sysmem = sysmem_tmp; - - memcpy(bo->map, nvbo->sysmem, nvbo->base.size); - nouveau_bo_ufree(nvbo); - nouveau_bo_unmap(bo); - } - } - - if (nvpb->nr_buffers >= NOUVEAU_GEM_MAX_BUFFERS) - return NULL; - pbbo = nvpb->buffers + nvpb->nr_buffers++; - nvbo->pending = pbbo; - nvbo->pending_channel = chan; - nvbo->pending_refcnt = 0; - - nouveau_bo_ref(bo, &ref); - pbbo->user_priv = (uint64_t)(unsigned long)ref; - pbbo->handle = nvbo->handle; - pbbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | NOUVEAU_GEM_DOMAIN_GART; - pbbo->read_domains = 0; - pbbo->write_domains = 0; - pbbo->presumed.domain = nvbo->domain; - pbbo->presumed.offset = nvbo->offset; - pbbo->presumed.valid = 1; - return pbbo; -} diff --git a/nouveau/nouveau_bo.h b/nouveau/nouveau_bo.h deleted file mode 100644 index 3a1f2d4..0000000 --- a/nouveau/nouveau_bo.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_BO_H__ -#define __NOUVEAU_BO_H__ - -/* Relocation/Buffer type flags */ -#define NOUVEAU_BO_VRAM (1 << 0) -#define NOUVEAU_BO_GART (1 << 1) -#define NOUVEAU_BO_RD (1 << 2) -#define NOUVEAU_BO_WR (1 << 3) -#define NOUVEAU_BO_RDWR (NOUVEAU_BO_RD | NOUVEAU_BO_WR) -#define NOUVEAU_BO_MAP (1 << 4) -#define NOUVEAU_BO_LOW (1 << 6) -#define NOUVEAU_BO_HIGH (1 << 7) -#define NOUVEAU_BO_OR (1 << 8) -#define NOUVEAU_BO_INVAL (1 << 12) -#define NOUVEAU_BO_NOSYNC (1 << 13) -#define NOUVEAU_BO_NOWAIT (1 << 14) -#define NOUVEAU_BO_IFLUSH (1 << 15) -#define NOUVEAU_BO_DUMMY (1 << 31) - -#define NOUVEAU_BO_TILE_LAYOUT_MASK 0x0000ff00 -#define NOUVEAU_BO_TILE_16BPP 0x00000001 -#define NOUVEAU_BO_TILE_32BPP 0x00000002 -#define NOUVEAU_BO_TILE_ZETA 0x00000004 -#define NOUVEAU_BO_TILE_SCANOUT 0x00000008 - -struct nouveau_bo { - struct nouveau_device *device; - uint32_t handle; - - uint64_t size; - void *map; - - uint32_t tile_mode; - uint32_t tile_flags; -}; - -int -nouveau_bo_new(struct nouveau_device *, uint32_t flags, int align, int size, - struct nouveau_bo **); - -int -nouveau_bo_new_tile(struct nouveau_device *, uint32_t flags, int align, - int size, uint32_t tile_mode, uint32_t tile_flags, - struct nouveau_bo **); - -int -nouveau_bo_user(struct nouveau_device *, void *ptr, int size, - struct nouveau_bo **); - -int -nouveau_bo_wrap(struct nouveau_device *, uint32_t handle, struct nouveau_bo **); - -int -nouveau_bo_handle_get(struct nouveau_bo *, uint32_t *); - -int -nouveau_bo_handle_ref(struct nouveau_device *, uint32_t handle, - struct nouveau_bo **); - -int -nouveau_bo_ref(struct nouveau_bo *, struct nouveau_bo **); - -int -nouveau_bo_map_range(struct nouveau_bo *, uint32_t delta, uint32_t size, - uint32_t flags); - -void -nouveau_bo_map_flush(struct nouveau_bo *, uint32_t delta, uint32_t size); - -int -nouveau_bo_map(struct nouveau_bo *, uint32_t flags); - -void -nouveau_bo_unmap(struct nouveau_bo *); - -int -nouveau_bo_busy(struct nouveau_bo *, uint32_t access); - -uint32_t -nouveau_bo_pending(struct nouveau_bo *); - -#endif diff --git a/nouveau/nouveau_channel.c b/nouveau/nouveau_channel.c deleted file mode 100644 index 96fa03b..0000000 --- a/nouveau/nouveau_channel.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include -#include - -#include "nouveau_private.h" - -int -nouveau_channel_alloc(struct nouveau_device *dev, uint32_t fb_ctxdma, - uint32_t tt_ctxdma, int pushbuf_size, - struct nouveau_channel **chan) -{ - struct nouveau_device_priv *nvdev = nouveau_device(dev); - struct nouveau_channel_priv *nvchan; - unsigned i; - int ret; - - if (!nvdev || !chan || *chan) - return -EINVAL; - - nvchan = calloc(1, sizeof(struct nouveau_channel_priv)); - if (!nvchan) - return -ENOMEM; - nvchan->base.device = dev; - - nvchan->drm.fb_ctxdma_handle = fb_ctxdma; - nvchan->drm.tt_ctxdma_handle = tt_ctxdma; - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_CHANNEL_ALLOC, - &nvchan->drm, sizeof(nvchan->drm)); - if (ret) { - free(nvchan); - return ret; - } - - nvchan->base.id = nvchan->drm.channel; - if (nouveau_grobj_ref(&nvchan->base, nvchan->drm.fb_ctxdma_handle, - &nvchan->base.vram) || - nouveau_grobj_ref(&nvchan->base, nvchan->drm.tt_ctxdma_handle, - &nvchan->base.gart)) { - nouveau_channel_free((void *)&nvchan); - return -EINVAL; - } - - /* Mark all DRM-assigned subchannels as in-use */ - for (i = 0; i < nvchan->drm.nr_subchan; i++) { - struct nouveau_grobj_priv *gr = calloc(1, sizeof(*gr)); - - gr->base.bound = NOUVEAU_GROBJ_BOUND_EXPLICIT; - gr->base.subc = i; - gr->base.handle = nvchan->drm.subchan[i].handle; - gr->base.grclass = nvchan->drm.subchan[i].grclass; - gr->base.channel = &nvchan->base; - - nvchan->base.subc[i].gr = &gr->base; - } - - if (dev->chipset < 0xc0) { - ret = nouveau_bo_wrap(dev, nvchan->drm.notifier_handle, - &nvchan->notifier_bo); - if (!ret) - ret = nouveau_bo_map(nvchan->notifier_bo, - NOUVEAU_BO_RDWR); - if (ret) { - nouveau_channel_free((void *)&nvchan); - return ret; - } - - ret = nouveau_grobj_alloc(&nvchan->base, 0x00000000, 0x0030, - &nvchan->base.nullobj); - if (ret) { - nouveau_channel_free((void *)&nvchan); - return ret; - } - } - - ret = nouveau_pushbuf_init(&nvchan->base, pushbuf_size); - if (ret) { - nouveau_channel_free((void *)&nvchan); - return ret; - } - - *chan = &nvchan->base; - return 0; -} - -void -nouveau_channel_free(struct nouveau_channel **chan) -{ - struct nouveau_channel_priv *nvchan; - struct nouveau_device_priv *nvdev; - struct drm_nouveau_channel_free cf; - unsigned i; - - if (!chan || !*chan) - return; - nvchan = nouveau_channel(*chan); - (*chan)->flush_notify = NULL; - *chan = NULL; - nvdev = nouveau_device(nvchan->base.device); - - FIRE_RING(&nvchan->base); - - nouveau_pushbuf_fini(&nvchan->base); - if (nvchan->notifier_bo) { - nouveau_bo_unmap(nvchan->notifier_bo); - nouveau_bo_ref(NULL, &nvchan->notifier_bo); - } - - for (i = 0; i < nvchan->drm.nr_subchan; i++) - free(nvchan->base.subc[i].gr); - - nouveau_grobj_free(&nvchan->base.vram); - nouveau_grobj_free(&nvchan->base.gart); - nouveau_grobj_free(&nvchan->base.nullobj); - - cf.channel = nvchan->drm.channel; - drmCommandWrite(nvdev->fd, DRM_NOUVEAU_CHANNEL_FREE, &cf, sizeof(cf)); - free(nvchan); -} - - diff --git a/nouveau/nouveau_channel.h b/nouveau/nouveau_channel.h deleted file mode 100644 index d61a4c0..0000000 --- a/nouveau/nouveau_channel.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_CHANNEL_H__ -#define __NOUVEAU_CHANNEL_H__ - -struct nouveau_subchannel { - struct nouveau_grobj *gr; - unsigned sequence; -}; - -struct nouveau_channel { - uint32_t *cur; - uint32_t *end; - - struct nouveau_device *device; - int id; - - struct nouveau_grobj *nullobj; - struct nouveau_grobj *vram; - struct nouveau_grobj *gart; - - void *user_private; - void (*hang_notify)(struct nouveau_channel *); - void (*flush_notify)(struct nouveau_channel *); - - struct nouveau_subchannel subc[8]; - unsigned subc_sequence; -}; - -int -nouveau_channel_alloc(struct nouveau_device *, uint32_t fb, uint32_t tt, - int pushbuf_size, struct nouveau_channel **); - -void -nouveau_channel_free(struct nouveau_channel **); - -#endif diff --git a/nouveau/nouveau_device.c b/nouveau/nouveau_device.c deleted file mode 100644 index 425c5d2..0000000 --- a/nouveau/nouveau_device.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include -#include - -#include "nouveau_private.h" - -int -nouveau_device_open_existing(struct nouveau_device **dev, int close, - int fd, drm_context_t ctx) -{ - struct nouveau_device_priv *nvdev; - drmVersionPtr ver; - uint64_t value; - int ret; - - if (!dev || *dev) - return -EINVAL; - - nvdev = calloc(1, sizeof(*nvdev)); - if (!nvdev) - return -ENOMEM; - nvdev->fd = fd; - nvdev->ctx = ctx; - nvdev->needs_close = close; - - ver = drmGetVersion(fd); - if (!ver) { - nouveau_device_close((void *)&nvdev); - return -EINVAL; - } - - if ((ver->version_major == 0 && ver->version_patchlevel != 16) || - ver->version_major > 1) { - nouveau_device_close((void *)&nvdev); - return -EINVAL; - } - - drmFreeVersion(ver); - - ret = nouveau_device_get_param(&nvdev->base, - NOUVEAU_GETPARAM_VM_VRAM_BASE, &value); - if (ret) { - nouveau_device_close((void *)&nvdev); - return ret; - } - nvdev->base.vm_vram_base = value; - - ret = nouveau_device_get_param(&nvdev->base, - NOUVEAU_GETPARAM_FB_SIZE, &value); - if (ret) { - nouveau_device_close((void *)&nvdev); - return ret; - } - nvdev->base.vm_vram_size = value; - - ret = nouveau_device_get_param(&nvdev->base, - NOUVEAU_GETPARAM_AGP_SIZE, &value); - if (ret) { - nouveau_device_close((void *)&nvdev); - return ret; - } - nvdev->base.vm_gart_size = value; - - ret = nouveau_bo_init(&nvdev->base); - if (ret) { - nouveau_device_close((void *)&nvdev); - return ret; - } - - ret = nouveau_device_get_param(&nvdev->base, - NOUVEAU_GETPARAM_CHIPSET_ID, &value); - if (ret) { - nouveau_device_close((void *)&nvdev); - return ret; - } - nvdev->base.chipset = value; - - ret = nouveau_device_get_param(&nvdev->base, - NOUVEAU_GETPARAM_HAS_BO_USAGE, &value); - if (!ret) - nvdev->has_bo_usage = value; - - *dev = &nvdev->base; - return 0; -} - -int -nouveau_device_open(struct nouveau_device **dev, const char *busid) -{ - drm_context_t ctx; - int fd, ret; - - if (!dev || *dev) - return -EINVAL; - - fd = drmOpen("nouveau", busid); - if (fd < 0) - return -EINVAL; - - ret = drmCreateContext(fd, &ctx); - if (ret) { - drmClose(fd); - return ret; - } - - ret = nouveau_device_open_existing(dev, 1, fd, ctx); - if (ret) { - drmDestroyContext(fd, ctx); - drmClose(fd); - return ret; - } - - return 0; -} - -void -nouveau_device_close(struct nouveau_device **dev) -{ - struct nouveau_device_priv *nvdev; - - if (!dev || !*dev) - return; - nvdev = nouveau_device(*dev); - *dev = NULL; - - nouveau_bo_takedown(&nvdev->base); - - if (nvdev->needs_close) { - drmDestroyContext(nvdev->fd, nvdev->ctx); - drmClose(nvdev->fd); - } - free(nvdev); -} - -int -nouveau_device_get_param(struct nouveau_device *dev, - uint64_t param, uint64_t *value) -{ - struct nouveau_device_priv *nvdev = nouveau_device(dev); - struct drm_nouveau_getparam g; - int ret; - - if (!nvdev || !value) - return -EINVAL; - - g.param = param; - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GETPARAM, - &g, sizeof(g)); - if (ret) - return ret; - - *value = g.value; - return 0; -} - -int -nouveau_device_set_param(struct nouveau_device *dev, - uint64_t param, uint64_t value) -{ - struct nouveau_device_priv *nvdev = nouveau_device(dev); - struct drm_nouveau_setparam s; - int ret; - - if (!nvdev) - return -EINVAL; - - s.param = param; - s.value = value; - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_SETPARAM, - &s, sizeof(s)); - if (ret) - return ret; - - return 0; -} - diff --git a/nouveau/nouveau_device.h b/nouveau/nouveau_device.h deleted file mode 100644 index c0d9333..0000000 --- a/nouveau/nouveau_device.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_DEVICE_H__ -#define __NOUVEAU_DEVICE_H__ - -struct nouveau_device { - unsigned chipset; - uint64_t vm_vram_base; - uint64_t vm_vram_size; - uint64_t vm_gart_size; -}; - -#endif diff --git a/nouveau/nouveau_drmif.h b/nouveau/nouveau_drmif.h deleted file mode 100644 index ec226a2..0000000 --- a/nouveau/nouveau_drmif.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2008 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_DRMIF_H__ -#define __NOUVEAU_DRMIF_H__ - -#include -#include - -#include "nouveau_device.h" - -struct nouveau_device_priv { - struct nouveau_device base; - - int fd; - drm_context_t ctx; - drmLock *lock; - int needs_close; - int has_bo_usage; -}; -#define nouveau_device(n) ((struct nouveau_device_priv *)(n)) - -int -nouveau_device_open_existing(struct nouveau_device **, int close, - int fd, drm_context_t ctx); - -int -nouveau_device_open(struct nouveau_device **, const char *busid); - -void -nouveau_device_close(struct nouveau_device **); - -int -nouveau_device_get_param(struct nouveau_device *, uint64_t param, uint64_t *v); - -int -nouveau_device_set_param(struct nouveau_device *, uint64_t param, uint64_t val); - -#endif diff --git a/nouveau/nouveau_grobj.c b/nouveau/nouveau_grobj.c deleted file mode 100644 index 36344b9..0000000 --- a/nouveau/nouveau_grobj.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include - -#include "nouveau_private.h" - -int -nouveau_grobj_alloc(struct nouveau_channel *chan, uint32_t handle, - int class, struct nouveau_grobj **grobj) -{ - struct nouveau_device_priv *nvdev = nouveau_device(chan->device); - struct nouveau_grobj_priv *nvgrobj; - struct drm_nouveau_grobj_alloc g; - int ret; - - if (!nvdev || !grobj || *grobj) - return -EINVAL; - - nvgrobj = calloc(1, sizeof(*nvgrobj)); - if (!nvgrobj) - return -ENOMEM; - nvgrobj->base.channel = chan; - nvgrobj->base.handle = handle; - nvgrobj->base.grclass = class; - nvgrobj->base.bound = NOUVEAU_GROBJ_UNBOUND; - nvgrobj->base.subc = -1; - - g.channel = chan->id; - g.handle = handle; - g.class = class; - ret = drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GROBJ_ALLOC, - &g, sizeof(g)); - if (ret) { - nouveau_grobj_free((void *)&nvgrobj); - return ret; - } - - *grobj = &nvgrobj->base; - return 0; -} - -int -nouveau_grobj_ref(struct nouveau_channel *chan, uint32_t handle, - struct nouveau_grobj **grobj) -{ - struct nouveau_grobj_priv *nvgrobj; - - if (!chan || !grobj || *grobj) - return -EINVAL; - - nvgrobj = calloc(1, sizeof(struct nouveau_grobj_priv)); - if (!nvgrobj) - return -ENOMEM; - nvgrobj->base.channel = chan; - nvgrobj->base.handle = handle; - nvgrobj->base.grclass = 0; - - *grobj = &nvgrobj->base; - return 0; -} - -void -nouveau_grobj_free(struct nouveau_grobj **grobj) -{ - struct nouveau_device_priv *nvdev; - struct nouveau_channel_priv *chan; - struct nouveau_grobj_priv *nvgrobj; - - if (!grobj || !*grobj) - return; - nvgrobj = nouveau_grobj(*grobj); - *grobj = NULL; - - - chan = nouveau_channel(nvgrobj->base.channel); - nvdev = nouveau_device(chan->base.device); - - if (nvgrobj->base.grclass) { - struct drm_nouveau_gpuobj_free f; - - FIRE_RING(&chan->base); - f.channel = chan->drm.channel; - f.handle = nvgrobj->base.handle; - drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, - &f, sizeof(f)); - } - if (nvgrobj->base.bound != NOUVEAU_GROBJ_UNBOUND) - chan->base.subc[nvgrobj->base.subc].gr = NULL; - free(nvgrobj); -} - -void -nouveau_grobj_autobind(struct nouveau_grobj *grobj) -{ - struct nouveau_channel *chan = grobj->channel; - struct nouveau_subchannel *subc = NULL; - int i; - - for (i = 0; i < 8; i++) { - struct nouveau_subchannel *scc = &grobj->channel->subc[i]; - - if (scc->gr && scc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT) - continue; - - if (!subc || scc->sequence < subc->sequence) - subc = scc; - } - - if (subc->gr) { - subc->gr->bound = NOUVEAU_GROBJ_UNBOUND; - subc->gr->subc = -1; - } - - subc->gr = grobj; - subc->gr->bound = NOUVEAU_GROBJ_BOUND; - subc->gr->subc = subc - &grobj->channel->subc[0]; - - WAIT_RING(chan, 2); - if (chan->device->chipset < 0xc0) { - OUT_RING (chan, (1 << 18) | (grobj->subc << 13)); - OUT_RING (chan, grobj->handle); - } else { - OUT_RING (chan, (2 << 28) | (1 << 16) | (grobj->subc << 13)); - OUT_RING (chan, grobj->grclass); - } -} - diff --git a/nouveau/nouveau_grobj.h b/nouveau/nouveau_grobj.h deleted file mode 100644 index 51ac7d9..0000000 --- a/nouveau/nouveau_grobj.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_GROBJ_H__ -#define __NOUVEAU_GROBJ_H__ - -#include "nouveau_channel.h" - -struct nouveau_grobj { - struct nouveau_channel *channel; - int grclass; - uint32_t handle; - - enum { - NOUVEAU_GROBJ_UNBOUND = 0, - NOUVEAU_GROBJ_BOUND = 1, - NOUVEAU_GROBJ_BOUND_EXPLICIT = 2 - } bound; - int subc; -}; - -int nouveau_grobj_alloc(struct nouveau_channel *, uint32_t handle, - int class, struct nouveau_grobj **); -int nouveau_grobj_ref(struct nouveau_channel *, uint32_t handle, - struct nouveau_grobj **); -void nouveau_grobj_free(struct nouveau_grobj **); -void nouveau_grobj_autobind(struct nouveau_grobj *); - -#endif diff --git a/nouveau/nouveau_notifier.c b/nouveau/nouveau_notifier.c deleted file mode 100644 index 513fa63..0000000 --- a/nouveau/nouveau_notifier.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include -#include - -#include "nouveau_private.h" - -#define NOTIFIER(__v) \ - struct nouveau_notifier_priv *nvnotify = nouveau_notifier(notifier); \ - volatile uint32_t *__v = (uint32_t *)((char *)nvnotify->map + (id * 32)) - -int -nouveau_notifier_alloc(struct nouveau_channel *chan, uint32_t handle, - int count, struct nouveau_notifier **notifier) -{ - struct nouveau_notifier_priv *nvnotify; - int ret; - - if (!chan || !notifier || *notifier) - return -EINVAL; - - nvnotify = calloc(1, sizeof(struct nouveau_notifier_priv)); - if (!nvnotify) - return -ENOMEM; - nvnotify->base.channel = chan; - nvnotify->base.handle = handle; - - nvnotify->drm.channel = chan->id; - nvnotify->drm.handle = handle; - nvnotify->drm.size = (count * 32); - if ((ret = drmCommandWriteRead(nouveau_device(chan->device)->fd, - DRM_NOUVEAU_NOTIFIEROBJ_ALLOC, - &nvnotify->drm, - sizeof(nvnotify->drm)))) { - nouveau_notifier_free((void *)&nvnotify); - return ret; - } - - nvnotify->map = (char *)nouveau_channel(chan)->notifier_bo->map + - nvnotify->drm.offset; - *notifier = &nvnotify->base; - return 0; -} - -void -nouveau_notifier_free(struct nouveau_notifier **notifier) -{ - - struct nouveau_notifier_priv *nvnotify; - struct nouveau_channel_priv *nvchan; - struct nouveau_device_priv *nvdev; - struct drm_nouveau_gpuobj_free f; - - if (!notifier || !*notifier) - return; - nvnotify = nouveau_notifier(*notifier); - *notifier = NULL; - - nvchan = nouveau_channel(nvnotify->base.channel); - nvdev = nouveau_device(nvchan->base.device); - - FIRE_RING(&nvchan->base); - - f.channel = nvchan->drm.channel; - f.handle = nvnotify->base.handle; - drmCommandWrite(nvdev->fd, DRM_NOUVEAU_GPUOBJ_FREE, &f, sizeof(f)); - free(nvnotify); -} - -void -nouveau_notifier_reset(struct nouveau_notifier *notifier, int id) -{ - NOTIFIER(n); - - n[NV_NOTIFY_TIME_0 /4] = 0x00000000; - n[NV_NOTIFY_TIME_1 /4] = 0x00000000; - n[NV_NOTIFY_RETURN_VALUE/4] = 0x00000000; - n[NV_NOTIFY_STATE /4] = (NV_NOTIFY_STATE_STATUS_IN_PROCESS << - NV_NOTIFY_STATE_STATUS_SHIFT); -} - -uint32_t -nouveau_notifier_status(struct nouveau_notifier *notifier, int id) -{ - NOTIFIER(n); - - return n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT; -} - -uint32_t -nouveau_notifier_return_val(struct nouveau_notifier *notifier, int id) -{ - NOTIFIER(n); - - return n[NV_NOTIFY_RETURN_VALUE/4]; -} - -static inline double -gettime(void) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - return (double)tv.tv_sec + tv.tv_usec / 1000000.0; -} - -int -nouveau_notifier_wait_status(struct nouveau_notifier *notifier, int id, - uint32_t status, double timeout) -{ - NOTIFIER(n); - double time = 0, t_start = gettime(); - - while (time <= timeout) { - uint32_t v; - - v = n[NV_NOTIFY_STATE/4] >> NV_NOTIFY_STATE_STATUS_SHIFT; - if (v == status) - return 0; - - if (timeout) - time = gettime() - t_start; - } - - return -EBUSY; -} - diff --git a/nouveau/nouveau_notifier.h b/nouveau/nouveau_notifier.h deleted file mode 100644 index dbc6a3b..0000000 --- a/nouveau/nouveau_notifier.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_NOTIFIER_H__ -#define __NOUVEAU_NOTIFIER_H__ - -#define NV_NOTIFIER_SIZE 32 -#define NV_NOTIFY_TIME_0 0x00000000 -#define NV_NOTIFY_TIME_1 0x00000004 -#define NV_NOTIFY_RETURN_VALUE 0x00000008 -#define NV_NOTIFY_STATE 0x0000000C -#define NV_NOTIFY_STATE_STATUS_MASK 0xFF000000 -#define NV_NOTIFY_STATE_STATUS_SHIFT 24 -#define NV_NOTIFY_STATE_STATUS_COMPLETED 0x00 -#define NV_NOTIFY_STATE_STATUS_IN_PROCESS 0x01 -#define NV_NOTIFY_STATE_ERROR_CODE_MASK 0x0000FFFF -#define NV_NOTIFY_STATE_ERROR_CODE_SHIFT 0 - -struct nouveau_notifier { - struct nouveau_channel *channel; - uint32_t handle; -}; - -int -nouveau_notifier_alloc(struct nouveau_channel *, uint32_t handle, int count, - struct nouveau_notifier **); - -void -nouveau_notifier_free(struct nouveau_notifier **); - -void -nouveau_notifier_reset(struct nouveau_notifier *, int id); - -uint32_t -nouveau_notifier_status(struct nouveau_notifier *, int id); - -uint32_t -nouveau_notifier_return_val(struct nouveau_notifier *, int id); - -int -nouveau_notifier_wait_status(struct nouveau_notifier *, int id, uint32_t status, - double timeout); - -#endif diff --git a/nouveau/nouveau_private.h b/nouveau/nouveau_private.h deleted file mode 100644 index 124fe87..0000000 --- a/nouveau/nouveau_private.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_PRIVATE_H__ -#define __NOUVEAU_PRIVATE_H__ - -#include -#include -#include - -#include "nouveau_drmif.h" -#include "nouveau_device.h" -#include "nouveau_channel.h" -#include "nouveau_grobj.h" -#include "nouveau_notifier.h" -#include "nouveau_bo.h" -#include "nouveau_resource.h" -#include "nouveau_pushbuf.h" -#include "nouveau_reloc.h" - -#define CALPB_BUFFERS 3 - -struct nouveau_pushbuf_priv { - uint32_t cal_suffix0; - uint32_t cal_suffix1; - struct nouveau_bo *buffer[CALPB_BUFFERS]; - int current; - int current_offset; - - unsigned *pushbuf; - unsigned size; - - uint32_t *marker; - unsigned marker_offset; - unsigned marker_relocs; - unsigned marker_push; - - struct drm_nouveau_gem_pushbuf_bo *buffers; - unsigned nr_buffers; - struct drm_nouveau_gem_pushbuf_reloc *relocs; - unsigned nr_relocs; - struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH]; - unsigned nr_push; -}; -#define nouveau_pushbuf(n) ((struct nouveau_pushbuf_priv *)(n)) - -int -nouveau_pushbuf_init(struct nouveau_channel *, int buf_size); -void -nouveau_pushbuf_fini(struct nouveau_channel *); - -struct nouveau_channel_priv { - struct nouveau_channel base; - - struct drm_nouveau_channel_alloc drm; - - struct nouveau_bo *notifier_bo; - - struct nouveau_pushbuf_priv pb; -}; -#define nouveau_channel(n) ((struct nouveau_channel_priv *)(n)) - -struct nouveau_grobj_priv { - struct nouveau_grobj base; -}; -#define nouveau_grobj(n) ((struct nouveau_grobj_priv *)(n)) - -struct nouveau_notifier_priv { - struct nouveau_notifier base; - - struct drm_nouveau_notifierobj_alloc drm; - volatile void *map; -}; -#define nouveau_notifier(n) ((struct nouveau_notifier_priv *)(n)) - -struct nouveau_bo_priv { - struct nouveau_bo base; - int refcount; - - /* Buffer configuration + usage hints */ - unsigned flags; - unsigned size; - unsigned align; - int user; - - /* Tracking */ - struct drm_nouveau_gem_pushbuf_bo *pending; - struct nouveau_channel *pending_channel; - int pending_refcnt; - int write_marker; - - /* Userspace object */ - void *sysmem; - - /* Kernel object */ - uint32_t global_handle; - drm_handle_t handle; - uint64_t map_handle; - int map_refcnt; - void *map; - - /* Last known information from kernel on buffer status */ - uint64_t offset; - uint32_t domain; -}; -#define nouveau_bo(n) ((struct nouveau_bo_priv *)(n)) - -int -nouveau_bo_init(struct nouveau_device *); - -void -nouveau_bo_takedown(struct nouveau_device *); - -struct drm_nouveau_gem_pushbuf_bo * -nouveau_bo_emit_buffer(struct nouveau_channel *, struct nouveau_bo *); - -#endif diff --git a/nouveau/nouveau_pushbuf.c b/nouveau/nouveau_pushbuf.c deleted file mode 100644 index 59f60d9..0000000 --- a/nouveau/nouveau_pushbuf.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include -#include -#include - -#include "nouveau_private.h" - -#define PB_BUFMGR_DWORDS (4096 / 2) -#define PB_MIN_USER_DWORDS 2048 - -static int -nouveau_pushbuf_space(struct nouveau_channel *chan, unsigned min) -{ - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - struct nouveau_bo *bo; - int ret; - - if (min < PB_MIN_USER_DWORDS) - min = PB_MIN_USER_DWORDS; - - nvpb->current_offset = chan->cur - nvpb->pushbuf; - if (chan->cur + min + 2 <= chan->end) - return 0; - - nvpb->current++; - if (nvpb->current == CALPB_BUFFERS) - nvpb->current = 0; - bo = nvpb->buffer[nvpb->current]; - - ret = nouveau_bo_map(bo, NOUVEAU_BO_WR); - if (ret) - return ret; - - nvpb->size = (bo->size - 8) / 4; - nvpb->pushbuf = bo->map; - nvpb->current_offset = 0; - - chan->cur = nvpb->pushbuf; - chan->end = nvpb->pushbuf + nvpb->size; - - nouveau_bo_unmap(bo); - return 0; -} - -static void -nouveau_pushbuf_fini_call(struct nouveau_channel *chan) -{ - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - int i; - - for (i = 0; i < CALPB_BUFFERS; i++) - nouveau_bo_ref(NULL, &nvpb->buffer[i]); - nvpb->pushbuf = NULL; -} - -static int -nouveau_pushbuf_init_call(struct nouveau_channel *chan, int buf_size) -{ - struct drm_nouveau_gem_pushbuf req; - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - struct nouveau_device *dev = chan->device; - uint32_t flags = 0; - int i, ret; - - if (nvchan->drm.pushbuf_domains & NOUVEAU_GEM_DOMAIN_GART) - flags |= NOUVEAU_BO_GART; - else - flags |= NOUVEAU_BO_VRAM; - - req.channel = chan->id; - req.nr_push = 0; - ret = drmCommandWriteRead(nouveau_device(dev)->fd, - DRM_NOUVEAU_GEM_PUSHBUF, &req, sizeof(req)); - if (ret) - return ret; - - for (i = 0; i < CALPB_BUFFERS; i++) { - ret = nouveau_bo_new(dev, flags | NOUVEAU_BO_MAP, - 0, buf_size, &nvpb->buffer[i]); - if (ret) { - nouveau_pushbuf_fini_call(chan); - return ret; - } - } - - nvpb->cal_suffix0 = req.suffix0; - nvpb->cal_suffix1 = req.suffix1; - return 0; -} - -int -nouveau_pushbuf_init(struct nouveau_channel *chan, int buf_size) -{ - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - int ret; - - ret = nouveau_pushbuf_init_call(chan, buf_size); - if (ret) - return ret; - - ret = nouveau_pushbuf_space(chan, 0); - if (ret) - return ret; - - nvpb->buffers = calloc(NOUVEAU_GEM_MAX_BUFFERS, - sizeof(struct drm_nouveau_gem_pushbuf_bo)); - nvpb->relocs = calloc(NOUVEAU_GEM_MAX_RELOCS, - sizeof(struct drm_nouveau_gem_pushbuf_reloc)); - return 0; -} - -void -nouveau_pushbuf_fini(struct nouveau_channel *chan) -{ - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - nouveau_pushbuf_fini_call(chan); - free(nvpb->buffers); - free(nvpb->relocs); -} - -static int -nouveau_pushbuf_bo_add(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned offset, unsigned length) -{ - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - struct drm_nouveau_gem_pushbuf_push *p = &nvpb->push[nvpb->nr_push++]; - struct drm_nouveau_gem_pushbuf_bo *pbbo; - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - - pbbo = nouveau_bo_emit_buffer(chan, bo); - if (!pbbo) - return -ENOMEM; - pbbo->valid_domains &= nvchan->drm.pushbuf_domains; - pbbo->read_domains |= nvchan->drm.pushbuf_domains; - nvbo->pending_refcnt++; - - p->bo_index = pbbo - nvpb->buffers; - p->offset = offset; - p->length = length; - return 0; -} - -int -nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned offset, unsigned length) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - int ret, len; - - if ((AVAIL_RING(chan) + nvpb->current_offset) != nvpb->size) { - if (nvpb->cal_suffix0 || nvpb->cal_suffix1) { - *(chan->cur++) = nvpb->cal_suffix0; - *(chan->cur++) = nvpb->cal_suffix1; - } - - len = (chan->cur - nvpb->pushbuf) - nvpb->current_offset; - - ret = nouveau_pushbuf_bo_add(chan, nvpb->buffer[nvpb->current], - nvpb->current_offset * 4, len * 4); - if (ret) - return ret; - - nvpb->current_offset += len; - } - - return bo ? nouveau_pushbuf_bo_add(chan, bo, offset, length) : 0; -} - -static void -nouveau_pushbuf_bo_unref(struct nouveau_pushbuf_priv *nvpb, int index) -{ - struct drm_nouveau_gem_pushbuf_bo *pbbo = &nvpb->buffers[index]; - struct nouveau_bo *bo = (void *)(unsigned long)pbbo->user_priv; - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - - if (--nvbo->pending_refcnt) - return; - - if (pbbo->presumed.valid == 0) { - nvbo->domain = pbbo->presumed.domain; - nvbo->offset = pbbo->presumed.offset; - } - - nvbo->pending = NULL; - nouveau_bo_ref(NULL, &bo); - - /* we only ever remove from the tail of the pending lists, - * so this is safe. - */ - nvpb->nr_buffers--; -} - -int -nouveau_pushbuf_flush(struct nouveau_channel *chan, unsigned min) -{ - struct nouveau_device_priv *nvdev = nouveau_device(chan->device); - struct nouveau_channel_priv *nvchan = nouveau_channel(chan); - struct nouveau_pushbuf_priv *nvpb = &nvchan->pb; - struct drm_nouveau_gem_pushbuf req; - unsigned i; - int ret; - - ret = nouveau_pushbuf_submit(chan, NULL, 0, 0); - if (ret) - return ret; - - if (!nvpb->nr_push) - return 0; - - req.channel = chan->id; - req.nr_push = nvpb->nr_push; - req.push = (uint64_t)(unsigned long)nvpb->push; - req.nr_buffers = nvpb->nr_buffers; - req.buffers = (uint64_t)(unsigned long)nvpb->buffers; - req.nr_relocs = nvpb->nr_relocs; - req.relocs = (uint64_t)(unsigned long)nvpb->relocs; - req.suffix0 = nvpb->cal_suffix0; - req.suffix1 = nvpb->cal_suffix1; - - do { - ret = drmCommandWriteRead(nvdev->fd, DRM_NOUVEAU_GEM_PUSHBUF, - &req, sizeof(req)); - } while (ret == -EAGAIN); - nvpb->cal_suffix0 = req.suffix0; - nvpb->cal_suffix1 = req.suffix1; - nvdev->base.vm_vram_size = req.vram_available; - nvdev->base.vm_gart_size = req.gart_available; - - /* Update presumed offset/domain for any buffers that moved. - * Dereference all buffers on validate list - */ - for (i = 0; i < nvpb->nr_relocs; i++) { - nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index); - nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index); - } - - for (i = 0; i < nvpb->nr_push; i++) - nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index); - - nvpb->nr_buffers = 0; - nvpb->nr_relocs = 0; - nvpb->nr_push = 0; - - /* Allocate space for next push buffer */ - if (nouveau_pushbuf_space(chan, min)) - assert(0); - - if (chan->flush_notify) - chan->flush_notify(chan); - - nvpb->marker = NULL; - return ret; -} - -int -nouveau_pushbuf_marker_emit(struct nouveau_channel *chan, - unsigned wait_dwords, unsigned wait_relocs) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - - if (AVAIL_RING(chan) < wait_dwords) - return nouveau_pushbuf_flush(chan, wait_dwords); - - if (nvpb->nr_relocs + wait_relocs >= NOUVEAU_GEM_MAX_RELOCS) - return nouveau_pushbuf_flush(chan, wait_dwords); - - nvpb->marker = chan->cur; - nvpb->marker_offset = nvpb->current_offset; - nvpb->marker_push = nvpb->nr_push; - nvpb->marker_relocs = nvpb->nr_relocs; - return 0; -} - -void -nouveau_pushbuf_marker_undo(struct nouveau_channel *chan) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - unsigned i; - - if (!nvpb->marker) - return; - - /* undo any relocs/buffers added to the list since last marker */ - for (i = nvpb->marker_relocs; i < nvpb->nr_relocs; i++) { - nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].bo_index); - nouveau_pushbuf_bo_unref(nvpb, nvpb->relocs[i].reloc_bo_index); - } - nvpb->nr_relocs = nvpb->marker_relocs; - - for (i = nvpb->marker_push; i < nvpb->nr_push; i++) - nouveau_pushbuf_bo_unref(nvpb, nvpb->push[i].bo_index); - nvpb->nr_push = nvpb->marker_push; - - /* reset pushbuf back to last marker */ - chan->cur = nvpb->marker; - nvpb->current_offset = nvpb->marker_offset; - nvpb->marker = NULL; -} - -int -nouveau_pushbuf_emit_reloc(struct nouveau_channel *chan, void *ptr, - struct nouveau_bo *bo, uint32_t data, uint32_t data2, - uint32_t flags, uint32_t vor, uint32_t tor) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - int ret; - - ret = nouveau_reloc_emit(chan, nvpb->buffer[nvpb->current], - (char *)ptr - (char *)nvpb->pushbuf, ptr, - bo, data, data2, flags, vor, tor); - if (ret) - return ret; - - return 0; -} - diff --git a/nouveau/nouveau_pushbuf.h b/nouveau/nouveau_pushbuf.h deleted file mode 100644 index 2a98789..0000000 --- a/nouveau/nouveau_pushbuf.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_PUSHBUF_H__ -#define __NOUVEAU_PUSHBUF_H__ - -#include -#include - -#include "nouveau_bo.h" -#include "nouveau_grobj.h" - -int -nouveau_pushbuf_flush(struct nouveau_channel *, unsigned min); - -int -nouveau_pushbuf_marker_emit(struct nouveau_channel *chan, - unsigned wait_dwords, unsigned wait_relocs); - -void -nouveau_pushbuf_marker_undo(struct nouveau_channel *chan); - -int -nouveau_pushbuf_emit_reloc(struct nouveau_channel *, void *ptr, - struct nouveau_bo *, uint32_t data, uint32_t data2, - uint32_t flags, uint32_t vor, uint32_t tor); - -int -nouveau_pushbuf_submit(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned offset, unsigned length); - -/* Push buffer access macros */ -static __inline__ int -MARK_RING(struct nouveau_channel *chan, unsigned dwords, unsigned relocs) -{ - return nouveau_pushbuf_marker_emit(chan, dwords, relocs); -} - -static __inline__ void -MARK_UNDO(struct nouveau_channel *chan) -{ - nouveau_pushbuf_marker_undo(chan); -} - -static __inline__ void -OUT_RING(struct nouveau_channel *chan, unsigned data) -{ - *(chan->cur++) = (data); -} - -static __inline__ void -OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned size) -{ - memcpy(chan->cur, data, size * 4); - chan->cur += size; -} - -static __inline__ void -OUT_RINGf(struct nouveau_channel *chan, float f) -{ - union { uint32_t i; float f; } c; - c.f = f; - OUT_RING(chan, c.i); -} - -static __inline__ unsigned -AVAIL_RING(struct nouveau_channel *chan) -{ - return chan->end - chan->cur; -} - -static __inline__ void -WAIT_RING(struct nouveau_channel *chan, unsigned size) -{ - if (chan->cur + size > chan->end) - nouveau_pushbuf_flush(chan, size); -} - -static __inline__ void -FIRE_RING(struct nouveau_channel *chan) -{ - nouveau_pushbuf_flush(chan, 0); -} - -static __inline__ int -OUT_RELOC(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned data, unsigned flags, unsigned vor, unsigned tor) -{ - return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo, - data, 0, flags, vor, tor); -} - -static __inline__ int -OUT_RELOC2(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned data, unsigned data2, unsigned flags, - unsigned vor, unsigned tor) -{ - return nouveau_pushbuf_emit_reloc(chan, chan->cur++, bo, - data, data2, flags, vor, tor); -} - -/* Raw data + flags depending on FB/TT buffer */ -static __inline__ int -OUT_RELOCd(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned data, unsigned flags, unsigned vor, unsigned tor) -{ - return OUT_RELOC(chan, bo, data, flags | NOUVEAU_BO_OR, vor, tor); -} - -/* FB/TT object handle */ -static __inline__ int -OUT_RELOCo(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned flags) -{ - return OUT_RELOC(chan, bo, 0, flags | NOUVEAU_BO_OR, - chan->vram->handle, chan->gart->handle); -} - -/* Low 32-bits of offset */ -static __inline__ int -OUT_RELOCl(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned delta, unsigned flags) -{ - return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_LOW, 0, 0); -} - -/* Low 32-bits of offset + GPU linear access range info */ -static __inline__ int -OUT_RELOCr(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned delta, unsigned size, unsigned flags) -{ - return OUT_RELOC2(chan, bo, delta, size, flags | NOUVEAU_BO_LOW, 0, 0); -} - -/* High 32-bits of offset */ -static __inline__ int -OUT_RELOCh(struct nouveau_channel *chan, struct nouveau_bo *bo, - unsigned delta, unsigned flags) -{ - return OUT_RELOC(chan, bo, delta, flags | NOUVEAU_BO_HIGH, 0, 0); -} - -#endif diff --git a/nouveau/nouveau_reloc.c b/nouveau/nouveau_reloc.c deleted file mode 100644 index cd219db..0000000 --- a/nouveau/nouveau_reloc.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2010 Nouveau 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 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 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. - */ - -#include -#include -#include -#include - -#include "nouveau_private.h" - -static uint32_t -nouveau_reloc_calc(struct drm_nouveau_gem_pushbuf_bo *pbbo, - struct drm_nouveau_gem_pushbuf_reloc *r) -{ - uint32_t push = 0; - - if (r->flags & NOUVEAU_GEM_RELOC_LOW) - push = (pbbo->presumed.offset + r->data); - else - if (r->flags & NOUVEAU_GEM_RELOC_HIGH) - push = (pbbo->presumed.offset + r->data) >> 32; - else - push = r->data; - - if (r->flags & NOUVEAU_GEM_RELOC_OR) { - if (pbbo->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) - push |= r->vor; - else - push |= r->tor; - } - - return push; -} - -int -nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo, - uint32_t reloc_offset, uint32_t *reloc_ptr, - struct nouveau_bo *bo, uint32_t data, uint32_t data2, - uint32_t flags, uint32_t vor, uint32_t tor) -{ - struct nouveau_pushbuf_priv *nvpb = &nouveau_channel(chan)->pb; - struct nouveau_bo_priv *nvbo = nouveau_bo(bo); - struct drm_nouveau_gem_pushbuf_reloc *r; - struct drm_nouveau_gem_pushbuf_bo *pbbo, *rpbbo; - uint32_t domains = 0; - - if (nvpb->nr_relocs >= NOUVEAU_GEM_MAX_RELOCS) { - fprintf(stderr, "too many relocs!!\n"); - return -ENOMEM; - } - - if (nvbo->user && (flags & NOUVEAU_BO_WR)) { - fprintf(stderr, "write to user buffer!!\n"); - return -EINVAL; - } - - /* We're about to reloc a user buffer, better make sure we don't cause - * a double migration. - */ - if (!(nvbo->flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM))) - nvbo->flags |= (flags & (NOUVEAU_BO_GART | NOUVEAU_BO_VRAM)); - - /* add buffer to validation list */ - pbbo = nouveau_bo_emit_buffer(chan, bo); - if (!pbbo) { - fprintf(stderr, "buffer emit fail :(\n"); - return -ENOMEM; - } - nouveau_bo(bo)->pending_refcnt++; - - if (flags & (NOUVEAU_BO_VRAM | NOUVEAU_BO_GART)) { - if (flags & NOUVEAU_BO_VRAM) - domains |= NOUVEAU_GEM_DOMAIN_VRAM; - if (flags & NOUVEAU_BO_GART) - domains |= NOUVEAU_GEM_DOMAIN_GART; - } else - domains |= nvbo->domain; - - if (!(pbbo->valid_domains & domains)) { - fprintf(stderr, "no valid domains remain!\n"); - return -EINVAL; - } - pbbo->valid_domains &= domains; - - assert(flags & NOUVEAU_BO_RDWR); - if (flags & NOUVEAU_BO_RD) { - pbbo->read_domains |= domains; - } - if (flags & NOUVEAU_BO_WR) { - pbbo->write_domains |= domains; - nvbo->write_marker = 1; - } - - /* nvc0 gallium driver uses reloc_emit() with NULL target buffer - * to inform bufmgr of a buffer's use - however, we need something - * to track, so create a reloc for now, and hope it never triggers - * (it shouldn't, constant virtual address..).. - */ - if (!reloc_bo) { - reloc_bo = nvpb->buffer[nvpb->current]; - reloc_offset = 0; - reloc_ptr = NULL; - } - - /* add reloc target bo to validation list, and create the reloc */ - rpbbo = nouveau_bo_emit_buffer(chan, reloc_bo); - if (!rpbbo) - return -ENOMEM; - nouveau_bo(reloc_bo)->pending_refcnt++; - - r = nvpb->relocs + nvpb->nr_relocs++; - r->reloc_bo_index = rpbbo - nvpb->buffers; - r->reloc_bo_offset = reloc_offset; - r->bo_index = pbbo - nvpb->buffers; - r->flags = 0; - if (flags & NOUVEAU_BO_LOW) - r->flags |= NOUVEAU_GEM_RELOC_LOW; - if (flags & NOUVEAU_BO_HIGH) - r->flags |= NOUVEAU_GEM_RELOC_HIGH; - if (flags & NOUVEAU_BO_OR) - r->flags |= NOUVEAU_GEM_RELOC_OR; - r->data = data; - r->vor = vor; - r->tor = tor; - - if (reloc_ptr) { - if (flags & NOUVEAU_BO_DUMMY) - *reloc_ptr = 0; - else - *reloc_ptr = nouveau_reloc_calc(pbbo, r); - } - - return 0; -} - diff --git a/nouveau/nouveau_reloc.h b/nouveau/nouveau_reloc.h deleted file mode 100644 index 24ddb52..0000000 --- a/nouveau/nouveau_reloc.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_RELOC_H__ -#define __NOUVEAU_RELOC_H__ - -int -nouveau_reloc_emit(struct nouveau_channel *chan, struct nouveau_bo *reloc_bo, - uint32_t reloc_offset, uint32_t *reloc_ptr, - struct nouveau_bo *bo, uint32_t data, uint32_t data2, - uint32_t flags, uint32_t vor, uint32_t tor); - -#endif diff --git a/nouveau/nouveau_resource.c b/nouveau/nouveau_resource.c deleted file mode 100644 index 7acaf7d..0000000 --- a/nouveau/nouveau_resource.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#include -#include - -#include "nouveau_private.h" - -int -nouveau_resource_init(struct nouveau_resource **heap, - unsigned start, unsigned size) -{ - struct nouveau_resource *r; - - r = calloc(1, sizeof(struct nouveau_resource)); - if (!r) - return 1; - - r->start = start; - r->size = size; - *heap = r; - return 0; -} - -void -nouveau_resource_destroy(struct nouveau_resource **heap) -{ - if (!*heap) - return; - free(*heap); - *heap = NULL; -} - -int -nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv, - struct nouveau_resource **res) -{ - struct nouveau_resource *r; - - if (!heap || !size || !res || *res) - return 1; - - while (heap) { - if (!heap->in_use && heap->size >= size) { - r = calloc(1, sizeof(struct nouveau_resource)); - if (!r) - return 1; - - r->start = (heap->start + heap->size) - size; - r->size = size; - r->in_use = 1; - r->priv = priv; - - heap->size -= size; - - r->next = heap->next; - if (heap->next) - heap->next->prev = r; - r->prev = heap; - heap->next = r; - - *res = r; - return 0; - } - - heap = heap->next; - } - - return 1; -} - -void -nouveau_resource_free(struct nouveau_resource **res) -{ - struct nouveau_resource *r; - - if (!res || !*res) - return; - r = *res; - *res = NULL; - - r->in_use = 0; - - if (r->next && !r->next->in_use) { - struct nouveau_resource *new = r->next; - - new->prev = r->prev; - if (r->prev) - r->prev->next = new; - new->size += r->size; - new->start = r->start; - - free(r); - r = new; - } - - if (r->prev && !r->prev->in_use) { - r->prev->next = r->next; - if (r->next) - r->next->prev = r->prev; - r->prev->size += r->size; - free(r); - } - -} diff --git a/nouveau/nouveau_resource.h b/nouveau/nouveau_resource.h deleted file mode 100644 index b760dfb..0000000 --- a/nouveau/nouveau_resource.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NOUVEAU_RESOURCE_H__ -#define __NOUVEAU_RESOURCE_H__ - -struct nouveau_resource { - struct nouveau_resource *prev; - struct nouveau_resource *next; - - int in_use; - void *priv; - - unsigned int start; - unsigned int size; -}; - -int -nouveau_resource_init(struct nouveau_resource **heap, unsigned start, - unsigned size); - -void -nouveau_resource_destroy(struct nouveau_resource **heap); - -int -nouveau_resource_alloc(struct nouveau_resource *heap, unsigned size, void *priv, - struct nouveau_resource **); - -void -nouveau_resource_free(struct nouveau_resource **); - -#endif diff --git a/nouveau/nv04_pushbuf.h b/nouveau/nv04_pushbuf.h deleted file mode 100644 index 586b284..0000000 --- a/nouveau/nv04_pushbuf.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2007 Nouveau 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 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 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. - */ - -#ifndef __NV04_PUSHBUF_H__ -#define __NV04_PUSHBUF_H__ - -#include "nouveau_pushbuf.h" - -static __inline__ void -BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned size) -{ - if (gr->bound == NOUVEAU_GROBJ_UNBOUND) - nouveau_grobj_autobind(gr); - chan->subc[gr->subc].sequence = chan->subc_sequence++; - - WAIT_RING(chan, size + 1); - OUT_RING(chan, (gr->subc << 13) | (size << 18) | mthd); -} - -/* non-incrementing BEGIN_RING */ -static __inline__ void -BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned size) -{ - BEGIN_RING(chan, gr, mthd | 0x40000000, size); -} - -static __inline__ void -BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc) -{ - struct nouveau_subchannel *subc = &gr->channel->subc[sc]; - - if (subc->gr) { - if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT) - assert(0); - subc->gr->bound = NOUVEAU_GROBJ_UNBOUND; - } - subc->gr = gr; - subc->gr->subc = sc; - subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT; - - BEGIN_RING(chan, gr, 0x0000, 1); - OUT_RING (chan, gr->handle); -} - -#endif diff --git a/nouveau/nvc0_pushbuf.h b/nouveau/nvc0_pushbuf.h deleted file mode 100644 index 40dc7e6..0000000 --- a/nouveau/nvc0_pushbuf.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2010 Nouveau 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 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 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. - */ - -#ifndef __NVC0_PUSHBUF_H__ -#define __NVC0_PUSHBUF_H__ - -#include "nouveau_pushbuf.h" - -#define SUBC_BIND(chan, gr) do { \ - if (gr->bound == NOUVEAU_GROBJ_UNBOUND) \ - nouveau_grobj_autobind(gr); \ - chan->subc[gr->subc].sequence = chan->subc_sequence++; \ -} while (0) - -/* incremental methods */ -static __inline__ void -BEGIN_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned size) -{ - SUBC_BIND(chan, gr); - WAIT_RING(chan, size + 1); - OUT_RING (chan, (0x2 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2)); -} - -/* non-incremental */ -static __inline__ void -BEGIN_RING_NI(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned size) -{ - SUBC_BIND(chan, gr); - WAIT_RING(chan, size + 1); - OUT_RING (chan, (0x6 << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2)); -} - -/* increment-once */ -static __inline__ void -BEGIN_RING_1I(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned size) -{ - SUBC_BIND(chan, gr); - WAIT_RING(chan, size + 1); - OUT_RING (chan, (0xa << 28) | (size << 16) | (gr->subc << 13) | (mthd >> 2)); -} - -/* inline-data */ -static __inline__ void -IMMED_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, - unsigned mthd, unsigned data) -{ - SUBC_BIND(chan, gr); - WAIT_RING(chan, 1); - OUT_RING (chan, (0x8 << 28) | (data << 16) | (gr->subc << 13) | (mthd >> 2)); -} - -static __inline__ void -BIND_RING(struct nouveau_channel *chan, struct nouveau_grobj *gr, unsigned sc) -{ - struct nouveau_subchannel *subc = &gr->channel->subc[sc]; - - if (subc->gr) { - if (subc->gr->bound == NOUVEAU_GROBJ_BOUND_EXPLICIT) - assert(0); - subc->gr->bound = NOUVEAU_GROBJ_UNBOUND; - } - subc->gr = gr; - subc->gr->subc = sc; - subc->gr->bound = NOUVEAU_GROBJ_BOUND_EXPLICIT; - - BEGIN_RING(chan, gr, 0x0000, 1); - OUT_RING (chan, gr->grclass); -} - -#endif diff --git a/nouveau/private.h b/nouveau/private.h new file mode 100644 index 0000000..b409cc8 --- /dev/null +++ b/nouveau/private.h @@ -0,0 +1,122 @@ +#ifndef __NOUVEAU_LIBDRM_PRIVATE_H__ +#define __NOUVEAU_LIBDRM_PRIVATE_H__ + +#include +#include +#include "nouveau_drm.h" + +#include "nouveau.h" + +#ifdef DEBUG +uint32_t nouveau_debug; +#define dbg_on(lvl) (nouveau_debug & (1 << lvl)) +#define dbg(lvl, fmt, args...) do { \ + if (dbg_on((lvl))) \ + fprintf(stderr, "nouveau: "fmt, ##args); \ +} while(0) +#else +#define dbg_on(lvl) (0) +#define dbg(lvl, fmt, args...) +#endif +#define err(fmt, args...) fprintf(stderr, "nouveau: "fmt, ##args) + +struct nouveau_client_kref { + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_pushbuf *push; +}; + +struct nouveau_client_priv { + struct nouveau_client base; + struct nouveau_client_kref *kref; + unsigned kref_nr; +}; + +static inline struct nouveau_client_priv * +nouveau_client(struct nouveau_client *client) +{ + return (struct nouveau_client_priv *)client; +} + +static inline struct drm_nouveau_gem_pushbuf_bo * +cli_kref_get(struct nouveau_client *client, struct nouveau_bo *bo) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + struct drm_nouveau_gem_pushbuf_bo *kref = NULL; + if (pcli->kref_nr > bo->handle) + kref = pcli->kref[bo->handle].kref; + return kref; +} + +static inline struct nouveau_pushbuf * +cli_push_get(struct nouveau_client *client, struct nouveau_bo *bo) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + struct nouveau_pushbuf *push = NULL; + if (pcli->kref_nr > bo->handle) + push = pcli->kref[bo->handle].push; + return push; +} + +static inline void +cli_kref_set(struct nouveau_client *client, struct nouveau_bo *bo, + struct drm_nouveau_gem_pushbuf_bo *kref, + struct nouveau_pushbuf *push) +{ + struct nouveau_client_priv *pcli = nouveau_client(client); + if (pcli->kref_nr <= bo->handle) { + pcli->kref = realloc(pcli->kref, + sizeof(*pcli->kref) * bo->handle * 2); + while (pcli->kref_nr < bo->handle * 2) { + pcli->kref[pcli->kref_nr].kref = NULL; + pcli->kref[pcli->kref_nr].push = NULL; + pcli->kref_nr++; + } + } + pcli->kref[bo->handle].kref = kref; + pcli->kref[bo->handle].push = push; +} + +struct nouveau_bo_priv { + struct nouveau_bo base; + struct nouveau_list head; + atomic_t refcnt; + uint64_t map_handle; + uint32_t name; + uint32_t access; +}; + +static inline struct nouveau_bo_priv * +nouveau_bo(struct nouveau_bo *bo) +{ + return (struct nouveau_bo_priv *)bo; +} + +struct nouveau_device_priv { + struct nouveau_device base; + int close; + atomic_t lock; + struct nouveau_list bo_list; + uint32_t *client; + int nr_client; + bool have_bo_usage; +}; + +static inline struct nouveau_device_priv * +nouveau_device(struct nouveau_device *dev) +{ + return (struct nouveau_device_priv *)dev; +} + +int +nouveau_device_open_existing(struct nouveau_device **, int, int, drm_context_t); + +/* abi16.c */ +int abi16_chan_nv04(struct nouveau_object *); +int abi16_chan_nvc0(struct nouveau_object *); +int abi16_engobj(struct nouveau_object *); +int abi16_ntfy(struct nouveau_object *); +void abi16_bo_info(struct nouveau_bo *, struct drm_nouveau_gem_info *); +int abi16_bo_init(struct nouveau_bo *, uint32_t alignment, + union nouveau_bo_config *); + +#endif diff --git a/nouveau/pushbuf.c b/nouveau/pushbuf.c new file mode 100644 index 0000000..7b9dbaa --- /dev/null +++ b/nouveau/pushbuf.c @@ -0,0 +1,771 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "libdrm_lists.h" +#include "nouveau_drm.h" + +#include "nouveau.h" +#include "private.h" + +struct nouveau_pushbuf_krec { + struct nouveau_pushbuf_krec *next; + struct drm_nouveau_gem_pushbuf_bo buffer[NOUVEAU_GEM_MAX_BUFFERS]; + struct drm_nouveau_gem_pushbuf_reloc reloc[NOUVEAU_GEM_MAX_RELOCS]; + struct drm_nouveau_gem_pushbuf_push push[NOUVEAU_GEM_MAX_PUSH]; + int nr_buffer; + int nr_reloc; + int nr_push; + uint64_t vram_used; + uint64_t gart_used; +}; + +struct nouveau_pushbuf_priv { + struct nouveau_pushbuf base; + struct nouveau_pushbuf_krec *list; + struct nouveau_pushbuf_krec *krec; + struct nouveau_list bctx_list; + struct nouveau_bo *bo; + uint32_t type; + uint32_t suffix0; + uint32_t suffix1; + uint32_t *ptr; + uint32_t *bgn; + int bo_next; + int bo_nr; + struct nouveau_bo *bos[]; +}; + +static inline struct nouveau_pushbuf_priv * +nouveau_pushbuf(struct nouveau_pushbuf *push) +{ + return (struct nouveau_pushbuf_priv *)push; +} + +static int pushbuf_validate(struct nouveau_pushbuf *, bool); +static int pushbuf_flush(struct nouveau_pushbuf *); + +static bool +pushbuf_kref_fits(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t *domains) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_device *dev = push->client->device; + struct nouveau_bo *kbo; + struct drm_nouveau_gem_pushbuf_bo *kref; + int i; + + /* VRAM is the only valid domain. GART and VRAM|GART buffers + * are all accounted to GART, so if this doesn't fit in VRAM + * straight up, a flush is needed. + */ + if (*domains == NOUVEAU_GEM_DOMAIN_VRAM) { + if (krec->vram_used + bo->size > dev->vram_limit) + return false; + krec->vram_used += bo->size; + return true; + } + + /* GART or VRAM|GART buffer. Account both of these buffer types + * to GART only for the moment, which simplifies things. If the + * buffer can fit already, we're done here. + */ + if (krec->gart_used + bo->size <= dev->gart_limit) { + krec->gart_used += bo->size; + return true; + } + + /* Ran out of GART space, if it's a VRAM|GART buffer and it'll + * fit into available VRAM, turn it into a VRAM buffer + */ + if ((*domains & NOUVEAU_GEM_DOMAIN_VRAM) && + krec->vram_used + bo->size <= dev->vram_limit) { + *domains &= NOUVEAU_GEM_DOMAIN_VRAM; + krec->vram_used += bo->size; + return true; + } + + /* Still couldn't fit the buffer in anywhere, so as a last resort; + * scan the buffer list for VRAM|GART buffers and turn them into + * VRAM buffers until we have enough space in GART for this one + */ + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART)) + continue; + + kbo = (void *)(unsigned long)kref->user_priv; + if (!(kref->valid_domains & NOUVEAU_GEM_DOMAIN_VRAM) || + krec->vram_used + kbo->size > dev->vram_limit) + continue; + + kref->valid_domains &= NOUVEAU_GEM_DOMAIN_VRAM; + krec->gart_used -= kbo->size; + krec->vram_used += kbo->size; + if (krec->gart_used + bo->size <= dev->gart_limit) { + krec->gart_used += bo->size; + return true; + } + } + + /* Couldn't resolve a placement, need to force a flush */ + return false; +} + +static struct drm_nouveau_gem_pushbuf_bo * +pushbuf_kref(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t flags) +{ + struct nouveau_device *dev = push->client->device; + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_pushbuf *fpush; + struct drm_nouveau_gem_pushbuf_bo *kref; + uint32_t domains, domains_wr, domains_rd; + + domains = 0; + if (flags & NOUVEAU_BO_VRAM) + domains |= NOUVEAU_GEM_DOMAIN_VRAM; + if (flags & NOUVEAU_BO_GART) + domains |= NOUVEAU_GEM_DOMAIN_GART; + domains_wr = domains * !!(flags & NOUVEAU_BO_WR); + domains_rd = domains * !!(flags & NOUVEAU_BO_RD); + + /* if buffer is referenced on another pushbuf that is owned by the + * same client, we need to flush the other pushbuf first to ensure + * the correct ordering of commands + */ + fpush = cli_push_get(push->client, bo); + if (fpush && fpush != push) + pushbuf_flush(fpush); + + kref = cli_kref_get(push->client, bo); + if (kref) { + /* possible conflict in memory types - flush and retry */ + if (!(kref->valid_domains & domains)) + return NULL; + + /* VRAM|GART buffer turning into a VRAM buffer. Make sure + * it'll fit in VRAM and force a flush if not. + */ + if ((kref->valid_domains & NOUVEAU_GEM_DOMAIN_GART) && + ( domains == NOUVEAU_GEM_DOMAIN_VRAM)) { + if (krec->vram_used + bo->size > dev->vram_limit) + return NULL; + krec->vram_used += bo->size; + krec->gart_used -= bo->size; + } + + kref->valid_domains &= domains; + kref->write_domains |= domains_wr; + kref->read_domains |= domains_rd; + } else { + if (krec->nr_buffer == NOUVEAU_GEM_MAX_BUFFERS || + !pushbuf_kref_fits(push, bo, &domains)) + return NULL; + + kref = &krec->buffer[krec->nr_buffer++]; + kref->user_priv = (unsigned long)bo; + kref->handle = bo->handle; + kref->valid_domains = domains; + kref->write_domains = domains_wr; + kref->read_domains = domains_rd; + kref->presumed.valid = 1; + kref->presumed.offset = bo->offset; + if (bo->flags & NOUVEAU_BO_VRAM) + kref->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; + else + kref->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; + + cli_kref_set(push->client, bo, kref, push); + atomic_inc(&nouveau_bo(bo)->refcnt); + } + + return kref; +} + +static uint32_t +pushbuf_krel(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_reloc *krel; + struct drm_nouveau_gem_pushbuf_bo *pkref; + struct drm_nouveau_gem_pushbuf_bo *bkref; + uint32_t reloc = data; + + pkref = cli_kref_get(push->client, nvpb->bo); + bkref = cli_kref_get(push->client, bo); + krel = &krec->reloc[krec->nr_reloc++]; + + krel->reloc_bo_index = pkref - krec->buffer; + krel->reloc_bo_offset = (push->cur - nvpb->ptr) * 4; + krel->bo_index = bkref - krec->buffer; + krel->flags = 0; + krel->data = data; + krel->vor = vor; + krel->tor = tor; + + if (flags & NOUVEAU_BO_LOW) { + reloc = (bkref->presumed.offset + data); + krel->flags |= NOUVEAU_GEM_RELOC_LOW; + } else + if (flags & NOUVEAU_BO_HIGH) { + reloc = (bkref->presumed.offset + data) >> 32; + krel->flags |= NOUVEAU_GEM_RELOC_HIGH; + } + if (flags & NOUVEAU_BO_OR) { + if (bkref->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) + reloc |= vor; + else + reloc |= tor; + krel->flags |= NOUVEAU_GEM_RELOC_OR; + } + + return reloc; +} + +static void +pushbuf_dump(struct nouveau_pushbuf_krec *krec, int krec_id, int chid) +{ + struct drm_nouveau_gem_pushbuf_reloc *krel; + struct drm_nouveau_gem_pushbuf_push *kpsh; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bo *bo; + uint32_t *bgn, *end; + int i; + + err("ch%d: krec %d pushes %d bufs %d relocs %d\n", chid, + krec_id, krec->nr_push, krec->nr_buffer, krec->nr_reloc); + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + err("ch%d: buf %08x %08x %08x %08x %08x\n", chid, i, + kref->handle, kref->valid_domains, + kref->read_domains, kref->write_domains); + } + + krel = krec->reloc; + for (i = 0; i < krec->nr_reloc; i++, krel++) { + err("ch%d: rel %08x %08x %08x %08x %08x %08x %08x\n", + chid, krel->reloc_bo_index, krel->reloc_bo_offset, + krel->bo_index, krel->flags, krel->data, + krel->vor, krel->tor); + } + + kpsh = krec->push; + for (i = 0; i < krec->nr_push; i++, kpsh++) { + kref = krec->buffer + kpsh->bo_index; + bo = (void *)(unsigned long)kref->user_priv; + bgn = (uint32_t *)((char *)bo->map + kpsh->offset); + end = bgn + (kpsh->length /4); + + err("ch%d: psh %08x %010llx %010llx\n", chid, kpsh->bo_index, + (unsigned long long)kpsh->offset, + (unsigned long long)(kpsh->offset + kpsh->length)); + while (bgn < end) + err("\t0x%08x\n", *bgn++); + } +} + +static int +pushbuf_submit(struct nouveau_pushbuf *push, struct nouveau_object *chan) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->list; + struct nouveau_device *dev = push->client->device; + struct drm_nouveau_gem_pushbuf_bo_presumed *info; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct drm_nouveau_gem_pushbuf req; + struct nouveau_fifo *fifo = chan->data; + struct nouveau_bo *bo; + int krec_id = 0; + int ret = 0, i; + + if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS) + return -EINVAL; + + if (push->kick_notify) + push->kick_notify(push); + + nouveau_pushbuf_data(push, NULL, 0, 0); + + while (krec && krec->nr_push) { + req.channel = fifo->channel; + req.nr_buffers = krec->nr_buffer; + req.buffers = (uint64_t)(unsigned long)krec->buffer; + req.nr_relocs = krec->nr_reloc; + req.nr_push = krec->nr_push; + req.relocs = (uint64_t)(unsigned long)krec->reloc; + req.push = (uint64_t)(unsigned long)krec->push; + req.suffix0 = nvpb->suffix0; + req.suffix1 = nvpb->suffix1; + + if (dbg_on(0)) + pushbuf_dump(krec, krec_id++, fifo->channel); + +#ifndef SIMULATE + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF, + &req, sizeof(req)); + nvpb->suffix0 = req.suffix0; + nvpb->suffix1 = req.suffix1; + dev->vram_limit = (req.vram_available * 80) / 100; + dev->gart_limit = (req.gart_available * 80) / 100; +#else + if (dbg_on(31)) + ret = -EINVAL; +#endif + + if (ret) { + err("kernel rejected pushbuf: %s\n", strerror(-ret)); + pushbuf_dump(krec, krec_id++, fifo->channel); + break; + } + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + bo = (void *)(unsigned long)kref->user_priv; + + info = &kref->presumed; + if (!info->valid) { + bo->flags &= ~NOUVEAU_BO_APER; + if (info->domain == NOUVEAU_GEM_DOMAIN_VRAM) + bo->flags |= NOUVEAU_BO_VRAM; + else + bo->flags |= NOUVEAU_BO_GART; + bo->offset = info->offset; + } + + if (kref->write_domains) + nouveau_bo(bo)->access |= NOUVEAU_BO_WR; + if (kref->read_domains) + nouveau_bo(bo)->access |= NOUVEAU_BO_RD; + } + + krec = krec->next; + } + + return ret; +} + +static int +pushbuf_flush(struct nouveau_pushbuf *push) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bufctx *bctx, *btmp; + struct nouveau_bo *bo; + int ret = 0, i; + + if (push->channel) { + ret = pushbuf_submit(push, push->channel); + } else { + nouveau_pushbuf_data(push, NULL, 0, 0); + krec->next = malloc(sizeof(*krec)); + nvpb->krec = krec->next; + } + + kref = krec->buffer; + for (i = 0; i < krec->nr_buffer; i++, kref++) { + bo = (void *)(unsigned long)kref->user_priv; + cli_kref_set(push->client, bo, NULL, NULL); + if (push->channel) + nouveau_bo_ref(NULL, &bo); + } + + krec = nvpb->krec; + krec->vram_used = 0; + krec->gart_used = 0; + krec->nr_buffer = 0; + krec->nr_reloc = 0; + krec->nr_push = 0; + + DRMLISTFOREACHENTRYSAFE(bctx, btmp, &nvpb->bctx_list, head) { + DRMLISTJOIN(&bctx->current, &bctx->pending); + DRMINITLISTHEAD(&bctx->current); + DRMLISTDELINIT(&bctx->head); + } + + return ret; +} + +static void +pushbuf_refn_fail(struct nouveau_pushbuf *push, int sref, int srel) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + + kref = krec->buffer + sref; + while (krec->nr_buffer-- > sref) { + struct nouveau_bo *bo = (void *)(unsigned long)kref->user_priv; + cli_kref_set(push->client, bo, NULL, NULL); + nouveau_bo_ref(NULL, &bo); + kref++; + } + krec->nr_buffer = sref; + krec->nr_reloc = srel; +} + +static int +pushbuf_refn(struct nouveau_pushbuf *push, bool retry, + struct nouveau_pushbuf_refn *refs, int nr) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + int sref = krec->nr_buffer; + int ret = 0, i; + + for (i = 0; i < nr; i++) { + kref = pushbuf_kref(push, refs[i].bo, refs[i].flags); + if (!kref) { + ret = -ENOSPC; + break; + } + } + + if (ret) { + pushbuf_refn_fail(push, sref, krec->nr_reloc); + if (retry) { + pushbuf_flush(push); + nouveau_pushbuf_space(push, 0, 0, 0); + return pushbuf_refn(push, false, refs, nr); + } + } + + return ret; +} + +static int +pushbuf_validate(struct nouveau_pushbuf *push, bool retry) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_bufctx *bctx = push->bufctx; + struct nouveau_bufref *bref; + int relocs = bctx ? bctx->relocs * 2: 0; + int sref, srel, ret; + + ret = nouveau_pushbuf_space(push, relocs, relocs, 0); + if (ret || bctx == NULL) + return ret; + + sref = krec->nr_buffer; + srel = krec->nr_reloc; + + DRMLISTDEL(&bctx->head); + DRMLISTADD(&bctx->head, &nvpb->bctx_list); + + DRMLISTFOREACHENTRY(bref, &bctx->pending, thead) { + kref = pushbuf_kref(push, bref->bo, bref->flags); + if (!kref) { + ret = -ENOSPC; + break; + } + + if (bref->packet) { + pushbuf_krel(push, bref->bo, bref->packet, 0, 0, 0); + *push->cur++ = 0; + pushbuf_krel(push, bref->bo, bref->data, bref->flags, + bref->vor, bref->tor); + *push->cur++ = 0; + } + } + + DRMLISTJOIN(&bctx->pending, &bctx->current); + DRMINITLISTHEAD(&bctx->pending); + + if (ret) { + pushbuf_refn_fail(push, sref, srel); + if (retry) { + pushbuf_flush(push); + return pushbuf_validate(push, false); + } + } + + return 0; +} + +int +nouveau_pushbuf_new(struct nouveau_client *client, struct nouveau_object *chan, + int nr, uint32_t size, bool immediate, + struct nouveau_pushbuf **ppush) +{ + struct nouveau_device *dev = client->device; + struct nouveau_fifo *fifo = chan->data; + struct nouveau_pushbuf_priv *nvpb; + struct nouveau_pushbuf *push; + struct drm_nouveau_gem_pushbuf req; + int ret; + + if (chan->oclass != NOUVEAU_FIFO_CHANNEL_CLASS) + return -EINVAL; + + /* nop pushbuf call, to get the current "return to main" sequence + * we need to append to the pushbuf on early chipsets + */ + req.channel = fifo->channel; + req.nr_push = 0; + ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_PUSHBUF, + &req, sizeof(req)); + if (ret) + return ret; + + nvpb = calloc(1, sizeof(*nvpb) + nr * sizeof(*nvpb->bos)); + if (!nvpb) + return -ENOMEM; + +#ifndef SIMULATE + nvpb->suffix0 = req.suffix0; + nvpb->suffix1 = req.suffix1; +#else + nvpb->suffix0 = 0xffffffff; + nvpb->suffix1 = 0xffffffff; +#endif + nvpb->krec = calloc(1, sizeof(*nvpb->krec)); + nvpb->list = nvpb->krec; + if (!nvpb->krec) { + free(nvpb); + return -ENOMEM; + } + + push = &nvpb->base; + push->client = client; + push->channel = immediate ? chan : NULL; + push->flags = NOUVEAU_BO_RD; + if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_VRAM) { + push->flags |= NOUVEAU_BO_VRAM; + nvpb->type = NOUVEAU_BO_VRAM; + } + if (fifo->pushbuf & NOUVEAU_GEM_DOMAIN_GART) { + push->flags |= NOUVEAU_BO_GART; + nvpb->type = NOUVEAU_BO_GART; + } + nvpb->type |= NOUVEAU_BO_MAP; + + for (nvpb->bo_nr = 0; nvpb->bo_nr < nr; nvpb->bo_nr++) { + ret = nouveau_bo_new(client->device, nvpb->type, 0, size, + NULL, &nvpb->bos[nvpb->bo_nr]); + if (ret) { + nouveau_pushbuf_del(&push); + return ret; + } + } + + DRMINITLISTHEAD(&nvpb->bctx_list); + *ppush = push; + return 0; +} + +void +nouveau_pushbuf_del(struct nouveau_pushbuf **ppush) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(*ppush); + if (nvpb) { + struct drm_nouveau_gem_pushbuf_bo *kref; + struct nouveau_pushbuf_krec *krec; + while ((krec = nvpb->list)) { + kref = krec->buffer; + while (krec->nr_buffer--) { + unsigned long priv = kref++->user_priv; + struct nouveau_bo *bo = (void *)priv; + cli_kref_set(nvpb->base.client, bo, NULL, NULL); + nouveau_bo_ref(NULL, &bo); + } + nvpb->list = krec->next; + free(krec); + } + while (nvpb->bo_nr--) + nouveau_bo_ref(NULL, &nvpb->bos[nvpb->bo_nr]); + nouveau_bo_ref(NULL, &nvpb->bo); + free(nvpb); + } + *ppush = NULL; +} + +struct nouveau_bufctx * +nouveau_pushbuf_bufctx(struct nouveau_pushbuf *push, struct nouveau_bufctx *ctx) +{ + struct nouveau_bufctx *prev = push->bufctx; + push->bufctx = ctx; + return prev; +} + +int +nouveau_pushbuf_space(struct nouveau_pushbuf *push, + uint32_t dwords, uint32_t relocs, uint32_t pushes) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct nouveau_client *client = push->client; + struct nouveau_bo *bo = NULL; + bool flushed = false; + int ret = 0; + + /* switch to next buffer if insufficient space in the current one */ + if (push->cur + dwords >= push->end) { + if (nvpb->bo_next < nvpb->bo_nr) { + nouveau_bo_ref(nvpb->bos[nvpb->bo_next++], &bo); + if (nvpb->bo_next == nvpb->bo_nr && push->channel) + nvpb->bo_next = 0; + } else { + ret = nouveau_bo_new(client->device, nvpb->type, 0, + nvpb->bos[0]->size, NULL, &bo); + if (ret) + return ret; + } + } + + /* make sure there's always enough space to queue up the pending + * data in the pushbuf proper + */ + pushes++; + + /* need to flush if we've run out of space on an immediate pushbuf, + * if the new buffer won't fit, or if the kernel push/reloc limits + * have been hit + */ + if ((bo && ( push->channel || + !pushbuf_kref(push, bo, push->flags))) || + krec->nr_reloc + relocs >= NOUVEAU_GEM_MAX_RELOCS || + krec->nr_push + pushes >= NOUVEAU_GEM_MAX_PUSH) { + if (nvpb->bo && krec->nr_buffer) + pushbuf_flush(push); + flushed = true; + } + + /* if necessary, switch to new buffer */ + if (bo) { + ret = nouveau_bo_map(bo, NOUVEAU_BO_WR, push->client); + if (ret) + return ret; + + nouveau_pushbuf_data(push, NULL, 0, 0); + nouveau_bo_ref(bo, &nvpb->bo); + nouveau_bo_ref(NULL, &bo); + + nvpb->bgn = nvpb->bo->map; + nvpb->ptr = nvpb->bgn; + push->cur = nvpb->bgn; + push->end = push->cur + (nvpb->bo->size / 4); + push->end -= 2 + push->rsvd_kick; /* space for suffix */ + } + + pushbuf_kref(push, nvpb->bo, push->flags); + return flushed ? pushbuf_validate(push, false) : 0; +} + +void +nouveau_pushbuf_data(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint64_t offset, uint64_t length) +{ + struct nouveau_pushbuf_priv *nvpb = nouveau_pushbuf(push); + struct nouveau_pushbuf_krec *krec = nvpb->krec; + struct drm_nouveau_gem_pushbuf_push *kpsh; + struct drm_nouveau_gem_pushbuf_bo *kref; + + if (bo != nvpb->bo && nvpb->bgn != push->cur) { + if (nvpb->suffix0 || nvpb->suffix1) { + *push->cur++ = nvpb->suffix0; + *push->cur++ = nvpb->suffix1; + } + + nouveau_pushbuf_data(push, nvpb->bo, + (nvpb->bgn - nvpb->ptr) * 4, + (push->cur - nvpb->bgn) * 4); + nvpb->bgn = push->cur; + } + + if (bo) { + kref = cli_kref_get(push->client, bo); + kpsh = &krec->push[krec->nr_push++]; + kpsh->bo_index = kref - krec->buffer; + kpsh->offset = offset; + kpsh->length = length; + } +} + +int +nouveau_pushbuf_refn(struct nouveau_pushbuf *push, + struct nouveau_pushbuf_refn *refs, int nr) +{ + return pushbuf_refn(push, true, refs, nr); +} + +void +nouveau_pushbuf_reloc(struct nouveau_pushbuf *push, struct nouveau_bo *bo, + uint32_t data, uint32_t flags, uint32_t vor, uint32_t tor) +{ + *push->cur++ = pushbuf_krel(push, bo, data, flags, vor, tor); +} + +int +nouveau_pushbuf_validate(struct nouveau_pushbuf *push) +{ + return pushbuf_validate(push, true); +} + +uint32_t +nouveau_pushbuf_refd(struct nouveau_pushbuf *push, struct nouveau_bo *bo) +{ + struct drm_nouveau_gem_pushbuf_bo *kref; + uint32_t flags = 0; + + if (cli_push_get(push->client, bo) == push) { + kref = cli_kref_get(push->client, bo); + if (kref->read_domains) + flags |= NOUVEAU_BO_RD; + if (kref->write_domains) + flags |= NOUVEAU_BO_WR; + } + + return flags; +} + +int +nouveau_pushbuf_kick(struct nouveau_pushbuf *push, struct nouveau_object *chan) +{ + if (!push->channel) + return pushbuf_submit(push, chan); + pushbuf_flush(push); + return pushbuf_validate(push, false); +} diff --git a/omap/Makefile.am b/omap/Makefile.am new file mode 100644 index 0000000..c77520b --- /dev/null +++ b/omap/Makefile.am @@ -0,0 +1,22 @@ +AM_CFLAGS = \ + $(WARN_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/omap \ + $(PTHREADSTUBS_CFLAGS) \ + -I$(top_srcdir)/include/drm + +libdrm_omap_la_LTLIBRARIES = libdrm_omap.la +libdrm_omap_ladir = $(libdir) +libdrm_omap_la_LDFLAGS = -version-number 1:0:0 -no-undefined +libdrm_omap_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ + +libdrm_omap_la_SOURCES = omap_drm.c + +libdrm_omapcommonincludedir = ${includedir}/omap +libdrm_omapcommoninclude_HEADERS = omap_drm.h + +libdrm_omapincludedir = ${includedir}/libdrm +libdrm_omapinclude_HEADERS = omap_drmif.h + +pkgconfigdir = @pkgconfigdir@ +pkgconfig_DATA = libdrm_omap.pc diff --git a/omap/libdrm_omap.pc.in b/omap/libdrm_omap.pc.in new file mode 100644 index 0000000..024533b --- /dev/null +++ b/omap/libdrm_omap.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libdrm_omap +Description: Userspace interface to omap kernel DRM services +Version: 0.6 +Libs: -L${libdir} -ldrm_omap +Cflags: -I${includedir} -I${includedir}/libdrm -I${includedir}/omap +Requires.private: libdrm diff --git a/omap/omap_drm.c b/omap/omap_drm.c new file mode 100644 index 0000000..336da11 --- /dev/null +++ b/omap/omap_drm.c @@ -0,0 +1,331 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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: + * Rob Clark + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include + +#include "omap_drm.h" +#include "omap_drmif.h" + +#define __round_mask(x, y) ((__typeof__(x))((y)-1)) +#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) +#define PAGE_SIZE 4096 + +struct omap_device { + int fd; +}; + +/* a GEM buffer object allocated from the DRM device */ +struct omap_bo { + struct omap_device *dev; + void *map; /* userspace mmap'ing (if there is one) */ + uint32_t size; + uint32_t handle; + uint32_t name; /* flink global handle (DRI2 name) */ + uint64_t offset; /* offset to mmap() */ + int fd; /* dmabuf handle */ +}; + +struct omap_device * omap_device_new(int fd) +{ + struct omap_device *dev = calloc(sizeof(*dev), 1); + if (!dev) + return NULL; + dev->fd = fd; + return dev; +} + +void omap_device_del(struct omap_device *dev) +{ + free(dev); +} + +int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value) +{ + struct drm_omap_param req = { + .param = param, + }; + int ret; + + ret = drmCommandWriteRead(dev->fd, DRM_OMAP_GET_PARAM, &req, sizeof(req)); + if (ret) { + return ret; + } + + *value = req.value; + + return 0; +} + +int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value) +{ + struct drm_omap_param req = { + .param = param, + .value = value, + }; + return drmCommandWrite(dev->fd, DRM_OMAP_SET_PARAM, &req, sizeof(req)); +} + +/* allocate a new buffer object */ +static struct omap_bo * omap_bo_new_impl(struct omap_device *dev, + union omap_gem_size size, uint32_t flags) +{ + struct omap_bo *bo = NULL; + struct drm_omap_gem_new req = { + .size = size, + .flags = flags, + }; + + if (size.bytes == 0) { + goto fail; + } + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + goto fail; + } + + bo->dev = dev; + + if (flags & OMAP_BO_TILED) { + bo->size = round_up(size.tiled.width, PAGE_SIZE) * size.tiled.height; + } else { + bo->size = size.bytes; + } + + if (drmCommandWriteRead(dev->fd, DRM_OMAP_GEM_NEW, &req, sizeof(req))) { + goto fail; + } + + bo->handle = req.handle; + + return bo; + +fail: + free(bo); + return NULL; +} + + +/* allocate a new (un-tiled) buffer object */ +struct omap_bo * omap_bo_new(struct omap_device *dev, + uint32_t size, uint32_t flags) +{ + union omap_gem_size gsize = { + .bytes = size, + }; + if (flags & OMAP_BO_TILED) { + return NULL; + } + return omap_bo_new_impl(dev, gsize, flags); +} + +/* allocate a new buffer object */ +struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, + uint32_t width, uint32_t height, uint32_t flags) +{ + union omap_gem_size gsize = { + .tiled = { + .width = width, + .height = height, + }, + }; + if (!(flags & OMAP_BO_TILED)) { + return NULL; + } + return omap_bo_new_impl(dev, gsize, flags); +} + +/* get buffer info */ +static int get_buffer_info(struct omap_bo *bo) +{ + struct drm_omap_gem_info req = { + .handle = bo->handle, + }; + int ret = drmCommandWriteRead(bo->dev->fd, DRM_OMAP_GEM_INFO, + &req, sizeof(req)); + if (ret) { + return ret; + } + + /* really all we need for now is mmap offset */ + bo->offset = req.offset; + bo->size = req.size; + + return 0; +} + +/* import a buffer object from DRI2 name */ +struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name) +{ + struct omap_bo *bo; + struct drm_gem_open req = { + .name = name, + }; + + bo = calloc(sizeof(*bo), 1); + if (!bo) { + goto fail; + } + + if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { + goto fail; + } + + bo->dev = dev; + bo->name = name; + bo->handle = req.handle; + + return bo; + +fail: + free(bo); + return NULL; +} + +/* destroy a buffer object */ +void omap_bo_del(struct omap_bo *bo) +{ + if (!bo) { + return; + } + + if (bo->map) { + munmap(bo->map, bo->size); + } + + if (bo->handle) { + struct drm_gem_close req = { + .handle = bo->handle, + }; + + drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); + } + + free(bo); +} + +/* get the global flink/DRI2 buffer name */ +int omap_bo_get_name(struct omap_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; + } + + bo->name = req.name; + } + + *name = bo->name; + + return 0; +} + +uint32_t omap_bo_handle(struct omap_bo *bo) +{ + return bo->handle; +} + +int omap_bo_dmabuf(struct omap_bo *bo) +{ + if (!bo->fd) { + struct drm_prime_handle req = { + .handle = bo->handle, + .flags = DRM_CLOEXEC, + }; + int ret; + + ret = drmIoctl(bo->dev->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &req); + if (ret) { + return ret; + } + + bo->fd = req.fd; + } + return bo->fd; +} + +uint32_t omap_bo_size(struct omap_bo *bo) +{ + if (!bo->size) { + get_buffer_info(bo); + } + return bo->size; +} + +void * omap_bo_map(struct omap_bo *bo) +{ + if (!bo->map) { + if (!bo->offset) { + get_buffer_info(bo); + } + + bo->map = mmap(0, bo->size, PROT_READ | PROT_WRITE, + MAP_SHARED, bo->dev->fd, bo->offset); + if (bo->map == MAP_FAILED) { + bo->map = NULL; + } + } + return bo->map; +} + +int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op) +{ + struct drm_omap_gem_cpu_prep req = { + .handle = bo->handle, + .op = op, + }; + return drmCommandWrite(bo->dev->fd, + DRM_OMAP_GEM_CPU_PREP, &req, sizeof(req)); +} + +int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op) +{ + struct drm_omap_gem_cpu_fini req = { + .handle = bo->handle, + .op = op, + .nregions = 0, + }; + return drmCommandWrite(bo->dev->fd, + DRM_OMAP_GEM_CPU_FINI, &req, sizeof(req)); +} diff --git a/omap/omap_drm.h b/omap/omap_drm.h new file mode 100644 index 0000000..f677cd8 --- /dev/null +++ b/omap/omap_drm.h @@ -0,0 +1,134 @@ +/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ + +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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: + * Rob Clark + */ + +#ifndef __OMAP_DRM_H__ +#define __OMAP_DRM_H__ + +#include "drm.h" + +/* Please note that modifications to all structs defined here are + * subject to backwards-compatibility constraints. + */ + +#define OMAP_PARAM_CHIPSET_ID 1 /* ie. 0x3430, 0x4430, etc */ + +struct drm_omap_param { + uint64_t param; /* in */ + uint64_t value; /* in (set_param), out (get_param) */ +}; + +struct drm_omap_get_base { + char plugin_name[64]; /* in */ + uint32_t ioctl_base; /* out */ + uint32_t __pad; +}; + +#define OMAP_BO_SCANOUT 0x00000001 /* scanout capable (phys contiguous) */ +#define OMAP_BO_CACHE_MASK 0x00000006 /* cache type mask, see cache modes */ +#define OMAP_BO_TILED_MASK 0x00000f00 /* tiled mapping mask, see tiled modes */ + +/* cache modes */ +#define OMAP_BO_CACHED 0x00000000 /* default */ +#define OMAP_BO_WC 0x00000002 /* write-combine */ +#define OMAP_BO_UNCACHED 0x00000004 /* strongly-ordered (uncached) */ + +/* tiled modes */ +#define OMAP_BO_TILED_8 0x00000100 +#define OMAP_BO_TILED_16 0x00000200 +#define OMAP_BO_TILED_32 0x00000300 +#define OMAP_BO_TILED (OMAP_BO_TILED_8 | OMAP_BO_TILED_16 | OMAP_BO_TILED_32) + +union omap_gem_size { + uint32_t bytes; /* (for non-tiled formats) */ + struct { + uint16_t width; + uint16_t height; + } tiled; /* (for tiled formats) */ +}; + +struct drm_omap_gem_new { + union omap_gem_size size; /* in */ + uint32_t flags; /* in */ + uint32_t handle; /* out */ + uint32_t __pad; +}; + +/* mask of operations: */ +enum omap_gem_op { + OMAP_GEM_READ = 0x01, + OMAP_GEM_WRITE = 0x02, +}; + +struct drm_omap_gem_cpu_prep { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ +}; + +struct drm_omap_gem_cpu_fini { + uint32_t handle; /* buffer handle (in) */ + uint32_t op; /* mask of omap_gem_op (in) */ + /* TODO maybe here we pass down info about what regions are touched + * by sw so we can be clever about cache ops? For now a placeholder, + * set to zero and we just do full buffer flush.. + */ + uint32_t nregions; + uint32_t __pad; +}; + +struct drm_omap_gem_info { + uint32_t handle; /* buffer handle (in) */ + uint32_t pad; + uint64_t offset; /* mmap offset (out) */ + /* note: in case of tiled buffers, the user virtual size can be + * different from the physical size (ie. how many pages are needed + * to back the object) which is returned in DRM_IOCTL_GEM_OPEN.. + * This size here is the one that should be used if you want to + * mmap() the buffer: + */ + uint32_t size; /* virtual size for mmap'ing (out) */ + uint32_t __pad; +}; + +#define DRM_OMAP_GET_PARAM 0x00 +#define DRM_OMAP_SET_PARAM 0x01 +#define DRM_OMAP_GET_BASE 0x02 +#define DRM_OMAP_GEM_NEW 0x03 +#define DRM_OMAP_GEM_CPU_PREP 0x04 +#define DRM_OMAP_GEM_CPU_FINI 0x05 +#define DRM_OMAP_GEM_INFO 0x06 +#define DRM_OMAP_NUM_IOCTLS 0x07 + +#define DRM_IOCTL_OMAP_GET_PARAM DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_PARAM, struct drm_omap_param) +#define DRM_IOCTL_OMAP_SET_PARAM DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_SET_PARAM, struct drm_omap_param) +#define DRM_IOCTL_OMAP_GET_BASE DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GET_BASE, struct drm_omap_get_base) +#define DRM_IOCTL_OMAP_GEM_NEW DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_NEW, struct drm_omap_gem_new) +#define DRM_IOCTL_OMAP_GEM_CPU_PREP DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_PREP, struct drm_omap_gem_cpu_prep) +#define DRM_IOCTL_OMAP_GEM_CPU_FINI DRM_IOW (DRM_COMMAND_BASE + DRM_OMAP_GEM_CPU_FINI, struct drm_omap_gem_cpu_fini) +#define DRM_IOCTL_OMAP_GEM_INFO DRM_IOWR(DRM_COMMAND_BASE + DRM_OMAP_GEM_INFO, struct drm_omap_gem_info) + +#endif /* __OMAP_DRM_H__ */ diff --git a/omap/omap_drmif.h b/omap/omap_drmif.h new file mode 100644 index 0000000..1e03eee --- /dev/null +++ b/omap/omap_drmif.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Texas Instruments, Inc + * + * 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: + * Rob Clark + */ + +#ifndef OMAP_DRMIF_H_ +#define OMAP_DRMIF_H_ + +#include +#include +#include + +struct omap_bo; +struct omap_device; + +/* device related functions: + */ + +struct omap_device * omap_device_new(int fd); +void omap_device_del(struct omap_device *dev); +int omap_get_param(struct omap_device *dev, uint64_t param, uint64_t *value); +int omap_set_param(struct omap_device *dev, uint64_t param, uint64_t value); + +/* buffer-object related functions: + */ + +struct omap_bo * omap_bo_new(struct omap_device *dev, + uint32_t size, uint32_t flags); +struct omap_bo * omap_bo_new_tiled(struct omap_device *dev, + uint32_t width, uint32_t height, uint32_t flags); +struct omap_bo * omap_bo_from_name(struct omap_device *dev, uint32_t name); +void omap_bo_del(struct omap_bo *bo); +int omap_bo_get_name(struct omap_bo *bo, uint32_t *name); +uint32_t omap_bo_handle(struct omap_bo *bo); +int omap_bo_dmabuf(struct omap_bo *bo); +uint32_t omap_bo_size(struct omap_bo *bo); +void * omap_bo_map(struct omap_bo *bo); +int omap_bo_cpu_prep(struct omap_bo *bo, enum omap_gem_op op); +int omap_bo_cpu_fini(struct omap_bo *bo, enum omap_gem_op op); + +#endif /* OMAP_DRMIF_H_ */ diff --git a/packaging/libdrm.spec b/packaging/libdrm.spec index d9ed836..939da25 100644 --- a/packaging/libdrm.spec +++ b/packaging/libdrm.spec @@ -1,7 +1,7 @@ #sbs-git:slp/pkgs/xorg/lib/libdrm libdrm 2.4.27 4df9ab272d6eac089f89ecd9302d39263541a794 Name: libdrm -Version: 2.4.27 -Release: 4 +Version: 2.4.35 +Release: 1 License: MIT Summary: Userspace interface to kernel DRM services Group: System/Libraries @@ -9,7 +9,6 @@ Source0: %{name}-%{version}.tar.gz BuildRequires: kernel-headers BuildRequires: pkgconfig(xorg-macros) BuildRequires: pkgconfig(pthread-stubs) -BuildRequires: pkgconfig(pciaccess) %description Description: %{summary} @@ -52,8 +51,8 @@ Userspace interface to kernel DRM buffer management %build %reconfigure --prefix=%{_prefix} --mandir=%{_prefix}/share/man --infodir=%{_prefix}/share/info \ - --enable-static=yes --enable-udev --enable-libkms \ - --disable-nouveau-experimental-api --disable-radeon --disable-intel + --enable-static=yes --enable-udev --enable-libkms --enable-exynos-experimental-api \ + --disable-nouveau --disable-radeon --disable-intel make %{?_smp_mflags} @@ -77,13 +76,16 @@ make %{?_smp_mflags} %files devel %dir %{_includedir}/libdrm %{_includedir}/* +%{_includedir}/exynos/* %{_libdir}/libdrm.so %{_libdir}/libdrm_slp.so +%{_libdir}/libdrm_exynos.so %{_libdir}/libkms.so %{_libdir}/pkgconfig/* %files -n libdrm2 %{_libdir}/libdrm.so.* +%{_libdir}/libdrm_exynos.so.* %files slp1 %{_libdir}/libdrm_slp*.so.* diff --git a/radeon/Makefile.am b/radeon/Makefile.am index dc94b5f..37be8cc 100644 --- a/radeon/Makefile.am +++ b/radeon/Makefile.am @@ -40,6 +40,7 @@ libdrm_radeon_la_SOURCES = \ radeon_cs_space.c \ radeon_bo.c \ radeon_cs.c \ + radeon_surface.c \ bof.c \ bof.h @@ -47,10 +48,12 @@ libdrm_radeonincludedir = ${includedir}/libdrm libdrm_radeoninclude_HEADERS = \ radeon_bo.h \ radeon_cs.h \ + radeon_surface.h \ radeon_bo_gem.h \ radeon_cs_gem.h \ radeon_bo_int.h \ - radeon_cs_int.h + radeon_cs_int.h \ + r600_pci_ids.h pkgconfigdir = @pkgconfigdir@ pkgconfig_DATA = libdrm_radeon.pc diff --git a/radeon/r600_pci_ids.h b/radeon/r600_pci_ids.h new file mode 100644 index 0000000..989ec00 --- /dev/null +++ b/radeon/r600_pci_ids.h @@ -0,0 +1,353 @@ +CHIPSET(0x9400, R600_9400, R600) +CHIPSET(0x9401, R600_9401, R600) +CHIPSET(0x9402, R600_9402, R600) +CHIPSET(0x9403, R600_9403, R600) +CHIPSET(0x9405, R600_9405, R600) +CHIPSET(0x940A, R600_940A, R600) +CHIPSET(0x940B, R600_940B, R600) +CHIPSET(0x940F, R600_940F, R600) + +CHIPSET(0x94C0, RV610_94C0, RV610) +CHIPSET(0x94C1, RV610_94C1, RV610) +CHIPSET(0x94C3, RV610_94C3, RV610) +CHIPSET(0x94C4, RV610_94C4, RV610) +CHIPSET(0x94C5, RV610_94C5, RV610) +CHIPSET(0x94C6, RV610_94C6, RV610) +CHIPSET(0x94C7, RV610_94C7, RV610) +CHIPSET(0x94C8, RV610_94C8, RV610) +CHIPSET(0x94C9, RV610_94C9, RV610) +CHIPSET(0x94CB, RV610_94CB, RV610) +CHIPSET(0x94CC, RV610_94CC, RV610) +CHIPSET(0x94CD, RV610_94CD, RV610) + +CHIPSET(0x9580, RV630_9580, RV630) +CHIPSET(0x9581, RV630_9581, RV630) +CHIPSET(0x9583, RV630_9583, RV630) +CHIPSET(0x9586, RV630_9586, RV630) +CHIPSET(0x9587, RV630_9587, RV630) +CHIPSET(0x9588, RV630_9588, RV630) +CHIPSET(0x9589, RV630_9589, RV630) +CHIPSET(0x958A, RV630_958A, RV630) +CHIPSET(0x958B, RV630_958B, RV630) +CHIPSET(0x958C, RV630_958C, RV630) +CHIPSET(0x958D, RV630_958D, RV630) +CHIPSET(0x958E, RV630_958E, RV630) +CHIPSET(0x958F, RV630_958F, RV630) + +CHIPSET(0x9500, RV670_9500, RV670) +CHIPSET(0x9501, RV670_9501, RV670) +CHIPSET(0x9504, RV670_9504, RV670) +CHIPSET(0x9505, RV670_9505, RV670) +CHIPSET(0x9506, RV670_9506, RV670) +CHIPSET(0x9507, RV670_9507, RV670) +CHIPSET(0x9508, RV670_9508, RV670) +CHIPSET(0x9509, RV670_9509, RV670) +CHIPSET(0x950F, RV670_950F, RV670) +CHIPSET(0x9511, RV670_9511, RV670) +CHIPSET(0x9515, RV670_9515, RV670) +CHIPSET(0x9517, RV670_9517, RV670) +CHIPSET(0x9519, RV670_9519, RV670) + +CHIPSET(0x95C0, RV620_95C0, RV620) +CHIPSET(0x95C2, RV620_95C2, RV620) +CHIPSET(0x95C4, RV620_95C4, RV620) +CHIPSET(0x95C5, RV620_95C5, RV620) +CHIPSET(0x95C6, RV620_95C6, RV620) +CHIPSET(0x95C7, RV620_95C7, RV620) +CHIPSET(0x95C9, RV620_95C9, RV620) +CHIPSET(0x95CC, RV620_95CC, RV620) +CHIPSET(0x95CD, RV620_95CD, RV620) +CHIPSET(0x95CE, RV620_95CE, RV620) +CHIPSET(0x95CF, RV620_95CF, RV620) + +CHIPSET(0x9590, RV635_9590, RV635) +CHIPSET(0x9591, RV635_9591, RV635) +CHIPSET(0x9593, RV635_9593, RV635) +CHIPSET(0x9595, RV635_9595, RV635) +CHIPSET(0x9596, RV635_9596, RV635) +CHIPSET(0x9597, RV635_9597, RV635) +CHIPSET(0x9598, RV635_9598, RV635) +CHIPSET(0x9599, RV635_9599, RV635) +CHIPSET(0x959B, RV635_959B, RV635) + +CHIPSET(0x9610, RS780_9610, RS780) +CHIPSET(0x9611, RS780_9611, RS780) +CHIPSET(0x9612, RS780_9612, RS780) +CHIPSET(0x9613, RS780_9613, RS780) +CHIPSET(0x9614, RS780_9614, RS780) +CHIPSET(0x9615, RS780_9615, RS780) +CHIPSET(0x9616, RS780_9616, RS780) + +CHIPSET(0x9710, RS880_9710, RS880) +CHIPSET(0x9711, RS880_9711, RS880) +CHIPSET(0x9712, RS880_9712, RS880) +CHIPSET(0x9713, RS880_9713, RS880) +CHIPSET(0x9714, RS880_9714, RS880) +CHIPSET(0x9715, RS880_9715, RS880) + +CHIPSET(0x9440, RV770_9440, RV770) +CHIPSET(0x9441, RV770_9441, RV770) +CHIPSET(0x9442, RV770_9442, RV770) +CHIPSET(0x9443, RV770_9443, RV770) +CHIPSET(0x9444, RV770_9444, RV770) +CHIPSET(0x9446, RV770_9446, RV770) +CHIPSET(0x944A, RV770_944A, RV770) +CHIPSET(0x944B, RV770_944B, RV770) +CHIPSET(0x944C, RV770_944C, RV770) +CHIPSET(0x944E, RV770_944E, RV770) +CHIPSET(0x9450, RV770_9450, RV770) +CHIPSET(0x9452, RV770_9452, RV770) +CHIPSET(0x9456, RV770_9456, RV770) +CHIPSET(0x945A, RV770_945A, RV770) +CHIPSET(0x945B, RV770_945B, RV770) +CHIPSET(0x945E, RV770_945E, RV770) +CHIPSET(0x9460, RV790_9460, RV770) +CHIPSET(0x9462, RV790_9462, RV770) +CHIPSET(0x946A, RV770_946A, RV770) +CHIPSET(0x946B, RV770_946B, RV770) +CHIPSET(0x947A, RV770_947A, RV770) +CHIPSET(0x947B, RV770_947B, RV770) + +CHIPSET(0x9480, RV730_9480, RV730) +CHIPSET(0x9487, RV730_9487, RV730) +CHIPSET(0x9488, RV730_9488, RV730) +CHIPSET(0x9489, RV730_9489, RV730) +CHIPSET(0x948A, RV730_948A, RV730) +CHIPSET(0x948F, RV730_948F, RV730) +CHIPSET(0x9490, RV730_9490, RV730) +CHIPSET(0x9491, RV730_9491, RV730) +CHIPSET(0x9495, RV730_9495, RV730) +CHIPSET(0x9498, RV730_9498, RV730) +CHIPSET(0x949C, RV730_949C, RV730) +CHIPSET(0x949E, RV730_949E, RV730) +CHIPSET(0x949F, RV730_949F, RV730) + +CHIPSET(0x9540, RV710_9540, RV710) +CHIPSET(0x9541, RV710_9541, RV710) +CHIPSET(0x9542, RV710_9542, RV710) +CHIPSET(0x954E, RV710_954E, RV710) +CHIPSET(0x954F, RV710_954F, RV710) +CHIPSET(0x9552, RV710_9552, RV710) +CHIPSET(0x9553, RV710_9553, RV710) +CHIPSET(0x9555, RV710_9555, RV710) +CHIPSET(0x9557, RV710_9557, RV710) +CHIPSET(0x955F, RV710_955F, RV710) + +CHIPSET(0x94A0, RV740_94A0, RV740) +CHIPSET(0x94A1, RV740_94A1, RV740) +CHIPSET(0x94A3, RV740_94A3, RV740) +CHIPSET(0x94B1, RV740_94B1, RV740) +CHIPSET(0x94B3, RV740_94B3, RV740) +CHIPSET(0x94B4, RV740_94B4, RV740) +CHIPSET(0x94B5, RV740_94B5, RV740) +CHIPSET(0x94B9, RV740_94B9, RV740) + +CHIPSET(0x68E0, CEDAR_68E0, CEDAR) +CHIPSET(0x68E1, CEDAR_68E1, CEDAR) +CHIPSET(0x68E4, CEDAR_68E4, CEDAR) +CHIPSET(0x68E5, CEDAR_68E5, CEDAR) +CHIPSET(0x68E8, CEDAR_68E8, CEDAR) +CHIPSET(0x68E9, CEDAR_68E9, CEDAR) +CHIPSET(0x68F1, CEDAR_68F1, CEDAR) +CHIPSET(0x68F2, CEDAR_68F2, CEDAR) +CHIPSET(0x68F8, CEDAR_68F8, CEDAR) +CHIPSET(0x68F9, CEDAR_68F9, CEDAR) +CHIPSET(0x68FA, CEDAR_68FA, CEDAR) +CHIPSET(0x68FE, CEDAR_68FE, CEDAR) + +CHIPSET(0x68C0, REDWOOD_68C0, REDWOOD) +CHIPSET(0x68C1, REDWOOD_68C1, REDWOOD) +CHIPSET(0x68C8, REDWOOD_68C8, REDWOOD) +CHIPSET(0x68C9, REDWOOD_68C9, REDWOOD) +CHIPSET(0x68D8, REDWOOD_68D8, REDWOOD) +CHIPSET(0x68D9, REDWOOD_68D9, REDWOOD) +CHIPSET(0x68DA, REDWOOD_68DA, REDWOOD) +CHIPSET(0x68DE, REDWOOD_68DE, REDWOOD) + +CHIPSET(0x68A0, JUNIPER_68A0, JUNIPER) +CHIPSET(0x68A1, JUNIPER_68A1, JUNIPER) +CHIPSET(0x68A8, JUNIPER_68A8, JUNIPER) +CHIPSET(0x68A9, JUNIPER_68A9, JUNIPER) +CHIPSET(0x68B0, JUNIPER_68B0, JUNIPER) +CHIPSET(0x68B8, JUNIPER_68B8, JUNIPER) +CHIPSET(0x68B9, JUNIPER_68B9, JUNIPER) +CHIPSET(0x68BA, JUNIPER_68BA, JUNIPER) +CHIPSET(0x68BE, JUNIPER_68BE, JUNIPER) +CHIPSET(0x68BF, JUNIPER_68BF, JUNIPER) + +CHIPSET(0x6880, CYPRESS_6880, CYPRESS) +CHIPSET(0x6888, CYPRESS_6888, CYPRESS) +CHIPSET(0x6889, CYPRESS_6889, CYPRESS) +CHIPSET(0x688A, CYPRESS_688A, CYPRESS) +CHIPSET(0x6898, CYPRESS_6898, CYPRESS) +CHIPSET(0x6899, CYPRESS_6899, CYPRESS) +CHIPSET(0x689B, CYPRESS_689B, CYPRESS) +CHIPSET(0x689E, CYPRESS_689E, CYPRESS) + +CHIPSET(0x689C, HEMLOCK_689C, HEMLOCK) +CHIPSET(0x689D, HEMLOCK_689D, HEMLOCK) + +CHIPSET(0x9802, PALM_9802, PALM) +CHIPSET(0x9803, PALM_9803, PALM) +CHIPSET(0x9804, PALM_9804, PALM) +CHIPSET(0x9805, PALM_9805, PALM) +CHIPSET(0x9806, PALM_9806, PALM) +CHIPSET(0x9807, PALM_9807, PALM) +CHIPSET(0x9808, PALM_9808, PALM) +CHIPSET(0x9809, PALM_9809, PALM) +CHIPSET(0x980A, PALM_980A, PALM) + +CHIPSET(0x9640, SUMO_9640, SUMO) +CHIPSET(0x9641, SUMO_9641, SUMO) +CHIPSET(0x9642, SUMO2_9642, SUMO2) +CHIPSET(0x9643, SUMO2_9643, SUMO2) +CHIPSET(0x9644, SUMO2_9644, SUMO2) +CHIPSET(0x9645, SUMO2_9645, SUMO2) +CHIPSET(0x9647, SUMO_9647, SUMO) +CHIPSET(0x9648, SUMO_9648, SUMO) +CHIPSET(0x9649, SUMO_9649, SUMO) +CHIPSET(0x964a, SUMO_964A, SUMO) +CHIPSET(0x964b, SUMO_964B, SUMO) +CHIPSET(0x964c, SUMO_964C, SUMO) +CHIPSET(0x964e, SUMO_964E, SUMO) +CHIPSET(0x964f, SUMO_964F, SUMO) + +CHIPSET(0x6700, CAYMAN_6700, CAYMAN) +CHIPSET(0x6701, CAYMAN_6701, CAYMAN) +CHIPSET(0x6702, CAYMAN_6702, CAYMAN) +CHIPSET(0x6703, CAYMAN_6703, CAYMAN) +CHIPSET(0x6704, CAYMAN_6704, CAYMAN) +CHIPSET(0x6705, CAYMAN_6705, CAYMAN) +CHIPSET(0x6706, CAYMAN_6706, CAYMAN) +CHIPSET(0x6707, CAYMAN_6707, CAYMAN) +CHIPSET(0x6708, CAYMAN_6708, CAYMAN) +CHIPSET(0x6709, CAYMAN_6709, CAYMAN) +CHIPSET(0x6718, CAYMAN_6718, CAYMAN) +CHIPSET(0x6719, CAYMAN_6719, CAYMAN) +CHIPSET(0x671C, CAYMAN_671C, CAYMAN) +CHIPSET(0x671D, CAYMAN_671D, CAYMAN) +CHIPSET(0x671F, CAYMAN_671F, CAYMAN) + +CHIPSET(0x6720, BARTS_6720, BARTS) +CHIPSET(0x6721, BARTS_6721, BARTS) +CHIPSET(0x6722, BARTS_6722, BARTS) +CHIPSET(0x6723, BARTS_6723, BARTS) +CHIPSET(0x6724, BARTS_6724, BARTS) +CHIPSET(0x6725, BARTS_6725, BARTS) +CHIPSET(0x6726, BARTS_6726, BARTS) +CHIPSET(0x6727, BARTS_6727, BARTS) +CHIPSET(0x6728, BARTS_6728, BARTS) +CHIPSET(0x6729, BARTS_6729, BARTS) +CHIPSET(0x6738, BARTS_6738, BARTS) +CHIPSET(0x6739, BARTS_6739, BARTS) +CHIPSET(0x673E, BARTS_673E, BARTS) + +CHIPSET(0x6740, TURKS_6740, TURKS) +CHIPSET(0x6741, TURKS_6741, TURKS) +CHIPSET(0x6742, TURKS_6742, TURKS) +CHIPSET(0x6743, TURKS_6743, TURKS) +CHIPSET(0x6744, TURKS_6744, TURKS) +CHIPSET(0x6745, TURKS_6745, TURKS) +CHIPSET(0x6746, TURKS_6746, TURKS) +CHIPSET(0x6747, TURKS_6747, TURKS) +CHIPSET(0x6748, TURKS_6748, TURKS) +CHIPSET(0x6749, TURKS_6749, TURKS) +CHIPSET(0x674A, TURKS_674A, TURKS) +CHIPSET(0x6750, TURKS_6750, TURKS) +CHIPSET(0x6751, TURKS_6751, TURKS) +CHIPSET(0x6758, TURKS_6758, TURKS) +CHIPSET(0x6759, TURKS_6759, TURKS) +CHIPSET(0x675B, TURKS_675B, TURKS) +CHIPSET(0x675D, TURKS_675D, TURKS) +CHIPSET(0x675F, TURKS_675F, TURKS) +CHIPSET(0x6840, TURKS_6840, TURKS) +CHIPSET(0x6841, TURKS_6841, TURKS) +CHIPSET(0x6842, TURKS_6842, TURKS) +CHIPSET(0x6843, TURKS_6843, TURKS) +CHIPSET(0x6849, TURKS_6849, TURKS) +CHIPSET(0x6850, TURKS_6850, TURKS) +CHIPSET(0x6858, TURKS_6858, TURKS) +CHIPSET(0x6859, TURKS_6859, TURKS) + +CHIPSET(0x6760, CAICOS_6760, CAICOS) +CHIPSET(0x6761, CAICOS_6761, CAICOS) +CHIPSET(0x6762, CAICOS_6762, CAICOS) +CHIPSET(0x6763, CAICOS_6763, CAICOS) +CHIPSET(0x6764, CAICOS_6764, CAICOS) +CHIPSET(0x6765, CAICOS_6765, CAICOS) +CHIPSET(0x6766, CAICOS_6766, CAICOS) +CHIPSET(0x6767, CAICOS_6767, CAICOS) +CHIPSET(0x6768, CAICOS_6768, CAICOS) +CHIPSET(0x6770, CAICOS_6770, CAICOS) +CHIPSET(0x6771, CAICOS_6771, CAICOS) +CHIPSET(0x6772, CAICOS_6772, CAICOS) +CHIPSET(0x6778, CAICOS_6778, CAICOS) +CHIPSET(0x6779, CAICOS_6779, CAICOS) +CHIPSET(0x677B, CAICOS_677B, CAICOS) + +CHIPSET(0x9900, ARUBA_9900, ARUBA) +CHIPSET(0x9901, ARUBA_9901, ARUBA) +CHIPSET(0x9903, ARUBA_9903, ARUBA) +CHIPSET(0x9904, ARUBA_9904, ARUBA) +CHIPSET(0x9905, ARUBA_9905, ARUBA) +CHIPSET(0x9906, ARUBA_9906, ARUBA) +CHIPSET(0x9907, ARUBA_9907, ARUBA) +CHIPSET(0x9908, ARUBA_9908, ARUBA) +CHIPSET(0x9909, ARUBA_9909, ARUBA) +CHIPSET(0x990A, ARUBA_990A, ARUBA) +CHIPSET(0x990F, ARUBA_990F, ARUBA) +CHIPSET(0x9910, ARUBA_9910, ARUBA) +CHIPSET(0x9913, ARUBA_9913, ARUBA) +CHIPSET(0x9917, ARUBA_9917, ARUBA) +CHIPSET(0x9918, ARUBA_9918, ARUBA) +CHIPSET(0x9919, ARUBA_9919, ARUBA) +CHIPSET(0x9990, ARUBA_9990, ARUBA) +CHIPSET(0x9991, ARUBA_9991, ARUBA) +CHIPSET(0x9992, ARUBA_9992, ARUBA) +CHIPSET(0x9993, ARUBA_9993, ARUBA) +CHIPSET(0x9994, ARUBA_9994, ARUBA) +CHIPSET(0x99A0, ARUBA_99A0, ARUBA) +CHIPSET(0x99A2, ARUBA_99A2, ARUBA) +CHIPSET(0x99A4, ARUBA_99A4, ARUBA) + +CHIPSET(0x6780, TAHITI_6780, TAHITI) +CHIPSET(0x6784, TAHITI_6784, TAHITI) +CHIPSET(0x6788, TAHITI_6788, TAHITI) +CHIPSET(0x678A, TAHITI_678A, TAHITI) +CHIPSET(0x6790, TAHITI_6790, TAHITI) +CHIPSET(0x6798, TAHITI_6798, TAHITI) +CHIPSET(0x6799, TAHITI_6799, TAHITI) +CHIPSET(0x679A, TAHITI_679A, TAHITI) +CHIPSET(0x679E, TAHITI_679E, TAHITI) +CHIPSET(0x679F, TAHITI_679F, TAHITI) + +CHIPSET(0x6800, PITCAIRN_6800, PITCAIRN) +CHIPSET(0x6801, PITCAIRN_6801, PITCAIRN) +CHIPSET(0x6802, PITCAIRN_6802, PITCAIRN) +CHIPSET(0x6808, PITCAIRN_6808, PITCAIRN) +CHIPSET(0x6809, PITCAIRN_6809, PITCAIRN) +CHIPSET(0x6810, PITCAIRN_6810, PITCAIRN) +CHIPSET(0x6818, PITCAIRN_6818, PITCAIRN) +CHIPSET(0x6819, PITCAIRN_6819, PITCAIRN) +CHIPSET(0x684C, PITCAIRN_684C, PITCAIRN) + +CHIPSET(0x6820, VERDE_6820, VERDE) +CHIPSET(0x6821, VERDE_6821, VERDE) +CHIPSET(0x6823, VERDE_6823, VERDE) +CHIPSET(0x6824, VERDE_6824, VERDE) +CHIPSET(0x6825, VERDE_6825, VERDE) +CHIPSET(0x6826, VERDE_6826, VERDE) +CHIPSET(0x6827, VERDE_6827, VERDE) +CHIPSET(0x6828, VERDE_6828, VERDE) +CHIPSET(0x6829, VERDE_6829, VERDE) +CHIPSET(0x682B, VERDE_682B, VERDE) +CHIPSET(0x682D, VERDE_682D, VERDE) +CHIPSET(0x682F, VERDE_682F, VERDE) +CHIPSET(0x6830, VERDE_6830, VERDE) +CHIPSET(0x6831, VERDE_6831, VERDE) +CHIPSET(0x6837, VERDE_6837, VERDE) +CHIPSET(0x6838, VERDE_6838, VERDE) +CHIPSET(0x6839, VERDE_6839, VERDE) +CHIPSET(0x683B, VERDE_683B, VERDE) +CHIPSET(0x683D, VERDE_683D, VERDE) +CHIPSET(0x683F, VERDE_683F, VERDE) diff --git a/radeon/radeon_cs_space.c b/radeon/radeon_cs_space.c index 208e1bb..be047a7 100644 --- a/radeon/radeon_cs_space.c +++ b/radeon/radeon_cs_space.c @@ -65,13 +65,16 @@ static inline int radeon_cs_setup_bo(struct radeon_cs_space_check *sc, struct ra } if (bo->space_accounted == 0) { - if (write_domain == RADEON_GEM_DOMAIN_VRAM) - sizes->op_vram_write += bo->size; - else if (write_domain == RADEON_GEM_DOMAIN_GTT) - sizes->op_gart_write += bo->size; - else + if (write_domain) { + if (write_domain == RADEON_GEM_DOMAIN_VRAM) + sizes->op_vram_write += bo->size; + else if (write_domain == RADEON_GEM_DOMAIN_GTT) + sizes->op_gart_write += bo->size; + sc->new_accounted = write_domain; + } else { sizes->op_read += bo->size; - sc->new_accounted = (read_domains << 16) | write_domain; + sc->new_accounted = read_domains << 16; + } } else { uint16_t old_read, old_write; diff --git a/radeon/radeon_surface.c b/radeon/radeon_surface.c new file mode 100644 index 0000000..adf209d --- /dev/null +++ b/radeon/radeon_surface.c @@ -0,0 +1,1025 @@ +/* + * Copyright © 2011 Red Hat 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: + * Jérôme Glisse + */ +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "xf86drm.h" +#include "radeon_drm.h" +#include "radeon_surface.h" + +#define ALIGN(value, alignment) (((value) + alignment - 1) & ~(alignment - 1)) +#define MAX2(A, B) ((A) > (B) ? (A) : (B)) +#define MIN2(A, B) ((A) < (B) ? (A) : (B)) + +/* keep this private */ +enum radeon_family { + CHIP_UNKNOWN, + CHIP_R600, + CHIP_RV610, + CHIP_RV630, + CHIP_RV670, + CHIP_RV620, + CHIP_RV635, + CHIP_RS780, + CHIP_RS880, + CHIP_RV770, + CHIP_RV730, + CHIP_RV710, + CHIP_RV740, + CHIP_CEDAR, + CHIP_REDWOOD, + CHIP_JUNIPER, + CHIP_CYPRESS, + CHIP_HEMLOCK, + CHIP_PALM, + CHIP_SUMO, + CHIP_SUMO2, + CHIP_BARTS, + CHIP_TURKS, + CHIP_CAICOS, + CHIP_CAYMAN, + CHIP_ARUBA, + CHIP_TAHITI, + CHIP_PITCAIRN, + CHIP_VERDE, + CHIP_LAST, +}; + +typedef int (*hw_init_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +typedef int (*hw_best_surface_t)(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +struct radeon_hw_info { + /* apply to r6, eg */ + uint32_t group_bytes; + uint32_t num_banks; + uint32_t num_pipes; + /* apply to eg */ + uint32_t row_size; + unsigned allow_2d; +}; + +struct radeon_surface_manager { + int fd; + uint32_t device_id; + struct radeon_hw_info hw_info; + unsigned family; + hw_init_surface_t surface_init; + hw_best_surface_t surface_best; +}; + +/* helper */ +static int radeon_get_value(int fd, unsigned req, uint32_t *value) +{ + struct drm_radeon_info info = {}; + int r; + + *value = 0; + info.request = req; + info.value = (uintptr_t)value; + r = drmCommandWriteRead(fd, DRM_RADEON_INFO, &info, + sizeof(struct drm_radeon_info)); + return r; +} + +static int radeon_get_family(struct radeon_surface_manager *surf_man) +{ + switch (surf_man->device_id) { +#define CHIPSET(pci_id, name, fam) case pci_id: surf_man->family = CHIP_##fam; break; +#include "r600_pci_ids.h" +#undef CHIPSET + default: + return -EINVAL; + } + return 0; +} + +static unsigned next_power_of_two(unsigned x) +{ + if (x <= 1) + return 1; + + return (1 << ((sizeof(unsigned) * 8) - __builtin_clz(x - 1))); +} + +static unsigned mip_minify(unsigned size, unsigned level) +{ + unsigned val; + + val = MAX2(1, size >> level); + if (level > 0) + val = next_power_of_two(val); + return val; +} + +static void surf_minify(struct radeon_surface *surf, + unsigned level, + uint32_t xalign, uint32_t yalign, uint32_t zalign, + unsigned offset) +{ + surf->level[level].npix_x = mip_minify(surf->npix_x, level); + surf->level[level].npix_y = mip_minify(surf->npix_y, level); + surf->level[level].npix_z = mip_minify(surf->npix_z, level); + surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w; + surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h; + surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d; + if (surf->level[level].mode == RADEON_SURF_MODE_2D) { + if (surf->level[level].nblk_x < xalign || surf->level[level].nblk_y < yalign) { + surf->level[level].mode = RADEON_SURF_MODE_1D; + return; + } + } + surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, xalign); + surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, yalign); + surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, zalign); + + surf->level[level].offset = offset; + surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe; + surf->level[level].slice_size = surf->level[level].pitch_bytes * surf->level[level].nblk_y; + + surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size; +} + +/* =========================================================================== + * r600/r700 family + */ +static int r6_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 14) { + surf_man->hw_info.allow_2d = 1; + } + + switch ((tiling_config & 0xe) >> 1) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0x30) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xc0) >> 6) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static int r6_surface_init_linear(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + /* the 32 alignment is for scanout, cb or db but to allow texture to be + * easily bound as such we force this alignment to all surface + */ + xalign = MAX2(1, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_linear_aligned(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign; + unsigned i; + + /* compute alignment */ + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + xalign = MAX2(64, surf_man->hw_info.group_bytes / surf->bpe); + yalign = 1; + zalign = 1; + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_LINEAR_ALIGNED; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + zalign = 1; + xalign = (surf_man->hw_info.group_bytes * surf_man->hw_info.num_banks) / + (tilew * surf->bpe * surf->nsamples); + xalign = MAX2(tilew * surf_man->hw_info.num_banks, xalign); + yalign = tilew * surf_man->hw_info.num_pipes; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + if (!start_level) { + surf->bo_alignment = + MAX2(surf_man->hw_info.num_pipes * + surf_man->hw_info.num_banks * + surf->bpe * 64, + xalign * yalign * surf->nsamples * surf->bpe); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_2D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + if (surf->level[i].mode == RADEON_SURF_MODE_1D) { + return r6_surface_init_1d(surf_man, surf, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + return 0; +} + +static int r6_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* force 1d on kernel that can't do 2d */ + if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) { + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + /* check surface dimension */ + if (surf->npix_x > 8192 || surf->npix_y > 8192 || surf->npix_z > 8192) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 14) { + return -EINVAL; + } + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = r6_surface_init_1d(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_2D: + r = r6_surface_init_2d(surf_man, surf, 0, 0); + break; + default: + return -EINVAL; + } + return r; +} + +static int r6_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + /* no value to optimize for r6xx/r7xx */ + return 0; +} + + +/* =========================================================================== + * evergreen family + */ +static int eg_init_hw_info(struct radeon_surface_manager *surf_man) +{ + uint32_t tiling_config; + drmVersionPtr version; + int r; + + r = radeon_get_value(surf_man->fd, RADEON_INFO_TILING_CONFIG, + &tiling_config); + if (r) { + return r; + } + + surf_man->hw_info.allow_2d = 0; + version = drmGetVersion(surf_man->fd); + if (version && version->version_minor >= 14) { + surf_man->hw_info.allow_2d = 1; + } + + switch (tiling_config & 0xf) { + case 0: + surf_man->hw_info.num_pipes = 1; + break; + case 1: + surf_man->hw_info.num_pipes = 2; + break; + case 2: + surf_man->hw_info.num_pipes = 4; + break; + case 3: + surf_man->hw_info.num_pipes = 8; + break; + default: + surf_man->hw_info.num_pipes = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf0) >> 4) { + case 0: + surf_man->hw_info.num_banks = 4; + break; + case 1: + surf_man->hw_info.num_banks = 8; + break; + case 2: + surf_man->hw_info.num_banks = 16; + break; + default: + surf_man->hw_info.num_banks = 8; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf00) >> 8) { + case 0: + surf_man->hw_info.group_bytes = 256; + break; + case 1: + surf_man->hw_info.group_bytes = 512; + break; + default: + surf_man->hw_info.group_bytes = 256; + surf_man->hw_info.allow_2d = 0; + break; + } + + switch ((tiling_config & 0xf000) >> 12) { + case 0: + surf_man->hw_info.row_size = 1024; + break; + case 1: + surf_man->hw_info.row_size = 2048; + break; + case 2: + surf_man->hw_info.row_size = 4096; + break; + default: + surf_man->hw_info.row_size = 4096; + surf_man->hw_info.allow_2d = 0; + break; + } + return 0; +} + +static void eg_surf_minify(struct radeon_surface *surf, + unsigned level, + unsigned slice_pt, + unsigned mtilew, + unsigned mtileh, + unsigned mtileb, + unsigned offset) +{ + unsigned mtile_pr, mtile_ps; + + surf->level[level].npix_x = mip_minify(surf->npix_x, level); + surf->level[level].npix_y = mip_minify(surf->npix_y, level); + surf->level[level].npix_z = mip_minify(surf->npix_z, level); + surf->level[level].nblk_x = (surf->level[level].npix_x + surf->blk_w - 1) / surf->blk_w; + surf->level[level].nblk_y = (surf->level[level].npix_y + surf->blk_h - 1) / surf->blk_h; + surf->level[level].nblk_z = (surf->level[level].npix_z + surf->blk_d - 1) / surf->blk_d; + if (surf->level[level].mode == RADEON_SURF_MODE_2D) { + if (surf->level[level].nblk_x < mtilew || surf->level[level].nblk_y < mtileh) { + surf->level[level].mode = RADEON_SURF_MODE_1D; + return; + } + } + surf->level[level].nblk_x = ALIGN(surf->level[level].nblk_x, mtilew); + surf->level[level].nblk_y = ALIGN(surf->level[level].nblk_y, mtileh); + surf->level[level].nblk_z = ALIGN(surf->level[level].nblk_z, 1); + + /* macro tile per row */ + mtile_pr = surf->level[level].nblk_x / mtilew; + /* macro tile per slice */ + mtile_ps = (mtile_pr * surf->level[level].nblk_y) / mtileh; + + surf->level[level].offset = offset; + surf->level[level].pitch_bytes = surf->level[level].nblk_x * surf->bpe * slice_pt; + surf->level[level].slice_size = mtile_ps * mtileb * slice_pt; + + surf->bo_size = offset + surf->level[level].slice_size * surf->level[level].nblk_z * surf->array_size; +} + +static int eg_surface_init_1d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + uint32_t xalign, yalign, zalign, tilew; + unsigned i; + + /* compute alignment */ + tilew = 8; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->bpe * surf->nsamples); + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = 0; + surf->stencil_tile_split = 0; + xalign = surf_man->hw_info.group_bytes / (tilew * surf->nsamples); + } + xalign = MAX2(tilew, xalign); + yalign = tilew; + zalign = 1; + if (surf->flags & RADEON_SURF_SCANOUT) { + xalign = MAX2((surf->bpe == 1) ? 64 : 32, xalign); + } + if (!start_level) { + surf->bo_alignment = MAX2(256, surf_man->hw_info.group_bytes); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_1D; + surf_minify(surf, i, xalign, yalign, zalign, offset); + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment); + surf->bo_size = surf->stencil_offset + surf->bo_size / 4; + } + + return 0; +} + +static int eg_surface_init_2d(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + uint64_t offset, unsigned start_level) +{ + unsigned tilew, tileh, tileb; + unsigned mtilew, mtileh, mtileb; + unsigned slice_pt; + unsigned i; + + surf->stencil_offset = 0; + /* compute tile values */ + tilew = 8; + tileh = 8; + tileb = tilew * tileh * surf->bpe * surf->nsamples; + /* slices per tile */ + slice_pt = 1; + if (tileb > surf->tile_split) { + slice_pt = tileb / surf->tile_split; + } + tileb = tileb / slice_pt; + + /* macro tile width & height */ + mtilew = (tilew * surf->bankw * surf_man->hw_info.num_pipes) * surf->mtilea; + mtileh = (tileh * surf->bankh * surf_man->hw_info.num_banks) / surf->mtilea; + /* macro tile bytes */ + mtileb = (mtilew / tilew) * (mtileh / tileh) * tileb; + + if (!start_level) { + surf->bo_alignment = MAX2(256, mtileb); + } + + /* build mipmap tree */ + for (i = start_level; i <= surf->last_level; i++) { + surf->level[i].mode = RADEON_SURF_MODE_2D; + eg_surf_minify(surf, i, slice_pt, mtilew, mtileh, mtileb, offset); + if (surf->level[i].mode == RADEON_SURF_MODE_1D) { + return eg_surface_init_1d(surf_man, surf, offset, i); + } + /* level0 and first mipmap need to have alignment */ + offset = surf->bo_size; + if ((i == 0)) { + offset = ALIGN(offset, surf->bo_alignment); + } + } + + if (surf->flags & RADEON_SURF_SBUFFER) { + surf->stencil_offset = ALIGN(surf->bo_size, surf->bo_alignment); + surf->bo_size = surf->stencil_offset + surf->bo_size / 4; + } + + return 0; +} + +static int eg_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned mode) +{ + unsigned tileb; + + /* check surface dimension */ + if (surf->npix_x > 16384 || surf->npix_y > 16384 || surf->npix_z > 16384) { + return -EINVAL; + } + + /* check mipmap last_level */ + if (surf->last_level > 15) { + return -EINVAL; + } + + /* force 1d on kernel that can't do 2d */ + if (!surf_man->hw_info.allow_2d && mode > RADEON_SURF_MODE_1D) { + mode = RADEON_SURF_MODE_1D; + surf->flags = RADEON_SURF_CLR(surf->flags, MODE); + surf->flags |= RADEON_SURF_SET(mode, MODE); + } + + /* check tile split */ + if (mode == RADEON_SURF_MODE_2D) { + switch (surf->tile_split) { + case 64: + case 128: + case 256: + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + return -EINVAL; + } + switch (surf->mtilea) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check aspect ratio */ + if (surf_man->hw_info.num_banks < surf->mtilea) { + return -EINVAL; + } + /* check bank width */ + switch (surf->bankw) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check bank height */ + switch (surf->bankh) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + if ((tileb * surf->bankh * surf->bankw) < surf_man->hw_info.group_bytes) { + return -EINVAL; + } + } + + return 0; +} + +static int eg_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* for some reason eg need to have room for stencil right after depth */ + if (surf->flags & RADEON_SURF_ZBUFFER) { + surf->flags |= RADEON_SURF_SBUFFER; + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + /* check tiling mode */ + switch (mode) { + case RADEON_SURF_MODE_LINEAR: + r = r6_surface_init_linear(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_LINEAR_ALIGNED: + r = r6_surface_init_linear_aligned(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_1D: + r = eg_surface_init_1d(surf_man, surf, 0, 0); + break; + case RADEON_SURF_MODE_2D: + r = eg_surface_init_2d(surf_man, surf, 0, 0); + break; + default: + return -EINVAL; + } + return r; +} + +static unsigned log2_int(unsigned x) +{ + unsigned l; + + if (x < 2) { + return 0; + } + for (l = 2; ; l++) { + if ((unsigned)(1 << l) > x) { + return l - 1; + } + } + return 0; +} + +/* compute best tile_split, bankw, bankh, mtilea + * depending on surface + */ +static int eg_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, tileb, h_over_w; + int r; + + /* tiling mode */ + mode = (surf->flags >> RADEON_SURF_MODE_SHIFT) & RADEON_SURF_MODE_MASK; + + /* for some reason eg need to have room for stencil right after depth */ + if (surf->flags & RADEON_SURF_ZBUFFER) { + surf->flags |= RADEON_SURF_SBUFFER; + } + + /* set some default value to avoid sanity check choking on them */ + surf->tile_split = 1024; + surf->bankw = 1; + surf->bankh = 1; + surf->mtilea = surf_man->hw_info.num_banks; + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + if (surf->mtilea > 8) { + surf->mtilea = 8; + } + + r = eg_surface_sanity(surf_man, surf, mode); + if (r) { + return r; + } + + if (mode != RADEON_SURF_MODE_2D) { + /* nothing to do for non 2D tiled surface */ + return 0; + } + + /* set tile split to row size, optimize latter for multi-sample surface + * tile split >= 256 for render buffer surface. Also depth surface want + * smaller value for optimal performances. + */ + surf->tile_split = surf_man->hw_info.row_size; + surf->stencil_tile_split = surf_man->hw_info.row_size / 2; + + /* bankw or bankh greater than 1 increase alignment requirement, not + * sure if it's worth using smaller bankw & bankh to stick with 2D + * tiling on small surface rather than falling back to 1D tiling. + * Use recommanded value based on tile size for now. + * + * fmask buffer has different optimal value figure them out once we + * use it. + */ + if (surf->flags & (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)) { + /* assume 1 bytes for stencil, we optimize for stencil as stencil + * and depth shares surface values + */ + tileb = MIN2(surf->tile_split, 64 * surf->nsamples); + } else { + tileb = MIN2(surf->tile_split, 64 * surf->bpe * surf->nsamples); + } + + /* use bankw of 1 to minimize width alignment, might be interesting to + * increase it for large surface + */ + surf->bankw = 1; + switch (tileb) { + case 64: + surf->bankh = 4; + break; + case 128: + case 256: + surf->bankh = 2; + break; + default: + surf->bankh = 1; + break; + } + /* double check the constraint */ + for (; surf->bankh <= 8; surf->bankh *= 2) { + if ((tileb * surf->bankh * surf->bankw) >= surf_man->hw_info.group_bytes) { + break; + } + } + + h_over_w = (((surf->bankh * surf_man->hw_info.num_banks) << 16) / + (surf->bankw * surf_man->hw_info.num_pipes)) >> 16; + surf->mtilea = 1 << (log2_int(h_over_w) >> 1); + + return 0; +} + + +/* =========================================================================== + * public API + */ +struct radeon_surface_manager *radeon_surface_manager_new(int fd) +{ + struct radeon_surface_manager *surf_man; + + surf_man = calloc(1, sizeof(struct radeon_surface_manager)); + if (surf_man == NULL) { + return NULL; + } + surf_man->fd = fd; + if (radeon_get_value(fd, RADEON_INFO_DEVICE_ID, &surf_man->device_id)) { + goto out_err; + } + if (radeon_get_family(surf_man)) { + goto out_err; + } + + if (surf_man->family <= CHIP_RV740) { + if (r6_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &r6_surface_init; + surf_man->surface_best = &r6_surface_best; + } else { + if (eg_init_hw_info(surf_man)) { + goto out_err; + } + surf_man->surface_init = &eg_surface_init; + surf_man->surface_best = &eg_surface_best; + } + + return surf_man; +out_err: + free(surf_man); + return NULL; +} + +void radeon_surface_manager_free(struct radeon_surface_manager *surf_man) +{ + free(surf_man); +} + +static int radeon_surface_sanity(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf, + unsigned type, + unsigned mode) +{ + if (surf_man == NULL || surf_man->surface_init == NULL || surf == NULL) { + return -EINVAL; + } + + /* all dimension must be at least 1 ! */ + if (!surf->npix_x || !surf->npix_y || !surf->npix_z) { + return -EINVAL; + } + if (!surf->blk_w || !surf->blk_h || !surf->blk_d) { + return -EINVAL; + } + if (!surf->array_size) { + return -EINVAL; + } + /* array size must be a power of 2 */ + surf->array_size = next_power_of_two(surf->array_size); + + switch (surf->nsamples) { + case 1: + case 2: + case 4: + case 8: + break; + default: + return -EINVAL; + } + /* check type */ + switch (type) { + case RADEON_SURF_TYPE_1D: + if (surf->npix_y > 1) { + return -EINVAL; + } + case RADEON_SURF_TYPE_2D: + if (surf->npix_z > 1) { + return -EINVAL; + } + break; + case RADEON_SURF_TYPE_CUBEMAP: + if (surf->npix_z > 1) { + return -EINVAL; + } + /* deal with cubemap as they were texture array */ + if (surf_man->family >= CHIP_RV770) { + surf->array_size = 8; + } else { + surf->array_size = 6; + } + break; + case RADEON_SURF_TYPE_3D: + break; + case RADEON_SURF_TYPE_1D_ARRAY: + if (surf->npix_y > 1) { + return -EINVAL; + } + case RADEON_SURF_TYPE_2D_ARRAY: + break; + default: + return -EINVAL; + } + return 0; +} + +int radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_init(surf_man, surf); +} + +int radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf) +{ + unsigned mode, type; + int r; + + type = RADEON_SURF_GET(surf->flags, TYPE); + mode = RADEON_SURF_GET(surf->flags, MODE); + + r = radeon_surface_sanity(surf_man, surf, type, mode); + if (r) { + return r; + } + return surf_man->surface_best(surf_man, surf); +} diff --git a/radeon/radeon_surface.h b/radeon/radeon_surface.h new file mode 100644 index 0000000..bfee8ab --- /dev/null +++ b/radeon/radeon_surface.h @@ -0,0 +1,114 @@ +/* + * Copyright © 2011 Red Hat 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: + * Jérôme Glisse + */ +#ifndef RADEON_SURFACE_H +#define RADEON_SURFACE_H + +/* Note : + * + * For texture array, the n layer are stored one after the other within each + * mipmap level. 0 value for field than can be hint is always valid. + */ + +#define RADEON_SURF_MAX_LEVEL 32 + +#define RADEON_SURF_TYPE_MASK 0xFF +#define RADEON_SURF_TYPE_SHIFT 0 +#define RADEON_SURF_TYPE_1D 0 +#define RADEON_SURF_TYPE_2D 1 +#define RADEON_SURF_TYPE_3D 2 +#define RADEON_SURF_TYPE_CUBEMAP 3 +#define RADEON_SURF_TYPE_1D_ARRAY 4 +#define RADEON_SURF_TYPE_2D_ARRAY 5 +#define RADEON_SURF_MODE_MASK 0xFF +#define RADEON_SURF_MODE_SHIFT 8 +#define RADEON_SURF_MODE_LINEAR 0 +#define RADEON_SURF_MODE_LINEAR_ALIGNED 1 +#define RADEON_SURF_MODE_1D 2 +#define RADEON_SURF_MODE_2D 3 +#define RADEON_SURF_SCANOUT (1 << 16) +#define RADEON_SURF_ZBUFFER (1 << 17) +#define RADEON_SURF_SBUFFER (1 << 18) + +#define RADEON_SURF_GET(v, field) (((v) >> RADEON_SURF_ ## field ## _SHIFT) & RADEON_SURF_ ## field ## _MASK) +#define RADEON_SURF_SET(v, field) (((v) & RADEON_SURF_ ## field ## _MASK) << RADEON_SURF_ ## field ## _SHIFT) +#define RADEON_SURF_CLR(v, field) ((v) & ~(RADEON_SURF_ ## field ## _MASK << RADEON_SURF_ ## field ## _SHIFT)) + +/* first field up to mode need to match r6 struct so that we can reuse + * same function for linear & linear aligned + */ +struct radeon_surface_level { + uint64_t offset; + uint64_t slice_size; + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t nblk_x; + uint32_t nblk_y; + uint32_t nblk_z; + uint32_t pitch_bytes; + uint32_t mode; +}; + +struct radeon_surface { + uint32_t npix_x; + uint32_t npix_y; + uint32_t npix_z; + uint32_t blk_w; + uint32_t blk_h; + uint32_t blk_d; + uint32_t array_size; + uint32_t last_level; + uint32_t bpe; + uint32_t nsamples; + uint32_t flags; + /* Following is updated/fill by the allocator. It's allowed to + * set some of the value but they are use as hint and can be + * overridden (things lile bankw/bankh on evergreen for + * instance). + */ + uint64_t bo_size; + uint64_t bo_alignment; + /* apply to eg */ + uint32_t bankw; + uint32_t bankh; + uint32_t mtilea; + uint32_t tile_split; + uint32_t stencil_tile_split; + uint64_t stencil_offset; + struct radeon_surface_level level[RADEON_SURF_MAX_LEVEL]; +}; + +struct radeon_surface_manager *radeon_surface_manager_new(int fd); +void radeon_surface_manager_free(struct radeon_surface_manager *surf_man); +int radeon_surface_init(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); +int radeon_surface_best(struct radeon_surface_manager *surf_man, + struct radeon_surface *surf); + +#endif diff --git a/slp/drm_slp_bufmgr.c b/slp/drm_slp_bufmgr.c old mode 100755 new mode 100644 index 6a01f24..f723ded --- a/slp/drm_slp_bufmgr.c +++ b/slp/drm_slp_bufmgr.c @@ -43,6 +43,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include "drm_slp_bufmgr.h" +#include "list.h" #define PREFIX_LIB "libdrm_slp_" #define SUFFIX_LIB ".so" @@ -52,6 +53,17 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SEM_NAME "pixmap_1" #define SEM_DEBUG 0 +#define DRM_RETURN_IF_FAIL(cond) {if (!(cond)) { fprintf (stderr, "[%s] : '%s' failed.\n", __FUNCTION__, #cond); return; }} +#define DRM_RETURN_VAL_IF_FAIL(cond, val) {if (!(cond)) { fprintf (stderr, "[%s] : '%s' failed.\n", __FUNCTION__, #cond); return val; }} + +#define MGR_IS_VALID(mgr) (mgr && \ + mgr->link.next && \ + mgr->link.next->prev == &mgr->link) +#define BO_IS_VALID(bo) (bo && \ + MGR_IS_VALID(bo->bufmgr) && \ + bo->list.next && \ + bo->list.next->prev == &bo->list) + typedef struct{ void* data; @@ -59,6 +71,8 @@ typedef struct{ drm_data_free free_func ; }drm_slp_user_data; +static struct list_head *gBufMgrs = NULL; + static int _sem_wait_wrapper(sem_t* sem) { @@ -243,498 +257,591 @@ _load_bufmgr(int fd, const char *file, void *arg) return bufmgr; } -drm_slp_bufmgr drm_slp_bufmgr_init(int fd, void *arg) +drm_slp_bufmgr +drm_slp_bufmgr_init(int fd, void *arg) { - drm_slp_bufmgr bufmgr = NULL; - const char *p = NULL; - - if (fd < 0) - return NULL; - - p = getenv ("SLP_BUFMGR_MODULE"); - if (p) { - char file[PATH_MAX] = {0,}; - snprintf(file, sizeof(file), PREFIX_LIB"%s"SUFFIX_LIB, p); - bufmgr = _load_bufmgr (fd, file, arg); - } - - if (!bufmgr) - bufmgr = _load_bufmgr (fd, DEFAULT_LIB, arg); - - if (!bufmgr) { - struct dirent **namelist; - int found = 0; - int n; - - n = scandir(BUFMGR_DIR, &namelist, 0, alphasort); - if (n < 0) - fprintf(stderr,"[libdrm] no files : %s\n", BUFMGR_DIR); - else { - while(n--) { - if (!found && strstr (namelist[n]->d_name, PREFIX_LIB)) { - char *p = strstr (namelist[n]->d_name, SUFFIX_LIB); - if (!strcmp (p, SUFFIX_LIB)) - { - bufmgr = _load_bufmgr (fd, namelist[n]->d_name, arg); - if (bufmgr) - found = 1; - } - } - free(namelist[n]); - } - free(namelist); - } - } - - if (!bufmgr) - { - fprintf(stderr,"[libdrm] backend is NULL.\n"); - return NULL; - } - - if (pthread_mutex_init(&bufmgr->lock, NULL) != 0) { - bufmgr->bufmgr_destroy(bufmgr); - free(bufmgr); - return NULL; - } - - return bufmgr; + drm_slp_bufmgr bufmgr = NULL; + const char *p = NULL; + + if (fd < 0) + return NULL; + + if(gBufMgrs == NULL) + { + gBufMgrs = malloc(sizeof(struct list_head)); + LIST_INITHEAD(gBufMgrs); + } + else + { + LIST_FOR_EACH_ENTRY(bufmgr, gBufMgrs, link) + { + if(bufmgr->drm_fd == fd) + { + bufmgr->ref_count++; + fprintf(stderr, "[libdrm] bufmgr ref: fd=%d, ref_count:%d\n", fd, bufmgr->ref_count); + return bufmgr; + } + } + bufmgr = NULL; + } + fprintf(stderr, "[libdrm] bufmgr init: fd=%d\n", fd); + + p = getenv ("SLP_BUFMGR_MODULE"); + if (p) + { + char file[PATH_MAX] = {0,}; + snprintf(file, sizeof(file), PREFIX_LIB"%s"SUFFIX_LIB, p); + bufmgr = _load_bufmgr (fd, file, arg); + } + + if (!bufmgr) + bufmgr = _load_bufmgr (fd, DEFAULT_LIB, arg); + + if (!bufmgr) + { + struct dirent **namelist; + int found = 0; + int n; + + n = scandir(BUFMGR_DIR, &namelist, 0, alphasort); + if (n < 0) + fprintf(stderr,"[libdrm] no files : %s\n", BUFMGR_DIR); + else + { + while(n--) + { + if (!found && strstr (namelist[n]->d_name, PREFIX_LIB)) + { + char *p = strstr (namelist[n]->d_name, SUFFIX_LIB); + if (!strcmp (p, SUFFIX_LIB)) + { + bufmgr = _load_bufmgr (fd, namelist[n]->d_name, arg); + if (bufmgr) + found = 1; + } + } + free(namelist[n]); + } + free(namelist); + } + } + + if (!bufmgr) + { + fprintf(stderr,"[libdrm] backend is NULL.\n"); + return NULL; + } + + if (pthread_mutex_init(&bufmgr->lock, NULL) != 0) + { + bufmgr->bufmgr_destroy(bufmgr); + free(bufmgr); + return NULL; + } + + bufmgr->ref_count = 1; + bufmgr->drm_fd = fd; + + LIST_INITHEAD(&bufmgr->bos); + LIST_ADD(&bufmgr->link, gBufMgrs); + + return bufmgr; } -void drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr) +void +drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr) { - if(!bufmgr) - return; - - bufmgr->bufmgr_destroy(bufmgr); - - if(bufmgr->semObj.isOpened) - { - _sem_close(bufmgr); - } + DRM_RETURN_IF_FAIL(MGR_IS_VALID(bufmgr)); + + fprintf(stderr, "[DRM] bufmgr destroy: bufmgr:%p, drm_fd:%d\n", + bufmgr, bufmgr->drm_fd); + + /*Check and Free bos*/ + if(!LIST_IS_EMPTY(&bufmgr->bos)) + { + drm_slp_bo bo, tmp; + + LIST_FOR_EACH_ENTRY_SAFE(bo, tmp, &bufmgr->bos, list) + { + fprintf(stderr, "[libdrm] Un-freed bo(%p, ref:%d) \n", bo, bo->ref_cnt); + bo->ref_cnt = 1; + drm_slp_bo_unref(bo); + } + } + + LIST_DEL(&bufmgr->link); + bufmgr->bufmgr_destroy(bufmgr); + + if(bufmgr->semObj.isOpened) + { + _sem_close(bufmgr); + } + + pthread_mutex_destroy(&bufmgr->lock); + free(bufmgr); +} - pthread_mutex_destroy(&bufmgr->lock); - free(bufmgr); +int +drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr) +{ + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), 0); + + pthread_mutex_lock(&bufmgr->lock); + + if(bufmgr->bufmgr_lock) + { + int ret; + ret = bufmgr->bufmgr_lock(bufmgr); + pthread_mutex_unlock(&bufmgr->lock); + return ret; + } + + if(!bufmgr->semObj.isOpened) + { + if(_sem_open(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } + bufmgr->semObj.isOpened = 1; + } + + if(_sem_lock(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } + + pthread_mutex_unlock(&bufmgr->lock); + + return 1; } -int drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr) +int +drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr) { - if(!bufmgr) - return 0; + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), 0); - pthread_mutex_lock(&bufmgr->lock); + pthread_mutex_lock(&bufmgr->lock); - if(!bufmgr->semObj.isOpened) - { - if(_sem_open(bufmgr) != 1) - { - pthread_mutex_unlock(&bufmgr->lock); - return 0; - } - bufmgr->semObj.isOpened = 1; - } + if(bufmgr->bufmgr_unlock) + { + int ret; + ret = bufmgr->bufmgr_unlock(bufmgr); + pthread_mutex_unlock(&bufmgr->lock); + return ret; + } - if(_sem_lock(bufmgr) != 1) - { - pthread_mutex_unlock(&bufmgr->lock); - return 0; - } + if(_sem_unlock(bufmgr) != 1) + { + pthread_mutex_unlock(&bufmgr->lock); + return 0; + } - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_unlock(&bufmgr->lock); - return 1; + return 1; } -int drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr) +int +drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags) { - if(!bufmgr) - return 0; + int ret; - pthread_mutex_lock(&bufmgr->lock); + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr) || BO_IS_VALID(bo), 0); - if(_sem_unlock(bufmgr) != 1) - { - pthread_mutex_unlock(&bufmgr->lock); - return 0; - } + if (!bo) + flags |= DRM_SLP_CACHE_ALL; - pthread_mutex_unlock(&bufmgr->lock); + if (bo) + { + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - return 1; + if(!bo->bufmgr) + return 0; + + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bufmgr_cache_flush(bufmgr, bo, flags); + pthread_mutex_unlock(&bo->bufmgr->lock); + } + else + { + pthread_mutex_lock(&bufmgr->lock); + ret = bufmgr->bufmgr_cache_flush(bufmgr, NULL, flags); + pthread_mutex_unlock(&bufmgr->lock); + } + + return ret; } -int drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags) +int +drm_slp_bo_size(drm_slp_bo bo) { - int ret; + int size; + drm_slp_bufmgr bufmgr; - if (!bufmgr && !bo) - return 0; - - if (!bo) - flags |= DRM_SLP_CACHE_ALL; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - if (bo) - { - if(!bo->bufmgr) - return 0; + bufmgr = bo->bufmgr; - pthread_mutex_lock(&bo->bufmgr->lock); - ret = bo->bufmgr->bufmgr_cache_flush(bufmgr, bo, flags); - pthread_mutex_unlock(&bo->bufmgr->lock); - } - else - { - pthread_mutex_lock(&bufmgr->lock); - ret = bufmgr->bufmgr_cache_flush(bufmgr, NULL, flags); - pthread_mutex_unlock(&bufmgr->lock); - } + pthread_mutex_lock(&bufmgr->lock); + size = bo->bufmgr->bo_size(bo); + pthread_mutex_unlock(&bufmgr->lock); - return ret; + return size; } -int drm_slp_bo_size(drm_slp_bo bo) +drm_slp_bo +drm_slp_bo_ref(drm_slp_bo bo) { - int size; - drm_slp_bufmgr bufmgr; + drm_slp_bufmgr bufmgr; - if(!bo || !bo->bufmgr) - return 0; - bufmgr = bo->bufmgr; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), NULL); + + bufmgr = bo->bufmgr; + + pthread_mutex_lock(&bufmgr->lock); + + bo->ref_cnt++; - pthread_mutex_lock(&bufmgr->lock); - size = bo->bufmgr->bo_size(bo); - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_unlock(&bufmgr->lock); - return size; + return bo; } -drm_slp_bo drm_slp_bo_ref(drm_slp_bo bo) +void +drm_slp_bo_unref(drm_slp_bo bo) { - drm_slp_bufmgr bufmgr; + drm_slp_bufmgr bufmgr; - if(!bo || !bo->bufmgr) - return NULL; - bufmgr = bo->bufmgr; + DRM_RETURN_IF_FAIL(BO_IS_VALID(bo)); - pthread_mutex_lock(&bufmgr->lock); + bufmgr = bo->bufmgr; - bo->ref_cnt++; + if(0 >= bo->ref_cnt) + return; - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_lock(&bufmgr->lock); - return bo; -} + bo->ref_cnt--; + if(bo->ref_cnt == 0) + { + if(bo->user_data) + { + void* rd; + drm_slp_user_data* old_data; + unsigned long key; -void drm_slp_bo_unref(drm_slp_bo bo) -{ - drm_slp_bufmgr bufmgr; + while(1==drmSLFirst(bo->user_data, &key, &rd)) + { + old_data = (drm_slp_user_data*)rd; - if(!bo || !bo->bufmgr) - return; - bufmgr = bo->bufmgr; + if(old_data->is_valid && old_data->free_func) + { + if(old_data->data) + old_data->free_func(old_data->data); + old_data->data = NULL; + free(old_data); + } + drmSLDelete(bo->user_data, key); + } - pthread_mutex_lock(&bufmgr->lock); + drmSLDestroy(bo->user_data); + bo->user_data = (void*)0; + } - if(0 >= bo->ref_cnt) - return; - bo->ref_cnt--; - if(bo->ref_cnt == 0) - { - bufmgr->bo_free(bo); - - if(bo->user_data) - { - void* rd; - drm_slp_user_data* old_data; - unsigned long key; - - while(1==drmSLFirst(bo->user_data, &key, &rd)) - { - old_data = (drm_slp_user_data*)rd; - - if(old_data->is_valid && old_data->free_func) - { - if(old_data->data) - old_data->free_func(old_data->data); - old_data->data = NULL; - free(old_data); - } - drmSLDelete(bo->user_data, key); - } - - drmSLDestroy(bo->user_data); - bo->user_data = (void*)0; - } - - free(bo); - } + LIST_DEL(&bo->list); + bufmgr->bo_free(bo); + + free(bo); + } - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_unlock(&bufmgr->lock); } -drm_slp_bo drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, const char * name, int size) +drm_slp_bo +drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, const char * name, int size, int flags) { - drm_slp_bo bo=NULL; + drm_slp_bo bo=NULL; - if(!bufmgr || size <= 0) - return NULL; + DRM_RETURN_VAL_IF_FAIL( MGR_IS_VALID(bufmgr) && (size > 0), NULL); - bo = calloc(sizeof(struct _drm_slp_bo), 1); - if(!bo) - return NULL; + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; - bo->bufmgr = bufmgr; + bo->bufmgr = bufmgr; - pthread_mutex_lock(&bufmgr->lock); - if(!bufmgr->bo_alloc(bo, name, size)) - { - free(bo); - pthread_mutex_unlock(&bufmgr->lock); - return NULL; - } - bo->ref_cnt = 1; - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_alloc(bo, name, size, flags)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); - return bo; + return bo; } -drm_slp_bo drm_slp_bo_attach(drm_slp_bufmgr bufmgr, +drm_slp_bo +drm_slp_bo_attach(drm_slp_bufmgr bufmgr, const char* name, - void* ptr, - int size, - void* native_handle) + int type, + int size, + unsigned int handle) { - drm_slp_bo bo; + drm_slp_bo bo; - if(!bufmgr) - return NULL; + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), NULL); - bo = calloc(sizeof(struct _drm_slp_bo), 1); - if(!bo) - return NULL; + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; - bo->bufmgr = bufmgr; + bo->bufmgr = bufmgr; - pthread_mutex_lock(&bufmgr->lock); - if(!bufmgr->bo_attach(bo, name, ptr, size, native_handle)) - { - free(bo); - pthread_mutex_unlock(&bufmgr->lock); - return NULL; - } - bo->ref_cnt = 1; - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_attach(bo, name, type, size, handle)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); - return bo; + return bo; } -drm_slp_bo drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key) +drm_slp_bo +drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key) { - drm_slp_bo bo; + drm_slp_bo bo; - if(!bufmgr) - return NULL; + DRM_RETURN_VAL_IF_FAIL(MGR_IS_VALID(bufmgr), NULL); - bo = calloc(sizeof(struct _drm_slp_bo), 1); - if(!bo) - return NULL; + bo = calloc(sizeof(struct _drm_slp_bo), 1); + if(!bo) + return NULL; - bo->bufmgr = bufmgr; + bo->bufmgr = bufmgr; - pthread_mutex_lock(&bufmgr->lock); - if(!bufmgr->bo_import(bo, key)) - { - free(bo); - pthread_mutex_unlock(&bufmgr->lock); - return NULL; - } - bo->ref_cnt = 1; - pthread_mutex_unlock(&bufmgr->lock); + pthread_mutex_lock(&bufmgr->lock); + if(!bufmgr->bo_import(bo, key)) + { + free(bo); + pthread_mutex_unlock(&bufmgr->lock); + return NULL; + } + bo->ref_cnt = 1; + LIST_ADD(&bo->list, &bufmgr->bos); + pthread_mutex_unlock(&bufmgr->lock); - return bo; + return bo; } -unsigned int drm_slp_bo_export(drm_slp_bo bo) +unsigned int +drm_slp_bo_export(drm_slp_bo bo) { - int ret; + int ret; - if(!bo || !bo->bufmgr) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - pthread_mutex_lock(&bo->bufmgr->lock); - ret = bo->bufmgr->bo_export(bo); - pthread_mutex_unlock(&bo->bufmgr->lock); + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_export(bo); + pthread_mutex_unlock(&bo->bufmgr->lock); - return ret; + return ret; } -void * drm_slp_bo_map(drm_slp_bo bo, int device, int opt) +unsigned int +drm_slp_bo_get_handle(drm_slp_bo bo, int device) { - void* ret; + unsigned int ret; - if(!bo || !bo->bufmgr) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - pthread_mutex_lock(&bo->bufmgr->lock); - ret = bo->bufmgr->bo_map(bo, device, opt); - pthread_mutex_unlock(&bo->bufmgr->lock); + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_get_handle(bo, device); + pthread_mutex_unlock(&bo->bufmgr->lock); - return ret; + return ret; } -int drm_slp_bo_unmap(drm_slp_bo bo, int device) +unsigned int +drm_slp_bo_map(drm_slp_bo bo, int device, int opt) { - int ret; + unsigned int ret; - if(!bo || !bo->bufmgr) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); + + pthread_mutex_lock(&bo->bufmgr->lock); + if(bo->bufmgr->bo_lock) + { + bo->bufmgr->bo_lock(bo, 0, (void*)0); + } - pthread_mutex_lock(&bo->bufmgr->lock); - ret = bo->bufmgr->bo_unmap(bo, device); - pthread_mutex_unlock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_map(bo, device, opt); + pthread_mutex_unlock(&bo->bufmgr->lock); - return 0; + return ret; } -int drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2) +int +drm_slp_bo_unmap(drm_slp_bo bo, int device) { - void* temp; + int ret; - if(!bo1 || !bo1->bufmgr) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - if(!bo2 || !bo2->bufmgr) - return 0; + pthread_mutex_lock(&bo->bufmgr->lock); + ret = bo->bufmgr->bo_unmap(bo, device); - if(bo1->bufmgr != bo2->bufmgr) - return 0; + if(bo->bufmgr->bo_unlock) + { + bo->bufmgr->bo_unlock(bo); + } + pthread_mutex_unlock(&bo->bufmgr->lock); - if(bo1->bufmgr->bo_size(bo1) != bo2->bufmgr->bo_size(bo2)) - return 0; + return 0; +} + +int +drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2) +{ + void* temp; - pthread_mutex_lock(&bo1->bufmgr->lock); - temp = bo1->private; - bo1->private = bo2->private; - bo2->private = temp; - pthread_mutex_unlock(&bo1->bufmgr->lock); + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo1), 0); + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo2), 0); - return 1; + if(bo1->bufmgr->bo_size(bo1) != bo2->bufmgr->bo_size(bo2)) + return 0; + + pthread_mutex_lock(&bo1->bufmgr->lock); + temp = bo1->priv; + bo1->priv = bo2->priv; + bo2->priv = temp; + pthread_mutex_unlock(&bo1->bufmgr->lock); + + return 1; } -int drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func) +int +drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func) { - int ret; - drm_slp_user_data* data; + int ret; + drm_slp_user_data* data; - if(!bo) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - if(!bo->user_data) - bo->user_data = drmSLCreate(); + if(!bo->user_data) + bo->user_data = drmSLCreate(); - data = calloc(1, sizeof(drm_slp_user_data)); - if(!data) - return 0; + data = calloc(1, sizeof(drm_slp_user_data)); + if(!data) + return 0; - data->free_func = data_free_func; - data->data = (void*)0; - data->is_valid = 0; + data->free_func = data_free_func; + data->data = (void*)0; + data->is_valid = 0; - ret = drmSLInsert(bo->user_data, key, data); - if(ret == 1) /* Already in list */ - { - free(data); - return 0; - } + ret = drmSLInsert(bo->user_data, key, data); + if(ret == 1) /* Already in list */ + { + free(data); + return 0; + } - return 1; + return 1; } -int drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data) +int +drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data) { - void *rd; - drm_slp_user_data* old_data; + void *rd; + drm_slp_user_data* old_data; - if(!bo || !bo->user_data) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo), 0); - if(drmSLLookup(bo->user_data, key, &rd)) - return 0; + if(!bo->user_data) + return 0; - old_data = (drm_slp_user_data*)rd; - if (!old_data) - return 0; + if(drmSLLookup(bo->user_data, key, &rd)) + return 0; - if(old_data->is_valid) - { - if(old_data->free_func) - { - if(old_data->data) - old_data->free_func(old_data->data); - old_data->data = NULL; - } - } - else - old_data->is_valid = 1; + old_data = (drm_slp_user_data*)rd; + if (!old_data) + return 0; - old_data->data = data; + if(old_data->is_valid) + { + if(old_data->free_func) + { + if(old_data->data) + old_data->free_func(old_data->data); + old_data->data = NULL; + } + } + else + old_data->is_valid = 1; - return 1; + old_data->data = data; + + return 1; } -int drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data) +int +drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data) { - void *rd; - drm_slp_user_data* old_data; - - if(!data) return 0; + void *rd; + drm_slp_user_data* old_data; - if(!bo || !bo->user_data) - { - *data = NULL; - return 0; - } + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo) && data && bo->user_data, 0); - if(drmSLLookup(bo->user_data, key, &rd)) - { - *data = NULL; - return 0; - } + if(drmSLLookup(bo->user_data, key, &rd)) + { + *data = NULL; + return 0; + } - old_data = (drm_slp_user_data*)rd; - if (!old_data) - { - *data = NULL; - return 0; - } + old_data = (drm_slp_user_data*)rd; + if (!old_data) + { + *data = NULL; + return 0; + } - *data = old_data->data; + *data = old_data->data; - return 1; + return 1; } -int drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key) +int +drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key) { - void *rd; - drm_slp_user_data* old_data=(void*)0; + void *rd; + drm_slp_user_data* old_data=(void*)0; - if(!bo || !bo->user_data) - return 0; + DRM_RETURN_VAL_IF_FAIL(BO_IS_VALID(bo) && bo->user_data, 0); - if(drmSLLookup(bo->user_data, key, &rd)) - return 0; + if(drmSLLookup(bo->user_data, key, &rd)) + return 0; - old_data = (drm_slp_user_data*)rd; - if (!old_data) - return 0; + old_data = (drm_slp_user_data*)rd; + if (!old_data) + return 0; - if(old_data->is_valid && old_data->free_func) - { + if(old_data->is_valid && old_data->free_func) + { if(old_data->data) - old_data->free_func(old_data->data); - free(old_data); - } - drmSLDelete(bo->user_data, key); + old_data->free_func(old_data->data); + free(old_data); + } + drmSLDelete(bo->user_data, key); - return 1; + return 1; } diff --git a/slp/drm_slp_bufmgr.h b/slp/drm_slp_bufmgr.h old mode 100755 new mode 100644 index 23a4c4b..a4adef5 --- a/slp/drm_slp_bufmgr.h +++ b/slp/drm_slp_bufmgr.h @@ -38,119 +38,164 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. typedef struct _drm_slp_bo * drm_slp_bo; typedef struct _drm_slp_bufmgr * drm_slp_bufmgr; +struct list_head +{ + struct list_head *prev; + struct list_head *next; +}; + struct _drm_slp_bo { - drm_slp_bufmgr bufmgr; - int ref_cnt; /*atomic count*/ - void *user_data; + struct list_head list; + drm_slp_bufmgr bufmgr; + int ref_cnt; /*atomic count*/ + void *user_data; - /* private data */ - void *private; + /* private data */ + void *priv; }; typedef enum { - STATUS_UNLOCK, - STATUS_READY_TO_LOCK, - STATUS_LOCK, + STATUS_UNLOCK, + STATUS_READY_TO_LOCK, + STATUS_LOCK, } lock_status; struct _drm_slp_bufmgr { - pthread_mutex_t lock; - struct { - int isOpened; - lock_status status; - sem_t* handle; - } semObj; - - void (*bufmgr_destroy)(drm_slp_bufmgr bufmgr); - int (*bufmgr_cache_flush)(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); - - int (*bo_size)(drm_slp_bo bo); - - void (*bo_free)(drm_slp_bo bo); - int (*bo_alloc)(drm_slp_bo bo, - const char* name, - int size); - - int (*bo_attach)(drm_slp_bo bo, - const char* name, - void* ptr, - int size, - void* native_handle); - - int (*bo_import)(drm_slp_bo bo, unsigned int key); - unsigned int (*bo_export)(drm_slp_bo bo); - - void* (*bo_map)(drm_slp_bo bo, int device, int opt); - int (*bo_unmap)(drm_slp_bo bo, int device); - - - /* Padding for future extension */ - void (*reserved1) (void); - void (*reserved2) (void); - void (*reserved3) (void); - void (*reserved4) (void); - void (*reserved5) (void); - void (*reserved6) (void); - - /* private data */ - void *private; + struct list_head bos; /*list head of bo*/ + + pthread_mutex_t lock; + struct { + int isOpened; + lock_status status; + sem_t* handle; + } semObj; + + void (*bufmgr_destroy)(drm_slp_bufmgr bufmgr); + int (*bufmgr_cache_flush)(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); + + int (*bo_size)(drm_slp_bo bo); + + void (*bo_free)(drm_slp_bo bo); + int (*bo_alloc)(drm_slp_bo bo, + const char* name, + int size, + int flags); + int (*bo_attach)(drm_slp_bo bo, + const char* name, + int type, + int size, + unsigned int handle); + int (*bo_import)(drm_slp_bo bo, unsigned int key); + unsigned int (*bo_export)(drm_slp_bo bo); + + unsigned int (*bo_get_handle)(drm_slp_bo bo, int device); + unsigned int (*bo_map)(drm_slp_bo bo, int device, int opt); + int (*bo_unmap)(drm_slp_bo bo, int device); + + + /* Padding for future extension */ + int (*bufmgr_lock) (drm_slp_bufmgr bufmgr); + int (*bufmgr_unlock) (drm_slp_bufmgr bufmgr); + int (*bo_lock) (drm_slp_bo bo, unsigned int checkOnly, unsigned int* isLocked); + int (*bo_unlock) (drm_slp_bo bo); + void (*reserved5) (void); + void (*reserved6) (void); + + /* private data */ + void *priv; + + struct list_head link; /*link of bufmgr*/ + + int drm_fd; + int ref_count; }; +/* DRM_SLP_MEM_TYPE */ +#define DRM_SLP_MEM_GEM 0 +#define DRM_SLP_MEM_USERPTR 1 +#define DRM_SLP_MEM_DMABUF 2 +#define DRM_SLP_MEM_GPU 3 + /* DRM_SLP_DEVICE_TYPE */ -#define DRM_SLP_DEVICE_CPU 1 -#define DRM_SLP_DEVICE_2D 2 -#define DRM_SLP_DEVICE_3D 3 +#define DRM_SLP_DEVICE_DEFAULT 0 //Default handle +#define DRM_SLP_DEVICE_CPU 1 +#define DRM_SLP_DEVICE_2D 2 +#define DRM_SLP_DEVICE_3D 3 +#define DRM_SLP_DEVICE_MM 4 /* DRM_SLP_OPTION */ -#define DRM_SLP_OPTION_INDEX0 0 -#define DRM_SLP_OPTION_INDEX1 1 -#define DRM_SLP_OPTION_INDEX2 2 -#define DRM_SLP_OPTION_READ (1 << 24) -#define DRM_SLP_OPTION_WRITE (1 << 25) +#define DRM_SLP_OPTION_READ (1 << 0) +#define DRM_SLP_OPTION_WRITE (1 << 1) +/* DRM_SLP_CACHE */ #define DRM_SLP_CACHE_INV 0x01 #define DRM_SLP_CACHE_CLN 0x02 #define DRM_SLP_CACHE_ALL 0x10 #define DRM_SLP_CACHE_FLUSH (DRM_SLP_CACHE_INV|DRM_SLP_CACHE_CLN) #define DRM_SLP_CACHE_FLUSH_ALL (DRM_SLP_CACHE_FLUSH|DRM_SLP_CACHE_ALL) -drm_slp_bufmgr drm_slp_bufmgr_init(int fd, void * arg); - -void drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr); -int drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr); -int drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr); -int drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); - -int drm_slp_bo_size (drm_slp_bo bo); - -drm_slp_bo drm_slp_bo_ref(drm_slp_bo bo); -void drm_slp_bo_unref(drm_slp_bo bo); +enum DRM_SLP_BO_FLAGS{ + DRM_SLP_BO_DEFAULT = 0, + DRM_SLP_BO_SCANOUT = (1<<0), + DRM_SLP_BO_NONCACHABLE = (1<<1), + DRM_SLP_BO_WC = (1<<2), +}; -drm_slp_bo drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, - const char* name, - int size); -drm_slp_bo drm_slp_bo_attach(drm_slp_bufmgr bufmgr, +/* Functions for buffer mnager */ +drm_slp_bufmgr +drm_slp_bufmgr_init(int fd, void * arg); +void +drm_slp_bufmgr_destroy(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_lock(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_unlock(drm_slp_bufmgr bufmgr); +int +drm_slp_bufmgr_cache_flush(drm_slp_bufmgr bufmgr, drm_slp_bo bo, int flags); + + +/*Functions for bo*/ +int +drm_slp_bo_size (drm_slp_bo bo); +drm_slp_bo +drm_slp_bo_ref(drm_slp_bo bo); +void +drm_slp_bo_unref(drm_slp_bo bo); +drm_slp_bo +drm_slp_bo_alloc(drm_slp_bufmgr bufmgr, + const char* name, + int size, + int flags); +drm_slp_bo +drm_slp_bo_attach(drm_slp_bufmgr bufmgr, const char* name, - void* ptr, - int size, - void* native_handle); - -drm_slp_bo drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key); -unsigned int drm_slp_bo_export(drm_slp_bo bo); - -void* drm_slp_bo_map(drm_slp_bo bo, int device, int opt); -int drm_slp_bo_unmap(drm_slp_bo bo, int device); - -int drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2); - - + int type, + int size, + unsigned int handle); +drm_slp_bo +drm_slp_bo_import(drm_slp_bufmgr bufmgr, unsigned int key); +unsigned int +drm_slp_bo_export(drm_slp_bo bo); +unsigned int +drm_slp_bo_get_handle(drm_slp_bo, int device); +unsigned int +drm_slp_bo_map(drm_slp_bo bo, int device, int opt); +int +drm_slp_bo_unmap(drm_slp_bo bo, int device); +int +drm_slp_bo_swap(drm_slp_bo bo1, drm_slp_bo bo2); + +/*Functions for userdata of bo*/ typedef void (*drm_data_free)(void *); -int drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func); -int drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key); -int drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data); -int drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data); - +int +drm_slp_bo_add_user_data(drm_slp_bo bo, unsigned long key, drm_data_free data_free_func); +int +drm_slp_bo_delete_user_data(drm_slp_bo bo, unsigned long key); +int +drm_slp_bo_set_user_data(drm_slp_bo bo, unsigned long key, void* data); +int +drm_slp_bo_get_user_data(drm_slp_bo bo, unsigned long key, void** data); #endif /* _DRM_SLP_BUFMGR_H_ */ diff --git a/slp/list.h b/slp/list.h new file mode 100644 index 0000000..e967b93 --- /dev/null +++ b/slp/list.h @@ -0,0 +1,131 @@ +/* + * + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA. + * 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. + * + */ + +/** + * \file + * List macros heavily inspired by the Linux kernel + * list handling. No list looping yet. + * + * Is not threadsafe, so common operations need to + * be protected using an external mutex. + */ +#ifndef _U_DOUBLE_LIST_H_ +#define _U_DOUBLE_LIST_H_ + +#include + +static void list_inithead(struct list_head *item) +{ + item->prev = item; + item->next = item; +} + +static inline void list_add(struct list_head *item, struct list_head *list) +{ + item->prev = list; + item->next = list->next; + list->next->prev = item; + list->next = item; +} + +static inline void list_addtail(struct list_head *item, struct list_head *list) +{ + item->next = list; + item->prev = list->prev; + list->prev->next = item; + list->prev = item; +} + +static inline void list_replace(struct list_head *from, struct list_head *to) +{ + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; +} + +static inline void list_del(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; +} + +static inline void list_delinit(struct list_head *item) +{ + item->prev->next = item->next; + item->next->prev = item->prev; + item->next = item; + item->prev = item; +} + +#define LIST_INITHEAD(__item) list_inithead(__item) +#define LIST_ADD(__item, __list) list_add(__item, __list) +#define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) +#define LIST_REPLACE(__from, __to) list_replace(__from, __to) +#define LIST_DEL(__item) list_del(__item) +#define LIST_DELINIT(__item) list_delinit(__item) + +#define LIST_ENTRY(__type, __item, __field) \ + ((__type *)(((char *)(__item)) - offsetof(__type, __field))) + +#define LIST_IS_EMPTY(__list) \ + ((__list)->next == (__list)) + +#ifndef container_of +#define container_of(ptr, sample, member) \ + (void *)((char *)(ptr) \ + - ((char *)&(sample)->member - (char *)(sample))) +#endif + +#define LIST_FOR_EACH_ENTRY(pos, head, member) \ + for (pos = container_of((head)->next, pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE(pos, storage, head, member) \ + for (pos = container_of((head)->next, pos, member), \ + storage = container_of(pos->member.next, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.next, storage, member)) + +#define LIST_FOR_EACH_ENTRY_SAFE_REV(pos, storage, head, member) \ + for (pos = container_of((head)->prev, pos, member), \ + storage = container_of(pos->member.prev, pos, member); \ + &pos->member != (head); \ + pos = storage, storage = container_of(storage->member.prev, storage, member)) + +#define LIST_FOR_EACH_ENTRY_FROM(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.next, pos, member)) + +#define LIST_FOR_EACH_ENTRY_FROM_REV(pos, start, head, member) \ + for (pos = container_of((start), pos, member); \ + &pos->member != (head); \ + pos = container_of(pos->member.prev, pos, member)) + +#endif /*_U_DOUBLE_LIST_H_*/ diff --git a/tests/Makefile.am b/tests/Makefile.am index 0851262..0d539fb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -10,13 +10,16 @@ check_PROGRAMS = \ dristat \ drmstat -SUBDIRS = modeprint +SUBDIRS = modeprint proptest if HAVE_LIBKMS -SUBDIRS += kmstest modetest planetest +SUBDIRS += kmstest modetest endif +SUBDIRS += ipptest +SUBDIRS += rottest SUBDIRS += gemtest +SUBDIRS += g2dtest if HAVE_RADEON SUBDIRS += radeon diff --git a/tests/planetest/Makefile.am b/tests/g2dtest/Makefile.am similarity index 61% rename from tests/planetest/Makefile.am rename to tests/g2dtest/Makefile.am index bc94ed4..fc24856 100644 --- a/tests/planetest/Makefile.am +++ b/tests/g2dtest/Makefile.am @@ -1,15 +1,18 @@ AM_CFLAGS = \ -I$(top_srcdir)/include/drm \ -I$(top_srcdir)/libkms/ \ + -I$(top_srcdir)/exynos/ \ -I$(top_srcdir) \ $(CAIRO_CFLAGS) noinst_PROGRAMS = \ - planetest + g2dtest -planetest_SOURCES = \ - planetest.c -planetest_LDADD = \ +g2dtest_SOURCES = \ + g2dtest.c + +g2dtest_LDADD = \ $(top_builddir)/libdrm.la \ $(top_builddir)/libkms/libkms.la \ + $(top_builddir)/exynos/libdrm_exynos.la \ $(CAIRO_LIBS) diff --git a/tests/g2dtest/g2d.h b/tests/g2dtest/g2d.h new file mode 100644 index 0000000..1a62880 --- /dev/null +++ b/tests/g2dtest/g2d.h @@ -0,0 +1,64 @@ +#ifndef _G2D_H_ +#define _G2D_H_ + +#include "g2d_reg.h" + +typedef enum { + G2D_SELECT_MODE_NORMAL = (0 << 0), + G2D_SELECT_MODE_FGCOLOR = (1 << 0), + G2D_SELECT_MODE_BGCOLOR = (2 << 0), + G2D_SELECT_MODE_MAX = (3 << 0), +} G2dSelectMode; + +typedef enum { + /* COLOR FORMAT */ + G2D_COLOR_FMT_XRGB8888, + G2D_COLOR_FMT_ARGB8888, + G2D_COLOR_FMT_RGB565, + G2D_COLOR_FMT_XRGB1555, + G2D_COLOR_FMT_ARGB1555, + G2D_COLOR_FMT_XRGB4444, + G2D_COLOR_FMT_ARGB4444, + G2D_COLOR_FMT_PRGB888, + G2D_COLOR_FMT_YCbCr444, + G2D_COLOR_FMT_YCbCr422, + G2D_COLOR_FMT_YCbCr420 = 10, + G2D_COLOR_FMT_A8, /* alpha 8bit */ + G2D_COLOR_FMT_L8, /* Luminance 8bit: gray color */ + G2D_COLOR_FMT_A1, /* alpha 1bit */ + G2D_COLOR_FMT_A4, /* alpha 4bit */ + G2D_COLOR_FMT_MASK = (15 << 0), /* VER4.1 */ + + /* COLOR ORDER */ + G2D_ORDER_AXRGB = (0 << 4), /* VER4.1 */ + G2D_ORDER_RGBAX = (1 << 4), /* VER4.1 */ + G2D_ORDER_AXBGR = (2 << 4), /* VER4.1 */ + G2D_ORDER_BGRAX = (3 << 4), /* VER4.1 */ + G2D_ORDER_MASK = (3 << 4), /* VER4.1 */ + + /* Number of YCbCr plane */ + G2D_YCbCr_1PLANE = (0 << 8), /* VER4.1 */ + G2D_YCbCr_2PLANE = (1 << 8), /* VER4.1 */ + G2D_YCbCr_PLANE_MASK = (3 << 8), /* VER4.1 */ + + /* Order in YCbCr */ + G2D_YCbCr_ORDER_CrY1CbY0 = (0 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_CbY1CrY0 = (1 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CrY0Cb = (2 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_Y1CbY0Cr = (3 << 12), /* VER4.1 */ + G2D_YCbCr_ORDER_MASK = (3 < 12), /* VER4.1 */ + + /* CSC */ + G2D_CSC_601 = (0 << 16), /* VER4.1 */ + G2D_CSC_709 = (1 << 16), /* VER4.1 */ + G2D_CSC_MASK = (1 << 16), /* VER4.1 */ + + /* Valid value range of YCbCr */ + G2D_YCbCr_RANGE_NARROW = (0 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_WIDE = (1 << 17), /* VER4.1 */ + G2D_YCbCr_RANGE_MASK= (1 << 17), /* VER4.1 */ + + G2D_COLOR_MODE_MASK = 0xFFFFFFFF +} G2dColorMode; + +#endif /* _G2D_H_ */ diff --git a/tests/g2dtest/g2d_reg.h b/tests/g2dtest/g2d_reg.h new file mode 100644 index 0000000..b991681 --- /dev/null +++ b/tests/g2dtest/g2d_reg.h @@ -0,0 +1,108 @@ +#ifndef _G2D_REG_H_ +#define _G2D_REG_H_ + +/* Registers */ +/* GEBERAL REGISTER */ +#define SOFT_RESET_REG (0x0000) +#define INTEN_REG (0x0004) +#define INTC_PEND_REG (0x000c) +#define FIFO_STAT_REG (0x0010) +#define AXI_MODE_REG (0x001C) +#define DMA_SFR_BASE_ADDR_REG (0x0080) +#define DMA_COMMAND_REG (0x0084) +#define DMA_EXE_LIST_NUM_REG (0x0088) +#define DMA_STATUS_REG (0x008C) +#define DMA_HOLD_CMD_REG (0x0090) + +/* COMMAND REGISTER */ +#define BITBLT_START_REG (0x0100) +#define BITBLT_COMMAND_REG (0x0104) +#define BLEND_FUNCTION_REG (0x0108) /* VER4.1 */ +#define ROUND_MODE_REG (0x010C) /* VER4.1 */ + +/* PARAMETER SETTING REGISTER */ + +/* ROTATE and DIRECTION */ +#define ROTATE_REG (0x0200) +#define SRC_MASK_DIRECT_REG (0x0204) +#define DST_PAT_DIRECT_REG (0x0208) + +/* SOURCE */ +#define SRC_SELECT_REG (0x0300) +#define SRC_BASE_ADDR_REG (0x0304) +#define SRC_STRIDE_REG (0x0308) +#define SRC_COLOR_MODE_REG (0x030c) +#define SRC_LEFT_TOP_REG (0x0310) +#define SRC_RIGHT_BOTTOM_REG (0x0314) +#define SRC_PLANE2_BASE_ADDR_REG (0x0318) /* VER4.1 */ +#define SRC_REPEAT_MODE_REG (0x031C) +#define SRC_PAD_VALUE_REG (0x0320) +#define SRC_A8_RGB_EXT_REG (0x0324) +#define SRC_SCALE_CTRL_REG (0x0328) +#define SRC_XSCALE_REG (0x032C) +#define SRC_YSCALE_REG (0x0330) + +/* DESTINATION */ +#define DST_SELECT_REG (0x0400) +#define DST_BASE_ADDR_REG (0x0404) +#define DST_STRIDE_REG (0x0408) +#define DST_COLOR_MODE_REG (0x040C) +#define DST_LEFT_TOP_REG (0x0410) +#define DST_RIGHT_BOTTOM_REG (0x0414) +#define DST_PLANE2_BASE_ADDR_REG (0x0418) /* VER4.1 */ +#define DST_A8_RGB_EXT_REG (0x041C) + +/* PATTERN */ +#define PAT_BASE_ADDR_REG (0x0500) +#define PAT_SIZE_REG (0x0504) +#define PAT_COLOR_MODE_REG (0x0508) +#define PAT_OFFSET_REG (0x050C) +#define PAT_STRIDE_REG (0x0510) + +/* MASK */ +#define MASK_BASE_ADDR_REG (0x0520) +#define MASK_STRIDE_REG (0x0524) +#define MASK_LEFT_TOP_REG (0x0528) /* VER4.1 */ +#define MASK_RIGHT_BOTTOM_REG (0x052C) /* VER4.1 */ +#define MASK_MODE_REG (0x0530) /* VER4.1 */ +#define MASK_REPEAT_MODE_REG (0x0534) +#define MASK_PAD_VALUE_REG (0x0538) +#define MASK_SCALE_CTRL_REG (0x053C) +#define MASK_XSCALE_REG (0x0540) +#define MASK_YSCALE_REG (0x0544) + +/* CLIPPING WINDOW */ +#define CW_LT_REG (0x0600) +#define CW_RB_REG (0x0604) + +/* ROP & ALPHA SETTING */ +#define THIRD_OPERAND_REG (0x0610) +#define ROP4_REG (0x0614) +#define ALPHA_REG (0x0618) + +/* COLOR SETTING */ +#define FG_COLOR_REG (0x0700) +#define BG_COLOR_REG (0x0704) +#define BS_COLOR_REG (0x0708) +#define SF_COLOR_REG (0x070C) /* VER4.1 */ + +/* COLOR KEY */ +#define SRC_COLORKEY_CTRL_REG (0x0710) +#define SRC_COLORKEY_DR_MIN_REG (0x0714) +#define SRC_COLORKEY_DR_MAX_REG (0x0718) +#define DST_COLORKEY_CTRL_REG (0x071C) +#define DST_COLORKEY_DR_MIN_REG (0x0720) +#define DST_COLORKEY_DR_MAX_REG (0x0724) +/* YCbCr src Color Key */ +#define YCbCr_SRC_COLORKEY_CTRL_REG (0x0728) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MIN_REG (0x072C) /* VER4.1 */ +#define YCbCr_SRC_COLORKEY_DR_MAX_REG (0x0730) /* VER4.1 */ +/* YCbCr dst Color Key */ +#define YCbCr_DST_COLORKEY_CTRL_REG (0x0734) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MIN_REG (0x0738) /* VER4.1 */ +#define YCbCr_DST_COLORKEY_DR_MAX_REG (0x073C) /* VER4.1 */ + +/* bits of BITBLT_COMMAND_REG */ +#define G2D_FAST_SOLID_COLOR_FILL (1 << 28) + +#endif /* _G2D_REG_H_ */ diff --git a/tests/g2dtest/g2dtest.c b/tests/g2dtest/g2dtest.c new file mode 100644 index 0000000..7fa2176 --- /dev/null +++ b/tests/g2dtest/g2dtest.c @@ -0,0 +1,593 @@ +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "exynos_drm.h" +#include "drm_fourcc.h" +#include "g2d.h" + +#define DRM_MODULE_NAME "exynos" + +struct connector { + uint32_t id; + char mode_str[64]; + drmModeModeInfo *mode; + drmModeEncoder *encoder; + int crtc; + int plane_zpos; + unsigned int fb_id[2], current_fb_id; + struct timeval start; + + int swap_count; +}; + +struct drm_buffer { + struct drm_exynos_gem_create gem; + struct drm_exynos_gem_mmap gem_mmap; +}; + +struct drm_fb { + uint32_t id; + struct drm_buffer drm_buffer; +}; + +struct drm_desc { + int fd; + struct connector connector; + int plane_id[5]; + int width; + int height; +}; + +enum format { + FMT_RGB565, + FMT_RGB888, + FMT_NV12M, +}; + +static void connector_find_mode(int fd, struct connector *c, + drmModeRes *resources) +{ + drmModeConnector *connector; + int i, j; + + /* First, find the connector & mode */ + c->mode = NULL; + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + drmModeFreeConnector(connector); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != c->id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = &connector->modes[j]; + if (!strcmp(c->mode->name, c->mode_str)) + break; + } + + /* Found it, break out */ + if (c->mode) + break; + + drmModeFreeConnector(connector); + } + + if (!c->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + return; + } + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!c->encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(c->encoder); + continue; + } + + if (c->encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(c->encoder); + } + + if (c->crtc == -1) + c->crtc = c->encoder->crtc_id; +} + +static int connector_find_plane(int fd, unsigned int *plane_id) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + int i; + + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return -1; + } + + for (i = 0; i < plane_resources->count_planes; i++) { + plane_id[i] = 0; + + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + if (ovr->possible_crtcs & (1 << 0)) + plane_id[i] = ovr->plane_id; + drmModeFreePlane(ovr); + } + + return 0; +} + +static int exynos_g2d_get_ver(int fd, struct drm_exynos_g2d_get_ver *ver) +{ + int ret; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_GET_VER, ver); + if (ret < 0) { + fprintf(stderr, "failed to get version: %s\n", strerror(-ret)); + return ret; + } + + return 0; +} + +static int exynos_g2d_set_cmdlist(int fd, + struct drm_exynos_g2d_set_cmdlist *cmdlist) +{ + int ret; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_SET_CMDLIST, cmdlist); + if (ret < 0) { + fprintf(stderr, "failed to set cmdlist: %s\n", strerror(-ret)); + return ret; + } + + return 0; +} + +static int exynos_g2d_exec(int fd, int async) +{ + struct drm_exynos_g2d_exec exec; + int ret; + + exec.async = async; + ret = ioctl(fd, DRM_IOCTL_EXYNOS_G2D_EXEC, &exec); + if (ret < 0) { + fprintf(stderr, "failed to execute: %s\n", strerror(-ret)); + return ret; + } + + return 0; +} + +static int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem) +{ + int ret; + + if (!gem) + return -EINVAL; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem); + if (ret < 0) + perror("ioctl failed\n"); + + return ret; +} + +static int exynos_gem_map_offset(int fd, struct drm_exynos_gem_map_off *map_off) +{ + int ret; + + if (!map_off) + return -EINVAL; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MAP_OFFSET, map_off); + if (ret < 0) + perror("ioctl failed\n"); + + return ret; +} + +static int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap) +{ + int ret; + + if (!in_mmap) + return -EINVAL; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap); + if (ret < 0) + perror("ioctl failed\n"); + + return ret; +} + +static int exynos_gem_close(int fd, struct drm_gem_close *gem_close) +{ + int ret; + + if (!gem_close) + return -EINVAL; + + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close); + if (ret < 0) + perror("ioctl failed\n"); + + return ret; +} + +static struct drm_desc *drm_alloc_desc(void) +{ + struct drm_desc *drm_desc; + + drm_desc = malloc(sizeof(struct drm_desc)); + if (!drm_desc) { + perror("memory alloc error\n"); + return NULL; + } + memset(drm_desc, 0, sizeof(struct drm_desc)); + + return drm_desc; +} + +static int drm_open(struct drm_desc *drm_desc) +{ + if (!drm_desc) { + fprintf(stderr, "drm_desc is NULL\n"); + return -EINVAL; + } + + drm_desc->fd = drmOpen(DRM_MODULE_NAME, NULL); + if (drm_desc->fd < 0) { + printf("Failed to open %s module\n", DRM_MODULE_NAME); + return drm_desc->fd; + } + + return 0; +} + +static int drm_create_buffer(struct drm_desc *drm_desc, struct drm_fb *drm_fb, + int width, int height) +{ + struct drm_buffer *drm_buffer; + unsigned int num_planes; + unsigned long size; + int i; + int ret; + + if (!drm_desc) + return -EINVAL; + + size = width * height * 4; + + drm_buffer = &drm_fb->drm_buffer; + + { + struct drm_exynos_gem_create *gem = &drm_buffer->gem; + struct drm_exynos_gem_mmap *gem_mmap = &drm_buffer->gem_mmap; + + memset(gem, 0, sizeof(struct drm_exynos_gem_create)); + gem->size = size; + + ret = exynos_gem_create(drm_desc->fd, gem); + if (ret < 0) { + printf("failed to create gem\n"); + goto err_gem; + } + + gem_mmap->handle = gem->handle; + gem_mmap->size = gem->size; + ret = exynos_gem_mmap(drm_desc->fd, gem_mmap); + if (ret < 0) { + printf("failed to mmap gem directly\n"); + goto err_gem; + } + + /* init gem buffer */ + memset((void *)(unsigned long)gem_mmap->mapped, 0, + gem_mmap->size); + } + + return 0; + +err_gem: + { + struct drm_exynos_gem_create *gem = &drm_buffer->gem; + struct drm_gem_close gem_close; + + gem_close.handle = gem->handle; + exynos_gem_close(drm_desc->fd, &gem_close); + } + + return ret; +} + +static int drm_create_fb(struct drm_desc *drm_desc, struct drm_fb *drm_fb, + int width, int height) +{ + unsigned int pixel_format; + unsigned int num_planes; + unsigned int pitch; + int i; + int j; + int ret; + + if (!drm_desc) + return -EINVAL; + + drm_desc->width = width; + drm_desc->height = height; + + pixel_format = DRM_FORMAT_RGBA8888; + num_planes = 1; + pitch = width * 4; + + { + uint32_t bo[4] = {0,}; + uint32_t pitches[4] = {0,}; + uint32_t offset[4] = {0,}; + + ret = drm_create_buffer(drm_desc, drm_fb, width, height); + if (ret < 0) + goto err; + + for (j = 0; j < num_planes; j++) { + struct drm_buffer *drm_buffer = &drm_fb->drm_buffer; + struct drm_exynos_gem_create *gem = &drm_buffer->gem; + + bo[j] = gem->handle; + pitches[j] = pitch; + } + + ret = drmModeAddFB2(drm_desc->fd, width, height, pixel_format, + bo, pitches, offset, &drm_fb->id, + 0); + if (ret < 0) { + perror("failed to add fb\n"); + goto err; + } + } + + return 0; + +err: + /* TODO: free buffer */ + return ret; +} + +static int drm_set_crtc(struct drm_desc *drm_desc, struct connector *c, + struct drm_fb *drm_fb) +{ + drmModeRes *resources; + int ret; + + memcpy(&drm_desc->connector, c, sizeof(struct connector)); + + resources = drmModeGetResources(drm_desc->fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + ret = -EFAULT; + goto err; + } + + connector_find_mode(drm_desc->fd, &drm_desc->connector, resources); + drmModeFreeResources(resources); + + ret = drmModeSetCrtc(drm_desc->fd, drm_desc->connector.crtc, + drm_fb->id, 0, 0, + &drm_desc->connector.id, 1, + drm_desc->connector.mode); + if (ret) { + fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); + goto err; + } + + return 0; + +err: + /* TODO */ + return ret; +} + +static inline void set_cmd(struct drm_exynos_g2d_cmd *cmd, + __u32 offset, __u32 data) +{ + cmd->offset = offset; + cmd->data = data; +} + +static int exynos_g2d_test_solid_fill(struct drm_desc *drm_desc, int x, int y, + int color, int gem_handle) +{ + struct drm_exynos_g2d_set_cmdlist cmdlist; + struct drm_exynos_g2d_cmd cmd[20]; + struct drm_exynos_g2d_cmd cmd_gem[5]; + int nr = 0; + int gem_nr = 0; + int ret; + + memset(&cmdlist, 0, sizeof(struct drm_exynos_g2d_set_cmdlist)); + memset(cmd, 0, sizeof(struct drm_exynos_g2d_cmd) * 20); + memset(cmd_gem, 0, sizeof(struct drm_exynos_g2d_cmd) * 5); + + cmdlist.cmd = cmd; + cmdlist.cmd_gem = cmd_gem; + + set_cmd(&cmd[nr++], BITBLT_COMMAND_REG, G2D_FAST_SOLID_COLOR_FILL); + /* [14:10] R, [9:5] G, [4:0] B */ + set_cmd(&cmd[nr++], SF_COLOR_REG, color); + + /* DST */ + set_cmd(&cmd[nr++], DST_SELECT_REG, G2D_SELECT_MODE_FGCOLOR); + set_cmd(&cmd_gem[gem_nr++], DST_BASE_ADDR_REG, gem_handle); + set_cmd(&cmd[nr++], DST_STRIDE_REG, 720 * 4); + set_cmd(&cmd[nr++], DST_COLOR_MODE_REG, G2D_COLOR_FMT_ARGB8888 | + G2D_ORDER_AXRGB); + set_cmd(&cmd[nr++], DST_LEFT_TOP_REG, (0 << 16) | 0); + set_cmd(&cmd[nr++], DST_RIGHT_BOTTOM_REG, (y << 16) | x); + set_cmd(&cmd[nr++], DST_A8_RGB_EXT_REG, 0); + + cmdlist.cmd_nr = nr; + cmdlist.cmd_gem_nr = gem_nr; + + cmdlist.event_type = G2D_EVENT_NONSTOP; + cmdlist.user_data = 1234; + + ret = exynos_g2d_set_cmdlist(drm_desc->fd, &cmdlist); + if (ret < 0) + return ret; +} + +static int exynos_g2d_event(int fd) +{ + char buffer[1024]; + int len, i; + struct drm_event *e; + struct drm_exynos_g2d_event *g2d_event; + + len = read(fd, buffer, sizeof buffer); + if (len == 0) + return 0; + if (len < sizeof *e) + return -1; + + i = 0; + while (i < len) { + e = (struct drm_event *) &buffer[i]; + switch (e->type) { + case DRM_EXYNOS_G2D_EVENT: + g2d_event = (struct drm_exynos_g2d_event *) e; + printf("cmdlist_no: %d\n", g2d_event->cmdlist_no); + printf("user_data: %lld\n", g2d_event->user_data); + break; + default: + break; + } + i += e->length; + } + + return 0; +} + +int main(int argc, char **argv) +{ + struct connector con_args; + struct drm_desc *drm_desc; + struct drm_fb drm_fb; + struct drm_exynos_g2d_get_ver ver; + int x, y; + int ret; + + /* default set of connector */ + memset(&con_args, 0, sizeof(struct connector)); + con_args.id = 12; + con_args.crtc = 3; + con_args.plane_zpos = -1; + strcpy(con_args.mode_str, "720x1280"); + x = 720; + y = 1280; + + drm_desc = drm_alloc_desc(); + if (!drm_desc) { + ret = -1; + goto err_free; + } + + ret = drm_open(drm_desc); + if (ret < 0) + goto err_free; + + /* check version */ + ret = exynos_g2d_get_ver(drm_desc->fd, &ver); + if (ret < 0) + return ret; + + if (ver.major != 4 || ver.minor != 1) { + fprintf(stderr, "version(%d.%d) mismatch\n", ver.major, ver.minor); + return -1; + } + printf("g2d hw version: %d.%d\n", ver.major, ver.minor); + + ret = drm_create_fb(drm_desc, &drm_fb, x, y); + if (ret < 0) + goto err_drm_close; + + ret = drm_set_crtc(drm_desc, &con_args, &drm_fb); + if (ret < 0) + goto err; + + getchar(); + + ret = exynos_g2d_test_solid_fill(drm_desc, x, y, 0x1f, + drm_fb.drm_buffer.gem.handle); + if (ret < 0) + goto err; + + ret = exynos_g2d_exec(drm_desc->fd, 1); + if (ret < 0) + return ret; + + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + int ret; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(drm_desc->fd, &fds); + ret = select(drm_desc->fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + exynos_g2d_event(drm_desc->fd); + } + + getchar(); + + /* TODO */ + +err: + /* TODO */ +err_drm_close: + drmClose(drm_desc->fd); +err_free: + if (drm_desc) + free(drm_desc); + + return ret; +} diff --git a/tests/gem_flink.c b/tests/gem_flink.c index 8dc8832..ce43e42 100644 --- a/tests/gem_flink.c +++ b/tests/gem_flink.c @@ -117,10 +117,15 @@ int main(int argc, char **argv) { int fd; + if (geteuid()) { + fprintf(stderr, "requires root privileges, skipping\n"); + return 77; + } + fd = drm_open_matching("8086:*", 0); if (fd < 0) { fprintf(stderr, "failed to open intel drm device, skipping\n"); - return 0; + return 77; } test_flink(fd); diff --git a/tests/gemtest/Makefile.am b/tests/gemtest/Makefile.am index 08432a1..eb46c07 100644 --- a/tests/gemtest/Makefile.am +++ b/tests/gemtest/Makefile.am @@ -1,5 +1,7 @@ AM_CFLAGS = \ -I$(top_srcdir)/include/drm \ + -I$(top_srcdir)/libkms/ \ + -I$(top_srcdir)/exynos/ \ -I$(top_srcdir) \ $(CAIRO_CFLAGS) @@ -8,6 +10,9 @@ noinst_PROGRAMS = \ gemtest_SOURCES = \ gemtest.c + gemtest_LDADD = \ $(top_builddir)/libdrm.la \ + $(top_builddir)/libkms/libkms.la \ + $(top_builddir)/exynos/libdrm_exynos.la \ $(CAIRO_LIBS) diff --git a/tests/gemtest/gemtest.c b/tests/gemtest/gemtest.c index f7f0e70..018f83d 100644 --- a/tests/gemtest/gemtest.c +++ b/tests/gemtest/gemtest.c @@ -45,14 +45,21 @@ #include #include #include +#include #include +#include #include #include #include #include "xf86drm.h" #include "xf86drmMode.h" +#include "libkms.h" + #include "exynos_drm.h" +#include "exynos_drmif.h" + +#include "ump_ref_drv.h" #ifdef HAVE_CAIRO #include @@ -60,6 +67,8 @@ #endif #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) + 1)) +#define DEFAULT_SIZE (1280 * 720 * 4) +#define MAX_CMD 5 /* * DIRECT_MAP: @@ -78,7 +87,63 @@ #define DIRECT_MAP //#define INDIRECT_MAP -#define CACHE_TEST +#if 0 +#define UMP_TEST + +#define GET_PHY_TEST + +#define VIDI_TEST + +#define GEMGET_TEST +#endif + +enum exynos_test_type { + CMD_ALLOC = 1 << 0, + CMD_CACHE = 1 << 1, + CMD_PRIME = 1 << 2, + CMD_UMP = 1 << 3, + + ALLOC_CONTIG = 1 << 4, + ALLOC_NONCONTIG = 1 << 5, + ALLOC_USERPTR = 1 << 6, + + ALLOC_MAP_C = 1 << 7, + ALLOC_MAP_NC = 1 << 8, + ALLOC_MAP_WC = 1 << 9, + + CACHE_L1 = 1 << 10, + CACHE_L2 = 1 << 11, + CACHE_ALL_CORES = 1 << 12, + CACHE_ALL_CACHES = CACHE_L1 | CACHE_L2, + CACHE_ALL_CACHES_CORES = CACHE_ALL_CACHES | CACHE_ALL_CORES, + + CACHE_CLEAN_ALL = 0 << 13, + CACHE_INV_ALL = 0 << 14, + CACHE_FLUSH_ALL = CACHE_CLEAN_ALL | CACHE_INV_ALL, + + CACHE_CLEAN_RANGE = 1 << 13, + CACHE_INV_RANGE = 1 << 14, + CACHE_FLUSH_RANGE = CACHE_CLEAN_RANGE | CACHE_INV_RANGE, + + DMABUF_IMPORT = 1 << 15, + DMABUF_EXPORT = 1 << 16, + DMABUF_ALL = DMABUF_IMPORT | DMABUF_EXPORT +}; + +struct exynos_gem_test { + char *scmd[MAX_CMD]; + + unsigned int cmd_type; + unsigned int mem_type; + unsigned int map_type; + unsigned int cache_type; + unsigned int cache_op_type; + unsigned long start_offset; + unsigned long end_offset; + unsigned int dmabuf_type; +}; + +struct exynos_gem_test exynos_test; drmModeRes *resources; int fd, modes; @@ -134,6 +199,7 @@ struct type_name connector_type_names[] = { { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, { DRM_MODE_CONNECTOR_TV, "TV" }, { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, }; type_name_fn(connector_type) @@ -289,6 +355,19 @@ void dump_framebuffers(void) printf("\n"); } +void exynos_test_dump(void) +{ + + printf("cmd_type = %d\n", exynos_test.cmd_type); + printf("mem_type = %d\n", exynos_test.mem_type); + printf("map_type = %d\n", exynos_test.map_type); + printf("cache_type = %d\n", exynos_test.cache_type); + printf("cache_type = %d\n", exynos_test.cache_op_type); + printf("start_offset = 0x%lx\n", exynos_test.start_offset); + printf("end_offset = 0x%lx\n", exynos_test.end_offset); + printf("dmabuf_type = %d\n", exynos_test.dmabuf_type); +} + /* * Mode setting with the kernel interfaces is a bit of a chore. * First you have to find the connector in question and make sure the @@ -375,6 +454,40 @@ connector_find_mode(struct connector *c) c->crtc = c->encoder->crtc_id; } +static struct kms_bo * +allocate_buffer(struct kms_driver *kms, + int width, int height, int *stride) +{ + struct kms_bo *bo; + unsigned bo_attribs[] = { + KMS_WIDTH, 0, + KMS_HEIGHT, 0, + KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, + KMS_TERMINATE_PROP_LIST + }; + int ret; + + bo_attribs[1] = width; + bo_attribs[3] = height; + + ret = kms_bo_create(kms, bo_attribs, &bo); + if (ret) { + fprintf(stderr, "failed to alloc buffer: %s\n", + strerror(-ret)); + return NULL; + } + + ret = kms_bo_get_prop(bo, KMS_PITCH, stride); + if (ret) { + fprintf(stderr, "failed to retreive buffer stride: %s\n", + strerror(-ret)); + kms_bo_destroy(&bo); + return NULL; + } + + return bo; +} + static void make_pwetty(void *data, int width, int height, int stride) { @@ -421,6 +534,78 @@ make_pwetty(void *data, int width, int height, int stride) #endif } +static int +create_test_buffer(struct kms_driver *kms, + int width, int height, int *stride_out, + struct kms_bo **bo_out) +{ + struct kms_bo *bo; + int ret, i, j, stride; + void *virtual; + + bo = allocate_buffer(kms, width, height, &stride); + if (!bo) + return -1; + + ret = kms_bo_map(bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-ret)); + kms_bo_destroy(&bo); + return -1; + } + + /* paint the buffer with colored tiles */ + for (j = 0; j < height; j++) { + uint32_t *fb_ptr = (uint32_t*)((char*)virtual + j * stride); + for (i = 0; i < width; i++) { + div_t d = div(i, width); + fb_ptr[i] = + 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + } + } + + make_pwetty(virtual, width, height, stride); + + kms_bo_unmap(bo); + + *bo_out = bo; + *stride_out = stride; + return 0; +} + +static int +create_grey_buffer(struct kms_driver *kms, + int width, int height, int *stride_out, + struct kms_bo **bo_out) +{ + struct kms_bo *bo; + int size, ret, stride; + void *virtual; + + bo = allocate_buffer(kms, width, height, &stride); + if (!bo) + return -1; + + ret = kms_bo_map(bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-ret)); + kms_bo_destroy(&bo); + return -1; + } + + size = stride * height; + memset(virtual, 0x77, size); + kms_bo_unmap(bo); + + *bo_out = bo; + *stride_out = stride; + + return 0; +} + void page_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) @@ -435,7 +620,7 @@ page_flip_handler(int fd, unsigned int frame, new_fb_id = c->fb_id[1]; else new_fb_id = c->fb_id[0]; - + drmModePageFlip(fd, c->crtc, new_fb_id, DRM_MODE_PAGE_FLIP_EVENT, c); c->current_fb_id = new_fb_id; @@ -450,25 +635,6 @@ page_flip_handler(int fd, unsigned int frame, } } -static int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem) -{ - int ret; - - if (!gem) { - fprintf(stderr, "gem object is null.\n"); - return -EFAULT; - } - - ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem); - if (ret < 0) { - fprintf(stderr, "failed to create gem buffer: %s\n", - strerror(-ret)); - return ret; - } - - return 0; -} - static int exynos_gem_map_offset(int fd, struct drm_exynos_gem_map_off *map_off) { int ret; @@ -483,13 +649,13 @@ static int exynos_gem_map_offset(int fd, struct drm_exynos_gem_map_off *map_off) return 0; } -static int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap) +static int exynos_gem_get_ump(int fd, struct drm_exynos_gem_ump *gem_ump) { int ret; - ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap); + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_EXPORT_UMP, gem_ump); if (ret < 0) { - fprintf(stderr, "failed to get buffer offset: %s\n", + fprintf(stderr, "failed to get ump: %s\n", strerror(-ret)); return ret; } @@ -497,13 +663,14 @@ static int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap) return 0; } -static int exynos_gem_close(int fd, struct drm_gem_close *gem_close) +static int exynos_gem_cache_op(int fd, + struct drm_exynos_gem_cache_op *cache_op) { int ret; - ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close); + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CACHE_OP, cache_op); if (ret < 0) { - fprintf(stderr, "failed to close gem buffer: %s\n", + fprintf(stderr, "failed to cache operation: %s\n", strerror(-ret)); return ret; } @@ -511,13 +678,14 @@ static int exynos_gem_close(int fd, struct drm_gem_close *gem_close) return 0; } -static int exynos_gem_get_ump(int fd, struct drm_exynos_gem_ump *gem_ump) +static int exynos_gem_get_phy(int fd, + struct drm_exynos_gem_get_phy *get_phy) { int ret; - ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_EXPORT_UMP, gem_ump); + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_GET_PHY, get_phy); if (ret < 0) { - fprintf(stderr, "failed to get ump: %s\n", + fprintf(stderr, "failed to get physical address: %s\n", strerror(-ret)); return ret; } @@ -525,14 +693,14 @@ static int exynos_gem_get_ump(int fd, struct drm_exynos_gem_ump *gem_ump) return 0; } -static int exynos_gem_cache_op(int fd, - struct drm_exynos_gem_cache_op *cache_op) +static int exynos_gem_phy_imp(int fd, + struct drm_exynos_gem_phy_imp *phy_imp) { int ret; - ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CACHE_OP, cache_op); + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_PHY_IMP, phy_imp); if (ret < 0) { - fprintf(stderr, "failed to cache operation: %s\n", + fprintf(stderr, "failed to import physical memory to gem: %s\n", strerror(-ret)); return ret; } @@ -543,18 +711,12 @@ static int exynos_gem_cache_op(int fd, static void set_mode(struct connector *c, int count, int page_flip) { - struct drm_exynos_gem_create gem1, gem2; - struct drm_exynos_gem_map_off map_off1, map_off2; - struct drm_exynos_gem_mmap mmap1; - struct drm_exynos_gem_cache_op cache_op; - struct drm_exynos_gem_ump gem_ump; - struct drm_gem_close args; + struct kms_driver *kms; + struct kms_bo *bo, *other_bo; unsigned int fb_id, other_fb_id; int i, ret, width, height, x, stride; unsigned handle; - void *usr_addr1, *usr_addr2; drmEventContext evctx; - unsigned int tmp; width = 0; height = 0; @@ -567,57 +729,421 @@ set_mode(struct connector *c, int count, int page_flip) height = c[i].mode->vdisplay; } -#ifdef CACHE_TEST - cache_op.flags = 0; - cache_op.flags = (EXYNOS_DRM_ALL_CACHE | EXYNOS_DRM_CACHE_FSH); + ret = kms_create(fd, &kms); + if (ret) { + fprintf(stderr, "failed to create kms driver: %s\n", + strerror(-ret)); + return; + } - exynos_gem_cache_op(fd, &cache_op); + if (create_test_buffer(kms, width, height, &stride, &bo)) + return; + + kms_bo_get_prop(bo, KMS_HANDLE, &handle); + ret = drmModeAddFB(fd, width, height, 24, 32, stride, handle, &fb_id); + if (ret) { + fprintf(stderr, "failed to add fb (%ux%u): %s\n", + width, height, strerror(errno)); + return; + } + + x = 0; + for (i = 0; i < count; i++) { + if (c[i].mode == NULL) + continue; + + printf("setting mode %s on connector %d, crtc %d\n", + c[i].mode_str, c[i].id, c[i].crtc); + + ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, + &c[i].id, 1, c[i].mode); + + /* XXX: Actually check if this is needed */ + drmModeDirtyFB(fd, fb_id, NULL, 0); + + x += c[i].mode->hdisplay; + + if (ret) { + fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); + return; + } + } + + if (!page_flip) + return; + + if (create_grey_buffer(kms, width, height, &stride, &other_bo)) + return; + + kms_bo_get_prop(other_bo, KMS_HANDLE, &handle); + ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, + &other_fb_id); + if (ret) { + fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); + return; + } + + for (i = 0; i < count; i++) { + if (c[i].mode == NULL) + continue; + + ret = drmModePageFlip(fd, c[i].crtc, other_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, &c[i]); + if (ret) { + fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); + return; + } + gettimeofday(&c[i].start, NULL); + c[i].swap_count = 0; + c[i].fb_id[0] = fb_id; + c[i].fb_id[1] = other_fb_id; + c[i].current_fb_id = other_fb_id; + } + + memset(&evctx, 0, sizeof evctx); + evctx.version = DRM_EVENT_CONTEXT_VERSION; + evctx.vblank_handler = NULL; + evctx.page_flip_handler = page_flip_handler; + + while (1) { +#if 0 + struct pollfd pfd[2]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; + pfd[1].fd = fd; + pfd[1].events = POLLIN; + + if (poll(pfd, 2, -1) < 0) { + fprintf(stderr, "poll error\n"); + break; + } + + if (pfd[0].revents) + break; +#else + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + int ret; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, NULL, NULL, &timeout); + + if (ret <= 0) { + fprintf(stderr, "select timed out or error (ret %d)\n", + ret); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } #endif - /* allocate gem buffer. */ - gem1.size = 1024 * 600 * 4; + drmHandleEvent(fd, &evctx); + } - ret = exynos_gem_create(fd, &gem1); - if (ret < 0) + kms_bo_destroy(&bo); + kms_bo_destroy(&other_bo); + kms_destroy(&kms); +} + +extern char *optarg; +extern int optind, opterr, optopt; +static char optstr[] = "ecpmfs:t:v"; + +void usage(char *name) +{ + fprintf(stderr, "usage: %s [-ecpmfst]\n", name); + fprintf(stderr, "\t-e\tlist encoders\n"); + fprintf(stderr, "\t-c\tlist connectors\n"); + fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-m\tlist modes\n"); + fprintf(stderr, "\t-f\tlist framebuffers\n"); + fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); + fprintf(stderr, "\t-s :\tset a mode\n"); + fprintf(stderr, "\t-s @:\tset a mode\n"); + fprintf(stderr, "\t-t \tsetup gem allocation\n"); + fprintf(stderr, "\t-t \tsetup cache operation\n"); + fprintf(stderr, "\t-t \tsetup drm prime or ump dmabuf\n"); + fprintf(stderr, "\n\tcommand line sentences to -t option\n"); + fprintf(stderr, "\t-t alloc:[contig,noncontig,userptr]:[cache,noncache,writecombine]\n"); + fprintf(stderr, "\t-t cache:[l1,l2,all]:[flush_range,clean_range,inv_range,flush_all,clean_all,inv_all]\n"); + fprintf(stderr, "\t-t [prime,ump]:dmabuf:[export,import,all]\n"); + fprintf(stderr, "\n\tDefault is to dump all info.\n"); + exit(0); +} + +#define dump_resource(res) if (res) dump_##res() + +static int page_flipping_supported(int fd) +{ + /*FIXME: generic ioctl needed? */ + return 1; +#if 0 + int ret, value; + struct drm_i915_getparam gp; + + gp.param = I915_PARAM_HAS_PAGEFLIPPING; + gp.value = &value; + + ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "drm_i915_getparam: %m\n"); + return 0; + } + + return *gp.value; +#endif +} + +static void test_exynos_gem(struct connector *c, int count, int page_flip) +{ + struct drm_exynos_gem_map_off map_off1; + + struct drm_exynos_gem_cache_op cache_op; + + struct ump_uk_dmabuf ump_dmabuf; + int ump_fd; + + void *vaddr; + + struct kms_driver *kms; + struct kms_bo *other_bo; + int i, ret, width, height, x, stride; + unsigned int fb_id, other_fb_id; + uint32_t handle; + drmEventContext evctx; + void *usr_addr1; + int prime_fd; + + struct exynos_device *dev; + struct exynos_bo *bo; + unsigned int gem_size, gem_flags; + +#if 0 +#ifdef UMP_TEST + struct drm_exynos_gem_ump gem_ump; +#endif +#ifdef GET_PHY_TEST + /* temporary codes. */ + struct drm_exynos_gem_get_phy get_phy; + struct drm_exynos_gem_phy_imp phy_imp; +#endif +#ifdef VIDI_TEST + struct drm_exynos_vidi_connection vidi; +#endif +#ifdef GEMGET_TEST + struct drm_exynos_gem_info info; +#endif +#ifdef VIDI_TEST + vidi.connection = 1; + exynos_vidi_connection(fd, &vidi); +#endif +#endif + + dev = exynos_device_create(fd); + if (!dev) return; - handle = gem1.handle; + exynos_test_dump(); + + width = 0; + height = 0; + for (i = 0; i < count; i++) { + connector_find_mode(&c[i]); + if (c[i].mode == NULL) + continue; + width += c[i].mode->hdisplay; + if (height < c[i].mode->vdisplay) + height = c[i].mode->vdisplay; + } + + if (exynos_test.cmd_type & CMD_ALLOC) { + if (exynos_test.mem_type & ALLOC_USERPTR) { + vaddr = malloc(DEFAULT_SIZE); + if (!vaddr) + return; + + ret = exynos_userptr(dev, vaddr, DEFAULT_SIZE, &handle); + if (ret < 0) + return; + + usr_addr1 = vaddr; + printf("userptr handle = %d\n", handle); + } else { + unsigned int flags; + + /* flag memory type. */ + if (exynos_test.mem_type & ALLOC_CONTIG) + flags = EXYNOS_BO_CONTIG; + else + flags = EXYNOS_BO_NONCONTIG; + + /* flag cache mapping type. */ + if (exynos_test.map_type & ALLOC_MAP_C) + flags |= EXYNOS_BO_CACHABLE; + else if (exynos_test.map_type & ALLOC_MAP_NC) + flags |= EXYNOS_BO_NONCACHABLE; + else + flags |= EXYNOS_BO_WC; + + bo = exynos_bo_create(dev, DEFAULT_SIZE, flags); + if (!bo) + return; + + handle = bo->handle; + + printf("gem handle = %d\n", bo->handle); + } + } #ifdef DIRECT_MAP - mmap1.handle = handle; - mmap1.size = gem1.size; - ret = exynos_gem_mmap(fd, &mmap1); - if (ret < 0) - return; + if (!(exynos_test.mem_type & ALLOC_USERPTR)) { + printf("handle = %d, size = 0x%x\n", bo->handle, bo->size); + + usr_addr1 = exynos_bo_map(bo); + if (!usr_addr1) + return; - usr_addr1 = mmap1.mapped; - memset(usr_addr1, 0x88, mmap1.size); + memset(usr_addr1, 0x88, bo->size); + } #endif #ifdef INDIRECT_MAP - map_off1.handle = handle; + /* FIXME */ + if (!(exynos_test.mem_type & ALLOC_USERPTR)) { + map_off1.handle = handle; + + /* get map offset. */ + ret = exynos_gem_map_offset(fd, &map_off1); + if (ret < 0) + return; - /* get map offset. */ - ret = exynos_gem_map_offset(fd, &map_off1); + usr_addr1 = mmap(0, gem1.size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, map_off1.offset); + + memset(usr_addr1, 0x88, gem1.size); + } +#endif + + if (exynos_test.cmd_type & CMD_CACHE) { + cache_op.flags = 0; + + /* flag cache units to do cache operation. */ + if (exynos_test.cache_type & CACHE_L1) + cache_op.flags |= EXYNOS_DRM_L1_CACHE; + if (exynos_test.cache_type & CACHE_L2) + cache_op.flags |= EXYNOS_DRM_L2_CACHE; + if (exynos_test.cache_type & CACHE_ALL_CORES) + cache_op.flags |= EXYNOS_DRM_ALL_CORES; + + /* flag cache operations. */ + if (exynos_test.cache_op_type & CACHE_CLEAN_RANGE) + cache_op.flags |= EXYNOS_DRM_CACHE_CLN_RANGE; + if (exynos_test.cache_op_type & CACHE_INV_RANGE) + cache_op.flags |= EXYNOS_DRM_CACHE_INV_RANGE; + if (!(exynos_test.cache_op_type & CACHE_CLEAN_RANGE)) { + cache_op.flags &= ~EXYNOS_DRM_CACHE_CLN_RANGE; + cache_op.flags |= EXYNOS_DRM_CACHE_CLN_ALL; + } + if (!(exynos_test.cache_op_type & CACHE_INV_RANGE)) { + cache_op.flags &= ~EXYNOS_DRM_CACHE_INV_RANGE; + cache_op.flags |= EXYNOS_DRM_CACHE_INV_ALL; + } + + cache_op.usr_addr = usr_addr1 + exynos_test.start_offset; + cache_op.size = exynos_test.end_offset - + exynos_test.start_offset; + + exynos_gem_cache_op(fd, &cache_op); + } + +#ifdef GEMGET_TEST + ret = exynos_bo_gem_info(dev, bo->handle, &gem_size, &gem_flags); if (ret < 0) return; - usr_addr1 = mmap(0, gem1.size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, map_off1.offset); + printf("[gem get] flags = 0x%x, size = 0x%x\n", gem_flags, gem_size); +#endif + + if (exynos_test.cmd_type & CMD_PRIME) { + if (exynos_test.dmabuf_type & DMABUF_EXPORT) { + ret = exynos_prime_handle_to_fd(dev, bo->handle, + &prime_fd); + if (ret < 0) + return; + + printf("handle to fd : handle(0x%x) ==> fd(%d)\n", + bo->handle, + prime_fd); + } + + if (exynos_test.dmabuf_type & DMABUF_IMPORT) { + uint32_t gem_handle; + + ret = exynos_prime_fd_to_handle(dev, prime_fd, &gem_handle); + if (ret < 0) + return; + + printf("fd to handle : fd(%d) ==> handle(0x%x)\n", + prime_fd, + gem_handle); + } + } + + if (exynos_test.cmd_type & CMD_UMP) { + ump_fd = open("/dev/ump", O_RDWR); + if (ump_fd < 0) { + printf("failed to open ump.\n"); + return; + } + + memset(&ump_dmabuf, 0, sizeof(struct ump_uk_dmabuf)); + + if (exynos_test.dmabuf_type & DMABUF_IMPORT) { + ump_dmabuf.fd = prime_fd; + ret = ioctl(ump_fd, UMP_IOC_DMABUF_IMPORT, &ump_dmabuf); + if (ret < 0) { + printf("failed to ioctl ump.\n"); + return; + } + + printf("ump handle = 0x%x\n", ump_dmabuf.ump_handle); + } + + close(ump_fd); + } - memset(usr_addr1, 0x88, gem1.size); +#if 0 +#ifdef GET_PHY_TEST + memset(&get_phy, 0, sizeof(struct drm_exynos_gem_get_phy)); + get_phy.gem_handle = handle; + exynos_gem_get_phy(fd, &get_phy); + printf("get_phy->phy_addr = 0x%llx, get_phy->size = 0x%llx\n", + get_phy.phy_addr, get_phy.size); + + memset(&phy_imp, 0, sizeof(struct drm_exynos_gem_phy_imp)); + phy_imp.phy_addr = get_phy.phy_addr; + phy_imp.size = get_phy.size; + exynos_gem_phy_imp(fd, &phy_imp); + printf("phy_imp->handle = 0x%x\n", phy_imp.gem_handle); #endif +#ifdef UMP_TEST /* get secure id for ump. */ gem_ump.gem_handle = handle; exynos_gem_get_ump(fd, &gem_ump); printf("secure id = %d\n", gem_ump.secure_id); +#endif +#endif + stride = width * 4; ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, &fb_id); if (ret) { fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); - return; + goto err; } x = 0; @@ -630,6 +1156,10 @@ set_mode(struct connector *c, int count, int page_flip) ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, &c[i].id, 1, c[i].mode); + + /* XXX: Actually check if this is needed */ + drmModeDirtyFB(fd, fb_id, NULL, 0); + x += c[i].mode->hdisplay; if (ret) { @@ -641,26 +1171,17 @@ set_mode(struct connector *c, int count, int page_flip) if (!page_flip) return; - /* for second gem object, INDIRECT_MODE would be used. */ - - gem2.size = 1024 * 600 * 4; - - /* allocate gem buffer. */ - ret = exynos_gem_create(fd, &gem2); - if (ret < 0) + ret = kms_create(fd, &kms); + if (ret) { + fprintf(stderr, "failed to create kms driver: %s\n", + strerror(-ret)); return; + } - handle = map_off2.handle = gem2.handle; - - /* get map offset. */ - ret = exynos_gem_map_offset(fd, &map_off2); - if (ret < 0) + if (create_test_buffer(kms, width, height, &stride, &other_bo)) return; - usr_addr2 = mmap(0, gem2.size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd, map_off2.offset); - - memset(usr_addr2, 0x0, gem2.size); + kms_bo_get_prop(other_bo, KMS_HANDLE, &handle); ret = drmModeAddFB(fd, width, height, 32, 32, stride, handle, &other_fb_id); if (ret) { @@ -672,8 +1193,12 @@ set_mode(struct connector *c, int count, int page_flip) if (c[i].mode == NULL) continue; - drmModePageFlip(fd, c[i].crtc, other_fb_id, - DRM_MODE_PAGE_FLIP_EVENT, &c[i]); + ret = drmModePageFlip(fd, c[i].crtc, other_fb_id, + DRM_MODE_PAGE_FLIP_EVENT, &c[i]); + if (ret) { + fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); + return; + } gettimeofday(&c[i].start, NULL); c[i].swap_count = 0; c[i].fb_id[0] = fb_id; @@ -707,65 +1232,128 @@ set_mode(struct connector *c, int count, int page_flip) drmHandleEvent(fd, &evctx); } - /* release user space memroy. */ -#if defined(INDIRECT_MAP) || defined(DIRECT_MAP) - munmap(usr_addr1, mmap1.size); -#endif - munmap(usr_addr2, gem2.size); + kms_bo_destroy(&other_bo); + kms_destroy(&kms); - args.handle = gem1.handle; +err: + if (exynos_test.mem_type == ALLOC_USERPTR) { + struct drm_gem_close gem_close; - /* relese gem buffer. */ - ret = exynos_gem_close(fd, &args); - if (ret < 0) - return; + gem_close.handle = handle; - args.handle = gem2.handle; - ret = exynos_gem_close(fd, &args); - if (ret < 0) - return; + free(usr_addr1); + drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &gem_close); + } else + exynos_bo_destroy(bo); } -extern char *optarg; -extern int optind, opterr, optopt; -static char optstr[] = "ecpmfs:v"; -void usage(char *name) +static int setup_exynos_gem_map_type(void) { - fprintf(stderr, "usage: %s [-ecpmf]\n", name); - fprintf(stderr, "\t-e\tlist encoders\n"); - fprintf(stderr, "\t-c\tlist connectors\n"); - fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); - fprintf(stderr, "\t-m\tlist modes\n"); - fprintf(stderr, "\t-f\tlist framebuffers\n"); - fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); - fprintf(stderr, "\t-s :\tset a mode\n"); - fprintf(stderr, "\t-s @:\tset a mode\n"); - fprintf(stderr, "\n\tDefault is to dump all info.\n"); - exit(0); + if (strncmp(exynos_test.scmd[2], "cache", 5) == 0) + exynos_test.map_type = ALLOC_MAP_C; + else if (strncmp(exynos_test.scmd[2], "noncache", 8) == 0) + exynos_test.map_type = ALLOC_MAP_NC; + else if (strncmp(exynos_test.scmd[2], "writecombine", 12) == 0) + exynos_test.map_type = ALLOC_MAP_WC; + else { + printf("invalid map type.\n"); + return -EINVAL; + } + + return 0; } -#define dump_resource(res) if (res) dump_##res() +static int setup_exynos_gem_cache_op_type(void) +{ + if (strncmp(exynos_test.scmd[2], "clean_range", 11) == 0) + exynos_test.cache_op_type |= CACHE_CLEAN_RANGE; + else if (strncmp(exynos_test.scmd[2], "inv_range", 9) == 0) + exynos_test.cache_op_type |= CACHE_INV_RANGE; + else if (strncmp(exynos_test.scmd[2], "flush_range", 11) == 0) + exynos_test.cache_op_type |= CACHE_FLUSH_RANGE; + else if (strncmp(exynos_test.scmd[2], "clean_all", 9) == 0) + exynos_test.cache_op_type &= ~CACHE_CLEAN_RANGE; /* all */ + else if (strncmp(exynos_test.scmd[2], "inv_all", 7) == 0) + exynos_test.cache_op_type &= ~CACHE_INV_RANGE; /* all */ + else if (strncmp(exynos_test.scmd[2], "flush_all", 9) == 0) + exynos_test.cache_op_type &= ~CACHE_FLUSH_RANGE; /* all */ + else { + printf("invalid cache op type.\n"); + return -EINVAL; + } -static int page_flipping_supported(int fd) + return 0; +} + +static int setup_exynos_gem_dmabuf_type(void) { - /*FIXME: generic ioctl needed? */ - return 1; -#if 0 - int ret, value; - struct drm_i915_getparam gp; + if (strncmp(exynos_test.scmd[2], "export", 6) == 0) + exynos_test.dmabuf_type |= DMABUF_EXPORT; + else if (strncmp(exynos_test.scmd[2], "import", 6) == 0) + exynos_test.dmabuf_type |= DMABUF_IMPORT; + else if (strncmp(exynos_test.scmd[2], "all", 3) == 0) + exynos_test.dmabuf_type |= DMABUF_ALL; + else { + printf("invalid dmabuf type.\n"); + return -EINVAL; + } - gp.param = I915_PARAM_HAS_PAGEFLIPPING; - gp.value = &value; + return 0; +} - ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp)); - if (ret) { - fprintf(stderr, "drm_i915_getparam: %m\n"); - return 0; +static int setup_exynos_gem_test(void) +{ + if (strncmp(exynos_test.scmd[0], "alloc", 5) == 0) { + exynos_test.cmd_type |= CMD_ALLOC; + + if (strncmp(exynos_test.scmd[1], "contig", 5) == 0) + exynos_test.mem_type = ALLOC_CONTIG; + else if (strncmp(exynos_test.scmd[1], "noncontig", 8) == 0) + exynos_test.mem_type = ALLOC_NONCONTIG; + else if (strncmp(exynos_test.scmd[1], "userptr", 7) == 0) + exynos_test.mem_type = ALLOC_USERPTR; + else { + printf("invalid option type.\n"); + return -EINVAL; + } + + return setup_exynos_gem_map_type(); + } else if (strncmp(exynos_test.scmd[0], "cache", 5) == 0) { + exynos_test.cmd_type |= CMD_CACHE; + + if (strncmp(exynos_test.scmd[1], "l1", 2) == 0) { + exynos_test.cache_type |= CACHE_L1; + } else if (strncmp(exynos_test.scmd[1], "l2", 2) == 0) { + exynos_test.cache_type |= CACHE_L2; + } else if (strncmp(exynos_test.scmd[1], "all", 3) == 0) { + exynos_test.cache_type |= CACHE_ALL_CACHES; + } else if (strncmp(exynos_test.scmd[1], "all_cores", 9) == 0) { + exynos_test.cache_type |= CACHE_ALL_CACHES_CORES; + } else { + printf("invalid option type.\n"); + return -EINVAL; + } + + return setup_exynos_gem_cache_op_type(); + } else if ((strncmp(exynos_test.scmd[0], "prime", 5) == 0) || + (strncmp(exynos_test.scmd[0], "ump", 3) == 0)) { + exynos_test.cmd_type |= (strncmp(exynos_test.scmd[0], + "prime", 5) == 0) ? + CMD_PRIME : CMD_UMP; + + if (strncmp(exynos_test.scmd[1], "dmabuf", 6) == 0) + return setup_exynos_gem_dmabuf_type(); + else { + printf("invalid option type.\n"); + return -EINVAL; + } + } else { + printf("invalid command type.\n"); + return -EINVAL; } - return *gp.value; -#endif + return 0; } int main(int argc, char **argv) @@ -773,12 +1361,13 @@ int main(int argc, char **argv) int c; int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; int test_vsync = 0; - char *modules[] = { "exynos-drm", "i915", "radeon", "nouveau" }; + char *modules[] = { "exynos", "i915", "radeon", "nouveau" }; char *modeset = NULL; - int i, count = 0; + int i, count = 0, private_test = 0, cmd_cnt = 0, ret = 0; struct connector con_args[2]; - + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { switch (c) { case 'e': @@ -810,7 +1399,23 @@ int main(int argc, char **argv) &con_args[count].crtc, con_args[count].mode_str) != 3) usage(argv[0]); - count++; + count++; + break; + case 't': + modeset = strdup(optarg); + exynos_test.scmd[cmd_cnt++] = strtok(modeset, ":~"); + while (exynos_test.scmd[cmd_cnt++] = strtok(NULL, ":~")); + + cmd_cnt--; + if (cmd_cnt != 3 && cmd_cnt != 5) + usage(argv[0]); + + ret = setup_exynos_gem_test(); + if (ret < 0) + return ret; + + private_test = 1; + cmd_cnt = 0; break; default: usage(argv[0]); @@ -856,7 +1461,11 @@ int main(int argc, char **argv) dump_resource(framebuffers); if (count > 0) { - set_mode(con_args, count, test_vsync); + if (private_test) + test_exynos_gem(con_args, count, test_vsync); + else + set_mode(con_args, count, test_vsync); + getchar(); } diff --git a/tests/gemtest/ump.h b/tests/gemtest/ump.h new file mode 100644 index 0000000..8e45825 --- /dev/null +++ b/tests/gemtest/ump.h @@ -0,0 +1,262 @@ +/* + * This confidential and proprietary software may be used only as + * authorised by a licensing agreement from ARM Limited + * (C) COPYRIGHT 2008-2010 ARM Limited + * ALL RIGHTS RESERVED + * The entire notice above must be reproduced on all authorised + * copies and copies may only be made to the extent permitted + * by a licensing agreement from ARM Limited. + */ + +/** + * @file ump.h + * + * This file contains the user space part of the UMP API. + */ + +#ifndef _UNIFIED_MEMORY_PROVIDER_H_ +#define _UNIFIED_MEMORY_PROVIDER_H_ + + +/** @defgroup ump_user_space_api UMP User Space API + * @{ */ + + +#include "ump_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * External representation of a UMP handle in user space. + */ +typedef void * ump_handle; + +/** + * Typedef for a secure ID, a system wide identificator for UMP memory buffers. + */ +typedef unsigned int ump_secure_id; + +/** + * Value to indicate an invalid UMP memory handle. + */ +#define UMP_INVALID_MEMORY_HANDLE ((ump_handle)0) + +/** + * Value to indicate an invalid secure Id. + */ +#define UMP_INVALID_SECURE_ID ((ump_secure_id)-1) + +/** + * UMP error codes for user space. + */ +typedef enum +{ + UMP_OK, /**< indicates success */ + UMP_ERROR, /**< indicates failure */ +} ump_result; + + +/** + * Opens and initializes the UMP library. + * + * This function must be called at least once before calling any other UMP API functions. + * Each open is reference counted and must be matched with a call to @ref ump_close "ump_close". + * + * @see ump_close + * + * @return UMP_OK indicates success, UMP_ERROR indicates failure. + */ +UMP_API_EXPORT ump_result ump_open(void); + + +/** + * Terminate the UMP library. + * + * This must be called once for every successful @ref ump_open "ump_open". The UMP library is + * terminated when, and only when, the last open reference to the UMP interface is closed. + * + * @see ump_open + */ +UMP_API_EXPORT void ump_close(void); + + +/** + * Retrieves the secure ID for the specified UMP memory. + * + * This identificator is unique across the entire system, and uniquely identifies + * the specified UMP memory. This identificator can later be used through the + * @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id" or + * @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id" + * functions in order to access this UMP memory, for instance from another process. + * + * @note There is a kernel space equivalent function called @ref ump_dd_secure_id_get "ump_dd_secure_id_get" + * + * @see ump_handle_create_from_secure_id + * @see ump_dd_handle_create_from_secure_id + * @see ump_dd_secure_id_get + * + * @param mem Handle to UMP memory. + * + * @return Returns the secure ID for the specified UMP memory. + */ +UMP_API_EXPORT ump_secure_id ump_secure_id_get(ump_handle mem); + + +/** + * Retrieves a handle to allocated UMP memory. + * + * The usage of UMP memory is reference counted, so this will increment the reference + * count by one for the specified UMP memory. + * Use @ref ump_reference_release "ump_reference_release" when there is no longer any + * use for the retrieved handle. + * + * @note There is a kernel space equivalent function called @ref ump_dd_handle_create_from_secure_id "ump_dd_handle_create_from_secure_id" + * + * @see ump_reference_release + * @see ump_dd_handle_create_from_secure_id + * + * @param secure_id The secure ID of the UMP memory to open, that can be retrieved using the @ref ump_secure_id_get "ump_secure_id_get " function. + * + * @return UMP_INVALID_MEMORY_HANDLE indicates failure, otherwise a valid handle is returned. + */ +UMP_API_EXPORT ump_handle ump_handle_create_from_secure_id(ump_secure_id secure_id); + + +/** + * Retrieves the actual size of the specified UMP memory. + * + * The size is reported in bytes, and is typically page aligned. + * + * @note There is a kernel space equivalent function called @ref ump_dd_size_get "ump_dd_size_get" + * + * @see ump_dd_size_get + * + * @param mem Handle to UMP memory. + * + * @return Returns the allocated size of the specified UMP memory, in bytes. + */ +UMP_API_EXPORT unsigned long ump_size_get(ump_handle mem); + + +/** + * Read from specified UMP memory. + * + * Another way of reading from (and writing to) UMP memory is to use the + * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" to retrieve + * a CPU mapped pointer to the memory. + * + * @see ump_mapped_pointer_get + * + * @param dst Destination buffer. + * @param src Handle to UMP memory to read from. + * @param offset Where to start reading, given in bytes. + * @param length How much to read, given in bytes. + */ +UMP_API_EXPORT void ump_read(void * dst, ump_handle src, unsigned long offset, unsigned long length); + + +/** + * Write to specified UMP memory. + * + * Another way of writing to (and reading from) UMP memory is to use the + * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" to retrieve + * a CPU mapped pointer to the memory. + * + * @see ump_mapped_pointer_get + * + * @param dst Handle to UMP memory to write to. + * @param offset Where to start writing, given in bytes. + * @param src Buffer to read from. + * @param length How much to write, given in bytes. + */ +UMP_API_EXPORT void ump_write(ump_handle dst, unsigned long offset, const void * src, unsigned long length); + + +/** + * Retrieves a memory mapped pointer to the specified UMP memory. + * + * This function retrieves a memory mapped pointer to the specified UMP memory, + * that can be used by the CPU. Every successful call to + * @ref ump_mapped_pointer_get "ump_mapped_pointer_get" is reference counted, + * and must therefor be followed by a call to + * @ref ump_mapped_pointer_release "ump_mapped_pointer_release " when the + * memory mapping is no longer needed. + * + * @note Systems without a MMU for the CPU only return the physical address, because no mapping is required. + * + * @see ump_mapped_pointer_release + * + * @param mem Handle to UMP memory. + * + * @return NULL indicates failure, otherwise a CPU mapped pointer is returned. + */ +UMP_API_EXPORT void * ump_mapped_pointer_get(ump_handle mem); + + +/** + * Releases a previously mapped pointer to the specified UMP memory. + * + * The CPU mapping of the specified UMP memory memory is reference counted, + * so every call to @ref ump_mapped_pointer_get "ump_mapped_pointer_get" must + * be matched with a call to this function when the mapping is no longer needed. + * + * The CPU mapping is not removed before all references to the mapping is released. + * + * @note Systems without a MMU must still implement this function, even though no unmapping should be needed. + * + * @param mem Handle to UMP memory. + */ +UMP_API_EXPORT void ump_mapped_pointer_release(ump_handle mem); + + +/** + * Adds an extra reference to the specified UMP memory. + * + * This function adds an extra reference to the specified UMP memory. This function should + * be used every time a UMP memory handle is duplicated, that is, assigned to another ump_handle + * variable. The function @ref ump_reference_release "ump_reference_release" must then be used + * to release each copy of the UMP memory handle. + * + * @note You are not required to call @ref ump_reference_add "ump_reference_add" + * for UMP handles returned from + * @ref ump_handle_create_from_secure_id "ump_handle_create_from_secure_id", + * because these handles are already reference counted by this function. + * + * @note There is a kernel space equivalent function called @ref ump_dd_reference_add "ump_dd_reference_add" + * + * @see ump_dd_reference_add + * + * @param mem Handle to UMP memory. + */ +UMP_API_EXPORT void ump_reference_add(ump_handle mem); + + +/** + * Releases a reference from the specified UMP memory. + * + * This function should be called once for every reference to the UMP memory handle. + * When the last reference is released, all resources associated with this UMP memory + * handle are freed. + * + * @note There is a kernel space equivalent function called @ref ump_dd_reference_release "ump_dd_reference_release" + * + * @see ump_dd_reference_release + * + * @param mem Handle to UMP memory. + */ +UMP_API_EXPORT void ump_reference_release(ump_handle mem); + + +#ifdef __cplusplus +} +#endif + + +/** @} */ /* end group ump_user_space_api */ + + +#endif /*_UNIFIED_MEMORY_PROVIDER_H_ */ diff --git a/tests/gemtest/ump_platform.h b/tests/gemtest/ump_platform.h new file mode 100644 index 0000000..9285aef --- /dev/null +++ b/tests/gemtest/ump_platform.h @@ -0,0 +1,46 @@ +/* + * This confidential and proprietary software may be used only as + * authorised by a licensing agreement from ARM Limited + * (C) COPYRIGHT 2008-2010 ARM Limited + * ALL RIGHTS RESERVED + * The entire notice above must be reproduced on all authorised + * copies and copies may only be made to the extent permitted + * by a licensing agreement from ARM Limited. + */ + +/** + * @file ump_platform.h + * + * This file should define UMP_API_EXPORT, + * which dictates how the UMP user space API should be exported/imported. + * Modify this file, if needed, to match your platform setup. + */ + +#ifndef __UMP_PLATFORM_H__ +#define __UMP_PLATFORM_H__ + +/** @addtogroup ump_user_space_api + * @{ */ + +/** + * A define which controls how UMP user space API functions are imported and exported. + * This define should be set by the implementor of the UMP API. + */ +#if defined(_WIN32) + +#define UMP_API_EXPORT + +#elif defined(__SYMBIAN32__) + +#define UMP_API_EXPORT IMPORT_C + +#else + +#define UMP_API_EXPORT + +#endif + +/** @} */ /* end group ump_user_space_api */ + + +#endif /* __UMP_PLATFORM_H__ */ diff --git a/tests/gemtest/ump_ref_drv.h b/tests/gemtest/ump_ref_drv.h new file mode 100644 index 0000000..32716ec --- /dev/null +++ b/tests/gemtest/ump_ref_drv.h @@ -0,0 +1,59 @@ +/* + * This confidential and proprietary software may be used only as + * authorised by a licensing agreement from ARM Limited + * (C) COPYRIGHT 2009-2010 ARM Limited + * ALL RIGHTS RESERVED + * The entire notice above must be reproduced on all authorised + * copies and copies may only be made to the extent permitted + * by a licensing agreement from ARM Limited. + */ + +/** + * @file ump_ref_drv.h + * + * Reference driver extensions to the UMP user space API for allocating UMP memory + */ + +#ifndef _UNIFIED_MEMORY_PROVIDER_REF_DRV_H_ +#define _UNIFIED_MEMORY_PROVIDER_REF_DRV_H_ + +#include "ump.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UMP_IOCTL_NR 0x90 + +typedef enum +{ + /* This enum must match with the IOCTL enum in ump_ioctl.h */ + UMP_REF_DRV_CONSTRAINT_NONE = 0, + UMP_REF_DRV_CONSTRAINT_PHYSICALLY_LINEAR = 1, + UMP_REF_DRV_CONSTRAINT_USE_CACHE = 128, +} ump_alloc_constraints; + +typedef enum +{ + UMP_MSYNC_CLEAN = 0 , + UMP_MSYNC_CLEAN_AND_INVALIDATE = 1, + UMP_MSYNC_READOUT_CACHE_ENABLED = 128, +} ump_cpu_msync_op; + +struct ump_uk_dmabuf { + void *ctx; + int fd; + size_t size; + uint32_t ump_handle; +}; + +#define _UMP_IOC_DMABUF_IMPORT 8 + +#define UMP_IOC_DMABUF_IMPORT _IOW(UMP_IOCTL_NR, _UMP_IOC_DMABUF_IMPORT,\ + struct ump_uk_dmabuf) + +#ifdef __cplusplus +} +#endif + +#endif /*_UNIFIED_MEMORY_PROVIDER_REF_DRV_H_ */ diff --git a/tests/ipptest/Makefile.am b/tests/ipptest/Makefile.am new file mode 100644 index 0000000..cae05c9 --- /dev/null +++ b/tests/ipptest/Makefile.am @@ -0,0 +1,21 @@ +AM_CFLAGS = \ + -I$(top_srcdir)/include/drm \ + -I$(top_srcdir)/libkms/ \ + -I$(top_srcdir)/exynos/ \ + -I$(top_srcdir) \ + $(CAIRO_CFLAGS) + +noinst_PROGRAMS = \ + ipptest + +ipptest_SOURCES = \ + fimctest.c \ + gem.c \ + util.c \ + fimc.c + +ipptest_LDADD = \ + $(top_builddir)/libdrm.la \ + $(top_builddir)/libkms/libkms.la \ + $(top_builddir)/exynos/libdrm_exynos.la \ + $(CAIRO_LIBS) diff --git a/tests/ipptest/fimc.c b/tests/ipptest/fimc.c new file mode 100644 index 0000000..089b707 --- /dev/null +++ b/tests/ipptest/fimc.c @@ -0,0 +1,538 @@ +/* + * DRM based fimc test program + * Copyright 2012 Samsung Electronics + * Eunchul Kim + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos_drm.h" +#include "fimctest.h" +#include "gem.h" +#include "util.h" + +#include "drm_fourcc.h" + +static int exynos_drm_ipp_property(int fd, + struct drm_exynos_ipp_property *property, + struct drm_exynos_sz *def_sz, + enum drm_exynos_ipp_cmd cmd, + enum drm_exynos_degree degree) +{ + struct drm_exynos_pos crop_pos = {0, 0, def_sz->hsize, def_sz->vsize}; + struct drm_exynos_pos scale_pos = {0, 0, def_sz->hsize, def_sz->vsize}; + struct drm_exynos_sz src_sz = {def_sz->hsize, def_sz->vsize}; + struct drm_exynos_sz dst_sz = {def_sz->hsize, def_sz->vsize}; + int ret = 0; + + memset(property, 0x00, sizeof(struct drm_exynos_ipp_property)); + + switch(cmd) { + case IPP_CMD_M2M: + property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; + property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; + property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_XRGB8888; + property->config[EXYNOS_DRM_OPS_SRC].pos = crop_pos; + property->config[EXYNOS_DRM_OPS_SRC].sz = src_sz; + + property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST; + property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_DST].degree = degree; + property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888; + if (property->config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90) { + dst_sz.hsize = def_sz->vsize; + dst_sz.vsize = def_sz->hsize; + + scale_pos.w = def_sz->vsize; + scale_pos.h = def_sz->hsize; + } + property->config[EXYNOS_DRM_OPS_DST].pos = scale_pos; + property->config[EXYNOS_DRM_OPS_DST].sz = dst_sz; + break; + case IPP_CMD_WB: + property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; + property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; + property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_YUV444; + property->config[EXYNOS_DRM_OPS_SRC].pos = crop_pos; + property->config[EXYNOS_DRM_OPS_SRC].sz = src_sz; + + property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST; + property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_DST].degree = degree; + property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888; + if (property->config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90) { + dst_sz.hsize = def_sz->vsize; + dst_sz.vsize = def_sz->hsize; + + scale_pos.w = def_sz->vsize; + scale_pos.h = def_sz->hsize; + } + property->config[EXYNOS_DRM_OPS_DST].pos = scale_pos; + property->config[EXYNOS_DRM_OPS_DST].sz = dst_sz; + break; + case IPP_CMD_OUT: + default: + ret = -EINVAL; + return ret; + } + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_PROPERTY, property); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_PROPERTY : %s\n", + strerror(errno)); + + return ret; +} + +static int exynos_drm_ipp_buf(int fd, struct drm_exynos_ipp_buf *buf, + enum drm_exynos_ops_id ops_id, + enum drm_exynos_ipp_buf_ctrl ctrl, + int id, + unsigned int gem_handle) +{ + int ret = 0; + + memset(buf, 0x00, sizeof(struct drm_exynos_ipp_buf)); + + buf->ops_id = ops_id; + buf->buf_ctrl = ctrl; + buf->user_data = 0; + buf->id = id; + buf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle; + buf->handle[EXYNOS_DRM_PLANAR_CB] = 0; + buf->handle[EXYNOS_DRM_PLANAR_CR] = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_BUF, buf); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_BUF[id:%d][ctrl:%d] : %s\n", + ops_id, ctrl, strerror(errno)); + + return ret; +} + +static int exynos_drm_ipp_ctrl(int fd, struct drm_exynos_ipp_ctrl *ctrl, + enum drm_exynos_ipp_cmd cmd, unsigned int use) +{ + int ret = 0; + + memset(ctrl, 0x00, sizeof(struct drm_exynos_ipp_ctrl)); + + ctrl->cmd = cmd; + ctrl->use = use; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_CTRL, ctrl); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_CTRL[cmd:%d][use:%d] : %s\n", + cmd, use, strerror(errno)); + + return ret; +} + +void fimc_m2m_set_mode(struct connector *c, int count, int page_flip, + long int *usec) +{ + struct drm_exynos_ipp_property property; + struct drm_exynos_ipp_ctrl ctrl; + struct drm_exynos_sz def_sz = {720, 1280}; + struct drm_exynos_ipp_buf buf1, buf2; + unsigned int width=720, height=1280, stride; + int ret, i, j, x; + struct drm_exynos_gem_create gem1, gem2; + struct drm_exynos_gem_mmap mmap1, mmap2; + void *usr_addr1, *usr_addr2; + struct timeval begin, end; + struct drm_gem_close args; + char filename[100]; + + /* For property */ + ret = exynos_drm_ipp_property(fd, &property, &def_sz, IPP_CMD_M2M, EXYNOS_DRM_DEGREE_90); + if (ret) { + fprintf(stderr, "failed to ipp property\n"); + return; + } + + /* For mode */ + width = height = 0; + for (i = 0; i < count; i++) { + connector_find_mode(&c[i]); + if (c[i].mode == NULL) continue; + width += c[i].mode->hdisplay; + if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay; + } + stride = width * 4; + + /* For source buffer */ + ret = util_gem_create_mmap(fd, &gem1, &mmap1, stride * height); + if (ret) { + fprintf(stderr, "failed to gem create mmap: %s\n", + strerror(errno)); + if (ret == -1) return; + else if (ret == -2) goto err_gem_mmap1; + } + usr_addr1 = (void *)(unsigned long)mmap1.mapped; + + util_draw_buffer(usr_addr1, 1, width, height, stride, 0); + + sprintf(filename, "/opt/media/fimc_m2m_src.bmp", j); + util_write_bmp(filename, usr_addr1, width, height); + + /* For destination buffer */ + ret = util_gem_create_mmap(fd, &gem2, &mmap2, stride * height); + if (ret) { + fprintf(stderr, "failed to gem create mmap: %s\n", + strerror(errno)); + if (ret == -1) goto err_gem_create2; + else if (ret == -2) goto err_gem_mmap2; + } + usr_addr2 = (void*)(unsigned long)mmap2.mapped; + + util_draw_buffer(usr_addr2, 0, 0, 0, 0, mmap2.size); + + sprintf(filename, "/opt/media/fimc_m2m_dst.bmp", j); + util_write_bmp(filename, usr_addr2, height, width); + + /* For source buffer map to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, + IPP_BUF_CTRL_MAP, 0, gem1.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf src map\n"); + goto err_ipp_buf_map1; + } + + /* For destination buffer map to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_MAP, 0, gem2.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst map\n"); + goto err_ipp_buf_map2; + } + + for (j = 0; j < MAX_LOOP; j++) { + /* Start */ + gettimeofday(&begin, NULL); + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 1); + if (ret) { + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_M2M start\n"); + goto err_ipp_ctrl_start; + } + + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + fprintf(stderr, "select timed out or error.\n"); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + gettimeofday(&end, NULL); + usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + + (end.tv_usec - begin.tv_usec); + + sprintf(filename, "/opt/media/fimc_m2m_%d.bmp", j); + util_write_bmp(filename, usr_addr2, height, width); + + break; + } + + /* For destination buffer queue to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_QUEUE, 0, gem2.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst queue\n"); + goto err_ipp_ctrl_start; + } + } + + /* For source buffer unmap to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, + IPP_BUF_CTRL_UNMAP, 0, gem1.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf src unmap\n"); + goto err_ipp_buf_unmap; + } + + /* For destination buffer unmap to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_UNMAP, 0, gem2.handle); + if (ret < 0) { + fprintf(stderr, "failed to ipp buf dst unmap\n"); + goto err_ipp_buf_unmap; + } + + /* Stop */ + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 0); + if (ret) { + fprintf(stderr, "failed to ipp ctrl IPP_CMD_M2M stop\n"); + goto err_ipp_buf_unmap; + } + + munmap(usr_addr2, mmap2.size); + munmap(usr_addr1, mmap1.size); + + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem2.handle; + exynos_gem_close(fd, &args); + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem1.handle; + exynos_gem_close(fd, &args); + + return; + +err_ipp_buf_unmap: + exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 0); +err_ipp_ctrl_start: + exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, IPP_BUF_CTRL_UNMAP, + 0, gem2.handle); +err_ipp_buf_map2: + exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, IPP_BUF_CTRL_UNMAP, + 0, gem1.handle); +err_ipp_buf_map1: + munmap(usr_addr2, mmap2.size); +err_gem_mmap2: + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem2.handle; + exynos_gem_close(fd, &args); +err_gem_create2: + munmap(usr_addr1, mmap1.size); +err_gem_mmap1: + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem1.handle; + exynos_gem_close(fd, &args); +} + +int fimc_event_handler(struct drm_exynos_ipp_buf *buf, struct drm_exynos_gem_create *gem, + void **usr_addr, unsigned int width, unsigned int height) +{ + char buffer[1024]; + int len, i; + struct drm_event *e; + struct drm_exynos_ipp_event *ipp_event; + char filename[100]; + int ret = 0; + static bmp_idx = 0; + + len = read(fd, buffer, sizeof buffer); + if (len == 0) + return 0; + if (len < sizeof *e) + return -1; + + i = 0; + while (i < len) { + e = (struct drm_event *) &buffer[i]; + switch (e->type) { + case DRM_EXYNOS_IPP_EVENT: + ipp_event = (struct drm_exynos_ipp_event *) e; + + fprintf(stderr, "%s:buf_idx[%d]bmp_idx[%d]\n", __func__, ipp_event->buf_idx, bmp_idx++); + sprintf(filename, "/opt/media/fimc_wb_%d.bmp", bmp_idx); + util_write_bmp(filename, usr_addr[ipp_event->buf_idx], width, height); + + /* For destination buffer queue to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf[ipp_event->buf_idx], EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_QUEUE, ipp_event->buf_idx, gem[ipp_event->buf_idx].handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst queue\n"); + goto err_ipp_ctrl_close; + } + break; + default: + break; + } + i += e->length; + } + +err_ipp_ctrl_close: + return ret; +} + +void fimc_wb_set_mode(struct connector *c, int count, int page_flip, + long int *usec) +{ + struct drm_exynos_pos def_pos = {0, 0, 720, 1280}; + struct drm_exynos_sz def_sz = {720, 1280}; + struct drm_exynos_ipp_property property; + struct drm_exynos_gem_create gem[MAX_BUF]; + struct drm_exynos_gem_mmap mmap[MAX_BUF]; + struct drm_exynos_ipp_buf buf[MAX_BUF]; + void *usr_addr[MAX_BUF]; + struct drm_exynos_ipp_ctrl ctrl; + unsigned int width, height, stride; + int ret, i, j; + struct timeval begin, end; + struct drm_gem_close args; + + /* For property */ + ret = exynos_drm_ipp_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_0); + if (ret) { + fprintf(stderr, "failed to ipp property\n"); + return; + } + + /* For mode */ + width = height = 0; + for (i = 0; i < count; i++) { + connector_find_mode(&c[i]); + if (c[i].mode == NULL) continue; + width += c[i].mode->hdisplay; + if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay; + } + stride = width * 4; + + /* For destination buffer */ + for (i = 0; i < MAX_BUF; i++) { + ret = util_gem_create_mmap(fd, &gem[i], &mmap[i], stride * height); + if (ret) { + fprintf(stderr, "failed to gem create mmap: %s\n", + strerror(errno)); + if (ret == -1) return; + else if (ret == -2) goto err_ipp_ctrl_close; + } + usr_addr[i] = (void *)(unsigned long)mmap[i].mapped; + /* For destination buffer map to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf[i], EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_MAP, i, gem[i].handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst map\n"); + goto err_ipp_ctrl_close; + } + } + + + /* Start */ + gettimeofday(&begin, NULL); + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_WB, 1); + if (ret) { + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_WB start\n"); + goto err_ipp_ctrl_close; + } + + j = 0; + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + fprintf(stderr, "select timed out or error.\n"); + continue; + } else if (FD_ISSET(0, &fds)) { + fprintf(stderr, "select error.\n"); + break; + } + + gettimeofday(&end, NULL); + usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + + (end.tv_usec - begin.tv_usec); + + if (property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_90 || + property.config[EXYNOS_DRM_OPS_DST].degree == EXYNOS_DRM_DEGREE_270) { + if(fimc_event_handler(buf, gem, usr_addr, height, width) < 0) + break; + } else { + if(fimc_event_handler(buf, gem, usr_addr, width, height) < 0) + break; + } + + if (++j > MAX_LOOP) + break; + + if (j == HALF_LOOP) { + /* Stop */ + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_WB, 0); + if (ret) { + fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n"); + goto err_ipp_ctrl_close; + } + + /* For property */ + ret = exynos_drm_ipp_property(fd, &property, &def_sz, IPP_CMD_WB, EXYNOS_DRM_DEGREE_90); + if (ret) { + fprintf(stderr, "failed to ipp property\n"); + goto err_ipp_ctrl_close; + } + + /* Start */ + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_WB, 1); + if (ret) { + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_WB start\n"); + goto err_ipp_ctrl_close; + } + } + + gettimeofday(&begin, NULL); + } + +err_ipp_ctrl_close: + /* For destination buffer unmap to IPP */ + for (i = 0; i < MAX_BUF; i++) { + ret = exynos_drm_ipp_buf(fd, &buf[i], EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_UNMAP, i, gem[i].handle); + if (ret < 0) + fprintf(stderr, "failed to ipp buf dst unmap\n"); + } + + /* Stop */ + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_WB, 0); + if (ret) + fprintf(stderr, "failed to ipp ctrl IPP_CMD_WB stop\n"); + + for (i = 0; i < MAX_BUF; i++) { + munmap(usr_addr[i], mmap[i].size); + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem[i].handle; + exynos_gem_close(fd, &args); + } + + return; +} + +void fimc_output_set_mode(struct connector *c, int count, int page_flip, + long int *usec) +{ + fprintf(stderr, "not supported. please wait v2\n"); +} + diff --git a/tests/ipptest/fimc.h b/tests/ipptest/fimc.h new file mode 100644 index 0000000..81e0e00 --- /dev/null +++ b/tests/ipptest/fimc.h @@ -0,0 +1,11 @@ +#ifndef __FIMC_H__ +#define __FIMC_H__ + +void fimc_m2m_set_mode(struct connector *c, int count, int page_flip, + long int *usec); +void fimc_wb_set_mode(struct connector *c, int count, int page_flip, + long int *usec); +void fimc_output_set_mode(struct connector *c, int count, int page_flip, + long int *usec); + +#endif diff --git a/tests/ipptest/fimctest.c b/tests/ipptest/fimctest.c new file mode 100644 index 0000000..dde9a49 --- /dev/null +++ b/tests/ipptest/fimctest.c @@ -0,0 +1,478 @@ +/* + * DRM based fimc test program + * Copyright 2012 Samsung Electronics + * Eunchul Kim + * + * 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 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. + */ + +/* + * This fairly simple test program dumps output in a similar format to the + * "xrandr" tool everyone knows & loves. It's necessarily slightly different + * since the kernel separates outputs into encoder and connector structures, + * each with their own unique ID. The program also allows test testing of the + * memory management and mode setting APIs by allowing the user to specify a + * connector and mode to use for mode setting. If all works as expected, a + * blue background should be painted on the monitor attached to the specified + * connector after the selected mode is set. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libkms.h" + +#include "exynos_drm.h" + +#include "fimctest.h" +#include "fimc.h" + +drmModeRes *resources; +int fd, modes; + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name { + int type; + char *name; +}; + +#define type_name_fn(res) \ +char * res##_str(int type) { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (res##_names[i].type == type) \ + return res##_names[i].name; \ + } \ + return "(invalid)"; \ +} + +struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +type_name_fn(encoder_type) + +struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +type_name_fn(connector_status) + +struct type_name connector_type_names[] = { + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, +}; + +type_name_fn(connector_type) + +static void dump_encoders(void) +{ + drmModeEncoder *encoder; + int i; + + printf("Encoders:\n"); + printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); + for (i = 0; i < resources->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + continue; + } + printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", + encoder->encoder_id, + encoder->crtc_id, + encoder_type_str(encoder->encoder_type), + encoder->possible_crtcs, + encoder->possible_clones); + drmModeFreeEncoder(encoder); + } + printf("\n"); +} + +static void dump_mode(drmModeModeInfo *mode) +{ + printf(" %s %d %d %d %d %d %d %d %d %d\n", + mode->name, + mode->vrefresh, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); +} + +static void dump_props(drmModeConnector *connector) +{ + drmModePropertyPtr props; + int i; + + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); + printf("\t%s, flags %d\n", props->name, props->flags); + drmModeFreeProperty(props); + } +} + +static void dump_connectors(void) +{ + drmModeConnector *connector; + int i, j; + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + continue; + } + + printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + for (j = 0; j < connector->count_encoders; j++) + printf("%s%d", j > 0 ? ", " : "", + connector->encoders[j]); + printf("\n"); + + if (!connector->count_modes) + continue; + + printf(" modes:\n"); + printf(" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot)\n"); + for (j = 0; j < connector->count_modes; j++) + dump_mode(&connector->modes[j]); + + printf(" props:\n"); + dump_props(connector); + + drmModeFreeConnector(connector); + } + printf("\n"); +} + +static void dump_crtcs(void) +{ + drmModeCrtc *crtc; + int i; + + printf("CRTCs:\n"); + printf("id\tfb\tpos\tsize\n"); + for (i = 0; i < resources->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, resources->crtcs[i]); + + if (!crtc) { + fprintf(stderr, "could not get crtc %i: %s\n", + resources->crtcs[i], strerror(errno)); + continue; + } + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + dump_mode(&crtc->mode); + + drmModeFreeCrtc(crtc); + } + printf("\n"); +} + +static void dump_framebuffers(void) +{ + drmModeFB *fb; + int i; + + printf("Frame buffers:\n"); + printf("id\tsize\tpitch\n"); + for (i = 0; i < resources->count_fbs; i++) { + fb = drmModeGetFB(fd, resources->fbs[i]); + + if (!fb) { + fprintf(stderr, "could not get fb %i: %s\n", + resources->fbs[i], strerror(errno)); + continue; + } + printf("%u\t(%ux%u)\t%u\n", + fb->fb_id, + fb->width, fb->height, + fb->pitch); + + drmModeFreeFB(fb); + } + printf("\n"); +} + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ + +void connector_find_mode(struct connector *c) +{ + drmModeConnector *connector; + int i, j; + + /* First, find the connector & mode */ + c->mode = NULL; + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + drmModeFreeConnector(connector); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != c->id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = &connector->modes[j]; + if (!strcmp(c->mode->name, c->mode_str)) + break; + } + + /* Found it, break out */ + if (c->mode) + break; + + drmModeFreeConnector(connector); + } + + if (!c->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + return; + } + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!c->encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(c->encoder); + continue; + } + + if (c->encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(c->encoder); + } + + if (c->crtc == -1) + c->crtc = c->encoder->crtc_id; +} + +extern char *optarg; +extern int optind, opterr, optopt; +static char optstr[] = "ecpmfo:s:v"; + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-ecpmf]\n", name); + fprintf(stderr, "\t-e\tlist encoders\n"); + fprintf(stderr, "\t-c\tlist connectors\n"); + fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-m\tlist modes\n"); + fprintf(stderr, "\t-f\tlist framebuffers\n"); + fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); + fprintf(stderr, "\t-o\tlist of operation id : 0: M2M, 1: Writeback, 2: Output\n"); + fprintf(stderr, "\t-s :\tset a mode\n"); + fprintf(stderr, "\t-s @:\tset a mode\n"); + fprintf(stderr, "\n\tDefault is to dump all info.\n"); + exit(0); +} + +#define dump_resource(res) if (res) dump_##res() + +int main(int argc, char **argv) +{ + int c; + int operations = 0, encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + int test_vsync = 0; + char *modules[] = {"exynos", "i915", "radeon", "nouveau", "vmwgfx"}; + char *modeset = NULL; + int i, count = 0; + struct connector con_args[2]; + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'e': + encoders = 1; + break; + case 'c': + connectors = 1; + break; + case 'p': + crtcs = 1; + break; + case 'm': + modes = 1; + break; + case 'f': + framebuffers = 1; + break; + case 'v': + test_vsync = 1; + break; + case 'o': + if (optarg) + sscanf(optarg, "%d", &operations); + break; + case 's': + modeset = strdup(optarg); + con_args[count].crtc = -1; + if (sscanf(optarg, "%d:%64s", + &con_args[count].id, + con_args[count].mode_str) != 2 && + sscanf(optarg, "%d@%d:%64s", + &con_args[count].id, + &con_args[count].crtc, + con_args[count].mode_str) != 3) + usage(argv[0]); + count++; + break; + default: + usage(argv[0]); + break; + } + } + + if (argc == 1) + encoders = connectors = crtcs = modes = framebuffers = 1; + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + printf("trying to load module %s...", modules[i]); + fd = drmOpen(modules[i], NULL); + if (fd < 0) { + printf("failed.\n"); + } else { + printf("success.\n"); + break; + } + } + + if (i == ARRAY_SIZE(modules)) { + fprintf(stderr, "failed to load any modules, aborting.\n"); + return -1; + } + + resources = drmModeGetResources(fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + drmClose(fd); + return 1; + } + + dump_resource(encoders); + dump_resource(connectors); + dump_resource(crtcs); + dump_resource(framebuffers); + + if (count > 0) { + long int sum = 0, usec[MAX_LOOP]; + + switch(operations) { + case 0: + fimc_m2m_set_mode(con_args, count, test_vsync, usec); + break; + case 1: + fimc_wb_set_mode(con_args, count, test_vsync, usec); + break; + case 2: + fimc_output_set_mode(con_args, count, test_vsync, usec); + break; + default: + break; + } + + for (i = 0; i < MAX_LOOP; i++) { + printf("[%d] : %d\n", i + 1, usec[i]); + sum += usec[i]; + } + printf("fimc : cma\n"); + printf("avg : [%d]\n", sum / MAX_LOOP); + getchar(); + } + + drmModeFreeResources(resources); + + return 0; +} diff --git a/tests/ipptest/fimctest.h b/tests/ipptest/fimctest.h new file mode 100644 index 0000000..2dd31fa --- /dev/null +++ b/tests/ipptest/fimctest.h @@ -0,0 +1,27 @@ +#ifndef __FIMCTEST_H__ +#define __FIMCTEST_H__ + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#define MAX_LOOP 20 +#define HALF_LOOP 10 +#define MAX_BUF 3 + +struct connector { + uint32_t id; + char mode_str[64]; + drmModeModeInfo *mode; + drmModeEncoder *encoder; + int crtc; + unsigned int fb_id[2], current_fb_id; + struct timeval start; + + int swap_count; +}; + +extern int fd; + +extern void connector_find_mode(struct connector *c); + +#endif diff --git a/tests/ipptest/gem.c b/tests/ipptest/gem.c new file mode 100644 index 0000000..40f192a --- /dev/null +++ b/tests/ipptest/gem.c @@ -0,0 +1,92 @@ +/* + * DRM based fimc test program + * Copyright 2012 Samsung Electronics + * Eunchul Kim + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "libkms.h" + +#include "exynos_drm.h" + +int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem) +{ + int ret = 0; + + if (!gem) { + fprintf(stderr, "gem object is null.\n"); + return -EFAULT; + } + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem); + if (ret < 0) + fprintf(stderr, "failed to create gem buffer: %s\n", + strerror(-ret)); + return ret; +} + +int exynos_gem_userptr(int fd, struct drm_exynos_gem_userptr *gem_userptr) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_USERPTR, gem_userptr); + if (ret < 0) + fprintf(stderr, "failed to userptr: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap); + if (ret < 0) + fprintf(stderr, "failed to mmap: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_close(int fd, struct drm_gem_close *gem_close) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close); + if (ret < 0) + fprintf(stderr, "failed to close: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_cache_op(int fd, struct drm_exynos_gem_cache_op *cache_op) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CACHE_OP, cache_op); + if (ret < 0) + fprintf(stderr, "failed to cache op: %s\n", strerror(-ret)); + return ret; +} diff --git a/tests/ipptest/gem.h b/tests/ipptest/gem.h new file mode 100644 index 0000000..2a5ed1d --- /dev/null +++ b/tests/ipptest/gem.h @@ -0,0 +1,12 @@ +#ifndef __GEM_H__ +#define __GEM_H__ + +extern int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem); +extern int exynos_gem_userptr(int fd, + struct drm_exynos_gem_userptr *gem_userptr); +extern int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap); +extern int exynos_gem_close(int fd, struct drm_gem_close *gem_close); +extern int exynos_gem_cache_op(int fd, + struct drm_exynos_gem_cache_op *cache_op); + +#endif diff --git a/tests/ipptest/util.c b/tests/ipptest/util.c new file mode 100644 index 0000000..745c212 --- /dev/null +++ b/tests/ipptest/util.c @@ -0,0 +1,132 @@ +/* + * DRM based fimc test program + * Copyright 2012 Samsung Electronics + * Eunchul Kim + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "exynos_drm.h" +#include "gem.h" + +int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, + struct drm_exynos_gem_mmap *mmap, + unsigned int size) +{ + /* initialize structure for gem create */ + memset(gem, 0x00, sizeof(struct drm_exynos_gem_create)); + gem->size = size; + + if (exynos_gem_create(fd, gem) < 0) { + fprintf(stderr, "failed to gem create: %s\n", strerror(errno)); + return -1; + } + + /* initialize structure for gem mmap */ + memset(mmap, 0x00, sizeof(struct drm_exynos_gem_mmap)); + mmap->handle = gem->handle; + mmap->size = gem->size; + + if (exynos_gem_mmap(fd, mmap) < 0) { + fprintf(stderr, "failed to gem mmap: %s\n", strerror(errno)); + return -2; + } + + return 0; +} + +void util_draw_buffer(void *addr, unsigned int stripe, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int size) +{ + if (stripe == 1) { + int i, j; + unsigned int *fb_ptr; + div_t d; + + for (j = 0; j < height; j++) { + fb_ptr = (unsigned int *)((char *)addr + j * stride); + for (i = 0; i < width; i++) { + d = div(i, width); + fb_ptr[i] = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + } + } + } else + memset(addr, 0x77, size); +} + +int util_write_bmp(const char *file, const void *data, unsigned int width, + unsigned int height) +{ + int i; + unsigned int * blocks; + FILE *fp; + struct { + unsigned char magic[2]; + } bmpfile_magic = { {'B', 'M'} }; + struct { + unsigned int filesz; + unsigned short creator1; + unsigned short creator2; + unsigned int bmp_offset; + } bmpfile_header = { 0, 0, 0, 0x36 }; + struct { + unsigned int header_sz; + unsigned int width; + unsigned int height; + unsigned short nplanes; + unsigned short bitspp; + unsigned int compress_type; + unsigned int bmp_bytesz; + unsigned int hres; + unsigned int vres; + unsigned int ncolors; + unsigned int nimpcolors; + } bmp_dib_v3_header_t = { 0x28, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0 }; + + fp = fopen(file, "wb"); + if (fp == NULL) return -1; + + bmpfile_header.filesz = sizeof(bmpfile_magic) + sizeof(bmpfile_header) + + sizeof(bmp_dib_v3_header_t) + width * height * 4; + bmp_dib_v3_header_t.header_sz = sizeof(bmp_dib_v3_header_t); + bmp_dib_v3_header_t.width = width; + bmp_dib_v3_header_t.height = -height; + bmp_dib_v3_header_t.nplanes = 1; + bmp_dib_v3_header_t.bmp_bytesz = width * height * 4; + + fwrite(&bmpfile_magic, sizeof(bmpfile_magic), 1, fp); + fwrite(&bmpfile_header, sizeof(bmpfile_header), 1, fp); + fwrite(&bmp_dib_v3_header_t, sizeof(bmp_dib_v3_header_t), 1, fp); + + blocks = (unsigned int*)data; + for (i = 0; i < height * width; i++) + fwrite(&blocks[i], 4, 1, fp); + + fclose(fp); + return 0; +} diff --git a/tests/ipptest/util.h b/tests/ipptest/util.h new file mode 100644 index 0000000..e1ffcca --- /dev/null +++ b/tests/ipptest/util.h @@ -0,0 +1,12 @@ +#ifndef __UTIL_H__ +#define __UTIL_H__ + +extern int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, + struct drm_exynos_gem_mmap *mmap, + unsigned int size); +extern void util_draw_buffer(void *addr, unsigned int stripe, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int size); +extern int util_write_bmp(const char *file, const void *data, + unsigned int width, unsigned int height); +#endif diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am index ea39685..2191242 100644 --- a/tests/modetest/Makefile.am +++ b/tests/modetest/Makefile.am @@ -1,7 +1,6 @@ AM_CFLAGS = \ -I$(top_srcdir)/include/drm \ -I$(top_srcdir)/libkms/ \ - -I$(top_srcdir)/slp/ \ -I$(top_srcdir) \ $(CAIRO_CFLAGS) @@ -13,5 +12,4 @@ modetest_SOURCES = \ modetest_LDADD = \ $(top_builddir)/libdrm.la \ $(top_builddir)/libkms/libkms.la \ - $(top_builddir)/slp/libdrm_slp.la \ $(CAIRO_LIBS) diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c old mode 100755 new mode 100644 index 0c49ad7..dc84cf3 --- a/tests/modetest/modetest.c +++ b/tests/modetest/modetest.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -51,16 +52,9 @@ #include "xf86drm.h" #include "xf86drmMode.h" +#include "drm_fourcc.h" #include "libkms.h" -#define TEST_SLP -#ifdef TEST_SLP -#include "drm_slp_bufmgr.h" -#include "exynos_drm.h" - -static drm_slp_bufmgr slp_bufmgr=NULL; -#endif - #ifdef HAVE_CAIRO #include #include @@ -78,7 +72,7 @@ struct type_name { #define type_name_fn(res) \ char * res##_str(int type) { \ - int i; \ + unsigned int i; \ for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ if (res##_names[i].type == type) \ return res##_names[i].name; \ @@ -152,7 +146,7 @@ void dump_encoders(void) void dump_mode(drmModeModeInfo *mode) { - printf(" %s %d %d %d %d %d %d %d %d %d\n", + printf("\t%s %d %d %d %d %d %d %d %d %d\n", mode->name, mode->vrefresh, mode->hdisplay, @@ -166,16 +160,98 @@ void dump_mode(drmModeModeInfo *mode) } static void -dump_props(drmModeConnector *connector) +dump_blob(uint32_t blob_id) +{ + uint32_t i; + unsigned char *blob_data; + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, blob_id); + if (!blob) + return; + + blob_data = blob->data; + + for (i = 0; i < blob->length; i++) { + if (i % 16 == 0) + printf("\n\t\t\t"); + printf("%.2hhx", blob_data[i]); + } + printf("\n"); + + drmModeFreePropertyBlob(blob); +} + +static void +dump_prop(uint32_t prop_id, uint64_t value) { - drmModePropertyPtr props; int i; + drmModePropertyPtr prop; + + prop = drmModeGetProperty(fd, prop_id); - for (i = 0; i < connector->count_props; i++) { - props = drmModeGetProperty(fd, connector->props[i]); - printf("\t%s, flags %d\n", props->name, props->flags); - drmModeFreeProperty(props); + printf("\t%d", prop_id); + if (!prop) { + printf("\n"); + return; } + + printf(" %s:\n", prop->name); + + printf("\t\tflags:"); + if (prop->flags & DRM_MODE_PROP_PENDING) + printf(" pending"); + if (prop->flags & DRM_MODE_PROP_RANGE) + printf(" range"); + if (prop->flags & DRM_MODE_PROP_IMMUTABLE) + printf(" immutable"); + if (prop->flags & DRM_MODE_PROP_ENUM) + printf(" enum"); + if (prop->flags & DRM_MODE_PROP_BITMASK) + printf(" bitmask"); + if (prop->flags & DRM_MODE_PROP_BLOB) + printf(" blob"); + printf("\n"); + + if (prop->flags & DRM_MODE_PROP_RANGE) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRIu64, prop->values[i]); + printf("\n"); + } + + if (prop->flags & DRM_MODE_PROP_ENUM) { + printf("\t\tenums:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=%llu", prop->enums[i].name, + prop->enums[i].value); + printf("\n"); + } else if (prop->flags & DRM_MODE_PROP_BITMASK) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=0x%llx", prop->enums[i].name, + (1LL << prop->enums[i].value)); + printf("\n"); + } else { + assert(prop->count_enums == 0); + } + + if (prop->flags & DRM_MODE_PROP_BLOB) { + printf("\t\tblobs:\n"); + for (i = 0; i < prop->count_blobs; i++) + dump_blob(prop->blob_ids[i]); + printf("\n"); + } else { + assert(prop->count_blobs == 0); + } + + printf("\t\tvalue:"); + if (prop->flags & DRM_MODE_PROP_BLOB) + dump_blob(value); + else + printf(" %"PRIu64"\n", value); + + drmModeFreeProperty(prop); } void dump_connectors(void) @@ -206,17 +282,18 @@ void dump_connectors(void) printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]); printf("\n"); - if (!connector->count_modes) - continue; - - printf(" modes:\n"); - printf(" name refresh (Hz) hdisp hss hse htot vdisp " - "vss vse vtot)\n"); - for (j = 0; j < connector->count_modes; j++) - dump_mode(&connector->modes[j]); - - printf(" props:\n"); - dump_props(connector); + if (connector->count_modes) { + printf(" modes:\n"); + printf("\tname refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot)\n"); + for (j = 0; j < connector->count_modes; j++) + dump_mode(&connector->modes[j]); + + printf(" props:\n"); + for (j = 0; j < connector->count_props; j++) + dump_prop(connector->props[j], + connector->prop_values[j]); + } drmModeFreeConnector(connector); } @@ -226,7 +303,9 @@ void dump_connectors(void) void dump_crtcs(void) { drmModeCrtc *crtc; + drmModeObjectPropertiesPtr props; int i; + uint32_t j; printf("CRTCs:\n"); printf("id\tfb\tpos\tsize\n"); @@ -245,6 +324,19 @@ void dump_crtcs(void) crtc->width, crtc->height); dump_mode(&crtc->mode); + printf(" props:\n"); + props = drmModeObjectGetProperties(fd, crtc->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (props) { + for (j = 0; j < props->count_props; j++) + dump_prop(props->props[j], + props->prop_values[j]); + drmModeFreeObjectProperties(props); + } else { + printf("\tcould not get crtc properties: %s\n", + strerror(errno)); + } + drmModeFreeCrtc(crtc); } printf("\n"); @@ -275,6 +367,64 @@ void dump_framebuffers(void) printf("\n"); } +static void dump_planes(void) +{ + drmModeObjectPropertiesPtr props; + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + unsigned int i, j; + + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return; + } + + printf("Planes:\n"); + printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n"); + for (i = 0; i < plane_resources->count_planes; i++) { + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + continue; + } + + printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n", + ovr->plane_id, ovr->crtc_id, ovr->fb_id, + ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, + ovr->gamma_size); + + if (!ovr->count_formats) + continue; + + printf(" formats:"); + for (j = 0; j < ovr->count_formats; j++) + printf(" %4.4s", (char *)&ovr->formats[j]); + printf("\n"); + + printf(" props:\n"); + props = drmModeObjectGetProperties(fd, ovr->plane_id, + DRM_MODE_OBJECT_PLANE); + if (props) { + for (j = 0; j < props->count_props; j++) + dump_prop(props->props[j], + props->prop_values[j]); + drmModeFreeObjectProperties(props); + } else { + printf("\tcould not get plane properties: %s\n", + strerror(errno)); + } + + drmModeFreePlane(ovr); + } + printf("\n"); + + drmModeFreePlaneResources(plane_resources); + return; +} + /* * Mode setting with the kernel interfaces is a bit of a chore. * First you have to find the connector in question and make sure the @@ -288,11 +438,19 @@ struct connector { drmModeModeInfo *mode; drmModeEncoder *encoder; int crtc; + int pipe; unsigned int fb_id[2], current_fb_id; struct timeval start; int swap_count; -}; +}; + +struct plane { + uint32_t con_id; /* the id of connector to bind to */ + uint32_t w, h; + unsigned int fb_id; + char format_str[5]; /* need to leave room for terminating \0 */ +}; static void connector_find_mode(struct connector *c) @@ -359,6 +517,15 @@ connector_find_mode(struct connector *c) if (c->crtc == -1) c->crtc = c->encoder->crtc_id; + + /* and figure out which crtc index it is: */ + for (i = 0; i < resources->count_crtcs; i++) { + if (c->crtc == resources->crtcs[i]) { + c->pipe = i; + break; + } + } + } static struct kms_bo * @@ -441,26 +608,6 @@ make_pwetty(void *data, int width, int height, int stride) #endif } -#ifdef TEST_SLP -static drm_slp_bo -make_drmbuf_from_kms(struct kms_bo* bo) -{ - unsigned int hKms; - drm_slp_bo drmBo = NULL; - - kms_bo_get_prop(bo, KMS_HANDLE, &hKms); - drmBo = drm_slp_bo_attach(slp_bufmgr, NULL, NULL, 0, &hKms); - if(!drmBo) - { - fprintf(stderr, "Fail attach\n"); - return drmBo; - } - - fprintf(stderr, "DRM_BO(%p) from KMS(%p, %d)\n", drmBo, bo, hKms); - return drmBo; -} -#endif - static int create_test_buffer(struct kms_driver *kms, int width, int height, int *stride_out, @@ -469,19 +616,11 @@ create_test_buffer(struct kms_driver *kms, struct kms_bo *bo; int ret, i, j, stride; void *virtual; -#ifdef TEST_SLP - drm_slp_bo drmBo; -#endif - bo = allocate_buffer(kms, width, height, &stride); if (!bo) return -1; -#ifdef TEST_SLP - drmBo = make_drmbuf_from_kms(bo); - virtual = drm_slp_bo_map(drmBo, DRM_SLP_DEVICE_CPU, DRM_SLP_OPTION_READ|DRM_SLP_OPTION_WRITE); -#else ret = kms_bo_map(bo, &virtual); if (ret) { fprintf(stderr, "failed to map buffer: %s\n", @@ -489,7 +628,6 @@ create_test_buffer(struct kms_driver *kms, kms_bo_destroy(&bo); return -1; } -#endif /* paint the buffer with colored tiles */ for (j = 0; j < height; j++) { @@ -504,11 +642,7 @@ create_test_buffer(struct kms_driver *kms, make_pwetty(virtual, width, height, stride); -#ifdef TEST_SLP - drm_slp_bo_unmap(drmBo, DRM_SLP_DEVICE_CPU); -#else kms_bo_unmap(bo); -#endif *bo_out = bo; *stride_out = stride; @@ -575,13 +709,245 @@ page_flip_handler(int fd, unsigned int frame, } } +/* swap these for big endian.. */ +#define RED 2 +#define GREEN 1 +#define BLUE 0 + +static void +fill420(unsigned char *y, unsigned char *u, unsigned char *v, + int cs /*chroma pixel stride */, + int n, int width, int height, int stride) +{ + int i, j; + + /* paint the buffer with colored tiles, in blocks of 2x2 */ + for (j = 0; j < height; j+=2) { + unsigned char *y1p = y + j * stride; + unsigned char *y2p = y1p + stride; + unsigned char *up = u + (j/2) * stride * cs / 2; + unsigned char *vp = v + (j/2) * stride * cs / 2; + + for (i = 0; i < width; i+=2) { + div_t d = div(n+i+j, width); + uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); + unsigned char *rgbp = (unsigned char *)&rgb; + unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]); + + *(y2p++) = *(y1p++) = y; + *(y2p++) = *(y1p++) = y; + + *up = (rgbp[BLUE] - y) * 0.565 + 128; + *vp = (rgbp[RED] - y) * 0.713 + 128; + up += cs; + vp += cs; + } + } +} + static void -set_mode(struct connector *c, int count, int page_flip) +fill422(unsigned char *virtual, int n, int width, int height, int stride) +{ + int i, j; + /* paint the buffer with colored tiles */ + for (j = 0; j < height; j++) { + uint8_t *ptr = (uint8_t*)((char*)virtual + j * stride); + for (i = 0; i < width; i++) { + div_t d = div(n+i+j, width); + uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); + unsigned char *rgbp = (unsigned char *)&rgb; + unsigned char y = (0.299 * rgbp[RED]) + (0.587 * rgbp[GREEN]) + (0.114 * rgbp[BLUE]); + + *(ptr++) = y; + *(ptr++) = (rgbp[BLUE] - y) * 0.565 + 128; + *(ptr++) = y; + *(ptr++) = (rgbp[RED] - y) * 0.713 + 128; + } + } +} + +static void +fill1555(unsigned char *virtual, int n, int width, int height, int stride) +{ + int i, j; + /* paint the buffer with colored tiles */ + for (j = 0; j < height; j++) { + uint16_t *ptr = (uint16_t*)((char*)virtual + j * stride); + for (i = 0; i < width; i++) { + div_t d = div(n+i+j, width); + uint32_t rgb = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6); + unsigned char *rgbp = (unsigned char *)&rgb; + + *(ptr++) = 0x8000 | + (rgbp[RED] >> 3) << 10 | + (rgbp[GREEN] >> 3) << 5 | + (rgbp[BLUE] >> 3); + } + } +} + +static int +set_plane(struct kms_driver *kms, struct connector *c, struct plane *p) +{ + drmModePlaneRes *plane_resources; + drmModePlane *ovr; + uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ + uint32_t plane_id = 0; + struct kms_bo *plane_bo; + uint32_t plane_flags = 0, format; + int ret, crtc_x, crtc_y, crtc_w, crtc_h; + unsigned int i; + + /* find an unused plane which can be connected to our crtc */ + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) { + fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", + strerror(errno)); + return -1; + } + + for (i = 0; i < plane_resources->count_planes && !plane_id; i++) { + ovr = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!ovr) { + fprintf(stderr, "drmModeGetPlane failed: %s\n", + strerror(errno)); + return -1; + } + + if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id) + plane_id = ovr->plane_id; + + drmModeFreePlane(ovr); + } + + fprintf(stderr, "testing %dx%d@%s overlay plane\n", + p->w, p->h, p->format_str); + + if (!plane_id) { + fprintf(stderr, "failed to find plane!\n"); + return -1; + } + + if (!strcmp(p->format_str, "XR24")) { + if (create_test_buffer(kms, p->w, p->h, &pitches[0], &plane_bo)) + return -1; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + format = DRM_FORMAT_XRGB8888; + } else { + void *virtual; + + /* TODO: this always allocates a buffer for 32bpp RGB.. but for + * YUV formats, we don't use all of it.. since 4bytes/pixel is + * worst case, so live with it for now and just don't use all + * the buffer: + */ + plane_bo = allocate_buffer(kms, p->w, p->h, &pitches[0]); + if (!plane_bo) + return -1; + + ret = kms_bo_map(plane_bo, &virtual); + if (ret) { + fprintf(stderr, "failed to map buffer: %s\n", + strerror(-ret)); + kms_bo_destroy(&plane_bo); + return -1; + } + + /* just testing a limited # of formats to test single + * and multi-planar path.. would be nice to add more.. + */ + if (!strcmp(p->format_str, "YUYV")) { + pitches[0] = p->w * 2; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + + fill422(virtual, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_YUYV; + } else if (!strcmp(p->format_str, "NV12")) { + pitches[0] = p->w; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + pitches[1] = p->w; + offsets[1] = p->w * p->h; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]); + + fill420(virtual, virtual+offsets[1], virtual+offsets[1]+1, + 2, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_NV12; + } else if (!strcmp(p->format_str, "YV12")) { + pitches[0] = p->w; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + pitches[1] = p->w / 2; + offsets[1] = p->w * p->h; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[1]); + pitches[2] = p->w / 2; + offsets[2] = offsets[1] + (p->w * p->h) / 4; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[2]); + + fill420(virtual, virtual+offsets[1], virtual+offsets[2], + 1, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_YVU420; + } else if (!strcmp(p->format_str, "XR15")) { + pitches[0] = p->w * 2; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + + fill1555(virtual, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_XRGB1555; + } else if (!strcmp(p->format_str, "AR15")) { + pitches[0] = p->w * 2; + offsets[0] = 0; + kms_bo_get_prop(plane_bo, KMS_HANDLE, &handles[0]); + + fill1555(virtual, 0, p->w, p->h, pitches[0]); + + format = DRM_FORMAT_ARGB1555; + } else { + fprintf(stderr, "Unknown format: %s\n", p->format_str); + return -1; + } + + kms_bo_unmap(plane_bo); + } + + /* just use single plane format for now.. */ + if (drmModeAddFB2(fd, p->w, p->h, format, + handles, pitches, offsets, &p->fb_id, plane_flags)) { + fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); + return -1; + } + + /* ok, boring.. but for now put in middle of screen: */ + crtc_x = c->mode->hdisplay / 3; + crtc_y = c->mode->vdisplay / 3; + crtc_w = crtc_x; + crtc_h = crtc_y; + + /* note src coords (last 4 args) are in Q16 format */ + if (drmModeSetPlane(fd, plane_id, c->crtc, p->fb_id, + plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, + 0, 0, p->w << 16, p->h << 16)) { + fprintf(stderr, "failed to enable plane: %s\n", + strerror(errno)); + return -1; + } + + return 0; +} + +static void +set_mode(struct connector *c, int count, struct plane *p, int plane_count, + int page_flip) { struct kms_driver *kms; struct kms_bo *bo, *other_bo; unsigned int fb_id, other_fb_id; - int i, ret, width, height, x, stride; + int i, j, ret, width, height, x, stride; unsigned handle; drmEventContext evctx; @@ -603,15 +969,6 @@ set_mode(struct connector *c, int count, int page_flip) return; } -#ifdef TEST_SLP - slp_bufmgr = drm_slp_bufmgr_init(fd, NULL); - if(!slp_bufmgr) - { - fprintf(stderr, "failed to make slp_bufmgr\n"); - return; - } -#endif - if (create_test_buffer(kms, width, height, &stride, &bo)) return; @@ -643,6 +1000,12 @@ set_mode(struct connector *c, int count, int page_flip) fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); return; } + + /* if we have a plane/overlay to show, set that up now: */ + for (j = 0; j < plane_count; j++) + if (p[j].con_id == c[i].id) + if (set_plane(kms, &c[i], &p[j])) + return; } if (!page_flip) @@ -726,26 +1089,28 @@ set_mode(struct connector *c, int count, int page_flip) extern char *optarg; extern int optind, opterr, optopt; -static char optstr[] = "ecpmfs:v"; +static char optstr[] = "ecpmfs:P:v"; void usage(char *name) { fprintf(stderr, "usage: %s [-ecpmf]\n", name); fprintf(stderr, "\t-e\tlist encoders\n"); fprintf(stderr, "\t-c\tlist connectors\n"); - fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); fprintf(stderr, "\t-m\tlist modes\n"); fprintf(stderr, "\t-f\tlist framebuffers\n"); fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); fprintf(stderr, "\t-s :\tset a mode\n"); fprintf(stderr, "\t-s @:\tset a mode\n"); + fprintf(stderr, "\t-P :x\tset a plane\n"); + fprintf(stderr, "\t-P :x@\tset a plane\n"); fprintf(stderr, "\n\tDefault is to dump all info.\n"); exit(0); } #define dump_resource(res) if (res) dump_##res() -static int page_flipping_supported(int fd) +static int page_flipping_supported(void) { /*FIXME: generic ioctl needed? */ return 1; @@ -769,12 +1134,13 @@ static int page_flipping_supported(int fd) int main(int argc, char **argv) { int c; - int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; int test_vsync = 0; - char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos-drm" }; - char *modeset = NULL; - int i, count = 0; + char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos" }; + unsigned int i; + int count = 0, plane_count = 0; struct connector con_args[2]; + struct plane plane_args[2] = {0}; opterr = 0; while ((c = getopt(argc, argv, optstr)) != -1) { @@ -787,6 +1153,7 @@ int main(int argc, char **argv) break; case 'p': crtcs = 1; + planes = 1; break; case 'm': modes = 1; @@ -798,7 +1165,6 @@ int main(int argc, char **argv) test_vsync = 1; break; case 's': - modeset = strdup(optarg); con_args[count].crtc = -1; if (sscanf(optarg, "%d:%64s", &con_args[count].id, @@ -810,6 +1176,20 @@ int main(int argc, char **argv) usage(argv[0]); count++; break; + case 'P': + strcpy(plane_args[plane_count].format_str, "XR24"); + if (sscanf(optarg, "%d:%dx%d@%4s", + &plane_args[plane_count].con_id, + &plane_args[plane_count].w, + &plane_args[plane_count].h, + plane_args[plane_count].format_str) != 4 && + sscanf(optarg, "%d:%dx%d", + &plane_args[plane_count].con_id, + &plane_args[plane_count].w, + &plane_args[plane_count].h) != 3) + usage(argv[0]); + plane_count++; + break; default: usage(argv[0]); break; @@ -817,7 +1197,7 @@ int main(int argc, char **argv) } if (argc == 1) - encoders = connectors = crtcs = modes = framebuffers = 1; + encoders = connectors = crtcs = planes = modes = framebuffers = 1; for (i = 0; i < ARRAY_SIZE(modules); i++) { printf("trying to load module %s...", modules[i]); @@ -830,7 +1210,7 @@ int main(int argc, char **argv) } } - if (test_vsync && !page_flipping_supported(fd)) { + if (test_vsync && !page_flipping_supported()) { fprintf(stderr, "page flipping not supported by drm.\n"); return -1; } @@ -851,10 +1231,11 @@ int main(int argc, char **argv) dump_resource(encoders); dump_resource(connectors); dump_resource(crtcs); + dump_resource(planes); dump_resource(framebuffers); if (count > 0) { - set_mode(con_args, count, test_vsync); + set_mode(con_args, count, plane_args, plane_count, test_vsync); getchar(); } diff --git a/tests/planetest/planetest.c b/tests/planetest/planetest.c deleted file mode 100644 index 3d05003..0000000 --- a/tests/planetest/planetest.c +++ /dev/null @@ -1,468 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "xf86drm.h" -#include "xf86drmMode.h" -#include "libkms.h" -#include "exynos_drm.h" - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) - -drmModeRes *resources; -int fd; - -struct connector { - uint32_t id; - char mode_str[64]; - drmModeModeInfo *mode; - drmModeEncoder *encoder; - int crtc; - unsigned int fb_id[2], current_fb_id; - struct timeval start; - - int swap_count; -}; - -struct fb_data { - struct kms_driver *kms; - struct kms_bo *bo; - unsigned int fb_id; -}; - -static void -connector_find_mode(struct connector *c) -{ - drmModeConnector *connector; - int i, j; - - /* First, find the connector & mode */ - c->mode = NULL; - for (i = 0; i < resources->count_connectors; i++) { - connector = drmModeGetConnector(fd, resources->connectors[i]); - - if (!connector) { - fprintf(stderr, "could not get connector %i: %s\n", - resources->connectors[i], strerror(errno)); - drmModeFreeConnector(connector); - continue; - } - - if (!connector->count_modes) { - drmModeFreeConnector(connector); - continue; - } - - if (connector->connector_id != c->id) { - drmModeFreeConnector(connector); - continue; - } - - for (j = 0; j < connector->count_modes; j++) { - c->mode = &connector->modes[j]; - if (!strcmp(c->mode->name, c->mode_str)) - break; - } - - /* Found it, break out */ - if (c->mode) - break; - - drmModeFreeConnector(connector); - } - - if (!c->mode) { - fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); - return; - } - - /* Now get the encoder */ - for (i = 0; i < resources->count_encoders; i++) { - c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); - - if (!c->encoder) { - fprintf(stderr, "could not get encoder %i: %s\n", - resources->encoders[i], strerror(errno)); - drmModeFreeEncoder(c->encoder); - continue; - } - - if (c->encoder->encoder_id == connector->encoder_id) - break; - - drmModeFreeEncoder(c->encoder); - } - - if (c->crtc == -1) - c->crtc = c->encoder->crtc_id; -} - -static struct kms_bo * -allocate_buffer(struct kms_driver *kms, - int width, int height, unsigned *stride) -{ - struct kms_bo *bo; - unsigned bo_attribs[] = { - KMS_WIDTH, 0, - KMS_HEIGHT, 0, - KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8, - KMS_TERMINATE_PROP_LIST - }; - int ret; - - bo_attribs[1] = width; - bo_attribs[3] = height; - - ret = kms_bo_create(kms, bo_attribs, &bo); - if (ret) { - fprintf(stderr, "failed to alloc buffer: %s\n", - strerror(-ret)); - return NULL; - } - - ret = kms_bo_get_prop(bo, KMS_PITCH, stride); - if (ret) { - fprintf(stderr, "failed to retreive buffer stride: %s\n", - strerror(-ret)); - kms_bo_destroy(&bo); - return NULL; - } - - return bo; -} - -static int -create_grey_buffer(struct kms_driver *kms, - int width, int height, int *stride_out, - struct kms_bo **bo_out, int color) -{ - struct kms_bo *bo; - int size, ret; - unsigned stride; - void *virtual; - - bo = allocate_buffer(kms, width, height, &stride); - if (!bo) - return -1; - - ret = kms_bo_map(bo, &virtual); - if (ret) { - fprintf(stderr, "failed to map buffer: %s\n", - strerror(-ret)); - kms_bo_destroy(&bo); - return -1; - } - - size = stride * height; - memset(virtual, color, size); - kms_bo_unmap(bo); - - *bo_out = bo; - *stride_out = stride; - - return 0; -} - -static int -connector_find_plane(struct connector *c) -{ - drmModePlaneRes *plane_resources; - drmModePlane *ovr; - uint32_t id = 0; - int i; - - plane_resources = drmModeGetPlaneResources(fd); - if (!plane_resources) { - fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", - strerror(errno)); - return 0; - } - - for (i = 0; i < plane_resources->count_planes; i++) { - ovr = drmModeGetPlane(fd, plane_resources->planes[i]); - if (!ovr) { - fprintf(stderr, "drmModeGetPlane failed: %s\n", - strerror(errno)); - continue; - } - - if (ovr->possible_crtcs & (1<plane_id; - drmModeFreePlane(ovr); - break; - } - drmModeFreePlane(ovr); - } - - return id; -} - -static int -connector_find_plane2(struct connector *c, unsigned int *plane_id) -{ - drmModePlaneRes *plane_resources; - drmModePlane *ovr; - int i; - - plane_resources = drmModeGetPlaneResources(fd); - if (!plane_resources) { - fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", - strerror(errno)); - return -1; - } - - for (i = 0; i < plane_resources->count_planes; i++) { - plane_id[i] = 0; - - ovr = drmModeGetPlane(fd, plane_resources->planes[i]); - if (!ovr) { - fprintf(stderr, "drmModeGetPlane failed: %s\n", - strerror(errno)); - continue; - } - - if (ovr->possible_crtcs & (1 << 0)) - plane_id[i] = ovr->plane_id; - drmModeFreePlane(ovr); - } - - return 0; -} - -static struct fb_data *make_fb(int w, int h, int color) -{ - struct fb_data *fb_data; - struct kms_driver *kms; - struct kms_bo *bo; - unsigned int fb_id; - unsigned handle; - int stride; - int err; - - fb_data = malloc(sizeof(struct fb_data)); - if (!fb_data) - return NULL; - - memset(fb_data, 0, sizeof(struct fb_data)); - - err = kms_create(fd, &kms); - if (err) { - fprintf(stderr, "failed to create kms driver: %s\n", - strerror(-err)); - goto err_alloc; - } - - if (create_grey_buffer(kms, w, h, &stride, &bo, color)) - goto err_alloc; - - kms_bo_get_prop(bo, KMS_HANDLE, &handle); - err = drmModeAddFB(fd, w, h, 32, 32, stride, handle, &fb_id); - if (err) { - fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); - goto err_alloc; - } - - fb_data->fb_id = fb_id; - fb_data->kms = kms; - fb_data->bo = bo; - - return fb_data; - -err_alloc: - free(fb_data); - return NULL; -} - -static int exynos_plane_set_zpos(int fd, unsigned int plane_id, int zpos) -{ - struct drm_exynos_plane_set_zpos zpos_req; - int ret; - - zpos_req.plane_id = plane_id; - zpos_req.zpos = zpos; - - ret = ioctl(fd, DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS, &zpos_req); - if (ret < 0) { - fprintf(stderr, "failed to set plane zpos: %s\n", - strerror(-ret)); - return ret; - } - - return 0; -} - -#define PLANE_NR 5 -static void planetest_start(int nr, int start_plane, int crtc, int connector) -{ - struct connector c; - struct fb_data *fb_data[PLANE_NR]; - unsigned int plane_id[PLANE_NR]; - int height; - int width; - int x; - int y; - int i; - int ret; - - c.id = connector; - c.crtc = crtc; - - if (nr < 1 || nr > PLANE_NR) { - fprintf(stderr, "wrong plane count\n"); - return; - } - - if (start_plane < 0 || start_plane > (nr -1) ) { - fprintf(stderr, "Wrong start plane\n"); - return; - } - - connector_find_mode(&c); - - if (c.mode == NULL) { - fprintf(stderr, "mode is NULL\n"); - return; - } - - width = c.mode->hdisplay; - height = c.mode->vdisplay; - - width /= 8; - height /= 8; - x = width; - y = height; - - ret = connector_find_plane2(&c, plane_id); - if (ret < 0) - goto err; - - for (i = start_plane; i < nr; i++) { - if (!plane_id[i]) - continue; - - fb_data[i] = make_fb(width, height, 0x30 + 0x20 * i); - if (!fb_data[i]) - return; - - if (exynos_plane_set_zpos(fd, plane_id[i], i)) - goto err; - - if (drmModeSetPlane(fd, plane_id[i], c.crtc, fb_data[i]->fb_id, - 0, x, y, width, height, - 0, 0, width, height)) { - fprintf(stderr, "failed to enable plane: %s\n", - strerror(errno)); - goto err; - } - - x += width - 30; - y += height - 30; - width += 40; - height += 40; - } - - getchar(); - -err: - for (i = start_plane; i < nr; i++) { - if (fb_data[i]) { - kms_bo_destroy(&fb_data[i]->bo); - kms_destroy(&fb_data[i]->kms); - free(fb_data[i]); - } - - if (!plane_id[i]) - continue; - - if (drmModeSetPlane(fd, plane_id[i], c.crtc, - 0, 0, 0, 0, /* fb_id, flags, crtc_x, crtc_y */ - 0, 0, /* crtc_w, crtc_h */ - 0, 0, 0, 0 /* src_XXX */)) { - fprintf(stderr, "failed to enable plane: %s\n", - strerror(errno)); - goto err; - } - } -} - -static void help(void) -{ - printf("Usage: ./planetest [OPTION]\n" - " [OPTION]\n" - " -s @//\n" - " -h Usage\n" - "\n" - "Default: connector 11, crtc 3, plane_count 5, start_plane 1\n"); - exit(0); -} - -static char optstr[] = "hs:"; - -int main(int argc, char **argv) -{ - char *modules[] = { "exynos-drm" }; - int opt; - int i, connector_id, nr, start_plane; - uint32_t crtc_id; - - // default option (LCD) - crtc_id = 3; - connector_id = 11; - nr = 5; - start_plane = 1; - - /* parse args */ - opterr = 0; - while ((opt = getopt(argc, argv, optstr)) != -1) { - switch (opt) { - case 's': - if (sscanf(optarg, "%d@%d/%d/%d", - &connector_id, - &crtc_id, - &nr, - &start_plane) != 4) { - help(); - break; - } - break; - case 'h': - default: - help(); - break; - } - break; - } - - for (i = 0; i < ARRAY_SIZE(modules); i++) { - printf("trying to load module %s...", modules[i]); - fd = drmOpen(modules[i], NULL); - if (fd < 0) { - printf("failed.\n"); - } else { - printf("success.\n"); - break; - } - } - - resources = drmModeGetResources(fd); - if (!resources) { - fprintf(stderr, "drmModeGetResources failed: %s\n", - strerror(errno)); - drmClose(fd); - return 1; - } - - planetest_start(nr, start_plane, crtc_id, connector_id); - - /* TODO */ - - drmModeFreeResources(resources); - - return 0; -} diff --git a/tests/proptest/Makefile.am b/tests/proptest/Makefile.am new file mode 100644 index 0000000..f81a3c0 --- /dev/null +++ b/tests/proptest/Makefile.am @@ -0,0 +1,11 @@ +AM_CFLAGS = \ + -I$(top_srcdir)/include/drm \ + -I$(top_srcdir) + +noinst_PROGRAMS = \ + proptest + +proptest_SOURCES = \ + proptest.c +proptest_LDADD = \ + $(top_builddir)/libdrm.la diff --git a/tests/proptest/proptest.c b/tests/proptest/proptest.c new file mode 100644 index 0000000..c6684eb --- /dev/null +++ b/tests/proptest/proptest.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2012 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: + * Paulo Zanoni + * + */ + +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +int fd; +drmModeResPtr res = NULL; +drmModePlaneResPtr plane_res = NULL; + +const char *connector_type_str(uint32_t type) +{ + switch (type) { + case DRM_MODE_CONNECTOR_Unknown: + return "Unknown"; + case DRM_MODE_CONNECTOR_VGA: + return "VGA"; + case DRM_MODE_CONNECTOR_DVII: + return "DVI-I"; + case DRM_MODE_CONNECTOR_DVID: + return "DVI-D"; + case DRM_MODE_CONNECTOR_DVIA: + return "DVI-A"; + case DRM_MODE_CONNECTOR_Composite: + return "Composite"; + case DRM_MODE_CONNECTOR_SVIDEO: + return "SVIDEO"; + case DRM_MODE_CONNECTOR_LVDS: + return "LVDS"; + case DRM_MODE_CONNECTOR_Component: + return "Component"; + case DRM_MODE_CONNECTOR_9PinDIN: + return "9PinDin"; + case DRM_MODE_CONNECTOR_DisplayPort: + return "DisplayPort"; + case DRM_MODE_CONNECTOR_HDMIA: + return "HDMI-A"; + case DRM_MODE_CONNECTOR_HDMIB: + return "HDMI-B"; + case DRM_MODE_CONNECTOR_TV: + return "TV"; + case DRM_MODE_CONNECTOR_eDP: + return "eDP"; + default: + return "Invalid"; + } +} + +/* dump_blob and dump_prop shamelessly copied from ../modetest/modetest.c */ +static void +dump_blob(uint32_t blob_id) +{ + uint32_t i; + unsigned char *blob_data; + drmModePropertyBlobPtr blob; + + blob = drmModeGetPropertyBlob(fd, blob_id); + if (!blob) + return; + + blob_data = blob->data; + + for (i = 0; i < blob->length; i++) { + if (i % 16 == 0) + printf("\n\t\t\t"); + printf("%.2hhx", blob_data[i]); + } + printf("\n"); + + drmModeFreePropertyBlob(blob); +} + +static void +dump_prop(uint32_t prop_id, uint64_t value) +{ + int i; + drmModePropertyPtr prop; + + prop = drmModeGetProperty(fd, prop_id); + + printf("\t%d", prop_id); + if (!prop) { + printf("\n"); + return; + } + + printf(" %s:\n", prop->name); + + printf("\t\tflags:"); + if (prop->flags & DRM_MODE_PROP_PENDING) + printf(" pending"); + if (prop->flags & DRM_MODE_PROP_RANGE) + printf(" range"); + if (prop->flags & DRM_MODE_PROP_IMMUTABLE) + printf(" immutable"); + if (prop->flags & DRM_MODE_PROP_ENUM) + printf(" enum"); + if (prop->flags & DRM_MODE_PROP_BITMASK) + printf(" bitmask"); + if (prop->flags & DRM_MODE_PROP_BLOB) + printf(" blob"); + printf("\n"); + + if (prop->flags & DRM_MODE_PROP_RANGE) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_values; i++) + printf(" %"PRIu64, prop->values[i]); + printf("\n"); + } + + if (prop->flags & DRM_MODE_PROP_ENUM) { + printf("\t\tenums:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=%llu", prop->enums[i].name, + prop->enums[i].value); + printf("\n"); + } else if (prop->flags & DRM_MODE_PROP_BITMASK) { + printf("\t\tvalues:"); + for (i = 0; i < prop->count_enums; i++) + printf(" %s=0x%llx", prop->enums[i].name, + (1LL << prop->enums[i].value)); + printf("\n"); + } else { + assert(prop->count_enums == 0); + } + + if (prop->flags & DRM_MODE_PROP_BLOB) { + printf("\t\tblobs:"); + for (i = 0; i < prop->count_blobs; i++) + dump_blob(prop->blob_ids[i]); + printf("\n"); + } else { + assert(prop->count_blobs == 0); + } + + printf("\t\tvalue:"); + if (prop->flags & DRM_MODE_PROP_BLOB) { + dump_blob(value); + printf("\n"); + } else { + printf(" %"PRIu64"\n", value); + } + + drmModeFreeProperty(prop); +} + +static void listObjectProperties(uint32_t id, uint32_t type) +{ + unsigned int i; + drmModeObjectPropertiesPtr props; + + props = drmModeObjectGetProperties(fd, id, type); + + if (!props) { + printf("\tNo properties: %s.\n", strerror(errno)); + return; + } + + for (i = 0; i < props->count_props; i++) + dump_prop(props->props[i], props->prop_values[i]); + + drmModeFreeObjectProperties(props); +} + +static void listConnectorProperties(void) +{ + int i; + drmModeConnectorPtr c; + + for (i = 0; i < res->count_connectors; i++) { + c = drmModeGetConnector(fd, res->connectors[i]); + + if (!c) { + fprintf(stderr, "Could not get connector %u: %s\n", + res->connectors[i], strerror(errno)); + continue; + } + + printf("Connector %u (%s-%u)\n", c->connector_id, + connector_type_str(c->connector_type), + c->connector_type_id); + + listObjectProperties(c->connector_id, + DRM_MODE_OBJECT_CONNECTOR); + + drmModeFreeConnector(c); + } +} + +static void listCrtcProperties(void) +{ + int i; + drmModeCrtcPtr c; + + for (i = 0; i < res->count_crtcs; i++) { + c = drmModeGetCrtc(fd, res->crtcs[i]); + + if (!c) { + fprintf(stderr, "Could not get crtc %u: %s\n", + res->crtcs[i], strerror(errno)); + continue; + } + + printf("CRTC %u\n", c->crtc_id); + + listObjectProperties(c->crtc_id, DRM_MODE_OBJECT_CRTC); + + drmModeFreeCrtc(c); + } +} + +static void listPlaneProperties(void) +{ + int i; + drmModePlanePtr p; + + for (i = 0; i < plane_res->count_planes; i++) { + p = drmModeGetPlane(fd, plane_res->planes[i]); + + if (!p) { + fprintf(stderr, "Could not get plane %u: %s\n", + plane_res->planes[i], strerror(errno)); + continue; + } + + printf("Plane %u\n", p->plane_id); + + listObjectProperties(p->plane_id, DRM_MODE_OBJECT_PLANE); + + drmModeFreePlane(p); + } +} + +static void listAllProperties(void) +{ + listConnectorProperties(); + listCrtcProperties(); + listPlaneProperties(); +} + +static int setProperty(char *argv[]) +{ + uint32_t obj_id, obj_type, prop_id; + uint64_t value; + + obj_id = atoi(argv[1]); + + if (!strcmp(argv[2], "connector")) { + obj_type = DRM_MODE_OBJECT_CONNECTOR; + } else if (!strcmp(argv[2], "crtc")) { + obj_type = DRM_MODE_OBJECT_CRTC; + } else if (!strcmp(argv[2], "plane")) { + obj_type = DRM_MODE_OBJECT_PLANE; + } else { + fprintf(stderr, "Invalid object type.\n"); + return 1; + } + + prop_id = atoi(argv[3]); + value = atoll(argv[4]); + + return drmModeObjectSetProperty(fd, obj_id, obj_type, prop_id, value); +} + +static void printUsage(void) +{ + printf("Usage:\n" +" proptest\n" +" proptest [obj id] [obj type] [prop id] [value]\n" +"\n" +"The first form just prints all the existing properties. The second one is\n" +"used to set the value of a specified property. The object type can be one of\n" +"the following strings:\n" +" connector crtc plane\n" +"\n" +"Example:\n" +" proptest 7 connector 2 1\n" +"will set property 2 of connector 7 to 1\n"); +} + +int main(int argc, char *argv[]) +{ + char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos" }; + unsigned int i, ret = 0; + + for (i = 0; i < ARRAY_SIZE(modules); i++){ + fd = drmOpen(modules[i], NULL); + if (fd >= 0) { + printf("Module %s loaded.\n", modules[i]); + break; + } + } + + if (i == ARRAY_SIZE(modules)) { + fprintf(stderr, "Failed to load drm modules.\n"); + return 1; + } + + res = drmModeGetResources(fd); + if (!res) { + fprintf(stderr, "Failed to get resources: %s\n", + strerror(errno)); + ret = 1; + goto done; + } + + plane_res = drmModeGetPlaneResources(fd); + if (!plane_res) { + fprintf(stderr, "Failed to get plane resources: %s\n", + strerror(errno)); + ret = 1; + goto done; + } + + if (argc < 2) { + listAllProperties(); + } else if (argc == 5) { + ret = setProperty(argv); + } else { + printUsage(); + ret = 1; + } + + drmModeFreeResources(res); +done: + drmClose(fd); + return ret; +} diff --git a/tests/rottest/Makefile.am b/tests/rottest/Makefile.am new file mode 100644 index 0000000..966173f --- /dev/null +++ b/tests/rottest/Makefile.am @@ -0,0 +1,21 @@ +AM_CFLAGS = \ + -I$(top_srcdir)/include/drm \ + -I$(top_srcdir)/libkms/ \ + -I$(top_srcdir)/exynos/ \ + -I$(top_srcdir) \ + $(CAIRO_CFLAGS) + +noinst_PROGRAMS = \ + rottest + +rottest_SOURCES = \ + rottest.c \ + gem.c \ + util.c \ + rotator.c + +rottest_LDADD = \ + $(top_builddir)/libdrm.la \ + $(top_builddir)/libkms/libkms.la \ + $(top_builddir)/exynos/libdrm_exynos.la \ + $(CAIRO_LIBS) diff --git a/tests/rottest/gem.c b/tests/rottest/gem.c new file mode 100644 index 0000000..f5bf811 --- /dev/null +++ b/tests/rottest/gem.c @@ -0,0 +1,92 @@ +/* + * DRM based rotator test program + * Copyright 2012 Samsung Electronics + * YoungJun Cho + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xf86drm.h" +#include "xf86drmMode.h" +#include "libkms.h" + +#include "exynos_drm.h" + +int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem) +{ + int ret = 0; + + if (!gem) { + fprintf(stderr, "gem object is null.\n"); + return -EFAULT; + } + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CREATE, gem); + if (ret < 0) + fprintf(stderr, "failed to create gem buffer: %s\n", + strerror(-ret)); + return ret; +} + +int exynos_gem_userptr(int fd, struct drm_exynos_gem_userptr *gem_userptr) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_USERPTR, gem_userptr); + if (ret < 0) + fprintf(stderr, "failed to userptr: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_MMAP, in_mmap); + if (ret < 0) + fprintf(stderr, "failed to mmap: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_close(int fd, struct drm_gem_close *gem_close) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, gem_close); + if (ret < 0) + fprintf(stderr, "failed to close: %s\n", strerror(-ret)); + return ret; +} + +int exynos_gem_cache_op(int fd, struct drm_exynos_gem_cache_op *cache_op) +{ + int ret = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_GEM_CACHE_OP, cache_op); + if (ret < 0) + fprintf(stderr, "failed to cache op: %s\n", strerror(-ret)); + return ret; +} diff --git a/tests/rottest/gem.h b/tests/rottest/gem.h new file mode 100644 index 0000000..2a5ed1d --- /dev/null +++ b/tests/rottest/gem.h @@ -0,0 +1,12 @@ +#ifndef __GEM_H__ +#define __GEM_H__ + +extern int exynos_gem_create(int fd, struct drm_exynos_gem_create *gem); +extern int exynos_gem_userptr(int fd, + struct drm_exynos_gem_userptr *gem_userptr); +extern int exynos_gem_mmap(int fd, struct drm_exynos_gem_mmap *in_mmap); +extern int exynos_gem_close(int fd, struct drm_gem_close *gem_close); +extern int exynos_gem_cache_op(int fd, + struct drm_exynos_gem_cache_op *cache_op); + +#endif diff --git a/tests/rottest/rotator.c b/tests/rottest/rotator.c new file mode 100644 index 0000000..996385b --- /dev/null +++ b/tests/rottest/rotator.c @@ -0,0 +1,297 @@ +/* + * DRM based rotator test program + * Copyright 2012 Samsung Electronics + * YoungJun Cho + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "exynos_drm.h" +#include "rottest.h" +#include "gem.h" +#include "util.h" + +#include "drm_fourcc.h" + +static int exynos_drm_ipp_property(int fd, + struct drm_exynos_ipp_property *property, + struct drm_exynos_pos *pos, + struct drm_exynos_sz *sz) +{ + int ret = 0; + + memset(property, 0x00, sizeof(struct drm_exynos_ipp_property)); + + property->config[EXYNOS_DRM_OPS_SRC].ops_id = EXYNOS_DRM_OPS_SRC; + property->config[EXYNOS_DRM_OPS_SRC].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_SRC].degree = EXYNOS_DRM_DEGREE_0; + property->config[EXYNOS_DRM_OPS_SRC].fmt = DRM_FORMAT_XRGB8888; + property->config[EXYNOS_DRM_OPS_SRC].pos = *pos; + property->config[EXYNOS_DRM_OPS_SRC].sz = *sz; + + property->config[EXYNOS_DRM_OPS_DST].ops_id = EXYNOS_DRM_OPS_DST; + property->config[EXYNOS_DRM_OPS_DST].flip = EXYNOS_DRM_FLIP_NONE; + property->config[EXYNOS_DRM_OPS_DST].degree = EXYNOS_DRM_DEGREE_90; + property->config[EXYNOS_DRM_OPS_DST].fmt = DRM_FORMAT_XRGB8888; + property->config[EXYNOS_DRM_OPS_DST].pos = *pos; + property->config[EXYNOS_DRM_OPS_DST].sz = *sz; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_PROPERTY, property); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_PROPERTY : %s\n", + strerror(errno)); + + return ret; +} + +static int exynos_drm_ipp_buf(int fd, struct drm_exynos_ipp_buf *buf, + enum drm_exynos_ops_id ops_id, + enum drm_exynos_ipp_buf_ctrl ctrl, + unsigned int gem_handle) +{ + int ret = 0; + + memset(buf, 0x00, sizeof(struct drm_exynos_ipp_buf)); + + buf->ops_id = ops_id; + buf->buf_ctrl = ctrl; + buf->user_data = 0; + buf->id = 0; + buf->handle[EXYNOS_DRM_PLANAR_Y] = gem_handle; + buf->handle[EXYNOS_DRM_PLANAR_CB] = 0; + buf->handle[EXYNOS_DRM_PLANAR_CR] = 0; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_BUF, buf); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_BUF[id:%d][ctrl:%d] : %s\n", + ops_id, ctrl, strerror(errno)); + + return ret; +} + +static int exynos_drm_ipp_ctrl(int fd, struct drm_exynos_ipp_ctrl *ctrl, + enum drm_exynos_ipp_cmd cmd, unsigned int use) +{ + int ret = 0; + + memset(ctrl, 0x00, sizeof(struct drm_exynos_ipp_ctrl)); + + ctrl->cmd = cmd; + ctrl->use = use; + + ret = ioctl(fd, DRM_IOCTL_EXYNOS_IPP_CTRL, ctrl); + if (ret) + fprintf(stderr, + "failed to DRM_IOCTL_EXYNOS_IPP_CTRL[cmd:%d][use:%d] : %s\n", + cmd, use, strerror(errno)); + + return ret; +} + +void rotator_set_mode(struct connector *c, int count, int page_flip, + long int *usec) +{ + struct drm_exynos_pos def_pos = {0, 0, 720, 1280}; + struct drm_exynos_sz def_sz = {720, 1280}; + struct drm_exynos_ipp_property property; + struct drm_exynos_ipp_buf buf1, buf2; + struct drm_exynos_ipp_ctrl ctrl; + unsigned int width, height, stride; + int ret, i, j, x; + struct drm_exynos_gem_create gem1, gem2; + struct drm_exynos_gem_mmap mmap1, mmap2; + void *usr_addr1, *usr_addr2; + struct timeval begin, end; + struct drm_gem_close args; + char filename[100]; + + /* For property */ + ret = exynos_drm_ipp_property(fd, &property, &def_pos, &def_sz); + if (ret) { + fprintf(stderr, "failed to ipp property\n"); + return; + } + + /* For mode */ + width = height = 0; + for (i = 0; i < count; i++) { + connector_find_mode(&c[i]); + if (c[i].mode == NULL) continue; + width += c[i].mode->hdisplay; + if (height < c[i].mode->vdisplay) height = c[i].mode->vdisplay; + } + stride = width * 4; + + /* For source buffer */ + ret = util_gem_create_mmap(fd, &gem1, &mmap1, stride * height); + if (ret) { + fprintf(stderr, "failed to gem create mmap: %s\n", + strerror(errno)); + if (ret == -1) return; + else if (ret == -2) goto err_gem_mmap1; + } + usr_addr1 = (void *)(unsigned long)mmap1.mapped; + + util_draw_buffer(usr_addr1, 1, width, height, stride, 0); + + sprintf(filename, "/opt/media/rot_src.bmp", j); + util_write_bmp(filename, usr_addr1, width, height); + + /* For destination buffer */ + ret = util_gem_create_mmap(fd, &gem2, &mmap2, stride * height); + if (ret) { + fprintf(stderr, "failed to gem create mmap: %s\n", + strerror(errno)); + if (ret == -1) goto err_gem_create2; + else if (ret == -2) goto err_gem_mmap2; + } + usr_addr2 = (void*)(unsigned long)mmap2.mapped; + + util_draw_buffer(usr_addr2, 0, 0, 0, 0, mmap2.size); + + sprintf(filename, "/opt/media/rot_dst.bmp", j); + util_write_bmp(filename, usr_addr2, height, width); + + /* For source buffer map to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, + IPP_BUF_CTRL_MAP, gem1.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf src map\n"); + goto err_ipp_buf_map1; + } + + /* For destination buffer map to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_MAP, gem2.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst map\n"); + goto err_ipp_buf_map2; + } + + for (j = 0; j < MAX_LOOP; j++) { + /* Start */ + gettimeofday(&begin, NULL); + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 1); + if (ret) { + fprintf(stderr, + "failed to ipp ctrl IPP_CMD_M2M start\n"); + goto err_ipp_ctrl_start; + } + + while (1) { + struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 }; + fd_set fds; + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(fd, &fds); + ret = select(fd + 1, &fds, NULL, NULL, &timeout); + if (ret <= 0) { + fprintf(stderr, "select timed out or error.\n"); + continue; + } else if (FD_ISSET(0, &fds)) { + break; + } + + gettimeofday(&end, NULL); + usec[j] = (end.tv_sec - begin.tv_sec) * 1000000 + + (end.tv_usec - begin.tv_usec); + + sprintf(filename, "/opt/media/rot_%d.bmp", j); + util_write_bmp(filename, usr_addr2, height, width); + + break; + } + + /* For destination buffer queue to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_QUEUE, gem2.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf dst queue\n"); + goto err_ipp_ctrl_start; + } + } + + /* For source buffer unmap to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, + IPP_BUF_CTRL_UNMAP, gem1.handle); + if (ret) { + fprintf(stderr, "failed to ipp buf src unmap\n"); + goto err_ipp_buf_unmap; + } + + /* For destination buffer unmap to IPP */ + ret = exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, + IPP_BUF_CTRL_UNMAP, gem2.handle); + if (ret < 0) { + fprintf(stderr, "failed to ipp buf dst unmap\n"); + goto err_ipp_buf_unmap; + } + + /* Stop */ + ret = exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 0); + if (ret) { + fprintf(stderr, "failed to ipp ctrl IPP_CMD_M2M stop\n"); + goto err_ipp_buf_unmap; + } + + munmap(usr_addr2, mmap2.size); + munmap(usr_addr1, mmap1.size); + + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem2.handle; + exynos_gem_close(fd, &args); + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem1.handle; + exynos_gem_close(fd, &args); + + return; + +err_ipp_buf_unmap: + exynos_drm_ipp_ctrl(fd, &ctrl, IPP_CMD_M2M, 0); +err_ipp_ctrl_start: + exynos_drm_ipp_buf(fd, &buf2, EXYNOS_DRM_OPS_DST, IPP_BUF_CTRL_UNMAP, + gem2.handle); +err_ipp_buf_map2: + exynos_drm_ipp_buf(fd, &buf1, EXYNOS_DRM_OPS_SRC, IPP_BUF_CTRL_UNMAP, + gem1.handle); +err_ipp_buf_map1: + munmap(usr_addr2, mmap2.size); +err_gem_mmap2: + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem2.handle; + exynos_gem_close(fd, &args); +err_gem_create2: + munmap(usr_addr1, mmap1.size); +err_gem_mmap1: + memset(&args, 0x00, sizeof(struct drm_gem_close)); + args.handle = gem1.handle; + exynos_gem_close(fd, &args); +} diff --git a/tests/rottest/rotator.h b/tests/rottest/rotator.h new file mode 100644 index 0000000..8835ee3 --- /dev/null +++ b/tests/rottest/rotator.h @@ -0,0 +1,7 @@ +#ifndef __ROTATOR_H__ +#define __ROTATOR_H__ + +extern void rotator_set_mode(struct connector *c, int count, int page_flip, + long int *usec); + +#endif diff --git a/tests/rottest/rottest.c b/tests/rottest/rottest.c new file mode 100644 index 0000000..1da52f3 --- /dev/null +++ b/tests/rottest/rottest.c @@ -0,0 +1,460 @@ +/* + * DRM based rotator test program + * Copyright 2012 Samsung Electronics + * YoungJun Cho + * + * 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 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. + */ + +/* + * This fairly simple test program dumps output in a similar format to the + * "xrandr" tool everyone knows & loves. It's necessarily slightly different + * since the kernel separates outputs into encoder and connector structures, + * each with their own unique ID. The program also allows test testing of the + * memory management and mode setting APIs by allowing the user to specify a + * connector and mode to use for mode setting. If all works as expected, a + * blue background should be painted on the monitor attached to the specified + * connector after the selected mode is set. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libkms.h" + +#include "exynos_drm.h" + +#include "rottest.h" +#include "rotator.h" + +drmModeRes *resources; +int fd, modes; + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct type_name { + int type; + char *name; +}; + +#define type_name_fn(res) \ +char * res##_str(int type) { \ + int i; \ + for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ + if (res##_names[i].type == type) \ + return res##_names[i].name; \ + } \ + return "(invalid)"; \ +} + +struct type_name encoder_type_names[] = { + { DRM_MODE_ENCODER_NONE, "none" }, + { DRM_MODE_ENCODER_DAC, "DAC" }, + { DRM_MODE_ENCODER_TMDS, "TMDS" }, + { DRM_MODE_ENCODER_LVDS, "LVDS" }, + { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, +}; + +type_name_fn(encoder_type) + +struct type_name connector_status_names[] = { + { DRM_MODE_CONNECTED, "connected" }, + { DRM_MODE_DISCONNECTED, "disconnected" }, + { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, +}; + +type_name_fn(connector_status) + +struct type_name connector_type_names[] = { + { DRM_MODE_CONNECTOR_Unknown, "unknown" }, + { DRM_MODE_CONNECTOR_VGA, "VGA" }, + { DRM_MODE_CONNECTOR_DVII, "DVI-I" }, + { DRM_MODE_CONNECTOR_DVID, "DVI-D" }, + { DRM_MODE_CONNECTOR_DVIA, "DVI-A" }, + { DRM_MODE_CONNECTOR_Composite, "composite" }, + { DRM_MODE_CONNECTOR_SVIDEO, "s-video" }, + { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, + { DRM_MODE_CONNECTOR_Component, "component" }, + { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, + { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, + { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, + { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, + { DRM_MODE_CONNECTOR_TV, "TV" }, + { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual" }, +}; + +type_name_fn(connector_type) + +static void dump_encoders(void) +{ + drmModeEncoder *encoder; + int i; + + printf("Encoders:\n"); + printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); + for (i = 0; i < resources->count_encoders; i++) { + encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + continue; + } + printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", + encoder->encoder_id, + encoder->crtc_id, + encoder_type_str(encoder->encoder_type), + encoder->possible_crtcs, + encoder->possible_clones); + drmModeFreeEncoder(encoder); + } + printf("\n"); +} + +static void dump_mode(drmModeModeInfo *mode) +{ + printf(" %s %d %d %d %d %d %d %d %d %d\n", + mode->name, + mode->vrefresh, + mode->hdisplay, + mode->hsync_start, + mode->hsync_end, + mode->htotal, + mode->vdisplay, + mode->vsync_start, + mode->vsync_end, + mode->vtotal); +} + +static void dump_props(drmModeConnector *connector) +{ + drmModePropertyPtr props; + int i; + + for (i = 0; i < connector->count_props; i++) { + props = drmModeGetProperty(fd, connector->props[i]); + printf("\t%s, flags %d\n", props->name, props->flags); + drmModeFreeProperty(props); + } +} + +static void dump_connectors(void) +{ + drmModeConnector *connector; + int i, j; + + printf("Connectors:\n"); + printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + continue; + } + + printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", + connector->connector_id, + connector->encoder_id, + connector_status_str(connector->connection), + connector_type_str(connector->connector_type), + connector->mmWidth, connector->mmHeight, + connector->count_modes); + + for (j = 0; j < connector->count_encoders; j++) + printf("%s%d", j > 0 ? ", " : "", + connector->encoders[j]); + printf("\n"); + + if (!connector->count_modes) + continue; + + printf(" modes:\n"); + printf(" name refresh (Hz) hdisp hss hse htot vdisp " + "vss vse vtot)\n"); + for (j = 0; j < connector->count_modes; j++) + dump_mode(&connector->modes[j]); + + printf(" props:\n"); + dump_props(connector); + + drmModeFreeConnector(connector); + } + printf("\n"); +} + +static void dump_crtcs(void) +{ + drmModeCrtc *crtc; + int i; + + printf("CRTCs:\n"); + printf("id\tfb\tpos\tsize\n"); + for (i = 0; i < resources->count_crtcs; i++) { + crtc = drmModeGetCrtc(fd, resources->crtcs[i]); + + if (!crtc) { + fprintf(stderr, "could not get crtc %i: %s\n", + resources->crtcs[i], strerror(errno)); + continue; + } + printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", + crtc->crtc_id, + crtc->buffer_id, + crtc->x, crtc->y, + crtc->width, crtc->height); + dump_mode(&crtc->mode); + + drmModeFreeCrtc(crtc); + } + printf("\n"); +} + +static void dump_framebuffers(void) +{ + drmModeFB *fb; + int i; + + printf("Frame buffers:\n"); + printf("id\tsize\tpitch\n"); + for (i = 0; i < resources->count_fbs; i++) { + fb = drmModeGetFB(fd, resources->fbs[i]); + + if (!fb) { + fprintf(stderr, "could not get fb %i: %s\n", + resources->fbs[i], strerror(errno)); + continue; + } + printf("%u\t(%ux%u)\t%u\n", + fb->fb_id, + fb->width, fb->height, + fb->pitch); + + drmModeFreeFB(fb); + } + printf("\n"); +} + +/* + * Mode setting with the kernel interfaces is a bit of a chore. + * First you have to find the connector in question and make sure the + * requested mode is available. + * Then you need to find the encoder attached to that connector so you + * can bind it with a free crtc. + */ + +void connector_find_mode(struct connector *c) +{ + drmModeConnector *connector; + int i, j; + + /* First, find the connector & mode */ + c->mode = NULL; + for (i = 0; i < resources->count_connectors; i++) { + connector = drmModeGetConnector(fd, resources->connectors[i]); + + if (!connector) { + fprintf(stderr, "could not get connector %i: %s\n", + resources->connectors[i], strerror(errno)); + drmModeFreeConnector(connector); + continue; + } + + if (!connector->count_modes) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connector_id != c->id) { + drmModeFreeConnector(connector); + continue; + } + + for (j = 0; j < connector->count_modes; j++) { + c->mode = &connector->modes[j]; + if (!strcmp(c->mode->name, c->mode_str)) + break; + } + + /* Found it, break out */ + if (c->mode) + break; + + drmModeFreeConnector(connector); + } + + if (!c->mode) { + fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); + return; + } + + /* Now get the encoder */ + for (i = 0; i < resources->count_encoders; i++) { + c->encoder = drmModeGetEncoder(fd, resources->encoders[i]); + + if (!c->encoder) { + fprintf(stderr, "could not get encoder %i: %s\n", + resources->encoders[i], strerror(errno)); + drmModeFreeEncoder(c->encoder); + continue; + } + + if (c->encoder->encoder_id == connector->encoder_id) + break; + + drmModeFreeEncoder(c->encoder); + } + + if (c->crtc == -1) + c->crtc = c->encoder->crtc_id; +} + +extern char *optarg; +extern int optind, opterr, optopt; +static char optstr[] = "ecpmfs:v"; + +static void usage(char *name) +{ + fprintf(stderr, "usage: %s [-ecpmf]\n", name); + fprintf(stderr, "\t-e\tlist encoders\n"); + fprintf(stderr, "\t-c\tlist connectors\n"); + fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n"); + fprintf(stderr, "\t-m\tlist modes\n"); + fprintf(stderr, "\t-f\tlist framebuffers\n"); + fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); + fprintf(stderr, "\t-s :\tset a mode\n"); + fprintf(stderr, "\t-s @:\tset a mode\n"); + fprintf(stderr, "\n\tDefault is to dump all info.\n"); + exit(0); +} + +#define dump_resource(res) if (res) dump_##res() + +int main(int argc, char **argv) +{ + int c; + int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0; + int test_vsync = 0; + char *modules[] = {"exynos", "i915", "radeon", "nouveau", "vmwgfx"}; + char *modeset = NULL; + int i, count = 0; + struct connector con_args[2]; + + opterr = 0; + while ((c = getopt(argc, argv, optstr)) != -1) { + switch (c) { + case 'e': + encoders = 1; + break; + case 'c': + connectors = 1; + break; + case 'p': + crtcs = 1; + break; + case 'm': + modes = 1; + break; + case 'f': + framebuffers = 1; + break; + case 'v': + test_vsync = 1; + break; + case 's': + modeset = strdup(optarg); + con_args[count].crtc = -1; + if (sscanf(optarg, "%d:%64s", + &con_args[count].id, + con_args[count].mode_str) != 2 && + sscanf(optarg, "%d@%d:%64s", + &con_args[count].id, + &con_args[count].crtc, + con_args[count].mode_str) != 3) + usage(argv[0]); + count++; + break; + default: + usage(argv[0]); + break; + } + } + + if (argc == 1) + encoders = connectors = crtcs = modes = framebuffers = 1; + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + printf("trying to load module %s...", modules[i]); + fd = drmOpen(modules[i], NULL); + if (fd < 0) { + printf("failed.\n"); + } else { + printf("success.\n"); + break; + } + } + + if (i == ARRAY_SIZE(modules)) { + fprintf(stderr, "failed to load any modules, aborting.\n"); + return -1; + } + + resources = drmModeGetResources(fd); + if (!resources) { + fprintf(stderr, "drmModeGetResources failed: %s\n", + strerror(errno)); + drmClose(fd); + return 1; + } + + dump_resource(encoders); + dump_resource(connectors); + dump_resource(crtcs); + dump_resource(framebuffers); + + if (count > 0) { + long int sum = 0, usec[MAX_LOOP]; + + rotator_set_mode(con_args, count, test_vsync, usec); + for (i = 0; i < MAX_LOOP; i++) { + printf("[%d] : %d\n", i + 1, usec[i]); + sum += usec[i]; + } + printf("rotator : cma\n"); + printf("avg : [%d]\n", sum / MAX_LOOP); + getchar(); + } + + drmModeFreeResources(resources); + + return 0; +} diff --git a/tests/rottest/rottest.h b/tests/rottest/rottest.h new file mode 100644 index 0000000..0edb3ca --- /dev/null +++ b/tests/rottest/rottest.h @@ -0,0 +1,25 @@ +#ifndef __ROTTEST_H__ +#define __ROTTEST_H__ + +#include "xf86drm.h" +#include "xf86drmMode.h" + +#define MAX_LOOP 20 + +struct connector { + uint32_t id; + char mode_str[64]; + drmModeModeInfo *mode; + drmModeEncoder *encoder; + int crtc; + unsigned int fb_id[2], current_fb_id; + struct timeval start; + + int swap_count; +}; + +extern int fd; + +extern void connector_find_mode(struct connector *c); + +#endif diff --git a/tests/rottest/util.c b/tests/rottest/util.c new file mode 100644 index 0000000..8800c48 --- /dev/null +++ b/tests/rottest/util.c @@ -0,0 +1,132 @@ +/* + * DRM based rotator test program + * Copyright 2012 Samsung Electronics + * YoungJun Cho + * + * 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 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "exynos_drm.h" +#include "gem.h" + +int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, + struct drm_exynos_gem_mmap *mmap, + unsigned int size) +{ + /* initialize structure for gem create */ + memset(gem, 0x00, sizeof(struct drm_exynos_gem_create)); + gem->size = size; + + if (exynos_gem_create(fd, gem) < 0) { + fprintf(stderr, "failed to gem create: %s\n", strerror(errno)); + return -1; + } + + /* initialize structure for gem mmap */ + memset(mmap, 0x00, sizeof(struct drm_exynos_gem_mmap)); + mmap->handle = gem->handle; + mmap->size = gem->size; + + if (exynos_gem_mmap(fd, mmap) < 0) { + fprintf(stderr, "failed to gem mmap: %s\n", strerror(errno)); + return -2; + } + + return 0; +} + +void util_draw_buffer(void *addr, unsigned int stripe, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int size) +{ + if (stripe == 1) { + int i, j; + unsigned int *fb_ptr; + div_t d; + + for (j = 0; j < height; j++) { + fb_ptr = (unsigned int *)((char *)addr + j * stride); + for (i = 0; i < width; i++) { + d = div(i, width); + fb_ptr[i] = 0x00130502 * (d.quot >> 6) + + 0x000a1120 * (d.rem >> 6); + } + } + } else + memset(addr, 0x77, size); +} + +int util_write_bmp(const char *file, const void *data, unsigned int width, + unsigned int height) +{ + int i; + unsigned int * blocks; + FILE *fp; + struct { + unsigned char magic[2]; + } bmpfile_magic = { {'B', 'M'} }; + struct { + unsigned int filesz; + unsigned short creator1; + unsigned short creator2; + unsigned int bmp_offset; + } bmpfile_header = { 0, 0, 0, 0x36 }; + struct { + unsigned int header_sz; + unsigned int width; + unsigned int height; + unsigned short nplanes; + unsigned short bitspp; + unsigned int compress_type; + unsigned int bmp_bytesz; + unsigned int hres; + unsigned int vres; + unsigned int ncolors; + unsigned int nimpcolors; + } bmp_dib_v3_header_t = { 0x28, 0, 0, 1, 32, 0, 0, 0, 0, 0, 0 }; + + fp = fopen(file, "wb"); + if (fp == NULL) return -1; + + bmpfile_header.filesz = sizeof(bmpfile_magic) + sizeof(bmpfile_header) + + sizeof(bmp_dib_v3_header_t) + width * height * 4; + bmp_dib_v3_header_t.header_sz = sizeof(bmp_dib_v3_header_t); + bmp_dib_v3_header_t.width = width; + bmp_dib_v3_header_t.height = -height; + bmp_dib_v3_header_t.nplanes = 1; + bmp_dib_v3_header_t.bmp_bytesz = width * height * 4; + + fwrite(&bmpfile_magic, sizeof(bmpfile_magic), 1, fp); + fwrite(&bmpfile_header, sizeof(bmpfile_header), 1, fp); + fwrite(&bmp_dib_v3_header_t, sizeof(bmp_dib_v3_header_t), 1, fp); + + blocks = (unsigned int*)data; + for (i = 0; i < height * width; i++) + fwrite(&blocks[i], 4, 1, fp); + + fclose(fp); + return 0; +} diff --git a/tests/rottest/util.h b/tests/rottest/util.h new file mode 100644 index 0000000..e1ffcca --- /dev/null +++ b/tests/rottest/util.h @@ -0,0 +1,12 @@ +#ifndef __UTIL_H__ +#define __UTIL_H__ + +extern int util_gem_create_mmap(int fd, struct drm_exynos_gem_create *gem, + struct drm_exynos_gem_mmap *mmap, + unsigned int size); +extern void util_draw_buffer(void *addr, unsigned int stripe, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int size); +extern int util_write_bmp(const char *file, const void *data, + unsigned int width, unsigned int height); +#endif diff --git a/tests/ttmtest/reconf b/tests/ttmtest/reconf old mode 100755 new mode 100644 diff --git a/tests/vbltest/vbltest.c b/tests/vbltest/vbltest.c index 20dae78..4fccd59 100644 --- a/tests/vbltest/vbltest.c +++ b/tests/vbltest/vbltest.c @@ -103,7 +103,7 @@ static void usage(char *name) int main(int argc, char **argv) { int i, c, fd, ret; - char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos-drm" }; + char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "exynos" }; drmVBlank vbl; drmEventContext evctx; struct vbl_info handler_info; diff --git a/xf86drmMode.c b/xf86drmMode.c index 66cabc9..04fdf1f 100644 --- a/xf86drmMode.c +++ b/xf86drmMode.c @@ -271,19 +271,14 @@ int drmModeAddFB2(int fd, uint32_t width, uint32_t height, f.height = height; f.pixel_format = pixel_format; f.flags = flags; - memcpy(f.handles, bo_handles, sizeof(uint32_t) * 4); - memcpy(f.pitches, pitches, sizeof(uint32_t) * 4); - memcpy(f.offsets, offsets, sizeof(uint32_t) * 4); + memcpy(f.handles, bo_handles, 4 * sizeof(bo_handles[0])); + memcpy(f.pitches, pitches, 4 * sizeof(pitches[0])); + memcpy(f.offsets, offsets, 4 * sizeof(offsets[0])); if ((ret = DRM_IOCTL(fd, DRM_IOCTL_MODE_ADDFB2, &f))) return ret; *buf_id = f.fb_id; - - memcpy(bo_handles, f.handles, sizeof(uint32_t) * 4); - memcpy(pitches, f.pitches, sizeof(uint32_t) * 4); - memcpy(offsets, f.offsets, sizeof(uint32_t) * 4); - return 0; } @@ -580,7 +575,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) if (prop.count_values) prop.values_ptr = VOID2U64(drmMalloc(prop.count_values * sizeof(uint64_t))); - if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_ENUM)) + if (prop.count_enum_blobs && (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK))) prop.enum_blob_ptr = VOID2U64(drmMalloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum))); if (prop.count_enum_blobs && (prop.flags & DRM_MODE_PROP_BLOB)) { @@ -602,7 +597,7 @@ drmModePropertyPtr drmModeGetProperty(int fd, uint32_t property_id) r->flags = prop.flags; if (prop.count_values) r->values = drmAllocCpy(U642VOID(prop.values_ptr), prop.count_values, sizeof(uint64_t)); - if (prop.flags & DRM_MODE_PROP_ENUM) { + if (prop.flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { r->count_enums = prop.count_enum_blobs; r->enums = drmAllocCpy(U642VOID(prop.enum_blob_ptr), prop.count_enum_blobs, sizeof(struct drm_mode_property_enum)); } else if (prop.flags & DRM_MODE_PROP_BLOB) { @@ -907,6 +902,7 @@ retry: ovr.count_format_types, sizeof(uint32_t)); if (ovr.count_format_types && !r->formats) { drmFree(r->formats); + drmFree(r); r = 0; } @@ -916,15 +912,6 @@ err_allocs: return r; } -void drmModeFreePlaneResources(drmModePlaneResPtr ptr) -{ - if (!ptr) - return; - - drmFree(ptr->planes); - drmFree(ptr); -} - void drmModeFreePlane(drmModePlanePtr ptr) { if (!ptr) @@ -969,6 +956,7 @@ retry: res.count_planes, sizeof(uint32_t)); if (res.count_planes && !r->planes) { drmFree(r->planes); + drmFree(r); r = 0; } @@ -977,3 +965,95 @@ err_allocs: return r; } + +void drmModeFreePlaneResources(drmModePlaneResPtr ptr) +{ + if (!ptr) + return; + + drmFree(ptr->planes); + drmFree(ptr); +} + +drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, + uint32_t object_id, + uint32_t object_type) +{ + struct drm_mode_obj_get_properties properties; + drmModeObjectPropertiesPtr ret = NULL; + uint32_t count; + +retry: + memset(&properties, 0, sizeof(struct drm_mode_obj_get_properties)); + properties.obj_id = object_id; + properties.obj_type = object_type; + + if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)) + return 0; + + count = properties.count_props; + + if (count) { + properties.props_ptr = VOID2U64(drmMalloc(count * + sizeof(uint32_t))); + if (!properties.props_ptr) + goto err_allocs; + properties.prop_values_ptr = VOID2U64(drmMalloc(count * + sizeof(uint64_t))); + if (!properties.prop_values_ptr) + goto err_allocs; + } + + if (drmIoctl(fd, DRM_IOCTL_MODE_OBJ_GETPROPERTIES, &properties)) + goto err_allocs; + + if (count < properties.count_props) { + drmFree(U642VOID(properties.props_ptr)); + drmFree(U642VOID(properties.prop_values_ptr)); + goto retry; + } + count = properties.count_props; + + ret = drmMalloc(sizeof(*ret)); + if (!ret) + goto err_allocs; + + ret->count_props = count; + ret->props = drmAllocCpy(U642VOID(properties.props_ptr), + count, sizeof(uint32_t)); + ret->prop_values = drmAllocCpy(U642VOID(properties.prop_values_ptr), + count, sizeof(uint64_t)); + if (ret->count_props && (!ret->props || !ret->prop_values)) { + drmFree(ret->props); + drmFree(ret->prop_values); + drmFree(ret); + ret = NULL; + } + +err_allocs: + drmFree(U642VOID(properties.props_ptr)); + drmFree(U642VOID(properties.prop_values_ptr)); + return ret; +} + +void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr) +{ + if (!ptr) + return; + drmFree(ptr->props); + drmFree(ptr->prop_values); + drmFree(ptr); +} + +int drmModeObjectSetProperty(int fd, uint32_t object_id, uint32_t object_type, + uint32_t property_id, uint64_t value) +{ + struct drm_mode_obj_set_property prop; + + prop.value = value; + prop.prop_id = property_id; + prop.obj_id = object_id; + prop.obj_type = object_type; + + return DRM_IOCTL(fd, DRM_IOCTL_MODE_OBJ_SETPROPERTY, &prop); +} diff --git a/xf86drmMode.h b/xf86drmMode.h index 004e34c..4f49362 100644 --- a/xf86drmMode.h +++ b/xf86drmMode.h @@ -33,6 +33,9 @@ * */ +#ifndef _XF86DRMMODE_H_ +#define _XF86DRMMODE_H_ + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif @@ -110,11 +113,12 @@ extern "C" { #define DRM_MODE_DITHERING_OFF 0 #define DRM_MODE_DITHERING_ON 1 -#define DRM_MODE_ENCODER_NONE 0 -#define DRM_MODE_ENCODER_DAC 1 -#define DRM_MODE_ENCODER_TMDS 2 -#define DRM_MODE_ENCODER_LVDS 3 -#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_NONE 0 +#define DRM_MODE_ENCODER_DAC 1 +#define DRM_MODE_ENCODER_TMDS 2 +#define DRM_MODE_ENCODER_LVDS 3 +#define DRM_MODE_ENCODER_TVDAC 4 +#define DRM_MODE_ENCODER_VIRTUAL 5 #define DRM_MODE_SUBCONNECTOR_Automatic 0 #define DRM_MODE_SUBCONNECTOR_Unknown 0 @@ -139,6 +143,7 @@ extern "C" { #define DRM_MODE_CONNECTOR_HDMIB 12 #define DRM_MODE_CONNECTOR_TV 13 #define DRM_MODE_CONNECTOR_eDP 14 +#define DRM_MODE_CONNECTOR_VIRTUAL 15 #define DRM_MODE_PROP_PENDING (1<<0) #define DRM_MODE_PROP_RANGE (1<<1) @@ -278,6 +283,12 @@ typedef struct _drmModeConnector { uint32_t *encoders; /**< List of encoder ids */ } drmModeConnector, *drmModeConnectorPtr; +typedef struct _drmModeObjectProperties { + uint32_t count_props; + uint32_t *props; + uint64_t *prop_values; +} drmModeObjectProperties, *drmModeObjectPropertiesPtr; + typedef struct _drmModePlane { uint32_t count_formats; uint32_t *formats; @@ -304,8 +315,8 @@ extern void drmModeFreeFB( drmModeFBPtr ptr ); extern void drmModeFreeCrtc( drmModeCrtcPtr ptr ); extern void drmModeFreeConnector( drmModeConnectorPtr ptr ); extern void drmModeFreeEncoder( drmModeEncoderPtr ptr ); -extern void drmModeFreePlaneResources( drmModePlaneResPtr ptr ); extern void drmModeFreePlane( drmModePlanePtr ptr ); +extern void drmModeFreePlaneResources(drmModePlaneResPtr ptr); /** * Retrives all of the resources associated with a card. @@ -425,6 +436,16 @@ extern int drmModeSetPlane(int fd, uint32_t plane_id, uint32_t crtc_id, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); +extern drmModeObjectPropertiesPtr drmModeObjectGetProperties(int fd, + uint32_t object_id, + uint32_t object_type); +extern void drmModeFreeObjectProperties(drmModeObjectPropertiesPtr ptr); +extern int drmModeObjectSetProperty(int fd, uint32_t object_id, + uint32_t object_type, uint32_t property_id, + uint64_t value); + #if defined(__cplusplus) || defined(c_plusplus) } #endif + +#endif