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/. */
10 #include <type_traits>
11 #include <unordered_map>
14 // Most WebIDL typedefs are identical to their OpenGL counterparts.
16 #include "mozilla/Casting.h"
17 #include "mozilla/CheckedInt.h"
18 #include "mozilla/Range.h"
19 #include "mozilla/RefCounted.h"
24 #include "mozilla/dom/WebGLRenderingContextBinding.h"
25 #include "mozilla/ipc/SharedMemoryBasic.h"
26 //#include "WebGLStrongTypes.h"
28 // Manual reflection of WebIDL typedefs that are different from their
29 // OpenGL counterparts.
30 typedef int64_t WebGLsizeiptr
;
31 typedef int64_t WebGLintptr
;
32 typedef bool WebGLboolean
;
38 class GLContext
; // This is going to be needed a lot.
42 // Prevent implicit conversions into calloc and malloc. (mozilla namespace
45 template <typename DestT
>
46 class ForbidNarrowing final
{
50 template <typename SrcT
>
51 MOZ_IMPLICIT
ForbidNarrowing(SrcT val
) : mVal(val
) {
53 std::numeric_limits
<SrcT
>::min() >= std::numeric_limits
<DestT
>::min(),
54 "SrcT must be narrower than DestT.");
56 std::numeric_limits
<SrcT
>::max() <= std::numeric_limits
<DestT
>::max(),
57 "SrcT must be narrower than DestT.");
60 explicit operator DestT() const { return mVal
; }
63 inline void* malloc(const ForbidNarrowing
<size_t> s
) {
64 return ::malloc(size_t(s
));
67 inline void* calloc(const ForbidNarrowing
<size_t> n
,
68 const ForbidNarrowing
<size_t> size
) {
69 return ::calloc(size_t(n
), size_t(size
));
76 template <typename From
>
77 class AutoAssertCastT final
{
81 explicit AutoAssertCastT(const From val
) : mVal(val
) {}
83 template <typename To
>
85 return AssertedCast
<To
>(mVal
);
91 template <typename From
>
92 inline auto AutoAssertCast(const From val
) {
93 return detail::AutoAssertCastT
<From
>(val
);
98 struct PcqParamTraits
;
102 class TexUnpackBytes
;
103 class TexUnpackImage
;
104 class TexUnpackSurface
;
107 class ClientWebGLContext
;
108 struct WebGLTexPboOffset
;
111 class WebGLFramebuffer
;
114 class WebGLRenderbuffer
;
119 class WebGLTransformFeedback
;
120 class WebGLVertexArray
;
124 class VRefCounted
: public RefCounted
<VRefCounted
> {
126 virtual ~VRefCounted() = default;
128 #ifdef MOZ_REFCOUNTED_LEAK_CHECKING
129 virtual const char* typeName() const = 0;
130 virtual size_t typeSize() const = 0;
137 * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
138 * emulating the vertex attrib 0 array when it's not enabled. Indeed,
139 * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
140 * desktop OpenGL does not allow that.
142 enum class WebGLVertexAttrib0Status
: uint8_t {
143 Default
, // default status - no emulation needed
144 EmulatedUninitializedArray
, // need an artificial attrib 0 array, but
145 // contents may be left uninitialized
146 EmulatedInitializedArray
// need an artificial attrib 0 array, and contents
147 // must be initialized
151 * The formats that may participate, either as source or destination formats,
152 * in WebGL texture conversions. This includes:
153 * - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
154 * - additional formats provided by extensions, e.g. RGB32F
155 * - additional source formats, depending on browser details, used when
156 * uploading textures from DOM elements. See gfxImageSurface::Format().
158 enum class WebGLTexelFormat
: uint8_t {
159 // returned by SurfaceFromElementResultToImageSurface to indicate absence of
162 // common value for formats for which format conversions are not supported
163 FormatNotSupportingAnyConversion
,
164 // dummy pseudo-format meaning "use the other format".
165 // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
166 // is implicitly treated as being RGB8 itself.
170 A16F
, // OES_texture_half_float
171 A32F
, // OES_texture_float
173 R16F
, // OES_texture_half_float
174 R32F
, // OES_texture_float
177 RA16F
, // OES_texture_half_float
178 RA32F
, // OES_texture_float
186 RGB16F
, // OES_texture_half_float
187 RGB32F
, // OES_texture_float
192 RGBA16F
, // OES_texture_half_float
193 RGBA32F
, // OES_texture_float
194 // DOM element source only formats.
200 enum class WebGLTexImageFunc
: uint8_t {
209 enum class WebGLTexDimensions
: uint8_t { Tex2D
, Tex3D
};
211 // Please keep extensions in alphabetic order.
212 enum class WebGLExtensionID
: uint8_t {
213 ANGLE_instanced_arrays
,
215 EXT_color_buffer_float
,
216 EXT_color_buffer_half_float
,
217 EXT_disjoint_timer_query
,
220 EXT_shader_texture_lod
,
222 EXT_texture_compression_bptc
,
223 EXT_texture_compression_rgtc
,
224 EXT_texture_filter_anisotropic
,
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
,
251 template <typename T
>
252 inline constexpr auto EnumValue(const T v
) {
253 return static_cast<typename
std::underlying_type
<T
>::type
>(v
);
257 // Like UniquePtr<>, but for void* and malloc/calloc/free.
261 UniqueBuffer() : mBuffer(nullptr) {}
263 MOZ_IMPLICIT
UniqueBuffer(void* buffer
) : mBuffer(buffer
) {}
265 ~UniqueBuffer() { free(mBuffer
); }
267 UniqueBuffer(UniqueBuffer
&& other
) {
268 this->mBuffer
= other
.mBuffer
;
269 other
.mBuffer
= nullptr;
272 UniqueBuffer
& operator=(UniqueBuffer
&& other
) {
274 this->mBuffer
= other
.mBuffer
;
275 other
.mBuffer
= nullptr;
279 UniqueBuffer
& operator=(void* newBuffer
) {
281 this->mBuffer
= newBuffer
;
285 explicit operator bool() const { return bool(mBuffer
); }
287 void* get() const { return mBuffer
; }
289 UniqueBuffer(const UniqueBuffer
& other
) =
290 delete; // construct using std::move()!
291 void operator=(const UniqueBuffer
& other
) =
292 delete; // assign using std::move()!
296 struct FormatUsageInfo
;
298 struct SampleableInfo final
{
299 const char* incompleteReason
= nullptr;
301 const webgl::FormatUsageInfo
* usage
= nullptr;
302 bool isDepthTexCompare
= false;
304 bool IsComplete() const { return bool(levels
); }
307 enum class AttribBaseType
: uint8_t {
308 Boolean
, // Can convert from anything.
309 Float
, // Also includes NormU?Int
313 webgl::AttribBaseType
ToAttribBaseType(GLenum
);
314 const char* ToString(AttribBaseType
);
316 enum class UniformBaseType
: uint8_t {
321 const char* ToString(UniformBaseType
);
323 typedef uint64_t ObjectId
;
325 enum class BufferKind
: uint8_t {
335 struct FloatOrInt final
// For TexParameter[fi] and friends.
341 explicit FloatOrInt(GLint x
= 0) : isFloat(false), f(x
), i(x
) {}
343 explicit FloatOrInt(GLfloat x
) : isFloat(true), f(x
), i(roundf(x
)) {}
345 FloatOrInt
& operator=(const FloatOrInt
& x
) {
346 memcpy(this, &x
, sizeof(x
));
351 struct WebGLPixelStore
{
352 uint32_t mUnpackImageHeight
= 0;
353 uint32_t mUnpackSkipImages
= 0;
354 uint32_t mUnpackRowLength
= 0;
355 uint32_t mUnpackSkipRows
= 0;
356 uint32_t mUnpackSkipPixels
= 0;
357 uint32_t mUnpackAlignment
= 0;
358 uint32_t mPackRowLength
= 0;
359 uint32_t mPackSkipRows
= 0;
360 uint32_t mPackSkipPixels
= 0;
361 uint32_t mPackAlignment
= 0;
362 GLenum mColorspaceConversion
= 0;
364 bool mPremultiplyAlpha
= false;
365 bool mRequireFastPath
= false;
368 using WebGLTexUnpackVariant
=
369 Variant
<UniquePtr
<webgl::TexUnpackBytes
>,
370 UniquePtr
<webgl::TexUnpackSurface
>,
371 UniquePtr
<webgl::TexUnpackImage
>, WebGLTexPboOffset
>;
373 using MaybeWebGLTexUnpackVariant
= Maybe
<WebGLTexUnpackVariant
>;
375 struct WebGLContextOptions
{
378 bool stencil
= false;
379 bool premultipliedAlpha
= true;
380 bool antialias
= true;
381 bool preserveDrawingBuffer
= false;
382 bool failIfMajorPerformanceCaveat
= false;
383 bool xrCompatible
= false;
384 dom::WebGLPowerPreference powerPreference
=
385 dom::WebGLPowerPreference::Default
;
386 bool shouldResistFingerprinting
= true;
387 bool enableDebugRendererInfo
= false;
389 WebGLContextOptions();
390 WebGLContextOptions(const WebGLContextOptions
&) = default;
392 bool operator==(const WebGLContextOptions
&) const;
393 bool operator!=(const WebGLContextOptions
& rhs
) const {
394 return !(*this == rhs
);
400 template <typename T
>
405 template <typename U
, typename V
>
406 static Maybe
<avec2
> From(const U _x
, const V _y
) {
407 const auto x
= CheckedInt
<T
>(_x
);
408 const auto y
= CheckedInt
<T
>(_y
);
409 if (!x
.isValid() || !y
.isValid()) return {};
410 return Some(avec2(x
.value(), y
.value()));
413 template <typename U
>
414 static auto From(const U
& val
) {
415 return From(val
.x
, val
.y
);
417 template <typename U
>
418 static auto FromSize(const U
& val
) {
419 return From(val
.width
, val
.height
);
423 avec2(const T _x
, const T _y
) : x(_x
), y(_y
) {}
425 bool operator==(const avec2
& rhs
) const { return x
== rhs
.x
&& y
== rhs
.y
; }
426 bool operator!=(const avec2
& rhs
) const { return !(*this == rhs
); }
429 template <typename T
>
435 template <typename U
, typename V
>
436 static Maybe
<avec3
> From(const U _x
, const V _y
, const V _z
) {
437 const auto x
= CheckedInt
<T
>(_x
);
438 const auto y
= CheckedInt
<T
>(_y
);
439 const auto z
= CheckedInt
<T
>(_z
);
440 if (!x
.isValid() || !y
.isValid() || !z
.isValid()) return {};
441 return Some(avec3(x
.value(), y
.value(), z
.value()));
444 template <typename U
>
445 static auto From(const U
& val
) {
446 return From(val
.x
, val
.y
, val
.z
);
450 avec3(const T _x
, const T _y
, const T _z
) : x(_x
), y(_y
), z(_z
) {}
452 bool operator==(const avec3
& rhs
) const {
453 return x
== rhs
.x
&& y
== rhs
.y
&& z
== rhs
.z
;
455 bool operator!=(const avec3
& rhs
) const { return !(*this == rhs
); }
458 typedef avec2
<int32_t> ivec2
;
459 typedef avec3
<int32_t> ivec3
;
460 typedef avec2
<uint32_t> uvec2
;
461 typedef avec3
<uint32_t> uvec3
;
467 class ExtensionBits final
{
470 struct BitRef final
{
474 explicit operator bool() const { return bits
.mBits
& mask
; }
476 auto& operator=(const bool val
) {
486 uint64_t Mask(const WebGLExtensionID i
) const {
487 return uint64_t{1} << static_cast<uint64_t>(i
);
491 BitRef
operator[](const WebGLExtensionID i
) { return {*this, Mask(i
)}; }
492 bool operator[](const WebGLExtensionID i
) const { return mBits
& Mask(i
); }
497 enum class ContextLossReason
: uint8_t {
503 inline bool ReadContextLossReason(const uint8_t val
,
504 ContextLossReason
* const out
) {
505 if (val
> static_cast<uint8_t>(ContextLossReason::Guilty
)) {
508 *out
= static_cast<ContextLossReason
>(val
);
514 struct InitContextDesc final
{
515 bool isWebgl2
= false;
516 bool resistFingerprinting
= false;
518 WebGLContextOptions options
;
519 uint32_t principalKey
= 0;
522 struct Limits final
{
523 ExtensionBits supportedExtensions
;
526 uint32_t maxTexUnits
= 0;
527 uint32_t maxTex2dSize
= 0;
528 uint32_t maxTexCubeSize
= 0;
529 uint32_t maxVertexAttribs
= 0;
530 std::array
<uint32_t, 2> maxViewportDims
= {};
531 std::array
<float, 2> pointSizeRange
= {{1, 1}};
532 std::array
<float, 2> lineWidthRange
= {{1, 1}};
535 uint32_t maxTexArrayLayers
= 0;
536 uint32_t maxTex3dSize
= 0;
537 uint32_t maxTransformFeedbackSeparateAttribs
= 0;
538 uint32_t maxUniformBufferBindings
= 0;
539 uint32_t uniformBufferOffsetAlignment
= 0;
542 bool astcHdr
= false;
543 uint32_t maxColorDrawBuffers
= 1;
544 uint64_t queryCounterBitsTimeElapsed
= 0;
545 uint64_t queryCounterBitsTimestamp
= 0;
546 uint32_t maxMultiviewLayers
= 0;
549 struct InitContextResult final
{
551 WebGLContextOptions options
;
552 webgl::Limits limits
;
557 struct ErrorInfo final
{
562 struct ShaderPrecisionFormat final
{
570 enum class LossStatus
{
580 struct CompileResult final
{
583 std::string translatedSource
;
584 bool success
= false;
590 GLenum elemType
= 0; // `type`
591 uint32_t elemCount
= 0; // `size`
595 struct ActiveAttribInfo final
: public ActiveInfo
{
596 int32_t location
= -1;
599 struct ActiveUniformInfo final
: public ActiveInfo
{
600 std::unordered_map
<uint32_t, uint32_t>
601 locByIndex
; // Uniform array locations are sparse.
602 int32_t block_index
= -1;
603 int32_t block_offset
= -1; // In block, offset.
604 int32_t block_arrayStride
= -1;
605 int32_t block_matrixStride
= -1;
606 bool block_isRowMajor
= false;
609 struct ActiveUniformBlockInfo final
{
611 // BLOCK_BINDING is dynamic state
612 uint32_t dataSize
= 0;
613 std::vector
<uint32_t> activeUniformIndices
;
614 bool referencedByVertexShader
= false;
615 bool referencedByFragmentShader
= false;
618 struct LinkActiveInfo final
{
619 std::vector
<ActiveAttribInfo
> activeAttribs
;
620 std::vector
<ActiveUniformInfo
> activeUniforms
;
621 std::vector
<ActiveUniformBlockInfo
> activeUniformBlocks
;
622 std::vector
<ActiveInfo
> activeTfVaryings
;
625 struct LinkResult final
{
628 bool success
= false;
629 LinkActiveInfo active
;
630 GLenum tfBufferMode
= 0;
635 /// 4x32-bit primitives, with a type tag.
636 struct TypedQuad final
{
637 alignas(alignof(float)) uint8_t data
[4 * sizeof(float)] = {};
638 webgl::AttribBaseType type
= webgl::AttribBaseType::Float
;
641 /// [1-16]x32-bit primitives, with a type tag.
642 struct GetUniformData final
{
643 alignas(alignof(float)) uint8_t data
[4 * 4 * sizeof(float)] = {};
649 // return value for the InitializeCanvasRenderer message
657 * Represents a block of memory that it may or may not own. The
658 * inner data type must be trivially copyable by memcpy. A RawBuffer
659 * may be backed by local memory or shared memory.
661 template <typename T
= uint8_t, typename nonCV
= typename RemoveCV
<T
>::Type
,
662 typename EnableIf
<std::is_trivially_assignable
<nonCV
&, nonCV
>::value
,
665 // The SharedMemoryBasic that owns mData, if any.
666 RefPtr
<mozilla::ipc::SharedMemoryBasic
> mSmem
;
667 // Pointer to the raw memory block
669 // Length is the number of elements of size T in the array
671 // true if we should delete[] the mData on destruction
672 bool mOwnsData
= false;
674 friend mozilla::ipc::PcqParamTraits
<RawBuffer
>;
677 using ElementType
= T
;
680 * If aTakeData is true, RawBuffer will delete[] the memory when destroyed.
682 RawBuffer(size_t len
, T
* data
, bool aTakeData
= false)
683 : mData(data
), mLength(len
), mOwnsData(aTakeData
) {}
685 RawBuffer(size_t len
, RefPtr
<mozilla::ipc::SharedMemoryBasic
>& aSmem
)
686 : mSmem(aSmem
), mData(aSmem
->memory()), mLength(len
), mOwnsData(false) {
687 MOZ_ASSERT(mData
&& mLength
);
691 // If we have a SharedMemoryBasic then it must own mData.
692 MOZ_ASSERT((!mSmem
) || (!mOwnsData
));
697 mSmem
->CloseHandle();
701 auto Length() const { return mLength
; }
703 T
* Data() { return mData
; }
704 const T
* Data() const { return mData
; }
706 T
& operator[](size_t idx
) {
707 MOZ_ASSERT(mData
&& (idx
< mLength
));
710 const T
& operator[](size_t idx
) const {
711 MOZ_ASSERT(mData
&& (idx
< mLength
));
716 RawBuffer(const RawBuffer
&) = delete;
717 RawBuffer
& operator=(const RawBuffer
&) = delete;
719 RawBuffer(RawBuffer
&& o
)
723 mOwnsData(o
.mOwnsData
) {
730 RawBuffer
& operator=(RawBuffer
&& o
) {
734 mOwnsData
= o
.mOwnsData
;
747 #define FOREACH_ID(X) \
748 X(FuncScopeIdError) \
749 X(compressedTexImage2D) \
750 X(compressedTexImage3D) \
751 X(compressedTexSubImage2D) \
752 X(compressedTexSubImage3D) \
753 X(copyTexSubImage2D) \
754 X(copyTexSubImage3D) \
756 X(drawArraysInstanced) \
758 X(drawElementsInstanced) \
759 X(drawRangeElements) \
760 X(renderbufferStorage) \
761 X(renderbufferStorageMultisample) \
777 X(vertexAttribI4iv) \
778 X(vertexAttribI4ui) \
779 X(vertexAttribI4uiv) \
780 X(vertexAttribIPointer) \
781 X(vertexAttribPointer)
785 enum class FuncScopeId
{
791 static constexpr const char* const FUNCSCOPE_NAME_BY_ID
[] = {
799 inline auto GetFuncScopeName(const FuncScopeId id
) {
800 return FUNCSCOPE_NAME_BY_ID
[static_cast<size_t>(id
)];
805 template <typename C
, typename K
>
806 inline auto MaybeFind(C
& container
, const K
& key
)
807 -> decltype(&(container
.find(key
)->second
)) {
808 const auto itr
= container
.find(key
);
809 if (itr
== container
.end()) return nullptr;
810 return &(itr
->second
);
813 template <typename C
, typename K
>
814 inline typename
C::mapped_type
Find(
815 const C
& container
, const K
& key
,
816 const typename
C::mapped_type notFound
= {}) {
817 const auto itr
= container
.find(key
);
818 if (itr
== container
.end()) return notFound
;
824 inline GLenum
ImageToTexTarget(const GLenum imageTarget
) {
825 switch (imageTarget
) {
826 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
827 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
828 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
829 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
830 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
831 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
832 return LOCAL_GL_TEXTURE_CUBE_MAP
;
845 struct TexImageSource
{
846 const dom::ArrayBufferView
* mView
= nullptr;
847 GLuint mViewElemOffset
= 0;
848 GLuint mViewElemLengthOverride
= 0;
850 const WebGLintptr
* mPboOffset
= nullptr;
852 const dom::ImageBitmap
* mImageBitmap
= nullptr;
853 const dom::ImageData
* mImageData
= nullptr;
855 const dom::Element
* mDomElem
= nullptr;
856 ErrorResult
* mOut_error
= nullptr;
859 // ---------------------------------------
862 template <typename T
, size_t N
>
863 inline Range
<const T
> MakeRange(T (&arr
)[N
]) {
867 template <typename T
>
868 inline Range
<const T
> MakeRange(const dom::Sequence
<T
>& seq
) {
869 return {seq
.Elements(), seq
.Length()};
872 template <typename T
>
873 inline Range
<const T
> MakeRange(const RawBuffer
<T
>& from
) {
874 return {from
.Data(), from
.Length()};
877 template <typename T
>
878 inline Range
<T
> MakeRange(RawBuffer
<T
>& from
) {
879 return {from
.Data(), from
.Length()};
882 // abv = ArrayBufferView
883 template <typename T
>
884 inline auto MakeRangeAbv(const T
& abv
)
885 -> Range
<const typename
T::element_type
> {
887 return {abv
.Data(), abv
.Length()};
890 Maybe
<Range
<const uint8_t>> GetRangeFromView(const dom::ArrayBufferView
& view
,
892 GLuint elemCountOverride
);
896 template <typename T
>
897 RawBuffer
<T
> RawBufferView(const Range
<T
>& range
) {
898 return {range
.length(), range
.begin().get()};
903 Maybe
<webgl::ErrorInfo
> CheckBindBufferRange(
904 const GLenum target
, const GLuint index
, const bool isBuffer
,
905 const uint64_t offset
, const uint64_t size
, const webgl::Limits
& limits
);
907 Maybe
<webgl::ErrorInfo
> CheckFramebufferAttach(const GLenum bindImageTarget
,
908 const GLenum curTexTarget
,
909 const uint32_t mipLevel
,
910 const uint32_t zLayerBase
,
911 const uint32_t zLayerCount
,
912 const webgl::Limits
& limits
);
914 Maybe
<webgl::ErrorInfo
> CheckVertexAttribPointer(bool webgl2
, bool isFuncInt
,
915 GLint size
, GLenum type
,
918 uint64_t byteOffset
);
920 uint8_t ElemTypeComponents(GLenum elemType
);
922 inline std::string
ToString(const nsACString
& text
) {
923 return {text
.BeginReading(), text
.Length()};
926 } // namespace mozilla