summaryrefslogtreecommitdiff
path: root/intel
diff options
context:
space:
mode:
Diffstat (limited to 'intel')
-rw-r--r--intel/intel_bufmgr_gem.c211
1 files changed, 151 insertions, 60 deletions
diff --git a/intel/intel_bufmgr_gem.c b/intel/intel_bufmgr_gem.c
index 9db7bfeb..571ab5c8 100644
--- a/intel/intel_bufmgr_gem.c
+++ b/intel/intel_bufmgr_gem.c
@@ -154,6 +154,11 @@ struct _drm_intel_bo_gem {
char used_as_reloc_target;
/**
+ * Boolean of whether we have encountered an error whilst building the relocation tree.
+ */
+ char has_error;
+
+ /**
* Boolean of whether this buffer can be re-used
*/
char reusable;
@@ -187,7 +192,6 @@ static int
drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
uint32_t stride);
-static void drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo);
static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo,
time_t time);
@@ -305,7 +309,7 @@ drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem)
}
}
-static void
+static inline void
drm_intel_gem_bo_reference(drm_intel_bo *bo)
{
drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
@@ -357,13 +361,33 @@ drm_intel_add_validate_buffer(drm_intel_bo *bo)
bufmgr_gem->exec_objects[index].alignment = 0;
bufmgr_gem->exec_objects[index].offset = 0;
bufmgr_gem->exec_bos[index] = bo;
- drm_intel_gem_bo_reference(bo);
bufmgr_gem->exec_count++;
}
#define RELOC_BUF_SIZE(x) ((I915_RELOC_HEADER + x * I915_RELOC0_STRIDE) * \
sizeof(uint32_t))
+static void
+drm_intel_bo_gem_set_in_aperture_size(drm_intel_bufmgr_gem *bufmgr_gem,
+ drm_intel_bo_gem *bo_gem)
+{
+ int size;
+
+ assert(!bo_gem->used_as_reloc_target);
+
+ /* The older chipsets are far-less flexible in terms of tiling,
+ * and require tiled buffer to be size aligned in the aperture.
+ * This means that in the worst possible case we will need a hole
+ * twice as large as the object in order for it to fit into the
+ * aperture. Optimal packing is for wimps.
+ */
+ size = bo_gem->bo.size;
+ if (!IS_I965G(bufmgr_gem) && bo_gem->tiling_mode != I915_TILING_NONE)
+ size *= 2;
+
+ bo_gem->reloc_tree_size = size;
+}
+
static int
drm_intel_setup_reloc_list(drm_intel_bo *bo)
{
@@ -377,6 +401,17 @@ drm_intel_setup_reloc_list(drm_intel_bo *bo)
bo_gem->relocs = malloc(max_relocs *
sizeof(struct drm_i915_gem_relocation_entry));
bo_gem->reloc_target_bo = malloc(max_relocs * sizeof(drm_intel_bo *));
+ if (bo_gem->relocs == NULL || bo_gem->reloc_target_bo == NULL) {
+ bo_gem->has_error = 1;
+
+ free (bo_gem->relocs);
+ bo_gem->relocs = NULL;
+
+ free (bo_gem->reloc_target_bo);
+ bo_gem->reloc_target_bo = NULL;
+
+ return 1;
+ }
return 0;
}
@@ -392,7 +427,9 @@ drm_intel_gem_bo_busy(drm_intel_bo *bo)
memset(&busy, 0, sizeof(busy));
busy.handle = bo_gem->gem_handle;
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
+ do {
+ ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy);
+ } while (ret == -1 && errno == EINTR);
return (ret == 0 && busy.busy);
}
@@ -524,7 +561,11 @@ retry:
memset(&create, 0, sizeof(create));
create.size = bo_size;
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_CREATE, &create);
+ do {
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_CREATE,
+ &create);
+ } while (ret == -1 && errno == EINTR);
bo_gem->gem_handle = create.handle;
bo_gem->bo.handle = bo_gem->gem_handle;
if (ret != 0) {
@@ -537,13 +578,15 @@ retry:
bo_gem->name = name;
atomic_set(&bo_gem->refcount, 1);
bo_gem->validate_index = -1;
- bo_gem->reloc_tree_size = bo_gem->bo.size;
bo_gem->reloc_tree_fences = 0;
bo_gem->used_as_reloc_target = 0;
+ bo_gem->has_error = 0;
bo_gem->tiling_mode = I915_TILING_NONE;
bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE;
bo_gem->reusable = 1;
+ drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
+
DBG("bo_create: buf %d (%s) %ldb\n",
bo_gem->gem_handle, bo_gem->name, size);
@@ -629,7 +672,11 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
memset(&open_arg, 0, sizeof(open_arg));
open_arg.name = handle;
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
+ do {
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_GEM_OPEN,
+ &open_arg);
+ } while (ret == -1 && errno == EINTR);
if (ret != 0) {
fprintf(stderr, "Couldn't reference %s handle 0x%08x: %s\n",
name, handle, strerror(errno));
@@ -660,6 +707,7 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr,
bo_gem->reloc_tree_fences = 0;
else
bo_gem->reloc_tree_fences = 1;
+ drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name);
@@ -679,9 +727,6 @@ drm_intel_gem_bo_free(drm_intel_bo *bo)
if (bo_gem->gtt_virtual)
munmap(bo_gem->gtt_virtual, bo_gem->bo.size);
- free(bo_gem->reloc_target_bo);
- free(bo_gem->relocs);
-
/* Close this object */
memset(&close, 0, sizeof(close));
close.handle = bo_gem->gem_handle;
@@ -734,44 +779,42 @@ drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time)
reloc_target_bo[i],
time);
}
+ bo_gem->reloc_count = 0;
+ bo_gem->used_as_reloc_target = 0;
DBG("bo_unreference final: %d (%s)\n",
bo_gem->gem_handle, bo_gem->name);
+ /* release memory associated with this object */
+ if (bo_gem->reloc_target_bo) {
+ free(bo_gem->reloc_target_bo);
+ bo_gem->reloc_target_bo = NULL;
+ }
+ if (bo_gem->relocs) {
+ free(bo_gem->relocs);
+ bo_gem->relocs = NULL;
+ }
+
bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size);
/* Put the buffer into our internal cache for reuse if we can. */
tiling_mode = I915_TILING_NONE;
if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL &&
- drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0) {
+ drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0 &&
+ drm_intel_gem_bo_madvise_internal(bufmgr_gem, bo_gem,
+ I915_MADV_DONTNEED)) {
bo_gem->free_time = time;
bo_gem->name = NULL;
bo_gem->validate_index = -1;
- bo_gem->reloc_count = 0;
DRMLISTADDTAIL(&bo_gem->head, &bucket->head);
- drm_intel_gem_bo_madvise_internal(bufmgr_gem, bo_gem,
- I915_MADV_DONTNEED);
drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time);
} else {
drm_intel_gem_bo_free(bo);
}
}
-static void drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo)
-{
- drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
-
- assert(atomic_read(&bo_gem->refcount) > 0);
- if (atomic_dec_and_test(&bo_gem->refcount)) {
- struct timespec time;
-
- clock_gettime(CLOCK_MONOTONIC, &time);
- drm_intel_gem_bo_unreference_final(bo, time.tv_sec);
- }
-}
-
static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo,
time_t time)
{
@@ -821,8 +864,13 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable)
mmap_arg.handle = bo_gem->gem_handle;
mmap_arg.offset = 0;
mmap_arg.size = bo->size;
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
+ do {
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_MMAP,
+ &mmap_arg);
+ } while (ret == -1 && errno == EINTR);
if (ret != 0) {
+ ret = -errno;
fprintf(stderr,
"%s:%d: Error mapping buffer %d (%s): %s .\n",
__FILE__, __LINE__, bo_gem->gem_handle,
@@ -843,10 +891,12 @@ static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable)
else
set_domain.write_domain = 0;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN,
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
&set_domain);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
+ ret = -errno;
fprintf(stderr, "%s:%d: Error setting to CPU domain %d: %s\n",
__FILE__, __LINE__, bo_gem->gem_handle,
strerror(errno));
@@ -879,9 +929,13 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
mmap_arg.handle = bo_gem->gem_handle;
/* Get the fake offset back... */
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MMAP_GTT,
- &mmap_arg);
+ do {
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_MMAP_GTT,
+ &mmap_arg);
+ } while (ret == -1 && errno == EINTR);
if (ret != 0) {
+ ret = -errno;
fprintf(stderr,
"%s:%d: Error preparing buffer map %d (%s): %s .\n",
__FILE__, __LINE__,
@@ -896,13 +950,14 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
MAP_SHARED, bufmgr_gem->fd,
mmap_arg.offset);
if (bo_gem->gtt_virtual == MAP_FAILED) {
+ ret = -errno;
fprintf(stderr,
"%s:%d: Error mapping buffer %d (%s): %s .\n",
__FILE__, __LINE__,
bo_gem->gem_handle, bo_gem->name,
strerror(errno));
pthread_mutex_unlock(&bufmgr_gem->lock);
- return errno;
+ return ret;
}
}
@@ -916,11 +971,13 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
set_domain.read_domains = I915_GEM_DOMAIN_GTT;
set_domain.write_domain = I915_GEM_DOMAIN_GTT;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN,
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
&set_domain);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
+ ret = -errno;
fprintf(stderr, "%s:%d: Error setting domain %d: %s\n",
__FILE__, __LINE__, bo_gem->gem_handle,
strerror(errno));
@@ -928,7 +985,7 @@ int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo)
pthread_mutex_unlock(&bufmgr_gem->lock);
- return 0;
+ return ret;
}
int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo)
@@ -968,7 +1025,8 @@ static int drm_intel_gem_bo_unmap(drm_intel_bo *bo)
*/
sw_finish.handle = bo_gem->gem_handle;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SW_FINISH,
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SW_FINISH,
&sw_finish);
} while (ret == -1 && errno == EINTR);
@@ -992,7 +1050,9 @@ drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset,
pwrite.size = size;
pwrite.data_ptr = (uint64_t) (uintptr_t) data;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite);
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_PWRITE,
+ &pwrite);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
fprintf(stderr,
@@ -1041,15 +1101,18 @@ drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset,
pread.size = size;
pread.data_ptr = (uint64_t) (uintptr_t) data;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PREAD, &pread);
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_PREAD,
+ &pread);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
+ ret = -errno;
fprintf(stderr,
"%s:%d: Error reading data from buffer %d: (%d %d) %s .\n",
__FILE__, __LINE__, bo_gem->gem_handle, (int)offset,
(int)size, strerror(errno));
}
- return 0;
+ return ret;
}
/** Waits for all GPU rendering to the object to have completed. */
@@ -1078,7 +1141,8 @@ drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable)
set_domain.read_domains = I915_GEM_DOMAIN_GTT;
set_domain.write_domain = write_enable ? I915_GEM_DOMAIN_GTT : 0;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_DOMAIN,
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_DOMAIN,
&set_domain);
} while (ret == -1 && errno == EINTR);
if (ret != 0) {
@@ -1138,10 +1202,22 @@ drm_intel_gem_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset,
drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo;
pthread_mutex_lock(&bufmgr_gem->lock);
+ if (bo_gem->has_error) {
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return -ENOMEM;
+ }
+
+ if (target_bo_gem->has_error) {
+ bo_gem->has_error = 1;
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return -ENOMEM;
+ }
/* Create a new relocation list if needed */
- if (bo_gem->relocs == NULL)
- drm_intel_setup_reloc_list(bo);
+ if (bo_gem->relocs == NULL && drm_intel_setup_reloc_list(bo)) {
+ pthread_mutex_unlock(&bufmgr_gem->lock);
+ return -ENOMEM;
+ }
/* Check overflow */
assert(bo_gem->reloc_count < bufmgr_gem->max_relocs);
@@ -1228,9 +1304,13 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used,
drm_clip_rect_t * cliprects, int num_cliprects, int DR4)
{
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_execbuffer execbuf;
int ret, i;
+ if (bo_gem->has_error)
+ return -ENOMEM;
+
pthread_mutex_lock(&bufmgr_gem->lock);
/* Update indices and set up the validate list. */
drm_intel_gem_bo_process_reloc(bo);
@@ -1250,21 +1330,25 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used,
execbuf.DR4 = DR4;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER,
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_EXECBUFFER,
&execbuf);
- } while (ret != 0 && errno == EAGAIN);
+ } while (ret != 0 && errno == EINTR);
- if (ret != 0 && errno == ENOMEM) {
- fprintf(stderr,
- "Execbuffer fails to pin. "
- "Estimate: %u. Actual: %u. Available: %u\n",
- drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
- bufmgr_gem->
- exec_count),
- drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
- bufmgr_gem->
- exec_count),
- (unsigned int)bufmgr_gem->gtt_size);
+ if (ret != 0) {
+ ret = -errno;
+ if (errno == ENOSPC) {
+ fprintf(stderr,
+ "Execbuffer fails to pin. "
+ "Estimate: %u. Actual: %u. Available: %u\n",
+ drm_intel_gem_estimate_batch_space(bufmgr_gem->exec_bos,
+ bufmgr_gem->
+ exec_count),
+ drm_intel_gem_compute_batch_space(bufmgr_gem->exec_bos,
+ bufmgr_gem->
+ exec_count),
+ (unsigned int)bufmgr_gem->gtt_size);
+ }
}
drm_intel_update_buffer_offsets(bufmgr_gem);
@@ -1277,13 +1361,12 @@ drm_intel_gem_bo_exec(drm_intel_bo *bo, int used,
/* Disconnect the buffer from the validate list */
bo_gem->validate_index = -1;
- drm_intel_gem_bo_unreference_locked(bo);
bufmgr_gem->exec_bos[i] = NULL;
}
bufmgr_gem->exec_count = 0;
pthread_mutex_unlock(&bufmgr_gem->lock);
- return 0;
+ return ret;
}
static int
@@ -1299,7 +1382,9 @@ drm_intel_gem_bo_pin(drm_intel_bo *bo, uint32_t alignment)
pin.alignment = alignment;
do {
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PIN, &pin);
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_PIN,
+ &pin);
} while (ret == -1 && errno == EINTR);
if (ret != 0)
@@ -1348,7 +1433,11 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
set_tiling.tiling_mode = *tiling_mode;
set_tiling.stride = stride;
- ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling);
+ do {
+ ret = ioctl(bufmgr_gem->fd,
+ DRM_IOCTL_I915_GEM_SET_TILING,
+ &set_tiling);
+ } while (ret == -1 && errno == EINTR);
if (ret != 0) {
*tiling_mode = bo_gem->tiling_mode;
return -errno;
@@ -1360,6 +1449,8 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
if (bo_gem->tiling_mode == I915_TILING_NONE)
bo_gem->reloc_tree_fences--;
+ drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem);
+
*tiling_mode = bo_gem->tiling_mode;
return 0;
}
@@ -1564,7 +1655,7 @@ drm_intel_gem_check_aperture_space(drm_intel_bo **bo_array, int count)
if (bufmgr_gem->available_fences) {
total_fences = drm_intel_gem_total_fences(bo_array, count);
if (total_fences > bufmgr_gem->available_fences)
- return -1;
+ return -ENOSPC;
}
total = drm_intel_gem_estimate_batch_space(bo_array, count);
@@ -1576,7 +1667,7 @@ drm_intel_gem_check_aperture_space(drm_intel_bo **bo_array, int count)
DBG("check_space: overflowed available aperture, "
"%dkb vs %dkb\n",
total / 1024, (int)bufmgr_gem->gtt_size / 1024);
- return -1;
+ return -ENOSPC;
} else {
DBG("drm_check_space: total %dkb vs bufgr %dkb\n", total / 1024,
(int)bufmgr_gem->gtt_size / 1024);