Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLContextValidate.cpp
Line
Count
Source (jump to first uncovered line)
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 "GLSLANG/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
////////////////////
38
// Minimum value constants defined in GLES 2.0.25 $6.2 "State Tables":
39
const uint32_t kMinMaxVertexAttribs          =   8; // Page 164
40
const uint32_t kMinMaxVertexUniformVectors   = 128; // Page 164
41
const uint32_t kMinMaxFragmentUniformVectors =  16; // Page 164
42
const uint32_t kMinMaxVaryingVectors         =   8; // Page 164
43
44
const uint32_t kMinMaxVertexTextureImageUnits   = 0; // Page 164
45
const uint32_t kMinMaxFragmentTextureImageUnits = 8; // Page 164
46
const uint32_t kMinMaxCombinedTextureImageUnits = 8; // Page 164
47
48
const uint32_t kMinMaxColorAttachments = 4;
49
const uint32_t kMinMaxDrawBuffers      = 4;
50
51
// These few deviate from the spec: (The minimum values in the spec are ridiculously low)
52
const uint32_t kMinMaxTextureSize        = 1024; // ES2 spec says `64` (p162)
53
const uint32_t kMinMaxCubeMapTextureSize =  512; // ES2 spec says `16` (p162)
54
const uint32_t kMinMaxRenderbufferSize   = 1024; // ES2 spec says `1` (p164)
55
56
// Minimum value constants defined in GLES 3.0.4 $6.2 "State Tables":
57
const uint32_t kMinMax3DTextureSize      = 256;
58
const uint32_t kMinMaxArrayTextureLayers = 256;
59
60
////////////////////
61
// "Common" but usable values to avoid WebGL fingerprinting:
62
const uint32_t kCommonMaxTextureSize        = 2048;
63
const uint32_t kCommonMaxCubeMapTextureSize = 2048;
64
const uint32_t kCommonMaxRenderbufferSize   = 2048;
65
66
const uint32_t kCommonMaxVertexTextureImageUnits   =  8;
67
const uint32_t kCommonMaxFragmentTextureImageUnits =  8;
68
const uint32_t kCommonMaxCombinedTextureImageUnits = 16;
69
70
const uint32_t kCommonMaxVertexAttribs          =  16;
71
const uint32_t kCommonMaxVertexUniformVectors   = 256;
72
const uint32_t kCommonMaxFragmentUniformVectors = 224;
73
const uint32_t kCommonMaxVaryingVectors         =   8;
74
75
const uint32_t kCommonMaxViewportDims = 4096;
76
77
// The following ranges came from a 2013 Moto E and an old macbook.
78
const float kCommonAliasedPointSizeRangeMin =  1;
79
const float kCommonAliasedPointSizeRangeMax = 63;
80
const float kCommonAliasedLineWidthRangeMin =  1;
81
const float kCommonAliasedLineWidthRangeMax =  1;
82
83
template<class T>
84
static bool
85
RestrictCap(T* const cap, const T restrictedVal)
86
0
{
87
0
    if (*cap < restrictedVal) {
88
0
        return false; // already too low!
89
0
    }
90
0
91
0
    *cap = restrictedVal;
92
0
    return true;
93
0
}
Unexecuted instantiation: Unified_cpp_dom_canvas2.cpp:bool RestrictCap<unsigned int>(unsigned int*, unsigned int)
Unexecuted instantiation: Unified_cpp_dom_canvas2.cpp:bool RestrictCap<float>(float*, float)
94
95
////////////////////
96
97
namespace mozilla {
98
99
bool
100
WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info)
101
0
{
102
0
    switch (mode) {
103
0
    case LOCAL_GL_FUNC_ADD:
104
0
    case LOCAL_GL_FUNC_SUBTRACT:
105
0
    case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
106
0
        return true;
107
0
108
0
    case LOCAL_GL_MIN:
109
0
    case LOCAL_GL_MAX:
110
0
        if (IsWebGL2() ||
111
0
            IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax))
112
0
        {
113
0
            return true;
114
0
        }
115
0
116
0
        break;
117
0
118
0
    default:
119
0
        break;
120
0
    }
121
0
122
0
    ErrorInvalidEnumInfo(info, mode);
123
0
    return false;
124
0
}
125
126
bool
127
WebGLContext::ValidateBlendFuncEnumsCompatibility(GLenum sfactor,
128
                                                  GLenum dfactor,
129
                                                  const char* info)
130
0
{
131
0
    bool sfactorIsConstantColor = sfactor == LOCAL_GL_CONSTANT_COLOR ||
132
0
                                  sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
133
0
    bool sfactorIsConstantAlpha = sfactor == LOCAL_GL_CONSTANT_ALPHA ||
134
0
                                  sfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
135
0
    bool dfactorIsConstantColor = dfactor == LOCAL_GL_CONSTANT_COLOR ||
136
0
                                  dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_COLOR;
137
0
    bool dfactorIsConstantAlpha = dfactor == LOCAL_GL_CONSTANT_ALPHA ||
138
0
                                  dfactor == LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA;
139
0
    if ( (sfactorIsConstantColor && dfactorIsConstantAlpha) ||
140
0
         (dfactorIsConstantColor && sfactorIsConstantAlpha) )
141
0
    {
142
0
        ErrorInvalidOperation("%s are mutually incompatible, see section 6.8 in"
143
0
                              " the WebGL 1.0 spec", info);
144
0
        return false;
145
0
    }
146
0
147
0
    return true;
148
0
}
149
150
bool
151
WebGLContext::ValidateStencilOpEnum(GLenum action, const char* info)
152
0
{
153
0
    switch (action) {
154
0
    case LOCAL_GL_KEEP:
155
0
    case LOCAL_GL_ZERO:
156
0
    case LOCAL_GL_REPLACE:
157
0
    case LOCAL_GL_INCR:
158
0
    case LOCAL_GL_INCR_WRAP:
159
0
    case LOCAL_GL_DECR:
160
0
    case LOCAL_GL_DECR_WRAP:
161
0
    case LOCAL_GL_INVERT:
162
0
        return true;
163
0
164
0
    default:
165
0
        ErrorInvalidEnumInfo(info, action);
166
0
        return false;
167
0
    }
168
0
}
169
170
bool
171
WebGLContext::ValidateFaceEnum(const GLenum face)
172
0
{
173
0
    switch (face) {
174
0
    case LOCAL_GL_FRONT:
175
0
    case LOCAL_GL_BACK:
176
0
    case LOCAL_GL_FRONT_AND_BACK:
177
0
        return true;
178
0
179
0
    default:
180
0
        ErrorInvalidEnumInfo("face", face);
181
0
        return false;
182
0
    }
183
0
}
184
185
bool
186
WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc)
187
0
{
188
0
    /* GLES 2.0.25, p38:
189
0
     *   If the value of location is -1, the Uniform* commands will silently
190
0
     *   ignore the data passed in, and the current uniform values will not be
191
0
     *   changed.
192
0
     */
193
0
    if (!loc)
194
0
        return false;
195
0
196
0
    if (!ValidateObjectAllowDeleted("loc", *loc))
197
0
        return false;
198
0
199
0
    if (!mCurrentProgram) {
200
0
        ErrorInvalidOperation("No program is currently bound.");
201
0
        return false;
202
0
    }
203
0
204
0
    return loc->ValidateForProgram(mCurrentProgram);
205
0
}
206
207
bool
208
WebGLContext::ValidateAttribArraySetter(uint32_t setterElemSize, uint32_t arrayLength)
209
0
{
210
0
    if (IsContextLost())
211
0
        return false;
212
0
213
0
    if (arrayLength < setterElemSize) {
214
0
        ErrorInvalidValue("Array must have >= %d elements.", setterElemSize);
215
0
        return false;
216
0
    }
217
0
218
0
    return true;
219
0
}
220
221
bool
222
WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
223
                                    uint8_t setterElemSize, GLenum setterType)
224
0
{
225
0
    if (IsContextLost())
226
0
        return false;
227
0
228
0
    if (!ValidateUniformLocation(loc))
229
0
        return false;
230
0
231
0
    if (!loc->ValidateSizeAndType(setterElemSize, setterType))
232
0
        return false;
233
0
234
0
    return true;
235
0
}
236
237
bool
238
WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
239
                                         uint8_t setterElemSize,
240
                                         GLenum setterType,
241
                                         uint32_t setterArraySize,
242
                                         uint32_t* const out_numElementsToUpload)
243
0
{
244
0
    if (IsContextLost())
245
0
        return false;
246
0
247
0
    if (!ValidateUniformLocation(loc))
248
0
        return false;
249
0
250
0
    if (!loc->ValidateSizeAndType(setterElemSize, setterType))
251
0
        return false;
252
0
253
0
    if (!loc->ValidateArrayLength(setterElemSize, setterArraySize))
254
0
        return false;
255
0
256
0
    const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
257
0
    MOZ_ASSERT(elemCount > loc->mArrayIndex);
258
0
    const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
259
0
260
0
    *out_numElementsToUpload = std::min(uniformElemCount,
261
0
                                        setterArraySize / setterElemSize);
262
0
    return true;
263
0
}
264
265
bool
266
WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
267
                                               uint8_t setterCols,
268
                                               uint8_t setterRows,
269
                                               GLenum setterType,
270
                                               uint32_t setterArraySize,
271
                                               bool setterTranspose,
272
                                               uint32_t* const out_numElementsToUpload)
273
0
{
274
0
    const uint8_t setterElemSize = setterCols * setterRows;
275
0
276
0
    if (IsContextLost())
277
0
        return false;
278
0
279
0
    if (!ValidateUniformLocation(loc))
280
0
        return false;
281
0
282
0
    if (!loc->ValidateSizeAndType(setterElemSize, setterType))
283
0
        return false;
284
0
285
0
    if (!loc->ValidateArrayLength(setterElemSize, setterArraySize))
286
0
        return false;
287
0
288
0
    if (setterTranspose && !IsWebGL2()) {
289
0
        ErrorInvalidValue("`transpose` must be false.");
290
0
        return false;
291
0
    }
292
0
293
0
    const auto& elemCount = loc->mInfo->mActiveInfo->mElemCount;
294
0
    MOZ_ASSERT(elemCount > loc->mArrayIndex);
295
0
    const uint32_t uniformElemCount = elemCount - loc->mArrayIndex;
296
0
297
0
    *out_numElementsToUpload = std::min(uniformElemCount,
298
0
                                        setterArraySize / setterElemSize);
299
0
    return true;
300
0
}
301
302
bool
303
WebGLContext::InitAndValidateGL(FailureReason* const out_failReason)
304
0
{
305
0
    MOZ_RELEASE_ASSERT(gl, "GFX: GL not initialized");
306
0
307
0
    // Unconditionally create a new format usage authority. This is
308
0
    // important when restoring contexts and extensions need to add
309
0
    // formats back into the authority.
310
0
    mFormatUsage = CreateFormatUsage(gl);
311
0
    if (!mFormatUsage) {
312
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_FORMAT",
313
0
                            "Failed to create mFormatUsage." };
314
0
        return false;
315
0
    }
316
0
317
0
    GLenum error = gl->fGetError();
318
0
    if (error != LOCAL_GL_NO_ERROR) {
319
0
        const nsPrintfCString reason("GL error 0x%x occurred during OpenGL context"
320
0
                                     " initialization, before WebGL initialization!",
321
0
                                     error);
322
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_1", reason };
323
0
        return false;
324
0
    }
325
0
326
0
    mDisableExtensions = gfxPrefs::WebGLDisableExtensions();
327
0
    mLoseContextOnMemoryPressure = gfxPrefs::WebGLLoseContextOnMemoryPressure();
328
0
    mCanLoseContextInForeground = gfxPrefs::WebGLCanLoseContextInForeground();
329
0
    mRestoreWhenVisible = gfxPrefs::WebGLRestoreWhenVisible();
330
0
331
0
    // These are the default values, see 6.2 State tables in the
332
0
    // OpenGL ES 2.0.25 spec.
333
0
    mColorWriteMask = 0x0f;
334
0
    mDriverColorMask = mColorWriteMask;
335
0
    mColorClearValue[0] = 0.f;
336
0
    mColorClearValue[1] = 0.f;
337
0
    mColorClearValue[2] = 0.f;
338
0
    mColorClearValue[3] = 0.f;
339
0
    mDepthWriteMask = true;
340
0
    mDepthClearValue = 1.f;
341
0
    mStencilClearValue = 0;
342
0
    mStencilRefFront = 0;
343
0
    mStencilRefBack = 0;
344
0
345
0
    mLineWidth = 1.0;
346
0
347
0
    /*
348
0
    // Technically, we should be setting mStencil[...] values to
349
0
    // `allOnes`, but either ANGLE breaks or the SGX540s on Try break.
350
0
    GLuint stencilBits = 0;
351
0
    gl->GetUIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
352
0
    GLuint allOnes = ~(UINT32_MAX << stencilBits);
353
0
    mStencilValueMaskFront = allOnes;
354
0
    mStencilValueMaskBack  = allOnes;
355
0
    mStencilWriteMaskFront = allOnes;
356
0
    mStencilWriteMaskBack  = allOnes;
357
0
    */
358
0
359
0
    gl->GetUIntegerv(LOCAL_GL_STENCIL_VALUE_MASK,      &mStencilValueMaskFront);
360
0
    gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_VALUE_MASK, &mStencilValueMaskBack);
361
0
    gl->GetUIntegerv(LOCAL_GL_STENCIL_WRITEMASK,       &mStencilWriteMaskFront);
362
0
    gl->GetUIntegerv(LOCAL_GL_STENCIL_BACK_WRITEMASK,  &mStencilWriteMaskBack);
363
0
364
0
    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,      mStencilValueMaskFront);
365
0
    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
366
0
    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,       mStencilWriteMaskFront);
367
0
    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK,  mStencilWriteMaskBack);
368
0
369
0
    mDitherEnabled = true;
370
0
    mRasterizerDiscardEnabled = false;
371
0
    mScissorTestEnabled = false;
372
0
373
0
    mDepthTestEnabled = 0;
374
0
    mDriverDepthTest = false;
375
0
    mStencilTestEnabled = 0;
376
0
    mDriverStencilTest = false;
377
0
378
0
    mGenerateMipmapHint = LOCAL_GL_DONT_CARE;
379
0
380
0
    // Bindings, etc.
381
0
    mActiveTexture = 0;
382
0
    mDefaultFB_DrawBuffer0 = LOCAL_GL_BACK;
383
0
    mDefaultFB_ReadBuffer = LOCAL_GL_BACK;
384
0
385
0
    mEmitContextLostErrorOnce = true;
386
0
    mWebGLError = LOCAL_GL_NO_ERROR;
387
0
    mUnderlyingGLError = LOCAL_GL_NO_ERROR;
388
0
389
0
    mBound2DTextures.Clear();
390
0
    mBoundCubeMapTextures.Clear();
391
0
    mBound3DTextures.Clear();
392
0
    mBound2DArrayTextures.Clear();
393
0
    mBoundSamplers.Clear();
394
0
395
0
    mBoundArrayBuffer = nullptr;
396
0
    mCurrentProgram = nullptr;
397
0
398
0
    mBoundDrawFramebuffer = nullptr;
399
0
    mBoundReadFramebuffer = nullptr;
400
0
    mBoundRenderbuffer = nullptr;
401
0
402
0
    gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_ATTRIBS, &mGLMaxVertexAttribs);
403
0
404
0
    if (mGLMaxVertexAttribs < 8) {
405
0
        const nsPrintfCString reason("GL_MAX_VERTEX_ATTRIBS: %d is < 8!",
406
0
                                     mGLMaxVertexAttribs);
407
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_V_ATRB", reason };
408
0
        return false;
409
0
    }
410
0
411
0
    // Note: GL_MAX_TEXTURE_UNITS is fixed at 4 for most desktop hardware,
412
0
    // even though the hardware supports much more.  The
413
0
    // GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS value is the accurate value.
414
0
    mGLMaxCombinedTextureImageUnits = gl->GetIntAs<GLuint>(LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
415
0
    mGLMaxTextureUnits = mGLMaxCombinedTextureImageUnits;
416
0
417
0
    if (mGLMaxCombinedTextureImageUnits < 8) {
418
0
        const nsPrintfCString reason("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %u is < 8!",
419
0
                                     mGLMaxTextureUnits);
420
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_T_UNIT", reason };
421
0
        return false;
422
0
    }
423
0
424
0
    mBound2DTextures.SetLength(mGLMaxTextureUnits);
425
0
    mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
426
0
    mBound3DTextures.SetLength(mGLMaxTextureUnits);
427
0
    mBound2DArrayTextures.SetLength(mGLMaxTextureUnits);
428
0
    mBoundSamplers.SetLength(mGLMaxTextureUnits);
429
0
430
0
    gl->fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, (GLint*)mGLMaxViewportDims);
431
0
432
0
    ////////////////
433
0
434
0
    gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, (GLint*)&mGLMaxTextureSize);
435
0
    gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&mGLMaxCubeMapTextureSize);
436
0
    gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, (GLint*)&mGLMaxRenderbufferSize);
437
0
438
0
    if (!gl->GetPotentialInteger(LOCAL_GL_MAX_3D_TEXTURE_SIZE, (GLint*)&mGLMax3DTextureSize))
439
0
        mGLMax3DTextureSize = 0;
440
0
    if (!gl->GetPotentialInteger(LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS, (GLint*)&mGLMaxArrayTextureLayers))
441
0
        mGLMaxArrayTextureLayers = 0;
442
0
443
0
    gl->GetUIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxFragmentTextureImageUnits);
444
0
    gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
445
0
446
0
    ////////////////
447
0
448
0
    mGLMaxColorAttachments = 1;
449
0
    mGLMaxDrawBuffers = 1;
450
0
451
0
    if (IsWebGL2()) {
452
0
        UpdateMaxDrawBuffers();
453
0
    }
454
0
455
0
    ////////////////
456
0
457
0
    if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
458
0
        gl->GetUIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS, &mGLMaxFragmentUniformVectors);
459
0
        gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS, &mGLMaxVertexUniformVectors);
460
0
        gl->GetUIntegerv(LOCAL_GL_MAX_VARYING_VECTORS, &mGLMaxVaryingVectors);
461
0
    } else {
462
0
        gl->GetUIntegerv(LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &mGLMaxFragmentUniformVectors);
463
0
        mGLMaxFragmentUniformVectors /= 4;
464
0
        gl->GetUIntegerv(LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS, &mGLMaxVertexUniformVectors);
465
0
        mGLMaxVertexUniformVectors /= 4;
466
0
467
0
        /* We are now going to try to read GL_MAX_VERTEX_OUTPUT_COMPONENTS
468
0
         * and GL_MAX_FRAGMENT_INPUT_COMPONENTS, however these constants
469
0
         * only entered the OpenGL standard at OpenGL 3.2. So we will try
470
0
         * reading, and check OpenGL error for INVALID_ENUM.
471
0
         *
472
0
         * On the public_webgl list, "problematic GetParameter pnames"
473
0
         * thread, the following formula was given:
474
0
         *   maxVaryingVectors = min(GL_MAX_VERTEX_OUTPUT_COMPONENTS,
475
0
         *                           GL_MAX_FRAGMENT_INPUT_COMPONENTS) / 4
476
0
         */
477
0
        uint32_t maxVertexOutputComponents = 0;
478
0
        uint32_t maxFragmentInputComponents = 0;
479
0
        bool ok = true;
480
0
        ok &= gl->GetPotentialInteger(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS,
481
0
                                      (GLint*)&maxVertexOutputComponents);
482
0
        ok &= gl->GetPotentialInteger(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS,
483
0
                                      (GLint*)&maxFragmentInputComponents);
484
0
        if (ok) {
485
0
            mGLMaxVaryingVectors = std::min(maxVertexOutputComponents,
486
0
                                            maxFragmentInputComponents) / 4;
487
0
        } else {
488
0
            mGLMaxVaryingVectors = 16;
489
0
            // 16 = 64/4, and 64 is the min value for
490
0
            // maxVertexOutputComponents in the OpenGL 3.2 spec.
491
0
        }
492
0
    }
493
0
494
0
    ////////////////
495
0
496
0
    gl->fGetFloatv(LOCAL_GL_ALIASED_LINE_WIDTH_RANGE, mGLAliasedLineWidthRange);
497
0
498
0
    const GLenum driverPName = gl->IsCoreProfile() ? LOCAL_GL_POINT_SIZE_RANGE
499
0
                                                   : LOCAL_GL_ALIASED_POINT_SIZE_RANGE;
500
0
    gl->fGetFloatv(driverPName, mGLAliasedPointSizeRange);
501
0
502
0
    ////////////////
503
0
504
0
    if (gfxPrefs::WebGLMinCapabilityMode()) {
505
0
        bool ok = true;
506
0
507
0
        ok &= RestrictCap(&mGLMaxVertexTextureImageUnits  , kMinMaxVertexTextureImageUnits);
508
0
        ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits, kMinMaxFragmentTextureImageUnits);
509
0
        ok &= RestrictCap(&mGLMaxCombinedTextureImageUnits, kMinMaxCombinedTextureImageUnits);
510
0
511
0
        ok &= RestrictCap(&mGLMaxVertexAttribs         , kMinMaxVertexAttribs);
512
0
        ok &= RestrictCap(&mGLMaxVertexUniformVectors  , kMinMaxVertexUniformVectors);
513
0
        ok &= RestrictCap(&mGLMaxFragmentUniformVectors, kMinMaxFragmentUniformVectors);
514
0
        ok &= RestrictCap(&mGLMaxVaryingVectors        , kMinMaxVaryingVectors);
515
0
516
0
        ok &= RestrictCap(&mGLMaxColorAttachments, kMinMaxColorAttachments);
517
0
        ok &= RestrictCap(&mGLMaxDrawBuffers     , kMinMaxDrawBuffers);
518
0
519
0
        ok &= RestrictCap(&mGLMaxTextureSize       , kMinMaxTextureSize);
520
0
        ok &= RestrictCap(&mGLMaxCubeMapTextureSize, kMinMaxCubeMapTextureSize);
521
0
        ok &= RestrictCap(&mGLMax3DTextureSize     , kMinMax3DTextureSize);
522
0
523
0
        ok &= RestrictCap(&mGLMaxArrayTextureLayers, kMinMaxArrayTextureLayers);
524
0
        ok &= RestrictCap(&mGLMaxRenderbufferSize  , kMinMaxRenderbufferSize);
525
0
526
0
        if (!ok) {
527
0
            GenerateWarning("Unable to restrict WebGL limits to minimums.");
528
0
            return false;
529
0
        }
530
0
531
0
        mDisableFragHighP = true;
532
0
    } else if (nsContentUtils::ShouldResistFingerprinting()) {
533
0
        bool ok = true;
534
0
535
0
        ok &= RestrictCap(&mGLMaxTextureSize       , kCommonMaxTextureSize);
536
0
        ok &= RestrictCap(&mGLMaxCubeMapTextureSize, kCommonMaxCubeMapTextureSize);
537
0
        ok &= RestrictCap(&mGLMaxRenderbufferSize  , kCommonMaxRenderbufferSize);
538
0
539
0
        ok &= RestrictCap(&mGLMaxVertexTextureImageUnits  , kCommonMaxVertexTextureImageUnits);
540
0
        ok &= RestrictCap(&mGLMaxFragmentTextureImageUnits, kCommonMaxFragmentTextureImageUnits);
541
0
        ok &= RestrictCap(&mGLMaxCombinedTextureImageUnits, kCommonMaxCombinedTextureImageUnits);
542
0
543
0
        ok &= RestrictCap(&mGLMaxVertexAttribs         , kCommonMaxVertexAttribs);
544
0
        ok &= RestrictCap(&mGLMaxVertexUniformVectors  , kCommonMaxVertexUniformVectors);
545
0
        ok &= RestrictCap(&mGLMaxFragmentUniformVectors, kCommonMaxFragmentUniformVectors);
546
0
        ok &= RestrictCap(&mGLMaxVaryingVectors        , kCommonMaxVaryingVectors);
547
0
548
0
        ok &= RestrictCap(&mGLAliasedLineWidthRange[0], kCommonAliasedLineWidthRangeMin);
549
0
        ok &= RestrictCap(&mGLAliasedLineWidthRange[1], kCommonAliasedLineWidthRangeMax);
550
0
        ok &= RestrictCap(&mGLAliasedPointSizeRange[0], kCommonAliasedPointSizeRangeMin);
551
0
        ok &= RestrictCap(&mGLAliasedPointSizeRange[1], kCommonAliasedPointSizeRangeMax);
552
0
553
0
        ok &= RestrictCap(&mGLMaxViewportDims[0], kCommonMaxViewportDims);
554
0
        ok &= RestrictCap(&mGLMaxViewportDims[1], kCommonMaxViewportDims);
555
0
556
0
        if (!ok) {
557
0
            GenerateWarning("Unable to restrict WebGL limits in order to resist fingerprinting");
558
0
            return false;
559
0
        }
560
0
    }
561
0
562
0
    ////////////////
563
0
564
0
    if (gl->IsCompatibilityProfile()) {
565
0
        gl->fEnable(LOCAL_GL_POINT_SPRITE);
566
0
    }
567
0
568
0
    if (!gl->IsGLES()) {
569
0
        gl->fEnable(LOCAL_GL_PROGRAM_POINT_SIZE);
570
0
    }
571
0
572
#ifdef XP_MACOSX
573
    if (gl->WorkAroundDriverBugs() &&
574
        gl->Vendor() == gl::GLVendor::ATI &&
575
        !nsCocoaFeatures::IsAtLeastVersion(10,9))
576
    {
577
        // The Mac ATI driver, in all known OSX version up to and including
578
        // 10.8, renders points sprites upside-down. (Apple bug 11778921)
579
        gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
580
                             LOCAL_GL_LOWER_LEFT);
581
    }
582
#endif
583
584
0
    if (gl->IsSupported(gl::GLFeature::seamless_cube_map_opt_in)) {
585
0
        gl->fEnable(LOCAL_GL_TEXTURE_CUBE_MAP_SEAMLESS);
586
0
    }
587
0
588
0
    // Check the shader validator pref
589
0
    mBypassShaderValidation = gfxPrefs::WebGLBypassShaderValidator();
590
0
591
0
    // initialize shader translator
592
0
    if (!sh::Initialize()) {
593
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_GLSL",
594
0
                            "GLSL translator initialization failed!" };
595
0
        return false;
596
0
    }
597
0
598
0
    // Mesa can only be detected with the GL_VERSION string, of the form
599
0
    // "2.1 Mesa 7.11.0"
600
0
    const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
601
0
    mIsMesa = strstr(versionStr, "Mesa");
602
0
603
0
    // Notice that the point of calling fGetError here is not only to check for
604
0
    // errors, but also to reset the error flags so that a subsequent WebGL
605
0
    // getError call will give the correct result.
606
0
    error = gl->fGetError();
607
0
    if (error != LOCAL_GL_NO_ERROR) {
608
0
        const nsPrintfCString reason("GL error 0x%x occurred during WebGL context"
609
0
                                     " initialization!",
610
0
                                     error);
611
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_GLERR_2", reason };
612
0
        return false;
613
0
    }
614
0
615
0
    if (IsWebGL2() &&
616
0
        !InitWebGL2(out_failReason))
617
0
    {
618
0
        // Todo: Bug 898404: Only allow WebGL2 on GL>=3.0 on desktop GL.
619
0
        return false;
620
0
    }
621
0
622
0
    if (!gl->IsSupported(GLFeature::vertex_array_object)) {
623
0
        *out_failReason = { "FEATURE_FAILURE_WEBGL_VAOS",
624
0
                            "Requires vertex_array_object." };
625
0
        return false;
626
0
    }
627
0
628
0
    mDefaultVertexArray = WebGLVertexArray::Create(this);
629
0
    mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
630
0
    mBoundVertexArray = mDefaultVertexArray;
631
0
632
0
    // OpenGL core profiles remove the default VAO object from version
633
0
    // 4.0.0. We create a default VAO for all core profiles,
634
0
    // regardless of version.
635
0
    //
636
0
    // GL Spec 4.0.0:
637
0
    // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
638
0
    // in Section E.2.2 "Removed Features", pg 397: "[...] The default
639
0
    // vertex array object (the name zero) is also deprecated. [...]"
640
0
641
0
    if (gl->IsCoreProfile()) {
642
0
        mDefaultVertexArray->GenVertexArray();
643
0
        mDefaultVertexArray->BindVertexArray();
644
0
    }
645
0
646
0
    mPixelStore_FlipY = false;
647
0
    mPixelStore_PremultiplyAlpha = false;
648
0
    mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL;
649
0
    mPixelStore_RequireFastPath = false;
650
0
651
0
    // GLES 3.0.4, p259:
652
0
    mPixelStore_UnpackImageHeight = 0;
653
0
    mPixelStore_UnpackSkipImages = 0;
654
0
    mPixelStore_UnpackRowLength = 0;
655
0
    mPixelStore_UnpackSkipRows = 0;
656
0
    mPixelStore_UnpackSkipPixels = 0;
657
0
    mPixelStore_UnpackAlignment = 4;
658
0
    mPixelStore_PackRowLength = 0;
659
0
    mPixelStore_PackSkipRows = 0;
660
0
    mPixelStore_PackSkipPixels = 0;
661
0
    mPixelStore_PackAlignment = 4;
662
0
663
0
    mPrimRestartTypeBytes = 0;
664
0
665
0
    mGenericVertexAttribTypes.reset(new GLenum[mGLMaxVertexAttribs]);
666
0
    std::fill_n(mGenericVertexAttribTypes.get(), mGLMaxVertexAttribs, LOCAL_GL_FLOAT);
667
0
    mGenericVertexAttribTypeInvalidator.InvalidateCaches();
668
0
669
0
    static const float kDefaultGenericVertexAttribData[4] = { 0, 0, 0, 1 };
670
0
    memcpy(mGenericVertexAttrib0Data, kDefaultGenericVertexAttribData,
671
0
           sizeof(mGenericVertexAttrib0Data));
672
0
673
0
    mFakeVertexAttrib0BufferObject = 0;
674
0
675
0
    mNeedsIndexValidation = !gl->IsSupported(gl::GLFeature::robust_buffer_access_behavior);
676
0
    switch (gfxPrefs::WebGLForceIndexValidation()) {
677
0
    case -1:
678
0
        mNeedsIndexValidation = false;
679
0
        break;
680
0
    case 1:
681
0
        mNeedsIndexValidation = true;
682
0
        break;
683
0
    default:
684
0
        MOZ_ASSERT(gfxPrefs::WebGLForceIndexValidation() == 0);
685
0
        break;
686
0
    }
687
0
688
0
    return true;
689
0
}
690
691
bool
692
WebGLContext::ValidateFramebufferTarget(GLenum target)
693
0
{
694
0
    bool isValid = true;
695
0
    switch (target) {
696
0
    case LOCAL_GL_FRAMEBUFFER:
697
0
        break;
698
0
699
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
700
0
    case LOCAL_GL_READ_FRAMEBUFFER:
701
0
        isValid = IsWebGL2();
702
0
        break;
703
0
704
0
    default:
705
0
        isValid = false;
706
0
        break;
707
0
    }
708
0
709
0
    if (MOZ_LIKELY(isValid)) {
710
0
        return true;
711
0
    }
712
0
713
0
    ErrorInvalidEnumArg("target", target);
714
0
    return false;
715
0
}
716
717
} // namespace mozilla