michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "WebGLContext.h" michael@0: #include "WebGLContextUtils.h" michael@0: #include "WebGLBuffer.h" michael@0: #include "WebGLShader.h" michael@0: #include "WebGLProgram.h" michael@0: #include "WebGLFramebuffer.h" michael@0: #include "WebGLRenderbuffer.h" michael@0: #include "WebGLTexture.h" michael@0: #include "WebGLVertexArray.h" michael@0: #include "GLContext.h" michael@0: #include "mozilla/dom/ToJSValue.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace dom; michael@0: michael@0: void michael@0: WebGLContext::Disable(GLenum cap) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateCapabilityEnum(cap, "disable")) michael@0: return; michael@0: michael@0: realGLboolean* trackingSlot = GetStateTrackingSlot(cap); michael@0: michael@0: if (trackingSlot) michael@0: { michael@0: *trackingSlot = 0; michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: gl->fDisable(cap); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::Enable(GLenum cap) michael@0: { michael@0: if (IsContextLost()) michael@0: return; michael@0: michael@0: if (!ValidateCapabilityEnum(cap, "enable")) michael@0: return; michael@0: michael@0: realGLboolean* trackingSlot = GetStateTrackingSlot(cap); michael@0: michael@0: if (trackingSlot) michael@0: { michael@0: *trackingSlot = 1; michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: gl->fEnable(cap); michael@0: } michael@0: michael@0: static JS::Value michael@0: StringValue(JSContext* cx, const char* chars, ErrorResult& rv) michael@0: { michael@0: JSString* str = JS_NewStringCopyZ(cx, chars); michael@0: if (!str) { michael@0: rv.Throw(NS_ERROR_OUT_OF_MEMORY); michael@0: return JS::NullValue(); michael@0: } michael@0: michael@0: return JS::StringValue(str); michael@0: } michael@0: michael@0: JS::Value michael@0: WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) michael@0: { michael@0: if (IsContextLost()) michael@0: return JS::NullValue(); michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: if (MinCapabilityMode()) { michael@0: switch(pname) { michael@0: //////////////////////////// michael@0: // Single-value params michael@0: michael@0: // int michael@0: case LOCAL_GL_MAX_VERTEX_ATTRIBS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS); michael@0: michael@0: case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS); michael@0: michael@0: case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS); michael@0: michael@0: case LOCAL_GL_MAX_VARYING_VECTORS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_VARYING_VECTORS); michael@0: michael@0: case LOCAL_GL_MAX_TEXTURE_SIZE: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_SIZE); michael@0: michael@0: case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE); michael@0: michael@0: case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS); michael@0: michael@0: case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); michael@0: michael@0: case LOCAL_GL_MAX_RENDERBUFFER_SIZE: michael@0: return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE); michael@0: michael@0: default: michael@0: // Return the real value; we're not overriding this one michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { michael@0: if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) { michael@0: return JS::Int32Value(mGLMaxColorAttachments); michael@0: michael@0: } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) { michael@0: return JS::Int32Value(mGLMaxDrawBuffers); michael@0: michael@0: } else if (pname >= LOCAL_GL_DRAW_BUFFER0 && michael@0: pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers)) michael@0: { michael@0: if (mBoundFramebuffer) { michael@0: GLint iv = 0; michael@0: gl->fGetIntegerv(pname, &iv); michael@0: return JS::Int32Value(iv); michael@0: } michael@0: michael@0: GLint iv = 0; michael@0: gl->fGetIntegerv(pname, &iv); michael@0: michael@0: if (iv == GLint(LOCAL_GL_COLOR_ATTACHMENT0 + pname - LOCAL_GL_DRAW_BUFFER0)) { michael@0: return JS::Int32Value(LOCAL_GL_BACK); michael@0: } michael@0: michael@0: return JS::Int32Value(LOCAL_GL_NONE); michael@0: } michael@0: } michael@0: michael@0: if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { michael@0: if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) { michael@0: if (mBoundVertexArray == mDefaultVertexArray){ michael@0: return WebGLObjectAsJSValue(cx, (WebGLVertexArray *) nullptr, rv); michael@0: } michael@0: michael@0: return WebGLObjectAsJSValue(cx, mBoundVertexArray.get(), rv); michael@0: } michael@0: } michael@0: michael@0: switch (pname) { michael@0: // michael@0: // String params michael@0: // michael@0: case LOCAL_GL_VENDOR: michael@0: return StringValue(cx, "Mozilla", rv); michael@0: case LOCAL_GL_RENDERER: michael@0: return StringValue(cx, "Mozilla", rv); michael@0: case LOCAL_GL_VERSION: { michael@0: const char* version = 0; michael@0: michael@0: if (IsWebGL2()) { michael@0: version = "WebGL 2.0"; michael@0: } else { michael@0: version = "WebGL 1.0"; michael@0: } michael@0: michael@0: MOZ_ASSERT(version != 0); michael@0: return StringValue(cx, version, rv); michael@0: } michael@0: case LOCAL_GL_SHADING_LANGUAGE_VERSION: michael@0: return StringValue(cx, "WebGL GLSL ES 1.0", rv); michael@0: michael@0: // Privileged string params exposed by WEBGL_debug_renderer_info: michael@0: case UNMASKED_VENDOR_WEBGL: michael@0: case UNMASKED_RENDERER_WEBGL: { michael@0: // The privilege check is done in WebGLContext::IsExtensionSupported. michael@0: // So here we just have to check that the extension is enabled. michael@0: if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) { michael@0: break; michael@0: } michael@0: GLenum glstringname = LOCAL_GL_NONE; michael@0: if (pname == UNMASKED_VENDOR_WEBGL) { michael@0: glstringname = LOCAL_GL_VENDOR; michael@0: } else if (pname == UNMASKED_RENDERER_WEBGL) { michael@0: glstringname = LOCAL_GL_RENDERER; michael@0: } michael@0: const char* string = reinterpret_cast(gl->fGetString(glstringname)); michael@0: return StringValue(cx, string, rv); michael@0: } michael@0: michael@0: //////////////////////////////// michael@0: // Single-value params michael@0: michael@0: // unsigned int michael@0: case LOCAL_GL_CULL_FACE_MODE: michael@0: case LOCAL_GL_FRONT_FACE: michael@0: case LOCAL_GL_ACTIVE_TEXTURE: michael@0: case LOCAL_GL_STENCIL_FUNC: michael@0: case LOCAL_GL_STENCIL_FAIL: michael@0: case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL: michael@0: case LOCAL_GL_STENCIL_PASS_DEPTH_PASS: michael@0: case LOCAL_GL_STENCIL_BACK_FUNC: michael@0: case LOCAL_GL_STENCIL_BACK_FAIL: michael@0: case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL: michael@0: case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS: michael@0: case LOCAL_GL_DEPTH_FUNC: michael@0: case LOCAL_GL_BLEND_SRC_RGB: michael@0: case LOCAL_GL_BLEND_SRC_ALPHA: michael@0: case LOCAL_GL_BLEND_DST_RGB: michael@0: case LOCAL_GL_BLEND_DST_ALPHA: michael@0: case LOCAL_GL_BLEND_EQUATION_RGB: michael@0: case LOCAL_GL_BLEND_EQUATION_ALPHA: michael@0: case LOCAL_GL_GENERATE_MIPMAP_HINT: { michael@0: GLint i = 0; michael@0: gl->fGetIntegerv(pname, &i); michael@0: return JS::NumberValue(uint32_t(i)); michael@0: } michael@0: // int michael@0: case LOCAL_GL_STENCIL_CLEAR_VALUE: michael@0: case LOCAL_GL_STENCIL_REF: michael@0: case LOCAL_GL_STENCIL_BACK_REF: michael@0: case LOCAL_GL_UNPACK_ALIGNMENT: michael@0: case LOCAL_GL_PACK_ALIGNMENT: michael@0: case LOCAL_GL_SUBPIXEL_BITS: michael@0: case LOCAL_GL_SAMPLE_BUFFERS: michael@0: case LOCAL_GL_SAMPLES: michael@0: case LOCAL_GL_MAX_VERTEX_ATTRIBS: michael@0: case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: michael@0: case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: michael@0: case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS: michael@0: case LOCAL_GL_RED_BITS: michael@0: case LOCAL_GL_GREEN_BITS: michael@0: case LOCAL_GL_BLUE_BITS: michael@0: case LOCAL_GL_ALPHA_BITS: michael@0: case LOCAL_GL_DEPTH_BITS: michael@0: case LOCAL_GL_STENCIL_BITS: { michael@0: GLint i = 0; michael@0: gl->fGetIntegerv(pname, &i); michael@0: return JS::Int32Value(i); michael@0: } michael@0: case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: { michael@0: if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) { michael@0: GLint i = 0; michael@0: gl->fGetIntegerv(pname, &i); michael@0: return JS::Int32Value(i); michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: case LOCAL_GL_MAX_TEXTURE_SIZE: michael@0: return JS::Int32Value(mGLMaxTextureSize); michael@0: michael@0: case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: michael@0: return JS::Int32Value(mGLMaxCubeMapTextureSize); michael@0: michael@0: case LOCAL_GL_MAX_RENDERBUFFER_SIZE: michael@0: return JS::Int32Value(mGLMaxRenderbufferSize); michael@0: michael@0: case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS: michael@0: return JS::Int32Value(mGLMaxVertexUniformVectors); michael@0: michael@0: case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS: michael@0: return JS::Int32Value(mGLMaxFragmentUniformVectors); michael@0: michael@0: case LOCAL_GL_MAX_VARYING_VECTORS: michael@0: return JS::Int32Value(mGLMaxVaryingVectors); michael@0: michael@0: case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS: michael@0: return JS::Int32Value(0); michael@0: case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: { michael@0: uint32_t length = mCompressedTextureFormats.Length(); michael@0: JSObject* obj = Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements()); michael@0: if (!obj) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS: { michael@0: if (!IsWebGL2()) { michael@0: break; michael@0: } michael@0: return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs); michael@0: } michael@0: michael@0: // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as michael@0: // javascript integer values. We just return them as doubles and javascript doesn't care. michael@0: case LOCAL_GL_STENCIL_BACK_VALUE_MASK: michael@0: case LOCAL_GL_STENCIL_BACK_WRITEMASK: michael@0: case LOCAL_GL_STENCIL_VALUE_MASK: michael@0: case LOCAL_GL_STENCIL_WRITEMASK: { michael@0: GLint i = 0; // the GL api (glGetIntegerv) only does signed ints michael@0: gl->fGetIntegerv(pname, &i); michael@0: GLuint i_unsigned(i); // this is where -1 becomes 2^32-1 michael@0: double i_double(i_unsigned); // pass as FP value to allow large values such as 2^32-1. michael@0: return JS::DoubleValue(i_double); michael@0: } michael@0: michael@0: // float michael@0: case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: { michael@0: if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) { michael@0: GLfloat f = 0.f; michael@0: gl->fGetFloatv(pname, &f); michael@0: return JS::DoubleValue(f); michael@0: } else { michael@0: break; michael@0: } michael@0: } michael@0: case LOCAL_GL_DEPTH_CLEAR_VALUE: michael@0: case LOCAL_GL_LINE_WIDTH: michael@0: case LOCAL_GL_POLYGON_OFFSET_FACTOR: michael@0: case LOCAL_GL_POLYGON_OFFSET_UNITS: michael@0: case LOCAL_GL_SAMPLE_COVERAGE_VALUE: { michael@0: GLfloat f = 0.f; michael@0: gl->fGetFloatv(pname, &f); michael@0: return JS::DoubleValue(f); michael@0: } michael@0: michael@0: // bool michael@0: case LOCAL_GL_BLEND: michael@0: case LOCAL_GL_DEPTH_TEST: michael@0: case LOCAL_GL_STENCIL_TEST: michael@0: case LOCAL_GL_CULL_FACE: michael@0: case LOCAL_GL_DITHER: michael@0: case LOCAL_GL_POLYGON_OFFSET_FILL: michael@0: case LOCAL_GL_SCISSOR_TEST: michael@0: case LOCAL_GL_SAMPLE_COVERAGE_INVERT: michael@0: case LOCAL_GL_DEPTH_WRITEMASK: { michael@0: realGLboolean b = 0; michael@0: gl->fGetBooleanv(pname, &b); michael@0: return JS::BooleanValue(bool(b)); michael@0: } michael@0: michael@0: // bool, WebGL-specific michael@0: case UNPACK_FLIP_Y_WEBGL: michael@0: return JS::BooleanValue(mPixelStoreFlipY); michael@0: case UNPACK_PREMULTIPLY_ALPHA_WEBGL: michael@0: return JS::BooleanValue(mPixelStorePremultiplyAlpha); michael@0: michael@0: // uint, WebGL-specific michael@0: case UNPACK_COLORSPACE_CONVERSION_WEBGL: michael@0: return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion)); michael@0: michael@0: //////////////////////////////// michael@0: // Complex values michael@0: michael@0: // 2 floats michael@0: case LOCAL_GL_DEPTH_RANGE: michael@0: case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: michael@0: case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: { michael@0: GLfloat fv[2] = { 0 }; michael@0: gl->fGetFloatv(pname, fv); michael@0: JSObject* obj = Float32Array::Create(cx, this, 2, fv); michael@0: if (!obj) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: michael@0: // 4 floats michael@0: case LOCAL_GL_COLOR_CLEAR_VALUE: michael@0: case LOCAL_GL_BLEND_COLOR: { michael@0: GLfloat fv[4] = { 0 }; michael@0: gl->fGetFloatv(pname, fv); michael@0: JSObject* obj = Float32Array::Create(cx, this, 4, fv); michael@0: if (!obj) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: michael@0: // 2 ints michael@0: case LOCAL_GL_MAX_VIEWPORT_DIMS: { michael@0: GLint iv[2] = { 0 }; michael@0: gl->fGetIntegerv(pname, iv); michael@0: JSObject* obj = Int32Array::Create(cx, this, 2, iv); michael@0: if (!obj) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: michael@0: // 4 ints michael@0: case LOCAL_GL_SCISSOR_BOX: michael@0: case LOCAL_GL_VIEWPORT: { michael@0: GLint iv[4] = { 0 }; michael@0: gl->fGetIntegerv(pname, iv); michael@0: JSObject* obj = Int32Array::Create(cx, this, 4, iv); michael@0: if (!obj) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return JS::ObjectOrNullValue(obj); michael@0: } michael@0: michael@0: // 4 bools michael@0: case LOCAL_GL_COLOR_WRITEMASK: { michael@0: realGLboolean gl_bv[4] = { 0 }; michael@0: gl->fGetBooleanv(pname, gl_bv); michael@0: bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]), michael@0: bool(gl_bv[2]), bool(gl_bv[3]) }; michael@0: JS::Rooted arr(cx); michael@0: if (!ToJSValue(cx, vals, &arr)) { michael@0: rv = NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: return arr; michael@0: } michael@0: michael@0: case LOCAL_GL_ARRAY_BUFFER_BINDING: { michael@0: return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: { michael@0: if (!IsWebGL2()) { michael@0: break; michael@0: } michael@0: return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: { michael@0: return WebGLObjectAsJSValue(cx, mBoundVertexArray->mBoundElementArrayBuffer.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_RENDERBUFFER_BINDING: { michael@0: return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_FRAMEBUFFER_BINDING: { michael@0: return WebGLObjectAsJSValue(cx, mBoundFramebuffer.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_CURRENT_PROGRAM: { michael@0: return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_TEXTURE_BINDING_2D: { michael@0: return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv); michael@0: } michael@0: michael@0: case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: { michael@0: return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv); michael@0: } michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: ErrorInvalidEnumInfo("getParameter: parameter", pname); michael@0: return JS::NullValue(); michael@0: } michael@0: michael@0: void michael@0: WebGLContext::GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index, michael@0: JS::MutableHandle retval) michael@0: { michael@0: if (IsContextLost()) { michael@0: retval.setNull(); michael@0: return; michael@0: } michael@0: michael@0: MakeContextCurrent(); michael@0: michael@0: switch (pname) { michael@0: case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING: michael@0: { michael@0: if (index >= mGLMaxTransformFeedbackSeparateAttribs) { michael@0: ErrorInvalidValue("getParameterIndexed: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", index); michael@0: retval.setNull(); michael@0: return; michael@0: } michael@0: retval.setNull(); // See bug 903594 michael@0: return; michael@0: } michael@0: michael@0: default: michael@0: break; michael@0: } michael@0: michael@0: ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname); michael@0: retval.setNull(); michael@0: } michael@0: michael@0: bool michael@0: WebGLContext::IsEnabled(GLenum cap) michael@0: { michael@0: if (IsContextLost()) michael@0: return false; michael@0: michael@0: if (!ValidateCapabilityEnum(cap, "isEnabled")) michael@0: return false; michael@0: michael@0: MakeContextCurrent(); michael@0: return gl->fIsEnabled(cap); michael@0: } michael@0: michael@0: bool michael@0: WebGLContext::ValidateCapabilityEnum(GLenum cap, const char* info) michael@0: { michael@0: switch (cap) { michael@0: case LOCAL_GL_BLEND: michael@0: case LOCAL_GL_CULL_FACE: michael@0: case LOCAL_GL_DEPTH_TEST: michael@0: case LOCAL_GL_DITHER: michael@0: case LOCAL_GL_POLYGON_OFFSET_FILL: michael@0: case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE: michael@0: case LOCAL_GL_SAMPLE_COVERAGE: michael@0: case LOCAL_GL_SCISSOR_TEST: michael@0: case LOCAL_GL_STENCIL_TEST: michael@0: return true; michael@0: case LOCAL_GL_RASTERIZER_DISCARD: michael@0: return IsWebGL2(); michael@0: default: michael@0: ErrorInvalidEnumInfo(info, cap); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: realGLboolean* michael@0: WebGLContext::GetStateTrackingSlot(GLenum cap) michael@0: { michael@0: switch (cap) { michael@0: case LOCAL_GL_SCISSOR_TEST: michael@0: return &mScissorTestEnabled; michael@0: case LOCAL_GL_DITHER: michael@0: return &mDitherEnabled; michael@0: case LOCAL_GL_RASTERIZER_DISCARD: michael@0: return &mRasterizerDiscardEnabled; michael@0: } michael@0: michael@0: return nullptr; michael@0: }