Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLContextState.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; 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 "GLContext.h"
9
#include "GLScreenBuffer.h"
10
#include "mozilla/dom/ToJSValue.h"
11
#include "mozilla/Maybe.h"
12
#include "mozilla/Preferences.h"
13
#include "MozFramebuffer.h"
14
#include "nsString.h"
15
#include "WebGLBuffer.h"
16
#include "WebGLContextUtils.h"
17
#include "WebGLFramebuffer.h"
18
#include "WebGLProgram.h"
19
#include "WebGLRenderbuffer.h"
20
#include "WebGLShader.h"
21
#include "WebGLTexture.h"
22
#include "WebGLVertexArray.h"
23
24
namespace mozilla {
25
26
void
27
WebGLContext::SetEnabled(const char* const funcName, const GLenum cap, const bool enabled)
28
0
{
29
0
    const FuncScope funcScope(*this, funcName);
30
0
    if (IsContextLost())
31
0
        return;
32
0
33
0
    if (!ValidateCapabilityEnum(cap))
34
0
        return;
35
0
36
0
    const auto& slot = GetStateTrackingSlot(cap);
37
0
    if (slot) {
38
0
        *slot = enabled;
39
0
    }
40
0
41
0
    switch (cap) {
42
0
    case LOCAL_GL_DEPTH_TEST:
43
0
    case LOCAL_GL_STENCIL_TEST:
44
0
        break; // Lazily applied, so don't tell GL yet or we will desync.
45
0
46
0
    default:
47
0
        // Non-lazy caps.
48
0
        gl->SetEnabled(cap, enabled);
49
0
        break;
50
0
    }
51
0
}
52
53
bool
54
WebGLContext::GetStencilBits(GLint* const out_stencilBits) const
55
0
{
56
0
    *out_stencilBits = 0;
57
0
    if (mBoundDrawFramebuffer) {
58
0
        if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() &&
59
0
            mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
60
0
        {
61
0
            // Error, we don't know which stencil buffer's bits to use
62
0
            ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
63
0
            return false;
64
0
        }
65
0
66
0
        if (mBoundDrawFramebuffer->StencilAttachment().IsDefined() ||
67
0
            mBoundDrawFramebuffer->DepthStencilAttachment().IsDefined())
68
0
        {
69
0
            *out_stencilBits = 8;
70
0
        }
71
0
    } else if (mOptions.stencil) {
72
0
        *out_stencilBits = 8;
73
0
    }
74
0
75
0
    return true;
76
0
}
77
78
JS::Value
79
WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
80
0
{
81
0
    const FuncScope funcScope(*this, "getParameter");
82
0
83
0
    if (IsContextLost())
84
0
        return JS::NullValue();
85
0
86
0
    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
87
0
        if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
88
0
            return JS::Int32Value(mGLMaxColorAttachments);
89
0
90
0
        } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
91
0
            return JS::Int32Value(mGLMaxDrawBuffers);
92
0
93
0
        } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
94
0
                   pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
95
0
        {
96
0
            GLint ret = LOCAL_GL_NONE;
97
0
            if (!mBoundDrawFramebuffer) {
98
0
                if (pname == LOCAL_GL_DRAW_BUFFER0) {
99
0
                    ret = mDefaultFB_DrawBuffer0;
100
0
                }
101
0
            } else {
102
0
                gl->fGetIntegerv(pname, &ret);
103
0
            }
104
0
            return JS::Int32Value(ret);
105
0
        }
106
0
    }
107
0
108
0
    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
109
0
        if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
110
0
            WebGLVertexArray* vao =
111
0
                (mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr;
112
0
            return WebGLObjectAsJSValue(cx, vao, rv);
113
0
        }
114
0
    }
115
0
116
0
    if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) {
117
0
        switch (pname) {
118
0
        case LOCAL_GL_TIMESTAMP_EXT:
119
0
            {
120
0
                uint64_t val = 0;
121
0
                if (Has64BitTimestamps()) {
122
0
                    gl->fGetInteger64v(pname, (GLint64*)&val);
123
0
                } else {
124
0
                    gl->fGetIntegerv(pname, (GLint*)&val);
125
0
                }
126
0
                // TODO: JS doesn't support 64-bit integers. Be lossy and
127
0
                // cast to double (53 bits)
128
0
                return JS::NumberValue(val);
129
0
            }
130
0
131
0
        case LOCAL_GL_GPU_DISJOINT_EXT:
132
0
            {
133
0
                realGLboolean val = false; // Not disjoint by default.
134
0
                if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) {
135
0
                    gl->fGetBooleanv(pname, &val);
136
0
                }
137
0
                return JS::BooleanValue(val);
138
0
            }
139
0
140
0
        default:
141
0
            break;
142
0
        }
143
0
    }
144
0
145
0
    // Privileged string params exposed by WEBGL_debug_renderer_info.
146
0
    // The privilege check is done in WebGLContext::IsExtensionSupported.
147
0
    // So here we just have to check that the extension is enabled.
148
0
    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) {
149
0
        switch (pname) {
150
0
        case UNMASKED_VENDOR_WEBGL:
151
0
        case UNMASKED_RENDERER_WEBGL:
152
0
            {
153
0
                const char* overridePref = nullptr;
154
0
                GLenum driverEnum = LOCAL_GL_NONE;
155
0
156
0
                switch (pname) {
157
0
                case UNMASKED_RENDERER_WEBGL:
158
0
                    overridePref = "webgl.renderer-string-override";
159
0
                    driverEnum = LOCAL_GL_RENDERER;
160
0
                    break;
161
0
                case UNMASKED_VENDOR_WEBGL:
162
0
                    overridePref = "webgl.vendor-string-override";
163
0
                    driverEnum = LOCAL_GL_VENDOR;
164
0
                    break;
165
0
                default:
166
0
                    MOZ_CRASH("GFX: bad `pname`");
167
0
                }
168
0
169
0
                bool hasRetVal = false;
170
0
171
0
                nsAutoString ret;
172
0
                if (overridePref) {
173
0
                    nsresult res = Preferences::GetString(overridePref, ret);
174
0
                    if (NS_SUCCEEDED(res) && ret.Length() > 0)
175
0
                        hasRetVal = true;
176
0
                }
177
0
178
0
                if (!hasRetVal) {
179
0
                    const char* chars = reinterpret_cast<const char*>(gl->fGetString(driverEnum));
180
0
                    ret = NS_ConvertASCIItoUTF16(chars);
181
0
                    hasRetVal = true;
182
0
                }
183
0
184
0
                return StringValue(cx, ret, rv);
185
0
            }
186
0
        }
187
0
    }
188
0
189
0
    if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
190
0
        if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) {
191
0
            GLint i = 0;
192
0
            gl->fGetIntegerv(pname, &i);
193
0
            return JS::Int32Value(i);
194
0
        }
195
0
    }
196
0
197
0
    if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
198
0
        if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) {
199
0
            GLfloat f = 0.f;
200
0
            gl->fGetFloatv(pname, &f);
201
0
            return JS::NumberValue(f);
202
0
        }
203
0
    }
204
0
205
0
    switch (pname) {
206
0
        //
207
0
        // String params
208
0
        //
209
0
        case LOCAL_GL_VENDOR:
210
0
        case LOCAL_GL_RENDERER:
211
0
            return StringValue(cx, "Mozilla", rv);
212
0
        case LOCAL_GL_VERSION:
213
0
            return StringValue(cx, "WebGL 1.0", rv);
214
0
        case LOCAL_GL_SHADING_LANGUAGE_VERSION:
215
0
            return StringValue(cx, "WebGL GLSL ES 1.0", rv);
216
0
217
0
        ////////////////////////////////
218
0
        // Single-value params
219
0
220
0
        // unsigned int
221
0
        case LOCAL_GL_CULL_FACE_MODE:
222
0
        case LOCAL_GL_FRONT_FACE:
223
0
        case LOCAL_GL_ACTIVE_TEXTURE:
224
0
        case LOCAL_GL_STENCIL_FUNC:
225
0
        case LOCAL_GL_STENCIL_FAIL:
226
0
        case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
227
0
        case LOCAL_GL_STENCIL_PASS_DEPTH_PASS:
228
0
        case LOCAL_GL_STENCIL_BACK_FUNC:
229
0
        case LOCAL_GL_STENCIL_BACK_FAIL:
230
0
        case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL:
231
0
        case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
232
0
        case LOCAL_GL_DEPTH_FUNC:
233
0
        case LOCAL_GL_BLEND_SRC_RGB:
234
0
        case LOCAL_GL_BLEND_SRC_ALPHA:
235
0
        case LOCAL_GL_BLEND_DST_RGB:
236
0
        case LOCAL_GL_BLEND_DST_ALPHA:
237
0
        case LOCAL_GL_BLEND_EQUATION_RGB:
238
0
        case LOCAL_GL_BLEND_EQUATION_ALPHA: {
239
0
            GLint i = 0;
240
0
            gl->fGetIntegerv(pname, &i);
241
0
            return JS::NumberValue(uint32_t(i));
242
0
        }
243
0
244
0
        case LOCAL_GL_GENERATE_MIPMAP_HINT:
245
0
            return JS::NumberValue(mGenerateMipmapHint);
246
0
247
0
        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT:
248
0
        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
249
0
            const webgl::FormatUsageInfo* usage;
250
0
            uint32_t width, height;
251
0
            if (!BindCurFBForColorRead(&usage, &width, &height))
252
0
                return JS::NullValue();
253
0
254
0
            const auto implPI = ValidImplementationColorReadPI(usage);
255
0
256
0
            GLenum ret;
257
0
            if (pname == LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT) {
258
0
                ret = implPI.format;
259
0
            } else {
260
0
                ret = implPI.type;
261
0
            }
262
0
            return JS::NumberValue(uint32_t(ret));
263
0
        }
264
0
265
0
        // int
266
0
        case LOCAL_GL_STENCIL_REF:
267
0
        case LOCAL_GL_STENCIL_BACK_REF: {
268
0
            GLint stencilBits = 0;
269
0
            if (!GetStencilBits(&stencilBits))
270
0
                return JS::NullValue();
271
0
272
0
            // Assuming stencils have 8 bits
273
0
            const GLint stencilMask = (1 << stencilBits) - 1;
274
0
275
0
            GLint refValue = 0;
276
0
            gl->fGetIntegerv(pname, &refValue);
277
0
278
0
            return JS::Int32Value(refValue & stencilMask);
279
0
        }
280
0
281
0
        case LOCAL_GL_SAMPLE_BUFFERS:
282
0
        case LOCAL_GL_SAMPLES: {
283
0
            const auto& fb = mBoundDrawFramebuffer;
284
0
            auto samples = [&]() -> Maybe<uint32_t> {
285
0
                if (!fb) {
286
0
                    if (!EnsureDefaultFB())
287
0
                        return Nothing();
288
0
                    return Some(mDefaultFB->mSamples);
289
0
                }
290
0
291
0
                if (!fb->IsCheckFramebufferStatusComplete())
292
0
                    return Some(0);
293
0
294
0
                DoBindFB(fb, LOCAL_GL_FRAMEBUFFER);
295
0
                return Some(gl->GetIntAs<uint32_t>(LOCAL_GL_SAMPLES));
296
0
            }();
297
0
            if (samples && pname == LOCAL_GL_SAMPLE_BUFFERS) {
298
0
                samples = Some(uint32_t(bool(samples.value())));
299
0
            }
300
0
            if (!samples)
301
0
                return JS::NullValue();
302
0
            return JS::NumberValue(samples.value());
303
0
        }
304
0
305
0
        case LOCAL_GL_STENCIL_CLEAR_VALUE:
306
0
        case LOCAL_GL_UNPACK_ALIGNMENT:
307
0
        case LOCAL_GL_PACK_ALIGNMENT:
308
0
        case LOCAL_GL_SUBPIXEL_BITS: {
309
0
            GLint i = 0;
310
0
            gl->fGetIntegerv(pname, &i);
311
0
            return JS::Int32Value(i);
312
0
        }
313
0
314
0
        case LOCAL_GL_RED_BITS:
315
0
        case LOCAL_GL_GREEN_BITS:
316
0
        case LOCAL_GL_BLUE_BITS:
317
0
        case LOCAL_GL_ALPHA_BITS:
318
0
        case LOCAL_GL_DEPTH_BITS:
319
0
        case LOCAL_GL_STENCIL_BITS: {
320
0
            const auto format = [&]() -> const webgl::FormatInfo* {
321
0
                if (mBoundDrawFramebuffer) {
322
0
                    const auto& fb = *mBoundDrawFramebuffer;
323
0
                    const auto& attachment = [&]() -> const auto& {
324
0
                        switch (pname) {
325
0
                        case LOCAL_GL_DEPTH_BITS:
326
0
                            return fb.AnyDepthAttachment();
327
0
328
0
                        case LOCAL_GL_STENCIL_BITS:
329
0
                            return fb.AnyStencilAttachment();
330
0
331
0
                        default:
332
0
                            return fb.ColorAttachment0();
333
0
                        }
334
0
                    }();
335
0
                    if (!attachment.HasImage())
336
0
                        return nullptr;
337
0
                    return attachment.Format()->format;
338
0
                }
339
0
340
0
                auto effFormat = webgl::EffectiveFormat::RGB8;
341
0
                switch (pname) {
342
0
                case LOCAL_GL_DEPTH_BITS:
343
0
                    if (mOptions.depth) {
344
0
                        effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
345
0
                    }
346
0
                    break;
347
0
348
0
                case LOCAL_GL_STENCIL_BITS:
349
0
                    if (mOptions.stencil) {
350
0
                        effFormat = webgl::EffectiveFormat::DEPTH24_STENCIL8;
351
0
                    }
352
0
                    break;
353
0
354
0
                default:
355
0
                    if (mOptions.alpha) {
356
0
                        effFormat = webgl::EffectiveFormat::RGBA8;
357
0
                    }
358
0
                    break;
359
0
                }
360
0
                return webgl::GetFormat(effFormat);
361
0
            }();
362
0
            int32_t ret = 0;
363
0
            if (format) {
364
0
                switch (pname) {
365
0
                case LOCAL_GL_RED_BITS:
366
0
                    ret = format->r;
367
0
                    break;
368
0
                case LOCAL_GL_GREEN_BITS:
369
0
                    ret = format->g;
370
0
                    break;
371
0
                case LOCAL_GL_BLUE_BITS:
372
0
                    ret = format->b;
373
0
                    break;
374
0
                case LOCAL_GL_ALPHA_BITS:
375
0
                    ret = format->a;
376
0
                    break;
377
0
                case LOCAL_GL_DEPTH_BITS:
378
0
                    ret = format->d;
379
0
                    break;
380
0
                case LOCAL_GL_STENCIL_BITS:
381
0
                    ret = format->s;
382
0
                    break;
383
0
                }
384
0
            }
385
0
            return JS::Int32Value(ret);
386
0
        }
387
0
388
0
        case LOCAL_GL_MAX_TEXTURE_SIZE:
389
0
            return JS::Int32Value(mGLMaxTextureSize);
390
0
391
0
        case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
392
0
            return JS::Int32Value(mGLMaxCubeMapTextureSize);
393
0
394
0
        case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
395
0
            return JS::Int32Value(mGLMaxRenderbufferSize);
396
0
397
0
        case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
398
0
            return JS::Int32Value(mGLMaxVertexTextureImageUnits);
399
0
400
0
        case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
401
0
            return JS::Int32Value(mGLMaxFragmentTextureImageUnits);
402
0
403
0
        case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
404
0
            return JS::Int32Value(mGLMaxCombinedTextureImageUnits);
405
0
406
0
        case LOCAL_GL_MAX_VERTEX_ATTRIBS:
407
0
            return JS::Int32Value(mGLMaxVertexAttribs);
408
0
409
0
        case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
410
0
            return JS::Int32Value(mGLMaxVertexUniformVectors);
411
0
412
0
        case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
413
0
            return JS::Int32Value(mGLMaxFragmentUniformVectors);
414
0
415
0
        case LOCAL_GL_MAX_VARYING_VECTORS:
416
0
            return JS::Int32Value(mGLMaxVaryingVectors);
417
0
418
0
        case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
419
0
            uint32_t length = mCompressedTextureFormats.Length();
420
0
            JSObject* obj = dom::Uint32Array::Create(cx, this, length,
421
0
                                                     mCompressedTextureFormats.Elements());
422
0
            if (!obj) {
423
0
                rv = NS_ERROR_OUT_OF_MEMORY;
424
0
            }
425
0
            return JS::ObjectOrNullValue(obj);
426
0
        }
427
0
428
0
        // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
429
0
        // javascript integer values. We just return them as doubles and javascript doesn't care.
430
0
        case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
431
0
            return JS::DoubleValue(mStencilValueMaskBack); // pass as FP value to allow large values such as 2^32-1.
432
0
433
0
        case LOCAL_GL_STENCIL_BACK_WRITEMASK:
434
0
            return JS::DoubleValue(mStencilWriteMaskBack);
435
0
436
0
        case LOCAL_GL_STENCIL_VALUE_MASK:
437
0
            return JS::DoubleValue(mStencilValueMaskFront);
438
0
439
0
        case LOCAL_GL_STENCIL_WRITEMASK:
440
0
            return JS::DoubleValue(mStencilWriteMaskFront);
441
0
442
0
        // float
443
0
        case LOCAL_GL_LINE_WIDTH:
444
0
            return JS::DoubleValue(mLineWidth);
445
0
446
0
        case LOCAL_GL_DEPTH_CLEAR_VALUE:
447
0
        case LOCAL_GL_POLYGON_OFFSET_FACTOR:
448
0
        case LOCAL_GL_POLYGON_OFFSET_UNITS:
449
0
        case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
450
0
            GLfloat f = 0.f;
451
0
            gl->fGetFloatv(pname, &f);
452
0
            return JS::DoubleValue(f);
453
0
        }
454
0
455
0
        // bool
456
0
        case LOCAL_GL_DEPTH_TEST:
457
0
            return JS::BooleanValue(mDepthTestEnabled);
458
0
        case LOCAL_GL_STENCIL_TEST:
459
0
            return JS::BooleanValue(mStencilTestEnabled);
460
0
461
0
        case LOCAL_GL_BLEND:
462
0
        case LOCAL_GL_CULL_FACE:
463
0
        case LOCAL_GL_DITHER:
464
0
        case LOCAL_GL_POLYGON_OFFSET_FILL:
465
0
        case LOCAL_GL_SCISSOR_TEST:
466
0
        case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
467
0
        case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
468
0
        case LOCAL_GL_SAMPLE_COVERAGE:
469
0
        case LOCAL_GL_DEPTH_WRITEMASK: {
470
0
            realGLboolean b = 0;
471
0
            gl->fGetBooleanv(pname, &b);
472
0
            return JS::BooleanValue(bool(b));
473
0
        }
474
0
475
0
        // bool, WebGL-specific
476
0
        case UNPACK_FLIP_Y_WEBGL:
477
0
            return JS::BooleanValue(mPixelStore_FlipY);
478
0
        case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
479
0
            return JS::BooleanValue(mPixelStore_PremultiplyAlpha);
480
0
481
0
        // uint, WebGL-specific
482
0
        case UNPACK_COLORSPACE_CONVERSION_WEBGL:
483
0
            return JS::NumberValue(uint32_t(mPixelStore_ColorspaceConversion));
484
0
485
0
        ////////////////////////////////
486
0
        // Complex values
487
0
488
0
        // 2 floats
489
0
        case LOCAL_GL_DEPTH_RANGE:
490
0
        case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
491
0
        case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
492
0
            GLfloat fv[2] = { 0 };
493
0
            switch (pname) {
494
0
            case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
495
0
                fv[0] = mGLAliasedPointSizeRange[0];
496
0
                fv[1] = mGLAliasedPointSizeRange[1];
497
0
                break;
498
0
            case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE:
499
0
                fv[0] = mGLAliasedLineWidthRange[0];
500
0
                fv[1] = mGLAliasedLineWidthRange[1];
501
0
                break;
502
0
            // case LOCAL_GL_DEPTH_RANGE:
503
0
            default:
504
0
                gl->fGetFloatv(pname, fv);
505
0
                break;
506
0
            }
507
0
            JSObject* obj = dom::Float32Array::Create(cx, this, 2, fv);
508
0
            if (!obj) {
509
0
                rv = NS_ERROR_OUT_OF_MEMORY;
510
0
            }
511
0
            return JS::ObjectOrNullValue(obj);
512
0
        }
513
0
514
0
        // 4 floats
515
0
        case LOCAL_GL_COLOR_CLEAR_VALUE:
516
0
        case LOCAL_GL_BLEND_COLOR: {
517
0
            GLfloat fv[4] = { 0 };
518
0
            gl->fGetFloatv(pname, fv);
519
0
            JSObject* obj = dom::Float32Array::Create(cx, this, 4, fv);
520
0
            if (!obj) {
521
0
                rv = NS_ERROR_OUT_OF_MEMORY;
522
0
            }
523
0
            return JS::ObjectOrNullValue(obj);
524
0
        }
525
0
526
0
        // 2 ints
527
0
        case LOCAL_GL_MAX_VIEWPORT_DIMS: {
528
0
            GLint iv[2] = { GLint(mGLMaxViewportDims[0]), GLint(mGLMaxViewportDims[1]) };
529
0
            JSObject* obj = dom::Int32Array::Create(cx, this, 2, iv);
530
0
            if (!obj) {
531
0
                rv = NS_ERROR_OUT_OF_MEMORY;
532
0
            }
533
0
            return JS::ObjectOrNullValue(obj);
534
0
        }
535
0
536
0
        // 4 ints
537
0
        case LOCAL_GL_SCISSOR_BOX:
538
0
        case LOCAL_GL_VIEWPORT: {
539
0
            GLint iv[4] = { 0 };
540
0
            gl->fGetIntegerv(pname, iv);
541
0
            JSObject* obj = dom::Int32Array::Create(cx, this, 4, iv);
542
0
            if (!obj) {
543
0
                rv = NS_ERROR_OUT_OF_MEMORY;
544
0
            }
545
0
            return JS::ObjectOrNullValue(obj);
546
0
        }
547
0
548
0
        // 4 bools
549
0
        case LOCAL_GL_COLOR_WRITEMASK: {
550
0
            const bool vals[4] = { bool(mColorWriteMask & (1 << 0)),
551
0
                                   bool(mColorWriteMask & (1 << 1)),
552
0
                                   bool(mColorWriteMask & (1 << 2)),
553
0
                                   bool(mColorWriteMask & (1 << 3)) };
554
0
            JS::Rooted<JS::Value> arr(cx);
555
0
            if (!dom::ToJSValue(cx, vals, &arr)) {
556
0
                rv = NS_ERROR_OUT_OF_MEMORY;
557
0
            }
558
0
            return arr;
559
0
        }
560
0
561
0
        case LOCAL_GL_ARRAY_BUFFER_BINDING: {
562
0
            return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
563
0
        }
564
0
565
0
        case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
566
0
            return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv);
567
0
        }
568
0
569
0
        case LOCAL_GL_RENDERBUFFER_BINDING: {
570
0
            return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
571
0
        }
572
0
573
0
        // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING.
574
0
        case LOCAL_GL_FRAMEBUFFER_BINDING: {
575
0
            return WebGLObjectAsJSValue(cx, mBoundDrawFramebuffer.get(), rv);
576
0
        }
577
0
578
0
        case LOCAL_GL_CURRENT_PROGRAM: {
579
0
            return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
580
0
        }
581
0
582
0
        case LOCAL_GL_TEXTURE_BINDING_2D: {
583
0
            return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
584
0
        }
585
0
586
0
        case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: {
587
0
            return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv);
588
0
        }
589
0
590
0
        default:
591
0
            break;
592
0
    }
593
0
594
0
    ErrorInvalidEnumInfo("pname", pname);
595
0
    return JS::NullValue();
596
0
}
597
598
void
599
WebGLContext::GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index,
600
                                  JS::MutableHandle<JS::Value> retval)
601
0
{
602
0
    const FuncScope funcScope(*this, "getParameterIndexed");
603
0
    if (IsContextLost()) {
604
0
        retval.setNull();
605
0
        return;
606
0
    }
607
0
608
0
    switch (pname) {
609
0
        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
610
0
        {
611
0
            if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
612
0
                ErrorInvalidValue("`index` should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
613
0
                retval.setNull();
614
0
                return;
615
0
            }
616
0
            retval.setNull(); // See bug 903594
617
0
            return;
618
0
        }
619
0
620
0
        default:
621
0
            break;
622
0
    }
623
0
624
0
    ErrorInvalidEnumInfo("pname", pname);
625
0
    retval.setNull();
626
0
}
627
628
bool
629
WebGLContext::IsEnabled(GLenum cap)
630
0
{
631
0
    const FuncScope funcScope(*this, "isEnabled");
632
0
    if (IsContextLost())
633
0
        return false;
634
0
635
0
    if (!ValidateCapabilityEnum(cap))
636
0
        return false;
637
0
638
0
    const auto& slot = GetStateTrackingSlot(cap);
639
0
    if (slot)
640
0
        return *slot;
641
0
642
0
    return gl->fIsEnabled(cap);
643
0
}
644
645
bool
646
WebGLContext::ValidateCapabilityEnum(GLenum cap)
647
0
{
648
0
    switch (cap) {
649
0
        case LOCAL_GL_BLEND:
650
0
        case LOCAL_GL_CULL_FACE:
651
0
        case LOCAL_GL_DEPTH_TEST:
652
0
        case LOCAL_GL_DITHER:
653
0
        case LOCAL_GL_POLYGON_OFFSET_FILL:
654
0
        case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
655
0
        case LOCAL_GL_SAMPLE_COVERAGE:
656
0
        case LOCAL_GL_SCISSOR_TEST:
657
0
        case LOCAL_GL_STENCIL_TEST:
658
0
            return true;
659
0
        case LOCAL_GL_RASTERIZER_DISCARD:
660
0
            return IsWebGL2();
661
0
        default:
662
0
            ErrorInvalidEnumInfo("cap", cap);
663
0
            return false;
664
0
    }
665
0
}
666
667
realGLboolean*
668
WebGLContext::GetStateTrackingSlot(GLenum cap)
669
0
{
670
0
    switch (cap) {
671
0
        case LOCAL_GL_DEPTH_TEST:
672
0
            return &mDepthTestEnabled;
673
0
        case LOCAL_GL_DITHER:
674
0
            return &mDitherEnabled;
675
0
        case LOCAL_GL_RASTERIZER_DISCARD:
676
0
            return &mRasterizerDiscardEnabled;
677
0
        case LOCAL_GL_SCISSOR_TEST:
678
0
            return &mScissorTestEnabled;
679
0
        case LOCAL_GL_STENCIL_TEST:
680
0
            return &mStencilTestEnabled;
681
0
    }
682
0
683
0
    return nullptr;
684
0
}
685
686
} // namespace mozilla