1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLFramebuffer.h"
9 #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 #include "WebGLContext.h"
11 #include "WebGLContextUtils.h"
12 #include "WebGLExtensions.h"
13 #include "WebGLRenderbuffer.h"
14 #include "WebGLTexture.h"
19 WebGLFramebuffer::WrapObject(JSContext
* cx
)
21 return dom::WebGLFramebufferBinding::Wrap(cx
, this);
24 WebGLFramebuffer::WebGLFramebuffer(WebGLContext
* webgl
, GLuint fbo
)
25 : WebGLBindableName
<FBTarget
>(fbo
)
26 , WebGLContextBoundObject(webgl
)
28 , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT
)
29 , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT
)
30 , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
32 mContext
->mFramebuffers
.insertBack(this);
34 mColorAttachments
.SetLength(1);
35 mColorAttachments
[0].mAttachmentPoint
= LOCAL_GL_COLOR_ATTACHMENT0
;
38 WebGLFramebuffer::Attachment::Attachment(FBAttachment attachmentPoint
)
39 : mAttachmentPoint(attachmentPoint
)
40 , mTexImageTarget(LOCAL_GL_NONE
)
41 , mNeedsFinalize(false)
44 WebGLFramebuffer::Attachment::~Attachment()
48 WebGLFramebuffer::Attachment::Reset()
50 mTexturePtr
= nullptr;
51 mRenderbufferPtr
= nullptr;
55 WebGLFramebuffer::Attachment::IsDeleteRequested() const
57 return Texture() ? Texture()->IsDeleteRequested()
58 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
63 WebGLFramebuffer::Attachment::IsDefined() const
65 return Renderbuffer() ||
66 (Texture() && Texture()->HasImageInfoAt(ImageTarget(), 0));
70 WebGLFramebuffer::Attachment::HasAlpha() const
72 MOZ_ASSERT(HasImage());
75 Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
))
77 return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget
,
78 mTexImageLevel
).EffectiveInternalFormat());
82 return FormatHasAlpha(Renderbuffer()->InternalFormat());
88 WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment
& attachment
) const
90 MOZ_ASSERT(attachment
.IsDefined());
91 MOZ_ASSERT(attachment
.Texture() || attachment
.Renderbuffer());
93 if (attachment
.Texture()) {
94 const WebGLTexture
& tex
= *attachment
.Texture();
95 MOZ_ASSERT(tex
.HasImageInfoAt(attachment
.ImageTarget(), 0));
97 const WebGLTexture::ImageInfo
& imgInfo
= tex
.ImageInfoAt(attachment
.ImageTarget(),
99 return imgInfo
.EffectiveInternalFormat().get();
102 if (attachment
.Renderbuffer())
103 return attachment
.Renderbuffer()->InternalFormat();
105 return LOCAL_GL_NONE
;
109 WebGLFramebuffer::Attachment::EffectiveInternalFormat() const
111 const WebGLTexture
* tex
= Texture();
112 if (tex
&& tex
->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
)) {
113 return tex
->ImageInfoAt(mTexImageTarget
,
114 mTexImageLevel
).EffectiveInternalFormat();
117 const WebGLRenderbuffer
* rb
= Renderbuffer();
119 return rb
->InternalFormat();
121 return LOCAL_GL_NONE
;
125 WebGLFramebuffer::Attachment::IsReadableFloat() const
127 TexInternalFormat internalformat
= EffectiveInternalFormat();
128 MOZ_ASSERT(internalformat
!= LOCAL_GL_NONE
);
129 TexType type
= TypeFromInternalFormat(internalformat
);
130 return type
== LOCAL_GL_FLOAT
||
131 type
== LOCAL_GL_HALF_FLOAT
;
135 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture
* tex
,
136 TexImageTarget target
, GLint level
)
139 mRenderbufferPtr
= nullptr;
140 mTexImageTarget
= target
;
141 mTexImageLevel
= level
;
143 mNeedsFinalize
= true;
147 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer
* rb
)
149 mTexturePtr
= nullptr;
150 mRenderbufferPtr
= rb
;
152 mNeedsFinalize
= true;
156 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
162 return Renderbuffer()->HasUninitializedImageData();
165 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
166 return Texture()->ImageInfoAt(mTexImageTarget
,
167 mTexImageLevel
).HasUninitializedImageData();
170 MOZ_ASSERT(false, "Should not get here.");
175 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus
)
180 if (Renderbuffer()) {
181 Renderbuffer()->SetImageDataStatus(newStatus
);
186 Texture()->SetImageDataStatus(mTexImageTarget
, mTexImageLevel
,
191 MOZ_ASSERT(false, "Should not get here.");
195 WebGLFramebuffer::Attachment::HasImage() const
197 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
))
206 const WebGLRectangleObject
&
207 WebGLFramebuffer::Attachment::RectangleObject() const
209 MOZ_ASSERT(HasImage(),
210 "Make sure it has an image before requesting the rectangle.");
213 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
214 return Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
);
218 return *Renderbuffer();
220 MOZ_CRASH("Should not get here.");
223 // The following IsValidFBOTextureXXX functions check the internal format that
224 // is used by GL or GL ES texture formats. This corresponds to the state that
225 // is stored in WebGLTexture::ImageInfo::InternalFormat()
228 IsValidFBOTextureDepthFormat(GLenum internalformat
)
230 return IsGLDepthFormat(internalformat
);
234 IsValidFBOTextureDepthStencilFormat(GLenum internalformat
)
236 return IsGLDepthStencilFormat(internalformat
);
239 // The following IsValidFBORenderbufferXXX functions check the internal format
240 // that is stored by WebGLRenderbuffer::InternalFormat(). Valid values can be
241 // found in WebGLContext::RenderbufferStorage.
244 IsValidFBORenderbufferDepthFormat(GLenum internalFormat
)
246 return internalFormat
== LOCAL_GL_DEPTH_COMPONENT16
;
250 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat
)
252 return internalFormat
== LOCAL_GL_DEPTH_STENCIL
;
256 IsValidFBORenderbufferStencilFormat(GLenum internalFormat
)
258 return internalFormat
== LOCAL_GL_STENCIL_INDEX8
;
262 WebGLContext::IsFormatValidForFB(GLenum sizedFormat
) const
264 switch (sizedFormat
) {
265 case LOCAL_GL_ALPHA8
:
266 case LOCAL_GL_LUMINANCE8
:
267 case LOCAL_GL_LUMINANCE8_ALPHA8
:
270 case LOCAL_GL_RGB565
:
271 case LOCAL_GL_RGB5_A1
:
276 case LOCAL_GL_SRGB8_ALPHA8_EXT
:
277 return IsExtensionEnabled(WebGLExtensionID::EXT_sRGB
);
279 case LOCAL_GL_RGB32F
:
280 case LOCAL_GL_RGBA32F
:
281 return IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
);
283 case LOCAL_GL_RGB16F
:
284 case LOCAL_GL_RGBA16F
:
285 return IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
);
292 WebGLFramebuffer::Attachment::IsComplete() const
297 const WebGLRectangleObject
& rect
= RectangleObject();
306 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
307 const WebGLTexture::ImageInfo
& imageInfo
=
308 Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
);
309 GLenum sizedFormat
= imageInfo
.EffectiveInternalFormat().get();
311 if (mAttachmentPoint
== LOCAL_GL_DEPTH_ATTACHMENT
)
312 return IsValidFBOTextureDepthFormat(sizedFormat
);
314 if (mAttachmentPoint
== LOCAL_GL_STENCIL_ATTACHMENT
) {
315 // Textures can't have the correct format for stencil buffers.
319 if (mAttachmentPoint
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
320 return IsValidFBOTextureDepthStencilFormat(sizedFormat
);
322 if (mAttachmentPoint
>= LOCAL_GL_COLOR_ATTACHMENT0
&&
323 mAttachmentPoint
<= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0
- 1 +
324 WebGLContext::kMaxColorAttachments
))
326 WebGLContext
* webgl
= Texture()->Context();
327 return webgl
->IsFormatValidForFB(sizedFormat
);
329 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
333 if (Renderbuffer()) {
334 GLenum internalFormat
= Renderbuffer()->InternalFormat();
336 if (mAttachmentPoint
== LOCAL_GL_DEPTH_ATTACHMENT
)
337 return IsValidFBORenderbufferDepthFormat(internalFormat
);
339 if (mAttachmentPoint
== LOCAL_GL_STENCIL_ATTACHMENT
)
340 return IsValidFBORenderbufferStencilFormat(internalFormat
);
342 if (mAttachmentPoint
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
343 return IsValidFBORenderbufferDepthStencilFormat(internalFormat
);
345 if (mAttachmentPoint
>= LOCAL_GL_COLOR_ATTACHMENT0
&&
346 mAttachmentPoint
<= FBAttachment(LOCAL_GL_COLOR_ATTACHMENT0
- 1 +
347 WebGLContext::kMaxColorAttachments
))
349 WebGLContext
* webgl
= Renderbuffer()->Context();
350 return webgl
->IsFormatValidForFB(internalFormat
);
352 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
355 MOZ_ASSERT(false, "Should not get here.");
360 WebGLFramebuffer::Attachment::FinalizeAttachment(gl::GLContext
* gl
,
361 FBAttachment attachmentLoc
) const
366 mNeedsFinalize
= false;
369 if (attachmentLoc
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
370 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
371 LOCAL_GL_DEPTH_ATTACHMENT
,
372 LOCAL_GL_RENDERBUFFER
, 0);
373 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
374 LOCAL_GL_STENCIL_ATTACHMENT
,
375 LOCAL_GL_RENDERBUFFER
, 0);
377 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
,
379 LOCAL_GL_RENDERBUFFER
, 0);
384 MOZ_ASSERT(HasImage());
387 MOZ_ASSERT(gl
== Texture()->Context()->GL());
389 const GLenum imageTarget
= ImageTarget().get();
390 const GLint mipLevel
= MipLevel();
391 const GLuint glName
= Texture()->GLName();
393 if (attachmentLoc
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
394 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
,
395 LOCAL_GL_DEPTH_ATTACHMENT
, imageTarget
,
397 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
,
398 LOCAL_GL_STENCIL_ATTACHMENT
, imageTarget
,
401 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, attachmentLoc
.get(),
402 imageTarget
, glName
, mipLevel
);
407 if (Renderbuffer()) {
408 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc
);
412 MOZ_ASSERT(false, "Should not get here.");
416 WebGLFramebuffer::Delete()
418 DetachAllAttachments();
419 mColorAttachments
.Clear();
420 mDepthAttachment
.Reset();
421 mStencilAttachment
.Reset();
422 mDepthStencilAttachment
.Reset();
424 mContext
->MakeContextCurrent();
425 mContext
->gl
->fDeleteFramebuffers(1, &mGLName
);
426 LinkedListElement
<WebGLFramebuffer
>::removeFrom(mContext
->mFramebuffers
);
430 WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment
& attachment
)
432 if (attachment
.Texture())
433 attachment
.Texture()->DetachFrom(this, attachment
.mAttachmentPoint
);
435 if (attachment
.Renderbuffer()) {
436 attachment
.Renderbuffer()->DetachFrom(this,
437 attachment
.mAttachmentPoint
);
442 WebGLFramebuffer::DetachAllAttachments()
444 for (size_t i
= 0; i
< mColorAttachments
.Length(); i
++) {
445 DetachAttachment(mColorAttachments
[i
]);
448 DetachAttachment(mDepthAttachment
);
449 DetachAttachment(mStencilAttachment
);
450 DetachAttachment(mDepthStencilAttachment
);
454 WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPoint
,
456 WebGLRenderbuffer
* rb
)
458 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
460 if (!mContext
->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer",
466 /* Get the requested attachment. If result is NULL, attachment is invalid
467 * and an error is generated.
469 * Don't use GetAttachment(...) here because it opt builds it returns
470 * mColorAttachment[0] for invalid attachment, which we really don't want to
473 Attachment
* attachment
= GetAttachmentOrNull(attachPoint
);
475 return; // Error generated internally to GetAttachmentOrNull.
477 // Invalidate cached framebuffer status and inform texture of its new
482 if (attachment
->Texture())
483 attachment
->Texture()->DetachFrom(this, attachPoint
);
484 else if (attachment
->Renderbuffer())
485 attachment
->Renderbuffer()->DetachFrom(this, attachPoint
);
489 rb
->AttachTo(this, attachPoint
);
491 attachment
->SetRenderbuffer(rb
);
495 WebGLFramebuffer::FramebufferTexture2D(FBAttachment attachPoint
,
496 TexImageTarget texImageTarget
,
497 WebGLTexture
* tex
, GLint level
)
499 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
501 if (!mContext
->ValidateObjectAllowNull("framebufferTexture2D: texture",
508 bool isTexture2D
= tex
->Target() == LOCAL_GL_TEXTURE_2D
;
509 bool isTexTarget2D
= texImageTarget
== LOCAL_GL_TEXTURE_2D
;
510 if (isTexture2D
!= isTexTarget2D
) {
511 mContext
->ErrorInvalidOperation("framebufferTexture2D: Mismatched"
512 " texture and texture target.");
518 mContext
->ErrorInvalidValue("framebufferTexture2D: Level must be 0.");
522 /* Get the requested attachment. If result is NULL, attachment is invalid
523 * and an error is generated.
525 * Don't use GetAttachment(...) here because it opt builds it returns
526 * mColorAttachment[0] for invalid attachment, which we really don't want to
529 Attachment
* attachment
= GetAttachmentOrNull(attachPoint
);
531 return; // Error generated internally to GetAttachmentOrNull.
533 // Invalidate cached framebuffer status and inform texture of its new
538 if (attachment
->Texture())
539 attachment
->Texture()->DetachFrom(this, attachPoint
);
540 else if (attachment
->Renderbuffer())
541 attachment
->Renderbuffer()->DetachFrom(this, attachPoint
);
545 tex
->AttachTo(this, attachPoint
);
547 attachment
->SetTexImage(tex
, texImageTarget
, level
);
550 WebGLFramebuffer::Attachment
*
551 WebGLFramebuffer::GetAttachmentOrNull(FBAttachment attachPoint
)
553 switch (attachPoint
.get()) {
554 case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
:
555 return &mDepthStencilAttachment
;
557 case LOCAL_GL_DEPTH_ATTACHMENT
:
558 return &mDepthAttachment
;
560 case LOCAL_GL_STENCIL_ATTACHMENT
:
561 return &mStencilAttachment
;
567 if (!mContext
->ValidateFramebufferAttachment(attachPoint
.get(),
568 "getAttachmentOrNull"))
573 size_t colorAttachmentId
= attachPoint
.get() - LOCAL_GL_COLOR_ATTACHMENT0
;
574 EnsureColorAttachments(colorAttachmentId
);
576 return &mColorAttachments
[colorAttachmentId
];
579 const WebGLFramebuffer::Attachment
&
580 WebGLFramebuffer::GetAttachment(FBAttachment attachPoint
) const
582 switch (attachPoint
.get()) {
583 case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
:
584 return mDepthStencilAttachment
;
586 case LOCAL_GL_DEPTH_ATTACHMENT
:
587 return mDepthAttachment
;
589 case LOCAL_GL_STENCIL_ATTACHMENT
:
590 return mStencilAttachment
;
596 if (!mContext
->ValidateFramebufferAttachment(attachPoint
.get(),
600 return mColorAttachments
[0];
603 size_t colorAttachmentId
= attachPoint
.get() - LOCAL_GL_COLOR_ATTACHMENT0
;
604 if (colorAttachmentId
>= mColorAttachments
.Length()) {
606 return mColorAttachments
[0];
609 return mColorAttachments
[colorAttachmentId
];
613 WebGLFramebuffer::DetachTexture(const WebGLTexture
* tex
)
615 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
616 if (mColorAttachments
[i
].Texture() == tex
) {
617 FramebufferTexture2D(LOCAL_GL_COLOR_ATTACHMENT0
+i
,
618 LOCAL_GL_TEXTURE_2D
, nullptr, 0);
619 // It might be attached in multiple places, so don't break.
623 if (mDepthAttachment
.Texture() == tex
) {
624 FramebufferTexture2D(LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_TEXTURE_2D
,
627 if (mStencilAttachment
.Texture() == tex
) {
628 FramebufferTexture2D(LOCAL_GL_STENCIL_ATTACHMENT
, LOCAL_GL_TEXTURE_2D
,
631 if (mDepthStencilAttachment
.Texture() == tex
) {
632 FramebufferTexture2D(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
,
633 LOCAL_GL_TEXTURE_2D
, nullptr, 0);
638 WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer
* rb
)
640 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
641 if (mColorAttachments
[i
].Renderbuffer() == rb
) {
642 FramebufferRenderbuffer(LOCAL_GL_COLOR_ATTACHMENT0
+i
,
643 LOCAL_GL_RENDERBUFFER
, nullptr);
644 // It might be attached in multiple places, so don't break.
648 if (mDepthAttachment
.Renderbuffer() == rb
) {
649 FramebufferRenderbuffer(LOCAL_GL_DEPTH_ATTACHMENT
,
650 LOCAL_GL_RENDERBUFFER
, nullptr);
652 if (mStencilAttachment
.Renderbuffer() == rb
) {
653 FramebufferRenderbuffer(LOCAL_GL_STENCIL_ATTACHMENT
,
654 LOCAL_GL_RENDERBUFFER
, nullptr);
656 if (mDepthStencilAttachment
.Renderbuffer() == rb
) {
657 FramebufferRenderbuffer(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
,
658 LOCAL_GL_RENDERBUFFER
, nullptr);
663 WebGLFramebuffer::HasDefinedAttachments() const
665 bool hasAttachments
= false;
667 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
668 hasAttachments
|= mColorAttachments
[i
].IsDefined();
671 hasAttachments
|= mDepthAttachment
.IsDefined();
672 hasAttachments
|= mStencilAttachment
.IsDefined();
673 hasAttachments
|= mDepthStencilAttachment
.IsDefined();
675 return hasAttachments
;
679 IsIncomplete(const WebGLFramebuffer::Attachment
& cur
)
681 return cur
.IsDefined() && !cur
.IsComplete();
685 WebGLFramebuffer::HasIncompleteAttachments() const
687 bool hasIncomplete
= false;
689 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
690 hasIncomplete
|= IsIncomplete(mColorAttachments
[i
]);
693 hasIncomplete
|= IsIncomplete(mDepthAttachment
);
694 hasIncomplete
|= IsIncomplete(mStencilAttachment
);
695 hasIncomplete
|= IsIncomplete(mDepthStencilAttachment
);
697 return hasIncomplete
;
700 const WebGLRectangleObject
&
701 WebGLFramebuffer::GetAnyRectObject() const
703 MOZ_ASSERT(HasDefinedAttachments());
705 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
706 if (mColorAttachments
[i
].HasImage())
707 return mColorAttachments
[i
].RectangleObject();
710 if (mDepthAttachment
.HasImage())
711 return mDepthAttachment
.RectangleObject();
713 if (mStencilAttachment
.HasImage())
714 return mStencilAttachment
.RectangleObject();
716 if (mDepthStencilAttachment
.HasImage())
717 return mDepthStencilAttachment
.RectangleObject();
719 MOZ_CRASH("Should not get here.");
723 RectsMatch(const WebGLFramebuffer::Attachment
& attachment
,
724 const WebGLRectangleObject
& rect
)
726 return attachment
.RectangleObject().HasSameDimensionsAs(rect
);
730 WebGLFramebuffer::AllImageRectsMatch() const
732 MOZ_ASSERT(HasDefinedAttachments());
733 MOZ_ASSERT(!HasIncompleteAttachments());
735 const WebGLRectangleObject
& rect
= GetAnyRectObject();
737 // Alright, we have *a* rect, let's check all the others.
738 bool imageRectsMatch
= true;
740 for (size_t i
= 0; i
< (size_t)mColorAttachments
.Length(); i
++) {
741 if (mColorAttachments
[i
].HasImage())
742 imageRectsMatch
&= RectsMatch(mColorAttachments
[i
], rect
);
745 if (mDepthAttachment
.HasImage())
746 imageRectsMatch
&= RectsMatch(mDepthAttachment
, rect
);
748 if (mStencilAttachment
.HasImage())
749 imageRectsMatch
&= RectsMatch(mStencilAttachment
, rect
);
751 if (mDepthStencilAttachment
.HasImage())
752 imageRectsMatch
&= RectsMatch(mDepthStencilAttachment
, rect
);
754 return imageRectsMatch
;
757 const WebGLRectangleObject
&
758 WebGLFramebuffer::RectangleObject() const
760 // If we're using this as the RectObj of an FB, we need to be sure the FB
761 // has a consistent rect.
762 MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
763 return GetAnyRectObject();
767 WebGLFramebuffer::PrecheckFramebufferStatus() const
769 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
771 if (!HasDefinedAttachments())
772 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
; // No attachments
774 if (HasIncompleteAttachments())
775 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
777 if (!AllImageRectsMatch())
778 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
; // Inconsistent sizes
780 if (HasDepthStencilConflict())
781 return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED
;
783 return LOCAL_GL_FRAMEBUFFER_COMPLETE
;
787 WebGLFramebuffer::CheckFramebufferStatus() const
792 mStatus
= PrecheckFramebufferStatus().get();
793 if (mStatus
!= LOCAL_GL_FRAMEBUFFER_COMPLETE
)
796 // Looks good on our end. Let's ask the driver.
797 mContext
->MakeContextCurrent();
799 // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
800 FinalizeAttachments();
802 mStatus
= mContext
->gl
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
807 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask
)
809 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE
)
812 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
813 bool hasPlanes
= true;
814 if (mask
& LOCAL_GL_COLOR_BUFFER_BIT
) {
815 hasPlanes
&= ColorAttachmentCount() &&
816 ColorAttachment(0).IsDefined();
819 if (mask
& LOCAL_GL_DEPTH_BUFFER_BIT
) {
820 hasPlanes
&= DepthAttachment().IsDefined() ||
821 DepthStencilAttachment().IsDefined();
824 if (mask
& LOCAL_GL_STENCIL_BUFFER_BIT
) {
825 hasPlanes
&= StencilAttachment().IsDefined() ||
826 DepthStencilAttachment().IsDefined();
833 WebGLFramebuffer::CheckAndInitializeAttachments()
835 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
837 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE
)
840 // Cool! We've checked out ok. Just need to initialize.
841 const size_t colorAttachmentCount
= mColorAttachments
.Length();
843 // Check if we need to initialize anything
845 bool hasUninitializedAttachments
= false;
847 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
848 if (mColorAttachments
[i
].HasImage())
849 hasUninitializedAttachments
|= mColorAttachments
[i
].HasUninitializedImageData();
852 if (mDepthAttachment
.HasImage())
853 hasUninitializedAttachments
|= mDepthAttachment
.HasUninitializedImageData();
854 if (mStencilAttachment
.HasImage())
855 hasUninitializedAttachments
|= mStencilAttachment
.HasUninitializedImageData();
856 if (mDepthStencilAttachment
.HasImage())
857 hasUninitializedAttachments
|= mDepthStencilAttachment
.HasUninitializedImageData();
859 if (!hasUninitializedAttachments
)
863 // Get buffer-bit-mask and color-attachment-mask-list
865 bool colorAttachmentsMask
[WebGLContext::kMaxColorAttachments
] = { false };
866 MOZ_ASSERT(colorAttachmentCount
<= WebGLContext::kMaxColorAttachments
);
868 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
869 if (mColorAttachments
[i
].HasUninitializedImageData()) {
870 colorAttachmentsMask
[i
] = true;
871 mask
|= LOCAL_GL_COLOR_BUFFER_BIT
;
875 if (mDepthAttachment
.HasUninitializedImageData() ||
876 mDepthStencilAttachment
.HasUninitializedImageData())
878 mask
|= LOCAL_GL_DEPTH_BUFFER_BIT
;
881 if (mStencilAttachment
.HasUninitializedImageData() ||
882 mDepthStencilAttachment
.HasUninitializedImageData())
884 mask
|= LOCAL_GL_STENCIL_BUFFER_BIT
;
888 mContext
->ForceClearFramebufferWithDefaultValues(mask
, colorAttachmentsMask
);
890 // Mark all the uninitialized images as initialized.
891 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
892 if (mColorAttachments
[i
].HasUninitializedImageData())
893 mColorAttachments
[i
].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
896 if (mDepthAttachment
.HasUninitializedImageData())
897 mDepthAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
898 if (mStencilAttachment
.HasUninitializedImageData())
899 mStencilAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
900 if (mDepthStencilAttachment
.HasUninitializedImageData())
901 mDepthStencilAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
906 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId
)
908 MOZ_ASSERT(colorAttachmentId
< WebGLContext::kMaxColorAttachments
);
910 size_t currentAttachmentCount
= mColorAttachments
.Length();
911 if (colorAttachmentId
< currentAttachmentCount
)
914 mColorAttachments
.SetLength(colorAttachmentId
+ 1);
916 for (size_t i
= colorAttachmentId
; i
>= currentAttachmentCount
; i
--) {
917 mColorAttachments
[i
].mAttachmentPoint
= LOCAL_GL_COLOR_ATTACHMENT0
+ i
;
922 WebGLFramebuffer::NotifyAttachableChanged() const
924 // Attachment has changed, so invalidate cached status
929 FinalizeDrawAndReadBuffers(gl::GLContext
* gl
, bool isColorBufferDefined
)
931 MOZ_ASSERT(gl
, "Expected a valid GLContext ptr.");
932 // GLES don't support DrawBuffer()/ReadBuffer.
933 // According to http://www.opengl.org/wiki/Framebuffer_Object
935 // Each draw buffers must either specify color attachment points that have images
936 // attached or must be GL_NONE. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER when false).
938 // If the read buffer is set, then it must specify an attachment point that has an
939 // image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER when false).
941 // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
944 gl
->IsSupported(gl::GLFeature::ES2_compatibility
) ||
945 gl
->IsAtLeast(gl::ContextProfile::OpenGL
, 420))
950 // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL.
951 GLenum colorBufferSource
= isColorBufferDefined
? LOCAL_GL_COLOR_ATTACHMENT0
953 gl
->fDrawBuffer(colorBufferSource
);
954 gl
->fReadBuffer(colorBufferSource
);
958 WebGLFramebuffer::FinalizeAttachments() const
960 gl::GLContext
* gl
= mContext
->gl
;
962 for (size_t i
= 0; i
< ColorAttachmentCount(); i
++) {
963 ColorAttachment(i
).FinalizeAttachment(gl
, LOCAL_GL_COLOR_ATTACHMENT0
+i
);
966 DepthAttachment().FinalizeAttachment(gl
, LOCAL_GL_DEPTH_ATTACHMENT
);
967 StencilAttachment().FinalizeAttachment(gl
, LOCAL_GL_STENCIL_ATTACHMENT
);
968 DepthStencilAttachment().FinalizeAttachment(gl
,
969 LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
);
971 FinalizeDrawAndReadBuffers(gl
, ColorAttachment(0).IsDefined());
975 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment
& field
)
977 field
.mTexturePtr
= nullptr;
978 field
.mRenderbufferPtr
= nullptr;
982 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& callback
,
983 mozilla::WebGLFramebuffer::Attachment
& field
,
987 CycleCollectionNoteChild(callback
, field
.mTexturePtr
.get(), name
, flags
);
988 CycleCollectionNoteChild(callback
, field
.mRenderbufferPtr
.get(), name
,
992 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer
,
996 mDepthStencilAttachment
)
998 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer
, AddRef
)
999 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer
, Release
)
1001 } // namespace mozilla