diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/WebGLTypes.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/WebGLTypes.h')
-rw-r--r-- | dom/canvas/WebGLTypes.h | 1255 |
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 |