ClientWebGLContext.h (86897B)
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/. */ 5 6 #ifndef CLIENTWEBGLCONTEXT_H_ 7 #define CLIENTWEBGLCONTEXT_H_ 8 9 #include <memory> 10 #include <type_traits> 11 #include <unordered_map> 12 #include <unordered_set> 13 #include <vector> 14 15 #include "GLConsts.h" 16 #include "WebGLCommandQueue.h" 17 #include "WebGLStrongTypes.h" 18 #include "WebGLTypes.h" 19 #include "js/GCAPI.h" 20 #include "mozilla/Logging.h" 21 #include "mozilla/Range.h" 22 #include "mozilla/RefCounted.h" 23 #include "mozilla/StaticPrefs_webgl.h" 24 #include "mozilla/WeakPtr.h" 25 #include "mozilla/dom/BufferSourceBindingFwd.h" 26 #include "mozilla/dom/ImageData.h" 27 #include "mozilla/dom/TypedArray.h" 28 #include "mozilla/dom/WebGL2RenderingContextBinding.h" 29 #include "mozilla/dom/WebGLRenderingContextBinding.h" 30 #include "mozilla/layers/LayersSurfaces.h" 31 #include "nsICanvasRenderingContextInternal.h" 32 #include "nsWrapperCache.h" 33 34 namespace mozilla { 35 36 class ClientWebGLExtensionBase; 37 class HostWebGLContext; 38 39 template <typename MethodT, MethodT Method> 40 size_t IdByMethod(); 41 42 namespace dom { 43 class OwningHTMLCanvasElementOrOffscreenCanvas; 44 class WebGLChild; 45 } // namespace dom 46 47 namespace webgl { 48 class AvailabilityRunnable; 49 class TexUnpackBlob; 50 class TexUnpackBytes; 51 } // namespace webgl 52 53 //////////////////////////////////// 54 55 class WebGLActiveInfoJS final : public RefCounted<WebGLActiveInfoJS> { 56 public: 57 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLActiveInfoJS) 58 59 const webgl::ActiveInfo mInfo; 60 61 explicit WebGLActiveInfoJS(const webgl::ActiveInfo& info) : mInfo(info) {} 62 63 virtual ~WebGLActiveInfoJS() = default; 64 65 // - 66 // WebIDL attributes 67 68 GLint Size() const { return static_cast<GLint>(mInfo.elemCount); } 69 GLenum Type() const { return mInfo.elemType; } 70 71 void GetName(nsString& retval) const { CopyUTF8toUTF16(mInfo.name, retval); } 72 73 bool WrapObject(JSContext*, JS::Handle<JSObject*>, 74 JS::MutableHandle<JSObject*>); 75 }; 76 77 class WebGLShaderPrecisionFormatJS final 78 : public RefCounted<WebGLShaderPrecisionFormatJS> { 79 public: 80 MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLShaderPrecisionFormatJS) 81 82 const webgl::ShaderPrecisionFormat mInfo; 83 84 explicit WebGLShaderPrecisionFormatJS( 85 const webgl::ShaderPrecisionFormat& info) 86 : mInfo(info) {} 87 88 virtual ~WebGLShaderPrecisionFormatJS() = default; 89 90 GLint RangeMin() const { return mInfo.rangeMin; } 91 GLint RangeMax() const { return mInfo.rangeMax; } 92 GLint Precision() const { return mInfo.precision; } 93 94 bool WrapObject(JSContext*, JS::Handle<JSObject*>, 95 JS::MutableHandle<JSObject*>); 96 }; 97 98 // ----------------------- 99 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; 111 112 namespace webgl { 113 114 struct LinkResult; 115 116 class ProgramKeepAlive final { 117 friend class mozilla::WebGLProgramJS; 118 119 WebGLProgramJS* mParent; 120 121 public: 122 explicit ProgramKeepAlive(WebGLProgramJS& parent) : mParent(&parent) {} 123 ~ProgramKeepAlive(); 124 }; 125 126 class ShaderKeepAlive final { 127 friend class mozilla::WebGLShaderJS; 128 129 const WebGLShaderJS* mParent; 130 131 public: 132 explicit ShaderKeepAlive(const WebGLShaderJS& parent) : mParent(&parent) {} 133 ~ShaderKeepAlive(); 134 }; 135 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; 142 143 RefPtr<WebGLTransformFeedbackJS> mDefaultTfo; 144 RefPtr<WebGLVertexArrayJS> mDefaultVao; 145 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; 154 155 struct TexUnit final { 156 RefPtr<WebGLSamplerJS> sampler; 157 std::unordered_map<GLenum, RefPtr<WebGLTextureJS>> texByTarget; 158 }; 159 uint32_t mActiveTexUnit = 0; 160 std::vector<TexUnit> mTexUnits; 161 162 bool mTfActiveAndNotPaused = false; 163 164 std::vector<TypedQuad> mGenericVertexAttribs; 165 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; 173 174 std::vector<GLenum> mCompressedTextureFormats; 175 176 Maybe<uvec2> mDrawingBufferSize; 177 178 webgl::ProvokingVertex mProvokingVertex = webgl::ProvokingVertex::LastVertex; 179 180 mutable std::unordered_map<GLenum, bool> mIsEnabledMap; 181 }; 182 183 // - 184 185 // In the cross process case, the WebGL actor's ownership relationship looks 186 // like this: 187 // --------------------------------------------------------------------- 188 // | ClientWebGLContext -> WebGLChild -> WebGLParent -> HostWebGLContext 189 // --------------------------------------------------------------------- 190 // 191 // where 'A -> B' means "A owns B" 192 193 struct NotLostData final : public SupportsWeakPtr, RefCounted<NotLostData> { 194 MOZ_DECLARE_REFCOUNTED_TYPENAME(NotLostData) 195 196 ClientWebGLContext& context; 197 webgl::InitContextResult info; 198 199 RefPtr<mozilla::dom::WebGLChild> outOfProcess; 200 std::unique_ptr<HostWebGLContext> inProcess; 201 202 webgl::ContextGenerationInfo state; 203 std::array<RefPtr<ClientWebGLExtensionBase>, 204 UnderlyingValue(WebGLExtensionID::Max)> 205 extensions; 206 207 RefPtr<layers::CanvasRenderer> mCanvasRenderer; 208 209 explicit NotLostData(ClientWebGLContext& context); 210 ~NotLostData(); 211 }; 212 213 // - 214 215 class ObjectJS { 216 friend ClientWebGLContext; 217 218 public: 219 const WeakPtr<NotLostData> mGeneration; 220 const ObjectId mId; 221 222 protected: 223 bool mDeleteRequested = false; 224 225 explicit ObjectJS(const ClientWebGLContext*); 226 virtual ~ObjectJS() = default; 227 228 public: 229 ClientWebGLContext* Context() const { 230 if (!mGeneration) return nullptr; 231 return &(mGeneration->context); 232 } 233 234 ClientWebGLContext* GetParentObject() const { return Context(); } 235 236 // A la carte: 237 bool IsForContext(const ClientWebGLContext&) const; 238 virtual bool IsDeleted() const { return mDeleteRequested; } 239 240 bool IsUsable(const ClientWebGLContext& context) const { 241 return IsForContext(context) && !IsDeleted(); 242 } 243 244 // The workhorse: 245 bool ValidateUsable(const ClientWebGLContext& context, 246 const char* const argName) const { 247 if (MOZ_LIKELY(IsUsable(context))) return true; 248 WarnInvalidUse(context, argName); 249 return false; 250 } 251 252 // Use by DeleteFoo: 253 bool ValidateForContext(const ClientWebGLContext& context, 254 const char* const argName) const; 255 256 private: 257 void WarnInvalidUse(const ClientWebGLContext&, const char* argName) const; 258 259 // The enum is INVALID_VALUE for Program/Shader :( 260 virtual GLenum ErrorOnDeleted() const { return LOCAL_GL_INVALID_OPERATION; } 261 }; 262 263 } // namespace webgl 264 265 // ------------------------- 266 267 class WebGLBufferJS final : public nsWrapperCache, public webgl::ObjectJS { 268 friend class ClientWebGLContext; 269 270 webgl::BufferKind mKind = 271 webgl::BufferKind::Undefined; // !IsBuffer until Bind 272 273 public: 274 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBufferJS) 275 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLBufferJS) 276 277 explicit WebGLBufferJS(const ClientWebGLContext& webgl) 278 : webgl::ObjectJS(&webgl) {} 279 280 private: 281 ~WebGLBufferJS(); 282 283 public: 284 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 285 }; 286 287 // - 288 289 class WebGLFramebufferJS final : public nsWrapperCache, public webgl::ObjectJS { 290 friend class ClientWebGLContext; 291 292 public: 293 struct Attachment final { 294 RefPtr<WebGLRenderbufferJS> rb; 295 RefPtr<WebGLTextureJS> tex; 296 }; 297 298 private: 299 bool mHasBeenBound = false; // !IsFramebuffer until Bind 300 std::unordered_map<GLenum, Attachment> mAttachments; 301 302 public: 303 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebufferJS) 304 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLFramebufferJS) 305 306 explicit WebGLFramebufferJS(const ClientWebGLContext&, bool opaque = false); 307 308 const bool mOpaque; 309 bool mInOpaqueRAF = false; 310 311 private: 312 ~WebGLFramebufferJS(); 313 314 void EnsureColorAttachments(); 315 316 public: 317 Attachment* GetAttachment(const GLenum slotEnum) { 318 auto ret = MaybeFind(mAttachments, slotEnum); 319 if (!ret) { 320 EnsureColorAttachments(); 321 ret = MaybeFind(mAttachments, slotEnum); 322 } 323 return ret; 324 } 325 326 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 327 }; 328 329 // - 330 331 class WebGLProgramJS final : public nsWrapperCache, public webgl::ObjectJS { 332 friend class ClientWebGLContext; 333 334 public: 335 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgramJS) 336 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLProgramJS) 337 // Must come first! 338 // If the REFCOUNTING macro isn't declared first, the AddRef at 339 // mInnerRef->js will panic when REFCOUNTING's "owning thread" var is still 340 // uninitialized. 341 342 struct Attachment final { 343 RefPtr<WebGLShaderJS> shader; 344 std::shared_ptr<webgl::ShaderKeepAlive> keepAlive; 345 }; 346 347 private: 348 std::shared_ptr<webgl::ProgramKeepAlive> mKeepAlive; 349 const std::weak_ptr<webgl::ProgramKeepAlive> mKeepAliveWeak; 350 351 std::unordered_map<GLenum, Attachment> mNextLink_Shaders; 352 bool mLastValidate = false; 353 mutable std::shared_ptr<webgl::LinkResult> 354 mResult; // Never null, often defaulted. 355 356 struct UniformLocInfo final { 357 const uint32_t location; 358 const GLenum elemType; 359 }; 360 361 mutable Maybe<std::unordered_map<std::string, UniformLocInfo>> 362 mUniformLocByName; 363 mutable std::vector<uint32_t> mUniformBlockBindings; 364 365 std::unordered_set<const WebGLTransformFeedbackJS*> mActiveTfos; 366 367 explicit WebGLProgramJS(const ClientWebGLContext&); 368 369 ~WebGLProgramJS() { 370 mKeepAlive = nullptr; // Try to delete. 371 372 const auto& maybe = mKeepAliveWeak.lock(); 373 if (maybe) { 374 maybe->mParent = nullptr; 375 } 376 } 377 378 public: 379 bool IsDeleted() const override { return !mKeepAliveWeak.lock(); } 380 GLenum ErrorOnDeleted() const override { return LOCAL_GL_INVALID_VALUE; } 381 382 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 383 }; 384 385 // - 386 387 class WebGLQueryJS final : public nsWrapperCache, 388 public webgl::ObjectJS, 389 public SupportsWeakPtr { 390 friend class ClientWebGLContext; 391 friend class webgl::AvailabilityRunnable; 392 393 GLenum mTarget = 0; // !IsQuery until Bind 394 bool mCanBeAvailable = false; 395 396 public: 397 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLQueryJS) 398 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLQueryJS) 399 400 explicit WebGLQueryJS(const ClientWebGLContext* const webgl) 401 : webgl::ObjectJS(webgl) {} 402 403 private: 404 ~WebGLQueryJS(); 405 406 public: 407 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 408 }; 409 410 // - 411 412 class WebGLRenderbufferJS final : public nsWrapperCache, 413 public webgl::ObjectJS { 414 friend class ClientWebGLContext; 415 416 public: 417 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbufferJS) 418 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLRenderbufferJS) 419 420 private: 421 bool mHasBeenBound = false; // !IsRenderbuffer until Bind 422 423 explicit WebGLRenderbufferJS(const ClientWebGLContext& webgl) 424 : webgl::ObjectJS(&webgl) {} 425 ~WebGLRenderbufferJS(); 426 427 public: 428 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 429 }; 430 431 // - 432 433 class WebGLSamplerJS final : public nsWrapperCache, public webgl::ObjectJS { 434 // IsSampler without Bind 435 public: 436 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSamplerJS) 437 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSamplerJS) 438 439 explicit WebGLSamplerJS(const ClientWebGLContext& webgl) 440 : webgl::ObjectJS(&webgl) {} 441 442 private: 443 ~WebGLSamplerJS(); 444 445 public: 446 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 447 }; 448 449 // - 450 451 class WebGLShaderJS final : public nsWrapperCache, public webgl::ObjectJS { 452 friend class ClientWebGLContext; 453 454 public: 455 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShaderJS) 456 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLShaderJS) 457 458 private: 459 const GLenum mType; 460 std::string mSource; 461 std::shared_ptr<webgl::ShaderKeepAlive> mKeepAlive; 462 const std::weak_ptr<webgl::ShaderKeepAlive> mKeepAliveWeak; 463 464 mutable webgl::CompileResult mResult; 465 466 WebGLShaderJS(const ClientWebGLContext&, GLenum type); 467 468 ~WebGLShaderJS() { 469 mKeepAlive = nullptr; // Try to delete. 470 471 const auto& maybe = mKeepAliveWeak.lock(); 472 if (maybe) { 473 maybe->mParent = nullptr; 474 } 475 } 476 477 public: 478 bool IsDeleted() const override { return !mKeepAliveWeak.lock(); } 479 GLenum ErrorOnDeleted() const override { return LOCAL_GL_INVALID_VALUE; } 480 481 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 482 }; 483 484 // - 485 486 class WebGLSyncJS final : public nsWrapperCache, 487 public webgl::ObjectJS, 488 public SupportsWeakPtr { 489 friend class ClientWebGLContext; 490 friend class webgl::AvailabilityRunnable; 491 492 bool mCanBeAvailable = false; 493 uint8_t mNumQueriesBeforeFirstFrameBoundary = 0; 494 uint8_t mNumQueriesWithoutFlushCommandsBit = 0; 495 496 public: 497 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSyncJS) 498 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLSyncJS) 499 500 explicit WebGLSyncJS(const ClientWebGLContext& webgl) 501 : webgl::ObjectJS(&webgl) {} 502 503 private: 504 ~WebGLSyncJS(); 505 506 public: 507 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 508 }; 509 510 // - 511 512 class WebGLTextureJS final : public nsWrapperCache, public webgl::ObjectJS { 513 friend class ClientWebGLContext; 514 515 GLenum mTarget = 0; // !IsTexture until Bind 516 517 public: 518 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTextureJS) 519 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTextureJS) 520 521 explicit WebGLTextureJS(const ClientWebGLContext& webgl) 522 : webgl::ObjectJS(&webgl) {} 523 524 private: 525 ~WebGLTextureJS(); 526 527 public: 528 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 529 }; 530 531 // - 532 533 class WebGLTransformFeedbackJS final : public nsWrapperCache, 534 public webgl::ObjectJS { 535 friend class ClientWebGLContext; 536 537 bool mHasBeenBound = false; // !IsTransformFeedback until Bind 538 bool mActiveOrPaused = false; 539 std::vector<RefPtr<WebGLBufferJS>> mAttribBuffers; 540 RefPtr<WebGLProgramJS> mActiveProgram; 541 std::shared_ptr<webgl::ProgramKeepAlive> mActiveProgramKeepAlive; 542 543 public: 544 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedbackJS) 545 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLTransformFeedbackJS) 546 547 explicit WebGLTransformFeedbackJS(const ClientWebGLContext&); 548 549 private: 550 ~WebGLTransformFeedbackJS(); 551 552 public: 553 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 554 }; 555 556 // - 557 558 std::array<uint16_t, 3> ValidUploadElemTypes(GLenum); 559 560 class WebGLUniformLocationJS final : public nsWrapperCache, 561 public webgl::ObjectJS { 562 friend class ClientWebGLContext; 563 564 const WeakPtr<webgl::LinkResult> mParent; 565 const uint32_t mLocation; 566 const std::array<uint16_t, 3> mValidUploadElemTypes; 567 568 public: 569 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocationJS) 570 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLUniformLocationJS) 571 572 WebGLUniformLocationJS(const ClientWebGLContext& webgl, 573 const WeakPtr<webgl::LinkResult>& parent, uint32_t loc, 574 GLenum elemType) 575 : webgl::ObjectJS(&webgl), 576 mParent(parent), 577 mLocation(loc), 578 mValidUploadElemTypes(ValidUploadElemTypes(elemType)) {} 579 580 private: 581 ~WebGLUniformLocationJS() = default; 582 583 public: 584 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 585 }; 586 587 // - 588 589 class WebGLVertexArrayJS final : public nsWrapperCache, public webgl::ObjectJS { 590 friend class ClientWebGLContext; 591 592 bool mHasBeenBound = false; // !IsVertexArray until Bind 593 RefPtr<WebGLBufferJS> mIndexBuffer; 594 std::vector<RefPtr<WebGLBufferJS>> mAttribBuffers; 595 596 public: 597 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArrayJS) 598 NS_DECL_CYCLE_COLLECTION_NATIVE_WRAPPERCACHE_CLASS(WebGLVertexArrayJS) 599 600 explicit WebGLVertexArrayJS(const ClientWebGLContext*); 601 602 private: 603 ~WebGLVertexArrayJS(); 604 605 public: 606 JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override; 607 }; 608 609 //////////////////////////////////// 610 611 using Float32ListU = dom::MaybeSharedFloat32ArrayOrUnrestrictedFloatSequence; 612 using Int32ListU = dom::MaybeSharedInt32ArrayOrLongSequence; 613 using Uint32ListU = dom::MaybeSharedUint32ArrayOrUnsignedLongSequence; 614 615 template <typename Converter, typename T> 616 inline bool ConvertSequence(const dom::Sequence<T>& sequence, 617 Converter&& converter) { 618 // It's ok to GC here, but we need a common parameter list for 619 // Converter with the typed array version. 620 JS::AutoCheckCannotGC nogc; 621 nogc.reset(); 622 return std::forward<Converter>(converter)(Span(sequence), std::move(nogc)); 623 } 624 625 template <typename Converter> 626 inline bool Convert(const Float32ListU& list, Converter&& converter) { 627 if (list.IsFloat32Array()) { 628 return list.GetAsFloat32Array().ProcessData( 629 std::forward<Converter>(converter)); 630 } 631 632 return ConvertSequence(list.GetAsUnrestrictedFloatSequence(), 633 std::forward<Converter>(converter)); 634 } 635 636 template <typename Converter> 637 inline bool Convert(const Int32ListU& list, Converter&& converter) { 638 if (list.IsInt32Array()) { 639 return list.GetAsInt32Array().ProcessData( 640 std::forward<Converter>(converter)); 641 } 642 643 return ConvertSequence(list.GetAsLongSequence(), 644 std::forward<Converter>(converter)); 645 } 646 647 template <typename Converter> 648 inline bool Convert(const Uint32ListU& list, Converter&& converter) { 649 if (list.IsUint32Array()) { 650 return list.GetAsUint32Array().ProcessData( 651 std::forward<Converter>(converter)); 652 } 653 654 return ConvertSequence(list.GetAsUnsignedLongSequence(), 655 std::forward<Converter>(converter)); 656 } 657 658 template <typename T> 659 inline Range<const uint8_t> MakeByteRange(const T& x) { 660 const auto typed = MakeRange(x); 661 return Range<const uint8_t>( 662 reinterpret_cast<const uint8_t*>(typed.begin().get()), 663 typed.length() * sizeof(typed[0])); 664 } 665 666 template <typename T> 667 inline Range<const uint8_t> MakeByteRange(const Span<T>& x) { 668 return AsBytes(x); 669 } 670 671 // - 672 673 struct TexImageSourceAdapter final : public TexImageSource { 674 TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView, 675 ErrorResult*) { 676 if (!maybeView->IsNull()) { 677 mView = &(maybeView->Value()); 678 } 679 } 680 681 TexImageSourceAdapter(const dom::Nullable<dom::ArrayBufferView>* maybeView, 682 GLuint viewElemOffset) { 683 if (!maybeView->IsNull()) { 684 mView = &(maybeView->Value()); 685 } 686 mViewElemOffset = viewElemOffset; 687 } 688 689 TexImageSourceAdapter(const dom::ArrayBufferView* view, ErrorResult*) { 690 mView = view; 691 } 692 693 TexImageSourceAdapter(const dom::ArrayBufferView* view, GLuint viewElemOffset, 694 GLuint viewElemLengthOverride = 0) { 695 mView = view; 696 mViewElemOffset = viewElemOffset; 697 mViewElemLengthOverride = viewElemLengthOverride; 698 } 699 700 explicit TexImageSourceAdapter(const WebGLintptr* pboOffset, 701 GLuint ignored1 = 0, GLuint ignored2 = 0) { 702 mPboOffset = pboOffset; 703 } 704 705 TexImageSourceAdapter(const WebGLintptr* pboOffset, ErrorResult* ignored) { 706 mPboOffset = pboOffset; 707 } 708 709 TexImageSourceAdapter(const dom::ImageBitmap* imageBitmap, 710 ErrorResult* out_error) { 711 mImageBitmap = imageBitmap; 712 mOut_error = out_error; 713 } 714 715 TexImageSourceAdapter(const dom::ImageData* imageData, ErrorResult*) { 716 mImageData = imageData; 717 } 718 719 TexImageSourceAdapter(const dom::OffscreenCanvas* offscreenCanvas, 720 ErrorResult* const out_error) { 721 mOffscreenCanvas = offscreenCanvas; 722 mOut_error = out_error; 723 } 724 725 TexImageSourceAdapter(const dom::VideoFrame* videoFrame, 726 ErrorResult* const out_error) { 727 mVideoFrame = videoFrame; 728 mOut_error = out_error; 729 } 730 731 TexImageSourceAdapter(const dom::Element* domElem, 732 ErrorResult* const out_error) { 733 mDomElem = domElem; 734 mOut_error = out_error; 735 } 736 }; 737 738 /** 739 * Base class for all IDL implementations of WebGLContext 740 */ 741 class ClientWebGLContext final : public nsICanvasRenderingContextInternal, 742 public nsWrapperCache { 743 friend class webgl::AvailabilityRunnable; 744 friend class webgl::ObjectJS; 745 friend class webgl::ProgramKeepAlive; 746 friend class webgl::ShaderKeepAlive; 747 748 // ----------------------------- Lifetime and DOM --------------------------- 749 public: 750 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 751 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ClientWebGLContext) 752 753 JSObject* WrapObject(JSContext* cx, 754 JS::Handle<JSObject*> givenProto) override { 755 if (mIsWebGL2) { 756 return dom::WebGL2RenderingContext_Binding::Wrap(cx, this, givenProto); 757 } 758 return dom::WebGLRenderingContext_Binding::Wrap(cx, this, givenProto); 759 } 760 761 // - 762 763 public: 764 const bool mIsWebGL2; 765 766 private: 767 bool mIsCanvasDirty = false; 768 uvec2 mRequestedSize = {}; 769 770 public: 771 explicit ClientWebGLContext(bool webgl2); 772 773 private: 774 virtual ~ClientWebGLContext(); 775 776 const RefPtr<ClientWebGLExtensionLoseContext> mExtLoseContext; 777 778 mutable RefPtr<webgl::NotLostData> mNotLost; 779 mutable GLenum mNextError = 0; 780 mutable webgl::LossStatus mLossStatus = webgl::LossStatus::Ready; 781 mutable bool mAwaitingRestore = false; 782 mutable webgl::ObjectId mLastId = 0; 783 784 public: 785 webgl::ObjectId NextId() const { return mLastId += 1; } 786 787 // Holds Some Id if async present is used 788 mutable Maybe<layers::RemoteTextureId> mLastRemoteTextureId; 789 mutable Maybe<layers::RemoteTextureOwnerId> mRemoteTextureOwnerId; 790 mutable RefPtr<layers::FwdTransactionTracker> mFwdTransactionTracker; 791 792 // - 793 794 public: 795 const auto& Limits() const { return mNotLost->info.limits; } 796 const auto& Vendor() const { return mNotLost->info.vendor; } 797 // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters 798 const WebGLContextOptions& ActualContextParameters() const { 799 MOZ_ASSERT(mNotLost != nullptr); 800 return mNotLost->info.options; 801 } 802 803 auto& State() { return mNotLost->state; } 804 const auto& State() const { 805 return const_cast<ClientWebGLContext*>(this)->State(); 806 } 807 808 // - 809 810 private: 811 mutable RefPtr<webgl::AvailabilityRunnable> mAvailabilityRunnable; 812 813 public: 814 webgl::AvailabilityRunnable& EnsureAvailabilityRunnable() const; 815 816 // - 817 818 public: 819 void EmulateLoseContext() const; 820 void OnContextLoss(webgl::ContextLossReason) const; 821 void RestoreContext(webgl::LossStatus requiredStatus) const; 822 823 private: 824 bool DispatchEvent(const nsAString&) const; 825 void Event_webglcontextlost() const; 826 void Event_webglcontextrestored() const; 827 828 bool CreateHostContext(const uvec2& requestedSize); 829 void ThrowEvent_WebGLContextCreationError(const std::string&) const; 830 831 void UpdateCanvasParameters(); 832 833 public: 834 void MarkCanvasDirty(); 835 836 void MarkContextClean() override {} 837 838 void OnBeforePaintTransaction() override; 839 840 mozilla::dom::WebGLChild* GetChild() const { 841 if (!mNotLost) return nullptr; 842 if (!mNotLost->outOfProcess) return nullptr; 843 return mNotLost->outOfProcess.get(); 844 } 845 846 // ------------------------------------------------------------------------- 847 // Client WebGL API call tracking and error message reporting 848 // ------------------------------------------------------------------------- 849 public: 850 // Remembers the WebGL function that is lowest on the stack for client-side 851 // error generation. 852 class FuncScope final { 853 public: 854 const ClientWebGLContext& mWebGL; 855 const RefPtr<webgl::NotLostData> mKeepNotLostOrNull; 856 const char* const mFuncName; 857 858 FuncScope(const ClientWebGLContext& webgl, const char* funcName) 859 : mWebGL(webgl), 860 mKeepNotLostOrNull(webgl.mNotLost), 861 mFuncName(funcName) { 862 // Only set if an "outer" scope hasn't already been set. 863 if (!mWebGL.mFuncScope) { 864 mWebGL.mFuncScope = this; 865 } 866 } 867 868 ~FuncScope() { 869 if (this == mWebGL.mFuncScope) { 870 mWebGL.mFuncScope = nullptr; 871 } 872 } 873 874 FuncScope(const FuncScope&) = delete; 875 FuncScope(FuncScope&&) = delete; 876 }; 877 878 protected: 879 // The scope of the function at the top of the current WebGL function call 880 // stack 881 mutable FuncScope* mFuncScope = nullptr; 882 883 const char* FuncName() const { 884 return mFuncScope ? mFuncScope->mFuncName : nullptr; 885 } 886 887 public: 888 template <typename... Args> 889 void EnqueueError(const GLenum error, const char* const format, 890 const Args&... args) const { 891 MOZ_ASSERT(FuncName()); 892 nsCString text; 893 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 # pragma GCC diagnostic ignored "-Wformat-overflow" 901 #endif 902 text.AppendPrintf("WebGL warning: %s: ", FuncName()); 903 text.AppendPrintf(format, args...); 904 #ifdef __clang__ 905 # pragma clang diagnostic pop 906 #elif defined(__GNUC__) 907 # pragma GCC diagnostic pop 908 #endif 909 910 EnqueueErrorImpl(error, text); 911 } 912 913 void EnqueueError(const webgl::ErrorInfo& info) const { 914 EnqueueError(info.type, "%s", info.info.c_str()); 915 } 916 917 template <typename... Args> 918 void EnqueueWarning(const char* const format, const Args&... args) const { 919 EnqueueError(0, format, args...); 920 } 921 922 template <typename... Args> 923 void EnqueuePerfWarning(const char* const format, const Args&... args) const { 924 EnqueueError(webgl::kErrorPerfWarning, format, args...); 925 } 926 927 void EnqueueError_ArgEnum(const char* argName, 928 GLenum val) const; // Cold code. 929 930 private: 931 void EnqueueErrorImpl(GLenum errorOrZero, const nsACString&) const; 932 933 public: 934 Maybe<Span<uint8_t>> ValidateArrayBufferView(const Span<uint8_t>& bytes, 935 size_t elemSize, 936 GLuint elemOffset, 937 GLuint elemCountOverride, 938 const GLenum errorEnum) const; 939 940 protected: 941 template <typename T> 942 bool ValidateNonNull(const char* const argName, 943 const dom::Nullable<T>& maybe) const { 944 if (maybe.IsNull()) { 945 EnqueueError(LOCAL_GL_INVALID_VALUE, "%s: Cannot be null.", argName); 946 return false; 947 } 948 return true; 949 } 950 951 bool ValidateNonNegative(const char* argName, int64_t val) const { 952 if (MOZ_UNLIKELY(val < 0)) { 953 EnqueueError(LOCAL_GL_INVALID_VALUE, "`%s` must be non-negative.", 954 argName); 955 return false; 956 } 957 return true; 958 } 959 960 bool ValidateViewType(GLenum unpackType, const TexImageSource& src) const; 961 962 Maybe<uvec3> ValidateExtents(GLsizei width, GLsizei height, GLsizei depth, 963 GLint border) const; 964 965 // ------------------------------------------------------------------------- 966 // nsICanvasRenderingContextInternal / nsAPostRefreshObserver 967 // ------------------------------------------------------------------------- 968 public: 969 bool InitializeCanvasRenderer(nsDisplayListBuilder* aBuilder, 970 layers::CanvasRenderer* aRenderer) override; 971 972 void MarkContextCleanForFrameCapture() override { 973 mFrameCaptureState = FrameCaptureState::CLEAN; 974 } 975 // Note that 'clean' here refers to its invalidation state, not the 976 // contents of the buffer. 977 Watchable<FrameCaptureState>* GetFrameCaptureState() override { 978 return &mFrameCaptureState; 979 } 980 981 void OnMemoryPressure() override; 982 void SetContextOptions(const WebGLContextOptions& aOptions) { 983 mInitialOptions.emplace(aOptions); 984 } 985 const WebGLContextOptions& GetContextOptions() const { 986 return mInitialOptions.ref(); 987 } 988 NS_IMETHOD 989 SetContextOptions(JSContext* cx, JS::Handle<JS::Value> options, 990 ErrorResult& aRvForDictionaryInit) override; 991 NS_IMETHOD 992 SetDimensions(int32_t width, int32_t height) override; 993 bool UpdateWebRenderCanvasData( 994 nsDisplayListBuilder* aBuilder, 995 layers::WebRenderCanvasData* aCanvasData) override; 996 997 // ------ 998 999 int32_t GetWidth() override { return AutoAssertCast(DrawingBufferSize().x); } 1000 int32_t GetHeight() override { return AutoAssertCast(DrawingBufferSize().y); } 1001 1002 NS_IMETHOD InitializeWithDrawTarget(nsIDocShell*, 1003 NotNull<gfx::DrawTarget*>) override { 1004 return NS_ERROR_NOT_IMPLEMENTED; 1005 } 1006 1007 void ResetBitmap() override; 1008 1009 UniquePtr<uint8_t[]> GetImageBuffer( 1010 mozilla::CanvasUtils::ImageExtraction aExtractionBehavior, 1011 int32_t* out_format, gfx::IntSize* out_imageSize) override; 1012 NS_IMETHOD GetInputStream( 1013 const char* mimeType, const nsAString& encoderOptions, 1014 mozilla::CanvasUtils::ImageExtraction extractionBehavior, 1015 const nsACString& randomizationKey, nsIInputStream** out_stream) override; 1016 1017 already_AddRefed<mozilla::gfx::SourceSurface> GetSurfaceSnapshot( 1018 gfxAlphaType* out_alphaType) override; 1019 1020 mozilla::ipc::IProtocol* SupportsSnapshotExternalCanvas() const override; 1021 1022 void SetOpaqueValueFromOpaqueAttr(bool) override {}; 1023 bool GetIsOpaque() override { return !mInitialOptions->alpha; } 1024 1025 /** 1026 * An abstract base class to be implemented by callers wanting to be notified 1027 * that a refresh has occurred. Callers must ensure an observer is removed 1028 * before it is destroyed. 1029 */ 1030 void DidRefresh() override; 1031 1032 NS_IMETHOD Redraw(const gfxRect&) override { 1033 return NS_ERROR_NOT_IMPLEMENTED; 1034 } 1035 1036 // ------ 1037 1038 protected: 1039 layers::LayersBackend GetCompositorBackendType() const; 1040 1041 Watchable<FrameCaptureState> mFrameCaptureState = { 1042 FrameCaptureState::CLEAN, "ClientWebGLContext::mFrameCaptureState"}; 1043 1044 // ------------------------------------------------------------------------- 1045 // WebGLRenderingContext Basic Properties and Methods 1046 // ------------------------------------------------------------------------- 1047 public: 1048 dom::HTMLCanvasElement* GetCanvas() const { return mCanvasElement; } 1049 void Commit(); 1050 void GetCanvas( 1051 dom::Nullable<dom::OwningHTMLCanvasElementOrOffscreenCanvas>& retval); 1052 1053 GLsizei DrawingBufferWidth() { 1054 const FuncScope funcScope(*this, "drawingBufferWidth"); 1055 return AutoAssertCast(DrawingBufferSize().x); 1056 } 1057 GLsizei DrawingBufferHeight() { 1058 const FuncScope funcScope(*this, "drawingBufferHeight"); 1059 return AutoAssertCast(DrawingBufferSize().y); 1060 } 1061 1062 // - 1063 1064 private: 1065 std::optional<dom::PredefinedColorSpace> mDrawingBufferColorSpace; 1066 std::optional<dom::PredefinedColorSpace> mUnpackColorSpace; 1067 1068 public: 1069 auto DrawingBufferColorSpace() const { 1070 return mDrawingBufferColorSpace ? *mDrawingBufferColorSpace 1071 : dom::PredefinedColorSpace::Srgb; 1072 } 1073 void SetDrawingBufferColorSpace(dom::PredefinedColorSpace); 1074 1075 auto UnpackColorSpace() const { 1076 return mUnpackColorSpace ? *mUnpackColorSpace 1077 : dom::PredefinedColorSpace::Srgb; 1078 } 1079 void SetUnpackColorSpace(dom::PredefinedColorSpace); 1080 1081 // - 1082 1083 void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval); 1084 1085 private: 1086 webgl::SwapChainOptions PrepareAsyncSwapChainOptions( 1087 WebGLFramebufferJS* fb, bool webvr, 1088 const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); 1089 1090 public: 1091 layers::TextureType GetTexTypeForSwapChain() const; 1092 void Present( 1093 WebGLFramebufferJS*, const bool webvr = false, 1094 const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); 1095 void Present( 1096 WebGLFramebufferJS*, layers::TextureType, const bool webvr = false, 1097 const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); 1098 void CopyToSwapChain( 1099 WebGLFramebufferJS*, 1100 const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); 1101 void EndOfFrame(); 1102 Maybe<layers::SurfaceDescriptor> GetFrontBuffer( 1103 WebGLFramebufferJS*, const bool webvr = false) override; 1104 Maybe<layers::SurfaceDescriptor> PresentFrontBuffer( 1105 WebGLFramebufferJS*, const bool webvr = false) override; 1106 RefPtr<gfx::SourceSurface> GetFrontBufferSnapshot( 1107 bool requireAlphaPremult = true) override; 1108 already_AddRefed<layers::FwdTransactionTracker> UseCompositableForwarder( 1109 layers::CompositableForwarder* aForwarder) override; 1110 void OnDestroyChild(dom::WebGLChild* aChild); 1111 1112 void ClearVRSwapChain(); 1113 1114 private: 1115 RefPtr<gfx::DataSourceSurface> BackBufferSnapshot(); 1116 [[nodiscard]] bool DoReadPixels(const webgl::ReadPixelsDesc&, 1117 Span<uint8_t>) const; 1118 uvec2 DrawingBufferSize(); 1119 1120 // - 1121 1122 mutable bool mAutoFlushPending = false; 1123 1124 void AutoEnqueueFlush() const { 1125 if (MOZ_LIKELY(mAutoFlushPending)) return; 1126 mAutoFlushPending = true; 1127 1128 const auto DeferredFlush = [weak = 1129 WeakPtr<const ClientWebGLContext>(this)]() { 1130 const auto strong = RefPtr<const ClientWebGLContext>(weak); 1131 if (!strong) return; 1132 if (!strong->mAutoFlushPending) return; 1133 strong->mAutoFlushPending = false; 1134 1135 if (!StaticPrefs::webgl_auto_flush()) return; 1136 const bool flushGl = StaticPrefs::webgl_auto_flush_gl(); 1137 strong->Flush(flushGl); 1138 }; 1139 1140 already_AddRefed<mozilla::CancelableRunnable> runnable = 1141 NS_NewCancelableRunnableFunction("ClientWebGLContext::DeferredFlush", 1142 DeferredFlush); 1143 NS_DispatchToCurrentThread(std::move(runnable)); 1144 } 1145 1146 void CancelAutoFlush() const { mAutoFlushPending = false; } 1147 1148 // - 1149 1150 void AfterDrawCall() { 1151 if (!mNotLost) return; 1152 const auto& state = State(); 1153 if (!state.mBoundDrawFb) { 1154 MarkCanvasDirty(); 1155 } 1156 1157 AutoEnqueueFlush(); 1158 } 1159 1160 // ------------------------------------------------------------------------- 1161 // Client-side helper methods. Dispatch to a Host method. 1162 // ------------------------------------------------------------------------- 1163 1164 // ------------------------- GL State ------------------------- 1165 public: 1166 bool IsContextLost() const { return !mNotLost; } 1167 1168 void Disable(GLenum cap) const { SetEnabledI(cap, {}, false); } 1169 void Enable(GLenum cap) const { SetEnabledI(cap, {}, true); } 1170 void SetEnabledI(GLenum cap, Maybe<GLuint> i, bool val) const; 1171 1172 bool IsEnabled(GLenum cap) const; 1173 1174 private: 1175 Maybe<double> GetNumber(GLenum pname); 1176 Maybe<std::string> GetString(GLenum pname); 1177 1178 public: 1179 void GetParameter(JSContext* cx, GLenum pname, 1180 JS::MutableHandle<JS::Value> retval, ErrorResult& rv, 1181 bool debug = false); 1182 1183 void GetBufferParameter(JSContext* cx, GLenum target, GLenum pname, 1184 JS::MutableHandle<JS::Value> retval) const; 1185 1186 void GetFramebufferAttachmentParameter(JSContext* cx, GLenum target, 1187 GLenum attachment, GLenum pname, 1188 JS::MutableHandle<JS::Value> retval, 1189 ErrorResult& rv) const; 1190 1191 void GetRenderbufferParameter(JSContext* cx, GLenum target, GLenum pname, 1192 JS::MutableHandle<JS::Value> retval) const; 1193 1194 void GetIndexedParameter(JSContext* cx, GLenum target, GLuint index, 1195 JS::MutableHandle<JS::Value> retval, 1196 ErrorResult& rv) const; 1197 1198 already_AddRefed<WebGLShaderPrecisionFormatJS> GetShaderPrecisionFormat( 1199 GLenum shadertype, GLenum precisiontype); 1200 1201 void UseProgram(WebGLProgramJS*); 1202 void ValidateProgram(WebGLProgramJS&) const; 1203 1204 // - 1205 1206 already_AddRefed<WebGLBufferJS> CreateBuffer() const; 1207 already_AddRefed<WebGLFramebufferJS> CreateFramebuffer() const; 1208 already_AddRefed<WebGLFramebufferJS> CreateOpaqueFramebuffer( 1209 const webgl::OpaqueFramebufferOptions&) const; 1210 already_AddRefed<WebGLProgramJS> CreateProgram() const; 1211 already_AddRefed<WebGLQueryJS> CreateQuery() const; 1212 already_AddRefed<WebGLRenderbufferJS> CreateRenderbuffer() const; 1213 already_AddRefed<WebGLSamplerJS> CreateSampler() const; 1214 already_AddRefed<WebGLShaderJS> CreateShader(GLenum type) const; 1215 already_AddRefed<WebGLSyncJS> FenceSync(GLenum condition, 1216 GLbitfield flags) const; 1217 already_AddRefed<WebGLTextureJS> CreateTexture() const; 1218 already_AddRefed<WebGLTransformFeedbackJS> CreateTransformFeedback() const; 1219 already_AddRefed<WebGLVertexArrayJS> CreateVertexArray() const; 1220 1221 void DeleteBuffer(WebGLBufferJS*); 1222 void DeleteFramebuffer(WebGLFramebufferJS*, bool canDeleteOpaque = false); 1223 void DeleteProgram(WebGLProgramJS*) const; 1224 void DeleteQuery(WebGLQueryJS*); 1225 void DeleteRenderbuffer(WebGLRenderbufferJS*); 1226 void DeleteSampler(WebGLSamplerJS*); 1227 void DeleteShader(WebGLShaderJS*) const; 1228 void DeleteSync(WebGLSyncJS*) const; 1229 void DeleteTexture(WebGLTextureJS*); 1230 void DeleteTransformFeedback(WebGLTransformFeedbackJS*); 1231 void DeleteVertexArray(WebGLVertexArrayJS*); 1232 1233 private: 1234 void DoDeleteProgram(WebGLProgramJS&) const; 1235 void DoDeleteShader(const WebGLShaderJS&) const; 1236 1237 public: 1238 // - 1239 1240 bool IsBuffer(const WebGLBufferJS*) const; 1241 bool IsFramebuffer(const WebGLFramebufferJS*) const; 1242 bool IsProgram(const WebGLProgramJS*) const; 1243 bool IsQuery(const WebGLQueryJS*) const; 1244 bool IsRenderbuffer(const WebGLRenderbufferJS*) const; 1245 bool IsSampler(const WebGLSamplerJS*) const; 1246 bool IsShader(const WebGLShaderJS*) const; 1247 bool IsSync(const WebGLSyncJS*) const; 1248 bool IsTexture(const WebGLTextureJS*) const; 1249 bool IsTransformFeedback(const WebGLTransformFeedbackJS*) const; 1250 bool IsVertexArray(const WebGLVertexArrayJS*) const; 1251 1252 // - 1253 // WebGLProgramJS 1254 1255 private: 1256 const webgl::LinkResult& GetLinkResult(const WebGLProgramJS&) const; 1257 1258 public: 1259 void AttachShader(WebGLProgramJS&, WebGLShaderJS&) const; 1260 void BindAttribLocation(WebGLProgramJS&, GLuint location, 1261 const nsAString& name) const; 1262 void DetachShader(WebGLProgramJS&, const WebGLShaderJS&) const; 1263 void GetAttachedShaders( 1264 const WebGLProgramJS&, 1265 dom::Nullable<nsTArray<RefPtr<WebGLShaderJS>>>& retval) const; 1266 void LinkProgram(WebGLProgramJS&) const; 1267 void TransformFeedbackVaryings(WebGLProgramJS&, 1268 const dom::Sequence<nsString>& varyings, 1269 GLenum bufferMode) const; 1270 void UniformBlockBinding(WebGLProgramJS&, GLuint blockIndex, 1271 GLuint blockBinding) const; 1272 1273 // Link result reflection 1274 already_AddRefed<WebGLActiveInfoJS> GetActiveAttrib(const WebGLProgramJS&, 1275 GLuint index); 1276 already_AddRefed<WebGLActiveInfoJS> GetActiveUniform(const WebGLProgramJS&, 1277 GLuint index); 1278 void GetActiveUniformBlockName(const WebGLProgramJS&, 1279 GLuint uniformBlockIndex, 1280 nsAString& retval) const; 1281 void GetActiveUniformBlockParameter(JSContext* cx, const WebGLProgramJS&, 1282 GLuint uniformBlockIndex, GLenum pname, 1283 JS::MutableHandle<JS::Value> retval, 1284 ErrorResult& rv); 1285 void GetActiveUniforms(JSContext*, const WebGLProgramJS&, 1286 const dom::Sequence<GLuint>& uniformIndices, 1287 GLenum pname, 1288 JS::MutableHandle<JS::Value> retval) const; 1289 GLint GetAttribLocation(const WebGLProgramJS&, const nsAString& name) const; 1290 GLint GetFragDataLocation(const WebGLProgramJS&, const nsAString& name) const; 1291 void GetProgramInfoLog(const WebGLProgramJS& prog, nsAString& retval) const; 1292 void GetProgramParameter(JSContext*, const WebGLProgramJS&, GLenum pname, 1293 JS::MutableHandle<JS::Value> retval) const; 1294 already_AddRefed<WebGLActiveInfoJS> GetTransformFeedbackVarying( 1295 const WebGLProgramJS&, GLuint index); 1296 GLuint GetUniformBlockIndex(const WebGLProgramJS&, 1297 const nsAString& uniformBlockName) const; 1298 void GetUniformIndices(const WebGLProgramJS&, 1299 const dom::Sequence<nsString>& uniformNames, 1300 dom::Nullable<nsTArray<GLuint>>& retval) const; 1301 1302 // WebGLUniformLocationJS 1303 already_AddRefed<WebGLUniformLocationJS> GetUniformLocation( 1304 const WebGLProgramJS&, const nsAString& name) const; 1305 void GetUniform(JSContext*, const WebGLProgramJS&, 1306 const WebGLUniformLocationJS&, 1307 JS::MutableHandle<JS::Value> retval); 1308 1309 // - 1310 // WebGLShaderJS 1311 1312 private: 1313 const webgl::CompileResult& GetCompileResult(const WebGLShaderJS&) const; 1314 1315 public: 1316 void CompileShader(WebGLShaderJS&) const; 1317 void GetShaderInfoLog(const WebGLShaderJS&, nsAString& retval) const; 1318 void GetShaderParameter(JSContext*, const WebGLShaderJS&, GLenum pname, 1319 JS::MutableHandle<JS::Value> retval) const; 1320 void GetShaderSource(const WebGLShaderJS&, nsAString& retval) const; 1321 void GetTranslatedShaderSource(const WebGLShaderJS& shader, 1322 nsAString& retval) const; 1323 void ShaderSource(WebGLShaderJS&, const nsAString&) const; 1324 1325 // - 1326 1327 void BindFramebuffer(GLenum target, WebGLFramebufferJS*); 1328 1329 void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a); 1330 1331 // - 1332 1333 void BlendEquation(GLenum mode) { BlendEquationSeparate(mode, mode); } 1334 void BlendFunc(GLenum sfactor, GLenum dfactor) { 1335 BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); 1336 } 1337 1338 void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { 1339 BlendEquationSeparateI({}, modeRGB, modeAlpha); 1340 } 1341 void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, 1342 GLenum dstAlpha) { 1343 BlendFuncSeparateI({}, srcRGB, dstRGB, srcAlpha, dstAlpha); 1344 } 1345 1346 void BlendEquationSeparateI(Maybe<GLuint> buf, GLenum modeRGB, 1347 GLenum modeAlpha); 1348 void BlendFuncSeparateI(Maybe<GLuint> buf, GLenum srcRGB, GLenum dstRGB, 1349 GLenum srcAlpha, GLenum dstAlpha); 1350 1351 // - 1352 1353 GLenum CheckFramebufferStatus(GLenum target); 1354 1355 void Clear(GLbitfield mask); 1356 1357 // - 1358 1359 private: 1360 void ClearBufferTv(const GLenum buffer, const GLint drawBuffer, 1361 const webgl::AttribBaseType type, 1362 JS::AutoCheckCannotGC&& nogc, 1363 const Span<const uint8_t>& view, 1364 const GLuint srcElemOffset); 1365 1366 public: 1367 void ClearBufferfv(GLenum buffer, GLint drawBuffer, const Float32ListU& list, 1368 GLuint srcElemOffset) { 1369 const FuncScope funcScope(*this, "clearBufferfv"); 1370 if (!Convert(list, [&](const Span<const float>& aData, 1371 JS::AutoCheckCannotGC&& nogc) { 1372 ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Float, 1373 std::move(nogc), AsBytes(aData), srcElemOffset); 1374 return true; 1375 })) { 1376 EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small."); 1377 } 1378 } 1379 void ClearBufferiv(GLenum buffer, GLint drawBuffer, const Int32ListU& list, 1380 GLuint srcElemOffset) { 1381 const FuncScope funcScope(*this, "clearBufferiv"); 1382 if (!Convert(list, [&](const Span<const int32_t>& aData, 1383 JS::AutoCheckCannotGC&& nogc) { 1384 ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Int, 1385 std::move(nogc), AsBytes(aData), srcElemOffset); 1386 return true; 1387 })) { 1388 EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small."); 1389 } 1390 } 1391 void ClearBufferuiv(GLenum buffer, GLint drawBuffer, const Uint32ListU& list, 1392 GLuint srcElemOffset) { 1393 const FuncScope funcScope(*this, "clearBufferuiv"); 1394 if (!Convert(list, [&](const Span<const uint32_t>& aData, 1395 JS::AutoCheckCannotGC&& nogc) { 1396 ClearBufferTv(buffer, drawBuffer, webgl::AttribBaseType::Uint, 1397 std::move(nogc), AsBytes(aData), srcElemOffset); 1398 return true; 1399 })) { 1400 EnqueueError(LOCAL_GL_INVALID_VALUE, "`values` too small."); 1401 } 1402 } 1403 1404 // - 1405 1406 void ClearBufferfi(GLenum buffer, GLint drawBuffer, GLfloat depth, 1407 GLint stencil); 1408 1409 void ClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a); 1410 1411 void ClearDepth(GLclampf v); 1412 1413 void ClearStencil(GLint v); 1414 1415 void ColorMask(bool r, bool g, bool b, bool a) const { 1416 ColorMaskI({}, r, g, b, a); 1417 } 1418 void ColorMaskI(Maybe<GLuint> buf, bool r, bool g, bool b, bool a) const; 1419 1420 void CullFace(GLenum face); 1421 1422 void DepthFunc(GLenum func); 1423 1424 void DepthMask(WebGLboolean b); 1425 1426 void DepthRange(GLclampf zNear, GLclampf zFar); 1427 1428 void Flush(bool flushGl = true) const; 1429 1430 void SyncSnapshot() override { Flush(); } 1431 1432 void Finish(); 1433 1434 void FrontFace(GLenum mode); 1435 1436 GLenum GetError(); 1437 1438 void Hint(GLenum target, GLenum mode); 1439 1440 void LineWidth(GLfloat width); 1441 1442 void PixelStorei(GLenum pname, GLint param); 1443 1444 void PolygonOffset(GLfloat factor, GLfloat units); 1445 1446 void SampleCoverage(GLclampf value, WebGLboolean invert); 1447 1448 void Scissor(GLint x, GLint y, GLsizei width, GLsizei height); 1449 1450 // - 1451 1452 void StencilFunc(GLenum func, GLint ref, GLuint mask) { 1453 StencilFuncSeparate(LOCAL_GL_FRONT_AND_BACK, func, ref, mask); 1454 } 1455 void StencilMask(GLuint mask) { 1456 StencilMaskSeparate(LOCAL_GL_FRONT_AND_BACK, mask); 1457 } 1458 void StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass) { 1459 StencilOpSeparate(LOCAL_GL_FRONT_AND_BACK, sfail, dpfail, dppass); 1460 } 1461 1462 void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); 1463 void StencilMaskSeparate(GLenum face, GLuint mask); 1464 void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, 1465 GLenum dppass); 1466 1467 // - 1468 1469 void Viewport(GLint x, GLint y, GLsizei width, GLsizei height); 1470 1471 // ------------------------- Buffer Objects ------------------------- 1472 public: 1473 void BindBuffer(GLenum target, WebGLBufferJS*); 1474 1475 // - 1476 1477 private: 1478 void BindBufferRangeImpl(const GLenum target, const GLuint index, 1479 WebGLBufferJS* const buffer, const uint64_t offset, 1480 const uint64_t size); 1481 1482 public: 1483 void BindBufferBase(const GLenum target, const GLuint index, 1484 WebGLBufferJS* const buffer) { 1485 const FuncScope funcScope(*this, "bindBufferBase"); 1486 if (IsContextLost()) return; 1487 1488 BindBufferRangeImpl(target, index, buffer, 0, 0); 1489 } 1490 1491 void BindBufferRange(const GLenum target, const GLuint index, 1492 WebGLBufferJS* const buffer, const WebGLintptr offset, 1493 const WebGLsizeiptr size) { 1494 const FuncScope funcScope(*this, "bindBufferRange"); 1495 if (IsContextLost()) return; 1496 1497 if (buffer) { 1498 if (!ValidateNonNegative("offset", offset)) return; 1499 1500 if (size < 1) { 1501 EnqueueError(LOCAL_GL_INVALID_VALUE, 1502 "`size` must be positive for non-null `buffer`."); 1503 return; 1504 } 1505 } 1506 1507 BindBufferRangeImpl(target, index, buffer, static_cast<uint64_t>(offset), 1508 static_cast<uint64_t>(size)); 1509 } 1510 1511 // - 1512 1513 void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, 1514 GLintptr readOffset, GLintptr writeOffset, 1515 GLsizeiptr size); 1516 1517 void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage); 1518 void BufferData(GLenum target, 1519 const dom::Nullable<dom::ArrayBuffer>& maybeSrc, 1520 GLenum usage); 1521 void BufferData(GLenum target, const dom::ArrayBufferView& srcData, 1522 GLenum usage, GLuint srcElemOffset = 0, 1523 GLuint srcElemCountOverride = 0); 1524 1525 void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset, 1526 const dom::ArrayBufferView& src, GLuint srcElemOffset = 0, 1527 GLuint srcElemCountOverride = 0); 1528 void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset, 1529 const dom::ArrayBuffer& src); 1530 void BufferSubData(GLenum target, WebGLsizeiptr dstByteOffset, 1531 const dom::AllowSharedBufferSource& src); 1532 1533 void GetBufferSubData(GLenum target, GLintptr srcByteOffset, 1534 const dom::ArrayBufferView& dstData, 1535 GLuint dstElemOffset, GLuint dstElemCountOverride); 1536 1537 // -------------------------- Framebuffer Objects -------------------------- 1538 1539 void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, 1540 GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, 1541 GLbitfield mask, GLenum filter); 1542 1543 // - 1544 1545 private: 1546 // `bindTarget` if non-zero allows initializing the rb/tex with that target. 1547 void FramebufferAttach(GLenum target, GLenum attachEnum, GLenum bindTarget, 1548 WebGLRenderbufferJS*, WebGLTextureJS*, 1549 uint32_t mipLevel, uint32_t zLayer, 1550 uint32_t numViewLayers) const; 1551 1552 public: 1553 void FramebufferRenderbuffer(GLenum target, GLenum attachSlot, 1554 GLenum rbTarget, WebGLRenderbufferJS* rb) const { 1555 const FuncScope funcScope(*this, "framebufferRenderbuffer"); 1556 if (IsContextLost()) return; 1557 if (rbTarget != LOCAL_GL_RENDERBUFFER) { 1558 EnqueueError_ArgEnum("rbTarget", rbTarget); 1559 return; 1560 } 1561 FramebufferAttach(target, attachSlot, rbTarget, rb, nullptr, 0, 0, 0); 1562 } 1563 1564 void FramebufferTexture2D(GLenum target, GLenum attachSlot, 1565 GLenum texImageTarget, WebGLTextureJS*, 1566 GLint mipLevel) const; 1567 1568 void FramebufferTextureLayer(GLenum target, GLenum attachSlot, 1569 WebGLTextureJS* tex, GLint mipLevel, 1570 GLint zLayer) const { 1571 const FuncScope funcScope(*this, "framebufferTextureLayer"); 1572 if (IsContextLost()) return; 1573 FramebufferAttach(target, attachSlot, 0, nullptr, tex, 1574 static_cast<uint32_t>(mipLevel), 1575 static_cast<uint32_t>(zLayer), 0); 1576 } 1577 1578 void FramebufferTextureMultiview(GLenum target, GLenum attachSlot, 1579 WebGLTextureJS* tex, GLint mipLevel, 1580 GLint zLayerBase, 1581 GLsizei numViewLayers) const { 1582 const FuncScope funcScope(*this, "framebufferTextureMultiview"); 1583 if (IsContextLost()) return; 1584 if (tex && numViewLayers < 1) { 1585 EnqueueError(LOCAL_GL_INVALID_VALUE, "`numViewLayers` must be >=1."); 1586 return; 1587 } 1588 FramebufferAttach(target, attachSlot, 0, nullptr, tex, 1589 static_cast<uint32_t>(mipLevel), 1590 static_cast<uint32_t>(zLayerBase), 1591 static_cast<uint32_t>(numViewLayers)); 1592 } 1593 1594 // - 1595 1596 void InvalidateFramebuffer(GLenum target, 1597 const dom::Sequence<GLenum>& attachments, 1598 ErrorResult& unused); 1599 void InvalidateSubFramebuffer(GLenum target, 1600 const dom::Sequence<GLenum>& attachments, 1601 GLint x, GLint y, GLsizei width, GLsizei height, 1602 ErrorResult& unused); 1603 1604 void ReadBuffer(GLenum mode); 1605 1606 // ----------------------- Renderbuffer objects ----------------------- 1607 void GetInternalformatParameter(JSContext* cx, GLenum target, 1608 GLenum internalformat, GLenum pname, 1609 JS::MutableHandle<JS::Value> retval, 1610 ErrorResult& rv); 1611 1612 void BindRenderbuffer(GLenum target, WebGLRenderbufferJS*); 1613 1614 void RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, 1615 GLsizei height) const { 1616 RenderbufferStorageMultisample(target, 0, internalFormat, width, height); 1617 } 1618 1619 void RenderbufferStorageMultisample(GLenum target, GLsizei samples, 1620 GLenum internalFormat, GLsizei width, 1621 GLsizei height) const; 1622 1623 // --------------------------- Texture objects --------------------------- 1624 1625 void ActiveTexture(GLenum texUnit); 1626 1627 void BindTexture(GLenum texTarget, WebGLTextureJS*); 1628 1629 void GenerateMipmap(GLenum texTarget) const; 1630 1631 void GetTexParameter(JSContext* cx, GLenum texTarget, GLenum pname, 1632 JS::MutableHandle<JS::Value> retval) const; 1633 1634 void TexParameterf(GLenum texTarget, GLenum pname, GLfloat param); 1635 void TexParameteri(GLenum texTarget, GLenum pname, GLint param); 1636 1637 // - 1638 1639 private: 1640 void TexStorage(uint8_t funcDims, GLenum target, GLsizei levels, 1641 GLenum internalFormat, const ivec3& size) const; 1642 1643 // Primitive tex upload functions 1644 void TexImage(uint8_t funcDims, GLenum target, GLint level, 1645 GLenum respecFormat, const ivec3& offset, 1646 const Maybe<ivec3>& size, GLint border, 1647 const webgl::PackingInfo& pi, const TexImageSource& src) const; 1648 void CompressedTexImage(bool sub, uint8_t funcDims, GLenum target, 1649 GLint level, GLenum format, const ivec3& offset, 1650 const ivec3& size, GLint border, 1651 const TexImageSource& src, 1652 GLsizei pboImageSize) const; 1653 void CopyTexImage(uint8_t funcDims, GLenum target, GLint level, 1654 GLenum respecFormat, const ivec3& dstOffset, 1655 const ivec2& srcOffset, const ivec2& size, 1656 GLint border) const; 1657 1658 public: 1659 void TexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, 1660 GLsizei width, GLsizei height) const { 1661 TexStorage(2, target, levels, internalFormat, {width, height, 1}); 1662 } 1663 1664 void TexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, 1665 GLsizei width, GLsizei height, GLsizei depth) const { 1666 TexStorage(3, target, levels, internalFormat, {width, height, depth}); 1667 } 1668 1669 //////////////////////////////////// 1670 1671 template <typename T> // TexImageSource or WebGLintptr 1672 void TexImage2D(GLenum target, GLint level, GLenum internalFormat, 1673 GLsizei width, GLsizei height, GLint border, 1674 GLenum unpackFormat, GLenum unpackType, const T& anySrc, 1675 ErrorResult& out_error) const { 1676 const TexImageSourceAdapter src(&anySrc, &out_error); 1677 TexImage(2, target, level, internalFormat, {0, 0, 0}, 1678 Some(ivec3{width, height, 1}), border, {unpackFormat, unpackType}, 1679 src); 1680 } 1681 1682 void TexImage2D(GLenum target, GLint level, GLenum internalFormat, 1683 GLsizei width, GLsizei height, GLint border, 1684 GLenum unpackFormat, GLenum unpackType, 1685 const dom::ArrayBufferView& view, GLuint viewElemOffset, 1686 ErrorResult&) const { 1687 const TexImageSourceAdapter src(&view, viewElemOffset); 1688 TexImage(2, target, level, internalFormat, {0, 0, 0}, 1689 Some(ivec3{width, height, 1}), border, {unpackFormat, unpackType}, 1690 src); 1691 } 1692 1693 // - 1694 1695 template <typename T> // TexImageSource or WebGLintptr 1696 void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset, 1697 GLsizei width, GLsizei height, GLenum unpackFormat, 1698 GLenum unpackType, const T& anySrc, 1699 ErrorResult& out_error) const { 1700 const TexImageSourceAdapter src(&anySrc, &out_error); 1701 TexImage(2, target, level, 0, {xOffset, yOffset, 0}, 1702 Some(ivec3{width, height, 1}), 0, {unpackFormat, unpackType}, src); 1703 } 1704 1705 void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset, 1706 GLsizei width, GLsizei height, GLenum unpackFormat, 1707 GLenum unpackType, const dom::ArrayBufferView& view, 1708 GLuint viewElemOffset, ErrorResult&) const { 1709 const TexImageSourceAdapter src(&view, viewElemOffset); 1710 TexImage(2, target, level, 0, {xOffset, yOffset, 0}, 1711 Some(ivec3{width, height, 1}), 0, {unpackFormat, unpackType}, src); 1712 } 1713 1714 // - 1715 1716 template <typename T> // TexImageSource or WebGLintptr 1717 void TexImage3D(GLenum target, GLint level, GLenum internalFormat, 1718 GLsizei width, GLsizei height, GLsizei depth, GLint border, 1719 GLenum unpackFormat, GLenum unpackType, const T& anySrc, 1720 ErrorResult& out_error) const { 1721 const TexImageSourceAdapter src(&anySrc, &out_error); 1722 TexImage(3, target, level, internalFormat, {0, 0, 0}, 1723 Some(ivec3{width, height, depth}), border, 1724 {unpackFormat, unpackType}, src); 1725 } 1726 1727 void TexImage3D(GLenum target, GLint level, GLenum internalFormat, 1728 GLsizei width, GLsizei height, GLsizei depth, GLint border, 1729 GLenum unpackFormat, GLenum unpackType, 1730 const dom::ArrayBufferView& view, GLuint viewElemOffset, 1731 ErrorResult&) const { 1732 const TexImageSourceAdapter src(&view, viewElemOffset); 1733 TexImage(3, target, level, internalFormat, {0, 0, 0}, 1734 Some(ivec3{width, height, depth}), border, 1735 {unpackFormat, unpackType}, src); 1736 } 1737 1738 // - 1739 1740 template <typename T> // TexImageSource or WebGLintptr 1741 void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, 1742 GLint zOffset, GLsizei width, GLsizei height, 1743 GLsizei depth, GLenum unpackFormat, GLenum unpackType, 1744 const T& anySrc, ErrorResult& out_error) const { 1745 const TexImageSourceAdapter src(&anySrc, &out_error); 1746 TexImage(3, target, level, 0, {xOffset, yOffset, zOffset}, 1747 Some(ivec3{width, height, depth}), 0, {unpackFormat, unpackType}, 1748 src); 1749 } 1750 1751 void TexSubImage3D(GLenum target, GLint level, GLint xOffset, GLint yOffset, 1752 GLint zOffset, GLsizei width, GLsizei height, 1753 GLsizei depth, GLenum unpackFormat, GLenum unpackType, 1754 const dom::Nullable<dom::ArrayBufferView>& maybeSrcView, 1755 GLuint srcElemOffset, ErrorResult&) const { 1756 const TexImageSourceAdapter src(&maybeSrcView, srcElemOffset); 1757 TexImage(3, target, level, 0, {xOffset, yOffset, zOffset}, 1758 Some(ivec3{width, height, depth}), 0, {unpackFormat, unpackType}, 1759 src); 1760 } 1761 1762 //////////////////////////////////// 1763 1764 public: 1765 void CompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat, 1766 GLsizei width, GLsizei height, GLint border, 1767 GLsizei imageSize, WebGLintptr offset) const { 1768 const TexImageSourceAdapter src(&offset); 1769 CompressedTexImage(false, 2, target, level, internalFormat, {0, 0, 0}, 1770 {width, height, 1}, border, src, imageSize); 1771 } 1772 1773 void CompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat, 1774 GLsizei width, GLsizei height, GLint border, 1775 const dom::ArrayBufferView& view, 1776 GLuint viewElemOffset = 0, 1777 GLuint viewElemLengthOverride = 0) const { 1778 const TexImageSourceAdapter src(&view, viewElemOffset, 1779 viewElemLengthOverride); 1780 CompressedTexImage(false, 2, target, level, internalFormat, {0, 0, 0}, 1781 {width, height, 1}, border, src, 0); 1782 } 1783 1784 // - 1785 1786 void CompressedTexSubImage2D(GLenum target, GLint level, GLint xOffset, 1787 GLint yOffset, GLsizei width, GLsizei height, 1788 GLenum unpackFormat, GLsizei imageSize, 1789 WebGLintptr offset) const { 1790 const TexImageSourceAdapter src(&offset); 1791 CompressedTexImage(true, 2, target, level, unpackFormat, 1792 {xOffset, yOffset, 0}, {width, height, 1}, 0, src, 1793 imageSize); 1794 } 1795 1796 void CompressedTexSubImage2D(GLenum target, GLint level, GLint xOffset, 1797 GLint yOffset, GLsizei width, GLsizei height, 1798 GLenum unpackFormat, 1799 const dom::ArrayBufferView& view, 1800 GLuint viewElemOffset = 0, 1801 GLuint viewElemLengthOverride = 0) const { 1802 const TexImageSourceAdapter src(&view, viewElemOffset, 1803 viewElemLengthOverride); 1804 CompressedTexImage(true, 2, target, level, unpackFormat, 1805 {xOffset, yOffset, 0}, {width, height, 1}, 0, src, 0); 1806 } 1807 1808 // - 1809 1810 void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat, 1811 GLsizei width, GLsizei height, GLsizei depth, 1812 GLint border, GLsizei imageSize, 1813 WebGLintptr offset) const { 1814 const TexImageSourceAdapter src(&offset); 1815 CompressedTexImage(false, 3, target, level, internalFormat, {0, 0, 0}, 1816 {width, height, depth}, border, src, imageSize); 1817 } 1818 1819 void CompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat, 1820 GLsizei width, GLsizei height, GLsizei depth, 1821 GLint border, const dom::ArrayBufferView& view, 1822 GLuint viewElemOffset = 0, 1823 GLuint viewElemLengthOverride = 0) const { 1824 const TexImageSourceAdapter src(&view, viewElemOffset, 1825 viewElemLengthOverride); 1826 CompressedTexImage(false, 3, target, level, internalFormat, {0, 0, 0}, 1827 {width, height, depth}, border, src, 0); 1828 } 1829 1830 // - 1831 1832 void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, 1833 GLint yOffset, GLint zOffset, GLsizei width, 1834 GLsizei height, GLsizei depth, 1835 GLenum unpackFormat, GLsizei imageSize, 1836 WebGLintptr offset) const { 1837 const TexImageSourceAdapter src(&offset); 1838 CompressedTexImage(true, 3, target, level, unpackFormat, 1839 {xOffset, yOffset, zOffset}, {width, height, depth}, 0, 1840 src, imageSize); 1841 } 1842 1843 void CompressedTexSubImage3D(GLenum target, GLint level, GLint xOffset, 1844 GLint yOffset, GLint zOffset, GLsizei width, 1845 GLsizei height, GLsizei depth, 1846 GLenum unpackFormat, 1847 const dom::ArrayBufferView& view, 1848 GLuint viewElemOffset = 0, 1849 GLuint viewElemLengthOverride = 0) const { 1850 const TexImageSourceAdapter src(&view, viewElemOffset, 1851 viewElemLengthOverride); 1852 CompressedTexImage(true, 3, target, level, unpackFormat, 1853 {xOffset, yOffset, zOffset}, {width, height, depth}, 0, 1854 src, 0); 1855 } 1856 1857 // -------------------- 1858 1859 void CopyTexImage2D(GLenum target, GLint level, GLenum internalFormat, 1860 GLint x, GLint y, GLsizei width, GLsizei height, 1861 GLint border) const { 1862 CopyTexImage(2, target, level, internalFormat, {0, 0, 0}, {x, y}, 1863 {width, height}, border); 1864 } 1865 1866 void CopyTexSubImage2D(GLenum target, GLint level, GLint xOffset, 1867 GLint yOffset, GLint x, GLint y, GLsizei width, 1868 GLsizei height) const { 1869 CopyTexImage(2, target, level, 0, {xOffset, yOffset, 0}, {x, y}, 1870 {width, height}, 0); 1871 } 1872 1873 void CopyTexSubImage3D(GLenum target, GLint level, GLint xOffset, 1874 GLint yOffset, GLint zOffset, GLint x, GLint y, 1875 GLsizei width, GLsizei height) const { 1876 CopyTexImage(3, target, level, 0, {xOffset, yOffset, zOffset}, {x, y}, 1877 {width, height}, 0); 1878 } 1879 1880 // ------------------- 1881 // legacy TexImageSource uploads without width/height. 1882 // The width/height params are webgl2 only, and let you do subrect 1883 // selection with e.g. width < UNPACK_ROW_LENGTH. 1884 1885 template <typename TexImageSourceT> 1886 void TexImage2D(GLenum target, GLint level, GLenum internalFormat, 1887 GLenum unpackFormat, GLenum unpackType, 1888 const TexImageSourceT& anySrc, ErrorResult& out_error) const { 1889 const TexImageSourceAdapter src(&anySrc, &out_error); 1890 TexImage(2, target, level, internalFormat, {}, {}, 0, 1891 {unpackFormat, unpackType}, src); 1892 } 1893 1894 template <typename TexImageSourceT> 1895 void TexSubImage2D(GLenum target, GLint level, GLint xOffset, GLint yOffset, 1896 GLenum unpackFormat, GLenum unpackType, 1897 const TexImageSourceT& anySrc, 1898 ErrorResult& out_error) const { 1899 const TexImageSourceAdapter src(&anySrc, &out_error); 1900 TexImage(2, target, level, 0, {xOffset, yOffset, 0}, {}, 0, 1901 {unpackFormat, unpackType}, src); 1902 } 1903 1904 // ------------------------ Uniforms and attributes ------------------------ 1905 1906 private: 1907 Maybe<double> GetVertexAttribPriv(GLuint index, GLenum pname); 1908 1909 public: 1910 void GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, 1911 JS::MutableHandle<JS::Value> retval, ErrorResult& rv); 1912 1913 private: 1914 const webgl::LinkResult* GetActiveLinkResult() const { 1915 const auto& state = State(); 1916 if (state.mCurrentProgram) { 1917 (void)GetLinkResult(*state.mCurrentProgram); 1918 } 1919 return state.mActiveLinkResult.get(); 1920 } 1921 1922 // Used by callers that have a `nogc` token that ensures that no GC will 1923 // happen while `bytes` is alive. Internally, the nogc range will be ended 1924 // after `bytes` is used (either successfully but where the data are possibly 1925 // sent over IPC which has a tendency to GC, or unsuccesfully in which case 1926 // error handling can GC.) 1927 void UniformData(GLenum funcElemType, const WebGLUniformLocationJS* const loc, 1928 bool transpose, const Range<const uint8_t>& bytes, 1929 JS::AutoCheckCannotGC&& nogc, GLuint elemOffset = 0, 1930 GLuint elemCountOverride = 0) const; 1931 1932 // Used by callers that are not passing `bytes` that might be GC-controlled. 1933 // This will create an artificial and unnecessary nogc region that should 1934 // get optimized away to nothing. 1935 void UniformData(GLenum funcElemType, const WebGLUniformLocationJS* const loc, 1936 bool transpose, const Range<const uint8_t>& bytes, 1937 GLuint elemOffset = 0, GLuint elemCountOverride = 0) const { 1938 JS::AutoCheckCannotGC nogc; 1939 UniformData(funcElemType, loc, transpose, bytes, std::move(nogc), 1940 elemOffset, elemCountOverride); 1941 } 1942 1943 // - 1944 1945 template <typename T> 1946 Maybe<Range<T>> ValidateSubrange(const Range<T>& data, size_t elemOffset, 1947 size_t elemLengthOverride = 0) const { 1948 auto ret = data; 1949 if (elemOffset > ret.length()) { 1950 EnqueueError(LOCAL_GL_INVALID_VALUE, 1951 "`elemOffset` too large for `data`."); 1952 return {}; 1953 } 1954 ret = {ret.begin() + elemOffset, ret.end()}; 1955 if (elemLengthOverride) { 1956 if (elemLengthOverride > ret.length()) { 1957 EnqueueError( 1958 LOCAL_GL_INVALID_VALUE, 1959 "`elemLengthOverride` too large for `data` and `elemOffset`."); 1960 return {}; 1961 } 1962 ret = {ret.begin().get(), elemLengthOverride}; 1963 } 1964 return Some(ret); 1965 } 1966 1967 public: 1968 #define _(T, type_t, TYPE) \ 1969 void Uniform1##T(const WebGLUniformLocationJS* const loc, type_t x) const { \ 1970 const type_t arr[] = {x}; \ 1971 UniformData(TYPE, loc, false, MakeByteRange(arr)); \ 1972 } \ 1973 void Uniform2##T(const WebGLUniformLocationJS* const loc, type_t x, \ 1974 type_t y) const { \ 1975 const type_t arr[] = {x, y}; \ 1976 UniformData(TYPE##_VEC2, loc, false, MakeByteRange(arr)); \ 1977 } \ 1978 void Uniform3##T(const WebGLUniformLocationJS* const loc, type_t x, \ 1979 type_t y, type_t z) const { \ 1980 const type_t arr[] = {x, y, z}; \ 1981 UniformData(TYPE##_VEC3, loc, false, MakeByteRange(arr)); \ 1982 } \ 1983 void Uniform4##T(const WebGLUniformLocationJS* const loc, type_t x, \ 1984 type_t y, type_t z, type_t w) const { \ 1985 const type_t arr[] = {x, y, z, w}; \ 1986 UniformData(TYPE##_VEC4, loc, false, MakeByteRange(arr)); \ 1987 } 1988 1989 _(f, float, LOCAL_GL_FLOAT) 1990 _(i, int32_t, LOCAL_GL_INT) 1991 _(ui, uint32_t, LOCAL_GL_UNSIGNED_INT) 1992 1993 #undef _ 1994 1995 // - 1996 1997 #define _(NT, TypeListU, TYPE) \ 1998 void Uniform##NT##v(const WebGLUniformLocationJS* const loc, \ 1999 const TypeListU& list, GLuint elemOffset = 0, \ 2000 GLuint elemCountOverride = 0) const { \ 2001 Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&& nogc) { \ 2002 UniformData(TYPE, loc, false, MakeByteRange(aData), std::move(nogc), \ 2003 elemOffset, elemCountOverride); \ 2004 return true; \ 2005 }); \ 2006 } 2007 2008 _(1f, Float32ListU, LOCAL_GL_FLOAT) 2009 _(2f, Float32ListU, LOCAL_GL_FLOAT_VEC2) 2010 _(3f, Float32ListU, LOCAL_GL_FLOAT_VEC3) 2011 _(4f, Float32ListU, LOCAL_GL_FLOAT_VEC4) 2012 _(1i, Int32ListU, LOCAL_GL_INT) 2013 _(2i, Int32ListU, LOCAL_GL_INT_VEC2) 2014 _(3i, Int32ListU, LOCAL_GL_INT_VEC3) 2015 _(4i, Int32ListU, LOCAL_GL_INT_VEC4) 2016 _(1ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT) 2017 _(2ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC2) 2018 _(3ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC3) 2019 _(4ui, Uint32ListU, LOCAL_GL_UNSIGNED_INT_VEC4) 2020 2021 #undef _ 2022 2023 // - 2024 2025 #define _(X) \ 2026 void UniformMatrix##X##fv(const WebGLUniformLocationJS* loc, bool transpose, \ 2027 const Float32ListU& list, GLuint elemOffset = 0, \ 2028 GLuint elemCountOverride = 0) const { \ 2029 Convert(list, [&](const Span<const float>& aData, \ 2030 JS::AutoCheckCannotGC&& nogc) { \ 2031 UniformData(LOCAL_GL_FLOAT_MAT##X, loc, transpose, MakeByteRange(aData), \ 2032 std::move(nogc), elemOffset, elemCountOverride); \ 2033 return true; \ 2034 }); \ 2035 } 2036 2037 _(2) 2038 _(2x3) 2039 _(2x4) 2040 2041 _(3x2) 2042 _(3) 2043 _(3x4) 2044 2045 _(4x2) 2046 _(4x3) 2047 _(4) 2048 2049 #undef _ 2050 2051 // - 2052 2053 void EnableVertexAttribArray(GLuint index); 2054 2055 void DisableVertexAttribArray(GLuint index); 2056 2057 WebGLsizeiptr GetVertexAttribOffset(GLuint index, GLenum pname); 2058 2059 // - 2060 2061 private: 2062 void VertexAttrib4Tv(GLuint index, webgl::AttribBaseType, 2063 const Range<const uint8_t>&); 2064 2065 public: 2066 void VertexAttrib1f(GLuint index, GLfloat x) { 2067 VertexAttrib4f(index, x, 0, 0, 1); 2068 } 2069 void VertexAttrib2f(GLuint index, GLfloat x, GLfloat y) { 2070 VertexAttrib4f(index, x, y, 0, 1); 2071 } 2072 void VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) { 2073 VertexAttrib4f(index, x, y, z, 1); 2074 } 2075 2076 void VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, 2077 GLfloat w) { 2078 const float arr[4] = {x, y, z, w}; 2079 VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr)); 2080 } 2081 2082 // - 2083 2084 template <typename List, typename T, size_t N> 2085 bool MakeArrayFromList(const List& list, T (&array)[N]) { 2086 bool badLength = false; 2087 if (!Convert(list, [&](const auto& aData, JS::AutoCheckCannotGC&&) { 2088 static_assert( 2089 std::is_same_v<std::remove_const_t< 2090 std::remove_reference_t<decltype(aData[0])>>, 2091 T>); 2092 if (N > aData.Length()) { 2093 badLength = true; 2094 return false; 2095 } 2096 2097 std::copy_n(aData.begin(), N, array); 2098 return true; 2099 })) { 2100 EnqueueError( 2101 LOCAL_GL_INVALID_VALUE, 2102 badLength 2103 ? nsPrintfCString("Length of `list` must be >=%zu.", N).get() 2104 : "Conversion of `list` failed."); 2105 return false; 2106 } 2107 return true; 2108 } 2109 2110 void VertexAttrib1fv(const GLuint index, const Float32ListU& list) { 2111 const FuncScope funcScope(*this, "vertexAttrib1fv"); 2112 if (IsContextLost()) return; 2113 2114 float arr[1]; 2115 if (!MakeArrayFromList(list, arr)) { 2116 return; 2117 } 2118 VertexAttrib1f(index, arr[0]); 2119 } 2120 2121 void VertexAttrib2fv(const GLuint index, const Float32ListU& list) { 2122 const FuncScope funcScope(*this, "vertexAttrib1fv"); 2123 if (IsContextLost()) return; 2124 2125 float arr[2]; 2126 if (!MakeArrayFromList(list, arr)) { 2127 return; 2128 } 2129 VertexAttrib2f(index, arr[0], arr[1]); 2130 } 2131 2132 void VertexAttrib3fv(const GLuint index, const Float32ListU& list) { 2133 const FuncScope funcScope(*this, "vertexAttrib1fv"); 2134 if (IsContextLost()) return; 2135 2136 float arr[3]; 2137 if (!MakeArrayFromList(list, arr)) { 2138 return; 2139 } 2140 VertexAttrib3f(index, arr[0], arr[1], arr[2]); 2141 } 2142 2143 void VertexAttrib4fv(GLuint index, const Float32ListU& list) { 2144 const FuncScope funcScope(*this, "vertexAttrib4fv"); 2145 float arr[4]; 2146 if (!MakeArrayFromList(list, arr)) { 2147 return; 2148 } 2149 VertexAttrib4Tv(index, webgl::AttribBaseType::Float, MakeByteRange(arr)); 2150 } 2151 void VertexAttribI4iv(GLuint index, const Int32ListU& list) { 2152 const FuncScope funcScope(*this, "vertexAttribI4iv"); 2153 int32_t arr[4]; 2154 if (!MakeArrayFromList(list, arr)) { 2155 return; 2156 } 2157 VertexAttrib4Tv(index, webgl::AttribBaseType::Int, MakeByteRange(arr)); 2158 } 2159 void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) { 2160 const FuncScope funcScope(*this, "vertexAttribI4uiv"); 2161 uint32_t arr[4]; 2162 if (!MakeArrayFromList(list, arr)) { 2163 return; 2164 } 2165 VertexAttrib4Tv(index, webgl::AttribBaseType::Uint, MakeByteRange(arr)); 2166 } 2167 2168 void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w) { 2169 const int32_t arr[4] = {x, y, z, w}; 2170 VertexAttrib4Tv(index, webgl::AttribBaseType::Int, MakeByteRange(arr)); 2171 } 2172 void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w) { 2173 const uint32_t arr[4] = {x, y, z, w}; 2174 VertexAttrib4Tv(index, webgl::AttribBaseType::Uint, MakeByteRange(arr)); 2175 } 2176 2177 private: 2178 void VertexAttribPointerImpl(bool isFuncInt, GLuint index, GLint size, 2179 GLenum type, WebGLboolean normalized, 2180 GLsizei iStride, WebGLintptr iByteOffset); 2181 2182 public: 2183 void VertexAttribIPointer(GLuint index, GLint size, GLenum type, 2184 GLsizei stride, WebGLintptr byteOffset) { 2185 VertexAttribPointerImpl(true, index, size, type, false, stride, byteOffset); 2186 } 2187 2188 void VertexAttribPointer(GLuint index, GLint size, GLenum type, 2189 WebGLboolean normalized, GLsizei stride, 2190 WebGLintptr byteOffset) { 2191 VertexAttribPointerImpl(false, index, size, type, normalized, stride, 2192 byteOffset); 2193 } 2194 2195 // -------------------------------- Drawing ------------------------------- 2196 public: 2197 void DrawArrays(GLenum mode, GLint first, GLsizei count) { 2198 DrawArraysInstanced(mode, first, count, 1); 2199 } 2200 2201 void DrawElements(GLenum mode, GLsizei count, GLenum type, 2202 WebGLintptr byteOffset) { 2203 DrawElementsInstanced(mode, count, type, byteOffset, 1); 2204 } 2205 2206 void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, 2207 GLenum type, WebGLintptr byteOffset) { 2208 const FuncScope funcScope(*this, "drawRangeElements"); 2209 if (end < start) { 2210 EnqueueError(LOCAL_GL_INVALID_VALUE, "end must be >= start."); 2211 return; 2212 } 2213 DrawElementsInstanced(mode, count, type, byteOffset, 1); 2214 } 2215 2216 // ------------------------------ Readback ------------------------------- 2217 public: 2218 void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, 2219 GLenum format, GLenum type, 2220 const dom::Nullable<dom::ArrayBufferView>& maybeView, 2221 dom::CallerType aCallerType, ErrorResult& out_error) const { 2222 const FuncScope funcScope(*this, "readPixels"); 2223 if (!ValidateNonNull("pixels", maybeView)) return; 2224 ReadPixels(x, y, width, height, format, type, maybeView.Value(), 0, 2225 aCallerType, out_error); 2226 } 2227 2228 void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, 2229 GLenum format, GLenum type, WebGLsizeiptr offset, 2230 dom::CallerType aCallerType, ErrorResult& out_error) const; 2231 2232 void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, 2233 GLenum format, GLenum type, 2234 const dom::ArrayBufferView& dstData, GLuint dstElemOffset, 2235 dom::CallerType aCallerType, ErrorResult& out_error) const; 2236 2237 protected: 2238 bool ReadPixels_SharedPrecheck(GLenum* inout_readType, 2239 dom::CallerType aCallerType, 2240 ErrorResult& out_error) const; 2241 2242 // ------------------------------ Vertex Array ------------------------------ 2243 public: 2244 void BindVertexArray(WebGLVertexArrayJS*); 2245 2246 void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, 2247 GLsizei primcount); 2248 2249 void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, 2250 WebGLintptr offset, GLsizei primcount); 2251 2252 void VertexAttribDivisor(GLuint index, GLuint divisor); 2253 2254 // --------------------------------- GL Query 2255 // --------------------------------- 2256 public: 2257 void GetQuery(JSContext*, GLenum target, GLenum pname, 2258 JS::MutableHandle<JS::Value> retval) const; 2259 void GetQueryParameter(JSContext*, WebGLQueryJS&, GLenum pname, 2260 JS::MutableHandle<JS::Value> retval) const; 2261 void BeginQuery(GLenum target, WebGLQueryJS&); 2262 void EndQuery(GLenum target); 2263 void QueryCounter(WebGLQueryJS&, GLenum target) const; 2264 2265 // -------------------------------- Sampler ------------------------------- 2266 2267 void GetSamplerParameter(JSContext*, const WebGLSamplerJS&, GLenum pname, 2268 JS::MutableHandle<JS::Value> retval) const; 2269 2270 void BindSampler(GLuint unit, WebGLSamplerJS*); 2271 void SamplerParameteri(WebGLSamplerJS&, GLenum pname, GLint param) const; 2272 void SamplerParameterf(WebGLSamplerJS&, GLenum pname, GLfloat param) const; 2273 2274 // ------------------------------- GL Sync --------------------------------- 2275 2276 GLenum ClientWaitSync(WebGLSyncJS&, GLbitfield flags, GLuint64 timeout) const; 2277 void GetSyncParameter(JSContext*, WebGLSyncJS&, GLenum pname, 2278 JS::MutableHandle<JS::Value> retval) const; 2279 void WaitSync(const WebGLSyncJS&, GLbitfield flags, GLint64 timeout) const; 2280 2281 mutable webgl::ObjectId mCompletedSyncId = 0; 2282 void OnSyncComplete(webgl::ObjectId id) const { 2283 if (mCompletedSyncId < id) { 2284 mCompletedSyncId = id; 2285 } 2286 } 2287 2288 // -------------------------- Transform Feedback --------------------------- 2289 2290 void BindTransformFeedback(GLenum target, WebGLTransformFeedbackJS*); 2291 void BeginTransformFeedback(GLenum primitiveMode); 2292 void EndTransformFeedback(); 2293 void PauseTransformFeedback(); 2294 void ResumeTransformFeedback(); 2295 2296 // -------------------------- Opaque Framebuffers --------------------------- 2297 2298 void SetFramebufferIsInOpaqueRAF(WebGLFramebufferJS*, bool); 2299 2300 // ------------------------------ Extensions ------------------------------ 2301 public: 2302 void GetSupportedExtensions(dom::Nullable<nsTArray<nsString>>& retval, 2303 dom::CallerType callerType) const; 2304 2305 bool IsSupported(WebGLExtensionID, dom::CallerType callerType = 2306 dom::CallerType::NonSystem) const; 2307 2308 void GetExtension(JSContext* cx, const nsAString& name, 2309 JS::MutableHandle<JSObject*> retval, 2310 dom::CallerType callerType, ErrorResult& rv); 2311 2312 protected: 2313 bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext, 2314 const dom::CallerType callerType) const; 2315 2316 RefPtr<ClientWebGLExtensionBase> GetExtension(WebGLExtensionID ext, 2317 dom::CallerType callerType); 2318 void RequestExtension(WebGLExtensionID) const; 2319 2320 public: 2321 bool IsExtensionEnabled(const WebGLExtensionID id) const { 2322 return bool(mNotLost->extensions[UnderlyingValue(id)]); 2323 } 2324 2325 void AddCompressedFormat(GLenum); 2326 2327 // ---------------------------- Misc Extensions ---------------------------- 2328 public: 2329 void DrawBuffers(const dom::Sequence<GLenum>& buffers); 2330 2331 void GetSupportedProfilesASTC( 2332 dom::Nullable<nsTArray<nsString>>& retval) const; 2333 2334 void MOZDebugGetParameter(JSContext* cx, GLenum pname, 2335 JS::MutableHandle<JS::Value> retval, 2336 ErrorResult& rv) { 2337 GetParameter(cx, pname, retval, rv, true); 2338 } 2339 2340 void ProvokingVertex(GLenum rawMode) const; 2341 2342 // ------------------------------------------------------------------------- 2343 // Client-side methods. Calls in the Host are forwarded to the client. 2344 // ------------------------------------------------------------------------- 2345 public: 2346 void JsWarning(const std::string&) const; 2347 2348 // ------------------------------------------------------------------------- 2349 // The cross-process communication mechanism 2350 // ------------------------------------------------------------------------- 2351 protected: 2352 // If we are running WebGL in this process then call the HostWebGLContext 2353 // method directly. Otherwise, dispatch over IPC. 2354 template <typename MethodType, MethodType method, typename... CallerArgs> 2355 void Run(const CallerArgs&... args) const { 2356 const auto id = IdByMethod<MethodType, method>(); 2357 auto noNoGc = std::optional<JS::AutoCheckCannotGC>{}; 2358 Run_WithDestArgTypes_ConstnessHelper(std::move(noNoGc), method, id, 2359 args...); 2360 } 2361 2362 // Same as above for use when using potentially GC-controlled data. The scope 2363 // of `aNoGC` will be ended after the data is no longer needed. 2364 template <typename MethodType, MethodType method, typename... CallerArgs> 2365 void RunWithGCData(JS::AutoCheckCannotGC&& aNoGC, 2366 const CallerArgs&... aArgs) const { 2367 const auto id = IdByMethod<MethodType, method>(); 2368 auto noGc = std::optional<JS::AutoCheckCannotGC>{std::move(aNoGC)}; 2369 Run_WithDestArgTypes_ConstnessHelper(std::move(noGc), method, id, aArgs...); 2370 } 2371 2372 // Because we're trying to explicitly pull `DestArgs` via `method`, we have 2373 // one overload for mut-methods and one for const-methods. 2374 template <typename... DestArgs> 2375 void Run_WithDestArgTypes_ConstnessHelper( 2376 std::optional<JS::AutoCheckCannotGC>&& noGc, 2377 void (HostWebGLContext::*method)(DestArgs...), const size_t id, 2378 const std::remove_reference_t<std::remove_const_t<DestArgs>>&... args) 2379 const { 2380 Run_WithDestArgTypes(std::move(noGc), method, id, args...); 2381 } 2382 template <typename... DestArgs> 2383 void Run_WithDestArgTypes_ConstnessHelper( 2384 std::optional<JS::AutoCheckCannotGC>&& noGc, 2385 void (HostWebGLContext::*method)(DestArgs...) const, const size_t id, 2386 const std::remove_reference_t<std::remove_const_t<DestArgs>>&... args) 2387 const { 2388 Run_WithDestArgTypes(std::move(noGc), method, id, args...); 2389 } 2390 2391 template <typename MethodT, typename... DestArgs> 2392 void Run_WithDestArgTypes(std::optional<JS::AutoCheckCannotGC>&&, MethodT, 2393 const size_t id, const DestArgs&...) const; 2394 2395 // ------------------------------------------------------------------------- 2396 // Helpers for DOM operations, composition, actors, etc 2397 // ------------------------------------------------------------------------- 2398 2399 public: 2400 // https://immersive-web.github.io/webxr/#xr-compatible 2401 bool IsXRCompatible() const; 2402 already_AddRefed<dom::Promise> MakeXRCompatible(ErrorResult& aRv); 2403 2404 protected: 2405 uint32_t GetPrincipalHashValue() const; 2406 2407 // Prepare the context for capture before compositing 2408 void BeginComposition(); 2409 2410 // Clean up the context after captured for compositing 2411 void EndComposition(); 2412 2413 mozilla::dom::Document* GetOwnerDoc() const; 2414 2415 mutable bool mResetLayer = true; 2416 Maybe<const WebGLContextOptions> mInitialOptions; 2417 bool mXRCompatible = false; 2418 }; 2419 2420 // used by DOM bindings in conjunction with GetParentObject 2421 inline nsISupports* ToSupports(ClientWebGLContext* webgl) { 2422 return static_cast<nsICanvasRenderingContextInternal*>(webgl); 2423 } 2424 2425 const char* GetExtensionName(WebGLExtensionID); 2426 2427 // - 2428 2429 inline bool webgl::ObjectJS::IsForContext( 2430 const ClientWebGLContext& context) const { 2431 const auto& notLost = context.mNotLost; 2432 if (!notLost) return false; 2433 if (notLost != mGeneration) return false; 2434 return true; 2435 } 2436 2437 void AutoJsWarning(const std::string& utf8); 2438 2439 } // namespace mozilla 2440 2441 #endif // CLIENTWEBGLCONTEXT_H_