gecko-dev/dom/canvas/WebGLFramebuffer.h

291 строка
8.1 KiB
C++

/* -*- 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 <vector>
#include "mozilla/LinkedList.h"
#include "mozilla/WeakPtr.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
#include "WebGLRenderbuffer.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;
} // namespace gl
namespace webgl {
struct FbAttachInfo final {
WebGLRenderbuffer* rb = nullptr;
WebGLTexture* tex = nullptr;
GLint mipLevel = 0;
GLint zLayer = 0;
GLsizei zLayerCount = 1;
bool isMultiview = false;
};
} // namespace webgl
class WebGLFBAttachPoint final {
friend class WebGLFramebuffer;
public:
const GLenum mAttachmentPoint = 0;
const bool mDeferAttachment = false;
private:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
uint32_t mTexImageLayer = 0;
uint8_t mTexImageZLayerCount = 1;
uint8_t mTexImageLevel = 0;
bool mIsMultiview = false;
////
WebGLFBAttachPoint() = default;
WebGLFBAttachPoint(const WebGLContext* webgl, GLenum attachmentPoint);
explicit WebGLFBAttachPoint(WebGLFBAttachPoint&) =
default; // Make this private.
public:
~WebGLFBAttachPoint();
////
void Unlink() { Clear(); }
bool HasAttachment() const {
return bool(mTexturePtr) | bool(mRenderbufferPtr);
}
bool IsDeleteRequested() const;
void Clear();
void Set(gl::GLContext* gl, const webgl::FbAttachInfo&);
WebGLTexture* Texture() const { return mTexturePtr; }
WebGLRenderbuffer* Renderbuffer() const { return mRenderbufferPtr; }
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;
JS::Value GetParameter(WebGLContext* webgl, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error) 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 nsWrapperCache,
public WebGLRefCountedObject<WebGLFramebuffer>,
public LinkedListElement<WebGLFramebuffer>,
public SupportsWeakPtr<WebGLFramebuffer>,
public CacheInvalidator {
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
const GLuint mGLName;
bool mHasBeenBound = false;
private:
mutable uint64_t mNumFBStatusInvals = 0;
////
protected:
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
// In theory, this number can be unbounded based on the driver. However, no
// driver appears to expose more than 8. We might as well stop there too, for
// now.
// (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
static const size_t kMaxColorAttachments =
8; // jgilbert's MacBook Pro exposes 8.
WebGLFBAttachPoint mColorAttachments[kMaxColorAttachments];
////
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;
bool hasFloat32 = false;
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:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
WebGLContext* GetParentObject() const { return mContext; }
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> givenProto) override;
private:
~WebGLFramebuffer() {
DeleteOnce();
InvalidateCaches();
}
public:
void Delete();
////
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,
GLenum 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]; }
////////////////
// Invalidation
const auto* GetCompletenessInfo() const { return mCompletenessInfo.get(); }
////////////////
// WebGL funcs
bool IsCheckFramebufferStatusComplete() const {
return CheckFramebufferStatus() == LOCAL_GL_FRAMEBUFFER_COMPLETE;
}
FBStatus CheckFramebufferStatus() const;
void FramebufferAttach(GLenum attachEnum,
const webgl::FbAttachInfo& toAttach);
void DrawBuffers(const dom::Sequence<GLenum>& buffers);
void ReadBuffer(GLenum attachPoint);
JS::Value GetAttachmentParameter(JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
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_