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