[igt-dev] [PATCH i-g-t v4 07/10] tests/xe_intel_bb: Check if intel-bb Xe support correctness

Manszewski, Christoph christoph.manszewski at intel.com
Fri Apr 21 13:52:35 UTC 2023


Hi Zbigniew,

On 21.04.2023 07:54, Zbigniew Kempczyński wrote:
> As we're reusing intel-bb for Xe we need to check it behaves correctly
> for buffer handling and submission.
> 
> Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
> ---
>   tests/meson.build      |    1 +
>   tests/xe/xe_intel_bb.c | 1182 ++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 1183 insertions(+)
>   create mode 100644 tests/xe/xe_intel_bb.c
> 
> diff --git a/tests/meson.build b/tests/meson.build
> index 9072cfadc6..5c7affad88 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -255,6 +255,7 @@ xe_progs = [
>   	'xe_exec_threads',
>   	'xe_guc_pc',
>   	'xe_huc_copy',
> +	'xe_intel_bb',
>   	'xe_mmap',
>   	'xe_mmio',
>   	'xe_module_load',
> diff --git a/tests/xe/xe_intel_bb.c b/tests/xe/xe_intel_bb.c
> new file mode 100644
> index 0000000000..e4d12c1070
> --- /dev/null
> +++ b/tests/xe/xe_intel_bb.c
> @@ -0,0 +1,1182 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2023 Intel Corporation
> + */
> +
> +#include <cairo.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <glib.h>
> +#include <inttypes.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +#include <zlib.h>
> +
> +#include "igt.h"
> +#include "igt_crc.h"
> +#include "intel_bufops.h"
> +#include "xe/xe_ioctl.h"
> +#include "xe/xe_query.h"
> +
> +/**
> + * TEST: Basic tests for intel-bb xe functionality
> + * Category: Software building block
> + * Sub-category: xe
> + * Test category: functionality test
> + */
> +
> +#define PAGE_SIZE 4096
> +
> +#define WIDTH	64
> +#define HEIGHT	64
> +#define STRIDE	(WIDTH * 4)
> +#define SIZE	(HEIGHT * STRIDE)
> +
> +#define COLOR_00	0x00
> +#define COLOR_33	0x33
> +#define COLOR_77	0x77
> +#define COLOR_CC	0xcc
> +
> +IGT_TEST_DESCRIPTION("xe_intel_bb API check.");
> +
> +static bool debug_bb;
> +static bool write_png;
> +static bool buf_info;
> +static bool print_base64;
> +
> +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 xe = buf_ops_get_fd(buf->bops);
> +	int i;
> +
> +	ptr = xe_bo_map(xe, buf->handle, buf->surface[0].size);
> +
> +	for (i = 0; i < buf->surface[0].size; i++)
> +		ptr[i] = color;
> +
> +	munmap(ptr, buf->surface[0].size);
> +}
> +
> +static void check_buf(struct intel_buf *buf, uint8_t color)
> +{
> +	uint8_t *ptr;
> +	int xe = buf_ops_get_fd(buf->bops);
> +	int i;
> +
> +	ptr = xe_bo_map(xe, buf->handle, buf->surface[0].size);
> +
> +	for (i = 0; i < buf->surface[0].size; i++)
> +		igt_assert(ptr[i] == color);
> +
> +	munmap(ptr, buf->surface[0].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 xe = buf_ops_get_fd(buf->bops);
> +
> +	ptr = xe_bo_map(xe, buf->handle, buf->surface[0].size);
> +
> +	igt_debug("[%s] Buf handle: %d, size: %" PRIu64
> +		  ", v: 0x%02x, presumed_addr: %p\n",
> +		  name, buf->handle, buf->surface[0].size, ptr[0],
> +		  from_user_pointer(buf->addr.offset));
> +	munmap(ptr, buf->surface[0].size);
> +}
> +
> +/**
> + * SUBTEST: reset-bb
> + * Description: check bb reset
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void reset_bb(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	intel_bb_reset(ibb, false);
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: purge-bb
> + * Description: check bb reset == full (purge)
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void purge_bb(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_buf *buf;
> +	struct intel_bb *ibb;
> +	uint64_t offset0, offset1;
> +
> +	buf = intel_buf_create(bops, 512, 512, 32, 0, I915_TILING_NONE,
> +			       I915_COMPRESSION_NONE);
> +	ibb = intel_bb_create(xe, 4096);
> +	intel_bb_set_debug(ibb, true);
> +
> +	intel_bb_add_intel_buf(ibb, buf, false);
> +	offset0 = buf->addr.offset;
> +
> +	intel_bb_reset(ibb, true);
> +	buf->addr.offset = INTEL_BUF_INVALID_ADDRESS;
> +
> +	intel_bb_add_intel_buf(ibb, buf, false);
> +	offset1 = buf->addr.offset;
> +
> +	igt_assert(offset0 == offset1);
> +
> +	intel_buf_destroy(buf);
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: simple-%s
> + * Description: Run simple bb xe %arg[1] test
> + * Run type: BAT
> + *
> + * arg[1]:
> + *
> + * @bb:     bb
> + * @bb-ctx: bb-ctx
> + */
> +static void simple_bb(struct buf_ops *bops, bool new_context)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	uint32_t ctx = 0;
> +
> +	ibb = intel_bb_create_with_allocator(xe, ctx, NULL, PAGE_SIZE,
> +					     INTEL_ALLOCATOR_SIMPLE);
> +	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);
> +
> +	if (new_context) {
> +		ctx = xe_vm_create(xe, DRM_XE_VM_CREATE_ASYNC_BIND_OPS, 0);
> +		intel_bb_destroy(ibb);
> +		ibb = intel_bb_create_with_context(xe, ctx, NULL, PAGE_SIZE);
> +		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);
> +		xe_vm_destroy(xe, ctx);
> +	}
> +
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: bb-with-allocator
> + * Description: check bb with passed allocator
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void bb_with_allocator(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf *src, *dst;
> +	uint32_t ctx = 0;
> +
> +	ibb = intel_bb_create_with_allocator(xe, ctx, NULL, PAGE_SIZE,
> +					     INTEL_ALLOCATOR_SIMPLE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	src = intel_buf_create(bops, 4096/32, 32, 8, 0, I915_TILING_NONE,
> +			       I915_COMPRESSION_NONE);
> +	dst = intel_buf_create(bops, 4096/32, 32, 8, 0, I915_TILING_NONE,
> +			       I915_COMPRESSION_NONE);
> +
> +	intel_bb_add_intel_buf(ibb, src, false);
> +	intel_bb_add_intel_buf(ibb, dst, true);
> +	intel_bb_copy_intel_buf(ibb, dst, src, 4096);
> +	intel_bb_remove_intel_buf(ibb, src);
> +	intel_bb_remove_intel_buf(ibb, dst);
> +
> +	intel_buf_destroy(src);
> +	intel_buf_destroy(dst);
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: lot-of-buffers
> + * Description: check running bb with many buffers
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +#define NUM_BUFS 500
> +static void lot_of_buffers(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf *buf[NUM_BUFS];
> +	int i;
> +
> +	ibb = intel_bb_create(xe, 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);
> +
> +	for (i = 0; i < NUM_BUFS; i++) {
> +		buf[i] = intel_buf_create(bops, 4096, 1, 8, 0, I915_TILING_NONE,
> +					  I915_COMPRESSION_NONE);
> +		if (i % 2)
> +			intel_bb_add_intel_buf(ibb, buf[i], false);
> +		else
> +			intel_bb_add_intel_buf_with_alignment(ibb, buf[i],
> +							      0x4000, false);
> +	}
> +
> +	intel_bb_exec(ibb, intel_bb_offset(ibb),
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	for (i = 0; i < NUM_BUFS; i++)
> +		intel_buf_destroy(buf[i]);
> +
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: add-remove-objects
> + * Description: check bb object manipulation (add + remove)
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void add_remove_objects(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf *src, *mid, *dst;
> +	uint32_t offset;
> +	const uint32_t width = 512;
> +	const uint32_t height = 512;
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	src = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +	mid = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +	dst = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +
> +	intel_bb_add_intel_buf(ibb, src, false);
> +	intel_bb_add_intel_buf(ibb, mid, true);
> +	intel_bb_remove_intel_buf(ibb, mid);
> +	intel_bb_remove_intel_buf(ibb, mid);
> +	intel_bb_remove_intel_buf(ibb, mid);
> +	intel_bb_add_intel_buf(ibb, dst, true);
> +
> +	offset = intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, offset,
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	intel_buf_destroy(src);
> +	intel_buf_destroy(mid);
> +	intel_buf_destroy(dst);
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: destroy-bb
> + * Description: check bb destroy/create
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void destroy_bb(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf *src, *mid, *dst;
> +	uint32_t offset;
> +	const uint32_t width = 512;
> +	const uint32_t height = 512;
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	src = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +	mid = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +	dst = intel_buf_create(bops, width, height, 32, 0,
> +			       I915_TILING_NONE, I915_COMPRESSION_NONE);
> +
> +	intel_bb_add_intel_buf(ibb, src, false);
> +	intel_bb_add_intel_buf(ibb, mid, true);
> +	intel_bb_add_intel_buf(ibb, dst, true);
> +
> +	offset = intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, offset,
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	/* Check destroy will detach intel_bufs */
> +	intel_bb_destroy(ibb);
> +	igt_assert(src->addr.offset == INTEL_BUF_INVALID_ADDRESS);
> +	igt_assert(src->ibb == NULL);
> +	igt_assert(mid->addr.offset == INTEL_BUF_INVALID_ADDRESS);
> +	igt_assert(mid->ibb == NULL);
> +	igt_assert(dst->addr.offset == INTEL_BUF_INVALID_ADDRESS);
> +	igt_assert(dst->ibb == NULL);
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	intel_bb_add_intel_buf(ibb, src, false);
> +	offset = intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, offset,
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	intel_bb_destroy(ibb);
> +	intel_buf_destroy(src);
> +	intel_buf_destroy(mid);
> +	intel_buf_destroy(dst);
> +}
> +
> +/**
> + * SUBTEST: create-in-region
> + * Description: check size validation on available regions
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void create_in_region(struct buf_ops *bops, uint64_t region)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf buf = {};
> +	uint32_t handle, offset;
> +	uint64_t size;
> +	int width = 64;
> +	int height = 64;
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	size = xe_min_page_size(xe, system_memory(xe));
> +	handle = xe_bo_create_flags(xe, 0, size, system_memory(xe));
> +	intel_buf_init_full(bops, handle, &buf,
> +			    width/4, height, 32, 0,
> +			    I915_TILING_NONE, 0,
> +			    size, region);
> +	intel_buf_set_ownership(&buf, true);
> +
> +	intel_bb_add_intel_buf(ibb, &buf, false);
> +	offset = intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, offset,
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	intel_buf_close(bops, &buf);
> +	intel_bb_destroy(ibb);
> +}
> +
> +static void __emit_blit(struct intel_bb *ibb,
> +			 struct intel_buf *src, struct intel_buf *dst)
> +{
> +	intel_bb_emit_blt_copy(ibb,
> +			       src, 0, 0, src->surface[0].stride,
> +			       dst, 0, 0, dst->surface[0].stride,
> +			       intel_buf_width(dst),
> +			       intel_buf_height(dst),
> +			       dst->bpp);
> +}
> +
> +/**
> + * SUBTEST: blit-%s
> + * Description: Run blit on %arg[1] allocator
> + * Run type: BAT
> + *
> + * arg[1]:
> + *
> + * @simple:				simple
> + * @reloc:				reloc
> + */
> +static void blit(struct buf_ops *bops, uint8_t allocator_type)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	struct intel_buf *src, *dst;
> +	uint64_t poff_src, poff_dst;
> +	uint64_t flags = 0;
> +
> +	ibb = intel_bb_create_with_allocator(xe, 0, NULL, PAGE_SIZE,
> +					     allocator_type);
> +	flags |= I915_EXEC_NO_RELOC;
> +
> +	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 (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	__emit_blit(ibb, src, dst);
> +	intel_bb_emit_bbe(ibb);
> +	intel_bb_flush_blit(ibb);
> +	intel_bb_sync(ibb);
> +	intel_bb_reset(ibb, false);
> +	check_buf(dst, COLOR_CC);
> +
> +	poff_src = intel_bb_get_object_offset(ibb, src->handle);
> +	poff_dst = intel_bb_get_object_offset(ibb, dst->handle);
> +
> +	/* Add buffers again */
> +	intel_bb_add_intel_buf(ibb, src, false);
> +	intel_bb_add_intel_buf(ibb, dst, true);
> +
> +	igt_assert_f(poff_src == src->addr.offset,
> +		     "prev src addr: %" PRIx64 " <> src addr %" PRIx64 "\n",
> +		     poff_src, src->addr.offset);
> +	igt_assert_f(poff_dst == dst->addr.offset,
> +		     "prev dst addr: %" PRIx64 " <> dst addr %" PRIx64 "\n",
> +		     poff_dst, dst->addr.offset);
> +
> +	fill_buf(src, COLOR_77);
> +	fill_buf(dst, COLOR_00);
> +
> +	__emit_blit(ibb, src, dst);
> +	intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, intel_bb_offset(ibb),
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +	check_buf(dst, COLOR_77);
> +
> +	intel_bb_emit_bbe(ibb);
> +	intel_bb_exec(ibb, intel_bb_offset(ibb),
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +	check_buf(dst, COLOR_77);
> +
> +	intel_buf_destroy(src);
> +	intel_buf_destroy(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->surface[0].size);
> +
> +	surface = cairo_image_surface_create_for_data(linear,
> +						      CAIRO_FORMAT_RGB24,
> +						      intel_buf_width(buf),
> +						      intel_buf_height(buf),
> +						      buf->surface[0].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);
> +}
> +
> +#define GROUP_SIZE 4096
> +static int compare_detail(const uint32_t *ptr1, uint32_t *ptr2,
> +			  uint32_t size)
> +{
> +	int i, ok = 0, fail = 0;
> +	int groups = size / GROUP_SIZE;
> +	int *hist = calloc(GROUP_SIZE, groups);
> +
> +	igt_debug("size: %d, group_size: %d, groups: %d\n",
> +		  size, GROUP_SIZE, groups);
> +
> +	for (i = 0; i < size / sizeof(uint32_t); i++) {
> +		if (ptr1[i] == ptr2[i]) {
> +			ok++;
> +		} else {
> +			fail++;
> +			hist[i * sizeof(uint32_t) / GROUP_SIZE]++;
> +		}
> +	}
> +
> +	for (i = 0; i < groups; i++) {
> +		if (hist[i])
> +			igt_debug("[group %4x]: %d\n", i, hist[i]);
> +	}

Nit: redundant braces


> +	free(hist);
> +
> +	igt_debug("ok: %d, fail: %d\n", ok, fail);
> +
> +	return fail;
> +}
> +
> +static int compare_bufs(struct intel_buf *buf1, struct intel_buf *buf2,
> +			 bool detail_compare)
> +{
> +	void *ptr1, *ptr2;
> +	int fd1, fd2, ret;
> +
> +	igt_assert(buf1->surface[0].size == buf2->surface[0].size);
> +
> +	fd1 = buf_ops_get_fd(buf1->bops);
> +	fd2 = buf_ops_get_fd(buf2->bops);
> +
> +	ptr1 = xe_bo_map(fd1, buf1->handle, buf1->surface[0].size);
> +	ptr2 = xe_bo_map(fd2, buf2->handle, buf2->surface[0].size);
> +	ret = memcmp(ptr1, ptr2, buf1->surface[0].size);
> +	if (detail_compare)
> +		ret = compare_detail(ptr1, ptr2, buf1->surface[0].size);
> +
> +	munmap(ptr1, buf1->surface[0].size);
> +	munmap(ptr2, buf2->surface[0].size);
> +
> +	return ret;
> +}
> +
> +#define LINELEN 76ul
> +static int dump_base64(const char *name, struct intel_buf *buf)
> +{
> +	void *ptr;
> +	int fd, ret;
> +	uLongf outsize = buf->surface[0].size * 3 / 2;
> +	Bytef *destbuf = malloc(outsize);
> +	gchar *str, *pos;
> +
> +	fd = buf_ops_get_fd(buf->bops);
> +
> +	ptr = gem_mmap__device_coherent(fd, buf->handle, 0,
> +					buf->surface[0].size, PROT_READ);
> +
> +	ret = compress2(destbuf, &outsize, ptr, buf->surface[0].size,
> +			Z_BEST_COMPRESSION);
> +	if (ret != Z_OK) {
> +		igt_warn("error compressing, ret: %d\n", ret);
> +	} else {
> +		igt_info("compressed %" PRIu64 " -> %lu\n",
> +			 buf->surface[0].size, outsize);
> +
> +		igt_info("--- %s ---\n", name);
> +		pos = str = g_base64_encode(destbuf, outsize);
> +		outsize = strlen(str);
> +		while (pos) {
> +			char line[LINELEN + 1];
> +			int to_copy = min(LINELEN, outsize);
> +
> +			memcpy(line, pos, to_copy);
> +			line[to_copy] = 0;
> +			igt_info("%s\n", line);
> +			pos += LINELEN;
> +			outsize -= to_copy;
> +
> +			if (outsize == 0)
> +				break;
> +		}
> +		free(str);
> +	}
> +
> +	munmap(ptr, buf->surface[0].size);
> +	free(destbuf);
> +
> +	return ret;
> +}
> +
> +static int __do_intel_bb_blit(struct buf_ops *bops, uint32_t tiling)
> +{
> +	struct intel_bb *ibb;
> +	const int width = 1024;
> +	const int height = 1024;
> +	struct intel_buf src, dst, final;
> +	char name[128];
> +	int xe = buf_ops_get_fd(bops), fails;
> +
> +	ibb = intel_bb_create(xe, 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, tiling,
> +			 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.surface[0].stride,
> +			  &dst, 0, 0, dst.surface[0].stride,
> +			  intel_buf_width(&dst),
> +			  intel_buf_height(&dst),
> +			  dst.bpp);
> +
> +	intel_bb_blt_copy(ibb,
> +			  &dst, 0, 0, dst.surface[0].stride,
> +			  &final, 0, 0, final.surface[0].stride,
> +			  intel_buf_width(&dst),
> +			  intel_buf_height(&dst),
> +			  dst.bpp);
> +
> +	igt_assert(intel_bb_sync(ibb) == 0);
> +	intel_bb_destroy(ibb);
> +
> +	if (write_png) {
> +		snprintf(name, sizeof(name) - 1,
> +			 "bb_blit_dst_tiling_%d.png", tiling);
> +		intel_buf_write_to_png(&src, "bb_blit_src_tiling_none.png");
> +		intel_buf_write_to_png(&dst, name);
> +		intel_buf_write_to_png(&final, "bb_blit_final_tiling_none.png");
> +	}
> +
> +	/* We'll fail on src <-> final compare so just warn */
> +	if (tiling == I915_TILING_NONE) {
> +		if (compare_bufs(&src, &dst, false) > 0)
> +			igt_warn("none->none blit failed!");
> +	} else {
> +		if (compare_bufs(&src, &dst, false) == 0)
> +			igt_warn("none->tiled blit failed!");
> +	}

Maybe:

	if (tiling == I915_TILING_NONE && compare_bufs(&src, &dst, false) > 0)
		igt_warn("none->none blit failed!");
	else if (compare_bufs(&src, &dst, false) == 0)
		igt_warn("none->tiled blit failed!");


> +
> +	fails = compare_bufs(&src, &final, true);
> +
> +	intel_buf_close(bops, &src);
> +	intel_buf_close(bops, &dst);
> +	intel_buf_close(bops, &final);
> +
> +	return fails;
> +}
> +
> +/**
> + * SUBTEST: intel-bb-blit-%s
> + * Description: Run simple bb xe %arg[1] test
> + * Run type: BAT
> + *
> + * arg[1]:
> + *
> + * @none:				none
> + * @x:					x
> + * @y:					y
> + */

Hmm not sure I understand those docs on the multi-test functions. Either 
I am missing something or they don't tell much.


> +static void do_intel_bb_blit(struct buf_ops *bops, int loops, uint32_t tiling)
> +{
> +	int i, fails = 0, xe = buf_ops_get_fd(bops);
> +
> +	/* We'll fix it for gen2/3 later. */
> +	igt_require(intel_gen(intel_get_drm_devid(xe)) > 3);
> +
> +	for (i = 0; i < loops; i++)
> +		fails += __do_intel_bb_blit(bops, tiling);
> +
> +	igt_assert_f(fails == 0, "intel-bb-blit (tiling: %d) fails: %d\n",
> +		     tiling, fails);
> +}
> +
> +/**
> + * SUBTEST: offset-control
> + * Description: check offset is kept on default simple allocator
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void offset_control(struct buf_ops *bops)
> +{
> +	int xe = 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(xe, 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, intel_buf_bo_size(src),
> +			    src->addr.offset, 0, false);
> +	intel_bb_add_object(ibb, dst1->handle, intel_buf_bo_size(dst1),
> +			    dst1->addr.offset, 0, true);
> +	intel_bb_add_object(ibb, dst2->handle, intel_buf_bo_size(dst2),
> +			    dst2->addr.offset, 0, 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");
> +	}
> +
> +	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, intel_buf_bo_size(dst3),
> +			    dst3->addr.offset, 0, true);
> +	intel_bb_add_object(ibb, src->handle, intel_buf_bo_size(src),
> +			    src->addr.offset, 0, false);
> +	intel_bb_add_object(ibb, dst1->handle, intel_buf_bo_size(dst1),
> +			    dst1->addr.offset, 0, true);
> +	intel_bb_add_object(ibb, dst2->handle, intel_buf_bo_size(dst2),
> +			    dst2->addr.offset, 0, 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);
> +	intel_bb_reset(ibb, 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_buf_destroy(src);
> +	intel_buf_destroy(dst1);
> +	intel_buf_destroy(dst2);
> +	intel_buf_destroy(dst3);
> +	intel_bb_destroy(ibb);
> +}
> +
> +/*
> + * Idea of the test is to verify delta is properly added to address
> + * when emit_reloc() is called.
> + */
> +
> +/**
> + * SUBTEST: delta-check
> + * Description: check delta is honoured in intel-bb pipelines
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +#define DELTA_BUFFERS 3
> +static void delta_check(struct buf_ops *bops)
> +{
> +	const uint32_t expected = 0x1234abcd;
> +	int xe = buf_ops_get_fd(bops);
> +	uint32_t *ptr, hi, lo, val;
> +	struct intel_buf *buf;
> +	struct intel_bb *ibb;
> +	uint64_t offset;
> +	uint64_t obj_size = xe_get_default_alignment(xe) + 0x2000;
> +	uint64_t obj_offset = (1ULL << 32) - xe_get_default_alignment(xe);
> +	uint64_t delta = xe_get_default_alignment(xe) + 0x1000;
> +
> +	ibb = intel_bb_create_with_allocator(xe, 0, NULL, PAGE_SIZE,
> +					     INTEL_ALLOCATOR_SIMPLE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	buf = create_buf(bops, obj_size, 0x1, COLOR_CC);
> +	buf->addr.offset = obj_offset;
> +	intel_bb_add_object(ibb, buf->handle, intel_buf_bo_size(buf),
> +			    buf->addr.offset, 0, false);
> +
> +	intel_bb_out(ibb, MI_STORE_DWORD_IMM_GEN4);
> +	intel_bb_emit_reloc(ibb, buf->handle,
> +			    I915_GEM_DOMAIN_RENDER,
> +			    I915_GEM_DOMAIN_RENDER,
> +			    delta, buf->addr.offset);
> +	intel_bb_out(ibb, expected);
> +
> +	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, false);
> +	intel_bb_sync(ibb);
> +
> +	/* Buffer should be @ obj_offset */
> +	offset = intel_bb_get_object_offset(ibb, buf->handle);
> +	igt_assert_eq_u64(offset, obj_offset);
> +
> +	ptr = xe_bo_map(xe, ibb->handle, ibb->size);
> +	lo = ptr[1];
> +	hi = ptr[2];
> +	gem_munmap(ptr, ibb->size);
> +
> +	ptr = xe_bo_map(xe, buf->handle, intel_buf_size(buf));
> +	val = ptr[delta / sizeof(uint32_t)];
> +	gem_munmap(ptr, intel_buf_size(buf));
> +
> +	intel_buf_destroy(buf);
> +	intel_bb_destroy(ibb);
> +
> +	/* Assert after all resources are freed */
> +	igt_assert_f(lo == 0x1000 && hi == 0x1,
> +		     "intel-bb doesn't properly handle delta in emit relocation\n");
> +	igt_assert_f(val == expected,
> +		     "Address doesn't contain expected [%x] value [%x]\n",
> +		     expected, val);
> +}
> +
> +/**
> + * SUBTEST: full-batch
> + * Description: check bb totally filled is executing correct
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static void full_batch(struct buf_ops *bops)
> +{
> +	int xe = buf_ops_get_fd(bops);
> +	struct intel_bb *ibb;
> +	int i;
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	for (i = 0; i < PAGE_SIZE / sizeof(uint32_t) - 1; i++)
> +		intel_bb_out(ibb, 0);
> +	intel_bb_emit_bbe(ibb);
> +
> +	igt_assert(intel_bb_offset(ibb) == PAGE_SIZE);
> +	intel_bb_exec(ibb, intel_bb_offset(ibb),
> +		      I915_EXEC_DEFAULT | I915_EXEC_NO_RELOC, true);
> +	intel_bb_reset(ibb, false);
> +
> +	intel_bb_destroy(ibb);
> +}
> +
> +/**
> + * SUBTEST: render
> + * Description: check intel-bb render pipeline
> + * Run type: FULL
> + * TODO: change ``'Run type' == FULL`` to a better category
> + */
> +static int render(struct buf_ops *bops, uint32_t tiling,
> +		  uint32_t width, uint32_t height)
> +{
> +	struct intel_bb *ibb;
> +	struct intel_buf src, dst, final;
> +	int xe = buf_ops_get_fd(bops);
> +	uint32_t fails = 0;
> +	char name[128];
> +	uint32_t devid = intel_get_drm_devid(xe);
> +	igt_render_copyfunc_t render_copy = NULL;
> +
> +	igt_debug("%s() gen: %d\n", __func__, intel_gen(devid));
> +
> +	ibb = intel_bb_create(xe, PAGE_SIZE);
> +
> +	if (debug_bb)
> +		intel_bb_set_debug(ibb, true);
> +
> +	if (print_base64)
> +		intel_bb_set_dump_base64(ibb, true);
> +
> +	scratch_buf_init(bops, &src, width, height, I915_TILING_NONE,
> +			 I915_COMPRESSION_NONE);
> +	scratch_buf_init(bops, &dst, width, height, tiling,
> +			 I915_COMPRESSION_NONE);
> +	scratch_buf_init(bops, &final, width, height, I915_TILING_NONE,
> +			 I915_COMPRESSION_NONE);
> +
> +	scratch_buf_draw_pattern(bops, &src,
> +				 0, 0, width, height,
> +				 0, 0, width, height, 0);
> +
> +	render_copy = igt_get_render_copyfunc(devid);
> +	igt_assert(render_copy);
> +
> +	render_copy(ibb,
> +		    &src,
> +		    0, 0, width, height,
> +		    &dst,
> +		    0, 0);
> +
> +	render_copy(ibb,
> +		    &dst,
> +		    0, 0, width, height,
> +		    &final,
> +		    0, 0);
> +
> +	intel_bb_sync(ibb);
> +	intel_bb_destroy(ibb);
> +
> +	if (write_png) {
> +		snprintf(name, sizeof(name) - 1,
> +			 "render_dst_tiling_%d.png", tiling);
> +		intel_buf_write_to_png(&src, "render_src_tiling_none.png");
> +		intel_buf_write_to_png(&dst, name);
> +		intel_buf_write_to_png(&final, "render_final_tiling_none.png");
> +	}
> +
> +	/* We'll fail on src <-> final compare so just warn */
> +	if (tiling == I915_TILING_NONE) {
> +		if (compare_bufs(&src, &dst, false) > 0)
> +			igt_warn("%s: none->none failed!\n", __func__);
> +	} else {
> +		if (compare_bufs(&src, &dst, false) == 0)
> +			igt_warn("%s: none->tiled failed!\n", __func__);
> +	}

Like for blit, can be compacted, not insisting though.


> +
> +	fails = compare_bufs(&src, &final, true);
> +
> +	if (fails && print_base64) {
> +		dump_base64("src", &src);
> +		dump_base64("dst", &dst);
> +		dump_base64("final", &final);
> +	}
> +
> +	intel_buf_close(bops, &src);
> +	intel_buf_close(bops, &dst);
> +	intel_buf_close(bops, &final);
> +
> +	igt_assert_f(fails == 0, "%s: (tiling: %d) fails: %d\n",
> +		     __func__, tiling, fails);
> +
> +	return fails;
> +}
> +
> +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;
> +	case 'b':
> +		print_base64 = 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"
> +	"  -b\tDump to base64 (bb and images)\n"
> +	"  -c n\tCalculate crc up to (1 << n)\n"

'c' seems to be missing in opt_handler above, and in opt list below.


> +	;
> +
> +igt_main_args("dpib", NULL, help_str, opt_handler, NULL)
> +{
> +	int xe, i;
> +	struct buf_ops *bops;
> +	uint32_t width;
> +
> +	struct test {
> +		uint32_t tiling;
> +		const char *tiling_name;
> +	} tests[] = {
> +		{ I915_TILING_NONE, "none" },
> +		{ I915_TILING_X, "x" },
> +		{ I915_TILING_Y, "y" },
> +	};
> +
> +	igt_fixture {
> +		xe = drm_open_driver(DRIVER_XE);
> +		bops = buf_ops_create(xe);
> +		xe_device_get(xe);
> +	}
> +
> +	igt_describe("Ensure reset is possible on fresh bb");
> +	igt_subtest("reset-bb")
> +		reset_bb(bops);
> +
> +	igt_subtest_f("purge-bb")
> +		purge_bb(bops);
> +
> +	igt_subtest("simple-bb")
> +		simple_bb(bops, false);
> +
> +	igt_subtest("simple-bb-ctx")
> +		simple_bb(bops, true);
> +
> +	igt_subtest("bb-with-allocator")
> +		bb_with_allocator(bops);
> +
> +	igt_subtest("lot-of-buffers")
> +		lot_of_buffers(bops);
> +
> +	igt_subtest("add-remove-objects")
> +		add_remove_objects(bops);
> +
> +	igt_subtest("destroy-bb")
> +		destroy_bb(bops);
> +
> +	igt_subtest_with_dynamic("create-in-region") {
> +		uint64_t memreg = all_memory_regions(xe), region;
> +
> +		xe_for_each_mem_region(fd, memreg, region)
> +			igt_dynamic_f("region-%s", xe_region_name(region))
> +				create_in_region(bops, region);
> +	}
> +
> +	igt_subtest("blit-simple")
> +		blit(bops, INTEL_ALLOCATOR_SIMPLE);
> +
> +	igt_subtest("blit-reloc")
> +		blit(bops, INTEL_ALLOCATOR_RELOC);
> +
> +	igt_subtest("intel-bb-blit-none")
> +		do_intel_bb_blit(bops, 3, I915_TILING_NONE);
> +
> +	igt_subtest("intel-bb-blit-x")
> +		do_intel_bb_blit(bops, 3, I915_TILING_X);
> +
> +	igt_subtest("intel-bb-blit-y") {
> +		igt_require(intel_gen(intel_get_drm_devid(xe)) >= 6);
> +		do_intel_bb_blit(bops, 3, I915_TILING_Y);
> +	}
> +
> +	igt_subtest("offset-control")
> +		offset_control(bops);
> +
> +	igt_subtest("delta-check")
> +		delta_check(bops);
> +
> +	igt_subtest("full-batch")
> +		full_batch(bops);
> +
> +	igt_subtest_with_dynamic("render") {
> +		for (i = 0; i < ARRAY_SIZE(tests); i++) {
> +			const struct test *t = &tests[i];
> +
> +			for (width = 512; width <= 1024; width += 512) {
> +				igt_dynamic_f("render-%s-%u", t->tiling_name, width) {
> +					render(bops, t->tiling, width, width);
> +				}
> +			}

Nit: redundant braces in igt_dynamic_f and nested for.


The only thing that hints something may be missing, is the crc opt.
Other than that - lgtm.

Reviewed-by: Christoph Manszewski <christoph.manszewski at intel.com>

Christoph


> +		}
> +	}
> +
> +	igt_fixture {
> +		xe_device_put(xe);
> +		buf_ops_destroy(bops);
> +		close(xe);
> +	}
> +}
---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
ul. Slowackiego 173 | 80-298 Gdansk | Sad Rejonowy Gdansk Polnoc | VII Wydzial Gospodarczy Krajowego Rejestru Sadowego - KRS 101882 | NIP 957-07-52-316 | Kapital zakladowy 200.000 PLN.
Spolka oswiadcza, ze posiada status duzego przedsiebiorcy w rozumieniu ustawy z dnia 8 marca 2013 r. o przeciwdzialaniu nadmiernym opoznieniom w transakcjach handlowych.

Ta wiadomosc wraz z zalacznikami jest przeznaczona dla okreslonego adresata i moze zawierac informacje poufne. W razie przypadkowego otrzymania tej wiadomosci, prosimy o powiadomienie nadawcy oraz trwale jej usuniecie; jakiekolwiek przegladanie lub rozpowszechnianie jest zabronione.
This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). If you are not the intended recipient, please contact the sender and delete all copies; any review or distribution by others is strictly prohibited.


More information about the igt-dev mailing list