Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / dom / canvas / WebGLFramebuffer.cpp
blob98dae837e7ae99e6985077d8504b36e4d41a9957
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;
20 JSObject*
21 WebGLFramebuffer::WrapObject(JSContext* cx)
23 return dom::WebGLFramebufferBinding::Wrap(cx, this);
26 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
27 : WebGLBindableName()
28 , WebGLContextBoundObject(context)
29 , mStatus(0)
30 , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
31 , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
32 , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
34 SetIsDOMBinding();
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()
51 void
52 WebGLFramebuffer::Attachment::Reset()
54 mTexturePtr = nullptr;
55 mRenderbufferPtr = nullptr;
58 bool
59 WebGLFramebuffer::Attachment::IsDeleteRequested() const
61 return Texture() ? Texture()->IsDeleteRequested()
62 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
63 : false;
66 bool
67 WebGLFramebuffer::Attachment::HasAlpha() const
69 MOZ_ASSERT(HasImage());
71 GLenum format = 0;
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);
79 GLenum
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();
96 return LOCAL_GL_NONE;
99 bool
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();
105 switch (type) {
106 case LOCAL_GL_FLOAT:
107 case LOCAL_GL_HALF_FLOAT_OES:
108 return true;
110 return false;
113 const WebGLRenderbuffer* rb = Renderbuffer();
114 if (rb) {
115 GLenum format = rb->InternalFormat();
116 switch (format) {
117 case LOCAL_GL_RGB16F:
118 case LOCAL_GL_RGBA16F:
119 case LOCAL_GL_RGB32F:
120 case LOCAL_GL_RGBA32F:
121 return true;
123 return false;
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.");
129 return false;
132 void
133 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
135 mTexturePtr = tex;
136 mRenderbufferPtr = nullptr;
137 mTexImageTarget = target;
138 mTexImageLevel = level;
140 mNeedsFinalize = true;
143 void
144 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb)
146 mTexturePtr = nullptr;
147 mRenderbufferPtr = rb;
149 mNeedsFinalize = true;
152 bool
153 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
155 if (!HasImage())
156 return false;
158 if (Renderbuffer()) {
159 return Renderbuffer()->HasUninitializedImageData();
162 if (Texture()) {
163 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
164 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
167 MOZ_ASSERT(false, "Should not get here.");
168 return false;
171 void
172 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus)
174 if (!HasImage())
175 return;
177 if (Renderbuffer()) {
178 Renderbuffer()->SetImageDataStatus(newStatus);
179 return;
182 if (Texture()) {
183 Texture()->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
184 return;
187 MOZ_ASSERT(false, "Should not get here.");
190 bool
191 WebGLFramebuffer::Attachment::HasImage() const
193 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
194 return true;
196 if (Renderbuffer())
197 return true;
199 return false;
202 const WebGLRectangleObject&
203 WebGLFramebuffer::Attachment::RectangleObject() const
205 MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle.");
207 if (Texture()) {
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()*/
223 static inline bool
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.
233 return (
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
258 static inline bool
259 IsValidFBOTextureDepthFormat(GLenum internalFormat)
261 return (
262 internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
263 internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
264 internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
267 static inline bool
268 IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
270 return (
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. */
278 static inline bool
279 IsValidFBORenderbufferColorFormat(GLenum internalFormat)
281 return (
282 internalFormat == LOCAL_GL_RGB565 ||
283 internalFormat == LOCAL_GL_RGB5_A1 ||
284 internalFormat == LOCAL_GL_RGBA4 ||
285 internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT);
288 static inline bool
289 IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
291 return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
294 static inline bool
295 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
297 return internalFormat == LOCAL_GL_DEPTH_STENCIL;
300 static inline bool
301 IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
303 return internalFormat == LOCAL_GL_STENCIL_INDEX8;
306 bool
307 WebGLFramebuffer::Attachment::IsComplete() const
309 if (!HasImage())
310 return false;
312 const WebGLRectangleObject& rect = RectangleObject();
314 if (!rect.Width() ||
315 !rect.Height())
317 return false;
320 if (Texture()) {
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?");
343 return false;
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?");
365 return false;
368 MOZ_ASSERT(false, "Should not get here.");
369 return false;
372 void
373 WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmentLoc) const
375 if (!mNeedsFinalize)
376 return;
378 mNeedsFinalize = false;
380 if (!HasImage()) {
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);
386 } else {
387 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
388 LOCAL_GL_RENDERBUFFER, 0);
391 return;
393 MOZ_ASSERT(HasImage());
395 if (Texture()) {
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());
403 } else {
404 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
405 TexImageTarget(), Texture()->GLName(), TexImageLevel());
407 return;
410 if (Renderbuffer()) {
411 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
412 return;
415 MOZ_ASSERT(false, "Should not get here.");
418 void
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);
432 void
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);
442 void
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);
455 void
456 WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
457 GLenum attachment,
458 GLenum rbtarget,
459 WebGLRenderbuffer* wrb)
461 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
463 if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
464 return;
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);
480 if (!a)
481 return; // Error generated internally to GetAttachmentOrNull.
483 /* Invalidate cached framebuffer status and inform texture of it's
484 * new attachment
486 mStatus = 0;
487 // Detach current
488 if (a->Texture())
489 a->Texture()->DetachFrom(this, attachment);
490 else if (a->Renderbuffer())
491 a->Renderbuffer()->DetachFrom(this, attachment);
493 // Attach new
494 if (wrb)
495 wrb->AttachTo(this, attachment);
497 a->SetRenderbuffer(wrb);
500 void
501 WebGLFramebuffer::FramebufferTexture2D(GLenum target,
502 GLenum attachment,
503 GLenum textarget,
504 WebGLTexture* wtex,
505 GLint level)
507 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
509 if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
510 return;
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);
522 if (wtex) {
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");
530 if (level != 0)
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);
541 if (!a)
542 return; // Error generated internally to GetAttachmentOrNull.
544 /* Invalidate cached framebuffer status and inform texture of it's
545 * new attachment
547 mStatus = 0;
548 // Detach current
549 if (a->Texture())
550 a->Texture()->DetachFrom(this, attachment);
551 else if (a->Renderbuffer())
552 a->Renderbuffer()->DetachFrom(this, attachment);
554 // Attach new
555 if (wtex)
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"))
574 return nullptr;
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")) {
593 MOZ_ASSERT(false);
594 return mColorAttachments[0];
597 size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
598 if (colorAttachmentId >= mColorAttachments.Length()) {
599 MOZ_ASSERT(false);
600 return mColorAttachments[0];
603 return mColorAttachments[colorAttachmentId];
606 void
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);
625 void
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);
644 bool
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;
662 static bool
663 IsIncomplete(const WebGLFramebuffer::Attachment& cur)
665 return cur.IsDefined() && !cur.IsComplete();
668 bool
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.");
710 static bool
711 RectsMatch(const WebGLFramebuffer::Attachment& attachment,
712 const WebGLRectangleObject& rect)
714 return attachment.RectangleObject().HasSameDimensionsAs(rect);
717 bool
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();
756 GLenum
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;
776 GLenum
777 WebGLFramebuffer::CheckFramebufferStatus() const
779 if (mStatus != 0)
780 return mStatus;
782 mStatus = PrecheckFramebufferStatus();
783 if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
784 return mStatus;
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);
793 return mStatus;
796 bool
797 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
799 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
800 return false;
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();
819 return hasPlanes;
822 bool
823 WebGLFramebuffer::CheckAndInitializeAttachments()
825 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
827 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
828 return false;
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)
850 return true;
853 // Get buffer-bit-mask and color-attachment-mask-list
854 uint32_t mask = 0;
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;
877 // Clear!
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);
893 return true;
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);
905 return false;
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);
913 return false;
914 } else {
915 mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
916 return false;
920 return true;
923 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
925 MOZ_ASSERT(colorAttachmentId < WebGLContext::kMaxColorAttachments);
927 size_t currentAttachmentCount = mColorAttachments.Length();
928 if (colorAttachmentId < currentAttachmentCount)
929 return;
931 mColorAttachments.SetLength(colorAttachmentId + 1);
933 for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
934 mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i;
938 void
939 WebGLFramebuffer::NotifyAttachableChanged() const
941 // Attachment has changed, so invalidate cached status
942 mStatus = 0;
945 static void
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
959 // available.
960 if (aGL->IsGLES() ||
961 aGL->IsSupported(GLFeature::ES2_compatibility) ||
962 aGL->IsAtLeast(ContextProfile::OpenGL, 420))
964 return;
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);
973 void
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());
990 inline void
991 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& aField)
993 aField.mTexturePtr = nullptr;
994 aField.mRenderbufferPtr = nullptr;
997 inline void
998 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
999 mozilla::WebGLFramebuffer::Attachment& aField,
1000 const char* aName,
1001 uint32_t aFlags = 0)
1003 CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(),
1004 aName, aFlags);
1006 CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
1007 aName, aFlags);
1010 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
1011 mColorAttachments,
1012 mDepthAttachment,
1013 mStencilAttachment,
1014 mDepthStencilAttachment)
1016 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
1017 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)