#include "string.h"
#include "i915_drm.h"
+#include "uthash.h"
#ifdef HAVE_VALGRIND
#include <valgrind.h>
drmMMListHead managers;
- drmMMListHead named;
+ drm_intel_bo_gem *name_table;
+ drm_intel_bo_gem *handle_table;
+
drmMMListHead vma_cache;
int vma_count, vma_open, vma_max;
unsigned int bo_reuse : 1;
unsigned int no_exec : 1;
unsigned int has_vebox : 1;
+ unsigned int has_exec_async : 1;
bool fenced_relocs;
struct {
* List contains both flink named and prime fd'd objects
*/
unsigned int global_name;
- drmMMListHead name_list;
+
+ UT_hash_handle handle_hh;
+ UT_hash_handle name_hh;
/**
* Index of the buffer within the validation list while preparing a
uint32_t swizzle_mode;
unsigned long stride;
+ unsigned long kflags;
+
time_t free_time;
/** Array passed to the DRM containing relocation information. */
void *mem_virtual;
/** GTT virtual address for the buffer, saved across map/unmap cycles */
void *gtt_virtual;
+ /** WC CPU address for the buffer, saved across map/unmap cycles */
+ void *wc_virtual;
/**
* Virtual address of the buffer allocated by user, used for userptr
* objects only.
* 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
+ * buffers are those that have been shared with other
* processes, so we don't know their state.
*/
bool idle;
bool is_userptr;
/**
- * Boolean of whether this buffer can be placed in the full 48-bit
- * address range on gen8+.
- *
- * By default, buffers will be keep in a 32-bit range, unless this
- * flag is explicitly set.
- */
- bool use_48b_address_range;
-
- /**
- * Whether this buffer is softpinned at offset specified by the user
- */
- bool is_softpin;
-
- /**
* Size in bytes of this buffer and its relocation descendents.
*
* Used to avoid costly tree walking in
*/
int reloc_tree_fences;
- /** Flags that we may need to do the SW_FINSIH ioctl on unmap. */
+ /** Flags that we may need to do the SW_FINISH ioctl on unmap. */
bool mapped_cpu_write;
};
if (bo_gem->relocs == NULL && bo_gem->softpin_target == NULL) {
DBG("%2d: %d %s(%s)\n", i, bo_gem->gem_handle,
- bo_gem->is_softpin ? "*" : "",
+ bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
bo_gem->name);
continue;
}
drm_intel_bo_gem *target_gem =
(drm_intel_bo_gem *) target_bo;
- DBG("%2d: %d %s(%s)@0x%016llx -> "
- "%d (%s)@0x%016llx + 0x%08x\n",
+ DBG("%2d: %d %s(%s)@0x%08x %08x -> "
+ "%d (%s)@0x%08x %08x + 0x%08x\n",
i,
bo_gem->gem_handle,
- bo_gem->is_softpin ? "*" : "",
+ bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
bo_gem->name,
- (unsigned long long) bo_gem->relocs[j].offset,
+ upper_32_bits(bo_gem->relocs[j].offset),
+ lower_32_bits(bo_gem->relocs[j].offset),
target_gem->gem_handle,
target_gem->name,
- (unsigned long long) target_bo->offset64,
+ upper_32_bits(target_bo->offset64),
+ lower_32_bits(target_bo->offset64),
bo_gem->relocs[j].delta);
}
drm_intel_bo_gem *target_gem =
(drm_intel_bo_gem *) target_bo;
DBG("%2d: %d %s(%s) -> "
- "%d *(%s)@0x%016lx\n",
+ "%d *(%s)@0x%08x %08x\n",
i,
bo_gem->gem_handle,
- bo_gem->is_softpin ? "*" : "",
+ bo_gem->kflags & EXEC_OBJECT_PINNED ? "*" : "",
bo_gem->name,
target_gem->gem_handle,
target_gem->name,
- target_bo->offset64);
+ upper_32_bits(target_bo->offset64),
+ lower_32_bits(target_bo->offset64));
}
}
}
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo;
int index;
- int flags = 0;
+ unsigned long flags;
+ flags = 0;
if (need_fence)
flags |= EXEC_OBJECT_NEEDS_FENCE;
- if (bo_gem->use_48b_address_range)
- flags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
- if (bo_gem->is_softpin)
- flags |= EXEC_OBJECT_PINNED;
if (bo_gem->validate_index != -1) {
bufmgr_gem->exec2_objects[bo_gem->validate_index].flags |= flags;
bufmgr_gem->exec2_objects[index].relocation_count = bo_gem->reloc_count;
bufmgr_gem->exec2_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs;
bufmgr_gem->exec2_objects[index].alignment = bo->align;
- bufmgr_gem->exec2_objects[index].offset = bo_gem->is_softpin ?
- bo->offset64 : 0;
- bufmgr_gem->exec_bos[index] = bo;
- bufmgr_gem->exec2_objects[index].flags = flags;
+ bufmgr_gem->exec2_objects[index].offset = bo->offset64;
+ bufmgr_gem->exec2_objects[index].flags = bo_gem->kflags | flags;
bufmgr_gem->exec2_objects[index].rsvd1 = 0;
bufmgr_gem->exec2_objects[index].rsvd2 = 0;
+ bufmgr_gem->exec_bos[index] = bo;
bufmgr_gem->exec_count++;
}
} else {
return false;
}
- return (ret == 0 && busy.busy);
}
static int
}
}
}
- pthread_mutex_unlock(&bufmgr_gem->lock);
if (!alloc_from_cache) {
struct drm_i915_gem_create create;
bo_gem = calloc(1, sizeof(*bo_gem));
if (!bo_gem)
- return NULL;
+ goto err;
+
+ /* drm_intel_gem_bo_free calls DRMLISTDEL() for an uninitialized
+ list (vma_list), so better set the list head here */
+ DRMINITLISTHEAD(&bo_gem->vma_list);
bo_gem->bo.size = bo_size;
ret = drmIoctl(bufmgr_gem->fd,
DRM_IOCTL_I915_GEM_CREATE,
&create);
- bo_gem->gem_handle = create.handle;
- bo_gem->bo.handle = bo_gem->gem_handle;
if (ret != 0) {
free(bo_gem);
- return NULL;
+ goto err;
}
+
+ bo_gem->gem_handle = create.handle;
+ HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+ gem_handle, sizeof(bo_gem->gem_handle),
+ bo_gem);
+
+ bo_gem->bo.handle = bo_gem->gem_handle;
bo_gem->bo.bufmgr = bufmgr;
bo_gem->bo.align = alignment;
bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
bo_gem->stride = 0;
- /* drm_intel_gem_bo_free calls DRMLISTDEL() for an uninitialized
- list (vma_list), so better set the list head here */
- DRMINITLISTHEAD(&bo_gem->name_list);
- DRMINITLISTHEAD(&bo_gem->vma_list);
if (drm_intel_gem_bo_set_tiling_internal(&bo_gem->bo,
tiling_mode,
- stride)) {
- drm_intel_gem_bo_free(&bo_gem->bo);
- return NULL;
- }
+ stride))
+ goto err_free;
}
bo_gem->name = name;
bo_gem->used_as_reloc_target = false;
bo_gem->has_error = false;
bo_gem->reusable = true;
- bo_gem->use_48b_address_range = false;
drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, alignment);
+ pthread_mutex_unlock(&bufmgr_gem->lock);
DBG("bo_create: buf %d (%s) %ldb\n",
bo_gem->gem_handle, bo_gem->name, size);
return &bo_gem->bo;
+
+err_free:
+ drm_intel_gem_bo_free(&bo_gem->bo);
+err:
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return NULL;
}
static drm_intel_bo *
if (!bo_gem)
return NULL;
+ atomic_set(&bo_gem->refcount, 1);
+ DRMINITLISTHEAD(&bo_gem->vma_list);
+
bo_gem->bo.size = size;
memclear(userptr);
return NULL;
}
+ pthread_mutex_lock(&bufmgr_gem->lock);
+
bo_gem->gem_handle = userptr.handle;
bo_gem->bo.handle = bo_gem->gem_handle;
bo_gem->bo.bufmgr = bufmgr;
bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
bo_gem->stride = 0;
- DRMINITLISTHEAD(&bo_gem->name_list);
- DRMINITLISTHEAD(&bo_gem->vma_list);
+ HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+ gem_handle, sizeof(bo_gem->gem_handle),
+ bo_gem);
bo_gem->name = name;
- atomic_set(&bo_gem->refcount, 1);
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;
- bo_gem->use_48b_address_range = false;
drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem, 0);
+ pthread_mutex_unlock(&bufmgr_gem->lock);
DBG("bo_create_userptr: "
"ptr %p buf %d (%s) size %ldb, stride 0x%x, tile mode %d\n",
int ret;
struct drm_gem_open open_arg;
struct drm_i915_gem_get_tiling get_tiling;
- drmMMListHead *list;
/* At the moment most applications only have a few named bo.
* For instance, in a DRI client only the render buffers passed
* provides a sufficiently fast match.
*/
pthread_mutex_lock(&bufmgr_gem->lock);
- 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->global_name == handle) {
- drm_intel_gem_bo_reference(&bo_gem->bo);
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return &bo_gem->bo;
- }
+ HASH_FIND(name_hh, bufmgr_gem->name_table,
+ &handle, sizeof(handle), bo_gem);
+ if (bo_gem) {
+ drm_intel_gem_bo_reference(&bo_gem->bo);
+ goto out;
}
memclear(open_arg);
if (ret != 0) {
DBG("Couldn't reference %s handle 0x%08x: %s\n",
name, handle, strerror(errno));
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return NULL;
+ bo_gem = NULL;
+ goto out;
}
/* 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);
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return &bo_gem->bo;
- }
+ HASH_FIND(handle_hh, bufmgr_gem->handle_table,
+ &open_arg.handle, sizeof(open_arg.handle), bo_gem);
+ if (bo_gem) {
+ drm_intel_gem_bo_reference(&bo_gem->bo);
+ goto out;
}
bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem) {
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return NULL;
- }
+ if (!bo_gem)
+ goto out;
+
+ atomic_set(&bo_gem->refcount, 1);
+ DRMINITLISTHEAD(&bo_gem->vma_list);
bo_gem->bo.size = open_arg.size;
bo_gem->bo.offset = 0;
bo_gem->bo.virtual = NULL;
bo_gem->bo.bufmgr = bufmgr;
bo_gem->name = name;
- atomic_set(&bo_gem->refcount, 1);
bo_gem->validate_index = -1;
bo_gem->gem_handle = open_arg.handle;
bo_gem->bo.handle = open_arg.handle;
bo_gem->global_name = handle;
bo_gem->reusable = false;
- bo_gem->use_48b_address_range = false;
+
+ HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+ gem_handle, sizeof(bo_gem->gem_handle), bo_gem);
+ HASH_ADD(name_hh, bufmgr_gem->name_table,
+ global_name, sizeof(bo_gem->global_name), bo_gem);
memclear(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);
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return NULL;
- }
+ if (ret != 0)
+ goto err_unref;
+
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, 0);
-
- DRMINITLISTHEAD(&bo_gem->vma_list);
- DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
- pthread_mutex_unlock(&bufmgr_gem->lock);
DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
+out:
+ pthread_mutex_unlock(&bufmgr_gem->lock);
return &bo_gem->bo;
+
+err_unref:
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return NULL;
}
static void
drm_munmap(bo_gem->mem_virtual, bo_gem->bo.size);
bufmgr_gem->vma_count--;
}
+ if (bo_gem->wc_virtual) {
+ VG(VALGRIND_FREELIKE_BLOCK(bo_gem->wc_virtual, 0));
+ drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size);
+ bufmgr_gem->vma_count--;
+ }
if (bo_gem->gtt_virtual) {
drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
bufmgr_gem->vma_count--;
}
+ if (bo_gem->global_name)
+ HASH_DELETE(name_hh, bufmgr_gem->name_table, bo_gem);
+ HASH_DELETE(handle_hh, bufmgr_gem->handle_table, bo_gem);
+
/* Close this object */
memclear(close);
close.handle = bo_gem->gem_handle;
if (bo_gem->mem_virtual)
VALGRIND_MAKE_MEM_NOACCESS(bo_gem->mem_virtual, bo->size);
+ if (bo_gem->wc_virtual)
+ VALGRIND_MAKE_MEM_NOACCESS(bo_gem->wc_virtual, bo->size);
+
if (bo_gem->gtt_virtual)
VALGRIND_MAKE_MEM_NOACCESS(bo_gem->gtt_virtual, bo->size);
#endif
bo_gem->mem_virtual = NULL;
bufmgr_gem->vma_count--;
}
+ if (bo_gem->wc_virtual) {
+ drm_munmap(bo_gem->wc_virtual, bo_gem->bo.size);
+ bo_gem->wc_virtual = NULL;
+ bufmgr_gem->vma_count--;
+ }
if (bo_gem->gtt_virtual) {
drm_munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
bo_gem->gtt_virtual = NULL;
DRMLISTADDTAIL(&bo_gem->vma_list, &bufmgr_gem->vma_cache);
if (bo_gem->mem_virtual)
bufmgr_gem->vma_count++;
+ if (bo_gem->wc_virtual)
+ bufmgr_gem->vma_count++;
if (bo_gem->gtt_virtual)
bufmgr_gem->vma_count++;
drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
DRMLISTDEL(&bo_gem->vma_list);
if (bo_gem->mem_virtual)
bufmgr_gem->vma_count--;
+ if (bo_gem->wc_virtual)
+ bufmgr_gem->vma_count--;
if (bo_gem->gtt_virtual)
bufmgr_gem->vma_count--;
drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
for (i = 0; i < bo_gem->softpin_target_count; i++)
drm_intel_gem_bo_unreference_locked_timed(bo_gem->softpin_target[i],
time);
+ bo_gem->kflags = 0;
bo_gem->reloc_count = 0;
bo_gem->used_as_reloc_target = false;
bo_gem->softpin_target_count = 0;
drm_intel_gem_bo_mark_mmaps_incoherent(bo);
}
- DRMLISTDEL(&bo_gem->name_list);
-
bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
/* Put the buffer into our internal cache for reuse if we can. */
if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL &&
}
/* We need to unmap after every innovation as we cannot track
- * an open vma for every bo as that will exhaasut the system
+ * an open vma for every bo as that will exhaust the system
* limits and cause later failures.
*/
if (--bo_gem->map_count == 0) {
drm_intel_gem_bo_use_48b_address_range(drm_intel_bo *bo, uint32_t enable)
{
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
- bo_gem->use_48b_address_range = enable;
+
+ if (enable)
+ bo_gem->kflags |= EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
+ else
+ bo_gem->kflags &= ~EXEC_OBJECT_SUPPORTS_48B_ADDRESS;
}
static int
return -ENOMEM;
}
- if (!target_bo_gem->is_softpin)
+ if (!(target_bo_gem->kflags & EXEC_OBJECT_PINNED))
return -EINVAL;
if (target_bo_gem == bo_gem)
return -EINVAL;
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *)target_bo;
- if (target_bo_gem->is_softpin)
+ if (target_bo_gem->kflags & EXEC_OBJECT_PINNED)
return drm_intel_gem_bo_add_softpin_target(bo, target_bo);
else
return do_bo_emit_reloc(bo, offset, target_bo, target_offset,
/* If we're seeing softpinned object here it means that the kernel
* has relocated our object... Indicating a programming error
*/
- assert(!bo_gem->is_softpin);
- DBG("BO %d (%s) migrated: 0x%016llx -> 0x%016llx\n",
+ assert(!(bo_gem->kflags & EXEC_OBJECT_PINNED));
+ DBG("BO %d (%s) migrated: 0x%08x %08x -> 0x%08x %08x\n",
bo_gem->gem_handle, bo_gem->name,
- (unsigned long long) bo->offset64,
- (unsigned long long) bufmgr_gem->exec2_objects[i].offset);
+ upper_32_bits(bo->offset64),
+ lower_32_bits(bo->offset64),
+ upper_32_bits(bufmgr_gem->exec2_objects[i].offset),
+ lower_32_bits(bufmgr_gem->exec2_objects[i].offset));
bo->offset64 = bufmgr_gem->exec2_objects[i].offset;
bo->offset = bufmgr_gem->exec2_objects[i].offset;
}
static int
do_exec2(drm_intel_bo *bo, int used, drm_intel_context *ctx,
drm_clip_rect_t *cliprects, int num_cliprects, int DR4,
+ int in_fence, int *out_fence,
unsigned int flags)
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr;
else
i915_execbuffer2_set_context_id(execbuf, ctx->ctx_id);
execbuf.rsvd2 = 0;
+ if (in_fence != -1) {
+ execbuf.rsvd2 = in_fence;
+ execbuf.flags |= I915_EXEC_FENCE_IN;
+ }
+ if (out_fence != NULL) {
+ *out_fence = -1;
+ execbuf.flags |= I915_EXEC_FENCE_OUT;
+ }
if (bufmgr_gem->no_exec)
goto skip_execution;
ret = drmIoctl(bufmgr_gem->fd,
- DRM_IOCTL_I915_GEM_EXECBUFFER2,
+ DRM_IOCTL_I915_GEM_EXECBUFFER2_WR,
&execbuf);
if (ret != 0) {
ret = -errno;
}
drm_intel_update_buffer_offsets2(bufmgr_gem);
+ if (ret == 0 && out_fence != NULL)
+ *out_fence = execbuf.rsvd2 >> 32;
+
skip_execution:
if (bufmgr_gem->bufmgr.debug)
drm_intel_gem_dump_validation_list(bufmgr_gem);
int DR4)
{
return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
- I915_EXEC_RENDER);
+ -1, NULL, I915_EXEC_RENDER);
}
static int
unsigned int flags)
{
return do_exec2(bo, used, NULL, cliprects, num_cliprects, DR4,
- flags);
+ -1, NULL, 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);
+ return do_exec2(bo, used, ctx, NULL, 0, 0, -1, NULL, flags);
+}
+
+int
+drm_intel_gem_bo_fence_exec(drm_intel_bo *bo,
+ drm_intel_context *ctx,
+ int used,
+ int in_fence,
+ int *out_fence,
+ unsigned int flags)
+{
+ return do_exec2(bo, used, ctx, NULL, 0, 0, in_fence, out_fence, flags);
}
static int
{
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
- bo_gem->is_softpin = true;
bo->offset64 = offset;
bo->offset = offset;
+ bo_gem->kflags |= EXEC_OBJECT_PINNED;
+
return 0;
}
uint32_t handle;
drm_intel_bo_gem *bo_gem;
struct drm_i915_gem_get_tiling get_tiling;
- drmMMListHead *list;
pthread_mutex_lock(&bufmgr_gem->lock);
ret = drmPrimeFDToHandle(bufmgr_gem->fd, prime_fd, &handle);
* 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);
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return &bo_gem->bo;
- }
+ HASH_FIND(handle_hh, bufmgr_gem->handle_table,
+ &handle, sizeof(handle), bo_gem);
+ if (bo_gem) {
+ drm_intel_gem_bo_reference(&bo_gem->bo);
+ goto out;
}
bo_gem = calloc(1, sizeof(*bo_gem));
- if (!bo_gem) {
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return NULL;
- }
+ if (!bo_gem)
+ goto out;
+
+ atomic_set(&bo_gem->refcount, 1);
+ DRMINITLISTHEAD(&bo_gem->vma_list);
+
/* 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
bo_gem->bo.bufmgr = bufmgr;
bo_gem->gem_handle = handle;
-
- atomic_set(&bo_gem->refcount, 1);
+ HASH_ADD(handle_hh, bufmgr_gem->handle_table,
+ gem_handle, sizeof(bo_gem->gem_handle), bo_gem);
bo_gem->name = "prime";
bo_gem->validate_index = -1;
bo_gem->used_as_reloc_target = false;
bo_gem->has_error = false;
bo_gem->reusable = false;
- bo_gem->use_48b_address_range = false;
-
- DRMINITLISTHEAD(&bo_gem->vma_list);
- DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
- pthread_mutex_unlock(&bufmgr_gem->lock);
memclear(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) {
- DBG("create_from_prime: failed to get tiling: %s\n", strerror(errno));
- drm_intel_gem_bo_unreference(&bo_gem->bo);
- return NULL;
- }
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_GET_TILING,
+ &get_tiling))
+ goto err;
+
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, 0);
+out:
+ pthread_mutex_unlock(&bufmgr_gem->lock);
return &bo_gem->bo;
+
+err:
+ drm_intel_gem_bo_free(&bo_gem->bo);
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return NULL;
}
int
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
- pthread_mutex_lock(&bufmgr_gem->lock);
- if (DRMLISTEMPTY(&bo_gem->name_list))
- DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
- pthread_mutex_unlock(&bufmgr_gem->lock);
-
if (drmPrimeHandleToFD(bufmgr_gem->fd, bo_gem->gem_handle,
DRM_CLOEXEC, prime_fd) != 0)
return -errno;
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
- int ret;
if (!bo_gem->global_name) {
struct drm_gem_flink flink;
memclear(flink);
flink.handle = bo_gem->gem_handle;
+ if (drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink))
+ return -errno;
pthread_mutex_lock(&bufmgr_gem->lock);
+ if (!bo_gem->global_name) {
+ bo_gem->global_name = flink.name;
+ bo_gem->reusable = false;
- ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink);
- if (ret != 0) {
- pthread_mutex_unlock(&bufmgr_gem->lock);
- return -errno;
+ HASH_ADD(name_hh, bufmgr_gem->name_table,
+ global_name, sizeof(bo_gem->global_name),
+ bo_gem);
}
-
- bo_gem->global_name = flink.name;
- bo_gem->reusable = false;
-
- if (DRMLISTEMPTY(&bo_gem->name_list))
- DRMLISTADDTAIL(&bo_gem->name_list, &bufmgr_gem->named);
pthread_mutex_unlock(&bufmgr_gem->lock);
}
}
/**
+ * Disables implicit synchronisation before executing the bo
+ *
+ * This will cause rendering corruption unless you correctly manage explicit
+ * fences for all rendering involving this buffer - including use by others.
+ * Disabling the implicit serialisation is only required if that serialisation
+ * is too coarse (for example, you have split the buffer into many
+ * non-overlapping regions and are sharing the whole buffer between concurrent
+ * independent command streams).
+ *
+ * Note the kernel must advertise support via I915_PARAM_HAS_EXEC_ASYNC,
+ * which can be checked using drm_intel_bufmgr_can_disable_implicit_sync,
+ * or subsequent execbufs involving the bo will generate EINVAL.
+ */
+void
+drm_intel_gem_bo_disable_implicit_sync(drm_intel_bo *bo)
+{
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ bo_gem->kflags |= EXEC_OBJECT_ASYNC;
+}
+
+/**
+ * Enables implicit synchronisation before executing the bo
+ *
+ * This is the default behaviour of the kernel, to wait upon prior writes
+ * completing on the object before rendering with it, or to wait for prior
+ * reads to complete before writing into the object.
+ * drm_intel_gem_bo_disable_implicit_sync() can stop this behaviour, telling
+ * the kernel never to insert a stall before using the object. Then this
+ * function can be used to restore the implicit sync before subsequent
+ * rendering.
+ */
+void
+drm_intel_gem_bo_enable_implicit_sync(drm_intel_bo *bo)
+{
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ bo_gem->kflags &= ~EXEC_OBJECT_ASYNC;
+}
+
+/**
+ * Query whether the kernel supports disabling of its implicit synchronisation
+ * before execbuf. See drm_intel_gem_bo_disable_implicit_sync()
+ */
+int
+drm_intel_bufmgr_gem_can_disable_implicit_sync(drm_intel_bufmgr *bufmgr)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
+
+ return bufmgr_gem->has_exec_async;
+}
+
+/**
* Enable use of fenced reloc type.
*
* New code should enable this to avoid unnecessary fence register
drm_intel_gem_bo_purge_vma_cache(bufmgr_gem);
}
+static int
+parse_devid_override(const char *devid_override)
+{
+ static const struct {
+ const char *name;
+ int pci_id;
+ } name_map[] = {
+ { "brw", PCI_CHIP_I965_GM },
+ { "g4x", PCI_CHIP_GM45_GM },
+ { "ilk", PCI_CHIP_ILD_G },
+ { "snb", PCI_CHIP_SANDYBRIDGE_M_GT2_PLUS },
+ { "ivb", PCI_CHIP_IVYBRIDGE_S_GT2 },
+ { "hsw", PCI_CHIP_HASWELL_CRW_E_GT3 },
+ { "byt", PCI_CHIP_VALLEYVIEW_3 },
+ { "bdw", 0x1620 | BDW_ULX },
+ { "skl", PCI_CHIP_SKYLAKE_DT_GT2 },
+ { "kbl", PCI_CHIP_KABYLAKE_DT_GT2 },
+ };
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(name_map); i++) {
+ if (!strcmp(name_map[i].name, devid_override))
+ return name_map[i].pci_id;
+ }
+
+ return strtod(devid_override, NULL);
+}
+
/**
* Get the PCI ID for the device. This can be overridden by setting the
* INTEL_DEVID_OVERRIDE environment variable to the desired ID.
devid_override = getenv("INTEL_DEVID_OVERRIDE");
if (devid_override) {
bufmgr_gem->no_exec = true;
- return strtod(devid_override, NULL);
+ return parse_devid_override(devid_override);
}
}
return context;
}
+int
+drm_intel_gem_context_get_id(drm_intel_context *ctx, uint32_t *ctx_id)
+{
+ if (ctx == NULL)
+ return -EINVAL;
+
+ *ctx_id = ctx->ctx_id;
+
+ return 0;
+}
+
void
drm_intel_gem_context_destroy(drm_intel_context *ctx)
{
return 0;
}
+int
+drm_intel_get_pooled_eu(int fd)
+{
+ drm_i915_getparam_t gp;
+ int ret = -1;
+
+ memclear(gp);
+ gp.param = I915_PARAM_HAS_POOLED_EU;
+ gp.value = &ret;
+ if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
+ return -errno;
+
+ return ret;
+}
+
+int
+drm_intel_get_min_eu_in_pool(int fd)
+{
+ drm_i915_getparam_t gp;
+ int ret = -1;
+
+ memclear(gp);
+ gp.param = I915_PARAM_MIN_EU_IN_POOL;
+ gp.value = &ret;
+ if (drmIoctl(fd, DRM_IOCTL_I915_GETPARAM, &gp))
+ return -errno;
+
+ return ret;
+}
+
/**
* Annotate the given bo for use in aub dumping.
*
}
}
+void *drm_intel_gem_bo_map__gtt(drm_intel_bo *bo)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ if (bo_gem->gtt_virtual)
+ return bo_gem->gtt_virtual;
+
+ if (bo_gem->is_userptr)
+ return NULL;
+
+ pthread_mutex_lock(&bufmgr_gem->lock);
+ if (bo_gem->gtt_virtual == NULL) {
+ struct drm_i915_gem_mmap_gtt mmap_arg;
+ void *ptr;
+
+ DBG("bo_map_gtt: mmap %d (%s), map_count=%d\n",
+ bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+ if (bo_gem->map_count++ == 0)
+ drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+ memclear(mmap_arg);
+ mmap_arg.handle = bo_gem->gem_handle;
+
+ /* Get the fake offset back... */
+ ptr = MAP_FAILED;
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_MMAP_GTT,
+ &mmap_arg) == 0) {
+ /* and mmap it */
+ ptr = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, bufmgr_gem->fd,
+ mmap_arg.offset);
+ }
+ if (ptr == MAP_FAILED) {
+ if (--bo_gem->map_count == 0)
+ drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+ ptr = NULL;
+ }
+
+ bo_gem->gtt_virtual = ptr;
+ }
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+
+ return bo_gem->gtt_virtual;
+}
+
+void *drm_intel_gem_bo_map__cpu(drm_intel_bo *bo)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ if (bo_gem->mem_virtual)
+ return bo_gem->mem_virtual;
+
+ if (bo_gem->is_userptr) {
+ /* Return the same user ptr */
+ return bo_gem->user_virtual;
+ }
+
+ pthread_mutex_lock(&bufmgr_gem->lock);
+ if (!bo_gem->mem_virtual) {
+ struct drm_i915_gem_mmap mmap_arg;
+
+ if (bo_gem->map_count++ == 0)
+ drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+ DBG("bo_map: %d (%s), map_count=%d\n",
+ bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+ memclear(mmap_arg);
+ mmap_arg.handle = bo_gem->gem_handle;
+ mmap_arg.size = bo->size;
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_MMAP,
+ &mmap_arg)) {
+ DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+ __FILE__, __LINE__, bo_gem->gem_handle,
+ bo_gem->name, strerror(errno));
+ if (--bo_gem->map_count == 0)
+ drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+ } else {
+ VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1));
+ bo_gem->mem_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr;
+ }
+ }
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+
+ return bo_gem->mem_virtual;
+}
+
+void *drm_intel_gem_bo_map__wc(drm_intel_bo *bo)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr;
+ drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+ if (bo_gem->wc_virtual)
+ return bo_gem->wc_virtual;
+
+ if (bo_gem->is_userptr)
+ return NULL;
+
+ pthread_mutex_lock(&bufmgr_gem->lock);
+ if (!bo_gem->wc_virtual) {
+ struct drm_i915_gem_mmap mmap_arg;
+
+ if (bo_gem->map_count++ == 0)
+ drm_intel_gem_bo_open_vma(bufmgr_gem, bo_gem);
+
+ DBG("bo_map: %d (%s), map_count=%d\n",
+ bo_gem->gem_handle, bo_gem->name, bo_gem->map_count);
+
+ memclear(mmap_arg);
+ mmap_arg.handle = bo_gem->gem_handle;
+ mmap_arg.size = bo->size;
+ mmap_arg.flags = I915_MMAP_WC;
+ if (drmIoctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_MMAP,
+ &mmap_arg)) {
+ DBG("%s:%d: Error mapping buffer %d (%s): %s .\n",
+ __FILE__, __LINE__, bo_gem->gem_handle,
+ bo_gem->name, strerror(errno));
+ if (--bo_gem->map_count == 0)
+ drm_intel_gem_bo_close_vma(bufmgr_gem, bo_gem);
+ } else {
+ VG(VALGRIND_MALLOCLIKE_BLOCK(mmap_arg.addr_ptr, mmap_arg.size, 0, 1));
+ bo_gem->wc_virtual = (void *)(uintptr_t) mmap_arg.addr_ptr;
+ }
+ }
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+
+ return bo_gem->wc_virtual;
+}
+
/**
* Initializes the GEM buffer manager, which uses the kernel to allocate, map,
* and manage map buffer objections.
bufmgr_gem->gen = 8;
else if (IS_GEN9(bufmgr_gem->pci_device))
bufmgr_gem->gen = 9;
+ else if (IS_GEN10(bufmgr_gem->pci_device))
+ bufmgr_gem->gen = 10;
else {
free(bufmgr_gem);
bufmgr_gem = NULL;
bufmgr_gem->gtt_size > 256*1024*1024) {
/* The unmappable part of gtt on gen 3 (i.e. above 256MB) can't
* be used for tiled blits. To simplify the accounting, just
- * substract the unmappable part (fixed to 256MB on all known
+ * subtract the unmappable part (fixed to 256MB on all known
* gen3 devices) if the kernel advertises it. */
bufmgr_gem->gtt_size -= 256*1024*1024;
}
ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
bufmgr_gem->has_relaxed_fencing = ret == 0;
+ gp.param = I915_PARAM_HAS_EXEC_ASYNC;
+ ret = drmIoctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp);
+ bufmgr_gem->has_exec_async = ret == 0;
+
bufmgr_gem->bufmgr.bo_alloc_userptr = check_bo_alloc_userptr;
gp.param = I915_PARAM_HAS_WAIT_TIMEOUT;
drm_intel_gem_get_pipe_from_crtc_id;
bufmgr_gem->bufmgr.bo_references = drm_intel_gem_bo_references;
- DRMINITLISTHEAD(&bufmgr_gem->named);
init_cache_buckets(bufmgr_gem);
DRMINITLISTHEAD(&bufmgr_gem->vma_cache);