[igt-dev] [PATCH i-g-t v3 3/4] tests/api_intel_bb: Add intel_bb API test
Zbigniew Kempczyński
zbigniew.kempczynski at intel.com
Tue Jun 23 13:00:55 UTC 2020
IGT code contains some mechanisms which are quite large and cover
different gens so they deserve own api_* checks.
Starting with api_intel_bb verify intel_bb functions work as expected.
Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
---
tests/i915/api_intel_bb.c | 563 ++++++++++++++++++++++++++++++++++++++
tests/meson.build | 1 +
2 files changed, 564 insertions(+)
create mode 100644 tests/i915/api_intel_bb.c
diff --git a/tests/i915/api_intel_bb.c b/tests/i915/api_intel_bb.c
new file mode 100644
index 00000000..ecc5c156
--- /dev/null
+++ b/tests/i915/api_intel_bb.c
@@ -0,0 +1,563 @@
+/*
+ * Copyright © 2020 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "igt.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <cairo.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include "intel_bufops.h"
+
+#define PAGE_SIZE 4096
+
+#define WIDTH 64
+#define HEIGHT 64
+#define COLOR_00 0x00
+#define COLOR_33 0x33
+#define COLOR_77 0x77
+#define COLOR_CC 0xcc
+
+IGT_TEST_DESCRIPTION("intel_bb API check.");
+
+enum reloc_objects {
+ RELOC,
+ NORELOC,
+};
+
+enum obj_cache_ops {
+ PURGE_CACHE,
+ KEEP_CACHE,
+};
+
+static bool debug_bb = false;
+static bool write_png = false;
+static bool buf_info = false;
+
+static void *alloc_aligned(uint64_t size)
+{
+ void *p;
+
+ igt_assert_eq(posix_memalign(&p, 16, size), 0);
+
+ return p;
+}
+
+static void fill_buf(struct intel_buf *buf, uint8_t color)
+{
+ uint8_t *ptr;
+ int i915 = buf_ops_get_fd(buf->bops);
+ int i;
+
+ ptr = gem_mmap__device_coherent(i915, buf->handle, 0, buf->size,
+ PROT_WRITE);
+
+ for (i = 0; i < buf->size; i++)
+ ptr[i] = color;
+
+ munmap(ptr, buf->size);
+}
+
+static void check_buf(struct intel_buf *buf, uint8_t color)
+{
+ uint8_t *ptr;
+ int i915 = buf_ops_get_fd(buf->bops);
+ int i;
+
+ ptr = gem_mmap__device_coherent(i915, buf->handle, 0, buf->size,
+ PROT_READ);
+
+ for (i = 0; i < buf->size; i++)
+ igt_assert(ptr[i] == color);
+
+ munmap(ptr, buf->size);
+}
+
+
+static struct intel_buf *
+create_buf(struct buf_ops *bops, int width, int height, uint8_t color)
+{
+ struct intel_buf *buf;
+
+ buf = calloc(1, sizeof(*buf));
+ igt_assert(buf);
+
+ intel_buf_init(bops, buf, width/4, height, 32, 0, I915_TILING_NONE, 0);
+ fill_buf(buf, color);
+
+ return buf;
+}
+
+static void print_buf(struct intel_buf *buf, const char *name)
+{
+ uint8_t *ptr;
+ int i915 = buf_ops_get_fd(buf->bops);
+
+ ptr = gem_mmap__device_coherent(i915, buf->handle, 0, buf->size,
+ PROT_READ);
+ igt_debug("[%s] Buf handle: %d, size: %d, v: 0x%02x\n", name,
+ buf->handle, buf->size, ptr[0]);
+ munmap(ptr, buf->size);
+}
+
+static void simple_bb(struct buf_ops *bops)
+{
+ int i915 = buf_ops_get_fd(bops);
+ struct intel_bb *ibb;
+ uint32_t ctx;
+
+ gem_require_contexts(i915);
+
+ ctx = gem_context_create(i915);
+ ibb = intel_bb_create(i915, PAGE_SIZE);
+ if (debug_bb)
+ intel_bb_set_debug(ibb, true);
+
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END);
+ intel_bb_ptr_align(ibb, 8);
+
+ intel_bb_exec(ibb, intel_bb_offset(ibb),
+ I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
+
+ /* Check we're safe with reset and no double-free will occur */
+ intel_bb_reset(ibb, true);
+ intel_bb_reset(ibb, false);
+ intel_bb_reset(ibb, true);
+
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END);
+ intel_bb_ptr_align(ibb, 8);
+
+ intel_bb_exec_with_context(ibb, intel_bb_offset(ibb), ctx,
+ I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
+
+ intel_bb_destroy(ibb);
+ gem_context_destroy(i915, ctx);
+}
+
+static void __emit_blit(struct intel_bb *ibb,
+ struct intel_buf *src, struct intel_buf *dst)
+{
+ bool has_64b_reloc;
+
+ has_64b_reloc = ibb->gen >= 8;
+
+ intel_bb_out(ibb,
+ XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ (6 + 2 * has_64b_reloc));
+ intel_bb_out(ibb, 3 << 24 | 0xcc << 16 | dst->stride);
+ intel_bb_out(ibb, 0);
+ intel_bb_out(ibb, intel_buf_height(dst) << 16 | intel_buf_width(dst));
+ intel_bb_emit_reloc_fenced(ibb, dst->handle,
+ I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER,
+ 0, 0x0);
+ intel_bb_out(ibb, 0);
+ intel_bb_out(ibb, src->stride);
+ intel_bb_emit_reloc_fenced(ibb, src->handle,
+ I915_GEM_DOMAIN_RENDER, 0,
+ 0, 0x0);
+
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END);
+ intel_bb_ptr_align(ibb, 8);
+}
+
+static void blit(struct buf_ops *bops,
+ enum reloc_objects reloc_obj,
+ enum obj_cache_ops cache_op)
+{
+ int i915 = buf_ops_get_fd(bops);
+ struct intel_bb *ibb;
+ struct intel_buf *src, *dst;
+ uint64_t poff_bb, poff_src, poff_dst;
+ uint64_t poff2_bb, poff2_src, poff2_dst;
+ uint64_t flags = I915_EXEC_BLT;
+ bool purge_cache = cache_op == PURGE_CACHE ? true : false;
+ bool do_relocs = reloc_obj == RELOC ? true : false;
+
+ src = create_buf(bops, WIDTH, HEIGHT, COLOR_CC);
+ dst = create_buf(bops, WIDTH, HEIGHT, COLOR_00);
+
+ if (buf_info) {
+ print_buf(src, "src");
+ print_buf(dst, "dst");
+ }
+
+ if (do_relocs) {
+ ibb = intel_bb_create_with_relocs(i915, PAGE_SIZE);
+ } else {
+ ibb = intel_bb_create(i915, PAGE_SIZE);
+ flags |= I915_EXEC_NO_RELOC;
+ }
+
+ if (debug_bb)
+ intel_bb_set_debug(ibb, true);
+
+ __emit_blit(ibb, src, dst);
+
+ /* We expect initial addresses are zeroed for relocs */
+ if (reloc_obj == RELOC) {
+ igt_assert(intel_bb_get_object_offset(ibb, ibb->handle) == 0);
+ igt_assert(intel_bb_get_object_offset(ibb, src->handle) == 0);
+ igt_assert(intel_bb_get_object_offset(ibb, dst->handle) == 0);
+ }
+
+ intel_bb_exec(ibb, intel_bb_offset(ibb), flags, true);
+ check_buf(dst, COLOR_CC);
+
+ poff_bb = intel_bb_get_object_offset(ibb, ibb->handle);
+ poff_src = intel_bb_get_object_offset(ibb, src->handle);
+ poff_dst = intel_bb_get_object_offset(ibb, dst->handle);
+ igt_debug("bb presumed offset: 0x%lx\n", poff_bb);
+ igt_debug("src presumed offset: 0x%lx\n", poff_src);
+ igt_debug("dst presumed offset: 0x%lx\n", poff_dst);
+
+ intel_bb_reset(ibb, purge_cache);
+
+ fill_buf(src, COLOR_77);
+ fill_buf(dst, COLOR_00);
+
+ __emit_blit(ibb, src, dst);
+
+ poff2_bb = intel_bb_get_object_offset(ibb, ibb->handle);
+ poff2_src = intel_bb_get_object_offset(ibb, src->handle);
+ poff2_dst = intel_bb_get_object_offset(ibb, dst->handle);
+ igt_debug("bb2 presumed offset: 0x%lx\n", poff2_bb);
+ igt_debug("src2 presumed offset: 0x%lx\n", poff2_src);
+ igt_debug("dst2 presumed offset: 0x%lx\n", poff2_dst);
+ if (purge_cache) {
+ if (do_relocs) {
+ igt_assert(poff2_bb == 0);
+ igt_assert(poff2_src == 0);
+ igt_assert(poff2_dst == 0);
+ } else {
+ igt_assert(poff_bb != poff2_bb);
+ igt_assert(poff_src != poff2_src);
+ igt_assert(poff_dst != poff2_dst);
+ }
+ } else {
+ igt_assert(poff_bb == poff2_bb);
+ igt_assert(poff_src == poff2_src);
+ igt_assert(poff_dst == poff2_dst);
+ }
+
+ intel_bb_exec(ibb, intel_bb_offset(ibb), flags, true);
+ check_buf(dst, COLOR_77);
+
+ poff2_src = intel_bb_get_object_offset(ibb, src->handle);
+ poff2_dst = intel_bb_get_object_offset(ibb, dst->handle);
+ igt_assert(poff_src == poff2_src);
+ igt_assert(poff_dst == poff2_dst);
+
+ intel_bb_destroy(ibb);
+}
+
+static void scratch_buf_init(struct buf_ops *bops,
+ struct intel_buf *buf,
+ int width, int height,
+ uint32_t req_tiling,
+ enum i915_compression compression)
+{
+ int bpp = 32;
+
+ intel_buf_init(bops, buf, width, height, bpp, 0,
+ req_tiling, compression);
+
+ igt_assert(intel_buf_width(buf) == width);
+ igt_assert(intel_buf_height(buf) == height);
+}
+
+static void scratch_buf_draw_pattern(struct buf_ops *bops,
+ struct intel_buf *buf,
+ int x, int y, int w, int h,
+ int cx, int cy, int cw, int ch,
+ bool use_alternate_colors)
+{
+ cairo_surface_t *surface;
+ cairo_pattern_t *pat;
+ cairo_t *cr;
+ void *linear;
+
+ linear = alloc_aligned(buf->size);
+
+ surface = cairo_image_surface_create_for_data(linear,
+ CAIRO_FORMAT_RGB24,
+ intel_buf_width(buf),
+ intel_buf_height(buf),
+ buf->stride);
+
+ cr = cairo_create(surface);
+
+ cairo_rectangle(cr, cx, cy, cw, ch);
+ cairo_clip(cr);
+
+ pat = cairo_pattern_create_mesh();
+ cairo_mesh_pattern_begin_patch(pat);
+ cairo_mesh_pattern_move_to(pat, x, y);
+ cairo_mesh_pattern_line_to(pat, x+w, y);
+ cairo_mesh_pattern_line_to(pat, x+w, y+h);
+ cairo_mesh_pattern_line_to(pat, x, y+h);
+ if (use_alternate_colors) {
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 0, 0.0, 1.0, 1.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 1, 1.0, 0.0, 1.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 2, 1.0, 1.0, 0.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 3, 0.0, 0.0, 0.0);
+ } else {
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 0, 1.0, 0.0, 0.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 1, 0.0, 1.0, 0.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 2, 0.0, 0.0, 1.0);
+ cairo_mesh_pattern_set_corner_color_rgb(pat, 3, 1.0, 1.0, 1.0);
+ }
+ cairo_mesh_pattern_end_patch(pat);
+
+ cairo_rectangle(cr, x, y, w, h);
+ cairo_set_source(cr, pat);
+ cairo_fill(cr);
+ cairo_pattern_destroy(pat);
+
+ cairo_destroy(cr);
+
+ cairo_surface_destroy(surface);
+
+ linear_to_intel_buf(bops, buf, linear);
+
+ free(linear);
+}
+
+static bool compare_bufs(struct intel_buf *buf1, struct intel_buf *buf2)
+{
+ void *ptr1, *ptr2;
+ int fd1, fd2, ret;
+
+ igt_assert(buf1->size == buf2->size);
+
+ fd1 = buf_ops_get_fd(buf1->bops);
+ fd2 = buf_ops_get_fd(buf2->bops);
+
+ ptr1 = gem_mmap__device_coherent(fd1, buf1->handle, 0, buf1->size,
+ PROT_READ);
+ ptr2 = gem_mmap__device_coherent(fd2, buf2->handle, 0, buf2->size,
+ PROT_READ);
+ ret = memcmp(ptr1, ptr2, buf1->size);
+
+ munmap(ptr1, buf1->size);
+ munmap(ptr2, buf2->size);
+
+ return ret;
+}
+
+static void do_intel_bb_blit(struct buf_ops *bops)
+{
+ struct intel_bb *ibb;
+ const int width = 1024;
+ const int height = 1024;
+ struct intel_buf src, dst, final;
+ int i915 = buf_ops_get_fd(bops);
+
+ ibb = intel_bb_create(i915, PAGE_SIZE);
+ if (debug_bb)
+ intel_bb_set_debug(ibb, true);
+
+ scratch_buf_init(bops, &src, width, height, I915_TILING_NONE,
+ I915_COMPRESSION_NONE);
+ scratch_buf_init(bops, &dst, width, height, I915_TILING_Y,
+ I915_COMPRESSION_NONE);
+ scratch_buf_init(bops, &final, width, height, I915_TILING_NONE,
+ I915_COMPRESSION_NONE);
+
+ if (buf_info) {
+ intel_buf_print(&src);
+ intel_buf_print(&dst);
+ }
+
+ scratch_buf_draw_pattern(bops, &src,
+ 0, 0, width, height,
+ 0, 0, width, height, 0);
+
+ intel_bb_blt_copy(ibb,
+ &src, 0, 0, src.stride,
+ &dst, 0, 0, dst.stride,
+ intel_buf_width(&dst),
+ intel_buf_height(&dst),
+ dst.bpp);
+
+ intel_bb_blt_copy(ibb,
+ &dst, 0, 0, dst.stride,
+ &final, 0, 0, final.stride,
+ intel_buf_width(&dst),
+ intel_buf_height(&dst),
+ dst.bpp);
+
+ intel_bb_destroy(ibb);
+
+ if (write_png) {
+ intel_buf_write_to_png(&src, "bb_blit_src_tiling_none.png");
+ intel_buf_write_to_png(&dst, "bb_blit_dst_tiling_y.png");
+ intel_buf_write_to_png(&final, "bb_blit_final_tiling_none.png");
+ }
+
+ igt_assert(compare_bufs(&src, &dst) != 0);
+ igt_assert(compare_bufs(&src, &final) == 0);
+
+ intel_buf_close(bops, &src);
+ intel_buf_close(bops, &dst);
+ intel_buf_close(bops, &final);
+}
+
+
+static void offset_control(struct buf_ops *bops)
+{
+ int i915 = buf_ops_get_fd(bops);
+ struct intel_bb *ibb;
+ struct intel_buf *src, *dst1, *dst2, *dst3;
+ uint64_t poff_src, poff_dst1, poff_dst2;
+
+ ibb = intel_bb_create(i915, PAGE_SIZE);
+ if (debug_bb)
+ intel_bb_set_debug(ibb, true);
+
+ src = create_buf(bops, WIDTH, HEIGHT, COLOR_CC);
+ dst1 = create_buf(bops, WIDTH, HEIGHT, COLOR_00);
+ dst2 = create_buf(bops, WIDTH, HEIGHT, COLOR_77);
+
+ intel_bb_add_object(ibb, src->handle, src->addr.offset, false);
+ intel_bb_add_object(ibb, dst1->handle, dst1->addr.offset, true);
+ intel_bb_add_object(ibb, dst2->handle, dst2->addr.offset, true);
+
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END);
+ intel_bb_ptr_align(ibb, 8);
+
+ intel_bb_exec(ibb, intel_bb_offset(ibb),
+ I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, false);
+
+ if (buf_info) {
+ print_buf(src, "src ");
+ print_buf(dst1, "dst1");
+ print_buf(dst2, "dst2");
+ }
+
+ igt_assert(intel_bb_object_offset_to_buf(ibb, src) == true);
+ igt_assert(intel_bb_object_offset_to_buf(ibb, dst1) == true);
+ igt_assert(intel_bb_object_offset_to_buf(ibb, dst2) == true);
+ poff_src = src->addr.offset;
+ poff_dst1 = dst1->addr.offset;
+ poff_dst2 = dst2->addr.offset;
+ intel_bb_reset(ibb, true);
+
+ dst3 = create_buf(bops, WIDTH, HEIGHT, COLOR_33);
+ intel_bb_add_object(ibb, dst3->handle, dst3->addr.offset, true);
+ intel_bb_add_object(ibb, src->handle, src->addr.offset, false);
+ intel_bb_add_object(ibb, dst1->handle, dst1->addr.offset, true);
+ intel_bb_add_object(ibb, dst2->handle, dst2->addr.offset, true);
+
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END);
+ intel_bb_ptr_align(ibb, 8);
+
+ intel_bb_exec(ibb, intel_bb_offset(ibb),
+ I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, false);
+ intel_bb_sync(ibb);
+
+ igt_assert(intel_bb_object_offset_to_buf(ibb, src) == true);
+ igt_assert(intel_bb_object_offset_to_buf(ibb, dst1) == true);
+ igt_assert(intel_bb_object_offset_to_buf(ibb, dst2) == true);
+ igt_assert(intel_bb_object_offset_to_buf(ibb, dst3) == true);
+ igt_assert(poff_src == src->addr.offset);
+ igt_assert(poff_dst1 == dst1->addr.offset);
+ igt_assert(poff_dst2 == dst2->addr.offset);
+
+ if (buf_info) {
+ print_buf(src, "src ");
+ print_buf(dst1, "dst1");
+ print_buf(dst2, "dst2");
+ }
+
+ intel_bb_destroy(ibb);
+}
+
+static int opt_handler(int opt, int opt_index, void *data)
+{
+ switch (opt) {
+ case 'd':
+ debug_bb = true;
+ break;
+ case 'p':
+ write_png = true;
+ break;
+ case 'i':
+ buf_info = true;
+ break;
+ default:
+ return IGT_OPT_HANDLER_ERROR;
+ }
+
+ return IGT_OPT_HANDLER_SUCCESS;
+}
+
+const char *help_str =
+ " -d\tDebug bb\n"
+ " -p\tWrite surfaces to png\n"
+ " -i\tPrint buffer info\n"
+ ;
+
+igt_main_args("dpi", NULL, help_str, opt_handler, NULL)
+{
+ int i915;
+ struct buf_ops *bops;
+
+ igt_fixture {
+ i915 = drm_open_driver(DRIVER_INTEL);
+ bops = buf_ops_create(i915);
+ }
+
+ igt_subtest("simple-bb")
+ simple_bb(bops);
+
+ igt_subtest("blit-noreloc-keep-cache")
+ blit(bops, NORELOC, KEEP_CACHE);
+
+ igt_subtest("blit-reloc-purge-cache")
+ blit(bops, RELOC, PURGE_CACHE);
+
+ igt_subtest("blit-noreloc-purge-cache")
+ blit(bops, NORELOC, PURGE_CACHE);
+
+ igt_subtest("blit-reloc-keep-cache")
+ blit(bops, RELOC, KEEP_CACHE);
+
+ igt_subtest("intel-bb-blit")
+ do_intel_bb_blit(bops);
+
+ igt_subtest("offset-control")
+ offset_control(bops);
+
+ igt_fixture {
+ buf_ops_destroy(bops);
+ close(i915);
+ }
+}
diff --git a/tests/meson.build b/tests/meson.build
index 28091794..06a47e37 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -103,6 +103,7 @@ test_progs = [
]
i915_progs = [
+ 'api_intel_bb',
'gen3_mixed_blits',
'gen3_render_linear_blits',
'gen3_render_mixed_blits',
--
2.26.0
More information about the igt-dev
mailing list