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 "WebGLContext.h"
7 #include "WebGLFramebuffer.h"
8 #include "WebGLExtensions.h"
9 #include "WebGLRenderbuffer.h"
10 #include "WebGLTexture.h"
11 #include "mozilla/dom/WebGLRenderingContextBinding.h"
12 #include "WebGLTexture.h"
13 #include "WebGLRenderbuffer.h"
14 #include "GLContext.h"
15 #include "WebGLContextUtils.h"
17 using namespace mozilla
;
18 using namespace mozilla::gl
;
21 WebGLFramebuffer::WrapObject(JSContext
* cx
)
23 return dom::WebGLFramebufferBinding::Wrap(cx
, this);
26 WebGLFramebuffer::WebGLFramebuffer(WebGLContext
* context
)
28 , WebGLContextBoundObject(context
)
30 , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT
)
31 , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT
)
32 , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
35 mContext
->MakeContextCurrent();
36 mContext
->gl
->fGenFramebuffers(1, &mGLName
);
37 mContext
->mFramebuffers
.insertBack(this);
39 mColorAttachments
.SetLength(1);
40 mColorAttachments
[0].mAttachmentPoint
= LOCAL_GL_COLOR_ATTACHMENT0
;
43 WebGLFramebuffer::Attachment::Attachment(GLenum aAttachmentPoint
)
44 : mAttachmentPoint(aAttachmentPoint
)
45 , mNeedsFinalize(false)
48 WebGLFramebuffer::Attachment::~Attachment()
52 WebGLFramebuffer::Attachment::Reset()
54 mTexturePtr
= nullptr;
55 mRenderbufferPtr
= nullptr;
59 WebGLFramebuffer::Attachment::IsDeleteRequested() const
61 return Texture() ? Texture()->IsDeleteRequested()
62 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
67 WebGLFramebuffer::Attachment::HasAlpha() const
69 MOZ_ASSERT(HasImage());
72 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
))
73 format
= Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
).WebGLFormat();
74 else if (Renderbuffer())
75 format
= Renderbuffer()->InternalFormat();
76 return FormatHasAlpha(format
);
80 WebGLFramebuffer::GetFormatForAttachment(const WebGLFramebuffer::Attachment
& attachment
) const
82 MOZ_ASSERT(attachment
.IsDefined());
83 MOZ_ASSERT(attachment
.Texture() || attachment
.Renderbuffer());
85 if (attachment
.Texture()) {
86 const WebGLTexture
& tex
= *attachment
.Texture();
87 MOZ_ASSERT(tex
.HasImageInfoAt(tex
.Target(), 0));
89 const WebGLTexture::ImageInfo
& imgInfo
= tex
.ImageInfoAt(tex
.Target(), 0);
90 return imgInfo
.WebGLFormat();
93 if (attachment
.Renderbuffer())
94 return attachment
.Renderbuffer()->InternalFormat();
100 WebGLFramebuffer::Attachment::IsReadableFloat() const
102 const WebGLTexture
* tex
= Texture();
103 if (tex
&& tex
->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
)) {
104 GLenum type
= tex
->ImageInfoAt(mTexImageTarget
, mTexImageLevel
).WebGLType();
107 case LOCAL_GL_HALF_FLOAT_OES
:
113 const WebGLRenderbuffer
* rb
= Renderbuffer();
115 GLenum format
= rb
->InternalFormat();
117 case LOCAL_GL_RGB16F
:
118 case LOCAL_GL_RGBA16F
:
119 case LOCAL_GL_RGB32F
:
120 case LOCAL_GL_RGBA32F
:
126 // If we arrive here Attachment isn't correct setup because it has
127 // no texture nor render buffer pointer.
128 MOZ_ASSERT(false, "Should not get here.");
133 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture
* tex
, GLenum target
, GLint level
)
136 mRenderbufferPtr
= nullptr;
137 mTexImageTarget
= target
;
138 mTexImageLevel
= level
;
140 mNeedsFinalize
= true;
144 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer
* rb
)
146 mTexturePtr
= nullptr;
147 mRenderbufferPtr
= rb
;
149 mNeedsFinalize
= true;
153 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
158 if (Renderbuffer()) {
159 return Renderbuffer()->HasUninitializedImageData();
163 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
164 return Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
).HasUninitializedImageData();
167 MOZ_ASSERT(false, "Should not get here.");
172 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus
)
177 if (Renderbuffer()) {
178 Renderbuffer()->SetImageDataStatus(newStatus
);
183 Texture()->SetImageDataStatus(mTexImageTarget
, mTexImageLevel
, newStatus
);
187 MOZ_ASSERT(false, "Should not get here.");
191 WebGLFramebuffer::Attachment::HasImage() const
193 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
))
202 const WebGLRectangleObject
&
203 WebGLFramebuffer::Attachment::RectangleObject() const
205 MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle.");
208 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
209 return Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
);
212 if (Renderbuffer()) {
213 return *Renderbuffer();
216 MOZ_CRASH("Should not get here.");
219 /* The following IsValidFBOTextureXXX functions check the internal
220 format that is used by GL or GL ES texture formats. This
221 corresponds to the state that is stored in
222 WebGLTexture::ImageInfo::InternalFormat()*/
224 IsValidFBOTextureColorFormat(GLenum internalFormat
)
226 /* These formats are internal formats for each texture -- the actual
227 * low level format, which we might have to do conversions for when
228 * running against desktop GL (e.g. GL_RGBA + GL_FLOAT -> GL_RGBA32F).
230 * This function just handles all of them whether desktop GL or ES.
234 /* linear 8-bit formats */
235 internalFormat
== LOCAL_GL_ALPHA
||
236 internalFormat
== LOCAL_GL_LUMINANCE
||
237 internalFormat
== LOCAL_GL_LUMINANCE_ALPHA
||
238 internalFormat
== LOCAL_GL_RGB
||
239 internalFormat
== LOCAL_GL_RGBA
||
240 /* sRGB 8-bit formats */
241 internalFormat
== LOCAL_GL_SRGB_EXT
||
242 internalFormat
== LOCAL_GL_SRGB_ALPHA_EXT
||
243 /* linear float32 formats */
244 internalFormat
== LOCAL_GL_ALPHA32F_ARB
||
245 internalFormat
== LOCAL_GL_LUMINANCE32F_ARB
||
246 internalFormat
== LOCAL_GL_LUMINANCE_ALPHA32F_ARB
||
247 internalFormat
== LOCAL_GL_RGB32F_ARB
||
248 internalFormat
== LOCAL_GL_RGBA32F_ARB
||
249 /* texture_half_float formats */
250 internalFormat
== LOCAL_GL_ALPHA16F_ARB
||
251 internalFormat
== LOCAL_GL_LUMINANCE16F_ARB
||
252 internalFormat
== LOCAL_GL_LUMINANCE_ALPHA16F_ARB
||
253 internalFormat
== LOCAL_GL_RGB16F_ARB
||
254 internalFormat
== LOCAL_GL_RGBA16F_ARB
259 IsValidFBOTextureDepthFormat(GLenum internalFormat
)
262 internalFormat
== LOCAL_GL_DEPTH_COMPONENT
||
263 internalFormat
== LOCAL_GL_DEPTH_COMPONENT16
||
264 internalFormat
== LOCAL_GL_DEPTH_COMPONENT32
);
268 IsValidFBOTextureDepthStencilFormat(GLenum internalFormat
)
271 internalFormat
== LOCAL_GL_DEPTH_STENCIL
||
272 internalFormat
== LOCAL_GL_DEPTH24_STENCIL8
);
275 /* The following IsValidFBORenderbufferXXX functions check the internal
276 format that is stored by WebGLRenderbuffer::InternalFormat(). Valid
277 values can be found in WebGLContext::RenderbufferStorage. */
279 IsValidFBORenderbufferColorFormat(GLenum internalFormat
)
282 internalFormat
== LOCAL_GL_RGB565
||
283 internalFormat
== LOCAL_GL_RGB5_A1
||
284 internalFormat
== LOCAL_GL_RGBA4
||
285 internalFormat
== LOCAL_GL_SRGB8_ALPHA8_EXT
);
289 IsValidFBORenderbufferDepthFormat(GLenum internalFormat
)
291 return internalFormat
== LOCAL_GL_DEPTH_COMPONENT16
;
295 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat
)
297 return internalFormat
== LOCAL_GL_DEPTH_STENCIL
;
301 IsValidFBORenderbufferStencilFormat(GLenum internalFormat
)
303 return internalFormat
== LOCAL_GL_STENCIL_INDEX8
;
307 WebGLFramebuffer::Attachment::IsComplete() const
312 const WebGLRectangleObject
& rect
= RectangleObject();
321 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget
, mTexImageLevel
));
322 const WebGLTexture::ImageInfo
& imageInfo
=
323 Texture()->ImageInfoAt(mTexImageTarget
, mTexImageLevel
);
324 GLenum webGLFormat
= imageInfo
.WebGLFormat();
326 if (mAttachmentPoint
== LOCAL_GL_DEPTH_ATTACHMENT
)
327 return IsValidFBOTextureDepthFormat(webGLFormat
);
329 if (mAttachmentPoint
== LOCAL_GL_STENCIL_ATTACHMENT
)
330 return false; // Textures can't have the correct format for stencil buffers
332 if (mAttachmentPoint
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
333 return IsValidFBOTextureDepthStencilFormat(webGLFormat
);
336 if (mAttachmentPoint
>= LOCAL_GL_COLOR_ATTACHMENT0
&&
337 mAttachmentPoint
< GLenum(LOCAL_GL_COLOR_ATTACHMENT0
+
338 WebGLContext::kMaxColorAttachments
))
340 return IsValidFBOTextureColorFormat(webGLFormat
);
342 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
346 if (Renderbuffer()) {
347 GLenum internalFormat
= Renderbuffer()->InternalFormat();
349 if (mAttachmentPoint
== LOCAL_GL_DEPTH_ATTACHMENT
)
350 return IsValidFBORenderbufferDepthFormat(internalFormat
);
352 if (mAttachmentPoint
== LOCAL_GL_STENCIL_ATTACHMENT
)
353 return IsValidFBORenderbufferStencilFormat(internalFormat
);
355 if (mAttachmentPoint
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
356 return IsValidFBORenderbufferDepthStencilFormat(internalFormat
);
358 if (mAttachmentPoint
>= LOCAL_GL_COLOR_ATTACHMENT0
&&
359 mAttachmentPoint
< GLenum(LOCAL_GL_COLOR_ATTACHMENT0
+
360 WebGLContext::kMaxColorAttachments
))
362 return IsValidFBORenderbufferColorFormat(internalFormat
);
364 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
368 MOZ_ASSERT(false, "Should not get here.");
373 WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext
* gl
, GLenum attachmentLoc
) const
378 mNeedsFinalize
= false;
381 if (attachmentLoc
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
382 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
,
383 LOCAL_GL_RENDERBUFFER
, 0);
384 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
,
385 LOCAL_GL_RENDERBUFFER
, 0);
387 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, attachmentLoc
,
388 LOCAL_GL_RENDERBUFFER
, 0);
393 MOZ_ASSERT(HasImage());
396 MOZ_ASSERT(gl
== Texture()->Context()->gl
);
398 if (attachmentLoc
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
399 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
,
400 TexImageTarget(), Texture()->GLName(), TexImageLevel());
401 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
,
402 TexImageTarget(), Texture()->GLName(), TexImageLevel());
404 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, attachmentLoc
,
405 TexImageTarget(), Texture()->GLName(), TexImageLevel());
410 if (Renderbuffer()) {
411 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc
);
415 MOZ_ASSERT(false, "Should not get here.");
419 WebGLFramebuffer::Delete()
421 DetachAllAttachments();
422 mColorAttachments
.Clear();
423 mDepthAttachment
.Reset();
424 mStencilAttachment
.Reset();
425 mDepthStencilAttachment
.Reset();
427 mContext
->MakeContextCurrent();
428 mContext
->gl
->fDeleteFramebuffers(1, &mGLName
);
429 LinkedListElement
<WebGLFramebuffer
>::removeFrom(mContext
->mFramebuffers
);
433 WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment
& attachment
)
435 if (attachment
.Texture())
436 attachment
.Texture()->DetachFrom(this, attachment
.mAttachmentPoint
);
438 if (attachment
.Renderbuffer())
439 attachment
.Renderbuffer()->DetachFrom(this, attachment
.mAttachmentPoint
);
443 WebGLFramebuffer::DetachAllAttachments()
445 size_t count
= mColorAttachments
.Length();
446 for (size_t i
= 0; i
< count
; i
++) {
447 DetachAttachment(mColorAttachments
[i
]);
450 DetachAttachment(mDepthAttachment
);
451 DetachAttachment(mStencilAttachment
);
452 DetachAttachment(mDepthStencilAttachment
);
456 WebGLFramebuffer::FramebufferRenderbuffer(GLenum target
,
459 WebGLRenderbuffer
* wrb
)
461 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
463 if (!mContext
->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb
))
466 if (target
!= LOCAL_GL_FRAMEBUFFER
)
467 return mContext
->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target
);
469 if (rbtarget
!= LOCAL_GL_RENDERBUFFER
)
470 return mContext
->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget
);
472 /* Get the requested attachment. If result is NULL, attachment is
473 * invalid and an error is generated.
475 * Don't use GetAttachment(...) here because it opt builds it
476 * returns mColorAttachment[0] for invalid attachment, which we
477 * really don't want to mess with.
479 Attachment
* a
= GetAttachmentOrNull(attachment
);
481 return; // Error generated internally to GetAttachmentOrNull.
483 /* Invalidate cached framebuffer status and inform texture of it's
489 a
->Texture()->DetachFrom(this, attachment
);
490 else if (a
->Renderbuffer())
491 a
->Renderbuffer()->DetachFrom(this, attachment
);
495 wrb
->AttachTo(this, attachment
);
497 a
->SetRenderbuffer(wrb
);
501 WebGLFramebuffer::FramebufferTexture2D(GLenum target
,
507 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
509 if (!mContext
->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex
))
512 if (target
!= LOCAL_GL_FRAMEBUFFER
)
513 return mContext
->ErrorInvalidEnumInfo("framebufferTexture2D: target", target
);
515 if (textarget
!= LOCAL_GL_TEXTURE_2D
&&
516 (textarget
< LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
||
517 textarget
> LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
))
519 return mContext
->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget
);
523 bool isTexture2D
= wtex
->Target() == LOCAL_GL_TEXTURE_2D
;
524 bool isTexTarget2D
= textarget
== LOCAL_GL_TEXTURE_2D
;
525 if (isTexture2D
!= isTexTarget2D
) {
526 return mContext
->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target");
531 return mContext
->ErrorInvalidValue("framebufferTexture2D: level must be 0");
533 /* Get the requested attachment. If result is NULL, attachment is
534 * invalid and an error is generated.
536 * Don't use GetAttachment(...) here because it opt builds it
537 * returns mColorAttachment[0] for invalid attachment, which we
538 * really don't want to mess with.
540 Attachment
* a
= GetAttachmentOrNull(attachment
);
542 return; // Error generated internally to GetAttachmentOrNull.
544 /* Invalidate cached framebuffer status and inform texture of it's
550 a
->Texture()->DetachFrom(this, attachment
);
551 else if (a
->Renderbuffer())
552 a
->Renderbuffer()->DetachFrom(this, attachment
);
556 wtex
->AttachTo(this, attachment
);
558 a
->SetTexImage(wtex
, textarget
, level
);
561 WebGLFramebuffer::Attachment
*
562 WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment
)
564 if (attachment
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
565 return &mDepthStencilAttachment
;
567 if (attachment
== LOCAL_GL_DEPTH_ATTACHMENT
)
568 return &mDepthAttachment
;
570 if (attachment
== LOCAL_GL_STENCIL_ATTACHMENT
)
571 return &mStencilAttachment
;
573 if (!CheckColorAttachmentNumber(attachment
, "getAttachmentOrNull"))
576 size_t colorAttachmentId
= attachment
- LOCAL_GL_COLOR_ATTACHMENT0
;
577 EnsureColorAttachments(colorAttachmentId
);
579 return &mColorAttachments
[colorAttachmentId
];
582 const WebGLFramebuffer::Attachment
&
583 WebGLFramebuffer::GetAttachment(GLenum attachment
) const
585 if (attachment
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
586 return mDepthStencilAttachment
;
587 if (attachment
== LOCAL_GL_DEPTH_ATTACHMENT
)
588 return mDepthAttachment
;
589 if (attachment
== LOCAL_GL_STENCIL_ATTACHMENT
)
590 return mStencilAttachment
;
592 if (!CheckColorAttachmentNumber(attachment
, "getAttachment")) {
594 return mColorAttachments
[0];
597 size_t colorAttachmentId
= attachment
- LOCAL_GL_COLOR_ATTACHMENT0
;
598 if (colorAttachmentId
>= mColorAttachments
.Length()) {
600 return mColorAttachments
[0];
603 return mColorAttachments
[colorAttachmentId
];
607 WebGLFramebuffer::DetachTexture(const WebGLTexture
* tex
)
609 size_t count
= mColorAttachments
.Length();
610 for (size_t i
= 0; i
< count
; i
++) {
611 if (mColorAttachments
[i
].Texture() == tex
) {
612 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
+i
, LOCAL_GL_TEXTURE_2D
, nullptr, 0);
613 // a texture might be attached more that once while editing the framebuffer
617 if (mDepthAttachment
.Texture() == tex
)
618 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_TEXTURE_2D
, nullptr, 0);
619 if (mStencilAttachment
.Texture() == tex
)
620 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
, LOCAL_GL_TEXTURE_2D
, nullptr, 0);
621 if (mDepthStencilAttachment
.Texture() == tex
)
622 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
, LOCAL_GL_TEXTURE_2D
, nullptr, 0);
626 WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer
* rb
)
628 size_t count
= mColorAttachments
.Length();
629 for (size_t i
= 0; i
< count
; i
++) {
630 if (mColorAttachments
[i
].Renderbuffer() == rb
) {
631 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
+i
, LOCAL_GL_RENDERBUFFER
, nullptr);
632 // a renderbuffer might be attached more that once while editing the framebuffer
636 if (mDepthAttachment
.Renderbuffer() == rb
)
637 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, nullptr);
638 if (mStencilAttachment
.Renderbuffer() == rb
)
639 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, nullptr);
640 if (mDepthStencilAttachment
.Renderbuffer() == rb
)
641 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
, LOCAL_GL_RENDERBUFFER
, nullptr);
645 WebGLFramebuffer::HasDefinedAttachments() const
647 bool hasAttachments
= false;
649 size_t count
= mColorAttachments
.Length();
650 for (size_t i
= 0; i
< count
; i
++) {
651 hasAttachments
|= mColorAttachments
[i
].IsDefined();
654 hasAttachments
|= mDepthAttachment
.IsDefined();
655 hasAttachments
|= mStencilAttachment
.IsDefined();
656 hasAttachments
|= mDepthStencilAttachment
.IsDefined();
658 return hasAttachments
;
663 IsIncomplete(const WebGLFramebuffer::Attachment
& cur
)
665 return cur
.IsDefined() && !cur
.IsComplete();
669 WebGLFramebuffer::HasIncompleteAttachments() const
671 bool hasIncomplete
= false;
673 size_t count
= mColorAttachments
.Length();
674 for (size_t i
= 0; i
< count
; i
++) {
675 hasIncomplete
|= IsIncomplete(mColorAttachments
[i
]);
678 hasIncomplete
|= IsIncomplete(mDepthAttachment
);
679 hasIncomplete
|= IsIncomplete(mStencilAttachment
);
680 hasIncomplete
|= IsIncomplete(mDepthStencilAttachment
);
682 return hasIncomplete
;
686 const WebGLRectangleObject
&
687 WebGLFramebuffer::GetAnyRectObject() const
689 MOZ_ASSERT(HasDefinedAttachments());
691 size_t count
= mColorAttachments
.Length();
692 for (size_t i
= 0; i
< count
; i
++) {
693 if (mColorAttachments
[i
].HasImage())
694 return mColorAttachments
[i
].RectangleObject();
697 if (mDepthAttachment
.HasImage())
698 return mDepthAttachment
.RectangleObject();
700 if (mStencilAttachment
.HasImage())
701 return mStencilAttachment
.RectangleObject();
703 if (mDepthStencilAttachment
.HasImage())
704 return mDepthStencilAttachment
.RectangleObject();
706 MOZ_CRASH("Should not get here.");
711 RectsMatch(const WebGLFramebuffer::Attachment
& attachment
,
712 const WebGLRectangleObject
& rect
)
714 return attachment
.RectangleObject().HasSameDimensionsAs(rect
);
718 WebGLFramebuffer::AllImageRectsMatch() const
720 MOZ_ASSERT(HasDefinedAttachments());
721 MOZ_ASSERT(!HasIncompleteAttachments());
723 const WebGLRectangleObject
& rect
= GetAnyRectObject();
725 // Alright, we have *a* rect, let's check all the others.
726 bool imageRectsMatch
= true;
728 size_t count
= mColorAttachments
.Length();
729 for (size_t i
= 0; i
< count
; i
++) {
730 if (mColorAttachments
[i
].HasImage())
731 imageRectsMatch
&= RectsMatch(mColorAttachments
[i
], rect
);
734 if (mDepthAttachment
.HasImage())
735 imageRectsMatch
&= RectsMatch(mDepthAttachment
, rect
);
737 if (mStencilAttachment
.HasImage())
738 imageRectsMatch
&= RectsMatch(mStencilAttachment
, rect
);
740 if (mDepthStencilAttachment
.HasImage())
741 imageRectsMatch
&= RectsMatch(mDepthStencilAttachment
, rect
);
743 return imageRectsMatch
;
747 const WebGLRectangleObject
&
748 WebGLFramebuffer::RectangleObject() const
750 // If we're using this as the RectObj of an FB, we need to be sure the FB
751 // has a consistent rect.
752 MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
753 return GetAnyRectObject();
757 WebGLFramebuffer::PrecheckFramebufferStatus() const
759 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
761 if (!HasDefinedAttachments())
762 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
; // No attachments
764 if (HasIncompleteAttachments())
765 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT
;
767 if (!AllImageRectsMatch())
768 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
; // Inconsistent sizes
770 if (HasDepthStencilConflict())
771 return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED
;
773 return LOCAL_GL_FRAMEBUFFER_COMPLETE
;
777 WebGLFramebuffer::CheckFramebufferStatus() const
782 mStatus
= PrecheckFramebufferStatus();
783 if (mStatus
!= LOCAL_GL_FRAMEBUFFER_COMPLETE
)
786 // Looks good on our end. Let's ask the driver.
787 mContext
->MakeContextCurrent();
789 // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
790 FinalizeAttachments();
792 mStatus
= mContext
->gl
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
797 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask
)
799 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE
)
802 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
803 bool hasPlanes
= true;
804 if (mask
& LOCAL_GL_COLOR_BUFFER_BIT
) {
805 hasPlanes
&= ColorAttachmentCount() &&
806 ColorAttachment(0).IsDefined();
809 if (mask
& LOCAL_GL_DEPTH_BUFFER_BIT
) {
810 hasPlanes
&= DepthAttachment().IsDefined() ||
811 DepthStencilAttachment().IsDefined();
814 if (mask
& LOCAL_GL_STENCIL_BUFFER_BIT
) {
815 hasPlanes
&= StencilAttachment().IsDefined() ||
816 DepthStencilAttachment().IsDefined();
823 WebGLFramebuffer::CheckAndInitializeAttachments()
825 MOZ_ASSERT(mContext
->mBoundFramebuffer
== this);
827 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE
)
830 // Cool! We've checked out ok. Just need to initialize.
831 size_t colorAttachmentCount
= mColorAttachments
.Length();
833 // Check if we need to initialize anything
835 bool hasUninitializedAttachments
= false;
837 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
838 if (mColorAttachments
[i
].HasImage())
839 hasUninitializedAttachments
|= mColorAttachments
[i
].HasUninitializedImageData();
842 if (mDepthAttachment
.HasImage())
843 hasUninitializedAttachments
|= mDepthAttachment
.HasUninitializedImageData();
844 if (mStencilAttachment
.HasImage())
845 hasUninitializedAttachments
|= mStencilAttachment
.HasUninitializedImageData();
846 if (mDepthStencilAttachment
.HasImage())
847 hasUninitializedAttachments
|= mDepthStencilAttachment
.HasUninitializedImageData();
849 if (!hasUninitializedAttachments
)
853 // Get buffer-bit-mask and color-attachment-mask-list
855 bool colorAttachmentsMask
[WebGLContext::kMaxColorAttachments
] = { false };
856 MOZ_ASSERT(colorAttachmentCount
<= WebGLContext::kMaxColorAttachments
);
858 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
859 if (mColorAttachments
[i
].HasUninitializedImageData()) {
860 colorAttachmentsMask
[i
] = true;
861 mask
|= LOCAL_GL_COLOR_BUFFER_BIT
;
865 if (mDepthAttachment
.HasUninitializedImageData() ||
866 mDepthStencilAttachment
.HasUninitializedImageData())
868 mask
|= LOCAL_GL_DEPTH_BUFFER_BIT
;
871 if (mStencilAttachment
.HasUninitializedImageData() ||
872 mDepthStencilAttachment
.HasUninitializedImageData())
874 mask
|= LOCAL_GL_STENCIL_BUFFER_BIT
;
878 mContext
->ForceClearFramebufferWithDefaultValues(mask
, colorAttachmentsMask
);
880 // Mark all the uninitialized images as initialized.
881 for (size_t i
= 0; i
< colorAttachmentCount
; i
++) {
882 if (mColorAttachments
[i
].HasUninitializedImageData())
883 mColorAttachments
[i
].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
886 if (mDepthAttachment
.HasUninitializedImageData())
887 mDepthAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
888 if (mStencilAttachment
.HasUninitializedImageData())
889 mStencilAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
890 if (mDepthStencilAttachment
.HasUninitializedImageData())
891 mDepthStencilAttachment
.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData
);
896 bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment
, const char* functionName
) const
898 const char* const errorFormating
= "%s: attachment: invalid enum value 0x%x";
900 if (mContext
->IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers
)) {
901 if (attachment
< LOCAL_GL_COLOR_ATTACHMENT0
||
902 attachment
>= GLenum(LOCAL_GL_COLOR_ATTACHMENT0
+ mContext
->mGLMaxColorAttachments
))
904 mContext
->ErrorInvalidEnum(errorFormating
, functionName
, attachment
);
907 } else if (attachment
!= LOCAL_GL_COLOR_ATTACHMENT0
) {
908 if (attachment
> LOCAL_GL_COLOR_ATTACHMENT0
&&
909 attachment
<= LOCAL_GL_COLOR_ATTACHMENT15
)
911 mContext
->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. "
912 "Try the WEBGL_draw_buffers extension if supported.", functionName
, attachment
);
915 mContext
->ErrorInvalidEnum(errorFormating
, functionName
, attachment
);
923 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId
)
925 MOZ_ASSERT(colorAttachmentId
< WebGLContext::kMaxColorAttachments
);
927 size_t currentAttachmentCount
= mColorAttachments
.Length();
928 if (colorAttachmentId
< currentAttachmentCount
)
931 mColorAttachments
.SetLength(colorAttachmentId
+ 1);
933 for (size_t i
= colorAttachmentId
; i
>= currentAttachmentCount
; i
--) {
934 mColorAttachments
[i
].mAttachmentPoint
= LOCAL_GL_COLOR_ATTACHMENT0
+ i
;
939 WebGLFramebuffer::NotifyAttachableChanged() const
941 // Attachment has changed, so invalidate cached status
946 FinalizeDrawAndReadBuffers(GLContext
* aGL
, bool aColorBufferDefined
)
948 MOZ_ASSERT(aGL
, "Expected a valid GLContext ptr.");
949 // GLES don't support DrawBuffer()/ReadBuffer.
950 // According to http://www.opengl.org/wiki/Framebuffer_Object
952 // Each draw buffers must either specify color attachment points that have images
953 // attached or must be GL_NONE. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER when false).
955 // If the read buffer is set, then it must specify an attachment point that has an
956 // image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER when false).
958 // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
961 aGL
->IsSupported(GLFeature::ES2_compatibility
) ||
962 aGL
->IsAtLeast(ContextProfile::OpenGL
, 420))
967 // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL.
968 GLenum colorBufferSource
= aColorBufferDefined
? LOCAL_GL_COLOR_ATTACHMENT0
: LOCAL_GL_NONE
;
969 aGL
->fDrawBuffer(colorBufferSource
);
970 aGL
->fReadBuffer(colorBufferSource
);
974 WebGLFramebuffer::FinalizeAttachments() const
976 GLContext
* gl
= mContext
->gl
;
978 size_t count
= ColorAttachmentCount();
979 for (size_t i
= 0; i
< count
; i
++) {
980 ColorAttachment(i
).FinalizeAttachment(gl
, LOCAL_GL_COLOR_ATTACHMENT0
+ i
);
983 DepthAttachment().FinalizeAttachment(gl
, LOCAL_GL_DEPTH_ATTACHMENT
);
984 StencilAttachment().FinalizeAttachment(gl
, LOCAL_GL_STENCIL_ATTACHMENT
);
985 DepthStencilAttachment().FinalizeAttachment(gl
, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
);
987 FinalizeDrawAndReadBuffers(gl
, ColorAttachment(0).IsDefined());
991 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment
& aField
)
993 aField
.mTexturePtr
= nullptr;
994 aField
.mRenderbufferPtr
= nullptr;
998 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback
& aCallback
,
999 mozilla::WebGLFramebuffer::Attachment
& aField
,
1001 uint32_t aFlags
= 0)
1003 CycleCollectionNoteChild(aCallback
, aField
.mTexturePtr
.get(),
1006 CycleCollectionNoteChild(aCallback
, aField
.mRenderbufferPtr
.get(),
1010 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer
,
1014 mDepthStencilAttachment
)
1016 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer
, AddRef
)
1017 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer
, Release
)