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/. */
6 #ifndef CLIENTWEBGLCONTEXT_H_
7 #define CLIENTWEBGLCONTEXT_H_
11 #include "mozilla/dom/ImageData.h"
12 #include "mozilla/Range.h"
13 #include "mozilla/RefCounted.h"
14 #include "mozilla/dom/TypedArray.h"
15 #include "nsICanvasRenderingContextInternal.h"
16 #include "nsWrapperCache.h"
17 #include "mozilla/dom/WebGLRenderingContextBinding.h"
18 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
19 #include "mozilla/layers/LayersSurfaces.h"
20 #include "mozilla/StaticPrefs_webgl.h"
21 #include "WebGLStrongTypes.h"
22 #include "WebGLTypes.h"
24 #include "mozilla/Logging.h"
25 #include "WebGLCommandQueue.h"
28 #include <type_traits>
29 #include <unordered_map>
30 #include <unordered_set>
35 class ClientWebGLExtensionBase
;
36 class HostWebGLContext
;
38 template <typename MethodT
, MethodT Method
>
42 class OwningHTMLCanvasElementOrOffscreenCanvas
;
47 class AvailabilityRunnable
;
52 ////////////////////////////////////
54 class WebGLActiveInfoJS final
: public RefCounted
<WebGLActiveInfoJS
> {
56 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLActiveInfoJS
)
58 const webgl::ActiveInfo mInfo
;
60 explicit WebGLActiveInfoJS(const webgl::ActiveInfo
& info
) : mInfo(info
) {}
62 virtual ~WebGLActiveInfoJS() = default;
67 GLint
Size() const { return static_cast<GLint
>(mInfo
.elemCount
); }
68 GLenum
Type() const { return mInfo
.elemType
; }
70 void GetName(nsString
& retval
) const { CopyUTF8toUTF16(mInfo
.name
, retval
); }
72 bool WrapObject(JSContext
*, JS::Handle
<JSObject
*>,
73 JS::MutableHandle
<JSObject
*>);
76 class WebGLShaderPrecisionFormatJS final
77 : public RefCounted
<WebGLShaderPrecisionFormatJS
> {
79 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLShaderPrecisionFormatJS
)
81 const webgl::ShaderPrecisionFormat mInfo
;
83 explicit WebGLShaderPrecisionFormatJS(
84 const webgl::ShaderPrecisionFormat
& info
)
87 virtual ~WebGLShaderPrecisionFormatJS() = default;
89 GLint
RangeMin() const { return mInfo
.rangeMin
; }
90 GLint
RangeMax() const { return mInfo
.rangeMax
; }
91 GLint
Precision() const { return mInfo
.precision
; }
93 bool WrapObject(JSContext
*, JS::Handle
<JSObject
*>,
94 JS::MutableHandle
<JSObject
*>);
97 // -----------------------
99 class ClientWebGLContext
;
101 class WebGLFramebufferJS
;
102 class WebGLProgramJS
;
104 class WebGLRenderbufferJS
;
105 class WebGLSamplerJS
;
107 class WebGLTextureJS
;
108 class WebGLTransformFeedbackJS
;
109 class WebGLVertexArrayJS
;
115 class ProgramKeepAlive final
{
116 friend class mozilla::WebGLProgramJS
;
118 WebGLProgramJS
* mParent
;
121 explicit ProgramKeepAlive(WebGLProgramJS
& parent
) : mParent(&parent
) {}
125 class ShaderKeepAlive final
{
126 friend class mozilla::WebGLShaderJS
;
128 const WebGLShaderJS
* mParent
;
131 explicit ShaderKeepAlive(const WebGLShaderJS
& parent
) : mParent(&parent
) {}
135 class ContextGenerationInfo final
{
137 webgl::ExtensionBits mEnabledExtensions
;
138 RefPtr
<WebGLProgramJS
> mCurrentProgram
;
139 std::shared_ptr
<webgl::ProgramKeepAlive
> mProgramKeepAlive
;
140 mutable std::shared_ptr
<webgl::LinkResult
> mActiveLinkResult
;
142 RefPtr
<WebGLTransformFeedbackJS
> mDefaultTfo
;
143 RefPtr
<WebGLVertexArrayJS
> mDefaultVao
;
145 std::unordered_map
<GLenum
, RefPtr
<WebGLBufferJS
>> mBoundBufferByTarget
;
146 std::vector
<RefPtr
<WebGLBufferJS
>> mBoundUbos
;
147 RefPtr
<WebGLFramebufferJS
> mBoundDrawFb
;
148 RefPtr
<WebGLFramebufferJS
> mBoundReadFb
;
149 RefPtr
<WebGLRenderbufferJS
> mBoundRb
;
150 RefPtr
<WebGLTransformFeedbackJS
> mBoundTfo
;
151 RefPtr
<WebGLVertexArrayJS
> mBoundVao
;
152 std::unordered_map
<GLenum
, RefPtr
<WebGLQueryJS
>> mCurrentQueryByTarget
;
154 struct TexUnit final
{
155 RefPtr
<WebGLSamplerJS
> sampler
;
156 std::unordered_map
<GLenum
, RefPtr
<WebGLTextureJS
>> texByTarget
;
158 uint32_t mActiveTexUnit
= 0;
159 std::vector
<TexUnit
> mTexUnits
;
161 bool mTfActiveAndNotPaused
= false;
163 std::vector
<TypedQuad
> mGenericVertexAttribs
;
165 std::array
<int32_t, 4> mScissor
= {};
166 std::array
<int32_t, 4> mViewport
= {};
167 std::array
<float, 4> mClearColor
= {{0, 0, 0, 0}};
168 std::array
<float, 4> mBlendColor
= {{0, 0, 0, 0}};
169 std::array
<float, 2> mDepthRange
= {{0, 1}};
170 webgl::PixelPackingState mPixelPackState
;
171 webgl::PixelUnpackStateWebgl mPixelUnpackState
;
173 std::vector
<GLenum
> mCompressedTextureFormats
;
175 Maybe
<uvec2
> mDrawingBufferSize
;
177 webgl::ProvokingVertex mProvokingVertex
= webgl::ProvokingVertex::LastVertex
;
179 mutable std::unordered_map
<GLenum
, bool> mIsEnabledMap
;
184 // In the cross process case, the WebGL actor's ownership relationship looks
186 // ---------------------------------------------------------------------
187 // | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext
188 // ---------------------------------------------------------------------
190 // where 'A -> B' means "A owns B"
192 struct NotLostData final
{
193 ClientWebGLContext
& context
;
194 webgl::InitContextResult info
;
196 RefPtr
<mozilla::dom::WebGLChild
> outOfProcess
;
197 UniquePtr
<HostWebGLContext
> inProcess
;
199 webgl::ContextGenerationInfo state
;
200 std::array
<RefPtr
<ClientWebGLExtensionBase
>,
201 UnderlyingValue(WebGLExtensionID::Max
)>
204 RefPtr
<layers::CanvasRenderer
> mCanvasRenderer
;
206 explicit NotLostData(ClientWebGLContext
& context
);
213 friend ClientWebGLContext
;
216 const std::weak_ptr
<NotLostData
> mGeneration
;
220 bool mDeleteRequested
= false;
222 explicit ObjectJS(const ClientWebGLContext
*);
223 virtual ~ObjectJS() = default;
226 ClientWebGLContext
* Context() const {
227 const auto locked
= mGeneration
.lock();
228 if (!locked
) return nullptr;
229 return &(locked
->context
);
232 ClientWebGLContext
* GetParentObject() const { return Context(); }
235 bool IsForContext(const ClientWebGLContext
&) const;
236 virtual bool IsDeleted() const { return mDeleteRequested
; }
238 bool IsUsable(const ClientWebGLContext
& context
) const {
239 return IsForContext(context
) && !IsDeleted();
243 bool ValidateUsable(const ClientWebGLContext
& context
,
244 const char* const argName
) const {
245 if (MOZ_LIKELY(IsUsable(context
))) return true;
246 WarnInvalidUse(context
, argName
);
251 bool ValidateForContext(const ClientWebGLContext
& context
,
252 const char* const argName
) const;
255 void WarnInvalidUse(const ClientWebGLContext
&, const char* argName
) const;
257 // The enum is INVALID_VALUE for Program/Shader :(
258 virtual GLenum
ErrorOnDeleted() const { return LOCAL_GL_INVALID_OPERATION
; }
263 // -------------------------
265 class WebGLBufferJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
266 friend class ClientWebGLContext
;
268 webgl::BufferKind mKind
=
269 webgl::BufferKind::Undefined
; // !IsBuffer until Bind
272 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBufferJS
)
273 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLBufferJS
)
275 explicit WebGLBufferJS(const ClientWebGLContext
& webgl
)
276 : webgl::ObjectJS(&webgl
) {}
282 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
287 class WebGLFramebufferJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
288 friend class ClientWebGLContext
;
291 struct Attachment final
{
292 RefPtr
<WebGLRenderbufferJS
> rb
;
293 RefPtr
<WebGLTextureJS
> tex
;
297 bool mHasBeenBound
= false; // !IsFramebuffer until Bind
298 std::unordered_map
<GLenum
, Attachment
> mAttachments
;
301 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebufferJS
)
302 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLFramebufferJS
)
304 explicit WebGLFramebufferJS(const ClientWebGLContext
&, bool opaque
= false);
307 bool mInOpaqueRAF
= false;
310 ~WebGLFramebufferJS();
312 void EnsureColorAttachments();
315 Attachment
* GetAttachment(const GLenum slotEnum
) {
316 auto ret
= MaybeFind(mAttachments
, slotEnum
);
318 EnsureColorAttachments();
319 ret
= MaybeFind(mAttachments
, slotEnum
);
324 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
329 class WebGLProgramJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
330 friend class ClientWebGLContext
;
333 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgramJS
)
334 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLProgramJS
)
336 // If the REFCOUNTING macro isn't declared first, the AddRef at
337 // mInnerRef->js will panic when REFCOUNTING's "owning thread" var is still
340 struct Attachment final
{
341 RefPtr
<WebGLShaderJS
> shader
;
342 std::shared_ptr
<webgl::ShaderKeepAlive
> keepAlive
;
346 std::shared_ptr
<webgl::ProgramKeepAlive
> mKeepAlive
;
347 const std::weak_ptr
<webgl::ProgramKeepAlive
> mKeepAliveWeak
;
349 std::unordered_map
<GLenum
, Attachment
> mNextLink_Shaders
;
350 bool mLastValidate
= false;
351 mutable std::shared_ptr
<webgl::LinkResult
>
352 mResult
; // Never null, often defaulted.
354 struct UniformLocInfo final
{
355 const uint32_t location
;
356 const GLenum elemType
;
359 mutable Maybe
<std::unordered_map
<std::string
, UniformLocInfo
>>
361 mutable std::vector
<uint32_t> mUniformBlockBindings
;
363 std::unordered_set
<const WebGLTransformFeedbackJS
*> mActiveTfos
;
365 explicit WebGLProgramJS(const ClientWebGLContext
&);
368 mKeepAlive
= nullptr; // Try to delete.
370 const auto& maybe
= mKeepAliveWeak
.lock();
372 maybe
->mParent
= nullptr;
377 bool IsDeleted() const override
{ return !mKeepAliveWeak
.lock(); }
378 GLenum
ErrorOnDeleted() const override
{ return LOCAL_GL_INVALID_VALUE
; }
380 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
385 class WebGLQueryJS final
: public nsWrapperCache
,
386 public webgl::ObjectJS
,
387 public SupportsWeakPtr
{
388 friend class ClientWebGLContext
;
389 friend class webgl::AvailabilityRunnable
;
391 GLenum mTarget
= 0; // !IsQuery until Bind
392 bool mCanBeAvailable
= false;
395 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQueryJS
)
396 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLQueryJS
)
398 explicit WebGLQueryJS(const ClientWebGLContext
* const webgl
)
399 : webgl::ObjectJS(webgl
) {}
405 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
410 class WebGLRenderbufferJS final
: public nsWrapperCache
,
411 public webgl::ObjectJS
{
412 friend class ClientWebGLContext
;
415 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbufferJS
)
416 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLRenderbufferJS
)
419 bool mHasBeenBound
= false; // !IsRenderbuffer until Bind
421 explicit WebGLRenderbufferJS(const ClientWebGLContext
& webgl
)
422 : webgl::ObjectJS(&webgl
) {}
423 ~WebGLRenderbufferJS();
426 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
431 class WebGLSamplerJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
432 // IsSampler without Bind
434 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSamplerJS
)
435 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSamplerJS
)
437 explicit WebGLSamplerJS(const ClientWebGLContext
& webgl
)
438 : webgl::ObjectJS(&webgl
) {}
444 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
449 class WebGLShaderJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
450 friend class ClientWebGLContext
;
453 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShaderJS
)
454 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLShaderJS
)
459 std::shared_ptr
<webgl::ShaderKeepAlive
> mKeepAlive
;
460 const std::weak_ptr
<webgl::ShaderKeepAlive
> mKeepAliveWeak
;
462 mutable webgl::CompileResult mResult
;
464 WebGLShaderJS(const ClientWebGLContext
&, GLenum type
);
467 mKeepAlive
= nullptr; // Try to delete.
469 const auto& maybe
= mKeepAliveWeak
.lock();
471 maybe
->mParent
= nullptr;
476 bool IsDeleted() const override
{ return !mKeepAliveWeak
.lock(); }
477 GLenum
ErrorOnDeleted() const override
{ return LOCAL_GL_INVALID_VALUE
; }
479 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
484 class WebGLSyncJS final
: public nsWrapperCache
,
485 public webgl::ObjectJS
,
486 public SupportsWeakPtr
{
487 friend class ClientWebGLContext
;
488 friend class webgl::AvailabilityRunnable
;
490 bool mCanBeAvailable
= false;
491 uint8_t mNumQueriesBeforeFirstFrameBoundary
= 0;
492 uint8_t mNumQueriesWithoutFlushCommandsBit
= 0;
495 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS
)
496 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSyncJS
)
498 explicit WebGLSyncJS(const ClientWebGLContext
& webgl
)
499 : webgl::ObjectJS(&webgl
) {}
505 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
510 class WebGLTextureJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
511 friend class ClientWebGLContext
;
513 GLenum mTarget
= 0; // !IsTexture until Bind
516 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTextureJS
)
517 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTextureJS
)
519 explicit WebGLTextureJS(const ClientWebGLContext
& webgl
)
520 : webgl::ObjectJS(&webgl
) {}
526 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
531 class WebGLTransformFeedbackJS final
: public nsWrapperCache
,
532 public webgl::ObjectJS
{
533 friend class ClientWebGLContext
;
535 bool mHasBeenBound
= false; // !IsTransformFeedback until Bind
536 bool mActiveOrPaused
= false;
537 std::vector
<RefPtr
<WebGLBufferJS
>> mAttribBuffers
;
538 RefPtr
<WebGLProgramJS
> mActiveProgram
;
539 std::shared_ptr
<webgl::ProgramKeepAlive
> mActiveProgramKeepAlive
;
542 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedbackJS
)
543 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTransformFeedbackJS
)
545 explicit WebGLTransformFeedbackJS(const ClientWebGLContext
&);
548 ~WebGLTransformFeedbackJS();
551 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
556 std::array
<uint16_t, 3> ValidUploadElemTypes(GLenum
);
558 class WebGLUniformLocationJS final
: public nsWrapperCache
,
559 public webgl::ObjectJS
{
560 friend class ClientWebGLContext
;
562 const std::weak_ptr
<webgl::LinkResult
> mParent
;
563 const uint32_t mLocation
;
564 const std::array
<uint16_t, 3> mValidUploadElemTypes
;
567 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocationJS
)
568 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLUniformLocationJS
)
570 WebGLUniformLocationJS(const ClientWebGLContext
& webgl
,
571 std::weak_ptr
<webgl::LinkResult
> parent
, uint32_t loc
,
573 : webgl::ObjectJS(&webgl
),
576 mValidUploadElemTypes(ValidUploadElemTypes(elemType
)) {}
579 ~WebGLUniformLocationJS() = default;
582 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
587 class WebGLVertexArrayJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
588 friend class ClientWebGLContext
;
590 bool mHasBeenBound
= false; // !IsVertexArray until Bind
591 RefPtr
<WebGLBufferJS
> mIndexBuffer
;
592 std::vector
<RefPtr
<WebGLBufferJS
>> mAttribBuffers
;
595 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArrayJS
)
596 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLVertexArrayJS
)
598 explicit WebGLVertexArrayJS(const ClientWebGLContext
*);
601 ~WebGLVertexArrayJS();
604 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
607 ////////////////////////////////////
609 using Float32ListU
= dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence
;
610 using Int32ListU
= dom::MaybeSharedInt32ArrayOrLongSequence
;
611 using Uint32ListU
= dom::MaybeSharedUint32ArrayOrUnsignedLongSequence
;
613 template <typename Converter
, typename T
>
614 inline bool ConvertSequence(const dom::Sequence
<T
>& sequence
,
615 Converter
&& converter
) {
616 // It's ok to GC here, but we need a common parameter list for
617 // Converter with the typed array version.
618 JS::AutoCheckCannotGC nogc
;
620 return std::forward
<Converter
>(converter
)(Span(sequence
), std::move(nogc
));
623 template <typename Converter
>
624 inline bool Convert(const Float32ListU
& list
, Converter
&& converter
) {
625 if (list
.IsFloat32Array()) {
626 return list
.GetAsFloat32Array().ProcessData(
627 std::forward
<Converter
>(converter
));
630 return ConvertSequence(list
.GetAsUnrestrictedFloatSequence(),
631 std::forward
<Converter
>(converter
));
634 template <typename Converter
>
635 inline bool Convert(const Int32ListU
& list
, Converter
&& converter
) {
636 if (list
.IsInt32Array()) {
637 return list
.GetAsInt32Array().ProcessData(
638 std::forward
<Converter
>(converter
));
641 return ConvertSequence(list
.GetAsLongSequence(),
642 std::forward
<Converter
>(converter
));
645 template <typename Converter
>
646 inline bool Convert(const Uint32ListU
& list
, Converter
&& converter
) {
647 if (list
.IsUint32Array()) {
648 return list
.GetAsUint32Array().ProcessData(
649 std::forward
<Converter
>(converter
));
652 return ConvertSequence(list
.GetAsUnsignedLongSequence(),
653 std::forward
<Converter
>(converter
));
656 template <typename T
>
657 inline Range
<const uint8_t> MakeByteRange(const T
& x
) {
658 const auto typed
= MakeRange(x
);
659 return Range
<const uint8_t>(
660 reinterpret_cast<const uint8_t*>(typed
.begin().get()),
661 typed
.length() * sizeof(typed
[0]));
664 template <typename T
>
665 inline Range
<const uint8_t> MakeByteRange(const Span
<T
>& x
) {
671 struct TexImageSourceAdapter final
: public TexImageSource
{
672 TexImageSourceAdapter(const dom::Nullable
<dom::ArrayBufferView
>* maybeView
,
674 if (!maybeView
->IsNull()) {
675 mView
= &(maybeView
->Value());
679 TexImageSourceAdapter(const dom::Nullable
<dom::ArrayBufferView
>* maybeView
,
680 GLuint viewElemOffset
) {
681 if (!maybeView
->IsNull()) {
682 mView
= &(maybeView
->Value());
684 mViewElemOffset
= viewElemOffset
;
687 TexImageSourceAdapter(const dom::ArrayBufferView
* view
, ErrorResult
*) {
691 TexImageSourceAdapter(const dom::ArrayBufferView
* view
, GLuint viewElemOffset
,
692 GLuint viewElemLengthOverride
= 0) {
694 mViewElemOffset
= viewElemOffset
;
695 mViewElemLengthOverride
= viewElemLengthOverride
;
698 explicit TexImageSourceAdapter(const WebGLintptr
* pboOffset
,
699 GLuint ignored1
= 0, GLuint ignored2
= 0) {
700 mPboOffset
= pboOffset
;
703 TexImageSourceAdapter(const WebGLintptr
* pboOffset
, ErrorResult
* ignored
) {
704 mPboOffset
= pboOffset
;
707 TexImageSourceAdapter(const dom::ImageBitmap
* imageBitmap
,
708 ErrorResult
* out_error
) {
709 mImageBitmap
= imageBitmap
;
710 mOut_error
= out_error
;
713 TexImageSourceAdapter(const dom::ImageData
* imageData
, ErrorResult
*) {
714 mImageData
= imageData
;
717 TexImageSourceAdapter(const dom::OffscreenCanvas
* offscreenCanvas
,
718 ErrorResult
* const out_error
) {
719 mOffscreenCanvas
= offscreenCanvas
;
720 mOut_error
= out_error
;
723 TexImageSourceAdapter(const dom::VideoFrame
* videoFrame
,
724 ErrorResult
* const out_error
) {
725 mVideoFrame
= videoFrame
;
726 mOut_error
= out_error
;
729 TexImageSourceAdapter(const dom::Element
* domElem
,
730 ErrorResult
* const out_error
) {
732 mOut_error
= out_error
;
737 * Base class for all IDL implementations of WebGLContext
739 class ClientWebGLContext final
: public nsICanvasRenderingContextInternal
,
740 public nsWrapperCache
{
741 friend class webgl::AvailabilityRunnable
;
742 friend class webgl::ObjectJS
;
743 friend class webgl::ProgramKeepAlive
;
744 friend class webgl::ShaderKeepAlive
;
746 // ----------------------------- Lifetime and DOM ---------------------------
748 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
749 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ClientWebGLContext
)
751 JSObject
* WrapObject(JSContext
* cx
,
752 JS::Handle
<JSObject
*> givenProto
) override
{
754 return dom::WebGL2RenderingContext_Binding::Wrap(cx
, this, givenProto
);
756 return dom::WebGLRenderingContext_Binding::Wrap(cx
, this, givenProto
);
762 const bool mIsWebGL2
;
765 bool mIsCanvasDirty
= false;
766 uvec2 mRequestedSize
= {};
769 explicit ClientWebGLContext(bool webgl2
);
772 virtual ~ClientWebGLContext();
774 const RefPtr
<ClientWebGLExtensionLoseContext
> mExtLoseContext
;
776 mutable std::shared_ptr
<webgl::NotLostData
> mNotLost
;
777 mutable GLenum mNextError
= 0;
778 mutable webgl::LossStatus mLossStatus
= webgl::LossStatus::Ready
;
779 mutable bool mAwaitingRestore
= false;
780 mutable webgl::ObjectId mLastId
= 0;
783 webgl::ObjectId
NextId() const { return mLastId
+= 1; }
785 // Holds Some Id if async present is used
786 mutable Maybe
<layers::RemoteTextureId
> mLastRemoteTextureId
;
787 mutable Maybe
<layers::RemoteTextureOwnerId
> mRemoteTextureOwnerId
;
788 mutable RefPtr
<layers::FwdTransactionTracker
> mFwdTransactionTracker
;
793 const auto& Limits() const { return mNotLost
->info
.limits
; }
794 const auto& Vendor() const { return mNotLost
->info
.vendor
; }
795 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters
796 const WebGLContextOptions
& ActualContextParameters() const {
797 MOZ_ASSERT(mNotLost
!= nullptr);
798 return mNotLost
->info
.options
;
801 auto& State() { return mNotLost
->state
; }
802 const auto& State() const {
803 return const_cast<ClientWebGLContext
*>(this)->State();
809 mutable RefPtr
<webgl::AvailabilityRunnable
> mAvailabilityRunnable
;
812 webgl::AvailabilityRunnable
& EnsureAvailabilityRunnable() const;
817 void EmulateLoseContext() const;
818 void OnContextLoss(webgl::ContextLossReason
) const;
819 void RestoreContext(webgl::LossStatus requiredStatus
) const;
822 bool DispatchEvent(const nsAString
&) const;
823 void Event_webglcontextlost() const;
824 void Event_webglcontextrestored() const;
826 bool CreateHostContext(const uvec2
& requestedSize
);
827 void ThrowEvent_WebGLContextCreationError(const std::string
&) const;
829 void UpdateCanvasParameters();
832 void MarkCanvasDirty();
834 void MarkContextClean() override
{}
836 void OnBeforePaintTransaction() override
;
838 mozilla::dom::WebGLChild
* GetChild() const {
839 if (!mNotLost
) return nullptr;
840 if (!mNotLost
->outOfProcess
) return nullptr;
841 return mNotLost
->outOfProcess
.get();
844 // -------------------------------------------------------------------------
845 // Client WebGL API call tracking and error message reporting
846 // -------------------------------------------------------------------------
848 // Remembers the WebGL function that is lowest on the stack for client-side
850 class FuncScope final
{
852 const ClientWebGLContext
& mWebGL
;
853 const std::shared_ptr
<webgl::NotLostData
> mKeepNotLostOrNull
;
854 const char* const mFuncName
;
856 FuncScope(const ClientWebGLContext
& webgl
, const char* funcName
)
858 mKeepNotLostOrNull(webgl
.mNotLost
),
859 mFuncName(funcName
) {
860 // Only set if an "outer" scope hasn't already been set.
861 if (!mWebGL
.mFuncScope
) {
862 mWebGL
.mFuncScope
= this;
867 if (this == mWebGL
.mFuncScope
) {
868 mWebGL
.mFuncScope
= nullptr;
872 FuncScope(const FuncScope
&) = delete;
873 FuncScope(FuncScope
&&) = delete;
877 // The scope of the function at the top of the current WebGL function call
879 mutable FuncScope
* mFuncScope
= nullptr;
881 const char* FuncName() const {
882 return mFuncScope
? mFuncScope
->mFuncName
: nullptr;
886 template <typename
... Args
>
887 void EnqueueError(const GLenum error
, const char* const format
,
888 const Args
&... args
) const {
889 MOZ_ASSERT(FuncName());
891 text
.AppendPrintf("WebGL warning: %s: ", FuncName());
894 # pragma clang diagnostic push
895 # pragma clang diagnostic ignored "-Wformat-security"
896 #elif defined(__GNUC__)
897 # pragma GCC diagnostic push
898 # pragma GCC diagnostic ignored "-Wformat-security"
900 text
.AppendPrintf(format
, args
...);
902 # pragma clang diagnostic pop
903 #elif defined(__GNUC__)
904 # pragma GCC diagnostic pop
907 EnqueueErrorImpl(error
, text
);
910 void EnqueueError(const webgl::ErrorInfo
& info
) const {
911 EnqueueError(info
.type
, "%s", info
.info
.c_str());
914 template <typename
... Args
>
915 void EnqueueWarning(const char* const format
, const Args
&... args
) const {
916 EnqueueError(0, format
, args
...);
919 template <typename
... Args
>
920 void EnqueuePerfWarning(const char* const format
, const Args
&... args
) const {
921 EnqueueError(webgl::kErrorPerfWarning
, format
, args
...);
924 void EnqueueError_ArgEnum(const char* argName
,
925 GLenum val
) const; // Cold code.
928 void EnqueueErrorImpl(GLenum errorOrZero
, const nsACString
&) const;
931 Maybe
<Span
<uint8_t>> ValidateArrayBufferView(const Span
<uint8_t>& bytes
,
934 GLuint elemCountOverride
,
935 const GLenum errorEnum
) const;
938 template <typename T
>
939 bool ValidateNonNull(const char* const argName
,
940 const dom::Nullable
<T
>& maybe
) const {
941 if (maybe
.IsNull()) {
942 EnqueueError(LOCAL_GL_INVALID_VALUE
, "%s: Cannot be null.", argName
);
948 bool ValidateNonNegative(const char* argName
, int64_t val
) const {
949 if (MOZ_UNLIKELY(val
< 0)) {
950 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`%s` must be non-negative.",
957 bool ValidateViewType(GLenum unpackType
, const TexImageSource
& src
) const;
959 Maybe
<uvec3
> ValidateExtents(GLsizei width
, GLsizei height
, GLsizei depth
,
962 // -------------------------------------------------------------------------
963 // nsICanvasRenderingContextInternal / nsAPostRefreshObserver
964 // -------------------------------------------------------------------------
966 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
967 layers::CanvasRenderer
* aRenderer
) override
;
969 void MarkContextCleanForFrameCapture() override
{
970 mFrameCaptureState
= FrameCaptureState::CLEAN
;
972 // Note that 'clean' here refers to its invalidation state, not the
973 // contents of the buffer.
974 Watchable
<FrameCaptureState
>* GetFrameCaptureState() override
{
975 return &mFrameCaptureState
;
978 void OnMemoryPressure() override
;
979 void SetContextOptions(const WebGLContextOptions
& aOptions
) {
980 mInitialOptions
.emplace(aOptions
);
982 const WebGLContextOptions
& GetContextOptions() const {
983 return mInitialOptions
.ref();
986 SetContextOptions(JSContext
* cx
, JS::Handle
<JS::Value
> options
,
987 ErrorResult
& aRvForDictionaryInit
) override
;
989 SetDimensions(int32_t width
, int32_t height
) override
;
990 bool UpdateWebRenderCanvasData(
991 nsDisplayListBuilder
* aBuilder
,
992 layers::WebRenderCanvasData
* aCanvasData
) override
;
996 int32_t GetWidth() override
{ return AutoAssertCast(DrawingBufferSize().x
); }
997 int32_t GetHeight() override
{ return AutoAssertCast(DrawingBufferSize().y
); }
999 NS_IMETHOD
InitializeWithDrawTarget(nsIDocShell
*,
1000 NotNull
<gfx::DrawTarget
*>) override
{
1001 return NS_ERROR_NOT_IMPLEMENTED
;
1004 void ResetBitmap() override
;
1006 UniquePtr
<uint8_t[]> GetImageBuffer(int32_t* out_format
,
1007 gfx::IntSize
* out_imageSize
) override
;
1008 NS_IMETHOD
GetInputStream(const char* mimeType
,
1009 const nsAString
& encoderOptions
,
1010 nsIInputStream
** out_stream
) override
;
1012 already_AddRefed
<mozilla::gfx::SourceSurface
> GetSurfaceSnapshot(
1013 gfxAlphaType
* out_alphaType
) override
;
1015 void SetOpaqueValueFromOpaqueAttr(bool) override
{};
1016 bool GetIsOpaque() override
{ return !mInitialOptions
->alpha
; }
1019 * An abstract base class to be implemented by callers wanting to be notified
1020 * that a refresh has occurred. Callers must ensure an observer is removed
1021 * before it is destroyed.
1023 void DidRefresh() override
;
1025 NS_IMETHOD
Redraw(const gfxRect
&) override
{
1026 return NS_ERROR_NOT_IMPLEMENTED
;
1032 layers::LayersBackend
GetCompositorBackendType() const;
1034 Watchable
<FrameCaptureState
> mFrameCaptureState
= {
1035 FrameCaptureState::CLEAN
, "ClientWebGLContext::mFrameCaptureState"};
1037 // -------------------------------------------------------------------------
1038 // WebGLRenderingContext Basic Properties and Methods
1039 // -------------------------------------------------------------------------
1041 dom::HTMLCanvasElement
* GetCanvas() const { return mCanvasElement
; }
1044 dom::Nullable
<dom::OwningHTMLCanvasElementOrOffscreenCanvas
>& retval
);
1046 GLsizei
DrawingBufferWidth() {
1047 const FuncScope
funcScope(*this, "drawingBufferWidth");
1048 return AutoAssertCast(DrawingBufferSize().x
);
1050 GLsizei
DrawingBufferHeight() {
1051 const FuncScope
funcScope(*this, "drawingBufferHeight");
1052 return AutoAssertCast(DrawingBufferSize().y
);
1058 std::optional
<dom::PredefinedColorSpace
> mDrawingBufferColorSpace
;
1059 std::optional
<dom::PredefinedColorSpace
> mUnpackColorSpace
;
1062 auto DrawingBufferColorSpace() const {
1063 return mDrawingBufferColorSpace
? *mDrawingBufferColorSpace
1064 : dom::PredefinedColorSpace::Srgb
;
1066 void SetDrawingBufferColorSpace(dom::PredefinedColorSpace
);
1068 auto UnpackColorSpace() const {
1069 return mUnpackColorSpace
? *mUnpackColorSpace
1070 : dom::PredefinedColorSpace::Srgb
;
1072 void SetUnpackColorSpace(dom::PredefinedColorSpace
);
1076 void GetContextAttributes(dom::Nullable
<dom::WebGLContextAttributes
>& retval
);
1079 webgl::SwapChainOptions
PrepareAsyncSwapChainOptions(
1080 WebGLFramebufferJS
* fb
, bool webvr
,
1081 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1084 layers::TextureType
GetTexTypeForSwapChain() const;
1086 WebGLFramebufferJS
*, const bool webvr
= false,
1087 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1089 WebGLFramebufferJS
*, layers::TextureType
, const bool webvr
= false,
1090 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1091 void CopyToSwapChain(
1092 WebGLFramebufferJS
*,
1093 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1095 Maybe
<layers::SurfaceDescriptor
> GetFrontBuffer(
1096 WebGLFramebufferJS
*, const bool webvr
= false) override
;
1097 Maybe
<layers::SurfaceDescriptor
> PresentFrontBuffer(
1098 WebGLFramebufferJS
*, const bool webvr
= false) override
;
1099 RefPtr
<gfx::SourceSurface
> GetFrontBufferSnapshot(
1100 bool requireAlphaPremult
= true) override
;
1101 already_AddRefed
<layers::FwdTransactionTracker
> UseCompositableForwarder(
1102 layers::CompositableForwarder
* aForwarder
) override
;
1103 void OnDestroyChild(dom::WebGLChild
* aChild
);
1105 void ClearVRSwapChain();
1108 RefPtr
<gfx::DataSourceSurface
> BackBufferSnapshot();
1109 [[nodiscard
]] bool DoReadPixels(const webgl::ReadPixelsDesc
&,
1110 Span
<uint8_t>) const;
1111 uvec2
DrawingBufferSize();
1115 mutable bool mAutoFlushPending
= false;
1117 void AutoEnqueueFlush() const {
1118 if (MOZ_LIKELY(mAutoFlushPending
)) return;
1119 mAutoFlushPending
= true;
1121 const auto DeferredFlush
= [weak
=
1122 WeakPtr
<const ClientWebGLContext
>(this)]() {
1123 const auto strong
= RefPtr
<const ClientWebGLContext
>(weak
);
1124 if (!strong
) return;
1125 if (!strong
->mAutoFlushPending
) return;
1126 strong
->mAutoFlushPending
= false;
1128 if (!StaticPrefs::webgl_auto_flush()) return;
1129 const bool flushGl
= StaticPrefs::webgl_auto_flush_gl();
1130 strong
->Flush(flushGl
);
1133 already_AddRefed
<mozilla::CancelableRunnable
> runnable
=
1134 NS_NewCancelableRunnableFunction("ClientWebGLContext::DeferredFlush",
1136 NS_DispatchToCurrentThread(std::move(runnable
));
1139 void CancelAutoFlush() const { mAutoFlushPending
= false; }
1143 void AfterDrawCall() {
1144 if (!mNotLost
) return;
1145 const auto& state
= State();
1146 if (!state
.mBoundDrawFb
) {
1153 // -------------------------------------------------------------------------
1154 // Client-side helper methods. Dispatch to a Host method.
1155 // -------------------------------------------------------------------------
1157 // ------------------------- GL State -------------------------
1159 bool IsContextLost() const { return !mNotLost
; }
1161 void Disable(GLenum cap
) const { SetEnabledI(cap
, {}, false); }
1162 void Enable(GLenum cap
) const { SetEnabledI(cap
, {}, true); }
1163 void SetEnabledI(GLenum cap
, Maybe
<GLuint
> i
, bool val
) const;
1165 bool IsEnabled(GLenum cap
) const;
1168 Maybe
<double> GetNumber(GLenum pname
);
1169 Maybe
<std::string
> GetString(GLenum pname
);
1172 void GetParameter(JSContext
* cx
, GLenum pname
,
1173 JS::MutableHandle
<JS::Value
> retval
, ErrorResult
& rv
,
1174 bool debug
= false);
1176 void GetBufferParameter(JSContext
* cx
, GLenum target
, GLenum pname
,
1177 JS::MutableHandle
<JS::Value
> retval
) const;
1179 void GetFramebufferAttachmentParameter(JSContext
* cx
, GLenum target
,
1180 GLenum attachment
, GLenum pname
,
1181 JS::MutableHandle
<JS::Value
> retval
,
1182 ErrorResult
& rv
) const;
1184 void GetRenderbufferParameter(JSContext
* cx
, GLenum target
, GLenum pname
,
1185 JS::MutableHandle
<JS::Value
> retval
) const;
1187 void GetIndexedParameter(JSContext
* cx
, GLenum target
, GLuint index
,
1188 JS::MutableHandle
<JS::Value
> retval
,
1189 ErrorResult
& rv
) const;
1191 already_AddRefed
<WebGLShaderPrecisionFormatJS
> GetShaderPrecisionFormat(
1192 GLenum shadertype
, GLenum precisiontype
);
1194 void UseProgram(WebGLProgramJS
*);
1195 void ValidateProgram(WebGLProgramJS
&) const;
1199 already_AddRefed
<WebGLBufferJS
> CreateBuffer() const;
1200 already_AddRefed
<WebGLFramebufferJS
> CreateFramebuffer() const;
1201 already_AddRefed
<WebGLFramebufferJS
> CreateOpaqueFramebuffer(
1202 const webgl::OpaqueFramebufferOptions
&) const;
1203 already_AddRefed
<WebGLProgramJS
> CreateProgram() const;
1204 already_AddRefed
<WebGLQueryJS
> CreateQuery() const;
1205 already_AddRefed
<WebGLRenderbufferJS
> CreateRenderbuffer() const;
1206 already_AddRefed
<WebGLSamplerJS
> CreateSampler() const;
1207 already_AddRefed
<WebGLShaderJS
> CreateShader(GLenum type
) const;
1208 already_AddRefed
<WebGLSyncJS
> FenceSync(GLenum condition
,
1209 GLbitfield flags
) const;
1210 already_AddRefed
<WebGLTextureJS
> CreateTexture() const;
1211 already_AddRefed
<WebGLTransformFeedbackJS
> CreateTransformFeedback() const;
1212 already_AddRefed
<WebGLVertexArrayJS
> CreateVertexArray() const;
1214 void DeleteBuffer(WebGLBufferJS
*);
1215 void DeleteFramebuffer(WebGLFramebufferJS
*, bool canDeleteOpaque
= false);
1216 void DeleteProgram(WebGLProgramJS
*) const;
1217 void DeleteQuery(WebGLQueryJS
*);
1218 void DeleteRenderbuffer(WebGLRenderbufferJS
*);
1219 void DeleteSampler(WebGLSamplerJS
*);
1220 void DeleteShader(WebGLShaderJS
*) const;
1221 void DeleteSync(WebGLSyncJS
*) const;
1222 void DeleteTexture(WebGLTextureJS
*);
1223 void DeleteTransformFeedback(WebGLTransformFeedbackJS
*);
1224 void DeleteVertexArray(WebGLVertexArrayJS
*);
1227 void DoDeleteProgram(WebGLProgramJS
&) const;
1228 void DoDeleteShader(const WebGLShaderJS
&) const;
1233 bool IsBuffer(const WebGLBufferJS
*) const;
1234 bool IsFramebuffer(const WebGLFramebufferJS
*) const;
1235 bool IsProgram(const WebGLProgramJS
*) const;
1236 bool IsQuery(const WebGLQueryJS
*) const;
1237 bool IsRenderbuffer(const WebGLRenderbufferJS
*) const;
1238 bool IsSampler(const WebGLSamplerJS
*) const;
1239 bool IsShader(const WebGLShaderJS
*) const;
1240 bool IsSync(const WebGLSyncJS
*) const;
1241 bool IsTexture(const WebGLTextureJS
*) const;
1242 bool IsTransformFeedback(const WebGLTransformFeedbackJS
*) const;
1243 bool IsVertexArray(const WebGLVertexArrayJS
*) const;
1249 const webgl::LinkResult
& GetLinkResult(const WebGLProgramJS
&) const;
1252 void AttachShader(WebGLProgramJS
&, WebGLShaderJS
&) const;
1253 void BindAttribLocation(WebGLProgramJS
&, GLuint location
,
1254 const nsAString
& name
) const;
1255 void DetachShader(WebGLProgramJS
&, const WebGLShaderJS
&) const;
1256 void GetAttachedShaders(
1257 const WebGLProgramJS
&,
1258 dom::Nullable
<nsTArray
<RefPtr
<WebGLShaderJS
>>>& retval
) const;
1259 void LinkProgram(WebGLProgramJS
&) const;
1260 void TransformFeedbackVaryings(WebGLProgramJS
&,
1261 const dom::Sequence
<nsString
>& varyings
,
1262 GLenum bufferMode
) const;
1263 void UniformBlockBinding(WebGLProgramJS
&, GLuint blockIndex
,
1264 GLuint blockBinding
) const;
1266 // Link result reflection
1267 already_AddRefed
<WebGLActiveInfoJS
> GetActiveAttrib(const WebGLProgramJS
&,
1269 already_AddRefed
<WebGLActiveInfoJS
> GetActiveUniform(const WebGLProgramJS
&,
1271 void GetActiveUniformBlockName(const WebGLProgramJS
&,
1272 GLuint uniformBlockIndex
,
1273 nsAString
& retval
) const;
1274 void GetActiveUniformBlockParameter(JSContext
* cx
, const WebGLProgramJS
&,
1275 GLuint uniformBlockIndex
, GLenum pname
,
1276 JS::MutableHandle
<JS::Value
> retval
,
1278 void GetActiveUniforms(JSContext
*, const WebGLProgramJS
&,
1279 const dom::Sequence
<GLuint
>& uniformIndices
,
1281 JS::MutableHandle
<JS::Value
> retval
) const;
1282 GLint
GetAttribLocation(const WebGLProgramJS
&, const nsAString
& name
) const;
1283 GLint
GetFragDataLocation(const WebGLProgramJS
&, const nsAString
& name
) const;
1284 void GetProgramInfoLog(const WebGLProgramJS
& prog
, nsAString
& retval
) const;
1285 void GetProgramParameter(JSContext
*, const WebGLProgramJS
&, GLenum pname
,
1286 JS::MutableHandle
<JS::Value
> retval
) const;
1287 already_AddRefed
<WebGLActiveInfoJS
> GetTransformFeedbackVarying(
1288 const WebGLProgramJS
&, GLuint index
);
1289 GLuint
GetUniformBlockIndex(const WebGLProgramJS
&,
1290 const nsAString
& uniformBlockName
) const;
1291 void GetUniformIndices(const WebGLProgramJS
&,
1292 const dom::Sequence
<nsString
>& uniformNames
,
1293 dom::Nullable
<nsTArray
<GLuint
>>& retval
) const;
1295 // WebGLUniformLocationJS
1296 already_AddRefed
<WebGLUniformLocationJS
> GetUniformLocation(
1297 const WebGLProgramJS
&, const nsAString
& name
) const;
1298 void GetUniform(JSContext
*, const WebGLProgramJS
&,
1299 const WebGLUniformLocationJS
&,
1300 JS::MutableHandle
<JS::Value
> retval
);
1306 const webgl::CompileResult
& GetCompileResult(const WebGLShaderJS
&) const;
1309 void CompileShader(WebGLShaderJS
&) const;
1310 void GetShaderInfoLog(const WebGLShaderJS
&, nsAString
& retval
) const;
1311 void GetShaderParameter(JSContext
*, const WebGLShaderJS
&, GLenum pname
,
1312 JS::MutableHandle
<JS::Value
> retval
) const;
1313 void GetShaderSource(const WebGLShaderJS
&, nsAString
& retval
) const;
1314 void GetTranslatedShaderSource(const WebGLShaderJS
& shader
,
1315 nsAString
& retval
) const;
1316 void ShaderSource(WebGLShaderJS
&, const nsAString
&) const;
1320 void BindFramebuffer(GLenum target
, WebGLFramebufferJS
*);
1322 void BlendColor(GLclampf r
, GLclampf g
, GLclampf b
, GLclampf a
);
1326 void BlendEquation(GLenum mode
) { BlendEquationSeparate(mode
, mode
); }
1327 void BlendFunc(GLenum sfactor
, GLenum dfactor
) {
1328 BlendFuncSeparate(sfactor
, dfactor
, sfactor
, dfactor
);
1331 void BlendEquationSeparate(GLenum modeRGB
, GLenum modeAlpha
) {
1332 BlendEquationSeparateI({}, modeRGB
, modeAlpha
);
1334 void BlendFuncSeparate(GLenum srcRGB
, GLenum dstRGB
, GLenum srcAlpha
,
1336 BlendFuncSeparateI({}, srcRGB
, dstRGB
, srcAlpha
, dstAlpha
);
1339 void BlendEquationSeparateI(Maybe
<GLuint
> buf
, GLenum modeRGB
,
1341 void BlendFuncSeparateI(Maybe
<GLuint
> buf
, GLenum srcRGB
, GLenum dstRGB
,
1342 GLenum srcAlpha
, GLenum dstAlpha
);
1346 GLenum
CheckFramebufferStatus(GLenum target
);
1348 void Clear(GLbitfield mask
);
1353 void ClearBufferTv(const GLenum buffer
, const GLint drawBuffer
,
1354 const webgl::AttribBaseType type
,
1355 JS::AutoCheckCannotGC
&& nogc
,
1356 const Span
<const uint8_t>& view
,
1357 const GLuint srcElemOffset
);
1360 void ClearBufferfv(GLenum buffer
, GLint drawBuffer
, const Float32ListU
& list
,
1361 GLuint srcElemOffset
) {
1362 const FuncScope
funcScope(*this, "clearBufferfv");
1363 if (!Convert(list
, [&](const Span
<const float>& aData
,
1364 JS::AutoCheckCannotGC
&& nogc
) {
1365 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Float
,
1366 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1369 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1372 void ClearBufferiv(GLenum buffer
, GLint drawBuffer
, const Int32ListU
& list
,
1373 GLuint srcElemOffset
) {
1374 const FuncScope
funcScope(*this, "clearBufferiv");
1375 if (!Convert(list
, [&](const Span
<const int32_t>& aData
,
1376 JS::AutoCheckCannotGC
&& nogc
) {
1377 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Int
,
1378 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1381 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1384 void ClearBufferuiv(GLenum buffer
, GLint drawBuffer
, const Uint32ListU
& list
,
1385 GLuint srcElemOffset
) {
1386 const FuncScope
funcScope(*this, "clearBufferuiv");
1387 if (!Convert(list
, [&](const Span
<const uint32_t>& aData
,
1388 JS::AutoCheckCannotGC
&& nogc
) {
1389 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Uint
,
1390 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1393 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1399 void ClearBufferfi(GLenum buffer
, GLint drawBuffer
, GLfloat depth
,
1402 void ClearColor(GLclampf r
, GLclampf g
, GLclampf b
, GLclampf a
);
1404 void ClearDepth(GLclampf v
);
1406 void ClearStencil(GLint v
);
1408 void ColorMask(bool r
, bool g
, bool b
, bool a
) const {
1409 ColorMaskI({}, r
, g
, b
, a
);
1411 void ColorMaskI(Maybe
<GLuint
> buf
, bool r
, bool g
, bool b
, bool a
) const;
1413 void CullFace(GLenum face
);
1415 void DepthFunc(GLenum func
);
1417 void DepthMask(WebGLboolean b
);
1419 void DepthRange(GLclampf zNear
, GLclampf zFar
);
1421 void Flush(bool flushGl
= true) const;
1425 void FrontFace(GLenum mode
);
1429 void Hint(GLenum target
, GLenum mode
);
1431 void LineWidth(GLfloat width
);
1433 void PixelStorei(GLenum pname
, GLint param
);
1435 void PolygonOffset(GLfloat factor
, GLfloat units
);
1437 void SampleCoverage(GLclampf value
, WebGLboolean invert
);
1439 void Scissor(GLint x
, GLint y
, GLsizei width
, GLsizei height
);
1443 void StencilFunc(GLenum func
, GLint ref
, GLuint mask
) {
1444 StencilFuncSeparate(LOCAL_GL_FRONT_AND_BACK
, func
, ref
, mask
);
1446 void StencilMask(GLuint mask
) {
1447 StencilMaskSeparate(LOCAL_GL_FRONT_AND_BACK
, mask
);
1449 void StencilOp(GLenum sfail
, GLenum dpfail
, GLenum dppass
) {
1450 StencilOpSeparate(LOCAL_GL_FRONT_AND_BACK
, sfail
, dpfail
, dppass
);
1453 void StencilFuncSeparate(GLenum face
, GLenum func
, GLint ref
, GLuint mask
);
1454 void StencilMaskSeparate(GLenum face
, GLuint mask
);
1455 void StencilOpSeparate(GLenum face
, GLenum sfail
, GLenum dpfail
,
1460 void Viewport(GLint x
, GLint y
, GLsizei width
, GLsizei height
);
1462 // ------------------------- Buffer Objects -------------------------
1464 void BindBuffer(GLenum target
, WebGLBufferJS
*);
1469 void BindBufferRangeImpl(const GLenum target
, const GLuint index
,
1470 WebGLBufferJS
* const buffer
, const uint64_t offset
,
1471 const uint64_t size
);
1474 void BindBufferBase(const GLenum target
, const GLuint index
,
1475 WebGLBufferJS
* const buffer
) {
1476 const FuncScope
funcScope(*this, "bindBufferBase");
1477 if (IsContextLost()) return;
1479 BindBufferRangeImpl(target
, index
, buffer
, 0, 0);
1482 void BindBufferRange(const GLenum target
, const GLuint index
,
1483 WebGLBufferJS
* const buffer
, const WebGLintptr offset
,
1484 const WebGLsizeiptr size
) {
1485 const FuncScope
funcScope(*this, "bindBufferRange");
1486 if (IsContextLost()) return;
1489 if (!ValidateNonNegative("offset", offset
)) return;
1492 EnqueueError(LOCAL_GL_INVALID_VALUE
,
1493 "`size` must be positive for non-null `buffer`.");
1498 BindBufferRangeImpl(target
, index
, buffer
, static_cast<uint64_t>(offset
),
1499 static_cast<uint64_t>(size
));
1504 void CopyBufferSubData(GLenum readTarget
, GLenum writeTarget
,
1505 GLintptr readOffset
, GLintptr writeOffset
,
1508 void BufferData(GLenum target
, WebGLsizeiptr size
, GLenum usage
);
1509 void BufferData(GLenum target
,
1510 const dom::Nullable
<dom::ArrayBuffer
>& maybeSrc
,
1512 void BufferData(GLenum target
, const dom::ArrayBufferView
& srcData
,
1513 GLenum usage
, GLuint srcElemOffset
= 0,
1514 GLuint srcElemCountOverride
= 0);
1516 void BufferSubData(GLenum target
, WebGLsizeiptr dstByteOffset
,
1517 const dom::ArrayBufferView
& src
, GLuint srcElemOffset
= 0,
1518 GLuint srcElemCountOverride
= 0);
1519 void BufferSubData(GLenum target
, WebGLsizeiptr dstByteOffset
,
1520 const dom::ArrayBuffer
& src
);
1522 void GetBufferSubData(GLenum target
, GLintptr srcByteOffset
,
1523 const dom::ArrayBufferView
& dstData
,
1524 GLuint dstElemOffset
, GLuint dstElemCountOverride
);
1526 // -------------------------- Framebuffer Objects --------------------------
1528 void BlitFramebuffer(GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
1529 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
,
1530 GLbitfield mask
, GLenum filter
);
1535 // `bindTarget` if non-zero allows initializing the rb/tex with that target.
1536 void FramebufferAttach(GLenum target
, GLenum attachEnum
, GLenum bindTarget
,
1537 WebGLRenderbufferJS
*, WebGLTextureJS
*,
1538 uint32_t mipLevel
, uint32_t zLayer
,
1539 uint32_t numViewLayers
) const;
1542 void FramebufferRenderbuffer(GLenum target
, GLenum attachSlot
,
1543 GLenum rbTarget
, WebGLRenderbufferJS
* rb
) const {
1544 const FuncScope
funcScope(*this, "framebufferRenderbuffer");
1545 if (IsContextLost()) return;
1546 if (rbTarget
!= LOCAL_GL_RENDERBUFFER
) {
1547 EnqueueError_ArgEnum("rbTarget", rbTarget
);
1550 FramebufferAttach(target
, attachSlot
, rbTarget
, rb
, nullptr, 0, 0, 0);
1553 void FramebufferTexture2D(GLenum target
, GLenum attachSlot
,
1554 GLenum texImageTarget
, WebGLTextureJS
*,
1555 GLint mipLevel
) const;
1557 void FramebufferTextureLayer(GLenum target
, GLenum attachSlot
,
1558 WebGLTextureJS
* tex
, GLint mipLevel
,
1559 GLint zLayer
) const {
1560 const FuncScope
funcScope(*this, "framebufferTextureLayer");
1561 if (IsContextLost()) return;
1562 FramebufferAttach(target
, attachSlot
, 0, nullptr, tex
,
1563 static_cast<uint32_t>(mipLevel
),
1564 static_cast<uint32_t>(zLayer
), 0);
1567 void FramebufferTextureMultiview(GLenum target
, GLenum attachSlot
,
1568 WebGLTextureJS
* tex
, GLint mipLevel
,
1570 GLsizei numViewLayers
) const {
1571 const FuncScope
funcScope(*this, "framebufferTextureMultiview");
1572 if (IsContextLost()) return;
1573 if (tex
&& numViewLayers
< 1) {
1574 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`numViewLayers` must be >=1.");
1577 FramebufferAttach(target
, attachSlot
, 0, nullptr, tex
,
1578 static_cast<uint32_t>(mipLevel
),
1579 static_cast<uint32_t>(zLayerBase
),
1580 static_cast<uint32_t>(numViewLayers
));
1585 void InvalidateFramebuffer(GLenum target
,
1586 const dom::Sequence
<GLenum
>& attachments
,
1587 ErrorResult
& unused
);
1588 void InvalidateSubFramebuffer(GLenum target
,
1589 const dom::Sequence
<GLenum
>& attachments
,
1590 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
1591 ErrorResult
& unused
);
1593 void ReadBuffer(GLenum mode
);
1595 // ----------------------- Renderbuffer objects -----------------------
1596 void GetInternalformatParameter(JSContext
* cx
, GLenum target
,
1597 GLenum internalformat
, GLenum pname
,
1598 JS::MutableHandle
<JS::Value
> retval
,
1601 void BindRenderbuffer(GLenum target
, WebGLRenderbufferJS
*);
1603 void RenderbufferStorage(GLenum target
, GLenum internalFormat
, GLsizei width
,
1604 GLsizei height
) const {
1605 RenderbufferStorageMultisample(target
, 0, internalFormat
, width
, height
);
1608 void RenderbufferStorageMultisample(GLenum target
, GLsizei samples
,
1609 GLenum internalFormat
, GLsizei width
,
1610 GLsizei height
) const;
1612 // --------------------------- Texture objects ---------------------------
1614 void ActiveTexture(GLenum texUnit
);
1616 void BindTexture(GLenum texTarget
, WebGLTextureJS
*);
1618 void GenerateMipmap(GLenum texTarget
) const;
1620 void GetTexParameter(JSContext
* cx
, GLenum texTarget
, GLenum pname
,
1621 JS::MutableHandle
<JS::Value
> retval
) const;
1623 void TexParameterf(GLenum texTarget
, GLenum pname
, GLfloat param
);
1624 void TexParameteri(GLenum texTarget
, GLenum pname
, GLint param
);
1629 void TexStorage(uint8_t funcDims
, GLenum target
, GLsizei levels
,
1630 GLenum internalFormat
, const ivec3
& size
) const;
1632 // Primitive tex upload functions
1633 void TexImage(uint8_t funcDims
, GLenum target
, GLint level
,
1634 GLenum respecFormat
, const ivec3
& offset
,
1635 const Maybe
<ivec3
>& size
, GLint border
,
1636 const webgl::PackingInfo
& pi
, const TexImageSource
& src
) const;
1637 void CompressedTexImage(bool sub
, uint8_t funcDims
, GLenum target
,
1638 GLint level
, GLenum format
, const ivec3
& offset
,
1639 const ivec3
& size
, GLint border
,
1640 const TexImageSource
& src
,
1641 GLsizei pboImageSize
) const;
1642 void CopyTexImage(uint8_t funcDims
, GLenum target
, GLint level
,
1643 GLenum respecFormat
, const ivec3
& dstOffset
,
1644 const ivec2
& srcOffset
, const ivec2
& size
,
1645 GLint border
) const;
1648 void TexStorage2D(GLenum target
, GLsizei levels
, GLenum internalFormat
,
1649 GLsizei width
, GLsizei height
) const {
1650 TexStorage(2, target
, levels
, internalFormat
, {width
, height
, 1});
1653 void TexStorage3D(GLenum target
, GLsizei levels
, GLenum internalFormat
,
1654 GLsizei width
, GLsizei height
, GLsizei depth
) const {
1655 TexStorage(3, target
, levels
, internalFormat
, {width
, height
, depth
});
1658 ////////////////////////////////////
1660 template <typename T
> // TexImageSource or WebGLintptr
1661 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1662 GLsizei width
, GLsizei height
, GLint border
,
1663 GLenum unpackFormat
, GLenum unpackType
, const T
& anySrc
,
1664 ErrorResult
& out_error
) const {
1665 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1666 TexImage(2, target
, level
, internalFormat
, {0, 0, 0},
1667 Some(ivec3
{width
, height
, 1}), border
, {unpackFormat
, unpackType
},
1671 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1672 GLsizei width
, GLsizei height
, GLint border
,
1673 GLenum unpackFormat
, GLenum unpackType
,
1674 const dom::ArrayBufferView
& view
, GLuint viewElemOffset
,
1675 ErrorResult
&) const {
1676 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1677 TexImage(2, target
, level
, internalFormat
, {0, 0, 0},
1678 Some(ivec3
{width
, height
, 1}), border
, {unpackFormat
, unpackType
},
1684 template <typename T
> // TexImageSource or WebGLintptr
1685 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1686 GLsizei width
, GLsizei height
, GLenum unpackFormat
,
1687 GLenum unpackType
, const T
& anySrc
,
1688 ErrorResult
& out_error
) const {
1689 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1690 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0},
1691 Some(ivec3
{width
, height
, 1}), 0, {unpackFormat
, unpackType
}, src
);
1694 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1695 GLsizei width
, GLsizei height
, GLenum unpackFormat
,
1696 GLenum unpackType
, const dom::ArrayBufferView
& view
,
1697 GLuint viewElemOffset
, ErrorResult
&) const {
1698 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1699 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0},
1700 Some(ivec3
{width
, height
, 1}), 0, {unpackFormat
, unpackType
}, src
);
1705 template <typename T
> // TexImageSource or WebGLintptr
1706 void TexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1707 GLsizei width
, GLsizei height
, GLsizei depth
, GLint border
,
1708 GLenum unpackFormat
, GLenum unpackType
, const T
& anySrc
,
1709 ErrorResult
& out_error
) const {
1710 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1711 TexImage(3, target
, level
, internalFormat
, {0, 0, 0},
1712 Some(ivec3
{width
, height
, depth
}), border
,
1713 {unpackFormat
, unpackType
}, src
);
1716 void TexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1717 GLsizei width
, GLsizei height
, GLsizei depth
, GLint border
,
1718 GLenum unpackFormat
, GLenum unpackType
,
1719 const dom::ArrayBufferView
& view
, GLuint viewElemOffset
,
1720 ErrorResult
&) const {
1721 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1722 TexImage(3, target
, level
, internalFormat
, {0, 0, 0},
1723 Some(ivec3
{width
, height
, depth
}), border
,
1724 {unpackFormat
, unpackType
}, src
);
1729 template <typename T
> // TexImageSource or WebGLintptr
1730 void TexSubImage3D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1731 GLint zOffset
, GLsizei width
, GLsizei height
,
1732 GLsizei depth
, GLenum unpackFormat
, GLenum unpackType
,
1733 const T
& anySrc
, ErrorResult
& out_error
) const {
1734 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1735 TexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
},
1736 Some(ivec3
{width
, height
, depth
}), 0, {unpackFormat
, unpackType
},
1740 void TexSubImage3D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1741 GLint zOffset
, GLsizei width
, GLsizei height
,
1742 GLsizei depth
, GLenum unpackFormat
, GLenum unpackType
,
1743 const dom::Nullable
<dom::ArrayBufferView
>& maybeSrcView
,
1744 GLuint srcElemOffset
, ErrorResult
&) const {
1745 const TexImageSourceAdapter
src(&maybeSrcView
, srcElemOffset
);
1746 TexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
},
1747 Some(ivec3
{width
, height
, depth
}), 0, {unpackFormat
, unpackType
},
1751 ////////////////////////////////////
1754 void CompressedTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1755 GLsizei width
, GLsizei height
, GLint border
,
1756 GLsizei imageSize
, WebGLintptr offset
) const {
1757 const TexImageSourceAdapter
src(&offset
);
1758 CompressedTexImage(false, 2, target
, level
, internalFormat
, {0, 0, 0},
1759 {width
, height
, 1}, border
, src
, imageSize
);
1762 void CompressedTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1763 GLsizei width
, GLsizei height
, GLint border
,
1764 const dom::ArrayBufferView
& view
,
1765 GLuint viewElemOffset
= 0,
1766 GLuint viewElemLengthOverride
= 0) const {
1767 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1768 viewElemLengthOverride
);
1769 CompressedTexImage(false, 2, target
, level
, internalFormat
, {0, 0, 0},
1770 {width
, height
, 1}, border
, src
, 0);
1775 void CompressedTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1776 GLint yOffset
, GLsizei width
, GLsizei height
,
1777 GLenum unpackFormat
, GLsizei imageSize
,
1778 WebGLintptr offset
) const {
1779 const TexImageSourceAdapter
src(&offset
);
1780 CompressedTexImage(true, 2, target
, level
, unpackFormat
,
1781 {xOffset
, yOffset
, 0}, {width
, height
, 1}, 0, src
,
1785 void CompressedTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1786 GLint yOffset
, GLsizei width
, GLsizei height
,
1787 GLenum unpackFormat
,
1788 const dom::ArrayBufferView
& view
,
1789 GLuint viewElemOffset
= 0,
1790 GLuint viewElemLengthOverride
= 0) const {
1791 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1792 viewElemLengthOverride
);
1793 CompressedTexImage(true, 2, target
, level
, unpackFormat
,
1794 {xOffset
, yOffset
, 0}, {width
, height
, 1}, 0, src
, 0);
1799 void CompressedTexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1800 GLsizei width
, GLsizei height
, GLsizei depth
,
1801 GLint border
, GLsizei imageSize
,
1802 WebGLintptr offset
) const {
1803 const TexImageSourceAdapter
src(&offset
);
1804 CompressedTexImage(false, 3, target
, level
, internalFormat
, {0, 0, 0},
1805 {width
, height
, depth
}, border
, src
, imageSize
);
1808 void CompressedTexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1809 GLsizei width
, GLsizei height
, GLsizei depth
,
1810 GLint border
, const dom::ArrayBufferView
& view
,
1811 GLuint viewElemOffset
= 0,
1812 GLuint viewElemLengthOverride
= 0) const {
1813 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1814 viewElemLengthOverride
);
1815 CompressedTexImage(false, 3, target
, level
, internalFormat
, {0, 0, 0},
1816 {width
, height
, depth
}, border
, src
, 0);
1821 void CompressedTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1822 GLint yOffset
, GLint zOffset
, GLsizei width
,
1823 GLsizei height
, GLsizei depth
,
1824 GLenum unpackFormat
, GLsizei imageSize
,
1825 WebGLintptr offset
) const {
1826 const TexImageSourceAdapter
src(&offset
);
1827 CompressedTexImage(true, 3, target
, level
, unpackFormat
,
1828 {xOffset
, yOffset
, zOffset
}, {width
, height
, depth
}, 0,
1832 void CompressedTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1833 GLint yOffset
, GLint zOffset
, GLsizei width
,
1834 GLsizei height
, GLsizei depth
,
1835 GLenum unpackFormat
,
1836 const dom::ArrayBufferView
& view
,
1837 GLuint viewElemOffset
= 0,
1838 GLuint viewElemLengthOverride
= 0) const {
1839 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1840 viewElemLengthOverride
);
1841 CompressedTexImage(true, 3, target
, level
, unpackFormat
,
1842 {xOffset
, yOffset
, zOffset
}, {width
, height
, depth
}, 0,
1846 // --------------------
1848 void CopyTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1849 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
1850 GLint border
) const {
1851 CopyTexImage(2, target
, level
, internalFormat
, {0, 0, 0}, {x
, y
},
1852 {width
, height
}, border
);
1855 void CopyTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1856 GLint yOffset
, GLint x
, GLint y
, GLsizei width
,
1857 GLsizei height
) const {
1858 CopyTexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0}, {x
, y
},
1859 {width
, height
}, 0);
1862 void CopyTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1863 GLint yOffset
, GLint zOffset
, GLint x
, GLint y
,
1864 GLsizei width
, GLsizei height
) const {
1865 CopyTexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
}, {x
, y
},
1866 {width
, height
}, 0);
1869 // -------------------
1870 // legacy TexImageSource uploads without width/height.
1871 // The width/height params are webgl2 only, and let you do subrect
1872 // selection with e.g. width < UNPACK_ROW_LENGTH.
1874 template <typename TexImageSourceT
>
1875 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1876 GLenum unpackFormat
, GLenum unpackType
,
1877 const TexImageSourceT
& anySrc
, ErrorResult
& out_error
) const {
1878 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1879 TexImage(2, target
, level
, internalFormat
, {}, {}, 0,
1880 {unpackFormat
, unpackType
}, src
);
1883 template <typename TexImageSourceT
>
1884 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1885 GLenum unpackFormat
, GLenum unpackType
,
1886 const TexImageSourceT
& anySrc
,
1887 ErrorResult
& out_error
) const {
1888 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1889 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0}, {}, 0,
1890 {unpackFormat
, unpackType
}, src
);
1893 // ------------------------ Uniforms and attributes ------------------------
1896 Maybe
<double> GetVertexAttribPriv(GLuint index
, GLenum pname
);
1899 void GetVertexAttrib(JSContext
* cx
, GLuint index
, GLenum pname
,
1900 JS::MutableHandle
<JS::Value
> retval
, ErrorResult
& rv
);
1903 const webgl::LinkResult
* GetActiveLinkResult() const {
1904 const auto& state
= State();
1905 if (state
.mCurrentProgram
) {
1906 (void)GetLinkResult(*state
.mCurrentProgram
);
1908 return state
.mActiveLinkResult
.get();
1911 // Used by callers that have a `nogc` token that ensures that no GC will
1912 // happen while `bytes` is alive. Internally, the nogc range will be ended
1913 // after `bytes` is used (either successfully but where the data are possibly
1914 // sent over IPC which has a tendency to GC, or unsuccesfully in which case
1915 // error handling can GC.)
1916 void UniformData(GLenum funcElemType
, const WebGLUniformLocationJS
* const loc
,
1917 bool transpose
, const Range
<const uint8_t>& bytes
,
1918 JS::AutoCheckCannotGC
&& nogc
, GLuint elemOffset
= 0,
1919 GLuint elemCountOverride
= 0) const;
1921 // Used by callers that are not passing `bytes` that might be GC-controlled.
1922 // This will create an artificial and unnecessary nogc region that should
1923 // get optimized away to nothing.
1924 void UniformData(GLenum funcElemType
, const WebGLUniformLocationJS
* const loc
,
1925 bool transpose
, const Range
<const uint8_t>& bytes
,
1926 GLuint elemOffset
= 0, GLuint elemCountOverride
= 0) const {
1927 JS::AutoCheckCannotGC nogc
;
1928 UniformData(funcElemType
, loc
, transpose
, bytes
, std::move(nogc
),
1929 elemOffset
, elemCountOverride
);
1934 template <typename T
>
1935 Maybe
<Range
<T
>> ValidateSubrange(const Range
<T
>& data
, size_t elemOffset
,
1936 size_t elemLengthOverride
= 0) const {
1938 if (elemOffset
> ret
.length()) {
1939 EnqueueError(LOCAL_GL_INVALID_VALUE
,
1940 "`elemOffset` too large for `data`.");
1943 ret
= {ret
.begin() + elemOffset
, ret
.end()};
1944 if (elemLengthOverride
) {
1945 if (elemLengthOverride
> ret
.length()) {
1947 LOCAL_GL_INVALID_VALUE
,
1948 "`elemLengthOverride` too large for `data` and `elemOffset`.");
1951 ret
= {ret
.begin().get(), elemLengthOverride
};
1957 #define _(T, type_t, TYPE) \
1958 void Uniform1##T(const WebGLUniformLocationJS* const loc, type_t x) const { \
1959 const type_t arr[] = {x}; \
1960 UniformData(TYPE, loc, false, MakeByteRange(arr)); \
1962 void Uniform2##T(const WebGLUniformLocationJS* const loc, type_t x, \
1964 const type_t arr[] = {x, y}; \
1965 UniformData(TYPE##_VEC2, loc, false, MakeByteRange(arr)); \
1967 void Uniform3##T(const WebGLUniformLocationJS* const loc, type_t x, \
1968 type_t y, type_t z) const { \
1969 const type_t arr[] = {x, y, z}; \
1970 UniformData(TYPE##_VEC3, loc, false, MakeByteRange(arr)); \
1972 void Uniform4##T(const WebGLUniformLocationJS* const loc, type_t x, \
1973 type_t y, type_t z, type_t w) const { \
1974 const type_t arr[] = {x, y, z, w}; \
1975 UniformData(TYPE##_VEC4, loc, false, MakeByteRange(arr)); \
1978 _(f
, float, LOCAL_GL_FLOAT
)
1979 _(i
, int32_t, LOCAL_GL_INT
)
1980 _(ui
, uint32_t, LOCAL_GL_UNSIGNED_INT
)
1986 #define _(NT, TypeListU, TYPE) \
1987 void Uniform##NT##v(const WebGLUniformLocationJS* const loc, \
1988 const TypeListU& list, GLuint elemOffset = 0, \
1989 GLuint elemCountOverride = 0) const { \
1990 Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&& nogc) { \
1991 UniformData(TYPE, loc, false, MakeByteRange(aData), std::move(nogc), \
1992 elemOffset, elemCountOverride); \
1997 _(1f
, Float32ListU
, LOCAL_GL_FLOAT
)
1998 _(2f
, Float32ListU
, LOCAL_GL_FLOAT_VEC2
)
1999 _(3f
, Float32ListU
, LOCAL_GL_FLOAT_VEC3
)
2000 _(4f
, Float32ListU
, LOCAL_GL_FLOAT_VEC4
)
2001 _(1i
, Int32ListU
, LOCAL_GL_INT
)
2002 _(2i
, Int32ListU
, LOCAL_GL_INT_VEC2
)
2003 _(3i
, Int32ListU
, LOCAL_GL_INT_VEC3
)
2004 _(4i
, Int32ListU
, LOCAL_GL_INT_VEC4
)
2005 _(1ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT
)
2006 _(2ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC2
)
2007 _(3ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC3
)
2008 _(4ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC4
)
2015 void UniformMatrix##X##fv(const WebGLUniformLocationJS* loc, bool transpose, \
2016 const Float32ListU& list, GLuint elemOffset = 0, \
2017 GLuint elemCountOverride = 0) const { \
2018 Convert(list, [&](const Span<const float>& aData, \
2019 JS::AutoCheckCannotGC&& nogc) { \
2020 UniformData(LOCAL_GL_FLOAT_MAT##X, loc, transpose, MakeByteRange(aData), \
2021 std::move(nogc), elemOffset, elemCountOverride); \
2042 void EnableVertexAttribArray(GLuint index
);
2044 void DisableVertexAttribArray(GLuint index
);
2046 WebGLsizeiptr
GetVertexAttribOffset(GLuint index
, GLenum pname
);
2051 void VertexAttrib4Tv(GLuint index
, webgl::AttribBaseType
,
2052 const Range
<const uint8_t>&);
2055 void VertexAttrib1f(GLuint index
, GLfloat x
) {
2056 VertexAttrib4f(index
, x
, 0, 0, 1);
2058 void VertexAttrib2f(GLuint index
, GLfloat x
, GLfloat y
) {
2059 VertexAttrib4f(index
, x
, y
, 0, 1);
2061 void VertexAttrib3f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
) {
2062 VertexAttrib4f(index
, x
, y
, z
, 1);
2065 void VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
,
2067 const float arr
[4] = {x
, y
, z
, w
};
2068 VertexAttrib4Tv(index
, webgl::AttribBaseType::Float
, MakeByteRange(arr
));
2073 template <typename List
, typename T
, size_t N
>
2074 bool MakeArrayFromList(const List
& list
, T (&array
)[N
]) {
2075 bool badLength
= false;
2076 if (!Convert(list
, [&](const auto& aData
, JS::AutoCheckCannotGC
&&) {
2078 std::is_same_v
<std::remove_const_t
<
2079 std::remove_reference_t
<decltype(aData
[0])>>,
2081 if (N
> aData
.Length()) {
2086 std::copy_n(aData
.begin(), N
, array
);
2090 LOCAL_GL_INVALID_VALUE
,
2092 ? nsPrintfCString("Length of `list` must be >=%zu.", N
).get()
2093 : "Conversion of `list` failed.");
2099 void VertexAttrib1fv(const GLuint index
, const Float32ListU
& list
) {
2100 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2101 if (IsContextLost()) return;
2104 if (!MakeArrayFromList(list
, arr
)) {
2107 VertexAttrib1f(index
, arr
[0]);
2110 void VertexAttrib2fv(const GLuint index
, const Float32ListU
& list
) {
2111 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2112 if (IsContextLost()) return;
2115 if (!MakeArrayFromList(list
, arr
)) {
2118 VertexAttrib2f(index
, arr
[0], arr
[1]);
2121 void VertexAttrib3fv(const GLuint index
, const Float32ListU
& list
) {
2122 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2123 if (IsContextLost()) return;
2126 if (!MakeArrayFromList(list
, arr
)) {
2129 VertexAttrib3f(index
, arr
[0], arr
[1], arr
[2]);
2132 void VertexAttrib4fv(GLuint index
, const Float32ListU
& list
) {
2133 const FuncScope
funcScope(*this, "vertexAttrib4fv");
2135 if (!MakeArrayFromList(list
, arr
)) {
2138 VertexAttrib4Tv(index
, webgl::AttribBaseType::Float
, MakeByteRange(arr
));
2140 void VertexAttribI4iv(GLuint index
, const Int32ListU
& list
) {
2141 const FuncScope
funcScope(*this, "vertexAttribI4iv");
2143 if (!MakeArrayFromList(list
, arr
)) {
2146 VertexAttrib4Tv(index
, webgl::AttribBaseType::Int
, MakeByteRange(arr
));
2148 void VertexAttribI4uiv(GLuint index
, const Uint32ListU
& list
) {
2149 const FuncScope
funcScope(*this, "vertexAttribI4uiv");
2151 if (!MakeArrayFromList(list
, arr
)) {
2154 VertexAttrib4Tv(index
, webgl::AttribBaseType::Uint
, MakeByteRange(arr
));
2157 void VertexAttribI4i(GLuint index
, GLint x
, GLint y
, GLint z
, GLint w
) {
2158 const int32_t arr
[4] = {x
, y
, z
, w
};
2159 VertexAttrib4Tv(index
, webgl::AttribBaseType::Int
, MakeByteRange(arr
));
2161 void VertexAttribI4ui(GLuint index
, GLuint x
, GLuint y
, GLuint z
, GLuint w
) {
2162 const uint32_t arr
[4] = {x
, y
, z
, w
};
2163 VertexAttrib4Tv(index
, webgl::AttribBaseType::Uint
, MakeByteRange(arr
));
2167 void VertexAttribPointerImpl(bool isFuncInt
, GLuint index
, GLint size
,
2168 GLenum type
, WebGLboolean normalized
,
2169 GLsizei iStride
, WebGLintptr iByteOffset
);
2172 void VertexAttribIPointer(GLuint index
, GLint size
, GLenum type
,
2173 GLsizei stride
, WebGLintptr byteOffset
) {
2174 VertexAttribPointerImpl(true, index
, size
, type
, false, stride
, byteOffset
);
2177 void VertexAttribPointer(GLuint index
, GLint size
, GLenum type
,
2178 WebGLboolean normalized
, GLsizei stride
,
2179 WebGLintptr byteOffset
) {
2180 VertexAttribPointerImpl(false, index
, size
, type
, normalized
, stride
,
2184 // -------------------------------- Drawing -------------------------------
2186 void DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
2187 DrawArraysInstanced(mode
, first
, count
, 1);
2190 void DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
2191 WebGLintptr byteOffset
) {
2192 DrawElementsInstanced(mode
, count
, type
, byteOffset
, 1);
2195 void DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
, GLsizei count
,
2196 GLenum type
, WebGLintptr byteOffset
) {
2197 const FuncScope
funcScope(*this, "drawRangeElements");
2199 EnqueueError(LOCAL_GL_INVALID_VALUE
, "end must be >= start.");
2202 DrawElementsInstanced(mode
, count
, type
, byteOffset
, 1);
2205 // ------------------------------ Readback -------------------------------
2207 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2208 GLenum format
, GLenum type
,
2209 const dom::Nullable
<dom::ArrayBufferView
>& maybeView
,
2210 dom::CallerType aCallerType
, ErrorResult
& out_error
) const {
2211 const FuncScope
funcScope(*this, "readPixels");
2212 if (!ValidateNonNull("pixels", maybeView
)) return;
2213 ReadPixels(x
, y
, width
, height
, format
, type
, maybeView
.Value(), 0,
2214 aCallerType
, out_error
);
2217 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2218 GLenum format
, GLenum type
, WebGLsizeiptr offset
,
2219 dom::CallerType aCallerType
, ErrorResult
& out_error
) const;
2221 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2222 GLenum format
, GLenum type
,
2223 const dom::ArrayBufferView
& dstData
, GLuint dstElemOffset
,
2224 dom::CallerType aCallerType
, ErrorResult
& out_error
) const;
2227 bool ReadPixels_SharedPrecheck(dom::CallerType aCallerType
,
2228 ErrorResult
& out_error
) const;
2230 // ------------------------------ Vertex Array ------------------------------
2232 void BindVertexArray(WebGLVertexArrayJS
*);
2234 void DrawArraysInstanced(GLenum mode
, GLint first
, GLsizei count
,
2237 void DrawElementsInstanced(GLenum mode
, GLsizei count
, GLenum type
,
2238 WebGLintptr offset
, GLsizei primcount
);
2240 void VertexAttribDivisor(GLuint index
, GLuint divisor
);
2242 // --------------------------------- GL Query
2243 // ---------------------------------
2245 void GetQuery(JSContext
*, GLenum target
, GLenum pname
,
2246 JS::MutableHandle
<JS::Value
> retval
) const;
2247 void GetQueryParameter(JSContext
*, WebGLQueryJS
&, GLenum pname
,
2248 JS::MutableHandle
<JS::Value
> retval
) const;
2249 void BeginQuery(GLenum target
, WebGLQueryJS
&);
2250 void EndQuery(GLenum target
);
2251 void QueryCounter(WebGLQueryJS
&, GLenum target
) const;
2253 // -------------------------------- Sampler -------------------------------
2255 void GetSamplerParameter(JSContext
*, const WebGLSamplerJS
&, GLenum pname
,
2256 JS::MutableHandle
<JS::Value
> retval
) const;
2258 void BindSampler(GLuint unit
, WebGLSamplerJS
*);
2259 void SamplerParameteri(WebGLSamplerJS
&, GLenum pname
, GLint param
) const;
2260 void SamplerParameterf(WebGLSamplerJS
&, GLenum pname
, GLfloat param
) const;
2262 // ------------------------------- GL Sync ---------------------------------
2264 GLenum
ClientWaitSync(WebGLSyncJS
&, GLbitfield flags
, GLuint64 timeout
) const;
2265 void GetSyncParameter(JSContext
*, WebGLSyncJS
&, GLenum pname
,
2266 JS::MutableHandle
<JS::Value
> retval
) const;
2267 void WaitSync(const WebGLSyncJS
&, GLbitfield flags
, GLint64 timeout
) const;
2269 mutable webgl::ObjectId mCompletedSyncId
= 0;
2270 void OnSyncComplete(webgl::ObjectId id
) const {
2271 if (mCompletedSyncId
< id
) {
2272 mCompletedSyncId
= id
;
2276 // -------------------------- Transform Feedback ---------------------------
2278 void BindTransformFeedback(GLenum target
, WebGLTransformFeedbackJS
*);
2279 void BeginTransformFeedback(GLenum primitiveMode
);
2280 void EndTransformFeedback();
2281 void PauseTransformFeedback();
2282 void ResumeTransformFeedback();
2284 // -------------------------- Opaque Framebuffers ---------------------------
2286 void SetFramebufferIsInOpaqueRAF(WebGLFramebufferJS
*, bool);
2288 // ------------------------------ Extensions ------------------------------
2290 void GetSupportedExtensions(dom::Nullable
<nsTArray
<nsString
>>& retval
,
2291 dom::CallerType callerType
) const;
2293 bool IsSupported(WebGLExtensionID
, dom::CallerType callerType
=
2294 dom::CallerType::NonSystem
) const;
2296 void GetExtension(JSContext
* cx
, const nsAString
& name
,
2297 JS::MutableHandle
<JSObject
*> retval
,
2298 dom::CallerType callerType
, ErrorResult
& rv
);
2301 bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext
,
2302 const dom::CallerType callerType
) const;
2304 RefPtr
<ClientWebGLExtensionBase
> GetExtension(WebGLExtensionID ext
,
2305 dom::CallerType callerType
);
2306 void RequestExtension(WebGLExtensionID
) const;
2309 bool IsExtensionEnabled(const WebGLExtensionID id
) const {
2310 return bool(mNotLost
->extensions
[UnderlyingValue(id
)]);
2313 void AddCompressedFormat(GLenum
);
2315 // ---------------------------- Misc Extensions ----------------------------
2317 void DrawBuffers(const dom::Sequence
<GLenum
>& buffers
);
2319 void GetSupportedProfilesASTC(
2320 dom::Nullable
<nsTArray
<nsString
>>& retval
) const;
2322 void MOZDebugGetParameter(JSContext
* cx
, GLenum pname
,
2323 JS::MutableHandle
<JS::Value
> retval
,
2325 GetParameter(cx
, pname
, retval
, rv
, true);
2328 void ProvokingVertex(GLenum rawMode
) const;
2330 // -------------------------------------------------------------------------
2331 // Client-side methods. Calls in the Host are forwarded to the client.
2332 // -------------------------------------------------------------------------
2334 void JsWarning(const std::string
&) const;
2336 // -------------------------------------------------------------------------
2337 // The cross-process communication mechanism
2338 // -------------------------------------------------------------------------
2340 // If we are running WebGL in this process then call the HostWebGLContext
2341 // method directly. Otherwise, dispatch over IPC.
2342 template <typename MethodType
, MethodType method
, typename
... CallerArgs
>
2343 void Run(const CallerArgs
&... args
) const {
2344 const auto id
= IdByMethod
<MethodType
, method
>();
2345 auto noNoGc
= std::optional
<JS::AutoCheckCannotGC
>{};
2346 Run_WithDestArgTypes_ConstnessHelper(std::move(noNoGc
), method
, id
,
2350 // Same as above for use when using potentially GC-controlled data. The scope
2351 // of `aNoGC` will be ended after the data is no longer needed.
2352 template <typename MethodType
, MethodType method
, typename
... CallerArgs
>
2353 void RunWithGCData(JS::AutoCheckCannotGC
&& aNoGC
,
2354 const CallerArgs
&... aArgs
) const {
2355 const auto id
= IdByMethod
<MethodType
, method
>();
2356 auto noGc
= std::optional
<JS::AutoCheckCannotGC
>{std::move(aNoGC
)};
2357 Run_WithDestArgTypes_ConstnessHelper(std::move(noGc
), method
, id
, aArgs
...);
2360 // Because we're trying to explicitly pull `DestArgs` via `method`, we have
2361 // one overload for mut-methods and one for const-methods.
2362 template <typename
... DestArgs
>
2363 void Run_WithDestArgTypes_ConstnessHelper(
2364 std::optional
<JS::AutoCheckCannotGC
>&& noGc
,
2365 void (HostWebGLContext::*method
)(DestArgs
...), const size_t id
,
2366 const std::remove_reference_t
<std::remove_const_t
<DestArgs
>>&... args
)
2368 Run_WithDestArgTypes(std::move(noGc
), method
, id
, args
...);
2370 template <typename
... DestArgs
>
2371 void Run_WithDestArgTypes_ConstnessHelper(
2372 std::optional
<JS::AutoCheckCannotGC
>&& noGc
,
2373 void (HostWebGLContext::*method
)(DestArgs
...) const, const size_t id
,
2374 const std::remove_reference_t
<std::remove_const_t
<DestArgs
>>&... args
)
2376 Run_WithDestArgTypes(std::move(noGc
), method
, id
, args
...);
2379 template <typename MethodT
, typename
... DestArgs
>
2380 void Run_WithDestArgTypes(std::optional
<JS::AutoCheckCannotGC
>&&, MethodT
,
2381 const size_t id
, const DestArgs
&...) const;
2383 // -------------------------------------------------------------------------
2384 // Helpers for DOM operations, composition, actors, etc
2385 // -------------------------------------------------------------------------
2388 // https://immersive-web.github.io/webxr/#xr-compatible
2389 bool IsXRCompatible() const;
2390 already_AddRefed
<dom::Promise
> MakeXRCompatible(ErrorResult
& aRv
);
2393 uint32_t GetPrincipalHashValue() const;
2395 // Prepare the context for capture before compositing
2396 void BeginComposition();
2398 // Clean up the context after captured for compositing
2399 void EndComposition();
2401 mozilla::dom::Document
* GetOwnerDoc() const;
2403 mutable bool mResetLayer
= true;
2404 Maybe
<const WebGLContextOptions
> mInitialOptions
;
2405 bool mXRCompatible
= false;
2408 // used by DOM bindings in conjunction with GetParentObject
2409 inline nsISupports
* ToSupports(ClientWebGLContext
* webgl
) {
2410 return static_cast<nsICanvasRenderingContextInternal
*>(webgl
);
2413 const char* GetExtensionName(WebGLExtensionID
);
2417 inline bool webgl::ObjectJS::IsForContext(
2418 const ClientWebGLContext
& context
) const {
2419 const auto& notLost
= context
.mNotLost
;
2420 if (!notLost
) return false;
2421 if (notLost
.get() != mGeneration
.lock().get()) return false;
2425 void AutoJsWarning(const std::string
& utf8
);
2427 } // namespace mozilla
2429 #endif // CLIENTWEBGLCONTEXT_H_