diff options
Diffstat (limited to 'intel')
-rw-r--r-- | intel/intel_bufmgr_gem.c | 211 |
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); |