1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef WEBGLTYPES_H_
7 #define WEBGLTYPES_H_
8
9 #include <limits>
10 #include <type_traits>
11 #include <unordered_map>
12 #include <vector>
13
14 #include "GLDefs.h"
15 #include "ImageContainer.h"
16 #include "mozilla/Casting.h"
17 #include "mozilla/CheckedInt.h"
18 #include "mozilla/MathAlgorithms.h"
19 #include "mozilla/Range.h"
20 #include "mozilla/RefCounted.h"
21 #include "mozilla/ResultVariant.h"
22 #include "mozilla/gfx/2D.h"
23 #include "mozilla/gfx/BuildConstants.h"
24 #include "mozilla/gfx/Point.h"
25 #include "mozilla/gfx/Rect.h"
26 #include "mozilla/ipc/Shmem.h"
27 #include "mozilla/layers/LayersSurfaces.h"
28 #include "gfxTypes.h"
29
30 #include "nsTArray.h"
31 #include "nsString.h"
32 #include "mozilla/dom/WebGLRenderingContextBinding.h"
33 #include "mozilla/ipc/SharedMemoryBasic.h"
34
35 // Manual reflection of WebIDL typedefs that are different from their
36 // OpenGL counterparts.
37 typedef int64_t WebGLsizeiptr;
38 typedef int64_t WebGLintptr;
39 typedef bool WebGLboolean;
40
41 // -
42
43 namespace mozilla {
44 namespace gl {
45 class GLContext; // This is going to be needed a lot.
46 } // namespace gl
47
48 // -
49 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
50 // only!)
51
52 template <typename DestT>
53 class ForbidNarrowing final {
54 DestT mVal;
55
56 public:
57 template <typename SrcT>
ForbidNarrowing(SrcT val)58 MOZ_IMPLICIT ForbidNarrowing(SrcT val) : mVal(val) {
59 static_assert(
60 std::numeric_limits<SrcT>::min() >= std::numeric_limits<DestT>::min(),
61 "SrcT must be narrower than DestT.");
62 static_assert(
63 std::numeric_limits<SrcT>::max() <= std::numeric_limits<DestT>::max(),
64 "SrcT must be narrower than DestT.");
65 }
66
DestT()67 explicit operator DestT() const { return mVal; }
68 };
69
malloc(const ForbidNarrowing<size_t> s)70 inline void* malloc(const ForbidNarrowing<size_t> s) {
71 return ::malloc(size_t(s));
72 }
73
calloc(const ForbidNarrowing<size_t> n,const ForbidNarrowing<size_t> size)74 inline void* calloc(const ForbidNarrowing<size_t> n,
75 const ForbidNarrowing<size_t> size) {
76 return ::calloc(size_t(n), size_t(size));
77 }
78
79 // -
80
81 namespace detail {
82
83 template <typename From>
84 class AutoAssertCastT final {
85 const From mVal;
86
87 public:
AutoAssertCastT(const From val)88 explicit AutoAssertCastT(const From val) : mVal(val) {}
89
90 template <typename To>
To()91 operator To() const {
92 return AssertedCast<To>(mVal);
93 }
94 };
95
96 } // namespace detail
97
98 template <typename From>
AutoAssertCast(const From val)99 inline auto AutoAssertCast(const From val) {
100 return detail::AutoAssertCastT<From>(val);
101 }
102
103 namespace webgl {
104 template <typename T>
105 struct QueueParamTraits;
106 class TexUnpackBytes;
107 class TexUnpackImage;
108 class TexUnpackSurface;
109 } // namespace webgl
110
111 class ClientWebGLContext;
112 struct WebGLTexPboOffset;
113 class WebGLTexture;
114 class WebGLBuffer;
115 class WebGLFramebuffer;
116 class WebGLProgram;
117 class WebGLQuery;
118 class WebGLRenderbuffer;
119 class WebGLSampler;
120 class WebGLShader;
121 class WebGLSync;
122 class WebGLTexture;
123 class WebGLTransformFeedback;
124 class WebGLVertexArray;
125
126 // -
127
128 class VRefCounted : public RefCounted<VRefCounted> {
129 public:
130 virtual ~VRefCounted() = default;
131
132 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
133 virtual const char* typeName() const = 0;
134 virtual size_t typeSize() const = 0;
135 #endif
136 };
137
138 // -
139
140 /*
141 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
142 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
143 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
144 * desktop OpenGL does not allow that.
145 */
146 enum class WebGLVertexAttrib0Status : uint8_t {
147 Default, // default status - no emulation needed
148 EmulatedUninitializedArray, // need an artificial attrib 0 array, but
149 // contents may be left uninitialized
150 EmulatedInitializedArray // need an artificial attrib 0 array, and contents
151 // must be initialized
152 };
153
154 /*
155 * The formats that may participate, either as source or destination formats,
156 * in WebGL texture conversions. This includes:
157 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
158 * - additional formats provided by extensions, e.g. RGB32F
159 * - additional source formats, depending on browser details, used when
160 * uploading textures from DOM elements. See gfxImageSurface::Format().
161 */
162 enum class WebGLTexelFormat : uint8_t {
163 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
164 // image data
165 None,
166 // common value for formats for which format conversions are not supported
167 FormatNotSupportingAnyConversion,
168 // dummy pseudo-format meaning "use the other format".
169 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
170 // is implicitly treated as being RGB8 itself.
171 Auto,
172 // 1-channel formats
173 A8,
174 A16F, // OES_texture_half_float
175 A32F, // OES_texture_float
176 R8,
177 R16F, // OES_texture_half_float
178 R32F, // OES_texture_float
179 // 2-channel formats
180 RA8,
181 RA16F, // OES_texture_half_float
182 RA32F, // OES_texture_float
183 RG8,
184 RG16F,
185 RG32F,
186 // 3-channel formats
187 RGB8,
188 RGB565,
189 RGB11F11F10F,
190 RGB16F, // OES_texture_half_float
191 RGB32F, // OES_texture_float
192 // 4-channel formats
193 RGBA8,
194 RGBA5551,
195 RGBA4444,
196 RGBA16F, // OES_texture_half_float
197 RGBA32F, // OES_texture_float
198 // DOM element source only formats.
199 RGBX8,
200 BGRX8,
201 BGRA8
202 };
203
204 enum class WebGLTexImageFunc : uint8_t {
205 TexImage,
206 TexSubImage,
207 CopyTexImage,
208 CopyTexSubImage,
209 CompTexImage,
210 CompTexSubImage,
211 };
212
213 enum class WebGLTexDimensions : uint8_t { Tex2D, Tex3D };
214
215 // Please keep extensions in alphabetic order.
216 enum class WebGLExtensionID : uint8_t {
217 ANGLE_instanced_arrays,
218 EXT_blend_minmax,
219 EXT_color_buffer_float,
220 EXT_color_buffer_half_float,
221 EXT_disjoint_timer_query,
222 EXT_float_blend,
223 EXT_frag_depth,
224 EXT_shader_texture_lod,
225 EXT_sRGB,
226 EXT_texture_compression_bptc,
227 EXT_texture_compression_rgtc,
228 EXT_texture_filter_anisotropic,
229 EXT_texture_norm16,
230 MOZ_debug,
231 OES_element_index_uint,
232 OES_fbo_render_mipmap,
233 OES_standard_derivatives,
234 OES_texture_float,
235 OES_texture_float_linear,
236 OES_texture_half_float,
237 OES_texture_half_float_linear,
238 OES_vertex_array_object,
239 OVR_multiview2,
240 WEBGL_color_buffer_float,
241 WEBGL_compressed_texture_astc,
242 WEBGL_compressed_texture_etc,
243 WEBGL_compressed_texture_etc1,
244 WEBGL_compressed_texture_pvrtc,
245 WEBGL_compressed_texture_s3tc,
246 WEBGL_compressed_texture_s3tc_srgb,
247 WEBGL_debug_renderer_info,
248 WEBGL_debug_shaders,
249 WEBGL_depth_texture,
250 WEBGL_draw_buffers,
251 WEBGL_explicit_present,
252 WEBGL_lose_context,
253 Max
254 };
255
256 class UniqueBuffer {
257 // Like UniquePtr<>, but for void* and malloc/calloc/free.
258 void* mBuffer;
259
260 public:
Alloc(const size_t byteSize)261 static inline UniqueBuffer Alloc(const size_t byteSize) {
262 return {malloc(byteSize)};
263 }
264
UniqueBuffer()265 UniqueBuffer() : mBuffer(nullptr) {}
266
UniqueBuffer(void * buffer)267 MOZ_IMPLICIT UniqueBuffer(void* buffer) : mBuffer(buffer) {}
268
~UniqueBuffer()269 ~UniqueBuffer() { free(mBuffer); }
270
UniqueBuffer(UniqueBuffer && other)271 UniqueBuffer(UniqueBuffer&& other) {
272 this->mBuffer = other.mBuffer;
273 other.mBuffer = nullptr;
274 }
275
276 UniqueBuffer& operator=(UniqueBuffer&& other) {
277 free(this->mBuffer);
278 this->mBuffer = other.mBuffer;
279 other.mBuffer = nullptr;
280 return *this;
281 }
282
283 UniqueBuffer& operator=(void* newBuffer) {
284 free(this->mBuffer);
285 this->mBuffer = newBuffer;
286 return *this;
287 }
288
289 explicit operator bool() const { return bool(mBuffer); }
290
get()291 void* get() const { return mBuffer; }
292
293 explicit UniqueBuffer(const UniqueBuffer& other) =
294 delete; // construct using std::move()!
295 UniqueBuffer& operator=(const UniqueBuffer& other) =
296 delete; // assign using std::move()!
297 };
298
299 namespace webgl {
300 struct FormatUsageInfo;
301
302 static constexpr GLenum kErrorPerfWarning = 0x10001;
303
304 struct SampleableInfo final {
305 const char* incompleteReason = nullptr;
306 uint32_t levels = 0;
307 const webgl::FormatUsageInfo* usage = nullptr;
308 bool isDepthTexCompare = false;
309
IsCompletefinal310 bool IsComplete() const { return bool(levels); }
311 };
312
313 enum class AttribBaseType : uint8_t {
314 Boolean, // Can convert from anything.
315 Float, // Also includes NormU?Int
316 Int,
317 Uint,
318 };
319 webgl::AttribBaseType ToAttribBaseType(GLenum);
320 const char* ToString(AttribBaseType);
321
322 enum class UniformBaseType : uint8_t {
323 Float,
324 Int,
325 Uint,
326 };
327 const char* ToString(UniformBaseType);
328
329 typedef uint64_t ObjectId;
330
331 enum class BufferKind : uint8_t {
332 Undefined,
333 Index,
334 NonIndex,
335 };
336
337 } // namespace webgl
338
339 // -
340
341 struct FloatOrInt final // For TexParameter[fi] and friends.
342 {
343 const bool isFloat;
344 const GLfloat f;
345 const GLint i;
346
isFloatfinal347 explicit FloatOrInt(GLint x = 0) : isFloat(false), f(x), i(x) {}
348
FloatOrIntfinal349 explicit FloatOrInt(GLfloat x) : isFloat(true), f(x), i(roundf(x)) {}
350
351 FloatOrInt& operator=(const FloatOrInt& x) {
352 memcpy(this, &x, sizeof(x));
353 return *this;
354 }
355 };
356
357 using WebGLTexUnpackVariant =
358 Variant<UniquePtr<webgl::TexUnpackBytes>,
359 UniquePtr<webgl::TexUnpackSurface>,
360 UniquePtr<webgl::TexUnpackImage>, WebGLTexPboOffset>;
361
362 using MaybeWebGLTexUnpackVariant = Maybe<WebGLTexUnpackVariant>;
363
364 struct WebGLContextOptions {
365 bool alpha = true;
366 bool depth = true;
367 bool stencil = false;
368 bool premultipliedAlpha = true;
369 bool antialias = true;
370 bool preserveDrawingBuffer = false;
371 bool failIfMajorPerformanceCaveat = false;
372 bool xrCompatible = false;
373 dom::WebGLPowerPreference powerPreference =
374 dom::WebGLPowerPreference::Default;
375 bool shouldResistFingerprinting = true;
376 bool enableDebugRendererInfo = false;
377
378 WebGLContextOptions();
379 WebGLContextOptions(const WebGLContextOptions&) = default;
380
381 bool operator==(const WebGLContextOptions&) const;
382 bool operator!=(const WebGLContextOptions& rhs) const {
383 return !(*this == rhs);
384 }
385 };
386
387 // -
388
389 template <typename _T>
390 struct avec2 {
391 using T = _T;
392
393 T x = T();
394 T y = T();
395
396 template <typename U, typename V>
Fromavec2397 static Maybe<avec2> From(const U _x, const V _y) {
398 const auto x = CheckedInt<T>(_x);
399 const auto y = CheckedInt<T>(_y);
400 if (!x.isValid() || !y.isValid()) return {};
401 return Some(avec2(x.value(), y.value()));
402 }
403
404 template <typename U>
Fromavec2405 static auto From(const U& val) {
406 return From(val.x, val.y);
407 }
408 template <typename U>
FromSizeavec2409 static auto FromSize(const U& val) {
410 return From(val.width, val.height);
411 }
412
413 avec2() = default;
avec2avec2414 avec2(const T _x, const T _y) : x(_x), y(_y) {}
415
416 bool operator==(const avec2& rhs) const { return x == rhs.x && y == rhs.y; }
417 bool operator!=(const avec2& rhs) const { return !(*this == rhs); }
418
419 #define _(OP) \
420 avec2 operator OP(const avec2& rhs) const { \
421 return {x OP rhs.x, y OP rhs.y}; \
422 } \
423 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
424
425 _(+)
426 _(-)
427 _(*)
428 _(/)
429
430 #undef _
431
Clampavec2432 avec2 Clamp(const avec2& min, const avec2& max) const {
433 return {mozilla::Clamp(x, min.x, max.x), mozilla::Clamp(y, min.y, max.y)};
434 }
435
436 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
437 // helper.
ClampMinMaxavec2438 avec2 ClampMinMax(const avec2& min, const avec2& max) const {
439 const auto ClampScalar = [](const T v, const T min, const T max) {
440 return std::max(min, std::min(v, max));
441 };
442 return {ClampScalar(x, min.x, max.x), ClampScalar(y, min.y, max.y)};
443 }
444
445 template <typename U>
StaticCastavec2446 U StaticCast() const {
447 return {static_cast<typename U::T>(x), static_cast<typename U::T>(y)};
448 }
449 };
450
451 template <typename T>
MinExtents(const avec2<T> & a,const avec2<T> & b)452 avec2<T> MinExtents(const avec2<T>& a, const avec2<T>& b) {
453 return {std::min(a.x, b.x), std::min(a.y, b.y)};
454 }
455
456 template <typename T>
MaxExtents(const avec2<T> & a,const avec2<T> & b)457 avec2<T> MaxExtents(const avec2<T>& a, const avec2<T>& b) {
458 return {std::max(a.x, b.x), std::max(a.y, b.y)};
459 }
460
461 // -
462
463 template <typename _T>
464 struct avec3 {
465 using T = _T;
466
467 T x = T();
468 T y = T();
469 T z = T();
470
471 template <typename U, typename V>
Fromavec3472 static Maybe<avec3> From(const U _x, const V _y, const V _z) {
473 const auto x = CheckedInt<T>(_x);
474 const auto y = CheckedInt<T>(_y);
475 const auto z = CheckedInt<T>(_z);
476 if (!x.isValid() || !y.isValid() || !z.isValid()) return {};
477 return Some(avec3(x.value(), y.value(), z.value()));
478 }
479
480 template <typename U>
Fromavec3481 static auto From(const U& val) {
482 return From(val.x, val.y, val.z);
483 }
484
485 avec3() = default;
avec3avec3486 avec3(const T _x, const T _y, const T _z) : x(_x), y(_y), z(_z) {}
487
488 bool operator==(const avec3& rhs) const {
489 return x == rhs.x && y == rhs.y && z == rhs.z;
490 }
491 bool operator!=(const avec3& rhs) const { return !(*this == rhs); }
492 };
493
494 typedef avec2<int32_t> ivec2;
495 typedef avec3<int32_t> ivec3;
496 typedef avec2<uint32_t> uvec2;
497 typedef avec3<uint32_t> uvec3;
498
AsVec(const gfx::IntSize & s)499 inline ivec2 AsVec(const gfx::IntSize& s) { return {s.width, s.height}; }
500
501 // -
502
503 namespace webgl {
504
505 struct PackingInfo final {
506 GLenum format = 0;
507 GLenum type = 0;
508
509 bool operator<(const PackingInfo& x) const {
510 if (format != x.format) return format < x.format;
511
512 return type < x.type;
513 }
514
515 bool operator==(const PackingInfo& x) const {
516 return (format == x.format && type == x.type);
517 }
518 };
519
520 struct DriverUnpackInfo final {
521 GLenum internalFormat = 0;
522 GLenum unpackFormat = 0;
523 GLenum unpackType = 0;
524
ToPackingfinal525 PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
526 };
527
528 struct PixelPackState final {
529 uint32_t alignment = 4;
530 uint32_t rowLength = 0;
531 uint32_t skipRows = 0;
532 uint32_t skipPixels = 0;
533 };
534
535 struct ReadPixelsDesc final {
536 ivec2 srcOffset;
537 uvec2 size;
538 PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
539 PixelPackState packState;
540 };
541
542 // -
543
544 template <typename E>
545 class EnumMask {
546 public:
547 uint64_t mBits = 0;
548
549 private:
550 struct BitRef final {
551 EnumMask& bits;
552 const uint64_t mask;
553
554 explicit operator bool() const { return bits.mBits & mask; }
555
556 auto& operator=(const bool val) {
557 if (val) {
558 bits.mBits |= mask;
559 } else {
560 bits.mBits &= ~mask;
561 }
562 return *this;
563 }
564 };
565
Mask(const E i)566 uint64_t Mask(const E i) const {
567 return uint64_t{1} << static_cast<uint64_t>(i);
568 }
569
570 public:
571 BitRef operator[](const E i) { return {*this, Mask(i)}; }
572 bool operator[](const E i) const { return mBits & Mask(i); }
573 };
574
575 class ExtensionBits : public EnumMask<WebGLExtensionID> {};
576
577 // -
578
579 enum class ContextLossReason : uint8_t {
580 None,
581 Manual,
582 Guilty,
583 };
584
ReadContextLossReason(const uint8_t val,ContextLossReason * const out)585 inline bool ReadContextLossReason(const uint8_t val,
586 ContextLossReason* const out) {
587 if (val > static_cast<uint8_t>(ContextLossReason::Guilty)) {
588 return false;
589 }
590 *out = static_cast<ContextLossReason>(val);
591 return true;
592 }
593
594 // -
595
596 struct InitContextDesc final {
597 bool isWebgl2 = false;
598 bool resistFingerprinting = false;
599 uvec2 size = {};
600 WebGLContextOptions options;
601 uint32_t principalKey = 0;
602 };
603
604 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs = 4;
605
606 struct Limits final {
607 ExtensionBits supportedExtensions;
608
609 // WebGL 1
610 uint32_t maxTexUnits = 0;
611 uint32_t maxTex2dSize = 0;
612 uint32_t maxTexCubeSize = 0;
613 uint32_t maxVertexAttribs = 0;
614 uint32_t maxViewportDim = 0;
615 std::array<float, 2> pointSizeRange = {{1, 1}};
616 std::array<float, 2> lineWidthRange = {{1, 1}};
617
618 // WebGL 2
619 uint32_t maxTexArrayLayers = 0;
620 uint32_t maxTex3dSize = 0;
621 uint32_t maxUniformBufferBindings = 0;
622 uint32_t uniformBufferOffsetAlignment = 0;
623
624 // Exts
625 bool astcHdr = false;
626 uint32_t maxColorDrawBuffers = 1;
627 uint64_t queryCounterBitsTimeElapsed = 0;
628 uint64_t queryCounterBitsTimestamp = 0;
629 uint32_t maxMultiviewLayers = 0;
630 };
631
632 struct InitContextResult final {
633 std::string error;
634 WebGLContextOptions options;
635 webgl::Limits limits;
636 EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
637 };
638
639 // -
640
641 struct ErrorInfo final {
642 GLenum type;
643 std::string info;
644 };
645
646 struct ShaderPrecisionFormat final {
647 GLint rangeMin = 0;
648 GLint rangeMax = 0;
649 GLint precision = 0;
650 };
651
652 // -
653
654 enum class LossStatus {
655 Ready,
656
657 Lost,
658 LostForever,
659 LostManually,
660 };
661
662 // -
663
664 struct CompileResult final {
665 bool pending = true;
666 nsCString log;
667 nsCString translatedSource;
668 bool success = false;
669 };
670
671 // -
672
673 struct OpaqueFramebufferOptions final {
674 bool depthStencil = true;
675 bool antialias = true;
676 uint32_t width = 0;
677 uint32_t height = 0;
678 };
679
680 // -
681
682 struct ActiveInfo {
683 GLenum elemType = 0; // `type`
684 uint32_t elemCount = 0; // `size`
685 std::string name;
686 };
687
688 struct ActiveAttribInfo final : public ActiveInfo {
689 int32_t location = -1;
690 AttribBaseType baseType = AttribBaseType::Float;
691 };
692
693 struct ActiveUniformInfo final : public ActiveInfo {
694 std::unordered_map<uint32_t, uint32_t>
695 locByIndex; // Uniform array locations are sparse.
696 int32_t block_index = -1;
697 int32_t block_offset = -1; // In block, offset.
698 int32_t block_arrayStride = -1;
699 int32_t block_matrixStride = -1;
700 bool block_isRowMajor = false;
701 };
702
703 struct ActiveUniformBlockInfo final {
704 std::string name;
705 // BLOCK_BINDING is dynamic state
706 uint32_t dataSize = 0;
707 std::vector<uint32_t> activeUniformIndices;
708 bool referencedByVertexShader = false;
709 bool referencedByFragmentShader = false;
710 };
711
712 struct LinkActiveInfo final {
713 std::vector<ActiveAttribInfo> activeAttribs;
714 std::vector<ActiveUniformInfo> activeUniforms;
715 std::vector<ActiveUniformBlockInfo> activeUniformBlocks;
716 std::vector<ActiveInfo> activeTfVaryings;
717 };
718
719 struct LinkResult final {
720 bool pending = true;
721 nsCString log;
722 bool success = false;
723 LinkActiveInfo active;
724 GLenum tfBufferMode = 0;
725 };
726
727 // -
728
729 /// 4x32-bit primitives, with a type tag.
730 struct TypedQuad final {
731 alignas(alignof(float)) uint8_t data[4 * sizeof(float)] = {};
732 webgl::AttribBaseType type = webgl::AttribBaseType::Float;
733 };
734
735 /// [1-16]x32-bit primitives, with a type tag.
736 struct GetUniformData final {
737 alignas(alignof(float)) uint8_t data[4 * 4 * sizeof(float)] = {};
738 GLenum type = 0;
739 };
740
741 struct FrontBufferSnapshotIpc final {
742 uvec2 surfSize = {};
743 mozilla::ipc::Shmem shmem = {};
744 };
745
746 struct ReadPixelsResult {
747 gfx::IntRect subrect = {};
748 size_t byteStride = 0;
749 };
750
751 struct ReadPixelsResultIpc final : public ReadPixelsResult {
752 mozilla::ipc::Shmem shmem = {};
753 };
754
755 struct VertAttribPointerDesc final {
756 bool intFunc = false;
757 uint8_t channels = 4;
758 bool normalized = false;
759 uint8_t byteStrideOrZero = 0;
760 GLenum type = LOCAL_GL_FLOAT;
761 uint64_t byteOffset = 0;
762 };
763
764 struct VertAttribPointerCalculated final {
765 uint8_t byteSize = 4 * 4;
766 uint8_t byteStride = 4 * 4; // at-most 255
767 webgl::AttribBaseType baseType = webgl::AttribBaseType::Float;
768 };
769
770 } // namespace webgl
771
772 // return value for the InitializeCanvasRenderer message
773 struct ICRData {
774 gfx::IntSize size;
775 bool hasAlpha;
776 bool isPremultAlpha;
777 };
778
779 /**
780 * Represents a block of memory that it may or may not own. The
781 * inner data type must be trivially copyable by memcpy.
782 */
783 template <typename T = uint8_t>
784 class RawBuffer final {
785 const T* mBegin = nullptr;
786 size_t mLen = 0;
787 UniqueBuffer mOwned;
788
789 public:
790 using ElementType = T;
791
792 /**
793 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
794 */
795 explicit RawBuffer(const Range<const T>& data, UniqueBuffer&& owned = {})
796 : mBegin(data.begin().get()),
797 mLen(data.length()),
798 mOwned(std::move(owned)) {}
799
RawBuffer(const size_t len)800 explicit RawBuffer(const size_t len) : mLen(len) {}
801
802 ~RawBuffer() = default;
803
Data()804 Range<const T> Data() const { return {mBegin, mLen}; }
begin()805 const auto& begin() const { return mBegin; }
size()806 const auto& size() const { return mLen; }
807
Shrink(const size_t newLen)808 void Shrink(const size_t newLen) {
809 if (mLen <= newLen) return;
810 mLen = newLen;
811 }
812
813 RawBuffer() = default;
814
815 RawBuffer(const RawBuffer&) = delete;
816 RawBuffer& operator=(const RawBuffer&) = delete;
817
818 RawBuffer(RawBuffer&&) = default;
819 RawBuffer& operator=(RawBuffer&&) = default;
820 };
821
822 // -
823
824 struct CopyableRange final : public Range<const uint8_t> {};
825
826 // -
827
828 // clang-format off
829
830 #define FOREACH_ID(X) \
831 X(FuncScopeIdError) \
832 X(compressedTexImage2D) \
833 X(compressedTexImage3D) \
834 X(compressedTexSubImage2D) \
835 X(compressedTexSubImage3D) \
836 X(copyTexSubImage2D) \
837 X(copyTexSubImage3D) \
838 X(drawArrays) \
839 X(drawArraysInstanced) \
840 X(drawElements) \
841 X(drawElementsInstanced) \
842 X(drawRangeElements) \
843 X(renderbufferStorage) \
844 X(renderbufferStorageMultisample) \
845 X(texImage2D) \
846 X(texImage3D) \
847 X(TexStorage2D) \
848 X(TexStorage3D) \
849 X(texSubImage2D) \
850 X(texSubImage3D) \
851 X(vertexAttrib1f) \
852 X(vertexAttrib1fv) \
853 X(vertexAttrib2f) \
854 X(vertexAttrib2fv) \
855 X(vertexAttrib3f) \
856 X(vertexAttrib3fv) \
857 X(vertexAttrib4f) \
858 X(vertexAttrib4fv) \
859 X(vertexAttribI4i) \
860 X(vertexAttribI4iv) \
861 X(vertexAttribI4ui) \
862 X(vertexAttribI4uiv) \
863 X(vertexAttribIPointer) \
864 X(vertexAttribPointer)
865
866 // clang-format on
867
868 enum class FuncScopeId {
869 #define _(X) X,
870 FOREACH_ID(_)
871 #undef _
872 };
873
874 static constexpr const char* const FUNCSCOPE_NAME_BY_ID[] = {
875 #define _(X) #X,
876 FOREACH_ID(_)
877 #undef _
878 };
879
880 #undef FOREACH_ID
881
GetFuncScopeName(const FuncScopeId id)882 inline auto GetFuncScopeName(const FuncScopeId id) {
883 return FUNCSCOPE_NAME_BY_ID[static_cast<size_t>(id)];
884 }
885
886 // -
887
888 template <typename C, typename K>
889 inline auto MaybeFind(C& container, const K& key)
890 -> decltype(&(container.find(key)->second)) {
891 const auto itr = container.find(key);
892 if (itr == container.end()) return nullptr;
893 return &(itr->second);
894 }
895
896 template <typename C, typename K>
897 inline typename C::mapped_type Find(
898 const C& container, const K& key,
899 const typename C::mapped_type notFound = {}) {
900 const auto itr = container.find(key);
901 if (itr == container.end()) return notFound;
902 return itr->second;
903 }
904
905 // -
906
907 template <typename T, typename U>
MaybeAs(const U val)908 inline Maybe<T> MaybeAs(const U val) {
909 const auto checked = CheckedInt<T>(val);
910 if (!checked.isValid()) return {};
911 return Some(checked.value());
912 }
913
914 // -
915
ImageToTexTarget(const GLenum imageTarget)916 inline GLenum ImageToTexTarget(const GLenum imageTarget) {
917 switch (imageTarget) {
918 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
919 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
920 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
921 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
922 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
923 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
924 return LOCAL_GL_TEXTURE_CUBE_MAP;
925 default:
926 return imageTarget;
927 }
928 }
929
IsTexTarget3D(const GLenum texTarget)930 inline bool IsTexTarget3D(const GLenum texTarget) {
931 switch (texTarget) {
932 case LOCAL_GL_TEXTURE_2D_ARRAY:
933 case LOCAL_GL_TEXTURE_3D:
934 return true;
935
936 default:
937 return false;
938 }
939 }
940
941 // -
942
943 namespace dom {
944 class Element;
945 class ImageBitmap;
946 class ImageData;
947 } // namespace dom
948
949 struct TexImageSource {
950 const dom::ArrayBufferView* mView = nullptr;
951 GLuint mViewElemOffset = 0;
952 GLuint mViewElemLengthOverride = 0;
953
954 const WebGLintptr* mPboOffset = nullptr;
955
956 const dom::ImageBitmap* mImageBitmap = nullptr;
957 const dom::ImageData* mImageData = nullptr;
958
959 const dom::Element* mDomElem = nullptr;
960 ErrorResult* mOut_error = nullptr;
961 };
962
963 struct WebGLPixelStore final {
964 uint32_t mUnpackImageHeight = 0;
965 uint32_t mUnpackSkipImages = 0;
966 uint32_t mUnpackRowLength = 0;
967 uint32_t mUnpackSkipRows = 0;
968 uint32_t mUnpackSkipPixels = 0;
969 uint32_t mUnpackAlignment = 4;
970 GLenum mColorspaceConversion =
971 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL;
972 bool mFlipY = false;
973 bool mPremultiplyAlpha = false;
974 bool mRequireFastPath = false;
975
AssertDefaultfinal976 static void AssertDefault(gl::GLContext& gl, const bool isWebgl2) {
977 WebGLPixelStore expected;
978 MOZ_ASSERT(expected.AssertCurrent(gl, isWebgl2));
979 Unused << expected;
980 }
981
982 void Apply(gl::GLContext&, bool isWebgl2, const uvec3& uploadSize) const;
983 bool AssertCurrent(gl::GLContext&, bool isWebgl2) const;
984
ForUseWithfinal985 WebGLPixelStore ForUseWith(const GLenum target, const uvec3& uploadSize,
986 const Maybe<uvec2>& structuredSrcSize) const {
987 auto ret = *this;
988
989 if (!IsTexTarget3D(target)) {
990 ret.mUnpackSkipImages = 0;
991 ret.mUnpackImageHeight = 0;
992 }
993
994 if (structuredSrcSize) {
995 ret.mUnpackRowLength = structuredSrcSize->x;
996 }
997
998 if (!ret.mUnpackRowLength) {
999 ret.mUnpackRowLength = uploadSize.x;
1000 }
1001 if (!ret.mUnpackImageHeight) {
1002 ret.mUnpackImageHeight = uploadSize.y;
1003
1004 if (!IsTexTarget3D(target)) {
1005 // 2D targets don't enforce skipRows+height<=imageHeight.
1006 ret.mUnpackImageHeight += ret.mUnpackSkipRows;
1007 }
1008 }
1009
1010 return ret;
1011 }
1012
UsedPixelsPerRowfinal1013 CheckedInt<size_t> UsedPixelsPerRow(const uvec3& size) const {
1014 if (!size.x || !size.y || !size.z) return 0;
1015 return CheckedInt<size_t>(mUnpackSkipPixels) + size.x;
1016 }
1017
FullRowsNeededfinal1018 CheckedInt<size_t> FullRowsNeeded(const uvec3& size) const {
1019 if (!size.x || !size.y || !size.z) return 0;
1020
1021 // The spec guarantees:
1022 // * SKIP_PIXELS + width <= ROW_LENGTH.
1023 // * SKIP_ROWS + height <= IMAGE_HEIGHT.
1024 MOZ_ASSERT(mUnpackImageHeight);
1025 auto skipFullRows =
1026 CheckedInt<size_t>(mUnpackSkipImages) * mUnpackImageHeight;
1027 skipFullRows += mUnpackSkipRows;
1028
1029 // Full rows in the final image, excluding the tail.
1030 auto usedFullRows = CheckedInt<size_t>(size.z - 1) * mUnpackImageHeight;
1031 usedFullRows += size.y - 1;
1032
1033 return skipFullRows + usedFullRows;
1034 }
1035 };
1036
1037 struct TexImageData final {
1038 WebGLPixelStore unpackState;
1039
1040 Maybe<uint64_t> pboOffset;
1041
1042 RawBuffer<> data;
1043
1044 const dom::Element* domElem = nullptr;
1045 ErrorResult* out_domElemError = nullptr;
1046 };
1047
1048 namespace webgl {
1049
1050 struct TexUnpackBlobDesc final {
1051 GLenum imageTarget = LOCAL_GL_TEXTURE_2D;
1052 uvec3 size;
1053 gfxAlphaType srcAlphaType = gfxAlphaType::NonPremult;
1054
1055 Maybe<RawBuffer<>> cpuData;
1056 Maybe<uint64_t> pboOffset;
1057
1058 uvec2 imageSize;
1059 RefPtr<layers::Image> image;
1060 Maybe<layers::SurfaceDescriptor> sd;
1061 RefPtr<gfx::DataSourceSurface> dataSurf;
1062
1063 WebGLPixelStore unpacking;
1064
1065 void Shrink(const webgl::PackingInfo&);
1066 };
1067
1068 } // namespace webgl
1069
1070 // ---------------------------------------
1071 // MakeRange
1072
1073 template <typename T, size_t N>
MakeRange(T (& arr)[N])1074 inline Range<const T> MakeRange(T (&arr)[N]) {
1075 return {arr, N};
1076 }
1077
1078 template <typename T>
MakeRange(const dom::Sequence<T> & seq)1079 inline Range<const T> MakeRange(const dom::Sequence<T>& seq) {
1080 return {seq.Elements(), seq.Length()};
1081 }
1082
1083 template <typename T>
MakeRange(const RawBuffer<T> & from)1084 inline Range<const T> MakeRange(const RawBuffer<T>& from) {
1085 return from.Data();
1086 }
1087
1088 // abv = ArrayBufferView
1089 template <typename T>
1090 inline auto MakeRangeAbv(const T& abv)
1091 -> Range<const typename T::element_type> {
1092 abv.ComputeState();
1093 return {abv.Data(), abv.Length()};
1094 }
1095
1096 // -
1097
1098 constexpr auto kUniversalAlignment = alignof(std::max_align_t);
1099
1100 template <typename T>
AlignmentOffset(const size_t alignment,const T posOrPtr)1101 inline size_t AlignmentOffset(const size_t alignment, const T posOrPtr) {
1102 MOZ_ASSERT(alignment);
1103 const auto begin = reinterpret_cast<uintptr_t>(posOrPtr);
1104 const auto wholeMultiples = (begin + (alignment - 1)) / alignment;
1105 const auto aligned = wholeMultiples * alignment;
1106 return aligned - begin;
1107 }
1108
1109 template <typename T>
ByteSize(const Range<T> & range)1110 inline size_t ByteSize(const Range<T>& range) {
1111 return range.length() * sizeof(T);
1112 }
1113
1114 Maybe<Range<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView& view,
1115 GLuint elemOffset,
1116 GLuint elemCountOverride);
1117
1118 // -
1119
1120 template <typename T>
RawBufferView(const Range<T> & range)1121 RawBuffer<T> RawBufferView(const Range<T>& range) {
1122 return RawBuffer<T>{range};
1123 }
1124
1125 // -
1126
1127 Maybe<webgl::ErrorInfo> CheckBindBufferRange(
1128 const GLenum target, const GLuint index, const bool isBuffer,
1129 const uint64_t offset, const uint64_t size, const webgl::Limits& limits);
1130
1131 Maybe<webgl::ErrorInfo> CheckFramebufferAttach(const GLenum bindImageTarget,
1132 const GLenum curTexTarget,
1133 const uint32_t mipLevel,
1134 const uint32_t zLayerBase,
1135 const uint32_t zLayerCount,
1136 const webgl::Limits& limits);
1137
1138 Result<webgl::VertAttribPointerCalculated, webgl::ErrorInfo>
1139 CheckVertexAttribPointer(bool isWebgl2, const webgl::VertAttribPointerDesc&);
1140
1141 uint8_t ElemTypeComponents(GLenum elemType);
1142
ToString(const nsACString & text)1143 inline std::string ToString(const nsACString& text) {
1144 return {text.BeginReading(), text.Length()};
1145 }
1146
Memcpy(const RangedPtr<uint8_t> & destBytes,const RangedPtr<const uint8_t> & srcBytes,const size_t byteSize)1147 inline void Memcpy(const RangedPtr<uint8_t>& destBytes,
1148 const RangedPtr<const uint8_t>& srcBytes,
1149 const size_t byteSize) {
1150 // Trigger range asserts
1151 (void)(srcBytes + byteSize);
1152 (void)(destBytes + byteSize);
1153
1154 memcpy(destBytes.get(), srcBytes.get(), byteSize);
1155 }
1156
1157 // -
1158
1159 } // namespace mozilla
1160
1161 #endif
1162