Bumping manifests a=b2g-bump
[gecko.git] / dom / canvas / WebGLFramebuffer.cpp
blob4d15b842d8d14c9afe54b8f53bc269c9169ce4fc
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"
8 #include "GLContext.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"
16 namespace mozilla {
18 JSObject*
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)
27 , mStatus(0)
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()
47 void
48 WebGLFramebuffer::Attachment::Reset()
50 mTexturePtr = nullptr;
51 mRenderbufferPtr = nullptr;
54 bool
55 WebGLFramebuffer::Attachment::IsDeleteRequested() const
57 return Texture() ? Texture()->IsDeleteRequested()
58 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
59 : false;
62 bool
63 WebGLFramebuffer::Attachment::IsDefined() const
65 return Renderbuffer() ||
66 (Texture() && Texture()->HasImageInfoAt(ImageTarget(), 0));
69 bool
70 WebGLFramebuffer::Attachment::HasAlpha() const
72 MOZ_ASSERT(HasImage());
74 if (Texture() &&
75 Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
77 return FormatHasAlpha(Texture()->ImageInfoAt(mTexImageTarget,
78 mTexImageLevel).EffectiveInternalFormat());
81 if (Renderbuffer())
82 return FormatHasAlpha(Renderbuffer()->InternalFormat());
84 return false;
87 GLenum
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(),
98 0);
99 return imgInfo.EffectiveInternalFormat().get();
102 if (attachment.Renderbuffer())
103 return attachment.Renderbuffer()->InternalFormat();
105 return LOCAL_GL_NONE;
108 TexInternalFormat
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();
118 if (rb)
119 return rb->InternalFormat();
121 return LOCAL_GL_NONE;
124 bool
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;
134 void
135 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex,
136 TexImageTarget target, GLint level)
138 mTexturePtr = tex;
139 mRenderbufferPtr = nullptr;
140 mTexImageTarget = target;
141 mTexImageLevel = level;
143 mNeedsFinalize = true;
146 void
147 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb)
149 mTexturePtr = nullptr;
150 mRenderbufferPtr = rb;
152 mNeedsFinalize = true;
155 bool
156 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
158 if (!HasImage())
159 return false;
161 if (Renderbuffer())
162 return Renderbuffer()->HasUninitializedImageData();
164 if (Texture()) {
165 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
166 return Texture()->ImageInfoAt(mTexImageTarget,
167 mTexImageLevel).HasUninitializedImageData();
170 MOZ_ASSERT(false, "Should not get here.");
171 return false;
174 void
175 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus)
177 if (!HasImage())
178 return;
180 if (Renderbuffer()) {
181 Renderbuffer()->SetImageDataStatus(newStatus);
182 return;
185 if (Texture()) {
186 Texture()->SetImageDataStatus(mTexImageTarget, mTexImageLevel,
187 newStatus);
188 return;
191 MOZ_ASSERT(false, "Should not get here.");
194 bool
195 WebGLFramebuffer::Attachment::HasImage() const
197 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
198 return true;
200 if (Renderbuffer())
201 return true;
203 return false;
206 const WebGLRectangleObject&
207 WebGLFramebuffer::Attachment::RectangleObject() const
209 MOZ_ASSERT(HasImage(),
210 "Make sure it has an image before requesting the rectangle.");
212 if (Texture()) {
213 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
214 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
217 if (Renderbuffer())
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()
227 static inline bool
228 IsValidFBOTextureDepthFormat(GLenum internalformat)
230 return IsGLDepthFormat(internalformat);
233 static inline bool
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.
243 static inline bool
244 IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
246 return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
249 static inline bool
250 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
252 return internalFormat == LOCAL_GL_DEPTH_STENCIL;
255 static inline bool
256 IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
258 return internalFormat == LOCAL_GL_STENCIL_INDEX8;
261 bool
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:
268 case LOCAL_GL_RGB8:
269 case LOCAL_GL_RGBA8:
270 case LOCAL_GL_RGB565:
271 case LOCAL_GL_RGB5_A1:
272 case LOCAL_GL_RGBA4:
273 return true;
275 case LOCAL_GL_SRGB8:
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);
288 return false;
291 bool
292 WebGLFramebuffer::Attachment::IsComplete() const
294 if (!HasImage())
295 return false;
297 const WebGLRectangleObject& rect = RectangleObject();
299 if (!rect.Width() ||
300 !rect.Height())
302 return false;
305 if (Texture()) {
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.
316 return false;
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?");
330 return false;
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?");
353 return false;
355 MOZ_ASSERT(false, "Should not get here.");
356 return false;
359 void
360 WebGLFramebuffer::Attachment::FinalizeAttachment(gl::GLContext* gl,
361 FBAttachment attachmentLoc) const
363 if (!mNeedsFinalize)
364 return;
366 mNeedsFinalize = false;
368 if (!HasImage()) {
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);
376 } else {
377 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER,
378 attachmentLoc.get(),
379 LOCAL_GL_RENDERBUFFER, 0);
382 return;
384 MOZ_ASSERT(HasImage());
386 if (Texture()) {
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,
396 glName, mipLevel);
397 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER,
398 LOCAL_GL_STENCIL_ATTACHMENT, imageTarget,
399 glName, mipLevel);
400 } else {
401 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc.get(),
402 imageTarget, glName, mipLevel);
404 return;
407 if (Renderbuffer()) {
408 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
409 return;
412 MOZ_ASSERT(false, "Should not get here.");
415 void
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);
429 void
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);
441 void
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);
453 void
454 WebGLFramebuffer::FramebufferRenderbuffer(FBAttachment attachPoint,
455 RBTarget rbtarget,
456 WebGLRenderbuffer* rb)
458 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
460 if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer",
461 rb))
463 return;
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
471 * mess with.
473 Attachment* attachment = GetAttachmentOrNull(attachPoint);
474 if (!attachment)
475 return; // Error generated internally to GetAttachmentOrNull.
477 // Invalidate cached framebuffer status and inform texture of its new
478 // attachment.
479 mStatus = 0;
481 // Detach current:
482 if (attachment->Texture())
483 attachment->Texture()->DetachFrom(this, attachPoint);
484 else if (attachment->Renderbuffer())
485 attachment->Renderbuffer()->DetachFrom(this, attachPoint);
487 // Attach new:
488 if (rb)
489 rb->AttachTo(this, attachPoint);
491 attachment->SetRenderbuffer(rb);
494 void
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",
502 tex))
504 return;
507 if (tex) {
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.");
513 return;
517 if (level != 0) {
518 mContext->ErrorInvalidValue("framebufferTexture2D: Level must be 0.");
519 return;
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
527 * mess with.
529 Attachment* attachment = GetAttachmentOrNull(attachPoint);
530 if (!attachment)
531 return; // Error generated internally to GetAttachmentOrNull.
533 // Invalidate cached framebuffer status and inform texture of its new
534 // attachment.
535 mStatus = 0;
537 // Detach current:
538 if (attachment->Texture())
539 attachment->Texture()->DetachFrom(this, attachPoint);
540 else if (attachment->Renderbuffer())
541 attachment->Renderbuffer()->DetachFrom(this, attachPoint);
543 // Attach new:
544 if (tex)
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;
563 default:
564 break;
567 if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
568 "getAttachmentOrNull"))
570 return nullptr;
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;
592 default:
593 break;
596 if (!mContext->ValidateFramebufferAttachment(attachPoint.get(),
597 "getAttachment"))
599 MOZ_ASSERT(false);
600 return mColorAttachments[0];
603 size_t colorAttachmentId = attachPoint.get() - LOCAL_GL_COLOR_ATTACHMENT0;
604 if (colorAttachmentId >= mColorAttachments.Length()) {
605 MOZ_ASSERT(false);
606 return mColorAttachments[0];
609 return mColorAttachments[colorAttachmentId];
612 void
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,
625 nullptr, 0);
627 if (mStencilAttachment.Texture() == tex) {
628 FramebufferTexture2D(LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D,
629 nullptr, 0);
631 if (mDepthStencilAttachment.Texture() == tex) {
632 FramebufferTexture2D(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT,
633 LOCAL_GL_TEXTURE_2D, nullptr, 0);
637 void
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);
662 bool
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;
678 static bool
679 IsIncomplete(const WebGLFramebuffer::Attachment& cur)
681 return cur.IsDefined() && !cur.IsComplete();
684 bool
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.");
722 static bool
723 RectsMatch(const WebGLFramebuffer::Attachment& attachment,
724 const WebGLRectangleObject& rect)
726 return attachment.RectangleObject().HasSameDimensionsAs(rect);
729 bool
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();
766 FBStatus
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;
786 FBStatus
787 WebGLFramebuffer::CheckFramebufferStatus() const
789 if (mStatus != 0)
790 return mStatus;
792 mStatus = PrecheckFramebufferStatus().get();
793 if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
794 return mStatus;
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);
803 return mStatus;
806 bool
807 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
809 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
810 return false;
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();
829 return hasPlanes;
832 bool
833 WebGLFramebuffer::CheckAndInitializeAttachments()
835 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
837 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
838 return false;
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)
860 return true;
863 // Get buffer-bit-mask and color-attachment-mask-list
864 uint32_t mask = 0;
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;
887 // Clear!
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);
903 return true;
906 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
908 MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments);
910 size_t currentAttachmentCount = mColorAttachments.Length();
911 if (colorAttachmentId < currentAttachmentCount)
912 return;
914 mColorAttachments.SetLength(colorAttachmentId + 1);
916 for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
917 mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i;
921 void
922 WebGLFramebuffer::NotifyAttachableChanged() const
924 // Attachment has changed, so invalidate cached status
925 mStatus = 0;
928 static void
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
942 // available.
943 if (gl->IsGLES() ||
944 gl->IsSupported(gl::GLFeature::ES2_compatibility) ||
945 gl->IsAtLeast(gl::ContextProfile::OpenGL, 420))
947 return;
950 // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL.
951 GLenum colorBufferSource = isColorBufferDefined ? LOCAL_GL_COLOR_ATTACHMENT0
952 : LOCAL_GL_NONE;
953 gl->fDrawBuffer(colorBufferSource);
954 gl->fReadBuffer(colorBufferSource);
957 void
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());
974 inline void
975 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& field)
977 field.mTexturePtr = nullptr;
978 field.mRenderbufferPtr = nullptr;
981 inline void
982 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
983 mozilla::WebGLFramebuffer::Attachment& field,
984 const char* name,
985 uint32_t flags = 0)
987 CycleCollectionNoteChild(callback, field.mTexturePtr.get(), name, flags);
988 CycleCollectionNoteChild(callback, field.mRenderbufferPtr.get(), name,
989 flags);
992 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
993 mColorAttachments,
994 mDepthAttachment,
995 mStencilAttachment,
996 mDepthStencilAttachment)
998 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
999 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)
1001 } // namespace mozilla