diff options
-rw-r--r-- | configure.ac | 17 | ||||
-rw-r--r-- | libdrm/intel/Makefile.am | 1 | ||||
-rw-r--r-- | libdrm/intel/intel_atomic.h | 59 | ||||
-rw-r--r-- | libdrm/intel/intel_bufmgr_gem.c | 128 |
4 files changed, 141 insertions, 64 deletions
diff --git a/configure.ac b/configure.ac index d7070529..2852962e 100644 --- a/configure.ac +++ b/configure.ac @@ -146,6 +146,23 @@ if test "x$HAVE_LIBUDEV" = xyes; then fi AM_CONDITIONAL(HAVE_LIBUDEV, [test "x$HAVE_LIBUDEV" = xyes]) +# Check for atomic intrinsics +AC_CACHE_CHECK([for native atomic primitives], drm_cv_atomic_primitives, +[ + drm_cv_atomic_primitives="none" + + AC_TRY_LINK([ +int atomic_add(int i) { return __sync_fetch_and_add (&i, 1); } +int atomic_cmpxchg(int i, int j, int k) { return __sync_val_compare_and_swap (&i, j, k); } +], [], + drm_cv_atomic_primitives="Intel" + ) +]) +if test "x$drm_cv_atomic_primitives" = xIntel; then + AC_DEFINE(HAVE_INTEL_ATOMIC_PRIMITIVES, 1, + [Enable if your compiler supports the Intel __sync_* atomic primitives]) +fi + AC_SUBST(WARN_CFLAGS) AC_OUTPUT([ Makefile diff --git a/libdrm/intel/Makefile.am b/libdrm/intel/Makefile.am index e68a3b46..28f8952b 100644 --- a/libdrm/intel/Makefile.am +++ b/libdrm/intel/Makefile.am @@ -35,6 +35,7 @@ libdrm_intel_la_LDFLAGS = -version-number 1:0:0 -no-undefined libdrm_intel_la_LIBADD = ../libdrm.la @PTHREADSTUBS_LIBS@ @CLOCK_LIB@ libdrm_intel_la_SOURCES = \ + intel_atomic.h \ intel_bufmgr.c \ intel_bufmgr_priv.h \ intel_bufmgr_fake.c \ diff --git a/libdrm/intel/intel_atomic.h b/libdrm/intel/intel_atomic.h new file mode 100644 index 00000000..562394a7 --- /dev/null +++ b/libdrm/intel/intel_atomic.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2009 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: + * Chris Wilson <chris@chris-wilson.co.uk> + * + */ + +/** + * @file intel_atomics.h + * + * Private definitions for atomic operations + */ + +#ifndef INTEL_ATOMICS_H +#define INTEL_ATOMICS_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_INTEL_ATOMIC_PRIMITIVES + +#define HAS_ATOMIC_OPS 1 + +typedef struct { int atomic; } atomic_t; + +# define atomic_read(x) ((x)->atomic) +# define atomic_set(x, val) ((x)->atomic = (val)) +# define atomic_inc(x) ((void) __sync_fetch_and_add (&(x)->atomic, 1)) +# define atomic_dec_and_test(x) (__sync_fetch_and_add (&(x)->atomic, -1) == 1) +# define atomic_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (&(x)->atomic, oldv, newv) + +#endif + +#if ! HAS_ATOMIC_OPS +#error libdrm-intel requires atomic operations, please define them for your CPU/compiler. +#endif + +#endif diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c index 902c1ed7..ce3cbabd 100644 --- a/libdrm/intel/intel_bufmgr_gem.c +++ b/libdrm/intel/intel_bufmgr_gem.c @@ -53,6 +53,7 @@ #include "errno.h" #include "libdrm_lists.h" +#include "intel_atomic.h" #include "intel_bufmgr.h" #include "intel_bufmgr_priv.h" #include "intel_chipset.h" @@ -102,7 +103,7 @@ typedef struct _drm_intel_bufmgr_gem { struct _drm_intel_bo_gem { drm_intel_bo bo; - int refcount; + atomic_t refcount; /** Boolean whether the mmap ioctl has been called for this buffer yet. */ uint32_t gem_handle; const char *name; @@ -172,8 +173,6 @@ struct _drm_intel_bo_gem { int reloc_tree_fences; }; -static void drm_intel_gem_bo_reference_locked(drm_intel_bo *bo); - static unsigned int drm_intel_gem_estimate_batch_space(drm_intel_bo **bo_array, int count); @@ -189,6 +188,9 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, uint32_t stride); static void +drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo); + +static void drm_intel_gem_bo_unreference(drm_intel_bo *bo); static void @@ -237,6 +239,15 @@ static void drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) } } +static void +drm_intel_gem_bo_reference(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + + assert(atomic_read(&bo_gem->refcount) > 0); + atomic_inc(&bo_gem->refcount); +} + /** * Adds the given buffer to the list of buffers to be validated (moved into the * appropriate memory type) with the next batch submission. @@ -280,7 +291,7 @@ drm_intel_add_validate_buffer(drm_intel_bo *bo) bufmgr_gem->exec_objects[index].alignment = 0; bufmgr_gem->exec_objects[index].offset = 0; bufmgr_gem->exec_bos[index] = bo; - drm_intel_gem_bo_reference_locked(bo); + drm_intel_gem_bo_reference(bo); bufmgr_gem->exec_count++; } @@ -436,7 +447,7 @@ retry: } bo_gem->name = name; - bo_gem->refcount = 1; + atomic_set(&bo_gem->refcount, 1); bo_gem->validate_index = -1; bo_gem->reloc_tree_size = bo_gem->bo.size; bo_gem->reloc_tree_fences = 0; @@ -499,7 +510,7 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, const char *name, bo_gem->bo.virtual = NULL; bo_gem->bo.bufmgr = bufmgr; bo_gem->name = name; - bo_gem->refcount = 1; + atomic_set (&bo_gem->refcount, 1); bo_gem->validate_index = -1; bo_gem->gem_handle = open_arg.handle; bo_gem->global_name = handle; @@ -525,27 +536,6 @@ drm_intel_bo_gem_create_from_name(drm_intel_bufmgr *bufmgr, const char *name, } 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; - - assert(bo_gem->refcount > 0); - pthread_mutex_lock(&bufmgr_gem->lock); - bo_gem->refcount++; - pthread_mutex_unlock(&bufmgr_gem->lock); -} - -static void -drm_intel_gem_bo_reference_locked(drm_intel_bo *bo) -{ - drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - - assert(bo_gem->refcount > 0); - bo_gem->refcount++; -} - -static void drm_intel_gem_bo_free(drm_intel_bo *bo) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; @@ -597,60 +587,70 @@ drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time) } static void -drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) +drm_intel_gem_bo_unreference_final(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_intel_gem_bo_bucket *bucket; + uint32_t tiling_mode; - assert(bo_gem->refcount > 0); - if (--bo_gem->refcount == 0) { - struct drm_intel_gem_bo_bucket *bucket; - uint32_t tiling_mode; - - if (bo_gem->relocs != NULL) { - 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]); - } + /* 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]); + } - DBG("bo_unreference final: %d (%s)\n", - bo_gem->gem_handle, bo_gem->name); + DBG("bo_unreference final: %d (%s)\n", + bo_gem->gem_handle, bo_gem->name); - bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size); - /* Put the buffer into our internal cache for reuse if we can. */ - tiling_mode = I915_TILING_NONE; - if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL && - drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0) - { - struct timespec time; + bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo->size); + /* Put the buffer into our internal cache for reuse if we can. */ + tiling_mode = I915_TILING_NONE; + if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL && + drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0) + { + struct timespec time; - clock_gettime(CLOCK_MONOTONIC, &time); - bo_gem->free_time = time.tv_sec; + clock_gettime(CLOCK_MONOTONIC, &time); + bo_gem->free_time = time.tv_sec; - bo_gem->name = NULL; - bo_gem->validate_index = -1; - bo_gem->reloc_count = 0; + bo_gem->name = NULL; + bo_gem->validate_index = -1; + bo_gem->reloc_count = 0; - DRMLISTADDTAIL(&bo_gem->head, &bucket->head); + DRMLISTADDTAIL(&bo_gem->head, &bucket->head); - drm_intel_gem_bo_madvise(bufmgr_gem, bo_gem, I915_MADV_DONTNEED); - drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec); - } else { - drm_intel_gem_bo_free(bo); - } + drm_intel_gem_bo_madvise(bufmgr_gem, bo_gem, I915_MADV_DONTNEED); + drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec); + } else { + drm_intel_gem_bo_free(bo); } } static void +drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) +{ + drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; + + assert(atomic_read(&bo_gem->refcount) > 0); + if (atomic_dec_and_test (&bo_gem->refcount)) + drm_intel_gem_bo_unreference_final(bo); +} + +static void drm_intel_gem_bo_unreference(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; - pthread_mutex_lock(&bufmgr_gem->lock); - drm_intel_gem_bo_unreference_locked(bo); - pthread_mutex_unlock(&bufmgr_gem->lock); + assert(atomic_read(&bo_gem->refcount) > 0); + if (atomic_dec_and_test (&bo_gem->refcount)) { + drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; + pthread_mutex_lock(&bufmgr_gem->lock); + drm_intel_gem_bo_unreference_final(bo); + pthread_mutex_unlock(&bufmgr_gem->lock); + } } static int @@ -1017,7 +1017,7 @@ drm_intel_gem_bo_emit_reloc(drm_intel_bo *bo, uint32_t offset, bo_gem->relocs[bo_gem->reloc_count].presumed_offset = target_bo->offset; bo_gem->reloc_target_bo[bo_gem->reloc_count] = target_bo; - drm_intel_gem_bo_reference_locked(target_bo); + drm_intel_gem_bo_reference(target_bo); bo_gem->reloc_count++; |