Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLContextGL.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
#include "WebGL2Context.h"
8
9
#include "WebGLActiveInfo.h"
10
#include "WebGLContextUtils.h"
11
#include "WebGLBuffer.h"
12
#include "WebGLVertexAttribData.h"
13
#include "WebGLShader.h"
14
#include "WebGLProgram.h"
15
#include "WebGLUniformLocation.h"
16
#include "WebGLFormats.h"
17
#include "WebGLFramebuffer.h"
18
#include "WebGLQuery.h"
19
#include "WebGLRenderbuffer.h"
20
#include "WebGLShaderPrecisionFormat.h"
21
#include "WebGLTexture.h"
22
#include "WebGLExtensions.h"
23
#include "WebGLVertexArray.h"
24
25
#include "nsDebug.h"
26
#include "nsReadableUtils.h"
27
#include "nsString.h"
28
29
#include "gfxContext.h"
30
#include "gfxPlatform.h"
31
#include "GLContext.h"
32
33
#include "nsContentUtils.h"
34
#include "nsError.h"
35
#include "nsLayoutUtils.h"
36
37
#include "CanvasUtils.h"
38
#include "gfxUtils.h"
39
40
#include "jsfriendapi.h"
41
42
#include "WebGLTexelConversions.h"
43
#include "WebGLValidateStrings.h"
44
#include <algorithm>
45
46
// needed to check if current OS is lower than 10.7
47
#if defined(MOZ_WIDGET_COCOA)
48
#include "nsCocoaFeatures.h"
49
#endif
50
51
#include "mozilla/DebugOnly.h"
52
#include "mozilla/dom/BindingUtils.h"
53
#include "mozilla/dom/ImageData.h"
54
#include "mozilla/dom/ToJSValue.h"
55
#include "mozilla/EndianUtils.h"
56
#include "mozilla/RefPtr.h"
57
#include "mozilla/UniquePtrExtensions.h"
58
59
namespace mozilla {
60
61
bool
62
WebGLContext::ValidateObject(const char* const argName, const WebGLProgram& object)
63
0
{
64
0
    return ValidateObject(argName, object, true);
65
0
}
66
67
bool
68
WebGLContext::ValidateObject(const char* const argName, const WebGLShader& object)
69
0
{
70
0
    return ValidateObject(argName, object, true);
71
0
}
72
73
using namespace mozilla::dom;
74
using namespace mozilla::gfx;
75
using namespace mozilla::gl;
76
77
//
78
//  WebGL API
79
//
80
81
void
82
WebGLContext::ActiveTexture(GLenum texture)
83
0
{
84
0
    const FuncScope funcScope(*this, "activeTexture");
85
0
    if (IsContextLost())
86
0
        return;
87
0
88
0
    if (texture < LOCAL_GL_TEXTURE0 ||
89
0
        texture >= LOCAL_GL_TEXTURE0 + mGLMaxTextureUnits)
90
0
    {
91
0
        return ErrorInvalidEnum(
92
0
            "Texture unit %d out of range. "
93
0
            "Accepted values range from TEXTURE0 to TEXTURE0 + %d. "
94
0
            "Notice that TEXTURE0 != 0.",
95
0
            texture, mGLMaxTextureUnits);
96
0
    }
97
0
98
0
    mActiveTexture = texture - LOCAL_GL_TEXTURE0;
99
0
    gl->fActiveTexture(texture);
100
0
}
101
102
void
103
WebGLContext::AttachShader(WebGLProgram& program, WebGLShader& shader)
104
0
{
105
0
    const FuncScope funcScope(*this, "attachShader");
106
0
    if (IsContextLost())
107
0
        return;
108
0
109
0
    if (!ValidateObject("program", program) ||
110
0
        !ValidateObject("shader", shader))
111
0
    {
112
0
        return;
113
0
    }
114
0
115
0
    program.AttachShader(&shader);
116
0
}
117
118
void
119
WebGLContext::BindAttribLocation(WebGLProgram& prog, GLuint location,
120
                                 const nsAString& name)
121
0
{
122
0
    const FuncScope funcScope(*this, "bindAttribLocation");
123
0
    if (IsContextLost())
124
0
        return;
125
0
126
0
    if (!ValidateObject("program", prog))
127
0
        return;
128
0
129
0
    prog.BindAttribLocation(location, name);
130
0
}
131
132
void
133
WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
134
0
{
135
0
    const FuncScope funcScope(*this, "bindFramebuffer");
136
0
    if (IsContextLost())
137
0
        return;
138
0
139
0
    if (!ValidateFramebufferTarget(target))
140
0
        return;
141
0
142
0
    if (wfb && !ValidateObject("fb", *wfb))
143
0
        return;
144
0
145
0
    if (!wfb) {
146
0
        gl->fBindFramebuffer(target, 0);
147
0
    } else {
148
0
        GLuint framebuffername = wfb->mGLName;
149
0
        gl->fBindFramebuffer(target, framebuffername);
150
#ifdef ANDROID
151
        wfb->mIsFB = true;
152
#endif
153
    }
154
0
155
0
    switch (target) {
156
0
    case LOCAL_GL_FRAMEBUFFER:
157
0
        mBoundDrawFramebuffer = wfb;
158
0
        mBoundReadFramebuffer = wfb;
159
0
        break;
160
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
161
0
        mBoundDrawFramebuffer = wfb;
162
0
        break;
163
0
    case LOCAL_GL_READ_FRAMEBUFFER:
164
0
        mBoundReadFramebuffer = wfb;
165
0
        break;
166
0
    default:
167
0
        break;
168
0
    }
169
0
}
170
171
void
172
WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer* wrb)
173
0
{
174
0
    const FuncScope funcScope(*this, "bindRenderbuffer");
175
0
    if (IsContextLost())
176
0
        return;
177
0
178
0
    if (target != LOCAL_GL_RENDERBUFFER)
179
0
        return ErrorInvalidEnumInfo("target", target);
180
0
181
0
    if (wrb && !ValidateObject("rb", *wrb))
182
0
        return;
183
0
184
0
    // Usually, we would now call into glBindRenderbuffer. However, since we have to
185
0
    // potentially emulate packed-depth-stencil, there's not a specific renderbuffer that
186
0
    // we know we should bind here.
187
0
    // Instead, we do all renderbuffer binding lazily.
188
0
189
0
    if (wrb) {
190
0
        wrb->mHasBeenBound = true;
191
0
    }
192
0
193
0
    mBoundRenderbuffer = wrb;
194
0
}
195
196
void WebGLContext::BlendEquation(GLenum mode)
197
0
{
198
0
    const FuncScope funcScope(*this, "blendEquation");
199
0
    if (IsContextLost())
200
0
        return;
201
0
202
0
    if (!ValidateBlendEquationEnum(mode, "mode"))
203
0
        return;
204
0
205
0
    gl->fBlendEquation(mode);
206
0
}
207
208
void WebGLContext::BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
209
0
{
210
0
    const FuncScope funcScope(*this, "blendEquationSeparate");
211
0
    if (IsContextLost())
212
0
        return;
213
0
214
0
    if (!ValidateBlendEquationEnum(modeRGB, "modeRGB") ||
215
0
        !ValidateBlendEquationEnum(modeAlpha, "modeAlpha"))
216
0
    {
217
0
        return;
218
0
    }
219
0
220
0
    gl->fBlendEquationSeparate(modeRGB, modeAlpha);
221
0
}
222
223
static bool
224
ValidateBlendFuncEnum(WebGLContext* webgl, GLenum factor, const char* varName)
225
0
{
226
0
    switch (factor) {
227
0
    case LOCAL_GL_ZERO:
228
0
    case LOCAL_GL_ONE:
229
0
    case LOCAL_GL_SRC_COLOR:
230
0
    case LOCAL_GL_ONE_MINUS_SRC_COLOR:
231
0
    case LOCAL_GL_DST_COLOR:
232
0
    case LOCAL_GL_ONE_MINUS_DST_COLOR:
233
0
    case LOCAL_GL_SRC_ALPHA:
234
0
    case LOCAL_GL_ONE_MINUS_SRC_ALPHA:
235
0
    case LOCAL_GL_DST_ALPHA:
236
0
    case LOCAL_GL_ONE_MINUS_DST_ALPHA:
237
0
    case LOCAL_GL_CONSTANT_COLOR:
238
0
    case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
239
0
    case LOCAL_GL_CONSTANT_ALPHA:
240
0
    case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
241
0
    case LOCAL_GL_SRC_ALPHA_SATURATE:
242
0
        return true;
243
0
244
0
    default:
245
0
        webgl->ErrorInvalidEnumInfo(varName, factor);
246
0
        return false;
247
0
    }
248
0
}
249
250
static bool
251
ValidateBlendFuncEnums(WebGLContext* webgl, GLenum srcRGB, GLenum srcAlpha,
252
                       GLenum dstRGB, GLenum dstAlpha)
253
0
{
254
0
    if (!webgl->IsWebGL2()) {
255
0
       if (dstRGB == LOCAL_GL_SRC_ALPHA_SATURATE || dstAlpha == LOCAL_GL_SRC_ALPHA_SATURATE) {
256
0
          webgl->ErrorInvalidEnum("LOCAL_GL_SRC_ALPHA_SATURATE as a destination"
257
0
                                  " blend function is disallowed in WebGL 1 (dstRGB ="
258
0
                                  " 0x%04x, dstAlpha = 0x%04x).",
259
0
                                  dstRGB, dstAlpha);
260
0
          return false;
261
0
       }
262
0
    }
263
0
264
0
    if (!ValidateBlendFuncEnum(webgl, srcRGB, "srcRGB") ||
265
0
        !ValidateBlendFuncEnum(webgl, srcAlpha, "srcAlpha") ||
266
0
        !ValidateBlendFuncEnum(webgl, dstRGB, "dstRGB") ||
267
0
        !ValidateBlendFuncEnum(webgl, dstAlpha, "dstAlpha"))
268
0
    {
269
0
       return false;
270
0
    }
271
0
272
0
    return true;
273
0
}
274
275
void WebGLContext::BlendFunc(GLenum sfactor, GLenum dfactor)
276
0
{
277
0
    const FuncScope funcScope(*this, "blendFunc");
278
0
    if (IsContextLost())
279
0
        return;
280
0
281
0
    if (!ValidateBlendFuncEnums(this, sfactor, sfactor, dfactor, dfactor))
282
0
       return;
283
0
284
0
    if (!ValidateBlendFuncEnumsCompatibility(sfactor, dfactor, "srcRGB and dstRGB"))
285
0
        return;
286
0
287
0
    gl->fBlendFunc(sfactor, dfactor);
288
0
}
289
290
void
291
WebGLContext::BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB,
292
                                GLenum srcAlpha, GLenum dstAlpha)
293
0
{
294
0
    const FuncScope funcScope(*this, "blendFuncSeparate");
295
0
    if (IsContextLost())
296
0
        return;
297
0
298
0
    if (!ValidateBlendFuncEnums(this, srcRGB, srcAlpha, dstRGB, dstAlpha))
299
0
       return;
300
0
301
0
    // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
302
0
    // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
303
0
    if (!ValidateBlendFuncEnumsCompatibility(srcRGB, dstRGB, "srcRGB and dstRGB"))
304
0
        return;
305
0
306
0
    gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
307
0
}
308
309
GLenum
310
WebGLContext::CheckFramebufferStatus(GLenum target)
311
0
{
312
0
    const FuncScope funcScope(*this, "checkFramebufferStatus");
313
0
    if (IsContextLost())
314
0
        return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
315
0
316
0
    if (!ValidateFramebufferTarget(target))
317
0
        return 0;
318
0
319
0
    WebGLFramebuffer* fb;
320
0
    switch (target) {
321
0
    case LOCAL_GL_FRAMEBUFFER:
322
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
323
0
        fb = mBoundDrawFramebuffer;
324
0
        break;
325
0
326
0
    case LOCAL_GL_READ_FRAMEBUFFER:
327
0
        fb = mBoundReadFramebuffer;
328
0
        break;
329
0
330
0
    default:
331
0
        MOZ_CRASH("GFX: Bad target.");
332
0
    }
333
0
334
0
    if (!fb)
335
0
        return LOCAL_GL_FRAMEBUFFER_COMPLETE;
336
0
337
0
    return fb->CheckFramebufferStatus().get();
338
0
}
339
340
already_AddRefed<WebGLProgram>
341
WebGLContext::CreateProgram()
342
0
{
343
0
    const FuncScope funcScope(*this, "createProgram");
344
0
    if (IsContextLost())
345
0
        return nullptr;
346
0
    RefPtr<WebGLProgram> globj = new WebGLProgram(this);
347
0
    return globj.forget();
348
0
}
349
350
already_AddRefed<WebGLShader>
351
WebGLContext::CreateShader(GLenum type)
352
0
{
353
0
    const FuncScope funcScope(*this, "createShader");
354
0
    if (IsContextLost())
355
0
        return nullptr;
356
0
357
0
    if (type != LOCAL_GL_VERTEX_SHADER &&
358
0
        type != LOCAL_GL_FRAGMENT_SHADER)
359
0
    {
360
0
        ErrorInvalidEnumInfo("type", type);
361
0
        return nullptr;
362
0
    }
363
0
364
0
    RefPtr<WebGLShader> shader = new WebGLShader(this, type);
365
0
    return shader.forget();
366
0
}
367
368
void
369
WebGLContext::CullFace(GLenum face)
370
0
{
371
0
    const FuncScope funcScope(*this, "cullFace");
372
0
    if (IsContextLost())
373
0
        return;
374
0
375
0
    if (!ValidateFaceEnum(face))
376
0
        return;
377
0
378
0
    gl->fCullFace(face);
379
0
}
380
381
void
382
WebGLContext::DeleteFramebuffer(WebGLFramebuffer* fbuf)
383
0
{
384
0
    const FuncScope funcScope(*this, "deleteFramebuffer");
385
0
    if (!ValidateDeleteObject(fbuf))
386
0
        return;
387
0
388
0
    fbuf->RequestDelete();
389
0
390
0
    if (mBoundReadFramebuffer == mBoundDrawFramebuffer) {
391
0
        if (mBoundDrawFramebuffer == fbuf) {
392
0
            BindFramebuffer(LOCAL_GL_FRAMEBUFFER,
393
0
                            static_cast<WebGLFramebuffer*>(nullptr));
394
0
        }
395
0
    } else if (mBoundDrawFramebuffer == fbuf) {
396
0
        BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER,
397
0
                        static_cast<WebGLFramebuffer*>(nullptr));
398
0
    } else if (mBoundReadFramebuffer == fbuf) {
399
0
        BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER,
400
0
                        static_cast<WebGLFramebuffer*>(nullptr));
401
0
    }
402
0
}
403
404
void
405
WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer* rbuf)
406
0
{
407
0
    const FuncScope funcScope(*this, "deleteRenderbuffer");
408
0
    if (!ValidateDeleteObject(rbuf))
409
0
        return;
410
0
411
0
    if (mBoundDrawFramebuffer)
412
0
        mBoundDrawFramebuffer->DetachRenderbuffer(rbuf);
413
0
414
0
    if (mBoundReadFramebuffer)
415
0
        mBoundReadFramebuffer->DetachRenderbuffer(rbuf);
416
0
417
0
    rbuf->InvalidateStatusOfAttachedFBs();
418
0
419
0
    if (mBoundRenderbuffer == rbuf)
420
0
        BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nullptr);
421
0
422
0
    rbuf->RequestDelete();
423
0
}
424
425
void
426
WebGLContext::DeleteTexture(WebGLTexture* tex)
427
0
{
428
0
    const FuncScope funcScope(*this, "deleteTexture");
429
0
    if (!ValidateDeleteObject(tex))
430
0
        return;
431
0
432
0
    if (mBoundDrawFramebuffer)
433
0
        mBoundDrawFramebuffer->DetachTexture(tex);
434
0
435
0
    if (mBoundReadFramebuffer)
436
0
        mBoundReadFramebuffer->DetachTexture(tex);
437
0
438
0
    GLuint activeTexture = mActiveTexture;
439
0
    for (uint32_t i = 0; i < mGLMaxTextureUnits; i++) {
440
0
        if (mBound2DTextures[i] == tex ||
441
0
            mBoundCubeMapTextures[i] == tex ||
442
0
            mBound3DTextures[i] == tex ||
443
0
            mBound2DArrayTextures[i] == tex)
444
0
        {
445
0
            ActiveTexture(LOCAL_GL_TEXTURE0 + i);
446
0
            BindTexture(tex->Target().get(), nullptr);
447
0
        }
448
0
    }
449
0
    ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
450
0
451
0
    tex->RequestDelete();
452
0
}
453
454
void
455
WebGLContext::DeleteProgram(WebGLProgram* prog)
456
0
{
457
0
    const FuncScope funcScope(*this, "deleteProgram");
458
0
    if (!ValidateDeleteObject(prog))
459
0
        return;
460
0
461
0
    prog->RequestDelete();
462
0
}
463
464
void
465
WebGLContext::DeleteShader(WebGLShader* shader)
466
0
{
467
0
    const FuncScope funcScope(*this, "deleteShader");
468
0
    if (!ValidateDeleteObject(shader))
469
0
        return;
470
0
471
0
    shader->RequestDelete();
472
0
}
473
474
void
475
WebGLContext::DetachShader(WebGLProgram& program, const WebGLShader& shader)
476
0
{
477
0
    const FuncScope funcScope(*this, "detachShader");
478
0
    if (IsContextLost())
479
0
        return;
480
0
481
0
    // It's valid to attempt to detach a deleted shader, since it's still a
482
0
    // shader.
483
0
    if (!ValidateObject("program", program) ||
484
0
        !ValidateObjectAllowDeleted("shader", shader))
485
0
    {
486
0
        return;
487
0
    }
488
0
489
0
    program.DetachShader(&shader);
490
0
}
491
492
static bool
493
ValidateComparisonEnum(WebGLContext& webgl, const GLenum func)
494
0
{
495
0
    switch (func) {
496
0
    case LOCAL_GL_NEVER:
497
0
    case LOCAL_GL_LESS:
498
0
    case LOCAL_GL_LEQUAL:
499
0
    case LOCAL_GL_GREATER:
500
0
    case LOCAL_GL_GEQUAL:
501
0
    case LOCAL_GL_EQUAL:
502
0
    case LOCAL_GL_NOTEQUAL:
503
0
    case LOCAL_GL_ALWAYS:
504
0
        return true;
505
0
506
0
    default:
507
0
        webgl.ErrorInvalidEnumInfo("func", func);
508
0
        return false;
509
0
    }
510
0
}
511
512
void
513
WebGLContext::DepthFunc(GLenum func)
514
0
{
515
0
    const FuncScope funcScope(*this, "depthFunc");
516
0
    if (IsContextLost())
517
0
        return;
518
0
519
0
    if (!ValidateComparisonEnum(*this, func))
520
0
        return;
521
0
522
0
    gl->fDepthFunc(func);
523
0
}
524
525
void
526
WebGLContext::DepthRange(GLfloat zNear, GLfloat zFar)
527
0
{
528
0
    const FuncScope funcScope(*this, "depthRange");
529
0
    if (IsContextLost())
530
0
        return;
531
0
532
0
    if (zNear > zFar)
533
0
        return ErrorInvalidOperation("the near value is greater than the far value!");
534
0
535
0
    gl->fDepthRange(zNear, zFar);
536
0
}
537
538
void
539
WebGLContext::FramebufferRenderbuffer(GLenum target, GLenum attachment,
540
                                      GLenum rbtarget, WebGLRenderbuffer* wrb)
541
0
{
542
0
    const FuncScope funcScope(*this, "framebufferRenderbuffer");
543
0
    if (IsContextLost())
544
0
        return;
545
0
546
0
    if (!ValidateFramebufferTarget(target))
547
0
        return;
548
0
549
0
    WebGLFramebuffer* fb;
550
0
    switch (target) {
551
0
    case LOCAL_GL_FRAMEBUFFER:
552
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
553
0
        fb = mBoundDrawFramebuffer;
554
0
        break;
555
0
556
0
    case LOCAL_GL_READ_FRAMEBUFFER:
557
0
        fb = mBoundReadFramebuffer;
558
0
        break;
559
0
560
0
    default:
561
0
        MOZ_CRASH("GFX: Bad target.");
562
0
    }
563
0
564
0
    if (!fb)
565
0
        return ErrorInvalidOperation("Cannot modify framebuffer 0.");
566
0
567
0
    fb->FramebufferRenderbuffer(attachment, rbtarget, wrb);
568
0
}
569
570
void
571
WebGLContext::FramebufferTexture2D(GLenum target,
572
                                   GLenum attachment,
573
                                   GLenum textarget,
574
                                   WebGLTexture* tobj,
575
                                   GLint level)
576
0
{
577
0
    const FuncScope funcScope(*this, "framebufferTexture2D");
578
0
    if (IsContextLost())
579
0
        return;
580
0
581
0
    if (!ValidateFramebufferTarget(target))
582
0
        return;
583
0
584
0
    WebGLFramebuffer* fb;
585
0
    switch (target) {
586
0
    case LOCAL_GL_FRAMEBUFFER:
587
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
588
0
        fb = mBoundDrawFramebuffer;
589
0
        break;
590
0
591
0
    case LOCAL_GL_READ_FRAMEBUFFER:
592
0
        fb = mBoundReadFramebuffer;
593
0
        break;
594
0
595
0
    default:
596
0
        MOZ_CRASH("GFX: Bad target.");
597
0
    }
598
0
599
0
    if (!fb)
600
0
        return ErrorInvalidOperation("Cannot modify framebuffer 0.");
601
0
602
0
    fb->FramebufferTexture2D(attachment, textarget, tobj, level);
603
0
}
604
605
void
606
WebGLContext::FrontFace(GLenum mode)
607
0
{
608
0
    const FuncScope funcScope(*this, "frontFace");
609
0
    if (IsContextLost())
610
0
        return;
611
0
612
0
    switch (mode) {
613
0
        case LOCAL_GL_CW:
614
0
        case LOCAL_GL_CCW:
615
0
            break;
616
0
        default:
617
0
            return ErrorInvalidEnumInfo("mode", mode);
618
0
    }
619
0
620
0
    gl->fFrontFace(mode);
621
0
}
622
623
already_AddRefed<WebGLActiveInfo>
624
WebGLContext::GetActiveAttrib(const WebGLProgram& prog, GLuint index)
625
0
{
626
0
    const FuncScope funcScope(*this, "getActiveAttrib");
627
0
    if (IsContextLost())
628
0
        return nullptr;
629
0
630
0
    if (!ValidateObject("program", prog))
631
0
        return nullptr;
632
0
633
0
    return prog.GetActiveAttrib(index);
634
0
}
635
636
already_AddRefed<WebGLActiveInfo>
637
WebGLContext::GetActiveUniform(const WebGLProgram& prog, GLuint index)
638
0
{
639
0
    const FuncScope funcScope(*this, "getActiveUniform");
640
0
    if (IsContextLost())
641
0
        return nullptr;
642
0
643
0
    if (!ValidateObject("program", prog))
644
0
        return nullptr;
645
0
646
0
    return prog.GetActiveUniform(index);
647
0
}
648
649
void
650
WebGLContext::GetAttachedShaders(const WebGLProgram& prog,
651
                                 dom::Nullable<nsTArray<RefPtr<WebGLShader>>>& retval)
652
0
{
653
0
    retval.SetNull();
654
0
    const FuncScope funcScope(*this, "getAttachedShaders");
655
0
    if (IsContextLost())
656
0
        return;
657
0
658
0
    if (!ValidateObject("prog", prog))
659
0
        return;
660
0
661
0
    prog.GetAttachedShaders(&retval.SetValue());
662
0
}
663
664
GLint
665
WebGLContext::GetAttribLocation(const WebGLProgram& prog, const nsAString& name)
666
0
{
667
0
    const FuncScope funcScope(*this, "getAttribLocation");
668
0
    if (IsContextLost())
669
0
        return -1;
670
0
671
0
    if (!ValidateObject("program", prog))
672
0
        return -1;
673
0
674
0
    return prog.GetAttribLocation(name);
675
0
}
676
677
JS::Value
678
WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
679
0
{
680
0
    const FuncScope funcScope(*this, "getBufferParameter");
681
0
    if (IsContextLost())
682
0
        return JS::NullValue();
683
0
684
0
    const auto& slot = ValidateBufferSlot(target);
685
0
    if (!slot)
686
0
        return JS::NullValue();
687
0
    const auto& buffer = *slot;
688
0
689
0
    if (!buffer) {
690
0
        ErrorInvalidOperation("Buffer for `target` is null.");
691
0
        return JS::NullValue();
692
0
    }
693
0
694
0
    switch (pname) {
695
0
    case LOCAL_GL_BUFFER_SIZE:
696
0
        return JS::NumberValue(buffer->ByteLength());
697
0
698
0
    case LOCAL_GL_BUFFER_USAGE:
699
0
        return JS::NumberValue(buffer->Usage());
700
0
701
0
    default:
702
0
        ErrorInvalidEnumInfo("pname", pname);
703
0
        return JS::NullValue();
704
0
    }
705
0
}
706
707
JS::Value
708
WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx,
709
                                                GLenum target,
710
                                                GLenum attachment,
711
                                                GLenum pname,
712
                                                ErrorResult& rv)
713
0
{
714
0
    const FuncScope funcScope(*this, "getFramebufferAttachmentParameter");
715
0
    if (IsContextLost())
716
0
        return JS::NullValue();
717
0
718
0
    if (!ValidateFramebufferTarget(target))
719
0
        return JS::NullValue();
720
0
721
0
    WebGLFramebuffer* fb;
722
0
    switch (target) {
723
0
    case LOCAL_GL_FRAMEBUFFER:
724
0
    case LOCAL_GL_DRAW_FRAMEBUFFER:
725
0
        fb = mBoundDrawFramebuffer;
726
0
        break;
727
0
728
0
    case LOCAL_GL_READ_FRAMEBUFFER:
729
0
        fb = mBoundReadFramebuffer;
730
0
        break;
731
0
732
0
    default:
733
0
        MOZ_CRASH("GFX: Bad target.");
734
0
    }
735
0
736
0
    if (fb)
737
0
        return fb->GetAttachmentParameter(cx, target, attachment, pname, &rv);
738
0
739
0
    ////////////////////////////////////
740
0
741
0
    if (!IsWebGL2()) {
742
0
        ErrorInvalidOperation("Querying against the default framebuffer is not"
743
0
                              " allowed in WebGL 1.");
744
0
        return JS::NullValue();
745
0
    }
746
0
747
0
    switch (attachment) {
748
0
    case LOCAL_GL_BACK:
749
0
    case LOCAL_GL_DEPTH:
750
0
    case LOCAL_GL_STENCIL:
751
0
        break;
752
0
753
0
    default:
754
0
        ErrorInvalidEnum("For the default framebuffer, can only query COLOR, DEPTH,"
755
0
                         " or STENCIL.");
756
0
        return JS::NullValue();
757
0
    }
758
0
759
0
    switch (pname) {
760
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
761
0
        switch (attachment) {
762
0
        case LOCAL_GL_BACK:
763
0
            break;
764
0
        case LOCAL_GL_DEPTH:
765
0
            if (!mOptions.depth) {
766
0
              return JS::Int32Value(LOCAL_GL_NONE);
767
0
            }
768
0
            break;
769
0
        case LOCAL_GL_STENCIL:
770
0
            if (!mOptions.stencil) {
771
0
              return JS::Int32Value(LOCAL_GL_NONE);
772
0
            }
773
0
            break;
774
0
        default:
775
0
            ErrorInvalidEnum("With the default framebuffer, can only query COLOR, DEPTH,"
776
0
                             " or STENCIL for GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE");
777
0
            return JS::NullValue();
778
0
        }
779
0
        return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT);
780
0
781
0
    ////////////////
782
0
783
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
784
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
785
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
786
0
        if (attachment == LOCAL_GL_BACK)
787
0
            return JS::NumberValue(8);
788
0
        return JS::NumberValue(0);
789
0
790
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
791
0
        if (attachment == LOCAL_GL_BACK) {
792
0
            if (mOptions.alpha) {
793
0
                return JS::NumberValue(8);
794
0
            }
795
0
            ErrorInvalidOperation("The default framebuffer doesn't contain an alpha buffer");
796
0
            return JS::NullValue();
797
0
        }
798
0
        return JS::NumberValue(0);
799
0
800
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
801
0
        if (attachment == LOCAL_GL_DEPTH) {
802
0
            if (mOptions.depth) {
803
0
                return JS::NumberValue(24);
804
0
            }
805
0
            ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
806
0
            return JS::NullValue();
807
0
        }
808
0
        return JS::NumberValue(0);
809
0
810
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
811
0
        if (attachment == LOCAL_GL_STENCIL) {
812
0
            if (mOptions.stencil) {
813
0
                return JS::NumberValue(8);
814
0
            }
815
0
            ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
816
0
            return JS::NullValue();
817
0
        }
818
0
        return JS::NumberValue(0);
819
0
820
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
821
0
        if (attachment == LOCAL_GL_STENCIL) {
822
0
            if (mOptions.stencil) {
823
0
                return JS::NumberValue(LOCAL_GL_UNSIGNED_INT);
824
0
            }
825
0
            ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
826
0
        } else if (attachment == LOCAL_GL_DEPTH) {
827
0
            if (mOptions.depth) {
828
0
                return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED);
829
0
            }
830
0
            ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
831
0
        } else { // LOCAL_GL_BACK
832
0
            return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED);
833
0
        }
834
0
        return JS::NullValue();
835
0
836
0
    case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
837
0
        if (attachment == LOCAL_GL_STENCIL) {
838
0
            if (!mOptions.stencil) {
839
0
                ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer");
840
0
                return JS::NullValue();
841
0
            }
842
0
        } else if (attachment == LOCAL_GL_DEPTH) {
843
0
            if (!mOptions.depth) {
844
0
                ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer");
845
0
                return JS::NullValue();
846
0
            }
847
0
        }
848
0
        return JS::NumberValue(LOCAL_GL_LINEAR);
849
0
    }
850
0
851
0
    ErrorInvalidEnumInfo("pname", pname);
852
0
    return JS::NullValue();
853
0
}
854
855
JS::Value
856
WebGLContext::GetRenderbufferParameter(GLenum target, GLenum pname)
857
0
{
858
0
    const FuncScope funcScope(*this, "getRenderbufferParameter");
859
0
    if (IsContextLost())
860
0
        return JS::NullValue();
861
0
862
0
    if (target != LOCAL_GL_RENDERBUFFER) {
863
0
        ErrorInvalidEnumInfo("target", target);
864
0
        return JS::NullValue();
865
0
    }
866
0
867
0
    if (!mBoundRenderbuffer) {
868
0
        ErrorInvalidOperation("No renderbuffer is bound.");
869
0
        return JS::NullValue();
870
0
    }
871
0
872
0
    switch (pname) {
873
0
    case LOCAL_GL_RENDERBUFFER_SAMPLES:
874
0
        if (!IsWebGL2())
875
0
            break;
876
0
        MOZ_FALLTHROUGH;
877
0
878
0
    case LOCAL_GL_RENDERBUFFER_WIDTH:
879
0
    case LOCAL_GL_RENDERBUFFER_HEIGHT:
880
0
    case LOCAL_GL_RENDERBUFFER_RED_SIZE:
881
0
    case LOCAL_GL_RENDERBUFFER_GREEN_SIZE:
882
0
    case LOCAL_GL_RENDERBUFFER_BLUE_SIZE:
883
0
    case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE:
884
0
    case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE:
885
0
    case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE:
886
0
    case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT:
887
0
    {
888
0
        // RB emulation means we have to ask the RB itself.
889
0
        GLint i = mBoundRenderbuffer->GetRenderbufferParameter(target, pname);
890
0
        return JS::Int32Value(i);
891
0
    }
892
0
893
0
    default:
894
0
        break;
895
0
    }
896
0
897
0
    ErrorInvalidEnumInfo("pname", pname);
898
0
    return JS::NullValue();
899
0
}
900
901
already_AddRefed<WebGLTexture>
902
WebGLContext::CreateTexture()
903
0
{
904
0
    const FuncScope funcScope(*this, "createTexture");
905
0
    if (IsContextLost())
906
0
        return nullptr;
907
0
908
0
    GLuint tex = 0;
909
0
    gl->fGenTextures(1, &tex);
910
0
911
0
    RefPtr<WebGLTexture> globj = new WebGLTexture(this, tex);
912
0
    return globj.forget();
913
0
}
914
915
static GLenum
916
GetAndClearError(GLenum* errorVar)
917
0
{
918
0
    MOZ_ASSERT(errorVar);
919
0
    GLenum ret = *errorVar;
920
0
    *errorVar = LOCAL_GL_NO_ERROR;
921
0
    return ret;
922
0
}
923
924
GLenum
925
WebGLContext::GetError()
926
0
{
927
0
    const FuncScope funcScope(*this, "getError");
928
0
    /* WebGL 1.0: Section 5.14.3: Setting and getting state:
929
0
     *   If the context's webgl context lost flag is set, returns
930
0
     *   CONTEXT_LOST_WEBGL the first time this method is called.
931
0
     *   Afterward, returns NO_ERROR until the context has been
932
0
     *   restored.
933
0
     *
934
0
     * WEBGL_lose_context:
935
0
     *   [When this extension is enabled: ] loseContext and
936
0
     *   restoreContext are allowed to generate INVALID_OPERATION errors
937
0
     *   even when the context is lost.
938
0
     */
939
0
940
0
    if (IsContextLost()) {
941
0
        if (mEmitContextLostErrorOnce) {
942
0
            mEmitContextLostErrorOnce = false;
943
0
            return LOCAL_GL_CONTEXT_LOST_WEBGL;
944
0
        }
945
0
        // Don't return yet, since WEBGL_lose_contexts contradicts the
946
0
        // original spec, and allows error generation while lost.
947
0
    }
948
0
949
0
    GLenum err = GetAndClearError(&mWebGLError);
950
0
    if (err != LOCAL_GL_NO_ERROR)
951
0
        return err;
952
0
953
0
    if (IsContextLost())
954
0
        return LOCAL_GL_NO_ERROR;
955
0
956
0
    // Either no WebGL-side error, or it's already been cleared.
957
0
    // UnderlyingGL-side errors, now.
958
0
959
0
    GetAndFlushUnderlyingGLErrors();
960
0
961
0
    err = GetAndClearError(&mUnderlyingGLError);
962
0
    return err;
963
0
}
964
965
JS::Value
966
WebGLContext::GetProgramParameter(const WebGLProgram& prog, GLenum pname)
967
0
{
968
0
    const FuncScope funcScope(*this, "getProgramParameter");
969
0
    if (IsContextLost())
970
0
        return JS::NullValue();
971
0
972
0
    if (!ValidateObjectAllowDeleted("program", prog))
973
0
        return JS::NullValue();
974
0
975
0
    return prog.GetProgramParameter(pname);
976
0
}
977
978
void
979
WebGLContext::GetProgramInfoLog(const WebGLProgram& prog, nsAString& retval)
980
0
{
981
0
    retval.SetIsVoid(true);
982
0
    const FuncScope funcScope(*this, "getProgramInfoLog");
983
0
984
0
    if (IsContextLost())
985
0
        return;
986
0
987
0
    if (!ValidateObject("program", prog))
988
0
        return;
989
0
990
0
    prog.GetProgramInfoLog(&retval);
991
0
}
992
993
JS::Value
994
WebGLContext::GetUniform(JSContext* js, const WebGLProgram& prog,
995
                         const WebGLUniformLocation& loc)
996
0
{
997
0
    const FuncScope funcScope(*this, "getUniform");
998
0
    if (IsContextLost())
999
0
        return JS::NullValue();
1000
0
1001
0
    if (!ValidateObject("program", prog))
1002
0
        return JS::NullValue();
1003
0
1004
0
    if (!ValidateObjectAllowDeleted("location", loc))
1005
0
        return JS::NullValue();
1006
0
1007
0
    if (!loc.ValidateForProgram(&prog))
1008
0
        return JS::NullValue();
1009
0
1010
0
    return loc.GetUniform(js);
1011
0
}
1012
1013
already_AddRefed<WebGLUniformLocation>
1014
WebGLContext::GetUniformLocation(const WebGLProgram& prog, const nsAString& name)
1015
0
{
1016
0
    const FuncScope funcScope(*this, "getUniformLocation");
1017
0
    if (IsContextLost())
1018
0
        return nullptr;
1019
0
1020
0
    if (!ValidateObject("program", prog))
1021
0
        return nullptr;
1022
0
1023
0
    return prog.GetUniformLocation(name);
1024
0
}
1025
1026
void
1027
WebGLContext::Hint(GLenum target, GLenum mode)
1028
0
{
1029
0
    const FuncScope funcScope(*this, "hint");
1030
0
    if (IsContextLost())
1031
0
        return;
1032
0
1033
0
    bool isValid = false;
1034
0
1035
0
    switch (target) {
1036
0
    case LOCAL_GL_GENERATE_MIPMAP_HINT:
1037
0
        mGenerateMipmapHint = mode;
1038
0
        isValid = true;
1039
0
1040
0
        // Deprecated and removed in desktop GL Core profiles.
1041
0
        if (gl->IsCoreProfile())
1042
0
            return;
1043
0
1044
0
        break;
1045
0
1046
0
    case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT:
1047
0
        if (IsWebGL2() ||
1048
0
            IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
1049
0
        {
1050
0
            isValid = true;
1051
0
        }
1052
0
        break;
1053
0
    }
1054
0
1055
0
    if (!isValid)
1056
0
        return ErrorInvalidEnumInfo("target", target);
1057
0
1058
0
    gl->fHint(target, mode);
1059
0
}
1060
1061
// -
1062
1063
bool
1064
WebGLContext::IsBuffer(const WebGLBuffer* const obj)
1065
0
{
1066
0
    const FuncScope funcScope(*this, "isBuffer");
1067
0
    if (!ValidateIsObject(obj))
1068
0
        return false;
1069
0
1070
0
    return gl->fIsBuffer(obj->mGLName);
1071
0
}
1072
1073
bool
1074
WebGLContext::IsFramebuffer(const WebGLFramebuffer* const obj)
1075
0
{
1076
0
    const FuncScope funcScope(*this, "isFramebuffer");
1077
0
    if (!ValidateIsObject(obj))
1078
0
        return false;
1079
0
1080
#ifdef ANDROID
1081
    if (gl->WorkAroundDriverBugs() &&
1082
        gl->Renderer() == GLRenderer::AndroidEmulator)
1083
    {
1084
        return obj->mIsFB;
1085
    }
1086
#endif
1087
1088
0
    return gl->fIsFramebuffer(obj->mGLName);
1089
0
}
1090
1091
bool
1092
WebGLContext::IsProgram(const WebGLProgram* const obj)
1093
0
{
1094
0
    const FuncScope funcScope(*this, "isProgram");
1095
0
    return ValidateIsObject(obj);
1096
0
}
1097
1098
bool
1099
WebGLContext::IsQuery(const WebGLQuery* const obj)
1100
0
{
1101
0
    const FuncScope funcScope(*this, "isQuery");
1102
0
    if (!ValidateIsObject(obj))
1103
0
        return false;
1104
0
1105
0
    return obj->IsQuery();
1106
0
}
1107
1108
bool
1109
WebGLContext::IsRenderbuffer(const WebGLRenderbuffer* const obj)
1110
0
{
1111
0
    const FuncScope funcScope(*this, "isRenderbuffer");
1112
0
    if (!ValidateIsObject(obj))
1113
0
        return false;
1114
0
1115
0
    return obj->mHasBeenBound;
1116
0
}
1117
1118
bool
1119
WebGLContext::IsShader(const WebGLShader* const obj)
1120
0
{
1121
0
    const FuncScope funcScope(*this, "isShader");
1122
0
    return ValidateIsObject(obj);
1123
0
}
1124
1125
bool
1126
WebGLContext::IsTexture(const WebGLTexture* const obj)
1127
0
{
1128
0
    const FuncScope funcScope(*this, "isTexture");
1129
0
    if (!ValidateIsObject(obj))
1130
0
        return false;
1131
0
1132
0
    return obj->IsTexture();
1133
0
}
1134
1135
bool
1136
WebGLContext::IsVertexArray(const WebGLVertexArray* const obj)
1137
0
{
1138
0
    const FuncScope funcScope(*this, "isVertexArray");
1139
0
    if (!ValidateIsObject(obj))
1140
0
        return false;
1141
0
1142
0
    return obj->IsVertexArray();
1143
0
}
1144
1145
// -
1146
1147
void
1148
WebGLContext::LinkProgram(WebGLProgram& prog)
1149
0
{
1150
0
    const FuncScope funcScope(*this, "linkProgram");
1151
0
    if (IsContextLost())
1152
0
        return;
1153
0
1154
0
    if (!ValidateObject("prog", prog))
1155
0
        return;
1156
0
1157
0
    prog.LinkProgram();
1158
0
1159
0
    if (!prog.IsLinked()) {
1160
0
        // If we failed to link, but `prog == mCurrentProgram`, we are *not* supposed to
1161
0
        // null out mActiveProgramLinkInfo.
1162
0
        return;
1163
0
    }
1164
0
1165
0
    if (&prog == mCurrentProgram) {
1166
0
        mActiveProgramLinkInfo = prog.LinkInfo();
1167
0
1168
0
        if (gl->WorkAroundDriverBugs() &&
1169
0
            gl->Vendor() == gl::GLVendor::NVIDIA)
1170
0
        {
1171
0
            gl->fUseProgram(prog.mGLName);
1172
0
        }
1173
0
    }
1174
0
}
1175
1176
void
1177
WebGLContext::PixelStorei(GLenum pname, GLint param)
1178
0
{
1179
0
    const FuncScope funcScope(*this, "pixelStorei");
1180
0
    if (IsContextLost())
1181
0
        return;
1182
0
1183
0
    if (IsWebGL2()) {
1184
0
        uint32_t* pValueSlot = nullptr;
1185
0
        switch (pname) {
1186
0
        case LOCAL_GL_UNPACK_IMAGE_HEIGHT:
1187
0
            pValueSlot = &mPixelStore_UnpackImageHeight;
1188
0
            break;
1189
0
1190
0
        case LOCAL_GL_UNPACK_SKIP_IMAGES:
1191
0
            pValueSlot = &mPixelStore_UnpackSkipImages;
1192
0
            break;
1193
0
1194
0
        case LOCAL_GL_UNPACK_ROW_LENGTH:
1195
0
            pValueSlot = &mPixelStore_UnpackRowLength;
1196
0
            break;
1197
0
1198
0
        case LOCAL_GL_UNPACK_SKIP_ROWS:
1199
0
            pValueSlot = &mPixelStore_UnpackSkipRows;
1200
0
            break;
1201
0
1202
0
        case LOCAL_GL_UNPACK_SKIP_PIXELS:
1203
0
            pValueSlot = &mPixelStore_UnpackSkipPixels;
1204
0
            break;
1205
0
1206
0
        case LOCAL_GL_PACK_ROW_LENGTH:
1207
0
            pValueSlot = &mPixelStore_PackRowLength;
1208
0
            break;
1209
0
1210
0
        case LOCAL_GL_PACK_SKIP_ROWS:
1211
0
            pValueSlot = &mPixelStore_PackSkipRows;
1212
0
            break;
1213
0
1214
0
        case LOCAL_GL_PACK_SKIP_PIXELS:
1215
0
            pValueSlot = &mPixelStore_PackSkipPixels;
1216
0
            break;
1217
0
        }
1218
0
1219
0
        if (pValueSlot) {
1220
0
            if (!ValidateNonNegative("param", param))
1221
0
                return;
1222
0
1223
0
            gl->fPixelStorei(pname, param);
1224
0
            *pValueSlot = param;
1225
0
            return;
1226
0
        }
1227
0
    }
1228
0
1229
0
    switch (pname) {
1230
0
    case UNPACK_FLIP_Y_WEBGL:
1231
0
        mPixelStore_FlipY = bool(param);
1232
0
        return;
1233
0
1234
0
    case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
1235
0
        mPixelStore_PremultiplyAlpha = bool(param);
1236
0
        return;
1237
0
1238
0
    case UNPACK_COLORSPACE_CONVERSION_WEBGL:
1239
0
        switch (param) {
1240
0
        case LOCAL_GL_NONE:
1241
0
        case BROWSER_DEFAULT_WEBGL:
1242
0
            mPixelStore_ColorspaceConversion = param;
1243
0
            return;
1244
0
1245
0
        default:
1246
0
            ErrorInvalidEnumInfo("colorspace conversion parameter", param);
1247
0
            return;
1248
0
        }
1249
0
1250
0
    case UNPACK_REQUIRE_FASTPATH:
1251
0
        if (IsExtensionEnabled(WebGLExtensionID::MOZ_debug)) {
1252
0
            mPixelStore_RequireFastPath = bool(param);
1253
0
            return;
1254
0
        }
1255
0
        break;
1256
0
1257
0
    case LOCAL_GL_PACK_ALIGNMENT:
1258
0
    case LOCAL_GL_UNPACK_ALIGNMENT:
1259
0
        switch (param) {
1260
0
        case 1:
1261
0
        case 2:
1262
0
        case 4:
1263
0
        case 8:
1264
0
            if (pname == LOCAL_GL_PACK_ALIGNMENT)
1265
0
                mPixelStore_PackAlignment = param;
1266
0
            else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
1267
0
                mPixelStore_UnpackAlignment = param;
1268
0
1269
0
            gl->fPixelStorei(pname, param);
1270
0
            return;
1271
0
1272
0
        default:
1273
0
            ErrorInvalidValue("Invalid pack/unpack alignment value.");
1274
0
            return;
1275
0
        }
1276
0
1277
0
1278
0
    default:
1279
0
        break;
1280
0
    }
1281
0
1282
0
    ErrorInvalidEnumInfo("pname", pname);
1283
0
}
1284
1285
bool
1286
WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x, GLint y,
1287
                                     GLsizei width, GLsizei height, GLenum format,
1288
                                     GLenum destType, void* dest, uint32_t destSize,
1289
                                     uint32_t rowStride)
1290
0
{
1291
0
    // On at least Win+NV, we'll get PBO errors if we don't have at least
1292
0
    // `rowStride * height` bytes available to read into.
1293
0
    const auto naiveBytesNeeded = CheckedUint32(rowStride) * height;
1294
0
    const bool isDangerCloseToEdge = (!naiveBytesNeeded.isValid() ||
1295
0
                                      naiveBytesNeeded.value() > destSize);
1296
0
    const bool useParanoidHandling = (gl->WorkAroundDriverBugs() &&
1297
0
                                      isDangerCloseToEdge &&
1298
0
                                      mBoundPixelPackBuffer);
1299
0
    if (!useParanoidHandling) {
1300
0
        gl->fReadPixels(x, y, width, height, format, destType, dest);
1301
0
        return true;
1302
0
    }
1303
0
1304
0
    // Read everything but the last row.
1305
0
    const auto bodyHeight = height - 1;
1306
0
    if (bodyHeight) {
1307
0
        gl->fReadPixels(x, y, width, bodyHeight, format, destType, dest);
1308
0
    }
1309
0
1310
0
    // Now read the last row.
1311
0
    gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 1);
1312
0
    gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
1313
0
    gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
1314
0
1315
0
    const auto tailRowOffset = (char*)dest + rowStride * bodyHeight;
1316
0
    gl->fReadPixels(x, y+bodyHeight, width, 1, format, destType, tailRowOffset);
1317
0
1318
0
    gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment);
1319
0
    gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength);
1320
0
    gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows);
1321
0
    return true;
1322
0
}
1323
1324
static bool
1325
GetJSScalarFromGLType(GLenum type, js::Scalar::Type* const out_scalarType)
1326
0
{
1327
0
    switch (type) {
1328
0
    case LOCAL_GL_BYTE:
1329
0
        *out_scalarType = js::Scalar::Int8;
1330
0
        return true;
1331
0
1332
0
    case LOCAL_GL_UNSIGNED_BYTE:
1333
0
        *out_scalarType = js::Scalar::Uint8;
1334
0
        return true;
1335
0
1336
0
    case LOCAL_GL_SHORT:
1337
0
        *out_scalarType = js::Scalar::Int16;
1338
0
        return true;
1339
0
1340
0
    case LOCAL_GL_HALF_FLOAT:
1341
0
    case LOCAL_GL_HALF_FLOAT_OES:
1342
0
    case LOCAL_GL_UNSIGNED_SHORT:
1343
0
    case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
1344
0
    case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
1345
0
    case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
1346
0
        *out_scalarType = js::Scalar::Uint16;
1347
0
        return true;
1348
0
1349
0
    case LOCAL_GL_UNSIGNED_INT:
1350
0
    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
1351
0
    case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
1352
0
    case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
1353
0
    case LOCAL_GL_UNSIGNED_INT_24_8:
1354
0
        *out_scalarType = js::Scalar::Uint32;
1355
0
        return true;
1356
0
    case LOCAL_GL_INT:
1357
0
        *out_scalarType = js::Scalar::Int32;
1358
0
        return true;
1359
0
1360
0
    case LOCAL_GL_FLOAT:
1361
0
        *out_scalarType = js::Scalar::Float32;
1362
0
        return true;
1363
0
1364
0
    default:
1365
0
        return false;
1366
0
    }
1367
0
}
1368
1369
bool
1370
WebGLContext::ReadPixels_SharedPrecheck(CallerType aCallerType,
1371
                                        ErrorResult& out_error)
1372
0
{
1373
0
    if (mCanvasElement &&
1374
0
        mCanvasElement->IsWriteOnly() &&
1375
0
        aCallerType != CallerType::System)
1376
0
    {
1377
0
        GenerateWarning("readPixels: Not allowed");
1378
0
        out_error.Throw(NS_ERROR_DOM_SECURITY_ERR);
1379
0
        return false;
1380
0
    }
1381
0
1382
0
    return true;
1383
0
}
1384
1385
bool
1386
WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
1387
                               uint8_t bytesPerPixel, uint32_t* const out_rowStride,
1388
                               uint32_t* const out_endOffset)
1389
0
{
1390
0
    if (!width || !height) {
1391
0
        *out_rowStride = 0;
1392
0
        *out_endOffset = 0;
1393
0
        return true;
1394
0
    }
1395
0
1396
0
    // GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
1397
0
1398
0
    const auto rowLength = (mPixelStore_PackRowLength ? mPixelStore_PackRowLength
1399
0
                                                      : width);
1400
0
    const auto skipPixels = mPixelStore_PackSkipPixels;
1401
0
    const auto skipRows = mPixelStore_PackSkipRows;
1402
0
    const auto alignment = mPixelStore_PackAlignment;
1403
0
1404
0
    const auto usedPixelsPerRow = CheckedUint32(skipPixels) + width;
1405
0
    const auto usedRowsPerImage = CheckedUint32(skipRows) + height;
1406
0
1407
0
    if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > rowLength) {
1408
0
        ErrorInvalidOperation("SKIP_PIXELS + width > ROW_LENGTH.");
1409
0
        return false;
1410
0
    }
1411
0
1412
0
    const auto rowLengthBytes = CheckedUint32(rowLength) * bytesPerPixel;
1413
0
    const auto rowStride = RoundUpToMultipleOf(rowLengthBytes, alignment);
1414
0
1415
0
    const auto usedBytesPerRow = usedPixelsPerRow * bytesPerPixel;
1416
0
    const auto usedBytesPerImage = (usedRowsPerImage - 1) * rowStride + usedBytesPerRow;
1417
0
1418
0
    if (!rowStride.isValid() || !usedBytesPerImage.isValid()) {
1419
0
        ErrorInvalidOperation("Invalid UNPACK_ params.");
1420
0
        return false;
1421
0
    }
1422
0
1423
0
    *out_rowStride = rowStride.value();
1424
0
    *out_endOffset = usedBytesPerImage.value();
1425
0
    return true;
1426
0
}
1427
1428
void
1429
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
1430
                         GLenum type, const dom::ArrayBufferView& dstView,
1431
                         GLuint dstElemOffset, CallerType aCallerType,
1432
                         ErrorResult& out_error)
1433
0
{
1434
0
    const FuncScope funcScope(*this, "readPixels");
1435
0
    if (IsContextLost())
1436
0
        return;
1437
0
1438
0
    if (!ReadPixels_SharedPrecheck(aCallerType, out_error))
1439
0
        return;
1440
0
1441
0
    if (mBoundPixelPackBuffer) {
1442
0
        ErrorInvalidOperation("PIXEL_PACK_BUFFER must be null.");
1443
0
        return;
1444
0
    }
1445
0
1446
0
    ////
1447
0
1448
0
    js::Scalar::Type reqScalarType;
1449
0
    if (!GetJSScalarFromGLType(type, &reqScalarType)) {
1450
0
        ErrorInvalidEnumInfo("type", type);
1451
0
        return;
1452
0
    }
1453
0
1454
0
    const auto& viewElemType = dstView.Type();
1455
0
    if (viewElemType != reqScalarType) {
1456
0
        ErrorInvalidOperation("`pixels` type does not match `type`.");
1457
0
        return;
1458
0
    }
1459
0
1460
0
    ////
1461
0
1462
0
    uint8_t* bytes;
1463
0
    size_t byteLen;
1464
0
    if (!ValidateArrayBufferView(dstView, dstElemOffset, 0, &bytes, &byteLen))
1465
0
        return;
1466
0
1467
0
    ////
1468
0
1469
0
    ReadPixelsImpl(x, y, width, height, format, type, bytes, byteLen);
1470
0
}
1471
1472
void
1473
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
1474
                         GLenum type, WebGLsizeiptr offset,
1475
                         CallerType aCallerType, ErrorResult& out_error)
1476
0
{
1477
0
    const FuncScope funcScope(*this, "readPixels");
1478
0
    if (IsContextLost())
1479
0
        return;
1480
0
1481
0
    if (!ReadPixels_SharedPrecheck(aCallerType, out_error))
1482
0
        return;
1483
0
1484
0
    const auto& buffer = ValidateBufferSelection(LOCAL_GL_PIXEL_PACK_BUFFER);
1485
0
    if (!buffer)
1486
0
        return;
1487
0
1488
0
    //////
1489
0
1490
0
    if (!ValidateNonNegative("offset", offset))
1491
0
        return;
1492
0
1493
0
    {
1494
0
        const auto bytesPerType = webgl::BytesPerPixel({LOCAL_GL_RED, type});
1495
0
1496
0
        if (offset % bytesPerType != 0) {
1497
0
            ErrorInvalidOperation("`offset` must be divisible by the size of `type`"
1498
0
                                  " in bytes.");
1499
0
            return;
1500
0
        }
1501
0
    }
1502
0
1503
0
    //////
1504
0
1505
0
    const auto bytesAvailable = buffer->ByteLength();
1506
0
    const auto checkedBytesAfterOffset = CheckedUint32(bytesAvailable) - offset;
1507
0
1508
0
    uint32_t bytesAfterOffset = 0;
1509
0
    if (checkedBytesAfterOffset.isValid()) {
1510
0
        bytesAfterOffset = checkedBytesAfterOffset.value();
1511
0
    }
1512
0
1513
0
    const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, buffer);
1514
0
1515
0
    ReadPixelsImpl(x, y, width, height, format, type, (void*)offset, bytesAfterOffset);
1516
0
1517
0
    buffer->ResetLastUpdateFenceId();
1518
0
}
1519
1520
static webgl::PackingInfo
1521
DefaultReadPixelPI(const webgl::FormatUsageInfo* usage)
1522
0
{
1523
0
    MOZ_ASSERT(usage->IsRenderable());
1524
0
1525
0
    switch (usage->format->componentType) {
1526
0
    case webgl::ComponentType::NormUInt:
1527
0
        return { LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE };
1528
0
1529
0
    case webgl::ComponentType::Int:
1530
0
        return { LOCAL_GL_RGBA_INTEGER, LOCAL_GL_INT };
1531
0
1532
0
    case webgl::ComponentType::UInt:
1533
0
        return { LOCAL_GL_RGBA_INTEGER, LOCAL_GL_UNSIGNED_INT };
1534
0
1535
0
    case webgl::ComponentType::Float:
1536
0
        return { LOCAL_GL_RGBA, LOCAL_GL_FLOAT };
1537
0
1538
0
    default:
1539
0
        MOZ_CRASH();
1540
0
    }
1541
0
}
1542
1543
static bool
1544
ArePossiblePackEnums(const WebGLContext* webgl, const webgl::PackingInfo& pi)
1545
0
{
1546
0
    // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
1547
0
    // combination for glReadPixels()...
1548
0
1549
0
    // So yeah, we are actually checking that these are valid as /unpack/ formats, instead
1550
0
    // of /pack/ formats here, but it should cover the INVALID_ENUM cases.
1551
0
    if (!webgl->mFormatUsage->AreUnpackEnumsValid(pi.format, pi.type))
1552
0
        return false;
1553
0
1554
0
    // Only valid when pulled from:
1555
0
    // * GLES 2.0.25 p105:
1556
0
    //   "table 3.4, excluding formats LUMINANCE and LUMINANCE_ALPHA."
1557
0
    // * GLES 3.0.4 p193:
1558
0
    //   "table 3.2, excluding formats DEPTH_COMPONENT and DEPTH_STENCIL."
1559
0
    switch (pi.format) {
1560
0
    case LOCAL_GL_LUMINANCE:
1561
0
    case LOCAL_GL_LUMINANCE_ALPHA:
1562
0
    case LOCAL_GL_DEPTH_COMPONENT:
1563
0
    case LOCAL_GL_DEPTH_STENCIL:
1564
0
        return false;
1565
0
    }
1566
0
1567
0
    if (pi.type == LOCAL_GL_UNSIGNED_INT_24_8)
1568
0
        return false;
1569
0
1570
0
    return true;
1571
0
}
1572
1573
webgl::PackingInfo
1574
WebGLContext::ValidImplementationColorReadPI(const webgl::FormatUsageInfo* usage) const
1575
0
{
1576
0
    const auto defaultPI = DefaultReadPixelPI(usage);
1577
0
1578
0
    // ES2_compatibility always returns RGBA/UNSIGNED_BYTE, so branch on actual IsGLES().
1579
0
    // Also OSX+NV generates an error here.
1580
0
    if (!gl->IsGLES())
1581
0
        return defaultPI;
1582
0
1583
0
    webgl::PackingInfo implPI;
1584
0
    gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, (GLint*)&implPI.format);
1585
0
    gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&implPI.type);
1586
0
1587
0
    if (!ArePossiblePackEnums(this, implPI))
1588
0
        return defaultPI;
1589
0
1590
0
    return implPI;
1591
0
}
1592
1593
static bool
1594
ValidateReadPixelsFormatAndType(const webgl::FormatUsageInfo* srcUsage,
1595
                                const webgl::PackingInfo& pi, gl::GLContext* gl,
1596
                                WebGLContext* webgl)
1597
0
{
1598
0
    if (!ArePossiblePackEnums(webgl, pi)) {
1599
0
        webgl->ErrorInvalidEnum("Unexpected format or type.");
1600
0
        return false;
1601
0
    }
1602
0
1603
0
    const auto defaultPI = DefaultReadPixelPI(srcUsage);
1604
0
    if (pi == defaultPI)
1605
0
        return true;
1606
0
1607
0
    ////
1608
0
1609
0
    // OpenGL ES 3.0.4 p194 - When the internal format of the rendering surface is
1610
0
    // RGB10_A2, a third combination of format RGBA and type UNSIGNED_INT_2_10_10_10_REV
1611
0
    // is accepted.
1612
0
1613
0
    if (webgl->IsWebGL2() &&
1614
0
        srcUsage->format->effectiveFormat == webgl::EffectiveFormat::RGB10_A2 &&
1615
0
        pi.format == LOCAL_GL_RGBA &&
1616
0
        pi.type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV)
1617
0
    {
1618
0
        return true;
1619
0
    }
1620
0
1621
0
    ////
1622
0
1623
0
    MOZ_ASSERT(gl->IsCurrent());
1624
0
    const auto implPI = webgl->ValidImplementationColorReadPI(srcUsage);
1625
0
    if (pi == implPI)
1626
0
        return true;
1627
0
1628
0
    ////
1629
0
1630
0
    webgl->ErrorInvalidOperation("Incompatible format or type.");
1631
0
    return false;
1632
0
}
1633
1634
void
1635
WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth, GLsizei rawHeight,
1636
                             GLenum packFormat, GLenum packType, void* dest,
1637
                             uint32_t dataLen)
1638
0
{
1639
0
    if (!ValidateNonNegative("width", rawWidth) ||
1640
0
        !ValidateNonNegative("height", rawHeight))
1641
0
    {
1642
0
        return;
1643
0
    }
1644
0
1645
0
    const uint32_t width(rawWidth);
1646
0
    const uint32_t height(rawHeight);
1647
0
1648
0
    //////
1649
0
1650
0
    const webgl::FormatUsageInfo* srcFormat;
1651
0
    uint32_t srcWidth;
1652
0
    uint32_t srcHeight;
1653
0
    if (!BindCurFBForColorRead(&srcFormat, &srcWidth, &srcHeight))
1654
0
        return;
1655
0
1656
0
    //////
1657
0
1658
0
    const webgl::PackingInfo pi = {packFormat, packType};
1659
0
    if (!ValidateReadPixelsFormatAndType(srcFormat, pi, gl, this))
1660
0
        return;
1661
0
1662
0
    uint8_t bytesPerPixel;
1663
0
    if (!webgl::GetBytesPerPixel(pi, &bytesPerPixel)) {
1664
0
        ErrorInvalidOperation("Unsupported format and type.");
1665
0
        return;
1666
0
    }
1667
0
1668
0
    //////
1669
0
1670
0
    uint32_t rowStride;
1671
0
    uint32_t bytesNeeded;
1672
0
    if (!ValidatePackSize(width, height, bytesPerPixel, &rowStride, &bytesNeeded))
1673
0
        return;
1674
0
1675
0
    if (bytesNeeded > dataLen) {
1676
0
        ErrorInvalidOperation("buffer too small");
1677
0
        return;
1678
0
    }
1679
0
1680
0
    ////
1681
0
1682
0
    int32_t readX, readY;
1683
0
    int32_t writeX, writeY;
1684
0
    int32_t rwWidth, rwHeight;
1685
0
    if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) ||
1686
0
        !Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight))
1687
0
    {
1688
0
        ErrorOutOfMemory("Bad subrect selection.");
1689
0
        return;
1690
0
    }
1691
0
1692
0
    ////////////////
1693
0
    // Now that the errors are out of the way, on to actually reading!
1694
0
1695
0
    if (!rwWidth || !rwHeight) {
1696
0
        // Disjoint rects, so we're done already.
1697
0
        DummyReadFramebufferOperation();
1698
0
        return;
1699
0
    }
1700
0
1701
0
    if (uint32_t(rwWidth) == width &&
1702
0
        uint32_t(rwHeight) == height)
1703
0
    {
1704
0
        DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat,
1705
0
                               packType, dest, dataLen, rowStride);
1706
0
        return;
1707
0
    }
1708
0
1709
0
    // Read request contains out-of-bounds pixels. Unfortunately:
1710
0
    // GLES 3.0.4 p194 "Obtaining Pixels from the Framebuffer":
1711
0
    // "If any of these pixels lies outside of the window allocated to the current GL
1712
0
    //  context, or outside of the image attached to the currently bound framebuffer
1713
0
    //  object, then the values obtained for those pixels are undefined."
1714
0
1715
0
    // This is a slow-path, so warn people away!
1716
0
    GenerateWarning("Out-of-bounds reads with readPixels are deprecated, and"
1717
0
                    " may be slow.");
1718
0
1719
0
    ////////////////////////////////////
1720
0
    // Read only the in-bounds pixels.
1721
0
1722
0
    if (IsWebGL2()) {
1723
0
        if (!mPixelStore_PackRowLength) {
1724
0
            gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH,
1725
0
                             mPixelStore_PackSkipPixels + width);
1726
0
        }
1727
0
        gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels + writeX);
1728
0
        gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows + writeY);
1729
0
1730
0
        DoReadPixelsAndConvert(srcFormat->format, readX, readY, rwWidth, rwHeight,
1731
0
                               packFormat, packType, dest, dataLen, rowStride);
1732
0
1733
0
        gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore_PackRowLength);
1734
0
        gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore_PackSkipPixels);
1735
0
        gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore_PackSkipRows);
1736
0
    } else {
1737
0
        // I *did* say "hilariously slow".
1738
0
1739
0
        uint8_t* row = (uint8_t*)dest + writeX * bytesPerPixel;
1740
0
        row += writeY * rowStride;
1741
0
        for (uint32_t j = 0; j < uint32_t(rwHeight); j++) {
1742
0
            DoReadPixelsAndConvert(srcFormat->format, readX, readY+j, rwWidth, 1,
1743
0
                                   packFormat, packType, row, dataLen, rowStride);
1744
0
            row += rowStride;
1745
0
        }
1746
0
    }
1747
0
}
1748
1749
void
1750
WebGLContext::RenderbufferStorage_base(GLenum target, GLsizei samples,
1751
                                       GLenum internalFormat,
1752
                                       GLsizei width, GLsizei height)
1753
0
{
1754
0
    if (IsContextLost())
1755
0
        return;
1756
0
1757
0
    if (target != LOCAL_GL_RENDERBUFFER) {
1758
0
        ErrorInvalidEnumInfo("target", target);
1759
0
        return;
1760
0
    }
1761
0
1762
0
    if (!mBoundRenderbuffer) {
1763
0
        ErrorInvalidOperation("Called on renderbuffer 0.");
1764
0
        return;
1765
0
    }
1766
0
1767
0
    if (!ValidateNonNegative("width", width) ||
1768
0
        !ValidateNonNegative("height", height) ||
1769
0
        !ValidateNonNegative("samples", samples))
1770
0
    {
1771
0
        return;
1772
0
    }
1773
0
1774
0
    mBoundRenderbuffer->RenderbufferStorage(uint32_t(samples), internalFormat,
1775
0
                                            uint32_t(width), uint32_t(height));
1776
0
}
1777
1778
void
1779
WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
1780
0
{
1781
0
    const FuncScope funcScope(*this, "scissor");
1782
0
    if (IsContextLost())
1783
0
        return;
1784
0
1785
0
    if (!ValidateNonNegative("width", width) ||
1786
0
        !ValidateNonNegative("height", height))
1787
0
    {
1788
0
        return;
1789
0
    }
1790
0
1791
0
    gl->fScissor(x, y, width, height);
1792
0
}
1793
1794
void
1795
WebGLContext::StencilFunc(GLenum func, GLint ref, GLuint mask)
1796
0
{
1797
0
    const FuncScope funcScope(*this, "stencilFunc");
1798
0
    if (IsContextLost())
1799
0
        return;
1800
0
1801
0
    if (!ValidateComparisonEnum(*this, func))
1802
0
        return;
1803
0
1804
0
    mStencilRefFront = ref;
1805
0
    mStencilRefBack = ref;
1806
0
    mStencilValueMaskFront = mask;
1807
0
    mStencilValueMaskBack = mask;
1808
0
1809
0
    gl->fStencilFunc(func, ref, mask);
1810
0
}
1811
1812
void
1813
WebGLContext::StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
1814
0
{
1815
0
    const FuncScope funcScope(*this, "stencilFuncSeparate");
1816
0
    if (IsContextLost())
1817
0
        return;
1818
0
1819
0
    if (!ValidateFaceEnum(face) ||
1820
0
        !ValidateComparisonEnum(*this, func))
1821
0
    {
1822
0
        return;
1823
0
    }
1824
0
1825
0
    switch (face) {
1826
0
        case LOCAL_GL_FRONT_AND_BACK:
1827
0
            mStencilRefFront = ref;
1828
0
            mStencilRefBack = ref;
1829
0
            mStencilValueMaskFront = mask;
1830
0
            mStencilValueMaskBack = mask;
1831
0
            break;
1832
0
        case LOCAL_GL_FRONT:
1833
0
            mStencilRefFront = ref;
1834
0
            mStencilValueMaskFront = mask;
1835
0
            break;
1836
0
        case LOCAL_GL_BACK:
1837
0
            mStencilRefBack = ref;
1838
0
            mStencilValueMaskBack = mask;
1839
0
            break;
1840
0
    }
1841
0
1842
0
    gl->fStencilFuncSeparate(face, func, ref, mask);
1843
0
}
1844
1845
void
1846
WebGLContext::StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass)
1847
0
{
1848
0
    const FuncScope funcScope(*this, "stencilOp");
1849
0
    if (IsContextLost())
1850
0
        return;
1851
0
1852
0
    if (!ValidateStencilOpEnum(sfail, "sfail") ||
1853
0
        !ValidateStencilOpEnum(dpfail, "dpfail") ||
1854
0
        !ValidateStencilOpEnum(dppass, "dppass"))
1855
0
        return;
1856
0
1857
0
    gl->fStencilOp(sfail, dpfail, dppass);
1858
0
}
1859
1860
void
1861
WebGLContext::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass)
1862
0
{
1863
0
    const FuncScope funcScope(*this, "stencilOpSeparate");
1864
0
    if (IsContextLost())
1865
0
        return;
1866
0
1867
0
    if (!ValidateFaceEnum(face) ||
1868
0
        !ValidateStencilOpEnum(sfail, "sfail") ||
1869
0
        !ValidateStencilOpEnum(dpfail, "dpfail") ||
1870
0
        !ValidateStencilOpEnum(dppass, "dppass"))
1871
0
        return;
1872
0
1873
0
    gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
1874
0
}
1875
1876
////////////////////////////////////////////////////////////////////////////////
1877
// Uniform setters.
1878
1879
class ValidateIfSampler
1880
{
1881
    const WebGLUniformLocation* const mLoc;
1882
    const size_t mDataCount;
1883
    const GLint* const mData;
1884
    bool mIsValidatedSampler;
1885
1886
public:
1887
    ValidateIfSampler(WebGLContext* webgl,
1888
                      WebGLUniformLocation* loc, size_t dataCount, const GLint* data,
1889
                      bool* const out_error)
1890
        : mLoc(loc)
1891
        , mDataCount(dataCount)
1892
        , mData(data)
1893
        , mIsValidatedSampler(false)
1894
0
    {
1895
0
        if (!mLoc->mInfo->mSamplerTexList) {
1896
0
            *out_error = false;
1897
0
            return;
1898
0
        }
1899
0
1900
0
        for (size_t i = 0; i < mDataCount; i++) {
1901
0
            const auto& val = mData[i];
1902
0
            if (val < 0 || uint32_t(val) >= webgl->GLMaxTextureUnits()) {
1903
0
                webgl->ErrorInvalidValue("This uniform location is a sampler, but %d"
1904
0
                                         " is not a valid texture unit.",
1905
0
                                         val);
1906
0
                *out_error = true;
1907
0
                return;
1908
0
            }
1909
0
        }
1910
0
1911
0
        mIsValidatedSampler = true;
1912
0
        *out_error = false;
1913
0
    }
1914
1915
0
    ~ValidateIfSampler() {
1916
0
        if (!mIsValidatedSampler)
1917
0
            return;
1918
0
1919
0
        auto& samplerValues = mLoc->mInfo->mSamplerValues;
1920
0
1921
0
        for (size_t i = 0; i < mDataCount; i++) {
1922
0
            const size_t curIndex = mLoc->mArrayIndex + i;
1923
0
            if (curIndex >= samplerValues.size())
1924
0
                break;
1925
0
1926
0
            samplerValues[curIndex] = mData[i];
1927
0
        }
1928
0
    }
1929
};
1930
1931
////////////////////
1932
1933
void
1934
WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
1935
0
{
1936
0
    const FuncScope funcScope(*this, "uniform1i");
1937
0
    if (!ValidateUniformSetter(loc, 1, LOCAL_GL_INT))
1938
0
        return;
1939
0
1940
0
    bool error;
1941
0
    const ValidateIfSampler validate(this, loc, 1, &a1, &error);
1942
0
    if (error)
1943
0
        return;
1944
0
1945
0
    gl->fUniform1i(loc->mLoc, a1);
1946
0
}
1947
1948
void
1949
WebGLContext::Uniform2i(WebGLUniformLocation* loc, GLint a1, GLint a2)
1950
0
{
1951
0
    const FuncScope funcScope(*this, "uniform2i");
1952
0
    if (!ValidateUniformSetter(loc, 2, LOCAL_GL_INT))
1953
0
        return;
1954
0
1955
0
    gl->fUniform2i(loc->mLoc, a1, a2);
1956
0
}
1957
1958
void
1959
WebGLContext::Uniform3i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3)
1960
0
{
1961
0
    const FuncScope funcScope(*this, "uniform3i");
1962
0
    if (!ValidateUniformSetter(loc, 3, LOCAL_GL_INT))
1963
0
        return;
1964
0
1965
0
    gl->fUniform3i(loc->mLoc, a1, a2, a3);
1966
0
}
1967
1968
void
1969
WebGLContext::Uniform4i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3,
1970
                        GLint a4)
1971
0
{
1972
0
    const FuncScope funcScope(*this, "uniform4i");
1973
0
    if (!ValidateUniformSetter(loc, 4, LOCAL_GL_INT))
1974
0
        return;
1975
0
1976
0
    gl->fUniform4i(loc->mLoc, a1, a2, a3, a4);
1977
0
}
1978
1979
//////////
1980
1981
void
1982
WebGLContext::Uniform1f(WebGLUniformLocation* loc, GLfloat a1)
1983
0
{
1984
0
    const FuncScope funcScope(*this, "uniform1f");
1985
0
    if (!ValidateUniformSetter(loc, 1, LOCAL_GL_FLOAT))
1986
0
        return;
1987
0
1988
0
    gl->fUniform1f(loc->mLoc, a1);
1989
0
}
1990
1991
void
1992
WebGLContext::Uniform2f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2)
1993
0
{
1994
0
    const FuncScope funcScope(*this, "uniform2f");
1995
0
    if (!ValidateUniformSetter(loc, 2, LOCAL_GL_FLOAT))
1996
0
        return;
1997
0
1998
0
    gl->fUniform2f(loc->mLoc, a1, a2);
1999
0
}
2000
2001
void
2002
WebGLContext::Uniform3f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
2003
                        GLfloat a3)
2004
0
{
2005
0
    const FuncScope funcScope(*this, "uniform3f");
2006
0
    if (!ValidateUniformSetter(loc, 3, LOCAL_GL_FLOAT))
2007
0
        return;
2008
0
2009
0
    gl->fUniform3f(loc->mLoc, a1, a2, a3);
2010
0
}
2011
2012
void
2013
WebGLContext::Uniform4f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
2014
                        GLfloat a3, GLfloat a4)
2015
0
{
2016
0
    const FuncScope funcScope(*this, "uniform4f");
2017
0
    if (!ValidateUniformSetter(loc, 4, LOCAL_GL_FLOAT))
2018
0
        return;
2019
0
2020
0
    gl->fUniform4f(loc->mLoc, a1, a2, a3, a4);
2021
0
}
2022
2023
////////////////////////////////////////
2024
// Array
2025
2026
static bool
2027
ValidateArrOffsetAndCount(WebGLContext* webgl, size_t elemsAvail,
2028
                          GLuint elemOffset, GLuint elemCountOverride,
2029
                          size_t* const out_elemCount)
2030
0
{
2031
0
    if (webgl->IsContextLost())
2032
0
        return false;
2033
0
2034
0
    if (elemOffset > elemsAvail) {
2035
0
        webgl->ErrorInvalidValue("Bad offset into list.");
2036
0
        return false;
2037
0
    }
2038
0
    elemsAvail -= elemOffset;
2039
0
2040
0
    if (elemCountOverride) {
2041
0
        if (elemCountOverride > elemsAvail) {
2042
0
            webgl->ErrorInvalidValue("Bad count override for sub-list.");
2043
0
            return false;
2044
0
        }
2045
0
        elemsAvail = elemCountOverride;
2046
0
    }
2047
0
2048
0
    *out_elemCount = elemsAvail;
2049
0
    return true;
2050
0
}
2051
2052
void
2053
WebGLContext::UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
2054
                         const Int32Arr& arr, GLuint elemOffset, GLuint elemCountOverride)
2055
0
{
2056
0
    const FuncScope funcScope(*this, funcName);
2057
0
2058
0
    size_t elemCount;
2059
0
    if (!ValidateArrOffsetAndCount(this, arr.elemCount, elemOffset,
2060
0
                                   elemCountOverride, &elemCount))
2061
0
    {
2062
0
        return;
2063
0
    }
2064
0
    const auto elemBytes = arr.elemBytes + elemOffset;
2065
0
2066
0
    uint32_t numElementsToUpload;
2067
0
    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_INT, elemCount,
2068
0
                                    &numElementsToUpload))
2069
0
    {
2070
0
        return;
2071
0
    }
2072
0
2073
0
    bool error;
2074
0
    const ValidateIfSampler samplerValidator(this, loc, numElementsToUpload,
2075
0
                                             elemBytes, &error);
2076
0
    if (error)
2077
0
        return;
2078
0
2079
0
    static const decltype(&gl::GLContext::fUniform1iv) kFuncList[] = {
2080
0
        &gl::GLContext::fUniform1iv,
2081
0
        &gl::GLContext::fUniform2iv,
2082
0
        &gl::GLContext::fUniform3iv,
2083
0
        &gl::GLContext::fUniform4iv
2084
0
    };
2085
0
    const auto func = kFuncList[N-1];
2086
0
2087
0
    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
2088
0
}
2089
2090
void
2091
WebGLContext::UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
2092
                          const Uint32Arr& arr, GLuint elemOffset,
2093
                          GLuint elemCountOverride)
2094
0
{
2095
0
    const FuncScope funcScope(*this, funcName);
2096
0
2097
0
    size_t elemCount;
2098
0
    if (!ValidateArrOffsetAndCount(this, arr.elemCount, elemOffset,
2099
0
                                   elemCountOverride, &elemCount))
2100
0
    {
2101
0
        return;
2102
0
    }
2103
0
    const auto elemBytes = arr.elemBytes + elemOffset;
2104
0
2105
0
    uint32_t numElementsToUpload;
2106
0
    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_UNSIGNED_INT, elemCount,
2107
0
                                    &numElementsToUpload))
2108
0
    {
2109
0
        return;
2110
0
    }
2111
0
    MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
2112
0
2113
0
    static const decltype(&gl::GLContext::fUniform1uiv) kFuncList[] = {
2114
0
        &gl::GLContext::fUniform1uiv,
2115
0
        &gl::GLContext::fUniform2uiv,
2116
0
        &gl::GLContext::fUniform3uiv,
2117
0
        &gl::GLContext::fUniform4uiv
2118
0
    };
2119
0
    const auto func = kFuncList[N-1];
2120
0
2121
0
    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
2122
0
}
2123
2124
void
2125
WebGLContext::UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
2126
                         const Float32Arr& arr, GLuint elemOffset,
2127
                         GLuint elemCountOverride)
2128
0
{
2129
0
    const FuncScope funcScope(*this, funcName);
2130
0
2131
0
    size_t elemCount;
2132
0
    if (!ValidateArrOffsetAndCount(this, arr.elemCount, elemOffset,
2133
0
                                   elemCountOverride, &elemCount))
2134
0
    {
2135
0
        return;
2136
0
    }
2137
0
    const auto elemBytes = arr.elemBytes + elemOffset;
2138
0
2139
0
    uint32_t numElementsToUpload;
2140
0
    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_FLOAT, elemCount,
2141
0
                                    &numElementsToUpload))
2142
0
    {
2143
0
        return;
2144
0
    }
2145
0
    MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
2146
0
2147
0
    static const decltype(&gl::GLContext::fUniform1fv) kFuncList[] = {
2148
0
        &gl::GLContext::fUniform1fv,
2149
0
        &gl::GLContext::fUniform2fv,
2150
0
        &gl::GLContext::fUniform3fv,
2151
0
        &gl::GLContext::fUniform4fv
2152
0
    };
2153
0
    const auto func = kFuncList[N-1];
2154
0
2155
0
    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
2156
0
}
2157
2158
static inline void
2159
MatrixAxBToRowMajor(const uint8_t width, const uint8_t height,
2160
                    const float* __restrict srcColMajor,
2161
                    float* __restrict dstRowMajor)
2162
0
{
2163
0
    for (uint8_t x = 0; x < width; ++x) {
2164
0
        for (uint8_t y = 0; y < height; ++y) {
2165
0
            dstRowMajor[y * width + x] = srcColMajor[x * height + y];
2166
0
        }
2167
0
    }
2168
0
}
2169
2170
void
2171
WebGLContext::UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
2172
                                 WebGLUniformLocation* loc, const bool transpose,
2173
                                 const Float32Arr& arr, GLuint elemOffset,
2174
                                 GLuint elemCountOverride)
2175
0
{
2176
0
    const FuncScope funcScope(*this, funcName);
2177
0
2178
0
    size_t elemCount;
2179
0
    if (!ValidateArrOffsetAndCount(this, arr.elemCount, elemOffset,
2180
0
                                   elemCountOverride, &elemCount))
2181
0
    {
2182
0
        return;
2183
0
    }
2184
0
    const auto elemBytes = arr.elemBytes + elemOffset;
2185
0
2186
0
    uint32_t numMatsToUpload;
2187
0
    if (!ValidateUniformMatrixArraySetter(loc, A, B, LOCAL_GL_FLOAT, elemCount,
2188
0
                                          transpose, &numMatsToUpload))
2189
0
    {
2190
0
        return;
2191
0
    }
2192
0
    MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
2193
0
2194
0
    ////
2195
0
2196
0
    bool uploadTranspose = transpose;
2197
0
    const float* uploadBytes = elemBytes;
2198
0
2199
0
    UniqueBuffer temp;
2200
0
    if (!transpose && gl->WorkAroundDriverBugs() && gl->IsANGLE() &&
2201
0
        gl->IsAtLeast(gl::ContextProfile::OpenGLES, 300))
2202
0
    {
2203
0
        // ANGLE is really slow at non-GL-transposed matrices.
2204
0
        const size_t kElemsPerMat = A * B;
2205
0
2206
0
        temp = malloc(numMatsToUpload * kElemsPerMat * sizeof(float));
2207
0
        if (!temp) {
2208
0
            ErrorOutOfMemory("Failed to alloc temporary buffer for transposition.");
2209
0
            return;
2210
0
        }
2211
0
2212
0
        auto srcItr = (const float*)elemBytes;
2213
0
        auto dstItr = (float*)temp.get();
2214
0
        const auto srcEnd = srcItr + numMatsToUpload * kElemsPerMat;
2215
0
2216
0
        while (srcItr != srcEnd) {
2217
0
            MatrixAxBToRowMajor(A, B, srcItr, dstItr);
2218
0
            srcItr += kElemsPerMat;
2219
0
            dstItr += kElemsPerMat;
2220
0
        }
2221
0
2222
0
        uploadBytes = (const float*)temp.get();
2223
0
        uploadTranspose = true;
2224
0
    }
2225
0
2226
0
    ////
2227
0
2228
0
    static const decltype(&gl::GLContext::fUniformMatrix2fv) kFuncList[] = {
2229
0
        &gl::GLContext::fUniformMatrix2fv,
2230
0
        &gl::GLContext::fUniformMatrix2x3fv,
2231
0
        &gl::GLContext::fUniformMatrix2x4fv,
2232
0
2233
0
        &gl::GLContext::fUniformMatrix3x2fv,
2234
0
        &gl::GLContext::fUniformMatrix3fv,
2235
0
        &gl::GLContext::fUniformMatrix3x4fv,
2236
0
2237
0
        &gl::GLContext::fUniformMatrix4x2fv,
2238
0
        &gl::GLContext::fUniformMatrix4x3fv,
2239
0
        &gl::GLContext::fUniformMatrix4fv
2240
0
    };
2241
0
    const auto func = kFuncList[3*(A-2) + (B-2)];
2242
0
2243
0
    (gl->*func)(loc->mLoc, numMatsToUpload, uploadTranspose, uploadBytes);
2244
0
}
2245
2246
////////////////////////////////////////////////////////////////////////////////
2247
2248
void
2249
WebGLContext::UseProgram(WebGLProgram* prog)
2250
0
{
2251
0
    const FuncScope funcScope(*this, "useProgram");
2252
0
    if (IsContextLost())
2253
0
        return;
2254
0
2255
0
    if (!prog) {
2256
0
        mCurrentProgram = nullptr;
2257
0
        mActiveProgramLinkInfo = nullptr;
2258
0
        return;
2259
0
    }
2260
0
2261
0
    if (!ValidateObject("prog", *prog))
2262
0
        return;
2263
0
2264
0
    if (prog->UseProgram()) {
2265
0
        mCurrentProgram = prog;
2266
0
        mActiveProgramLinkInfo = mCurrentProgram->LinkInfo();
2267
0
    }
2268
0
}
2269
2270
void
2271
WebGLContext::ValidateProgram(const WebGLProgram& prog)
2272
0
{
2273
0
    const FuncScope funcScope(*this, "validateProgram");
2274
0
    if (IsContextLost())
2275
0
        return;
2276
0
2277
0
    if (!ValidateObject("prog", prog))
2278
0
        return;
2279
0
2280
0
    prog.ValidateProgram();
2281
0
}
2282
2283
already_AddRefed<WebGLFramebuffer>
2284
WebGLContext::CreateFramebuffer()
2285
0
{
2286
0
    const FuncScope funcScope(*this, "createFramebuffer");
2287
0
    if (IsContextLost())
2288
0
        return nullptr;
2289
0
2290
0
    GLuint fbo = 0;
2291
0
    gl->fGenFramebuffers(1, &fbo);
2292
0
2293
0
    RefPtr<WebGLFramebuffer> globj = new WebGLFramebuffer(this, fbo);
2294
0
    return globj.forget();
2295
0
}
2296
2297
already_AddRefed<WebGLRenderbuffer>
2298
WebGLContext::CreateRenderbuffer()
2299
0
{
2300
0
    const FuncScope funcScope(*this, "createRenderbuffer");
2301
0
    if (IsContextLost())
2302
0
        return nullptr;
2303
0
2304
0
    RefPtr<WebGLRenderbuffer> globj = new WebGLRenderbuffer(this);
2305
0
    return globj.forget();
2306
0
}
2307
2308
void
2309
WebGLContext::Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
2310
0
{
2311
0
    const FuncScope funcScope(*this, "viewport");
2312
0
    if (IsContextLost())
2313
0
        return;
2314
0
2315
0
    if (!ValidateNonNegative("width", width) ||
2316
0
        !ValidateNonNegative("height", height))
2317
0
    {
2318
0
        return;
2319
0
    }
2320
0
2321
0
    width = std::min(width, (GLsizei)mGLMaxViewportDims[0]);
2322
0
    height = std::min(height, (GLsizei)mGLMaxViewportDims[1]);
2323
0
2324
0
    gl->fViewport(x, y, width, height);
2325
0
2326
0
    mViewportX = x;
2327
0
    mViewportY = y;
2328
0
    mViewportWidth = width;
2329
0
    mViewportHeight = height;
2330
0
}
2331
2332
void
2333
WebGLContext::CompileShader(WebGLShader& shader)
2334
0
{
2335
0
    const FuncScope funcScope(*this, "compileShader");
2336
0
    if (IsContextLost())
2337
0
        return;
2338
0
2339
0
    if (!ValidateObject("shader", shader))
2340
0
        return;
2341
0
2342
0
    shader.CompileShader();
2343
0
}
2344
2345
JS::Value
2346
WebGLContext::GetShaderParameter(const WebGLShader& shader, GLenum pname)
2347
0
{
2348
0
    const FuncScope funcScope(*this, "getShaderParameter");
2349
0
    if (IsContextLost())
2350
0
        return JS::NullValue();
2351
0
2352
0
    if (!ValidateObjectAllowDeleted("shader", shader))
2353
0
        return JS::NullValue();
2354
0
2355
0
    return shader.GetShaderParameter(pname);
2356
0
}
2357
2358
void
2359
WebGLContext::GetShaderInfoLog(const WebGLShader& shader, nsAString& retval)
2360
0
{
2361
0
    retval.SetIsVoid(true);
2362
0
    const FuncScope funcScope(*this, "getShaderInfoLog");
2363
0
2364
0
    if (IsContextLost())
2365
0
        return;
2366
0
2367
0
    if (!ValidateObject("shader", shader))
2368
0
        return;
2369
0
2370
0
    shader.GetShaderInfoLog(&retval);
2371
0
}
2372
2373
already_AddRefed<WebGLShaderPrecisionFormat>
2374
WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
2375
0
{
2376
0
    const FuncScope funcScope(*this, "getShaderPrecisionFormat");
2377
0
    if (IsContextLost())
2378
0
        return nullptr;
2379
0
2380
0
    switch (shadertype) {
2381
0
        case LOCAL_GL_FRAGMENT_SHADER:
2382
0
        case LOCAL_GL_VERTEX_SHADER:
2383
0
            break;
2384
0
        default:
2385
0
            ErrorInvalidEnumInfo("shadertype", shadertype);
2386
0
            return nullptr;
2387
0
    }
2388
0
2389
0
    switch (precisiontype) {
2390
0
        case LOCAL_GL_LOW_FLOAT:
2391
0
        case LOCAL_GL_MEDIUM_FLOAT:
2392
0
        case LOCAL_GL_HIGH_FLOAT:
2393
0
        case LOCAL_GL_LOW_INT:
2394
0
        case LOCAL_GL_MEDIUM_INT:
2395
0
        case LOCAL_GL_HIGH_INT:
2396
0
            break;
2397
0
        default:
2398
0
            ErrorInvalidEnumInfo("precisiontype", precisiontype);
2399
0
            return nullptr;
2400
0
    }
2401
0
2402
0
    GLint range[2], precision;
2403
0
2404
0
    if (mDisableFragHighP &&
2405
0
        shadertype == LOCAL_GL_FRAGMENT_SHADER &&
2406
0
        (precisiontype == LOCAL_GL_HIGH_FLOAT ||
2407
0
         precisiontype == LOCAL_GL_HIGH_INT))
2408
0
    {
2409
0
      precision = 0;
2410
0
      range[0] = 0;
2411
0
      range[1] = 0;
2412
0
    } else {
2413
0
      gl->fGetShaderPrecisionFormat(shadertype, precisiontype, range, &precision);
2414
0
    }
2415
0
2416
0
    RefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
2417
0
        = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
2418
0
    return retShaderPrecisionFormat.forget();
2419
0
}
2420
2421
void
2422
WebGLContext::GetShaderSource(const WebGLShader& shader, nsAString& retval)
2423
0
{
2424
0
    retval.SetIsVoid(true);
2425
0
    const FuncScope funcScope(*this, "getShaderSource");
2426
0
2427
0
    if (IsContextLost())
2428
0
        return;
2429
0
2430
0
    if (!ValidateObject("shader", shader))
2431
0
        return;
2432
0
2433
0
    shader.GetShaderSource(&retval);
2434
0
}
2435
2436
void
2437
WebGLContext::ShaderSource(WebGLShader& shader, const nsAString& source)
2438
0
{
2439
0
    const FuncScope funcScope(*this, "shaderSource");
2440
0
    if (IsContextLost())
2441
0
        return;
2442
0
2443
0
    if (!ValidateObject("shader", shader))
2444
0
        return;
2445
0
2446
0
    shader.ShaderSource(source);
2447
0
}
2448
2449
void
2450
WebGLContext::LoseContext()
2451
0
{
2452
0
    const FuncScope funcScope(*this, "loseContext");
2453
0
    if (IsContextLost())
2454
0
        return ErrorInvalidOperation("Context is already lost.");
2455
0
2456
0
    ForceLoseContext(true);
2457
0
}
2458
2459
void
2460
WebGLContext::RestoreContext()
2461
0
{
2462
0
    const FuncScope funcScope(*this, "restoreContext");
2463
0
    if (!IsContextLost())
2464
0
        return ErrorInvalidOperation("Context is not lost.");
2465
0
2466
0
    if (!mLastLossWasSimulated) {
2467
0
        return ErrorInvalidOperation("Context loss was not simulated."
2468
0
                                     " Cannot simulate restore.");
2469
0
    }
2470
0
    // If we're currently lost, and the last loss was simulated, then
2471
0
    // we're currently only simulated-lost, allowing us to call
2472
0
    // restoreContext().
2473
0
2474
0
    if (!mAllowContextRestore)
2475
0
        return ErrorInvalidOperation("Context cannot be restored.");
2476
0
2477
0
    ForceRestoreContext();
2478
0
}
2479
2480
void
2481
WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
2482
0
{
2483
0
    const FuncScope funcScope(*this, "blendColor");
2484
0
    if (IsContextLost())
2485
0
        return;
2486
0
2487
0
    gl->fBlendColor(r, g, b, a);
2488
0
}
2489
2490
void
2491
WebGLContext::Flush()
2492
0
{
2493
0
    const FuncScope funcScope(*this, "flush");
2494
0
    if (IsContextLost())
2495
0
        return;
2496
0
2497
0
    gl->fFlush();
2498
0
}
2499
2500
void
2501
WebGLContext::Finish()
2502
0
{
2503
0
    const FuncScope funcScope(*this, "finish");
2504
0
    if (IsContextLost())
2505
0
        return;
2506
0
2507
0
    gl->fFinish();
2508
0
2509
0
    mCompletedFenceId = mNextFenceId;
2510
0
    mNextFenceId += 1;
2511
0
}
2512
2513
void
2514
WebGLContext::LineWidth(GLfloat width)
2515
0
{
2516
0
    const FuncScope funcScope(*this, "lineWidth");
2517
0
    if (IsContextLost())
2518
0
        return;
2519
0
2520
0
    // Doing it this way instead of `if (width <= 0.0)` handles NaNs.
2521
0
    const bool isValid = width > 0.0;
2522
0
    if (!isValid) {
2523
0
        ErrorInvalidValue("`width` must be positive and non-zero.");
2524
0
        return;
2525
0
    }
2526
0
2527
0
    mLineWidth = width;
2528
0
2529
0
    if (gl->IsCoreProfile() && width > 1.0) {
2530
0
        width = 1.0;
2531
0
    }
2532
0
2533
0
    gl->fLineWidth(width);
2534
0
}
2535
2536
void
2537
WebGLContext::PolygonOffset(GLfloat factor, GLfloat units)
2538
0
{
2539
0
    const FuncScope funcScope(*this, "polygonOffset");
2540
0
    if (IsContextLost())
2541
0
        return;
2542
0
2543
0
    gl->fPolygonOffset(factor, units);
2544
0
}
2545
2546
void
2547
WebGLContext::SampleCoverage(GLclampf value, WebGLboolean invert)
2548
0
{
2549
0
    const FuncScope funcScope(*this, "sampleCoverage");
2550
0
    if (IsContextLost())
2551
0
        return;
2552
0
2553
0
    gl->fSampleCoverage(value, invert);
2554
0
}
2555
2556
} // namespace mozilla