Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / dom / canvas / WebGLContextValidate.cpp
blobadc090fa38384682a3cf644f32042b55584228b7
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"
8 #include <algorithm>
9 #include "angle/ShaderLang.h"
10 #include "CanvasUtils.h"
11 #include "GLContext.h"
12 #include "jsfriendapi.h"
13 #include "mozilla/CheckedInt.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/Services.h"
16 #include "nsIObserverService.h"
17 #include "WebGLBuffer.h"
18 #include "WebGLContextUtils.h"
19 #include "WebGLFramebuffer.h"
20 #include "WebGLProgram.h"
21 #include "WebGLRenderbuffer.h"
22 #include "WebGLShader.h"
23 #include "WebGLTexture.h"
24 #include "WebGLUniformLocation.h"
25 #include "WebGLVertexArray.h"
26 #include "WebGLVertexAttribData.h"
28 #if defined(MOZ_WIDGET_COCOA)
29 #include "nsCocoaFeatures.h"
30 #endif
32 namespace mozilla {
34 /**
35 * Return the block size for format.
37 static void
38 BlockSizeFor(GLenum format, GLint* const out_blockWidth,
39 GLint* const out_blockHeight)
41 MOZ_ASSERT(out_blockWidth && out_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 *out_blockWidth = 4;
52 *out_blockHeight = 4;
53 break;
55 case LOCAL_GL_ETC1_RGB8_OES:
56 // 4x4 blocks, but no 4-multiple requirement.
57 break;
59 default:
60 break;
64 static bool
65 IsCompressedFunc(WebGLTexImageFunc func)
67 return func == WebGLTexImageFunc::CompTexImage ||
68 func == WebGLTexImageFunc::CompTexSubImage;
71 /**
72 * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
73 * name for \a glenum.
75 static void
76 ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum,
77 WebGLTexImageFunc func, WebGLTexDimensions dims)
79 const char* name = WebGLContext::EnumName(glenum);
80 if (name) {
81 ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func, dims), msg, name);
82 } else {
83 ctx->ErrorInvalidEnum("%s: %s 0x%04x", InfoFrom(func, dims), msg,
84 glenum);
88 /**
89 * Return true if the format is valid for source calls.
91 static bool
92 IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
94 switch (format) {
95 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
96 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
97 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
98 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
99 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
100 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
101 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
102 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
103 return (func == WebGLTexImageFunc::CompTexImage ||
104 func == WebGLTexImageFunc::CompTexSubImage);
106 case LOCAL_GL_ATC_RGB:
107 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
108 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
109 case LOCAL_GL_ETC1_RGB8_OES:
110 return func == WebGLTexImageFunc::CompTexImage;
113 return true;
117 * Returns true if func is a CopyTexImage variant.
119 static bool
120 IsCopyFunc(WebGLTexImageFunc func)
122 return (func == WebGLTexImageFunc::CopyTexImage ||
123 func == WebGLTexImageFunc::CopyTexSubImage);
127 * Returns true if func is a SubImage variant.
129 static bool
130 IsSubFunc(WebGLTexImageFunc func)
132 return (func == WebGLTexImageFunc::TexSubImage ||
133 func == WebGLTexImageFunc::CopyTexSubImage ||
134 func == WebGLTexImageFunc::CompTexSubImage);
138 * returns true is target is a texture cube map target.
140 static bool
141 IsTexImageCubemapTarget(GLenum texImageTarget)
143 return (texImageTarget >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
144 texImageTarget <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
147 bool
148 WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info)
150 switch (mode) {
151 case LOCAL_GL_FUNC_ADD:
152 case LOCAL_GL_FUNC_SUBTRACT:
153 case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
154 return true;
156 case LOCAL_GL_MIN:
157 case LOCAL_GL_MAX:
158 if (IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax))
159 return true;
161 break;
163 default:
164 break;
167 ErrorInvalidEnumInfo(info, mode);
168 return false;
171 bool
172 WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char* info)
174 switch (factor) {
175 case LOCAL_GL_ZERO:
176 case LOCAL_GL_ONE:
177 case LOCAL_GL_SRC_COLOR:
178 case LOCAL_GL_ONE_MINUS_SRC_COLOR:
179 case LOCAL_GL_DST_COLOR:
180 case LOCAL_GL_ONE_MINUS_DST_COLOR:
181 case LOCAL_GL_SRC_ALPHA:
182 case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
183 case LOCAL_GL_DST_ALPHA:
184 case LOCAL_GL_ONE_MINUS_DST_ALPHA:
185 case LOCAL_GL_CONSTANT_COLOR:
186 case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
187 case LOCAL_GL_CONSTANT_ALPHA:
188 case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
189 return true;
191 default:
192 ErrorInvalidEnumInfo(info, factor);
193 return false;
197 bool
198 WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char* info)
200 if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
201 return true;
203 return ValidateBlendFuncDstEnum(factor, info);
206 bool
207 WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
208 GLenum dfactor,
209 const char* info)
211 bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
212 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
213 bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
214 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
215 bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
216 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
217 bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
218 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
219 if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
220 (dfactorIsConstantColor && sfactorIsConstantAlpha) )
222 ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in"
223 " the WebGL 1.0 spec", info);
224 return false;
227 return true;
230 bool
231 WebGLContext::ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info)
233 if (offset < 0) {
234 ErrorInvalidValue("%s: offset must be positive", info);
235 return false;
238 if (size < 0) {
239 ErrorInvalidValue("%s: size must be positive", info);
240 return false;
243 // *** Careful *** WebGLsizeiptr is always 64-bits but GLsizeiptr
244 // is like intptr_t. On some platforms it is 32-bits.
245 CheckedInt<GLsizeiptr> neededBytes = CheckedInt<GLsizeiptr>(offset) + size;
246 if (!neededBytes.isValid() || neededBytes.value() > bufferSize) {
247 ErrorInvalidValue("%s: invalid range", info);
248 return false;
251 return true;
255 * Check data ranges [readOffset, readOffset + size] and [writeOffset,
256 * writeOffset + size] for overlap.
258 * It is assumed that offset and size have already been validated with
259 * ValidateDataOffsetSize().
261 bool
262 WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info)
264 MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
265 MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
267 bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset);
268 if (!separate)
269 ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, writeOffset + size) overlap");
271 return separate;
274 bool
275 WebGLContext::ValidateTextureTargetEnum(GLenum target, const char* info)
277 switch (target) {
278 case LOCAL_GL_TEXTURE_2D:
279 case LOCAL_GL_TEXTURE_CUBE_MAP:
280 return true;
282 case LOCAL_GL_TEXTURE_3D:
283 if (IsWebGL2())
284 return true;
286 break;
288 default:
289 break;
292 ErrorInvalidEnumInfo(info, target);
293 return false;
296 bool
297 WebGLContext::ValidateComparisonEnum(GLenum target, const char* info)
299 switch (target) {
300 case LOCAL_GL_NEVER:
301 case LOCAL_GL_LESS:
302 case LOCAL_GL_LEQUAL:
303 case LOCAL_GL_GREATER:
304 case LOCAL_GL_GEQUAL:
305 case LOCAL_GL_EQUAL:
306 case LOCAL_GL_NOTEQUAL:
307 case LOCAL_GL_ALWAYS:
308 return true;
310 default:
311 ErrorInvalidEnumInfo(info, target);
312 return false;
316 bool
317 WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info)
319 switch (action) {
320 case LOCAL_GL_KEEP:
321 case LOCAL_GL_ZERO:
322 case LOCAL_GL_REPLACE:
323 case LOCAL_GL_INCR:
324 case LOCAL_GL_INCR_WRAP:
325 case LOCAL_GL_DECR:
326 case LOCAL_GL_DECR_WRAP:
327 case LOCAL_GL_INVERT:
328 return true;
330 default:
331 ErrorInvalidEnumInfo(info, action);
332 return false;
336 bool
337 WebGLContext::ValidateFaceEnum(GLenum face, const char* info)
339 switch (face) {
340 case LOCAL_GL_FRONT:
341 case LOCAL_GL_BACK:
342 case LOCAL_GL_FRONT_AND_BACK:
343 return true;
345 default:
346 ErrorInvalidEnumInfo(info, face);
347 return false;
351 bool
352 WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
354 switch (mode) {
355 case LOCAL_GL_TRIANGLES:
356 case LOCAL_GL_TRIANGLE_STRIP:
357 case LOCAL_GL_TRIANGLE_FAN:
358 case LOCAL_GL_POINTS:
359 case LOCAL_GL_LINE_STRIP:
360 case LOCAL_GL_LINE_LOOP:
361 case LOCAL_GL_LINES:
362 return true;
364 default:
365 ErrorInvalidEnumInfo(info, mode);
366 return false;
370 bool
371 WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char* info)
373 if (name.IsEmpty())
374 return false;
376 const uint32_t maxSize = 256;
377 if (name.Length() > maxSize) {
378 ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
379 " maximum allowed length of %d characters.", info,
380 name.Length(), maxSize);
381 return false;
384 if (!ValidateGLSLString(name, info))
385 return false;
387 nsString prefix1 = NS_LITERAL_STRING("webgl_");
388 nsString prefix2 = NS_LITERAL_STRING("_webgl_");
390 if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
391 Substring(name, 0, prefix2.Length()).Equals(prefix2))
393 ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
394 info);
395 return false;
398 return true;
401 bool WebGLContext::ValidateGLSLString(const nsAString& string, const char* info)
403 for (uint32_t i = 0; i < string.Length(); ++i) {
404 if (!ValidateGLSLCharacter(string.CharAt(i))) {
405 ErrorInvalidValue("%s: String contains the illegal character"
406 " '%d'.", info, string.CharAt(i));
407 return false;
411 return true;
415 * Return true if the framebuffer attachment is valid. Attachment must
416 * be one of depth/stencil/depth_stencil/color attachment.
418 bool
419 WebGLContext::ValidateFramebufferAttachment(GLenum attachment,
420 const char* funcName)
422 if (!mBoundFramebuffer) {
423 switch (attachment) {
424 case LOCAL_GL_COLOR:
425 case LOCAL_GL_DEPTH:
426 case LOCAL_GL_STENCIL:
427 return true;
429 default:
430 ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.",
431 funcName, attachment);
432 return false;
436 if (attachment == LOCAL_GL_DEPTH_ATTACHMENT ||
437 attachment == LOCAL_GL_STENCIL_ATTACHMENT ||
438 attachment == LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
440 return true;
443 GLenum colorAttachCount = 1;
444 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
445 colorAttachCount = mGLMaxColorAttachments;
447 if (attachment >= LOCAL_GL_COLOR_ATTACHMENT0 &&
448 attachment < GLenum(LOCAL_GL_COLOR_ATTACHMENT0 + colorAttachCount))
450 return true;
453 ErrorInvalidEnum("%s: attachment: invalid enum value 0x%x.", funcName,
454 attachment);
455 return false;
459 * Return true if pname is valid for GetSamplerParameter calls.
461 bool
462 WebGLContext::ValidateSamplerParameterName(GLenum pname, const char* info)
464 switch (pname) {
465 case LOCAL_GL_TEXTURE_MIN_FILTER:
466 case LOCAL_GL_TEXTURE_MAG_FILTER:
467 case LOCAL_GL_TEXTURE_WRAP_S:
468 case LOCAL_GL_TEXTURE_WRAP_T:
469 case LOCAL_GL_TEXTURE_WRAP_R:
470 case LOCAL_GL_TEXTURE_MIN_LOD:
471 case LOCAL_GL_TEXTURE_MAX_LOD:
472 case LOCAL_GL_TEXTURE_COMPARE_MODE:
473 case LOCAL_GL_TEXTURE_COMPARE_FUNC:
474 return true;
476 default:
477 ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
478 return false;
483 * Return true if pname and param are valid combination for SamplerParameter calls.
485 bool
486 WebGLContext::ValidateSamplerParameterParams(GLenum pname, const WebGLIntOrFloat& param, const char* info)
488 const GLenum p = param.AsInt();
490 switch (pname) {
491 case LOCAL_GL_TEXTURE_MIN_FILTER:
492 switch (p) {
493 case LOCAL_GL_NEAREST:
494 case LOCAL_GL_LINEAR:
495 case LOCAL_GL_NEAREST_MIPMAP_NEAREST:
496 case LOCAL_GL_NEAREST_MIPMAP_LINEAR:
497 case LOCAL_GL_LINEAR_MIPMAP_NEAREST:
498 case LOCAL_GL_LINEAR_MIPMAP_LINEAR:
499 return true;
501 default:
502 ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
503 return false;
506 case LOCAL_GL_TEXTURE_MAG_FILTER:
507 switch (p) {
508 case LOCAL_GL_NEAREST:
509 case LOCAL_GL_LINEAR:
510 return true;
512 default:
513 ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
514 return false;
517 case LOCAL_GL_TEXTURE_WRAP_S:
518 case LOCAL_GL_TEXTURE_WRAP_T:
519 case LOCAL_GL_TEXTURE_WRAP_R:
520 switch (p) {
521 case LOCAL_GL_CLAMP_TO_EDGE:
522 case LOCAL_GL_REPEAT:
523 case LOCAL_GL_MIRRORED_REPEAT:
524 return true;
526 default:
527 ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
528 return false;
531 case LOCAL_GL_TEXTURE_MIN_LOD:
532 case LOCAL_GL_TEXTURE_MAX_LOD:
533 return true;
535 case LOCAL_GL_TEXTURE_COMPARE_MODE:
536 switch (param.AsInt()) {
537 case LOCAL_GL_NONE:
538 case LOCAL_GL_COMPARE_REF_TO_TEXTURE:
539 return true;
541 default:
542 ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
543 return false;
546 case LOCAL_GL_TEXTURE_COMPARE_FUNC:
547 switch (p) {
548 case LOCAL_GL_LEQUAL:
549 case LOCAL_GL_GEQUAL:
550 case LOCAL_GL_LESS:
551 case LOCAL_GL_GREATER:
552 case LOCAL_GL_EQUAL:
553 case LOCAL_GL_NOTEQUAL:
554 case LOCAL_GL_ALWAYS:
555 case LOCAL_GL_NEVER:
556 return true;
558 default:
559 ErrorInvalidEnum("%s: invalid param: %s", info, EnumName(p));
560 return false;
563 default:
564 ErrorInvalidEnum("%s: invalid pname: %s", info, EnumName(pname));
565 return false;
571 * Return true if format is a valid texture image format for source,
572 * taking into account enabled WebGL extensions.
574 bool
575 WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func,
576 WebGLTexDimensions dims)
578 /* Core WebGL texture formats */
579 if (format == LOCAL_GL_ALPHA ||
580 format == LOCAL_GL_RGB ||
581 format == LOCAL_GL_RGBA ||
582 format == LOCAL_GL_LUMINANCE ||
583 format == LOCAL_GL_LUMINANCE_ALPHA)
585 return true;
588 /* WebGL2 new formats */
589 if (format == LOCAL_GL_RED ||
590 format == LOCAL_GL_RG ||
591 format == LOCAL_GL_RED_INTEGER ||
592 format == LOCAL_GL_RG_INTEGER ||
593 format == LOCAL_GL_RGB_INTEGER ||
594 format == LOCAL_GL_RGBA_INTEGER)
596 if (IsWebGL2())
597 return true;
599 ErrorInvalidEnum("%s: Invalid format %s: Requires WebGL version 2.0 or"
600 " newer.", InfoFrom(func, dims), EnumName(format));
601 return false;
604 /* WEBGL_depth_texture added formats */
605 if (format == LOCAL_GL_DEPTH_COMPONENT ||
606 format == LOCAL_GL_DEPTH_STENCIL)
608 if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
609 ErrorInvalidEnum("%s: Invalid format %s: Requires that"
610 " WEBGL_depth_texture is enabled.",
611 InfoFrom(func, dims), EnumName(format));
612 return false;
615 // If WEBGL_depth_texture is enabled, then it is not allowed to be used
616 // with the copyTexImage, or copyTexSubImage methods, and it is not
617 // allowed with texSubImage in WebGL1.
618 if ((func == WebGLTexImageFunc::TexSubImage && !IsWebGL2()) ||
619 func == WebGLTexImageFunc::CopyTexImage ||
620 func == WebGLTexImageFunc::CopyTexSubImage)
622 ErrorInvalidOperation("%s: format %s is not supported",
623 InfoFrom(func, dims), EnumName(format));
624 return false;
627 return true;
630 // Needs to be below the depth_texture check because an invalid operation
631 // error needs to be generated instead of invalid enum.
632 // Only core formats are valid for CopyTex[Sub]Image.
633 // TODO: Revisit this once color_buffer_[half_]float lands.
634 if (IsCopyFunc(func)) {
635 ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
636 return false;
639 // EXT_sRGB added formats
640 if (format == LOCAL_GL_SRGB ||
641 format == LOCAL_GL_SRGB_ALPHA)
643 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
644 return true;
646 ErrorInvalidEnum("%s: Invalid format %s: Requires that EXT_sRGB is"
647 " enabled.", InfoFrom(func, dims),
648 WebGLContext::EnumName(format));
649 return false;
652 ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
653 return false;
657 * Check if the given texture target is valid for TexImage.
659 bool
660 WebGLContext::ValidateTexImageTarget(GLenum target, WebGLTexImageFunc func,
661 WebGLTexDimensions dims)
663 switch (dims) {
664 case WebGLTexDimensions::Tex2D:
665 if (target == LOCAL_GL_TEXTURE_2D ||
666 IsTexImageCubemapTarget(target))
668 return true;
671 ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
672 return false;
674 case WebGLTexDimensions::Tex3D:
675 if (target == LOCAL_GL_TEXTURE_3D)
677 return true;
680 ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
681 return false;
683 default:
684 MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
687 return false;
691 * Return true if type is a valid texture image type for source,
692 * taking into account enabled WebGL extensions.
694 bool
695 WebGLContext::ValidateTexImageType(GLenum type, WebGLTexImageFunc func,
696 WebGLTexDimensions dims)
698 /* Core WebGL texture types */
699 if (type == LOCAL_GL_UNSIGNED_BYTE ||
700 type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
701 type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
702 type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
704 return true;
707 /* WebGL2 new types */
708 if (type == LOCAL_GL_BYTE ||
709 type == LOCAL_GL_SHORT ||
710 type == LOCAL_GL_INT ||
711 type == LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV ||
712 type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV ||
713 type == LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV ||
714 type == LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV)
716 if (IsWebGL2())
717 return true;
719 ErrorInvalidEnum("%s: Invalid type %s: Requires WebGL version 2.0 or"
720 " newer.", InfoFrom(func, dims),
721 WebGLContext::EnumName(type));
722 return false;
725 /* OES_texture_float added types */
726 if (type == LOCAL_GL_FLOAT) {
727 if (IsExtensionEnabled(WebGLExtensionID::OES_texture_float))
728 return true;
730 ErrorInvalidEnum("%s: Invalid type %s: Requires that OES_texture_float"
731 " is enabled.",
732 InfoFrom(func, dims), WebGLContext::EnumName(type));
733 return false;
736 /* OES_texture_half_float add types */
737 if (type == LOCAL_GL_HALF_FLOAT) {
738 if (IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float))
739 return true;
741 ErrorInvalidEnum("%s: Invalid type %s: Requires that"
742 " OES_texture_half_float is enabled.",
743 InfoFrom(func, dims), WebGLContext::EnumName(type));
744 return false;
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)
752 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture))
753 return true;
755 ErrorInvalidEnum("%s: Invalid type %s: Requires that"
756 " WEBGL_depth_texture is enabled.",
757 InfoFrom(func, dims), WebGLContext::EnumName(type));
758 return false;
761 ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
762 return false;
766 * Validate texture image sizing extra constraints for
767 * CompressedTex(Sub)?Image.
769 // TODO: WebGL 2
770 bool
771 WebGLContext::ValidateCompTexImageSize(GLint level, GLenum format,
772 GLint xoffset, GLint yoffset,
773 GLsizei width, GLsizei height,
774 GLsizei levelWidth, GLsizei levelHeight,
775 WebGLTexImageFunc func,
776 WebGLTexDimensions dims)
778 // Negative parameters must already have been handled above
779 MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
780 width >= 0 && height >= 0);
782 if (xoffset + width > (GLint) levelWidth) {
783 ErrorInvalidValue("%s: xoffset + width must be <= levelWidth.",
784 InfoFrom(func, dims));
785 return false;
788 if (yoffset + height > (GLint) levelHeight) {
789 ErrorInvalidValue("%s: yoffset + height must be <= levelHeight.",
790 InfoFrom(func, dims));
791 return false;
794 GLint blockWidth = 1;
795 GLint blockHeight = 1;
796 BlockSizeFor(format, &blockWidth, &blockHeight);
798 // If blockWidth || blockHeight != 1, then the compressed format had
799 // block-based constraints to be checked. (For example, PVRTC is compressed
800 // but isn't a block-based format)
801 if (blockWidth != 1 || blockHeight != 1) {
802 // Offsets must be multiple of block size.
803 if (xoffset % blockWidth != 0) {
804 ErrorInvalidOperation("%s: xoffset must be multiple of %d.",
805 InfoFrom(func, dims), blockWidth);
806 return false;
809 if (yoffset % blockHeight != 0) {
810 ErrorInvalidOperation("%s: yoffset must be multiple of %d.",
811 InfoFrom(func, dims), blockHeight);
812 return false;
815 /* The size must be a multiple of blockWidth and blockHeight, or must be
816 * using offset+size that exactly hits the edge. Important for small
817 * mipmap levels.
819 * From the WEBGL_compressed_texture_s3tc spec:
820 * When level equals zero width and height must be a multiple of 4.
821 * When level is greater than 0 width and height must be 0, 1, 2 or
822 * a multiple of 4. If they are not an INVALID_OPERATION error is
823 * generated."
825 if (level == 0) {
826 if (width % blockWidth != 0) {
827 ErrorInvalidOperation("%s: Width of level 0 must be a multiple"
828 " of %d.", InfoFrom(func, dims),
829 blockWidth);
830 return false;
833 if (height % blockHeight != 0) {
834 ErrorInvalidOperation("%s: Height of level 0 must be a multiple"
835 " of %d.", InfoFrom(func, dims),
836 blockHeight);
837 return false;
839 } else if (level > 0) {
840 if (width % blockWidth != 0 && width > 2) {
841 ErrorInvalidOperation("%s: Width of level %d must be a multiple"
842 " of %d, or be 0, 1, or 2.",
843 InfoFrom(func, dims), level, blockWidth);
844 return false;
847 if (height % blockHeight != 0 && height > 2) {
848 ErrorInvalidOperation("%s: Height of level %d must be a"
849 " multiple of %d, or be 0, 1, or 2.",
850 InfoFrom(func, dims), level, blockHeight);
851 return false;
855 if (IsSubFunc(func)) {
856 if ((xoffset % blockWidth) != 0) {
857 ErrorInvalidOperation("%s: xoffset must be a multiple of %d.",
858 InfoFrom(func, dims), blockWidth);
859 return false;
862 if (yoffset % blockHeight != 0) {
863 ErrorInvalidOperation("%s: yoffset must be a multiple of %d.",
864 InfoFrom(func, dims), blockHeight);
865 return false;
870 switch (format) {
871 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
872 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
873 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
874 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
875 if (!IsPOTAssumingNonnegative(width) ||
876 !IsPOTAssumingNonnegative(height))
878 ErrorInvalidValue("%s: Width and height must be powers of two.",
879 InfoFrom(func, dims));
880 return false;
884 return true;
888 * Return true if the enough data is present to satisfy compressed
889 * texture format constraints.
891 bool
892 WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
893 GLsizei width, GLsizei height,
894 uint32_t byteLength,
895 WebGLTexImageFunc func,
896 WebGLTexDimensions dims)
898 // negative width and height must already have been handled above
899 MOZ_ASSERT(width >= 0 && height >= 0);
901 CheckedUint32 required_byteLength = 0;
903 switch (format) {
904 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
905 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
906 case LOCAL_GL_ATC_RGB:
907 case LOCAL_GL_ETC1_RGB8_OES:
908 required_byteLength = ((CheckedUint32(width) + 3) / 4) *
909 ((CheckedUint32(height) + 3) / 4) * 8;
910 break;
912 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
913 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
914 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
915 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
916 required_byteLength = ((CheckedUint32(width) + 3) / 4) *
917 ((CheckedUint32(height) + 3) / 4) * 16;
918 break;
920 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
921 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
922 required_byteLength = CheckedUint32(std::max(width, 8)) *
923 CheckedUint32(std::max(height, 8)) / 2;
924 break;
926 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
927 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
928 required_byteLength = CheckedUint32(std::max(width, 16)) *
929 CheckedUint32(std::max(height, 8)) / 4;
930 break;
933 if (!required_byteLength.isValid() ||
934 required_byteLength.value() != byteLength)
936 ErrorInvalidValue("%s: Data size does not match dimensions.",
937 InfoFrom(func, dims));
938 return false;
941 return true;
945 * Validate the width, height, and depth of a texture image, \return
946 * true is valid, false otherwise.
947 * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
948 * Target and level must have been validated before calling.
950 bool
951 WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
952 GLint width, GLint height, GLint depth,
953 WebGLTexImageFunc func,
954 WebGLTexDimensions dims)
956 MOZ_ASSERT(level >= 0, "level should already be validated");
958 /* Bug 966630: maxTextureSize >> level runs into "undefined"
959 * behaviour depending on ISA. For example, on Intel shifts
960 * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
961 * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
962 * what would be expected. Make the required behaviour explicit by
963 * clamping to a shift of 31 bits if level is greater than that
964 * ammount. This will give 0 that if (!maxAllowedSize) is
965 * expecting.
968 if (level > 31)
969 level = 31;
971 auto texTarget = TexImageTargetToTexTarget(texImageTarget);
972 const GLuint maxTexImageSize = MaxTextureSizeForTarget(texTarget) >> level;
974 const bool isCubemapTarget = IsTexImageCubemapTarget(texImageTarget.get());
975 const bool isSub = IsSubFunc(func);
977 if (!isSub && isCubemapTarget && (width != height)) {
978 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
979 * "When the target parameter to TexImage2D is one of the
980 * six cube map two-dimensional image targets, the error
981 * INVALID_VALUE is generated if the width and height
982 * parameters are not equal."
984 ErrorInvalidValue("%s: For cube maps, width must equal height.",
985 InfoFrom(func, dims));
986 return false;
989 if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget) {
990 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
991 * "If wt and ht are the specified image width and height,
992 * and if either wt or ht are less than zero, then the error
993 * INVALID_VALUE is generated."
995 if (width < 0) {
996 ErrorInvalidValue("%s: Width must be >= 0.", InfoFrom(func, dims));
997 return false;
1000 if (height < 0) {
1001 ErrorInvalidValue("%s: Height must be >= 0.", InfoFrom(func, dims));
1002 return false;
1005 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
1006 * "The maximum allowable width and height of a
1007 * two-dimensional texture image must be at least 2**(k−lod)
1008 * for image arrays of level zero through k, where k is the
1009 * log base 2 of MAX_TEXTURE_SIZE. and lod is the
1010 * level-of-detail of the image array. It may be zero for
1011 * image arrays of any level-of-detail greater than k. The
1012 * error INVALID_VALUE is generated if the specified image
1013 * is too large to be stored under any conditions.
1015 if (width > (int) maxTexImageSize) {
1016 ErrorInvalidValue("%s: The maximum width for level %d is %u.",
1017 InfoFrom(func, dims), level, maxTexImageSize);
1018 return false;
1021 if (height > (int) maxTexImageSize) {
1022 ErrorInvalidValue("%s: The maximum height for level %d is %u.",
1023 InfoFrom(func, dims), level, maxTexImageSize);
1024 return false;
1027 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
1028 * "If level is greater than zero, and either width or
1029 * height is not a power-of-two, the error INVALID_VALUE is
1030 * generated."
1032 * This restriction does not apply to GL ES Version 3.0+.
1034 if (!IsWebGL2() && level > 0) {
1035 if (!IsPOTAssumingNonnegative(width)) {
1036 ErrorInvalidValue("%s: For level > 0, width of %d must be a"
1037 " power of two.", InfoFrom(func, dims),
1038 width);
1039 return false;
1042 if (!IsPOTAssumingNonnegative(height)) {
1043 ErrorInvalidValue("%s: For level > 0, height of %d must be a"
1044 " power of two.", InfoFrom(func, dims),
1045 height);
1046 return false;
1051 // TODO: WebGL 2
1052 if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
1053 if (depth < 0) {
1054 ErrorInvalidValue("%s: Depth must be >= 0.", InfoFrom(func, dims));
1055 return false;
1058 if (!IsWebGL2() && !IsPOTAssumingNonnegative(depth)) {
1059 ErrorInvalidValue("%s: Depth of %d must be a power of two.",
1060 InfoFrom(func, dims), depth);
1061 return false;
1065 return true;
1069 * Validate texture image sizing for Tex(Sub)?Image variants.
1071 // TODO: WebGL 2. Update this to handle 3D textures.
1072 bool
1073 WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset,
1074 GLint /*zoffset*/, GLsizei width,
1075 GLsizei height, GLsizei /*depth*/,
1076 GLsizei baseWidth, GLsizei baseHeight,
1077 GLsizei /*baseDepth*/,
1078 WebGLTexImageFunc func,
1079 WebGLTexDimensions dims)
1081 /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
1082 * "Taking wt and ht to be the specified width and height of the
1083 * texture array, and taking x, y, w, and h to be the xoffset,
1084 * yoffset, width, and height argument values, any of the
1085 * following relationships generates the error INVALID_VALUE:
1086 * x < 0
1087 * x + w > wt
1088 * y < 0
1089 * y + h > ht"
1092 if (xoffset < 0) {
1093 ErrorInvalidValue("%s: xoffset must be >= 0.", InfoFrom(func, dims));
1094 return false;
1097 if (yoffset < 0) {
1098 ErrorInvalidValue("%s: yoffset must be >= 0.", InfoFrom(func, dims));
1099 return false;
1102 if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height,
1103 baseWidth, baseHeight))
1105 ErrorInvalidValue("%s: Subtexture rectangle out-of-bounds.",
1106 InfoFrom(func, dims));
1107 return false;
1110 return true;
1114 * Perform validation of format/type combinations for TexImage variants.
1115 * Returns true if the format/type is a valid combination, false otherwise.
1117 bool
1118 WebGLContext::ValidateTexImageFormatAndType(GLenum format, GLenum type,
1119 WebGLTexImageFunc func,
1120 WebGLTexDimensions dims)
1122 if (IsCompressedFunc(func) || IsCopyFunc(func)) {
1123 MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
1124 return true;
1127 if (!ValidateTexImageFormat(format, func, dims) ||
1128 !ValidateTexImageType(type, func, dims))
1130 return false;
1133 // Here we're reinterpreting format as an unsized internalformat;
1134 // these are the same in practice and there's no point in having the
1135 // same code implemented twice.
1136 TexInternalFormat effective =
1137 EffectiveInternalFormatFromInternalFormatAndType(format, type);
1139 if (effective != LOCAL_GL_NONE)
1140 return true;
1142 ErrorInvalidOperation("%s: Invalid combination of format %s and type %s.",
1143 InfoFrom(func, dims), WebGLContext::EnumName(format),
1144 WebGLContext::EnumName(type));
1145 return false;
1148 bool
1149 WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
1150 WebGLTexImageFunc func,
1151 WebGLTexDimensions dims)
1153 if (!IsCompressedTextureFormat(format)) {
1154 ErrorInvalidEnum("%s: Invalid compressed texture format: %s",
1155 InfoFrom(func, dims), WebGLContext::EnumName(format));
1156 return false;
1159 /* WEBGL_compressed_texture_atc added formats */
1160 if (format == LOCAL_GL_ATC_RGB ||
1161 format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
1162 format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
1164 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc))
1165 return true;
1167 ErrorInvalidEnum("%s: Invalid format %s: Requires that"
1168 " WEBGL_compressed_texture_atc is enabled.",
1169 InfoFrom(func, dims), WebGLContext::EnumName(format));
1170 return false;
1173 // WEBGL_compressed_texture_etc1
1174 if (format == LOCAL_GL_ETC1_RGB8_OES) {
1175 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1))
1176 return true;
1178 ErrorInvalidEnum("%s: Invalid format %s: Requires that"
1179 " WEBGL_compressed_texture_etc1 is enabled.",
1180 InfoFrom(func, dims), WebGLContext::EnumName(format));
1181 return false;
1185 if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
1186 format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
1187 format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
1188 format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
1190 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc))
1191 return true;
1193 ErrorInvalidEnum("%s: Invalid format %s: Requires that"
1194 " WEBGL_compressed_texture_pvrtc is enabled.",
1195 InfoFrom(func, dims), WebGLContext::EnumName(format));
1196 return false;
1200 if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
1201 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
1202 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
1203 format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
1205 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc))
1206 return true;
1208 ErrorInvalidEnum("%s: Invalid format %s: Requires that"
1209 " WEBGL_compressed_texture_s3tc is enabled.",
1210 InfoFrom(func, dims), WebGLContext::EnumName(format));
1211 return false;
1214 MOZ_ASSERT(false);
1215 return false;
1218 bool
1219 WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
1220 WebGLTexImageFunc func,
1221 WebGLTexDimensions dims)
1223 switch (format) {
1224 case LOCAL_GL_RGBA:
1225 case LOCAL_GL_RGB:
1226 case LOCAL_GL_LUMINANCE_ALPHA:
1227 case LOCAL_GL_LUMINANCE:
1228 case LOCAL_GL_ALPHA:
1229 return true;
1231 // In CopyTexImage, internalFormat is a function parameter,
1232 // so a bad value is an INVALID_ENUM error.
1233 // In CopyTexSubImage, internalFormat is part of existing state,
1234 // so this is an INVALID_OPERATION error.
1235 GenerateWarning("%s: Invalid texture internal format: %s",
1236 InfoFrom(func, dims), WebGLContext::EnumName(format));
1238 GLenum error;
1239 if (func == WebGLTexImageFunc::CopyTexImage)
1240 error = LOCAL_GL_INVALID_ENUM;
1241 else
1242 error = LOCAL_GL_INVALID_OPERATION;
1244 SynthesizeGLError(error);
1245 return false;
1248 * Return true if format, type and jsArrayType are a valid combination.
1249 * Also returns the size for texel of format and type (in bytes) via
1250 * \a texelSize.
1252 * It is assumed that type has previously been validated.
1254 bool
1255 WebGLContext::ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
1256 WebGLTexImageFunc func,
1257 WebGLTexDimensions dims)
1259 // We're using js::Scalar::MaxTypedArrayViewType as dummy value for when
1260 // the tex source wasn't a typed array.
1261 if (jsArrayType == js::Scalar::MaxTypedArrayViewType)
1262 return true;
1264 const char invalidTypedArray[] = "%s: Invalid typed array type for given"
1265 " texture data type.";
1267 bool validInput = false;
1268 switch (type) {
1269 case LOCAL_GL_UNSIGNED_BYTE:
1270 validInput = jsArrayType == js::Scalar::Uint8;
1271 break;
1273 case LOCAL_GL_BYTE:
1274 validInput = jsArrayType == js::Scalar::Int8;
1275 break;
1277 case LOCAL_GL_HALF_FLOAT:
1278 case LOCAL_GL_UNSIGNED_SHORT:
1279 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
1280 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
1281 case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
1282 validInput = jsArrayType == js::Scalar::Uint16;
1283 break;
1285 case LOCAL_GL_SHORT:
1286 validInput = jsArrayType == js::Scalar::Int16;
1287 break;
1289 case LOCAL_GL_UNSIGNED_INT:
1290 case LOCAL_GL_UNSIGNED_INT_24_8:
1291 case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
1292 case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
1293 case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
1294 validInput = jsArrayType == js::Scalar::Uint32;
1295 break;
1297 case LOCAL_GL_INT:
1298 validInput = jsArrayType == js::Scalar::Int32;
1299 break;
1301 case LOCAL_GL_FLOAT:
1302 validInput = jsArrayType == js::Scalar::Float32;
1303 break;
1305 default:
1306 break;
1309 if (!validInput)
1310 ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
1312 return validInput;
1316 * Checks specific for the CopyTex[Sub]Image2D functions.
1317 * Verifies:
1318 * - Framebuffer is complete and has valid read planes
1319 * - Copy format is a subset of framebuffer format (i.e. all required components
1320 * are available)
1322 bool
1323 WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func,
1324 WebGLTexDimensions dims)
1326 MOZ_ASSERT(IsCopyFunc(func));
1328 // Default framebuffer format
1329 GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
1331 if (mBoundFramebuffer) {
1332 if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
1333 ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
1334 InfoFrom(func, dims));
1335 return false;
1338 GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
1339 if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
1340 ErrorInvalidOperation("%s: Read source attachment doesn't have the"
1341 " correct color/depth/stencil type.",
1342 InfoFrom(func, dims));
1343 return false;
1346 // Get the correct format for the framebuffer, as it's not the default
1347 // one.
1348 const WebGLFramebuffer::Attachment& color0 =
1349 mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
1351 fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
1354 // Make sure the format of the framebuffer is a superset of the format
1355 // requested by the CopyTex[Sub]Image2D functions.
1356 const GLComponents formatComps = GLComponents(format);
1357 const GLComponents fboComps = GLComponents(fboFormat);
1358 if (!formatComps.IsSubsetOf(fboComps)) {
1359 ErrorInvalidOperation("%s: Format %s is not a subset of the current"
1360 " framebuffer format, which is %s.",
1361 InfoFrom(func, dims), EnumName(format),
1362 EnumName(fboFormat));
1363 return false;
1366 return true;
1370 * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
1371 * Verifies each of the parameters against the WebGL standard and enabled
1372 * extensions.
1374 // TODO: Texture dims is here for future expansion in WebGL 2.0
1375 bool
1376 WebGLContext::ValidateTexImage(TexImageTarget texImageTarget, GLint level,
1377 GLenum internalFormat, GLint xoffset,
1378 GLint yoffset, GLint zoffset, GLint width,
1379 GLint height, GLint depth, GLint border,
1380 GLenum format, GLenum type,
1381 WebGLTexImageFunc func,
1382 WebGLTexDimensions dims)
1384 const char* info = InfoFrom(func, dims);
1386 // Check level
1387 if (level < 0) {
1388 ErrorInvalidValue("%s: `level` must be >= 0.", info);
1389 return false;
1392 // Check border
1393 if (border != 0) {
1394 ErrorInvalidValue("%s: `border` must be 0.", info);
1395 return false;
1398 // Check incoming image format and type
1399 if (!ValidateTexImageFormatAndType(format, type, func, dims))
1400 return false;
1402 if (!TexInternalFormat::IsValueLegal(internalFormat)) {
1403 ErrorInvalidEnum("%s: Invalid `internalformat` enum %s.", info,
1404 EnumName(internalFormat));
1405 return false;
1407 TexInternalFormat unsizedInternalFormat =
1408 UnsizedInternalFormatFromInternalFormat(internalFormat);
1410 if (IsCompressedFunc(func)) {
1411 if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims))
1412 return false;
1414 } else if (IsCopyFunc(func)) {
1415 if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(),
1416 func, dims))
1418 return false;
1420 } else if (format != unsizedInternalFormat) {
1421 if (IsWebGL2()) {
1422 // In WebGL2, it's OK to have `internalFormat != format` if
1423 // internalFormat is the sized internal format corresponding to the
1424 // (format, type) pair according to Table 3.2 in the OpenGL ES 3.0.3
1425 // spec.
1426 auto effectiveFormat = EffectiveInternalFormatFromInternalFormatAndType(format,
1427 type);
1428 if (internalFormat != effectiveFormat) {
1429 bool exceptionallyAllowed = false;
1430 if (internalFormat == LOCAL_GL_SRGB8_ALPHA8 &&
1431 format == LOCAL_GL_RGBA &&
1432 type == LOCAL_GL_UNSIGNED_BYTE)
1434 exceptionallyAllowed = true;
1436 else if (internalFormat == LOCAL_GL_SRGB8 &&
1437 format == LOCAL_GL_RGB &&
1438 type == LOCAL_GL_UNSIGNED_BYTE)
1440 exceptionallyAllowed = true;
1442 if (!exceptionallyAllowed) {
1443 ErrorInvalidOperation("%s: `internalformat` does not match"
1444 " `format` and `type`.", info);
1445 return false;
1448 } else {
1449 // In WebGL 1, format must be equal to internalformat.
1450 ErrorInvalidOperation("%s: `internalformat` does not match"
1451 " `format`.", info);
1452 return false;
1456 // Check texture image size
1457 if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func,
1458 dims))
1460 return false;
1463 /* 5.14.8 Texture objects - WebGL Spec.
1464 * "If an attempt is made to call these functions with no
1465 * WebGLTexture bound (see above), an INVALID_OPERATION error
1466 * is generated."
1468 WebGLTexture* tex = ActiveBoundTextureForTexImageTarget(texImageTarget);
1469 if (!tex) {
1470 ErrorInvalidOperation("%s: No texture is bound to target %s.", info,
1471 WebGLContext::EnumName(texImageTarget.get()));
1472 return false;
1475 if (IsSubFunc(func)) {
1476 if (!tex->HasImageInfoAt(texImageTarget, level)) {
1477 ErrorInvalidOperation("%s: No texture image previously defined for"
1478 " target %s at level %d.", info,
1479 WebGLContext::EnumName(texImageTarget.get()),
1480 level);
1481 return false;
1484 const auto& imageInfo = tex->ImageInfoAt(texImageTarget, level);
1485 if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset, width, height,
1486 depth, imageInfo.Width(),
1487 imageInfo.Height(), 0, func, dims))
1489 return false;
1493 // Additional checks for depth textures
1494 if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
1495 (format == LOCAL_GL_DEPTH_COMPONENT ||
1496 format == LOCAL_GL_DEPTH_STENCIL))
1498 ErrorInvalidOperation("%s: With format of %s, target must be"
1499 " TEXTURE_2D.", info,
1500 WebGLContext::EnumName(format));
1501 return false;
1504 // Additional checks for compressed textures
1505 if (!IsAllowedFromSource(internalFormat, func)) {
1506 ErrorInvalidOperation("%s: Invalid format %s for this operation.",
1507 info, WebGLContext::EnumName(format));
1508 return false;
1511 // Parameters are OK
1512 return true;
1515 bool
1516 WebGLContext::ValidateUniformLocation(const char* info,
1517 WebGLUniformLocation* loc)
1519 if (!ValidateObjectAllowNull(info, loc))
1520 return false;
1522 if (!loc)
1523 return false;
1525 // The need to check specifically for !mCurrentProgram here is explained in
1526 // bug 657556.
1527 if (!mCurrentProgram) {
1528 ErrorInvalidOperation("%s: No program is currently bound.", info);
1529 return false;
1532 if (mCurrentProgram != loc->Program()) {
1533 ErrorInvalidOperation("%s: This uniform location doesn't correspond to"
1534 " the current program.", info);
1535 return false;
1538 if (mCurrentProgram->Generation() != loc->ProgramGeneration()) {
1539 ErrorInvalidOperation("%s: This uniform location is obsolete since the"
1540 " program has been relinked.", info);
1541 return false;
1544 return true;
1547 bool
1548 WebGLContext::ValidateSamplerUniformSetter(const char* info,
1549 WebGLUniformLocation* loc,
1550 GLint value)
1552 if (loc->Info().type != LOCAL_GL_SAMPLER_2D &&
1553 loc->Info().type != LOCAL_GL_SAMPLER_CUBE)
1555 return true;
1558 if (value >= 0 && value < mGLMaxTextureUnits)
1559 return true;
1561 ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
1562 " valid texture unit.", info, value);
1563 return false;
1566 bool
1567 WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt,
1568 uint32_t arrayLength)
1570 if (IsContextLost())
1571 return false;
1573 if (arrayLength < cnt) {
1574 ErrorInvalidOperation("%s: Array must be >= %d elements.", name, cnt);
1575 return false;
1578 return true;
1581 static bool
1582 IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
1584 switch (uniformType) {
1585 case LOCAL_GL_BOOL:
1586 case LOCAL_GL_BOOL_VEC2:
1587 case LOCAL_GL_BOOL_VEC3:
1588 case LOCAL_GL_BOOL_VEC4:
1589 return true; // GLfloat(0.0) sets a bool to false.
1591 case LOCAL_GL_INT:
1592 case LOCAL_GL_INT_SAMPLER_2D:
1593 case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
1594 case LOCAL_GL_INT_SAMPLER_3D:
1595 case LOCAL_GL_INT_SAMPLER_CUBE:
1596 case LOCAL_GL_INT_VEC2:
1597 case LOCAL_GL_INT_VEC3:
1598 case LOCAL_GL_INT_VEC4:
1599 case LOCAL_GL_SAMPLER_2D:
1600 case LOCAL_GL_SAMPLER_2D_ARRAY:
1601 case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
1602 case LOCAL_GL_SAMPLER_2D_SHADOW:
1603 case LOCAL_GL_SAMPLER_CUBE:
1604 case LOCAL_GL_SAMPLER_CUBE_SHADOW:
1605 case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
1606 case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
1607 case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
1608 case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
1609 return setterType == LOCAL_GL_INT;
1611 case LOCAL_GL_FLOAT:
1612 case LOCAL_GL_FLOAT_MAT2:
1613 case LOCAL_GL_FLOAT_MAT2x3:
1614 case LOCAL_GL_FLOAT_MAT2x4:
1615 case LOCAL_GL_FLOAT_MAT3:
1616 case LOCAL_GL_FLOAT_MAT3x2:
1617 case LOCAL_GL_FLOAT_MAT3x4:
1618 case LOCAL_GL_FLOAT_MAT4:
1619 case LOCAL_GL_FLOAT_MAT4x2:
1620 case LOCAL_GL_FLOAT_MAT4x3:
1621 case LOCAL_GL_FLOAT_VEC2:
1622 case LOCAL_GL_FLOAT_VEC3:
1623 case LOCAL_GL_FLOAT_VEC4:
1624 return setterType == LOCAL_GL_FLOAT;
1626 default:
1627 MOZ_ASSERT(false); // should never get here
1628 return false;
1632 static bool
1633 CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
1634 uint8_t setterElemSize, GLenum setterType,
1635 const char* info)
1637 if (setterElemSize != loc->ElementSize()) {
1638 webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
1639 loc->ElementSize());
1640 return false;
1643 if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
1644 webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
1645 loc->Info().type);
1646 return false;
1649 return true;
1652 static bool
1653 CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
1654 uint8_t setterElemSize, size_t setterArraySize,
1655 const char* info)
1657 if (setterArraySize == 0 ||
1658 setterArraySize % setterElemSize)
1660 webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
1661 " %d, got an array of length %d.", info,
1662 setterElemSize, setterArraySize);
1663 return false;
1666 if (!loc->Info().isArray &&
1667 setterArraySize != setterElemSize)
1669 webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
1670 " (since this uniform is not an array"
1671 " uniform), got an array of length %d.",
1672 info, setterElemSize, setterArraySize);
1673 return false;
1676 return true;
1679 bool
1680 WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
1681 uint8_t setterElemSize, GLenum setterType,
1682 const char* info, GLuint* out_rawLoc)
1684 if (IsContextLost())
1685 return false;
1687 if (!ValidateUniformLocation(info, loc))
1688 return false;
1690 if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
1691 return false;
1693 *out_rawLoc = loc->Location();
1694 return true;
1697 bool
1698 WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
1699 uint8_t setterElemSize,
1700 GLenum setterType,
1701 size_t setterArraySize,
1702 const char* info,
1703 GLuint* const out_rawLoc,
1704 GLsizei* const out_numElementsToUpload)
1706 if (IsContextLost())
1707 return false;
1709 if (!ValidateUniformLocation(info, loc))
1710 return false;
1712 if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
1713 return false;
1715 if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
1716 info))
1718 return false;
1721 *out_rawLoc = loc->Location();
1722 *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
1723 setterArraySize / setterElemSize);
1724 return true;
1727 bool
1728 WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
1729 uint8_t setterDims,
1730 GLenum setterType,
1731 size_t setterArraySize,
1732 bool setterTranspose,
1733 const char* info,
1734 GLuint* const out_rawLoc,
1735 GLsizei* const out_numElementsToUpload)
1737 uint8_t setterElemSize = setterDims * setterDims;
1739 if (IsContextLost())
1740 return false;
1742 if (!ValidateUniformLocation(info, loc))
1743 return false;
1745 if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
1746 return false;
1748 if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
1749 info))
1751 return false;
1754 if (setterTranspose) {
1755 ErrorInvalidValue("%s: `transpose` must be false.", info);
1756 return false;
1759 *out_rawLoc = loc->Location();
1760 *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
1761 setterArraySize / setterElemSize);
1762 return true;
1765 bool
1766 WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
1768 bool valid = (index < MaxVertexAttribs());
1770 if (!valid) {
1771 if (index == GLuint(-1)) {
1772 ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
1773 " probably comes from a getAttribLocation()"
1774 " call, where this return value -1 means"
1775 " that the passed name didn't correspond to"
1776 " an active attribute in the specified"
1777 " program.", info);
1778 } else {
1779 ErrorInvalidValue("%s: `index` must be less than"
1780 " MAX_VERTEX_ATTRIBS.", info);
1784 return valid;
1787 bool
1788 WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
1789 WebGLboolean normalized, GLsizei stride,
1790 WebGLintptr byteOffset, const char* info)
1792 WebGLBuffer* buffer = mBoundArrayBuffer;
1793 if (!buffer) {
1794 ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info);
1795 return false;
1798 GLsizei requiredAlignment = 0;
1799 if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info))
1800 return false;
1802 // requiredAlignment should always be a power of two
1803 MOZ_ASSERT(IsPOTAssumingNonnegative(requiredAlignment));
1804 GLsizei requiredAlignmentMask = requiredAlignment - 1;
1806 if (size < 1 || size > 4) {
1807 ErrorInvalidValue("%s: invalid element size", info);
1808 return false;
1811 // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
1812 if (stride < 0 || stride > 255) {
1813 ErrorInvalidValue("%s: negative or too large stride", info);
1814 return false;
1817 if (byteOffset < 0) {
1818 ErrorInvalidValue("%s: negative offset", info);
1819 return false;
1822 if (stride & requiredAlignmentMask) {
1823 ErrorInvalidOperation("%s: stride doesn't satisfy the alignment "
1824 "requirement of given type", info);
1825 return false;
1828 if (byteOffset & requiredAlignmentMask) {
1829 ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment "
1830 "requirement of given type", info);
1831 return false;
1834 return true;
1837 bool
1838 WebGLContext::ValidateStencilParamsForDrawCall()
1840 const char msg[] = "%s set different front and back stencil %s. Drawing in"
1841 " this configuration is not allowed.";
1843 if (mStencilRefFront != mStencilRefBack) {
1844 ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
1845 return false;
1848 if (mStencilValueMaskFront != mStencilValueMaskBack) {
1849 ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
1850 return false;
1853 if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
1854 ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
1855 return false;
1858 return true;
1861 static inline int32_t
1862 FloorPOT(int32_t x)
1864 MOZ_ASSERT(x > 0);
1865 int32_t pot = 1;
1866 while (pot < 0x40000000) {
1867 if (x < pot*2)
1868 break;
1869 pot *= 2;
1871 return pot;
1874 bool
1875 WebGLContext::InitAndValidateGL()
1877 if (!gl)
1878 return false;
1880 GLenum error = gl->fGetError();
1881 if (error != LOCAL_GL_NO_ERROR) {
1882 GenerateWarning("GL error 0x%x occurred during OpenGL context"
1883 " initialization, before WebGL initialization!", error);
1884 return false;
1887 mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
1888 mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
1889 mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-pressure", false);
1890 mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
1891 mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true);
1893 if (MinCapabilityMode())
1894 mDisableFragHighP = true;
1896 // These are the default values, see 6.2 State tables in the
1897 // OpenGL ES 2.0.25 spec.
1898 mColorWriteMask[0] = 1;
1899 mColorWriteMask[1] = 1;
1900 mColorWriteMask[2] = 1;
1901 mColorWriteMask[3] = 1;
1902 mDepthWriteMask = 1;
1903 mColorClearValue[0] = 0.f;
1904 mColorClearValue[1] = 0.f;
1905 mColorClearValue[2] = 0.f;
1906 mColorClearValue[3] = 0.f;
1907 mDepthClearValue = 1.f;
1908 mStencilClearValue = 0;
1909 mStencilRefFront = 0;
1910 mStencilRefBack = 0;
1913 // Technically, we should be setting mStencil[...] values to
1914 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
1915 GLuint stencilBits = 0;
1916 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
1917 GLuint allOnes = ~(UINT32_MAX << stencilBits);
1918 mStencilValueMaskFront = allOnes;
1919 mStencilValueMaskBack = allOnes;
1920 mStencilWriteMaskFront = allOnes;
1921 mStencilWriteMaskBack = allOnes;
1924 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
1925 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
1926 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
1927 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
1929 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
1930 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
1931 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront);
1932 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
1934 mDitherEnabled = true;
1935 mRasterizerDiscardEnabled = false;
1936 mScissorTestEnabled = false;
1938 // Bindings, etc.
1939 mActiveTexture = 0;
1940 mEmitContextLostErrorOnce = true;
1941 mWebGLError = LOCAL_GL_NO_ERROR;
1942 mUnderlyingGLError = LOCAL_GL_NO_ERROR;
1944 mBound2DTextures.Clear();
1945 mBoundCubeMapTextures.Clear();
1946 mBound3DTextures.Clear();
1948 mBoundArrayBuffer = nullptr;
1949 mBoundTransformFeedbackBuffer = nullptr;
1950 mCurrentProgram = nullptr;
1952 mBoundFramebuffer = nullptr;
1953 mBoundRenderbuffer = nullptr;
1955 MakeContextCurrent();
1957 // on desktop OpenGL, we always keep vertex attrib 0 array enabled
1958 if (!gl->IsGLES())
1959 gl->fEnableVertexAttribArray(0);
1961 if (MinCapabilityMode())
1962 mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
1963 else
1964 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
1966 if (mGLMaxVertexAttribs < 8) {
1967 GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
1968 mGLMaxVertexAttribs);
1969 return false;
1972 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
1973 // even though the hardware supports much more. The
1974 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
1975 if (MinCapabilityMode())
1976 mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
1977 else
1978 gl->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &mGLMaxTextureUnits);
1980 if (mGLMaxTextureUnits < 8) {
1981 GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!",
1982 mGLMaxTextureUnits);
1983 return false;
1986 mBound2DTextures.SetLength(mGLMaxTextureUnits);
1987 mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
1988 mBound3DTextures.SetLength(mGLMaxTextureUnits);
1990 if (MinCapabilityMode()) {
1991 mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
1992 mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
1993 mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
1994 mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
1995 mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
1996 } else {
1997 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
1998 gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
1999 gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
2000 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
2001 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
2004 // Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize
2005 mGLMaxTextureSizeLog2 = 0;
2006 int32_t tempSize = mGLMaxTextureSize;
2007 while (tempSize >>= 1) {
2008 ++mGLMaxTextureSizeLog2;
2011 mGLMaxCubeMapTextureSizeLog2 = 0;
2012 tempSize = mGLMaxCubeMapTextureSize;
2013 while (tempSize >>= 1) {
2014 ++mGLMaxCubeMapTextureSizeLog2;
2017 mGLMaxTextureSize = FloorPOT(mGLMaxTextureSize);
2018 mGLMaxRenderbufferSize = FloorPOT(mGLMaxRenderbufferSize);
2020 if (MinCapabilityMode()) {
2021 mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
2022 mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
2023 mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
2024 } else {
2025 if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
2026 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
2027 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
2028 gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
2029 } else {
2030 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
2031 mGLMaxFragmentUniformVectors /= 4;
2032 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
2033 mGLMaxVertexUniformVectors /= 4;
2035 /* We are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS
2036 * and GL_MAX_FRAGMENT_INPUT_COMPONENTS, however these constants
2037 * only entered the OpenGL standard at OpenGL 3.2. So we will try
2038 * reading, and check OpenGL error for INVALID_ENUM.
2040 * On the public_webgl list, "problematic GetParameter pnames"
2041 * thread, the following formula was given:
2042 * maxVaryingVectors = min(GL_MAX_VERTEX_OUTPUT_COMPONENTS,
2043 * GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
2045 GLint maxVertexOutputComponents = 0;
2046 GLint maxFragmentInputComponents = 0;
2048 const bool ok = (gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS,
2049 &maxVertexOutputComponents) &&
2050 gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS,
2051 &maxFragmentInputComponents));
2053 if (ok) {
2054 mGLMaxVaryingVectors = std::min(maxVertexOutputComponents,
2055 maxFragmentInputComponents) / 4;
2056 } else {
2057 mGLMaxVaryingVectors = 16;
2058 // 16 = 64/4, and 64 is the min value for
2059 // maxVertexOutputComponents in the OpenGL 3.2 spec.
2064 // Always 1 for GLES2
2065 mMaxFramebufferColorAttachments = 1;
2067 if (!gl->IsGLES()) {
2068 // gl_PointSize is always available in ES2 GLSL, but has to be
2069 // specifically enabled on desktop GLSL.
2070 gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
2072 /* gl_PointCoord is always available in ES2 GLSL and in newer desktop
2073 * GLSL versions, but apparently not in OpenGL 2 and apparently not (due
2074 * to a driver bug) on certain NVIDIA setups. See:
2075 * http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
2077 * Note that this used to cause crashes on old ATI drivers... Hopefully
2078 * not a significant anymore. See bug 602183.
2080 gl->fEnable(LOCAL_GL_POINT_SPRITE);
2083 #ifdef XP_MACOSX
2084 if (gl->WorkAroundDriverBugs() &&
2085 gl->Vendor() == gl::GLVendor::ATI &&
2086 !nsCocoaFeatures::IsAtLeastVersion(10,9))
2088 // The Mac ATI driver, in all known OSX version up to and including
2089 // 10.8, renders points sprites upside-down. (Apple bug 11778921)
2090 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
2091 LOCAL_GL_LOWER_LEFT);
2093 #endif
2095 // Check the shader validator pref
2096 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
2098 mShaderValidation = Preferences::GetBool("webgl.shader_validator",
2099 mShaderValidation);
2101 // initialize shader translator
2102 if (mShaderValidation) {
2103 if (!ShInitialize()) {
2104 GenerateWarning("GLSL translator initialization failed!");
2105 return false;
2109 // Mesa can only be detected with the GL_VERSION string, of the form
2110 // "2.1 Mesa 7.11.0"
2111 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
2112 mIsMesa = strstr(versionStr, "Mesa");
2114 // Notice that the point of calling fGetError here is not only to check for
2115 // errors, but also to reset the error flags so that a subsequent WebGL
2116 // getError call will give the correct result.
2117 error = gl->fGetError();
2118 if (error != LOCAL_GL_NO_ERROR) {
2119 GenerateWarning("GL error 0x%x occurred during WebGL context"
2120 " initialization!", error);
2121 return false;
2124 if (IsWebGL2() &&
2125 !InitWebGL2())
2127 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
2128 return false;
2131 // Default value for all disabled vertex attributes is [0, 0, 0, 1]
2132 for (int32_t index = 0; index < mGLMaxVertexAttribs; ++index) {
2133 VertexAttrib4f(index, 0, 0, 0, 1);
2136 mDefaultVertexArray = WebGLVertexArray::Create(this);
2137 mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
2138 mBoundVertexArray = mDefaultVertexArray;
2140 if (mLoseContextOnMemoryPressure)
2141 mContextObserver->RegisterMemoryPressureEvent();
2143 return true;
2146 } // namespace mozilla