content/canvas/src/WebGLFramebuffer.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:e2ff502b286f
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/. */
5
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"
16
17 using namespace mozilla;
18 using namespace mozilla::gl;
19
20 JSObject*
21 WebGLFramebuffer::WrapObject(JSContext* cx)
22 {
23 return dom::WebGLFramebufferBinding::Wrap(cx, this);
24 }
25
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);
38
39 mColorAttachments.SetLength(1);
40 mColorAttachments[0].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0;
41 }
42
43 bool
44 WebGLFramebuffer::Attachment::IsDeleteRequested() const
45 {
46 return Texture() ? Texture()->IsDeleteRequested()
47 : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
48 : false;
49 }
50
51 bool
52 WebGLFramebuffer::Attachment::HasAlpha() const
53 {
54 MOZ_ASSERT(HasImage());
55
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 }
63
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 }
76
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 }
88
89 MOZ_ASSERT(false, "Should not get here.");
90 return false;
91 }
92
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;
100
101 mNeedsFinalize = true;
102 }
103
104 void
105 WebGLFramebuffer::Attachment::SetRenderbuffer(WebGLRenderbuffer* rb)
106 {
107 mTexturePtr = nullptr;
108 mRenderbufferPtr = rb;
109
110 mNeedsFinalize = true;
111 }
112
113 bool
114 WebGLFramebuffer::Attachment::HasUninitializedImageData() const
115 {
116 if (!HasImage())
117 return false;
118
119 if (Renderbuffer()) {
120 return Renderbuffer()->HasUninitializedImageData();
121 }
122
123 if (Texture()) {
124 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
125 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
126 }
127
128 MOZ_ASSERT(false, "Should not get here.");
129 return false;
130 }
131
132 void
133 WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus)
134 {
135 if (!HasImage())
136 return;
137
138 if (Renderbuffer()) {
139 Renderbuffer()->SetImageDataStatus(newStatus);
140 return;
141 }
142
143 if (Texture()) {
144 Texture()->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
145 return;
146 }
147
148 MOZ_ASSERT(false, "Should not get here.");
149 }
150
151 bool
152 WebGLFramebuffer::Attachment::HasImage() const
153 {
154 if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
155 return true;
156
157 if (Renderbuffer())
158 return true;
159
160 return false;
161 }
162
163 const WebGLRectangleObject&
164 WebGLFramebuffer::Attachment::RectangleObject() const
165 {
166 MOZ_ASSERT(HasImage(), "Make sure it has an image before requesting the rectangle.");
167
168 if (Texture()) {
169 MOZ_ASSERT(Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel));
170 return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
171 }
172
173 if (Renderbuffer()) {
174 return *Renderbuffer();
175 }
176
177 MOZ_CRASH("Should not get here.");
178 }
179
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 */
193
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 }
218
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 }
227
228 static inline bool
229 IsValidFBOTextureDepthStencilFormat(GLenum internalFormat)
230 {
231 return (
232 internalFormat == LOCAL_GL_DEPTH_STENCIL ||
233 internalFormat == LOCAL_GL_DEPTH24_STENCIL8);
234 }
235
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 }
248
249 static inline bool
250 IsValidFBORenderbufferDepthFormat(GLenum internalFormat)
251 {
252 return internalFormat == LOCAL_GL_DEPTH_COMPONENT16;
253 }
254
255 static inline bool
256 IsValidFBORenderbufferDepthStencilFormat(GLenum internalFormat)
257 {
258 return internalFormat == LOCAL_GL_DEPTH_STENCIL;
259 }
260
261 static inline bool
262 IsValidFBORenderbufferStencilFormat(GLenum internalFormat)
263 {
264 return internalFormat == LOCAL_GL_STENCIL_INDEX8;
265 }
266
267 bool
268 WebGLFramebuffer::Attachment::IsComplete() const
269 {
270 if (!HasImage())
271 return false;
272
273 const WebGLRectangleObject& rect = RectangleObject();
274
275 if (!rect.Width() ||
276 !rect.Height())
277 {
278 return false;
279 }
280
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();
286
287 if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
288 return IsValidFBOTextureDepthFormat(webGLFormat);
289
290 if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
291 return IsValidFBOTextureDepthStencilFormat(webGLFormat);
292
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 }
302
303 if (Renderbuffer()) {
304 GLenum internalFormat = Renderbuffer()->InternalFormat();
305
306 if (mAttachmentPoint == LOCAL_GL_DEPTH_ATTACHMENT)
307 return IsValidFBORenderbufferDepthFormat(internalFormat);
308
309 if (mAttachmentPoint == LOCAL_GL_STENCIL_ATTACHMENT)
310 return IsValidFBORenderbufferStencilFormat(internalFormat);
311
312 if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
313 return IsValidFBORenderbufferDepthStencilFormat(internalFormat);
314
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 }
324
325 MOZ_ASSERT(false, "Should not get here.");
326 return false;
327 }
328
329 void
330 WebGLFramebuffer::Attachment::FinalizeAttachment(GLContext* gl, GLenum attachmentLoc) const
331 {
332 if (!mNeedsFinalize)
333 return;
334
335 mNeedsFinalize = false;
336
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 }
347
348 return;
349 }
350 MOZ_ASSERT(HasImage());
351
352 if (Texture()) {
353 MOZ_ASSERT(gl == Texture()->Context()->gl);
354
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 }
366
367 if (Renderbuffer()) {
368 Renderbuffer()->FramebufferRenderbuffer(attachmentLoc);
369 return;
370 }
371
372 MOZ_ASSERT(false, "Should not get here.");
373 }
374
375 void
376 WebGLFramebuffer::Delete()
377 {
378 DetachAllAttachments();
379 mColorAttachments.Clear();
380 mDepthAttachment.Reset();
381 mStencilAttachment.Reset();
382 mDepthStencilAttachment.Reset();
383
384 mContext->MakeContextCurrent();
385 mContext->gl->fDeleteFramebuffers(1, &mGLName);
386 LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
387 }
388
389 void
390 WebGLFramebuffer::DetachAttachment(WebGLFramebuffer::Attachment& attachment)
391 {
392 if (attachment.Texture())
393 attachment.Texture()->DetachFrom(this, attachment.mAttachmentPoint);
394
395 if (attachment.Renderbuffer())
396 attachment.Renderbuffer()->DetachFrom(this, attachment.mAttachmentPoint);
397 }
398
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 }
406
407 DetachAttachment(mDepthAttachment);
408 DetachAttachment(mStencilAttachment);
409 DetachAttachment(mDepthStencilAttachment);
410 }
411
412 void
413 WebGLFramebuffer::FramebufferRenderbuffer(GLenum target,
414 GLenum attachment,
415 GLenum rbtarget,
416 WebGLRenderbuffer* wrb)
417 {
418 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
419
420 if (!mContext->ValidateObjectAllowNull("framebufferRenderbuffer: renderbuffer", wrb))
421 return;
422
423 if (target != LOCAL_GL_FRAMEBUFFER)
424 return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: target", target);
425
426 if (rbtarget != LOCAL_GL_RENDERBUFFER)
427 return mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: renderbuffer target:", rbtarget);
428
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.
439
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);
449
450 // Attach new
451 if (wrb)
452 wrb->AttachTo(this, attachment);
453
454 a->SetRenderbuffer(wrb);
455 }
456
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);
465
466 if (!mContext->ValidateObjectAllowNull("framebufferTexture2D: texture", wtex))
467 return;
468
469 if (target != LOCAL_GL_FRAMEBUFFER)
470 return mContext->ErrorInvalidEnumInfo("framebufferTexture2D: target", target);
471
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 }
478
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 }
486
487 if (level != 0)
488 return mContext->ErrorInvalidValue("framebufferTexture2D: level must be 0");
489
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.
500
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);
510
511 // Attach new
512 if (wtex)
513 wtex->AttachTo(this, attachment);
514
515 a->SetTexImage(wtex, textarget, level);
516 }
517
518 WebGLFramebuffer::Attachment*
519 WebGLFramebuffer::GetAttachmentOrNull(GLenum attachment)
520 {
521 if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
522 return &mDepthStencilAttachment;
523
524 if (attachment == LOCAL_GL_DEPTH_ATTACHMENT)
525 return &mDepthAttachment;
526
527 if (attachment == LOCAL_GL_STENCIL_ATTACHMENT)
528 return &mStencilAttachment;
529
530 if (!CheckColorAttachmentNumber(attachment, "getAttachmentOrNull"))
531 return nullptr;
532
533 size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
534 EnsureColorAttachments(colorAttachmentId);
535
536 return &mColorAttachments[colorAttachmentId];
537 }
538
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;
548
549 if (!CheckColorAttachmentNumber(attachment, "getAttachment")) {
550 MOZ_ASSERT(false);
551 return mColorAttachments[0];
552 }
553
554 size_t colorAttachmentId = attachment - LOCAL_GL_COLOR_ATTACHMENT0;
555 if (colorAttachmentId >= mColorAttachments.Length()) {
556 MOZ_ASSERT(false);
557 return mColorAttachments[0];
558 }
559
560 return mColorAttachments[colorAttachmentId];
561 }
562
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 }
573
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 }
581
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 }
592
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 }
600
601 bool
602 WebGLFramebuffer::HasDefinedAttachments() const
603 {
604 bool hasAttachments = false;
605
606 size_t count = mColorAttachments.Length();
607 for (size_t i = 0; i < count; i++) {
608 hasAttachments |= mColorAttachments[i].IsDefined();
609 }
610
611 hasAttachments |= mDepthAttachment.IsDefined();
612 hasAttachments |= mStencilAttachment.IsDefined();
613 hasAttachments |= mDepthStencilAttachment.IsDefined();
614
615 return hasAttachments;
616 }
617
618
619 static bool
620 IsIncomplete(const WebGLFramebuffer::Attachment& cur)
621 {
622 return cur.IsDefined() && !cur.IsComplete();
623 }
624
625 bool
626 WebGLFramebuffer::HasIncompleteAttachments() const
627 {
628 bool hasIncomplete = false;
629
630 size_t count = mColorAttachments.Length();
631 for (size_t i = 0; i < count; i++) {
632 hasIncomplete |= IsIncomplete(mColorAttachments[i]);
633 }
634
635 hasIncomplete |= IsIncomplete(mDepthAttachment);
636 hasIncomplete |= IsIncomplete(mStencilAttachment);
637 hasIncomplete |= IsIncomplete(mDepthStencilAttachment);
638
639 return hasIncomplete;
640 }
641
642
643 const WebGLRectangleObject&
644 WebGLFramebuffer::GetAnyRectObject() const
645 {
646 MOZ_ASSERT(HasDefinedAttachments());
647
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 }
653
654 if (mDepthAttachment.HasImage())
655 return mDepthAttachment.RectangleObject();
656
657 if (mStencilAttachment.HasImage())
658 return mStencilAttachment.RectangleObject();
659
660 if (mDepthStencilAttachment.HasImage())
661 return mDepthStencilAttachment.RectangleObject();
662
663 MOZ_CRASH("Should not get here.");
664 }
665
666
667 static bool
668 RectsMatch(const WebGLFramebuffer::Attachment& attachment,
669 const WebGLRectangleObject& rect)
670 {
671 return attachment.RectangleObject().HasSameDimensionsAs(rect);
672 }
673
674 bool
675 WebGLFramebuffer::AllImageRectsMatch() const
676 {
677 MOZ_ASSERT(HasDefinedAttachments());
678 MOZ_ASSERT(!HasIncompleteAttachments());
679
680 const WebGLRectangleObject& rect = GetAnyRectObject();
681
682 // Alright, we have *a* rect, let's check all the others.
683 bool imageRectsMatch = true;
684
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 }
690
691 if (mDepthAttachment.HasImage())
692 imageRectsMatch &= RectsMatch(mDepthAttachment, rect);
693
694 if (mStencilAttachment.HasImage())
695 imageRectsMatch &= RectsMatch(mStencilAttachment, rect);
696
697 if (mDepthStencilAttachment.HasImage())
698 imageRectsMatch &= RectsMatch(mDepthStencilAttachment, rect);
699
700 return imageRectsMatch;
701 }
702
703
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 }
712
713 GLenum
714 WebGLFramebuffer::PrecheckFramebufferStatus() const
715 {
716 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
717
718 if (!HasDefinedAttachments())
719 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
720
721 if (HasIncompleteAttachments())
722 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
723
724 if (!AllImageRectsMatch())
725 return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
726
727 if (HasDepthStencilConflict())
728 return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
729
730 return LOCAL_GL_FRAMEBUFFER_COMPLETE;
731 }
732
733 GLenum
734 WebGLFramebuffer::CheckFramebufferStatus() const
735 {
736 if (mStatus != 0)
737 return mStatus;
738
739 mStatus = PrecheckFramebufferStatus();
740 if (mStatus != LOCAL_GL_FRAMEBUFFER_COMPLETE)
741 return mStatus;
742
743 // Looks good on our end. Let's ask the driver.
744 mContext->MakeContextCurrent();
745
746 // Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
747 FinalizeAttachments();
748
749 mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
750 return mStatus;
751 }
752
753 bool
754 WebGLFramebuffer::HasCompletePlanes(GLbitfield mask)
755 {
756 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
757 return false;
758
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 }
765
766 if (mask & LOCAL_GL_DEPTH_BUFFER_BIT) {
767 hasPlanes &= DepthAttachment().IsDefined() ||
768 DepthStencilAttachment().IsDefined();
769 }
770
771 if (mask & LOCAL_GL_STENCIL_BUFFER_BIT) {
772 hasPlanes &= StencilAttachment().IsDefined() ||
773 DepthStencilAttachment().IsDefined();
774 }
775
776 return hasPlanes;
777 }
778
779 bool
780 WebGLFramebuffer::CheckAndInitializeAttachments()
781 {
782 MOZ_ASSERT(mContext->mBoundFramebuffer == this);
783
784 if (CheckFramebufferStatus() != LOCAL_GL_FRAMEBUFFER_COMPLETE)
785 return false;
786
787 // Cool! We've checked out ok. Just need to initialize.
788 size_t colorAttachmentCount = mColorAttachments.Length();
789
790 // Check if we need to initialize anything
791 {
792 bool hasUninitializedAttachments = false;
793
794 for (size_t i = 0; i < colorAttachmentCount; i++) {
795 if (mColorAttachments[i].HasImage())
796 hasUninitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
797 }
798
799 if (mDepthAttachment.HasImage())
800 hasUninitializedAttachments |= mDepthAttachment.HasUninitializedImageData();
801 if (mStencilAttachment.HasImage())
802 hasUninitializedAttachments |= mStencilAttachment.HasUninitializedImageData();
803 if (mDepthStencilAttachment.HasImage())
804 hasUninitializedAttachments |= mDepthStencilAttachment.HasUninitializedImageData();
805
806 if (!hasUninitializedAttachments)
807 return true;
808 }
809
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);
814
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 }
821
822 if (mDepthAttachment.HasUninitializedImageData() ||
823 mDepthStencilAttachment.HasUninitializedImageData())
824 {
825 mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
826 }
827
828 if (mStencilAttachment.HasUninitializedImageData() ||
829 mDepthStencilAttachment.HasUninitializedImageData())
830 {
831 mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
832 }
833
834 // Clear!
835 mContext->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
836
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 }
842
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);
849
850 return true;
851 }
852
853 bool WebGLFramebuffer::CheckColorAttachmentNumber(GLenum attachment, const char* functionName) const
854 {
855 const char* const errorFormating = "%s: attachment: invalid enum value 0x%x";
856
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 }
876
877 return true;
878 }
879
880 void WebGLFramebuffer::EnsureColorAttachments(size_t colorAttachmentId)
881 {
882 MOZ_ASSERT(colorAttachmentId < WebGLContext::sMaxColorAttachments);
883
884 size_t currentAttachmentCount = mColorAttachments.Length();
885 if (colorAttachmentId < currentAttachmentCount)
886 return;
887
888 mColorAttachments.SetLength(colorAttachmentId + 1);
889
890 for (size_t i = colorAttachmentId; i >= currentAttachmentCount; i--) {
891 mColorAttachments[i].mAttachmentPoint = LOCAL_GL_COLOR_ATTACHMENT0 + i;
892 }
893 }
894
895 void
896 WebGLFramebuffer::NotifyAttachableChanged() const
897 {
898 // Attachment has changed, so invalidate cached status
899 mStatus = 0;
900 }
901
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 }
923
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 }
929
930 void
931 WebGLFramebuffer::FinalizeAttachments() const
932 {
933 GLContext* gl = mContext->gl;
934
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 }
939
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);
943
944 FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined());
945 }
946
947 inline void
948 ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& aField)
949 {
950 aField.mTexturePtr = nullptr;
951 aField.mRenderbufferPtr = nullptr;
952 }
953
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);
962
963 CycleCollectionNoteChild(aCallback, aField.mRenderbufferPtr.get(),
964 aName, aFlags);
965 }
966
967 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_4(WebGLFramebuffer,
968 mColorAttachments,
969 mDepthAttachment,
970 mStencilAttachment,
971 mDepthStencilAttachment)
972
973 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
974 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)

mercurial