diff options
Diffstat (limited to 'dom/canvas/WebGLFramebuffer.h')
-rw-r--r-- | dom/canvas/WebGLFramebuffer.h | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/dom/canvas/WebGLFramebuffer.h b/dom/canvas/WebGLFramebuffer.h new file mode 100644 index 0000000000..beab87d7af --- /dev/null +++ b/dom/canvas/WebGLFramebuffer.h @@ -0,0 +1,273 @@ +/* -*- 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 WEBGL_FRAMEBUFFER_H_ +#define WEBGL_FRAMEBUFFER_H_ + +#include <bitset> +#include <vector> + +#include "mozilla/WeakPtr.h" + +#include "GLScreenBuffer.h" +#include "WebGLObjectModel.h" +#include "WebGLStrongTypes.h" +#include "WebGLTexture.h" +#include "WebGLTypes.h" + +namespace mozilla { + +class WebGLFramebuffer; +class WebGLRenderbuffer; +class WebGLTexture; + +template <typename T> +class PlacementArray; + +namespace gl { +class GLContext; +class MozFramebuffer; +} // namespace gl + +namespace webgl { +struct FbAttachInfo final { + WebGLRenderbuffer* rb = nullptr; + WebGLTexture* tex = nullptr; + uint32_t mipLevel = 0; + uint32_t zLayer = 0; + uint32_t zLayerCount = 1; + bool isMultiview = false; +}; +} // namespace webgl + +class WebGLFBAttachPoint final { + friend class WebGLFramebuffer; + + public: + const GLenum mAttachmentPoint = 0; + const bool mDeferAttachment = false; + + private: + RefPtr<WebGLTexture> mTexturePtr; + RefPtr<WebGLRenderbuffer> mRenderbufferPtr; + uint32_t mTexImageLayer = 0; + uint8_t mTexImageZLayerCount = 1; + uint8_t mTexImageLevel = 0; + bool mIsMultiview = false; + + //// + + WebGLFBAttachPoint(); + explicit WebGLFBAttachPoint(WebGLFBAttachPoint&); // Make this private. + WebGLFBAttachPoint(const WebGLContext* webgl, GLenum attachmentPoint); + + public: + ~WebGLFBAttachPoint(); + + //// + + bool HasAttachment() const { + return bool(mTexturePtr) || bool(mRenderbufferPtr); + } + + void Clear(); + + void Set(gl::GLContext* gl, const webgl::FbAttachInfo&); + + WebGLTexture* Texture() const { return mTexturePtr; } + WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; } + + Maybe<size_t> ColorAttachmentId() const { + const size_t id = mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0; + if (id >= webgl::kMaxDrawBuffers) return {}; + return Some(id); + } + + auto Layer() const { return mTexImageLayer; } + auto ZLayerCount() const { return mTexImageZLayerCount; } + auto MipLevel() const { return mTexImageLevel; } + const auto& IsMultiview() const { return mIsMultiview; } + + void AttachmentName(nsCString* out) const; + + const webgl::ImageInfo* GetImageInfo() const; + + bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const; + + void DoAttachment(gl::GLContext* gl) const; + + Maybe<double> GetParameter(WebGLContext* webgl, GLenum attachment, + GLenum pname) const; + + bool IsEquivalentForFeedback(const WebGLFBAttachPoint& other) const { + if (!HasAttachment() || !other.HasAttachment()) return false; + +#define _(X) (X == other.X) + return (_(mRenderbufferPtr) && _(mTexturePtr) && _(mTexImageLevel) && + _(mTexImageLayer) && _(mTexImageZLayerCount)); +#undef _ + } + + //// + + struct Ordered { + const WebGLFBAttachPoint& mRef; + + explicit Ordered(const WebGLFBAttachPoint& ref) : mRef(ref) {} + + bool operator<(const Ordered& other) const { + MOZ_ASSERT(mRef.HasAttachment() && other.mRef.HasAttachment()); + +#define ORDER_BY(X) \ + if (X != other.X) return X < other.X; + + ORDER_BY(mRef.mRenderbufferPtr) + ORDER_BY(mRef.mTexturePtr) + ORDER_BY(mRef.mTexImageLevel) + ORDER_BY(mRef.mTexImageLayer) + ORDER_BY(mRef.mTexImageZLayerCount) + +#undef ORDER_BY + return false; + } + }; +}; + +class WebGLFramebuffer final : public WebGLContextBoundObject, + public SupportsWeakPtr, + public CacheInvalidator { + public: + MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(WebGLFramebuffer, override) + + const GLuint mGLName; + bool mHasBeenBound = false; + const UniquePtr<gl::MozFramebuffer> mOpaque; + bool mInOpaqueRAF = false; + // Swap chain that may be used to present this framebuffer, for opaque + // framebuffers or other use cases. (e.g. DrawTargetWebgl) + gl::SwapChain mSwapChain; + + private: + mutable uint64_t mNumFBStatusInvals = 0; + + //// + + protected: + WebGLFBAttachPoint mDepthAttachment; + WebGLFBAttachPoint mStencilAttachment; + WebGLFBAttachPoint mDepthStencilAttachment; + + std::array<WebGLFBAttachPoint, webgl::kMaxDrawBuffers> mColorAttachments = {}; + std::bitset<webgl::kMaxDrawBuffers> mDrawBufferEnabled = {1}; + //// + + std::vector<WebGLFBAttachPoint*> mAttachments; // Non-null. + + std::vector<const WebGLFBAttachPoint*> mColorDrawBuffers; // Non-null + const WebGLFBAttachPoint* mColorReadBuffer; // Null if NONE + + //// + + struct CompletenessInfo final { + const WebGLFramebuffer* fb = nullptr; + + uint32_t width = 0; + uint32_t height = 0; + std::bitset<webgl::kMaxDrawBuffers> hasAttachment = 0; + std::bitset<webgl::kMaxDrawBuffers> isAttachmentF32 = 0; + uint8_t zLayerCount = 1; + bool isMultiview = false; + + // IsFeedback + std::vector<const WebGLFBAttachPoint*> texAttachments; // Non-null + + ~CompletenessInfo(); + }; + friend struct CompletenessInfo; + + mutable CacheMaybe<const CompletenessInfo> mCompletenessInfo; + + //// + + public: + WebGLFramebuffer(WebGLContext* webgl, GLuint fbo); + WebGLFramebuffer(WebGLContext* webgl, UniquePtr<gl::MozFramebuffer> fbo); + ~WebGLFramebuffer() override; + + //// + + bool HasDuplicateAttachments() const; + bool HasDefinedAttachments() const; + bool HasIncompleteAttachments(nsCString* const out_info) const; + bool AllImageRectsMatch() const; + bool AllImageSamplesMatch() const; + FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const; + + protected: + Maybe<WebGLFBAttachPoint*> GetAttachPoint(GLenum attachment); // Fallible + Maybe<WebGLFBAttachPoint*> GetColorAttachPoint( + GLenum attachment); // Fallible + void DoDeferredAttachments() const; + void RefreshDrawBuffers() const; + void RefreshReadBuffer() const; + void ResolveAttachmentData() const; + + public: + void DetachTexture(const WebGLTexture* tex); + void DetachRenderbuffer(const WebGLRenderbuffer* rb); + bool ValidateAndInitAttachments(GLenum incompleteFbError) const; + bool ValidateClearBufferType(GLenum buffer, uint32_t drawBuffer, + webgl::AttribBaseType funcType) const; + + bool ValidateForColorRead(const webgl::FormatUsageInfo** out_format, + uint32_t* out_width, uint32_t* out_height) const; + + //////////////// + // Getters + +#define GETTER(X) \ + const decltype(m##X)& X() const { return m##X; } + + GETTER(DepthAttachment) + GETTER(StencilAttachment) + GETTER(DepthStencilAttachment) + GETTER(Attachments) + GETTER(ColorDrawBuffers) + GETTER(ColorReadBuffer) + +#undef GETTER + + const auto& ColorAttachment0() const { return mColorAttachments[0]; } + const auto& DrawBufferEnabled() const { return mDrawBufferEnabled; } + + //////////////// + // Invalidation + + const auto* GetCompletenessInfo() const { return mCompletenessInfo.get(); } + + //////////////// + // WebGL funcs + + bool IsCheckFramebufferStatusComplete() const { + return CheckFramebufferStatus() == LOCAL_GL_FRAMEBUFFER_COMPLETE; + } + + FBStatus CheckFramebufferStatus() const; + bool FramebufferAttach(GLenum attachEnum, + const webgl::FbAttachInfo& toAttach); + void DrawBuffers(const std::vector<GLenum>& buffers); + void ReadBuffer(GLenum attachPoint); + + Maybe<double> GetAttachmentParameter(GLenum attachment, GLenum pname); + + static void BlitFramebuffer(WebGLContext* webgl, GLint srcX0, GLint srcY0, + GLint srcX1, GLint srcY1, GLint dstX0, + GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); +}; + +} // namespace mozilla + +#endif // WEBGL_FRAMEBUFFER_H_ |