diff options
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/Makefile.sources | 1 | ||||
-rw-r--r-- | tests/gem_ppgtt.c | 324 |
4 files changed, 327 insertions, 0 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 4448cb64..941760d2 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -54,6 +54,7 @@ gem_partial_pwrite_pread gem_persistent_relocs gem_pin gem_pipe_control_store_loop +gem_ppgtt gem_pread gem_pread_after_blit gem_pwrite diff --git a/tests/Makefile.am b/tests/Makefile.am index b8cddd56..287391e1 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -32,6 +32,7 @@ LDADD = ../lib/libintel_tools.la $(PCIACCESS_LIBS) $(DRM_LIBS) LDADD += $(CAIRO_LIBS) $(LIBUDEV_LIBS) $(GLIB_LIBS) AM_CFLAGS += $(CAIRO_CFLAGS) $(LIBUDEV_CFLAGS) $(GLIB_CFLAGS) +gem_ppgtt_LDADD = $(LDADD) -lpthread gem_close_race_LDADD = $(LDADD) -lpthread gem_fence_thrash_CFLAGS = $(AM_CFLAGS) $(THREAD_CFLAGS) gem_fence_thrash_LDADD = $(LDADD) -lpthread diff --git a/tests/Makefile.sources b/tests/Makefile.sources index aa34aeb2..3eb50dd3 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -36,6 +36,7 @@ TESTS_progs_M = \ gem_mmap_gtt \ gem_partial_pwrite_pread \ gem_persistent_relocs \ + gem_ppgtt \ gem_pread \ gem_pread_after_blit \ gem_pwrite \ diff --git a/tests/gem_ppgtt.c b/tests/gem_ppgtt.c new file mode 100644 index 00000000..266a6a32 --- /dev/null +++ b/tests/gem_ppgtt.c @@ -0,0 +1,324 @@ +/* + * Copyright © 2013 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: + * Oscar Mateo <oscar.mateo@intel.com> + * + */ + +/* + * This test covers some tricky corner cases found during + * True PPGTT development + */ + +#include <pthread.h> +#include "rendercopy.h" +#include "igt_debugfs.h" + +#define WIDTH 512 +#define STRIDE (WIDTH*4) +#define HEIGHT 512 +#define SIZE (HEIGHT*STRIDE) + +/* options */ +int option_num_threads = 10; +int option_num_iter = 200; +bool option_tiled = false; + +/* globals */ +int global_fd; +int devid; +render_copyfunc_t rendercopy; + +static void init_buffer(drm_intel_bufmgr *bufmgr, + struct scratch_buf *buf, bool special) +{ + uint32_t tiling; + unsigned long pitch = STRIDE; + + if (option_tiled) + { + tiling = I915_TILING_X; + buf->bo = drm_intel_bo_alloc_tiled(bufmgr, "", + WIDTH, HEIGHT, 4, + &tiling, &pitch, 0); + } + else + { + tiling = I915_TILING_NONE; + buf->bo = drm_intel_bo_alloc(bufmgr, "", + special? 16*SIZE : SIZE, 4096); + } + + igt_assert(buf->bo); + buf->size = SIZE; + buf->tiling = tiling; + buf->stride = pitch; +} + +static bool check_buffer_contents(struct scratch_buf *buf, uint32_t val) +{ + uint32_t *ptr; + int i; + drm_intel_bo *bo = buf->bo; + + if (buf->tiling == I915_TILING_NONE) + do_or_die(drm_intel_bo_map(bo, 0)); + else + do_or_die(drm_intel_gem_bo_map_gtt(bo)); + + ptr = bo->virtual; + for (i = 0; i < WIDTH*HEIGHT; i++) { + if (ptr[i] != val) { + printf("Expected 0x%08x, found 0x%08x at offset 0x%08x\n", + val, ptr[i], i * 4); + return false; + } + val++; + } + + if (buf->tiling == I915_TILING_NONE) + drm_intel_bo_unmap(bo); + else + drm_intel_gem_bo_unmap_gtt(bo); + + return true; +} + +static void init_buffer_contents(struct scratch_buf *buf, uint32_t val) +{ + uint32_t *ptr; + int i; + drm_intel_bo *bo = buf->bo; + + if (buf->tiling == I915_TILING_NONE) + do_or_die(drm_intel_bo_map(bo, 1)); + else + do_or_die(drm_intel_gem_bo_map_gtt(bo)); + + ptr = bo->virtual; + for (i = 0; i < WIDTH*HEIGHT; i++) + ptr[i] = val++; + + if (buf->tiling == I915_TILING_NONE) + drm_intel_bo_unmap(bo); + else + drm_intel_gem_bo_unmap_gtt(bo); +} + +static void run(void) +{ + int fd; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + struct scratch_buf src, dst; + int i; + uint32_t start = 0; + + /* Initialize */ + igt_assert((fd = drm_open_any()) >= 0); + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + batch = intel_batchbuffer_alloc(bufmgr, devid); + init_buffer(bufmgr, &src, false); + init_buffer_contents(&src, start); + init_buffer(bufmgr, &dst, false); + + /* Work */ + for (i = 0; i < option_num_iter; i++) + rendercopy(batch, NULL, &src, 0, 0, WIDTH, HEIGHT, &dst, 0, 0); + igt_assert(check_buffer_contents(&dst, start)); + + /* Cleanup */ + drm_intel_bo_unreference(src.bo); + drm_intel_bo_unreference(dst.bo); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + close(fd); +} + +static void *work_multiple(void *arg) +{ + run(); + + pthread_exit(NULL); +} + +static void run_multiple(void) +{ + int i = 0; + void *retval; + pthread_t *threads = calloc(option_num_threads, sizeof(*threads)); + + for (i = 0; i < option_num_threads; i++) + pthread_create(&threads[i], NULL, work_multiple, &i); + + for (i = 0; i < option_num_threads; i++) + igt_assert(pthread_join(threads[i], &retval) == 0); + + free(threads); +} + +static void run_with_namedbo(uint32_t name) +{ + int fd; + drm_intel_bufmgr *bufmgr; + struct intel_batchbuffer *batch; + struct scratch_buf src, dst; + uint32_t start = 0; + int i; + + /* Initialize */ + igt_assert((fd = drm_open_any()) >= 0); + bufmgr = drm_intel_bufmgr_gem_init(fd, 4096); + batch = intel_batchbuffer_alloc(bufmgr, devid); + init_buffer(bufmgr, &dst, false); + + /* Recover src */ + src.size = dst.size; + src.tiling = dst.tiling; + src.stride = dst.stride; + src.bo = drm_intel_bo_gem_create_from_name(bufmgr, "", name); + igt_assert(src.bo); + igt_assert(check_buffer_contents(&src, start)); + + /* Work */ + for (i = 0; i < option_num_iter; i++) + rendercopy(batch, NULL, &src, 0, 0, WIDTH, HEIGHT, &dst, 0, 0); + igt_assert(check_buffer_contents(&dst, start)); + + /* Cleanup */ + drm_intel_bo_unreference(src.bo); + drm_intel_bo_unreference(dst.bo); + intel_batchbuffer_free(batch); + drm_intel_bufmgr_destroy(bufmgr); + close(fd); +} + +static void *work_flinked(void *arg) +{ + uint32_t *name = (uint32_t *)arg; + + run_with_namedbo(*name); + + pthread_exit(NULL); +} + +static void run_flinked(void) +{ + drm_intel_bufmgr *bufmgr; + struct scratch_buf src; + uint32_t name; + uint32_t start = 0; + int i; + void *retval; + pthread_t *threads = calloc(option_num_threads, sizeof(*threads)); + + bufmgr = drm_intel_bufmgr_gem_init(global_fd, 4096); + init_buffer(bufmgr, &src, false); + init_buffer_contents(&src, start); + do_or_die(drm_intel_bo_flink(src.bo, &name)); + + for (i = 0; i < option_num_threads; i++) + pthread_create(&threads[i], NULL, work_flinked, &name); + + for (i = 0; i < option_num_threads; i++) + igt_assert(pthread_join(threads[i], &retval) == 0); + + free(threads); + drm_intel_bo_unreference(src.bo); + drm_intel_bufmgr_destroy(bufmgr); +} + +static void run_pinned(void) +{ + drm_intel_bufmgr *bufmgr; + struct scratch_buf src; + uint32_t name; + uint32_t val = 0; + + bufmgr = drm_intel_bufmgr_gem_init(global_fd, 4096); + init_buffer(bufmgr, &src, true); + init_buffer_contents(&src, val); + do_or_die(drm_intel_bo_flink(src.bo, &name)); + + /* Pin to GGTT */ + drm_intel_bo_pin(src.bo, 4096); + + /* Use the source bo in a different context (pin to a PPGTT) */ + run_with_namedbo(name); + + /* Make sure we switch the context in every ring so that the + * previous context finally dies */ + gem_quiescent_gpu(global_fd); + igt_drop_caches_set(DROP_RETIRE); + + drm_intel_bo_unpin(src.bo); + drm_intel_bo_unreference(src.bo); + drm_intel_bufmgr_destroy(bufmgr); +} + +static void do_tests(bool use_tiled, const char *suffix) +{ + option_tiled = use_tiled; + + /* One context, rendercopying in a loop */ + igt_subtest_f("single-ctx-%s", suffix) + run(); + + /* Multiple threads, each with its own context + * rendercopying in a loop */ + igt_subtest_f("multiple-ctx-%s", suffix) { + run_multiple(); + } + + /* Multiple threads, each with its own context + * rendercopying in a loop. The src bo is shared + * among them */ + igt_subtest_f("multiple-ctx-flink-%s", suffix) { + run_flinked(); + } + + /* Pin object to GGTT, create a context, bind the + * object to its PPGTT and then clean the context */ + igt_subtest_f("single-ctx-pinned-%s", suffix) { + run_pinned(); + } +} + +igt_main +{ + igt_fixture { + global_fd = drm_open_any(); + devid = intel_get_drm_devid(global_fd); + rendercopy = get_render_copyfunc(devid); + igt_require(rendercopy); + if (igt_run_in_simulation()) + option_num_iter = 10; + option_num_threads = 3; + } + + do_tests(false, "linear"); + do_tests(true, "tiled"); + + igt_fixture + close(global_fd); +} |