/* -*- 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_