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/. */
5
6 #include "WebGLContext.h"
7
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"
27
28 #if defined(MOZ_WIDGET_COCOA)
29 # include "nsCocoaFeatures.h"
30 #endif
31
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
38
39 const uint32_t kMinMaxVertexTextureImageUnits = 0; // Page 164
40 const uint32_t kMinMaxFragmentTextureImageUnits = 8; // Page 164
41 const uint32_t kMinMaxCombinedTextureImageUnits = 8; // Page 164
42
43 const uint32_t kMinMaxDrawBuffers = 4;
44
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)
50
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;
54
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;
60
61 const uint32_t kCommonMaxVertexTextureImageUnits = 8;
62 const uint32_t kCommonMaxFragmentTextureImageUnits = 8;
63 const uint32_t kCommonMaxCombinedTextureImageUnits = 16;
64
65 const uint32_t kCommonMaxVertexAttribs = 16;
66 const uint32_t kCommonMaxVertexUniformVectors = 256;
67 const uint32_t kCommonMaxFragmentUniformVectors = 224;
68 const uint32_t kCommonMaxVaryingVectors = 8;
69
70 const uint32_t kCommonMaxViewportDims = 4096;
71
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;
77
78 template <class T>
RestrictCap(T * const cap,const T restrictedVal)79 static bool RestrictCap(T* const cap, const T restrictedVal) {
80 if (*cap < restrictedVal) {
81 return false; // already too low!
82 }
83
84 *cap = restrictedVal;
85 return true;
86 }
87
88 ////////////////////
89
90 namespace mozilla {
91
ValidateBlendEquationEnum(GLenum mode,const char * info)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;
98
99 case LOCAL_GL_MIN:
100 case LOCAL_GL_MAX:
101 if (IsWebGL2() ||
102 IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) {
103 return true;
104 }
105
106 break;
107
108 default:
109 break;
110 }
111
112 ErrorInvalidEnumInfo(info, mode);
113 return false;
114 }
115
ValidateBlendFuncEnumsCompatibility(GLenum sfactor,GLenum dfactor,const char * info)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;
134 }
135
136 return true;
137 }
138
ValidateStencilOpEnum(GLenum action,const char * info)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;
150
151 default:
152 ErrorInvalidEnumInfo(info, action);
153 return false;
154 }
155 }
156
ValidateFaceEnum(const GLenum face)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;
163
164 default:
165 ErrorInvalidEnumInfo("face", face);
166 return false;
167 }
168 }
169
ValidateAttribArraySetter(uint32_t setterElemSize,uint32_t arrayLength)170 bool WebGLContext::ValidateAttribArraySetter(uint32_t setterElemSize,
171 uint32_t arrayLength) {
172 if (IsContextLost()) return false;
173
174 if (arrayLength < setterElemSize) {
175 ErrorInvalidValue("Array must have >= %d elements.", setterElemSize);
176 return false;
177 }
178
179 return true;
180 }
181
182 // ---------------------
183
MakeLimits(const WebGLContext & webgl)184 static webgl::Limits MakeLimits(const WebGLContext& webgl) {
185 webgl::Limits limits;
186
187 gl::GLContext& gl = *webgl.GL();
188
189 // -
190
191 for (const auto i : IntegerRange(UnderlyingValue(WebGLExtensionID::Max))) {
192 const auto ext = WebGLExtensionID(i);
193 limits.supportedExtensions[ext] = webgl.IsExtensionSupported(ext);
194 }
195
196 // -
197 // WebGL 1
198
199 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
200 // even though the hardware supports much more. The
201 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
202 gl.GetUIntegerv(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
203 &limits.maxTexUnits);
204
205 gl.GetUIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &limits.maxTex2dSize);
206 gl.GetUIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &limits.maxTexCubeSize);
207 gl.GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &limits.maxVertexAttribs);
208
209 auto dims = std::array<uint32_t, 2>{};
210 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, dims.data());
211 limits.maxViewportDim = std::min(dims[0], dims[1]);
212
213 if (!gl.IsCoreProfile()) {
214 gl.fGetFloatv(LOCAL_GL_ALIASED_LINE_WIDTH_RANGE,
215 limits.lineWidthRange.data());
216 }
217
218 {
219 const GLenum driverPName = gl.IsCoreProfile()
220 ? LOCAL_GL_POINT_SIZE_RANGE
221 : LOCAL_GL_ALIASED_POINT_SIZE_RANGE;
222 gl.fGetFloatv(driverPName, limits.pointSizeRange.data());
223 }
224
225 if (webgl.IsWebGL2()) {
226 gl.GetUIntegerv(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS,
227 &limits.maxTexArrayLayers);
228 gl.GetUIntegerv(LOCAL_GL_MAX_3D_TEXTURE_SIZE, &limits.maxTex3dSize);
229 gl.GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
230 &limits.maxUniformBufferBindings);
231 gl.GetUIntegerv(LOCAL_GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
232 &limits.uniformBufferOffsetAlignment);
233 }
234
235 if (limits.supportedExtensions
236 [WebGLExtensionID::WEBGL_compressed_texture_astc]) {
237 limits.astcHdr = gl.IsExtensionSupported(
238 gl::GLContext::KHR_texture_compression_astc_hdr);
239 }
240
241 if (webgl.IsWebGL2() ||
242 limits.supportedExtensions[WebGLExtensionID::WEBGL_draw_buffers]) {
243 gl.GetUIntegerv(LOCAL_GL_MAX_DRAW_BUFFERS, &limits.maxColorDrawBuffers);
244 }
245
246 if (limits.supportedExtensions[WebGLExtensionID::EXT_disjoint_timer_query]) {
247 gl.fGetQueryiv(LOCAL_GL_TIME_ELAPSED_EXT, LOCAL_GL_QUERY_COUNTER_BITS,
248 (int32_t*)&limits.queryCounterBitsTimeElapsed);
249 gl.fGetQueryiv(LOCAL_GL_TIMESTAMP_EXT, LOCAL_GL_QUERY_COUNTER_BITS,
250 (int32_t*)&limits.queryCounterBitsTimestamp);
251 }
252
253 if (limits.supportedExtensions[WebGLExtensionID::OVR_multiview2]) {
254 gl.GetUIntegerv(LOCAL_GL_MAX_VIEWS_OVR, &limits.maxMultiviewLayers);
255 }
256
257 return limits;
258 }
259
InitAndValidateGL(FailureReason * const out_failReason)260 bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) {
261 MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
262
263 // Unconditionally create a new format usage authority. This is
264 // important when restoring contexts and extensions need to add
265 // formats back into the authority.
266 mFormatUsage = CreateFormatUsage(gl);
267 if (!mFormatUsage) {
268 *out_failReason = {"FEATURE_FAILURE_WEBGL_FORMAT",
269 "Failed to create mFormatUsage."};
270 return false;
271 }
272
273 GLenum error = gl->fGetError();
274 if (error != LOCAL_GL_NO_ERROR) {
275 const nsPrintfCString reason(
276 "GL error 0x%x occurred during OpenGL context"
277 " initialization, before WebGL initialization!",
278 error);
279 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_1", reason};
280 return false;
281 }
282
283 mLoseContextOnMemoryPressure =
284 StaticPrefs::webgl_lose_context_on_memory_pressure();
285 mCanLoseContextInForeground =
286 StaticPrefs::webgl_can_lose_context_in_foreground();
287
288 /*
289 // Technically, we should be setting mStencil[...] values to
290 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
291 GLuint stencilBits = 0;
292 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
293 GLuint allOnes = ~(UINT32_MAX << stencilBits);
294 mStencilValueMaskFront = allOnes;
295 mStencilValueMaskBack = allOnes;
296 mStencilWriteMaskFront = allOnes;
297 mStencilWriteMaskBack = allOnes;
298 */
299
300 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
301 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
302 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
303 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
304
305 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,
306 mStencilValueMaskFront);
307 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK,
308 mStencilValueMaskBack);
309 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,
310 mStencilWriteMaskFront);
311 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,
312 mStencilWriteMaskBack);
313
314 // Bindings, etc.
315
316 mBound2DTextures.Clear();
317 mBoundCubeMapTextures.Clear();
318 mBound3DTextures.Clear();
319 mBound2DArrayTextures.Clear();
320 mBoundSamplers.Clear();
321
322 mBoundArrayBuffer = nullptr;
323 mCurrentProgram = nullptr;
324
325 mBoundDrawFramebuffer = nullptr;
326 mBoundReadFramebuffer = nullptr;
327
328 // -----------------------
329
330 auto limits = MakeLimits(*this);
331
332 // -
333
334 if (limits.maxVertexAttribs < 8) {
335 const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
336 limits.maxVertexAttribs);
337 *out_failReason = {"FEATURE_FAILURE_WEBGL_V_ATRB", reason};
338 return false;
339 }
340
341 if (limits.maxTexUnits < 8) {
342 const nsPrintfCString reason(
343 "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!", limits.maxTexUnits);
344 *out_failReason = {"FEATURE_FAILURE_WEBGL_T_UNIT", reason};
345 return false;
346 }
347
348 mBound2DTextures.SetLength(limits.maxTexUnits);
349 mBoundCubeMapTextures.SetLength(limits.maxTexUnits);
350 mBound3DTextures.SetLength(limits.maxTexUnits);
351 mBound2DArrayTextures.SetLength(limits.maxTexUnits);
352 mBoundSamplers.SetLength(limits.maxTexUnits);
353
354 ////////////////
355
356 gl->GetUIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
357 gl->GetUIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS,
358 &mGLMaxFragmentTextureImageUnits);
359 gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
360 &mGLMaxVertexTextureImageUnits);
361
362 ////////////////
363
364 if (gl->IsGLES()) {
365 mGLMaxFragmentUniformVectors =
366 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
367 mGLMaxVertexUniformVectors =
368 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS);
369 if (gl->Version() >= 300) {
370 mGLMaxVertexOutputVectors =
371 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
372 mGLMaxFragmentInputVectors =
373 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
374 } else {
375 mGLMaxFragmentInputVectors =
376 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_VECTORS);
377 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
378 }
379 } else {
380 mGLMaxFragmentUniformVectors =
381 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4;
382 mGLMaxVertexUniformVectors =
383 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4;
384
385 if (gl->Version() >= 320) {
386 mGLMaxVertexOutputVectors =
387 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
388 mGLMaxFragmentInputVectors =
389 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
390 } else {
391 // Same enum val as GL2's GL_MAX_VARYING_FLOATS.
392 mGLMaxFragmentInputVectors =
393 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_COMPONENTS) / 4;
394 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
395 }
396 }
397
398 ////////////////
399
400 if (StaticPrefs::webgl_min_capability_mode()) {
401 bool ok = true;
402
403 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
404 kMinMaxVertexTextureImageUnits);
405 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
406 kMinMaxFragmentTextureImageUnits);
407 ok &= RestrictCap(&limits.maxTexUnits, kMinMaxCombinedTextureImageUnits);
408
409 ok &= RestrictCap(&limits.maxVertexAttribs, kMinMaxVertexAttribs);
410 ok &= RestrictCap(&mGLMaxVertexUniformVectors, kMinMaxVertexUniformVectors);
411 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
412 kMinMaxFragmentUniformVectors);
413 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kMinMaxVaryingVectors);
414 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kMinMaxVaryingVectors);
415
416 ok &= RestrictCap(&limits.maxColorDrawBuffers, kMinMaxDrawBuffers);
417
418 ok &= RestrictCap(&limits.maxTex2dSize, kMinMaxTextureSize);
419 ok &= RestrictCap(&limits.maxTexCubeSize, kMinMaxCubeMapTextureSize);
420 ok &= RestrictCap(&limits.maxTex3dSize, kMinMax3DTextureSize);
421
422 ok &= RestrictCap(&limits.maxTexArrayLayers, kMinMaxArrayTextureLayers);
423 ok &= RestrictCap(&mGLMaxRenderbufferSize, kMinMaxRenderbufferSize);
424
425 if (!ok) {
426 GenerateWarning("Unable to restrict WebGL limits to minimums.");
427 return false;
428 }
429
430 mDisableFragHighP = true;
431 } else if (mResistFingerprinting) {
432 bool ok = true;
433
434 ok &= RestrictCap(&limits.maxTex2dSize, kCommonMaxTextureSize);
435 ok &= RestrictCap(&limits.maxTexCubeSize, kCommonMaxCubeMapTextureSize);
436 ok &= RestrictCap(&mGLMaxRenderbufferSize, kCommonMaxRenderbufferSize);
437
438 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
439 kCommonMaxVertexTextureImageUnits);
440 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
441 kCommonMaxFragmentTextureImageUnits);
442 ok &= RestrictCap(&limits.maxTexUnits, kCommonMaxCombinedTextureImageUnits);
443
444 ok &= RestrictCap(&limits.maxVertexAttribs, kCommonMaxVertexAttribs);
445 ok &= RestrictCap(&mGLMaxVertexUniformVectors,
446 kCommonMaxVertexUniformVectors);
447 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
448 kCommonMaxFragmentUniformVectors);
449 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kCommonMaxVaryingVectors);
450 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kCommonMaxVaryingVectors);
451
452 if (limits.lineWidthRange[0] <= kCommonAliasedLineWidthRangeMin) {
453 limits.lineWidthRange[0] = kCommonAliasedLineWidthRangeMin;
454 } else {
455 ok = false;
456 }
457 if (limits.pointSizeRange[0] <= kCommonAliasedPointSizeRangeMin) {
458 limits.pointSizeRange[0] = kCommonAliasedPointSizeRangeMin;
459 } else {
460 ok = false;
461 }
462
463 ok &=
464 RestrictCap(&limits.lineWidthRange[1], kCommonAliasedLineWidthRangeMax);
465 ok &=
466 RestrictCap(&limits.pointSizeRange[1], kCommonAliasedPointSizeRangeMax);
467 ok &= RestrictCap(&limits.maxViewportDim, kCommonMaxViewportDims);
468
469 if (!ok) {
470 GenerateWarning(
471 "Unable to restrict WebGL limits in order to resist fingerprinting");
472 return false;
473 }
474 }
475
476 mLimits = Some(limits);
477
478 ////////////////
479
480 if (gl->IsCompatibilityProfile()) {
481 gl->fEnable(LOCAL_GL_POINT_SPRITE);
482 }
483
484 if (!gl->IsGLES()) {
485 gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE);
486 }
487
488 #ifdef XP_MACOSX
489 if (gl->WorkAroundDriverBugs() && gl->Vendor() == gl::GLVendor::ATI &&
490 !nsCocoaFeatures::IsAtLeastVersion(10, 9)) {
491 // The Mac ATI driver, in all known OSX version up to and including
492 // 10.8, renders points sprites upside-down. (Apple bug 11778921)
493 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
494 LOCAL_GL_LOWER_LEFT);
495 }
496 #endif
497
498 if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) {
499 gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
500 }
501
502 // initialize shader translator
503 if (!sh::Initialize()) {
504 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLSL",
505 "GLSL translator initialization failed!"};
506 return false;
507 }
508
509 // Mesa can only be detected with the GL_VERSION string, of the form
510 // "2.1 Mesa 7.11.0"
511 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
512 mIsMesa = strstr(versionStr, "Mesa");
513
514 // Notice that the point of calling fGetError here is not only to check for
515 // errors, but also to reset the error flags so that a subsequent WebGL
516 // getError call will give the correct result.
517 error = gl->fGetError();
518 if (error != LOCAL_GL_NO_ERROR) {
519 const nsPrintfCString reason(
520 "GL error 0x%x occurred during WebGL context"
521 " initialization!",
522 error);
523 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_2", reason};
524 return false;
525 }
526
527 if (IsWebGL2() && !InitWebGL2(out_failReason)) {
528 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
529 return false;
530 }
531
532 if (!gl->IsSupported(gl::GLFeature::vertex_array_object)) {
533 *out_failReason = {"FEATURE_FAILURE_WEBGL_VAOS",
534 "Requires vertex_array_object."};
535 return false;
536 }
537
538 // OpenGL core profiles remove the default VAO object from version
539 // 4.0.0. We create a default VAO for all core profiles,
540 // regardless of version.
541 //
542 // GL Spec 4.0.0:
543 // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
544 // in Section E.2.2 "Removed Features", pg 397: "[...] The default
545 // vertex array object (the name zero) is also deprecated. [...]"
546 mDefaultVertexArray = WebGLVertexArray::Create(this);
547 mDefaultVertexArray->BindVertexArray();
548
549 mPrimRestartTypeBytes = 0;
550
551 mGenericVertexAttribTypes.assign(limits.maxVertexAttribs,
552 webgl::AttribBaseType::Float);
553 mGenericVertexAttribTypeInvalidator.InvalidateCaches();
554
555 static const float kDefaultGenericVertexAttribData[4] = {0, 0, 0, 1};
556 memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
557 sizeof(mGenericVertexAttrib0Data));
558
559 mFakeVertexAttrib0BufferObject = 0;
560
561 mNeedsIndexValidation =
562 !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior);
563 switch (StaticPrefs::webgl_force_index_validation()) {
564 case -1:
565 mNeedsIndexValidation = false;
566 break;
567 case 1:
568 mNeedsIndexValidation = true;
569 break;
570 default:
571 MOZ_ASSERT(StaticPrefs::webgl_force_index_validation() == 0);
572 break;
573 }
574
575 for (auto& cur : mExtensions) {
576 cur = {};
577 }
578
579 return true;
580 }
581
ValidateFramebufferTarget(GLenum target) const582 bool WebGLContext::ValidateFramebufferTarget(GLenum target) const {
583 bool isValid = true;
584 switch (target) {
585 case LOCAL_GL_FRAMEBUFFER:
586 break;
587
588 case LOCAL_GL_DRAW_FRAMEBUFFER:
589 case LOCAL_GL_READ_FRAMEBUFFER:
590 isValid = IsWebGL2();
591 break;
592
593 default:
594 isValid = false;
595 break;
596 }
597
598 if (MOZ_LIKELY(isValid)) {
599 return true;
600 }
601
602 ErrorInvalidEnumArg("target", target);
603 return false;
604 }
605
606 } // namespace mozilla
607