tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

WebGLTypes.h (37261B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef WEBGLTYPES_H_
      7 #define WEBGLTYPES_H_
      8 
      9 #include <limits>
     10 #include <string>
     11 #include <string_view>
     12 #include <tuple>
     13 #include <type_traits>
     14 #include <unordered_map>
     15 #include <vector>
     16 
     17 #include "GLContextTypes.h"
     18 #include "GLDefs.h"
     19 #include "ImageContainer.h"
     20 #include "gfxTypes.h"
     21 #include "mozilla/Casting.h"
     22 #include "mozilla/CheckedInt.h"
     23 #include "mozilla/EnumTypeTraits.h"
     24 #include "mozilla/IsEnumCase.h"
     25 #include "mozilla/Range.h"
     26 #include "mozilla/RefCounted.h"
     27 #include "mozilla/Result.h"
     28 #include "mozilla/ResultVariant.h"
     29 #include "mozilla/Span.h"
     30 #include "mozilla/TiedFields.h"
     31 #include "mozilla/TypedEnumBits.h"
     32 #include "mozilla/WeakPtr.h"
     33 #include "mozilla/dom/WebGLRenderingContextBinding.h"
     34 #include "mozilla/gfx/2D.h"
     35 #include "mozilla/gfx/BuildConstants.h"
     36 #include "mozilla/gfx/Logging.h"
     37 #include "mozilla/gfx/Point.h"
     38 #include "mozilla/gfx/Rect.h"
     39 #include "mozilla/ipc/Shmem.h"
     40 #include "mozilla/layers/LayersSurfaces.h"
     41 #include "nsString.h"
     42 #include "nsTArray.h"
     43 
     44 // Manual reflection of WebIDL typedefs that are different from their
     45 // OpenGL counterparts.
     46 using WebGLsizeiptr = int64_t;
     47 using WebGLintptr = int64_t;
     48 using WebGLboolean = bool;
     49 
     50 // -
     51 
     52 namespace mozilla {
     53 namespace gl {
     54 class GLContext;  // This is going to be needed a lot.
     55 }  // namespace gl
     56 
     57 // -
     58 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
     59 // only!)
     60 
     61 template <typename DestT>
     62 class ForbidNarrowing final {
     63  DestT mVal;
     64 
     65 public:
     66  template <typename SrcT>
     67  MOZ_IMPLICIT ForbidNarrowing(SrcT val) : mVal(val) {
     68    static_assert(
     69        std::numeric_limits<SrcT>::min() >= std::numeric_limits<DestT>::min(),
     70        "SrcT must be narrower than DestT.");
     71    static_assert(
     72        std::numeric_limits<SrcT>::max() <= std::numeric_limits<DestT>::max(),
     73        "SrcT must be narrower than DestT.");
     74  }
     75 
     76  explicit operator DestT() const { return mVal; }
     77 };
     78 
     79 inline void* malloc(const ForbidNarrowing<size_t> s) {
     80  return ::malloc(size_t(s));
     81 }
     82 
     83 inline void* calloc(const ForbidNarrowing<size_t> n,
     84                    const ForbidNarrowing<size_t> size) {
     85  return ::calloc(size_t(n), size_t(size));
     86 }
     87 
     88 // -
     89 
     90 // TODO: Remove this now-mere-alias.
     91 template <typename From>
     92 inline auto AutoAssertCast(const From val) {
     93  return LazyAssertedCast(val);
     94 }
     95 
     96 const char* GetEnumName(GLenum val, const char* defaultRet = "<unknown>");
     97 std::string EnumString(GLenum val);
     98 
     99 namespace webgl {
    100 template <typename T>
    101 struct QueueParamTraits;
    102 class TexUnpackBytes;
    103 class TexUnpackSurface;
    104 }  // namespace webgl
    105 
    106 class ClientWebGLContext;
    107 struct WebGLTexPboOffset;
    108 class WebGLTexture;
    109 class WebGLBuffer;
    110 class WebGLFramebuffer;
    111 class WebGLProgram;
    112 class WebGLQuery;
    113 class WebGLRenderbuffer;
    114 class WebGLSampler;
    115 class WebGLShader;
    116 class WebGLSync;
    117 class WebGLTexture;
    118 class WebGLTransformFeedback;
    119 class WebGLVertexArray;
    120 
    121 // -
    122 
    123 class VRefCounted : public RefCounted<VRefCounted> {
    124 public:
    125  virtual ~VRefCounted() = default;
    126 
    127 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
    128  virtual const char* typeName() const = 0;
    129  virtual size_t typeSize() const = 0;
    130 #endif
    131 };
    132 
    133 // -
    134 
    135 /*
    136 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
    137 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
    138 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
    139 * desktop OpenGL does not allow that.
    140 */
    141 enum class WebGLVertexAttrib0Status : uint8_t {
    142  Default,                     // default status - no emulation needed
    143  EmulatedUninitializedArray,  // need an artificial attrib 0 array, but
    144                               // contents may be left uninitialized
    145  EmulatedInitializedArray  // need an artificial attrib 0 array, and contents
    146                            // must be initialized
    147 };
    148 
    149 /*
    150 * The formats that may participate, either as source or destination formats,
    151 * in WebGL texture conversions. This includes:
    152 *  - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
    153 *  - additional formats provided by extensions, e.g. RGB32F
    154 *  - additional source formats, depending on browser details, used when
    155 * uploading textures from DOM elements. See gfxImageSurface::Format().
    156 */
    157 enum class WebGLTexelFormat : uint8_t {
    158  // returned by SurfaceFromElementResultToImageSurface to indicate absence of
    159  // image data
    160  None,
    161  // common value for formats for which format conversions are not supported
    162  FormatNotSupportingAnyConversion,
    163  // dummy pseudo-format meaning "use the other format".
    164  // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
    165  // is implicitly treated as being RGB8 itself.
    166  Auto,
    167  // 1-channel formats
    168  A8,
    169  A16F,  // OES_texture_half_float
    170  A32F,  // OES_texture_float
    171  R8,
    172  R16F,  // OES_texture_half_float
    173  R32F,  // OES_texture_float
    174  // 2-channel formats
    175  RA8,
    176  RA16F,  // OES_texture_half_float
    177  RA32F,  // OES_texture_float
    178  RG8,
    179  RG16F,
    180  RG32F,
    181  // 3-channel formats
    182  RGB8,
    183  RGB565,
    184  RGB11F11F10F,
    185  RGB16F,  // OES_texture_half_float
    186  RGB32F,  // OES_texture_float
    187  // 4-channel formats
    188  RGBA8,
    189  RGBA5551,
    190  RGBA4444,
    191  RGBA16F,  // OES_texture_half_float
    192  RGBA32F,  // OES_texture_float
    193  // DOM element source only formats.
    194  RGBX8,
    195  BGRX8,
    196  BGRA8
    197 };
    198 
    199 enum class WebGLTexImageFunc : uint8_t {
    200  TexImage,
    201  TexSubImage,
    202  CopyTexImage,
    203  CopyTexSubImage,
    204  CompTexImage,
    205  CompTexSubImage,
    206 };
    207 
    208 enum class WebGLTexDimensions : uint8_t { Tex2D, Tex3D };
    209 
    210 // Please keep extensions in alphabetic order.
    211 enum class WebGLExtensionID : uint8_t {
    212  ANGLE_instanced_arrays,
    213  EXT_blend_minmax,
    214  EXT_color_buffer_float,
    215  EXT_color_buffer_half_float,
    216  EXT_depth_clamp,
    217  EXT_disjoint_timer_query,
    218  EXT_float_blend,
    219  EXT_frag_depth,
    220  EXT_shader_texture_lod,
    221  EXT_sRGB,
    222  EXT_texture_compression_bptc,
    223  EXT_texture_compression_rgtc,
    224  EXT_texture_filter_anisotropic,
    225  EXT_texture_norm16,
    226  MOZ_debug,
    227  OES_draw_buffers_indexed,
    228  OES_element_index_uint,
    229  OES_fbo_render_mipmap,
    230  OES_standard_derivatives,
    231  OES_texture_float,
    232  OES_texture_float_linear,
    233  OES_texture_half_float,
    234  OES_texture_half_float_linear,
    235  OES_vertex_array_object,
    236  OVR_multiview2,
    237  WEBGL_color_buffer_float,
    238  WEBGL_compressed_texture_astc,
    239  WEBGL_compressed_texture_etc,
    240  WEBGL_compressed_texture_etc1,
    241  WEBGL_compressed_texture_pvrtc,
    242  WEBGL_compressed_texture_s3tc,
    243  WEBGL_compressed_texture_s3tc_srgb,
    244  WEBGL_debug_renderer_info,
    245  WEBGL_debug_shaders,
    246  WEBGL_depth_texture,
    247  WEBGL_draw_buffers,
    248  WEBGL_explicit_present,
    249  WEBGL_lose_context,
    250  WEBGL_provoking_vertex,
    251  Max
    252 };
    253 
    254 class UniqueBuffer final {
    255  // Like unique_ptr<>, but for void* and malloc/calloc/free.
    256  void* mBuffer = nullptr;
    257 
    258 public:
    259  static inline UniqueBuffer Take(void* buffer) {
    260    UniqueBuffer ret;
    261    ret.mBuffer = buffer;
    262    return ret;
    263  }
    264 
    265  UniqueBuffer() = default;
    266 
    267  ~UniqueBuffer() { reset(); }
    268 
    269  UniqueBuffer(UniqueBuffer&& rhs) { *this = std::move(rhs); }
    270 
    271  UniqueBuffer& operator=(UniqueBuffer&& rhs) {
    272    reset();
    273    this->mBuffer = rhs.mBuffer;
    274    rhs.mBuffer = nullptr;
    275    return *this;
    276  }
    277 
    278  explicit operator bool() const { return bool(mBuffer); }
    279 
    280  void* get() const { return mBuffer; }
    281 
    282  void reset() {
    283    // Believe it or not, when `free` unconditional, it was showing up
    284    // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
    285    // on Aquarium.
    286    if (mBuffer) {
    287      free(mBuffer);
    288      mBuffer = nullptr;
    289    }
    290  }
    291 };
    292 
    293 namespace webgl {
    294 struct FormatUsageInfo;
    295 
    296 static constexpr GLenum kErrorPerfWarning = 0x10001;
    297 
    298 struct SampleableInfo final {
    299  const char* incompleteReason = nullptr;
    300  uint32_t levels = 0;
    301  const webgl::FormatUsageInfo* usage = nullptr;
    302  bool isDepthTexCompare = false;
    303 
    304  bool IsComplete() const { return bool(levels); }
    305 };
    306 
    307 enum class AttribBaseType : uint8_t {
    308  Boolean,  // Can convert from anything.
    309  Float,    // Also includes NormU?Int
    310  Int,
    311  Uint,
    312 };
    313 }  // namespace webgl
    314 template <>
    315 inline constexpr bool IsEnumCase<webgl::AttribBaseType>(
    316    const webgl::AttribBaseType v) {
    317  switch (v) {
    318    case webgl::AttribBaseType::Boolean:
    319    case webgl::AttribBaseType::Float:
    320    case webgl::AttribBaseType::Int:
    321    case webgl::AttribBaseType::Uint:
    322      return true;
    323  }
    324  return false;
    325 }
    326 namespace webgl {
    327 webgl::AttribBaseType ToAttribBaseType(GLenum);
    328 const char* ToString(AttribBaseType);
    329 
    330 enum class UniformBaseType : uint8_t {
    331  Float,
    332  Int,
    333  Uint,
    334 };
    335 const char* ToString(UniformBaseType);
    336 
    337 using ObjectId = uint64_t;
    338 
    339 enum class BufferKind : uint8_t {
    340  Undefined,
    341  Index,
    342  NonIndex,
    343 };
    344 
    345 }  // namespace webgl
    346 
    347 // -
    348 
    349 struct FloatOrInt final  // For TexParameter[fi] and friends.
    350 {
    351  bool isFloat = false;
    352  uint8_t padding[3] = {};
    353  GLfloat f = 0;
    354  GLint i = 0;
    355 
    356  explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
    357 
    358  explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
    359 
    360  auto MutTiedFields() { return std::tie(isFloat, padding, f, i); }
    361 };
    362 
    363 // -
    364 
    365 struct WebGLContextOptions final {
    366  bool alpha = true;
    367  bool depth = true;
    368  bool stencil = false;
    369  bool premultipliedAlpha = true;
    370 
    371  bool antialias = true;
    372  bool preserveDrawingBuffer = false;
    373  bool failIfMajorPerformanceCaveat = false;
    374  bool xrCompatible = false;
    375 
    376  dom::WebGLPowerPreference powerPreference =
    377      dom::WebGLPowerPreference::Default;
    378  bool forceSoftwareRendering = false;
    379  bool shouldResistFingerprinting = true;
    380  bool enableDebugRendererInfo = false;
    381 
    382  auto MutTiedFields() {
    383    // clang-format off
    384    return std::tie(
    385      alpha,
    386      depth,
    387      stencil,
    388      premultipliedAlpha,
    389 
    390      antialias,
    391      preserveDrawingBuffer,
    392      failIfMajorPerformanceCaveat,
    393      xrCompatible,
    394 
    395      powerPreference,
    396      forceSoftwareRendering,
    397      shouldResistFingerprinting,
    398      enableDebugRendererInfo);
    399    // clang-format on
    400  }
    401 
    402  // -
    403 
    404  WebGLContextOptions();
    405  WebGLContextOptions(const WebGLContextOptions&) = default;
    406 
    407  using Self = WebGLContextOptions;
    408  friend bool operator==(const Self& a, const Self& b) {
    409    return TiedFields(a) == TiedFields(b);
    410  }
    411  friend bool operator!=(const Self& a, const Self& b) { return !(a == b); }
    412 };
    413 
    414 namespace gfx {
    415 
    416 inline ColorSpace2 ToColorSpace2(const dom::PredefinedColorSpace cs) {
    417  switch (cs) {
    418    case dom::PredefinedColorSpace::Srgb:
    419      return ColorSpace2::SRGB;
    420    case dom::PredefinedColorSpace::Display_p3:
    421      return ColorSpace2::DISPLAY_P3;
    422  }
    423  MOZ_CRASH("Exhaustive switch");
    424 }
    425 
    426 }  // namespace gfx
    427 
    428 // -
    429 
    430 template <typename _T>
    431 struct avec2 {
    432  using T = _T;
    433 
    434  T x = T();
    435  T y = T();
    436 
    437  auto MutTiedFields() { return std::tie(x, y); }
    438 
    439  template <typename U, typename V>
    440  static Maybe<avec2> From(const U _x, const V _y) {
    441    const auto x = CheckedInt<T>(_x);
    442    const auto y = CheckedInt<T>(_y);
    443    if (!x.isValid() || !y.isValid()) return {};
    444    return Some(avec2(x.value(), y.value()));
    445  }
    446 
    447  template <typename U>
    448  static auto From(const U& val) {
    449    return From(val.x, val.y);
    450  }
    451  template <typename U>
    452  static auto FromSize(const U& val) {
    453    return From(val.width, val.height);
    454  }
    455 
    456  avec2() = default;
    457  avec2(const T _x, const T _y) : x(_x), y(_y) {}
    458 
    459  bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
    460  bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
    461 
    462 #define _(OP)                                 \
    463  avec2 operator OP(const avec2& rhs) const { \
    464    return {x OP rhs.x, y OP rhs.y};          \
    465  }                                           \
    466  avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
    467 
    468  _(+)
    469  _(-)
    470  _(*)
    471  _(/)
    472 
    473 #undef _
    474 
    475  avec2 Clamp(const avec2& min, const avec2& max) const {
    476    return {std::clamp(x, min.x, max.x), std::clamp(y, min.y, max.y)};
    477  }
    478 
    479  template <typename U>
    480  U StaticCast() const {
    481    return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
    482  }
    483 };
    484 
    485 template <typename T>
    486 avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
    487  return {std::min(a.x, b.x), std::min(a.y, b.y)};
    488 }
    489 
    490 template <typename T>
    491 avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
    492  return {std::max(a.x, b.x), std::max(a.y, b.y)};
    493 }
    494 
    495 // -
    496 
    497 template <typename _T>
    498 struct avec3 {
    499  using T = _T;
    500 
    501  T x = T();
    502  T y = T();
    503  T z = T();
    504 
    505  auto MutTiedFields() { return std::tie(x, y, z); }
    506 
    507  template <typename U, typename V>
    508  static Maybe<avec3> From(const U _x, const V _y, const V _z) {
    509    const auto x = CheckedInt<T>(_x);
    510    const auto y = CheckedInt<T>(_y);
    511    const auto z = CheckedInt<T>(_z);
    512    if (!x.isValid() || !y.isValid() || !z.isValid()) return {};
    513    return Some(avec3(x.value(), y.value(), z.value()));
    514  }
    515 
    516  template <typename U>
    517  static auto From(const U& val) {
    518    return From(val.x, val.y, val.z);
    519  }
    520 
    521  avec3() = default;
    522  avec3(const T _x, const T _y, const T _z) : x(_x), y(_y), z(_z) {}
    523 
    524  bool operator==(const avec3& rhs) const {
    525    return x == rhs.x && y == rhs.y && z == rhs.z;
    526  }
    527  bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
    528 };
    529 
    530 using ivec2 = avec2<int32_t>;
    531 using ivec3 = avec3<int32_t>;
    532 using uvec2 = avec2<uint32_t>;
    533 using uvec3 = avec3<uint32_t>;
    534 
    535 inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
    536 
    537 // -
    538 
    539 namespace webgl {
    540 
    541 struct PackingInfo final {
    542  GLenum format = 0;
    543  GLenum type = 0;
    544 
    545  auto MutTiedFields() { return std::tie(format, type); }
    546 
    547  using Self = PackingInfo;
    548  friend bool operator<(const Self& a, const Self& b) {
    549    return TiedFields(a) < TiedFields(b);
    550  }
    551  friend bool operator==(const Self& a, const Self& b) {
    552    return TiedFields(a) == TiedFields(b);
    553  }
    554  friend bool operator!=(const Self& a, const Self& b) {
    555    return TiedFields(a) != TiedFields(b);
    556  }
    557 
    558  template <class T>
    559  friend T& operator<<(T& s, const PackingInfo& pi) {
    560    s << "PackingInfo{format: " << EnumString(pi.format)
    561      << ", type: " << EnumString(pi.type) << "}";
    562    return s;
    563  }
    564 };
    565 std::string format_as(const PackingInfo& pi);
    566 
    567 struct DriverUnpackInfo final {
    568  using Self = DriverUnpackInfo;
    569 
    570  GLenum internalFormat = 0;
    571  GLenum unpackFormat = 0;
    572  GLenum unpackType = 0;
    573 
    574  PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
    575 
    576  template <class ConstOrMutSelf>
    577  static constexpr auto Fields(ConstOrMutSelf& self) {
    578    return std::tie(self.internalFormat, self.unpackFormat, self.unpackType);
    579  }
    580 
    581  constexpr bool operator==(const Self& rhs) const {
    582    return Fields(*this) == Fields(rhs);
    583  }
    584  constexpr bool operator!=(const Self& rhs) const {
    585    return Fields(*this) != Fields(rhs);
    586  }
    587 };
    588 
    589 // -
    590 
    591 template <typename E>
    592 class EnumMask {
    593 public:
    594  uint64_t mBits = 0;
    595 
    596 private:
    597  struct BitRef final {
    598    EnumMask& bits;
    599    const uint64_t mask;
    600 
    601    explicit operator bool() const { return bits.mBits & mask; }
    602 
    603    auto& operator=(const bool val) {
    604      if (val) {
    605        bits.mBits |= mask;
    606      } else {
    607        bits.mBits &= ~mask;
    608      }
    609      return *this;
    610    }
    611  };
    612 
    613  uint64_t Mask(const E i) const {
    614    return uint64_t{1} << static_cast<uint64_t>(i);
    615  }
    616 
    617 public:
    618  BitRef operator[](const E i) { return {*this, Mask(i)}; }
    619  bool operator[](const E i) const { return mBits & Mask(i); }
    620 
    621  // -
    622 
    623  auto MutTiedFields() { return std::tie(mBits); }
    624 };
    625 
    626 using ExtensionBits = EnumMask<WebGLExtensionID>;
    627 
    628 // -
    629 
    630 enum class ContextLossReason : uint8_t {
    631  None,
    632  Manual,
    633  Guilty,
    634 };
    635 
    636 inline bool ReadContextLossReason(const uint8_t val,
    637                                  ContextLossReason* const out) {
    638  if (val > static_cast<uint8_t>(ContextLossReason::Guilty)) {
    639    return false;
    640  }
    641  *out = static_cast<ContextLossReason>(val);
    642  return true;
    643 }
    644 
    645 // -
    646 
    647 struct InitContextDesc final {
    648  bool isWebgl2 = false;
    649  bool resistFingerprinting = false;
    650  std::array<uint8_t, 2> _padding;
    651  uint32_t principalKey = 0;
    652  uvec2 size = {};
    653  WebGLContextOptions options;
    654 
    655  auto MutTiedFields() {
    656    return std::tie(isWebgl2, resistFingerprinting, _padding, principalKey,
    657                    size, options);
    658  }
    659 };
    660 
    661 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs = 4;
    662 
    663 struct Limits final {
    664  ExtensionBits supportedExtensions;
    665 
    666  // WebGL 1
    667  uint32_t maxTexUnits = 0;
    668  uint32_t maxTex2dSize = 0;
    669  uint32_t maxTexCubeSize = 0;
    670  uint32_t maxVertexAttribs = 0;
    671  uint32_t maxViewportDim = 0;
    672  std::array<float, 2> pointSizeRange = {{1, 1}};
    673  std::array<float, 2> lineWidthRange = {{1, 1}};
    674 
    675  // WebGL 2
    676  uint32_t maxTexArrayLayers = 0;
    677  uint32_t maxTex3dSize = 0;
    678  uint32_t maxUniformBufferBindings = 0;
    679  uint32_t uniformBufferOffsetAlignment = 0;
    680 
    681  // Exts
    682  bool astcHdr = false;
    683  std::array<uint8_t, 3> _padding;
    684  uint32_t maxColorDrawBuffers = 1;
    685  uint32_t maxMultiviewLayers = 0;
    686  uint64_t queryCounterBitsTimeElapsed = 0;
    687  uint64_t queryCounterBitsTimestamp = 0;
    688 
    689  auto MutTiedFields() {
    690    return std::tie(supportedExtensions,
    691 
    692                    maxTexUnits, maxTex2dSize, maxTexCubeSize, maxVertexAttribs,
    693                    maxViewportDim, pointSizeRange, lineWidthRange,
    694 
    695                    maxTexArrayLayers, maxTex3dSize, maxUniformBufferBindings,
    696                    uniformBufferOffsetAlignment,
    697 
    698                    astcHdr, _padding, maxColorDrawBuffers, maxMultiviewLayers,
    699                    queryCounterBitsTimeElapsed, queryCounterBitsTimestamp);
    700  }
    701 };
    702 
    703 // -
    704 namespace details {
    705 template <class T, size_t Padding>
    706 struct PaddedBase {
    707 protected:
    708  T val = {};
    709 
    710 private:
    711  uint8_t padding[Padding] = {};
    712 };
    713 
    714 template <class T>
    715 struct PaddedBase<T, 0> {
    716 protected:
    717  T val = {};
    718 };
    719 }  // namespace details
    720 
    721 template <class T, size_t PaddedSize>
    722 struct Padded : details::PaddedBase<T, PaddedSize - sizeof(T)> {
    723  static_assert(PaddedSize >= sizeof(T));
    724 
    725  // Try to be invisible:
    726  operator T&() { return this->val; }
    727  operator const T&() const { return this->val; }
    728 
    729  auto& operator=(const T& rhs) { return this->val = rhs; }
    730  auto& operator=(T&& rhs) { return this->val = std::move(rhs); }
    731 
    732  auto& operator*() { return this->val; }
    733  auto& operator*() const { return this->val; }
    734  auto operator->() { return &this->val; }
    735  auto operator->() const { return &this->val; }
    736 };
    737 
    738 // -
    739 
    740 enum class OptionalRenderableFormatBits : uint8_t {
    741  RGB8 = (1 << 0),
    742  SRGB8 = (1 << 1),
    743 };
    744 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OptionalRenderableFormatBits)
    745 
    746 }  // namespace webgl
    747 template <>
    748 inline constexpr bool IsEnumCase<webgl::OptionalRenderableFormatBits>(
    749    const webgl::OptionalRenderableFormatBits raw) {
    750  auto rawWithoutValidBits = UnderlyingValue(raw);
    751  auto bit = decltype(rawWithoutValidBits){1};
    752  while (bit) {
    753    switch (webgl::OptionalRenderableFormatBits{bit}) {
    754      // -Werror=switch ensures exhaustive.
    755      case webgl::OptionalRenderableFormatBits::RGB8:
    756      case webgl::OptionalRenderableFormatBits::SRGB8:
    757        rawWithoutValidBits &= ~bit;
    758        break;
    759    }
    760    bit <<= 1;
    761  }
    762  return rawWithoutValidBits == 0;
    763 }
    764 namespace webgl {
    765 
    766 // -
    767 
    768 using GetShaderPrecisionFormatArgs = std::tuple<GLenum, GLenum>;
    769 
    770 template <class Tuple>
    771 struct TupleStdHash {
    772  size_t operator()(const Tuple& t) const {
    773    size_t ret = 0;
    774    mozilla::MapTuple(t, [&](const auto& field) {
    775      using FieldT = std::remove_cv_t<std::remove_reference_t<decltype(field)>>;
    776      ret ^= std::hash<FieldT>{}(field);
    777      return true;  // ignored
    778    });
    779    return ret;
    780  }
    781 };
    782 
    783 struct ShaderPrecisionFormat final {
    784  // highp float: [127, 127, 23]
    785  // highp int: [31, 30, 0]
    786  uint8_t rangeMin = 0;  // highp float: +127 (meaning 2^-127)
    787  uint8_t rangeMax = 0;
    788  uint8_t precision = 0;
    789  uint8_t _padding = 0;
    790 
    791  auto MutTiedFields() {
    792    return std::tie(rangeMin, rangeMax, precision, _padding);
    793  }
    794 };
    795 
    796 // -
    797 
    798 struct InitContextResult final {
    799  Padded<std::string, 32> error;  // MINGW 32-bit needs this padding.
    800  WebGLContextOptions options;
    801  gl::GLVendor vendor;
    802  OptionalRenderableFormatBits optionalRenderableFormatBits;
    803  std::array<uint8_t, 2> _padding = {};
    804  Limits limits;
    805  EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
    806  // Padded because of "Android 5.0 ARMv7" builds:
    807  Padded<std::unordered_map<GetShaderPrecisionFormatArgs, ShaderPrecisionFormat,
    808                            TupleStdHash<GetShaderPrecisionFormatArgs>>,
    809         64>
    810      shaderPrecisions;
    811 
    812  auto MutTiedFields() {
    813    return std::tie(error, options, vendor, optionalRenderableFormatBits,
    814                    _padding, limits, uploadableSdTypes, shaderPrecisions);
    815  }
    816 };
    817 
    818 // -
    819 
    820 struct ErrorInfo final {
    821  GLenum type;
    822  std::string info;
    823 };
    824 
    825 // -
    826 
    827 enum class LossStatus {
    828  Ready,
    829 
    830  Lost,
    831  LostForever,
    832  LostManually,
    833 };
    834 
    835 // -
    836 
    837 struct CompileResult final {
    838  bool pending = true;
    839  nsCString log;
    840  nsCString translatedSource;
    841  bool success = false;
    842 };
    843 
    844 // -
    845 
    846 struct OpaqueFramebufferOptions final {
    847  bool depthStencil = true;
    848  bool antialias = true;
    849  std::array<uint8_t, 2> _padding;
    850  uint32_t width = 0;
    851  uint32_t height = 0;
    852 
    853  auto MutTiedFields() {
    854    return std::tie(depthStencil, antialias, _padding, width, height);
    855  }
    856 };
    857 
    858 // -
    859 
    860 struct SwapChainOptions final {
    861  layers::RemoteTextureId remoteTextureId;
    862  layers::RemoteTextureOwnerId remoteTextureOwnerId;
    863  bool bgra = false;
    864  bool forceAsyncPresent = false;
    865  // Pad to sizeof(u64):
    866  uint16_t padding1 = 0;
    867  uint32_t padding2 = 0;
    868 
    869  auto MutTiedFields() {
    870    return std::tie(remoteTextureId, remoteTextureOwnerId, bgra,
    871                    forceAsyncPresent, padding1, padding2);
    872  }
    873 };
    874 
    875 // -
    876 
    877 struct ActiveInfo {
    878  GLenum elemType = 0;     // `type`
    879  uint32_t elemCount = 0;  // `size`
    880  std::string name;
    881 };
    882 
    883 struct ActiveAttribInfo final : public ActiveInfo {
    884  int32_t location = -1;
    885  AttribBaseType baseType = AttribBaseType::Float;
    886 };
    887 
    888 struct ActiveUniformInfo final : public ActiveInfo {
    889  std::unordered_map<uint32_t, uint32_t>
    890      locByIndex;  // Uniform array locations are sparse.
    891  int32_t block_index = -1;
    892  int32_t block_offset = -1;  // In block, offset.
    893  int32_t block_arrayStride = -1;
    894  int32_t block_matrixStride = -1;
    895  bool block_isRowMajor = false;
    896 };
    897 
    898 struct ActiveUniformBlockInfo final {
    899  std::string name;
    900  // BLOCK_BINDING is dynamic state
    901  uint32_t dataSize = 0;
    902  std::vector<uint32_t> activeUniformIndices;
    903  bool referencedByVertexShader = false;
    904  bool referencedByFragmentShader = false;
    905 };
    906 
    907 struct LinkActiveInfo final {
    908  std::vector<ActiveAttribInfo> activeAttribs;
    909  std::vector<ActiveUniformInfo> activeUniforms;
    910  std::vector<ActiveUniformBlockInfo> activeUniformBlocks;
    911  std::vector<ActiveInfo> activeTfVaryings;
    912 };
    913 
    914 struct LinkResult final : public SupportsWeakPtr {
    915  LinkResult() {}
    916  ~LinkResult() = default;
    917 
    918  bool pending = true;
    919  nsCString log;
    920  bool success = false;
    921  LinkActiveInfo active;
    922  GLenum tfBufferMode = 0;
    923 };
    924 
    925 // -
    926 
    927 /// 4x32-bit primitives, with a type tag.
    928 struct TypedQuad final {
    929  alignas(alignof(float)) std::array<uint8_t, 4 * sizeof(float)> data = {};
    930  webgl::AttribBaseType type = webgl::AttribBaseType::Float;
    931  uint8_t padding[3] = {};
    932 
    933  constexpr auto MutTiedFields() { return std::tie(data, type, padding); }
    934 };
    935 
    936 /// [1-16]x32-bit primitives, with a type tag.
    937 struct GetUniformData final {
    938  alignas(alignof(float)) uint8_t data[4 * 4 * sizeof(float)] = {};
    939  GLenum type = 0;
    940 };
    941 
    942 struct FrontBufferSnapshotIpc final {
    943  uvec2 surfSize = {};
    944  size_t byteStride = 0;
    945  Maybe<mozilla::ipc::Shmem> shmem = {};
    946 };
    947 
    948 struct ReadPixelsResult {
    949  gfx::IntRect subrect = {};
    950  size_t byteStride = 0;
    951 };
    952 
    953 struct ReadPixelsResultIpc final : public ReadPixelsResult {
    954  Maybe<mozilla::ipc::Shmem> shmem = {};
    955 };
    956 
    957 struct VertAttribPointerDesc final {
    958  bool intFunc = false;
    959  uint8_t channels = 4;
    960  bool normalized = false;
    961  uint8_t byteStrideOrZero = 0;
    962  GLenum type = LOCAL_GL_FLOAT;
    963  uint64_t byteOffset = 0;
    964 
    965  auto MutTiedFields() {
    966    return std::tie(intFunc, channels, normalized, byteStrideOrZero, type,
    967                    byteOffset);
    968  }
    969 };
    970 
    971 struct VertAttribPointerCalculated final {
    972  uint8_t byteSize = 4 * 4;
    973  uint8_t byteStride = 4 * 4;  // at-most 255
    974  webgl::AttribBaseType baseType = webgl::AttribBaseType::Float;
    975 };
    976 
    977 }  // namespace webgl
    978 
    979 template <class T>
    980 inline Range<T> ShmemRange(const mozilla::ipc::Shmem& shmem) {
    981  return {shmem.get<T>(), shmem.Size<T>()};
    982 }
    983 
    984 // -
    985 
    986 template <typename C, typename K>
    987 inline auto MaybeFind(C& container, const K& key)
    988    -> decltype(&(container.find(key)->second)) {
    989  const auto itr = container.find(key);
    990  if (itr == container.end()) return nullptr;
    991  return &(itr->second);
    992 }
    993 
    994 template <typename C, typename K>
    995 inline typename C::mapped_type Find(
    996    const C& container, const K& key,
    997    const typename C::mapped_type notFound = {}) {
    998  const auto itr = container.find(key);
    999  if (itr == container.end()) return notFound;
   1000  return itr->second;
   1001 }
   1002 
   1003 // -
   1004 
   1005 template <typename T, typename U>
   1006 inline Maybe<T> MaybeAs(const U val) {
   1007  const auto checked = CheckedInt<T>(val);
   1008  if (!checked.isValid()) return {};
   1009  return Some(checked.value());
   1010 }
   1011 
   1012 // -
   1013 
   1014 inline GLenum IsTexMipmapFilter(const GLenum texFilter) {
   1015  switch (texFilter) {
   1016    case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
   1017    case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
   1018    case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
   1019    case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
   1020      return true;
   1021  }
   1022  return false;
   1023 }
   1024 
   1025 inline GLenum IsTexImageTarget(const GLenum imageTarget) {
   1026  switch (imageTarget) {
   1027    case LOCAL_GL_TEXTURE_2D:
   1028    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1029    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1030    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1031    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1032    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1033    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1034    case LOCAL_GL_TEXTURE_3D:
   1035    case LOCAL_GL_TEXTURE_2D_ARRAY:
   1036      return true;
   1037  }
   1038  return false;
   1039 }
   1040 
   1041 inline GLenum ImageToTexTarget(const GLenum imageTarget) {
   1042  switch (imageTarget) {
   1043    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   1044    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   1045    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   1046    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   1047    case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   1048    case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   1049      return LOCAL_GL_TEXTURE_CUBE_MAP;
   1050  }
   1051  if (IsTexImageTarget(imageTarget)) {
   1052    return imageTarget;
   1053  }
   1054  return 0;
   1055 }
   1056 
   1057 inline bool IsTexTarget3D(const GLenum texTarget) {
   1058  switch (texTarget) {
   1059    case LOCAL_GL_TEXTURE_2D_ARRAY:
   1060    case LOCAL_GL_TEXTURE_3D:
   1061      return true;
   1062 
   1063    default:
   1064      return false;
   1065  }
   1066 }
   1067 
   1068 // -
   1069 
   1070 namespace dom {
   1071 class Element;
   1072 class ImageBitmap;
   1073 class ImageData;
   1074 class OffscreenCanvas;
   1075 class VideoFrame;
   1076 }  // namespace dom
   1077 
   1078 struct TexImageSource {
   1079  const dom::ArrayBufferView* mView = nullptr;
   1080  GLuint mViewElemOffset = 0;
   1081  GLuint mViewElemLengthOverride = 0;
   1082 
   1083  const WebGLintptr* mPboOffset = nullptr;
   1084 
   1085  const dom::ImageBitmap* mImageBitmap = nullptr;
   1086  const dom::ImageData* mImageData = nullptr;
   1087 
   1088  const dom::OffscreenCanvas* mOffscreenCanvas = nullptr;
   1089 
   1090  const dom::VideoFrame* mVideoFrame = nullptr;
   1091 
   1092  const dom::Element* mDomElem = nullptr;
   1093  ErrorResult* mOut_error = nullptr;
   1094 };
   1095 
   1096 namespace webgl {
   1097 
   1098 template <class DerivedT>
   1099 struct DeriveNotEq {
   1100  bool operator!=(const DerivedT& rhs) const {
   1101    const auto self = reinterpret_cast<const DerivedT*>(this);
   1102    return !(*self == rhs);
   1103  }
   1104 };
   1105 
   1106 struct PixelPackingState : public DeriveNotEq<PixelPackingState> {
   1107  uint32_t alignmentInTypeElems = 4;  // ALIGNMENT isn't naive byte alignment!
   1108  uint32_t rowLength = 0;
   1109  uint32_t imageHeight = 0;
   1110  uint32_t skipPixels = 0;
   1111  uint32_t skipRows = 0;
   1112  uint32_t skipImages = 0;
   1113 
   1114  auto MutTiedFields() {
   1115    return std::tie(alignmentInTypeElems, rowLength, imageHeight, skipPixels,
   1116                    skipRows, skipImages);
   1117  }
   1118 
   1119  using Self = PixelPackingState;
   1120  friend bool operator==(const Self& a, const Self& b) {
   1121    return TiedFields(a) == TiedFields(b);
   1122  }
   1123 
   1124  static void AssertDefaultUnpack(gl::GLContext& gl, const bool isWebgl2) {
   1125    PixelPackingState{}.AssertCurrentUnpack(gl, isWebgl2);
   1126  }
   1127 
   1128  void ApplyUnpack(gl::GLContext&, bool isWebgl2,
   1129                   const uvec3& uploadSize) const;
   1130  bool AssertCurrentUnpack(gl::GLContext&, bool isWebgl2) const;
   1131 };
   1132 
   1133 struct PixelUnpackStateWebgl final : public PixelPackingState {
   1134  GLenum colorspaceConversion =
   1135      dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
   1136  bool flipY = false;
   1137  bool premultiplyAlpha = false;
   1138  bool requireFastPath = false;
   1139  uint8_t padding = {};
   1140 
   1141  auto MutTiedFields() {
   1142    return std::tuple_cat(PixelPackingState::MutTiedFields(),
   1143                          std::tie(colorspaceConversion, flipY,
   1144                                   premultiplyAlpha, requireFastPath, padding));
   1145  }
   1146 };
   1147 
   1148 struct ExplicitPixelPackingState final {
   1149  struct Metrics final {
   1150    uvec3 usedSize = {};
   1151    size_t bytesPerPixel = 0;
   1152 
   1153    // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
   1154    // ...aligned to ALIGNMENT.
   1155    size_t bytesPerRowStride = 0;
   1156 
   1157    // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
   1158    size_t totalRows = 0;
   1159 
   1160    // This ensures that no one else needs to do CheckedInt math.
   1161    size_t totalBytesUsed = 0;
   1162    size_t totalBytesStrided = 0;
   1163  };
   1164 
   1165  // It's so important that these aren't modified once evaluated.
   1166  const PixelPackingState state;
   1167  const Metrics metrics;
   1168 
   1169  static Result<ExplicitPixelPackingState, std::string> ForUseWith(
   1170      const PixelPackingState&, GLenum target, const uvec3& subrectSize,
   1171      const webgl::PackingInfo&, const Maybe<size_t> bytesPerRowStrideOverride);
   1172 };
   1173 
   1174 struct ReadPixelsDesc final {
   1175  ivec2 srcOffset;
   1176  uvec2 size;
   1177  PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
   1178  PixelPackingState packState;
   1179 
   1180  auto MutTiedFields() { return std::tie(srcOffset, size, pi, packState); }
   1181 };
   1182 
   1183 }  // namespace webgl
   1184 
   1185 namespace webgl {
   1186 
   1187 struct TexUnpackBlobDesc final {
   1188  GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
   1189  uvec3 size;
   1190  gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
   1191 
   1192  Maybe<Span<const uint8_t>> cpuData;
   1193  Maybe<uint64_t> pboOffset;
   1194 
   1195  Maybe<uvec2> structuredSrcSize;
   1196  RefPtr<layers::Image> image;
   1197  Maybe<layers::SurfaceDescriptor> sd;
   1198  RefPtr<gfx::SourceSurface> sourceSurf;
   1199 
   1200  webgl::PixelUnpackStateWebgl unpacking;
   1201  bool applyUnpackTransforms = true;
   1202 
   1203  // -
   1204 
   1205  auto ExplicitUnpacking(const webgl::PackingInfo& pi,
   1206                         const Maybe<size_t> bytesPerRowStrideOverride) const {
   1207    return ExplicitPixelPackingState::ForUseWith(this->unpacking,
   1208                                                 this->imageTarget, this->size,
   1209                                                 pi, bytesPerRowStrideOverride);
   1210  }
   1211 
   1212  void Shrink(const webgl::PackingInfo&);
   1213 };
   1214 
   1215 }  // namespace webgl
   1216 
   1217 // ---------------------------------------
   1218 // MakeRange
   1219 
   1220 template <typename T, size_t N>
   1221 inline Range<const T> MakeRange(T (&arr)[N]) {
   1222  return {arr, N};
   1223 }
   1224 
   1225 template <typename T>
   1226 inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
   1227  return {seq.Elements(), seq.Length()};
   1228 }
   1229 
   1230 // -
   1231 
   1232 constexpr auto kUniversalAlignment = alignof(std::max_align_t);
   1233 
   1234 template <typename T>
   1235 inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
   1236  MOZ_ASSERT(alignment);
   1237  const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
   1238  const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
   1239  const auto aligned = wholeMultiples * alignment;
   1240  return aligned - begin;
   1241 }
   1242 
   1243 template <typename T>
   1244 inline size_t ByteSize(const Range<T>& range) {
   1245  return range.length() * sizeof(T);
   1246 }
   1247 
   1248 // -
   1249 
   1250 Maybe<webgl::ErrorInfo> CheckBindBufferRange(
   1251    const GLenum target, const GLuint index, const bool isBuffer,
   1252    const uint64_t offset, const uint64_t size, const webgl::Limits& limits);
   1253 
   1254 Maybe<webgl::ErrorInfo> CheckFramebufferAttach(const GLenum bindImageTarget,
   1255                                               const GLenum curTexTarget,
   1256                                               const uint32_t mipLevel,
   1257                                               const uint32_t zLayerBase,
   1258                                               const uint32_t zLayerCount,
   1259                                               const webgl::Limits& limits);
   1260 
   1261 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
   1262 CheckVertexAttribPointer(bool isWebgl2, const webgl::VertAttribPointerDesc&);
   1263 
   1264 uint8_t ElemTypeComponents(GLenum elemType);
   1265 
   1266 inline std::string ToString(const nsACString& text) {
   1267  return {text.BeginReading(), text.Length()};
   1268 }
   1269 
   1270 inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
   1271                   const RangedPtr<const uint8_t>& srcBytes,
   1272                   const size_t byteSize) {
   1273  // Trigger range asserts
   1274  (void)(srcBytes + byteSize);
   1275  (void)(destBytes + byteSize);
   1276 
   1277  memcpy(destBytes.get(), srcBytes.get(), byteSize);
   1278 }
   1279 
   1280 template <class T, class U>
   1281 inline void Memcpy(const Range<T>* const destRange,
   1282                   const RangedPtr<U>& srcBegin) {
   1283  Memcpy(destRange->begin(), srcBegin, destRange->length());
   1284 }
   1285 template <class T, class U>
   1286 inline void Memcpy(const RangedPtr<T>* const destBegin,
   1287                   const Range<U>& srcRange) {
   1288  Memcpy(destBegin, srcRange->begin(), srcRange->length());
   1289 }
   1290 
   1291 template <typename Dst, typename Src>
   1292 inline void Memcpy(const Span<Dst>* const dest, const Span<Src>& src) {
   1293  MOZ_RELEASE_ASSERT(src.size_bytes() >= dest->size_bytes());
   1294  MOZ_ASSERT(src.size_bytes() == dest->size_bytes());
   1295  memcpy(dest->data(), src.data(), dest->size_bytes());
   1296 }
   1297 
   1298 // -
   1299 
   1300 inline bool StartsWith(const std::string_view str,
   1301                       const std::string_view part) {
   1302  return str.find(part) == 0;
   1303 }
   1304 
   1305 // -
   1306 
   1307 namespace webgl {
   1308 
   1309 // In theory, this number can be unbounded based on the driver. However, no
   1310 // driver appears to expose more than 8. We might as well stop there too, for
   1311 // now.
   1312 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
   1313 inline constexpr size_t kMaxDrawBuffers = 8;
   1314 
   1315 union UniformDataVal {
   1316  float f32;
   1317  int32_t i32;
   1318  uint32_t u32;
   1319 };
   1320 
   1321 enum class ProvokingVertex : GLenum {
   1322  FirstVertex = LOCAL_GL_FIRST_VERTEX_CONVENTION,
   1323  LastVertex = LOCAL_GL_LAST_VERTEX_CONVENTION,
   1324 };
   1325 
   1326 }  // namespace webgl
   1327 
   1328 template <>
   1329 inline constexpr bool IsEnumCase<webgl::ProvokingVertex>(
   1330    const webgl::ProvokingVertex raw) {
   1331  switch (raw) {
   1332    case webgl::ProvokingVertex::FirstVertex:
   1333    case webgl::ProvokingVertex::LastVertex:
   1334      return true;
   1335  }
   1336  return false;
   1337 }
   1338 
   1339 namespace webgl {
   1340 
   1341 // -
   1342 
   1343 struct BufferAndIndex final {
   1344  const WebGLBuffer* buffer = nullptr;
   1345  uint32_t id = -1;
   1346 };
   1347 
   1348 }  // namespace webgl
   1349 
   1350 struct IndexedBufferBinding final {
   1351  RefPtr<WebGLBuffer> mBufferBinding;
   1352  uint64_t mRangeStart = 0;
   1353  uint64_t mRangeSize = 0;
   1354 
   1355  IndexedBufferBinding();
   1356  ~IndexedBufferBinding();
   1357 
   1358  uint64_t ByteCount() const;
   1359 };
   1360 
   1361 // -
   1362 
   1363 template <class... Args>
   1364 inline std::string PrintfStdString(const char* const format,
   1365                                   const Args&... args) {
   1366  const auto nsStr = nsPrintfCString(format, args...);
   1367  return ToString(nsStr);
   1368 }
   1369 
   1370 inline const char* ToChars(const bool val) {
   1371  if (val) return "true";
   1372  return "false";
   1373 }
   1374 
   1375 template <class To>
   1376 struct ReinterpretToSpan {
   1377  template <class FromT>
   1378  static inline constexpr Span<To> From(const Span<FromT>& from) {
   1379    static_assert(sizeof(FromT) == sizeof(To));
   1380    return {reinterpret_cast<To*>(from.data()), from.size()};
   1381  }
   1382 };
   1383 
   1384 // -
   1385 
   1386 inline std::string Join(Span<const std::string> ss,
   1387                        const std::string_view& delim) {
   1388  if (!ss.size()) return "";
   1389  auto ret = std::string();
   1390  {
   1391    auto chars = delim.size() * (ss.size() - 1);
   1392    for (const auto& s : ss) {
   1393      chars += s.size();
   1394    }
   1395    ret.reserve(chars);
   1396  }
   1397 
   1398  ret = ss[0];
   1399  ss = ss.subspan(1);
   1400  for (const auto& s : ss) {
   1401    ret += delim;
   1402    ret += s;
   1403  }
   1404  return ret;
   1405 }
   1406 
   1407 inline std::string ToStringWithCommas(uint64_t v) {
   1408  if (!v) return "0";
   1409  std::vector<std::string> chunks;
   1410  while (v) {
   1411    const auto chunk = v % 1000;
   1412    v /= 1000;
   1413    chunks.insert(chunks.begin(), std::to_string(chunk));
   1414  }
   1415  return Join(chunks, ",");
   1416 }
   1417 
   1418 // -
   1419 // C++17 polyfill implementation from:
   1420 // https://en.cppreference.com/w/cpp/container/array/to_array
   1421 
   1422 namespace detail {
   1423 template <class T, size_t N, size_t... I>
   1424 constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(
   1425    T (&a)[N], std::index_sequence<I...>) {
   1426  return {{a[I]...}};
   1427 }
   1428 
   1429 template <class T, size_t N, size_t... I>
   1430 constexpr std::array<std::remove_cv_t<T>, N> to_array_impl(
   1431    T (&&a)[N], std::index_sequence<I...>) {
   1432  return {{std::move(a[I])...}};
   1433 }
   1434 }  // namespace detail
   1435 
   1436 template <class T, size_t N>
   1437 constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) {
   1438  return detail::to_array_impl(a, std::make_index_sequence<N>{});
   1439 }
   1440 
   1441 template <class T, size_t N>
   1442 constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&&a)[N]) {
   1443  return detail::to_array_impl(std::move(a), std::make_index_sequence<N>{});
   1444 }
   1445 
   1446 // -
   1447 
   1448 namespace webgl {
   1449 
   1450 std::unordered_map<GLenum, bool> MakeIsEnabledMap(bool webgl2);
   1451 
   1452 static constexpr uint32_t kMaxClientWaitSyncTimeoutNS =
   1453    1000 * 1000 * 1000;  // 1000ms in ns.
   1454 
   1455 }  // namespace webgl
   1456 }  // namespace mozilla
   1457 
   1458 #endif