Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGLContextVertices.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 "mozilla/CheckedInt.h"
10
#include "WebGLBuffer.h"
11
#include "WebGLFramebuffer.h"
12
#include "WebGLProgram.h"
13
#include "WebGLRenderbuffer.h"
14
#include "WebGLShader.h"
15
#include "WebGLTexture.h"
16
#include "WebGLVertexArray.h"
17
#include "WebGLVertexAttribData.h"
18
19
#include "mozilla/Casting.h"
20
21
namespace mozilla {
22
23
static bool
24
ValidateAttribIndex(WebGLContext& webgl, GLuint index)
25
0
{
26
0
    bool valid = (index < webgl.MaxVertexAttribs());
27
0
28
0
    if (!valid) {
29
0
        if (index == GLuint(-1)) {
30
0
            webgl.ErrorInvalidValue("-1 is not a valid `index`. This value"
31
0
                                    " probably comes from a getAttribLocation()"
32
0
                                    " call, where this return value -1 means"
33
0
                                    " that the passed name didn't correspond to"
34
0
                                    " an active attribute in the specified"
35
0
                                    " program.");
36
0
        } else {
37
0
            webgl.ErrorInvalidValue("`index` must be less than"
38
0
                                    " MAX_VERTEX_ATTRIBS.");
39
0
        }
40
0
    }
41
0
42
0
    return valid;
43
0
}
44
45
JSObject*
46
WebGLContext::GetVertexAttribFloat32Array(JSContext* cx, GLuint index)
47
0
{
48
0
    GLfloat attrib[4];
49
0
    if (index) {
50
0
        gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, attrib);
51
0
    } else {
52
0
        memcpy(attrib, mGenericVertexAttrib0Data, sizeof(mGenericVertexAttrib0Data));
53
0
    }
54
0
    return dom::Float32Array::Create(cx, this, 4, attrib);
55
0
}
56
57
JSObject*
58
WebGLContext::GetVertexAttribInt32Array(JSContext* cx, GLuint index)
59
0
{
60
0
    GLint attrib[4];
61
0
    if (index) {
62
0
        gl->fGetVertexAttribIiv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, attrib);
63
0
    } else {
64
0
        memcpy(attrib, mGenericVertexAttrib0Data, sizeof(mGenericVertexAttrib0Data));
65
0
    }
66
0
    return dom::Int32Array::Create(cx, this, 4, attrib);
67
0
}
68
69
JSObject*
70
WebGLContext::GetVertexAttribUint32Array(JSContext* cx, GLuint index)
71
0
{
72
0
    GLuint attrib[4];
73
0
    if (index) {
74
0
        gl->fGetVertexAttribIuiv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, attrib);
75
0
    } else {
76
0
        memcpy(attrib, mGenericVertexAttrib0Data, sizeof(mGenericVertexAttrib0Data));
77
0
    }
78
0
    return dom::Uint32Array::Create(cx, this, 4, attrib);
79
0
}
80
81
////////////////////////////////////////
82
83
void
84
WebGLContext::VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
85
0
{
86
0
    const FuncScope funcScope(*this, "vertexAttrib4f");
87
0
    if (IsContextLost())
88
0
        return;
89
0
90
0
    if (!ValidateAttribIndex(*this, index))
91
0
        return;
92
0
93
0
    ////
94
0
95
0
    if (index || !gl->IsCompatibilityProfile()) {
96
0
        gl->fVertexAttrib4f(index, x, y, z, w);
97
0
    }
98
0
99
0
    ////
100
0
101
0
    mGenericVertexAttribTypes[index] = LOCAL_GL_FLOAT;
102
0
    mGenericVertexAttribTypeInvalidator.InvalidateCaches();
103
0
104
0
    if (!index) {
105
0
        const float data[4] = { x, y, z, w };
106
0
        memcpy(mGenericVertexAttrib0Data, data, sizeof(data));
107
0
    }
108
0
}
109
110
void
111
WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
112
0
{
113
0
    const FuncScope funcScope(*this, "vertexAttribI4i");
114
0
    if (IsContextLost())
115
0
        return;
116
0
117
0
    if (!ValidateAttribIndex(*this, index))
118
0
        return;
119
0
120
0
    ////
121
0
122
0
    if (index || !gl->IsCompatibilityProfile()) {
123
0
        gl->fVertexAttribI4i(index, x, y, z, w);
124
0
    }
125
0
126
0
    ////
127
0
128
0
    mGenericVertexAttribTypes[index] = LOCAL_GL_INT;
129
0
    mGenericVertexAttribTypeInvalidator.InvalidateCaches();
130
0
131
0
    if (!index) {
132
0
        const int32_t data[4] = { x, y, z, w };
133
0
        memcpy(mGenericVertexAttrib0Data, data, sizeof(data));
134
0
    }
135
0
}
136
137
void
138
WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
139
0
{
140
0
    const FuncScope funcScope(*this, "vertexAttribI4ui");
141
0
    if (IsContextLost())
142
0
        return;
143
0
144
0
    if (!ValidateAttribIndex(*this, index))
145
0
        return;
146
0
147
0
    ////
148
0
149
0
    if (index || !gl->IsCompatibilityProfile()) {
150
0
        gl->fVertexAttribI4ui(index, x, y, z, w);
151
0
    }
152
0
153
0
    ////
154
0
155
0
    mGenericVertexAttribTypes[index] = LOCAL_GL_UNSIGNED_INT;
156
0
    mGenericVertexAttribTypeInvalidator.InvalidateCaches();
157
0
158
0
    if (!index) {
159
0
        const uint32_t data[4] = { x, y, z, w };
160
0
        memcpy(mGenericVertexAttrib0Data, data, sizeof(data));
161
0
    }
162
0
}
163
164
////////////////////////////////////////
165
166
void
167
WebGLContext::EnableVertexAttribArray(GLuint index)
168
0
{
169
0
    const FuncScope funcScope(*this, "enableVertexAttribArray");
170
0
    if (IsContextLost())
171
0
        return;
172
0
173
0
    if (!ValidateAttribIndex(*this, index))
174
0
        return;
175
0
176
0
    gl->fEnableVertexAttribArray(index);
177
0
178
0
    MOZ_ASSERT(mBoundVertexArray);
179
0
    mBoundVertexArray->mAttribs[index].mEnabled = true;
180
0
    mBoundVertexArray->InvalidateCaches();
181
0
}
182
183
void
184
WebGLContext::DisableVertexAttribArray(GLuint index)
185
0
{
186
0
    const FuncScope funcScope(*this, "disableVertexAttribArray");
187
0
    if (IsContextLost())
188
0
        return;
189
0
190
0
    if (!ValidateAttribIndex(*this, index))
191
0
        return;
192
0
193
0
    if (index || !gl->IsCompatibilityProfile()) {
194
0
        gl->fDisableVertexAttribArray(index);
195
0
    }
196
0
197
0
    MOZ_ASSERT(mBoundVertexArray);
198
0
    mBoundVertexArray->mAttribs[index].mEnabled = false;
199
0
    mBoundVertexArray->InvalidateCaches();
200
0
}
201
202
JS::Value
203
WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
204
                              ErrorResult& rv)
205
0
{
206
0
    const FuncScope funcScope(*this, "getVertexAttrib");
207
0
    if (IsContextLost())
208
0
        return JS::NullValue();
209
0
210
0
    if (!ValidateAttribIndex(*this, index))
211
0
        return JS::NullValue();
212
0
213
0
    MOZ_ASSERT(mBoundVertexArray);
214
0
215
0
    switch (pname) {
216
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
217
0
        return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].mBuf.get(), rv);
218
0
219
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE:
220
0
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Stride());
221
0
222
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE:
223
0
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Size());
224
0
225
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE:
226
0
        return JS::Int32Value(mBoundVertexArray->mAttribs[index].Type());
227
0
228
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER:
229
0
        if (IsWebGL2())
230
0
            return JS::BooleanValue(mBoundVertexArray->mAttribs[index].IntegerFunc());
231
0
232
0
        break;
233
0
234
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
235
0
        if (IsWebGL2() ||
236
0
            IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays))
237
0
        {
238
0
            return JS::Int32Value(mBoundVertexArray->mAttribs[index].mDivisor);
239
0
        }
240
0
        break;
241
0
242
0
    case LOCAL_GL_CURRENT_VERTEX_ATTRIB:
243
0
        {
244
0
            JS::RootedObject obj(cx);
245
0
            switch (mGenericVertexAttribTypes[index]) {
246
0
            case LOCAL_GL_FLOAT:
247
0
                obj = GetVertexAttribFloat32Array(cx, index);
248
0
                break;
249
0
250
0
            case LOCAL_GL_INT:
251
0
                obj =  GetVertexAttribInt32Array(cx, index);
252
0
                break;
253
0
254
0
            case LOCAL_GL_UNSIGNED_INT:
255
0
                obj = GetVertexAttribUint32Array(cx, index);
256
0
                break;
257
0
            }
258
0
259
0
            if (!obj) {
260
0
                rv.Throw(NS_ERROR_OUT_OF_MEMORY);
261
0
                return JS::NullValue();
262
0
            }
263
0
            return JS::ObjectValue(*obj);
264
0
        }
265
0
266
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED:
267
0
        return JS::BooleanValue(mBoundVertexArray->mAttribs[index].mEnabled);
268
0
269
0
    case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
270
0
        return JS::BooleanValue(mBoundVertexArray->mAttribs[index].Normalized());
271
0
272
0
    default:
273
0
        break;
274
0
    }
275
0
276
0
    ErrorInvalidEnumInfo("pname", pname);
277
0
    return JS::NullValue();
278
0
}
279
280
WebGLsizeiptr
281
WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
282
0
{
283
0
    const FuncScope funcScope(*this, "getVertexAttribOffset");
284
0
    if (IsContextLost())
285
0
        return 0;
286
0
287
0
    if (!ValidateAttribIndex(*this, index))
288
0
        return 0;
289
0
290
0
    if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
291
0
        ErrorInvalidEnum("`pname` must be VERTEX_ATTRIB_ARRAY_POINTER.");
292
0
        return 0;
293
0
    }
294
0
295
0
    MOZ_ASSERT(mBoundVertexArray);
296
0
    return mBoundVertexArray->mAttribs[index].ByteOffset();
297
0
}
298
299
////////////////////////////////////////
300
301
void
302
WebGLContext::VertexAttribAnyPointer(bool isFuncInt, GLuint index,
303
                                     GLint size, GLenum type, bool normalized,
304
                                     GLsizei stride, WebGLintptr byteOffset)
305
0
{
306
0
    if (IsContextLost())
307
0
        return;
308
0
309
0
    if (!ValidateAttribIndex(*this, index))
310
0
        return;
311
0
312
0
    ////
313
0
314
0
    if (size < 1 || size > 4) {
315
0
        ErrorInvalidValue("Invalid element size.");
316
0
        return;
317
0
    }
318
0
319
0
    // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
320
0
    if (stride < 0 || stride > 255) {
321
0
        ErrorInvalidValue("Negative or too large stride.");
322
0
        return;
323
0
    }
324
0
325
0
    if (byteOffset < 0) {
326
0
        ErrorInvalidValue("Negative offset.");
327
0
        return;
328
0
    }
329
0
330
0
    ////
331
0
332
0
    bool isTypeValid = true;
333
0
    uint8_t typeAlignment;
334
0
    switch (type) {
335
0
    // WebGL 1:
336
0
    case LOCAL_GL_BYTE:
337
0
    case LOCAL_GL_UNSIGNED_BYTE:
338
0
        typeAlignment = 1;
339
0
        break;
340
0
341
0
    case LOCAL_GL_SHORT:
342
0
    case LOCAL_GL_UNSIGNED_SHORT:
343
0
        typeAlignment = 2;
344
0
        break;
345
0
346
0
    case LOCAL_GL_FLOAT:
347
0
        if (isFuncInt) {
348
0
            isTypeValid = false;
349
0
        }
350
0
        typeAlignment = 4;
351
0
        break;
352
0
353
0
    // WebGL 2:
354
0
    case LOCAL_GL_INT:
355
0
    case LOCAL_GL_UNSIGNED_INT:
356
0
        if (!IsWebGL2()) {
357
0
            isTypeValid = false;
358
0
        }
359
0
        typeAlignment = 4;
360
0
        break;
361
0
362
0
    case LOCAL_GL_HALF_FLOAT:
363
0
        if (isFuncInt || !IsWebGL2()) {
364
0
            isTypeValid = false;
365
0
        }
366
0
        typeAlignment = 2;
367
0
        break;
368
0
369
0
    case LOCAL_GL_FIXED:
370
0
        if (isFuncInt || !IsWebGL2()) {
371
0
            isTypeValid = false;
372
0
        }
373
0
        typeAlignment = 4;
374
0
        break;
375
0
376
0
    case LOCAL_GL_INT_2_10_10_10_REV:
377
0
    case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
378
0
        if (isFuncInt || !IsWebGL2()) {
379
0
            isTypeValid = false;
380
0
            break;
381
0
        }
382
0
        if (size != 4) {
383
0
            ErrorInvalidOperation("Size must be 4 for this type.");
384
0
            return;
385
0
        }
386
0
        typeAlignment = 4;
387
0
        break;
388
0
389
0
    default:
390
0
        isTypeValid = false;
391
0
        break;
392
0
    }
393
0
    if (!isTypeValid) {
394
0
        ErrorInvalidEnumInfo("type", type);
395
0
        return;
396
0
    }
397
0
398
0
    ////
399
0
400
0
    // `alignment` should always be a power of two.
401
0
    MOZ_ASSERT(IsPowerOfTwo(typeAlignment));
402
0
    const GLsizei typeAlignmentMask = typeAlignment - 1;
403
0
404
0
    if (stride & typeAlignmentMask ||
405
0
        byteOffset & typeAlignmentMask)
406
0
    {
407
0
        ErrorInvalidOperation("`stride` and `byteOffset` must satisfy the alignment"
408
0
                              " requirement of `type`.");
409
0
        return;
410
0
    }
411
0
412
0
    ////
413
0
414
0
    const auto& buffer = mBoundArrayBuffer;
415
0
    if (!buffer && byteOffset) {
416
0
        ErrorInvalidOperation("If ARRAY_BUFFER is null, byteOffset must be zero.");
417
0
        return;
418
0
    }
419
0
420
0
    ////
421
0
422
0
    if (isFuncInt) {
423
0
        gl->fVertexAttribIPointer(index, size, type, stride,
424
0
                                  reinterpret_cast<void*>(byteOffset));
425
0
    } else {
426
0
        gl->fVertexAttribPointer(index, size, type, normalized, stride,
427
0
                                 reinterpret_cast<void*>(byteOffset));
428
0
    }
429
0
430
0
    WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
431
0
    vd.VertexAttribPointer(isFuncInt, buffer, size, type, normalized, stride, byteOffset);
432
0
    mBoundVertexArray->InvalidateCaches();
433
0
}
434
435
////////////////////////////////////////
436
437
void
438
WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
439
0
{
440
0
    const FuncScope funcScope(*this, "vertexAttribDivisor");
441
0
    if (IsContextLost())
442
0
        return;
443
0
444
0
    if (!ValidateAttribIndex(*this, index))
445
0
        return;
446
0
447
0
    MOZ_ASSERT(mBoundVertexArray);
448
0
    mBoundVertexArray->mAttribs[index].mDivisor = divisor;
449
0
    mBoundVertexArray->InvalidateCaches();
450
0
451
0
    gl->fVertexAttribDivisor(index, divisor);
452
0
}
453
454
} // namespace mozilla