content/canvas/src/WebGLContextState.cpp

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:61d6fcc1aa62
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 "WebGLContextUtils.h"
8 #include "WebGLBuffer.h"
9 #include "WebGLShader.h"
10 #include "WebGLProgram.h"
11 #include "WebGLFramebuffer.h"
12 #include "WebGLRenderbuffer.h"
13 #include "WebGLTexture.h"
14 #include "WebGLVertexArray.h"
15 #include "GLContext.h"
16 #include "mozilla/dom/ToJSValue.h"
17
18 using namespace mozilla;
19 using namespace dom;
20
21 void
22 WebGLContext::Disable(GLenum cap)
23 {
24 if (IsContextLost())
25 return;
26
27 if (!ValidateCapabilityEnum(cap, "disable"))
28 return;
29
30 realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
31
32 if (trackingSlot)
33 {
34 *trackingSlot = 0;
35 }
36
37 MakeContextCurrent();
38 gl->fDisable(cap);
39 }
40
41 void
42 WebGLContext::Enable(GLenum cap)
43 {
44 if (IsContextLost())
45 return;
46
47 if (!ValidateCapabilityEnum(cap, "enable"))
48 return;
49
50 realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
51
52 if (trackingSlot)
53 {
54 *trackingSlot = 1;
55 }
56
57 MakeContextCurrent();
58 gl->fEnable(cap);
59 }
60
61 static JS::Value
62 StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
63 {
64 JSString* str = JS_NewStringCopyZ(cx, chars);
65 if (!str) {
66 rv.Throw(NS_ERROR_OUT_OF_MEMORY);
67 return JS::NullValue();
68 }
69
70 return JS::StringValue(str);
71 }
72
73 JS::Value
74 WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
75 {
76 if (IsContextLost())
77 return JS::NullValue();
78
79 MakeContextCurrent();
80
81 if (MinCapabilityMode()) {
82 switch(pname) {
83 ////////////////////////////
84 // Single-value params
85
86 // int
87 case LOCAL_GL_MAX_VERTEX_ATTRIBS:
88 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS);
89
90 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
91 return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
92
93 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
94 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS);
95
96 case LOCAL_GL_MAX_VARYING_VECTORS:
97 return JS::Int32Value(MINVALUE_GL_MAX_VARYING_VECTORS);
98
99 case LOCAL_GL_MAX_TEXTURE_SIZE:
100 return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_SIZE);
101
102 case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
103 return JS::Int32Value(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE);
104
105 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
106 return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS);
107
108 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
109 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
110
111 case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
112 return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE);
113
114 default:
115 // Return the real value; we're not overriding this one
116 break;
117 }
118 }
119
120 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
121 if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
122 return JS::Int32Value(mGLMaxColorAttachments);
123
124 } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
125 return JS::Int32Value(mGLMaxDrawBuffers);
126
127 } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
128 pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
129 {
130 if (mBoundFramebuffer) {
131 GLint iv = 0;
132 gl->fGetIntegerv(pname, &iv);
133 return JS::Int32Value(iv);
134 }
135
136 GLint iv = 0;
137 gl->fGetIntegerv(pname, &iv);
138
139 if (iv == GLint(LOCAL_GL_COLOR_ATTACHMENT0 + pname - LOCAL_GL_DRAW_BUFFER0)) {
140 return JS::Int32Value(LOCAL_GL_BACK);
141 }
142
143 return JS::Int32Value(LOCAL_GL_NONE);
144 }
145 }
146
147 if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
148 if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) {
149 if (mBoundVertexArray == mDefaultVertexArray){
150 return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv);
151 }
152
153 return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
154 }
155 }
156
157 switch (pname) {
158 //
159 // String params
160 //
161 case LOCAL_GL_VENDOR:
162 return StringValue(cx, "Mozilla", rv);
163 case LOCAL_GL_RENDERER:
164 return StringValue(cx, "Mozilla", rv);
165 case LOCAL_GL_VERSION: {
166 const char* version = 0;
167
168 if (IsWebGL2()) {
169 version = "WebGL 2.0";
170 } else {
171 version = "WebGL 1.0";
172 }
173
174 MOZ_ASSERT(version != 0);
175 return StringValue(cx, version, rv);
176 }
177 case LOCAL_GL_SHADING_LANGUAGE_VERSION:
178 return StringValue(cx, "WebGL GLSL ES 1.0", rv);
179
180 // Privileged string params exposed by WEBGL_debug_renderer_info:
181 case UNMASKED_VENDOR_WEBGL:
182 case UNMASKED_RENDERER_WEBGL: {
183 // The privilege check is done in WebGLContext::IsExtensionSupported.
184 // So here we just have to check that the extension is enabled.
185 if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) {
186 break;
187 }
188 GLenum glstringname = LOCAL_GL_NONE;
189 if (pname == UNMASKED_VENDOR_WEBGL) {
190 glstringname = LOCAL_GL_VENDOR;
191 } else if (pname == UNMASKED_RENDERER_WEBGL) {
192 glstringname = LOCAL_GL_RENDERER;
193 }
194 const char* string = reinterpret_cast<const char*>(gl->fGetString(glstringname));
195 return StringValue(cx, string, rv);
196 }
197
198 ////////////////////////////////
199 // Single-value params
200
201 // unsigned int
202 case LOCAL_GL_CULL_FACE_MODE:
203 case LOCAL_GL_FRONT_FACE:
204 case LOCAL_GL_ACTIVE_TEXTURE:
205 case LOCAL_GL_STENCIL_FUNC:
206 case LOCAL_GL_STENCIL_FAIL:
207 case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL:
208 case LOCAL_GL_STENCIL_PASS_DEPTH_PASS:
209 case LOCAL_GL_STENCIL_BACK_FUNC:
210 case LOCAL_GL_STENCIL_BACK_FAIL:
211 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL:
212 case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
213 case LOCAL_GL_DEPTH_FUNC:
214 case LOCAL_GL_BLEND_SRC_RGB:
215 case LOCAL_GL_BLEND_SRC_ALPHA:
216 case LOCAL_GL_BLEND_DST_RGB:
217 case LOCAL_GL_BLEND_DST_ALPHA:
218 case LOCAL_GL_BLEND_EQUATION_RGB:
219 case LOCAL_GL_BLEND_EQUATION_ALPHA:
220 case LOCAL_GL_GENERATE_MIPMAP_HINT: {
221 GLint i = 0;
222 gl->fGetIntegerv(pname, &i);
223 return JS::NumberValue(uint32_t(i));
224 }
225 // int
226 case LOCAL_GL_STENCIL_CLEAR_VALUE:
227 case LOCAL_GL_STENCIL_REF:
228 case LOCAL_GL_STENCIL_BACK_REF:
229 case LOCAL_GL_UNPACK_ALIGNMENT:
230 case LOCAL_GL_PACK_ALIGNMENT:
231 case LOCAL_GL_SUBPIXEL_BITS:
232 case LOCAL_GL_SAMPLE_BUFFERS:
233 case LOCAL_GL_SAMPLES:
234 case LOCAL_GL_MAX_VERTEX_ATTRIBS:
235 case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
236 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
237 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
238 case LOCAL_GL_RED_BITS:
239 case LOCAL_GL_GREEN_BITS:
240 case LOCAL_GL_BLUE_BITS:
241 case LOCAL_GL_ALPHA_BITS:
242 case LOCAL_GL_DEPTH_BITS:
243 case LOCAL_GL_STENCIL_BITS: {
244 GLint i = 0;
245 gl->fGetIntegerv(pname, &i);
246 return JS::Int32Value(i);
247 }
248 case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
249 if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
250 GLint i = 0;
251 gl->fGetIntegerv(pname, &i);
252 return JS::Int32Value(i);
253 } else {
254 break;
255 }
256 }
257 case LOCAL_GL_MAX_TEXTURE_SIZE:
258 return JS::Int32Value(mGLMaxTextureSize);
259
260 case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
261 return JS::Int32Value(mGLMaxCubeMapTextureSize);
262
263 case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
264 return JS::Int32Value(mGLMaxRenderbufferSize);
265
266 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
267 return JS::Int32Value(mGLMaxVertexUniformVectors);
268
269 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
270 return JS::Int32Value(mGLMaxFragmentUniformVectors);
271
272 case LOCAL_GL_MAX_VARYING_VECTORS:
273 return JS::Int32Value(mGLMaxVaryingVectors);
274
275 case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
276 return JS::Int32Value(0);
277 case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
278 uint32_t length = mCompressedTextureFormats.Length();
279 JSObject* obj = Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements());
280 if (!obj) {
281 rv = NS_ERROR_OUT_OF_MEMORY;
282 }
283 return JS::ObjectOrNullValue(obj);
284 }
285 case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: {
286 if (!IsWebGL2()) {
287 break;
288 }
289 return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs);
290 }
291
292 // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
293 // javascript integer values. We just return them as doubles and javascript doesn't care.
294 case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
295 case LOCAL_GL_STENCIL_BACK_WRITEMASK:
296 case LOCAL_GL_STENCIL_VALUE_MASK:
297 case LOCAL_GL_STENCIL_WRITEMASK: {
298 GLint i = 0; // the GL api (glGetIntegerv) only does signed ints
299 gl->fGetIntegerv(pname, &i);
300 GLuint i_unsigned(i); // this is where -1 becomes 2^32-1
301 double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1.
302 return JS::DoubleValue(i_double);
303 }
304
305 // float
306 case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: {
307 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
308 GLfloat f = 0.f;
309 gl->fGetFloatv(pname, &f);
310 return JS::DoubleValue(f);
311 } else {
312 break;
313 }
314 }
315 case LOCAL_GL_DEPTH_CLEAR_VALUE:
316 case LOCAL_GL_LINE_WIDTH:
317 case LOCAL_GL_POLYGON_OFFSET_FACTOR:
318 case LOCAL_GL_POLYGON_OFFSET_UNITS:
319 case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
320 GLfloat f = 0.f;
321 gl->fGetFloatv(pname, &f);
322 return JS::DoubleValue(f);
323 }
324
325 // bool
326 case LOCAL_GL_BLEND:
327 case LOCAL_GL_DEPTH_TEST:
328 case LOCAL_GL_STENCIL_TEST:
329 case LOCAL_GL_CULL_FACE:
330 case LOCAL_GL_DITHER:
331 case LOCAL_GL_POLYGON_OFFSET_FILL:
332 case LOCAL_GL_SCISSOR_TEST:
333 case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
334 case LOCAL_GL_DEPTH_WRITEMASK: {
335 realGLboolean b = 0;
336 gl->fGetBooleanv(pname, &b);
337 return JS::BooleanValue(bool(b));
338 }
339
340 // bool, WebGL-specific
341 case UNPACK_FLIP_Y_WEBGL:
342 return JS::BooleanValue(mPixelStoreFlipY);
343 case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
344 return JS::BooleanValue(mPixelStorePremultiplyAlpha);
345
346 // uint, WebGL-specific
347 case UNPACK_COLORSPACE_CONVERSION_WEBGL:
348 return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion));
349
350 ////////////////////////////////
351 // Complex values
352
353 // 2 floats
354 case LOCAL_GL_DEPTH_RANGE:
355 case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
356 case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
357 GLfloat fv[2] = { 0 };
358 gl->fGetFloatv(pname, fv);
359 JSObject* obj = Float32Array::Create(cx, this, 2, fv);
360 if (!obj) {
361 rv = NS_ERROR_OUT_OF_MEMORY;
362 }
363 return JS::ObjectOrNullValue(obj);
364 }
365
366 // 4 floats
367 case LOCAL_GL_COLOR_CLEAR_VALUE:
368 case LOCAL_GL_BLEND_COLOR: {
369 GLfloat fv[4] = { 0 };
370 gl->fGetFloatv(pname, fv);
371 JSObject* obj = Float32Array::Create(cx, this, 4, fv);
372 if (!obj) {
373 rv = NS_ERROR_OUT_OF_MEMORY;
374 }
375 return JS::ObjectOrNullValue(obj);
376 }
377
378 // 2 ints
379 case LOCAL_GL_MAX_VIEWPORT_DIMS: {
380 GLint iv[2] = { 0 };
381 gl->fGetIntegerv(pname, iv);
382 JSObject* obj = Int32Array::Create(cx, this, 2, iv);
383 if (!obj) {
384 rv = NS_ERROR_OUT_OF_MEMORY;
385 }
386 return JS::ObjectOrNullValue(obj);
387 }
388
389 // 4 ints
390 case LOCAL_GL_SCISSOR_BOX:
391 case LOCAL_GL_VIEWPORT: {
392 GLint iv[4] = { 0 };
393 gl->fGetIntegerv(pname, iv);
394 JSObject* obj = Int32Array::Create(cx, this, 4, iv);
395 if (!obj) {
396 rv = NS_ERROR_OUT_OF_MEMORY;
397 }
398 return JS::ObjectOrNullValue(obj);
399 }
400
401 // 4 bools
402 case LOCAL_GL_COLOR_WRITEMASK: {
403 realGLboolean gl_bv[4] = { 0 };
404 gl->fGetBooleanv(pname, gl_bv);
405 bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]),
406 bool(gl_bv[2]), bool(gl_bv[3]) };
407 JS::Rooted<JS::Value> arr(cx);
408 if (!ToJSValue(cx, vals, &arr)) {
409 rv = NS_ERROR_OUT_OF_MEMORY;
410 }
411 return arr;
412 }
413
414 case LOCAL_GL_ARRAY_BUFFER_BINDING: {
415 return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
416 }
417
418 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: {
419 if (!IsWebGL2()) {
420 break;
421 }
422 return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
423 }
424
425 case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
426 return WebGLObjectAsJSValue(cx, mBoundVertexArray->mBoundElementArrayBuffer.get(), rv);
427 }
428
429 case LOCAL_GL_RENDERBUFFER_BINDING: {
430 return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
431 }
432
433 case LOCAL_GL_FRAMEBUFFER_BINDING: {
434 return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv);
435 }
436
437 case LOCAL_GL_CURRENT_PROGRAM: {
438 return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
439 }
440
441 case LOCAL_GL_TEXTURE_BINDING_2D: {
442 return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
443 }
444
445 case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: {
446 return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv);
447 }
448
449 default:
450 break;
451 }
452
453 ErrorInvalidEnumInfo("getParameter: parameter", pname);
454 return JS::NullValue();
455 }
456
457 void
458 WebGLContext::GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index,
459 JS::MutableHandle<JS::Value> retval)
460 {
461 if (IsContextLost()) {
462 retval.setNull();
463 return;
464 }
465
466 MakeContextCurrent();
467
468 switch (pname) {
469 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
470 {
471 if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
472 ErrorInvalidValue("getParameterIndexed: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", index);
473 retval.setNull();
474 return;
475 }
476 retval.setNull(); // See bug 903594
477 return;
478 }
479
480 default:
481 break;
482 }
483
484 ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname);
485 retval.setNull();
486 }
487
488 bool
489 WebGLContext::IsEnabled(GLenum cap)
490 {
491 if (IsContextLost())
492 return false;
493
494 if (!ValidateCapabilityEnum(cap, "isEnabled"))
495 return false;
496
497 MakeContextCurrent();
498 return gl->fIsEnabled(cap);
499 }
500
501 bool
502 WebGLContext::ValidateCapabilityEnum(GLenum cap, const char* info)
503 {
504 switch (cap) {
505 case LOCAL_GL_BLEND:
506 case LOCAL_GL_CULL_FACE:
507 case LOCAL_GL_DEPTH_TEST:
508 case LOCAL_GL_DITHER:
509 case LOCAL_GL_POLYGON_OFFSET_FILL:
510 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
511 case LOCAL_GL_SAMPLE_COVERAGE:
512 case LOCAL_GL_SCISSOR_TEST:
513 case LOCAL_GL_STENCIL_TEST:
514 return true;
515 case LOCAL_GL_RASTERIZER_DISCARD:
516 return IsWebGL2();
517 default:
518 ErrorInvalidEnumInfo(info, cap);
519 return false;
520 }
521 }
522
523 realGLboolean*
524 WebGLContext::GetStateTrackingSlot(GLenum cap)
525 {
526 switch (cap) {
527 case LOCAL_GL_SCISSOR_TEST:
528 return &mScissorTestEnabled;
529 case LOCAL_GL_DITHER:
530 return &mDitherEnabled;
531 case LOCAL_GL_RASTERIZER_DISCARD:
532 return &mRasterizerDiscardEnabled;
533 }
534
535 return nullptr;
536 }

mercurial