Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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)
22 {
23 return dom::WebGLFramebufferBinding::Wrap(cx, this);
24 }
26 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
27 : WebGLContextBoundObject(context)
28 , mStatus(0)
29 , mHasEverBeenBound(false)
30 , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
31 , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
32 , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
33 {
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;
41 }
43 bool
44 WebGLFramebuffer::Attachment::IsDeleteRequested() const
45 {
46 return Texture() ? Texture()->IsDeleteRequested()
47 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
48 : false;
49 }
51 bool
52 WebGLFramebuffer::Attachment::HasAlpha() const
53 {
54 MOZ_ASSERT(HasImage());
56 GLenum format = 0;
57 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
58 format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLFormat();
59 else if (Renderbuffer())
60 format = Renderbuffer()->InternalFormat();
61 return FormatHasAlpha(format);
62 }
64 bool
65 WebGLFramebuffer::Attachment::IsReadableFloat() const
66 {
67 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
68 GLenum type = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLType();
69 switch (type) {
70 case LOCAL_GL_FLOAT:
71 case LOCAL_GL_HALF_FLOAT_OES:
72 return true;
73 }
74 return false;
75 }
77 if (Renderbuffer()) {
78 GLenum format = Renderbuffer()->InternalFormat();
79 switch (format) {
80 case LOCAL_GL_RGB16F:
81 case LOCAL_GL_RGBA16F:
82 case LOCAL_GL_RGB32F:
83 case LOCAL_GL_RGBA32F:
84 return true;
85 }
86 return false;
87 }
89 MOZ_ASSERT(false, "Should not get here.");
90 return false;
91 }
93 void
94 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
95 {
96 mTexturePtr = tex;
97 mRenderbufferPtr = nullptr;
98 mTexImageTarget = target;
99 mTexImageLevel = level;
101 mNeedsFinalize = true;
102 }
104 void
105 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb)
106 {
107 mTexturePtr = nullptr;
108 mRenderbufferPtr = rb;
110 mNeedsFinalize = true;
111 }
113 bool
114 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
115 {
116 if (!HasImage())
117 return false;
119 if (Renderbuffer()) {
120 return Renderbuffer()->HasUninitializedImageData();
121 }
123 if (Texture()) {
124 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
125 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
126 }
128 MOZ_ASSERT(false, "Should not get here.");
129 return false;
130 }
132 void
133 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus)
134 {
135 if (!HasImage())
136 return;
138 if (Renderbuffer()) {
139 Renderbuffer()->SetImageDataStatus(newStatus);
140 return;
141 }
143 if (Texture()) {
144 Texture()->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
145 return;
146 }
148 MOZ_ASSERT(false, "Should not get here.");
149 }
151 bool
152 WebGLFramebuffer::Attachment::HasImage() const
153 {
154 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
155 return true;
157 if (Renderbuffer())
158 return true;
160 return false;
161 }
163 const WebGLRectangleObject&
164 WebGLFramebuffer::Attachment::RectangleObject() const
165 {
166 MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle.");
168 if (Texture()) {
169 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
170 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
171 }
173 if (Renderbuffer()) {
174 return *Renderbuffer();
175 }
177 MOZ_CRASH("Should not get here.");
178 }
180 /* The following IsValidFBOTextureXXX functions check the internal
181 format that is used by GL or GL ES texture formats. This
182 corresponds to the state that is stored in
183 WebGLTexture::ImageInfo::InternalFormat()*/
184 static inline bool
185 IsValidFBOTextureColorFormat(GLenum internalFormat)
186 {
187 /* These formats are internal formats for each texture -- the actual
188 * low level format, which we might have to do conversions for when
189 * running against desktop GL (e.g. GL_RGBA + GL_FLOAT -> GL_RGBA32F).
190 *
191 * This function just handles all of them whether desktop GL or ES.
192 */
194 return (
195 /* linear 8-bit formats */
196 internalFormat == LOCAL_GL_ALPHA ||
197 internalFormat == LOCAL_GL_LUMINANCE ||
198 internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
199 internalFormat == LOCAL_GL_RGB ||
200 internalFormat == LOCAL_GL_RGBA ||
201 /* sRGB 8-bit formats */
202 internalFormat == LOCAL_GL_SRGB_EXT ||
203 internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
204 /* linear float32 formats */
205 internalFormat == LOCAL_GL_ALPHA32F_ARB ||
206 internalFormat == LOCAL_GL_LUMINANCE32F_ARB ||
207 internalFormat == LOCAL_GL_LUMINANCE_ALPHA32F_ARB ||
208 internalFormat == LOCAL_GL_RGB32F_ARB ||
209 internalFormat == LOCAL_GL_RGBA32F_ARB ||
210 /* texture_half_float formats */
211 internalFormat == LOCAL_GL_ALPHA16F_ARB ||
212 internalFormat == LOCAL_GL_LUMINANCE16F_ARB ||
213 internalFormat == LOCAL_GL_LUMINANCE_ALPHA16F_ARB ||
214 internalFormat == LOCAL_GL_RGB16F_ARB ||
215 internalFormat == LOCAL_GL_RGBA16F_ARB
216 );
217 }
219 static inline bool
220 IsValidFBOTextureDepthFormat(GLenum internalFormat)
221 {
222 return (
223 internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
224 internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
225 internalFormat == LOCAL_GL_DEPTH_COMPONENT32);
226 }
228 static inline bool
229 IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
230 {
231 return (
232 internalFormat == LOCAL_GL_DEPTH_STENCIL ||
233 internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
234 }
236 /* The following IsValidFBORenderbufferXXX functions check the internal
237 format that is stored by WebGLRenderbuffer::InternalFormat(). Valid
238 values can be found in WebGLContext::RenderbufferStorage. */
239 static inline bool
240 IsValidFBORenderbufferColorFormat(GLenum internalFormat)
241 {
242 return (
243 internalFormat == LOCAL_GL_RGB565 ||
244 internalFormat == LOCAL_GL_RGB5_A1 ||
245 internalFormat == LOCAL_GL_RGBA4 ||
246 internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT);
247 }
249 static inline bool
250 IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
251 {
252 return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
253 }
255 static inline bool
256 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
257 {
258 return internalFormat == LOCAL_GL_DEPTH_STENCIL;
259 }
261 static inline bool
262 IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
263 {
264 return internalFormat == LOCAL_GL_STENCIL_INDEX8;
265 }
267 bool
268 WebGLFramebuffer::Attachment::IsComplete() const
269 {
270 if (!HasImage())
271 return false;
273 const WebGLRectangleObject& rect = RectangleObject();
275 if (!rect.Width() ||
276 !rect.Height())
277 {
278 return false;
279 }
281 if (Texture()) {
282 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
283 const WebGLTexture::ImageInfo& imageInfo =
284 Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
285 GLenum webGLFormat = imageInfo.WebGLFormat();
287 if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
288 return IsValidFBOTextureDepthFormat(webGLFormat);
290 if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
291 return IsValidFBOTextureDepthStencilFormat(webGLFormat);
293 if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
294 mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
295 WebGLContext::sMaxColorAttachments))
296 {
297 return IsValidFBOTextureColorFormat(webGLFormat);
298 }
299 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
300 return false;
301 }
303 if (Renderbuffer()) {
304 GLenum internalFormat = Renderbuffer()->InternalFormat();
306 if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
307 return IsValidFBORenderbufferDepthFormat(internalFormat);
309 if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
310 return IsValidFBORenderbufferStencilFormat(internalFormat);
312 if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
313 return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
315 if (mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0 &&
316 mAttachmentPoint < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 +
317 WebGLContext::sMaxColorAttachments))
318 {
319 return IsValidFBORenderbufferColorFormat(internalFormat);
320 }
321 MOZ_ASSERT(false, "Invalid WebGL attachment point?");
322 return false;
323 }
325 MOZ_ASSERT(false, "Should not get here.");
326 return false;
327 }
329 void
330 WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmentLoc) const
331 {
332 if (!mNeedsFinalize)
333 return;
335 mNeedsFinalize = false;
337 if (!HasImage()) {
338 if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
339 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
340 LOCAL_GL_RENDERBUFFER, 0);
341 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
342 LOCAL_GL_RENDERBUFFER, 0);
343 } else {
344 gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
345 LOCAL_GL_RENDERBUFFER, 0);
346 }
348 return;
349 }
350 MOZ_ASSERT(HasImage());
352 if (Texture()) {
353 MOZ_ASSERT(gl == Texture()->Context()->gl);
355 if (attachmentLoc == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
356 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
357 TexImageTarget(), Texture()->GLName(), TexImageLevel());
358 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
359 TexImageTarget(), Texture()->GLName(), TexImageLevel());
360 } else {
361 gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentLoc,
362 TexImageTarget(), Texture()->GLName(), TexImageLevel());
363 }
364 return;
365 }
367 if (Renderbuffer()) {
368 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
369 return;
370 }
372 MOZ_ASSERT(false, "Should not get here.");
373 }
375 void
376 WebGLFramebuffer::Delete()
377 {
378 DetachAllAttachments();
379 mColorAttachments.Clear();
380 mDepthAttachment.Reset();
381 mStencilAttachment.Reset();
382 mDepthStencilAttachment.Reset();
384 mContext->MakeContextCurrent();
385 mContext->gl->fDeleteFramebuffers(1, &mGLName);
386 LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
387 }
389 void
390 WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment& attachment)
391 {
392 if (attachment.Texture())
393 attachment.Texture()->DetachFrom(this, attachment.mAttachmentPoint);
395 if (attachment.Renderbuffer())
396 attachment.Renderbuffer()->DetachFrom(this, attachment.mAttachmentPoint);
397 }
399 void
400 WebGLFramebuffer::DetachAllAttachments()
401 {
402 size_t count = mColorAttachments.Length();
403 for (size_t i = 0; i < count; i++) {
404 DetachAttachment(mColorAttachments[i]);
405 }
407 DetachAttachment(mDepthAttachment);
408 DetachAttachment(mStencilAttachment);
409 DetachAttachment(mDepthStencilAttachment);
410 }
412 void
413 WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
414 GLenum attachment,
415 GLenum rbtarget,
416 WebGLRenderbuffer* wrb)
417 {
418 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
420 if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
421 return;
423 if (target != LOCAL_GL_FRAMEBUFFER)
424 return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
426 if (rbtarget != LOCAL_GL_RENDERBUFFER)
427 return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
429 /* Get the requested attachment. If result is NULL, attachment is
430 * invalid and an error is generated.
431 *
432 * Don't use GetAttachment(...) here because it opt builds it
433 * returns mColorAttachment[0] for invalid attachment, which we
434 * really don't want to mess with.
435 */
436 Attachment* a = GetAttachmentOrNull(attachment);
437 if (!a)
438 return; // Error generated internally to GetAttachmentOrNull.
440 /* Invalidate cached framebuffer status and inform texture of it's
441 * new attachment
442 */
443 mStatus = 0;
444 // Detach current
445 if (a->Texture())
446 a->Texture()->DetachFrom(this, attachment);
447 else if (a->Renderbuffer())
448 a->Renderbuffer()->DetachFrom(this, attachment);
450 // Attach new
451 if (wrb)
452 wrb->AttachTo(this, attachment);
454 a->SetRenderbuffer(wrb);
455 }
457 void
458 WebGLFramebuffer::FramebufferTexture2D(GLenum target,
459 GLenum attachment,
460 GLenum textarget,
461 WebGLTexture* wtex,
462 GLint level)
463 {
464 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
466 if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
467 return;
469 if (target != LOCAL_GL_FRAMEBUFFER)
470 return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
472 if (textarget != LOCAL_GL_TEXTURE_2D &&
473 (textarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
474 textarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
475 {
476 return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: invalid texture target", textarget);
477 }
479 if (wtex) {
480 bool isTexture2D = wtex->Target() == LOCAL_GL_TEXTURE_2D;
481 bool isTexTarget2D = textarget == LOCAL_GL_TEXTURE_2D;
482 if (isTexture2D != isTexTarget2D) {
483 return mContext->ErrorInvalidOperation("framebufferTexture2D: mismatched texture and texture target");
484 }
485 }
487 if (level != 0)
488 return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
490 /* Get the requested attachment. If result is NULL, attachment is
491 * invalid and an error is generated.
492 *
493 * Don't use GetAttachment(...) here because it opt builds it
494 * returns mColorAttachment[0] for invalid attachment, which we
495 * really don't want to mess with.
496 */
497 Attachment* a = GetAttachmentOrNull(attachment);
498 if (!a)
499 return; // Error generated internally to GetAttachmentOrNull.
501 /* Invalidate cached framebuffer status and inform texture of it's
502 * new attachment
503 */
504 mStatus = 0;
505 // Detach current
506 if (a->Texture())
507 a->Texture()->DetachFrom(this, attachment);
508 else if (a->Renderbuffer())
509 a->Renderbuffer()->DetachFrom(this, attachment);
511 // Attach new
512 if (wtex)
513 wtex->AttachTo(this, attachment);
515 a->SetTexImage(wtex, textarget, level);
516 }
518 WebGLFramebuffer::Attachment*
519 WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment)
520 {
521 if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
522 return &mDepthStencilAttachment;
524 if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
525 return &mDepthAttachment;
527 if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
528 return &mStencilAttachment;
530 if (!CheckColorAttachmentNumber(attachment, "getAttachmentOrNull"))
531 return nullptr;
533 size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
534 EnsureColorAttachments(colorAttachmentId);
536 return &mColorAttachments[colorAttachmentId];
537 }
539 const WebGLFramebuffer::Attachment&
540 WebGLFramebuffer::GetAttachment(GLenum attachment) const
541 {
542 if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
543 return mDepthStencilAttachment;
544 if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
545 return mDepthAttachment;
546 if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
547 return mStencilAttachment;
549 if (!CheckColorAttachmentNumber(attachment, "getAttachment")) {
550 MOZ_ASSERT(false);
551 return mColorAttachments[0];
552 }
554 size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
555 if (colorAttachmentId >= mColorAttachments.Length()) {
556 MOZ_ASSERT(false);
557 return mColorAttachments[0];
558 }
560 return mColorAttachments[colorAttachmentId];
561 }
563 void
564 WebGLFramebuffer::DetachTexture(const WebGLTexture* tex)
565 {
566 size_t count = mColorAttachments.Length();
567 for (size_t i = 0; i < count; i++) {
568 if (mColorAttachments[i].Texture() == tex) {
569 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_TEXTURE_2D, nullptr, 0);
570 // a texture might be attached more that once while editing the framebuffer
571 }
572 }
574 if (mDepthAttachment.Texture() == tex)
575 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
576 if (mStencilAttachment.Texture() == tex)
577 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
578 if (mDepthStencilAttachment.Texture() == tex)
579 FramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_TEXTURE_2D, nullptr, 0);
580 }
582 void
583 WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer* rb)
584 {
585 size_t count = mColorAttachments.Length();
586 for (size_t i = 0; i < count; i++) {
587 if (mColorAttachments[i].Renderbuffer() == rb) {
588 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0+i, LOCAL_GL_RENDERBUFFER, nullptr);
589 // a renderbuffer might be attached more that once while editing the framebuffer
590 }
591 }
593 if (mDepthAttachment.Renderbuffer() == rb)
594 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
595 if (mStencilAttachment.Renderbuffer() == rb)
596 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
597 if (mDepthStencilAttachment.Renderbuffer() == rb)
598 FramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT, LOCAL_GL_RENDERBUFFER, nullptr);
599 }
601 bool
602 WebGLFramebuffer::HasDefinedAttachments() const
603 {
604 bool hasAttachments = false;
606 size_t count = mColorAttachments.Length();
607 for (size_t i = 0; i < count; i++) {
608 hasAttachments |= mColorAttachments[i].IsDefined();
609 }
611 hasAttachments |= mDepthAttachment.IsDefined();
612 hasAttachments |= mStencilAttachment.IsDefined();
613 hasAttachments |= mDepthStencilAttachment.IsDefined();
615 return hasAttachments;
616 }
619 static bool
620 IsIncomplete(const WebGLFramebuffer::Attachment& cur)
621 {
622 return cur.IsDefined() && !cur.IsComplete();
623 }
625 bool
626 WebGLFramebuffer::HasIncompleteAttachments() const
627 {
628 bool hasIncomplete = false;
630 size_t count = mColorAttachments.Length();
631 for (size_t i = 0; i < count; i++) {
632 hasIncomplete |= IsIncomplete(mColorAttachments[i]);
633 }
635 hasIncomplete |= IsIncomplete(mDepthAttachment);
636 hasIncomplete |= IsIncomplete(mStencilAttachment);
637 hasIncomplete |= IsIncomplete(mDepthStencilAttachment);
639 return hasIncomplete;
640 }
643 const WebGLRectangleObject&
644 WebGLFramebuffer::GetAnyRectObject() const
645 {
646 MOZ_ASSERT(HasDefinedAttachments());
648 size_t count = mColorAttachments.Length();
649 for (size_t i = 0; i < count; i++) {
650 if (mColorAttachments[i].HasImage())
651 return mColorAttachments[i].RectangleObject();
652 }
654 if (mDepthAttachment.HasImage())
655 return mDepthAttachment.RectangleObject();
657 if (mStencilAttachment.HasImage())
658 return mStencilAttachment.RectangleObject();
660 if (mDepthStencilAttachment.HasImage())
661 return mDepthStencilAttachment.RectangleObject();
663 MOZ_CRASH("Should not get here.");
664 }
667 static bool
668 RectsMatch(const WebGLFramebuffer::Attachment& attachment,
669 const WebGLRectangleObject& rect)
670 {
671 return attachment.RectangleObject().HasSameDimensionsAs(rect);
672 }
674 bool
675 WebGLFramebuffer::AllImageRectsMatch() const
676 {
677 MOZ_ASSERT(HasDefinedAttachments());
678 MOZ_ASSERT(!HasIncompleteAttachments());
680 const WebGLRectangleObject& rect = GetAnyRectObject();
682 // Alright, we have *a* rect, let's check all the others.
683 bool imageRectsMatch = true;
685 size_t count = mColorAttachments.Length();
686 for (size_t i = 0; i < count; i++) {
687 if (mColorAttachments[i].HasImage())
688 imageRectsMatch &= RectsMatch(mColorAttachments[i], rect);
689 }
691 if (mDepthAttachment.HasImage())
692 imageRectsMatch &= RectsMatch(mDepthAttachment, rect);
694 if (mStencilAttachment.HasImage())
695 imageRectsMatch &= RectsMatch(mStencilAttachment, rect);
697 if (mDepthStencilAttachment.HasImage())
698 imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect);
700 return imageRectsMatch;
701 }
704 const WebGLRectangleObject&
705 WebGLFramebuffer::RectangleObject() const
706 {
707 // If we're using this as the RectObj of an FB, we need to be sure the FB
708 // has a consistent rect.
709 MOZ_ASSERT(AllImageRectsMatch(), "Did you mean `GetAnyRectObject`?");
710 return GetAnyRectObject();
711 }
713 GLenum
714 WebGLFramebuffer::PrecheckFramebufferStatus() const
715 {
716 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
718 if (!HasDefinedAttachments())
719 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
721 if (HasIncompleteAttachments())
722 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
724 if (!AllImageRectsMatch())
725 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
727 if (HasDepthStencilConflict())
728 return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
730 return LOCAL_GL_FRAMEBUFFER_COMPLETE;
731 }
733 GLenum
734 WebGLFramebuffer::CheckFramebufferStatus() const
735 {
736 if (mStatus != 0)
737 return mStatus;
739 mStatus = PrecheckFramebufferStatus();
740 if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
741 return mStatus;
743 // Looks good on our end. Let's ask the driver.
744 mContext->MakeContextCurrent();
746 // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
747 FinalizeAttachments();
749 mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
750 return mStatus;
751 }
753 bool
754 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
755 {
756 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
757 return false;
759 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
760 bool hasPlanes = true;
761 if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
762 hasPlanes &= ColorAttachmentCount() &&
763 ColorAttachment(0).IsDefined();
764 }
766 if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
767 hasPlanes &= DepthAttachment().IsDefined() ||
768 DepthStencilAttachment().IsDefined();
769 }
771 if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) {
772 hasPlanes &= StencilAttachment().IsDefined() ||
773 DepthStencilAttachment().IsDefined();
774 }
776 return hasPlanes;
777 }
779 bool
780 WebGLFramebuffer::CheckAndInitializeAttachments()
781 {
782 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
784 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
785 return false;
787 // Cool! We've checked out ok. Just need to initialize.
788 size_t colorAttachmentCount = mColorAttachments.Length();
790 // Check if we need to initialize anything
791 {
792 bool hasUninitializedAttachments = false;
794 for (size_t i = 0; i < colorAttachmentCount; i++) {
795 if (mColorAttachments[i].HasImage())
796 hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
797 }
799 if (mDepthAttachment.HasImage())
800 hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData();
801 if (mStencilAttachment.HasImage())
802 hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData();
803 if (mDepthStencilAttachment.HasImage())
804 hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData();
806 if (!hasUninitializedAttachments)
807 return true;
808 }
810 // Get buffer-bit-mask and color-attachment-mask-list
811 uint32_t mask = 0;
812 bool colorAttachmentsMask[WebGLContext::sMaxColorAttachments] = { false };
813 MOZ_ASSERT(colorAttachmentCount <= WebGLContext::sMaxColorAttachments);
815 for (size_t i = 0; i < colorAttachmentCount; i++) {
816 if (mColorAttachments[i].HasUninitializedImageData()) {
817 colorAttachmentsMask[i] = true;
818 mask |= LOCAL_GL_COLOR_BUFFER_BIT;
819 }
820 }
822 if (mDepthAttachment.HasUninitializedImageData() ||
823 mDepthStencilAttachment.HasUninitializedImageData())
824 {
825 mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
826 }
828 if (mStencilAttachment.HasUninitializedImageData() ||
829 mDepthStencilAttachment.HasUninitializedImageData())
830 {
831 mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
832 }
834 // Clear!
835 mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
837 // Mark all the uninitialized images as initialized.
838 for (size_t i = 0; i < colorAttachmentCount; i++) {
839 if (mColorAttachments[i].HasUninitializedImageData())
840 mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
841 }
843 if (mDepthAttachment.HasUninitializedImageData())
844 mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
845 if (mStencilAttachment.HasUninitializedImageData())
846 mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
847 if (mDepthStencilAttachment.HasUninitializedImageData())
848 mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
850 return true;
851 }
853 bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const
854 {
855 const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
857 if (mContext->IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
858 if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
859 attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mContext->mGLMaxColorAttachments))
860 {
861 mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
862 return false;
863 }
864 } else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0) {
865 if (attachment > LOCAL_GL_COLOR_ATTACHMENT0 &&
866 attachment <= LOCAL_GL_COLOR_ATTACHMENT15)
867 {
868 mContext->ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x. "
869 "Try the WEBGL_draw_buffers extension if supported.", functionName, attachment);
870 return false;
871 } else {
872 mContext->ErrorInvalidEnum(errorFormating, functionName, attachment);
873 return false;
874 }
875 }
877 return true;
878 }
880 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
881 {
882 MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments);
884 size_t currentAttachmentCount = mColorAttachments.Length();
885 if (colorAttachmentId < currentAttachmentCount)
886 return;
888 mColorAttachments.SetLength(colorAttachmentId + 1);
890 for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
891 mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i;
892 }
893 }
895 void
896 WebGLFramebuffer::NotifyAttachableChanged() const
897 {
898 // Attachment has changed, so invalidate cached status
899 mStatus = 0;
900 }
902 static void
903 FinalizeDrawAndReadBuffers(GLContext* aGL, bool aColorBufferDefined)
904 {
905 MOZ_ASSERT(aGL, "Expected a valid GLContext ptr.");
906 // GLES don't support DrawBuffer()/ReadBuffer.
907 // According to http://www.opengl.org/wiki/Framebuffer_Object
908 //
909 // Each draw buffers must either specify color attachment points that have images
910 // attached or must be GL_NONE. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER when false).
911 //
912 // If the read buffer is set, then it must specify an attachment point that has an
913 // image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER when false).
914 //
915 // Note that this test is not performed if OpenGL 4.2 or ARB_ES2_compatibility is
916 // available.
917 if (aGL->IsGLES() ||
918 aGL->IsSupported(GLFeature::ES2_compatibility) ||
919 aGL->IsAtLeast(ContextProfile::OpenGL, 420))
920 {
921 return;
922 }
924 // TODO(djg): Assert that fDrawBuffer/fReadBuffer is not NULL.
925 GLenum colorBufferSource = aColorBufferDefined ? LOCAL_GL_COLOR_ATTACHMENT0 : LOCAL_GL_NONE;
926 aGL->fDrawBuffer(colorBufferSource);
927 aGL->fReadBuffer(colorBufferSource);
928 }
930 void
931 WebGLFramebuffer::FinalizeAttachments() const
932 {
933 GLContext* gl = mContext->gl;
935 size_t count = ColorAttachmentCount();
936 for (size_t i = 0; i < count; i++) {
937 ColorAttachment(i).FinalizeAttachment(gl, LOCAL_GL_COLOR_ATTACHMENT0 + i);
938 }
940 DepthAttachment().FinalizeAttachment(gl, LOCAL_GL_DEPTH_ATTACHMENT);
941 StencilAttachment().FinalizeAttachment(gl, LOCAL_GL_STENCIL_ATTACHMENT);
942 DepthStencilAttachment().FinalizeAttachment(gl, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
944 FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined());
945 }
947 inline void
948 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& aField)
949 {
950 aField.mTexturePtr = nullptr;
951 aField.mRenderbufferPtr = nullptr;
952 }
954 inline void
955 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
956 mozilla::WebGLFramebuffer::Attachment& aField,
957 const char* aName,
958 uint32_t aFlags = 0)
959 {
960 CycleCollectionNoteChild(aCallback, aField.mTexturePtr.get(),
961 aName, aFlags);
963 CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
964 aName, aFlags);
965 }
967 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer,
968 mColorAttachments,
969 mDepthAttachment,
970 mStencilAttachment,
971 mDepthStencilAttachment)
973 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
974 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)