Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/dom/canvas/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 58 kB image not shown  

Quelle  WebGLFormats.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "WebGLFormats.h"

#include "GLContext.h"
#include "GLDefs.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/StaticMutex.h"

namespace mozilla::webgl {

const char* ToString(const ComponentType type) {
  switch (type) {
    case ComponentType::Int:
      return "Int";
    case ComponentType::UInt:
      return "UInt";
    case ComponentType::NormInt:
      return "NormInt";
    case ComponentType::NormUInt:
      return "NormUInt";
    case ComponentType::Float:
      return "Float";
  }
  MOZ_CRASH("pacify gcc6 warning");
}

static TextureBaseType ToBaseType(const ComponentType type) {
  switch (type) {
    case ComponentType::Int:
      return TextureBaseType::Int;
    case ComponentType::UInt:
      return TextureBaseType::UInt;
    case ComponentType::NormInt:
    case ComponentType::NormUInt:
    case ComponentType::Float:
      // case ComponentType::Depth:
      return TextureBaseType::Float;
  }
  MOZ_CRASH("pacify gcc6 warning");
}

const char* ToString(const TextureBaseType x) {
  switch (x) {
    case webgl::TextureBaseType::Float:
      return "FLOAT";
    case webgl::TextureBaseType::Int:
      return "INT";
    case webgl::TextureBaseType::UInt:
      return "UINT";
  }
  MOZ_CRASH("pacify gcc6 warning");
}

// -

template <typename K, typename V, typename K2, typename V2>
static inline void AlwaysInsert(std::map<K, V>& dest, const K2& key,
                                const V2& val) {
  auto res = dest.insert({key, val});
  bool didInsert = res.second;
  MOZ_ALWAYS_TRUE(didInsert);
}

template <typename K, typename V, typename K2>
static inline V* FindOrNull(const std::map<K, V*>& dest, const K2& key) {
  auto itr = dest.find(key);
  if (itr == dest.end()) return nullptr;

  return itr->second;
}

// Returns a pointer to the in-place value for `key`.
template <typename C, typename K2>
static inline auto FindPtrOrNull(C& container, const K2& key) {
  auto itr = container.find(key);
  using R = decltype(&(itr->second));
  if (itr == container.end()) return R{nullptr};

  return &(itr->second);
}

//////////////////////////////////////////////////////////////////////////////////////////

MOZ_RUNINIT std::map<EffectiveFormat, const CompressedFormatInfo>
    gCompressedFormatInfoMap;
MOZ_RUNINIT std::map<EffectiveFormat, FormatInfo> gFormatInfoMap;

static inline const CompressedFormatInfo* GetCompressedFormatInfo(
    EffectiveFormat format) {
  MOZ_ASSERT(!gCompressedFormatInfoMap.empty());
  return FindPtrOrNull(gCompressedFormatInfoMap, format);
}

static inline FormatInfo* GetFormatInfo_NoLock(EffectiveFormat format) {
  MOZ_ASSERT(!gFormatInfoMap.empty());
  return FindPtrOrNull(gFormatInfoMap, format);
}

//////////////////////////////////////////////////////////////////////////////////////////

static void AddCompressedFormatInfo(EffectiveFormat format,
                                    uint16_t bitsPerBlock, uint8_t blockWidth,
                                    uint8_t blockHeight,
                                    CompressionFamily family) {
  MOZ_ASSERT(bitsPerBlock % 8 == 0);
  uint16_t bytesPerBlock = bitsPerBlock / 8;  // The specs always state these in
                                              // bits, but it's only ever useful
                                              // to us as bytes.
  MOZ_ASSERT(bytesPerBlock <= 255);

  const CompressedFormatInfo info = {format, uint8_t(bytesPerBlock), blockWidth,
                                     blockHeight, family};
  AlwaysInsert(gCompressedFormatInfoMap, format, info);
}

static void InitCompressedFormatInfo() {
  // clang-format off

    // GLES 3.0.4, p147, table 3.19
    // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_ETC2                     ,  64, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ETC2                    ,  64, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA8_ETC2_EAC                , 128, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC         , 128, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_R11_EAC                       ,  64, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RG11_EAC                      , 128, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_R11_EAC                ,  64, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_RG11_EAC               , 128, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ,  64, 4, 4, CompressionFamily::ES3);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,  64, 4, 4, CompressionFamily::ES3);

    // EXT_texture_compression_bptc
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_BPTC_UNORM        , 16*8, 4, 4, CompressionFamily::BPTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM  , 16*8, 4, 4, CompressionFamily::BPTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_BPTC_SIGNED_FLOAT  , 16*8, 4, 4, CompressionFamily::BPTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, 16*8, 4, 4, CompressionFamily::BPTC);

    // EXT_texture_compression_rgtc
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RED_RGTC1       ,  8*8, 4, 4, CompressionFamily::RGTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_RED_RGTC1,  8*8, 4, 4, CompressionFamily::RGTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RG_RGTC2        , 16*8, 4, 4, CompressionFamily::RGTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SIGNED_RG_RGTC2 , 16*8, 4, 4, CompressionFamily::RGTC);

    // EXT_texture_compression_s3tc
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_S3TC_DXT1_EXT ,  64, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT1_EXT,  64, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);

    // EXT_texture_compression_s3tc_srgb
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT ,       64, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,  64, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, 128, 4, 4, CompressionFamily::S3TC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, 128, 4, 4, CompressionFamily::S3TC);

    // KHR_texture_compression_astc_ldr
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_4x4_KHR          , 128,  4,  4, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x4_KHR          , 128,  5,  4, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_5x5_KHR          , 128,  5,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x5_KHR          , 128,  6,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_6x6_KHR          , 128,  6,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x5_KHR          , 128,  8,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x6_KHR          , 128,  8,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_8x8_KHR          , 128,  8,  8, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x5_KHR         , 128, 10,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x6_KHR         , 128, 10,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x8_KHR         , 128, 10,  8, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_10x10_KHR        , 128, 10, 10, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_12x10_KHR        , 128, 12, 10, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_ASTC_12x12_KHR        , 128, 12, 12, CompressionFamily::ASTC);

    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR  , 128,  4,  4, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR  , 128,  5,  4, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR  , 128,  5,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR  , 128,  6,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR  , 128,  6,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR  , 128,  8,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR  , 128,  8,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR  , 128,  8,  8, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR , 128, 10,  5, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR , 128, 10,  6, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR , 128, 10,  8, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, 128, 10, 10, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR, 128, 12, 10, CompressionFamily::ASTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, 128, 12, 12, CompressionFamily::ASTC);

    // IMG_texture_compression_pvrtc
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_4BPPV1 , 256,  8, 8, CompressionFamily::PVRTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_4BPPV1, 256,  8, 8, CompressionFamily::PVRTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGB_PVRTC_2BPPV1 , 256, 16, 8, CompressionFamily::PVRTC);
    AddCompressedFormatInfo(EffectiveFormat::COMPRESSED_RGBA_PVRTC_2BPPV1, 256, 16, 8, CompressionFamily::PVRTC);

    // OES_compressed_ETC1_RGB8_texture
    AddCompressedFormatInfo(EffectiveFormat::ETC1_RGB8_OES, 64, 4, 4, CompressionFamily::ETC1);

  // clang-format on
}

//////////////////////////////////////////////////////////////////////////////////////////

static void AddFormatInfo(EffectiveFormat format, const char* name,
                          GLenum sizedFormat, uint8_t bytesPerPixel, uint8_t r,
                          uint8_t g, uint8_t b, uint8_t a, uint8_t d, uint8_t s,
                          UnsizedFormat unsizedFormat, bool isSRGB,
                          ComponentType componentType) {
  switch (unsizedFormat) {
    case UnsizedFormat::R:
      MOZ_ASSERT(r && !g && !b && !a && !d && !s);
      break;

    case UnsizedFormat::RG:
      MOZ_ASSERT(r && g && !b && !a && !d && !s);
      break;

    case UnsizedFormat::RGB:
      MOZ_ASSERT(r && g && b && !a && !d && !s);
      break;

    case UnsizedFormat::RGBA:
      MOZ_ASSERT(r && g && b && a && !d && !s);
      break;

    case UnsizedFormat::L:
      MOZ_ASSERT(r && !g && !b && !a && !d && !s);
      break;

    case UnsizedFormat::A:
      MOZ_ASSERT(!r && !g && !b && a && !d && !s);
      break;

    case UnsizedFormat::LA:
      MOZ_ASSERT(r && !g && !b && a && !d && !s);
      break;

    case UnsizedFormat::D:
      MOZ_ASSERT(!r && !g && !b && !a && d && !s);
      break;

    case UnsizedFormat::S:
      MOZ_ASSERT(!r && !g && !b && !a && !d && s);
      break;

    case UnsizedFormat::DEPTH_STENCIL:
      MOZ_ASSERT(!r && !g && !b && !a && d && s);
      break;
  }

  const CompressedFormatInfo* compressedFormatInfo =
      GetCompressedFormatInfo(format);
  MOZ_ASSERT(!bytesPerPixel == bool(compressedFormatInfo));

#ifdef DEBUG
  uint8_t totalBits = r + g + b + a + d + s;
  if (format == EffectiveFormat::RGB9_E5) {
    totalBits = 9 + 9 + 9 + 5;
  }

  if (compressedFormatInfo) {
    MOZ_ASSERT(totalBits);
    MOZ_ASSERT(!bytesPerPixel);
  } else {
    MOZ_ASSERT(totalBits == bytesPerPixel * 8);
  }
#endif

  const FormatInfo info = {format,
                           name,
                           sizedFormat,
                           unsizedFormat,
                           componentType,
                           ToBaseType(componentType),
                           isSRGB,
                           compressedFormatInfo,
                           bytesPerPixel,
                           r,
                           g,
                           b,
                           a,
                           d,
                           s};
  AlwaysInsert(gFormatInfoMap, format, info);
}

static void InitFormatInfo() {
  // This function is full of expressive formatting, so:
  // clang-format off

#define FOO(x) EffectiveFormat::x, #x, LOCAL_GL_ ## x

    // GLES 3.0.4, p130-132, table 3.13
    AddFormatInfo(FOO(R8            ),  1,  8, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(R8_SNORM      ),  1,  8, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::NormInt );
    AddFormatInfo(FOO(RG8           ),  2,  8, 8, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RG8_SNORM     ),  2,  8, 8, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::NormInt );
    AddFormatInfo(FOO(RGB8          ),  3,  8, 8, 8, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGB8_SNORM    ),  3,  8, 8, 8, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::NormInt );
    AddFormatInfo(FOO(RGB565        ),  2,  5, 6, 5, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGBA4         ),  2,  4, 4, 4, 4,  0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGB5_A1       ),  2,  5, 5, 5, 1,  0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGBA8         ),  4,  8, 8, 8, 8,  0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGBA8_SNORM   ),  4,  8, 8, 8, 8,  0,0, UnsizedFormat::RGBA, false, ComponentType::NormInt );
    AddFormatInfo(FOO(RGB10_A2      ),  4, 10,10,10, 2,  0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGB10_A2UI    ),  4, 10,10,10, 2,  0,0, UnsizedFormat::RGBA, false, ComponentType::UInt    );

    AddFormatInfo(FOO(SRGB8         ),  3,  8, 8, 8, 0,  0,0, UnsizedFormat::RGB , true , ComponentType::NormUInt);
    AddFormatInfo(FOO(SRGB8_ALPHA8  ),  4,  8, 8, 8, 8,  0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);

    AddFormatInfo(FOO(R16F          ),  2, 16, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::Float   );
    AddFormatInfo(FOO(RG16F         ),  4, 16,16, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::Float   );
    AddFormatInfo(FOO(RGB16F        ),  6, 16,16,16, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Float   );
    AddFormatInfo(FOO(RGBA16F       ),  8, 16,16,16,16,  0,0, UnsizedFormat::RGBA, false, ComponentType::Float   );
    AddFormatInfo(FOO(R32F          ),  4, 32, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::Float   );
    AddFormatInfo(FOO(RG32F         ),  8, 32,32, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::Float   );
    AddFormatInfo(FOO(RGB32F        ), 12, 32,32,32, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Float   );
    AddFormatInfo(FOO(RGBA32F       ), 16, 32,32,32,32,  0,0, UnsizedFormat::RGBA, false, ComponentType::Float   );

    AddFormatInfo(FOO(R11F_G11F_B10F),  4, 11,11,10, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Float   );
    AddFormatInfo(FOO(RGB9_E5       ),  4, 14,14,14, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Float   );

    AddFormatInfo(FOO(R8I           ),  1,  8, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::Int     );
    AddFormatInfo(FOO(R8UI          ),  1,  8, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::UInt    );
    AddFormatInfo(FOO(R16I          ),  2, 16, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::Int     );
    AddFormatInfo(FOO(R16UI         ),  2, 16, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::UInt    );
    AddFormatInfo(FOO(R32I          ),  4, 32, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::Int     );
    AddFormatInfo(FOO(R32UI         ),  4, 32, 0, 0, 0,  0,0, UnsizedFormat::R   , false, ComponentType::UInt    );

    AddFormatInfo(FOO(RG8I          ),  2,  8, 8, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::Int     );
    AddFormatInfo(FOO(RG8UI         ),  2,  8, 8, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::UInt    );
    AddFormatInfo(FOO(RG16I         ),  4, 16,16, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::Int     );
    AddFormatInfo(FOO(RG16UI        ),  4, 16,16, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::UInt    );
    AddFormatInfo(FOO(RG32I         ),  8, 32,32, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::Int     );
    AddFormatInfo(FOO(RG32UI        ),  8, 32,32, 0, 0,  0,0, UnsizedFormat::RG  , false, ComponentType::UInt    );

    AddFormatInfo(FOO(RGB8I         ),  3,  8, 8, 8, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Int     );
    AddFormatInfo(FOO(RGB8UI        ),  3,  8, 8, 8, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::UInt    );
    AddFormatInfo(FOO(RGB16I        ),  6, 16,16,16, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Int     );
    AddFormatInfo(FOO(RGB16UI       ),  6, 16,16,16, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::UInt    );
    AddFormatInfo(FOO(RGB32I        ), 12, 32,32,32, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::Int     );
    AddFormatInfo(FOO(RGB32UI       ), 12, 32,32,32, 0,  0,0, UnsizedFormat::RGB , false, ComponentType::UInt    );

    AddFormatInfo(FOO(RGBA8I        ),  4,  8, 8, 8, 8,  0,0, UnsizedFormat::RGBA, false, ComponentType::Int     );
    AddFormatInfo(FOO(RGBA8UI       ),  4,  8, 8, 8, 8,  0,0, UnsizedFormat::RGBA, false, ComponentType::UInt    );
    AddFormatInfo(FOO(RGBA16I       ),  8, 16,16,16,16,  0,0, UnsizedFormat::RGBA, false, ComponentType::Int     );
    AddFormatInfo(FOO(RGBA16UI      ),  8, 16,16,16,16,  0,0, UnsizedFormat::RGBA, false, ComponentType::UInt    );
    AddFormatInfo(FOO(RGBA32I       ), 16, 32,32,32,32,  0,0, UnsizedFormat::RGBA, false, ComponentType::Int     );
    AddFormatInfo(FOO(RGBA32UI      ), 16, 32,32,32,32,  0,0, UnsizedFormat::RGBA, false, ComponentType::UInt    );

    // GLES 3.0.4, p133, table 3.14
    AddFormatInfo(FOO(DEPTH_COMPONENT16 ), 2, 0,0,0,0, 16,0, UnsizedFormat::D , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(DEPTH_COMPONENT24 ), 3, 0,0,0,0, 24,0, UnsizedFormat::D , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(DEPTH_COMPONENT32F), 4, 0,0,0,0, 32,0, UnsizedFormat::D , false, ComponentType::Float);
    // DEPTH_STENCIL types are sampled as their depth component.
    AddFormatInfo(FOO(DEPTH24_STENCIL8  ), 4, 0,0,0,0, 24,8, UnsizedFormat::DEPTH_STENCIL, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(DEPTH32F_STENCIL8 ), 5, 0,0,0,0, 32,8, UnsizedFormat::DEPTH_STENCILfalse, ComponentType::Float);

    // GLES 3.0.4, p205-206, "Required Renderbuffer Formats"
    AddFormatInfo(FOO(STENCIL_INDEX8), 1, 0,0,0,0, 0,8, UnsizedFormat::S, false, ComponentType::Int);

    // GLES 3.0.4, p147, table 3.19
    // GLES 3.0.4  p286+  $C.1 "ETC Compressed Texture Image Formats"
    AddFormatInfo(FOO(COMPRESSED_RGB8_ETC2                     ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ETC2                    ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA8_ETC2_EAC                ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_R11_EAC                       ), 0, 1,0,0,0, 0,0, UnsizedFormat::R   , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RG11_EAC                      ), 0, 1,1,0,0, 0,0, UnsizedFormat::RG  , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SIGNED_R11_EAC                ), 0, 1,0,0,0, 0,0, UnsizedFormat::R   , false, ComponentType::NormInt );
    AddFormatInfo(FOO(COMPRESSED_SIGNED_RG11_EAC               ), 0, 1,1,0,0, 0,0, UnsizedFormat::RG  , false, ComponentType::NormInt );
    AddFormatInfo(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);

    // EXT_texture_compression_bptc
    AddFormatInfo(FOO(COMPRESSED_RGBA_BPTC_UNORM        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_BPTC_UNORM  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGB_BPTC_SIGNED_FLOAT  ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::Float   );
    AddFormatInfo(FOO(COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::Float   );

    // EXT_texture_compression_rgtc
    AddFormatInfo(FOO(COMPRESSED_RED_RGTC1       ), 0, 1,0,0,0, 0,0, UnsizedFormat::R , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SIGNED_RED_RGTC1), 0, 1,0,0,0, 0,0, UnsizedFormat::R , false, ComponentType::NormInt );
    AddFormatInfo(FOO(COMPRESSED_RG_RGTC2        ), 0, 1,1,0,0, 0,0, UnsizedFormat::RG, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SIGNED_RG_RGTC2 ), 0, 1,1,0,0, 0,0, UnsizedFormat::RG, false, ComponentType::NormInt );

    // EXT_texture_compression_s3tc
    AddFormatInfo(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);

    // EXT_texture_compression_s3tc_srgb
    AddFormatInfo(FOO(COMPRESSED_SRGB_S3TC_DXT1_EXT ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , true, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true, ComponentType::NormUInt);

    // KHR_texture_compression_astc_ldr
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_8x8_KHR          ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x5_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x6_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x8_KHR         ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_10x10_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_12x10_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_ASTC_12x12_KHR        ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);

    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR  ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR ), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, true , ComponentType::NormUInt);

    // IMG_texture_compression_pvrtc
    AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_4BPPV1 ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGB_PVRTC_2BPPV1 ), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1), 0, 1,1,1,1, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);

    // OES_compressed_ETC1_RGB8_texture
    AddFormatInfo(FOO(ETC1_RGB8_OES), 0, 1,1,1,0, 0,0, UnsizedFormat::RGB, false, ComponentType::NormUInt);

    // EXT_texture_norm16
    AddFormatInfo(FOO(R16   ), 2, 16, 0, 0, 0, 0,0, UnsizedFormat::R   , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RG16  ), 4, 16,16, 0, 0, 0,0, UnsizedFormat::RG  , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGB16 ), 6, 16,16,16, 0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(RGBA16), 8, 16,16,16,16, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormUInt);

    AddFormatInfo(FOO(R16_SNORM   ), 2, 16, 0, 0, 0, 0,0, UnsizedFormat::R   , false, ComponentType::NormInt);
    AddFormatInfo(FOO(RG16_SNORM  ), 4, 16,16, 0, 0, 0,0, UnsizedFormat::RG  , false, ComponentType::NormInt);
    AddFormatInfo(FOO(RGB16_SNORM ), 6, 16,16,16, 0, 0,0, UnsizedFormat::RGB , false, ComponentType::NormInt);
    AddFormatInfo(FOO(RGBA16_SNORM), 8, 16,16,16,16, 0,0, UnsizedFormat::RGBA, false, ComponentType::NormInt);

#undef FOO

    // 'Virtual' effective formats have no sizedFormat.
#define FOO(x) EffectiveFormat::x, #x, 0

    // GLES 3.0.4, p128, table 3.12.
    AddFormatInfo(FOO(Luminance8Alpha8), 2, 8,0,0,8, 0,0, UnsizedFormat::LA, false, ComponentType::NormUInt);
    AddFormatInfo(FOO(Luminance8      ), 1, 8,0,0,0, 0,0, UnsizedFormat::L , false, ComponentType::NormUInt);
    AddFormatInfo(FOO(Alpha8          ), 1, 0,0,0,8, 0,0, UnsizedFormat::A , false, ComponentType::NormUInt);

    // OES_texture_float
    AddFormatInfo(FOO(Luminance32FAlpha32F), 8, 32,0,0,32, 0,0, UnsizedFormat::LA, falseComponentType::Float);
    AddFormatInfo(FOO(Luminance32F        ), 4, 32,0,0, 0, 0,0, UnsizedFormat::L , false, ComponentType::Float);
    AddFormatInfo(FOO(Alpha32F            ), 4,  0,0,0,32, 0,0, UnsizedFormat::A , false, ComponentType::Float);

    // OES_texture_half_float
    AddFormatInfo(FOO(Luminance16FAlpha16F), 4, 16,0,0,16, 0,0, UnsizedFormat::LA, falseComponentType::Float);
    AddFormatInfo(FOO(Luminance16F        ), 2, 16,0,0, 0, 0,0, UnsizedFormat::L , false, ComponentType::Float);
    AddFormatInfo(FOO(Alpha16F            ), 2,  0,0,0,16, 0,0, UnsizedFormat::A , false, ComponentType::Float);

#undef FOO

    ////////////////////////////////////////////////////////////////////////////

    const auto fnSetCopyDecay = [](EffectiveFormat src, EffectiveFormat asR,
                                   EffectiveFormat asRG, EffectiveFormat asRGB,
                                   EffectiveFormat asRGBA, EffectiveFormat asL,
                                   EffectiveFormat asA, EffectiveFormat asLA)
    {
        auto& map = GetFormatInfo_NoLock(src)->copyDecayFormats;

        const auto fnSet = [&map](UnsizedFormat uf, EffectiveFormat ef) {
            if (ef == EffectiveFormat::MAX)
                return;

            const auto* format = GetFormatInfo_NoLock(ef);
            MOZ_ASSERT(format->unsizedFormat == uf);
            AlwaysInsert(map, uf, format);
        };

        fnSet(UnsizedFormat::R   , asR);
        fnSet(UnsizedFormat::RG  , asRG);
        fnSet(UnsizedFormat::RGB , asRGB);
        fnSet(UnsizedFormat::RGBA, asRGBA);
        fnSet(UnsizedFormat::L   , asL);
        fnSet(UnsizedFormat::A   , asA);
        fnSet(UnsizedFormat::LA  , asLA);
    };

#define SET_COPY_DECAY(src,asR,asRG,asRGB,asRGBA,asL,asA,asLA) \
    fnSetCopyDecay(EffectiveFormat::src, EffectiveFormat::asR, EffectiveFormat::asRG,     \
                   EffectiveFormat::asRGB, EffectiveFormat::asRGBA, EffectiveFormat::asL, \
                   EffectiveFormat::asA, EffectiveFormat::asLA);

    //////

#define SET_BY_SUFFIX(X) \
        SET_COPY_DECAY(   R##X, R##X,   MAX,    MAX,     MAX, Luminance##X,      MAX,                    MAX) \
        SET_COPY_DECAY(  RG##X, R##X, RG##X,    MAX,     MAX, Luminance##X,      MAX,                    MAX) \
        SET_COPY_DECAY( RGB##X, R##X, RG##X, RGB##X,     MAX, Luminance##X,      MAX,                    MAX) \
        SET_COPY_DECAY(RGBA##X, R##X, RG##X, RGB##X, RGBA##X, Luminance##X, Alpha##X, Luminance##X##Alpha##X)

    SET_BY_SUFFIX(8)   // WebGL decided that RGB8 should be guaranteed renderable.
    SET_BY_SUFFIX(16F) // RGB16F is renderable in EXT_color_buffer_half_float, though not
                       // EXT_color_buffer_float.
    SET_BY_SUFFIX(32F) // Technically RGB32F is never renderable, but no harm here.

#undef SET_BY_SUFFIX


    //////

#define SET_BY_SUFFIX(X) \
        SET_COPY_DECAY(   R##X, R##X,   MAX,    MAX,     MAX, MAX, MAX, MAX) \
        SET_COPY_DECAY(  RG##X, R##X, RG##X,    MAX,     MAX, MAX, MAX, MAX) \
        SET_COPY_DECAY(RGBA##X, R##X, RG##X, RGB##X, RGBA##X, MAX, MAX, MAX)

    SET_BY_SUFFIX(8I)
    SET_BY_SUFFIX(8UI)

    SET_BY_SUFFIX(16)
    SET_BY_SUFFIX(16I)
    SET_BY_SUFFIX(16UI)

    SET_BY_SUFFIX(32I)
    SET_BY_SUFFIX(32UI)

#undef SET_BY_SUFFIX

    //////

    SET_COPY_DECAY(    RGB565, R8, RG8, RGB565,      MAX, Luminance8,    MAX,              MAX)
    SET_COPY_DECAY(     RGBA4, R8, RG8, RGB565,    RGBA4, Luminance8, Alpha8, Luminance8Alpha8)
    SET_COPY_DECAY(   RGB5_A1, R8, RG8, RGB565,  RGB5_A1, Luminance8, Alpha8, Luminance8Alpha8)
    SET_COPY_DECAY(  RGB10_A2, R8, RG8,   RGB8, RGB10_A2, Luminance8, Alpha8,              MAX)

    SET_COPY_DECAY(RGB10_A2UI, R8UI, RG8UI, RGB8UI, RGB10_A2UI, MAX, MAX, MAX)

    SET_COPY_DECAY(SRGB8_ALPHA8, MAX, MAX, MAX, SRGB8_ALPHA8, MAX, Alpha8, MAX)

    SET_COPY_DECAY(R11F_G11F_B10F, R16F, RG16F, R11F_G11F_B10F, MAX, Luminance16F, MAX, MAX)

#undef SET_COPY_DECAY

  // clang-format on
}

//////////////////////////////////////////////////////////////////////////////////////////

bool gAreFormatTablesInitialized = false;

static void EnsureInitFormatTables(
    const StaticMutexAutoLock&)  // Prove that you locked it!
{
  if (MOZ_LIKELY(gAreFormatTablesInitialized)) return;

  gAreFormatTablesInitialized = true;

  InitCompressedFormatInfo();
  InitFormatInfo();
}

//////////////////////////////////////////////////////////////////////////////////////////
// Public funcs

StaticMutex gFormatMapMutex;

const FormatInfo* GetFormat(EffectiveFormat format) {
  StaticMutexAutoLock lock(gFormatMapMutex);
  EnsureInitFormatTables(lock);

  return GetFormatInfo_NoLock(format);
}

//////////////////////////////////////////////////////////////////////////////////////////

const FormatInfo* FormatInfo::GetCopyDecayFormat(UnsizedFormat uf) const {
  return FindOrNull(this->copyDecayFormats, uf);
}

Maybe<PackingInfoInfo> PackingInfoInfo::For(const PackingInfo& pi) {
  PackingInfoInfo ret{};

  switch (pi.type) {
    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
      ret = {2, 1, true};
      break;

    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
    case LOCAL_GL_UNSIGNED_INT_24_8:
    case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
      ret = {4, 1, true};
      break;

    case LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
      ret = {8, 1, true};
      break;

      // Alright, that's all the fixed-size unpackTypes.

    case LOCAL_GL_BYTE:
    case LOCAL_GL_UNSIGNED_BYTE:
      ret = {1, 0, false};
      break;

    case LOCAL_GL_SHORT:
    case LOCAL_GL_UNSIGNED_SHORT:
    case LOCAL_GL_HALF_FLOAT:
    case LOCAL_GL_HALF_FLOAT_OES:
      ret = {2, 0, false};
      break;

    case LOCAL_GL_INT:
    case LOCAL_GL_UNSIGNED_INT:
    case LOCAL_GL_FLOAT:
      ret = {4, 0, false};
      break;

    default:
      return {};
  }

  if (!ret.isPacked) {
    switch (pi.format) {
      case LOCAL_GL_RED:
      case LOCAL_GL_RED_INTEGER:
      case LOCAL_GL_LUMINANCE:
      case LOCAL_GL_ALPHA:
      case LOCAL_GL_DEPTH_COMPONENT:
        ret.elementsPerPixel = 1;
        break;

      case LOCAL_GL_RG:
      case LOCAL_GL_RG_INTEGER:
      case LOCAL_GL_LUMINANCE_ALPHA:
        ret.elementsPerPixel = 2;
        break;

      case LOCAL_GL_RGB:
      case LOCAL_GL_RGB_INTEGER:
      case LOCAL_GL_SRGB:
        ret.elementsPerPixel = 3;
        break;

      case LOCAL_GL_BGRA:
      case LOCAL_GL_RGBA:
      case LOCAL_GL_RGBA_INTEGER:
      case LOCAL_GL_SRGB_ALPHA:
        ret.elementsPerPixel = 4;
        break;

      default:
        return {};
    }
  }

  return Some(ret);
}

//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////
// FormatUsageAuthority

bool FormatUsageInfo::IsUnpackValid(
    const PackingInfo& key, const DriverUnpackInfo** const out_value) const {
  auto itr = validUnpacks.find(key);
  if (itr == validUnpacks.end()) return false;

  *out_value = &(itr->second);
  return true;
}

void FormatUsageInfo::ResolveMaxSamples(gl::GLContext& gl) const {
  MOZ_ASSERT(gl.IsCurrent());
  MOZ_ASSERT(!this->maxSamplesKnown);
  MOZ_ASSERT(!this->maxSamples);
  this->maxSamplesKnown = true;

  const GLenum internalFormat = this->format->sizedFormat;
  if (!internalFormat) return;
  if (!gl.IsSupported(gl::GLFeature::internalformat_query)) return;

  // GL_SAMPLES returns a list in descending order, so ask for just one elem to
  // get the max.
  gl.fGetInternalformativ(LOCAL_GL_RENDERBUFFER, internalFormat,
                          LOCAL_GL_SAMPLES, 1,
                          reinterpret_cast<GLint*>(&this->maxSamples));
}

////////////////////////////////////////

static void AddSimpleUnsized(FormatUsageAuthority* fua, GLenum unpackFormat,
                             GLenum unpackType, EffectiveFormat effFormat) {
  auto usage = fua->EditUsage(effFormat);
  usage->isFilterable = true;

  const PackingInfo pi = {unpackFormat, unpackType};
  const DriverUnpackInfo dui = {unpackFormat, unpackFormat, unpackType};
  fua->AddTexUnpack(usage, pi, dui);

  fua->AllowUnsizedTexFormat(pi, usage);
};

/*static*/ const GLint FormatUsageInfo::kLuminanceSwizzleRGBA[4] = {
    LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_ONE};
/*static*/ const GLint FormatUsageInfo::kAlphaSwizzleRGBA[4] = {
    LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_ZERO, LOCAL_GL_RED};
/*static*/ const GLint FormatUsageInfo::kLumAlphaSwizzleRGBA[4] = {
    LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_RED, LOCAL_GL_GREEN};

static bool AddLegacyFormats_LA8(FormatUsageAuthority* fua, gl::GLContext* gl) {
  if (gl->IsCoreProfile()) {
    if (!gl->IsSupported(gl::GLFeature::texture_swizzle)) return false;

    PackingInfo pi;
    DriverUnpackInfo dui;

    const auto fnAdd = [fua, &pi, &dui](EffectiveFormat effFormat,
                                        const GLint* swizzle) {
      auto usage = fua->EditUsage(effFormat);
      usage->isFilterable = true;
      usage->textureSwizzleRGBA = swizzle;

      fua->AddTexUnpack(usage, pi, dui);

      fua->AllowUnsizedTexFormat(pi, usage);
    };

    pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_UNSIGNED_BYTE};
    dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
    fnAdd(EffectiveFormat::Luminance8, FormatUsageInfo::kLuminanceSwizzleRGBA);

    pi = {LOCAL_GL_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
    dui = {LOCAL_GL_R8, LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE};
    fnAdd(EffectiveFormat::Alpha8, FormatUsageInfo::kAlphaSwizzleRGBA);

    pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE};
    dui = {LOCAL_GL_RG8, LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE};
    fnAdd(EffectiveFormat::Luminance8Alpha8,
          FormatUsageInfo::kLumAlphaSwizzleRGBA);
  } else {
    // clang-format off
        AddSimpleUnsized(fua, LOCAL_GL_LUMINANCE      , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8      );
        AddSimpleUnsized(fua, LOCAL_GL_ALPHA          , LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Alpha8          );
        AddSimpleUnsized(fua, LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_UNSIGNED_BYTE, EffectiveFormat::Luminance8Alpha8);
    // clang-format on
  }

  return true;
}

static bool AddUnsizedFormats(FormatUsageAuthority* fua, gl::GLContext* gl) {
  // clang-format off

    // GLES 2.0.25, p63, Table 3.4
    AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE         , EffectiveFormat::RGBA8  );
    AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4, EffectiveFormat::RGBA4  );
    AddSimpleUnsized(fua, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1, EffectiveFormat::RGB5_A1);
    AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_BYTE         , EffectiveFormat::RGB8   );
    AddSimpleUnsized(fua, LOCAL_GL_RGB , LOCAL_GL_UNSIGNED_SHORT_5_6_5  , EffectiveFormat::RGB565 );

    // L, A, LA
    return AddLegacyFormats_LA8(fua, gl);

  // clang-format on
}

void FormatUsageInfo::SetRenderable(const FormatRenderableState& state) {
  if (!renderableState.IsExplicit()) {
    renderableState = state;
  }

#ifdef DEBUG
  const auto format = this->format;
  if (format->IsColorFormat()) {
    const auto& map = format->copyDecayFormats;
    const auto itr = map.find(format->unsizedFormat);
    MOZ_ASSERT(itr != map.end(),
               "Renderable formats must be in copyDecayFormats.");
    MOZ_ASSERT(itr->second == format);
  }
#endif
}

std::unique_ptr<FormatUsageAuthority> FormatUsageAuthority::CreateForWebGL1(
    gl::GLContext* gl) {
  std::unique_ptr<FormatUsageAuthority> ret(new FormatUsageAuthority);
  const auto ptr = ret.get();

  ////////////////////////////////////////////////////////////////////////////
  // Usages

  const auto fnSet = [ptr](EffectiveFormat effFormat, bool isRenderable,
                           bool isFilterable) {
    MOZ_ASSERT(!ptr->GetUsage(effFormat));

    auto usage = ptr->EditUsage(effFormat);
    usage->isFilterable = isFilterable;

    if (isRenderable) {
      usage->SetRenderable();
    }
  };

  // GLES 2.0.25, p117, Table 4.5
  // RGBA8 is made renderable in WebGL 1.0, "Framebuffer Object Attachments"
  //                              render filter
  //                              able   able
  fnSet(EffectiveFormat::RGBA8, truetrue);
  fnSet(EffectiveFormat::RGBA4, truetrue);
  fnSet(EffectiveFormat::RGB5_A1, truetrue);
  fnSet(EffectiveFormat::RGB565, truetrue);

  // RGB8 is not guaranteed to be renderable, but we should allow it for
  // web-compat. Min-capability mode should mark this as non-renderable.
  fnSet(EffectiveFormat::RGB8, truetrue);

  fnSet(EffectiveFormat::Luminance8Alpha8, falsetrue);
  fnSet(EffectiveFormat::Luminance8, falsetrue);
  fnSet(EffectiveFormat::Alpha8, falsetrue);

  fnSet(EffectiveFormat::DEPTH_COMPONENT16, truetrue);
  fnSet(EffectiveFormat::DEPTH_COMPONENT24, true,
        true);  // Requires WEBGL_depth_texture.
  fnSet(EffectiveFormat::STENCIL_INDEX8, truefalse);

  // Added in WebGL 1.0 spec:
  fnSet(EffectiveFormat::DEPTH24_STENCIL8, truetrue);

  ////////////////////////////////////
  // RB formats

#define FOO(x) \
  ptr->AllowRBFormat(LOCAL_GL_##x, ptr->GetUsage(EffectiveFormat::x))

  FOO(RGBA4);
  FOO(RGB5_A1);
  FOO(RGB565);
  FOO(DEPTH_COMPONENT16);
  FOO(STENCIL_INDEX8);
  // FOO(DEPTH24_STENCIL8 ); // WebGL 1 uses DEPTH_STENCIL instead of
  // DEPTH24_STENCIL8.

#undef FOO

  ptr->AllowRBFormat(LOCAL_GL_DEPTH_STENCIL,
                     ptr->GetUsage(EffectiveFormat::DEPTH24_STENCIL8));

  ////////////////////////////////////////////////////////////////////////////

  if (!AddUnsizedFormats(ptr, gl)) return nullptr;

  return ret;
}

std::unique_ptr<FormatUsageAuthority> FormatUsageAuthority::CreateForWebGL2(
    gl::GLContext* gl) {
  std::unique_ptr<FormatUsageAuthority> ret(new FormatUsageAuthority);
  const auto ptr = ret.get();

  ////////////////////////////////////////////////////////////////////////////
  // GLES 3.0.4 p111-113

  const auto fnAddSizedUnpack = [ptr](EffectiveFormat effFormat,
                                      GLenum internalFormat,
                                      GLenum unpackFormat, GLenum unpackType) {
    auto usage = ptr->EditUsage(effFormat);

    const PackingInfo pi = {unpackFormat, unpackType};
    const DriverUnpackInfo dui = {internalFormat, unpackFormat, unpackType};
    ptr->AddTexUnpack(usage, pi, dui);
  };

  // clang-format off
#define FOO(x) EffectiveFormat::x, LOCAL_GL_ ## x

    // RGBA
    fnAddSizedUnpack(FOO(RGBA8       ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE              );
    fnAddSizedUnpack(FOO(RGBA4       ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_4_4_4_4     );
    fnAddSizedUnpack(FOO(RGBA4       ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE              );
    fnAddSizedUnpack(FOO(RGB5_A1     ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT_5_5_5_1     );
    fnAddSizedUnpack(FOO(RGB5_A1     ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE              );
    fnAddSizedUnpack(FOO(RGB5_A1     ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);
    fnAddSizedUnpack(FOO(SRGB8_ALPHA8), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE              );
    fnAddSizedUnpack(FOO(RGBA8_SNORM ), LOCAL_GL_RGBA, LOCAL_GL_BYTE                       );
    fnAddSizedUnpack(FOO(RGB10_A2    ), LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);
    fnAddSizedUnpack(FOO(RGBA16F     ), LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT                 );
    fnAddSizedUnpack(FOO(RGBA16F     ), LOCAL_GL_RGBA, LOCAL_GL_FLOAT                      );
    fnAddSizedUnpack(FOO(RGBA32F     ), LOCAL_GL_RGBA, LOCAL_GL_FLOAT                      );

    // RGBA_INTEGER
    fnAddSizedUnpack(FOO(RGBA8UI   ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_BYTE              );
    fnAddSizedUnpack(FOO(RGBA8I    ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_BYTE                       );
    fnAddSizedUnpack(FOO(RGBA16UI  ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_SHORT             );
    fnAddSizedUnpack(FOO(RGBA16I   ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_SHORT                      );
    fnAddSizedUnpack(FOO(RGBA32UI  ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT               );
    fnAddSizedUnpack(FOO(RGBA32I   ), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT                        );
    fnAddSizedUnpack(FOO(RGB10_A2UI), LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV);

    // RGB
    fnAddSizedUnpack(FOO(RGB8          ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE               );
    fnAddSizedUnpack(FOO(SRGB8         ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE               );
    fnAddSizedUnpack(FOO(RGB565        ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5        );
    fnAddSizedUnpack(FOO(RGB565        ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_BYTE               );
    fnAddSizedUnpack(FOO(RGB8_SNORM    ), LOCAL_GL_RGB, LOCAL_GL_BYTE                        );
    fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV);
    fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT                  );
    fnAddSizedUnpack(FOO(R11F_G11F_B10F), LOCAL_GL_RGB, LOCAL_GL_FLOAT                       );
    fnAddSizedUnpack(FOO(RGB16F        ), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT                  );
    fnAddSizedUnpack(FOO(RGB16F        ), LOCAL_GL_RGB, LOCAL_GL_FLOAT                       );
    fnAddSizedUnpack(FOO(RGB9_E5       ), LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV    );
    fnAddSizedUnpack(FOO(RGB9_E5       ), LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT                  );
    fnAddSizedUnpack(FOO(RGB9_E5       ), LOCAL_GL_RGB, LOCAL_GL_FLOAT                       );
    fnAddSizedUnpack(FOO(RGB32F        ), LOCAL_GL_RGB, LOCAL_GL_FLOAT                       );

    // RGB_INTEGER
    fnAddSizedUnpack(FOO(RGB8UI ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
    fnAddSizedUnpack(FOO(RGB8I  ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_BYTE          );
    fnAddSizedUnpack(FOO(RGB16UI), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
    fnAddSizedUnpack(FOO(RGB16I ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_SHORT         );
    fnAddSizedUnpack(FOO(RGB32UI), LOCAL_GL_RGB_INTEGER, LOCAL_GL_UNSIGNED_INT  );
    fnAddSizedUnpack(FOO(RGB32I ), LOCAL_GL_RGB_INTEGER, LOCAL_GL_INT           );

    // RG
    fnAddSizedUnpack(FOO(RG8      ), LOCAL_GL_RG, LOCAL_GL_UNSIGNED_BYTE);
    fnAddSizedUnpack(FOO(RG8_SNORM), LOCAL_GL_RG, LOCAL_GL_BYTE         );
    fnAddSizedUnpack(FOO(RG16F    ), LOCAL_GL_RG, LOCAL_GL_HALF_FLOAT   );
    fnAddSizedUnpack(FOO(RG16F    ), LOCAL_GL_RG, LOCAL_GL_FLOAT        );
    fnAddSizedUnpack(FOO(RG32F    ), LOCAL_GL_RG, LOCAL_GL_FLOAT        );

    // RG_INTEGER
    fnAddSizedUnpack(FOO(RG8UI ), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
    fnAddSizedUnpack(FOO(RG8I  ), LOCAL_GL_RG_INTEGER, LOCAL_GL_BYTE          );
    fnAddSizedUnpack(FOO(RG16UI), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
    fnAddSizedUnpack(FOO(RG16I ), LOCAL_GL_RG_INTEGER, LOCAL_GL_SHORT         );
    fnAddSizedUnpack(FOO(RG32UI), LOCAL_GL_RG_INTEGER, LOCAL_GL_UNSIGNED_INT  );
    fnAddSizedUnpack(FOO(RG32I ), LOCAL_GL_RG_INTEGER, LOCAL_GL_INT           );

    // RED
    fnAddSizedUnpack(FOO(R8      ), LOCAL_GL_RED, LOCAL_GL_UNSIGNED_BYTE);
    fnAddSizedUnpack(FOO(R8_SNORM), LOCAL_GL_RED, LOCAL_GL_BYTE         );
    fnAddSizedUnpack(FOO(R16F    ), LOCAL_GL_RED, LOCAL_GL_HALF_FLOAT   );
    fnAddSizedUnpack(FOO(R16F    ), LOCAL_GL_RED, LOCAL_GL_FLOAT        );
    fnAddSizedUnpack(FOO(R32F    ), LOCAL_GL_RED, LOCAL_GL_FLOAT        );

    // RED_INTEGER
    fnAddSizedUnpack(FOO(R8UI ), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_BYTE );
    fnAddSizedUnpack(FOO(R8I  ), LOCAL_GL_RED_INTEGER, LOCAL_GL_BYTE          );
    fnAddSizedUnpack(FOO(R16UI), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_SHORT);
    fnAddSizedUnpack(FOO(R16I ), LOCAL_GL_RED_INTEGER, LOCAL_GL_SHORT         );
    fnAddSizedUnpack(FOO(R32UI), LOCAL_GL_RED_INTEGER, LOCAL_GL_UNSIGNED_INT  );
    fnAddSizedUnpack(FOO(R32I ), LOCAL_GL_RED_INTEGER, LOCAL_GL_INT           );

    // DEPTH_COMPONENT
    fnAddSizedUnpack(FOO(DEPTH_COMPONENT16 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_SHORT);
    fnAddSizedUnpack(FOO(DEPTH_COMPONENT16 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT  );
    fnAddSizedUnpack(FOO(DEPTH_COMPONENT24 ), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_UNSIGNED_INT  );
    fnAddSizedUnpack(FOO(DEPTH_COMPONENT32F), LOCAL_GL_DEPTH_COMPONENT, LOCAL_GL_FLOAT         );

    // DEPTH_STENCIL
    fnAddSizedUnpack(FOO(DEPTH24_STENCIL8 ), LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_UNSIGNED_INT_24_8             );
    fnAddSizedUnpack(FOO(DEPTH32F_STENCIL8), LOCAL_GL_DEPTH_STENCIL, LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV);

#undef FOO
  // clang-format on

  ////////////////////////////////////////////////////////////////////////////

  // For renderable, see GLES 3.0.4, p212 "Framebuffer Completeness"
  // For filterable, see GLES 3.0.4, p161 "...a texture is complete unless..."

  const auto fnAllowES3TexFormat = [ptr](GLenum sizedFormat,
                                         EffectiveFormat effFormat,
                                         bool isRenderable, bool isFilterable) {
    auto usage = ptr->EditUsage(effFormat);
    usage->isFilterable = isFilterable;

    if (isRenderable) {
      usage->SetRenderable();
    }

    ptr->AllowSizedTexFormat(sizedFormat, usage);

    if (isRenderable) {
      ptr->AllowRBFormat(sizedFormat, usage);
    }
  };

#define FOO(x) LOCAL_GL_##x, EffectiveFormat::x

  // GLES 3.0.4, p128-129 "Required Texture Formats"
  // GLES 3.0.4, p130-132, table 3.13
  //                                   render filter
  //                                    able   able
  fnAllowES3TexFormat(FOO(R8), truetrue);
  fnAllowES3TexFormat(FOO(R8_SNORM), falsetrue);
  fnAllowES3TexFormat(FOO(RG8), truetrue);
  fnAllowES3TexFormat(FOO(RG8_SNORM), falsetrue);
  fnAllowES3TexFormat(FOO(RGB8), truetrue);
  fnAllowES3TexFormat(FOO(RGB8_SNORM), falsetrue);
  fnAllowES3TexFormat(FOO(RGB565), truetrue);
  fnAllowES3TexFormat(FOO(RGBA4), truetrue);
  fnAllowES3TexFormat(FOO(RGB5_A1), truetrue);
  fnAllowES3TexFormat(FOO(RGBA8), truetrue);
  fnAllowES3TexFormat(FOO(RGBA8_SNORM), falsetrue);
  fnAllowES3TexFormat(FOO(RGB10_A2), truetrue);
  fnAllowES3TexFormat(FOO(RGB10_A2UI), truefalse);

  fnAllowES3TexFormat(FOO(SRGB8), falsetrue);
  fnAllowES3TexFormat(FOO(SRGB8_ALPHA8), truetrue);

  fnAllowES3TexFormat(FOO(R16F), falsetrue);
  fnAllowES3TexFormat(FOO(RG16F), falsetrue);
  fnAllowES3TexFormat(FOO(RGB16F), falsetrue);
  fnAllowES3TexFormat(FOO(RGBA16F), falsetrue);

  fnAllowES3TexFormat(FOO(R32F), falsefalse);
  fnAllowES3TexFormat(FOO(RG32F), falsefalse);
  fnAllowES3TexFormat(FOO(RGB32F), falsefalse);
  fnAllowES3TexFormat(FOO(RGBA32F), falsefalse);

  fnAllowES3TexFormat(FOO(R11F_G11F_B10F), falsetrue);
  fnAllowES3TexFormat(FOO(RGB9_E5), falsetrue);

  fnAllowES3TexFormat(FOO(R8I), truefalse);
  fnAllowES3TexFormat(FOO(R8UI), truefalse);
  fnAllowES3TexFormat(FOO(R16I), truefalse);
  fnAllowES3TexFormat(FOO(R16UI), truefalse);
  fnAllowES3TexFormat(FOO(R32I), truefalse);
  fnAllowES3TexFormat(FOO(R32UI), truefalse);

  fnAllowES3TexFormat(FOO(RG8I), truefalse);
  fnAllowES3TexFormat(FOO(RG8UI), truefalse);
  fnAllowES3TexFormat(FOO(RG16I), truefalse);
  fnAllowES3TexFormat(FOO(RG16UI), truefalse);
  fnAllowES3TexFormat(FOO(RG32I), truefalse);
  fnAllowES3TexFormat(FOO(RG32UI), truefalse);

  fnAllowES3TexFormat(FOO(RGB8I), falsefalse);
  fnAllowES3TexFormat(FOO(RGB8UI), falsefalse);
  fnAllowES3TexFormat(FOO(RGB16I), falsefalse);
  fnAllowES3TexFormat(FOO(RGB16UI), falsefalse);
  fnAllowES3TexFormat(FOO(RGB32I), falsefalse);
  fnAllowES3TexFormat(FOO(RGB32UI), falsefalse);

  fnAllowES3TexFormat(FOO(RGBA8I), truefalse);
  fnAllowES3TexFormat(FOO(RGBA8UI), truefalse);
  fnAllowES3TexFormat(FOO(RGBA16I), truefalse);
  fnAllowES3TexFormat(FOO(RGBA16UI), truefalse);
  fnAllowES3TexFormat(FOO(RGBA32I), truefalse);
  fnAllowES3TexFormat(FOO(RGBA32UI), truefalse);

  // Sized depth or depth-stencil formats are not filterable
  // per GLES 3.0.6 p161.
  // Specifically, they're texture-incomplete if depth-compare:none and
  // not NEAREST.
  fnAllowES3TexFormat(FOO(DEPTH_COMPONENT16), truefalse);
  fnAllowES3TexFormat(FOO(DEPTH_COMPONENT24), truefalse);
  fnAllowES3TexFormat(FOO(DEPTH_COMPONENT32F), truefalse);
  fnAllowES3TexFormat(FOO(DEPTH24_STENCIL8), truefalse);
  fnAllowES3TexFormat(FOO(DEPTH32F_STENCIL8), truefalse);

#undef FOO

  // GLES 3.0.4, p206, "Required Renderbuffer Formats":
  // "Implementations are also required to support STENCIL_INDEX8. Requesting
  // this internal format for a renderbuffer will allocate at least 8 stencil
  // bit planes."

  auto usage = ptr->EditUsage(EffectiveFormat::STENCIL_INDEX8);
  usage->SetRenderable();
  ptr->AllowRBFormat(LOCAL_GL_STENCIL_INDEX8, usage);

  ////////////////
  // Legacy formats

  if (!AddUnsizedFormats(ptr, gl)) return nullptr;

  ptr->AllowRBFormat(LOCAL_GL_DEPTH_STENCIL,
                     ptr->GetUsage(EffectiveFormat::DEPTH24_STENCIL8));

  ////////////////////////////////////

  return ret;
}

//////////////////////////////////////////////////////////////////////////////////////////

void FormatUsageAuthority::AddTexUnpack(FormatUsageInfo* usage,
                                        const PackingInfo& pi,
                                        const DriverUnpackInfo& dui) {
  // Don't AlwaysInsert here, since we'll see duplicates from sized and unsized
  // formats.
  auto res = usage->validUnpacks.insert({pi, dui});
  auto itr = res.first;

  if (!usage->idealUnpack) {
    // First one!
    usage->idealUnpack = &(itr->second);
  }

  mValidTexUnpackFormats.insert(pi.format);
  mValidTexUnpackTypes.insert(pi.type);
}

static bool Contains(const std::set<GLenum>& set, GLenum key) {
  return set.find(key) != set.end();
}

bool FormatUsageAuthority::IsInternalFormatEnumValid(
    GLenum internalFormat) const {
  return Contains(mValidTexInternalFormats, internalFormat);
}

bool FormatUsageAuthority::AreUnpackEnumsValid(GLenum unpackFormat,
                                               GLenum unpackType) const {
  return (Contains(mValidTexUnpackFormats, unpackFormat) &&
          Contains(mValidTexUnpackTypes, unpackType));
}

////////////////////

void FormatUsageAuthority::AllowRBFormat(GLenum sizedFormat,
                                         const FormatUsageInfo* usage,
                                         const bool expectRenderable) {
  MOZ_ASSERT(!usage->format->compression);
  MOZ_ASSERT(usage->format->sizedFormat);
  MOZ_ASSERT(usage->IsRenderable() || !expectRenderable);

  const auto& found = mRBFormatMap.find(sizedFormat);
  if (found != mRBFormatMap.end()) {
    MOZ_ASSERT(found->second == usage);
    return;
  }
  AlwaysInsert(mRBFormatMap, sizedFormat, usage);
}

void FormatUsageAuthority::AllowSizedTexFormat(GLenum sizedFormat,
                                               const FormatUsageInfo* usage) {
  if (usage->format->compression) {
    MOZ_ASSERT(usage->isFilterable, "Compressed formats should be filterable.");
  } else {
    MOZ_ASSERT(!usage->validUnpacks.empty() && usage->idealUnpack,
               "AddTexUnpack() first.");
  }

  AlwaysInsert(mSizedTexFormatMap, sizedFormat, usage);

  mValidTexInternalFormats.insert(sizedFormat);
}

void FormatUsageAuthority::AllowUnsizedTexFormat(const PackingInfo& pi,
                                                 const FormatUsageInfo* usage) {
  MOZ_ASSERT(!usage->format->compression);
  MOZ_ASSERT(!usage->validUnpacks.empty() && usage->idealUnpack,
             "AddTexUnpack() first.");

  AlwaysInsert(mUnsizedTexFormatMap, pi, usage);

  mValidTexInternalFormats.insert(pi.format);
  mValidTexUnpackFormats.insert(pi.format);
  mValidTexUnpackTypes.insert(pi.type);
}

const FormatUsageInfo* FormatUsageAuthority::GetRBUsage(
    GLenum sizedFormat) const {
  return FindOrNull(mRBFormatMap, sizedFormat);
}

const FormatUsageInfo* FormatUsageAuthority::GetSizedTexUsage(
    GLenum sizedFormat) const {
  return FindOrNull(mSizedTexFormatMap, sizedFormat);
}

const FormatUsageInfo* FormatUsageAuthority::GetUnsizedTexUsage(
    const PackingInfo& pi) const {
  return FindOrNull(mUnsizedTexFormatMap, pi);
}

FormatUsageInfo* FormatUsageAuthority::EditUsage(EffectiveFormat format) {
  auto itr = mUsageMap.find(format);

  if (itr == mUsageMap.end()) {
    const FormatInfo* formatInfo = GetFormat(format);
    MOZ_RELEASE_ASSERT(formatInfo, "GFX: no format info set.");

    FormatUsageInfo usage(formatInfo);

    auto res = mUsageMap.insert({format, usage});
    DebugOnly<bool> didInsert = res.second;
    MOZ_ASSERT(didInsert);

    itr = res.first;
  }

  return &(itr->second);
}

const FormatUsageInfo* FormatUsageAuthority::GetUsage(
    EffectiveFormat format) const {
  auto itr = mUsageMap.find(format);
  if (itr == mUsageMap.end()) return nullptr;

  return &(itr->second);
}

////////////////////////////////////////////////////////////////////////////////

}  // namespace mozilla::webgl

Messung V0.5
C=89 H=97 G=93

¤ Dauer der Verarbeitung: 0.16 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.