1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/src/WebGLContextExtensions.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,368 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "WebGLContext.h" 1.10 +#include "WebGLContextUtils.h" 1.11 +#include "WebGLExtensions.h" 1.12 +#include "GLContext.h" 1.13 + 1.14 +#include "nsString.h" 1.15 +#include "mozilla/Preferences.h" 1.16 +#include "AccessCheck.h" 1.17 + 1.18 +using namespace mozilla; 1.19 +using namespace mozilla::gl; 1.20 + 1.21 +/* static */ const char* 1.22 +WebGLContext::GetExtensionString(WebGLExtensionID ext) 1.23 +{ 1.24 + // must match WebGLExtensionID. 1.25 + // Once we can use variadic templates, EnumeratedArray should get a constructor 1.26 + // allowing to initialize it directly without using this auxiliary plain array. 1.27 + static const char *kExtensionNames[] = { 1.28 + "ANGLE_instanced_arrays", 1.29 + "EXT_color_buffer_half_float", 1.30 + "EXT_frag_depth", 1.31 + "EXT_sRGB", 1.32 + "EXT_texture_filter_anisotropic", 1.33 + "OES_element_index_uint", 1.34 + "OES_standard_derivatives", 1.35 + "OES_texture_float", 1.36 + "OES_texture_float_linear", 1.37 + "OES_texture_half_float", 1.38 + "OES_texture_half_float_linear", 1.39 + "OES_vertex_array_object", 1.40 + "WEBGL_color_buffer_float", 1.41 + "WEBGL_compressed_texture_atc", 1.42 + "WEBGL_compressed_texture_etc1", 1.43 + "WEBGL_compressed_texture_pvrtc", 1.44 + "WEBGL_compressed_texture_s3tc", 1.45 + "WEBGL_debug_renderer_info", 1.46 + "WEBGL_debug_shaders", 1.47 + "WEBGL_depth_texture", 1.48 + "WEBGL_draw_buffers", 1.49 + "WEBGL_lose_context" 1.50 + }; 1.51 + 1.52 + typedef EnumeratedArray<WebGLExtensionID, WebGLExtensionID::Max, const char*> 1.53 + names_array_t; 1.54 + static const names_array_t kExtensionNamesEnumeratedArray(kExtensionNames); 1.55 + 1.56 + return kExtensionNamesEnumeratedArray[ext]; 1.57 +} 1.58 + 1.59 +bool 1.60 +WebGLContext::IsExtensionEnabled(WebGLExtensionID ext) const { 1.61 + return mExtensions[ext]; 1.62 +} 1.63 + 1.64 +bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) const 1.65 +{ 1.66 + bool allowPrivilegedExts = false; 1.67 + 1.68 + // Chrome contexts need access to debug information even when 1.69 + // webgl.disable-extensions is set. This is used in the graphics 1.70 + // section of about:support. 1.71 + if (xpc::AccessCheck::isChrome(js::GetContextCompartment(cx))) 1.72 + allowPrivilegedExts = true; 1.73 + 1.74 + if (Preferences::GetBool("webgl.enable-privileged-extensions", false)) 1.75 + allowPrivilegedExts = true; 1.76 + 1.77 + if (allowPrivilegedExts) { 1.78 + switch (ext) { 1.79 + case WebGLExtensionID::WEBGL_debug_renderer_info: 1.80 + return true; 1.81 + case WebGLExtensionID::WEBGL_debug_shaders: 1.82 + return true; 1.83 + default: 1.84 + // For warnings-as-errors. 1.85 + break; 1.86 + } 1.87 + } 1.88 + 1.89 + return IsExtensionSupported(ext); 1.90 +} 1.91 + 1.92 +bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const 1.93 +{ 1.94 + if (mDisableExtensions) { 1.95 + return false; 1.96 + } 1.97 + 1.98 + switch (ext) { 1.99 + case WebGLExtensionID::OES_element_index_uint: 1.100 + return gl->IsSupported(GLFeature::element_index_uint); 1.101 + case WebGLExtensionID::OES_standard_derivatives: 1.102 + return gl->IsSupported(GLFeature::standard_derivatives); 1.103 + case WebGLExtensionID::WEBGL_lose_context: 1.104 + // We always support this extension. 1.105 + return true; 1.106 + case WebGLExtensionID::OES_texture_float: 1.107 + return gl->IsSupported(GLFeature::texture_float); 1.108 + case WebGLExtensionID::OES_texture_float_linear: 1.109 + return gl->IsSupported(GLFeature::texture_float_linear); 1.110 + case WebGLExtensionID::OES_texture_half_float: 1.111 + // If we have Feature::texture_half_float, we must not be on ES2 1.112 + // and need to translate HALF_FLOAT_OES -> HALF_FLOAT. We do that 1.113 + // right before making the relevant calls. 1.114 + return gl->IsExtensionSupported(GLContext::OES_texture_half_float) || 1.115 + gl->IsSupported(GLFeature::texture_half_float); 1.116 + case WebGLExtensionID::OES_texture_half_float_linear: 1.117 + return gl->IsSupported(GLFeature::texture_half_float_linear); 1.118 + case WebGLExtensionID::WEBGL_color_buffer_float: 1.119 + return WebGLExtensionColorBufferFloat::IsSupported(this); 1.120 + case WebGLExtensionID::EXT_color_buffer_half_float: 1.121 + return WebGLExtensionColorBufferHalfFloat::IsSupported(this); 1.122 + case WebGLExtensionID::OES_vertex_array_object: 1.123 + return WebGLExtensionVertexArray::IsSupported(this); 1.124 + case WebGLExtensionID::EXT_texture_filter_anisotropic: 1.125 + return gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic); 1.126 + case WebGLExtensionID::WEBGL_compressed_texture_s3tc: 1.127 + if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_s3tc)) { 1.128 + return true; 1.129 + } 1.130 + else if (gl->IsExtensionSupported(GLContext::EXT_texture_compression_dxt1) && 1.131 + gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt3) && 1.132 + gl->IsExtensionSupported(GLContext::ANGLE_texture_compression_dxt5)) 1.133 + { 1.134 + return true; 1.135 + } 1.136 + return false; 1.137 + case WebGLExtensionID::WEBGL_compressed_texture_atc: 1.138 + return gl->IsExtensionSupported(GLContext::AMD_compressed_ATC_texture); 1.139 + case WebGLExtensionID::WEBGL_compressed_texture_etc1: 1.140 + return gl->IsExtensionSupported(GLContext::OES_compressed_ETC1_RGB8_texture); 1.141 + case WebGLExtensionID::WEBGL_compressed_texture_pvrtc: 1.142 + return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc); 1.143 + case WebGLExtensionID::WEBGL_depth_texture: 1.144 + // WEBGL_depth_texture supports DEPTH_STENCIL textures 1.145 + if (!gl->IsSupported(GLFeature::packed_depth_stencil)) { 1.146 + return false; 1.147 + } 1.148 + return gl->IsSupported(GLFeature::depth_texture) || 1.149 + gl->IsExtensionSupported(GLContext::ANGLE_depth_texture); 1.150 + case WebGLExtensionID::ANGLE_instanced_arrays: 1.151 + return WebGLExtensionInstancedArrays::IsSupported(this); 1.152 + case WebGLExtensionID::EXT_sRGB: 1.153 + return WebGLExtensionSRGB::IsSupported(this); 1.154 + case WebGLExtensionID::WEBGL_draw_buffers: 1.155 + return WebGLExtensionDrawBuffers::IsSupported(this); 1.156 + case WebGLExtensionID::EXT_frag_depth: 1.157 + return WebGLExtensionFragDepth::IsSupported(this); 1.158 + default: 1.159 + // For warnings-as-errors. 1.160 + break; 1.161 + } 1.162 +// Uncomment this switch for any new extensions 1.163 +#if 0 1.164 + if (Preferences::GetBool("webgl.enable-draft-extensions", false) || IsWebGL2()) { 1.165 + switch (ext) { 1.166 + default: 1.167 + // For warnings-as-errors. 1.168 + break; 1.169 + } 1.170 + } 1.171 +#endif 1.172 + 1.173 + return false; 1.174 +} 1.175 + 1.176 +static bool 1.177 +CompareWebGLExtensionName(const nsACString& name, const char *other) 1.178 +{ 1.179 + return name.Equals(other, nsCaseInsensitiveCStringComparator()); 1.180 +} 1.181 + 1.182 +void 1.183 +WebGLContext::GetExtension(JSContext *cx, const nsAString& aName, 1.184 + JS::MutableHandle<JSObject*> aRetval, 1.185 + ErrorResult& rv) 1.186 +{ 1.187 + if (IsContextLost()) { 1.188 + aRetval.set(nullptr); 1.189 + return; 1.190 + } 1.191 + 1.192 + NS_LossyConvertUTF16toASCII name(aName); 1.193 + 1.194 + WebGLExtensionID ext = WebGLExtensionID::Unknown; 1.195 + 1.196 + // step 1: figure what extension is wanted 1.197 + for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) 1.198 + { 1.199 + WebGLExtensionID extension = WebGLExtensionID(i); 1.200 + 1.201 + if (CompareWebGLExtensionName(name, GetExtensionString(extension))) { 1.202 + ext = extension; 1.203 + break; 1.204 + } 1.205 + } 1.206 + 1.207 + if (ext == WebGLExtensionID::Unknown) 1.208 + { 1.209 + /** 1.210 + * We keep backward compatibility for these deprecated vendor-prefixed 1.211 + * alias. Do not add new ones anymore. Hide it behind the 1.212 + * webgl.enable-draft-extensions flag instead. 1.213 + */ 1.214 + if (CompareWebGLExtensionName(name, "MOZ_WEBGL_lose_context")) { 1.215 + ext = WebGLExtensionID::WEBGL_lose_context; 1.216 + } 1.217 + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_s3tc")) { 1.218 + ext = WebGLExtensionID::WEBGL_compressed_texture_s3tc; 1.219 + } 1.220 + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_atc")) { 1.221 + ext = WebGLExtensionID::WEBGL_compressed_texture_atc; 1.222 + } 1.223 + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_compressed_texture_pvrtc")) { 1.224 + ext = WebGLExtensionID::WEBGL_compressed_texture_pvrtc; 1.225 + } 1.226 + else if (CompareWebGLExtensionName(name, "MOZ_WEBGL_depth_texture")) { 1.227 + ext = WebGLExtensionID::WEBGL_depth_texture; 1.228 + } 1.229 + 1.230 + if (ext != WebGLExtensionID::Unknown) { 1.231 + GenerateWarning("getExtension('%s'): MOZ_ prefixed WebGL extension strings are deprecated. " 1.232 + "Support for them will be removed in the future. Use unprefixed extension strings. " 1.233 + "To get draft extensions, set the webgl.enable-draft-extensions preference.", 1.234 + name.get()); 1.235 + } 1.236 + } 1.237 + 1.238 + if (ext == WebGLExtensionID::Unknown) { 1.239 + aRetval.set(nullptr); 1.240 + return; 1.241 + } 1.242 + 1.243 + // step 2: check if the extension is supported 1.244 + if (!IsExtensionSupported(cx, ext)) { 1.245 + aRetval.set(nullptr); 1.246 + return; 1.247 + } 1.248 + 1.249 + // step 3: if the extension hadn't been previously been created, create it now, thus enabling it 1.250 + if (!IsExtensionEnabled(ext)) { 1.251 + EnableExtension(ext); 1.252 + } 1.253 + 1.254 + aRetval.set(WebGLObjectAsJSObject(cx, mExtensions[ext].get(), rv)); 1.255 +} 1.256 + 1.257 +void 1.258 +WebGLContext::EnableExtension(WebGLExtensionID ext) 1.259 +{ 1.260 + MOZ_ASSERT(IsExtensionEnabled(ext) == false); 1.261 + 1.262 + WebGLExtensionBase* obj = nullptr; 1.263 + switch (ext) { 1.264 + case WebGLExtensionID::OES_element_index_uint: 1.265 + obj = new WebGLExtensionElementIndexUint(this); 1.266 + break; 1.267 + case WebGLExtensionID::OES_standard_derivatives: 1.268 + obj = new WebGLExtensionStandardDerivatives(this); 1.269 + break; 1.270 + case WebGLExtensionID::EXT_texture_filter_anisotropic: 1.271 + obj = new WebGLExtensionTextureFilterAnisotropic(this); 1.272 + break; 1.273 + case WebGLExtensionID::WEBGL_lose_context: 1.274 + obj = new WebGLExtensionLoseContext(this); 1.275 + break; 1.276 + case WebGLExtensionID::WEBGL_compressed_texture_s3tc: 1.277 + obj = new WebGLExtensionCompressedTextureS3TC(this); 1.278 + break; 1.279 + case WebGLExtensionID::WEBGL_compressed_texture_atc: 1.280 + obj = new WebGLExtensionCompressedTextureATC(this); 1.281 + break; 1.282 + case WebGLExtensionID::WEBGL_compressed_texture_etc1: 1.283 + obj = new WebGLExtensionCompressedTextureETC1(this); 1.284 + break; 1.285 + case WebGLExtensionID::WEBGL_compressed_texture_pvrtc: 1.286 + obj = new WebGLExtensionCompressedTexturePVRTC(this); 1.287 + break; 1.288 + case WebGLExtensionID::WEBGL_debug_renderer_info: 1.289 + obj = new WebGLExtensionDebugRendererInfo(this); 1.290 + break; 1.291 + case WebGLExtensionID::WEBGL_debug_shaders: 1.292 + obj = new WebGLExtensionDebugShaders(this); 1.293 + break; 1.294 + case WebGLExtensionID::WEBGL_depth_texture: 1.295 + obj = new WebGLExtensionDepthTexture(this); 1.296 + break; 1.297 + case WebGLExtensionID::OES_texture_float: 1.298 + obj = new WebGLExtensionTextureFloat(this); 1.299 + break; 1.300 + case WebGLExtensionID::OES_texture_float_linear: 1.301 + obj = new WebGLExtensionTextureFloatLinear(this); 1.302 + break; 1.303 + case WebGLExtensionID::OES_texture_half_float: 1.304 + obj = new WebGLExtensionTextureHalfFloat(this); 1.305 + break; 1.306 + case WebGLExtensionID::OES_texture_half_float_linear: 1.307 + obj = new WebGLExtensionTextureHalfFloatLinear(this); 1.308 + break; 1.309 + case WebGLExtensionID::WEBGL_color_buffer_float: 1.310 + obj = new WebGLExtensionColorBufferFloat(this); 1.311 + break; 1.312 + case WebGLExtensionID::EXT_color_buffer_half_float: 1.313 + obj = new WebGLExtensionColorBufferHalfFloat(this); 1.314 + break; 1.315 + case WebGLExtensionID::WEBGL_draw_buffers: 1.316 + obj = new WebGLExtensionDrawBuffers(this); 1.317 + break; 1.318 + case WebGLExtensionID::OES_vertex_array_object: 1.319 + obj = new WebGLExtensionVertexArray(this); 1.320 + break; 1.321 + case WebGLExtensionID::ANGLE_instanced_arrays: 1.322 + obj = new WebGLExtensionInstancedArrays(this); 1.323 + break; 1.324 + case WebGLExtensionID::EXT_sRGB: 1.325 + obj = new WebGLExtensionSRGB(this); 1.326 + break; 1.327 + case WebGLExtensionID::EXT_frag_depth: 1.328 + obj = new WebGLExtensionFragDepth(this); 1.329 + break; 1.330 + default: 1.331 + MOZ_ASSERT(false, "should not get there."); 1.332 + } 1.333 + 1.334 + mExtensions[ext] = obj; 1.335 +} 1.336 + 1.337 +void 1.338 +WebGLContext::GetSupportedExtensions(JSContext *cx, Nullable< nsTArray<nsString> > &retval) 1.339 +{ 1.340 + retval.SetNull(); 1.341 + if (IsContextLost()) 1.342 + return; 1.343 + 1.344 + nsTArray<nsString>& arr = retval.SetValue(); 1.345 + 1.346 + for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) 1.347 + { 1.348 + WebGLExtensionID extension = WebGLExtensionID(i); 1.349 + 1.350 + if (IsExtensionSupported(cx, extension)) { 1.351 + arr.AppendElement(NS_ConvertUTF8toUTF16(GetExtensionString(extension))); 1.352 + } 1.353 + } 1.354 + 1.355 + /** 1.356 + * We keep backward compatibility for these deprecated vendor-prefixed 1.357 + * alias. Do not add new ones anymore. Hide it behind the 1.358 + * webgl.enable-draft-extensions flag instead. 1.359 + */ 1.360 + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_lose_context)) 1.361 + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_lose_context")); 1.362 + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_s3tc)) 1.363 + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_s3tc")); 1.364 + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_atc)) 1.365 + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_atc")); 1.366 + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_compressed_texture_pvrtc)) 1.367 + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_compressed_texture_pvrtc")); 1.368 + if (IsExtensionSupported(cx, WebGLExtensionID::WEBGL_depth_texture)) 1.369 + arr.AppendElement(NS_LITERAL_STRING("MOZ_WEBGL_depth_texture")); 1.370 +} 1.371 +