diff options
Diffstat (limited to 'dom/canvas/WebGLExtensions.cpp')
-rw-r--r-- | dom/canvas/WebGLExtensions.cpp | 1022 |
1 files changed, 1022 insertions, 0 deletions
diff --git a/dom/canvas/WebGLExtensions.cpp b/dom/canvas/WebGLExtensions.cpp new file mode 100644 index 0000000000..e1a8961a40 --- /dev/null +++ b/dom/canvas/WebGLExtensions.cpp @@ -0,0 +1,1022 @@ +/* -*- Mode: C++; tab-width: 20; 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 "WebGLExtensions.h" + +#include "GLContext.h" +#include "mozilla/dom/WebGLRenderingContextBinding.h" +#include "mozilla/StaticPrefs_webgl.h" +#include "WebGLContext.h" + +namespace mozilla { + +WebGLExtensionBlendMinMax::WebGLExtensionBlendMinMax(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionBlendMinMax::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + return webgl->GL()->IsSupported(gl::GLFeature::blend_minmax); +} + +// - + +WebGLExtensionColorBufferFloat::WebGLExtensionColorBufferFloat( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + SetRenderable(webgl::FormatRenderableState::Implicit( + WebGLExtensionID::WEBGL_color_buffer_float)); +} + +void WebGLExtensionColorBufferFloat::SetRenderable( + const webgl::FormatRenderableState state) { + auto& fua = mContext->mFormatUsage; + + auto fnUpdateUsage = [&](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto usage = fua->EditUsage(effFormat); + usage->SetRenderable(state); + fua->AllowRBFormat(sizedFormat, usage); + }; + +#define FOO(x) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x) + + // The extension doesn't actually add RGB32F; only RGBA32F. + FOO(RGBA32F); + +#undef FOO +} + +void WebGLExtensionColorBufferFloat::OnSetExplicit() { + SetRenderable(webgl::FormatRenderableState::Explicit()); +} + +bool WebGLExtensionColorBufferFloat::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + const auto& gl = webgl->gl; + return gl->IsSupported(gl::GLFeature::renderbuffer_color_float) && + gl->IsSupported(gl::GLFeature::frag_color_float); +} + +// - + +WebGLExtensionColorBufferHalfFloat::WebGLExtensionColorBufferHalfFloat( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + SetRenderable(webgl::FormatRenderableState::Implicit( + WebGLExtensionID::EXT_color_buffer_half_float)); +} + +void WebGLExtensionColorBufferHalfFloat::SetRenderable( + const webgl::FormatRenderableState state) { + auto& fua = mContext->mFormatUsage; + + auto fnUpdateUsage = [&](GLenum sizedFormat, webgl::EffectiveFormat effFormat, + const bool renderable) { + auto usage = fua->EditUsage(effFormat); + if (renderable) { + usage->SetRenderable(state); + } + fua->AllowRBFormat(sizedFormat, usage, renderable); + }; + +#define FOO(x, y) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x, y) + + FOO(RGBA16F, true); + FOO(RGB16F, false); // It's not required, thus not portable. (Also there's a + // wicked driver bug on Mac+Intel) + +#undef FOO +} + +void WebGLExtensionColorBufferHalfFloat::OnSetExplicit() { + SetRenderable(webgl::FormatRenderableState::Explicit()); +} + +bool WebGLExtensionColorBufferHalfFloat::IsSupported( + const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + const auto& gl = webgl->gl; + return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) && + gl->IsSupported(gl::GLFeature::frag_color_float); +} + +// - + +WebGLExtensionCompressedTextureASTC::WebGLExtensionCompressedTextureASTC( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x8_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x5_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x6_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x8_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x10_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x10_KHR)); + fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x12_KHR)); + + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR)); + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR)); + +#undef FOO +} + +bool WebGLExtensionCompressedTextureASTC::IsSupported( + const WebGLContext* webgl) { + gl::GLContext* gl = webgl->GL(); + return gl->IsExtensionSupported( + gl::GLContext::KHR_texture_compression_astc_ldr); +} + +// - + +WebGLExtensionCompressedTextureBPTC::WebGLExtensionCompressedTextureBPTC( + WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + + auto& fua = webgl->mFormatUsage; + + const auto fnAdd = [&](const GLenum sizedFormat, + const webgl::EffectiveFormat effFormat) { + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define _(X) LOCAL_GL_##X, webgl::EffectiveFormat::X + + fnAdd(_(COMPRESSED_RGBA_BPTC_UNORM)); + fnAdd(_(COMPRESSED_SRGB_ALPHA_BPTC_UNORM)); + fnAdd(_(COMPRESSED_RGB_BPTC_SIGNED_FLOAT)); + fnAdd(_(COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT)); + +#undef _ +} + +bool WebGLExtensionCompressedTextureBPTC::IsSupported( + const WebGLContext* const webgl) { + return webgl->gl->IsSupported(gl::GLFeature::texture_compression_bptc); +} + +// - + +WebGLExtensionCompressedTextureES3::WebGLExtensionCompressedTextureES3( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + // GLES 3.0.4, p147, table 3.19 + // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats" + // Note that all compressed texture formats are filterable: + // GLES 3.0.4 p161: + // "[A] texture is complete unless any of the following conditions hold true: + // [...] + // * The effective internal format specified for the texture arrays is a + // sized internal color format that is not texture-filterable (see table + // 3.13) and [the mag filter requires filtering]." + // Compressed formats are not sized internal color formats, and indeed they + // are not listed in table 3.13. + + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(COMPRESSED_R11_EAC)); + fnAdd(FOO(COMPRESSED_SIGNED_R11_EAC)); + fnAdd(FOO(COMPRESSED_RG11_EAC)); + fnAdd(FOO(COMPRESSED_SIGNED_RG11_EAC)); + fnAdd(FOO(COMPRESSED_RGB8_ETC2)); + fnAdd(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2)); + fnAdd(FOO(COMPRESSED_RGBA8_ETC2_EAC)); + + // sRGB support is manadatory in GL 4.3 and GL ES 3.0, which are the only + // versions to support ETC2. + fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC)); + fnAdd(FOO(COMPRESSED_SRGB8_ETC2)); + fnAdd(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2)); + +#undef FOO +} + +// - + +WebGLExtensionCompressedTextureETC1::WebGLExtensionCompressedTextureETC1( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(ETC1_RGB8_OES)); + +#undef FOO +} + +// - + +WebGLExtensionCompressedTexturePVRTC::WebGLExtensionCompressedTexturePVRTC( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(COMPRESSED_RGB_PVRTC_4BPPV1)); + fnAdd(FOO(COMPRESSED_RGB_PVRTC_2BPPV1)); + fnAdd(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1)); + fnAdd(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1)); + +#undef FOO +} + +// - + +WebGLExtensionCompressedTextureRGTC::WebGLExtensionCompressedTextureRGTC( + WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + + auto& fua = webgl->mFormatUsage; + + const auto fnAdd = [&](const GLenum sizedFormat, + const webgl::EffectiveFormat effFormat) { + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define _(X) LOCAL_GL_##X, webgl::EffectiveFormat::X + + fnAdd(_(COMPRESSED_RED_RGTC1)); + fnAdd(_(COMPRESSED_SIGNED_RED_RGTC1)); + fnAdd(_(COMPRESSED_RG_RGTC2)); + fnAdd(_(COMPRESSED_SIGNED_RG_RGTC2)); + +#undef _ +} + +bool WebGLExtensionCompressedTextureRGTC::IsSupported( + const WebGLContext* const webgl) { + return webgl->gl->IsSupported(gl::GLFeature::texture_compression_rgtc); +} + +// - + +WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT)); + fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT)); + fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT)); + fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT)); + +#undef FOO +} + +bool WebGLExtensionCompressedTextureS3TC::IsSupported( + const WebGLContext* webgl) { + gl::GLContext* gl = webgl->GL(); + if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc)) + return true; + + return gl->IsExtensionSupported( + gl::GLContext::EXT_texture_compression_dxt1) && + gl->IsExtensionSupported( + gl::GLContext::ANGLE_texture_compression_dxt3) && + gl->IsExtensionSupported( + gl::GLContext::ANGLE_texture_compression_dxt5); +} + +// - + +WebGLExtensionCompressedTextureS3TC_SRGB:: + WebGLExtensionCompressedTextureS3TC_SRGB(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275 + const auto fnAdd = [&webgl_](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto& fua = webgl_->mFormatUsage; + + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + fua->AllowSizedTexFormat(sizedFormat, usage); + }; + +#define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x + + fnAdd(FOO(COMPRESSED_SRGB_S3TC_DXT1_EXT)); + fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT)); + fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT)); + fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT)); + +#undef FOO +} + +bool WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported( + const WebGLContext* webgl) { + gl::GLContext* gl = webgl->GL(); + if (gl->IsGLES()) + return gl->IsExtensionSupported( + gl::GLContext::EXT_texture_compression_s3tc_srgb); + + // Desktop GL is more complicated: It's EXT_texture_sRGB, when + // EXT_texture_compression_s3tc is supported, that enables srgb+s3tc. + return gl->IsExtensionSupported(gl::GLContext::EXT_texture_sRGB) && + gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc); +} + +// - + +WebGLExtensionDepthTexture::WebGLExtensionDepthTexture( + WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + auto& fua = webgl->mFormatUsage; + + const auto fnAdd = [&fua](webgl::EffectiveFormat effFormat, + GLenum unpackFormat, GLenum unpackType) { + auto usage = fua->EditUsage(effFormat); + MOZ_ASSERT(usage->isFilterable); + MOZ_ASSERT(usage->IsRenderable()); + + const webgl::PackingInfo pi = {unpackFormat, unpackType}; + const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat, + unpackType}; + fua->AddTexUnpack(usage, pi, dui); + fua->AllowUnsizedTexFormat(pi, usage); + }; + + fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT16, LOCAL_GL_DEPTH_COMPONENT, + LOCAL_GL_UNSIGNED_SHORT); + fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT24, LOCAL_GL_DEPTH_COMPONENT, + LOCAL_GL_UNSIGNED_INT); + fnAdd(webgl::EffectiveFormat::DEPTH24_STENCIL8, LOCAL_GL_DEPTH_STENCIL, + LOCAL_GL_UNSIGNED_INT_24_8); +} + +bool WebGLExtensionDepthTexture::IsSupported(const WebGLContext* const webgl) { + if (webgl->IsWebGL2()) return false; + + // WEBGL_depth_texture supports DEPTH_STENCIL textures + const auto& gl = webgl->gl; + if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil)) return false; + + return gl->IsSupported(gl::GLFeature::depth_texture) || + gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture); +} + +// - + +WebGLExtensionDisjointTimerQuery::WebGLExtensionDisjointTimerQuery( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionDisjointTimerQuery::IsSupported( + const WebGLContext* const webgl) { + if (!StaticPrefs::webgl_enable_privileged_extensions()) return false; + + gl::GLContext* gl = webgl->GL(); + return gl->IsSupported(gl::GLFeature::query_objects) && + gl->IsSupported(gl::GLFeature::get_query_object_i64v) && + gl->IsSupported( + gl::GLFeature::query_counter); // provides GL_TIMESTAMP +} + +// - + +WebGLExtensionDrawBuffers::WebGLExtensionDrawBuffers(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + if (gl->IsGLES() && gl->Version() >= 300) { + // ANGLE's shader translator can't translate ESSL1 exts to ESSL3. (bug + // 1524804) + return false; + } + return gl->IsSupported(gl::GLFeature::draw_buffers); +} + +// - + +WebGLExtensionExplicitPresent::WebGLExtensionExplicitPresent( + WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + if (!IsSupported(webgl)) { + NS_WARNING( + "Constructing WebGLExtensionExplicitPresent but IsSupported() is " + "false!"); + // This was previously an assert, but it seems like we get races against + // StaticPrefs changes/initialization? + } +} + +bool WebGLExtensionExplicitPresent::IsSupported( + const WebGLContext* const webgl) { + return StaticPrefs::webgl_enable_draft_extensions(); +} + +// - + +WebGLExtensionEXTColorBufferFloat::WebGLExtensionEXTColorBufferFloat( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + + auto& fua = webgl->mFormatUsage; + + auto fnUpdateUsage = [&fua](GLenum sizedFormat, + webgl::EffectiveFormat effFormat) { + auto usage = fua->EditUsage(effFormat); + usage->SetRenderable(); + fua->AllowRBFormat(sizedFormat, usage); + }; + +#define FOO(x) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x) + + FOO(R16F); + FOO(RG16F); + FOO(RGBA16F); + + FOO(R32F); + FOO(RG32F); + FOO(RGBA32F); + + FOO(R11F_G11F_B10F); + +#undef FOO +} + +/*static*/ +bool WebGLExtensionEXTColorBufferFloat::IsSupported(const WebGLContext* webgl) { + if (!webgl->IsWebGL2()) return false; + + const gl::GLContext* gl = webgl->GL(); + return gl->IsSupported(gl::GLFeature::EXT_color_buffer_float); +} + +// - + +WebGLExtensionFBORenderMipmap::WebGLExtensionFBORenderMipmap( + WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionFBORenderMipmap::IsSupported( + const WebGLContext* const webgl) { + if (webgl->IsWebGL2()) return false; + + const auto& gl = webgl->gl; + if (!gl->IsGLES()) return true; + if (gl->Version() >= 300) return true; + return gl->IsExtensionSupported(gl::GLContext::OES_fbo_render_mipmap); +} + +// - + +WebGLExtensionFloatBlend::WebGLExtensionFloatBlend(WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionFloatBlend::IsSupported(const WebGLContext* const webgl) { + if (!WebGLExtensionColorBufferFloat::IsSupported(webgl) && + !WebGLExtensionEXTColorBufferFloat::IsSupported(webgl)) + return false; + + const auto& gl = webgl->gl; + if (!gl->IsGLES() && gl->Version() >= 300) return true; + if (gl->IsGLES() && gl->Version() >= 320) return true; + return gl->IsExtensionSupported(gl::GLContext::EXT_float_blend); +} + +// - + +WebGLExtensionFragDepth::WebGLExtensionFragDepth(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionFragDepth::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + if (gl->IsGLES() && gl->Version() >= 300) { + // ANGLE's shader translator can't translate ESSL1 exts to ESSL3. (bug + // 1524804) + return false; + } + return gl->IsSupported(gl::GLFeature::frag_depth); +} + +// - + +WebGLExtensionInstancedArrays::WebGLExtensionInstancedArrays( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionInstancedArrays::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + return gl->IsSupported(gl::GLFeature::draw_instanced) && + gl->IsSupported(gl::GLFeature::instanced_arrays); +} + +// - + +WebGLExtensionMultiview::WebGLExtensionMultiview(WebGLContext* const webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionMultiview::IsSupported(const WebGLContext* const webgl) { + if (!webgl->IsWebGL2()) return false; + + const auto& gl = webgl->gl; + return gl->IsSupported(gl::GLFeature::multiview); +} + +// - + +WebGLExtensionShaderTextureLod::WebGLExtensionShaderTextureLod( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); +} + +bool WebGLExtensionShaderTextureLod::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + if (gl->IsGLES() && gl->Version() >= 300) { + // ANGLE's shader translator doesn't yet translate + // WebGL1+EXT_shader_texture_lod to ES3. (Bug 1491221) + return false; + } + return gl->IsSupported(gl::GLFeature::shader_texture_lod); +} + +// - + +WebGLExtensionSRGB::WebGLExtensionSRGB(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported."); + + gl::GLContext* gl = webgl->GL(); + if (!gl->IsGLES()) { + // Desktop OpenGL requires the following to be enabled in order to + // support sRGB operations on framebuffers. + gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT); + } + + auto& fua = webgl->mFormatUsage; + + RefPtr<gl::GLContext> gl_ = gl; // Bug 1201275 + const auto fnAdd = [&fua, &gl_](webgl::EffectiveFormat effFormat, + GLenum format, GLenum desktopUnpackFormat) { + auto usage = fua->EditUsage(effFormat); + usage->isFilterable = true; + + webgl::DriverUnpackInfo dui = {format, format, LOCAL_GL_UNSIGNED_BYTE}; + const auto pi = dui.ToPacking(); + + if (!gl_->IsGLES()) dui.unpackFormat = desktopUnpackFormat; + + fua->AddTexUnpack(usage, pi, dui); + + fua->AllowUnsizedTexFormat(pi, usage); + }; + + fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB, LOCAL_GL_RGB); + fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA, + LOCAL_GL_RGBA); + + auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8); + usage->SetRenderable(); + fua->AllowRBFormat(LOCAL_GL_SRGB8_ALPHA8, usage); +} + +bool WebGLExtensionSRGB::IsSupported(const WebGLContext* const webgl) { + if (webgl->IsWebGL2()) return false; + + return webgl->gl->IsSupported(gl::GLFeature::sRGB); +} + +// - + +WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(IsSupported(webgl)); + + auto& fua = webgl->mFormatUsage; + gl::GLContext* gl = webgl->GL(); + + webgl::PackingInfo pi; + webgl::DriverUnpackInfo dui; + const GLint* swizzle = nullptr; + + const auto fnAdd = [&](webgl::EffectiveFormat effFormat) { + MOZ_ASSERT_IF(swizzle, gl->IsSupported(gl::GLFeature::texture_swizzle)); + + auto usage = fua->EditUsage(effFormat); + usage->textureSwizzleRGBA = swizzle; + fua->AddTexUnpack(usage, pi, dui); + + fua->AllowUnsizedTexFormat(pi, usage); + }; + + bool useSizedFormats = true; + const bool hasSizedLegacyFormats = gl->IsCompatibilityProfile(); + if (gl->IsGLES() && gl->Version() < 300) { + useSizedFormats = false; + } + + //////////////// + + pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT}; + dui = {pi.format, pi.format, pi.type}; + swizzle = nullptr; + if (useSizedFormats || gl->IsExtensionSupported( + gl::GLContext::CHROMIUM_color_buffer_float_rgba)) { + // ANGLE only exposes renderable RGBA32F via + // CHROMIUM_color_buffer_float_rgba, which uses sized formats. + dui.internalFormat = LOCAL_GL_RGBA32F; + } + fnAdd(webgl::EffectiveFormat::RGBA32F); + + ////// + + pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT}; + dui = {pi.format, pi.format, pi.type}; + swizzle = nullptr; + if (useSizedFormats) { + dui.internalFormat = LOCAL_GL_RGB32F; + } + fnAdd(webgl::EffectiveFormat::RGB32F); + + ////// + + pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT}; + dui = {pi.format, pi.format, pi.type}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_LUMINANCE32F_ARB; + } else { + dui.internalFormat = LOCAL_GL_R32F; + dui.unpackFormat = LOCAL_GL_RED; + swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Luminance32F); + + ////// + + pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT}; + dui = {pi.format, pi.format, pi.type}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_ALPHA32F_ARB; + } else { + dui.internalFormat = LOCAL_GL_R32F; + dui.unpackFormat = LOCAL_GL_RED; + swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Alpha32F); + + ////// + + pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT}; + dui = {pi.format, pi.format, pi.type}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB; + } else { + dui.internalFormat = LOCAL_GL_RG32F; + dui.unpackFormat = LOCAL_GL_RG; + swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F); +} + +bool WebGLExtensionTextureFloat::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + if (!gl->IsSupported(gl::GLFeature::texture_float)) return false; + + const bool needsSwizzle = gl->IsCoreProfile(); + const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle); + if (needsSwizzle && !hasSwizzle) return false; + + return true; +} + +// - + +WebGLExtensionTextureFloatLinear::WebGLExtensionTextureFloatLinear( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + auto& fua = webgl->mFormatUsage; + + fua->EditUsage(webgl::EffectiveFormat::RGBA32F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::RGB32F)->isFilterable = true; + + if (webgl->IsWebGL2()) { + fua->EditUsage(webgl::EffectiveFormat::R32F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::RG32F)->isFilterable = true; + } else { + fua->EditUsage(webgl::EffectiveFormat::Luminance32FAlpha32F)->isFilterable = + true; + fua->EditUsage(webgl::EffectiveFormat::Luminance32F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::Alpha32F)->isFilterable = true; + } +} + +// - + +WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + auto& fua = webgl->mFormatUsage; + gl::GLContext* gl = webgl->GL(); + + webgl::PackingInfo pi; + webgl::DriverUnpackInfo dui; + const GLint* swizzle = nullptr; + + const auto fnAdd = [&](webgl::EffectiveFormat effFormat) { + MOZ_ASSERT_IF(swizzle, gl->IsSupported(gl::GLFeature::texture_swizzle)); + + auto usage = fua->EditUsage(effFormat); + usage->textureSwizzleRGBA = swizzle; + fua->AddTexUnpack(usage, pi, dui); + + fua->AllowUnsizedTexFormat(pi, usage); + }; + + bool useSizedFormats = true; + const bool hasSizedLegacyFormats = gl->IsCompatibilityProfile(); + if (gl->IsGLES() && gl->Version() < 300) { + useSizedFormats = false; + } + + GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT; + if (!gl->IsSupported(gl::GLFeature::texture_half_float)) { + MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float)); + driverUnpackType = LOCAL_GL_HALF_FLOAT_OES; + } + + //////////////// + + pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES}; + dui = {pi.format, pi.format, driverUnpackType}; + swizzle = nullptr; + if (useSizedFormats) { + dui.internalFormat = LOCAL_GL_RGBA16F; + } + fnAdd(webgl::EffectiveFormat::RGBA16F); + + ////// + + pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES}; + dui = {pi.format, pi.format, driverUnpackType}; + swizzle = nullptr; + if (useSizedFormats) { + dui.internalFormat = LOCAL_GL_RGB16F; + } + fnAdd(webgl::EffectiveFormat::RGB16F); + + ////// + + pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES}; + dui = {pi.format, pi.format, driverUnpackType}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_LUMINANCE16F_ARB; + } else { + dui.internalFormat = LOCAL_GL_R16F; + dui.unpackFormat = LOCAL_GL_RED; + swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Luminance16F); + + ////// + + pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES}; + dui = {pi.format, pi.format, driverUnpackType}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_ALPHA16F_ARB; + } else { + dui.internalFormat = LOCAL_GL_R16F; + dui.unpackFormat = LOCAL_GL_RED; + swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Alpha16F); + + ////// + + pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES}; + dui = {pi.format, pi.format, driverUnpackType}; + swizzle = nullptr; + if (useSizedFormats) { + if (hasSizedLegacyFormats) { + dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB; + } else { + dui.internalFormat = LOCAL_GL_RG16F; + dui.unpackFormat = LOCAL_GL_RG; + swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA; + } + } + fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F); +} + +bool WebGLExtensionTextureHalfFloat::IsSupported(const WebGLContext* webgl) { + if (webgl->IsWebGL2()) return false; + + gl::GLContext* gl = webgl->GL(); + if (!gl->IsSupported(gl::GLFeature::texture_half_float) && + !gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float)) { + return false; + } + + const bool needsSwizzle = gl->IsCoreProfile(); + const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle); + if (needsSwizzle && !hasSwizzle) return false; + + return true; +} + +// - + +WebGLExtensionTextureHalfFloatLinear::WebGLExtensionTextureHalfFloatLinear( + WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + MOZ_ASSERT(!webgl->IsWebGL2()); + auto& fua = webgl->mFormatUsage; + + fua->EditUsage(webgl::EffectiveFormat::RGBA16F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::RGB16F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::Luminance16FAlpha16F)->isFilterable = + true; + fua->EditUsage(webgl::EffectiveFormat::Luminance16F)->isFilterable = true; + fua->EditUsage(webgl::EffectiveFormat::Alpha16F)->isFilterable = true; +} + +// - + +bool WebGLExtensionTextureNorm16::IsSupported(const WebGLContext* const webgl) { + if (!StaticPrefs::webgl_enable_draft_extensions()) return false; + if (!webgl->IsWebGL2()) return false; + + const auto& gl = webgl->gl; + + // ANGLE's support is broken in our checkout. + if (gl->IsANGLE()) return false; + + return gl->IsSupported(gl::GLFeature::texture_norm16); +} + +WebGLExtensionTextureNorm16::WebGLExtensionTextureNorm16(WebGLContext* webgl) + : WebGLExtensionBase(webgl) { + if (!IsSupported(webgl)) { + NS_WARNING( + "Constructing WebGLExtensionTextureNorm16 but IsSupported() is " + "false!"); + // This was previously an assert, but it seems like we get races against + // StaticPrefs changes/initialization? + } + + auto& fua = *webgl->mFormatUsage; + + const auto fnAdd = [&](webgl::EffectiveFormat effFormat, + const bool renderable, const webgl::PackingInfo& pi) { + auto& usage = *fua.EditUsage(effFormat); + const auto& format = *usage.format; + + const auto dui = + webgl::DriverUnpackInfo{format.sizedFormat, pi.format, pi.type}; + fua.AddTexUnpack(&usage, pi, dui); + + fua.AllowSizedTexFormat(format.sizedFormat, &usage); + fua.AllowUnsizedTexFormat(pi, &usage); + + if (renderable) { + usage.SetRenderable(); + fua.AllowRBFormat(format.sizedFormat, &usage); + } + }; + + fnAdd(webgl::EffectiveFormat::R16, true, + {LOCAL_GL_RED, LOCAL_GL_UNSIGNED_SHORT}); + fnAdd(webgl::EffectiveFormat::RG16, true, + {LOCAL_GL_RG, LOCAL_GL_UNSIGNED_SHORT}); + fnAdd(webgl::EffectiveFormat::RGB16, false, + {LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT}); + fnAdd(webgl::EffectiveFormat::RGBA16, true, + {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT}); + + fnAdd(webgl::EffectiveFormat::R16_SNORM, false, + {LOCAL_GL_RED, LOCAL_GL_SHORT}); + fnAdd(webgl::EffectiveFormat::RG16_SNORM, false, + {LOCAL_GL_RG, LOCAL_GL_SHORT}); + fnAdd(webgl::EffectiveFormat::RGB16_SNORM, false, + {LOCAL_GL_RGB, LOCAL_GL_SHORT}); + fnAdd(webgl::EffectiveFormat::RGBA16_SNORM, false, + {LOCAL_GL_RGBA, LOCAL_GL_SHORT}); +} + +} // namespace mozilla |