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/IsEnumCase.h"
24 #include "mozilla/MathAlgorithms.h"
25 #include "mozilla/Range.h"
26 #include "mozilla/RefCounted.h"
27 #include "mozilla/Result.h"
28 #include "mozilla/ResultVariant.h"
29 #include "mozilla/Span.h"
30 #include "mozilla/TiedFields.h"
31 #include "mozilla/TypedEnumBits.h"
32 #include "mozilla/gfx/2D.h"
33 #include "mozilla/gfx/BuildConstants.h"
34 #include "mozilla/gfx/Logging.h"
35 #include "mozilla/gfx/Point.h"
36 #include "mozilla/gfx/Rect.h"
37 #include "mozilla/ipc/Shmem.h"
38 #include "mozilla/layers/LayersSurfaces.h"
43 #include "mozilla/dom/WebGLRenderingContextBinding.h"
44 #include "mozilla/ipc/SharedMemory.h"
46 // Manual reflection of WebIDL typedefs that are different from their
47 // OpenGL counterparts.
48 using WebGLsizeiptr
= int64_t;
49 using WebGLintptr
= int64_t;
50 using WebGLboolean
= bool;
56 class GLContext
; // This is going to be needed a lot.
60 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
63 template <typename DestT
>
64 class ForbidNarrowing final
{
68 template <typename SrcT
>
69 MOZ_IMPLICIT
ForbidNarrowing(SrcT val
) : mVal(val
) {
71 std::numeric_limits
<SrcT
>::min() >= std::numeric_limits
<DestT
>::min(),
72 "SrcT must be narrower than DestT.");
74 std::numeric_limits
<SrcT
>::max() <= std::numeric_limits
<DestT
>::max(),
75 "SrcT must be narrower than DestT.");
78 explicit operator DestT() const { return mVal
; }
81 inline void* malloc(const ForbidNarrowing
<size_t> s
) {
82 return ::malloc(size_t(s
));
85 inline void* calloc(const ForbidNarrowing
<size_t> n
,
86 const ForbidNarrowing
<size_t> size
) {
87 return ::calloc(size_t(n
), size_t(size
));
92 // TODO: Remove this now-mere-alias.
93 template <typename From
>
94 inline auto AutoAssertCast(const From val
) {
95 return LazyAssertedCast(val
);
98 const char* GetEnumName(GLenum val
, const char* defaultRet
= "<unknown>");
99 std::string
EnumString(GLenum val
);
102 template <typename T
>
103 struct QueueParamTraits
;
104 class TexUnpackBytes
;
105 class TexUnpackImage
;
106 class TexUnpackSurface
;
109 class ClientWebGLContext
;
110 struct WebGLTexPboOffset
;
113 class WebGLFramebuffer
;
116 class WebGLRenderbuffer
;
121 class WebGLTransformFeedback
;
122 class WebGLVertexArray
;
126 class VRefCounted
: public RefCounted
<VRefCounted
> {
128 virtual ~VRefCounted() = default;
130 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
131 virtual const char* typeName() const = 0;
132 virtual size_t typeSize() const = 0;
139 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
140 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
141 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
142 * desktop OpenGL does not allow that.
144 enum class WebGLVertexAttrib0Status
: uint8_t {
145 Default
, // default status - no emulation needed
146 EmulatedUninitializedArray
, // need an artificial attrib 0 array, but
147 // contents may be left uninitialized
148 EmulatedInitializedArray
// need an artificial attrib 0 array, and contents
149 // must be initialized
153 * The formats that may participate, either as source or destination formats,
154 * in WebGL texture conversions. This includes:
155 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
156 * - additional formats provided by extensions, e.g. RGB32F
157 * - additional source formats, depending on browser details, used when
158 * uploading textures from DOM elements. See gfxImageSurface::Format().
160 enum class WebGLTexelFormat
: uint8_t {
161 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
164 // common value for formats for which format conversions are not supported
165 FormatNotSupportingAnyConversion
,
166 // dummy pseudo-format meaning "use the other format".
167 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
168 // is implicitly treated as being RGB8 itself.
172 A16F
, // OES_texture_half_float
173 A32F
, // OES_texture_float
175 R16F
, // OES_texture_half_float
176 R32F
, // OES_texture_float
179 RA16F
, // OES_texture_half_float
180 RA32F
, // OES_texture_float
188 RGB16F
, // OES_texture_half_float
189 RGB32F
, // OES_texture_float
194 RGBA16F
, // OES_texture_half_float
195 RGBA32F
, // OES_texture_float
196 // DOM element source only formats.
202 enum class WebGLTexImageFunc
: uint8_t {
211 enum class WebGLTexDimensions
: uint8_t { Tex2D
, Tex3D
};
213 // Please keep extensions in alphabetic order.
214 enum class WebGLExtensionID
: uint8_t {
215 ANGLE_instanced_arrays
,
217 EXT_color_buffer_float
,
218 EXT_color_buffer_half_float
,
220 EXT_disjoint_timer_query
,
223 EXT_shader_texture_lod
,
225 EXT_texture_compression_bptc
,
226 EXT_texture_compression_rgtc
,
227 EXT_texture_filter_anisotropic
,
230 OES_draw_buffers_indexed
,
231 OES_element_index_uint
,
232 OES_fbo_render_mipmap
,
233 OES_standard_derivatives
,
235 OES_texture_float_linear
,
236 OES_texture_half_float
,
237 OES_texture_half_float_linear
,
238 OES_vertex_array_object
,
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
,
251 WEBGL_explicit_present
,
253 WEBGL_provoking_vertex
,
257 class UniqueBuffer final
{
258 // Like unique_ptr<>, but for void* and malloc/calloc/free.
259 void* mBuffer
= nullptr;
262 static inline UniqueBuffer
Take(void* buffer
) {
264 ret
.mBuffer
= buffer
;
268 UniqueBuffer() = default;
270 ~UniqueBuffer() { reset(); }
272 UniqueBuffer(UniqueBuffer
&& rhs
) { *this = std::move(rhs
); }
274 UniqueBuffer
& operator=(UniqueBuffer
&& rhs
) {
276 this->mBuffer
= rhs
.mBuffer
;
277 rhs
.mBuffer
= nullptr;
281 explicit operator bool() const { return bool(mBuffer
); }
283 void* get() const { return mBuffer
; }
286 // Believe it or not, when `free` unconditional, it was showing up
287 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
297 struct FormatUsageInfo
;
299 static constexpr GLenum kErrorPerfWarning
= 0x10001;
301 struct SampleableInfo final
{
302 const char* incompleteReason
= nullptr;
304 const webgl::FormatUsageInfo
* usage
= nullptr;
305 bool isDepthTexCompare
= false;
307 bool IsComplete() const { return bool(levels
); }
310 enum class AttribBaseType
: uint8_t {
311 Boolean
, // Can convert from anything.
312 Float
, // Also includes NormU?Int
318 inline constexpr bool IsEnumCase
<webgl::AttribBaseType
>(
319 const webgl::AttribBaseType v
) {
321 case webgl::AttribBaseType::Boolean
:
322 case webgl::AttribBaseType::Float
:
323 case webgl::AttribBaseType::Int
:
324 case webgl::AttribBaseType::Uint
:
330 webgl::AttribBaseType
ToAttribBaseType(GLenum
);
331 const char* ToString(AttribBaseType
);
333 enum class UniformBaseType
: uint8_t {
338 const char* ToString(UniformBaseType
);
340 using ObjectId
= uint64_t;
342 enum class BufferKind
: uint8_t {
352 struct FloatOrInt final
// For TexParameter[fi] and friends.
354 bool isFloat
= false;
355 uint8_t padding
[3] = {};
359 explicit FloatOrInt(GLint x
= 0) : isFloat(false), f(x
), i(x
) {}
361 explicit FloatOrInt(GLfloat x
) : isFloat(true), f(x
), i(roundf(x
)) {}
363 auto MutTiedFields() { return std::tie(isFloat
, padding
, f
, i
); }
368 struct WebGLContextOptions final
{
371 bool stencil
= false;
372 bool premultipliedAlpha
= true;
374 bool antialias
= true;
375 bool preserveDrawingBuffer
= false;
376 bool failIfMajorPerformanceCaveat
= false;
377 bool xrCompatible
= false;
379 dom::WebGLPowerPreference powerPreference
=
380 dom::WebGLPowerPreference::Default
;
381 bool forceSoftwareRendering
= false;
382 bool shouldResistFingerprinting
= true;
383 bool enableDebugRendererInfo
= false;
384 PaddingField
<bool, 7> _padding
;
386 auto MutTiedFields() {
395 preserveDrawingBuffer
,
396 failIfMajorPerformanceCaveat
,
400 forceSoftwareRendering
,
401 shouldResistFingerprinting
,
402 enableDebugRendererInfo
,
409 WebGLContextOptions();
410 WebGLContextOptions(const WebGLContextOptions
&) = default;
412 using Self
= WebGLContextOptions
;
413 friend bool operator==(const Self
& a
, const Self
& b
) {
414 return TiedFields(a
) == TiedFields(b
);
416 friend bool operator!=(const Self
& a
, const Self
& b
) { return !(a
== b
); }
421 inline ColorSpace2
ToColorSpace2(const dom::PredefinedColorSpace cs
) {
423 case dom::PredefinedColorSpace::Srgb
:
424 return ColorSpace2::SRGB
;
425 case dom::PredefinedColorSpace::Display_p3
:
426 return ColorSpace2::DISPLAY_P3
;
428 MOZ_CRASH("Exhaustive switch");
435 template <typename _T
>
442 auto MutTiedFields() { return std::tie(x
, y
); }
444 template <typename U
, typename V
>
445 static Maybe
<avec2
> From(const U _x
, const V _y
) {
446 const auto x
= CheckedInt
<T
>(_x
);
447 const auto y
= CheckedInt
<T
>(_y
);
448 if (!x
.isValid() || !y
.isValid()) return {};
449 return Some(avec2(x
.value(), y
.value()));
452 template <typename U
>
453 static auto From(const U
& val
) {
454 return From(val
.x
, val
.y
);
456 template <typename U
>
457 static auto FromSize(const U
& val
) {
458 return From(val
.width
, val
.height
);
462 avec2(const T _x
, const T _y
) : x(_x
), y(_y
) {}
464 bool operator==(const avec2
& rhs
) const { return x
== rhs
.x
&& y
== rhs
.y
; }
465 bool operator!=(const avec2
& rhs
) const { return !(*this == rhs
); }
468 avec2 operator OP(const avec2& rhs) const { \
469 return {x OP rhs.x, y OP rhs.y}; \
471 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
480 avec2
Clamp(const avec2
& min
, const avec2
& max
) const {
481 return {std::clamp(x
, min
.x
, max
.x
), std::clamp(y
, min
.y
, max
.y
)};
484 template <typename U
>
485 U
StaticCast() const {
486 return {static_cast<typename
U::T
>(x
), static_cast<typename
U::T
>(y
)};
490 template <typename T
>
491 avec2
<T
> MinExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
492 return {std::min(a
.x
, b
.x
), std::min(a
.y
, b
.y
)};
495 template <typename T
>
496 avec2
<T
> MaxExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
497 return {std::max(a
.x
, b
.x
), std::max(a
.y
, b
.y
)};
502 template <typename _T
>
510 auto MutTiedFields() { return std::tie(x
, y
, z
); }
512 template <typename U
, typename V
>
513 static Maybe
<avec3
> From(const U _x
, const V _y
, const V _z
) {
514 const auto x
= CheckedInt
<T
>(_x
);
515 const auto y
= CheckedInt
<T
>(_y
);
516 const auto z
= CheckedInt
<T
>(_z
);
517 if (!x
.isValid() || !y
.isValid() || !z
.isValid()) return {};
518 return Some(avec3(x
.value(), y
.value(), z
.value()));
521 template <typename U
>
522 static auto From(const U
& val
) {
523 return From(val
.x
, val
.y
, val
.z
);
527 avec3(const T _x
, const T _y
, const T _z
) : x(_x
), y(_y
), z(_z
) {}
529 bool operator==(const avec3
& rhs
) const {
530 return x
== rhs
.x
&& y
== rhs
.y
&& z
== rhs
.z
;
532 bool operator!=(const avec3
& rhs
) const { return !(*this == rhs
); }
535 using ivec2
= avec2
<int32_t>;
536 using ivec3
= avec3
<int32_t>;
537 using uvec2
= avec2
<uint32_t>;
538 using uvec3
= avec3
<uint32_t>;
540 inline ivec2
AsVec(const gfx::IntSize
& s
) { return {s
.width
, s
.height
}; }
546 struct PackingInfo final
{
550 auto MutTiedFields() { return std::tie(format
, type
); }
552 using Self
= PackingInfo
;
553 friend bool operator<(const Self
& a
, const Self
& b
) {
554 return TiedFields(a
) < TiedFields(b
);
556 friend bool operator==(const Self
& a
, const Self
& b
) {
557 return TiedFields(a
) == TiedFields(b
);
561 friend T
& operator<<(T
& s
, const PackingInfo
& pi
) {
562 s
<< "PackingInfo{format: " << EnumString(pi
.format
)
563 << ", type: " << EnumString(pi
.type
) << "}";
568 struct DriverUnpackInfo final
{
569 GLenum internalFormat
= 0;
570 GLenum unpackFormat
= 0;
571 GLenum unpackType
= 0;
573 PackingInfo
ToPacking() const { return {unpackFormat
, unpackType
}; }
578 template <typename E
>
584 struct BitRef final
{
588 explicit operator bool() const { return bits
.mBits
& mask
; }
590 auto& operator=(const bool val
) {
600 uint64_t Mask(const E i
) const {
601 return uint64_t{1} << static_cast<uint64_t>(i
);
605 BitRef
operator[](const E i
) { return {*this, Mask(i
)}; }
606 bool operator[](const E i
) const { return mBits
& Mask(i
); }
610 auto MutTiedFields() { return std::tie(mBits
); }
613 using ExtensionBits
= EnumMask
<WebGLExtensionID
>;
617 enum class ContextLossReason
: uint8_t {
623 inline bool ReadContextLossReason(const uint8_t val
,
624 ContextLossReason
* const out
) {
625 if (val
> static_cast<uint8_t>(ContextLossReason::Guilty
)) {
628 *out
= static_cast<ContextLossReason
>(val
);
634 struct InitContextDesc final
{
635 bool isWebgl2
= false;
636 bool resistFingerprinting
= false;
637 std::array
<uint8_t, 2> _padding
;
638 uint32_t principalKey
= 0;
640 WebGLContextOptions options
;
641 std::array
<uint8_t, 5> _padding2
;
643 auto MutTiedFields() {
644 return std::tie(isWebgl2
, resistFingerprinting
, _padding
, principalKey
,
645 size
, options
, _padding2
);
649 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs
= 4;
651 struct Limits final
{
652 ExtensionBits supportedExtensions
;
655 uint32_t maxTexUnits
= 0;
656 uint32_t maxTex2dSize
= 0;
657 uint32_t maxTexCubeSize
= 0;
658 uint32_t maxVertexAttribs
= 0;
659 uint32_t maxViewportDim
= 0;
660 std::array
<float, 2> pointSizeRange
= {{1, 1}};
661 std::array
<float, 2> lineWidthRange
= {{1, 1}};
664 uint32_t maxTexArrayLayers
= 0;
665 uint32_t maxTex3dSize
= 0;
666 uint32_t maxUniformBufferBindings
= 0;
667 uint32_t uniformBufferOffsetAlignment
= 0;
670 bool astcHdr
= false;
671 std::array
<uint8_t, 3> _padding
;
672 uint32_t maxColorDrawBuffers
= 1;
673 uint32_t maxMultiviewLayers
= 0;
674 uint64_t queryCounterBitsTimeElapsed
= 0;
675 uint64_t queryCounterBitsTimestamp
= 0;
677 auto MutTiedFields() {
678 return std::tie(supportedExtensions
,
680 maxTexUnits
, maxTex2dSize
, maxTexCubeSize
, maxVertexAttribs
,
681 maxViewportDim
, pointSizeRange
, lineWidthRange
,
683 maxTexArrayLayers
, maxTex3dSize
, maxUniformBufferBindings
,
684 uniformBufferOffsetAlignment
,
686 astcHdr
, _padding
, maxColorDrawBuffers
, maxMultiviewLayers
,
687 queryCounterBitsTimeElapsed
, queryCounterBitsTimestamp
);
693 template <class T
, size_t Padding
>
699 uint8_t padding
[Padding
] = {};
703 struct PaddedBase
<T
, 0> {
707 } // namespace details
709 template <class T
, size_t PaddedSize
>
710 struct Padded
: details::PaddedBase
<T
, PaddedSize
- sizeof(T
)> {
711 operator T
&() { return this->val
; }
712 operator const T
&() const { return this->val
; }
714 auto& operator=(const T
& rhs
) { return this->val
= rhs
; }
715 auto& operator=(T
&& rhs
) { return this->val
= std::move(rhs
); }
717 auto& operator*() { return this->val
; }
718 auto& operator*() const { return this->val
; }
719 auto operator->() { return &this->val
; }
720 auto operator->() const { return &this->val
; }
725 enum class OptionalRenderableFormatBits
: uint8_t {
729 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OptionalRenderableFormatBits
)
733 inline constexpr bool IsEnumCase
<webgl::OptionalRenderableFormatBits
>(
734 const webgl::OptionalRenderableFormatBits raw
) {
735 auto rawWithoutValidBits
= UnderlyingValue(raw
);
736 auto bit
= decltype(rawWithoutValidBits
){1};
738 switch (webgl::OptionalRenderableFormatBits
{bit
}) {
739 // -Werror=switch ensures exhaustive.
740 case webgl::OptionalRenderableFormatBits::RGB8
:
741 case webgl::OptionalRenderableFormatBits::SRGB8
:
742 rawWithoutValidBits
&= ~bit
;
747 return rawWithoutValidBits
== 0;
753 struct InitContextResult final
{
754 Padded
<std::string
, 32> error
; // MINGW 32-bit needs this padding.
755 WebGLContextOptions options
;
757 OptionalRenderableFormatBits optionalRenderableFormatBits
;
758 std::array
<uint8_t, 3> _padding
= {};
760 EnumMask
<layers::SurfaceDescriptor::Type
> uploadableSdTypes
;
762 auto MutTiedFields() {
763 return std::tie(error
, options
, vendor
, optionalRenderableFormatBits
,
764 _padding
, limits
, uploadableSdTypes
);
770 struct ErrorInfo final
{
775 struct ShaderPrecisionFormat final
{
783 enum class LossStatus
{
793 struct CompileResult final
{
796 nsCString translatedSource
;
797 bool success
= false;
802 struct OpaqueFramebufferOptions final
{
803 bool depthStencil
= true;
804 bool antialias
= true;
805 std::array
<uint8_t, 2> _padding
;
809 auto MutTiedFields() {
810 return std::tie(depthStencil
, antialias
, _padding
, width
, height
);
816 struct SwapChainOptions final
{
817 layers::RemoteTextureId remoteTextureId
;
818 layers::RemoteTextureOwnerId remoteTextureOwnerId
;
820 bool forceAsyncPresent
= false;
821 // Pad to sizeof(u64):
822 uint16_t padding1
= 0;
823 uint32_t padding2
= 0;
825 auto MutTiedFields() {
826 return std::tie(remoteTextureId
, remoteTextureOwnerId
, bgra
,
827 forceAsyncPresent
, padding1
, padding2
);
834 GLenum elemType
= 0; // `type`
835 uint32_t elemCount
= 0; // `size`
839 struct ActiveAttribInfo final
: public ActiveInfo
{
840 int32_t location
= -1;
841 AttribBaseType baseType
= AttribBaseType::Float
;
844 struct ActiveUniformInfo final
: public ActiveInfo
{
845 std::unordered_map
<uint32_t, uint32_t>
846 locByIndex
; // Uniform array locations are sparse.
847 int32_t block_index
= -1;
848 int32_t block_offset
= -1; // In block, offset.
849 int32_t block_arrayStride
= -1;
850 int32_t block_matrixStride
= -1;
851 bool block_isRowMajor
= false;
854 struct ActiveUniformBlockInfo final
{
856 // BLOCK_BINDING is dynamic state
857 uint32_t dataSize
= 0;
858 std::vector
<uint32_t> activeUniformIndices
;
859 bool referencedByVertexShader
= false;
860 bool referencedByFragmentShader
= false;
863 struct LinkActiveInfo final
{
864 std::vector
<ActiveAttribInfo
> activeAttribs
;
865 std::vector
<ActiveUniformInfo
> activeUniforms
;
866 std::vector
<ActiveUniformBlockInfo
> activeUniformBlocks
;
867 std::vector
<ActiveInfo
> activeTfVaryings
;
870 struct LinkResult final
{
873 bool success
= false;
874 LinkActiveInfo active
;
875 GLenum tfBufferMode
= 0;
880 /// 4x32-bit primitives, with a type tag.
881 struct TypedQuad final
{
882 alignas(alignof(float)) std::array
<uint8_t, 4 * sizeof(float)> data
= {};
883 webgl::AttribBaseType type
= webgl::AttribBaseType::Float
;
884 uint8_t padding
[3] = {};
886 constexpr auto MutTiedFields() { return std::tie(data
, type
, padding
); }
889 /// [1-16]x32-bit primitives, with a type tag.
890 struct GetUniformData final
{
891 alignas(alignof(float)) uint8_t data
[4 * 4 * sizeof(float)] = {};
895 struct FrontBufferSnapshotIpc final
{
897 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
900 struct ReadPixelsResult
{
901 gfx::IntRect subrect
= {};
902 size_t byteStride
= 0;
905 struct ReadPixelsResultIpc final
: public ReadPixelsResult
{
906 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
909 struct VertAttribPointerDesc final
{
910 bool intFunc
= false;
911 uint8_t channels
= 4;
912 bool normalized
= false;
913 uint8_t byteStrideOrZero
= 0;
914 GLenum type
= LOCAL_GL_FLOAT
;
915 uint64_t byteOffset
= 0;
917 auto MutTiedFields() {
918 return std::tie(intFunc
, channels
, normalized
, byteStrideOrZero
, type
,
923 struct VertAttribPointerCalculated final
{
924 uint8_t byteSize
= 4 * 4;
925 uint8_t byteStride
= 4 * 4; // at-most 255
926 webgl::AttribBaseType baseType
= webgl::AttribBaseType::Float
;
932 inline Range
<T
> ShmemRange(const mozilla::ipc::Shmem
& shmem
) {
933 return {shmem
.get
<T
>(), shmem
.Size
<T
>()};
938 template <typename C
, typename K
>
939 inline auto MaybeFind(C
& container
, const K
& key
)
940 -> decltype(&(container
.find(key
)->second
)) {
941 const auto itr
= container
.find(key
);
942 if (itr
== container
.end()) return nullptr;
943 return &(itr
->second
);
946 template <typename C
, typename K
>
947 inline typename
C::mapped_type
Find(
948 const C
& container
, const K
& key
,
949 const typename
C::mapped_type notFound
= {}) {
950 const auto itr
= container
.find(key
);
951 if (itr
== container
.end()) return notFound
;
957 template <typename T
, typename U
>
958 inline Maybe
<T
> MaybeAs(const U val
) {
959 const auto checked
= CheckedInt
<T
>(val
);
960 if (!checked
.isValid()) return {};
961 return Some(checked
.value());
966 inline GLenum
IsTexImageTarget(const GLenum imageTarget
) {
967 switch (imageTarget
) {
968 case LOCAL_GL_TEXTURE_2D
:
969 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
970 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
971 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
972 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
973 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
974 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
975 case LOCAL_GL_TEXTURE_3D
:
976 case LOCAL_GL_TEXTURE_2D_ARRAY
:
982 inline GLenum
ImageToTexTarget(const GLenum imageTarget
) {
983 switch (imageTarget
) {
984 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
985 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
986 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
987 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
988 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
989 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
990 return LOCAL_GL_TEXTURE_CUBE_MAP
;
992 if (IsTexImageTarget(imageTarget
)) {
998 inline bool IsTexTarget3D(const GLenum texTarget
) {
1000 case LOCAL_GL_TEXTURE_2D_ARRAY
:
1001 case LOCAL_GL_TEXTURE_3D
:
1015 class OffscreenCanvas
;
1019 struct TexImageSource
{
1020 const dom::ArrayBufferView
* mView
= nullptr;
1021 GLuint mViewElemOffset
= 0;
1022 GLuint mViewElemLengthOverride
= 0;
1024 const WebGLintptr
* mPboOffset
= nullptr;
1026 const dom::ImageBitmap
* mImageBitmap
= nullptr;
1027 const dom::ImageData
* mImageData
= nullptr;
1029 const dom::OffscreenCanvas
* mOffscreenCanvas
= nullptr;
1031 const dom::VideoFrame
* mVideoFrame
= nullptr;
1033 const dom::Element
* mDomElem
= nullptr;
1034 ErrorResult
* mOut_error
= nullptr;
1039 template <class DerivedT
>
1040 struct DeriveNotEq
{
1041 bool operator!=(const DerivedT
& rhs
) const {
1042 const auto self
= reinterpret_cast<const DerivedT
*>(this);
1043 return !(*self
== rhs
);
1047 struct PixelPackingState
: public DeriveNotEq
<PixelPackingState
> {
1048 uint32_t alignmentInTypeElems
= 4; // ALIGNMENT isn't naive byte alignment!
1049 uint32_t rowLength
= 0;
1050 uint32_t imageHeight
= 0;
1051 uint32_t skipPixels
= 0;
1052 uint32_t skipRows
= 0;
1053 uint32_t skipImages
= 0;
1055 auto MutTiedFields() {
1056 return std::tie(alignmentInTypeElems
, rowLength
, imageHeight
, skipPixels
,
1057 skipRows
, skipImages
);
1060 using Self
= PixelPackingState
;
1061 friend bool operator==(const Self
& a
, const Self
& b
) {
1062 return TiedFields(a
) == TiedFields(b
);
1065 static void AssertDefaultUnpack(gl::GLContext
& gl
, const bool isWebgl2
) {
1066 PixelPackingState
{}.AssertCurrentUnpack(gl
, isWebgl2
);
1069 void ApplyUnpack(gl::GLContext
&, bool isWebgl2
,
1070 const uvec3
& uploadSize
) const;
1071 bool AssertCurrentUnpack(gl::GLContext
&, bool isWebgl2
) const;
1074 struct PixelUnpackStateWebgl final
: public PixelPackingState
{
1075 GLenum colorspaceConversion
=
1076 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL
;
1078 bool premultiplyAlpha
= false;
1079 bool requireFastPath
= false;
1080 uint8_t padding
= {};
1082 auto MutTiedFields() {
1083 return std::tuple_cat(PixelPackingState::MutTiedFields(),
1084 std::tie(colorspaceConversion
, flipY
,
1085 premultiplyAlpha
, requireFastPath
, padding
));
1089 struct ExplicitPixelPackingState final
{
1090 struct Metrics final
{
1091 uvec3 usedSize
= {};
1092 size_t bytesPerPixel
= 0;
1094 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1095 // ...aligned to ALIGNMENT.
1096 size_t bytesPerRowStride
= 0;
1098 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1099 size_t totalRows
= 0;
1101 // This ensures that no one else needs to do CheckedInt math.
1102 size_t totalBytesUsed
= 0;
1103 size_t totalBytesStrided
= 0;
1106 // It's so important that these aren't modified once evaluated.
1107 const PixelPackingState state
;
1108 const Metrics metrics
;
1110 static Result
<ExplicitPixelPackingState
, std::string
> ForUseWith(
1111 const PixelPackingState
&, GLenum target
, const uvec3
& subrectSize
,
1112 const webgl::PackingInfo
&, const Maybe
<size_t> bytesPerRowStrideOverride
);
1115 struct ReadPixelsDesc final
{
1118 PackingInfo pi
= {LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
};
1119 PixelPackingState packState
;
1121 auto MutTiedFields() { return std::tie(srcOffset
, size
, pi
, packState
); }
1124 } // namespace webgl
1128 struct TexUnpackBlobDesc final
{
1129 GLenum imageTarget
= LOCAL_GL_TEXTURE_2D
;
1131 gfxAlphaType srcAlphaType
= gfxAlphaType::NonPremult
;
1133 Maybe
<Span
<const uint8_t>> cpuData
;
1134 Maybe
<uint64_t> pboOffset
;
1136 Maybe
<uvec2
> structuredSrcSize
;
1137 RefPtr
<layers::Image
> image
;
1138 Maybe
<layers::SurfaceDescriptor
> sd
;
1139 RefPtr
<gfx::DataSourceSurface
> dataSurf
;
1141 webgl::PixelUnpackStateWebgl unpacking
;
1142 bool applyUnpackTransforms
= true;
1146 auto ExplicitUnpacking(const webgl::PackingInfo
& pi
,
1147 const Maybe
<size_t> bytesPerRowStrideOverride
) const {
1148 return ExplicitPixelPackingState::ForUseWith(this->unpacking
,
1149 this->imageTarget
, this->size
,
1150 pi
, bytesPerRowStrideOverride
);
1153 void Shrink(const webgl::PackingInfo
&);
1156 } // namespace webgl
1158 // ---------------------------------------
1161 template <typename T
, size_t N
>
1162 inline Range
<const T
> MakeRange(T (&arr
)[N
]) {
1166 template <typename T
>
1167 inline Range
<const T
> MakeRange(const dom::Sequence
<T
>& seq
) {
1168 return {seq
.Elements(), seq
.Length()};
1173 constexpr auto kUniversalAlignment
= alignof(std::max_align_t
);
1175 template <typename T
>
1176 inline size_t AlignmentOffset(const size_t alignment
, const T posOrPtr
) {
1177 MOZ_ASSERT(alignment
);
1178 const auto begin
= reinterpret_cast<uintptr_t>(posOrPtr
);
1179 const auto wholeMultiples
= (begin
+ (alignment
- 1)) / alignment
;
1180 const auto aligned
= wholeMultiples
* alignment
;
1181 return aligned
- begin
;
1184 template <typename T
>
1185 inline size_t ByteSize(const Range
<T
>& range
) {
1186 return range
.length() * sizeof(T
);
1191 Maybe
<webgl::ErrorInfo
> CheckBindBufferRange(
1192 const GLenum target
, const GLuint index
, const bool isBuffer
,
1193 const uint64_t offset
, const uint64_t size
, const webgl::Limits
& limits
);
1195 Maybe
<webgl::ErrorInfo
> CheckFramebufferAttach(const GLenum bindImageTarget
,
1196 const GLenum curTexTarget
,
1197 const uint32_t mipLevel
,
1198 const uint32_t zLayerBase
,
1199 const uint32_t zLayerCount
,
1200 const webgl::Limits
& limits
);
1202 Result
<webgl::VertAttribPointerCalculated
, webgl::ErrorInfo
>
1203 CheckVertexAttribPointer(bool isWebgl2
, const webgl::VertAttribPointerDesc
&);
1205 uint8_t ElemTypeComponents(GLenum elemType
);
1207 inline std::string
ToString(const nsACString
& text
) {
1208 return {text
.BeginReading(), text
.Length()};
1211 inline void Memcpy(const RangedPtr
<uint8_t>& destBytes
,
1212 const RangedPtr
<const uint8_t>& srcBytes
,
1213 const size_t byteSize
) {
1214 // Trigger range asserts
1215 (void)(srcBytes
+ byteSize
);
1216 (void)(destBytes
+ byteSize
);
1218 memcpy(destBytes
.get(), srcBytes
.get(), byteSize
);
1221 template <class T
, class U
>
1222 inline void Memcpy(const Range
<T
>* const destRange
,
1223 const RangedPtr
<U
>& srcBegin
) {
1224 Memcpy(destRange
->begin(), srcBegin
, destRange
->length());
1226 template <class T
, class U
>
1227 inline void Memcpy(const RangedPtr
<T
>* const destBegin
,
1228 const Range
<U
>& srcRange
) {
1229 Memcpy(destBegin
, srcRange
->begin(), srcRange
->length());
1232 template <typename Dst
, typename Src
>
1233 inline void Memcpy(const Span
<Dst
>* const dest
, const Span
<Src
>& src
) {
1234 MOZ_RELEASE_ASSERT(src
.size_bytes() >= dest
->size_bytes());
1235 MOZ_ASSERT(src
.size_bytes() == dest
->size_bytes());
1236 memcpy(dest
->data(), src
.data(), dest
->size_bytes());
1241 inline bool StartsWith(const std::string_view str
,
1242 const std::string_view part
) {
1243 return str
.find(part
) == 0;
1250 // In theory, this number can be unbounded based on the driver. However, no
1251 // driver appears to expose more than 8. We might as well stop there too, for
1253 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1254 inline constexpr size_t kMaxDrawBuffers
= 8;
1256 union UniformDataVal
{
1262 enum class ProvokingVertex
: GLenum
{
1263 FirstVertex
= LOCAL_GL_FIRST_VERTEX_CONVENTION
,
1264 LastVertex
= LOCAL_GL_LAST_VERTEX_CONVENTION
,
1267 } // namespace webgl
1270 inline constexpr bool IsEnumCase
<webgl::ProvokingVertex
>(
1271 const webgl::ProvokingVertex raw
) {
1273 case webgl::ProvokingVertex::FirstVertex
:
1274 case webgl::ProvokingVertex::LastVertex
:
1284 struct BufferAndIndex final
{
1285 const WebGLBuffer
* buffer
= nullptr;
1289 } // namespace webgl
1291 struct IndexedBufferBinding final
{
1292 RefPtr
<WebGLBuffer
> mBufferBinding
;
1293 uint64_t mRangeStart
= 0;
1294 uint64_t mRangeSize
= 0;
1296 IndexedBufferBinding();
1297 ~IndexedBufferBinding();
1299 uint64_t ByteCount() const;
1304 template <class... Args
>
1305 inline std::string
PrintfStdString(const char* const format
,
1306 const Args
&... args
) {
1307 const auto nsStr
= nsPrintfCString(format
, args
...);
1308 return ToString(nsStr
);
1311 inline const char* ToChars(const bool val
) {
1312 if (val
) return "true";
1317 struct ReinterpretToSpan
{
1318 template <class FromT
>
1319 static inline constexpr Span
<To
> From(const Span
<FromT
>& from
) {
1320 static_assert(sizeof(FromT
) == sizeof(To
));
1321 return {reinterpret_cast<To
*>(from
.data()), from
.size()};
1327 inline std::string
Join(Span
<const std::string
> ss
,
1328 const std::string_view
& delim
) {
1329 if (!ss
.size()) return "";
1330 auto ret
= std::string();
1332 auto chars
= delim
.size() * (ss
.size() - 1);
1333 for (const auto& s
: ss
) {
1341 for (const auto& s
: ss
) {
1348 inline std::string
ToStringWithCommas(uint64_t v
) {
1350 std::vector
<std::string
> chunks
;
1352 const auto chunk
= v
% 1000;
1354 chunks
.insert(chunks
.begin(), std::to_string(chunk
));
1356 return Join(chunks
, ",");
1363 std::unordered_map
<GLenum
, bool> MakeIsEnabledMap(bool webgl2
);
1365 static constexpr uint32_t kMaxClientWaitSyncTimeoutNS
=
1366 1000 * 1000 * 1000; // 1000ms in ns.
1368 } // namespace webgl
1369 } // namespace mozilla