bool WebGLContext::IsFormatValidForFB(GLenum sizedFormat) const { switch (sizedFormat) { case LOCAL_GL_RGB8: case LOCAL_GL_RGBA8: case LOCAL_GL_RGB565: case LOCAL_GL_RGB5_A1: case LOCAL_GL_RGBA4: return true; case LOCAL_GL_SRGB8: case LOCAL_GL_SRGB8_ALPHA8_EXT: return IsExtensionEnabled(WebGLExtensionID::EXT_sRGB); case LOCAL_GL_RGB32F: case LOCAL_GL_RGBA32F: return IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float); case LOCAL_GL_RGB16F: case LOCAL_GL_RGBA16F: return IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float); } return false; }
void WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) { if (IsContextLost()) return; MakeContextCurrent(); const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_float) || IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) || IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float)); if (!supportsFloatColorBuffers) { r = GLClampFloat(r); g = GLClampFloat(g); b = GLClampFloat(b); a = GLClampFloat(a); } gl->fClearColor(r, g, b, a); mColorClearValue[0] = r; mColorClearValue[1] = g; mColorClearValue[2] = b; mColorClearValue[3] = a; }
webgl::ShaderValidator* WebGLContext::CreateShaderValidator(GLenum shaderType) const { if (mBypassShaderValidation) return nullptr; ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC; ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT; // If we're using WebGL2 we want a more specific version of GLSL if (IsWebGL2()) outputLanguage = ShaderOutput(gl); ShBuiltInResources resources; memset(&resources, 0, sizeof(resources)); ShInitBuiltInResources(&resources); resources.HashFunction = webgl::IdentifierHashFunc; resources.MaxVertexAttribs = mGLMaxVertexAttribs; resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors; resources.MaxVaryingVectors = mGLMaxVaryingVectors; resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits; resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits; resources.MaxTextureImageUnits = mGLMaxTextureImageUnits; resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors; resources.MaxDrawBuffers = mGLMaxDrawBuffers; if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth)) resources.EXT_frag_depth = 1; if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) resources.OES_standard_derivatives = 1; if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) resources.EXT_draw_buffers = 1; if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod)) resources.EXT_shader_texture_lod = 1; // Tell ANGLE to allow highp in frag shaders. (unless disabled) // If underlying GLES doesn't have highp in frag shaders, it should complain anyways. resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1; if (gl->WorkAroundDriverBugs()) { #ifdef XP_MACOSX if (gl->Vendor() == gl::GLVendor::NVIDIA) { // Work around bug 890432 resources.MaxExpressionComplexity = 1000; } #endif } int compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl); return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources, compileOptions); }
void WebGLContext::GetQuery(JSContext* cx, GLenum target, GLenum pname, JS::MutableHandleValue retval) { const FuncScope funcScope(*this, "getQuery"); retval.setNull(); if (IsContextLost()) return; switch (pname) { case LOCAL_GL_CURRENT_QUERY_EXT: { if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query) && target == LOCAL_GL_TIMESTAMP) { // Doesn't seem illegal to ask about, but is always null. // TIMESTAMP has no slot, so ValidateQuerySlotByTarget would generate // INVALID_ENUM. return; } const auto& slot = ValidateQuerySlotByTarget(target); if (!slot || !*slot) return; const auto& query = *slot; if (target != query->Target()) return; JS::Rooted<JS::Value> v(cx); dom::GetOrCreateDOMReflector(cx, slot->get(), &v); retval.set(v); } return; case LOCAL_GL_QUERY_COUNTER_BITS_EXT: if (!IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) break; if (target != LOCAL_GL_TIME_ELAPSED_EXT && target != LOCAL_GL_TIMESTAMP_EXT) { ErrorInvalidEnumInfo("target", target); return; } { GLint bits = 0; gl->fGetQueryiv(target, pname, &bits); if (!Has64BitTimestamps() && bits > 32) { bits = 32; } retval.set(JS::Int32Value(bits)); } return; default: break; } ErrorInvalidEnumInfo("pname", pname); }
WebGLRefPtr<WebGLQuery>* WebGLContext::ValidateQuerySlotByTarget( GLenum target) { if (IsWebGL2()) { switch (target) { case LOCAL_GL_ANY_SAMPLES_PASSED: case LOCAL_GL_ANY_SAMPLES_PASSED_CONSERVATIVE: return &mQuerySlot_SamplesPassed; case LOCAL_GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN: return &mQuerySlot_TFPrimsWritten; default: break; } } if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) { switch (target) { case LOCAL_GL_TIME_ELAPSED_EXT: return &mQuerySlot_TimeElapsed; default: break; } } ErrorInvalidEnumInfo("target", target); return nullptr; }
bool WebGLContext::ValidateBlendEquationEnum(GLenum mode, const char* info) { switch (mode) { case LOCAL_GL_FUNC_ADD: case LOCAL_GL_FUNC_SUBTRACT: case LOCAL_GL_FUNC_REVERSE_SUBTRACT: return true; case LOCAL_GL_MIN: case LOCAL_GL_MAX: if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::EXT_blend_minmax)) { return true; } break; default: break; } ErrorInvalidEnumInfo(info, mode); return false; }
ValidateOutputs::ValidateOutputs(const TExtensionBehavior &extBehavior, int maxDrawBuffers) : TIntermTraverser(true, false, false), mMaxDrawBuffers(maxDrawBuffers), mAllowUnspecifiedOutputLocationResolution( IsExtensionEnabled(extBehavior, "GL_EXT_blend_func_extended")) { }
bool WebGLContext::InitWebGL2() { MOZ_ASSERT(IsWebGL2(), "WebGLContext is not a WebGL 2 context!"); // check OpenGL features if (!gl->IsSupported(gl::GLFeature::occlusion_query) && !gl->IsSupported(gl::GLFeature::occlusion_query_boolean)) { // On desktop, we fake occlusion_query_boolean with occlusion_query if // necessary. (See WebGL2ContextQueries.cpp) GenerateWarning("WebGL 2 unavailable. Requires occlusion queries."); return false; } std::vector<gl::GLFeature> missingList; for (size_t i = 0; i < ArrayLength(kRequiredFeatures); i++) { if (!gl->IsSupported(kRequiredFeatures[i])) missingList.push_back(kRequiredFeatures[i]); } if (missingList.size()) { nsAutoCString exts; for (auto itr = missingList.begin(); itr != missingList.end(); ++itr) { exts.AppendLiteral("\n "); exts.Append(gl::GLContext::GetFeatureName(*itr)); } GenerateWarning("WebGL 2 unavailable. The following required features are" " unavailible: %s", exts.BeginReading()); return false; } // ok WebGL 2 is compatible, we can enable natively supported extensions. for (size_t i = 0; i < ArrayLength(kNativelySupportedExtensions); i++) { EnableExtension(kNativelySupportedExtensions[i]); MOZ_ASSERT(IsExtensionEnabled(kNativelySupportedExtensions[i])); } // we initialise WebGL 2 related stuff. gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs); gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS, &mGLMaxUniformBufferBindings); mBoundTransformFeedbackBuffers.SetLength(mGLMaxTransformFeedbackSeparateAttribs); mBoundUniformBuffers.SetLength(mGLMaxUniformBufferBindings); mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0); mBoundTransformFeedback = mDefaultTransformFeedback; mBypassShaderValidation = true; return true; }
WebGLExtensionBase* WebGLContext::EnableSupportedExtension(JSContext* js, WebGLExtensionID ext) { if (!IsExtensionEnabled(ext)) { if (!IsExtensionSupported(js, ext)) return nullptr; EnableExtension(ext); } return mExtensions[ext]; }
WebGLExtensionBase* WebGLContext::EnableSupportedExtension(dom::CallerType callerType, WebGLExtensionID ext) { if (!IsExtensionEnabled(ext)) { if (!IsExtensionSupported(callerType, ext)) return nullptr; EnableExtension(ext); } return mExtensions[ext]; }
void WebGLContext::AssertCachedBindings() const { #ifdef DEBUG gl::GLContext::LocalErrorScope errorScope(*gl); if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, mBoundVertexArray->mGLName); } GLint stencilBits = 0; if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer. const GLuint stencilRefMask = (1 << stencilBits) - 1; AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); } // Program GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); // Textures GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0; AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture); WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound); curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound); // Buffers bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(mBoundVertexArray); WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer; bound = curBuff ? curBuff->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError())); #endif // We do not check the renderbuffer binding, because we never rely on it // matching. }
bool WebGLContext::IsTexParamValid(GLenum pname) const { switch (pname) { case LOCAL_GL_TEXTURE_MIN_FILTER: case LOCAL_GL_TEXTURE_MAG_FILTER: case LOCAL_GL_TEXTURE_WRAP_S: case LOCAL_GL_TEXTURE_WRAP_T: return true; case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT: return IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic); default: return false; } }
bool WebGLContext::DrawInstanced_check(const char* info) { MOZ_ASSERT(IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)); if (!mBufferFetchingHasPerVertex) { /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt * If all of the enabled vertex attribute arrays that are bound to active * generic attributes in the program have a non-zero divisor, the draw * call should return INVALID_OPERATION. * * NB: This also appears to apply to NV_instanced_arrays, though the * INVALID_OPERATION emission is not explicitly stated. * ARB_instanced_arrays does not have this restriction. */ ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info); return false; } return true; }
bool WebGLContext::DrawElements_check(const char* funcName, GLenum mode, GLsizei vertCount, GLenum type, WebGLintptr byteOffset, GLsizei instanceCount) { if (!ValidateDrawModeEnum(mode, funcName)) return false; if (mBoundTransformFeedback && mBoundTransformFeedback->mIsActive && !mBoundTransformFeedback->mIsPaused) { ErrorInvalidOperation("%s: DrawElements* functions are incompatible with" " transform feedback.", funcName); return false; } if (!ValidateNonNegative(funcName, "vertCount", vertCount) || !ValidateNonNegative(funcName, "byteOffset", byteOffset) || !ValidateNonNegative(funcName, "instanceCount", instanceCount)) { return false; } if (!ValidateStencilParamsForDrawCall()) return false; if (!vertCount || !instanceCount) return false; // No error, just early out. uint8_t bytesPerElem = 0; switch (type) { case LOCAL_GL_UNSIGNED_BYTE: bytesPerElem = 1; break; case LOCAL_GL_UNSIGNED_SHORT: bytesPerElem = 2; break; case LOCAL_GL_UNSIGNED_INT: if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) { bytesPerElem = 4; } break; } if (!bytesPerElem) { ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", funcName, type); return false; } if (byteOffset % bytesPerElem != 0) { ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`", funcName); return false; } //// if (IsWebGL2() && !gl->IsSupported(gl::GLFeature::prim_restart_fixed)) { MOZ_ASSERT(gl->IsSupported(gl::GLFeature::prim_restart)); if (mPrimRestartTypeBytes != bytesPerElem) { mPrimRestartTypeBytes = bytesPerElem; const uint32_t ones = UINT32_MAX >> (32 - 8*mPrimRestartTypeBytes); gl->fEnable(LOCAL_GL_PRIMITIVE_RESTART); gl->fPrimitiveRestartIndex(ones); }
void TranslatorGLSL::translate(TIntermNode *root, int compileOptions) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); writePragma(); // Write extension behaviour as needed writeExtensionBehavior(root); bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); emulatePrecision.writeEmulationHelpers(sink, getOutputType()); } // Write emulated built-in functions if needed. if (!getBuiltInFunctionEmulator().IsOutputEmpty()) { sink << "// BEGIN: Generated code for built-in function emulation\n\n"; sink << "#define webgl_emu_precision\n\n"; getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); sink << "// END: Generated code for built-in function emulation\n\n"; } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // if it's core profile shaders and they are used. if (getShaderType() == GL_FRAGMENT_SHADER) { const bool mayHaveESSL1SecondaryOutputs = IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") && getShaderVersion() == 100; const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); bool hasGLFragColor = false; bool hasGLFragData = false; bool hasGLSecondaryFragColor = false; bool hasGLSecondaryFragData = false; for (const auto &outputVar : outputVariables) { if (declareGLFragmentOutputs) { if (outputVar.name == "gl_FragColor") { ASSERT(!hasGLFragColor); hasGLFragColor = true; continue; } else if (outputVar.name == "gl_FragData") { ASSERT(!hasGLFragData); hasGLFragData = true; continue; } } if (mayHaveESSL1SecondaryOutputs) { if (outputVar.name == "gl_SecondaryFragColorEXT") { ASSERT(!hasGLSecondaryFragColor); hasGLSecondaryFragColor = true; continue; } else if (outputVar.name == "gl_SecondaryFragDataEXT") { ASSERT(!hasGLSecondaryFragData); hasGLSecondaryFragData = true; continue; } } } ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && (hasGLFragData || hasGLSecondaryFragData))); if (hasGLFragColor) { sink << "out vec4 webgl_FragColor;\n"; } if (hasGLFragData) { sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; } if (hasGLSecondaryFragColor) { sink << "out vec4 angle_SecondaryFragColor;\n"; } if (hasGLSecondaryFragData) { sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers << "];\n"; } } // Write translated shader. TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderVersion(), getOutputType()); root->traverse(&outputGLSL); }
JS::Value WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv) { if (IsContextLost()) return JS::NullValue(); MakeContextCurrent(); if (MinCapabilityMode()) { switch(pname) { //////////////////////////// // Single-value params // int case LOCAL_GL_MAX_VERTEX_ATTRIBS: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_ATTRIBS); case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS: return JS::Int32Value(MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS); case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS); case LOCAL_GL_MAX_VARYING_VECTORS: return JS::Int32Value(MINVALUE_GL_MAX_VARYING_VECTORS); case LOCAL_GL_MAX_TEXTURE_SIZE: return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_SIZE); case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: return JS::Int32Value(MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE); case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS: return JS::Int32Value(MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS); case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: return JS::Int32Value(MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS); case LOCAL_GL_MAX_RENDERBUFFER_SIZE: return JS::Int32Value(MINVALUE_GL_MAX_RENDERBUFFER_SIZE); default: // Return the real value; we're not overriding this one break; } } if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers)) { if (pname == LOCAL_GL_MAX_COLOR_ATTACHMENTS) { return JS::Int32Value(mGLMaxColorAttachments); } else if (pname == LOCAL_GL_MAX_DRAW_BUFFERS) { return JS::Int32Value(mGLMaxDrawBuffers); } else if (pname >= LOCAL_GL_DRAW_BUFFER0 && pname < GLenum(LOCAL_GL_DRAW_BUFFER0 + mGLMaxDrawBuffers)) { GLint iv = 0; gl->fGetIntegerv(pname, &iv); if (mBoundDrawFramebuffer) return JS::Int32Value(iv); const GLint index = (pname - LOCAL_GL_DRAW_BUFFER0); if (iv == LOCAL_GL_COLOR_ATTACHMENT0 + index) return JS::Int32Value(LOCAL_GL_BACK); return JS::Int32Value(LOCAL_GL_NONE); } } if (IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { if (pname == LOCAL_GL_VERTEX_ARRAY_BINDING) { WebGLVertexArray* vao = (mBoundVertexArray != mDefaultVertexArray) ? mBoundVertexArray.get() : nullptr; return WebGLObjectAsJSValue(cx, vao, rv); } } if (IsExtensionEnabled(WebGLExtensionID::EXT_disjoint_timer_query)) { if (pname == LOCAL_GL_TIMESTAMP_EXT) { GLuint64 iv = 0; gl->fGetInteger64v(pname, (GLint64*) &iv); // TODO: JS doesn't support 64-bit integers. Be lossy and // cast to double (53 bits) return JS::NumberValue(static_cast<double>(iv)); } else if (pname == LOCAL_GL_GPU_DISJOINT_EXT) { // When disjoint isn't supported, leave as false. realGLboolean disjoint = LOCAL_GL_FALSE; if (gl->IsExtensionSupported(gl::GLContext::EXT_disjoint_timer_query)) { gl->fGetBooleanv(pname, &disjoint); } return JS::BooleanValue(bool(disjoint)); } } // Privileged string params exposed by WEBGL_debug_renderer_info. // The privilege check is done in WebGLContext::IsExtensionSupported. // So here we just have to check that the extension is enabled. if (IsExtensionEnabled(WebGLExtensionID::WEBGL_debug_renderer_info)) { switch (pname) { case UNMASKED_VENDOR_WEBGL: case UNMASKED_RENDERER_WEBGL: { const char* overridePref = nullptr; GLenum driverEnum = LOCAL_GL_NONE; switch (pname) { case UNMASKED_RENDERER_WEBGL: overridePref = "webgl.renderer-string-override"; driverEnum = LOCAL_GL_RENDERER; break; case UNMASKED_VENDOR_WEBGL: overridePref = "webgl.vendor-string-override"; driverEnum = LOCAL_GL_VENDOR; break; default: MOZ_CRASH("bad `pname`"); } bool hasRetVal = false; nsAutoString ret; if (overridePref) { nsresult res = Preferences::GetString(overridePref, &ret); if (NS_SUCCEEDED(res) && ret.Length() > 0) hasRetVal = true; } if (!hasRetVal) { const char* chars = reinterpret_cast<const char*>(gl->fGetString(driverEnum)); ret = NS_ConvertASCIItoUTF16(chars); hasRetVal = true; } return StringValue(cx, ret, rv); } } } if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) { if (pname == LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT) { GLint i = 0; gl->fGetIntegerv(pname, &i); return JS::Int32Value(i); } } if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic)) { if (pname == LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT) { GLfloat f = 0.f; gl->fGetFloatv(pname, &f); return JS::NumberValue(f); } } switch (pname) { // // String params // case LOCAL_GL_VENDOR: case LOCAL_GL_RENDERER: return StringValue(cx, "Mozilla", rv); case LOCAL_GL_VERSION: return StringValue(cx, "WebGL 1.0", rv); case LOCAL_GL_SHADING_LANGUAGE_VERSION: return StringValue(cx, "WebGL GLSL ES 1.0", rv); //////////////////////////////// // Single-value params // unsigned int case LOCAL_GL_CULL_FACE_MODE: case LOCAL_GL_FRONT_FACE: case LOCAL_GL_ACTIVE_TEXTURE: case LOCAL_GL_STENCIL_FUNC: case LOCAL_GL_STENCIL_FAIL: case LOCAL_GL_STENCIL_PASS_DEPTH_FAIL: case LOCAL_GL_STENCIL_PASS_DEPTH_PASS: case LOCAL_GL_STENCIL_BACK_FUNC: case LOCAL_GL_STENCIL_BACK_FAIL: case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_FAIL: case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS: case LOCAL_GL_DEPTH_FUNC: case LOCAL_GL_BLEND_SRC_RGB: case LOCAL_GL_BLEND_SRC_ALPHA: case LOCAL_GL_BLEND_DST_RGB: case LOCAL_GL_BLEND_DST_ALPHA: case LOCAL_GL_BLEND_EQUATION_RGB: case LOCAL_GL_BLEND_EQUATION_ALPHA: case LOCAL_GL_GENERATE_MIPMAP_HINT: { GLint i = 0; gl->fGetIntegerv(pname, &i); return JS::NumberValue(uint32_t(i)); } case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: { if (mBoundReadFramebuffer) { FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus(); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { ErrorInvalidOperation("getParameter: Read framebuffer must be" " complete before querying" " IMPLEMENTATION_COLOR_READ_TYPE."); return JS::NullValue(); } } GLint i = 0; if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { gl->fGetIntegerv(pname, &i); } else { i = LOCAL_GL_UNSIGNED_BYTE; } return JS::NumberValue(uint32_t(i)); } case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: { if (mBoundReadFramebuffer) { FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus(); if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) { ErrorInvalidOperation("getParameter: Read framebuffer must be" " complete before querying" " IMPLEMENTATION_COLOR_READ_FORMAT."); return JS::NullValue(); } } GLint i = 0; if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) { gl->fGetIntegerv(pname, &i); } else { i = LOCAL_GL_RGBA; } return JS::NumberValue(uint32_t(i)); } // int case LOCAL_GL_STENCIL_REF: case LOCAL_GL_STENCIL_BACK_REF: { GLint stencilBits = 0; if (!GetStencilBits(&stencilBits)) return JS::NullValue(); // Assuming stencils have 8 bits const GLint stencilMask = (1 << stencilBits) - 1; GLint refValue = 0; gl->fGetIntegerv(pname, &refValue); return JS::Int32Value(refValue & stencilMask); } case LOCAL_GL_STENCIL_BITS: { GLint stencilBits = 0; GetStencilBits(&stencilBits); return JS::Int32Value(stencilBits); } case LOCAL_GL_STENCIL_CLEAR_VALUE: case LOCAL_GL_UNPACK_ALIGNMENT: case LOCAL_GL_PACK_ALIGNMENT: case LOCAL_GL_SUBPIXEL_BITS: case LOCAL_GL_SAMPLE_BUFFERS: case LOCAL_GL_SAMPLES: case LOCAL_GL_MAX_VERTEX_ATTRIBS: case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS: case LOCAL_GL_RED_BITS: case LOCAL_GL_GREEN_BITS: case LOCAL_GL_BLUE_BITS: case LOCAL_GL_DEPTH_BITS: { GLint i = 0; gl->fGetIntegerv(pname, &i); return JS::Int32Value(i); } case LOCAL_GL_ALPHA_BITS: { GLint i = 0; if (!mNeedsFakeNoAlpha) { gl->fGetIntegerv(pname, &i); } return JS::Int32Value(i); } case LOCAL_GL_MAX_TEXTURE_SIZE: return JS::Int32Value(mGLMaxTextureSize); case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE: return JS::Int32Value(mGLMaxCubeMapTextureSize); case LOCAL_GL_MAX_RENDERBUFFER_SIZE: return JS::Int32Value(mGLMaxRenderbufferSize); case LOCAL_GL_MAX_VERTEX_UNIFORM_VECTORS: return JS::Int32Value(mGLMaxVertexUniformVectors); case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS: return JS::Int32Value(mGLMaxFragmentUniformVectors); case LOCAL_GL_MAX_VARYING_VECTORS: return JS::Int32Value(mGLMaxVaryingVectors); case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS: return JS::Int32Value(0); case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS: { uint32_t length = mCompressedTextureFormats.Length(); JSObject* obj = dom::Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements()); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } return JS::ObjectOrNullValue(obj); } // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as // javascript integer values. We just return them as doubles and javascript doesn't care. case LOCAL_GL_STENCIL_BACK_VALUE_MASK: return JS::DoubleValue(mStencilValueMaskBack); // pass as FP value to allow large values such as 2^32-1. case LOCAL_GL_STENCIL_BACK_WRITEMASK: return JS::DoubleValue(mStencilWriteMaskBack); case LOCAL_GL_STENCIL_VALUE_MASK: return JS::DoubleValue(mStencilValueMaskFront); case LOCAL_GL_STENCIL_WRITEMASK: return JS::DoubleValue(mStencilWriteMaskFront); // float case LOCAL_GL_DEPTH_CLEAR_VALUE: case LOCAL_GL_LINE_WIDTH: case LOCAL_GL_POLYGON_OFFSET_FACTOR: case LOCAL_GL_POLYGON_OFFSET_UNITS: case LOCAL_GL_SAMPLE_COVERAGE_VALUE: { GLfloat f = 0.f; gl->fGetFloatv(pname, &f); return JS::DoubleValue(f); } // bool case LOCAL_GL_BLEND: case LOCAL_GL_DEPTH_TEST: case LOCAL_GL_STENCIL_TEST: case LOCAL_GL_CULL_FACE: case LOCAL_GL_DITHER: case LOCAL_GL_POLYGON_OFFSET_FILL: case LOCAL_GL_SCISSOR_TEST: case LOCAL_GL_SAMPLE_COVERAGE_INVERT: case LOCAL_GL_DEPTH_WRITEMASK: { realGLboolean b = 0; gl->fGetBooleanv(pname, &b); return JS::BooleanValue(bool(b)); } // bool, WebGL-specific case UNPACK_FLIP_Y_WEBGL: return JS::BooleanValue(mPixelStoreFlipY); case UNPACK_PREMULTIPLY_ALPHA_WEBGL: return JS::BooleanValue(mPixelStorePremultiplyAlpha); // uint, WebGL-specific case UNPACK_COLORSPACE_CONVERSION_WEBGL: return JS::NumberValue(uint32_t(mPixelStoreColorspaceConversion)); //////////////////////////////// // Complex values // 2 floats case LOCAL_GL_DEPTH_RANGE: case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: { GLfloat fv[2] = { 0 }; gl->fGetFloatv(pname, fv); JSObject* obj = dom::Float32Array::Create(cx, this, 2, fv); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } return JS::ObjectOrNullValue(obj); } // 4 floats case LOCAL_GL_COLOR_CLEAR_VALUE: case LOCAL_GL_BLEND_COLOR: { GLfloat fv[4] = { 0 }; gl->fGetFloatv(pname, fv); JSObject* obj = dom::Float32Array::Create(cx, this, 4, fv); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } return JS::ObjectOrNullValue(obj); } // 2 ints case LOCAL_GL_MAX_VIEWPORT_DIMS: { GLint iv[2] = { 0 }; gl->fGetIntegerv(pname, iv); JSObject* obj = dom::Int32Array::Create(cx, this, 2, iv); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } return JS::ObjectOrNullValue(obj); } // 4 ints case LOCAL_GL_SCISSOR_BOX: case LOCAL_GL_VIEWPORT: { GLint iv[4] = { 0 }; gl->fGetIntegerv(pname, iv); JSObject* obj = dom::Int32Array::Create(cx, this, 4, iv); if (!obj) { rv = NS_ERROR_OUT_OF_MEMORY; } return JS::ObjectOrNullValue(obj); } // 4 bools case LOCAL_GL_COLOR_WRITEMASK: { realGLboolean gl_bv[4] = { 0 }; gl->fGetBooleanv(pname, gl_bv); bool vals[4] = { bool(gl_bv[0]), bool(gl_bv[1]), bool(gl_bv[2]), bool(gl_bv[3]) }; JS::Rooted<JS::Value> arr(cx); if (!dom::ToJSValue(cx, vals, &arr)) { rv = NS_ERROR_OUT_OF_MEMORY; } return arr; } case LOCAL_GL_ARRAY_BUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv); } case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundVertexArray->mElementArrayBuffer.get(), rv); } case LOCAL_GL_RENDERBUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv); } // DRAW_FRAMEBUFFER_BINDING is the same as FRAMEBUFFER_BINDING. case LOCAL_GL_FRAMEBUFFER_BINDING: { return WebGLObjectAsJSValue(cx, mBoundDrawFramebuffer.get(), rv); } case LOCAL_GL_CURRENT_PROGRAM: { return WebGLObjectAsJSValue(cx, mCurrentProgram.get(), rv); } case LOCAL_GL_TEXTURE_BINDING_2D: { return WebGLObjectAsJSValue(cx, mBound2DTextures[mActiveTexture].get(), rv); } case LOCAL_GL_TEXTURE_BINDING_CUBE_MAP: { return WebGLObjectAsJSValue(cx, mBoundCubeMapTextures[mActiveTexture].get(), rv); } default: break; } ErrorInvalidEnumInfo("getParameter: parameter", pname); return JS::NullValue(); }
bool WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset, GLsizei primcount, const char* info, GLuint* out_upperBound) { if (count < 0 || byteOffset < 0) { ErrorInvalidValue("%s: negative count or offset", info); return false; } if (primcount < 0) { ErrorInvalidValue("%s: negative primcount", info); return false; } if (!ValidateStencilParamsForDrawCall()) { return false; } // If count is 0, there's nothing to do. if (count == 0 || primcount == 0) return false; uint8_t bytesPerElem = 0; switch (type) { case LOCAL_GL_UNSIGNED_BYTE: bytesPerElem = 1; break; case LOCAL_GL_UNSIGNED_SHORT: bytesPerElem = 2; break; case LOCAL_GL_UNSIGNED_INT: if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint)) { bytesPerElem = 4; } break; } if (!bytesPerElem) { ErrorInvalidEnum("%s: Invalid `type`: 0x%04x", info, type); return false; } if (byteOffset % bytesPerElem != 0) { ErrorInvalidOperation("%s: `byteOffset` must be a multiple of the size of `type`", info); return false; } const GLsizei first = byteOffset / bytesPerElem; const CheckedUint32 checked_byteCount = bytesPerElem * CheckedUint32(count); if (!checked_byteCount.isValid()) { ErrorInvalidValue("%s: overflow in byteCount", info); return false; } // Any checks below this depend on a program being available. if (!mCurrentProgram) { ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info); return false; } if (!mBoundVertexArray->mElementArrayBuffer) { ErrorInvalidOperation("%s: must have element array buffer binding", info); return false; } WebGLBuffer& elemArrayBuffer = *mBoundVertexArray->mElementArrayBuffer; if (!elemArrayBuffer.ByteLength()) { ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info); return false; } CheckedInt<GLsizei> checked_neededByteCount = checked_byteCount.toChecked<GLsizei>() + byteOffset; if (!checked_neededByteCount.isValid()) { ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info); return false; } if (uint32_t(checked_neededByteCount.value()) > elemArrayBuffer.ByteLength()) { ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info); return false; } if (!ValidateBufferFetching(info)) return false; if (!mMaxFetchedVertices || !elemArrayBuffer.Validate(type, mMaxFetchedVertices - 1, first, count, out_upperBound)) { ErrorInvalidOperation( "%s: bound vertex attribute buffers do not have sufficient " "size for given indices from the bound element array", info); return false; } if (uint32_t(primcount) > mMaxFetchedInstances) { ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info); return false; } // Bug 1008310 - Check if buffer has been used with a different previous type if (elemArrayBuffer.IsElementArrayUsedWithMultipleTypes()) { GenerateWarning("%s: bound element array buffer previously used with a type other than " "%s, this will affect performance.", info, WebGLContext::EnumName(type)); } MOZ_ASSERT(gl->IsCurrent()); if (mBoundDrawFramebuffer) { if (!mBoundDrawFramebuffer->ValidateAndInitAttachments(info)) return false; } else { ClearBackbufferIfNeeded(); } if (!DoFakeVertexAttrib0(mMaxFetchedVertices)) { return false; } return true; }
void WebGLContext::AssertCachedBindings() { #ifdef DEBUG MakeContextCurrent(); GetAndFlushUnderlyingGLErrors(); if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) { GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0; AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound); } // Framebuffers if (IsWebGL2()) { GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound); bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound); } else { MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer); GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound); } GLint stencilBits = 0; if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer. const GLuint stencilRefMask = (1 << stencilBits) - 1; AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront); AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack); } // Program GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound); // Textures GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0; AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture); WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound); curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP); bound = curTex ? curTex->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound); // Buffers bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(mBoundVertexArray); WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer; bound = curBuff ? curBuff->mGLName : 0; AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound); MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors()); #endif // We do not check the renderbuffer binding, because we never rely on it matching. }
void TranslatorGLSL::translate(TIntermNode *root, ShCompileOptions compileOptions) { TInfoSinkBase& sink = getInfoSink().obj; // Write GLSL version. writeVersion(root); // Write extension behaviour as needed writeExtensionBehavior(root); // Write pragmas after extensions because some drivers consider pragmas // like non-preprocessor tokens. writePragma(compileOptions); // If flattening the global invariant pragma, write invariant declarations for built-in // variables. It should be harmless to do this twice in the case that the shader also explicitly // did this. However, it's important to emit invariant qualifiers only for those built-in // variables that are actually used, to avoid affecting the behavior of the shader. if ((compileOptions & SH_FLATTEN_PRAGMA_STDGL_INVARIANT_ALL) && getPragma().stdgl.invariantAll) { ASSERT(wereVariablesCollected()); switch (getShaderType()) { case GL_VERTEX_SHADER: sink << "invariant gl_Position;\n"; // gl_PointSize should be declared invariant in both ESSL 1.00 and 3.00 fragment // shaders if it's statically referenced. conditionallyOutputInvariantDeclaration("gl_PointSize"); break; case GL_FRAGMENT_SHADER: // The preprocessor will reject this pragma if it's used in ESSL 3.00 fragment // shaders, so we can use simple logic to determine whether to declare these // variables invariant. conditionallyOutputInvariantDeclaration("gl_FragCoord"); conditionallyOutputInvariantDeclaration("gl_PointCoord"); break; default: // Currently not reached, but leave this in for future expansion. ASSERT(false); break; } } if ((compileOptions & SH_REWRITE_TEXELFETCHOFFSET_TO_TEXELFETCH) != 0) { sh::RewriteTexelFetchOffset(root, getSymbolTable(), getShaderVersion()); } bool precisionEmulation = getResources().WEBGL_debug_shader_precision && getPragma().debugShaderPrecision; if (precisionEmulation) { EmulatePrecision emulatePrecision(getSymbolTable(), getShaderVersion()); root->traverse(&emulatePrecision); emulatePrecision.updateTree(); emulatePrecision.writeEmulationHelpers(sink, getShaderVersion(), getOutputType()); } // Write emulated built-in functions if needed. if (!getBuiltInFunctionEmulator().IsOutputEmpty()) { sink << "// BEGIN: Generated code for built-in function emulation\n\n"; sink << "#define webgl_emu_precision\n\n"; getBuiltInFunctionEmulator().OutputEmulatedFunctions(sink); sink << "// END: Generated code for built-in function emulation\n\n"; } // Write array bounds clamping emulation if needed. getArrayBoundsClamper().OutputClampingFunctionDefinition(sink); // Declare gl_FragColor and glFragData as webgl_FragColor and webgl_FragData // if it's core profile shaders and they are used. if (getShaderType() == GL_FRAGMENT_SHADER) { const bool mayHaveESSL1SecondaryOutputs = IsExtensionEnabled(getExtensionBehavior(), "GL_EXT_blend_func_extended") && getShaderVersion() == 100; const bool declareGLFragmentOutputs = IsGLSL130OrNewer(getOutputType()); bool hasGLFragColor = false; bool hasGLFragData = false; bool hasGLSecondaryFragColor = false; bool hasGLSecondaryFragData = false; for (const auto &outputVar : outputVariables) { if (declareGLFragmentOutputs) { if (outputVar.name == "gl_FragColor") { ASSERT(!hasGLFragColor); hasGLFragColor = true; continue; } else if (outputVar.name == "gl_FragData") { ASSERT(!hasGLFragData); hasGLFragData = true; continue; } } if (mayHaveESSL1SecondaryOutputs) { if (outputVar.name == "gl_SecondaryFragColorEXT") { ASSERT(!hasGLSecondaryFragColor); hasGLSecondaryFragColor = true; continue; } else if (outputVar.name == "gl_SecondaryFragDataEXT") { ASSERT(!hasGLSecondaryFragData); hasGLSecondaryFragData = true; continue; } } } ASSERT(!((hasGLFragColor || hasGLSecondaryFragColor) && (hasGLFragData || hasGLSecondaryFragData))); if (hasGLFragColor) { sink << "out vec4 webgl_FragColor;\n"; } if (hasGLFragData) { sink << "out vec4 webgl_FragData[gl_MaxDrawBuffers];\n"; } if (hasGLSecondaryFragColor) { sink << "out vec4 angle_SecondaryFragColor;\n"; } if (hasGLSecondaryFragData) { sink << "out vec4 angle_SecondaryFragData[" << getResources().MaxDualSourceDrawBuffers << "];\n"; } } if (getShaderType() == GL_COMPUTE_SHADER && isComputeShaderLocalSizeDeclared()) { const sh::WorkGroupSize &localSize = getComputeShaderLocalSize(); sink << "layout (local_size_x=" << localSize[0] << ", local_size_y=" << localSize[1] << ", local_size_z=" << localSize[2] << ") in;\n"; } // Write translated shader. TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable(), getShaderType(), getShaderVersion(), getOutputType(), compileOptions); root->traverse(&outputGLSL); }
void WebGLContext::EnableExtension(WebGLExtensionID ext) { MOZ_ASSERT(IsExtensionEnabled(ext) == false); WebGLExtensionBase* obj = nullptr; switch (ext) { // ANGLE_ case WebGLExtensionID::ANGLE_instanced_arrays: obj = new WebGLExtensionInstancedArrays(this); break; // EXT_ case WebGLExtensionID::EXT_blend_minmax: obj = new WebGLExtensionBlendMinMax(this); break; case WebGLExtensionID::EXT_color_buffer_float: obj = new WebGLExtensionEXTColorBufferFloat(this); break; case WebGLExtensionID::EXT_color_buffer_half_float: obj = new WebGLExtensionColorBufferHalfFloat(this); break; case WebGLExtensionID::EXT_disjoint_timer_query: obj = new WebGLExtensionDisjointTimerQuery(this); break; case WebGLExtensionID::EXT_frag_depth: obj = new WebGLExtensionFragDepth(this); break; case WebGLExtensionID::EXT_shader_texture_lod: obj = new WebGLExtensionShaderTextureLod(this); break; case WebGLExtensionID::EXT_sRGB: obj = new WebGLExtensionSRGB(this); break; case WebGLExtensionID::EXT_texture_filter_anisotropic: obj = new WebGLExtensionTextureFilterAnisotropic(this); break; // MOZ_ case WebGLExtensionID::MOZ_debug: obj = new WebGLExtensionMOZDebug(this); break; // OES_ case WebGLExtensionID::OES_element_index_uint: obj = new WebGLExtensionElementIndexUint(this); break; case WebGLExtensionID::OES_standard_derivatives: obj = new WebGLExtensionStandardDerivatives(this); break; case WebGLExtensionID::OES_texture_float: obj = new WebGLExtensionTextureFloat(this); break; case WebGLExtensionID::OES_texture_float_linear: obj = new WebGLExtensionTextureFloatLinear(this); break; case WebGLExtensionID::OES_texture_half_float: obj = new WebGLExtensionTextureHalfFloat(this); break; case WebGLExtensionID::OES_texture_half_float_linear: obj = new WebGLExtensionTextureHalfFloatLinear(this); break; case WebGLExtensionID::OES_vertex_array_object: obj = new WebGLExtensionVertexArray(this); break; // WEBGL_ case WebGLExtensionID::WEBGL_color_buffer_float: obj = new WebGLExtensionColorBufferFloat(this); break; case WebGLExtensionID::WEBGL_compressed_texture_astc: obj = new WebGLExtensionCompressedTextureASTC(this); break; case WebGLExtensionID::WEBGL_compressed_texture_atc: obj = new WebGLExtensionCompressedTextureATC(this); break; case WebGLExtensionID::WEBGL_compressed_texture_etc: obj = new WebGLExtensionCompressedTextureES3(this); break; case WebGLExtensionID::WEBGL_compressed_texture_etc1: obj = new WebGLExtensionCompressedTextureETC1(this); break; case WebGLExtensionID::WEBGL_compressed_texture_pvrtc: obj = new WebGLExtensionCompressedTexturePVRTC(this); break; case WebGLExtensionID::WEBGL_compressed_texture_s3tc: obj = new WebGLExtensionCompressedTextureS3TC(this); break; case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb: obj = new WebGLExtensionCompressedTextureS3TC_SRGB(this); break; case WebGLExtensionID::WEBGL_debug_renderer_info: obj = new WebGLExtensionDebugRendererInfo(this); break; case WebGLExtensionID::WEBGL_debug_shaders: obj = new WebGLExtensionDebugShaders(this); break; case WebGLExtensionID::WEBGL_depth_texture: obj = new WebGLExtensionDepthTexture(this); break; case WebGLExtensionID::WEBGL_draw_buffers: obj = new WebGLExtensionDrawBuffers(this); break; case WebGLExtensionID::WEBGL_lose_context: obj = new WebGLExtensionLoseContext(this); break; default: MOZ_ASSERT(false, "should not get there."); } mExtensions[ext] = obj; }
JS::Value WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, ErrorResult& rv) { const char funcName[] = "getVertexAttrib"; if (IsContextLost()) return JS::NullValue(); if (!ValidateAttribIndex(index, funcName)) return JS::NullValue(); MOZ_ASSERT(mBoundVertexArray); MakeContextCurrent(); switch (pname) { case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].mBuf.get(), rv); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE: return JS::Int32Value(mBoundVertexArray->mAttribs[index].Stride()); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE: return JS::Int32Value(mBoundVertexArray->mAttribs[index].Size()); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE: return JS::Int32Value(mBoundVertexArray->mAttribs[index].Type()); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_INTEGER: if (IsWebGL2()) return JS::BooleanValue(mBoundVertexArray->mAttribs[index].IntegerFunc()); break; case LOCAL_GL_VERTEX_ATTRIB_ARRAY_DIVISOR: if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays)) { return JS::Int32Value(mBoundVertexArray->mAttribs[index].mDivisor); } break; case LOCAL_GL_CURRENT_VERTEX_ATTRIB: { JS::RootedObject obj(cx); switch (mGenericVertexAttribTypes[index]) { case LOCAL_GL_FLOAT: obj = GetVertexAttribFloat32Array(cx, index); break; case LOCAL_GL_INT: obj = GetVertexAttribInt32Array(cx, index); break; case LOCAL_GL_UNSIGNED_INT: obj = GetVertexAttribUint32Array(cx, index); break; } if (!obj) rv.Throw(NS_ERROR_OUT_OF_MEMORY); return JS::ObjectOrNullValue(obj); } case LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED: return JS::BooleanValue(mBoundVertexArray->mAttribs[index].mEnabled); case LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED: return JS::BooleanValue(mBoundVertexArray->mAttribs[index].Normalized()); default: break; } ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname); return JS::NullValue(); }