content/canvas/src/WebGLContextGL.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "WebGLContext.h"
     7 #include "WebGLContextUtils.h"
     8 #include "WebGLBuffer.h"
     9 #include "WebGLVertexAttribData.h"
    10 #include "WebGLShader.h"
    11 #include "WebGLProgram.h"
    12 #include "WebGLUniformLocation.h"
    13 #include "WebGLFramebuffer.h"
    14 #include "WebGLRenderbuffer.h"
    15 #include "WebGLShaderPrecisionFormat.h"
    16 #include "WebGLTexture.h"
    17 #include "WebGLExtensions.h"
    18 #include "WebGLVertexArray.h"
    20 #include "nsString.h"
    21 #include "nsDebug.h"
    23 #include "gfxContext.h"
    24 #include "gfxPlatform.h"
    25 #include "GLContext.h"
    27 #include "nsContentUtils.h"
    28 #include "nsError.h"
    29 #include "nsLayoutUtils.h"
    31 #include "CanvasUtils.h"
    32 #include "gfxUtils.h"
    34 #include "jsfriendapi.h"
    36 #include "WebGLTexelConversions.h"
    37 #include "WebGLValidateStrings.h"
    38 #include <algorithm>
    40 // needed to check if current OS is lower than 10.7
    41 #if defined(MOZ_WIDGET_COCOA)
    42 #include "nsCocoaFeatures.h"
    43 #endif
    45 #include "mozilla/dom/BindingUtils.h"
    46 #include "mozilla/dom/ImageData.h"
    47 #include "mozilla/dom/ToJSValue.h"
    48 #include "mozilla/Endian.h"
    50 using namespace mozilla;
    51 using namespace mozilla::dom;
    52 using namespace mozilla::gl;
    53 using namespace mozilla::gfx;
    55 static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
    57 const WebGLRectangleObject*
    58 WebGLContext::CurValidFBRectObject() const
    59 {
    60     const WebGLRectangleObject* rect = nullptr;
    62     if (mBoundFramebuffer) {
    63         // We don't really need to ask the driver.
    64         // Use 'precheck' to just check that our internal state looks good.
    65         GLenum precheckStatus = mBoundFramebuffer->PrecheckFramebufferStatus();
    66         if (precheckStatus == LOCAL_GL_FRAMEBUFFER_COMPLETE)
    67             rect = &mBoundFramebuffer->RectangleObject();
    68     } else {
    69         rect = static_cast<const WebGLRectangleObject*>(this);
    70     }
    72     return rect;
    73 }
    75 //
    76 //  WebGL API
    77 //
    79 void
    80 WebGLContext::ActiveTexture(GLenum texture)
    81 {
    82     if (IsContextLost())
    83         return;
    85     if (texture < LOCAL_GL_TEXTURE0 ||
    86         texture >= LOCAL_GL_TEXTURE0 + uint32_t(mGLMaxTextureUnits))
    87     {
    88         return ErrorInvalidEnum(
    89             "ActiveTexture: texture unit %d out of range. "
    90             "Accepted values range from TEXTURE0 to TEXTURE0 + %d. "
    91             "Notice that TEXTURE0 != 0.",
    92             texture, mGLMaxTextureUnits);
    93     }
    95     MakeContextCurrent();
    96     mActiveTexture = texture - LOCAL_GL_TEXTURE0;
    97     gl->fActiveTexture(texture);
    98 }
   100 void
   101 WebGLContext::AttachShader(WebGLProgram *program, WebGLShader *shader)
   102 {
   103     if (IsContextLost())
   104         return;
   106     if (!ValidateObject("attachShader: program", program) ||
   107         !ValidateObject("attachShader: shader", shader))
   108         return;
   110     // Per GLSL ES 2.0, we can only have one of each type of shader
   111     // attached.  This renders the next test somewhat moot, but we'll
   112     // leave it for when we support more than one shader of each type.
   113     if (program->HasAttachedShaderOfType(shader->ShaderType()))
   114         return ErrorInvalidOperation("attachShader: only one of each type of shader may be attached to a program");
   116     if (!program->AttachShader(shader))
   117         return ErrorInvalidOperation("attachShader: shader is already attached");
   118 }
   121 void
   122 WebGLContext::BindAttribLocation(WebGLProgram *prog, GLuint location,
   123                                  const nsAString& name)
   124 {
   125     if (IsContextLost())
   126         return;
   128     if (!ValidateObject("bindAttribLocation: program", prog))
   129         return;
   131     GLuint progname = prog->GLName();
   133     if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
   134         return;
   136     if (!ValidateAttribIndex(location, "bindAttribLocation"))
   137         return;
   139     NS_LossyConvertUTF16toASCII cname(name);
   140     nsCString mappedName;
   141     prog->MapIdentifier(cname, &mappedName);
   143     MakeContextCurrent();
   144     gl->fBindAttribLocation(progname, location, mappedName.get());
   145 }
   147 void
   148 WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer *wfb)
   149 {
   150     if (IsContextLost())
   151         return;
   153     if (target != LOCAL_GL_FRAMEBUFFER)
   154         return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER");
   156     if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb))
   157         return;
   159     // silently ignore a deleted frame buffer
   160     if (wfb && wfb->IsDeleted())
   161         return;
   163     MakeContextCurrent();
   165     if (!wfb) {
   166         gl->fBindFramebuffer(target, 0);
   167     } else {
   168         GLuint framebuffername = wfb->GLName();
   169         gl->fBindFramebuffer(target, framebuffername);
   170         wfb->SetHasEverBeenBound(true);
   171     }
   173     mBoundFramebuffer = wfb;
   174 }
   176 void
   177 WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb)
   178 {
   179     if (IsContextLost())
   180         return;
   182     if (target != LOCAL_GL_RENDERBUFFER)
   183         return ErrorInvalidEnumInfo("bindRenderbuffer: target", target);
   185     if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb))
   186         return;
   188     // silently ignore a deleted buffer
   189     if (wrb && wrb->IsDeleted())
   190         return;
   192     if (wrb)
   193         wrb->SetHasEverBeenBound(true);
   195     MakeContextCurrent();
   197     // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
   198     // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
   199     if (wrb) {
   200         wrb->BindRenderbuffer();
   201     } else {
   202         gl->fBindRenderbuffer(target, 0);
   203     }
   205     mBoundRenderbuffer = wrb;
   206 }
   208 void
   209 WebGLContext::BindTexture(GLenum target, WebGLTexture *newTex)
   210 {
   211     if (IsContextLost())
   212         return;
   214      if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex))
   215         return;
   217     // silently ignore a deleted texture
   218     if (newTex && newTex->IsDeleted())
   219         return;
   221     WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
   223     if (target == LOCAL_GL_TEXTURE_2D) {
   224         currentTexPtr = &mBound2DTextures[mActiveTexture];
   225     } else if (target == LOCAL_GL_TEXTURE_CUBE_MAP) {
   226         currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
   227     } else {
   228         return ErrorInvalidEnumInfo("bindTexture: target", target);
   229     }
   231     WebGLTextureFakeBlackStatus currentTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
   232     if (*currentTexPtr) {
   233         currentTexFakeBlackStatus = (*currentTexPtr)->ResolvedFakeBlackStatus();
   234     }
   235     WebGLTextureFakeBlackStatus newTexFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
   236     if (newTex) {
   237         newTexFakeBlackStatus = newTex->ResolvedFakeBlackStatus();
   238     }
   240     *currentTexPtr = newTex;
   242     if (currentTexFakeBlackStatus != newTexFakeBlackStatus) {
   243         SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
   244     }
   246     MakeContextCurrent();
   248     if (newTex)
   249         newTex->Bind(target);
   250     else
   251         gl->fBindTexture(target, 0 /* == texturename */);
   252 }
   254 void WebGLContext::BlendEquation(GLenum mode)
   255 {
   256     if (IsContextLost())
   257         return;
   259     if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
   260         return;
   262     MakeContextCurrent();
   263     gl->fBlendEquation(mode);
   264 }
   266 void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
   267 {
   268     if (IsContextLost())
   269         return;
   271     if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
   272         !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
   273         return;
   275     MakeContextCurrent();
   276     gl->fBlendEquationSeparate(modeRGB, modeAlpha);
   277 }
   279 void WebGLContext::BlendFunc(GLenum sfactor, GLenum dfactor)
   280 {
   281     if (IsContextLost())
   282         return;
   284     if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
   285         !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
   286         return;
   288     if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "blendFuncSeparate: srcRGB and dstRGB"))
   289         return;
   291     MakeContextCurrent();
   292     gl->fBlendFunc(sfactor, dfactor);
   293 }
   295 void
   296 WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
   297                                 GLenum srcAlpha, GLenum dstAlpha)
   298 {
   299     if (IsContextLost())
   300         return;
   302     if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
   303         !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
   304         !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
   305         !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
   306         return;
   308     // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
   309     // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
   310     if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "blendFuncSeparate: srcRGB and dstRGB"))
   311         return;
   313     MakeContextCurrent();
   314     gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
   315 }
   317 GLenum
   318 WebGLContext::CheckFramebufferStatus(GLenum target)
   319 {
   320     if (IsContextLost())
   321         return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
   323     if (target != LOCAL_GL_FRAMEBUFFER) {
   324         ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
   325         return 0;
   326     }
   328     if (!mBoundFramebuffer)
   329         return LOCAL_GL_FRAMEBUFFER_COMPLETE;
   331     return mBoundFramebuffer->CheckFramebufferStatus();
   332 }
   334 void
   335 WebGLContext::CopyTexSubImage2D_base(GLenum target,
   336                                      GLint level,
   337                                      GLenum internalformat,
   338                                      GLint xoffset,
   339                                      GLint yoffset,
   340                                      GLint x,
   341                                      GLint y,
   342                                      GLsizei width,
   343                                      GLsizei height,
   344                                      bool sub)
   345 {
   346     const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
   347     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
   348     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
   350     const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
   351     WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
   353     // TODO: This changes with color_buffer_float. Reassess when the
   354     // patch lands.
   355     if (!ValidateTexImage(2, target, level, internalformat,
   356                           xoffset, yoffset, 0,
   357                           width, height, 0,
   358                           0, internalformat, LOCAL_GL_UNSIGNED_BYTE,
   359                           func))
   360     {
   361         return;
   362     }
   364     MakeContextCurrent();
   366     WebGLTexture *tex = activeBoundTextureForTarget(target);
   368     if (!tex)
   369         return ErrorInvalidOperation("%s: no texture is bound to this target");
   371     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
   372         if (sub)
   373             gl->fCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
   374         else
   375             gl->fCopyTexImage2D(target, level, internalformat, x, y, width, height, 0);
   376     } else {
   378         // the rect doesn't fit in the framebuffer
   380         /*** first, we initialize the texture as black ***/
   382         // first, compute the size of the buffer we should allocate to initialize the texture as black
   384         if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE, -1, func))
   385             return;
   387         uint32_t texelSize = GetBitsPerTexel(internalformat, LOCAL_GL_UNSIGNED_BYTE) / 8;
   389         CheckedUint32 checked_neededByteLength =
   390             GetImageSize(height, width, texelSize, mPixelStoreUnpackAlignment);
   392         if (!checked_neededByteLength.isValid())
   393             return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info);
   395         uint32_t bytesNeeded = checked_neededByteLength.value();
   397         // now that the size is known, create the buffer
   399         // We need some zero pages, because GL doesn't guarantee the
   400         // contents of a texture allocated with nullptr data.
   401         // Hopefully calloc will just mmap zero pages here.
   402         void* tempZeroData = calloc(1, bytesNeeded);
   403         if (!tempZeroData)
   404             return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info, bytesNeeded);
   406         // now initialize the texture as black
   408         if (sub)
   409             gl->fTexSubImage2D(target, level, 0, 0, width, height,
   410                                internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
   411         else
   412             gl->fTexImage2D(target, level, internalformat, width, height,
   413                             0, internalformat, LOCAL_GL_UNSIGNED_BYTE, tempZeroData);
   414         free(tempZeroData);
   416         // if we are completely outside of the framebuffer, we can exit now with our black texture
   417         if (   x >= framebufferWidth
   418             || x+width <= 0
   419             || y >= framebufferHeight
   420             || y+height <= 0)
   421         {
   422             // we are completely outside of range, can exit now with buffer filled with zeros
   423             return DummyFramebufferOperation(info);
   424         }
   426         GLint   actual_x             = clamped(x, 0, framebufferWidth);
   427         GLint   actual_x_plus_width  = clamped(x + width, 0, framebufferWidth);
   428         GLsizei actual_width   = actual_x_plus_width  - actual_x;
   429         GLint   actual_xoffset = xoffset + actual_x - x;
   431         GLint   actual_y             = clamped(y, 0, framebufferHeight);
   432         GLint   actual_y_plus_height = clamped(y + height, 0, framebufferHeight);
   433         GLsizei actual_height  = actual_y_plus_height - actual_y;
   434         GLint   actual_yoffset = yoffset + actual_y - y;
   436         gl->fCopyTexSubImage2D(target, level, actual_xoffset, actual_yoffset, actual_x, actual_y, actual_width, actual_height);
   437     }
   438 }
   440 void
   441 WebGLContext::CopyTexImage2D(GLenum target,
   442                              GLint level,
   443                              GLenum internalformat,
   444                              GLint x,
   445                              GLint y,
   446                              GLsizei width,
   447                              GLsizei height,
   448                              GLint border)
   449 {
   450     if (IsContextLost())
   451         return;
   453     // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
   454     const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
   455     const GLenum format = internalformat; // WebGL/ES Format
   456     const GLenum type = LOCAL_GL_UNSIGNED_BYTE; // WebGL/ES Format
   458     if (!ValidateTexImage(2, target, level, format,
   459                           0, 0, 0,
   460                           width, height, 0,
   461                           border, format, type,
   462                           func))
   463     {
   464         return;
   465     }
   467     if (mBoundFramebuffer) {
   468         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
   469             return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
   471         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
   472         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
   473             return ErrorInvalidOperation("copyTexImage2D: Read source attachment doesn't have the"
   474                                          " correct color/depth/stencil type.");
   475         }
   476     } else {
   477       ClearBackbufferIfNeeded();
   478     }
   480     bool texFormatRequiresAlpha = format == LOCAL_GL_RGBA ||
   481                                   format == LOCAL_GL_ALPHA ||
   482                                   format == LOCAL_GL_LUMINANCE_ALPHA;
   483     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
   484                                                : bool(gl->GetPixelFormat().alpha > 0);
   485     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
   486         return ErrorInvalidOperation("copyTexImage2D: texture format requires an alpha channel "
   487                                      "but the framebuffer doesn't have one");
   489     // check if the memory size of this texture may change with this call
   490     bool sizeMayChange = true;
   491     WebGLTexture* tex = activeBoundTextureForTarget(target);
   492     if (tex->HasImageInfoAt(target, level)) {
   493         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
   495         sizeMayChange = width != imageInfo.Width() ||
   496                         height != imageInfo.Height() ||
   497                         format != imageInfo.WebGLFormat() ||
   498                         type != imageInfo.WebGLType();
   499     }
   501     if (sizeMayChange)
   502         GetAndFlushUnderlyingGLErrors();
   504     CopyTexSubImage2D_base(target, level, format, 0, 0, x, y, width, height, false);
   506     if (sizeMayChange) {
   507         GLenum error = GetAndFlushUnderlyingGLErrors();
   508         if (error) {
   509             GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
   510             return;
   511         }
   512     }
   514     tex->SetImageInfo(target, level, width, height, format, type,
   515                       WebGLImageDataStatus::InitializedImageData);
   516 }
   518 void
   519 WebGLContext::CopyTexSubImage2D(GLenum target,
   520                                 GLint level,
   521                                 GLint xoffset,
   522                                 GLint yoffset,
   523                                 GLint x,
   524                                 GLint y,
   525                                 GLsizei width,
   526                                 GLsizei height)
   527 {
   528     if (IsContextLost())
   529         return;
   531     switch (target) {
   532         case LOCAL_GL_TEXTURE_2D:
   533         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
   534         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
   535         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
   536         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
   537         case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
   538         case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
   539             break;
   540         default:
   541             return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target);
   542     }
   544     if (level < 0)
   545         return ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
   547     GLsizei maxTextureSize = MaxTextureSizeForTarget(target);
   548     if (!(maxTextureSize >> level))
   549         return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
   551     if (width < 0 || height < 0)
   552         return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
   554     if (xoffset < 0 || yoffset < 0)
   555         return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
   557     WebGLTexture *tex = activeBoundTextureForTarget(target);
   558     if (!tex)
   559         return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
   561     if (!tex->HasImageInfoAt(target, level))
   562         return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
   564     const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
   565     GLsizei texWidth = imageInfo.Width();
   566     GLsizei texHeight = imageInfo.Height();
   568     if (xoffset + width > texWidth || xoffset + width < 0)
   569       return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
   571     if (yoffset + height > texHeight || yoffset + height < 0)
   572       return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
   574     GLenum webGLFormat = imageInfo.WebGLFormat();
   575     if (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat))
   576         return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
   578     if (mBoundFramebuffer) {
   579         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
   580             return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
   582         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
   583         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
   584             return ErrorInvalidOperation("copyTexSubImage2D: Read source attachment doesn't have the"
   585                                          " correct color/depth/stencil type.");
   586         }
   587     } else {
   588         ClearBackbufferIfNeeded();
   589     }
   591     bool texFormatRequiresAlpha = FormatHasAlpha(webGLFormat);
   592     bool fboFormatHasAlpha = mBoundFramebuffer ? mBoundFramebuffer->ColorAttachment(0).HasAlpha()
   593                                                : bool(gl->GetPixelFormat().alpha > 0);
   595     if (texFormatRequiresAlpha && !fboFormatHasAlpha)
   596         return ErrorInvalidOperation("copyTexSubImage2D: texture format requires an alpha channel "
   597                                      "but the framebuffer doesn't have one");
   599     if (imageInfo.HasUninitializedImageData()) {
   600         tex->DoDeferredImageInitialization(target, level);
   601     }
   603     return CopyTexSubImage2D_base(target, level, webGLFormat, xoffset, yoffset, x, y, width, height, true);
   604 }
   607 already_AddRefed<WebGLProgram>
   608 WebGLContext::CreateProgram()
   609 {
   610     if (IsContextLost())
   611         return nullptr;
   612     nsRefPtr<WebGLProgram> globj = new WebGLProgram(this);
   613     return globj.forget();
   614 }
   616 already_AddRefed<WebGLShader>
   617 WebGLContext::CreateShader(GLenum type)
   618 {
   619     if (IsContextLost())
   620         return nullptr;
   622     if (type != LOCAL_GL_VERTEX_SHADER &&
   623         type != LOCAL_GL_FRAGMENT_SHADER)
   624     {
   625         ErrorInvalidEnumInfo("createShader: type", type);
   626         return nullptr;
   627     }
   629     nsRefPtr<WebGLShader> shader = new WebGLShader(this, type);
   630     return shader.forget();
   631 }
   633 void
   634 WebGLContext::CullFace(GLenum face)
   635 {
   636     if (IsContextLost())
   637         return;
   639     if (!ValidateFaceEnum(face, "cullFace"))
   640         return;
   642     MakeContextCurrent();
   643     gl->fCullFace(face);
   644 }
   646 void
   647 WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
   648 {
   649     if (IsContextLost())
   650         return;
   652     if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf))
   653         return;
   655     if (!fbuf || fbuf->IsDeleted())
   656         return;
   658     fbuf->RequestDelete();
   660     if (mBoundFramebuffer == fbuf)
   661         BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
   662                         static_cast<WebGLFramebuffer*>(nullptr));
   663 }
   665 void
   666 WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer *rbuf)
   667 {
   668     if (IsContextLost())
   669         return;
   671     if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf))
   672         return;
   674     if (!rbuf || rbuf->IsDeleted())
   675         return;
   677     if (mBoundFramebuffer)
   678         mBoundFramebuffer->DetachRenderbuffer(rbuf);
   680     // Invalidate framebuffer status cache
   681     rbuf->NotifyFBsStatusChanged();
   683     if (mBoundRenderbuffer == rbuf)
   684         BindRenderbuffer(LOCAL_GL_RENDERBUFFER,
   685                          static_cast<WebGLRenderbuffer*>(nullptr));
   687     rbuf->RequestDelete();
   688 }
   690 void
   691 WebGLContext::DeleteTexture(WebGLTexture *tex)
   692 {
   693     if (IsContextLost())
   694         return;
   696     if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex))
   697         return;
   699     if (!tex || tex->IsDeleted())
   700         return;
   702     if (mBoundFramebuffer)
   703         mBoundFramebuffer->DetachTexture(tex);
   705     // Invalidate framebuffer status cache
   706     tex->NotifyFBsStatusChanged();
   708     GLuint activeTexture = mActiveTexture;
   709     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
   710         if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) ||
   711             (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex))
   712         {
   713             ActiveTexture(LOCAL_GL_TEXTURE0 + i);
   714             BindTexture(tex->Target(), static_cast<WebGLTexture*>(nullptr));
   715         }
   716     }
   717     ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
   719     tex->RequestDelete();
   720 }
   722 void
   723 WebGLContext::DeleteProgram(WebGLProgram *prog)
   724 {
   725     if (IsContextLost())
   726         return;
   728     if (!ValidateObjectAllowDeletedOrNull("deleteProgram", prog))
   729         return;
   731     if (!prog || prog->IsDeleted())
   732         return;
   734     prog->RequestDelete();
   735 }
   737 void
   738 WebGLContext::DeleteShader(WebGLShader *shader)
   739 {
   740     if (IsContextLost())
   741         return;
   743     if (!ValidateObjectAllowDeletedOrNull("deleteShader", shader))
   744         return;
   746     if (!shader || shader->IsDeleted())
   747         return;
   749     shader->RequestDelete();
   750 }
   752 void
   753 WebGLContext::DetachShader(WebGLProgram *program, WebGLShader *shader)
   754 {
   755     if (IsContextLost())
   756         return;
   758     if (!ValidateObject("detachShader: program", program) ||
   759         // it's valid to attempt to detach a deleted shader, since it's
   760         // still a shader
   761         !ValidateObjectAllowDeleted("detashShader: shader", shader))
   762         return;
   764     if (!program->DetachShader(shader))
   765         return ErrorInvalidOperation("detachShader: shader is not attached");
   766 }
   768 void
   769 WebGLContext::DepthFunc(GLenum func)
   770 {
   771     if (IsContextLost())
   772         return;
   774     if (!ValidateComparisonEnum(func, "depthFunc"))
   775         return;
   777     MakeContextCurrent();
   778     gl->fDepthFunc(func);
   779 }
   781 void
   782 WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
   783 {
   784     if (IsContextLost())
   785         return;
   787     if (zNear > zFar)
   788         return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
   790     MakeContextCurrent();
   791     gl->fDepthRange(zNear, zFar);
   792 }
   794 void
   795 WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum rbtarget, WebGLRenderbuffer *wrb)
   796 {
   797     if (IsContextLost())
   798         return;
   800     if (!mBoundFramebuffer)
   801         return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
   803     return mBoundFramebuffer->FramebufferRenderbuffer(target, attachment, rbtarget, wrb);
   804 }
   806 void
   807 WebGLContext::FramebufferTexture2D(GLenum target,
   808                                    GLenum attachment,
   809                                    GLenum textarget,
   810                                    WebGLTexture *tobj,
   811                                    GLint level)
   812 {
   813     if (IsContextLost())
   814         return;
   816     if (!mBoundFramebuffer)
   817         return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
   819     return mBoundFramebuffer->FramebufferTexture2D(target, attachment, textarget, tobj, level);
   820 }
   822 void
   823 WebGLContext::FrontFace(GLenum mode)
   824 {
   825     if (IsContextLost())
   826         return;
   828     switch (mode) {
   829         case LOCAL_GL_CW:
   830         case LOCAL_GL_CCW:
   831             break;
   832         default:
   833             return ErrorInvalidEnumInfo("frontFace: mode", mode);
   834     }
   836     MakeContextCurrent();
   837     gl->fFrontFace(mode);
   838 }
   840 already_AddRefed<WebGLActiveInfo>
   841 WebGLContext::GetActiveAttrib(WebGLProgram *prog, uint32_t index)
   842 {
   843     if (IsContextLost())
   844         return nullptr;
   846     if (!ValidateObject("getActiveAttrib: program", prog))
   847         return nullptr;
   849     MakeContextCurrent();
   851     GLint len = 0;
   852     GLuint progname = prog->GLName();;
   853     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
   854     if (len == 0)
   855         return nullptr;
   857     nsAutoArrayPtr<char> name(new char[len]);
   858     GLint attrsize = 0;
   859     GLuint attrtype = 0;
   861     gl->fGetActiveAttrib(progname, index, len, &len, &attrsize, &attrtype, name);
   862     if (attrsize == 0 || attrtype == 0) {
   863         return nullptr;
   864     }
   866     nsCString reverseMappedName;
   867     prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
   869     nsRefPtr<WebGLActiveInfo> retActiveInfo =
   870         new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
   871     return retActiveInfo.forget();
   872 }
   874 void
   875 WebGLContext::GenerateMipmap(GLenum target)
   876 {
   877     if (IsContextLost())
   878         return;
   880     if (!ValidateTextureTargetEnum(target, "generateMipmap"))
   881         return;
   883     WebGLTexture *tex = activeBoundTextureForTarget(target);
   885     if (!tex)
   886         return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
   888     GLenum imageTarget = (target == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_2D
   889                                                          : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
   890     if (!tex->HasImageInfoAt(imageTarget, 0))
   891     {
   892         return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
   893     }
   895     if (!tex->IsFirstImagePowerOfTwo())
   896         return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
   898     GLenum webGLFormat = tex->ImageInfoAt(imageTarget, 0).WebGLFormat();
   899     if (IsTextureFormatCompressed(webGLFormat))
   900         return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
   902     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture) &&
   903         (IsGLDepthFormat(webGLFormat) || IsGLDepthStencilFormat(webGLFormat)))
   904     {
   905         return ErrorInvalidOperation("generateMipmap: "
   906                                      "A texture that has a base internal format of "
   907                                      "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
   908     }
   910     if (!tex->AreAllLevel0ImageInfosEqual())
   911         return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
   913     tex->SetGeneratedMipmap();
   915     MakeContextCurrent();
   917     if (gl->WorkAroundDriverBugs()) {
   918         // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
   919         // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
   920         // overhead so we do it unconditionally.
   921         //
   922         // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
   923         gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST_MIPMAP_NEAREST);
   924         gl->fGenerateMipmap(target);
   925         gl->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter());
   926     } else {
   927         gl->fGenerateMipmap(target);
   928     }
   929 }
   931 already_AddRefed<WebGLActiveInfo>
   932 WebGLContext::GetActiveUniform(WebGLProgram *prog, uint32_t index)
   933 {
   934     if (IsContextLost())
   935         return nullptr;
   937     if (!ValidateObject("getActiveUniform: program", prog))
   938         return nullptr;
   940     MakeContextCurrent();
   942     GLint len = 0;
   943     GLuint progname = prog->GLName();
   944     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
   945     if (len == 0)
   946         return nullptr;
   948     nsAutoArrayPtr<char> name(new char[len]);
   950     GLint usize = 0;
   951     GLuint utype = 0;
   953     gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
   954     if (len == 0 || usize == 0 || utype == 0) {
   955         return nullptr;
   956     }
   958     nsCString reverseMappedName;
   959     prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
   961     // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
   962     // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
   963     //
   964     // > If the active uniform is an array, the uniform name returned in name will always
   965     // > be the name of the uniform array appended with "[0]".
   966     //
   967     // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning
   968     // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the
   969     // returned name ends in [0], and if it doesn't, append that.
   970     //
   971     // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
   972     // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
   973     // we do it unconditionally.
   974     if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
   975         reverseMappedName.AppendLiteral("[0]");
   977     nsRefPtr<WebGLActiveInfo> retActiveInfo =
   978         new WebGLActiveInfo(usize, utype, reverseMappedName);
   979     return retActiveInfo.forget();
   980 }
   982 void
   983 WebGLContext::GetAttachedShaders(WebGLProgram *prog,
   984                                  Nullable< nsTArray<WebGLShader*> > &retval)
   985 {
   986     retval.SetNull();
   987     if (IsContextLost())
   988         return;
   990     if (!ValidateObjectAllowNull("getAttachedShaders", prog))
   991         return;
   993     MakeContextCurrent();
   995     if (!prog) {
   996         retval.SetNull();
   997         ErrorInvalidValue("getAttachedShaders: invalid program");
   998     } else if (prog->AttachedShaders().Length() == 0) {
   999         retval.SetValue().TruncateLength(0);
  1000     } else {
  1001         retval.SetValue().AppendElements(prog->AttachedShaders());
  1005 GLint
  1006 WebGLContext::GetAttribLocation(WebGLProgram *prog, const nsAString& name)
  1008     if (IsContextLost())
  1009         return -1;
  1011     if (!ValidateObject("getAttribLocation: program", prog))
  1012         return -1;
  1014     if (!ValidateGLSLVariableName(name, "getAttribLocation"))
  1015         return -1;
  1017     NS_LossyConvertUTF16toASCII cname(name);
  1018     nsCString mappedName;
  1019     prog->MapIdentifier(cname, &mappedName);
  1021     GLuint progname = prog->GLName();
  1023     MakeContextCurrent();
  1024     return gl->fGetAttribLocation(progname, mappedName.get());
  1027 JS::Value
  1028 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
  1030     if (IsContextLost())
  1031         return JS::NullValue();
  1033     if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
  1034         ErrorInvalidEnumInfo("getBufferParameter: target", target);
  1035         return JS::NullValue();
  1038     MakeContextCurrent();
  1040     switch (pname) {
  1041         case LOCAL_GL_BUFFER_SIZE:
  1042         case LOCAL_GL_BUFFER_USAGE:
  1044             GLint i = 0;
  1045             gl->fGetBufferParameteriv(target, pname, &i);
  1046             if (pname == LOCAL_GL_BUFFER_SIZE) {
  1047                 return JS::Int32Value(i);
  1050             MOZ_ASSERT(pname == LOCAL_GL_BUFFER_USAGE);
  1051             return JS::NumberValue(uint32_t(i));
  1053             break;
  1055         default:
  1056             ErrorInvalidEnumInfo("getBufferParameter: parameter", pname);
  1059     return JS::NullValue();
  1062 JS::Value
  1063 WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
  1064                                                 GLenum target,
  1065                                                 GLenum attachment,
  1066                                                 GLenum pname,
  1067                                                 ErrorResult& rv)
  1069     if (IsContextLost())
  1070         return JS::NullValue();
  1072     if (target != LOCAL_GL_FRAMEBUFFER) {
  1073         ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target);
  1074         return JS::NullValue();
  1077     if (!mBoundFramebuffer) {
  1078         ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
  1079         return JS::NullValue();
  1082     if (attachment != LOCAL_GL_DEPTH_ATTACHMENT &&
  1083         attachment != LOCAL_GL_STENCIL_ATTACHMENT &&
  1084         attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
  1086         if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
  1088             if (attachment < LOCAL_GL_COLOR_ATTACHMENT0 ||
  1089                 attachment >= GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments))
  1091                 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
  1092                 return JS::NullValue();
  1095             mBoundFramebuffer->EnsureColorAttachments(attachment - LOCAL_GL_COLOR_ATTACHMENT0);
  1097         else if (attachment != LOCAL_GL_COLOR_ATTACHMENT0)
  1099             ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment);
  1100             return JS::NullValue();
  1104     MakeContextCurrent();
  1106     const WebGLFramebuffer::Attachment& fba = mBoundFramebuffer->GetAttachment(attachment);
  1108     if (fba.Renderbuffer()) {
  1109         switch (pname) {
  1110             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
  1111                 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
  1112                     const GLenum internalFormat = fba.Renderbuffer()->InternalFormat();
  1113                     return (internalFormat == LOCAL_GL_SRGB_EXT ||
  1114                             internalFormat == LOCAL_GL_SRGB_ALPHA_EXT ||
  1115                             internalFormat == LOCAL_GL_SRGB8_ALPHA8_EXT) ?
  1116                         JS::NumberValue(uint32_t(LOCAL_GL_SRGB_EXT)) :
  1117                         JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
  1119                 break;
  1121             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1122                 return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER));
  1124             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
  1125                 return WebGLObjectAsJSValue(cx, fba.Renderbuffer(), rv);
  1127             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
  1128                 if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
  1129                     !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
  1131                     break;
  1134                 if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
  1135                     ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
  1136                                           " type of a depth-stencil attachment.");
  1137                     return JS::NullValue();
  1140                 if (!fba.IsComplete())
  1141                     return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1143                 uint32_t ret = LOCAL_GL_NONE;
  1144                 switch (fba.Renderbuffer()->InternalFormat()) {
  1145                 case LOCAL_GL_RGBA4:
  1146                 case LOCAL_GL_RGB5_A1:
  1147                 case LOCAL_GL_RGB565:
  1148                 case LOCAL_GL_SRGB8_ALPHA8:
  1149                     ret = LOCAL_GL_UNSIGNED_NORMALIZED;
  1150                     break;
  1151                 case LOCAL_GL_RGB16F:
  1152                 case LOCAL_GL_RGBA16F:
  1153                 case LOCAL_GL_RGB32F:
  1154                 case LOCAL_GL_RGBA32F:
  1155                     ret = LOCAL_GL_FLOAT;
  1156                     break;
  1157                 case LOCAL_GL_DEPTH_COMPONENT16:
  1158                 case LOCAL_GL_STENCIL_INDEX8:
  1159                     ret = LOCAL_GL_UNSIGNED_INT;
  1160                     break;
  1161                 default:
  1162                     MOZ_ASSERT(false, "Unhandled RB component type.");
  1163                     break;
  1165                 return JS::NumberValue(uint32_t(ret));
  1169         ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1170         return JS::NullValue();
  1171     } else if (fba.Texture()) {
  1172         switch (pname) {
  1173              case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT:
  1174                 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
  1175                     const GLenum webGLFormat =
  1176                         fba.Texture()->ImageInfoBase().WebGLFormat();
  1177                     return (webGLFormat == LOCAL_GL_SRGB ||
  1178                             webGLFormat == LOCAL_GL_SRGB_ALPHA) ?
  1179                         JS::NumberValue(uint32_t(LOCAL_GL_SRGB)) :
  1180                         JS::NumberValue(uint32_t(LOCAL_GL_LINEAR));
  1182                 break;
  1184             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1185                 return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE));
  1187             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
  1188                 return WebGLObjectAsJSValue(cx, fba.Texture(), rv);
  1190             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
  1191                 return JS::Int32Value(fba.TexImageLevel());
  1193             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE: {
  1194                 GLenum face = fba.TexImageTarget();
  1195                 if (face == LOCAL_GL_TEXTURE_2D)
  1196                     face = 0;
  1197                 return JS::Int32Value(face);
  1200             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: {
  1201                 if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) &&
  1202                     !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
  1204                     break;
  1207                 if (attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) {
  1208                     ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
  1209                                           " type of depth-stencil attachments.");
  1210                     return JS::NullValue();
  1213                 if (!fba.IsComplete())
  1214                     return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1216                 uint32_t ret = LOCAL_GL_NONE;
  1217                 GLenum type = fba.Texture()->ImageInfoAt(fba.TexImageTarget(),
  1218                                                          fba.TexImageLevel()).WebGLType();
  1219                 switch (type) {
  1220                 case LOCAL_GL_UNSIGNED_BYTE:
  1221                 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1222                 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1223                 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1224                     ret = LOCAL_GL_UNSIGNED_NORMALIZED;
  1225                     break;
  1226                 case LOCAL_GL_FLOAT:
  1227                 case LOCAL_GL_HALF_FLOAT_OES:
  1228                     ret = LOCAL_GL_FLOAT;
  1229                     break;
  1230                 case LOCAL_GL_UNSIGNED_SHORT:
  1231                 case LOCAL_GL_UNSIGNED_INT:
  1232                     ret = LOCAL_GL_UNSIGNED_INT;
  1233                     break;
  1234                 default:
  1235                     MOZ_ASSERT(false, "Unhandled RB component type.");
  1236                     break;
  1238                 return JS::NumberValue(uint32_t(ret));
  1242         ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1243         return JS::NullValue();
  1244     } else {
  1245         switch (pname) {
  1246             case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
  1247                 return JS::NumberValue(uint32_t(LOCAL_GL_NONE));
  1249             default:
  1250                 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname);
  1251                 return JS::NullValue();
  1255     return JS::NullValue();
  1258 JS::Value
  1259 WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
  1261     if (IsContextLost())
  1262         return JS::NullValue();
  1264     if (target != LOCAL_GL_RENDERBUFFER) {
  1265         ErrorInvalidEnumInfo("getRenderbufferParameter: target", target);
  1266         return JS::NullValue();
  1269     if (!mBoundRenderbuffer) {
  1270         ErrorInvalidOperation("getRenderbufferParameter: no render buffer is bound");
  1271         return JS::NullValue();
  1274     MakeContextCurrent();
  1276     switch (pname) {
  1277         case LOCAL_GL_RENDERBUFFER_WIDTH:
  1278         case LOCAL_GL_RENDERBUFFER_HEIGHT:
  1279         case LOCAL_GL_RENDERBUFFER_RED_SIZE:
  1280         case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
  1281         case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
  1282         case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
  1283         case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
  1284         case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
  1286             // RB emulation means we have to ask the RB itself.
  1287             GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
  1288             return JS::Int32Value(i);
  1290         case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
  1292             return JS::NumberValue(mBoundRenderbuffer->InternalFormat());
  1294         default:
  1295             ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname);
  1298     return JS::NullValue();
  1301 already_AddRefed<WebGLTexture>
  1302 WebGLContext::CreateTexture()
  1304     if (IsContextLost())
  1305         return nullptr;
  1306     nsRefPtr<WebGLTexture> globj = new WebGLTexture(this);
  1307     return globj.forget();
  1310 static GLenum
  1311 GetAndClearError(GLenum* errorVar)
  1313     MOZ_ASSERT(errorVar);
  1314     GLenum ret = *errorVar;
  1315     *errorVar = LOCAL_GL_NO_ERROR;
  1316     return ret;
  1319 GLenum
  1320 WebGLContext::GetError()
  1322     /* WebGL 1.0: Section 5.14.3: Setting and getting state:
  1323      *   If the context's webgl context lost flag is set, returns
  1324      *   CONTEXT_LOST_WEBGL the first time this method is called.
  1325      *   Afterward, returns NO_ERROR until the context has been
  1326      *   restored.
  1328      * WEBGL_lose_context:
  1329      *   [When this extension is enabled: ] loseContext and
  1330      *   restoreContext are allowed to generate INVALID_OPERATION errors
  1331      *   even when the context is lost.
  1332      */
  1334     if (IsContextLost()) {
  1335         if (mEmitContextLostErrorOnce) {
  1336             mEmitContextLostErrorOnce = false;
  1337             return LOCAL_GL_CONTEXT_LOST;
  1339         // Don't return yet, since WEBGL_lose_contexts contradicts the
  1340         // original spec, and allows error generation while lost.
  1343     GLenum err = GetAndClearError(&mWebGLError);
  1344     if (err != LOCAL_GL_NO_ERROR)
  1345         return err;
  1347     if (IsContextLost())
  1348         return LOCAL_GL_NO_ERROR;
  1350     // Either no WebGL-side error, or it's already been cleared.
  1351     // UnderlyingGL-side errors, now.
  1353     MakeContextCurrent();
  1354     GetAndFlushUnderlyingGLErrors();
  1356     err = GetAndClearError(&mUnderlyingGLError);
  1357     return err;
  1360 JS::Value
  1361 WebGLContext::GetProgramParameter(WebGLProgram *prog, GLenum pname)
  1363     if (IsContextLost())
  1364         return JS::NullValue();
  1366     if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog))
  1367         return JS::NullValue();
  1369     GLuint progname = prog->GLName();
  1371     MakeContextCurrent();
  1373     switch (pname) {
  1374         case LOCAL_GL_ATTACHED_SHADERS:
  1375         case LOCAL_GL_ACTIVE_UNIFORMS:
  1376         case LOCAL_GL_ACTIVE_ATTRIBUTES:
  1378             GLint i = 0;
  1379             gl->fGetProgramiv(progname, pname, &i);
  1380             return JS::Int32Value(i);
  1382         case LOCAL_GL_DELETE_STATUS:
  1383             return JS::BooleanValue(prog->IsDeleteRequested());
  1384         case LOCAL_GL_LINK_STATUS:
  1386             return JS::BooleanValue(prog->LinkStatus());
  1388         case LOCAL_GL_VALIDATE_STATUS:
  1390             GLint i = 0;
  1391 #ifdef XP_MACOSX
  1392             // See comment in ValidateProgram below.
  1393             if (gl->WorkAroundDriverBugs())
  1394                 i = 1;
  1395             else
  1396                 gl->fGetProgramiv(progname, pname, &i);
  1397 #else
  1398             gl->fGetProgramiv(progname, pname, &i);
  1399 #endif
  1400             return JS::BooleanValue(bool(i));
  1402             break;
  1404         default:
  1405             ErrorInvalidEnumInfo("getProgramParameter: parameter", pname);
  1408     return JS::NullValue();
  1411 void
  1412 WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsAString& retval)
  1414     nsAutoCString s;
  1415     GetProgramInfoLog(prog, s);
  1416     if (s.IsVoid())
  1417         retval.SetIsVoid(true);
  1418     else
  1419         CopyASCIItoUTF16(s, retval);
  1422 void
  1423 WebGLContext::GetProgramInfoLog(WebGLProgram *prog, nsACString& retval)
  1425     if (IsContextLost())
  1427         retval.SetIsVoid(true);
  1428         return;
  1431     if (!ValidateObject("getProgramInfoLog: program", prog)) {
  1432         retval.Truncate();
  1433         return;
  1436     GLuint progname = prog->GLName();
  1438     MakeContextCurrent();
  1440     GLint k = -1;
  1441     gl->fGetProgramiv(progname, LOCAL_GL_INFO_LOG_LENGTH, &k);
  1442     if (k == -1) {
  1443         // If GetProgramiv doesn't modify |k|,
  1444         // it's because there was a GL error.
  1445         // GetProgramInfoLog should return null on error. (Bug 746740)
  1446         retval.SetIsVoid(true);
  1447         return;
  1450     if (k == 0) {
  1451         retval.Truncate();
  1452         return;
  1455     retval.SetCapacity(k);
  1456     gl->fGetProgramInfoLog(progname, k, &k, (char*) retval.BeginWriting());
  1457     retval.SetLength(k);
  1460 // here we have to support all pnames with both int and float params.
  1461 // See this discussion:
  1462 //  https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
  1463 void WebGLContext::TexParameter_base(GLenum target, GLenum pname,
  1464                                      GLint *intParamPtr,
  1465                                      GLfloat *floatParamPtr)
  1467     MOZ_ASSERT(intParamPtr || floatParamPtr);
  1469     if (IsContextLost())
  1470         return;
  1472     GLint intParam = intParamPtr ? *intParamPtr : GLint(*floatParamPtr);
  1473     GLfloat floatParam = floatParamPtr ? *floatParamPtr : GLfloat(*intParamPtr);
  1475     if (!ValidateTextureTargetEnum(target, "texParameter: target"))
  1476         return;
  1478     WebGLTexture *tex = activeBoundTextureForTarget(target);
  1479     if (!tex)
  1480         return ErrorInvalidOperation("texParameter: no texture is bound to this target");
  1482     bool pnameAndParamAreIncompatible = false;
  1483     bool paramValueInvalid = false;
  1485     switch (pname) {
  1486         case LOCAL_GL_TEXTURE_MIN_FILTER:
  1487             switch (intParam) {
  1488                 case LOCAL_GL_NEAREST:
  1489                 case LOCAL_GL_LINEAR:
  1490                 case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
  1491                 case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
  1492                 case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
  1493                 case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
  1494                     tex->SetMinFilter(intParam);
  1495                     break;
  1496                 default:
  1497                     pnameAndParamAreIncompatible = true;
  1499             break;
  1500         case LOCAL_GL_TEXTURE_MAG_FILTER:
  1501             switch (intParam) {
  1502                 case LOCAL_GL_NEAREST:
  1503                 case LOCAL_GL_LINEAR:
  1504                     tex->SetMagFilter(intParam);
  1505                     break;
  1506                 default:
  1507                     pnameAndParamAreIncompatible = true;
  1509             break;
  1510         case LOCAL_GL_TEXTURE_WRAP_S:
  1511             switch (intParam) {
  1512                 case LOCAL_GL_CLAMP_TO_EDGE:
  1513                 case LOCAL_GL_MIRRORED_REPEAT:
  1514                 case LOCAL_GL_REPEAT:
  1515                     tex->SetWrapS(intParam);
  1516                     break;
  1517                 default:
  1518                     pnameAndParamAreIncompatible = true;
  1520             break;
  1521         case LOCAL_GL_TEXTURE_WRAP_T:
  1522             switch (intParam) {
  1523                 case LOCAL_GL_CLAMP_TO_EDGE:
  1524                 case LOCAL_GL_MIRRORED_REPEAT:
  1525                 case LOCAL_GL_REPEAT:
  1526                     tex->SetWrapT(intParam);
  1527                     break;
  1528                 default:
  1529                     pnameAndParamAreIncompatible = true;
  1531             break;
  1532         case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  1533             if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
  1534                 if (floatParamPtr && floatParam < 1.f)
  1535                     paramValueInvalid = true;
  1536                 else if (intParamPtr && intParam < 1)
  1537                     paramValueInvalid = true;
  1539             else
  1540                 pnameAndParamAreIncompatible = true;
  1541             break;
  1542         default:
  1543             return ErrorInvalidEnumInfo("texParameter: pname", pname);
  1546     if (pnameAndParamAreIncompatible) {
  1547         if (intParamPtr)
  1548             return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
  1549                                     pname, intParam, intParam);
  1550         else
  1551             return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
  1552                                     pname, floatParam);
  1553     } else if (paramValueInvalid) {
  1554         if (intParamPtr)
  1555             return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
  1556                                     pname, intParam, intParam);
  1557         else
  1558             return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
  1559                                     pname, floatParam);
  1562     MakeContextCurrent();
  1563     if (intParamPtr)
  1564         gl->fTexParameteri(target, pname, intParam);
  1565     else
  1566         gl->fTexParameterf(target, pname, floatParam);
  1569 JS::Value
  1570 WebGLContext::GetTexParameter(GLenum target, GLenum pname)
  1572     if (IsContextLost())
  1573         return JS::NullValue();
  1575     MakeContextCurrent();
  1577     if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
  1578         return JS::NullValue();
  1580     if (!activeBoundTextureForTarget(target)) {
  1581         ErrorInvalidOperation("getTexParameter: no texture bound");
  1582         return JS::NullValue();
  1585     switch (pname) {
  1586         case LOCAL_GL_TEXTURE_MIN_FILTER:
  1587         case LOCAL_GL_TEXTURE_MAG_FILTER:
  1588         case LOCAL_GL_TEXTURE_WRAP_S:
  1589         case LOCAL_GL_TEXTURE_WRAP_T:
  1591             GLint i = 0;
  1592             gl->fGetTexParameteriv(target, pname, &i);
  1593             return JS::NumberValue(uint32_t(i));
  1595         case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
  1596             if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
  1597                 GLfloat f = 0.f;
  1598                 gl->fGetTexParameterfv(target, pname, &f);
  1599                 return JS::DoubleValue(f);
  1602             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
  1603             break;
  1605         default:
  1606             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
  1609     return JS::NullValue();
  1612 JS::Value
  1613 WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
  1614                          WebGLUniformLocation *location)
  1616     if (IsContextLost())
  1617         return JS::NullValue();
  1619     if (!ValidateObject("getUniform: program", prog))
  1620         return JS::NullValue();
  1622     if (!ValidateObject("getUniform: location", location))
  1623         return JS::NullValue();
  1625     if (location->Program() != prog) {
  1626         ErrorInvalidValue("getUniform: this uniform location corresponds to another program");
  1627         return JS::NullValue();
  1630     if (location->ProgramGeneration() != prog->Generation()) {
  1631         ErrorInvalidOperation("getUniform: this uniform location is obsolete since the program has been relinked");
  1632         return JS::NullValue();
  1635     GLuint progname = prog->GLName();
  1637     MakeContextCurrent();
  1639     GLint uniforms = 0;
  1640     GLint uniformNameMaxLength = 0;
  1641     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms);
  1642     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength);
  1644     // we now need the type info to switch between fGetUniformfv and fGetUniformiv
  1645     // the only way to get that is to iterate through all active uniforms by index until
  1646     // one matches the given uniform location.
  1647     GLenum uniformType = 0;
  1648     nsAutoArrayPtr<GLchar> uniformName(new GLchar[uniformNameMaxLength]);
  1649     // this buffer has 16 more bytes to be able to store [index] at the end.
  1650     nsAutoArrayPtr<GLchar> uniformNameBracketIndex(new GLchar[uniformNameMaxLength + 16]);
  1652     GLint index;
  1653     for (index = 0; index < uniforms; ++index) {
  1654         GLsizei length;
  1655         GLint size;
  1656         gl->fGetActiveUniform(progname, index, uniformNameMaxLength, &length,
  1657                               &size, &uniformType, uniformName);
  1658         if (gl->fGetUniformLocation(progname, uniformName) == location->Location())
  1659             break;
  1661         // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size'
  1662         // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above,
  1663         // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]".
  1664         if (size > 1) {
  1665             bool found_it = false;
  1666             if (uniformName[length - 1] == ']') { // if uniformName ends in [0]
  1667                 // remove the [0] at the end
  1668                 length -= 3;
  1669                 uniformName[length] = 0;
  1671             for (GLint arrayIndex = 1; arrayIndex < size; arrayIndex++) {
  1672                 sprintf(uniformNameBracketIndex.get(), "%s[%d]", uniformName.get(), arrayIndex);
  1673                 if (gl->fGetUniformLocation(progname, uniformNameBracketIndex) == location->Location()) {
  1674                     found_it = true;
  1675                     break;
  1678             if (found_it) break;
  1682     if (index == uniforms) {
  1683         GenerateWarning("getUniform: internal error: hit an OpenGL driver bug");
  1684         return JS::NullValue();
  1687     GLenum baseType;
  1688     GLint unitSize;
  1689     if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize)) {
  1690         GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType);
  1691         return JS::NullValue();
  1694     // this should never happen
  1695     if (unitSize > 16) {
  1696         GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize);
  1697         return JS::NullValue();
  1700     if (baseType == LOCAL_GL_FLOAT) {
  1701         GLfloat fv[16] = { GLfloat(0) };
  1702         gl->fGetUniformfv(progname, location->Location(), fv);
  1703         if (unitSize == 1) {
  1704             return JS::DoubleValue(fv[0]);
  1705         } else {
  1706             JSObject* obj = Float32Array::Create(cx, this, unitSize, fv);
  1707             if (!obj) {
  1708                 ErrorOutOfMemory("getUniform: out of memory");
  1709                 return JS::NullValue();
  1711             return JS::ObjectOrNullValue(obj);
  1713     } else if (baseType == LOCAL_GL_INT) {
  1714         GLint iv[16] = { 0 };
  1715         gl->fGetUniformiv(progname, location->Location(), iv);
  1716         if (unitSize == 1) {
  1717             return JS::Int32Value(iv[0]);
  1718         } else {
  1719             JSObject* obj = Int32Array::Create(cx, this, unitSize, iv);
  1720             if (!obj) {
  1721                 ErrorOutOfMemory("getUniform: out of memory");
  1722                 return JS::NullValue();
  1724             return JS::ObjectOrNullValue(obj);
  1726     } else if (baseType == LOCAL_GL_BOOL) {
  1727         GLint iv[16] = { 0 };
  1728         gl->fGetUniformiv(progname, location->Location(), iv);
  1729         if (unitSize == 1) {
  1730             return JS::BooleanValue(iv[0] ? true : false);
  1731         } else {
  1732             bool uv[16];
  1733             for (int k = 0; k < unitSize; k++)
  1734                 uv[k] = iv[k];
  1735             JS::Rooted<JS::Value> val(cx);
  1736             // Be careful: we don't want to convert all of |uv|!
  1737             if (!ToJSValue(cx, uv, unitSize, &val)) {
  1738                 ErrorOutOfMemory("getUniform: out of memory");
  1739                 return JS::NullValue();
  1741             return val;
  1745     // Else preserving behavior, but I'm not sure this is correct per spec
  1746     return JS::UndefinedValue();
  1749 already_AddRefed<WebGLUniformLocation>
  1750 WebGLContext::GetUniformLocation(WebGLProgram *prog, const nsAString& name)
  1752     if (IsContextLost())
  1753         return nullptr;
  1755     if (!ValidateObject("getUniformLocation: program", prog))
  1756         return nullptr;
  1758     if (!ValidateGLSLVariableName(name, "getUniformLocation"))
  1759         return nullptr;
  1761     NS_LossyConvertUTF16toASCII cname(name);
  1762     nsCString mappedName;
  1763     prog->MapIdentifier(cname, &mappedName);
  1765     GLuint progname = prog->GLName();
  1766     MakeContextCurrent();
  1767     GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
  1769     nsRefPtr<WebGLUniformLocation> loc;
  1770     if (intlocation >= 0) {
  1771         WebGLUniformInfo info = prog->GetUniformInfoForMappedIdentifier(mappedName);
  1772         loc = new WebGLUniformLocation(this,
  1773                                        prog,
  1774                                        intlocation,
  1775                                        info);
  1777     return loc.forget();
  1780 void
  1781 WebGLContext::Hint(GLenum target, GLenum mode)
  1783     if (IsContextLost())
  1784         return;
  1786     bool isValid = false;
  1788     switch (target) {
  1789         case LOCAL_GL_GENERATE_MIPMAP_HINT:
  1790             isValid = true;
  1791             break;
  1792         case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
  1793             if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
  1794                 isValid = true;
  1795             break;
  1798     if (!isValid)
  1799         return ErrorInvalidEnum("hint: invalid hint");
  1801     MakeContextCurrent();
  1802     gl->fHint(target, mode);
  1805 bool
  1806 WebGLContext::IsFramebuffer(WebGLFramebuffer *fb)
  1808     if (IsContextLost())
  1809         return false;
  1811     return ValidateObjectAllowDeleted("isFramebuffer", fb) &&
  1812         !fb->IsDeleted() &&
  1813         fb->HasEverBeenBound();
  1816 bool
  1817 WebGLContext::IsProgram(WebGLProgram *prog)
  1819     if (IsContextLost())
  1820         return false;
  1822     return ValidateObjectAllowDeleted("isProgram", prog) && !prog->IsDeleted();
  1825 bool
  1826 WebGLContext::IsRenderbuffer(WebGLRenderbuffer *rb)
  1828     if (IsContextLost())
  1829         return false;
  1831     return ValidateObjectAllowDeleted("isRenderBuffer", rb) &&
  1832         !rb->IsDeleted() &&
  1833         rb->HasEverBeenBound();
  1836 bool
  1837 WebGLContext::IsShader(WebGLShader *shader)
  1839     if (IsContextLost())
  1840         return false;
  1842     return ValidateObjectAllowDeleted("isShader", shader) &&
  1843         !shader->IsDeleted();
  1846 bool
  1847 WebGLContext::IsTexture(WebGLTexture *tex)
  1849     if (IsContextLost())
  1850         return false;
  1852     return ValidateObjectAllowDeleted("isTexture", tex) &&
  1853         !tex->IsDeleted() &&
  1854         tex->HasEverBeenBound();
  1857 // Try to bind an attribute that is an array to location 0:
  1858 bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram *program)
  1860     if (mBoundVertexArray->IsAttribArrayEnabled(0)) {
  1861         return false;
  1864     GLint leastArrayLocation = -1;
  1866     std::map<GLint, nsCString>::iterator itr;
  1867     for (itr = program->mActiveAttribMap.begin();
  1868          itr != program->mActiveAttribMap.end();
  1869          itr++) {
  1870         int32_t index = itr->first;
  1871         if (mBoundVertexArray->IsAttribArrayEnabled(index) &&
  1872             index < leastArrayLocation)
  1874             leastArrayLocation = index;
  1878     if (leastArrayLocation > 0) {
  1879         nsCString& attrName = program->mActiveAttribMap.find(leastArrayLocation)->second;
  1880         const char* attrNameCStr = attrName.get();
  1881         gl->fBindAttribLocation(program->GLName(), 0, attrNameCStr);
  1882         return true;
  1884     return false;
  1887 void
  1888 WebGLContext::LinkProgram(WebGLProgram *program)
  1890     if (IsContextLost())
  1891         return;
  1893     if (!ValidateObject("linkProgram", program))
  1894         return;
  1896     InvalidateBufferFetching(); // we do it early in this function
  1897     // as some of the validation below changes program state
  1899     GLuint progname = program->GLName();
  1901     if (!program->NextGeneration()) {
  1902         // XXX throw?
  1903         return;
  1906     if (!program->HasBothShaderTypesAttached()) {
  1907         GenerateWarning("linkProgram: this program doesn't have both a vertex shader"
  1908                         " and a fragment shader");
  1909         program->SetLinkStatus(false);
  1910         return;
  1913     // bug 777028
  1914     // Mesa can't handle more than 16 samplers per program, counting each array entry.
  1915     if (gl->WorkAroundDriverBugs() &&
  1916         mIsMesa &&
  1917         program->UpperBoundNumSamplerUniforms() > 16)
  1919         GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers " "to avoid a Mesa crasher.");
  1920         program->SetLinkStatus(false);
  1921         return;
  1924     bool updateInfoSucceeded = false;
  1925     GLint ok = 0;
  1926     if (gl->WorkAroundDriverBugs() &&
  1927         program->HasBadShaderAttached())
  1929         // it's a common driver bug, caught by program-test.html, that linkProgram doesn't
  1930         // correctly preserve the state of an in-use program that has been attached a bad shader
  1931         // see bug 777883
  1932         ok = false;
  1933     } else {
  1934         MakeContextCurrent();
  1935         gl->fLinkProgram(progname);
  1936         gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
  1938         if (ok) {
  1939             updateInfoSucceeded = program->UpdateInfo();
  1940             program->SetLinkStatus(updateInfoSucceeded);
  1942             if (BindArrayAttribToLocation0(program)) {
  1943                 GenerateWarning("linkProgram: relinking program to make attrib0 an "
  1944                                 "array.");
  1945                 gl->fLinkProgram(progname);
  1946                 gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
  1947                 if (ok) {
  1948                     updateInfoSucceeded = program->UpdateInfo();
  1949                     program->SetLinkStatus(updateInfoSucceeded);
  1955     if (ok) {
  1956         // Bug 750527
  1957         if (gl->WorkAroundDriverBugs() &&
  1958             updateInfoSucceeded &&
  1959             gl->Vendor() == gl::GLVendor::NVIDIA)
  1961             if (program == mCurrentProgram)
  1962                 gl->fUseProgram(progname);
  1964     } else {
  1965         program->SetLinkStatus(false);
  1967         if (ShouldGenerateWarnings()) {
  1969             // report shader/program infoLogs as warnings.
  1970             // note that shader compilation errors can be deferred to linkProgram,
  1971             // which is why we can't do anything in compileShader. In practice we could
  1972             // report in compileShader the translation errors generated by ANGLE,
  1973             // but it seems saner to keep a single way of obtaining shader infologs.
  1975             nsAutoCString log;
  1977             bool alreadyReportedShaderInfoLog = false;
  1979             for (size_t i = 0; i < program->AttachedShaders().Length(); i++) {
  1981                 WebGLShader* shader = program->AttachedShaders()[i];
  1983                 if (shader->CompileStatus())
  1984                     continue;
  1986                 const char *shaderTypeName = nullptr;
  1987                 if (shader->ShaderType() == LOCAL_GL_VERTEX_SHADER) {
  1988                     shaderTypeName = "vertex";
  1989                 } else if (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) {
  1990                     shaderTypeName = "fragment";
  1991                 } else {
  1992                     // should have been validated earlier
  1993                     MOZ_ASSERT(false);
  1994                     shaderTypeName = "<unknown>";
  1997                 GetShaderInfoLog(shader, log);
  1999                 GenerateWarning("linkProgram: a %s shader used in this program failed to "
  2000                                 "compile, with this log:\n%s\n",
  2001                                 shaderTypeName,
  2002                                 log.get());
  2003                 alreadyReportedShaderInfoLog = true;
  2006             if (!alreadyReportedShaderInfoLog) {
  2007                 GetProgramInfoLog(program, log);
  2008                 if (!log.IsEmpty()) {
  2009                     GenerateWarning("linkProgram failed, with this log:\n%s\n",
  2010                                     log.get());
  2017 void
  2018 WebGLContext::PixelStorei(GLenum pname, GLint param)
  2020     if (IsContextLost())
  2021         return;
  2023     switch (pname) {
  2024         case UNPACK_FLIP_Y_WEBGL:
  2025             mPixelStoreFlipY = (param != 0);
  2026             break;
  2027         case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
  2028             mPixelStorePremultiplyAlpha = (param != 0);
  2029             break;
  2030         case UNPACK_COLORSPACE_CONVERSION_WEBGL:
  2031             if (param == LOCAL_GL_NONE || param == BROWSER_DEFAULT_WEBGL)
  2032                 mPixelStoreColorspaceConversion = param;
  2033             else
  2034                 return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param);
  2035             break;
  2036         case LOCAL_GL_PACK_ALIGNMENT:
  2037         case LOCAL_GL_UNPACK_ALIGNMENT:
  2038             if (param != 1 &&
  2039                 param != 2 &&
  2040                 param != 4 &&
  2041                 param != 8)
  2042                 return ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
  2043             if (pname == LOCAL_GL_PACK_ALIGNMENT)
  2044                 mPixelStorePackAlignment = param;
  2045             else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
  2046                 mPixelStoreUnpackAlignment = param;
  2047             MakeContextCurrent();
  2048             gl->fPixelStorei(pname, param);
  2049             break;
  2050         default:
  2051             return ErrorInvalidEnumInfo("pixelStorei: parameter", pname);
  2055 void
  2056 WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
  2057                          GLsizei height, GLenum format,
  2058                          GLenum type, const Nullable<ArrayBufferView> &pixels,
  2059                          ErrorResult& rv)
  2061     if (IsContextLost())
  2062         return;
  2064     if (mCanvasElement->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
  2065         GenerateWarning("readPixels: Not allowed");
  2066         return rv.Throw(NS_ERROR_DOM_SECURITY_ERR);
  2069     if (width < 0 || height < 0)
  2070         return ErrorInvalidValue("readPixels: negative size passed");
  2072     if (pixels.IsNull())
  2073         return ErrorInvalidValue("readPixels: null destination buffer");
  2075     const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
  2076     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
  2077     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
  2079     uint32_t channels = 0;
  2081     // Check the format param
  2082     switch (format) {
  2083         case LOCAL_GL_ALPHA:
  2084             channels = 1;
  2085             break;
  2086         case LOCAL_GL_RGB:
  2087             channels = 3;
  2088             break;
  2089         case LOCAL_GL_RGBA:
  2090             channels = 4;
  2091             break;
  2092         default:
  2093             return ErrorInvalidEnum("readPixels: Bad format");
  2096     uint32_t bytesPerPixel = 0;
  2097     int requiredDataType = 0;
  2099     // Check the type param
  2100     bool isReadTypeValid = false;
  2101     bool isReadTypeFloat = false;
  2102     switch (type) {
  2103         case LOCAL_GL_UNSIGNED_BYTE:
  2104             isReadTypeValid = true;
  2105             bytesPerPixel = 1*channels;
  2106             requiredDataType = js::ArrayBufferView::TYPE_UINT8;
  2107             break;
  2108         case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  2109         case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  2110         case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  2111             isReadTypeValid = true;
  2112             bytesPerPixel = 2;
  2113             requiredDataType = js::ArrayBufferView::TYPE_UINT16;
  2114             break;
  2115         case LOCAL_GL_FLOAT:
  2116             if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
  2117                 IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
  2119                 isReadTypeValid = true;
  2120                 isReadTypeFloat = true;
  2121                 bytesPerPixel = 4*channels;
  2122                 requiredDataType = js::ArrayBufferView::TYPE_FLOAT32;
  2124             break;
  2126     if (!isReadTypeValid)
  2127         return ErrorInvalidEnum("readPixels: Bad type", type);
  2129     const ArrayBufferView& pixbuf = pixels.Value();
  2130     int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
  2132     // Check the pixels param type
  2133     if (dataType != requiredDataType)
  2134         return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
  2136     // Check the pixels param size
  2137     CheckedUint32 checked_neededByteLength =
  2138         GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
  2140     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
  2142     CheckedUint32 checked_alignedRowSize =
  2143         RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
  2145     if (!checked_neededByteLength.isValid())
  2146         return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
  2148     // Compute length and data.  Don't reenter after this point, lest the
  2149     // precomputed go out of sync with the instant length/data.
  2150     pixbuf.ComputeLengthAndData();
  2152     uint32_t dataByteLen = pixbuf.Length();
  2153     if (checked_neededByteLength.value() > dataByteLen)
  2154         return ErrorInvalidOperation("readPixels: buffer too small");
  2156     void* data = pixbuf.Data();
  2157     if (!data) {
  2158         ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
  2159         return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
  2162     bool isSourceTypeFloat = false;
  2163     if (mBoundFramebuffer &&
  2164         mBoundFramebuffer->ColorAttachmentCount() &&
  2165         mBoundFramebuffer->ColorAttachment(0).IsDefined())
  2167         isSourceTypeFloat = mBoundFramebuffer->ColorAttachment(0).IsReadableFloat();
  2170     if (isReadTypeFloat != isSourceTypeFloat)
  2171         return ErrorInvalidOperation("readPixels: Invalid type floatness");
  2173     // Check the format and type params to assure they are an acceptable pair (as per spec)
  2174     switch (format) {
  2175         case LOCAL_GL_RGBA: {
  2176             switch (type) {
  2177                 case LOCAL_GL_UNSIGNED_BYTE:
  2178                     break;
  2179                 case LOCAL_GL_FLOAT:
  2180                     break;
  2181                 default:
  2182                     return ErrorInvalidOperation("readPixels: Invalid format/type pair");
  2184             break;
  2186         default:
  2187             return ErrorInvalidOperation("readPixels: Invalid format/type pair");
  2190     MakeContextCurrent();
  2192     if (mBoundFramebuffer) {
  2193         // prevent readback of arbitrary video memory through uninitialized renderbuffers!
  2194         if (!mBoundFramebuffer->CheckAndInitializeAttachments())
  2195             return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
  2197         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
  2198         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
  2199             return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
  2200                                          " correct color/depth/stencil type.");
  2202     } else {
  2203       ClearBackbufferIfNeeded();
  2205     // Now that the errors are out of the way, on to actually reading
  2207     // If we won't be reading any pixels anyways, just skip the actual reading
  2208     if (width == 0 || height == 0)
  2209         return DummyFramebufferOperation("readPixels");
  2211     if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
  2212         // the easy case: we're not reading out-of-range pixels
  2213         gl->fReadPixels(x, y, width, height, format, type, data);
  2214     } else {
  2215         // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
  2216         // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
  2217         // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
  2218         // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
  2219         // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
  2220         // to accomodate the potentially different strides (widths).
  2222         // Zero the whole pixel dest area in the destination buffer.
  2223         memset(data, 0, checked_neededByteLength.value());
  2225         if (   x >= framebufferWidth
  2226             || x+width <= 0
  2227             || y >= framebufferHeight
  2228             || y+height <= 0)
  2230             // we are completely outside of range, can exit now with buffer filled with zeros
  2231             return DummyFramebufferOperation("readPixels");
  2234         // compute the parameters of the subrect we're actually going to call glReadPixels on
  2235         GLint   subrect_x      = std::max(x, 0);
  2236         GLint   subrect_end_x  = std::min(x+width, framebufferWidth);
  2237         GLsizei subrect_width  = subrect_end_x - subrect_x;
  2239         GLint   subrect_y      = std::max(y, 0);
  2240         GLint   subrect_end_y  = std::min(y+height, framebufferHeight);
  2241         GLsizei subrect_height = subrect_end_y - subrect_y;
  2243         if (subrect_width < 0 || subrect_height < 0 ||
  2244             subrect_width > width || subrect_height > height)
  2245             return ErrorInvalidOperation("readPixels: integer overflow computing clipped rect size");
  2247         // now we know that subrect_width is in the [0..width] interval, and same for heights.
  2249         // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
  2250         // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
  2251         uint32_t subrect_plainRowSize = subrect_width * bytesPerPixel;
  2252     // There are checks above to ensure that this doesn't overflow.
  2253         uint32_t subrect_alignedRowSize =
  2254             RoundedToNextMultipleOf(subrect_plainRowSize, mPixelStorePackAlignment).value();
  2255         uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize;
  2257         // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
  2258         GLubyte *subrect_data = new GLubyte[subrect_byteLength];
  2259         gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height, format, type, subrect_data);
  2261         // notice that this for loop terminates because we already checked that subrect_height is at most height
  2262         for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
  2263             GLint subrect_x_in_dest_buffer = subrect_x - x;
  2264             GLint subrect_y_in_dest_buffer = subrect_y - y;
  2265             memcpy(static_cast<GLubyte*>(data)
  2266                      + checked_alignedRowSize.value() * (subrect_y_in_dest_buffer + y_inside_subrect)
  2267                      + bytesPerPixel * subrect_x_in_dest_buffer, // destination
  2268                    subrect_data + subrect_alignedRowSize * y_inside_subrect, // source
  2269                    subrect_plainRowSize); // size
  2271         delete [] subrect_data;
  2274     // if we're reading alpha, we may need to do fixup.  Note that we don't allow
  2275     // GL_ALPHA to readpixels currently, but we had the code written for it already.
  2276     if (format == LOCAL_GL_ALPHA ||
  2277         format == LOCAL_GL_RGBA)
  2279         bool needAlphaFixup;
  2280         if (mBoundFramebuffer) {
  2281             needAlphaFixup = !mBoundFramebuffer->ColorAttachment(0).HasAlpha();
  2282         } else {
  2283             needAlphaFixup = gl->GetPixelFormat().alpha == 0;
  2286         if (needAlphaFixup) {
  2287             if (format == LOCAL_GL_ALPHA && type == LOCAL_GL_UNSIGNED_BYTE) {
  2288                 // this is easy; it's an 0xff memset per row
  2289                 uint8_t *row = static_cast<uint8_t*>(data);
  2290                 for (GLint j = 0; j < height; ++j) {
  2291                     memset(row, 0xff, checked_plainRowSize.value());
  2292                     row += checked_alignedRowSize.value();
  2294             } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_UNSIGNED_BYTE) {
  2295                 // this is harder, we need to just set the alpha byte here
  2296                 uint8_t *row = static_cast<uint8_t*>(data);
  2297                 for (GLint j = 0; j < height; ++j) {
  2298                     uint8_t *rowp = row;
  2299 #if MOZ_LITTLE_ENDIAN
  2300                     // offset to get the alpha byte; we're always going to
  2301                     // move by 4 bytes
  2302                     rowp += 3;
  2303 #endif
  2304                     uint8_t *endrowp = rowp + 4 * width;
  2305                     while (rowp != endrowp) {
  2306                         *rowp = 0xff;
  2307                         rowp += 4;
  2310                     row += checked_alignedRowSize.value();
  2312             } else if (format == LOCAL_GL_RGBA && type == LOCAL_GL_FLOAT) {
  2313                 float* row = static_cast<float*>(data);
  2315                 for (GLint j = 0; j < height; ++j) {
  2316                     float* pAlpha = row + 3;
  2317                     float* pAlphaEnd = pAlpha + 4*width;
  2319                     while (pAlpha != pAlphaEnd) {
  2320                         *pAlpha = 1.0f;
  2321                         pAlpha += 4;
  2324                     row += checked_alignedRowSize.value();
  2326             } else {
  2327                 NS_WARNING("Unhandled case, how'd we get here?");
  2328                 return rv.Throw(NS_ERROR_FAILURE);
  2334 void
  2335 WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
  2337     if (IsContextLost())
  2338         return;
  2340     if (!mBoundRenderbuffer)
  2341         return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
  2343     if (target != LOCAL_GL_RENDERBUFFER)
  2344         return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
  2346     if (width < 0 || height < 0)
  2347         return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
  2349     if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize)
  2350         return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size");
  2352     // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
  2353     GLenum internalformatForGL = internalformat;
  2355     switch (internalformat) {
  2356     case LOCAL_GL_RGBA4:
  2357     case LOCAL_GL_RGB5_A1:
  2358         // 16-bit RGBA formats are not supported on desktop GL
  2359         if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
  2360         break;
  2361     case LOCAL_GL_RGB565:
  2362         // the RGB565 format is not supported on desktop GL
  2363         if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
  2364         break;
  2365     case LOCAL_GL_DEPTH_COMPONENT16:
  2366         if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
  2367             internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
  2368         else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
  2369             internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
  2370         break;
  2371     case LOCAL_GL_STENCIL_INDEX8:
  2372         break;
  2373     case LOCAL_GL_DEPTH_STENCIL:
  2374         // We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
  2375         internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
  2376         break;
  2377     case LOCAL_GL_SRGB8_ALPHA8_EXT:
  2378         break;
  2379     case LOCAL_GL_RGB16F:
  2380     case LOCAL_GL_RGBA16F: {
  2381         bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
  2382                              IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float);
  2383         if (!hasExtensions)
  2384             return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
  2385         break;
  2387     case LOCAL_GL_RGB32F:
  2388     case LOCAL_GL_RGBA32F: {
  2389         bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
  2390                              IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float);
  2391         if (!hasExtensions)
  2392             return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target);
  2393         break;
  2395     default:
  2396         return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
  2399     MakeContextCurrent();
  2401     bool sizeChanges = width != mBoundRenderbuffer->Width() ||
  2402                        height != mBoundRenderbuffer->Height() ||
  2403                        internalformat != mBoundRenderbuffer->InternalFormat();
  2404     if (sizeChanges) {
  2405         // Invalidate framebuffer status cache
  2406         mBoundRenderbuffer->NotifyFBsStatusChanged();
  2407         GetAndFlushUnderlyingGLErrors();
  2408         mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
  2409         GLenum error = GetAndFlushUnderlyingGLErrors();
  2410         if (error) {
  2411             GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
  2412             return;
  2414     } else {
  2415         mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
  2418     mBoundRenderbuffer->SetInternalFormat(internalformat);
  2419     mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
  2420     mBoundRenderbuffer->setDimensions(width, height);
  2421     mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
  2424 void
  2425 WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
  2427     if (IsContextLost())
  2428         return;
  2430     if (width < 0 || height < 0)
  2431         return ErrorInvalidValue("scissor: negative size");
  2433     MakeContextCurrent();
  2434     gl->fScissor(x, y, width, height);
  2437 void
  2438 WebGLContext::StencilFunc(GLenum func, GLint ref, GLuint mask)
  2440     if (IsContextLost())
  2441         return;
  2443     if (!ValidateComparisonEnum(func, "stencilFunc: func"))
  2444         return;
  2446     mStencilRefFront = ref;
  2447     mStencilRefBack = ref;
  2448     mStencilValueMaskFront = mask;
  2449     mStencilValueMaskBack = mask;
  2451     MakeContextCurrent();
  2452     gl->fStencilFunc(func, ref, mask);
  2455 void
  2456 WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
  2458     if (IsContextLost())
  2459         return;
  2461     if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
  2462         !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
  2463         return;
  2465     switch (face) {
  2466         case LOCAL_GL_FRONT_AND_BACK:
  2467             mStencilRefFront = ref;
  2468             mStencilRefBack = ref;
  2469             mStencilValueMaskFront = mask;
  2470             mStencilValueMaskBack = mask;
  2471             break;
  2472         case LOCAL_GL_FRONT:
  2473             mStencilRefFront = ref;
  2474             mStencilValueMaskFront = mask;
  2475             break;
  2476         case LOCAL_GL_BACK:
  2477             mStencilRefBack = ref;
  2478             mStencilValueMaskBack = mask;
  2479             break;
  2482     MakeContextCurrent();
  2483     gl->fStencilFuncSeparate(face, func, ref, mask);
  2486 void
  2487 WebGLContext::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
  2489     if (IsContextLost())
  2490         return;
  2492     if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
  2493         !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
  2494         !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
  2495         return;
  2497     MakeContextCurrent();
  2498     gl->fStencilOp(sfail, dpfail, dppass);
  2501 void
  2502 WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
  2504     if (IsContextLost())
  2505         return;
  2507     if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
  2508         !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
  2509         !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
  2510         !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
  2511         return;
  2513     MakeContextCurrent();
  2514     gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
  2517 nsresult
  2518 WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
  2519                                                      RefPtr<DataSourceSurface>& imageOut, WebGLTexelFormat *format)
  2521    *format = WebGLTexelFormat::None;
  2523     if (!res.mSourceSurface)
  2524         return NS_OK;
  2525     RefPtr<DataSourceSurface> data = res.mSourceSurface->GetDataSurface();
  2526     if (!data) {
  2527         // SurfaceFromElement lied!
  2528         return NS_OK;
  2531     if (!mPixelStorePremultiplyAlpha && res.mIsPremultiplied) {
  2532       data = gfxUtils::UnpremultiplyDataSurface(data);
  2535     // We disallow loading cross-domain images and videos that have not been validated
  2536     // with CORS as WebGL textures. The reason for doing that is that timing
  2537     // attacks on WebGL shaders are able to retrieve approximations of the
  2538     // pixel values in WebGL textures; see bug 655987.
  2539     //
  2540     // To prevent a loophole where a Canvas2D would be used as a proxy to load
  2541     // cross-domain textures, we also disallow loading textures from write-only
  2542     // Canvas2D's.
  2544     // part 1: check that the DOM element is same-origin, or has otherwise been
  2545     // validated for cross-domain use.
  2546     if (!res.mCORSUsed) {
  2547         bool subsumes;
  2548         nsresult rv = mCanvasElement->NodePrincipal()->Subsumes(res.mPrincipal, &subsumes);
  2549         if (NS_FAILED(rv) || !subsumes) {
  2550             GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
  2551                                 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
  2552             return NS_ERROR_DOM_SECURITY_ERR;
  2556     // part 2: if the DOM element is write-only, it might contain
  2557     // cross-domain image data.
  2558     if (res.mIsWriteOnly) {
  2559         GenerateWarning("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
  2560                         "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
  2561                         "when a cross-domain image is drawn on it. "
  2562                         "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
  2563         return NS_ERROR_DOM_SECURITY_ERR;
  2566     // End of security checks, now we should be safe regarding cross-domain images
  2567     // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
  2568     // texture sources in the first place.
  2570     switch (data->GetFormat()) {
  2571         case SurfaceFormat::B8G8R8A8:
  2572             *format = WebGLTexelFormat::BGRA8; // careful, our ARGB means BGRA
  2573             break;
  2574         case SurfaceFormat::B8G8R8X8:
  2575             *format = WebGLTexelFormat::BGRX8; // careful, our RGB24 is not tightly packed. Whence BGRX8.
  2576             break;
  2577         case SurfaceFormat::A8:
  2578             *format = WebGLTexelFormat::A8;
  2579             break;
  2580         case SurfaceFormat::R5G6B5:
  2581             *format = WebGLTexelFormat::RGB565;
  2582             break;
  2583         default:
  2584             NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
  2585             return NS_ERROR_NOT_IMPLEMENTED;
  2588     imageOut = data;
  2590     return NS_OK;
  2595 void
  2596 WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
  2598     GLint location;
  2599     if (!ValidateUniformSetter("Uniform1i", location_object, location))
  2600         return;
  2602     // Only uniform1i can take sampler settings.
  2603     if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
  2604         return;
  2606     MakeContextCurrent();
  2607     gl->fUniform1i(location, a1);
  2610 void
  2611 WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
  2612                         GLint a2)
  2614     GLint location;
  2615     if (!ValidateUniformSetter("Uniform2i", location_object, location))
  2616         return;
  2618     MakeContextCurrent();
  2619     gl->fUniform2i(location, a1, a2);
  2622 void
  2623 WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
  2624                         GLint a2, GLint a3)
  2626     GLint location;
  2627     if (!ValidateUniformSetter("Uniform3i", location_object, location))
  2628         return;
  2630     MakeContextCurrent();
  2631     gl->fUniform3i(location, a1, a2, a3);
  2634 void
  2635 WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
  2636                         GLint a2, GLint a3, GLint a4)
  2638     GLint location;
  2639     if (!ValidateUniformSetter("Uniform4i", location_object, location))
  2640         return;
  2642     MakeContextCurrent();
  2643     gl->fUniform4i(location, a1, a2, a3, a4);
  2646 void
  2647 WebGLContext::Uniform1f(WebGLUniformLocation *location_object, GLfloat a1)
  2649     GLint location;
  2650     if (!ValidateUniformSetter("Uniform1f", location_object, location))
  2651         return;
  2652     MakeContextCurrent();
  2653     gl->fUniform1f(location, a1);
  2656 void
  2657 WebGLContext::Uniform2f(WebGLUniformLocation *location_object, GLfloat a1,
  2658                         GLfloat a2)
  2660     GLint location;
  2661     if (!ValidateUniformSetter("Uniform2f", location_object, location))
  2662         return;
  2663     MakeContextCurrent();
  2664     gl->fUniform2f(location, a1, a2);
  2667 void
  2668 WebGLContext::Uniform3f(WebGLUniformLocation *location_object, GLfloat a1,
  2669                         GLfloat a2, GLfloat a3)
  2671     GLint location;
  2672     if (!ValidateUniformSetter("Uniform3f", location_object, location))
  2673         return;
  2674     MakeContextCurrent();
  2675     gl->fUniform3f(location, a1, a2, a3);
  2678 void
  2679 WebGLContext::Uniform4f(WebGLUniformLocation *location_object, GLfloat a1,
  2680                         GLfloat a2, GLfloat a3, GLfloat a4)
  2682     GLint location;
  2683     if (!ValidateUniformSetter("Uniform4f", location_object, location))
  2684         return;
  2685     MakeContextCurrent();
  2686     gl->fUniform4f(location, a1, a2, a3, a4);
  2689 void
  2690 WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object,
  2691                               uint32_t arrayLength, const GLint* data)
  2693     uint32_t numElementsToUpload;
  2694     GLint location;
  2695     if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location,
  2696                                     numElementsToUpload, arrayLength)) {
  2697         return;
  2700     if (!ValidateSamplerUniformSetter("Uniform1iv", location_object, data[0]))
  2701         return;
  2703     MakeContextCurrent();
  2704     gl->fUniform1iv(location, numElementsToUpload, data);
  2707 void
  2708 WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object,
  2709                               uint32_t arrayLength, const GLint* data)
  2711     uint32_t numElementsToUpload;
  2712     GLint location;
  2713     if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location,
  2714                                     numElementsToUpload, arrayLength)) {
  2715         return;
  2718     if (!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[0]) ||
  2719         !ValidateSamplerUniformSetter("Uniform2iv", location_object, data[1]))
  2721         return;
  2724     MakeContextCurrent();
  2725     gl->fUniform2iv(location, numElementsToUpload, data);
  2728 void
  2729 WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object,
  2730                               uint32_t arrayLength, const GLint* data)
  2732     uint32_t numElementsToUpload;
  2733     GLint location;
  2734     if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location,
  2735                                     numElementsToUpload, arrayLength)) {
  2736         return;
  2739     if (!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[0]) ||
  2740         !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[1]) ||
  2741         !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[2]))
  2743         return;
  2746     MakeContextCurrent();
  2747     gl->fUniform3iv(location, numElementsToUpload, data);
  2750 void
  2751 WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object,
  2752                               uint32_t arrayLength, const GLint* data)
  2754     uint32_t numElementsToUpload;
  2755     GLint location;
  2756     if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location,
  2757                                     numElementsToUpload, arrayLength)) {
  2758         return;
  2761     if (!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[0]) ||
  2762         !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[1]) ||
  2763         !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[2]) ||
  2764         !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[3]))
  2766         return;
  2769     MakeContextCurrent();
  2770     gl->fUniform4iv(location, numElementsToUpload, data);
  2773 void
  2774 WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object,
  2775                               uint32_t arrayLength, const GLfloat* data)
  2777     uint32_t numElementsToUpload;
  2778     GLint location;
  2779     if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location,
  2780                                     numElementsToUpload, arrayLength)) {
  2781         return;
  2783     MakeContextCurrent();
  2784     gl->fUniform1fv(location, numElementsToUpload, data);
  2787 void
  2788 WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object,
  2789                               uint32_t arrayLength, const GLfloat* data)
  2791     uint32_t numElementsToUpload;
  2792     GLint location;
  2793     if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location,
  2794                                     numElementsToUpload, arrayLength)) {
  2795         return;
  2797     MakeContextCurrent();
  2798     gl->fUniform2fv(location, numElementsToUpload, data);
  2801 void
  2802 WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object,
  2803                               uint32_t arrayLength, const GLfloat* data)
  2805     uint32_t numElementsToUpload;
  2806     GLint location;
  2807     if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location,
  2808                                     numElementsToUpload, arrayLength)) {
  2809         return;
  2811     MakeContextCurrent();
  2812     gl->fUniform3fv(location, numElementsToUpload, data);
  2815 void
  2816 WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object,
  2817                               uint32_t arrayLength, const GLfloat* data)
  2819     uint32_t numElementsToUpload;
  2820     GLint location;
  2821     if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location,
  2822                                     numElementsToUpload, arrayLength)) {
  2823         return;
  2825     MakeContextCurrent();
  2826     gl->fUniform4fv(location, numElementsToUpload, data);
  2829 void
  2830 WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object,
  2831                                     WebGLboolean aTranspose, uint32_t arrayLength,
  2832                                     const float* data)
  2834     uint32_t numElementsToUpload;
  2835     GLint location;
  2836     if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location,
  2837                                          numElementsToUpload, arrayLength, aTranspose)) {
  2838         return;
  2840     MakeContextCurrent();
  2841     gl->fUniformMatrix2fv(location, numElementsToUpload, false, data);
  2844 void
  2845 WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object,
  2846                                     WebGLboolean aTranspose, uint32_t arrayLength,
  2847                                     const float* data)
  2849     uint32_t numElementsToUpload;
  2850     GLint location;
  2851     if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location,
  2852                                          numElementsToUpload, arrayLength, aTranspose)) {
  2853         return;
  2855     MakeContextCurrent();
  2856     gl->fUniformMatrix3fv(location, numElementsToUpload, false, data);
  2859 void
  2860 WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
  2861                                     WebGLboolean aTranspose, uint32_t arrayLength,
  2862                                     const float* data)
  2864     uint32_t numElementsToUpload;
  2865     GLint location;
  2866     if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location,
  2867                                          numElementsToUpload, arrayLength, aTranspose)) {
  2868         return;
  2870     MakeContextCurrent();
  2871     gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
  2874 void
  2875 WebGLContext::UseProgram(WebGLProgram *prog)
  2877     if (IsContextLost())
  2878         return;
  2880     if (!ValidateObjectAllowNull("useProgram", prog))
  2881         return;
  2883     MakeContextCurrent();
  2885     InvalidateBufferFetching();
  2887     GLuint progname = prog ? prog->GLName() : 0;
  2889     if (prog && !prog->LinkStatus())
  2890         return ErrorInvalidOperation("useProgram: program was not linked successfully");
  2892     gl->fUseProgram(progname);
  2894     mCurrentProgram = prog;
  2897 void
  2898 WebGLContext::ValidateProgram(WebGLProgram *prog)
  2900     if (IsContextLost())
  2901         return;
  2903     if (!ValidateObject("validateProgram", prog))
  2904         return;
  2906     MakeContextCurrent();
  2908 #ifdef XP_MACOSX
  2909     // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
  2910     if (gl->WorkAroundDriverBugs()) {
  2911         GenerateWarning("validateProgram: implemented as a no-operation on Mac to work around crashes");
  2912         return;
  2914 #endif
  2916     GLuint progname = prog->GLName();
  2917     gl->fValidateProgram(progname);
  2920 already_AddRefed<WebGLFramebuffer>
  2921 WebGLContext::CreateFramebuffer()
  2923     if (IsContextLost())
  2924         return nullptr;
  2925     nsRefPtr<WebGLFramebuffer> globj = new WebGLFramebuffer(this);
  2926     return globj.forget();
  2929 already_AddRefed<WebGLRenderbuffer>
  2930 WebGLContext::CreateRenderbuffer()
  2932     if (IsContextLost())
  2933         return nullptr;
  2934     nsRefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
  2935     return globj.forget();
  2938 void
  2939 WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
  2941     if (IsContextLost())
  2942         return;
  2944     if (width < 0 || height < 0)
  2945         return ErrorInvalidValue("viewport: negative size");
  2947     MakeContextCurrent();
  2948     gl->fViewport(x, y, width, height);
  2950     mViewportX = x;
  2951     mViewportY = y;
  2952     mViewportWidth = width;
  2953     mViewportHeight = height;
  2956 void
  2957 WebGLContext::CompileShader(WebGLShader *shader)
  2959     if (IsContextLost())
  2960         return;
  2962     if (!ValidateObject("compileShader", shader))
  2963         return;
  2965     GLuint shadername = shader->GLName();
  2967     shader->SetCompileStatus(false);
  2969     MakeContextCurrent();
  2971     ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
  2972     bool useShaderSourceTranslation = true;
  2974     if (shader->NeedsTranslation() && mShaderValidation) {
  2975         ShHandle compiler = 0;
  2976         ShBuiltInResources resources;
  2977         memset(&resources, 0, sizeof(ShBuiltInResources));
  2979         resources.MaxVertexAttribs = mGLMaxVertexAttribs;
  2980         resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
  2981         resources.MaxVaryingVectors = mGLMaxVaryingVectors;
  2982         resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
  2983         resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
  2984         resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
  2985         resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
  2986         resources.MaxDrawBuffers = mGLMaxDrawBuffers;
  2988         if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
  2989             resources.EXT_frag_depth = 1;
  2991         if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
  2992             resources.OES_standard_derivatives = 1;
  2994         if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
  2995             resources.EXT_draw_buffers = 1;
  2997         // Tell ANGLE to allow highp in frag shaders. (unless disabled)
  2998         // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
  2999         resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
  3001         if (gl->WorkAroundDriverBugs()) {
  3002 #ifdef XP_MACOSX
  3003             if (gl->Vendor() == gl::GLVendor::NVIDIA) {
  3004                 // Work around bug 890432
  3005                 resources.MaxExpressionComplexity = 1000;
  3007 #endif
  3010         // We're storing an actual instance of StripComments because, if we don't, the
  3011         // cleanSource nsAString instance will be destroyed before the reference is
  3012         // actually used.
  3013         StripComments stripComments(shader->Source());
  3014         const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
  3015         if (!ValidateGLSLString(cleanSource, "compileShader"))
  3016             return;
  3018         // shaderSource() already checks that the source stripped of comments is in the
  3019         // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
  3020         NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
  3022         if (gl->WorkAroundDriverBugs()) {
  3023             const uint32_t maxSourceLength = 0x3ffff;
  3024             if (sourceCString.Length() > maxSourceLength)
  3025                 return ErrorInvalidValue("compileShader: source has more than %d characters",
  3026                                          maxSourceLength);
  3029         const char *s = sourceCString.get();
  3031 #define WEBGL2_BYPASS_ANGLE
  3032 #ifdef WEBGL2_BYPASS_ANGLE
  3033         /*
  3034          * The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
  3035          * is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
  3037          * To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
  3039          * To bypass angle, the context must be a WebGL 2 and the shader must have the
  3040          * following line at the very top :
  3041          *      #version proto-200
  3043          * In this case, byPassANGLE == true and here is what we do :
  3044          *  We create two shader source code:
  3045          *    - one for the driver, that enable GL_EXT_gpu_shader4
  3046          *    - one for the angle compilor, to get informations about vertex attributes
  3047          *      and uniforms
  3048          */
  3049         static const char *bypassPrefixSearch = "#version proto-200";
  3050         static const char *bypassANGLEPrefix[2] = {"precision mediump float;\n"
  3051                                                    "#define gl_VertexID 0\n"
  3052                                                    "#define gl_InstanceID 0\n",
  3054                                                    "precision mediump float;\n"
  3055                                                    "#extension GL_EXT_draw_buffers : enable\n"
  3056                                                    "#define gl_PrimitiveID 0\n"};
  3058         const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0);
  3060         const char *angleShaderCode = s;
  3061         nsTArray<char> bypassANGLEShaderCode;
  3062         nsTArray<char> bypassDriverShaderCode;
  3064         if (bypassANGLE) {
  3065             const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0;
  3066             const char *originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch);
  3067             int originalShaderSize = strlen(s) - (originalShader - s);
  3068             int bypassShaderCodeSize = originalShaderSize + 4096 + 1;
  3070             bypassANGLEShaderCode.SetLength(bypassShaderCodeSize);
  3071             strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]);
  3072             strcat(bypassANGLEShaderCode.Elements(), originalShader);
  3074             bypassDriverShaderCode.SetLength(bypassShaderCodeSize);
  3075             strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
  3076             strcat(bypassDriverShaderCode.Elements(), originalShader);
  3078             angleShaderCode = bypassANGLEShaderCode.Elements();
  3080 #endif
  3082         compiler = ShConstructCompiler((ShShaderType) shader->ShaderType(),
  3083                                        SH_WEBGL_SPEC,
  3084                                        targetShaderSourceLanguage,
  3085                                        &resources);
  3087         int compileOptions = SH_ATTRIBUTES_UNIFORMS |
  3088                              SH_ENFORCE_PACKING_RESTRICTIONS;
  3090         if (resources.MaxExpressionComplexity > 0) {
  3091             compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
  3094         // We want to do this everywhere, but:
  3095 #ifndef XP_MACOSX // To do this on Mac, we need to do it only on Mac OSX > 10.6 as this
  3096                   // causes the shader compiler in 10.6 to crash
  3097         compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
  3098 #endif
  3100         if (useShaderSourceTranslation) {
  3101             compileOptions |= SH_OBJECT_CODE
  3102                             | SH_MAP_LONG_VARIABLE_NAMES;
  3104 #ifdef XP_MACOSX
  3105             if (gl->WorkAroundDriverBugs()) {
  3106                 // Work around bug 665578 and bug 769810
  3107                 if (gl->Vendor() == gl::GLVendor::ATI) {
  3108                     compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
  3111                 // Work around bug 735560
  3112                 if (gl->Vendor() == gl::GLVendor::Intel) {
  3113                     compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
  3116 #endif
  3119 #ifdef WEBGL2_BYPASS_ANGLE
  3120         if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
  3121 #else
  3122         if (!ShCompile(compiler, &s, 1, compileOptions)) {
  3123 #endif
  3124             size_t lenWithNull = 0;
  3125             ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
  3127             if (!lenWithNull) {
  3128                 // Error in ShGetInfo.
  3129                 shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
  3130             } else {
  3131                 size_t len = lenWithNull - 1;
  3133                 nsAutoCString info;
  3134                 info.SetLength(len); // Allocates len+1, for the null-term.
  3135                 ShGetInfoLog(compiler, info.BeginWriting());
  3137                 shader->SetTranslationFailure(info);
  3139             ShDestruct(compiler);
  3140             shader->SetCompileStatus(false);
  3141             return;
  3144         size_t num_attributes = 0;
  3145         ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
  3146         size_t num_uniforms = 0;
  3147         ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
  3148         size_t attrib_max_length = 0;
  3149         ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
  3150         size_t uniform_max_length = 0;
  3151         ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
  3152         size_t mapped_max_length = 0;
  3153         ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
  3155         shader->mAttribMaxNameLength = attrib_max_length;
  3157         shader->mAttributes.Clear();
  3158         shader->mUniforms.Clear();
  3159         shader->mUniformInfos.Clear();
  3161         nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
  3162         nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
  3163         nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
  3165         for (size_t i = 0; i < num_uniforms; i++) {
  3166             size_t length;
  3167             int size;
  3168             ShDataType type;
  3169             ShGetActiveUniform(compiler, (int)i,
  3170                                 &length, &size, &type,
  3171                                 uniform_name,
  3172                                 mapped_name);
  3173             if (useShaderSourceTranslation) {
  3174                 shader->mUniforms.AppendElement(WebGLMappedIdentifier(
  3175                                                     nsDependentCString(uniform_name),
  3176                                                     nsDependentCString(mapped_name)));
  3179             // we always query uniform info, regardless of useShaderSourceTranslation,
  3180             // as we need it to validate uniform setter calls, and it doesn't rely on
  3181             // shader translation.
  3182             char mappedNameLength = strlen(mapped_name);
  3183             char mappedNameLastChar = mappedNameLength > 1
  3184                                       ? mapped_name[mappedNameLength - 1]
  3185                                       : 0;
  3186             shader->mUniformInfos.AppendElement(WebGLUniformInfo(
  3187                                                     size,
  3188                                                     mappedNameLastChar == ']',
  3189                                                     type));
  3192         if (useShaderSourceTranslation) {
  3194             for (size_t i = 0; i < num_attributes; i++) {
  3195                 size_t length;
  3196                 int size;
  3197                 ShDataType type;
  3198                 ShGetActiveAttrib(compiler, (int)i,
  3199                                   &length, &size, &type,
  3200                                   attribute_name,
  3201                                   mapped_name);
  3202                 shader->mAttributes.AppendElement(WebGLMappedIdentifier(
  3203                                                     nsDependentCString(attribute_name),
  3204                                                     nsDependentCString(mapped_name)));
  3207             size_t lenWithNull = 0;
  3208             ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
  3209             MOZ_ASSERT(lenWithNull >= 1);
  3210             size_t len = lenWithNull - 1;
  3212             nsAutoCString translatedSrc;
  3213             translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
  3214             ShGetObjectCode(compiler, translatedSrc.BeginWriting());
  3216             CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
  3218             const char *ts = translatedSrc.get();
  3220 #ifdef WEBGL2_BYPASS_ANGLE
  3221             if (bypassANGLE) {
  3222                 const char* driverShaderCode = bypassDriverShaderCode.Elements();
  3223                 gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr);
  3225             else {
  3226                 gl->fShaderSource(shadername, 1, &ts, nullptr);
  3228 #else
  3229             gl->fShaderSource(shadername, 1, &ts, nullptr);
  3230 #endif
  3231         } else { // not useShaderSourceTranslation
  3232             // we just pass the raw untranslated shader source. We then can't use ANGLE idenfier mapping.
  3233             // that's really bad, as that means we can't be 100% conformant. We should work towards always
  3234             // using ANGLE identifier mapping.
  3235             gl->fShaderSource(shadername, 1, &s, nullptr);
  3237             CopyASCIItoUTF16(s, shader->mTranslatedSource);
  3240         shader->SetTranslationSuccess();
  3242         ShDestruct(compiler);
  3244         gl->fCompileShader(shadername);
  3245         GLint ok;
  3246         gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
  3247         shader->SetCompileStatus(ok);
  3251 void
  3252 WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat,
  3253                                    GLsizei width, GLsizei height, GLint border,
  3254                                    const ArrayBufferView& view)
  3256     if (IsContextLost())
  3257         return;
  3259     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
  3261     if (!ValidateTexImage(2, target, level, internalformat,
  3262                           0, 0, 0, width, height, 0,
  3263                           border, internalformat, LOCAL_GL_UNSIGNED_BYTE,
  3264                           func))
  3266         return;
  3269     view.ComputeLengthAndData();
  3271     uint32_t byteLength = view.Length();
  3272     if (!ValidateCompTexImageDataSize(target, internalformat, width, height, byteLength, func)) {
  3273         return;
  3276     if (!ValidateCompTexImageSize(target, level, internalformat, 0, 0,
  3277                                   width, height, width, height, func))
  3279         return;
  3282     MakeContextCurrent();
  3283     gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
  3284     WebGLTexture* tex = activeBoundTextureForTarget(target);
  3285     MOZ_ASSERT(tex);
  3286     tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
  3287                       WebGLImageDataStatus::InitializedImageData);
  3290 void
  3291 WebGLContext::CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset,
  3292                                       GLint yoffset, GLsizei width, GLsizei height,
  3293                                       GLenum format, const ArrayBufferView& view)
  3295     if (IsContextLost())
  3296         return;
  3298     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
  3300     if (!ValidateTexImage(2, target,
  3301                           level, format,
  3302                           xoffset, yoffset, 0,
  3303                           width, height, 0,
  3304                           0, format, LOCAL_GL_UNSIGNED_BYTE,
  3305                           func))
  3307         return;
  3310     WebGLTexture *tex = activeBoundTextureForTarget(target);
  3311     MOZ_ASSERT(tex);
  3312     WebGLTexture::ImageInfo& levelInfo = tex->ImageInfoAt(target, level);
  3314     view.ComputeLengthAndData();
  3316     uint32_t byteLength = view.Length();
  3317     if (!ValidateCompTexImageDataSize(target, format, width, height, byteLength, func))
  3318         return;
  3320     if (!ValidateCompTexImageSize(target, level, format,
  3321                                   xoffset, yoffset,
  3322                                   width, height,
  3323                                   levelInfo.Width(), levelInfo.Height(),
  3324                                   func))
  3326         return;
  3329     if (levelInfo.HasUninitializedImageData())
  3330         tex->DoDeferredImageInitialization(target, level);
  3332     MakeContextCurrent();
  3333     gl->fCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, byteLength, view.Data());
  3336 JS::Value
  3337 WebGLContext::GetShaderParameter(WebGLShader *shader, GLenum pname)
  3339     if (IsContextLost())
  3340         return JS::NullValue();
  3342     if (!ValidateObject("getShaderParameter: shader", shader))
  3343         return JS::NullValue();
  3345     GLuint shadername = shader->GLName();
  3347     MakeContextCurrent();
  3349     switch (pname) {
  3350         case LOCAL_GL_SHADER_TYPE:
  3352             GLint i = 0;
  3353             gl->fGetShaderiv(shadername, pname, &i);
  3354             return JS::NumberValue(uint32_t(i));
  3356             break;
  3357         case LOCAL_GL_DELETE_STATUS:
  3358             return JS::BooleanValue(shader->IsDeleteRequested());
  3359             break;
  3360         case LOCAL_GL_COMPILE_STATUS:
  3362             GLint i = 0;
  3363             gl->fGetShaderiv(shadername, pname, &i);
  3364             return JS::BooleanValue(bool(i));
  3366             break;
  3367         default:
  3368             ErrorInvalidEnumInfo("getShaderParameter: parameter", pname);
  3371     return JS::NullValue();
  3374 void
  3375 WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsAString& retval)
  3377     nsAutoCString s;
  3378     GetShaderInfoLog(shader, s);
  3379     if (s.IsVoid())
  3380         retval.SetIsVoid(true);
  3381     else
  3382         CopyASCIItoUTF16(s, retval);
  3385 void
  3386 WebGLContext::GetShaderInfoLog(WebGLShader *shader, nsACString& retval)
  3388     if (IsContextLost())
  3390         retval.SetIsVoid(true);
  3391         return;
  3394     if (!ValidateObject("getShaderInfoLog: shader", shader))
  3395         return;
  3397     retval = shader->TranslationLog();
  3398     if (!retval.IsVoid()) {
  3399         return;
  3402     MakeContextCurrent();
  3404     GLuint shadername = shader->GLName();
  3405     GLint k = -1;
  3406     gl->fGetShaderiv(shadername, LOCAL_GL_INFO_LOG_LENGTH, &k);
  3407     if (k == -1) {
  3408         // XXX GL Error? should never happen.
  3409         return;
  3412     if (k == 0) {
  3413         retval.Truncate();
  3414         return;
  3417     retval.SetCapacity(k);
  3418     gl->fGetShaderInfoLog(shadername, k, &k, (char*) retval.BeginWriting());
  3419     retval.SetLength(k);
  3422 already_AddRefed<WebGLShaderPrecisionFormat>
  3423 WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
  3425     if (IsContextLost())
  3426         return nullptr;
  3428     switch (shadertype) {
  3429         case LOCAL_GL_FRAGMENT_SHADER:
  3430         case LOCAL_GL_VERTEX_SHADER:
  3431             break;
  3432         default:
  3433             ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype);
  3434             return nullptr;
  3437     switch (precisiontype) {
  3438         case LOCAL_GL_LOW_FLOAT:
  3439         case LOCAL_GL_MEDIUM_FLOAT:
  3440         case LOCAL_GL_HIGH_FLOAT:
  3441         case LOCAL_GL_LOW_INT:
  3442         case LOCAL_GL_MEDIUM_INT:
  3443         case LOCAL_GL_HIGH_INT:
  3444             break;
  3445         default:
  3446             ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype);
  3447             return nullptr;
  3450     MakeContextCurrent();
  3451     GLint range[2], precision;
  3453     if (mDisableFragHighP &&
  3454         shadertype == LOCAL_GL_FRAGMENT_SHADER &&
  3455         (precisiontype == LOCAL_GL_HIGH_FLOAT ||
  3456          precisiontype == LOCAL_GL_HIGH_INT))
  3458       precision = 0;
  3459       range[0] = 0;
  3460       range[1] = 0;
  3461     } else {
  3462       gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
  3465     nsRefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
  3466         = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
  3467     return retShaderPrecisionFormat.forget();
  3470 void
  3471 WebGLContext::GetShaderSource(WebGLShader *shader, nsAString& retval)
  3473     if (IsContextLost()) {
  3474         retval.SetIsVoid(true);
  3475         return;
  3478     if (!ValidateObject("getShaderSource: shader", shader))
  3479         return;
  3481     retval.Assign(shader->Source());
  3484 void
  3485 WebGLContext::ShaderSource(WebGLShader *shader, const nsAString& source)
  3487     if (IsContextLost())
  3488         return;
  3490     if (!ValidateObject("shaderSource: shader", shader))
  3491         return;
  3493     // We're storing an actual instance of StripComments because, if we don't, the
  3494     // cleanSource nsAString instance will be destroyed before the reference is
  3495     // actually used.
  3496     StripComments stripComments(source);
  3497     const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
  3498     if (!ValidateGLSLString(cleanSource, "compileShader"))
  3499         return;
  3501     shader->SetSource(source);
  3503     shader->SetNeedsTranslation();
  3506 void
  3507 WebGLContext::GetShaderTranslatedSource(WebGLShader *shader, nsAString& retval)
  3509     if (IsContextLost()) {
  3510         retval.SetIsVoid(true);
  3511         return;
  3514     if (!ValidateObject("getShaderTranslatedSource: shader", shader))
  3515         return;
  3517     retval.Assign(shader->TranslatedSource());
  3520 GLenum WebGLContext::CheckedTexImage2D(GLenum target,
  3521                                        GLint level,
  3522                                        GLenum internalFormat,
  3523                                        GLsizei width,
  3524                                        GLsizei height,
  3525                                        GLint border,
  3526                                        GLenum format,
  3527                                        GLenum type,
  3528                                        const GLvoid *data)
  3530     MOZ_ASSERT(internalFormat == format);
  3531     WebGLTexture *tex = activeBoundTextureForTarget(target);
  3532     MOZ_ASSERT(tex != nullptr, "no texture bound");
  3534     bool sizeMayChange = true;
  3536     if (tex->HasImageInfoAt(target, level)) {
  3537         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
  3538         sizeMayChange = width != imageInfo.Width() ||
  3539                         height != imageInfo.Height() ||
  3540                         format != imageInfo.WebGLFormat() ||
  3541                         type != imageInfo.WebGLType();
  3544     // Convert to format and type required by OpenGL 'driver'.
  3545     GLenum driverType = DriverTypeFromType(gl, type);
  3546     GLenum driverInternalFormat = LOCAL_GL_NONE;
  3547     GLenum driverFormat = LOCAL_GL_NONE;
  3548     DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
  3550     if (sizeMayChange) {
  3551         GetAndFlushUnderlyingGLErrors();
  3554     gl->fTexImage2D(target, level, driverInternalFormat, width, height, border, driverFormat, driverType, data);
  3556     GLenum error = LOCAL_GL_NO_ERROR;
  3557     if (sizeMayChange) {
  3558         error = GetAndFlushUnderlyingGLErrors();
  3561     return error;
  3564 void
  3565 WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
  3566                               GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
  3567                               GLint border,
  3568                               GLenum format, GLenum type,
  3569                               void* data, uint32_t byteLength,
  3570                               int jsArrayType, // a TypedArray format enum, or -1 if not relevant
  3571                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
  3573     const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
  3575     if (!ValidateTexImage(2, target, level, internalformat,
  3576                           0, 0, 0,
  3577                           width, height, 0,
  3578                           border, format, type, func))
  3580         return;
  3583     const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT ||
  3584                                 format == LOCAL_GL_DEPTH_STENCIL;
  3586     if (isDepthTexture) {
  3587         if (data != nullptr || level != 0)
  3588             return ErrorInvalidOperation("texImage2D: "
  3589                                          "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
  3590                                          "data must be nullptr, "
  3591                                          "level must be zero");
  3594     if (!ValidateTexInputData(type, jsArrayType, func))
  3595         return;
  3597     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
  3598     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
  3600     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
  3602     CheckedUint32 checked_neededByteLength =
  3603         GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
  3605     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
  3606     CheckedUint32 checked_alignedRowSize =
  3607         RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
  3609     if (!checked_neededByteLength.isValid())
  3610         return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
  3612     uint32_t bytesNeeded = checked_neededByteLength.value();
  3614     if (byteLength && byteLength < bytesNeeded)
  3615         return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
  3616                                  bytesNeeded, byteLength);
  3618     WebGLTexture *tex = activeBoundTextureForTarget(target);
  3620     if (!tex)
  3621         return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
  3623     MakeContextCurrent();
  3625     nsAutoArrayPtr<uint8_t> convertedData;
  3626     void* pixels = nullptr;
  3627     WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::UninitializedImageData;
  3629     if (byteLength) {
  3630         size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
  3631         uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
  3632         size_t   dstPlainRowSize = dstTexelSize * width;
  3633         size_t   unpackAlignment = mPixelStoreUnpackAlignment;
  3634         size_t   dstStride = ((dstPlainRowSize + unpackAlignment-1) / unpackAlignment) * unpackAlignment;
  3636         if (actualSrcFormat == dstFormat &&
  3637             srcPremultiplied == mPixelStorePremultiplyAlpha &&
  3638             srcStride == dstStride &&
  3639             !mPixelStoreFlipY)
  3641             // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
  3642             pixels = data;
  3644         else
  3646             size_t convertedDataSize = height * dstStride;
  3647             convertedData = new uint8_t[convertedDataSize];
  3648             ConvertImage(width, height, srcStride, dstStride,
  3649                         static_cast<uint8_t*>(data), convertedData,
  3650                         actualSrcFormat, srcPremultiplied,
  3651                         dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
  3652             pixels = reinterpret_cast<void*>(convertedData.get());
  3654         imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
  3657     GLenum error = CheckedTexImage2D(target, level, internalformat, width,
  3658                                      height, border, format, type, pixels);
  3660     if (error) {
  3661         GenerateWarning("texImage2D generated error %s", ErrorName(error));
  3662         return;
  3665     // in all of the code paths above, we should have either initialized data,
  3666     // or allocated data and left it uninitialized, but in any case we shouldn't
  3667     // have NoImageData at this point.
  3668     MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
  3670     tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess);
  3673 void
  3674 WebGLContext::TexImage2D(GLenum target, GLint level,
  3675                          GLenum internalformat, GLsizei width,
  3676                          GLsizei height, GLint border, GLenum format,
  3677                          GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
  3679     if (IsContextLost())
  3680         return;
  3682     void* data;
  3683     uint32_t length;
  3684     int jsArrayType;
  3685     if (pixels.IsNull()) {
  3686         data = nullptr;
  3687         length = 0;
  3688         jsArrayType = -1;
  3689     } else {
  3690         const ArrayBufferView& view = pixels.Value();
  3691         view.ComputeLengthAndData();
  3693         data = view.Data();
  3694         length = view.Length();
  3695         jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
  3698     return TexImage2D_base(target, level, internalformat, width, height, 0, border, format, type,
  3699                            data, length, jsArrayType,
  3700                            WebGLTexelFormat::Auto, false);
  3703 void
  3704 WebGLContext::TexImage2D(GLenum target, GLint level,
  3705                          GLenum internalformat, GLenum format,
  3706                          GLenum type, ImageData* pixels, ErrorResult& rv)
  3708     if (IsContextLost())
  3709         return;
  3711     if (!pixels) {
  3712         // Spec says to generate an INVALID_VALUE error
  3713         return ErrorInvalidValue("texImage2D: null ImageData");
  3716     Uint8ClampedArray arr(pixels->GetDataObject());
  3717     arr.ComputeLengthAndData();
  3719     return TexImage2D_base(target, level, internalformat, pixels->Width(),
  3720                            pixels->Height(), 4*pixels->Width(), 0,
  3721                            format, type, arr.Data(), arr.Length(), -1,
  3722                            WebGLTexelFormat::RGBA8, false);
  3726 void
  3727 WebGLContext::TexSubImage2D_base(GLenum target, GLint level,
  3728                                  GLint xoffset, GLint yoffset,
  3729                                  GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
  3730                                  GLenum format, GLenum type,
  3731                                  void* data, uint32_t byteLength,
  3732                                  int jsArrayType,
  3733                                  WebGLTexelFormat srcFormat, bool srcPremultiplied)
  3735     const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
  3737     if (!ValidateTexImage(2, target, level, format,
  3738                           xoffset, yoffset, 0,
  3739                           width, height, 0,
  3740                           0, format, type, func))
  3742         return;
  3745     if (!ValidateTexInputData(type, jsArrayType, func))
  3746         return;
  3748     WebGLTexelFormat dstFormat = GetWebGLTexelFormat(format, type);
  3749     WebGLTexelFormat actualSrcFormat = srcFormat == WebGLTexelFormat::Auto ? dstFormat : srcFormat;
  3751     uint32_t srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat);
  3753     if (width == 0 || height == 0)
  3754         return; // ES 2.0 says it has no effect, we better return right now
  3756     CheckedUint32 checked_neededByteLength =
  3757         GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
  3759     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
  3761     CheckedUint32 checked_alignedRowSize =
  3762         RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
  3764     if (!checked_neededByteLength.isValid())
  3765         return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
  3767     uint32_t bytesNeeded = checked_neededByteLength.value();
  3769     if (byteLength < bytesNeeded)
  3770         return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
  3772     WebGLTexture *tex = activeBoundTextureForTarget(target);
  3773     const WebGLTexture::ImageInfo &imageInfo = tex->ImageInfoAt(target, level);
  3775     if (imageInfo.HasUninitializedImageData())
  3776         tex->DoDeferredImageInitialization(target, level);
  3778     MakeContextCurrent();
  3780     size_t   srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
  3781     uint32_t dstTexelSize = GetBitsPerTexel(format, type) / 8;
  3782     size_t   dstPlainRowSize = dstTexelSize * width;
  3783     // There are checks above to ensure that this won't overflow.
  3784     size_t   dstStride = RoundedToNextMultipleOf(dstPlainRowSize, mPixelStoreUnpackAlignment).value();
  3786     void* pixels = data;
  3787     nsAutoArrayPtr<uint8_t> convertedData;
  3789     // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
  3790     bool noConversion = (actualSrcFormat == dstFormat &&
  3791                          srcPremultiplied == mPixelStorePremultiplyAlpha &&
  3792                          srcStride == dstStride &&
  3793                          !mPixelStoreFlipY);
  3795     if (!noConversion) {
  3796         size_t convertedDataSize = height * dstStride;
  3797         convertedData = new uint8_t[convertedDataSize];
  3798         ConvertImage(width, height, srcStride, dstStride,
  3799                     static_cast<const uint8_t*>(data), convertedData,
  3800                     actualSrcFormat, srcPremultiplied,
  3801                     dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize);
  3802         pixels = reinterpret_cast<void*>(convertedData.get());
  3805     GLenum driverType = DriverTypeFromType(gl, type);
  3806     GLenum driverInternalFormat = LOCAL_GL_NONE;
  3807     GLenum driverFormat = LOCAL_GL_NONE;
  3808     DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
  3810     gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, driverFormat, driverType, pixels);
  3813 void
  3814 WebGLContext::TexSubImage2D(GLenum target, GLint level,
  3815                             GLint xoffset, GLint yoffset,
  3816                             GLsizei width, GLsizei height,
  3817                             GLenum format, GLenum type,
  3818                             const Nullable<ArrayBufferView> &pixels,
  3819                             ErrorResult& rv)
  3821     if (IsContextLost())
  3822         return;
  3824     if (pixels.IsNull())
  3825         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
  3827     const ArrayBufferView& view = pixels.Value();
  3828     view.ComputeLengthAndData();
  3830     return TexSubImage2D_base(target, level, xoffset, yoffset,
  3831                               width, height, 0, format, type,
  3832                               view.Data(), view.Length(),
  3833                               JS_GetArrayBufferViewType(view.Obj()),
  3834                               WebGLTexelFormat::Auto, false);
  3837 void
  3838 WebGLContext::TexSubImage2D(GLenum target, GLint level,
  3839                             GLint xoffset, GLint yoffset,
  3840                             GLenum format, GLenum type, ImageData* pixels,
  3841                             ErrorResult& rv)
  3843     if (IsContextLost())
  3844         return;
  3846     if (!pixels)
  3847         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
  3849     Uint8ClampedArray arr(pixels->GetDataObject());
  3850     arr.ComputeLengthAndData();
  3852     return TexSubImage2D_base(target, level, xoffset, yoffset,
  3853                               pixels->Width(), pixels->Height(),
  3854                               4*pixels->Width(), format, type,
  3855                               arr.Data(), arr.Length(),
  3856                               -1,
  3857                               WebGLTexelFormat::RGBA8, false);
  3860 bool
  3861 WebGLContext::LoseContext()
  3863     if (IsContextLost())
  3864         return false;
  3866     ForceLoseContext();
  3868     return true;
  3871 bool
  3872 WebGLContext::RestoreContext()
  3874     if (!IsContextLost() || !mAllowRestore) {
  3875         return false;
  3878     ForceRestoreContext();
  3880     return true;
  3883 bool
  3884 BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize)
  3886     switch (uType) {
  3887         case LOCAL_GL_INT:
  3888         case LOCAL_GL_INT_VEC2:
  3889         case LOCAL_GL_INT_VEC3:
  3890         case LOCAL_GL_INT_VEC4:
  3891         case LOCAL_GL_SAMPLER_2D:
  3892         case LOCAL_GL_SAMPLER_CUBE:
  3893             *baseType = LOCAL_GL_INT;
  3894             break;
  3895         case LOCAL_GL_FLOAT:
  3896         case LOCAL_GL_FLOAT_VEC2:
  3897         case LOCAL_GL_FLOAT_VEC3:
  3898         case LOCAL_GL_FLOAT_VEC4:
  3899         case LOCAL_GL_FLOAT_MAT2:
  3900         case LOCAL_GL_FLOAT_MAT3:
  3901         case LOCAL_GL_FLOAT_MAT4:
  3902             *baseType = LOCAL_GL_FLOAT;
  3903             break;
  3904         case LOCAL_GL_BOOL:
  3905         case LOCAL_GL_BOOL_VEC2:
  3906         case LOCAL_GL_BOOL_VEC3:
  3907         case LOCAL_GL_BOOL_VEC4:
  3908             *baseType = LOCAL_GL_BOOL; // pretend these are int
  3909             break;
  3910         default:
  3911             return false;
  3914     switch (uType) {
  3915         case LOCAL_GL_INT:
  3916         case LOCAL_GL_FLOAT:
  3917         case LOCAL_GL_BOOL:
  3918         case LOCAL_GL_SAMPLER_2D:
  3919         case LOCAL_GL_SAMPLER_CUBE:
  3920             *unitSize = 1;
  3921             break;
  3922         case LOCAL_GL_INT_VEC2:
  3923         case LOCAL_GL_FLOAT_VEC2:
  3924         case LOCAL_GL_BOOL_VEC2:
  3925             *unitSize = 2;
  3926             break;
  3927         case LOCAL_GL_INT_VEC3:
  3928         case LOCAL_GL_FLOAT_VEC3:
  3929         case LOCAL_GL_BOOL_VEC3:
  3930             *unitSize = 3;
  3931             break;
  3932         case LOCAL_GL_INT_VEC4:
  3933         case LOCAL_GL_FLOAT_VEC4:
  3934         case LOCAL_GL_BOOL_VEC4:
  3935             *unitSize = 4;
  3936             break;
  3937         case LOCAL_GL_FLOAT_MAT2:
  3938             *unitSize = 4;
  3939             break;
  3940         case LOCAL_GL_FLOAT_MAT3:
  3941             *unitSize = 9;
  3942             break;
  3943         case LOCAL_GL_FLOAT_MAT4:
  3944             *unitSize = 16;
  3945             break;
  3946         default:
  3947             return false;
  3950     return true;
  3954 WebGLTexelFormat mozilla::GetWebGLTexelFormat(GLenum internalformat, GLenum type)
  3956     //
  3957     // WEBGL_depth_texture
  3958     if (internalformat == LOCAL_GL_DEPTH_COMPONENT) {
  3959         switch (type) {
  3960             case LOCAL_GL_UNSIGNED_SHORT:
  3961                 return WebGLTexelFormat::D16;
  3962             case LOCAL_GL_UNSIGNED_INT:
  3963                 return WebGLTexelFormat::D32;
  3966         MOZ_CRASH("Invalid WebGL texture format/type?");
  3969     if (internalformat == LOCAL_GL_DEPTH_STENCIL) {
  3970         switch (type) {
  3971             case LOCAL_GL_UNSIGNED_INT_24_8_EXT:
  3972                 return WebGLTexelFormat::D24S8;
  3975         MOZ_CRASH("Invalid WebGL texture format/type?");
  3978     if (internalformat == LOCAL_GL_DEPTH_COMPONENT16) {
  3979         return WebGLTexelFormat::D16;
  3982     if (internalformat == LOCAL_GL_DEPTH_COMPONENT32) {
  3983         return WebGLTexelFormat::D32;
  3986     if (internalformat == LOCAL_GL_DEPTH24_STENCIL8) {
  3987         return WebGLTexelFormat::D24S8;
  3990     if (type == LOCAL_GL_UNSIGNED_BYTE) {
  3991         switch (internalformat) {
  3992             case LOCAL_GL_RGBA:
  3993             case LOCAL_GL_SRGB_ALPHA_EXT:
  3994                 return WebGLTexelFormat::RGBA8;
  3995             case LOCAL_GL_RGB:
  3996             case LOCAL_GL_SRGB_EXT:
  3997                 return WebGLTexelFormat::RGB8;
  3998             case LOCAL_GL_ALPHA:
  3999                 return WebGLTexelFormat::A8;
  4000             case LOCAL_GL_LUMINANCE:
  4001                 return WebGLTexelFormat::R8;
  4002             case LOCAL_GL_LUMINANCE_ALPHA:
  4003                 return WebGLTexelFormat::RA8;
  4006         MOZ_CRASH("Invalid WebGL texture format/type?");
  4009     if (type == LOCAL_GL_FLOAT) {
  4010         // OES_texture_float
  4011         switch (internalformat) {
  4012             case LOCAL_GL_RGBA:
  4013             case LOCAL_GL_RGBA32F:
  4014                 return WebGLTexelFormat::RGBA32F;
  4015             case LOCAL_GL_RGB:
  4016             case LOCAL_GL_RGB32F:
  4017                 return WebGLTexelFormat::RGB32F;
  4018             case LOCAL_GL_ALPHA:
  4019             case LOCAL_GL_ALPHA32F_ARB:
  4020                 return WebGLTexelFormat::A32F;
  4021             case LOCAL_GL_LUMINANCE:
  4022             case LOCAL_GL_LUMINANCE32F_ARB:
  4023                 return WebGLTexelFormat::R32F;
  4024             case LOCAL_GL_LUMINANCE_ALPHA:
  4025             case LOCAL_GL_LUMINANCE_ALPHA32F_ARB:
  4026                 return WebGLTexelFormat::RA32F;
  4029         MOZ_CRASH("Invalid WebGL texture format/type?");
  4030     } else if (type == LOCAL_GL_HALF_FLOAT_OES) {
  4031         // OES_texture_half_float
  4032         switch (internalformat) {
  4033             case LOCAL_GL_RGBA:
  4034             case LOCAL_GL_RGBA16F:
  4035                 return WebGLTexelFormat::RGBA16F;
  4036             case LOCAL_GL_RGB:
  4037             case LOCAL_GL_RGB16F:
  4038                 return WebGLTexelFormat::RGB16F;
  4039             case LOCAL_GL_ALPHA:
  4040             case LOCAL_GL_ALPHA16F_ARB:
  4041                 return WebGLTexelFormat::A16F;
  4042             case LOCAL_GL_LUMINANCE:
  4043             case LOCAL_GL_LUMINANCE16F_ARB:
  4044                 return WebGLTexelFormat::R16F;
  4045             case LOCAL_GL_LUMINANCE_ALPHA:
  4046             case LOCAL_GL_LUMINANCE_ALPHA16F_ARB:
  4047                 return WebGLTexelFormat::RA16F;
  4048             default:
  4049                 MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
  4050                 return WebGLTexelFormat::BadFormat;
  4054     switch (type) {
  4055         case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  4056            return WebGLTexelFormat::RGBA4444;
  4057         case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  4058            return WebGLTexelFormat::RGBA5551;
  4059         case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  4060            return WebGLTexelFormat::RGB565;
  4061         default:
  4062             MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
  4063             return WebGLTexelFormat::BadFormat;
  4066     MOZ_CRASH("Invalid WebGL texture format/type?");
  4069 void
  4070 WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
  4071     if (IsContextLost())
  4072         return;
  4073     MakeContextCurrent();
  4074     gl->fBlendColor(r, g, b, a);
  4077 void
  4078 WebGLContext::Flush() {
  4079     if (IsContextLost())
  4080         return;
  4081     MakeContextCurrent();
  4082     gl->fFlush();
  4085 void
  4086 WebGLContext::Finish() {
  4087     if (IsContextLost())
  4088         return;
  4089     MakeContextCurrent();
  4090     gl->fFinish();
  4093 void
  4094 WebGLContext::LineWidth(GLfloat width) {
  4095     if (IsContextLost())
  4096         return;
  4097     MakeContextCurrent();
  4098     gl->fLineWidth(width);
  4101 void
  4102 WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
  4103     if (IsContextLost())
  4104         return;
  4105     MakeContextCurrent();
  4106     gl->fPolygonOffset(factor, units);
  4109 void
  4110 WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert) {
  4111     if (IsContextLost())
  4112         return;
  4113     MakeContextCurrent();
  4114     gl->fSampleCoverage(value, invert);

mercurial