content/canvas/src/WebGLFramebuffer.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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)

mercurial