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/. */
11 #include <string_view>
13 #include <type_traits>
14 #include <unordered_map>
17 #include "GLContextTypes.h"
19 #include "ImageContainer.h"
20 #include "mozilla/Casting.h"
21 #include "mozilla/CheckedInt.h"
22 #include "mozilla/EnumTypeTraits.h"
23 #include "mozilla/MathAlgorithms.h"
24 #include "mozilla/Range.h"
25 #include "mozilla/RefCounted.h"
26 #include "mozilla/Result.h"
27 #include "mozilla/ResultVariant.h"
28 #include "mozilla/Span.h"
29 #include "mozilla/TypedEnumBits.h"
30 #include "mozilla/gfx/2D.h"
31 #include "mozilla/gfx/BuildConstants.h"
32 #include "mozilla/gfx/Logging.h"
33 #include "mozilla/gfx/Point.h"
34 #include "mozilla/gfx/Rect.h"
35 #include "mozilla/ipc/Shmem.h"
36 #include "mozilla/layers/LayersSurfaces.h"
41 #include "mozilla/dom/WebGLRenderingContextBinding.h"
42 #include "mozilla/ipc/SharedMemoryBasic.h"
43 #include "TiedFields.h"
45 // Manual reflection of WebIDL typedefs that are different from their
46 // OpenGL counterparts.
47 using WebGLsizeiptr
= int64_t;
48 using WebGLintptr
= int64_t;
49 using WebGLboolean
= bool;
55 class GLContext
; // This is going to be needed a lot.
59 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
62 template <typename DestT
>
63 class ForbidNarrowing final
{
67 template <typename SrcT
>
68 MOZ_IMPLICIT
ForbidNarrowing(SrcT val
) : mVal(val
) {
70 std::numeric_limits
<SrcT
>::min() >= std::numeric_limits
<DestT
>::min(),
71 "SrcT must be narrower than DestT.");
73 std::numeric_limits
<SrcT
>::max() <= std::numeric_limits
<DestT
>::max(),
74 "SrcT must be narrower than DestT.");
77 explicit operator DestT() const { return mVal
; }
80 inline void* malloc(const ForbidNarrowing
<size_t> s
) {
81 return ::malloc(size_t(s
));
84 inline void* calloc(const ForbidNarrowing
<size_t> n
,
85 const ForbidNarrowing
<size_t> size
) {
86 return ::calloc(size_t(n
), size_t(size
));
91 // TODO: Remove this now-mere-alias.
92 template <typename From
>
93 inline auto AutoAssertCast(const From val
) {
94 return LazyAssertedCast(val
);
97 const char* GetEnumName(GLenum val
, const char* defaultRet
= "<unknown>");
98 std::string
EnumString(GLenum val
);
101 template <typename T
>
102 struct QueueParamTraits
;
103 class TexUnpackBytes
;
104 class TexUnpackImage
;
105 class TexUnpackSurface
;
108 class ClientWebGLContext
;
109 struct WebGLTexPboOffset
;
112 class WebGLFramebuffer
;
115 class WebGLRenderbuffer
;
120 class WebGLTransformFeedback
;
121 class WebGLVertexArray
;
125 class VRefCounted
: public RefCounted
<VRefCounted
> {
127 virtual ~VRefCounted() = default;
129 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
130 virtual const char* typeName() const = 0;
131 virtual size_t typeSize() const = 0;
138 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
139 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
140 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
141 * desktop OpenGL does not allow that.
143 enum class WebGLVertexAttrib0Status
: uint8_t {
144 Default
, // default status - no emulation needed
145 EmulatedUninitializedArray
, // need an artificial attrib 0 array, but
146 // contents may be left uninitialized
147 EmulatedInitializedArray
// need an artificial attrib 0 array, and contents
148 // must be initialized
152 * The formats that may participate, either as source or destination formats,
153 * in WebGL texture conversions. This includes:
154 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
155 * - additional formats provided by extensions, e.g. RGB32F
156 * - additional source formats, depending on browser details, used when
157 * uploading textures from DOM elements. See gfxImageSurface::Format().
159 enum class WebGLTexelFormat
: uint8_t {
160 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
163 // common value for formats for which format conversions are not supported
164 FormatNotSupportingAnyConversion
,
165 // dummy pseudo-format meaning "use the other format".
166 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
167 // is implicitly treated as being RGB8 itself.
171 A16F
, // OES_texture_half_float
172 A32F
, // OES_texture_float
174 R16F
, // OES_texture_half_float
175 R32F
, // OES_texture_float
178 RA16F
, // OES_texture_half_float
179 RA32F
, // OES_texture_float
187 RGB16F
, // OES_texture_half_float
188 RGB32F
, // OES_texture_float
193 RGBA16F
, // OES_texture_half_float
194 RGBA32F
, // OES_texture_float
195 // DOM element source only formats.
201 enum class WebGLTexImageFunc
: uint8_t {
210 enum class WebGLTexDimensions
: uint8_t { Tex2D
, Tex3D
};
212 // Please keep extensions in alphabetic order.
213 enum class WebGLExtensionID
: uint8_t {
214 ANGLE_instanced_arrays
,
216 EXT_color_buffer_float
,
217 EXT_color_buffer_half_float
,
218 EXT_disjoint_timer_query
,
221 EXT_shader_texture_lod
,
223 EXT_texture_compression_bptc
,
224 EXT_texture_compression_rgtc
,
225 EXT_texture_filter_anisotropic
,
228 OES_draw_buffers_indexed
,
229 OES_element_index_uint
,
230 OES_fbo_render_mipmap
,
231 OES_standard_derivatives
,
233 OES_texture_float_linear
,
234 OES_texture_half_float
,
235 OES_texture_half_float_linear
,
236 OES_vertex_array_object
,
238 WEBGL_color_buffer_float
,
239 WEBGL_compressed_texture_astc
,
240 WEBGL_compressed_texture_etc
,
241 WEBGL_compressed_texture_etc1
,
242 WEBGL_compressed_texture_pvrtc
,
243 WEBGL_compressed_texture_s3tc
,
244 WEBGL_compressed_texture_s3tc_srgb
,
245 WEBGL_debug_renderer_info
,
249 WEBGL_explicit_present
,
251 WEBGL_provoking_vertex
,
255 class UniqueBuffer final
{
256 // Like UniquePtr<>, but for void* and malloc/calloc/free.
257 void* mBuffer
= nullptr;
260 static inline UniqueBuffer
Take(void* buffer
) {
262 ret
.mBuffer
= buffer
;
266 UniqueBuffer() = default;
268 ~UniqueBuffer() { reset(); }
270 UniqueBuffer(UniqueBuffer
&& rhs
) { *this = std::move(rhs
); }
272 UniqueBuffer
& operator=(UniqueBuffer
&& rhs
) {
274 this->mBuffer
= rhs
.mBuffer
;
275 rhs
.mBuffer
= nullptr;
279 explicit operator bool() const { return bool(mBuffer
); }
281 void* get() const { return mBuffer
; }
284 // Believe it or not, when `free` unconditional, it was showing up
285 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
295 struct FormatUsageInfo
;
297 static constexpr GLenum kErrorPerfWarning
= 0x10001;
299 struct SampleableInfo final
{
300 const char* incompleteReason
= nullptr;
302 const webgl::FormatUsageInfo
* usage
= nullptr;
303 bool isDepthTexCompare
= false;
305 bool IsComplete() const { return bool(levels
); }
308 enum class AttribBaseType
: uint8_t {
309 Boolean
, // Can convert from anything.
310 Float
, // Also includes NormU?Int
314 webgl::AttribBaseType
ToAttribBaseType(GLenum
);
315 const char* ToString(AttribBaseType
);
317 enum class UniformBaseType
: uint8_t {
322 const char* ToString(UniformBaseType
);
324 using ObjectId
= uint64_t;
326 enum class BufferKind
: uint8_t {
336 struct FloatOrInt final
// For TexParameter[fi] and friends.
338 bool isFloat
= false;
339 uint8_t padding
[3] = {};
343 explicit FloatOrInt(GLint x
= 0) : isFloat(false), f(x
), i(x
) {}
345 explicit FloatOrInt(GLfloat x
) : isFloat(true), f(x
), i(roundf(x
)) {}
347 auto MutTiedFields() { return std::tie(isFloat
, padding
, f
, i
); }
352 struct WebGLContextOptions final
{
355 bool stencil
= false;
356 bool premultipliedAlpha
= true;
358 bool antialias
= true;
359 bool preserveDrawingBuffer
= false;
360 bool failIfMajorPerformanceCaveat
= false;
361 bool xrCompatible
= false;
363 dom::WebGLPowerPreference powerPreference
=
364 dom::WebGLPowerPreference::Default
;
365 bool ignoreColorSpace
= true;
366 dom::PredefinedColorSpace colorSpace
= dom::PredefinedColorSpace::Srgb
;
367 bool shouldResistFingerprinting
= true;
369 bool enableDebugRendererInfo
= false;
371 auto MutTiedFields() {
380 preserveDrawingBuffer
,
381 failIfMajorPerformanceCaveat
,
387 shouldResistFingerprinting
,
389 enableDebugRendererInfo
);
395 WebGLContextOptions();
396 WebGLContextOptions(const WebGLContextOptions
&) = default;
398 using Self
= WebGLContextOptions
;
399 friend bool operator==(const Self
& a
, const Self
& b
) {
400 return TiedFields(a
) == TiedFields(b
);
402 friend bool operator!=(const Self
& a
, const Self
& b
) { return !(a
== b
); }
407 inline ColorSpace2
ToColorSpace2(const dom::PredefinedColorSpace cs
) {
409 case dom::PredefinedColorSpace::Srgb
:
410 return ColorSpace2::SRGB
;
411 case dom::PredefinedColorSpace::Display_p3
:
412 return ColorSpace2::DISPLAY_P3
;
414 MOZ_CRASH("Exhaustive switch");
421 template <typename _T
>
428 auto MutTiedFields() { return std::tie(x
, y
); }
430 template <typename U
, typename V
>
431 static Maybe
<avec2
> From(const U _x
, const V _y
) {
432 const auto x
= CheckedInt
<T
>(_x
);
433 const auto y
= CheckedInt
<T
>(_y
);
434 if (!x
.isValid() || !y
.isValid()) return {};
435 return Some(avec2(x
.value(), y
.value()));
438 template <typename U
>
439 static auto From(const U
& val
) {
440 return From(val
.x
, val
.y
);
442 template <typename U
>
443 static auto FromSize(const U
& val
) {
444 return From(val
.width
, val
.height
);
448 avec2(const T _x
, const T _y
) : x(_x
), y(_y
) {}
450 bool operator==(const avec2
& rhs
) const { return x
== rhs
.x
&& y
== rhs
.y
; }
451 bool operator!=(const avec2
& rhs
) const { return !(*this == rhs
); }
454 avec2 operator OP(const avec2& rhs) const { \
455 return {x OP rhs.x, y OP rhs.y}; \
457 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
466 avec2
Clamp(const avec2
& min
, const avec2
& max
) const {
467 return {mozilla::Clamp(x
, min
.x
, max
.x
), mozilla::Clamp(y
, min
.y
, max
.y
)};
470 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
472 avec2
ClampMinMax(const avec2
& min
, const avec2
& max
) const {
473 const auto ClampScalar
= [](const T v
, const T min
, const T max
) {
474 return std::max(min
, std::min(v
, max
));
476 return {ClampScalar(x
, min
.x
, max
.x
), ClampScalar(y
, min
.y
, max
.y
)};
479 template <typename U
>
480 U
StaticCast() const {
481 return {static_cast<typename
U::T
>(x
), static_cast<typename
U::T
>(y
)};
485 template <typename T
>
486 avec2
<T
> MinExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
487 return {std::min(a
.x
, b
.x
), std::min(a
.y
, b
.y
)};
490 template <typename T
>
491 avec2
<T
> MaxExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
492 return {std::max(a
.x
, b
.x
), std::max(a
.y
, b
.y
)};
497 template <typename _T
>
505 auto MutTiedFields() { return std::tie(x
, y
, z
); }
507 template <typename U
, typename V
>
508 static Maybe
<avec3
> From(const U _x
, const V _y
, const V _z
) {
509 const auto x
= CheckedInt
<T
>(_x
);
510 const auto y
= CheckedInt
<T
>(_y
);
511 const auto z
= CheckedInt
<T
>(_z
);
512 if (!x
.isValid() || !y
.isValid() || !z
.isValid()) return {};
513 return Some(avec3(x
.value(), y
.value(), z
.value()));
516 template <typename U
>
517 static auto From(const U
& val
) {
518 return From(val
.x
, val
.y
, val
.z
);
522 avec3(const T _x
, const T _y
, const T _z
) : x(_x
), y(_y
), z(_z
) {}
524 bool operator==(const avec3
& rhs
) const {
525 return x
== rhs
.x
&& y
== rhs
.y
&& z
== rhs
.z
;
527 bool operator!=(const avec3
& rhs
) const { return !(*this == rhs
); }
530 using ivec2
= avec2
<int32_t>;
531 using ivec3
= avec3
<int32_t>;
532 using uvec2
= avec2
<uint32_t>;
533 using uvec3
= avec3
<uint32_t>;
535 inline ivec2
AsVec(const gfx::IntSize
& s
) { return {s
.width
, s
.height
}; }
541 struct PackingInfo final
{
545 auto MutTiedFields() { return std::tie(format
, type
); }
547 using Self
= PackingInfo
;
548 friend bool operator<(const Self
& a
, const Self
& b
) {
549 return TiedFields(a
) < TiedFields(b
);
551 friend bool operator==(const Self
& a
, const Self
& b
) {
552 return TiedFields(a
) == TiedFields(b
);
556 friend T
& operator<<(T
& s
, const PackingInfo
& pi
) {
557 s
<< "PackingInfo{format: " << EnumString(pi
.format
)
558 << ", type: " << EnumString(pi
.type
) << "}";
563 struct DriverUnpackInfo final
{
564 GLenum internalFormat
= 0;
565 GLenum unpackFormat
= 0;
566 GLenum unpackType
= 0;
568 PackingInfo
ToPacking() const { return {unpackFormat
, unpackType
}; }
573 template <typename E
>
579 struct BitRef final
{
583 explicit operator bool() const { return bits
.mBits
& mask
; }
585 auto& operator=(const bool val
) {
595 uint64_t Mask(const E i
) const {
596 return uint64_t{1} << static_cast<uint64_t>(i
);
600 BitRef
operator[](const E i
) { return {*this, Mask(i
)}; }
601 bool operator[](const E i
) const { return mBits
& Mask(i
); }
605 auto MutTiedFields() { return std::tie(mBits
); }
608 using ExtensionBits
= EnumMask
<WebGLExtensionID
>;
612 enum class ContextLossReason
: uint8_t {
618 inline bool ReadContextLossReason(const uint8_t val
,
619 ContextLossReason
* const out
) {
620 if (val
> static_cast<uint8_t>(ContextLossReason::Guilty
)) {
623 *out
= static_cast<ContextLossReason
>(val
);
629 struct InitContextDesc final
{
630 bool isWebgl2
= false;
631 bool resistFingerprinting
= false;
632 std::array
<uint8_t, 2> _padding
;
633 uint32_t principalKey
= 0;
635 WebGLContextOptions options
;
636 std::array
<uint8_t, 3> _padding2
;
638 auto MutTiedFields() {
639 return std::tie(isWebgl2
, resistFingerprinting
, _padding
, principalKey
,
640 size
, options
, _padding2
);
644 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs
= 4;
646 struct Limits final
{
647 ExtensionBits supportedExtensions
;
650 uint32_t maxTexUnits
= 0;
651 uint32_t maxTex2dSize
= 0;
652 uint32_t maxTexCubeSize
= 0;
653 uint32_t maxVertexAttribs
= 0;
654 uint32_t maxViewportDim
= 0;
655 std::array
<float, 2> pointSizeRange
= {{1, 1}};
656 std::array
<float, 2> lineWidthRange
= {{1, 1}};
659 uint32_t maxTexArrayLayers
= 0;
660 uint32_t maxTex3dSize
= 0;
661 uint32_t maxUniformBufferBindings
= 0;
662 uint32_t uniformBufferOffsetAlignment
= 0;
665 bool astcHdr
= false;
666 std::array
<uint8_t, 3> _padding
;
667 uint32_t maxColorDrawBuffers
= 1;
668 uint32_t maxMultiviewLayers
= 0;
669 uint64_t queryCounterBitsTimeElapsed
= 0;
670 uint64_t queryCounterBitsTimestamp
= 0;
672 auto MutTiedFields() {
673 return std::tie(supportedExtensions
,
675 maxTexUnits
, maxTex2dSize
, maxTexCubeSize
, maxVertexAttribs
,
676 maxViewportDim
, pointSizeRange
, lineWidthRange
,
678 maxTexArrayLayers
, maxTex3dSize
, maxUniformBufferBindings
,
679 uniformBufferOffsetAlignment
,
681 astcHdr
, _padding
, maxColorDrawBuffers
, maxMultiviewLayers
,
682 queryCounterBitsTimeElapsed
, queryCounterBitsTimestamp
);
688 template <class T
, size_t PaddedSize
>
692 uint8_t padding
[PaddedSize
- sizeof(T
)] = {};
695 operator T
&() { return val
; }
696 operator const T
&() const { return val
; }
698 auto& operator=(const T
& rhs
) { return val
= rhs
; }
699 auto& operator=(T
&& rhs
) { return val
= std::move(rhs
); }
701 auto& operator*() { return val
; }
702 auto& operator*() const { return val
; }
703 auto operator->() { return &val
; }
704 auto operator->() const { return &val
; }
709 enum class OptionalRenderableFormatBits
: uint8_t {
713 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OptionalRenderableFormatBits
)
714 inline constexpr bool IsEnumCase(const OptionalRenderableFormatBits raw
) {
715 auto rawWithoutValidBits
= UnderlyingValue(raw
);
716 auto bit
= decltype(rawWithoutValidBits
){1};
718 switch (OptionalRenderableFormatBits
{bit
}) {
719 // -Werror=switch ensures exhaustive.
720 case OptionalRenderableFormatBits::RGB8
:
721 case OptionalRenderableFormatBits::SRGB8
:
722 rawWithoutValidBits
&= ~bit
;
727 return rawWithoutValidBits
== 0;
732 struct InitContextResult final
{
733 Padded
<std::string
, 32> error
; // MINGW 32-bit needs this padding.
734 WebGLContextOptions options
;
736 OptionalRenderableFormatBits optionalRenderableFormatBits
;
737 uint8_t _padding
= {};
739 EnumMask
<layers::SurfaceDescriptor::Type
> uploadableSdTypes
;
741 auto MutTiedFields() {
742 return std::tie(error
, options
, vendor
, optionalRenderableFormatBits
,
743 _padding
, limits
, uploadableSdTypes
);
749 struct ErrorInfo final
{
754 struct ShaderPrecisionFormat final
{
762 enum class LossStatus
{
772 struct CompileResult final
{
775 nsCString translatedSource
;
776 bool success
= false;
781 struct OpaqueFramebufferOptions final
{
782 bool depthStencil
= true;
783 bool antialias
= true;
784 std::array
<uint8_t, 2> _padding
;
788 auto MutTiedFields() {
789 return std::tie(depthStencil
, antialias
, _padding
, width
, height
);
795 struct SwapChainOptions final
{
796 layers::RemoteTextureId remoteTextureId
;
797 layers::RemoteTextureOwnerId remoteTextureOwnerId
;
799 bool forceAsyncPresent
= false;
800 // Pad to sizeof(u64):
801 uint16_t padding1
= 0;
802 uint32_t padding2
= 0;
804 auto MutTiedFields() {
805 return std::tie(remoteTextureId
, remoteTextureOwnerId
, bgra
,
806 forceAsyncPresent
, padding1
, padding2
);
813 GLenum elemType
= 0; // `type`
814 uint32_t elemCount
= 0; // `size`
818 struct ActiveAttribInfo final
: public ActiveInfo
{
819 int32_t location
= -1;
820 AttribBaseType baseType
= AttribBaseType::Float
;
823 struct ActiveUniformInfo final
: public ActiveInfo
{
824 std::unordered_map
<uint32_t, uint32_t>
825 locByIndex
; // Uniform array locations are sparse.
826 int32_t block_index
= -1;
827 int32_t block_offset
= -1; // In block, offset.
828 int32_t block_arrayStride
= -1;
829 int32_t block_matrixStride
= -1;
830 bool block_isRowMajor
= false;
833 struct ActiveUniformBlockInfo final
{
835 // BLOCK_BINDING is dynamic state
836 uint32_t dataSize
= 0;
837 std::vector
<uint32_t> activeUniformIndices
;
838 bool referencedByVertexShader
= false;
839 bool referencedByFragmentShader
= false;
842 struct LinkActiveInfo final
{
843 std::vector
<ActiveAttribInfo
> activeAttribs
;
844 std::vector
<ActiveUniformInfo
> activeUniforms
;
845 std::vector
<ActiveUniformBlockInfo
> activeUniformBlocks
;
846 std::vector
<ActiveInfo
> activeTfVaryings
;
849 struct LinkResult final
{
852 bool success
= false;
853 LinkActiveInfo active
;
854 GLenum tfBufferMode
= 0;
859 /// 4x32-bit primitives, with a type tag.
860 struct TypedQuad final
{
861 alignas(alignof(float)) std::array
<uint8_t, 4 * sizeof(float)> data
= {};
862 webgl::AttribBaseType type
= webgl::AttribBaseType::Float
;
863 uint8_t padding
[3] = {};
865 constexpr auto MutTiedFields() { return std::tie(data
, type
, padding
); }
868 /// [1-16]x32-bit primitives, with a type tag.
869 struct GetUniformData final
{
870 alignas(alignof(float)) uint8_t data
[4 * 4 * sizeof(float)] = {};
874 struct FrontBufferSnapshotIpc final
{
876 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
879 struct ReadPixelsResult
{
880 gfx::IntRect subrect
= {};
881 size_t byteStride
= 0;
884 struct ReadPixelsResultIpc final
: public ReadPixelsResult
{
885 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
888 struct VertAttribPointerDesc final
{
889 bool intFunc
= false;
890 uint8_t channels
= 4;
891 bool normalized
= false;
892 uint8_t byteStrideOrZero
= 0;
893 GLenum type
= LOCAL_GL_FLOAT
;
894 uint64_t byteOffset
= 0;
896 auto MutTiedFields() {
897 return std::tie(intFunc
, channels
, normalized
, byteStrideOrZero
, type
,
902 struct VertAttribPointerCalculated final
{
903 uint8_t byteSize
= 4 * 4;
904 uint8_t byteStride
= 4 * 4; // at-most 255
905 webgl::AttribBaseType baseType
= webgl::AttribBaseType::Float
;
911 inline Range
<T
> ShmemRange(const mozilla::ipc::Shmem
& shmem
) {
912 return {shmem
.get
<T
>(), shmem
.Size
<T
>()};
917 template <typename C
, typename K
>
918 inline auto MaybeFind(C
& container
, const K
& key
)
919 -> decltype(&(container
.find(key
)->second
)) {
920 const auto itr
= container
.find(key
);
921 if (itr
== container
.end()) return nullptr;
922 return &(itr
->second
);
925 template <typename C
, typename K
>
926 inline typename
C::mapped_type
Find(
927 const C
& container
, const K
& key
,
928 const typename
C::mapped_type notFound
= {}) {
929 const auto itr
= container
.find(key
);
930 if (itr
== container
.end()) return notFound
;
936 template <typename T
, typename U
>
937 inline Maybe
<T
> MaybeAs(const U val
) {
938 const auto checked
= CheckedInt
<T
>(val
);
939 if (!checked
.isValid()) return {};
940 return Some(checked
.value());
945 inline GLenum
IsTexImageTarget(const GLenum imageTarget
) {
946 switch (imageTarget
) {
947 case LOCAL_GL_TEXTURE_2D
:
948 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
949 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
950 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
951 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
952 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
953 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
954 case LOCAL_GL_TEXTURE_3D
:
955 case LOCAL_GL_TEXTURE_2D_ARRAY
:
961 inline GLenum
ImageToTexTarget(const GLenum imageTarget
) {
962 switch (imageTarget
) {
963 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
964 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
965 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
966 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
967 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
968 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
969 return LOCAL_GL_TEXTURE_CUBE_MAP
;
971 if (IsTexImageTarget(imageTarget
)) {
977 inline bool IsTexTarget3D(const GLenum texTarget
) {
979 case LOCAL_GL_TEXTURE_2D_ARRAY
:
980 case LOCAL_GL_TEXTURE_3D
:
994 class OffscreenCanvas
;
998 struct TexImageSource
{
999 const dom::ArrayBufferView
* mView
= nullptr;
1000 GLuint mViewElemOffset
= 0;
1001 GLuint mViewElemLengthOverride
= 0;
1003 const WebGLintptr
* mPboOffset
= nullptr;
1005 const dom::ImageBitmap
* mImageBitmap
= nullptr;
1006 const dom::ImageData
* mImageData
= nullptr;
1008 const dom::OffscreenCanvas
* mOffscreenCanvas
= nullptr;
1010 const dom::VideoFrame
* mVideoFrame
= nullptr;
1012 const dom::Element
* mDomElem
= nullptr;
1013 ErrorResult
* mOut_error
= nullptr;
1018 template <class DerivedT
>
1019 struct DeriveNotEq
{
1020 bool operator!=(const DerivedT
& rhs
) const {
1021 const auto self
= reinterpret_cast<const DerivedT
*>(this);
1022 return !(*self
== rhs
);
1026 struct PixelPackingState
: public DeriveNotEq
<PixelPackingState
> {
1027 uint32_t alignmentInTypeElems
= 4; // ALIGNMENT isn't naive byte alignment!
1028 uint32_t rowLength
= 0;
1029 uint32_t imageHeight
= 0;
1030 uint32_t skipPixels
= 0;
1031 uint32_t skipRows
= 0;
1032 uint32_t skipImages
= 0;
1034 auto MutTiedFields() {
1035 return std::tie(alignmentInTypeElems
, rowLength
, imageHeight
, skipPixels
,
1036 skipRows
, skipImages
);
1039 using Self
= PixelPackingState
;
1040 friend bool operator==(const Self
& a
, const Self
& b
) {
1041 return TiedFields(a
) == TiedFields(b
);
1044 static void AssertDefaultUnpack(gl::GLContext
& gl
, const bool isWebgl2
) {
1045 PixelPackingState
{}.AssertCurrentUnpack(gl
, isWebgl2
);
1048 void ApplyUnpack(gl::GLContext
&, bool isWebgl2
,
1049 const uvec3
& uploadSize
) const;
1050 bool AssertCurrentUnpack(gl::GLContext
&, bool isWebgl2
) const;
1053 struct PixelUnpackStateWebgl final
: public PixelPackingState
{
1054 GLenum colorspaceConversion
=
1055 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL
;
1057 bool premultiplyAlpha
= false;
1058 bool requireFastPath
= false;
1059 uint8_t padding
= {};
1061 auto MutTiedFields() {
1062 return std::tuple_cat(PixelPackingState::MutTiedFields(),
1063 std::tie(colorspaceConversion
, flipY
,
1064 premultiplyAlpha
, requireFastPath
, padding
));
1068 struct ExplicitPixelPackingState final
{
1069 struct Metrics final
{
1070 uvec3 usedSize
= {};
1071 size_t bytesPerPixel
= 0;
1073 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1074 // ...aligned to ALIGNMENT.
1075 size_t bytesPerRowStride
= 0;
1077 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1078 size_t totalRows
= 0;
1080 // This ensures that no one else needs to do CheckedInt math.
1081 size_t totalBytesUsed
= 0;
1082 size_t totalBytesStrided
= 0;
1085 // It's so important that these aren't modified once evaluated.
1086 const PixelPackingState state
;
1087 const Metrics metrics
;
1089 static Result
<ExplicitPixelPackingState
, std::string
> ForUseWith(
1090 const PixelPackingState
&, GLenum target
, const uvec3
& subrectSize
,
1091 const webgl::PackingInfo
&, const Maybe
<size_t> bytesPerRowStrideOverride
);
1094 struct ReadPixelsDesc final
{
1097 PackingInfo pi
= {LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
};
1098 PixelPackingState packState
;
1100 auto MutTiedFields() { return std::tie(srcOffset
, size
, pi
, packState
); }
1103 } // namespace webgl
1107 struct TexUnpackBlobDesc final
{
1108 GLenum imageTarget
= LOCAL_GL_TEXTURE_2D
;
1110 gfxAlphaType srcAlphaType
= gfxAlphaType::NonPremult
;
1112 Maybe
<Span
<const uint8_t>> cpuData
;
1113 Maybe
<uint64_t> pboOffset
;
1115 Maybe
<uvec2
> structuredSrcSize
;
1116 RefPtr
<layers::Image
> image
;
1117 Maybe
<layers::SurfaceDescriptor
> sd
;
1118 RefPtr
<gfx::DataSourceSurface
> dataSurf
;
1120 webgl::PixelUnpackStateWebgl unpacking
;
1121 bool applyUnpackTransforms
= true;
1125 auto ExplicitUnpacking(const webgl::PackingInfo
& pi
,
1126 const Maybe
<size_t> bytesPerRowStrideOverride
) const {
1127 return ExplicitPixelPackingState::ForUseWith(this->unpacking
,
1128 this->imageTarget
, this->size
,
1129 pi
, bytesPerRowStrideOverride
);
1132 void Shrink(const webgl::PackingInfo
&);
1135 } // namespace webgl
1137 // ---------------------------------------
1140 template <typename T
, size_t N
>
1141 inline Range
<const T
> MakeRange(T (&arr
)[N
]) {
1145 template <typename T
>
1146 inline Range
<const T
> MakeRange(const dom::Sequence
<T
>& seq
) {
1147 return {seq
.Elements(), seq
.Length()};
1152 constexpr auto kUniversalAlignment
= alignof(std::max_align_t
);
1154 template <typename T
>
1155 inline size_t AlignmentOffset(const size_t alignment
, const T posOrPtr
) {
1156 MOZ_ASSERT(alignment
);
1157 const auto begin
= reinterpret_cast<uintptr_t>(posOrPtr
);
1158 const auto wholeMultiples
= (begin
+ (alignment
- 1)) / alignment
;
1159 const auto aligned
= wholeMultiples
* alignment
;
1160 return aligned
- begin
;
1163 template <typename T
>
1164 inline size_t ByteSize(const Range
<T
>& range
) {
1165 return range
.length() * sizeof(T
);
1170 Maybe
<webgl::ErrorInfo
> CheckBindBufferRange(
1171 const GLenum target
, const GLuint index
, const bool isBuffer
,
1172 const uint64_t offset
, const uint64_t size
, const webgl::Limits
& limits
);
1174 Maybe
<webgl::ErrorInfo
> CheckFramebufferAttach(const GLenum bindImageTarget
,
1175 const GLenum curTexTarget
,
1176 const uint32_t mipLevel
,
1177 const uint32_t zLayerBase
,
1178 const uint32_t zLayerCount
,
1179 const webgl::Limits
& limits
);
1181 Result
<webgl::VertAttribPointerCalculated
, webgl::ErrorInfo
>
1182 CheckVertexAttribPointer(bool isWebgl2
, const webgl::VertAttribPointerDesc
&);
1184 uint8_t ElemTypeComponents(GLenum elemType
);
1186 inline std::string
ToString(const nsACString
& text
) {
1187 return {text
.BeginReading(), text
.Length()};
1190 inline void Memcpy(const RangedPtr
<uint8_t>& destBytes
,
1191 const RangedPtr
<const uint8_t>& srcBytes
,
1192 const size_t byteSize
) {
1193 // Trigger range asserts
1194 (void)(srcBytes
+ byteSize
);
1195 (void)(destBytes
+ byteSize
);
1197 memcpy(destBytes
.get(), srcBytes
.get(), byteSize
);
1200 template <class T
, class U
>
1201 inline void Memcpy(const Range
<T
>* const destRange
,
1202 const RangedPtr
<U
>& srcBegin
) {
1203 Memcpy(destRange
->begin(), srcBegin
, destRange
->length());
1205 template <class T
, class U
>
1206 inline void Memcpy(const RangedPtr
<T
>* const destBegin
,
1207 const Range
<U
>& srcRange
) {
1208 Memcpy(destBegin
, srcRange
->begin(), srcRange
->length());
1211 template <typename Dst
, typename Src
>
1212 inline void Memcpy(const Span
<Dst
>* const dest
, const Span
<Src
>& src
) {
1213 MOZ_RELEASE_ASSERT(src
.size_bytes() >= dest
->size_bytes());
1214 MOZ_ASSERT(src
.size_bytes() == dest
->size_bytes());
1215 memcpy(dest
->data(), src
.data(), dest
->size_bytes());
1220 inline bool StartsWith(const std::string_view str
,
1221 const std::string_view part
) {
1222 return str
.find(part
) == 0;
1228 Maybe
<T
> AsValidEnum(const std::underlying_type_t
<T
> raw_val
) {
1229 const auto raw_enum
= T
{raw_val
}; // This is the risk we prevent!
1230 if (!IsEnumCase(raw_enum
)) return {};
1231 return Some(raw_enum
);
1238 // In theory, this number can be unbounded based on the driver. However, no
1239 // driver appears to expose more than 8. We might as well stop there too, for
1241 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1242 inline constexpr size_t kMaxDrawBuffers
= 8;
1244 union UniformDataVal
{
1250 enum class ProvokingVertex
: GLenum
{
1251 FirstVertex
= LOCAL_GL_FIRST_VERTEX_CONVENTION
,
1252 LastVertex
= LOCAL_GL_LAST_VERTEX_CONVENTION
,
1254 inline constexpr bool IsEnumCase(const ProvokingVertex raw
) {
1256 case ProvokingVertex::FirstVertex
:
1257 case ProvokingVertex::LastVertex
:
1264 inline constexpr std::optional
<E
> AsEnumCase(
1265 const std::underlying_type_t
<E
> raw
) {
1266 const auto ret
= static_cast<E
>(raw
);
1267 if (!IsEnumCase(ret
)) return {};
1273 struct BufferAndIndex final
{
1274 const WebGLBuffer
* buffer
= nullptr;
1278 } // namespace webgl
1280 struct IndexedBufferBinding final
{
1281 RefPtr
<WebGLBuffer
> mBufferBinding
;
1282 uint64_t mRangeStart
= 0;
1283 uint64_t mRangeSize
= 0;
1285 IndexedBufferBinding();
1286 ~IndexedBufferBinding();
1288 uint64_t ByteCount() const;
1293 template <class... Args
>
1294 inline std::string
PrintfStdString(const char* const format
,
1295 const Args
&... args
) {
1296 const auto nsStr
= nsPrintfCString(format
, args
...);
1297 return ToString(nsStr
);
1300 inline const char* ToChars(const bool val
) {
1301 if (val
) return "true";
1306 struct ReinterpretToSpan
{
1307 template <class FromT
>
1308 static inline constexpr Span
<To
> From(const Span
<FromT
>& from
) {
1309 static_assert(sizeof(FromT
) == sizeof(To
));
1310 return {reinterpret_cast<To
*>(from
.data()), from
.size()};
1316 inline std::string
Join(Span
<const std::string
> ss
,
1317 const std::string_view
& delim
) {
1318 if (!ss
.size()) return "";
1319 auto ret
= std::string();
1321 auto chars
= delim
.size() * (ss
.size() - 1);
1322 for (const auto& s
: ss
) {
1330 for (const auto& s
: ss
) {
1337 inline std::string
ToStringWithCommas(uint64_t v
) {
1339 std::vector
<std::string
> chunks
;
1341 const auto chunk
= v
% 1000;
1343 chunks
.insert(chunks
.begin(), std::to_string(chunk
));
1345 return Join(chunks
, ",");
1352 std::unordered_map
<GLenum
, bool> MakeIsEnabledMap(bool webgl2
);
1354 static constexpr uint32_t kMaxClientWaitSyncTimeoutNS
=
1355 1000 * 1000 * 1000; // 1000ms in ns.
1357 } // namespace webgl
1358 } // namespace mozilla