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/. */
5
6 #include "WebGLContext.h"
7
8 #include <algorithm>
9 #include "angle/ShaderLang.h"
10 #include "CanvasUtils.h"
11 #include "gfxPrefs.h"
12 #include "GLContext.h"
13 #include "jsfriendapi.h"
14 #include "mozilla/CheckedInt.h"
15 #include "mozilla/Preferences.h"
16 #include "mozilla/Services.h"
17 #include "nsIObserverService.h"
18 #include "nsPrintfCString.h"
19 #include "WebGLActiveInfo.h"
20 #include "WebGLBuffer.h"
21 #include "WebGLContextUtils.h"
22 #include "WebGLFramebuffer.h"
23 #include "WebGLProgram.h"
24 #include "WebGLRenderbuffer.h"
25 #include "WebGLSampler.h"
26 #include "WebGLShader.h"
27 #include "WebGLTexture.h"
28 #include "WebGLUniformLocation.h"
29 #include "WebGLValidateStrings.h"
30 #include "WebGLVertexArray.h"
31 #include "WebGLVertexAttribData.h"
32
33 #if defined(MOZ_WIDGET_COCOA)
34 #include "nsCocoaFeatures.h"
35 #endif
36
37 namespace mozilla {
38
39 bool
ValidateBlendEquationEnum(GLenum mode,const char * info)40 WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info)
41 {
42 switch (mode) {
43 case LOCAL_GL_FUNC_ADD:
44 case LOCAL_GL_FUNC_SUBTRACT:
45 case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
46 return true;
47
48 case LOCAL_GL_MIN:
49 case LOCAL_GL_MAX:
50 if (IsWebGL2() ||
51 IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax))
52 {
53 return true;
54 }
55
56 break;
57
58 default:
59 break;
60 }
61
62 ErrorInvalidEnumInfo(info, mode);
63 return false;
64 }
65
66 bool
ValidateBlendFuncDstEnum(GLenum factor,const char * info)67 WebGLContext::ValidateBlendFuncDstEnum(GLenum factor, const char* info)
68 {
69 switch (factor) {
70 case LOCAL_GL_ZERO:
71 case LOCAL_GL_ONE:
72 case LOCAL_GL_SRC_COLOR:
73 case LOCAL_GL_ONE_MINUS_SRC_COLOR:
74 case LOCAL_GL_DST_COLOR:
75 case LOCAL_GL_ONE_MINUS_DST_COLOR:
76 case LOCAL_GL_SRC_ALPHA:
77 case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
78 case LOCAL_GL_DST_ALPHA:
79 case LOCAL_GL_ONE_MINUS_DST_ALPHA:
80 case LOCAL_GL_CONSTANT_COLOR:
81 case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
82 case LOCAL_GL_CONSTANT_ALPHA:
83 case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
84 return true;
85
86 default:
87 ErrorInvalidEnumInfo(info, factor);
88 return false;
89 }
90 }
91
92 bool
ValidateBlendFuncSrcEnum(GLenum factor,const char * info)93 WebGLContext::ValidateBlendFuncSrcEnum(GLenum factor, const char* info)
94 {
95 if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
96 return true;
97
98 return ValidateBlendFuncDstEnum(factor, info);
99 }
100
101 bool
ValidateBlendFuncEnumsCompatibility(GLenum sfactor,GLenum dfactor,const char * info)102 WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
103 GLenum dfactor,
104 const char* info)
105 {
106 bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
107 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
108 bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
109 sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
110 bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
111 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
112 bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
113 dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
114 if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
115 (dfactorIsConstantColor && sfactorIsConstantAlpha) )
116 {
117 ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in"
118 " the WebGL 1.0 spec", info);
119 return false;
120 }
121
122 return true;
123 }
124
125 bool
ValidateComparisonEnum(GLenum target,const char * info)126 WebGLContext::ValidateComparisonEnum(GLenum target, const char* info)
127 {
128 switch (target) {
129 case LOCAL_GL_NEVER:
130 case LOCAL_GL_LESS:
131 case LOCAL_GL_LEQUAL:
132 case LOCAL_GL_GREATER:
133 case LOCAL_GL_GEQUAL:
134 case LOCAL_GL_EQUAL:
135 case LOCAL_GL_NOTEQUAL:
136 case LOCAL_GL_ALWAYS:
137 return true;
138
139 default:
140 ErrorInvalidEnumInfo(info, target);
141 return false;
142 }
143 }
144
145 bool
ValidateStencilOpEnum(GLenum action,const char * info)146 WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info)
147 {
148 switch (action) {
149 case LOCAL_GL_KEEP:
150 case LOCAL_GL_ZERO:
151 case LOCAL_GL_REPLACE:
152 case LOCAL_GL_INCR:
153 case LOCAL_GL_INCR_WRAP:
154 case LOCAL_GL_DECR:
155 case LOCAL_GL_DECR_WRAP:
156 case LOCAL_GL_INVERT:
157 return true;
158
159 default:
160 ErrorInvalidEnumInfo(info, action);
161 return false;
162 }
163 }
164
165 bool
ValidateFaceEnum(GLenum face,const char * info)166 WebGLContext::ValidateFaceEnum(GLenum face, const char* info)
167 {
168 switch (face) {
169 case LOCAL_GL_FRONT:
170 case LOCAL_GL_BACK:
171 case LOCAL_GL_FRONT_AND_BACK:
172 return true;
173
174 default:
175 ErrorInvalidEnumInfo(info, face);
176 return false;
177 }
178 }
179
180 bool
ValidateDrawModeEnum(GLenum mode,const char * info)181 WebGLContext::ValidateDrawModeEnum(GLenum mode, const char* info)
182 {
183 switch (mode) {
184 case LOCAL_GL_TRIANGLES:
185 case LOCAL_GL_TRIANGLE_STRIP:
186 case LOCAL_GL_TRIANGLE_FAN:
187 case LOCAL_GL_POINTS:
188 case LOCAL_GL_LINE_STRIP:
189 case LOCAL_GL_LINE_LOOP:
190 case LOCAL_GL_LINES:
191 return true;
192
193 default:
194 ErrorInvalidEnumInfo(info, mode);
195 return false;
196 }
197 }
198
199 bool
ValidateUniformLocation(WebGLUniformLocation * loc,const char * funcName)200 WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
201 {
202 /* GLES 2.0.25, p38:
203 * If the value of location is -1, the Uniform* commands will silently
204 * ignore the data passed in, and the current uniform values will not be
205 * changed.
206 */
207 if (!loc)
208 return false;
209
210 if (!ValidateObjectAllowDeleted(funcName, *loc))
211 return false;
212
213 if (!mCurrentProgram) {
214 ErrorInvalidOperation("%s: No program is currently bound.", funcName);
215 return false;
216 }
217
218 return loc->ValidateForProgram(mCurrentProgram, funcName);
219 }
220
221 bool
ValidateAttribArraySetter(const char * name,uint32_t setterElemSize,uint32_t arrayLength)222 WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSize,
223 uint32_t arrayLength)
224 {
225 if (IsContextLost())
226 return false;
227
228 if (arrayLength < setterElemSize) {
229 ErrorInvalidValue("%s: Array must have >= %d elements.", name,
230 setterElemSize);
231 return false;
232 }
233
234 return true;
235 }
236
237 bool
ValidateUniformSetter(WebGLUniformLocation * loc,uint8_t setterElemSize,GLenum setterType,const char * funcName)238 WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
239 uint8_t setterElemSize, GLenum setterType,
240 const char* funcName)
241 {
242 if (IsContextLost())
243 return false;
244
245 if (!ValidateUniformLocation(loc, funcName))
246 return false;
247
248 if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
249 return false;
250
251 return true;
252 }
253
254 bool
ValidateUniformArraySetter(WebGLUniformLocation * loc,uint8_t setterElemSize,GLenum setterType,uint32_t setterArraySize,const char * funcName,uint32_t * const out_numElementsToUpload)255 WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
256 uint8_t setterElemSize,
257 GLenum setterType,
258 uint32_t setterArraySize,
259 const char* funcName,
260 uint32_t* const out_numElementsToUpload)
261 {
262 if (IsContextLost())
263 return false;
264
265 if (!ValidateUniformLocation(loc, funcName))
266 return false;
267
268 if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
269 return false;
270
271 if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
272 return false;
273
274 const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
275 MOZ_ASSERT(elemCount > loc->mArrayIndex);
276 const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
277
278 *out_numElementsToUpload = std::min(uniformElemCount,
279 setterArraySize / setterElemSize);
280 return true;
281 }
282
283 bool
ValidateUniformMatrixArraySetter(WebGLUniformLocation * loc,uint8_t setterCols,uint8_t setterRows,GLenum setterType,uint32_t setterArraySize,bool setterTranspose,const char * funcName,uint32_t * const out_numElementsToUpload)284 WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
285 uint8_t setterCols,
286 uint8_t setterRows,
287 GLenum setterType,
288 uint32_t setterArraySize,
289 bool setterTranspose,
290 const char* funcName,
291 uint32_t* const out_numElementsToUpload)
292 {
293 const uint8_t setterElemSize = setterCols * setterRows;
294
295 if (IsContextLost())
296 return false;
297
298 if (!ValidateUniformLocation(loc, funcName))
299 return false;
300
301 if (!loc->ValidateSizeAndType(setterElemSize, setterType, funcName))
302 return false;
303
304 if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, funcName))
305 return false;
306
307 if (!ValidateUniformMatrixTranspose(setterTranspose, funcName))
308 return false;
309
310 const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
311 MOZ_ASSERT(elemCount > loc->mArrayIndex);
312 const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
313
314 *out_numElementsToUpload = std::min(uniformElemCount,
315 setterArraySize / setterElemSize);
316 return true;
317 }
318
319 bool
ValidateAttribIndex(GLuint index,const char * info)320 WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
321 {
322 bool valid = (index < MaxVertexAttribs());
323
324 if (!valid) {
325 if (index == GLuint(-1)) {
326 ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
327 " probably comes from a getAttribLocation()"
328 " call, where this return value -1 means"
329 " that the passed name didn't correspond to"
330 " an active attribute in the specified"
331 " program.", info);
332 } else {
333 ErrorInvalidValue("%s: `index` must be less than"
334 " MAX_VERTEX_ATTRIBS.", info);
335 }
336 }
337
338 return valid;
339 }
340
341 bool
ValidateAttribPointer(bool integerMode,GLuint index,GLint size,GLenum type,WebGLboolean normalized,GLsizei stride,WebGLintptr byteOffset,const char * info)342 WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
343 WebGLboolean normalized, GLsizei stride,
344 WebGLintptr byteOffset, const char* info)
345 {
346 WebGLBuffer* buffer = mBoundArrayBuffer;
347 if (!buffer) {
348 ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info);
349 return false;
350 }
351
352 uint32_t requiredAlignment = 0;
353 if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info))
354 return false;
355
356 // requiredAlignment should always be a power of two
357 MOZ_ASSERT(IsPowerOfTwo(requiredAlignment));
358 GLsizei requiredAlignmentMask = requiredAlignment - 1;
359
360 if (size < 1 || size > 4) {
361 ErrorInvalidValue("%s: invalid element size", info);
362 return false;
363 }
364
365 switch (type) {
366 case LOCAL_GL_INT_2_10_10_10_REV:
367 case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
368 if (size != 4) {
369 ErrorInvalidOperation("%s: size must be 4 for this type.", info);
370 return false;
371 }
372 break;
373 }
374
375 // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
376 if (stride < 0 || stride > 255) {
377 ErrorInvalidValue("%s: negative or too large stride", info);
378 return false;
379 }
380
381 if (byteOffset < 0) {
382 ErrorInvalidValue("%s: negative offset", info);
383 return false;
384 }
385
386 if (stride & requiredAlignmentMask) {
387 ErrorInvalidOperation("%s: stride doesn't satisfy the alignment "
388 "requirement of given type", info);
389 return false;
390 }
391
392 if (byteOffset & requiredAlignmentMask) {
393 ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment "
394 "requirement of given type", info);
395 return false;
396 }
397
398 return true;
399 }
400
401 bool
ValidateStencilParamsForDrawCall()402 WebGLContext::ValidateStencilParamsForDrawCall()
403 {
404 const char msg[] = "%s set different front and back stencil %s. Drawing in"
405 " this configuration is not allowed.";
406
407 if (mStencilRefFront != mStencilRefBack) {
408 ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
409 return false;
410 }
411
412 if (mStencilValueMaskFront != mStencilValueMaskBack) {
413 ErrorInvalidOperation(msg, "stencilFuncSeparate", "value masks");
414 return false;
415 }
416
417 if (mStencilWriteMaskFront != mStencilWriteMaskBack) {
418 ErrorInvalidOperation(msg, "stencilMaskSeparate", "write masks");
419 return false;
420 }
421
422 return true;
423 }
424
425 static inline int32_t
FloorPOT(int32_t x)426 FloorPOT(int32_t x)
427 {
428 MOZ_ASSERT(x > 0);
429 int32_t pot = 1;
430 while (pot < 0x40000000) {
431 if (x < pot*2)
432 break;
433 pot *= 2;
434 }
435 return pot;
436 }
437
438 bool
InitAndValidateGL(FailureReason * const out_failReason)439 WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
440 {
441 MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
442
443 // Unconditionally create a new format usage authority. This is
444 // important when restoring contexts and extensions need to add
445 // formats back into the authority.
446 mFormatUsage = CreateFormatUsage(gl);
447 if (!mFormatUsage) {
448 *out_failReason = { "FEATURE_FAILURE_WEBGL_FORMAT",
449 "Failed to create mFormatUsage." };
450 return false;
451 }
452
453 GLenum error = gl->fGetError();
454 if (error != LOCAL_GL_NO_ERROR) {
455 const nsPrintfCString reason("GL error 0x%x occurred during OpenGL context"
456 " initialization, before WebGL initialization!",
457 error);
458 *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_1", reason };
459 return false;
460 }
461
462 mMinCapability = gfxPrefs::WebGLMinCapabilityMode();
463 mDisableExtensions = gfxPrefs::WebGLDisableExtensions();
464 mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure();
465 mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground();
466 mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible();
467
468 if (MinCapabilityMode())
469 mDisableFragHighP = true;
470
471 // These are the default values, see 6.2 State tables in the
472 // OpenGL ES 2.0.25 spec.
473 mColorWriteMask[0] = 1;
474 mColorWriteMask[1] = 1;
475 mColorWriteMask[2] = 1;
476 mColorWriteMask[3] = 1;
477 mDepthWriteMask = 1;
478 mColorClearValue[0] = 0.f;
479 mColorClearValue[1] = 0.f;
480 mColorClearValue[2] = 0.f;
481 mColorClearValue[3] = 0.f;
482 mDepthClearValue = 1.f;
483 mStencilClearValue = 0;
484 mStencilRefFront = 0;
485 mStencilRefBack = 0;
486
487 mLineWidth = 1.0;
488
489 /*
490 // Technically, we should be setting mStencil[...] values to
491 // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
492 GLuint stencilBits = 0;
493 gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
494 GLuint allOnes = ~(UINT32_MAX << stencilBits);
495 mStencilValueMaskFront = allOnes;
496 mStencilValueMaskBack = allOnes;
497 mStencilWriteMaskFront = allOnes;
498 mStencilWriteMaskBack = allOnes;
499 */
500
501 gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK, &mStencilValueMaskFront);
502 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
503 gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK, &mStencilWriteMaskFront);
504 gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK, &mStencilWriteMaskBack);
505
506 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, mStencilValueMaskFront);
507 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
508 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, mStencilWriteMaskFront);
509 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
510
511 mDitherEnabled = true;
512 mRasterizerDiscardEnabled = false;
513 mScissorTestEnabled = false;
514 mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
515
516 // Bindings, etc.
517 mActiveTexture = 0;
518 mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
519
520 mEmitContextLostErrorOnce = true;
521 mWebGLError = LOCAL_GL_NO_ERROR;
522 mUnderlyingGLError = LOCAL_GL_NO_ERROR;
523
524 mBound2DTextures.Clear();
525 mBoundCubeMapTextures.Clear();
526 mBound3DTextures.Clear();
527 mBound2DArrayTextures.Clear();
528 mBoundSamplers.Clear();
529
530 mBoundArrayBuffer = nullptr;
531 mCurrentProgram = nullptr;
532
533 mBoundDrawFramebuffer = nullptr;
534 mBoundReadFramebuffer = nullptr;
535 mBoundRenderbuffer = nullptr;
536
537 MakeContextCurrent();
538
539 if (MinCapabilityMode())
540 mGLMaxVertexAttribs = MINVALUE_GL_MAX_VERTEX_ATTRIBS;
541 else
542 gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
543
544 if (mGLMaxVertexAttribs < 8) {
545 const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
546 mGLMaxVertexAttribs);
547 *out_failReason = { "FEATURE_FAILURE_WEBGL_V_ATRB", reason };
548 return false;
549 }
550
551 // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
552 // even though the hardware supports much more. The
553 // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
554 if (MinCapabilityMode())
555 mGLMaxTextureUnits = MINVALUE_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS;
556 else
557 mGLMaxTextureUnits = gl->GetIntAs<GLint>(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
558
559 if (mGLMaxTextureUnits < 8) {
560 const nsPrintfCString reason("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!",
561 mGLMaxTextureUnits);
562 *out_failReason = { "FEATURE_FAILURE_WEBGL_T_UNIT", reason };
563 return false;
564 }
565
566 mBound2DTextures.SetLength(mGLMaxTextureUnits);
567 mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
568 mBound3DTextures.SetLength(mGLMaxTextureUnits);
569 mBound2DArrayTextures.SetLength(mGLMaxTextureUnits);
570 mBoundSamplers.SetLength(mGLMaxTextureUnits);
571
572 gl->fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, (GLint*)mImplMaxViewportDims);
573
574 ////////////////
575
576 if (MinCapabilityMode()) {
577 mImplMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
578 mImplMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
579 mImplMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
580
581 mImplMax3DTextureSize = MINVALUE_GL_MAX_3D_TEXTURE_SIZE;
582 mImplMaxArrayTextureLayers = MINVALUE_GL_MAX_ARRAY_TEXTURE_LAYERS;
583
584 mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
585 mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
586 } else {
587 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mImplMaxTextureSize);
588 gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mImplMaxCubeMapTextureSize);
589 gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, (GLint*)&mImplMaxRenderbufferSize);
590
591 if (!gl->GetPotentialInteger(LOCAL_GL_MAX_3D_TEXTURE_SIZE, (GLint*)&mImplMax3DTextureSize))
592 mImplMax3DTextureSize = 0;
593 if (!gl->GetPotentialInteger(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, (GLint*)&mImplMaxArrayTextureLayers))
594 mImplMaxArrayTextureLayers = 0;
595
596 gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
597 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
598 }
599
600 // If we don't support a target, its max size is 0. We should only floor-to-POT if the
601 // value if it's non-zero. (NB log2(0) is -Inf, so zero isn't an integer power-of-two)
602 const auto fnFloorPOTIfSupported = [](uint32_t& val) {
603 if (val) {
604 val = FloorPOT(val);
605 }
606 };
607
608 fnFloorPOTIfSupported(mImplMaxTextureSize);
609 fnFloorPOTIfSupported(mImplMaxCubeMapTextureSize);
610 fnFloorPOTIfSupported(mImplMaxRenderbufferSize);
611
612 fnFloorPOTIfSupported(mImplMax3DTextureSize);
613 fnFloorPOTIfSupported(mImplMaxArrayTextureLayers);
614
615 ////////////////
616
617 mGLMaxColorAttachments = 1;
618 mGLMaxDrawBuffers = 1;
619 gl->GetPotentialInteger(LOCAL_GL_MAX_COLOR_ATTACHMENTS,
620 (GLint*)&mGLMaxColorAttachments);
621 gl->GetPotentialInteger(LOCAL_GL_MAX_DRAW_BUFFERS, (GLint*)&mGLMaxDrawBuffers);
622
623 if (MinCapabilityMode()) {
624 mGLMaxColorAttachments = std::min(mGLMaxColorAttachments,
625 kMinMaxColorAttachments);
626 mGLMaxDrawBuffers = std::min(mGLMaxDrawBuffers, kMinMaxDrawBuffers);
627 }
628
629 if (IsWebGL2()) {
630 mImplMaxColorAttachments = mGLMaxColorAttachments;
631 mImplMaxDrawBuffers = std::min(mGLMaxDrawBuffers, mImplMaxColorAttachments);
632 } else {
633 mImplMaxColorAttachments = 1;
634 mImplMaxDrawBuffers = 1;
635 }
636
637 ////////////////
638
639 if (MinCapabilityMode()) {
640 mGLMaxFragmentUniformVectors = MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS;
641 mGLMaxVertexUniformVectors = MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS;
642 mGLMaxVaryingVectors = MINVALUE_GL_MAX_VARYING_VECTORS;
643 } else {
644 if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
645 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
646 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
647 gl->fGetIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
648 } else {
649 gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
650 mGLMaxFragmentUniformVectors /= 4;
651 gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
652 mGLMaxVertexUniformVectors /= 4;
653
654 /* We are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS
655 * and GL_MAX_FRAGMENT_INPUT_COMPONENTS, however these constants
656 * only entered the OpenGL standard at OpenGL 3.2. So we will try
657 * reading, and check OpenGL error for INVALID_ENUM.
658 *
659 * On the public_webgl list, "problematic GetParameter pnames"
660 * thread, the following formula was given:
661 * maxVaryingVectors = min(GL_MAX_VERTEX_OUTPUT_COMPONENTS,
662 * GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
663 */
664 GLint maxVertexOutputComponents = 0;
665 GLint maxFragmentInputComponents = 0;
666
667 const bool ok = (gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS,
668 &maxVertexOutputComponents) &&
669 gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS,
670 &maxFragmentInputComponents));
671
672 if (ok) {
673 mGLMaxVaryingVectors = std::min(maxVertexOutputComponents,
674 maxFragmentInputComponents) / 4;
675 } else {
676 mGLMaxVaryingVectors = 16;
677 // 16 = 64/4, and 64 is the min value for
678 // maxVertexOutputComponents in the OpenGL 3.2 spec.
679 }
680 }
681 }
682
683 if (gl->IsCompatibilityProfile()) {
684 gl->fEnable(LOCAL_GL_POINT_SPRITE);
685 }
686
687 if (!gl->IsGLES()) {
688 gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE);
689 }
690
691 #ifdef XP_MACOSX
692 if (gl->WorkAroundDriverBugs() &&
693 gl->Vendor() == gl::GLVendor::ATI &&
694 !nsCocoaFeatures::IsAtLeastVersion(10,9))
695 {
696 // The Mac ATI driver, in all known OSX version up to and including
697 // 10.8, renders points sprites upside-down. (Apple bug 11778921)
698 gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
699 LOCAL_GL_LOWER_LEFT);
700 }
701 #endif
702
703 if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) {
704 gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
705 }
706
707 // Check the shader validator pref
708 mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator();
709
710 // initialize shader translator
711 if (!ShInitialize()) {
712 *out_failReason = { "FEATURE_FAILURE_WEBGL_GLSL",
713 "GLSL translator initialization failed!" };
714 return false;
715 }
716
717 // Mesa can only be detected with the GL_VERSION string, of the form
718 // "2.1 Mesa 7.11.0"
719 const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
720 mIsMesa = strstr(versionStr, "Mesa");
721
722 // Notice that the point of calling fGetError here is not only to check for
723 // errors, but also to reset the error flags so that a subsequent WebGL
724 // getError call will give the correct result.
725 error = gl->fGetError();
726 if (error != LOCAL_GL_NO_ERROR) {
727 const nsPrintfCString reason("GL error 0x%x occurred during WebGL context"
728 " initialization!",
729 error);
730 *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_2", reason };
731 return false;
732 }
733
734 if (IsWebGL2() &&
735 !InitWebGL2(out_failReason))
736 {
737 // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
738 return false;
739 }
740
741 mDefaultVertexArray = WebGLVertexArray::Create(this);
742 mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
743 mBoundVertexArray = mDefaultVertexArray;
744
745 // OpenGL core profiles remove the default VAO object from version
746 // 4.0.0. We create a default VAO for all core profiles,
747 // regardless of version.
748 //
749 // GL Spec 4.0.0:
750 // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
751 // in Section E.2.2 "Removed Features", pg 397: "[...] The default
752 // vertex array object (the name zero) is also deprecated. [...]"
753
754 if (gl->IsCoreProfile()) {
755 mDefaultVertexArray->GenVertexArray();
756 mDefaultVertexArray->BindVertexArray();
757 }
758
759 mPixelStore_FlipY = false;
760 mPixelStore_PremultiplyAlpha = false;
761 mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL;
762
763 // GLES 3.0.4, p259:
764 mPixelStore_UnpackImageHeight = 0;
765 mPixelStore_UnpackSkipImages = 0;
766 mPixelStore_UnpackRowLength = 0;
767 mPixelStore_UnpackSkipRows = 0;
768 mPixelStore_UnpackSkipPixels = 0;
769 mPixelStore_UnpackAlignment = 4;
770 mPixelStore_PackRowLength = 0;
771 mPixelStore_PackSkipRows = 0;
772 mPixelStore_PackSkipPixels = 0;
773 mPixelStore_PackAlignment = 4;
774
775 mPrimRestartTypeBytes = 0;
776
777 mGenericVertexAttribTypes.reset(new GLenum[mGLMaxVertexAttribs]);
778 std::fill_n(mGenericVertexAttribTypes.get(), mGLMaxVertexAttribs, LOCAL_GL_FLOAT);
779
780 static const float kDefaultGenericVertexAttribData[4] = { 0, 0, 0, 1 };
781 memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
782 sizeof(mGenericVertexAttrib0Data));
783
784 mFakeVertexAttrib0BufferObject = 0;
785
786 return true;
787 }
788
789 bool
ValidateFramebufferTarget(GLenum target,const char * const info)790 WebGLContext::ValidateFramebufferTarget(GLenum target,
791 const char* const info)
792 {
793 bool isValid = true;
794 switch (target) {
795 case LOCAL_GL_FRAMEBUFFER:
796 break;
797
798 case LOCAL_GL_DRAW_FRAMEBUFFER:
799 case LOCAL_GL_READ_FRAMEBUFFER:
800 isValid = IsWebGL2();
801 break;
802
803 default:
804 isValid = false;
805 break;
806 }
807
808 if (MOZ_LIKELY(isValid)) {
809 return true;
810 }
811
812 ErrorInvalidEnumArg(info, "target", target);
813 return false;
814 }
815
816 } // namespace mozilla
817