util: add generic ringbuffer utitilty
authorKeith Whitwell <keithw@vmware.com>
Sat, 16 Jan 2010 21:11:01 +0000 (21:11 +0000)
committerKeith Whitwell <keithw@vmware.com>
Sat, 16 Jan 2010 21:15:55 +0000 (21:15 +0000)
src/gallium/auxiliary/Makefile
src/gallium/auxiliary/SConscript
src/gallium/auxiliary/util/u_ringbuffer.c [new file with mode: 0644]
src/gallium/auxiliary/util/u_ringbuffer.h [new file with mode: 0644]

index e3af41c6e04486f77da9e6f039c06d511fa7fb6e..8f937e3b4e9dbdab946b93394dbaa624fbf95d30 100644 (file)
@@ -111,6 +111,7 @@ C_SOURCES = \
        util/u_math.c \
        util/u_mm.c \
        util/u_rect.c \
+       util/u_ringbuffer.c \
        util/u_simple_shaders.c \
        util/u_snprintf.c \
        util/u_stream_stdc.c \
index 782eb5338636bc836f65305d2a57e1d1e7eb0a19..f957090b5fb1ebf6a5da4e9b0c12ddaa4b3ccfd2 100644 (file)
@@ -147,6 +147,7 @@ source = [
     'util/u_math.c',
     'util/u_mm.c',
     'util/u_rect.c',
+    'util/u_ringbuffer.c',
     'util/u_simple_shaders.c',
     'util/u_snprintf.c',
     'util/u_stream_stdc.c',
diff --git a/src/gallium/auxiliary/util/u_ringbuffer.c b/src/gallium/auxiliary/util/u_ringbuffer.c
new file mode 100644 (file)
index 0000000..3f43a19
--- /dev/null
@@ -0,0 +1,145 @@
+
+#include "pipe/p_thread.h"
+#include "pipe/p_defines.h"
+#include "util/u_ringbuffer.h"
+#include "util/u_math.h"
+#include "util/u_memory.h"
+
+/* Generic ringbuffer: 
+ */
+struct util_ringbuffer 
+{
+   struct util_packet *buf;
+   unsigned mask;
+
+   /* Can this be done with atomic variables??
+    */
+   unsigned head;
+   unsigned tail;
+   pipe_condvar change;
+   pipe_mutex mutex;
+};
+
+
+struct util_ringbuffer *util_ringbuffer_create( unsigned dwords )
+{
+   struct util_ringbuffer *ring = CALLOC_STRUCT(util_ringbuffer);
+   if (ring == NULL)
+      return NULL;
+
+   assert(util_is_power_of_two(dwords));
+   
+   ring->buf = MALLOC( dwords * sizeof(unsigned) );
+   if (ring->buf == NULL)
+      goto fail;
+
+   ring->mask = dwords - 1;
+
+   pipe_condvar_init(ring->change);
+   pipe_mutex_init(ring->mutex);
+   return ring;
+
+fail:
+   FREE(ring->buf);
+   FREE(ring);
+   return NULL;
+}
+
+void util_ringbuffer_destroy( struct util_ringbuffer *ring )
+{
+   pipe_condvar_destroy(ring->change);
+   pipe_mutex_destroy(ring->mutex);
+   FREE(ring->buf);
+   FREE(ring);
+}
+
+static INLINE unsigned util_ringbuffer_space( const struct util_ringbuffer *ring )
+{
+   return (ring->tail - (ring->head + 1)) & ring->mask;
+}
+
+void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
+                              const struct util_packet *packet )
+{
+   unsigned i;
+
+   /* XXX: over-reliance on mutexes, etc:
+    */
+   pipe_mutex_lock(ring->mutex);
+
+   /* Wait for free space:
+    */
+   while (util_ringbuffer_space(ring) < packet->dwords)
+      pipe_condvar_wait(ring->change, ring->mutex);
+
+   /* Copy data to ring:
+    */
+   for (i = 0; i < packet->dwords; i++) {
+
+      /* Copy all dwords of the packet.  Note we're abusing the
+       * typesystem a little - we're being passed a pointer to
+       * something, but probably not an array of packet structs:
+       */
+      ring->buf[ring->head] = packet[i];
+      ring->head++;
+      ring->head &= ring->mask;
+   }
+
+   /* Signal change:
+    */
+   pipe_condvar_signal(ring->change);
+   pipe_mutex_unlock(ring->mutex);
+}
+
+enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
+                                         struct util_packet *packet,
+                                         unsigned max_dwords,
+                                         boolean wait )
+{
+   const struct util_packet *ring_packet;
+   unsigned i;
+   int ret = PIPE_OK;
+
+   /* XXX: over-reliance on mutexes, etc:
+    */
+   pipe_mutex_lock(ring->mutex);
+
+   /* Wait for free space:
+    */
+   if (wait) {
+      while (util_ringbuffer_space(ring) == 0)
+         pipe_condvar_wait(ring->change, ring->mutex);
+   }
+   else {
+      if (util_ringbuffer_space(ring) == 0) {
+         ret = PIPE_ERROR_OUT_OF_MEMORY;
+         goto out;
+      }
+   }
+
+   ring_packet = &ring->buf[ring->tail];
+
+   /* Both of these are considered bugs.  Raise an assert on debug builds.
+    */
+   if (ring_packet->dwords > ring->mask + 1 - util_ringbuffer_space(ring) ||
+       ring_packet->dwords > max_dwords) {
+      assert(0);
+      ret = PIPE_ERROR_BAD_INPUT;
+      goto out;
+   }
+
+   /* Copy data from ring:
+    */
+   for (i = 0; i < ring_packet->dwords; i++) {
+      packet[i] = ring->buf[ring->tail];
+      ring->tail++;
+      ring->tail &= ring->mask;
+   }
+
+out:
+   /* Signal change:
+    */
+   pipe_condvar_signal(ring->change);
+   pipe_mutex_unlock(ring->mutex);
+   return ret;
+}
diff --git a/src/gallium/auxiliary/util/u_ringbuffer.h b/src/gallium/auxiliary/util/u_ringbuffer.h
new file mode 100644 (file)
index 0000000..85f0ad6
--- /dev/null
@@ -0,0 +1,29 @@
+
+#ifndef UTIL_RINGBUFFER_H
+#define UTIL_RINGBUFFER_H
+
+#include "pipe/p_compiler.h"
+#include "pipe/p_defines.h"       /* only for pipe_error! */
+
+/* Generic header
+ */
+struct util_packet {
+   unsigned dwords:8;
+   unsigned data24:24;
+};
+
+struct util_ringbuffer;
+
+struct util_ringbuffer *util_ringbuffer_create( unsigned dwords );
+
+void util_ringbuffer_destroy( struct util_ringbuffer *ring );
+
+void util_ringbuffer_enqueue( struct util_ringbuffer *ring,
+                              const struct util_packet *packet );
+
+enum pipe_error util_ringbuffer_dequeue( struct util_ringbuffer *ring,
+                                         struct util_packet *packet,
+                                         unsigned max_dwords,
+                                         boolean wait );
+
+#endif