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