content/canvas/src/WebGLContextValidate.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "WebGLContext.h"
     7 #include "WebGLBuffer.h"
     8 #include "WebGLVertexAttribData.h"
     9 #include "WebGLShader.h"
    10 #include "WebGLProgram.h"
    11 #include "WebGLUniformLocation.h"
    12 #include "WebGLFramebuffer.h"
    13 #include "WebGLRenderbuffer.h"
    14 #include "WebGLTexture.h"
    15 #include "WebGLVertexArray.h"
    16 #include "GLContext.h"
    17 #include "CanvasUtils.h"
    19 #include "mozilla/CheckedInt.h"
    20 #include "mozilla/Preferences.h"
    21 #include "mozilla/Services.h"
    23 #include "jsfriendapi.h"
    25 #include "angle/ShaderLang.h"
    27 #include <algorithm>
    29 #include "mozilla/Services.h"
    30 #include "nsIObserverService.h"
    32 using namespace mozilla;
    34 /**
    35  * Return the block size for format.
    36  */
    37 static void
    38 BlockSizeFor(GLenum format, GLint* blockWidth, GLint* blockHeight)
    39 {
    40     MOZ_ASSERT(blockWidth && blockHeight);
    42     switch (format) {
    43     case LOCAL_GL_ATC_RGB:
    44     case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
    45     case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
    46     case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
    47     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
    48     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
    49     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
    50         if (blockWidth)
    51             *blockWidth = 4;
    52         if (blockHeight)
    53             *blockHeight = 4;
    54         break;
    56     case LOCAL_GL_ETC1_RGB8_OES:
    57         // 4x4 blocks, but no 4-multiple requirement.
    58     default:
    59         break;
    60     }
    61 }
    63 /**
    64  * Return the displayable name for the texture function that is the
    65  * source for validation.
    66  */
    67 static const char*
    68 InfoFrom(WebGLTexImageFunc func)
    69 {
    70     // TODO: Account for dimensions (WebGL 2)
    71     switch (func) {
    72     case WebGLTexImageFunc::TexImage:        return "texImage2D";
    73     case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
    74     case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
    75     case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
    76     case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
    77     case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
    78     default:
    79         MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
    80         return "(error)";
    81     }
    82 }
    84 /**
    85  * Return displayable name for GLenum.
    86  * This version is like gl::GLenumToStr but with out the GL_ prefix to
    87  * keep consistency with how errors are reported from WebGL.
    88  */
    89 static const char*
    90 NameFrom(GLenum glenum)
    91 {
    92     switch (glenum) {
    93 #define XX(x) case LOCAL_GL_##x: return #x
    94         XX(ALPHA);
    95         XX(ATC_RGB);
    96         XX(ATC_RGBA_EXPLICIT_ALPHA);
    97         XX(ATC_RGBA_INTERPOLATED_ALPHA);
    98         XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
    99         XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
   100         XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
   101         XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
   102         XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
   103         XX(COMPRESSED_RGB_PVRTC_2BPPV1);
   104         XX(COMPRESSED_RGB_PVRTC_4BPPV1);
   105         XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
   106         XX(DEPTH_COMPONENT);
   107         XX(DEPTH_COMPONENT16);
   108         XX(DEPTH_COMPONENT32);
   109         XX(DEPTH_STENCIL);
   110         XX(DEPTH24_STENCIL8);
   111         XX(ETC1_RGB8_OES);
   112         XX(FLOAT);
   113         XX(HALF_FLOAT);
   114         XX(LUMINANCE);
   115         XX(LUMINANCE_ALPHA);
   116         XX(RGB);
   117         XX(RGB16F);
   118         XX(RGB32F);
   119         XX(RGBA);
   120         XX(RGBA16F);
   121         XX(RGBA32F);
   122         XX(SRGB);
   123         XX(SRGB_ALPHA);
   124         XX(TEXTURE_2D);
   125         XX(TEXTURE_3D);
   126         XX(TEXTURE_CUBE_MAP);
   127         XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
   128         XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
   129         XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
   130         XX(TEXTURE_CUBE_MAP_POSITIVE_X);
   131         XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
   132         XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
   133         XX(UNSIGNED_BYTE);
   134         XX(UNSIGNED_INT);
   135         XX(UNSIGNED_INT_24_8);
   136         XX(UNSIGNED_SHORT);
   137         XX(UNSIGNED_SHORT_4_4_4_4);
   138         XX(UNSIGNED_SHORT_5_5_5_1);
   139         XX(UNSIGNED_SHORT_5_6_5);
   140 #undef XX
   141     }
   143     return nullptr;
   144 }
   146 /**
   147  * Same as ErrorInvalidEnum but uses NameFrom to print displayable
   148  * name for \a glenum.
   149  */
   150 static void
   151 ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
   152 {
   153     const char* name = NameFrom(glenum);
   154     if (name)
   155         ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
   156     else
   157         ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
   158 }
   160 /**
   161  * Same as ErrorInvalidOperation but uses NameFrom to print displayable
   162  * name for \a glenum.
   163  */
   164 static void
   165 ErrorInvalidOperationWithName(WebGLContext* ctx, const char* msg, GLenum glenum,
   166                               WebGLTexImageFunc func)
   167 {
   168     const char* name = NameFrom(glenum);
   169     if (name)
   170         ctx->ErrorInvalidOperation("%s: %s %s", InfoFrom(func), msg, name);
   171     else
   172         ctx->ErrorInvalidOperation("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
   173 }
   175 /**
   176  * Return true if the format is valid for source calls.
   177  */
   178 static bool
   179 IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
   180 {
   181     switch (format) {
   182     case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
   183     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
   184     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
   185     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
   186     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   187     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   188     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   189     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   190         return (func == WebGLTexImageFunc::CompTexImage ||
   191                 func == WebGLTexImageFunc::CompTexSubImage);
   193     case LOCAL_GL_ATC_RGB:
   194     case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
   195     case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
   196     case LOCAL_GL_ETC1_RGB8_OES:
   197         return func == WebGLTexImageFunc::CompTexImage;
   198     }
   200     return true;
   201 }
   203 /**
   204  * Returns true if func is a CopyTexImage variant.
   205  */
   206 static bool
   207 IsCopyFunc(WebGLTexImageFunc func)
   208 {
   209     return (func == WebGLTexImageFunc::CopyTexImage ||
   210             func == WebGLTexImageFunc::CopyTexSubImage);
   211 }
   213 /**
   214  * Returns true if func is a SubImage variant.
   215  */
   216 static bool
   217 IsSubFunc(WebGLTexImageFunc func)
   218 {
   219     return (func == WebGLTexImageFunc::TexSubImage ||
   220             func == WebGLTexImageFunc::CopyTexSubImage ||
   221             func == WebGLTexImageFunc::CompTexSubImage);
   222 }
   224 /**
   225  * returns true is target is a texture cube map target.
   226  */
   227 static bool
   228 IsTexImageCubemapTarget(GLenum target)
   229 {
   230     return (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
   231             target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
   232 }
   234 /*
   235  * Pull data out of the program, post-linking
   236  */
   237 bool
   238 WebGLProgram::UpdateInfo()
   239 {
   240     mIdentifierMap = nullptr;
   241     mIdentifierReverseMap = nullptr;
   242     mUniformInfoMap = nullptr;
   244     mAttribMaxNameLength = 0;
   246     for (size_t i = 0; i < mAttachedShaders.Length(); i++)
   247         mAttribMaxNameLength = std::max(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
   249     GLint attribCount;
   250     mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
   252     if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
   253         mContext->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext->mGLMaxVertexAttribs);
   254         return false;
   255     }
   257     for (size_t i = 0; i < mAttribsInUse.Length(); i++)
   258         mAttribsInUse[i] = false;
   260     nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
   262     for (int i = 0; i < attribCount; ++i) {
   263         GLint attrnamelen;
   264         GLint attrsize;
   265         GLenum attrtype;
   266         mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
   267         if (attrnamelen > 0) {
   268             GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
   269             MOZ_ASSERT(loc >= 0, "major oops in managing the attributes of a WebGL program");
   270             if (loc < mContext->mGLMaxVertexAttribs) {
   271                 mAttribsInUse[loc] = true;
   272             } else {
   273                 mContext->GenerateWarning("program exceeds MAX_VERTEX_ATTRIBS");
   274                 return false;
   275             }
   276         }
   277     }
   279     if (!mUniformInfoMap) {
   280         mUniformInfoMap = new CStringToUniformInfoMap;
   281         for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
   282             for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
   283                 const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
   284                 const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
   285                 mUniformInfoMap->Put(uniform.mapped, info);
   286             }
   287         }
   288     }
   290     mActiveAttribMap.clear();
   292     GLint numActiveAttrs = 0;
   293     mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
   295     // Spec says the maximum attrib name length is 256 chars, so this is
   296     // sufficient to hold any attrib name.
   297     char attrName[257];
   299     GLint dummySize;
   300     GLenum dummyType;
   301     for (GLint i = 0; i < numActiveAttrs; i++) {
   302         mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
   303                                        &dummyType, attrName);
   304         GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
   305         MOZ_ASSERT(attrLoc >= 0);
   306         mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
   307     }
   309     return true;
   310 }
   312 /**
   313  * Return the simple base format for a given internal format.
   314  *
   315  * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
   316  * GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA), or GL_NONE if invalid enum.
   317  */
   318 GLenum
   319 WebGLContext::BaseTexFormat(GLenum internalFormat) const
   320 {
   321     if (internalFormat == LOCAL_GL_ALPHA ||
   322         internalFormat == LOCAL_GL_LUMINANCE ||
   323         internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
   324         internalFormat == LOCAL_GL_RGB ||
   325         internalFormat == LOCAL_GL_RGBA)
   326     {
   327         return internalFormat;
   328     }
   330     if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
   331         if (internalFormat == LOCAL_GL_SRGB)
   332             return LOCAL_GL_RGB;
   334         if (internalFormat == LOCAL_GL_SRGB_ALPHA)
   335             return LOCAL_GL_RGBA;
   336     }
   338     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc)) {
   339         if (internalFormat == LOCAL_GL_ATC_RGB)
   340             return LOCAL_GL_RGB;
   342         if (internalFormat == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
   343             internalFormat == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
   344         {
   345             return LOCAL_GL_RGBA;
   346         }
   347     }
   349     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1)) {
   350         if (internalFormat == LOCAL_GL_ETC1_RGB8_OES)
   351             return LOCAL_GL_RGB;
   352     }
   354     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) {
   355         if (internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
   356             internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1)
   357         {
   358             return LOCAL_GL_RGB;
   359         }
   361         if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
   362             internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
   363         {
   364             return LOCAL_GL_RGBA;
   365         }
   366     }
   368     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc)) {
   369         if (internalFormat == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
   370             return LOCAL_GL_RGB;
   372         if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
   373             internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
   374             internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
   375         {
   376             return LOCAL_GL_RGBA;
   377         }
   378     }
   380     if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
   381         if (internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
   382             internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
   383             internalFormat == LOCAL_GL_DEPTH_COMPONENT32)
   384         {
   385             return LOCAL_GL_DEPTH_COMPONENT;
   386         }
   388         if (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
   389             internalFormat == LOCAL_GL_DEPTH24_STENCIL8)
   390         {
   391             return LOCAL_GL_DEPTH_STENCIL;
   392         }
   393     }
   395     MOZ_ASSERT(false, "Unhandled internalFormat");
   396     return LOCAL_GL_NONE;
   397 }
   399 bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char *info)
   400 {
   401     switch (mode) {
   402         case LOCAL_GL_FUNC_ADD:
   403         case LOCAL_GL_FUNC_SUBTRACT:
   404         case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
   405             return true;
   406         case LOCAL_GL_MIN:
   407         case LOCAL_GL_MAX:
   408             if (IsWebGL2()) {
   409                 // http://www.opengl.org/registry/specs/EXT/blend_minmax.txt
   410                 return true;
   411             }
   412             break;
   413         default:
   414             break;
   415     }
   417     ErrorInvalidEnumInfo(info, mode);
   418     return false;
   419 }
   421 bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char *info)
   422 {
   423     switch (factor) {
   424         case LOCAL_GL_ZERO:
   425         case LOCAL_GL_ONE:
   426         case LOCAL_GL_SRC_COLOR:
   427         case LOCAL_GL_ONE_MINUS_SRC_COLOR:
   428         case LOCAL_GL_DST_COLOR:
   429         case LOCAL_GL_ONE_MINUS_DST_COLOR:
   430         case LOCAL_GL_SRC_ALPHA:
   431         case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
   432         case LOCAL_GL_DST_ALPHA:
   433         case LOCAL_GL_ONE_MINUS_DST_ALPHA:
   434         case LOCAL_GL_CONSTANT_COLOR:
   435         case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
   436         case LOCAL_GL_CONSTANT_ALPHA:
   437         case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
   438             return true;
   439         default:
   440             ErrorInvalidEnumInfo(info, factor);
   441             return false;
   442     }
   443 }
   445 bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char *info)
   446 {
   447     if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
   448         return true;
   449     else
   450         return ValidateBlendFuncDstEnum(factor, info);
   451 }
   453 bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info)
   454 {
   455     bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
   456                                     sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
   457     bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
   458                                     sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
   459     bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
   460                                     dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
   461     bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
   462                                     dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
   463     if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
   464          (dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
   465         ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
   466         return false;
   467     } else {
   468         return true;
   469     }
   470 }
   472 bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
   473 {
   474     switch (target) {
   475         case LOCAL_GL_TEXTURE_2D:
   476         case LOCAL_GL_TEXTURE_CUBE_MAP:
   477             return true;
   478         default:
   479             ErrorInvalidEnumInfo(info, target);
   480             return false;
   481     }
   482 }
   484 bool WebGLContext::ValidateComparisonEnum(GLenum target, const char *info)
   485 {
   486     switch (target) {
   487         case LOCAL_GL_NEVER:
   488         case LOCAL_GL_LESS:
   489         case LOCAL_GL_LEQUAL:
   490         case LOCAL_GL_GREATER:
   491         case LOCAL_GL_GEQUAL:
   492         case LOCAL_GL_EQUAL:
   493         case LOCAL_GL_NOTEQUAL:
   494         case LOCAL_GL_ALWAYS:
   495             return true;
   496         default:
   497             ErrorInvalidEnumInfo(info, target);
   498             return false;
   499     }
   500 }
   502 bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char *info)
   503 {
   504     switch (action) {
   505         case LOCAL_GL_KEEP:
   506         case LOCAL_GL_ZERO:
   507         case LOCAL_GL_REPLACE:
   508         case LOCAL_GL_INCR:
   509         case LOCAL_GL_INCR_WRAP:
   510         case LOCAL_GL_DECR:
   511         case LOCAL_GL_DECR_WRAP:
   512         case LOCAL_GL_INVERT:
   513             return true;
   514         default:
   515             ErrorInvalidEnumInfo(info, action);
   516             return false;
   517     }
   518 }
   520 bool WebGLContext::ValidateFaceEnum(GLenum face, const char *info)
   521 {
   522     switch (face) {
   523         case LOCAL_GL_FRONT:
   524         case LOCAL_GL_BACK:
   525         case LOCAL_GL_FRONT_AND_BACK:
   526             return true;
   527         default:
   528             ErrorInvalidEnumInfo(info, face);
   529             return false;
   530     }
   531 }
   533 bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char *info)
   534 {
   535     switch (mode) {
   536         case LOCAL_GL_TRIANGLES:
   537         case LOCAL_GL_TRIANGLE_STRIP:
   538         case LOCAL_GL_TRIANGLE_FAN:
   539         case LOCAL_GL_POINTS:
   540         case LOCAL_GL_LINE_STRIP:
   541         case LOCAL_GL_LINE_LOOP:
   542         case LOCAL_GL_LINES:
   543             return true;
   544         default:
   545             ErrorInvalidEnumInfo(info, mode);
   546             return false;
   547     }
   548 }
   550 bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
   551 {
   552     if (name.IsEmpty())
   553         return false;
   555     const uint32_t maxSize = 256;
   556     if (name.Length() > maxSize) {
   557         ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
   558                           info, name.Length(), maxSize);
   559         return false;
   560     }
   562     if (!ValidateGLSLString(name, info)) {
   563         return false;
   564     }
   566     nsString prefix1 = NS_LITERAL_STRING("webgl_");
   567     nsString prefix2 = NS_LITERAL_STRING("_webgl_");
   569     if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
   570         Substring(name, 0, prefix2.Length()).Equals(prefix2))
   571     {
   572         ErrorInvalidOperation("%s: string contains a reserved GLSL prefix", info);
   573         return false;
   574     }
   576     return true;
   577 }
   579 bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
   580 {
   581     for (uint32_t i = 0; i < string.Length(); ++i) {
   582         if (!ValidateGLSLCharacter(string.CharAt(i))) {
   583              ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
   584              return false;
   585         }
   586     }
   588     return true;
   589 }
   591 /**
   592  * Return true if format is a valid texture image format for source,
   593  * taking into account enabled WebGL extensions.
   594  */
   595 bool
   596 WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
   597 {
   598     /* Core WebGL texture formats */
   599     if (format == LOCAL_GL_ALPHA ||
   600         format == LOCAL_GL_RGB ||
   601         format == LOCAL_GL_RGBA ||
   602         format == LOCAL_GL_LUMINANCE ||
   603         format == LOCAL_GL_LUMINANCE_ALPHA)
   604     {
   605         return true;
   606     }
   608     /* Only core formats are valid for CopyTex(Sub)?Image */
   609     // TODO: Revisit this once color_buffer_(half_)?float lands
   610     if (IsCopyFunc(func)) {
   611         ErrorInvalidEnumWithName(this, "invalid format", format, func);
   612         return false;
   613     }
   615     /* WEBGL_depth_texture added formats */
   616     if (format == LOCAL_GL_DEPTH_COMPONENT ||
   617         format == LOCAL_GL_DEPTH_STENCIL)
   618     {
   619         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
   620         if (!validFormat)
   621             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
   622                              InfoFrom(func), NameFrom(format));
   623         return validFormat;
   624     }
   626     /* EXT_sRGB added formats */
   627     if (format == LOCAL_GL_SRGB ||
   628         format == LOCAL_GL_SRGB_ALPHA)
   629     {
   630         bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
   631         if (!validFormat)
   632             ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
   633                              InfoFrom(func), NameFrom(format));
   634         return validFormat;
   635     }
   637     /* WEBGL_compressed_texture_atc added formats */
   638     if (format == LOCAL_GL_ATC_RGB ||
   639         format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
   640         format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
   641     {
   642         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
   643         if (!validFormat)
   644             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
   645                              InfoFrom(func), NameFrom(format));
   646         return validFormat;
   647     }
   649     // WEBGL_compressed_texture_etc1
   650     if (format == LOCAL_GL_ETC1_RGB8_OES) {
   651         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
   652         if (!validFormat)
   653             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
   654                              InfoFrom(func), NameFrom(format));
   655         return validFormat;
   656     }
   659     if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
   660         format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
   661         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
   662         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
   663     {
   664         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
   665         if (!validFormat)
   666             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
   667                              InfoFrom(func), NameFrom(format));
   668         return validFormat;
   669     }
   672     if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
   673         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
   674         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
   675         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
   676     {
   677         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
   678         if (!validFormat)
   679             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
   680                              InfoFrom(func), NameFrom(format));
   681         return validFormat;
   682     }
   684     ErrorInvalidEnumWithName(this, "invalid format", format, func);
   686     return false;
   687 }
   689 /**
   690  * Check if the given texture target is valid for TexImage.
   691  */
   692 bool
   693 WebGLContext::ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func)
   694 {
   695     switch (dims) {
   696     case 2:
   697         if (target == LOCAL_GL_TEXTURE_2D ||
   698             IsTexImageCubemapTarget(target))
   699         {
   700             return true;
   701         }
   703         ErrorInvalidEnumWithName(this, "invalid target", target, func);
   704         return false;
   706     default:
   707         MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
   708     }
   710     return false;
   711 }
   713 /**
   714  * Return true if type is a valid texture image type for source,
   715  * taking into account enabled WebGL extensions.
   716  */
   717 bool
   718 WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func)
   719 {
   720     /* Core WebGL texture types */
   721     if (type == LOCAL_GL_UNSIGNED_BYTE ||
   722         type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
   723         type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
   724         type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
   725     {
   726         return true;
   727     }
   729     /* OES_texture_float added types */
   730     if (type == LOCAL_GL_FLOAT) {
   731         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
   732         if (!validType)
   733             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
   734                              InfoFrom(func), NameFrom(type));
   735         return validType;
   736     }
   738     /* OES_texture_half_float add types */
   739     if (type == LOCAL_GL_HALF_FLOAT_OES) {
   740         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
   741         if (!validType)
   742             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
   743                              InfoFrom(func), NameFrom(type));
   744         return validType;
   745     }
   747     /* WEBGL_depth_texture added types */
   748     if (type == LOCAL_GL_UNSIGNED_SHORT ||
   749         type == LOCAL_GL_UNSIGNED_INT ||
   750         type == LOCAL_GL_UNSIGNED_INT_24_8)
   751     {
   752         bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
   753         if (!validType)
   754             ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
   755                              InfoFrom(func), NameFrom(type));
   756         return validType;
   757     }
   759     ErrorInvalidEnumWithName(this, "invalid type", type, func);
   760     return false;
   761 }
   763 /**
   764  * Validate texture image sizing extra constraints for
   765  * CompressedTex(Sub)?Image.
   766  */
   767 // TODO: WebGL 2
   768 bool
   769 WebGLContext::ValidateCompTexImageSize(GLenum target, GLint level, GLenum format,
   770                                        GLint xoffset, GLint yoffset,
   771                                        GLsizei width, GLsizei height,
   772                                        GLsizei levelWidth, GLsizei levelHeight,
   773                                        WebGLTexImageFunc func)
   774 {
   775     // Negative parameters must already have been handled above
   776     MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
   777                width >= 0 && height >= 0);
   779     if (xoffset + width > (GLint) levelWidth) {
   780         ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
   781         return false;
   782     }
   784     if (yoffset + height > (GLint) levelHeight) {
   785         ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
   786         return false;
   787     }
   789     GLint blockWidth = 1;
   790     GLint blockHeight = 1;
   791     BlockSizeFor(format, &blockWidth, &blockHeight);
   793     /* If blockWidth || blockHeight != 1, then the compressed format
   794      * had block-based constraints to be checked. (For example, PVRTC is compressed but
   795      * isn't a block-based format)
   796      */
   797     if (blockWidth != 1 || blockHeight != 1) {
   798         /* offsets must be multiple of block size */
   799         if (xoffset % blockWidth != 0) {
   800             ErrorInvalidOperation("%s: xoffset must be multiple of %d",
   801                                   InfoFrom(func), blockWidth);
   802             return false;
   803         }
   805         if (yoffset % blockHeight != 0) {
   806             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
   807                                   InfoFrom(func), blockHeight);
   808             return false;
   809         }
   811         /* The size must be a multiple of blockWidth and blockHeight,
   812          * or must be using offset+size that exactly hits the edge.
   813          * Important for small mipmap levels.
   814          */
   815         /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
   816          * "When level equals zero width and height must be a multiple of 4. When
   817          *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
   818          *  If they are not an INVALID_OPERATION error is generated."
   819          */
   820         if (level == 0) {
   821             if (width % blockWidth != 0) {
   822                 ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
   823                                       InfoFrom(func), blockWidth);
   824                 return false;
   825             }
   827             if (height % blockHeight != 0) {
   828                 ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
   829                                       InfoFrom(func), blockHeight);
   830                 return false;
   831             }
   832         }
   833         else if (level > 0) {
   834             if (width % blockWidth != 0 && width > 2) {
   835                 ErrorInvalidOperation("%s: width of level %d must be multiple"
   836                                       " of %d or 0, 1, 2",
   837                                       InfoFrom(func), level, blockWidth);
   838                 return false;
   839             }
   841             if (height % blockHeight != 0 && height > 2) {
   842                 ErrorInvalidOperation("%s: height of level %d must be multiple"
   843                                       " of %d or 0, 1, 2",
   844                                       InfoFrom(func), level, blockHeight);
   845                 return false;
   846             }
   847         }
   849         if (IsSubFunc(func)) {
   850             if ((xoffset % blockWidth) != 0) {
   851                 ErrorInvalidOperation("%s: xoffset must be multiple of %d",
   852                                       InfoFrom(func), blockWidth);
   853                 return false;
   854             }
   856             if (yoffset % blockHeight != 0) {
   857                 ErrorInvalidOperation("%s: yoffset must be multiple of %d",
   858                                       InfoFrom(func), blockHeight);
   859                 return false;
   860             }
   861         }
   862     }
   864     switch (format) {
   865     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   866     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   867     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   868     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   869         if (!is_pot_assuming_nonnegative(width) ||
   870             !is_pot_assuming_nonnegative(height))
   871         {
   872             ErrorInvalidValue("%s: width and height must be powers of two",
   873                               InfoFrom(func));
   874             return false;
   875         }
   876     }
   878     return true;
   879 }
   881 /**
   882  * Return true if the enough data is present to satisfy compressed
   883  * texture format constraints.
   884  */
   885 bool
   886 WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
   887                                            GLsizei width, GLsizei height,
   888                                            uint32_t byteLength, WebGLTexImageFunc func)
   889 {
   890     // negative width and height must already have been handled above
   891     MOZ_ASSERT(width >= 0 && height >= 0);
   893     CheckedUint32 required_byteLength = 0;
   895     switch (format) {
   896         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
   897         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
   898         case LOCAL_GL_ATC_RGB:
   899         case LOCAL_GL_ETC1_RGB8_OES:
   900         {
   901             required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
   902             break;
   903         }
   904         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
   905         case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
   906         case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
   907         case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
   908         {
   909             required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
   910             break;
   911         }
   912         case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   913         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   914         {
   915             required_byteLength = CheckedUint32(std::max(width, 8)) * CheckedUint32(std::max(height, 8)) / 2;
   916             break;
   917         }
   918         case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   919         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   920         {
   921             required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
   922             break;
   923         }
   924     }
   926     if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
   927         ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
   928         return false;
   929     }
   931     return true;
   932 }
   934 /**
   935  * Validate the width, height, and depth of a texture image, \return
   936  * true is valid, false otherwise.
   937  * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
   938  * Target and level must have been validated before calling.
   939  */
   940 bool
   941 WebGLContext::ValidateTexImageSize(GLenum target, GLint level,
   942                                    GLint width, GLint height, GLint depth,
   943                                    WebGLTexImageFunc func)
   944 {
   945     MOZ_ASSERT(level >= 0, "level should already be validated");
   947     /* Bug 966630: maxTextureSize >> level runs into "undefined"
   948      * behaviour depending on ISA. For example, on Intel shifts
   949      * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
   950      * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
   951      * what would be expected. Make the required behaviour explicit by
   952      * clamping to a shift of 31 bits if level is greater than that
   953      * ammount. This will give 0 that if (!maxAllowedSize) is
   954      * expecting.
   955      */
   957     if (level > 31)
   958         level = 31;
   960     const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level;
   961     const bool isCubemapTarget = IsTexImageCubemapTarget(target);
   962     const bool isSub = IsSubFunc(func);
   964     if (!isSub && isCubemapTarget && (width != height)) {
   965         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   966          *   "When the target parameter to TexImage2D is one of the
   967          *   six cube map two-dimensional image targets, the error
   968          *   INVALID_VALUE is generated if the width and height
   969          *   parameters are not equal."
   970          */
   971         ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
   972         return false;
   973     }
   975     if (target == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
   976     {
   977         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   978          *   "If wt and ht are the specified image width and height,
   979          *   and if either wt or ht are less than zero, then the error
   980          *   INVALID_VALUE is generated."
   981          */
   982         if (width < 0) {
   983             ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
   984             return false;
   985         }
   987         if (height < 0) {
   988             ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
   989             return false;
   990         }
   992         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   993          *   "The maximum allowable width and height of a
   994          *   two-dimensional texture image must be at least 2**(k−lod)
   995          *   for image arrays of level zero through k, where k is the
   996          *   log base 2 of MAX_TEXTURE_SIZE. and lod is the
   997          *   level-of-detail of the image array. It may be zero for
   998          *   image arrays of any level-of-detail greater than k. The
   999          *   error INVALID_VALUE is generated if the specified image
  1000          *   is too large to be stored under any conditions.
  1001          */
  1002         if (width > (int) maxTexImageSize) {
  1003             ErrorInvalidValue("%s: the maximum width for level %d is %u",
  1004                               InfoFrom(func), level, maxTexImageSize);
  1005             return false;
  1008         if (height > (int) maxTexImageSize) {
  1009             ErrorInvalidValue("%s: tex maximum height for level %d is %u",
  1010                               InfoFrom(func), level, maxTexImageSize);
  1011             return false;
  1014         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
  1015          *   "If level is greater than zero, and either width or
  1016          *   height is not a power-of-two, the error INVALID_VALUE is
  1017          *   generated."
  1018          */
  1019         if (level > 0) {
  1020             if (!is_pot_assuming_nonnegative(width)) {
  1021                 ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
  1022                                   InfoFrom(func), width);
  1023                 return false;
  1026             if (!is_pot_assuming_nonnegative(height)) {
  1027                 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
  1028                                   InfoFrom(func), height);
  1029                 return false;
  1034     // TODO: WebGL 2
  1035     if (target == LOCAL_GL_TEXTURE_3D) {
  1036         if (depth < 0) {
  1037             ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
  1038             return false;
  1041         if (!is_pot_assuming_nonnegative(depth)) {
  1042             ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
  1043                               InfoFrom(func), depth);
  1044             return false;
  1048     return true;
  1051 /**
  1052  * Validate texture image sizing for Tex(Sub)?Image variants.
  1053  */
  1054 // TODO: WebGL 2. Update this to handle 3D textures.
  1055 bool
  1056 WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
  1057                                       GLsizei width, GLsizei height, GLsizei /*depth*/,
  1058                                       GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
  1059                                       WebGLTexImageFunc func)
  1061     /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
  1062      *   "Taking wt and ht to be the specified width and height of the
  1063      *   texture array, and taking x, y, w, and h to be the xoffset,
  1064      *   yoffset, width, and height argument values, any of the
  1065      *   following relationships generates the error INVALID_VALUE:
  1066      *       x < 0
  1067      *       x + w > wt
  1068      *       y < 0
  1069      *       y + h > ht"
  1070      */
  1072     if (xoffset < 0) {
  1073         ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
  1074         return false;
  1077     if (yoffset < 0) {
  1078         ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
  1079         return false;
  1082     if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
  1083         ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
  1084         return false;
  1087     return true;
  1090 /**
  1091  * Return the bits per texel for format & type combination.
  1092  * Assumes that format & type are a valid combination as checked with
  1093  * ValidateTexImageFormatAndType().
  1094  */
  1095 uint32_t
  1096 WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
  1098     // If there is no defined format or type, we're not taking up any memory
  1099     if (!format || !type) {
  1100         return 0;
  1103     /* Known fixed-sized types */
  1104     if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
  1105         type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
  1106         type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
  1108         return 16;
  1111     if (type == LOCAL_GL_UNSIGNED_INT_24_8)
  1112         return 32;
  1114     int bitsPerComponent = 0;
  1115     switch (type) {
  1116     case LOCAL_GL_UNSIGNED_BYTE:
  1117         bitsPerComponent = 8;
  1118         break;
  1120     case LOCAL_GL_HALF_FLOAT:
  1121     case LOCAL_GL_HALF_FLOAT_OES:
  1122     case LOCAL_GL_UNSIGNED_SHORT:
  1123         bitsPerComponent = 16;
  1124         break;
  1126     case LOCAL_GL_FLOAT:
  1127     case LOCAL_GL_UNSIGNED_INT:
  1128         bitsPerComponent = 32;
  1129         break;
  1131     default:
  1132         MOZ_ASSERT(false, "Unhandled type.");
  1133         break;
  1136     switch (format) {
  1137         // Uncompressed formats
  1138     case LOCAL_GL_ALPHA:
  1139     case LOCAL_GL_LUMINANCE:
  1140     case LOCAL_GL_DEPTH_COMPONENT:
  1141     case LOCAL_GL_DEPTH_STENCIL:
  1142         return 1 * bitsPerComponent;
  1144     case LOCAL_GL_LUMINANCE_ALPHA:
  1145         return 2 * bitsPerComponent;
  1147     case LOCAL_GL_RGB:
  1148     case LOCAL_GL_RGB32F:
  1149     case LOCAL_GL_SRGB_EXT:
  1150         return 3 * bitsPerComponent;
  1152     case LOCAL_GL_RGBA:
  1153     case LOCAL_GL_RGBA32F:
  1154     case LOCAL_GL_SRGB_ALPHA_EXT:
  1155         return 4 * bitsPerComponent;
  1157         // Compressed formats
  1158     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
  1159     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
  1160         return 2;
  1162     case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  1163     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1164     case LOCAL_GL_ATC_RGB:
  1165     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
  1166     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
  1167     case LOCAL_GL_ETC1_RGB8_OES:
  1168         return 4;
  1170     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1171     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1172     case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
  1173     case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
  1174         return 8;
  1176     default:
  1177         break;
  1180     MOZ_ASSERT(false, "Unhandled format+type combo.");
  1181     return 0;
  1184 /**
  1185  * Perform validation of format/type combinations for TexImage variants.
  1186  * Returns true if the format/type is a valid combination, false otherwise.
  1187  */
  1188 bool
  1189 WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func)
  1191     if (!ValidateTexImageFormat(format, func) ||
  1192         !ValidateTexImageType(type, func))
  1194         return false;
  1197     bool validCombo = false;
  1199     switch (format) {
  1200     case LOCAL_GL_ALPHA:
  1201     case LOCAL_GL_LUMINANCE:
  1202     case LOCAL_GL_LUMINANCE_ALPHA:
  1203         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1204                       type == LOCAL_GL_HALF_FLOAT ||
  1205                       type == LOCAL_GL_HALF_FLOAT_OES ||
  1206                       type == LOCAL_GL_FLOAT);
  1207         break;
  1209     case LOCAL_GL_RGB:
  1210     case LOCAL_GL_SRGB:
  1211         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1212                       type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
  1213                       type == LOCAL_GL_HALF_FLOAT ||
  1214                       type == LOCAL_GL_HALF_FLOAT_OES ||
  1215                       type == LOCAL_GL_FLOAT);
  1216         break;
  1218     case LOCAL_GL_RGBA:
  1219     case LOCAL_GL_SRGB_ALPHA:
  1220         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1221                       type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
  1222                       type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
  1223                       type == LOCAL_GL_HALF_FLOAT ||
  1224                       type == LOCAL_GL_HALF_FLOAT_OES ||
  1225                       type == LOCAL_GL_FLOAT);
  1226         break;
  1228     case LOCAL_GL_DEPTH_COMPONENT:
  1229         validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
  1230                       type == LOCAL_GL_UNSIGNED_INT);
  1231         break;
  1233     case LOCAL_GL_DEPTH_STENCIL:
  1234         validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
  1235         break;
  1237     case LOCAL_GL_ATC_RGB:
  1238     case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
  1239     case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
  1240     case LOCAL_GL_ETC1_RGB8_OES:
  1241     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
  1242     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
  1243     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
  1244     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
  1245     case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  1246     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1247     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1248     case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1249         validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
  1250         break;
  1252     default:
  1253         // Only valid formats should be passed to the switch stmt.
  1254         MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
  1255         validCombo = false;
  1256         // Fall through to return an InvalidOperations. This will alert us to the
  1257         // unexpected case that needs fixing in builds without asserts.
  1260     if (!validCombo)
  1261         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
  1262                               InfoFrom(func), NameFrom(format), NameFrom(type));
  1264     return validCombo;
  1267 /**
  1268  * Return true if format, type and jsArrayType are a valid combination.
  1269  * Also returns the size for texel of format and type (in bytes) via
  1270  * \a texelSize.
  1272  * It is assumed that type has previously been validated.
  1273  */
  1274 bool
  1275 WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
  1277     bool validInput = false;
  1278     const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
  1280     // First, we check for packed types
  1281     switch (type) {
  1282     case LOCAL_GL_UNSIGNED_BYTE:
  1283         validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT8);
  1284         break;
  1286         // TODO: WebGL spec doesn't allow half floats to specified as UInt16.
  1287     case LOCAL_GL_HALF_FLOAT:
  1288     case LOCAL_GL_HALF_FLOAT_OES:
  1289         validInput = (jsArrayType == -1);
  1290         break;
  1292     case LOCAL_GL_UNSIGNED_SHORT:
  1293     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1294     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1295     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1296         validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT16);
  1297         break;
  1299     case LOCAL_GL_UNSIGNED_INT:
  1300     case LOCAL_GL_UNSIGNED_INT_24_8:
  1301         validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT32);
  1302         break;
  1304     case LOCAL_GL_FLOAT:
  1305         validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_FLOAT32);
  1306         break;
  1308     default:
  1309         break;
  1312     if (!validInput)
  1313         ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
  1315     return validInput;
  1318 /**
  1319  * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
  1320  * Verifies each of the parameters against the WebGL standard and enabled extensions.
  1321  */
  1322 // TODO: Texture dims is here for future expansion in WebGL 2.0
  1323 bool
  1324 WebGLContext::ValidateTexImage(GLuint dims, GLenum target,
  1325                                GLint level, GLint internalFormat,
  1326                                GLint xoffset, GLint yoffset, GLint zoffset,
  1327                                GLint width, GLint height, GLint depth,
  1328                                GLint border, GLenum format, GLenum type,
  1329                                WebGLTexImageFunc func)
  1331     const char* info = InfoFrom(func);
  1333     /* Check target */
  1334     if (!ValidateTexImageTarget(dims, target, func))
  1335         return false;
  1337     /* Check level */
  1338     if (level < 0) {
  1339         ErrorInvalidValue("%s: level must be >= 0", info);
  1340         return false;
  1343     /* Check border */
  1344     if (border != 0) {
  1345         ErrorInvalidValue("%s: border must be 0", info);
  1346         return false;
  1349     /* Check incoming image format and type */
  1350     if (!ValidateTexImageFormatAndType(format, type, func))
  1351         return false;
  1353     /* WebGL and OpenGL ES 2.0 impose additional restrictions on the
  1354      * combinations of format, internalFormat, and type that can be
  1355      * used.  Formats and types that require additional extensions
  1356      * (e.g., GL_FLOAT requires GL_OES_texture_float) are filtered
  1357      * elsewhere.
  1358      */
  1359     if ((GLint) format != internalFormat) {
  1360         ErrorInvalidOperation("%s: format does not match internalformat", info);
  1361         return false;
  1364     /* check internalFormat */
  1365     // TODO: Not sure if this is a bit of over kill.
  1366     if (BaseTexFormat(internalFormat) == LOCAL_GL_NONE) {
  1367         MOZ_ASSERT(false);
  1368         ErrorInvalidValue("%s:", info);
  1369         return false;
  1372     /* Check texture image size */
  1373     if (!ValidateTexImageSize(target, level, width, height, 0, func))
  1374         return false;
  1376     /* 5.14.8 Texture objects - WebGL Spec.
  1377      *   "If an attempt is made to call these functions with no
  1378      *    WebGLTexture bound (see above), an INVALID_OPERATION error
  1379      *    is generated."
  1380      */
  1381     WebGLTexture* tex = activeBoundTextureForTarget(target);
  1382     if (!tex) {
  1383         ErrorInvalidOperation("%s: no texture is bound to target %s",
  1384                               info, NameFrom(target));
  1385         return false;
  1388     if (IsSubFunc(func)) {
  1389         if (!tex->HasImageInfoAt(target, level)) {
  1390             ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
  1391                                   info, NameFrom(target), level);
  1392             return false;
  1395         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
  1396         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
  1397                                      width, height, depth,
  1398                                      imageInfo.Width(), imageInfo.Height(), 0,
  1399                                      func))
  1401             return false;
  1404         /* Require the format and type to match that of the existing
  1405          * texture as created
  1406          */
  1407         if (imageInfo.WebGLFormat() != format ||
  1408             imageInfo.WebGLType() != type)
  1410             ErrorInvalidOperation("%s: format or type doesn't match the existing texture",
  1411                                   info);
  1412             return false;
  1416     /* Additional checks for depth textures */
  1417     if (format == LOCAL_GL_DEPTH_COMPONENT ||
  1418         format == LOCAL_GL_DEPTH_STENCIL)
  1420         if (func == WebGLTexImageFunc::TexSubImage || IsCopyFunc(func)) {
  1421             ErrorInvalidOperationWithName(this, "called with format/internalformat",
  1422                                           format, func);
  1423             return false;
  1426         if (func == WebGLTexImageFunc::TexImage &&
  1427             target != LOCAL_GL_TEXTURE_2D)
  1429             ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
  1430                                   info, NameFrom(format));
  1431             return false;
  1434         if (func == WebGLTexImageFunc::TexImage && level != 0) {
  1435             ErrorInvalidOperation("%s: with format of %s target, level must be 0",
  1436                                   info, NameFrom(format));
  1437             return false;
  1441     /* Additional checks for compressed textures */
  1442     if (!IsAllowedFromSource(format, func)) {
  1443         ErrorInvalidOperation("%s: Invalid format %s for this operation",
  1444                               info, NameFrom(format));
  1445         return false;
  1448     /* Parameters are OK */
  1449     return true;
  1452 bool
  1453 WebGLContext::ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object)
  1455     if (!ValidateObjectAllowNull(info, location_object))
  1456         return false;
  1457     if (!location_object)
  1458         return false;
  1459     /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
  1460     if (!mCurrentProgram) {
  1461         ErrorInvalidOperation("%s: no program is currently bound", info);
  1462         return false;
  1464     if (mCurrentProgram != location_object->Program()) {
  1465         ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info);
  1466         return false;
  1468     if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) {
  1469         ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info);
  1470         return false;
  1472     return true;
  1475 bool
  1476 WebGLContext::ValidateSamplerUniformSetter(const char* info, WebGLUniformLocation *location, GLint value)
  1478     if (location->Info().type != SH_SAMPLER_2D &&
  1479         location->Info().type != SH_SAMPLER_CUBE)
  1481         return true;
  1484     if (value >= 0 && value < mGLMaxTextureUnits)
  1485         return true;
  1487     ErrorInvalidValue("%s: this uniform location is a sampler, but %d is not a valid texture unit",
  1488                       info, value);
  1489     return false;
  1492 bool
  1493 WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
  1495     if (IsContextLost()) {
  1496         return false;
  1498     if (arrayLength < cnt) {
  1499         ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
  1500         return false;
  1502     return true;
  1505 bool
  1506 WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
  1507                                          GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
  1509     if (IsContextLost())
  1510         return false;
  1511     if (!ValidateUniformLocation(name, location_object))
  1512         return false;
  1513     location = location_object->Location();
  1514     uint32_t uniformElemSize = location_object->ElementSize();
  1515     if (expectedElemSize != uniformElemSize) {
  1516         ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
  1517                               " got a uniform of element size %d", name,
  1518                               expectedElemSize,
  1519                               uniformElemSize);
  1520         return false;
  1522     if (arrayLength == 0 ||
  1523         arrayLength % expectedElemSize)
  1525         ErrorInvalidValue("%s: expected an array of length a multiple"
  1526                           " of %d, got an array of length %d", name,
  1527                           expectedElemSize,
  1528                           arrayLength);
  1529         return false;
  1531     const WebGLUniformInfo& info = location_object->Info();
  1532     if (!info.isArray &&
  1533         arrayLength != expectedElemSize) {
  1534         ErrorInvalidOperation("%s: expected an array of length exactly"
  1535                               " %d (since this uniform is not an array"
  1536                               " uniform), got an array of length %d", name,
  1537                               expectedElemSize,
  1538                               arrayLength);
  1539         return false;
  1541     numElementsToUpload =
  1542         std::min(info.arraySize, arrayLength / expectedElemSize);
  1543     return true;
  1546 bool
  1547 WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
  1548                                               GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
  1549                                               WebGLboolean aTranspose)
  1551     uint32_t expectedElemSize = (dim)*(dim);
  1552     if (IsContextLost())
  1553         return false;
  1554     if (!ValidateUniformLocation(name, location_object))
  1555         return false;
  1556     location = location_object->Location();
  1557     uint32_t uniformElemSize = location_object->ElementSize();
  1558     if (expectedElemSize != uniformElemSize) {
  1559         ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
  1560                               " got a uniform of element size %d", name,
  1561                               expectedElemSize,
  1562                               uniformElemSize);
  1563         return false;
  1565     if (arrayLength == 0 ||
  1566         arrayLength % expectedElemSize)
  1568         ErrorInvalidValue("%s: expected an array of length a multiple"
  1569                           " of %d, got an array of length %d", name,
  1570                           expectedElemSize,
  1571                           arrayLength);
  1572         return false;
  1574     const WebGLUniformInfo& info = location_object->Info();
  1575     if (!info.isArray &&
  1576         arrayLength != expectedElemSize) {
  1577         ErrorInvalidOperation("%s: expected an array of length exactly"
  1578                               " %d (since this uniform is not an array"
  1579                               " uniform), got an array of length %d", name,
  1580                               expectedElemSize,
  1581                               arrayLength);
  1582         return false;
  1584     if (aTranspose) {
  1585         ErrorInvalidValue("%s: transpose must be FALSE as per the "
  1586                           "OpenGL ES 2.0 spec", name);
  1587         return false;
  1589     numElementsToUpload =
  1590         std::min(info.arraySize, arrayLength / (expectedElemSize));
  1591     return true;
  1594 bool
  1595 WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
  1597     if (IsContextLost())
  1598         return false;
  1599     if (!ValidateUniformLocation(name, location_object))
  1600         return false;
  1601     location = location_object->Location();
  1602     return true;
  1605 bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
  1607     return mBoundVertexArray->EnsureAttrib(index, info);
  1610 bool WebGLContext::ValidateStencilParamsForDrawCall()
  1612   const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
  1613   if (mStencilRefFront != mStencilRefBack) {
  1614       ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
  1615       return false;
  1617   if (mStencilValueMaskFront != mStencilValueMaskBack) {
  1618       ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
  1619       return false;
  1621   if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
  1622       ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
  1623       return false;
  1625   return true;
  1628 static inline int32_t floorPOT(int32_t x)
  1630     MOZ_ASSERT(x > 0);
  1631     int32_t pot = 1;
  1632     while (pot < 0x40000000) {
  1633         if (x < pot*2)
  1634             break;
  1635         pot *= 2;
  1637     return pot;
  1640 bool
  1641 WebGLContext::InitAndValidateGL()
  1643     if (!gl) return false;
  1645     GLenum error = gl->fGetError();
  1646     if (error != LOCAL_GL_NO_ERROR) {
  1647         GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
  1648         return false;
  1651     mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
  1652     mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
  1653     mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
  1654     mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
  1656     if (MinCapabilityMode()) {
  1657       mDisableFragHighP = true;
  1660     // These are the default values, see 6.2 State tables in the
  1661     // OpenGL ES 2.0.25 spec.
  1662     mColorWriteMask[0] = 1;
  1663     mColorWriteMask[1] = 1;
  1664     mColorWriteMask[2] = 1;
  1665     mColorWriteMask[3] = 1;
  1666     mDepthWriteMask = 1;
  1667     mColorClearValue[0] = 0.f;
  1668     mColorClearValue[1] = 0.f;
  1669     mColorClearValue[2] = 0.f;
  1670     mColorClearValue[3] = 0.f;
  1671     mDepthClearValue = 1.f;
  1672     mStencilClearValue = 0;
  1673     mStencilRefFront = 0;
  1674     mStencilRefBack = 0;
  1675     mStencilValueMaskFront = 0xffffffff;
  1676     mStencilValueMaskBack  = 0xffffffff;
  1677     mStencilWriteMaskFront = 0xffffffff;
  1678     mStencilWriteMaskBack  = 0xffffffff;
  1680     // Bindings, etc.
  1681     mActiveTexture = 0;
  1682     mEmitContextLostErrorOnce = true;
  1683     mWebGLError = LOCAL_GL_NO_ERROR;
  1684     mUnderlyingGLError = LOCAL_GL_NO_ERROR;
  1686     mBound2DTextures.Clear();
  1687     mBoundCubeMapTextures.Clear();
  1689     mBoundArrayBuffer = nullptr;
  1690     mBoundTransformFeedbackBuffer = nullptr;
  1691     mCurrentProgram = nullptr;
  1693     mBoundFramebuffer = nullptr;
  1694     mBoundRenderbuffer = nullptr;
  1696     MakeContextCurrent();
  1698     // on desktop OpenGL, we always keep vertex attrib 0 array enabled
  1699     if (!gl->IsGLES()) {
  1700         gl->fEnableVertexAttribArray(0);
  1703     if (MinCapabilityMode()) {
  1704         mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
  1705     } else {
  1706         gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
  1708     if (mGLMaxVertexAttribs < 8) {
  1709         GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
  1710         return false;
  1713     // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
  1714     // even though the hardware supports much more.  The
  1715     // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
  1716     if (MinCapabilityMode()) {
  1717         mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
  1718     } else {
  1719         gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
  1721     if (mGLMaxTextureUnits < 8) {
  1722         GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
  1723         return false;
  1726     mBound2DTextures.SetLength(mGLMaxTextureUnits);
  1727     mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
  1729     if (MinCapabilityMode()) {
  1730         mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
  1731         mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
  1732         mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
  1733         mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
  1734         mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
  1735     } else {
  1736         gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
  1737         gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
  1738         gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
  1739         gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
  1740         gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
  1743     mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
  1744     mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);
  1746     if (MinCapabilityMode()) {
  1747         mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
  1748         mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
  1749         mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
  1750     } else {
  1751         if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
  1752             gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
  1753             gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
  1754             gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
  1755         } else {
  1756             gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
  1757             mGLMaxFragmentUniformVectors /= 4;
  1758             gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
  1759             mGLMaxVertexUniformVectors /= 4;
  1761             // we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
  1762             // however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
  1763             // and check OpenGL error for INVALID_ENUM.
  1765             // before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
  1766             error = gl->GetAndClearError();
  1767             if (error != LOCAL_GL_NO_ERROR) {
  1768                 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1769                 return false;
  1772             // On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
  1773             //   mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
  1774             GLint maxVertexOutputComponents,
  1775                   minFragmentInputComponents;
  1776             gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
  1777             gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
  1779             error = gl->GetAndClearError();
  1780             switch (error) {
  1781                 case LOCAL_GL_NO_ERROR:
  1782                     mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
  1783                     break;
  1784                 case LOCAL_GL_INVALID_ENUM:
  1785                     mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
  1786                     break;
  1787                 default:
  1788                     GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1789                     return false;
  1794     // Always 1 for GLES2
  1795     mMaxFramebufferColorAttachments = 1;
  1797     if (!gl->IsGLES()) {
  1798         // gl_PointSize is always available in ES2 GLSL, but has to be
  1799         // specifically enabled on desktop GLSL.
  1800         gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
  1802         // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
  1803         // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
  1804         //   http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
  1805         // Note that this used to cause crashes on old ATI drivers... hopefully not a significant
  1806         // problem anymore. See bug 602183.
  1807         gl->fEnable(LOCAL_GL_POINT_SPRITE);
  1810 #ifdef XP_MACOSX
  1811     if (gl->WorkAroundDriverBugs() &&
  1812         gl->Vendor() == gl::GLVendor::ATI) {
  1813         // The Mac ATI driver, in all known OSX version up to and including 10.8,
  1814         // renders points sprites upside-down. Apple bug 11778921
  1815         gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN, LOCAL_GL_LOWER_LEFT);
  1817 #endif
  1819     // Check the shader validator pref
  1820     NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
  1822     mShaderValidation =
  1823         Preferences::GetBool("webgl.shader_validator", mShaderValidation);
  1825     // initialize shader translator
  1826     if (mShaderValidation) {
  1827         if (!ShInitialize()) {
  1828             GenerateWarning("GLSL translator initialization failed!");
  1829             return false;
  1833     // Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
  1834     mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
  1836     // notice that the point of calling GetAndClearError here is not only to check for error,
  1837     // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
  1838     error = gl->GetAndClearError();
  1839     if (error != LOCAL_GL_NO_ERROR) {
  1840         GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1841         return false;
  1844     if (IsWebGL2() &&
  1845         !InitWebGL2())
  1847         // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
  1848         return false;
  1851     mMemoryPressureObserver
  1852         = new WebGLMemoryPressureObserver(this);
  1853     nsCOMPtr<nsIObserverService> observerService
  1854         = mozilla::services::GetObserverService();
  1855     if (observerService) {
  1856         observerService->AddObserver(mMemoryPressureObserver,
  1857                                      "memory-pressure",
  1858                                      false);
  1861     mDefaultVertexArray = new WebGLVertexArray(this);
  1862     mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
  1863     mBoundVertexArray = mDefaultVertexArray;
  1865     return true;

mercurial