diff --git a/tests/.gitignore b/tests/.gitignore index 86795c02..a3f3143b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -100,6 +100,7 @@ gem_storedw_loop_blt gem_storedw_loop_bsd gem_storedw_loop_render gem_storedw_loop_vebox +gem_streaming_writes gem_stress gem_threaded_access_tiled gem_tiled_blits diff --git a/tests/Makefile.sources b/tests/Makefile.sources index 12f27f9e..994c31b6 100644 --- a/tests/Makefile.sources +++ b/tests/Makefile.sources @@ -54,6 +54,7 @@ TESTS_progs_M = \ gem_ringfill \ gem_set_tiling_vs_blt \ gem_storedw_batches_loop \ + gem_streaming_writes \ gem_tiled_blits \ gem_tiled_partial_pwrite_pread \ gem_userptr_blits \ diff --git a/tests/gem_streaming_writes.c b/tests/gem_streaming_writes.c new file mode 100644 index 00000000..152b9ab5 --- /dev/null +++ b/tests/gem_streaming_writes.c @@ -0,0 +1,214 @@ +/* + * Copyright © 2015 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 + * + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "drm.h" +#include "ioctl_wrappers.h" +#include "drmtest.h" +#include "igt_debugfs.h" +#include "igt_aux.h" +#include "intel_chipset.h" + +#define OBJECT_SIZE 256*1024 +#define CHUNK_SIZE 32 + +#define COPY_BLT_CMD (2<<29|0x53<<22|0x6) +#define BLT_WRITE_ALPHA (1<<21) +#define BLT_WRITE_RGB (1<<20) +#define BLT_WRITE_ARGB (BLT_WRITE_ALPHA | BLT_WRITE_RGB) + +IGT_TEST_DESCRIPTION("Test of streaming writes into active GPU sources"); + +static void test_streaming(int fd, int mode) +{ + const int has_64bit_reloc = intel_gen(intel_get_drm_devid(fd)) >= 8; + struct drm_i915_gem_execbuffer2 execbuf; + struct drm_i915_gem_exec_object2 exec[3]; + struct drm_i915_gem_relocation_entry reloc[2]; + uint32_t tmp[] = { MI_BATCH_BUFFER_END }; + uint64_t __src_offset, __dst_offset; + uint32_t *s, *d; + uint32_t offset; + struct { + uint32_t handle; + uint64_t offset; + } *batch; + int i; + + memset(exec, 0, sizeof(exec)); + exec[0].handle = gem_create(fd, OBJECT_SIZE); +#define dst exec[0].handle +#define dst_offset exec[0].offset + exec[1].handle = gem_create(fd, OBJECT_SIZE); +#define src exec[1].handle +#define src_offset exec[1].offset + + switch (mode) { + case 0: /* cpu/snoop */ + gem_set_caching(fd, src, I915_CACHING_CACHED); + s = gem_mmap__cpu(fd, src, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE); + break; + case 1: /* gtt */ + s = gem_mmap__gtt(fd, src, OBJECT_SIZE, PROT_READ | PROT_WRITE); + break; + case 2: /* wc */ + s = gem_mmap__wc(fd, src, 0, OBJECT_SIZE, PROT_READ | PROT_WRITE); + break; + } + igt_assert(s); + + d = gem_mmap__cpu(fd, dst, 0, OBJECT_SIZE, PROT_READ); + igt_assert(d); + + gem_write(fd, src, 0, tmp, sizeof(tmp)); + memset(&execbuf, 0, sizeof(execbuf)); + execbuf.buffers_ptr = (uintptr_t)exec; + execbuf.buffer_count = 2; + gem_execbuf(fd, &execbuf); + /* We assume that the active objects are fixed to avoid relocations */ + __src_offset = src_offset; + __dst_offset = dst_offset; + + memset(reloc, 0, sizeof(reloc)); + reloc[0].offset = 4 * sizeof(uint32_t); + reloc[0].delta = 0; + reloc[0].target_handle = dst; + reloc[0].presumed_offset = dst_offset; + reloc[0].read_domains = I915_GEM_DOMAIN_RENDER; + reloc[0].write_domain = I915_GEM_DOMAIN_RENDER; + + reloc[1].offset = 7 * sizeof(uint32_t); + if (has_64bit_reloc) + reloc[1].offset += sizeof(uint32_t); + reloc[1].delta = 0; + reloc[1].target_handle = src; + reloc[1].presumed_offset = src_offset; + reloc[1].read_domains = I915_GEM_DOMAIN_RENDER; + reloc[1].write_domain = 0; + + exec[2].relocation_count = 2; + exec[2].relocs_ptr = (uintptr_t)reloc; + execbuf.buffer_count = 3; + execbuf.flags = I915_EXEC_NO_RELOC; + if (gem_has_blt(fd)) + execbuf.flags |= I915_EXEC_BLT; + + batch = malloc(sizeof(*batch) * (OBJECT_SIZE / CHUNK_SIZE)); + for (i = 0; i < OBJECT_SIZE / CHUNK_SIZE; i++) { + unsigned x = (i * CHUNK_SIZE) % 4096 >> 2; + unsigned y = (i * CHUNK_SIZE) / 4096; + uint32_t *b; + int j; + + batch[i].handle = gem_create(fd, 4096); + batch[i].offset = 0; + + b = gem_mmap__cpu(fd, batch[i].handle, 0, 4096, PROT_WRITE); + igt_assert(b); + + j = 0; + b[j] = COPY_BLT_CMD | BLT_WRITE_ARGB; + if (has_64bit_reloc) + b[j] += 2; + j++; + b[j++] = 0xcc << 16 | 1 << 25 | 1 << 24 | 4096; + b[j++] = (y << 16) | x; + b[j++] = ((y+1) << 16) | (x + (CHUNK_SIZE >> 2)); + b[j++] = dst_offset; + if (has_64bit_reloc) + b[j++] = dst_offset >> 32; + b[j++] = (y << 16) | x; + b[j++] = 4096; + b[j++] = src_offset; + if (has_64bit_reloc) + b[j++] = src_offset >> 32; + b[j++] = MI_BATCH_BUFFER_END; + + munmap(b, 4096); + } + + for (int pass = 0; pass < 256; pass++) { + int domain = mode ? I915_GEM_DOMAIN_GTT : I915_GEM_DOMAIN_CPU; + gem_set_domain(fd, src, domain, domain); + + /* Now copy from the src to the dst in 32byte chunks */ + for (offset = 0; offset < OBJECT_SIZE; offset += CHUNK_SIZE) { + for (i = 0; i < CHUNK_SIZE/4; i++) + s[offset/4 + i] = (OBJECT_SIZE*pass + offset)/4 + i; + + exec[2].handle = batch[offset/CHUNK_SIZE].handle; + exec[2].offset = batch[offset/CHUNK_SIZE].offset; + + gem_execbuf(fd, &execbuf); + igt_assert(__src_offset == src_offset); + igt_assert(__dst_offset == dst_offset); + + batch[offset/CHUNK_SIZE].offset = exec[2].offset; + } + + gem_set_domain(fd, dst, I915_GEM_DOMAIN_CPU, 0); + for (offset = 0; offset < OBJECT_SIZE/4; offset++) + igt_assert_eq(pass*OBJECT_SIZE/4 + offset, d[offset]); + } + + for (i = 0; i < OBJECT_SIZE / CHUNK_SIZE; i++) + gem_close(fd, batch[i].handle); + free(batch); + + munmap(s, OBJECT_SIZE); + gem_close(fd, src); + munmap(d, OBJECT_SIZE); + gem_close(fd, dst); +} + +igt_main +{ + int fd; + + igt_fixture + fd = drm_open_any(); + + igt_subtest("cpu") + test_streaming(fd, 0); + igt_subtest("gtt") + test_streaming(fd, 1); + igt_subtest("wc") + test_streaming(fd, 2); + + igt_fixture + close(fd); +}