LCOV - code coverage report
Current view: top level - dom/canvas - WebGLFramebuffer.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 952 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 78 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "WebGLFramebuffer.h"
       7             : 
       8             : // You know it's going to be fun when these two show up:
       9             : #include <algorithm>
      10             : #include <iterator>
      11             : 
      12             : #include "GLContext.h"
      13             : #include "GLScreenBuffer.h"
      14             : #include "mozilla/dom/WebGLRenderingContextBinding.h"
      15             : #include "nsPrintfCString.h"
      16             : #include "WebGLContext.h"
      17             : #include "WebGLContextUtils.h"
      18             : #include "WebGLExtensions.h"
      19             : #include "WebGLRenderbuffer.h"
      20             : #include "WebGLTexture.h"
      21             : 
      22             : namespace mozilla {
      23             : 
      24           0 : WebGLFBAttachPoint::WebGLFBAttachPoint()
      25             :     : mFB(nullptr)
      26             :     , mAttachmentPoint(0)
      27             :     , mTexImageTarget(LOCAL_GL_NONE)
      28             :     , mTexImageLayer(0)
      29           0 :     , mTexImageLevel(0)
      30           0 : { }
      31             : 
      32           0 : WebGLFBAttachPoint::WebGLFBAttachPoint(WebGLFramebuffer* fb, GLenum attachmentPoint)
      33             :     : mFB(fb)
      34             :     , mAttachmentPoint(attachmentPoint)
      35             :     , mTexImageTarget(LOCAL_GL_NONE)
      36             :     , mTexImageLayer(0)
      37           0 :     , mTexImageLevel(0)
      38           0 : { }
      39             : 
      40           0 : WebGLFBAttachPoint::~WebGLFBAttachPoint()
      41             : {
      42           0 :     MOZ_ASSERT(mFB, "Should have been Init'd.");
      43           0 :     MOZ_ASSERT(!mRenderbufferPtr);
      44           0 :     MOZ_ASSERT(!mTexturePtr);
      45           0 : }
      46             : 
      47             : void
      48           0 : WebGLFBAttachPoint::Unlink()
      49             : {
      50           0 :     const char funcName[] = "WebGLFramebuffer::GC";
      51           0 :     Clear(funcName);
      52           0 : }
      53             : 
      54             : bool
      55           0 : WebGLFBAttachPoint::IsDeleteRequested() const
      56             : {
      57           0 :     return Texture() ? Texture()->IsDeleteRequested()
      58           0 :          : Renderbuffer() ? Renderbuffer()->IsDeleteRequested()
      59           0 :          : false;
      60             : }
      61             : 
      62             : bool
      63           0 : WebGLFBAttachPoint::IsDefined() const
      64             : {
      65             :     /*
      66             :     return (Renderbuffer() && Renderbuffer()->IsDefined()) ||
      67             :            (Texture() && Texture()->ImageInfoAt(mTexImageTarget,
      68             :                                                 mTexImageLevel).IsDefined());
      69             :     */
      70           0 :     return (Renderbuffer() || Texture());
      71             : }
      72             : 
      73             : const webgl::FormatUsageInfo*
      74           0 : WebGLFBAttachPoint::Format() const
      75             : {
      76           0 :     MOZ_ASSERT(IsDefined());
      77             : 
      78           0 :     if (Texture())
      79           0 :         return Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).mFormat;
      80             : 
      81           0 :     if (Renderbuffer())
      82           0 :         return Renderbuffer()->Format();
      83             : 
      84           0 :     return nullptr;
      85             : }
      86             : 
      87             : uint32_t
      88           0 : WebGLFBAttachPoint::Samples() const
      89             : {
      90           0 :     MOZ_ASSERT(IsDefined());
      91             : 
      92           0 :     if (mRenderbufferPtr)
      93           0 :         return mRenderbufferPtr->Samples();
      94             : 
      95           0 :     return 0;
      96             : }
      97             : 
      98             : bool
      99           0 : WebGLFBAttachPoint::HasAlpha() const
     100             : {
     101           0 :     return Format()->format->a;
     102             : }
     103             : 
     104             : bool
     105           0 : WebGLFBAttachPoint::IsReadableFloat() const
     106             : {
     107           0 :     auto formatUsage = Format();
     108           0 :     MOZ_ASSERT(formatUsage);
     109             : 
     110           0 :     auto format = formatUsage->format;
     111           0 :     if (!format->IsColorFormat())
     112           0 :         return false;
     113             : 
     114           0 :     return format->componentType == webgl::ComponentType::Float;
     115             : }
     116             : 
     117             : void
     118           0 : WebGLFBAttachPoint::Clear(const char* funcName)
     119             : {
     120           0 :     if (mRenderbufferPtr) {
     121           0 :         MOZ_ASSERT(!mTexturePtr);
     122           0 :         mRenderbufferPtr->UnmarkAttachment(*this);
     123           0 :     } else if (mTexturePtr) {
     124           0 :         mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).RemoveAttachPoint(this);
     125             :     }
     126             : 
     127           0 :     mTexturePtr = nullptr;
     128           0 :     mRenderbufferPtr = nullptr;
     129             : 
     130           0 :     OnBackingStoreRespecified(funcName);
     131           0 : }
     132             : 
     133             : void
     134           0 : WebGLFBAttachPoint::SetTexImage(const char* funcName, WebGLTexture* tex,
     135             :                                 TexImageTarget target, GLint level, GLint layer)
     136             : {
     137           0 :     Clear(funcName);
     138             : 
     139           0 :     mTexturePtr = tex;
     140           0 :     mTexImageTarget = target;
     141           0 :     mTexImageLevel = level;
     142           0 :     mTexImageLayer = layer;
     143             : 
     144           0 :     if (mTexturePtr) {
     145           0 :         mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).AddAttachPoint(this);
     146             :     }
     147           0 : }
     148             : 
     149             : void
     150           0 : WebGLFBAttachPoint::SetRenderbuffer(const char* funcName, WebGLRenderbuffer* rb)
     151             : {
     152           0 :     Clear(funcName);
     153             : 
     154           0 :     mRenderbufferPtr = rb;
     155             : 
     156           0 :     if (mRenderbufferPtr) {
     157           0 :         mRenderbufferPtr->MarkAttachment(*this);
     158             :     }
     159           0 : }
     160             : 
     161             : bool
     162           0 : WebGLFBAttachPoint::HasUninitializedImageData() const
     163             : {
     164           0 :     if (!HasImage())
     165           0 :         return false;
     166             : 
     167           0 :     if (mRenderbufferPtr)
     168           0 :         return mRenderbufferPtr->HasUninitializedImageData();
     169             : 
     170           0 :     MOZ_ASSERT(mTexturePtr);
     171             : 
     172           0 :     auto& imageInfo = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel);
     173           0 :     MOZ_ASSERT(imageInfo.IsDefined());
     174             : 
     175           0 :     return !imageInfo.IsDataInitialized();
     176             : }
     177             : 
     178             : void
     179           0 : WebGLFBAttachPoint::SetImageDataStatus(WebGLImageDataStatus newStatus) const
     180             : {
     181           0 :     if (!HasImage())
     182           0 :         return;
     183             : 
     184           0 :     if (mRenderbufferPtr) {
     185           0 :         mRenderbufferPtr->mImageDataStatus = newStatus;
     186           0 :         return;
     187             :     }
     188             : 
     189           0 :     MOZ_ASSERT(mTexturePtr);
     190             : 
     191           0 :     auto& imageInfo = mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel);
     192           0 :     MOZ_ASSERT(imageInfo.IsDefined());
     193             : 
     194           0 :     const bool isDataInitialized = (newStatus == WebGLImageDataStatus::InitializedImageData);
     195           0 :     imageInfo.SetIsDataInitialized(isDataInitialized, mTexturePtr);
     196             : }
     197             : 
     198             : bool
     199           0 : WebGLFBAttachPoint::HasImage() const
     200             : {
     201           0 :     if (Texture() && Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).IsDefined())
     202           0 :         return true;
     203             : 
     204           0 :     if (Renderbuffer() && Renderbuffer()->IsDefined())
     205           0 :         return true;
     206             : 
     207           0 :     return false;
     208             : }
     209             : 
     210             : void
     211           0 : WebGLFBAttachPoint::Size(uint32_t* const out_width, uint32_t* const out_height) const
     212             : {
     213           0 :     MOZ_ASSERT(HasImage());
     214             : 
     215           0 :     if (Renderbuffer()) {
     216           0 :         *out_width = Renderbuffer()->Width();
     217           0 :         *out_height = Renderbuffer()->Height();
     218           0 :         return;
     219             :     }
     220             : 
     221           0 :     MOZ_ASSERT(Texture());
     222           0 :     MOZ_ASSERT(Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).IsDefined());
     223           0 :     const auto& imageInfo = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel);
     224             : 
     225           0 :     *out_width = imageInfo.mWidth;
     226           0 :     *out_height = imageInfo.mHeight;
     227             : }
     228             : 
     229             : void
     230           0 : WebGLFBAttachPoint::OnBackingStoreRespecified(const char* funcName) const
     231             : {
     232           0 :     mFB->InvalidateFramebufferStatus(funcName);
     233           0 : }
     234             : 
     235             : void
     236           0 : WebGLFBAttachPoint::AttachmentName(nsCString* out) const
     237             : {
     238           0 :     switch (mAttachmentPoint) {
     239             :     case LOCAL_GL_DEPTH_ATTACHMENT:
     240           0 :         out->AssignLiteral("DEPTH_ATTACHMENT");
     241           0 :         return;
     242             : 
     243             :     case LOCAL_GL_STENCIL_ATTACHMENT:
     244           0 :         out->AssignLiteral("STENCIL_ATTACHMENT");
     245           0 :         return;
     246             : 
     247             :     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
     248           0 :         out->AssignLiteral("DEPTH_STENCIL_ATTACHMENT");
     249           0 :         return;
     250             : 
     251             :     default:
     252           0 :         MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
     253           0 :         out->AssignLiteral("COLOR_ATTACHMENT");
     254           0 :         const uint32_t n = mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0;
     255           0 :         out->AppendInt(n);
     256           0 :         return;
     257             :     }
     258             : }
     259             : 
     260             : bool
     261           0 : WebGLFBAttachPoint::IsComplete(WebGLContext* webgl, nsCString* const out_info) const
     262             : {
     263           0 :     MOZ_ASSERT(IsDefined());
     264             : 
     265           0 :     if (!HasImage()) {
     266           0 :         AttachmentName(out_info);
     267           0 :         out_info->AppendLiteral("'s image is not defined");
     268           0 :         return false;
     269             :     }
     270             : 
     271             :     uint32_t width;
     272             :     uint32_t height;
     273           0 :     Size(&width, &height);
     274           0 :     if (!width || !height) {
     275           0 :         AttachmentName(out_info);
     276           0 :         out_info->AppendLiteral(" has no width or height");
     277           0 :         return false;
     278             :     }
     279             : 
     280           0 :     const auto formatUsage = Format();
     281           0 :     if (!formatUsage->IsRenderable()) {
     282           0 :         nsAutoCString attachName;
     283           0 :         AttachmentName(&attachName);
     284             : 
     285           0 :         *out_info = nsPrintfCString("%s has an effective format of %s, which is not"
     286             :                                     " renderable",
     287           0 :                                     attachName.BeginReading(), formatUsage->format->name);
     288           0 :         return false;
     289             :     }
     290             : 
     291           0 :     if (webgl->IsWebGL2() && Texture() &&
     292           0 :         Texture()->IsCubeMap() && !Texture()->IsCubeComplete())
     293             :     {
     294           0 :         AttachmentName(out_info);
     295           0 :         out_info->AppendLiteral(" is not cube complete");
     296           0 :         return false;
     297             :     }
     298             : 
     299           0 :     const auto format = formatUsage->format;
     300             : 
     301             :     bool hasRequiredBits;
     302             : 
     303           0 :     switch (mAttachmentPoint) {
     304             :     case LOCAL_GL_DEPTH_ATTACHMENT:
     305           0 :         hasRequiredBits = format->d;
     306           0 :         break;
     307             : 
     308             :     case LOCAL_GL_STENCIL_ATTACHMENT:
     309           0 :         hasRequiredBits = format->s;
     310           0 :         break;
     311             : 
     312             :     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
     313           0 :         MOZ_ASSERT(!webgl->IsWebGL2());
     314           0 :         hasRequiredBits = (format->d && format->s);
     315           0 :         break;
     316             : 
     317             :     default:
     318           0 :         MOZ_ASSERT(mAttachmentPoint >= LOCAL_GL_COLOR_ATTACHMENT0);
     319           0 :         hasRequiredBits = format->IsColorFormat();
     320           0 :         break;
     321             :     }
     322             : 
     323           0 :     if (!hasRequiredBits) {
     324           0 :         AttachmentName(out_info);
     325           0 :         out_info->AppendLiteral("'s format is missing required color/depth/stencil bits");
     326           0 :         return false;
     327             :     }
     328             : 
     329           0 :     if (!webgl->IsWebGL2()) {
     330           0 :         bool hasSurplusPlanes = false;
     331             : 
     332           0 :         switch (mAttachmentPoint) {
     333             :         case LOCAL_GL_DEPTH_ATTACHMENT:
     334           0 :             hasSurplusPlanes = format->s;
     335           0 :             break;
     336             : 
     337             :         case LOCAL_GL_STENCIL_ATTACHMENT:
     338           0 :             hasSurplusPlanes = format->d;
     339           0 :             break;
     340             :         }
     341             : 
     342           0 :         if (hasSurplusPlanes) {
     343           0 :             AttachmentName(out_info);
     344           0 :             out_info->AppendLiteral("'s format has depth or stencil bits when it"
     345           0 :                                     " shouldn't");
     346           0 :             return false;
     347             :         }
     348             :     }
     349             : 
     350           0 :     return true;
     351             : }
     352             : 
     353             : void
     354           0 : WebGLFBAttachPoint::Resolve(gl::GLContext* gl) const
     355             : {
     356           0 :     if (!HasImage())
     357           0 :         return;
     358             : 
     359           0 :     if (Renderbuffer()) {
     360           0 :         Renderbuffer()->DoFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, mAttachmentPoint);
     361           0 :         return;
     362             :     }
     363           0 :     MOZ_ASSERT(Texture());
     364             : 
     365           0 :     MOZ_ASSERT(gl == Texture()->mContext->GL());
     366             : 
     367           0 :     const auto& texName = Texture()->mGLName;
     368             : 
     369             :     ////
     370             : 
     371           0 :     const auto fnAttach2D = [&](GLenum attachmentPoint) {
     372           0 :         gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, attachmentPoint,
     373           0 :                                   mTexImageTarget.get(), texName, mTexImageLevel);
     374           0 :     };
     375             : 
     376             :     ////
     377             : 
     378           0 :     switch (mTexImageTarget.get()) {
     379             :     case LOCAL_GL_TEXTURE_2D:
     380             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     381             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     382             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     383             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     384             :     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     385             :     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
     386           0 :         if (mAttachmentPoint == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
     387           0 :             fnAttach2D(LOCAL_GL_DEPTH_ATTACHMENT);
     388           0 :             fnAttach2D(LOCAL_GL_STENCIL_ATTACHMENT);
     389             :         } else {
     390           0 :             fnAttach2D(mAttachmentPoint);
     391             :         }
     392           0 :         break;
     393             : 
     394             :     case LOCAL_GL_TEXTURE_2D_ARRAY:
     395             :     case LOCAL_GL_TEXTURE_3D:
     396             :         // If we have fFramebufferTextureLayer, we can rely on having
     397             :         // DEPTH_STENCIL_ATTACHMENT.
     398           0 :         gl->fFramebufferTextureLayer(LOCAL_GL_FRAMEBUFFER, mAttachmentPoint, texName,
     399           0 :                                      mTexImageLevel, mTexImageLayer);
     400           0 :         break;
     401             :     }
     402             : }
     403             : 
     404             : JS::Value
     405           0 : WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSContext* cx,
     406             :                                  GLenum target, GLenum attachment, GLenum pname,
     407             :                                  ErrorResult* const out_error) const
     408             : {
     409           0 :     const bool hasAttachment = (mTexturePtr || mRenderbufferPtr);
     410           0 :     if (!hasAttachment) {
     411             :         // Divergent between GLES 3 and 2.
     412             : 
     413             :         // GLES 2.0.25 p127:
     414             :         // "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, then querying any
     415             :         //  other pname will generate INVALID_ENUM."
     416             : 
     417             :         // GLES 3.0.4 p240:
     418             :         // "If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is NONE, no framebuffer is
     419             :         //  bound to target. In this case querying pname
     420             :         //  FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero, and all other queries
     421             :         //  will generate an INVALID_OPERATION error."
     422           0 :         switch (pname) {
     423             :         case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
     424           0 :             return JS::Int32Value(LOCAL_GL_NONE);
     425             : 
     426             :         case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
     427           0 :             if (webgl->IsWebGL2())
     428           0 :                 return JS::NullValue();
     429             : 
     430           0 :             break;
     431             : 
     432             :         default:
     433           0 :             break;
     434             :         }
     435           0 :         nsCString attachmentName;
     436           0 :         WebGLContext::EnumName(attachment, &attachmentName);
     437           0 :         if (webgl->IsWebGL2()) {
     438           0 :             webgl->ErrorInvalidOperation("%s: No attachment at %s.", funcName,
     439           0 :                                          attachmentName.BeginReading());
     440             :         } else {
     441           0 :             webgl->ErrorInvalidEnum("%s: No attachment at %s.", funcName,
     442           0 :                                     attachmentName.BeginReading());
     443             :         }
     444           0 :         return JS::NullValue();
     445             :     }
     446             : 
     447           0 :     bool isPNameValid = false;
     448           0 :     switch (pname) {
     449             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
     450             :         return JS::Int32Value(mTexturePtr ? LOCAL_GL_TEXTURE
     451           0 :                                           : LOCAL_GL_RENDERBUFFER);
     452             : 
     453             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
     454           0 :         return (mTexturePtr ? webgl->WebGLObjectAsJSValue(cx, mTexturePtr.get(),
     455             :                                                           *out_error)
     456           0 :                             : webgl->WebGLObjectAsJSValue(cx, mRenderbufferPtr.get(),
     457           0 :                                                           *out_error));
     458             : 
     459             :         //////
     460             : 
     461             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
     462           0 :         if (mTexturePtr)
     463           0 :             return JS::Int32Value(MipLevel());
     464           0 :         break;
     465             : 
     466             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
     467           0 :         if (mTexturePtr) {
     468           0 :             GLenum face = 0;
     469           0 :             if (mTexturePtr->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) {
     470           0 :                 face = ImageTarget().get();
     471             :             }
     472           0 :             return JS::Int32Value(face);
     473             :         }
     474           0 :         break;
     475             : 
     476             :         //////
     477             : 
     478             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
     479           0 :         if (webgl->IsWebGL2() && mTexturePtr) {
     480           0 :             int32_t layer = 0;
     481           0 :             if (ImageTarget() == LOCAL_GL_TEXTURE_2D_ARRAY ||
     482           0 :                 ImageTarget() == LOCAL_GL_TEXTURE_3D)
     483             :             {
     484           0 :                 layer = Layer();
     485             :             }
     486           0 :             return JS::Int32Value(layer);
     487             :         }
     488           0 :         break;
     489             : 
     490             :         //////
     491             : 
     492             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
     493             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
     494             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
     495             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
     496             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
     497             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
     498             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
     499           0 :         isPNameValid = webgl->IsWebGL2();
     500           0 :         break;
     501             : 
     502             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
     503           0 :         isPNameValid = (webgl->IsWebGL2() ||
     504           0 :                         webgl->IsExtensionEnabled(WebGLExtensionID::EXT_sRGB));
     505           0 :         break;
     506             :     }
     507             : 
     508           0 :     if (!isPNameValid) {
     509           0 :         webgl->ErrorInvalidEnum("%s: Invalid pname: 0x%04x", funcName, pname);
     510           0 :         return JS::NullValue();
     511             :     }
     512             : 
     513           0 :     const auto usage = Format();
     514           0 :     if (!usage) {
     515           0 :         if (pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING)
     516           0 :             return JS::NumberValue(LOCAL_GL_LINEAR);
     517             : 
     518           0 :         return JS::NullValue();
     519             :     }
     520             : 
     521           0 :     auto format = usage->format;
     522             : 
     523           0 :     GLint ret = 0;
     524           0 :     switch (pname) {
     525             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
     526           0 :         ret = format->r;
     527           0 :         break;
     528             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
     529           0 :         ret = format->g;
     530           0 :         break;
     531             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
     532           0 :         ret = format->b;
     533           0 :         break;
     534             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
     535           0 :         ret = format->a;
     536           0 :         break;
     537             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
     538           0 :         ret = format->d;
     539           0 :         break;
     540             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
     541           0 :         ret = format->s;
     542           0 :         break;
     543             : 
     544             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
     545           0 :         ret = (format->isSRGB ? LOCAL_GL_SRGB
     546             :                               : LOCAL_GL_LINEAR);
     547           0 :         break;
     548             : 
     549             :     case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
     550           0 :         MOZ_ASSERT(attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT);
     551             : 
     552           0 :         if (format->componentType == webgl::ComponentType::Special) {
     553             :             // Special format is used for DS mixed format(e.g. D24S8 and D32FS8).
     554           0 :             MOZ_ASSERT(format->unsizedFormat == webgl::UnsizedFormat::DEPTH_STENCIL);
     555           0 :             MOZ_ASSERT(attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
     556             :                        attachment == LOCAL_GL_STENCIL_ATTACHMENT);
     557             : 
     558           0 :             if (attachment == LOCAL_GL_DEPTH_ATTACHMENT) {
     559           0 :                 switch (format->effectiveFormat) {
     560             :                 case webgl::EffectiveFormat::DEPTH24_STENCIL8:
     561           0 :                     format = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT24);
     562           0 :                     break;
     563             :                 case webgl::EffectiveFormat::DEPTH32F_STENCIL8:
     564           0 :                     format = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT32F);
     565           0 :                     break;
     566             :                 default:
     567           0 :                     MOZ_ASSERT(false, "no matched DS format");
     568             :                     break;
     569             :                 }
     570           0 :             } else if (attachment == LOCAL_GL_STENCIL_ATTACHMENT) {
     571           0 :                 switch (format->effectiveFormat) {
     572             :                 case webgl::EffectiveFormat::DEPTH24_STENCIL8:
     573             :                 case webgl::EffectiveFormat::DEPTH32F_STENCIL8:
     574           0 :                     format = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
     575           0 :                     break;
     576             :                 default:
     577           0 :                     MOZ_ASSERT(false, "no matched DS format");
     578             :                     break;
     579             :                 }
     580             :             }
     581             :         }
     582             : 
     583           0 :         switch (format->componentType) {
     584             :         case webgl::ComponentType::None:
     585           0 :             ret = LOCAL_GL_NONE;
     586           0 :             break;
     587             :         case webgl::ComponentType::Int:
     588           0 :             ret = LOCAL_GL_INT;
     589           0 :             break;
     590             :         case webgl::ComponentType::UInt:
     591           0 :             ret = LOCAL_GL_UNSIGNED_INT;
     592           0 :             break;
     593             :         case webgl::ComponentType::NormInt:
     594           0 :             ret = LOCAL_GL_SIGNED_NORMALIZED;
     595           0 :             break;
     596             :         case webgl::ComponentType::NormUInt:
     597           0 :             ret = LOCAL_GL_UNSIGNED_NORMALIZED;
     598           0 :             break;
     599             :         case webgl::ComponentType::Float:
     600           0 :             ret = LOCAL_GL_FLOAT;
     601           0 :             break;
     602             :         default:
     603           0 :             MOZ_ASSERT(false, "No matched component type");
     604             :             break;
     605             :         }
     606           0 :         break;
     607             : 
     608             :     default:
     609           0 :         MOZ_ASSERT(false, "Missing case.");
     610             :         break;
     611             :     }
     612             : 
     613           0 :     return JS::Int32Value(ret);
     614             : }
     615             : 
     616             : ////////////////////////////////////////////////////////////////////////////////
     617             : ////////////////////////////////////////////////////////////////////////////////
     618             : // WebGLFramebuffer
     619             : 
     620           0 : WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
     621             :     : WebGLRefCountedObject(webgl)
     622             :     , mGLName(fbo)
     623             :     , mNumFBStatusInvals(0)
     624             : #ifdef ANDROID
     625             :     , mIsFB(false)
     626             : #endif
     627             :     , mDepthAttachment(this, LOCAL_GL_DEPTH_ATTACHMENT)
     628             :     , mStencilAttachment(this, LOCAL_GL_STENCIL_ATTACHMENT)
     629           0 :     , mDepthStencilAttachment(this, LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
     630             : {
     631           0 :     mContext->mFramebuffers.insertBack(this);
     632             : 
     633           0 :     size_t i = 0;
     634           0 :     for (auto& cur : mColorAttachments) {
     635           0 :         new (&cur) WebGLFBAttachPoint(this, LOCAL_GL_COLOR_ATTACHMENT0 + i);
     636           0 :         i++;
     637             :     }
     638             : 
     639           0 :     mColorDrawBuffers.push_back(&mColorAttachments[0]);
     640           0 :     mColorReadBuffer = &mColorAttachments[0];
     641           0 : }
     642             : 
     643             : void
     644           0 : WebGLFramebuffer::Delete()
     645             : {
     646           0 :     const char funcName[] = "WebGLFramebuffer::Delete";
     647             : 
     648           0 :     InvalidateFramebufferStatus(funcName);
     649             : 
     650           0 :     mDepthAttachment.Clear(funcName);
     651           0 :     mStencilAttachment.Clear(funcName);
     652           0 :     mDepthStencilAttachment.Clear(funcName);
     653             : 
     654           0 :     for (auto& cur : mColorAttachments) {
     655           0 :         cur.Clear(funcName);
     656             :     }
     657             : 
     658           0 :     mContext->MakeContextCurrent();
     659           0 :     mContext->gl->fDeleteFramebuffers(1, &mGLName);
     660             : 
     661           0 :     LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
     662             : 
     663             : #ifdef ANDROID
     664             :     mIsFB = false;
     665             : #endif
     666           0 : }
     667             : 
     668             : ////
     669             : 
     670             : Maybe<WebGLFBAttachPoint*>
     671           0 : WebGLFramebuffer::GetColorAttachPoint(GLenum attachPoint)
     672             : {
     673           0 :     if (attachPoint == LOCAL_GL_NONE)
     674           0 :         return Some<WebGLFBAttachPoint*>(nullptr);
     675             : 
     676           0 :     if (attachPoint < LOCAL_GL_COLOR_ATTACHMENT0)
     677           0 :         return Nothing();
     678             : 
     679           0 :     const size_t colorId = attachPoint - LOCAL_GL_COLOR_ATTACHMENT0;
     680             : 
     681           0 :     MOZ_ASSERT(mContext->mImplMaxColorAttachments <= kMaxColorAttachments);
     682           0 :     if (colorId >= mContext->mImplMaxColorAttachments)
     683           0 :         return Nothing();
     684             : 
     685           0 :     return Some(&mColorAttachments[colorId]);
     686             : }
     687             : 
     688             : Maybe<WebGLFBAttachPoint*>
     689           0 : WebGLFramebuffer::GetAttachPoint(GLenum attachPoint)
     690             : {
     691           0 :     switch (attachPoint) {
     692             :     case LOCAL_GL_DEPTH_STENCIL_ATTACHMENT:
     693           0 :         return Some(&mDepthStencilAttachment);
     694             : 
     695             :     case LOCAL_GL_DEPTH_ATTACHMENT:
     696           0 :         return Some(&mDepthAttachment);
     697             : 
     698             :     case LOCAL_GL_STENCIL_ATTACHMENT:
     699           0 :         return Some(&mStencilAttachment);
     700             : 
     701             :     default:
     702           0 :         return GetColorAttachPoint(attachPoint);
     703             :     }
     704             : }
     705             : 
     706             : #define FOR_EACH_ATTACHMENT(X)            \
     707             :     X(mDepthAttachment);                  \
     708             :     X(mStencilAttachment);                \
     709             :     X(mDepthStencilAttachment);           \
     710             :                                           \
     711             :     for (auto& cur : mColorAttachments) { \
     712             :         X(cur);                           \
     713             :     }
     714             : 
     715             : void
     716           0 : WebGLFramebuffer::DetachTexture(const char* funcName, const WebGLTexture* tex)
     717             : {
     718           0 :     const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
     719           0 :         if (attach.Texture() == tex) {
     720           0 :             attach.Clear(funcName);
     721             :         }
     722           0 :     };
     723             : 
     724           0 :     FOR_EACH_ATTACHMENT(fnDetach)
     725           0 : }
     726             : 
     727             : void
     728           0 : WebGLFramebuffer::DetachRenderbuffer(const char* funcName, const WebGLRenderbuffer* rb)
     729             : {
     730           0 :     const auto fnDetach = [&](WebGLFBAttachPoint& attach) {
     731           0 :         if (attach.Renderbuffer() == rb) {
     732           0 :             attach.Clear(funcName);
     733             :         }
     734           0 :     };
     735             : 
     736           0 :     FOR_EACH_ATTACHMENT(fnDetach)
     737           0 : }
     738             : 
     739             : ////////////////////////////////////////////////////////////////////////////////
     740             : // Completeness
     741             : 
     742             : bool
     743           0 : WebGLFramebuffer::HasDefinedAttachments() const
     744             : {
     745           0 :     bool hasAttachments = false;
     746           0 :     const auto func = [&](const WebGLFBAttachPoint& attach) {
     747           0 :         hasAttachments |= attach.IsDefined();
     748           0 :     };
     749             : 
     750           0 :     FOR_EACH_ATTACHMENT(func)
     751           0 :     return hasAttachments;
     752             : }
     753             : 
     754             : bool
     755           0 : WebGLFramebuffer::HasIncompleteAttachments(nsCString* const out_info) const
     756             : {
     757           0 :     bool hasIncomplete = false;
     758           0 :     const auto func = [&](const WebGLFBAttachPoint& cur) {
     759           0 :         if (!cur.IsDefined())
     760           0 :             return; // Not defined, so can't count as incomplete.
     761             : 
     762           0 :         hasIncomplete |= !cur.IsComplete(mContext, out_info);
     763           0 :     };
     764             : 
     765           0 :     FOR_EACH_ATTACHMENT(func)
     766           0 :     return hasIncomplete;
     767             : }
     768             : 
     769             : bool
     770           0 : WebGLFramebuffer::AllImageRectsMatch() const
     771             : {
     772           0 :     MOZ_ASSERT(HasDefinedAttachments());
     773           0 :     DebugOnly<nsCString> fbStatusInfo;
     774           0 :     MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
     775             : 
     776           0 :     bool needsInit = true;
     777           0 :     uint32_t width = 0;
     778           0 :     uint32_t height = 0;
     779             : 
     780           0 :     bool hasMismatch = false;
     781           0 :     const auto func = [&](const WebGLFBAttachPoint& attach) {
     782           0 :         if (!attach.HasImage())
     783           0 :             return;
     784             : 
     785             :         uint32_t curWidth;
     786             :         uint32_t curHeight;
     787           0 :         attach.Size(&curWidth, &curHeight);
     788             : 
     789           0 :         if (needsInit) {
     790           0 :             needsInit = false;
     791           0 :             width = curWidth;
     792           0 :             height = curHeight;
     793           0 :             return;
     794             :         }
     795             : 
     796           0 :         hasMismatch |= (curWidth != width ||
     797           0 :                         curHeight != height);
     798           0 :     };
     799             : 
     800           0 :     FOR_EACH_ATTACHMENT(func)
     801           0 :     return !hasMismatch;
     802             : }
     803             : 
     804             : bool
     805           0 : WebGLFramebuffer::AllImageSamplesMatch() const
     806             : {
     807           0 :     MOZ_ASSERT(HasDefinedAttachments());
     808           0 :     DebugOnly<nsCString> fbStatusInfo;
     809           0 :     MOZ_ASSERT(!HasIncompleteAttachments(&fbStatusInfo));
     810             : 
     811           0 :     bool needsInit = true;
     812           0 :     uint32_t samples = 0;
     813             : 
     814           0 :     bool hasMismatch = false;
     815           0 :     const auto func = [&](const WebGLFBAttachPoint& attach) {
     816           0 :         if (!attach.HasImage())
     817           0 :           return;
     818             : 
     819           0 :         const uint32_t curSamples = attach.Samples();
     820             : 
     821           0 :         if (needsInit) {
     822           0 :             needsInit = false;
     823           0 :             samples = curSamples;
     824           0 :             return;
     825             :         }
     826             : 
     827           0 :         hasMismatch |= (curSamples != samples);
     828           0 :     };
     829             : 
     830           0 :     FOR_EACH_ATTACHMENT(func)
     831           0 :     return !hasMismatch;
     832             : }
     833             : 
     834             : #undef FOR_EACH_ATTACHMENT
     835             : 
     836             : FBStatus
     837           0 : WebGLFramebuffer::PrecheckFramebufferStatus(nsCString* const out_info) const
     838             : {
     839           0 :     MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
     840             :                mContext->mBoundReadFramebuffer == this);
     841             : 
     842           0 :     if (!HasDefinedAttachments())
     843           0 :         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; // No attachments
     844             : 
     845           0 :     if (HasIncompleteAttachments(out_info))
     846           0 :         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
     847             : 
     848           0 :     if (!AllImageRectsMatch())
     849           0 :         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; // Inconsistent sizes
     850             : 
     851           0 :     if (!AllImageSamplesMatch())
     852           0 :         return LOCAL_GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE; // Inconsistent samples
     853             : 
     854           0 :     if (mContext->IsWebGL2()) {
     855           0 :         MOZ_ASSERT(!mDepthStencilAttachment.IsDefined());
     856             :     } else {
     857           0 :         const auto depthOrStencilCount = int(mDepthAttachment.IsDefined()) +
     858           0 :                                          int(mStencilAttachment.IsDefined()) +
     859           0 :                                          int(mDepthStencilAttachment.IsDefined());
     860           0 :         if (depthOrStencilCount > 1)
     861           0 :             return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
     862             :     }
     863             : 
     864           0 :     return LOCAL_GL_FRAMEBUFFER_COMPLETE;
     865             : }
     866             : 
     867             : ////////////////////////////////////////
     868             : // Validation
     869             : 
     870             : bool
     871           0 : WebGLFramebuffer::ValidateAndInitAttachments(const char* funcName)
     872             : {
     873           0 :     MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
     874             :                mContext->mBoundReadFramebuffer == this);
     875             : 
     876           0 :     const auto fbStatus = CheckFramebufferStatus(funcName);
     877           0 :     if (fbStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
     878           0 :         return true;
     879             : 
     880           0 :     mContext->ErrorInvalidFramebufferOperation("%s: Framebuffer must be"
     881             :                                                " complete.",
     882           0 :                                                funcName);
     883           0 :     return false;
     884             : }
     885             : 
     886             : bool
     887           0 : WebGLFramebuffer::ValidateClearBufferType(const char* funcName, GLenum buffer,
     888             :                                           uint32_t drawBuffer, GLenum funcType) const
     889             : {
     890           0 :     if (buffer != LOCAL_GL_COLOR)
     891           0 :         return true;
     892             : 
     893           0 :     const auto& attach = mColorAttachments[drawBuffer];
     894           0 :     if (!attach.IsDefined())
     895           0 :         return true;
     896             : 
     897           0 :     if (!count(mColorDrawBuffers.begin(), mColorDrawBuffers.end(), &attach))
     898           0 :         return true; // DRAW_BUFFERi set to NONE.
     899             : 
     900             :     GLenum attachType;
     901           0 :     switch (attach.Format()->format->componentType) {
     902             :     case webgl::ComponentType::Int:
     903           0 :         attachType = LOCAL_GL_INT;
     904           0 :         break;
     905             :     case webgl::ComponentType::UInt:
     906           0 :         attachType = LOCAL_GL_UNSIGNED_INT;
     907           0 :         break;
     908             :     default:
     909           0 :         attachType = LOCAL_GL_FLOAT;
     910           0 :         break;
     911             :     }
     912             : 
     913           0 :     if (attachType != funcType) {
     914           0 :         mContext->ErrorInvalidOperation("%s: This attachment is of type 0x%04x, but"
     915             :                                         " this function is of type 0x%04x.",
     916           0 :                                         funcName, attachType, funcType);
     917           0 :         return false;
     918             :     }
     919             : 
     920           0 :     return true;
     921             : }
     922             : 
     923             : bool
     924           0 : WebGLFramebuffer::ValidateForRead(const char* funcName,
     925             :                                   const webgl::FormatUsageInfo** const out_format,
     926             :                                   uint32_t* const out_width, uint32_t* const out_height)
     927             : {
     928           0 :     if (!ValidateAndInitAttachments(funcName))
     929           0 :         return false;
     930             : 
     931           0 :     if (!mColorReadBuffer) {
     932           0 :         mContext->ErrorInvalidOperation("%s: READ_BUFFER must not be NONE.", funcName);
     933           0 :         return false;
     934             :     }
     935             : 
     936           0 :     if (!mColorReadBuffer->IsDefined()) {
     937           0 :         mContext->ErrorInvalidOperation("%s: The READ_BUFFER attachment is not defined.",
     938           0 :                                         funcName);
     939           0 :         return false;
     940             :     }
     941             : 
     942           0 :     if (mColorReadBuffer->Samples()) {
     943           0 :         mContext->ErrorInvalidOperation("%s: The READ_BUFFER attachment is multisampled.",
     944           0 :                                         funcName);
     945           0 :         return false;
     946             :     }
     947             : 
     948           0 :     *out_format = mColorReadBuffer->Format();
     949           0 :     mColorReadBuffer->Size(out_width, out_height);
     950           0 :     return true;
     951             : }
     952             : 
     953             : ////////////////////////////////////////////////////////////////////////////////
     954             : // Resolution and caching
     955             : 
     956             : void
     957           0 : WebGLFramebuffer::ResolveAttachments() const
     958             : {
     959           0 :     const auto& gl = mContext->gl;
     960             : 
     961             :     ////
     962             :     // Nuke attachment points.
     963             : 
     964           0 :     for (uint32_t i = 0; i < mContext->mImplMaxColorAttachments; i++) {
     965           0 :         const GLenum attachEnum = LOCAL_GL_COLOR_ATTACHMENT0 + i;
     966           0 :         gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, attachEnum,
     967           0 :                                      LOCAL_GL_RENDERBUFFER, 0);
     968             :     }
     969             : 
     970           0 :     gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
     971           0 :                                  LOCAL_GL_RENDERBUFFER, 0);
     972           0 :     gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
     973           0 :                                  LOCAL_GL_RENDERBUFFER, 0);
     974             : 
     975             :     ////
     976             : 
     977           0 :     for (const auto& attach : mColorAttachments) {
     978           0 :         attach.Resolve(gl);
     979             :     }
     980             : 
     981           0 :     mDepthAttachment.Resolve(gl);
     982           0 :     mStencilAttachment.Resolve(gl);
     983           0 :     mDepthStencilAttachment.Resolve(gl);
     984           0 : }
     985             : 
     986             : bool
     987           0 : WebGLFramebuffer::ResolveAttachmentData(const char* funcName) const
     988             : {
     989             :     //////
     990             :     // Check if we need to initialize anything
     991             : 
     992           0 :     const auto fnIs3D = [&](const WebGLFBAttachPoint& attach) {
     993           0 :         const auto& tex = attach.Texture();
     994           0 :         if (!tex)
     995           0 :             return false;
     996             : 
     997           0 :         const auto& info = tex->ImageInfoAt(attach.ImageTarget(), attach.MipLevel());
     998           0 :         if (info.mDepth == 1)
     999           0 :             return false;
    1000             : 
    1001           0 :         return true;
    1002             :     };
    1003             : 
    1004           0 :     uint32_t clearBits = 0;
    1005           0 :     std::vector<const WebGLFBAttachPoint*> attachmentsToClear;
    1006           0 :     std::vector<const WebGLFBAttachPoint*> colorAttachmentsToClear;
    1007           0 :     std::vector<const WebGLFBAttachPoint*> tex3DAttachmentsToInit;
    1008             : 
    1009           0 :     const auto fnGather = [&](const WebGLFBAttachPoint& attach, GLenum attachClearBits) {
    1010           0 :         if (!attach.HasUninitializedImageData())
    1011           0 :             return false;
    1012             : 
    1013           0 :         if (fnIs3D(attach)) {
    1014           0 :             tex3DAttachmentsToInit.push_back(&attach);
    1015           0 :             return false;
    1016             :         }
    1017             : 
    1018           0 :         clearBits |= attachClearBits;
    1019           0 :         attachmentsToClear.push_back(&attach);
    1020           0 :         return true;
    1021           0 :     };
    1022             : 
    1023             :     //////
    1024             : 
    1025           0 :     for (auto& cur : mColorDrawBuffers) {
    1026           0 :         if (fnGather(*cur, LOCAL_GL_COLOR_BUFFER_BIT)) {
    1027           0 :             colorAttachmentsToClear.push_back(cur);
    1028             :         }
    1029             :     }
    1030             : 
    1031           0 :     fnGather(mDepthAttachment, LOCAL_GL_DEPTH_BUFFER_BIT);
    1032           0 :     fnGather(mStencilAttachment, LOCAL_GL_STENCIL_BUFFER_BIT);
    1033           0 :     fnGather(mDepthStencilAttachment, LOCAL_GL_DEPTH_BUFFER_BIT |
    1034           0 :                                       LOCAL_GL_STENCIL_BUFFER_BIT);
    1035             : 
    1036             :     //////
    1037             : 
    1038           0 :     for (const auto& attach : tex3DAttachmentsToInit) {
    1039           0 :         const auto& tex = attach->Texture();
    1040           0 :         if (!tex->InitializeImageData(funcName, attach->ImageTarget(),
    1041             :                                       attach->MipLevel()))
    1042             :         {
    1043           0 :             return false;
    1044             :         }
    1045             :     }
    1046             : 
    1047           0 :     if (clearBits) {
    1048           0 :         const auto fnDrawBuffers = [&](const std::vector<const WebGLFBAttachPoint*>& src)
    1049             :         {
    1050           0 :             std::vector<GLenum> enumList;
    1051             : 
    1052           0 :             for (const auto& cur : src) {
    1053           0 :                 const auto& attachEnum = cur->mAttachmentPoint;
    1054           0 :                 const GLenum attachId = attachEnum - LOCAL_GL_COLOR_ATTACHMENT0;
    1055             : 
    1056           0 :                 while (enumList.size() < attachId) {
    1057           0 :                     enumList.push_back(LOCAL_GL_NONE);
    1058             :                 }
    1059           0 :                 enumList.push_back(attachEnum);
    1060             :             }
    1061             : 
    1062           0 :             mContext->gl->fDrawBuffers(enumList.size(), enumList.data());
    1063           0 :         };
    1064             : 
    1065             :         ////
    1066             :         // Clear
    1067             : 
    1068           0 :         mContext->MakeContextCurrent();
    1069             : 
    1070           0 :         const bool hasDrawBuffers = mContext->HasDrawBuffers();
    1071           0 :         if (hasDrawBuffers) {
    1072           0 :             fnDrawBuffers(colorAttachmentsToClear);
    1073             :         }
    1074             : 
    1075             :         {
    1076           0 :             gl::ScopedBindFramebuffer autoBind(mContext->gl, mGLName);
    1077             : 
    1078           0 :             mContext->ForceClearFramebufferWithDefaultValues(clearBits, false);
    1079             :         }
    1080             : 
    1081           0 :         if (hasDrawBuffers) {
    1082           0 :             RefreshDrawBuffers();
    1083             :         }
    1084             : 
    1085             :         // Mark initialized.
    1086           0 :         for (const auto& cur : attachmentsToClear) {
    1087           0 :             cur->SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
    1088             :         }
    1089             :     }
    1090             : 
    1091           0 :     return true;
    1092             : }
    1093             : 
    1094           0 : WebGLFramebuffer::ResolvedData::ResolvedData(const WebGLFramebuffer& parent)
    1095             : {
    1096             : 
    1097           0 :     texDrawBuffers.reserve(parent.mColorDrawBuffers.size() + 2); // +2 for depth+stencil.
    1098             : 
    1099           0 :     const auto fnCommon = [&](const WebGLFBAttachPoint& attach) {
    1100           0 :         if (!attach.IsDefined())
    1101           0 :             return false;
    1102             : 
    1103           0 :         if (attach.Texture()) {
    1104           0 :             texDrawBuffers.push_back(&attach);
    1105             :         }
    1106           0 :         return true;
    1107           0 :     };
    1108             : 
    1109             :     ////
    1110             : 
    1111           0 :     const auto fnDepthStencil = [&](const WebGLFBAttachPoint& attach) {
    1112           0 :         if (!fnCommon(attach))
    1113           0 :             return;
    1114             : 
    1115           0 :         drawSet.insert(WebGLFBAttachPoint::Ordered(attach));
    1116           0 :         readSet.insert(WebGLFBAttachPoint::Ordered(attach));
    1117           0 :     };
    1118             : 
    1119           0 :     fnDepthStencil(parent.mDepthAttachment);
    1120           0 :     fnDepthStencil(parent.mStencilAttachment);
    1121           0 :     fnDepthStencil(parent.mDepthStencilAttachment);
    1122             : 
    1123             :     ////
    1124             : 
    1125           0 :     for (const auto& pAttach : parent.mColorDrawBuffers) {
    1126           0 :         const auto& attach = *pAttach;
    1127           0 :         if (!fnCommon(attach))
    1128           0 :             return;
    1129             : 
    1130           0 :         drawSet.insert(WebGLFBAttachPoint::Ordered(attach));
    1131             :     }
    1132             : 
    1133           0 :     if (parent.mColorReadBuffer) {
    1134           0 :         const auto& attach = *parent.mColorReadBuffer;
    1135           0 :         if (!fnCommon(attach))
    1136           0 :             return;
    1137             : 
    1138           0 :         readSet.insert(WebGLFBAttachPoint::Ordered(attach));
    1139             :     }
    1140             : }
    1141             : 
    1142             : void
    1143           0 : WebGLFramebuffer::InvalidateFramebufferStatus(const char* funcName)
    1144             : {
    1145           0 :     if (mResolvedCompleteData) {
    1146           0 :         mNumFBStatusInvals++;
    1147           0 :         if (mNumFBStatusInvals > mContext->mMaxAcceptableFBStatusInvals) {
    1148           0 :             mContext->GeneratePerfWarning("%s: FB was invalidated after being complete %u"
    1149             :                                           " times.",
    1150           0 :                                           funcName, uint32_t(mNumFBStatusInvals));
    1151             :         }
    1152             :     }
    1153             : 
    1154           0 :     mResolvedCompleteData = nullptr;
    1155           0 : }
    1156             : 
    1157             : void
    1158           0 : WebGLFramebuffer::RefreshResolvedData()
    1159             : {
    1160           0 :     if (mResolvedCompleteData) {
    1161           0 :         mResolvedCompleteData.reset(new ResolvedData(*this));
    1162             :     }
    1163           0 : }
    1164             : 
    1165             : ////////////////////////////////////////////////////////////////////////////////
    1166             : // Entrypoints
    1167             : 
    1168             : FBStatus
    1169           0 : WebGLFramebuffer::CheckFramebufferStatus(const char* funcName)
    1170             : {
    1171           0 :     if (IsResolvedComplete())
    1172           0 :         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
    1173             : 
    1174             :     // Ok, let's try to resolve it!
    1175             : 
    1176           0 :     nsCString statusInfo;
    1177           0 :     FBStatus ret = PrecheckFramebufferStatus(&statusInfo);
    1178             :     do {
    1179           0 :         if (ret != LOCAL_GL_FRAMEBUFFER_COMPLETE)
    1180           0 :             break;
    1181             : 
    1182             :         // Looks good on our end. Let's ask the driver.
    1183           0 :         gl::GLContext* const gl = mContext->gl;
    1184           0 :         gl->MakeCurrent();
    1185             : 
    1186           0 :         const ScopedFBRebinder autoFB(mContext);
    1187           0 :         gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, mGLName);
    1188             : 
    1189             :         ////
    1190             : 
    1191           0 :         ResolveAttachments(); // OK, attach everything properly!
    1192           0 :         RefreshDrawBuffers();
    1193           0 :         RefreshReadBuffer();
    1194             : 
    1195           0 :         ret = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
    1196             : 
    1197             :         ////
    1198             : 
    1199           0 :         if (ret != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
    1200             :             const nsPrintfCString text("Bad status according to the driver: 0x%04x",
    1201           0 :                                        ret.get());
    1202           0 :             statusInfo = text;
    1203           0 :             break;
    1204             :         }
    1205             : 
    1206           0 :         if (!ResolveAttachmentData(funcName)) {
    1207           0 :             ret = LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
    1208           0 :             statusInfo.AssignLiteral("Failed to lazily-initialize attachment data.");
    1209           0 :             break;
    1210             :         }
    1211             : 
    1212           0 :         mResolvedCompleteData.reset(new ResolvedData(*this));
    1213           0 :         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
    1214             :     } while (false);
    1215             : 
    1216           0 :     MOZ_ASSERT(ret != LOCAL_GL_FRAMEBUFFER_COMPLETE);
    1217           0 :     mContext->GenerateWarning("%s: Framebuffer not complete. (status: 0x%04x) %s",
    1218           0 :                               funcName, ret.get(), statusInfo.BeginReading());
    1219           0 :     return ret;
    1220             : }
    1221             : 
    1222             : ////
    1223             : 
    1224             : void
    1225           0 : WebGLFramebuffer::RefreshDrawBuffers() const
    1226             : {
    1227           0 :     const auto& gl = mContext->gl;
    1228           0 :     if (!gl->IsSupported(gl::GLFeature::draw_buffers))
    1229           0 :         return;
    1230             : 
    1231             :     // Prior to GL4.1, having a no-image FB attachment that's selected by DrawBuffers
    1232             :     // yields a framebuffer status of FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER.
    1233             :     // We could workaround this only on affected versions, but it's easier be
    1234             :     // unconditional.
    1235           0 :     std::vector<GLenum> driverBuffers(mContext->mImplMaxDrawBuffers, LOCAL_GL_NONE);
    1236           0 :     for (const auto& attach : mColorDrawBuffers) {
    1237           0 :         if (attach->HasImage()) {
    1238           0 :             const uint32_t index = attach->mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0;
    1239           0 :             driverBuffers[index] = attach->mAttachmentPoint;
    1240             :         }
    1241             :     }
    1242             : 
    1243           0 :     gl->fDrawBuffers(driverBuffers.size(), driverBuffers.data());
    1244             : }
    1245             : 
    1246             : void
    1247           0 : WebGLFramebuffer::RefreshReadBuffer() const
    1248             : {
    1249           0 :     const auto& gl = mContext->gl;
    1250           0 :     if (!gl->IsSupported(gl::GLFeature::read_buffer))
    1251           0 :         return;
    1252             : 
    1253             :     // Prior to GL4.1, having a no-image FB attachment that's selected by ReadBuffer
    1254             :     // yields a framebuffer status of FRAMEBUFFER_INCOMPLETE_READ_BUFFER.
    1255             :     // We could workaround this only on affected versions, but it's easier be
    1256             :     // unconditional.
    1257           0 :     GLenum driverBuffer = LOCAL_GL_NONE;
    1258           0 :     if (mColorReadBuffer && mColorReadBuffer->HasImage()) {
    1259           0 :         driverBuffer = mColorReadBuffer->mAttachmentPoint;
    1260             :     }
    1261             : 
    1262           0 :     gl->fReadBuffer(driverBuffer);
    1263             : }
    1264             : 
    1265             : ////
    1266             : 
    1267             : void
    1268           0 : WebGLFramebuffer::DrawBuffers(const char* funcName, const dom::Sequence<GLenum>& buffers)
    1269             : {
    1270           0 :     if (buffers.Length() > mContext->mImplMaxDrawBuffers) {
    1271             :         // "An INVALID_VALUE error is generated if `n` is greater than MAX_DRAW_BUFFERS."
    1272           0 :         mContext->ErrorInvalidValue("%s: `buffers` must have a length <="
    1273           0 :                                     " MAX_DRAW_BUFFERS.", funcName);
    1274           0 :         return;
    1275             :     }
    1276             : 
    1277           0 :     std::vector<const WebGLFBAttachPoint*> newColorDrawBuffers;
    1278           0 :     newColorDrawBuffers.reserve(buffers.Length());
    1279             : 
    1280           0 :     for (size_t i = 0; i < buffers.Length(); i++) {
    1281             :         // "If the GL is bound to a draw framebuffer object, the `i`th buffer listed in
    1282             :         //  bufs must be COLOR_ATTACHMENTi or NONE. Specifying a buffer out of order,
    1283             :         //  BACK, or COLOR_ATTACHMENTm where `m` is greater than or equal to the value of
    1284             :         // MAX_COLOR_ATTACHMENTS, will generate the error INVALID_OPERATION.
    1285             : 
    1286             :         // WEBGL_draw_buffers:
    1287             :         // "The value of the MAX_COLOR_ATTACHMENTS_WEBGL parameter must be greater than or
    1288             :         //  equal to that of the MAX_DRAW_BUFFERS_WEBGL parameter."
    1289             :         // This means that if buffers.Length() isn't larger than MaxDrawBuffers, it won't
    1290             :         // be larger than MaxColorAttachments.
    1291           0 :         const auto& cur = buffers[i];
    1292           0 :         if (cur == LOCAL_GL_COLOR_ATTACHMENT0 + i) {
    1293           0 :             const auto& attach = mColorAttachments[i];
    1294           0 :             newColorDrawBuffers.push_back(&attach);
    1295           0 :         } else if (cur != LOCAL_GL_NONE) {
    1296           0 :             const bool isColorEnum = (cur >= LOCAL_GL_COLOR_ATTACHMENT0 &&
    1297           0 :                                       cur < mContext->LastColorAttachmentEnum());
    1298           0 :             if (cur != LOCAL_GL_BACK &&
    1299           0 :                 !isColorEnum)
    1300             :             {
    1301           0 :                 mContext->ErrorInvalidEnum("%s: Unexpected enum in buffers.", funcName);
    1302           0 :                 return;
    1303             :             }
    1304             : 
    1305           0 :             mContext->ErrorInvalidOperation("%s: `buffers[i]` must be NONE or"
    1306             :                                             " COLOR_ATTACHMENTi.",
    1307           0 :                                             funcName);
    1308           0 :             return;
    1309             :         }
    1310             :     }
    1311             : 
    1312             :     ////
    1313             : 
    1314           0 :     mContext->MakeContextCurrent();
    1315             : 
    1316           0 :     mColorDrawBuffers.swap(newColorDrawBuffers);
    1317           0 :     RefreshDrawBuffers(); // Calls glDrawBuffers.
    1318           0 :     RefreshResolvedData();
    1319             : }
    1320             : 
    1321             : void
    1322           0 : WebGLFramebuffer::ReadBuffer(const char* funcName, GLenum attachPoint)
    1323             : {
    1324           0 :     const auto& maybeAttach = GetColorAttachPoint(attachPoint);
    1325           0 :     if (!maybeAttach) {
    1326             :         const char text[] = "%s: `mode` must be a COLOR_ATTACHMENTi, for 0 <= i <"
    1327           0 :                             " MAX_DRAW_BUFFERS.";
    1328           0 :         if (attachPoint == LOCAL_GL_BACK) {
    1329           0 :             mContext->ErrorInvalidOperation(text, funcName);
    1330             :         } else {
    1331           0 :             mContext->ErrorInvalidEnum(text, funcName);
    1332             :         }
    1333           0 :         return;
    1334             :     }
    1335           0 :     const auto& attach = maybeAttach.value(); // Might be nullptr.
    1336             : 
    1337             :     ////
    1338             : 
    1339           0 :     mContext->MakeContextCurrent();
    1340             : 
    1341           0 :     mColorReadBuffer = attach;
    1342           0 :     RefreshReadBuffer(); // Calls glReadBuffer.
    1343           0 :     RefreshResolvedData();
    1344             : }
    1345             : 
    1346             : ////
    1347             : 
    1348             : void
    1349           0 : WebGLFramebuffer::FramebufferRenderbuffer(const char* funcName, GLenum attachEnum,
    1350             :                                           GLenum rbtarget, WebGLRenderbuffer* rb)
    1351             : {
    1352           0 :     MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
    1353             :                mContext->mBoundReadFramebuffer == this);
    1354             : 
    1355             :     // `attachment`
    1356           0 :     const auto maybeAttach = GetAttachPoint(attachEnum);
    1357           0 :     if (!maybeAttach || !maybeAttach.value()) {
    1358           0 :         mContext->ErrorInvalidEnum("%s: Bad `attachment`: 0x%x.", funcName, attachEnum);
    1359           0 :         return;
    1360             :     }
    1361           0 :     const auto& attach = maybeAttach.value();
    1362             : 
    1363             :     // `rbTarget`
    1364           0 :     if (rbtarget != LOCAL_GL_RENDERBUFFER) {
    1365           0 :         mContext->ErrorInvalidEnumInfo("framebufferRenderbuffer: rbtarget:", rbtarget);
    1366           0 :         return;
    1367             :     }
    1368             : 
    1369             :     // `rb`
    1370           0 :     if (rb && !mContext->ValidateObject("framebufferRenderbuffer: rb", *rb))
    1371           0 :         return;
    1372             : 
    1373             :     // End of validation.
    1374             : 
    1375           0 :     if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
    1376           0 :         mDepthAttachment.SetRenderbuffer(funcName, rb);
    1377           0 :         mStencilAttachment.SetRenderbuffer(funcName, rb);
    1378             :     } else {
    1379           0 :         attach->SetRenderbuffer(funcName, rb);
    1380             :     }
    1381             : 
    1382           0 :     InvalidateFramebufferStatus(funcName);
    1383             : }
    1384             : 
    1385             : void
    1386           0 : WebGLFramebuffer::FramebufferTexture2D(const char* funcName, GLenum attachEnum,
    1387             :                                        GLenum texImageTarget, WebGLTexture* tex,
    1388             :                                        GLint level)
    1389             : {
    1390           0 :     MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
    1391             :                mContext->mBoundReadFramebuffer == this);
    1392             : 
    1393             :     // `attachment`
    1394           0 :     const auto maybeAttach = GetAttachPoint(attachEnum);
    1395           0 :     if (!maybeAttach || !maybeAttach.value()) {
    1396           0 :         mContext->ErrorInvalidEnum("%s: Bad `attachment`: 0x%x.", funcName, attachEnum);
    1397           0 :         return;
    1398             :     }
    1399           0 :     const auto& attach = maybeAttach.value();
    1400             : 
    1401             :     // `texImageTarget`
    1402           0 :     if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
    1403           0 :         (texImageTarget < LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X ||
    1404             :          texImageTarget > LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z))
    1405             :     {
    1406           0 :         mContext->ErrorInvalidEnumInfo("framebufferTexture2D: texImageTarget:",
    1407           0 :                                        texImageTarget);
    1408           0 :         return;
    1409             :     }
    1410             : 
    1411             :     // `texture`
    1412           0 :     if (tex) {
    1413           0 :         if (!mContext->ValidateObject("framebufferTexture2D: texture", *tex))
    1414           0 :             return;
    1415             : 
    1416           0 :         if (!tex->HasEverBeenBound()) {
    1417           0 :             mContext->ErrorInvalidOperation("%s: `texture` has never been bound.",
    1418           0 :                                             funcName);
    1419           0 :             return;
    1420             :         }
    1421             : 
    1422           0 :         const TexTarget destTexTarget = TexImageTargetToTexTarget(texImageTarget);
    1423           0 :         if (tex->Target() != destTexTarget) {
    1424           0 :             mContext->ErrorInvalidOperation("%s: Mismatched texture and texture target.",
    1425           0 :                                             funcName);
    1426           0 :             return;
    1427             :         }
    1428             :     }
    1429             : 
    1430             :     // `level`
    1431           0 :     if (level < 0)
    1432           0 :         return mContext->ErrorInvalidValue("%s: `level` must not be negative.", funcName);
    1433             : 
    1434           0 :     if (mContext->IsWebGL2()) {
    1435             :         /* GLES 3.0.4 p208:
    1436             :          *   If textarget is one of TEXTURE_CUBE_MAP_POSITIVE_X,
    1437             :          *   TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z,
    1438             :          *   TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y,
    1439             :          *   or TEXTURE_CUBE_MAP_NEGATIVE_Z, then level must be greater
    1440             :          *   than or equal to zero and less than or equal to log2 of the
    1441             :          *   value of MAX_CUBE_MAP_TEXTURE_SIZE. If textarget is TEXTURE_2D,
    1442             :          *   level must be greater than or equal to zero and no larger than
    1443             :          *   log2 of the value of MAX_TEXTURE_SIZE. Otherwise, an
    1444             :          *   INVALID_VALUE error is generated.
    1445             :          */
    1446             : 
    1447           0 :         if (texImageTarget == LOCAL_GL_TEXTURE_2D) {
    1448           0 :             if (uint32_t(level) > FloorLog2(mContext->mImplMaxTextureSize))
    1449           0 :                 return mContext->ErrorInvalidValue("%s: `level` is too large.", funcName);
    1450             :         } else {
    1451           0 :             MOZ_ASSERT(texImageTarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
    1452             :                        texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
    1453             : 
    1454           0 :             if (uint32_t(level) > FloorLog2(mContext->mImplMaxCubeMapTextureSize))
    1455           0 :                 return mContext->ErrorInvalidValue("%s: `level` is too large.", funcName);
    1456             :         }
    1457           0 :     } else if (level != 0) {
    1458           0 :         return mContext->ErrorInvalidValue("%s: `level` must be 0.", funcName);
    1459             :     }
    1460             : 
    1461             :     // End of validation.
    1462             : 
    1463           0 :     if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
    1464           0 :         mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level);
    1465           0 :         mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level);
    1466             :     } else {
    1467           0 :         attach->SetTexImage(funcName, tex, texImageTarget, level);
    1468             :     }
    1469             : 
    1470           0 :     InvalidateFramebufferStatus(funcName);
    1471             : }
    1472             : 
    1473             : void
    1474           0 : WebGLFramebuffer::FramebufferTextureLayer(const char* funcName, GLenum attachEnum,
    1475             :                                           WebGLTexture* tex, GLint level, GLint layer)
    1476             : {
    1477           0 :     MOZ_ASSERT(mContext->mBoundDrawFramebuffer == this ||
    1478             :                mContext->mBoundReadFramebuffer == this);
    1479             : 
    1480             :     // `attachment`
    1481           0 :     const auto maybeAttach = GetAttachPoint(attachEnum);
    1482           0 :     if (!maybeAttach || !maybeAttach.value()) {
    1483           0 :         mContext->ErrorInvalidEnum("%s: Bad `attachment`: 0x%x.", funcName, attachEnum);
    1484           0 :         return;
    1485             :     }
    1486           0 :     const auto& attach = maybeAttach.value();
    1487             : 
    1488             :     // `level`, `layer`
    1489           0 :     if (layer < 0)
    1490           0 :         return mContext->ErrorInvalidValue("%s: `layer` must be >= 0.", funcName);
    1491             : 
    1492           0 :     if (level < 0)
    1493           0 :         return mContext->ErrorInvalidValue("%s: `level` must be >= 0.", funcName);
    1494             : 
    1495             :     // `texture`
    1496           0 :     GLenum texImageTarget = LOCAL_GL_TEXTURE_3D;
    1497           0 :     if (tex) {
    1498           0 :         if (!mContext->ValidateObject("framebufferTextureLayer: texture", *tex))
    1499           0 :             return;
    1500             : 
    1501           0 :         if (!tex->HasEverBeenBound()) {
    1502           0 :             mContext->ErrorInvalidOperation("%s: `texture` has never been bound.",
    1503           0 :                                             funcName);
    1504           0 :             return;
    1505             :         }
    1506             : 
    1507           0 :         texImageTarget = tex->Target().get();
    1508           0 :         switch (texImageTarget) {
    1509             :         case LOCAL_GL_TEXTURE_3D:
    1510           0 :             if (uint32_t(layer) >= mContext->mImplMax3DTextureSize) {
    1511           0 :                 mContext->ErrorInvalidValue("%s: `layer` must be < %s.", funcName,
    1512           0 :                                             "MAX_3D_TEXTURE_SIZE");
    1513           0 :                 return;
    1514             :             }
    1515             : 
    1516           0 :             if (uint32_t(level) > FloorLog2(mContext->mImplMax3DTextureSize)) {
    1517           0 :                 mContext->ErrorInvalidValue("%s: `level` must be <= log2(%s).", funcName,
    1518           0 :                                             "MAX_3D_TEXTURE_SIZE");
    1519           0 :                 return;
    1520             :             }
    1521           0 :             break;
    1522             : 
    1523             :         case LOCAL_GL_TEXTURE_2D_ARRAY:
    1524           0 :             if (uint32_t(layer) >= mContext->mImplMaxArrayTextureLayers) {
    1525           0 :                 mContext->ErrorInvalidValue("%s: `layer` must be < %s.", funcName,
    1526           0 :                                             "MAX_ARRAY_TEXTURE_LAYERS");
    1527           0 :                 return;
    1528             :             }
    1529             : 
    1530           0 :             if (uint32_t(level) > FloorLog2(mContext->mImplMaxTextureSize)) {
    1531           0 :                 mContext->ErrorInvalidValue("%s: `level` must be <= log2(%s).", funcName,
    1532           0 :                                             "MAX_TEXTURE_SIZE");
    1533           0 :                 return;
    1534             :             }
    1535           0 :             break;
    1536             : 
    1537             :         default:
    1538           0 :             mContext->ErrorInvalidOperation("%s: `texture` must be a TEXTURE_3D or"
    1539             :                                             " TEXTURE_2D_ARRAY.",
    1540           0 :                                             funcName);
    1541           0 :             return;
    1542             :         }
    1543             :     }
    1544             : 
    1545             :     // End of validation.
    1546             : 
    1547           0 :     if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
    1548           0 :         mDepthAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
    1549           0 :         mStencilAttachment.SetTexImage(funcName, tex, texImageTarget, level, layer);
    1550             :     } else {
    1551           0 :         attach->SetTexImage(funcName, tex, texImageTarget, level, layer);
    1552             :     }
    1553             : 
    1554           0 :     InvalidateFramebufferStatus(funcName);
    1555             : }
    1556             : 
    1557             : JS::Value
    1558           0 : WebGLFramebuffer::GetAttachmentParameter(const char* funcName, JSContext* cx,
    1559             :                                          GLenum target, GLenum attachEnum, GLenum pname,
    1560             :                                          ErrorResult* const out_error)
    1561             : {
    1562           0 :     const auto maybeAttach = GetAttachPoint(attachEnum);
    1563           0 :     if (!maybeAttach || attachEnum == LOCAL_GL_NONE) {
    1564           0 :         mContext->ErrorInvalidEnum("%s: Can only query COLOR_ATTACHMENTi,"
    1565             :                                    " DEPTH_ATTACHMENT, DEPTH_STENCIL_ATTACHMENT, or"
    1566             :                                    " STENCIL_ATTACHMENT for a framebuffer.",
    1567           0 :                                    funcName);
    1568           0 :         return JS::NullValue();
    1569             :     }
    1570           0 :     auto attach = maybeAttach.value();
    1571             : 
    1572           0 :     if (mContext->IsWebGL2() && attachEnum == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
    1573             :         // There are a couple special rules for this one.
    1574             : 
    1575           0 :         if (pname == LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE) {
    1576           0 :             mContext->ErrorInvalidOperation("%s: Querying"
    1577             :                                             " FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE"
    1578             :                                             " against DEPTH_STENCIL_ATTACHMENT is an"
    1579             :                                             " error.",
    1580           0 :                                             funcName);
    1581           0 :             return JS::NullValue();
    1582             :         }
    1583             : 
    1584           0 :         if (mDepthAttachment.Renderbuffer() != mStencilAttachment.Renderbuffer() ||
    1585           0 :             mDepthAttachment.Texture() != mStencilAttachment.Texture())
    1586             :         {
    1587           0 :             mContext->ErrorInvalidOperation("%s: DEPTH_ATTACHMENT and STENCIL_ATTACHMENT"
    1588             :                                             " have different objects bound.",
    1589           0 :                                             funcName);
    1590           0 :             return JS::NullValue();
    1591             :         }
    1592             : 
    1593           0 :         attach = &mDepthAttachment;
    1594             :     }
    1595             : 
    1596           0 :     return attach->GetParameter(funcName, mContext, cx, target, attachEnum, pname,
    1597           0 :                                 out_error);
    1598             : }
    1599             : 
    1600             : ////////////////////
    1601             : 
    1602             : static void
    1603           0 : GetBackbufferFormats(const WebGLContext* webgl,
    1604             :                      const webgl::FormatInfo** const out_color,
    1605             :                      const webgl::FormatInfo** const out_depth,
    1606             :                      const webgl::FormatInfo** const out_stencil)
    1607             : {
    1608           0 :     const auto& options = webgl->Options();
    1609             : 
    1610           0 :     const auto effFormat = (options.alpha ? webgl::EffectiveFormat::RGBA8
    1611           0 :                                           : webgl::EffectiveFormat::RGB8);
    1612           0 :     *out_color = webgl::GetFormat(effFormat);
    1613             : 
    1614           0 :     *out_depth = nullptr;
    1615           0 :     *out_stencil = nullptr;
    1616           0 :     if (options.depth && options.stencil) {
    1617           0 :         *out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH24_STENCIL8);
    1618           0 :         *out_stencil = *out_depth;
    1619             :     } else {
    1620           0 :         if (options.depth) {
    1621           0 :             *out_depth = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT16);
    1622             :         }
    1623           0 :         if (options.stencil) {
    1624           0 :             *out_stencil = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8);
    1625             :         }
    1626             :     }
    1627           0 : }
    1628             : 
    1629             : /*static*/ void
    1630           0 : WebGLFramebuffer::BlitFramebuffer(WebGLContext* webgl,
    1631             :                                   const WebGLFramebuffer* srcFB, GLint srcX0, GLint srcY0,
    1632             :                                   GLint srcX1, GLint srcY1,
    1633             :                                   const WebGLFramebuffer* dstFB, GLint dstX0, GLint dstY0,
    1634             :                                   GLint dstX1, GLint dstY1,
    1635             :                                   GLbitfield mask, GLenum filter)
    1636             : {
    1637           0 :     const char funcName[] = "blitFramebuffer";
    1638           0 :     const auto& gl = webgl->gl;
    1639             : 
    1640             :     ////
    1641             :     // Collect data
    1642             : 
    1643             :     const auto fnGetDepthAndStencilAttach = [](const WebGLFramebuffer* fb,
    1644             :                                                const WebGLFBAttachPoint** const out_depth,
    1645           0 :                                                const WebGLFBAttachPoint** const out_stencil)
    1646             :     {
    1647           0 :         *out_depth = nullptr;
    1648           0 :         *out_stencil = nullptr;
    1649             : 
    1650           0 :         if (!fb)
    1651           0 :             return;
    1652             : 
    1653           0 :         if (fb->mDepthStencilAttachment.IsDefined()) {
    1654           0 :             *out_depth = *out_stencil = &fb->mDepthStencilAttachment;
    1655           0 :             return;
    1656             :         }
    1657           0 :         if (fb->mDepthAttachment.IsDefined()) {
    1658           0 :             *out_depth = &fb->mDepthAttachment;
    1659             :         }
    1660           0 :         if (fb->mStencilAttachment.IsDefined()) {
    1661           0 :             *out_stencil = &fb->mStencilAttachment;
    1662             :         }
    1663             :     };
    1664             : 
    1665             :     const WebGLFBAttachPoint* srcDepthAttach;
    1666             :     const WebGLFBAttachPoint* srcStencilAttach;
    1667           0 :     fnGetDepthAndStencilAttach(srcFB, &srcDepthAttach, &srcStencilAttach);
    1668             :     const WebGLFBAttachPoint* dstDepthAttach;
    1669             :     const WebGLFBAttachPoint* dstStencilAttach;
    1670           0 :     fnGetDepthAndStencilAttach(dstFB, &dstDepthAttach, &dstStencilAttach);
    1671             : 
    1672             :     ////
    1673             : 
    1674             :     const auto fnGetFormat = [](const WebGLFBAttachPoint* cur,
    1675           0 :                                 bool* const out_hasSamples) -> const webgl::FormatInfo*
    1676             :     {
    1677           0 :         if (!cur || !cur->IsDefined())
    1678           0 :             return nullptr;
    1679             : 
    1680           0 :         *out_hasSamples |= bool(cur->Samples());
    1681           0 :         return cur->Format()->format;
    1682             :     };
    1683             : 
    1684           0 :     const auto fnNarrowComponentType = [&](const webgl::FormatInfo* format) {
    1685           0 :         switch (format->componentType) {
    1686             :         case webgl::ComponentType::NormInt:
    1687             :         case webgl::ComponentType::NormUInt:
    1688           0 :             return webgl::ComponentType::Float;
    1689             : 
    1690             :         default:
    1691           0 :             return format->componentType;
    1692             :         }
    1693             :     };
    1694             : 
    1695             :     bool srcHasSamples;
    1696             :     const webgl::FormatInfo* srcColorFormat;
    1697           0 :     webgl::ComponentType srcColorType = webgl::ComponentType::None;
    1698             :     const webgl::FormatInfo* srcDepthFormat;
    1699             :     const webgl::FormatInfo* srcStencilFormat;
    1700             : 
    1701           0 :     if (srcFB) {
    1702           0 :         srcHasSamples = false;
    1703           0 :         srcColorFormat = fnGetFormat(srcFB->mColorReadBuffer, &srcHasSamples);
    1704           0 :         srcDepthFormat = fnGetFormat(srcDepthAttach, &srcHasSamples);
    1705           0 :         srcStencilFormat = fnGetFormat(srcStencilAttach, &srcHasSamples);
    1706             :     } else {
    1707           0 :         srcHasSamples = false; // Always false.
    1708             : 
    1709           0 :         GetBackbufferFormats(webgl, &srcColorFormat, &srcDepthFormat, &srcStencilFormat);
    1710             :     }
    1711             : 
    1712           0 :     if (srcColorFormat) {
    1713           0 :         srcColorType = fnNarrowComponentType(srcColorFormat);
    1714             :     }
    1715             : 
    1716             :     ////
    1717             : 
    1718             :     bool dstHasSamples;
    1719             :     const webgl::FormatInfo* dstDepthFormat;
    1720             :     const webgl::FormatInfo* dstStencilFormat;
    1721           0 :     bool dstHasColor = false;
    1722           0 :     bool colorFormatsMatch = true;
    1723           0 :     bool colorTypesMatch = true;
    1724             : 
    1725           0 :     const auto fnCheckColorFormat = [&](const webgl::FormatInfo* dstFormat) {
    1726           0 :         MOZ_ASSERT(dstFormat->r || dstFormat->g || dstFormat->b || dstFormat->a);
    1727           0 :         dstHasColor = true;
    1728           0 :         colorFormatsMatch &= (dstFormat == srcColorFormat);
    1729           0 :         colorTypesMatch &= ( fnNarrowComponentType(dstFormat) == srcColorType );
    1730           0 :     };
    1731             : 
    1732           0 :     if (dstFB) {
    1733           0 :         dstHasSamples = false;
    1734             : 
    1735           0 :         for (const auto& cur : dstFB->mColorDrawBuffers) {
    1736           0 :             const auto& format = fnGetFormat(cur, &dstHasSamples);
    1737           0 :             if (!format)
    1738           0 :                 continue;
    1739             : 
    1740           0 :             fnCheckColorFormat(format);
    1741             :         }
    1742             : 
    1743           0 :         dstDepthFormat = fnGetFormat(dstDepthAttach, &dstHasSamples);
    1744           0 :         dstStencilFormat = fnGetFormat(dstStencilAttach, &dstHasSamples);
    1745             :     } else {
    1746           0 :         dstHasSamples = bool(gl->Screen()->Samples());
    1747             : 
    1748             :         const webgl::FormatInfo* dstColorFormat;
    1749           0 :         GetBackbufferFormats(webgl, &dstColorFormat, &dstDepthFormat, &dstStencilFormat);
    1750             : 
    1751           0 :         fnCheckColorFormat(dstColorFormat);
    1752             :     }
    1753             : 
    1754             :     ////
    1755             :     // Clear unused buffer bits
    1756             : 
    1757           0 :     if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
    1758           0 :         !srcColorFormat && !dstHasColor)
    1759             :     {
    1760           0 :         mask ^= LOCAL_GL_COLOR_BUFFER_BIT;
    1761             :     }
    1762             : 
    1763           0 :     if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
    1764           0 :         !srcDepthFormat && !dstDepthFormat)
    1765             :     {
    1766           0 :         mask ^= LOCAL_GL_DEPTH_BUFFER_BIT;
    1767             :     }
    1768             : 
    1769           0 :     if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
    1770           0 :         !srcStencilFormat && !dstStencilFormat)
    1771             :     {
    1772           0 :         mask ^= LOCAL_GL_STENCIL_BUFFER_BIT;
    1773             :     }
    1774             : 
    1775             :     ////
    1776             :     // Validation
    1777             : 
    1778           0 :     if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
    1779           0 :         if (srcColorFormat && filter == LOCAL_GL_LINEAR) {
    1780           0 :             const auto& type = srcColorFormat->componentType;
    1781           0 :             if (type == webgl::ComponentType::Int ||
    1782           0 :                 type == webgl::ComponentType::UInt)
    1783             :             {
    1784             :                 webgl->ErrorInvalidOperation("%s: `filter` is LINEAR and READ_BUFFER"
    1785             :                                              " contains integer data.",
    1786           0 :                                              funcName);
    1787           0 :                 return;
    1788             :             }
    1789             :         }
    1790             : 
    1791           0 :         if (!colorTypesMatch) {
    1792             :             webgl->ErrorInvalidOperation("%s: Color component types (fixed/float/uint/"
    1793             :                                          "int) must match.",
    1794           0 :                                          funcName);
    1795           0 :             return;
    1796             :         }
    1797             :     }
    1798             : 
    1799             :     const GLbitfield depthAndStencilBits = LOCAL_GL_DEPTH_BUFFER_BIT |
    1800           0 :                                            LOCAL_GL_STENCIL_BUFFER_BIT;
    1801           0 :     if (bool(mask & depthAndStencilBits) &&
    1802             :         filter != LOCAL_GL_NEAREST)
    1803             :     {
    1804             :         webgl->ErrorInvalidOperation("%s: DEPTH_BUFFER_BIT and STENCIL_BUFFER_BIT can"
    1805             :                                      " only be used with NEAREST filtering.",
    1806           0 :                                      funcName);
    1807           0 :         return;
    1808             :     }
    1809             : 
    1810             :     /* GLES 3.0.4, p199:
    1811             :      *   Calling BlitFramebuffer will result in an INVALID_OPERATION error if
    1812             :      *   mask includes DEPTH_BUFFER_BIT or STENCIL_BUFFER_BIT, and the source
    1813             :      *   and destination depth and stencil buffer formats do not match.
    1814             :      *
    1815             :      * jgilbert: The wording is such that if only DEPTH_BUFFER_BIT is specified,
    1816             :      * the stencil formats must match. This seems wrong. It could be a spec bug,
    1817             :      * or I could be missing an interaction in one of the earlier paragraphs.
    1818             :      */
    1819           0 :     if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
    1820           0 :         dstDepthFormat && dstDepthFormat != srcDepthFormat)
    1821             :     {
    1822             :         webgl->ErrorInvalidOperation("%s: Depth buffer formats must match if selected.",
    1823           0 :                                      funcName);
    1824           0 :         return;
    1825             :     }
    1826             : 
    1827           0 :     if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
    1828           0 :         dstStencilFormat && dstStencilFormat != srcStencilFormat)
    1829             :     {
    1830             :         webgl->ErrorInvalidOperation("%s: Stencil buffer formats must match if selected.",
    1831           0 :                                      funcName);
    1832           0 :         return;
    1833             :     }
    1834             : 
    1835             :     ////
    1836             : 
    1837           0 :     if (dstHasSamples) {
    1838             :         webgl->ErrorInvalidOperation("%s: DRAW_FRAMEBUFFER may not have multiple"
    1839             :                                      " samples.",
    1840           0 :                                      funcName);
    1841           0 :         return;
    1842             :     }
    1843             : 
    1844           0 :     if (srcHasSamples) {
    1845           0 :         if (mask & LOCAL_GL_COLOR_BUFFER_BIT &&
    1846           0 :             dstHasColor && !colorFormatsMatch)
    1847             :         {
    1848             :             webgl->ErrorInvalidOperation("%s: Color buffer formats must match if"
    1849             :                                          " selected, when reading from a multisampled"
    1850             :                                          " source.",
    1851           0 :                                          funcName);
    1852           0 :             return;
    1853             :         }
    1854             : 
    1855           0 :         if (dstX0 != srcX0 ||
    1856           0 :             dstX1 != srcX1 ||
    1857           0 :             dstY0 != srcY0 ||
    1858             :             dstY1 != srcY1)
    1859             :         {
    1860             :             webgl->ErrorInvalidOperation("%s: If the source is multisampled, then the"
    1861             :                                          " source and dest regions must match exactly.",
    1862           0 :                                          funcName);
    1863           0 :             return;
    1864             :         }
    1865             :     }
    1866             : 
    1867             :     ////
    1868             :     // Check for feedback
    1869             : 
    1870           0 :     if (srcFB && dstFB) {
    1871           0 :         const WebGLFBAttachPoint* feedback = nullptr;
    1872             : 
    1873           0 :         if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
    1874           0 :             MOZ_ASSERT(srcFB->mColorReadBuffer->IsDefined());
    1875           0 :             for (const auto& cur : dstFB->mColorDrawBuffers) {
    1876           0 :                 if (srcFB->mColorReadBuffer->IsEquivalentForFeedback(*cur)) {
    1877           0 :                     feedback = cur;
    1878           0 :                     break;
    1879             :                 }
    1880             :             }
    1881             :         }
    1882             : 
    1883           0 :         if (mask & LOCAL_GL_DEPTH_BUFFER_BIT &&
    1884           0 :             srcDepthAttach->IsEquivalentForFeedback(*dstDepthAttach))
    1885             :         {
    1886           0 :             feedback = dstDepthAttach;
    1887             :         }
    1888             : 
    1889           0 :         if (mask & LOCAL_GL_STENCIL_BUFFER_BIT &&
    1890           0 :             srcStencilAttach->IsEquivalentForFeedback(*dstStencilAttach))
    1891             :         {
    1892           0 :             feedback = dstStencilAttach;
    1893             :         }
    1894             : 
    1895           0 :         if (feedback) {
    1896             :             webgl->ErrorInvalidOperation("%s: Feedback detected into DRAW_FRAMEBUFFER's"
    1897             :                                          " 0x%04x attachment.",
    1898           0 :                                          funcName, feedback->mAttachmentPoint);
    1899           0 :             return;
    1900           0 :         }
    1901           0 :     } else if (!srcFB && !dstFB) {
    1902           0 :         webgl->ErrorInvalidOperation("%s: Feedback with default framebuffer.", funcName);
    1903           0 :         return;
    1904             :     }
    1905             : 
    1906             :     ////
    1907             : 
    1908           0 :     gl->MakeCurrent();
    1909           0 :     webgl->OnBeforeReadCall();
    1910           0 :     WebGLContext::ScopedDrawCallWrapper wrapper(*webgl);
    1911           0 :     gl->fBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
    1912             :                          dstX0, dstY0, dstX1, dstY1,
    1913           0 :                          mask, filter);
    1914             : }
    1915             : 
    1916             : ////////////////////////////////////////////////////////////////////////////////
    1917             : // Goop.
    1918             : 
    1919             : JSObject*
    1920           0 : WebGLFramebuffer::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
    1921             : {
    1922           0 :     return dom::WebGLFramebufferBinding::Wrap(cx, this, givenProto);
    1923             : }
    1924             : 
    1925             : inline void
    1926           0 : ImplCycleCollectionUnlink(mozilla::WebGLFBAttachPoint& field)
    1927             : {
    1928           0 :     field.Unlink();
    1929           0 : }
    1930             : 
    1931             : inline void
    1932           0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
    1933             :                             const mozilla::WebGLFBAttachPoint& field,
    1934             :                             const char* name,
    1935             :                             uint32_t flags = 0)
    1936             : {
    1937           0 :     CycleCollectionNoteChild(callback, field.Texture(), name, flags);
    1938           0 :     CycleCollectionNoteChild(callback, field.Renderbuffer(), name, flags);
    1939           0 : }
    1940             : 
    1941             : template<typename C>
    1942             : inline void
    1943           0 : ImplCycleCollectionUnlink(C& field)
    1944             : {
    1945           0 :     for (auto& cur : field) {
    1946           0 :         cur.Unlink();
    1947             :     }
    1948           0 : }
    1949             : 
    1950             : template<typename C>
    1951             : inline void
    1952           0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
    1953             :                             const C& field,
    1954             :                             const char* name,
    1955             :                             uint32_t flags = 0)
    1956             : {
    1957           0 :     for (auto& cur : field) {
    1958           0 :         ImplCycleCollectionTraverse(callback, cur, name, flags);
    1959             :     }
    1960           0 : }
    1961             : 
    1962           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLFramebuffer,
    1963             :                                       mDepthAttachment,
    1964             :                                       mStencilAttachment,
    1965             :                                       mDepthStencilAttachment,
    1966             :                                       mColorAttachments)
    1967             : 
    1968           0 : NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLFramebuffer, AddRef)
    1969           0 : NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLFramebuffer, Release)
    1970             : 
    1971             : } // namespace mozilla

Generated by: LCOV version 1.13