diff options
-rw-r--r-- | lib/libdrm/Makefile.inc | 2 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr.c | 216 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr.h | 135 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr_fake.c | 2374 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr_gem.c | 2280 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr_priv.h | 368 | ||||
-rw-r--r-- | lib/libdrm/intel/intel_chipset.h | 88 | ||||
-rw-r--r-- | lib/libdrm/intel/mm.c | 414 | ||||
-rw-r--r-- | lib/libdrm/intel/mm.h | 16 | ||||
-rw-r--r-- | lib/libdrm/intel/shlib_version | 2 | ||||
-rw-r--r-- | lib/libdrm/shlib_version | 2 | ||||
-rw-r--r-- | lib/libdrm/xf86drm.c | 46 | ||||
-rw-r--r-- | lib/libdrm/xf86drm.h | 3 | ||||
-rw-r--r-- | lib/libdrm/xf86drmMode.c | 3 | ||||
-rw-r--r-- | lib/libdrm/xf86drmSL.c | 3 |
15 files changed, 3360 insertions, 2592 deletions
diff --git a/lib/libdrm/Makefile.inc b/lib/libdrm/Makefile.inc index 4a9f8b171..c46ba2e82 100644 --- a/lib/libdrm/Makefile.inc +++ b/lib/libdrm/Makefile.inc @@ -1,2 +1,2 @@ -PACKAGE_VERSION= 2.4.9 +PACKAGE_VERSION= 2.4.15 diff --git a/lib/libdrm/intel/intel_bufmgr.c b/lib/libdrm/intel/intel_bufmgr.c index 25a6828ca..ce21a3323 100644 --- a/lib/libdrm/intel/intel_bufmgr.c +++ b/lib/libdrm/intel/intel_bufmgr.c @@ -44,124 +44,123 @@ * 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); +} + +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(bufmgr, name, size, alignment); + return bufmgr->bo_alloc_for_render(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_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_for_render(bufmgr, name, size, alignment); + return bufmgr->bo_alloc_tiled(bufmgr, name, x, y, cpp, + tiling_mode, pitch, flags); } -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; - - 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; + int ret; + + 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; } 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); - - 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; + int ret; + if (bo->bufmgr->bo_subdata) + return bo->bufmgr->bo_get_subdata(bo, offset, size, data); + + 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; } -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,41 +173,84 @@ drm_intel_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, read_domains, write_domain); } +/* For fence registers, not GL fences */ int -drm_intel_bo_pin(drm_intel_bo *bo, uint32_t alignment) +drm_intel_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + return bo->bufmgr->bo_emit_reloc_fence(bo, offset, + target_bo, target_offset, + read_domains, write_domain); +} + + +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; +} + +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); + + *tiling_mode = I915_TILING_NONE; + *swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + return 0; +} + +int drm_intel_bo_disable_reuse(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_disable_reuse) + return bo->bufmgr->bo_disable_reuse(bo); + return 0; +} + +int drm_intel_bo_busy(drm_intel_bo *bo) +{ + if (bo->bufmgr->bo_busy) + return bo->bufmgr->bo_busy(bo); + return 0; +} - *tiling_mode = I915_TILING_NONE; - return 0; +int drm_intel_bo_madvise(drm_intel_bo *bo, int madv) +{ + if (bo->bufmgr->bo_madvise) + return bo->bufmgr->bo_madvise(bo, madv); + return -1; } -int drm_intel_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode) +int drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) { - if (bo->bufmgr->bo_get_tiling) - return bo->bufmgr->bo_get_tiling(bo, tiling_mode, swizzle_mode); + return bo->bufmgr->bo_references(bo, target_bo); +} - *tiling_mode = I915_TILING_NONE; - *swizzle_mode = I915_BIT_6_SWIZZLE_NONE; - return 0; +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/lib/libdrm/intel/intel_bufmgr.h b/lib/libdrm/intel/intel_bufmgr.h index 542dc06fc..0984ab087 100644 --- a/lib/libdrm/intel/intel_bufmgr.h +++ b/lib/libdrm/intel/intel_bufmgr.h @@ -40,73 +40,93 @@ 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; + + /** + * 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; + + /** + * 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; }; +#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); 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_emit_reloc_fence(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_madvise(drm_intel_bo *bo, int madv); + +int drm_intel_bo_disable_reuse(drm_intel_bo *bo); +int drm_intel_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo); /* drm_intel_bufmgr_gem.c */ drm_intel_bufmgr *drm_intel_bufmgr_gem_init(int fd, int batch_size); @@ -114,35 +134,41 @@ drm_intel_bo *drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, const char *name, unsigned int handle); void drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr); +void drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr); int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo); int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo); void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable); +int drm_intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id); + /* drm_intel_bufmgr_fake.c */ 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); @@ -168,8 +194,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 @@ -190,4 +216,3 @@ void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr); /** @{ */ #endif /* INTEL_BUFMGR_H */ - diff --git a/lib/libdrm/intel/intel_bufmgr_fake.c b/lib/libdrm/intel/intel_bufmgr_fake.c index 5b045b0f6..e169d58bd 100644 --- a/lib/libdrm/intel/intel_bufmgr_fake.c +++ b/lib/libdrm/intel/intel_bufmgr_fake.c @@ -51,11 +51,14 @@ #include "mm.h" #include "libdrm_lists.h" -#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) +/* Support gcc's __FUNCTION__ for people using other compilers */ +#if !defined(__GNUC__) && !defined(__FUNCTION__) +# define __FUNCTION__ __func__ /* C99 */ +#endif #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 +75,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 +233,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 +425,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->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; } /*********************************************************************** @@ -709,10 +731,10 @@ static int evict_and_alloc_block(drm_intel_bo *bo) static void drm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake) { - unsigned int cookie; + unsigned int cookie; - cookie = _fence_emit_internal(bufmgr_fake); - _fence_wait_internal(bufmgr_fake, cookie); + cookie = _fence_emit_internal(bufmgr_fake); + _fence_wait_internal(bufmgr_fake, cookie); } /** @@ -724,23 +746,25 @@ drm_intel_bufmgr_fake_wait_idle(drm_intel_bufmgr_fake *bufmgr_fake) static void drm_intel_fake_bo_wait_rendering_locked(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->block == NULL || !bo_fake->block->fenced) - return; + if (bo_fake->block == NULL || !bo_fake->block->fenced) + return; - _fence_wait_internal(bufmgr_fake, bo_fake->block->fence); + _fence_wait_internal(bufmgr_fake, bo_fake->block->fence); } static void drm_intel_fake_bo_wait_rendering(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; - pthread_mutex_lock(&bufmgr_fake->lock); - drm_intel_fake_bo_wait_rendering_locked(bo); - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); + drm_intel_fake_bo_wait_rendering_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); } /* Specifically ignore texture memory sharing. @@ -750,188 +774,224 @@ drm_intel_fake_bo_wait_rendering(drm_intel_bo *bo) void drm_intel_bufmgr_fake_contended_lock_take(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; - struct block *block, *tmp; + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + struct block *block, *tmp; - pthread_mutex_lock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); - bufmgr_fake->need_fence = 1; - bufmgr_fake->fail = 0; + bufmgr_fake->need_fence = 1; + bufmgr_fake->fail = 0; - /* Wait for hardware idle. We don't know where acceleration has been - * happening, so we'll need to wait anyway before letting anything get - * put on the card again. - */ - drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + /* Wait for hardware idle. We don't know where acceleration has been + * happening, so we'll need to wait anyway before letting anything get + * put on the card again. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); - /* Check that we hadn't released the lock without having fenced the last - * set of buffers. - */ - assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); - assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); + /* Check that we hadn't released the lock without having fenced the last + * set of buffers. + */ + assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { - assert(_fence_test(bufmgr_fake, block->fence)); - set_dirty(block->bo); - } + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + assert(_fence_test(bufmgr_fake, block->fence)); + set_dirty(block->bo); + } - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_unlock(&bufmgr_fake->lock); } static drm_intel_bo * -drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment) +drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) { - drm_intel_bufmgr_fake *bufmgr_fake; - drm_intel_bo_fake *bo_fake; + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake; - bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; + bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; - assert(size != 0); + assert(size != 0); - bo_fake = calloc(1, sizeof(*bo_fake)); - if (!bo_fake) - return NULL; + bo_fake = calloc(1, sizeof(*bo_fake)); + if (!bo_fake) + return NULL; - bo_fake->bo.size = size; - bo_fake->bo.offset = -1; - bo_fake->bo.virtual = NULL; - bo_fake->bo.bufmgr = bufmgr; - bo_fake->refcount = 1; + bo_fake->bo.size = size; + bo_fake->bo.offset = -1; + bo_fake->bo.virtual = NULL; + bo_fake->bo.bufmgr = bufmgr; + bo_fake->refcount = 1; - /* Alignment must be a power of two */ - assert((alignment & (alignment - 1)) == 0); - if (alignment == 0) - alignment = 1; - bo_fake->alignment = alignment; - bo_fake->id = ++bufmgr_fake->buf_nr; - bo_fake->name = name; - bo_fake->flags = 0; - bo_fake->is_static = 0; + /* Alignment must be a power of two */ + assert((alignment & (alignment - 1)) == 0); + if (alignment == 0) + alignment = 1; + bo_fake->alignment = alignment; + bo_fake->id = ++bufmgr_fake->buf_nr; + bo_fake->name = name; + bo_fake->flags = 0; + bo_fake->is_static = 0; + + DBG("drm_bo_alloc: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, + bo_fake->bo.size / 1024); + + 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; - DBG("drm_bo_alloc: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, - bo_fake->bo.size / 1024); + /* Align it for being a render target. Shouldn't need anything else. */ + stride = x * cpp; + stride = ROUND_UP_TO(stride, 64); - return &bo_fake->bo; + /* 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, - unsigned long offset, unsigned long size, - void *virtual) +drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long offset, + unsigned long size, void *virtual) { - drm_intel_bufmgr_fake *bufmgr_fake; - drm_intel_bo_fake *bo_fake; + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake; - bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; + bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; - assert(size != 0); + assert(size != 0); - bo_fake = calloc(1, sizeof(*bo_fake)); - if (!bo_fake) - return NULL; + bo_fake = calloc(1, sizeof(*bo_fake)); + if (!bo_fake) + return NULL; - bo_fake->bo.size = size; - bo_fake->bo.offset = offset; - bo_fake->bo.virtual = virtual; - bo_fake->bo.bufmgr = bufmgr; - bo_fake->refcount = 1; - bo_fake->id = ++bufmgr_fake->buf_nr; - bo_fake->name = name; - bo_fake->flags = BM_PINNED; - bo_fake->is_static = 1; + bo_fake->bo.size = size; + bo_fake->bo.offset = offset; + bo_fake->bo.virtual = virtual; + bo_fake->bo.bufmgr = bufmgr; + bo_fake->refcount = 1; + bo_fake->id = ++bufmgr_fake->buf_nr; + bo_fake->name = name; + bo_fake->flags = BM_PINNED; + bo_fake->is_static = 1; - DBG("drm_bo_alloc_static: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, - bo_fake->bo.size / 1024); + DBG("drm_bo_alloc_static: (buf %d: %s, %d kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); - return &bo_fake->bo; + return &bo_fake->bo; } static void drm_intel_fake_bo_reference(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; - pthread_mutex_lock(&bufmgr_fake->lock); - bo_fake->refcount++; - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); + bo_fake->refcount++; + pthread_mutex_unlock(&bufmgr_fake->lock); } static void drm_intel_fake_bo_reference_locked(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; - bo_fake->refcount++; + bo_fake->refcount++; } static void drm_intel_fake_bo_unreference_locked(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; - int i; - - if (--bo_fake->refcount == 0) { - assert(bo_fake->map_count == 0); - /* No remaining references, so free it */ - if (bo_fake->block) - free_block(bufmgr_fake, bo_fake->block, 1); - free_backing_store(bo); - - for (i = 0; i < bo_fake->nr_relocs; i++) - drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i].target_buf); - - DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, bo_fake->name); - - free(bo_fake->relocs); - free(bo); - } + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; + + if (--bo_fake->refcount == 0) { + assert(bo_fake->map_count == 0); + /* No remaining references, so free it */ + if (bo_fake->block) + free_block(bufmgr_fake, bo_fake->block, 1); + free_backing_store(bo); + + for (i = 0; i < bo_fake->nr_relocs; i++) + drm_intel_fake_bo_unreference_locked(bo_fake->relocs[i]. + target_buf); + + DBG("drm_bo_unreference: free buf %d %s\n", bo_fake->id, + bo_fake->name); + + free(bo_fake->relocs); + free(bo); + } } static void drm_intel_fake_bo_unreference(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; - pthread_mutex_lock(&bufmgr_fake->lock); - drm_intel_fake_bo_unreference_locked(bo); - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); + drm_intel_fake_bo_unreference_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); } /** * Set the buffer as not requiring backing store, and instead get the callback * invoked whenever it would be set dirty. */ -void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, - void (*invalidate_cb)(drm_intel_bo *bo, - void *ptr), - void *ptr) +void +drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, + void (*invalidate_cb) (drm_intel_bo *bo, + void *ptr), + void *ptr) { - 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; - pthread_mutex_lock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); - if (bo_fake->backing_store) - free_backing_store(bo); + if (bo_fake->backing_store) + free_backing_store(bo); - bo_fake->flags |= BM_NO_BACKING_STORE; + bo_fake->flags |= BM_NO_BACKING_STORE; - DBG("disable_backing_store set buf %d dirty\n", bo_fake->id); - bo_fake->dirty = 1; - bo_fake->invalidate_cb = invalidate_cb; - bo_fake->invalidate_ptr = ptr; + DBG("disable_backing_store set buf %d dirty\n", bo_fake->id); + bo_fake->dirty = 1; + bo_fake->invalidate_cb = invalidate_cb; + bo_fake->invalidate_ptr = ptr; - /* Note that it is invalid right from the start. Also note - * invalidate_cb is called with the bufmgr locked, so cannot - * itself make bufmgr calls. - */ - if (invalidate_cb != NULL) - invalidate_cb(bo, ptr); + /* Note that it is invalid right from the start. Also note + * invalidate_cb is called with the bufmgr locked, so cannot + * itself make bufmgr calls. + */ + if (invalidate_cb != NULL) + invalidate_cb(bo, ptr); - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_unlock(&bufmgr_fake->lock); } /** @@ -939,236 +999,241 @@ void drm_intel_bo_fake_disable_backing_store(drm_intel_bo *bo, * BM_NO_BACKING_STORE or BM_PINNED) or backing store, as necessary. */ static int -drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable) + drm_intel_fake_bo_map_locked(drm_intel_bo *bo, int write_enable) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - - /* Static buffers are always mapped. */ - if (bo_fake->is_static) { - if (bo_fake->card_dirty) { - drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); - bo_fake->card_dirty = 0; - } - return 0; - } - - /* Allow recursive mapping. Mesa may recursively map buffers with - * nested display loops, and it is used internally in bufmgr_fake - * for relocation. - */ - if (bo_fake->map_count++ != 0) - return 0; - - { - DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, - bo_fake->bo.size / 1024); - - if (bo->virtual != NULL) { - drmMsg("%s: already mapped\n", __FUNCTION__); - abort(); - } - else if (bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED)) { - - if (!bo_fake->block && !evict_and_alloc_block(bo)) { - DBG("%s: alloc failed\n", __FUNCTION__); - bufmgr_fake->fail = 1; - return 1; - } - else { - assert(bo_fake->block); - bo_fake->dirty = 0; - - if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) && - bo_fake->block->fenced) { - drm_intel_fake_bo_wait_rendering_locked(bo); - } - - bo->virtual = bo_fake->block->virtual; - } - } - else { - if (write_enable) - set_dirty(bo); - - if (bo_fake->backing_store == 0) - alloc_backing_store(bo); - - if ((bo_fake->card_dirty == 1) && bo_fake->block) { - if (bo_fake->block->fenced) - drm_intel_fake_bo_wait_rendering_locked(bo); - - memcpy(bo_fake->backing_store, bo_fake->block->virtual, bo_fake->block->bo->size); - bo_fake->card_dirty = 0; - } - - bo->virtual = bo_fake->backing_store; - } - } - - 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; + + /* Static buffers are always mapped. */ + if (bo_fake->is_static) { + if (bo_fake->card_dirty) { + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + bo_fake->card_dirty = 0; + } + return 0; + } + + /* Allow recursive mapping. Mesa may recursively map buffers with + * nested display loops, and it is used internally in bufmgr_fake + * for relocation. + */ + if (bo_fake->map_count++ != 0) + return 0; + + { + DBG("drm_bo_map: (buf %d: %s, %d kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); + + if (bo->virtual != NULL) { + drmMsg("%s: already mapped\n", __FUNCTION__); + abort(); + } else if (bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED)) { + + if (!bo_fake->block && !evict_and_alloc_block(bo)) { + DBG("%s: alloc failed\n", __FUNCTION__); + bufmgr_fake->fail = 1; + return 1; + } else { + assert(bo_fake->block); + bo_fake->dirty = 0; + + if (!(bo_fake->flags & BM_NO_FENCE_SUBDATA) && + bo_fake->block->fenced) { + drm_intel_fake_bo_wait_rendering_locked + (bo); + } + + bo->virtual = bo_fake->block->virtual; + } + } else { + if (write_enable) + set_dirty(bo); + + if (bo_fake->backing_store == 0) + alloc_backing_store(bo); + + if ((bo_fake->card_dirty == 1) && bo_fake->block) { + if (bo_fake->block->fenced) + drm_intel_fake_bo_wait_rendering_locked + (bo); + + memcpy(bo_fake->backing_store, + bo_fake->block->virtual, + bo_fake->block->bo->size); + bo_fake->card_dirty = 0; + } + + bo->virtual = bo_fake->backing_store; + } + } + + return 0; } static int -drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable) + drm_intel_fake_bo_map(drm_intel_bo *bo, int write_enable) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - int ret; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + int ret; - pthread_mutex_lock(&bufmgr_fake->lock); - ret = drm_intel_fake_bo_map_locked(bo, write_enable); - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); + ret = drm_intel_fake_bo_map_locked(bo, write_enable); + pthread_mutex_unlock(&bufmgr_fake->lock); - return ret; + return ret; } static int -drm_intel_fake_bo_unmap_locked(drm_intel_bo *bo) + drm_intel_fake_bo_unmap_locked(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; - /* Static buffers are always mapped. */ - if (bo_fake->is_static) - return 0; + /* Static buffers are always mapped. */ + if (bo_fake->is_static) + return 0; - assert(bo_fake->map_count != 0); - if (--bo_fake->map_count != 0) - return 0; + assert(bo_fake->map_count != 0); + if (--bo_fake->map_count != 0) + return 0; - DBG("drm_bo_unmap: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, - bo_fake->bo.size / 1024); + DBG("drm_bo_unmap: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, + bo_fake->bo.size / 1024); - bo->virtual = NULL; + bo->virtual = NULL; - return 0; + return 0; } -static int -drm_intel_fake_bo_unmap(drm_intel_bo *bo) +static int drm_intel_fake_bo_unmap(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - int ret; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + int ret; - pthread_mutex_lock(&bufmgr_fake->lock); - ret = drm_intel_fake_bo_unmap_locked(bo); - pthread_mutex_unlock(&bufmgr_fake->lock); + pthread_mutex_lock(&bufmgr_fake->lock); + ret = drm_intel_fake_bo_unmap_locked(bo); + pthread_mutex_unlock(&bufmgr_fake->lock); - return ret; + return ret; } static void -drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake) + drm_intel_fake_kick_all_locked(drm_intel_bufmgr_fake *bufmgr_fake) { - struct block *block, *tmp; - - bufmgr_fake->performed_rendering = 0; - /* okay for ever BO that is on the HW kick it off. - seriously not afraid of the POLICE right now */ - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)block->bo; - - block->on_hardware = 0; - free_block(bufmgr_fake, block, 0); - bo_fake->block = NULL; - bo_fake->validated = 0; - if (!(bo_fake->flags & BM_NO_BACKING_STORE)) - bo_fake->dirty = 1; - } + struct block *block, *tmp; + + bufmgr_fake->performed_rendering = 0; + /* okay for ever BO that is on the HW kick it off. + seriously not afraid of the POLICE right now */ + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->on_hardware) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + + block->on_hardware = 0; + free_block(bufmgr_fake, block, 0); + bo_fake->block = NULL; + bo_fake->validated = 0; + if (!(bo_fake->flags & BM_NO_BACKING_STORE)) + bo_fake->dirty = 1; + } } static int -drm_intel_fake_bo_validate(drm_intel_bo *bo) + drm_intel_fake_bo_validate(drm_intel_bo *bo) { - drm_intel_bufmgr_fake *bufmgr_fake; - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - - bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - - DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id, bo_fake->name, - bo_fake->bo.size / 1024); - - /* Sanity check: Buffers should be unmapped before being validated. - * This is not so much of a problem for bufmgr_fake, but TTM refuses, - * and the problem is harder to debug there. - */ - assert(bo_fake->map_count == 0); - - if (bo_fake->is_static) { - /* Add it to the needs-fence list */ - bufmgr_fake->need_fence = 1; - return 0; - } - - /* Allocate the card memory */ - if (!bo_fake->block && !evict_and_alloc_block(bo)) { - bufmgr_fake->fail = 1; - DBG("Failed to validate buf %d:%s\n", bo_fake->id, bo_fake->name); - return -1; - } - - assert(bo_fake->block); - assert(bo_fake->block->bo == &bo_fake->bo); - - bo->offset = bo_fake->block->mem->ofs; - - /* Upload the buffer contents if necessary */ - if (bo_fake->dirty) { - DBG("Upload dirty buf %d:%s, sz %d offset 0x%x\n", bo_fake->id, - bo_fake->name, bo->size, bo_fake->block->mem->ofs); - - assert(!(bo_fake->flags & - (BM_NO_BACKING_STORE|BM_PINNED))); - - /* Actually, should be able to just wait for a fence on the memory, - * which we would be tracking when we free it. Waiting for idle is - * a sufficiently large hammer for now. - */ - drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); - - /* we may never have mapped this BO so it might not have any backing - * store if this happens it should be rare, but 0 the card memory - * in any case */ - if (bo_fake->backing_store) - memcpy(bo_fake->block->virtual, bo_fake->backing_store, bo->size); - else - memset(bo_fake->block->virtual, 0, bo->size); - - bo_fake->dirty = 0; - } - - bo_fake->block->fenced = 0; - bo_fake->block->on_hardware = 1; - DRMLISTDEL(bo_fake->block); - DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware); - - bo_fake->validated = 1; - bufmgr_fake->need_fence = 1; - - return 0; + drm_intel_bufmgr_fake *bufmgr_fake; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + + bufmgr_fake = (drm_intel_bufmgr_fake *) bo->bufmgr; + + DBG("drm_bo_validate: (buf %d: %s, %d kb)\n", bo_fake->id, + bo_fake->name, bo_fake->bo.size / 1024); + + /* Sanity check: Buffers should be unmapped before being validated. + * This is not so much of a problem for bufmgr_fake, but TTM refuses, + * and the problem is harder to debug there. + */ + assert(bo_fake->map_count == 0); + + if (bo_fake->is_static) { + /* Add it to the needs-fence list */ + bufmgr_fake->need_fence = 1; + return 0; + } + + /* Allocate the card memory */ + if (!bo_fake->block && !evict_and_alloc_block(bo)) { + bufmgr_fake->fail = 1; + DBG("Failed to validate buf %d:%s\n", bo_fake->id, + bo_fake->name); + return -1; + } + + assert(bo_fake->block); + assert(bo_fake->block->bo == &bo_fake->bo); + + bo->offset = bo_fake->block->mem->ofs; + + /* Upload the buffer contents if necessary */ + if (bo_fake->dirty) { + DBG("Upload dirty buf %d:%s, sz %d offset 0x%x\n", bo_fake->id, + bo_fake->name, bo->size, bo_fake->block->mem->ofs); + + assert(!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))); + + /* Actually, should be able to just wait for a fence on the + * mmory, hich we would be tracking when we free it. Waiting + * for idle is a sufficiently large hammer for now. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + + /* we may never have mapped this BO so it might not have any + * backing store if this happens it should be rare, but 0 the + * card memory in any case */ + if (bo_fake->backing_store) + memcpy(bo_fake->block->virtual, bo_fake->backing_store, + bo->size); + else + memset(bo_fake->block->virtual, 0, bo->size); + + bo_fake->dirty = 0; + } + + bo_fake->block->fenced = 0; + bo_fake->block->on_hardware = 1; + DRMLISTDEL(bo_fake->block); + DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware); + + bo_fake->validated = 1; + bufmgr_fake->need_fence = 1; + + return 0; } static void drm_intel_fake_fence_validated(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; - unsigned int cookie; + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + unsigned int cookie; - cookie = _fence_emit_internal(bufmgr_fake); - fence_blocks(bufmgr_fake, cookie); + cookie = _fence_emit_internal(bufmgr_fake); + fence_blocks(bufmgr_fake, cookie); - DBG("drm_fence_validated: 0x%08x cookie\n", cookie); + DBG("drm_fence_validated: 0x%08x cookie\n", cookie); } static void drm_intel_fake_destroy(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; - pthread_mutex_destroy(&bufmgr_fake->lock); - mmDestroy(bufmgr_fake->heap); - free(bufmgr); + pthread_mutex_destroy(&bufmgr_fake->lock); + mmDestroy(bufmgr_fake->heap); + free(bufmgr); } static int @@ -1176,48 +1241,89 @@ drm_intel_fake_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) { + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + struct fake_buffer_reloc *r; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *) target_bo; + int i; + + pthread_mutex_lock(&bufmgr_fake->lock); + + assert(bo); + assert(target_bo); + + if (bo_fake->relocs == NULL) { + bo_fake->relocs = + malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS); + } + + r = &bo_fake->relocs[bo_fake->nr_relocs++]; + + assert(bo_fake->nr_relocs <= MAX_RELOCS); + + drm_intel_fake_bo_reference_locked(target_bo); + + if (!target_fake->is_static) { + bo_fake->child_size += + ALIGN(target_bo->size, target_fake->alignment); + bo_fake->child_size += target_fake->child_size; + } + r->target_buf = target_bo; + r->offset = offset; + r->last_target_offset = target_bo->offset; + r->delta = target_offset; + r->read_domains = read_domains; + r->write_domain = write_domain; + + if (bufmgr_fake->debug) { + /* Check that a conflicting relocation hasn't already been + * emitted. + */ + for (i = 0; i < bo_fake->nr_relocs - 1; i++) { + struct fake_buffer_reloc *r2 = &bo_fake->relocs[i]; + + assert(r->offset != r2->offset); + } + } + + pthread_mutex_unlock(&bufmgr_fake->lock); + + return 0; +} + +static int +drm_intel_fake_pin(drm_intel_bo *bo, uint32_t alignment) +{ drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - struct fake_buffer_reloc *r; drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *)target_bo; - int i; - pthread_mutex_lock(&bufmgr_fake->lock); - - assert(bo); - assert(target_bo); - - if (bo_fake->relocs == NULL) { - bo_fake->relocs = malloc(sizeof(struct fake_buffer_reloc) * MAX_RELOCS); - } - - r = &bo_fake->relocs[bo_fake->nr_relocs++]; + assert(bo_fake->is_static == 0); - assert(bo_fake->nr_relocs <= MAX_RELOCS); + bo_fake->alignment = alignment; + if (drm_intel_fake_bo_validate(bo) == -1) + return ENOMEM; - drm_intel_fake_bo_reference_locked(target_bo); + bo_fake->is_static = 1; + bo->virtual = bo_fake->block->virtual; + /* we should be on the on_hardware list, take us off for now */ + DRMLISTDEL(bo_fake->block); - if (!target_fake->is_static) { - bo_fake->child_size += ALIGN(target_bo->size, target_fake->alignment); - bo_fake->child_size += target_fake->child_size; - } - r->target_buf = target_bo; - r->offset = offset; - r->last_target_offset = target_bo->offset; - r->delta = target_offset; - r->read_domains = read_domains; - r->write_domain = write_domain; + return 0; +} - if (bufmgr_fake->debug) { - /* Check that a conflicting relocation hasn't already been emitted. */ - for (i = 0; i < bo_fake->nr_relocs - 1; i++) { - struct fake_buffer_reloc *r2 = &bo_fake->relocs[i]; +static int +drm_intel_fake_unpin(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(r->offset != r2->offset); - } - } + assert(bo_fake->is_static); - pthread_mutex_unlock(&bufmgr_fake->lock); + bo_fake->is_static = 0; + bo->virtual = NULL; + DRMLISTDEL(bo_fake->block); + DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware); return 0; } @@ -1229,211 +1335,183 @@ drm_intel_fake_emit_reloc(drm_intel_bo *bo, uint32_t offset, static void drm_intel_fake_calculate_domains(drm_intel_bo *bo) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo; - int i; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; - for (i = 0; i < bo_fake->nr_relocs; i++) { - struct fake_buffer_reloc *r = &bo_fake->relocs[i]; - drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *)r->target_buf; + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; - /* Do the same for the tree of buffers we depend on */ - drm_intel_fake_calculate_domains(r->target_buf); + /* Do the same for the tree of buffers we depend on */ + drm_intel_fake_calculate_domains(r->target_buf); - target_fake->read_domains |= r->read_domains; - target_fake->write_domain |= r->write_domain; - } + target_fake->read_domains |= r->read_domains; + target_fake->write_domain |= r->write_domain; + } } - static int drm_intel_fake_reloc_and_validate_buffer(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; - int i, ret; - - assert(bo_fake->map_count == 0); - - for (i = 0; i < bo_fake->nr_relocs; i++) { - struct fake_buffer_reloc *r = &bo_fake->relocs[i]; - drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *)r->target_buf; - uint32_t reloc_data; - - /* Validate the target buffer if that hasn't been done. */ - if (!target_fake->validated) { - ret = drm_intel_fake_reloc_and_validate_buffer(r->target_buf); - if (ret != 0) { - if (bo->virtual != NULL) - drm_intel_fake_bo_unmap_locked(bo); - return ret; - } - } - - /* Calculate the value of the relocation entry. */ - if (r->target_buf->offset != r->last_target_offset) { - reloc_data = r->target_buf->offset + r->delta; - - if (bo->virtual == NULL) - drm_intel_fake_bo_map_locked(bo, 1); - - *(uint32_t *)((uint8_t *)bo->virtual + r->offset) = reloc_data; - - r->last_target_offset = r->target_buf->offset; - } - } - - if (bo->virtual != NULL) - drm_intel_fake_bo_unmap_locked(bo); - - if (bo_fake->write_domain != 0) { - if (!(bo_fake->flags & (BM_NO_BACKING_STORE|BM_PINNED))) { - if (bo_fake->backing_store == 0) - alloc_backing_store(bo); - } - bo_fake->card_dirty = 1; - bufmgr_fake->performed_rendering = 1; - } - - return drm_intel_fake_bo_validate(bo); + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i, ret; + + assert(bo_fake->map_count == 0); + + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; + uint32_t reloc_data; + + /* Validate the target buffer if that hasn't been done. */ + if (!target_fake->validated) { + ret = + drm_intel_fake_reloc_and_validate_buffer(r->target_buf); + if (ret != 0) { + if (bo->virtual != NULL) + drm_intel_fake_bo_unmap_locked(bo); + return ret; + } + } + + /* Calculate the value of the relocation entry. */ + if (r->target_buf->offset != r->last_target_offset) { + reloc_data = r->target_buf->offset + r->delta; + + if (bo->virtual == NULL) + drm_intel_fake_bo_map_locked(bo, 1); + + *(uint32_t *) ((uint8_t *) bo->virtual + r->offset) = + reloc_data; + + r->last_target_offset = r->target_buf->offset; + } + } + + if (bo->virtual != NULL) + drm_intel_fake_bo_unmap_locked(bo); + + if (bo_fake->write_domain != 0) { + if (!(bo_fake->flags & (BM_NO_BACKING_STORE | BM_PINNED))) { + if (bo_fake->backing_store == 0) + alloc_backing_store(bo); + } + bo_fake->card_dirty = 1; + bufmgr_fake->performed_rendering = 1; + } + + return drm_intel_fake_bo_validate(bo); } static void drm_intel_bo_fake_post_submit(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; - int i; - - for (i = 0; i < bo_fake->nr_relocs; i++) { - struct fake_buffer_reloc *r = &bo_fake->relocs[i]; - drm_intel_bo_fake *target_fake = (drm_intel_bo_fake *)r->target_buf; - - if (target_fake->validated) - drm_intel_bo_fake_post_submit(r->target_buf); - - DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n", - bo_fake->name, (uint32_t)bo->offset, r->offset, - target_fake->name, (uint32_t)r->target_buf->offset, r->delta); - } - - assert(bo_fake->map_count == 0); - bo_fake->validated = 0; - bo_fake->read_domains = 0; - bo_fake->write_domain = 0; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo; + int i; + + for (i = 0; i < bo_fake->nr_relocs; i++) { + struct fake_buffer_reloc *r = &bo_fake->relocs[i]; + drm_intel_bo_fake *target_fake = + (drm_intel_bo_fake *) r->target_buf; + + if (target_fake->validated) + drm_intel_bo_fake_post_submit(r->target_buf); + + DBG("%s@0x%08x + 0x%08x -> %s@0x%08x + 0x%08x\n", + bo_fake->name, (uint32_t) bo->offset, r->offset, + target_fake->name, (uint32_t) r->target_buf->offset, + r->delta); + } + + assert(bo_fake->map_count == 0); + bo_fake->validated = 0; + bo_fake->read_domains = 0; + bo_fake->write_domain = 0; } - -void drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr, - int (*exec)(drm_intel_bo *bo, - unsigned int used, - void *priv), +void +drm_intel_bufmgr_fake_set_exec_callback(drm_intel_bufmgr *bufmgr, + int (*exec) (drm_intel_bo *bo, + unsigned int used, + 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->exec = exec; - bufmgr_fake->exec_priv = priv; + bufmgr_fake->exec = exec; + bufmgr_fake->exec_priv = priv; } static int drm_intel_fake_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) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo->bufmgr; - drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *)bo; - struct drm_i915_batchbuffer batch; - int ret; - int retry_count = 0; - - pthread_mutex_lock(&bufmgr_fake->lock); - - bufmgr_fake->performed_rendering = 0; - - drm_intel_fake_calculate_domains(bo); - - batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; - - /* we've ran out of RAM so blow the whole lot away and retry */ - restart: - ret = drm_intel_fake_reloc_and_validate_buffer(bo); - if (bufmgr_fake->fail == 1) { - if (retry_count == 0) { - retry_count++; - drm_intel_fake_kick_all_locked(bufmgr_fake); - bufmgr_fake->fail = 0; - goto restart; - } else /* dump out the memory here */ - mmDumpMemInfo(bufmgr_fake->heap); - } - - assert(ret == 0); - - if (bufmgr_fake->exec != NULL) { - int ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv); - if (ret != 0) { - pthread_mutex_unlock(&bufmgr_fake->lock); - return ret; - } - } else { - batch.start = bo->offset; - batch.used = used; - batch.cliprects = cliprects; - batch.num_cliprects = num_cliprects; - batch.DR1 = 0; - batch.DR4 = DR4; - - if (drmCommandWrite(bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch, - sizeof(batch))) { - drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno); - pthread_mutex_unlock(&bufmgr_fake->lock); - return -errno; - } - } - - drm_intel_fake_fence_validated(bo->bufmgr); - - drm_intel_bo_fake_post_submit(bo); - - pthread_mutex_unlock(&bufmgr_fake->lock); - - return 0; -} - -static int -drm_intel_fake_pin(drm_intel_bo *bo, uint32_t alignment) -{ - 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->is_static == 0); - - bo_fake->alignment = alignment; - if (drm_intel_fake_bo_validate(bo) == -1) - return ENOMEM; - - bo_fake->is_static = 1; - bo->virtual = bo_fake->block->virtual; - /* we should be on the on_hardware list, take us off for now */ - DRMLISTDEL(bo_fake->block); - - return 0; -} - -static int -drm_intel_fake_unpin(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->is_static); - - bo_fake->is_static = 0; - bo->virtual = NULL; - DRMLISTDEL(bo_fake->block); - DRMLISTADDTAIL(bo_fake->block, &bufmgr_fake->on_hardware); - - return 0; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo->bufmgr; + drm_intel_bo_fake *batch_fake = (drm_intel_bo_fake *) bo; + struct drm_i915_batchbuffer batch; + int ret; + int retry_count = 0; + + pthread_mutex_lock(&bufmgr_fake->lock); + + bufmgr_fake->performed_rendering = 0; + + drm_intel_fake_calculate_domains(bo); + + batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; + + /* we've ran out of RAM so blow the whole lot away and retry */ +restart: + ret = drm_intel_fake_reloc_and_validate_buffer(bo); + if (bufmgr_fake->fail == 1) { + if (retry_count == 0) { + retry_count++; + drm_intel_fake_kick_all_locked(bufmgr_fake); + bufmgr_fake->fail = 0; + goto restart; + } else /* dump out the memory here */ + mmDumpMemInfo(bufmgr_fake->heap); + } + + assert(ret == 0); + + if (bufmgr_fake->exec != NULL) { + int ret = bufmgr_fake->exec(bo, used, bufmgr_fake->exec_priv); + if (ret != 0) { + pthread_mutex_unlock(&bufmgr_fake->lock); + return ret; + } + } else { + batch.start = bo->offset; + batch.used = used; + batch.cliprects = cliprects; + batch.num_cliprects = num_cliprects; + batch.DR1 = 0; + batch.DR4 = DR4; + + if (drmCommandWrite + (bufmgr_fake->fd, DRM_I915_BATCHBUFFER, &batch, + sizeof(batch))) { + drmMsg("DRM_I915_BATCHBUFFER: %d\n", -errno); + pthread_mutex_unlock(&bufmgr_fake->lock); + return -errno; + } + } + + drm_intel_fake_fence_validated(bo->bufmgr); + + drm_intel_bo_fake_post_submit(bo); + + pthread_mutex_unlock(&bufmgr_fake->lock); + + return 0; } /** @@ -1444,32 +1522,33 @@ drm_intel_fake_unpin(drm_intel_bo *bo) * a set smaller than the aperture. */ static int -drm_intel_fake_check_aperture_space(drm_intel_bo **bo_array, int count) +drm_intel_fake_check_aperture_space(drm_intel_bo ** bo_array, int count) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bo_array[0]->bufmgr; - unsigned int sz = 0; - int i; - - for (i = 0; i < count; i++) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)bo_array[i]; - - if (bo_fake == NULL) - continue; - - if (!bo_fake->is_static) - sz += ALIGN(bo_array[i]->size, bo_fake->alignment); - sz += bo_fake->child_size; - } - - if (sz > bufmgr_fake->size) { - DBG("check_space: overflowed bufmgr size, %dkb vs %dkb\n", - sz / 1024, bufmgr_fake->size / 1024); - return -1; - } - - DBG("drm_check_space: sz %dkb vs bufgr %dkb\n", sz / 1024 , - bufmgr_fake->size / 1024); - return 0; + drm_intel_bufmgr_fake *bufmgr_fake = + (drm_intel_bufmgr_fake *) bo_array[0]->bufmgr; + unsigned int sz = 0; + int i; + + for (i = 0; i < count; i++) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) bo_array[i]; + + if (bo_fake == NULL) + continue; + + if (!bo_fake->is_static) + sz += ALIGN(bo_array[i]->size, bo_fake->alignment); + sz += bo_fake->child_size; + } + + if (sz > bufmgr_fake->size) { + DBG("check_space: overflowed bufmgr size, %dkb vs %dkb\n", + sz / 1024, bufmgr_fake->size / 1024); + return -1; + } + + DBG("drm_check_space: sz %dkb vs bufgr %dkb\n", sz / 1024, + bufmgr_fake->size / 1024); + return 0; } /** @@ -1479,90 +1558,97 @@ drm_intel_fake_check_aperture_space(drm_intel_bo **bo_array, int count) * Used by the X Server on LeaveVT, when the card memory is no longer our * own. */ -void -drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr) +void drm_intel_bufmgr_fake_evict_all(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; - struct block *block, *tmp; - - pthread_mutex_lock(&bufmgr_fake->lock); - - bufmgr_fake->need_fence = 1; - bufmgr_fake->fail = 0; - - /* Wait for hardware idle. We don't know where acceleration has been - * happening, so we'll need to wait anyway before letting anything get - * put on the card again. - */ - drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); - - /* Check that we hadn't released the lock without having fenced the last - * set of buffers. - */ - assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); - assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); - - DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { - drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *)block->bo; - /* Releases the memory, and memcpys dirty contents out if necessary. */ - free_block(bufmgr_fake, block, 0); - bo_fake->block = NULL; - } - - pthread_mutex_unlock(&bufmgr_fake->lock); + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; + struct block *block, *tmp; + + pthread_mutex_lock(&bufmgr_fake->lock); + + bufmgr_fake->need_fence = 1; + bufmgr_fake->fail = 0; + + /* Wait for hardware idle. We don't know where acceleration has been + * happening, so we'll need to wait anyway before letting anything get + * put on the card again. + */ + drm_intel_bufmgr_fake_wait_idle(bufmgr_fake); + + /* Check that we hadn't released the lock without having fenced the last + * set of buffers. + */ + assert(DRMLISTEMPTY(&bufmgr_fake->fenced)); + assert(DRMLISTEMPTY(&bufmgr_fake->on_hardware)); + + DRMLISTFOREACHSAFE(block, tmp, &bufmgr_fake->lru) { + drm_intel_bo_fake *bo_fake = (drm_intel_bo_fake *) block->bo; + /* Releases the memory, and memcpys dirty contents out if + * necessary. + */ + free_block(bufmgr_fake, block, 0); + bo_fake->block = NULL; + } + + pthread_mutex_unlock(&bufmgr_fake->lock); } + void drm_intel_bufmgr_fake_set_last_dispatch(drm_intel_bufmgr *bufmgr, - volatile unsigned int *last_dispatch) + volatile unsigned int + *last_dispatch) { - drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *)bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake = (drm_intel_bufmgr_fake *) bufmgr; - bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; } -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) +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) { - drm_intel_bufmgr_fake *bufmgr_fake; - - bufmgr_fake = calloc(1, sizeof(*bufmgr_fake)); - - if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) { - free(bufmgr_fake); - return NULL; - } - - /* Initialize allocator */ - DRMINITLISTHEAD(&bufmgr_fake->fenced); - DRMINITLISTHEAD(&bufmgr_fake->on_hardware); - DRMINITLISTHEAD(&bufmgr_fake->lru); - - bufmgr_fake->low_offset = low_offset; - bufmgr_fake->virtual = low_virtual; - bufmgr_fake->size = size; - bufmgr_fake->heap = mmInit(low_offset, size); - - /* 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_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; - bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap; - bufmgr_fake->bufmgr.bo_wait_rendering = drm_intel_fake_bo_wait_rendering; - bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc; - bufmgr_fake->bufmgr.bo_pin = drm_intel_fake_pin; - bufmgr_fake->bufmgr.bo_unpin = drm_intel_fake_unpin; - bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy; - bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec; - bufmgr_fake->bufmgr.check_aperture_space = drm_intel_fake_check_aperture_space; - bufmgr_fake->bufmgr.debug = 0; - - bufmgr_fake->fd = fd; - bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; - - return &bufmgr_fake->bufmgr; + drm_intel_bufmgr_fake *bufmgr_fake; + + bufmgr_fake = calloc(1, sizeof(*bufmgr_fake)); + + if (pthread_mutex_init(&bufmgr_fake->lock, NULL) != 0) { + free(bufmgr_fake); + return NULL; + } + + /* Initialize allocator */ + DRMINITLISTHEAD(&bufmgr_fake->fenced); + DRMINITLISTHEAD(&bufmgr_fake->on_hardware); + DRMINITLISTHEAD(&bufmgr_fake->lru); + + bufmgr_fake->low_offset = low_offset; + bufmgr_fake->virtual = low_virtual; + bufmgr_fake->size = size; + bufmgr_fake->heap = mmInit(low_offset, size); + + /* 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; + bufmgr_fake->bufmgr.bo_unmap = drm_intel_fake_bo_unmap; + bufmgr_fake->bufmgr.bo_wait_rendering = + drm_intel_fake_bo_wait_rendering; + bufmgr_fake->bufmgr.bo_emit_reloc = drm_intel_fake_emit_reloc; + bufmgr_fake->bufmgr.bo_pin = drm_intel_fake_pin; + bufmgr_fake->bufmgr.bo_unpin = drm_intel_fake_unpin; + + bufmgr_fake->bufmgr.destroy = drm_intel_fake_destroy; + bufmgr_fake->bufmgr.bo_exec = drm_intel_fake_bo_exec; + bufmgr_fake->bufmgr.check_aperture_space = + drm_intel_fake_check_aperture_space; + bufmgr_fake->bufmgr.debug = 0; + + bufmgr_fake->fd = fd; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; + + return &bufmgr_fake->bufmgr; } - diff --git a/lib/libdrm/intel/intel_bufmgr_gem.c b/lib/libdrm/intel/intel_bufmgr_gem.c index ea8f21c44..fdc03cf31 100644 --- a/lib/libdrm/intel/intel_bufmgr_gem.c +++ b/lib/libdrm/intel/intel_bufmgr_gem.c @@ -53,6 +53,9 @@ #include "errno.h" #include "libdrm_lists.h" +#if 0 +#include "intel_atomic.h" +#endif #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" #include "intel_chipset.h" @@ -61,187 +64,282 @@ #include "i915_drm.h" #define DBG(...) do { \ - if (bufmgr_gem->bufmgr.debug) \ - fprintf(stderr, __VA_ARGS__); \ + if (bufmgr_gem->bufmgr.debug) \ + fprintf(stderr, __VA_ARGS__); \ } while (0) typedef struct _drm_intel_bo_gem drm_intel_bo_gem; struct drm_intel_gem_bo_bucket { - drmMMListHead head; - - /** - * Limit on the number of entries in this bucket. - * - * 0 means that this caching at this bucket size is disabled. - * -1 means that there is no limit to caching at this size. - */ - int max_entries; - int num_entries; - unsigned long size; + drmMMListHead head; + unsigned long size; }; /* Only cache objects up to 64MB. Bigger than that, and the rounding of the - * size makes many operation fail that wouldn't otherwise. + * size makes many operations fail that wouldn't otherwise. */ #define DRM_INTEL_GEM_BO_BUCKETS 14 typedef struct _drm_intel_bufmgr_gem { - drm_intel_bufmgr bufmgr; + drm_intel_bufmgr bufmgr; - int fd; + int fd; - int max_relocs; + int max_relocs; - pthread_mutex_t lock; + pthread_mutex_t lock; - struct drm_i915_gem_exec_object *exec_objects; - drm_intel_bo **exec_bos; - int exec_size; - int exec_count; + struct drm_i915_gem_exec_object2 *exec2_objects; + drm_intel_bo **exec_bos; + int exec_size; + int exec_count; - /** Array of lists of cached gem objects of power-of-two sizes */ - struct drm_intel_gem_bo_bucket cache_bucket[DRM_INTEL_GEM_BO_BUCKETS]; + /** Array of lists of cached gem objects of power-of-two sizes */ + struct drm_intel_gem_bo_bucket cache_bucket[DRM_INTEL_GEM_BO_BUCKETS]; - uint64_t gtt_size; - int available_fences; - int pci_device; + uint64_t gtt_size; + int available_fences; + int pci_device; + int gen; + char bo_reuse; + char fenced_relocs; } drm_intel_bufmgr_gem; +#define DRM_INTEL_RELOC_FENCE (1<<0) + +typedef struct _drm_intel_reloc_target_info { + drm_intel_bo *bo; + int flags; +} drm_intel_reloc_target; + struct _drm_intel_bo_gem { - drm_intel_bo bo; - - int refcount; - /** Boolean whether the mmap ioctl has been called for this buffer yet. */ - uint32_t gem_handle; - const char *name; - - /** - * Kenel-assigned global name for this object - */ - unsigned int global_name; - - /** - * Index of the buffer within the validation list while preparing a - * batchbuffer execution. - */ - int validate_index; - - /** - * Boolean whether we've started swrast - * Set when the buffer has been mapped - * Cleared when the buffer is unmapped - */ - int swrast; - - /** - * Current tiling mode - */ - uint32_t tiling_mode; - uint32_t swizzle_mode; - - time_t free_time; - - /** Array passed to the DRM containing relocation information. */ - struct drm_i915_gem_relocation_entry *relocs; - /** Array of bos corresponding to relocs[i].target_handle */ - drm_intel_bo **reloc_target_bo; - /** Number of entries in relocs */ - int reloc_count; - - /** BO cache list */ - drmMMListHead head; - - /** - * Boolean of whether this BO and its children have been included in - * the current drm_intel_bufmgr_check_aperture_space() total. - */ - char included_in_check_aperture; - - /** - * Boolean of whether this buffer has been used as a relocation - * target and had its size accounted for, and thus can't have any - * further relocations added to it. - */ - char used_as_reloc_target; - - /** - * Size in bytes of this buffer and its relocation descendents. - * - * Used to avoid costly tree walking in drm_intel_bufmgr_check_aperture in - * the common case. - */ - int reloc_tree_size; - /** - * Number of potential fence registers required by this buffer and its - * relocations. - */ - int reloc_tree_fences; - -#ifndef INTEL_ALWAYS_UNMAP - void *saved_virtual; -#endif -}; + drm_intel_bo bo; + + int refcount; + uint32_t gem_handle; + const char *name; + + /** + * Kenel-assigned global name for this object + */ + unsigned int global_name; + + /** + * Index of the buffer within the validation list while preparing a + * batchbuffer execution. + */ + int validate_index; -static void drm_intel_gem_bo_reference_locked(drm_intel_bo *bo); + /** + * Current tiling mode + */ + uint32_t tiling_mode; + uint32_t swizzle_mode; + + time_t free_time; + + /** Array passed to the DRM containing relocation information. */ + struct drm_i915_gem_relocation_entry *relocs; + /** + * Array of info structs corresponding to relocs[i].target_handle etc + */ + drm_intel_reloc_target *reloc_target_info; + /** Number of entries in relocs */ + int reloc_count; + + /** BO cache list */ + drmMMListHead head; + + /** + * Boolean of whether this BO and its children have been included in + * the current drm_intel_bufmgr_check_aperture_space() total. + */ + char included_in_check_aperture; + + /** + * Boolean of whether this buffer has been used as a relocation + * target and had its size accounted for, and thus can't have any + * further relocations added to it. + */ + 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; + + /** + * Size in bytes of this buffer and its relocation descendents. + * + * Used to avoid costly tree walking in + * drm_intel_bufmgr_check_aperture in the common case. + */ + int reloc_tree_size; + + /** + * Number of potential fence registers required by this buffer and its + * relocations. + */ + int reloc_tree_fences; + + /** Mapped address for the buffer, saved across map/unmap cycles */ + void *saved_virtual; +}; static unsigned int -drm_intel_gem_estimate_batch_space(drm_intel_bo **bo_array, int count); +drm_intel_gem_estimate_batch_space(drm_intel_bo ** bo_array, int count); static unsigned int -drm_intel_gem_compute_batch_space(drm_intel_bo **bo_array, int count); +drm_intel_gem_compute_batch_space(drm_intel_bo ** bo_array, int count); static int -drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode); +drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); static int -drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, +drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, uint32_t stride); -static void -drm_intel_gem_bo_unreference(drm_intel_bo *bo); +static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo, + time_t time); -static struct drm_intel_gem_bo_bucket * -drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem, - unsigned long size) +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) { - int i; + 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 (bufmgr_gem->gen >= 4) + return ROUND_UP_TO(size, 4096); + + /* Older chips need powers of two, of at least 512k or 1M */ + if (bufmgr_gem->gen == 3) { + min_size = 1024*1024; + max_size = 128*1024*1024; + } else { + min_size = 512*1024; + max_size = 64*1024*1024; + } - for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { - struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; - if (bucket->size >= size) { - return bucket; + if (size > max_size) { + *tiling_mode = I915_TILING_NONE; + return size; } - } - return NULL; + for (i = min_size; i < size; i <<= 1) + ; + + return i; } -static void drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) +/* + * 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) { - int i, j; + unsigned long tile_width; + unsigned long i; - for (i = 0; i < bufmgr_gem->exec_count; i++) { - drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + /* If untiled, then just align it so that we can do rendering + * to it with the 3D engine. + */ + if (tiling_mode == I915_TILING_NONE) + return ALIGN(pitch, 64); + + if (tiling_mode == I915_TILING_X) + tile_width = 512; + else + tile_width = 128; + + /* 965 is flexible */ + if (bufmgr_gem->gen >= 4) + return ROUND_UP_TO(pitch, tile_width); + + /* Pre-965 needs power of two tile width */ + for (i = tile_width; i < pitch; i <<= 1) + ; - if (bo_gem->relocs == NULL) { - DBG("%2d: %d (%s)\n", i, bo_gem->gem_handle, bo_gem->name); - continue; + 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) +{ + int i; + + for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; + if (bucket->size >= size) { + return bucket; + } } - for (j = 0; j < bo_gem->reloc_count; j++) { - drm_intel_bo *target_bo = bo_gem->reloc_target_bo[j]; - drm_intel_bo_gem *target_gem = (drm_intel_bo_gem *)target_bo; + return NULL; +} - DBG("%2d: %d (%s)@0x%08llx -> %d (%s)@0x%08lx + 0x%08x\n", - i, - bo_gem->gem_handle, bo_gem->name, - (unsigned long long)bo_gem->relocs[j].offset, - target_gem->gem_handle, target_gem->name, target_bo->offset, - bo_gem->relocs[j].delta); +static void +drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) +{ + int i, j; + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + if (bo_gem->relocs == NULL) { + DBG("%2d: %d (%s)\n", i, bo_gem->gem_handle, + bo_gem->name); + continue; + } + + for (j = 0; j < bo_gem->reloc_count; j++) { + drm_intel_bo *target_bo = bo_gem->reloc_target_info[j].bo; + drm_intel_bo_gem *target_gem = + (drm_intel_bo_gem *) target_bo; + + DBG("%2d: %d (%s)@0x%08llx -> " + "%d (%s)@0x%08lx + 0x%08x\n", + i, + bo_gem->gem_handle, bo_gem->name, + (unsigned long long)bo_gem->relocs[j].offset, + target_gem->gem_handle, + target_gem->name, + target_bo->offset, + bo_gem->relocs[j].delta); + } } - } +} + +static inline void +drm_intel_gem_bo_reference(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; + + /* XXX atomics */ + pthread_mutex_lock(&bufmgr_gem->lock); + assert(bo_gem->refcount > 0); + bo_gem->refcount++; + pthread_mutex_unlock(&bufmgr_gem->lock); } /** @@ -253,174 +351,349 @@ static void drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) * access flags. */ static void -drm_intel_add_validate_buffer(drm_intel_bo *bo) +drm_intel_add_validate_buffer2(drm_intel_bo *bo, int need_fence) { - 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; - - if (bo_gem->validate_index != -1) - return; - - /* Extend the array of validation entries as necessary. */ - if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) { - int new_size = bufmgr_gem->exec_size * 2; - - if (new_size == 0) - new_size = 5; - - bufmgr_gem->exec_objects = - realloc(bufmgr_gem->exec_objects, - sizeof(*bufmgr_gem->exec_objects) * new_size); - bufmgr_gem->exec_bos = - realloc(bufmgr_gem->exec_bos, - sizeof(*bufmgr_gem->exec_bos) * new_size); - bufmgr_gem->exec_size = new_size; - } - - index = bufmgr_gem->exec_count; - bo_gem->validate_index = index; - /* Fill in array entry */ - bufmgr_gem->exec_objects[index].handle = bo_gem->gem_handle; - bufmgr_gem->exec_objects[index].relocation_count = bo_gem->reloc_count; - bufmgr_gem->exec_objects[index].relocs_ptr = (uintptr_t)bo_gem->relocs; - 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_locked(bo); - bufmgr_gem->exec_count++; -} + 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; + + if (bo_gem->validate_index != -1) { + if (need_fence) + bufmgr_gem->exec2_objects[bo_gem->validate_index].flags |= + EXEC_OBJECT_NEEDS_FENCE; + return; + } + /* Extend the array of validation entries as necessary. */ + if (bufmgr_gem->exec_count == bufmgr_gem->exec_size) { + int new_size = bufmgr_gem->exec_size * 2; + + if (new_size == 0) + new_size = 5; + + bufmgr_gem->exec2_objects = + realloc(bufmgr_gem->exec2_objects, + sizeof(*bufmgr_gem->exec2_objects) * new_size); + bufmgr_gem->exec_bos = + realloc(bufmgr_gem->exec_bos, + sizeof(*bufmgr_gem->exec_bos) * new_size); + bufmgr_gem->exec_size = new_size; + } + + index = bufmgr_gem->exec_count; + bo_gem->validate_index = index; + /* Fill in array entry */ + bufmgr_gem->exec2_objects[index].handle = bo_gem->gem_handle; + 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 = 0; + bufmgr_gem->exec2_objects[index].offset = 0; + bufmgr_gem->exec_bos[index] = bo; + bufmgr_gem->exec2_objects[index].flags = 0; + bufmgr_gem->exec2_objects[index].rsvd1 = 0; + bufmgr_gem->exec2_objects[index].rsvd2 = 0; + if (need_fence) { + bufmgr_gem->exec2_objects[index].flags |= + EXEC_OBJECT_NEEDS_FENCE; + } + 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 (bufmgr_gem->gen < 4 && 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) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + unsigned int max_relocs = bufmgr_gem->max_relocs; + + if (bo->size / 4 < max_relocs) + max_relocs = bo->size / 4; + + bo_gem->relocs = malloc(max_relocs * + sizeof(struct drm_i915_gem_relocation_entry)); + bo_gem->reloc_target_info = malloc(max_relocs * + sizeof(drm_intel_reloc_target *)); + if (bo_gem->relocs == NULL || bo_gem->reloc_target_info == NULL) { + bo_gem->has_error = 1; - bo_gem->relocs = malloc(bufmgr_gem->max_relocs * - sizeof(struct drm_i915_gem_relocation_entry)); - bo_gem->reloc_target_bo = malloc(bufmgr_gem->max_relocs * - sizeof(drm_intel_bo *)); + free (bo_gem->relocs); + bo_gem->relocs = NULL; - return 0; + free (bo_gem->reloc_target_info); + bo_gem->reloc_target_info = NULL; + + return 1; + } + + return 0; } -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) +static int +drm_intel_gem_bo_busy(drm_intel_bo *bo) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; - drm_intel_bo_gem *bo_gem; - unsigned int page_size = getpagesize(); - int ret; - struct drm_intel_gem_bo_bucket *bucket; - int alloc_from_cache = 0; - unsigned long bo_size; - - /* Round the allocated size up to a power of two number of pages. */ - bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size); - - /* If we don't have caching at this size, don't actually round the - * allocation up. - */ - if (bucket == NULL || bucket->max_entries == 0) { - bo_size = size; - if (bo_size < page_size) - bo_size = page_size; - } else { - bo_size = bucket->size; - } - - pthread_mutex_lock(&bufmgr_gem->lock); - /* Get a buffer out of the cache if available */ - if (bucket != NULL && bucket->num_entries > 0) { + 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_busy busy; + int ret; - if (for_render) { - /* Allocate new render-target BOs from the tail (MRU) - * of the list, as it will likely be hot in the GPU cache - * and in the aperture for us. - */ - bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.prev, head); - DRMLISTDEL(&bo_gem->head); - bucket->num_entries--; - alloc_from_cache = 1; - } else { - /* For non-render-target BOs (where we're probably going to map it - * first thing in order to fill it with data), check if the - * last BO in the cache is unbusy, and only reuse in that case. - * Otherwise, allocating a new buffer is probably faster than - * waiting for the GPU to finish. - */ - bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head); + memset(&busy, 0, sizeof(busy)); + busy.handle = bo_gem->gem_handle; + + do { + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); + } while (ret == -1 && errno == EINTR); + + return (ret == 0 && busy.busy); +} - memset(&busy, 0, sizeof(busy)); - busy.handle = bo_gem->gem_handle; +static int +drm_intel_gem_bo_madvise_internal(drm_intel_bufmgr_gem *bufmgr_gem, + drm_intel_bo_gem *bo_gem, int state) +{ + struct drm_i915_gem_madvise madv; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_BUSY, &busy); - alloc_from_cache = (ret == 0 && busy.busy == 0); + madv.handle = bo_gem->gem_handle; + madv.madv = state; + madv.retained = 1; + ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MADVISE, &madv); + + return madv.retained; +} + +static int +drm_intel_gem_bo_madvise(drm_intel_bo *bo, int madv) +{ + return drm_intel_gem_bo_madvise_internal + ((drm_intel_bufmgr_gem *) bo->bufmgr, + (drm_intel_bo_gem *) bo, + madv); +} + +/* drop the oldest entries that have been purged by the kernel */ +static void +drm_intel_gem_bo_cache_purge_bucket(drm_intel_bufmgr_gem *bufmgr_gem, + struct drm_intel_gem_bo_bucket *bucket) +{ + while (!DRMLISTEMPTY(&bucket->head)) { + drm_intel_bo_gem *bo_gem; + + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (drm_intel_gem_bo_madvise_internal + (bufmgr_gem, bo_gem, I915_MADV_DONTNEED)) + break; - if (alloc_from_cache) { DRMLISTDEL(&bo_gem->head); - bucket->num_entries--; - } + drm_intel_gem_bo_free(&bo_gem->bo); } - } - pthread_mutex_unlock(&bufmgr_gem->lock); +} - if (!alloc_from_cache) { - struct drm_i915_gem_create create; +static drm_intel_bo * +drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned long flags) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + drm_intel_bo_gem *bo_gem; + unsigned int page_size = getpagesize(); + int ret; + struct drm_intel_gem_bo_bucket *bucket; + int alloc_from_cache; + unsigned long bo_size; + int for_render = 0; - bo_gem = calloc(1, sizeof(*bo_gem)); - if (!bo_gem) - return NULL; + if (flags & BO_ALLOC_FOR_RENDER) + for_render = 1; - bo_gem->bo.size = bo_size; - memset(&create, 0, sizeof(create)); - create.size = bo_size; + /* Round the allocated size up to a power of two number of pages. */ + bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size); - ret = ioctl(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; + /* If we don't have caching at this size, don't actually round the + * allocation up. + */ + if (bucket == NULL) { + bo_size = size; + if (bo_size < page_size) + bo_size = page_size; + } else { + bo_size = bucket->size; } - bo_gem->bo.bufmgr = bufmgr; - } - bo_gem->name = name; - 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->tiling_mode = I915_TILING_NONE; - bo_gem->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + pthread_mutex_lock(&bufmgr_gem->lock); + /* Get a buffer out of the cache if available */ +retry: + alloc_from_cache = 0; + if (bucket != NULL && !DRMLISTEMPTY(&bucket->head)) { + if (for_render) { + /* Allocate new render-target BOs from the tail (MRU) + * of the list, as it will likely be hot in the GPU + * cache and in the aperture for us. + */ + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.prev, head); + DRMLISTDEL(&bo_gem->head); + alloc_from_cache = 1; + } else { + /* For non-render-target BOs (where we're probably + * going to map it first thing in order to fill it + * with data), check if the last BO in the cache is + * unbusy, and only reuse in that case. Otherwise, + * allocating a new buffer is probably faster than + * waiting for the GPU to finish. + */ + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (!drm_intel_gem_bo_busy(&bo_gem->bo)) { + alloc_from_cache = 1; + DRMLISTDEL(&bo_gem->head); + } + } + + if (alloc_from_cache) { + if (!drm_intel_gem_bo_madvise_internal + (bufmgr_gem, bo_gem, I915_MADV_WILLNEED)) { + drm_intel_gem_bo_free(&bo_gem->bo); + drm_intel_gem_bo_cache_purge_bucket(bufmgr_gem, + bucket); + goto retry; + } + } + } + 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; + + bo_gem->bo.size = bo_size; + memset(&create, 0, sizeof(create)); + create.size = bo_size; + + 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) { + free(bo_gem); + return NULL; + } + bo_gem->bo.bufmgr = bufmgr; + } + + bo_gem->name = name; + bo_gem->refcount = 1; + bo_gem->validate_index = -1; + 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; - DBG("bo_create: buf %d (%s) %ldb\n", - bo_gem->gem_handle, bo_gem->name, size); + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem); - return &bo_gem->bo; + DBG("bo_create: buf %d (%s) %ldb\n", + bo_gem->gem_handle, bo_gem->name, size); + + return &bo_gem->bo; +} + +static drm_intel_bo * +drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) +{ + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, + BO_ALLOC_FOR_RENDER); } static drm_intel_bo * -drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment) +drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, + const char *name, + unsigned long size, + unsigned int alignment) { - return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, 1); + return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0); } static drm_intel_bo * -drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment) +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) { - return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment, 0); + 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 we're tiled, our allocations are in 8 or 32-row blocks, + * so failure to align our height means that we won't allocate + * enough pages. + * + * If we're untiled, we still have to align to 2 rows high + * because the data port accesses 2x2 blocks even if the + * bottom row isn't to be rendered, so failure to align means + * we could walk off the end of the GTT and fault. This is + * documented on 965, and may be the case on older chipsets + * too so we try to be careful. + */ + 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; } /** @@ -430,331 +703,382 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name, * to another. */ drm_intel_bo * -drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, const char *name, +drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, + const char *name, unsigned int handle) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; - drm_intel_bo_gem *bo_gem; - int ret; - struct drm_gem_open open_arg; - struct drm_i915_gem_get_tiling get_tiling; - - bo_gem = calloc(1, sizeof(*bo_gem)); - if (!bo_gem) - return NULL; - - memset(&open_arg, 0, sizeof(open_arg)); - open_arg.name = handle; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_OPEN, &open_arg); - if (ret != 0) { - fprintf(stderr, "Couldn't reference %s handle 0x%08x: %s\n", - name, handle, strerror(errno)); - free(bo_gem); - return NULL; - } - 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; - bo_gem->refcount = 1; - bo_gem->validate_index = -1; - bo_gem->gem_handle = open_arg.handle; - bo_gem->global_name = handle; - - memset(&get_tiling, 0, sizeof(get_tiling)); - get_tiling.handle = bo_gem->gem_handle; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling); - if (ret != 0) { - drm_intel_gem_bo_unreference(&bo_gem->bo); - return NULL; - } - bo_gem->tiling_mode = get_tiling.tiling_mode; - bo_gem->swizzle_mode = get_tiling.swizzle_mode; - if (bo_gem->tiling_mode == I915_TILING_NONE) - bo_gem->reloc_tree_fences = 0; - else - bo_gem->reloc_tree_fences = 1; - - DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name); - - return &bo_gem->bo; -} + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + drm_intel_bo_gem *bo_gem; + int ret; + struct drm_gem_open open_arg; + struct drm_i915_gem_get_tiling get_tiling; -static void -drm_intel_gem_bo_reference(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; + bo_gem = calloc(1, sizeof(*bo_gem)); + if (!bo_gem) + return NULL; + + memset(&open_arg, 0, sizeof(open_arg)); + open_arg.name = handle; + 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)); + free(bo_gem); + return NULL; + } + 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; + bo_gem->refcount = 1; + bo_gem->validate_index = -1; + bo_gem->gem_handle = open_arg.handle; + bo_gem->global_name = handle; + bo_gem->reusable = 0; - assert(bo_gem->refcount > 0); - pthread_mutex_lock(&bufmgr_gem->lock); - bo_gem->refcount++; - pthread_mutex_unlock(&bufmgr_gem->lock); -} + memset(&get_tiling, 0, sizeof(get_tiling)); + get_tiling.handle = bo_gem->gem_handle; + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_TILING, &get_tiling); + if (ret != 0) { + drm_intel_gem_bo_unreference(&bo_gem->bo); + return NULL; + } + bo_gem->tiling_mode = get_tiling.tiling_mode; + bo_gem->swizzle_mode = get_tiling.swizzle_mode; + drm_intel_bo_gem_set_in_aperture_size(bufmgr_gem, bo_gem); -static void -drm_intel_gem_bo_reference_locked(drm_intel_bo *bo) -{ - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name); - assert(bo_gem->refcount > 0); - bo_gem->refcount++; + return &bo_gem->bo; } static void drm_intel_gem_bo_free(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; - struct drm_gem_close close; - int ret; - - if (bo->virtual) - munmap (bo->virtual, bo_gem->bo.size); -#ifndef INTEL_ALWAYS_UNMAP - else if (bo_gem->saved_virtual) - munmap(bo_gem->saved_virtual, bo->size); -#endif - - /* Close this object */ - memset(&close, 0, sizeof(close)); - close.handle = bo_gem->gem_handle; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close); - if (ret != 0) { - fprintf(stderr, - "DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n", - bo_gem->gem_handle, bo_gem->name, strerror(errno)); - } - free(bo); + 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_gem_close close; + int ret; + + if (bo->virtual) + munmap(bo->virtual, bo_gem->bo.size); + else if (bo_gem->saved_virtual) + munmap(bo_gem->saved_virtual, bo_gem->bo.size); + + /* Close this object */ + memset(&close, 0, sizeof(close)); + close.handle = bo_gem->gem_handle; + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_CLOSE, &close); + if (ret != 0) { + fprintf(stderr, + "DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n", + bo_gem->gem_handle, bo_gem->name, strerror(errno)); + } + free(bo); } /** Frees all cached buffers significantly older than @time. */ static void drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time) { - int i; + int i; - for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { - struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; + for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; - while (!DRMLISTEMPTY(&bucket->head)) { - drm_intel_bo_gem *bo_gem; + while (!DRMLISTEMPTY(&bucket->head)) { + drm_intel_bo_gem *bo_gem; - bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head); - if (time - bo_gem->free_time <= 1) - break; + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + if (time - bo_gem->free_time <= 1) + break; - DRMLISTDEL(&bo_gem->head); - bucket->num_entries--; + DRMLISTDEL(&bo_gem->head); - drm_intel_gem_bo_free(&bo_gem->bo); + drm_intel_gem_bo_free(&bo_gem->bo); + } } - } } static void -drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) +drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - - assert(bo_gem->refcount > 0); - if (--bo_gem->refcount == 0) { + 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_intel_gem_bo_bucket *bucket; uint32_t tiling_mode; + int i; - if (bo_gem->relocs != NULL) { - int i; - - /* Unreference all the target buffers */ - for (i = 0; i < bo_gem->reloc_count; i++) - drm_intel_gem_bo_unreference_locked(bo_gem->reloc_target_bo[i]); - free(bo_gem->reloc_target_bo); - free(bo_gem->relocs); + /* Unreference all the target buffers */ + for (i = 0; i < bo_gem->reloc_count; i++) { + drm_intel_gem_bo_unreference_locked_timed(bo_gem-> + reloc_target_info[i].bo, + 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_info) { + free(bo_gem->reloc_target_info); + bo_gem->reloc_target_info = 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 (bo_gem->global_name == 0 && - bucket != NULL && - (bucket->max_entries == -1 || - (bucket->max_entries > 0 && - bucket->num_entries < bucket->max_entries)) && - drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0) - { - struct timespec time; - - clock_gettime(CLOCK_MONOTONIC, &time); - bo_gem->free_time = time.tv_sec; - - bo_gem->name = NULL; - bo_gem->validate_index = -1; - bo_gem->relocs = NULL; - bo_gem->reloc_target_bo = NULL; - bo_gem->reloc_count = 0; - - DRMLISTADDTAIL(&bo_gem->head, &bucket->head); - bucket->num_entries++; - - drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec); + 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_madvise_internal(bufmgr_gem, bo_gem, + I915_MADV_DONTNEED)) { + bo_gem->free_time = time; + + bo_gem->name = NULL; + bo_gem->validate_index = -1; + + DRMLISTADDTAIL(&bo_gem->head, &bucket->head); + + drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time); } else { - drm_intel_gem_bo_free(bo); + drm_intel_gem_bo_free(bo); } - } } -static void -drm_intel_gem_bo_unreference(drm_intel_bo *bo) +static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo, + time_t time) { - 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); - drm_intel_gem_bo_unreference_locked(bo); - pthread_mutex_unlock(&bufmgr_gem->lock); + /* XXX atomics */ + assert(bo_gem->refcount > 0); + if (--bo_gem->refcount == 0) + drm_intel_gem_bo_unreference_final(bo, time); } -static int -drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) +static void drm_intel_gem_bo_unreference(drm_intel_bo *bo) { - return drm_intel_gem_bo_map_gtt(bo); + 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); + assert(bo_gem->refcount > 0); + if (--bo_gem->refcount == 0) { + drm_intel_bufmgr_gem *bufmgr_gem = + (drm_intel_bufmgr_gem *) bo->bufmgr; + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + + drm_intel_gem_bo_unreference_final(bo, time.tv_sec); + } + pthread_mutex_unlock(&bufmgr_gem->lock); } -int -drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) +/* + * OpenBSD only supports GTT mapping of the backing memory, not a choice of + * faulted gtt memory, or the backing pages. This is due to cache coherency + * issues. + * + * Therefore, bo_map_gtt calls bo_map, and bo_unmap_gtt calls bo_unmap. + */ +static int drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable) { - 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_set_domain set_domain; - int ret; - - pthread_mutex_lock(&bufmgr_gem->lock); -#ifndef INTEL_ALWAYS_UNMAP - if (bo_gem->saved_virtual == NULL) { -#endif - assert(bo->virtual == NULL); - struct drm_i915_gem_mmap mmap_arg; - - DBG("bo_map_gtt: %d (%s)\n", bo_gem->gem_handle, bo_gem->name); - - memset(&mmap_arg, 0, sizeof(mmap_arg)); - mmap_arg.handle = bo_gem->gem_handle; - mmap_arg.size = bo->size; - - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg); - if (ret != 0) { - fprintf(stderr, "%s:%d: Error preparing buffer map %d (%s): %s .\n", - __FILE__, __LINE__, bo_gem->gem_handle, - bo_gem->name, strerror(errno)); - pthread_mutex_unlock(&bufmgr_gem->lock); - return ret; - } - - bo->virtual = (void *)(uintptr_t)mmap_arg.addr_ptr; - - DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, - bo->virtual); -#ifndef INTEL_ALWAYS_UNMAP - bo_gem->saved_virtual = bo->virtual; - } else + 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_set_domain set_domain; + struct drm_i915_gem_mmap mmap_arg; + int ret; + + pthread_mutex_lock(&bufmgr_gem->lock); + + /* Allow recursive mapping. Mesa may recursively map buffers with + * nested display loops. + */ + if (bo_gem->saved_virtual == NULL) { + DBG("bo_map: %d (%s)\n", bo_gem->gem_handle, bo_gem->name); + + memset(&mmap_arg, 0, sizeof(mmap_arg)); + mmap_arg.handle = bo_gem->gem_handle; + mmap_arg.offset = 0; + mmap_arg.size = bo->size; + 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, + bo_gem->name, strerror(errno)); + pthread_mutex_unlock(&bufmgr_gem->lock); + return ret; + } + + bo_gem->saved_virtual = (void *)(uintptr_t)mmap_arg.addr_ptr; + } + DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, + bo_gem->saved_virtual); bo->virtual = bo_gem->saved_virtual; -#endif - pthread_mutex_unlock(&bufmgr_gem->lock); + set_domain.handle = bo_gem->gem_handle; + set_domain.read_domains = I915_GEM_DOMAIN_GTT; + if (write_enable) + set_domain.write_domain = I915_GEM_DOMAIN_GTT; + else + set_domain.write_domain = 0; + do { + 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)); + pthread_mutex_unlock(&bufmgr_gem->lock); + return ret; + } + + pthread_mutex_unlock(&bufmgr_gem->lock); - return 0; + return 0; } -int -drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo) +int drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) +{ + return drm_intel_gem_bo_map(bo, 1); +} + +static int drm_intel_gem_bo_unmap(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; + 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 == NULL) - return 0; + if (bo == NULL) + return 0; - assert(bo->virtual != NULL); - pthread_mutex_lock(&bufmgr_gem->lock); -#ifdef INTEL_ALWAYS_UNMAP - munmap(bo->virtual, bo->size); -#else - assert(bo_gem->saved_virtual != NULL && - bo_gem->saved_virtual == bo->virtual); -#endif - bo->virtual = NULL; - pthread_mutex_unlock(&bufmgr_gem->lock); + assert(bo_gem->saved_virtual != NULL); + pthread_mutex_lock(&bufmgr_gem->lock); + bo->virtual = NULL; + pthread_mutex_unlock(&bufmgr_gem->lock); - return 0; + return 0; +} + +int drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo) +{ + return drm_intel_gem_bo_unmap(bo); } static int -drm_intel_gem_bo_unmap(drm_intel_bo *bo) +drm_intel_gem_bo_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data) { - return drm_intel_gem_bo_unmap_gtt(bo); + 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_pwrite pwrite; + int ret; + + memset(&pwrite, 0, sizeof(pwrite)); + pwrite.handle = bo_gem->gem_handle; + pwrite.offset = offset; + pwrite.size = size; + pwrite.data_ptr = (uint64_t) (uintptr_t) data; + do { + ret = ioctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_PWRITE, + &pwrite); + } while (ret == -1 && errno == EINTR); + if (ret != 0) { + ret = -errno; + fprintf(stderr, + "%s:%d: Error writing data to buffer %d: (%d %d) %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, (int)offset, + (int)size, strerror(errno)); + } + + return ret; } static int -drm_intel_gem_bo_subdata (drm_intel_bo *bo, unsigned long offset, - unsigned long size, const void *data) +drm_intel_gem_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, int crtc_id) { - 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_pwrite pwrite; - int ret; - - memset (&pwrite, 0, sizeof (pwrite)); - pwrite.handle = bo_gem->gem_handle; - pwrite.offset = offset; - pwrite.size = size; - pwrite.data_ptr = (uint64_t) (uintptr_t) data; - do { - ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite); - } while (ret == -1 && errno == EINTR); - if (ret != 0) { - fprintf (stderr, "%s:%d: Error writing data to buffer %d: (%d %d) %s .\n", - __FILE__, __LINE__, - bo_gem->gem_handle, (int) offset, (int) size, - strerror (errno)); - } - return 0; +#if 0 + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + struct drm_i915_get_pipe_from_crtc_id get_pipe_from_crtc_id; + int ret; + + get_pipe_from_crtc_id.crtc_id = crtc_id; + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, + &get_pipe_from_crtc_id); + if (ret != 0) { + /* We return -1 here to signal that we don't + * know which pipe is associated with this crtc. + * This lets the caller know that this information + * isn't available; using the wrong pipe for + * vblank waiting can cause the chipset to lock up + */ + return -1; + } + + return get_pipe_from_crtc_id.pipe; +#endif + /* only needed for KMS */ + return -1; } static int -drm_intel_gem_bo_get_subdata (drm_intel_bo *bo, unsigned long offset, - unsigned long size, void *data) +drm_intel_gem_bo_get_subdata(drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data) { - 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_pread pread; - int ret; - - memset (&pread, 0, sizeof (pread)); - pread.handle = bo_gem->gem_handle; - pread.offset = offset; - pread.size = size; - pread.data_ptr = (uint64_t) (uintptr_t) data; - do { - ret = ioctl (bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PREAD, &pread); - } while (ret == -1 && errno == EINTR); - if (ret != 0) { - 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; + 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_pread pread; + int ret; + + memset(&pread, 0, sizeof(pread)); + pread.handle = bo_gem->gem_handle; + pread.offset = offset; + pread.size = size; + pread.data_ptr = (uint64_t) (uintptr_t) data; + do { + 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 ret; } /** Waits for all GPU rendering to the object to have completed. */ static void drm_intel_gem_bo_wait_rendering(drm_intel_bo *bo) { - drm_intel_gem_bo_start_gtt_access(bo, 0); + drm_intel_gem_bo_start_gtt_access(bo, 0); } /** @@ -767,51 +1091,55 @@ drm_intel_gem_bo_wait_rendering(drm_intel_bo *bo) void drm_intel_gem_bo_start_gtt_access(drm_intel_bo *bo, int write_enable) { - 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_set_domain set_domain; - int ret; - - set_domain.handle = bo_gem->gem_handle; - 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, &set_domain); - } while (ret == -1 && errno == EINTR); - if (ret != 0) { - fprintf (stderr, "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n", - __FILE__, __LINE__, - bo_gem->gem_handle, set_domain.read_domains, set_domain.write_domain, - strerror (errno)); - } + 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_set_domain set_domain; + int ret; + + set_domain.handle = bo_gem->gem_handle; + 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, + &set_domain); + } while (ret == -1 && errno == EINTR); + if (ret != 0) { + fprintf(stderr, + "%s:%d: Error setting memory domains %d (%08x %08x): %s .\n", + __FILE__, __LINE__, bo_gem->gem_handle, + set_domain.read_domains, set_domain.write_domain, + strerror(errno)); + } } static void drm_intel_bufmgr_gem_destroy(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; - int i; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; + int i; - free(bufmgr_gem->exec_objects); - free(bufmgr_gem->exec_bos); + free(bufmgr_gem->exec2_objects); + free(bufmgr_gem->exec_bos); - pthread_mutex_destroy(&bufmgr_gem->lock); + pthread_mutex_destroy(&bufmgr_gem->lock); - /* Free any cached buffer objects we were going to reuse */ - for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { - struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; - drm_intel_bo_gem *bo_gem; + /* Free any cached buffer objects we were going to reuse */ + for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { + struct drm_intel_gem_bo_bucket *bucket = + &bufmgr_gem->cache_bucket[i]; + drm_intel_bo_gem *bo_gem; - while (!DRMLISTEMPTY(&bucket->head)) { - bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head); - DRMLISTDEL(&bo_gem->head); - bucket->num_entries--; + while (!DRMLISTEMPTY(&bucket->head)) { + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, + bucket->head.next, head); + DRMLISTDEL(&bo_gem->head); - drm_intel_gem_bo_free(&bo_gem->bo); + drm_intel_gem_bo_free(&bo_gem->bo); + } } - } - free(bufmgr); + free(bufmgr); } /** @@ -824,53 +1152,97 @@ drm_intel_bufmgr_gem_destroy(drm_intel_bufmgr *bufmgr) * last known offset in target_bo. */ static int -drm_intel_gem_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) +do_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 need_fence) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *)target_bo; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bufmgr; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo; - pthread_mutex_lock(&bufmgr_gem->lock); + if (bo_gem->has_error) + return -ENOMEM; - /* Create a new relocation list if needed */ - if (bo_gem->relocs == NULL) - drm_intel_setup_reloc_list(bo); + if (target_bo_gem->has_error) { + bo_gem->has_error = 1; + return -ENOMEM; + } - /* Check overflow */ - assert(bo_gem->reloc_count < bufmgr_gem->max_relocs); + if (target_bo_gem->tiling_mode == I915_TILING_NONE) + need_fence = 0; - /* Check args */ - assert (offset <= bo->size - 4); - assert ((write_domain & (write_domain-1)) == 0); + /* We never use HW fences for rendering on 965+ */ + if (bufmgr_gem->gen >= 4) + need_fence = 0; - /* Make sure that we're not adding a reloc to something whose size has - * already been accounted for. - */ - assert(!bo_gem->used_as_reloc_target); - bo_gem->reloc_tree_size += target_bo_gem->reloc_tree_size; - bo_gem->reloc_tree_fences += target_bo_gem->reloc_tree_fences; + /* Create a new relocation list if needed */ + if (bo_gem->relocs == NULL && drm_intel_setup_reloc_list(bo)) + return -ENOMEM; - /* Flag the target to disallow further relocations in it. */ - target_bo_gem->used_as_reloc_target = 1; + /* Check overflow */ + assert(bo_gem->reloc_count < bufmgr_gem->max_relocs); - bo_gem->relocs[bo_gem->reloc_count].offset = offset; - bo_gem->relocs[bo_gem->reloc_count].delta = target_offset; - bo_gem->relocs[bo_gem->reloc_count].target_handle = - target_bo_gem->gem_handle; - bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains; - bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain; - bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset; + /* Check args */ + assert(offset <= bo->size - 4); + assert((write_domain & (write_domain - 1)) == 0); - bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo; - drm_intel_gem_bo_reference_locked(target_bo); + /* Make sure that we're not adding a reloc to something whose size has + * already been accounted for. + */ + assert(!bo_gem->used_as_reloc_target); + bo_gem->reloc_tree_size += target_bo_gem->reloc_tree_size; + /* An object needing a fence is a tiled buffer, so it won't have + * relocs to other buffers. + */ + if (need_fence) + target_bo_gem->reloc_tree_fences = 1; + bo_gem->reloc_tree_fences += target_bo_gem->reloc_tree_fences; + + /* Flag the target to disallow further relocations in it. */ + target_bo_gem->used_as_reloc_target = 1; + + bo_gem->relocs[bo_gem->reloc_count].offset = offset; + bo_gem->relocs[bo_gem->reloc_count].delta = target_offset; + bo_gem->relocs[bo_gem->reloc_count].target_handle = + target_bo_gem->gem_handle; + bo_gem->relocs[bo_gem->reloc_count].read_domains = read_domains; + bo_gem->relocs[bo_gem->reloc_count].write_domain = write_domain; + bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset; + + bo_gem->reloc_target_info[bo_gem->reloc_count].bo = target_bo; + drm_intel_gem_bo_reference(target_bo); + if (need_fence) + bo_gem->reloc_target_info[bo_gem->reloc_count].flags = + DRM_INTEL_RELOC_FENCE; + else + bo_gem->reloc_target_info[bo_gem->reloc_count].flags = 0; + + bo_gem->reloc_count++; - bo_gem->reloc_count++; + return 0; +} - pthread_mutex_unlock(&bufmgr_gem->lock); +static int +drm_intel_gem_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) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; - return 0; + return do_bo_emit_reloc(bo, offset, target_bo, target_offset, + read_domains, write_domain, + !bufmgr_gem->fenced_relocs); +} + +static int +drm_intel_gem_bo_emit_reloc_fence(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, + uint32_t target_offset, + uint32_t read_domains, uint32_t write_domain) +{ + return do_bo_emit_reloc(bo, offset, target_bo, target_offset, + read_domains, write_domain, 1); } /** @@ -879,215 +1251,218 @@ drm_intel_gem_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, * index values into the validation list. */ static void -drm_intel_gem_bo_process_reloc(drm_intel_bo *bo) +drm_intel_gem_bo_process_reloc2(drm_intel_bo *bo) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - int i; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + int i; - if (bo_gem->relocs == NULL) - return; + if (bo_gem->relocs == NULL) + return; - for (i = 0; i < bo_gem->reloc_count; i++) { - drm_intel_bo *target_bo = bo_gem->reloc_target_bo[i]; + for (i = 0; i < bo_gem->reloc_count; i++) { + drm_intel_bo *target_bo = bo_gem->reloc_target_info[i].bo; + int need_fence; - /* Continue walking the tree depth-first. */ - drm_intel_gem_bo_process_reloc(target_bo); + /* Continue walking the tree depth-first. */ + drm_intel_gem_bo_process_reloc2(target_bo); - /* Add the target to the validate list */ - drm_intel_add_validate_buffer(target_bo); - } + need_fence = (bo_gem->reloc_target_info[i].flags & + DRM_INTEL_RELOC_FENCE); + + /* Add the target to the validate list */ + drm_intel_add_validate_buffer2(target_bo, need_fence); + } } static void -drm_intel_update_buffer_offsets (drm_intel_bufmgr_gem *bufmgr_gem) +drm_intel_update_buffer_offsets2 (drm_intel_bufmgr_gem *bufmgr_gem) { - int i; - - for (i = 0; i < bufmgr_gem->exec_count; i++) { - drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - - /* Update the buffer offset */ - if (bufmgr_gem->exec_objects[i].offset != bo->offset) { - DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n", - bo_gem->gem_handle, bo_gem->name, bo->offset, - (unsigned long long)bufmgr_gem->exec_objects[i].offset); - bo->offset = bufmgr_gem->exec_objects[i].offset; + int i; + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + + /* Update the buffer offset */ + if (bufmgr_gem->exec2_objects[i].offset != bo->offset) { + DBG("BO %d (%s) migrated: 0x%08lx -> 0x%08llx\n", + bo_gem->gem_handle, bo_gem->name, bo->offset, + (unsigned long long)bufmgr_gem->exec2_objects[i].offset); + bo->offset = bufmgr_gem->exec2_objects[i].offset; + } } - } } static int -drm_intel_gem_bo_exec(drm_intel_bo *bo, int used, - drm_clip_rect_t *cliprects, int num_cliprects, - int DR4) +drm_intel_gem_bo_exec2(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; - struct drm_i915_gem_execbuffer execbuf; - int ret, i; - - pthread_mutex_lock(&bufmgr_gem->lock); - /* Update indices and set up the validate list. */ - drm_intel_gem_bo_process_reloc(bo); - - /* Add the batch buffer to the validation list. There are no relocations - * pointing to it. - */ - drm_intel_add_validate_buffer(bo); - - execbuf.buffers_ptr = (uintptr_t)bufmgr_gem->exec_objects; - execbuf.buffer_count = bufmgr_gem->exec_count; - execbuf.batch_start_offset = 0; - execbuf.batch_len = used; - execbuf.cliprects_ptr = (uintptr_t)cliprects; - execbuf.num_cliprects = num_cliprects; - execbuf.DR1 = 0; - execbuf.DR4 = DR4; - - do { - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER, &execbuf); - } while (ret != 0 && errno == EAGAIN); - - 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); - } - drm_intel_update_buffer_offsets (bufmgr_gem); - - if (bufmgr_gem->bufmgr.debug) - drm_intel_gem_dump_validation_list(bufmgr_gem); - - for (i = 0; i < bufmgr_gem->exec_count; i++) { - drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + struct drm_i915_gem_execbuffer2 execbuf; + int ret, i; - /* Need to call swrast on next bo_map */ - bo_gem->swrast = 0; + pthread_mutex_lock(&bufmgr_gem->lock); + /* Update indices and set up the validate list. */ + drm_intel_gem_bo_process_reloc2(bo); - /* 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); + /* Add the batch buffer to the validation list. There are no relocations + * pointing to it. + */ + drm_intel_add_validate_buffer2(bo, 0); + + execbuf.buffers_ptr = (uintptr_t)bufmgr_gem->exec2_objects; + execbuf.buffer_count = bufmgr_gem->exec_count; + execbuf.batch_start_offset = 0; + execbuf.batch_len = used; + execbuf.flags = 0; + execbuf.rsvd1 = 0; + execbuf.rsvd2 = 0; + + do { + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, + &execbuf); + } while (ret != 0 && errno == EINTR); + + if (ret != 0) { + ret = -errno; + if (ret == -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); + } + } + drm_intel_update_buffer_offsets2(bufmgr_gem); + + if (bufmgr_gem->bufmgr.debug) + drm_intel_gem_dump_validation_list(bufmgr_gem); + + for (i = 0; i < bufmgr_gem->exec_count; i++) { + drm_intel_bo *bo = bufmgr_gem->exec_bos[i]; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + + /* Disconnect the buffer from the validate list */ + bo_gem->validate_index = -1; + bufmgr_gem->exec_bos[i] = NULL; + } + bufmgr_gem->exec_count = 0; + pthread_mutex_unlock(&bufmgr_gem->lock); - return 0; + return ret; } static int drm_intel_gem_bo_pin(drm_intel_bo *bo, uint32_t alignment) { - 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_pin pin; - int ret; + 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_pin pin; + int ret; - memset(&pin, 0, sizeof(pin)); - pin.handle = bo_gem->gem_handle; - pin.alignment = alignment; + memset(&pin, 0, sizeof(pin)); + pin.handle = bo_gem->gem_handle; + pin.alignment = alignment; - do { - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_PIN, &pin); - } while (ret == -1 && errno == EINTR); + do { + ret = ioctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_PIN, + &pin); + } while (ret == -1 && errno == EINTR); - if (ret != 0) - return -errno; + if (ret != 0) + return -errno; - bo->offset = pin.offset; - return 0; + bo->offset = pin.offset; + return 0; } static int drm_intel_gem_bo_unpin(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; - struct drm_i915_gem_unpin unpin; - int ret; + 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_unpin unpin; + int ret; - memset(&unpin, 0, sizeof(unpin)); - unpin.handle = bo_gem->gem_handle; + memset(&unpin, 0, sizeof(unpin)); + unpin.handle = bo_gem->gem_handle; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin); - if (ret != 0) - return -errno; + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_UNPIN, &unpin); + if (ret != 0) + return -errno; - return 0; + return 0; } static int -drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, +drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, uint32_t stride) { - 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_set_tiling set_tiling; - int ret; + 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_set_tiling set_tiling; + int ret; - if (bo_gem->global_name == 0 && *tiling_mode == bo_gem->tiling_mode) - return 0; + if (bo_gem->global_name == 0 && *tiling_mode == bo_gem->tiling_mode) + return 0; - /* If we're going from non-tiling to tiling, bump fence count */ - if (bo_gem->tiling_mode == I915_TILING_NONE) - bo_gem->reloc_tree_fences++; + memset(&set_tiling, 0, sizeof(set_tiling)); + set_tiling.handle = bo_gem->gem_handle; - memset(&set_tiling, 0, sizeof(set_tiling)); - set_tiling.handle = bo_gem->gem_handle; - set_tiling.tiling_mode = *tiling_mode; - set_tiling.stride = stride; + do { + set_tiling.tiling_mode = *tiling_mode; + set_tiling.stride = stride; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling); - if (ret != 0) { - *tiling_mode = bo_gem->tiling_mode; - return -errno; - } - bo_gem->tiling_mode = set_tiling.tiling_mode; - bo_gem->swizzle_mode = set_tiling.swizzle_mode; + ret = ioctl(bufmgr_gem->fd, + DRM_IOCTL_I915_GEM_SET_TILING, + &set_tiling); + } while (ret == -1 && errno == EINTR); + bo_gem->tiling_mode = set_tiling.tiling_mode; + bo_gem->swizzle_mode = set_tiling.swizzle_mode; - /* If we're going from tiling to non-tiling, drop fence count */ - 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; + *tiling_mode = bo_gem->tiling_mode; + return ret == 0 ? 0 : -errno; } static int -drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode) +drm_intel_gem_bo_get_tiling(drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; - *tiling_mode = bo_gem->tiling_mode; - *swizzle_mode = bo_gem->swizzle_mode; - return 0; + *tiling_mode = bo_gem->tiling_mode; + *swizzle_mode = bo_gem->swizzle_mode; + return 0; } static int -drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t *name) +drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t * name) { - 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_gem_flink flink; - int ret; - - if (!bo_gem->global_name) { - memset(&flink, 0, sizeof(flink)); - flink.handle = bo_gem->gem_handle; - - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink); - if (ret != 0) - return -errno; - bo_gem->global_name = flink.name; - } - - *name = bo_gem->global_name; - return 0; + 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_gem_flink flink; + int ret; + + if (!bo_gem->global_name) { + memset(&flink, 0, sizeof(flink)); + flink.handle = bo_gem->gem_handle; + + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_GEM_FLINK, &flink); + if (ret != 0) + return -errno; + bo_gem->global_name = flink.name; + bo_gem->reusable = 0; + } + + *name = bo_gem->global_name; + return 0; } /** @@ -1100,12 +1475,25 @@ drm_intel_gem_bo_flink(drm_intel_bo *bo, uint32_t *name) void drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; - int i; + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr; - for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { - bufmgr_gem->cache_bucket[i].max_entries = -1; - } + bufmgr_gem->bo_reuse = 1; +} + +/** + * Enable use of fenced reloc type. + * + * New code should enable this to avoid unnecessary fence register + * allocation. If this option is not enabled, all relocs will have fence + * register allocated. + */ +void +drm_intel_bufmgr_gem_enable_fenced_relocs(drm_intel_bufmgr *bufmgr) +{ + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr; + + if (bufmgr_gem->bufmgr.bo_exec == drm_intel_gem_bo_exec2) + bufmgr_gem->fenced_relocs = 1; } /** @@ -1115,20 +1503,22 @@ drm_intel_bufmgr_gem_enable_reuse(drm_intel_bufmgr *bufmgr) static int drm_intel_gem_bo_get_aperture_space(drm_intel_bo *bo) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - int i; - int total = 0; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + int total = 0; - if (bo == NULL || bo_gem->included_in_check_aperture) - return 0; + if (bo == NULL || bo_gem->included_in_check_aperture) + return 0; - total += bo->size; - bo_gem->included_in_check_aperture = 1; + total += bo->size; + bo_gem->included_in_check_aperture = 1; - for (i = 0; i < bo_gem->reloc_count; i++) - total += drm_intel_gem_bo_get_aperture_space(bo_gem->reloc_target_bo[i]); + for (i = 0; i < bo_gem->reloc_count; i++) + total += + drm_intel_gem_bo_get_aperture_space(bo_gem-> + reloc_target_info[i].bo); - return total; + return total; } /** @@ -1140,20 +1530,20 @@ drm_intel_gem_bo_get_aperture_space(drm_intel_bo *bo) * This function over-counts if the same buffer is used multiple times. */ static unsigned int -drm_intel_gem_total_fences(drm_intel_bo **bo_array, int count) +drm_intel_gem_total_fences(drm_intel_bo ** bo_array, int count) { - int i; - unsigned int total = 0; + int i; + unsigned int total = 0; - for (i = 0; i < count; i++) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo_array[i]; + for (i = 0; i < count; i++) { + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo_array[i]; - if (bo_gem == NULL) - continue; + if (bo_gem == NULL) + continue; - total += bo_gem->reloc_tree_fences; - } - return total; + total += bo_gem->reloc_tree_fences; + } + return total; } /** @@ -1163,16 +1553,17 @@ drm_intel_gem_total_fences(drm_intel_bo **bo_array, int count) static void drm_intel_gem_bo_clear_aperture_space_flag(drm_intel_bo *bo) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - int i; + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; - if (bo == NULL || !bo_gem->included_in_check_aperture) - return; + if (bo == NULL || !bo_gem->included_in_check_aperture) + return; - bo_gem->included_in_check_aperture = 0; + bo_gem->included_in_check_aperture = 0; - for (i = 0; i < bo_gem->reloc_count; i++) - drm_intel_gem_bo_clear_aperture_space_flag(bo_gem->reloc_target_bo[i]); + for (i = 0; i < bo_gem->reloc_count; i++) + drm_intel_gem_bo_clear_aperture_space_flag(bo_gem-> + reloc_target_info[i].bo); } /** @@ -1182,15 +1573,15 @@ drm_intel_gem_bo_clear_aperture_space_flag(drm_intel_bo *bo) static unsigned int drm_intel_gem_estimate_batch_space(drm_intel_bo **bo_array, int count) { - int i; - unsigned int total = 0; - - for (i = 0; i < count; i++) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo_array[i]; - if (bo_gem != NULL) - total += bo_gem->reloc_tree_size; - } - return total; + int i; + unsigned int total = 0; + + for (i = 0; i < count; i++) { + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo_array[i]; + if (bo_gem != NULL) + total += bo_gem->reloc_tree_size; + } + return total; } /** @@ -1201,28 +1592,30 @@ drm_intel_gem_estimate_batch_space(drm_intel_bo **bo_array, int count) static unsigned int drm_intel_gem_compute_batch_space(drm_intel_bo **bo_array, int count) { - int i; - unsigned int total = 0; - - for (i = 0; i < count; i++) { - total += drm_intel_gem_bo_get_aperture_space(bo_array[i]); - /* For the first buffer object in the array, we get an accurate count - * back for its reloc_tree size (since nothing had been flagged as - * being counted yet). We can save that value out as a more - * conservative reloc_tree_size that avoids double-counting target - * buffers. Since the first buffer happens to usually be the batch - * buffer in our callers, this can pull us back from doing the tree - * walk on every new batch emit. - */ - if (i == 0) { - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo_array[i]; - bo_gem->reloc_tree_size = total; + int i; + unsigned int total = 0; + + for (i = 0; i < count; i++) { + total += drm_intel_gem_bo_get_aperture_space(bo_array[i]); + /* For the first buffer object in the array, we get an + * accurate count back for its reloc_tree size (since nothing + * had been flagged as being counted yet). We can save that + * value out as a more conservative reloc_tree_size that + * avoids double-counting target buffers. Since the first + * buffer happens to usually be the batch buffer in our + * callers, this can pull us back from doing the tree + * walk on every new batch emit. + */ + if (i == 0) { + drm_intel_bo_gem *bo_gem = + (drm_intel_bo_gem *) bo_array[i]; + bo_gem->reloc_tree_size = total; + } } - } - for (i = 0; i < count; i++) - drm_intel_gem_bo_clear_aperture_space_flag(bo_array[i]); - return total; + for (i = 0; i < count; i++) + drm_intel_gem_bo_clear_aperture_space_flag(bo_array[i]); + return total; } /** @@ -1244,32 +1637,77 @@ drm_intel_gem_compute_batch_space(drm_intel_bo **bo_array, int count) static int drm_intel_gem_check_aperture_space(drm_intel_bo **bo_array, int count) { - drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo_array[0]->bufmgr; - unsigned int total = 0; - unsigned int threshold = bufmgr_gem->gtt_size * 3 / 4; - int total_fences; - - /* Check for fence reg constraints if necessary */ - if (bufmgr_gem->available_fences) { - total_fences = drm_intel_gem_total_fences(bo_array, count); - if (total_fences > bufmgr_gem->available_fences) - return -1; - } - - total = drm_intel_gem_estimate_batch_space(bo_array, count); - - if (total > threshold) - total = drm_intel_gem_compute_batch_space(bo_array, count); - - if (total > threshold) { - DBG("check_space: overflowed available aperture, %dkb vs %dkb\n", - total / 1024, (int)bufmgr_gem->gtt_size / 1024); - return -1; - } else { - DBG("drm_check_space: total %dkb vs bufgr %dkb\n", total / 1024 , - (int)bufmgr_gem->gtt_size / 1024); + drm_intel_bufmgr_gem *bufmgr_gem = + (drm_intel_bufmgr_gem *) bo_array[0]->bufmgr; + unsigned int total = 0; + unsigned int threshold = bufmgr_gem->gtt_size * 3 / 4; + int total_fences; + + /* Check for fence reg constraints if necessary */ + if (bufmgr_gem->available_fences) { + total_fences = drm_intel_gem_total_fences(bo_array, count); + if (total_fences > bufmgr_gem->available_fences) + return -ENOSPC; + } + + total = drm_intel_gem_estimate_batch_space(bo_array, count); + + if (total > threshold) + total = drm_intel_gem_compute_batch_space(bo_array, count); + + if (total > threshold) { + DBG("check_space: overflowed available aperture, " + "%dkb vs %dkb\n", + total / 1024, (int)bufmgr_gem->gtt_size / 1024); + return -ENOSPC; + } else { + DBG("drm_check_space: total %dkb vs bufgr %dkb\n", total / 1024, + (int)bufmgr_gem->gtt_size / 1024); + return 0; + } +} + +/* + * Disable buffer reuse for objects which are shared with the kernel + * as scanout buffers + */ +static int +drm_intel_gem_bo_disable_reuse(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + + bo_gem->reusable = 0; + return 0; +} + +static int +_drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo; + int i; + + for (i = 0; i < bo_gem->reloc_count; i++) { + if (bo_gem->reloc_target_info[i].bo == target_bo) + return 1; + if (_drm_intel_gem_bo_references(bo_gem->reloc_target_info[i].bo, + target_bo)) + return 1; + } + + return 0; +} + +/** Return true if target_bo is referenced by bo's relocation tree. */ +static int +drm_intel_gem_bo_references(drm_intel_bo *bo, drm_intel_bo *target_bo) +{ + drm_intel_bo_gem *target_bo_gem = (drm_intel_bo_gem *) target_bo; + + if (bo == NULL || target_bo == NULL) + return 0; + if (target_bo_gem->used_as_reloc_target) + return _drm_intel_gem_bo_references(bo, target_bo); return 0; - } } /** @@ -1281,85 +1719,123 @@ drm_intel_gem_check_aperture_space(drm_intel_bo **bo_array, int count) drm_intel_bufmgr * drm_intel_bufmgr_gem_init(int fd, int batch_size) { - drm_intel_bufmgr_gem *bufmgr_gem; - struct drm_i915_gem_get_aperture aperture; - drm_i915_getparam_t gp; - int ret, i; - unsigned long size; - - bufmgr_gem = calloc(1, sizeof(*bufmgr_gem)); - bufmgr_gem->fd = fd; - - if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) { - free(bufmgr_gem); - return NULL; - } - - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); - - if (ret == 0) - bufmgr_gem->gtt_size = aperture.aper_available_size; - else { - fprintf(stderr, "DRM_IOCTL_I915_GEM_APERTURE failed: %s\n", - strerror(errno)); - bufmgr_gem->gtt_size = 128 * 1024 * 1024; - fprintf(stderr, "Assuming %dkB available aperture size.\n" - "May lead to reduced performance or incorrect rendering.\n", - (int)bufmgr_gem->gtt_size / 1024); - } - - gp.param = I915_PARAM_CHIPSET_ID; - gp.value = &bufmgr_gem->pci_device; - ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); - if (ret) { - fprintf(stderr, "get chip id failed: %d\n", ret); - fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); - } - - if (!IS_I965G(bufmgr_gem)) { - gp.param = I915_PARAM_NUM_FENCES_AVAIL; - gp.value = &bufmgr_gem->available_fences; + drm_intel_bufmgr_gem *bufmgr_gem; + struct drm_i915_gem_get_aperture aperture; + drm_i915_getparam_t gp; + int ret, i; + unsigned long size; + + bufmgr_gem = calloc(1, sizeof(*bufmgr_gem)); + if (bufmgr_gem == NULL) + return NULL; + + bufmgr_gem->fd = fd; + + if (pthread_mutex_init(&bufmgr_gem->lock, NULL) != 0) { + free(bufmgr_gem); + return NULL; + } + + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_GET_APERTURE, &aperture); + + if (ret == 0) + bufmgr_gem->gtt_size = aperture.aper_available_size; + else { + fprintf(stderr, "DRM_IOCTL_I915_GEM_APERTURE failed: %s\n", + strerror(errno)); + bufmgr_gem->gtt_size = 128 * 1024 * 1024; + fprintf(stderr, "Assuming %dkB available aperture size.\n" + "May lead to reduced performance or incorrect " + "rendering.\n", + (int)bufmgr_gem->gtt_size / 1024); + } + + gp.param = I915_PARAM_CHIPSET_ID; + gp.value = &bufmgr_gem->pci_device; ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); if (ret) { - fprintf(stderr, "get fences failed: %d\n", ret); - fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); - bufmgr_gem->available_fences = 0; + fprintf(stderr, "get chip id failed: %d [%d]\n", ret, errno); + fprintf(stderr, "param: %d, val: %d\n", gp.param, *gp.value); + } + + if (IS_GEN2(bufmgr_gem)) + bufmgr_gem->gen = 2; + else if (IS_GEN3(bufmgr_gem)) + bufmgr_gem->gen = 3; + else if (IS_GEN4(bufmgr_gem)) + bufmgr_gem->gen = 4; + else + bufmgr_gem->gen = 6; + + if (bufmgr_gem->gen < 4) { + gp.param = I915_PARAM_NUM_FENCES_AVAIL; + gp.value = &bufmgr_gem->available_fences; + ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GETPARAM, &gp); + if (ret) { + fprintf(stderr, "get fences failed: %d [%d]\n", ret, + errno); + fprintf(stderr, "param: %d, val: %d\n", gp.param, + *gp.value); + bufmgr_gem->available_fences = 0; + } else { + /* XXX The kernel reports the total number of fences, + * including any that may be pinned. + * + * We presume that there will be at least one pinned + * fence for the scanout buffer, but there may be more + * than one scanout and the user may be manually + * pinning buffers. Let's move to execbuffer2 and + * thereby forget the insanity of using fences... + */ + bufmgr_gem->available_fences -= 2; + if (bufmgr_gem->available_fences < 0) + bufmgr_gem->available_fences = 0; + } } - } - - /* Let's go with one relocation per every 2 dwords (but round down a bit - * since a power of two will mean an extra page allocation for the reloc - * buffer). - * - * Every 4 was too few for the blender benchmark. - */ - bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2; - - 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_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; - bufmgr_gem->bufmgr.bo_unmap = drm_intel_gem_bo_unmap; - bufmgr_gem->bufmgr.bo_subdata = drm_intel_gem_bo_subdata; - bufmgr_gem->bufmgr.bo_get_subdata = drm_intel_gem_bo_get_subdata; - bufmgr_gem->bufmgr.bo_wait_rendering = drm_intel_gem_bo_wait_rendering; - bufmgr_gem->bufmgr.bo_emit_reloc = drm_intel_gem_bo_emit_reloc; - bufmgr_gem->bufmgr.bo_pin = drm_intel_gem_bo_pin; - bufmgr_gem->bufmgr.bo_unpin = drm_intel_gem_bo_unpin; - bufmgr_gem->bufmgr.bo_get_tiling = drm_intel_gem_bo_get_tiling; - bufmgr_gem->bufmgr.bo_set_tiling = drm_intel_gem_bo_set_tiling; - bufmgr_gem->bufmgr.bo_flink = drm_intel_gem_bo_flink; - bufmgr_gem->bufmgr.bo_exec = drm_intel_gem_bo_exec; - bufmgr_gem->bufmgr.destroy = drm_intel_bufmgr_gem_destroy; - bufmgr_gem->bufmgr.debug = 0; - bufmgr_gem->bufmgr.check_aperture_space = drm_intel_gem_check_aperture_space; - /* Initialize the linked lists for BO reuse cache. */ - for (i = 0, size = 4096; i < DRM_INTEL_GEM_BO_BUCKETS; i++, size *= 2) { - DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head); - bufmgr_gem->cache_bucket[i].size = size; - } - - return &bufmgr_gem->bufmgr; -} + /* Let's go with one relocation per every 2 dwords (but round down a bit + * since a power of two will mean an extra page allocation for the reloc + * buffer). + * + * Every 4 was too few for the blender benchmark. + */ + bufmgr_gem->max_relocs = batch_size / sizeof(uint32_t) / 2 - 2; + + 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; + bufmgr_gem->bufmgr.bo_unmap = drm_intel_gem_bo_unmap; + bufmgr_gem->bufmgr.bo_subdata = drm_intel_gem_bo_subdata; + bufmgr_gem->bufmgr.bo_get_subdata = drm_intel_gem_bo_get_subdata; + bufmgr_gem->bufmgr.bo_wait_rendering = drm_intel_gem_bo_wait_rendering; + bufmgr_gem->bufmgr.bo_emit_reloc = drm_intel_gem_bo_emit_reloc; + bufmgr_gem->bufmgr.bo_emit_reloc_fence = drm_intel_gem_bo_emit_reloc_fence; + bufmgr_gem->bufmgr.bo_pin = drm_intel_gem_bo_pin; + bufmgr_gem->bufmgr.bo_unpin = drm_intel_gem_bo_unpin; + bufmgr_gem->bufmgr.bo_get_tiling = drm_intel_gem_bo_get_tiling; + bufmgr_gem->bufmgr.bo_set_tiling = drm_intel_gem_bo_set_tiling; + bufmgr_gem->bufmgr.bo_flink = drm_intel_gem_bo_flink; + bufmgr_gem->bufmgr.bo_exec = drm_intel_gem_bo_exec2; + bufmgr_gem->bufmgr.bo_busy = drm_intel_gem_bo_busy; + bufmgr_gem->bufmgr.bo_madvise = drm_intel_gem_bo_madvise; + bufmgr_gem->bufmgr.destroy = drm_intel_bufmgr_gem_destroy; + bufmgr_gem->bufmgr.debug = 0; + bufmgr_gem->bufmgr.check_aperture_space = + drm_intel_gem_check_aperture_space; + bufmgr_gem->bufmgr.bo_disable_reuse = drm_intel_gem_bo_disable_reuse; + bufmgr_gem->bufmgr.get_pipe_from_crtc_id = + drm_intel_gem_get_pipe_from_crtc_id; + bufmgr_gem->bufmgr.bo_references = drm_intel_gem_bo_references; + + /* Initialize the linked lists for BO reuse cache. */ + for (i = 0, size = 4096; i < DRM_INTEL_GEM_BO_BUCKETS; i++, size *= 2) { + DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head); + bufmgr_gem->cache_bucket[i].size = size; + } + + return &bufmgr_gem->bufmgr; +} diff --git a/lib/libdrm/intel/intel_bufmgr_priv.h b/lib/libdrm/intel/intel_bufmgr_priv.h index 82d87b4cb..fb84e70f3 100644 --- a/lib/libdrm/intel/intel_bufmgr_priv.h +++ b/lib/libdrm/intel/intel_bufmgr_priv.h @@ -40,146 +40,234 @@ * Contains public methods followed by private storage for the buffer manager. */ struct _drm_intel_bufmgr { - /** - * Allocate a buffer object. - * - * 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. - */ - drm_intel_bo *(*bo_alloc)(drm_intel_bufmgr *bufmgr, const char *name, - unsigned long size, unsigned int alignment); - - /** - * Allocate a buffer object, hinting that it will be used as a render target. - * - * This is otherwise the same as bo_alloc. - */ - drm_intel_bo *(*bo_alloc_for_render)(drm_intel_bufmgr *bufmgr, - const char *name, - unsigned long size, - unsigned int alignment); - - /** Takes a reference on a buffer object */ - void (*bo_reference)(drm_intel_bo *bo); - - /** - * Releases a reference on a buffer object, freeing the data if - * rerefences remain. - */ - void (*bo_unreference)(drm_intel_bo *bo); - - /** - * Maps the buffer into userspace. - * - * This function will block waiting for any existing execution on the - * buffer to complete, first. The resulting mapping is available at - * buf->virtual. - */ - int (*bo_map)(drm_intel_bo *bo, int write_enable); - - /** Reduces the refcount on the userspace mapping of the buffer object. */ - int (*bo_unmap)(drm_intel_bo *bo); - - /** - * Write data into an object. - * - * This is an optional function, if missing, - * drm_intel_bo will map/memcpy/unmap. - */ - int (*bo_subdata)(drm_intel_bo *bo, unsigned long offset, - unsigned long size, const void *data); - - /** - * Read data from an object - * - * This is an optional function, if missing, - * drm_intel_bo will map/memcpy/unmap. - */ - int (*bo_get_subdata)(drm_intel_bo *bo, unsigned long offset, - unsigned long size, void *data); - - /** - * Waits for rendering to an object by the GPU to have completed. - * - * This is not required for any access to the BO by bo_map, bo_subdata, etc. - * It is merely a way for the driver to implement glFinish. - */ - void (*bo_wait_rendering)(drm_intel_bo *bo); - - /** - * Tears down the buffer manager instance. - */ - void (*destroy)(drm_intel_bufmgr *bufmgr); - - /** - * Add relocation entry in reloc_buf, which will be updated with the - * target buffer's real offset on on command submission. - * - * Relocations remain in place for the lifetime of the buffer object. - * - * \param bo Buffer to write the relocation into. - * \param offset Byte offset within reloc_bo of the pointer to target_bo. - * \param target_bo Buffer whose offset should be written into the - * relocation entry. - * \param target_offset Constant value to be added to target_bo's offset in - * relocation entry. - * \param read_domains GEM read domains which the buffer will be read into - * by the command that this relocation is part of. - * \param write_domains GEM read domains which the buffer will be dirtied - * in by the command that this relocation is part of. - */ - int (*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); - - /** Executes the command buffer pointed to by bo. */ - int (*bo_exec)(drm_intel_bo *bo, int used, - drm_clip_rect_t *cliprects, int num_cliprects, - int DR4); - - /** - * Pin a buffer to the aperture and fix the offset until unpinned - * - * \param buf Buffer to pin - * \param alignment Required alignment for aperture, in bytes - */ - int (*bo_pin)(drm_intel_bo *bo, uint32_t alignment); - /** - * Unpin a buffer from the aperture, allowing it to be removed - * - * \param buf Buffer to unpin - */ - int (*bo_unpin)(drm_intel_bo *bo); - /** - * Ask that the buffer be placed in tiling mode - * - * \param buf Buffer to set tiling mode for - * \param tiling_mode desired, and returned tiling mode - */ - int (*bo_set_tiling)(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t stride); - /** - * Get the current tiling (and resulting swizzling) mode for the bo. - * - * \param buf Buffer to get tiling mode for - * \param tiling_mode returned tiling mode - * \param swizzle_mode returned swizzling mode - */ - int (*bo_get_tiling)(drm_intel_bo *bo, uint32_t *tiling_mode, - uint32_t *swizzle_mode); - /** - * Create a visible name for a buffer which can be used by other apps - * - * \param buf Buffer to create a name for - * \param name Returned name - */ - int (*bo_flink)(drm_intel_bo *bo, uint32_t *name); - - int (*check_aperture_space)(drm_intel_bo **bo_array, int count); - int debug; /**< Enables verbose debugging printouts */ + /** + * Allocate a buffer object. + * + * Buffer objects are not necessarily initially mapped into CPU virtual + * address space or graphics device aperture. They must be mapped + * 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); + + /** + * Allocate a buffer object, hinting that it will be used as a + * render target. + * + * This is otherwise the same as bo_alloc. + */ + drm_intel_bo *(*bo_alloc_for_render) (drm_intel_bufmgr *bufmgr, + const char *name, + 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); + + /** + * Releases a reference on a buffer object, freeing the data if + * no references remain. + */ + void (*bo_unreference) (drm_intel_bo *bo); + + /** + * Maps the buffer into userspace. + * + * This function will block waiting for any existing execution on the + * buffer to complete, first. The resulting mapping is available at + * buf->virtual. + */ + int (*bo_map) (drm_intel_bo *bo, int write_enable); + + /** + * Reduces the refcount on the userspace mapping of the buffer + * object. + */ + int (*bo_unmap) (drm_intel_bo *bo); + + /** + * Write data into an object. + * + * This is an optional function, if missing, + * drm_intel_bo will map/memcpy/unmap. + */ + int (*bo_subdata) (drm_intel_bo *bo, unsigned long offset, + unsigned long size, const void *data); + + /** + * Read data from an object + * + * This is an optional function, if missing, + * drm_intel_bo will map/memcpy/unmap. + */ + int (*bo_get_subdata) (drm_intel_bo *bo, unsigned long offset, + unsigned long size, void *data); + + /** + * Waits for rendering to an object by the GPU to have completed. + * + * This is not required for any access to the BO by bo_map, + * bo_subdata, etc. It is merely a way for the driver to implement + * glFinish. + */ + void (*bo_wait_rendering) (drm_intel_bo *bo); + + /** + * Tears down the buffer manager instance. + */ + void (*destroy) (drm_intel_bufmgr *bufmgr); + + /** + * Add relocation entry in reloc_buf, which will be updated with the + * target buffer's real offset on on command submission. + * + * Relocations remain in place for the lifetime of the buffer object. + * + * \param bo Buffer to write the relocation into. + * \param offset Byte offset within reloc_bo of the pointer to + * target_bo. + * \param target_bo Buffer whose offset should be written into the + * relocation entry. + * \param target_offset Constant value to be added to target_bo's + * offset in relocation entry. + * \param read_domains GEM read domains which the buffer will be + * read into by the command that this relocation + * is part of. + * \param write_domains GEM read domains which the buffer will be + * dirtied in by the command that this + * relocation is part of. + */ + int (*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 (*bo_emit_reloc_fence)(drm_intel_bo *bo, uint32_t offset, + drm_intel_bo *target_bo, + uint32_t target_offset, + uint32_t read_domains, + uint32_t write_domain); + + /** Executes the command buffer pointed to by bo. */ + int (*bo_exec) (drm_intel_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4); + + /** + * Pin a buffer to the aperture and fix the offset until unpinned + * + * \param buf Buffer to pin + * \param alignment Required alignment for aperture, in bytes + */ + int (*bo_pin) (drm_intel_bo *bo, uint32_t alignment); + + /** + * Unpin a buffer from the aperture, allowing it to be removed + * + * \param buf Buffer to unpin + */ + int (*bo_unpin) (drm_intel_bo *bo); + + /** + * Ask that the buffer be placed in tiling mode + * + * \param buf Buffer to set tiling mode for + * \param tiling_mode desired, and returned tiling mode + */ + int (*bo_set_tiling) (drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t stride); + + /** + * Get the current tiling (and resulting swizzling) mode for the bo. + * + * \param buf Buffer to get tiling mode for + * \param tiling_mode returned tiling mode + * \param swizzle_mode returned swizzling mode + */ + int (*bo_get_tiling) (drm_intel_bo *bo, uint32_t * tiling_mode, + uint32_t * swizzle_mode); + + /** + * Create a visible name for a buffer which can be used by other apps + * + * \param buf Buffer to create a name for + * \param name Returned name + */ + int (*bo_flink) (drm_intel_bo *bo, uint32_t * name); + + /** + * Returns 1 if mapping the buffer for write could cause the process + * to block, due to the object being active in the GPU. + */ + int (*bo_busy) (drm_intel_bo *bo); + + /** + * Specify the volatility of the buffer. + * \param bo Buffer to create a name for + * \param madv The purgeable status + * + * Use I915_MADV_DONTNEED to mark the buffer as purgeable, and it will be + * reclaimed under memory pressure. If you subsequently require the buffer, + * then you must pass I915_MADV_WILLNEED to mark the buffer as required. + * + * Returns 1 if the buffer was retained, or 0 if it was discarded whilst + * marked as I915_MADV_DONTNEED. + */ + int (*bo_madvise) (drm_intel_bo *bo, int madv); + + int (*check_aperture_space) (drm_intel_bo ** bo_array, int count); + + /** + * Disable buffer reuse for buffers which will be shared in some way, + * as with scanout buffers. When the buffer reference count goes to + * zero, it will be freed and not placed in the reuse list. + * + * \param bo Buffer to disable reuse for + */ + int (*bo_disable_reuse) (drm_intel_bo *bo); + + /** + * + * Return the pipe associated with a crtc_id so that vblank + * synchronization can use the correct data in the request. + * This is only supported for KMS and gem at this point, when + * unsupported, this function returns -1 and leaves the decision + * of what to do in that case to the caller + * + * \param bufmgr the associated buffer manager + * \param crtc_id the crtc identifier + */ + int (*get_pipe_from_crtc_id) (drm_intel_bufmgr *bufmgr, int crtc_id); + + /** Returns true if target_bo is in the relocation tree rooted at bo. */ + int (*bo_references) (drm_intel_bo *bo, drm_intel_bo *target_bo); + + /**< Enables verbose debugging printouts */ + int debug; }; -#endif /* INTEL_BUFMGR_PRIV_H */ +#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 */ diff --git a/lib/libdrm/intel/intel_chipset.h b/lib/libdrm/intel/intel_chipset.h index 0b3af0236..b4e0747e7 100644 --- a/lib/libdrm/intel/intel_chipset.h +++ b/lib/libdrm/intel/intel_chipset.h @@ -28,44 +28,74 @@ #ifndef _INTEL_CHIPSET_H #define _INTEL_CHIPSET_H -#define IS_I830(dev) ((dev)->pci_device == 0x3577) -#define IS_845G(dev) ((dev)->pci_device == 0x2562) -#define IS_I85X(dev) ((dev)->pci_device == 0x3582) -#define IS_I855(dev) ((dev)->pci_device == 0x3582) -#define IS_I865G(dev) ((dev)->pci_device == 0x2572) +#define IS_830(dev) ((dev)->pci_device == 0x3577) +#define IS_845(dev) ((dev)->pci_device == 0x2562) +#define IS_85X(dev) ((dev)->pci_device == 0x3582) +#define IS_865(dev) ((dev)->pci_device == 0x2572) -#define IS_I915G(dev) ((dev)->pci_device == 0x2582 || (dev)->pci_device == 0x258a) -#define IS_I915GM(dev) ((dev)->pci_device == 0x2592) -#define IS_I945G(dev) ((dev)->pci_device == 0x2772) -#define IS_I945GM(dev) ((dev)->pci_device == 0x27A2 ||\ +#define IS_GEN2(dev) (IS_830(dev) || \ + IS_845(dev) || \ + IS_85X(dev) || \ + IS_865(dev)) + +#define IS_915G(dev) ((dev)->pci_device == 0x2582 || \ + (dev)->pci_device == 0x258a) +#define IS_915GM(dev) ((dev)->pci_device == 0x2592) +#define IS_945G(dev) ((dev)->pci_device == 0x2772) +#define IS_945GM(dev) ((dev)->pci_device == 0x27A2 || \ (dev)->pci_device == 0x27AE) -#define IS_I965G(dev) ((dev)->pci_device == 0x2972 || \ - (dev)->pci_device == 0x2982 || \ - (dev)->pci_device == 0x2992 || \ - (dev)->pci_device == 0x29A2 || \ - (dev)->pci_device == 0x2A02 || \ - (dev)->pci_device == 0x2A12 || \ - (dev)->pci_device == 0x2A42 || \ - (dev)->pci_device == 0x2E02 || \ - (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22) + +#define IS_915(dev) (IS_915G(dev) || \ + IS_915GM(dev)) + +#define IS_945(dev) (IS_945G(dev) || \ + IS_945GM(dev) || \ + IS_G33(dev) || \ + IS_PINEVIEW(dev)) + +#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ + (dev)->pci_device == 0x29B2 || \ + (dev)->pci_device == 0x29D2) + +#define IS_PINEVIEW(dev) ((dev)->pci_device == 0xa001 || \ + (dev)->pci_device == 0xa011) + +#define IS_GEN3(dev) (IS_915(dev) || \ + IS_945(dev) || \ + IS_G33(dev) || \ + IS_PINEVIEW(dev)) #define IS_I965GM(dev) ((dev)->pci_device == 0x2A02) +#define IS_GEN4(dev) ((dev)->pci_device == 0x2972 || \ + (dev)->pci_device == 0x2982 || \ + (dev)->pci_device == 0x2992 || \ + (dev)->pci_device == 0x29A2 || \ + (dev)->pci_device == 0x2A02 || \ + (dev)->pci_device == 0x2A12 || \ + (dev)->pci_device == 0x2A42 || \ + (dev)->pci_device == 0x2E02 || \ + (dev)->pci_device == 0x2E12 || \ + (dev)->pci_device == 0x2E22 || \ + (dev)->pci_device == 0x2E32 || \ + (dev)->pci_device == 0x2E42 || \ + (dev)->pci_device == 0x0042 || \ + (dev)->pci_device == 0x0046 || \ + IS_I965GM(dev) || \ + IS_G4X(dev)) + #define IS_GM45(dev) ((dev)->pci_device == 0x2A42) #define IS_G4X(dev) ((dev)->pci_device == 0x2E02 || \ (dev)->pci_device == 0x2E12 || \ - (dev)->pci_device == 0x2E22) - -#define IS_G33(dev) ((dev)->pci_device == 0x29C2 || \ - (dev)->pci_device == 0x29B2 || \ - (dev)->pci_device == 0x29D2) - -#define IS_I9XX(dev) (IS_I915G(dev) || IS_I915GM(dev) || IS_I945G(dev) || \ - IS_I945GM(dev) || IS_I965G(dev) || IS_G33(dev)) + (dev)->pci_device == 0x2E22 || \ + (dev)->pci_device == 0x2E32 || \ + (dev)->pci_device == 0x2E42 || \ + IS_GM45(dev)) -#define IS_MOBILE(dev) (IS_I830(dev) || IS_I85X(dev) || IS_I915GM(dev) || \ - IS_I945GM(dev) || IS_I965GM(dev) || IS_GM45(dev)) +#define IS_9XX(dev) (IS_GEN3(dev) || \ + IS_GEN4(dev) || \ + IS_GEN5(dev) || \ + IS_GEN6(dev)) #endif /* _INTEL_CHIPSET_H */ diff --git a/lib/libdrm/intel/mm.c b/lib/libdrm/intel/mm.c index 98146405a..106974525 100644 --- a/lib/libdrm/intel/mm.c +++ b/lib/libdrm/intel/mm.c @@ -28,254 +28,244 @@ #include "xf86drm.h" #include "mm.h" -void -mmDumpMemInfo(const struct mem_block *heap) +void mmDumpMemInfo(const struct mem_block *heap) { - drmMsg("Memory heap %p:\n", (void *)heap); - if (heap == 0) { - drmMsg(" heap == 0\n"); - } else { - const struct mem_block *p; - - for(p = heap->next; p != heap; p = p->next) { - drmMsg(" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, - p->free ? 'F':'.', - p->reserved ? 'R':'.'); - } - - drmMsg("\nFree list:\n"); - - for(p = heap->next_free; p != heap; p = p->next_free) { - drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size, - p->free ? 'F':'.', - p->reserved ? 'R':'.'); - } - - } - drmMsg("End of memory blocks\n"); + drmMsg("Memory heap %p:\n", (void *)heap); + if (heap == 0) { + drmMsg(" heap == 0\n"); + } else { + const struct mem_block *p; + + for (p = heap->next; p != heap; p = p->next) { + drmMsg(" Offset:%08x, Size:%08x, %c%c\n", p->ofs, + p->size, p->free ? 'F' : '.', + p->reserved ? 'R' : '.'); + } + + drmMsg("\nFree list:\n"); + + for (p = heap->next_free; p != heap; p = p->next_free) { + drmMsg(" FREE Offset:%08x, Size:%08x, %c%c\n", p->ofs, + p->size, p->free ? 'F' : '.', + p->reserved ? 'R' : '.'); + } + + } + drmMsg("End of memory blocks\n"); } -struct mem_block * -mmInit(int ofs, int size) +struct mem_block *mmInit(int ofs, int size) { - struct mem_block *heap, *block; - - if (size <= 0) - return NULL; - - heap = (struct mem_block *) calloc(1, sizeof(struct mem_block)); - if (!heap) - return NULL; - - block = (struct mem_block *) calloc(1, sizeof(struct mem_block)); - if (!block) { - free(heap); - return NULL; - } - - heap->next = block; - heap->prev = block; - heap->next_free = block; - heap->prev_free = block; - - block->heap = heap; - block->next = heap; - block->prev = heap; - block->next_free = heap; - block->prev_free = heap; - - block->ofs = ofs; - block->size = size; - block->free = 1; - - return heap; -} + struct mem_block *heap, *block; + if (size <= 0) + return NULL; -static struct mem_block * -SliceBlock(struct mem_block *p, - int startofs, int size, - int reserved, int alignment) -{ - struct mem_block *newblock; - - /* break left [p, newblock, p->next], then p = newblock */ - if (startofs > p->ofs) { - newblock = (struct mem_block*) calloc(1, sizeof(struct mem_block)); - if (!newblock) - return NULL; - newblock->ofs = startofs; - newblock->size = p->size - (startofs - p->ofs); - newblock->free = 1; - newblock->heap = p->heap; - - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - - newblock->next_free = p->next_free; - newblock->prev_free = p; - p->next_free->prev_free = newblock; - p->next_free = newblock; - - p->size -= newblock->size; - p = newblock; - } - - /* break right, also [p, newblock, p->next] */ - if (size < p->size) { - newblock = (struct mem_block*) calloc(1, sizeof(struct mem_block)); - if (!newblock) - return NULL; - newblock->ofs = startofs + size; - newblock->size = p->size - size; - newblock->free = 1; - newblock->heap = p->heap; - - newblock->next = p->next; - newblock->prev = p; - p->next->prev = newblock; - p->next = newblock; - - newblock->next_free = p->next_free; - newblock->prev_free = p; - p->next_free->prev_free = newblock; - p->next_free = newblock; - - p->size = size; - } - - /* p = middle block */ - p->free = 0; - - /* Remove p from the free list: - */ - p->next_free->prev_free = p->prev_free; - p->prev_free->next_free = p->next_free; - - p->next_free = 0; - p->prev_free = 0; - - p->reserved = reserved; - return p; + heap = (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!heap) + return NULL; + + block = (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!block) { + free(heap); + return NULL; + } + + heap->next = block; + heap->prev = block; + heap->next_free = block; + heap->prev_free = block; + + block->heap = heap; + block->next = heap; + block->prev = heap; + block->next_free = heap; + block->prev_free = heap; + + block->ofs = ofs; + block->size = size; + block->free = 1; + + return heap; } +static struct mem_block *SliceBlock(struct mem_block *p, + int startofs, int size, + int reserved, int alignment) +{ + struct mem_block *newblock; + + /* break left [p, newblock, p->next], then p = newblock */ + if (startofs > p->ofs) { + newblock = + (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!newblock) + return NULL; + newblock->ofs = startofs; + newblock->size = p->size - (startofs - p->ofs); + newblock->free = 1; + newblock->heap = p->heap; + + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + + newblock->next_free = p->next_free; + newblock->prev_free = p; + p->next_free->prev_free = newblock; + p->next_free = newblock; + + p->size -= newblock->size; + p = newblock; + } + + /* break right, also [p, newblock, p->next] */ + if (size < p->size) { + newblock = + (struct mem_block *)calloc(1, sizeof(struct mem_block)); + if (!newblock) + return NULL; + newblock->ofs = startofs + size; + newblock->size = p->size - size; + newblock->free = 1; + newblock->heap = p->heap; + + newblock->next = p->next; + newblock->prev = p; + p->next->prev = newblock; + p->next = newblock; + + newblock->next_free = p->next_free; + newblock->prev_free = p; + p->next_free->prev_free = newblock; + p->next_free = newblock; + + p->size = size; + } + + /* p = middle block */ + p->free = 0; + + /* Remove p from the free list: + */ + p->next_free->prev_free = p->prev_free; + p->prev_free->next_free = p->next_free; + + p->next_free = 0; + p->prev_free = 0; + + p->reserved = reserved; + return p; +} -struct mem_block * -mmAllocMem(struct mem_block *heap, int size, int align2, int startSearch) +struct mem_block *mmAllocMem(struct mem_block *heap, int size, int align2, + int startSearch) { - struct mem_block *p; - const int mask = (1 << align2)-1; - int startofs = 0; - int endofs; + struct mem_block *p; + const int mask = (1 << align2) - 1; + int startofs = 0; + int endofs; - if (!heap || align2 < 0 || size <= 0) - return NULL; + if (!heap || align2 < 0 || size <= 0) + return NULL; - for (p = heap->next_free; p != heap; p = p->next_free) { - assert(p->free); + for (p = heap->next_free; p != heap; p = p->next_free) { + assert(p->free); - startofs = (p->ofs + mask) & ~mask; - if ( startofs < startSearch ) { - startofs = startSearch; - } - endofs = startofs+size; - if (endofs <= (p->ofs+p->size)) - break; - } + startofs = (p->ofs + mask) & ~mask; + if (startofs < startSearch) { + startofs = startSearch; + } + endofs = startofs + size; + if (endofs <= (p->ofs + p->size)) + break; + } - if (p == heap) - return NULL; + if (p == heap) + return NULL; - assert(p->free); - p = SliceBlock(p,startofs,size,0,mask+1); + assert(p->free); + p = SliceBlock(p, startofs, size, 0, mask + 1); - return p; + return p; } - -struct mem_block * -mmFindBlock(struct mem_block *heap, int start) +struct mem_block *mmFindBlock(struct mem_block *heap, int start) { - struct mem_block *p; + struct mem_block *p; - for (p = heap->next; p != heap; p = p->next) { - if (p->ofs == start) - return p; - } + for (p = heap->next; p != heap; p = p->next) { + if (p->ofs == start) + return p; + } - return NULL; + return NULL; } - -static int -Join2Blocks(struct mem_block *p) +static int Join2Blocks(struct mem_block *p) { - /* XXX there should be some assertions here */ + /* XXX there should be some assertions here */ + + /* NOTE: heap->free == 0 */ - /* NOTE: heap->free == 0 */ + if (p->free && p->next->free) { + struct mem_block *q = p->next; - if (p->free && p->next->free) { - struct mem_block *q = p->next; + assert(p->ofs + p->size == q->ofs); + p->size += q->size; - assert(p->ofs + p->size == q->ofs); - p->size += q->size; + p->next = q->next; + q->next->prev = p; - p->next = q->next; - q->next->prev = p; + q->next_free->prev_free = q->prev_free; + q->prev_free->next_free = q->next_free; - q->next_free->prev_free = q->prev_free; - q->prev_free->next_free = q->next_free; - - free(q); - return 1; - } - return 0; + free(q); + return 1; + } + return 0; } -int -mmFreeMem(struct mem_block *b) +int mmFreeMem(struct mem_block *b) { - if (!b) - return 0; - - if (b->free) { - drmMsg("block already free\n"); - return -1; - } - if (b->reserved) { - drmMsg("block is reserved\n"); - return -1; - } - - b->free = 1; - b->next_free = b->heap->next_free; - b->prev_free = b->heap; - b->next_free->prev_free = b; - b->prev_free->next_free = b; - - Join2Blocks(b); - if (b->prev != b->heap) - Join2Blocks(b->prev); - - return 0; + if (!b) + return 0; + + if (b->free) { + drmMsg("block already free\n"); + return -1; + } + if (b->reserved) { + drmMsg("block is reserved\n"); + return -1; + } + + b->free = 1; + b->next_free = b->heap->next_free; + b->prev_free = b->heap; + b->next_free->prev_free = b; + b->prev_free->next_free = b; + + Join2Blocks(b); + if (b->prev != b->heap) + Join2Blocks(b->prev); + + return 0; } - -void -mmDestroy(struct mem_block *heap) +void mmDestroy(struct mem_block *heap) { - struct mem_block *p; + struct mem_block *p; - if (!heap) - return; + if (!heap) + return; - for (p = heap->next; p != heap; ) { - struct mem_block *next = p->next; - free(p); - p = next; - } + for (p = heap->next; p != heap;) { + struct mem_block *next = p->next; + free(p); + p = next; + } - free(heap); + free(heap); } diff --git a/lib/libdrm/intel/mm.h b/lib/libdrm/intel/mm.h index 49e3eecc5..8a5235b08 100644 --- a/lib/libdrm/intel/mm.h +++ b/lib/libdrm/intel/mm.h @@ -21,23 +21,21 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - /** * Memory manager code. Primarily used by device drivers to manage texture * heaps, etc. */ - #ifndef MM_H #define MM_H struct mem_block { - struct mem_block *next, *prev; - struct mem_block *next_free, *prev_free; - struct mem_block *heap; - int ofs,size; - unsigned int free:1; - unsigned int reserved:1; + struct mem_block *next, *prev; + struct mem_block *next_free, *prev_free; + struct mem_block *heap; + int ofs, size; + unsigned int free:1; + unsigned int reserved:1; }; /* Rename the variables in the drm copy of this code so that it doesn't @@ -67,7 +65,7 @@ extern struct mem_block *mmInit(int ofs, int size); * return: pointer to the allocated block, 0 if error */ extern struct mem_block *mmAllocMem(struct mem_block *heap, int size, - int align2, int startSearch); + int align2, int startSearch); /** * Free block starts at offset diff --git a/lib/libdrm/intel/shlib_version b/lib/libdrm/intel/shlib_version index 893819d18..c8860078e 100644 --- a/lib/libdrm/intel/shlib_version +++ b/lib/libdrm/intel/shlib_version @@ -1,2 +1,2 @@ major=1 -minor=1 +minor=2 diff --git a/lib/libdrm/shlib_version b/lib/libdrm/shlib_version index c87e1c60d..c29621c83 100644 --- a/lib/libdrm/shlib_version +++ b/lib/libdrm/shlib_version @@ -1,2 +1,2 @@ major=2 -minor=4 +minor=5 diff --git a/lib/libdrm/xf86drm.c b/lib/libdrm/xf86drm.c index 83a985a8f..7c3bb3929 100644 --- a/lib/libdrm/xf86drm.c +++ b/lib/libdrm/xf86drm.c @@ -221,22 +221,22 @@ static int drmMatchBusID(const char *id1, const char *id2) /* Try to match old/new-style PCI bus IDs. */ if (strncasecmp(id1, "pci", 3) == 0) { - int o1, b1, d1, f1; - int o2, b2, d2, f2; + unsigned int o1, b1, d1, f1; + unsigned int o2, b2, d2, f2; int ret; - ret = sscanf(id1, "pci:%04x:%02x:%02x.%d", &o1, &b1, &d1, &f1); + ret = sscanf(id1, "pci:%04x:%02x:%02x.%u", &o1, &b1, &d1, &f1); if (ret != 4) { o1 = 0; - ret = sscanf(id1, "PCI:%d:%d:%d", &b1, &d1, &f1); + ret = sscanf(id1, "PCI:%u:%u:%u", &b1, &d1, &f1); if (ret != 3) return 0; } - ret = sscanf(id2, "pci:%04x:%02x:%02x.%d", &o2, &b2, &d2, &f2); + ret = sscanf(id2, "pci:%04x:%02x:%02x.%u", &o2, &b2, &d2, &f2); if (ret != 4) { o2 = 0; - ret = sscanf(id2, "PCI:%d:%d:%d", &b2, &d2, &f2); + ret = sscanf(id2, "PCI:%u:%u:%u", &b2, &d2, &f2); if (ret != 3) return 0; } @@ -2388,24 +2388,54 @@ void drmCloseOnce(int fd) } } -#ifdef NOTYET int drmSetMaster(int fd) { +#ifdef NOTYET int ret; fprintf(stderr,"Setting master \n"); ret = ioctl(fd, DRM_IOCTL_SET_MASTER, 0); return ret; +#endif + return 0; } int drmDropMaster(int fd) { +#ifdef NOTYET int ret; fprintf(stderr,"Dropping master \n"); ret = ioctl(fd, DRM_IOCTL_DROP_MASTER, 0); return ret; -} #endif + return 0; +} + +char *drmGetDeviceNameFromFd(int fd) +{ + char name[128]; + struct stat sbuf; + dev_t d; + int i; + + /* The whole drmOpen thing is a fiasco and we need to find a way + * back to just using open(2). For now, however, lets just make + * things worse with even more ad hoc directory walking code to + * discover the device file name. */ + + fstat(fd, &sbuf); + d = sbuf.st_rdev; + + for (i = 0; i < DRM_MAX_MINOR; i++) { + snprintf(name, sizeof name, DRM_DEV_NAME, DRM_DIR_NAME, i); + if (stat(name, &sbuf) == 0 && sbuf.st_rdev == d) + break; + } + if (i == DRM_MAX_MINOR) + return NULL; + + return drmStrdup(name); +} #ifdef X_PRIVSEP static int diff --git a/lib/libdrm/xf86drm.h b/lib/libdrm/xf86drm.h index e3b50a435..d3e118b74 100644 --- a/lib/libdrm/xf86drm.h +++ b/lib/libdrm/xf86drm.h @@ -272,6 +272,7 @@ typedef struct _drmTextureRegion { typedef enum { DRM_VBLANK_ABSOLUTE = 0x0, /**< Wait for specific vblank sequence number */ DRM_VBLANK_RELATIVE = 0x1, /**< Wait for given number of vblanks */ + DRM_VBLANK_EVENT = 0x4000000, /**< Send event instead of blocking */ DRM_VBLANK_FLIP = 0x8000000, /**< Scheduled buffer swap should flip */ DRM_VBLANK_NEXTONMISS = 0x10000000, /**< If missed, wait for next vblank */ DRM_VBLANK_SECONDARY = 0x20000000, /**< Secondary display controller */ @@ -668,4 +669,6 @@ extern void drmMsg(const char *format, ...); extern int drmSetMaster(int fd); extern int drmDropMaster(int fd); +extern char *drmGetDeviceNameFromFd(int fd); + #endif diff --git a/lib/libdrm/xf86drmMode.c b/lib/libdrm/xf86drmMode.c index ea11207ec..88b4fe3af 100644 --- a/lib/libdrm/xf86drmMode.c +++ b/lib/libdrm/xf86drmMode.c @@ -116,6 +116,9 @@ void drmModeFreeConnector(drmModeConnectorPtr ptr) if (!ptr) return; + drmFree(ptr->encoders); + drmFree(ptr->prop_values); + drmFree(ptr->props); drmFree(ptr->modes); drmFree(ptr); diff --git a/lib/libdrm/xf86drmSL.c b/lib/libdrm/xf86drmSL.c index 58aefac71..acddb5411 100644 --- a/lib/libdrm/xf86drmSL.c +++ b/lib/libdrm/xf86drmSL.c @@ -265,11 +265,8 @@ int drmSLLookupNeighbors(void *l, unsigned long key, { SkipListPtr list = (SkipListPtr)l; SLEntryPtr update[SL_MAX_LEVEL + 1]; - SLEntryPtr entry; int retcode = 0; - entry = SLLocate(list, key, update); - *prev_key = *next_key = key; *prev_value = *next_value = NULL; |