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
;
22 WebGLContext::Disable(GLenum cap
)
27 if (!ValidateCapabilityEnum(cap
, "disable"))
30 realGLboolean
* trackingSlot
= GetStateTrackingSlot(cap
);
42 WebGLContext::Enable(GLenum cap
)
47 if (!ValidateCapabilityEnum(cap
, "enable"))
50 realGLboolean
* trackingSlot
= GetStateTrackingSlot(cap
);
62 StringValue(JSContext
* cx
, const char* chars
, ErrorResult
& rv
)
64 JSString
* str
= JS_NewStringCopyZ(cx
, chars
);
66 rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
67 return JS::NullValue();
70 return JS::StringValue(str
);
74 WebGLContext::GetParameter(JSContext
* cx
, GLenum pname
, ErrorResult
& rv
)
77 return JS::NullValue();
81 if (MinCapabilityMode()) {
83 ////////////////////////////
84 // Single-value params
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
);
115 // Return the real value; we're not overriding this one
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
) {
132 gl
->fGetIntegerv(pname
, &iv
);
133 return JS::Int32Value(iv
);
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
);
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;
169 version
= "WebGL 2.0";
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
)) {
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
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
: {
222 gl
->fGetIntegerv(pname
, &i
);
223 return JS::NumberValue(uint32_t(i
));
225 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE
: {
227 if (gl
->IsSupported(gl::GLFeature::ES2_compatibility
)) {
228 gl
->fGetIntegerv(pname
, &i
);
230 i
= LOCAL_GL_UNSIGNED_BYTE
;
232 return JS::NumberValue(uint32_t(i
));
234 case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
: {
236 if (gl
->IsSupported(gl::GLFeature::ES2_compatibility
)) {
237 gl
->fGetIntegerv(pname
, &i
);
241 return JS::NumberValue(uint32_t(i
));
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
: {
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
)) {
269 gl
->fGetIntegerv(pname
, &i
);
270 return JS::Int32Value(i
);
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());
299 rv
= NS_ERROR_OUT_OF_MEMORY
;
301 return JS::ObjectOrNullValue(obj
);
303 case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS
: {
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
);
324 case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
: {
325 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic
)) {
327 gl
->fGetFloatv(pname
, &f
);
328 return JS::DoubleValue(f
);
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
: {
339 gl
->fGetFloatv(pname
, &f
);
340 return JS::DoubleValue(f
);
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
: {
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 ////////////////////////////////
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
);
379 rv
= NS_ERROR_OUT_OF_MEMORY
;
381 return JS::ObjectOrNullValue(obj
);
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
);
391 rv
= NS_ERROR_OUT_OF_MEMORY
;
393 return JS::ObjectOrNullValue(obj
);
397 case LOCAL_GL_MAX_VIEWPORT_DIMS
: {
399 gl
->fGetIntegerv(pname
, iv
);
400 JSObject
* obj
= Int32Array::Create(cx
, this, 2, iv
);
402 rv
= NS_ERROR_OUT_OF_MEMORY
;
404 return JS::ObjectOrNullValue(obj
);
408 case LOCAL_GL_SCISSOR_BOX
:
409 case LOCAL_GL_VIEWPORT
: {
411 gl
->fGetIntegerv(pname
, iv
);
412 JSObject
* obj
= Int32Array::Create(cx
, this, 4, iv
);
414 rv
= NS_ERROR_OUT_OF_MEMORY
;
416 return JS::ObjectOrNullValue(obj
);
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
;
432 case LOCAL_GL_ARRAY_BUFFER_BINDING
: {
433 return WebGLObjectAsJSValue(cx
, mBoundArrayBuffer
.get(), rv
);
436 case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING
: {
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
);
471 ErrorInvalidEnumInfo("getParameter: parameter", pname
);
472 return JS::NullValue();
476 WebGLContext::GetParameterIndexed(JSContext
* cx
, GLenum pname
, GLuint index
,
477 JS::MutableHandle
<JS::Value
> retval
)
479 if (IsContextLost()) {
484 MakeContextCurrent();
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
);
494 retval
.setNull(); // See bug 903594
502 ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname
);
507 WebGLContext::IsEnabled(GLenum cap
)
512 if (!ValidateCapabilityEnum(cap
, "isEnabled"))
515 MakeContextCurrent();
516 return gl
->fIsEnabled(cap
);
520 WebGLContext::ValidateCapabilityEnum(GLenum cap
, const char* info
)
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
:
533 case LOCAL_GL_RASTERIZER_DISCARD
:
536 ErrorInvalidEnumInfo(info
, cap
);
542 WebGLContext::GetStateTrackingSlot(GLenum 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
;