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>
19 #include "ImageContainer.h"
20 #include "mozilla/Casting.h"
21 #include "mozilla/CheckedInt.h"
22 #include "mozilla/MathAlgorithms.h"
23 #include "mozilla/Range.h"
24 #include "mozilla/RefCounted.h"
25 #include "mozilla/Result.h"
26 #include "mozilla/ResultVariant.h"
27 #include "mozilla/gfx/2D.h"
28 #include "mozilla/gfx/BuildConstants.h"
29 #include "mozilla/gfx/Logging.h"
30 #include "mozilla/gfx/Point.h"
31 #include "mozilla/gfx/Rect.h"
32 #include "mozilla/ipc/Shmem.h"
33 #include "mozilla/layers/LayersSurfaces.h"
38 #include "mozilla/dom/WebGLRenderingContextBinding.h"
39 #include "mozilla/ipc/SharedMemoryBasic.h"
40 #include "TiedFields.h"
42 // Manual reflection of WebIDL typedefs that are different from their
43 // OpenGL counterparts.
44 using WebGLsizeiptr
= int64_t;
45 using WebGLintptr
= int64_t;
46 using WebGLboolean
= bool;
52 class GLContext
; // This is going to be needed a lot.
56 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
59 template <typename DestT
>
60 class ForbidNarrowing final
{
64 template <typename SrcT
>
65 MOZ_IMPLICIT
ForbidNarrowing(SrcT val
) : mVal(val
) {
67 std::numeric_limits
<SrcT
>::min() >= std::numeric_limits
<DestT
>::min(),
68 "SrcT must be narrower than DestT.");
70 std::numeric_limits
<SrcT
>::max() <= std::numeric_limits
<DestT
>::max(),
71 "SrcT must be narrower than DestT.");
74 explicit operator DestT() const { return mVal
; }
77 inline void* malloc(const ForbidNarrowing
<size_t> s
) {
78 return ::malloc(size_t(s
));
81 inline void* calloc(const ForbidNarrowing
<size_t> n
,
82 const ForbidNarrowing
<size_t> size
) {
83 return ::calloc(size_t(n
), size_t(size
));
88 // TODO: Remove this now-mere-alias.
89 template <typename From
>
90 inline auto AutoAssertCast(const From val
) {
91 return LazyAssertedCast(val
);
94 const char* GetEnumName(GLenum val
, const char* defaultRet
= "<unknown>");
95 std::string
EnumString(GLenum val
);
99 struct QueueParamTraits
;
100 class TexUnpackBytes
;
101 class TexUnpackImage
;
102 class TexUnpackSurface
;
105 class ClientWebGLContext
;
106 struct WebGLTexPboOffset
;
109 class WebGLFramebuffer
;
112 class WebGLRenderbuffer
;
117 class WebGLTransformFeedback
;
118 class WebGLVertexArray
;
122 class VRefCounted
: public RefCounted
<VRefCounted
> {
124 virtual ~VRefCounted() = default;
126 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
127 virtual const char* typeName() const = 0;
128 virtual size_t typeSize() const = 0;
135 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
136 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
137 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
138 * desktop OpenGL does not allow that.
140 enum class WebGLVertexAttrib0Status
: uint8_t {
141 Default
, // default status - no emulation needed
142 EmulatedUninitializedArray
, // need an artificial attrib 0 array, but
143 // contents may be left uninitialized
144 EmulatedInitializedArray
// need an artificial attrib 0 array, and contents
145 // must be initialized
149 * The formats that may participate, either as source or destination formats,
150 * in WebGL texture conversions. This includes:
151 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
152 * - additional formats provided by extensions, e.g. RGB32F
153 * - additional source formats, depending on browser details, used when
154 * uploading textures from DOM elements. See gfxImageSurface::Format().
156 enum class WebGLTexelFormat
: uint8_t {
157 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
160 // common value for formats for which format conversions are not supported
161 FormatNotSupportingAnyConversion
,
162 // dummy pseudo-format meaning "use the other format".
163 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
164 // is implicitly treated as being RGB8 itself.
168 A16F
, // OES_texture_half_float
169 A32F
, // OES_texture_float
171 R16F
, // OES_texture_half_float
172 R32F
, // OES_texture_float
175 RA16F
, // OES_texture_half_float
176 RA32F
, // OES_texture_float
184 RGB16F
, // OES_texture_half_float
185 RGB32F
, // OES_texture_float
190 RGBA16F
, // OES_texture_half_float
191 RGBA32F
, // OES_texture_float
192 // DOM element source only formats.
198 enum class WebGLTexImageFunc
: uint8_t {
207 enum class WebGLTexDimensions
: uint8_t { Tex2D
, Tex3D
};
209 // Please keep extensions in alphabetic order.
210 enum class WebGLExtensionID
: uint8_t {
211 ANGLE_instanced_arrays
,
213 EXT_color_buffer_float
,
214 EXT_color_buffer_half_float
,
215 EXT_disjoint_timer_query
,
218 EXT_shader_texture_lod
,
220 EXT_texture_compression_bptc
,
221 EXT_texture_compression_rgtc
,
222 EXT_texture_filter_anisotropic
,
225 OES_draw_buffers_indexed
,
226 OES_element_index_uint
,
227 OES_fbo_render_mipmap
,
228 OES_standard_derivatives
,
230 OES_texture_float_linear
,
231 OES_texture_half_float
,
232 OES_texture_half_float_linear
,
233 OES_vertex_array_object
,
235 WEBGL_color_buffer_float
,
236 WEBGL_compressed_texture_astc
,
237 WEBGL_compressed_texture_etc
,
238 WEBGL_compressed_texture_etc1
,
239 WEBGL_compressed_texture_pvrtc
,
240 WEBGL_compressed_texture_s3tc
,
241 WEBGL_compressed_texture_s3tc_srgb
,
242 WEBGL_debug_renderer_info
,
246 WEBGL_explicit_present
,
248 WEBGL_provoking_vertex
,
252 class UniqueBuffer final
{
253 // Like UniquePtr<>, but for void* and malloc/calloc/free.
254 void* mBuffer
= nullptr;
257 static inline UniqueBuffer
Take(void* buffer
) {
259 ret
.mBuffer
= buffer
;
263 UniqueBuffer() = default;
265 ~UniqueBuffer() { reset(); }
267 UniqueBuffer(UniqueBuffer
&& rhs
) { *this = std::move(rhs
); }
269 UniqueBuffer
& operator=(UniqueBuffer
&& rhs
) {
271 this->mBuffer
= rhs
.mBuffer
;
272 rhs
.mBuffer
= nullptr;
276 explicit operator bool() const { return bool(mBuffer
); }
278 void* get() const { return mBuffer
; }
281 // Believe it or not, when `free` unconditional, it was showing up
282 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
292 struct FormatUsageInfo
;
294 static constexpr GLenum kErrorPerfWarning
= 0x10001;
296 struct SampleableInfo final
{
297 const char* incompleteReason
= nullptr;
299 const webgl::FormatUsageInfo
* usage
= nullptr;
300 bool isDepthTexCompare
= false;
302 bool IsComplete() const { return bool(levels
); }
305 enum class AttribBaseType
: uint8_t {
306 Boolean
, // Can convert from anything.
307 Float
, // Also includes NormU?Int
311 webgl::AttribBaseType
ToAttribBaseType(GLenum
);
312 const char* ToString(AttribBaseType
);
314 enum class UniformBaseType
: uint8_t {
319 const char* ToString(UniformBaseType
);
321 using ObjectId
= uint64_t;
323 enum class BufferKind
: uint8_t {
333 struct FloatOrInt final
// For TexParameter[fi] and friends.
335 bool isFloat
= false;
336 uint8_t padding
[3] = {};
340 explicit FloatOrInt(GLint x
= 0) : isFloat(false), f(x
), i(x
) {}
342 explicit FloatOrInt(GLfloat x
) : isFloat(true), f(x
), i(roundf(x
)) {}
344 auto MutTiedFields() { return std::tie(isFloat
, padding
, f
, i
); }
349 struct WebGLContextOptions final
{
352 bool stencil
= false;
353 bool premultipliedAlpha
= true;
355 bool antialias
= true;
356 bool preserveDrawingBuffer
= false;
357 bool failIfMajorPerformanceCaveat
= false;
358 bool xrCompatible
= false;
360 dom::WebGLPowerPreference powerPreference
=
361 dom::WebGLPowerPreference::Default
;
362 bool ignoreColorSpace
= true;
363 dom::PredefinedColorSpace colorSpace
= dom::PredefinedColorSpace::Srgb
;
364 bool shouldResistFingerprinting
= true;
366 bool enableDebugRendererInfo
= false;
368 auto MutTiedFields() {
377 preserveDrawingBuffer
,
378 failIfMajorPerformanceCaveat
,
384 shouldResistFingerprinting
,
386 enableDebugRendererInfo
);
392 WebGLContextOptions();
393 WebGLContextOptions(const WebGLContextOptions
&) = default;
395 using Self
= WebGLContextOptions
;
396 friend bool operator==(const Self
& a
, const Self
& b
) {
397 return TiedFields(a
) == TiedFields(b
);
399 friend bool operator!=(const Self
& a
, const Self
& b
) { return !(a
== b
); }
404 inline ColorSpace2
ToColorSpace2(const dom::PredefinedColorSpace cs
) {
406 case dom::PredefinedColorSpace::Srgb
:
407 return ColorSpace2::SRGB
;
408 case dom::PredefinedColorSpace::Display_p3
:
409 return ColorSpace2::DISPLAY_P3
;
410 case dom::PredefinedColorSpace::EndGuard_
:
413 MOZ_CRASH("Exhaustive switch");
420 template <typename _T
>
427 auto MutTiedFields() { return std::tie(x
, y
); }
429 template <typename U
, typename V
>
430 static Maybe
<avec2
> From(const U _x
, const V _y
) {
431 const auto x
= CheckedInt
<T
>(_x
);
432 const auto y
= CheckedInt
<T
>(_y
);
433 if (!x
.isValid() || !y
.isValid()) return {};
434 return Some(avec2(x
.value(), y
.value()));
437 template <typename U
>
438 static auto From(const U
& val
) {
439 return From(val
.x
, val
.y
);
441 template <typename U
>
442 static auto FromSize(const U
& val
) {
443 return From(val
.width
, val
.height
);
447 avec2(const T _x
, const T _y
) : x(_x
), y(_y
) {}
449 bool operator==(const avec2
& rhs
) const { return x
== rhs
.x
&& y
== rhs
.y
; }
450 bool operator!=(const avec2
& rhs
) const { return !(*this == rhs
); }
453 avec2 operator OP(const avec2& rhs) const { \
454 return {x OP rhs.x, y OP rhs.y}; \
456 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
465 avec2
Clamp(const avec2
& min
, const avec2
& max
) const {
466 return {mozilla::Clamp(x
, min
.x
, max
.x
), mozilla::Clamp(y
, min
.y
, max
.y
)};
469 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
471 avec2
ClampMinMax(const avec2
& min
, const avec2
& max
) const {
472 const auto ClampScalar
= [](const T v
, const T min
, const T max
) {
473 return std::max(min
, std::min(v
, max
));
475 return {ClampScalar(x
, min
.x
, max
.x
), ClampScalar(y
, min
.y
, max
.y
)};
478 template <typename U
>
479 U
StaticCast() const {
480 return {static_cast<typename
U::T
>(x
), static_cast<typename
U::T
>(y
)};
484 template <typename T
>
485 avec2
<T
> MinExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
486 return {std::min(a
.x
, b
.x
), std::min(a
.y
, b
.y
)};
489 template <typename T
>
490 avec2
<T
> MaxExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
491 return {std::max(a
.x
, b
.x
), std::max(a
.y
, b
.y
)};
496 template <typename _T
>
504 auto MutTiedFields() { return std::tie(x
, y
, z
); }
506 template <typename U
, typename V
>
507 static Maybe
<avec3
> From(const U _x
, const V _y
, const V _z
) {
508 const auto x
= CheckedInt
<T
>(_x
);
509 const auto y
= CheckedInt
<T
>(_y
);
510 const auto z
= CheckedInt
<T
>(_z
);
511 if (!x
.isValid() || !y
.isValid() || !z
.isValid()) return {};
512 return Some(avec3(x
.value(), y
.value(), z
.value()));
515 template <typename U
>
516 static auto From(const U
& val
) {
517 return From(val
.x
, val
.y
, val
.z
);
521 avec3(const T _x
, const T _y
, const T _z
) : x(_x
), y(_y
), z(_z
) {}
523 bool operator==(const avec3
& rhs
) const {
524 return x
== rhs
.x
&& y
== rhs
.y
&& z
== rhs
.z
;
526 bool operator!=(const avec3
& rhs
) const { return !(*this == rhs
); }
529 using ivec2
= avec2
<int32_t>;
530 using ivec3
= avec3
<int32_t>;
531 using uvec2
= avec2
<uint32_t>;
532 using uvec3
= avec3
<uint32_t>;
534 inline ivec2
AsVec(const gfx::IntSize
& s
) { return {s
.width
, s
.height
}; }
540 struct PackingInfo final
{
544 auto MutTiedFields() { return std::tie(format
, type
); }
546 using Self
= PackingInfo
;
547 friend bool operator<(const Self
& a
, const Self
& b
) {
548 return TiedFields(a
) < TiedFields(b
);
550 friend bool operator==(const Self
& a
, const Self
& b
) {
551 return TiedFields(a
) == TiedFields(b
);
555 friend T
& operator<<(T
& s
, const PackingInfo
& pi
) {
556 s
<< "PackingInfo{format: " << EnumString(pi
.format
)
557 << ", type: " << EnumString(pi
.type
) << "}";
562 struct DriverUnpackInfo final
{
563 GLenum internalFormat
= 0;
564 GLenum unpackFormat
= 0;
565 GLenum unpackType
= 0;
567 PackingInfo
ToPacking() const { return {unpackFormat
, unpackType
}; }
572 template <typename E
>
578 struct BitRef final
{
582 explicit operator bool() const { return bits
.mBits
& mask
; }
584 auto& operator=(const bool val
) {
594 uint64_t Mask(const E i
) const {
595 return uint64_t{1} << static_cast<uint64_t>(i
);
599 BitRef
operator[](const E i
) { return {*this, Mask(i
)}; }
600 bool operator[](const E i
) const { return mBits
& Mask(i
); }
603 class ExtensionBits
: public EnumMask
<WebGLExtensionID
> {};
607 enum class ContextLossReason
: uint8_t {
613 inline bool ReadContextLossReason(const uint8_t val
,
614 ContextLossReason
* const out
) {
615 if (val
> static_cast<uint8_t>(ContextLossReason::Guilty
)) {
618 *out
= static_cast<ContextLossReason
>(val
);
624 struct InitContextDesc final
{
625 bool isWebgl2
= false;
626 bool resistFingerprinting
= false;
628 WebGLContextOptions options
;
629 uint32_t principalKey
= 0;
632 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs
= 4;
634 struct Limits final
{
635 ExtensionBits supportedExtensions
;
638 uint32_t maxTexUnits
= 0;
639 uint32_t maxTex2dSize
= 0;
640 uint32_t maxTexCubeSize
= 0;
641 uint32_t maxVertexAttribs
= 0;
642 uint32_t maxViewportDim
= 0;
643 std::array
<float, 2> pointSizeRange
= {{1, 1}};
644 std::array
<float, 2> lineWidthRange
= {{1, 1}};
647 uint32_t maxTexArrayLayers
= 0;
648 uint32_t maxTex3dSize
= 0;
649 uint32_t maxUniformBufferBindings
= 0;
650 uint32_t uniformBufferOffsetAlignment
= 0;
653 bool astcHdr
= false;
654 uint32_t maxColorDrawBuffers
= 1;
655 uint64_t queryCounterBitsTimeElapsed
= 0;
656 uint64_t queryCounterBitsTimestamp
= 0;
657 uint32_t maxMultiviewLayers
= 0;
660 struct InitContextResult final
{
662 WebGLContextOptions options
;
663 webgl::Limits limits
;
664 EnumMask
<layers::SurfaceDescriptor::Type
> uploadableSdTypes
;
670 struct ErrorInfo final
{
675 struct ShaderPrecisionFormat final
{
683 enum class LossStatus
{
693 struct CompileResult final
{
696 nsCString translatedSource
;
697 bool success
= false;
702 struct OpaqueFramebufferOptions final
{
703 bool depthStencil
= true;
704 bool antialias
= true;
711 struct SwapChainOptions final
{
712 layers::RemoteTextureId remoteTextureId
;
713 layers::RemoteTextureOwnerId remoteTextureOwnerId
;
715 bool forceAsyncPresent
= false;
716 // Pad to sizeof(u64):
717 uint16_t padding1
= 0;
718 uint32_t padding2
= 0;
720 auto MutTiedFields() {
721 return std::tie(remoteTextureId
, remoteTextureOwnerId
, bgra
,
722 forceAsyncPresent
, padding1
, padding2
);
729 GLenum elemType
= 0; // `type`
730 uint32_t elemCount
= 0; // `size`
734 struct ActiveAttribInfo final
: public ActiveInfo
{
735 int32_t location
= -1;
736 AttribBaseType baseType
= AttribBaseType::Float
;
739 struct ActiveUniformInfo final
: public ActiveInfo
{
740 std::unordered_map
<uint32_t, uint32_t>
741 locByIndex
; // Uniform array locations are sparse.
742 int32_t block_index
= -1;
743 int32_t block_offset
= -1; // In block, offset.
744 int32_t block_arrayStride
= -1;
745 int32_t block_matrixStride
= -1;
746 bool block_isRowMajor
= false;
749 struct ActiveUniformBlockInfo final
{
751 // BLOCK_BINDING is dynamic state
752 uint32_t dataSize
= 0;
753 std::vector
<uint32_t> activeUniformIndices
;
754 bool referencedByVertexShader
= false;
755 bool referencedByFragmentShader
= false;
758 struct LinkActiveInfo final
{
759 std::vector
<ActiveAttribInfo
> activeAttribs
;
760 std::vector
<ActiveUniformInfo
> activeUniforms
;
761 std::vector
<ActiveUniformBlockInfo
> activeUniformBlocks
;
762 std::vector
<ActiveInfo
> activeTfVaryings
;
765 struct LinkResult final
{
768 bool success
= false;
769 LinkActiveInfo active
;
770 GLenum tfBufferMode
= 0;
775 /// 4x32-bit primitives, with a type tag.
776 struct TypedQuad final
{
777 alignas(alignof(float)) std::array
<uint8_t, 4 * sizeof(float)> data
= {};
778 webgl::AttribBaseType type
= webgl::AttribBaseType::Float
;
779 uint8_t padding
[3] = {};
781 constexpr auto MutTiedFields() { return std::tie(data
, type
, padding
); }
784 /// [1-16]x32-bit primitives, with a type tag.
785 struct GetUniformData final
{
786 alignas(alignof(float)) uint8_t data
[4 * 4 * sizeof(float)] = {};
790 struct FrontBufferSnapshotIpc final
{
792 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
795 struct ReadPixelsResult
{
796 gfx::IntRect subrect
= {};
797 size_t byteStride
= 0;
800 struct ReadPixelsResultIpc final
: public ReadPixelsResult
{
801 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
804 struct VertAttribPointerDesc final
{
805 bool intFunc
= false;
806 uint8_t channels
= 4;
807 bool normalized
= false;
808 uint8_t byteStrideOrZero
= 0;
809 GLenum type
= LOCAL_GL_FLOAT
;
810 uint64_t byteOffset
= 0;
812 auto MutTiedFields() {
813 return std::tie(intFunc
, channels
, normalized
, byteStrideOrZero
, type
,
818 struct VertAttribPointerCalculated final
{
819 uint8_t byteSize
= 4 * 4;
820 uint8_t byteStride
= 4 * 4; // at-most 255
821 webgl::AttribBaseType baseType
= webgl::AttribBaseType::Float
;
827 * Represents a block of memory that it may or may not own. The
828 * inner data type must be trivially copyable by memcpy.
830 template <typename T
= uint8_t>
831 class RawBuffer final
{
832 const T
* mBegin
= nullptr;
837 using ElementType
= T
;
840 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
842 explicit RawBuffer(const Range
<const T
>& data
, UniqueBuffer
&& owned
= {})
843 : mBegin(data
.begin().get()),
845 mOwned(std::move(owned
)) {}
847 explicit RawBuffer(const size_t len
) : mLen(len
) {}
849 ~RawBuffer() = default;
851 Range
<const T
> Data() const { return {mBegin
, mLen
}; }
852 const auto& begin() const { return mBegin
; }
853 const auto& size() const { return mLen
; }
855 void Shrink(const size_t newLen
) {
856 if (mLen
<= newLen
) return;
860 RawBuffer() = default;
862 RawBuffer(const RawBuffer
&) = delete;
863 RawBuffer
& operator=(const RawBuffer
&) = delete;
865 RawBuffer(RawBuffer
&&) = default;
866 RawBuffer
& operator=(RawBuffer
&&) = default;
870 inline Range
<T
> ShmemRange(const mozilla::ipc::Shmem
& shmem
) {
871 return {shmem
.get
<T
>(), shmem
.Size
<T
>()};
876 template <typename C
, typename K
>
877 inline auto MaybeFind(C
& container
, const K
& key
)
878 -> decltype(&(container
.find(key
)->second
)) {
879 const auto itr
= container
.find(key
);
880 if (itr
== container
.end()) return nullptr;
881 return &(itr
->second
);
884 template <typename C
, typename K
>
885 inline typename
C::mapped_type
Find(
886 const C
& container
, const K
& key
,
887 const typename
C::mapped_type notFound
= {}) {
888 const auto itr
= container
.find(key
);
889 if (itr
== container
.end()) return notFound
;
895 template <typename T
, typename U
>
896 inline Maybe
<T
> MaybeAs(const U val
) {
897 const auto checked
= CheckedInt
<T
>(val
);
898 if (!checked
.isValid()) return {};
899 return Some(checked
.value());
904 inline GLenum
IsTexImageTarget(const GLenum imageTarget
) {
905 switch (imageTarget
) {
906 case LOCAL_GL_TEXTURE_2D
:
907 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
908 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
909 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
910 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
911 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
912 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
913 case LOCAL_GL_TEXTURE_3D
:
914 case LOCAL_GL_TEXTURE_2D_ARRAY
:
920 inline GLenum
ImageToTexTarget(const GLenum imageTarget
) {
921 switch (imageTarget
) {
922 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
923 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
924 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
925 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
926 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
927 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
928 return LOCAL_GL_TEXTURE_CUBE_MAP
;
930 if (IsTexImageTarget(imageTarget
)) {
936 inline bool IsTexTarget3D(const GLenum texTarget
) {
938 case LOCAL_GL_TEXTURE_2D_ARRAY
:
939 case LOCAL_GL_TEXTURE_3D
:
953 class OffscreenCanvas
;
956 struct TexImageSource
{
957 const dom::ArrayBufferView
* mView
= nullptr;
958 GLuint mViewElemOffset
= 0;
959 GLuint mViewElemLengthOverride
= 0;
961 const WebGLintptr
* mPboOffset
= nullptr;
963 const dom::ImageBitmap
* mImageBitmap
= nullptr;
964 const dom::ImageData
* mImageData
= nullptr;
966 const dom::OffscreenCanvas
* mOffscreenCanvas
= nullptr;
968 const dom::Element
* mDomElem
= nullptr;
969 ErrorResult
* mOut_error
= nullptr;
974 template <class DerivedT
>
976 bool operator!=(const DerivedT
& rhs
) const {
977 const auto self
= reinterpret_cast<const DerivedT
*>(this);
978 return !(*self
== rhs
);
982 struct PixelPackingState
: public DeriveNotEq
<PixelPackingState
> {
983 uint32_t alignmentInTypeElems
= 4; // ALIGNMENT isn't naive byte alignment!
984 uint32_t rowLength
= 0;
985 uint32_t imageHeight
= 0;
986 uint32_t skipPixels
= 0;
987 uint32_t skipRows
= 0;
988 uint32_t skipImages
= 0;
990 auto MutTiedFields() {
991 return std::tie(alignmentInTypeElems
, rowLength
, imageHeight
, skipPixels
,
992 skipRows
, skipImages
);
995 using Self
= PixelPackingState
;
996 friend bool operator==(const Self
& a
, const Self
& b
) {
997 return TiedFields(a
) == TiedFields(b
);
1000 static void AssertDefaultUnpack(gl::GLContext
& gl
, const bool isWebgl2
) {
1001 PixelPackingState
{}.AssertCurrentUnpack(gl
, isWebgl2
);
1004 void ApplyUnpack(gl::GLContext
&, bool isWebgl2
,
1005 const uvec3
& uploadSize
) const;
1006 bool AssertCurrentUnpack(gl::GLContext
&, bool isWebgl2
) const;
1009 struct PixelUnpackStateWebgl final
: public PixelPackingState
{
1010 GLenum colorspaceConversion
=
1011 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL
;
1013 bool premultiplyAlpha
= false;
1014 bool requireFastPath
= false;
1015 uint8_t padding
= {};
1017 auto MutTiedFields() {
1018 return std::tuple_cat(PixelPackingState::MutTiedFields(),
1019 std::tie(colorspaceConversion
, flipY
,
1020 premultiplyAlpha
, requireFastPath
, padding
));
1024 struct ExplicitPixelPackingState final
{
1025 struct Metrics final
{
1026 uvec3 usedSize
= {};
1027 size_t bytesPerPixel
= 0;
1029 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1030 // ...aligned to ALIGNMENT.
1031 size_t bytesPerRowStride
= 0;
1033 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1034 size_t totalRows
= 0;
1036 // This ensures that no one else needs to do CheckedInt math.
1037 size_t totalBytesUsed
= 0;
1038 size_t totalBytesStrided
= 0;
1041 // It's so important that these aren't modified once evaluated.
1042 const PixelPackingState state
;
1043 const Metrics metrics
;
1045 static Result
<ExplicitPixelPackingState
, std::string
> ForUseWith(
1046 const PixelPackingState
&, GLenum target
, const uvec3
& subrectSize
,
1047 const webgl::PackingInfo
&, const Maybe
<size_t> bytesPerRowStrideOverride
);
1050 struct ReadPixelsDesc final
{
1053 PackingInfo pi
= {LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
};
1054 PixelPackingState packState
;
1056 auto MutTiedFields() { return std::tie(srcOffset
, size
, pi
, packState
); }
1059 } // namespace webgl
1063 struct TexUnpackBlobDesc final
{
1064 GLenum imageTarget
= LOCAL_GL_TEXTURE_2D
;
1066 gfxAlphaType srcAlphaType
= gfxAlphaType::NonPremult
;
1068 Maybe
<RawBuffer
<>> cpuData
;
1069 Maybe
<uint64_t> pboOffset
;
1071 Maybe
<uvec2
> structuredSrcSize
;
1072 RefPtr
<layers::Image
> image
;
1073 Maybe
<layers::SurfaceDescriptor
> sd
;
1074 RefPtr
<gfx::DataSourceSurface
> dataSurf
;
1076 webgl::PixelUnpackStateWebgl unpacking
;
1077 bool applyUnpackTransforms
= true;
1081 auto ExplicitUnpacking(const webgl::PackingInfo
& pi
,
1082 const Maybe
<size_t> bytesPerRowStrideOverride
) const {
1083 return ExplicitPixelPackingState::ForUseWith(this->unpacking
,
1084 this->imageTarget
, this->size
,
1085 pi
, bytesPerRowStrideOverride
);
1088 void Shrink(const webgl::PackingInfo
&);
1091 } // namespace webgl
1093 // ---------------------------------------
1096 template <typename T
, size_t N
>
1097 inline Range
<const T
> MakeRange(T (&arr
)[N
]) {
1101 template <typename T
>
1102 inline Range
<const T
> MakeRange(const dom::Sequence
<T
>& seq
) {
1103 return {seq
.Elements(), seq
.Length()};
1106 template <typename T
>
1107 inline Range
<const T
> MakeRange(const RawBuffer
<T
>& from
) {
1111 // abv = ArrayBufferView
1112 template <typename T
>
1113 inline auto MakeRangeAbv(const T
& abv
)
1114 -> Range
<const typename
T::element_type
> {
1116 return {abv
.Data(), abv
.Length()};
1121 constexpr auto kUniversalAlignment
= alignof(std::max_align_t
);
1123 template <typename T
>
1124 inline size_t AlignmentOffset(const size_t alignment
, const T posOrPtr
) {
1125 MOZ_ASSERT(alignment
);
1126 const auto begin
= reinterpret_cast<uintptr_t>(posOrPtr
);
1127 const auto wholeMultiples
= (begin
+ (alignment
- 1)) / alignment
;
1128 const auto aligned
= wholeMultiples
* alignment
;
1129 return aligned
- begin
;
1132 template <typename T
>
1133 inline size_t ByteSize(const Range
<T
>& range
) {
1134 return range
.length() * sizeof(T
);
1137 Maybe
<Range
<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView
& view
,
1139 GLuint elemCountOverride
);
1143 template <typename T
>
1144 RawBuffer
<T
> RawBufferView(const Range
<T
>& range
) {
1145 return RawBuffer
<T
>{range
};
1150 Maybe
<webgl::ErrorInfo
> CheckBindBufferRange(
1151 const GLenum target
, const GLuint index
, const bool isBuffer
,
1152 const uint64_t offset
, const uint64_t size
, const webgl::Limits
& limits
);
1154 Maybe
<webgl::ErrorInfo
> CheckFramebufferAttach(const GLenum bindImageTarget
,
1155 const GLenum curTexTarget
,
1156 const uint32_t mipLevel
,
1157 const uint32_t zLayerBase
,
1158 const uint32_t zLayerCount
,
1159 const webgl::Limits
& limits
);
1161 Result
<webgl::VertAttribPointerCalculated
, webgl::ErrorInfo
>
1162 CheckVertexAttribPointer(bool isWebgl2
, const webgl::VertAttribPointerDesc
&);
1164 uint8_t ElemTypeComponents(GLenum elemType
);
1166 inline std::string
ToString(const nsACString
& text
) {
1167 return {text
.BeginReading(), text
.Length()};
1170 inline void Memcpy(const RangedPtr
<uint8_t>& destBytes
,
1171 const RangedPtr
<const uint8_t>& srcBytes
,
1172 const size_t byteSize
) {
1173 // Trigger range asserts
1174 (void)(srcBytes
+ byteSize
);
1175 (void)(destBytes
+ byteSize
);
1177 memcpy(destBytes
.get(), srcBytes
.get(), byteSize
);
1180 template <class T
, class U
>
1181 inline void Memcpy(const Range
<T
>* const destRange
,
1182 const RangedPtr
<U
>& srcBegin
) {
1183 Memcpy(destRange
->begin(), srcBegin
, destRange
->length());
1185 template <class T
, class U
>
1186 inline void Memcpy(const RangedPtr
<T
>* const destBegin
,
1187 const Range
<U
>& srcRange
) {
1188 Memcpy(destBegin
, srcRange
->begin(), srcRange
->length());
1193 inline bool StartsWith(const std::string_view str
,
1194 const std::string_view part
) {
1195 return str
.find(part
) == 0;
1202 // In theory, this number can be unbounded based on the driver. However, no
1203 // driver appears to expose more than 8. We might as well stop there too, for
1205 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1206 inline constexpr size_t kMaxDrawBuffers
= 8;
1208 union UniformDataVal
{
1214 enum class ProvokingVertex
: GLenum
{
1215 FirstVertex
= LOCAL_GL_FIRST_VERTEX_CONVENTION
,
1216 LastVertex
= LOCAL_GL_LAST_VERTEX_CONVENTION
,
1218 inline constexpr bool IsEnumCase(const ProvokingVertex raw
) {
1220 case ProvokingVertex::FirstVertex
:
1221 case ProvokingVertex::LastVertex
:
1228 inline constexpr std::optional
<E
> AsEnumCase(
1229 const std::underlying_type_t
<E
> raw
) {
1230 const auto ret
= static_cast<E
>(raw
);
1231 if (!IsEnumCase(ret
)) return {};
1235 } // namespace webgl
1237 } // namespace mozilla