Bumping manifests a=b2g-bump
[gecko.git] / dom / canvas / WebGLContextValidate.cpp
blob6900d1e98030730bc5d4cb32b1a27bcaa7349c12
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLContext.h"
7 #include "WebGLBuffer.h"
8 #include "WebGLVertexAttribData.h"
9 #include "WebGLShader.h"
10 #include "WebGLProgram.h"
11 #include "WebGLUniformLocation.h"
12 #include "WebGLFramebuffer.h"
13 #include "WebGLRenderbuffer.h"
14 #include "WebGLTexture.h"
15 #include "WebGLVertexArray.h"
16 #include "GLContext.h"
17 #include "CanvasUtils.h"
18 #include "WebGLContextUtils.h"
20 #include "mozilla/CheckedInt.h"
21 #include "mozilla/Preferences.h"
22 #include "mozilla/Services.h"
24 #include "jsfriendapi.h"
26 #include "angle/ShaderLang.h"
28 #include <algorithm>
30 #include "mozilla/Services.h"
31 #include "nsIObserverService.h"
33 using namespace mozilla;
35 /**
36 * Return the block size for format.
38 static void
39 BlockSizeFor(GLenum format, GLint* blockWidth, GLint* blockHeight)
41 MOZ_ASSERT(blockWidth && blockHeight);
43 switch (format) {
44 case LOCAL_GL_ATC_RGB:
45 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
46 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
47 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
48 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
49 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
50 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
51 if (blockWidth)
52 *blockWidth = 4;
53 if (blockHeight)
54 *blockHeight = 4;
55 break;
57 case LOCAL_GL_ETC1_RGB8_OES:
58 // 4x4 blocks, but no 4-multiple requirement.
59 default:
60 break;
64 /**
65 * Return the displayable name for the texture function that is the
66 * source for validation.
68 static const char*
69 InfoFrom(WebGLTexImageFunc func)
71 // TODO: Account for dimensions (WebGL 2)
72 switch (func) {
73 case WebGLTexImageFunc::TexImage: return "texImage2D";
74 case WebGLTexImageFunc::TexSubImage: return "texSubImage2D";
75 case WebGLTexImageFunc::CopyTexImage: return "copyTexImage2D";
76 case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
77 case WebGLTexImageFunc::CompTexImage: return "compressedTexImage2D";
78 case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
79 default:
80 MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
81 return "(error)";
85 /**
86 * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
87 * name for \a glenum.
89 static void
90 ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
92 const char* name = WebGLContext::EnumName(glenum);
93 if (name)
94 ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
95 else
96 ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
99 /**
100 * Return true if the format is valid for source calls.
102 static bool
103 IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
105 switch (format) {
106 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
107 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
108 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
109 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
110 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
111 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
112 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
113 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
114 return (func == WebGLTexImageFunc::CompTexImage ||
115 func == WebGLTexImageFunc::CompTexSubImage);
117 case LOCAL_GL_ATC_RGB:
118 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
119 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
120 case LOCAL_GL_ETC1_RGB8_OES:
121 return func == WebGLTexImageFunc::CompTexImage;
124 return true;
128 * Returns true if func is a CopyTexImage variant.
130 static bool
131 IsCopyFunc(WebGLTexImageFunc func)
133 return (func == WebGLTexImageFunc::CopyTexImage ||
134 func == WebGLTexImageFunc::CopyTexSubImage);
138 * Returns true if func is a SubImage variant.
140 static bool
141 IsSubFunc(WebGLTexImageFunc func)
143 return (func == WebGLTexImageFunc::TexSubImage ||
144 func == WebGLTexImageFunc::CopyTexSubImage ||
145 func == WebGLTexImageFunc::CompTexSubImage);
149 * returns true is target is a texture cube map target.
151 static bool
152 IsTexImageCubemapTarget(GLenum target)
154 return (target >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
155 target <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
159 * Pull data out of the program, post-linking
161 bool
162 WebGLProgram::UpdateInfo()
164 mAttribMaxNameLength = 0;
165 for (size_t i = 0; i < mAttachedShaders.Length(); i++)
166 mAttribMaxNameLength = std::max(mAttribMaxNameLength, mAttachedShaders[i]->mAttribMaxNameLength);
168 GLint attribCount;
169 mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
171 if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
172 mContext->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext->mGLMaxVertexAttribs);
173 return false;
176 for (size_t i = 0; i < mAttribsInUse.Length(); i++)
177 mAttribsInUse[i] = false;
179 nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
181 for (int i = 0; i < attribCount; ++i) {
182 GLint attrnamelen;
183 GLint attrsize;
184 GLenum attrtype;
185 mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength, &attrnamelen, &attrsize, &attrtype, nameBuf);
186 if (attrnamelen > 0) {
187 GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
188 MOZ_ASSERT(loc >= 0, "major oops in managing the attributes of a WebGL program");
189 if (loc < mContext->mGLMaxVertexAttribs) {
190 mAttribsInUse[loc] = true;
191 } else {
192 mContext->GenerateWarning("program exceeds MAX_VERTEX_ATTRIBS");
193 return false;
198 // nsAutoPtr will delete old version first
199 mIdentifierMap = new CStringMap;
200 mIdentifierReverseMap = new CStringMap;
201 mUniformInfoMap = new CStringToUniformInfoMap;
202 for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
203 // Loop through ATTRIBUTES
204 for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
205 const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
206 mIdentifierMap->Put(attrib.original, attrib.mapped); // FORWARD MAPPING
207 mIdentifierReverseMap->Put(attrib.mapped, attrib.original); // REVERSE MAPPING
210 // Loop through UNIFORMS
211 for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
212 // Add the uniforms name mapping to mIdentifier[Reverse]Map
213 const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
214 mIdentifierMap->Put(uniform.original, uniform.mapped); // FOWARD MAPPING
215 mIdentifierReverseMap->Put(uniform.mapped, uniform.original); // REVERSE MAPPING
217 // Add uniform info to mUniformInfoMap
218 const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
219 mUniformInfoMap->Put(uniform.mapped, info);
223 mActiveAttribMap.clear();
225 GLint numActiveAttrs = 0;
226 mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
228 // Spec says the maximum attrib name length is 256 chars, so this is
229 // sufficient to hold any attrib name.
230 char attrName[257];
232 GLint dummySize;
233 GLenum dummyType;
234 for (GLint i = 0; i < numActiveAttrs; i++) {
235 mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
236 &dummyType, attrName);
237 GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
238 MOZ_ASSERT(attrLoc >= 0);
239 mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
242 return true;
246 * Return the simple base format for a given internal format.
248 * \return the corresponding \u base internal format (GL_ALPHA, GL_LUMINANCE,
249 * GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA), or GL_NONE if invalid enum.
251 GLenum
252 WebGLContext::BaseTexFormat(GLenum internalFormat) const
254 if (internalFormat == LOCAL_GL_ALPHA ||
255 internalFormat == LOCAL_GL_LUMINANCE ||
256 internalFormat == LOCAL_GL_LUMINANCE_ALPHA ||
257 internalFormat == LOCAL_GL_RGB ||
258 internalFormat == LOCAL_GL_RGBA)
260 return internalFormat;
263 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB)) {
264 if (internalFormat == LOCAL_GL_SRGB)
265 return LOCAL_GL_RGB;
267 if (internalFormat == LOCAL_GL_SRGB_ALPHA)
268 return LOCAL_GL_RGBA;
271 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc)) {
272 if (internalFormat == LOCAL_GL_ATC_RGB)
273 return LOCAL_GL_RGB;
275 if (internalFormat == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
276 internalFormat == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
278 return LOCAL_GL_RGBA;
282 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1)) {
283 if (internalFormat == LOCAL_GL_ETC1_RGB8_OES)
284 return LOCAL_GL_RGB;
287 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) {
288 if (internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
289 internalFormat == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1)
291 return LOCAL_GL_RGB;
294 if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
295 internalFormat == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
297 return LOCAL_GL_RGBA;
301 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc)) {
302 if (internalFormat == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT)
303 return LOCAL_GL_RGB;
305 if (internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
306 internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
307 internalFormat == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
309 return LOCAL_GL_RGBA;
313 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
314 if (internalFormat == LOCAL_GL_DEPTH_COMPONENT ||
315 internalFormat == LOCAL_GL_DEPTH_COMPONENT16 ||
316 internalFormat == LOCAL_GL_DEPTH_COMPONENT32)
318 return LOCAL_GL_DEPTH_COMPONENT;
321 if (internalFormat == LOCAL_GL_DEPTH_STENCIL ||
322 internalFormat == LOCAL_GL_DEPTH24_STENCIL8)
324 return LOCAL_GL_DEPTH_STENCIL;
328 MOZ_ASSERT(false, "Unhandled internalFormat");
329 return LOCAL_GL_NONE;
332 bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char *info)
334 switch (mode) {
335 case LOCAL_GL_FUNC_ADD:
336 case LOCAL_GL_FUNC_SUBTRACT:
337 case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
338 return true;
339 case LOCAL_GL_MIN:
340 case LOCAL_GL_MAX:
341 if (IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) {
342 return true;
344 break;
345 default:
346 break;
349 ErrorInvalidEnumInfo(info, mode);
350 return false;
353 bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char *info)
355 switch (factor) {
356 case LOCAL_GL_ZERO:
357 case LOCAL_GL_ONE:
358 case LOCAL_GL_SRC_COLOR:
359 case LOCAL_GL_ONE_MINUS_SRC_COLOR:
360 case LOCAL_GL_DST_COLOR:
361 case LOCAL_GL_ONE_MINUS_DST_COLOR:
362 case LOCAL_GL_SRC_ALPHA:
363 case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
364 case LOCAL_GL_DST_ALPHA:
365 case LOCAL_GL_ONE_MINUS_DST_ALPHA:
366 case LOCAL_GL_CONSTANT_COLOR:
367 case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
368 case LOCAL_GL_CONSTANT_ALPHA:
369 case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
370 return true;
371 default:
372 ErrorInvalidEnumInfo(info, factor);
373 return false;
377 bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char *info)
379 if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
380 return true;
381 else
382 return ValidateBlendFuncDstEnum(factor, info);
385 bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info)
387 bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
388 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
389 bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
390 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
391 bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
392 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
393 bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
394 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
395 if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
396 (dfactorIsConstantColor && sfactorIsConstantAlpha) ) {
397 ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info);
398 return false;
399 } else {
400 return true;
404 bool WebGLContext::ValidateTextureTargetEnum(GLenum target, const char *info)
406 switch (target) {
407 case LOCAL_GL_TEXTURE_2D:
408 case LOCAL_GL_TEXTURE_CUBE_MAP:
409 return true;
410 default:
411 ErrorInvalidEnumInfo(info, target);
412 return false;
416 bool WebGLContext::ValidateComparisonEnum(GLenum target, const char *info)
418 switch (target) {
419 case LOCAL_GL_NEVER:
420 case LOCAL_GL_LESS:
421 case LOCAL_GL_LEQUAL:
422 case LOCAL_GL_GREATER:
423 case LOCAL_GL_GEQUAL:
424 case LOCAL_GL_EQUAL:
425 case LOCAL_GL_NOTEQUAL:
426 case LOCAL_GL_ALWAYS:
427 return true;
428 default:
429 ErrorInvalidEnumInfo(info, target);
430 return false;
434 bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char *info)
436 switch (action) {
437 case LOCAL_GL_KEEP:
438 case LOCAL_GL_ZERO:
439 case LOCAL_GL_REPLACE:
440 case LOCAL_GL_INCR:
441 case LOCAL_GL_INCR_WRAP:
442 case LOCAL_GL_DECR:
443 case LOCAL_GL_DECR_WRAP:
444 case LOCAL_GL_INVERT:
445 return true;
446 default:
447 ErrorInvalidEnumInfo(info, action);
448 return false;
452 bool WebGLContext::ValidateFaceEnum(GLenum face, const char *info)
454 switch (face) {
455 case LOCAL_GL_FRONT:
456 case LOCAL_GL_BACK:
457 case LOCAL_GL_FRONT_AND_BACK:
458 return true;
459 default:
460 ErrorInvalidEnumInfo(info, face);
461 return false;
465 bool WebGLContext::ValidateDrawModeEnum(GLenum mode, const char *info)
467 switch (mode) {
468 case LOCAL_GL_TRIANGLES:
469 case LOCAL_GL_TRIANGLE_STRIP:
470 case LOCAL_GL_TRIANGLE_FAN:
471 case LOCAL_GL_POINTS:
472 case LOCAL_GL_LINE_STRIP:
473 case LOCAL_GL_LINE_LOOP:
474 case LOCAL_GL_LINES:
475 return true;
476 default:
477 ErrorInvalidEnumInfo(info, mode);
478 return false;
482 bool WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char *info)
484 if (name.IsEmpty())
485 return false;
487 const uint32_t maxSize = 256;
488 if (name.Length() > maxSize) {
489 ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
490 info, name.Length(), maxSize);
491 return false;
494 if (!ValidateGLSLString(name, info)) {
495 return false;
498 nsString prefix1 = NS_LITERAL_STRING("webgl_");
499 nsString prefix2 = NS_LITERAL_STRING("_webgl_");
501 if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
502 Substring(name, 0, prefix2.Length()).Equals(prefix2))
504 ErrorInvalidOperation("%s: string contains a reserved GLSL prefix", info);
505 return false;
508 return true;
511 bool WebGLContext::ValidateGLSLString(const nsAString& string, const char *info)
513 for (uint32_t i = 0; i < string.Length(); ++i) {
514 if (!ValidateGLSLCharacter(string.CharAt(i))) {
515 ErrorInvalidValue("%s: string contains the illegal character '%d'", info, string.CharAt(i));
516 return false;
520 return true;
524 * Return true if format is a valid texture image format for source,
525 * taking into account enabled WebGL extensions.
527 bool
528 WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
530 /* Core WebGL texture formats */
531 if (format == LOCAL_GL_ALPHA ||
532 format == LOCAL_GL_RGB ||
533 format == LOCAL_GL_RGBA ||
534 format == LOCAL_GL_LUMINANCE ||
535 format == LOCAL_GL_LUMINANCE_ALPHA)
537 return true;
540 /* WEBGL_depth_texture added formats */
541 if (format == LOCAL_GL_DEPTH_COMPONENT ||
542 format == LOCAL_GL_DEPTH_STENCIL)
544 if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
545 ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
546 InfoFrom(func), EnumName(format));
547 return false;
550 // If WEBGL_depth_texture is enabled, then it is not allowed to be used with the
551 // texSubImage, copyTexImage, or copyTexSubImage methods
552 if (func == WebGLTexImageFunc::TexSubImage ||
553 func == WebGLTexImageFunc::CopyTexImage ||
554 func == WebGLTexImageFunc::CopyTexSubImage)
556 ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func), EnumName(format));
557 return false;
560 return true;
563 // Needs to be below the depth_texture check because an invalid operation
564 // error needs to be generated instead of invalid enum.
565 /* Only core formats are valid for CopyTex(Sub)?Image */
566 // TODO: Revisit this once color_buffer_(half_)?float lands
567 if (IsCopyFunc(func)) {
568 ErrorInvalidEnumWithName(this, "invalid format", format, func);
569 return false;
572 /* EXT_sRGB added formats */
573 if (format == LOCAL_GL_SRGB ||
574 format == LOCAL_GL_SRGB_ALPHA)
576 bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
577 if (!validFormat)
578 ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
579 InfoFrom(func), WebGLContext::EnumName(format));
580 return validFormat;
583 /* WEBGL_compressed_texture_atc added formats */
584 if (format == LOCAL_GL_ATC_RGB ||
585 format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
586 format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
588 bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
589 if (!validFormat)
590 ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
591 InfoFrom(func), WebGLContext::EnumName(format));
592 return validFormat;
595 // WEBGL_compressed_texture_etc1
596 if (format == LOCAL_GL_ETC1_RGB8_OES) {
597 bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
598 if (!validFormat)
599 ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
600 InfoFrom(func), WebGLContext::EnumName(format));
601 return validFormat;
605 if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
606 format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
607 format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
608 format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
610 bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
611 if (!validFormat)
612 ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
613 InfoFrom(func), WebGLContext::EnumName(format));
614 return validFormat;
618 if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
619 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
620 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
621 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
623 bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
624 if (!validFormat)
625 ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
626 InfoFrom(func), WebGLContext::EnumName(format));
627 return validFormat;
630 ErrorInvalidEnumWithName(this, "invalid format", format, func);
632 return false;
636 * Check if the given texture target is valid for TexImage.
638 bool
639 WebGLContext::ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func)
641 switch (dims) {
642 case 2:
643 if (target == LOCAL_GL_TEXTURE_2D ||
644 IsTexImageCubemapTarget(target))
646 return true;
649 ErrorInvalidEnumWithName(this, "invalid target", target, func);
650 return false;
652 default:
653 MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
656 return false;
660 * Return true if type is a valid texture image type for source,
661 * taking into account enabled WebGL extensions.
663 bool
664 WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func)
666 /* Core WebGL texture types */
667 if (type == LOCAL_GL_UNSIGNED_BYTE ||
668 type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
669 type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
670 type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
672 return true;
675 /* OES_texture_float added types */
676 if (type == LOCAL_GL_FLOAT) {
677 bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
678 if (!validType)
679 ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
680 InfoFrom(func), WebGLContext::EnumName(type));
681 return validType;
684 /* OES_texture_half_float add types */
685 if (type == LOCAL_GL_HALF_FLOAT_OES) {
686 bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
687 if (!validType)
688 ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
689 InfoFrom(func), WebGLContext::EnumName(type));
690 return validType;
693 /* WEBGL_depth_texture added types */
694 if (type == LOCAL_GL_UNSIGNED_SHORT ||
695 type == LOCAL_GL_UNSIGNED_INT ||
696 type == LOCAL_GL_UNSIGNED_INT_24_8)
698 bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
699 if (!validType)
700 ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
701 InfoFrom(func), WebGLContext::EnumName(type));
702 return validType;
705 ErrorInvalidEnumWithName(this, "invalid type", type, func);
706 return false;
710 * Validate texture image sizing extra constraints for
711 * CompressedTex(Sub)?Image.
713 // TODO: WebGL 2
714 bool
715 WebGLContext::ValidateCompTexImageSize(GLenum target, GLint level, GLenum format,
716 GLint xoffset, GLint yoffset,
717 GLsizei width, GLsizei height,
718 GLsizei levelWidth, GLsizei levelHeight,
719 WebGLTexImageFunc func)
721 // Negative parameters must already have been handled above
722 MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
723 width >= 0 && height >= 0);
725 if (xoffset + width > (GLint) levelWidth) {
726 ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
727 return false;
730 if (yoffset + height > (GLint) levelHeight) {
731 ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
732 return false;
735 GLint blockWidth = 1;
736 GLint blockHeight = 1;
737 BlockSizeFor(format, &blockWidth, &blockHeight);
739 /* If blockWidth || blockHeight != 1, then the compressed format
740 * had block-based constraints to be checked. (For example, PVRTC is compressed but
741 * isn't a block-based format)
743 if (blockWidth != 1 || blockHeight != 1) {
744 /* offsets must be multiple of block size */
745 if (xoffset % blockWidth != 0) {
746 ErrorInvalidOperation("%s: xoffset must be multiple of %d",
747 InfoFrom(func), blockWidth);
748 return false;
751 if (yoffset % blockHeight != 0) {
752 ErrorInvalidOperation("%s: yoffset must be multiple of %d",
753 InfoFrom(func), blockHeight);
754 return false;
757 /* The size must be a multiple of blockWidth and blockHeight,
758 * or must be using offset+size that exactly hits the edge.
759 * Important for small mipmap levels.
761 /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
762 * "When level equals zero width and height must be a multiple of 4. When
763 * level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
764 * If they are not an INVALID_OPERATION error is generated."
766 if (level == 0) {
767 if (width % blockWidth != 0) {
768 ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
769 InfoFrom(func), blockWidth);
770 return false;
773 if (height % blockHeight != 0) {
774 ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
775 InfoFrom(func), blockHeight);
776 return false;
779 else if (level > 0) {
780 if (width % blockWidth != 0 && width > 2) {
781 ErrorInvalidOperation("%s: width of level %d must be multiple"
782 " of %d or 0, 1, 2",
783 InfoFrom(func), level, blockWidth);
784 return false;
787 if (height % blockHeight != 0 && height > 2) {
788 ErrorInvalidOperation("%s: height of level %d must be multiple"
789 " of %d or 0, 1, 2",
790 InfoFrom(func), level, blockHeight);
791 return false;
795 if (IsSubFunc(func)) {
796 if ((xoffset % blockWidth) != 0) {
797 ErrorInvalidOperation("%s: xoffset must be multiple of %d",
798 InfoFrom(func), blockWidth);
799 return false;
802 if (yoffset % blockHeight != 0) {
803 ErrorInvalidOperation("%s: yoffset must be multiple of %d",
804 InfoFrom(func), blockHeight);
805 return false;
810 switch (format) {
811 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
812 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
813 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
814 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
815 if (!is_pot_assuming_nonnegative(width) ||
816 !is_pot_assuming_nonnegative(height))
818 ErrorInvalidValue("%s: width and height must be powers of two",
819 InfoFrom(func));
820 return false;
824 return true;
828 * Return true if the enough data is present to satisfy compressed
829 * texture format constraints.
831 bool
832 WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
833 GLsizei width, GLsizei height,
834 uint32_t byteLength, WebGLTexImageFunc func)
836 // negative width and height must already have been handled above
837 MOZ_ASSERT(width >= 0 && height >= 0);
839 CheckedUint32 required_byteLength = 0;
841 switch (format) {
842 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
843 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
844 case LOCAL_GL_ATC_RGB:
845 case LOCAL_GL_ETC1_RGB8_OES:
847 required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 8;
848 break;
850 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
851 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
852 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
853 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
855 required_byteLength = ((CheckedUint32(width) + 3) / 4) * ((CheckedUint32(height) + 3) / 4) * 16;
856 break;
858 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
859 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
861 required_byteLength = CheckedUint32(std::max(width, 8)) * CheckedUint32(std::max(height, 8)) / 2;
862 break;
864 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
865 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
867 required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
868 break;
872 if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
873 ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
874 return false;
877 return true;
881 * Validate the width, height, and depth of a texture image, \return
882 * true is valid, false otherwise.
883 * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
884 * Target and level must have been validated before calling.
886 bool
887 WebGLContext::ValidateTexImageSize(GLenum target, GLint level,
888 GLint width, GLint height, GLint depth,
889 WebGLTexImageFunc func)
891 MOZ_ASSERT(level >= 0, "level should already be validated");
893 /* Bug 966630: maxTextureSize >> level runs into "undefined"
894 * behaviour depending on ISA. For example, on Intel shifts
895 * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
896 * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
897 * what would be expected. Make the required behaviour explicit by
898 * clamping to a shift of 31 bits if level is greater than that
899 * ammount. This will give 0 that if (!maxAllowedSize) is
900 * expecting.
903 if (level > 31)
904 level = 31;
906 const GLuint maxTexImageSize = MaxTextureSizeForTarget(target) >> level;
907 const bool isCubemapTarget = IsTexImageCubemapTarget(target);
908 const bool isSub = IsSubFunc(func);
910 if (!isSub && isCubemapTarget && (width != height)) {
911 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
912 * "When the target parameter to TexImage2D is one of the
913 * six cube map two-dimensional image targets, the error
914 * INVALID_VALUE is generated if the width and height
915 * parameters are not equal."
917 ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
918 return false;
921 if (target == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
923 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
924 * "If wt and ht are the specified image width and height,
925 * and if either wt or ht are less than zero, then the error
926 * INVALID_VALUE is generated."
928 if (width < 0) {
929 ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
930 return false;
933 if (height < 0) {
934 ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
935 return false;
938 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
939 * "The maximum allowable width and height of a
940 * two-dimensional texture image must be at least 2**(k−lod)
941 * for image arrays of level zero through k, where k is the
942 * log base 2 of MAX_TEXTURE_SIZE. and lod is the
943 * level-of-detail of the image array. It may be zero for
944 * image arrays of any level-of-detail greater than k. The
945 * error INVALID_VALUE is generated if the specified image
946 * is too large to be stored under any conditions.
948 if (width > (int) maxTexImageSize) {
949 ErrorInvalidValue("%s: the maximum width for level %d is %u",
950 InfoFrom(func), level, maxTexImageSize);
951 return false;
954 if (height > (int) maxTexImageSize) {
955 ErrorInvalidValue("%s: tex maximum height for level %d is %u",
956 InfoFrom(func), level, maxTexImageSize);
957 return false;
960 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
961 * "If level is greater than zero, and either width or
962 * height is not a power-of-two, the error INVALID_VALUE is
963 * generated."
965 if (level > 0) {
966 if (!is_pot_assuming_nonnegative(width)) {
967 ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
968 InfoFrom(func), width);
969 return false;
972 if (!is_pot_assuming_nonnegative(height)) {
973 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
974 InfoFrom(func), height);
975 return false;
980 // TODO: WebGL 2
981 if (target == LOCAL_GL_TEXTURE_3D) {
982 if (depth < 0) {
983 ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
984 return false;
987 if (!is_pot_assuming_nonnegative(depth)) {
988 ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
989 InfoFrom(func), depth);
990 return false;
994 return true;
998 * Validate texture image sizing for Tex(Sub)?Image variants.
1000 // TODO: WebGL 2. Update this to handle 3D textures.
1001 bool
1002 WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
1003 GLsizei width, GLsizei height, GLsizei /*depth*/,
1004 GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
1005 WebGLTexImageFunc func)
1007 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
1008 * "Taking wt and ht to be the specified width and height of the
1009 * texture array, and taking x, y, w, and h to be the xoffset,
1010 * yoffset, width, and height argument values, any of the
1011 * following relationships generates the error INVALID_VALUE:
1012 * x < 0
1013 * x + w > wt
1014 * y < 0
1015 * y + h > ht"
1018 if (xoffset < 0) {
1019 ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
1020 return false;
1023 if (yoffset < 0) {
1024 ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
1025 return false;
1028 if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
1029 ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
1030 return false;
1033 return true;
1037 * Return the bits per texel for format & type combination.
1038 * Assumes that format & type are a valid combination as checked with
1039 * ValidateTexImageFormatAndType().
1041 uint32_t
1042 WebGLContext::GetBitsPerTexel(GLenum format, GLenum type)
1044 // If there is no defined format or type, we're not taking up any memory
1045 if (!format || !type) {
1046 return 0;
1049 /* Known fixed-sized types */
1050 if (type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
1051 type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
1052 type == LOCAL_GL_UNSIGNED_SHORT_5_6_5)
1054 return 16;
1057 if (type == LOCAL_GL_UNSIGNED_INT_24_8)
1058 return 32;
1060 int bitsPerComponent = 0;
1061 switch (type) {
1062 case LOCAL_GL_UNSIGNED_BYTE:
1063 bitsPerComponent = 8;
1064 break;
1066 case LOCAL_GL_HALF_FLOAT:
1067 case LOCAL_GL_HALF_FLOAT_OES:
1068 case LOCAL_GL_UNSIGNED_SHORT:
1069 bitsPerComponent = 16;
1070 break;
1072 case LOCAL_GL_FLOAT:
1073 case LOCAL_GL_UNSIGNED_INT:
1074 bitsPerComponent = 32;
1075 break;
1077 default:
1078 MOZ_ASSERT(false, "Unhandled type.");
1079 break;
1082 switch (format) {
1083 // Uncompressed formats
1084 case LOCAL_GL_ALPHA:
1085 case LOCAL_GL_LUMINANCE:
1086 case LOCAL_GL_DEPTH_COMPONENT:
1087 case LOCAL_GL_DEPTH_STENCIL:
1088 return 1 * bitsPerComponent;
1090 case LOCAL_GL_LUMINANCE_ALPHA:
1091 return 2 * bitsPerComponent;
1093 case LOCAL_GL_RGB:
1094 case LOCAL_GL_RGB32F:
1095 case LOCAL_GL_SRGB_EXT:
1096 return 3 * bitsPerComponent;
1098 case LOCAL_GL_RGBA:
1099 case LOCAL_GL_RGBA32F:
1100 case LOCAL_GL_SRGB_ALPHA_EXT:
1101 return 4 * bitsPerComponent;
1103 // Compressed formats
1104 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
1105 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
1106 return 2;
1108 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1109 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1110 case LOCAL_GL_ATC_RGB:
1111 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
1112 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
1113 case LOCAL_GL_ETC1_RGB8_OES:
1114 return 4;
1116 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1117 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1118 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
1119 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
1120 return 8;
1122 default:
1123 break;
1126 MOZ_ASSERT(false, "Unhandled format+type combo.");
1127 return 0;
1131 * Perform validation of format/type combinations for TexImage variants.
1132 * Returns true if the format/type is a valid combination, false otherwise.
1134 bool
1135 WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func)
1137 if (!ValidateTexImageFormat(format, func) ||
1138 !ValidateTexImageType(type, func))
1140 return false;
1143 bool validCombo = false;
1145 switch (format) {
1146 case LOCAL_GL_ALPHA:
1147 case LOCAL_GL_LUMINANCE:
1148 case LOCAL_GL_LUMINANCE_ALPHA:
1149 validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
1150 type == LOCAL_GL_HALF_FLOAT ||
1151 type == LOCAL_GL_HALF_FLOAT_OES ||
1152 type == LOCAL_GL_FLOAT);
1153 break;
1155 case LOCAL_GL_RGB:
1156 case LOCAL_GL_SRGB:
1157 validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
1158 type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
1159 type == LOCAL_GL_HALF_FLOAT ||
1160 type == LOCAL_GL_HALF_FLOAT_OES ||
1161 type == LOCAL_GL_FLOAT);
1162 break;
1164 case LOCAL_GL_RGBA:
1165 case LOCAL_GL_SRGB_ALPHA:
1166 validCombo = (type == LOCAL_GL_UNSIGNED_BYTE ||
1167 type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
1168 type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1 ||
1169 type == LOCAL_GL_HALF_FLOAT ||
1170 type == LOCAL_GL_HALF_FLOAT_OES ||
1171 type == LOCAL_GL_FLOAT);
1172 break;
1174 case LOCAL_GL_DEPTH_COMPONENT:
1175 validCombo = (type == LOCAL_GL_UNSIGNED_SHORT ||
1176 type == LOCAL_GL_UNSIGNED_INT);
1177 break;
1179 case LOCAL_GL_DEPTH_STENCIL:
1180 validCombo = (type == LOCAL_GL_UNSIGNED_INT_24_8);
1181 break;
1183 case LOCAL_GL_ATC_RGB:
1184 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
1185 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
1186 case LOCAL_GL_ETC1_RGB8_OES:
1187 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
1188 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
1189 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
1190 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
1191 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1192 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1193 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1194 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1195 validCombo = (type == LOCAL_GL_UNSIGNED_BYTE);
1196 break;
1198 default:
1199 // Only valid formats should be passed to the switch stmt.
1200 MOZ_ASSERT(false, "Unexpected format and type combo. How'd this happen?");
1201 validCombo = false;
1202 // Fall through to return an InvalidOperations. This will alert us to the
1203 // unexpected case that needs fixing in builds without asserts.
1206 if (!validCombo)
1207 ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
1208 InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
1210 return validCombo;
1214 * Return true if format, type and jsArrayType are a valid combination.
1215 * Also returns the size for texel of format and type (in bytes) via
1216 * \a texelSize.
1218 * It is assumed that type has previously been validated.
1220 bool
1221 WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
1223 bool validInput = false;
1224 const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
1226 // First, we check for packed types
1227 switch (type) {
1228 case LOCAL_GL_UNSIGNED_BYTE:
1229 validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
1230 break;
1232 case LOCAL_GL_HALF_FLOAT:
1233 case LOCAL_GL_HALF_FLOAT_OES:
1234 case LOCAL_GL_UNSIGNED_SHORT:
1235 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
1236 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
1237 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
1238 validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
1239 break;
1241 case LOCAL_GL_UNSIGNED_INT:
1242 case LOCAL_GL_UNSIGNED_INT_24_8:
1243 validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint32);
1244 break;
1246 case LOCAL_GL_FLOAT:
1247 validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Float32);
1248 break;
1250 default:
1251 break;
1254 if (!validInput)
1255 ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
1257 return validInput;
1261 * Checks specific for the CopyTex[Sub]Image2D functions.
1262 * Verifies:
1263 * - Framebuffer is complete and has valid read planes
1264 * - Copy format is a subset of framebuffer format (i.e. all required components are available)
1266 bool
1267 WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func)
1269 MOZ_ASSERT(IsCopyFunc(func));
1271 // Default framebuffer format
1272 GLenum fboFormat = bool(gl->GetPixelFormat().alpha > 0) ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
1274 if (mBoundFramebuffer) {
1275 if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
1276 ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func));
1277 return false;
1280 GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
1281 if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
1282 ErrorInvalidOperation("%s: Read source attachment doesn't have the"
1283 " correct color/depth/stencil type.", InfoFrom(func));
1284 return false;
1287 // Get the correct format for the framebuffer, as it's not the default one
1288 const WebGLFramebuffer::Attachment& color0 = mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
1289 fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
1292 // Make sure the format of the framebuffer is a superset of
1293 // the format requested by the CopyTex[Sub]Image2D functions.
1294 const GLComponents formatComps = GLComponents(format);
1295 const GLComponents fboComps = GLComponents(fboFormat);
1296 if (!formatComps.IsSubsetOf(fboComps)) {
1297 ErrorInvalidOperation("%s: format %s is not a subset of the current framebuffer format, which is %s.",
1298 InfoFrom(func), EnumName(format), EnumName(fboFormat));
1299 return false;
1302 return true;
1306 * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
1307 * Verifies each of the parameters against the WebGL standard and enabled extensions.
1309 // TODO: Texture dims is here for future expansion in WebGL 2.0
1310 bool
1311 WebGLContext::ValidateTexImage(GLuint dims, GLenum target,
1312 GLint level, GLint internalFormat,
1313 GLint xoffset, GLint yoffset, GLint zoffset,
1314 GLint width, GLint height, GLint depth,
1315 GLint border, GLenum format, GLenum type,
1316 WebGLTexImageFunc func)
1318 const char* info = InfoFrom(func);
1320 /* Check target */
1321 if (!ValidateTexImageTarget(dims, target, func))
1322 return false;
1324 /* Check level */
1325 if (level < 0) {
1326 ErrorInvalidValue("%s: level must be >= 0", info);
1327 return false;
1330 /* Check border */
1331 if (border != 0) {
1332 ErrorInvalidValue("%s: border must be 0", info);
1333 return false;
1336 /* Check incoming image format and type */
1337 if (!ValidateTexImageFormatAndType(format, type, func))
1338 return false;
1340 /* WebGL and OpenGL ES 2.0 impose additional restrictions on the
1341 * combinations of format, internalFormat, and type that can be
1342 * used. Formats and types that require additional extensions
1343 * (e.g., GL_FLOAT requires GL_OES_texture_float) are filtered
1344 * elsewhere.
1346 if ((GLint) format != internalFormat) {
1347 ErrorInvalidOperation("%s: format does not match internalformat", info);
1348 return false;
1351 /* check internalFormat */
1352 // TODO: Not sure if this is a bit of over kill.
1353 if (BaseTexFormat(internalFormat) == LOCAL_GL_NONE) {
1354 MOZ_ASSERT(false);
1355 ErrorInvalidValue("%s:", info);
1356 return false;
1359 /* Check texture image size */
1360 if (!ValidateTexImageSize(target, level, width, height, 0, func))
1361 return false;
1363 /* 5.14.8 Texture objects - WebGL Spec.
1364 * "If an attempt is made to call these functions with no
1365 * WebGLTexture bound (see above), an INVALID_OPERATION error
1366 * is generated."
1368 WebGLTexture* tex = activeBoundTextureForTarget(target);
1369 if (!tex) {
1370 ErrorInvalidOperation("%s: no texture is bound to target %s",
1371 info, WebGLContext::EnumName(target));
1372 return false;
1375 if (IsSubFunc(func)) {
1376 if (!tex->HasImageInfoAt(target, level)) {
1377 ErrorInvalidOperation("%s: no texture image previously defined for target %s at level %d",
1378 info, WebGLContext::EnumName(target), level);
1379 return false;
1382 const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(target, level);
1383 if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
1384 width, height, depth,
1385 imageInfo.Width(), imageInfo.Height(), 0,
1386 func))
1388 return false;
1391 /* Require the format and type to match that of the existing
1392 * texture as created
1394 if (imageInfo.WebGLFormat() != format ||
1395 imageInfo.WebGLType() != type)
1397 ErrorInvalidOperation("%s: format or type doesn't match the existing texture",
1398 info);
1399 return false;
1403 /* Additional checks for depth textures */
1404 if (target != LOCAL_GL_TEXTURE_2D &&
1405 (format == LOCAL_GL_DEPTH_COMPONENT ||
1406 format == LOCAL_GL_DEPTH_STENCIL))
1408 ErrorInvalidOperation("%s: with format of %s target must be TEXTURE_2D",
1409 info, WebGLContext::EnumName(format));
1410 return false;
1413 /* Additional checks for compressed textures */
1414 if (!IsAllowedFromSource(format, func)) {
1415 ErrorInvalidOperation("%s: Invalid format %s for this operation",
1416 info, WebGLContext::EnumName(format));
1417 return false;
1420 /* Parameters are OK */
1421 return true;
1424 bool
1425 WebGLContext::ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object)
1427 if (!ValidateObjectAllowNull(info, location_object))
1428 return false;
1429 if (!location_object)
1430 return false;
1431 /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
1432 if (!mCurrentProgram) {
1433 ErrorInvalidOperation("%s: no program is currently bound", info);
1434 return false;
1436 if (mCurrentProgram != location_object->Program()) {
1437 ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info);
1438 return false;
1440 if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) {
1441 ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info);
1442 return false;
1444 return true;
1447 bool
1448 WebGLContext::ValidateSamplerUniformSetter(const char* info, WebGLUniformLocation *location, GLint value)
1450 if (location->Info().type != SH_SAMPLER_2D &&
1451 location->Info().type != SH_SAMPLER_CUBE)
1453 return true;
1456 if (value >= 0 && value < mGLMaxTextureUnits)
1457 return true;
1459 ErrorInvalidValue("%s: this uniform location is a sampler, but %d is not a valid texture unit",
1460 info, value);
1461 return false;
1464 bool
1465 WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
1467 if (IsContextLost()) {
1468 return false;
1470 if (arrayLength < cnt) {
1471 ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
1472 return false;
1474 return true;
1477 bool
1478 WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
1479 GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
1481 if (IsContextLost())
1482 return false;
1483 if (!ValidateUniformLocation(name, location_object))
1484 return false;
1485 location = location_object->Location();
1486 uint32_t uniformElemSize = location_object->ElementSize();
1487 if (expectedElemSize != uniformElemSize) {
1488 ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
1489 " got a uniform of element size %d", name,
1490 expectedElemSize,
1491 uniformElemSize);
1492 return false;
1494 if (arrayLength == 0 ||
1495 arrayLength % expectedElemSize)
1497 ErrorInvalidValue("%s: expected an array of length a multiple"
1498 " of %d, got an array of length %d", name,
1499 expectedElemSize,
1500 arrayLength);
1501 return false;
1503 const WebGLUniformInfo& info = location_object->Info();
1504 if (!info.isArray &&
1505 arrayLength != expectedElemSize) {
1506 ErrorInvalidOperation("%s: expected an array of length exactly"
1507 " %d (since this uniform is not an array"
1508 " uniform), got an array of length %d", name,
1509 expectedElemSize,
1510 arrayLength);
1511 return false;
1513 numElementsToUpload =
1514 std::min(info.arraySize, arrayLength / expectedElemSize);
1515 return true;
1518 bool
1519 WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
1520 GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
1521 WebGLboolean aTranspose)
1523 uint32_t expectedElemSize = (dim)*(dim);
1524 if (IsContextLost())
1525 return false;
1526 if (!ValidateUniformLocation(name, location_object))
1527 return false;
1528 location = location_object->Location();
1529 uint32_t uniformElemSize = location_object->ElementSize();
1530 if (expectedElemSize != uniformElemSize) {
1531 ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
1532 " got a uniform of element size %d", name,
1533 expectedElemSize,
1534 uniformElemSize);
1535 return false;
1537 if (arrayLength == 0 ||
1538 arrayLength % expectedElemSize)
1540 ErrorInvalidValue("%s: expected an array of length a multiple"
1541 " of %d, got an array of length %d", name,
1542 expectedElemSize,
1543 arrayLength);
1544 return false;
1546 const WebGLUniformInfo& info = location_object->Info();
1547 if (!info.isArray &&
1548 arrayLength != expectedElemSize) {
1549 ErrorInvalidOperation("%s: expected an array of length exactly"
1550 " %d (since this uniform is not an array"
1551 " uniform), got an array of length %d", name,
1552 expectedElemSize,
1553 arrayLength);
1554 return false;
1556 if (aTranspose) {
1557 ErrorInvalidValue("%s: transpose must be FALSE as per the "
1558 "OpenGL ES 2.0 spec", name);
1559 return false;
1561 numElementsToUpload =
1562 std::min(info.arraySize, arrayLength / (expectedElemSize));
1563 return true;
1566 bool
1567 WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
1569 if (IsContextLost())
1570 return false;
1571 if (!ValidateUniformLocation(name, location_object))
1572 return false;
1573 location = location_object->Location();
1574 return true;
1577 bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
1579 return mBoundVertexArray->EnsureAttrib(index, info);
1582 bool WebGLContext::ValidateStencilParamsForDrawCall()
1584 const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
1585 if (mStencilRefFront != mStencilRefBack) {
1586 ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
1587 return false;
1589 if (mStencilValueMaskFront != mStencilValueMaskBack) {
1590 ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
1591 return false;
1593 if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
1594 ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
1595 return false;
1597 return true;
1600 static inline int32_t floorPOT(int32_t x)
1602 MOZ_ASSERT(x > 0);
1603 int32_t pot = 1;
1604 while (pot < 0x40000000) {
1605 if (x < pot*2)
1606 break;
1607 pot *= 2;
1609 return pot;
1612 bool
1613 WebGLContext::InitAndValidateGL()
1615 if (!gl) return false;
1617 GLenum error = gl->fGetError();
1618 if (error != LOCAL_GL_NO_ERROR) {
1619 GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error);
1620 return false;
1623 mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
1624 mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
1625 mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false);
1626 mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
1627 mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true);
1629 if (MinCapabilityMode()) {
1630 mDisableFragHighP = true;
1633 // These are the default values, see 6.2 State tables in the
1634 // OpenGL ES 2.0.25 spec.
1635 mColorWriteMask[0] = 1;
1636 mColorWriteMask[1] = 1;
1637 mColorWriteMask[2] = 1;
1638 mColorWriteMask[3] = 1;
1639 mDepthWriteMask = 1;
1640 mColorClearValue[0] = 0.f;
1641 mColorClearValue[1] = 0.f;
1642 mColorClearValue[2] = 0.f;
1643 mColorClearValue[3] = 0.f;
1644 mDepthClearValue = 1.f;
1645 mStencilClearValue = 0;
1646 mStencilRefFront = 0;
1647 mStencilRefBack = 0;
1650 // Technically, we should be setting mStencil[...] values to
1651 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
1652 GLuint stencilBits = 0;
1653 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
1654 GLuint allOnes = ~(UINT32_MAX << stencilBits);
1655 mStencilValueMaskFront = allOnes;
1656 mStencilValueMaskBack = allOnes;
1657 mStencilWriteMaskFront = allOnes;
1658 mStencilWriteMaskBack = allOnes;
1661 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
1662 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
1663 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
1664 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
1666 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
1667 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
1668 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront);
1669 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
1671 mDitherEnabled = true;
1672 mRasterizerDiscardEnabled = false;
1673 mScissorTestEnabled = false;
1675 // Bindings, etc.
1676 mActiveTexture = 0;
1677 mEmitContextLostErrorOnce = true;
1678 mWebGLError = LOCAL_GL_NO_ERROR;
1679 mUnderlyingGLError = LOCAL_GL_NO_ERROR;
1681 mBound2DTextures.Clear();
1682 mBoundCubeMapTextures.Clear();
1684 mBoundArrayBuffer = nullptr;
1685 mBoundTransformFeedbackBuffer = nullptr;
1686 mCurrentProgram = nullptr;
1688 mBoundFramebuffer = nullptr;
1689 mBoundRenderbuffer = nullptr;
1691 MakeContextCurrent();
1693 // on desktop OpenGL, we always keep vertex attrib 0 array enabled
1694 if (!gl->IsGLES()) {
1695 gl->fEnableVertexAttribArray(0);
1698 if (MinCapabilityMode()) {
1699 mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
1700 } else {
1701 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
1703 if (mGLMaxVertexAttribs < 8) {
1704 GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs);
1705 return false;
1708 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
1709 // even though the hardware supports much more. The
1710 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
1711 if (MinCapabilityMode()) {
1712 mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
1713 } else {
1714 gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
1716 if (mGLMaxTextureUnits < 8) {
1717 GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
1718 return false;
1721 mBound2DTextures.SetLength(mGLMaxTextureUnits);
1722 mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
1724 if (MinCapabilityMode()) {
1725 mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
1726 mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
1727 mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
1728 mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
1729 mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
1730 } else {
1731 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
1732 gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
1733 gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
1734 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
1735 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
1738 mGLMaxTextureSize = floorPOT(mGLMaxTextureSize);
1739 mGLMaxRenderbufferSize = floorPOT(mGLMaxRenderbufferSize);
1741 if (MinCapabilityMode()) {
1742 mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
1743 mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
1744 mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
1745 } else {
1746 if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
1747 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
1748 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
1749 gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
1750 } else {
1751 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
1752 mGLMaxFragmentUniformVectors /= 4;
1753 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
1754 mGLMaxVertexUniformVectors /= 4;
1756 // we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
1757 // however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
1758 // and check OpenGL error for INVALID_ENUM.
1760 // before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
1761 error = gl->GetAndClearError();
1762 if (error != LOCAL_GL_NO_ERROR) {
1763 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
1764 return false;
1767 // On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
1768 // mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
1769 GLint maxVertexOutputComponents,
1770 minFragmentInputComponents;
1771 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &maxVertexOutputComponents);
1772 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &minFragmentInputComponents);
1774 error = gl->GetAndClearError();
1775 switch (error) {
1776 case LOCAL_GL_NO_ERROR:
1777 mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
1778 break;
1779 case LOCAL_GL_INVALID_ENUM:
1780 mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
1781 break;
1782 default:
1783 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
1784 return false;
1789 // Always 1 for GLES2
1790 mMaxFramebufferColorAttachments = 1;
1792 if (!gl->IsGLES()) {
1793 // gl_PointSize is always available in ES2 GLSL, but has to be
1794 // specifically enabled on desktop GLSL.
1795 gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
1797 // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
1798 // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
1799 // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
1800 // Note that this used to cause crashes on old ATI drivers... hopefully not a significant
1801 // problem anymore. See bug 602183.
1802 gl->fEnable(LOCAL_GL_POINT_SPRITE);
1805 #ifdef XP_MACOSX
1806 if (gl->WorkAroundDriverBugs() &&
1807 gl->Vendor() == gl::GLVendor::ATI) {
1808 // The Mac ATI driver, in all known OSX version up to and including 10.8,
1809 // renders points sprites upside-down. Apple bug 11778921
1810 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN, LOCAL_GL_LOWER_LEFT);
1812 #endif
1814 // Check the shader validator pref
1815 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
1817 mShaderValidation =
1818 Preferences::GetBool("webgl.shader_validator", mShaderValidation);
1820 // initialize shader translator
1821 if (mShaderValidation) {
1822 if (!ShInitialize()) {
1823 GenerateWarning("GLSL translator initialization failed!");
1824 return false;
1828 // Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
1829 mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
1831 // notice that the point of calling GetAndClearError here is not only to check for error,
1832 // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
1833 error = gl->GetAndClearError();
1834 if (error != LOCAL_GL_NO_ERROR) {
1835 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
1836 return false;
1839 if (IsWebGL2() &&
1840 !InitWebGL2())
1842 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
1843 return false;
1846 // Default value for all disabled vertex attributes is [0, 0, 0, 1]
1847 for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
1848 VertexAttrib4f(index, 0, 0, 0, 1);
1851 mDefaultVertexArray = WebGLVertexArray::Create(this);
1852 mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
1853 mBoundVertexArray = mDefaultVertexArray;
1855 if (mLoseContextOnMemoryPressure) {
1856 mContextObserver->RegisterMemoryPressureEvent();
1859 return true;