forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			1307 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1307 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #ifndef WEBGLTYPES_H_
 | |
| #define WEBGLTYPES_H_
 | |
| 
 | |
| #include <limits>
 | |
| #include <string>
 | |
| #include <string_view>
 | |
| #include <tuple>
 | |
| #include <type_traits>
 | |
| #include <unordered_map>
 | |
| #include <vector>
 | |
| 
 | |
| #include "GLContextTypes.h"
 | |
| #include "GLDefs.h"
 | |
| #include "ImageContainer.h"
 | |
| #include "mozilla/Casting.h"
 | |
| #include "mozilla/CheckedInt.h"
 | |
| #include "mozilla/EnumTypeTraits.h"
 | |
| #include "mozilla/MathAlgorithms.h"
 | |
| #include "mozilla/Range.h"
 | |
| #include "mozilla/RefCounted.h"
 | |
| #include "mozilla/Result.h"
 | |
| #include "mozilla/ResultVariant.h"
 | |
| #include "mozilla/Span.h"
 | |
| #include "mozilla/TypedEnumBits.h"
 | |
| #include "mozilla/gfx/2D.h"
 | |
| #include "mozilla/gfx/BuildConstants.h"
 | |
| #include "mozilla/gfx/Logging.h"
 | |
| #include "mozilla/gfx/Point.h"
 | |
| #include "mozilla/gfx/Rect.h"
 | |
| #include "mozilla/ipc/Shmem.h"
 | |
| #include "mozilla/layers/LayersSurfaces.h"
 | |
| #include "gfxTypes.h"
 | |
| 
 | |
| #include "nsTArray.h"
 | |
| #include "nsString.h"
 | |
| #include "mozilla/dom/WebGLRenderingContextBinding.h"
 | |
| #include "mozilla/ipc/SharedMemoryBasic.h"
 | |
| #include "TiedFields.h"
 | |
| 
 | |
| // Manual reflection of WebIDL typedefs that are different from their
 | |
| // OpenGL counterparts.
 | |
| using WebGLsizeiptr = int64_t;
 | |
| using WebGLintptr = int64_t;
 | |
| using WebGLboolean = bool;
 | |
| 
 | |
| // -
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace gl {
 | |
| class GLContext;  // This is going to be needed a lot.
 | |
| }  // namespace gl
 | |
| 
 | |
| // -
 | |
| // Prevent implicit conversions into calloc and malloc. (mozilla namespace
 | |
| // only!)
 | |
| 
 | |
| template <typename DestT>
 | |
| class ForbidNarrowing final {
 | |
|   DestT mVal;
 | |
| 
 | |
|  public:
 | |
|   template <typename SrcT>
 | |
|   MOZ_IMPLICIT ForbidNarrowing(SrcT val) : mVal(val) {
 | |
|     static_assert(
 | |
|         std::numeric_limits<SrcT>::min() >= std::numeric_limits<DestT>::min(),
 | |
|         "SrcT must be narrower than DestT.");
 | |
|     static_assert(
 | |
|         std::numeric_limits<SrcT>::max() <= std::numeric_limits<DestT>::max(),
 | |
|         "SrcT must be narrower than DestT.");
 | |
|   }
 | |
| 
 | |
|   explicit operator DestT() const { return mVal; }
 | |
| };
 | |
| 
 | |
| inline void* malloc(const ForbidNarrowing<size_t> s) {
 | |
|   return ::malloc(size_t(s));
 | |
| }
 | |
| 
 | |
| inline void* calloc(const ForbidNarrowing<size_t> n,
 | |
|                     const ForbidNarrowing<size_t> size) {
 | |
|   return ::calloc(size_t(n), size_t(size));
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| // TODO: Remove this now-mere-alias.
 | |
| template <typename From>
 | |
| inline auto AutoAssertCast(const From val) {
 | |
|   return LazyAssertedCast(val);
 | |
| }
 | |
| 
 | |
| const char* GetEnumName(GLenum val, const char* defaultRet = "<unknown>");
 | |
| std::string EnumString(GLenum val);
 | |
| 
 | |
| namespace webgl {
 | |
| template <typename T>
 | |
| struct QueueParamTraits;
 | |
| class TexUnpackBytes;
 | |
| class TexUnpackImage;
 | |
| class TexUnpackSurface;
 | |
| }  // namespace webgl
 | |
| 
 | |
| class ClientWebGLContext;
 | |
| struct WebGLTexPboOffset;
 | |
| class WebGLTexture;
 | |
| class WebGLBuffer;
 | |
| class WebGLFramebuffer;
 | |
| class WebGLProgram;
 | |
| class WebGLQuery;
 | |
| class WebGLRenderbuffer;
 | |
| class WebGLSampler;
 | |
| class WebGLShader;
 | |
| class WebGLSync;
 | |
| class WebGLTexture;
 | |
| class WebGLTransformFeedback;
 | |
| class WebGLVertexArray;
 | |
| 
 | |
| // -
 | |
| 
 | |
| class VRefCounted : public RefCounted<VRefCounted> {
 | |
|  public:
 | |
|   virtual ~VRefCounted() = default;
 | |
| 
 | |
| #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
 | |
|   virtual const char* typeName() const = 0;
 | |
|   virtual size_t typeSize() const = 0;
 | |
| #endif
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| /*
 | |
|  * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
 | |
|  * emulating the vertex attrib 0 array when it's not enabled. Indeed,
 | |
|  * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
 | |
|  * desktop OpenGL does not allow that.
 | |
|  */
 | |
| enum class WebGLVertexAttrib0Status : uint8_t {
 | |
|   Default,                     // default status - no emulation needed
 | |
|   EmulatedUninitializedArray,  // need an artificial attrib 0 array, but
 | |
|                                // contents may be left uninitialized
 | |
|   EmulatedInitializedArray  // need an artificial attrib 0 array, and contents
 | |
|                             // must be initialized
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * The formats that may participate, either as source or destination formats,
 | |
|  * in WebGL texture conversions. This includes:
 | |
|  *  - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
 | |
|  *  - additional formats provided by extensions, e.g. RGB32F
 | |
|  *  - additional source formats, depending on browser details, used when
 | |
|  * uploading textures from DOM elements. See gfxImageSurface::Format().
 | |
|  */
 | |
| enum class WebGLTexelFormat : uint8_t {
 | |
|   // returned by SurfaceFromElementResultToImageSurface to indicate absence of
 | |
|   // image data
 | |
|   None,
 | |
|   // common value for formats for which format conversions are not supported
 | |
|   FormatNotSupportingAnyConversion,
 | |
|   // dummy pseudo-format meaning "use the other format".
 | |
|   // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
 | |
|   // is implicitly treated as being RGB8 itself.
 | |
|   Auto,
 | |
|   // 1-channel formats
 | |
|   A8,
 | |
|   A16F,  // OES_texture_half_float
 | |
|   A32F,  // OES_texture_float
 | |
|   R8,
 | |
|   R16F,  // OES_texture_half_float
 | |
|   R32F,  // OES_texture_float
 | |
|   // 2-channel formats
 | |
|   RA8,
 | |
|   RA16F,  // OES_texture_half_float
 | |
|   RA32F,  // OES_texture_float
 | |
|   RG8,
 | |
|   RG16F,
 | |
|   RG32F,
 | |
|   // 3-channel formats
 | |
|   RGB8,
 | |
|   RGB565,
 | |
|   RGB11F11F10F,
 | |
|   RGB16F,  // OES_texture_half_float
 | |
|   RGB32F,  // OES_texture_float
 | |
|   // 4-channel formats
 | |
|   RGBA8,
 | |
|   RGBA5551,
 | |
|   RGBA4444,
 | |
|   RGBA16F,  // OES_texture_half_float
 | |
|   RGBA32F,  // OES_texture_float
 | |
|   // DOM element source only formats.
 | |
|   RGBX8,
 | |
|   BGRX8,
 | |
|   BGRA8
 | |
| };
 | |
| 
 | |
| enum class WebGLTexImageFunc : uint8_t {
 | |
|   TexImage,
 | |
|   TexSubImage,
 | |
|   CopyTexImage,
 | |
|   CopyTexSubImage,
 | |
|   CompTexImage,
 | |
|   CompTexSubImage,
 | |
| };
 | |
| 
 | |
| enum class WebGLTexDimensions : uint8_t { Tex2D, Tex3D };
 | |
| 
 | |
| // Please keep extensions in alphabetic order.
 | |
| enum class WebGLExtensionID : uint8_t {
 | |
|   ANGLE_instanced_arrays,
 | |
|   EXT_blend_minmax,
 | |
|   EXT_color_buffer_float,
 | |
|   EXT_color_buffer_half_float,
 | |
|   EXT_disjoint_timer_query,
 | |
|   EXT_float_blend,
 | |
|   EXT_frag_depth,
 | |
|   EXT_shader_texture_lod,
 | |
|   EXT_sRGB,
 | |
|   EXT_texture_compression_bptc,
 | |
|   EXT_texture_compression_rgtc,
 | |
|   EXT_texture_filter_anisotropic,
 | |
|   EXT_texture_norm16,
 | |
|   MOZ_debug,
 | |
|   OES_draw_buffers_indexed,
 | |
|   OES_element_index_uint,
 | |
|   OES_fbo_render_mipmap,
 | |
|   OES_standard_derivatives,
 | |
|   OES_texture_float,
 | |
|   OES_texture_float_linear,
 | |
|   OES_texture_half_float,
 | |
|   OES_texture_half_float_linear,
 | |
|   OES_vertex_array_object,
 | |
|   OVR_multiview2,
 | |
|   WEBGL_color_buffer_float,
 | |
|   WEBGL_compressed_texture_astc,
 | |
|   WEBGL_compressed_texture_etc,
 | |
|   WEBGL_compressed_texture_etc1,
 | |
|   WEBGL_compressed_texture_pvrtc,
 | |
|   WEBGL_compressed_texture_s3tc,
 | |
|   WEBGL_compressed_texture_s3tc_srgb,
 | |
|   WEBGL_debug_renderer_info,
 | |
|   WEBGL_debug_shaders,
 | |
|   WEBGL_depth_texture,
 | |
|   WEBGL_draw_buffers,
 | |
|   WEBGL_explicit_present,
 | |
|   WEBGL_lose_context,
 | |
|   WEBGL_provoking_vertex,
 | |
|   Max
 | |
| };
 | |
| 
 | |
| class UniqueBuffer final {
 | |
|   // Like UniquePtr<>, but for void* and malloc/calloc/free.
 | |
|   void* mBuffer = nullptr;
 | |
| 
 | |
|  public:
 | |
|   static inline UniqueBuffer Take(void* buffer) {
 | |
|     UniqueBuffer ret;
 | |
|     ret.mBuffer = buffer;
 | |
|     return ret;
 | |
|   }
 | |
| 
 | |
|   UniqueBuffer() = default;
 | |
| 
 | |
|   ~UniqueBuffer() { reset(); }
 | |
| 
 | |
|   UniqueBuffer(UniqueBuffer&& rhs) { *this = std::move(rhs); }
 | |
| 
 | |
|   UniqueBuffer& operator=(UniqueBuffer&& rhs) {
 | |
|     reset();
 | |
|     this->mBuffer = rhs.mBuffer;
 | |
|     rhs.mBuffer = nullptr;
 | |
|     return *this;
 | |
|   }
 | |
| 
 | |
|   explicit operator bool() const { return bool(mBuffer); }
 | |
| 
 | |
|   void* get() const { return mBuffer; }
 | |
| 
 | |
|   void reset() {
 | |
|     // Believe it or not, when `free` unconditional, it was showing up
 | |
|     // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
 | |
|     // on Aquarium.
 | |
|     if (mBuffer) {
 | |
|       free(mBuffer);
 | |
|       mBuffer = nullptr;
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| namespace webgl {
 | |
| struct FormatUsageInfo;
 | |
| 
 | |
| static constexpr GLenum kErrorPerfWarning = 0x10001;
 | |
| 
 | |
| struct SampleableInfo final {
 | |
|   const char* incompleteReason = nullptr;
 | |
|   uint32_t levels = 0;
 | |
|   const webgl::FormatUsageInfo* usage = nullptr;
 | |
|   bool isDepthTexCompare = false;
 | |
| 
 | |
|   bool IsComplete() const { return bool(levels); }
 | |
| };
 | |
| 
 | |
| enum class AttribBaseType : uint8_t {
 | |
|   Boolean,  // Can convert from anything.
 | |
|   Float,    // Also includes NormU?Int
 | |
|   Int,
 | |
|   Uint,
 | |
| };
 | |
| webgl::AttribBaseType ToAttribBaseType(GLenum);
 | |
| const char* ToString(AttribBaseType);
 | |
| 
 | |
| enum class UniformBaseType : uint8_t {
 | |
|   Float,
 | |
|   Int,
 | |
|   Uint,
 | |
| };
 | |
| const char* ToString(UniformBaseType);
 | |
| 
 | |
| using ObjectId = uint64_t;
 | |
| 
 | |
| enum class BufferKind : uint8_t {
 | |
|   Undefined,
 | |
|   Index,
 | |
|   NonIndex,
 | |
| };
 | |
| 
 | |
| }  // namespace webgl
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct FloatOrInt final  // For TexParameter[fi] and friends.
 | |
| {
 | |
|   bool isFloat = false;
 | |
|   uint8_t padding[3] = {};
 | |
|   GLfloat f = 0;
 | |
|   GLint i = 0;
 | |
| 
 | |
|   explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
 | |
| 
 | |
|   explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(isFloat, padding, f, i); }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct WebGLContextOptions final {
 | |
|   bool alpha = true;
 | |
|   bool depth = true;
 | |
|   bool stencil = false;
 | |
|   bool premultipliedAlpha = true;
 | |
| 
 | |
|   bool antialias = true;
 | |
|   bool preserveDrawingBuffer = false;
 | |
|   bool failIfMajorPerformanceCaveat = false;
 | |
|   bool xrCompatible = false;
 | |
| 
 | |
|   dom::WebGLPowerPreference powerPreference =
 | |
|       dom::WebGLPowerPreference::Default;
 | |
|   bool ignoreColorSpace = true;
 | |
|   dom::PredefinedColorSpace colorSpace = dom::PredefinedColorSpace::Srgb;
 | |
|   bool shouldResistFingerprinting = true;
 | |
| 
 | |
|   bool enableDebugRendererInfo = false;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     // clang-format off
 | |
|     return std::tie(
 | |
|       alpha,
 | |
|       depth,
 | |
|       stencil,
 | |
|       premultipliedAlpha,
 | |
| 
 | |
|       antialias,
 | |
|       preserveDrawingBuffer,
 | |
|       failIfMajorPerformanceCaveat,
 | |
|       xrCompatible,
 | |
| 
 | |
|       powerPreference,
 | |
|       colorSpace,
 | |
|       ignoreColorSpace,
 | |
|       shouldResistFingerprinting,
 | |
| 
 | |
|       enableDebugRendererInfo);
 | |
|     // clang-format on
 | |
|   }
 | |
| 
 | |
|   // -
 | |
| 
 | |
|   WebGLContextOptions();
 | |
|   WebGLContextOptions(const WebGLContextOptions&) = default;
 | |
| 
 | |
|   using Self = WebGLContextOptions;
 | |
|   friend bool operator==(const Self& a, const Self& b) {
 | |
|     return TiedFields(a) == TiedFields(b);
 | |
|   }
 | |
|   friend bool operator!=(const Self& a, const Self& b) { return !(a == b); }
 | |
| };
 | |
| 
 | |
| namespace gfx {
 | |
| 
 | |
| inline ColorSpace2 ToColorSpace2(const dom::PredefinedColorSpace cs) {
 | |
|   switch (cs) {
 | |
|     case dom::PredefinedColorSpace::Srgb:
 | |
|       return ColorSpace2::SRGB;
 | |
|     case dom::PredefinedColorSpace::Display_p3:
 | |
|       return ColorSpace2::DISPLAY_P3;
 | |
|   }
 | |
|   MOZ_CRASH("Exhaustive switch");
 | |
| }
 | |
| 
 | |
| }  // namespace gfx
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <typename _T>
 | |
| struct avec2 {
 | |
|   using T = _T;
 | |
| 
 | |
|   T x = T();
 | |
|   T y = T();
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(x, y); }
 | |
| 
 | |
|   template <typename U, typename V>
 | |
|   static Maybe<avec2> From(const U _x, const V _y) {
 | |
|     const auto x = CheckedInt<T>(_x);
 | |
|     const auto y = CheckedInt<T>(_y);
 | |
|     if (!x.isValid() || !y.isValid()) return {};
 | |
|     return Some(avec2(x.value(), y.value()));
 | |
|   }
 | |
| 
 | |
|   template <typename U>
 | |
|   static auto From(const U& val) {
 | |
|     return From(val.x, val.y);
 | |
|   }
 | |
|   template <typename U>
 | |
|   static auto FromSize(const U& val) {
 | |
|     return From(val.width, val.height);
 | |
|   }
 | |
| 
 | |
|   avec2() = default;
 | |
|   avec2(const T _x, const T _y) : x(_x), y(_y) {}
 | |
| 
 | |
|   bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
 | |
|   bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
 | |
| 
 | |
| #define _(OP)                                 \
 | |
|   avec2 operator OP(const avec2& rhs) const { \
 | |
|     return {x OP rhs.x, y OP rhs.y};          \
 | |
|   }                                           \
 | |
|   avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
 | |
| 
 | |
|   _(+)
 | |
|   _(-)
 | |
|   _(*)
 | |
|   _(/)
 | |
| 
 | |
| #undef _
 | |
| 
 | |
|   avec2 Clamp(const avec2& min, const avec2& max) const {
 | |
|     return {mozilla::Clamp(x, min.x, max.x), mozilla::Clamp(y, min.y, max.y)};
 | |
|   }
 | |
| 
 | |
|   // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
 | |
|   // helper.
 | |
|   avec2 ClampMinMax(const avec2& min, const avec2& max) const {
 | |
|     const auto ClampScalar = [](const T v, const T min, const T max) {
 | |
|       return std::max(min, std::min(v, max));
 | |
|     };
 | |
|     return {ClampScalar(x, min.x, max.x), ClampScalar(y, min.y, max.y)};
 | |
|   }
 | |
| 
 | |
|   template <typename U>
 | |
|   U StaticCast() const {
 | |
|     return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <typename T>
 | |
| avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
 | |
|   return {std::min(a.x, b.x), std::min(a.y, b.y)};
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
 | |
|   return {std::max(a.x, b.x), std::max(a.y, b.y)};
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <typename _T>
 | |
| struct avec3 {
 | |
|   using T = _T;
 | |
| 
 | |
|   T x = T();
 | |
|   T y = T();
 | |
|   T z = T();
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(x, y, z); }
 | |
| 
 | |
|   template <typename U, typename V>
 | |
|   static Maybe<avec3> From(const U _x, const V _y, const V _z) {
 | |
|     const auto x = CheckedInt<T>(_x);
 | |
|     const auto y = CheckedInt<T>(_y);
 | |
|     const auto z = CheckedInt<T>(_z);
 | |
|     if (!x.isValid() || !y.isValid() || !z.isValid()) return {};
 | |
|     return Some(avec3(x.value(), y.value(), z.value()));
 | |
|   }
 | |
| 
 | |
|   template <typename U>
 | |
|   static auto From(const U& val) {
 | |
|     return From(val.x, val.y, val.z);
 | |
|   }
 | |
| 
 | |
|   avec3() = default;
 | |
|   avec3(const T _x, const T _y, const T _z) : x(_x), y(_y), z(_z) {}
 | |
| 
 | |
|   bool operator==(const avec3& rhs) const {
 | |
|     return x == rhs.x && y == rhs.y && z == rhs.z;
 | |
|   }
 | |
|   bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
 | |
| };
 | |
| 
 | |
| using ivec2 = avec2<int32_t>;
 | |
| using ivec3 = avec3<int32_t>;
 | |
| using uvec2 = avec2<uint32_t>;
 | |
| using uvec3 = avec3<uint32_t>;
 | |
| 
 | |
| inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
 | |
| 
 | |
| // -
 | |
| 
 | |
| namespace webgl {
 | |
| 
 | |
| struct PackingInfo final {
 | |
|   GLenum format = 0;
 | |
|   GLenum type = 0;
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(format, type); }
 | |
| 
 | |
|   using Self = PackingInfo;
 | |
|   friend bool operator<(const Self& a, const Self& b) {
 | |
|     return TiedFields(a) < TiedFields(b);
 | |
|   }
 | |
|   friend bool operator==(const Self& a, const Self& b) {
 | |
|     return TiedFields(a) == TiedFields(b);
 | |
|   }
 | |
| 
 | |
|   template <class T>
 | |
|   friend T& operator<<(T& s, const PackingInfo& pi) {
 | |
|     s << "PackingInfo{format: " << EnumString(pi.format)
 | |
|       << ", type: " << EnumString(pi.type) << "}";
 | |
|     return s;
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct DriverUnpackInfo final {
 | |
|   GLenum internalFormat = 0;
 | |
|   GLenum unpackFormat = 0;
 | |
|   GLenum unpackType = 0;
 | |
| 
 | |
|   PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <typename E>
 | |
| class EnumMask {
 | |
|  public:
 | |
|   uint64_t mBits = 0;
 | |
| 
 | |
|  private:
 | |
|   struct BitRef final {
 | |
|     EnumMask& bits;
 | |
|     const uint64_t mask;
 | |
| 
 | |
|     explicit operator bool() const { return bits.mBits & mask; }
 | |
| 
 | |
|     auto& operator=(const bool val) {
 | |
|       if (val) {
 | |
|         bits.mBits |= mask;
 | |
|       } else {
 | |
|         bits.mBits &= ~mask;
 | |
|       }
 | |
|       return *this;
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   uint64_t Mask(const E i) const {
 | |
|     return uint64_t{1} << static_cast<uint64_t>(i);
 | |
|   }
 | |
| 
 | |
|  public:
 | |
|   BitRef operator[](const E i) { return {*this, Mask(i)}; }
 | |
|   bool operator[](const E i) const { return mBits & Mask(i); }
 | |
| 
 | |
|   // -
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(mBits); }
 | |
| };
 | |
| 
 | |
| using ExtensionBits = EnumMask<WebGLExtensionID>;
 | |
| 
 | |
| // -
 | |
| 
 | |
| enum class ContextLossReason : uint8_t {
 | |
|   None,
 | |
|   Manual,
 | |
|   Guilty,
 | |
| };
 | |
| 
 | |
| inline bool ReadContextLossReason(const uint8_t val,
 | |
|                                   ContextLossReason* const out) {
 | |
|   if (val > static_cast<uint8_t>(ContextLossReason::Guilty)) {
 | |
|     return false;
 | |
|   }
 | |
|   *out = static_cast<ContextLossReason>(val);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct InitContextDesc final {
 | |
|   bool isWebgl2 = false;
 | |
|   bool resistFingerprinting = false;
 | |
|   std::array<uint8_t, 2> _padding;
 | |
|   uint32_t principalKey = 0;
 | |
|   uvec2 size = {};
 | |
|   WebGLContextOptions options;
 | |
|   std::array<uint8_t, 3> _padding2;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(isWebgl2, resistFingerprinting, _padding, principalKey,
 | |
|                     size, options, _padding2);
 | |
|   }
 | |
| };
 | |
| 
 | |
| constexpr uint32_t kMaxTransformFeedbackSeparateAttribs = 4;
 | |
| 
 | |
| struct Limits final {
 | |
|   ExtensionBits supportedExtensions;
 | |
| 
 | |
|   // WebGL 1
 | |
|   uint32_t maxTexUnits = 0;
 | |
|   uint32_t maxTex2dSize = 0;
 | |
|   uint32_t maxTexCubeSize = 0;
 | |
|   uint32_t maxVertexAttribs = 0;
 | |
|   uint32_t maxViewportDim = 0;
 | |
|   std::array<float, 2> pointSizeRange = {{1, 1}};
 | |
|   std::array<float, 2> lineWidthRange = {{1, 1}};
 | |
| 
 | |
|   // WebGL 2
 | |
|   uint32_t maxTexArrayLayers = 0;
 | |
|   uint32_t maxTex3dSize = 0;
 | |
|   uint32_t maxUniformBufferBindings = 0;
 | |
|   uint32_t uniformBufferOffsetAlignment = 0;
 | |
| 
 | |
|   // Exts
 | |
|   bool astcHdr = false;
 | |
|   std::array<uint8_t, 3> _padding;
 | |
|   uint32_t maxColorDrawBuffers = 1;
 | |
|   uint32_t maxMultiviewLayers = 0;
 | |
|   uint64_t queryCounterBitsTimeElapsed = 0;
 | |
|   uint64_t queryCounterBitsTimestamp = 0;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(supportedExtensions,
 | |
| 
 | |
|                     maxTexUnits, maxTex2dSize, maxTexCubeSize, maxVertexAttribs,
 | |
|                     maxViewportDim, pointSizeRange, lineWidthRange,
 | |
| 
 | |
|                     maxTexArrayLayers, maxTex3dSize, maxUniformBufferBindings,
 | |
|                     uniformBufferOffsetAlignment,
 | |
| 
 | |
|                     astcHdr, _padding, maxColorDrawBuffers, maxMultiviewLayers,
 | |
|                     queryCounterBitsTimeElapsed, queryCounterBitsTimestamp);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <class T, size_t PaddedSize>
 | |
| struct Padded {
 | |
|  private:
 | |
|   T val = {};
 | |
|   uint8_t padding[PaddedSize - sizeof(T)] = {};
 | |
| 
 | |
|  public:
 | |
|   operator T&() { return val; }
 | |
|   operator const T&() const { return val; }
 | |
| 
 | |
|   auto& operator=(const T& rhs) { return val = rhs; }
 | |
|   auto& operator=(T&& rhs) { return val = std::move(rhs); }
 | |
| 
 | |
|   auto& operator*() { return val; }
 | |
|   auto& operator*() const { return val; }
 | |
|   auto operator->() { return &val; }
 | |
|   auto operator->() const { return &val; }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| enum class OptionalRenderableFormatBits : uint8_t {
 | |
|   RGB8 = (1 << 0),
 | |
|   SRGB8 = (1 << 1),
 | |
| };
 | |
| MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OptionalRenderableFormatBits)
 | |
| inline constexpr bool IsEnumCase(const OptionalRenderableFormatBits raw) {
 | |
|   auto rawWithoutValidBits = UnderlyingValue(raw);
 | |
|   auto bit = decltype(rawWithoutValidBits){1};
 | |
|   while (bit) {
 | |
|     switch (OptionalRenderableFormatBits{bit}) {
 | |
|       // -Werror=switch ensures exhaustive.
 | |
|       case OptionalRenderableFormatBits::RGB8:
 | |
|       case OptionalRenderableFormatBits::SRGB8:
 | |
|         rawWithoutValidBits &= ~bit;
 | |
|         break;
 | |
|     }
 | |
|     bit <<= 1;
 | |
|   }
 | |
|   return rawWithoutValidBits == 0;
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct InitContextResult final {
 | |
|   Padded<std::string, 32> error;  // MINGW 32-bit needs this padding.
 | |
|   WebGLContextOptions options;
 | |
|   gl::GLVendor vendor;
 | |
|   OptionalRenderableFormatBits optionalRenderableFormatBits;
 | |
|   uint8_t _padding = {};
 | |
|   Limits limits;
 | |
|   EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(error, options, vendor, optionalRenderableFormatBits,
 | |
|                     _padding, limits, uploadableSdTypes);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct ErrorInfo final {
 | |
|   GLenum type;
 | |
|   std::string info;
 | |
| };
 | |
| 
 | |
| struct ShaderPrecisionFormat final {
 | |
|   GLint rangeMin = 0;
 | |
|   GLint rangeMax = 0;
 | |
|   GLint precision = 0;
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| enum class LossStatus {
 | |
|   Ready,
 | |
| 
 | |
|   Lost,
 | |
|   LostForever,
 | |
|   LostManually,
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct CompileResult final {
 | |
|   bool pending = true;
 | |
|   nsCString log;
 | |
|   nsCString translatedSource;
 | |
|   bool success = false;
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct OpaqueFramebufferOptions final {
 | |
|   bool depthStencil = true;
 | |
|   bool antialias = true;
 | |
|   std::array<uint8_t, 2> _padding;
 | |
|   uint32_t width = 0;
 | |
|   uint32_t height = 0;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(depthStencil, antialias, _padding, width, height);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct SwapChainOptions final {
 | |
|   layers::RemoteTextureId remoteTextureId;
 | |
|   layers::RemoteTextureOwnerId remoteTextureOwnerId;
 | |
|   bool bgra = false;
 | |
|   bool forceAsyncPresent = false;
 | |
|   // Pad to sizeof(u64):
 | |
|   uint16_t padding1 = 0;
 | |
|   uint32_t padding2 = 0;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(remoteTextureId, remoteTextureOwnerId, bgra,
 | |
|                     forceAsyncPresent, padding1, padding2);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct ActiveInfo {
 | |
|   GLenum elemType = 0;     // `type`
 | |
|   uint32_t elemCount = 0;  // `size`
 | |
|   std::string name;
 | |
| };
 | |
| 
 | |
| struct ActiveAttribInfo final : public ActiveInfo {
 | |
|   int32_t location = -1;
 | |
|   AttribBaseType baseType = AttribBaseType::Float;
 | |
| };
 | |
| 
 | |
| struct ActiveUniformInfo final : public ActiveInfo {
 | |
|   std::unordered_map<uint32_t, uint32_t>
 | |
|       locByIndex;  // Uniform array locations are sparse.
 | |
|   int32_t block_index = -1;
 | |
|   int32_t block_offset = -1;  // In block, offset.
 | |
|   int32_t block_arrayStride = -1;
 | |
|   int32_t block_matrixStride = -1;
 | |
|   bool block_isRowMajor = false;
 | |
| };
 | |
| 
 | |
| struct ActiveUniformBlockInfo final {
 | |
|   std::string name;
 | |
|   // BLOCK_BINDING is dynamic state
 | |
|   uint32_t dataSize = 0;
 | |
|   std::vector<uint32_t> activeUniformIndices;
 | |
|   bool referencedByVertexShader = false;
 | |
|   bool referencedByFragmentShader = false;
 | |
| };
 | |
| 
 | |
| struct LinkActiveInfo final {
 | |
|   std::vector<ActiveAttribInfo> activeAttribs;
 | |
|   std::vector<ActiveUniformInfo> activeUniforms;
 | |
|   std::vector<ActiveUniformBlockInfo> activeUniformBlocks;
 | |
|   std::vector<ActiveInfo> activeTfVaryings;
 | |
| };
 | |
| 
 | |
| struct LinkResult final {
 | |
|   bool pending = true;
 | |
|   nsCString log;
 | |
|   bool success = false;
 | |
|   LinkActiveInfo active;
 | |
|   GLenum tfBufferMode = 0;
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| /// 4x32-bit primitives, with a type tag.
 | |
| struct TypedQuad final {
 | |
|   alignas(alignof(float)) std::array<uint8_t, 4 * sizeof(float)> data = {};
 | |
|   webgl::AttribBaseType type = webgl::AttribBaseType::Float;
 | |
|   uint8_t padding[3] = {};
 | |
| 
 | |
|   constexpr auto MutTiedFields() { return std::tie(data, type, padding); }
 | |
| };
 | |
| 
 | |
| /// [1-16]x32-bit primitives, with a type tag.
 | |
| struct GetUniformData final {
 | |
|   alignas(alignof(float)) uint8_t data[4 * 4 * sizeof(float)] = {};
 | |
|   GLenum type = 0;
 | |
| };
 | |
| 
 | |
| struct FrontBufferSnapshotIpc final {
 | |
|   uvec2 surfSize = {};
 | |
|   Maybe<mozilla::ipc::Shmem> shmem = {};
 | |
| };
 | |
| 
 | |
| struct ReadPixelsResult {
 | |
|   gfx::IntRect subrect = {};
 | |
|   size_t byteStride = 0;
 | |
| };
 | |
| 
 | |
| struct ReadPixelsResultIpc final : public ReadPixelsResult {
 | |
|   Maybe<mozilla::ipc::Shmem> shmem = {};
 | |
| };
 | |
| 
 | |
| struct VertAttribPointerDesc final {
 | |
|   bool intFunc = false;
 | |
|   uint8_t channels = 4;
 | |
|   bool normalized = false;
 | |
|   uint8_t byteStrideOrZero = 0;
 | |
|   GLenum type = LOCAL_GL_FLOAT;
 | |
|   uint64_t byteOffset = 0;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(intFunc, channels, normalized, byteStrideOrZero, type,
 | |
|                     byteOffset);
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct VertAttribPointerCalculated final {
 | |
|   uint8_t byteSize = 4 * 4;
 | |
|   uint8_t byteStride = 4 * 4;  // at-most 255
 | |
|   webgl::AttribBaseType baseType = webgl::AttribBaseType::Float;
 | |
| };
 | |
| 
 | |
| }  // namespace webgl
 | |
| 
 | |
| template <class T>
 | |
| inline Range<T> ShmemRange(const mozilla::ipc::Shmem& shmem) {
 | |
|   return {shmem.get<T>(), shmem.Size<T>()};
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <typename C, typename K>
 | |
| inline auto MaybeFind(C& container, const K& key)
 | |
|     -> decltype(&(container.find(key)->second)) {
 | |
|   const auto itr = container.find(key);
 | |
|   if (itr == container.end()) return nullptr;
 | |
|   return &(itr->second);
 | |
| }
 | |
| 
 | |
| template <typename C, typename K>
 | |
| inline typename C::mapped_type Find(
 | |
|     const C& container, const K& key,
 | |
|     const typename C::mapped_type notFound = {}) {
 | |
|   const auto itr = container.find(key);
 | |
|   if (itr == container.end()) return notFound;
 | |
|   return itr->second;
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <typename T, typename U>
 | |
| inline Maybe<T> MaybeAs(const U val) {
 | |
|   const auto checked = CheckedInt<T>(val);
 | |
|   if (!checked.isValid()) return {};
 | |
|   return Some(checked.value());
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| inline GLenum IsTexImageTarget(const GLenum imageTarget) {
 | |
|   switch (imageTarget) {
 | |
|     case LOCAL_GL_TEXTURE_2D:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
 | |
|     case LOCAL_GL_TEXTURE_3D:
 | |
|     case LOCAL_GL_TEXTURE_2D_ARRAY:
 | |
|       return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| inline GLenum ImageToTexTarget(const GLenum imageTarget) {
 | |
|   switch (imageTarget) {
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
 | |
|     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
 | |
|       return LOCAL_GL_TEXTURE_CUBE_MAP;
 | |
|   }
 | |
|   if (IsTexImageTarget(imageTarget)) {
 | |
|     return imageTarget;
 | |
|   }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| inline bool IsTexTarget3D(const GLenum texTarget) {
 | |
|   switch (texTarget) {
 | |
|     case LOCAL_GL_TEXTURE_2D_ARRAY:
 | |
|     case LOCAL_GL_TEXTURE_3D:
 | |
|       return true;
 | |
| 
 | |
|     default:
 | |
|       return false;
 | |
|   }
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| namespace dom {
 | |
| class Element;
 | |
| class ImageBitmap;
 | |
| class ImageData;
 | |
| class OffscreenCanvas;
 | |
| class VideoFrame;
 | |
| }  // namespace dom
 | |
| 
 | |
| struct TexImageSource {
 | |
|   const dom::ArrayBufferView* mView = nullptr;
 | |
|   GLuint mViewElemOffset = 0;
 | |
|   GLuint mViewElemLengthOverride = 0;
 | |
| 
 | |
|   const WebGLintptr* mPboOffset = nullptr;
 | |
| 
 | |
|   const dom::ImageBitmap* mImageBitmap = nullptr;
 | |
|   const dom::ImageData* mImageData = nullptr;
 | |
| 
 | |
|   const dom::OffscreenCanvas* mOffscreenCanvas = nullptr;
 | |
| 
 | |
|   const dom::VideoFrame* mVideoFrame = nullptr;
 | |
| 
 | |
|   const dom::Element* mDomElem = nullptr;
 | |
|   ErrorResult* mOut_error = nullptr;
 | |
| };
 | |
| 
 | |
| namespace webgl {
 | |
| 
 | |
| template <class DerivedT>
 | |
| struct DeriveNotEq {
 | |
|   bool operator!=(const DerivedT& rhs) const {
 | |
|     const auto self = reinterpret_cast<const DerivedT*>(this);
 | |
|     return !(*self == rhs);
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct PixelPackingState : public DeriveNotEq<PixelPackingState> {
 | |
|   uint32_t alignmentInTypeElems = 4;  // ALIGNMENT isn't naive byte alignment!
 | |
|   uint32_t rowLength = 0;
 | |
|   uint32_t imageHeight = 0;
 | |
|   uint32_t skipPixels = 0;
 | |
|   uint32_t skipRows = 0;
 | |
|   uint32_t skipImages = 0;
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tie(alignmentInTypeElems, rowLength, imageHeight, skipPixels,
 | |
|                     skipRows, skipImages);
 | |
|   }
 | |
| 
 | |
|   using Self = PixelPackingState;
 | |
|   friend bool operator==(const Self& a, const Self& b) {
 | |
|     return TiedFields(a) == TiedFields(b);
 | |
|   }
 | |
| 
 | |
|   static void AssertDefaultUnpack(gl::GLContext& gl, const bool isWebgl2) {
 | |
|     PixelPackingState{}.AssertCurrentUnpack(gl, isWebgl2);
 | |
|   }
 | |
| 
 | |
|   void ApplyUnpack(gl::GLContext&, bool isWebgl2,
 | |
|                    const uvec3& uploadSize) const;
 | |
|   bool AssertCurrentUnpack(gl::GLContext&, bool isWebgl2) const;
 | |
| };
 | |
| 
 | |
| struct PixelUnpackStateWebgl final : public PixelPackingState {
 | |
|   GLenum colorspaceConversion =
 | |
|       dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
 | |
|   bool flipY = false;
 | |
|   bool premultiplyAlpha = false;
 | |
|   bool requireFastPath = false;
 | |
|   uint8_t padding = {};
 | |
| 
 | |
|   auto MutTiedFields() {
 | |
|     return std::tuple_cat(PixelPackingState::MutTiedFields(),
 | |
|                           std::tie(colorspaceConversion, flipY,
 | |
|                                    premultiplyAlpha, requireFastPath, padding));
 | |
|   }
 | |
| };
 | |
| 
 | |
| struct ExplicitPixelPackingState final {
 | |
|   struct Metrics final {
 | |
|     uvec3 usedSize = {};
 | |
|     size_t bytesPerPixel = 0;
 | |
| 
 | |
|     // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
 | |
|     // ...aligned to ALIGNMENT.
 | |
|     size_t bytesPerRowStride = 0;
 | |
| 
 | |
|     // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
 | |
|     size_t totalRows = 0;
 | |
| 
 | |
|     // This ensures that no one else needs to do CheckedInt math.
 | |
|     size_t totalBytesUsed = 0;
 | |
|     size_t totalBytesStrided = 0;
 | |
|   };
 | |
| 
 | |
|   // It's so important that these aren't modified once evaluated.
 | |
|   const PixelPackingState state;
 | |
|   const Metrics metrics;
 | |
| 
 | |
|   static Result<ExplicitPixelPackingState, std::string> ForUseWith(
 | |
|       const PixelPackingState&, GLenum target, const uvec3& subrectSize,
 | |
|       const webgl::PackingInfo&, const Maybe<size_t> bytesPerRowStrideOverride);
 | |
| };
 | |
| 
 | |
| struct ReadPixelsDesc final {
 | |
|   ivec2 srcOffset;
 | |
|   uvec2 size;
 | |
|   PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
 | |
|   PixelPackingState packState;
 | |
| 
 | |
|   auto MutTiedFields() { return std::tie(srcOffset, size, pi, packState); }
 | |
| };
 | |
| 
 | |
| }  // namespace webgl
 | |
| 
 | |
| namespace webgl {
 | |
| 
 | |
| struct TexUnpackBlobDesc final {
 | |
|   GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
 | |
|   uvec3 size;
 | |
|   gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
 | |
| 
 | |
|   Maybe<Span<const uint8_t>> cpuData;
 | |
|   Maybe<uint64_t> pboOffset;
 | |
| 
 | |
|   Maybe<uvec2> structuredSrcSize;
 | |
|   RefPtr<layers::Image> image;
 | |
|   Maybe<layers::SurfaceDescriptor> sd;
 | |
|   RefPtr<gfx::DataSourceSurface> dataSurf;
 | |
| 
 | |
|   webgl::PixelUnpackStateWebgl unpacking;
 | |
|   bool applyUnpackTransforms = true;
 | |
| 
 | |
|   // -
 | |
| 
 | |
|   auto ExplicitUnpacking(const webgl::PackingInfo& pi,
 | |
|                          const Maybe<size_t> bytesPerRowStrideOverride) const {
 | |
|     return ExplicitPixelPackingState::ForUseWith(this->unpacking,
 | |
|                                                  this->imageTarget, this->size,
 | |
|                                                  pi, bytesPerRowStrideOverride);
 | |
|   }
 | |
| 
 | |
|   void Shrink(const webgl::PackingInfo&);
 | |
| };
 | |
| 
 | |
| }  // namespace webgl
 | |
| 
 | |
| // ---------------------------------------
 | |
| // MakeRange
 | |
| 
 | |
| template <typename T, size_t N>
 | |
| inline Range<const T> MakeRange(T (&arr)[N]) {
 | |
|   return {arr, N};
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
 | |
|   return {seq.Elements(), seq.Length()};
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| constexpr auto kUniversalAlignment = alignof(std::max_align_t);
 | |
| 
 | |
| template <typename T>
 | |
| inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
 | |
|   MOZ_ASSERT(alignment);
 | |
|   const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
 | |
|   const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
 | |
|   const auto aligned = wholeMultiples * alignment;
 | |
|   return aligned - begin;
 | |
| }
 | |
| 
 | |
| template <typename T>
 | |
| inline size_t ByteSize(const Range<T>& range) {
 | |
|   return range.length() * sizeof(T);
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| Maybe<webgl::ErrorInfo> CheckBindBufferRange(
 | |
|     const GLenum target, const GLuint index, const bool isBuffer,
 | |
|     const uint64_t offset, const uint64_t size, const webgl::Limits& limits);
 | |
| 
 | |
| Maybe<webgl::ErrorInfo> CheckFramebufferAttach(const GLenum bindImageTarget,
 | |
|                                                const GLenum curTexTarget,
 | |
|                                                const uint32_t mipLevel,
 | |
|                                                const uint32_t zLayerBase,
 | |
|                                                const uint32_t zLayerCount,
 | |
|                                                const webgl::Limits& limits);
 | |
| 
 | |
| Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
 | |
| CheckVertexAttribPointer(bool isWebgl2, const webgl::VertAttribPointerDesc&);
 | |
| 
 | |
| uint8_t ElemTypeComponents(GLenum elemType);
 | |
| 
 | |
| inline std::string ToString(const nsACString& text) {
 | |
|   return {text.BeginReading(), text.Length()};
 | |
| }
 | |
| 
 | |
| inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
 | |
|                    const RangedPtr<const uint8_t>& srcBytes,
 | |
|                    const size_t byteSize) {
 | |
|   // Trigger range asserts
 | |
|   (void)(srcBytes + byteSize);
 | |
|   (void)(destBytes + byteSize);
 | |
| 
 | |
|   memcpy(destBytes.get(), srcBytes.get(), byteSize);
 | |
| }
 | |
| 
 | |
| template <class T, class U>
 | |
| inline void Memcpy(const Range<T>* const destRange,
 | |
|                    const RangedPtr<U>& srcBegin) {
 | |
|   Memcpy(destRange->begin(), srcBegin, destRange->length());
 | |
| }
 | |
| template <class T, class U>
 | |
| inline void Memcpy(const RangedPtr<T>* const destBegin,
 | |
|                    const Range<U>& srcRange) {
 | |
|   Memcpy(destBegin, srcRange->begin(), srcRange->length());
 | |
| }
 | |
| 
 | |
| template <typename Dst, typename Src>
 | |
| inline void Memcpy(const Span<Dst>* const dest, const Span<Src>& src) {
 | |
|   MOZ_RELEASE_ASSERT(src.size_bytes() >= dest->size_bytes());
 | |
|   MOZ_ASSERT(src.size_bytes() == dest->size_bytes());
 | |
|   memcpy(dest->data(), src.data(), dest->size_bytes());
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| inline bool StartsWith(const std::string_view str,
 | |
|                        const std::string_view part) {
 | |
|   return str.find(part) == 0;
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| namespace webgl {
 | |
| 
 | |
| // In theory, this number can be unbounded based on the driver. However, no
 | |
| // driver appears to expose more than 8. We might as well stop there too, for
 | |
| // now.
 | |
| // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
 | |
| inline constexpr size_t kMaxDrawBuffers = 8;
 | |
| 
 | |
| union UniformDataVal {
 | |
|   float f32;
 | |
|   int32_t i32;
 | |
|   uint32_t u32;
 | |
| };
 | |
| 
 | |
| enum class ProvokingVertex : GLenum {
 | |
|   FirstVertex = LOCAL_GL_FIRST_VERTEX_CONVENTION,
 | |
|   LastVertex = LOCAL_GL_LAST_VERTEX_CONVENTION,
 | |
| };
 | |
| inline constexpr bool IsEnumCase(const ProvokingVertex raw) {
 | |
|   switch (raw) {
 | |
|     case ProvokingVertex::FirstVertex:
 | |
|     case ProvokingVertex::LastVertex:
 | |
|       return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| template <class E>
 | |
| inline constexpr std::optional<E> AsEnumCase(
 | |
|     const std::underlying_type_t<E> raw) {
 | |
|   const auto ret = static_cast<E>(raw);
 | |
|   if (!IsEnumCase(ret)) return {};
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| // -
 | |
| 
 | |
| struct BufferAndIndex final {
 | |
|   const WebGLBuffer* buffer = nullptr;
 | |
|   uint32_t id = -1;
 | |
| };
 | |
| 
 | |
| }  // namespace webgl
 | |
| 
 | |
| struct IndexedBufferBinding final {
 | |
|   RefPtr<WebGLBuffer> mBufferBinding;
 | |
|   uint64_t mRangeStart = 0;
 | |
|   uint64_t mRangeSize = 0;
 | |
| 
 | |
|   IndexedBufferBinding();
 | |
|   ~IndexedBufferBinding();
 | |
| 
 | |
|   uint64_t ByteCount() const;
 | |
| };
 | |
| 
 | |
| // -
 | |
| 
 | |
| template <class... Args>
 | |
| inline std::string PrintfStdString(const char* const format,
 | |
|                                    const Args&... args) {
 | |
|   const auto nsStr = nsPrintfCString(format, args...);
 | |
|   return ToString(nsStr);
 | |
| }
 | |
| 
 | |
| inline const char* ToChars(const bool val) {
 | |
|   if (val) return "true";
 | |
|   return "false";
 | |
| }
 | |
| 
 | |
| template <class To>
 | |
| struct ReinterpretToSpan {
 | |
|   template <class FromT>
 | |
|   static inline constexpr Span<To> From(const Span<FromT>& from) {
 | |
|     static_assert(sizeof(FromT) == sizeof(To));
 | |
|     return {reinterpret_cast<To*>(from.data()), from.size()};
 | |
|   }
 | |
| };
 | |
| 
 | |
| }  // namespace mozilla
 | |
| 
 | |
| #endif
 | 
