gecko-dev/dom/canvas/WebGLContextExtensions.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

567 строки
20 KiB
C++
Исходник Обычный вид История

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "WebGLContextEndpoint.h"
#include "WebGLContextUtils.h"
#include "WebGLExtensions.h"
#include "ClientWebGLExtensions.h"
#include "GLContext.h"
#include "nsString.h"
#include "nsContentUtils.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "AccessCheck.h"
namespace mozilla {
/*static*/ const char* ClientWebGLContext::GetExtensionString(
WebGLExtensionID ext) {
typedef EnumeratedArray<WebGLExtensionID, WebGLExtensionID::Max, const char*>
names_array_t;
static names_array_t sExtensionNamesEnumeratedArray;
static bool initialized = false;
if (!initialized) {
initialized = true;
#define WEBGL_EXTENSION_IDENTIFIER(x) \
sExtensionNamesEnumeratedArray[WebGLExtensionID::x] = #x;
WEBGL_EXTENSION_IDENTIFIER(ANGLE_instanced_arrays)
WEBGL_EXTENSION_IDENTIFIER(EXT_blend_minmax)
WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_float)
WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_half_float)
WEBGL_EXTENSION_IDENTIFIER(EXT_disjoint_timer_query)
WEBGL_EXTENSION_IDENTIFIER(EXT_float_blend)
WEBGL_EXTENSION_IDENTIFIER(EXT_frag_depth)
WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod)
WEBGL_EXTENSION_IDENTIFIER(EXT_sRGB)
WEBGL_EXTENSION_IDENTIFIER(EXT_texture_compression_bptc)
WEBGL_EXTENSION_IDENTIFIER(EXT_texture_compression_rgtc)
WEBGL_EXTENSION_IDENTIFIER(EXT_texture_filter_anisotropic)
WEBGL_EXTENSION_IDENTIFIER(MOZ_debug)
WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint)
WEBGL_EXTENSION_IDENTIFIER(OES_fbo_render_mipmap)
WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float)
WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear)
WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
WEBGL_EXTENSION_IDENTIFIER(OVR_multiview2)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_astc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc_srgb)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_draw_buffers)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_explicit_present)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_lose_context)
#undef WEBGL_EXTENSION_IDENTIFIER
}
return sExtensionNamesEnumeratedArray[ext];
}
bool WebGLContext::IsExtensionSupported(dom::CallerType callerType,
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 (callerType == dom::CallerType::System) {
allowPrivilegedExts = true;
}
if (StaticPrefs::webgl_enable_privileged_extensions()) {
allowPrivilegedExts = true;
}
if (allowPrivilegedExts) {
switch (ext) {
case WebGLExtensionID::EXT_disjoint_timer_query:
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
case WebGLExtensionID::MOZ_debug:
return true;
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;
bool shouldResistFingerprinting = ShouldResistFingerprinting();
switch (ext) {
// In alphabetical order
// ANGLE_
case WebGLExtensionID::ANGLE_instanced_arrays:
return WebGLExtensionInstancedArrays::IsSupported(this);
// EXT_
case WebGLExtensionID::EXT_blend_minmax:
return WebGLExtensionBlendMinMax::IsSupported(this);
case WebGLExtensionID::EXT_color_buffer_float:
return WebGLExtensionEXTColorBufferFloat::IsSupported(this);
case WebGLExtensionID::EXT_color_buffer_half_float:
return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
case WebGLExtensionID::EXT_float_blend:
return WebGLExtensionFloatBlend::IsSupported(this);
case WebGLExtensionID::EXT_frag_depth:
return WebGLExtensionFragDepth::IsSupported(this);
case WebGLExtensionID::EXT_shader_texture_lod:
return WebGLExtensionShaderTextureLod::IsSupported(this);
case WebGLExtensionID::EXT_sRGB:
return WebGLExtensionSRGB::IsSupported(this);
case WebGLExtensionID::EXT_texture_compression_bptc:
return WebGLExtensionCompressedTextureBPTC::IsSupported(this);
case WebGLExtensionID::EXT_texture_compression_rgtc:
return WebGLExtensionCompressedTextureRGTC::IsSupported(this);
case WebGLExtensionID::EXT_texture_filter_anisotropic:
return gl->IsExtensionSupported(
gl::GLContext::EXT_texture_filter_anisotropic);
// OES_
case WebGLExtensionID::OES_element_index_uint:
if (IsWebGL2()) return false;
return gl->IsSupported(gl::GLFeature::element_index_uint);
case WebGLExtensionID::OES_fbo_render_mipmap:
return WebGLExtensionFBORenderMipmap::IsSupported(this);
case WebGLExtensionID::OES_standard_derivatives:
if (IsWebGL2()) return false;
return gl->IsSupported(gl::GLFeature::standard_derivatives);
case WebGLExtensionID::OES_texture_float:
return WebGLExtensionTextureFloat::IsSupported(this);
case WebGLExtensionID::OES_texture_float_linear:
return gl->IsSupported(gl::GLFeature::texture_float_linear);
case WebGLExtensionID::OES_texture_half_float:
return WebGLExtensionTextureHalfFloat::IsSupported(this);
case WebGLExtensionID::OES_texture_half_float_linear:
if (IsWebGL2()) return false;
return gl->IsSupported(gl::GLFeature::texture_half_float_linear);
case WebGLExtensionID::OES_vertex_array_object:
return !IsWebGL2(); // Always supported in webgl1.
// OVR_
case WebGLExtensionID::OVR_multiview2:
return WebGLExtensionMultiview::IsSupported(this);
// WEBGL_
case WebGLExtensionID::WEBGL_color_buffer_float:
return WebGLExtensionColorBufferFloat::IsSupported(this);
case WebGLExtensionID::WEBGL_compressed_texture_astc:
return WebGLExtensionCompressedTextureASTC::IsSupported(this);
case WebGLExtensionID::WEBGL_compressed_texture_etc:
return gl->IsSupported(gl::GLFeature::ES3_compatibility) &&
!gl->IsANGLE();
case WebGLExtensionID::WEBGL_compressed_texture_etc1:
return gl->IsExtensionSupported(
gl::GLContext::OES_compressed_ETC1_RGB8_texture) &&
!gl->IsANGLE();
case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(
gl::GLContext::IMG_texture_compression_pvrtc);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
return WebGLExtensionCompressedTextureS3TC::IsSupported(this);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
return WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported(this);
case WebGLExtensionID::WEBGL_debug_renderer_info:
return Preferences::GetBool("webgl.enable-debug-renderer-info", false) &&
!shouldResistFingerprinting;
case WebGLExtensionID::WEBGL_debug_shaders:
return !shouldResistFingerprinting;
case WebGLExtensionID::WEBGL_depth_texture:
return WebGLExtensionDepthTexture::IsSupported(this);
case WebGLExtensionID::WEBGL_draw_buffers:
return WebGLExtensionDrawBuffers::IsSupported(this);
case WebGLExtensionID::WEBGL_explicit_present:
return WebGLExtensionExplicitPresent::IsSupported(this);
case WebGLExtensionID::WEBGL_lose_context:
// We always support this extension.
return true;
case WebGLExtensionID::EXT_disjoint_timer_query:
case WebGLExtensionID::MOZ_debug:
case WebGLExtensionID::Max:
return false;
}
return false;
}
bool WebGLContext::IsExtensionExplicit(const WebGLExtensionID ext) const {
MOZ_ASSERT(ext < WebGLExtensionID::Max);
return mExtensions[ext] && mExtensions[ext]->IsExplicit();
}
void WebGLContext::WarnIfImplicit(const WebGLExtensionID ext) {
MOZ_ASSERT(ext < WebGLExtensionID::Max);
const auto& extension = mExtensions[ext];
if (!extension || extension->IsExplicit()) return;
GenerateWarning(
"Using format enabled by implicitly enabled extension: %s. "
"For maximal portability enable it explicitly.",
GetExtensionString(ext));
// Don't spam warnings
extension->SetExplicit();
}
static bool CompareWebGLExtensionName(const nsACString& name,
const char* other) {
return name.Equals(other, nsCaseInsensitiveCStringComparator());
}
WebGLExtensionBase* WebGLContext::EnableSupportedExtension(
dom::CallerType callerType, WebGLExtensionID ext, bool explict) {
if (!IsExtensionEnabled(ext)) {
if (!IsExtensionSupported(callerType, ext)) return nullptr;
EnableExtension(ext);
}
const auto extension = mExtensions[ext];
MOZ_ASSERT(extension);
if (explict && !extension->IsExplicit()) {
extension->SetExplicit();
}
return extension;
}
void ClientWebGLContext::GetExtension(JSContext* cx, const nsAString& wideName,
JS::MutableHandle<JSObject*> retval,
dom::CallerType callerType,
ErrorResult& rv) {
retval.set(nullptr);
const FuncScope funcScope(this, "getExtension");
NS_LossyConvertUTF16toASCII name(wideName);
WebGLExtensionID ext = WebGLExtensionID::Max;
// 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::Max) return;
// step 2: if the extension hadn't been previously been created then we
// have to tell the host we are using it
ClientWebGLExtensionBase* extObj = GetExtension(callerType, ext, true);
if (!extObj) return;
// Step 3: Enable any implied extensions.
switch (ext) {
case WebGLExtensionID::EXT_color_buffer_float:
EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
false);
break;
case WebGLExtensionID::OES_texture_float:
EnableSupportedExtension(
callerType, WebGLExtensionID::WEBGL_color_buffer_float, false);
EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
false);
break;
case WebGLExtensionID::OES_texture_half_float:
EnableSupportedExtension(
callerType, WebGLExtensionID::EXT_color_buffer_half_float, false);
break;
case WebGLExtensionID::WEBGL_color_buffer_float:
EnableSupportedExtension(callerType, WebGLExtensionID::EXT_float_blend,
false);
break;
default:
break;
}
retval.set(WebGLObjectAsJSObject(cx, extObj, rv));
}
void WebGLContext::CreateExtension(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_float_blend:
obj = new WebGLExtensionFloatBlend(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_compression_bptc:
obj = new WebGLExtensionCompressedTextureBPTC(this);
break;
case WebGLExtensionID::EXT_texture_compression_rgtc:
obj = new WebGLExtensionCompressedTextureRGTC(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_fbo_render_mipmap:
obj = new WebGLExtensionFBORenderMipmap(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::OVR_multiview2:
obj = new WebGLExtensionMultiview(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_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_explicit_present:
obj = new WebGLExtensionExplicitPresent(this);
break;
case WebGLExtensionID::WEBGL_lose_context:
obj = new WebGLExtensionLoseContext(this);
break;
case WebGLExtensionID::Max:
MOZ_CRASH();
}
mExtensions[ext] = obj;
}
const Maybe<ExtensionSets> WebGLContext::GetSupportedExtensions() {
const FuncScope funcScope(*this, "getSupportedExtensions");
if (IsContextLost()) return Nothing();
Maybe<ExtensionSets> ret = Some(ExtensionSets());
auto& sets = ret.ref();
for (size_t i = 0; i < size_t(WebGLExtensionID::Max); i++) {
const auto extension = WebGLExtensionID(i);
if (IsExtensionSupported(dom::CallerType::NonSystem, extension)) {
sets.mNonSystem.AppendElement(extension);
} else if (IsExtensionSupported(dom::CallerType::System, extension)) {
sets.mSystem.AppendElement(extension);
}
}
return ret;
}
ClientWebGLExtensionBase* ClientWebGLContext::UseExtension(
WebGLExtensionID ext) {
switch (ext) {
// ANGLE_
case WebGLExtensionID::ANGLE_instanced_arrays:
return new ClientWebGLExtensionInstancedArrays(this);
// EXT_
case WebGLExtensionID::EXT_blend_minmax:
return new ClientWebGLExtensionBlendMinMax(this);
case WebGLExtensionID::EXT_color_buffer_float:
return new ClientWebGLExtensionEXTColorBufferFloat(this);
case WebGLExtensionID::EXT_color_buffer_half_float:
return new ClientWebGLExtensionColorBufferHalfFloat(this);
case WebGLExtensionID::EXT_disjoint_timer_query:
return new ClientWebGLExtensionDisjointTimerQuery(this);
case WebGLExtensionID::EXT_frag_depth:
return new ClientWebGLExtensionFragDepth(this);
case WebGLExtensionID::EXT_shader_texture_lod:
return new ClientWebGLExtensionShaderTextureLod(this);
case WebGLExtensionID::EXT_sRGB:
return new ClientWebGLExtensionSRGB(this);
case WebGLExtensionID::EXT_texture_compression_bptc:
return new ClientWebGLExtensionCompressedTextureBPTC(this);
case WebGLExtensionID::EXT_texture_compression_rgtc:
return new ClientWebGLExtensionCompressedTextureRGTC(this);
case WebGLExtensionID::EXT_texture_filter_anisotropic:
return new ClientWebGLExtensionTextureFilterAnisotropic(this);
// MOZ_
case WebGLExtensionID::MOZ_debug:
return new ClientWebGLExtensionMOZDebug(this);
// OES_
case WebGLExtensionID::OES_element_index_uint:
return new ClientWebGLExtensionElementIndexUint(this);
case WebGLExtensionID::OES_standard_derivatives:
return new ClientWebGLExtensionStandardDerivatives(this);
case WebGLExtensionID::OES_texture_float:
return new ClientWebGLExtensionTextureFloat(this);
case WebGLExtensionID::OES_texture_float_linear:
return new ClientWebGLExtensionTextureFloatLinear(this);
case WebGLExtensionID::OES_texture_half_float:
return new ClientWebGLExtensionTextureHalfFloat(this);
case WebGLExtensionID::OES_texture_half_float_linear:
return new ClientWebGLExtensionTextureHalfFloatLinear(this);
case WebGLExtensionID::OES_vertex_array_object:
return new ClientWebGLExtensionVertexArray(this);
// WEBGL_
case WebGLExtensionID::WEBGL_color_buffer_float:
return new ClientWebGLExtensionColorBufferFloat(this);
case WebGLExtensionID::WEBGL_compressed_texture_astc:
return new ClientWebGLExtensionCompressedTextureASTC(this);
case WebGLExtensionID::WEBGL_compressed_texture_etc:
return new ClientWebGLExtensionCompressedTextureES3(this);
case WebGLExtensionID::WEBGL_compressed_texture_etc1:
return new ClientWebGLExtensionCompressedTextureETC1(this);
case WebGLExtensionID::WEBGL_compressed_texture_pvrtc:
return new ClientWebGLExtensionCompressedTexturePVRTC(this);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc:
return new ClientWebGLExtensionCompressedTextureS3TC(this);
case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb:
return new ClientWebGLExtensionCompressedTextureS3TC_SRGB(this);
case WebGLExtensionID::WEBGL_debug_renderer_info:
return new ClientWebGLExtensionDebugRendererInfo(this);
case WebGLExtensionID::WEBGL_debug_shaders:
return new ClientWebGLExtensionDebugShaders(this);
case WebGLExtensionID::WEBGL_depth_texture:
return new ClientWebGLExtensionDepthTexture(this);
case WebGLExtensionID::WEBGL_draw_buffers:
return new ClientWebGLExtensionDrawBuffers(this);
case WebGLExtensionID::WEBGL_lose_context:
return new ClientWebGLExtensionLoseContext(this);
default:
MOZ_ASSERT_UNREACHABLE("illegal extension enum");
return nullptr;
}
}
} // namespace mozilla