Bug 962392 - Clean up WebGLFramebuffer, particularly handling of RectangleObjects. - r=dglastonbury

This commit is contained in:
Jeff Gilbert 2014-01-22 19:59:34 -08:00
parent 49b5a372fe
commit ece68b1952
5 changed files with 338 additions and 240 deletions

View File

@ -230,7 +230,8 @@ public:
// all context resources to be lost.
uint32_t Generation() { return mGeneration.value(); }
const WebGLRectangleObject *FramebufferRectangleObject() const;
// Returns null if the current bound FB is not likely complete.
const WebGLRectangleObject* CurValidFBRectObject() const;
static const size_t sMaxColorAttachments = 16;

View File

@ -53,9 +53,22 @@ using namespace mozilla::gfx;
static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
static GLenum InternalFormatForFormatAndType(GLenum format, GLenum type, bool isGLES2);
const WebGLRectangleObject *WebGLContext::FramebufferRectangleObject() const {
return mBoundFramebuffer ? mBoundFramebuffer->RectangleObject()
: static_cast<const WebGLRectangleObject*>(this);
const WebGLRectangleObject*
WebGLContext::CurValidFBRectObject() const
{
const WebGLRectangleObject* rect = nullptr;
if (mBoundFramebuffer) {
// We don't really need to ask the driver.
// Use 'precheck' to just check that our internal state looks good.
GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
rect = &mBoundFramebuffer->RectangleObject();
} else {
rect = static_cast<const WebGLRectangleObject*>(this);
}
return rect;
}
WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext *gl, GLenum target, GLenum format)
@ -347,11 +360,8 @@ GLenum
WebGLContext::CheckFramebufferStatus(GLenum target)
{
if (IsContextLost())
{
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
}
MakeContextCurrent();
if (target != LOCAL_GL_FRAMEBUFFER) {
ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
return 0;
@ -359,42 +369,8 @@ WebGLContext::CheckFramebufferStatus(GLenum target)
if (!mBoundFramebuffer)
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
if(mBoundFramebuffer->HasDepthStencilConflict())
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
bool hasImages = false;
hasImages |= mBoundFramebuffer->DepthAttachment().IsDefined();
hasImages |= mBoundFramebuffer->StencilAttachment().IsDefined();
hasImages |= mBoundFramebuffer->DepthStencilAttachment().IsDefined();
if (!hasImages) {
int32_t colorAttachmentCount = mBoundFramebuffer->mColorAttachments.Length();
for(int32_t i = 0; i < colorAttachmentCount; i++) {
if (mBoundFramebuffer->ColorAttachment(i).IsDefined()) {
hasImages = true;
break;
}
}
/* http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf section 4.4.5 (page 118)
GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
No images are attached to the framebuffer.
*/
if (!hasImages) {
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
}
}
if(mBoundFramebuffer->HasIncompleteAttachment())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
if(mBoundFramebuffer->HasAttachmentsOfMismatchedDimensions())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
mBoundFramebuffer->FinalizeAttachments();
return gl->fCheckFramebufferStatus(target);
return mBoundFramebuffer->CheckFramebufferStatus();
}
void
@ -409,7 +385,7 @@ WebGLContext::CopyTexSubImage2D_base(GLenum target,
GLsizei height,
bool sub)
{
const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject();
const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
@ -2269,7 +2245,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
if (pixels.IsNull())
return ErrorInvalidValue("readPixels: null destination buffer");
const WebGLRectangleObject *framebufferRect = FramebufferRectangleObject();
const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;

View File

@ -735,7 +735,7 @@ void WebGLContext::Draw_cleanup()
}
// Let's check the viewport
const WebGLRectangleObject* rect = FramebufferRectangleObject();
const WebGLRectangleObject* rect = CurValidFBRectObject();
if (rect) {
if (mViewportWidth > rect->Width() ||
mViewportHeight > rect->Height())

View File

@ -12,16 +12,18 @@
#include "WebGLTexture.h"
#include "WebGLRenderbuffer.h"
#include "GLContext.h"
#include "WebGLContextUtils.h"
using namespace mozilla;
using namespace mozilla::gl;
JSObject*
WebGLFramebuffer::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope) {
WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> scope)
{
return dom::WebGLFramebufferBinding::Wrap(cx, scope, this);
}
WebGLFramebuffer::WebGLFramebuffer(WebGLContext *context)
WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
: WebGLContextBoundObject(context)
, mHasEverBeenBound(false)
, mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
@ -38,14 +40,16 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext *context)
}
bool
WebGLFramebuffer::Attachment::IsDeleteRequested() const {
WebGLFramebuffer::Attachment::IsDeleteRequested() const
{
return Texture() ? Texture()->IsDeleteRequested()
: Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
: false;
}
bool
WebGLFramebuffer::Attachment::HasAlpha() const {
WebGLFramebuffer::Attachment::HasAlpha() const
{
GLenum format = 0;
if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat();
@ -55,7 +59,8 @@ WebGLFramebuffer::Attachment::HasAlpha() const {
}
void
WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLint level) {
WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
{
mTexturePtr = tex;
mRenderbufferPtr = nullptr;
mTexImageTarget = target;
@ -63,50 +68,68 @@ WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLin
}
bool
WebGLFramebuffer::Attachment::HasUninitializedImageData() const {
if (mRenderbufferPtr) {
return mRenderbufferPtr->HasUninitializedImageData();
} else if (mTexturePtr) {
if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
return false;
return mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
} else {
WebGLFramebuffer::Attachment::HasUninitializedImageData() const
{
if (!HasImage())
return false;
if (Renderbuffer()) {
return Renderbuffer()->HasUninitializedImageData();
} else if (Texture()) {
MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
}
MOZ_ASSERT(false, "Should not get here.");
return false;
}
void
WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) {
WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus)
{
if (!HasImage())
return;
if (mRenderbufferPtr) {
mRenderbufferPtr->SetImageDataStatus(newStatus);
return;
} else if (mTexturePtr) {
mTexturePtr->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
} else {
MOZ_ASSERT(false); // should not get here, worth crashing a debug build.
return;
}
}
const WebGLRectangleObject*
WebGLFramebuffer::Attachment::RectangleObject() const {
if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
return &Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
else if (Renderbuffer())
return Renderbuffer();
else
return nullptr;
MOZ_ASSERT(false, "Should not get here.");
}
bool
WebGLFramebuffer::Attachment::HasSameDimensionsAs(const Attachment& other) const {
const WebGLRectangleObject *thisRect = RectangleObject();
const WebGLRectangleObject *otherRect = other.RectangleObject();
return thisRect &&
otherRect &&
thisRect->HasSameDimensionsAs(*otherRect);
WebGLFramebuffer::Attachment::HasImage() const
{
if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
return true;
else if (Renderbuffer())
return true;
return false;
}
const WebGLRectangleObject&
WebGLFramebuffer::Attachment::RectangleObject() const
{
MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle.");
if (Texture()) {
MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
} else if (Renderbuffer()) {
return *Renderbuffer();
}
MOZ_CRASH("Should not get here.");
}
static inline bool
IsValidAttachedTextureColorFormat(GLenum format) {
IsValidAttachedTextureColorFormat(GLenum format)
{
return (
/* linear 8-bit formats */
format == LOCAL_GL_ALPHA ||
@ -126,31 +149,34 @@ IsValidAttachedTextureColorFormat(GLenum format) {
}
bool
WebGLFramebuffer::Attachment::IsComplete() const {
const WebGLRectangleObject *thisRect = RectangleObject();
if (!thisRect ||
!thisRect->Width() ||
!thisRect->Height())
WebGLFramebuffer::Attachment::IsComplete() const
{
if (!HasImage())
return false;
if (mTexturePtr) {
if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
return false;
const WebGLRectangleObject& rect = RectangleObject();
if (!rect.Width() ||
!rect.Height())
{
return false;
}
if (mTexturePtr) {
MOZ_ASSERT(mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
GLenum format = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).InternalFormat();
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
return format == LOCAL_GL_DEPTH_COMPONENT;
}
else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
} else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
return format == LOCAL_GL_DEPTH_STENCIL;
}
else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) {
} else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
{
return IsValidAttachedTextureColorFormat(format);
}
MOZ_CRASH("Invalid WebGL attachment poin?");
MOZ_ASSERT(false, "Invalid WebGL attachment point?");
return false;
}
if (mRenderbufferPtr) {
@ -158,29 +184,31 @@ WebGLFramebuffer::Attachment::IsComplete() const {
if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT) {
return format == LOCAL_GL_DEPTH_COMPONENT16;
}
else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) {
} else if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT) {
return format == LOCAL_GL_STENCIL_INDEX8;
}
else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
} else if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
return format == LOCAL_GL_DEPTH_STENCIL;
} else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments))
{
return format == LOCAL_GL_RGB565 ||
format == LOCAL_GL_RGB5_A1 ||
format == LOCAL_GL_RGBA4 ||
format == LOCAL_GL_SRGB8_ALPHA8_EXT;
}
else if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + WebGLContext::sMaxColorAttachments)) {
return (format == LOCAL_GL_RGB565 ||
format == LOCAL_GL_RGB5_A1 ||
format == LOCAL_GL_RGBA4 ||
format == LOCAL_GL_SRGB8_ALPHA8_EXT);
}
MOZ_CRASH("Invalid WebGL attachment poin?");
MOZ_ASSERT(false, "Invalid WebGL attachment point?");
return false;
}
MOZ_ASSERT(false); // should never get there
MOZ_ASSERT(false, "Should not get here.");
return false;
}
void
WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const {
WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const
{
MOZ_ASSERT(HasImage());
if (Texture()) {
GLContext* gl = Texture()->Context()->gl;
if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
@ -200,16 +228,17 @@ WebGLFramebuffer::Attachment::FinalizeAttachment(GLenum attachmentLoc) const {
return;
}
// Neither?
MOZ_ASSERT(false, "FB attachment without a tex or RB.");
MOZ_ASSERT(false, "Should not get here.");
}
void
WebGLFramebuffer::Delete() {
WebGLFramebuffer::Delete()
{
mColorAttachments.Clear();
mDepthAttachment.Reset();
mStencilAttachment.Reset();
mDepthStencilAttachment.Reset();
mContext->MakeContextCurrent();
mContext->gl->fDeleteFramebuffers(1, &mGLName);
LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
@ -217,15 +246,13 @@ WebGLFramebuffer::Delete() {
void
WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
GLenum attachment,
GLenum rbtarget,
WebGLRenderbuffer *wrb)
GLenum attachment,
GLenum rbtarget,
WebGLRenderbuffer* wrb)
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
{
return;
}
if (target != LOCAL_GL_FRAMEBUFFER)
return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
@ -258,10 +285,10 @@ WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
void
WebGLFramebuffer::FramebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
WebGLTexture *wtex,
GLint level)
GLenum attachment,
GLenum textarget,
WebGLTexture* wtex,
GLint level)
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture",
@ -276,7 +303,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target,
if (textarget != LOCAL_GL_TEXTURE_2D &&
(textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
{
return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
}
if (wtex) {
bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D;
@ -300,9 +329,8 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target,
mDepthStencilAttachment.SetTexImage(wtex, textarget, level);
break;
default:
if (!CheckColorAttachementNumber(attachment, "framebufferTexture2D")){
if (!CheckColorAttachementNumber(attachment, "framebufferTexture2D"))
return;
}
size_t colorAttachmentId = size_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
EnsureColorAttachments(colorAttachmentId);
@ -311,42 +339,9 @@ WebGLFramebuffer::FramebufferTexture2D(GLenum target,
}
}
bool
WebGLFramebuffer::HasIncompleteAttachment() const {
int32_t colorAttachmentCount = mColorAttachments.Length();
for (int32_t i = 0; i < colorAttachmentCount; i++)
{
if (mColorAttachments[i].IsDefined() && !mColorAttachments[i].IsComplete())
{
return true;
}
}
return ((mDepthAttachment.IsDefined() && !mDepthAttachment.IsComplete()) ||
(mStencilAttachment.IsDefined() && !mStencilAttachment.IsComplete()) ||
(mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.IsComplete()));
}
bool
WebGLFramebuffer::HasAttachmentsOfMismatchedDimensions() const {
int32_t colorAttachmentCount = mColorAttachments.Length();
for (int32_t i = 1; i < colorAttachmentCount; i++)
{
if (mColorAttachments[i].IsDefined() && !mColorAttachments[i].HasSameDimensionsAs(mColorAttachments[0]))
{
return true;
}
}
return ((mDepthAttachment.IsDefined() && !mDepthAttachment.HasSameDimensionsAs(mColorAttachments[0])) ||
(mStencilAttachment.IsDefined() && !mStencilAttachment.HasSameDimensionsAs(mColorAttachments[0])) ||
(mDepthStencilAttachment.IsDefined() && !mDepthStencilAttachment.HasSameDimensionsAs(mColorAttachments[0])));
}
const WebGLFramebuffer::Attachment&
WebGLFramebuffer::GetAttachment(GLenum attachment) const {
WebGLFramebuffer::GetAttachment(GLenum attachment) const
{
if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
return mDepthStencilAttachment;
if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
@ -359,8 +354,7 @@ WebGLFramebuffer::GetAttachment(GLenum attachment) const {
return mColorAttachments[0];
}
uint32_t colorAttachmentId = uint32_t(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
if (colorAttachmentId >= mColorAttachments.Length()) {
MOZ_ASSERT(false);
return mColorAttachments[0];
@ -370,10 +364,9 @@ WebGLFramebuffer::GetAttachment(GLenum attachment) const {
}
void
WebGLFramebuffer::DetachTexture(const WebGLTexture *tex) {
int32_t colorAttachmentCount = mColorAttachments.Length();
for (int32_t i = 0; i < colorAttachmentCount; i++) {
WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
{
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
if (mColorAttachments[i].Texture() == tex) {
FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_TEXTURE_2D, nullptr, 0);
// a texture might be attached more that once while editing the framebuffer
@ -389,10 +382,9 @@ WebGLFramebuffer::DetachTexture(const WebGLTexture *tex) {
}
void
WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) {
int32_t colorAttachmentCount = mColorAttachments.Length();
for (int32_t i = 0; i < colorAttachmentCount; i++) {
WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
{
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
if (mColorAttachments[0].Renderbuffer() == rb) {
FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, LOCAL_GL_RENDERBUFFER, nullptr);
// a renderbuffer might be attached more that once while editing the framebuffer
@ -408,62 +400,191 @@ WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) {
}
bool
WebGLFramebuffer::CheckAndInitializeAttachments()
WebGLFramebuffer::HasDefinedAttachments() const
{
bool hasAttachments = false;
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
hasAttachments |= mColorAttachments[i].IsDefined();
}
hasAttachments |= mDepthAttachment.IsDefined();
hasAttachments |= mStencilAttachment.IsDefined();
hasAttachments |= mDepthStencilAttachment.IsDefined();
return hasAttachments;
}
static bool
IsIncomplete(const WebGLFramebuffer::Attachment& cur)
{
return cur.IsDefined() && !cur.IsComplete();
}
bool
WebGLFramebuffer::HasIncompleteAttachments() const
{
bool hasIncomplete = false;
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
hasIncomplete |= IsIncomplete(mColorAttachments[i]);
}
hasIncomplete |= IsIncomplete(mDepthAttachment);
hasIncomplete |= IsIncomplete(mStencilAttachment);
hasIncomplete |= IsIncomplete(mDepthStencilAttachment);
return hasIncomplete;
}
const WebGLRectangleObject&
WebGLFramebuffer::GetAnyRectObject() const
{
MOZ_ASSERT(HasDefinedAttachments());
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
if (mColorAttachments[i].HasImage())
return mColorAttachments[i].RectangleObject();
}
if (mDepthAttachment.HasImage())
return mDepthAttachment.RectangleObject();
if (mStencilAttachment.HasImage())
return mStencilAttachment.RectangleObject();
if (mDepthStencilAttachment.HasImage())
return mDepthStencilAttachment.RectangleObject();
MOZ_CRASH("Should not get here.");
}
static bool
RectsMatch(const WebGLFramebuffer::Attachment& attachment,
const WebGLRectangleObject& rect)
{
return attachment.RectangleObject().HasSameDimensionsAs(rect);
}
bool
WebGLFramebuffer::AllImageRectsMatch() const
{
MOZ_ASSERT(HasDefinedAttachments());
MOZ_ASSERT(!HasIncompleteAttachments());
const WebGLRectangleObject& rect = GetAnyRectObject();
// Alright, we have *a* rect, let's check all the others.
bool imageRectsMatch = true;
for (size_t i = 0; i < mColorAttachments.Length(); i++) {
if (mColorAttachments[i].HasImage())
imageRectsMatch &= RectsMatch(mColorAttachments[i], rect);
}
if (mDepthAttachment.HasImage())
imageRectsMatch &= RectsMatch(mDepthAttachment, rect);
if (mStencilAttachment.HasImage())
imageRectsMatch &= RectsMatch(mStencilAttachment, rect);
if (mDepthStencilAttachment.HasImage())
imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect);
return imageRectsMatch;
}
const WebGLRectangleObject&
WebGLFramebuffer::RectangleObject() const
{
// If we're using this as the RectObj of an FB, we need to be sure the FB
// has a consistent rect.
MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
return GetAnyRectObject();
}
GLenum
WebGLFramebuffer::PrecheckFramebufferStatus() const
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
// enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
// generate the INVALID_FRAMEBUFFER_OPERATION that we need here
if (!HasDefinedAttachments())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
if (HasIncompleteAttachments())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
if (!AllImageRectsMatch())
return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // No consistent size
if (HasDepthStencilConflict())
return false;
return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
if (HasIncompleteAttachment())
return false;
return LOCAL_GL_FRAMEBUFFER_COMPLETE;
}
GLenum
WebGLFramebuffer::CheckFramebufferStatus() const
{
GLenum precheckStatus = PrecheckFramebufferStatus();
if (precheckStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return precheckStatus;
// Looks good on our end. Let's ask the driver.
mContext->MakeContextCurrent();
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
FinalizeAttachments();
return mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
}
bool
WebGLFramebuffer::CheckAndInitializeAttachments()
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return false;
// Cool! We've checked out ok. Just need to initialize.
size_t colorAttachmentCount = size_t(mColorAttachments.Length());
// Check if we need to initialize anything
{
bool hasUnitializedAttachments = false;
bool hasUninitializedAttachments = false;
for (size_t i = 0; i < colorAttachmentCount; i++) {
hasUnitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
if (mColorAttachments[i].HasImage())
hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
}
if (!hasUnitializedAttachments &&
!mDepthAttachment.HasUninitializedImageData() &&
!mStencilAttachment.HasUninitializedImageData() &&
!mDepthStencilAttachment.HasUninitializedImageData())
{
if (mDepthAttachment.HasImage())
hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData();
if (mStencilAttachment.HasImage())
hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData();
if (mDepthStencilAttachment.HasImage())
hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData();
if (!hasUninitializedAttachments)
return true;
}
}
// ensure INVALID_FRAMEBUFFER_OPERATION in zero-size case
const WebGLRectangleObject *rect = mColorAttachments[0].RectangleObject();
if (!rect ||
!rect->Width() ||
!rect->Height())
return false;
GLenum status = mContext->CheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return false;
// Get buffer-bit-mask and color-attachment-mask-list
uint32_t mask = 0;
bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false };
MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments);
MOZ_ASSERT( colorAttachmentCount <= WebGLContext::sMaxColorAttachments );
for (size_t i = 0; i < colorAttachmentCount; i++)
{
colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedImageData();
if (colorAttachmentsMask[i]) {
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
for (size_t i = 0; i < colorAttachmentCount; i++) {
if (mColorAttachments[i].HasUninitializedImageData()) {
colorAttachmentsMask[i] = true;
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
}
}
@ -479,10 +600,11 @@ WebGLFramebuffer::CheckAndInitializeAttachments()
mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
}
// Clear!
mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
for (size_t i = 0; i < colorAttachmentCount; i++)
{
// Mark all the uninitialized images as initialized.
for (size_t i = 0; i < colorAttachmentCount; i++) {
if (mColorAttachments[i].HasUninitializedImageData())
mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
}
@ -497,30 +619,25 @@ WebGLFramebuffer::CheckAndInitializeAttachments()
return true;
}
bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char * functionName) const
bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char* functionName) const
{
const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers))
{
if (mContext->IsExtensionEnabled(WebGLContext::WEBGL_draw_buffers)) {
if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
{
mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
return false;
}
}
else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
{
} else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) {
if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 &&
attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
{
mContext->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. "
"Try the WEBGL_draw_buffers extension if supported.", functionName, attachment);
return false;
}
else
{
} else {
mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
return false;
}
@ -529,14 +646,13 @@ bool WebGLFramebuffer::CheckColorAttachementNumber(GLenum attachment, const char
return true;
}
void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) {
void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
{
MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments);
size_t currentAttachmentCount = mColorAttachments.Length();
if (mColorAttachments.Length() > colorAttachmentId) {
if (colorAttachmentId < currentAttachmentCount)
return;
}
MOZ_ASSERT( colorAttachmentId < WebGLContext::sMaxColorAttachments );
mColorAttachments.SetLength(colorAttachmentId + 1);
@ -546,7 +662,8 @@ void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId) {
}
void
WebGLFramebuffer::FinalizeAttachments() const {
WebGLFramebuffer::FinalizeAttachments() const
{
for (size_t i = 0; i < ColorAttachmentCount(); i++) {
if (ColorAttachment(i).IsDefined())
ColorAttachment(i).FinalizeAttachment(LOCAL_GL_COLOR_ATTACHMENT0 + i);

View File

@ -27,7 +27,7 @@ class WebGLFramebuffer MOZ_FINAL
, public WebGLContextBoundObject
{
public:
WebGLFramebuffer(WebGLContext *context);
WebGLFramebuffer(WebGLContext* context);
~WebGLFramebuffer() {
DeleteOnce();
@ -54,21 +54,21 @@ public:
bool HasAlpha() const;
void SetTexImage(WebGLTexture *tex, GLenum target, GLint level);
void SetRenderbuffer(WebGLRenderbuffer *rb) {
void SetTexImage(WebGLTexture* tex, GLenum target, GLint level);
void SetRenderbuffer(WebGLRenderbuffer* rb) {
mTexturePtr = nullptr;
mRenderbufferPtr = rb;
}
const WebGLTexture *Texture() const {
const WebGLTexture* Texture() const {
return mTexturePtr;
}
WebGLTexture *Texture() {
WebGLTexture* Texture() {
return mTexturePtr;
}
const WebGLRenderbuffer *Renderbuffer() const {
const WebGLRenderbuffer* Renderbuffer() const {
return mRenderbufferPtr;
}
WebGLRenderbuffer *Renderbuffer() {
WebGLRenderbuffer* Renderbuffer() {
return mRenderbufferPtr;
}
GLenum TexImageTarget() const {
@ -86,9 +86,9 @@ public:
mRenderbufferPtr = nullptr;
}
const WebGLRectangleObject* RectangleObject() const;
bool HasSameDimensionsAs(const Attachment& other) const;
const WebGLRectangleObject& RectangleObject() const;
bool HasImage() const;
bool IsComplete() const;
void FinalizeAttachment(GLenum attachmentLoc) const;
@ -103,15 +103,23 @@ public:
void FramebufferRenderbuffer(GLenum target,
GLenum attachment,
GLenum rbtarget,
WebGLRenderbuffer *wrb);
WebGLRenderbuffer* wrb);
void FramebufferTexture2D(GLenum target,
GLenum attachment,
GLenum textarget,
WebGLTexture *wtex,
WebGLTexture* wtex,
GLint level);
bool HasIncompleteAttachment() const;
private:
const WebGLRectangleObject& GetAnyRectObject() const;
public:
bool HasDefinedAttachments() const;
bool HasIncompleteAttachments() const;
bool AllImageRectsMatch() const;
GLenum PrecheckFramebufferStatus() const;
GLenum CheckFramebufferStatus() const;
bool HasDepthStencilConflict() const {
return int(mDepthAttachment.IsDefined()) +
@ -119,12 +127,10 @@ public:
int(mDepthStencilAttachment.IsDefined()) >= 2;
}
bool HasAttachmentsOfMismatchedDimensions() const;
const size_t ColorAttachmentCount() const {
size_t ColorAttachmentCount() const {
return mColorAttachments.Length();
}
const Attachment& ColorAttachment(uint32_t colorAttachmentId) const {
const Attachment& ColorAttachment(size_t colorAttachmentId) const {
return mColorAttachments[colorAttachmentId];
}
@ -142,21 +148,19 @@ public:
const Attachment& GetAttachment(GLenum attachment) const;
void DetachTexture(const WebGLTexture *tex);
void DetachTexture(const WebGLTexture* tex);
void DetachRenderbuffer(const WebGLRenderbuffer *rb);
void DetachRenderbuffer(const WebGLRenderbuffer* rb);
const WebGLRectangleObject *RectangleObject() {
return mColorAttachments[0].RectangleObject();
}
const WebGLRectangleObject& RectangleObject() const;
WebGLContext *GetParentObject() const {
WebGLContext* GetParentObject() const {
return Context();
}
void FinalizeAttachments() const;
virtual JSObject* WrapObject(JSContext *cx,
virtual JSObject* WrapObject(JSContext* cx,
JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
@ -164,7 +168,7 @@ public:
bool CheckAndInitializeAttachments();
bool CheckColorAttachementNumber(GLenum attachment, const char * functionName) const;
bool CheckColorAttachementNumber(GLenum attachment, const char* functionName) const;
GLuint mGLName;
bool mHasEverBeenBound;