Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / dom / canvas / ClientWebGLContext.h
blobe736235361ee7734ae9c0e71ee00da306323dae8
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_
9 #include "GLConsts.h"
10 #include "js/GCAPI.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"
28 #include <memory>
29 #include <type_traits>
30 #include <unordered_map>
31 #include <unordered_set>
32 #include <vector>
34 namespace mozilla {
36 class ClientWebGLExtensionBase;
37 class HostWebGLContext;
39 template <typename MethodT, MethodT Method>
40 size_t IdByMethod();
42 namespace dom {
43 class OwningHTMLCanvasElementOrOffscreenCanvas;
44 class WebGLChild;
45 } // namespace dom
47 namespace webgl {
48 class AvailabilityRunnable;
49 class TexUnpackBlob;
50 class TexUnpackBytes;
51 } // namespace webgl
53 ////////////////////////////////////
55 class WebGLActiveInfoJS final : public RefCounted<WebGLActiveInfoJS> {
56 public:
57 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLActiveInfoJS)
59 const webgl::ActiveInfo mInfo;
61 explicit WebGLActiveInfoJS(const webgl::ActiveInfo& info) : mInfo(info) {}
63 virtual ~WebGLActiveInfoJS() = default;
65 // -
66 // WebIDL attributes
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> {
79 public:
80 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLShaderPrecisionFormatJS)
82 const webgl::ShaderPrecisionFormat mInfo;
84 explicit WebGLShaderPrecisionFormatJS(
85 const webgl::ShaderPrecisionFormat& info)
86 : mInfo(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;
101 class WebGLBufferJS;
102 class WebGLFramebufferJS;
103 class WebGLProgramJS;
104 class WebGLQueryJS;
105 class WebGLRenderbufferJS;
106 class WebGLSamplerJS;
107 class WebGLShaderJS;
108 class WebGLTextureJS;
109 class WebGLTransformFeedbackJS;
110 class WebGLVertexArrayJS;
112 namespace webgl {
114 struct LinkResult;
116 class ProgramKeepAlive final {
117 friend class mozilla::WebGLProgramJS;
119 WebGLProgramJS* mParent;
121 public:
122 explicit ProgramKeepAlive(WebGLProgramJS& parent) : mParent(&parent) {}
123 ~ProgramKeepAlive();
126 class ShaderKeepAlive final {
127 friend class mozilla::WebGLShaderJS;
129 const WebGLShaderJS* mParent;
131 public:
132 explicit ShaderKeepAlive(const WebGLShaderJS& parent) : mParent(&parent) {}
133 ~ShaderKeepAlive();
136 class ContextGenerationInfo final {
137 public:
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;
183 // -
185 // In the cross process case, the WebGL actor's ownership relationship looks
186 // like this:
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)>
203 extensions;
205 RefPtr<layers::CanvasRenderer> mCanvasRenderer;
207 explicit NotLostData(ClientWebGLContext& context);
208 ~NotLostData();
211 // -
213 class ObjectJS {
214 friend ClientWebGLContext;
216 public:
217 const std::weak_ptr<NotLostData> mGeneration;
218 const ObjectId mId;
220 protected:
221 bool mDeleteRequested = false;
223 explicit ObjectJS(const ClientWebGLContext&);
224 virtual ~ObjectJS() = default;
226 public:
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(); }
235 // A la carte:
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();
243 // The workhorse:
244 bool ValidateUsable(const ClientWebGLContext& context,
245 const char* const argName) const {
246 if (MOZ_LIKELY(IsUsable(context))) return true;
247 WarnInvalidUse(context, argName);
248 return false;
251 // Use by DeleteFoo:
252 bool ValidateForContext(const ClientWebGLContext& context,
253 const char* const argName) const;
255 private:
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; }
262 } // namespace webgl
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
272 public:
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) {}
279 private:
280 ~WebGLBufferJS();
282 public:
283 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
286 // -
288 class WebGLFramebufferJS final : public nsWrapperCache, public webgl::ObjectJS {
289 friend class ClientWebGLContext;
291 public:
292 struct Attachment final {
293 RefPtr<WebGLRenderbufferJS> rb;
294 RefPtr<WebGLTextureJS> tex;
297 private:
298 bool mHasBeenBound = false; // !IsFramebuffer until Bind
299 std::unordered_map<GLenum, Attachment> mAttachments;
301 public:
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);
307 const bool mOpaque;
308 bool mInOpaqueRAF = false;
310 private:
311 ~WebGLFramebufferJS();
313 void EnsureColorAttachments();
315 public:
316 Attachment* GetAttachment(const GLenum slotEnum) {
317 auto ret = MaybeFind(mAttachments, slotEnum);
318 if (!ret) {
319 EnsureColorAttachments();
320 ret = MaybeFind(mAttachments, slotEnum);
322 return ret;
325 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
328 // -
330 class WebGLProgramJS final : public nsWrapperCache, public webgl::ObjectJS {
331 friend class ClientWebGLContext;
333 public:
334 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgramJS)
335 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLProgramJS)
336 // Must come first!
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
339 // uninitialized.
341 struct Attachment final {
342 RefPtr<WebGLShaderJS> shader;
343 std::shared_ptr<webgl::ShaderKeepAlive> keepAlive;
346 private:
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>>
361 mUniformLocByName;
362 mutable std::vector<uint32_t> mUniformBlockBindings;
364 std::unordered_set<const WebGLTransformFeedbackJS*> mActiveTfos;
366 explicit WebGLProgramJS(const ClientWebGLContext&);
368 ~WebGLProgramJS() {
369 mKeepAlive = nullptr; // Try to delete.
371 const auto& maybe = mKeepAliveWeak.lock();
372 if (maybe) {
373 maybe->mParent = nullptr;
377 public:
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;
384 // -
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;
395 public:
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) {}
402 private:
403 ~WebGLQueryJS();
405 public:
406 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
409 // -
411 class WebGLRenderbufferJS final : public nsWrapperCache,
412 public webgl::ObjectJS {
413 friend class ClientWebGLContext;
415 public:
416 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbufferJS)
417 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLRenderbufferJS)
419 private:
420 bool mHasBeenBound = false; // !IsRenderbuffer until Bind
422 explicit WebGLRenderbufferJS(const ClientWebGLContext& webgl)
423 : webgl::ObjectJS(webgl) {}
424 ~WebGLRenderbufferJS();
426 public:
427 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
430 // -
432 class WebGLSamplerJS final : public nsWrapperCache, public webgl::ObjectJS {
433 // IsSampler without Bind
434 public:
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) {}
441 private:
442 ~WebGLSamplerJS();
444 public:
445 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
448 // -
450 class WebGLShaderJS final : public nsWrapperCache, public webgl::ObjectJS {
451 friend class ClientWebGLContext;
453 public:
454 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShaderJS)
455 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLShaderJS)
457 private:
458 const GLenum mType;
459 std::string mSource;
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);
467 ~WebGLShaderJS() {
468 mKeepAlive = nullptr; // Try to delete.
470 const auto& maybe = mKeepAliveWeak.lock();
471 if (maybe) {
472 maybe->mParent = nullptr;
476 public:
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;
483 // -
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;
495 public:
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) {}
502 private:
503 ~WebGLSyncJS();
505 public:
506 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
509 // -
511 class WebGLTextureJS final : public nsWrapperCache, public webgl::ObjectJS {
512 friend class ClientWebGLContext;
514 GLenum mTarget = 0; // !IsTexture until Bind
516 public:
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) {}
523 private:
524 ~WebGLTextureJS();
526 public:
527 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
530 // -
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;
542 public:
543 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedbackJS)
544 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTransformFeedbackJS)
546 explicit WebGLTransformFeedbackJS(const ClientWebGLContext&);
548 private:
549 ~WebGLTransformFeedbackJS();
551 public:
552 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
555 // -
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;
567 public:
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,
573 GLenum elemType)
574 : webgl::ObjectJS(webgl),
575 mParent(parent),
576 mLocation(loc),
577 mValidUploadElemTypes(ValidUploadElemTypes(elemType)) {}
579 private:
580 ~WebGLUniformLocationJS() = default;
582 public:
583 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
586 // -
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;
595 public:
596 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArrayJS)
597 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLVertexArrayJS)
599 explicit WebGLVertexArrayJS(const ClientWebGLContext&);
601 private:
602 ~WebGLVertexArrayJS();
604 public:
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;
620 nogc.reset();
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) {
667 return AsBytes(x);
670 // -
672 struct TexImageSourceAdapter final : public TexImageSource {
673 TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView,
674 ErrorResult*) {
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*) {
689 mView = view;
692 TexImageSourceAdapter(const dom::ArrayBufferView* view, GLuint viewElemOffset,
693 GLuint viewElemLengthOverride = 0) {
694 mView = view;
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) {
732 mDomElem = domElem;
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 ---------------------------
748 public:
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 {
754 if (mIsWebGL2) {
755 return dom::WebGL2RenderingContext_Binding::Wrap(cx, this, givenProto);
757 return dom::WebGLRenderingContext_Binding::Wrap(cx, this, givenProto);
760 // -
762 public:
763 const bool mIsWebGL2;
765 private:
766 bool mIsCanvasDirty = false;
767 uvec2 mRequestedSize = {};
769 public:
770 explicit ClientWebGLContext(bool webgl2);
772 private:
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;
783 public:
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;
791 // -
793 public:
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();
807 // -
809 private:
810 mutable RefPtr<webgl::AvailabilityRunnable> mAvailabilityRunnable;
812 public:
813 webgl::AvailabilityRunnable& EnsureAvailabilityRunnable() const;
815 // -
817 public:
818 void EmulateLoseContext() const;
819 void OnContextLoss(webgl::ContextLossReason) const;
820 void RestoreContext(webgl::LossStatus requiredStatus) const;
822 private:
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();
832 public:
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 // -------------------------------------------------------------------------
848 public:
849 // Remembers the WebGL function that is lowest on the stack for client-side
850 // error generation.
851 class FuncScope final {
852 public:
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)
858 : mWebGL(webgl),
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;
867 ~FuncScope() {
868 if (this == mWebGL.mFuncScope) {
869 mWebGL.mFuncScope = nullptr;
873 FuncScope(const FuncScope&) = delete;
874 FuncScope(FuncScope&&) = delete;
877 protected:
878 // The scope of the function at the top of the current WebGL function call
879 // stack
880 mutable FuncScope* mFuncScope = nullptr;
882 const char* FuncName() const {
883 return mFuncScope ? mFuncScope->mFuncName : nullptr;
886 public:
887 template <typename... Args>
888 void EnqueueError(const GLenum error, const char* const format,
889 const Args&... args) const {
890 MOZ_ASSERT(FuncName());
891 nsCString text;
892 text.AppendPrintf("WebGL warning: %s: ", FuncName());
894 #ifdef __clang__
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"
900 #endif
901 text.AppendPrintf(format, args...);
902 #ifdef __clang__
903 # pragma clang diagnostic pop
904 #elif defined(__GNUC__)
905 # pragma GCC diagnostic pop
906 #endif
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.
928 private:
929 void EnqueueErrorImpl(GLenum errorOrZero, const nsACString&) const;
931 public:
932 Maybe<Span<uint8_t>> ValidateArrayBufferView(const Span<uint8_t>& bytes,
933 size_t elemSize,
934 GLuint elemOffset,
935 GLuint elemCountOverride,
936 const GLenum errorEnum) const;
938 protected:
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);
944 return false;
946 return true;
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.",
952 argName);
953 return false;
955 return true;
958 bool ValidateViewType(GLenum unpackType, const TexImageSource& src) const;
960 Maybe<uvec3> ValidateExtents(GLsizei width, GLsizei height, GLsizei depth,
961 GLint border) const;
963 // -------------------------------------------------------------------------
964 // nsICanvasRenderingContextInternal / nsAPostRefreshObserver
965 // -------------------------------------------------------------------------
966 public:
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();
986 NS_IMETHOD
987 SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options,
988 ErrorResult& aRvForDictionaryInit) override;
989 NS_IMETHOD
990 SetDimensions(int32_t width, int32_t height) override;
991 bool UpdateWebRenderCanvasData(
992 nsDisplayListBuilder* aBuilder,
993 layers::WebRenderCanvasData* aCanvasData) override;
995 // ------
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;
1030 // ------
1032 protected:
1033 layers::LayersBackend GetCompositorBackendType() const;
1035 Watchable<FrameCaptureState> mFrameCaptureState = {
1036 FrameCaptureState::CLEAN, "ClientWebGLContext::mFrameCaptureState"};
1038 // -------------------------------------------------------------------------
1039 // WebGLRenderingContext Basic Properties and Methods
1040 // -------------------------------------------------------------------------
1041 public:
1042 dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; }
1043 void Commit();
1044 void GetCanvas(
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);
1057 private:
1058 webgl::SwapChainOptions PrepareAsyncSwapChainOptions(
1059 WebGLFramebufferJS* fb, bool webvr,
1060 const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
1062 public:
1063 layers::TextureType GetTexTypeForSwapChain() const;
1064 void Present(
1065 WebGLFramebufferJS*, const bool webvr = false,
1066 const webgl::SwapChainOptions& options = webgl::SwapChainOptions());
1067 void Present(
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());
1073 void EndOfFrame();
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();
1087 private:
1088 RefPtr<gfx::DataSourceSurface> BackBufferSnapshot();
1089 [[nodiscard]] bool DoReadPixels(const webgl::ReadPixelsDesc&,
1090 Span<uint8_t>) const;
1091 uvec2 DrawingBufferSize();
1093 // -
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",
1115 DeferredFlush);
1116 NS_DispatchToCurrentThread(std::move(runnable));
1119 void CancelAutoFlush() const { mAutoFlushPending = false; }
1121 // -
1123 void AfterDrawCall() {
1124 if (!mNotLost) return;
1125 const auto& state = State();
1126 if (!state.mBoundDrawFb) {
1127 MarkCanvasDirty();
1130 AutoEnqueueFlush();
1133 // -------------------------------------------------------------------------
1134 // Client-side helper methods. Dispatch to a Host method.
1135 // -------------------------------------------------------------------------
1137 // ------------------------- GL State -------------------------
1138 public:
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;
1147 private:
1148 Maybe<double> GetNumber(GLenum pname);
1149 Maybe<std::string> GetString(GLenum pname);
1151 public:
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;
1177 // -
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*);
1206 private:
1207 void DoDeleteProgram(WebGLProgramJS&) const;
1208 void DoDeleteShader(const WebGLShaderJS&) const;
1210 public:
1211 // -
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;
1225 // -
1226 // WebGLProgramJS
1228 private:
1229 const webgl::LinkResult& GetLinkResult(const WebGLProgramJS&) const;
1231 public:
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&,
1248 GLuint index);
1249 already_AddRefed<WebGLActiveInfoJS> GetActiveUniform(const WebGLProgramJS&,
1250 GLuint index);
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,
1257 ErrorResult& rv);
1258 void GetActiveUniforms(JSContext*, const WebGLProgramJS&,
1259 const dom::Sequence<GLuint>& uniformIndices,
1260 GLenum pname,
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);
1282 // -
1283 // WebGLShaderJS
1285 private:
1286 const webgl::CompileResult& GetCompileResult(const WebGLShaderJS&) const;
1288 public:
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;
1298 // -
1300 void BindFramebuffer(GLenum target, WebGLFramebufferJS*);
1302 void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
1304 // -
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,
1315 GLenum dstAlpha) {
1316 BlendFuncSeparateI({}, srcRGB, dstRGB, srcAlpha, dstAlpha);
1319 void BlendEquationSeparateI(Maybe<GLuint> buf, GLenum modeRGB,
1320 GLenum modeAlpha);
1321 void BlendFuncSeparateI(Maybe<GLuint> buf, GLenum srcRGB, GLenum dstRGB,
1322 GLenum srcAlpha, GLenum dstAlpha);
1324 // -
1326 GLenum CheckFramebufferStatus(GLenum target);
1328 void Clear(GLbitfield mask);
1330 // -
1332 private:
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);
1339 public:
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);
1347 return true;
1348 })) {
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);
1359 return true;
1360 })) {
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);
1371 return true;
1372 })) {
1373 EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small.");
1377 // -
1379 void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth,
1380 GLint stencil);
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;
1403 void Finish();
1405 void FrontFace(GLenum mode);
1407 GLenum GetError();
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);
1421 // -
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,
1436 GLenum dppass);
1438 // -
1440 void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
1442 // ------------------------- Buffer Objects -------------------------
1443 public:
1444 void BindBuffer(GLenum target, WebGLBufferJS*);
1446 // -
1448 private:
1449 void BindBufferRangeImpl(const GLenum target, const GLuint index,
1450 WebGLBufferJS* const buffer, const uint64_t offset,
1451 const uint64_t size);
1453 public:
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;
1468 if (buffer) {
1469 if (!ValidateNonNegative("offset", offset)) return;
1471 if (size < 1) {
1472 EnqueueError(LOCAL_GL_INVALID_VALUE,
1473 "`size` must be positive for non-null `buffer`.");
1474 return;
1478 BindBufferRangeImpl(target, index, buffer, static_cast<uint64_t>(offset),
1479 static_cast<uint64_t>(size));
1482 // -
1484 void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
1485 GLintptr readOffset, GLintptr writeOffset,
1486 GLsizeiptr size);
1488 void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
1489 void BufferData(GLenum target,
1490 const dom::Nullable<dom::ArrayBuffer>& maybeSrc,
1491 GLenum usage);
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);
1512 // -
1514 private:
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;
1521 public:
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);
1528 return;
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,
1549 GLint zLayerBase,
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.");
1555 return;
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));
1563 // -
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,
1579 ErrorResult& rv);
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);
1606 // -
1608 private:
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;
1627 public:
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},
1648 src);
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},
1659 src);
1662 // -
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);
1683 // -
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);
1707 // -
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},
1717 src);
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},
1728 src);
1731 ////////////////////////////////////
1733 public:
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);
1753 // -
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,
1762 imageSize);
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);
1777 // -
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);
1799 // -
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,
1809 src, imageSize);
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,
1823 src, 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 ------------------------
1875 private:
1876 Maybe<double> GetVertexAttribPriv(GLuint index, GLenum pname);
1878 public:
1879 void GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
1880 JS::MutableHandle<JS::Value> retval, ErrorResult& rv);
1882 private:
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);
1912 // -
1914 template <typename T>
1915 Maybe<Range<T>> ValidateSubrange(const Range<T>& data, size_t elemOffset,
1916 size_t elemLengthOverride = 0) const {
1917 auto ret = data;
1918 if (elemOffset > ret.length()) {
1919 EnqueueError(LOCAL_GL_INVALID_VALUE,
1920 "`elemOffset` too large for `data`.");
1921 return {};
1923 ret = {ret.begin() + elemOffset, ret.end()};
1924 if (elemLengthOverride) {
1925 if (elemLengthOverride > ret.length()) {
1926 EnqueueError(
1927 LOCAL_GL_INVALID_VALUE,
1928 "`elemLengthOverride` too large for `data` and `elemOffset`.");
1929 return {};
1931 ret = {ret.begin().get(), elemLengthOverride};
1933 return Some(ret);
1936 public:
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, \
1943 type_t y) const { \
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)
1962 #undef _
1964 // -
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); \
1973 return true; \
1974 }); \
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)
1990 #undef _
1992 // -
1994 #define _(X) \
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); \
2002 return true; \
2003 }); \
2006 _(2)
2007 _(2x3)
2008 _(2x4)
2010 _(3x2)
2011 _(3)
2012 _(3x4)
2014 _(4x2)
2015 _(4x3)
2016 _(4)
2018 #undef _
2020 // -
2022 void EnableVertexAttribArray(GLuint index);
2024 void DisableVertexAttribArray(GLuint index);
2026 WebGLsizeiptr GetVertexAttribOffset(GLuint index, GLenum pname);
2028 // -
2030 private:
2031 void VertexAttrib4Tv(GLuint index, webgl::AttribBaseType,
2032 const Range<const uint8_t>&);
2034 public:
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,
2046 GLfloat w) {
2047 const float arr[4] = {x, y, z, w};
2048 VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr));
2051 // -
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&&) {
2057 static_assert(
2058 std::is_same_v<std::remove_const_t<
2059 std::remove_reference_t<decltype(aData[0])>>,
2060 T>);
2061 if (N > aData.Length()) {
2062 badLength = true;
2063 return false;
2066 std::copy_n(aData.begin(), N, array);
2067 return true;
2068 })) {
2069 EnqueueError(
2070 LOCAL_GL_INVALID_VALUE,
2071 badLength
2072 ? nsPrintfCString("Length of `list` must be >=%zu.", N).get()
2073 : "Conversion of `list` failed.");
2074 return false;
2076 return true;
2079 void VertexAttrib1fv(const GLuint index, const Float32ListU& list) {
2080 const FuncScope funcScope(*this, "vertexAttrib1fv");
2081 if (IsContextLost()) return;
2083 float arr[1];
2084 if (!MakeArrayFromList(list, arr)) {
2085 return;
2087 VertexAttrib1f(index, arr[0]);
2090 void VertexAttrib2fv(const GLuint index, const Float32ListU& list) {
2091 const FuncScope funcScope(*this, "vertexAttrib1fv");
2092 if (IsContextLost()) return;
2094 float arr[2];
2095 if (!MakeArrayFromList(list, arr)) {
2096 return;
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;
2105 float arr[3];
2106 if (!MakeArrayFromList(list, arr)) {
2107 return;
2109 VertexAttrib3f(index, arr[0], arr[1], arr[2]);
2112 void VertexAttrib4fv(GLuint index, const Float32ListU& list) {
2113 const FuncScope funcScope(*this, "vertexAttrib4fv");
2114 float arr[4];
2115 if (!MakeArrayFromList(list, arr)) {
2116 return;
2118 VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr));
2120 void VertexAttribI4iv(GLuint index, const Int32ListU& list) {
2121 const FuncScope funcScope(*this, "vertexAttribI4iv");
2122 int32_t arr[4];
2123 if (!MakeArrayFromList(list, arr)) {
2124 return;
2126 VertexAttrib4Tv(index, webgl::AttribBaseType::Int, MakeByteRange(arr));
2128 void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) {
2129 const FuncScope funcScope(*this, "vertexAttribI4uiv");
2130 uint32_t arr[4];
2131 if (!MakeArrayFromList(list, arr)) {
2132 return;
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));
2146 private:
2147 void VertexAttribPointerImpl(bool isFuncInt, GLuint index, GLint size,
2148 GLenum type, WebGLboolean normalized,
2149 GLsizei iStride, WebGLintptr iByteOffset);
2151 public:
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,
2161 byteOffset);
2164 // -------------------------------- Drawing -------------------------------
2165 public:
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");
2178 if (end < start) {
2179 EnqueueError(LOCAL_GL_INVALID_VALUE, "end must be >= start.");
2180 return;
2182 DrawElementsInstanced(mode, count, type, byteOffset, 1);
2185 // ------------------------------ Readback -------------------------------
2186 public:
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;
2206 protected:
2207 bool ReadPixels_SharedPrecheck(dom::CallerType aCallerType,
2208 ErrorResult& out_error) const;
2210 // ------------------------------ Vertex Array ------------------------------
2211 public:
2212 void BindVertexArray(WebGLVertexArrayJS*);
2214 void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count,
2215 GLsizei primcount);
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 // ---------------------------------
2224 public:
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 ------------------------------
2269 public:
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);
2280 protected:
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;
2288 public:
2289 bool IsExtensionEnabled(const WebGLExtensionID id) const {
2290 return bool(mNotLost->extensions[UnderlyingValue(id)]);
2293 void AddCompressedFormat(GLenum);
2295 // ---------------------------- Misc Extensions ----------------------------
2296 public:
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,
2304 ErrorResult& rv) {
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 // -------------------------------------------------------------------------
2313 public:
2314 void JsWarning(const std::string&) const;
2316 // -------------------------------------------------------------------------
2317 // The cross-process communication mechanism
2318 // -------------------------------------------------------------------------
2319 protected:
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,
2327 args...);
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)
2347 const {
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)
2355 const {
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 // -------------------------------------------------------------------------
2367 public:
2368 // https://immersive-web.github.io/webxr/#xr-compatible
2369 bool IsXRCompatible() const;
2370 already_AddRefed<dom::Promise> MakeXRCompatible(ErrorResult& aRv);
2372 protected:
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);
2395 // -
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;
2402 return true;
2405 void AutoJsWarning(const std::string& utf8);
2407 } // namespace mozilla
2409 #endif // CLIENTWEBGLCONTEXT_H_