summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGLTypes.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/canvas/WebGLTypes.h')
-rw-r--r--dom/canvas/WebGLTypes.h1255
1 files changed, 1255 insertions, 0 deletions
diff --git a/dom/canvas/WebGLTypes.h b/dom/canvas/WebGLTypes.h
new file mode 100644
index 0000000000..b06aa8a314
--- /dev/null
+++ b/dom/canvas/WebGLTypes.h
@@ -0,0 +1,1255 @@
+/* -*- 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 "GLDefs.h"
+#include "GLVendor.h"
+#include "ImageContainer.h"
+#include "mozilla/Casting.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/MathAlgorithms.h"
+#include "mozilla/Range.h"
+#include "mozilla/RefCounted.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultVariant.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));
+}
+
+// -
+
+namespace detail {
+
+template <typename From>
+class AutoAssertCastT final {
+ const From mVal;
+
+ public:
+ explicit AutoAssertCastT(const From val) : mVal(val) {}
+
+ template <typename To>
+ operator To() const {
+ return AssertedCast<To>(mVal);
+ }
+};
+
+} // namespace detail
+
+template <typename From>
+inline auto AutoAssertCast(const From val) {
+ return detail::AutoAssertCastT<From>(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;
+ case dom::PredefinedColorSpace::EndGuard_:
+ break;
+ }
+ 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); }
+};
+
+class ExtensionBits : public 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;
+ uvec2 size = {};
+ WebGLContextOptions options;
+ uint32_t principalKey = 0;
+};
+
+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;
+ uint32_t maxColorDrawBuffers = 1;
+ uint64_t queryCounterBitsTimeElapsed = 0;
+ uint64_t queryCounterBitsTimestamp = 0;
+ uint32_t maxMultiviewLayers = 0;
+};
+
+struct InitContextResult final {
+ std::string error;
+ WebGLContextOptions options;
+ webgl::Limits limits;
+ EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
+ gl::GLVendor vendor;
+};
+
+// -
+
+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;
+ uint32_t width = 0;
+ uint32_t height = 0;
+};
+
+// -
+
+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
+
+/**
+ * Represents a block of memory that it may or may not own. The
+ * inner data type must be trivially copyable by memcpy.
+ */
+template <typename T = uint8_t>
+class RawBuffer final {
+ const T* mBegin = nullptr;
+ size_t mLen = 0;
+ UniqueBuffer mOwned;
+
+ public:
+ using ElementType = T;
+
+ /**
+ * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
+ */
+ explicit RawBuffer(const Range<const T>& data, UniqueBuffer&& owned = {})
+ : mBegin(data.begin().get()),
+ mLen(data.length()),
+ mOwned(std::move(owned)) {}
+
+ explicit RawBuffer(const size_t len) : mLen(len) {}
+
+ ~RawBuffer() = default;
+
+ Range<const T> Data() const { return {mBegin, mLen}; }
+ const auto& begin() const { return mBegin; }
+ const auto& size() const { return mLen; }
+
+ void Shrink(const size_t newLen) {
+ if (mLen <= newLen) return;
+ mLen = newLen;
+ }
+
+ RawBuffer() = default;
+
+ RawBuffer(const RawBuffer&) = delete;
+ RawBuffer& operator=(const RawBuffer&) = delete;
+
+ RawBuffer(RawBuffer&&) = default;
+ RawBuffer& operator=(RawBuffer&&) = default;
+};
+
+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;
+} // 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::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<RawBuffer<>> 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()};
+}
+
+template <typename T>
+inline Range<const T> MakeRange(const RawBuffer<T>& from) {
+ return from.Data();
+}
+
+// abv = ArrayBufferView
+template <typename T>
+inline auto MakeRangeAbv(const T& abv)
+ -> Range<const typename T::element_type> {
+ abv.ComputeState();
+ return {abv.Data(), abv.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<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
+ GLuint elemOffset,
+ GLuint elemCountOverride);
+
+// -
+
+template <typename T>
+RawBuffer<T> RawBufferView(const Range<T>& range) {
+ return RawBuffer<T>{range};
+}
+
+// -
+
+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());
+}
+
+// -
+
+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;
+}
+
+} // namespace webgl
+
+} // namespace mozilla
+
+#endif