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 +}