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 "WebGLFormats.h"
22 #include "WebGLStrongTypes.h"
23 #include "WebGLTypes.h"
25 #include "mozilla/Logging.h"
26 #include "WebGLCommandQueue.h"
29 #include <type_traits>
30 #include <unordered_map>
31 #include <unordered_set>
36 class ClientWebGLExtensionBase
;
37 class HostWebGLContext
;
39 template <typename MethodT
, MethodT Method
>
43 class OwningHTMLCanvasElementOrOffscreenCanvas
;
48 class AvailabilityRunnable
;
53 ////////////////////////////////////
55 class WebGLActiveInfoJS final
: public RefCounted
<WebGLActiveInfoJS
> {
57 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLActiveInfoJS
)
59 const webgl::ActiveInfo mInfo
;
61 explicit WebGLActiveInfoJS(const webgl::ActiveInfo
& info
) : mInfo(info
) {}
63 virtual ~WebGLActiveInfoJS() = default;
68 GLint
Size() const { return static_cast<GLint
>(mInfo
.elemCount
); }
69 GLenum
Type() const { return mInfo
.elemType
; }
71 void GetName(nsString
& retval
) const { CopyUTF8toUTF16(mInfo
.name
, retval
); }
73 bool WrapObject(JSContext
*, JS::Handle
<JSObject
*>,
74 JS::MutableHandle
<JSObject
*>);
77 class WebGLShaderPrecisionFormatJS final
78 : public RefCounted
<WebGLShaderPrecisionFormatJS
> {
80 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLShaderPrecisionFormatJS
)
82 const webgl::ShaderPrecisionFormat mInfo
;
84 explicit WebGLShaderPrecisionFormatJS(
85 const webgl::ShaderPrecisionFormat
& info
)
88 virtual ~WebGLShaderPrecisionFormatJS() = default;
90 GLint
RangeMin() const { return mInfo
.rangeMin
; }
91 GLint
RangeMax() const { return mInfo
.rangeMax
; }
92 GLint
Precision() const { return mInfo
.precision
; }
94 bool WrapObject(JSContext
*, JS::Handle
<JSObject
*>,
95 JS::MutableHandle
<JSObject
*>);
98 // -----------------------
100 class ClientWebGLContext
;
102 class WebGLFramebufferJS
;
103 class WebGLProgramJS
;
105 class WebGLRenderbufferJS
;
106 class WebGLSamplerJS
;
108 class WebGLTextureJS
;
109 class WebGLTransformFeedbackJS
;
110 class WebGLVertexArrayJS
;
116 class ProgramKeepAlive final
{
117 friend class mozilla::WebGLProgramJS
;
119 WebGLProgramJS
* mParent
;
122 explicit ProgramKeepAlive(WebGLProgramJS
& parent
) : mParent(&parent
) {}
126 class ShaderKeepAlive final
{
127 friend class mozilla::WebGLShaderJS
;
129 const WebGLShaderJS
* mParent
;
132 explicit ShaderKeepAlive(const WebGLShaderJS
& parent
) : mParent(&parent
) {}
136 class ContextGenerationInfo final
{
138 webgl::ExtensionBits mEnabledExtensions
;
139 RefPtr
<WebGLProgramJS
> mCurrentProgram
;
140 std::shared_ptr
<webgl::ProgramKeepAlive
> mProgramKeepAlive
;
141 mutable std::shared_ptr
<webgl::LinkResult
> mActiveLinkResult
;
143 RefPtr
<WebGLTransformFeedbackJS
> mDefaultTfo
;
144 RefPtr
<WebGLVertexArrayJS
> mDefaultVao
;
146 std::unordered_map
<GLenum
, RefPtr
<WebGLBufferJS
>> mBoundBufferByTarget
;
147 std::vector
<RefPtr
<WebGLBufferJS
>> mBoundUbos
;
148 RefPtr
<WebGLFramebufferJS
> mBoundDrawFb
;
149 RefPtr
<WebGLFramebufferJS
> mBoundReadFb
;
150 RefPtr
<WebGLRenderbufferJS
> mBoundRb
;
151 RefPtr
<WebGLTransformFeedbackJS
> mBoundTfo
;
152 RefPtr
<WebGLVertexArrayJS
> mBoundVao
;
153 std::unordered_map
<GLenum
, RefPtr
<WebGLQueryJS
>> mCurrentQueryByTarget
;
155 struct TexUnit final
{
156 RefPtr
<WebGLSamplerJS
> sampler
;
157 std::unordered_map
<GLenum
, RefPtr
<WebGLTextureJS
>> texByTarget
;
159 uint32_t mActiveTexUnit
= 0;
160 std::vector
<TexUnit
> mTexUnits
;
162 bool mTfActiveAndNotPaused
= false;
164 std::vector
<TypedQuad
> mGenericVertexAttribs
;
166 std::array
<int32_t, 4> mScissor
= {};
167 std::array
<int32_t, 4> mViewport
= {};
168 std::array
<float, 4> mClearColor
= {{0, 0, 0, 0}};
169 std::array
<float, 4> mBlendColor
= {{0, 0, 0, 0}};
170 std::array
<float, 2> mDepthRange
= {{0, 1}};
171 webgl::PixelPackingState mPixelPackState
;
172 webgl::PixelUnpackStateWebgl mPixelUnpackState
;
174 std::vector
<GLenum
> mCompressedTextureFormats
;
176 Maybe
<uvec2
> mDrawingBufferSize
;
178 webgl::ProvokingVertex mProvokingVertex
= webgl::ProvokingVertex::LastVertex
;
180 mutable Maybe
<std::unordered_map
<GLenum
, bool>> mIsEnabledMap
;
185 // In the cross process case, the WebGL actor's ownership relationship looks
187 // ---------------------------------------------------------------------
188 // | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext
189 // ---------------------------------------------------------------------
191 // where 'A -> B' means "A owns B"
193 struct NotLostData final
{
194 ClientWebGLContext
& context
;
195 webgl::InitContextResult info
;
197 RefPtr
<mozilla::dom::WebGLChild
> outOfProcess
;
198 UniquePtr
<HostWebGLContext
> inProcess
;
200 webgl::ContextGenerationInfo state
;
201 std::array
<RefPtr
<ClientWebGLExtensionBase
>,
202 UnderlyingValue(WebGLExtensionID::Max
)>
205 RefPtr
<layers::CanvasRenderer
> mCanvasRenderer
;
207 explicit NotLostData(ClientWebGLContext
& context
);
214 friend ClientWebGLContext
;
217 const std::weak_ptr
<NotLostData
> mGeneration
;
221 bool mDeleteRequested
= false;
223 explicit ObjectJS(const ClientWebGLContext
&);
224 virtual ~ObjectJS() = default;
227 ClientWebGLContext
* Context() const {
228 const auto locked
= mGeneration
.lock();
229 if (!locked
) return nullptr;
230 return &(locked
->context
);
233 ClientWebGLContext
* GetParentObject() const { return Context(); }
236 bool IsForContext(const ClientWebGLContext
&) const;
237 virtual bool IsDeleted() const { return mDeleteRequested
; }
239 bool IsUsable(const ClientWebGLContext
& context
) const {
240 return IsForContext(context
) && !IsDeleted();
244 bool ValidateUsable(const ClientWebGLContext
& context
,
245 const char* const argName
) const {
246 if (MOZ_LIKELY(IsUsable(context
))) return true;
247 WarnInvalidUse(context
, argName
);
252 bool ValidateForContext(const ClientWebGLContext
& context
,
253 const char* const argName
) const;
256 void WarnInvalidUse(const ClientWebGLContext
&, const char* argName
) const;
258 // The enum is INVALID_VALUE for Program/Shader :(
259 virtual GLenum
ErrorOnDeleted() const { return LOCAL_GL_INVALID_OPERATION
; }
264 // -------------------------
266 class WebGLBufferJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
267 friend class ClientWebGLContext
;
269 webgl::BufferKind mKind
=
270 webgl::BufferKind::Undefined
; // !IsBuffer until Bind
273 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBufferJS
)
274 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLBufferJS
)
276 explicit WebGLBufferJS(const ClientWebGLContext
& webgl
)
277 : webgl::ObjectJS(webgl
) {}
283 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
288 class WebGLFramebufferJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
289 friend class ClientWebGLContext
;
292 struct Attachment final
{
293 RefPtr
<WebGLRenderbufferJS
> rb
;
294 RefPtr
<WebGLTextureJS
> tex
;
298 bool mHasBeenBound
= false; // !IsFramebuffer until Bind
299 std::unordered_map
<GLenum
, Attachment
> mAttachments
;
302 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebufferJS
)
303 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLFramebufferJS
)
305 explicit WebGLFramebufferJS(const ClientWebGLContext
&, bool opaque
= false);
308 bool mInOpaqueRAF
= false;
311 ~WebGLFramebufferJS();
313 void EnsureColorAttachments();
316 Attachment
* GetAttachment(const GLenum slotEnum
) {
317 auto ret
= MaybeFind(mAttachments
, slotEnum
);
319 EnsureColorAttachments();
320 ret
= MaybeFind(mAttachments
, slotEnum
);
325 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
330 class WebGLProgramJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
331 friend class ClientWebGLContext
;
334 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgramJS
)
335 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLProgramJS
)
337 // If the REFCOUNTING macro isn't declared first, the AddRef at
338 // mInnerRef->js will panic when REFCOUNTING's "owning thread" var is still
341 struct Attachment final
{
342 RefPtr
<WebGLShaderJS
> shader
;
343 std::shared_ptr
<webgl::ShaderKeepAlive
> keepAlive
;
347 std::shared_ptr
<webgl::ProgramKeepAlive
> mKeepAlive
;
348 const std::weak_ptr
<webgl::ProgramKeepAlive
> mKeepAliveWeak
;
350 std::unordered_map
<GLenum
, Attachment
> mNextLink_Shaders
;
351 bool mLastValidate
= false;
352 mutable std::shared_ptr
<webgl::LinkResult
>
353 mResult
; // Never null, often defaulted.
355 struct UniformLocInfo final
{
356 const uint32_t location
;
357 const GLenum elemType
;
360 mutable Maybe
<std::unordered_map
<std::string
, UniformLocInfo
>>
362 mutable std::vector
<uint32_t> mUniformBlockBindings
;
364 std::unordered_set
<const WebGLTransformFeedbackJS
*> mActiveTfos
;
366 explicit WebGLProgramJS(const ClientWebGLContext
&);
369 mKeepAlive
= nullptr; // Try to delete.
371 const auto& maybe
= mKeepAliveWeak
.lock();
373 maybe
->mParent
= nullptr;
378 bool IsDeleted() const override
{ return !mKeepAliveWeak
.lock(); }
379 GLenum
ErrorOnDeleted() const override
{ return LOCAL_GL_INVALID_VALUE
; }
381 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
386 class WebGLQueryJS final
: public nsWrapperCache
,
387 public webgl::ObjectJS
,
388 public SupportsWeakPtr
{
389 friend class ClientWebGLContext
;
390 friend class webgl::AvailabilityRunnable
;
392 GLenum mTarget
= 0; // !IsQuery until Bind
393 bool mCanBeAvailable
= false;
396 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQueryJS
)
397 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLQueryJS
)
399 explicit WebGLQueryJS(const ClientWebGLContext
& webgl
)
400 : webgl::ObjectJS(webgl
) {}
406 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
411 class WebGLRenderbufferJS final
: public nsWrapperCache
,
412 public webgl::ObjectJS
{
413 friend class ClientWebGLContext
;
416 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbufferJS
)
417 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLRenderbufferJS
)
420 bool mHasBeenBound
= false; // !IsRenderbuffer until Bind
422 explicit WebGLRenderbufferJS(const ClientWebGLContext
& webgl
)
423 : webgl::ObjectJS(webgl
) {}
424 ~WebGLRenderbufferJS();
427 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
432 class WebGLSamplerJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
433 // IsSampler without Bind
435 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSamplerJS
)
436 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSamplerJS
)
438 explicit WebGLSamplerJS(const ClientWebGLContext
& webgl
)
439 : webgl::ObjectJS(webgl
) {}
445 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
450 class WebGLShaderJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
451 friend class ClientWebGLContext
;
454 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShaderJS
)
455 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLShaderJS
)
460 std::shared_ptr
<webgl::ShaderKeepAlive
> mKeepAlive
;
461 const std::weak_ptr
<webgl::ShaderKeepAlive
> mKeepAliveWeak
;
463 mutable webgl::CompileResult mResult
;
465 WebGLShaderJS(const ClientWebGLContext
&, GLenum type
);
468 mKeepAlive
= nullptr; // Try to delete.
470 const auto& maybe
= mKeepAliveWeak
.lock();
472 maybe
->mParent
= nullptr;
477 bool IsDeleted() const override
{ return !mKeepAliveWeak
.lock(); }
478 GLenum
ErrorOnDeleted() const override
{ return LOCAL_GL_INVALID_VALUE
; }
480 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
485 class WebGLSyncJS final
: public nsWrapperCache
,
486 public webgl::ObjectJS
,
487 public SupportsWeakPtr
{
488 friend class ClientWebGLContext
;
489 friend class webgl::AvailabilityRunnable
;
491 bool mCanBeAvailable
= false;
492 uint8_t mNumQueriesBeforeFirstFrameBoundary
= 0;
493 uint8_t mNumQueriesWithoutFlushCommandsBit
= 0;
496 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS
)
497 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSyncJS
)
499 explicit WebGLSyncJS(const ClientWebGLContext
& webgl
)
500 : webgl::ObjectJS(webgl
) {}
506 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
511 class WebGLTextureJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
512 friend class ClientWebGLContext
;
514 GLenum mTarget
= 0; // !IsTexture until Bind
517 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTextureJS
)
518 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTextureJS
)
520 explicit WebGLTextureJS(const ClientWebGLContext
& webgl
)
521 : webgl::ObjectJS(webgl
) {}
527 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
532 class WebGLTransformFeedbackJS final
: public nsWrapperCache
,
533 public webgl::ObjectJS
{
534 friend class ClientWebGLContext
;
536 bool mHasBeenBound
= false; // !IsTransformFeedback until Bind
537 bool mActiveOrPaused
= false;
538 std::vector
<RefPtr
<WebGLBufferJS
>> mAttribBuffers
;
539 RefPtr
<WebGLProgramJS
> mActiveProgram
;
540 std::shared_ptr
<webgl::ProgramKeepAlive
> mActiveProgramKeepAlive
;
543 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedbackJS
)
544 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTransformFeedbackJS
)
546 explicit WebGLTransformFeedbackJS(const ClientWebGLContext
&);
549 ~WebGLTransformFeedbackJS();
552 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
557 std::array
<uint16_t, 3> ValidUploadElemTypes(GLenum
);
559 class WebGLUniformLocationJS final
: public nsWrapperCache
,
560 public webgl::ObjectJS
{
561 friend class ClientWebGLContext
;
563 const std::weak_ptr
<webgl::LinkResult
> mParent
;
564 const uint32_t mLocation
;
565 const std::array
<uint16_t, 3> mValidUploadElemTypes
;
568 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocationJS
)
569 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLUniformLocationJS
)
571 WebGLUniformLocationJS(const ClientWebGLContext
& webgl
,
572 std::weak_ptr
<webgl::LinkResult
> parent
, uint32_t loc
,
574 : webgl::ObjectJS(webgl
),
577 mValidUploadElemTypes(ValidUploadElemTypes(elemType
)) {}
580 ~WebGLUniformLocationJS() = default;
583 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
588 class WebGLVertexArrayJS final
: public nsWrapperCache
, public webgl::ObjectJS
{
589 friend class ClientWebGLContext
;
591 bool mHasBeenBound
= false; // !IsVertexArray until Bind
592 RefPtr
<WebGLBufferJS
> mIndexBuffer
;
593 std::vector
<RefPtr
<WebGLBufferJS
>> mAttribBuffers
;
596 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArrayJS
)
597 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLVertexArrayJS
)
599 explicit WebGLVertexArrayJS(const ClientWebGLContext
&);
602 ~WebGLVertexArrayJS();
605 JSObject
* WrapObject(JSContext
*, JS::Handle
<JSObject
*>) override
;
608 ////////////////////////////////////
610 using Float32ListU
= dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence
;
611 using Int32ListU
= dom::MaybeSharedInt32ArrayOrLongSequence
;
612 using Uint32ListU
= dom::MaybeSharedUint32ArrayOrUnsignedLongSequence
;
614 template <typename Converter
, typename T
>
615 inline bool ConvertSequence(const dom::Sequence
<T
>& sequence
,
616 Converter
&& converter
) {
617 // It's ok to GC here, but we need a common parameter list for
618 // Converter with the typed array version.
619 JS::AutoCheckCannotGC nogc
;
621 return std::forward
<Converter
>(converter
)(Span(sequence
), std::move(nogc
));
624 template <typename Converter
>
625 inline bool Convert(const Float32ListU
& list
, Converter
&& converter
) {
626 if (list
.IsFloat32Array()) {
627 return list
.GetAsFloat32Array().ProcessData(
628 std::forward
<Converter
>(converter
));
631 return ConvertSequence(list
.GetAsUnrestrictedFloatSequence(),
632 std::forward
<Converter
>(converter
));
635 template <typename Converter
>
636 inline bool Convert(const Int32ListU
& list
, Converter
&& converter
) {
637 if (list
.IsInt32Array()) {
638 return list
.GetAsInt32Array().ProcessData(
639 std::forward
<Converter
>(converter
));
642 return ConvertSequence(list
.GetAsLongSequence(),
643 std::forward
<Converter
>(converter
));
646 template <typename Converter
>
647 inline bool Convert(const Uint32ListU
& list
, Converter
&& converter
) {
648 if (list
.IsUint32Array()) {
649 return list
.GetAsUint32Array().ProcessData(
650 std::forward
<Converter
>(converter
));
653 return ConvertSequence(list
.GetAsUnsignedLongSequence(),
654 std::forward
<Converter
>(converter
));
657 template <typename T
>
658 inline Range
<const uint8_t> MakeByteRange(const T
& x
) {
659 const auto typed
= MakeRange(x
);
660 return Range
<const uint8_t>(
661 reinterpret_cast<const uint8_t*>(typed
.begin().get()),
662 typed
.length() * sizeof(typed
[0]));
665 template <typename T
>
666 inline Range
<const uint8_t> MakeByteRange(const Span
<T
>& x
) {
672 struct TexImageSourceAdapter final
: public TexImageSource
{
673 TexImageSourceAdapter(const dom::Nullable
<dom::ArrayBufferView
>* maybeView
,
675 if (!maybeView
->IsNull()) {
676 mView
= &(maybeView
->Value());
680 TexImageSourceAdapter(const dom::Nullable
<dom::ArrayBufferView
>* maybeView
,
681 GLuint viewElemOffset
) {
682 if (!maybeView
->IsNull()) {
683 mView
= &(maybeView
->Value());
685 mViewElemOffset
= viewElemOffset
;
688 TexImageSourceAdapter(const dom::ArrayBufferView
* view
, ErrorResult
*) {
692 TexImageSourceAdapter(const dom::ArrayBufferView
* view
, GLuint viewElemOffset
,
693 GLuint viewElemLengthOverride
= 0) {
695 mViewElemOffset
= viewElemOffset
;
696 mViewElemLengthOverride
= viewElemLengthOverride
;
699 explicit TexImageSourceAdapter(const WebGLintptr
* pboOffset
,
700 GLuint ignored1
= 0, GLuint ignored2
= 0) {
701 mPboOffset
= pboOffset
;
704 TexImageSourceAdapter(const WebGLintptr
* pboOffset
, ErrorResult
* ignored
) {
705 mPboOffset
= pboOffset
;
708 TexImageSourceAdapter(const dom::ImageBitmap
* imageBitmap
,
709 ErrorResult
* out_error
) {
710 mImageBitmap
= imageBitmap
;
711 mOut_error
= out_error
;
714 TexImageSourceAdapter(const dom::ImageData
* imageData
, ErrorResult
*) {
715 mImageData
= imageData
;
718 TexImageSourceAdapter(const dom::OffscreenCanvas
* offscreenCanvas
,
719 ErrorResult
* const out_error
) {
720 mOffscreenCanvas
= offscreenCanvas
;
721 mOut_error
= out_error
;
724 TexImageSourceAdapter(const dom::VideoFrame
* videoFrame
,
725 ErrorResult
* const out_error
) {
726 mVideoFrame
= videoFrame
;
727 mOut_error
= out_error
;
730 TexImageSourceAdapter(const dom::Element
* domElem
,
731 ErrorResult
* const out_error
) {
733 mOut_error
= out_error
;
738 * Base class for all IDL implementations of WebGLContext
740 class ClientWebGLContext final
: public nsICanvasRenderingContextInternal
,
741 public nsWrapperCache
{
742 friend class webgl::AvailabilityRunnable
;
743 friend class webgl::ObjectJS
;
744 friend class webgl::ProgramKeepAlive
;
745 friend class webgl::ShaderKeepAlive
;
747 // ----------------------------- Lifetime and DOM ---------------------------
749 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
750 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ClientWebGLContext
)
752 JSObject
* WrapObject(JSContext
* cx
,
753 JS::Handle
<JSObject
*> givenProto
) override
{
755 return dom::WebGL2RenderingContext_Binding::Wrap(cx
, this, givenProto
);
757 return dom::WebGLRenderingContext_Binding::Wrap(cx
, this, givenProto
);
763 const bool mIsWebGL2
;
766 bool mIsCanvasDirty
= false;
767 uvec2 mRequestedSize
= {};
770 explicit ClientWebGLContext(bool webgl2
);
773 virtual ~ClientWebGLContext();
775 const RefPtr
<ClientWebGLExtensionLoseContext
> mExtLoseContext
;
777 mutable std::shared_ptr
<webgl::NotLostData
> mNotLost
;
778 mutable GLenum mNextError
= 0;
779 mutable webgl::LossStatus mLossStatus
= webgl::LossStatus::Ready
;
780 mutable bool mAwaitingRestore
= false;
781 mutable webgl::ObjectId mLastId
= 0;
784 webgl::ObjectId
NextId() const { return mLastId
+= 1; }
786 // Holds Some Id if async present is used
787 mutable Maybe
<layers::RemoteTextureId
> mLastRemoteTextureId
;
788 mutable Maybe
<layers::RemoteTextureOwnerId
> mRemoteTextureOwnerId
;
789 mutable RefPtr
<layers::FwdTransactionTracker
> mFwdTransactionTracker
;
794 const auto& Limits() const { return mNotLost
->info
.limits
; }
795 const auto& Vendor() const { return mNotLost
->info
.vendor
; }
796 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters
797 const WebGLContextOptions
& ActualContextParameters() const {
798 MOZ_ASSERT(mNotLost
!= nullptr);
799 return mNotLost
->info
.options
;
802 auto& State() { return mNotLost
->state
; }
803 const auto& State() const {
804 return const_cast<ClientWebGLContext
*>(this)->State();
810 mutable RefPtr
<webgl::AvailabilityRunnable
> mAvailabilityRunnable
;
813 webgl::AvailabilityRunnable
& EnsureAvailabilityRunnable() const;
818 void EmulateLoseContext() const;
819 void OnContextLoss(webgl::ContextLossReason
) const;
820 void RestoreContext(webgl::LossStatus requiredStatus
) const;
823 bool DispatchEvent(const nsAString
&) const;
824 void Event_webglcontextlost() const;
825 void Event_webglcontextrestored() const;
827 bool CreateHostContext(const uvec2
& requestedSize
);
828 void ThrowEvent_WebGLContextCreationError(const std::string
&) const;
830 void UpdateCanvasParameters();
833 void MarkCanvasDirty();
835 void MarkContextClean() override
{}
837 void OnBeforePaintTransaction() override
;
839 mozilla::dom::WebGLChild
* GetChild() const {
840 if (!mNotLost
) return nullptr;
841 if (!mNotLost
->outOfProcess
) return nullptr;
842 return mNotLost
->outOfProcess
.get();
845 // -------------------------------------------------------------------------
846 // Client WebGL API call tracking and error message reporting
847 // -------------------------------------------------------------------------
849 // Remembers the WebGL function that is lowest on the stack for client-side
851 class FuncScope final
{
853 const ClientWebGLContext
& mWebGL
;
854 const std::shared_ptr
<webgl::NotLostData
> mKeepNotLostOrNull
;
855 const char* const mFuncName
;
857 FuncScope(const ClientWebGLContext
& webgl
, const char* funcName
)
859 mKeepNotLostOrNull(webgl
.mNotLost
),
860 mFuncName(funcName
) {
861 // Only set if an "outer" scope hasn't already been set.
862 if (!mWebGL
.mFuncScope
) {
863 mWebGL
.mFuncScope
= this;
868 if (this == mWebGL
.mFuncScope
) {
869 mWebGL
.mFuncScope
= nullptr;
873 FuncScope(const FuncScope
&) = delete;
874 FuncScope(FuncScope
&&) = delete;
878 // The scope of the function at the top of the current WebGL function call
880 mutable FuncScope
* mFuncScope
= nullptr;
882 const char* FuncName() const {
883 return mFuncScope
? mFuncScope
->mFuncName
: nullptr;
887 template <typename
... Args
>
888 void EnqueueError(const GLenum error
, const char* const format
,
889 const Args
&... args
) const {
890 MOZ_ASSERT(FuncName());
892 text
.AppendPrintf("WebGL warning: %s: ", FuncName());
895 # pragma clang diagnostic push
896 # pragma clang diagnostic ignored "-Wformat-security"
897 #elif defined(__GNUC__)
898 # pragma GCC diagnostic push
899 # pragma GCC diagnostic ignored "-Wformat-security"
901 text
.AppendPrintf(format
, args
...);
903 # pragma clang diagnostic pop
904 #elif defined(__GNUC__)
905 # pragma GCC diagnostic pop
908 EnqueueErrorImpl(error
, text
);
911 void EnqueueError(const webgl::ErrorInfo
& info
) const {
912 EnqueueError(info
.type
, "%s", info
.info
.c_str());
915 template <typename
... Args
>
916 void EnqueueWarning(const char* const format
, const Args
&... args
) const {
917 EnqueueError(0, format
, args
...);
920 template <typename
... Args
>
921 void EnqueuePerfWarning(const char* const format
, const Args
&... args
) const {
922 EnqueueError(webgl::kErrorPerfWarning
, format
, args
...);
925 void EnqueueError_ArgEnum(const char* argName
,
926 GLenum val
) const; // Cold code.
929 void EnqueueErrorImpl(GLenum errorOrZero
, const nsACString
&) const;
932 Maybe
<Span
<uint8_t>> ValidateArrayBufferView(const Span
<uint8_t>& bytes
,
935 GLuint elemCountOverride
,
936 const GLenum errorEnum
) const;
939 template <typename T
>
940 bool ValidateNonNull(const char* const argName
,
941 const dom::Nullable
<T
>& maybe
) const {
942 if (maybe
.IsNull()) {
943 EnqueueError(LOCAL_GL_INVALID_VALUE
, "%s: Cannot be null.", argName
);
949 bool ValidateNonNegative(const char* argName
, int64_t val
) const {
950 if (MOZ_UNLIKELY(val
< 0)) {
951 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`%s` must be non-negative.",
958 bool ValidateViewType(GLenum unpackType
, const TexImageSource
& src
) const;
960 Maybe
<uvec3
> ValidateExtents(GLsizei width
, GLsizei height
, GLsizei depth
,
963 // -------------------------------------------------------------------------
964 // nsICanvasRenderingContextInternal / nsAPostRefreshObserver
965 // -------------------------------------------------------------------------
967 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
968 layers::CanvasRenderer
* aRenderer
) override
;
970 void MarkContextCleanForFrameCapture() override
{
971 mFrameCaptureState
= FrameCaptureState::CLEAN
;
973 // Note that 'clean' here refers to its invalidation state, not the
974 // contents of the buffer.
975 Watchable
<FrameCaptureState
>* GetFrameCaptureState() override
{
976 return &mFrameCaptureState
;
979 void OnMemoryPressure() override
;
980 void SetContextOptions(const WebGLContextOptions
& aOptions
) {
981 mInitialOptions
.emplace(aOptions
);
983 const WebGLContextOptions
& GetContextOptions() const {
984 return mInitialOptions
.ref();
987 SetContextOptions(JSContext
* cx
, JS::Handle
<JS::Value
> options
,
988 ErrorResult
& aRvForDictionaryInit
) override
;
990 SetDimensions(int32_t width
, int32_t height
) override
;
991 bool UpdateWebRenderCanvasData(
992 nsDisplayListBuilder
* aBuilder
,
993 layers::WebRenderCanvasData
* aCanvasData
) override
;
997 int32_t GetWidth() override
{ return AutoAssertCast(DrawingBufferSize().x
); }
998 int32_t GetHeight() override
{ return AutoAssertCast(DrawingBufferSize().y
); }
1000 NS_IMETHOD
InitializeWithDrawTarget(nsIDocShell
*,
1001 NotNull
<gfx::DrawTarget
*>) override
{
1002 return NS_ERROR_NOT_IMPLEMENTED
;
1005 void ResetBitmap() override
;
1007 UniquePtr
<uint8_t[]> GetImageBuffer(int32_t* out_format
,
1008 gfx::IntSize
* out_imageSize
) override
;
1009 NS_IMETHOD
GetInputStream(const char* mimeType
,
1010 const nsAString
& encoderOptions
,
1011 nsIInputStream
** out_stream
) override
;
1013 already_AddRefed
<mozilla::gfx::SourceSurface
> GetSurfaceSnapshot(
1014 gfxAlphaType
* out_alphaType
) override
;
1016 void SetOpaqueValueFromOpaqueAttr(bool) override
{};
1017 bool GetIsOpaque() override
{ return !mInitialOptions
->alpha
; }
1020 * An abstract base class to be implemented by callers wanting to be notified
1021 * that a refresh has occurred. Callers must ensure an observer is removed
1022 * before it is destroyed.
1024 void DidRefresh() override
;
1026 NS_IMETHOD
Redraw(const gfxRect
&) override
{
1027 return NS_ERROR_NOT_IMPLEMENTED
;
1033 layers::LayersBackend
GetCompositorBackendType() const;
1035 Watchable
<FrameCaptureState
> mFrameCaptureState
= {
1036 FrameCaptureState::CLEAN
, "ClientWebGLContext::mFrameCaptureState"};
1038 // -------------------------------------------------------------------------
1039 // WebGLRenderingContext Basic Properties and Methods
1040 // -------------------------------------------------------------------------
1042 dom::HTMLCanvasElement
* GetCanvas() const { return mCanvasElement
; }
1045 dom::Nullable
<dom::OwningHTMLCanvasElementOrOffscreenCanvas
>& retval
);
1047 GLsizei
DrawingBufferWidth() {
1048 const FuncScope
funcScope(*this, "drawingBufferWidth");
1049 return AutoAssertCast(DrawingBufferSize().x
);
1051 GLsizei
DrawingBufferHeight() {
1052 const FuncScope
funcScope(*this, "drawingBufferHeight");
1053 return AutoAssertCast(DrawingBufferSize().y
);
1055 void GetContextAttributes(dom::Nullable
<dom::WebGLContextAttributes
>& retval
);
1058 webgl::SwapChainOptions
PrepareAsyncSwapChainOptions(
1059 WebGLFramebufferJS
* fb
, bool webvr
,
1060 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1063 layers::TextureType
GetTexTypeForSwapChain() const;
1065 WebGLFramebufferJS
*, const bool webvr
= false,
1066 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1068 WebGLFramebufferJS
*, layers::TextureType
, const bool webvr
= false,
1069 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1070 void CopyToSwapChain(
1071 WebGLFramebufferJS
*,
1072 const webgl::SwapChainOptions
& options
= webgl::SwapChainOptions());
1074 Maybe
<layers::SurfaceDescriptor
> GetFrontBuffer(
1075 WebGLFramebufferJS
*, const bool webvr
= false) override
;
1076 Maybe
<layers::SurfaceDescriptor
> PresentFrontBuffer(
1077 WebGLFramebufferJS
*, layers::TextureType
,
1078 const bool webvr
= false) override
;
1079 RefPtr
<gfx::SourceSurface
> GetFrontBufferSnapshot(
1080 bool requireAlphaPremult
= true) override
;
1081 already_AddRefed
<layers::FwdTransactionTracker
> UseCompositableForwarder(
1082 layers::CompositableForwarder
* aForwarder
) override
;
1083 void OnDestroyChild(dom::WebGLChild
* aChild
);
1085 void ClearVRSwapChain();
1088 RefPtr
<gfx::DataSourceSurface
> BackBufferSnapshot();
1089 [[nodiscard
]] bool DoReadPixels(const webgl::ReadPixelsDesc
&,
1090 Span
<uint8_t>) const;
1091 uvec2
DrawingBufferSize();
1095 mutable bool mAutoFlushPending
= false;
1097 void AutoEnqueueFlush() const {
1098 if (MOZ_LIKELY(mAutoFlushPending
)) return;
1099 mAutoFlushPending
= true;
1101 const auto DeferredFlush
= [weak
=
1102 WeakPtr
<const ClientWebGLContext
>(this)]() {
1103 const auto strong
= RefPtr
<const ClientWebGLContext
>(weak
);
1104 if (!strong
) return;
1105 if (!strong
->mAutoFlushPending
) return;
1106 strong
->mAutoFlushPending
= false;
1108 if (!StaticPrefs::webgl_auto_flush()) return;
1109 const bool flushGl
= StaticPrefs::webgl_auto_flush_gl();
1110 strong
->Flush(flushGl
);
1113 already_AddRefed
<mozilla::CancelableRunnable
> runnable
=
1114 NS_NewCancelableRunnableFunction("ClientWebGLContext::DeferredFlush",
1116 NS_DispatchToCurrentThread(std::move(runnable
));
1119 void CancelAutoFlush() const { mAutoFlushPending
= false; }
1123 void AfterDrawCall() {
1124 if (!mNotLost
) return;
1125 const auto& state
= State();
1126 if (!state
.mBoundDrawFb
) {
1133 // -------------------------------------------------------------------------
1134 // Client-side helper methods. Dispatch to a Host method.
1135 // -------------------------------------------------------------------------
1137 // ------------------------- GL State -------------------------
1139 bool IsContextLost() const { return !mNotLost
; }
1141 void Disable(GLenum cap
) const { SetEnabledI(cap
, {}, false); }
1142 void Enable(GLenum cap
) const { SetEnabledI(cap
, {}, true); }
1143 void SetEnabledI(GLenum cap
, Maybe
<GLuint
> i
, bool val
) const;
1145 bool IsEnabled(GLenum cap
) const;
1148 Maybe
<double> GetNumber(GLenum pname
);
1149 Maybe
<std::string
> GetString(GLenum pname
);
1152 void GetParameter(JSContext
* cx
, GLenum pname
,
1153 JS::MutableHandle
<JS::Value
> retval
, ErrorResult
& rv
,
1154 bool debug
= false);
1156 void GetBufferParameter(JSContext
* cx
, GLenum target
, GLenum pname
,
1157 JS::MutableHandle
<JS::Value
> retval
) const;
1159 void GetFramebufferAttachmentParameter(JSContext
* cx
, GLenum target
,
1160 GLenum attachment
, GLenum pname
,
1161 JS::MutableHandle
<JS::Value
> retval
,
1162 ErrorResult
& rv
) const;
1164 void GetRenderbufferParameter(JSContext
* cx
, GLenum target
, GLenum pname
,
1165 JS::MutableHandle
<JS::Value
> retval
) const;
1167 void GetIndexedParameter(JSContext
* cx
, GLenum target
, GLuint index
,
1168 JS::MutableHandle
<JS::Value
> retval
,
1169 ErrorResult
& rv
) const;
1171 already_AddRefed
<WebGLShaderPrecisionFormatJS
> GetShaderPrecisionFormat(
1172 GLenum shadertype
, GLenum precisiontype
);
1174 void UseProgram(WebGLProgramJS
*);
1175 void ValidateProgram(WebGLProgramJS
&) const;
1179 already_AddRefed
<WebGLBufferJS
> CreateBuffer() const;
1180 already_AddRefed
<WebGLFramebufferJS
> CreateFramebuffer() const;
1181 already_AddRefed
<WebGLFramebufferJS
> CreateOpaqueFramebuffer(
1182 const webgl::OpaqueFramebufferOptions
&) const;
1183 already_AddRefed
<WebGLProgramJS
> CreateProgram() const;
1184 already_AddRefed
<WebGLQueryJS
> CreateQuery() const;
1185 already_AddRefed
<WebGLRenderbufferJS
> CreateRenderbuffer() const;
1186 already_AddRefed
<WebGLSamplerJS
> CreateSampler() const;
1187 already_AddRefed
<WebGLShaderJS
> CreateShader(GLenum type
) const;
1188 already_AddRefed
<WebGLSyncJS
> FenceSync(GLenum condition
,
1189 GLbitfield flags
) const;
1190 already_AddRefed
<WebGLTextureJS
> CreateTexture() const;
1191 already_AddRefed
<WebGLTransformFeedbackJS
> CreateTransformFeedback() const;
1192 already_AddRefed
<WebGLVertexArrayJS
> CreateVertexArray() const;
1194 void DeleteBuffer(WebGLBufferJS
*);
1195 void DeleteFramebuffer(WebGLFramebufferJS
*, bool canDeleteOpaque
= false);
1196 void DeleteProgram(WebGLProgramJS
*) const;
1197 void DeleteQuery(WebGLQueryJS
*);
1198 void DeleteRenderbuffer(WebGLRenderbufferJS
*);
1199 void DeleteSampler(WebGLSamplerJS
*);
1200 void DeleteShader(WebGLShaderJS
*) const;
1201 void DeleteSync(WebGLSyncJS
*) const;
1202 void DeleteTexture(WebGLTextureJS
*);
1203 void DeleteTransformFeedback(WebGLTransformFeedbackJS
*);
1204 void DeleteVertexArray(WebGLVertexArrayJS
*);
1207 void DoDeleteProgram(WebGLProgramJS
&) const;
1208 void DoDeleteShader(const WebGLShaderJS
&) const;
1213 bool IsBuffer(const WebGLBufferJS
*) const;
1214 bool IsFramebuffer(const WebGLFramebufferJS
*) const;
1215 bool IsProgram(const WebGLProgramJS
*) const;
1216 bool IsQuery(const WebGLQueryJS
*) const;
1217 bool IsRenderbuffer(const WebGLRenderbufferJS
*) const;
1218 bool IsSampler(const WebGLSamplerJS
*) const;
1219 bool IsShader(const WebGLShaderJS
*) const;
1220 bool IsSync(const WebGLSyncJS
*) const;
1221 bool IsTexture(const WebGLTextureJS
*) const;
1222 bool IsTransformFeedback(const WebGLTransformFeedbackJS
*) const;
1223 bool IsVertexArray(const WebGLVertexArrayJS
*) const;
1229 const webgl::LinkResult
& GetLinkResult(const WebGLProgramJS
&) const;
1232 void AttachShader(WebGLProgramJS
&, WebGLShaderJS
&) const;
1233 void BindAttribLocation(WebGLProgramJS
&, GLuint location
,
1234 const nsAString
& name
) const;
1235 void DetachShader(WebGLProgramJS
&, const WebGLShaderJS
&) const;
1236 void GetAttachedShaders(
1237 const WebGLProgramJS
&,
1238 dom::Nullable
<nsTArray
<RefPtr
<WebGLShaderJS
>>>& retval
) const;
1239 void LinkProgram(WebGLProgramJS
&) const;
1240 void TransformFeedbackVaryings(WebGLProgramJS
&,
1241 const dom::Sequence
<nsString
>& varyings
,
1242 GLenum bufferMode
) const;
1243 void UniformBlockBinding(WebGLProgramJS
&, GLuint blockIndex
,
1244 GLuint blockBinding
) const;
1246 // Link result reflection
1247 already_AddRefed
<WebGLActiveInfoJS
> GetActiveAttrib(const WebGLProgramJS
&,
1249 already_AddRefed
<WebGLActiveInfoJS
> GetActiveUniform(const WebGLProgramJS
&,
1251 void GetActiveUniformBlockName(const WebGLProgramJS
&,
1252 GLuint uniformBlockIndex
,
1253 nsAString
& retval
) const;
1254 void GetActiveUniformBlockParameter(JSContext
* cx
, const WebGLProgramJS
&,
1255 GLuint uniformBlockIndex
, GLenum pname
,
1256 JS::MutableHandle
<JS::Value
> retval
,
1258 void GetActiveUniforms(JSContext
*, const WebGLProgramJS
&,
1259 const dom::Sequence
<GLuint
>& uniformIndices
,
1261 JS::MutableHandle
<JS::Value
> retval
) const;
1262 GLint
GetAttribLocation(const WebGLProgramJS
&, const nsAString
& name
) const;
1263 GLint
GetFragDataLocation(const WebGLProgramJS
&, const nsAString
& name
) const;
1264 void GetProgramInfoLog(const WebGLProgramJS
& prog
, nsAString
& retval
) const;
1265 void GetProgramParameter(JSContext
*, const WebGLProgramJS
&, GLenum pname
,
1266 JS::MutableHandle
<JS::Value
> retval
) const;
1267 already_AddRefed
<WebGLActiveInfoJS
> GetTransformFeedbackVarying(
1268 const WebGLProgramJS
&, GLuint index
);
1269 GLuint
GetUniformBlockIndex(const WebGLProgramJS
&,
1270 const nsAString
& uniformBlockName
) const;
1271 void GetUniformIndices(const WebGLProgramJS
&,
1272 const dom::Sequence
<nsString
>& uniformNames
,
1273 dom::Nullable
<nsTArray
<GLuint
>>& retval
) const;
1275 // WebGLUniformLocationJS
1276 already_AddRefed
<WebGLUniformLocationJS
> GetUniformLocation(
1277 const WebGLProgramJS
&, const nsAString
& name
) const;
1278 void GetUniform(JSContext
*, const WebGLProgramJS
&,
1279 const WebGLUniformLocationJS
&,
1280 JS::MutableHandle
<JS::Value
> retval
);
1286 const webgl::CompileResult
& GetCompileResult(const WebGLShaderJS
&) const;
1289 void CompileShader(WebGLShaderJS
&) const;
1290 void GetShaderInfoLog(const WebGLShaderJS
&, nsAString
& retval
) const;
1291 void GetShaderParameter(JSContext
*, const WebGLShaderJS
&, GLenum pname
,
1292 JS::MutableHandle
<JS::Value
> retval
) const;
1293 void GetShaderSource(const WebGLShaderJS
&, nsAString
& retval
) const;
1294 void GetTranslatedShaderSource(const WebGLShaderJS
& shader
,
1295 nsAString
& retval
) const;
1296 void ShaderSource(WebGLShaderJS
&, const nsAString
&) const;
1300 void BindFramebuffer(GLenum target
, WebGLFramebufferJS
*);
1302 void BlendColor(GLclampf r
, GLclampf g
, GLclampf b
, GLclampf a
);
1306 void BlendEquation(GLenum mode
) { BlendEquationSeparate(mode
, mode
); }
1307 void BlendFunc(GLenum sfactor
, GLenum dfactor
) {
1308 BlendFuncSeparate(sfactor
, dfactor
, sfactor
, dfactor
);
1311 void BlendEquationSeparate(GLenum modeRGB
, GLenum modeAlpha
) {
1312 BlendEquationSeparateI({}, modeRGB
, modeAlpha
);
1314 void BlendFuncSeparate(GLenum srcRGB
, GLenum dstRGB
, GLenum srcAlpha
,
1316 BlendFuncSeparateI({}, srcRGB
, dstRGB
, srcAlpha
, dstAlpha
);
1319 void BlendEquationSeparateI(Maybe
<GLuint
> buf
, GLenum modeRGB
,
1321 void BlendFuncSeparateI(Maybe
<GLuint
> buf
, GLenum srcRGB
, GLenum dstRGB
,
1322 GLenum srcAlpha
, GLenum dstAlpha
);
1326 GLenum
CheckFramebufferStatus(GLenum target
);
1328 void Clear(GLbitfield mask
);
1333 void ClearBufferTv(const GLenum buffer
, const GLint drawBuffer
,
1334 const webgl::AttribBaseType type
,
1335 JS::AutoCheckCannotGC
&& nogc
,
1336 const Span
<const uint8_t>& view
,
1337 const GLuint srcElemOffset
);
1340 void ClearBufferfv(GLenum buffer
, GLint drawBuffer
, const Float32ListU
& list
,
1341 GLuint srcElemOffset
) {
1342 const FuncScope
funcScope(*this, "clearBufferfv");
1343 if (!Convert(list
, [&](const Span
<const float>& aData
,
1344 JS::AutoCheckCannotGC
&& nogc
) {
1345 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Float
,
1346 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1349 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1352 void ClearBufferiv(GLenum buffer
, GLint drawBuffer
, const Int32ListU
& list
,
1353 GLuint srcElemOffset
) {
1354 const FuncScope
funcScope(*this, "clearBufferiv");
1355 if (!Convert(list
, [&](const Span
<const int32_t>& aData
,
1356 JS::AutoCheckCannotGC
&& nogc
) {
1357 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Int
,
1358 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1361 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1364 void ClearBufferuiv(GLenum buffer
, GLint drawBuffer
, const Uint32ListU
& list
,
1365 GLuint srcElemOffset
) {
1366 const FuncScope
funcScope(*this, "clearBufferuiv");
1367 if (!Convert(list
, [&](const Span
<const uint32_t>& aData
,
1368 JS::AutoCheckCannotGC
&& nogc
) {
1369 ClearBufferTv(buffer
, drawBuffer
, webgl::AttribBaseType::Uint
,
1370 std::move(nogc
), AsBytes(aData
), srcElemOffset
);
1373 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`values` too small.");
1379 void ClearBufferfi(GLenum buffer
, GLint drawBuffer
, GLfloat depth
,
1382 void ClearColor(GLclampf r
, GLclampf g
, GLclampf b
, GLclampf a
);
1384 void ClearDepth(GLclampf v
);
1386 void ClearStencil(GLint v
);
1388 void ColorMask(bool r
, bool g
, bool b
, bool a
) const {
1389 ColorMaskI({}, r
, g
, b
, a
);
1391 void ColorMaskI(Maybe
<GLuint
> buf
, bool r
, bool g
, bool b
, bool a
) const;
1393 void CullFace(GLenum face
);
1395 void DepthFunc(GLenum func
);
1397 void DepthMask(WebGLboolean b
);
1399 void DepthRange(GLclampf zNear
, GLclampf zFar
);
1401 void Flush(bool flushGl
= true) const;
1405 void FrontFace(GLenum mode
);
1409 void Hint(GLenum target
, GLenum mode
);
1411 void LineWidth(GLfloat width
);
1413 void PixelStorei(GLenum pname
, GLint param
);
1415 void PolygonOffset(GLfloat factor
, GLfloat units
);
1417 void SampleCoverage(GLclampf value
, WebGLboolean invert
);
1419 void Scissor(GLint x
, GLint y
, GLsizei width
, GLsizei height
);
1423 void StencilFunc(GLenum func
, GLint ref
, GLuint mask
) {
1424 StencilFuncSeparate(LOCAL_GL_FRONT_AND_BACK
, func
, ref
, mask
);
1426 void StencilMask(GLuint mask
) {
1427 StencilMaskSeparate(LOCAL_GL_FRONT_AND_BACK
, mask
);
1429 void StencilOp(GLenum sfail
, GLenum dpfail
, GLenum dppass
) {
1430 StencilOpSeparate(LOCAL_GL_FRONT_AND_BACK
, sfail
, dpfail
, dppass
);
1433 void StencilFuncSeparate(GLenum face
, GLenum func
, GLint ref
, GLuint mask
);
1434 void StencilMaskSeparate(GLenum face
, GLuint mask
);
1435 void StencilOpSeparate(GLenum face
, GLenum sfail
, GLenum dpfail
,
1440 void Viewport(GLint x
, GLint y
, GLsizei width
, GLsizei height
);
1442 // ------------------------- Buffer Objects -------------------------
1444 void BindBuffer(GLenum target
, WebGLBufferJS
*);
1449 void BindBufferRangeImpl(const GLenum target
, const GLuint index
,
1450 WebGLBufferJS
* const buffer
, const uint64_t offset
,
1451 const uint64_t size
);
1454 void BindBufferBase(const GLenum target
, const GLuint index
,
1455 WebGLBufferJS
* const buffer
) {
1456 const FuncScope
funcScope(*this, "bindBufferBase");
1457 if (IsContextLost()) return;
1459 BindBufferRangeImpl(target
, index
, buffer
, 0, 0);
1462 void BindBufferRange(const GLenum target
, const GLuint index
,
1463 WebGLBufferJS
* const buffer
, const WebGLintptr offset
,
1464 const WebGLsizeiptr size
) {
1465 const FuncScope
funcScope(*this, "bindBufferRange");
1466 if (IsContextLost()) return;
1469 if (!ValidateNonNegative("offset", offset
)) return;
1472 EnqueueError(LOCAL_GL_INVALID_VALUE
,
1473 "`size` must be positive for non-null `buffer`.");
1478 BindBufferRangeImpl(target
, index
, buffer
, static_cast<uint64_t>(offset
),
1479 static_cast<uint64_t>(size
));
1484 void CopyBufferSubData(GLenum readTarget
, GLenum writeTarget
,
1485 GLintptr readOffset
, GLintptr writeOffset
,
1488 void BufferData(GLenum target
, WebGLsizeiptr size
, GLenum usage
);
1489 void BufferData(GLenum target
,
1490 const dom::Nullable
<dom::ArrayBuffer
>& maybeSrc
,
1492 void BufferData(GLenum target
, const dom::ArrayBufferView
& srcData
,
1493 GLenum usage
, GLuint srcElemOffset
= 0,
1494 GLuint srcElemCountOverride
= 0);
1496 void BufferSubData(GLenum target
, WebGLsizeiptr dstByteOffset
,
1497 const dom::ArrayBufferView
& src
, GLuint srcElemOffset
= 0,
1498 GLuint srcElemCountOverride
= 0);
1499 void BufferSubData(GLenum target
, WebGLsizeiptr dstByteOffset
,
1500 const dom::ArrayBuffer
& src
);
1502 void GetBufferSubData(GLenum target
, GLintptr srcByteOffset
,
1503 const dom::ArrayBufferView
& dstData
,
1504 GLuint dstElemOffset
, GLuint dstElemCountOverride
);
1506 // -------------------------- Framebuffer Objects --------------------------
1508 void BlitFramebuffer(GLint srcX0
, GLint srcY0
, GLint srcX1
, GLint srcY1
,
1509 GLint dstX0
, GLint dstY0
, GLint dstX1
, GLint dstY1
,
1510 GLbitfield mask
, GLenum filter
);
1515 // `bindTarget` if non-zero allows initializing the rb/tex with that target.
1516 void FramebufferAttach(GLenum target
, GLenum attachEnum
, GLenum bindTarget
,
1517 WebGLRenderbufferJS
*, WebGLTextureJS
*,
1518 uint32_t mipLevel
, uint32_t zLayer
,
1519 uint32_t numViewLayers
) const;
1522 void FramebufferRenderbuffer(GLenum target
, GLenum attachSlot
,
1523 GLenum rbTarget
, WebGLRenderbufferJS
* rb
) const {
1524 const FuncScope
funcScope(*this, "framebufferRenderbuffer");
1525 if (IsContextLost()) return;
1526 if (rbTarget
!= LOCAL_GL_RENDERBUFFER
) {
1527 EnqueueError_ArgEnum("rbTarget", rbTarget
);
1530 FramebufferAttach(target
, attachSlot
, rbTarget
, rb
, nullptr, 0, 0, 0);
1533 void FramebufferTexture2D(GLenum target
, GLenum attachSlot
,
1534 GLenum texImageTarget
, WebGLTextureJS
*,
1535 GLint mipLevel
) const;
1537 void FramebufferTextureLayer(GLenum target
, GLenum attachSlot
,
1538 WebGLTextureJS
* tex
, GLint mipLevel
,
1539 GLint zLayer
) const {
1540 const FuncScope
funcScope(*this, "framebufferTextureLayer");
1541 if (IsContextLost()) return;
1542 FramebufferAttach(target
, attachSlot
, 0, nullptr, tex
,
1543 static_cast<uint32_t>(mipLevel
),
1544 static_cast<uint32_t>(zLayer
), 0);
1547 void FramebufferTextureMultiview(GLenum target
, GLenum attachSlot
,
1548 WebGLTextureJS
* tex
, GLint mipLevel
,
1550 GLsizei numViewLayers
) const {
1551 const FuncScope
funcScope(*this, "framebufferTextureMultiview");
1552 if (IsContextLost()) return;
1553 if (tex
&& numViewLayers
< 1) {
1554 EnqueueError(LOCAL_GL_INVALID_VALUE
, "`numViewLayers` must be >=1.");
1557 FramebufferAttach(target
, attachSlot
, 0, nullptr, tex
,
1558 static_cast<uint32_t>(mipLevel
),
1559 static_cast<uint32_t>(zLayerBase
),
1560 static_cast<uint32_t>(numViewLayers
));
1565 void InvalidateFramebuffer(GLenum target
,
1566 const dom::Sequence
<GLenum
>& attachments
,
1567 ErrorResult
& unused
);
1568 void InvalidateSubFramebuffer(GLenum target
,
1569 const dom::Sequence
<GLenum
>& attachments
,
1570 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
1571 ErrorResult
& unused
);
1573 void ReadBuffer(GLenum mode
);
1575 // ----------------------- Renderbuffer objects -----------------------
1576 void GetInternalformatParameter(JSContext
* cx
, GLenum target
,
1577 GLenum internalformat
, GLenum pname
,
1578 JS::MutableHandle
<JS::Value
> retval
,
1581 void BindRenderbuffer(GLenum target
, WebGLRenderbufferJS
*);
1583 void RenderbufferStorage(GLenum target
, GLenum internalFormat
, GLsizei width
,
1584 GLsizei height
) const {
1585 RenderbufferStorageMultisample(target
, 0, internalFormat
, width
, height
);
1588 void RenderbufferStorageMultisample(GLenum target
, GLsizei samples
,
1589 GLenum internalFormat
, GLsizei width
,
1590 GLsizei height
) const;
1592 // --------------------------- Texture objects ---------------------------
1594 void ActiveTexture(GLenum texUnit
);
1596 void BindTexture(GLenum texTarget
, WebGLTextureJS
*);
1598 void GenerateMipmap(GLenum texTarget
) const;
1600 void GetTexParameter(JSContext
* cx
, GLenum texTarget
, GLenum pname
,
1601 JS::MutableHandle
<JS::Value
> retval
) const;
1603 void TexParameterf(GLenum texTarget
, GLenum pname
, GLfloat param
);
1604 void TexParameteri(GLenum texTarget
, GLenum pname
, GLint param
);
1609 void TexStorage(uint8_t funcDims
, GLenum target
, GLsizei levels
,
1610 GLenum internalFormat
, const ivec3
& size
) const;
1612 // Primitive tex upload functions
1613 void TexImage(uint8_t funcDims
, GLenum target
, GLint level
,
1614 GLenum respecFormat
, const ivec3
& offset
,
1615 const Maybe
<ivec3
>& size
, GLint border
,
1616 const webgl::PackingInfo
& pi
, const TexImageSource
& src
) const;
1617 void CompressedTexImage(bool sub
, uint8_t funcDims
, GLenum target
,
1618 GLint level
, GLenum format
, const ivec3
& offset
,
1619 const ivec3
& size
, GLint border
,
1620 const TexImageSource
& src
,
1621 GLsizei pboImageSize
) const;
1622 void CopyTexImage(uint8_t funcDims
, GLenum target
, GLint level
,
1623 GLenum respecFormat
, const ivec3
& dstOffset
,
1624 const ivec2
& srcOffset
, const ivec2
& size
,
1625 GLint border
) const;
1628 void TexStorage2D(GLenum target
, GLsizei levels
, GLenum internalFormat
,
1629 GLsizei width
, GLsizei height
) const {
1630 TexStorage(2, target
, levels
, internalFormat
, {width
, height
, 1});
1633 void TexStorage3D(GLenum target
, GLsizei levels
, GLenum internalFormat
,
1634 GLsizei width
, GLsizei height
, GLsizei depth
) const {
1635 TexStorage(3, target
, levels
, internalFormat
, {width
, height
, depth
});
1638 ////////////////////////////////////
1640 template <typename T
> // TexImageSource or WebGLintptr
1641 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1642 GLsizei width
, GLsizei height
, GLint border
,
1643 GLenum unpackFormat
, GLenum unpackType
, const T
& anySrc
,
1644 ErrorResult
& out_error
) const {
1645 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1646 TexImage(2, target
, level
, internalFormat
, {0, 0, 0},
1647 Some(ivec3
{width
, height
, 1}), border
, {unpackFormat
, unpackType
},
1651 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1652 GLsizei width
, GLsizei height
, GLint border
,
1653 GLenum unpackFormat
, GLenum unpackType
,
1654 const dom::ArrayBufferView
& view
, GLuint viewElemOffset
,
1655 ErrorResult
&) const {
1656 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1657 TexImage(2, target
, level
, internalFormat
, {0, 0, 0},
1658 Some(ivec3
{width
, height
, 1}), border
, {unpackFormat
, unpackType
},
1664 template <typename T
> // TexImageSource or WebGLintptr
1665 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1666 GLsizei width
, GLsizei height
, GLenum unpackFormat
,
1667 GLenum unpackType
, const T
& anySrc
,
1668 ErrorResult
& out_error
) const {
1669 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1670 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0},
1671 Some(ivec3
{width
, height
, 1}), 0, {unpackFormat
, unpackType
}, src
);
1674 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1675 GLsizei width
, GLsizei height
, GLenum unpackFormat
,
1676 GLenum unpackType
, const dom::ArrayBufferView
& view
,
1677 GLuint viewElemOffset
, ErrorResult
&) const {
1678 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1679 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0},
1680 Some(ivec3
{width
, height
, 1}), 0, {unpackFormat
, unpackType
}, src
);
1685 template <typename T
> // TexImageSource or WebGLintptr
1686 void TexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1687 GLsizei width
, GLsizei height
, GLsizei depth
, GLint border
,
1688 GLenum unpackFormat
, GLenum unpackType
, const T
& anySrc
,
1689 ErrorResult
& out_error
) const {
1690 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1691 TexImage(3, target
, level
, internalFormat
, {0, 0, 0},
1692 Some(ivec3
{width
, height
, depth
}), border
,
1693 {unpackFormat
, unpackType
}, src
);
1696 void TexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1697 GLsizei width
, GLsizei height
, GLsizei depth
, GLint border
,
1698 GLenum unpackFormat
, GLenum unpackType
,
1699 const dom::ArrayBufferView
& view
, GLuint viewElemOffset
,
1700 ErrorResult
&) const {
1701 const TexImageSourceAdapter
src(&view
, viewElemOffset
);
1702 TexImage(3, target
, level
, internalFormat
, {0, 0, 0},
1703 Some(ivec3
{width
, height
, depth
}), border
,
1704 {unpackFormat
, unpackType
}, src
);
1709 template <typename T
> // TexImageSource or WebGLintptr
1710 void TexSubImage3D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1711 GLint zOffset
, GLsizei width
, GLsizei height
,
1712 GLsizei depth
, GLenum unpackFormat
, GLenum unpackType
,
1713 const T
& anySrc
, ErrorResult
& out_error
) const {
1714 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1715 TexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
},
1716 Some(ivec3
{width
, height
, depth
}), 0, {unpackFormat
, unpackType
},
1720 void TexSubImage3D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1721 GLint zOffset
, GLsizei width
, GLsizei height
,
1722 GLsizei depth
, GLenum unpackFormat
, GLenum unpackType
,
1723 const dom::Nullable
<dom::ArrayBufferView
>& maybeSrcView
,
1724 GLuint srcElemOffset
, ErrorResult
&) const {
1725 const TexImageSourceAdapter
src(&maybeSrcView
, srcElemOffset
);
1726 TexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
},
1727 Some(ivec3
{width
, height
, depth
}), 0, {unpackFormat
, unpackType
},
1731 ////////////////////////////////////
1734 void CompressedTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1735 GLsizei width
, GLsizei height
, GLint border
,
1736 GLsizei imageSize
, WebGLintptr offset
) const {
1737 const TexImageSourceAdapter
src(&offset
);
1738 CompressedTexImage(false, 2, target
, level
, internalFormat
, {0, 0, 0},
1739 {width
, height
, 1}, border
, src
, imageSize
);
1742 void CompressedTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1743 GLsizei width
, GLsizei height
, GLint border
,
1744 const dom::ArrayBufferView
& view
,
1745 GLuint viewElemOffset
= 0,
1746 GLuint viewElemLengthOverride
= 0) const {
1747 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1748 viewElemLengthOverride
);
1749 CompressedTexImage(false, 2, target
, level
, internalFormat
, {0, 0, 0},
1750 {width
, height
, 1}, border
, src
, 0);
1755 void CompressedTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1756 GLint yOffset
, GLsizei width
, GLsizei height
,
1757 GLenum unpackFormat
, GLsizei imageSize
,
1758 WebGLintptr offset
) const {
1759 const TexImageSourceAdapter
src(&offset
);
1760 CompressedTexImage(true, 2, target
, level
, unpackFormat
,
1761 {xOffset
, yOffset
, 0}, {width
, height
, 1}, 0, src
,
1765 void CompressedTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1766 GLint yOffset
, GLsizei width
, GLsizei height
,
1767 GLenum unpackFormat
,
1768 const dom::ArrayBufferView
& view
,
1769 GLuint viewElemOffset
= 0,
1770 GLuint viewElemLengthOverride
= 0) const {
1771 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1772 viewElemLengthOverride
);
1773 CompressedTexImage(true, 2, target
, level
, unpackFormat
,
1774 {xOffset
, yOffset
, 0}, {width
, height
, 1}, 0, src
, 0);
1779 void CompressedTexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1780 GLsizei width
, GLsizei height
, GLsizei depth
,
1781 GLint border
, GLsizei imageSize
,
1782 WebGLintptr offset
) const {
1783 const TexImageSourceAdapter
src(&offset
);
1784 CompressedTexImage(false, 3, target
, level
, internalFormat
, {0, 0, 0},
1785 {width
, height
, depth
}, border
, src
, imageSize
);
1788 void CompressedTexImage3D(GLenum target
, GLint level
, GLenum internalFormat
,
1789 GLsizei width
, GLsizei height
, GLsizei depth
,
1790 GLint border
, const dom::ArrayBufferView
& view
,
1791 GLuint viewElemOffset
= 0,
1792 GLuint viewElemLengthOverride
= 0) const {
1793 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1794 viewElemLengthOverride
);
1795 CompressedTexImage(false, 3, target
, level
, internalFormat
, {0, 0, 0},
1796 {width
, height
, depth
}, border
, src
, 0);
1801 void CompressedTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1802 GLint yOffset
, GLint zOffset
, GLsizei width
,
1803 GLsizei height
, GLsizei depth
,
1804 GLenum unpackFormat
, GLsizei imageSize
,
1805 WebGLintptr offset
) const {
1806 const TexImageSourceAdapter
src(&offset
);
1807 CompressedTexImage(true, 3, target
, level
, unpackFormat
,
1808 {xOffset
, yOffset
, zOffset
}, {width
, height
, depth
}, 0,
1812 void CompressedTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1813 GLint yOffset
, GLint zOffset
, GLsizei width
,
1814 GLsizei height
, GLsizei depth
,
1815 GLenum unpackFormat
,
1816 const dom::ArrayBufferView
& view
,
1817 GLuint viewElemOffset
= 0,
1818 GLuint viewElemLengthOverride
= 0) const {
1819 const TexImageSourceAdapter
src(&view
, viewElemOffset
,
1820 viewElemLengthOverride
);
1821 CompressedTexImage(true, 3, target
, level
, unpackFormat
,
1822 {xOffset
, yOffset
, zOffset
}, {width
, height
, depth
}, 0,
1826 // --------------------
1828 void CopyTexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1829 GLint x
, GLint y
, GLsizei width
, GLsizei height
,
1830 GLint border
) const {
1831 CopyTexImage(2, target
, level
, internalFormat
, {0, 0, 0}, {x
, y
},
1832 {width
, height
}, border
);
1835 void CopyTexSubImage2D(GLenum target
, GLint level
, GLint xOffset
,
1836 GLint yOffset
, GLint x
, GLint y
, GLsizei width
,
1837 GLsizei height
) const {
1838 CopyTexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0}, {x
, y
},
1839 {width
, height
}, 0);
1842 void CopyTexSubImage3D(GLenum target
, GLint level
, GLint xOffset
,
1843 GLint yOffset
, GLint zOffset
, GLint x
, GLint y
,
1844 GLsizei width
, GLsizei height
) const {
1845 CopyTexImage(3, target
, level
, 0, {xOffset
, yOffset
, zOffset
}, {x
, y
},
1846 {width
, height
}, 0);
1849 // -------------------
1850 // legacy TexImageSource uploads without width/height.
1851 // The width/height params are webgl2 only, and let you do subrect
1852 // selection with e.g. width < UNPACK_ROW_LENGTH.
1854 template <typename TexImageSourceT
>
1855 void TexImage2D(GLenum target
, GLint level
, GLenum internalFormat
,
1856 GLenum unpackFormat
, GLenum unpackType
,
1857 const TexImageSourceT
& anySrc
, ErrorResult
& out_error
) const {
1858 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1859 TexImage(2, target
, level
, internalFormat
, {}, {}, 0,
1860 {unpackFormat
, unpackType
}, src
);
1863 template <typename TexImageSourceT
>
1864 void TexSubImage2D(GLenum target
, GLint level
, GLint xOffset
, GLint yOffset
,
1865 GLenum unpackFormat
, GLenum unpackType
,
1866 const TexImageSourceT
& anySrc
,
1867 ErrorResult
& out_error
) const {
1868 const TexImageSourceAdapter
src(&anySrc
, &out_error
);
1869 TexImage(2, target
, level
, 0, {xOffset
, yOffset
, 0}, {}, 0,
1870 {unpackFormat
, unpackType
}, src
);
1873 // ------------------------ Uniforms and attributes ------------------------
1876 Maybe
<double> GetVertexAttribPriv(GLuint index
, GLenum pname
);
1879 void GetVertexAttrib(JSContext
* cx
, GLuint index
, GLenum pname
,
1880 JS::MutableHandle
<JS::Value
> retval
, ErrorResult
& rv
);
1883 const webgl::LinkResult
* GetActiveLinkResult() const {
1884 const auto& state
= State();
1885 if (state
.mCurrentProgram
) {
1886 (void)GetLinkResult(*state
.mCurrentProgram
);
1888 return state
.mActiveLinkResult
.get();
1891 // Used by callers that have a `nogc` token that ensures that no GC will
1892 // happen while `bytes` is alive. Internally, the nogc range will be ended
1893 // after `bytes` is used (either successfully but where the data are possibly
1894 // sent over IPC which has a tendency to GC, or unsuccesfully in which case
1895 // error handling can GC.)
1896 void UniformData(GLenum funcElemType
, const WebGLUniformLocationJS
* const loc
,
1897 bool transpose
, const Range
<const uint8_t>& bytes
,
1898 JS::AutoCheckCannotGC
&& nogc
, GLuint elemOffset
= 0,
1899 GLuint elemCountOverride
= 0) const;
1901 // Used by callers that are not passing `bytes` that might be GC-controlled.
1902 // This will create an artificial and unnecessary nogc region that should
1903 // get optimized away to nothing.
1904 void UniformData(GLenum funcElemType
, const WebGLUniformLocationJS
* const loc
,
1905 bool transpose
, const Range
<const uint8_t>& bytes
,
1906 GLuint elemOffset
= 0, GLuint elemCountOverride
= 0) const {
1907 JS::AutoCheckCannotGC nogc
;
1908 UniformData(funcElemType
, loc
, transpose
, bytes
, std::move(nogc
),
1909 elemOffset
, elemCountOverride
);
1914 template <typename T
>
1915 Maybe
<Range
<T
>> ValidateSubrange(const Range
<T
>& data
, size_t elemOffset
,
1916 size_t elemLengthOverride
= 0) const {
1918 if (elemOffset
> ret
.length()) {
1919 EnqueueError(LOCAL_GL_INVALID_VALUE
,
1920 "`elemOffset` too large for `data`.");
1923 ret
= {ret
.begin() + elemOffset
, ret
.end()};
1924 if (elemLengthOverride
) {
1925 if (elemLengthOverride
> ret
.length()) {
1927 LOCAL_GL_INVALID_VALUE
,
1928 "`elemLengthOverride` too large for `data` and `elemOffset`.");
1931 ret
= {ret
.begin().get(), elemLengthOverride
};
1937 #define _(T, type_t, TYPE) \
1938 void Uniform1##T(const WebGLUniformLocationJS* const loc, type_t x) const { \
1939 const type_t arr[] = {x}; \
1940 UniformData(TYPE, loc, false, MakeByteRange(arr)); \
1942 void Uniform2##T(const WebGLUniformLocationJS* const loc, type_t x, \
1944 const type_t arr[] = {x, y}; \
1945 UniformData(TYPE##_VEC2, loc, false, MakeByteRange(arr)); \
1947 void Uniform3##T(const WebGLUniformLocationJS* const loc, type_t x, \
1948 type_t y, type_t z) const { \
1949 const type_t arr[] = {x, y, z}; \
1950 UniformData(TYPE##_VEC3, loc, false, MakeByteRange(arr)); \
1952 void Uniform4##T(const WebGLUniformLocationJS* const loc, type_t x, \
1953 type_t y, type_t z, type_t w) const { \
1954 const type_t arr[] = {x, y, z, w}; \
1955 UniformData(TYPE##_VEC4, loc, false, MakeByteRange(arr)); \
1958 _(f
, float, LOCAL_GL_FLOAT
)
1959 _(i
, int32_t, LOCAL_GL_INT
)
1960 _(ui
, uint32_t, LOCAL_GL_UNSIGNED_INT
)
1966 #define _(NT, TypeListU, TYPE) \
1967 void Uniform##NT##v(const WebGLUniformLocationJS* const loc, \
1968 const TypeListU& list, GLuint elemOffset = 0, \
1969 GLuint elemCountOverride = 0) const { \
1970 Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&& nogc) { \
1971 UniformData(TYPE, loc, false, MakeByteRange(aData), std::move(nogc), \
1972 elemOffset, elemCountOverride); \
1977 _(1f
, Float32ListU
, LOCAL_GL_FLOAT
)
1978 _(2f
, Float32ListU
, LOCAL_GL_FLOAT_VEC2
)
1979 _(3f
, Float32ListU
, LOCAL_GL_FLOAT_VEC3
)
1980 _(4f
, Float32ListU
, LOCAL_GL_FLOAT_VEC4
)
1981 _(1i
, Int32ListU
, LOCAL_GL_INT
)
1982 _(2i
, Int32ListU
, LOCAL_GL_INT_VEC2
)
1983 _(3i
, Int32ListU
, LOCAL_GL_INT_VEC3
)
1984 _(4i
, Int32ListU
, LOCAL_GL_INT_VEC4
)
1985 _(1ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT
)
1986 _(2ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC2
)
1987 _(3ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC3
)
1988 _(4ui
, Uint32ListU
, LOCAL_GL_UNSIGNED_INT_VEC4
)
1995 void UniformMatrix##X##fv(const WebGLUniformLocationJS* loc, bool transpose, \
1996 const Float32ListU& list, GLuint elemOffset = 0, \
1997 GLuint elemCountOverride = 0) const { \
1998 Convert(list, [&](const Span<const float>& aData, \
1999 JS::AutoCheckCannotGC&& nogc) { \
2000 UniformData(LOCAL_GL_FLOAT_MAT##X, loc, transpose, MakeByteRange(aData), \
2001 std::move(nogc), elemOffset, elemCountOverride); \
2022 void EnableVertexAttribArray(GLuint index
);
2024 void DisableVertexAttribArray(GLuint index
);
2026 WebGLsizeiptr
GetVertexAttribOffset(GLuint index
, GLenum pname
);
2031 void VertexAttrib4Tv(GLuint index
, webgl::AttribBaseType
,
2032 const Range
<const uint8_t>&);
2035 void VertexAttrib1f(GLuint index
, GLfloat x
) {
2036 VertexAttrib4f(index
, x
, 0, 0, 1);
2038 void VertexAttrib2f(GLuint index
, GLfloat x
, GLfloat y
) {
2039 VertexAttrib4f(index
, x
, y
, 0, 1);
2041 void VertexAttrib3f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
) {
2042 VertexAttrib4f(index
, x
, y
, z
, 1);
2045 void VertexAttrib4f(GLuint index
, GLfloat x
, GLfloat y
, GLfloat z
,
2047 const float arr
[4] = {x
, y
, z
, w
};
2048 VertexAttrib4Tv(index
, webgl::AttribBaseType::Float
, MakeByteRange(arr
));
2053 template <typename List
, typename T
, size_t N
>
2054 bool MakeArrayFromList(const List
& list
, T (&array
)[N
]) {
2055 bool badLength
= false;
2056 if (!Convert(list
, [&](const auto& aData
, JS::AutoCheckCannotGC
&&) {
2058 std::is_same_v
<std::remove_const_t
<
2059 std::remove_reference_t
<decltype(aData
[0])>>,
2061 if (N
> aData
.Length()) {
2066 std::copy_n(aData
.begin(), N
, array
);
2070 LOCAL_GL_INVALID_VALUE
,
2072 ? nsPrintfCString("Length of `list` must be >=%zu.", N
).get()
2073 : "Conversion of `list` failed.");
2079 void VertexAttrib1fv(const GLuint index
, const Float32ListU
& list
) {
2080 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2081 if (IsContextLost()) return;
2084 if (!MakeArrayFromList(list
, arr
)) {
2087 VertexAttrib1f(index
, arr
[0]);
2090 void VertexAttrib2fv(const GLuint index
, const Float32ListU
& list
) {
2091 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2092 if (IsContextLost()) return;
2095 if (!MakeArrayFromList(list
, arr
)) {
2098 VertexAttrib2f(index
, arr
[0], arr
[1]);
2101 void VertexAttrib3fv(const GLuint index
, const Float32ListU
& list
) {
2102 const FuncScope
funcScope(*this, "vertexAttrib1fv");
2103 if (IsContextLost()) return;
2106 if (!MakeArrayFromList(list
, arr
)) {
2109 VertexAttrib3f(index
, arr
[0], arr
[1], arr
[2]);
2112 void VertexAttrib4fv(GLuint index
, const Float32ListU
& list
) {
2113 const FuncScope
funcScope(*this, "vertexAttrib4fv");
2115 if (!MakeArrayFromList(list
, arr
)) {
2118 VertexAttrib4Tv(index
, webgl::AttribBaseType::Float
, MakeByteRange(arr
));
2120 void VertexAttribI4iv(GLuint index
, const Int32ListU
& list
) {
2121 const FuncScope
funcScope(*this, "vertexAttribI4iv");
2123 if (!MakeArrayFromList(list
, arr
)) {
2126 VertexAttrib4Tv(index
, webgl::AttribBaseType::Int
, MakeByteRange(arr
));
2128 void VertexAttribI4uiv(GLuint index
, const Uint32ListU
& list
) {
2129 const FuncScope
funcScope(*this, "vertexAttribI4uiv");
2131 if (!MakeArrayFromList(list
, arr
)) {
2134 VertexAttrib4Tv(index
, webgl::AttribBaseType::Uint
, MakeByteRange(arr
));
2137 void VertexAttribI4i(GLuint index
, GLint x
, GLint y
, GLint z
, GLint w
) {
2138 const int32_t arr
[4] = {x
, y
, z
, w
};
2139 VertexAttrib4Tv(index
, webgl::AttribBaseType::Int
, MakeByteRange(arr
));
2141 void VertexAttribI4ui(GLuint index
, GLuint x
, GLuint y
, GLuint z
, GLuint w
) {
2142 const uint32_t arr
[4] = {x
, y
, z
, w
};
2143 VertexAttrib4Tv(index
, webgl::AttribBaseType::Uint
, MakeByteRange(arr
));
2147 void VertexAttribPointerImpl(bool isFuncInt
, GLuint index
, GLint size
,
2148 GLenum type
, WebGLboolean normalized
,
2149 GLsizei iStride
, WebGLintptr iByteOffset
);
2152 void VertexAttribIPointer(GLuint index
, GLint size
, GLenum type
,
2153 GLsizei stride
, WebGLintptr byteOffset
) {
2154 VertexAttribPointerImpl(true, index
, size
, type
, false, stride
, byteOffset
);
2157 void VertexAttribPointer(GLuint index
, GLint size
, GLenum type
,
2158 WebGLboolean normalized
, GLsizei stride
,
2159 WebGLintptr byteOffset
) {
2160 VertexAttribPointerImpl(false, index
, size
, type
, normalized
, stride
,
2164 // -------------------------------- Drawing -------------------------------
2166 void DrawArrays(GLenum mode
, GLint first
, GLsizei count
) {
2167 DrawArraysInstanced(mode
, first
, count
, 1);
2170 void DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
2171 WebGLintptr byteOffset
) {
2172 DrawElementsInstanced(mode
, count
, type
, byteOffset
, 1);
2175 void DrawRangeElements(GLenum mode
, GLuint start
, GLuint end
, GLsizei count
,
2176 GLenum type
, WebGLintptr byteOffset
) {
2177 const FuncScope
funcScope(*this, "drawRangeElements");
2179 EnqueueError(LOCAL_GL_INVALID_VALUE
, "end must be >= start.");
2182 DrawElementsInstanced(mode
, count
, type
, byteOffset
, 1);
2185 // ------------------------------ Readback -------------------------------
2187 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2188 GLenum format
, GLenum type
,
2189 const dom::Nullable
<dom::ArrayBufferView
>& maybeView
,
2190 dom::CallerType aCallerType
, ErrorResult
& out_error
) const {
2191 const FuncScope
funcScope(*this, "readPixels");
2192 if (!ValidateNonNull("pixels", maybeView
)) return;
2193 ReadPixels(x
, y
, width
, height
, format
, type
, maybeView
.Value(), 0,
2194 aCallerType
, out_error
);
2197 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2198 GLenum format
, GLenum type
, WebGLsizeiptr offset
,
2199 dom::CallerType aCallerType
, ErrorResult
& out_error
) const;
2201 void ReadPixels(GLint x
, GLint y
, GLsizei width
, GLsizei height
,
2202 GLenum format
, GLenum type
,
2203 const dom::ArrayBufferView
& dstData
, GLuint dstElemOffset
,
2204 dom::CallerType aCallerType
, ErrorResult
& out_error
) const;
2207 bool ReadPixels_SharedPrecheck(dom::CallerType aCallerType
,
2208 ErrorResult
& out_error
) const;
2210 // ------------------------------ Vertex Array ------------------------------
2212 void BindVertexArray(WebGLVertexArrayJS
*);
2214 void DrawArraysInstanced(GLenum mode
, GLint first
, GLsizei count
,
2217 void DrawElementsInstanced(GLenum mode
, GLsizei count
, GLenum type
,
2218 WebGLintptr offset
, GLsizei primcount
);
2220 void VertexAttribDivisor(GLuint index
, GLuint divisor
);
2222 // --------------------------------- GL Query
2223 // ---------------------------------
2225 void GetQuery(JSContext
*, GLenum target
, GLenum pname
,
2226 JS::MutableHandle
<JS::Value
> retval
) const;
2227 void GetQueryParameter(JSContext
*, WebGLQueryJS
&, GLenum pname
,
2228 JS::MutableHandle
<JS::Value
> retval
) const;
2229 void BeginQuery(GLenum target
, WebGLQueryJS
&);
2230 void EndQuery(GLenum target
);
2231 void QueryCounter(WebGLQueryJS
&, GLenum target
) const;
2233 // -------------------------------- Sampler -------------------------------
2235 void GetSamplerParameter(JSContext
*, const WebGLSamplerJS
&, GLenum pname
,
2236 JS::MutableHandle
<JS::Value
> retval
) const;
2238 void BindSampler(GLuint unit
, WebGLSamplerJS
*);
2239 void SamplerParameteri(WebGLSamplerJS
&, GLenum pname
, GLint param
) const;
2240 void SamplerParameterf(WebGLSamplerJS
&, GLenum pname
, GLfloat param
) const;
2242 // ------------------------------- GL Sync ---------------------------------
2244 GLenum
ClientWaitSync(WebGLSyncJS
&, GLbitfield flags
, GLuint64 timeout
) const;
2245 void GetSyncParameter(JSContext
*, WebGLSyncJS
&, GLenum pname
,
2246 JS::MutableHandle
<JS::Value
> retval
) const;
2247 void WaitSync(const WebGLSyncJS
&, GLbitfield flags
, GLint64 timeout
) const;
2249 mutable webgl::ObjectId mCompletedSyncId
= 0;
2250 void OnSyncComplete(webgl::ObjectId id
) const {
2251 if (mCompletedSyncId
< id
) {
2252 mCompletedSyncId
= id
;
2256 // -------------------------- Transform Feedback ---------------------------
2258 void BindTransformFeedback(GLenum target
, WebGLTransformFeedbackJS
*);
2259 void BeginTransformFeedback(GLenum primitiveMode
);
2260 void EndTransformFeedback();
2261 void PauseTransformFeedback();
2262 void ResumeTransformFeedback();
2264 // -------------------------- Opaque Framebuffers ---------------------------
2266 void SetFramebufferIsInOpaqueRAF(WebGLFramebufferJS
*, bool);
2268 // ------------------------------ Extensions ------------------------------
2270 void GetSupportedExtensions(dom::Nullable
<nsTArray
<nsString
>>& retval
,
2271 dom::CallerType callerType
) const;
2273 bool IsSupported(WebGLExtensionID
, dom::CallerType callerType
=
2274 dom::CallerType::NonSystem
) const;
2276 void GetExtension(JSContext
* cx
, const nsAString
& name
,
2277 JS::MutableHandle
<JSObject
*> retval
,
2278 dom::CallerType callerType
, ErrorResult
& rv
);
2281 bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext
,
2282 const dom::CallerType callerType
) const;
2284 RefPtr
<ClientWebGLExtensionBase
> GetExtension(WebGLExtensionID ext
,
2285 dom::CallerType callerType
);
2286 void RequestExtension(WebGLExtensionID
) const;
2289 bool IsExtensionEnabled(const WebGLExtensionID id
) const {
2290 return bool(mNotLost
->extensions
[UnderlyingValue(id
)]);
2293 void AddCompressedFormat(GLenum
);
2295 // ---------------------------- Misc Extensions ----------------------------
2297 void DrawBuffers(const dom::Sequence
<GLenum
>& buffers
);
2299 void GetSupportedProfilesASTC(
2300 dom::Nullable
<nsTArray
<nsString
>>& retval
) const;
2302 void MOZDebugGetParameter(JSContext
* cx
, GLenum pname
,
2303 JS::MutableHandle
<JS::Value
> retval
,
2305 GetParameter(cx
, pname
, retval
, rv
, true);
2308 void ProvokingVertex(GLenum rawMode
) const;
2310 // -------------------------------------------------------------------------
2311 // Client-side methods. Calls in the Host are forwarded to the client.
2312 // -------------------------------------------------------------------------
2314 void JsWarning(const std::string
&) const;
2316 // -------------------------------------------------------------------------
2317 // The cross-process communication mechanism
2318 // -------------------------------------------------------------------------
2320 // If we are running WebGL in this process then call the HostWebGLContext
2321 // method directly. Otherwise, dispatch over IPC.
2322 template <typename MethodType
, MethodType method
, typename
... CallerArgs
>
2323 void Run(const CallerArgs
&... args
) const {
2324 const auto id
= IdByMethod
<MethodType
, method
>();
2325 auto noNoGc
= std::optional
<JS::AutoCheckCannotGC
>{};
2326 Run_WithDestArgTypes_ConstnessHelper(std::move(noNoGc
), method
, id
,
2330 // Same as above for use when using potentially GC-controlled data. The scope
2331 // of `aNoGC` will be ended after the data is no longer needed.
2332 template <typename MethodType
, MethodType method
, typename
... CallerArgs
>
2333 void RunWithGCData(JS::AutoCheckCannotGC
&& aNoGC
,
2334 const CallerArgs
&... aArgs
) const {
2335 const auto id
= IdByMethod
<MethodType
, method
>();
2336 auto noGc
= std::optional
<JS::AutoCheckCannotGC
>{std::move(aNoGC
)};
2337 Run_WithDestArgTypes_ConstnessHelper(std::move(noGc
), method
, id
, aArgs
...);
2340 // Because we're trying to explicitly pull `DestArgs` via `method`, we have
2341 // one overload for mut-methods and one for const-methods.
2342 template <typename
... DestArgs
>
2343 void Run_WithDestArgTypes_ConstnessHelper(
2344 std::optional
<JS::AutoCheckCannotGC
>&& noGc
,
2345 void (HostWebGLContext::*method
)(DestArgs
...), const size_t id
,
2346 const std::remove_reference_t
<std::remove_const_t
<DestArgs
>>&... args
)
2348 Run_WithDestArgTypes(std::move(noGc
), method
, id
, args
...);
2350 template <typename
... DestArgs
>
2351 void Run_WithDestArgTypes_ConstnessHelper(
2352 std::optional
<JS::AutoCheckCannotGC
>&& noGc
,
2353 void (HostWebGLContext::*method
)(DestArgs
...) const, const size_t id
,
2354 const std::remove_reference_t
<std::remove_const_t
<DestArgs
>>&... args
)
2356 Run_WithDestArgTypes(std::move(noGc
), method
, id
, args
...);
2359 template <typename MethodT
, typename
... DestArgs
>
2360 void Run_WithDestArgTypes(std::optional
<JS::AutoCheckCannotGC
>&&, MethodT
,
2361 const size_t id
, const DestArgs
&...) const;
2363 // -------------------------------------------------------------------------
2364 // Helpers for DOM operations, composition, actors, etc
2365 // -------------------------------------------------------------------------
2368 // https://immersive-web.github.io/webxr/#xr-compatible
2369 bool IsXRCompatible() const;
2370 already_AddRefed
<dom::Promise
> MakeXRCompatible(ErrorResult
& aRv
);
2373 uint32_t GetPrincipalHashValue() const;
2375 // Prepare the context for capture before compositing
2376 void BeginComposition();
2378 // Clean up the context after captured for compositing
2379 void EndComposition();
2381 mozilla::dom::Document
* GetOwnerDoc() const;
2383 mutable bool mResetLayer
= true;
2384 Maybe
<const WebGLContextOptions
> mInitialOptions
;
2385 bool mXRCompatible
= false;
2388 // used by DOM bindings in conjunction with GetParentObject
2389 inline nsISupports
* ToSupports(ClientWebGLContext
* webgl
) {
2390 return static_cast<nsICanvasRenderingContextInternal
*>(webgl
);
2393 const char* GetExtensionName(WebGLExtensionID
);
2397 inline bool webgl::ObjectJS::IsForContext(
2398 const ClientWebGLContext
& context
) const {
2399 const auto& notLost
= context
.mNotLost
;
2400 if (!notLost
) return false;
2401 if (notLost
.get() != mGeneration
.lock().get()) return false;
2405 void AutoJsWarning(const std::string
& utf8
);
2407 } // namespace mozilla
2409 #endif // CLIENTWEBGLCONTEXT_H_