summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLFormats.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLFormats.cpp')
-rw-r--r--dom/canvas/WebGLFormats.cpp1227
1 files changed, 1227 insertions, 0 deletions
diff --git a/dom/canvas/WebGLFormats.cpp b/dom/canvas/WebGLFormats.cpp
new file mode 100644
index 0000000000..e27d9d1335
--- /dev/null
+++ b/dom/canvas/WebGLFormats.cpp
@@ -0,0 +1,1227 @@
+/* -*- 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);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+std::map<EffectiveFormat, const CompressedFormatInfo> gCompressedFormatInfoMap;
+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_STENCIL, false, 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, false, ComponentType::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, false, ComponentType::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
+}
+
+UniquePtr<FormatUsageAuthority> FormatUsageAuthority::CreateForWebGL1(
+ gl::GLContext* gl) {
+ UniquePtr<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, true, true);
+ fnSet(EffectiveFormat::RGBA4, true, true);
+ fnSet(EffectiveFormat::RGB5_A1, true, true);
+ fnSet(EffectiveFormat::RGB565, true, true);
+
+ // 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, true, true);
+
+ fnSet(EffectiveFormat::Luminance8Alpha8, false, true);
+ fnSet(EffectiveFormat::Luminance8, false, true);
+ fnSet(EffectiveFormat::Alpha8, false, true);
+
+ fnSet(EffectiveFormat::DEPTH_COMPONENT16, true, true);
+ fnSet(EffectiveFormat::DEPTH_COMPONENT24, true,
+ true); // Requires WEBGL_depth_texture.
+ fnSet(EffectiveFormat::STENCIL_INDEX8, true, false);
+
+ // Added in WebGL 1.0 spec:
+ fnSet(EffectiveFormat::DEPTH24_STENCIL8, true, true);
+
+ ////////////////////////////////////
+ // 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;
+}
+
+UniquePtr<FormatUsageAuthority> FormatUsageAuthority::CreateForWebGL2(
+ gl::GLContext* gl) {
+ UniquePtr<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), true, true);
+ fnAllowES3TexFormat(FOO(R8_SNORM), false, true);
+ fnAllowES3TexFormat(FOO(RG8), true, true);
+ fnAllowES3TexFormat(FOO(RG8_SNORM), false, true);
+ fnAllowES3TexFormat(FOO(RGB8), true, true);
+ fnAllowES3TexFormat(FOO(RGB8_SNORM), false, true);
+ fnAllowES3TexFormat(FOO(RGB565), true, true);
+ fnAllowES3TexFormat(FOO(RGBA4), true, true);
+ fnAllowES3TexFormat(FOO(RGB5_A1), true, true);
+ fnAllowES3TexFormat(FOO(RGBA8), true, true);
+ fnAllowES3TexFormat(FOO(RGBA8_SNORM), false, true);
+ fnAllowES3TexFormat(FOO(RGB10_A2), true, true);
+ fnAllowES3TexFormat(FOO(RGB10_A2UI), true, false);
+
+ fnAllowES3TexFormat(FOO(SRGB8), false, true);
+ fnAllowES3TexFormat(FOO(SRGB8_ALPHA8), true, true);
+
+ fnAllowES3TexFormat(FOO(R16F), false, true);
+ fnAllowES3TexFormat(FOO(RG16F), false, true);
+ fnAllowES3TexFormat(FOO(RGB16F), false, true);
+ fnAllowES3TexFormat(FOO(RGBA16F), false, true);
+
+ fnAllowES3TexFormat(FOO(R32F), false, false);
+ fnAllowES3TexFormat(FOO(RG32F), false, false);
+ fnAllowES3TexFormat(FOO(RGB32F), false, false);
+ fnAllowES3TexFormat(FOO(RGBA32F), false, false);
+
+ fnAllowES3TexFormat(FOO(R11F_G11F_B10F), false, true);
+ fnAllowES3TexFormat(FOO(RGB9_E5), false, true);
+
+ fnAllowES3TexFormat(FOO(R8I), true, false);
+ fnAllowES3TexFormat(FOO(R8UI), true, false);
+ fnAllowES3TexFormat(FOO(R16I), true, false);
+ fnAllowES3TexFormat(FOO(R16UI), true, false);
+ fnAllowES3TexFormat(FOO(R32I), true, false);
+ fnAllowES3TexFormat(FOO(R32UI), true, false);
+
+ fnAllowES3TexFormat(FOO(RG8I), true, false);
+ fnAllowES3TexFormat(FOO(RG8UI), true, false);
+ fnAllowES3TexFormat(FOO(RG16I), true, false);
+ fnAllowES3TexFormat(FOO(RG16UI), true, false);
+ fnAllowES3TexFormat(FOO(RG32I), true, false);
+ fnAllowES3TexFormat(FOO(RG32UI), true, false);
+
+ fnAllowES3TexFormat(FOO(RGB8I), false, false);
+ fnAllowES3TexFormat(FOO(RGB8UI), false, false);
+ fnAllowES3TexFormat(FOO(RGB16I), false, false);
+ fnAllowES3TexFormat(FOO(RGB16UI), false, false);
+ fnAllowES3TexFormat(FOO(RGB32I), false, false);
+ fnAllowES3TexFormat(FOO(RGB32UI), false, false);
+
+ fnAllowES3TexFormat(FOO(RGBA8I), true, false);
+ fnAllowES3TexFormat(FOO(RGBA8UI), true, false);
+ fnAllowES3TexFormat(FOO(RGBA16I), true, false);
+ fnAllowES3TexFormat(FOO(RGBA16UI), true, false);
+ fnAllowES3TexFormat(FOO(RGBA32I), true, false);
+ fnAllowES3TexFormat(FOO(RGBA32UI), true, false);
+
+ // 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), true, false);
+ fnAllowES3TexFormat(FOO(DEPTH_COMPONENT24), true, false);
+ fnAllowES3TexFormat(FOO(DEPTH_COMPONENT32F), true, false);
+ fnAllowES3TexFormat(FOO(DEPTH24_STENCIL8), true, false);
+ fnAllowES3TexFormat(FOO(DEPTH32F_STENCIL8), true, false);
+
+#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