content/canvas/src/WebGLContextValidate.cpp

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

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

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

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

mercurial