gallium: new, unified pipe_context::set_sampler_views() function
[mesa.git] / src / gallium / auxiliary / vl / vl_vlc.h
index e17eae83fb3a993675cbfb9cf3a7524b55d2af84..0dc1df98fb8af2a64a9d648dbc1fcb603ad66044 100644 (file)
  *
  **************************************************************************/
 
+/*
+ * Functions for fast bitwise access to multiple probably unaligned input buffers
+ */
+
 #ifndef vl_vlc_h
 #define vl_vlc_h
 
-#include <assert.h>
-
-#include <pipe/p_compiler.h>
+#include "pipe/p_compiler.h"
 
-#include <util/u_math.h>
+#include "util/u_math.h"
 #include "util/u_pointer.h"
+#include "util/u_debug.h"
 
 struct vl_vlc
 {
    uint64_t buffer;
-   unsigned valid_bits;
-   uint32_t *data;
-   uint32_t *end;
+   signed invalid_bits;
+   const uint8_t *data;
+   const uint8_t *end;
+
+   unsigned          num_inputs;
+   const void *const *inputs;
+   const unsigned    *sizes;
+   unsigned          bytes_left;
 };
 
 struct vl_vlc_entry
@@ -55,11 +63,17 @@ struct vl_vlc_compressed
    struct vl_vlc_entry entry;
 };
 
+/**
+ * initalize and decompress a lookup table
+ */
 static INLINE void
 vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_vlc_compressed *src, unsigned src_size)
 {
    unsigned i, bits = util_logbase2(dst_size);
 
+   assert(dst && dst_size);
+   assert(src && src_size);
+
    for (i=0;i<dst_size;++i) {
       dst[i].length = 0;
       dst[i].value = 0;
@@ -71,77 +85,168 @@ vl_vlc_init_table(struct vl_vlc_entry *dst, unsigned dst_size, const struct vl_v
    }
 }
 
+/**
+ * switch over to next input buffer
+ */
+static INLINE void
+vl_vlc_next_input(struct vl_vlc *vlc)
+{
+   unsigned len = vlc->sizes[0];
+
+   assert(vlc);
+   assert(vlc->num_inputs);
+
+   vlc->bytes_left -= len;
+
+   vlc->data = vlc->inputs[0];
+   vlc->end = vlc->data + len;
+
+   --vlc->num_inputs;
+   ++vlc->inputs;
+   ++vlc->sizes;
+}
+
+/**
+ * align the data pointer to the next dword
+ */
+static INLINE void
+vl_vlc_align_data_ptr(struct vl_vlc *vlc)
+{
+   /* align the data pointer */
+   while (vlc->data != vlc->end && pointer_to_uintptr(vlc->data) & 3) {
+      vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
+      ++vlc->data;
+      vlc->invalid_bits -= 8;
+   }
+}
+
+/**
+ * fill the bit buffer, so that at least 32 bits are valid
+ */
 static INLINE void
 vl_vlc_fillbits(struct vl_vlc *vlc)
 {
-   if (vlc->valid_bits < 32) {
-      uint32_t value = *vlc->data;
+   assert(vlc);
+
+   /* as long as the buffer needs to be filled */
+   while (vlc->invalid_bits > 0) {
+      unsigned bytes_left = vlc->end - vlc->data;
+
+      /* if this input is depleted */
+      if (bytes_left == 0) {
+
+         if (vlc->num_inputs)
+            /* go on to next input */
+            vl_vlc_next_input(vlc);
+         else
+            /* or give up since we don't have anymore inputs */
+            return;
+
+      } else if (bytes_left >= 4) {
 
-      //assert(vlc->data <= vlc->end);
+         /* enough bytes in buffer, read in a whole dword */
+         uint64_t value = *(const uint32_t*)vlc->data;
 
 #ifndef PIPE_ARCH_BIG_ENDIAN
-      value = util_bswap32(value);
+         value = util_bswap32(value);
 #endif
 
-      vlc->buffer |= (uint64_t)value << (32 - vlc->valid_bits);
-      ++vlc->data;
-      vlc->valid_bits += 32;
+         vlc->buffer |= value << vlc->invalid_bits;
+         vlc->data += 4;
+         vlc->invalid_bits -= 32;
+
+         /* buffer is now definitely filled up avoid the loop test */
+         break;
+
+      } else while (vlc->data < vlc->end) {
+
+         /* not enough bytes left in buffer, read single bytes */
+         vlc->buffer |= (uint64_t)*vlc->data << (24 + vlc->invalid_bits);
+         ++vlc->data;
+         vlc->invalid_bits -= 8;
+      }
    }
 }
 
+/**
+ * initialize vlc structure and start reading from first input buffer
+ */
 static INLINE void
-vl_vlc_init(struct vl_vlc *vlc, const uint8_t *data, unsigned len)
+vl_vlc_init(struct vl_vlc *vlc, unsigned num_inputs,
+            const void *const *inputs, const unsigned *sizes)
 {
+   unsigned i;
+
    assert(vlc);
-   assert(data && len);
+   assert(num_inputs);
 
    vlc->buffer = 0;
-   vlc->valid_bits = 0;
+   vlc->invalid_bits = 32;
+   vlc->num_inputs = num_inputs;
+   vlc->inputs = inputs;
+   vlc->sizes = sizes;
+   vlc->bytes_left = 0;
 
-   /* align the data pointer */
-   while (pointer_to_uintptr(data) & 3) {
-      vlc->buffer |= (uint64_t)*data << (56 - vlc->valid_bits);
-      ++data;
-      --len;
-      vlc->valid_bits += 8;
-   }
-   vlc->data = (uint32_t*)data;
-   vlc->end = (uint32_t*)(data + len);
+   for (i = 0; i < num_inputs; ++i)
+      vlc->bytes_left += sizes[i];
 
+   vl_vlc_next_input(vlc);
+   vl_vlc_align_data_ptr(vlc);
    vl_vlc_fillbits(vlc);
    vl_vlc_fillbits(vlc);
 }
 
+/**
+ * number of bits still valid in bit buffer
+ */
+static INLINE unsigned
+vl_vlc_valid_bits(struct vl_vlc *vlc)
+{
+   return 32 - vlc->invalid_bits;
+}
+
+/**
+ * number of bits left over all inbut buffers
+ */
 static INLINE unsigned
 vl_vlc_bits_left(struct vl_vlc *vlc)
 {
-   signed bytes_left = ((uint8_t*)vlc->end)-((uint8_t*)vlc->data);
-   return bytes_left * 8 + vlc->valid_bits;
+   signed bytes_left = vlc->end - vlc->data;
+   bytes_left += vlc->bytes_left;
+   return bytes_left * 8 + vl_vlc_valid_bits(vlc);
 }
 
+/**
+ * get num_bits from bit buffer without removing them
+ */
 static INLINE unsigned
 vl_vlc_peekbits(struct vl_vlc *vlc, unsigned num_bits)
 {
-   //assert(vlc->valid_bits >= num_bits);
-
+   assert(vl_vlc_valid_bits(vlc) >= num_bits || vlc->data >= vlc->end);
    return vlc->buffer >> (64 - num_bits);
 }
 
+/**
+ * remove num_bits from bit buffer
+ */
 static INLINE void
 vl_vlc_eatbits(struct vl_vlc *vlc, unsigned num_bits)
 {
-   //assert(vlc->valid_bits > num_bits);
+   assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
    vlc->buffer <<= num_bits;
-   vlc->valid_bits -= num_bits;
+   vlc->invalid_bits += num_bits;
 }
 
+/**
+ * get num_bits from bit buffer with removing them
+ */
 static INLINE unsigned
 vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
 {
    unsigned value;
 
-   //assert(vlc->valid_bits >= num_bits);
+   assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
    value = vlc->buffer >> (64 - num_bits);
    vl_vlc_eatbits(vlc, num_bits);
@@ -149,12 +254,15 @@ vl_vlc_get_uimsbf(struct vl_vlc *vlc, unsigned num_bits)
    return value;
 }
 
+/**
+ * treat num_bits as signed value and remove them from bit buffer
+ */
 static INLINE signed
 vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
 {
    signed value;
 
-   //assert(vlc->valid_bits >= num_bits);
+   assert(vl_vlc_valid_bits(vlc) >= num_bits);
 
    value = ((int64_t)vlc->buffer) >> (64 - num_bits);
    vl_vlc_eatbits(vlc, num_bits);
@@ -162,6 +270,9 @@ vl_vlc_get_simsbf(struct vl_vlc *vlc, unsigned num_bits)
    return value;
 }
 
+/**
+ * lookup a value and length in a decompressed table
+ */
 static INLINE int8_t
 vl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned num_bits)
 {
@@ -170,4 +281,61 @@ vl_vlc_get_vlclbf(struct vl_vlc *vlc, const struct vl_vlc_entry *tbl, unsigned n
    return tbl->value;
 }
 
+/**
+ * fast forward search for a specific byte value
+ */
+static INLINE boolean
+vl_vlc_search_byte(struct vl_vlc *vlc, unsigned num_bits, uint8_t value)
+{
+   /* make sure we are on a byte boundary */
+   assert((vl_vlc_valid_bits(vlc) % 8) == 0);
+   assert(num_bits == ~0 || (num_bits % 8) == 0);
+
+   /* deplete the bit buffer */
+   while (vl_vlc_valid_bits(vlc) > 0) {
+
+      if (vl_vlc_peekbits(vlc, 8) == value) {
+         vl_vlc_fillbits(vlc);
+         return TRUE;
+      }
+
+      vl_vlc_eatbits(vlc, 8);
+
+      if (num_bits != ~0) {
+         num_bits -= 8;
+         if (num_bits == 0)
+            return FALSE;
+      }
+   }
+
+   /* deplete the byte buffers */
+   while (1) {
+
+      /* if this input is depleted */
+      if (vlc->data == vlc->end) {
+         if (vlc->num_inputs)
+            /* go on to next input */
+            vl_vlc_next_input(vlc);
+         else
+            /* or give up since we don't have anymore inputs */
+            return FALSE;
+      }
+
+      if (*vlc->data == value) {
+         vl_vlc_align_data_ptr(vlc);
+         vl_vlc_fillbits(vlc);
+         return TRUE;
+      }
+
+      ++vlc->data;
+      if (num_bits != ~0) {
+         num_bits -= 8;
+         if (num_bits == 0) {
+            vl_vlc_align_data_ptr(vlc);
+            return FALSE;
+         }
+      }
+   }
+}
+
 #endif /* vl_vlc_h */