summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGraydon, Tracy <tracy.graydon@intel.com>2013-01-31 15:14:28 -0800
committerGraydon, Tracy <tracy.graydon@intel.com>2013-01-31 15:14:28 -0800
commit3c7b03f2f7b4ecfb18fb30f2e43b6321cb1aa4de (patch)
treebb8c57f401c0087a3ce4e96dc733abff854c3a43 /tests
downloadintel-gpu-tools-3c7b03f2f7b4ecfb18fb30f2e43b6321cb1aa4de.tar.gz
intel-gpu-tools-3c7b03f2f7b4ecfb18fb30f2e43b6321cb1aa4de.tar.bz2
intel-gpu-tools-3c7b03f2f7b4ecfb18fb30f2e43b6321cb1aa4de.zip
Diffstat (limited to 'tests')
-rw-r--r--tests/.gitignore78
-rw-r--r--tests/Makefile.am148
-rwxr-xr-xtests/ZZ_check_dmesg11
-rwxr-xr-xtests/ZZ_hangman42
-rwxr-xr-xtests/check_drm_clients6
-rwxr-xr-xtests/debugfs_emon_crash16
-rwxr-xr-xtests/debugfs_reader9
-rwxr-xr-xtests/debugfs_wedged10
-rwxr-xr-xtests/drm_lib.sh32
-rw-r--r--tests/drm_vma_limiter.c110
-rw-r--r--tests/drm_vma_limiter_cached.c138
-rw-r--r--tests/drm_vma_limiter_cpu.c100
-rw-r--r--tests/drm_vma_limiter_gtt.c101
-rw-r--r--tests/flip_test.c317
-rw-r--r--tests/gem_bad_address.c81
-rw-r--r--tests/gem_bad_batch.c77
-rw-r--r--tests/gem_bad_blit.c121
-rw-r--r--tests/gem_bad_length.c132
-rw-r--r--tests/gem_basic.c90
-rw-r--r--tests/gem_cpu_concurrent_blit.c142
-rw-r--r--tests/gem_cs_prefetch.c169
-rw-r--r--tests/gem_ctx_bad_destroy.c109
-rw-r--r--tests/gem_ctx_bad_exec.c125
-rw-r--r--tests/gem_ctx_basic.c166
-rw-r--r--tests/gem_ctx_create.c64
-rw-r--r--tests/gem_ctx_exec.c139
-rw-r--r--tests/gem_double_irq_loop.c147
-rw-r--r--tests/gem_dummy_reloc_loop.c194
-rw-r--r--tests/gem_exec_bad_domains.c145
-rw-r--r--tests/gem_exec_blt.c263
-rw-r--r--tests/gem_exec_faulting_reloc.c226
-rw-r--r--tests/gem_exec_nop.c119
-rw-r--r--tests/gem_fence_thrash.c119
-rw-r--r--tests/gem_fenced_exec_thrash.c166
-rw-r--r--tests/gem_flink.c130
-rw-r--r--tests/gem_gtt_concurrent_blit.c145
-rw-r--r--tests/gem_gtt_cpu_tlb.c108
-rw-r--r--tests/gem_gtt_speed.c292
-rw-r--r--tests/gem_hang.c97
-rw-r--r--tests/gem_hangcheck_forcewake.c127
-rw-r--r--tests/gem_largeobject.c95
-rw-r--r--tests/gem_linear_blits.c250
-rw-r--r--tests/gem_mmap.c96
-rw-r--r--tests/gem_mmap_gtt.c161
-rw-r--r--tests/gem_mmap_offset_exhaustion.c96
-rw-r--r--tests/gem_partial_pwrite_pread.c263
-rw-r--r--tests/gem_pipe_control_store_loop.c184
-rw-r--r--tests/gem_pread_after_blit.c175
-rw-r--r--tests/gem_pwrite.c122
-rw-r--r--tests/gem_readwrite.c134
-rw-r--r--tests/gem_reg_read.c98
-rw-r--r--tests/gem_reloc_vs_gpu.c206
-rw-r--r--tests/gem_ring_sync_loop.c139
-rw-r--r--tests/gem_ringfill.c233
-rw-r--r--tests/gem_set_tiling_vs_blt.c269
-rw-r--r--tests/gem_set_tiling_vs_gtt.c137
-rw-r--r--tests/gem_set_tiling_vs_pwrite.c99
-rw-r--r--tests/gem_storedw_batches_loop.c173
-rw-r--r--tests/gem_storedw_loop_blt.c154
-rw-r--r--tests/gem_storedw_loop_bsd.c160
-rw-r--r--tests/gem_storedw_loop_render.c148
-rw-r--r--tests/gem_stress.c945
-rw-r--r--tests/gem_tiled_blits.c214
-rw-r--r--tests/gem_tiled_fence_blits.c174
-rw-r--r--tests/gem_tiled_partial_pwrite_pread.c294
-rw-r--r--tests/gem_tiled_pread.c237
-rw-r--r--tests/gem_tiled_pread_pwrite.c159
-rw-r--r--tests/gem_tiled_swapping.c145
-rw-r--r--tests/gem_unfence_active_buffers.c171
-rw-r--r--tests/gem_unref_active_buffers.c107
-rw-r--r--tests/gem_vmap_blits.c355
-rw-r--r--tests/gem_wait_render_timeout.c230
-rw-r--r--tests/gen3_mixed_blits.c541
-rw-r--r--tests/gen3_render_linear_blits.c400
-rw-r--r--tests/gen3_render_mixed_blits.c429
-rw-r--r--tests/gen3_render_tiledx_blits.c408
-rw-r--r--tests/gen3_render_tiledy_blits.c415
-rw-r--r--tests/getclient.c61
-rw-r--r--tests/getstats.c50
-rw-r--r--tests/getversion.c49
-rwxr-xr-xtests/module_reload41
-rw-r--r--tests/pass.pngbin0 -> 569 bytes
-rw-r--r--tests/prime_nv_api.c408
-rw-r--r--tests/prime_nv_pcopy.c1329
-rw-r--r--tests/prime_nv_test.c582
-rw-r--r--tests/prime_self_import.c123
-rwxr-xr-xtests/sysfs_edid_timing20
-rwxr-xr-xtests/sysfs_l3_parity27
-rw-r--r--tests/sysfs_rc6_residency.c119
-rw-r--r--tests/testdisplay.c765
-rw-r--r--tests/testdisplay.h35
-rw-r--r--tests/testdisplay_hotplug.c136
92 files changed, 17172 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 00000000..1a6795bc
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,78 @@
+flip_test
+drm_vma_limiter
+drm_vma_limiter_cached
+drm_vma_limiter_cpu
+drm_vma_limiter_gtt
+gem_bad_address
+gem_bad_batch
+gem_bad_blit
+gem_bad_length
+gem_basic
+gem_cs_prefetch
+gem_cpu_concurrent_blit
+gem_ctx_bad_destroy
+gem_ctx_bad_exec
+gem_ctx_basic
+gem_ctx_create
+gem_ctx_exec
+gem_double_irq_loop
+gem_dummy_reloc_loop
+gem_exec_bad_domains
+gem_exec_blt
+gem_exec_faulting_reloc
+gem_exec_nop
+gem_fenced_exec_thrash
+gem_fence_thrash
+gem_flink
+gem_gtt_speed
+gem_gtt_concurrent_blit
+gem_gtt_cpu_tlb
+gem_hang
+gem_hangcheck_forcewake
+gem_largeobject
+gem_linear_blits
+gem_mmap
+gem_mmap_gtt
+gem_mmap_offset_exhaustion
+gem_partial_pwrite_pread
+gem_pipe_control_store_loop
+gem_pread_after_blit
+gem_pwrite
+gem_readwrite
+gem_reloc_vs_gpu
+gem_reg_read
+gem_ringfill
+gem_ring_sync_loop
+gem_set_tiling_vs_blt
+gem_set_tiling_vs_gtt
+gem_set_tiling_vs_pwrite
+gem_storedw_batches_loop
+gem_storedw_loop_blt
+gem_storedw_loop_bsd
+gem_storedw_loop_render
+gem_stress
+gem_tiled_blits
+gem_tiled_fence_blits
+gem_tiled_partial_pwrite_pread
+gem_tiled_pread
+gem_tiled_pread_pwrite
+gem_tiled_swapping
+gem_unfence_active_buffers
+gem_unref_active_buffers
+gem_vmap_blits
+gem_wait_render_timeout
+gen3_mixed_blits
+gen3_render_linear_blits
+gen3_render_mixed_blits
+gen3_render_tiledx_blits
+gen3_render_tiledy_blits
+getclient
+getstats
+getversion
+prime_nv_api
+prime_nv_pcopy
+prime_nv_test
+prime_self_import
+testdisplay
+sysfs_rc6_residency
+# Please keep sorted alphabetically
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 00000000..e29a383a
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,148 @@
+noinst_PROGRAMS = \
+ gem_stress \
+ $(TESTS_progs) \
+ $(HANG) \
+ $(NULL)
+
+if HAVE_NOUVEAU
+NOUVEAU_TESTS = \
+ prime_nv_api \
+ prime_nv_pcopy \
+ prime_nv_test
+endif
+
+TESTS_progs = \
+ getversion \
+ getclient \
+ getstats \
+ gem_basic \
+ gem_cpu_concurrent_blit \
+ gem_gtt_concurrent_blit \
+ gem_exec_nop \
+ gem_exec_blt \
+ gem_exec_bad_domains \
+ gem_exec_faulting_reloc \
+ gem_flink \
+ gem_readwrite \
+ gem_ringfill \
+ gem_mmap \
+ gem_mmap_gtt \
+ gem_mmap_offset_exhaustion \
+ gem_pwrite \
+ gem_pread_after_blit \
+ gem_set_tiling_vs_blt \
+ gem_set_tiling_vs_gtt \
+ gem_set_tiling_vs_pwrite \
+ gem_tiled_pread \
+ gem_tiled_pread_pwrite \
+ gem_tiled_partial_pwrite_pread \
+ gem_tiled_swapping \
+ gem_partial_pwrite_pread \
+ gem_linear_blits \
+ gem_vmap_blits \
+ gem_tiled_blits \
+ gem_tiled_fence_blits \
+ gem_largeobject \
+ gem_bad_length \
+ gem_fence_thrash \
+ gem_fenced_exec_thrash \
+ gem_gtt_speed \
+ gem_gtt_cpu_tlb \
+ gem_cs_prefetch \
+ gen3_render_linear_blits \
+ gen3_render_tiledx_blits \
+ gen3_render_tiledy_blits \
+ gen3_render_mixed_blits \
+ gen3_mixed_blits \
+ gem_storedw_loop_render \
+ gem_storedw_loop_blt \
+ gem_storedw_loop_bsd \
+ gem_storedw_batches_loop \
+ gem_dummy_reloc_loop \
+ gem_double_irq_loop \
+ gem_ring_sync_loop \
+ gem_pipe_control_store_loop \
+ gem_unfence_active_buffers \
+ gem_unref_active_buffers \
+ gem_reloc_vs_gpu \
+ drm_vma_limiter \
+ drm_vma_limiter_cpu \
+ drm_vma_limiter_gtt \
+ drm_vma_limiter_cached \
+ sysfs_rc6_residency \
+ flip_test \
+ gem_wait_render_timeout \
+ gem_ctx_create \
+ gem_ctx_bad_destroy \
+ gem_ctx_exec \
+ gem_ctx_bad_exec \
+ gem_ctx_basic \
+ gem_reg_read \
+ $(NOUVEAU_TESTS) \
+ prime_self_import \
+ $(NULL)
+
+# IMPORTANT: The ZZ_ tests need to be run last!
+# ... and make can't deal with inlined comments ...
+TESTS_scripts = \
+ debugfs_reader \
+ debugfs_emon_crash \
+ sysfs_l3_parity \
+ sysfs_edid_timing \
+ module_reload \
+ ZZ_check_dmesg \
+ ZZ_hangman \
+ $(NULL)
+
+kernel_tests = \
+ $(TESTS_progs) \
+ $(TESTS_scripts) \
+ $(NULL)
+
+TESTS = \
+ $(NULL)
+
+test:
+ whoami | grep root || ( echo ERROR: not running as root; exit 1 )
+ ./check_drm_clients
+ make TESTS="${kernel_tests}" check
+
+HANG = \
+ gem_bad_batch \
+ gem_hang \
+ gem_bad_blit \
+ gem_bad_address \
+ $(NULL)
+
+EXTRA_PROGRAMS = $(TESTS_progs) $(HANG)
+EXTRA_DIST = $(TESTS_scripts) drm_lib.sh check_drm_clients debugfs_wedged
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+AM_CFLAGS = $(DRM_CFLAGS) $(CWARNFLAGS) \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../lib
+LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS)
+
+testdisplay_SOURCES = \
+ testdisplay.c \
+ testdisplay.h \
+ testdisplay_hotplug.c \
+ $(NULL)
+
+TESTS_progs += testdisplay
+LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS)
+AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS)
+
+gem_fence_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS)
+gem_fence_thrash_LDADD = $(LDADD) -lpthread
+
+gem_wait_render_timeout_LDADD = $(LDADD) -lrt
+
+gem_ctx_basic_LDADD = $(LDADD) -lpthread
+
+prime_nv_test_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS)
+prime_nv_test_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS)
+prime_nv_api_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS)
+prime_nv_api_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS)
+prime_nv_pcopy_CFLAGS = $(AM_CFLAGS) $(DRM_NOUVEAU_CFLAGS)
+prime_nv_pcopy_LDADD = $(LDADD) $(DRM_NOUVEAU_LIBS)
diff --git a/tests/ZZ_check_dmesg b/tests/ZZ_check_dmesg
new file mode 100755
index 00000000..e28ba35f
--- /dev/null
+++ b/tests/ZZ_check_dmesg
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+if dmesg | grep '\*ERROR\*' > /dev/null ; then
+ echo "DRM_ERROR dirt in dmesg"
+ exit 1
+fi
+
+if dmesg | grep -- '------\[ cut here \]----' > /dev/null ; then
+ echo "found a backtrace in dmesg"
+ exit 1
+fi
diff --git a/tests/ZZ_hangman b/tests/ZZ_hangman
new file mode 100755
index 00000000..b8f4a682
--- /dev/null
+++ b/tests/ZZ_hangman
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# Testcase: Simulate gpu hang
+#
+# This check uses the stop_rings facility to exercise the gpu hang code.
+# by reading /sys/kernel/debug/dri/0/i915_emon_status too quickly
+#
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+oldpath=`pwd`
+
+cd $i915_path
+
+if [ ! -f i915_ring_stop ] ; then
+ echo "kernel doesn't support ring stopping"
+ exit 77
+fi
+
+if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then
+ echo "gpu hang dectected"
+ exit 1
+fi
+
+# stop rings
+echo 0xf > i915_ring_stop
+echo "rings stopped"
+
+(cd $oldpath; $SOURCE_DIR/gem_exec_nop) > /dev/null
+
+if cat i915_error_state | grep -v "no error state collected" > /dev/null ; then
+ echo "gpu hang correctly dectected"
+else
+ echo "gpu hang not dectected"
+ exit 2
+fi
+
+# clear error state
+echo > i915_error_state
+
+exit 0
diff --git a/tests/check_drm_clients b/tests/check_drm_clients
new file mode 100755
index 00000000..eb12416a
--- /dev/null
+++ b/tests/check_drm_clients
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+exit 0
diff --git a/tests/debugfs_emon_crash b/tests/debugfs_emon_crash
new file mode 100755
index 00000000..6e139a41
--- /dev/null
+++ b/tests/debugfs_emon_crash
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# This check if we can crash the kernel with segmentation-fault
+# by reading /sys/kernel/debug/dri/0/i915_emon_status too quickly
+#
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+for z in $(seq 1 1000); do
+ cat $i915_path/i915_emon_status > /dev/null 2&>1
+done
+
+# If we got here, we haven't crashed
+
+exit 0
diff --git a/tests/debugfs_reader b/tests/debugfs_reader
new file mode 100755
index 00000000..80d59988
--- /dev/null
+++ b/tests/debugfs_reader
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+# read everything we can
+cat $i915_path/* > /dev/null 2>&1
+
+exit 0
diff --git a/tests/debugfs_wedged b/tests/debugfs_wedged
new file mode 100755
index 00000000..80a32f61
--- /dev/null
+++ b/tests/debugfs_wedged
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+# Testcase: wedge the hw to check the error_state reading
+#
+# Unfortunately wedged is permanent, so this test is not run by default
+echo 1 > ${i915_path}/i915_wedged
+cat $i915_path/i915_error_state > /dev/null 2>&1
diff --git a/tests/drm_lib.sh b/tests/drm_lib.sh
new file mode 100755
index 00000000..a76fd474
--- /dev/null
+++ b/tests/drm_lib.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+die() {
+ echo "$@"
+ exit 1
+}
+
+if [ -d /debug/dri ] ; then
+ debugfs_path=/debug/dri
+fi
+
+if [ -d /sys/kernel/debug/dri ] ; then
+ debugfs_path=/sys/kernel/debug/dri
+fi
+
+i915_path=x
+for dir in `ls $debugfs_path` ; do
+ if [ -f $debugfs_path/$dir/i915_error_state ] ; then
+ i915_path=$debugfs_path/$dir
+ break
+ fi
+done
+
+if [ $i915_path = "x" ] ; then
+ die " i915 debugfs path not found."
+fi
+
+# read everything we can
+if [ `cat $i915_path/clients | wc -l` -gt "2" ] ; then
+ die "ERROR: other drm clients running"
+fi
+
+
diff --git a/tests/drm_vma_limiter.c b/tests/drm_vma_limiter.c
new file mode 100644
index 00000000..1971e2dc
--- /dev/null
+++ b/tests/drm_vma_limiter.c
@@ -0,0 +1,110 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+/* Testcase: check whether the libdrm vma limiter works
+ *
+ * We've had reports of the X server exhausting the default rlimit of 64k vma's
+ * in the kernel. libdrm has grown facilities to limit the vma caching since,
+ * this checks whether they actually work.
+ */
+
+/* we do both cpu and gtt maps, so only need half of 64k to exhaust */
+#define BO_ARRAY_SIZE 35000
+drm_intel_bo *bos[BO_ARRAY_SIZE];
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int i;
+ char *ptr;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500);
+
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_bo_map(bos[i], 1);
+ ptr = bos[i]->virtual;
+ assert(ptr);
+ *ptr = 'c';
+ drm_intel_bo_unmap(bos[i]);
+
+ drm_intel_gem_bo_map_gtt(bos[i]);
+ ptr = bos[i]->virtual;
+ assert(ptr);
+ *ptr = 'c';
+ drm_intel_gem_bo_unmap_gtt(bos[i]);
+ }
+
+ /* and recheck whether a second map of the same still works */
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_bo_map(bos[i], 1);
+ ptr = bos[i]->virtual;
+ assert(*ptr = 'c');
+ drm_intel_bo_unmap(bos[i]);
+
+ drm_intel_gem_bo_map_gtt(bos[i]);
+ ptr = bos[i]->virtual;
+ assert(*ptr = 'c');
+ drm_intel_gem_bo_unmap_gtt(bos[i]);
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/drm_vma_limiter_cached.c b/tests/drm_vma_limiter_cached.c
new file mode 100644
index 00000000..37976185
--- /dev/null
+++ b/tests/drm_vma_limiter_cached.c
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+/* Testcase: check whether the libdrm vma limiter works
+ *
+ * We've had reports of the X server exhausting the default rlimit of 64k vma's
+ * in the kernel. libdrm has grown facilities to limit the vma caching since,
+ * this checks whether they actually work.
+ *
+ * This one checks whether mmaps of unused cached bos are also properly reaped.
+ */
+
+/* we do both cpu and gtt maps, so only need half of 64k to exhaust */
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int i;
+ char *ptr;
+ drm_intel_bo *load_bo;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ load_bo = drm_intel_bo_alloc(bufmgr, "target bo", 1024*4096, 4096);
+ assert(load_bo);
+
+ drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500);
+
+ /* IMPORTANT: we need to enable buffer reuse, otherwise we won't test
+ * the libdrm bo cache! */
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ /* put some load onto the gpu to keep the light buffers active for long
+ * enough */
+ for (i = 0; i < 10000; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 4096);
+ OUT_BATCH(0); /* dst x1,y1 */
+ OUT_BATCH((1024 << 16) | 512);
+ OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH((0 << 16) | 512); /* src x1, y1 */
+ OUT_BATCH(4096);
+ OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+ }
+
+#define GROUP_SZ 100
+ for (i = 0; i < 68000; ) {
+ int j;
+ drm_intel_bo *bo[GROUP_SZ];
+
+ for (j = 0; j < GROUP_SZ; j++, i++) {
+ bo[j] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bo[j]);
+
+ drm_intel_gem_bo_map_gtt(bo[j]);
+ ptr = bo[j]->virtual;
+ assert(ptr);
+ *ptr = 'c';
+ drm_intel_gem_bo_unmap_gtt(bo[j]);
+
+ /* put it onto the active list ... */
+ BEGIN_BATCH(6);
+ OUT_BATCH(XY_COLOR_BLT_CMD |
+ XY_COLOR_BLT_WRITE_ALPHA |
+ XY_COLOR_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ 128);
+ OUT_BATCH(0); /* dst x1,y1 */
+ OUT_BATCH((1 << 16) | 1);
+ OUT_RELOC(bo[j], I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0xffffffff); /* color */
+ ADVANCE_BATCH();
+ }
+ intel_batchbuffer_flush(batch);
+
+ for (j = 0; j < GROUP_SZ; j++)
+ drm_intel_bo_unreference(bo[j]);
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/drm_vma_limiter_cpu.c b/tests/drm_vma_limiter_cpu.c
new file mode 100644
index 00000000..24ce188e
--- /dev/null
+++ b/tests/drm_vma_limiter_cpu.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+/* Testcase: check whether the libdrm vma limiter works
+ *
+ * We've had reports of the X server exhausting the default rlimit of 64k vma's
+ * in the kernel. libdrm has grown facilities to limit the vma caching since,
+ * this checks whether they actually work.
+ *
+ * This one checks cpu mmaps only.
+ */
+
+#define BO_ARRAY_SIZE 68000
+drm_intel_bo *bos[BO_ARRAY_SIZE];
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int i;
+ char *ptr;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500);
+
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_bo_map(bos[i], 1);
+ ptr = bos[i]->virtual;
+ assert(ptr);
+ *ptr = 'c';
+ drm_intel_bo_unmap(bos[i]);
+ }
+
+ /* and recheck whether a second map of the same still works */
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_bo_map(bos[i], 1);
+ ptr = bos[i]->virtual;
+ assert(*ptr = 'c');
+ drm_intel_bo_unmap(bos[i]);
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/drm_vma_limiter_gtt.c b/tests/drm_vma_limiter_gtt.c
new file mode 100644
index 00000000..540ea917
--- /dev/null
+++ b/tests/drm_vma_limiter_gtt.c
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+/* Testcase: check whether the libdrm vma limiter works
+ *
+ * We've had reports of the X server exhausting the default rlimit of 64k vma's
+ * in the kernel. libdrm has grown facilities to limit the vma caching since,
+ * this checks whether they actually work.
+ *
+ * This one checks cpu mmaps only.
+ */
+
+/* we do both cpu and gtt maps, so only need half of 64k to exhaust */
+#define BO_ARRAY_SIZE 68000
+drm_intel_bo *bos[BO_ARRAY_SIZE];
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int i;
+ char *ptr;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ drm_intel_bufmgr_gem_set_vma_cache_size(bufmgr, 500);
+
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_gem_bo_map_gtt(bos[i]);
+ ptr = bos[i]->virtual;
+ assert(ptr);
+ *ptr = 'c';
+ drm_intel_gem_bo_unmap_gtt(bos[i]);
+ }
+
+ /* and recheck whether a second map of the same still works */
+ for (i = 0; i < BO_ARRAY_SIZE; i++) {
+ bos[i] = drm_intel_bo_alloc(bufmgr, "mmap bo", 4096, 4096);
+ assert(bos[i]);
+
+ drm_intel_gem_bo_map_gtt(bos[i]);
+ ptr = bos[i]->virtual;
+ assert(*ptr = 'c');
+ drm_intel_gem_bo_unmap_gtt(bos[i]);
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/flip_test.c b/tests/flip_test.c
new file mode 100644
index 00000000..67105905
--- /dev/null
+++ b/tests/flip_test.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2012 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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 "config.h"
+
+#include <assert.h>
+#include <cairo.h>
+#include <errno.h>
+#include <math.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "testdisplay.h"
+
+drmModeRes *resources;
+int drm_fd;
+int test_time = 3;
+
+uint32_t *fb_ptr;
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+struct type_name {
+ int type;
+ const char *name;
+};
+
+struct test_output {
+ uint32_t id;
+ int mode_valid;
+ drmModeModeInfo mode;
+ drmModeEncoder *encoder;
+ drmModeConnector *connector;
+ int crtc;
+ int pipe;
+ unsigned int current_fb_id;
+ unsigned int fb_ids[2];
+};
+
+static void page_flip_handler(int fd, unsigned int frame, unsigned int sec,
+ unsigned int usec, void *data)
+{
+ struct test_output *o = data;
+ unsigned int new_fb_id;
+
+ if (o->current_fb_id == o->fb_ids[0])
+ new_fb_id = o->fb_ids[1];
+ else
+ new_fb_id = o->fb_ids[0];
+
+ drmModePageFlip(drm_fd, o->crtc, new_fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT, o);
+ o->current_fb_id = new_fb_id;
+}
+
+static void connector_find_preferred_mode(struct test_output *o, int crtc_id)
+{
+ drmModeConnector *connector;
+ drmModeEncoder *encoder = NULL;
+ int i, j;
+
+ /* First, find the connector & mode */
+ o->mode_valid = 0;
+ o->crtc = 0;
+ connector = drmModeGetConnector(drm_fd, o->id);
+ assert(connector);
+
+ if (connector->connection != DRM_MODE_CONNECTED) {
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ if (!connector->count_modes) {
+ fprintf(stderr, "connector %d has no modes\n", o->id);
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ if (connector->connector_id != o->id) {
+ fprintf(stderr, "connector id doesn't match (%d != %d)\n",
+ connector->connector_id, o->id);
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ for (j = 0; j < connector->count_modes; j++) {
+ o->mode = connector->modes[j];
+ if (o->mode.type & DRM_MODE_TYPE_PREFERRED) {
+ o->mode_valid = 1;
+ break;
+ }
+ }
+
+ if (!o->mode_valid) {
+ if (connector->count_modes > 0) {
+ /* use the first mode as test mode */
+ o->mode = connector->modes[0];
+ o->mode_valid = 1;
+ }
+ else {
+ fprintf(stderr, "failed to find any modes on connector %d\n",
+ o->id);
+ return;
+ }
+ }
+
+ /* Now get the encoder */
+ for (i = 0; i < connector->count_encoders; i++) {
+ encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
+
+ if (!encoder) {
+ fprintf(stderr, "could not get encoder %i: %s\n",
+ resources->encoders[i], strerror(errno));
+ drmModeFreeEncoder(encoder);
+ continue;
+ }
+
+ break;
+ }
+
+ o->encoder = encoder;
+
+ if (i == resources->count_encoders) {
+ fprintf(stderr, "failed to find encoder\n");
+ o->mode_valid = 0;
+ return;
+ }
+
+ /* Find first CRTC not in use */
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (resources->crtcs[i] != crtc_id)
+ continue;
+ if (resources->crtcs[i] &&
+ (o->encoder->possible_crtcs & (1<<i))) {
+ o->crtc = resources->crtcs[i];
+ break;
+ }
+ }
+
+ if (!o->crtc) {
+ fprintf(stderr, "could not find requested crtc %d\n", crtc_id);
+ o->mode_valid = 0;
+ return;
+ }
+
+ o->pipe = i;
+
+ o->connector = connector;
+}
+
+static void
+paint_flip_mode(cairo_t *cr, int width, int height, void *priv)
+{
+ bool odd_frame = (bool) priv;
+
+ if (odd_frame)
+ cairo_rectangle(cr, width/4, height/2, width/4, height/8);
+ else
+ cairo_rectangle(cr, width/2, height/2, width/4, height/8);
+
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+}
+
+static void set_mode(struct test_output *o, int crtc)
+{
+ int ret;
+ int bpp = 32, depth = 24;
+ drmEventContext evctx;
+ int width, height;
+ struct timeval end;
+ struct kmstest_fb fb_info[2];
+
+ connector_find_preferred_mode(o, crtc);
+ if (!o->mode_valid)
+ return;
+
+ width = o->mode.hdisplay;
+ height = o->mode.vdisplay;
+
+ o->fb_ids[0] = kmstest_create_fb(drm_fd, width, height, bpp, depth,
+ false, &fb_info[0],
+ paint_flip_mode, (void *)false);
+ o->fb_ids[1] = kmstest_create_fb(drm_fd, width, height, bpp, depth,
+ false, &fb_info[1],
+ paint_flip_mode, (void *)true);
+ if (!o->fb_ids[0] || !o->fb_ids[1]) {
+ fprintf(stderr, "failed to create fbs\n");
+ exit(3);
+ }
+
+ gem_close(drm_fd, fb_info[0].gem_handle);
+ gem_close(drm_fd, fb_info[1].gem_handle);
+
+ kmstest_dump_mode(&o->mode);
+ if (drmModeSetCrtc(drm_fd, o->crtc, o->fb_ids[0], 0, 0,
+ &o->id, 1, &o->mode)) {
+ fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n",
+ width, height, o->mode.vrefresh,
+ strerror(errno));
+ exit(3);
+ }
+
+ ret = drmModePageFlip(drm_fd, o->crtc, o->fb_ids[1],
+ DRM_MODE_PAGE_FLIP_EVENT, o);
+ if (ret) {
+ fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
+ exit(4);
+ }
+ o->current_fb_id = o->fb_ids[1];
+
+ memset(&evctx, 0, sizeof evctx);
+ evctx.version = DRM_EVENT_CONTEXT_VERSION;
+ evctx.vblank_handler = NULL;
+ evctx.page_flip_handler = page_flip_handler;
+
+ gettimeofday(&end, NULL);
+ end.tv_sec += 3;
+
+ while (1) {
+ struct timeval now, timeout = { .tv_sec = 3, .tv_usec = 0 };
+ fd_set fds;
+
+ FD_ZERO(&fds);
+ FD_SET(0, &fds);
+ FD_SET(drm_fd, &fds);
+ ret = select(drm_fd + 1, &fds, NULL, NULL, &timeout);
+
+ if (ret <= 0) {
+ fprintf(stderr, "select timed out or error (ret %d)\n",
+ ret);
+ exit(1);
+ } else if (FD_ISSET(0, &fds)) {
+ fprintf(stderr, "no fds active, breaking\n");
+ exit(2);
+ }
+
+ gettimeofday(&now, NULL);
+ if (now.tv_sec > end.tv_sec ||
+ (now.tv_sec == end.tv_sec && now.tv_usec >= end.tv_usec)) {
+ ret = 0;
+ break;
+ }
+
+ drmHandleEvent(drm_fd, &evctx);
+ }
+
+ fprintf(stdout, "page flipping on crtc %d, connector %d: PASSED\n",
+ crtc, o->id);
+
+ drmModeFreeEncoder(o->encoder);
+ drmModeFreeConnector(o->connector);
+}
+
+static int run_test(void)
+{
+ struct test_output *connectors;
+ int c, i;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ fprintf(stderr, "drmModeGetResources failed: %s\n",
+ strerror(errno));
+ exit(5);
+ }
+
+ connectors = calloc(resources->count_connectors,
+ sizeof(struct test_output));
+ assert(connectors);
+
+ /* Find any connected displays */
+ for (c = 0; c < resources->count_connectors; c++) {
+ connectors[c].id = resources->connectors[c];
+ for (i = 0; i < resources->count_crtcs; i++)
+ set_mode(&connectors[c], resources->crtcs[i]);
+ }
+
+ drmModeFreeResources(resources);
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ drm_fd = drm_open_any();
+
+ run_test();
+
+ close(drm_fd);
+
+ return 0;
+}
diff --git a/tests/gem_bad_address.c b/tests/gem_bad_address.c
new file mode 100644
index 00000000..fbb96497
--- /dev/null
+++ b/tests/gem_bad_address.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+#define BAD_GTT_DEST ((512*1024*1024)) /* past end of aperture */
+
+static void
+bad_store(void)
+{
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_STORE_DWORD_IMM | MI_MEM_VIRTUAL | 1 << 21);
+ OUT_BATCH(0);
+ OUT_BATCH(BAD_GTT_DEST);
+ OUT_BATCH(0xdeadbeef);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ bad_store();
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_bad_batch.c b/tests/gem_bad_batch.c
new file mode 100644
index 00000000..db6636ae
--- /dev/null
+++ b/tests/gem_bad_batch.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+static void
+bad_batch(void)
+{
+ BEGIN_BATCH(2);
+ OUT_BATCH(MI_BATCH_BUFFER_START);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ bad_batch();
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_bad_blit.c b/tests/gem_bad_blit.c
new file mode 100644
index 00000000..22165270
--- /dev/null
+++ b/tests/gem_bad_blit.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_tiled_blits.c
+ *
+ * This is a test of doing many tiled blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to catch a couple types of failure;
+ * - Fence management problems on pre-965.
+ * - A17 or L-shaped memory tiling workaround problems in acceleration.
+ *
+ * The model is to fill a collection of 1MB objects in a way that can't trip
+ * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled
+ * object. Then, copy the 1MB objects randomly between each other for a while.
+ * Finally, download their data through linear objects again and see what
+ * resulted.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+#define BAD_GTT_DEST ((256*1024*1024)) /* past end of aperture */
+
+static void
+bad_blit(drm_intel_bo *src_bo, uint32_t devid)
+{
+ uint32_t src_pitch = 512, dst_pitch = 512;
+ uint32_t cmd_bits = 0;
+
+ if (IS_965(devid)) {
+ src_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ if (IS_965(devid)) {
+ dst_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ cmd_bits);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ dst_pitch);
+ OUT_BATCH(0); /* dst x1,y1 */
+ OUT_BATCH((64 << 16) | 64); /* 64x64 blit */
+ OUT_BATCH(BAD_GTT_DEST);
+ OUT_BATCH(0); /* src x1,y1 */
+ OUT_BATCH(src_pitch);
+ OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+int main(int argc, char **argv)
+{
+ drm_intel_bo *src;
+ int fd;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ src = drm_intel_bo_alloc(bufmgr, "src", 128 * 128, 4096);
+
+ bad_blit(src, batch->devid);
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_bad_length.c b/tests/gem_bad_length.c
new file mode 100644
index 00000000..41f44d7f
--- /dev/null
+++ b/tests/gem_bad_length.c
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+
+/*
+ * Testcase: Minmal bo_create and batchbuffer exec
+ *
+ * Originally this caught an kernel oops due to the unchecked assumption that
+ * objects have size > 0.
+ */
+
+static uint32_t do_gem_create(int fd, int size, int *retval)
+{
+ struct drm_i915_gem_create create;
+ int ret;
+
+ create.handle = 0;
+ create.size = (size + 4095) & -4096;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ assert(retval || ret == 0);
+ if (retval)
+ *retval = errno;
+
+ return create.handle;
+}
+
+static int gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
+{
+ return drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, execbuf);
+}
+
+static void create0(int fd)
+{
+ int retval = 0;
+ printf("trying to create a zero-length gem object\n");
+ do_gem_create(fd, 0, &retval);
+ assert(retval == EINVAL);
+}
+
+static void exec0(int fd)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 exec[1];
+ uint32_t buf[2] = { MI_BATCH_BUFFER_END, 0 };
+
+ /* Just try executing with a zero-length bo.
+ * We expect the kernel to either accept the nop batch, or reject it
+ * for the zero-length buffer, but never crash.
+ */
+
+ exec[0].handle = gem_create(fd, 4096);
+ gem_write(fd, exec[0].handle, 0, buf, sizeof(buf));
+ exec[0].relocation_count = 0;
+ exec[0].relocs_ptr = 0;
+ exec[0].alignment = 0;
+ exec[0].offset = 0;
+ exec[0].flags = 0;
+ exec[0].rsvd1 = 0;
+ exec[0].rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = sizeof(buf);
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = 0;
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ execbuf.rsvd2 = 0;
+
+ printf("trying to run an empty batchbuffer\n");
+ gem_exec(fd, &execbuf);
+
+ gem_close(fd, exec[0].handle);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ create0(fd);
+
+ //exec0(fd);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_basic.c b/tests/gem_basic.c
new file mode 100644
index 00000000..24ad445f
--- /dev/null
+++ b/tests/gem_basic.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2008 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 <eric@anholt.net>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+static void
+test_bad_close(int fd)
+{
+ struct drm_gem_close close_bo;
+ int ret;
+
+ printf("Testing error return on bad close ioctl.\n");
+
+ close_bo.handle = 0x10101010;
+ ret = ioctl(fd, DRM_IOCTL_GEM_CLOSE, &close_bo);
+
+ assert(ret == -1 && errno == EINVAL);
+}
+
+static void
+test_create_close(int fd)
+{
+ uint32_t handle;
+
+ printf("Testing creating and closing an object.\n");
+
+ handle = gem_create(fd, 16*1024);
+
+ gem_close(fd, handle);
+}
+
+static void
+test_create_fd_close(int fd)
+{
+ printf("Testing closing with an object allocated.\n");
+
+ gem_create(fd, 16*1024);
+ /* leak it */
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ test_bad_close(fd);
+ test_create_close(fd);
+ test_create_fd_close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_cpu_concurrent_blit.c b/tests/gem_cpu_concurrent_blit.c
new file mode 100644
index 00000000..fd517d00
--- /dev/null
+++ b/tests/gem_cpu_concurrent_blit.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright © 2009,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:
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gem_cpu_concurrent_blit.c
+ *
+ * This is a test of CPU read/write behavior when writing to active
+ * buffers.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static void
+set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
+{
+ int size = width * height;
+ uint32_t *vaddr;
+
+ drm_intel_bo_map(bo, true);
+ vaddr = bo->virtual;
+ while (size--)
+ *vaddr++ = val;
+ drm_intel_bo_unmap(bo);
+}
+
+static void
+cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
+{
+ int size = width * height;
+ uint32_t *vaddr;
+
+ drm_intel_bo_map(bo, false);
+ vaddr = bo->virtual;
+ while (size--)
+ assert(*vaddr++ == val);
+ drm_intel_bo_unmap(bo);
+}
+
+static drm_intel_bo *
+create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
+{
+ drm_intel_bo *bo;
+
+ bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0);
+ assert(bo);
+
+ set_bo(bo, val, width, height);
+
+ return bo;
+}
+
+int
+main(int argc, char **argv)
+{
+ drm_intel_bufmgr *bufmgr;
+ struct intel_batchbuffer *batch;
+ int num_buffers = 128, max;
+ drm_intel_bo *src[128], *dst[128], *dummy;
+ int width = 512, height = 512;
+ int fd;
+ int i;
+
+ fd = drm_open_any();
+
+ max = gem_aperture_size (fd) / (1024 * 1024) / 2;
+ if (num_buffers > max)
+ num_buffers = max;
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ for (i = 0; i < num_buffers; i++) {
+ src[i] = create_bo(bufmgr, i, width, height);
+ dst[i] = create_bo(bufmgr, ~i, width, height);
+ }
+ dummy = create_bo(bufmgr, 0, width, height);
+
+ /* try to overwrite the source values */
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ set_bo(src[i], 0xdeadbeef, width, height);
+ for (i = 0; i < num_buffers; i++)
+ cmp_bo(dst[i], i, width, height);
+
+ /* try to read the results before the copy completes */
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ cmp_bo(dst[i], 0xdeadbeef, width, height);
+
+ /* and finally try to trick the kernel into loosing the pending write */
+ for (i = num_buffers; i--; )
+ set_bo(src[i], 0xabcdabcd, width, height);
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ intel_copy_bo(batch, dummy, dst[i], width, height);
+ for (i = num_buffers; i--; )
+ cmp_bo(dst[i], 0xabcdabcd, width, height);
+
+ return 0;
+}
diff --git a/tests/gem_cs_prefetch.c b/tests/gem_cs_prefetch.c
new file mode 100644
index 00000000..4fb2fc4e
--- /dev/null
+++ b/tests/gem_cs_prefetch.c
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/*
+ * Testcase: Test the CS prefetch behaviour on batches
+ *
+ * Historically the batch prefetcher doesn't check whether it's crossing page
+ * boundaries and likes to throw up when it gets a pagefault in return for his
+ * over-eager behaviour. Check for this.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+static void exec(int fd, uint32_t handle)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 gem_exec[1];
+ int ret = 0;
+
+ gem_exec[0].handle = handle;
+ gem_exec[0].relocation_count = 0;
+ gem_exec[0].relocs_ptr = 0;
+ gem_exec[0].alignment = 0;
+ gem_exec[0].offset = 0;
+ gem_exec[0].flags = 0;
+ gem_exec[0].rsvd1 = 0;
+ gem_exec[0].rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)gem_exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = 4096;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = 0;
+ execbuf.rsvd1 = 0;
+ execbuf.rsvd2 = 0;
+
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf);
+ gem_sync(fd, handle);
+ assert(ret == 0);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t batch_end[4] = {MI_BATCH_BUFFER_END, 0, 0, 0};
+ int fd, i, ret;
+ uint64_t aper_size;
+ int count;
+ drm_intel_bo *sample_batch_bo;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ aper_size = gem_aperture_size(fd);
+
+ /* presume a big per-bo overhead */
+ if (intel_get_total_ram_mb() < (aper_size / (1024*1024)) * 3 / 2) {
+ fprintf(stderr, "not enough mem to run test\n");
+ return 77;
+ }
+
+ count = aper_size / 4096;
+
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+ assert(batch);
+
+ sample_batch_bo = drm_intel_bo_alloc(bufmgr, "", 4096, 4096);
+ assert(sample_batch_bo);
+ ret = drm_intel_bo_subdata(sample_batch_bo, 4096-sizeof(batch_end),
+ sizeof(batch_end), batch_end);
+ assert(ret == 0);
+
+ /* fill the entire gart with batches and run them */
+ for (i = 0; i < count; i++) {
+ drm_intel_bo *batch_bo;
+
+ batch_bo = drm_intel_bo_alloc(bufmgr, "", 4096, 4096);
+ assert(batch_bo);
+
+ /* copy the sample batch with the gpu to the new one, so that we
+ * also test the unmappable part of the gtt. */
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 4096);
+ OUT_BATCH(0); /* dst y1,x1 */
+ OUT_BATCH((1 << 16) | 1024);
+ OUT_RELOC(batch_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH((0 << 16) | 0); /* src x1, y1 */
+ OUT_BATCH(4096);
+ OUT_RELOC(sample_batch_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+ if (i % 100 == 0)
+ gem_sync(fd, batch_bo->handle);
+
+ drm_intel_bo_disable_reuse(batch_bo);
+
+ /* launch the newly created batch */
+ exec(fd, batch_bo->handle);
+
+ // leak buffers
+ //drm_intel_bo_unreference(batch_bo);
+ drmtest_progress("gem_cs_prefetch: ", i, count);
+ }
+
+ fprintf(stderr, "Test suceeded, cleanup up - this might take a while.\n");
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_ctx_bad_destroy.c b/tests/gem_ctx_bad_destroy.c
new file mode 100644
index 00000000..02d24eb3
--- /dev/null
+++ b/tests/gem_ctx_bad_destroy.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+/*
+ * Negative test cases for destroy contexts
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "i915_drm.h"
+#include "drmtest.h"
+
+struct local_drm_i915_context_create {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+struct local_drm_i915_context_destroy {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_context_create)
+#define CONTEXT_DESTROY_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2e, struct local_drm_i915_context_destroy)
+
+static uint32_t context_create(int fd)
+{
+ struct local_drm_i915_context_create create;
+ int ret;
+
+ ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+ if (ret == -1 && (errno == ENODEV || errno == EINVAL))
+ exit(77);
+ else if (ret)
+ abort();
+
+ return create.ctx_id;
+}
+
+static void handle_bad(int ret, int lerrno, int expected, const char *desc)
+{
+ if (ret != 0 && lerrno != expected) {
+ fprintf(stderr, "%s - errno was %d, but should have been %d\n",
+ desc, lerrno, expected);
+ exit(EXIT_FAILURE);
+ } else if (ret == 0) {
+ fprintf(stderr, "%s - Command succeeded, but should have failed\n",
+ desc);
+ exit(EXIT_FAILURE);
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ struct local_drm_i915_context_destroy destroy;
+ uint32_t ctx_id;
+ int ret, fd;
+
+ fd = drm_open_any();
+
+ ctx_id = context_create(fd);
+
+ destroy.ctx_id = ctx_id;
+ /* Make sure a proper destroy works first */
+ ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy);
+ assert(ret == 0);
+
+ /* try double destroy */
+ ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy);
+ handle_bad(ret, errno, ENOENT, "double destroy");
+
+ /* destroy something random */
+ destroy.ctx_id = 2;
+ ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy);
+ handle_bad(ret, errno, ENOENT, "random destroy");
+
+ /* Try to destroy the default context */
+ destroy.ctx_id = 0;
+ ret = drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &destroy);
+ handle_bad(ret, errno, ENOENT, "default destroy");
+
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_ctx_bad_exec.c b/tests/gem_ctx_bad_exec.c
new file mode 100644
index 00000000..8a57fd41
--- /dev/null
+++ b/tests/gem_ctx_bad_exec.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+/*
+ * Negative test cases:
+ * test we can't submit contexts to unsupported rings
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+struct local_drm_i915_gem_context_create {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create)
+
+static uint32_t context_create(int fd)
+{
+ struct local_drm_i915_gem_context_create create;
+ int ret;
+
+ ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+ if (ret == -1 && (errno == ENODEV || errno == EINVAL)) {
+ exit(77);
+ } else if (ret) {
+ abort();
+ }
+
+ return create.ctx_id;
+}
+
+/* Copied from gem_exec_nop.c */
+static int exec(int fd, uint32_t handle, int ring, int ctx_id)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 gem_exec;
+ int ret = 0;
+
+ gem_exec.handle = handle;
+ gem_exec.relocation_count = 0;
+ gem_exec.relocs_ptr = 0;
+ gem_exec.alignment = 0;
+ gem_exec.offset = 0;
+ gem_exec.flags = 0;
+ gem_exec.rsvd1 = 0;
+ gem_exec.rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)&gem_exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = 8;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = ring;
+ i915_execbuffer2_set_context_id(execbuf, ctx_id);
+ execbuf.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf);
+ gem_sync(fd, handle);
+
+ return ret;
+}
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+int main(int argc, char *argv[])
+{
+ uint32_t handle;
+ uint32_t batch[2] = {MI_BATCH_BUFFER_END};
+ uint32_t ctx_id;
+ int fd;
+ fd = drm_open_any();
+
+ ctx_id = context_create(fd);
+
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+ assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0);
+ assert(exec(fd, handle, I915_EXEC_BSD, ctx_id) != 0);
+ assert(exec(fd, handle, I915_EXEC_BLT, ctx_id) != 0);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_ctx_basic.c b/tests/gem_ctx_basic.c
new file mode 100644
index 00000000..632651ae
--- /dev/null
+++ b/tests/gem_ctx_basic.c
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+/*
+ * This test is useful for finding memory and refcount leaks.
+ */
+
+#include <pthread.h>
+#include "rendercopy.h"
+
+/* options */
+int num_contexts = 10;
+int uncontexted = 0; /* test only context create/destroy */
+int multiple_fds = 1;
+int iter = 10000;
+
+/* globals */
+pthread_t *threads;
+int *returns;
+int devid;
+int fd;
+
+static void init_buffer(drm_intel_bufmgr *bufmgr,
+ struct scratch_buf *buf,
+ uint32_t size)
+{
+ buf->bo = drm_intel_bo_alloc(bufmgr, "", size, 4096);
+ buf->size = size;
+ assert(buf->bo);
+ buf->tiling = I915_TILING_NONE;
+ buf->stride = 4096;
+}
+
+static void *work(void *arg)
+{
+ struct intel_batchbuffer *batch;
+ drm_intel_context *context;
+ drm_intel_bufmgr *bufmgr;
+ int thread_id = *(int *)arg;
+ int td_fd;
+ int i;
+
+ if (multiple_fds)
+ td_fd = fd = drm_open_any();
+ else
+ td_fd = fd;
+
+ assert(td_fd >= 0);
+
+ bufmgr = drm_intel_bufmgr_gem_init(td_fd, 4096);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ context = drm_intel_gem_context_create(bufmgr);
+
+ if (!context) {
+ returns[thread_id] = 77;
+ goto out;
+ }
+
+ for (i = 0; i < iter; i++) {
+ struct scratch_buf src, dst;
+
+ init_buffer(bufmgr, &src, 4096);
+ init_buffer(bufmgr, &dst, 4096);
+
+
+ if (uncontexted) {
+ gen6_render_copyfunc(batch, &src, 0, 0, 0, 0, &dst, 0, 0);
+ } else {
+ int ret;
+ ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer);
+ assert(ret == 0);
+ intel_batchbuffer_flush_with_context(batch, context);
+ }
+ }
+
+out:
+ drm_intel_gem_context_destroy(context);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ if (multiple_fds)
+ close(td_fd);
+
+ pthread_exit(&returns[thread_id]);
+}
+
+static void parse(int argc, char *argv[])
+{
+ int opt;
+ while ((opt = getopt(argc, argv, "i:c:n:muh?")) != -1) {
+ switch (opt) {
+ case 'i':
+ iter = atoi(optarg);
+ break;
+ case 'c':
+ num_contexts = atoi(optarg);
+ break;
+ case 'm':
+ multiple_fds = 1;
+ break;
+ case 'u':
+ uncontexted = 1;
+ break;
+ case 'h':
+ case '?':
+ default:
+ exit(EXIT_SUCCESS);
+ break;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ parse(argc, argv);
+
+ threads = calloc(num_contexts, sizeof(*threads));
+ returns = calloc(num_contexts, sizeof(*returns));
+
+ for (i = 0; i < num_contexts; i++)
+ pthread_create(&threads[i], NULL, work, &i);
+
+ for (i = 0; i < num_contexts; i++) {
+ int thread_status, ret;
+ void *retval;
+ ret = pthread_join(threads[i], &retval);
+ thread_status = *(int *)retval;
+ if (!ret && thread_status)
+ exit(thread_status);
+ }
+
+ free(returns);
+ free(threads);
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_ctx_create.c b/tests/gem_ctx_create.c
new file mode 100644
index 00000000..def76d34
--- /dev/null
+++ b/tests/gem_ctx_create.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "i915_drm.h"
+#include "drmtest.h"
+
+struct local_drm_i915_gem_context_create {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create)
+
+int main(int argc, char *argv[])
+{
+ int ret, fd;
+ struct local_drm_i915_gem_context_create create;
+
+ create.ctx_id = rand();
+ create.pad = rand();
+
+ fd = drm_open_any();
+
+ ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+ if (ret != 0 && (errno == ENODEV || errno == EINVAL)) {
+ fprintf(stderr, "Kernel is too old, or contexts not supported: %s\n",
+ strerror(errno));
+ exit(77);
+ } else if (ret != 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ assert(create.ctx_id != 0);
+
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_ctx_exec.c b/tests/gem_ctx_exec.c
new file mode 100644
index 00000000..423f1eec
--- /dev/null
+++ b/tests/gem_ctx_exec.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+/*
+ * This test covers basic context switch functionality
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+struct local_drm_i915_gem_context_create {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+struct local_drm_i915_gem_context_destroy {
+ __u32 ctx_id;
+ __u32 pad;
+};
+
+#define CONTEXT_CREATE_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2d, struct local_drm_i915_gem_context_create)
+#define CONTEXT_DESTROY_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x23, struct local_drm_i915_gem_context_destroy)
+
+static uint32_t context_create(int fd)
+{
+ struct local_drm_i915_gem_context_create create;
+ int ret;
+
+ ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+ if (ret == -1 && (errno == ENODEV || errno == EINVAL))
+ exit(77);
+ else if (ret)
+ abort();
+
+ return create.ctx_id;
+}
+
+static void context_destroy(int fd, uint32_t ctx_id)
+{
+ struct local_drm_i915_gem_context_destroy destroy;
+ destroy.ctx_id = ctx_id;
+ do_ioctl(fd, CONTEXT_DESTROY_IOCTL, &destroy);
+}
+
+/* Copied from gem_exec_nop.c */
+static int exec(int fd, uint32_t handle, int ring, int ctx_id)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 gem_exec;
+ int ret = 0;
+
+ gem_exec.handle = handle;
+ gem_exec.relocation_count = 0;
+ gem_exec.relocs_ptr = 0;
+ gem_exec.alignment = 0;
+ gem_exec.offset = 0;
+ gem_exec.flags = 0;
+ gem_exec.rsvd1 = 0;
+ gem_exec.rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)&gem_exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = 8;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = ring;
+ i915_execbuffer2_set_context_id(execbuf, ctx_id);
+ execbuf.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf);
+ gem_sync(fd, handle);
+
+ return ret;
+}
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+int main(int argc, char *argv[])
+{
+ uint32_t handle;
+ uint32_t batch[2] = {0, MI_BATCH_BUFFER_END};
+ uint32_t ctx_id;
+ int fd;
+ fd = drm_open_any();
+
+ ctx_id = context_create(fd);
+ handle = gem_create(fd, 4096);
+
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+ assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0);
+ context_destroy(fd, ctx_id);
+
+ ctx_id = context_create(fd);
+ assert(exec(fd, handle, I915_EXEC_RENDER, ctx_id) == 0);
+ context_destroy(fd, ctx_id);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_double_irq_loop.c b/tests/gem_double_irq_loop.c
new file mode 100644
index 00000000..f2f8b1a8
--- /dev/null
+++ b/tests/gem_double_irq_loop.c
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+#include "i830_reg.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer, *blt_bo;
+
+/*
+ * Testcase: Basic check for missed irqs on blt
+ *
+ * Execs one large and then immediately a tiny batch on the blt ring. Then waits
+ * on the second batch. This hopefully catches races in our irq acknowledgement.
+ */
+
+
+#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1)
+#define MI_DO_COMPARE (1<<21)
+static void
+dummy_reloc_loop(void)
+{
+ int i;
+
+ for (i = 0; i < 0x800; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 4*4096);
+ OUT_BATCH(2048 << 16 | 0);
+ OUT_BATCH((4096) << 16 | (2048));
+ OUT_RELOC_FENCED(blt_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(4*4096);
+ OUT_RELOC_FENCED(blt_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+ intel_batchbuffer_flush(batch);
+
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_FLUSH_DW | 1);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP | (1<<22) | (0xf));
+ ADVANCE_BATCH();
+ intel_batchbuffer_flush(batch);
+
+ drm_intel_bo_map(target_buffer, 0);
+ // map to force completion
+ drm_intel_bo_unmap(target_buffer);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+ if (!HAS_BLT_RING(devid)) {
+ fprintf(stderr, "not (yet) implemented for pre-snb\n");
+ return 77;
+ }
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ blt_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4*4096*4096, 4096);
+ if (!blt_bo) {
+ fprintf(stderr, "failed to alloc blt buffer\n");
+ exit(-1);
+ }
+
+ dummy_reloc_loop();
+
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_dummy_reloc_loop.c b/tests/gem_dummy_reloc_loop.c
new file mode 100644
index 00000000..82d8f77e
--- /dev/null
+++ b/tests/gem_dummy_reloc_loop.c
@@ -0,0 +1,194 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+#include "i830_reg.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer;
+
+/*
+ * Testcase: Basic check of ring<->cpu sync using a dummy reloc
+ *
+ * The last test (that randomly switches the ring) seems to be pretty effective
+ * at hitting the missed irq bug that's worked around with the HWSTAM irq write.
+ */
+
+
+#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1)
+#define MI_DO_COMPARE (1<<21)
+static void
+dummy_reloc_loop(int ring)
+{
+ int i;
+
+ for (i = 0; i < 0x100000; i++) {
+ if (ring == I915_EXEC_RENDER) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE);
+ OUT_BATCH(0xffffffff); /* compare dword */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP);
+ ADVANCE_BATCH();
+ } else {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_FLUSH_DW | 1);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP | (1<<22) | (0xf));
+ ADVANCE_BATCH();
+ }
+ intel_batchbuffer_flush_on_ring(batch, ring);
+
+ drm_intel_bo_map(target_buffer, 0);
+ // map to force completion
+ drm_intel_bo_unmap(target_buffer);
+ }
+}
+
+static void
+dummy_reloc_loop_random_ring(void)
+{
+ int i;
+
+ srandom(0xdeadbeef);
+
+ for (i = 0; i < 0x100000; i++) {
+ int ring = random() % 3 + 1;
+
+ if (ring == I915_EXEC_RENDER) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE);
+ OUT_BATCH(0xffffffff); /* compare dword */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP);
+ ADVANCE_BATCH();
+ } else {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_FLUSH_DW | 1);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP | (1<<22) | (0xf));
+ ADVANCE_BATCH();
+ }
+ intel_batchbuffer_flush_on_ring(batch, ring);
+
+ drm_intel_bo_map(target_buffer, 0);
+ // map to force waiting on rendering
+ drm_intel_bo_unmap(target_buffer);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+ if (!HAS_BLT_RING(devid)) {
+ fprintf(stderr, "not (yet) implemented for pre-snb\n");
+ return 77;
+ }
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ fprintf(stderr, "running dummy loop on render\n");
+ dummy_reloc_loop(I915_EXEC_RENDER);
+ fprintf(stderr, "dummy loop run on render completed\n");
+
+ if (!HAS_BSD_RING(devid))
+ goto skip;
+
+ sleep(2);
+ fprintf(stderr, "running dummy loop on bsd\n");
+ dummy_reloc_loop(I915_EXEC_BSD);
+ fprintf(stderr, "dummy loop run on bsd completed\n");
+
+ if (!HAS_BLT_RING(devid))
+ goto skip;
+
+ sleep(2);
+ fprintf(stderr, "running dummy loop on blt\n");
+ dummy_reloc_loop(I915_EXEC_BLT);
+ fprintf(stderr, "dummy loop run on blt completed\n");
+
+ sleep(2);
+ fprintf(stderr, "running dummy loop on random rings\n");
+ dummy_reloc_loop_random_ring();
+ fprintf(stderr, "dummy loop run on random rings completed\n");
+
+skip:
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_exec_bad_domains.c b/tests/gem_exec_bad_domains.c
new file mode 100644
index 00000000..f3ee08b7
--- /dev/null
+++ b/tests/gem_exec_bad_domains.c
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+/* Testcase: Test whether the kernel rejects relocations with non-gpu domains
+ *
+ * If it does not, it'll oops somewhen later on because we don't expect that.
+ */
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+#define BAD_GTT_DEST ((512*1024*1024)) /* past end of aperture */
+
+static int
+run_batch(void)
+{
+ unsigned int used = batch->ptr - batch->buffer;
+ int ret;
+
+ if (used == 0)
+ return 0;
+
+ /* Round batchbuffer usage to 2 DWORDs. */
+ if ((used & 4) == 0) {
+ *(uint32_t *) (batch->ptr) = 0; /* noop */
+ batch->ptr += 4;
+ }
+
+ /* Mark the end of the buffer. */
+ *(uint32_t *)(batch->ptr) = MI_BATCH_BUFFER_END; /* noop */
+ batch->ptr += 4;
+ used = batch->ptr - batch->buffer;
+
+ ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer);
+ assert(ret == 0);
+
+ batch->ptr = NULL;
+
+ ret = drm_intel_bo_mrb_exec(batch->bo, used, NULL, 0, 0, 0);
+
+ intel_batchbuffer_reset(batch);
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int fd, ret;
+ drm_intel_bo *tmp;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ tmp = drm_intel_bo_alloc(bufmgr, "tmp", 128 * 128, 4096);
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(0);
+ OUT_RELOC(tmp, I915_GEM_DOMAIN_CPU, 0, 0);
+ ADVANCE_BATCH();
+ ret = run_batch();
+ if (ret != -EINVAL) {
+ fprintf(stderr, "(cpu, 0) reloc not rejected\n");
+ exit(1);
+ }
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(0);
+ OUT_RELOC(tmp, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU, 0);
+ ADVANCE_BATCH();
+ ret = run_batch();
+ if (ret != -EINVAL) {
+ fprintf(stderr, "(cpu, cpu) reloc not rejected\n");
+ exit(1);
+ }
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(0);
+ OUT_RELOC(tmp, I915_GEM_DOMAIN_GTT, 0, 0);
+ ADVANCE_BATCH();
+ ret = run_batch();
+ if (ret != -EINVAL) {
+ fprintf(stderr, "(gtt, 0) reloc not rejected\n");
+ exit(1);
+ }
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(0);
+ OUT_RELOC(tmp, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT, 0);
+ ADVANCE_BATCH();
+ ret = run_batch();
+ if (ret != -EINVAL) {
+ fprintf(stderr, "(gtt, gtt) reloc not rejected\n");
+ exit(1);
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_exec_blt.c b/tests/gem_exec_blt.c
new file mode 100644
index 00000000..eb5ae668
--- /dev/null
+++ b/tests/gem_exec_blt.c
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+
+#define OBJECT_SIZE 16384
+
+#define COPY_BLT_CMD (2<<29|0x53<<22|0x6)
+#define BLT_WRITE_ALPHA (1<<21)
+#define BLT_WRITE_RGB (1<<20)
+#define BLT_SRC_TILED (1<<15)
+#define BLT_DST_TILED (1<<11)
+
+static int gem_linear_blt(uint32_t *batch,
+ uint32_t src,
+ uint32_t dst,
+ uint32_t length,
+ struct drm_i915_gem_relocation_entry *reloc)
+{
+ uint32_t *b = batch;
+ int height = length / (16 * 1024);
+
+ assert(height <= 1<<16);
+
+ if (height) {
+ b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024);
+ b[2] = 0;
+ b[3] = height << 16 | (4*1024);
+ b[4] = 0;
+ reloc->offset = (b-batch+4) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = dst;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = I915_GEM_DOMAIN_RENDER;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b[5] = 0;
+ b[6] = 16*1024;
+ b[7] = 0;
+ reloc->offset = (b-batch+7) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = src;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = 0;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b += 8;
+ length -= height * 16*1024;
+ }
+
+ if (length) {
+ b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024);
+ b[2] = height << 16;
+ b[3] = (1+height) << 16 | (length / 4);
+ b[4] = 0;
+ reloc->offset = (b-batch+4) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = dst;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = I915_GEM_DOMAIN_RENDER;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b[5] = height << 16;
+ b[6] = 16*1024;
+ b[7] = 0;
+ reloc->offset = (b-batch+7) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = src;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = 0;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b += 8;
+ }
+
+ b[0] = MI_BATCH_BUFFER_END;
+ b[1] = 0;
+
+ return (b+2 - batch) * sizeof(uint32_t);
+}
+
+static int gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf, int loops)
+{
+ int ret = 0;
+
+ while (loops-- && ret == 0) {
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ execbuf);
+ }
+
+ return ret;
+}
+
+static double elapsed(const struct timeval *start,
+ const struct timeval *end,
+ int loop)
+{
+ return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
+}
+
+static const char *bytes_per_sec(char *buf, double v)
+{
+ const char *order[] = {
+ "",
+ "KiB",
+ "MiB",
+ "GiB",
+ "TiB",
+ "PiB",
+ NULL,
+ }, **o = order;
+
+ while (v > 1024 && o[1]) {
+ v /= 1024;
+ o++;
+ }
+ sprintf(buf, "%.1f%s/s", v, *o);
+ return buf;
+}
+
+static void run(int object_size)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 exec[3];
+ struct drm_i915_gem_relocation_entry reloc[4];
+ uint32_t buf[20];
+ uint32_t handle, src, dst;
+ int fd, len, count;
+ int ring;
+
+ fd = drm_open_any();
+ handle = gem_create(fd, 4096);
+ src = gem_create(fd, object_size);
+ dst = gem_create(fd, object_size);
+
+ len = gem_linear_blt(buf, src, dst, object_size, reloc);
+ gem_write(fd, handle, 0, buf, len);
+
+ exec[0].handle = src;
+ exec[0].relocation_count = 0;
+ exec[0].relocs_ptr = 0;
+ exec[0].alignment = 0;
+ exec[0].offset = 0;
+ exec[0].flags = 0;
+ exec[0].rsvd1 = 0;
+ exec[0].rsvd2 = 0;
+
+ exec[1].handle = dst;
+ exec[1].relocation_count = 0;
+ exec[1].relocs_ptr = 0;
+ exec[1].alignment = 0;
+ exec[1].offset = 0;
+ exec[1].flags = 0;
+ exec[1].rsvd1 = 0;
+ exec[1].rsvd2 = 0;
+
+ exec[2].handle = handle;
+ exec[2].relocation_count = len > 40 ? 4 : 2;
+ exec[2].relocs_ptr = (uintptr_t)reloc;
+ exec[2].alignment = 0;
+ exec[2].offset = 0;
+ exec[2].flags = 0;
+ exec[2].rsvd1 = 0;
+ exec[2].rsvd2 = 0;
+
+ ring = 0;
+ if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+ ring = I915_EXEC_BLT;
+
+ execbuf.buffers_ptr = (uintptr_t)exec;
+ execbuf.buffer_count = 3;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = len;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = ring;
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ execbuf.rsvd2 = 0;
+
+ for (count = 1; count <= 1<<17; count <<= 1) {
+ struct timeval start, end;
+
+ gettimeofday(&start, NULL);
+ if (gem_exec(fd, &execbuf, count))
+ exit(1);
+ gem_sync(fd, handle);
+ gettimeofday(&end, NULL);
+ printf("Time to blt %d bytes x %6d: %7.3fµs, %s\n",
+ object_size, count,
+ elapsed(&start, &end, count),
+ bytes_per_sec((char *)buf, object_size/elapsed(&start, &end, count)*1e6));
+ fflush(stdout);
+ }
+ gem_close(fd, handle);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ if (argc > 1) {
+ for (i = 1; i < argc; i++) {
+ int object_size = atoi(argv[i]);
+ if (object_size)
+ run((object_size + 3) & -4);
+ }
+ } else
+ run(OBJECT_SIZE);
+
+ return 0;
+}
diff --git a/tests/gem_exec_faulting_reloc.c b/tests/gem_exec_faulting_reloc.c
new file mode 100644
index 00000000..863a1b03
--- /dev/null
+++ b/tests/gem_exec_faulting_reloc.c
@@ -0,0 +1,226 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_chipset.h"
+#include "intel_gpu_tools.h"
+
+/* Testcase: Submit patches with relocations in memory that will fault
+ *
+ * To be really evil, use a gtt mmap for them.
+ */
+
+#define OBJECT_SIZE 16384
+
+#define COPY_BLT_CMD (2<<29|0x53<<22|0x6)
+#define BLT_WRITE_ALPHA (1<<21)
+#define BLT_WRITE_RGB (1<<20)
+#define BLT_SRC_TILED (1<<15)
+#define BLT_DST_TILED (1<<11)
+
+static int gem_linear_blt(uint32_t *batch,
+ uint32_t src,
+ uint32_t dst,
+ uint32_t length,
+ struct drm_i915_gem_relocation_entry *reloc)
+{
+ uint32_t *b = batch;
+ int height = length / (16 * 1024);
+
+ assert(height <= 1<<16);
+
+ if (height) {
+ b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024);
+ b[2] = 0;
+ b[3] = height << 16 | (4*1024);
+ b[4] = 0;
+ reloc->offset = (b-batch+4) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = dst;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = I915_GEM_DOMAIN_RENDER;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b[5] = 0;
+ b[6] = 16*1024;
+ b[7] = 0;
+ reloc->offset = (b-batch+7) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = src;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = 0;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b += 8;
+ length -= height * 16*1024;
+ }
+
+ if (length) {
+ b[0] = COPY_BLT_CMD | BLT_WRITE_ALPHA | BLT_WRITE_RGB;
+ b[1] = 0xcc << 16 | 1 << 25 | 1 << 24 | (16*1024);
+ b[2] = height << 16;
+ b[3] = (1+height) << 16 | (length / 4);
+ b[4] = 0;
+ reloc->offset = (b-batch+4) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = dst;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = I915_GEM_DOMAIN_RENDER;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b[5] = height << 16;
+ b[6] = 16*1024;
+ b[7] = 0;
+ reloc->offset = (b-batch+7) * sizeof(uint32_t);
+ reloc->delta = 0;
+ reloc->target_handle = src;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = 0;
+ reloc->presumed_offset = 0;
+ reloc++;
+
+ b += 8;
+ }
+
+ b[0] = MI_BATCH_BUFFER_END;
+ b[1] = 0;
+
+ return (b+2 - batch) * sizeof(uint32_t);
+}
+
+static void gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
+{
+ int ret;
+
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ execbuf);
+ assert(ret == 0);
+}
+
+static void run(int object_size)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 exec[3];
+ struct drm_i915_gem_relocation_entry reloc[4];
+ uint32_t buf[20];
+ uint32_t handle, handle_relocs, src, dst;
+ void *gtt_relocs;
+ int fd, len;
+ int ring;
+
+ fd = drm_open_any();
+ handle = gem_create(fd, 4096);
+ src = gem_create(fd, object_size);
+ dst = gem_create(fd, object_size);
+
+ len = gem_linear_blt(buf, src, dst, object_size, reloc);
+ gem_write(fd, handle, 0, buf, len);
+
+ exec[0].handle = src;
+ exec[0].relocation_count = 0;
+ exec[0].relocs_ptr = 0;
+ exec[0].alignment = 0;
+ exec[0].offset = 0;
+ exec[0].flags = 0;
+ exec[0].rsvd1 = 0;
+ exec[0].rsvd2 = 0;
+
+ exec[1].handle = dst;
+ exec[1].relocation_count = 0;
+ exec[1].relocs_ptr = 0;
+ exec[1].alignment = 0;
+ exec[1].offset = 0;
+ exec[1].flags = 0;
+ exec[1].rsvd1 = 0;
+ exec[1].rsvd2 = 0;
+
+ handle_relocs = gem_create(fd, 4096);
+ gem_write(fd, handle_relocs, 0, reloc, sizeof(reloc));
+ gtt_relocs = gem_mmap(fd, handle_relocs, 4096,
+ PROT_READ | PROT_WRITE);
+ assert(gtt_relocs);
+
+ exec[2].handle = handle;
+ exec[2].relocation_count = len > 40 ? 4 : 2;
+ /* A newly mmap gtt bo will fault on first access. */
+ exec[2].relocs_ptr = (uintptr_t)gtt_relocs;
+ exec[2].alignment = 0;
+ exec[2].offset = 0;
+ exec[2].flags = 0;
+ exec[2].rsvd1 = 0;
+ exec[2].rsvd2 = 0;
+
+ ring = 0;
+ if (HAS_BLT_RING(intel_get_drm_devid(fd)))
+ ring = I915_EXEC_BLT;
+
+ execbuf.buffers_ptr = (uintptr_t)exec;
+ execbuf.buffer_count = 3;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = len;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = ring;
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ execbuf.rsvd2 = 0;
+
+ gem_exec(fd, &execbuf);
+ gem_sync(fd, handle);
+
+ gem_close(fd, handle);
+
+ close(fd);
+}
+
+int main(int argc, char **argv)
+{
+ run(OBJECT_SIZE);
+
+ return 0;
+}
diff --git a/tests/gem_exec_nop.c b/tests/gem_exec_nop.c
new file mode 100644
index 00000000..9dd055cf
--- /dev/null
+++ b/tests/gem_exec_nop.c
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+
+static double elapsed(const struct timeval *start,
+ const struct timeval *end,
+ int loop)
+{
+ return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
+}
+
+static int exec(int fd, uint32_t handle, int loops)
+{
+ struct drm_i915_gem_execbuffer2 execbuf;
+ struct drm_i915_gem_exec_object2 gem_exec[1];
+ int ret = 0;
+
+ gem_exec[0].handle = handle;
+ gem_exec[0].relocation_count = 0;
+ gem_exec[0].relocs_ptr = 0;
+ gem_exec[0].alignment = 0;
+ gem_exec[0].offset = 0;
+ gem_exec[0].flags = 0;
+ gem_exec[0].rsvd1 = 0;
+ gem_exec[0].rsvd2 = 0;
+
+ execbuf.buffers_ptr = (uintptr_t)gem_exec;
+ execbuf.buffer_count = 1;
+ execbuf.batch_start_offset = 0;
+ execbuf.batch_len = 8;
+ execbuf.cliprects_ptr = 0;
+ execbuf.num_cliprects = 0;
+ execbuf.DR1 = 0;
+ execbuf.DR4 = 0;
+ execbuf.flags = 0;
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ execbuf.rsvd2 = 0;
+
+ while (loops-- && ret == 0) {
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf);
+ }
+ gem_sync(fd, handle);
+
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t batch[2] = {MI_BATCH_BUFFER_END};
+ uint32_t handle;
+ int count;
+ int fd;
+
+ fd = drm_open_any();
+
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+
+ for (count = 1; count <= 1<<17; count <<= 1) {
+ struct timeval start, end;
+
+ gettimeofday(&start, NULL);
+ if (exec(fd, handle, count))
+ exit(1);
+ gettimeofday(&end, NULL);
+ printf("Time to exec x %d: %7.3fµs\n",
+ count, elapsed(&start, &end, count));
+ fflush(stdout);
+ }
+ gem_close(fd, handle);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_fence_thrash.c b/tests/gem_fence_thrash.c
new file mode 100644
index 00000000..3d50e334
--- /dev/null
+++ b/tests/gem_fence_thrash.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2008-9 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 <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE (128*1024) /* restricted to 1MiB alignment on i915 fences */
+
+/* Before introduction of the LRU list for fences, allocation of a fence for a page
+ * fault would use the first inactive fence (i.e. in preference one with no outstanding
+ * GPU activity, or it would wait on the first to finish). Given the choice, it would simply
+ * reuse the fence that had just been allocated for the previous page-fault - the worst choice
+ * when copying between two buffers and thus constantly swapping fences.
+ */
+
+static void *
+bo_create (int fd)
+{
+ void *ptr;
+ int handle;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ gem_set_tiling(fd, handle, I915_TILING_X, 1024);
+
+ ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
+
+ /* XXX: mmap_gtt pulls the bo into the GTT read domain. */
+ gem_sync(fd, handle);
+
+ return ptr;
+}
+
+static void *
+bo_copy (void *_arg)
+{
+ int fd = *(int *)_arg;
+ int n;
+ char *a, *b;
+
+ a = bo_create (fd);
+ b = bo_create (fd);
+
+ for (n = 0; n < 1000; n++) {
+ memcpy (a, b, OBJECT_SIZE);
+ sched_yield ();
+ }
+
+ return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+ drm_i915_getparam_t gp;
+ pthread_t threads[32];
+ int n, num_fences;
+ int fd, ret;
+
+ fd = drm_open_any();
+
+ gp.param = I915_PARAM_NUM_FENCES_AVAIL;
+ gp.value = &num_fences;
+ ret = ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ assert (ret == 0);
+
+ printf ("creating %d threads\n", num_fences);
+ assert (num_fences < sizeof (threads) / sizeof (threads[0]));
+
+ for (n = 0; n < num_fences; n++)
+ pthread_create (&threads[n], NULL, bo_copy, &fd);
+
+ for (n = 0; n < num_fences; n++)
+ pthread_join (threads[n], NULL);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_fenced_exec_thrash.c b/tests/gem_fenced_exec_thrash.c
new file mode 100644
index 00000000..8281449e
--- /dev/null
+++ b/tests/gem_fenced_exec_thrash.c
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <drm.h>
+#include <i915_drm.h>
+
+#include "drmtest.h"
+
+#define WIDTH 1024
+#define HEIGHT 1024
+#define OBJECT_SIZE (4*WIDTH*HEIGHT)
+
+#define BATCH_SIZE 4096
+
+#define MAX_FENCES 16
+
+#define MI_BATCH_BUFFER_END (0xA<<23)
+
+/*
+ * Testcase: execbuf fence accounting
+ *
+ * We had a bug where we were falsely accounting upon reservation already
+ * fenced buffers as occupying a fence register even if they did not require
+ * one for the batch.
+ *
+ * We aim to exercise this by performing a sequence of fenced BLT
+ * with 2*num_avail_fence buffers, but alternating which half are fenced in
+ * each command.
+ */
+
+static uint32_t
+tiled_bo_create (int fd)
+{
+ uint32_t handle;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ gem_set_tiling(fd, handle, I915_TILING_X, WIDTH*4);
+
+ return handle;
+}
+
+static uint32_t
+batch_create (int fd)
+{
+ uint32_t buf[] = { MI_BATCH_BUFFER_END, 0 };
+ uint32_t batch_handle;
+
+ batch_handle = gem_create(fd, BATCH_SIZE);
+
+ gem_write(fd, batch_handle, 0, buf, sizeof(buf));
+
+ return batch_handle;
+}
+
+static int get_num_fences(int fd)
+{
+ drm_i915_getparam_t gp;
+ int ret, val;
+
+ gp.param = I915_PARAM_NUM_FENCES_AVAIL;
+ gp.value = &val;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ assert (ret == 0);
+
+ printf ("total %d fences\n", val);
+ assert(val > 4);
+
+ return val - 2;
+}
+
+static void fill_reloc(struct drm_i915_gem_relocation_entry *reloc, uint32_t handle)
+{
+ reloc->offset = 2 * sizeof(uint32_t);
+ reloc->target_handle = handle;
+ reloc->read_domains = I915_GEM_DOMAIN_RENDER;
+ reloc->write_domain = 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ struct drm_i915_gem_execbuffer2 execbuf[2];
+ struct drm_i915_gem_exec_object2 exec[2][2*MAX_FENCES+1];
+ struct drm_i915_gem_relocation_entry reloc[2*MAX_FENCES];
+
+ int fd = drm_open_any();
+ int i, n, num_fences;
+ int loop = 1000;
+
+ memset(execbuf, 0, sizeof(execbuf));
+ memset(exec, 0, sizeof(exec));
+ memset(reloc, 0, sizeof(reloc));
+
+ num_fences = get_num_fences(fd) & ~1;
+ assert(num_fences <= MAX_FENCES);
+ for (n = 0; n < 2*num_fences; n++) {
+ uint32_t handle = tiled_bo_create(fd);
+ exec[1][2*num_fences - n-1].handle = exec[0][n].handle = handle;
+ fill_reloc(&reloc[n], handle);
+ }
+
+ for (i = 0; i < 2; i++) {
+ for (n = 0; n < num_fences; n++)
+ exec[i][n].flags = EXEC_OBJECT_NEEDS_FENCE;
+
+ exec[i][2*num_fences].handle = batch_create(fd);
+ exec[i][2*num_fences].relocs_ptr = (uintptr_t)reloc;
+ exec[i][2*num_fences].relocation_count = 2*num_fences;
+
+ execbuf[i].buffers_ptr = (uintptr_t)exec[i];
+ execbuf[i].buffer_count = 2*num_fences+1;
+ execbuf[i].batch_len = 2*sizeof(uint32_t);
+ }
+
+ do {
+ int ret;
+
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf[0]);
+ assert(ret == 0);
+
+ ret = drmIoctl(fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ &execbuf[1]);
+ assert(ret == 0);
+ } while (--loop);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_flink.c b/tests/gem_flink.c
new file mode 100644
index 00000000..c8694808
--- /dev/null
+++ b/tests/gem_flink.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2008 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 <eric@anholt.net>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+static void
+test_flink(int fd)
+{
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ struct drm_gem_open gem_open;
+ int ret;
+
+ printf("Testing flink and open.\n");
+
+ memset(&create, 0, sizeof(create));
+ create.size = 16 * 1024;
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ assert(ret == 0);
+
+ flink.handle = create.handle;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ assert(ret == 0);
+
+ gem_open.name = flink.name;
+ ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &gem_open);
+ assert(ret == 0);
+ assert(gem_open.handle != 0);
+}
+
+static void
+test_double_flink(int fd)
+{
+ struct drm_i915_gem_create create;
+ struct drm_gem_flink flink;
+ struct drm_gem_flink flink2;
+ int ret;
+
+ printf("Testing repeated flink.\n");
+
+ memset(&create, 0, sizeof(create));
+ create.size = 16 * 1024;
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ assert(ret == 0);
+
+ flink.handle = create.handle;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ assert(ret == 0);
+
+ flink2.handle = create.handle;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink2);
+ assert(ret == 0);
+ assert(flink2.name == flink.name);
+}
+
+static void
+test_bad_flink(int fd)
+{
+ struct drm_gem_flink flink;
+ int ret;
+
+ printf("Testing error return on bad flink ioctl.\n");
+
+ flink.handle = 0x10101010;
+ ret = ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink);
+ assert(ret == -1 && errno == ENOENT);
+}
+
+static void
+test_bad_open(int fd)
+{
+ struct drm_gem_open gem_open;
+ int ret;
+
+ printf("Testing error return on bad open ioctl.\n");
+
+ gem_open.name = 0x10101010;
+ ret = ioctl(fd, DRM_IOCTL_GEM_OPEN, &gem_open);
+
+ assert(ret == -1 && errno == ENOENT);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ test_flink(fd);
+ test_double_flink(fd);
+ test_bad_flink(fd);
+ test_bad_open(fd);
+
+ return 0;
+}
diff --git a/tests/gem_gtt_concurrent_blit.c b/tests/gem_gtt_concurrent_blit.c
new file mode 100644
index 00000000..c68af7b5
--- /dev/null
+++ b/tests/gem_gtt_concurrent_blit.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2009,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:
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gem_cpu_concurrent_blit.c
+ *
+ * This is a test of GTT mmap read/write behavior when writing to active
+ * buffers.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static void
+set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
+{
+ int size = width * height;
+ uint32_t *vaddr;
+
+ drm_intel_gem_bo_start_gtt_access(bo, true);
+ vaddr = bo->virtual;
+ while (size--)
+ *vaddr++ = val;
+}
+
+static void
+cmp_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
+{
+ int size = width * height;
+ uint32_t *vaddr;
+
+ drm_intel_gem_bo_start_gtt_access(bo, false);
+ vaddr = bo->virtual;
+ while (size--)
+ assert(*vaddr++ == val);
+}
+
+static drm_intel_bo *
+create_bo(drm_intel_bufmgr *bufmgr, uint32_t val, int width, int height)
+{
+ drm_intel_bo *bo;
+
+ bo = drm_intel_bo_alloc(bufmgr, "bo", 4*width*height, 0);
+ assert(bo);
+
+ /* gtt map doesn't have a write parameter, so just keep the mapping
+ * around (to avoid the set_domain with the gtt write domain set) and
+ * manually tell the kernel when we start access the gtt. */
+ drm_intel_gem_bo_map_gtt(bo);
+
+ set_bo(bo, val, width, height);
+
+ return bo;
+}
+
+int
+main(int argc, char **argv)
+{
+ drm_intel_bufmgr *bufmgr;
+ struct intel_batchbuffer *batch;
+ int num_buffers = 128, max;
+ drm_intel_bo *src[128], *dst[128], *dummy;
+ int width = 512, height = 512;
+ int fd;
+ int i;
+
+ fd = drm_open_any();
+
+ max = gem_aperture_size (fd) / (1024 * 1024) / 2;
+ if (num_buffers > max)
+ num_buffers = max;
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ for (i = 0; i < num_buffers; i++) {
+ src[i] = create_bo(bufmgr, i, width, height);
+ dst[i] = create_bo(bufmgr, ~i, width, height);
+ }
+ dummy = create_bo(bufmgr, 0, width, height);
+
+ /* try to overwrite the source values */
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ set_bo(src[i], 0xdeadbeef, width, height);
+ for (i = 0; i < num_buffers; i++)
+ cmp_bo(dst[i], i, width, height);
+
+ /* try to read the results before the copy completes */
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ cmp_bo(dst[i], 0xdeadbeef, width, height);
+
+ /* and finally try to trick the kernel into loosing the pending write */
+ for (i = num_buffers; i--; )
+ set_bo(src[i], 0xabcdabcd, width, height);
+ for (i = 0; i < num_buffers; i++)
+ intel_copy_bo(batch, dst[i], src[i], width, height);
+ for (i = num_buffers; i--; )
+ intel_copy_bo(batch, dummy, dst[i], width, height);
+ for (i = num_buffers; i--; )
+ cmp_bo(dst[i], 0xabcdabcd, width, height);
+
+ return 0;
+}
diff --git a/tests/gem_gtt_cpu_tlb.c b/tests/gem_gtt_cpu_tlb.c
new file mode 100644
index 00000000..68533709
--- /dev/null
+++ b/tests/gem_gtt_cpu_tlb.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright © 2009 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/** @file gem_gtt_cpu_tlb.c
+ *
+ * This test checks whether gtt tlbs for cpu access are correctly invalidated.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define OBJ_SIZE (1024*1024)
+
+#define PAGE_SIZE 4096
+
+static uint32_t
+create_bo(int fd)
+{
+ uint32_t handle;
+ uint32_t *data;
+ int i;
+
+ handle = gem_create(fd, OBJ_SIZE);
+
+ /* Fill the BO with dwords starting at start_val */
+ data = gem_mmap(fd, handle, OBJ_SIZE, PROT_READ | PROT_WRITE);
+ for (i = 0; i < OBJ_SIZE/4; i++)
+ data[i] = i;
+ munmap(data, OBJ_SIZE);
+
+ return handle;
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ int i;
+ uint32_t handle;
+
+ uint32_t *ptr;
+
+ fd = drm_open_any();
+
+ handle = gem_create(fd, OBJ_SIZE);
+
+ /* touch one page */
+ ptr = gem_mmap(fd, handle, OBJ_SIZE, PROT_READ | PROT_WRITE);
+ *ptr = 0xdeadbeef;
+ munmap(ptr, OBJ_SIZE);
+
+ gem_close(fd, handle);
+
+ /* stirr up the page allocator a bit. */
+ ptr = malloc(OBJ_SIZE);
+ assert(ptr);
+ memset(ptr, 0x1, OBJ_SIZE);
+
+ handle = create_bo(fd);
+
+ /* Read a bunch of random subsets of the data and check that they come
+ * out right.
+ */
+ gem_read(fd, handle, 0, ptr, OBJ_SIZE);
+ for (i = 0; i < OBJ_SIZE/4; i++)
+ assert(ptr[i] == i);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_gtt_speed.c b/tests/gem_gtt_speed.c
new file mode 100644
index 00000000..73a3c6dc
--- /dev/null
+++ b/tests/gem_gtt_speed.c
@@ -0,0 +1,292 @@
+/*
+ * 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 <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE 16384
+
+static double elapsed(const struct timeval *start,
+ const struct timeval *end,
+ int loop)
+{
+ return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
+}
+
+int main(int argc, char **argv)
+{
+ struct timeval start, end;
+ uint8_t *buf;
+ uint32_t handle;
+ int size = OBJECT_SIZE;
+ int loop, i, tiling;
+ int fd;
+
+ if (argc > 1)
+ size = atoi(argv[1]);
+ if (size == 0) {
+ fprintf(stderr, "Invalid object size specified\n");
+ return 1;
+ }
+
+ buf = malloc(size);
+ memset(buf, 0, size);
+ fd = drm_open_any();
+
+ handle = gem_create(fd, size);
+ assert(handle);
+
+ for (tiling = I915_TILING_NONE; tiling <= I915_TILING_Y; tiling++) {
+ if (tiling != I915_TILING_NONE) {
+ printf("\nSetting tiling mode to %s\n",
+ tiling == I915_TILING_X ? "X" : "Y");
+ gem_set_tiling(fd, handle, tiling, 512);
+ }
+
+ if (tiling == I915_TILING_NONE) {
+ gem_set_domain(fd, handle,
+ I915_GEM_DOMAIN_CPU,
+ I915_GEM_DOMAIN_CPU);
+
+ {
+ uint32_t *base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE);
+ volatile uint32_t *ptr = base;
+ int x = 0;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ x += ptr[i];
+
+ /* force overtly clever gcc to actually compute x */
+ ptr[0] = x;
+
+ munmap(base, size);
+
+ /* mmap read */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE);
+ ptr = base;
+ x = 0;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ x += ptr[i];
+
+ /* force overtly clever gcc to actually compute x */
+ ptr[0] = x;
+
+ munmap(base, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to read %dk through a CPU map: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* mmap write */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ base = gem_mmap__cpu(fd, handle, size, PROT_READ | PROT_WRITE);
+ ptr = base;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ ptr[i] = i;
+
+ munmap(base, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to write %dk through a CPU map: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+ }
+
+ /* CPU pwrite */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++)
+ gem_write(fd, handle, 0, buf, size);
+ gettimeofday(&end, NULL);
+ printf("Time to pwrite %dk through the CPU: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* CPU pread */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++)
+ gem_read(fd, handle, 0, buf, size);
+ gettimeofday(&end, NULL);
+ printf("Time to pread %dk through the CPU: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+ }
+
+ /* prefault into gtt */
+ {
+ uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE);
+ volatile uint32_t *ptr = base;
+ int x = 0;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ x += ptr[i];
+
+ /* force overtly clever gcc to actually compute x */
+ ptr[0] = x;
+
+ munmap(base, size);
+ }
+ /* mmap read */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE);
+ volatile uint32_t *ptr = base;
+ int x = 0;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ x += ptr[i];
+
+ /* force overtly clever gcc to actually compute x */
+ ptr[0] = x;
+
+ munmap(base, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to read %dk through a GTT map: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* mmap write */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE);
+ volatile uint32_t *ptr = base;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ ptr[i] = i;
+
+ munmap(base, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to write %dk through a GTT map: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* mmap read */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ uint32_t *base = gem_mmap(fd, handle, size, PROT_READ | PROT_WRITE);
+ volatile uint32_t *ptr = base;
+ int x = 0;
+
+ for (i = 0; i < size/sizeof(*ptr); i++)
+ x += ptr[i];
+
+ /* force overtly clever gcc to actually compute x */
+ ptr[0] = x;
+
+ munmap(base, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to read %dk (again) through a GTT map: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ if (tiling == I915_TILING_NONE) {
+ /* GTT pwrite */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++)
+ gem_write(fd, handle, 0, buf, size);
+ gettimeofday(&end, NULL);
+ printf("Time to pwrite %dk through the GTT: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* GTT pread */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++)
+ gem_read(fd, handle, 0, buf, size);
+ gettimeofday(&end, NULL);
+ printf("Time to pread %dk through the GTT: %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* GTT pwrite, including clflush */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ gem_write(fd, handle, 0, buf, size);
+ gem_sync(fd, handle);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* GTT pread, including clflush */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ gem_sync(fd, handle);
+ gem_read(fd, handle, 0, buf, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to pread %dk through the GTT (clflush): %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* partial writes */
+ printf("Now partial writes.\n");
+ size /= 4;
+
+ /* partial GTT pwrite, including clflush */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ gem_write(fd, handle, 0, buf, size);
+ gem_sync(fd, handle);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to pwrite %dk through the GTT (clflush): %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ /* partial GTT pread, including clflush */
+ gettimeofday(&start, NULL);
+ for (loop = 0; loop < 1000; loop++) {
+ gem_sync(fd, handle);
+ gem_read(fd, handle, 0, buf, size);
+ }
+ gettimeofday(&end, NULL);
+ printf("Time to pread %dk through the GTT (clflush): %7.3fµs\n",
+ size/1024, elapsed(&start, &end, loop));
+
+ size *= 4;
+ }
+
+ }
+
+ gem_close(fd, handle);
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_hang.c b/tests/gem_hang.c
new file mode 100644
index 00000000..f9db3400
--- /dev/null
+++ b/tests/gem_hang.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static int bad_pipe;
+
+static void
+gpu_hang(void)
+{
+ int cmd;
+
+ cmd = bad_pipe ? MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW :
+ MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
+
+ BEGIN_BATCH(6);
+ /* The documentation says that the LOAD_SCAN_LINES command
+ * always comes in pairs. Don't ask me why. */
+ OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | (bad_pipe << 20));
+ OUT_BATCH((0 << 16) | 2048);
+ OUT_BATCH(MI_LOAD_SCAN_LINES_INCL | (bad_pipe << 20));
+ OUT_BATCH((0 << 16) | 2048);
+ OUT_BATCH(MI_WAIT_FOR_EVENT | cmd);
+ OUT_BATCH(MI_NOOP);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <disabled pipe number>\n",
+ argv[0]);
+ exit(-1);
+ }
+
+ bad_pipe = atoi(argv[1]);
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ gpu_hang();
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_hangcheck_forcewake.c b/tests/gem_hangcheck_forcewake.c
new file mode 100644
index 00000000..96a30fef
--- /dev/null
+++ b/tests/gem_hangcheck_forcewake.c
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+/*
+ * Testcase: Provoke the hangcheck timer on an otherwise idle system
+ *
+ * This tries to hit forcewake locking bugs when the hangcheck runs. Somehow we
+ * often luck out and the hangcheck runs while someone else is already holding
+ * the dev->struct_mutex.
+ *
+ * It's imperative that nothing else runs while this test runs, i.e. kill your X
+ * session, please.
+ */
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+uint32_t blob[2048*2048];
+
+#define MAX_BLT_SIZE 128
+int main(int argc, char **argv)
+{
+ drm_intel_bo *bo = NULL;
+ uint32_t tiling_mode = I915_TILING_X;
+ unsigned long pitch, act_size;
+ int fd, i, devid;
+
+ memset(blob, 'A', sizeof(blob));
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ act_size = 2048;
+ printf("filling ring\n");
+ drm_intel_bo_unreference(bo);
+ bo = drm_intel_bo_alloc_tiled(bufmgr, "tiled bo", act_size, act_size,
+ 4, &tiling_mode, &pitch, 0);
+
+ drm_intel_bo_subdata(bo, 0, act_size*act_size*4, blob);
+
+ if (IS_965(devid))
+ pitch /= 4;
+
+ for (i = 0; i < 10000; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ XY_SRC_COPY_BLT_SRC_TILED |
+ XY_SRC_COPY_BLT_DST_TILED);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ pitch);
+ OUT_BATCH(0 << 16 | 1024);
+ OUT_BATCH((2048) << 16 | (2048));
+ OUT_RELOC_FENCED(bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(pitch);
+ OUT_RELOC_FENCED(bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+ }
+
+ printf("waiting\n");
+ sleep(10);
+
+ printf("done waiting, check dmesg\n");
+ drm_intel_bo_unreference(bo);
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_largeobject.c b/tests/gem_largeobject.c
new file mode 100644
index 00000000..163bf101
--- /dev/null
+++ b/tests/gem_largeobject.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2008 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:
+ * Jesse Barnes <jbarnes@virtuousgeek.org>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+/* Should take 64 pages to store the page pointers on 64 bit */
+#define OBJ_SIZE (128 * 1024 * 1024)
+
+unsigned char data[OBJ_SIZE];
+
+static void
+test_large_object(int fd)
+{
+ struct drm_i915_gem_create create;
+ struct drm_i915_gem_pin pin;
+ uint32_t obj_size;
+ int ret;
+
+ memset(&create, 0, sizeof(create));
+ memset(&pin, 0, sizeof(pin));
+
+ if (gem_aperture_size(fd)*3/4 < OBJ_SIZE/2)
+ obj_size = OBJ_SIZE / 4;
+ else if (gem_aperture_size(fd)*3/4 < OBJ_SIZE)
+ obj_size = OBJ_SIZE / 2;
+ else
+ obj_size = OBJ_SIZE;
+ create.size = obj_size;
+ printf("obj size %i\n", obj_size);
+
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ if (ret) {
+ fprintf(stderr, "object creation failed: %s\n",
+ strerror(errno));
+ exit(ret);
+ }
+
+ pin.handle = create.handle;
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_PIN, &pin);
+ if (ret) {
+ fprintf(stderr, "pin failed: %s\n",
+ strerror(errno));
+ exit(ret);
+ }
+
+ gem_write(fd, create.handle, 0, data, obj_size);
+
+ /* kernel should clean this up for us */
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ test_large_object(fd);
+
+ return 0;
+}
diff --git a/tests/gem_linear_blits.c b/tests/gem_linear_blits.c
new file mode 100644
index 00000000..fe15f1d1
--- /dev/null
+++ b/tests/gem_linear_blits.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_linear_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static void
+copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[10];
+ struct drm_i915_gem_relocation_entry reloc[2];
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ batch[0] = XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB;
+ batch[1] = (3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ WIDTH*4;
+ batch[2] = 0; /* dst x1,y1 */
+ batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+ batch[4] = 0; /* dst reloc */
+ batch[5] = 0; /* src x1,y1 */
+ batch[6] = WIDTH*4;
+ batch[7] = 0; /* src reloc */
+ batch[8] = MI_BATCH_BUFFER_END;
+ batch[9] = MI_NOOP;
+
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+
+ reloc[0].target_handle = dst;
+ reloc[0].delta = 0;
+ reloc[0].offset = 4 * sizeof(batch[0]);
+ reloc[0].presumed_offset = 0;
+ reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
+ reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+ reloc[1].target_handle = src;
+ reloc[1].delta = 0;
+ reloc[1].offset = 7 * sizeof(batch[0]);
+ reloc[1].presumed_offset = 0;
+ reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
+ reloc[1].write_domain = 0;
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = sizeof(batch);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+ uint32_t handle;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+
+ /* Fill the BO with dwords starting at val */
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ linear[i] = val++;
+ gem_write(fd, handle, 0, linear, sizeof(linear));
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ int i;
+
+ gem_read(fd, handle, 0, linear, sizeof(linear));
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (linear[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, linear[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+
+ if (count > intel_get_total_ram_mb() * 9 / 10) {
+ count = intel_get_total_ram_mb() * 9 / 10;
+ printf("not enough RAM to run test, reducing buffer count\n");
+ }
+
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*2);
+ start_val = handle + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation...\n");
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, forward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, backward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Random blits...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (src == dst)
+ continue;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ return 0;
+}
diff --git a/tests/gem_mmap.c b/tests/gem_mmap.c
new file mode 100644
index 00000000..f9369f43
--- /dev/null
+++ b/tests/gem_mmap.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2008 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 <eric@anholt.net>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE 16384
+
+int main(int argc, char **argv)
+{
+ int fd;
+ struct drm_i915_gem_mmap arg;
+ uint8_t expected[OBJECT_SIZE];
+ uint8_t buf[OBJECT_SIZE];
+ uint8_t *addr;
+ int ret;
+ int handle;
+
+ fd = drm_open_any();
+
+ memset(&arg, 0, sizeof(arg));
+ arg.handle = 0x10101010;
+ arg.offset = 0;
+ arg.size = 4096;
+ printf("Testing mmaping of bad object.\n");
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg);
+ assert(ret == -1 && errno == ENOENT);
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ printf("Testing mmaping of newly created object.\n");
+ arg.handle = handle;
+ arg.offset = 0;
+ arg.size = OBJECT_SIZE;
+ ret = ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &arg);
+ assert(ret == 0);
+ addr = (uint8_t *)(uintptr_t)arg.addr_ptr;
+
+ printf("Testing contents of newly created object.\n");
+ memset(expected, 0, sizeof(expected));
+ assert(memcmp(addr, expected, sizeof(expected)) == 0);
+
+ printf("Testing coherency of writes and mmap reads.\n");
+ memset(buf, 0, sizeof(buf));
+ memset(buf + 1024, 0x01, 1024);
+ memset(expected + 1024, 0x01, 1024);
+ gem_write(fd, handle, 0, buf, OBJECT_SIZE);
+ assert(memcmp(buf, addr, sizeof(buf)) == 0);
+
+ printf("Testing that mapping stays after close\n");
+ gem_close(fd, handle);
+ assert(memcmp(buf, addr, sizeof(buf)) == 0);
+
+ printf("Testing unmapping\n");
+ munmap(addr, OBJECT_SIZE);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_mmap_gtt.c b/tests/gem_mmap_gtt.c
new file mode 100644
index 00000000..e7a48679
--- /dev/null
+++ b/tests/gem_mmap_gtt.c
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE (16*1024*1024)
+
+static void set_domain(int fd, uint32_t handle)
+{
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+}
+
+static void *
+mmap_bo(int fd, uint32_t handle)
+{
+ void *ptr;
+
+ ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
+ assert(ptr != MAP_FAILED);
+
+ return ptr;
+}
+
+static void *
+create_pointer(int fd)
+{
+ uint32_t handle;
+ void *ptr;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ ptr = mmap_bo(fd, handle);
+
+ gem_close(fd, handle);
+
+ return ptr;
+}
+
+static void
+test_copy(int fd)
+{
+ void *src, *dst;
+
+ /* copy from a fresh src to fresh dst to force pagefault on both */
+ src = create_pointer(fd);
+ dst = create_pointer(fd);
+
+ memcpy(dst, src, OBJECT_SIZE);
+ memcpy(src, dst, OBJECT_SIZE);
+
+ munmap(dst, OBJECT_SIZE);
+ munmap(src, OBJECT_SIZE);
+}
+
+static void
+test_write(int fd)
+{
+ void *src;
+ uint32_t dst;
+
+ /* copy from a fresh src to fresh dst to force pagefault on both */
+ src = create_pointer(fd);
+ dst = gem_create(fd, OBJECT_SIZE);
+
+ gem_write(fd, dst, 0, src, OBJECT_SIZE);
+
+ gem_close(fd, dst);
+ munmap(src, OBJECT_SIZE);
+}
+
+static void
+test_write_gtt(int fd)
+{
+ uint32_t dst;
+ char *dst_gtt;
+ void *src;
+
+ dst = gem_create(fd, OBJECT_SIZE);
+
+ /* prefault object into gtt */
+ dst_gtt = mmap_bo(fd, dst);
+ set_domain(fd, dst);
+ memset(dst_gtt, 0, OBJECT_SIZE);
+ munmap(dst_gtt, OBJECT_SIZE);
+
+ src = create_pointer(fd);
+
+ gem_write(fd, dst, 0, src, OBJECT_SIZE);
+
+ gem_close(fd, dst);
+ munmap(src, OBJECT_SIZE);
+}
+
+static void
+test_read(int fd)
+{
+ void *dst;
+ uint32_t src;
+
+ /* copy from a fresh src to fresh dst to force pagefault on both */
+ dst = create_pointer(fd);
+ src = gem_create(fd, OBJECT_SIZE);
+
+ gem_read(fd, src, 0, dst, OBJECT_SIZE);
+
+ gem_close(fd, src);
+ munmap(dst, OBJECT_SIZE);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = drm_open_any();
+
+ test_copy(fd);
+ test_read(fd);
+ test_write(fd);
+ test_write_gtt(fd);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_mmap_offset_exhaustion.c b/tests/gem_mmap_offset_exhaustion.c
new file mode 100644
index 00000000..51ae5990
--- /dev/null
+++ b/tests/gem_mmap_offset_exhaustion.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE (1024*1024)
+
+/* Testcase: checks whether the kernel handles mmap offset exhaustion correctly
+ *
+ * Currently the kernel doesn't reap the mmap offset of purged objects, albeit
+ * there's nothing that prevents it ABI-wise and it helps to get out of corners
+ * (because drm_mm is only 32bit on 32bit archs unfortunately.
+ *
+ * Note that on 64bit machines we have plenty of address space (because drm_mm
+ * uses unsigned long).
+ */
+
+static void
+create_and_map_bo(int fd)
+{
+ uint32_t handle;
+ char *ptr;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
+
+ if (!ptr) {
+ fprintf(stderr, "mmap failed\n");
+ assert(ptr);
+ }
+
+ /* touch it to force it into the gtt */
+ *ptr = 0;
+
+ /* but then unmap it again because we only have limited address space on
+ * 32 bit */
+ munmap(ptr, OBJECT_SIZE);
+
+ /* we happily leak objects to exhaust mmap offset space, the kernel will
+ * reap backing storage. */
+ gem_madvise(fd, handle, I915_MADV_DONTNEED);
+}
+
+int main(int argc, char **argv)
+{
+ int fd, i;
+
+ fd = drm_open_any();
+
+ /* we have 32bit of address space, so try to fit one MB more
+ * than that. */
+ for (i = 0; i < 4096 + 1; i++)
+ create_and_map_bo(fd);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_partial_pwrite_pread.c b/tests/gem_partial_pwrite_pread.c
new file mode 100644
index 00000000..5c8f6f5f
--- /dev/null
+++ b/tests/gem_partial_pwrite_pread.c
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+/*
+ * Testcase: pwrite/pread consistency when touching partial cachelines
+ *
+ * Some fancy new pwrite/pread optimizations clflush in-line while
+ * reading/writing. Check whether all required clflushes happen.
+ *
+ */
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+drm_intel_bo *scratch_bo;
+drm_intel_bo *staging_bo;
+#define BO_SIZE (4*4096)
+uint32_t devid;
+uint64_t mappable_gtt_limit;
+int fd;
+
+static void
+copy_bo(drm_intel_bo *src, drm_intel_bo *dst)
+{
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 4096);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH((BO_SIZE/4096) << 16 | 1024);
+ OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(4096);
+ OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+static void
+blt_bo_fill(drm_intel_bo *tmp_bo, drm_intel_bo *bo, int val)
+{
+ uint8_t *gtt_ptr;
+ int i;
+
+ drm_intel_gem_bo_map_gtt(tmp_bo);
+ gtt_ptr = tmp_bo->virtual;
+
+ for (i = 0; i < BO_SIZE; i++)
+ gtt_ptr[i] = val;
+
+ drm_intel_gem_bo_unmap_gtt(tmp_bo);
+
+ if (bo->offset < mappable_gtt_limit &&
+ (IS_G33(devid) || intel_gen(devid) >= 4))
+ drmtest_trash_aperture();
+
+ copy_bo(tmp_bo, bo);
+}
+
+#define MAX_BLT_SIZE 128
+#define ROUNDS 1000
+int main(int argc, char **argv)
+{
+ int i, j;
+ uint8_t tmp[BO_SIZE];
+ uint8_t *gtt_ptr;
+
+ srandom(0xdeadbeef);
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ /* overallocate the buffers we're actually using because */
+ scratch_bo = drm_intel_bo_alloc(bufmgr, "scratch bo", BO_SIZE, 4096);
+ staging_bo = drm_intel_bo_alloc(bufmgr, "staging bo", BO_SIZE, 4096);
+
+ drmtest_init_aperture_trashers(bufmgr);
+ mappable_gtt_limit = gem_mappable_aperture_size();
+
+ printf("checking partial reads\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
+ for (j = 0; j < len; j++) {
+ if (tmp[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+
+ drmtest_progress("partial reads test: ", i, ROUNDS);
+ }
+
+ printf("checking partial writes\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ memset(tmp, i + 63, BO_SIZE);
+
+ drm_intel_bo_subdata(scratch_bo, start, len, tmp);
+
+ copy_bo(scratch_bo, staging_bo);
+ drm_intel_gem_bo_map_gtt(staging_bo);
+ gtt_ptr = staging_bo->virtual;
+
+ for (j = 0; j < start; j++) {
+ if (gtt_ptr[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ for (; j < start + len; j++) {
+ if (gtt_ptr[j] != tmp[0]) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], i);
+ exit(1);
+ }
+ }
+ for (; j < BO_SIZE; j++) {
+ if (gtt_ptr[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ drm_intel_gem_bo_unmap_gtt(staging_bo);
+
+ drmtest_progress("partial writes test: ", i, ROUNDS);
+ }
+
+ printf("checking partial writes after partial reads\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ /* partial read */
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
+ for (j = 0; j < len; j++) {
+ if (tmp[j] != val) {
+ printf("mismatch in read at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+
+ /* Change contents through gtt to make the pread cachelines
+ * stale. */
+ val = (i + 17) % 256;
+ blt_bo_fill(staging_bo, scratch_bo, val);
+
+ /* partial write */
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ memset(tmp, i + 63, BO_SIZE);
+
+ drm_intel_bo_subdata(scratch_bo, start, len, tmp);
+
+ copy_bo(scratch_bo, staging_bo);
+ drm_intel_gem_bo_map_gtt(staging_bo);
+ gtt_ptr = staging_bo->virtual;
+
+ for (j = 0; j < start; j++) {
+ if (gtt_ptr[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ for (; j < start + len; j++) {
+ if (gtt_ptr[j] != tmp[0]) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], tmp[0]);
+ exit(1);
+ }
+ }
+ for (; j < BO_SIZE; j++) {
+ if (gtt_ptr[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ drm_intel_gem_bo_unmap_gtt(staging_bo);
+
+ drmtest_progress("partial read/writes test: ", i, ROUNDS);
+ }
+
+ drmtest_cleanup_aperture_trashers();
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_pipe_control_store_loop.c b/tests/gem_pipe_control_store_loop.c
new file mode 100644
index 00000000..e03cddd7
--- /dev/null
+++ b/tests/gem_pipe_control_store_loop.c
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c)
+ *
+ */
+
+/*
+ * Testcase: (TLB-)Coherency of pipe_control QW writes
+ *
+ * Writes a counter-value into an always newly allocated target bo (by disabling
+ * buffer reuse). Decently trashes on tlb inconsistencies, too.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+uint32_t devid;
+
+#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
+#define PIPE_CONTROL_WRITE_IMMEDIATE (1<<14)
+#define PIPE_CONTROL_WRITE_TIMESTAMP (3<<14)
+#define PIPE_CONTROL_DEPTH_STALL (1<<13)
+#define PIPE_CONTROL_WC_FLUSH (1<<12)
+#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
+#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
+#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1)
+#define PIPE_CONTROL_CS_STALL (1<<20)
+#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
+
+/* Like the store dword test, but we create new command buffers each time */
+static void
+store_pipe_control_loop(void)
+{
+ int i, val = 0;
+ uint32_t *buf;
+ drm_intel_bo *target_bo;
+
+ for (i = 0; i < 0x10000; i++) {
+ /* we want to check tlb consistency of the pipe_control target,
+ * so get a new buffer every time around */
+ target_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_bo) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ /* gem_storedw_batches_loop.c is a bit overenthusiastic with
+ * creating new batchbuffers - with buffer reuse disabled, the
+ * support code will do that for us. */
+ if (intel_gen(devid) >= 6) {
+ /* work-around hw issue, see intel_emit_post_sync_nonzero_flush
+ * in mesa sources. */
+ BEGIN_BATCH(4);
+ OUT_BATCH(GFX_OP_PIPE_CONTROL);
+ OUT_BATCH(PIPE_CONTROL_CS_STALL |
+ PIPE_CONTROL_STALL_AT_SCOREBOARD);
+ OUT_BATCH(0); /* address */
+ OUT_BATCH(0); /* write data */
+ ADVANCE_BATCH();
+
+ BEGIN_BATCH(4);
+ OUT_BATCH(GFX_OP_PIPE_CONTROL);
+ OUT_BATCH(PIPE_CONTROL_WRITE_IMMEDIATE);
+ OUT_RELOC(target_bo,
+ I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
+ PIPE_CONTROL_GLOBAL_GTT);
+ OUT_BATCH(val); /* write data */
+ ADVANCE_BATCH();
+ } else if (intel_gen(devid) >= 4) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_WC_FLUSH |
+ PIPE_CONTROL_TC_FLUSH |
+ PIPE_CONTROL_WRITE_IMMEDIATE | 2);
+ OUT_RELOC(target_bo,
+ I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION,
+ PIPE_CONTROL_GLOBAL_GTT);
+ OUT_BATCH(val);
+ OUT_BATCH(0xdeadbeef);
+ ADVANCE_BATCH();
+ }
+
+ intel_batchbuffer_flush_on_ring(batch, 0);
+
+ drm_intel_bo_map(target_bo, 1);
+
+ buf = target_bo->virtual;
+ if (buf[0] != val) {
+ fprintf(stderr,
+ "value mismatch: cur 0x%08x, stored 0x%08x\n",
+ buf[0], val);
+ exit(-1);
+ }
+ buf[0] = 0; /* let batch write it again */
+ drm_intel_bo_unmap(target_bo);
+
+ drm_intel_bo_unreference(target_bo);
+
+ val++;
+ }
+
+ printf("completed %d writes successfully\n", i);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+
+ if (IS_GEN2(devid) || IS_GEN3(devid)) {
+ fprintf(stderr, "no pipe_control on gen2/3\n");
+ return 77;
+ }
+ if (devid == PCI_CHIP_I965_G) {
+ fprintf(stderr, "pipe_control totally broken on i965\n");
+ return 77;
+ }
+ /* IMPORTANT: No call to
+ * drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ * here because we wan't to have fresh buffers (to trash the tlb)
+ * every time! */
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ store_pipe_control_loop();
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_pread_after_blit.c b/tests/gem_pread_after_blit.c
new file mode 100644
index 00000000..c9c8b02c
--- /dev/null
+++ b/tests/gem_pread_after_blit.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_pread_after_blit.c
+ *
+ * This is a test of pread's behavior when getting values out of just-drawn-to
+ * buffers.
+ *
+ * The goal is to catch failure in the whole-buffer-flush or
+ * ranged-buffer-flush paths in the kernel.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static const int width = 512, height = 512;
+static const int size = 1024 * 1024;
+
+#define PAGE_SIZE 4096
+
+static drm_intel_bo *
+create_bo(uint32_t val)
+{
+ drm_intel_bo *bo;
+ uint32_t *vaddr;
+ int i;
+
+ bo = drm_intel_bo_alloc(bufmgr, "src bo", size, 4096);
+
+ /* Fill the BO with dwords starting at start_val */
+ drm_intel_bo_map(bo, 1);
+ vaddr = bo->virtual;
+
+ for (i = 0; i < 1024 * 1024 / 4; i++)
+ vaddr[i] = val++;
+
+ drm_intel_bo_unmap(bo);
+
+ return bo;
+}
+
+static void
+verify_large_read(drm_intel_bo *bo, uint32_t val)
+{
+ uint32_t buf[size / 4];
+ int i;
+
+ drm_intel_bo_get_subdata(bo, 0, size, buf);
+
+ for (i = 0; i < size / 4; i++) {
+ if (buf[i] != val) {
+ fprintf(stderr,
+ "Unexpected value 0x%08x instead of "
+ "0x%08x at offset 0x%08x (%p)\n",
+ buf[i], val, i * 4, buf);
+ abort();
+ }
+ val++;
+ }
+}
+
+/** This reads at the size that Mesa usees for software fallbacks. */
+static void
+verify_small_read(drm_intel_bo *bo, uint32_t val)
+{
+ uint32_t buf[4096 / 4];
+ int offset, i;
+
+ for (i = 0; i < 4096 / 4; i++)
+ buf[i] = 0x00c0ffee;
+
+ for (offset = 0; offset < size; offset += PAGE_SIZE) {
+ drm_intel_bo_get_subdata(bo, offset, PAGE_SIZE, buf);
+
+ for (i = 0; i < PAGE_SIZE; i += 4) {
+ if (buf[i / 4] != val) {
+ fprintf(stderr,
+ "Unexpected value 0x%08x instead of "
+ "0x%08x at offset 0x%08x\n",
+ buf[i / 4], val, i * 4);
+ abort();
+ }
+ val++;
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ drm_intel_bo *src1, *src2, *bo;
+ uint32_t start1 = 0;
+ uint32_t start2 = 1024 * 1024 / 4;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ src1 = create_bo(start1);
+ src2 = create_bo(start2);
+
+ bo = drm_intel_bo_alloc(bufmgr, "dst bo", size, 4096);
+
+ /* First, do a full-buffer read after blitting */
+ printf("Large read after blit 1\n");
+ intel_copy_bo(batch, bo, src1, width, height);
+ verify_large_read(bo, start1);
+ printf("Large read after blit 2\n");
+ intel_copy_bo(batch, bo, src2, width, height);
+ verify_large_read(bo, start2);
+
+ printf("Small reads after blit 1\n");
+ intel_copy_bo(batch, bo, src1, width, height);
+ verify_small_read(bo, start1);
+ printf("Small reads after blit 2\n");
+ intel_copy_bo(batch, bo, src2, width, height);
+ verify_small_read(bo, start2);
+
+ printf("Large read after blit 3\n");
+ intel_copy_bo(batch, bo, src1, width, height);
+ verify_large_read(bo, start1);
+
+ drm_intel_bo_unreference(src1);
+ drm_intel_bo_unreference(src2);
+ drm_intel_bo_unreference(bo);
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_pwrite.c b/tests/gem_pwrite.c
new file mode 100644
index 00000000..051ed3b5
--- /dev/null
+++ b/tests/gem_pwrite.c
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE 16384
+
+#define COPY_BLT_CMD (2<<29|0x53<<22|0x6)
+#define BLT_WRITE_ALPHA (1<<21)
+#define BLT_WRITE_RGB (1<<20)
+#define BLT_SRC_TILED (1<<15)
+#define BLT_DST_TILED (1<<11)
+#define MI_BATCH_BUFFER_END (0xA<<23)
+
+static void do_gem_write(int fd, uint32_t handle, void *buf, int len, int loops)
+{
+ while (loops--)
+ gem_write(fd, handle, 0, buf, len);
+}
+
+static double elapsed(const struct timeval *start,
+ const struct timeval *end,
+ int loop)
+{
+ return (1e6*(end->tv_sec - start->tv_sec) + (end->tv_usec - start->tv_usec))/loop;
+}
+
+static const char *bytes_per_sec(char *buf, double v)
+{
+ const char *order[] = {
+ "",
+ "KiB",
+ "MiB",
+ "GiB",
+ "TiB",
+ NULL,
+ }, **o = order;
+
+ while (v > 1000 && o[1]) {
+ v /= 1000;
+ o++;
+ }
+ sprintf(buf, "%.1f%s/s", v, *o);
+ return buf;
+}
+
+
+int main(int argc, char **argv)
+{
+ int object_size = 0;
+ uint32_t buf[20];
+ uint32_t *src, dst;
+ int fd, count;
+
+ if (argc > 1)
+ object_size = atoi(argv[1]);
+ if (object_size == 0)
+ object_size = OBJECT_SIZE;
+ object_size = (object_size + 3) & -4;
+
+ fd = drm_open_any();
+
+ dst = gem_create(fd, object_size);
+ src = malloc(object_size);
+ for (count = 1; count <= 1<<17; count <<= 1) {
+ struct timeval start, end;
+
+ gettimeofday(&start, NULL);
+ do_gem_write(fd, dst, src, object_size, count);
+ gettimeofday(&end, NULL);
+ printf("Time to pwrite %d bytes x %6d: %7.3fµs, %s\n",
+ object_size, count,
+ elapsed(&start, &end, count),
+ bytes_per_sec((char *)buf, object_size/elapsed(&start, &end, count)*1e6));
+ fflush(stdout);
+ }
+ free(src);
+ gem_close(fd, dst);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_readwrite.c b/tests/gem_readwrite.c
new file mode 100644
index 00000000..68c3ff28
--- /dev/null
+++ b/tests/gem_readwrite.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright © 2008 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 <eric@anholt.net>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define OBJECT_SIZE 16384
+
+static int
+do_read(int fd, int handle, void *buf, int offset, int size)
+{
+ struct drm_i915_gem_pread read;
+
+ /* Ensure that we don't have any convenient data in buf in case
+ * we fail.
+ */
+ memset(buf, 0xd0, size);
+
+ memset(&read, 0, sizeof(read));
+ read.handle = handle;
+ read.data_ptr = (uintptr_t)buf;
+ read.size = size;
+ read.offset = offset;
+
+ return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &read);
+}
+
+static int
+do_write(int fd, int handle, void *buf, int offset, int size)
+{
+ struct drm_i915_gem_pwrite write;
+
+ memset(&write, 0, sizeof(write));
+ write.handle = handle;
+ write.data_ptr = (uintptr_t)buf;
+ write.size = size;
+ write.offset = offset;
+
+ return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &write);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ uint8_t expected[OBJECT_SIZE];
+ uint8_t buf[OBJECT_SIZE];
+ int ret;
+ int handle;
+
+ fd = drm_open_any();
+
+ handle = gem_create(fd, OBJECT_SIZE);
+
+ printf("Testing contents of newly created object.\n");
+ ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
+ assert(ret == 0);
+ memset(&expected, 0, sizeof(expected));
+ assert(memcmp(expected, buf, sizeof(expected)) == 0);
+
+ printf("Testing read beyond end of buffer.\n");
+ ret = do_read(fd, handle, buf, OBJECT_SIZE / 2, OBJECT_SIZE);
+ assert(ret == -1 && errno == EINVAL);
+
+ printf("Testing full write of buffer\n");
+ memset(buf, 0, sizeof(buf));
+ memset(buf + 1024, 0x01, 1024);
+ memset(expected + 1024, 0x01, 1024);
+ ret = do_write(fd, handle, buf, 0, OBJECT_SIZE);
+ assert(ret == 0);
+ ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
+ assert(ret == 0);
+ assert(memcmp(buf, expected, sizeof(buf)) == 0);
+
+ printf("Testing partial write of buffer\n");
+ memset(buf + 4096, 0x02, 1024);
+ memset(expected + 4096, 0x02, 1024);
+ ret = do_write(fd, handle, buf + 4096, 4096, 1024);
+ assert(ret == 0);
+ ret = do_read(fd, handle, buf, 0, OBJECT_SIZE);
+ assert(ret == 0);
+ assert(memcmp(buf, expected, sizeof(buf)) == 0);
+
+ printf("Testing partial read of buffer\n");
+ ret = do_read(fd, handle, buf, 512, 1024);
+ assert(ret == 0);
+ assert(memcmp(buf, expected + 512, 1024) == 0);
+
+ printf("Testing read of bad buffer handle\n");
+ ret = do_read(fd, 1234, buf, 0, 1024);
+ assert(ret == -1 && errno == ENOENT);
+
+ printf("Testing write of bad buffer handle\n");
+ ret = do_write(fd, 1234, buf, 0, 1024);
+ assert(ret == -1 && errno == ENOENT);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_reg_read.c b/tests/gem_reg_read.c
new file mode 100644
index 00000000..1d6db1f1
--- /dev/null
+++ b/tests/gem_reg_read.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "i915_drm.h"
+#include "drmtest.h"
+
+struct local_drm_i915_reg_read {
+ __u64 offset;
+ __u64 val; /* Return value */
+};
+
+#define REG_READ_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x31, struct local_drm_i915_reg_read)
+
+static void handle_bad(int ret, int lerrno, int expected, const char *desc)
+{
+ if (ret != 0 && lerrno != expected) {
+ fprintf(stderr, "%s - errno was %d, but should have been %d\n",
+ desc, lerrno, expected);
+ exit(EXIT_FAILURE);
+ } else if (ret == 0) {
+ fprintf(stderr, "%s - Command succeeded, but should have failed\n",
+ desc);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static uint64_t timer_query(int fd)
+{
+ struct local_drm_i915_reg_read read;
+ int ret;
+
+ read.offset = 0x2358;
+ ret = drmIoctl(fd, REG_READ_IOCTL, &read);
+ if (ret) {
+ perror("positive test case failed: ");
+ exit(EXIT_FAILURE);
+ }
+
+ return read.val;
+}
+
+int main(int argc, char *argv[])
+{
+ struct local_drm_i915_reg_read read;
+ int ret, fd;
+ uint64_t val;
+
+ fd = drm_open_any();
+
+ read.offset = 0x2358;
+ ret = drmIoctl(fd, REG_READ_IOCTL, &read);
+ if (errno == EINVAL)
+ exit(77);
+ else if (ret)
+ exit(EXIT_FAILURE);
+
+ val = timer_query(fd);
+ sleep(1);
+ if (timer_query(fd) == val) {
+ fprintf(stderr, "Timer isn't moving, probably busted\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* bad reg */
+ read.offset = 0x12345678;
+ ret = drmIoctl(fd, REG_READ_IOCTL, &read);
+ handle_bad(ret, errno, EINVAL, "bad register");
+
+ close(fd);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/gem_reloc_vs_gpu.c b/tests/gem_reloc_vs_gpu.c
new file mode 100644
index 00000000..47681d51
--- /dev/null
+++ b/tests/gem_reloc_vs_gpu.c
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+/*
+ * Testcase: Kernel relocations vs. gpu races
+ *
+ */
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+uint32_t blob[2048*2048];
+#define NUM_TARGET_BOS 16
+drm_intel_bo *pc_target_bo[NUM_TARGET_BOS];
+drm_intel_bo *dummy_bo;
+drm_intel_bo *special_bo;
+uint32_t devid;
+int special_reloc_ofs;
+int special_batch_len;
+
+#define GFX_OP_PIPE_CONTROL ((0x3<<29)|(0x3<<27)|(0x2<<24)|2)
+#define PIPE_CONTROL_WRITE_IMMEDIATE (1<<14)
+#define PIPE_CONTROL_WRITE_TIMESTAMP (3<<14)
+#define PIPE_CONTROL_DEPTH_STALL (1<<13)
+#define PIPE_CONTROL_WC_FLUSH (1<<12)
+#define PIPE_CONTROL_IS_FLUSH (1<<11) /* MBZ on Ironlake */
+#define PIPE_CONTROL_TC_FLUSH (1<<10) /* GM45+ only */
+#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1)
+#define PIPE_CONTROL_CS_STALL (1<<20)
+#define PIPE_CONTROL_GLOBAL_GTT (1<<2) /* in addr dword */
+
+static void create_special_bo(void)
+{
+ uint32_t data[1024];
+ int len = 0;
+ int small_pitch = 64;
+#define BATCH(dw) data[len++] = (dw);
+
+ memset(data, 0, 4096);
+ special_bo = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096);
+
+ BATCH(XY_COLOR_BLT_CMD | COLOR_BLT_WRITE_ALPHA | XY_COLOR_BLT_WRITE_RGB);
+ BATCH((3 << 24) | (0xf0 << 16) | small_pitch);
+ BATCH(0);
+ BATCH(1 << 16 | 1);
+ special_reloc_ofs = 4*len;
+ BATCH(0);
+ BATCH(0xdeadbeef);
+
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+ /* batchbuffer end */
+ if (IS_GEN5(batch->devid)) {
+ BATCH(CMD_POLY_STIPPLE_OFFSET << 16);
+ BATCH(0);
+ }
+ assert(len % 2 == 0);
+ BATCH(MI_NOOP);
+ BATCH(MI_BATCH_BUFFER_END);
+
+ drm_intel_bo_subdata(special_bo, 0, 4096, data);
+ special_batch_len = len*4;
+}
+
+static void emit_dummy_load(int pitch)
+{
+ int i;
+ uint32_t tile_flags = 0;
+
+ if (IS_965(devid)) {
+ pitch /= 4;
+ tile_flags = XY_SRC_COPY_BLT_SRC_TILED |
+ XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ for (i = 0; i < 10; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ tile_flags);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ pitch);
+ OUT_BATCH(0 << 16 | 1024);
+ OUT_BATCH((2048) << 16 | (2048));
+ OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(pitch);
+ OUT_RELOC_FENCED(dummy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+ }
+ intel_batchbuffer_flush(batch);
+}
+
+#define MAX_BLT_SIZE 128
+int main(int argc, char **argv)
+{
+ uint32_t tiling_mode = I915_TILING_X;
+ unsigned long pitch, act_size;
+ int fd, i, ring;
+ uint32_t test;
+
+ memset(blob, 'A', sizeof(blob));
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ /* disable reuse, otherwise the test fails */
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ act_size = 2048;
+ dummy_bo = drm_intel_bo_alloc_tiled(bufmgr, "tiled dummy_bo", act_size, act_size,
+ 4, &tiling_mode, &pitch, 0);
+
+ drm_intel_bo_subdata(dummy_bo, 0, act_size*act_size*4, blob);
+
+ create_special_bo();
+
+ if (intel_gen(devid) >= 6)
+ ring = I915_EXEC_BLT;
+ else
+ ring = 0;
+
+ for (i = 0; i < NUM_TARGET_BOS; i++) {
+ pc_target_bo[i] = drm_intel_bo_alloc(bufmgr, "special batch", 4096, 4096);
+ emit_dummy_load(pitch);
+ assert(pc_target_bo[i]->offset == 0);
+ drm_intel_bo_emit_reloc(special_bo, special_reloc_ofs,
+ pc_target_bo[i],
+ 0,
+ I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER);
+ drm_intel_bo_mrb_exec(special_bo, special_batch_len, NULL,
+ 0, 0, ring);
+ }
+
+ /* Only check at the end to avoid unnecessary synchronous behaviour. */
+ for (i = 0; i < NUM_TARGET_BOS; i++) {
+ drm_intel_bo_get_subdata(pc_target_bo[i], 0, 4, &test);
+ if (test != 0xdeadbeef) {
+ fprintf(stderr, "mismatch in buffer %i: 0x%08x instead of 0xdeadbeef\n", i, test);
+ exit(1);
+ }
+ drm_intel_bo_unreference(pc_target_bo[i]);
+ }
+
+ drm_intel_gem_bo_map_gtt(dummy_bo);
+ drm_intel_gem_bo_unmap_gtt(dummy_bo);
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_ring_sync_loop.c b/tests/gem_ring_sync_loop.c
new file mode 100644
index 00000000..b689bcde
--- /dev/null
+++ b/tests/gem_ring_sync_loop.c
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch> (based on gem_storedw_*.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+#include "i830_reg.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer;
+
+/*
+ * Testcase: Basic check of ring<->ring sync using a dummy reloc
+ *
+ * Extremely efficient at catching missed irqs with semaphores=0 ...
+ */
+
+#define MI_COND_BATCH_BUFFER_END (0x36<<23 | 1)
+#define MI_DO_COMPARE (1<<21)
+
+static void
+store_dword_loop(void)
+{
+ int i;
+
+ srandom(0xdeadbeef);
+
+ for (i = 0; i < 0x100000; i++) {
+ int ring = random() % 3 + 1;
+
+ if (ring == I915_EXEC_RENDER) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_COND_BATCH_BUFFER_END | MI_DO_COMPARE);
+ OUT_BATCH(0xffffffff); /* compare dword */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP);
+ ADVANCE_BATCH();
+ } else {
+ BEGIN_BATCH(4);
+ OUT_BATCH(MI_FLUSH_DW | 1);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(MI_NOOP | (1<<22) | (0xf));
+ ADVANCE_BATCH();
+ }
+ intel_batchbuffer_flush_on_ring(batch, ring);
+ }
+
+ drm_intel_bo_map(target_buffer, 0);
+ // map to force waiting on rendering
+ drm_intel_bo_unmap(target_buffer);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+ if (!HAS_BLT_RING(devid)) {
+ fprintf(stderr, "inter ring check needs gen6+\n");
+ return 77;
+ }
+
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ store_dword_loop();
+
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_ringfill.c b/tests/gem_ringfill.c
new file mode 100644
index 00000000..5bae8f11
--- /dev/null
+++ b/tests/gem_ringfill.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_ringfill.c
+ *
+ * This is a test of doing many tiny batchbuffer operations, in the hope of
+ * catching failure to manage the ring properly near full.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "drm.h"
+#include "i915_drm.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+#include "rendercopy.h"
+
+struct bo {
+ const char *ring;
+ drm_intel_bo *src, *dst, *tmp;
+};
+
+static const int width = 512, height = 512;
+
+static void create_bo(drm_intel_bufmgr *bufmgr,
+ struct bo *b,
+ const char *ring)
+{
+ int size = 4 * width * height, i;
+ uint32_t *map;
+
+ b->ring = ring;
+ b->src = drm_intel_bo_alloc(bufmgr, "src", size, 4096);
+ b->dst = drm_intel_bo_alloc(bufmgr, "dst", size, 4096);
+ b->tmp = drm_intel_bo_alloc(bufmgr, "tmp", size, 4096);
+
+ /* Fill the src with indexes of the pixels */
+ drm_intel_bo_map(b->src, true);
+ map = b->src->virtual;
+ for (i = 0; i < width * height; i++)
+ map[i] = i;
+ drm_intel_bo_unmap(b->src);
+
+ /* Fill the dst with garbage. */
+ drm_intel_bo_map(b->dst, true);
+ map = b->dst->virtual;
+ for (i = 0; i < width * height; i++)
+ map[i] = 0xd0d0d0d0;
+ drm_intel_bo_unmap(b->dst);
+}
+
+static int check_bo(struct bo *b)
+{
+ const uint32_t *map;
+ int i, fails = 0;
+
+ drm_intel_bo_map(b->dst, false);
+ map = b->dst->virtual;
+ for (i = 0; i < width*height; i++) {
+ if (map[i] != i && ++fails <= 9) {
+ int x = i % width;
+ int y = i / width;
+
+ printf("%s: copy #%d at %d,%d failed: read 0x%08x\n",
+ b->ring, i, x, y, map[i]);
+ }
+ }
+ drm_intel_bo_unmap(b->dst);
+
+ return fails;
+}
+
+static void destroy_bo(struct bo *b)
+{
+ drm_intel_bo_unreference(b->src);
+ drm_intel_bo_unreference(b->tmp);
+ drm_intel_bo_unreference(b->dst);
+}
+
+static int check_ring(drm_intel_bufmgr *bufmgr,
+ struct intel_batchbuffer *batch,
+ const char *ring,
+ render_copyfunc_t copy)
+{
+ struct scratch_buf src, tmp, dst;
+ struct bo bo;
+ char output[100];
+ int i;
+
+ snprintf(output, 100, "filling %s ring: ", ring);
+
+ create_bo(bufmgr, &bo, ring);
+
+ src.stride = 4 * width;
+ src.tiling = 0;
+ src.data = src.cpu_mapping = NULL;
+ src.size = 4 * width * height;
+ src.num_tiles = 4 * width * height;
+ dst = tmp = src;
+
+ src.bo = bo.src;
+ tmp.bo = bo.tmp;
+ dst.bo = bo.dst;
+
+ /* The ring we've been using is 128k, and each rendering op
+ * will use at least 8 dwords:
+ *
+ * BATCH_START
+ * BATCH_START offset
+ * MI_FLUSH
+ * STORE_DATA_INDEX
+ * STORE_DATA_INDEX offset
+ * STORE_DATA_INDEX value
+ * MI_USER_INTERRUPT
+ * (padding)
+ *
+ * So iterate just a little more than that -- if we don't fill the ring
+ * doing this, we aren't likely to with this test.
+ */
+ for (i = 0; i < width * height; i++) {
+ int x = i % width;
+ int y = i / width;
+
+ drmtest_progress(output, i, width*height);
+
+ assert(y < height);
+
+ /* Dummy load to fill the ring */
+ copy(batch, &src, 0, 0, width, height, &tmp, 0, 0);
+ /* And copy the src into dst, pixel by pixel */
+ copy(batch, &src, x, y, 1, 1, &dst, x, y);
+ }
+
+ /* verify */
+ printf("verifying\n");
+ i = check_bo(&bo);
+ destroy_bo(&bo);
+
+ return i;
+}
+
+static void blt_copy(struct intel_batchbuffer *batch,
+ struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ unsigned w, unsigned h,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y)
+{
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ dst->stride);
+ OUT_BATCH((dst_y << 16) | dst_x); /* dst x1,y1 */
+ OUT_BATCH(((dst_y + h) << 16) | (dst_x + w)); /* dst x2,y2 */
+ OUT_RELOC(dst->bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH((src_y << 16) | src_x); /* src x1,y1 */
+ OUT_BATCH(src->stride);
+ OUT_RELOC(src->bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+int main(int argc, char **argv)
+{
+ drm_intel_bufmgr *bufmgr;
+ struct intel_batchbuffer *batch;
+ render_copyfunc_t copy;
+ int fd, fails = 0;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ fails += check_ring(bufmgr, batch, "blt", blt_copy);
+
+ /* Strictly only required on architectures with a separate BLT ring,
+ * but lets stress everybody.
+ */
+ copy = NULL;
+ if (IS_GEN2(batch->devid))
+ copy = gen2_render_copyfunc;
+ else if (IS_GEN3(batch->devid))
+ copy = gen3_render_copyfunc;
+ else if (IS_GEN6(batch->devid))
+ copy = gen6_render_copyfunc;
+ if (copy)
+ fails += check_ring(bufmgr, batch, "render", copy);
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return fails != 0;
+}
diff --git a/tests/gem_set_tiling_vs_blt.c b/tests/gem_set_tiling_vs_blt.c
new file mode 100644
index 00000000..5fa90d49
--- /dev/null
+++ b/tests/gem_set_tiling_vs_blt.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/** @file gem_set_tiling_vs_blt.c
+ *
+ * Testcase: Check for proper synchronization of tiling changes vs. tiled gpu
+ * access
+ *
+ * The blitter on gen3 and earlier needs properly set up fences. Which also
+ * means that for untiled blits we may not set up a fence before that blt has
+ * finished.
+ *
+ * Current kernels have a bug there, but it's pretty hard to hit because you
+ * need:
+ * - a blt on an untiled object which is aligned correctly for tiling.
+ * - a set_tiling to switch that object to tiling
+ * - another blt without any intervening cpu access that uses this object.
+ *
+ * Testcase has been extended to also check tiled->untiled and tiled->tiled
+ * transitions (i.e. changing stride).
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+uint32_t devid;
+
+#define TEST_SIZE (1024*1024)
+#define TEST_STRIDE (4*1024)
+#define TEST_HEIGHT(stride) (TEST_SIZE/(stride))
+#define TEST_WIDTH(stride) ((stride)/4)
+
+uint32_t data[TEST_SIZE/4];
+
+static void do_test(uint32_t tiling, unsigned stride,
+ uint32_t tiling_after, unsigned stride_after)
+{
+ drm_intel_bo *busy_bo, *test_bo, *target_bo;
+ int i, ret;
+ uint32_t *ptr;
+ uint32_t test_bo_handle;
+ uint32_t blt_stride, blt_bits;
+ bool tiling_changed = false;
+
+ printf("filling ring .. ");
+ busy_bo = drm_intel_bo_alloc(bufmgr, "busy bo bo", 16*1024*1024, 4096);
+
+ for (i = 0; i < 250; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 2*1024*4);
+ OUT_BATCH(0 << 16 | 1024);
+ OUT_BATCH((2048) << 16 | (2048));
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(2*1024*4);
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+ }
+ intel_batchbuffer_flush(batch);
+
+ printf("playing tricks .. ");
+ /* first allocate the target so it gets out of the way of playing funky
+ * tricks */
+ target_bo = drm_intel_bo_alloc(bufmgr, "target bo", TEST_SIZE, 4096);
+
+ /* allocate buffer with parameters _after_ transition we want to check
+ * and touch it, so that it's properly aligned in the gtt. */
+ test_bo = drm_intel_bo_alloc(bufmgr, "tiled busy bo", TEST_SIZE, 4096);
+ test_bo_handle = test_bo->handle;
+ ret = drm_intel_bo_set_tiling(test_bo, &tiling_after, stride_after);
+ assert(ret == 0);
+ drm_intel_gem_bo_map_gtt(test_bo);
+ ptr = test_bo->virtual;
+ *ptr = 0;
+ ptr = NULL;
+ drm_intel_gem_bo_unmap_gtt(test_bo);
+
+ drm_intel_bo_unreference(test_bo);
+
+ test_bo = NULL;
+
+ /* note we need a bo bigger than batches, otherwise the buffer reuse
+ * trick will fail. */
+ test_bo = drm_intel_bo_alloc(bufmgr, "busy bo", TEST_SIZE, 4096);
+ if (test_bo_handle != test_bo->handle)
+ fprintf(stderr, "libdrm reuse trick failed\n");
+ test_bo_handle = test_bo->handle;
+ /* ensure we have the right tiling before we start. */
+ ret = drm_intel_bo_set_tiling(test_bo, &tiling, stride);
+ assert(ret == 0);
+
+ if (tiling == I915_TILING_NONE) {
+ drm_intel_bo_subdata(test_bo, 0, TEST_SIZE, data);
+ } else {
+ drm_intel_gem_bo_map_gtt(test_bo);
+ ptr = test_bo->virtual;
+ memcpy(ptr, data, TEST_SIZE);
+ ptr = NULL;
+ drm_intel_gem_bo_unmap_gtt(test_bo);
+ }
+
+ blt_stride = stride;
+ blt_bits = 0;
+ if (intel_gen(devid) >= 4 && tiling != I915_TILING_NONE) {
+ blt_stride /= 4;
+ blt_bits = XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ blt_bits |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ stride);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH((TEST_HEIGHT(stride)) << 16 | (TEST_WIDTH(stride)));
+ OUT_RELOC_FENCED(target_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(blt_stride);
+ OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+ intel_batchbuffer_flush(batch);
+
+ drm_intel_bo_unreference(test_bo);
+
+ test_bo = drm_intel_bo_alloc_for_render(bufmgr, "tiled busy bo", TEST_SIZE, 4096);
+ if (test_bo_handle != test_bo->handle)
+ fprintf(stderr, "libdrm reuse trick failed\n");
+ ret = drm_intel_bo_set_tiling(test_bo, &tiling_after, stride_after);
+ assert(ret == 0);
+
+ /* Note: We don't care about gen4+ here because the blitter doesn't use
+ * fences there. So not setting tiling flags on the tiled buffer is ok.
+ */
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ stride_after);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH((1) << 16 | (1));
+ OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(stride_after);
+ OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+ intel_batchbuffer_flush(batch);
+
+ /* Now try to trick the kernel the kernel into changing up the fencing
+ * too early. */
+
+ printf("checking .. ");
+ memset(data, 0, TEST_SIZE);
+ drm_intel_bo_get_subdata(target_bo, 0, TEST_SIZE, data);
+ for (i = 0; i < TEST_SIZE/4; i++)
+ assert(data[i] == i);
+
+ /* check whether tiling on the test_bo actually changed. */
+ drm_intel_gem_bo_map_gtt(test_bo);
+ ptr = test_bo->virtual;
+ for (i = 0; i < TEST_SIZE/4; i++)
+ if (ptr[i] != data[i])
+ tiling_changed = true;
+ ptr = NULL;
+ drm_intel_gem_bo_unmap_gtt(test_bo);
+ assert(tiling_changed);
+
+ drm_intel_bo_unreference(test_bo);
+ drm_intel_bo_unreference(target_bo);
+ drm_intel_bo_unreference(busy_bo);
+ printf("done\n");
+}
+
+int main(int argc, char **argv)
+{
+ int i, fd;
+ uint32_t tiling, tiling_after;
+
+ for (i = 0; i < 1024*256; i++)
+ data[i] = i;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+
+ printf("testing untiled->tiled transisition:\n");
+ tiling = I915_TILING_NONE;
+ tiling_after = I915_TILING_X;
+ do_test(tiling, TEST_STRIDE, tiling_after, TEST_STRIDE);
+ assert(tiling == I915_TILING_NONE);
+ assert(tiling_after == I915_TILING_X);
+
+ printf("testing tiled->untiled transisition:\n");
+ tiling = I915_TILING_X;
+ tiling_after = I915_TILING_NONE;
+ do_test(tiling, TEST_STRIDE, tiling_after, TEST_STRIDE);
+ assert(tiling == I915_TILING_X);
+ assert(tiling_after == I915_TILING_NONE);
+
+ printf("testing tiled->tiled transisition:\n");
+ tiling = I915_TILING_X;
+ tiling_after = I915_TILING_X;
+ do_test(tiling, TEST_STRIDE/2, tiling_after, TEST_STRIDE);
+ assert(tiling == I915_TILING_X);
+ assert(tiling_after == I915_TILING_X);
+
+ return 0;
+}
diff --git a/tests/gem_set_tiling_vs_gtt.c b/tests/gem_set_tiling_vs_gtt.c
new file mode 100644
index 00000000..1241b54d
--- /dev/null
+++ b/tests/gem_set_tiling_vs_gtt.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define OBJECT_SIZE (1024*1024)
+#define TEST_STRIDE (1024*4)
+
+/**
+ * Testcase: Check set_tiling vs gtt mmap coherency
+ */
+
+int main(int argc, char **argv)
+{
+ int fd;
+ uint32_t *ptr;
+ uint32_t data[OBJECT_SIZE/4];
+ int i;
+ uint32_t handle;
+ bool tiling_changed;
+ int tile_height;
+
+ fd = drm_open_any();
+
+ if (IS_GEN2(intel_get_drm_devid(fd)))
+ tile_height = 16;
+ else
+ tile_height = 8;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+ ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
+ assert(ptr);
+
+ /* gtt coherency is done with set_domain in libdrm, don't break that */
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ ptr[i] = data[i] = i;
+
+ gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE);
+
+ printf("testing untiled->tiled\n");
+ tiling_changed = false;
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ /* Too lazy to check for the correct tiling, and impossible anyway on
+ * bit17 swizzling machines. */
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ if (ptr[i] != data[i])
+ tiling_changed = true;
+ assert(tiling_changed);
+
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ ptr[i] = data[i] = i;
+
+ gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE*2);
+
+ printf("testing tiled->tiled\n");
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ for (i = 0; i < OBJECT_SIZE/4; i++) {
+ int tile_row = i / (TEST_STRIDE * tile_height / 4);
+ int row = i / (TEST_STRIDE * 2 / 4);
+ int half = i & (TEST_STRIDE / 4);
+ int ofs = i % (TEST_STRIDE / 4);
+ int data_i = (tile_row/2)*(TEST_STRIDE * tile_height / 4)
+ + row*TEST_STRIDE/4
+ + half*tile_height + ofs;
+ uint32_t val = data[data_i];
+
+ if (ptr[i] != val) {
+ printf("mismatch at %i, row=%i, half=%i, ofs=%i\n",
+ i, row, half, ofs);
+ printf("read: 0x%08x, expected: 0x%08x\n",
+ ptr[i], val);
+ assert(0);
+ }
+
+ }
+
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ ptr[i] = data[i] = i;
+
+ gem_set_tiling(fd, handle, I915_TILING_NONE, 0);
+ printf("testing tiled->untiled\n");
+ tiling_changed = false;
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, 0);
+ /* Too lazy to check for the correct tiling, and impossible anyway on
+ * bit17 swizzling machines. */
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ if (ptr[i] != data[i])
+ tiling_changed = true;
+ assert(tiling_changed);
+
+ munmap(ptr, OBJECT_SIZE);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_set_tiling_vs_pwrite.c b/tests/gem_set_tiling_vs_pwrite.c
new file mode 100644
index 00000000..35ec5cdc
--- /dev/null
+++ b/tests/gem_set_tiling_vs_pwrite.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define OBJECT_SIZE (1024*1024)
+#define TEST_STRIDE (1024*4)
+
+/**
+ * Testcase: Check set_tiling vs pwrite coherency
+ */
+
+int main(int argc, char **argv)
+{
+ int fd;
+ uint32_t *ptr;
+ uint32_t data[OBJECT_SIZE/4];
+ int i;
+ uint32_t handle;
+
+ fd = drm_open_any();
+
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ data[i] = i;
+
+ handle = gem_create(fd, OBJECT_SIZE);
+ ptr = gem_mmap(fd, handle, OBJECT_SIZE, PROT_READ | PROT_WRITE);
+ assert(ptr);
+
+ gem_set_tiling(fd, handle, I915_TILING_X, TEST_STRIDE);
+
+ /* touch it */
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ *ptr = 0xdeadbeef;
+
+ printf("testing pwrite on tiled buffer\n");
+ gem_write(fd, handle, 0, data, OBJECT_SIZE);
+ memset(data, 0, OBJECT_SIZE);
+ gem_read(fd, handle, 0, data, OBJECT_SIZE);
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ assert(i == data[i]);
+
+ /* touch it before changing the tiling, so that the fence sticks around */
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT);
+ *ptr = 0xdeadbeef;
+
+ gem_set_tiling(fd, handle, I915_TILING_NONE, 0);
+
+ printf("testing pwrite on untiled, but still fenced buffer\n");
+ gem_write(fd, handle, 0, data, OBJECT_SIZE);
+ memset(data, 0, OBJECT_SIZE);
+ gem_read(fd, handle, 0, data, OBJECT_SIZE);
+ for (i = 0; i < OBJECT_SIZE/4; i++)
+ assert(i == data[i]);
+
+ munmap(ptr, OBJECT_SIZE);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_storedw_batches_loop.c b/tests/gem_storedw_batches_loop.c
new file mode 100644
index 00000000..8cf5f719
--- /dev/null
+++ b/tests/gem_storedw_batches_loop.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+static drm_intel_bo *target_bo;
+static int has_ppgtt = 0;
+
+/* Like the store dword test, but we create new command buffers each time */
+static void
+store_dword_loop(void)
+{
+ int cmd, i, val = 0, ret;
+ uint32_t *buf;
+ drm_intel_bo *cmd_bo;
+
+ cmd = MI_STORE_DWORD_IMM;
+ if (!has_ppgtt)
+ cmd |= MI_MEM_VIRTUAL;
+
+ for (i = 0; i < 0x80000; i++) {
+ cmd_bo = drm_intel_bo_alloc(bufmgr, "cmd bo", 4096, 4096);
+ if (!cmd_bo) {
+ fprintf(stderr, "failed to alloc cmd bo\n");
+ exit(-1);
+ }
+
+ drm_intel_bo_map(cmd_bo, 1);
+ buf = cmd_bo->virtual;
+
+ buf[0] = cmd;
+ buf[1] = 0;
+ buf[2] = target_bo->offset;
+ buf[3] = 0x42000000 + val;
+
+ ret = drm_intel_bo_references(cmd_bo, target_bo);
+ if (ret) {
+ fprintf(stderr, "failed to link cmd & target bos\n");
+ exit(-1);
+ }
+
+ ret = drm_intel_bo_emit_reloc(cmd_bo, 8, target_bo, 0,
+ I915_GEM_DOMAIN_INSTRUCTION,
+ I915_GEM_DOMAIN_INSTRUCTION);
+ if (ret) {
+ fprintf(stderr, "failed to emit reloc\n");
+ exit(-1);
+ }
+
+ buf[4] = MI_BATCH_BUFFER_END;
+ buf[5] = MI_BATCH_BUFFER_END;
+
+ drm_intel_bo_unmap(cmd_bo);
+
+ ret = drm_intel_bo_references(cmd_bo, target_bo);
+ if (ret != 1) {
+ fprintf(stderr, "bad bo reference count: %d\n", ret);
+ exit(-1);
+ }
+
+ ret = drm_intel_bo_exec(cmd_bo, 6 * 4, NULL, 0, 0);
+ if (ret) {
+ fprintf(stderr, "bo exec failed: %d\n", ret);
+ exit(-1);
+ }
+
+ drm_intel_bo_wait_rendering(cmd_bo);
+
+ drm_intel_bo_map(target_bo, 1);
+
+ buf = target_bo->virtual;
+ if (buf[0] != (0x42000000 | val)) {
+ fprintf(stderr,
+ "value mismatch: cur 0x%08x, stored 0x%08x\n",
+ buf[0], 0x42000000 | val);
+ exit(-1);
+ }
+ buf[0] = 0; /* let batch write it again */
+ drm_intel_bo_unmap(target_bo);
+
+ drm_intel_bo_unreference(cmd_bo);
+
+ val++;
+ }
+
+ printf("completed %d writes successfully\n", i);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ has_ppgtt = gem_uses_aliasing_ppgtt(fd);
+
+ if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) {
+
+ fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and"
+ "needs snoopable mem on pre-gen6\n");
+ return 77;
+ }
+
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+// drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ target_bo = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_bo) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ store_dword_loop();
+
+ drm_intel_bo_unreference(target_bo);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_storedw_loop_blt.c b/tests/gem_storedw_loop_blt.c
new file mode 100644
index 00000000..dda9b835
--- /dev/null
+++ b/tests/gem_storedw_loop_blt.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer;
+static int has_ppgtt = 0;
+
+/*
+ * Testcase: Basic blitter MI check using MI_STORE_DATA_IMM
+ */
+
+static void
+store_dword_loop(void)
+{
+ int cmd, i, val = 0;
+ uint32_t *buf;
+
+ cmd = MI_STORE_DWORD_IMM;
+ if (!has_ppgtt)
+ cmd |= MI_MEM_VIRTUAL;
+
+ for (i = 0; i < 0x100000; i++) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(cmd);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION,
+ I915_GEM_DOMAIN_INSTRUCTION, 0);
+ OUT_BATCH(val);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush_on_ring(batch, I915_EXEC_BLT);
+
+ drm_intel_bo_map(target_buffer, 0);
+
+ buf = target_buffer->virtual;
+ if (buf[0] != val) {
+ fprintf(stderr,
+ "value mismatch: cur 0x%08x, stored 0x%08x\n",
+ buf[0], val);
+ exit(-1);
+ }
+
+ drm_intel_bo_unmap(target_buffer);
+
+ val++;
+ }
+
+ drm_intel_bo_map(target_buffer, 0);
+ buf = target_buffer->virtual;
+
+ printf("completed %d writes successfully, current value: 0x%08x\n", i,
+ buf[0]);
+ drm_intel_bo_unmap(target_buffer);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ has_ppgtt = gem_uses_aliasing_ppgtt(fd);
+
+ if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) {
+
+ fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and "
+ "needs snoopable mem on pre-gen6\n");
+ return 77;
+ }
+
+ /* This only works with ppgtt */
+ if (!has_ppgtt) {
+ fprintf(stderr, "no ppgtt detected, which is required\n");
+ return 77;
+ }
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ store_dword_loop();
+
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_storedw_loop_bsd.c b/tests/gem_storedw_loop_bsd.c
new file mode 100644
index 00000000..d7c61047
--- /dev/null
+++ b/tests/gem_storedw_loop_bsd.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer;
+static int has_ppgtt = 0;
+
+/*
+ * Testcase: Basic bsd MI check using MI_STORE_DATA_IMM
+ */
+
+static void
+store_dword_loop(void)
+{
+ int cmd, i, val = 0;
+ uint32_t *buf;
+
+ cmd = MI_STORE_DWORD_IMM;
+ if (!has_ppgtt)
+ cmd |= MI_MEM_VIRTUAL;
+
+ for (i = 0; i < 0x100000; i++) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(cmd);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION,
+ I915_GEM_DOMAIN_INSTRUCTION, 0);
+ OUT_BATCH(val);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush_on_ring(batch, I915_EXEC_BSD);
+
+ drm_intel_bo_map(target_buffer, 0);
+
+ buf = target_buffer->virtual;
+ if (buf[0] != val) {
+ fprintf(stderr,
+ "value mismatch: cur 0x%08x, stored 0x%08x\n",
+ buf[0], val);
+ exit(-1);
+ }
+
+ drm_intel_bo_unmap(target_buffer);
+
+ val++;
+ }
+
+ drm_intel_bo_map(target_buffer, 0);
+ buf = target_buffer->virtual;
+
+ printf("completed %d writes successfully, current value: 0x%08x\n", i,
+ buf[0]);
+ drm_intel_bo_unmap(target_buffer);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ has_ppgtt = gem_uses_aliasing_ppgtt(fd);
+
+ if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) {
+
+ fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and "
+ "needs snoopable mem on pre-gen6\n");
+ return 77;
+ }
+
+ if (IS_GEN6(devid)) {
+
+ fprintf(stderr, "MI_STORE_DATA broken on gen6 bsd\n");
+ return 77;
+ }
+
+ /* This only works with ppgtt */
+ if (!has_ppgtt) {
+ fprintf(stderr, "no ppgtt detected, which is required\n");
+ return 77;
+ }
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ store_dword_loop();
+
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_storedw_loop_render.c b/tests/gem_storedw_loop_render.c
new file mode 100644
index 00000000..19a41b65
--- /dev/null
+++ b/tests/gem_storedw_loop_render.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ * Jesse Barnes <jbarnes@virtuousgeek.org> (based on gem_bad_blit.c)
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *target_buffer;
+static int has_ppgtt = 0;
+
+/*
+ * Testcase: Basic render MI check using MI_STORE_DATA_IMM
+ */
+
+static void
+store_dword_loop(void)
+{
+ int cmd, i, val = 0;
+ uint32_t *buf;
+
+ cmd = MI_STORE_DWORD_IMM;
+ if (!has_ppgtt)
+ cmd |= MI_MEM_VIRTUAL;
+
+ for (i = 0; i < 0x100000; i++) {
+ BEGIN_BATCH(4);
+ OUT_BATCH(cmd);
+ OUT_BATCH(0); /* reserved */
+ OUT_RELOC(target_buffer, I915_GEM_DOMAIN_INSTRUCTION,
+ I915_GEM_DOMAIN_INSTRUCTION, 0);
+ OUT_BATCH(val);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush_on_ring(batch, 0);
+
+ drm_intel_bo_map(target_buffer, 0);
+
+ buf = target_buffer->virtual;
+ if (buf[0] != val) {
+ fprintf(stderr,
+ "value mismatch: cur 0x%08x, stored 0x%08x\n",
+ buf[0], val);
+ exit(-1);
+ }
+
+ drm_intel_bo_unmap(target_buffer);
+
+ val++;
+ }
+
+ drm_intel_bo_map(target_buffer, 0);
+ buf = target_buffer->virtual;
+
+ printf("completed %d writes successfully, current value: 0x%08x\n", i,
+ buf[0]);
+ drm_intel_bo_unmap(target_buffer);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+ int devid;
+
+ if (argc != 1) {
+ fprintf(stderr, "usage: %s\n", argv[0]);
+ exit(-1);
+ }
+
+ fd = drm_open_any();
+ devid = intel_get_drm_devid(fd);
+
+ has_ppgtt = gem_uses_aliasing_ppgtt(fd);
+
+ if (IS_GEN2(devid) || IS_GEN3(devid) || IS_GEN4(devid) || IS_GEN5(devid)) {
+
+ fprintf(stderr, "MI_STORE_DATA can only use GTT address on gen4+/g33 and "
+ "needs snoopable mem on pre-gen6\n");
+ return 77;
+ }
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+ if (!batch) {
+ fprintf(stderr, "failed to create batch buffer\n");
+ exit(-1);
+ }
+
+ target_buffer = drm_intel_bo_alloc(bufmgr, "target bo", 4096, 4096);
+ if (!target_buffer) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ store_dword_loop();
+
+ drm_intel_bo_unreference(target_buffer);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_stress.c b/tests/gem_stress.c
new file mode 100644
index 00000000..69239ac1
--- /dev/null
+++ b/tests/gem_stress.c
@@ -0,0 +1,945 @@
+/*
+ * Copyright © 2011 Daniel Vetter
+ *
+ * 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * Partially based upon gem_tiled_fence_blits.c
+ */
+
+/** @file gem_stress.c
+ *
+ * This is a general gem coherency test. It's designed to eventually replicate
+ * any possible sequence of access patterns. It works by copying a set of tiles
+ * between two sets of backing buffer objects, randomly permutating the assinged
+ * position on each copy operations.
+ *
+ * The copy operation are done in tiny portions (to reduce any race windows
+ * for corruptions, hence increasing the chances for observing one) and are
+ * constantly switched between all means to copy stuff (fenced blitter, unfenced
+ * render, mmap, pwrite/read).
+ *
+ * After every complete move of a set tiling parameters of a buffer are randomly
+ * changed to simulate the effects of libdrm caching.
+ *
+ * Buffers are 1mb big to nicely fit into fences on gen2/3. A few are further
+ * split up to test relaxed fencing. Using this to push the average working set
+ * size over the available gtt space forces objects to be mapped as unfenceable
+ * (and as a side-effect tests gtt map/unmap coherency).
+ *
+ * In short: designed for maximum evilness.
+ */
+
+#include "rendercopy.h"
+
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+
+/** TODO:
+ * - beat on relaxed fencing (i.e. mappable/fenceable tracking in the kernel)
+ * - render copy (to check fence tracking and cache coherency management by the
+ * kernel)
+ * - multi-threading: probably just a wrapper script to launch multiple
+ * instances + an option to accordingly reduce the working set
+ * - gen6 inter-ring coherency (needs render copy, first)
+ * - variable buffer size
+ * - add an option to fork a second process that randomly sends signals to the
+ * first one (to check consistency of the kernel recovery paths)
+ */
+
+drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+int drm_fd;
+int devid;
+int num_fences;
+
+drm_intel_bo *busy_bo;
+
+struct option_struct {
+ unsigned scratch_buf_size;
+ unsigned max_dimension;
+ unsigned num_buffers;
+ int trace_tile;
+ int no_hw;
+ int gpu_busy_load;
+ int use_render;
+ int use_blt;
+ int forced_tiling;
+ int use_cpu_maps;
+ int total_rounds;
+ int fail;
+ int tiles_per_buf;
+ int ducttape;
+ int tile_size;
+ int check_render_cpyfn;
+ int use_signal_helper;
+};
+
+struct option_struct options;
+
+#define MAX_BUFS 4096
+#define SCRATCH_BUF_SIZE 1024*1024
+#define BUSY_BUF_SIZE (256*4096)
+#define TILE_BYTES(size) ((size)*(size)*sizeof(uint32_t))
+
+static struct scratch_buf buffers[2][MAX_BUFS];
+/* tile i is at logical position tile_permutation[i] */
+static unsigned *tile_permutation;
+static unsigned num_buffers = 0;
+static unsigned current_set = 0;
+static unsigned target_set = 0;
+static unsigned num_total_tiles = 0;
+
+int fence_storm = 0;
+static int gpu_busy_load = 10;
+
+struct {
+ unsigned num_failed;
+ unsigned max_failed_reads;
+} stats;
+
+static void tile2xy(struct scratch_buf *buf, unsigned tile, unsigned *x, unsigned *y)
+{
+ assert(tile < buf->num_tiles);
+ *x = (tile*options.tile_size) % (buf->stride/sizeof(uint32_t));
+ *y = ((tile*options.tile_size) / (buf->stride/sizeof(uint32_t))) * options.tile_size;
+}
+
+static void emit_blt(drm_intel_bo *src_bo, uint32_t src_tiling, unsigned src_pitch,
+ unsigned src_x, unsigned src_y, unsigned w, unsigned h,
+ drm_intel_bo *dst_bo, uint32_t dst_tiling, unsigned dst_pitch,
+ unsigned dst_x, unsigned dst_y)
+{
+ uint32_t cmd_bits = 0;
+
+ if (IS_965(devid) && src_tiling) {
+ src_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ if (IS_965(devid) && dst_tiling) {
+ dst_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ /* copy lower half to upper half */
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ cmd_bits);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ dst_pitch);
+ OUT_BATCH(dst_y << 16 | dst_x);
+ OUT_BATCH((dst_y+h) << 16 | (dst_x+w));
+ OUT_RELOC_FENCED(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(src_y << 16 | src_x);
+ OUT_BATCH(src_pitch);
+ OUT_RELOC_FENCED(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+}
+
+/* All this gem trashing wastes too much cpu time, so give the gpu something to
+ * do to increase changes for races. */
+static void keep_gpu_busy(void)
+{
+ int tmp;
+
+ tmp = 1 << gpu_busy_load;
+ assert(tmp <= 1024);
+
+ emit_blt(busy_bo, 0, 4096, 0, 0, tmp, 128,
+ busy_bo, 0, 4096, 0, 128);
+}
+
+static void set_to_cpu_domain(struct scratch_buf *buf, int writing)
+{
+ gem_set_domain(drm_fd, buf->bo->handle, I915_GEM_DOMAIN_CPU,
+ writing ? I915_GEM_DOMAIN_CPU : 0);
+}
+
+static unsigned int copyfunc_seq = 0;
+static void (*copyfunc)(struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no);
+
+/* stride, x, y in units of uint32_t! */
+static void cpucpy2d(uint32_t *src, unsigned src_stride, unsigned src_x, unsigned src_y,
+ uint32_t *dst, unsigned dst_stride, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no)
+{
+ int i, j;
+ int failed = 0;
+
+ for (i = 0; i < options.tile_size; i++) {
+ for (j = 0; j < options.tile_size; j++) {
+ unsigned dst_ofs = dst_x + j + dst_stride * (dst_y + i);
+ unsigned src_ofs = src_x + j + src_stride * (src_y + i);
+ unsigned expect = logical_tile_no*options.tile_size*options.tile_size
+ + i*options.tile_size + j;
+ uint32_t tmp = src[src_ofs];
+ if (tmp != expect) {
+ printf("mismatch at tile %i pos %i, read %i, expected %i, diff %i\n",
+ logical_tile_no, i*options.tile_size + j, tmp, expect, (int) tmp - expect);
+ if (options.trace_tile >= 0 && options.fail)
+ exit(1);
+ failed++;
+ }
+ /* when not aborting, correct any errors */
+ dst[dst_ofs] = expect;
+ }
+ }
+ if (failed && options.fail)
+ exit(1);
+
+ if (failed > stats.max_failed_reads)
+ stats.max_failed_reads = failed;
+ if (failed)
+ stats.num_failed++;
+}
+
+static void cpu_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no)
+{
+ assert(batch->ptr == batch->buffer);
+
+ if (options.ducttape)
+ drm_intel_bo_wait_rendering(dst->bo);
+
+ if (options.use_cpu_maps) {
+ set_to_cpu_domain(src, 0);
+ set_to_cpu_domain(dst, 1);
+ }
+
+ cpucpy2d(src->data, src->stride/sizeof(uint32_t), src_x, src_y,
+ dst->data, dst->stride/sizeof(uint32_t), dst_x, dst_y,
+ logical_tile_no);
+}
+
+static void prw_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no)
+{
+ uint32_t tmp_tile[options.tile_size*options.tile_size];
+ int i;
+
+ assert(batch->ptr == batch->buffer);
+
+ if (options.ducttape)
+ drm_intel_bo_wait_rendering(dst->bo);
+
+ if (src->tiling == I915_TILING_NONE) {
+ for (i = 0; i < options.tile_size; i++) {
+ unsigned ofs = src_x*sizeof(uint32_t) + src->stride*(src_y + i);
+ drm_intel_bo_get_subdata(src->bo, ofs,
+ options.tile_size*sizeof(uint32_t),
+ tmp_tile + options.tile_size*i);
+ }
+ } else {
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(src, 0);
+
+ cpucpy2d(src->data, src->stride/sizeof(uint32_t), src_x, src_y,
+ tmp_tile, options.tile_size, 0, 0, logical_tile_no);
+ }
+
+ if (dst->tiling == I915_TILING_NONE) {
+ for (i = 0; i < options.tile_size; i++) {
+ unsigned ofs = dst_x*sizeof(uint32_t) + dst->stride*(dst_y + i);
+ drm_intel_bo_subdata(dst->bo, ofs,
+ options.tile_size*sizeof(uint32_t),
+ tmp_tile + options.tile_size*i);
+ }
+ } else {
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(dst, 1);
+
+ cpucpy2d(tmp_tile, options.tile_size, 0, 0,
+ dst->data, dst->stride/sizeof(uint32_t), dst_x, dst_y,
+ logical_tile_no);
+ }
+}
+
+static void blitter_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no)
+{
+ static unsigned keep_gpu_busy_counter = 0;
+
+ /* check both edges of the fence usage */
+ if (keep_gpu_busy_counter & 1 && !fence_storm)
+ keep_gpu_busy();
+
+ emit_blt(src->bo, src->tiling, src->stride, src_x, src_y,
+ options.tile_size, options.tile_size,
+ dst->bo, dst->tiling, dst->stride, dst_x, dst_y);
+
+ if (!(keep_gpu_busy_counter & 1) && !fence_storm)
+ keep_gpu_busy();
+
+ keep_gpu_busy_counter++;
+
+ if (src->tiling)
+ fence_storm--;
+ if (dst->tiling)
+ fence_storm--;
+
+ if (fence_storm <= 1) {
+ fence_storm = 0;
+ intel_batchbuffer_flush(batch);
+ }
+}
+
+static void render_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y,
+ struct scratch_buf *dst, unsigned dst_x, unsigned dst_y,
+ unsigned logical_tile_no)
+{
+ static unsigned keep_gpu_busy_counter = 0;
+
+ /* check both edges of the fence usage */
+ if (keep_gpu_busy_counter & 1)
+ keep_gpu_busy();
+
+ if (IS_GEN2(devid))
+ gen2_render_copyfunc(batch,
+ src, src_x, src_y,
+ options.tile_size, options.tile_size,
+ dst, dst_x, dst_y);
+ else if (IS_GEN3(devid))
+ gen3_render_copyfunc(batch,
+ src, src_x, src_y,
+ options.tile_size, options.tile_size,
+ dst, dst_x, dst_y);
+ else if (IS_GEN6(devid))
+ gen6_render_copyfunc(batch,
+ src, src_x, src_y,
+ options.tile_size, options.tile_size,
+ dst, dst_x, dst_y);
+ else if (IS_GEN7(devid))
+ gen7_render_copyfunc(batch,
+ src, src_x, src_y,
+ options.tile_size, options.tile_size,
+ dst, dst_x, dst_y);
+ else
+ blitter_copyfunc(src, src_x, src_y,
+ dst, dst_x, dst_y,
+ logical_tile_no);
+ if (!(keep_gpu_busy_counter & 1))
+ keep_gpu_busy();
+
+ keep_gpu_busy_counter++;
+ intel_batchbuffer_flush(batch);
+}
+
+static void next_copyfunc(int tile)
+{
+ if (fence_storm) {
+ if (tile == options.trace_tile)
+ printf(" using fence storm\n");
+ return;
+ }
+
+ if (copyfunc_seq % 61 == 0
+ && options.forced_tiling != I915_TILING_NONE) {
+ if (tile == options.trace_tile)
+ printf(" using fence storm\n");
+ fence_storm = num_fences;
+ copyfunc = blitter_copyfunc;
+ } else if (copyfunc_seq % 17 == 0) {
+ if (tile == options.trace_tile)
+ printf(" using cpu\n");
+ copyfunc = cpu_copyfunc;
+ } else if (copyfunc_seq % 19 == 0) {
+ if (tile == options.trace_tile)
+ printf(" using prw\n");
+ copyfunc = prw_copyfunc;
+ } else if (copyfunc_seq % 3 == 0 && options.use_render) {
+ if (tile == options.trace_tile)
+ printf(" using render\n");
+ copyfunc = render_copyfunc;
+ } else if (options.use_blt){
+ if (tile == options.trace_tile)
+ printf(" using blitter\n");
+ copyfunc = blitter_copyfunc;
+ } else if (options.use_render){
+ if (tile == options.trace_tile)
+ printf(" using render\n");
+ copyfunc = render_copyfunc;
+ } else {
+ copyfunc = cpu_copyfunc;
+ }
+
+ copyfunc_seq++;
+}
+
+static void fan_out(void)
+{
+ uint32_t tmp_tile[options.tile_size*options.tile_size];
+ uint32_t seq = 0;
+ int i, k;
+ unsigned tile, buf_idx, x, y;
+
+ for (i = 0; i < num_total_tiles; i++) {
+ tile = i;
+ buf_idx = tile / options.tiles_per_buf;
+ tile %= options.tiles_per_buf;
+
+ tile2xy(&buffers[current_set][buf_idx], tile, &x, &y);
+
+ for (k = 0; k < options.tile_size*options.tile_size; k++)
+ tmp_tile[k] = seq++;
+
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(&buffers[current_set][buf_idx], 1);
+
+ cpucpy2d(tmp_tile, options.tile_size, 0, 0,
+ buffers[current_set][buf_idx].data,
+ buffers[current_set][buf_idx].stride / sizeof(uint32_t),
+ x, y, i);
+ }
+
+ for (i = 0; i < num_total_tiles; i++)
+ tile_permutation[i] = i;
+}
+
+static void fan_in_and_check(void)
+{
+ uint32_t tmp_tile[options.tile_size*options.tile_size];
+ unsigned tile, buf_idx, x, y;
+ int i;
+ for (i = 0; i < num_total_tiles; i++) {
+ tile = tile_permutation[i];
+ buf_idx = tile / options.tiles_per_buf;
+ tile %= options.tiles_per_buf;
+
+ tile2xy(&buffers[current_set][buf_idx], tile, &x, &y);
+
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(&buffers[current_set][buf_idx], 0);
+
+ cpucpy2d(buffers[current_set][buf_idx].data,
+ buffers[current_set][buf_idx].stride / sizeof(uint32_t),
+ x, y,
+ tmp_tile, options.tile_size, 0, 0,
+ i);
+ }
+}
+
+static void sanitize_stride(struct scratch_buf *buf)
+{
+
+ if (buf_height(buf) > options.max_dimension)
+ buf->stride = buf->size / options.max_dimension;
+
+ if (buf_height(buf) < options.tile_size)
+ buf->stride = buf->size / options.tile_size;
+
+ if (buf_width(buf) < options.tile_size)
+ buf->stride = options.tile_size * sizeof(uint32_t);
+
+ assert(buf->stride <= 8192);
+ assert(buf_width(buf) <= options.max_dimension);
+ assert(buf_height(buf) <= options.max_dimension);
+
+ assert(buf_width(buf) >= options.tile_size);
+ assert(buf_height(buf) >= options.tile_size);
+
+}
+
+static void init_buffer(struct scratch_buf *buf, unsigned size)
+{
+ buf->bo = drm_intel_bo_alloc(bufmgr, "tiled bo", size, 4096);
+ buf->size = size;
+ assert(buf->bo);
+ buf->tiling = I915_TILING_NONE;
+ buf->stride = 4096;
+
+ sanitize_stride(buf);
+
+ if (options.no_hw)
+ buf->data = malloc(size);
+ else {
+ if (options.use_cpu_maps)
+ drm_intel_bo_map(buf->bo, 1);
+ else
+ drm_intel_gem_bo_map_gtt(buf->bo);
+ buf->data = buf->bo->virtual;
+ }
+
+ buf->num_tiles = options.tiles_per_buf;
+}
+
+static void exchange_buf(void *array, unsigned i, unsigned j)
+{
+ struct scratch_buf *buf_arr, tmp;
+ buf_arr = array;
+
+ memcpy(&tmp, &buf_arr[i], sizeof(struct scratch_buf));
+ memcpy(&buf_arr[i], &buf_arr[j], sizeof(struct scratch_buf));
+ memcpy(&buf_arr[j], &tmp, sizeof(struct scratch_buf));
+}
+
+
+static void init_set(unsigned set)
+{
+ long int r;
+ int i;
+
+ drmtest_permute_array(buffers[set], num_buffers, exchange_buf);
+
+ if (current_set == 1 && options.gpu_busy_load == 0) {
+ gpu_busy_load++;
+ if (gpu_busy_load > 10)
+ gpu_busy_load = 6;
+ }
+
+ for (i = 0; i < num_buffers; i++) {
+ r = random();
+ if ((r & 3) != 0)
+ continue;
+ r >>= 2;
+
+ if ((r & 3) != 0)
+ buffers[set][i].tiling = I915_TILING_X;
+ else
+ buffers[set][i].tiling = I915_TILING_NONE;
+ r >>= 2;
+ if (options.forced_tiling >= 0)
+ buffers[set][i].tiling = options.forced_tiling;
+
+ if (buffers[set][i].tiling == I915_TILING_NONE) {
+ /* min 64 byte stride */
+ r %= 8;
+ buffers[set][i].stride = 64 * (1 << r);
+ } else if (IS_GEN2(devid)) {
+ /* min 128 byte stride */
+ r %= 7;
+ buffers[set][i].stride = 128 * (1 << r);
+ } else {
+ /* min 512 byte stride */
+ r %= 5;
+ buffers[set][i].stride = 512 * (1 << r);
+ }
+
+ sanitize_stride(&buffers[set][i]);
+
+ gem_set_tiling(drm_fd, buffers[set][i].bo->handle,
+ buffers[set][i].tiling,
+ buffers[set][i].stride);
+
+ if (options.trace_tile != -1 && i == options.trace_tile/options.tiles_per_buf)
+ printf("changing buffer %i containing tile %i: tiling %i, stride %i\n", i,
+ options.trace_tile,
+ buffers[set][i].tiling, buffers[set][i].stride);
+ }
+}
+
+static void exchange_uint(void *array, unsigned i, unsigned j)
+{
+ unsigned *i_arr = array;
+ unsigned i_tmp;
+
+ i_tmp = i_arr[i];
+ i_arr[i] = i_arr[j];
+ i_arr[j] = i_tmp;
+}
+
+static void copy_tiles(unsigned *permutation)
+{
+ unsigned src_tile, src_buf_idx, src_x, src_y;
+ unsigned dst_tile, dst_buf_idx, dst_x, dst_y;
+ struct scratch_buf *src_buf, *dst_buf;
+ int i, idx;
+ for (i = 0; i < num_total_tiles; i++) {
+ /* tile_permutation is independent of current_permutation, so
+ * abuse it to randomize the order of the src bos */
+ idx = tile_permutation[i];
+ src_buf_idx = idx / options.tiles_per_buf;
+ src_tile = idx % options.tiles_per_buf;
+ src_buf = &buffers[current_set][src_buf_idx];
+
+ tile2xy(src_buf, src_tile, &src_x, &src_y);
+
+ dst_buf_idx = permutation[idx] / options.tiles_per_buf;
+ dst_tile = permutation[idx] % options.tiles_per_buf;
+ dst_buf = &buffers[target_set][dst_buf_idx];
+
+ tile2xy(dst_buf, dst_tile, &dst_x, &dst_y);
+
+ if (options.trace_tile == i)
+ printf("copying tile %i from %i (%i, %i) to %i (%i, %i)", i,
+ tile_permutation[i], src_buf_idx, src_tile,
+ permutation[idx], dst_buf_idx, dst_tile);
+
+ if (options.no_hw) {
+ cpucpy2d(src_buf->data,
+ src_buf->stride / sizeof(uint32_t),
+ src_x, src_y,
+ dst_buf->data,
+ dst_buf->stride / sizeof(uint32_t),
+ dst_x, dst_y,
+ i);
+ } else {
+ next_copyfunc(i);
+
+ copyfunc(src_buf, src_x, src_y, dst_buf, dst_x, dst_y,
+ i);
+ }
+ }
+
+ intel_batchbuffer_flush(batch);
+}
+
+static int get_num_fences(void)
+{
+ drm_i915_getparam_t gp;
+ int ret, val;
+
+ gp.param = I915_PARAM_NUM_FENCES_AVAIL;
+ gp.value = &val;
+ ret = drmIoctl(drm_fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ assert (ret == 0);
+
+ printf ("total %d fences\n", val);
+ assert(val > 4);
+
+ return val - 2;
+}
+
+static void sanitize_tiles_per_buf(void)
+{
+ if (options.tiles_per_buf > options.scratch_buf_size / TILE_BYTES(options.tile_size))
+ options.tiles_per_buf = options.scratch_buf_size / TILE_BYTES(options.tile_size);
+}
+
+static void parse_options(int argc, char **argv)
+{
+ int c, tmp;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"no-hw", 0, 0, 'd'},
+ {"buf-size", 1, 0, 's'},
+ {"gpu-busy-load", 1, 0, 'g'},
+ {"no-signals", 0, 0, 'S'},
+ {"buffer-count", 1, 0, 'c'},
+ {"trace-tile", 1, 0, 't'},
+ {"disable-blt", 0, 0, 'b'},
+ {"disable-render", 0, 0, 'r'},
+ {"untiled", 0, 0, 'u'},
+ {"x-tiled", 0, 0, 'x'},
+ {"use-cpu-maps", 0, 0, 'm'},
+ {"rounds", 1, 0, 'o'},
+ {"no-fail", 0, 0, 'f'},
+ {"tiles-per-buf", 0, 0, 'p'},
+#define DUCTAPE 0xdead0001
+ {"remove-duct-tape", 0, 0, DUCTAPE},
+#define TILESZ 0xdead0002
+ {"tile-size", 1, 0, TILESZ},
+#define CHCK_RENDER 0xdead0003
+ {"check-render-cpyfn", 0, 0, CHCK_RENDER},
+ };
+
+ options.scratch_buf_size = 256*4096;
+ options.no_hw = 0;
+ options.use_signal_helper = 1;
+ options.gpu_busy_load = 0;
+ options.num_buffers = 0;
+ options.trace_tile = -1;
+ options.use_render = 1;
+ options.use_blt = 1;
+ options.forced_tiling = -1;
+ options.use_cpu_maps = 0;
+ options.total_rounds = 512;
+ options.fail = 1;
+ options.ducttape = 1;
+ options.tile_size = 16;
+ options.tiles_per_buf = options.scratch_buf_size / TILE_BYTES(options.tile_size);
+ options.check_render_cpyfn = 0;
+
+ while((c = getopt_long(argc, argv, "ds:g:c:t:rbuxmo:fp:",
+ long_options, &option_index)) != -1) {
+ switch(c) {
+ case 'd':
+ options.no_hw = 1;
+ printf("no-hw debug mode\n");
+ break;
+ case 'S':
+ options.use_signal_helper = 0;
+ printf("disabling that pesky nuisance who keeps interrupting us\n");
+ break;
+ case 's':
+ tmp = atoi(optarg);
+ if (tmp < options.tile_size*8192)
+ printf("scratch buffer size needs to be at least %i\n",
+ options.tile_size*8192);
+ else if (tmp & (tmp - 1)) {
+ printf("scratch buffer size needs to be a power-of-two\n");
+ } else {
+ printf("fixed scratch buffer size to %u\n", tmp);
+ options.scratch_buf_size = tmp;
+ sanitize_tiles_per_buf();
+ }
+ break;
+ case 'g':
+ tmp = atoi(optarg);
+ if (tmp < 0 || tmp > 10)
+ printf("gpu busy load needs to be bigger than 0 and smaller than 10\n");
+ else {
+ printf("gpu busy load factor set to %i\n", tmp);
+ gpu_busy_load = options.gpu_busy_load = tmp;
+ }
+ break;
+ case 'c':
+ options.num_buffers = atoi(optarg);
+ printf("buffer count set to %i\n", options.num_buffers);
+ break;
+ case 't':
+ options.trace_tile = atoi(optarg);
+ printf("tracing tile %i\n", options.trace_tile);
+ break;
+ case 'r':
+ options.use_render = 0;
+ printf("disabling render copy\n");
+ break;
+ case 'b':
+ options.use_blt = 0;
+ printf("disabling blt copy\n");
+ break;
+ case 'u':
+ options.forced_tiling = I915_TILING_NONE;
+ printf("disabling tiling\n");
+ break;
+ case 'x':
+ if (options.use_cpu_maps) {
+ printf("tiling not possible with cpu maps\n");
+ } else {
+ options.forced_tiling = I915_TILING_X;
+ printf("using only X-tiling\n");
+ }
+ break;
+ case 'm':
+ options.use_cpu_maps = 1;
+ options.forced_tiling = I915_TILING_NONE;
+ printf("disabling tiling\n");
+ break;
+ case 'o':
+ options.total_rounds = atoi(optarg);
+ printf("total rounds %i\n", options.total_rounds);
+ break;
+ case 'f':
+ options.fail = 0;
+ printf("not failing when detecting errors\n");
+ break;
+ case 'p':
+ options.tiles_per_buf = atoi(optarg);
+ printf("tiles per buffer %i\n", options.tiles_per_buf);
+ break;
+ case DUCTAPE:
+ options.ducttape = 0;
+ printf("applying duct-tape\n");
+ break;
+ case TILESZ:
+ options.tile_size = atoi(optarg);
+ sanitize_tiles_per_buf();
+ printf("til size %i\n", options.tile_size);
+ break;
+ case CHCK_RENDER:
+ options.check_render_cpyfn = 1;
+ printf("checking render copy function\n");
+ break;
+ default:
+ printf("unkown command options\n");
+ break;
+ }
+ }
+
+ if (optind < argc)
+ printf("unkown command options\n");
+
+ /* actually 32767, according to docs, but that kills our nice pot calculations. */
+ options.max_dimension = 16*1024;
+ if (options.use_render) {
+ if (IS_GEN2(devid) || IS_GEN3(devid))
+ options.max_dimension = 2048;
+ else
+ options.max_dimension = 8192;
+ }
+ printf("Limiting buffer to %dx%d\n",
+ options.max_dimension, options.max_dimension);
+}
+
+static void init(void)
+{
+ int i;
+ unsigned tmp;
+
+ if (options.num_buffers == 0) {
+ tmp = gem_aperture_size(drm_fd);
+ tmp = tmp > 256*(1024*1024) ? 256*(1024*1024) : tmp;
+ num_buffers = 2 * tmp / options.scratch_buf_size / 3;
+ num_buffers /= 2;
+ printf("using %u buffers\n", num_buffers);
+ } else
+ num_buffers = options.num_buffers;
+
+ bufmgr = drm_intel_bufmgr_gem_init(drm_fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ drm_intel_bufmgr_gem_enable_fenced_relocs(bufmgr);
+ num_fences = get_num_fences();
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ busy_bo = drm_intel_bo_alloc(bufmgr, "tiled bo", BUSY_BUF_SIZE, 4096);
+ if (options.forced_tiling >= 0)
+ gem_set_tiling(drm_fd, busy_bo->handle, options.forced_tiling, 4096);
+
+ for (i = 0; i < num_buffers; i++) {
+ init_buffer(&buffers[0][i], options.scratch_buf_size);
+ init_buffer(&buffers[1][i], options.scratch_buf_size);
+
+ num_total_tiles += buffers[0][i].num_tiles;
+ }
+ current_set = 0;
+
+ /* just in case it helps reproducability */
+ srandom(0xdeadbeef);
+}
+
+static void check_render_copyfunc(void)
+{
+ struct scratch_buf src, dst;
+ uint32_t *ptr;
+ int i, j, pass;
+
+ if (!options.check_render_cpyfn)
+ return;
+
+ init_buffer(&src, options.scratch_buf_size);
+ init_buffer(&dst, options.scratch_buf_size);
+
+ for (pass = 0; pass < 16; pass++) {
+ int sx = random() % (buf_width(&src)-options.tile_size);
+ int sy = random() % (buf_height(&src)-options.tile_size);
+ int dx = random() % (buf_width(&dst)-options.tile_size);
+ int dy = random() % (buf_height(&dst)-options.tile_size);
+
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(&src, 1);
+
+ memset(src.data, 0xff, options.scratch_buf_size);
+ for (j = 0; j < options.tile_size; j++) {
+ ptr = (uint32_t*)((char *)src.data + sx*4 + (sy+j) * src.stride);
+ for (i = 0; i < options.tile_size; i++)
+ ptr[i] = j * options.tile_size + i;
+ }
+
+ render_copyfunc(&src, sx, sy, &dst, dx, dy, 0);
+
+ if (options.use_cpu_maps)
+ set_to_cpu_domain(&dst, 0);
+
+ for (j = 0; j < options.tile_size; j++) {
+ ptr = (uint32_t*)((char *)dst.data + dx*4 + (dy+j) * dst.stride);
+ for (i = 0; i < options.tile_size; i++)
+ if (ptr[i] != j * options.tile_size + i) {
+ printf("render copyfunc mismatch at (%d, %d): found %d, expected %d\n",
+ i, j, ptr[i], j*options.tile_size + i);
+ }
+ }
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, j;
+ unsigned *current_permutation, *tmp_permutation;
+
+ drm_fd = drm_open_any();
+ devid = intel_get_drm_devid(drm_fd);
+
+ parse_options(argc, argv);
+
+ /* start our little helper early before too may allocations occur */
+ if (options.use_signal_helper)
+ drmtest_fork_signal_helper();
+
+ init();
+
+ check_render_copyfunc();
+
+ tile_permutation = malloc(num_total_tiles*sizeof(uint32_t));
+ current_permutation = malloc(num_total_tiles*sizeof(uint32_t));
+ tmp_permutation = malloc(num_total_tiles*sizeof(uint32_t));
+ assert(tile_permutation);
+ assert(current_permutation);
+ assert(tmp_permutation);
+
+ fan_out();
+
+ for (i = 0; i < options.total_rounds; i++) {
+ printf("round %i\n", i);
+ if (i % 64 == 63) {
+ fan_in_and_check();
+ printf("everything correct after %i rounds\n", i + 1);
+ }
+
+ target_set = (current_set + 1) & 1;
+ init_set(target_set);
+
+ for (j = 0; j < num_total_tiles; j++)
+ current_permutation[j] = j;
+ drmtest_permute_array(current_permutation, num_total_tiles, exchange_uint);
+
+ copy_tiles(current_permutation);
+
+ memcpy(tmp_permutation, tile_permutation, sizeof(unsigned)*num_total_tiles);
+
+ /* accumulate the permutations */
+ for (j = 0; j < num_total_tiles; j++)
+ tile_permutation[j] = current_permutation[tmp_permutation[j]];
+
+ current_set = target_set;
+ }
+
+ fan_in_and_check();
+
+ fprintf(stderr, "num failed tiles %u, max incoherent bytes %zd\n",
+ stats.num_failed, stats.max_failed_reads*sizeof(uint32_t));
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(drm_fd);
+
+ drmtest_stop_signal_helper();
+
+ return 0;
+}
diff --git a/tests/gem_tiled_blits.c b/tests/gem_tiled_blits.c
new file mode 100644
index 00000000..86c9a886
--- /dev/null
+++ b/tests/gem_tiled_blits.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_tiled_blits.c
+ *
+ * This is a test of doing many tiled blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to catch a couple types of failure;
+ * - Fence management problems on pre-965.
+ * - A17 or L-shaped memory tiling workaround problems in acceleration.
+ *
+ * The model is to fill a collection of 1MB objects in a way that can't trip
+ * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled
+ * object. Then, copy the 1MB objects randomly between each other for a while.
+ * Finally, download their data through linear objects again and see what
+ * resulted.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static int width = 512, height = 512;
+
+static drm_intel_bo *
+create_bo(uint32_t start_val)
+{
+ drm_intel_bo *bo, *linear_bo;
+ uint32_t *linear;
+ uint32_t tiling = I915_TILING_X;
+ int ret, i;
+
+ bo = drm_intel_bo_alloc(bufmgr, "tiled bo", 1024 * 1024, 4096);
+ ret = drm_intel_bo_set_tiling(bo, &tiling, width * 4);
+ assert(ret == 0);
+ assert(tiling == I915_TILING_X);
+
+ linear_bo = drm_intel_bo_alloc(bufmgr, "linear src", 1024 * 1024, 4096);
+
+ /* Fill the BO with dwords starting at start_val */
+ drm_intel_bo_map(linear_bo, 1);
+ linear = linear_bo->virtual;
+ for (i = 0; i < 1024 * 1024 / 4; i++)
+ linear[i] = start_val++;
+ drm_intel_bo_unmap(linear_bo);
+
+ intel_copy_bo (batch, bo, linear_bo, width, height);
+
+ drm_intel_bo_unreference(linear_bo);
+
+ return bo;
+}
+
+static void
+check_bo(drm_intel_bo *bo, uint32_t start_val)
+{
+ drm_intel_bo *linear_bo;
+ uint32_t *linear;
+ int i;
+
+ linear_bo = drm_intel_bo_alloc(bufmgr, "linear dst", 1024 * 1024, 4096);
+
+ intel_copy_bo(batch, linear_bo, bo, width, height);
+
+ drm_intel_bo_map(linear_bo, 0);
+ linear = linear_bo->virtual;
+
+ for (i = 0; i < 1024 * 1024 / 4; i++) {
+ if (linear[i] != start_val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ start_val, linear[i], i * 4);
+ abort();
+ }
+ start_val++;
+ }
+ drm_intel_bo_unmap(linear_bo);
+
+ drm_intel_bo_unreference(linear_bo);
+}
+
+int main(int argc, char **argv)
+{
+ drm_intel_bo **bo;
+ uint32_t *bo_start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0) {
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ count += (count & 1) == 0;
+ }
+
+ if (count > intel_get_total_ram_mb() * 9 / 10) {
+ count = intel_get_total_ram_mb() * 9 / 10;
+ printf("not enough RAM to run test, reducing buffer count\n");
+ }
+
+ printf("Using %d 1MiB buffers\n", count);
+
+ bo = malloc(sizeof(drm_intel_bo *)*count);
+ bo_start_val = malloc(sizeof(uint32_t)*count);
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ for (i = 0; i < count; i++) {
+ bo[i] = create_bo(start);
+ bo_start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+ printf("Verifying initialisation...\n");
+ for (i = 0; i < count; i++)
+ check_bo(bo[i], bo_start_val[i]);
+
+ printf("Cyclic blits, forward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = i % count;
+ int dst = (i+1) % count;
+
+ if (src == dst)
+ continue;
+
+ intel_copy_bo(batch, bo[dst], bo[src], width, height);
+ bo_start_val[dst] = bo_start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(bo[i], bo_start_val[i]);
+
+ printf("Cyclic blits, backward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = (i+1) % count;
+ int dst = i % count;
+
+ if (src == dst)
+ continue;
+
+ intel_copy_bo(batch, bo[dst], bo[src], width, height);
+ bo_start_val[dst] = bo_start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(bo[i], bo_start_val[i]);
+
+ printf("Random blits...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (src == dst)
+ continue;
+
+ intel_copy_bo(batch, bo[dst], bo[src], width, height);
+ bo_start_val[dst] = bo_start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(bo[i], bo_start_val[i]);
+
+ for (i = 0; i < count; i++) {
+ drm_intel_bo_unreference(bo[i]);
+ bo[i] = NULL;
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_tiled_fence_blits.c b/tests/gem_tiled_fence_blits.c
new file mode 100644
index 00000000..dc654793
--- /dev/null
+++ b/tests/gem_tiled_fence_blits.c
@@ -0,0 +1,174 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+/** @file gem_tiled_fence_blits.c
+ *
+ * This is a test of doing many tiled blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to catch a couple types of failure;
+ * - Fence management problems on pre-965.
+ * - A17 or L-shaped memory tiling workaround problems in acceleration.
+ *
+ * The model is to fill a collection of 1MB objects in a way that can't trip
+ * over A6 swizzling -- upload data to a non-tiled object, blit to the tiled
+ * object. Then, copy the 1MB objects randomly between each other for a while.
+ * Finally, download their data through linear objects again and see what
+ * resulted.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static int width = 512, height = 512;
+static uint32_t linear[1024*1024/4];
+
+static drm_intel_bo *
+create_bo(int fd, uint32_t start_val)
+{
+ drm_intel_bo *bo;
+ uint32_t tiling = I915_TILING_X;
+ int ret, i;
+
+ bo = drm_intel_bo_alloc(bufmgr, "tiled bo", 1024 * 1024, 4096);
+ ret = drm_intel_bo_set_tiling(bo, &tiling, width * 4);
+ assert(ret == 0);
+ assert(tiling == I915_TILING_X);
+
+ /* Fill the BO with dwords starting at start_val */
+ for (i = 0; i < 1024 * 1024 / 4; i++)
+ linear[i] = start_val++;
+
+ gem_write(fd, bo->handle, 0, linear, sizeof(linear));
+
+ return bo;
+}
+
+static void
+check_bo(int fd, drm_intel_bo *bo, uint32_t start_val)
+{
+ int i;
+
+ gem_read(fd, bo->handle, 0, linear, sizeof(linear));
+
+ for (i = 0; i < 1024 * 1024 / 4; i++) {
+ if (linear[i] != start_val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ start_val, linear[i], i * 4);
+ abort();
+ }
+ start_val++;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ drm_intel_bo *bo[4096];
+ uint32_t bo_start_val[4096];
+ uint32_t start = 0;
+ int fd, i, count;
+
+ fd = drm_open_any();
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ if (count > intel_get_total_ram_mb() * 9 / 10) {
+ count = intel_get_total_ram_mb() * 9 / 10;
+ printf("not enough RAM to run test, reducing buffer count\n");
+ }
+ count |= 1;
+ printf("Using %d 1MiB buffers\n", count);
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ for (i = 0; i < count; i++) {
+ bo[i] = create_bo(fd, start);
+ bo_start_val[i] = start;
+
+ /*
+ printf("Creating bo %d\n", i);
+ check_bo(bo[i], bo_start_val[i]);
+ */
+
+ start += 1024 * 1024 / 4;
+ }
+
+ for (i = 0; i < count; i++) {
+ int src = count - i - 1;
+ intel_copy_bo(batch, bo[i], bo[src], width, height);
+ bo_start_val[i] = bo_start_val[src];
+ }
+
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (src == dst)
+ continue;
+
+ intel_copy_bo(batch, bo[dst], bo[src], width, height);
+ bo_start_val[dst] = bo_start_val[src];
+
+ /*
+ check_bo(bo[dst], bo_start_val[dst]);
+ printf("%d: copy bo %d to %d\n", i, src, dst);
+ */
+ }
+
+ for (i = 0; i < count; i++) {
+ /*
+ printf("check %d\n", i);
+ */
+ check_bo(fd, bo[i], bo_start_val[i]);
+
+ drm_intel_bo_unreference(bo[i]);
+ bo[i] = NULL;
+ }
+
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_tiled_partial_pwrite_pread.c b/tests/gem_tiled_partial_pwrite_pread.c
new file mode 100644
index 00000000..bd0d4e09
--- /dev/null
+++ b/tests/gem_tiled_partial_pwrite_pread.c
@@ -0,0 +1,294 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+/*
+ * Testcase: pwrite/pread consistency when touching partial cachelines
+ *
+ * Some fancy new pwrite/pread optimizations clflush in-line while
+ * reading/writing. Check whether all required clflushes happen.
+ *
+ * Unfortunately really old mesa used unaligned pread/pwrite for s/w fallback
+ * rendering, so we need to check whether this works on tiled buffers, too.
+ *
+ */
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+
+drm_intel_bo *scratch_bo;
+drm_intel_bo *staging_bo;
+drm_intel_bo *tiled_staging_bo;
+unsigned long scratch_pitch;
+#define BO_SIZE (32*4096)
+uint32_t devid;
+uint64_t mappable_gtt_limit;
+int fd;
+
+static void
+copy_bo(drm_intel_bo *src, int src_tiled,
+ drm_intel_bo *dst, int dst_tiled)
+{
+ unsigned long dst_pitch = scratch_pitch;
+ unsigned long src_pitch = scratch_pitch;
+ uint32_t cmd_bits = 0;
+
+ /* dst is tiled ... */
+ if (intel_gen(devid) >= 4 && dst_tiled) {
+ dst_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ if (intel_gen(devid) >= 4 && dst_tiled) {
+ src_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ cmd_bits);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ dst_pitch);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(BO_SIZE/scratch_pitch << 16 | 1024);
+ OUT_RELOC_FENCED(dst, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(src_pitch);
+ OUT_RELOC_FENCED(src, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+static void
+blt_bo_fill(drm_intel_bo *tmp_bo, drm_intel_bo *bo, int val)
+{
+ uint8_t *gtt_ptr;
+ int i;
+
+ drm_intel_gem_bo_map_gtt(tmp_bo);
+ gtt_ptr = tmp_bo->virtual;
+
+ for (i = 0; i < BO_SIZE; i++)
+ gtt_ptr[i] = val;
+
+ drm_intel_gem_bo_unmap_gtt(tmp_bo);
+
+ if (bo->offset < mappable_gtt_limit &&
+ (IS_G33(devid) || intel_gen(devid) >= 4))
+ drmtest_trash_aperture();
+
+ copy_bo(tmp_bo, 0, bo, 1);
+}
+
+#define MAX_BLT_SIZE 128
+#define ROUNDS 200
+int main(int argc, char **argv)
+{
+ int i, j;
+ uint8_t tmp[BO_SIZE];
+ uint8_t compare_tmp[BO_SIZE];
+ uint32_t tiling_mode = I915_TILING_X;
+
+ srandom(0xdeadbeef);
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ /* overallocate the buffers we're actually using because */
+ scratch_bo = drm_intel_bo_alloc_tiled(bufmgr, "scratch bo", 1024,
+ BO_SIZE/4096, 4,
+ &tiling_mode, &scratch_pitch, 0);
+ assert(tiling_mode == I915_TILING_X);
+ assert(scratch_pitch == 4096);
+ staging_bo = drm_intel_bo_alloc(bufmgr, "staging bo", BO_SIZE, 4096);
+ tiled_staging_bo = drm_intel_bo_alloc_tiled(bufmgr, "scratch bo", 1024,
+ BO_SIZE/4096, 4,
+ &tiling_mode,
+ &scratch_pitch, 0);
+
+ drmtest_init_aperture_trashers(bufmgr);
+ mappable_gtt_limit = gem_mappable_aperture_size();
+
+ printf("checking partial reads\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
+ for (j = 0; j < len; j++) {
+ if (tmp[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ start + j, tmp[j], val);
+ exit(1);
+ }
+ }
+
+ drmtest_progress("partial reads test: ", i, ROUNDS);
+ }
+
+ printf("checking partial writes\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ memset(tmp, i + 63, BO_SIZE);
+
+ drm_intel_bo_subdata(scratch_bo, start, len, tmp);
+
+ copy_bo(scratch_bo, 1, tiled_staging_bo, 1);
+ drm_intel_bo_get_subdata(tiled_staging_bo, 0, BO_SIZE,
+ compare_tmp);
+
+ for (j = 0; j < start; j++) {
+ if (compare_tmp[j] != val) {
+ printf("amismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ for (; j < start + len; j++) {
+ if (compare_tmp[j] != tmp[0]) {
+ printf("bmismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], i);
+ exit(1);
+ }
+ }
+ for (; j < BO_SIZE; j++) {
+ if (compare_tmp[j] != val) {
+ printf("cmismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ drm_intel_gem_bo_unmap_gtt(staging_bo);
+
+ drmtest_progress("partial writes test: ", i, ROUNDS);
+ }
+
+ printf("checking partial writes after partial reads\n");
+ for (i = 0; i < ROUNDS; i++) {
+ int start, len;
+ int val = i % 256;
+
+ blt_bo_fill(staging_bo, scratch_bo, i);
+
+ /* partial read */
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ drm_intel_bo_get_subdata(scratch_bo, start, len, tmp);
+ for (j = 0; j < len; j++) {
+ if (tmp[j] != val) {
+ printf("mismatch in read at %i, got: %i, expected: %i\n",
+ start + j, tmp[j], val);
+ exit(1);
+ }
+ }
+
+ /* Change contents through gtt to make the pread cachelines
+ * stale. */
+ val = (i + 17) % 256;
+ blt_bo_fill(staging_bo, scratch_bo, val);
+
+ /* partial write */
+ start = random() % BO_SIZE;
+ len = random() % (BO_SIZE-start) + 1;
+
+ memset(tmp, i + 63, BO_SIZE);
+
+ drm_intel_bo_subdata(scratch_bo, start, len, tmp);
+
+ copy_bo(scratch_bo, 1, tiled_staging_bo, 1);
+ drm_intel_bo_get_subdata(tiled_staging_bo, 0, BO_SIZE,
+ compare_tmp);
+
+ for (j = 0; j < start; j++) {
+ if (compare_tmp[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ for (; j < start + len; j++) {
+ if (compare_tmp[j] != tmp[0]) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], tmp[0]);
+ exit(1);
+ }
+ }
+ for (; j < BO_SIZE; j++) {
+ if (compare_tmp[j] != val) {
+ printf("mismatch at %i, got: %i, expected: %i\n",
+ j, tmp[j], val);
+ exit(1);
+ }
+ }
+ drm_intel_gem_bo_unmap_gtt(staging_bo);
+
+ drmtest_progress("partial read/writes test: ", i, ROUNDS);
+ }
+
+ drmtest_cleanup_aperture_trashers();
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_tiled_pread.c b/tests/gem_tiled_pread.c
new file mode 100644
index 00000000..189affce
--- /dev/null
+++ b/tests/gem_tiled_pread.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_tiled_pread.c
+ *
+ * This is a test of pread's behavior on tiled objects with respect to the
+ * reported swizzling value.
+ *
+ * The goal is to exercise the slow_bit17_copy path for reading on bit17
+ * machines, but will also be useful for catching swizzling value bugs on
+ * other systems.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+static uint32_t linear[WIDTH * HEIGHT];
+
+#define PAGE_SIZE 4096
+
+static int tile_width;
+static int tile_height;
+static int tile_size;
+
+static void
+gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle)
+{
+ struct drm_i915_gem_get_tiling get_tiling;
+ int ret;
+
+ memset(&get_tiling, 0, sizeof(get_tiling));
+ get_tiling.handle = handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
+ assert(ret == 0);
+
+ *tiling = get_tiling.tiling_mode;
+ *swizzle = get_tiling.swizzle_mode;
+}
+
+static uint32_t
+create_bo(int fd)
+{
+ uint32_t handle;
+ uint32_t *data;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+ gem_set_tiling(fd, handle, I915_TILING_X, WIDTH * sizeof(uint32_t));
+
+ /* Fill the BO with dwords starting at start_val */
+ data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ data[i] = i;
+ munmap(data, sizeof(linear));
+
+ return handle;
+}
+
+static int
+swizzle_bit(int bit, int offset)
+{
+ return (offset & (1 << bit)) >> (bit - 6);
+}
+
+/* Translate from a swizzled offset in the tiled buffer to the corresponding
+ * value from the original linear buffer.
+ */
+static uint32_t
+calculate_expected(int offset)
+{
+ int tile_off = offset & (tile_size - 1);
+ int tile_base = offset & -tile_size;
+ int tile_index = tile_base / tile_size;
+ int tiles_per_row = 4*WIDTH / tile_width;
+
+ /* base x,y values from the tile (page) index. */
+ int base_y = tile_index / tiles_per_row * tile_height;
+ int base_x = tile_index % tiles_per_row * (tile_width/4);
+
+ /* x, y offsets within the tile */
+ int tile_y = tile_off / tile_width;
+ int tile_x = (tile_off % tile_width) / 4;
+
+ /* printf("%3d, %3d, %3d,%3d\n", base_x, base_y, tile_x, tile_y); */
+ return (base_y + tile_y) * WIDTH + base_x + tile_x;
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ int i, iter = 100;
+ uint32_t tiling, swizzle;
+ uint32_t handle;
+ uint32_t devid;
+
+ fd = drm_open_any();
+
+ handle = create_bo(fd);
+ gem_get_tiling(fd, handle, &tiling, &swizzle);
+
+ devid = intel_get_drm_devid(fd);
+
+ if (IS_GEN2(devid)) {
+ tile_height = 16;
+ tile_width = 128;
+ tile_size = 2048;
+ } else {
+ tile_height = 8;
+ tile_width = 512;
+ tile_size = PAGE_SIZE;
+ }
+
+ /* Read a bunch of random subsets of the data and check that they come
+ * out right.
+ */
+ for (i = 0; i < iter; i++) {
+ int size = WIDTH * HEIGHT * 4;
+ int offset = (random() % size) & ~3;
+ int len = (random() % size) & ~3;
+ int j;
+
+ if (len == 0)
+ len = 4;
+
+ if (offset + len > size)
+ len = size - offset;
+
+ if (i == 0) {
+ offset = 0;
+ len = size;
+ }
+
+ gem_read(fd, handle, offset, linear, len);
+
+ /* Translate from offsets in the read buffer to the swizzled
+ * address that it corresponds to. This is the opposite of
+ * what Mesa does (calculate offset to be read given the linear
+ * offset it's looking for).
+ */
+ for (j = offset; j < offset + len; j += 4) {
+ uint32_t expected_val, found_val;
+ int swizzled_offset;
+ const char *swizzle_str;
+
+ switch (swizzle) {
+ case I915_BIT_6_SWIZZLE_NONE:
+ swizzled_offset = j;
+ swizzle_str = "none";
+ break;
+ case I915_BIT_6_SWIZZLE_9:
+ swizzled_offset = j ^
+ swizzle_bit(9, j);
+ swizzle_str = "bit9";
+ break;
+ case I915_BIT_6_SWIZZLE_9_10:
+ swizzled_offset = j ^
+ swizzle_bit(9, j) ^
+ swizzle_bit(10, j);
+ swizzle_str = "bit9^10";
+ break;
+ case I915_BIT_6_SWIZZLE_9_11:
+ swizzled_offset = j ^
+ swizzle_bit(9, j) ^
+ swizzle_bit(11, j);
+ swizzle_str = "bit9^11";
+ break;
+ case I915_BIT_6_SWIZZLE_9_10_11:
+ swizzled_offset = j ^
+ swizzle_bit(9, j) ^
+ swizzle_bit(10, j) ^
+ swizzle_bit(11, j);
+ swizzle_str = "bit9^10^11";
+ break;
+ default:
+ fprintf(stderr, "Bad swizzle bits; %d\n",
+ swizzle);
+ abort();
+ }
+ expected_val = calculate_expected(swizzled_offset);
+ found_val = linear[(j - offset) / 4];
+ if (expected_val != found_val) {
+ fprintf(stderr,
+ "Bad read [%d]: %d instead of %d at 0x%08x "
+ "for read from 0x%08x to 0x%08x, swizzle=%s\n",
+ i, found_val, expected_val, j,
+ offset, offset + len,
+ swizzle_str);
+ abort();
+ }
+ }
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_tiled_pread_pwrite.c b/tests/gem_tiled_pread_pwrite.c
new file mode 100644
index 00000000..e2225c5e
--- /dev/null
+++ b/tests/gem_tiled_pread_pwrite.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2009 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 <eric@anholt.net>
+ *
+ */
+
+/** @file gem_tiled_pread_pwrite.c
+ *
+ * This is a test of pread's behavior on tiled objects with respect to the
+ * reported swizzling value.
+ *
+ * The goal is to exercise the slow_bit17_copy path for reading on bit17
+ * machines, but will also be useful for catching swizzling value bugs on
+ * other systems.
+ */
+
+/*
+ * Testcase: Test swizzling by testing pwrite does the invers of pread
+ *
+ * Together with the explicit pread testcase, this should cover our swizzle
+ * handling.
+ *
+ * Note that this test will use swap in an effort to test all of ram.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+static uint32_t linear[WIDTH * HEIGHT];
+static uint32_t current_tiling_mode;
+
+#define PAGE_SIZE 4096
+
+static void
+gem_get_tiling(int fd, uint32_t handle, uint32_t *tiling, uint32_t *swizzle)
+{
+ struct drm_i915_gem_get_tiling get_tiling;
+ int ret;
+
+ memset(&get_tiling, 0, sizeof(get_tiling));
+ get_tiling.handle = handle;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling);
+ assert(ret == 0);
+
+ *tiling = get_tiling.tiling_mode;
+ *swizzle = get_tiling.swizzle_mode;
+}
+
+static uint32_t
+create_bo_and_fill(int fd)
+{
+ uint32_t handle;
+ uint32_t *data;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+ gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t));
+
+ /* Fill the BO with dwords starting at start_val */
+ data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ data[i] = i;
+ munmap(data, sizeof(linear));
+
+ return handle;
+}
+
+static uint32_t
+create_bo(int fd)
+{
+ uint32_t handle;
+
+ handle = gem_create(fd, sizeof(linear));
+ gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t));
+
+ return handle;
+}
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ uint32_t *data;
+ int i, j;
+ uint32_t tiling, swizzle;
+ uint32_t handle, handle_target;
+ int count;
+
+
+ fd = drm_open_any();
+ count = intel_get_total_ram_mb() * 9 / 10;
+
+ for (i = 0; i < count/2; i++) {
+ current_tiling_mode = I915_TILING_X;
+
+ handle = create_bo_and_fill(fd);
+ gem_get_tiling(fd, handle, &tiling, &swizzle);
+
+ gem_read(fd, handle, 0, linear, sizeof(linear));
+
+ handle_target = create_bo(fd);
+ gem_write(fd, handle_target, 0, linear, sizeof(linear));
+
+ /* Check the target bo's contents. */
+ data = gem_mmap(fd, handle_target, sizeof(linear), PROT_READ | PROT_WRITE);
+ for (j = 0; j < WIDTH*HEIGHT; j++)
+ if (data[j] != j) {
+ fprintf(stderr, "mismatch at %i: %i\n",
+ j, data[j]);
+ exit(1);
+ }
+ munmap(data, sizeof(linear));
+
+ /* Leak both bos so that we use all of system mem! */
+
+ drmtest_progress("gem_tiled_pread_pwrite: ", i, count/2);
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_tiled_swapping.c b/tests/gem_tiled_swapping.c
new file mode 100644
index 00000000..d1484f0e
--- /dev/null
+++ b/tests/gem_tiled_swapping.c
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/** @file gem_tiled_pread_pwrite.c
+ *
+ * This is a test of pread's behavior on tiled objects with respect to the
+ * reported swizzling value.
+ *
+ * The goal is to exercise the slow_bit17_copy path for reading on bit17
+ * machines, but will also be useful for catching swizzling value bugs on
+ * other systems.
+ */
+
+/*
+ * Testcase: Exercise swizzle code for swapping
+ *
+ * The swizzle checks in the swapin path are at a different place than the ones
+ * for pread/pwrite, so we need to check them separately.
+ *
+ * This test obviously needs swap present (and exits if none is detected).
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+static uint32_t linear[WIDTH * HEIGHT];
+static uint32_t current_tiling_mode;
+
+#define PAGE_SIZE 4096
+
+static uint32_t
+create_bo_and_fill(int fd)
+{
+ uint32_t handle;
+ uint32_t *data;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+ gem_set_tiling(fd, handle, current_tiling_mode, WIDTH * sizeof(uint32_t));
+
+ /* Fill the BO with dwords starting at start_val */
+ data = gem_mmap(fd, handle, sizeof(linear), PROT_READ | PROT_WRITE);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ data[i] = i;
+ munmap(data, sizeof(linear));
+
+ return handle;
+}
+
+uint32_t *bo_handles;
+int *idx_arr;
+
+int
+main(int argc, char **argv)
+{
+ int fd;
+ uint32_t *data;
+ int i, j;
+ int count;
+ current_tiling_mode = I915_TILING_X;
+
+ fd = drm_open_any();
+ /* need slightly more than total ram */
+ count = intel_get_total_ram_mb() * 11 / 10;
+ bo_handles = calloc(count, sizeof(uint32_t));
+ assert(bo_handles);
+
+ idx_arr = calloc(count, sizeof(int));
+ assert(idx_arr);
+
+ if (intel_get_total_swap_mb() == 0) {
+ printf("no swap detected\n");
+ return 77;
+ }
+
+ if (intel_get_total_ram_mb() / 4 > intel_get_total_swap_mb()) {
+ printf("not enough swap detected\n");
+ return 77;
+ }
+
+ for (i = 0; i < count; i++)
+ bo_handles[i] = create_bo_and_fill(fd);
+
+ for (i = 0; i < count; i++)
+ idx_arr[i] = i;
+
+ drmtest_permute_array(idx_arr, count,
+ drmtest_exchange_int);
+
+ for (i = 0; i < count/2; i++) {
+ /* Check the target bo's contents. */
+ data = gem_mmap(fd, bo_handles[idx_arr[i]],
+ sizeof(linear), PROT_READ | PROT_WRITE);
+ for (j = 0; j < WIDTH*HEIGHT; j++)
+ if (data[j] != j) {
+ fprintf(stderr, "mismatch at %i: %i\n",
+ j, data[j]);
+ exit(1);
+ }
+ munmap(data, sizeof(linear));
+ }
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_unfence_active_buffers.c b/tests/gem_unfence_active_buffers.c
new file mode 100644
index 00000000..bffc62ea
--- /dev/null
+++ b/tests/gem_unfence_active_buffers.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/** @file gem_unfence_active_buffers.c
+ *
+ * Testcase: Check for use-after free in the fence stealing code
+ *
+ * If we're stealing the fence of a active object where the active list is the
+ * only thing holding a reference, we need to be careful not to access the old
+ * object we're stealing the fence from after that reference has been dropped by
+ * retire_requests.
+ *
+ * Note that this needs slab poisoning enabled in the kernel to reliably hit the
+ * problem - the race window is too small.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <stdbool.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+uint32_t devid;
+
+#define TEST_SIZE (1024*1024)
+#define TEST_STRIDE (4*1024)
+
+uint32_t data[TEST_SIZE/4];
+
+int main(int argc, char **argv)
+{
+ int i, ret, fd, num_fences;
+ drm_intel_bo *busy_bo, *test_bo;
+ uint32_t tiling = I915_TILING_X;
+
+ for (i = 0; i < 1024*256; i++)
+ data[i] = i;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ devid = intel_get_drm_devid(fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ printf("filling ring\n");
+ busy_bo = drm_intel_bo_alloc(bufmgr, "busy bo bo", 16*1024*1024, 4096);
+
+ for (i = 0; i < 250; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 2*1024*4);
+ OUT_BATCH(0 << 16 | 1024);
+ OUT_BATCH((2048) << 16 | (2048));
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(2*1024*4);
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+ }
+ intel_batchbuffer_flush(batch);
+
+ num_fences = gem_available_fences(fd);
+ printf("creating havoc on %i fences\n", num_fences);
+
+ for (i = 0; i < num_fences*2; i++) {
+ test_bo = drm_intel_bo_alloc(bufmgr, "test_bo",
+ TEST_SIZE, 4096);
+ ret = drm_intel_bo_set_tiling(test_bo, &tiling, TEST_STRIDE);
+ assert(ret == 0);
+
+ drm_intel_bo_disable_reuse(test_bo);
+
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ TEST_STRIDE);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH((1) << 16 | (1));
+ OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(TEST_STRIDE);
+ OUT_RELOC_FENCED(test_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+ intel_batchbuffer_flush(batch);
+ printf("test bo offset: %#lx\n", test_bo->offset);
+
+ drm_intel_bo_unreference(test_bo);
+ }
+
+ /* launch a few batchs to ensure the damaged slab objects get reused. */
+ for (i = 0; i < 10; i++) {
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 2*1024*4);
+ OUT_BATCH(0 << 16 | 1024);
+ OUT_BATCH((1) << 16 | (1));
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(0 << 16 | 0);
+ OUT_BATCH(2*1024*4);
+ OUT_RELOC_FENCED(busy_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ if (IS_GEN6(devid) || IS_GEN7(devid)) {
+ BEGIN_BATCH(3);
+ OUT_BATCH(XY_SETUP_CLIP_BLT_CMD);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+ }
+ }
+ intel_batchbuffer_flush(batch);
+
+ return 0;
+}
diff --git a/tests/gem_unref_active_buffers.c b/tests/gem_unref_active_buffers.c
new file mode 100644
index 00000000..aa29c1de
--- /dev/null
+++ b/tests/gem_unref_active_buffers.c
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/*
+ * Testcase: Unreferencing of active buffers
+ *
+ * Execs buffers and immediately unreferences them, hence the kernel active list
+ * will be the last one to hold a reference on them. Usually libdrm bo caching
+ * prevents that by keeping another reference.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+static drm_intel_bufmgr *bufmgr;
+struct intel_batchbuffer *batch;
+static drm_intel_bo *load_bo;
+
+int main(int argc, char **argv)
+{
+ int fd, i;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ if (!bufmgr) {
+ fprintf(stderr, "failed to init libdrm\n");
+ exit(-1);
+ }
+ /* don't enable buffer reuse!! */
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+ assert(batch);
+
+ /* put some load onto the gpu to keep the light buffers active for long
+ * enough */
+ for (i = 0; i < 1000; i++) {
+ load_bo = drm_intel_bo_alloc(bufmgr, "target bo", 1024*4096, 4096);
+ if (!load_bo) {
+ fprintf(stderr, "failed to alloc target buffer\n");
+ exit(-1);
+ }
+
+ BEGIN_BATCH(8);
+ OUT_BATCH(XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ 4096);
+ OUT_BATCH(0); /* dst x1,y1 */
+ OUT_BATCH((1024 << 16) | 512);
+ OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH((0 << 16) | 512); /* src x1, y1 */
+ OUT_BATCH(4096);
+ OUT_RELOC(load_bo, I915_GEM_DOMAIN_RENDER, 0, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+
+ drm_intel_bo_disable_reuse(load_bo);
+ drm_intel_bo_unreference(load_bo);
+ }
+
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gem_vmap_blits.c b/tests/gem_vmap_blits.c
new file mode 100644
index 00000000..b8868214
--- /dev/null
+++ b/tests/gem_vmap_blits.c
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gem_vmap_blits.c
+ *
+ * This is a test of doing many blits using a mixture of normal system pages
+ * and uncached linear buffers, with a working set larger than the
+ * aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_bufmgr.h"
+#include "intel_batchbuffer.h"
+#include "intel_gpu_tools.h"
+
+#if !defined(I915_PARAM_HAS_VMAP)
+#warning No vmap support in drm, skipping
+int main(int argc, char **argv)
+{
+ fprintf(stderr, "No vmap support in drm.\n");
+ return 77;
+}
+#else
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static uint32_t gem_vmap(int fd, void *ptr, int size, int read_only)
+{
+ struct drm_i915_gem_vmap vmap;
+
+ vmap.user_ptr = (uintptr_t)ptr;
+ vmap.user_size = size;
+ vmap.flags = 0;
+ if (read_only)
+ vmap.flags |= I915_VMAP_READ_ONLY;
+
+ if (drmIoctl(fd, DRM_IOCTL_I915_GEM_VMAP, &vmap))
+ return 0;
+
+ return vmap.handle;
+}
+
+
+static void gem_vmap_sync(int fd, uint32_t handle)
+{
+ gem_set_domain(fd, handle, I915_GEM_DOMAIN_CPU, I915_GEM_DOMAIN_CPU);
+}
+
+static void
+gem_read(int fd, uint32_t handle, int offset, int size, void *buf)
+{
+ struct drm_i915_gem_pread pread;
+ int ret;
+
+ pread.handle = handle;
+ pread.offset = offset;
+ pread.size = size;
+ pread.data_ptr = (uintptr_t)buf;
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_PREAD, &pread);
+ assert(ret == 0);
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[10];
+ struct drm_i915_gem_relocation_entry reloc[2];
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ batch[0] = XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB;
+ batch[1] = (3 << 24) | /* 32 bits */
+ (0xcc << 16) | /* copy ROP */
+ WIDTH*4;
+ batch[2] = 0; /* dst x1,y1 */
+ batch[3] = (HEIGHT << 16) | WIDTH; /* dst x2,y2 */
+ batch[4] = 0; /* dst reloc */
+ batch[5] = 0; /* src x1,y1 */
+ batch[6] = WIDTH*4;
+ batch[7] = 0; /* src reloc */
+ batch[8] = MI_BATCH_BUFFER_END;
+ batch[9] = MI_NOOP;
+
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, sizeof(batch));
+
+ reloc[0].target_handle = dst;
+ reloc[0].delta = 0;
+ reloc[0].offset = 4 * sizeof(batch[0]);
+ reloc[0].presumed_offset = 0;
+ reloc[0].read_domains = I915_GEM_DOMAIN_RENDER;;
+ reloc[0].write_domain = I915_GEM_DOMAIN_RENDER;
+
+ reloc[1].target_handle = src;
+ reloc[1].delta = 0;
+ reloc[1].offset = 7 * sizeof(batch[0]);
+ reloc[1].presumed_offset = 0;
+ reloc[1].read_domains = I915_GEM_DOMAIN_RENDER;;
+ reloc[1].write_domain = 0;
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = sizeof(batch);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = HAS_BLT_RING(intel_get_drm_devid(fd)) ? I915_EXEC_BLT : 0;
+ exec.rsvd1 = exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_vmap(int fd, uint32_t val, uint32_t *ptr)
+{
+ uint32_t handle;
+ int i;
+
+ handle = gem_vmap(fd, ptr, sizeof(linear), 0);
+
+ /* Fill the BO with dwords starting at val */
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ ptr[i] = val++;
+
+ return handle;
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+ uint32_t handle;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+
+ /* Fill the BO with dwords starting at val */
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ linear[i] = val++;
+ gem_write(fd, handle, 0, linear, sizeof(linear));
+
+ return handle;
+}
+
+static void
+check_cpu(uint32_t *ptr, uint32_t val)
+{
+ int i;
+
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (ptr[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, ptr[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+}
+
+static void
+check_gpu(int fd, uint32_t handle, uint32_t val)
+{
+ gem_read(fd, handle, 0, linear, sizeof(linear));
+ check_cpu(linear, val);
+}
+
+static int has_vmap(int fd)
+{
+ drm_i915_getparam_t gp;
+ int i;
+
+ gp.param = I915_PARAM_HAS_VMAP;
+ gp.value = &i;
+
+ return drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == 0 && i > 0;
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *memory;
+ uint32_t *cpu, *cpu_val;
+ uint32_t *gpu, *gpu_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!has_vmap(fd)) {
+ fprintf(stderr, "No vmap support, ignoring.\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 4;
+ printf("Using 2x%d 1MiB buffers\n", count);
+
+ memory = malloc(count*sizeof(linear));
+ if (memory == NULL) {
+ fprintf(stderr, "Unable to allocate %lld bytes\n",
+ (long long)count*sizeof(linear));
+ return 1;
+ }
+
+ gpu = malloc(sizeof(uint32_t)*count*4);
+ gpu_val = gpu + count;
+ cpu = gpu_val + count;
+ cpu_val = cpu + count;
+
+ for (i = 0; i < count; i++) {
+ gpu[i] = create_bo(fd, start);
+ gpu_val[i] = start;
+ start += WIDTH*HEIGHT;
+ }
+
+ for (i = 0; i < count; i++) {
+ cpu[i] = create_vmap(fd, start, memory+i*WIDTH*HEIGHT);
+ cpu_val[i] = start;
+ start += WIDTH*HEIGHT;;
+ }
+
+ printf("Verifying initialisation...\n");
+ for (i = 0; i < count; i++) {
+ check_gpu(fd, gpu[i], gpu_val[i]);
+ check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+ }
+
+ printf("Cyclic blits cpu->gpu, forward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, gpu[dst], cpu[src]);
+ gpu_val[dst] = cpu_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_gpu(fd, gpu[i], gpu_val[i]);
+
+ printf("Cyclic blits gpu->cpu, backward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, cpu[dst], gpu[src]);
+ cpu_val[dst] = gpu_val[src];
+ }
+ for (i = 0; i < count; i++) {
+ gem_vmap_sync(fd, cpu[i]);
+ check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+ }
+
+ printf("Random blits...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (random() & 1) {
+ copy(fd, gpu[dst], cpu[src]);
+ gpu_val[dst] = cpu_val[src];
+ } else {
+ copy(fd, cpu[dst], gpu[src]);
+ cpu_val[dst] = gpu_val[src];
+ }
+ }
+ for (i = 0; i < count; i++) {
+ check_gpu(fd, gpu[i], gpu_val[i]);
+ gem_vmap_sync(fd, cpu[i]);
+ check_cpu(memory+i*WIDTH*HEIGHT, cpu_val[i]);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/tests/gem_wait_render_timeout.c b/tests/gem_wait_render_timeout.c
new file mode 100644
index 00000000..c321d36c
--- /dev/null
+++ b/tests/gem_wait_render_timeout.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include "drm.h"
+#include "rendercopy.h"
+
+#define MSEC_PER_SEC 1000L
+#define USEC_PER_MSEC 1000L
+#define NSEC_PER_USEC 1000L
+#define NSEC_PER_MSEC 1000000L
+#define USEC_PER_SEC 1000000L
+#define NSEC_PER_SEC 1000000000L
+
+#define ENOUGH_WORK_IN_SECONDS 2
+#define BUF_SIZE (8<<20)
+#define BUF_PAGES ((8<<20)>>12)
+drm_intel_bo *dst, *dst2;
+
+/* returns time diff in milliseconds */
+static int64_t
+do_time_diff(struct timespec *end, struct timespec *start)
+{
+ int64_t ret;
+ ret = (MSEC_PER_SEC * difftime(end->tv_sec, start->tv_sec)) +
+ ((end->tv_nsec/NSEC_PER_MSEC) - (start->tv_nsec/NSEC_PER_MSEC));
+ return ret;
+}
+
+/* to avoid stupid depencies on libdrm, copy&paste */
+struct local_drm_i915_gem_wait {
+ /** Handle of BO we shall wait on */
+ __u32 bo_handle;
+ __u32 flags;
+ /** Number of nanoseconds to wait, Returns time remaining. */
+ __u64 timeout_ns;
+};
+
+# define WAIT_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2c, struct local_drm_i915_gem_wait)
+
+static int
+gem_bo_wait_timeout(int fd, uint32_t handle, uint64_t *timeout_ns)
+{
+ struct local_drm_i915_gem_wait wait;
+ int ret;
+
+ assert(timeout_ns);
+
+ wait.bo_handle = handle;
+ wait.timeout_ns = *timeout_ns;
+ wait.flags = 0;
+ ret = drmIoctl(fd, WAIT_IOCTL, &wait);
+ *timeout_ns = wait.timeout_ns;
+
+ return ret ? -errno : 0;
+}
+
+static bool
+gem_bo_busy(int fd, uint32_t handle)
+{
+ struct drm_i915_gem_busy busy;
+
+ busy.handle = handle;
+ do_or_die(drmIoctl(fd, DRM_IOCTL_I915_GEM_BUSY, &busy));
+
+ return !!busy.busy;
+}
+
+static void blt_color_fill(struct intel_batchbuffer *batch,
+ drm_intel_bo *buf,
+ const unsigned int pages)
+{
+ const unsigned short height = pages/4;
+ const unsigned short width = 4096;
+ BEGIN_BATCH(5);
+ OUT_BATCH(COLOR_BLT_CMD |
+ COLOR_BLT_WRITE_ALPHA |
+ COLOR_BLT_WRITE_RGB);
+ OUT_BATCH((3 << 24) | /* 32 Bit Color */
+ 0xF0 | /* Raster OP copy background register */
+ 0); /* Dest pitch is 0 */
+ OUT_BATCH(width << 16 |
+ height);
+ OUT_RELOC(buf, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0);
+ OUT_BATCH(rand()); /* random pattern */
+ ADVANCE_BATCH();
+}
+
+int main(int argc, char **argv)
+{
+ drm_intel_bufmgr *bufmgr;
+ struct intel_batchbuffer *batch;
+ uint64_t timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
+ int fd, ret;
+ const bool do_signals = true; /* signals will seem to make the operation
+ * use less process CPU time */
+ bool done = false;
+ int i, iter = 1;
+
+ fd = drm_open_any();
+
+ bufmgr = drm_intel_bufmgr_gem_init(fd, 4096);
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+ batch = intel_batchbuffer_alloc(bufmgr, intel_get_drm_devid(fd));
+
+ dst = drm_intel_bo_alloc(bufmgr, "dst", BUF_SIZE, 4096);
+ dst2 = drm_intel_bo_alloc(bufmgr, "dst2", BUF_SIZE, 4096);
+
+ if (gem_bo_wait_timeout(fd, dst->handle, &timeout) == -EINVAL) {
+ printf("kernel doesn't support wait_timeout, skipping test\n");
+ return -77;
+ }
+ timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
+
+ /* Figure out a rough number of fills required to consume 1 second of
+ * GPU work.
+ */
+ do {
+ struct timespec start, end;
+ long diff;
+
+#ifndef CLOCK_MONOTONIC_RAW
+#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+
+ assert(clock_gettime(CLOCK_MONOTONIC_RAW, &start) == 0);
+ for (i = 0; i < iter; i++)
+ blt_color_fill(batch, dst, BUF_PAGES);
+ intel_batchbuffer_flush(batch);
+ drm_intel_bo_wait_rendering(dst);
+ assert(clock_gettime(CLOCK_MONOTONIC_RAW, &end) == 0);
+
+ diff = do_time_diff(&end, &start);
+ assert(diff >= 0);
+
+ if ((diff / MSEC_PER_SEC) > ENOUGH_WORK_IN_SECONDS)
+ done = true;
+ else
+ iter <<= 1;
+ } while (!done && iter < 1000000);
+
+ assert(iter < 1000000);
+
+ printf("%d iters is enough work\n", iter);
+ gem_quiescent_gpu(fd);
+ if (do_signals)
+ drmtest_fork_signal_helper();
+
+ /* We should be able to do half as much work in the same amount of time,
+ * but because we might schedule almost twice as much as required, we
+ * might accidentally time out. Hence add some fudge. */
+ for (i = 0; i < iter/3; i++)
+ blt_color_fill(batch, dst2, BUF_PAGES);
+
+ intel_batchbuffer_flush(batch);
+ assert(gem_bo_busy(fd, dst2->handle) == true);
+
+ ret = gem_bo_wait_timeout(fd, dst2->handle, &timeout);
+ if (ret) {
+ fprintf(stderr, "Timed wait failed %s\n", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ assert(gem_bo_busy(fd, dst2->handle) == false);
+ assert(timeout != 0);
+ if (timeout == (ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC))
+ printf("Buffer was already done!\n");
+ else {
+ printf("Finished with %lu time remaining\n", timeout);
+ }
+
+ /* check that polling with timeout=0 works. */
+ timeout = 0;
+ assert(gem_bo_wait_timeout(fd, dst2->handle, &timeout) == 0);
+ assert(timeout == 0);
+
+ /* Now check that we correctly time out, twice the auto-tune load should
+ * be good enough. */
+ timeout = ENOUGH_WORK_IN_SECONDS * NSEC_PER_SEC;
+ for (i = 0; i < iter*2; i++)
+ blt_color_fill(batch, dst2, BUF_PAGES);
+
+ intel_batchbuffer_flush(batch);
+
+ ret = gem_bo_wait_timeout(fd, dst2->handle, &timeout);
+ assert(ret == -ETIME);
+ assert(timeout == 0);
+ assert(gem_bo_busy(fd, dst2->handle) == true);
+
+ /* check that polling with timeout=0 works. */
+ timeout = 0;
+ assert(gem_bo_wait_timeout(fd, dst2->handle, &timeout) == -ETIME);
+ assert(timeout == 0);
+
+
+ if (do_signals)
+ drmtest_stop_signal_helper();
+ drm_intel_bo_unreference(dst2);
+ drm_intel_bo_unreference(dst);
+ intel_batchbuffer_free(batch);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(fd);
+
+ return 0;
+}
diff --git a/tests/gen3_mixed_blits.c b/tests/gen3_mixed_blits.c
new file mode 100644
index 00000000..5bb6d868
--- /dev/null
+++ b/tests/gen3_mixed_blits.c
@@ -0,0 +1,541 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gen3_linear_render_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#include "i915_reg.h"
+#include "i915_3d.h"
+
+#define WIDTH (512)
+#define HEIGHT (512)
+
+static inline uint32_t pack_float(float f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+ u.f = f;
+ return u.dw;
+}
+
+static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+ uint32_t offset,
+ uint32_t handle,
+ uint32_t read_domain,
+ uint32_t write_domain)
+{
+ reloc->target_handle = handle;
+ reloc->delta = 0;
+ reloc->offset = offset * sizeof(uint32_t);
+ reloc->presumed_offset = 0;
+ reloc->read_domains = read_domain;
+ reloc->write_domain = write_domain;
+
+ return reloc->presumed_offset + reloc->delta;
+}
+
+static void
+render_copy(int fd,
+ uint32_t dst, int dst_tiling,
+ uint32_t src, int src_tiling,
+ int use_fence)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ uint32_t tiling_bits;
+ int ret;
+
+ /* invariant state */
+ *b++ = (_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0);
+ *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR |
+ (BLENDFACT_ONE << IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR |
+ (BLENDFACT_ZERO << IAB_DST_FACTOR_SHIFT));
+ *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_SPEC_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_Z_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB(0, 0) |
+ CSB_TCB(1, 1) |
+ CSB_TCB(2, 2) |
+ CSB_TCB(3, 3) |
+ CSB_TCB(4, 4) |
+ CSB_TCB(5, 5) |
+ CSB_TCB(6, 6) |
+ CSB_TCB(7, 7));
+ *b++ = (_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) |
+ ENABLE_TEXKILL_3D_4D |
+ TEXKILL_4D);
+ *b++ = (_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff));
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2);
+ *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */
+ *b++ = ((1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY);
+ *b++ = (0x00000000); /* Stencil. */
+ *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD);
+ *b++ = (0);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE);
+ *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */
+ *b++ = (0);
+ *b++ = (_3DSTATE_STIPPLE);
+ *b++ = (0x00000000);
+ *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0);
+
+ /* samler state */
+ if (use_fence) {
+ tiling_bits = MS3_USE_FENCE_REGS;
+ } else {
+ tiling_bits = 0;
+ if (src_tiling != I915_TILING_NONE)
+ tiling_bits = MS3_TILED_SURFACE;
+ if (src_tiling == I915_TILING_Y)
+ tiling_bits |= MS3_TILE_WALK;
+ }
+
+#define TEX_COUNT 1
+ *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++;
+ *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | tiling_bits |
+ (HEIGHT - 1) << MS3_HEIGHT_SHIFT |
+ (WIDTH - 1) << MS3_WIDTH_SHIFT);
+ *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT);
+
+ *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT |
+ TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT |
+ 0 << SS3_TEXTUREMAP_INDEX_SHIFT);
+ *b++ = (0x00000000);
+
+ /* render target state */
+ if (use_fence) {
+ tiling_bits = BUF_3D_USE_FENCE;
+ } else {
+ tiling_bits = 0;
+ if (dst_tiling != I915_TILING_NONE)
+ tiling_bits = BUF_3D_TILED_SURFACE;
+ if (dst_tiling == I915_TILING_Y)
+ tiling_bits |= BUF_3D_TILE_WALK_Y;
+ }
+ *b++ = (_3DSTATE_BUF_INFO_CMD);
+ *b++ = (BUF_3D_ID_COLOR_BACK | tiling_bits | WIDTH*4);
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ b++;
+
+ *b++ = (_3DSTATE_DST_BUF_VARS_CMD);
+ *b++ = (COLR_BUF_ARGB8888 |
+ DSTORG_HORT_BIAS(0x8) |
+ DSTORG_VERT_BIAS(0x8));
+
+ /* draw rect is unconditional */
+ *b++ = (_3DSTATE_DRAW_RECT_CMD);
+ *b++ = (0x00000000);
+ *b++ = (0x00000000); /* ymin, xmin */
+ *b++ = (DRAW_YMAX(HEIGHT - 1) |
+ DRAW_XMAX(WIDTH - 1));
+ /* yorig, xorig (relate to color buffer?) */
+ *b++ = (0x00000000);
+
+ /* texfmt */
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2);
+ *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT));
+ *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) |
+ S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D));
+ *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT |
+ BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT |
+ BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT);
+
+ /* pixel shader */
+ *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2));
+ /* decl FS_T0 */
+ *b++ = (D0_DCL |
+ REG_TYPE(FS_T0) << D0_TYPE_SHIFT |
+ REG_NR(FS_T0) << D0_NR_SHIFT |
+ ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* decl FS_S0 */
+ *b++ = (D0_DCL |
+ (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) |
+ (REG_NR(FS_S0) << D0_NR_SHIFT) |
+ ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* texld(FS_OC, FS_S0, FS_T0 */
+ *b++ = (T0_TEXLD |
+ (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) |
+ (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) |
+ (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT));
+ *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) |
+ (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT));
+ *b++ = (0);
+
+ *b++ = (PRIM3D_RECTLIST | (3*4 - 1));
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ tiling_bits = 0;
+ if (use_fence)
+ tiling_bits = EXEC_OBJECT_NEEDS_FENCE;
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = tiling_bits;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = tiling_bits;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static void blt_copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ *b++ = (XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB);
+ *b++ = 3 << 24 | 0xcc << 16 | WIDTH * 4;
+ *b++ = 0;
+ *b++ = HEIGHT << 16 | WIDTH;
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER); b++;
+ *b++ = 0;
+ *b++ = WIDTH*4;
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_RENDER, 0); b++;
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = EXEC_OBJECT_NEEDS_FENCE;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = EXEC_OBJECT_NEEDS_FENCE;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+
+static void
+copy(int fd,
+ uint32_t dst, int dst_tiling,
+ uint32_t src, int src_tiling)
+{
+retry:
+ switch (random() % 3) {
+ case 0: render_copy(fd, dst, dst_tiling, src, src_tiling, 0); break;
+ case 1: render_copy(fd, dst, dst_tiling, src, src_tiling, 1); break;
+ case 2: if (dst_tiling == I915_TILING_Y || src_tiling == I915_TILING_Y)
+ goto retry;
+ blt_copy(fd, dst, src);
+ break;
+ }
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val, int tiling)
+{
+ uint32_t handle;
+ uint32_t *v;
+ int i;
+
+ handle = gem_create(fd, WIDTH*HEIGHT*4);
+ gem_set_tiling(fd, handle, tiling, WIDTH*4);
+
+ /* Fill the BO with dwords starting at val */
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ v[i] = val++;
+ munmap(v, WIDTH*HEIGHT*4);
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ uint32_t *v;
+ int i;
+
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (v[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, v[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+ munmap(v, WIDTH*HEIGHT*4);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *tiling, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!IS_GEN3(intel_get_drm_devid(fd))) {
+ printf("gen3-only test, doing nothing\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*3);
+ tiling = handle + count;
+ start_val = tiling + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start, tiling[i] = i % 3);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, forward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, backward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Random blits..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ while (src == dst)
+ dst = random() % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ return 0;
+}
diff --git a/tests/gen3_render_linear_blits.c b/tests/gen3_render_linear_blits.c
new file mode 100644
index 00000000..529e23ff
--- /dev/null
+++ b/tests/gen3_render_linear_blits.c
@@ -0,0 +1,400 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gen3_linear_render_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#include "i915_reg.h"
+#include "i915_3d.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static uint32_t linear[WIDTH*HEIGHT];
+
+static inline uint32_t pack_float(float f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+ u.f = f;
+ return u.dw;
+}
+
+static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+ uint32_t offset,
+ uint32_t handle,
+ uint32_t read_domain,
+ uint32_t write_domain)
+{
+ reloc->target_handle = handle;
+ reloc->delta = 0;
+ reloc->offset = offset * sizeof(uint32_t);
+ reloc->presumed_offset = 0;
+ reloc->read_domains = read_domain;
+ reloc->write_domain = write_domain;
+
+ return reloc->presumed_offset + reloc->delta;
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ /* invariant state */
+ *b++ = (_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0);
+ *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE <<
+ IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO <<
+ IAB_DST_FACTOR_SHIFT));
+ *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_SPEC_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_Z_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB(0, 0) |
+ CSB_TCB(1, 1) |
+ CSB_TCB(2, 2) |
+ CSB_TCB(3, 3) |
+ CSB_TCB(4, 4) |
+ CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7));
+ *b++ = (_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D);
+ *b++ = (_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff));
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2);
+ *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */
+ *b++ = ((1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY);
+ *b++ = (0x00000000); /* Stencil. */
+ *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD);
+ *b++ = (0);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE);
+ *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */
+ *b++ = (0);
+ *b++ = (_3DSTATE_STIPPLE);
+ *b++ = (0x00000000);
+ *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0);
+
+ /* samler state */
+#define TEX_COUNT 1
+ *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++;
+ *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 |
+ (HEIGHT - 1) << MS3_HEIGHT_SHIFT |
+ (WIDTH - 1) << MS3_WIDTH_SHIFT);
+ *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT);
+
+ *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT |
+ TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT |
+ 0 << SS3_TEXTUREMAP_INDEX_SHIFT);
+ *b++ = (0x00000000);
+
+ /* render target state */
+ *b++ = (_3DSTATE_BUF_INFO_CMD);
+ *b++ = (BUF_3D_ID_COLOR_BACK | WIDTH*4);
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ b++;
+
+ *b++ = (_3DSTATE_DST_BUF_VARS_CMD);
+ *b++ = (COLR_BUF_ARGB8888 |
+ DSTORG_HORT_BIAS(0x8) |
+ DSTORG_VERT_BIAS(0x8));
+
+ /* draw rect is unconditional */
+ *b++ = (_3DSTATE_DRAW_RECT_CMD);
+ *b++ = (0x00000000);
+ *b++ = (0x00000000); /* ymin, xmin */
+ *b++ = (DRAW_YMAX(HEIGHT - 1) |
+ DRAW_XMAX(WIDTH - 1));
+ /* yorig, xorig (relate to color buffer?) */
+ *b++ = (0x00000000);
+
+ /* texfmt */
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2);
+ *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT));
+ *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) |
+ S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D));
+ *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT |
+ BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT |
+ BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT);
+
+ /* pixel shader */
+ *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2));
+ /* decl FS_T0 */
+ *b++ = (D0_DCL |
+ REG_TYPE(FS_T0) << D0_TYPE_SHIFT |
+ REG_NR(FS_T0) << D0_NR_SHIFT |
+ ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* decl FS_S0 */
+ *b++ = (D0_DCL |
+ (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) |
+ (REG_NR(FS_S0) << D0_NR_SHIFT) |
+ ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* texld(FS_OC, FS_S0, FS_T0 */
+ *b++ = (T0_TEXLD |
+ (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) |
+ (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) |
+ (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT));
+ *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) |
+ (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT));
+ *b++ = (0);
+
+ *b++ = (PRIM3D_RECTLIST | (3*4 - 1));
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+ uint32_t handle;
+ int i;
+
+ handle = gem_create(fd, sizeof(linear));
+
+ /* Fill the BO with dwords starting at val */
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ linear[i] = val++;
+ gem_write(fd, handle, 0, linear, sizeof(linear));
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ int i;
+
+ gem_read(fd, handle, 0, linear, sizeof(linear));
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (linear[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, linear[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!IS_GEN3(intel_get_drm_devid(fd))) {
+ printf("gen3-only test, doing nothing\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*2);
+ start_val = handle + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation...\n");
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, forward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, backward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Random blits...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (src == dst)
+ continue;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ return 0;
+}
diff --git a/tests/gen3_render_mixed_blits.c b/tests/gen3_render_mixed_blits.c
new file mode 100644
index 00000000..1353b9d7
--- /dev/null
+++ b/tests/gen3_render_mixed_blits.c
@@ -0,0 +1,429 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gen3_linear_render_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#include "i915_reg.h"
+#include "i915_3d.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static inline uint32_t pack_float(float f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+ u.f = f;
+ return u.dw;
+}
+
+static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+ uint32_t offset,
+ uint32_t handle,
+ uint32_t read_domain,
+ uint32_t write_domain)
+{
+ reloc->target_handle = handle;
+ reloc->delta = 0;
+ reloc->offset = offset * sizeof(uint32_t);
+ reloc->presumed_offset = 0;
+ reloc->read_domains = read_domain;
+ reloc->write_domain = write_domain;
+
+ return reloc->presumed_offset + reloc->delta;
+}
+
+static void
+copy(int fd,
+ uint32_t dst, int dst_tiling,
+ uint32_t src, int src_tiling)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ uint32_t tiling_bits;
+ int ret;
+
+ /* invariant state */
+ *b++ = (_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0);
+ *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE <<
+ IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO <<
+ IAB_DST_FACTOR_SHIFT));
+ *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_SPEC_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_Z_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB(0, 0) |
+ CSB_TCB(1, 1) |
+ CSB_TCB(2, 2) |
+ CSB_TCB(3, 3) |
+ CSB_TCB(4, 4) |
+ CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7));
+ *b++ = (_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D);
+ *b++ = (_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff));
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2);
+ *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */
+ *b++ = ((1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY);
+ *b++ = (0x00000000); /* Stencil. */
+ *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD);
+ *b++ = (0);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE);
+ *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */
+ *b++ = (0);
+ *b++ = (_3DSTATE_STIPPLE);
+ *b++ = (0x00000000);
+ *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0);
+
+ /* samler state */
+ tiling_bits = 0;
+ if (src_tiling != I915_TILING_NONE)
+ tiling_bits = MS3_TILED_SURFACE;
+ if (src_tiling == I915_TILING_Y)
+ tiling_bits |= MS3_TILE_WALK;
+
+#define TEX_COUNT 1
+ *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++;
+ *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 | tiling_bits |
+ (HEIGHT - 1) << MS3_HEIGHT_SHIFT |
+ (WIDTH - 1) << MS3_WIDTH_SHIFT);
+ *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT);
+
+ *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT |
+ TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT |
+ 0 << SS3_TEXTUREMAP_INDEX_SHIFT);
+ *b++ = (0x00000000);
+
+ /* render target state */
+ tiling_bits = 0;
+ if (dst_tiling != I915_TILING_NONE)
+ tiling_bits = BUF_3D_TILED_SURFACE;
+ if (dst_tiling == I915_TILING_Y)
+ tiling_bits |= BUF_3D_TILE_WALK_Y;
+ *b++ = (_3DSTATE_BUF_INFO_CMD);
+ *b++ = (BUF_3D_ID_COLOR_BACK | tiling_bits | WIDTH*4);
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ b++;
+
+ *b++ = (_3DSTATE_DST_BUF_VARS_CMD);
+ *b++ = (COLR_BUF_ARGB8888 |
+ DSTORG_HORT_BIAS(0x8) |
+ DSTORG_VERT_BIAS(0x8));
+
+ /* draw rect is unconditional */
+ *b++ = (_3DSTATE_DRAW_RECT_CMD);
+ *b++ = (0x00000000);
+ *b++ = (0x00000000); /* ymin, xmin */
+ *b++ = (DRAW_YMAX(HEIGHT - 1) |
+ DRAW_XMAX(WIDTH - 1));
+ /* yorig, xorig (relate to color buffer?) */
+ *b++ = (0x00000000);
+
+ /* texfmt */
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2);
+ *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT));
+ *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) |
+ S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D));
+ *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT |
+ BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT |
+ BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT);
+
+ /* pixel shader */
+ *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2));
+ /* decl FS_T0 */
+ *b++ = (D0_DCL |
+ REG_TYPE(FS_T0) << D0_TYPE_SHIFT |
+ REG_NR(FS_T0) << D0_NR_SHIFT |
+ ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* decl FS_S0 */
+ *b++ = (D0_DCL |
+ (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) |
+ (REG_NR(FS_S0) << D0_NR_SHIFT) |
+ ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* texld(FS_OC, FS_S0, FS_T0 */
+ *b++ = (T0_TEXLD |
+ (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) |
+ (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) |
+ (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT));
+ *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) |
+ (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT));
+ *b++ = (0);
+
+ *b++ = (PRIM3D_RECTLIST | (3*4 - 1));
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val, int tiling)
+{
+ uint32_t handle;
+ uint32_t *v;
+ int i;
+
+ handle = gem_create(fd, WIDTH*HEIGHT*4);
+ gem_set_tiling(fd, handle, tiling, WIDTH*4);
+
+ /* Fill the BO with dwords starting at val */
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ v[i] = val++;
+ munmap(v, WIDTH*HEIGHT*4);
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ uint32_t *v;
+ int i;
+
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (v[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, v[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+ munmap(v, WIDTH*HEIGHT*4);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *tiling, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!IS_GEN3(intel_get_drm_devid(fd))) {
+ printf("gen3-only test, doing nothing\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*3);
+ tiling = handle + count;
+ start_val = tiling + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start, tiling[i] = i % 3);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, forward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, backward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Random blits..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ while (src == dst)
+ dst = random() % count;
+
+ copy(fd, handle[dst], tiling[dst], handle[src], tiling[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ return 0;
+}
diff --git a/tests/gen3_render_tiledx_blits.c b/tests/gen3_render_tiledx_blits.c
new file mode 100644
index 00000000..0e96e797
--- /dev/null
+++ b/tests/gen3_render_tiledx_blits.c
@@ -0,0 +1,408 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gen3_linear_render_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#include "i915_reg.h"
+#include "i915_3d.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static inline uint32_t pack_float(float f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+ u.f = f;
+ return u.dw;
+}
+
+static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+ uint32_t offset,
+ uint32_t handle,
+ uint32_t read_domain,
+ uint32_t write_domain)
+{
+ reloc->target_handle = handle;
+ reloc->delta = 0;
+ reloc->offset = offset * sizeof(uint32_t);
+ reloc->presumed_offset = 0;
+ reloc->read_domains = read_domain;
+ reloc->write_domain = write_domain;
+
+ return reloc->presumed_offset + reloc->delta;
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ /* invariant state */
+ *b++ = (_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0);
+ *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE <<
+ IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO <<
+ IAB_DST_FACTOR_SHIFT));
+ *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_SPEC_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_Z_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB(0, 0) |
+ CSB_TCB(1, 1) |
+ CSB_TCB(2, 2) |
+ CSB_TCB(3, 3) |
+ CSB_TCB(4, 4) |
+ CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7));
+ *b++ = (_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D);
+ *b++ = (_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff));
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2);
+ *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */
+ *b++ = ((1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY);
+ *b++ = (0x00000000); /* Stencil. */
+ *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD);
+ *b++ = (0);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE);
+ *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */
+ *b++ = (0);
+ *b++ = (_3DSTATE_STIPPLE);
+ *b++ = (0x00000000);
+ *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0);
+
+ /* samler state */
+#define TEX_COUNT 1
+ *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++;
+ *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 |
+ MS3_TILED_SURFACE |
+ (HEIGHT - 1) << MS3_HEIGHT_SHIFT |
+ (WIDTH - 1) << MS3_WIDTH_SHIFT);
+ *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT);
+
+ *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT |
+ TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT |
+ 0 << SS3_TEXTUREMAP_INDEX_SHIFT);
+ *b++ = (0x00000000);
+
+ /* render target state */
+ *b++ = (_3DSTATE_BUF_INFO_CMD);
+ *b++ = (BUF_3D_ID_COLOR_BACK | BUF_3D_TILED_SURFACE | WIDTH*4);
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ b++;
+
+ *b++ = (_3DSTATE_DST_BUF_VARS_CMD);
+ *b++ = (COLR_BUF_ARGB8888 |
+ DSTORG_HORT_BIAS(0x8) |
+ DSTORG_VERT_BIAS(0x8));
+
+ /* draw rect is unconditional */
+ *b++ = (_3DSTATE_DRAW_RECT_CMD);
+ *b++ = (0x00000000);
+ *b++ = (0x00000000); /* ymin, xmin */
+ *b++ = (DRAW_YMAX(HEIGHT - 1) |
+ DRAW_XMAX(WIDTH - 1));
+ /* yorig, xorig (relate to color buffer?) */
+ *b++ = (0x00000000);
+
+ /* texfmt */
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2);
+ *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT));
+ *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) |
+ S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D));
+ *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT |
+ BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT |
+ BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT);
+
+ /* pixel shader */
+ *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2));
+ /* decl FS_T0 */
+ *b++ = (D0_DCL |
+ REG_TYPE(FS_T0) << D0_TYPE_SHIFT |
+ REG_NR(FS_T0) << D0_NR_SHIFT |
+ ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* decl FS_S0 */
+ *b++ = (D0_DCL |
+ (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) |
+ (REG_NR(FS_S0) << D0_NR_SHIFT) |
+ ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* texld(FS_OC, FS_S0, FS_T0 */
+ *b++ = (T0_TEXLD |
+ (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) |
+ (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) |
+ (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT));
+ *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) |
+ (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT));
+ *b++ = (0);
+
+ *b++ = (PRIM3D_RECTLIST | (3*4 - 1));
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+ uint32_t handle;
+ uint32_t *v;
+ int i;
+
+ handle = gem_create(fd, WIDTH*HEIGHT*4);
+ gem_set_tiling(fd, handle, I915_TILING_X, WIDTH*4);
+
+ /* Fill the BO with dwords starting at val */
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ v[i] = val++;
+ munmap(v, WIDTH*HEIGHT*4);
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ uint32_t *v;
+ int i;
+
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (v[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, v[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+ munmap(v, WIDTH*HEIGHT*4);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!IS_GEN3(intel_get_drm_devid(fd))) {
+ printf("gen3-only test, doing nothing\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*2);
+ start_val = handle + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation...\n");
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, forward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Cyclic blits, backward...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ printf("Random blits...\n");
+ for (i = 0; i < count * 4; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ if (src == dst)
+ continue;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+
+ return 0;
+}
diff --git a/tests/gen3_render_tiledy_blits.c b/tests/gen3_render_tiledy_blits.c
new file mode 100644
index 00000000..90fc7eb9
--- /dev/null
+++ b/tests/gen3_render_tiledy_blits.c
@@ -0,0 +1,415 @@
+/*
+ * 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.
+ *
+ * Authors:
+ * Chris Wilson <chris@chris-wilson.co.uk>
+ *
+ */
+
+/** @file gen3_linear_render_blits.c
+ *
+ * This is a test of doing many blits, with a working set
+ * larger than the aperture size.
+ *
+ * The goal is to simply ensure the basics work.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "intel_gpu_tools.h"
+
+#include "i915_reg.h"
+#include "i915_3d.h"
+
+#define WIDTH 512
+#define HEIGHT 512
+
+static inline uint32_t pack_float(float f)
+{
+ union {
+ uint32_t dw;
+ float f;
+ } u;
+ u.f = f;
+ return u.dw;
+}
+
+static uint32_t fill_reloc(struct drm_i915_gem_relocation_entry *reloc,
+ uint32_t offset,
+ uint32_t handle,
+ uint32_t read_domain,
+ uint32_t write_domain)
+{
+ reloc->target_handle = handle;
+ reloc->delta = 0;
+ reloc->offset = offset * sizeof(uint32_t);
+ reloc->presumed_offset = 0;
+ reloc->read_domains = read_domain;
+ reloc->write_domain = write_domain;
+
+ return reloc->presumed_offset + reloc->delta;
+}
+
+static void
+copy(int fd, uint32_t dst, uint32_t src)
+{
+ uint32_t batch[1024], *b = batch;
+ struct drm_i915_gem_relocation_entry reloc[2], *r = reloc;
+ struct drm_i915_gem_exec_object2 obj[3];
+ struct drm_i915_gem_execbuffer2 exec;
+ uint32_t handle;
+ int ret;
+
+ /* invariant state */
+ *b++ = (_3DSTATE_AA_CMD |
+ AA_LINE_ECAAR_WIDTH_ENABLE |
+ AA_LINE_ECAAR_WIDTH_1_0 |
+ AA_LINE_REGION_WIDTH_ENABLE | AA_LINE_REGION_WIDTH_1_0);
+ *b++ = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD |
+ IAB_MODIFY_ENABLE |
+ IAB_MODIFY_FUNC | (BLENDFUNC_ADD << IAB_FUNC_SHIFT) |
+ IAB_MODIFY_SRC_FACTOR | (BLENDFACT_ONE <<
+ IAB_SRC_FACTOR_SHIFT) |
+ IAB_MODIFY_DST_FACTOR | (BLENDFACT_ZERO <<
+ IAB_DST_FACTOR_SHIFT));
+ *b++ = (_3DSTATE_DFLT_DIFFUSE_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_SPEC_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DFLT_Z_CMD);
+ *b++ = (0);
+ *b++ = (_3DSTATE_COORD_SET_BINDINGS |
+ CSB_TCB(0, 0) |
+ CSB_TCB(1, 1) |
+ CSB_TCB(2, 2) |
+ CSB_TCB(3, 3) |
+ CSB_TCB(4, 4) |
+ CSB_TCB(5, 5) | CSB_TCB(6, 6) | CSB_TCB(7, 7));
+ *b++ = (_3DSTATE_RASTER_RULES_CMD |
+ ENABLE_POINT_RASTER_RULE |
+ OGL_POINT_RASTER_RULE |
+ ENABLE_LINE_STRIP_PROVOKE_VRTX |
+ ENABLE_TRI_FAN_PROVOKE_VRTX |
+ LINE_STRIP_PROVOKE_VRTX(1) |
+ TRI_FAN_PROVOKE_VRTX(2) | ENABLE_TEXKILL_3D_4D | TEXKILL_4D);
+ *b++ = (_3DSTATE_MODES_4_CMD |
+ ENABLE_LOGIC_OP_FUNC | LOGIC_OP_FUNC(LOGICOP_COPY) |
+ ENABLE_STENCIL_WRITE_MASK | STENCIL_WRITE_MASK(0xff) |
+ ENABLE_STENCIL_TEST_MASK | STENCIL_TEST_MASK(0xff));
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(3) | I1_LOAD_S(4) | I1_LOAD_S(5) | 2);
+ *b++ = (0x00000000); /* Disable texture coordinate wrap-shortest */
+ *b++ = ((1 << S4_POINT_WIDTH_SHIFT) |
+ S4_LINE_WIDTH_ONE |
+ S4_CULLMODE_NONE |
+ S4_VFMT_XY);
+ *b++ = (0x00000000); /* Stencil. */
+ *b++ = (_3DSTATE_SCISSOR_ENABLE_CMD | DISABLE_SCISSOR_RECT);
+ *b++ = (_3DSTATE_SCISSOR_RECT_0_CMD);
+ *b++ = (0);
+ *b++ = (0);
+ *b++ = (_3DSTATE_DEPTH_SUBRECT_DISABLE);
+ *b++ = (_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */
+ *b++ = (0);
+ *b++ = (_3DSTATE_STIPPLE);
+ *b++ = (0x00000000);
+ *b++ = (_3DSTATE_BACKFACE_STENCIL_OPS | BFO_ENABLE_STENCIL_TWO_SIDE | 0);
+
+ /* samler state */
+#define TEX_COUNT 1
+ *b++ = (_3DSTATE_MAP_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b = fill_reloc(r++, b-batch, src, I915_GEM_DOMAIN_SAMPLER, 0); b++;
+ *b++ = (MAPSURF_32BIT | MT_32BIT_ARGB8888 |
+ MS3_TILED_SURFACE | MS3_TILE_WALK |
+ (HEIGHT - 1) << MS3_HEIGHT_SHIFT |
+ (WIDTH - 1) << MS3_WIDTH_SHIFT);
+ *b++ = ((WIDTH-1) << MS4_PITCH_SHIFT);
+
+ *b++ = (_3DSTATE_SAMPLER_STATE | (3 * TEX_COUNT));
+ *b++ = ((1 << TEX_COUNT) - 1);
+ *b++ = (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MAG_FILTER_SHIFT |
+ FILTER_NEAREST << SS2_MIN_FILTER_SHIFT);
+ *b++ = (TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT |
+ TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT |
+ 0 << SS3_TEXTUREMAP_INDEX_SHIFT);
+ *b++ = (0x00000000);
+
+ /* render target state */
+ *b++ = (_3DSTATE_BUF_INFO_CMD);
+ *b++ = (BUF_3D_ID_COLOR_BACK | BUF_3D_TILED_SURFACE | BUF_3D_TILE_WALK_Y | WIDTH*4);
+ *b = fill_reloc(r++, b-batch, dst,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER);
+ b++;
+
+ *b++ = (_3DSTATE_DST_BUF_VARS_CMD);
+ *b++ = (COLR_BUF_ARGB8888 |
+ DSTORG_HORT_BIAS(0x8) |
+ DSTORG_VERT_BIAS(0x8));
+
+ /* draw rect is unconditional */
+ *b++ = (_3DSTATE_DRAW_RECT_CMD);
+ *b++ = (0x00000000);
+ *b++ = (0x00000000); /* ymin, xmin */
+ *b++ = (DRAW_YMAX(HEIGHT - 1) |
+ DRAW_XMAX(WIDTH - 1));
+ /* yorig, xorig (relate to color buffer?) */
+ *b++ = (0x00000000);
+
+ /* texfmt */
+ *b++ = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | I1_LOAD_S(1) | I1_LOAD_S(2) | I1_LOAD_S(6) | 2);
+ *b++ = ((4 << S1_VERTEX_WIDTH_SHIFT) | (4 << S1_VERTEX_PITCH_SHIFT));
+ *b++ = (~S2_TEXCOORD_FMT(0, TEXCOORDFMT_NOT_PRESENT) |
+ S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D));
+ *b++ = (S6_CBUF_BLEND_ENABLE | S6_COLOR_WRITE_ENABLE |
+ BLENDFUNC_ADD << S6_CBUF_BLEND_FUNC_SHIFT |
+ BLENDFACT_ONE << S6_CBUF_SRC_BLEND_FACT_SHIFT |
+ BLENDFACT_ZERO << S6_CBUF_DST_BLEND_FACT_SHIFT);
+
+ /* pixel shader */
+ *b++ = (_3DSTATE_PIXEL_SHADER_PROGRAM | (1 + 3*3 - 2));
+ /* decl FS_T0 */
+ *b++ = (D0_DCL |
+ REG_TYPE(FS_T0) << D0_TYPE_SHIFT |
+ REG_NR(FS_T0) << D0_NR_SHIFT |
+ ((REG_TYPE(FS_T0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* decl FS_S0 */
+ *b++ = (D0_DCL |
+ (REG_TYPE(FS_S0) << D0_TYPE_SHIFT) |
+ (REG_NR(FS_S0) << D0_NR_SHIFT) |
+ ((REG_TYPE(FS_S0) != REG_TYPE_S) ? D0_CHANNEL_ALL : 0));
+ *b++ = (0);
+ *b++ = (0);
+ /* texld(FS_OC, FS_S0, FS_T0 */
+ *b++ = (T0_TEXLD |
+ (REG_TYPE(FS_OC) << T0_DEST_TYPE_SHIFT) |
+ (REG_NR(FS_OC) << T0_DEST_NR_SHIFT) |
+ (REG_NR(FS_S0) << T0_SAMPLER_NR_SHIFT));
+ *b++ = ((REG_TYPE(FS_T0) << T1_ADDRESS_REG_TYPE_SHIFT) |
+ (REG_NR(FS_T0) << T1_ADDRESS_REG_NR_SHIFT));
+ *b++ = (0);
+
+ *b++ = (PRIM3D_RECTLIST | (3*4 - 1));
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(WIDTH);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+ *b++ = pack_float(0);
+ *b++ = pack_float(HEIGHT);
+
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+ *b++ = pack_float(0);
+
+ *b++ = MI_BATCH_BUFFER_END;
+ if ((b - batch) & 1)
+ *b++ = 0;
+
+ assert(b - batch <= 1024);
+ handle = gem_create(fd, 4096);
+ gem_write(fd, handle, 0, batch, (b-batch)*sizeof(batch[0]));
+
+ assert(r-reloc == 2);
+
+ obj[0].handle = dst;
+ obj[0].relocation_count = 0;
+ obj[0].relocs_ptr = 0;
+ obj[0].alignment = 0;
+ obj[0].offset = 0;
+ obj[0].flags = 0;
+ obj[0].rsvd1 = 0;
+ obj[0].rsvd2 = 0;
+
+ obj[1].handle = src;
+ obj[1].relocation_count = 0;
+ obj[1].relocs_ptr = 0;
+ obj[1].alignment = 0;
+ obj[1].offset = 0;
+ obj[1].flags = 0;
+ obj[1].rsvd1 = 0;
+ obj[1].rsvd2 = 0;
+
+ obj[2].handle = handle;
+ obj[2].relocation_count = 2;
+ obj[2].relocs_ptr = (uintptr_t)reloc;
+ obj[2].alignment = 0;
+ obj[2].offset = 0;
+ obj[2].flags = 0;
+ obj[2].rsvd1 = obj[2].rsvd2 = 0;
+
+ exec.buffers_ptr = (uintptr_t)obj;
+ exec.buffer_count = 3;
+ exec.batch_start_offset = 0;
+ exec.batch_len = (b-batch)*sizeof(batch[0]);
+ exec.DR1 = exec.DR4 = 0;
+ exec.num_cliprects = 0;
+ exec.cliprects_ptr = 0;
+ exec.flags = 0;
+ i915_execbuffer2_set_context_id(exec, 0);
+ exec.rsvd2 = 0;
+
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ while (ret && errno == EBUSY) {
+ drmCommandNone(fd, DRM_I915_GEM_THROTTLE);
+ ret = drmIoctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &exec);
+ }
+ assert(ret == 0);
+
+ gem_close(fd, handle);
+}
+
+static uint32_t
+create_bo(int fd, uint32_t val)
+{
+ uint32_t handle;
+ uint32_t *v;
+ int i;
+
+ handle = gem_create(fd, WIDTH*HEIGHT*4);
+ gem_set_tiling(fd, handle, I915_TILING_Y, WIDTH*4);
+
+ /* Fill the BO with dwords starting at val */
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ | PROT_WRITE);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++)
+ v[i] = val++;
+ munmap(v, WIDTH*HEIGHT*4);
+
+ return handle;
+}
+
+static void
+check_bo(int fd, uint32_t handle, uint32_t val)
+{
+ uint32_t *v;
+ int i;
+
+ v = gem_mmap(fd, handle, WIDTH*HEIGHT*4, PROT_READ);
+ assert(v);
+ for (i = 0; i < WIDTH*HEIGHT; i++) {
+ if (v[i] != val) {
+ fprintf(stderr, "Expected 0x%08x, found 0x%08x "
+ "at offset 0x%08x\n",
+ val, v[i], i * 4);
+ abort();
+ }
+ val++;
+ }
+ munmap(v, WIDTH*HEIGHT*4);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t *handle, *start_val;
+ uint32_t start = 0;
+ int i, fd, count;
+
+ fd = drm_open_any();
+
+ if (!IS_GEN3(intel_get_drm_devid(fd))) {
+ printf("gen3-only test, doing nothing\n");
+ return 77;
+ }
+
+ count = 0;
+ if (argc > 1)
+ count = atoi(argv[1]);
+ if (count == 0)
+ count = 3 * gem_aperture_size(fd) / (1024*1024) / 2;
+ printf("Using %d 1MiB buffers\n", count);
+
+ handle = malloc(sizeof(uint32_t)*count*2);
+ start_val = handle + count;
+
+ for (i = 0; i < count; i++) {
+ handle[i] = create_bo(fd, start);
+ start_val[i] = start;
+ start += 1024 * 1024 / 4;
+ }
+
+ printf("Verifying initialisation..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, forward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = i % count;
+ int dst = (i + 1) % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Cyclic blits, backward..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = (i + 1) % count;
+ int dst = i % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ printf("Random blits..."); fflush(stdout);
+ for (i = 0; i < count * 32; i++) {
+ int src = random() % count;
+ int dst = random() % count;
+
+ while (src == dst)
+ dst = random() % count;
+
+ copy(fd, handle[dst], handle[src]);
+ start_val[dst] = start_val[src];
+ }
+ printf("verifying..."); fflush(stdout);
+ for (i = 0; i < count; i++)
+ check_bo(fd, handle[i], start_val[i]);
+ printf("done\n");
+
+ return 0;
+}
diff --git a/tests/getclient.c b/tests/getclient.c
new file mode 100644
index 00000000..481ce119
--- /dev/null
+++ b/tests/getclient.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2007 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 <eric@anholt.net>
+ *
+ */
+
+#include <limits.h>
+#include <sys/ioctl.h>
+#include "drmtest.h"
+
+/**
+ * Checks DRM_IOCTL_GET_CLIENT.
+ */
+int main(int argc, char **argv)
+{
+ int fd, ret;
+ drm_client_t client;
+
+ fd = drm_open_any();
+
+ /* Look for client index 0. This should exist whether we're operating
+ * on an otherwise unused drm device, or the X Server is running on
+ * the device.
+ */
+ client.idx = 0;
+ ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
+ assert(ret == 0);
+
+ /* Look for some absurd client index and make sure it's invalid.
+ * The DRM drivers currently always return data, so the user has
+ * no real way to detect when the list has terminated. That's bad,
+ * and this test is XFAIL as a result.
+ */
+ client.idx = 0x7fffffff;
+ ret = ioctl(fd, DRM_IOCTL_GET_CLIENT, &client);
+ assert(ret == -1 && errno == EINVAL);
+
+ close(fd);
+ return 0;
+}
diff --git a/tests/getstats.c b/tests/getstats.c
new file mode 100644
index 00000000..8a7d2999
--- /dev/null
+++ b/tests/getstats.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2007 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 <eric@anholt.net>
+ *
+ */
+
+#include <limits.h>
+#include <sys/ioctl.h>
+#include "drmtest.h"
+
+/**
+ * Checks DRM_IOCTL_GET_STATS.
+ *
+ * I don't care too much about the actual contents, just that the kernel
+ * doesn't crash.
+ */
+int main(int argc, char **argv)
+{
+ int fd, ret;
+ drm_stats_t stats;
+
+ fd = drm_open_any();
+
+ ret = ioctl(fd, DRM_IOCTL_GET_STATS, &stats);
+ assert(ret == 0);
+
+ close(fd);
+ return 0;
+}
diff --git a/tests/getversion.c b/tests/getversion.c
new file mode 100644
index 00000000..4847e796
--- /dev/null
+++ b/tests/getversion.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2007 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 <eric@anholt.net>
+ *
+ */
+
+#include <string.h>
+#include <sys/ioctl.h>
+#include "drmtest.h"
+
+/**
+ * Checks DRM_IOCTL_GET_VERSION and libdrm's drmGetVersion() interface to it.
+ */
+int main(int argc, char **argv)
+{
+ int fd;
+ drmVersionPtr v;
+
+ fd = drm_open_any();
+ v = drmGetVersion(fd);
+ assert(strlen(v->name) != 0);
+ assert(strlen(v->date) != 0);
+ assert(strlen(v->desc) != 0);
+ assert(v->version_major >= 1);
+ drmFree(v);
+ close(fd);
+ return 0;
+}
diff --git a/tests/module_reload b/tests/module_reload
new file mode 100755
index 00000000..400fdd04
--- /dev/null
+++ b/tests/module_reload
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# Testcase: Reload the drm module
+#
+# ... we've broken this way too often :(
+#
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+# no other drm service should be running, so we can just unbind
+
+# vtcon0 is vga, vtcon1 fbcon and let's pray that won't change due to boot load
+# time changes
+if ! echo 0 > /sys/class/vtconsole/vtcon1/bind ; then
+ echo -e "no kms unload support"
+ echo "please enable CONFIG_VT_HW_CONSOLE_BINDING in the kernel"
+ exit 77
+fi
+
+#ignore errors in ips - gen5 only
+rmmod intel_ips &> /dev/null
+rmmod i915
+#ignore errors in intel-gtt, often built-in
+rmmod intel-gtt &> /dev/null
+rmmod drm_kms_helper
+rmmod drm
+
+if lsmod | grep i915 &> /dev/null ; then
+ echo WARNING: i915.ko still loaded!
+ exitcode=1
+else
+ echo module successfully unloaded
+ exitcode=0
+fi
+
+modprobe i915
+echo 1 > /sys/class/vtconsole/vtcon1/bind
+
+# try to run something
+$SOURCE_DIR/gem_exec_nop > /dev/null && echo "module successfully loaded again"
diff --git a/tests/pass.png b/tests/pass.png
new file mode 100644
index 00000000..36a5236b
--- /dev/null
+++ b/tests/pass.png
Binary files differ
diff --git a/tests/prime_nv_api.c b/tests/prime_nv_api.c
new file mode 100644
index 00000000..962e903d
--- /dev/null
+++ b/tests/prime_nv_api.c
@@ -0,0 +1,408 @@
+/* wierd use of API tests */
+
+/* test1- export buffer from intel, import same fd twice into nouveau,
+ check handles match
+ test2 - export buffer from intel, import fd once, close fd, try import again
+ fail if it succeeds
+ test3 - export buffer from intel, import twice on nouveau, check handle is the same
+ test4 - export handle twice from intel, import into nouveau twice, check handle is the same
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "intel_bufmgr.h"
+#include "nouveau.h"
+#include "intel_gpu_tools.h"
+#include "intel_batchbuffer.h"
+
+#define BO_SIZE (256*1024)
+
+int intel_fd = -1, intel_fd2 = -1, nouveau_fd = -1, nouveau_fd2 = -1;
+drm_intel_bufmgr *bufmgr;
+drm_intel_bufmgr *bufmgr2;
+struct nouveau_device *ndev, *ndev2;
+struct nouveau_client *nclient, *nclient2;
+uint32_t devid;
+struct intel_batchbuffer *intel_batch;
+
+static int find_and_open_devices(void)
+{
+ int i;
+ char path[80];
+ struct stat buf;
+ FILE *fl;
+ char vendor_id[8];
+ int venid;
+ for (i = 0; i < 9; i++) {
+ sprintf(path, "/sys/class/drm/card%d/device/vendor", i);
+ if (stat(path, &buf))
+ break;
+
+ fl = fopen(path, "r");
+ if (!fl)
+ break;
+
+ fgets(vendor_id, 8, fl);
+ fclose(fl);
+
+ venid = strtoul(vendor_id, NULL, 16);
+ sprintf(path, "/dev/dri/card%d", i);
+ if (venid == 0x8086) {
+ intel_fd = open(path, O_RDWR);
+ if (!intel_fd)
+ return -1;
+ intel_fd2 = open(path, O_RDWR);
+ if (!intel_fd2)
+ return -1;
+ } else if (venid == 0x10de) {
+ nouveau_fd = open(path, O_RDWR);
+ if (!nouveau_fd)
+ return -1;
+ nouveau_fd2 = open(path, O_RDWR);
+ if (!nouveau_fd2)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int test1(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (ret)
+ goto out;
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ if (ret < 0) {
+ close(prime_fd);
+ goto out;
+ }
+ ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2);
+ close(prime_fd);
+ if (ret < 0)
+ goto out;
+
+ if (nvbo->handle != nvbo2->handle)
+ ret = -1;
+out:
+ nouveau_bo_ref(NULL, &nvbo2);
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+
+static int test2(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (ret < 0)
+ goto out;
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ close(prime_fd);
+ if (ret < 0)
+ goto out;
+ ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2);
+ if (ret == 0)
+ ret = -1;
+ else
+ ret = 0;
+
+out:
+ nouveau_bo_ref(NULL, &nvbo2);
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+
+/* import handle twice on one driver */
+static int test3(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ ret = drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (ret < 0)
+ goto out;
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ if (ret < 0) {
+ close(prime_fd);
+ goto out;
+ }
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo2);
+ close(prime_fd);
+ if (ret < 0)
+ goto out;
+
+ if (nvbo->handle != nvbo2->handle)
+ ret = -1;
+
+out:
+ nouveau_bo_ref(NULL, &nvbo2);
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* export handle twice from one driver - import twice
+ see if we get same object */
+static int test4(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd, prime_fd2;
+ struct nouveau_bo *nvbo = NULL, *nvbo2 = NULL;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd2);
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ close(prime_fd);
+ if (ret >= 0)
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd2, &nvbo2);
+ close(prime_fd2);
+ if (ret < 0)
+ goto out;
+
+ if (nvbo->handle != nvbo2->handle)
+ ret = -1;
+
+out:
+ nouveau_bo_ref(NULL, &nvbo2);
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* export handle from intel driver - reimport to intel driver
+ see if you get same object */
+static int test5(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo, *test_intel_bo2;
+ int prime_fd;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ test_intel_bo2 = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo2) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+ if (test_intel_bo->handle != test_intel_bo2->handle)
+ ret = -1;
+
+out:
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* nouveau export reimport test */
+static int test6(void)
+{
+ int ret;
+ int prime_fd;
+ struct nouveau_bo *nvbo, *nvbo2;
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo2);
+ close(prime_fd);
+ if (ret < 0)
+ return ret;
+
+ if (nvbo->handle != nvbo2->handle)
+ fprintf(stderr,"mismatch handles %d %d\n", nvbo->handle, nvbo2->handle);
+ nouveau_bo_ref(NULL, &nvbo);
+ nouveau_bo_ref(NULL, &nvbo2);
+ return 0;
+}
+
+/* export handle from intel driver - reimport to another intel driver bufmgr
+ see if you get same object */
+static int test7(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo, *test_intel_bo2;
+ int prime_fd;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ test_intel_bo2 = drm_intel_bo_gem_create_from_prime(bufmgr2, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo2) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+ /* not sure what to test for, just that we don't explode */
+out:
+ drm_intel_bo_unreference(test_intel_bo2);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* nouveau export reimport to other driver test */
+static int test8(void)
+{
+ int ret;
+ int prime_fd;
+ struct nouveau_bo *nvbo, *nvbo2;
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ ret = nouveau_bo_prime_handle_ref(ndev2, prime_fd, &nvbo2);
+ close(prime_fd);
+ if (ret < 0)
+ return ret;
+
+ /* not sure what to test for, just make sure we don't explode */
+ nouveau_bo_ref(NULL, &nvbo);
+ nouveau_bo_ref(NULL, &nvbo2);
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ ret = find_and_open_devices();
+ if (ret < 0)
+ return ret;
+
+ if (nouveau_fd == -1 || intel_fd == -1 || nouveau_fd2 == -1 || intel_fd2 == -1) {
+ fprintf(stderr,"failed to find intel and nouveau GPU\n");
+ return 77;
+ }
+
+ /* set up intel bufmgr */
+ bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096);
+ if (!bufmgr)
+ return -1;
+ /* Do not enable reuse, we share (almost) all buffers. */
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ bufmgr2 = drm_intel_bufmgr_gem_init(intel_fd2, 4096);
+ if (!bufmgr2)
+ return -1;
+ drm_intel_bufmgr_gem_enable_reuse(bufmgr2);
+
+ /* set up nouveau bufmgr */
+ ret = nouveau_device_wrap(nouveau_fd, 0, &ndev);
+ if (ret < 0) {
+ fprintf(stderr,"failed to wrap nouveau device\n");
+ return 77;
+ }
+
+ ret = nouveau_client_new(ndev, &nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to setup nouveau client\n");
+ return -1;
+ }
+
+ /* set up nouveau bufmgr */
+ ret = nouveau_device_wrap(nouveau_fd2, 0, &ndev2);
+ if (ret < 0) {
+ fprintf(stderr,"failed to wrap nouveau device\n");
+ return 77;
+ }
+
+ ret = nouveau_client_new(ndev2, &nclient2);
+ if (ret < 0) {
+ fprintf(stderr,"failed to setup nouveau client\n");
+ return -1;
+ }
+
+ /* set up an intel batch buffer */
+ devid = intel_get_drm_devid(intel_fd);
+ intel_batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ ret = test1();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 1\n");
+
+ ret = test2();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 2\n");
+
+ ret = test3();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 3\n");
+
+ ret = test4();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 4\n");
+
+ ret = test5();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 5\n");
+
+ ret = test6();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 6\n");
+
+ ret = test7();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 7\n");
+
+ ret = test8();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 8\n");
+
+ intel_batchbuffer_free(intel_batch);
+
+ nouveau_device_del(&ndev);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(intel_fd);
+ close(nouveau_fd);
+
+ return ret;
+}
diff --git a/tests/prime_nv_pcopy.c b/tests/prime_nv_pcopy.c
new file mode 100644
index 00000000..21dccf38
--- /dev/null
+++ b/tests/prime_nv_pcopy.c
@@ -0,0 +1,1329 @@
+/* basic set of prime tests between intel and nouveau */
+
+/* test list -
+ 1. share buffer from intel -> nouveau.
+ 2. share buffer from nouveau -> intel
+ 3. share intel->nouveau, map on both, write intel, read nouveau
+ 4. share intel->nouveau, blit intel fill, readback on nouveau
+ test 1 + map buffer, read/write, map other size.
+ do some hw actions on the buffer
+ some illegal operations -
+ close prime fd try and map
+
+ TODO add some nouveau rendering tests
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include "i915_drm.h"
+#include "intel_bufmgr.h"
+#include "nouveau.h"
+#include "intel_gpu_tools.h"
+#include "intel_batchbuffer.h"
+
+static int intel_fd = -1, nouveau_fd = -1;
+static drm_intel_bufmgr *bufmgr;
+static struct nouveau_device *ndev;
+static struct nouveau_client *nclient;
+static uint32_t devid;
+static struct intel_batchbuffer *batch;
+static struct nouveau_object *nchannel, *pcopy;
+static struct nouveau_bufctx *nbufctx;
+static struct nouveau_pushbuf *npush;
+
+static struct nouveau_bo *query_bo;
+static uint32_t query_counter;
+static volatile uint32_t *query;
+static uint32_t memtype_intel, tile_intel_y, tile_intel_x;
+
+#define SUBC_COPY(x) 6, (x)
+#define NV01_SUBCHAN_OBJECT 0
+
+#define NV01_SUBC(subc, mthd) SUBC_##subc((NV01_SUBCHAN_##mthd))
+
+#if 0
+#define dbg(fmt...) fprintf(stderr, fmt);
+#else
+#define dbg(...) do { } while (0)
+#endif
+
+typedef struct {
+ uint32_t w, h;
+ uint32_t pitch, lines;
+} rect;
+
+static int nv_bo_alloc(struct nouveau_bo **bo, rect *r,
+ uint32_t w, uint32_t h, uint32_t tile_mode,
+ int handle, uint32_t dom)
+{
+ uint32_t size;
+ uint32_t dx = 1, dy = 1, memtype = 0;
+ int ret;
+
+ *bo = NULL;
+ if (tile_mode) {
+ uint32_t tile_y;
+ uint32_t tile_x;
+
+ /* Y major tiling */
+ if ((tile_mode & 0xf) == 0xe)
+ /* but the internal layout is different */
+ tile_x = 7;
+ else
+ tile_x = 6 + (tile_mode & 0xf);
+ if (ndev->chipset < 0xc0) {
+ memtype = 0x70;
+ tile_y = 2;
+ } else {
+ memtype = 0xfe;
+ tile_y = 3;
+ }
+ if ((tile_mode & 0xf) == 0xe)
+ memtype = memtype_intel;
+ tile_y += ((tile_mode & 0xf0)>>4);
+
+ dx = 1 << tile_x;
+ dy = 1 << tile_y;
+ dbg("Tiling requirements: x y %u %u\n", dx, dy);
+ }
+
+ r->w = w;
+ r->h = h;
+
+ r->pitch = w = (w + dx-1) & ~(dx-1);
+ r->lines = h = (h + dy-1) & ~(dy-1);
+ size = w*h;
+
+ if (handle < 0) {
+ union nouveau_bo_config cfg;
+ cfg.nv50.memtype = memtype;
+ cfg.nv50.tile_mode = tile_mode;
+ if (dom == NOUVEAU_BO_GART)
+ dom |= NOUVEAU_BO_MAP;
+ ret = nouveau_bo_new(ndev, dom, 4096, size, &cfg, bo);
+ if (!ret)
+ ret = nouveau_bo_map(*bo, NOUVEAU_BO_RDWR, nclient);
+ if (ret) {
+ fprintf(stderr, "creating bo failed with %i %s\n",
+ ret, strerror(-ret));
+ nouveau_bo_ref(NULL, bo);
+ return ret;
+ }
+
+ dbg("new flags %08x memtype %08x tile %08x\n", (*bo)->flags, (*bo)->config.nv50.memtype, (*bo)->config.nv50.tile_mode);
+ if (tile_mode == tile_intel_y || tile_mode == tile_intel_x) {
+ dbg("tile mode was: %02x, now: %02x\n", (*bo)->config.nv50.tile_mode, tile_mode);
+ /* Doesn't like intel tiling much.. */
+ (*bo)->config.nv50.tile_mode = tile_mode;
+ }
+ } else {
+ ret = nouveau_bo_prime_handle_ref(ndev, handle, bo);
+ close(handle);
+ if (ret < 0) {
+ fprintf(stderr, "receiving bo failed with %i %s\n",
+ ret, strerror(-ret));
+ return ret;
+ }
+ if ((*bo)->size < size) {
+ fprintf(stderr, "expected bo size to be at least %u,"
+ "but received %"PRIu64"\n", size, (*bo)->size);
+ nouveau_bo_ref(NULL, bo);
+ return -1;
+ }
+ dbg("prime flags %08x memtype %08x tile %08x\n", (*bo)->flags, (*bo)->config.nv50.memtype, (*bo)->config.nv50.tile_mode);
+ (*bo)->config.nv50.memtype = memtype;
+ (*bo)->config.nv50.tile_mode = tile_mode;
+ }
+ dbg("size: %"PRIu64"\n", (*bo)->size);
+
+ return ret;
+}
+
+static inline void
+PUSH_DATA(struct nouveau_pushbuf *push, uint32_t data)
+{
+ *push->cur++ = data;
+}
+
+static inline void
+BEGIN_NV04(struct nouveau_pushbuf *push, int subc, int mthd, int size)
+{
+ PUSH_DATA (push, 0x00000000 | (size << 18) | (subc << 13) | mthd);
+}
+
+static inline void
+BEGIN_NI04(struct nouveau_pushbuf *push, int subc, int mthd, int size)
+{
+ PUSH_DATA (push, 0x40000000 | (size << 18) | (subc << 13) | mthd);
+}
+
+static inline void
+BEGIN_NVC0(struct nouveau_pushbuf *push, int subc, int mthd, int size)
+{
+ PUSH_DATA (push, 0x20000000 | (size << 16) | (subc << 13) | (mthd / 4));
+}
+
+static inline void
+BEGIN_NVXX(struct nouveau_pushbuf *push, int subc, int mthd, int size)
+{
+ if (ndev->chipset < 0xc0)
+ BEGIN_NV04(push, subc, mthd, size);
+ else
+ BEGIN_NVC0(push, subc, mthd, size);
+}
+
+static void
+noop_intel(drm_intel_bo *bo)
+{
+ BEGIN_BATCH(3);
+ OUT_BATCH(MI_NOOP);
+ OUT_BATCH(MI_BATCH_BUFFER_END);
+ OUT_RELOC(bo, I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER, 0);
+ ADVANCE_BATCH();
+
+ intel_batchbuffer_flush(batch);
+}
+
+static int find_and_open_devices(void)
+{
+ int i;
+ char path[80], *unused;
+ struct stat buf;
+ FILE *fl;
+ char vendor_id[8] = {};
+ int venid;
+ for (i = 0; i < 9; i++) {
+ sprintf(path, "/sys/class/drm/card%d/device/vendor", i);
+ if (stat(path, &buf))
+ break;
+
+ fl = fopen(path, "r");
+ if (!fl)
+ break;
+
+ unused = fgets(vendor_id, sizeof(vendor_id)-1, fl);
+ (void)unused;
+ fclose(fl);
+
+ venid = strtoul(vendor_id, NULL, 16);
+ sprintf(path, "/dev/dri/card%d", i);
+ if (venid == 0x8086) {
+ intel_fd = open(path, O_RDWR);
+ if (!intel_fd)
+ return -1;
+ } else if (venid == 0x10de) {
+ nouveau_fd = open(path, O_RDWR);
+ if (!nouveau_fd)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int init_nouveau(void)
+{
+ struct nv04_fifo nv04_data = { .vram = 0xbeef0201,
+ .gart = 0xbeef0202 };
+ struct nvc0_fifo nvc0_data = { };
+ struct nouveau_fifo *fifo;
+ int size, ret;
+ uint32_t class;
+ void *data;
+
+ ret = nouveau_device_wrap(nouveau_fd, 0, &ndev);
+ if (ret < 0) {
+ fprintf(stderr,"failed to wrap nouveau device\n");
+ return ret;
+ }
+
+ ret = nouveau_client_new(ndev, &nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to setup nouveau client\n");
+ return ret;
+ }
+
+ if (ndev->chipset < 0xa3 || ndev->chipset == 0xaa || ndev->chipset == 0xac) {
+ fprintf(stderr, "Your card doesn't support PCOPY\n");
+ return -1;
+ }
+
+ // TODO: Get a kepler and add support for it
+ if (ndev->chipset >= 0xe0) {
+ fprintf(stderr, "Unsure how kepler works!\n");
+ return -1;
+ }
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 4096, 4096, NULL, &query_bo);
+ if (!ret)
+ ret = nouveau_bo_map(query_bo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to setup query counter\n");
+ return ret;
+ }
+ query = query_bo->map;
+ *query = query_counter;
+
+ if (ndev->chipset < 0xc0) {
+ class = 0x85b5;
+ data = &nv04_data;
+ size = sizeof(nv04_data);
+ } else {
+ class = ndev->chipset < 0xe0 ? 0x490b5 : 0xa0b5;
+ data = &nvc0_data;
+ size = sizeof(nvc0_data);
+ }
+
+ ret = nouveau_object_new(&ndev->object, 0, NOUVEAU_FIFO_CHANNEL_CLASS,
+ data, size, &nchannel);
+ if (ret) {
+ fprintf(stderr, "Error creating GPU channel: %d\n", ret);
+ if (ret == -ENODEV) {
+ fprintf(stderr, "Make sure nouveau_accel is active\n");
+ fprintf(stderr, "nvd9 is likely broken regardless\n");
+ }
+ return ret;
+ }
+
+ fifo = nchannel->data;
+
+ ret = nouveau_pushbuf_new(nclient, nchannel, 4, 32 * 1024,
+ true, &npush);
+ if (ret) {
+ fprintf(stderr, "Error allocating DMA push buffer: %d\n", ret);
+ return ret;
+ }
+
+ ret = nouveau_bufctx_new(nclient, 1, &nbufctx);
+ if (ret) {
+ fprintf(stderr, "Error allocating buffer context: %d\n", ret);
+ return ret;
+ }
+
+ npush->user_priv = nbufctx;
+
+ /* Hope this is enough init for PCOPY */
+ ret = nouveau_object_new(nchannel, class, class & 0xffff, NULL, 0, &pcopy);
+ if (ret) {
+ fprintf(stderr, "Failed to allocate pcopy: %d\n", ret);
+ return ret;
+ }
+ ret = nouveau_pushbuf_space(npush, 512, 0, 0);
+ if (ret) {
+ fprintf(stderr, "No space in pushbuf: %d\n", ret);
+ return ret;
+ }
+ if (ndev->chipset < 0xc0) {
+ struct nv04_fifo *nv04_fifo = (struct nv04_fifo*)fifo;
+ tile_intel_y = 0x3e;
+ tile_intel_x = 0x13;
+
+ BEGIN_NV04(npush, NV01_SUBC(COPY, OBJECT), 1);
+ PUSH_DATA(npush, pcopy->handle);
+ BEGIN_NV04(npush, SUBC_COPY(0x0180), 3);
+ PUSH_DATA(npush, nv04_fifo->vram);
+ PUSH_DATA(npush, nv04_fifo->vram);
+ PUSH_DATA(npush, nv04_fifo->vram);
+ } else {
+ tile_intel_y = 0x2e;
+ tile_intel_x = 0x03;
+ BEGIN_NVC0(npush, NV01_SUBC(COPY, OBJECT), 1);
+ PUSH_DATA(npush, pcopy->handle);
+ }
+ nouveau_pushbuf_kick(npush, npush->channel);
+ return ret;
+}
+
+static void fill16(void *ptr, uint32_t val)
+{
+ uint32_t *p = ptr;
+ val = (val) | (val << 8) | (val << 16) | (val << 24);
+ p[0] = p[1] = p[2] = p[3] = val;
+}
+
+#define TILE_SIZE 4096
+
+static int swtile_y(uint8_t *out, const uint8_t *in, int w, int h)
+{
+ uint32_t x, y, dx, dy;
+ uint8_t *endptr = out + w * h;
+ assert(!(w % 128));
+ assert(!(h % 32));
+
+ for (y = 0; y < h; y += 32) {
+ for (x = 0; x < w; x += 128, out += TILE_SIZE) {
+ for (dx = 0; dx < 8; ++dx) {
+ for (dy = 0; dy < 32; ++dy) {
+ uint32_t out_ofs = (dx * 32 + dy) * 16;
+ uint32_t in_ofs = (y + dy) * w + (x + 16 * dx);
+ assert(out_ofs < TILE_SIZE);
+ assert(in_ofs < w*h);
+
+ // To do the Y tiling quirk:
+ // out_ofs = out_ofs ^ (((out_ofs >> 9) & 1) << 6);
+ memcpy(&out[out_ofs], &in[in_ofs], 16);
+ }
+ }
+ }
+ }
+ assert(out == endptr);
+ return 0;
+}
+
+static int swtile_x(uint8_t *out, const uint8_t *in, int w, int h)
+{
+ uint32_t x, y, dy;
+ uint8_t *endptr = out + w * h;
+ assert(!(w % 512));
+ assert(!(h % 8));
+
+ for (y = 0; y < h; y += 8) {
+ for (x = 0; x < w; x += 512, out += TILE_SIZE) {
+ for (dy = 0; dy < 8; ++dy) {
+ uint32_t out_ofs = 512 * dy;
+ uint32_t in_ofs = (y + dy) * w + x;
+ assert(out_ofs < TILE_SIZE);
+ assert(in_ofs < w*h);
+ memcpy(&out[out_ofs], &in[in_ofs], 512);
+ }
+ }
+ }
+ assert(out == endptr);
+ return 0;
+}
+
+#if 0
+/* X tiling is approximately linear, except tiled in 512x8 blocks, so lets abuse that
+ *
+ * How? Whole contiguous tiles can be copied safely as if linear
+ */
+
+static int perform_copy_hack(struct nouveau_bo *nvbo, const rect *dst,
+ uint32_t dst_x, uint32_t dst_y,
+ struct nouveau_bo *nvbi, const rect *src,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t w, uint32_t h)
+{
+ struct nouveau_pushbuf_refn refs[] = {
+ { nvbi, (nvbi->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_RD },
+ { nvbo, (nvbo->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_WR },
+ { query_bo, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR }
+ };
+ uint32_t exec = 0x00000000;
+ uint32_t src_off = 0, dst_off = 0;
+ struct nouveau_pushbuf *push = npush;
+ uint32_t dw, tiles, tile_src = nvbi->config.nv50.tile_mode, tile_dst = nvbo->config.nv50.tile_mode;
+
+ if (tile_src == tile_intel_x)
+ dw = 512 - (src_x & 512);
+ else
+ dw = 512 - (dst_x % 512);
+
+ if (!nvbi->config.nv50.memtype)
+ exec |= 0x00000010;
+ if (!tile_src)
+ src_off = src_y * src->pitch + src_x;
+
+ if (!nvbo->config.nv50.memtype)
+ exec |= 0x00000100;
+ if (!tile_dst)
+ dst_off = dst_y * dst->pitch + dst_x;
+
+ if (dw > w)
+ dw = w;
+ tiles = 1 + ((w - dw + 511)/512);
+
+ if (nouveau_pushbuf_space(push, 8 + tiles * 32, 0, 0) ||
+ nouveau_pushbuf_refn(push, refs, 3))
+ return -1;
+
+ for (; w; w -= dw, src_x += dw, dst_x += dw, dw = w > 512 ? 512 : w) {
+ if (tile_src == tile_intel_x) {
+ /* Find the correct tiled offset */
+ src_off = 8 * dst->pitch * (src_y / 8);
+ src_off += src_x / 512 * 4096;
+ src_off += (src_x % 512) + 512 * (src_y % 8);
+
+ if (!tile_dst)
+ dst_off = dst_y * dst->pitch + dst_x;
+ } else {
+ if (!tile_src)
+ src_off = src_y * src->pitch + src_x;
+
+ dst_off = 8 * dst->pitch * (dst_y / 8);
+ dst_off += dst_x / 512 * 4096;
+ dst_off += (dst_x % 512) + 512 * (dst_y % 8);
+ }
+
+ fprintf(stderr, "Copying from %u to %u for %u bytes\n", src_x, dst_x, dw);
+ fprintf(stderr, "src ofs: %u, dst ofs: %u\n", src_off, dst_off);
+ BEGIN_NVXX(push, SUBC_COPY(0x0200), 7);
+ PUSH_DATA (push, tile_src == tile_intel_x ? 0 : nvbi->config.nv50.tile_mode);
+ PUSH_DATA (push, src->pitch);
+ PUSH_DATA (push, src->h);
+ PUSH_DATA (push, 1);
+ PUSH_DATA (push, 0);
+ PUSH_DATA (push, src_x);
+ PUSH_DATA (push, src_y);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0220), 7);
+ PUSH_DATA (push, tile_dst == tile_intel_x ? 0 : nvbo->config.nv50.tile_mode);
+ PUSH_DATA (push, dst->pitch);
+ PUSH_DATA (push, dst->h);
+ PUSH_DATA (push, 1);
+ PUSH_DATA (push, 0);
+ PUSH_DATA (push, dst_x);
+ PUSH_DATA (push, dst_y);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x030c), 8);
+ PUSH_DATA (push, (nvbi->offset + src_off) >> 32);
+ PUSH_DATA (push, (nvbi->offset + src_off));
+ PUSH_DATA (push, (nvbo->offset + dst_off) >> 32);
+ PUSH_DATA (push, (nvbo->offset + dst_off));
+ PUSH_DATA (push, src->pitch);
+ PUSH_DATA (push, dst->pitch);
+ PUSH_DATA (push, dw);
+ PUSH_DATA (push, h);
+
+ if (w == dw) {
+ exec |= 0x3000; /* QUERY|QUERY_SHORT */
+ BEGIN_NVXX(push, SUBC_COPY(0x0338), 3);
+ PUSH_DATA (push, (query_bo->offset) >> 32);
+ PUSH_DATA (push, (query_bo->offset));
+ PUSH_DATA (push, ++query_counter);
+ }
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0300), 1);
+ PUSH_DATA (push, exec);
+ }
+ nouveau_pushbuf_kick(push, push->channel);
+ while (*query < query_counter) { }
+ return 0;
+}
+#endif
+
+static int perform_copy(struct nouveau_bo *nvbo, const rect *dst,
+ uint32_t dst_x, uint32_t dst_y,
+ struct nouveau_bo *nvbi, const rect *src,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t w, uint32_t h)
+{
+#if 0
+ /* Too much effort */
+ if (nvbi->config.nv50.tile_mode == tile_intel_x &&
+ nvbo->config.nv50.tile_mode == tile_intel_x)
+ return -1;
+ else if (nvbi->config.nv50.tile_mode == tile_intel_x ||
+ nvbo->config.nv50.tile_mode == tile_intel_x)
+ return perform_copy_hack(nvbo, dst, dst_x, dst_y,
+ nvbi, src, src_x, src_y, w, h);
+#endif
+ struct nouveau_pushbuf_refn refs[] = {
+ { nvbi, (nvbi->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_RD },
+ { nvbo, (nvbo->flags & NOUVEAU_BO_APER) | NOUVEAU_BO_WR },
+ { query_bo, NOUVEAU_BO_GART | NOUVEAU_BO_RDWR }
+ };
+ uint32_t cpp = 1, exec = 0x00003000; /* QUERY|QUERY_SHORT|FORMAT */
+ uint32_t src_off = 0, dst_off = 0;
+ struct nouveau_pushbuf *push = npush;
+
+ if (nvbi->config.nv50.tile_mode == tile_intel_y)
+ dbg("src is y-tiled\n");
+ if (nvbo->config.nv50.tile_mode == tile_intel_y)
+ dbg("dst is y-tiled\n");
+
+ if (nouveau_pushbuf_space(push, 64, 0, 0) ||
+ nouveau_pushbuf_refn(push, refs, 3))
+ return -1;
+
+ if (!nvbi->config.nv50.tile_mode) {
+ src_off = src_y * src->pitch + src_x;
+ exec |= 0x00000010;
+ }
+
+ if (!nvbo->config.nv50.tile_mode) {
+ dst_off = dst_y * dst->pitch + dst_x;
+ exec |= 0x00000100;
+ }
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0200), 7);
+ PUSH_DATA (push, nvbi->config.nv50.tile_mode);
+ PUSH_DATA (push, src->pitch / cpp);
+ PUSH_DATA (push, src->h);
+ PUSH_DATA (push, 1);
+ PUSH_DATA (push, 0);
+ PUSH_DATA (push, src_x / cpp);
+ PUSH_DATA (push, src_y);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0220), 7);
+ PUSH_DATA (push, nvbo->config.nv50.tile_mode);
+ PUSH_DATA (push, dst->pitch / cpp);
+ PUSH_DATA (push, dst->h);
+ PUSH_DATA (push, 1);
+ PUSH_DATA (push, 0);
+ PUSH_DATA (push, dst_x / cpp);
+ PUSH_DATA (push, dst_y);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x030c), 9);
+ PUSH_DATA (push, (nvbi->offset + src_off) >> 32);
+ PUSH_DATA (push, (nvbi->offset + src_off));
+ PUSH_DATA (push, (nvbo->offset + dst_off) >> 32);
+ PUSH_DATA (push, (nvbo->offset + dst_off));
+ PUSH_DATA (push, src->pitch);
+ PUSH_DATA (push, dst->pitch);
+ PUSH_DATA (push, w / cpp);
+ PUSH_DATA (push, h);
+ PUSH_DATA (push, 0x03333120);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0338), 3);
+ PUSH_DATA (push, (query_bo->offset) >> 32);
+ PUSH_DATA (push, (query_bo->offset));
+ PUSH_DATA (push, ++query_counter);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0300), 1);
+ PUSH_DATA (push, exec);
+
+ nouveau_pushbuf_kick(push, push->channel);
+ while (*query < query_counter) { usleep(1000); }
+ return 0;
+}
+
+static int check1_macro(uint32_t *p, uint32_t w, uint32_t h)
+{
+ uint32_t i, val, j;
+
+ for (i = 0; i < 256; ++i, p += 4) {
+ val = (i) | (i << 8) | (i << 16) | (i << 24);
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in first tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+
+ val = 0x3e3e3e3e;
+ for (i = 0; i < 256 * (w-1); ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in second tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+
+ for (j = 1; j < h; ++j) {
+ val = 0x7e7e7e7e;
+ for (i = 0; i < 256; ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in third tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+
+ val = 0xcececece;
+ for (i = 0; i < 256 * (w-1); ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in fourth tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* test 1, see if we can copy from linear to intel Y format safely */
+static int test1_macro(void)
+{
+ int ret, prime_fd = -1;
+ struct nouveau_bo *nvbo = NULL, *nvbi = NULL;
+ rect dst, src;
+ uint8_t *ptr;
+ uint32_t w = 2 * 128, h = 2 * 32, x, y;
+
+ ret = nv_bo_alloc(&nvbi, &src, w, h, 0, -1, NOUVEAU_BO_GART);
+ if (ret >= 0)
+ ret = nv_bo_alloc(&nvbo, &dst, w, h, tile_intel_y, -1, NOUVEAU_BO_GART);
+ if (ret < 0)
+ goto out;
+
+ nouveau_bo_set_prime(nvbo, &prime_fd);
+
+ /* Set up something for our tile that should map into the first
+ * y-major tile, assuming my understanding of documentation is
+ * correct
+ */
+
+ /* First tile should be read out in groups of 16 bytes that
+ * are all set to a linear increasing value..
+ */
+ ptr = nvbi->map;
+ for (x = 0; x < 128; x += 16)
+ for (y = 0; y < 32; ++y)
+ fill16(&ptr[y * w + x], x * 2 + y);
+
+ /* second tile */
+ for (x = 128; x < w; x += 16)
+ for (y = 0; y < 32; ++y)
+ fill16(&ptr[y * w + x], 0x3e);
+
+ /* third tile */
+ for (x = 0; x < 128; x += 16)
+ for (y = 32; y < h; ++y)
+ fill16(&ptr[y * w + x], 0x7e);
+
+ /* last tile */
+ for (x = 128; x < w; x += 16)
+ for (y = 32; y < h; ++y)
+ fill16(&ptr[y * w + x], 0xce);
+ memset(nvbo->map, 0xfc, w * h);
+
+ if (pcopy)
+ ret = perform_copy(nvbo, &dst, 0, 0, nvbi, &src, 0, 0, w, h);
+ else
+ ret = swtile_y(nvbo->map, nvbi->map, w, h);
+ if (!ret)
+ ret = check1_macro(nvbo->map, w/128, h/32);
+
+out:
+ nouveau_bo_ref(NULL, &nvbo);
+ nouveau_bo_ref(NULL, &nvbi);
+ close(prime_fd);
+ return ret;
+}
+
+static int dump_line(uint8_t *map)
+{
+ uint32_t dx, dy;
+ fprintf(stderr, "Dumping sub-tile:\n");
+ for (dy = 0; dy < 32; ++dy) {
+ for (dx = 0; dx < 15; ++dx, ++map) {
+ fprintf(stderr, "%02x ", *map);
+ }
+ fprintf(stderr, "%02x\n", *(map++));
+ }
+ return -1;
+}
+
+static int check1_micro(void *map, uint32_t pitch, uint32_t lines,
+ uint32_t dst_x, uint32_t dst_y, uint32_t w, uint32_t h)
+{
+ uint32_t x, y;
+
+ /* check only the relevant subrectangle [0..w) [0...h) */
+ uint8_t *m = map;
+ for (y = 0; y < h; ++y, m += pitch) {
+ for (x = 0; x < w; ++x) {
+ uint8_t expected = ((y & 3) << 6) | (x & 0x3f);
+ if (expected != m[x]) {
+ fprintf(stderr, "failed check at x=%u y=%u, expected %02x got %02x\n",
+ x, y, expected, m[x]);
+ return dump_line(m);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* test 1, but check micro format, should be unaffected by bit9 swizzling */
+static int test1_micro(void)
+{
+ struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL;
+ rect intel, nvidia, linear;
+ int ret = -1;
+ uint32_t tiling = I915_TILING_Y;
+
+ uint32_t src_x = 0, src_y = 0;
+ uint32_t dst_x = 0, dst_y = 0;
+ uint32_t x, y, w = 256, h = 64;
+
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", w * h, 4096);
+ if (!test_intel_bo)
+ return -1;
+ drm_intel_bo_set_tiling(test_intel_bo, &tiling, w);
+ if (tiling != I915_TILING_Y) {
+ fprintf(stderr, "Couldn't set y tiling\n");
+ goto out;
+ }
+ ret = drm_intel_gem_bo_map_gtt(test_intel_bo);
+ if (ret)
+ goto out;
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (prime_fd < 0) {
+ drm_intel_bo_unreference(test_intel_bo);
+ goto out;
+ }
+ noop_intel(test_intel_bo);
+
+ ret = nv_bo_alloc(&bo_intel, &intel, w, h, tile_intel_y, prime_fd, 0);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_nvidia, &nvidia, w, h, 0x10, -1, NOUVEAU_BO_VRAM);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_linear, &linear, w, h, 0, -1, NOUVEAU_BO_GART);
+ if (ret)
+ goto out;
+
+ for (y = 0; y < linear.h; ++y) {
+ uint8_t *map = bo_linear->map;
+ map += y * linear.pitch;
+ for (x = 0; x < linear.pitch; ++x) {
+ uint8_t pos = x & 0x3f;
+ /* low 4 bits: micro tile pos */
+ /* 2 bits: x pos in tile (wraps) */
+ /* 2 bits: y pos in tile (wraps) */
+ pos |= (y & 3) << 6;
+ map[x] = pos;
+ }
+ }
+
+ ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h);
+ if (ret)
+ goto out;
+
+ /* Perform the actual sub rectangle copy */
+ if (pcopy)
+ ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h);
+ else
+ ret = swtile_y(test_intel_bo->virtual, bo_linear->map, w, h);
+ if (ret)
+ goto out;
+
+ noop_intel(test_intel_bo);
+ ret = check1_micro(test_intel_bo->virtual, intel.pitch, intel.h, dst_x, dst_y, w, h);
+
+out:
+ nouveau_bo_ref(NULL, &bo_linear);
+ nouveau_bo_ref(NULL, &bo_nvidia);
+ nouveau_bo_ref(NULL, &bo_intel);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+static int check1_swizzle(uint32_t *p, uint32_t pitch, uint32_t lines,
+ uint32_t dst_x, uint32_t dst_y, uint32_t w, uint32_t h)
+{
+ uint32_t i, val, j;
+
+ for (j = 0; j < 32; ++j, p += (pitch - w)/4) {
+ for (i = 0; i < 8; ++i, p += 4) {
+ val = (i * 32) + j;
+ val = (val) | (val << 8) | (val << 16) | (val << 24);
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in first tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+
+ val = 0x3e3e3e3e;
+ for (; i < w/16; ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in second tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+ }
+
+ for (j = 32; j < h; ++j, p += (pitch - w)/4) {
+ val = 0x7e7e7e7e;
+ for (i = 0; i < 8; ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in third tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+
+ val = 0xcececece;
+ for (; i < w/16; ++i, p += 4) {
+ if (p[0] != val || p[1] != val || p[2] != val || p[3] != val) {
+ fprintf(stderr, "Retile check failed in fourth tile!\n");
+ fprintf(stderr, "%08x %08x %08x %08x instead of %08x\n",
+ p[0], p[1], p[2], p[3], val);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* Create a new bo, set tiling to y, and see if macro swizzling is done correctl */
+static int test1_swizzle(void)
+{
+ struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL;
+ rect intel, nvidia, linear;
+ int ret = -1;
+ uint32_t tiling = I915_TILING_Y;
+
+ uint32_t src_x = 0, src_y = 0;
+ uint32_t dst_x = 0, dst_y = 0;
+ uint32_t x, y, w = 256, h = 64;
+ uint8_t *ptr;
+
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", w * h, 4096);
+ if (!test_intel_bo)
+ return -1;
+ drm_intel_bo_set_tiling(test_intel_bo, &tiling, w);
+ if (tiling != I915_TILING_Y) {
+ fprintf(stderr, "Couldn't set y tiling\n");
+ goto out;
+ }
+ ret = drm_intel_gem_bo_map_gtt(test_intel_bo);
+ if (ret)
+ goto out;
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (prime_fd < 0) {
+ drm_intel_bo_unreference(test_intel_bo);
+ goto out;
+ }
+
+ ret = nv_bo_alloc(&bo_intel, &intel, w, h, tile_intel_y, prime_fd, 0);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_nvidia, &nvidia, w, h, 0x10, -1, NOUVEAU_BO_VRAM);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_linear, &linear, w, h, 0, -1, NOUVEAU_BO_GART);
+ if (ret)
+ goto out;
+
+ noop_intel(test_intel_bo);
+ ptr = bo_linear->map;
+ for (x = 0; x < 128; x += 16)
+ for (y = 0; y < 32; ++y)
+ fill16(&ptr[y * w + x], x * 2 + y);
+
+ /* second tile */
+ for (x = 128; x < w; x += 16)
+ for (y = 0; y < 32; ++y)
+ fill16(&ptr[y * w + x], 0x3e);
+
+ /* third tile */
+ for (x = 0; x < 128; x += 16)
+ for (y = 32; y < h; ++y)
+ fill16(&ptr[y * w + x], 0x7e);
+
+ /* last tile */
+ for (x = 128; x < w; x += 16)
+ for (y = 32; y < h; ++y)
+ fill16(&ptr[y * w + x], 0xce);
+
+ ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h);
+ if (ret)
+ goto out;
+
+ /* Perform the actual sub rectangle copy */
+ ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h);
+ if (ret)
+ goto out;
+ noop_intel(test_intel_bo);
+
+ ret = check1_swizzle(test_intel_bo->virtual, intel.pitch, intel.h, dst_x, dst_y, w, h);
+
+out:
+ nouveau_bo_ref(NULL, &bo_linear);
+ nouveau_bo_ref(NULL, &bo_nvidia);
+ nouveau_bo_ref(NULL, &bo_intel);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* test 2, see if we can copy from linear to intel X format safely
+ * Seems nvidia lacks a method to do it, so just keep this test
+ * as a reference for potential future tests. Software tiling is
+ * used for now
+ */
+static int test2(void)
+{
+ int ret;
+ struct nouveau_bo *nvbo = NULL, *nvbi = NULL;
+ rect dst, src;
+ uint8_t *ptr;
+ uint32_t w = 1024, h = 16, x, y;
+
+ ret = nv_bo_alloc(&nvbi, &src, w, h, 0, -1, NOUVEAU_BO_GART);
+ if (ret >= 0)
+ ret = nv_bo_alloc(&nvbo, &dst, w, h, tile_intel_x, -1, NOUVEAU_BO_GART);
+ if (ret < 0)
+ goto out;
+
+ /* Set up something for our tile that should map into the first
+ * y-major tile, assuming my understanding of documentation is
+ * correct
+ */
+
+ /* First tile should be read out in groups of 16 bytes that
+ * are all set to a linear increasing value..
+ */
+ ptr = nvbi->map;
+ for (y = 0; y < 8; ++y)
+ for (x = 0; x < 512; x += 16)
+ fill16(&ptr[y * w + x], (y * 512 + x)/16);
+
+ for (y = 0; y < 8; ++y)
+ for (x = 512; x < w; x += 16)
+ fill16(&ptr[y * w + x], 0x3e);
+
+ for (y = 8; y < h; ++y)
+ for (x = 0; x < 512; x += 16)
+ fill16(&ptr[y * w + x], 0x7e);
+
+ for (y = 8; y < h; ++y)
+ for (x = 512; x < w; x += 16)
+ fill16(&ptr[y * w + x], 0xce);
+ memset(nvbo->map, 0xfc, w * h);
+
+ /* do this in software, there is no X major tiling in PCOPY (yet?) */
+ if (0 && pcopy)
+ ret = perform_copy(nvbo, &dst, 0, 0, nvbi, &src, 0, 0, w, h);
+ else
+ ret = swtile_x(nvbo->map, nvbi->map, w, h);
+ if (!ret)
+ ret = check1_macro(nvbo->map, w/512, h/8);
+
+out:
+ nouveau_bo_ref(NULL, &nvbo);
+ nouveau_bo_ref(NULL, &nvbi);
+ return ret;
+}
+
+static int check3(const uint32_t *p, uint32_t pitch, uint32_t lines,
+ uint32_t sub_x, uint32_t sub_y,
+ uint32_t sub_w, uint32_t sub_h)
+{
+ uint32_t x, y;
+
+ sub_w += sub_x;
+ sub_h += sub_y;
+
+ if (p[pitch * lines / 4 - 1] == 0x03030303) {
+ fprintf(stderr, "copy failed: Not all lines have been copied back!\n");
+ return -1;
+ }
+
+ for (y = 0; y < lines; ++y) {
+ for (x = 0; x < pitch; x += 4, ++p) {
+ uint32_t expected;
+ if ((x < sub_x || x >= sub_w) ||
+ (y < sub_y || y >= sub_h))
+ expected = 0x80808080;
+ else
+ expected = 0x04040404;
+ if (*p != expected) {
+ fprintf(stderr, "%u,%u should be %08x, but is %08x\n", x, y, expected, *p);
+ return -1;
+ }
+ }
+ }
+ return 0;
+}
+
+/* copy from nvidia bo to intel bo and copy to a linear bo to check if tiling went succesful */
+static int test3_base(int tile_src, int tile_dst)
+{
+ struct nouveau_bo *bo_intel = NULL, *bo_nvidia = NULL, *bo_linear = NULL;
+ rect intel, nvidia, linear;
+ int ret;
+ uint32_t cpp = 4;
+
+ uint32_t src_x = 1 * cpp, src_y = 1;
+ uint32_t dst_x = 2 * cpp, dst_y = 26;
+ uint32_t w = 298 * cpp, h = 298;
+
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", 2048 * cpp * 768, 4096);
+ if (!test_intel_bo)
+ return -1;
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (prime_fd < 0) {
+ drm_intel_bo_unreference(test_intel_bo);
+ return -1;
+ }
+
+ ret = nv_bo_alloc(&bo_intel, &intel, 2048 * cpp, 768, tile_dst, prime_fd, 0);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_nvidia, &nvidia, 300 * cpp, 300, tile_src, -1, NOUVEAU_BO_VRAM);
+ if (!ret)
+ ret = nv_bo_alloc(&bo_linear, &linear, 2048 * cpp, 768, 0, -1, NOUVEAU_BO_GART);
+ if (ret)
+ goto out;
+
+ noop_intel(test_intel_bo);
+ memset(bo_linear->map, 0x80, bo_linear->size);
+ ret = perform_copy(bo_intel, &intel, 0, 0, bo_linear, &linear, 0, 0, linear.pitch, linear.h);
+ if (ret)
+ goto out;
+ noop_intel(test_intel_bo);
+
+ memset(bo_linear->map, 0x04, bo_linear->size);
+ ret = perform_copy(bo_nvidia, &nvidia, 0, 0, bo_linear, &linear, 0, 0, nvidia.pitch, nvidia.h);
+ if (ret)
+ goto out;
+
+ /* Perform the actual sub rectangle copy */
+ noop_intel(test_intel_bo);
+ ret = perform_copy(bo_intel, &intel, dst_x, dst_y, bo_nvidia, &nvidia, src_x, src_y, w, h);
+ if (ret)
+ goto out;
+ noop_intel(test_intel_bo);
+
+ memset(bo_linear->map, 0x3, bo_linear->size);
+ noop_intel(test_intel_bo);
+ ret = perform_copy(bo_linear, &linear, 0, 0, bo_intel, &intel, 0, 0, intel.pitch, intel.h);
+ if (ret)
+ goto out;
+ noop_intel(test_intel_bo);
+
+ ret = check3(bo_linear->map, linear.pitch, linear.h, dst_x, dst_y, w, h);
+
+out:
+ nouveau_bo_ref(NULL, &bo_linear);
+ nouveau_bo_ref(NULL, &bo_nvidia);
+ nouveau_bo_ref(NULL, &bo_intel);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+static int test3_1(void)
+{
+ /* nvidia tiling to intel */
+ return test3_base(0x40, tile_intel_y);
+}
+
+static int test3_2(void)
+{
+ /* intel tiling to nvidia */
+ return test3_base(tile_intel_y, 0x40);
+}
+
+static int test3_3(void)
+{
+ /* intel tiling to linear */
+ return test3_base(tile_intel_y, 0);
+}
+
+static int test3_4(void)
+{
+ /* linear tiling to intel */
+ return test3_base(0, tile_intel_y);
+}
+
+static int test3_5(void)
+{
+ /* linear to linear */
+ return test3_base(0, 0);
+}
+
+/* Acquire when == SEQUENCE */
+#define SEMA_ACQUIRE_EQUAL 1
+
+/* Release, and write a 16 byte query structure to sema:
+ * { (uint32)seq, (uint32)0, (uint64)timestamp } */
+#define SEMA_WRITE_LONG 2
+
+/* Acquire when >= SEQUENCE */
+#define SEMA_ACQUIRE_GEQUAL 4
+
+/* Test only new style semaphores, old ones are AWFUL */
+static int test_semaphore(void)
+{
+ drm_intel_bo *test_intel_bo = NULL;
+ struct nouveau_bo *sema_bo = NULL;
+ int ret = -1, prime_fd;
+ uint32_t *sema;
+ struct nouveau_pushbuf *push = npush;
+
+ if (ndev->chipset < 0x84)
+ return -1;
+
+ /* Should probably be kept in sysmem */
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "semaphore bo", 4096, 4096);
+ if (!test_intel_bo)
+ goto out;
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+ if (prime_fd < 0)
+ goto out;
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &sema_bo);
+ close(prime_fd);
+ if (ret < 0)
+ goto out;
+
+ ret = drm_intel_gem_bo_map_gtt(test_intel_bo);
+ if (ret != 0) {
+ fprintf(stderr,"failed to map bo\n");
+ goto out;
+ }
+ sema = test_intel_bo->virtual;
+ sema++;
+ *sema = 0;
+
+ ret = -1;
+ if (nouveau_pushbuf_space(push, 64, 0, 0) ||
+ nouveau_pushbuf_refn(push, &(struct nouveau_pushbuf_refn)
+ { sema_bo, NOUVEAU_BO_GART|NOUVEAU_BO_RDWR }, 1))
+ goto out;
+
+ if (ndev->chipset < 0xc0) {
+ struct nv04_fifo *nv04_fifo = nchannel->data;
+ /* kernel binds it's own dma object here and overwrites old one,
+ * so just rebind vram every time we submit
+ */
+ BEGIN_NV04(npush, SUBC_COPY(0x0060), 1);
+ PUSH_DATA(npush, nv04_fifo->vram);
+ }
+ BEGIN_NVXX(push, SUBC_COPY(0x0010), 4);
+ PUSH_DATA(push, sema_bo->offset >> 32);
+ PUSH_DATA(push, sema_bo->offset + 4);
+ PUSH_DATA(push, 2); // SEQUENCE
+ PUSH_DATA(push, SEMA_WRITE_LONG); // TRIGGER
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 3);
+ PUSH_DATA(push, SEMA_ACQUIRE_EQUAL);
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 4);
+ PUSH_DATA(push, SEMA_WRITE_LONG);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 5);
+ PUSH_DATA(push, SEMA_ACQUIRE_GEQUAL);
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 6);
+ PUSH_DATA(push, SEMA_WRITE_LONG);
+
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 7);
+ PUSH_DATA(push, SEMA_ACQUIRE_GEQUAL);
+ BEGIN_NVXX(push, SUBC_COPY(0x0018), 2);
+ PUSH_DATA(push, 9);
+ PUSH_DATA(push, SEMA_WRITE_LONG);
+ nouveau_pushbuf_kick(push, push->channel);
+
+ usleep(1000);
+ if (*sema != 2) {
+ fprintf(stderr, "new sema should be 2 is %u\n", *sema);
+ goto out;
+ }
+
+ *sema = 3;
+ usleep(1000);
+ if (*sema != 4) {
+ fprintf(stderr, "new sema should be 4 is %u\n", *sema);
+ goto out;
+ }
+
+ *sema = 5;
+ usleep(1000);
+ if (*sema != 6) {
+ fprintf(stderr, "new sema should be 6 is %u\n", *sema);
+ goto out;
+ }
+
+ *sema = 8;
+ usleep(1000);
+ if (*sema != 9) {
+ fprintf(stderr, "new sema should be 9 is %u\n", *sema);
+ goto out;
+ }
+ ret = 0;
+
+out:
+ nouveau_bo_ref(NULL, &sema_bo);
+ if (test_intel_bo)
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+int main(int argc, char **argv)
+{
+ int ret, failed = 0, run = 0;
+
+ ret = find_and_open_devices();
+ if (ret < 0)
+ return ret;
+
+ if (nouveau_fd == -1 || intel_fd == -1) {
+ fprintf(stderr,"failed to find intel and nouveau GPU\n");
+ return 77;
+ }
+
+ /* set up intel bufmgr */
+ bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096);
+ if (!bufmgr)
+ return -1;
+ /* Do not enable reuse, we share (almost) all buffers. */
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ /* set up nouveau bufmgr */
+ ret = init_nouveau();
+ if (ret < 0)
+ return 77;
+
+ /* set up an intel batch buffer */
+ devid = intel_get_drm_devid(intel_fd);
+ batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+#define xtest(x, args...) do { \
+ ret = ((x)(args)); \
+ ++run; \
+ if (ret) { \
+ ++failed; \
+ fprintf(stderr, "prime_pcopy: failed " #x "\n"); } \
+ } while (0)
+
+ xtest(test1_macro);
+ xtest(test1_micro);
+ xtest(test1_swizzle);
+ xtest(test2);
+ xtest(test3_1);
+ xtest(test3_2);
+ xtest(test3_3);
+ xtest(test3_4);
+ xtest(test3_5);
+ xtest(test_semaphore);
+
+ nouveau_bo_ref(NULL, &query_bo);
+ nouveau_object_del(&pcopy);
+ nouveau_bufctx_del(&nbufctx);
+ nouveau_pushbuf_del(&npush);
+ nouveau_object_del(&nchannel);
+
+ intel_batchbuffer_free(batch);
+
+ nouveau_client_del(&nclient);
+ nouveau_device_del(&ndev);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(intel_fd);
+ close(nouveau_fd);
+
+ printf("Tests: %u run, %u failed\n", run, failed);
+ return failed;
+}
diff --git a/tests/prime_nv_test.c b/tests/prime_nv_test.c
new file mode 100644
index 00000000..2269f84f
--- /dev/null
+++ b/tests/prime_nv_test.c
@@ -0,0 +1,582 @@
+/* basic set of prime tests between intel and nouveau */
+
+/* test list -
+ 1. share buffer from intel -> nouveau.
+ 2. share buffer from nouveau -> intel
+ 3. share intel->nouveau, map on both, write intel, read nouveau
+ 4. share intel->nouveau, blit intel fill, readback on nouveau
+ test 1 + map buffer, read/write, map other size.
+ do some hw actions on the buffer
+ some illegal operations -
+ close prime fd try and map
+
+ TODO add some nouveau rendering tests
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include "i915_drm.h"
+#include "intel_bufmgr.h"
+#include "nouveau.h"
+#include "intel_gpu_tools.h"
+#include "intel_batchbuffer.h"
+
+int intel_fd = -1, nouveau_fd = -1;
+drm_intel_bufmgr *bufmgr;
+struct nouveau_device *ndev;
+struct nouveau_client *nclient;
+uint32_t devid;
+struct intel_batchbuffer *intel_batch;
+
+#define BO_SIZE (256*1024)
+
+static int find_and_open_devices(void)
+{
+ int i;
+ char path[80];
+ struct stat buf;
+ FILE *fl;
+ char vendor_id[8];
+ int venid;
+ for (i = 0; i < 9; i++) {
+ sprintf(path, "/sys/class/drm/card%d/device/vendor", i);
+ if (stat(path, &buf))
+ break;
+
+ fl = fopen(path, "r");
+ if (!fl)
+ break;
+
+ fgets(vendor_id, 8, fl);
+ fclose(fl);
+
+ venid = strtoul(vendor_id, NULL, 16);
+ sprintf(path, "/dev/dri/card%d", i);
+ if (venid == 0x8086) {
+ intel_fd = open(path, O_RDWR);
+ if (!intel_fd)
+ return -1;
+ } else if (venid == 0x10de) {
+ nouveau_fd = open(path, O_RDWR);
+ if (!nouveau_fd)
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * prime test 1 -
+ * allocate buffer on intel,
+ * set prime on buffer,
+ * retrive buffer from nouveau,
+ * close prime_fd,
+ * unref buffers
+ */
+static int test1(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ close(prime_fd);
+ if (ret < 0)
+ return ret;
+
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return 0;
+}
+
+/*
+ * prime test 2 -
+ * allocate buffer on nouveau
+ * set prime on buffer,
+ * retrive buffer from intel
+ * close prime_fd,
+ * unref buffers
+ */
+static int test2(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo;
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo)
+ return -1;
+
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return 0;
+}
+
+/*
+ * allocate intel, give to nouveau, map on nouveau
+ * write 0xdeadbeef, non-gtt map on intel, read
+ */
+static int test3(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL;
+ uint32_t *ptr;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ if (ret < 0) {
+ fprintf(stderr,"failed to ref prime buffer %d\n", ret);
+ close(prime_fd);
+ goto free_intel;
+ }
+ close(prime_fd);
+ goto free_intel;
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+ ptr = nvbo->map;
+ *ptr = 0xdeadbeef;
+
+ drm_intel_bo_map(test_intel_bo, 1);
+
+ ptr = test_intel_bo->virtual;
+
+ if (*ptr != 0xdeadbeef) {
+ fprintf(stderr,"mapped value doesn't match\n");
+ ret = -1;
+ }
+out:
+ nouveau_bo_ref(NULL, &nvbo);
+free_intel:
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/*
+ * allocate intel, give to nouveau, map on nouveau
+ * write 0xdeadbeef, gtt map on intel, read
+ */
+static int test4(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL;
+ uint32_t *ptr;
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ close(prime_fd);
+ if (ret < 0) {
+ fprintf(stderr,"failed to ref prime buffer\n");
+ return ret;
+ }
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+
+ ptr = nvbo->map;
+ *ptr = 0xdeadbeef;
+
+ drm_intel_gem_bo_map_gtt(test_intel_bo);
+ ptr = test_intel_bo->virtual;
+
+ if (*ptr != 0xdeadbeef) {
+ fprintf(stderr,"mapped value doesn't match\n");
+ ret = -1;
+ }
+out:
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* test drm_intel_bo_map doesn't work properly,
+ this tries to map the backing shmem fd, which doesn't exist
+ for these objects */
+static int test5(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo;
+ uint32_t *ptr;
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo)
+ return -1;
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+ ptr = nvbo->map;
+ *ptr = 0xdeadbeef;
+
+ ret = drm_intel_bo_map(test_intel_bo, 0);
+ if (ret != 0) {
+ /* failed to map the bo is expected */
+ ret = 0;
+ goto out;
+ }
+ if (!test_intel_bo->virtual) {
+ ret = 0;
+ goto out;
+ }
+ ptr = test_intel_bo->virtual;
+
+ if (*ptr != 0xdeadbeef) {
+ fprintf(stderr,"mapped value doesn't match %08x\n", *ptr);
+ ret = -1;
+ }
+ out:
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* test drm_intel_bo_map_gtt works properly,
+ this tries to map the backing shmem fd, which doesn't exist
+ for these objects */
+static int test6(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo;
+ uint32_t *ptr;
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo)
+ return -1;
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+ ptr = nvbo->map;
+ *ptr = 0xdeadbeef;
+ *(ptr + 1) = 0xa55a55;
+
+ ret = drm_intel_gem_bo_map_gtt(test_intel_bo);
+ if (ret != 0) {
+ fprintf(stderr,"failed to map bo\n");
+ goto out;
+ }
+ if (!test_intel_bo->virtual) {
+ ret = -1;
+ fprintf(stderr,"failed to map bo\n");
+ goto out;
+ }
+ ptr = test_intel_bo->virtual;
+
+ if (*ptr != 0xdeadbeef) {
+ fprintf(stderr,"mapped value doesn't match %08x %08x\n", *ptr, *(ptr + 1));
+ ret = -1;
+ }
+ out:
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+static int do_read(int fd, int handle, void *buf, int offset, int size)
+{
+ struct drm_i915_gem_pread intel_pread;
+
+ /* Ensure that we don't have any convenient data in buf in case
+ * we fail.
+ */
+ memset(buf, 0xd0, size);
+
+ memset(&intel_pread, 0, sizeof(intel_pread));
+ intel_pread.handle = handle;
+ intel_pread.data_ptr = (uintptr_t)buf;
+ intel_pread.size = size;
+ intel_pread.offset = offset;
+
+ return ioctl(fd, DRM_IOCTL_I915_GEM_PREAD, &intel_pread);
+}
+
+static int do_write(int fd, int handle, void *buf, int offset, int size)
+{
+ struct drm_i915_gem_pwrite intel_pwrite;
+
+ memset(&intel_pwrite, 0, sizeof(intel_pwrite));
+ intel_pwrite.handle = handle;
+ intel_pwrite.data_ptr = (uintptr_t)buf;
+ intel_pwrite.size = size;
+ intel_pwrite.offset = offset;
+
+ return ioctl(fd, DRM_IOCTL_I915_GEM_PWRITE, &intel_pwrite);
+}
+
+/* test 7 - import from nouveau into intel, test pread/pwrite fail */
+static int test7(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo;
+ uint32_t *ptr;
+ uint32_t buf[64];
+
+ ret = nouveau_bo_new(ndev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
+ 0, BO_SIZE, NULL, &nvbo);
+ if (ret < 0)
+ return ret;
+ ret = nouveau_bo_set_prime(nvbo, &prime_fd);
+ if (ret < 0)
+ return ret;
+
+ test_intel_bo = drm_intel_bo_gem_create_from_prime(bufmgr, prime_fd, BO_SIZE);
+ close(prime_fd);
+ if (!test_intel_bo)
+ return -1;
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+ ptr = nvbo->map;
+ *ptr = 0xdeadbeef;
+
+ ret = do_read(intel_fd, test_intel_bo->handle, buf, 0, 256);
+ if (ret != -1) {
+ fprintf(stderr,"pread succeedded %d\n", ret);
+ goto out;
+ }
+ buf[0] = 0xabcdef55;
+
+ ret = do_write(intel_fd, test_intel_bo->handle, buf, 0, 4);
+ if (ret != -1) {
+ fprintf(stderr,"pwrite succeedded\n");
+ goto out;
+ }
+ ret = 0;
+ out:
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+static void
+set_bo(drm_intel_bo *bo, uint32_t val, int width, int height)
+{
+ int size = width * height;
+ uint32_t *vaddr;
+
+ drm_intel_gem_bo_start_gtt_access(bo, true);
+ vaddr = bo->virtual;
+ while (size--)
+ *vaddr++ = val;
+}
+
+static drm_intel_bo *
+create_bo(drm_intel_bufmgr *ibufmgr, uint32_t val, int width, int height)
+{
+ drm_intel_bo *bo;
+
+ bo = drm_intel_bo_alloc(ibufmgr, "bo", 4*width*height, 0);
+ assert(bo);
+
+ /* gtt map doesn't have a write parameter, so just keep the mapping
+ * around (to avoid the set_domain with the gtt write domain set) and
+ * manually tell the kernel when we start access the gtt. */
+ drm_intel_gem_bo_map_gtt(bo);
+
+ set_bo(bo, val, width, height);
+
+ return bo;
+}
+
+/* use intel hw to fill the BO with a blit from another BO,
+ then readback from the nouveau bo, check value is correct */
+static int test8(void)
+{
+ int ret;
+ drm_intel_bo *test_intel_bo, *src_bo;
+ int prime_fd;
+ struct nouveau_bo *nvbo = NULL;
+ uint32_t *ptr;
+
+ src_bo = create_bo(bufmgr, 0xaa55aa55, 256, 1);
+
+ test_intel_bo = drm_intel_bo_alloc(bufmgr, "test bo", BO_SIZE, 4096);
+
+ drm_intel_bo_gem_export_to_prime(test_intel_bo, &prime_fd);
+
+ ret = nouveau_bo_prime_handle_ref(ndev, prime_fd, &nvbo);
+ close(prime_fd);
+ if (ret < 0) {
+ fprintf(stderr,"failed to ref prime buffer\n");
+ return ret;
+ }
+
+ intel_copy_bo(intel_batch, test_intel_bo, src_bo, 256, 1);
+
+ ret = nouveau_bo_map(nvbo, NOUVEAU_BO_RDWR, nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to map nouveau bo\n");
+ goto out;
+ }
+
+ drm_intel_bo_map(test_intel_bo, 0);
+
+ ptr = nvbo->map;
+ if (*ptr != 0xaa55aa55) {
+ fprintf(stderr,"mapped value doesn't match\n");
+ ret = -1;
+ }
+out:
+ nouveau_bo_ref(NULL, &nvbo);
+ drm_intel_bo_unreference(test_intel_bo);
+ return ret;
+}
+
+/* test 8 use nouveau to do blit */
+
+/* test 9 nouveau copy engine?? */
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ ret = find_and_open_devices();
+ if (ret < 0)
+ return ret;
+
+ if (nouveau_fd == -1 || intel_fd == -1) {
+ fprintf(stderr,"failed to find intel and nouveau GPU\n");
+ return 77;
+ }
+
+ /* set up intel bufmgr */
+ bufmgr = drm_intel_bufmgr_gem_init(intel_fd, 4096);
+ if (!bufmgr)
+ return -1;
+ /* Do not enable reuse, we share (almost) all buffers. */
+ //drm_intel_bufmgr_gem_enable_reuse(bufmgr);
+
+ /* set up nouveau bufmgr */
+ ret = nouveau_device_wrap(nouveau_fd, 0, &ndev);
+ if (ret < 0) {
+ fprintf(stderr,"failed to wrap nouveau device\n");
+ return 77;
+ }
+
+ ret = nouveau_client_new(ndev, &nclient);
+ if (ret < 0) {
+ fprintf(stderr,"failed to setup nouveau client\n");
+ return -1;
+ }
+
+ /* set up an intel batch buffer */
+ devid = intel_get_drm_devid(intel_fd);
+ intel_batch = intel_batchbuffer_alloc(bufmgr, devid);
+
+ /* create an object on the i915 */
+ ret = test1();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 1\n");
+
+ ret = test2();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 2\n");
+
+ ret = test3();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 3\n");
+
+ ret = test4();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 4\n");
+
+ ret = test5();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 5\n");
+
+ ret = test6();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 6\n");
+
+ ret = test7();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 7\n");
+
+ ret = test8();
+ if (ret)
+ fprintf(stderr,"prime_test: failed test 8\n");
+
+ intel_batchbuffer_free(intel_batch);
+
+ nouveau_device_del(&ndev);
+ drm_intel_bufmgr_destroy(bufmgr);
+
+ close(intel_fd);
+ close(nouveau_fd);
+
+ return ret;
+}
diff --git a/tests/prime_self_import.c b/tests/prime_self_import.c
new file mode 100644
index 00000000..111ed4da
--- /dev/null
+++ b/tests/prime_self_import.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright © 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:
+ * Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ */
+
+/*
+ * Testcase: Check whether prime import/export works on the same device
+ *
+ * ... but with different fds, i.e. the wayland usecase.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include "drm.h"
+#include "i915_drm.h"
+#include "drmtest.h"
+
+#define BO_SIZE (16*1024)
+
+static void
+check_bo(int fd1, uint32_t handle1, int fd2, uint32_t handle2)
+{
+ char *ptr1, *ptr2;
+ static char counter = 0;
+ int i;
+
+ ptr1 = gem_mmap(fd1, handle1, BO_SIZE, PROT_READ | PROT_WRITE);
+ ptr2 = gem_mmap(fd2, handle2, BO_SIZE, PROT_READ | PROT_WRITE);
+
+ assert(ptr1);
+
+ /* check whether it's still our old object first. */
+ for (i = 0; i < BO_SIZE; i++) {
+ assert(ptr1[i] == counter);
+ assert(ptr2[i] == counter);
+ }
+
+ counter++;
+
+ memset(ptr1, counter, BO_SIZE);
+ assert(memcmp(ptr1, ptr2, BO_SIZE) == 0);
+
+ munmap(ptr1, BO_SIZE);
+ munmap(ptr2, BO_SIZE);
+}
+
+int main(int argc, char **argv)
+{
+ int fd1, fd2;
+ uint32_t handle, handle_import1, handle_import2, handle_selfimport;
+ int dma_buf_fd;
+
+ fd1 = drm_open_any();
+ fd2 = drm_open_any();
+
+ handle = gem_create(fd1, BO_SIZE);
+
+ dma_buf_fd = prime_handle_to_fd(fd1, handle);
+ handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
+
+ check_bo(fd1, handle, fd2, handle_import1);
+
+ /* reimport should give us the same handle so that userspace can check
+ * whether it has that bo already somewhere. */
+ handle_import2 = prime_fd_to_handle(fd2, dma_buf_fd);
+ assert(handle_import1 == handle_import2);
+
+ /* Same for re-importing on the exporting fd. */
+ handle_selfimport = prime_fd_to_handle(fd1, dma_buf_fd);
+ assert(handle == handle_selfimport);
+
+ /* close dma_buf, check whether nothing disappears. */
+ close(dma_buf_fd);
+ check_bo(fd1, handle, fd2, handle_import1);
+
+ gem_close(fd1, handle);
+ check_bo(fd2, handle_import1, fd2, handle_import1);
+
+ /* re-import into old exporter */
+ dma_buf_fd = prime_handle_to_fd(fd2, handle_import1);
+ /* but drop all references to the obj in between */
+ gem_close(fd2, handle_import1);
+ handle = prime_fd_to_handle(fd1, dma_buf_fd);
+ handle_import1 = prime_fd_to_handle(fd2, dma_buf_fd);
+ check_bo(fd1, handle, fd2, handle_import1);
+
+ /* Completely rip out exporting fd. */
+ close(fd1);
+ check_bo(fd2, handle_import1, fd2, handle_import1);
+
+ return 0;
+}
diff --git a/tests/sysfs_edid_timing b/tests/sysfs_edid_timing
new file mode 100755
index 00000000..3a8c6c0e
--- /dev/null
+++ b/tests/sysfs_edid_timing
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# This check the time we take to read the content of all the possible connectors.
+# Without the edid -ENXIO patch (http://permalink.gmane.org/gmane.comp.video.dri.devel/62083),
+# we sometimes take a *really* long time. So let's just check for some reasonable timing here
+#
+
+TIME1=$(date +%s%N)
+cat $(find /sys/devices/|grep drm | grep /status) > /dev/null
+TIME2=$(date +%s%N)
+
+# time in ms
+RES=$(((TIME2 - TIME1) / 1000000))
+
+if [ $RES -gt 600 ]; then
+ echo "Talking to outputs took ${RES}ms, something is wrong"
+ exit 1
+fi
+
+exit 0
diff --git a/tests/sysfs_l3_parity b/tests/sysfs_l3_parity
new file mode 100755
index 00000000..6f814a13
--- /dev/null
+++ b/tests/sysfs_l3_parity
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+if ! find /sys/class/drm/card*/ | grep l3_parity > /dev/null ; then
+ echo "no l3_parity interface, skipping test"
+ exit 77
+fi
+
+SOURCE_DIR="$( dirname "${BASH_SOURCE[0]}" )"
+. $SOURCE_DIR/drm_lib.sh
+
+$SOURCE_DIR/../tools/intel_l3_parity -c
+
+#Check that we can remap a row
+$SOURCE_DIR/../tools/intel_l3_parity 0,0,0
+disabled=`$SOURCE_DIR/../tools/intel_l3_parity | grep -c 'Row 0, Bank 0, Subbank 0 is disabled'`
+if [ "$disabled" != "1" ] ; then
+ echo "Fail"
+ exit 1
+fi
+
+$SOURCE_DIR/../tools/intel_l3_parity -c
+
+#Check that we can clear remaps
+if [ `$SOURCE_DIR/../tools/intel_l3_parity | wc -c` != "0" ] ; then
+ echo "Fail"
+ exit 1
+fi
diff --git a/tests/sysfs_rc6_residency.c b/tests/sysfs_rc6_residency.c
new file mode 100644
index 00000000..2f33697a
--- /dev/null
+++ b/tests/sysfs_rc6_residency.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 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:
+ * Ben Widawsky <ben@bwidawsk.net>
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "drmtest.h"
+
+#define SLEEP_DURATION 3000 // in milliseconds
+#define RC6_FUDGE 900 // in milliseconds
+
+static unsigned int readit(const char *path)
+{
+ unsigned int ret;
+
+ FILE *file;
+ file = fopen(path, "r");
+ if (file == NULL) {
+ fprintf(stderr, "Couldn't open %s (%d)\n", path, errno);
+ abort();
+ }
+ fscanf(file, "%u", &ret);
+ fclose(file);
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ const int device = drm_get_card(0);
+ char *path, *pathp, *pathpp;
+ int fd, ret;
+ unsigned int value1, value1p, value1pp, value2, value2p, value2pp;
+ FILE *file;
+ int diff;
+
+ /* Use drm_open_any to verify device existence */
+ fd = drm_open_any();
+ close(fd);
+
+ ret = asprintf(&path, "/sys/class/drm/card%d/power/rc6_enable", device);
+ assert(ret != -1);
+
+ /* For some reason my ivb isn't idle even after syncing up with the gpu.
+ * Let's add a sleept just to make it happy. */
+ sleep(5);
+
+ file = fopen(path, "r");
+ if (!file) {
+ printf("kernel too old or rc6 not supported on this platform.\n");
+ exit(77);
+ }
+
+ /* claim success if no rc6 enabled. */
+ if (readit(path) == 0)
+ exit(EXIT_SUCCESS);
+
+ ret = asprintf(&path, "/sys/class/drm/card%d/power/rc6_residency_ms", device);
+ assert(ret != -1);
+ ret = asprintf(&pathp, "/sys/class/drm/card%d/power/rc6p_residency_ms", device);
+ assert(ret != -1);
+ ret = asprintf(&pathpp, "/sys/class/drm/card%d/power/rc6pp_residency_ms", device);
+ assert(ret != -1);
+
+ value1 = readit(path);
+ value1p = readit(pathp);
+ value1pp = readit(pathpp);
+ sleep(SLEEP_DURATION / 1000);
+ value2 = readit(path);
+ value2p = readit(pathp);
+ value2pp = readit(pathpp);
+
+ free(pathpp);
+ free(pathp);
+ free(path);
+
+ diff = (value2pp - value1pp) +
+ (value2p - value1p) +
+ (value2 - value1);
+
+ if (diff > (SLEEP_DURATION + RC6_FUDGE)) {
+ fprintf(stderr, "Diff was too high. That is unpossible\n");
+ exit(EXIT_FAILURE);
+ }
+ if (diff < (SLEEP_DURATION - RC6_FUDGE)) {
+ fprintf(stderr, "GPU was not in RC6 long enough. Check that "
+ "the GPU is as idle as possible (ie. no X, "
+ "running and running no other tests)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
new file mode 100644
index 00000000..14d7da39
--- /dev/null
+++ b/tests/testdisplay.c
@@ -0,0 +1,765 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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 program is intended for testing of display functionality. It should
+ * allow for testing of
+ * - hotplug
+ * - mode setting
+ * - clone & twin modes
+ * - panel fitting
+ * - test patterns & pixel generators
+ * Additional programs can test the detected outputs against VBT provided
+ * device lists (both docked & undocked).
+ *
+ * TODO:
+ * - pixel generator in transcoder
+ * - test pattern reg in pipe
+ * - test patterns on outputs (e.g. TV)
+ * - handle hotplug (leaks crtcs, can't handle clones)
+ * - allow mode force
+ * - expose output specific controls
+ * - e.g. DDC-CI brightness
+ * - HDMI controls
+ * - panel brightness
+ * - DP commands (e.g. poweroff)
+ * - verify outputs against VBT/physical connectors
+ */
+#include "config.h"
+
+#include <assert.h>
+#include <cairo.h>
+#include <errno.h>
+#include <math.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "i915_drm.h"
+#include "drmtest.h"
+#include "testdisplay.h"
+
+#include <stdlib.h>
+#include <signal.h>
+
+drmModeRes *resources;
+int drm_fd, modes;
+int dump_info = 0, test_all_modes =0, test_preferred_mode = 0, force_mode = 0,
+ test_plane, enable_tiling;
+int sleep_between_modes = 5;
+uint32_t depth = 24, stride, bpp;
+int qr_code = 0;
+
+drmModeModeInfo force_timing;
+
+int crtc_x, crtc_y, crtc_w, crtc_h, width, height;
+unsigned int plane_fb_id;
+unsigned int plane_crtc_id;
+unsigned int plane_id;
+int plane_width, plane_height;
+static const uint32_t SPRITE_COLOR_KEY = 0x00aaaaaa;
+uint32_t *fb_ptr;
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
+struct type_name {
+ int type;
+ const char *name;
+};
+
+#define type_name_fn(res) \
+static const char * res##_str(int type) { \
+ unsigned 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" },
+};
+
+type_name_fn(connector_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
+ * requested mode is available.
+ * Then you need to find the encoder attached to that connector so you
+ * can bind it with a free crtc.
+ */
+struct connector {
+ uint32_t id;
+ int mode_valid;
+ drmModeModeInfo mode;
+ drmModeEncoder *encoder;
+ drmModeConnector *connector;
+ int crtc;
+ int pipe;
+};
+
+static void dump_connectors_fd(int drmfd)
+{
+ int i, j;
+
+ drmModeRes *mode_resources = drmModeGetResources(drmfd);
+
+ if (!mode_resources) {
+ fprintf(stderr, "drmModeGetResources failed: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ printf("Connectors:\n");
+ printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
+ for (i = 0; i < mode_resources->count_connectors; i++) {
+ drmModeConnector *connector;
+
+ connector = drmModeGetConnector(drmfd, mode_resources->connectors[i]);
+ if (!connector) {
+ fprintf(stderr, "could not get connector %i: %s\n",
+ mode_resources->connectors[i], strerror(errno));
+ continue;
+ }
+
+ printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
+ connector->connector_id,
+ connector->encoder_id,
+ connector_status_str(connector->connection),
+ connector_type_str(connector->connector_type),
+ connector->mmWidth, connector->mmHeight,
+ connector->count_modes);
+
+ if (!connector->count_modes)
+ continue;
+
+ printf(" modes:\n");
+ printf(" name refresh (Hz) hdisp hss hse htot vdisp "
+ "vss vse vtot flags type clock\n");
+ for (j = 0; j < connector->count_modes; j++)
+ kmstest_dump_mode(&connector->modes[j]);
+
+ drmModeFreeConnector(connector);
+ }
+ printf("\n");
+
+ drmModeFreeResources(mode_resources);
+}
+
+static void dump_crtcs_fd(int drmfd)
+{
+ int i;
+ drmModeRes *mode_resources = drmModeGetResources(drmfd);
+
+ printf("CRTCs:\n");
+ printf("id\tfb\tpos\tsize\n");
+ for (i = 0; i < mode_resources->count_crtcs; i++) {
+ drmModeCrtc *crtc;
+
+ crtc = drmModeGetCrtc(drmfd, mode_resources->crtcs[i]);
+ if (!crtc) {
+ fprintf(stderr, "could not get crtc %i: %s\n",
+ mode_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);
+ kmstest_dump_mode(&crtc->mode);
+
+ drmModeFreeCrtc(crtc);
+ }
+ printf("\n");
+
+ drmModeFreeResources(mode_resources);
+}
+
+static void connector_find_preferred_mode(struct connector *c)
+{
+ drmModeConnector *connector;
+ drmModeEncoder *encoder = NULL;
+ int i, j;
+
+ /* First, find the connector & mode */
+ c->mode_valid = 0;
+ connector = drmModeGetConnector(drm_fd, c->id);
+ if (!connector) {
+ fprintf(stderr, "could not get connector %d: %s\n",
+ c->id, strerror(errno));
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ if (connector->connection != DRM_MODE_CONNECTED) {
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ if (!connector->count_modes) {
+ fprintf(stderr, "connector %d has no modes\n", c->id);
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ if (connector->connector_id != c->id) {
+ fprintf(stderr, "connector id doesn't match (%d != %d)\n",
+ connector->connector_id, c->id);
+ drmModeFreeConnector(connector);
+ return;
+ }
+
+ for (j = 0; j < connector->count_modes; j++) {
+ c->mode = connector->modes[j];
+ if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
+ c->mode_valid = 1;
+ break;
+ }
+ }
+
+ if (!c->mode_valid) {
+ if (connector->count_modes > 0) {
+ /* use the first mode as test mode */
+ c->mode = connector->modes[0];
+ c->mode_valid = 1;
+ }
+ else {
+ fprintf(stderr, "failed to find any modes on connector %d\n",
+ c->id);
+ return;
+ }
+ }
+
+ /* Now get the encoder */
+ for (i = 0; i < connector->count_encoders; i++) {
+ encoder = drmModeGetEncoder(drm_fd, connector->encoders[i]);
+
+ if (!encoder) {
+ fprintf(stderr, "could not get encoder %i: %s\n",
+ resources->encoders[i], strerror(errno));
+ drmModeFreeEncoder(encoder);
+ continue;
+ }
+
+ break;
+ }
+
+ c->encoder = encoder;
+
+ if (i == resources->count_encoders) {
+ fprintf(stderr, "failed to find encoder\n");
+ c->mode_valid = 0;
+ return;
+ }
+
+ /* Find first CRTC not in use */
+ for (i = 0; i < resources->count_crtcs; i++) {
+ if (resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
+ break;
+ }
+ c->crtc = resources->crtcs[i];
+ c->pipe = i;
+
+ if(test_preferred_mode || force_mode)
+ resources->crtcs[i] = 0;
+
+ c->connector = connector;
+}
+
+static void
+paint_color_key(void)
+{
+ int i, j;
+
+ for (i = crtc_y; i < crtc_y + crtc_h; i++)
+ for (j = crtc_x; j < crtc_x + crtc_w; j++) {
+ uint32_t offset;
+
+ offset = (i * width) + j;
+ fb_ptr[offset] = SPRITE_COLOR_KEY;
+ }
+}
+
+static void paint_image(cairo_t *cr, const char *file)
+{
+ int img_x, img_y, img_w, img_h, img_w_o, img_h_o;
+ double img_w_scale, img_h_scale;
+
+ cairo_surface_t *image;
+
+ img_y = height * (0.10 );
+ img_h = height * 0.08 * 4;
+ img_w = img_h;
+
+ img_x = (width / 2) - (img_w / 2);
+
+ image = cairo_image_surface_create_from_png(file);
+
+ img_w_o = cairo_image_surface_get_width(image);
+ img_h_o = cairo_image_surface_get_height(image);
+
+ cairo_translate(cr, img_x, img_y);
+
+ img_w_scale = (double)img_w / (double)img_w_o;
+ img_h_scale = (double)img_h / (double)img_h_o;
+ cairo_scale(cr, img_w_scale, img_h_scale);
+
+ cairo_set_source_surface(cr, image, 0, 0);
+ cairo_scale(cr, 1, 1);
+
+ cairo_paint(cr);
+ cairo_surface_destroy(image);
+}
+
+static void
+paint_output_info(cairo_t *cr, int l_width, int l_height, void *priv)
+{
+ struct connector *c = priv;
+ cairo_text_extents_t name_extents, mode_extents;
+ char name_buf[128], mode_buf[128];
+ int i, x, y, modes_x, modes_y;
+
+ /* Get text extents for each string */
+ snprintf(name_buf, sizeof name_buf, "%s",
+ connector_type_str(c->connector->connector_type));
+ cairo_set_font_size(cr, 48);
+ cairo_select_font_face(cr, "Helvetica",
+ CAIRO_FONT_SLANT_NORMAL,
+ CAIRO_FONT_WEIGHT_NORMAL);
+ cairo_text_extents(cr, name_buf, &name_extents);
+
+ snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz on %s encoder",
+ c->mode.name, c->mode.vrefresh,
+ encoder_type_str(c->encoder->encoder_type));
+ cairo_set_font_size(cr, 36);
+ cairo_text_extents(cr, mode_buf, &mode_extents);
+
+ /* Paint output name */
+ x = l_width / 2;
+ x -= name_extents.width / 2;
+ y = l_height / 2;
+ y -= (name_extents.height / 2) - (mode_extents.height / 2) - 10;
+ cairo_set_font_size(cr, 48);
+ cairo_move_to(cr, x, y);
+ cairo_text_path(cr, name_buf);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+
+ /* Paint mode name */
+ x = l_width / 2;
+ x -= mode_extents.width / 2;
+ modes_x = x;
+ y = l_height / 2;
+ y += (mode_extents.height / 2) + (name_extents.height / 2) + 10;
+ cairo_set_font_size(cr, 36);
+ cairo_move_to(cr, x, y);
+ cairo_text_path(cr, mode_buf);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+
+ /* List available modes */
+ snprintf(mode_buf, sizeof mode_buf, "Available modes:");
+ cairo_set_font_size(cr, 18);
+ cairo_text_extents(cr, mode_buf, &mode_extents);
+ x = modes_x;
+ modes_x = x + mode_extents.width;
+ y += mode_extents.height + 10;
+ modes_y = y;
+ cairo_move_to(cr, x, y);
+ cairo_text_path(cr, mode_buf);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+
+ for (i = 0; i < c->connector->count_modes; i++) {
+ snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz",
+ c->connector->modes[i].name,
+ c->connector->modes[i].vrefresh);
+ cairo_set_font_size(cr, 18);
+ cairo_text_extents(cr, mode_buf, &mode_extents);
+ x = modes_x - mode_extents.width; /* right justify modes */
+ y += mode_extents.height + 10;
+ if (y + mode_extents.height >= height) {
+ y = modes_y + mode_extents.height + 10;
+ modes_x += mode_extents.width + 10;
+ x = modes_x - mode_extents.width;
+ }
+ cairo_move_to(cr, x, y);
+ cairo_text_path(cr, mode_buf);
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_stroke_preserve(cr);
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_fill(cr);
+ }
+
+ if (qr_code)
+ paint_image(cr, "./pass.png");
+}
+
+static void sighandler(int signo)
+{
+ return;
+}
+
+static void set_single(void)
+{
+ int sigs[] = { SIGUSR1 };
+ struct sigaction sa;
+ sa.sa_handler = sighandler;
+
+ sigemptyset(&sa.sa_mask);
+
+ if (sigaction(sigs[0], &sa, NULL) == -1)
+ perror("Could not set signal handler");
+}
+
+static void
+set_mode(struct connector *c)
+{
+ unsigned int fb_id = 0;
+ int j, test_mode_num;
+
+ if (depth <= 8)
+ bpp = 8;
+ else if (depth > 8 && depth <= 16)
+ bpp = 16;
+ else if (depth > 16 && depth <= 32)
+ bpp = 32;
+
+ connector_find_preferred_mode(c);
+ if (!c->mode_valid)
+ return;
+
+ test_mode_num = 1;
+ if (force_mode){
+ memcpy( &c->mode, &force_timing, sizeof(force_timing));
+ c->mode.vrefresh =(force_timing.clock*1e3)/(force_timing.htotal*force_timing.vtotal);
+ c->mode_valid = 1;
+ sprintf(c->mode.name, "%dx%d", force_timing.hdisplay, force_timing.vdisplay);
+ } else if (test_all_modes)
+ test_mode_num = c->connector->count_modes;
+
+ for (j = 0; j < test_mode_num; j++) {
+ struct kmstest_fb fb_info;
+
+ if (test_all_modes)
+ c->mode = c->connector->modes[j];
+
+ if (!c->mode_valid)
+ continue;
+
+ width = c->mode.hdisplay;
+ height = c->mode.vdisplay;
+
+ fb_id = kmstest_create_fb(drm_fd, width, height, bpp, depth,
+ enable_tiling, &fb_info,
+ paint_output_info, c);
+
+ fb_ptr = gem_mmap(drm_fd, fb_info.gem_handle,
+ fb_info.size, PROT_READ | PROT_WRITE);
+ assert(fb_ptr);
+ paint_color_key();
+
+ gem_close(drm_fd, fb_info.gem_handle);
+
+ fprintf(stdout, "CRTS(%u):",c->crtc);
+ kmstest_dump_mode(&c->mode);
+ if (drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
+ &c->id, 1, &c->mode)) {
+ fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n",
+ width, height, c->mode.vrefresh,
+ strerror(errno));
+ continue;
+ }
+
+ if (sleep_between_modes && test_all_modes && !qr_code)
+ sleep(sleep_between_modes);
+
+ if (qr_code){
+ set_single();
+ pause();
+ }
+
+ }
+
+ if(test_all_modes){
+ drmModeRmFB(drm_fd,fb_id);
+ drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0, &c->id, 1, 0);
+ }
+
+ drmModeFreeEncoder(c->encoder);
+ drmModeFreeConnector(c->connector);
+}
+
+/*
+ * Re-probe outputs and light up as many as possible.
+ *
+ * On Intel, we have two CRTCs that we can drive independently with
+ * different timings and scanout buffers.
+ *
+ * Each connector has a corresponding encoder, except in the SDVO case
+ * where an encoder may have multiple connectors.
+ */
+int update_display(void)
+{
+ struct connector *connectors;
+ int c;
+
+ resources = drmModeGetResources(drm_fd);
+ if (!resources) {
+ fprintf(stderr, "drmModeGetResources failed: %s\n",
+ strerror(errno));
+ return 0;
+ }
+
+ connectors = calloc(resources->count_connectors,
+ sizeof(struct connector));
+ if (!connectors)
+ return 0;
+
+ if (dump_info) {
+ dump_connectors_fd(drm_fd);
+ dump_crtcs_fd(drm_fd);
+ }
+
+ if (test_preferred_mode || test_all_modes || force_mode) {
+ /* Find any connected displays */
+ for (c = 0; c < resources->count_connectors; c++) {
+ connectors[c].id = resources->connectors[c];
+ set_mode(&connectors[c]);
+ }
+ }
+ drmModeFreeResources(resources);
+ return 1;
+}
+
+static char optstr[] = "hiaf:s:d:p:mrt";
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage: %s [-hiasdpmtf]\n", name);
+ fprintf(stderr, "\t-i\tdump info\n");
+ fprintf(stderr, "\t-a\ttest all modes\n");
+ fprintf(stderr, "\t-s\t<duration>\tsleep between each mode test\n");
+ fprintf(stderr, "\t-d\t<depth>\tbit depth of scanout buffer\n");
+ fprintf(stderr, "\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n");
+ fprintf(stderr, "\t-m\ttest the preferred mode\n");
+ fprintf(stderr, "\t-t\tuse a tiled framebuffer\n");
+ fprintf(stderr, "\t-r\tprint a QR code on the screen whose content is \"pass\" for the automatic test\n");
+ fprintf(stderr, "\t-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n");
+ fprintf(stderr, "\t\t<vdisp>,<vsync-start>,<vsync-end>,<vtotal>\n");
+ fprintf(stderr, "\t\ttest force mode\n");
+ fprintf(stderr, "\tDefault is to test all modes.\n");
+ exit(0);
+}
+
+#define dump_resource(res) if (res) dump_##res()
+
+static gboolean input_event(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ gchar buf[2];
+ gsize count;
+
+ count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
+ if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
+ exit(0);
+ }
+
+ return TRUE;
+}
+
+static void enter_exec_path( char **argv )
+{
+ char *exec_path = NULL;
+ char *pos = NULL;
+ short len_path = 0;
+
+ len_path = strlen( argv[0] );
+ exec_path = (char*) malloc(len_path);
+
+ memcpy(exec_path, argv[0], len_path);
+ pos = strrchr(exec_path, '/');
+ if (pos != NULL)
+ *(pos+1) = '\0';
+
+ chdir(exec_path);
+ free(exec_path);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int ret = 0;
+ GIOChannel *stdinchannel;
+ GMainLoop *mainloop;
+ float force_clock;
+
+ enter_exec_path( argv );
+
+ opterr = 0;
+ while ((c = getopt(argc, argv, optstr)) != -1) {
+ switch (c) {
+ case 'i':
+ dump_info = 1;
+ break;
+ case 'a':
+ test_all_modes = 1;
+ break;
+ case 'f':
+ force_mode = 1;
+ if(sscanf(optarg,"%f,%hu,%hu,%hu,%hu,%hu,%hu,%hu,%hu",
+ &force_clock,&force_timing.hdisplay, &force_timing.hsync_start,&force_timing.hsync_end,&force_timing.htotal,
+ &force_timing.vdisplay, &force_timing.vsync_start, &force_timing.vsync_end, &force_timing.vtotal)!= 9)
+ usage(argv[0]);
+ force_timing.clock = force_clock*1000;
+
+ break;
+ case 's':
+ sleep_between_modes = atoi(optarg);
+ break;
+ case 'd':
+ depth = atoi(optarg);
+ fprintf(stderr, "using depth %d\n", depth);
+ break;
+ case 'p':
+ if (sscanf(optarg, "%d,%d,%d,%d,%d,%d", &plane_width,
+ &plane_height, &crtc_x, &crtc_y,
+ &crtc_w, &crtc_h) != 6)
+ usage(argv[0]);
+ test_plane = 1;
+ break;
+ case 'm':
+ test_preferred_mode = 1;
+ break;
+ case 't':
+ enable_tiling = 1;
+ break;
+ case 'r':
+ qr_code = 1;
+ break;
+ default:
+ fprintf(stderr, "unknown option %c\n", c);
+ /* fall through */
+ case 'h':
+ usage(argv[0]);
+ break;
+ }
+ }
+ if (!test_all_modes && !force_mode && !dump_info &&
+ !test_preferred_mode)
+ test_all_modes = 1;
+
+ drm_fd = drm_open_any();
+
+ mainloop = g_main_loop_new(NULL, FALSE);
+ if (!mainloop) {
+ fprintf(stderr, "failed to create glib mainloop\n");
+ ret = -1;
+ goto out_close;
+ }
+
+ if (!testdisplay_setup_hotplug()) {
+ fprintf(stderr, "failed to initialize hotplug support\n");
+ goto out_mainloop;
+ }
+
+ stdinchannel = g_io_channel_unix_new(0);
+ if (!stdinchannel) {
+ fprintf(stderr, "failed to create stdin GIO channel\n");
+ goto out_hotplug;
+ }
+
+ ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
+ NULL);
+ if (ret < 0) {
+ fprintf(stderr, "failed to add watch on stdin GIO channel\n");
+ goto out_stdio;
+ }
+
+ ret = 0;
+
+ if (!update_display()) {
+ ret = 1;
+ goto out_stdio;
+ }
+
+ if (dump_info || test_all_modes)
+ goto out_stdio;
+
+ g_main_loop_run(mainloop);
+
+out_stdio:
+ g_io_channel_shutdown(stdinchannel, TRUE, NULL);
+out_hotplug:
+ testdisplay_cleanup_hotplug();
+out_mainloop:
+ g_main_loop_unref(mainloop);
+out_close:
+ close(drm_fd);
+
+ return ret;
+}
diff --git a/tests/testdisplay.h b/tests/testdisplay.h
new file mode 100644
index 00000000..962e6219
--- /dev/null
+++ b/tests/testdisplay.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <glib.h>
+
+extern int drm_fd;
+
+gboolean testdisplay_setup_hotplug(void);
+void testdisplay_cleanup_hotplug(void);
+
+/* called by the hotplug code */
+int update_display(void);
diff --git a/tests/testdisplay_hotplug.c b/tests/testdisplay_hotplug.c
new file mode 100644
index 00000000..3f80dc73
--- /dev/null
+++ b/tests/testdisplay_hotplug.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2010 Intel Corporation
+ * Jesse Barnes <jesse.barnes@intel.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "testdisplay.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_UDEV
+#include <libudev.h>
+static struct udev_monitor *uevent_monitor;
+static struct udev *udev;
+static GIOChannel *udevchannel;
+
+static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
+ gpointer data)
+{
+ struct udev_device *dev;
+ dev_t udev_devnum;
+ struct stat s;
+ const char *hotplug;
+
+ dev = udev_monitor_receive_device(uevent_monitor);
+ if (!dev)
+ goto out;
+
+ udev_devnum = udev_device_get_devnum(dev);
+ fstat(drm_fd, &s);
+
+ hotplug = udev_device_get_property_value(dev, "HOTPLUG");
+
+ if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
+ hotplug && atoi(hotplug) == 1)
+ update_display();
+
+ udev_device_unref(dev);
+out:
+ return TRUE;
+}
+
+
+gboolean testdisplay_setup_hotplug(void)
+{
+ int ret;
+
+ udev = udev_new();
+ if (!udev) {
+ fprintf(stderr, "failed to create udev object\n");
+ goto out;
+ }
+
+ uevent_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ if (!uevent_monitor) {
+ fprintf(stderr, "failed to create udev event monitor\n");
+ goto out;
+ }
+
+ ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
+ "drm",
+ "drm_minor");
+ if (ret < 0) {
+ fprintf(stderr, "failed to filter for drm events\n");
+ goto out;
+ }
+
+ ret = udev_monitor_enable_receiving(uevent_monitor);
+ if (ret < 0) {
+ fprintf(stderr, "failed to enable udev event reception\n");
+ goto out;
+ }
+
+ udevchannel =
+ g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
+ if (!udevchannel) {
+ fprintf(stderr, "failed to create udev GIO channel\n");
+ goto out;
+ }
+
+ ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
+ udev);
+ if (ret < 0) {
+ fprintf(stderr, "failed to add watch on udev GIO channel\n");
+ goto out;
+ }
+
+ return TRUE;
+
+out:
+ testdisplay_cleanup_hotplug();
+ return FALSE;
+}
+
+void testdisplay_cleanup_hotplug(void)
+{
+ if (udevchannel)
+ g_io_channel_shutdown(udevchannel, TRUE, NULL);
+ if (uevent_monitor)
+ udev_monitor_unref(uevent_monitor);
+ if (udev)
+ udev_unref(udev);
+}
+#else
+gboolean testdisplay_setup_hotplug(void)
+{
+ fprintf(stderr, "no hotplug support on this platform\n");
+ return TRUE;
+}
+
+void testdisplay_cleanup_hotplug(void)
+{
+}
+#endif