|
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 "WebGLUniformInfo.h" |
|
17 #include "WebGLVertexArray.h" |
|
18 #include "WebGLVertexAttribData.h" |
|
19 |
|
20 using namespace mozilla; |
|
21 using namespace dom; |
|
22 |
|
23 void |
|
24 WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0) |
|
25 { |
|
26 if (IsContextLost()) |
|
27 return; |
|
28 |
|
29 MakeContextCurrent(); |
|
30 |
|
31 if (index) { |
|
32 gl->fVertexAttrib1f(index, x0); |
|
33 } else { |
|
34 mVertexAttrib0Vector[0] = x0; |
|
35 mVertexAttrib0Vector[1] = 0; |
|
36 mVertexAttrib0Vector[2] = 0; |
|
37 mVertexAttrib0Vector[3] = 1; |
|
38 if (gl->IsGLES()) |
|
39 gl->fVertexAttrib1f(index, x0); |
|
40 } |
|
41 } |
|
42 |
|
43 void |
|
44 WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1) |
|
45 { |
|
46 if (IsContextLost()) |
|
47 return; |
|
48 |
|
49 MakeContextCurrent(); |
|
50 |
|
51 if (index) { |
|
52 gl->fVertexAttrib2f(index, x0, x1); |
|
53 } else { |
|
54 mVertexAttrib0Vector[0] = x0; |
|
55 mVertexAttrib0Vector[1] = x1; |
|
56 mVertexAttrib0Vector[2] = 0; |
|
57 mVertexAttrib0Vector[3] = 1; |
|
58 if (gl->IsGLES()) |
|
59 gl->fVertexAttrib2f(index, x0, x1); |
|
60 } |
|
61 } |
|
62 |
|
63 void |
|
64 WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2) |
|
65 { |
|
66 if (IsContextLost()) |
|
67 return; |
|
68 |
|
69 MakeContextCurrent(); |
|
70 |
|
71 if (index) { |
|
72 gl->fVertexAttrib3f(index, x0, x1, x2); |
|
73 } else { |
|
74 mVertexAttrib0Vector[0] = x0; |
|
75 mVertexAttrib0Vector[1] = x1; |
|
76 mVertexAttrib0Vector[2] = x2; |
|
77 mVertexAttrib0Vector[3] = 1; |
|
78 if (gl->IsGLES()) |
|
79 gl->fVertexAttrib3f(index, x0, x1, x2); |
|
80 } |
|
81 } |
|
82 |
|
83 void |
|
84 WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1, |
|
85 GLfloat x2, GLfloat x3) |
|
86 { |
|
87 if (IsContextLost()) |
|
88 return; |
|
89 |
|
90 MakeContextCurrent(); |
|
91 |
|
92 if (index) { |
|
93 gl->fVertexAttrib4f(index, x0, x1, x2, x3); |
|
94 } else { |
|
95 mVertexAttrib0Vector[0] = x0; |
|
96 mVertexAttrib0Vector[1] = x1; |
|
97 mVertexAttrib0Vector[2] = x2; |
|
98 mVertexAttrib0Vector[3] = x3; |
|
99 if (gl->IsGLES()) |
|
100 gl->fVertexAttrib4f(index, x0, x1, x2, x3); |
|
101 } |
|
102 } |
|
103 |
|
104 |
|
105 void |
|
106 WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength, |
|
107 const GLfloat* ptr) |
|
108 { |
|
109 if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength)) |
|
110 return; |
|
111 |
|
112 MakeContextCurrent(); |
|
113 if (idx) { |
|
114 gl->fVertexAttrib1fv(idx, ptr); |
|
115 } else { |
|
116 mVertexAttrib0Vector[0] = ptr[0]; |
|
117 mVertexAttrib0Vector[1] = GLfloat(0); |
|
118 mVertexAttrib0Vector[2] = GLfloat(0); |
|
119 mVertexAttrib0Vector[3] = GLfloat(1); |
|
120 if (gl->IsGLES()) |
|
121 gl->fVertexAttrib1fv(idx, ptr); |
|
122 } |
|
123 } |
|
124 |
|
125 void |
|
126 WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength, |
|
127 const GLfloat* ptr) |
|
128 { |
|
129 if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength)) |
|
130 return; |
|
131 |
|
132 MakeContextCurrent(); |
|
133 if (idx) { |
|
134 gl->fVertexAttrib2fv(idx, ptr); |
|
135 } else { |
|
136 mVertexAttrib0Vector[0] = ptr[0]; |
|
137 mVertexAttrib0Vector[1] = ptr[1]; |
|
138 mVertexAttrib0Vector[2] = GLfloat(0); |
|
139 mVertexAttrib0Vector[3] = GLfloat(1); |
|
140 if (gl->IsGLES()) |
|
141 gl->fVertexAttrib2fv(idx, ptr); |
|
142 } |
|
143 } |
|
144 |
|
145 void |
|
146 WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength, |
|
147 const GLfloat* ptr) |
|
148 { |
|
149 if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength)) |
|
150 return; |
|
151 |
|
152 MakeContextCurrent(); |
|
153 if (idx) { |
|
154 gl->fVertexAttrib3fv(idx, ptr); |
|
155 } else { |
|
156 mVertexAttrib0Vector[0] = ptr[0]; |
|
157 mVertexAttrib0Vector[1] = ptr[1]; |
|
158 mVertexAttrib0Vector[2] = ptr[2]; |
|
159 mVertexAttrib0Vector[3] = GLfloat(1); |
|
160 if (gl->IsGLES()) |
|
161 gl->fVertexAttrib3fv(idx, ptr); |
|
162 } |
|
163 } |
|
164 |
|
165 void |
|
166 WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength, |
|
167 const GLfloat* ptr) |
|
168 { |
|
169 if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength)) |
|
170 return; |
|
171 |
|
172 MakeContextCurrent(); |
|
173 if (idx) { |
|
174 gl->fVertexAttrib4fv(idx, ptr); |
|
175 } else { |
|
176 mVertexAttrib0Vector[0] = ptr[0]; |
|
177 mVertexAttrib0Vector[1] = ptr[1]; |
|
178 mVertexAttrib0Vector[2] = ptr[2]; |
|
179 mVertexAttrib0Vector[3] = ptr[3]; |
|
180 if (gl->IsGLES()) |
|
181 gl->fVertexAttrib4fv(idx, ptr); |
|
182 } |
|
183 } |
|
184 |
|
185 void |
|
186 WebGLContext::EnableVertexAttribArray(GLuint index) |
|
187 { |
|
188 if (IsContextLost()) |
|
189 return; |
|
190 |
|
191 if (!ValidateAttribIndex(index, "enableVertexAttribArray")) |
|
192 return; |
|
193 |
|
194 MakeContextCurrent(); |
|
195 InvalidateBufferFetching(); |
|
196 |
|
197 gl->fEnableVertexAttribArray(index); |
|
198 MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier |
|
199 mBoundVertexArray->mAttribs[index].enabled = true; |
|
200 } |
|
201 |
|
202 void |
|
203 WebGLContext::DisableVertexAttribArray(GLuint index) |
|
204 { |
|
205 if (IsContextLost()) |
|
206 return; |
|
207 |
|
208 if (!ValidateAttribIndex(index, "disableVertexAttribArray")) |
|
209 return; |
|
210 |
|
211 MakeContextCurrent(); |
|
212 InvalidateBufferFetching(); |
|
213 |
|
214 if (index || gl->IsGLES()) |
|
215 gl->fDisableVertexAttribArray(index); |
|
216 |
|
217 MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier |
|
218 mBoundVertexArray->mAttribs[index].enabled = false; |
|
219 } |
|
220 |
|
221 |
|
222 JS::Value |
|
223 WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, |
|
224 ErrorResult& rv) |
|
225 { |
|
226 if (IsContextLost()) |
|
227 return JS::NullValue(); |
|
228 |
|
229 if (!ValidateAttribIndex(index, "getVertexAttrib")) |
|
230 return JS::NullValue(); |
|
231 |
|
232 MakeContextCurrent(); |
|
233 |
|
234 switch (pname) { |
|
235 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: |
|
236 { |
|
237 return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv); |
|
238 } |
|
239 |
|
240 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE: |
|
241 { |
|
242 return JS::Int32Value(mBoundVertexArray->mAttribs[index].stride); |
|
243 } |
|
244 |
|
245 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE: |
|
246 { |
|
247 if (!ValidateAttribIndex(index, "getVertexAttrib")) |
|
248 return JS::NullValue(); |
|
249 |
|
250 if (!mBoundVertexArray->mAttribs[index].enabled) |
|
251 return JS::Int32Value(4); |
|
252 |
|
253 // Don't break; fall through. |
|
254 } |
|
255 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE: |
|
256 { |
|
257 GLint i = 0; |
|
258 gl->fGetVertexAttribiv(index, pname, &i); |
|
259 if (pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE) |
|
260 return JS::Int32Value(i); |
|
261 MOZ_ASSERT(pname == LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE); |
|
262 return JS::NumberValue(uint32_t(i)); |
|
263 } |
|
264 |
|
265 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR: |
|
266 { |
|
267 if (IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) |
|
268 { |
|
269 return JS::Int32Value(mBoundVertexArray->mAttribs[index].divisor); |
|
270 } |
|
271 break; |
|
272 } |
|
273 |
|
274 case LOCAL_GL_CURRENT_VERTEX_ATTRIB: |
|
275 { |
|
276 GLfloat vec[4] = {0, 0, 0, 1}; |
|
277 if (index) { |
|
278 gl->fGetVertexAttribfv(index, LOCAL_GL_CURRENT_VERTEX_ATTRIB, &vec[0]); |
|
279 } else { |
|
280 vec[0] = mVertexAttrib0Vector[0]; |
|
281 vec[1] = mVertexAttrib0Vector[1]; |
|
282 vec[2] = mVertexAttrib0Vector[2]; |
|
283 vec[3] = mVertexAttrib0Vector[3]; |
|
284 } |
|
285 JSObject* obj = Float32Array::Create(cx, this, 4, vec); |
|
286 if (!obj) { |
|
287 rv.Throw(NS_ERROR_OUT_OF_MEMORY); |
|
288 } |
|
289 return JS::ObjectOrNullValue(obj); |
|
290 } |
|
291 |
|
292 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED: |
|
293 { |
|
294 return JS::BooleanValue(mBoundVertexArray->mAttribs[index].enabled); |
|
295 } |
|
296 |
|
297 case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: |
|
298 { |
|
299 return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized); |
|
300 } |
|
301 |
|
302 default: |
|
303 break; |
|
304 } |
|
305 |
|
306 ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname); |
|
307 |
|
308 return JS::NullValue(); |
|
309 } |
|
310 |
|
311 WebGLsizeiptr |
|
312 WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname) |
|
313 { |
|
314 if (IsContextLost()) |
|
315 return 0; |
|
316 |
|
317 if (!ValidateAttribIndex(index, "getVertexAttribOffset")) |
|
318 return 0; |
|
319 |
|
320 if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) { |
|
321 ErrorInvalidEnum("getVertexAttribOffset: bad parameter"); |
|
322 return 0; |
|
323 } |
|
324 |
|
325 return mBoundVertexArray->mAttribs[index].byteOffset; |
|
326 } |
|
327 |
|
328 void |
|
329 WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type, |
|
330 WebGLboolean normalized, GLsizei stride, |
|
331 WebGLintptr byteOffset) |
|
332 { |
|
333 if (IsContextLost()) |
|
334 return; |
|
335 |
|
336 if (mBoundArrayBuffer == nullptr) |
|
337 return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding"); |
|
338 |
|
339 GLsizei requiredAlignment = 1; |
|
340 switch (type) { |
|
341 case LOCAL_GL_BYTE: |
|
342 case LOCAL_GL_UNSIGNED_BYTE: |
|
343 requiredAlignment = 1; |
|
344 break; |
|
345 case LOCAL_GL_SHORT: |
|
346 case LOCAL_GL_UNSIGNED_SHORT: |
|
347 requiredAlignment = 2; |
|
348 break; |
|
349 // XXX case LOCAL_GL_FIXED: |
|
350 case LOCAL_GL_FLOAT: |
|
351 requiredAlignment = 4; |
|
352 break; |
|
353 default: |
|
354 return ErrorInvalidEnumInfo("vertexAttribPointer: type", type); |
|
355 } |
|
356 |
|
357 // requiredAlignment should always be a power of two. |
|
358 GLsizei requiredAlignmentMask = requiredAlignment - 1; |
|
359 |
|
360 if (!ValidateAttribIndex(index, "vertexAttribPointer")) { |
|
361 return; |
|
362 } |
|
363 |
|
364 if (size < 1 || size > 4) |
|
365 return ErrorInvalidValue("vertexAttribPointer: invalid element size"); |
|
366 |
|
367 if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride" |
|
368 return ErrorInvalidValue("vertexAttribPointer: negative or too large stride"); |
|
369 |
|
370 if (byteOffset < 0) |
|
371 return ErrorInvalidValue("vertexAttribPointer: negative offset"); |
|
372 |
|
373 if (stride & requiredAlignmentMask) { |
|
374 return ErrorInvalidOperation("vertexAttribPointer: stride doesn't satisfy the alignment " |
|
375 "requirement of given type"); |
|
376 } |
|
377 |
|
378 if (byteOffset & requiredAlignmentMask) { |
|
379 return ErrorInvalidOperation("vertexAttribPointer: byteOffset doesn't satisfy the alignment " |
|
380 "requirement of given type"); |
|
381 |
|
382 } |
|
383 |
|
384 InvalidateBufferFetching(); |
|
385 |
|
386 /* XXX make work with bufferSubData & heterogeneous types |
|
387 if (type != mBoundArrayBuffer->GLType()) |
|
388 return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType()); |
|
389 */ |
|
390 |
|
391 WebGLVertexAttribData &vd = mBoundVertexArray->mAttribs[index]; |
|
392 |
|
393 vd.buf = mBoundArrayBuffer; |
|
394 vd.stride = stride; |
|
395 vd.size = size; |
|
396 vd.byteOffset = byteOffset; |
|
397 vd.type = type; |
|
398 vd.normalized = normalized; |
|
399 |
|
400 MakeContextCurrent(); |
|
401 |
|
402 gl->fVertexAttribPointer(index, size, type, normalized, |
|
403 stride, |
|
404 reinterpret_cast<void*>(byteOffset)); |
|
405 } |
|
406 |
|
407 void |
|
408 WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor) |
|
409 { |
|
410 if (IsContextLost()) |
|
411 return; |
|
412 |
|
413 if (!ValidateAttribIndex(index, "vertexAttribDivisor")) { |
|
414 return; |
|
415 } |
|
416 |
|
417 WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index]; |
|
418 vd.divisor = divisor; |
|
419 |
|
420 InvalidateBufferFetching(); |
|
421 |
|
422 MakeContextCurrent(); |
|
423 |
|
424 gl->fVertexAttribDivisor(index, divisor); |
|
425 } |