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