Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / canvas / WebGLContextValidate.cpp
blob462f26258b20cee9c3b8a3b4d5bd6ac6bafe7998
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 "GLSLANG/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/StaticPrefs_webgl.h"
16 #include "nsPrintfCString.h"
17 #include "WebGLBuffer.h"
18 #include "WebGLContextUtils.h"
19 #include "WebGLFramebuffer.h"
20 #include "WebGLProgram.h"
21 #include "WebGLRenderbuffer.h"
22 #include "WebGLSampler.h"
23 #include "WebGLShader.h"
24 #include "WebGLTexture.h"
25 #include "WebGLValidateStrings.h"
26 #include "WebGLVertexArray.h"
28 #if defined(MOZ_WIDGET_COCOA)
29 # include "nsCocoaFeatures.h"
30 #endif
32 ////////////////////
33 // Minimum value constants defined in GLES 2.0.25 $6.2 "State Tables":
34 const uint32_t kMinMaxVertexAttribs = 8; // Page 164
35 const uint32_t kMinMaxVertexUniformVectors = 128; // Page 164
36 const uint32_t kMinMaxFragmentUniformVectors = 16; // Page 164
37 const uint32_t kMinMaxVaryingVectors = 8; // Page 164
39 const uint32_t kMinMaxVertexTextureImageUnits = 0; // Page 164
40 const uint32_t kMinMaxFragmentTextureImageUnits = 8; // Page 164
41 const uint32_t kMinMaxCombinedTextureImageUnits = 8; // Page 164
43 const uint32_t kMinMaxDrawBuffers = 4;
45 // These few deviate from the spec: (The minimum values in the spec are
46 // ridiculously low)
47 const uint32_t kMinMaxTextureSize = 1024; // ES2 spec says `64` (p162)
48 const uint32_t kMinMaxCubeMapTextureSize = 512; // ES2 spec says `16` (p162)
49 const uint32_t kMinMaxRenderbufferSize = 1024; // ES2 spec says `1` (p164)
51 // Minimum value constants defined in GLES 3.0.4 $6.2 "State Tables":
52 const uint32_t kMinMax3DTextureSize = 256;
53 const uint32_t kMinMaxArrayTextureLayers = 256;
55 ////////////////////
56 // "Common" but usable values to avoid WebGL fingerprinting:
57 const uint32_t kCommonMaxTextureSize = 2048;
58 const uint32_t kCommonMaxCubeMapTextureSize = 2048;
59 const uint32_t kCommonMaxRenderbufferSize = 2048;
61 const uint32_t kCommonMaxVertexTextureImageUnits = 8;
62 const uint32_t kCommonMaxFragmentTextureImageUnits = 8;
63 const uint32_t kCommonMaxCombinedTextureImageUnits = 16;
65 const uint32_t kCommonMaxVertexAttribs = 16;
66 const uint32_t kCommonMaxVertexUniformVectors = 256;
67 const uint32_t kCommonMaxFragmentUniformVectors = 224;
68 const uint32_t kCommonMaxVaryingVectors = 8;
70 const uint32_t kCommonMaxViewportDims = 4096;
72 // The following ranges came from a 2013 Moto E and an old macbook.
73 const float kCommonAliasedPointSizeRangeMin = 1;
74 const float kCommonAliasedPointSizeRangeMax = 63;
75 const float kCommonAliasedLineWidthRangeMin = 1;
76 const float kCommonAliasedLineWidthRangeMax = 1;
78 template <class T>
79 static bool RestrictCap(T* const cap, const T restrictedVal) {
80 if (*cap < restrictedVal) {
81 return false; // already too low!
84 *cap = restrictedVal;
85 return true;
88 ////////////////////
90 namespace mozilla {
92 bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info) {
93 switch (mode) {
94 case LOCAL_GL_FUNC_ADD:
95 case LOCAL_GL_FUNC_SUBTRACT:
96 case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
97 return true;
99 case LOCAL_GL_MIN:
100 case LOCAL_GL_MAX:
101 if (IsWebGL2() ||
102 IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) {
103 return true;
106 break;
108 default:
109 break;
112 ErrorInvalidEnumInfo(info, mode);
113 return false;
116 bool WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
117 GLenum dfactor,
118 const char* info) {
119 bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
120 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
121 bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
122 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
123 bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
124 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
125 bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
126 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
127 if ((sfactorIsConstantColor && dfactorIsConstantAlpha) ||
128 (dfactorIsConstantColor && sfactorIsConstantAlpha)) {
129 ErrorInvalidOperation(
130 "%s are mutually incompatible, see section 6.8 in"
131 " the WebGL 1.0 spec",
132 info);
133 return false;
136 return true;
139 bool WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info) {
140 switch (action) {
141 case LOCAL_GL_KEEP:
142 case LOCAL_GL_ZERO:
143 case LOCAL_GL_REPLACE:
144 case LOCAL_GL_INCR:
145 case LOCAL_GL_INCR_WRAP:
146 case LOCAL_GL_DECR:
147 case LOCAL_GL_DECR_WRAP:
148 case LOCAL_GL_INVERT:
149 return true;
151 default:
152 ErrorInvalidEnumInfo(info, action);
153 return false;
157 bool WebGLContext::ValidateFaceEnum(const GLenum face) {
158 switch (face) {
159 case LOCAL_GL_FRONT:
160 case LOCAL_GL_BACK:
161 case LOCAL_GL_FRONT_AND_BACK:
162 return true;
164 default:
165 ErrorInvalidEnumInfo("face", face);
166 return false;
170 bool WebGLContext::ValidateAttribArraySetter(uint32_t setterElemSize,
171 uint32_t arrayLength) {
172 if (IsContextLost()) return false;
174 if (arrayLength < setterElemSize) {
175 ErrorInvalidValue("Array must have >= %d elements.", setterElemSize);
176 return false;
179 return true;
182 // ---------------------
184 static webgl::Limits MakeLimits(const WebGLContext& webgl) {
185 webgl::Limits limits;
187 for (const auto i : IntegerRange(UnderlyingValue(WebGLExtensionID::Max))) {
188 const auto ext = WebGLExtensionID(i);
189 limits.supportedExtensions[ext] = webgl.IsExtensionSupported(ext);
192 gl::GLContext& gl = *webgl.GL();
194 // -
195 // WebGL 1
197 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
198 // even though the hardware supports much more. The
199 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
200 gl.GetUIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
201 &limits.maxTexUnits);
203 gl.GetUIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &limits.maxTex2dSize);
204 gl.GetUIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &limits.maxTexCubeSize);
205 gl.GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &limits.maxVertexAttribs);
206 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, limits.maxViewportDims.data());
208 if (!gl.IsCoreProfile()) {
209 gl.fGetFloatv(LOCAL_GL_ALIASED_LINE_WIDTH_RANGE,
210 limits.lineWidthRange.data());
214 const GLenum driverPName = gl.IsCoreProfile()
215 ? LOCAL_GL_POINT_SIZE_RANGE
216 : LOCAL_GL_ALIASED_POINT_SIZE_RANGE;
217 gl.fGetFloatv(driverPName, limits.pointSizeRange.data());
220 if (webgl.IsWebGL2()) {
221 gl.GetUIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
222 &limits.maxTexArrayLayers);
223 gl.GetUIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE, &limits.maxTex3dSize);
224 gl.GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
225 &limits.maxTransformFeedbackSeparateAttribs);
226 gl.GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
227 &limits.maxUniformBufferBindings);
228 gl.GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
229 &limits.uniformBufferOffsetAlignment);
232 if (limits.supportedExtensions
233 [WebGLExtensionID::WEBGL_compressed_texture_astc]) {
234 limits.astcHdr = gl.IsExtensionSupported(
235 gl::GLContext::KHR_texture_compression_astc_hdr);
238 if (webgl.IsWebGL2() ||
239 limits.supportedExtensions[WebGLExtensionID::WEBGL_draw_buffers]) {
240 gl.GetUIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &limits.maxColorDrawBuffers);
243 if (limits.supportedExtensions[WebGLExtensionID::EXT_disjoint_timer_query]) {
244 gl.fGetQueryiv(LOCAL_GL_TIME_ELAPSED_EXT, LOCAL_GL_QUERY_COUNTER_BITS,
245 (int32_t*)&limits.queryCounterBitsTimeElapsed);
246 gl.fGetQueryiv(LOCAL_GL_TIMESTAMP_EXT, LOCAL_GL_QUERY_COUNTER_BITS,
247 (int32_t*)&limits.queryCounterBitsTimestamp);
250 if (limits.supportedExtensions[WebGLExtensionID::OVR_multiview2]) {
251 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWS_OVR, &limits.maxMultiviewLayers);
254 return limits;
257 bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) {
258 MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
260 // Unconditionally create a new format usage authority. This is
261 // important when restoring contexts and extensions need to add
262 // formats back into the authority.
263 mFormatUsage = CreateFormatUsage(gl);
264 if (!mFormatUsage) {
265 *out_failReason = {"FEATURE_FAILURE_WEBGL_FORMAT",
266 "Failed to create mFormatUsage."};
267 return false;
270 GLenum error = gl->fGetError();
271 if (error != LOCAL_GL_NO_ERROR) {
272 const nsPrintfCString reason(
273 "GL error 0x%x occurred during OpenGL context"
274 " initialization, before WebGL initialization!",
275 error);
276 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_1", reason};
277 return false;
280 mLoseContextOnMemoryPressure =
281 StaticPrefs::webgl_lose_context_on_memory_pressure();
282 mCanLoseContextInForeground =
283 StaticPrefs::webgl_can_lose_context_in_foreground();
285 // These are the default values, see 6.2 State tables in the
286 // OpenGL ES 2.0.25 spec.
287 mDriverColorMask = mColorWriteMask;
288 mColorClearValue[0] = 0.f;
289 mColorClearValue[1] = 0.f;
290 mColorClearValue[2] = 0.f;
291 mColorClearValue[3] = 0.f;
292 mDepthWriteMask = true;
293 mDepthClearValue = 1.f;
294 mStencilClearValue = 0;
295 mStencilRefFront = 0;
296 mStencilRefBack = 0;
298 mLineWidth = 1.0;
301 // Technically, we should be setting mStencil[...] values to
302 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
303 GLuint stencilBits = 0;
304 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
305 GLuint allOnes = ~(UINT32_MAX << stencilBits);
306 mStencilValueMaskFront = allOnes;
307 mStencilValueMaskBack = allOnes;
308 mStencilWriteMaskFront = allOnes;
309 mStencilWriteMaskBack = allOnes;
312 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
313 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
314 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
315 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
317 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,
318 mStencilValueMaskFront);
319 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK,
320 mStencilValueMaskBack);
321 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,
322 mStencilWriteMaskFront);
323 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,
324 mStencilWriteMaskBack);
326 mDitherEnabled = true;
327 mRasterizerDiscardEnabled = false;
328 mScissorTestEnabled = false;
330 mDepthTestEnabled = 0;
331 mDriverDepthTest = false;
332 mStencilTestEnabled = 0;
333 mDriverStencilTest = false;
335 mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
337 // Bindings, etc.
338 mActiveTexture = 0;
339 mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
340 mDefaultFB_ReadBuffer = LOCAL_GL_BACK;
342 mWebGLError = LOCAL_GL_NO_ERROR;
344 mBound2DTextures.Clear();
345 mBoundCubeMapTextures.Clear();
346 mBound3DTextures.Clear();
347 mBound2DArrayTextures.Clear();
348 mBoundSamplers.Clear();
350 mBoundArrayBuffer = nullptr;
351 mCurrentProgram = nullptr;
353 mBoundDrawFramebuffer = nullptr;
354 mBoundReadFramebuffer = nullptr;
356 // -----------------------
358 auto limits = MakeLimits(*this);
360 // -
362 if (limits.maxVertexAttribs < 8) {
363 const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
364 limits.maxVertexAttribs);
365 *out_failReason = {"FEATURE_FAILURE_WEBGL_V_ATRB", reason};
366 return false;
369 if (limits.maxTexUnits < 8) {
370 const nsPrintfCString reason(
371 "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!", limits.maxTexUnits);
372 *out_failReason = {"FEATURE_FAILURE_WEBGL_T_UNIT", reason};
373 return false;
376 mBound2DTextures.SetLength(limits.maxTexUnits);
377 mBoundCubeMapTextures.SetLength(limits.maxTexUnits);
378 mBound3DTextures.SetLength(limits.maxTexUnits);
379 mBound2DArrayTextures.SetLength(limits.maxTexUnits);
380 mBoundSamplers.SetLength(limits.maxTexUnits);
382 ////////////////
384 gl->GetUIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
385 gl->GetUIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS,
386 &mGLMaxFragmentTextureImageUnits);
387 gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
388 &mGLMaxVertexTextureImageUnits);
390 ////////////////
392 if (gl->IsGLES()) {
393 mGLMaxFragmentUniformVectors =
394 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
395 mGLMaxVertexUniformVectors =
396 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS);
397 if (gl->Version() >= 300) {
398 mGLMaxVertexOutputVectors =
399 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
400 mGLMaxFragmentInputVectors =
401 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
402 } else {
403 mGLMaxFragmentInputVectors =
404 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_VECTORS);
405 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
407 } else {
408 mGLMaxFragmentUniformVectors =
409 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4;
410 mGLMaxVertexUniformVectors =
411 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4;
413 if (gl->Version() >= 320) {
414 mGLMaxVertexOutputVectors =
415 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
416 mGLMaxFragmentInputVectors =
417 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
418 } else {
419 // Same enum val as GL2's GL_MAX_VARYING_FLOATS.
420 mGLMaxFragmentInputVectors =
421 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_COMPONENTS) / 4;
422 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
426 ////////////////
428 if (StaticPrefs::webgl_min_capability_mode()) {
429 bool ok = true;
431 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
432 kMinMaxVertexTextureImageUnits);
433 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
434 kMinMaxFragmentTextureImageUnits);
435 ok &= RestrictCap(&limits.maxTexUnits, kMinMaxCombinedTextureImageUnits);
437 ok &= RestrictCap(&limits.maxVertexAttribs, kMinMaxVertexAttribs);
438 ok &= RestrictCap(&mGLMaxVertexUniformVectors, kMinMaxVertexUniformVectors);
439 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
440 kMinMaxFragmentUniformVectors);
441 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kMinMaxVaryingVectors);
442 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kMinMaxVaryingVectors);
444 ok &= RestrictCap(&limits.maxColorDrawBuffers, kMinMaxDrawBuffers);
446 ok &= RestrictCap(&limits.maxTex2dSize, kMinMaxTextureSize);
447 ok &= RestrictCap(&limits.maxTexCubeSize, kMinMaxCubeMapTextureSize);
448 ok &= RestrictCap(&limits.maxTex3dSize, kMinMax3DTextureSize);
450 ok &= RestrictCap(&limits.maxTexArrayLayers, kMinMaxArrayTextureLayers);
451 ok &= RestrictCap(&mGLMaxRenderbufferSize, kMinMaxRenderbufferSize);
453 if (!ok) {
454 GenerateWarning("Unable to restrict WebGL limits to minimums.");
455 return false;
458 mDisableFragHighP = true;
459 } else if (mResistFingerprinting) {
460 bool ok = true;
462 ok &= RestrictCap(&limits.maxTex2dSize, kCommonMaxTextureSize);
463 ok &= RestrictCap(&limits.maxTexCubeSize, kCommonMaxCubeMapTextureSize);
464 ok &= RestrictCap(&mGLMaxRenderbufferSize, kCommonMaxRenderbufferSize);
466 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
467 kCommonMaxVertexTextureImageUnits);
468 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
469 kCommonMaxFragmentTextureImageUnits);
470 ok &= RestrictCap(&limits.maxTexUnits, kCommonMaxCombinedTextureImageUnits);
472 ok &= RestrictCap(&limits.maxVertexAttribs, kCommonMaxVertexAttribs);
473 ok &= RestrictCap(&mGLMaxVertexUniformVectors,
474 kCommonMaxVertexUniformVectors);
475 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
476 kCommonMaxFragmentUniformVectors);
477 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kCommonMaxVaryingVectors);
478 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kCommonMaxVaryingVectors);
480 if (limits.lineWidthRange[0] <= kCommonAliasedLineWidthRangeMin) {
481 limits.lineWidthRange[0] = kCommonAliasedLineWidthRangeMin;
482 } else {
483 ok = false;
485 if (limits.pointSizeRange[0] <= kCommonAliasedPointSizeRangeMin) {
486 limits.pointSizeRange[0] = kCommonAliasedPointSizeRangeMin;
487 } else {
488 ok = false;
491 ok &=
492 RestrictCap(&limits.lineWidthRange[1], kCommonAliasedLineWidthRangeMax);
493 ok &=
494 RestrictCap(&limits.pointSizeRange[1], kCommonAliasedPointSizeRangeMax);
495 ok &= RestrictCap(&limits.maxViewportDims[0], kCommonMaxViewportDims);
496 ok &= RestrictCap(&limits.maxViewportDims[1], kCommonMaxViewportDims);
498 if (!ok) {
499 GenerateWarning(
500 "Unable to restrict WebGL limits in order to resist fingerprinting");
501 return false;
505 mLimits = Some(limits);
507 ////////////////
509 if (gl->IsCompatibilityProfile()) {
510 gl->fEnable(LOCAL_GL_POINT_SPRITE);
513 if (!gl->IsGLES()) {
514 gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE);
517 #ifdef XP_MACOSX
518 if (gl->WorkAroundDriverBugs() && gl->Vendor() == gl::GLVendor::ATI &&
519 !nsCocoaFeatures::IsAtLeastVersion(10, 9)) {
520 // The Mac ATI driver, in all known OSX version up to and including
521 // 10.8, renders points sprites upside-down. (Apple bug 11778921)
522 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
523 LOCAL_GL_LOWER_LEFT);
525 #endif
527 if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) {
528 gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
531 // initialize shader translator
532 if (!sh::Initialize()) {
533 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLSL",
534 "GLSL translator initialization failed!"};
535 return false;
538 // Mesa can only be detected with the GL_VERSION string, of the form
539 // "2.1 Mesa 7.11.0"
540 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
541 mIsMesa = strstr(versionStr, "Mesa");
543 // Notice that the point of calling fGetError here is not only to check for
544 // errors, but also to reset the error flags so that a subsequent WebGL
545 // getError call will give the correct result.
546 error = gl->fGetError();
547 if (error != LOCAL_GL_NO_ERROR) {
548 const nsPrintfCString reason(
549 "GL error 0x%x occurred during WebGL context"
550 " initialization!",
551 error);
552 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_2", reason};
553 return false;
556 if (IsWebGL2() && !InitWebGL2(out_failReason)) {
557 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
558 return false;
561 if (!gl->IsSupported(gl::GLFeature::vertex_array_object)) {
562 *out_failReason = {"FEATURE_FAILURE_WEBGL_VAOS",
563 "Requires vertex_array_object."};
564 return false;
567 // OpenGL core profiles remove the default VAO object from version
568 // 4.0.0. We create a default VAO for all core profiles,
569 // regardless of version.
571 // GL Spec 4.0.0:
572 // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
573 // in Section E.2.2 "Removed Features", pg 397: "[...] The default
574 // vertex array object (the name zero) is also deprecated. [...]"
575 mDefaultVertexArray = WebGLVertexArray::Create(this);
576 mDefaultVertexArray->BindVertexArray();
578 mPrimRestartTypeBytes = 0;
580 mGenericVertexAttribTypes.assign(limits.maxVertexAttribs,
581 webgl::AttribBaseType::Float);
582 mGenericVertexAttribTypeInvalidator.InvalidateCaches();
584 static const float kDefaultGenericVertexAttribData[4] = {0, 0, 0, 1};
585 memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
586 sizeof(mGenericVertexAttrib0Data));
588 mFakeVertexAttrib0BufferObject = 0;
590 mNeedsIndexValidation =
591 !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior);
592 switch (StaticPrefs::webgl_force_index_validation()) {
593 case -1:
594 mNeedsIndexValidation = false;
595 break;
596 case 1:
597 mNeedsIndexValidation = true;
598 break;
599 default:
600 MOZ_ASSERT(StaticPrefs::webgl_force_index_validation() == 0);
601 break;
604 for (auto& cur : mExtensions) {
605 cur = {};
608 return true;
611 bool WebGLContext::ValidateFramebufferTarget(GLenum target) const {
612 bool isValid = true;
613 switch (target) {
614 case LOCAL_GL_FRAMEBUFFER:
615 break;
617 case LOCAL_GL_DRAW_FRAMEBUFFER:
618 case LOCAL_GL_READ_FRAMEBUFFER:
619 isValid = IsWebGL2();
620 break;
622 default:
623 isValid = false;
624 break;
627 if (MOZ_LIKELY(isValid)) {
628 return true;
631 ErrorInvalidEnumArg("target", target);
632 return false;
635 } // namespace mozilla