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