diff options
Diffstat (limited to 'dom/canvas/WebGLContext.h')
-rw-r--r-- | dom/canvas/WebGLContext.h | 1435 |
1 files changed, 1435 insertions, 0 deletions
diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h new file mode 100644 index 0000000000..12727c4969 --- /dev/null +++ b/dom/canvas/WebGLContext.h @@ -0,0 +1,1435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WEBGLCONTEXT_H_ +#define WEBGLCONTEXT_H_ + +#include <bitset> +#include <memory> +#include <stdarg.h> + +#include "GLContextTypes.h" +#include "GLDefs.h" +#include "GLScreenBuffer.h" +#include "js/ScalarType.h" // js::Scalar::Type +#include "mozilla/Attributes.h" +#include "mozilla/Atomics.h" +#include "mozilla/CheckedInt.h" +#include "mozilla/dom/ipc/IdType.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/dom/Nullable.h" +#include "mozilla/dom/TypedArray.h" +#include "mozilla/EnumeratedArray.h" +#include "mozilla/gfx/2D.h" +#include "mozilla/Mutex.h" +#include "mozilla/StaticMutex.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/WeakPtr.h" +#include "nsICanvasRenderingContextInternal.h" +#include "nsTArray.h" +#include "SurfaceTypes.h" +#include "ScopedGLHelpers.h" +#include "TexUnpackBlob.h" + +// Local +#include "CacheInvalidator.h" +#include "WebGLContextLossHandler.h" +#include "WebGLExtensions.h" +#include "WebGLObjectModel.h" +#include "WebGLStrongTypes.h" +#include "WebGLTypes.h" + +// Generated +#include "mozilla/dom/WebGLRenderingContextBinding.h" +#include "mozilla/dom/WebGL2RenderingContextBinding.h" + +#include <list> + +class nsIDocShell; + +// WebGL-only GLenums +// clang-format off +#define LOCAL_GL_BROWSER_DEFAULT_WEBGL 0x9244 +#define LOCAL_GL_CONTEXT_LOST_WEBGL 0x9242 +#define LOCAL_GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL 0x9247 +#define LOCAL_GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243 +#define LOCAL_GL_UNPACK_FLIP_Y_WEBGL 0x9240 +#define LOCAL_GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241 +// clang-format on + +namespace mozilla { +class HostWebGLContext; +class ScopedCopyTexImageSource; +class ScopedDrawCallWrapper; +class ScopedResolveTexturesForDraw; +class WebGLBuffer; +class WebGLExtensionBase; +class WebGLFramebuffer; +class WebGLProgram; +class WebGLQuery; +class WebGLRenderbuffer; +class WebGLSampler; +class WebGLShader; +class WebGLSync; +class WebGLTexture; +class WebGLTransformFeedback; +class WebGLVertexArray; + +namespace dom { +class Document; +class Element; +class ImageData; +class OwningHTMLCanvasElementOrOffscreenCanvas; +struct WebGLContextAttributes; +} // namespace dom + +namespace gfx { +class SourceSurface; +class VRLayerChild; +} // namespace gfx + +namespace gl { +class GLScreenBuffer; +class MozFramebuffer; +class SharedSurface; +class Texture; +} // namespace gl + +namespace layers { +class CompositableHost; +class RemoteTextureOwnerClient; +class SurfaceDescriptor; +} // namespace layers + +namespace webgl { +class AvailabilityRunnable; +struct CachedDrawFetchLimits; +struct FbAttachInfo; +struct FormatInfo; +class FormatUsageAuthority; +struct FormatUsageInfo; +struct ImageInfo; +struct LinkedProgramInfo; +struct SamplerUniformInfo; +struct SamplingState; +class ScopedPrepForResourceClear; +class ShaderValidator; +class TexUnpackBlob; +struct UniformInfo; +struct UniformBlockInfo; +struct VertAttribPointerDesc; +} // namespace webgl + +struct WebGLTexImageData { + TexImageTarget mTarget; + int32_t mRowLength; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mDepth; + gfxAlphaType mSrcAlphaType; +}; + +struct WebGLTexPboOffset { + TexImageTarget mTarget; + uint32_t mWidth; + uint32_t mHeight; + uint32_t mDepth; + WebGLsizeiptr mPboOffset; + bool mHasExpectedImageSize; + GLsizei mExpectedImageSize; +}; + +WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format); + +void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow); + +// From WebGLContextUtils +TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget); + +struct WebGLIntOrFloat { + const enum { Int, Float, Uint } mType; + + union { + GLint i; + GLfloat f; + GLuint u; + } mValue; + + explicit WebGLIntOrFloat(GLint i) : mType(Int) { mValue.i = i; } + explicit WebGLIntOrFloat(GLfloat f) : mType(Float) { mValue.f = f; } + + GLint AsInt() const { + return (mType == Int) ? mValue.i : NS_lroundf(mValue.f); + } + GLfloat AsFloat() const { + return (mType == Float) ? mValue.f : GLfloat(mValue.i); + } +}; + +//////////////////////////////////// + +namespace webgl { + +class AvailabilityRunnable final : public DiscardableRunnable { + public: + const WeakPtr<const ClientWebGLContext> mWebGL; + std::vector<WeakPtr<WebGLQueryJS>> mQueries; + std::vector<WeakPtr<WebGLSyncJS>> mSyncs; + + explicit AvailabilityRunnable(const ClientWebGLContext* webgl); + ~AvailabilityRunnable(); + + NS_IMETHOD Run() override; +}; + +} // namespace webgl + +//////////////////////////////////////////////////////////////////////////////// + +class WebGLContext : public VRefCounted, public SupportsWeakPtr { + friend class ScopedDrawCallWrapper; + friend class ScopedDrawWithTransformFeedback; + friend class ScopedFakeVertexAttrib0; + friend class ScopedFBRebinder; + friend class WebGL2Context; + friend class WebGLContextUserData; + friend class WebGLExtensionCompressedTextureASTC; + friend class WebGLExtensionCompressedTextureBPTC; + friend class WebGLExtensionCompressedTextureES3; + friend class WebGLExtensionCompressedTextureETC1; + friend class WebGLExtensionCompressedTexturePVRTC; + friend class WebGLExtensionCompressedTextureRGTC; + friend class WebGLExtensionCompressedTextureS3TC; + friend class WebGLExtensionCompressedTextureS3TC_SRGB; + friend class WebGLExtensionDepthTexture; + friend class WebGLExtensionDisjointTimerQuery; + friend class WebGLExtensionDrawBuffers; + friend class WebGLExtensionLoseContext; + friend class WebGLExtensionMOZDebug; + friend class WebGLExtensionVertexArray; + friend class WebGLMemoryTracker; + friend class webgl::AvailabilityRunnable; + friend struct webgl::LinkedProgramInfo; + friend struct webgl::SamplerUniformInfo; + friend class webgl::ScopedPrepForResourceClear; + friend struct webgl::UniformBlockInfo; + + friend const webgl::CachedDrawFetchLimits* ValidateDraw(WebGLContext*, GLenum, + uint32_t); + friend RefPtr<const webgl::LinkedProgramInfo> QueryProgramInfo( + WebGLProgram* prog, gl::GLContext* gl); + + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(WebGLContext, override) + + enum { + UNPACK_FLIP_Y_WEBGL = 0x9240, + UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241, + // We throw InvalidOperation in TexImage if we fail to use GPU fast-path + // for texture copy when it is set to true, only for debug purpose. + UNPACK_REQUIRE_FASTPATH = 0x10001, + CONTEXT_LOST_WEBGL = 0x9242, + UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243, + BROWSER_DEFAULT_WEBGL = 0x9244, + UNMASKED_VENDOR_WEBGL = 0x9245, + UNMASKED_RENDERER_WEBGL = 0x9246 + }; + + private: + class LruPosition final { + std::list<WebGLContext*>::iterator mItr; + + LruPosition(const LruPosition&) = delete; + LruPosition(LruPosition&&) = delete; + LruPosition& operator=(const LruPosition&) = delete; + LruPosition& operator=(LruPosition&&) = delete; + + public: + void AssignLocked(WebGLContext& aContext) MOZ_REQUIRES(sLruMutex); + void Reset(); + void ResetLocked() MOZ_REQUIRES(sLruMutex); + bool IsInsertedLocked() const MOZ_REQUIRES(sLruMutex); + + LruPosition(); + explicit LruPosition(WebGLContext&); + + ~LruPosition() { Reset(); } + }; + + mutable LruPosition mLruPosition MOZ_GUARDED_BY(sLruMutex); + + void BumpLruLocked() MOZ_REQUIRES(sLruMutex); + + public: + void BumpLru(); + void LoseLruContextIfLimitExceeded(); + + // - + + // We've had issues in the past with nulling `gl` without actually releasing + // all of our resources. This construction ensures that we are aware that we + // should only null `gl` in DestroyResourcesAndContext. + RefPtr<gl::GLContext> mGL_OnlyClearInDestroyResourcesAndContext; + + public: + // Grab a const reference so we can see changes, but can't make changes. + const decltype(mGL_OnlyClearInDestroyResourcesAndContext)& gl; + + public: + void CheckForInactivity(); + + protected: + const WeakPtr<HostWebGLContext> mHost; + const bool mResistFingerprinting; + WebGLContextOptions mOptions; + const uint32_t mPrincipalKey; + Maybe<webgl::Limits> mLimits; + const uint32_t mMaxVertIdsPerDraw = + StaticPrefs::webgl_max_vert_ids_per_draw(); + + bool mIsContextLost = false; + Atomic<bool> mPendingContextLoss = Atomic<bool>{false}; + webgl::ContextLossReason mPendingContextLossReason = + webgl::ContextLossReason::None; + const uint32_t mMaxPerfWarnings = StaticPrefs::webgl_perf_max_warnings(); + mutable uint64_t mNumPerfWarnings = 0; + const uint32_t mMaxAcceptableFBStatusInvals = + StaticPrefs::webgl_perf_max_acceptable_fb_status_invals(); + bool mWarnOnce_DepthTexCompareFilterable = true; + + uint64_t mNextFenceId = 1; + uint64_t mCompletedFenceId = 0; + + std::unique_ptr<gl::Texture> mIncompleteTexOverride; + + public: + class FuncScope; + + private: + mutable FuncScope* mFuncScope = nullptr; + + public: + static RefPtr<WebGLContext> Create(HostWebGLContext*, + const webgl::InitContextDesc&, + webgl::InitContextResult* out); + + private: + bool mIsRgb8Renderable = false; + void FinishInit(); + + protected: + WebGLContext(HostWebGLContext*, const webgl::InitContextDesc&); + virtual ~WebGLContext(); + + RefPtr<layers::CompositableHost> mCompositableHost; + + layers::LayersBackend mBackend = layers::LayersBackend::LAYERS_NONE; + + public: + void Resize(uvec2 size); + + void SetCompositableHost(RefPtr<layers::CompositableHost>& aCompositableHost); + + /** + * An abstract base class to be implemented by callers wanting to be notified + * that a refresh has occurred. Callers must ensure an observer is removed + * before it is destroyed. + */ + virtual void DidRefresh(); + + void OnMemoryPressure(); + + // - + + /* + + Here are the bind calls that are supposed to be fully-validated client side, + so that client's binding state doesn't diverge: + * AttachShader + * DetachShader + * BindFramebuffer + * FramebufferAttach + * BindBuffer + * BindBufferRange + * BindTexture + * UseProgram + * BindSampler + * BindTransformFeedback + * BindVertexArray + * BeginQuery + * EndQuery + * ActiveTexture + + */ + + const auto& CurFuncScope() const { return *mFuncScope; } + const char* FuncName() const; + + class FuncScope final { + public: + const WebGLContext& mWebGL; + const char* const mFuncName; + bool mBindFailureGuard = false; + + public: + FuncScope(const WebGLContext& webgl, const char* funcName); + ~FuncScope(); + }; + + void GenerateErrorImpl(const GLenum err, const nsACString& text) const { + GenerateErrorImpl(err, std::string(text.BeginReading())); + } + void GenerateErrorImpl(const GLenum err, const std::string& text) const; + + void GenerateError(const webgl::ErrorInfo& err) { + GenerateError(err.type, "%s", err.info.c_str()); + } + + template <typename... Args> + void GenerateError(const GLenum err, const char* const fmt, + const Args&... args) const { + MOZ_ASSERT(FuncName()); + + nsCString text; + text.AppendPrintf("WebGL warning: %s: ", FuncName()); + +#ifdef __clang__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wformat-security" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wformat-security" +#endif + text.AppendPrintf(fmt, args...); +#ifdef __clang__ +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#endif + + GenerateErrorImpl(err, text); + } + + template <typename... Args> + void ErrorInvalidEnum(const char* const fmt, const Args&... args) const { + GenerateError(LOCAL_GL_INVALID_ENUM, fmt, args...); + } + template <typename... Args> + void ErrorInvalidOperation(const char* const fmt, const Args&... args) const { + GenerateError(LOCAL_GL_INVALID_OPERATION, fmt, args...); + } + template <typename... Args> + void ErrorInvalidValue(const char* const fmt, const Args&... args) const { + GenerateError(LOCAL_GL_INVALID_VALUE, fmt, args...); + } + template <typename... Args> + void ErrorInvalidFramebufferOperation(const char* const fmt, + const Args&... args) const { + GenerateError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION, fmt, args...); + } + template <typename... Args> + void ErrorOutOfMemory(const char* const fmt, const Args&... args) const { + GenerateError(LOCAL_GL_OUT_OF_MEMORY, fmt, args...); + } + + template <typename... Args> + void ErrorImplementationBug(const char* const fmt, + const Args&... args) const { + const nsPrintfCString newFmt( + "Implementation bug, please file at %s! %s", + "https://bugzilla.mozilla.org/" + "enter_bug.cgi?product=Core&component=Canvas%3A+WebGL", + fmt); + GenerateError(LOCAL_GL_OUT_OF_MEMORY, newFmt.BeginReading(), args...); + MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug"); + NS_ERROR("WebGLContext::ErrorImplementationBug"); + } + + void ErrorInvalidEnumInfo(const char* info, GLenum enumValue) const; + void ErrorInvalidEnumArg(const char* argName, GLenum val) const; + + static const char* ErrorName(GLenum error); + + void JsWarning(const std::string& text) const; + + /** + * Return displayable name for GLenum. + * This version is like gl::GLenumToStr but with out the GL_ prefix to + * keep consistency with how errors are reported from WebGL. + * Returns hex formatted version of glenum if glenum is unknown. + */ + static void EnumName(GLenum val, nsCString* out_name); + + void DummyReadFramebufferOperation(); + + dom::ContentParentId GetContentId() const; + + WebGLTexture* GetActiveTex(const GLenum texTarget) const; + + gl::GLContext* GL() const { return gl; } + + bool IsPremultAlpha() const { return mOptions.premultipliedAlpha; } + + bool IsPreservingDrawingBuffer() const { + return mOptions.preserveDrawingBuffer; + } + + // Present to compositor + private: + bool PresentInto(gl::SwapChain& swapChain); + bool PresentIntoXR(gl::SwapChain& swapChain, const gl::MozFramebuffer& xrFb); + + public: + // Present swaps the front and back buffers of the swap chain for compositing. + // This assumes the framebuffer may directly alias with the back buffer, + // dependent on remoting state or other concerns. Framebuffer and swap chain + // surface formats are assumed to be similar to enable this aliasing. As such, + // the back buffer may be invalidated by this swap with the front buffer, + // unless overriden by explicitly setting the preserveDrawingBuffer option, + // which may incur a further copy to preserve the back buffer. + void Present( + WebGLFramebuffer*, layers::TextureType, const bool webvr, + const webgl::SwapChainOptions& options = webgl::SwapChainOptions()); + // CopyToSwapChain forces a copy from the supplied framebuffer into the back + // buffer before swapping the front and back buffers of the swap chain for + // compositing. The formats of the framebuffer and the swap chain buffers + // may differ subject to available format conversion options. Since this + // operation uses an explicit copy, it inherently preserves the framebuffer + // without need to set the preserveDrawingBuffer option. + bool CopyToSwapChain( + WebGLFramebuffer*, layers::TextureType, + const webgl::SwapChainOptions& options = webgl::SwapChainOptions(), + layers::RemoteTextureOwnerClient* ownerClient = nullptr); + // In use cases where a framebuffer is used as an offscreen framebuffer and + // does not need to be committed to the swap chain, it may still be useful + // for the implementation to delineate distinct frames, such as when sharing + // a single WebGLContext amongst many distinct users. EndOfFrame signals that + // frame rendering is complete so that any implementation side-effects such + // as resetting internal profile counters or resource queues may be handled + // appropriately. + void EndOfFrame(); + RefPtr<gfx::DataSourceSurface> GetFrontBufferSnapshot(); + Maybe<uvec2> FrontBufferSnapshotInto( + const Maybe<Range<uint8_t>> dest, + const Maybe<size_t> destStride = Nothing()); + Maybe<uvec2> FrontBufferSnapshotInto( + const std::shared_ptr<gl::SharedSurface>& front, + const Maybe<Range<uint8_t>> dest, + const Maybe<size_t> destStride = Nothing()); + Maybe<uvec2> SnapshotInto(GLuint srcFb, const gfx::IntSize& size, + const Range<uint8_t>& dest, + const Maybe<size_t> destStride = Nothing()); + gl::SwapChain* GetSwapChain(WebGLFramebuffer*, const bool webvr); + Maybe<layers::SurfaceDescriptor> GetFrontBuffer(WebGLFramebuffer*, + const bool webvr); + + void ClearVRSwapChain(); + + void RunContextLossTimer(); + void CheckForContextLoss(); + void HandlePendingContextLoss(); + + bool TryToRestoreContext(); + + void AssertCachedBindings() const; + void AssertCachedGlobalState() const; + + // WebIDL WebGLRenderingContext API + void Commit(); + + uvec2 DrawingBufferSize(); + + public: + void GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval); + + // This is the entrypoint. Don't test against it directly. + bool IsContextLost() const { + auto* self = const_cast<WebGLContext*>(this); + if (self->mPendingContextLoss.exchange(false)) { + self->HandlePendingContextLoss(); + } + return mIsContextLost; + } + + // - + + RefPtr<WebGLBuffer> CreateBuffer(); + RefPtr<WebGLFramebuffer> CreateFramebuffer(); + RefPtr<WebGLFramebuffer> CreateOpaqueFramebuffer( + const webgl::OpaqueFramebufferOptions& options); + RefPtr<WebGLProgram> CreateProgram(); + RefPtr<WebGLQuery> CreateQuery(); + RefPtr<WebGLRenderbuffer> CreateRenderbuffer(); + RefPtr<WebGLShader> CreateShader(GLenum type); + RefPtr<WebGLTexture> CreateTexture(); + RefPtr<WebGLVertexArray> CreateVertexArray(); + + // - + + void AttachShader(WebGLProgram& prog, WebGLShader& shader); + void BindAttribLocation(WebGLProgram& prog, GLuint location, + const std::string& name) const; + void BindFramebuffer(GLenum target, WebGLFramebuffer* fb); + void BindRenderbuffer(GLenum target, WebGLRenderbuffer* fb); + void BindVertexArray(WebGLVertexArray* vao); + void BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a); + void BlendEquationSeparate(Maybe<GLuint> i, GLenum modeRGB, GLenum modeAlpha); + void BlendFuncSeparate(Maybe<GLuint> i, GLenum srcRGB, GLenum dstRGB, + GLenum srcAlpha, GLenum dstAlpha); + GLenum CheckFramebufferStatus(GLenum target); + void Clear(GLbitfield mask); + void ClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a); + void ClearDepth(GLclampf v); + void ClearStencil(GLint v); + void ColorMask(Maybe<GLuint> i, uint8_t mask); + void CompileShader(WebGLShader& shader); + + private: + void CompileShaderANGLE(WebGLShader* shader); + void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource); + + public: + void CullFace(GLenum face); + void DepthFunc(GLenum func); + void DepthMask(WebGLboolean b); + void DepthRange(GLclampf zNear, GLclampf zFar); + void DetachShader(WebGLProgram& prog, const WebGLShader& shader); + void DrawBuffers(const std::vector<GLenum>& buffers); + void Flush(); + void Finish(); + + void FramebufferAttach(GLenum target, GLenum attachSlot, + GLenum bindImageTarget, + const webgl::FbAttachInfo& toAttach); + + void FrontFace(GLenum mode); + + Maybe<double> GetBufferParameter(GLenum target, GLenum pname); + webgl::CompileResult GetCompileResult(const WebGLShader&) const; + GLenum GetError(); + GLint GetFragDataLocation(const WebGLProgram&, const std::string& name) const; + + Maybe<double> GetFramebufferAttachmentParameter(WebGLFramebuffer*, + GLenum attachment, + GLenum pname) const; + + Maybe<double> GetRenderbufferParameter(const WebGLRenderbuffer&, + GLenum pname) const; + webgl::LinkResult GetLinkResult(const WebGLProgram&) const; + + Maybe<webgl::ShaderPrecisionFormat> GetShaderPrecisionFormat( + GLenum shadertype, GLenum precisiontype) const; + + webgl::GetUniformData GetUniform(const WebGLProgram&, uint32_t loc) const; + + void Hint(GLenum target, GLenum mode); + + void LineWidth(GLfloat width); + void LinkProgram(WebGLProgram& prog); + void PolygonOffset(GLfloat factor, GLfloat units); + void ProvokingVertex(webgl::ProvokingVertex) const; + + //// + + webgl::PackingInfo ValidImplementationColorReadPI( + const webgl::FormatUsageInfo* usage) const; + + protected: + webgl::ReadPixelsResult ReadPixelsImpl(const webgl::ReadPixelsDesc&, + uintptr_t dest, uint64_t availBytes); + bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, + const webgl::ReadPixelsDesc&, uintptr_t dest, + uint64_t dataLen, uint32_t rowStride); + + public: + void ReadPixelsPbo(const webgl::ReadPixelsDesc&, uint64_t offset); + webgl::ReadPixelsResult ReadPixelsInto(const webgl::ReadPixelsDesc&, + const Range<uint8_t>& dest); + + //// + + void RenderbufferStorageMultisample(WebGLRenderbuffer&, uint32_t samples, + GLenum internalformat, uint32_t width, + uint32_t height) const; + + public: + void SampleCoverage(GLclampf value, WebGLboolean invert); + void Scissor(GLint x, GLint y, GLsizei width, GLsizei height); + void ShaderSource(WebGLShader& shader, const std::string& source) const; + void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask); + void StencilMaskSeparate(GLenum face, GLuint mask); + void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, + GLenum dppass); + + ////////////////////////// + + void UniformData(uint32_t loc, bool transpose, + const Range<const webgl::UniformDataVal>& data) const; + + //////////////////////////////////// + + void UseProgram(WebGLProgram* prog); + + bool ValidateAttribArraySetter(uint32_t count, uint32_t arrayLength); + bool ValidateProgram(const WebGLProgram& prog) const; + void Viewport(GLint x, GLint y, GLsizei width, GLsizei height); + + // ----------------------------------------------------------------------------- + // Buffer Objects (WebGLContextBuffers.cpp) + void BindBuffer(GLenum target, WebGLBuffer* buffer); + void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf, + uint64_t offset, uint64_t size); + + void BufferData(GLenum target, uint64_t dataLen, const uint8_t* data, + GLenum usage) const; + void UninitializedBufferData_SizeOnly(GLenum target, uint64_t dataLen, + GLenum usage) const; + // The unsynchronized flag may allow for better performance when + // interleaving buffer updates with draw calls. However, care must + // be taken. This has similar semantics to glMapBufferRange's + // GL_MAP_UNSYNCHRONIZED_BIT: the results of any pending operations + // that reference the region of the buffer being updated are + // undefined. + void BufferSubData(GLenum target, uint64_t dstByteOffset, uint64_t srcDataLen, + const uint8_t* srcData, bool unsynchronized = false) const; + + protected: + // bound buffer state + RefPtr<WebGLBuffer> mBoundArrayBuffer; + RefPtr<WebGLBuffer> mBoundCopyReadBuffer; + RefPtr<WebGLBuffer> mBoundCopyWriteBuffer; + RefPtr<WebGLBuffer> mBoundPixelPackBuffer; + RefPtr<WebGLBuffer> mBoundPixelUnpackBuffer; + RefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer; + RefPtr<WebGLBuffer> mBoundUniformBuffer; + + std::vector<IndexedBufferBinding> mIndexedUniformBufferBindings; + + RefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target); + RefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target, + GLuint index); + + // - + + void GenErrorIllegalUse(GLenum useTarget, uint32_t useId, GLenum boundTarget, + uint32_t boundId) const; + + bool ValidateBufferForNonTf(const WebGLBuffer&, GLenum nonTfTarget, + uint32_t nonTfId) const; + + bool ValidateBufferForNonTf(const WebGLBuffer* const nonTfBuffer, + const GLenum nonTfTarget, + const uint32_t nonTfId = -1) const { + if (!nonTfBuffer) return true; + return ValidateBufferForNonTf(*nonTfBuffer, nonTfTarget, nonTfId); + } + + bool ValidateBuffersForTf(const WebGLTransformFeedback&, + const webgl::LinkedProgramInfo&) const; + bool ValidateBuffersForTf( + const std::vector<webgl::BufferAndIndex>& tfBuffers) const; + + // ----------------------------------------------------------------------------- + // Queries (WebGL2ContextQueries.cpp) + protected: + RefPtr<WebGLQuery> mQuerySlot_SamplesPassed; + RefPtr<WebGLQuery> mQuerySlot_TFPrimsWritten; + RefPtr<WebGLQuery> mQuerySlot_TimeElapsed; + + RefPtr<WebGLQuery>* ValidateQuerySlotByTarget(GLenum target); + + public: + void BeginQuery(GLenum target, WebGLQuery& query); + void EndQuery(GLenum target); + Maybe<double> GetQueryParameter(const WebGLQuery& query, GLenum pname) const; + void QueryCounter(WebGLQuery&) const; + + // ----------------------------------------------------------------------------- + // State and State Requests (WebGLContextState.cpp) + void SetEnabled(GLenum cap, Maybe<GLuint> i, bool enabled); + bool GetStencilBits(GLint* const out_stencilBits) const; + + virtual Maybe<double> GetParameter(GLenum pname); + Maybe<std::string> GetString(GLenum pname) const; + + bool IsEnabled(GLenum cap); + + private: + static StaticMutex sLruMutex; + static std::list<WebGLContext*> sLru MOZ_GUARDED_BY(sLruMutex); + + // State tracking slots + bool mDitherEnabled = true; + bool mRasterizerDiscardEnabled = false; + bool mScissorTestEnabled = false; + bool mDepthTestEnabled = false; + bool mStencilTestEnabled = false; + GLenum mGenerateMipmapHint = LOCAL_GL_DONT_CARE; + + struct ScissorRect final { + GLint x; + GLint y; + GLsizei w; + GLsizei h; + + void Apply(gl::GLContext&) const; + }; + ScissorRect mScissorRect = {}; + + bool ValidateCapabilityEnum(GLenum cap); + bool* GetStateTrackingSlot(GLenum cap, GLuint i); + + // Allocation debugging variables + mutable uint64_t mDataAllocGLCallCount = 0; + + void OnDataAllocCall() const { mDataAllocGLCallCount++; } + + uint64_t GetNumGLDataAllocCalls() const { return mDataAllocGLCallCount; } + + void OnEndOfFrame(); + + // ----------------------------------------------------------------------------- + // Texture funcions (WebGLContextTextures.cpp) + public: + void ActiveTexture(uint32_t texUnit); + void BindTexture(GLenum texTarget, WebGLTexture* tex); + void GenerateMipmap(GLenum texTarget); + + Maybe<double> GetTexParameter(const WebGLTexture&, GLenum pname) const; + void TexParameter_base(GLenum texTarget, GLenum pname, + const FloatOrInt& param); + + virtual bool IsTexParamValid(GLenum pname) const; + + //////////////////////////////////// + // Uploads + + // CompressedTexSubImage if `sub` + void CompressedTexImage(bool sub, GLenum imageTarget, uint32_t level, + GLenum format, uvec3 offset, uvec3 size, + const Range<const uint8_t>& src, + const uint32_t pboImageSize, + const Maybe<uint64_t>& pboOffset) const; + + // CopyTexSubImage if `!respectFormat` + void CopyTexImage(GLenum imageTarget, uint32_t level, GLenum respecFormat, + uvec3 dstOffset, const ivec2& srcOffset, + const uvec2& size) const; + + // TexSubImage if `!respectFormat` + void TexImage(uint32_t level, GLenum respecFormat, uvec3 offset, + const webgl::PackingInfo& pi, + const webgl::TexUnpackBlobDesc&) const; + + void TexStorage(GLenum texTarget, uint32_t levels, GLenum sizedFormat, + uvec3 size) const; + + UniquePtr<webgl::TexUnpackBlob> ToTexUnpackBytes( + const WebGLTexImageData& imageData); + + UniquePtr<webgl::TexUnpackBytes> ToTexUnpackBytes(WebGLTexPboOffset& aPbo); + + //////////////////////////////////// + // WebGLTextureUpload.cpp + protected: + bool ValidateTexImageSpecification(uint8_t funcDims, GLenum texImageTarget, + GLint level, GLsizei width, GLsizei height, + GLsizei depth, GLint border, + TexImageTarget* const out_target, + WebGLTexture** const out_texture, + webgl::ImageInfo** const out_imageInfo); + bool ValidateTexImageSelection(uint8_t funcDims, GLenum texImageTarget, + GLint level, GLint xOffset, GLint yOffset, + GLint zOffset, GLsizei width, GLsizei height, + GLsizei depth, + TexImageTarget* const out_target, + WebGLTexture** const out_texture, + webgl::ImageInfo** const out_imageInfo); + bool ValidateUnpackInfo(bool usePBOs, GLenum format, GLenum type, + webgl::PackingInfo* const out); + + // ----------------------------------------------------------------------------- + // Vertices Feature (WebGLContextVertices.cpp) + GLenum mPrimRestartTypeBytes = 0; + + public: + void DrawArraysInstanced(GLenum mode, GLint first, GLsizei vertexCount, + GLsizei instanceCount); + void DrawElementsInstanced(GLenum mode, GLsizei vertexCount, GLenum type, + WebGLintptr byteOffset, GLsizei instanceCount); + + void EnableVertexAttribArray(GLuint index); + void DisableVertexAttribArray(GLuint index); + + Maybe<double> GetVertexAttrib(GLuint index, GLenum pname); + + //// + + void VertexAttrib4T(GLuint index, const webgl::TypedQuad&); + + //// + + void VertexAttribPointer(uint32_t index, const webgl::VertAttribPointerDesc&); + + void VertexAttribDivisor(GLuint index, GLuint divisor); + + private: + WebGLBuffer* DrawElements_check(GLsizei indexCount, GLenum type, + WebGLintptr byteOffset, + GLsizei instanceCount); + void Draw_cleanup(); + + void VertexAttrib1fv_base(GLuint index, uint32_t arrayLength, + const GLfloat* ptr); + void VertexAttrib2fv_base(GLuint index, uint32_t arrayLength, + const GLfloat* ptr); + void VertexAttrib3fv_base(GLuint index, uint32_t arrayLength, + const GLfloat* ptr); + void VertexAttrib4fv_base(GLuint index, uint32_t arrayLength, + const GLfloat* ptr); + + bool BindArrayAttribToLocation0(WebGLProgram* prog); + + // ----------------------------------------------------------------------------- + // PROTECTED + protected: + WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need() const; + bool DoFakeVertexAttrib0(uint64_t fakeVertexCount, + WebGLVertexAttrib0Status whatDoesAttrib0Need); + void UndoFakeVertexAttrib0(); + + bool mResetLayer = true; + bool mOptionsFrozen = false; + bool mIsMesa = false; + bool mLoseContextOnMemoryPressure = false; + bool mCanLoseContextInForeground = true; + bool mShouldPresent = false; + bool mDisableFragHighP = false; + bool mForceResizeOnPresent = false; + bool mVRReady = false; + + template <typename WebGLObjectType> + void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array); + + GLuint mActiveTexture = 0; + GLenum mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK; + GLenum mDefaultFB_ReadBuffer = LOCAL_GL_BACK; + + mutable GLenum mWebGLError = 0; + + std::unique_ptr<webgl::ShaderValidator> CreateShaderValidator( + GLenum shaderType) const; + + // some GL constants + uint32_t mGLMaxFragmentUniformVectors = 0; + uint32_t mGLMaxVertexUniformVectors = 0; + uint32_t mGLMaxVertexOutputVectors = 0; + uint32_t mGLMaxFragmentInputVectors = 0; + + uint32_t mGLMaxVertexTextureImageUnits = 0; + uint32_t mGLMaxFragmentTextureImageUnits = 0; + uint32_t mGLMaxCombinedTextureImageUnits = 0; + + // ES3: + uint32_t mGLMinProgramTexelOffset = 0; + uint32_t mGLMaxProgramTexelOffset = 0; + + public: + auto GLMaxDrawBuffers() const { return mLimits->maxColorDrawBuffers; } + + uint32_t MaxValidDrawBuffers() const { + if (IsWebGL2() || + IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { + return GLMaxDrawBuffers(); + } + return 1; + } + + GLenum LastColorAttachmentEnum() const { + return LOCAL_GL_COLOR_ATTACHMENT0 + MaxValidDrawBuffers() - 1; + } + + const auto& Options() const { return mOptions; } + + protected: + uint32_t mGLMaxRenderbufferSize = 0; + + public: + const auto& Limits() const { return *mLimits; } + auto MaxVertexAttribs() const { return mLimits->maxVertexAttribs; } + auto GLMaxTextureUnits() const { return mLimits->maxTexUnits; } + + bool IsFormatValidForFB(TexInternalFormat format) const; + + protected: + // ------------------------------------------------------------------------- + // WebGL extensions (implemented in WebGLContextExtensions.cpp) + + EnumeratedArray<WebGLExtensionID, WebGLExtensionID::Max, + std::unique_ptr<WebGLExtensionBase>> + mExtensions; + + public: + void RequestExtension(WebGLExtensionID, bool explicitly = true); + + // returns true if the extension has been enabled by calling getExtension. + bool IsExtensionEnabled(const WebGLExtensionID id) const { + return bool(mExtensions[id]); + } + + bool IsExtensionExplicit(WebGLExtensionID) const; + void WarnIfImplicit(WebGLExtensionID) const; + + bool IsExtensionSupported(WebGLExtensionID) const; + + // ------------------------------------------------------------------------- + // WebGL 2 specifics (implemented in WebGL2Context.cpp) + public: + virtual bool IsWebGL2() const { return false; } + + struct FailureReason { + nsCString key; // For reporting. + nsCString info; + + FailureReason() = default; + + template <typename A, typename B> + FailureReason(const A& _key, const B& _info) + : key(nsCString(_key)), info(nsCString(_info)) {} + }; + + protected: + bool InitWebGL2(FailureReason* const out_failReason); + + bool CreateAndInitGL(bool forceEnabled, + std::vector<FailureReason>* const out_failReasons); + + // ------------------------------------------------------------------------- + // Validation functions (implemented in WebGLContextValidate.cpp) + bool InitAndValidateGL(FailureReason* const out_failReason); + + bool ValidateBlendEquationEnum(GLenum cap, const char* info); + bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, + const char* info); + bool ValidateStencilOpEnum(GLenum action, const char* info); + bool ValidateFaceEnum(GLenum face); + bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType, + WebGLTexImageFunc func, WebGLTexDimensions dims); + bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, + GLenum type, WebGLboolean normalized, + GLsizei stride, WebGLintptr byteOffset, + const char* info); + bool ValidateStencilParamsForDrawCall() const; + + bool ValidateCopyTexImage(TexInternalFormat srcFormat, + TexInternalFormat dstformat, WebGLTexImageFunc func, + WebGLTexDimensions dims); + + bool ValidateTexImage(TexImageTarget texImageTarget, GLint level, + GLenum internalFormat, GLint xoffset, GLint yoffset, + GLint zoffset, GLint width, GLint height, GLint depth, + GLint border, GLenum format, GLenum type, + WebGLTexImageFunc func, WebGLTexDimensions dims); + bool ValidateTexImageFormat(GLenum internalFormat, WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateTexImageFormatAndType(GLenum format, GLenum type, + WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateCompTexImageInternalFormat(GLenum format, WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateCopyTexImageInternalFormat(GLenum format, WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateTexImageSize(TexImageTarget texImageTarget, GLint level, + GLint width, GLint height, GLint depth, + WebGLTexImageFunc func, WebGLTexDimensions dims); + bool ValidateTexSubImageSize(GLint x, GLint y, GLint z, GLsizei width, + GLsizei height, GLsizei depth, GLsizei baseWidth, + GLsizei baseHeight, GLsizei baseDepth, + WebGLTexImageFunc func, WebGLTexDimensions dims); + bool ValidateCompTexImageSize(GLint level, GLenum internalFormat, + GLint xoffset, GLint yoffset, GLsizei width, + GLsizei height, GLsizei levelWidth, + GLsizei levelHeight, WebGLTexImageFunc func, + WebGLTexDimensions dims); + bool ValidateCompTexImageDataSize(GLint level, GLenum internalFormat, + GLsizei width, GLsizei height, + uint32_t byteLength, WebGLTexImageFunc func, + WebGLTexDimensions dims); + + bool HasDrawBuffers() const { + return IsWebGL2() || + IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers); + } + + RefPtr<WebGLBuffer>* ValidateBufferSlot(GLenum target); + + public: + WebGLBuffer* ValidateBufferSelection(GLenum target) const; + + protected: + IndexedBufferBinding* ValidateIndexedBufferSlot(GLenum target, GLuint index); + + bool ValidateIndexedBufferBinding( + GLenum target, GLuint index, + RefPtr<WebGLBuffer>** const out_genericBinding, + IndexedBufferBinding** const out_indexedBinding); + + public: + bool ValidateNonNegative(const char* argName, int64_t val) const { + if (MOZ_UNLIKELY(val < 0)) { + ErrorInvalidValue("`%s` must be non-negative.", argName); + return false; + } + return true; + } + + template <typename T> + bool ValidateNonNull(const char* const argName, + const dom::Nullable<T>& maybe) const { + if (maybe.IsNull()) { + ErrorInvalidValue("%s: Cannot be null.", argName); + return false; + } + return true; + } + + //// + + protected: + void DestroyResourcesAndContext(); + + // helpers + + bool ConvertImage(size_t width, size_t height, size_t srcStride, + size_t dstStride, const uint8_t* src, uint8_t* dst, + WebGLTexelFormat srcFormat, bool srcPremultiplied, + WebGLTexelFormat dstFormat, bool dstPremultiplied, + size_t dstTexelSize); + + ////// + public: + template <typename T> + bool ValidateObject(const char* const argName, const T& object) const { + // Todo: Remove all callers. + return true; + } + + template <typename T> + bool ValidateObject(const char* const argName, const T* const object) const { + // Todo: Remove most (all?) callers. + if (!object) { + ErrorInvalidOperation( + "%s: Object argument cannot have been marked for" + " deletion.", + argName); + return false; + } + return true; + } + + //// + + private: + void LoseContextLruLocked(webgl::ContextLossReason reason) + MOZ_REQUIRES(sLruMutex); + + public: + void LoseContext( + webgl::ContextLossReason reason = webgl::ContextLossReason::None); + + protected: + nsTArray<RefPtr<WebGLTexture>> mBound2DTextures; + nsTArray<RefPtr<WebGLTexture>> mBoundCubeMapTextures; + nsTArray<RefPtr<WebGLTexture>> mBound3DTextures; + nsTArray<RefPtr<WebGLTexture>> mBound2DArrayTextures; + nsTArray<RefPtr<WebGLSampler>> mBoundSamplers; + + void ResolveTexturesForDraw() const; + + RefPtr<WebGLProgram> mCurrentProgram; + RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo; + + bool ValidateFramebufferTarget(GLenum target) const; + bool ValidateInvalidateFramebuffer(GLenum target, + const Range<const GLenum>& attachments, + std::vector<GLenum>* const scopedVector, + GLsizei* const out_glNumAttachments, + const GLenum** const out_glAttachments); + + RefPtr<WebGLFramebuffer> mBoundDrawFramebuffer; + RefPtr<WebGLFramebuffer> mBoundReadFramebuffer; + RefPtr<WebGLTransformFeedback> mBoundTransformFeedback; + RefPtr<WebGLVertexArray> mBoundVertexArray; + + public: + const auto& BoundReadFb() const { return mBoundReadFramebuffer; } + + protected: + RefPtr<WebGLTransformFeedback> mDefaultTransformFeedback; + RefPtr<WebGLVertexArray> mDefaultVertexArray; + + //////////////////////////////////// + + protected: + GLuint mEmptyTFO = 0; + + // Generic Vertex Attributes + // Though CURRENT_VERTEX_ATTRIB is listed under "Vertex Shader State" in the + // spec state tables, this isn't vertex shader /object/ state. This array is + // merely state useful to vertex shaders, but is global state. + std::vector<webgl::AttribBaseType> mGenericVertexAttribTypes; + CacheInvalidator mGenericVertexAttribTypeInvalidator; + + GLuint mFakeVertexAttrib0BufferObject = 0; + intptr_t mFakeVertexAttrib0BufferObjectSize = 0; + bool mFakeVertexAttrib0DataDefined = false; + alignas(alignof(float)) uint8_t + mGenericVertexAttrib0Data[sizeof(float) * 4] = {}; + alignas(alignof(float)) uint8_t + mFakeVertexAttrib0Data[sizeof(float) * 4] = {}; + + GLint mStencilRefFront = 0; + GLint mStencilRefBack = 0; + GLuint mStencilValueMaskFront = 0; + GLuint mStencilValueMaskBack = 0; + GLuint mStencilWriteMaskFront = 0; + GLuint mStencilWriteMaskBack = 0; + uint8_t mColorWriteMask0 = 0xf; // bitmask + mutable uint8_t mDriverColorMask0 = 0xf; + bool mDepthWriteMask = true; + GLfloat mColorClearValue[4] = {0, 0, 0, 0}; + GLint mStencilClearValue = 0; + GLfloat mDepthClearValue = 1.0f; + + std::bitset<webgl::kMaxDrawBuffers> mColorWriteMaskNonzero = -1; + std::bitset<webgl::kMaxDrawBuffers> mBlendEnabled = 0; + + GLint mViewportX = 0; + GLint mViewportY = 0; + GLsizei mViewportWidth = 0; + GLsizei mViewportHeight = 0; + bool mAlreadyWarnedAboutViewportLargerThanDest = false; + + GLfloat mLineWidth = 1.0; + + WebGLContextLossHandler mContextLossHandler; + + // Used for some hardware (particularly Tegra 2 and 4) that likes to + // be Flushed while doing hundreds of draw calls. + mutable uint64_t mDrawCallsSinceLastFlush = 0; + + mutable uint64_t mWarningCount = 0; + const uint64_t mMaxWarnings = StaticPrefs::webgl_max_warnings_per_context(); + bool mAlreadyWarnedAboutFakeVertexAttrib0 = false; + + bool ShouldGenerateWarnings() const { return mWarningCount < mMaxWarnings; } + + bool ShouldGeneratePerfWarnings() const { + return mNumPerfWarnings < mMaxPerfWarnings; + } + + bool mNeedsFakeNoAlpha = false; + bool mNeedsFakeNoDepth = false; + bool mNeedsFakeNoStencil = false; + + bool mDriverDepthTest = false; + bool mDriverStencilTest = false; + + bool mNeedsLegacyVertexAttrib0Handling = false; + bool mMaybeNeedsLegacyVertexAttrib0Handling = false; + bool mNeedsIndexValidation = false; + bool mBug_DrawArraysInstancedUserAttribFetchAffectedByFirst = false; + + const bool mAllowFBInvalidation = StaticPrefs::webgl_allow_fb_invalidation(); + + bool Has64BitTimestamps() const; + + // -- + + const uint8_t mMsaaSamples = + static_cast<uint8_t>(StaticPrefs::webgl_msaa_samples()); + mutable uvec2 mRequestedSize; + mutable UniquePtr<gl::MozFramebuffer> mDefaultFB; + mutable bool mDefaultFB_IsInvalid = false; + mutable UniquePtr<gl::MozFramebuffer> mResolvedDefaultFB; + + gl::SwapChain mSwapChain; + gl::SwapChain mWebVRSwapChain; + + RefPtr<layers::RemoteTextureOwnerClient> mRemoteTextureOwner; + + bool PushRemoteTexture( + WebGLFramebuffer*, gl::SwapChain&, std::shared_ptr<gl::SharedSurface>, + const webgl::SwapChainOptions& options, + layers::RemoteTextureOwnerClient* ownerClient = nullptr); + + void EnsureContextLostRemoteTextureOwner( + const webgl::SwapChainOptions& options); + + public: + void WaitForTxn(layers::RemoteTextureOwnerId ownerId, + layers::RemoteTextureTxnType txnType, + layers::RemoteTextureTxnId txnId); + + // -- + + protected: + bool EnsureDefaultFB(); + bool ValidateAndInitFB( + const WebGLFramebuffer* fb, + GLenum incompleteFbError = LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION); + void DoBindFB(const WebGLFramebuffer* fb, + GLenum target = LOCAL_GL_FRAMEBUFFER) const; + + bool BindCurFBForDraw(); + bool BindCurFBForColorRead( + const webgl::FormatUsageInfo** out_format, uint32_t* out_width, + uint32_t* out_height, + GLenum incompleteFbError = LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION); + void DoColorMask(Maybe<GLuint> i, uint8_t bitmask) const; + void BlitBackbufferToCurDriverFB( + WebGLFramebuffer* const srcAsWebglFb = nullptr, + const gl::MozFramebuffer* const srcAsMozFb = nullptr, + bool srcIsBGRA = false) const; + bool BindDefaultFBForRead(); + + // -- + + public: + // console logging helpers + template <typename... Args> + void GenerateWarning(const char* const fmt, const Args&... args) const { + GenerateError(0, fmt, args...); + } + + template <typename... Args> + void GeneratePerfWarning(const char* const fmt, const Args&... args) const { + GenerateError(webgl::kErrorPerfWarning, fmt, args...); + } + + public: + UniquePtr<webgl::FormatUsageAuthority> mFormatUsage; + + virtual UniquePtr<webgl::FormatUsageAuthority> CreateFormatUsage( + gl::GLContext* gl) const; + + const decltype(mBound2DTextures)* TexListForElemType(GLenum elemType) const; + + // Friend list + friend class ScopedCopyTexImageSource; + friend class ScopedResolveTexturesForDraw; + friend class webgl::TexUnpackBlob; + friend class webgl::TexUnpackBytes; + friend class webgl::TexUnpackImage; + friend class webgl::TexUnpackSurface; + friend struct webgl::UniformInfo; + friend class WebGLTexture; + friend class WebGLFBAttachPoint; + friend class WebGLFramebuffer; + friend class WebGLRenderbuffer; + friend class WebGLProgram; + friend class WebGLQuery; + friend class WebGLBuffer; + friend class WebGLSampler; + friend class WebGLShader; + friend class WebGLSync; + friend class WebGLTransformFeedback; + friend class WebGLVertexArray; + friend class WebGLVertexArrayFake; + friend class WebGLVertexArrayGL; +}; + +// Returns `value` rounded to the next highest multiple of `multiple`. +// AKA PadToAlignment, StrideForAlignment. +template <typename V, typename M> +V RoundUpToMultipleOf(const V& value, const M& multiple) { + return ((value + multiple - 1) / multiple) * multiple; +} + +class ScopedFBRebinder final { + private: + const WebGLContext* const mWebGL; + + public: + explicit ScopedFBRebinder(const WebGLContext* const webgl) : mWebGL(webgl) {} + ~ScopedFBRebinder(); +}; + +// - + +constexpr inline bool IsBufferTargetLazilyBound(const GLenum target) { + return target != LOCAL_GL_ELEMENT_ARRAY_BUFFER; +} + +void DoBindBuffer(gl::GLContext&, GLenum target, const WebGLBuffer*); + +class ScopedLazyBind final { + private: + gl::GLContext& mGL; + const GLenum mTarget; + + public: + ScopedLazyBind(gl::GLContext* const gl, const GLenum target, + const WebGLBuffer* const buf) + : mGL(*gl), mTarget(IsBufferTargetLazilyBound(target) ? target : 0) { + if (mTarget) { + DoBindBuffer(mGL, mTarget, buf); + } + } + + ~ScopedLazyBind() { + if (mTarget) { + DoBindBuffer(mGL, mTarget, nullptr); + } + } +}; + +//// + +bool Intersect(int32_t srcSize, int32_t read0, int32_t readSize, + int32_t* out_intRead0, int32_t* out_intWrite0, + int32_t* out_intSize); + +uint64_t AvailGroups(uint64_t totalAvailItems, uint64_t firstItemOffset, + uint32_t groupSize, uint32_t groupStride); + +//// + +class ScopedDrawCallWrapper final { + public: + WebGLContext& mWebGL; + + explicit ScopedDrawCallWrapper(WebGLContext& webgl); + ~ScopedDrawCallWrapper(); +}; + +namespace webgl { + +class ScopedPrepForResourceClear final { + const WebGLContext& webgl; + + public: + explicit ScopedPrepForResourceClear(const WebGLContext&); + ~ScopedPrepForResourceClear(); +}; + +struct IndexedName final { + std::string name; + uint64_t index; +}; +Maybe<IndexedName> ParseIndexed(const std::string& str); + +} // namespace webgl + +webgl::LinkActiveInfo GetLinkActiveInfo( + gl::GLContext& gl, const GLuint prog, const bool webgl2, + const std::unordered_map<std::string, std::string>& nameUnmap); + +} // namespace mozilla + +#endif |