Bumping manifests a=b2g-bump
[gecko.git] / dom / canvas / WebGLContextState.cpp
blob9f1da2a2cfc0829c1e2ff81d485297da9630d51d
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/. */
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"
18 using namespace mozilla;
19 using namespace dom;
21 void
22 WebGLContext::Disable(GLenum cap)
24 if (IsContextLost())
25 return;
27 if (!ValidateCapabilityEnum(cap, "disable"))
28 return;
30 realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
32 if (trackingSlot)
34 *trackingSlot = 0;
37 MakeContextCurrent();
38 gl->fDisable(cap);
41 void
42 WebGLContext::Enable(GLenum cap)
44 if (IsContextLost())
45 return;
47 if (!ValidateCapabilityEnum(cap, "enable"))
48 return;
50 realGLboolean* trackingSlot = GetStateTrackingSlot(cap);
52 if (trackingSlot)
54 *trackingSlot = 1;
57 MakeContextCurrent();
58 gl->fEnable(cap);
61 static JS::Value
62 StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
64 JSString* str = JS_NewStringCopyZ(cx, chars);
65 if (!str) {
66 rv.Throw(NS_ERROR_OUT_OF_MEMORY);
67 return JS::NullValue();
70 return JS::StringValue(str);
73 JS::Value
74 WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
76 if (IsContextLost())
77 return JS::NullValue();
79 MakeContextCurrent();
81 if (MinCapabilityMode()) {
82 switch(pname) {
83 ////////////////////////////
84 // Single-value params
86 // int
87 case LOCAL_GL_MAX_VERTEX_ATTRIBS:
88 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS);
90 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
91 return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS);
93 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
94 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS);
96 case LOCAL_GL_MAX_VARYING_VECTORS:
97 return JS::Int32Value(MINVALUE_GL_MAX_VARYING_VECTORS);
99 case LOCAL_GL_MAX_TEXTURE_SIZE:
100 return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_SIZE);
102 case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
103 return JS::Int32Value(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE);
105 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
106 return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS);
108 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
109 return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
111 case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
112 return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE);
114 default:
115 // Return the real value; we're not overriding this one
116 break;
120 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) {
121 if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) {
122 return JS::Int32Value(mGLMaxColorAttachments);
124 } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) {
125 return JS::Int32Value(mGLMaxDrawBuffers);
127 } else if (pname >= LOCAL_GL_DRAW_BUFFER0 &&
128 pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers))
130 if (mBoundFramebuffer) {
131 GLint iv = 0;
132 gl->fGetIntegerv(pname, &iv);
133 return JS::Int32Value(iv);
136 GLint iv = 0;
137 gl->fGetIntegerv(pname, &iv);
139 if (iv == GLint(LOCAL_GL_COLOR_ATTACHMENT0 + pname - LOCAL_GL_DRAW_BUFFER0)) {
140 return JS::Int32Value(LOCAL_GL_BACK);
143 return JS::Int32Value(LOCAL_GL_NONE);
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);
153 return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv);
157 switch (pname) {
159 // String params
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;
168 if (IsWebGL2()) {
169 version = "WebGL 2.0";
170 } else {
171 version = "WebGL 1.0";
174 MOZ_ASSERT(version != 0);
175 return StringValue(cx, version, rv);
177 case LOCAL_GL_SHADING_LANGUAGE_VERSION:
178 return StringValue(cx, "WebGL GLSL ES 1.0", rv);
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;
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;
194 const char* string = reinterpret_cast<const char*>(gl->fGetString(glstringname));
195 return StringValue(cx, string, rv);
198 ////////////////////////////////
199 // Single-value params
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));
225 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
226 GLint i = 0;
227 if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
228 gl->fGetIntegerv(pname, &i);
229 } else {
230 i = LOCAL_GL_UNSIGNED_BYTE;
232 return JS::NumberValue(uint32_t(i));
234 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
235 GLint i = 0;
236 if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
237 gl->fGetIntegerv(pname, &i);
238 } else {
239 i = LOCAL_GL_RGBA;
241 return JS::NumberValue(uint32_t(i));
243 // int
244 case LOCAL_GL_STENCIL_CLEAR_VALUE:
245 case LOCAL_GL_STENCIL_REF:
246 case LOCAL_GL_STENCIL_BACK_REF:
247 case LOCAL_GL_UNPACK_ALIGNMENT:
248 case LOCAL_GL_PACK_ALIGNMENT:
249 case LOCAL_GL_SUBPIXEL_BITS:
250 case LOCAL_GL_SAMPLE_BUFFERS:
251 case LOCAL_GL_SAMPLES:
252 case LOCAL_GL_MAX_VERTEX_ATTRIBS:
253 case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
254 case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
255 case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
256 case LOCAL_GL_RED_BITS:
257 case LOCAL_GL_GREEN_BITS:
258 case LOCAL_GL_BLUE_BITS:
259 case LOCAL_GL_ALPHA_BITS:
260 case LOCAL_GL_DEPTH_BITS:
261 case LOCAL_GL_STENCIL_BITS: {
262 GLint i = 0;
263 gl->fGetIntegerv(pname, &i);
264 return JS::Int32Value(i);
266 case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
267 if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
268 GLint i = 0;
269 gl->fGetIntegerv(pname, &i);
270 return JS::Int32Value(i);
271 } else {
272 break;
275 case LOCAL_GL_MAX_TEXTURE_SIZE:
276 return JS::Int32Value(mGLMaxTextureSize);
278 case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
279 return JS::Int32Value(mGLMaxCubeMapTextureSize);
281 case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
282 return JS::Int32Value(mGLMaxRenderbufferSize);
284 case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS:
285 return JS::Int32Value(mGLMaxVertexUniformVectors);
287 case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
288 return JS::Int32Value(mGLMaxFragmentUniformVectors);
290 case LOCAL_GL_MAX_VARYING_VECTORS:
291 return JS::Int32Value(mGLMaxVaryingVectors);
293 case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
294 return JS::Int32Value(0);
295 case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: {
296 uint32_t length = mCompressedTextureFormats.Length();
297 JSObject* obj = Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements());
298 if (!obj) {
299 rv = NS_ERROR_OUT_OF_MEMORY;
301 return JS::ObjectOrNullValue(obj);
303 case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: {
304 if (!IsWebGL2()) {
305 break;
307 return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs);
310 // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
311 // javascript integer values. We just return them as doubles and javascript doesn't care.
312 case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
313 case LOCAL_GL_STENCIL_BACK_WRITEMASK:
314 case LOCAL_GL_STENCIL_VALUE_MASK:
315 case LOCAL_GL_STENCIL_WRITEMASK: {
316 GLint i = 0; // the GL api (glGetIntegerv) only does signed ints
317 gl->fGetIntegerv(pname, &i);
318 GLuint i_unsigned(i); // this is where -1 becomes 2^32-1
319 double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1.
320 return JS::DoubleValue(i_double);
323 // float
324 case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: {
325 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) {
326 GLfloat f = 0.f;
327 gl->fGetFloatv(pname, &f);
328 return JS::DoubleValue(f);
329 } else {
330 break;
333 case LOCAL_GL_DEPTH_CLEAR_VALUE:
334 case LOCAL_GL_LINE_WIDTH:
335 case LOCAL_GL_POLYGON_OFFSET_FACTOR:
336 case LOCAL_GL_POLYGON_OFFSET_UNITS:
337 case LOCAL_GL_SAMPLE_COVERAGE_VALUE: {
338 GLfloat f = 0.f;
339 gl->fGetFloatv(pname, &f);
340 return JS::DoubleValue(f);
343 // bool
344 case LOCAL_GL_BLEND:
345 case LOCAL_GL_DEPTH_TEST:
346 case LOCAL_GL_STENCIL_TEST:
347 case LOCAL_GL_CULL_FACE:
348 case LOCAL_GL_DITHER:
349 case LOCAL_GL_POLYGON_OFFSET_FILL:
350 case LOCAL_GL_SCISSOR_TEST:
351 case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
352 case LOCAL_GL_DEPTH_WRITEMASK: {
353 realGLboolean b = 0;
354 gl->fGetBooleanv(pname, &b);
355 return JS::BooleanValue(bool(b));
358 // bool, WebGL-specific
359 case UNPACK_FLIP_Y_WEBGL:
360 return JS::BooleanValue(mPixelStoreFlipY);
361 case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
362 return JS::BooleanValue(mPixelStorePremultiplyAlpha);
364 // uint, WebGL-specific
365 case UNPACK_COLORSPACE_CONVERSION_WEBGL:
366 return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion));
368 ////////////////////////////////
369 // Complex values
371 // 2 floats
372 case LOCAL_GL_DEPTH_RANGE:
373 case LOCAL_GL_ALIASED_POINT_SIZE_RANGE:
374 case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: {
375 GLfloat fv[2] = { 0 };
376 gl->fGetFloatv(pname, fv);
377 JSObject* obj = Float32Array::Create(cx, this, 2, fv);
378 if (!obj) {
379 rv = NS_ERROR_OUT_OF_MEMORY;
381 return JS::ObjectOrNullValue(obj);
384 // 4 floats
385 case LOCAL_GL_COLOR_CLEAR_VALUE:
386 case LOCAL_GL_BLEND_COLOR: {
387 GLfloat fv[4] = { 0 };
388 gl->fGetFloatv(pname, fv);
389 JSObject* obj = Float32Array::Create(cx, this, 4, fv);
390 if (!obj) {
391 rv = NS_ERROR_OUT_OF_MEMORY;
393 return JS::ObjectOrNullValue(obj);
396 // 2 ints
397 case LOCAL_GL_MAX_VIEWPORT_DIMS: {
398 GLint iv[2] = { 0 };
399 gl->fGetIntegerv(pname, iv);
400 JSObject* obj = Int32Array::Create(cx, this, 2, iv);
401 if (!obj) {
402 rv = NS_ERROR_OUT_OF_MEMORY;
404 return JS::ObjectOrNullValue(obj);
407 // 4 ints
408 case LOCAL_GL_SCISSOR_BOX:
409 case LOCAL_GL_VIEWPORT: {
410 GLint iv[4] = { 0 };
411 gl->fGetIntegerv(pname, iv);
412 JSObject* obj = Int32Array::Create(cx, this, 4, iv);
413 if (!obj) {
414 rv = NS_ERROR_OUT_OF_MEMORY;
416 return JS::ObjectOrNullValue(obj);
419 // 4 bools
420 case LOCAL_GL_COLOR_WRITEMASK: {
421 realGLboolean gl_bv[4] = { 0 };
422 gl->fGetBooleanv(pname, gl_bv);
423 bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]),
424 bool(gl_bv[2]), bool(gl_bv[3]) };
425 JS::Rooted<JS::Value> arr(cx);
426 if (!ToJSValue(cx, vals, &arr)) {
427 rv = NS_ERROR_OUT_OF_MEMORY;
429 return arr;
432 case LOCAL_GL_ARRAY_BUFFER_BINDING: {
433 return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
436 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: {
437 if (!IsWebGL2()) {
438 break;
440 return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
443 case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: {
444 return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv);
447 case LOCAL_GL_RENDERBUFFER_BINDING: {
448 return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
451 case LOCAL_GL_FRAMEBUFFER_BINDING: {
452 return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv);
455 case LOCAL_GL_CURRENT_PROGRAM: {
456 return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv);
459 case LOCAL_GL_TEXTURE_BINDING_2D: {
460 return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv);
463 case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: {
464 return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv);
467 default:
468 break;
471 ErrorInvalidEnumInfo("getParameter: parameter", pname);
472 return JS::NullValue();
475 void
476 WebGLContext::GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index,
477 JS::MutableHandle<JS::Value> retval)
479 if (IsContextLost()) {
480 retval.setNull();
481 return;
484 MakeContextCurrent();
486 switch (pname) {
487 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
489 if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
490 ErrorInvalidValue("getParameterIndexed: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", index);
491 retval.setNull();
492 return;
494 retval.setNull(); // See bug 903594
495 return;
498 default:
499 break;
502 ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname);
503 retval.setNull();
506 bool
507 WebGLContext::IsEnabled(GLenum cap)
509 if (IsContextLost())
510 return false;
512 if (!ValidateCapabilityEnum(cap, "isEnabled"))
513 return false;
515 MakeContextCurrent();
516 return gl->fIsEnabled(cap);
519 bool
520 WebGLContext::ValidateCapabilityEnum(GLenum cap, const char* info)
522 switch (cap) {
523 case LOCAL_GL_BLEND:
524 case LOCAL_GL_CULL_FACE:
525 case LOCAL_GL_DEPTH_TEST:
526 case LOCAL_GL_DITHER:
527 case LOCAL_GL_POLYGON_OFFSET_FILL:
528 case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
529 case LOCAL_GL_SAMPLE_COVERAGE:
530 case LOCAL_GL_SCISSOR_TEST:
531 case LOCAL_GL_STENCIL_TEST:
532 return true;
533 case LOCAL_GL_RASTERIZER_DISCARD:
534 return IsWebGL2();
535 default:
536 ErrorInvalidEnumInfo(info, cap);
537 return false;
541 realGLboolean*
542 WebGLContext::GetStateTrackingSlot(GLenum cap)
544 switch (cap) {
545 case LOCAL_GL_SCISSOR_TEST:
546 return &mScissorTestEnabled;
547 case LOCAL_GL_DITHER:
548 return &mDitherEnabled;
549 case LOCAL_GL_RASTERIZER_DISCARD:
550 return &mRasterizerDiscardEnabled;
553 return nullptr;