From: <an...@ke...> - 2009-10-06 23:17:59
|
libdrm/intel/intel_atomic.h | 4 libdrm/intel/intel_bufmgr.c | 172 +- libdrm/intel/intel_bufmgr.h | 123 +- libdrm/intel/intel_bufmgr_fake.c | 2316 ++++++++++++++++++++------------------- libdrm/intel/intel_bufmgr_gem.c | 2193 +++++++++++++++++++----------------- libdrm/intel/intel_bufmgr_priv.h | 381 +++--- libdrm/intel/mm.c | 414 +++--- libdrm/intel/mm.h | 16 8 files changed, 2940 insertions(+), 2679 deletions(-) New commits: commit 3a7dfcdfafdd6ac83a4d3e7b4c1c52fd901b93ae Author: Jesse Barnes <jb...@vi...> Date: Tue Oct 6 14:34:06 2009 -0700 intel: Add a bo_alloc function for tiled BOs. This simplifies driver code in handling object allocation, and also gives us an opportunity to possibly cache tiled buffers if it turns out to be a win. [anholt: This is chopped out of the execbuf2 patch, as it seems to be useful separately and cleans up the execbuf2 changes to be more obvious] diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c index fd5a2e7..2469cd8 100644 --- a/libdrm/intel/intel_bufmgr.c +++ b/libdrm/intel/intel_bufmgr.c @@ -58,6 +58,15 @@ drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment); } +drm_intel_bo * +drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name, + int x, int y, int cpp, uint32_t *tiling_mode, + unsigned long *pitch, unsigned long flags) +{ + return bufmgr->bo_alloc_tiled(bufmgr, name, x, y, cpp, + tiling_mode, pitch, flags); +} + void drm_intel_bo_reference(drm_intel_bo *bo) { bo->bufmgr->bo_reference(bo); diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index 0dbe880..3801ff3 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -77,12 +77,20 @@ struct _drm_intel_bo { int handle; }; +#define BO_ALLOC_FOR_RENDER (1<<0) + drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, unsigned long size, unsigned int alignment); drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name, unsigned long size, unsigned int alignment); +drm_intel_bo *drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags); void drm_intel_bo_reference(drm_intel_bo *bo); void drm_intel_bo_unreference(drm_intel_bo *bo); int drm_intel_bo_map(drm_intel_bo *bo, int write_enable); diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index f325482..54b3cb8 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -51,8 +51,6 @@ #include "mm.h" #include "libdrm_lists.h" -#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) - #define DBG(...) do { \ if (bufmgr_fake->bufmgr.debug) \ drmMsg(__VA_ARGS__); \ @@ -838,6 +836,32 @@ drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr, return &bo_fake->bo; } +static drm_intel_bo * +drm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags) +{ + unsigned long stride, aligned_y; + + /* No runtime tiling support for fake. */ + *tiling_mode = I915_TILING_NONE; + + /* Align it for being a render target. Shouldn't need anything else. */ + stride = x * cpp; + stride = ROUND_UP_TO(stride, 64); + + /* 965 subspan loading alignment */ + aligned_y = ALIGN(y, 2); + + *pitch = stride; + + return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y, + 4096); +} + drm_intel_bo * drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr, const char *name, @@ -1565,6 +1589,7 @@ drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd, /* Hook in methods */ bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc; bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc; + bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled; bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference; bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference; bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map; diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index aa55f2d..3e46f53 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -193,6 +193,66 @@ static void drm_intel_gem_bo_unreference(drm_intel_bo *bo); static void drm_intel_gem_bo_free(drm_intel_bo *bo); +static unsigned long +drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size, + uint32_t *tiling_mode) +{ + unsigned long min_size, max_size; + unsigned long i; + + if (*tiling_mode == I915_TILING_NONE) + return size; + + /* 965+ just need multiples of page size for tiling */ + if (IS_I965G(bufmgr_gem)) + return ROUND_UP_TO(size, 4096); + + /* Older chips need powers of two, of at least 512k or 1M */ + if (IS_I9XX(bufmgr_gem)) { + min_size = 1024*1024; + max_size = 128*1024*1024; + } else { + min_size = 512*1024; + max_size = 64*1024*1024; + } + + if (size > max_size) { + *tiling_mode = I915_TILING_NONE; + return size; + } + + for (i = min_size; i < size; i <<= 1) + ; + + return i; +} + +/* + * Round a given pitch up to the minimum required for X tiling on a + * given chip. We use 512 as the minimum to allow for a later tiling + * change. + */ +static unsigned long +drm_intel_gem_bo_tile_pitch(drm_intel_bufmgr_gem *bufmgr_gem, + unsigned long pitch, uint32_t tiling_mode) +{ + unsigned long tile_width = 512; + unsigned long i; + + if (tiling_mode == I915_TILING_NONE) + return ROUND_UP_TO(pitch, tile_width); + + /* 965 is flexible */ + if (IS_I965G(bufmgr_gem)) + return ROUND_UP_TO(pitch, tile_width); + + /* Pre-965 needs power of two tile width */ + for (i = tile_width; i < pitch; i <<= 1) + ; + + return i; +} + static struct drm_intel_gem_bo_bucket * drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size) @@ -372,8 +432,7 @@ static drm_intel_bo * drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, const char *name, unsigned long size, - unsigned int alignment, - int for_render) + unsigned long flags) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; drm_intel_bo_gem *bo_gem; @@ -382,6 +441,10 @@ drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, struct drm_intel_gem_bo_bucket *bucket; int alloc_from_cache; unsigned long bo_size; + int for_render = 0; + + if (flags & BO_ALLOC_FOR_RENDER) + for_render = 1; /* Round the allocated size up to a power of two number of pages. */ bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size); @@ -482,8 +545,9 @@ drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, unsigned long size, unsigned int alignment) { - return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, - 1); + assert(alignment <= 4096); + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, + BO_ALLOC_FOR_RENDER); } static drm_intel_bo * @@ -492,8 +556,45 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, unsigned long size, unsigned int alignment) { - return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, - 0); + assert(alignment <= 4096); + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0); +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name, + int x, int y, int cpp, uint32_t *tiling_mode, + unsigned long *pitch, unsigned long flags) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + drm_intel_bo *bo; + unsigned long size, stride, aligned_y = y; + int ret; + + if (*tiling_mode == I915_TILING_NONE) + aligned_y = ALIGN(y, 2); + else if (*tiling_mode == I915_TILING_X) + aligned_y = ALIGN(y, 8); + else if (*tiling_mode == I915_TILING_Y) + aligned_y = ALIGN(y, 32); + + stride = x * cpp; + stride = drm_intel_gem_bo_tile_pitch(bufmgr_gem, stride, *tiling_mode); + size = stride * aligned_y; + size = drm_intel_gem_bo_tile_size(bufmgr_gem, size, tiling_mode); + + bo = drm_intel_gem_bo_alloc_internal(bufmgr, name, size, flags); + if (!bo) + return NULL; + + ret = drm_intel_gem_bo_set_tiling(bo, tiling_mode, stride); + if (ret != 0) { + drm_intel_gem_bo_unreference(bo); + return NULL; + } + + *pitch = stride; + + return bo; } /** @@ -1565,6 +1666,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem->bufmgr.bo_alloc = drm_intel_gem_bo_alloc; bufmgr_gem->bufmgr.bo_alloc_for_render = drm_intel_gem_bo_alloc_for_render; + bufmgr_gem->bufmgr.bo_alloc_tiled = drm_intel_gem_bo_alloc_tiled; bufmgr_gem->bufmgr.bo_reference = drm_intel_gem_bo_reference; bufmgr_gem->bufmgr.bo_unreference = drm_intel_gem_bo_unreference; bufmgr_gem->bufmgr.bo_map = drm_intel_gem_bo_map; diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h index 3b19eca..475c402 100644 --- a/libdrm/intel/intel_bufmgr_priv.h +++ b/libdrm/intel/intel_bufmgr_priv.h @@ -61,6 +61,28 @@ struct _drm_intel_bufmgr { unsigned long size, unsigned int alignment); + /** + * Allocate a tiled buffer object. + * + * Alignment for tiled objects is set automatically; the 'flags' + * argument provides a hint about how the object will be used initially. + * + * Valid tiling formats are: + * I915_TILING_NONE + * I915_TILING_X + * I915_TILING_Y + * + * Note the tiling format may be rejected; callers should check the + * 'tiling_mode' field on return, as well as the pitch value, which + * may have been rounded up to accommodate for tiling restrictions. + */ + drm_intel_bo *(*bo_alloc_tiled) (drm_intel_bufmgr *bufmgr, + const char *name, + int x, int y, int cpp, + uint32_t *tiling_mode, + unsigned long *pitch, + unsigned long flags); + /** Takes a reference on a buffer object */ void (*bo_reference) (drm_intel_bo *bo); @@ -225,4 +247,8 @@ struct _drm_intel_bufmgr { int debug; }; +#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) +#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y)) +#define ROUND_UP_TO_MB(x) ROUND_UP_TO((x), 1024*1024) + #endif /* INTEL_BUFMGR_PRIV_H */ commit 02c775fc750b48ae25b6a4af51afbfe090ebada4 Author: Eric Anholt <er...@an...> Date: Tue Oct 6 15:25:21 2009 -0700 intel: Fix up some stale doxygen comments. diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index 9f07a94..0dbe880 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -56,8 +56,9 @@ struct _drm_intel_bo { unsigned long align; /** - * Card virtual address (offset from the beginning of the aperture) - * for the object. Only valid while validated. + * Last seen card virtual address (offset from the beginning of the + * aperture) for the object. This should be used to fill relocation + * entries when calling drm_intel_bo_emit_reloc() */ unsigned long offset; diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h index b7cae6f..3b19eca 100644 --- a/libdrm/intel/intel_bufmgr_priv.h +++ b/libdrm/intel/intel_bufmgr_priv.h @@ -45,8 +45,7 @@ struct _drm_intel_bufmgr { * * Buffer objects are not necessarily initially mapped into CPU virtual * address space or graphics device aperture. They must be mapped - * using bo_map() to be used by the CPU, and validated for use using - * bo_validate() to be used from the graphics device. + * using bo_map() or drm_intel_gem_bo_map_gtt() to be used by the CPU. */ drm_intel_bo *(*bo_alloc) (drm_intel_bufmgr *bufmgr, const char *name, unsigned long size, unsigned int alignment); @@ -67,7 +66,7 @@ struct _drm_intel_bufmgr { /** * Releases a reference on a buffer object, freeing the data if - * rerefences remain. + * no references remain. */ void (*bo_unreference) (drm_intel_bo *bo); commit d70d60529f77ec73322be7b887fd6a3faf133bce Author: Eric Anholt <er...@an...> Date: Tue Oct 6 12:40:42 2009 -0700 intel: Reformat to the kernel coding style. Welcome to the 8-space future. This is done with: Lindent *.[ch] perl -pi -e 's|drm_intel_bo \* |drm_intel_bo *|g' *.[ch] perl -pi -e 's|drm_intel_bufmgr \* |drm_intel_bufmgr *|g' *.[ch] perl -pi -e 's|drm_intel_bo_gem \* |drm_intel_bo_gem *|g' *.[ch] perl -pi -e 's|drm_intel_bufmgr_gem \* |drm_intel_bufmgr_gem *|g' *.[ch] perl -pi -e 's|_fake \* |_fake *|g' *.[ch] hand-editing to whack indented comments into line and other touchups. diff --git a/libdrm/intel/intel_atomic.h b/libdrm/intel/intel_atomic.h index 562394a..9eb50a1 100644 --- a/libdrm/intel/intel_atomic.h +++ b/libdrm/intel/intel_atomic.h @@ -42,7 +42,9 @@ #define HAS_ATOMIC_OPS 1 -typedef struct { int atomic; } atomic_t; +typedef struct { + int atomic; +} atomic_t; # define atomic_read(x) ((x)->atomic) # define atomic_set(x, val) ((x)->atomic = (val)) diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c index 20e59b8..fd5a2e7 100644 --- a/libdrm/intel/intel_bufmgr.c +++ b/libdrm/intel/intel_bufmgr.c @@ -44,124 +44,114 @@ * Convenience functions for buffer management methods. */ -drm_intel_bo * -drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment) +drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, + unsigned long size, unsigned int alignment) { - return bufmgr->bo_alloc(bufmgr, name, size, alignment); + return bufmgr->bo_alloc(bufmgr, name, size, alignment); } -drm_intel_bo * -drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment) +drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) { - return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment); + return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment); } -void -drm_intel_bo_reference(drm_intel_bo *bo) +void drm_intel_bo_reference(drm_intel_bo *bo) { - bo->bufmgr->bo_reference(bo); + bo->bufmgr->bo_reference(bo); } -void -drm_intel_bo_unreference(drm_intel_bo *bo) +void drm_intel_bo_unreference(drm_intel_bo *bo) { - if (bo == NULL) - return; + if (bo == NULL) + return; - bo->bufmgr->bo_unreference(bo); + bo->bufmgr->bo_unreference(bo); } -int -drm_intel_bo_map(drm_intel_bo *buf, int write_enable) +int drm_intel_bo_map(drm_intel_bo *buf, int write_enable) { - return buf->bufmgr->bo_map(buf, write_enable); + return buf->bufmgr->bo_map(buf, write_enable); } -int -drm_intel_bo_unmap(drm_intel_bo *buf) +int drm_intel_bo_unmap(drm_intel_bo *buf) { - return buf->bufmgr->bo_unmap(buf); + return buf->bufmgr->bo_unmap(buf); } int drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset, unsigned long size, const void *data) { - int ret; + int ret; - if (bo->bufmgr->bo_subdata) - return bo->bufmgr->bo_subdata(bo, offset, size, data); - if (size == 0 || data == NULL) - return 0; + if (bo->bufmgr->bo_subdata) + return bo->bufmgr->bo_subdata(bo, offset, size, data); + if (size == 0 || data == NULL) + return 0; - ret = drm_intel_bo_map(bo, 1); - if (ret) - return ret; - memcpy((unsigned char *)bo->virtual + offset, data, size); - drm_intel_bo_unmap(bo); - return 0; + ret = drm_intel_bo_map(bo, 1); + if (ret) + return ret; + memcpy((unsigned char *)bo->virtual + offset, data, size); + drm_intel_bo_unmap(bo); + return 0; } int drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, unsigned long size, void *data) { - int ret; - if (bo->bufmgr->bo_subdata) - return bo->bufmgr->bo_get_subdata(bo, offset, size, data); + int ret; + if (bo->bufmgr->bo_subdata) + return bo->bufmgr->bo_get_subdata(bo, offset, size, data); - if (size == 0 || data == NULL) - return 0; + if (size == 0 || data == NULL) + return 0; - ret = drm_intel_bo_map(bo, 0); - if (ret) - return ret; - memcpy(data, (unsigned char *)bo->virtual + offset, size); - drm_intel_bo_unmap(bo); - return 0; + ret = drm_intel_bo_map(bo, 0); + if (ret) + return ret; + memcpy(data, (unsigned char *)bo->virtual + offset, size); + drm_intel_bo_unmap(bo); + return 0; } -void -drm_intel_bo_wait_rendering(drm_intel_bo *bo) +void drm_intel_bo_wait_rendering(drm_intel_bo *bo) { - bo->bufmgr->bo_wait_rendering(bo); + bo->bufmgr->bo_wait_rendering(bo); } -void -drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr) +void drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr) { - bufmgr->destroy(bufmgr); + bufmgr->destroy(bufmgr); } int drm_intel_bo_exec(drm_intel_bo *bo, int used, - drm_clip_rect_t *cliprects, int num_cliprects, - int DR4) + drm_clip_rect_t * cliprects, int num_cliprects, int DR4) { - return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4); + return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4); } -void -drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug) +void drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug) { - bufmgr->debug = enable_debug; + bufmgr->debug = enable_debug; } -int -drm_intel_bufmgr_check_aperture_space(drm_intel_bo **bo_array, int count) +int drm_intel_bufmgr_check_aperture_space(drm_intel_bo ** bo_array, int count) { return bo_array[0]->bufmgr->check_aperture_space(bo_array, count); } -int -drm_intel_bo_flink(drm_intel_bo *bo, uint32_t *name) +int drm_intel_bo_flink(drm_intel_bo *bo, uint32_t * name) { - if (bo->bufmgr->bo_flink) - return bo->bufmgr->bo_flink(bo, name); + if (bo->bufmgr->bo_flink) + return bo->bufmgr->bo_flink(bo, name); - return -ENODEV; + return -ENODEV; } int @@ -174,43 +164,41 @@ drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, read_domains, write_domain); } -int -drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment) +int drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment) { - if (bo->bufmgr->bo_pin) - return bo->bufmgr->bo_pin(bo, alignment); + if (bo->bufmgr->bo_pin) + return bo->bufmgr->bo_pin(bo, alignment); - return -ENODEV; + return -ENODEV; } -int -drm_intel_bo_unpin(drm_intel_bo *bo) +int drm_intel_bo_unpin(drm_intel_bo *bo) { - if (bo->bufmgr->bo_unpin) - return bo->bufmgr->bo_unpin(bo); + if (bo->bufmgr->bo_unpin) + return bo->bufmgr->bo_unpin(bo); - return -ENODEV; + return -ENODEV; } -int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, +int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, uint32_t stride) { - if (bo->bufmgr->bo_set_tiling) - return bo->bufmgr->bo_set_tiling(bo, tiling_mode, stride); + if (bo->bufmgr->bo_set_tiling) + return bo->bufmgr->bo_set_tiling(bo, tiling_mode, stride); - *tiling_mode = I915_TILING_NONE; - return 0; + *tiling_mode = I915_TILING_NONE; + return 0; } -int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode) +int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode) { - if (bo->bufmgr->bo_get_tiling) - return bo->bufmgr->bo_get_tiling(bo, tiling_mode, swizzle_mode); + if (bo->bufmgr->bo_get_tiling) + return bo->bufmgr->bo_get_tiling(bo, tiling_mode, swizzle_mode); - *tiling_mode = I915_TILING_NONE; - *swizzle_mode = I915_BIT_6_SWIZZLE_NONE; - return 0; + *tiling_mode = I915_TILING_NONE; + *swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + return 0; } int drm_intel_bo_disable_reuse(drm_intel_bo *bo) @@ -227,17 +215,14 @@ int drm_intel_bo_busy(drm_intel_bo *bo) return 0; } -int -drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +int drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) { return bo->bufmgr->bo_references(bo, target_bo); } -int -drm_intel_get_pipe_from_crtc_id (drm_intel_bufmgr *bufmgr, int crtc_id) +int drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id) { if (bufmgr->get_pipe_from_crtc_id) return bufmgr->get_pipe_from_crtc_id(bufmgr, crtc_id); return -1; } - diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index cb7196c..9f07a94 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -40,37 +40,40 @@ typedef struct _drm_intel_bufmgr drm_intel_bufmgr; typedef struct _drm_intel_bo drm_intel_bo; struct _drm_intel_bo { - /** - * Size in bytes of the buffer object. - * - * The size may be larger than the size originally requested for the - * allocation, such as being aligned to page size. - */ - unsigned long size; - /** - * Alignment requirement for object - * - * Used for GTT mapping & pinning the object. - */ - unsigned long align; - - /** - * Card virtual address (offset from the beginning of the aperture) for the - * object. Only valid while validated. - */ - unsigned long offset; - /** - * Virtual address for accessing the buffer data. Only valid while mapped. - */ - void *virtual; - - /** Buffer manager context associated with this buffer object */ - drm_intel_bufmgr *bufmgr; - - /** - * MM-specific handle for accessing object - */ - int handle; + /** + * Size in bytes of the buffer object. + * + * The size may be larger than the size originally requested for the + * allocation, such as being aligned to page size. + */ + unsigned long size; + + /** + * Alignment requirement for object + * + * Used for GTT mapping & pinning the object. + */ + unsigned long align; + + /** + * Card virtual address (offset from the beginning of the aperture) + * for the object. Only valid while validated. + */ + unsigned long offset; + + /** + * Virtual address for accessing the buffer data. Only valid while + * mapped. + */ + void *virtual; + + /** Buffer manager context associated with this buffer object */ + drm_intel_bufmgr *bufmgr; + + /** + * MM-specific handle for accessing object + */ + int handle; }; drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, @@ -85,28 +88,27 @@ int drm_intel_bo_map(drm_intel_bo *bo, int write_enable); int drm_intel_bo_unmap(drm_intel_bo *bo); int drm_intel_bo_subdata(drm_intel_bo *bo, unsigned long offset, - unsigned long size, const void *data); + unsigned long size, const void *data); int drm_intel_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, - unsigned long size, void *data); + unsigned long size, void *data); void drm_intel_bo_wait_rendering(drm_intel_bo *bo); void drm_intel_bufmgr_set_debug(drm_intel_bufmgr *bufmgr, int enable_debug); void drm_intel_bufmgr_destroy(drm_intel_bufmgr *bufmgr); int drm_intel_bo_exec(drm_intel_bo *bo, int used, - drm_clip_rect_t *cliprects, int num_cliprects, - int DR4); -int drm_intel_bufmgr_check_aperture_space(drm_intel_bo **bo_array, int count); + drm_clip_rect_t * cliprects, int num_cliprects, int DR4); +int drm_intel_bufmgr_check_aperture_space(drm_intel_bo ** bo_array, int count); int drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, drm_intel_bo *target_bo, uint32_t target_offset, uint32_t read_domains, uint32_t write_domain); int drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment); int drm_intel_bo_unpin(drm_intel_bo *bo); -int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, +int drm_intel_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, uint32_t stride); -int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode); -int drm_intel_bo_flink(drm_intel_bo *bo, uint32_t *name); +int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); +int drm_intel_bo_flink(drm_intel_bo *bo, uint32_t * name); int drm_intel_bo_busy(drm_intel_bo *bo); int drm_intel_bo_disable_reuse(drm_intel_bo *bo); @@ -129,26 +131,29 @@ drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd, unsigned long low_offset, void *low_virtual, unsigned long size, - volatile unsigned int *last_dispatch); + volatile unsigned int + *last_dispatch); void drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr, - volatile unsigned int *last_dispatch); + volatile unsigned int + *last_dispatch); void drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr, - int (*exec)(drm_intel_bo *bo, - unsigned int used, - void *priv), + int (*exec) (drm_intel_bo *bo, + unsigned int used, + void *priv), void *priv); void drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr, - unsigned int (*emit)(void *priv), - void (*wait)(unsigned int fence, - void *priv), + unsigned int (*emit) (void *priv), + void (*wait) (unsigned int fence, + void *priv), void *priv); drm_intel_bo *drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long offset, unsigned long size, - void *virtual); + unsigned long offset, + unsigned long size, void *virtual); void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, - void (*invalidate_cb)(drm_intel_bo *bo, - void *ptr), + void (*invalidate_cb) (drm_intel_bo + * bo, + void *ptr), void *ptr); void drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr); @@ -174,8 +179,8 @@ void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr); #define dri_bo_emit_reloc(reloc_bo, read, write, target_offset, \ reloc_offset, target_bo) \ drm_intel_bo_emit_reloc(reloc_bo, reloc_offset, \ - target_bo, target_offset, \ - read, write); + target_bo, target_offset, \ + read, write); #define dri_bo_pin drm_intel_bo_pin #define dri_bo_unpin drm_intel_bo_unpin #define dri_bo_get_tiling drm_intel_bo_get_tiling @@ -196,4 +201,3 @@ void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr); /** @{ */ #endif /* INTEL_BUFMGR_H */ - diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 969c03d..f325482 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -54,8 +54,8 @@ #define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) #define DBG(...) do { \ - if (bufmgr_fake->bufmgr.debug) \ - drmMsg(__VA_ARGS__); \ + if (bufmgr_fake->bufmgr.debug) \ + drmMsg(__VA_ARGS__); \ } while (0) /* Internal flags: @@ -72,150 +72,157 @@ */ #define MAX_RELOCS 4096 -struct fake_buffer_reloc -{ - /** Buffer object that the relocation points at. */ - drm_intel_bo *target_buf; - /** Offset of the relocation entry within reloc_buf. */ - uint32_t offset; - /** Cached value of the offset when we last performed this relocation. */ - uint32_t last_target_offset; - /** Value added to target_buf's offset to get the relocation entry. */ - uint32_t delta; - /** Cache domains the target buffer is read into. */ - uint32_t read_domains; - /** Cache domain the target buffer will have dirty cachelines in. */ - uint32_t write_domain; +struct fake_buffer_reloc { + /** Buffer object that the relocation points at. */ + drm_intel_bo *target_buf; + /** Offset of the relocation entry within reloc_buf. */ + uint32_t offset; + /** + * Cached value of the offset when we last performed this relocation. + */ + uint32_t last_target_offset; + /** Value added to target_buf's offset to get the relocation entry. */ + uint32_t delta; + /** Cache domains the target buffer is read into. */ + uint32_t read_domains; + /** Cache domain the target buffer will have dirty cachelines in. */ + uint32_t write_domain; }; struct block { - struct block *next, *prev; - struct mem_block *mem; /* BM_MEM_AGP */ - - /** - * Marks that the block is currently in the aperture and has yet to be - * fenced. - */ - unsigned on_hardware:1; - /** - * Marks that the block is currently fenced (being used by rendering) and - * can't be freed until @fence is passed. - */ - unsigned fenced:1; - - /** Fence cookie for the block. */ - unsigned fence; /* Split to read_fence, write_fence */ - - drm_intel_bo *bo; - void *virtual; + struct block *next, *prev; + struct mem_block *mem; /* BM_MEM_AGP */ + + /** + * Marks that the block is currently in the aperture and has yet to be + * fenced. + */ + unsigned on_hardware:1; + /** + * Marks that the block is currently fenced (being used by rendering) + * and can't be freed until @fence is passed. + */ + unsigned fenced:1; + + /** Fence cookie for the block. */ + unsigned fence; /* Split to read_fence, write_fence */ + + drm_intel_bo *bo; + void *virtual; }; typedef struct _bufmgr_fake { - drm_intel_bufmgr bufmgr; - - pthread_mutex_t lock; - - unsigned long low_offset; - unsigned long size; - void *virtual; - - struct mem_block *heap; - - unsigned buf_nr; /* for generating ids */ - - /** - * List of blocks which are currently in the GART but haven't been - * fenced yet. - */ - struct block on_hardware; - /** - * List of blocks which are in the GART and have an active fence on them. - */ - struct block fenced; - /** - * List of blocks which have an expired fence and are ready to be evicted. - */ - struct block lru; - - unsigned int last_fence; - - unsigned fail:1; - unsigned need_fence:1; - int thrashing; - - /** - * Driver callback to emit a fence, returning the cookie. - * - * This allows the driver to hook in a replacement for the DRM usage in - * bufmgr_fake. - * - * Currently, this also requires that a write flush be emitted before - * emitting the fence, but this should change. - */ - unsigned int (*fence_emit)(void *private); - /** Driver callback to wait for a fence cookie to have passed. */ - void (*fence_wait)(unsigned int fence, void *private); - void *fence_priv; - - /** - * Driver callback to execute a buffer. - * - * This allows the driver to hook in a replacement for the DRM usage in - * bufmgr_fake. - */ - int (*exec)(drm_intel_bo *bo, unsigned int used, void *priv); - void *exec_priv; - - /** Driver-supplied argument to driver callbacks */ - void *driver_priv; - /* Pointer to kernel-updated sarea data for the last completed user irq */ - volatile int *last_dispatch; - - int fd; - - int debug; - - int performed_rendering; + drm_intel_bufmgr bufmgr; + + pthread_mutex_t lock; + + unsigned long low_offset; + unsigned long size; + void *virtual; + + struct mem_block *heap; + + unsigned buf_nr; /* for generating ids */ + + /** + * List of blocks which are currently in the GART but haven't been + * fenced yet. + */ + struct block on_hardware; + /** + * List of blocks which are in the GART and have an active fence on + * them. + */ + struct block fenced; + /** + * List of blocks which have an expired fence and are ready to be + * evicted. + */ + struct block lru; + + unsigned int last_fence; + + unsigned fail:1; + unsigned need_fence:1; + int thrashing; + + /** + * Driver callback to emit a fence, returning the cookie. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + * + * Currently, this also requires that a write flush be emitted before + * emitting the fence, but this should change. + */ + unsigned int (*fence_emit) (void *private); + /** Driver callback to wait for a fence cookie to have passed. */ + void (*fence_wait) (unsigned int fence, void *private); + void *fence_priv; + + /** + * Driver callback to execute a buffer. + * + * This allows the driver to hook in a replacement for the DRM usage in + * bufmgr_fake. + */ + int (*exec) (drm_intel_bo *bo, unsigned int used, void *priv); + void *exec_priv; + + /** Driver-supplied argument to driver callbacks */ + void *driver_priv; + /** + * Pointer to kernel-updated sarea data for the last completed user irq + */ + volatile int *last_dispatch; + + int fd; + + int debug; + + int performed_rendering; } drm_intel_bufmgr_fake; typedef struct _drm_intel_bo_fake { - drm_intel_bo bo; - - unsigned id; /* debug only */ - const char *name; - - unsigned dirty:1; - /** has the card written to this buffer - we make need to copy it back */ - unsigned card_dirty:1; - unsigned int refcount; - /* Flags may consist of any of the DRM_BO flags, plus - * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the first two - * driver private flags. - */ - uint64_t flags; - /** Cache domains the target buffer is read into. */ - uint32_t read_domains; - /** Cache domain the target buffer will have dirty cachelines in. */ - uint32_t write_domain; - - unsigned int alignment; - int is_static, validated; - unsigned int map_count; - - /** relocation list */ - struct fake_buffer_reloc *relocs; - int nr_relocs; - /** - * Total size of the target_bos of this buffer. - * - * Used for estimation in check_aperture. - */ - unsigned int child_size; - - struct block *block; - void *backing_store; - void (*invalidate_cb)(drm_intel_bo *bo, void *ptr); - void *invalidate_ptr; + drm_intel_bo bo; + + unsigned id; /* debug only */ + const char *name; + + unsigned dirty:1; + /** + * has the card written to this buffer - we make need to copy it back + */ + unsigned card_dirty:1; + unsigned int refcount; + /* Flags may consist of any of the DRM_BO flags, plus + * DRM_BO_NO_BACKING_STORE and BM_NO_FENCE_SUBDATA, which are the + * first two driver private flags. + */ + uint64_t flags; + /** Cache domains the target buffer is read into. */ + uint32_t read_domains; + /** Cache domain the target buffer will have dirty cachelines in. */ + uint32_t write_domain; + + unsigned int alignment; + int is_static, validated; + unsigned int map_count; + + /** relocation list */ + struct fake_buffer_reloc *relocs; + int nr_relocs; + /** + * Total size of the target_bos of this buffer. + * + * Used for estimation in check_aperture. + */ + unsigned int child_size; + + struct block *block; + void *backing_store; + void (*invalidate_cb) (drm_intel_bo *bo, void *ptr); + void *invalidate_ptr; } drm_intel_bo_fake; static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, @@ -223,185 +230,190 @@ static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, #define MAXFENCE 0x7fffffff -static int FENCE_LTE( unsigned a, unsigned b ) +static int +FENCE_LTE(unsigned a, unsigned b) { - if (a == b) - return 1; + if (a == b) + return 1; - if (a < b && b - a < (1<<24)) - return 1; + if (a < b && b - a < (1 << 24)) + return 1; - if (a > b && MAXFENCE - a + b < (1<<24)) - return 1; + if (a > b && MAXFENCE - a + b < (1 << 24)) + return 1; - return 0; + return 0; } -void drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr, - unsigned int (*emit)(void *priv), - void (*wait)(unsigned int fence, - void *priv), - void *priv) +void +drm_intel_bufmgr_fake_set_fence_callback(drm_intel_bufmgr *bufmgr, + unsigned int (*emit) (void *priv), + void (*wait) (unsigned int fence, + void *priv), + void *priv) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; - bufmgr_fake->fence_emit = emit; - bufmgr_fake->fence_wait = wait; - bufmgr_fake->fence_priv = priv; + bufmgr_fake->fence_emit = emit; + bufmgr_fake->fence_wait = wait; + bufmgr_fake->fence_priv = priv; } static unsigned int _fence_emit_internal(drm_intel_bufmgr_fake *bufmgr_fake) { - struct drm_i915_irq_emit ie; - int ret, seq = 1; - - if (bufmgr_fake->fence_emit != NULL) { - seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv); - return seq; - } - - ie.irq_seq = &seq; - ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, - &ie, sizeof(ie)); - if (ret) { - drmMsg("%s: drm_i915_irq_emit: %d\n", __FUNCTION__, ret); - abort(); - } - - DBG("emit 0x%08x\n", seq); - return seq; + struct drm_i915_irq_emit ie; + int ret, seq = 1; + + if (bufmgr_fake->fence_emit != NULL) { + seq = bufmgr_fake->fence_emit(bufmgr_fake->fence_priv); + return seq; + } + + ie.irq_seq = &seq; + ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, + &ie, sizeof(ie)); + if (ret) { + drmMsg("%s: drm_i915_irq_emit: %d\n", __FUNCTION__, ret); + abort(); + } + + DBG("emit 0x%08x\n", seq); + return seq; } static void _fence_wait_internal(drm_intel_bufmgr_fake *bufmgr_fake, int seq) { - struct drm_i915_irq_wait iw; - int hw_seq, busy_count = 0; - int ret; - int kernel_lied; - - if (bufmgr_fake->fence_wait != NULL) { - bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv); - clear_fenced(bufmgr_fake, seq); - return; - } - - DBG("wait 0x%08x\n", iw.irq_seq); - - iw.irq_seq = seq; - - /* The kernel IRQ_WAIT implementation is all sorts of broken. - * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit unsigned - * range. - * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit - * signed range. - * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit - * signed range. - * 4) It returns -EBUSY in 3 seconds even if the hardware is still - * successfully chewing through buffers. - * - * Assume that in userland we treat sequence numbers as ints, which makes - * some of the comparisons convenient, since the sequence numbers are - * all postive signed integers. - * - * From this we get several cases we need to handle. Here's a timeline. - * 0x2 0x7 0x7ffffff8 0x7ffffffd - * | | | | - * ------------------------------------------------------------------- - * - * A) Normal wait for hw to catch up - * hw_seq seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = 5. If we call IRQ_WAIT, it will wait for hw to catch up. - * - * B) Normal wait for a sequence number that's already passed. - * seq hw_seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = -5. If we call IRQ_WAIT, it returns 0 quickly. - * - * C) Hardware has already wrapped around ahead of us - * hw_seq seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = 0x80000000 - 5. If we called IRQ_WAIT, it would wait - * for hw_seq >= seq, which may never occur. Thus, we want to catch this - * in userland and return 0. - * - * D) We've wrapped around ahead of the hardware. - * seq hw_seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = -(0x80000000 - 5). If we called IRQ_WAIT, it would return - * 0 quickly because hw_seq >= seq, even though the hardware isn't caught up. - * Thus, we need to catch this early return in userland and bother the - * kernel until the hardware really does catch up. - * - * E) Hardware might wrap after we test in userland. - * hw_seq seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = 5. If we call IRQ_WAIT, it will likely see seq >= hw_seq - * and wait. However, suppose hw_seq wraps before we make it into the - * kernel. The kernel sees hw_seq >= seq and waits for 3 seconds then - * returns -EBUSY. This is case C). We should catch this and then return - * successfully. - * - * F) Hardware might take a long time on a buffer. - * hw_seq seq - * | | - * ------------------------------------------------------------------- - * seq - hw_seq = 5. If we call IRQ_WAIT, if sequence 2 through 5 take too - * long, it will return -EBUSY. Batchbuffers in the gltestperf demo were - * seen to take up to 7 seconds. We should catch early -EBUSY return - * and keep trying. - */ - - do { - /* Keep a copy of last_dispatch so that if the wait -EBUSYs because the - * hardware didn't catch up in 3 seconds, we can see if it at least made - * progress and retry. - */ - hw_seq = *bufmgr_fake->last_dispatch; - - /* Catch case C */ - if (seq - hw_seq > 0x40000000) - return; - - ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, - &iw, sizeof(iw)); - /* Catch case D */ - kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch < - -0x40000000); - - /* Catch case E */ - if (ret == -EBUSY && (seq - *bufmgr_fake->last_dispatch > 0x40000000)) - ret = 0; - - /* Catch case F: Allow up to 15 seconds chewing on one buffer. */ - if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch)) - busy_count = 0; - else - busy_count++; - } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || - (ret == -EBUSY && busy_count < 5)); - - if (ret != 0) { - drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__, __LINE__, - strerror(-ret)); - abort(); - } - clear_fenced(bufmgr_fake, seq); + struct drm_i915_irq_wait iw; + int hw_seq, busy_count = 0; + int ret; + int kernel_lied; + + if (bufmgr_fake->fence_wait != NULL) { + bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv); + clear_fenced(bufmgr_fake, seq); + return; + } + + DBG("wait 0x%08x\n", iw.irq_seq); + + iw.irq_seq = seq; + + /* The kernel IRQ_WAIT implementation is all sorts of broken. + * 1) It returns 1 to 0x7fffffff instead of using the full 32-bit + * unsigned range. + * 2) It returns 0 if hw_seq >= seq, not seq - hw_seq < 0 on the 32-bit + * signed range. + * 3) It waits if seq < hw_seq, not seq - hw_seq > 0 on the 32-bit + * signed range. + * 4) It returns -EBUSY in 3 seconds even if the hardware is still + * successfully chewing through buffers. + * + * Assume that in userland we treat sequence numbers as ints, which + * makes some of the comparisons convenient, since the sequence + * numbers are all postive signed integers. + * + * From this we get several cases we need to handle. Here's a timeline. + * 0x2 0x7 0x7ffffff8 0x7ffffffd + * | | | | + * ------------------------------------------------------------ + * + * A) Normal wait for hw to catch up + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 5. If we call IRQ_WAIT, it will wait for hw to + * catch up. + * + * B) Normal wait for a sequence number that's already passed. + * seq hw_seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = -5. If we call IRQ_WAIT, it returns 0 quickly. + * + * C) Hardware has already wrapped around ahead of us + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 0x80000000 - 5. If we called IRQ_WAIT, it would wait + * for hw_seq >= seq, which may never occur. Thus, we want to catch + * this in userland and return 0. + * + * D) We've wrapped around ahead of the hardware. + * seq hw_seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = -(0x80000000 - 5). If we called IRQ_WAIT, it would + * return 0 quickly because hw_seq >= seq, even though the hardware + * isn't caught up. Thus, we need to catch this early return in + * userland and bother the kernel until the hardware really does + * catch up. + * + * E) Hardware might wrap after we test in userland. + * hw_seq seq + * | | + * ------------------------------------------------------------ + * seq - hw_seq = 5. If we call IRQ_WAIT, it will likely see seq >= + * hw_seq and wait. However, suppose hw_seq wraps before we make it + * into the kernel. The kernel sees hw_seq >= seq and waits for 3 + * seconds then returns -EBUSY. This is case C). We should catch + * this and then return successfully. + * + * F) Hardware might take a long time on a buffer. + * hw_seq seq + * | | + * ------------------------------------------------------------------- + * seq - hw_seq = 5. If we call IRQ_WAIT, if sequence 2 through 5 + * take too long, it will return -EBUSY. Batchbuffers in the + * gltestperf demo were seen to take up to 7 seconds. We should + * catch early -EBUSY return and keep trying. + */ + + do { + /* Keep a copy of last_dispatch so that if the wait -EBUSYs + * because the hardware didn't catch up in 3 seconds, we can + * see if it at least made progress and retry. + */ + hw_seq = *bufmgr_fake->last_dispatch; + + /* Catch case C */ + if (seq - hw_seq > 0x40000000) + return; + + ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, + &iw, sizeof(iw)); + /* Catch case D */ + kernel_lied = (ret == 0) && (seq - *bufmgr_fake->last_dispatch < + -0x40000000); + + /* Catch case E */ + if (ret == -EBUSY + && (seq - *bufmgr_fake->last_dispatch > 0x40000000)) + ret = 0; + + /* Catch case F: Allow up to 15 seconds chewing on one buffer. */ + if ((ret == -EBUSY) && (hw_seq != *bufmgr_fake->last_dispatch)) + busy_count = 0; + else + busy_count++; + } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && busy_count < 5)); + + if (ret != 0) { + drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__, + __LINE__, strerror(-ret)); + abort(); + } + clear_fenced(bufmgr_fake, seq); } static int _fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) { - /* Slight problem with wrap-around: - */ - return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence); + /* Slight problem with wrap-around: + */ + return fence == 0 || FENCE_LTE(fence, bufmgr_fake->last_fence); } /** @@ -410,293 +422,300 @@ _fence_test(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) static int alloc_block(drm_intel_bo *bo) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - drm_intel_bufmgr_fake *bufmgr_fake= (drm_intel_bufmgr_fake *)bo->bufmgr; - struct block *block = (struct block *)calloc(sizeof *block, 1); - unsigned int align_log2 = ffs(bo_fake->alignment) - 1; - unsigned int sz; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + struct block *block = (struct block *)calloc(sizeof *block, 1); + unsigned int align_log2 = ffs(bo_fake->alignment) - 1; + unsigned int sz; - if (!block) - return 1; + if (!block) + return 1; - sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1); + sz = (bo->size + bo_fake->alignment - 1) & ~(bo_fake->alignment - 1); - block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0); - if (!block->mem) { - free(block); - return 0; - } + block->mem = mmAllocMem(bufmgr_fake->heap, sz, align_log2, 0); + if (!block->mem) { + free(block); + return 0; + } - DRMINITLISTHEAD(block); + DRMINITLISTHEAD(block); - /* Insert at head or at tail??? - */ - DRMLISTADDTAIL(block, &bufmgr_fake->lru); + /* Insert at head or at tail??? */ + DRMLISTADDTAIL(block, &bufmgr_fake->lru); - block->virtual = (uint8_t *)bufmgr_fake->virtual + - block->mem->ofs - bufmgr_fake->low_offset; - block->bo = bo; + block->virtual = (uint8_t *) bufmgr_fake->virtual + + block->mem->ofs - bufmgr_fake->low_offset; + block->bo = bo; - bo_fake->block = block; + bo_fake->block = block; - return 1; + return 1; } /* Release the card storage associated with buf: */ -static void free_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block, - int skip_dirty_copy) +static void +free_block(drm_intel_bufmgr_fake *bufmgr_fake, struct block *block, + int skip_dirty_copy) { - drm_intel_bo_fake *bo_fake; - DBG("free block %p %08x %d %d\n", block, block->mem->ofs, block->on_hardware, block->fenced); - - if (!block) - return; - - bo_fake = (drm_intel_bo_fake *)block->bo; - - if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)) - skip_dirty_copy = 1; - - if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) { - memcpy(bo_fake->backing_store, block->virtual, block->bo->size); - bo_fake->card_dirty = 0; - bo_fake->dirty = 1; - } - - if (block->on_hardware) { - block->bo = NULL; - } - else if (block->fenced) { - block->bo = NULL; - } - else { - DBG(" - free immediately\n"); - DRMLISTDEL(block); - - mmFreeMem(block->mem); - free(block); - } + drm_intel_bo_fake *bo_fake; + DBG("free block %p %08x %d %d\n", block, block->mem->ofs, + block->on_hardware, block->fenced); + + if (!block) + return; + + bo_fake = (drm_intel_bo_fake *) block->bo; + + if (bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE)) + skip_dirty_copy = 1; + + if (!skip_dirty_copy && (bo_fake->card_dirty == 1)) { + memcpy(bo_fake->backing_store, block->virtual, block->bo->size); + bo_fake->card_dirty = 0; + bo_fake->dirty = 1; + } + + if (block->on_hardware) { + block->bo = NULL; + } else if (block->fenced) { + block->bo = NULL; + } else { + DBG(" - free immediately\n"); + DRMLISTDEL(block); + + mmFreeMem(block->mem); + free(block); + } } static void alloc_backing_store(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - assert(!bo_fake->backing_store); - assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE))); + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + assert(!bo_fake->backing_store); + assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))); - bo_fake->backing_store = malloc(bo->size); + bo_fake->backing_store = malloc(bo->size); - DBG("alloc_backing - buf %d %p %d\n", bo_fake->id, bo_fake->backing_store, bo->size); - assert(bo_fake->backing_store); + DBG("alloc_backing - buf %d %p %d\n", bo_fake->id, + bo_fake->backing_store, bo->size); + assert(bo_fake->backing_store); } static void free_backing_store(drm_intel_bo *bo) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; - if (bo_fake->backing_store) { - assert(!(bo_fake->flags & (BM_PINNED|BM_NO_BACKING_STORE))); - free(bo_fake->backing_store); - bo_fake->backing_store = NULL; - } + if (bo_fake->backing_store) { + assert(!(bo_fake->flags & (BM_PINNED | BM_NO_BACKING_STORE))); + free(bo_fake->backing_store); + bo_fake->backing_store = NULL; + } } static void set_dirty(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; - if (bo_fake->flags & BM_NO_BACKING_STORE && bo_fake->invalidate_cb != NULL) - bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr); + if (bo_fake->flags & BM_NO_BACKING_STORE + && bo_fake->invalidate_cb != NULL) + bo_fake->invalidate_cb(bo, bo_fake->invalidate_ptr); - assert(!(bo_fake->flags & BM_PINNED)); + assert(!(bo_fake->flags & BM_PINNED)); - DBG("set_dirty - buf %d\n", bo_fake->id); - bo_fake->dirty = 1; + DBG("set_dirty - buf %d\n", bo_fake->id); + bo_fake->dirty = 1; } static int evict_lru(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int max_fence) { - struct block *block, *tmp; + struct block *block, *tmp; - DBG("%s\n", __FUNCTION__); + DBG("%s\n", __FUNCTION__); - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)block->bo; + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; - if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) - continue; + if (bo_fake != NULL && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) + continue; - if (block->fence && max_fence && !FENCE_LTE(block->fence, max_fence)) - return 0; + if (block->fence && max_fence && !FENCE_LTE(block->fence, + max_fence)) + return 0; - set_dirty(&bo_fake->bo); - bo_fake->block = NULL; + set_dirty(&bo_fake->bo); + bo_fake->block = NULL; - free_block(bufmgr_fake, block, 0); - return 1; - } + free_block(bufmgr_fake, block, 0); + return 1; + } - return 0; + return 0; } static int evict_mru(drm_intel_bufmgr_fake *bufmgr_fake) { - struct block *block, *tmp; + struct block *block, *tmp; - DBG("%s\n", __FUNCTION__); + DBG("%s\n", __FUNCTION__); - DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)block->bo; + DRMLISTFOREACHSAFEREVERSE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; - if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) - continue; + if (bo_fake && (bo_fake->flags & BM_NO_FENCE_SUBDATA)) + continue; - set_dirty(&bo_fake->bo); - bo_fake->block = NULL; + set_dirty(&bo_fake->bo); + bo_fake->block = NULL; - free_block(bufmgr_fake, block, 0); - return 1; - } + free_block(bufmgr_fake, block, 0); + return 1; + } - return 0; + return 0; } /** * Removes all objects from the fenced list older than the given fence. */ -static int clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, - unsigned int fence_cookie) +static int +clear_fenced(drm_intel_bufmgr_fake *bufmgr_fake, unsigned int fence_cookie) { - struct block *block, *tmp; - int ret = 0; - - bufmgr_fake->last_fence = fence_cookie; - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) { - assert(block->fenced); - - if (_fence_test(bufmgr_fake, block->fence)) { - - block->fenced = 0; - - if (!block->bo) { - DBG("delayed free: offset %x sz %x\n", - block->mem->ofs, block->mem->size); - DRMLISTDEL(block); - mmFreeMem(block->mem); - free(block); - } - else { - DBG("return to lru: offset %x sz %x\n", - block->mem->ofs, block->mem->size); - DRMLISTDEL(block); - DRMLISTADDTAIL(block, &bufmgr_fake->lru); - } - - ret = 1; - } - else { - /* Blocks are ordered by fence, so if one fails, all from - * here will fail also: - */ - DBG("fence not passed: offset %x sz %x %d %d \n", - block->mem->ofs, block->mem->size, block->fence, bufmgr_fake->last_fence); - break; - } - } - - DBG("%s: %d\n", __FUNCTION__, ret); - return ret; + struct block *block, *tmp; + int ret = 0; + + bufmgr_fake->last_fence = fence_cookie; + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->fenced) { + assert(block->fenced); + + if (_fence_test(bufmgr_fake, block->fence)) { + + block->fenced = 0; + + if (!block->bo) { + DBG("delayed free: offset %x sz %x\n", + block->mem->ofs, block->mem->size); + DRMLISTDEL(block); + mmFreeMem(block->mem); + free(block); + } else { + DBG("return to lru: offset %x sz %x\n", + block->mem->ofs, block->mem->size); + DRMLISTDEL(block); + DRMLISTADDTAIL(block, &bufmgr_fake->lru); + } + + ret = 1; + } else { + /* Blocks are ordered by fence, so if one fails, all + * from here will fail also: + */ + DBG("fence not passed: offset %x sz %x %d %d \n", + block->mem->ofs, block->mem->size, block->fence, + bufmgr_fake->last_fence); + break; + } + } + + DBG("%s: %d\n", __FUNCTION__, ret); + return ret; } -static void fence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) +static void +fence_blocks(drm_intel_bufmgr_fake *bufmgr_fake, unsigned fence) { - struct block *block, *tmp; + struct block *block, *tmp; - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { - DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n", block, - block->mem->size, block->mem->ofs, block->bo, fence); - block->fence = fence; + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { + DBG("Fence block %p (sz 0x%x ofs %x buf %p) with fence %d\n", + block, block->mem->size, block->mem->ofs, block->bo, fence); + block->fence = fence; - block->on_hardware = 0; - block->fenced = 1; + block->on_hardware = 0; + block->fenced = 1; - /* Move to tail of pending list here - */ - DRMLISTDEL(block); - DRMLISTADDTAIL(block, &bufmgr_fake->fenced); - } + /* Move to tail of pending list here + */ + DRMLISTDEL(block); + DRMLISTADDTAIL(block, &bufmgr_fake->fenced); + } - assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); } -static int evict_and_alloc_block(drm_intel_bo *bo) +static int +evict_and_alloc_block(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - - assert(bo_fake->block == NULL); - - /* Search for already free memory: - */ - if (alloc_block(bo)) - return 1; - - /* If we're not thrashing, allow lru eviction to dig deeper into - * recently used textures. We'll probably be thrashing soon: - */ - if (!bufmgr_fake->thrashing) { - while (evict_lru(bufmgr_fake, 0)) - if (alloc_block(bo)) - return 1; - } - - /* Keep thrashing counter alive? - */ - if (bufmgr_fake->thrashing) - bufmgr_fake->thrashing = 20; - - /* Wait on any already pending fences - here we are waiting for any - * freed memory that has been submitted to hardware and fenced to - * become available: - */ - while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) { - uint32_t fence = bufmgr_fake->fenced.next->fence; - _fence_wait_internal(bufmgr_fake, fence); - - if (alloc_block(bo)) - return 1; - } - - if (!DRMLISTEMPTY(&bufmgr_fake->on_hardware)) { - while (!DRMLISTEMPTY(&bufmgr_fake->fenced)) { - uint32_t fence = bufmgr_fake->fenced.next->fence; - _fence_wait_internal(bufmgr_fake, fence); - } - - if (!bufmgr_fake->thrashing) { - DBG("thrashing\n"); - } - bufmgr_fake->thrashing = 20; - - if (alloc_block(bo)) - return 1; - } - - while (evict_mru(bufmgr_fake)) - if (alloc_block(bo)) - return 1; - - DBG("%s 0x%x bytes failed\n", __FUNCTION__, bo->size); - - return 0; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + assert(bo_fake->block == NULL); + + /* Search for already free memory: + */ + if (alloc_block(bo)) + return 1; + + /* If we're not thrashing, allow lru eviction to dig deeper into + * recently used textures. We'll probably be thrashing soon: + */ + if (!bufmgr_fake->... [truncated message content] |