diff -r 000000000000 -r 6474c204b198 content/canvas/src/WebGLContextExtensions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/content/canvas/src/WebGLContextExtensions.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "WebGLContext.h" +#include "WebGLContextUtils.h" +#include "WebGLExtensions.h" +#include "GLContext.h" + +#include "nsString.h" +#include "mozilla/Preferences.h" +#include "AccessCheck.h" + +using namespace mozilla; +using namespace mozilla::gl; + +/* static */ const char* +WebGLContext::GetExtensionString(WebGLExtensionID ext) +{ + // must match WebGLExtensionID. + // Once we can use variadic templates, EnumeratedArray should get a constructor + // allowing to initialize it directly without using this auxiliary plain array. + static const char *kExtensionNames[] = { + "ANGLE_instanced_arrays", + "EXT_color_buffer_half_float", + "EXT_frag_depth", + "EXT_sRGB", + "EXT_texture_filter_anisotropic", + "OES_element_index_uint", + "OES_standard_derivatives", + "OES_texture_float", + "OES_texture_float_linear", + "OES_texture_half_float", + "OES_texture_half_float_linear", + "OES_vertex_array_object", + "WEBGL_color_buffer_float", + "WEBGL_compressed_texture_atc", + "WEBGL_compressed_texture_etc1", + "WEBGL_compressed_texture_pvrtc", + "WEBGL_compressed_texture_s3tc", + "WEBGL_debug_renderer_info", + "WEBGL_debug_shaders", + "WEBGL_depth_texture", + "WEBGL_draw_buffers", + "WEBGL_lose_context" + }; + + typedef EnumeratedArray + names_array_t; + static const names_array_t kExtensionNamesEnumeratedArray(kExtensionNames); + + return kExtensionNamesEnumeratedArray[ext]; +} + +bool +WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const { + return mExtensions[ext]; +} + +bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const +{ + bool allowPrivilegedExts = false; + + // Chrome contexts need access to debug information even when + // webgl.disable-extensions is set. This is used in the graphics + // section of about:support. + if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) + allowPrivilegedExts = true; + + if (Preferences::GetBool("webgl.enable-privileged-extensions", false)) + allowPrivilegedExts = true; + + if (allowPrivilegedExts) { + switch (ext) { + case WebGLExtensionID::WEBGL_debug_renderer_info: + return true; + case WebGLExtensionID::WEBGL_debug_shaders: + return true; + default: + // For warnings-as-errors. + break; + } + } + + return IsExtensionSupported(ext); +} + +bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const +{ + if (mDisableExtensions) { + return false; + } + + switch (ext) { + case WebGLExtensionID::OES_element_index_uint: + return gl->IsSupported(GLFeature::element_index_uint); + case WebGLExtensionID::OES_standard_derivatives: + return gl->IsSupported(GLFeature::standard_derivatives); + case WebGLExtensionID::WEBGL_lose_context: + // We always support this extension. + return true; + case WebGLExtensionID::OES_texture_float: + return gl->IsSupported(GLFeature::texture_float); + case WebGLExtensionID::OES_texture_float_linear: + return gl->IsSupported(GLFeature::texture_float_linear); + case WebGLExtensionID::OES_texture_half_float: + // If we have Feature::texture_half_float, we must not be on ES2 + // and need to translate HALF_FLOAT_OES -> HALF_FLOAT. We do that + // right before making the relevant calls. + return gl->IsExtensionSupported(GLContext::OES_texture_half_float) || + gl->IsSupported(GLFeature::texture_half_float); + case WebGLExtensionID::OES_texture_half_float_linear: + return gl->IsSupported(GLFeature::texture_half_float_linear); + case WebGLExtensionID::WEBGL_color_buffer_float: + return WebGLExtensionColorBufferFloat::IsSupported(this); + case WebGLExtensionID::EXT_color_buffer_half_float: + return WebGLExtensionColorBufferHalfFloat::IsSupported(this); + case WebGLExtensionID::OES_vertex_array_object: + return WebGLExtensionVertexArray::IsSupported(this); + case WebGLExtensionID::EXT_texture_filter_anisotropic: + return gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic); + case WebGLExtensionID::WEBGL_compressed_texture_s3tc: + if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc)) { + return true; + } + else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) && + gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) && + gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5)) + { + return true; + } + return false; + case WebGLExtensionID::WEBGL_compressed_texture_atc: + return gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture); + case WebGLExtensionID::WEBGL_compressed_texture_etc1: + return gl->IsExtensionSupported(GLContext::OES_compressed_ETC1_RGB8_texture); + case WebGLExtensionID::WEBGL_compressed_texture_pvrtc: + return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc); + case WebGLExtensionID::WEBGL_depth_texture: + // WEBGL_depth_texture supports DEPTH_STENCIL textures + if (!gl->IsSupported(GLFeature::packed_depth_stencil)) { + return false; + } + return gl->IsSupported(GLFeature::depth_texture) || + gl->IsExtensionSupported(GLContext::ANGLE_depth_texture); + case WebGLExtensionID::ANGLE_instanced_arrays: + return WebGLExtensionInstancedArrays::IsSupported(this); + case WebGLExtensionID::EXT_sRGB: + return WebGLExtensionSRGB::IsSupported(this); + case WebGLExtensionID::WEBGL_draw_buffers: + return WebGLExtensionDrawBuffers::IsSupported(this); + case WebGLExtensionID::EXT_frag_depth: + return WebGLExtensionFragDepth::IsSupported(this); + default: + // For warnings-as-errors. + break; + } +// Uncomment this switch for any new extensions +#if 0 + if (Preferences::GetBool("webgl.enable-draft-extensions", false) || IsWebGL2()) { + switch (ext) { + default: + // For warnings-as-errors. + break; + } + } +#endif + + return false; +} + +static bool +CompareWebGLExtensionName(const nsACString& name, const char *other) +{ + return name.Equals(other, nsCaseInsensitiveCStringComparator()); +} + +void +WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, + JS::MutableHandle aRetval, + ErrorResult& rv) +{ + if (IsContextLost()) { + aRetval.set(nullptr); + return; + } + + NS_LossyConvertUTF16toASCII name(aName); + + WebGLExtensionID ext = WebGLExtensionID::Unknown; + + // step 1: figure what extension is wanted + for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) + { + WebGLExtensionID extension = WebGLExtensionID(i); + + if (CompareWebGLExtensionName(name, GetExtensionString(extension))) { + ext = extension; + break; + } + } + + if (ext == WebGLExtensionID::Unknown) + { + /** + * We keep backward compatibility for these deprecated vendor-prefixed + * alias. Do not add new ones anymore. Hide it behind the + * webgl.enable-draft-extensions flag instead. + */ + if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context")) { + ext = WebGLExtensionID::WEBGL_lose_context; + } + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc")) { + ext = WebGLExtensionID::WEBGL_compressed_texture_s3tc; + } + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc")) { + ext = WebGLExtensionID::WEBGL_compressed_texture_atc; + } + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc")) { + ext = WebGLExtensionID::WEBGL_compressed_texture_pvrtc; + } + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture")) { + ext = WebGLExtensionID::WEBGL_depth_texture; + } + + if (ext != WebGLExtensionID::Unknown) { + GenerateWarning("getExtension('%s'): MOZ_ prefixed WebGL extension strings are deprecated. " + "Support for them will be removed in the future. Use unprefixed extension strings. " + "To get draft extensions, set the webgl.enable-draft-extensions preference.", + name.get()); + } + } + + if (ext == WebGLExtensionID::Unknown) { + aRetval.set(nullptr); + return; + } + + // step 2: check if the extension is supported + if (!IsExtensionSupported(cx, ext)) { + aRetval.set(nullptr); + return; + } + + // step 3: if the extension hadn't been previously been created, create it now, thus enabling it + if (!IsExtensionEnabled(ext)) { + EnableExtension(ext); + } + + aRetval.set(WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv)); +} + +void +WebGLContext::EnableExtension(WebGLExtensionID ext) +{ + MOZ_ASSERT(IsExtensionEnabled(ext) == false); + + WebGLExtensionBase* obj = nullptr; + switch (ext) { + case WebGLExtensionID::OES_element_index_uint: + obj = new WebGLExtensionElementIndexUint(this); + break; + case WebGLExtensionID::OES_standard_derivatives: + obj = new WebGLExtensionStandardDerivatives(this); + break; + case WebGLExtensionID::EXT_texture_filter_anisotropic: + obj = new WebGLExtensionTextureFilterAnisotropic(this); + break; + case WebGLExtensionID::WEBGL_lose_context: + obj = new WebGLExtensionLoseContext(this); + break; + case WebGLExtensionID::WEBGL_compressed_texture_s3tc: + obj = new WebGLExtensionCompressedTextureS3TC(this); + break; + case WebGLExtensionID::WEBGL_compressed_texture_atc: + obj = new WebGLExtensionCompressedTextureATC(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_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::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::WEBGL_color_buffer_float: + obj = new WebGLExtensionColorBufferFloat(this); + break; + case WebGLExtensionID::EXT_color_buffer_half_float: + obj = new WebGLExtensionColorBufferHalfFloat(this); + break; + case WebGLExtensionID::WEBGL_draw_buffers: + obj = new WebGLExtensionDrawBuffers(this); + break; + case WebGLExtensionID::OES_vertex_array_object: + obj = new WebGLExtensionVertexArray(this); + break; + case WebGLExtensionID::ANGLE_instanced_arrays: + obj = new WebGLExtensionInstancedArrays(this); + break; + case WebGLExtensionID::EXT_sRGB: + obj = new WebGLExtensionSRGB(this); + break; + case WebGLExtensionID::EXT_frag_depth: + obj = new WebGLExtensionFragDepth(this); + break; + default: + MOZ_ASSERT(false, "should not get there."); + } + + mExtensions[ext] = obj; +} + +void +WebGLContext::GetSupportedExtensions(JSContext *cx, Nullable< nsTArray > &retval) +{ + retval.SetNull(); + if (IsContextLost()) + return; + + nsTArray& arr = retval.SetValue(); + + for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) + { + WebGLExtensionID extension = WebGLExtensionID(i); + + if (IsExtensionSupported(cx, extension)) { + arr.AppendElement(NS_ConvertUTF8toUTF16(GetExtensionString(extension))); + } + } + + /** + * We keep backward compatibility for these deprecated vendor-prefixed + * alias. Do not add new ones anymore. Hide it behind the + * webgl.enable-draft-extensions flag instead. + */ + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_lose_context)) + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context")); + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_s3tc)) + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc")); + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_atc)) + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc")); + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc")); + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_depth_texture)) + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture")); +} +