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"
18 #include "mozilla/CheckedInt.h"
19 #include "mozilla/Preferences.h"
20 #include "mozilla/Services.h"
22 #include "jsfriendapi.h"
24 #include "angle/ShaderLang.h"
28 #include "mozilla/Services.h"
29 #include "nsIObserverService.h"
31 using namespace mozilla
;
34 * Pull data out of the program, post-linking
37 WebGLProgram::UpdateInfo()
39 mIdentifierMap
= nullptr;
40 mIdentifierReverseMap
= nullptr;
41 mUniformInfoMap
= nullptr;
43 mAttribMaxNameLength
= 0;
45 for (size_t i
= 0; i
< mAttachedShaders
.Length(); i
++)
46 mAttribMaxNameLength
= std::max(mAttribMaxNameLength
, mAttachedShaders
[i
]->mAttribMaxNameLength
);
49 mContext
->gl
->fGetProgramiv(mGLName
, LOCAL_GL_ACTIVE_ATTRIBUTES
, &attribCount
);
51 if (!mAttribsInUse
.SetLength(mContext
->mGLMaxVertexAttribs
)) {
52 mContext
->ErrorOutOfMemory("updateInfo: out of memory to allocate %d attribs", mContext
->mGLMaxVertexAttribs
);
56 for (size_t i
= 0; i
< mAttribsInUse
.Length(); i
++)
57 mAttribsInUse
[i
] = false;
59 nsAutoArrayPtr
<char> nameBuf(new char[mAttribMaxNameLength
]);
61 for (int i
= 0; i
< attribCount
; ++i
) {
65 mContext
->gl
->fGetActiveAttrib(mGLName
, i
, mAttribMaxNameLength
, &attrnamelen
, &attrsize
, &attrtype
, nameBuf
);
66 if (attrnamelen
> 0) {
67 GLint loc
= mContext
->gl
->fGetAttribLocation(mGLName
, nameBuf
);
68 MOZ_ASSERT(loc
>= 0, "major oops in managing the attributes of a WebGL program");
69 if (loc
< mContext
->mGLMaxVertexAttribs
) {
70 mAttribsInUse
[loc
] = true;
72 mContext
->GenerateWarning("program exceeds MAX_VERTEX_ATTRIBS");
78 if (!mUniformInfoMap
) {
79 mUniformInfoMap
= new CStringToUniformInfoMap
;
80 for (size_t i
= 0; i
< mAttachedShaders
.Length(); i
++) {
81 for (size_t j
= 0; j
< mAttachedShaders
[i
]->mUniforms
.Length(); j
++) {
82 const WebGLMappedIdentifier
& uniform
= mAttachedShaders
[i
]->mUniforms
[j
];
83 const WebGLUniformInfo
& info
= mAttachedShaders
[i
]->mUniformInfos
[j
];
84 mUniformInfoMap
->Put(uniform
.mapped
, info
);
89 mActiveAttribMap
.clear();
91 GLint numActiveAttrs
= 0;
92 mContext
->gl
->fGetProgramiv(mGLName
, LOCAL_GL_ACTIVE_ATTRIBUTES
, &numActiveAttrs
);
94 // Spec says the maximum attrib name length is 256 chars, so this is
95 // sufficient to hold any attrib name.
100 for (GLint i
= 0; i
< numActiveAttrs
; i
++) {
101 mContext
->gl
->fGetActiveAttrib(mGLName
, i
, 257, nullptr, &dummySize
,
102 &dummyType
, attrName
);
103 GLint attrLoc
= mContext
->gl
->fGetAttribLocation(mGLName
, attrName
);
104 MOZ_ASSERT(attrLoc
>= 0);
105 mActiveAttribMap
.insert(std::make_pair(attrLoc
, nsCString(attrName
)));
111 bool WebGLContext::ValidateBlendEquationEnum(GLenum mode
, const char *info
)
114 case LOCAL_GL_FUNC_ADD
:
115 case LOCAL_GL_FUNC_SUBTRACT
:
116 case LOCAL_GL_FUNC_REVERSE_SUBTRACT
:
121 // http://www.opengl.org/registry/specs/EXT/blend_minmax.txt
129 ErrorInvalidEnumInfo(info
, mode
);
133 bool WebGLContext::ValidateBlendFuncDstEnum(GLenum factor
, const char *info
)
138 case LOCAL_GL_SRC_COLOR
:
139 case LOCAL_GL_ONE_MINUS_SRC_COLOR
:
140 case LOCAL_GL_DST_COLOR
:
141 case LOCAL_GL_ONE_MINUS_DST_COLOR
:
142 case LOCAL_GL_SRC_ALPHA
:
143 case LOCAL_GL_ONE_MINUS_SRC_ALPHA
:
144 case LOCAL_GL_DST_ALPHA
:
145 case LOCAL_GL_ONE_MINUS_DST_ALPHA
:
146 case LOCAL_GL_CONSTANT_COLOR
:
147 case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR
:
148 case LOCAL_GL_CONSTANT_ALPHA
:
149 case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA
:
152 ErrorInvalidEnumInfo(info
, factor
);
157 bool WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor
, const char *info
)
159 if (factor
== LOCAL_GL_SRC_ALPHA_SATURATE
)
162 return ValidateBlendFuncDstEnum(factor
, info
);
165 bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor
, GLenum dfactor
, const char *info
)
167 bool sfactorIsConstantColor
= sfactor
== LOCAL_GL_CONSTANT_COLOR
||
168 sfactor
== LOCAL_GL_ONE_MINUS_CONSTANT_COLOR
;
169 bool sfactorIsConstantAlpha
= sfactor
== LOCAL_GL_CONSTANT_ALPHA
||
170 sfactor
== LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA
;
171 bool dfactorIsConstantColor
= dfactor
== LOCAL_GL_CONSTANT_COLOR
||
172 dfactor
== LOCAL_GL_ONE_MINUS_CONSTANT_COLOR
;
173 bool dfactorIsConstantAlpha
= dfactor
== LOCAL_GL_CONSTANT_ALPHA
||
174 dfactor
== LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA
;
175 if ( (sfactorIsConstantColor
&& dfactorIsConstantAlpha
) ||
176 (dfactorIsConstantColor
&& sfactorIsConstantAlpha
) ) {
177 ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in the WebGL 1.0 spec", info
);
184 bool WebGLContext::ValidateTextureTargetEnum(GLenum target
, const char *info
)
187 case LOCAL_GL_TEXTURE_2D
:
188 case LOCAL_GL_TEXTURE_CUBE_MAP
:
191 ErrorInvalidEnumInfo(info
, target
);
196 bool WebGLContext::ValidateComparisonEnum(GLenum target
, const char *info
)
201 case LOCAL_GL_LEQUAL
:
202 case LOCAL_GL_GREATER
:
203 case LOCAL_GL_GEQUAL
:
205 case LOCAL_GL_NOTEQUAL
:
206 case LOCAL_GL_ALWAYS
:
209 ErrorInvalidEnumInfo(info
, target
);
214 bool WebGLContext::ValidateStencilOpEnum(GLenum action
, const char *info
)
219 case LOCAL_GL_REPLACE
:
221 case LOCAL_GL_INCR_WRAP
:
223 case LOCAL_GL_DECR_WRAP
:
224 case LOCAL_GL_INVERT
:
227 ErrorInvalidEnumInfo(info
, action
);
232 bool WebGLContext::ValidateFaceEnum(GLenum face
, const char *info
)
237 case LOCAL_GL_FRONT_AND_BACK
:
240 ErrorInvalidEnumInfo(info
, face
);
245 bool WebGLContext::ValidateDrawModeEnum(GLenum mode
, const char *info
)
248 case LOCAL_GL_TRIANGLES
:
249 case LOCAL_GL_TRIANGLE_STRIP
:
250 case LOCAL_GL_TRIANGLE_FAN
:
251 case LOCAL_GL_POINTS
:
252 case LOCAL_GL_LINE_STRIP
:
253 case LOCAL_GL_LINE_LOOP
:
257 ErrorInvalidEnumInfo(info
, mode
);
262 bool WebGLContext::ValidateGLSLVariableName(const nsAString
& name
, const char *info
)
267 const uint32_t maxSize
= 256;
268 if (name
.Length() > maxSize
) {
269 ErrorInvalidValue("%s: identifier is %d characters long, exceeds the maximum allowed length of %d characters",
270 info
, name
.Length(), maxSize
);
274 if (!ValidateGLSLString(name
, info
)) {
278 nsString prefix1
= NS_LITERAL_STRING("webgl_");
279 nsString prefix2
= NS_LITERAL_STRING("_webgl_");
281 if (Substring(name
, 0, prefix1
.Length()).Equals(prefix1
) ||
282 Substring(name
, 0, prefix2
.Length()).Equals(prefix2
))
284 ErrorInvalidOperation("%s: string contains a reserved GLSL prefix", info
);
291 bool WebGLContext::ValidateGLSLString(const nsAString
& string
, const char *info
)
293 for (uint32_t i
= 0; i
< string
.Length(); ++i
) {
294 if (!ValidateGLSLCharacter(string
.CharAt(i
))) {
295 ErrorInvalidValue("%s: string contains the illegal character '%d'", info
, string
.CharAt(i
));
303 bool WebGLContext::ValidateTexImage2DTarget(GLenum target
, GLsizei width
, GLsizei height
,
307 case LOCAL_GL_TEXTURE_2D
:
309 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
310 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
311 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
312 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
313 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
314 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
315 if (width
!= height
) {
316 ErrorInvalidValue("%s: with cube map targets, width and height must be equal", info
);
321 ErrorInvalidEnum("%s: invalid target enum 0x%x", info
, target
);
328 bool WebGLContext::ValidateCompressedTextureSize(GLenum target
, GLint level
,
330 GLsizei width
, GLsizei height
, uint32_t byteLength
, const char* info
)
332 if (!ValidateLevelWidthHeightForTarget(target
, level
, width
, height
, info
)) {
336 // negative width and height must already have been handled above
337 MOZ_ASSERT(width
>= 0 && height
>= 0);
339 CheckedUint32 required_byteLength
= 0;
342 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
343 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
344 case LOCAL_GL_ATC_RGB
:
346 required_byteLength
= ((CheckedUint32(width
) + 3) / 4) * ((CheckedUint32(height
) + 3) / 4) * 8;
349 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
350 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
351 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA
:
352 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA
:
354 required_byteLength
= ((CheckedUint32(width
) + 3) / 4) * ((CheckedUint32(height
) + 3) / 4) * 16;
357 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1
:
358 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1
:
360 required_byteLength
= CheckedUint32(std::max(width
, 8)) * CheckedUint32(std::max(height
, 8)) / 2;
363 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1
:
364 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1
:
366 required_byteLength
= CheckedUint32(std::max(width
, 16)) * CheckedUint32(std::max(height
, 8)) / 4;
371 if (!required_byteLength
.isValid() || required_byteLength
.value() != byteLength
) {
372 ErrorInvalidValue("%s: data size does not match dimensions", info
);
377 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
378 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
379 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
380 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
382 if (level
== 0 && width
% 4 == 0 && height
% 4 == 0) {
386 && (width
== 0 || width
== 1 || width
== 2 || width
% 4 == 0)
387 && (height
== 0 || height
== 1 || height
== 2 || height
% 4 == 0))
391 ErrorInvalidOperation("%s: level parameter does not match width and height", info
);
394 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1
:
395 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1
:
396 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1
:
397 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1
:
399 if (!is_pot_assuming_nonnegative(width
) ||
400 !is_pot_assuming_nonnegative(height
))
402 ErrorInvalidValue("%s: width and height must be powers of two", info
);
411 bool WebGLContext::ValidateLevelWidthHeightForTarget(GLenum target
, GLint level
, GLsizei width
,
412 GLsizei height
, const char* info
)
414 GLsizei maxTextureSize
= MaxTextureSizeForTarget(target
);
417 ErrorInvalidValue("%s: level must be >= 0", info
);
421 GLsizei maxAllowedSize
= maxTextureSize
>> level
;
423 if (!maxAllowedSize
) {
424 ErrorInvalidValue("%s: 2^level exceeds maximum texture size", info
);
428 if (width
< 0 || height
< 0) {
429 ErrorInvalidValue("%s: width and height must be >= 0", info
);
433 if (width
> maxAllowedSize
|| height
> maxAllowedSize
) {
434 ErrorInvalidValue("%s: the maximum texture size for level %d is %d", info
, level
, maxAllowedSize
);
441 uint32_t WebGLContext::GetBitsPerTexel(GLenum format
, GLenum type
)
443 // If there is no defined format or type, we're not taking up any memory
444 if (!format
|| !type
) {
448 if (format
== LOCAL_GL_DEPTH_COMPONENT
) {
449 if (type
== LOCAL_GL_UNSIGNED_SHORT
)
451 else if (type
== LOCAL_GL_UNSIGNED_INT
)
453 } else if (format
== LOCAL_GL_DEPTH_STENCIL
) {
454 if (type
== LOCAL_GL_UNSIGNED_INT_24_8_EXT
)
458 if (type
== LOCAL_GL_UNSIGNED_BYTE
|| type
== LOCAL_GL_FLOAT
) {
459 int multiplier
= type
== LOCAL_GL_FLOAT
? 32 : 8;
462 case LOCAL_GL_LUMINANCE
:
463 return 1 * multiplier
;
464 case LOCAL_GL_LUMINANCE_ALPHA
:
465 return 2 * multiplier
;
467 return 3 * multiplier
;
469 return 4 * multiplier
;
470 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1
:
471 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1
:
473 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT
:
474 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
:
475 case LOCAL_GL_ATC_RGB
:
476 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1
:
477 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1
:
479 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
:
480 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
:
481 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA
:
482 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA
:
487 } else if (type
== LOCAL_GL_UNSIGNED_SHORT_4_4_4_4
||
488 type
== LOCAL_GL_UNSIGNED_SHORT_5_5_5_1
||
489 type
== LOCAL_GL_UNSIGNED_SHORT_5_6_5
)
498 bool WebGLContext::ValidateTexFormatAndType(GLenum format
, GLenum type
, int jsArrayType
,
499 uint32_t *texelSize
, const char *info
)
501 if (IsExtensionEnabled(WEBGL_depth_texture
)) {
502 if (format
== LOCAL_GL_DEPTH_COMPONENT
) {
503 if (jsArrayType
!= -1) {
504 if ((type
== LOCAL_GL_UNSIGNED_SHORT
&& jsArrayType
!= js::ArrayBufferView::TYPE_UINT16
) ||
505 (type
== LOCAL_GL_UNSIGNED_INT
&& jsArrayType
!= js::ArrayBufferView::TYPE_UINT32
)) {
506 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info
);
512 case LOCAL_GL_UNSIGNED_SHORT
:
515 case LOCAL_GL_UNSIGNED_INT
:
519 ErrorInvalidOperation("%s: invalid type 0x%x", info
, type
);
525 } else if (format
== LOCAL_GL_DEPTH_STENCIL
) {
526 if (type
!= LOCAL_GL_UNSIGNED_INT_24_8_EXT
) {
527 ErrorInvalidOperation("%s: invalid format 0x%x", info
, format
);
530 if (jsArrayType
!= -1) {
531 if (jsArrayType
!= js::ArrayBufferView::TYPE_UINT32
) {
532 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info
);
543 if (type
== LOCAL_GL_UNSIGNED_BYTE
||
544 (IsExtensionEnabled(OES_texture_float
) && type
== LOCAL_GL_FLOAT
))
546 if (jsArrayType
!= -1) {
547 if ((type
== LOCAL_GL_UNSIGNED_BYTE
&& jsArrayType
!= js::ArrayBufferView::TYPE_UINT8
) ||
548 (type
== LOCAL_GL_FLOAT
&& jsArrayType
!= js::ArrayBufferView::TYPE_FLOAT32
))
550 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info
);
555 int texMultiplier
= type
== LOCAL_GL_FLOAT
? 4 : 1;
558 case LOCAL_GL_LUMINANCE
:
559 *texelSize
= 1 * texMultiplier
;
561 case LOCAL_GL_LUMINANCE_ALPHA
:
562 *texelSize
= 2 * texMultiplier
;
565 *texelSize
= 3 * texMultiplier
;
568 *texelSize
= 4 * texMultiplier
;
574 ErrorInvalidEnum("%s: invalid format 0x%x", info
, format
);
579 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4
:
580 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1
:
581 if (jsArrayType
!= -1 && jsArrayType
!= js::ArrayBufferView::TYPE_UINT16
) {
582 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info
);
586 if (format
== LOCAL_GL_RGBA
) {
590 ErrorInvalidOperation("%s: mutually incompatible format and type", info
);
593 case LOCAL_GL_UNSIGNED_SHORT_5_6_5
:
594 if (jsArrayType
!= -1 && jsArrayType
!= js::ArrayBufferView::TYPE_UINT16
) {
595 ErrorInvalidOperation("%s: invalid typed array type for given texture data type", info
);
599 if (format
== LOCAL_GL_RGB
) {
603 ErrorInvalidOperation("%s: mutually incompatible format and type", info
);
610 ErrorInvalidEnum("%s: invalid type 0x%x", info
, type
);
615 WebGLContext::ValidateUniformLocation(const char* info
, WebGLUniformLocation
*location_object
)
617 if (!ValidateObjectAllowNull(info
, location_object
))
619 if (!location_object
)
621 /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
622 if (!mCurrentProgram
) {
623 ErrorInvalidOperation("%s: no program is currently bound", info
);
626 if (mCurrentProgram
!= location_object
->Program()) {
627 ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info
);
630 if (mCurrentProgram
->Generation() != location_object
->ProgramGeneration()) {
631 ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info
);
638 WebGLContext::ValidateSamplerUniformSetter(const char* info
, WebGLUniformLocation
*location
, GLint value
)
640 if (location
->Info().type
!= SH_SAMPLER_2D
&&
641 location
->Info().type
!= SH_SAMPLER_CUBE
)
646 if (value
>= 0 && value
< mGLMaxTextureUnits
)
649 ErrorInvalidValue("%s: this uniform location is a sampler, but %d is not a valid texture unit",
655 WebGLContext::ValidateAttribArraySetter(const char* name
, uint32_t cnt
, uint32_t arrayLength
)
657 if (IsContextLost()) {
660 if (arrayLength
< cnt
) {
661 ErrorInvalidOperation("%s: array must be >= %d elements", name
, cnt
);
668 WebGLContext::ValidateUniformArraySetter(const char* name
, uint32_t expectedElemSize
, WebGLUniformLocation
*location_object
,
669 GLint
& location
, uint32_t& numElementsToUpload
, uint32_t arrayLength
)
673 if (!ValidateUniformLocation(name
, location_object
))
675 location
= location_object
->Location();
676 uint32_t uniformElemSize
= location_object
->ElementSize();
677 if (expectedElemSize
!= uniformElemSize
) {
678 ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
679 " got a uniform of element size %d", name
,
684 if (arrayLength
== 0 ||
685 arrayLength
% expectedElemSize
)
687 ErrorInvalidValue("%s: expected an array of length a multiple"
688 " of %d, got an array of length %d", name
,
693 const WebGLUniformInfo
& info
= location_object
->Info();
695 arrayLength
!= expectedElemSize
) {
696 ErrorInvalidOperation("%s: expected an array of length exactly"
697 " %d (since this uniform is not an array"
698 " uniform), got an array of length %d", name
,
703 numElementsToUpload
=
704 std::min(info
.arraySize
, arrayLength
/ expectedElemSize
);
709 WebGLContext::ValidateUniformMatrixArraySetter(const char* name
, int dim
, WebGLUniformLocation
*location_object
,
710 GLint
& location
, uint32_t& numElementsToUpload
, uint32_t arrayLength
,
711 WebGLboolean aTranspose
)
713 uint32_t expectedElemSize
= (dim
)*(dim
);
716 if (!ValidateUniformLocation(name
, location_object
))
718 location
= location_object
->Location();
719 uint32_t uniformElemSize
= location_object
->ElementSize();
720 if (expectedElemSize
!= uniformElemSize
) {
721 ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
722 " got a uniform of element size %d", name
,
727 if (arrayLength
== 0 ||
728 arrayLength
% expectedElemSize
)
730 ErrorInvalidValue("%s: expected an array of length a multiple"
731 " of %d, got an array of length %d", name
,
736 const WebGLUniformInfo
& info
= location_object
->Info();
738 arrayLength
!= expectedElemSize
) {
739 ErrorInvalidOperation("%s: expected an array of length exactly"
740 " %d (since this uniform is not an array"
741 " uniform), got an array of length %d", name
,
747 ErrorInvalidValue("%s: transpose must be FALSE as per the "
748 "OpenGL ES 2.0 spec", name
);
751 numElementsToUpload
=
752 std::min(info
.arraySize
, arrayLength
/ (expectedElemSize
));
757 WebGLContext::ValidateUniformSetter(const char* name
, WebGLUniformLocation
*location_object
, GLint
& location
)
761 if (!ValidateUniformLocation(name
, location_object
))
763 location
= location_object
->Location();
767 bool WebGLContext::ValidateAttribIndex(GLuint index
, const char *info
)
769 return mBoundVertexArray
->EnsureAttrib(index
, info
);
772 bool WebGLContext::ValidateStencilParamsForDrawCall()
774 const char *msg
= "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
775 if (mStencilRefFront
!= mStencilRefBack
) {
776 ErrorInvalidOperation(msg
, "stencilFuncSeparate", "reference values");
779 if (mStencilValueMaskFront
!= mStencilValueMaskBack
) {
780 ErrorInvalidOperation(msg
, "stencilFuncSeparate", "value masks");
783 if (mStencilWriteMaskFront
!= mStencilWriteMaskBack
) {
784 ErrorInvalidOperation(msg
, "stencilMaskSeparate", "write masks");
790 static inline int32_t floorPOT(int32_t x
)
794 while (pot
< 0x40000000) {
803 WebGLContext::InitAndValidateGL()
805 if (!gl
) return false;
807 GLenum error
= gl
->fGetError();
808 if (error
!= LOCAL_GL_NO_ERROR
) {
809 GenerateWarning("GL error 0x%x occurred during OpenGL context initialization, before WebGL initialization!", error
);
813 mMinCapability
= Preferences::GetBool("webgl.min_capability_mode", false);
814 mDisableExtensions
= Preferences::GetBool("webgl.disable-extensions", false);
815 mLoseContextOnHeapMinimize
= Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
816 mCanLoseContextInForeground
= Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
818 if (MinCapabilityMode()) {
819 mDisableFragHighP
= true;
823 mWebGLError
= LOCAL_GL_NO_ERROR
;
825 mBound2DTextures
.Clear();
826 mBoundCubeMapTextures
.Clear();
828 mBoundArrayBuffer
= nullptr;
829 mBoundTransformFeedbackBuffer
= nullptr;
830 mCurrentProgram
= nullptr;
832 mBoundFramebuffer
= nullptr;
833 mBoundRenderbuffer
= nullptr;
835 MakeContextCurrent();
837 // on desktop OpenGL, we always keep vertex attrib 0 array enabled
838 if (!gl
->IsGLES2()) {
839 gl
->fEnableVertexAttribArray(0);
842 if (MinCapabilityMode()) {
843 mGLMaxVertexAttribs
= MINVALUE_GL_MAX_VERTEX_ATTRIBS
;
845 gl
->fGetIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS
, &mGLMaxVertexAttribs
);
847 if (mGLMaxVertexAttribs
< 8) {
848 GenerateWarning("GL_MAX_VERTEX_ATTRIBS: %d is < 8!", mGLMaxVertexAttribs
);
852 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
853 // even though the hardware supports much more. The
854 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
855 if (MinCapabilityMode()) {
856 mGLMaxTextureUnits
= MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
;
858 gl
->fGetIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
, &mGLMaxTextureUnits
);
860 if (mGLMaxTextureUnits
< 8) {
861 GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits
);
865 mBound2DTextures
.SetLength(mGLMaxTextureUnits
);
866 mBoundCubeMapTextures
.SetLength(mGLMaxTextureUnits
);
868 if (MinCapabilityMode()) {
869 mGLMaxTextureSize
= MINVALUE_GL_MAX_TEXTURE_SIZE
;
870 mGLMaxCubeMapTextureSize
= MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE
;
871 mGLMaxRenderbufferSize
= MINVALUE_GL_MAX_RENDERBUFFER_SIZE
;
872 mGLMaxTextureImageUnits
= MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS
;
873 mGLMaxVertexTextureImageUnits
= MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
;
875 gl
->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE
, &mGLMaxTextureSize
);
876 gl
->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE
, &mGLMaxCubeMapTextureSize
);
877 gl
->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE
, &mGLMaxRenderbufferSize
);
878 gl
->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS
, &mGLMaxTextureImageUnits
);
879 gl
->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
, &mGLMaxVertexTextureImageUnits
);
882 mGLMaxTextureSize
= floorPOT(mGLMaxTextureSize
);
883 mGLMaxRenderbufferSize
= floorPOT(mGLMaxRenderbufferSize
);
885 if (MinCapabilityMode()) {
886 mGLMaxFragmentUniformVectors
= MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS
;
887 mGLMaxVertexUniformVectors
= MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS
;
888 mGLMaxVaryingVectors
= MINVALUE_GL_MAX_VARYING_VECTORS
;
890 if (gl
->IsSupported(gl::GLFeature::ES2_compatibility
)) {
891 gl
->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS
, &mGLMaxFragmentUniformVectors
);
892 gl
->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS
, &mGLMaxVertexUniformVectors
);
893 gl
->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS
, &mGLMaxVaryingVectors
);
895 gl
->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS
, &mGLMaxFragmentUniformVectors
);
896 mGLMaxFragmentUniformVectors
/= 4;
897 gl
->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS
, &mGLMaxVertexUniformVectors
);
898 mGLMaxVertexUniformVectors
/= 4;
900 // we are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS and GL_MAX_FRAGMENT_INPUT_COMPONENTS,
901 // however these constants only entered the OpenGL standard at OpenGL 3.2. So we will try reading,
902 // and check OpenGL error for INVALID_ENUM.
904 // before we start, we check that no error already occurred, to prevent hiding it in our subsequent error handling
905 error
= gl
->GetAndClearError();
906 if (error
!= LOCAL_GL_NO_ERROR
) {
907 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error
);
911 // On the public_webgl list, "problematic GetParameter pnames" thread, the following formula was given:
912 // mGLMaxVaryingVectors = min (GL_MAX_VERTEX_OUTPUT_COMPONENTS, GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
913 GLint maxVertexOutputComponents
,
914 minFragmentInputComponents
;
915 gl
->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS
, &maxVertexOutputComponents
);
916 gl
->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS
, &minFragmentInputComponents
);
918 error
= gl
->GetAndClearError();
920 case LOCAL_GL_NO_ERROR
:
921 mGLMaxVaryingVectors
= std::min(maxVertexOutputComponents
, minFragmentInputComponents
) / 4;
923 case LOCAL_GL_INVALID_ENUM
:
924 mGLMaxVaryingVectors
= 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
927 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error
);
933 // Always 1 for GLES2
934 mMaxFramebufferColorAttachments
= 1;
936 if (!gl
->IsGLES2()) {
937 // gl_PointSize is always available in ES2 GLSL, but has to be
938 // specifically enabled on desktop GLSL.
939 gl
->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE
);
941 // gl_PointCoord is always available in ES2 GLSL and in newer desktop GLSL versions, but apparently
942 // not in OpenGL 2 and apparently not (due to a driver bug) on certain NVIDIA setups. See:
943 // http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=261472
944 // Note that this used to cause crashes on old ATI drivers... hopefully not a significant
945 // problem anymore. See bug 602183.
946 gl
->fEnable(LOCAL_GL_POINT_SPRITE
);
950 if (gl
->WorkAroundDriverBugs() &&
951 gl
->Vendor() == gl::GLContext::VendorATI
) {
952 // The Mac ATI driver, in all known OSX version up to and including 10.8,
953 // renders points sprites upside-down. Apple bug 11778921
954 gl
->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN
, LOCAL_GL_LOWER_LEFT
);
958 // Check the shader validator pref
959 NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
962 Preferences::GetBool("webgl.shader_validator", mShaderValidation
);
964 // initialize shader translator
965 if (mShaderValidation
) {
966 if (!ShInitialize()) {
967 GenerateWarning("GLSL translator initialization failed!");
972 // Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
973 mIsMesa
= strstr((const char *)(gl
->fGetString(LOCAL_GL_VERSION
)), "Mesa");
975 // notice that the point of calling GetAndClearError here is not only to check for error,
976 // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
977 error
= gl
->GetAndClearError();
978 if (error
!= LOCAL_GL_NO_ERROR
) {
979 GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error
);
986 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
990 mMemoryPressureObserver
991 = new WebGLMemoryPressureObserver(this);
992 nsCOMPtr
<nsIObserverService
> observerService
993 = mozilla::services::GetObserverService();
994 if (observerService
) {
995 observerService
->AddObserver(mMemoryPressureObserver
,
1000 mDefaultVertexArray
= new WebGLVertexArray(this);
1001 mDefaultVertexArray
->mAttribs
.SetLength(mGLMaxVertexAttribs
);
1002 mBoundVertexArray
= mDefaultVertexArray
;