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