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 <type_traits>
12 #include <unordered_map>
16 #include "ImageContainer.h"
17 #include "mozilla/Casting.h"
18 #include "mozilla/CheckedInt.h"
19 #include "mozilla/MathAlgorithms.h"
20 #include "mozilla/Range.h"
21 #include "mozilla/RefCounted.h"
22 #include "mozilla/Result.h"
23 #include "mozilla/ResultVariant.h"
24 #include "mozilla/gfx/2D.h"
25 #include "mozilla/gfx/BuildConstants.h"
26 #include "mozilla/gfx/Point.h"
27 #include "mozilla/gfx/Rect.h"
28 #include "mozilla/ipc/Shmem.h"
29 #include "mozilla/layers/LayersSurfaces.h"
34 #include "mozilla/dom/WebGLRenderingContextBinding.h"
35 #include "mozilla/ipc/SharedMemoryBasic.h"
37 // Manual reflection of WebIDL typedefs that are different from their
38 // OpenGL counterparts.
39 using WebGLsizeiptr
= int64_t;
40 using WebGLintptr
= int64_t;
41 using WebGLboolean
= bool;
47 class GLContext
; // This is going to be needed a lot.
51 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
54 template <typename DestT
>
55 class ForbidNarrowing final
{
59 template <typename SrcT
>
60 MOZ_IMPLICIT
ForbidNarrowing(SrcT val
) : mVal(val
) {
62 std::numeric_limits
<SrcT
>::min() >= std::numeric_limits
<DestT
>::min(),
63 "SrcT must be narrower than DestT.");
65 std::numeric_limits
<SrcT
>::max() <= std::numeric_limits
<DestT
>::max(),
66 "SrcT must be narrower than DestT.");
69 explicit operator DestT() const { return mVal
; }
72 inline void* malloc(const ForbidNarrowing
<size_t> s
) {
73 return ::malloc(size_t(s
));
76 inline void* calloc(const ForbidNarrowing
<size_t> n
,
77 const ForbidNarrowing
<size_t> size
) {
78 return ::calloc(size_t(n
), size_t(size
));
85 template <typename From
>
86 class AutoAssertCastT final
{
90 explicit AutoAssertCastT(const From val
) : mVal(val
) {}
92 template <typename To
>
94 return AssertedCast
<To
>(mVal
);
100 template <typename From
>
101 inline auto AutoAssertCast(const From val
) {
102 return detail::AutoAssertCastT
<From
>(val
);
106 template <typename T
>
107 struct QueueParamTraits
;
108 class TexUnpackBytes
;
109 class TexUnpackImage
;
110 class TexUnpackSurface
;
113 class ClientWebGLContext
;
114 struct WebGLTexPboOffset
;
117 class WebGLFramebuffer
;
120 class WebGLRenderbuffer
;
125 class WebGLTransformFeedback
;
126 class WebGLVertexArray
;
130 class VRefCounted
: public RefCounted
<VRefCounted
> {
132 virtual ~VRefCounted() = default;
134 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
135 virtual const char* typeName() const = 0;
136 virtual size_t typeSize() const = 0;
143 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
144 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
145 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
146 * desktop OpenGL does not allow that.
148 enum class WebGLVertexAttrib0Status
: uint8_t {
149 Default
, // default status - no emulation needed
150 EmulatedUninitializedArray
, // need an artificial attrib 0 array, but
151 // contents may be left uninitialized
152 EmulatedInitializedArray
// need an artificial attrib 0 array, and contents
153 // must be initialized
157 * The formats that may participate, either as source or destination formats,
158 * in WebGL texture conversions. This includes:
159 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
160 * - additional formats provided by extensions, e.g. RGB32F
161 * - additional source formats, depending on browser details, used when
162 * uploading textures from DOM elements. See gfxImageSurface::Format().
164 enum class WebGLTexelFormat
: uint8_t {
165 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
168 // common value for formats for which format conversions are not supported
169 FormatNotSupportingAnyConversion
,
170 // dummy pseudo-format meaning "use the other format".
171 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
172 // is implicitly treated as being RGB8 itself.
176 A16F
, // OES_texture_half_float
177 A32F
, // OES_texture_float
179 R16F
, // OES_texture_half_float
180 R32F
, // OES_texture_float
183 RA16F
, // OES_texture_half_float
184 RA32F
, // OES_texture_float
192 RGB16F
, // OES_texture_half_float
193 RGB32F
, // OES_texture_float
198 RGBA16F
, // OES_texture_half_float
199 RGBA32F
, // OES_texture_float
200 // DOM element source only formats.
206 enum class WebGLTexImageFunc
: uint8_t {
215 enum class WebGLTexDimensions
: uint8_t { Tex2D
, Tex3D
};
217 // Please keep extensions in alphabetic order.
218 enum class WebGLExtensionID
: uint8_t {
219 ANGLE_instanced_arrays
,
221 EXT_color_buffer_float
,
222 EXT_color_buffer_half_float
,
223 EXT_disjoint_timer_query
,
226 EXT_shader_texture_lod
,
228 EXT_texture_compression_bptc
,
229 EXT_texture_compression_rgtc
,
230 EXT_texture_filter_anisotropic
,
233 OES_draw_buffers_indexed
,
234 OES_element_index_uint
,
235 OES_fbo_render_mipmap
,
236 OES_standard_derivatives
,
238 OES_texture_float_linear
,
239 OES_texture_half_float
,
240 OES_texture_half_float_linear
,
241 OES_vertex_array_object
,
243 WEBGL_color_buffer_float
,
244 WEBGL_compressed_texture_astc
,
245 WEBGL_compressed_texture_etc
,
246 WEBGL_compressed_texture_etc1
,
247 WEBGL_compressed_texture_pvrtc
,
248 WEBGL_compressed_texture_s3tc
,
249 WEBGL_compressed_texture_s3tc_srgb
,
250 WEBGL_debug_renderer_info
,
254 WEBGL_explicit_present
,
259 class UniqueBuffer final
{
260 // Like UniquePtr<>, but for void* and malloc/calloc/free.
261 void* mBuffer
= nullptr;
264 static inline UniqueBuffer
Take(void* buffer
) {
266 ret
.mBuffer
= buffer
;
270 UniqueBuffer() = default;
272 ~UniqueBuffer() { reset(); }
274 UniqueBuffer(UniqueBuffer
&& rhs
) { *this = std::move(rhs
); }
276 UniqueBuffer
& operator=(UniqueBuffer
&& rhs
) {
278 this->mBuffer
= rhs
.mBuffer
;
279 rhs
.mBuffer
= nullptr;
283 explicit operator bool() const { return bool(mBuffer
); }
285 void* get() const { return mBuffer
; }
288 // Believe it or not, when `free` unconditional, it was showing up
289 // in profiles, nearly 20% of time spent in MethodDispatcther<UniformData>
299 struct FormatUsageInfo
;
301 static constexpr GLenum kErrorPerfWarning
= 0x10001;
303 struct SampleableInfo final
{
304 const char* incompleteReason
= nullptr;
306 const webgl::FormatUsageInfo
* usage
= nullptr;
307 bool isDepthTexCompare
= false;
309 bool IsComplete() const { return bool(levels
); }
312 enum class AttribBaseType
: uint8_t {
313 Boolean
, // Can convert from anything.
314 Float
, // Also includes NormU?Int
318 webgl::AttribBaseType
ToAttribBaseType(GLenum
);
319 const char* ToString(AttribBaseType
);
321 enum class UniformBaseType
: uint8_t {
326 const char* ToString(UniformBaseType
);
328 using ObjectId
= uint64_t;
330 enum class BufferKind
: uint8_t {
340 struct FloatOrInt final
// For TexParameter[fi] and friends.
346 explicit FloatOrInt(GLint x
= 0) : isFloat(false), f(x
), i(x
) {}
348 explicit FloatOrInt(GLfloat x
) : isFloat(true), f(x
), i(roundf(x
)) {}
350 FloatOrInt
& operator=(const FloatOrInt
& x
) {
351 memcpy(this, &x
, sizeof(x
));
356 struct WebGLContextOptions
{
359 bool stencil
= false;
360 bool premultipliedAlpha
= true;
361 bool antialias
= true;
362 bool preserveDrawingBuffer
= false;
363 bool failIfMajorPerformanceCaveat
= false;
364 bool xrCompatible
= false;
365 dom::WebGLPowerPreference powerPreference
=
366 dom::WebGLPowerPreference::Default
;
367 Maybe
<dom::PredefinedColorSpace
> colorSpace
;
368 bool shouldResistFingerprinting
= true;
369 bool enableDebugRendererInfo
= false;
371 WebGLContextOptions();
372 WebGLContextOptions(const WebGLContextOptions
&) = default;
374 bool operator==(const WebGLContextOptions
&) const;
375 bool operator!=(const WebGLContextOptions
& rhs
) const {
376 return !(*this == rhs
);
382 inline ColorSpace2
ToColorSpace2(const Maybe
<dom::PredefinedColorSpace
> cs
) {
384 return ColorSpace2::UNKNOWN
;
388 case dom::PredefinedColorSpace::Srgb
:
389 return ColorSpace2::SRGB
;
390 case dom::PredefinedColorSpace::Display_p3
:
391 return ColorSpace2::DISPLAY_P3
;
392 case dom::PredefinedColorSpace::EndGuard_
:
395 MOZ_CRASH("Exhaustive switch");
402 template <typename _T
>
409 template <typename U
, typename V
>
410 static Maybe
<avec2
> From(const U _x
, const V _y
) {
411 const auto x
= CheckedInt
<T
>(_x
);
412 const auto y
= CheckedInt
<T
>(_y
);
413 if (!x
.isValid() || !y
.isValid()) return {};
414 return Some(avec2(x
.value(), y
.value()));
417 template <typename U
>
418 static auto From(const U
& val
) {
419 return From(val
.x
, val
.y
);
421 template <typename U
>
422 static auto FromSize(const U
& val
) {
423 return From(val
.width
, val
.height
);
427 avec2(const T _x
, const T _y
) : x(_x
), y(_y
) {}
429 bool operator==(const avec2
& rhs
) const { return x
== rhs
.x
&& y
== rhs
.y
; }
430 bool operator!=(const avec2
& rhs
) const { return !(*this == rhs
); }
433 avec2 operator OP(const avec2& rhs) const { \
434 return {x OP rhs.x, y OP rhs.y}; \
436 avec2 operator OP(const T rhs) const { return {x OP rhs, y OP rhs}; }
445 avec2
Clamp(const avec2
& min
, const avec2
& max
) const {
446 return {mozilla::Clamp(x
, min
.x
, max
.x
), mozilla::Clamp(y
, min
.y
, max
.y
)};
449 // mozilla::Clamp doesn't work on floats, so be clear that this is a min+max
451 avec2
ClampMinMax(const avec2
& min
, const avec2
& max
) const {
452 const auto ClampScalar
= [](const T v
, const T min
, const T max
) {
453 return std::max(min
, std::min(v
, max
));
455 return {ClampScalar(x
, min
.x
, max
.x
), ClampScalar(y
, min
.y
, max
.y
)};
458 template <typename U
>
459 U
StaticCast() const {
460 return {static_cast<typename
U::T
>(x
), static_cast<typename
U::T
>(y
)};
464 template <typename T
>
465 avec2
<T
> MinExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
466 return {std::min(a
.x
, b
.x
), std::min(a
.y
, b
.y
)};
469 template <typename T
>
470 avec2
<T
> MaxExtents(const avec2
<T
>& a
, const avec2
<T
>& b
) {
471 return {std::max(a
.x
, b
.x
), std::max(a
.y
, b
.y
)};
476 template <typename _T
>
484 template <typename U
, typename V
>
485 static Maybe
<avec3
> From(const U _x
, const V _y
, const V _z
) {
486 const auto x
= CheckedInt
<T
>(_x
);
487 const auto y
= CheckedInt
<T
>(_y
);
488 const auto z
= CheckedInt
<T
>(_z
);
489 if (!x
.isValid() || !y
.isValid() || !z
.isValid()) return {};
490 return Some(avec3(x
.value(), y
.value(), z
.value()));
493 template <typename U
>
494 static auto From(const U
& val
) {
495 return From(val
.x
, val
.y
, val
.z
);
499 avec3(const T _x
, const T _y
, const T _z
) : x(_x
), y(_y
), z(_z
) {}
501 bool operator==(const avec3
& rhs
) const {
502 return x
== rhs
.x
&& y
== rhs
.y
&& z
== rhs
.z
;
504 bool operator!=(const avec3
& rhs
) const { return !(*this == rhs
); }
507 using ivec2
= avec2
<int32_t>;
508 using ivec3
= avec3
<int32_t>;
509 using uvec2
= avec2
<uint32_t>;
510 using uvec3
= avec3
<uint32_t>;
512 inline ivec2
AsVec(const gfx::IntSize
& s
) { return {s
.width
, s
.height
}; }
518 struct PackingInfo final
{
522 bool operator<(const PackingInfo
& x
) const {
523 if (format
!= x
.format
) return format
< x
.format
;
525 return type
< x
.type
;
528 bool operator==(const PackingInfo
& x
) const {
529 return (format
== x
.format
&& type
== x
.type
);
533 struct DriverUnpackInfo final
{
534 GLenum internalFormat
= 0;
535 GLenum unpackFormat
= 0;
536 GLenum unpackType
= 0;
538 PackingInfo
ToPacking() const { return {unpackFormat
, unpackType
}; }
543 template <typename E
>
549 struct BitRef final
{
553 explicit operator bool() const { return bits
.mBits
& mask
; }
555 auto& operator=(const bool val
) {
565 uint64_t Mask(const E i
) const {
566 return uint64_t{1} << static_cast<uint64_t>(i
);
570 BitRef
operator[](const E i
) { return {*this, Mask(i
)}; }
571 bool operator[](const E i
) const { return mBits
& Mask(i
); }
574 class ExtensionBits
: public EnumMask
<WebGLExtensionID
> {};
578 enum class ContextLossReason
: uint8_t {
584 inline bool ReadContextLossReason(const uint8_t val
,
585 ContextLossReason
* const out
) {
586 if (val
> static_cast<uint8_t>(ContextLossReason::Guilty
)) {
589 *out
= static_cast<ContextLossReason
>(val
);
595 struct InitContextDesc final
{
596 bool isWebgl2
= false;
597 bool resistFingerprinting
= false;
599 WebGLContextOptions options
;
600 uint32_t principalKey
= 0;
603 constexpr uint32_t kMaxTransformFeedbackSeparateAttribs
= 4;
605 struct Limits final
{
606 ExtensionBits supportedExtensions
;
609 uint32_t maxTexUnits
= 0;
610 uint32_t maxTex2dSize
= 0;
611 uint32_t maxTexCubeSize
= 0;
612 uint32_t maxVertexAttribs
= 0;
613 uint32_t maxViewportDim
= 0;
614 std::array
<float, 2> pointSizeRange
= {{1, 1}};
615 std::array
<float, 2> lineWidthRange
= {{1, 1}};
618 uint32_t maxTexArrayLayers
= 0;
619 uint32_t maxTex3dSize
= 0;
620 uint32_t maxUniformBufferBindings
= 0;
621 uint32_t uniformBufferOffsetAlignment
= 0;
624 bool astcHdr
= false;
625 uint32_t maxColorDrawBuffers
= 1;
626 uint64_t queryCounterBitsTimeElapsed
= 0;
627 uint64_t queryCounterBitsTimestamp
= 0;
628 uint32_t maxMultiviewLayers
= 0;
631 struct InitContextResult final
{
633 WebGLContextOptions options
;
634 webgl::Limits limits
;
635 EnumMask
<layers::SurfaceDescriptor::Type
> uploadableSdTypes
;
640 struct ErrorInfo final
{
645 struct ShaderPrecisionFormat final
{
653 enum class LossStatus
{
663 struct CompileResult final
{
666 nsCString translatedSource
;
667 bool success
= false;
672 struct OpaqueFramebufferOptions final
{
673 bool depthStencil
= true;
674 bool antialias
= true;
681 struct SwapChainOptions final
{
688 GLenum elemType
= 0; // `type`
689 uint32_t elemCount
= 0; // `size`
693 struct ActiveAttribInfo final
: public ActiveInfo
{
694 int32_t location
= -1;
695 AttribBaseType baseType
= AttribBaseType::Float
;
698 struct ActiveUniformInfo final
: public ActiveInfo
{
699 std::unordered_map
<uint32_t, uint32_t>
700 locByIndex
; // Uniform array locations are sparse.
701 int32_t block_index
= -1;
702 int32_t block_offset
= -1; // In block, offset.
703 int32_t block_arrayStride
= -1;
704 int32_t block_matrixStride
= -1;
705 bool block_isRowMajor
= false;
708 struct ActiveUniformBlockInfo final
{
710 // BLOCK_BINDING is dynamic state
711 uint32_t dataSize
= 0;
712 std::vector
<uint32_t> activeUniformIndices
;
713 bool referencedByVertexShader
= false;
714 bool referencedByFragmentShader
= false;
717 struct LinkActiveInfo final
{
718 std::vector
<ActiveAttribInfo
> activeAttribs
;
719 std::vector
<ActiveUniformInfo
> activeUniforms
;
720 std::vector
<ActiveUniformBlockInfo
> activeUniformBlocks
;
721 std::vector
<ActiveInfo
> activeTfVaryings
;
724 struct LinkResult final
{
727 bool success
= false;
728 LinkActiveInfo active
;
729 GLenum tfBufferMode
= 0;
734 /// 4x32-bit primitives, with a type tag.
735 struct TypedQuad final
{
736 alignas(alignof(float)) uint8_t data
[4 * sizeof(float)] = {};
737 webgl::AttribBaseType type
= webgl::AttribBaseType::Float
;
740 /// [1-16]x32-bit primitives, with a type tag.
741 struct GetUniformData final
{
742 alignas(alignof(float)) uint8_t data
[4 * 4 * sizeof(float)] = {};
746 struct FrontBufferSnapshotIpc final
{
748 Maybe
<mozilla::ipc::Shmem
> shmem
= {};
751 struct ReadPixelsResult
{
752 gfx::IntRect subrect
= {};
753 size_t byteStride
= 0;
756 struct ReadPixelsResultIpc final
: public ReadPixelsResult
{
757 mozilla::ipc::Shmem shmem
= {};
760 struct VertAttribPointerDesc final
{
761 bool intFunc
= false;
762 uint8_t channels
= 4;
763 bool normalized
= false;
764 uint8_t byteStrideOrZero
= 0;
765 GLenum type
= LOCAL_GL_FLOAT
;
766 uint64_t byteOffset
= 0;
769 struct VertAttribPointerCalculated final
{
770 uint8_t byteSize
= 4 * 4;
771 uint8_t byteStride
= 4 * 4; // at-most 255
772 webgl::AttribBaseType baseType
= webgl::AttribBaseType::Float
;
778 * Represents a block of memory that it may or may not own. The
779 * inner data type must be trivially copyable by memcpy.
781 template <typename T
= uint8_t>
782 class RawBuffer final
{
783 const T
* mBegin
= nullptr;
788 using ElementType
= T
;
791 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
793 explicit RawBuffer(const Range
<const T
>& data
, UniqueBuffer
&& owned
= {})
794 : mBegin(data
.begin().get()),
796 mOwned(std::move(owned
)) {}
798 explicit RawBuffer(const size_t len
) : mLen(len
) {}
800 ~RawBuffer() = default;
802 Range
<const T
> Data() const { return {mBegin
, mLen
}; }
803 const auto& begin() const { return mBegin
; }
804 const auto& size() const { return mLen
; }
806 void Shrink(const size_t newLen
) {
807 if (mLen
<= newLen
) return;
811 RawBuffer() = default;
813 RawBuffer(const RawBuffer
&) = delete;
814 RawBuffer
& operator=(const RawBuffer
&) = delete;
816 RawBuffer(RawBuffer
&&) = default;
817 RawBuffer
& operator=(RawBuffer
&&) = default;
822 struct CopyableRange final
: public Range
<const uint8_t> {};
828 #define FOREACH_ID(X) \
829 X(FuncScopeIdError) \
830 X(compressedTexImage2D) \
831 X(compressedTexImage3D) \
832 X(compressedTexSubImage2D) \
833 X(compressedTexSubImage3D) \
834 X(copyTexSubImage2D) \
835 X(copyTexSubImage3D) \
837 X(drawArraysInstanced) \
839 X(drawElementsInstanced) \
840 X(drawRangeElements) \
841 X(renderbufferStorage) \
842 X(renderbufferStorageMultisample) \
858 X(vertexAttribI4iv) \
859 X(vertexAttribI4ui) \
860 X(vertexAttribI4uiv) \
861 X(vertexAttribIPointer) \
862 X(vertexAttribPointer)
866 enum class FuncScopeId
{
872 static constexpr const char* const FUNCSCOPE_NAME_BY_ID
[] = {
880 inline auto GetFuncScopeName(const FuncScopeId id
) {
881 return FUNCSCOPE_NAME_BY_ID
[static_cast<size_t>(id
)];
886 template <typename C
, typename K
>
887 inline auto MaybeFind(C
& container
, const K
& key
)
888 -> decltype(&(container
.find(key
)->second
)) {
889 const auto itr
= container
.find(key
);
890 if (itr
== container
.end()) return nullptr;
891 return &(itr
->second
);
894 template <typename C
, typename K
>
895 inline typename
C::mapped_type
Find(
896 const C
& container
, const K
& key
,
897 const typename
C::mapped_type notFound
= {}) {
898 const auto itr
= container
.find(key
);
899 if (itr
== container
.end()) return notFound
;
905 template <typename T
, typename U
>
906 inline Maybe
<T
> MaybeAs(const U val
) {
907 const auto checked
= CheckedInt
<T
>(val
);
908 if (!checked
.isValid()) return {};
909 return Some(checked
.value());
914 inline GLenum
ImageToTexTarget(const GLenum imageTarget
) {
915 switch (imageTarget
) {
916 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
917 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
918 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
919 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
920 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
921 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
922 return LOCAL_GL_TEXTURE_CUBE_MAP
;
928 inline bool IsTexTarget3D(const GLenum texTarget
) {
930 case LOCAL_GL_TEXTURE_2D_ARRAY
:
931 case LOCAL_GL_TEXTURE_3D
:
945 class OffscreenCanvas
;
948 struct TexImageSource
{
949 const dom::ArrayBufferView
* mView
= nullptr;
950 GLuint mViewElemOffset
= 0;
951 GLuint mViewElemLengthOverride
= 0;
953 const WebGLintptr
* mPboOffset
= nullptr;
955 const dom::ImageBitmap
* mImageBitmap
= nullptr;
956 const dom::ImageData
* mImageData
= nullptr;
958 const dom::OffscreenCanvas
* mOffscreenCanvas
= nullptr;
960 const dom::Element
* mDomElem
= nullptr;
961 ErrorResult
* mOut_error
= nullptr;
966 template <class DerivedT
>
968 bool operator!=(const DerivedT
& rhs
) const {
969 const auto self
= reinterpret_cast<const DerivedT
*>(this);
970 return !(*self
== rhs
);
974 struct PixelPackingState
: public DeriveNotEq
<PixelPackingState
> {
975 uint32_t alignmentInTypeElems
= 4; // ALIGNMENT isn't naive byte alignment!
976 uint32_t rowLength
= 0;
977 uint32_t imageHeight
= 0;
978 uint32_t skipPixels
= 0;
979 uint32_t skipRows
= 0;
980 uint32_t skipImages
= 0;
982 // C++20's default comparison operators can't come soon enough!
983 bool operator==(const PixelPackingState
& rhs
) const {
984 return alignmentInTypeElems
== rhs
.alignmentInTypeElems
&&
985 rowLength
== rhs
.rowLength
&& imageHeight
== rhs
.imageHeight
&&
986 skipPixels
== rhs
.skipPixels
&& skipRows
== rhs
.skipRows
&&
987 skipImages
== rhs
.skipImages
;
990 static void AssertDefaultUnpack(gl::GLContext
& gl
, const bool isWebgl2
) {
991 PixelPackingState
{}.AssertCurrentUnpack(gl
, isWebgl2
);
994 void ApplyUnpack(gl::GLContext
&, bool isWebgl2
,
995 const uvec3
& uploadSize
) const;
996 bool AssertCurrentUnpack(gl::GLContext
&, bool isWebgl2
) const;
999 struct PixelUnpackStateWebgl final
: public PixelPackingState
{
1000 GLenum colorspaceConversion
=
1001 dom::WebGLRenderingContext_Binding::BROWSER_DEFAULT_WEBGL
;
1003 bool premultiplyAlpha
= false;
1004 bool requireFastPath
= false;
1007 struct ExplicitPixelPackingState final
{
1008 struct Metrics final
{
1009 uvec3 usedSize
= {};
1010 size_t bytesPerPixel
= 0;
1012 // (srcStrideAndRowOverride.x, otherwise ROW_LENGTH != 0, otherwise size.x)
1013 // ...aligned to ALIGNMENT.
1014 size_t bytesPerRowStride
= 0;
1016 // structuredSrcSize.y, otherwise IMAGE_HEIGHT*(SKIP_IMAGES+size.z)
1017 size_t totalRows
= 0;
1019 // This ensures that no one else needs to do CheckedInt math.
1020 size_t totalBytesUsed
= 0;
1021 size_t totalBytesStrided
= 0;
1024 // It's so important that these aren't modified once evaluated.
1025 const PixelPackingState state
;
1026 const Metrics metrics
;
1028 static Result
<ExplicitPixelPackingState
, std::string
> ForUseWith(
1029 const PixelPackingState
&, GLenum target
, const uvec3
& subrectSize
,
1030 const webgl::PackingInfo
&, const Maybe
<size_t> bytesPerRowStrideOverride
);
1033 struct ReadPixelsDesc final
{
1036 PackingInfo pi
= {LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
};
1037 PixelPackingState packState
;
1040 } // namespace webgl
1044 struct TexUnpackBlobDesc final
{
1045 GLenum imageTarget
= LOCAL_GL_TEXTURE_2D
;
1047 gfxAlphaType srcAlphaType
= gfxAlphaType::NonPremult
;
1049 Maybe
<RawBuffer
<>> cpuData
;
1050 Maybe
<uint64_t> pboOffset
;
1052 Maybe
<uvec2
> structuredSrcSize
;
1053 RefPtr
<layers::Image
> image
;
1054 Maybe
<layers::SurfaceDescriptor
> sd
;
1055 RefPtr
<gfx::DataSourceSurface
> dataSurf
;
1057 webgl::PixelUnpackStateWebgl unpacking
;
1058 bool applyUnpackTransforms
= true;
1062 auto ExplicitUnpacking(const webgl::PackingInfo
& pi
,
1063 const Maybe
<size_t> bytesPerRowStrideOverride
) const {
1064 return ExplicitPixelPackingState::ForUseWith(this->unpacking
,
1065 this->imageTarget
, this->size
,
1066 pi
, bytesPerRowStrideOverride
);
1069 void Shrink(const webgl::PackingInfo
&);
1072 } // namespace webgl
1074 // ---------------------------------------
1077 template <typename T
, size_t N
>
1078 inline Range
<const T
> MakeRange(T (&arr
)[N
]) {
1082 template <typename T
>
1083 inline Range
<const T
> MakeRange(const dom::Sequence
<T
>& seq
) {
1084 return {seq
.Elements(), seq
.Length()};
1087 template <typename T
>
1088 inline Range
<const T
> MakeRange(const RawBuffer
<T
>& from
) {
1092 // abv = ArrayBufferView
1093 template <typename T
>
1094 inline auto MakeRangeAbv(const T
& abv
)
1095 -> Range
<const typename
T::element_type
> {
1097 return {abv
.Data(), abv
.Length()};
1102 constexpr auto kUniversalAlignment
= alignof(std::max_align_t
);
1104 template <typename T
>
1105 inline size_t AlignmentOffset(const size_t alignment
, const T posOrPtr
) {
1106 MOZ_ASSERT(alignment
);
1107 const auto begin
= reinterpret_cast<uintptr_t>(posOrPtr
);
1108 const auto wholeMultiples
= (begin
+ (alignment
- 1)) / alignment
;
1109 const auto aligned
= wholeMultiples
* alignment
;
1110 return aligned
- begin
;
1113 template <typename T
>
1114 inline size_t ByteSize(const Range
<T
>& range
) {
1115 return range
.length() * sizeof(T
);
1118 Maybe
<Range
<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView
& view
,
1120 GLuint elemCountOverride
);
1124 template <typename T
>
1125 RawBuffer
<T
> RawBufferView(const Range
<T
>& range
) {
1126 return RawBuffer
<T
>{range
};
1131 Maybe
<webgl::ErrorInfo
> CheckBindBufferRange(
1132 const GLenum target
, const GLuint index
, const bool isBuffer
,
1133 const uint64_t offset
, const uint64_t size
, const webgl::Limits
& limits
);
1135 Maybe
<webgl::ErrorInfo
> CheckFramebufferAttach(const GLenum bindImageTarget
,
1136 const GLenum curTexTarget
,
1137 const uint32_t mipLevel
,
1138 const uint32_t zLayerBase
,
1139 const uint32_t zLayerCount
,
1140 const webgl::Limits
& limits
);
1142 Result
<webgl::VertAttribPointerCalculated
, webgl::ErrorInfo
>
1143 CheckVertexAttribPointer(bool isWebgl2
, const webgl::VertAttribPointerDesc
&);
1145 uint8_t ElemTypeComponents(GLenum elemType
);
1147 inline std::string
ToString(const nsACString
& text
) {
1148 return {text
.BeginReading(), text
.Length()};
1151 inline void Memcpy(const RangedPtr
<uint8_t>& destBytes
,
1152 const RangedPtr
<const uint8_t>& srcBytes
,
1153 const size_t byteSize
) {
1154 // Trigger range asserts
1155 (void)(srcBytes
+ byteSize
);
1156 (void)(destBytes
+ byteSize
);
1158 memcpy(destBytes
.get(), srcBytes
.get(), byteSize
);
1165 // In theory, this number can be unbounded based on the driver. However, no
1166 // driver appears to expose more than 8. We might as well stop there too, for
1168 // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
1169 inline constexpr size_t kMaxDrawBuffers
= 8;
1170 } // namespace webgl
1172 } // namespace mozilla