mesa/main: avoid null access in format_array_table_init()
[mesa.git] / src / mesa / main / formats.c
index b10b628235c068bba8815bcda994be92cee887ae..f7c94024f65938fa720edb67ebd207ecaeec51d7 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.
@@ -74,7 +75,7 @@ struct gl_format_info
    mesa_array_format ArrayFormat;
 };
 
-#include "format_info.c"
+#include "format_info.h"
 
 static const struct gl_format_info *
 _mesa_get_format_info(mesa_format format)
@@ -106,8 +107,8 @@ GLint
 _mesa_get_format_bytes(mesa_format format)
 {
    const struct gl_format_info *info = _mesa_get_format_info(format);
-   ASSERT(info->BytesPerBlock);
-   ASSERT(info->BytesPerBlock <= MAX_PIXEL_BYTES ||
+   assert(info->BytesPerBlock);
+   assert(info->BytesPerBlock <= MAX_PIXEL_BYTES ||
           _mesa_is_format_compressed(format));
    return info->BytesPerBlock;
 }
@@ -377,24 +378,77 @@ _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(void)
+{
+   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);
+
+   if (!format_array_format_table) {
+      _mesa_error_no_memory(__func__);
+      return;
+   }
+
+   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);
+   call_once(&format_array_format_table_exists, format_array_format_table_init);
 
-   for (f = 1; f < MESA_FORMAT_COUNT; ++f)
-      if (_mesa_get_format_info(f)->ArrayFormat == af)
-         return f;
+   if (!format_array_format_table) {
+      format_array_format_table_exists = ONCE_FLAG_INIT;
+      return MESA_FORMAT_NONE;
+   }
 
-   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? */
@@ -472,6 +526,25 @@ _mesa_is_format_integer(mesa_format format)
    return (info->DataType == GL_INT || info->DataType == GL_UNSIGNED_INT);
 }
 
+
+/**
+ * Return true if the given format is a color format.
+ */
+GLenum
+_mesa_is_format_color_format(mesa_format format)
+{
+   const struct gl_format_info *info = _mesa_get_format_info(format);
+   switch (info->BaseFormat) {
+   case GL_DEPTH_COMPONENT:
+   case GL_STENCIL_INDEX:
+   case GL_DEPTH_STENCIL:
+      return false;
+   default:
+      return true;
+   }
+}
+
+
 /**
  * Return color encoding for given format.
  * \return GL_LINEAR or GL_SRGB
@@ -748,7 +821,7 @@ _mesa_format_image_size(mesa_format format, GLsizei width,
 
 /**
  * Same as _mesa_format_image_size() but returns a 64-bit value to
- * accomodate very large textures.
+ * accommodate very large textures.
  */
 uint64_t
 _mesa_format_image_size64(mesa_format format, GLsizei width,
@@ -824,7 +897,7 @@ _mesa_test_formats(void)
 {
    GLuint i;
 
-   STATIC_ASSERT(Elements(format_info) == MESA_FORMAT_COUNT);
+   STATIC_ASSERT(ARRAY_SIZE(format_info) == MESA_FORMAT_COUNT);
 
    for (i = 0; i < MESA_FORMAT_COUNT; i++) {
       const struct gl_format_info *info = _mesa_get_format_info(i);
@@ -991,6 +1064,34 @@ _mesa_format_to_type_and_comps(mesa_format format,
       *comps = 1;
       return;
 
+   case MESA_FORMAT_R3G3B2_UNORM:
+      *datatype = GL_UNSIGNED_BYTE_2_3_3_REV;
+      *comps = 3;
+      return;
+   case MESA_FORMAT_A4B4G4R4_UNORM:
+      *datatype = GL_UNSIGNED_SHORT_4_4_4_4;
+      *comps = 4;
+      return;
+
+   case MESA_FORMAT_R4G4B4A4_UNORM:
+      *datatype = GL_UNSIGNED_SHORT_4_4_4_4;
+      *comps = 4;
+      return;
+   case MESA_FORMAT_R5G5B5A1_UNORM:
+      *datatype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
+      *comps = 4;
+      return;
+   case MESA_FORMAT_A2B10G10R10_UNORM:
+   case MESA_FORMAT_A2B10G10R10_UINT:
+      *datatype = GL_UNSIGNED_INT_10_10_10_2;
+      *comps = 4;
+      return;
+   case MESA_FORMAT_A2R10G10B10_UNORM:
+   case MESA_FORMAT_A2R10G10B10_UINT:
+      *datatype = GL_UNSIGNED_INT_10_10_10_2;
+      *comps = 4;
+      return;
+
    case MESA_FORMAT_B2G3R3_UNORM:
       *datatype = GL_UNSIGNED_BYTE_3_3_2;
       *comps = 3;
@@ -1392,6 +1493,7 @@ _mesa_format_to_type_and_comps(mesa_format format,
       return;
 
    case MESA_FORMAT_B10G10R10X2_UNORM:
+   case MESA_FORMAT_R10G10B10X2_UNORM:
       *datatype = GL_UNSIGNED_INT_2_10_10_10_REV;
       *comps = 4;
       return;
@@ -1634,6 +1736,54 @@ _mesa_format_matches_format_and_type(mesa_format mesa_format,
    case MESA_FORMAT_B2G3R3_UNORM:
       return format == GL_RGB && type == GL_UNSIGNED_BYTE_3_3_2;
 
+   case MESA_FORMAT_R3G3B2_UNORM:
+      return format == GL_RGB && type == GL_UNSIGNED_BYTE_2_3_3_REV;
+
+   case MESA_FORMAT_A4B4G4R4_UNORM:
+      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4 && !swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_ABGR_EXT && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && !swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_ABGR_EXT && type == GL_UNSIGNED_SHORT_4_4_4_4 && swapBytes)
+         return GL_TRUE;
+
+      return GL_FALSE;
+
+   case MESA_FORMAT_R4G4B4A4_UNORM:
+      if (format == GL_ABGR_EXT && type == GL_UNSIGNED_SHORT_4_4_4_4 && !swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_ABGR_EXT && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4_REV && !swapBytes)
+         return GL_TRUE;
+
+      if (format == GL_RGBA && type == GL_UNSIGNED_SHORT_4_4_4_4 && swapBytes)
+         return GL_TRUE;
+
+      return GL_FALSE;
+
+   case MESA_FORMAT_R5G5B5A1_UNORM:
+      return format == GL_RGBA && type == GL_UNSIGNED_SHORT_1_5_5_5_REV;
+
+   case MESA_FORMAT_A2B10G10R10_UNORM:
+      return format == GL_RGBA && type == GL_UNSIGNED_INT_10_10_10_2;
+
+   case MESA_FORMAT_A2B10G10R10_UINT:
+      return format == GL_RGBA_INTEGER_EXT && type == GL_UNSIGNED_INT_10_10_10_2;
+
+   case MESA_FORMAT_A2R10G10B10_UNORM:
+      return format == GL_BGRA && type == GL_UNSIGNED_INT_10_10_10_2;
+
+   case MESA_FORMAT_A2R10G10B10_UINT:
+      return format == GL_BGRA_INTEGER_EXT && type == GL_UNSIGNED_INT_10_10_10_2;
+
    case MESA_FORMAT_A_UNORM8:
       return format == GL_ALPHA && type == GL_UNSIGNED_BYTE;
    case MESA_FORMAT_A_UNORM16:
@@ -1995,6 +2145,7 @@ _mesa_format_matches_format_and_type(mesa_format mesa_format,
    case MESA_FORMAT_RGBX_UINT8:
    case MESA_FORMAT_RGBX_SINT8:
    case MESA_FORMAT_B10G10R10X2_UNORM:
+   case MESA_FORMAT_R10G10B10X2_UNORM:
    case MESA_FORMAT_RGBX_UNORM16:
    case MESA_FORMAT_RGBX_SNORM16:
    case MESA_FORMAT_RGBX_FLOAT16: