content/canvas/src/WebGLContextValidate.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/content/canvas/src/WebGLContextValidate.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1866 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "WebGLContext.h"
    1.10 +#include "WebGLBuffer.h"
    1.11 +#include "WebGLVertexAttribData.h"
    1.12 +#include "WebGLShader.h"
    1.13 +#include "WebGLProgram.h"
    1.14 +#include "WebGLUniformLocation.h"
    1.15 +#include "WebGLFramebuffer.h"
    1.16 +#include "WebGLRenderbuffer.h"
    1.17 +#include "WebGLTexture.h"
    1.18 +#include "WebGLVertexArray.h"
    1.19 +#include "GLContext.h"
    1.20 +#include "CanvasUtils.h"
    1.21 +
    1.22 +#include "mozilla/CheckedInt.h"
    1.23 +#include "mozilla/Preferences.h"
    1.24 +#include "mozilla/Services.h"
    1.25 +
    1.26 +#include "jsfriendapi.h"
    1.27 +
    1.28 +#include "angle/ShaderLang.h"
    1.29 +
    1.30 +#include <algorithm>
    1.31 +
    1.32 +#include "mozilla/Services.h"
    1.33 +#include "nsIObserverService.h"
    1.34 +
    1.35 +using namespace mozilla;
    1.36 +
    1.37 +/**
    1.38 + * Return the block size for format.
    1.39 + */
    1.40 +static void
    1.41 +BlockSizeFor(GLenum format, GLint* blockWidth, GLint* blockHeight)
    1.42 +{
    1.43 +    MOZ_ASSERT(blockWidth && blockHeight);
    1.44 +
    1.45 +    switch (format) {
    1.46 +    case LOCAL_GL_ATC_RGB:
    1.47 +    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
    1.48 +    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
    1.49 +    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
    1.50 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
    1.51 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
    1.52 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
    1.53 +        if (blockWidth)
    1.54 +            *blockWidth = 4;
    1.55 +        if (blockHeight)
    1.56 +            *blockHeight = 4;
    1.57 +        break;
    1.58 +
    1.59 +    case LOCAL_GL_ETC1_RGB8_OES:
    1.60 +        // 4x4 blocks, but no 4-multiple requirement.
    1.61 +    default:
    1.62 +        break;
    1.63 +    }
    1.64 +}
    1.65 +
    1.66 +/**
    1.67 + * Return the displayable name for the texture function that is the
    1.68 + * source for validation.
    1.69 + */
    1.70 +static const char*
    1.71 +InfoFrom(WebGLTexImageFunc func)
    1.72 +{
    1.73 +    // TODO: Account for dimensions (WebGL 2)
    1.74 +    switch (func) {
    1.75 +    case WebGLTexImageFunc::TexImage:        return "texImage2D";
    1.76 +    case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
    1.77 +    case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
    1.78 +    case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
    1.79 +    case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
    1.80 +    case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
    1.81 +    default:
    1.82 +        MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
    1.83 +        return "(error)";
    1.84 +    }
    1.85 +}
    1.86 +
    1.87 +/**
    1.88 + * Return displayable name for GLenum.
    1.89 + * This version is like gl::GLenumToStr but with out the GL_ prefix to
    1.90 + * keep consistency with how errors are reported from WebGL.
    1.91 + */
    1.92 +static const char*
    1.93 +NameFrom(GLenum glenum)
    1.94 +{
    1.95 +    switch (glenum) {
    1.96 +#define XX(x) case LOCAL_GL_##x: return #x
    1.97 +        XX(ALPHA);
    1.98 +        XX(ATC_RGB);
    1.99 +        XX(ATC_RGBA_EXPLICIT_ALPHA);
   1.100 +        XX(ATC_RGBA_INTERPOLATED_ALPHA);
   1.101 +        XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
   1.102 +        XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
   1.103 +        XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
   1.104 +        XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
   1.105 +        XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
   1.106 +        XX(COMPRESSED_RGB_PVRTC_2BPPV1);
   1.107 +        XX(COMPRESSED_RGB_PVRTC_4BPPV1);
   1.108 +        XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
   1.109 +        XX(DEPTH_COMPONENT);
   1.110 +        XX(DEPTH_COMPONENT16);
   1.111 +        XX(DEPTH_COMPONENT32);
   1.112 +        XX(DEPTH_STENCIL);
   1.113 +        XX(DEPTH24_STENCIL8);
   1.114 +        XX(ETC1_RGB8_OES);
   1.115 +        XX(FLOAT);
   1.116 +        XX(HALF_FLOAT);
   1.117 +        XX(LUMINANCE);
   1.118 +        XX(LUMINANCE_ALPHA);
   1.119 +        XX(RGB);
   1.120 +        XX(RGB16F);
   1.121 +        XX(RGB32F);
   1.122 +        XX(RGBA);
   1.123 +        XX(RGBA16F);
   1.124 +        XX(RGBA32F);
   1.125 +        XX(SRGB);
   1.126 +        XX(SRGB_ALPHA);
   1.127 +        XX(TEXTURE_2D);
   1.128 +        XX(TEXTURE_3D);
   1.129 +        XX(TEXTURE_CUBE_MAP);
   1.130 +        XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
   1.131 +        XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
   1.132 +        XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
   1.133 +        XX(TEXTURE_CUBE_MAP_POSITIVE_X);
   1.134 +        XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
   1.135 +        XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
   1.136 +        XX(UNSIGNED_BYTE);
   1.137 +        XX(UNSIGNED_INT);
   1.138 +        XX(UNSIGNED_INT_24_8);
   1.139 +        XX(UNSIGNED_SHORT);
   1.140 +        XX(UNSIGNED_SHORT_4_4_4_4);
   1.141 +        XX(UNSIGNED_SHORT_5_5_5_1);
   1.142 +        XX(UNSIGNED_SHORT_5_6_5);
   1.143 +#undef XX
   1.144 +    }
   1.145 +
   1.146 +    return nullptr;
   1.147 +}
   1.148 +
   1.149 +/**
   1.150 + * Same as ErrorInvalidEnum but uses NameFrom to print displayable
   1.151 + * name for \a glenum.
   1.152 + */
   1.153 +static void
   1.154 +ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
   1.155 +{
   1.156 +    const char* name = NameFrom(glenum);
   1.157 +    if (name)
   1.158 +        ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
   1.159 +    else
   1.160 +        ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
   1.161 +}
   1.162 +
   1.163 +/**
   1.164 + * Same as ErrorInvalidOperation but uses NameFrom to print displayable
   1.165 + * name for \a glenum.
   1.166 + */
   1.167 +static void
   1.168 +ErrorInvalidOperationWithName(WebGLContext* ctx, const char* msg, GLenum glenum,
   1.169 +                              WebGLTexImageFunc func)
   1.170 +{
   1.171 +    const char* name = NameFrom(glenum);
   1.172 +    if (name)
   1.173 +        ctx->ErrorInvalidOperation("%s: %s %s", InfoFrom(func), msg, name);
   1.174 +    else
   1.175 +        ctx->ErrorInvalidOperation("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
   1.176 +}
   1.177 +
   1.178 +/**
   1.179 + * Return true if the format is valid for source calls.
   1.180 + */
   1.181 +static bool
   1.182 +IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
   1.183 +{
   1.184 +    switch (format) {
   1.185 +    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
   1.186 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
   1.187 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
   1.188 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
   1.189 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   1.190 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   1.191 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   1.192 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   1.193 +        return (func == WebGLTexImageFunc::CompTexImage ||
   1.194 +                func == WebGLTexImageFunc::CompTexSubImage);
   1.195 +
   1.196 +    case LOCAL_GL_ATC_RGB:
   1.197 +    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
   1.198 +    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
   1.199 +    case LOCAL_GL_ETC1_RGB8_OES:
   1.200 +        return func == WebGLTexImageFunc::CompTexImage;
   1.201 +    }
   1.202 +
   1.203 +    return true;
   1.204 +}
   1.205 +
   1.206 +/**
   1.207 + * Returns true if func is a CopyTexImage variant.
   1.208 + */
   1.209 +static bool
   1.210 +IsCopyFunc(WebGLTexImageFunc func)
   1.211 +{
   1.212 +    return (func == WebGLTexImageFunc::CopyTexImage ||
   1.213 +            func == WebGLTexImageFunc::CopyTexSubImage);
   1.214 +}
   1.215 +
   1.216 +/**
   1.217 + * Returns true if func is a SubImage variant.
   1.218 + */
   1.219 +static bool
   1.220 +IsSubFunc(WebGLTexImageFunc func)
   1.221 +{
   1.222 +    return (func == WebGLTexImageFunc::TexSubImage ||
   1.223 +            func == WebGLTexImageFunc::CopyTexSubImage ||
   1.224 +            func == WebGLTexImageFunc::CompTexSubImage);
   1.225 +}
   1.226 +
   1.227 +/**
   1.228 + * returns true is target is a texture cube map target.
   1.229 + */
   1.230 +static bool
   1.231 +IsTexImageCubemapTarget(GLenum target)
   1.232 +{
   1.233 +    return (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
   1.234 +            target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
   1.235 +}
   1.236 +
   1.237 +/*
   1.238 + * Pull data out of the program, post-linking
   1.239 + */
   1.240 +bool
   1.241 +WebGLProgram::UpdateInfo()
   1.242 +{
   1.243 +    mIdentifierMap = nullptr;
   1.244 +    mIdentifierReverseMap = nullptr;
   1.245 +    mUniformInfoMap = nullptr;
   1.246 +
   1.247 +    mAttribMaxNameLength = 0;
   1.248 +
   1.249 +    for (size_t i = 0; i < mAttachedShaders.Length(); i++)
   1.250 +        mAttribMaxNameLength = std::max(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
   1.251 +
   1.252 +    GLint attribCount;
   1.253 +    mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
   1.254 +
   1.255 +    if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
   1.256 +        mContext->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext->mGLMaxVertexAttribs);
   1.257 +        return false;
   1.258 +    }
   1.259 +
   1.260 +    for (size_t i = 0; i < mAttribsInUse.Length(); i++)
   1.261 +        mAttribsInUse[i] = false;
   1.262 +
   1.263 +    nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
   1.264 +
   1.265 +    for (int i = 0; i < attribCount; ++i) {
   1.266 +        GLint attrnamelen;
   1.267 +        GLint attrsize;
   1.268 +        GLenum attrtype;
   1.269 +        mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
   1.270 +        if (attrnamelen > 0) {
   1.271 +            GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
   1.272 +            MOZ_ASSERT(loc >= 0, "major oops in managing the attributes of a WebGL program");
   1.273 +            if (loc < mContext->mGLMaxVertexAttribs) {
   1.274 +                mAttribsInUse[loc] = true;
   1.275 +            } else {
   1.276 +                mContext->GenerateWarning("program exceeds MAX_VERTEX_ATTRIBS");
   1.277 +                return false;
   1.278 +            }
   1.279 +        }
   1.280 +    }
   1.281 +
   1.282 +    if (!mUniformInfoMap) {
   1.283 +        mUniformInfoMap = new CStringToUniformInfoMap;
   1.284 +        for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
   1.285 +            for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
   1.286 +                const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
   1.287 +                const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
   1.288 +                mUniformInfoMap->Put(uniform.mapped, info);
   1.289 +            }
   1.290 +        }
   1.291 +    }
   1.292 +
   1.293 +    mActiveAttribMap.clear();
   1.294 +
   1.295 +    GLint numActiveAttrs = 0;
   1.296 +    mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
   1.297 +
   1.298 +    // Spec says the maximum attrib name length is 256 chars, so this is
   1.299 +    // sufficient to hold any attrib name.
   1.300 +    char attrName[257];
   1.301 +
   1.302 +    GLint dummySize;
   1.303 +    GLenum dummyType;
   1.304 +    for (GLint i = 0; i < numActiveAttrs; i++) {
   1.305 +        mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
   1.306 +                                       &dummyType, attrName);
   1.307 +        GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
   1.308 +        MOZ_ASSERT(attrLoc >= 0);
   1.309 +        mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
   1.310 +    }
   1.311 +
   1.312 +    return true;
   1.313 +}
   1.314 +
   1.315 +/**
   1.316 + * Return the simple base format for a given internal format.
   1.317 + *
   1.318 + * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
   1.319 + * GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA), or GL_NONE if invalid enum.
   1.320 + */
   1.321 +GLenum
   1.322 +WebGLContext::BaseTexFormat(GLenum internalFormat) const
   1.323 +{
   1.324 +    if (internalFormat == LOCAL_GL_ALPHA ||
   1.325 +        internalFormat == LOCAL_GL_LUMINANCE ||
   1.326 +        internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
   1.327 +        internalFormat == LOCAL_GL_RGB ||
   1.328 +        internalFormat == LOCAL_GL_RGBA)
   1.329 +    {
   1.330 +        return internalFormat;
   1.331 +    }
   1.332 +
   1.333 +    if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
   1.334 +        if (internalFormat == LOCAL_GL_SRGB)
   1.335 +            return LOCAL_GL_RGB;
   1.336 +
   1.337 +        if (internalFormat == LOCAL_GL_SRGB_ALPHA)
   1.338 +            return LOCAL_GL_RGBA;
   1.339 +    }
   1.340 +
   1.341 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc)) {
   1.342 +        if (internalFormat == LOCAL_GL_ATC_RGB)
   1.343 +            return LOCAL_GL_RGB;
   1.344 +
   1.345 +        if (internalFormat == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
   1.346 +            internalFormat == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
   1.347 +        {
   1.348 +            return LOCAL_GL_RGBA;
   1.349 +        }
   1.350 +    }
   1.351 +
   1.352 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1)) {
   1.353 +        if (internalFormat == LOCAL_GL_ETC1_RGB8_OES)
   1.354 +            return LOCAL_GL_RGB;
   1.355 +    }
   1.356 +
   1.357 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) {
   1.358 +        if (internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
   1.359 +            internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1)
   1.360 +        {
   1.361 +            return LOCAL_GL_RGB;
   1.362 +        }
   1.363 +
   1.364 +        if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
   1.365 +            internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
   1.366 +        {
   1.367 +            return LOCAL_GL_RGBA;
   1.368 +        }
   1.369 +    }
   1.370 +
   1.371 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc)) {
   1.372 +        if (internalFormat == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
   1.373 +            return LOCAL_GL_RGB;
   1.374 +
   1.375 +        if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
   1.376 +            internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
   1.377 +            internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
   1.378 +        {
   1.379 +            return LOCAL_GL_RGBA;
   1.380 +        }
   1.381 +    }
   1.382 +
   1.383 +    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
   1.384 +        if (internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
   1.385 +            internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
   1.386 +            internalFormat == LOCAL_GL_DEPTH_COMPONENT32)
   1.387 +        {
   1.388 +            return LOCAL_GL_DEPTH_COMPONENT;
   1.389 +        }
   1.390 +
   1.391 +        if (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
   1.392 +            internalFormat == LOCAL_GL_DEPTH24_STENCIL8)
   1.393 +        {
   1.394 +            return LOCAL_GL_DEPTH_STENCIL;
   1.395 +        }
   1.396 +    }
   1.397 +
   1.398 +    MOZ_ASSERT(false, "Unhandled internalFormat");
   1.399 +    return LOCAL_GL_NONE;
   1.400 +}
   1.401 +
   1.402 +bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char *info)
   1.403 +{
   1.404 +    switch (mode) {
   1.405 +        case LOCAL_GL_FUNC_ADD:
   1.406 +        case LOCAL_GL_FUNC_SUBTRACT:
   1.407 +        case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
   1.408 +            return true;
   1.409 +        case LOCAL_GL_MIN:
   1.410 +        case LOCAL_GL_MAX:
   1.411 +            if (IsWebGL2()) {
   1.412 +                // http://www.opengl.org/registry/specs/EXT/blend_minmax.txt
   1.413 +                return true;
   1.414 +            }
   1.415 +            break;
   1.416 +        default:
   1.417 +            break;
   1.418 +    }
   1.419 +
   1.420 +    ErrorInvalidEnumInfo(info, mode);
   1.421 +    return false;
   1.422 +}
   1.423 +
   1.424 +bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char *info)
   1.425 +{
   1.426 +    switch (factor) {
   1.427 +        case LOCAL_GL_ZERO:
   1.428 +        case LOCAL_GL_ONE:
   1.429 +        case LOCAL_GL_SRC_COLOR:
   1.430 +        case LOCAL_GL_ONE_MINUS_SRC_COLOR:
   1.431 +        case LOCAL_GL_DST_COLOR:
   1.432 +        case LOCAL_GL_ONE_MINUS_DST_COLOR:
   1.433 +        case LOCAL_GL_SRC_ALPHA:
   1.434 +        case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
   1.435 +        case LOCAL_GL_DST_ALPHA:
   1.436 +        case LOCAL_GL_ONE_MINUS_DST_ALPHA:
   1.437 +        case LOCAL_GL_CONSTANT_COLOR:
   1.438 +        case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
   1.439 +        case LOCAL_GL_CONSTANT_ALPHA:
   1.440 +        case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
   1.441 +            return true;
   1.442 +        default:
   1.443 +            ErrorInvalidEnumInfo(info, factor);
   1.444 +            return false;
   1.445 +    }
   1.446 +}
   1.447 +
   1.448 +bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char *info)
   1.449 +{
   1.450 +    if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
   1.451 +        return true;
   1.452 +    else
   1.453 +        return ValidateBlendFuncDstEnum(factor, info);
   1.454 +}
   1.455 +
   1.456 +bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info)
   1.457 +{
   1.458 +    bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
   1.459 +                                    sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
   1.460 +    bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
   1.461 +                                    sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
   1.462 +    bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
   1.463 +                                    dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
   1.464 +    bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
   1.465 +                                    dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
   1.466 +    if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
   1.467 +         (dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
   1.468 +        ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
   1.469 +        return false;
   1.470 +    } else {
   1.471 +        return true;
   1.472 +    }
   1.473 +}
   1.474 +
   1.475 +bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
   1.476 +{
   1.477 +    switch (target) {
   1.478 +        case LOCAL_GL_TEXTURE_2D:
   1.479 +        case LOCAL_GL_TEXTURE_CUBE_MAP:
   1.480 +            return true;
   1.481 +        default:
   1.482 +            ErrorInvalidEnumInfo(info, target);
   1.483 +            return false;
   1.484 +    }
   1.485 +}
   1.486 +
   1.487 +bool WebGLContext::ValidateComparisonEnum(GLenum target, const char *info)
   1.488 +{
   1.489 +    switch (target) {
   1.490 +        case LOCAL_GL_NEVER:
   1.491 +        case LOCAL_GL_LESS:
   1.492 +        case LOCAL_GL_LEQUAL:
   1.493 +        case LOCAL_GL_GREATER:
   1.494 +        case LOCAL_GL_GEQUAL:
   1.495 +        case LOCAL_GL_EQUAL:
   1.496 +        case LOCAL_GL_NOTEQUAL:
   1.497 +        case LOCAL_GL_ALWAYS:
   1.498 +            return true;
   1.499 +        default:
   1.500 +            ErrorInvalidEnumInfo(info, target);
   1.501 +            return false;
   1.502 +    }
   1.503 +}
   1.504 +
   1.505 +bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char *info)
   1.506 +{
   1.507 +    switch (action) {
   1.508 +        case LOCAL_GL_KEEP:
   1.509 +        case LOCAL_GL_ZERO:
   1.510 +        case LOCAL_GL_REPLACE:
   1.511 +        case LOCAL_GL_INCR:
   1.512 +        case LOCAL_GL_INCR_WRAP:
   1.513 +        case LOCAL_GL_DECR:
   1.514 +        case LOCAL_GL_DECR_WRAP:
   1.515 +        case LOCAL_GL_INVERT:
   1.516 +            return true;
   1.517 +        default:
   1.518 +            ErrorInvalidEnumInfo(info, action);
   1.519 +            return false;
   1.520 +    }
   1.521 +}
   1.522 +
   1.523 +bool WebGLContext::ValidateFaceEnum(GLenum face, const char *info)
   1.524 +{
   1.525 +    switch (face) {
   1.526 +        case LOCAL_GL_FRONT:
   1.527 +        case LOCAL_GL_BACK:
   1.528 +        case LOCAL_GL_FRONT_AND_BACK:
   1.529 +            return true;
   1.530 +        default:
   1.531 +            ErrorInvalidEnumInfo(info, face);
   1.532 +            return false;
   1.533 +    }
   1.534 +}
   1.535 +
   1.536 +bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char *info)
   1.537 +{
   1.538 +    switch (mode) {
   1.539 +        case LOCAL_GL_TRIANGLES:
   1.540 +        case LOCAL_GL_TRIANGLE_STRIP:
   1.541 +        case LOCAL_GL_TRIANGLE_FAN:
   1.542 +        case LOCAL_GL_POINTS:
   1.543 +        case LOCAL_GL_LINE_STRIP:
   1.544 +        case LOCAL_GL_LINE_LOOP:
   1.545 +        case LOCAL_GL_LINES:
   1.546 +            return true;
   1.547 +        default:
   1.548 +            ErrorInvalidEnumInfo(info, mode);
   1.549 +            return false;
   1.550 +    }
   1.551 +}
   1.552 +
   1.553 +bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
   1.554 +{
   1.555 +    if (name.IsEmpty())
   1.556 +        return false;
   1.557 +
   1.558 +    const uint32_t maxSize = 256;
   1.559 +    if (name.Length() > maxSize) {
   1.560 +        ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
   1.561 +                          info, name.Length(), maxSize);
   1.562 +        return false;
   1.563 +    }
   1.564 +
   1.565 +    if (!ValidateGLSLString(name, info)) {
   1.566 +        return false;
   1.567 +    }
   1.568 +
   1.569 +    nsString prefix1 = NS_LITERAL_STRING("webgl_");
   1.570 +    nsString prefix2 = NS_LITERAL_STRING("_webgl_");
   1.571 +
   1.572 +    if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
   1.573 +        Substring(name, 0, prefix2.Length()).Equals(prefix2))
   1.574 +    {
   1.575 +        ErrorInvalidOperation("%s: string contains a reserved GLSL prefix", info);
   1.576 +        return false;
   1.577 +    }
   1.578 +
   1.579 +    return true;
   1.580 +}
   1.581 +
   1.582 +bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
   1.583 +{
   1.584 +    for (uint32_t i = 0; i < string.Length(); ++i) {
   1.585 +        if (!ValidateGLSLCharacter(string.CharAt(i))) {
   1.586 +             ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
   1.587 +             return false;
   1.588 +        }
   1.589 +    }
   1.590 +
   1.591 +    return true;
   1.592 +}
   1.593 +
   1.594 +/**
   1.595 + * Return true if format is a valid texture image format for source,
   1.596 + * taking into account enabled WebGL extensions.
   1.597 + */
   1.598 +bool
   1.599 +WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
   1.600 +{
   1.601 +    /* Core WebGL texture formats */
   1.602 +    if (format == LOCAL_GL_ALPHA ||
   1.603 +        format == LOCAL_GL_RGB ||
   1.604 +        format == LOCAL_GL_RGBA ||
   1.605 +        format == LOCAL_GL_LUMINANCE ||
   1.606 +        format == LOCAL_GL_LUMINANCE_ALPHA)
   1.607 +    {
   1.608 +        return true;
   1.609 +    }
   1.610 +
   1.611 +    /* Only core formats are valid for CopyTex(Sub)?Image */
   1.612 +    // TODO: Revisit this once color_buffer_(half_)?float lands
   1.613 +    if (IsCopyFunc(func)) {
   1.614 +        ErrorInvalidEnumWithName(this, "invalid format", format, func);
   1.615 +        return false;
   1.616 +    }
   1.617 +
   1.618 +    /* WEBGL_depth_texture added formats */
   1.619 +    if (format == LOCAL_GL_DEPTH_COMPONENT ||
   1.620 +        format == LOCAL_GL_DEPTH_STENCIL)
   1.621 +    {
   1.622 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
   1.623 +        if (!validFormat)
   1.624 +            ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
   1.625 +                             InfoFrom(func), NameFrom(format));
   1.626 +        return validFormat;
   1.627 +    }
   1.628 +
   1.629 +    /* EXT_sRGB added formats */
   1.630 +    if (format == LOCAL_GL_SRGB ||
   1.631 +        format == LOCAL_GL_SRGB_ALPHA)
   1.632 +    {
   1.633 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
   1.634 +        if (!validFormat)
   1.635 +            ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
   1.636 +                             InfoFrom(func), NameFrom(format));
   1.637 +        return validFormat;
   1.638 +    }
   1.639 +
   1.640 +    /* WEBGL_compressed_texture_atc added formats */
   1.641 +    if (format == LOCAL_GL_ATC_RGB ||
   1.642 +        format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
   1.643 +        format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
   1.644 +    {
   1.645 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
   1.646 +        if (!validFormat)
   1.647 +            ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
   1.648 +                             InfoFrom(func), NameFrom(format));
   1.649 +        return validFormat;
   1.650 +    }
   1.651 +
   1.652 +    // WEBGL_compressed_texture_etc1
   1.653 +    if (format == LOCAL_GL_ETC1_RGB8_OES) {
   1.654 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
   1.655 +        if (!validFormat)
   1.656 +            ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
   1.657 +                             InfoFrom(func), NameFrom(format));
   1.658 +        return validFormat;
   1.659 +    }
   1.660 +
   1.661 +
   1.662 +    if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
   1.663 +        format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
   1.664 +        format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
   1.665 +        format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
   1.666 +    {
   1.667 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
   1.668 +        if (!validFormat)
   1.669 +            ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
   1.670 +                             InfoFrom(func), NameFrom(format));
   1.671 +        return validFormat;
   1.672 +    }
   1.673 +
   1.674 +
   1.675 +    if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
   1.676 +        format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
   1.677 +        format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
   1.678 +        format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
   1.679 +    {
   1.680 +        bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
   1.681 +        if (!validFormat)
   1.682 +            ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
   1.683 +                             InfoFrom(func), NameFrom(format));
   1.684 +        return validFormat;
   1.685 +    }
   1.686 +
   1.687 +    ErrorInvalidEnumWithName(this, "invalid format", format, func);
   1.688 +
   1.689 +    return false;
   1.690 +}
   1.691 +
   1.692 +/**
   1.693 + * Check if the given texture target is valid for TexImage.
   1.694 + */
   1.695 +bool
   1.696 +WebGLContext::ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func)
   1.697 +{
   1.698 +    switch (dims) {
   1.699 +    case 2:
   1.700 +        if (target == LOCAL_GL_TEXTURE_2D ||
   1.701 +            IsTexImageCubemapTarget(target))
   1.702 +        {
   1.703 +            return true;
   1.704 +        }
   1.705 +
   1.706 +        ErrorInvalidEnumWithName(this, "invalid target", target, func);
   1.707 +        return false;
   1.708 +
   1.709 +    default:
   1.710 +        MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
   1.711 +    }
   1.712 +
   1.713 +    return false;
   1.714 +}
   1.715 +
   1.716 +/**
   1.717 + * Return true if type is a valid texture image type for source,
   1.718 + * taking into account enabled WebGL extensions.
   1.719 + */
   1.720 +bool
   1.721 +WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func)
   1.722 +{
   1.723 +    /* Core WebGL texture types */
   1.724 +    if (type == LOCAL_GL_UNSIGNED_BYTE ||
   1.725 +        type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
   1.726 +        type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
   1.727 +        type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
   1.728 +    {
   1.729 +        return true;
   1.730 +    }
   1.731 +
   1.732 +    /* OES_texture_float added types */
   1.733 +    if (type == LOCAL_GL_FLOAT) {
   1.734 +        bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
   1.735 +        if (!validType)
   1.736 +            ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
   1.737 +                             InfoFrom(func), NameFrom(type));
   1.738 +        return validType;
   1.739 +    }
   1.740 +
   1.741 +    /* OES_texture_half_float add types */
   1.742 +    if (type == LOCAL_GL_HALF_FLOAT_OES) {
   1.743 +        bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
   1.744 +        if (!validType)
   1.745 +            ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
   1.746 +                             InfoFrom(func), NameFrom(type));
   1.747 +        return validType;
   1.748 +    }
   1.749 +
   1.750 +    /* WEBGL_depth_texture added types */
   1.751 +    if (type == LOCAL_GL_UNSIGNED_SHORT ||
   1.752 +        type == LOCAL_GL_UNSIGNED_INT ||
   1.753 +        type == LOCAL_GL_UNSIGNED_INT_24_8)
   1.754 +    {
   1.755 +        bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
   1.756 +        if (!validType)
   1.757 +            ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
   1.758 +                             InfoFrom(func), NameFrom(type));
   1.759 +        return validType;
   1.760 +    }
   1.761 +
   1.762 +    ErrorInvalidEnumWithName(this, "invalid type", type, func);
   1.763 +    return false;
   1.764 +}
   1.765 +
   1.766 +/**
   1.767 + * Validate texture image sizing extra constraints for
   1.768 + * CompressedTex(Sub)?Image.
   1.769 + */
   1.770 +// TODO: WebGL 2
   1.771 +bool
   1.772 +WebGLContext::ValidateCompTexImageSize(GLenum target, GLint level, GLenum format,
   1.773 +                                       GLint xoffset, GLint yoffset,
   1.774 +                                       GLsizei width, GLsizei height,
   1.775 +                                       GLsizei levelWidth, GLsizei levelHeight,
   1.776 +                                       WebGLTexImageFunc func)
   1.777 +{
   1.778 +    // Negative parameters must already have been handled above
   1.779 +    MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
   1.780 +               width >= 0 && height >= 0);
   1.781 +
   1.782 +    if (xoffset + width > (GLint) levelWidth) {
   1.783 +        ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
   1.784 +        return false;
   1.785 +    }
   1.786 +
   1.787 +    if (yoffset + height > (GLint) levelHeight) {
   1.788 +        ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
   1.789 +        return false;
   1.790 +    }
   1.791 +
   1.792 +    GLint blockWidth = 1;
   1.793 +    GLint blockHeight = 1;
   1.794 +    BlockSizeFor(format, &blockWidth, &blockHeight);
   1.795 +
   1.796 +    /* If blockWidth || blockHeight != 1, then the compressed format
   1.797 +     * had block-based constraints to be checked. (For example, PVRTC is compressed but
   1.798 +     * isn't a block-based format)
   1.799 +     */
   1.800 +    if (blockWidth != 1 || blockHeight != 1) {
   1.801 +        /* offsets must be multiple of block size */
   1.802 +        if (xoffset % blockWidth != 0) {
   1.803 +            ErrorInvalidOperation("%s: xoffset must be multiple of %d",
   1.804 +                                  InfoFrom(func), blockWidth);
   1.805 +            return false;
   1.806 +        }
   1.807 +
   1.808 +        if (yoffset % blockHeight != 0) {
   1.809 +            ErrorInvalidOperation("%s: yoffset must be multiple of %d",
   1.810 +                                  InfoFrom(func), blockHeight);
   1.811 +            return false;
   1.812 +        }
   1.813 +
   1.814 +        /* The size must be a multiple of blockWidth and blockHeight,
   1.815 +         * or must be using offset+size that exactly hits the edge.
   1.816 +         * Important for small mipmap levels.
   1.817 +         */
   1.818 +        /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
   1.819 +         * "When level equals zero width and height must be a multiple of 4. When
   1.820 +         *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
   1.821 +         *  If they are not an INVALID_OPERATION error is generated."
   1.822 +         */
   1.823 +        if (level == 0) {
   1.824 +            if (width % blockWidth != 0) {
   1.825 +                ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
   1.826 +                                      InfoFrom(func), blockWidth);
   1.827 +                return false;
   1.828 +            }
   1.829 +
   1.830 +            if (height % blockHeight != 0) {
   1.831 +                ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
   1.832 +                                      InfoFrom(func), blockHeight);
   1.833 +                return false;
   1.834 +            }
   1.835 +        }
   1.836 +        else if (level > 0) {
   1.837 +            if (width % blockWidth != 0 && width > 2) {
   1.838 +                ErrorInvalidOperation("%s: width of level %d must be multiple"
   1.839 +                                      " of %d or 0, 1, 2",
   1.840 +                                      InfoFrom(func), level, blockWidth);
   1.841 +                return false;
   1.842 +            }
   1.843 +
   1.844 +            if (height % blockHeight != 0 && height > 2) {
   1.845 +                ErrorInvalidOperation("%s: height of level %d must be multiple"
   1.846 +                                      " of %d or 0, 1, 2",
   1.847 +                                      InfoFrom(func), level, blockHeight);
   1.848 +                return false;
   1.849 +            }
   1.850 +        }
   1.851 +
   1.852 +        if (IsSubFunc(func)) {
   1.853 +            if ((xoffset % blockWidth) != 0) {
   1.854 +                ErrorInvalidOperation("%s: xoffset must be multiple of %d",
   1.855 +                                      InfoFrom(func), blockWidth);
   1.856 +                return false;
   1.857 +            }
   1.858 +
   1.859 +            if (yoffset % blockHeight != 0) {
   1.860 +                ErrorInvalidOperation("%s: yoffset must be multiple of %d",
   1.861 +                                      InfoFrom(func), blockHeight);
   1.862 +                return false;
   1.863 +            }
   1.864 +        }
   1.865 +    }
   1.866 +
   1.867 +    switch (format) {
   1.868 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   1.869 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   1.870 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   1.871 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   1.872 +        if (!is_pot_assuming_nonnegative(width) ||
   1.873 +            !is_pot_assuming_nonnegative(height))
   1.874 +        {
   1.875 +            ErrorInvalidValue("%s: width and height must be powers of two",
   1.876 +                              InfoFrom(func));
   1.877 +            return false;
   1.878 +        }
   1.879 +    }
   1.880 +
   1.881 +    return true;
   1.882 +}
   1.883 +
   1.884 +/**
   1.885 + * Return true if the enough data is present to satisfy compressed
   1.886 + * texture format constraints.
   1.887 + */
   1.888 +bool
   1.889 +WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
   1.890 +                                           GLsizei width, GLsizei height,
   1.891 +                                           uint32_t byteLength, WebGLTexImageFunc func)
   1.892 +{
   1.893 +    // negative width and height must already have been handled above
   1.894 +    MOZ_ASSERT(width >= 0 && height >= 0);
   1.895 +
   1.896 +    CheckedUint32 required_byteLength = 0;
   1.897 +
   1.898 +    switch (format) {
   1.899 +        case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
   1.900 +        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
   1.901 +        case LOCAL_GL_ATC_RGB:
   1.902 +        case LOCAL_GL_ETC1_RGB8_OES:
   1.903 +        {
   1.904 +            required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
   1.905 +            break;
   1.906 +        }
   1.907 +        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
   1.908 +        case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
   1.909 +        case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
   1.910 +        case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
   1.911 +        {
   1.912 +            required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
   1.913 +            break;
   1.914 +        }
   1.915 +        case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
   1.916 +        case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
   1.917 +        {
   1.918 +            required_byteLength = CheckedUint32(std::max(width, 8)) * CheckedUint32(std::max(height, 8)) / 2;
   1.919 +            break;
   1.920 +        }
   1.921 +        case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
   1.922 +        case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
   1.923 +        {
   1.924 +            required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
   1.925 +            break;
   1.926 +        }
   1.927 +    }
   1.928 +
   1.929 +    if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
   1.930 +        ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
   1.931 +        return false;
   1.932 +    }
   1.933 +
   1.934 +    return true;
   1.935 +}
   1.936 +
   1.937 +/**
   1.938 + * Validate the width, height, and depth of a texture image, \return
   1.939 + * true is valid, false otherwise.
   1.940 + * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
   1.941 + * Target and level must have been validated before calling.
   1.942 + */
   1.943 +bool
   1.944 +WebGLContext::ValidateTexImageSize(GLenum target, GLint level,
   1.945 +                                   GLint width, GLint height, GLint depth,
   1.946 +                                   WebGLTexImageFunc func)
   1.947 +{
   1.948 +    MOZ_ASSERT(level >= 0, "level should already be validated");
   1.949 +
   1.950 +    /* Bug 966630: maxTextureSize >> level runs into "undefined"
   1.951 +     * behaviour depending on ISA. For example, on Intel shifts
   1.952 +     * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
   1.953 +     * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
   1.954 +     * what would be expected. Make the required behaviour explicit by
   1.955 +     * clamping to a shift of 31 bits if level is greater than that
   1.956 +     * ammount. This will give 0 that if (!maxAllowedSize) is
   1.957 +     * expecting.
   1.958 +     */
   1.959 +
   1.960 +    if (level > 31)
   1.961 +        level = 31;
   1.962 +
   1.963 +    const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level;
   1.964 +    const bool isCubemapTarget = IsTexImageCubemapTarget(target);
   1.965 +    const bool isSub = IsSubFunc(func);
   1.966 +
   1.967 +    if (!isSub && isCubemapTarget && (width != height)) {
   1.968 +        /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   1.969 +         *   "When the target parameter to TexImage2D is one of the
   1.970 +         *   six cube map two-dimensional image targets, the error
   1.971 +         *   INVALID_VALUE is generated if the width and height
   1.972 +         *   parameters are not equal."
   1.973 +         */
   1.974 +        ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
   1.975 +        return false;
   1.976 +    }
   1.977 +
   1.978 +    if (target == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
   1.979 +    {
   1.980 +        /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   1.981 +         *   "If wt and ht are the specified image width and height,
   1.982 +         *   and if either wt or ht are less than zero, then the error
   1.983 +         *   INVALID_VALUE is generated."
   1.984 +         */
   1.985 +        if (width < 0) {
   1.986 +            ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
   1.987 +            return false;
   1.988 +        }
   1.989 +
   1.990 +        if (height < 0) {
   1.991 +            ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
   1.992 +            return false;
   1.993 +        }
   1.994 +
   1.995 +        /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
   1.996 +         *   "The maximum allowable width and height of a
   1.997 +         *   two-dimensional texture image must be at least 2**(k−lod)
   1.998 +         *   for image arrays of level zero through k, where k is the
   1.999 +         *   log base 2 of MAX_TEXTURE_SIZE. and lod is the
  1.1000 +         *   level-of-detail of the image array. It may be zero for
  1.1001 +         *   image arrays of any level-of-detail greater than k. The
  1.1002 +         *   error INVALID_VALUE is generated if the specified image
  1.1003 +         *   is too large to be stored under any conditions.
  1.1004 +         */
  1.1005 +        if (width > (int) maxTexImageSize) {
  1.1006 +            ErrorInvalidValue("%s: the maximum width for level %d is %u",
  1.1007 +                              InfoFrom(func), level, maxTexImageSize);
  1.1008 +            return false;
  1.1009 +        }
  1.1010 +
  1.1011 +        if (height > (int) maxTexImageSize) {
  1.1012 +            ErrorInvalidValue("%s: tex maximum height for level %d is %u",
  1.1013 +                              InfoFrom(func), level, maxTexImageSize);
  1.1014 +            return false;
  1.1015 +        }
  1.1016 +
  1.1017 +        /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
  1.1018 +         *   "If level is greater than zero, and either width or
  1.1019 +         *   height is not a power-of-two, the error INVALID_VALUE is
  1.1020 +         *   generated."
  1.1021 +         */
  1.1022 +        if (level > 0) {
  1.1023 +            if (!is_pot_assuming_nonnegative(width)) {
  1.1024 +                ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
  1.1025 +                                  InfoFrom(func), width);
  1.1026 +                return false;
  1.1027 +            }
  1.1028 +
  1.1029 +            if (!is_pot_assuming_nonnegative(height)) {
  1.1030 +                ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
  1.1031 +                                  InfoFrom(func), height);
  1.1032 +                return false;
  1.1033 +            }
  1.1034 +        }
  1.1035 +    }
  1.1036 +
  1.1037 +    // TODO: WebGL 2
  1.1038 +    if (target == LOCAL_GL_TEXTURE_3D) {
  1.1039 +        if (depth < 0) {
  1.1040 +            ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
  1.1041 +            return false;
  1.1042 +        }
  1.1043 +
  1.1044 +        if (!is_pot_assuming_nonnegative(depth)) {
  1.1045 +            ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
  1.1046 +                              InfoFrom(func), depth);
  1.1047 +            return false;
  1.1048 +        }
  1.1049 +    }
  1.1050 +
  1.1051 +    return true;
  1.1052 +}
  1.1053 +
  1.1054 +/**
  1.1055 + * Validate texture image sizing for Tex(Sub)?Image variants.
  1.1056 + */
  1.1057 +// TODO: WebGL 2. Update this to handle 3D textures.
  1.1058 +bool
  1.1059 +WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
  1.1060 +                                      GLsizei width, GLsizei height, GLsizei /*depth*/,
  1.1061 +                                      GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
  1.1062 +                                      WebGLTexImageFunc func)
  1.1063 +{
  1.1064 +    /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
  1.1065 +     *   "Taking wt and ht to be the specified width and height of the
  1.1066 +     *   texture array, and taking x, y, w, and h to be the xoffset,
  1.1067 +     *   yoffset, width, and height argument values, any of the
  1.1068 +     *   following relationships generates the error INVALID_VALUE:
  1.1069 +     *       x < 0
  1.1070 +     *       x + w > wt
  1.1071 +     *       y < 0
  1.1072 +     *       y + h > ht"
  1.1073 +     */
  1.1074 +
  1.1075 +    if (xoffset < 0) {
  1.1076 +        ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
  1.1077 +        return false;
  1.1078 +    }
  1.1079 +
  1.1080 +    if (yoffset < 0) {
  1.1081 +        ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
  1.1082 +        return false;
  1.1083 +    }
  1.1084 +
  1.1085 +    if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
  1.1086 +        ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
  1.1087 +        return false;
  1.1088 +    }
  1.1089 +
  1.1090 +    return true;
  1.1091 +}
  1.1092 +
  1.1093 +/**
  1.1094 + * Return the bits per texel for format & type combination.
  1.1095 + * Assumes that format & type are a valid combination as checked with
  1.1096 + * ValidateTexImageFormatAndType().
  1.1097 + */
  1.1098 +uint32_t
  1.1099 +WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
  1.1100 +{
  1.1101 +    // If there is no defined format or type, we're not taking up any memory
  1.1102 +    if (!format || !type) {
  1.1103 +        return 0;
  1.1104 +    }
  1.1105 +
  1.1106 +    /* Known fixed-sized types */
  1.1107 +    if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
  1.1108 +        type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
  1.1109 +        type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
  1.1110 +    {
  1.1111 +        return 16;
  1.1112 +    }
  1.1113 +
  1.1114 +    if (type == LOCAL_GL_UNSIGNED_INT_24_8)
  1.1115 +        return 32;
  1.1116 +
  1.1117 +    int bitsPerComponent = 0;
  1.1118 +    switch (type) {
  1.1119 +    case LOCAL_GL_UNSIGNED_BYTE:
  1.1120 +        bitsPerComponent = 8;
  1.1121 +        break;
  1.1122 +
  1.1123 +    case LOCAL_GL_HALF_FLOAT:
  1.1124 +    case LOCAL_GL_HALF_FLOAT_OES:
  1.1125 +    case LOCAL_GL_UNSIGNED_SHORT:
  1.1126 +        bitsPerComponent = 16;
  1.1127 +        break;
  1.1128 +
  1.1129 +    case LOCAL_GL_FLOAT:
  1.1130 +    case LOCAL_GL_UNSIGNED_INT:
  1.1131 +        bitsPerComponent = 32;
  1.1132 +        break;
  1.1133 +
  1.1134 +    default:
  1.1135 +        MOZ_ASSERT(false, "Unhandled type.");
  1.1136 +        break;
  1.1137 +    }
  1.1138 +
  1.1139 +    switch (format) {
  1.1140 +        // Uncompressed formats
  1.1141 +    case LOCAL_GL_ALPHA:
  1.1142 +    case LOCAL_GL_LUMINANCE:
  1.1143 +    case LOCAL_GL_DEPTH_COMPONENT:
  1.1144 +    case LOCAL_GL_DEPTH_STENCIL:
  1.1145 +        return 1 * bitsPerComponent;
  1.1146 +
  1.1147 +    case LOCAL_GL_LUMINANCE_ALPHA:
  1.1148 +        return 2 * bitsPerComponent;
  1.1149 +
  1.1150 +    case LOCAL_GL_RGB:
  1.1151 +    case LOCAL_GL_RGB32F:
  1.1152 +    case LOCAL_GL_SRGB_EXT:
  1.1153 +        return 3 * bitsPerComponent;
  1.1154 +
  1.1155 +    case LOCAL_GL_RGBA:
  1.1156 +    case LOCAL_GL_RGBA32F:
  1.1157 +    case LOCAL_GL_SRGB_ALPHA_EXT:
  1.1158 +        return 4 * bitsPerComponent;
  1.1159 +
  1.1160 +        // Compressed formats
  1.1161 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
  1.1162 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
  1.1163 +        return 2;
  1.1164 +
  1.1165 +    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  1.1166 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1.1167 +    case LOCAL_GL_ATC_RGB:
  1.1168 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
  1.1169 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
  1.1170 +    case LOCAL_GL_ETC1_RGB8_OES:
  1.1171 +        return 4;
  1.1172 +
  1.1173 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1.1174 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1.1175 +    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
  1.1176 +    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
  1.1177 +        return 8;
  1.1178 +
  1.1179 +    default:
  1.1180 +        break;
  1.1181 +    }
  1.1182 +
  1.1183 +    MOZ_ASSERT(false, "Unhandled format+type combo.");
  1.1184 +    return 0;
  1.1185 +}
  1.1186 +
  1.1187 +/**
  1.1188 + * Perform validation of format/type combinations for TexImage variants.
  1.1189 + * Returns true if the format/type is a valid combination, false otherwise.
  1.1190 + */
  1.1191 +bool
  1.1192 +WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func)
  1.1193 +{
  1.1194 +    if (!ValidateTexImageFormat(format, func) ||
  1.1195 +        !ValidateTexImageType(type, func))
  1.1196 +    {
  1.1197 +        return false;
  1.1198 +    }
  1.1199 +
  1.1200 +    bool validCombo = false;
  1.1201 +
  1.1202 +    switch (format) {
  1.1203 +    case LOCAL_GL_ALPHA:
  1.1204 +    case LOCAL_GL_LUMINANCE:
  1.1205 +    case LOCAL_GL_LUMINANCE_ALPHA:
  1.1206 +        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1.1207 +                      type == LOCAL_GL_HALF_FLOAT ||
  1.1208 +                      type == LOCAL_GL_HALF_FLOAT_OES ||
  1.1209 +                      type == LOCAL_GL_FLOAT);
  1.1210 +        break;
  1.1211 +
  1.1212 +    case LOCAL_GL_RGB:
  1.1213 +    case LOCAL_GL_SRGB:
  1.1214 +        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1.1215 +                      type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
  1.1216 +                      type == LOCAL_GL_HALF_FLOAT ||
  1.1217 +                      type == LOCAL_GL_HALF_FLOAT_OES ||
  1.1218 +                      type == LOCAL_GL_FLOAT);
  1.1219 +        break;
  1.1220 +
  1.1221 +    case LOCAL_GL_RGBA:
  1.1222 +    case LOCAL_GL_SRGB_ALPHA:
  1.1223 +        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
  1.1224 +                      type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
  1.1225 +                      type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
  1.1226 +                      type == LOCAL_GL_HALF_FLOAT ||
  1.1227 +                      type == LOCAL_GL_HALF_FLOAT_OES ||
  1.1228 +                      type == LOCAL_GL_FLOAT);
  1.1229 +        break;
  1.1230 +
  1.1231 +    case LOCAL_GL_DEPTH_COMPONENT:
  1.1232 +        validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
  1.1233 +                      type == LOCAL_GL_UNSIGNED_INT);
  1.1234 +        break;
  1.1235 +
  1.1236 +    case LOCAL_GL_DEPTH_STENCIL:
  1.1237 +        validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
  1.1238 +        break;
  1.1239 +
  1.1240 +    case LOCAL_GL_ATC_RGB:
  1.1241 +    case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
  1.1242 +    case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
  1.1243 +    case LOCAL_GL_ETC1_RGB8_OES:
  1.1244 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
  1.1245 +    case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
  1.1246 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
  1.1247 +    case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
  1.1248 +    case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
  1.1249 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  1.1250 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  1.1251 +    case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  1.1252 +        validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
  1.1253 +        break;
  1.1254 +
  1.1255 +    default:
  1.1256 +        // Only valid formats should be passed to the switch stmt.
  1.1257 +        MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
  1.1258 +        validCombo = false;
  1.1259 +        // Fall through to return an InvalidOperations. This will alert us to the
  1.1260 +        // unexpected case that needs fixing in builds without asserts.
  1.1261 +    }
  1.1262 +
  1.1263 +    if (!validCombo)
  1.1264 +        ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
  1.1265 +                              InfoFrom(func), NameFrom(format), NameFrom(type));
  1.1266 +
  1.1267 +    return validCombo;
  1.1268 +}
  1.1269 +
  1.1270 +/**
  1.1271 + * Return true if format, type and jsArrayType are a valid combination.
  1.1272 + * Also returns the size for texel of format and type (in bytes) via
  1.1273 + * \a texelSize.
  1.1274 + *
  1.1275 + * It is assumed that type has previously been validated.
  1.1276 + */
  1.1277 +bool
  1.1278 +WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
  1.1279 +{
  1.1280 +    bool validInput = false;
  1.1281 +    const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
  1.1282 +
  1.1283 +    // First, we check for packed types
  1.1284 +    switch (type) {
  1.1285 +    case LOCAL_GL_UNSIGNED_BYTE:
  1.1286 +        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT8);
  1.1287 +        break;
  1.1288 +
  1.1289 +        // TODO: WebGL spec doesn't allow half floats to specified as UInt16.
  1.1290 +    case LOCAL_GL_HALF_FLOAT:
  1.1291 +    case LOCAL_GL_HALF_FLOAT_OES:
  1.1292 +        validInput = (jsArrayType == -1);
  1.1293 +        break;
  1.1294 +
  1.1295 +    case LOCAL_GL_UNSIGNED_SHORT:
  1.1296 +    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
  1.1297 +    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
  1.1298 +    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
  1.1299 +        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT16);
  1.1300 +        break;
  1.1301 +
  1.1302 +    case LOCAL_GL_UNSIGNED_INT:
  1.1303 +    case LOCAL_GL_UNSIGNED_INT_24_8:
  1.1304 +        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_UINT32);
  1.1305 +        break;
  1.1306 +
  1.1307 +    case LOCAL_GL_FLOAT:
  1.1308 +        validInput = (jsArrayType == -1 || jsArrayType == js::ArrayBufferView::TYPE_FLOAT32);
  1.1309 +        break;
  1.1310 +
  1.1311 +    default:
  1.1312 +        break;
  1.1313 +    }
  1.1314 +
  1.1315 +    if (!validInput)
  1.1316 +        ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
  1.1317 +
  1.1318 +    return validInput;
  1.1319 +}
  1.1320 +
  1.1321 +/**
  1.1322 + * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
  1.1323 + * Verifies each of the parameters against the WebGL standard and enabled extensions.
  1.1324 + */
  1.1325 +// TODO: Texture dims is here for future expansion in WebGL 2.0
  1.1326 +bool
  1.1327 +WebGLContext::ValidateTexImage(GLuint dims, GLenum target,
  1.1328 +                               GLint level, GLint internalFormat,
  1.1329 +                               GLint xoffset, GLint yoffset, GLint zoffset,
  1.1330 +                               GLint width, GLint height, GLint depth,
  1.1331 +                               GLint border, GLenum format, GLenum type,
  1.1332 +                               WebGLTexImageFunc func)
  1.1333 +{
  1.1334 +    const char* info = InfoFrom(func);
  1.1335 +
  1.1336 +    /* Check target */
  1.1337 +    if (!ValidateTexImageTarget(dims, target, func))
  1.1338 +        return false;
  1.1339 +
  1.1340 +    /* Check level */
  1.1341 +    if (level < 0) {
  1.1342 +        ErrorInvalidValue("%s: level must be >= 0", info);
  1.1343 +        return false;
  1.1344 +    }
  1.1345 +
  1.1346 +    /* Check border */
  1.1347 +    if (border != 0) {
  1.1348 +        ErrorInvalidValue("%s: border must be 0", info);
  1.1349 +        return false;
  1.1350 +    }
  1.1351 +
  1.1352 +    /* Check incoming image format and type */
  1.1353 +    if (!ValidateTexImageFormatAndType(format, type, func))
  1.1354 +        return false;
  1.1355 +
  1.1356 +    /* WebGL and OpenGL ES 2.0 impose additional restrictions on the
  1.1357 +     * combinations of format, internalFormat, and type that can be
  1.1358 +     * used.  Formats and types that require additional extensions
  1.1359 +     * (e.g., GL_FLOAT requires GL_OES_texture_float) are filtered
  1.1360 +     * elsewhere.
  1.1361 +     */
  1.1362 +    if ((GLint) format != internalFormat) {
  1.1363 +        ErrorInvalidOperation("%s: format does not match internalformat", info);
  1.1364 +        return false;
  1.1365 +    }
  1.1366 +
  1.1367 +    /* check internalFormat */
  1.1368 +    // TODO: Not sure if this is a bit of over kill.
  1.1369 +    if (BaseTexFormat(internalFormat) == LOCAL_GL_NONE) {
  1.1370 +        MOZ_ASSERT(false);
  1.1371 +        ErrorInvalidValue("%s:", info);
  1.1372 +        return false;
  1.1373 +    }
  1.1374 +
  1.1375 +    /* Check texture image size */
  1.1376 +    if (!ValidateTexImageSize(target, level, width, height, 0, func))
  1.1377 +        return false;
  1.1378 +
  1.1379 +    /* 5.14.8 Texture objects - WebGL Spec.
  1.1380 +     *   "If an attempt is made to call these functions with no
  1.1381 +     *    WebGLTexture bound (see above), an INVALID_OPERATION error
  1.1382 +     *    is generated."
  1.1383 +     */
  1.1384 +    WebGLTexture* tex = activeBoundTextureForTarget(target);
  1.1385 +    if (!tex) {
  1.1386 +        ErrorInvalidOperation("%s: no texture is bound to target %s",
  1.1387 +                              info, NameFrom(target));
  1.1388 +        return false;
  1.1389 +    }
  1.1390 +
  1.1391 +    if (IsSubFunc(func)) {
  1.1392 +        if (!tex->HasImageInfoAt(target, level)) {
  1.1393 +            ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
  1.1394 +                                  info, NameFrom(target), level);
  1.1395 +            return false;
  1.1396 +        }
  1.1397 +
  1.1398 +        const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
  1.1399 +        if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
  1.1400 +                                     width, height, depth,
  1.1401 +                                     imageInfo.Width(), imageInfo.Height(), 0,
  1.1402 +                                     func))
  1.1403 +        {
  1.1404 +            return false;
  1.1405 +        }
  1.1406 +
  1.1407 +        /* Require the format and type to match that of the existing
  1.1408 +         * texture as created
  1.1409 +         */
  1.1410 +        if (imageInfo.WebGLFormat() != format ||
  1.1411 +            imageInfo.WebGLType() != type)
  1.1412 +        {
  1.1413 +            ErrorInvalidOperation("%s: format or type doesn't match the existing texture",
  1.1414 +                                  info);
  1.1415 +            return false;
  1.1416 +        }
  1.1417 +    }
  1.1418 +
  1.1419 +    /* Additional checks for depth textures */
  1.1420 +    if (format == LOCAL_GL_DEPTH_COMPONENT ||
  1.1421 +        format == LOCAL_GL_DEPTH_STENCIL)
  1.1422 +    {
  1.1423 +        if (func == WebGLTexImageFunc::TexSubImage || IsCopyFunc(func)) {
  1.1424 +            ErrorInvalidOperationWithName(this, "called with format/internalformat",
  1.1425 +                                          format, func);
  1.1426 +            return false;
  1.1427 +        }
  1.1428 +
  1.1429 +        if (func == WebGLTexImageFunc::TexImage &&
  1.1430 +            target != LOCAL_GL_TEXTURE_2D)
  1.1431 +        {
  1.1432 +            ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
  1.1433 +                                  info, NameFrom(format));
  1.1434 +            return false;
  1.1435 +        }
  1.1436 +
  1.1437 +        if (func == WebGLTexImageFunc::TexImage && level != 0) {
  1.1438 +            ErrorInvalidOperation("%s: with format of %s target, level must be 0",
  1.1439 +                                  info, NameFrom(format));
  1.1440 +            return false;
  1.1441 +        }
  1.1442 +    }
  1.1443 +
  1.1444 +    /* Additional checks for compressed textures */
  1.1445 +    if (!IsAllowedFromSource(format, func)) {
  1.1446 +        ErrorInvalidOperation("%s: Invalid format %s for this operation",
  1.1447 +                              info, NameFrom(format));
  1.1448 +        return false;
  1.1449 +    }
  1.1450 +
  1.1451 +    /* Parameters are OK */
  1.1452 +    return true;
  1.1453 +}
  1.1454 +
  1.1455 +bool
  1.1456 +WebGLContext::ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object)
  1.1457 +{
  1.1458 +    if (!ValidateObjectAllowNull(info, location_object))
  1.1459 +        return false;
  1.1460 +    if (!location_object)
  1.1461 +        return false;
  1.1462 +    /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
  1.1463 +    if (!mCurrentProgram) {
  1.1464 +        ErrorInvalidOperation("%s: no program is currently bound", info);
  1.1465 +        return false;
  1.1466 +    }
  1.1467 +    if (mCurrentProgram != location_object->Program()) {
  1.1468 +        ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info);
  1.1469 +        return false;
  1.1470 +    }
  1.1471 +    if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) {
  1.1472 +        ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info);
  1.1473 +        return false;
  1.1474 +    }
  1.1475 +    return true;
  1.1476 +}
  1.1477 +
  1.1478 +bool
  1.1479 +WebGLContext::ValidateSamplerUniformSetter(const char* info, WebGLUniformLocation *location, GLint value)
  1.1480 +{
  1.1481 +    if (location->Info().type != SH_SAMPLER_2D &&
  1.1482 +        location->Info().type != SH_SAMPLER_CUBE)
  1.1483 +    {
  1.1484 +        return true;
  1.1485 +    }
  1.1486 +
  1.1487 +    if (value >= 0 && value < mGLMaxTextureUnits)
  1.1488 +        return true;
  1.1489 +
  1.1490 +    ErrorInvalidValue("%s: this uniform location is a sampler, but %d is not a valid texture unit",
  1.1491 +                      info, value);
  1.1492 +    return false;
  1.1493 +}
  1.1494 +
  1.1495 +bool
  1.1496 +WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
  1.1497 +{
  1.1498 +    if (IsContextLost()) {
  1.1499 +        return false;
  1.1500 +    }
  1.1501 +    if (arrayLength < cnt) {
  1.1502 +        ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
  1.1503 +        return false;
  1.1504 +    }
  1.1505 +    return true;
  1.1506 +}
  1.1507 +
  1.1508 +bool
  1.1509 +WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
  1.1510 +                                         GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
  1.1511 +{
  1.1512 +    if (IsContextLost())
  1.1513 +        return false;
  1.1514 +    if (!ValidateUniformLocation(name, location_object))
  1.1515 +        return false;
  1.1516 +    location = location_object->Location();
  1.1517 +    uint32_t uniformElemSize = location_object->ElementSize();
  1.1518 +    if (expectedElemSize != uniformElemSize) {
  1.1519 +        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
  1.1520 +                              " got a uniform of element size %d", name,
  1.1521 +                              expectedElemSize,
  1.1522 +                              uniformElemSize);
  1.1523 +        return false;
  1.1524 +    }
  1.1525 +    if (arrayLength == 0 ||
  1.1526 +        arrayLength % expectedElemSize)
  1.1527 +    {
  1.1528 +        ErrorInvalidValue("%s: expected an array of length a multiple"
  1.1529 +                          " of %d, got an array of length %d", name,
  1.1530 +                          expectedElemSize,
  1.1531 +                          arrayLength);
  1.1532 +        return false;
  1.1533 +    }
  1.1534 +    const WebGLUniformInfo& info = location_object->Info();
  1.1535 +    if (!info.isArray &&
  1.1536 +        arrayLength != expectedElemSize) {
  1.1537 +        ErrorInvalidOperation("%s: expected an array of length exactly"
  1.1538 +                              " %d (since this uniform is not an array"
  1.1539 +                              " uniform), got an array of length %d", name,
  1.1540 +                              expectedElemSize,
  1.1541 +                              arrayLength);
  1.1542 +        return false;
  1.1543 +    }
  1.1544 +    numElementsToUpload =
  1.1545 +        std::min(info.arraySize, arrayLength / expectedElemSize);
  1.1546 +    return true;
  1.1547 +}
  1.1548 +
  1.1549 +bool
  1.1550 +WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
  1.1551 +                                              GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
  1.1552 +                                              WebGLboolean aTranspose)
  1.1553 +{
  1.1554 +    uint32_t expectedElemSize = (dim)*(dim);
  1.1555 +    if (IsContextLost())
  1.1556 +        return false;
  1.1557 +    if (!ValidateUniformLocation(name, location_object))
  1.1558 +        return false;
  1.1559 +    location = location_object->Location();
  1.1560 +    uint32_t uniformElemSize = location_object->ElementSize();
  1.1561 +    if (expectedElemSize != uniformElemSize) {
  1.1562 +        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
  1.1563 +                              " got a uniform of element size %d", name,
  1.1564 +                              expectedElemSize,
  1.1565 +                              uniformElemSize);
  1.1566 +        return false;
  1.1567 +    }
  1.1568 +    if (arrayLength == 0 ||
  1.1569 +        arrayLength % expectedElemSize)
  1.1570 +    {
  1.1571 +        ErrorInvalidValue("%s: expected an array of length a multiple"
  1.1572 +                          " of %d, got an array of length %d", name,
  1.1573 +                          expectedElemSize,
  1.1574 +                          arrayLength);
  1.1575 +        return false;
  1.1576 +    }
  1.1577 +    const WebGLUniformInfo& info = location_object->Info();
  1.1578 +    if (!info.isArray &&
  1.1579 +        arrayLength != expectedElemSize) {
  1.1580 +        ErrorInvalidOperation("%s: expected an array of length exactly"
  1.1581 +                              " %d (since this uniform is not an array"
  1.1582 +                              " uniform), got an array of length %d", name,
  1.1583 +                              expectedElemSize,
  1.1584 +                              arrayLength);
  1.1585 +        return false;
  1.1586 +    }
  1.1587 +    if (aTranspose) {
  1.1588 +        ErrorInvalidValue("%s: transpose must be FALSE as per the "
  1.1589 +                          "OpenGL ES 2.0 spec", name);
  1.1590 +        return false;
  1.1591 +    }
  1.1592 +    numElementsToUpload =
  1.1593 +        std::min(info.arraySize, arrayLength / (expectedElemSize));
  1.1594 +    return true;
  1.1595 +}
  1.1596 +
  1.1597 +bool
  1.1598 +WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
  1.1599 +{
  1.1600 +    if (IsContextLost())
  1.1601 +        return false;
  1.1602 +    if (!ValidateUniformLocation(name, location_object))
  1.1603 +        return false;
  1.1604 +    location = location_object->Location();
  1.1605 +    return true;
  1.1606 +}
  1.1607 +
  1.1608 +bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
  1.1609 +{
  1.1610 +    return mBoundVertexArray->EnsureAttrib(index, info);
  1.1611 +}
  1.1612 +
  1.1613 +bool WebGLContext::ValidateStencilParamsForDrawCall()
  1.1614 +{
  1.1615 +  const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
  1.1616 +  if (mStencilRefFront != mStencilRefBack) {
  1.1617 +      ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
  1.1618 +      return false;
  1.1619 +  }
  1.1620 +  if (mStencilValueMaskFront != mStencilValueMaskBack) {
  1.1621 +      ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
  1.1622 +      return false;
  1.1623 +  }
  1.1624 +  if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
  1.1625 +      ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
  1.1626 +      return false;
  1.1627 +  }
  1.1628 +  return true;
  1.1629 +}
  1.1630 +
  1.1631 +static inline int32_t floorPOT(int32_t x)
  1.1632 +{
  1.1633 +    MOZ_ASSERT(x > 0);
  1.1634 +    int32_t pot = 1;
  1.1635 +    while (pot < 0x40000000) {
  1.1636 +        if (x < pot*2)
  1.1637 +            break;
  1.1638 +        pot *= 2;
  1.1639 +    }
  1.1640 +    return pot;
  1.1641 +}
  1.1642 +
  1.1643 +bool
  1.1644 +WebGLContext::InitAndValidateGL()
  1.1645 +{
  1.1646 +    if (!gl) return false;
  1.1647 +
  1.1648 +    GLenum error = gl->fGetError();
  1.1649 +    if (error != LOCAL_GL_NO_ERROR) {
  1.1650 +        GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
  1.1651 +        return false;
  1.1652 +    }
  1.1653 +
  1.1654 +    mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
  1.1655 +    mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
  1.1656 +    mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
  1.1657 +    mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
  1.1658 +
  1.1659 +    if (MinCapabilityMode()) {
  1.1660 +      mDisableFragHighP = true;
  1.1661 +    }
  1.1662 +
  1.1663 +    // These are the default values, see 6.2 State tables in the
  1.1664 +    // OpenGL ES 2.0.25 spec.
  1.1665 +    mColorWriteMask[0] = 1;
  1.1666 +    mColorWriteMask[1] = 1;
  1.1667 +    mColorWriteMask[2] = 1;
  1.1668 +    mColorWriteMask[3] = 1;
  1.1669 +    mDepthWriteMask = 1;
  1.1670 +    mColorClearValue[0] = 0.f;
  1.1671 +    mColorClearValue[1] = 0.f;
  1.1672 +    mColorClearValue[2] = 0.f;
  1.1673 +    mColorClearValue[3] = 0.f;
  1.1674 +    mDepthClearValue = 1.f;
  1.1675 +    mStencilClearValue = 0;
  1.1676 +    mStencilRefFront = 0;
  1.1677 +    mStencilRefBack = 0;
  1.1678 +    mStencilValueMaskFront = 0xffffffff;
  1.1679 +    mStencilValueMaskBack  = 0xffffffff;
  1.1680 +    mStencilWriteMaskFront = 0xffffffff;
  1.1681 +    mStencilWriteMaskBack  = 0xffffffff;
  1.1682 +
  1.1683 +    // Bindings, etc.
  1.1684 +    mActiveTexture = 0;
  1.1685 +    mEmitContextLostErrorOnce = true;
  1.1686 +    mWebGLError = LOCAL_GL_NO_ERROR;
  1.1687 +    mUnderlyingGLError = LOCAL_GL_NO_ERROR;
  1.1688 +
  1.1689 +    mBound2DTextures.Clear();
  1.1690 +    mBoundCubeMapTextures.Clear();
  1.1691 +
  1.1692 +    mBoundArrayBuffer = nullptr;
  1.1693 +    mBoundTransformFeedbackBuffer = nullptr;
  1.1694 +    mCurrentProgram = nullptr;
  1.1695 +
  1.1696 +    mBoundFramebuffer = nullptr;
  1.1697 +    mBoundRenderbuffer = nullptr;
  1.1698 +
  1.1699 +    MakeContextCurrent();
  1.1700 +
  1.1701 +    // on desktop OpenGL, we always keep vertex attrib 0 array enabled
  1.1702 +    if (!gl->IsGLES()) {
  1.1703 +        gl->fEnableVertexAttribArray(0);
  1.1704 +    }
  1.1705 +
  1.1706 +    if (MinCapabilityMode()) {
  1.1707 +        mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
  1.1708 +    } else {
  1.1709 +        gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
  1.1710 +    }
  1.1711 +    if (mGLMaxVertexAttribs < 8) {
  1.1712 +        GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
  1.1713 +        return false;
  1.1714 +    }
  1.1715 +
  1.1716 +    // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
  1.1717 +    // even though the hardware supports much more.  The
  1.1718 +    // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
  1.1719 +    if (MinCapabilityMode()) {
  1.1720 +        mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
  1.1721 +    } else {
  1.1722 +        gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
  1.1723 +    }
  1.1724 +    if (mGLMaxTextureUnits < 8) {
  1.1725 +        GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
  1.1726 +        return false;
  1.1727 +    }
  1.1728 +
  1.1729 +    mBound2DTextures.SetLength(mGLMaxTextureUnits);
  1.1730 +    mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
  1.1731 +
  1.1732 +    if (MinCapabilityMode()) {
  1.1733 +        mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
  1.1734 +        mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
  1.1735 +        mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
  1.1736 +        mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
  1.1737 +        mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
  1.1738 +    } else {
  1.1739 +        gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
  1.1740 +        gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
  1.1741 +        gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
  1.1742 +        gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
  1.1743 +        gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
  1.1744 +    }
  1.1745 +
  1.1746 +    mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
  1.1747 +    mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);
  1.1748 +
  1.1749 +    if (MinCapabilityMode()) {
  1.1750 +        mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
  1.1751 +        mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
  1.1752 +        mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
  1.1753 +    } else {
  1.1754 +        if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
  1.1755 +            gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
  1.1756 +            gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
  1.1757 +            gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
  1.1758 +        } else {
  1.1759 +            gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
  1.1760 +            mGLMaxFragmentUniformVectors /= 4;
  1.1761 +            gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
  1.1762 +            mGLMaxVertexUniformVectors /= 4;
  1.1763 +
  1.1764 +            // we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
  1.1765 +            // however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
  1.1766 +            // and check OpenGL error for INVALID_ENUM.
  1.1767 +
  1.1768 +            // before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
  1.1769 +            error = gl->GetAndClearError();
  1.1770 +            if (error != LOCAL_GL_NO_ERROR) {
  1.1771 +                GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1.1772 +                return false;
  1.1773 +            }
  1.1774 +
  1.1775 +            // On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
  1.1776 +            //   mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
  1.1777 +            GLint maxVertexOutputComponents,
  1.1778 +                  minFragmentInputComponents;
  1.1779 +            gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
  1.1780 +            gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
  1.1781 +
  1.1782 +            error = gl->GetAndClearError();
  1.1783 +            switch (error) {
  1.1784 +                case LOCAL_GL_NO_ERROR:
  1.1785 +                    mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
  1.1786 +                    break;
  1.1787 +                case LOCAL_GL_INVALID_ENUM:
  1.1788 +                    mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
  1.1789 +                    break;
  1.1790 +                default:
  1.1791 +                    GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1.1792 +                    return false;
  1.1793 +            }
  1.1794 +        }
  1.1795 +    }
  1.1796 +
  1.1797 +    // Always 1 for GLES2
  1.1798 +    mMaxFramebufferColorAttachments = 1;
  1.1799 +
  1.1800 +    if (!gl->IsGLES()) {
  1.1801 +        // gl_PointSize is always available in ES2 GLSL, but has to be
  1.1802 +        // specifically enabled on desktop GLSL.
  1.1803 +        gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
  1.1804 +
  1.1805 +        // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
  1.1806 +        // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
  1.1807 +        //   http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
  1.1808 +        // Note that this used to cause crashes on old ATI drivers... hopefully not a significant
  1.1809 +        // problem anymore. See bug 602183.
  1.1810 +        gl->fEnable(LOCAL_GL_POINT_SPRITE);
  1.1811 +    }
  1.1812 +
  1.1813 +#ifdef XP_MACOSX
  1.1814 +    if (gl->WorkAroundDriverBugs() &&
  1.1815 +        gl->Vendor() == gl::GLVendor::ATI) {
  1.1816 +        // The Mac ATI driver, in all known OSX version up to and including 10.8,
  1.1817 +        // renders points sprites upside-down. Apple bug 11778921
  1.1818 +        gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN, LOCAL_GL_LOWER_LEFT);
  1.1819 +    }
  1.1820 +#endif
  1.1821 +
  1.1822 +    // Check the shader validator pref
  1.1823 +    NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
  1.1824 +
  1.1825 +    mShaderValidation =
  1.1826 +        Preferences::GetBool("webgl.shader_validator", mShaderValidation);
  1.1827 +
  1.1828 +    // initialize shader translator
  1.1829 +    if (mShaderValidation) {
  1.1830 +        if (!ShInitialize()) {
  1.1831 +            GenerateWarning("GLSL translator initialization failed!");
  1.1832 +            return false;
  1.1833 +        }
  1.1834 +    }
  1.1835 +
  1.1836 +    // Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
  1.1837 +    mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
  1.1838 +
  1.1839 +    // notice that the point of calling GetAndClearError here is not only to check for error,
  1.1840 +    // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
  1.1841 +    error = gl->GetAndClearError();
  1.1842 +    if (error != LOCAL_GL_NO_ERROR) {
  1.1843 +        GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
  1.1844 +        return false;
  1.1845 +    }
  1.1846 +
  1.1847 +    if (IsWebGL2() &&
  1.1848 +        !InitWebGL2())
  1.1849 +    {
  1.1850 +        // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
  1.1851 +        return false;
  1.1852 +    }
  1.1853 +
  1.1854 +    mMemoryPressureObserver
  1.1855 +        = new WebGLMemoryPressureObserver(this);
  1.1856 +    nsCOMPtr<nsIObserverService> observerService
  1.1857 +        = mozilla::services::GetObserverService();
  1.1858 +    if (observerService) {
  1.1859 +        observerService->AddObserver(mMemoryPressureObserver,
  1.1860 +                                     "memory-pressure",
  1.1861 +                                     false);
  1.1862 +    }
  1.1863 +
  1.1864 +    mDefaultVertexArray = new WebGLVertexArray(this);
  1.1865 +    mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
  1.1866 +    mBoundVertexArray = mDefaultVertexArray;
  1.1867 +
  1.1868 +    return true;
  1.1869 +}

mercurial