gecko-dev/dom/canvas/WebGLFramebuffer.h

293 lines
7.8 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 "mozilla/LinkedList.h"
#include "mozilla/WeakPtr.h"
#include "nsWrapperCache.h"
#include "WebGLObjectModel.h"
#include "WebGLStrongTypes.h"
#include "WebGLRenderbuffer.h"
#include "WebGLTexture.h"
namespace mozilla {
class WebGLFramebuffer;
class WebGLRenderbuffer;
class WebGLTexture;
template<typename T>
class PlacementArray;
namespace gl {
class GLContext;
} // namespace gl
class WebGLFBAttachPoint
{
public:
WebGLFramebuffer* const mFB;
const GLenum mAttachmentPoint;
private:
WebGLRefPtr<WebGLTexture> mTexturePtr;
WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr;
TexImageTarget mTexImageTarget;
GLint mTexImageLayer;
GLint mTexImageLevel;
// PlacementArray needs a default constructor.
template<typename T>
friend class PlacementArray;
WebGLFBAttachPoint()
: mFB(nullptr)
, mAttachmentPoint(0)
{ }
public:
WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint);
~WebGLFBAttachPoint();
void Unlink();
bool IsDefined() const;
bool IsDeleteRequested() const;
const webgl::FormatUsageInfo* Format() const;
uint32_t Samples() const;
bool HasAlpha() const;
bool IsReadableFloat() const;
void Clear();
void SetTexImage(WebGLTexture* tex, TexImageTarget target, GLint level);
void SetTexImageLayer(WebGLTexture* tex, TexImageTarget target, GLint level,
GLint layer);
void SetRenderbuffer(WebGLRenderbuffer* rb);
const WebGLTexture* Texture() const {
return mTexturePtr;
}
WebGLTexture* Texture() {
return mTexturePtr;
}
const WebGLRenderbuffer* Renderbuffer() const {
return mRenderbufferPtr;
}
WebGLRenderbuffer* Renderbuffer() {
return mRenderbufferPtr;
}
TexImageTarget ImageTarget() const {
return mTexImageTarget;
}
GLint Layer() const {
return mTexImageLayer;
}
GLint MipLevel() const {
return mTexImageLevel;
}
void AttachmentName(nsCString* out) const;
bool HasUninitializedImageData() const;
void SetImageDataStatus(WebGLImageDataStatus x);
void Size(uint32_t* const out_width, uint32_t* const out_height) const;
bool HasImage() const;
bool IsComplete(WebGLContext* webgl, nsCString* const out_info) const;
void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
JS::Value GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
GLenum target, GLenum attachment, GLenum pname,
ErrorResult* const out_error);
void OnBackingStoreRespecified() const;
};
template<typename T>
class PlacementArray
{
public:
const size_t mCapacity;
protected:
size_t mSize;
T* const mArray;
public:
explicit PlacementArray(size_t capacity)
: mCapacity(capacity)
, mSize(0)
, mArray((T*)moz_xmalloc(sizeof(T) * capacity))
{ }
~PlacementArray() {
for (auto& cur : *this) {
cur.~T();
}
free(mArray);
}
T* begin() const {
return mArray;
}
T* end() const {
return mArray + mSize;
}
T& operator [](size_t offset) const {
MOZ_ASSERT(offset < mSize);
return mArray[offset];
}
const size_t& Size() const { return mSize; }
template<typename A, typename B>
void AppendNew(A a, B b) {
if (mSize == mCapacity)
MOZ_CRASH("Bad EmplaceAppend.");
// Placement `new`:
new (&(mArray[mSize])) T(a, b);
++mSize;
}
};
class WebGLFramebuffer final
: public nsWrapperCache
, public WebGLRefCountedObject<WebGLFramebuffer>
, public LinkedListElement<WebGLFramebuffer>
, public WebGLContextBoundObject
, public SupportsWeakPtr<WebGLFramebuffer>
{
friend class WebGLContext;
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
const GLuint mGLName;
private:
mutable bool mIsKnownFBComplete;
GLenum mReadBufferMode;
// No need to chase pointers for the oft-used color0.
WebGLFBAttachPoint mColorAttachment0;
WebGLFBAttachPoint mDepthAttachment;
WebGLFBAttachPoint mStencilAttachment;
WebGLFBAttachPoint mDepthStencilAttachment;
PlacementArray<WebGLFBAttachPoint> mMoreColorAttachments;
std::vector<GLenum> mDrawBuffers;
bool IsDrawBuffer(size_t n) const {
if (n < mDrawBuffers.size())
return bool(mDrawBuffers[n]);
return false;
}
#ifdef ANDROID
// Bug 1140459: Some drivers (including our test slaves!) don't
// give reasonable answers for IsRenderbuffer, maybe others.
// This shows up on Android 2.3 emulator.
//
// So we track the `is a Framebuffer` state ourselves.
bool mIsFB;
#endif
public:
WebGLFramebuffer(WebGLContext* webgl, GLuint fbo);
private:
~WebGLFramebuffer() {
DeleteOnce();
}
const WebGLRectangleObject& GetAnyRectObject() const;
public:
void Delete();
void FramebufferRenderbuffer(GLenum attachment, RBTarget rbtarget,
WebGLRenderbuffer* rb);
void FramebufferTexture2D(GLenum attachment, TexImageTarget texImageTarget,
WebGLTexture* tex, GLint level);
void FramebufferTextureLayer(GLenum attachment, WebGLTexture* tex, GLint level,
GLint layer);
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments(nsCString* const out_info) const;
bool AllImageRectsMatch() const;
bool AllImageSamplesMatch() const;
FBStatus PrecheckFramebufferStatus(nsCString* const out_info) const;
FBStatus CheckFramebufferStatus(nsCString* const out_info) const;
const webgl::FormatUsageInfo*
GetFormatForAttachment(const WebGLFBAttachPoint& attachment) const;
const WebGLFBAttachPoint& ColorAttachment(size_t colorAttachmentId) const {
MOZ_ASSERT(colorAttachmentId < 1 + mMoreColorAttachments.Size());
return colorAttachmentId ? mMoreColorAttachments[colorAttachmentId - 1]
: mColorAttachment0;
}
const WebGLFBAttachPoint& DepthAttachment() const {
return mDepthAttachment;
}
const WebGLFBAttachPoint& StencilAttachment() const {
return mStencilAttachment;
}
const WebGLFBAttachPoint& DepthStencilAttachment() const {
return mDepthStencilAttachment;
}
protected:
WebGLFBAttachPoint* GetAttachPoint(GLenum attachment); // Fallible
public:
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
WebGLContext* GetParentObject() const {
return mContext;
}
void FinalizeAttachments() const;
virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
bool ValidateAndInitAttachments(const char* funcName);
void InvalidateFramebufferStatus() const {
mIsKnownFBComplete = false;
}
bool ValidateForRead(const char* info,
const webgl::FormatUsageInfo** const out_format,
uint32_t* const out_width, uint32_t* const out_height);
JS::Value GetAttachmentParameter(const char* funcName, JSContext* cx, GLenum target,
GLenum attachment, GLenum pname,
ErrorResult* const out_error);
};
} // namespace mozilla
#endif // WEBGL_FRAMEBUFFER_H_