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