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 // These are the default values, see 6.2 State tables in the
289 // OpenGL ES 2.0.25 spec.
290 mDriverColorMask = mColorWriteMask;
291 mColorClearValue[0] = 0.f;
292 mColorClearValue[1] = 0.f;
293 mColorClearValue[2] = 0.f;
294 mColorClearValue[3] = 0.f;
295 mDepthWriteMask = true;
296 mDepthClearValue = 1.f;
297 mStencilClearValue = 0;
298 mStencilRefFront = 0;
299 mStencilRefBack = 0;
300
301 mLineWidth = 1.0;
302
303 /*
304 // Technically, we should be setting mStencil[...] values to
305 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
306 GLuint stencilBits = 0;
307 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
308 GLuint allOnes = ~(UINT32_MAX << stencilBits);
309 mStencilValueMaskFront = allOnes;
310 mStencilValueMaskBack = allOnes;
311 mStencilWriteMaskFront = allOnes;
312 mStencilWriteMaskBack = allOnes;
313 */
314
315 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
316 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
317 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
318 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
319
320 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,
321 mStencilValueMaskFront);
322 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK,
323 mStencilValueMaskBack);
324 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,
325 mStencilWriteMaskFront);
326 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,
327 mStencilWriteMaskBack);
328
329 mDitherEnabled = true;
330 mRasterizerDiscardEnabled = false;
331 mScissorTestEnabled = false;
332
333 mDepthTestEnabled = 0;
334 mDriverDepthTest = false;
335 mStencilTestEnabled = 0;
336 mDriverStencilTest = false;
337
338 mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
339
340 // Bindings, etc.
341 mActiveTexture = 0;
342 mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
343 mDefaultFB_ReadBuffer = LOCAL_GL_BACK;
344
345 mWebGLError = LOCAL_GL_NO_ERROR;
346
347 mBound2DTextures.Clear();
348 mBoundCubeMapTextures.Clear();
349 mBound3DTextures.Clear();
350 mBound2DArrayTextures.Clear();
351 mBoundSamplers.Clear();
352
353 mBoundArrayBuffer = nullptr;
354 mCurrentProgram = nullptr;
355
356 mBoundDrawFramebuffer = nullptr;
357 mBoundReadFramebuffer = nullptr;
358
359 // -----------------------
360
361 auto limits = MakeLimits(*this);
362
363 // -
364
365 if (limits.maxVertexAttribs < 8) {
366 const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
367 limits.maxVertexAttribs);
368 *out_failReason = {"FEATURE_FAILURE_WEBGL_V_ATRB", reason};
369 return false;
370 }
371
372 if (limits.maxTexUnits < 8) {
373 const nsPrintfCString reason(
374 "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!", limits.maxTexUnits);
375 *out_failReason = {"FEATURE_FAILURE_WEBGL_T_UNIT", reason};
376 return false;
377 }
378
379 mBound2DTextures.SetLength(limits.maxTexUnits);
380 mBoundCubeMapTextures.SetLength(limits.maxTexUnits);
381 mBound3DTextures.SetLength(limits.maxTexUnits);
382 mBound2DArrayTextures.SetLength(limits.maxTexUnits);
383 mBoundSamplers.SetLength(limits.maxTexUnits);
384
385 ////////////////
386
387 gl->GetUIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
388 gl->GetUIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS,
389 &mGLMaxFragmentTextureImageUnits);
390 gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
391 &mGLMaxVertexTextureImageUnits);
392
393 ////////////////
394
395 if (gl->IsGLES()) {
396 mGLMaxFragmentUniformVectors =
397 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
398 mGLMaxVertexUniformVectors =
399 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS);
400 if (gl->Version() >= 300) {
401 mGLMaxVertexOutputVectors =
402 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
403 mGLMaxFragmentInputVectors =
404 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
405 } else {
406 mGLMaxFragmentInputVectors =
407 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_VECTORS);
408 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
409 }
410 } else {
411 mGLMaxFragmentUniformVectors =
412 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS) / 4;
413 mGLMaxVertexUniformVectors =
414 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS) / 4;
415
416 if (gl->Version() >= 320) {
417 mGLMaxVertexOutputVectors =
418 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS) / 4;
419 mGLMaxFragmentInputVectors =
420 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4;
421 } else {
422 // Same enum val as GL2's GL_MAX_VARYING_FLOATS.
423 mGLMaxFragmentInputVectors =
424 gl->GetIntAs<uint32_t>(LOCAL_GL_MAX_VARYING_COMPONENTS) / 4;
425 mGLMaxVertexOutputVectors = mGLMaxFragmentInputVectors;
426 }
427 }
428
429 ////////////////
430
431 if (StaticPrefs::webgl_min_capability_mode()) {
432 bool ok = true;
433
434 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
435 kMinMaxVertexTextureImageUnits);
436 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
437 kMinMaxFragmentTextureImageUnits);
438 ok &= RestrictCap(&limits.maxTexUnits, kMinMaxCombinedTextureImageUnits);
439
440 ok &= RestrictCap(&limits.maxVertexAttribs, kMinMaxVertexAttribs);
441 ok &= RestrictCap(&mGLMaxVertexUniformVectors, kMinMaxVertexUniformVectors);
442 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
443 kMinMaxFragmentUniformVectors);
444 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kMinMaxVaryingVectors);
445 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kMinMaxVaryingVectors);
446
447 ok &= RestrictCap(&limits.maxColorDrawBuffers, kMinMaxDrawBuffers);
448
449 ok &= RestrictCap(&limits.maxTex2dSize, kMinMaxTextureSize);
450 ok &= RestrictCap(&limits.maxTexCubeSize, kMinMaxCubeMapTextureSize);
451 ok &= RestrictCap(&limits.maxTex3dSize, kMinMax3DTextureSize);
452
453 ok &= RestrictCap(&limits.maxTexArrayLayers, kMinMaxArrayTextureLayers);
454 ok &= RestrictCap(&mGLMaxRenderbufferSize, kMinMaxRenderbufferSize);
455
456 if (!ok) {
457 GenerateWarning("Unable to restrict WebGL limits to minimums.");
458 return false;
459 }
460
461 mDisableFragHighP = true;
462 } else if (mResistFingerprinting) {
463 bool ok = true;
464
465 ok &= RestrictCap(&limits.maxTex2dSize, kCommonMaxTextureSize);
466 ok &= RestrictCap(&limits.maxTexCubeSize, kCommonMaxCubeMapTextureSize);
467 ok &= RestrictCap(&mGLMaxRenderbufferSize, kCommonMaxRenderbufferSize);
468
469 ok &= RestrictCap(&mGLMaxVertexTextureImageUnits,
470 kCommonMaxVertexTextureImageUnits);
471 ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits,
472 kCommonMaxFragmentTextureImageUnits);
473 ok &= RestrictCap(&limits.maxTexUnits, kCommonMaxCombinedTextureImageUnits);
474
475 ok &= RestrictCap(&limits.maxVertexAttribs, kCommonMaxVertexAttribs);
476 ok &= RestrictCap(&mGLMaxVertexUniformVectors,
477 kCommonMaxVertexUniformVectors);
478 ok &= RestrictCap(&mGLMaxFragmentUniformVectors,
479 kCommonMaxFragmentUniformVectors);
480 ok &= RestrictCap(&mGLMaxVertexOutputVectors, kCommonMaxVaryingVectors);
481 ok &= RestrictCap(&mGLMaxFragmentInputVectors, kCommonMaxVaryingVectors);
482
483 if (limits.lineWidthRange[0] <= kCommonAliasedLineWidthRangeMin) {
484 limits.lineWidthRange[0] = kCommonAliasedLineWidthRangeMin;
485 } else {
486 ok = false;
487 }
488 if (limits.pointSizeRange[0] <= kCommonAliasedPointSizeRangeMin) {
489 limits.pointSizeRange[0] = kCommonAliasedPointSizeRangeMin;
490 } else {
491 ok = false;
492 }
493
494 ok &=
495 RestrictCap(&limits.lineWidthRange[1], kCommonAliasedLineWidthRangeMax);
496 ok &=
497 RestrictCap(&limits.pointSizeRange[1], kCommonAliasedPointSizeRangeMax);
498 ok &= RestrictCap(&limits.maxViewportDim, kCommonMaxViewportDims);
499
500 if (!ok) {
501 GenerateWarning(
502 "Unable to restrict WebGL limits in order to resist fingerprinting");
503 return false;
504 }
505 }
506
507 mLimits = Some(limits);
508
509 ////////////////
510
511 if (gl->IsCompatibilityProfile()) {
512 gl->fEnable(LOCAL_GL_POINT_SPRITE);
513 }
514
515 if (!gl->IsGLES()) {
516 gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE);
517 }
518
519 #ifdef XP_MACOSX
520 if (gl->WorkAroundDriverBugs() && gl->Vendor() == gl::GLVendor::ATI &&
521 !nsCocoaFeatures::IsAtLeastVersion(10, 9)) {
522 // The Mac ATI driver, in all known OSX version up to and including
523 // 10.8, renders points sprites upside-down. (Apple bug 11778921)
524 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
525 LOCAL_GL_LOWER_LEFT);
526 }
527 #endif
528
529 if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) {
530 gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
531 }
532
533 // initialize shader translator
534 if (!sh::Initialize()) {
535 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLSL",
536 "GLSL translator initialization failed!"};
537 return false;
538 }
539
540 // Mesa can only be detected with the GL_VERSION string, of the form
541 // "2.1 Mesa 7.11.0"
542 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
543 mIsMesa = strstr(versionStr, "Mesa");
544
545 // Notice that the point of calling fGetError here is not only to check for
546 // errors, but also to reset the error flags so that a subsequent WebGL
547 // getError call will give the correct result.
548 error = gl->fGetError();
549 if (error != LOCAL_GL_NO_ERROR) {
550 const nsPrintfCString reason(
551 "GL error 0x%x occurred during WebGL context"
552 " initialization!",
553 error);
554 *out_failReason = {"FEATURE_FAILURE_WEBGL_GLERR_2", reason};
555 return false;
556 }
557
558 if (IsWebGL2() && !InitWebGL2(out_failReason)) {
559 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
560 return false;
561 }
562
563 if (!gl->IsSupported(gl::GLFeature::vertex_array_object)) {
564 *out_failReason = {"FEATURE_FAILURE_WEBGL_VAOS",
565 "Requires vertex_array_object."};
566 return false;
567 }
568
569 // OpenGL core profiles remove the default VAO object from version
570 // 4.0.0. We create a default VAO for all core profiles,
571 // regardless of version.
572 //
573 // GL Spec 4.0.0:
574 // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
575 // in Section E.2.2 "Removed Features", pg 397: "[...] The default
576 // vertex array object (the name zero) is also deprecated. [...]"
577 mDefaultVertexArray = WebGLVertexArray::Create(this);
578 mDefaultVertexArray->BindVertexArray();
579
580 mPrimRestartTypeBytes = 0;
581
582 mGenericVertexAttribTypes.assign(limits.maxVertexAttribs,
583 webgl::AttribBaseType::Float);
584 mGenericVertexAttribTypeInvalidator.InvalidateCaches();
585
586 static const float kDefaultGenericVertexAttribData[4] = {0, 0, 0, 1};
587 memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
588 sizeof(mGenericVertexAttrib0Data));
589
590 mFakeVertexAttrib0BufferObject = 0;
591
592 mNeedsIndexValidation =
593 !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior);
594 switch (StaticPrefs::webgl_force_index_validation()) {
595 case -1:
596 mNeedsIndexValidation = false;
597 break;
598 case 1:
599 mNeedsIndexValidation = true;
600 break;
601 default:
602 MOZ_ASSERT(StaticPrefs::webgl_force_index_validation() == 0);
603 break;
604 }
605
606 for (auto& cur : mExtensions) {
607 cur = {};
608 }
609
610 return true;
611 }
612
ValidateFramebufferTarget(GLenum target) const613 bool WebGLContext::ValidateFramebufferTarget(GLenum target) const {
614 bool isValid = true;
615 switch (target) {
616 case LOCAL_GL_FRAMEBUFFER:
617 break;
618
619 case LOCAL_GL_DRAW_FRAMEBUFFER:
620 case LOCAL_GL_READ_FRAMEBUFFER:
621 isValid = IsWebGL2();
622 break;
623
624 default:
625 isValid = false;
626 break;
627 }
628
629 if (MOZ_LIKELY(isValid)) {
630 return true;
631 }
632
633 ErrorInvalidEnumArg("target", target);
634 return false;
635 }
636
637 } // namespace mozilla
638