Bug 1703654 - Prototype display-p3 for WebGL canvas. r=lsalzman,emilio,webidl,smaug
[gecko.git] / dom / canvas / WebGLTypes.h
blob6ffaf1d10614128fddad86ccf76e012927a85096
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGLTYPES_H_
7 #define WEBGLTYPES_H_
9 #include <limits>
10 #include <string>
11 #include <type_traits>
12 #include <unordered_map>
13 #include <vector>
15 #include "GLDefs.h"
16 #include "ImageContainer.h"
17 #include "mozilla/Casting.h"
18 #include "mozilla/CheckedInt.h"
19 #include "mozilla/MathAlgorithms.h"
20 #include "mozilla/Range.h"
21 #include "mozilla/RefCounted.h"
22 #include "mozilla/Result.h"
23 #include "mozilla/ResultVariant.h"
24 #include "mozilla/gfx/2D.h"
25 #include "mozilla/gfx/BuildConstants.h"
26 #include "mozilla/gfx/Point.h"
27 #include "mozilla/gfx/Rect.h"
28 #include "mozilla/ipc/Shmem.h"
29 #include "mozilla/layers/LayersSurfaces.h"
30 #include "gfxTypes.h"
32 #include "nsTArray.h"
33 #include "nsString.h"
34 #include "mozilla/dom/WebGLRenderingContextBinding.h"
35 #include "mozilla/ipc/SharedMemoryBasic.h"
37 // Manual reflection of WebIDL typedefs that are different from their
38 // OpenGL counterparts.
39 using WebGLsizeiptr = int64_t;
40 using WebGLintptr = int64_t;
41 using WebGLboolean = bool;
43 // -
45 namespace mozilla {
46 namespace gl {
47 class GLContext; // This is going to be needed a lot.
48 } // namespace gl
50 // -
51 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
52 // only!)
54 template <typename DestT>
55 class ForbidNarrowing final {
56 DestT mVal;
58 public:
59 template <typename SrcT>
60 MOZ_IMPLICIT ForbidNarrowing(SrcT val) : mVal(val) {
61 static_assert(
62 std::numeric_limits<SrcT>::min() >= std::numeric_limits<DestT>::min(),
63 "SrcT must be narrower than DestT.");
64 static_assert(
65 std::numeric_limits<SrcT>::max() <= std::numeric_limits<DestT>::max(),
66 "SrcT must be narrower than DestT.");
69 explicit operator DestT() const { return mVal; }
72 inline void* malloc(const ForbidNarrowing<size_t> s) {
73 return ::malloc(size_t(s));
76 inline void* calloc(const ForbidNarrowing<size_t> n,
77 const ForbidNarrowing<size_t> size) {
78 return ::calloc(size_t(n), size_t(size));
81 // -
83 namespace detail {
85 template <typename From>
86 class AutoAssertCastT final {
87 const From mVal;
89 public:
90 explicit AutoAssertCastT(const From val) : mVal(val) {}
92 template <typename To>
93 operator To() const {
94 return AssertedCast<To>(mVal);
98 } // namespace detail
100 template <typename From>
101 inline auto AutoAssertCast(const From val) {
102 return detail::AutoAssertCastT<From>(val);
105 namespace webgl {
106 template <typename T>
107 struct QueueParamTraits;
108 class TexUnpackBytes;
109 class TexUnpackImage;
110 class TexUnpackSurface;
111 } // namespace webgl
113 class ClientWebGLContext;
114 struct WebGLTexPboOffset;
115 class WebGLTexture;
116 class WebGLBuffer;
117 class WebGLFramebuffer;
118 class WebGLProgram;
119 class WebGLQuery;
120 class WebGLRenderbuffer;
121 class WebGLSampler;
122 class WebGLShader;
123 class WebGLSync;
124 class WebGLTexture;
125 class WebGLTransformFeedback;
126 class WebGLVertexArray;
128 // -
130 class VRefCounted : public RefCounted<VRefCounted> {
131 public:
132 virtual ~VRefCounted() = default;
134 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
135 virtual const char* typeName() const = 0;
136 virtual size_t typeSize() const = 0;
137 #endif
140 // -
143 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
144 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
145 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
146 * desktop OpenGL does not allow that.
148 enum class WebGLVertexAttrib0Status : uint8_t {
149 Default, // default status - no emulation needed
150 EmulatedUninitializedArray, // need an artificial attrib 0 array, but
151 // contents may be left uninitialized
152 EmulatedInitializedArray // need an artificial attrib 0 array, and contents
153 // must be initialized
157 * The formats that may participate, either as source or destination formats,
158 * in WebGL texture conversions. This includes:
159 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
160 * - additional formats provided by extensions, e.g. RGB32F
161 * - additional source formats, depending on browser details, used when
162 * uploading textures from DOM elements. See gfxImageSurface::Format().
164 enum class WebGLTexelFormat : uint8_t {
165 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
166 // image data
167 None,
168 // common value for formats for which format conversions are not supported
169 FormatNotSupportingAnyConversion,
170 // dummy pseudo-format meaning "use the other format".
171 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
172 // is implicitly treated as being RGB8 itself.
173 Auto,
174 // 1-channel formats
176 A16F, // OES_texture_half_float
177 A32F, // OES_texture_float
179 R16F, // OES_texture_half_float
180 R32F, // OES_texture_float
181 // 2-channel formats
182 RA8,
183 RA16F, // OES_texture_half_float
184 RA32F, // OES_texture_float
185 RG8,
186 RG16F,
187 RG32F,
188 // 3-channel formats
189 RGB8,
190 RGB565,
191 RGB11F11F10F,
192 RGB16F, // OES_texture_half_float
193 RGB32F, // OES_texture_float
194 // 4-channel formats
195 RGBA8,
196 RGBA5551,
197 RGBA4444,
198 RGBA16F, // OES_texture_half_float
199 RGBA32F, // OES_texture_float
200 // DOM element source only formats.
201 RGBX8,
202 BGRX8,
203 BGRA8
206 enum class WebGLTexImageFunc : uint8_t {
207 TexImage,
208 TexSubImage,
209 CopyTexImage,
210 CopyTexSubImage,
211 CompTexImage,
212 CompTexSubImage,
215 enum class WebGLTexDimensions : uint8_t { Tex2D, Tex3D };
217 // Please keep extensions in alphabetic order.
218 enum class WebGLExtensionID : uint8_t {
219 ANGLE_instanced_arrays,
220 EXT_blend_minmax,
221 EXT_color_buffer_float,
222 EXT_color_buffer_half_float,
223 EXT_disjoint_timer_query,
224 EXT_float_blend,
225 EXT_frag_depth,
226 EXT_shader_texture_lod,
227 EXT_sRGB,
228 EXT_texture_compression_bptc,
229 EXT_texture_compression_rgtc,
230 EXT_texture_filter_anisotropic,
231 EXT_texture_norm16,
232 MOZ_debug,
233 OES_draw_buffers_indexed,
234 OES_element_index_uint,
235 OES_fbo_render_mipmap,
236 OES_standard_derivatives,
237 OES_texture_float,
238 OES_texture_float_linear,
239 OES_texture_half_float,
240 OES_texture_half_float_linear,
241 OES_vertex_array_object,
242 OVR_multiview2,
243 WEBGL_color_buffer_float,
244 WEBGL_compressed_texture_astc,
245 WEBGL_compressed_texture_etc,
246 WEBGL_compressed_texture_etc1,
247 WEBGL_compressed_texture_pvrtc,
248 WEBGL_compressed_texture_s3tc,
249 WEBGL_compressed_texture_s3tc_srgb,
250 WEBGL_debug_renderer_info,
251 WEBGL_debug_shaders,
252 WEBGL_depth_texture,
253 WEBGL_draw_buffers,
254 WEBGL_explicit_present,
255 WEBGL_lose_context,
259 class UniqueBuffer final {
260 // Like UniquePtr<>, but for void* and malloc/calloc/free.
261 void* mBuffer = nullptr;
263 public:
264 static inline UniqueBuffer Take(void* buffer) {
265 UniqueBuffer ret;
266 ret.mBuffer = buffer;
267 return ret;
270 UniqueBuffer() = default;
272 ~UniqueBuffer() { reset(); }
274 UniqueBuffer(UniqueBuffer&& rhs) { *this = std::move(rhs); }
276 UniqueBuffer& operator=(UniqueBuffer&& rhs) {
277 reset();
278 this->mBuffer = rhs.mBuffer;
279 rhs.mBuffer = nullptr;
280 return *this;
283 explicit operator bool() const { return bool(mBuffer); }
285 void* get() const { return mBuffer; }
287 void reset() {
288 // Believe it or not, when `free` unconditional, it was showing up
289 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
290 // on Aquarium.
291 if (mBuffer) {
292 free(mBuffer);
293 mBuffer = nullptr;
298 namespace webgl {
299 struct FormatUsageInfo;
301 static constexpr GLenum kErrorPerfWarning = 0x10001;
303 struct SampleableInfo final {
304 const char* incompleteReason = nullptr;
305 uint32_t levels = 0;
306 const webgl::FormatUsageInfo* usage = nullptr;
307 bool isDepthTexCompare = false;
309 bool IsComplete() const { return bool(levels); }
312 enum class AttribBaseType : uint8_t {
313 Boolean, // Can convert from anything.
314 Float, // Also includes NormU?Int
315 Int,
316 Uint,
318 webgl::AttribBaseType ToAttribBaseType(GLenum);
319 const char* ToString(AttribBaseType);
321 enum class UniformBaseType : uint8_t {
322 Float,
323 Int,
324 Uint,
326 const char* ToString(UniformBaseType);
328 using ObjectId = uint64_t;
330 enum class BufferKind : uint8_t {
331 Undefined,
332 Index,
333 NonIndex,
336 } // namespace webgl
338 // -
340 struct FloatOrInt final // For TexParameter[fi] and friends.
342 const bool isFloat;
343 const GLfloat f;
344 const GLint i;
346 explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
348 explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
350 FloatOrInt& operator=(const FloatOrInt& x) {
351 memcpy(this, &x, sizeof(x));
352 return *this;
356 struct WebGLContextOptions {
357 bool alpha = true;
358 bool depth = true;
359 bool stencil = false;
360 bool premultipliedAlpha = true;
361 bool antialias = true;
362 bool preserveDrawingBuffer = false;
363 bool failIfMajorPerformanceCaveat = false;
364 bool xrCompatible = false;
365 dom::WebGLPowerPreference powerPreference =
366 dom::WebGLPowerPreference::Default;
367 Maybe<dom::PredefinedColorSpace> colorSpace;
368 bool shouldResistFingerprinting = true;
369 bool enableDebugRendererInfo = false;
371 WebGLContextOptions();
372 WebGLContextOptions(const WebGLContextOptions&) = default;
374 bool operator==(const WebGLContextOptions&) const;
375 bool operator!=(const WebGLContextOptions& rhs) const {
376 return !(*this == rhs);
380 namespace gfx {
382 inline ColorSpace2 ToColorSpace2(const Maybe<dom::PredefinedColorSpace> cs) {
383 if (!cs) {
384 return ColorSpace2::UNKNOWN;
387 switch (*cs) {
388 case dom::PredefinedColorSpace::Srgb:
389 return ColorSpace2::SRGB;
390 case dom::PredefinedColorSpace::Display_p3:
391 return ColorSpace2::DISPLAY_P3;
392 case dom::PredefinedColorSpace::EndGuard_:
393 break;
395 MOZ_CRASH("Exhaustive switch");
398 } // namespace gfx
400 // -
402 template <typename _T>
403 struct avec2 {
404 using T = _T;
406 T x = T();
407 T y = T();
409 template <typename U, typename V>
410 static Maybe<avec2> From(const U _x, const V _y) {
411 const auto x = CheckedInt<T>(_x);
412 const auto y = CheckedInt<T>(_y);
413 if (!x.isValid() || !y.isValid()) return {};
414 return Some(avec2(x.value(), y.value()));
417 template <typename U>
418 static auto From(const U& val) {
419 return From(val.x, val.y);
421 template <typename U>
422 static auto FromSize(const U& val) {
423 return From(val.width, val.height);
426 avec2() = default;
427 avec2(const T _x, const T _y) : x(_x), y(_y) {}
429 bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
430 bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
432 #define _(OP) \
433 avec2 operator OP(const avec2& rhs) const { \
434 return {x OP rhs.x, y OP rhs.y}; \
436 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
438 _(+)
439 _(-)
440 _(*)
441 _(/)
443 #undef _
445 avec2 Clamp(const avec2& min, const avec2& max) const {
446 return {mozilla::Clamp(x, min.x, max.x), mozilla::Clamp(y, min.y, max.y)};
449 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
450 // helper.
451 avec2 ClampMinMax(const avec2& min, const avec2& max) const {
452 const auto ClampScalar = [](const T v, const T min, const T max) {
453 return std::max(min, std::min(v, max));
455 return {ClampScalar(x, min.x, max.x), ClampScalar(y, min.y, max.y)};
458 template <typename U>
459 U StaticCast() const {
460 return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
464 template <typename T>
465 avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
466 return {std::min(a.x, b.x), std::min(a.y, b.y)};
469 template <typename T>
470 avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
471 return {std::max(a.x, b.x), std::max(a.y, b.y)};
474 // -
476 template <typename _T>
477 struct avec3 {
478 using T = _T;
480 T x = T();
481 T y = T();
482 T z = T();
484 template <typename U, typename V>
485 static Maybe<avec3> From(const U _x, const V _y, const V _z) {
486 const auto x = CheckedInt<T>(_x);
487 const auto y = CheckedInt<T>(_y);
488 const auto z = CheckedInt<T>(_z);
489 if (!x.isValid() || !y.isValid() || !z.isValid()) return {};
490 return Some(avec3(x.value(), y.value(), z.value()));
493 template <typename U>
494 static auto From(const U& val) {
495 return From(val.x, val.y, val.z);
498 avec3() = default;
499 avec3(const T _x, const T _y, const T _z) : x(_x), y(_y), z(_z) {}
501 bool operator==(const avec3& rhs) const {
502 return x == rhs.x && y == rhs.y && z == rhs.z;
504 bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
507 using ivec2 = avec2<int32_t>;
508 using ivec3 = avec3<int32_t>;
509 using uvec2 = avec2<uint32_t>;
510 using uvec3 = avec3<uint32_t>;
512 inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
514 // -
516 namespace webgl {
518 struct PackingInfo final {
519 GLenum format = 0;
520 GLenum type = 0;
522 bool operator<(const PackingInfo& x) const {
523 if (format != x.format) return format < x.format;
525 return type < x.type;
528 bool operator==(const PackingInfo& x) const {
529 return (format == x.format && type == x.type);
533 struct DriverUnpackInfo final {
534 GLenum internalFormat = 0;
535 GLenum unpackFormat = 0;
536 GLenum unpackType = 0;
538 PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
541 // -
543 template <typename E>
544 class EnumMask {
545 public:
546 uint64_t mBits = 0;
548 private:
549 struct BitRef final {
550 EnumMask& bits;
551 const uint64_t mask;
553 explicit operator bool() const { return bits.mBits & mask; }
555 auto& operator=(const bool val) {
556 if (val) {
557 bits.mBits |= mask;
558 } else {
559 bits.mBits &= ~mask;
561 return *this;
565 uint64_t Mask(const E i) const {
566 return uint64_t{1} << static_cast<uint64_t>(i);
569 public:
570 BitRef operator[](const E i) { return {*this, Mask(i)}; }
571 bool operator[](const E i) const { return mBits & Mask(i); }
574 class ExtensionBits : public EnumMask<WebGLExtensionID> {};
576 // -
578 enum class ContextLossReason : uint8_t {
579 None,
580 Manual,
581 Guilty,
584 inline bool ReadContextLossReason(const uint8_t val,
585 ContextLossReason* const out) {
586 if (val > static_cast<uint8_t>(ContextLossReason::Guilty)) {
587 return false;
589 *out = static_cast<ContextLossReason>(val);
590 return true;
593 // -
595 struct InitContextDesc final {
596 bool isWebgl2 = false;
597 bool resistFingerprinting = false;
598 uvec2 size = {};
599 WebGLContextOptions options;
600 uint32_t principalKey = 0;
603 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs = 4;
605 struct Limits final {
606 ExtensionBits supportedExtensions;
608 // WebGL 1
609 uint32_t maxTexUnits = 0;
610 uint32_t maxTex2dSize = 0;
611 uint32_t maxTexCubeSize = 0;
612 uint32_t maxVertexAttribs = 0;
613 uint32_t maxViewportDim = 0;
614 std::array<float, 2> pointSizeRange = {{1, 1}};
615 std::array<float, 2> lineWidthRange = {{1, 1}};
617 // WebGL 2
618 uint32_t maxTexArrayLayers = 0;
619 uint32_t maxTex3dSize = 0;
620 uint32_t maxUniformBufferBindings = 0;
621 uint32_t uniformBufferOffsetAlignment = 0;
623 // Exts
624 bool astcHdr = false;
625 uint32_t maxColorDrawBuffers = 1;
626 uint64_t queryCounterBitsTimeElapsed = 0;
627 uint64_t queryCounterBitsTimestamp = 0;
628 uint32_t maxMultiviewLayers = 0;
631 struct InitContextResult final {
632 std::string error;
633 WebGLContextOptions options;
634 webgl::Limits limits;
635 EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
638 // -
640 struct ErrorInfo final {
641 GLenum type;
642 std::string info;
645 struct ShaderPrecisionFormat final {
646 GLint rangeMin = 0;
647 GLint rangeMax = 0;
648 GLint precision = 0;
651 // -
653 enum class LossStatus {
654 Ready,
656 Lost,
657 LostForever,
658 LostManually,
661 // -
663 struct CompileResult final {
664 bool pending = true;
665 nsCString log;
666 nsCString translatedSource;
667 bool success = false;
670 // -
672 struct OpaqueFramebufferOptions final {
673 bool depthStencil = true;
674 bool antialias = true;
675 uint32_t width = 0;
676 uint32_t height = 0;
679 // -
681 struct SwapChainOptions final {
682 bool bgra = false;
685 // -
687 struct ActiveInfo {
688 GLenum elemType = 0; // `type`
689 uint32_t elemCount = 0; // `size`
690 std::string name;
693 struct ActiveAttribInfo final : public ActiveInfo {
694 int32_t location = -1;
695 AttribBaseType baseType = AttribBaseType::Float;
698 struct ActiveUniformInfo final : public ActiveInfo {
699 std::unordered_map<uint32_t, uint32_t>
700 locByIndex; // Uniform array locations are sparse.
701 int32_t block_index = -1;
702 int32_t block_offset = -1; // In block, offset.
703 int32_t block_arrayStride = -1;
704 int32_t block_matrixStride = -1;
705 bool block_isRowMajor = false;
708 struct ActiveUniformBlockInfo final {
709 std::string name;
710 // BLOCK_BINDING is dynamic state
711 uint32_t dataSize = 0;
712 std::vector<uint32_t> activeUniformIndices;
713 bool referencedByVertexShader = false;
714 bool referencedByFragmentShader = false;
717 struct LinkActiveInfo final {
718 std::vector<ActiveAttribInfo> activeAttribs;
719 std::vector<ActiveUniformInfo> activeUniforms;
720 std::vector<ActiveUniformBlockInfo> activeUniformBlocks;
721 std::vector<ActiveInfo> activeTfVaryings;
724 struct LinkResult final {
725 bool pending = true;
726 nsCString log;
727 bool success = false;
728 LinkActiveInfo active;
729 GLenum tfBufferMode = 0;
732 // -
734 /// 4x32-bit primitives, with a type tag.
735 struct TypedQuad final {
736 alignas(alignof(float)) uint8_t data[4 * sizeof(float)] = {};
737 webgl::AttribBaseType type = webgl::AttribBaseType::Float;
740 /// [1-16]x32-bit primitives, with a type tag.
741 struct GetUniformData final {
742 alignas(alignof(float)) uint8_t data[4 * 4 * sizeof(float)] = {};
743 GLenum type = 0;
746 struct FrontBufferSnapshotIpc final {
747 uvec2 surfSize = {};
748 Maybe<mozilla::ipc::Shmem> shmem = {};
751 struct ReadPixelsResult {
752 gfx::IntRect subrect = {};
753 size_t byteStride = 0;
756 struct ReadPixelsResultIpc final : public ReadPixelsResult {
757 mozilla::ipc::Shmem shmem = {};
760 struct VertAttribPointerDesc final {
761 bool intFunc = false;
762 uint8_t channels = 4;
763 bool normalized = false;
764 uint8_t byteStrideOrZero = 0;
765 GLenum type = LOCAL_GL_FLOAT;
766 uint64_t byteOffset = 0;
769 struct VertAttribPointerCalculated final {
770 uint8_t byteSize = 4 * 4;
771 uint8_t byteStride = 4 * 4; // at-most 255
772 webgl::AttribBaseType baseType = webgl::AttribBaseType::Float;
775 } // namespace webgl
778 * Represents a block of memory that it may or may not own. The
779 * inner data type must be trivially copyable by memcpy.
781 template <typename T = uint8_t>
782 class RawBuffer final {
783 const T* mBegin = nullptr;
784 size_t mLen = 0;
785 UniqueBuffer mOwned;
787 public:
788 using ElementType = T;
791 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
793 explicit RawBuffer(const Range<const T>& data, UniqueBuffer&& owned = {})
794 : mBegin(data.begin().get()),
795 mLen(data.length()),
796 mOwned(std::move(owned)) {}
798 explicit RawBuffer(const size_t len) : mLen(len) {}
800 ~RawBuffer() = default;
802 Range<const T> Data() const { return {mBegin, mLen}; }
803 const auto& begin() const { return mBegin; }
804 const auto& size() const { return mLen; }
806 void Shrink(const size_t newLen) {
807 if (mLen <= newLen) return;
808 mLen = newLen;
811 RawBuffer() = default;
813 RawBuffer(const RawBuffer&) = delete;
814 RawBuffer& operator=(const RawBuffer&) = delete;
816 RawBuffer(RawBuffer&&) = default;
817 RawBuffer& operator=(RawBuffer&&) = default;
820 // -
822 struct CopyableRange final : public Range<const uint8_t> {};
824 // -
826 // clang-format off
828 #define FOREACH_ID(X) \
829 X(FuncScopeIdError) \
830 X(compressedTexImage2D) \
831 X(compressedTexImage3D) \
832 X(compressedTexSubImage2D) \
833 X(compressedTexSubImage3D) \
834 X(copyTexSubImage2D) \
835 X(copyTexSubImage3D) \
836 X(drawArrays) \
837 X(drawArraysInstanced) \
838 X(drawElements) \
839 X(drawElementsInstanced) \
840 X(drawRangeElements) \
841 X(renderbufferStorage) \
842 X(renderbufferStorageMultisample) \
843 X(texImage2D) \
844 X(texImage3D) \
845 X(TexStorage2D) \
846 X(TexStorage3D) \
847 X(texSubImage2D) \
848 X(texSubImage3D) \
849 X(vertexAttrib1f) \
850 X(vertexAttrib1fv) \
851 X(vertexAttrib2f) \
852 X(vertexAttrib2fv) \
853 X(vertexAttrib3f) \
854 X(vertexAttrib3fv) \
855 X(vertexAttrib4f) \
856 X(vertexAttrib4fv) \
857 X(vertexAttribI4i) \
858 X(vertexAttribI4iv) \
859 X(vertexAttribI4ui) \
860 X(vertexAttribI4uiv) \
861 X(vertexAttribIPointer) \
862 X(vertexAttribPointer)
864 // clang-format on
866 enum class FuncScopeId {
867 #define _(X) X,
868 FOREACH_ID(_)
869 #undef _
872 static constexpr const char* const FUNCSCOPE_NAME_BY_ID[] = {
873 #define _(X) #X,
874 FOREACH_ID(_)
875 #undef _
878 #undef FOREACH_ID
880 inline auto GetFuncScopeName(const FuncScopeId id) {
881 return FUNCSCOPE_NAME_BY_ID[static_cast<size_t>(id)];
884 // -
886 template <typename C, typename K>
887 inline auto MaybeFind(C& container, const K& key)
888 -> decltype(&(container.find(key)->second)) {
889 const auto itr = container.find(key);
890 if (itr == container.end()) return nullptr;
891 return &(itr->second);
894 template <typename C, typename K>
895 inline typename C::mapped_type Find(
896 const C& container, const K& key,
897 const typename C::mapped_type notFound = {}) {
898 const auto itr = container.find(key);
899 if (itr == container.end()) return notFound;
900 return itr->second;
903 // -
905 template <typename T, typename U>
906 inline Maybe<T> MaybeAs(const U val) {
907 const auto checked = CheckedInt<T>(val);
908 if (!checked.isValid()) return {};
909 return Some(checked.value());
912 // -
914 inline GLenum ImageToTexTarget(const GLenum imageTarget) {
915 switch (imageTarget) {
916 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
917 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
918 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
919 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
920 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
921 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
922 return LOCAL_GL_TEXTURE_CUBE_MAP;
923 default:
924 return imageTarget;
928 inline bool IsTexTarget3D(const GLenum texTarget) {
929 switch (texTarget) {
930 case LOCAL_GL_TEXTURE_2D_ARRAY:
931 case LOCAL_GL_TEXTURE_3D:
932 return true;
934 default:
935 return false;
939 // -
941 namespace dom {
942 class Element;
943 class ImageBitmap;
944 class ImageData;
945 class OffscreenCanvas;
946 } // namespace dom
948 struct TexImageSource {
949 const dom::ArrayBufferView* mView = nullptr;
950 GLuint mViewElemOffset = 0;
951 GLuint mViewElemLengthOverride = 0;
953 const WebGLintptr* mPboOffset = nullptr;
955 const dom::ImageBitmap* mImageBitmap = nullptr;
956 const dom::ImageData* mImageData = nullptr;
958 const dom::OffscreenCanvas* mOffscreenCanvas = nullptr;
960 const dom::Element* mDomElem = nullptr;
961 ErrorResult* mOut_error = nullptr;
964 namespace webgl {
966 template <class DerivedT>
967 struct DeriveNotEq {
968 bool operator!=(const DerivedT& rhs) const {
969 const auto self = reinterpret_cast<const DerivedT*>(this);
970 return !(*self == rhs);
974 struct PixelPackingState : public DeriveNotEq<PixelPackingState> {
975 uint32_t alignmentInTypeElems = 4; // ALIGNMENT isn't naive byte alignment!
976 uint32_t rowLength = 0;
977 uint32_t imageHeight = 0;
978 uint32_t skipPixels = 0;
979 uint32_t skipRows = 0;
980 uint32_t skipImages = 0;
982 // C++20's default comparison operators can't come soon enough!
983 bool operator==(const PixelPackingState& rhs) const {
984 return alignmentInTypeElems == rhs.alignmentInTypeElems &&
985 rowLength == rhs.rowLength && imageHeight == rhs.imageHeight &&
986 skipPixels == rhs.skipPixels && skipRows == rhs.skipRows &&
987 skipImages == rhs.skipImages;
990 static void AssertDefaultUnpack(gl::GLContext& gl, const bool isWebgl2) {
991 PixelPackingState{}.AssertCurrentUnpack(gl, isWebgl2);
994 void ApplyUnpack(gl::GLContext&, bool isWebgl2,
995 const uvec3& uploadSize) const;
996 bool AssertCurrentUnpack(gl::GLContext&, bool isWebgl2) const;
999 struct PixelUnpackStateWebgl final : public PixelPackingState {
1000 GLenum colorspaceConversion =
1001 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
1002 bool flipY = false;
1003 bool premultiplyAlpha = false;
1004 bool requireFastPath = false;
1007 struct ExplicitPixelPackingState final {
1008 struct Metrics final {
1009 uvec3 usedSize = {};
1010 size_t bytesPerPixel = 0;
1012 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1013 // ...aligned to ALIGNMENT.
1014 size_t bytesPerRowStride = 0;
1016 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1017 size_t totalRows = 0;
1019 // This ensures that no one else needs to do CheckedInt math.
1020 size_t totalBytesUsed = 0;
1021 size_t totalBytesStrided = 0;
1024 // It's so important that these aren't modified once evaluated.
1025 const PixelPackingState state;
1026 const Metrics metrics;
1028 static Result<ExplicitPixelPackingState, std::string> ForUseWith(
1029 const PixelPackingState&, GLenum target, const uvec3& subrectSize,
1030 const webgl::PackingInfo&, const Maybe<size_t> bytesPerRowStrideOverride);
1033 struct ReadPixelsDesc final {
1034 ivec2 srcOffset;
1035 uvec2 size;
1036 PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
1037 PixelPackingState packState;
1040 } // namespace webgl
1042 namespace webgl {
1044 struct TexUnpackBlobDesc final {
1045 GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
1046 uvec3 size;
1047 gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
1049 Maybe<RawBuffer<>> cpuData;
1050 Maybe<uint64_t> pboOffset;
1052 Maybe<uvec2> structuredSrcSize;
1053 RefPtr<layers::Image> image;
1054 Maybe<layers::SurfaceDescriptor> sd;
1055 RefPtr<gfx::DataSourceSurface> dataSurf;
1057 webgl::PixelUnpackStateWebgl unpacking;
1058 bool applyUnpackTransforms = true;
1060 // -
1062 auto ExplicitUnpacking(const webgl::PackingInfo& pi,
1063 const Maybe<size_t> bytesPerRowStrideOverride) const {
1064 return ExplicitPixelPackingState::ForUseWith(this->unpacking,
1065 this->imageTarget, this->size,
1066 pi, bytesPerRowStrideOverride);
1069 void Shrink(const webgl::PackingInfo&);
1072 } // namespace webgl
1074 // ---------------------------------------
1075 // MakeRange
1077 template <typename T, size_t N>
1078 inline Range<const T> MakeRange(T (&arr)[N]) {
1079 return {arr, N};
1082 template <typename T>
1083 inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
1084 return {seq.Elements(), seq.Length()};
1087 template <typename T>
1088 inline Range<const T> MakeRange(const RawBuffer<T>& from) {
1089 return from.Data();
1092 // abv = ArrayBufferView
1093 template <typename T>
1094 inline auto MakeRangeAbv(const T& abv)
1095 -> Range<const typename T::element_type> {
1096 abv.ComputeState();
1097 return {abv.Data(), abv.Length()};
1100 // -
1102 constexpr auto kUniversalAlignment = alignof(std::max_align_t);
1104 template <typename T>
1105 inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
1106 MOZ_ASSERT(alignment);
1107 const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
1108 const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
1109 const auto aligned = wholeMultiples * alignment;
1110 return aligned - begin;
1113 template <typename T>
1114 inline size_t ByteSize(const Range<T>& range) {
1115 return range.length() * sizeof(T);
1118 Maybe<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
1119 GLuint elemOffset,
1120 GLuint elemCountOverride);
1122 // -
1124 template <typename T>
1125 RawBuffer<T> RawBufferView(const Range<T>& range) {
1126 return RawBuffer<T>{range};
1129 // -
1131 Maybe<webgl::ErrorInfo> CheckBindBufferRange(
1132 const GLenum target, const GLuint index, const bool isBuffer,
1133 const uint64_t offset, const uint64_t size, const webgl::Limits& limits);
1135 Maybe<webgl::ErrorInfo> CheckFramebufferAttach(const GLenum bindImageTarget,
1136 const GLenum curTexTarget,
1137 const uint32_t mipLevel,
1138 const uint32_t zLayerBase,
1139 const uint32_t zLayerCount,
1140 const webgl::Limits& limits);
1142 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
1143 CheckVertexAttribPointer(bool isWebgl2, const webgl::VertAttribPointerDesc&);
1145 uint8_t ElemTypeComponents(GLenum elemType);
1147 inline std::string ToString(const nsACString& text) {
1148 return {text.BeginReading(), text.Length()};
1151 inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
1152 const RangedPtr<const uint8_t>& srcBytes,
1153 const size_t byteSize) {
1154 // Trigger range asserts
1155 (void)(srcBytes + byteSize);
1156 (void)(destBytes + byteSize);
1158 memcpy(destBytes.get(), srcBytes.get(), byteSize);
1161 // -
1163 namespace webgl {
1165 // In theory, this number can be unbounded based on the driver. However, no
1166 // driver appears to expose more than 8. We might as well stop there too, for
1167 // now.
1168 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1169 inline constexpr size_t kMaxDrawBuffers = 8;
1170 } // namespace webgl
1172 } // namespace mozilla
1174 #endif