#include <stdbool.h>
#include "errno.h"
+#ifndef ETIME
+#define ETIME ETIMEDOUT
+#endif
#include "libdrm_lists.h"
#include "intel_bufmgr.h"
#include "intel_bufmgr_priv.h"
unsigned int has_blt : 1;
unsigned int has_relaxed_fencing : 1;
unsigned int has_llc : 1;
+ unsigned int has_wait_timeout : 1;
unsigned int bo_reuse : 1;
unsigned int no_exec : 1;
+ unsigned int has_vebox : 1;
bool fenced_relocs;
+ char *aub_filename;
FILE *aub_file;
uint32_t aub_offset;
} drm_intel_bufmgr_gem;
/**
* Kenel-assigned global name for this object
+ *
+ * List contains both flink named and prime fd'd objects
*/
unsigned int global_name;
drmMMListHead name_list;
bool reusable;
/**
+ * Boolean of whether the GPU is definitely not accessing the buffer.
+ *
+ * This is only valid when reusable, since non-reusable
+ * buffers are those that have been shared wth other
+ * processes, so we don't know their state.
+ */
+ bool idle;
+
+ /**
* Size in bytes of this buffer and its relocation descendents.
*
* Used to avoid costly tree walking in
bool mapped_cpu_write;
uint32_t aub_offset;
+
+ drm_intel_aub_annotation *aub_annotations;
+ unsigned aub_annotation_count;
};
static unsigned int
(unsigned long long)bo_gem->relocs[j].offset,
target_gem->gem_handle,
target_gem->name,
- target_bo->offset,
+ target_bo->offset64,
bo_gem->relocs[j].delta);
}
}
struct drm_i915_gem_busy busy;
int ret;
+ if (bo_gem->reusable && bo_gem->idle)
+ return false;
+
VG_CLEAR(busy);
busy.handle = bo_gem->gem_handle;
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
-
+ if (ret == 0) {
+ bo_gem->idle = !busy.busy;
+ return busy.busy;
+ } else {
+ return false;
+ }
return (ret == 0 && busy.busy);
}
bo_gem->used_as_reloc_target = false;
bo_gem->has_error = false;
bo_gem->reusable = true;
+ bo_gem->aub_annotations = NULL;
+ bo_gem->aub_annotation_count = 0;
drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
}
}
- bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem)
- return NULL;
-
VG_CLEAR(open_arg);
open_arg.name = handle;
ret = drmIoctl(bufmgr_gem->fd,
if (ret != 0) {
DBG("Couldn't reference %s handle 0x%08x: %s\n",
name, handle, strerror(errno));
- free(bo_gem);
return NULL;
}
+ /* Now see if someone has used a prime handle to get this
+ * object from the kernel before by looking through the list
+ * again for a matching gem_handle
+ */
+ for (list = bufmgr_gem->named.next;
+ list != &bufmgr_gem->named;
+ list = list->next) {
+ bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
+ if (bo_gem->gem_handle == open_arg.handle) {
+ drm_intel_gem_bo_reference(&bo_gem->bo);
+ return &bo_gem->bo;
+ }
+ }
+
+ bo_gem = calloc(1, sizeof(*bo_gem));
+ if (!bo_gem)
+ return NULL;
+
bo_gem->bo.size = open_arg.size;
bo_gem->bo.offset = 0;
+ bo_gem->bo.offset64 = 0;
bo_gem->bo.virtual = NULL;
bo_gem->bo.bufmgr = bufmgr;
bo_gem->name = name;
DBG("DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n",
bo_gem->gem_handle, bo_gem->name, strerror(errno));
}
+ free(bo_gem->aub_annotations);
free(bo);
}
int drm_intel_gem_bo_map_unsynchronized(drm_intel_bo *bo)
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+#ifdef HAVE_VALGRIND
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+#endif
int ret;
/* If the CPU cache isn't coherent with the GTT, then use a
return drm_intel_gem_bo_map_gtt(bo);
pthread_mutex_lock(&bufmgr_gem->lock);
+
ret = map_gtt(bo);
+ if (ret == 0) {
+ drm_intel_gem_bo_mark_mmaps_incoherent(bo);
+ VG(VALGRIND_MAKE_MEM_DEFINED(bo_gem->gtt_virtual, bo->size));
+ }
+
pthread_mutex_unlock(&bufmgr_gem->lock);
return ret;
}
/**
+ * Waits on a BO for the given amount of time.
+ *
+ * @bo: buffer object to wait for
+ * @timeout_ns: amount of time to wait in nanoseconds.
+ * If value is less than 0, an infinite wait will occur.
+ *
+ * Returns 0 if the wait was successful ie. the last batch referencing the
+ * object has completed within the allotted time. Otherwise some negative return
+ * value describes the error. Of particular interest is -ETIME when the wait has
+ * failed to yield the desired result.
+ *
+ * Similar to drm_intel_gem_bo_wait_rendering except a timeout parameter allows
+ * the operation to give up after a certain amount of time. Another subtle
+ * difference is the internal locking semantics are different (this variant does
+ * not hold the lock for the duration of the wait). This makes the wait subject
+ * to a larger userspace race window.
+ *
+ * The implementation shall wait until the object is no longer actively
+ * referenced within a batch buffer at the time of the call. The wait will
+ * not guarantee that the buffer is re-issued via another thread, or an flinked
+ * handle. Userspace must make sure this race does not occur if such precision
+ * is important.
+ */
+int drm_intel_gem_bo_wait(drm_intel_bo *bo, int64_t timeout_ns)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+ struct drm_i915_gem_wait wait;
+ int ret;
+
+ if (!bufmgr_gem->has_wait_timeout) {
+ DBG("%s:%d: Timed wait is not supported. Falling back to "
+ "infinite wait\n", __FILE__, __LINE__);
+ if (timeout_ns) {
+ drm_intel_gem_bo_wait_rendering(bo);
+ return 0;
+ } else {
+ return drm_intel_gem_bo_busy(bo) ? -ETIME : 0;
+ }
+ }
+
+ wait.bo_handle = bo_gem->gem_handle;
+ wait.timeout_ns = timeout_ns;
+ wait.flags = 0;
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_WAIT, &wait);
+ if (ret == -1)
+ return -errno;
+
+ return ret;
+}
+
+/**
* Sets the object to the GTT read and possibly write domain, used by the X
* 2D driver in the absence of kernel support to do drm_intel_gem_bo_map_gtt().
*
free(bufmgr_gem->exec2_objects);
free(bufmgr_gem->exec_objects);
free(bufmgr_gem->exec_bos);
+ free(bufmgr_gem->aub_filename);
pthread_mutex_destroy(&bufmgr_gem->lock);
target_bo_gem->gem_handle;
bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains;
bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain;
- bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset;
+ bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset64;
bo_gem->reloc_target_info[bo_gem->reloc_count].bo = target_bo;
if (target_bo != bo)
assert(bo_gem->reloc_count >= start);
/* Unreference the cleared target buffers */
for (i = start; i < bo_gem->reloc_count; i++) {
- if (bo_gem->reloc_target_info[i].bo != bo) {
- drm_intel_gem_bo_unreference_locked_timed(bo_gem->
- reloc_target_info[i].bo,
+ drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) bo_gem->reloc_target_info[i].bo;
+ if (&target_bo_gem->bo != bo) {
+ bo_gem->reloc_tree_fences -= target_bo_gem->reloc_tree_fences;
+ drm_intel_gem_bo_unreference_locked_timed(&target_bo_gem->bo,
time.tv_sec);
}
}
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
/* Update the buffer offset */
- if (bufmgr_gem->exec_objects[i].offset != bo->offset) {
+ if (bufmgr_gem->exec_objects[i].offset != bo->offset64) {
DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n",
- bo_gem->gem_handle, bo_gem->name, bo->offset,
+ bo_gem->gem_handle, bo_gem->name, bo->offset64,
(unsigned long long)bufmgr_gem->exec_objects[i].
offset);
+ bo->offset64 = bufmgr_gem->exec_objects[i].offset;
bo->offset = bufmgr_gem->exec_objects[i].offset;
}
}
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo;
/* Update the buffer offset */
- if (bufmgr_gem->exec2_objects[i].offset != bo->offset) {
+ if (bufmgr_gem->exec2_objects[i].offset != bo->offset64) {
DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n",
- bo_gem->gem_handle, bo_gem->name, bo->offset,
+ bo_gem->gem_handle, bo_gem->name, bo->offset64,
(unsigned long long)bufmgr_gem->exec2_objects[i].offset);
+ bo->offset64 = bufmgr_gem->exec2_objects[i].offset;
bo->offset = bufmgr_gem->exec2_objects[i].offset;
}
}
aub_out(bufmgr_gem,
CMD_AUB_TRACE_HEADER_BLOCK |
- (5 - 2));
+ ((bufmgr_gem->gen >= 8 ? 6 : 5) - 2));
aub_out(bufmgr_gem,
AUB_TRACE_MEMTYPE_GTT | type | AUB_TRACE_OP_DATA_WRITE);
aub_out(bufmgr_gem, subtype);
aub_out(bufmgr_gem, bo_gem->aub_offset + offset);
aub_out(bufmgr_gem, size);
+ if (bufmgr_gem->gen >= 8)
+ aub_out(bufmgr_gem, 0);
aub_write_bo_data(bo, offset, size);
}
+/**
+ * Break up large objects into multiple writes. Otherwise a 128kb VBO
+ * would overflow the 16 bits of size field in the packet header and
+ * everything goes badly after that.
+ */
static void
-aub_write_bo(drm_intel_bo *bo)
+aub_write_large_trace_block(drm_intel_bo *bo, uint32_t type, uint32_t subtype,
+ uint32_t offset, uint32_t size)
{
uint32_t block_size;
- uint32_t offset;
-
- aub_bo_get_address(bo);
+ uint32_t sub_offset;
- /* Break up large objects into multiple writes. Otherwise a
- * 128kb VBO would overflow the 16 bits of size field in the
- * packet header and everything goes badly after that.
- */
- for (offset = 0; offset < bo->size; offset += block_size) {
- block_size = bo->size - offset;
+ for (sub_offset = 0; sub_offset < size; sub_offset += block_size) {
+ block_size = size - sub_offset;
if (block_size > 8 * 4096)
block_size = 8 * 4096;
- aub_write_trace_block(bo, AUB_TRACE_TYPE_NOTYPE, 0,
- offset, block_size);
+ aub_write_trace_block(bo, type, subtype, offset + sub_offset,
+ block_size);
+ }
+}
+
+static void
+aub_write_bo(drm_intel_bo *bo)
+{
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+ uint32_t offset = 0;
+ unsigned i;
+
+ aub_bo_get_address(bo);
+
+ /* Write out each annotated section separately. */
+ for (i = 0; i < bo_gem->aub_annotation_count; ++i) {
+ drm_intel_aub_annotation *annotation =
+ &bo_gem->aub_annotations[i];
+ uint32_t ending_offset = annotation->ending_offset;
+ if (ending_offset > bo->size)
+ ending_offset = bo->size;
+ if (ending_offset > offset) {
+ aub_write_large_trace_block(bo, annotation->type,
+ annotation->subtype,
+ offset,
+ ending_offset - offset);
+ offset = ending_offset;
+ }
+ }
+
+ /* Write out any remaining unannotated data */
+ if (offset < bo->size) {
+ aub_write_large_trace_block(bo, AUB_TRACE_TYPE_NOTYPE, 0,
+ offset, bo->size - offset);
}
}
if (ring_flag == I915_EXEC_BSD)
ring = AUB_TRACE_TYPE_RING_PRB1;
+ else if (ring_flag == I915_EXEC_BLT)
+ ring = AUB_TRACE_TYPE_RING_PRB2;
/* Make a ring buffer to execute our batchbuffer. */
memset(ringbuffer, 0, sizeof(ringbuffer));
- ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START;
- ringbuffer[ring_count++] = batch_buffer;
+ if (bufmgr_gem->gen >= 8) {
+ ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START | (3 - 2);
+ ringbuffer[ring_count++] = batch_buffer;
+ ringbuffer[ring_count++] = 0;
+ } else {
+ ringbuffer[ring_count++] = AUB_MI_BATCH_BUFFER_START;
+ ringbuffer[ring_count++] = batch_buffer;
+ }
/* Write out the ring. This appears to trigger execution of
* the ring in the simulator.
*/
aub_out(bufmgr_gem,
CMD_AUB_TRACE_HEADER_BLOCK |
- (5 - 2));
+ ((bufmgr_gem->gen >= 8 ? 6 : 5) - 2));
aub_out(bufmgr_gem,
AUB_TRACE_MEMTYPE_GTT | ring | AUB_TRACE_OP_COMMAND_WRITE);
aub_out(bufmgr_gem, 0); /* general/surface subtype */
aub_out(bufmgr_gem, bufmgr_gem->aub_offset);
aub_out(bufmgr_gem, ring_count * 4);
+ if (bufmgr_gem->gen >= 8)
+ aub_out(bufmgr_gem, 0);
/* FIXME: Need some flush operations here? */
aub_out_data(bufmgr_gem, ringbuffer, ring_count * 4);
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
int i;
+ bool batch_buffer_needs_annotations;
if (!bufmgr_gem->aub_file)
return;
- /* Write out all but the batchbuffer to AUB memory */
- for (i = 0; i < bufmgr_gem->exec_count - 1; i++) {
- if (bufmgr_gem->exec_bos[i] != bo)
- aub_write_bo(bufmgr_gem->exec_bos[i]);
+ /* If batch buffer is not annotated, annotate it the best we
+ * can.
+ */
+ batch_buffer_needs_annotations = bo_gem->aub_annotation_count == 0;
+ if (batch_buffer_needs_annotations) {
+ drm_intel_aub_annotation annotations[2] = {
+ { AUB_TRACE_TYPE_BATCH, 0, used },
+ { AUB_TRACE_TYPE_NOTYPE, 0, bo->size }
+ };
+ drm_intel_bufmgr_gem_set_aub_annotations(bo, annotations, 2);
}
- aub_bo_get_address(bo);
+ /* Write out all buffers to AUB memory */
+ for (i = 0; i < bufmgr_gem->exec_count; i++) {
+ aub_write_bo(bufmgr_gem->exec_bos[i]);
+ }
- /* Dump the batchbuffer. */
- aub_write_trace_block(bo, AUB_TRACE_TYPE_BATCH, 0,
- 0, used);
- aub_write_trace_block(bo, AUB_TRACE_TYPE_NOTYPE, 0,
- used, bo->size - used);
+ /* Remove any annotations we added */
+ if (batch_buffer_needs_annotations)
+ drm_intel_bufmgr_gem_set_aub_annotations(bo, NULL, 0);
/* Dump ring buffer */
aub_build_dump_ringbuffer(bufmgr_gem, bo_gem->aub_offset, ring_flag);
drm_intel_bo *bo = bufmgr_gem->exec_bos[i];
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+ bo_gem->idle = false;
+
/* Disconnect the buffer from the validate list */
bo_gem->validate_index = -1;
bufmgr_gem->exec_bos[i] = NULL;
}
static int
-drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used,
- drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
- unsigned int flags)
+do_exec2(drm_intel_bo *bo, int used, drm_intel_context *ctx,
+ drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
+ unsigned int flags)
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
struct drm_i915_gem_execbuffer2 execbuf;
if (!bufmgr_gem->has_bsd)
return -EINVAL;
break;
+ case I915_EXEC_VEBOX:
+ if (!bufmgr_gem->has_vebox)
+ return -EINVAL;
+ break;
case I915_EXEC_RENDER:
case I915_EXEC_DEFAULT:
break;
execbuf.DR1 = 0;
execbuf.DR4 = DR4;
execbuf.flags = flags;
- execbuf.rsvd1 = 0;
+ if (ctx == NULL)
+ i915_execbuffer2_set_context_id(execbuf, 0);
+ else
+ i915_execbuffer2_set_context_id(execbuf, ctx->ctx_id);
execbuf.rsvd2 = 0;
aub_exec(bo, flags, used);
drm_intel_bo *bo = bufmgr_gem->exec_bos[i];
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo;
+ bo_gem->idle = false;
+
/* Disconnect the buffer from the validate list */
bo_gem->validate_index = -1;
bufmgr_gem->exec_bos[i] = NULL;
drm_clip_rect_t *cliprects, int num_cliprects,
int DR4)
{
- return drm_intel_gem_bo_mrb_exec2(bo, used,
- cliprects, num_cliprects, DR4,
- I915_EXEC_RENDER);
+ return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
+ I915_EXEC_RENDER);
+}
+
+static int
+drm_intel_gem_bo_mrb_exec2(drm_intel_bo *bo, int used,
+ drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
+ unsigned int flags)
+{
+ return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
+ flags);
+}
+
+int
+drm_intel_gem_bo_context_exec(drm_intel_bo *bo, drm_intel_context *ctx,
+ int used, unsigned int flags)
+{
+ return do_exec2(bo, used, ctx, NULL, 0, 0, flags);
}
static int
if (ret != 0)
return -errno;
+ bo->offset64 = pin.offset;
bo->offset = pin.offset;
return 0;
}
return 0;
}
+drm_intel_bo *
+drm_intel_bo_gem_create_from_prime(drm_intel_bufmgr *bufmgr, int prime_fd, int size)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
+ int ret;
+ uint32_t handle;
+ drm_intel_bo_gem *bo_gem;
+ struct drm_i915_gem_get_tiling get_tiling;
+ drmMMListHead *list;
+
+ ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle);
+
+ /*
+ * See if the kernel has already returned this buffer to us. Just as
+ * for named buffers, we must not create two bo's pointing at the same
+ * kernel object
+ */
+ for (list = bufmgr_gem->named.next;
+ list != &bufmgr_gem->named;
+ list = list->next) {
+ bo_gem = DRMLISTENTRY(drm_intel_bo_gem, list, name_list);
+ if (bo_gem->gem_handle == handle) {
+ drm_intel_gem_bo_reference(&bo_gem->bo);
+ return &bo_gem->bo;
+ }
+ }
+
+ if (ret) {
+ fprintf(stderr,"ret is %d %d\n", ret, errno);
+ return NULL;
+ }
+
+ bo_gem = calloc(1, sizeof(*bo_gem));
+ if (!bo_gem)
+ return NULL;
+
+ /* Determine size of bo. The fd-to-handle ioctl really should
+ * return the size, but it doesn't. If we have kernel 3.12 or
+ * later, we can lseek on the prime fd to get the size. Older
+ * kernels will just fail, in which case we fall back to the
+ * provided (estimated or guess size). */
+ ret = lseek(prime_fd, 0, SEEK_END);
+ if (ret != -1)
+ bo_gem->bo.size = ret;
+ else
+ bo_gem->bo.size = size;
+
+ bo_gem->bo.handle = handle;
+ bo_gem->bo.bufmgr = bufmgr;
+
+ bo_gem->gem_handle = handle;
+
+ atomic_set(&bo_gem->refcount, 1);
+
+ bo_gem->name = "prime";
+ bo_gem->validate_index = -1;
+ bo_gem->reloc_tree_fences = 0;
+ bo_gem->used_as_reloc_target = false;
+ bo_gem->has_error = false;
+ bo_gem->reusable = false;
+
+ DRMINITLISTHEAD(&bo_gem->vma_list);
+ DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
+
+ VG_CLEAR(get_tiling);
+ get_tiling.handle = bo_gem->gem_handle;
+ ret = drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_GET_TILING,
+ &get_tiling);
+ if (ret != 0) {
+ drm_intel_gem_bo_unreference(&bo_gem->bo);
+ return NULL;
+ }
+ bo_gem->tiling_mode = get_tiling.tiling_mode;
+ bo_gem->swizzle_mode = get_tiling.swizzle_mode;
+ /* XXX stride is unknown */
+ drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
+
+ return &bo_gem->bo;
+}
+
+int
+drm_intel_bo_gem_export_to_prime(drm_intel_bo *bo, int *prime_fd)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ if (DRMLISTEMPTY(&bo_gem->name_list))
+ DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
+
+ if (drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->gem_handle,
+ DRM_CLOEXEC, prime_fd) != 0)
+ return -errno;
+
+ bo_gem->reusable = false;
+
+ return 0;
+}
+
static int
drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name)
{
bo_gem->global_name = flink.name;
bo_gem->reusable = false;
- DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
+ if (DRMLISTEMPTY(&bo_gem->name_list))
+ DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
}
*name = bo_gem->global_name;
}
}
+ VG_CLEAR(devid);
VG_CLEAR(gp);
gp.param = I915_PARAM_CHIPSET_ID;
gp.value = &devid;
}
/**
+ * Sets the AUB filename.
+ *
+ * This function has to be called before drm_intel_bufmgr_gem_set_aub_dump()
+ * for it to have any effect.
+ */
+void
+drm_intel_bufmgr_gem_set_aub_filename(drm_intel_bufmgr *bufmgr,
+ const char *filename)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+
+ free(bufmgr_gem->aub_filename);
+ if (filename)
+ bufmgr_gem->aub_filename = strdup(filename);
+}
+
+/**
* Sets up AUB dumping.
*
* This is a trace file format that can be used with the simulator.
int entry = 0x200003;
int i;
int gtt_size = 0x10000;
+ const char *filename;
if (!enable) {
if (bufmgr_gem->aub_file) {
fclose(bufmgr_gem->aub_file);
bufmgr_gem->aub_file = NULL;
}
+ return;
}
if (geteuid() != getuid())
return;
- bufmgr_gem->aub_file = fopen("intel.aub", "w+");
+ if (bufmgr_gem->aub_filename)
+ filename = bufmgr_gem->aub_filename;
+ else
+ filename = "intel.aub";
+ bufmgr_gem->aub_file = fopen(filename, "w+");
if (!bufmgr_gem->aub_file)
return;
aub_out(bufmgr_gem, 0); /* comment len */
/* Set up the GTT. The max we can handle is 256M */
- aub_out(bufmgr_gem, CMD_AUB_TRACE_HEADER_BLOCK | (5 - 2));
+ aub_out(bufmgr_gem, CMD_AUB_TRACE_HEADER_BLOCK | ((bufmgr_gem->gen >= 8 ? 6 : 5) - 2));
aub_out(bufmgr_gem, AUB_TRACE_MEMTYPE_NONLOCAL | 0 | AUB_TRACE_OP_DATA_WRITE);
aub_out(bufmgr_gem, 0); /* subtype */
aub_out(bufmgr_gem, 0); /* offset */
aub_out(bufmgr_gem, gtt_size); /* size */
+ if (bufmgr_gem->gen >= 8)
+ aub_out(bufmgr_gem, 0);
for (i = 0x000; i < gtt_size; i += 4, entry += 0x1000) {
aub_out(bufmgr_gem, entry);
}
}
+drm_intel_context *
+drm_intel_gem_context_create(drm_intel_bufmgr *bufmgr)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+ struct drm_i915_gem_context_create create;
+ drm_intel_context *context = NULL;
+ int ret;
+
+ context = calloc(1, sizeof(*context));
+ if (!context)
+ return NULL;
+
+ VG_CLEAR(create);
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE, &create);
+ if (ret != 0) {
+ DBG("DRM_IOCTL_I915_GEM_CONTEXT_CREATE failed: %s\n",
+ strerror(errno));
+ free(context);
+ return NULL;
+ }
+
+ context->ctx_id = create.ctx_id;
+ context->bufmgr = bufmgr;
+
+ return context;
+}
+
+void
+drm_intel_gem_context_destroy(drm_intel_context *ctx)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem;
+ struct drm_i915_gem_context_destroy destroy;
+ int ret;
+
+ if (ctx == NULL)
+ return;
+
+ VG_CLEAR(destroy);
+
+ bufmgr_gem = (drm_intel_bufmgr_gem *)ctx->bufmgr;
+ destroy.ctx_id = ctx->ctx_id;
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CONTEXT_DESTROY,
+ &destroy);
+ if (ret != 0)
+ fprintf(stderr, "DRM_IOCTL_I915_GEM_CONTEXT_DESTROY failed: %s\n",
+ strerror(errno));
+
+ free(ctx);
+}
+
+int
+drm_intel_get_reset_stats(drm_intel_context *ctx,
+ uint32_t *reset_count,
+ uint32_t *active,
+ uint32_t *pending)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem;
+ struct drm_i915_reset_stats stats;
+ int ret;
+
+ if (ctx == NULL)
+ return -EINVAL;
+
+ memset(&stats, 0, sizeof(stats));
+
+ bufmgr_gem = (drm_intel_bufmgr_gem *)ctx->bufmgr;
+ stats.ctx_id = ctx->ctx_id;
+ ret = drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GET_RESET_STATS,
+ &stats);
+ if (ret == 0) {
+ if (reset_count != NULL)
+ *reset_count = stats.reset_count;
+
+ if (active != NULL)
+ *active = stats.batch_active;
+
+ if (pending != NULL)
+ *pending = stats.batch_pending;
+ }
+
+ return ret;
+}
+
+int
+drm_intel_reg_read(drm_intel_bufmgr *bufmgr,
+ uint32_t offset,
+ uint64_t *result)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+ struct drm_i915_reg_read reg_read;
+ int ret;
+
+ VG_CLEAR(reg_read);
+ reg_read.offset = offset;
+
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_REG_READ, ®_read);
+
+ *result = reg_read.val;
+ return ret;
+}
+
+
+/**
+ * Annotate the given bo for use in aub dumping.
+ *
+ * \param annotations is an array of drm_intel_aub_annotation objects
+ * describing the type of data in various sections of the bo. Each
+ * element of the array specifies the type and subtype of a section of
+ * the bo, and the past-the-end offset of that section. The elements
+ * of \c annotations must be sorted so that ending_offset is
+ * increasing.
+ *
+ * \param count is the number of elements in the \c annotations array.
+ * If \c count is zero, then \c annotations will not be dereferenced.
+ *
+ * Annotations are copied into a private data structure, so caller may
+ * re-use the memory pointed to by \c annotations after the call
+ * returns.
+ *
+ * Annotations are stored for the lifetime of the bo; to reset to the
+ * default state (no annotations), call this function with a \c count
+ * of zero.
+ */
+void
+drm_intel_bufmgr_gem_set_aub_annotations(drm_intel_bo *bo,
+ drm_intel_aub_annotation *annotations,
+ unsigned count)
+{
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+ unsigned size = sizeof(*annotations) * count;
+ drm_intel_aub_annotation *new_annotations =
+ count > 0 ? realloc(bo_gem->aub_annotations, size) : NULL;
+ if (new_annotations == NULL) {
+ free(bo_gem->aub_annotations);
+ bo_gem->aub_annotations = NULL;
+ bo_gem->aub_annotation_count = 0;
+ return;
+ }
+ memcpy(new_annotations, annotations, size);
+ bo_gem->aub_annotations = new_annotations;
+ bo_gem->aub_annotation_count = count;
+}
+
/**
* Initializes the GEM buffer manager, which uses the kernel to allocate, map,
* and manage map buffer objections.
else if (IS_GEN6(bufmgr_gem->pci_device))
bufmgr_gem->gen = 6;
else if (IS_GEN7(bufmgr_gem->pci_device))
- bufmgr_gem->gen = 7;
- else
- assert(0);
+ bufmgr_gem->gen = 7;
+ else if (IS_GEN8(bufmgr_gem->pci_device))
+ bufmgr_gem->gen = 8;
+ else {
+ free(bufmgr_gem);
+ return NULL;
+ }
if (IS_GEN3(bufmgr_gem->pci_device) &&
bufmgr_gem->gtt_size > 256*1024*1024) {
bufmgr_gem->gtt_size -= 256*1024*1024;
}
+ VG_CLEAR(gp);
gp.value = &tmp;
gp.param = I915_PARAM_HAS_EXECBUF2;
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
bufmgr_gem->has_relaxed_fencing = ret == 0;
+ gp.param = I915_PARAM_HAS_WAIT_TIMEOUT;
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ bufmgr_gem->has_wait_timeout = ret == 0;
+
gp.param = I915_PARAM_HAS_LLC;
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
if (ret != 0) {
bufmgr_gem->has_llc = (IS_GEN6(bufmgr_gem->pci_device) |
IS_GEN7(bufmgr_gem->pci_device));
} else
- bufmgr_gem->has_llc = ret == 0;
+ bufmgr_gem->has_llc = *gp.value;
+
+ gp.param = I915_PARAM_HAS_VEBOX;
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ bufmgr_gem->has_vebox = (ret == 0) & (*gp.value > 0);
if (bufmgr_gem->gen < 4) {
gp.param = I915_PARAM_NUM_FENCES_AVAIL;