formats: Use a hash table for _mesa_format_from_array_format
authorJason Ekstrand <jason.ekstrand@intel.com>
Mon, 12 Jan 2015 22:43:34 +0000 (14:43 -0800)
committerJason Ekstrand <jason.ekstrand@intel.com>
Thu, 22 Jan 2015 18:35:43 +0000 (10:35 -0800)
Going through the for loop every time has noticable overhead.  This fixes
things up so we only do that once ever and then just do a hash table lookup
which should be much cheaper.

v2 Jason Ekstrand <jason.ekstrand@intel.com>:
 - Use once_flag and call_once from c11/threads.h instead of pthreads

Reviewed-by: Neil Roberts <neil@linux.intel.com>
src/mesa/main/formats.c

index b6c51242f80473d0048cb29756962fb9ed41da1b..958d6f245ea47b58858881e427dec94619ac0372 100644 (file)
@@ -28,7 +28,8 @@
 #include "formats.h"
 #include "macros.h"
 #include "glformats.h"
-
+#include "c11/threads.h"
+#include "util/hash_table.h"
 
 /**
  * Information about texture formats.
@@ -377,24 +378,67 @@ _mesa_format_to_array_format(mesa_format format)
       return _mesa_array_format_flip_channels(info->ArrayFormat);
 }
 
+static struct hash_table *format_array_format_table;
+static once_flag format_array_format_table_exists = ONCE_FLAG_INIT;
+
+static bool
+array_formats_equal(const void *a, const void *b)
+{
+   return (intptr_t)a == (intptr_t)b;
+}
+
+static void
+format_array_format_table_init()
+{
+   const struct gl_format_info *info;
+   mesa_array_format array_format;
+   unsigned f;
+
+   format_array_format_table = _mesa_hash_table_create(NULL, NULL,
+                                                       array_formats_equal);
+
+   for (f = 1; f < MESA_FORMAT_COUNT; ++f) {
+      info = _mesa_get_format_info(f);
+      if (!info->ArrayFormat)
+         continue;
+
+      if (_mesa_little_endian()) {
+         array_format = info->ArrayFormat;
+      } else {
+         array_format = _mesa_array_format_flip_channels(info->ArrayFormat);
+      }
+
+      /* This can happen and does for some of the BGR formats.  Let's take
+       * the first one in the list.
+       */
+      if (_mesa_hash_table_search_pre_hashed(format_array_format_table,
+                                             array_format,
+                                             (void *)(intptr_t)array_format))
+         continue;
+
+      _mesa_hash_table_insert_pre_hashed(format_array_format_table,
+                                         array_format,
+                                         (void *)(intptr_t)array_format,
+                                         (void *)(intptr_t)f);
+   }
+}
+
 mesa_format
 _mesa_format_from_array_format(uint32_t array_format)
 {
-   mesa_array_format af;
-   unsigned f;
+   struct hash_entry *entry;
 
    assert(_mesa_format_is_mesa_array_format(array_format));
 
-   if (_mesa_little_endian())
-      af = array_format;
-   else
-      af = _mesa_array_format_flip_channels(array_format);
-
-   for (f = 1; f < MESA_FORMAT_COUNT; ++f)
-      if (_mesa_get_format_info(f)->ArrayFormat == af)
-         return f;
+   call_once(&format_array_format_table_exists, format_array_format_table_init);
 
-   return MESA_FORMAT_NONE;
+   entry = _mesa_hash_table_search_pre_hashed(format_array_format_table,
+                                              array_format,
+                                              (void *)(intptr_t)array_format);
+   if (entry)
+      return (intptr_t)entry->data;
+   else
+      return MESA_FORMAT_NONE;
 }
 
 /** Is the given format a compressed format? */