[igt-dev] [PATCH i-g-t v4 1/4] lib/intel_batchbuffer: Extend intel_bb
Zbigniew Kempczyński
zbigniew.kempczynski at intel.com
Tue Jun 23 14:21:39 UTC 2020
As we're going toward removing libdrm from rendercopy tests some
additional code in intel_bb is required. So add new functions
and fix memory issues in the reset path.
Signed-off-by: Zbigniew Kempczyński <zbigniew.kempczynski at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
---
lib/intel_batchbuffer.c | 394 +++++++++++++++++++++++++++++++++++++---
lib/intel_batchbuffer.h | 52 +++++-
2 files changed, 417 insertions(+), 29 deletions(-)
diff --git a/lib/intel_batchbuffer.c b/lib/intel_batchbuffer.c
index 2a882627..c3cbafa3 100644
--- a/lib/intel_batchbuffer.c
+++ b/lib/intel_batchbuffer.c
@@ -1045,8 +1045,6 @@ void igt_blitter_fast_copy(struct intel_batchbuffer *batch,
intel_batchbuffer_flush(batch);
}
-#undef CHECK_RANGE
-
/**
* igt_get_render_copyfunc:
* @devid: pci device id
@@ -1211,7 +1209,8 @@ static void __reallocate_objects(struct intel_bb *ibb)
*
* Pointer the intel_bb, asserts on failure.
*/
-struct intel_bb *intel_bb_create(int i915, uint32_t size)
+static struct intel_bb *
+__intel_bb_create(int i915, uint32_t size, bool do_relocs)
{
struct intel_bb *ibb = calloc(1, sizeof(*ibb));
uint64_t gtt_size;
@@ -1221,6 +1220,7 @@ struct intel_bb *intel_bb_create(int i915, uint32_t size)
ibb->i915 = i915;
ibb->devid = intel_get_drm_devid(i915);
ibb->gen = intel_gen(ibb->devid);
+ ibb->enforce_relocs = do_relocs;
ibb->handle = gem_create(i915, size);
ibb->size = size;
ibb->batch = calloc(1, size);
@@ -1241,6 +1241,37 @@ struct intel_bb *intel_bb_create(int i915, uint32_t size)
return ibb;
}
+/**
+ * intel_bb_create:
+ * @i915: drm fd
+ * @size: size of the batchbuffer
+ *
+ * Returns:
+ *
+ * Pointer the intel_bb, asserts on failure.
+ */
+struct intel_bb *intel_bb_create(int i915, uint32_t size)
+{
+ return __intel_bb_create(i915, size, false);
+}
+
+/**
+ * intel_bb_create_with_relocs:
+ * @i915: drm fd
+ * @size: size of the batchbuffer
+ *
+ * Disable passing or randomizing addresses. This will lead to relocations
+ * when objects are not previously pinned.
+ *
+ * Returns:
+ *
+ * Pointer the intel_bb, asserts on failure.
+ */
+struct intel_bb *intel_bb_create_with_relocs(int i915, uint32_t size)
+{
+ return __intel_bb_create(i915, size, true);
+}
+
/*
* tdestroy() calls free function for each node, but we spread tree
* on objects array, so do nothing.
@@ -1250,23 +1281,34 @@ static void __do_nothing(void *node)
(void) node;
}
-static void __intel_bb_destroy_objects(struct intel_bb *ibb)
+static void __intel_bb_destroy_relocations(struct intel_bb *ibb)
{
uint32_t i;
/* Free relocations */
- for (i = 0; i < ibb->num_objects; i++)
+ for (i = 0; i < ibb->num_objects; i++) {
free(from_user_pointer(ibb->objects[i].relocs_ptr));
+ ibb->objects[i].relocs_ptr = to_user_pointer(NULL);
+ }
- free(ibb->objects);
- tdestroy(ibb->root, __do_nothing);
+ ibb->relocs = NULL;
+ ibb->num_relocs = 0;
+ ibb->allocated_relocs = 0;
+}
+static void __intel_bb_destroy_objects(struct intel_bb *ibb)
+{
+ free(ibb->objects);
ibb->objects = NULL;
+
+ tdestroy(ibb->root, __do_nothing);
ibb->root = NULL;
+
+ memset(ibb->batch, 0, ibb->size);
+
ibb->num_objects = 0;
- ibb->num_relocs = 0;
ibb->allocated_objects = 0;
- ibb->allocated_relocs = 0;
+
ibb->ptr = ibb->batch;
}
@@ -1280,6 +1322,7 @@ void intel_bb_destroy(struct intel_bb *ibb)
{
igt_assert(ibb);
+ __intel_bb_destroy_relocations(ibb);
__intel_bb_destroy_objects(ibb);
gem_close(ibb->i915, ibb->handle);
@@ -1295,6 +1338,8 @@ void intel_bb_destroy(struct intel_bb *ibb)
*/
void intel_bb_reset(struct intel_bb *ibb, bool purge_objects_cache)
{
+ __intel_bb_destroy_relocations(ibb);
+
if (purge_objects_cache) {
__intel_bb_destroy_objects(ibb);
__reallocate_objects(ibb);
@@ -1307,6 +1352,60 @@ void intel_bb_reset(struct intel_bb *ibb, bool purge_objects_cache)
ibb->ptr = ibb->batch;
}
+/*
+ * intel_bb_sync:
+ * @ibb: pointer to intel_bb
+ *
+ * Waits for bb completion.
+*/
+void intel_bb_sync(struct intel_bb *ibb)
+{
+ gem_sync(ibb->i915, ibb->handle);
+}
+
+/*
+ * intel_bb_print:
+ * @ibb: pointer to intel_bb
+ *
+ * Prints batch to stdout.
+*/
+void intel_bb_print(struct intel_bb *ibb)
+{
+ igt_info("drm fd: %d, gen: %d, devid: %u, debug: %d\n",
+ ibb->i915, ibb->gen, ibb->devid, ibb->debug);
+ igt_info("handle: %u, size: %u, batch: %p, ptr: %p\n",
+ ibb->handle, ibb->size, ibb->batch, ibb->ptr);
+ igt_info("prng: %u, gtt_size: %" PRIu64 ", supports 48bit: %d\n",
+ ibb->prng, ibb->gtt_size, ibb->supports_48b_address);
+ igt_info("ctx: %u\n", ibb->ctx);
+ igt_info("root: %p\n", ibb->root);
+ igt_info("objects: %p, num_objects: %u, allocated obj: %u\n",
+ ibb->objects, ibb->num_objects, ibb->allocated_objects);
+ igt_info("relocs: %p, num_relocs: %u, allocated_relocs: %u\n----\n",
+ ibb->relocs, ibb->num_relocs, ibb->allocated_relocs);
+}
+
+/*
+ * intel_bb_dump:
+ * @ibb: pointer to intel_bb
+ * @filename: name to which write bb
+ *
+ * Dump batch bo to file.
+*/
+void intel_bb_dump(struct intel_bb *ibb, const char *filename)
+{
+ FILE *out;
+ void *ptr;
+
+ ptr = gem_mmap__device_coherent(ibb->i915, ibb->handle, 0, ibb->size,
+ PROT_READ);
+ out = fopen(filename, "wb");
+ igt_assert(out);
+ fwrite(ptr, ibb->size, 1, out);
+ fclose(out);
+ munmap(ptr, ibb->size);
+}
+
/**
* intel_bb_set_debug:
* @ibb: pointer to intel_bb
@@ -1361,7 +1460,7 @@ intel_bb_add_object(struct intel_bb *ibb, uint32_t handle,
object = *found;
/* Assign address once */
- if (object->offset == 0) {
+ if (!ibb->enforce_relocs && object->offset == 0) {
if (offset) {
object->offset = offset;
} else {
@@ -1382,6 +1481,23 @@ intel_bb_add_object(struct intel_bb *ibb, uint32_t handle,
return object;
}
+static bool intel_bb_object_set_fence(struct intel_bb *ibb, uint32_t handle)
+{
+ struct drm_i915_gem_exec_object2 object = { .handle = handle };
+ struct drm_i915_gem_exec_object2 **found;
+
+ found = tfind((void *) &object, &ibb->root, __compare_objects);
+ if (!found) {
+ igt_warn("Trying to set fence on not found handle: %u\n",
+ handle);
+ return false;
+ }
+
+ (*found)->flags |= EXEC_OBJECT_NEEDS_FENCE;
+
+ return true;
+}
+
/*
* intel_bb_add_reloc:
* @ibb: pointer to intel_bb
@@ -1479,6 +1595,23 @@ uint64_t intel_bb_emit_reloc(struct intel_bb *ibb,
return address;
}
+uint64_t intel_bb_emit_reloc_fenced(struct intel_bb *ibb,
+ uint32_t handle,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint64_t delta,
+ uint64_t presumed_offset)
+{
+ uint64_t address;
+
+ address = intel_bb_emit_reloc(ibb, handle, read_domains, write_domain,
+ delta, presumed_offset);
+
+ intel_bb_object_set_fence(ibb, handle);
+
+ return address;
+}
+
/**
* intel_bb_offset_reloc:
* @ibb: pointer to intel_bb
@@ -1509,7 +1642,23 @@ uint64_t intel_bb_offset_reloc(struct intel_bb *ibb,
0, offset, presumed_offset);
}
-static void intel_bb_dump_execbuf(struct drm_i915_gem_execbuffer2 *execbuf)
+uint64_t intel_bb_offset_reloc_with_delta(struct intel_bb *ibb,
+ uint32_t handle,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint32_t delta,
+ uint32_t offset,
+ uint64_t presumed_offset)
+{
+ igt_assert(ibb);
+
+ return intel_bb_add_reloc(ibb, handle, read_domains, write_domain,
+ delta, offset, presumed_offset);
+}
+
+
+static void intel_bb_dump_execbuf(struct intel_bb *ibb,
+ struct drm_i915_gem_execbuffer2 *execbuf)
{
struct drm_i915_gem_exec_object2 *objects;
struct drm_i915_gem_relocation_entry *relocs, *reloc;
@@ -1535,7 +1684,8 @@ static void intel_bb_dump_execbuf(struct drm_i915_gem_execbuffer2 *execbuf)
i, objects->handle, objects->relocation_count,
relocs,
objects->alignment,
- objects->offset, objects->flags,
+ objects->offset & (ibb->gtt_size - 1),
+ objects->flags,
objects->rsvd1, objects->rsvd2);
if (objects->relocation_count) {
igt_info("\texecbuf relocs:\n");
@@ -1548,7 +1698,7 @@ static void intel_bb_dump_execbuf(struct drm_i915_gem_execbuffer2 *execbuf)
"write_domain: 0x%x\n",
j, reloc->target_handle,
reloc->offset, reloc->delta,
- reloc->presumed_offset,
+ reloc->presumed_offset & (ibb->gtt_size - 1),
reloc->read_domains,
reloc->write_domain);
}
@@ -1616,7 +1766,7 @@ int __intel_bb_exec(struct intel_bb *ibb, uint32_t end_offset,
gem_sync(ibb->i915, ibb->handle);
if (ibb->debug) {
- intel_bb_dump_execbuf(&execbuf);
+ intel_bb_dump_execbuf(ibb, &execbuf);
if (intel_bb_debug_tree) {
igt_info("\nTree:\n");
twalk(ibb->root, print_node);
@@ -1679,7 +1829,7 @@ uint64_t intel_bb_get_object_offset(struct intel_bb *ibb, uint32_t handle)
if (!found)
return 0;
- return (*found)->offset;
+ return (*found)->offset & (ibb->gtt_size - 1);
}
/**
@@ -1692,22 +1842,212 @@ uint64_t intel_bb_get_object_offset(struct intel_bb *ibb, uint32_t handle)
*/
bool intel_bb_object_offset_to_buf(struct intel_bb *ibb, struct intel_buf *buf)
{
- struct drm_i915_gem_exec_object2 object = { .handle = buf->handle };
- struct drm_i915_gem_exec_object2 **found;
+ struct drm_i915_gem_exec_object2 object = { .handle = buf->handle };
+ struct drm_i915_gem_exec_object2 **found;
- igt_assert(ibb);
- igt_assert(buf);
+ igt_assert(ibb);
+ igt_assert(buf);
- found = tfind((void *) &object, &ibb->root, __compare_objects);
- if (!found) {
- buf->addr.offset = 0;
- buf->addr.ctx = 0;
+ found = tfind((void *) &object, &ibb->root, __compare_objects);
+ if (!found) {
+ buf->addr.offset = 0;
+ buf->addr.ctx = 0;
- return false;
+ return false;
+ }
+
+ buf->addr.offset = (*found)->offset & (ibb->gtt_size - 1);
+ buf->addr.ctx = ibb->ctx;
+
+ return true;
+}
+
+/*
+ * intel_bb_out_flush:
+ * @ibb: batchbuffer
+ *
+ * Outputs flushing code to the batch.
+ */
+uint32_t intel_bb_out_flush(struct intel_bb *ibb)
+{
+ if (intel_bb_offset(ibb) == 0)
+ return 0;
+
+ if (IS_GEN5(ibb->devid)) {
+ /* emit gen5 w/a without batch space checks - we reserve that
+ * already. */
+ intel_bb_out(ibb, CMD_POLY_STIPPLE_OFFSET << 16);
+ intel_bb_out(ibb, 0);
}
- buf->addr.offset = (*found)->offset;
- buf->addr.ctx = ibb->ctx;
+ /* Round batchbuffer usage to 2 DWORDs. */
+ intel_bb_ptr_align(ibb, 8);
- return true;
+ /* Mark the end of the buffer. */
+ intel_bb_out(ibb, MI_BATCH_BUFFER_END); /* noop */
+ intel_bb_out(ibb, 0);
+
+ return intel_bb_offset(ibb);
+}
+
+/*
+ * intel_bb_flush_with_context:
+ * @ibb: batchbuffer
+ * @ctx: context id
+ *
+ * Submits the batch for execution on the render engine with the supplied
+ * hardware context.
+ */
+void intel_bb_flush_with_context(struct intel_bb *ibb, uint32_t ctx)
+{
+ if (intel_bb_out_flush(ibb) == 0)
+ return;
+
+ intel_bb_exec_with_context(ibb, intel_bb_offset(ibb), ctx,
+ I915_EXEC_RENDER | I915_EXEC_NO_RELOC,
+ true);
+ intel_bb_reset(ibb, false);
+}
+
+void intel_bb_flush_on_ring(struct intel_bb *ibb, int ring)
+{
+ unsigned int used = intel_bb_out_flush(ibb);
+ uint32_t ctx;
+
+ if (used == 0)
+ return;
+
+ /* XXX bad kernel API */
+ ctx = ibb->ctx;
+ if (ring != I915_EXEC_RENDER)
+ ctx = 0;
+
+ intel_bb_exec_with_context(ibb, intel_bb_offset(ibb), ctx,
+ ring | I915_EXEC_NO_RELOC,
+ true);
+ intel_bb_reset(ibb, false);
+}
+
+void intel_bb_flush(struct intel_bb *ibb)
+{
+ int ring = 0;
+
+ if (HAS_BLT_RING(ibb->devid))
+ ring = I915_EXEC_BLT;
+
+ intel_bb_flush_on_ring(ibb, ring);
+}
+
+uint32_t intel_bb_copy_data(struct intel_bb *ibb,
+ const void *data, unsigned int bytes,
+ uint32_t align)
+{
+ uint32_t *subdata, offset;
+
+ igt_assert((bytes & 3) == 0);
+
+ intel_bb_ptr_align(ibb, align);
+ offset = intel_bb_offset(ibb);
+ igt_assert(offset + bytes < ibb->size);
+
+ subdata = intel_bb_ptr(ibb);
+ memcpy(subdata, data, bytes);
+ intel_bb_ptr_add(ibb, bytes);
+
+ return offset;
+}
+
+void intel_bb_blit_start(struct intel_bb *ibb, uint32_t flags)
+{
+ intel_bb_out(ibb, XY_SRC_COPY_BLT_CMD |
+ XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB |
+ (flags) |
+ (6 + 2*(ibb->gen >= 8)));
+}
+
+void intel_bb_blt_copy(struct intel_bb *ibb,
+ struct intel_buf *src,
+ int src_x1, int src_y1, int src_pitch,
+ struct intel_buf *dst,
+ int dst_x1, int dst_y1, int dst_pitch,
+ int width, int height, int bpp)
+{
+ const int gen = ibb->gen;
+ uint32_t cmd_bits = 0;
+ uint32_t br13_bits;
+
+ igt_assert(bpp*(src_x1 + width) <= 8*src_pitch);
+ igt_assert(bpp*(dst_x1 + width) <= 8*dst_pitch);
+ igt_assert(src_pitch * (src_y1 + height) <= src->size);
+ igt_assert(dst_pitch * (dst_y1 + height) <= dst->size);
+
+ if (gen >= 4 && src->tiling != I915_TILING_NONE) {
+ src_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_SRC_TILED;
+ }
+
+ if (gen >= 4 && dst->tiling != I915_TILING_NONE) {
+ dst_pitch /= 4;
+ cmd_bits |= XY_SRC_COPY_BLT_DST_TILED;
+ }
+
+ CHECK_RANGE(src_x1); CHECK_RANGE(src_y1);
+ CHECK_RANGE(dst_x1); CHECK_RANGE(dst_y1);
+ CHECK_RANGE(width); CHECK_RANGE(height);
+ CHECK_RANGE(src_x1 + width); CHECK_RANGE(src_y1 + height);
+ CHECK_RANGE(dst_x1 + width); CHECK_RANGE(dst_y1 + height);
+ CHECK_RANGE(src_pitch); CHECK_RANGE(dst_pitch);
+
+ br13_bits = 0;
+ switch (bpp) {
+ case 8:
+ break;
+ case 16: /* supporting only RGB565, not ARGB1555 */
+ br13_bits |= 1 << 24;
+ break;
+ case 32:
+ br13_bits |= 3 << 24;
+ cmd_bits |= XY_SRC_COPY_BLT_WRITE_ALPHA |
+ XY_SRC_COPY_BLT_WRITE_RGB;
+ break;
+ default:
+ igt_fail(IGT_EXIT_FAILURE);
+ }
+
+ intel_bb_blit_start(ibb, cmd_bits);
+ intel_bb_out(ibb, (br13_bits) |
+ (0xcc << 16) | /* copy ROP */
+ dst_pitch);
+ intel_bb_out(ibb, (dst_y1 << 16) | dst_x1); /* dst x1,y1 */
+ intel_bb_out(ibb, ((dst_y1 + height) << 16) | (dst_x1 + width)); /* dst x2,y2 */
+ intel_bb_emit_reloc_fenced(ibb, dst->handle,
+ I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
+ 0, dst->addr.offset);
+ intel_bb_out(ibb, (src_y1 << 16) | src_x1); /* src x1,y1 */
+ intel_bb_out(ibb, src_pitch);
+ intel_bb_emit_reloc_fenced(ibb, src->handle,
+ I915_GEM_DOMAIN_RENDER, 0,
+ 0, src->addr.offset);
+
+#define CMD_POLY_STIPPLE_OFFSET 0x7906
+ if (gen == 5) {
+ intel_bb_out(ibb, CMD_POLY_STIPPLE_OFFSET << 16);
+ intel_bb_out(ibb, 0);
+ }
+
+ if (gen >= 6 && src->handle == dst->handle) {
+ intel_bb_out(ibb, XY_SETUP_CLIP_BLT_CMD);
+ intel_bb_out(ibb, 0);
+ intel_bb_out(ibb, 0);
+ }
+
+ if (ibb->gen <= 4) {
+ intel_bb_out(ibb, MI_FLUSH | 2);
+ intel_bb_out(ibb, 0);
+ intel_bb_out(ibb, 0);
+ intel_bb_out(ibb, 0);
+ }
+
+ intel_bb_flush(ibb);
}
diff --git a/lib/intel_batchbuffer.h b/lib/intel_batchbuffer.h
index 0649fc22..d0bd0197 100644
--- a/lib/intel_batchbuffer.h
+++ b/lib/intel_batchbuffer.h
@@ -433,6 +433,7 @@ struct intel_bb {
int i915;
int gen;
bool debug;
+ bool enforce_relocs;
uint32_t devid;
uint32_t handle;
uint32_t size;
@@ -457,9 +458,12 @@ struct intel_bb {
};
struct intel_bb *intel_bb_create(int i915, uint32_t size);
-
+struct intel_bb *intel_bb_create_with_relocs(int i915, uint32_t size);
void intel_bb_destroy(struct intel_bb *ibb);
void intel_bb_reset(struct intel_bb *ibb, bool purge_objects_cache);
+void intel_bb_sync(struct intel_bb *ibb);
+void intel_bb_print(struct intel_bb *ibb);
+void intel_bb_dump(struct intel_bb *ibb, const char *filename);
void intel_bb_set_debug(struct intel_bb *ibb, bool debug);
static inline uint32_t intel_bb_offset(struct intel_bb *ibb)
@@ -479,10 +483,22 @@ static inline void intel_bb_ptr_add(struct intel_bb *ibb, uint32_t offset)
intel_bb_ptr_set(ibb, intel_bb_offset(ibb) + offset);
}
-static inline void intel_bb_ptr_align(struct intel_bb *ibb,
+static inline uint32_t intel_bb_ptr_add_return_prev_offset(struct intel_bb *ibb,
+ uint32_t offset)
+{
+ uint32_t previous_offset = intel_bb_offset(ibb);
+
+ intel_bb_ptr_set(ibb, previous_offset + offset);
+
+ return previous_offset;
+}
+
+static inline void *intel_bb_ptr_align(struct intel_bb *ibb,
uint32_t alignment)
{
intel_bb_ptr_set(ibb, ALIGN(intel_bb_offset(ibb), alignment));
+
+ return (void *) ibb->ptr;
}
static inline void *intel_bb_ptr(struct intel_bb *ibb)
@@ -510,6 +526,13 @@ uint64_t intel_bb_emit_reloc(struct intel_bb *ibb,
uint64_t delta,
uint64_t presumed_offset);
+uint64_t intel_bb_emit_reloc_fenced(struct intel_bb *ibb,
+ uint32_t handle,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint64_t delta,
+ uint64_t presumed_offset);
+
uint64_t intel_bb_offset_reloc(struct intel_bb *ibb,
uint32_t handle,
uint32_t read_domains,
@@ -517,6 +540,14 @@ uint64_t intel_bb_offset_reloc(struct intel_bb *ibb,
uint32_t offset,
uint64_t presumed_offset);
+uint64_t intel_bb_offset_reloc_with_delta(struct intel_bb *ibb,
+ uint32_t handle,
+ uint32_t read_domains,
+ uint32_t write_domain,
+ uint32_t delta,
+ uint32_t offset,
+ uint64_t presumed_offset);
+
int __intel_bb_exec(struct intel_bb *ibb, uint32_t end_offset,
uint32_t ctx, uint64_t flags, bool sync);
@@ -529,4 +560,21 @@ void intel_bb_exec_with_context(struct intel_bb *ibb, uint32_t end_offset,
uint64_t intel_bb_get_object_offset(struct intel_bb *ibb, uint32_t handle);
bool intel_bb_object_offset_to_buf(struct intel_bb *ibb, struct intel_buf *buf);
+uint32_t intel_bb_out_flush(struct intel_bb *ibb);
+void intel_bb_flush_with_context(struct intel_bb *ibb, uint32_t ctx);
+void intel_bb_flush_on_ring(struct intel_bb *ibb, int ring);
+void intel_bb_flush(struct intel_bb *ibb);
+
+uint32_t intel_bb_copy_data(struct intel_bb *ibb,
+ const void *data, unsigned int bytes,
+ uint32_t align);
+
+void intel_bb_blit_start(struct intel_bb *ibb, uint32_t flags);
+
+void intel_bb_blt_copy(struct intel_bb *ibb,
+ struct intel_buf *src,
+ int src_x1, int src_y1, int src_pitch,
+ struct intel_buf *dst,
+ int dst_x1, int dst_y1, int dst_pitch,
+ int width, int height, int bpp);
#endif
--
2.26.0
More information about the igt-dev
mailing list