From 0239594fc318c2b55bbfbea27f23218f6d7a4b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristian=20H=C3=B8gsberg?= Date: Tue, 26 Aug 2008 14:28:08 -0400 Subject: [intel_bufmgr_gem] Remember global name when creating buffer from name. --- libdrm/intel/intel_bufmgr_gem.c | 1 + 1 file changed, 1 insertion(+) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 48a47701..8634fdf8 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -369,6 +369,7 @@ intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, bo_gem->refcount = 1; bo_gem->validate_index = -1; bo_gem->gem_handle = open_arg.handle; + bo_gem->global_name = handle; DBG("bo_create_from_handle: %d (%s)\n", handle, bo_gem->name); -- cgit v1.2.3 From 738e36acbce24df0ccadb499c5cf62ccb74f56df Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Fri, 5 Sep 2008 10:35:32 +0100 Subject: Move intel libdrm stuff to libdrm_intel.so dri_bufmgr.h is replaced by intel_bufmgr.h, and several functions are renamed, though the structures and many functions remain dri_bufmgr_* and dri_bo_* --- libdrm/intel/Makefile.am | 7 +- libdrm/intel/intel_bufmgr.c | 192 +++++++++++++++++++++++++++++++++++++ libdrm/intel/intel_bufmgr.h | 114 ++++++++++------------ libdrm/intel/intel_bufmgr_fake.c | 6 +- libdrm/intel/intel_bufmgr_gem.c | 90 +++--------------- libdrm/intel/intel_bufmgr_priv.h | 200 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 464 insertions(+), 145 deletions(-) create mode 100644 libdrm/intel/intel_bufmgr.c create mode 100644 libdrm/intel/intel_bufmgr_priv.h (limited to 'libdrm/intel') diff --git a/libdrm/intel/Makefile.am b/libdrm/intel/Makefile.am index 31a8512a..607c4765 100644 --- a/libdrm/intel/Makefile.am +++ b/libdrm/intel/Makefile.am @@ -25,11 +25,16 @@ AM_CFLAGS = \ $(WARN_CFLAGS) \ -I$(top_srcdir)/libdrm \ + -I$(top_srcdir)/libdrm/intel \ -I$(top_srcdir)/shared-core -noinst_LTLIBRARIES = libdrm_intel.la +libdrm_intel_la_LTLIBRARIES = libdrm_intel.la +libdrm_intel_ladir = $(libdir) +libdrm_intel_la_LDFLAGS = -version-number 1:0:0 -no-undefined libdrm_intel_la_SOURCES = \ + intel_bufmgr.c \ + intel_bufmgr_priv.h \ intel_bufmgr_fake.c \ intel_bufmgr_gem.c \ mm.c \ diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c new file mode 100644 index 00000000..5a9cdbe6 --- /dev/null +++ b/libdrm/intel/intel_bufmgr.c @@ -0,0 +1,192 @@ +/* + * Copyright © 2007 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" + +/** @file dri_bufmgr.c + * + * Convenience functions for buffer management methods. + */ + +dri_bo * +dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size, + unsigned int alignment) +{ + return bufmgr->bo_alloc(bufmgr, name, size, alignment); +} + +void +dri_bo_reference(dri_bo *bo) +{ + bo->bufmgr->bo_reference(bo); +} + +void +dri_bo_unreference(dri_bo *bo) +{ + if (bo == NULL) + return; + + bo->bufmgr->bo_unreference(bo); +} + +int +dri_bo_map(dri_bo *buf, int write_enable) +{ + return buf->bufmgr->bo_map(buf, write_enable); +} + +int +dri_bo_unmap(dri_bo *buf) +{ + return buf->bufmgr->bo_unmap(buf); +} + +int +dri_bo_subdata(dri_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 = dri_bo_map(bo, 1); + if (ret) + return ret; + memcpy((unsigned char *)bo->virtual + offset, data, size); + dri_bo_unmap(bo); + return 0; +} + +int +dri_bo_get_subdata(dri_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 = dri_bo_map(bo, 0); + if (ret) + return ret; + memcpy(data, (unsigned char *)bo->virtual + offset, size); + dri_bo_unmap(bo); + return 0; +} + +void +dri_bo_wait_rendering(dri_bo *bo) +{ + bo->bufmgr->bo_wait_rendering(bo); +} + +void +dri_bufmgr_destroy(dri_bufmgr *bufmgr) +{ + bufmgr->destroy(bufmgr); +} + +void *dri_process_relocs(dri_bo *batch_buf) +{ + return batch_buf->bufmgr->process_relocs(batch_buf); +} + +void dri_post_submit(dri_bo *batch_buf) +{ + batch_buf->bufmgr->post_submit(batch_buf); +} + +void +dri_bufmgr_set_debug(dri_bufmgr *bufmgr, int enable_debug) +{ + bufmgr->debug = enable_debug; +} + +int +dri_bufmgr_check_aperture_space(dri_bo **bo_array, int count) +{ + return bo_array[0]->bufmgr->check_aperture_space(bo_array, count); +} + +int +dri_bo_flink(dri_bo *bo, uint32_t *name) +{ + if (bo->bufmgr->bo_flink) + return bo->bufmgr->bo_flink(bo, name); + + return -ENODEV; +} + +int +dri_bo_emit_reloc(dri_bo *reloc_buf, + uint32_t read_domains, uint32_t write_domain, + uint32_t delta, uint32_t offset, dri_bo *target_buf) +{ + return reloc_buf->bufmgr->bo_emit_reloc(reloc_buf, + read_domains, write_domain, + delta, offset, target_buf); +} + +int +dri_bo_pin(dri_bo *bo, uint32_t alignment) +{ + if (bo->bufmgr->bo_pin) + return bo->bufmgr->bo_pin(bo, alignment); + + return -ENODEV; +} + +int +dri_bo_unpin(dri_bo *bo) +{ + if (bo->bufmgr->bo_unpin) + return bo->bufmgr->bo_unpin(bo); + + return -ENODEV; +} + +int dri_bo_set_tiling(dri_bo *bo, uint32_t *tiling_mode) +{ + if (bo->bufmgr->bo_set_tiling) + return bo->bufmgr->bo_set_tiling(bo, tiling_mode); + + *tiling_mode = I915_TILING_NONE; + return 0; +} diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index 4d335210..0b473f3b 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -31,65 +31,65 @@ * Public definitions of Intel-specific bufmgr functions. */ -#ifndef INTEL_BUFMGR_GEM_H -#define INTEL_BUFMGR_GEM_H +#ifndef INTEL_BUFMGR_H +#define INTEL_BUFMGR_H -#include "dri_bufmgr.h" +#include -/** - * Intel-specific bufmgr bits that follow immediately after the - * generic bufmgr structure. - */ -struct intel_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 reloc_buf Buffer to write the relocation into. - * \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. - * \param delta Constant value to be added to the relocation target's - * offset. - * \param offset Byte offset within batch_buf of the relocated pointer. - * \param target Buffer whose offset should be written into the relocation - * entry. - */ - int (*emit_reloc)(dri_bo *reloc_buf, - uint32_t read_domains, uint32_t write_domain, - uint32_t delta, uint32_t offset, dri_bo *target); - /** - * 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 (*pin) (dri_bo *buf, uint32_t alignment); +typedef struct _dri_bufmgr dri_bufmgr; +typedef struct _dri_bo dri_bo; + +struct _dri_bo { /** - * Unpin a buffer from the aperture, allowing it to be removed + * Size in bytes of the buffer object. * - * \param buf Buffer to unpin + * The size may be larger than the size originally requested for the + * allocation, such as being aligned to page size. */ - int (*unpin) (dri_bo *buf); + unsigned long size; /** - * 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 + * Card virtual address (offset from the beginning of the aperture) for the + * object. Only valid while validated. */ - int (*set_tiling) (dri_bo *bo, uint32_t *tiling_mode); + unsigned long offset; /** - * 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 + * Virtual address for accessing the buffer data. Only valid while mapped. */ - int (*flink) (dri_bo *buf, uint32_t *name); + void *virtual; + + /** Buffer manager context associated with this buffer object */ + dri_bufmgr *bufmgr; }; +dri_bo *dri_bo_alloc(dri_bufmgr *bufmgr, const char *name, unsigned long size, + unsigned int alignment); +void dri_bo_reference(dri_bo *bo); +void dri_bo_unreference(dri_bo *bo); +int dri_bo_map(dri_bo *buf, int write_enable); +int dri_bo_unmap(dri_bo *buf); + +int dri_bo_subdata(dri_bo *bo, unsigned long offset, + unsigned long size, const void *data); +int dri_bo_get_subdata(dri_bo *bo, unsigned long offset, + unsigned long size, void *data); +void dri_bo_wait_rendering(dri_bo *bo); + +void dri_bufmgr_set_debug(dri_bufmgr *bufmgr, int enable_debug); +void dri_bufmgr_destroy(dri_bufmgr *bufmgr); + +void *dri_process_relocs(dri_bo *batch_buf); +void dri_post_process_relocs(dri_bo *batch_buf); +void dri_post_submit(dri_bo *batch_buf); +int dri_bufmgr_check_aperture_space(dri_bo **bo_array, int count); + +int dri_bo_emit_reloc(dri_bo *reloc_buf, + uint32_t read_domains, uint32_t write_domain, + uint32_t delta, uint32_t offset, dri_bo *target_buf); +int dri_bo_pin(dri_bo *buf, uint32_t alignment); +int dri_bo_unpin(dri_bo *buf); +int dri_bo_set_tiling(dri_bo *buf, uint32_t *tiling_mode); +int dri_bo_flink(dri_bo *buf, uint32_t *name); + /* intel_bufmgr_gem.c */ dri_bufmgr *intel_bufmgr_gem_init(int fd, int batch_size); dri_bo *intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, @@ -106,25 +106,13 @@ dri_bufmgr *intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, dri_bo *intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, unsigned long offset, unsigned long size, void *virtual); - -void intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr); void intel_bo_fake_disable_backing_store(dri_bo *bo, void (*invalidate_cb)(dri_bo *bo, void *ptr), void *ptr); -void intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr); - -int intel_bo_emit_reloc(dri_bo *reloc_buf, - uint32_t read_domains, uint32_t write_domain, - uint32_t delta, uint32_t offset, dri_bo *target_buf); - -int intel_bo_pin(dri_bo *buf, uint32_t alignment); - -int intel_bo_unpin(dri_bo *buf); -int intel_bo_set_tiling(dri_bo *buf, uint32_t *tiling_mode); - -int intel_bo_flink(dri_bo *buf, uint32_t *name); +void intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr); +void intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr); -#endif /* INTEL_BUFMGR_GEM_H */ +#endif /* INTEL_BUFMGR_H */ diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index e2dd9dc7..8e581aed 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -37,8 +37,9 @@ #include #include #include -#include "dri_bufmgr.h" +#include #include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" #include "drm.h" #include "i915_drm.h" #include "mm.h" @@ -105,7 +106,6 @@ struct block { typedef struct _bufmgr_fake { dri_bufmgr bufmgr; - struct intel_bufmgr intel_bufmgr; unsigned long low_offset; unsigned long size; @@ -1216,12 +1216,12 @@ intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, bufmgr_fake->bufmgr.bo_map = dri_fake_bo_map; bufmgr_fake->bufmgr.bo_unmap = dri_fake_bo_unmap; bufmgr_fake->bufmgr.bo_wait_rendering = dri_fake_bo_wait_rendering; + bufmgr_fake->bufmgr.bo_emit_reloc = dri_fake_emit_reloc; bufmgr_fake->bufmgr.destroy = dri_fake_destroy; bufmgr_fake->bufmgr.process_relocs = dri_fake_process_relocs; bufmgr_fake->bufmgr.post_submit = dri_fake_post_submit; bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; - bufmgr_fake->intel_bufmgr.emit_reloc = dri_fake_emit_reloc; bufmgr_fake->fence_emit = fence_emit; bufmgr_fake->fence_wait = fence_wait; diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 8634fdf8..43d2d986 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -44,8 +44,8 @@ #include #include "errno.h" -#include "dri_bufmgr.h" #include "intel_bufmgr.h" +#include "intel_bufmgr_priv.h" #include "string.h" #include "i915_drm.h" @@ -76,8 +76,6 @@ struct dri_gem_bo_bucket { typedef struct _dri_bufmgr_gem { dri_bufmgr bufmgr; - struct intel_bufmgr intel_bufmgr; - int fd; int max_relocs; @@ -650,8 +648,8 @@ dri_bufmgr_gem_destroy(dri_bufmgr *bufmgr) * last known offset in target_bo. */ static int -dri_gem_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain, - uint32_t delta, uint32_t offset, dri_bo *target_bo) +dri_gem_bo_emit_reloc(dri_bo *bo, uint32_t read_domains, uint32_t write_domain, + uint32_t delta, uint32_t offset, dri_bo *target_bo) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -775,7 +773,7 @@ dri_gem_post_submit(dri_bo *batch_buf) } static int -dri_gem_pin(dri_bo *bo, uint32_t alignment) +dri_gem_bo_pin(dri_bo *bo, uint32_t alignment) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -794,7 +792,7 @@ dri_gem_pin(dri_bo *bo, uint32_t alignment) } static int -dri_gem_unpin(dri_bo *bo) +dri_gem_bo_unpin(dri_bo *bo) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -811,7 +809,7 @@ dri_gem_unpin(dri_bo *bo) } static int -dri_gem_set_tiling(dri_bo *bo, uint32_t *tiling_mode) +dri_gem_bo_set_tiling(dri_bo *bo, uint32_t *tiling_mode) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -832,7 +830,7 @@ dri_gem_set_tiling(dri_bo *bo, uint32_t *tiling_mode) } static int -dri_gem_flink(dri_bo *bo, uint32_t *name) +dri_gem_bo_flink(dri_bo *bo, uint32_t *name) { dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; dri_bo_gem *bo_gem = (dri_bo_gem *)bo; @@ -910,16 +908,16 @@ intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem->bufmgr.bo_subdata = dri_gem_bo_subdata; bufmgr_gem->bufmgr.bo_get_subdata = dri_gem_bo_get_subdata; bufmgr_gem->bufmgr.bo_wait_rendering = dri_gem_bo_wait_rendering; + bufmgr_gem->bufmgr.bo_emit_reloc = dri_gem_bo_emit_reloc; + bufmgr_gem->bufmgr.bo_pin = dri_gem_bo_pin; + bufmgr_gem->bufmgr.bo_unpin = dri_gem_bo_unpin; + bufmgr_gem->bufmgr.bo_set_tiling = dri_gem_bo_set_tiling; + bufmgr_gem->bufmgr.bo_flink = dri_gem_bo_flink; bufmgr_gem->bufmgr.destroy = dri_bufmgr_gem_destroy; bufmgr_gem->bufmgr.process_relocs = dri_gem_process_reloc; bufmgr_gem->bufmgr.post_submit = dri_gem_post_submit; bufmgr_gem->bufmgr.debug = 0; bufmgr_gem->bufmgr.check_aperture_space = dri_gem_check_aperture_space; - bufmgr_gem->intel_bufmgr.emit_reloc = dri_gem_emit_reloc; - bufmgr_gem->intel_bufmgr.pin = dri_gem_pin; - bufmgr_gem->intel_bufmgr.unpin = dri_gem_unpin; - bufmgr_gem->intel_bufmgr.set_tiling = dri_gem_set_tiling; - bufmgr_gem->intel_bufmgr.flink = dri_gem_flink; /* Initialize the linked lists for BO reuse cache. */ for (i = 0; i < INTEL_GEM_BO_BUCKETS; i++) bufmgr_gem->cache_bucket[i].tail = &bufmgr_gem->cache_bucket[i].head; @@ -927,67 +925,3 @@ intel_bufmgr_gem_init(int fd, int batch_size) return &bufmgr_gem->bufmgr; } -int -intel_bo_emit_reloc(dri_bo *reloc_buf, - uint32_t read_domains, uint32_t write_domain, - uint32_t delta, uint32_t offset, dri_bo *target_buf) -{ - struct intel_bufmgr *intel_bufmgr; - - intel_bufmgr = (struct intel_bufmgr *)(reloc_buf->bufmgr + 1); - - return intel_bufmgr->emit_reloc(reloc_buf, read_domains, write_domain, - delta, offset, target_buf); -} - -int -intel_bo_pin(dri_bo *bo, uint32_t alignment) -{ - struct intel_bufmgr *intel_bufmgr; - - intel_bufmgr = (struct intel_bufmgr *)(bo->bufmgr + 1); - - if (intel_bufmgr->pin) - return intel_bufmgr->pin(bo, alignment); - - return 0; -} - -int -intel_bo_unpin(dri_bo *bo) -{ - struct intel_bufmgr *intel_bufmgr; - - intel_bufmgr = (struct intel_bufmgr *)(bo->bufmgr + 1); - - if (intel_bufmgr->unpin) - return intel_bufmgr->unpin(bo); - - return 0; -} - -int intel_bo_set_tiling(dri_bo *bo, uint32_t *tiling_mode) -{ - struct intel_bufmgr *intel_bufmgr; - - intel_bufmgr = (struct intel_bufmgr *)(bo->bufmgr + 1); - - if (intel_bufmgr->set_tiling) - return intel_bufmgr->set_tiling (bo, tiling_mode); - - *tiling_mode = I915_TILING_NONE; - return 0; -} - -int intel_bo_flink(dri_bo *bo, uint32_t *name) -{ - struct intel_bufmgr *intel_bufmgr; - - intel_bufmgr = (struct intel_bufmgr *)(bo->bufmgr + 1); - - if (intel_bufmgr->flink) - return intel_bufmgr->flink (bo, name); - - return -ENODEV; -} - diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h new file mode 100644 index 00000000..92476aec --- /dev/null +++ b/libdrm/intel/intel_bufmgr_priv.h @@ -0,0 +1,200 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Eric Anholt + * + */ + +/** + * @file intel_bufmgr_priv.h + * + * Private definitions of Intel-specific bufmgr functions and structures. + */ + +#ifndef INTEL_BUFMGR_PRIV_H +#define INTEL_BUFMGR_PRIV_H + +/** + * Context for a buffer manager instance. + * + * Contains public methods followed by private storage for the buffer manager. + */ +struct _dri_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. + */ + dri_bo *(*bo_alloc)(dri_bufmgr *bufmgr_ctx, const char *name, + unsigned long size, unsigned int alignment); + + /** Takes a reference on a buffer object */ + void (*bo_reference)(dri_bo *bo); + + /** + * Releases a reference on a buffer object, freeing the data if + * rerefences remain. + */ + void (*bo_unreference)(dri_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)(dri_bo *buf, int write_enable); + + /** Reduces the refcount on the userspace mapping of the buffer object. */ + int (*bo_unmap)(dri_bo *buf); + + /** + * Write data into an object. + * + * This is an optional function, if missing, + * dri_bo will map/memcpy/unmap. + */ + int (*bo_subdata) (dri_bo *buf, unsigned long offset, + unsigned long size, const void *data); + + /** + * Read data from an object + * + * This is an optional function, if missing, + * dri_bo will map/memcpy/unmap. + */ + int (*bo_get_subdata) (dri_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) (dri_bo *bo); + + /** + * Tears down the buffer manager instance. + */ + void (*destroy)(dri_bufmgr *bufmgr); + + /** + * Processes the relocations, either in userland or by converting the list + * for use in batchbuffer submission. + * + * Kernel-based implementations will return a pointer to the arguments + * to be handed with batchbuffer submission to the kernel. The userland + * implementation performs the buffer validation and emits relocations + * into them the appopriate order. + * + * \param batch_buf buffer at the root of the tree of relocations + * \return argument to be completed and passed to the execbuffers ioctl + * (if any). + */ + void *(*process_relocs)(dri_bo *batch_buf); + + void (*post_submit)(dri_bo *batch_buf); + + /** + * 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 reloc_buf Buffer to write the relocation into. + * \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. + * \param delta Constant value to be added to the relocation target's + * offset. + * \param offset Byte offset within batch_buf of the relocated pointer. + * \param target Buffer whose offset should be written into the relocation + * entry. + */ + int (*bo_emit_reloc)(dri_bo *reloc_buf, + uint32_t read_domains, uint32_t write_domain, + uint32_t delta, uint32_t offset, dri_bo *target); + /** + * 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) (dri_bo *buf, uint32_t alignment); + /** + * Unpin a buffer from the aperture, allowing it to be removed + * + * \param buf Buffer to unpin + */ + int (*bo_unpin) (dri_bo *buf); + /** + * 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) (dri_bo *bo, uint32_t *tiling_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) (dri_bo *buf, uint32_t *name); + + int (*check_aperture_space)(dri_bo **bo_array, int count); + int debug; /**< Enables verbose debugging printouts */ +}; + +/* intel_bufmgr_gem.c */ +dri_bufmgr *intel_bufmgr_gem_init(int fd, int batch_size); +dri_bo *intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, + unsigned int handle); +void intel_bufmgr_gem_enable_reuse(dri_bufmgr *bufmgr); + +/* intel_bufmgr_fake.c */ +dri_bufmgr *intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, + unsigned long size, + unsigned int (*fence_emit)(void *private), + int (*fence_wait)(void *private, + unsigned int cookie), + void *driver_priv); +dri_bo *intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, + unsigned long offset, unsigned long size, + void *virtual); + +void intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr); +void intel_bo_fake_disable_backing_store(dri_bo *bo, + void (*invalidate_cb)(dri_bo *bo, + void *ptr), + void *ptr); +void intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr); + +#endif /* INTEL_BUFMGR_PRIV_H */ + -- cgit v1.2.3 From 869d8bebedddf2075c59d6bffea8ee640cb80353 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Sat, 6 Sep 2008 03:07:41 +0100 Subject: intel: Move IRQ emit/wait from callbacks into the bufmgr. In the process, work around the glaring bugs of the kernel irq wait function. --- libdrm/intel/intel_bufmgr.h | 10 ++--- libdrm/intel/intel_bufmgr_fake.c | 89 ++++++++++++++++++++++++++++++---------- libdrm/intel/intel_bufmgr_priv.h | 24 ----------- 3 files changed, 72 insertions(+), 51 deletions(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index 0b473f3b..57a9e33a 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -97,12 +97,12 @@ dri_bo *intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, void intel_bufmgr_gem_enable_reuse(dri_bufmgr *bufmgr); /* intel_bufmgr_fake.c */ -dri_bufmgr *intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, +dri_bufmgr *intel_bufmgr_fake_init(int fd, + unsigned long low_offset, void *low_virtual, unsigned long size, - unsigned int (*fence_emit)(void *private), - int (*fence_wait)(void *private, - unsigned int cookie), - void *driver_priv); + volatile unsigned int *last_dispatch); +void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, + volatile unsigned int *last_dispatch); dri_bo *intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, unsigned long offset, unsigned long size, void *virtual); diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 8e581aed..47629033 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" @@ -135,17 +136,10 @@ typedef struct _bufmgr_fake { unsigned need_fence:1; int thrashing; - /** - * Driver callback to emit a fence, returning the cookie. - * - * 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. */ - int (*fence_wait)(void *private, unsigned int fence_cookie); - /** Driver-supplied argument to driver callbacks */ - void *driver_priv; + /* Pointer to kernel-updated sarea data for the last completed user irq */ + volatile unsigned int *last_dispatch; + + int fd; int debug; @@ -214,18 +208,64 @@ static int FENCE_LTE( unsigned a, unsigned b ) static unsigned int _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) { - bufmgr_fake->last_fence = bufmgr_fake->fence_emit(bufmgr_fake->driver_priv); + struct drm_i915_irq_emit ie; + int ret, seq = 1; + + 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(); + } + + /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has + * been since it was first introduced. It only checks for + * completed_seq >= seq, and thus returns success early for wrapped irq + * values if the CPU wins a race. + * + * We have to do it up front at emit when we discover wrap, so that another + * client can't race (after we drop the lock) to emit and wait and fail. + */ + if (seq == 0 || seq == 1) { + drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_FLUSH, &ie, sizeof(ie)); + } + + DBG("emit 0x%08x\n", seq); + bufmgr_fake->last_fence = seq; return bufmgr_fake->last_fence; } static void _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) { + struct drm_i915_irq_wait iw; + unsigned int last_dispatch; int ret; - ret = bufmgr_fake->fence_wait(bufmgr_fake->driver_priv, cookie); + DBG("wait 0x%08x\n", iw.irq_seq); + + /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has + * been since it was first introduced. It only checks for + * completed_seq >= seq, and thus never returns for pre-wrapped irq values + * if the GPU wins the race. + * + * So, check if it looks like a pre-wrapped value and just return success. + */ + if (*bufmgr_fake->last_dispatch - cookie > 0x4000000) + return; + + iw.irq_seq = cookie; + + do { + last_dispatch = *bufmgr_fake->last_dispatch; + ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, + &iw, sizeof(iw)); + } while (ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && last_dispatch != *bufmgr_fake->last_dispatch)); + if (ret != 0) { - drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__); + drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); abort(); } clear_fenced(bufmgr_fake, cookie); @@ -540,7 +580,7 @@ dri_bufmgr_fake_wait_idle(dri_bufmgr_fake *bufmgr_fake) { unsigned int cookie; - cookie = bufmgr_fake->fence_emit(bufmgr_fake->driver_priv); + cookie = _fence_emit_internal(bufmgr_fake); _fence_wait_internal(bufmgr_fake, cookie); } @@ -1187,13 +1227,19 @@ intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr) free_block(bufmgr_fake, block); } } +void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, + volatile unsigned int *last_dispatch) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->last_dispatch = last_dispatch; +} dri_bufmgr * -intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, +intel_bufmgr_fake_init(int fd, + unsigned long low_offset, void *low_virtual, unsigned long size, - unsigned int (*fence_emit)(void *private), - int (*fence_wait)(void *private, unsigned int cookie), - void *driver_priv) + volatile unsigned int *last_dispatch) { dri_bufmgr_fake *bufmgr_fake; @@ -1223,9 +1269,8 @@ intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; - bufmgr_fake->fence_emit = fence_emit; - bufmgr_fake->fence_wait = fence_wait; - bufmgr_fake->driver_priv = driver_priv; + bufmgr_fake->fd = fd; + bufmgr_fake->last_dispatch = last_dispatch; return &bufmgr_fake->bufmgr; } diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h index 92476aec..8a5741fa 100644 --- a/libdrm/intel/intel_bufmgr_priv.h +++ b/libdrm/intel/intel_bufmgr_priv.h @@ -172,29 +172,5 @@ struct _dri_bufmgr { int debug; /**< Enables verbose debugging printouts */ }; -/* intel_bufmgr_gem.c */ -dri_bufmgr *intel_bufmgr_gem_init(int fd, int batch_size); -dri_bo *intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, - unsigned int handle); -void intel_bufmgr_gem_enable_reuse(dri_bufmgr *bufmgr); - -/* intel_bufmgr_fake.c */ -dri_bufmgr *intel_bufmgr_fake_init(unsigned long low_offset, void *low_virtual, - unsigned long size, - unsigned int (*fence_emit)(void *private), - int (*fence_wait)(void *private, - unsigned int cookie), - void *driver_priv); -dri_bo *intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, - unsigned long offset, unsigned long size, - void *virtual); - -void intel_bufmgr_fake_contended_lock_take(dri_bufmgr *bufmgr); -void intel_bo_fake_disable_backing_store(dri_bo *bo, - void (*invalidate_cb)(dri_bo *bo, - void *ptr), - void *ptr); -void intel_bufmgr_fake_evict_all(dri_bufmgr *bufmgr); - #endif /* INTEL_BUFMGR_PRIV_H */ -- cgit v1.2.3 From f9d98beefc9e7b8d06a29f5b69a19f10fd3c435f Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 8 Sep 2008 08:51:40 -0700 Subject: intel: move drm calls to exec buffers to libdrm_intel. This avoids duplicating the effort in 3 places. Also, added emit/wait fence callbacks back in bufmgr_fake since we need it for non-drm 2d. Sigh. --- libdrm/intel/intel_bufmgr.c | 12 ++-- libdrm/intel/intel_bufmgr.h | 17 +++-- libdrm/intel/intel_bufmgr_fake.c | 151 +++++++++++++++++++++++++++++---------- libdrm/intel/intel_bufmgr_gem.c | 60 ++++++++-------- libdrm/intel/intel_bufmgr_priv.h | 23 ++---- 5 files changed, 168 insertions(+), 95 deletions(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c index 5a9cdbe6..45b691d6 100644 --- a/libdrm/intel/intel_bufmgr.c +++ b/libdrm/intel/intel_bufmgr.c @@ -123,14 +123,12 @@ dri_bufmgr_destroy(dri_bufmgr *bufmgr) bufmgr->destroy(bufmgr); } -void *dri_process_relocs(dri_bo *batch_buf) -{ - return batch_buf->bufmgr->process_relocs(batch_buf); -} - -void dri_post_submit(dri_bo *batch_buf) +int +dri_bo_exec(dri_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4) { - batch_buf->bufmgr->post_submit(batch_buf); + return bo->bufmgr->bo_exec(bo, used, cliprects, num_cliprects, DR4); } void diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h index 57a9e33a..c44d596b 100644 --- a/libdrm/intel/intel_bufmgr.h +++ b/libdrm/intel/intel_bufmgr.h @@ -76,10 +76,9 @@ void dri_bo_wait_rendering(dri_bo *bo); void dri_bufmgr_set_debug(dri_bufmgr *bufmgr, int enable_debug); void dri_bufmgr_destroy(dri_bufmgr *bufmgr); - -void *dri_process_relocs(dri_bo *batch_buf); -void dri_post_process_relocs(dri_bo *batch_buf); -void dri_post_submit(dri_bo *batch_buf); +int dri_bo_exec(dri_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4); int dri_bufmgr_check_aperture_space(dri_bo **bo_array, int count); int dri_bo_emit_reloc(dri_bo *reloc_buf, @@ -103,6 +102,16 @@ dri_bufmgr *intel_bufmgr_fake_init(int fd, volatile unsigned int *last_dispatch); void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, volatile unsigned int *last_dispatch); +void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr, + int (*exec)(dri_bo *bo, + unsigned int used, + void *priv), + void *priv); +void intel_bufmgr_fake_set_fence_callback(dri_bufmgr *bufmgr, + unsigned int (*emit)(void *priv), + void (*wait)(unsigned int fence, + void *priv), + void *priv); dri_bo *intel_bo_fake_alloc_static(dri_bufmgr *bufmgr, const char *name, unsigned long offset, unsigned long size, void *virtual); diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 47629033..f9e1cd12 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -136,6 +136,31 @@ typedef struct _bufmgr_fake { 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)(dri_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 unsigned int *last_dispatch; @@ -205,12 +230,28 @@ static int FENCE_LTE( unsigned a, unsigned b ) return 0; } +void intel_bufmgr_fake_set_fence_callback(dri_bufmgr *bufmgr, + unsigned int (*emit)(void *priv), + void (*wait)(unsigned int fence, + void *priv), + void *priv) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->fence_emit = emit; + bufmgr_fake->fence_wait = wait; + bufmgr_fake->fence_priv = priv; +} + static unsigned int _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) { struct drm_i915_irq_emit ie; int ret, seq = 1; + if (bufmgr_fake->fence_emit != NULL) + return bufmgr_fake->fence_emit(bufmgr_fake->fence_priv); + ie.irq_seq = &seq; ret = drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_IRQ_EMIT, &ie, sizeof(ie)); @@ -243,6 +284,11 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) unsigned int last_dispatch; int ret; + if (bufmgr_fake->fence_wait != NULL) { + bufmgr_fake->fence_wait(cookie, bufmgr_fake->fence_priv); + return; + } + DBG("wait 0x%08x\n", iw.irq_seq); /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has @@ -1092,38 +1138,6 @@ dri_fake_reloc_and_validate_buffer(dri_bo *bo) return dri_fake_bo_validate(bo); } -static void * -dri_fake_process_relocs(dri_bo *batch_buf) -{ - dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)batch_buf->bufmgr; - dri_bo_fake *batch_fake = (dri_bo_fake *)batch_buf; - int ret; - int retry_count = 0; - - bufmgr_fake->performed_rendering = 0; - - dri_fake_calculate_domains(batch_buf); - - batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; - - /* we've ran out of RAM so blow the whole lot away and retry */ - restart: - ret = dri_fake_reloc_and_validate_buffer(batch_buf); - if (bufmgr_fake->fail == 1) { - if (retry_count == 0) { - retry_count++; - dri_fake_kick_all(bufmgr_fake); - bufmgr_fake->fail = 0; - goto restart; - } else /* dump out the memory here */ - mmDumpMemInfo(bufmgr_fake->heap); - } - - assert(ret == 0); - - return NULL; -} - static void dri_bo_fake_post_submit(dri_bo *bo) { @@ -1150,12 +1164,74 @@ dri_bo_fake_post_submit(dri_bo *bo) } -static void -dri_fake_post_submit(dri_bo *batch_buf) +void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr, + int (*exec)(dri_bo *bo, + unsigned int used, + void *priv), + void *priv) +{ + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; + + bufmgr_fake->exec = exec; + bufmgr_fake->exec_priv = exec; +} + +static int +dri_fake_bo_exec(dri_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4) { - dri_fake_fence_validated(batch_buf->bufmgr); + dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bo->bufmgr; + dri_bo_fake *batch_fake = (dri_bo_fake *)bo; + struct drm_i915_batchbuffer batch; + int ret; + int retry_count = 0; + + bufmgr_fake->performed_rendering = 0; + + dri_fake_calculate_domains(bo); - dri_bo_fake_post_submit(batch_buf); + batch_fake->read_domains = I915_GEM_DOMAIN_COMMAND; + + /* we've ran out of RAM so blow the whole lot away and retry */ + restart: + ret = dri_fake_reloc_and_validate_buffer(bo); + if (bufmgr_fake->fail == 1) { + if (retry_count == 0) { + retry_count++; + dri_fake_kick_all(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) + 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); + return -errno; + } + } + + dri_fake_fence_validated(bo->bufmgr); + + dri_bo_fake_post_submit(bo); + + return 0; } /** @@ -1264,8 +1340,7 @@ intel_bufmgr_fake_init(int fd, bufmgr_fake->bufmgr.bo_wait_rendering = dri_fake_bo_wait_rendering; bufmgr_fake->bufmgr.bo_emit_reloc = dri_fake_emit_reloc; bufmgr_fake->bufmgr.destroy = dri_fake_destroy; - bufmgr_fake->bufmgr.process_relocs = dri_fake_process_relocs; - bufmgr_fake->bufmgr.post_submit = dri_fake_post_submit; + bufmgr_fake->bufmgr.bo_exec = dri_fake_bo_exec; bufmgr_fake->bufmgr.check_aperture_space = dri_fake_check_aperture_space; bufmgr_fake->bufmgr.debug = 0; diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 43d2d986..44152728 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -87,8 +87,6 @@ typedef struct _dri_bufmgr_gem { /** Array of lists of cached gem objects of power-of-two sizes */ struct dri_gem_bo_bucket cache_bucket[INTEL_GEM_BO_BUCKETS]; - - struct drm_i915_gem_execbuffer exec_arg; } dri_bufmgr_gem; struct _dri_bo_gem { @@ -706,27 +704,6 @@ dri_gem_bo_process_reloc(dri_bo *bo) } } -static void * -dri_gem_process_reloc(dri_bo *batch_buf) -{ - dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *) batch_buf->bufmgr; - - /* Update indices and set up the validate list. */ - dri_gem_bo_process_reloc(batch_buf); - - /* Add the batch buffer to the validation list. There are no relocations - * pointing to it. - */ - intel_add_validate_buffer(batch_buf); - - bufmgr_gem->exec_arg.buffers_ptr = (uintptr_t)bufmgr_gem->exec_objects; - bufmgr_gem->exec_arg.buffer_count = bufmgr_gem->exec_count; - bufmgr_gem->exec_arg.batch_start_offset = 0; - bufmgr_gem->exec_arg.batch_len = 0; /* written in intel_exec_ioctl */ - - return &bufmgr_gem->exec_arg; -} - static void intel_update_buffer_offsets (dri_bufmgr_gem *bufmgr_gem) { @@ -746,11 +723,35 @@ intel_update_buffer_offsets (dri_bufmgr_gem *bufmgr_gem) } } -static void -dri_gem_post_submit(dri_bo *batch_buf) +static int +dri_gem_bo_exec(dri_bo *bo, int used, + drm_clip_rect_t *cliprects, int num_cliprects, + int DR4) { - dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)batch_buf->bufmgr; - int i; + dri_bufmgr_gem *bufmgr_gem = (dri_bufmgr_gem *)bo->bufmgr; + struct drm_i915_gem_execbuffer execbuf; + int ret, i; + + /* Update indices and set up the validate list. */ + dri_gem_bo_process_reloc(bo); + + /* Add the batch buffer to the validation list. There are no relocations + * pointing to it. + */ + 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 == -EAGAIN); intel_update_buffer_offsets (bufmgr_gem); @@ -770,6 +771,8 @@ dri_gem_post_submit(dri_bo *batch_buf) bufmgr_gem->exec_bos[i] = NULL; } bufmgr_gem->exec_count = 0; + + return 0; } static int @@ -913,9 +916,8 @@ intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem->bufmgr.bo_unpin = dri_gem_bo_unpin; bufmgr_gem->bufmgr.bo_set_tiling = dri_gem_bo_set_tiling; bufmgr_gem->bufmgr.bo_flink = dri_gem_bo_flink; + bufmgr_gem->bufmgr.bo_exec = dri_gem_bo_exec; bufmgr_gem->bufmgr.destroy = dri_bufmgr_gem_destroy; - bufmgr_gem->bufmgr.process_relocs = dri_gem_process_reloc; - bufmgr_gem->bufmgr.post_submit = dri_gem_post_submit; bufmgr_gem->bufmgr.debug = 0; bufmgr_gem->bufmgr.check_aperture_space = dri_gem_check_aperture_space; /* Initialize the linked lists for BO reuse cache. */ diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h index 8a5741fa..7f39bfc2 100644 --- a/libdrm/intel/intel_bufmgr_priv.h +++ b/libdrm/intel/intel_bufmgr_priv.h @@ -103,23 +103,6 @@ struct _dri_bufmgr { */ void (*destroy)(dri_bufmgr *bufmgr); - /** - * Processes the relocations, either in userland or by converting the list - * for use in batchbuffer submission. - * - * Kernel-based implementations will return a pointer to the arguments - * to be handed with batchbuffer submission to the kernel. The userland - * implementation performs the buffer validation and emits relocations - * into them the appopriate order. - * - * \param batch_buf buffer at the root of the tree of relocations - * \return argument to be completed and passed to the execbuffers ioctl - * (if any). - */ - void *(*process_relocs)(dri_bo *batch_buf); - - void (*post_submit)(dri_bo *batch_buf); - /** * Add relocation entry in reloc_buf, which will be updated with the * target buffer's real offset on on command submission. @@ -140,6 +123,12 @@ struct _dri_bufmgr { int (*bo_emit_reloc)(dri_bo *reloc_buf, uint32_t read_domains, uint32_t write_domain, uint32_t delta, uint32_t offset, dri_bo *target); + + /** Executes the command buffer pointed to by bo. */ + int (*bo_exec)(dri_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 * -- cgit v1.2.3 From 368b392e6dcd19cb75675c0c18d02f70257af1df Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Wed, 10 Sep 2008 13:54:34 -0700 Subject: intel: don't forget to include config.h in bufmgr code. Thanks to airlied for catching this. --- libdrm/intel/intel_bufmgr.c | 4 ++++ libdrm/intel/intel_bufmgr_fake.c | 4 ++++ libdrm/intel/intel_bufmgr_gem.c | 4 ++++ 3 files changed, 12 insertions(+) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c index 45b691d6..fc7284b5 100644 --- a/libdrm/intel/intel_bufmgr.c +++ b/libdrm/intel/intel_bufmgr.c @@ -25,6 +25,10 @@ * */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index f9e1cd12..4b4c2a1b 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -34,6 +34,10 @@ * the bugs in the old texture manager. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 44152728..97e387f5 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -34,6 +34,10 @@ * Dave Airlie */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include -- cgit v1.2.3 From 3949f3c9eaad9547fe046ca4d469fa7cc8f12304 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Mon, 22 Sep 2008 10:16:19 +0800 Subject: intel: Fix driver-supplied argument to exec function (fd.o bug #17653). --- libdrm/intel/intel_bufmgr_fake.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 4b4c2a1b..28c7f6b3 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -1177,7 +1177,7 @@ void intel_bufmgr_fake_set_exec_callback(dri_bufmgr *bufmgr, dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; bufmgr_fake->exec = exec; - bufmgr_fake->exec_priv = exec; + bufmgr_fake->exec_priv = priv; } static int -- cgit v1.2.3 From 1b3abe62b5751d0514d57aa850e584dca7dfc23e Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 23 Sep 2008 10:47:21 -0700 Subject: intel: Do strerror on errno, not on the -1 return value from ioctl. --- libdrm/intel/intel_bufmgr_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 97e387f5..cd36cdc7 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -357,7 +357,7 @@ intel_bo_gem_create_from_name(dri_bufmgr *bufmgr, const char *name, 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(-ret)); + name, handle, strerror(errno)); free(bo_gem); return NULL; } @@ -401,7 +401,7 @@ dri_gem_bo_free(dri_bo *bo) if (ret != 0) { fprintf(stderr, "DRM_IOCTL_GEM_CLOSE %d failed (%s): %s\n", - bo_gem->gem_handle, bo_gem->name, strerror(-ret)); + bo_gem->gem_handle, bo_gem->name, strerror(errno)); } free(bo); } -- cgit v1.2.3 From 0dccf017ab629d69fce91e18b013882ecb45f55d Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 23 Sep 2008 10:48:39 -0700 Subject: intel: Replace wraparound test logic in bufmgr_fake. Again. I'd swapped the operands, so if we weren't in lockstep with the hardware we said the sequence was always passed. Additionally, a race was available that we might have failed at recovering from. Instead, I've replaced the logic with new stuff that should be more robust and not rely on all the parties in userland following the same IRQ_EMIT() == 1 protocol. Also, in a radical departure from past efforts, include a long comment describing the failure modes and how we're working around them. Thanks to haihao for catching the original issue. --- libdrm/intel/intel_bufmgr_fake.c | 115 ++++++++++++++++++++++++++++----------- 1 file changed, 84 insertions(+), 31 deletions(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index 28c7f6b3..e26d46c1 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -166,7 +166,7 @@ typedef struct _bufmgr_fake { /** Driver-supplied argument to driver callbacks */ void *driver_priv; /* Pointer to kernel-updated sarea data for the last completed user irq */ - volatile unsigned int *last_dispatch; + volatile int *last_dispatch; int fd; @@ -264,61 +264,114 @@ _fence_emit_internal(dri_bufmgr_fake *bufmgr_fake) abort(); } - /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has - * been since it was first introduced. It only checks for - * completed_seq >= seq, and thus returns success early for wrapped irq - * values if the CPU wins a race. - * - * We have to do it up front at emit when we discover wrap, so that another - * client can't race (after we drop the lock) to emit and wait and fail. - */ - if (seq == 0 || seq == 1) { - drmCommandWriteRead(bufmgr_fake->fd, DRM_I915_FLUSH, &ie, sizeof(ie)); - } - DBG("emit 0x%08x\n", seq); bufmgr_fake->last_fence = seq; return bufmgr_fake->last_fence; } static void -_fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, unsigned int cookie) +_fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) { struct drm_i915_irq_wait iw; - unsigned int last_dispatch; + int hw_seq; int ret; + int kernel_lied; if (bufmgr_fake->fence_wait != NULL) { - bufmgr_fake->fence_wait(cookie, bufmgr_fake->fence_priv); + bufmgr_fake->fence_wait(seq, bufmgr_fake->fence_priv); return; } DBG("wait 0x%08x\n", iw.irq_seq); - /* The kernel implementation of IRQ_WAIT is broken for wraparound, and has - * been since it was first introduced. It only checks for - * completed_seq >= seq, and thus never returns for pre-wrapped irq values - * if the GPU wins the race. + 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. * - * So, check if it looks like a pre-wrapped value and just return success. + * 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. */ - if (*bufmgr_fake->last_dispatch - cookie > 0x4000000) - return; + 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; - iw.irq_seq = cookie; + /* Catch case C */ + if (seq - hw_seq > 0x40000000) + return; - do { - last_dispatch = *bufmgr_fake->last_dispatch; ret = drmCommandWrite(bufmgr_fake->fd, DRM_I915_IRQ_WAIT, &iw, sizeof(iw)); - } while (ret == -EAGAIN || ret == -EINTR || - (ret == -EBUSY && last_dispatch != *bufmgr_fake->last_dispatch)); + /* 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; + } while (kernel_lied || ret == -EAGAIN || ret == -EINTR || + (ret == -EBUSY && hw_seq != *bufmgr_fake->last_dispatch)); if (ret != 0) { drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); abort(); } - clear_fenced(bufmgr_fake, cookie); + clear_fenced(bufmgr_fake, seq); } static int @@ -1312,7 +1365,7 @@ void intel_bufmgr_fake_set_last_dispatch(dri_bufmgr *bufmgr, { dri_bufmgr_fake *bufmgr_fake = (dri_bufmgr_fake *)bufmgr; - bufmgr_fake->last_dispatch = last_dispatch; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; } dri_bufmgr * @@ -1349,7 +1402,7 @@ intel_bufmgr_fake_init(int fd, bufmgr_fake->bufmgr.debug = 0; bufmgr_fake->fd = fd; - bufmgr_fake->last_dispatch = last_dispatch; + bufmgr_fake->last_dispatch = (volatile int *)last_dispatch; return &bufmgr_fake->bufmgr; } -- cgit v1.2.3 From 2db8e0c8ef8c7a66460fceda129533b364f6418c Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 23 Sep 2008 17:06:01 -0700 Subject: intel: Allow up to 15 seconds chewing on one buffer before acknowledging -EBUSY. The gltestperf demo in some cases took over seven seconds to make it through one batchbuffer on a GM965. Bug #17004. --- libdrm/intel/intel_bufmgr_fake.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'libdrm/intel') diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c index e26d46c1..a5b183aa 100644 --- a/libdrm/intel/intel_bufmgr_fake.c +++ b/libdrm/intel/intel_bufmgr_fake.c @@ -273,7 +273,7 @@ static void _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) { struct drm_i915_irq_wait iw; - int hw_seq; + int hw_seq, busy_count = 0; int ret; int kernel_lied; @@ -343,7 +343,17 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) * 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 @@ -364,11 +374,18 @@ _fence_wait_internal(dri_bufmgr_fake *bufmgr_fake, int seq) /* 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 && hw_seq != *bufmgr_fake->last_dispatch)); + (ret == -EBUSY && busy_count < 5)); if (ret != 0) { - drmMsg("%s:%d: Error %d waiting for fence.\n", __FILE__, __LINE__, ret); + drmMsg("%s:%d: Error waiting for fence: %s.\n", __FILE__, __LINE__, + strerror(-ret)); abort(); } clear_fenced(bufmgr_fake, seq); -- cgit v1.2.3