Merge autoland to mozilla-central. a=merge
[gecko.git] / dom / canvas / WebGLExtensions.cpp
blob1eaaea7dfd907ad538985fa96b72ace2d8887755
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLExtensions.h"
8 #include "GLContext.h"
9 #include "mozilla/Casting.h"
10 #include "mozilla/dom/WebGLRenderingContextBinding.h"
11 #include "mozilla/ScopeExit.h"
12 #include "mozilla/StaticPrefs_webgl.h"
13 #include "WebGLContext.h"
15 namespace mozilla {
17 static bool TestShaderCompile(gl::GLContext* const gl, const GLenum type,
18 const std::string& source) {
19 const auto shader = gl->fCreateShader(type);
20 const auto cleanup = MakeScopeExit([&]() { gl->fDeleteShader(shader); });
22 const std::array<const char*, 1> parts = {source.c_str()};
23 gl->fShaderSource(shader, parts.size(), parts.data(), nullptr);
24 gl->fCompileShader(shader);
26 GLint status = 0;
27 gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &status);
29 if (status == LOCAL_GL_TRUE) return true;
31 std::vector<char> chars;
32 chars.resize(1000);
33 gl->fGetShaderInfoLog(shader, LazyAssertedCast(chars.size() - 1), nullptr,
34 chars.data());
35 printf_stderr("GetShaderInfoLog() ->\n%s\n", chars.data());
37 gl->fGetShaderSource(shader, LazyAssertedCast(chars.size() - 1), nullptr,
38 chars.data());
39 printf_stderr("GetShaderSource() ->\n%s\n", chars.data());
41 return false;
44 // -
46 WebGLExtensionBlendMinMax::WebGLExtensionBlendMinMax(WebGLContext* webgl)
47 : WebGLExtensionBase(webgl) {
48 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
51 bool WebGLExtensionBlendMinMax::IsSupported(const WebGLContext* webgl) {
52 if (webgl->IsWebGL2()) return false;
54 return webgl->GL()->IsSupported(gl::GLFeature::blend_minmax);
57 // -
59 WebGLExtensionColorBufferFloat::WebGLExtensionColorBufferFloat(
60 WebGLContext* webgl)
61 : WebGLExtensionBase(webgl) {
62 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
63 SetRenderable(webgl::FormatRenderableState::Implicit(
64 WebGLExtensionID::WEBGL_color_buffer_float));
67 void WebGLExtensionColorBufferFloat::SetRenderable(
68 const webgl::FormatRenderableState state) {
69 auto& fua = mContext->mFormatUsage;
71 auto fnUpdateUsage = [&](GLenum sizedFormat,
72 webgl::EffectiveFormat effFormat) {
73 auto usage = fua->EditUsage(effFormat);
74 usage->SetRenderable(state);
75 fua->AllowRBFormat(sizedFormat, usage);
78 #define FOO(x) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x)
80 // The extension doesn't actually add RGB32F; only RGBA32F.
81 FOO(RGBA32F);
83 #undef FOO
86 void WebGLExtensionColorBufferFloat::OnSetExplicit() {
87 SetRenderable(webgl::FormatRenderableState::Explicit());
90 bool WebGLExtensionColorBufferFloat::IsSupported(const WebGLContext* webgl) {
91 if (webgl->IsWebGL2()) return false;
93 const auto& gl = webgl->gl;
94 return gl->IsSupported(gl::GLFeature::renderbuffer_color_float) &&
95 gl->IsSupported(gl::GLFeature::frag_color_float);
98 // -
100 WebGLExtensionColorBufferHalfFloat::WebGLExtensionColorBufferHalfFloat(
101 WebGLContext* webgl)
102 : WebGLExtensionBase(webgl) {
103 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
104 SetRenderable(webgl::FormatRenderableState::Implicit(
105 WebGLExtensionID::EXT_color_buffer_half_float));
108 void WebGLExtensionColorBufferHalfFloat::SetRenderable(
109 const webgl::FormatRenderableState state) {
110 auto& fua = mContext->mFormatUsage;
112 auto fnUpdateUsage = [&](GLenum sizedFormat, webgl::EffectiveFormat effFormat,
113 const bool renderable) {
114 auto usage = fua->EditUsage(effFormat);
115 if (renderable) {
116 usage->SetRenderable(state);
118 fua->AllowRBFormat(sizedFormat, usage, renderable);
121 #define FOO(x, y) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x, y)
123 FOO(RGBA16F, true);
124 FOO(RGB16F, false); // It's not required, thus not portable. (Also there's a
125 // wicked driver bug on Mac+Intel)
127 #undef FOO
130 void WebGLExtensionColorBufferHalfFloat::OnSetExplicit() {
131 SetRenderable(webgl::FormatRenderableState::Explicit());
134 bool WebGLExtensionColorBufferHalfFloat::IsSupported(
135 const WebGLContext* webgl) {
136 if (webgl->IsWebGL2()) return false;
138 const auto& gl = webgl->gl;
139 return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) &&
140 gl->IsSupported(gl::GLFeature::frag_color_float);
143 // -
145 WebGLExtensionCompressedTextureASTC::WebGLExtensionCompressedTextureASTC(
146 WebGLContext* webgl)
147 : WebGLExtensionBase(webgl) {
148 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
150 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
151 const auto fnAdd = [&webgl_](GLenum sizedFormat,
152 webgl::EffectiveFormat effFormat) {
153 auto& fua = webgl_->mFormatUsage;
155 auto usage = fua->EditUsage(effFormat);
156 usage->isFilterable = true;
157 fua->AllowSizedTexFormat(sizedFormat, usage);
160 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
162 fnAdd(FOO(COMPRESSED_RGBA_ASTC_4x4_KHR));
163 fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x4_KHR));
164 fnAdd(FOO(COMPRESSED_RGBA_ASTC_5x5_KHR));
165 fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x5_KHR));
166 fnAdd(FOO(COMPRESSED_RGBA_ASTC_6x6_KHR));
167 fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x5_KHR));
168 fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x6_KHR));
169 fnAdd(FOO(COMPRESSED_RGBA_ASTC_8x8_KHR));
170 fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x5_KHR));
171 fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x6_KHR));
172 fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x8_KHR));
173 fnAdd(FOO(COMPRESSED_RGBA_ASTC_10x10_KHR));
174 fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x10_KHR));
175 fnAdd(FOO(COMPRESSED_RGBA_ASTC_12x12_KHR));
177 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR));
178 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR));
179 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR));
180 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR));
181 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR));
182 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR));
183 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR));
184 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR));
185 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR));
186 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR));
187 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR));
188 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR));
189 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR));
190 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR));
192 #undef FOO
195 bool WebGLExtensionCompressedTextureASTC::IsSupported(
196 const WebGLContext* webgl) {
197 gl::GLContext* gl = webgl->GL();
198 return gl->IsExtensionSupported(
199 gl::GLContext::KHR_texture_compression_astc_ldr);
202 // -
204 WebGLExtensionCompressedTextureBPTC::WebGLExtensionCompressedTextureBPTC(
205 WebGLContext* const webgl)
206 : WebGLExtensionBase(webgl) {
207 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
209 auto& fua = webgl->mFormatUsage;
211 const auto fnAdd = [&](const GLenum sizedFormat,
212 const webgl::EffectiveFormat effFormat) {
213 auto usage = fua->EditUsage(effFormat);
214 usage->isFilterable = true;
215 fua->AllowSizedTexFormat(sizedFormat, usage);
218 #define _(X) LOCAL_GL_##X, webgl::EffectiveFormat::X
220 fnAdd(_(COMPRESSED_RGBA_BPTC_UNORM));
221 fnAdd(_(COMPRESSED_SRGB_ALPHA_BPTC_UNORM));
222 fnAdd(_(COMPRESSED_RGB_BPTC_SIGNED_FLOAT));
223 fnAdd(_(COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT));
225 #undef _
228 bool WebGLExtensionCompressedTextureBPTC::IsSupported(
229 const WebGLContext* const webgl) {
230 return webgl->gl->IsSupported(gl::GLFeature::texture_compression_bptc);
233 // -
235 WebGLExtensionCompressedTextureES3::WebGLExtensionCompressedTextureES3(
236 WebGLContext* webgl)
237 : WebGLExtensionBase(webgl) {
238 // GLES 3.0.4, p147, table 3.19
239 // GLES 3.0.4, p286+, $C.1 "ETC Compressed Texture Image Formats"
240 // Note that all compressed texture formats are filterable:
241 // GLES 3.0.4 p161:
242 // "[A] texture is complete unless any of the following conditions hold true:
243 // [...]
244 // * The effective internal format specified for the texture arrays is a
245 // sized internal color format that is not texture-filterable (see table
246 // 3.13) and [the mag filter requires filtering]."
247 // Compressed formats are not sized internal color formats, and indeed they
248 // are not listed in table 3.13.
250 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
251 const auto fnAdd = [&webgl_](GLenum sizedFormat,
252 webgl::EffectiveFormat effFormat) {
253 auto& fua = webgl_->mFormatUsage;
255 auto usage = fua->EditUsage(effFormat);
256 usage->isFilterable = true;
257 fua->AllowSizedTexFormat(sizedFormat, usage);
260 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
262 fnAdd(FOO(COMPRESSED_R11_EAC));
263 fnAdd(FOO(COMPRESSED_SIGNED_R11_EAC));
264 fnAdd(FOO(COMPRESSED_RG11_EAC));
265 fnAdd(FOO(COMPRESSED_SIGNED_RG11_EAC));
266 fnAdd(FOO(COMPRESSED_RGB8_ETC2));
267 fnAdd(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2));
268 fnAdd(FOO(COMPRESSED_RGBA8_ETC2_EAC));
270 // sRGB support is manadatory in GL 4.3 and GL ES 3.0, which are the only
271 // versions to support ETC2.
272 fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC));
273 fnAdd(FOO(COMPRESSED_SRGB8_ETC2));
274 fnAdd(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2));
276 #undef FOO
279 // -
281 WebGLExtensionCompressedTextureETC1::WebGLExtensionCompressedTextureETC1(
282 WebGLContext* webgl)
283 : WebGLExtensionBase(webgl) {
284 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
285 const auto fnAdd = [&webgl_](GLenum sizedFormat,
286 webgl::EffectiveFormat effFormat) {
287 auto& fua = webgl_->mFormatUsage;
289 auto usage = fua->EditUsage(effFormat);
290 usage->isFilterable = true;
291 fua->AllowSizedTexFormat(sizedFormat, usage);
294 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
296 fnAdd(FOO(ETC1_RGB8_OES));
298 #undef FOO
301 // -
303 WebGLExtensionCompressedTexturePVRTC::WebGLExtensionCompressedTexturePVRTC(
304 WebGLContext* webgl)
305 : WebGLExtensionBase(webgl) {
306 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
307 const auto fnAdd = [&webgl_](GLenum sizedFormat,
308 webgl::EffectiveFormat effFormat) {
309 auto& fua = webgl_->mFormatUsage;
311 auto usage = fua->EditUsage(effFormat);
312 usage->isFilterable = true;
313 fua->AllowSizedTexFormat(sizedFormat, usage);
316 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
318 fnAdd(FOO(COMPRESSED_RGB_PVRTC_4BPPV1));
319 fnAdd(FOO(COMPRESSED_RGB_PVRTC_2BPPV1));
320 fnAdd(FOO(COMPRESSED_RGBA_PVRTC_4BPPV1));
321 fnAdd(FOO(COMPRESSED_RGBA_PVRTC_2BPPV1));
323 #undef FOO
326 // -
328 WebGLExtensionCompressedTextureRGTC::WebGLExtensionCompressedTextureRGTC(
329 WebGLContext* const webgl)
330 : WebGLExtensionBase(webgl) {
331 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
333 auto& fua = webgl->mFormatUsage;
335 const auto fnAdd = [&](const GLenum sizedFormat,
336 const webgl::EffectiveFormat effFormat) {
337 auto usage = fua->EditUsage(effFormat);
338 usage->isFilterable = true;
339 fua->AllowSizedTexFormat(sizedFormat, usage);
342 #define _(X) LOCAL_GL_##X, webgl::EffectiveFormat::X
344 fnAdd(_(COMPRESSED_RED_RGTC1));
345 fnAdd(_(COMPRESSED_SIGNED_RED_RGTC1));
346 fnAdd(_(COMPRESSED_RG_RGTC2));
347 fnAdd(_(COMPRESSED_SIGNED_RG_RGTC2));
349 #undef _
352 bool WebGLExtensionCompressedTextureRGTC::IsSupported(
353 const WebGLContext* const webgl) {
354 return webgl->gl->IsSupported(gl::GLFeature::texture_compression_rgtc);
357 // -
359 WebGLExtensionCompressedTextureS3TC::WebGLExtensionCompressedTextureS3TC(
360 WebGLContext* webgl)
361 : WebGLExtensionBase(webgl) {
362 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
363 const auto fnAdd = [&webgl_](GLenum sizedFormat,
364 webgl::EffectiveFormat effFormat) {
365 auto& fua = webgl_->mFormatUsage;
367 auto usage = fua->EditUsage(effFormat);
368 usage->isFilterable = true;
369 fua->AllowSizedTexFormat(sizedFormat, usage);
372 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
374 fnAdd(FOO(COMPRESSED_RGB_S3TC_DXT1_EXT));
375 fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT1_EXT));
376 fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT3_EXT));
377 fnAdd(FOO(COMPRESSED_RGBA_S3TC_DXT5_EXT));
379 #undef FOO
382 bool WebGLExtensionCompressedTextureS3TC::IsSupported(
383 const WebGLContext* webgl) {
384 gl::GLContext* gl = webgl->GL();
385 if (gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc))
386 return true;
388 return gl->IsExtensionSupported(
389 gl::GLContext::EXT_texture_compression_dxt1) &&
390 gl->IsExtensionSupported(
391 gl::GLContext::ANGLE_texture_compression_dxt3) &&
392 gl->IsExtensionSupported(
393 gl::GLContext::ANGLE_texture_compression_dxt5);
396 // -
398 WebGLExtensionCompressedTextureS3TC_SRGB::
399 WebGLExtensionCompressedTextureS3TC_SRGB(WebGLContext* webgl)
400 : WebGLExtensionBase(webgl) {
401 RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
402 const auto fnAdd = [&webgl_](GLenum sizedFormat,
403 webgl::EffectiveFormat effFormat) {
404 auto& fua = webgl_->mFormatUsage;
406 auto usage = fua->EditUsage(effFormat);
407 usage->isFilterable = true;
408 fua->AllowSizedTexFormat(sizedFormat, usage);
411 #define FOO(x) LOCAL_GL_##x, webgl::EffectiveFormat::x
413 fnAdd(FOO(COMPRESSED_SRGB_S3TC_DXT1_EXT));
414 fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT));
415 fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT));
416 fnAdd(FOO(COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT));
418 #undef FOO
421 bool WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported(
422 const WebGLContext* webgl) {
423 gl::GLContext* gl = webgl->GL();
424 if (gl->IsGLES())
425 return gl->IsExtensionSupported(
426 gl::GLContext::EXT_texture_compression_s3tc_srgb);
428 // Desktop GL is more complicated: It's EXT_texture_sRGB, when
429 // EXT_texture_compression_s3tc is supported, that enables srgb+s3tc.
430 return gl->IsExtensionSupported(gl::GLContext::EXT_texture_sRGB) &&
431 gl->IsExtensionSupported(gl::GLContext::EXT_texture_compression_s3tc);
434 // -
436 WebGLExtensionDepthClamp::WebGLExtensionDepthClamp(WebGLContext* const webgl)
437 : WebGLExtensionBase(webgl) {
438 webgl->mIsEnabledMapKeys.insert(LOCAL_GL_DEPTH_CLAMP);
441 // -
443 WebGLExtensionDepthTexture::WebGLExtensionDepthTexture(
444 WebGLContext* const webgl)
445 : WebGLExtensionBase(webgl) {
446 auto& fua = webgl->mFormatUsage;
448 const auto fnAdd = [&fua](webgl::EffectiveFormat effFormat,
449 GLenum unpackFormat, GLenum unpackType) {
450 auto usage = fua->EditUsage(effFormat);
451 MOZ_ASSERT(usage->isFilterable);
452 MOZ_ASSERT(usage->IsRenderable());
454 const webgl::PackingInfo pi = {unpackFormat, unpackType};
455 const webgl::DriverUnpackInfo dui = {unpackFormat, unpackFormat,
456 unpackType};
457 fua->AddTexUnpack(usage, pi, dui);
458 fua->AllowUnsizedTexFormat(pi, usage);
461 fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT16, LOCAL_GL_DEPTH_COMPONENT,
462 LOCAL_GL_UNSIGNED_SHORT);
463 fnAdd(webgl::EffectiveFormat::DEPTH_COMPONENT24, LOCAL_GL_DEPTH_COMPONENT,
464 LOCAL_GL_UNSIGNED_INT);
465 fnAdd(webgl::EffectiveFormat::DEPTH24_STENCIL8, LOCAL_GL_DEPTH_STENCIL,
466 LOCAL_GL_UNSIGNED_INT_24_8);
469 bool WebGLExtensionDepthTexture::IsSupported(const WebGLContext* const webgl) {
470 if (webgl->IsWebGL2()) return false;
472 // WEBGL_depth_texture supports DEPTH_STENCIL textures
473 const auto& gl = webgl->gl;
474 if (!gl->IsSupported(gl::GLFeature::packed_depth_stencil)) return false;
476 return gl->IsSupported(gl::GLFeature::depth_texture) ||
477 gl->IsExtensionSupported(gl::GLContext::ANGLE_depth_texture);
480 // -
482 WebGLExtensionDisjointTimerQuery::WebGLExtensionDisjointTimerQuery(
483 WebGLContext* webgl)
484 : WebGLExtensionBase(webgl) {
485 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
488 bool WebGLExtensionDisjointTimerQuery::IsSupported(
489 const WebGLContext* const webgl) {
490 if (!StaticPrefs::webgl_enable_privileged_extensions()) return false;
492 gl::GLContext* gl = webgl->GL();
493 return gl->IsSupported(gl::GLFeature::query_objects) &&
494 gl->IsSupported(gl::GLFeature::get_query_object_i64v) &&
495 gl->IsSupported(
496 gl::GLFeature::query_counter); // provides GL_TIMESTAMP
499 // -
501 WebGLExtensionDrawBuffers::WebGLExtensionDrawBuffers(WebGLContext* webgl)
502 : WebGLExtensionBase(webgl) {
503 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
506 bool WebGLExtensionDrawBuffers::IsSupported(const WebGLContext* webgl) {
507 if (!webgl->mIsSupportedCache_DrawBuffers) {
508 webgl->mIsSupportedCache_DrawBuffers = [&]() {
509 gl::GLContext* const gl = webgl->GL();
511 if (webgl->IsWebGL2()) return false;
512 if (!gl->IsSupported(gl::GLFeature::draw_buffers)) return false;
514 if (gl->IsGLES() && gl->Version() >= 300) {
515 // ANGLE's shader translator can't translate ESSL1 exts to ESSL3. (bug
516 // 1524804)
517 // The spec (and some implementations of ES3) don't require support for
518 // any extensions in ESSL 100, but an implementation can choose to
519 // support them anyway. So let's check!
520 const bool ok = TestShaderCompile(gl, LOCAL_GL_FRAGMENT_SHADER, R"(
521 #extension GL_EXT_draw_buffers: require
522 void main() {}
523 )");
524 if (!ok) return false;
527 return true;
528 }();
531 return *webgl->mIsSupportedCache_DrawBuffers;
534 // -
536 WebGLExtensionExplicitPresent::WebGLExtensionExplicitPresent(
537 WebGLContext* const webgl)
538 : WebGLExtensionBase(webgl) {
539 if (!IsSupported(webgl)) {
540 NS_WARNING(
541 "Constructing WebGLExtensionExplicitPresent but IsSupported() is "
542 "false!");
543 // This was previously an assert, but it seems like we get races against
544 // StaticPrefs changes/initialization?
548 bool WebGLExtensionExplicitPresent::IsSupported(
549 const WebGLContext* const webgl) {
550 return StaticPrefs::webgl_enable_draft_extensions();
553 // -
555 WebGLExtensionEXTColorBufferFloat::WebGLExtensionEXTColorBufferFloat(
556 WebGLContext* webgl)
557 : WebGLExtensionBase(webgl) {
558 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
560 auto& fua = webgl->mFormatUsage;
562 auto fnUpdateUsage = [&fua](GLenum sizedFormat,
563 webgl::EffectiveFormat effFormat) {
564 auto usage = fua->EditUsage(effFormat);
565 usage->SetRenderable();
566 fua->AllowRBFormat(sizedFormat, usage);
569 #define FOO(x) fnUpdateUsage(LOCAL_GL_##x, webgl::EffectiveFormat::x)
571 FOO(R16F);
572 FOO(RG16F);
573 FOO(RGBA16F);
575 FOO(R32F);
576 FOO(RG32F);
577 FOO(RGBA32F);
579 FOO(R11F_G11F_B10F);
581 #undef FOO
584 /*static*/
585 bool WebGLExtensionEXTColorBufferFloat::IsSupported(const WebGLContext* webgl) {
586 if (!webgl->IsWebGL2()) return false;
588 const gl::GLContext* gl = webgl->GL();
589 return gl->IsSupported(gl::GLFeature::EXT_color_buffer_float);
592 // -
594 WebGLExtensionFBORenderMipmap::WebGLExtensionFBORenderMipmap(
595 WebGLContext* const webgl)
596 : WebGLExtensionBase(webgl) {
597 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
600 bool WebGLExtensionFBORenderMipmap::IsSupported(
601 const WebGLContext* const webgl) {
602 if (webgl->IsWebGL2()) return false;
604 const auto& gl = webgl->gl;
605 if (!gl->IsGLES()) return true;
606 if (gl->Version() >= 300) return true;
607 return gl->IsExtensionSupported(gl::GLContext::OES_fbo_render_mipmap);
610 // -
612 WebGLExtensionFloatBlend::WebGLExtensionFloatBlend(WebGLContext* const webgl)
613 : WebGLExtensionBase(webgl) {
614 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
617 bool WebGLExtensionFloatBlend::IsSupported(const WebGLContext* const webgl) {
618 if (!WebGLExtensionColorBufferFloat::IsSupported(webgl) &&
619 !WebGLExtensionEXTColorBufferFloat::IsSupported(webgl))
620 return false;
622 const auto& gl = webgl->gl;
623 if (!gl->IsGLES() && gl->Version() >= 300) return true;
624 if (gl->IsGLES() && gl->Version() >= 320) return true;
625 return gl->IsExtensionSupported(gl::GLContext::EXT_float_blend);
628 // -
630 WebGLExtensionFragDepth::WebGLExtensionFragDepth(WebGLContext* webgl)
631 : WebGLExtensionBase(webgl) {
632 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
635 bool WebGLExtensionFragDepth::IsSupported(const WebGLContext* const webgl) {
636 if (!webgl->mIsSupportedCache_FragDepth) {
637 webgl->mIsSupportedCache_FragDepth = [&]() {
638 gl::GLContext* const gl = webgl->GL();
640 if (webgl->IsWebGL2()) return false;
641 if (!gl->IsSupported(gl::GLFeature::frag_depth)) return false;
643 if (gl->IsGLES() && gl->Version() >= 300) {
644 // ANGLE's shader translator can't translate ESSL1 exts to ESSL3. (bug
645 // 1524804)
646 // The spec (and some implementations of ES3) don't require support for
647 // any extensions in ESSL 100, but an implementation can choose to
648 // support them anyway. So let's check!
649 const bool ok = TestShaderCompile(gl, LOCAL_GL_FRAGMENT_SHADER, R"(
650 #extension GL_EXT_frag_depth: require
651 void main() {}
652 )");
653 if (!ok) return false;
656 return true;
657 }();
660 return *webgl->mIsSupportedCache_FragDepth;
663 // -
665 WebGLExtensionInstancedArrays::WebGLExtensionInstancedArrays(
666 WebGLContext* webgl)
667 : WebGLExtensionBase(webgl) {
668 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
671 bool WebGLExtensionInstancedArrays::IsSupported(const WebGLContext* webgl) {
672 if (webgl->IsWebGL2()) return false;
674 gl::GLContext* gl = webgl->GL();
675 return gl->IsSupported(gl::GLFeature::draw_instanced) &&
676 gl->IsSupported(gl::GLFeature::instanced_arrays);
679 // -
681 WebGLExtensionMultiview::WebGLExtensionMultiview(WebGLContext* const webgl)
682 : WebGLExtensionBase(webgl) {
683 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
686 bool WebGLExtensionMultiview::IsSupported(const WebGLContext* const webgl) {
687 if (!webgl->IsWebGL2()) return false;
689 const auto& gl = webgl->gl;
690 return gl->IsSupported(gl::GLFeature::multiview);
693 // -
695 WebGLExtensionShaderTextureLod::WebGLExtensionShaderTextureLod(
696 WebGLContext* webgl)
697 : WebGLExtensionBase(webgl) {
698 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
701 bool WebGLExtensionShaderTextureLod::IsSupported(const WebGLContext* webgl) {
702 if (!webgl->mIsSupportedCache_ShaderTextureLod) {
703 webgl->mIsSupportedCache_ShaderTextureLod = [&]() {
704 gl::GLContext* const gl = webgl->GL();
706 if (webgl->IsWebGL2()) return false;
707 if (!gl->IsSupported(gl::GLFeature::shader_texture_lod)) return false;
709 if (gl->IsGLES() && gl->Version() >= 300) {
710 // ANGLE's shader translator doesn't yet translate
711 // WebGL1+EXT_shader_texture_lod to ES3. (Bug 1491221)
712 // The spec (and some implementations of ES3) don't require support for
713 // any extensions in ESSL 100, but an implementation can choose to
714 // support them anyway. So let's check!
715 const bool ok = TestShaderCompile(gl, LOCAL_GL_FRAGMENT_SHADER, R"(
716 #extension GL_EXT_shader_texture_lod: require
717 void main() {}
718 )");
719 if (!ok) return false;
722 return true;
723 }();
725 return *webgl->mIsSupportedCache_ShaderTextureLod;
728 // -
730 WebGLExtensionSRGB::WebGLExtensionSRGB(WebGLContext* webgl)
731 : WebGLExtensionBase(webgl) {
732 MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
734 gl::GLContext* gl = webgl->GL();
735 if (!gl->IsGLES()) {
736 // Desktop OpenGL requires the following to be enabled in order to
737 // support sRGB operations on framebuffers.
738 gl->fEnable(LOCAL_GL_FRAMEBUFFER_SRGB_EXT);
741 auto& fua = webgl->mFormatUsage;
743 RefPtr<gl::GLContext> gl_ = gl; // Bug 1201275
744 const auto fnAdd = [&fua, &gl_](webgl::EffectiveFormat effFormat,
745 GLenum format, GLenum desktopUnpackFormat) {
746 auto usage = fua->EditUsage(effFormat);
747 usage->isFilterable = true;
749 webgl::DriverUnpackInfo dui = {format, format, LOCAL_GL_UNSIGNED_BYTE};
750 const auto pi = dui.ToPacking();
752 if (!gl_->IsGLES()) dui.unpackFormat = desktopUnpackFormat;
754 fua->AddTexUnpack(usage, pi, dui);
756 fua->AllowUnsizedTexFormat(pi, usage);
759 fnAdd(webgl::EffectiveFormat::SRGB8, LOCAL_GL_SRGB, LOCAL_GL_RGB);
760 fnAdd(webgl::EffectiveFormat::SRGB8_ALPHA8, LOCAL_GL_SRGB_ALPHA,
761 LOCAL_GL_RGBA);
763 auto usage = fua->EditUsage(webgl::EffectiveFormat::SRGB8_ALPHA8);
764 usage->SetRenderable();
765 fua->AllowRBFormat(LOCAL_GL_SRGB8_ALPHA8, usage);
768 bool WebGLExtensionSRGB::IsSupported(const WebGLContext* const webgl) {
769 if (webgl->IsWebGL2()) return false;
771 return webgl->gl->IsSupported(gl::GLFeature::sRGB);
774 // -
776 WebGLExtensionTextureFloat::WebGLExtensionTextureFloat(WebGLContext* webgl)
777 : WebGLExtensionBase(webgl) {
778 MOZ_ASSERT(IsSupported(webgl));
780 auto& fua = webgl->mFormatUsage;
781 gl::GLContext* gl = webgl->GL();
783 webgl::PackingInfo pi;
784 webgl::DriverUnpackInfo dui;
785 const GLint* swizzle = nullptr;
787 const auto fnAdd = [&](webgl::EffectiveFormat effFormat) {
788 MOZ_ASSERT_IF(swizzle, gl->IsSupported(gl::GLFeature::texture_swizzle));
790 auto usage = fua->EditUsage(effFormat);
791 usage->textureSwizzleRGBA = swizzle;
792 fua->AddTexUnpack(usage, pi, dui);
794 fua->AllowUnsizedTexFormat(pi, usage);
797 bool useSizedFormats = true;
798 const bool hasSizedLegacyFormats = gl->IsCompatibilityProfile();
799 if (gl->IsGLES() && gl->Version() < 300) {
800 useSizedFormats = false;
803 ////////////////
805 pi = {LOCAL_GL_RGBA, LOCAL_GL_FLOAT};
806 dui = {pi.format, pi.format, pi.type};
807 swizzle = nullptr;
808 if (useSizedFormats || gl->IsExtensionSupported(
809 gl::GLContext::CHROMIUM_color_buffer_float_rgba)) {
810 // ANGLE only exposes renderable RGBA32F via
811 // CHROMIUM_color_buffer_float_rgba, which uses sized formats.
812 dui.internalFormat = LOCAL_GL_RGBA32F;
814 fnAdd(webgl::EffectiveFormat::RGBA32F);
816 //////
818 pi = {LOCAL_GL_RGB, LOCAL_GL_FLOAT};
819 dui = {pi.format, pi.format, pi.type};
820 swizzle = nullptr;
821 if (useSizedFormats) {
822 dui.internalFormat = LOCAL_GL_RGB32F;
824 fnAdd(webgl::EffectiveFormat::RGB32F);
826 //////
828 pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_FLOAT};
829 dui = {pi.format, pi.format, pi.type};
830 swizzle = nullptr;
831 if (useSizedFormats) {
832 if (hasSizedLegacyFormats) {
833 dui.internalFormat = LOCAL_GL_LUMINANCE32F_ARB;
834 } else {
835 dui.internalFormat = LOCAL_GL_R32F;
836 dui.unpackFormat = LOCAL_GL_RED;
837 swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
840 fnAdd(webgl::EffectiveFormat::Luminance32F);
842 //////
844 pi = {LOCAL_GL_ALPHA, LOCAL_GL_FLOAT};
845 dui = {pi.format, pi.format, pi.type};
846 swizzle = nullptr;
847 if (useSizedFormats) {
848 if (hasSizedLegacyFormats) {
849 dui.internalFormat = LOCAL_GL_ALPHA32F_ARB;
850 } else {
851 dui.internalFormat = LOCAL_GL_R32F;
852 dui.unpackFormat = LOCAL_GL_RED;
853 swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
856 fnAdd(webgl::EffectiveFormat::Alpha32F);
858 //////
860 pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_FLOAT};
861 dui = {pi.format, pi.format, pi.type};
862 swizzle = nullptr;
863 if (useSizedFormats) {
864 if (hasSizedLegacyFormats) {
865 dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA32F_ARB;
866 } else {
867 dui.internalFormat = LOCAL_GL_RG32F;
868 dui.unpackFormat = LOCAL_GL_RG;
869 swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
872 fnAdd(webgl::EffectiveFormat::Luminance32FAlpha32F);
875 bool WebGLExtensionTextureFloat::IsSupported(const WebGLContext* webgl) {
876 if (webgl->IsWebGL2()) return false;
878 gl::GLContext* gl = webgl->GL();
879 if (!gl->IsSupported(gl::GLFeature::texture_float)) return false;
881 const bool needsSwizzle = gl->IsCoreProfile();
882 const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
883 if (needsSwizzle && !hasSwizzle) return false;
885 return true;
888 // -
890 WebGLExtensionTextureFloatLinear::WebGLExtensionTextureFloatLinear(
891 WebGLContext* webgl)
892 : WebGLExtensionBase(webgl) {
893 auto& fua = webgl->mFormatUsage;
895 fua->EditUsage(webgl::EffectiveFormat::RGBA32F)->isFilterable = true;
896 fua->EditUsage(webgl::EffectiveFormat::RGB32F)->isFilterable = true;
898 if (webgl->IsWebGL2()) {
899 fua->EditUsage(webgl::EffectiveFormat::R32F)->isFilterable = true;
900 fua->EditUsage(webgl::EffectiveFormat::RG32F)->isFilterable = true;
901 } else {
902 fua->EditUsage(webgl::EffectiveFormat::Luminance32FAlpha32F)->isFilterable =
903 true;
904 fua->EditUsage(webgl::EffectiveFormat::Luminance32F)->isFilterable = true;
905 fua->EditUsage(webgl::EffectiveFormat::Alpha32F)->isFilterable = true;
909 // -
911 WebGLExtensionTextureHalfFloat::WebGLExtensionTextureHalfFloat(
912 WebGLContext* webgl)
913 : WebGLExtensionBase(webgl) {
914 auto& fua = webgl->mFormatUsage;
915 gl::GLContext* gl = webgl->GL();
917 webgl::PackingInfo pi;
918 webgl::DriverUnpackInfo dui;
919 const GLint* swizzle = nullptr;
921 const auto fnAdd = [&](webgl::EffectiveFormat effFormat) {
922 MOZ_ASSERT_IF(swizzle, gl->IsSupported(gl::GLFeature::texture_swizzle));
924 auto usage = fua->EditUsage(effFormat);
925 usage->textureSwizzleRGBA = swizzle;
926 fua->AddTexUnpack(usage, pi, dui);
928 fua->AllowUnsizedTexFormat(pi, usage);
931 bool useSizedFormats = true;
932 const bool hasSizedLegacyFormats = gl->IsCompatibilityProfile();
933 if (gl->IsGLES() && gl->Version() < 300) {
934 useSizedFormats = false;
937 GLenum driverUnpackType = LOCAL_GL_HALF_FLOAT;
938 if (!gl->IsSupported(gl::GLFeature::texture_half_float)) {
939 MOZ_ASSERT(gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float));
940 driverUnpackType = LOCAL_GL_HALF_FLOAT_OES;
943 ////////////////
945 pi = {LOCAL_GL_RGBA, LOCAL_GL_HALF_FLOAT_OES};
946 dui = {pi.format, pi.format, driverUnpackType};
947 swizzle = nullptr;
948 if (useSizedFormats) {
949 dui.internalFormat = LOCAL_GL_RGBA16F;
951 fnAdd(webgl::EffectiveFormat::RGBA16F);
953 //////
955 pi = {LOCAL_GL_RGB, LOCAL_GL_HALF_FLOAT_OES};
956 dui = {pi.format, pi.format, driverUnpackType};
957 swizzle = nullptr;
958 if (useSizedFormats) {
959 dui.internalFormat = LOCAL_GL_RGB16F;
961 fnAdd(webgl::EffectiveFormat::RGB16F);
963 //////
965 pi = {LOCAL_GL_LUMINANCE, LOCAL_GL_HALF_FLOAT_OES};
966 dui = {pi.format, pi.format, driverUnpackType};
967 swizzle = nullptr;
968 if (useSizedFormats) {
969 if (hasSizedLegacyFormats) {
970 dui.internalFormat = LOCAL_GL_LUMINANCE16F_ARB;
971 } else {
972 dui.internalFormat = LOCAL_GL_R16F;
973 dui.unpackFormat = LOCAL_GL_RED;
974 swizzle = webgl::FormatUsageInfo::kLuminanceSwizzleRGBA;
977 fnAdd(webgl::EffectiveFormat::Luminance16F);
979 //////
981 pi = {LOCAL_GL_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
982 dui = {pi.format, pi.format, driverUnpackType};
983 swizzle = nullptr;
984 if (useSizedFormats) {
985 if (hasSizedLegacyFormats) {
986 dui.internalFormat = LOCAL_GL_ALPHA16F_ARB;
987 } else {
988 dui.internalFormat = LOCAL_GL_R16F;
989 dui.unpackFormat = LOCAL_GL_RED;
990 swizzle = webgl::FormatUsageInfo::kAlphaSwizzleRGBA;
993 fnAdd(webgl::EffectiveFormat::Alpha16F);
995 //////
997 pi = {LOCAL_GL_LUMINANCE_ALPHA, LOCAL_GL_HALF_FLOAT_OES};
998 dui = {pi.format, pi.format, driverUnpackType};
999 swizzle = nullptr;
1000 if (useSizedFormats) {
1001 if (hasSizedLegacyFormats) {
1002 dui.internalFormat = LOCAL_GL_LUMINANCE_ALPHA16F_ARB;
1003 } else {
1004 dui.internalFormat = LOCAL_GL_RG16F;
1005 dui.unpackFormat = LOCAL_GL_RG;
1006 swizzle = webgl::FormatUsageInfo::kLumAlphaSwizzleRGBA;
1009 fnAdd(webgl::EffectiveFormat::Luminance16FAlpha16F);
1012 bool WebGLExtensionTextureHalfFloat::IsSupported(const WebGLContext* webgl) {
1013 if (webgl->IsWebGL2()) return false;
1015 gl::GLContext* gl = webgl->GL();
1016 if (!gl->IsSupported(gl::GLFeature::texture_half_float) &&
1017 !gl->IsExtensionSupported(gl::GLContext::OES_texture_half_float)) {
1018 return false;
1021 const bool needsSwizzle = gl->IsCoreProfile();
1022 const bool hasSwizzle = gl->IsSupported(gl::GLFeature::texture_swizzle);
1023 if (needsSwizzle && !hasSwizzle) return false;
1025 return true;
1028 // -
1030 WebGLExtensionTextureHalfFloatLinear::WebGLExtensionTextureHalfFloatLinear(
1031 WebGLContext* webgl)
1032 : WebGLExtensionBase(webgl) {
1033 MOZ_ASSERT(!webgl->IsWebGL2());
1034 auto& fua = webgl->mFormatUsage;
1036 fua->EditUsage(webgl::EffectiveFormat::RGBA16F)->isFilterable = true;
1037 fua->EditUsage(webgl::EffectiveFormat::RGB16F)->isFilterable = true;
1038 fua->EditUsage(webgl::EffectiveFormat::Luminance16FAlpha16F)->isFilterable =
1039 true;
1040 fua->EditUsage(webgl::EffectiveFormat::Luminance16F)->isFilterable = true;
1041 fua->EditUsage(webgl::EffectiveFormat::Alpha16F)->isFilterable = true;
1044 // -
1046 bool WebGLExtensionTextureNorm16::IsSupported(const WebGLContext* const webgl) {
1047 if (!StaticPrefs::webgl_enable_draft_extensions()) return false;
1048 if (!webgl->IsWebGL2()) return false;
1050 const auto& gl = webgl->gl;
1052 // ANGLE's support is broken in our checkout.
1053 if (gl->IsANGLE()) return false;
1055 return gl->IsSupported(gl::GLFeature::texture_norm16);
1058 WebGLExtensionTextureNorm16::WebGLExtensionTextureNorm16(WebGLContext* webgl)
1059 : WebGLExtensionBase(webgl) {
1060 if (!IsSupported(webgl)) {
1061 NS_WARNING(
1062 "Constructing WebGLExtensionTextureNorm16 but IsSupported() is "
1063 "false!");
1064 // This was previously an assert, but it seems like we get races against
1065 // StaticPrefs changes/initialization?
1068 auto& fua = *webgl->mFormatUsage;
1070 const auto fnAdd = [&](webgl::EffectiveFormat effFormat,
1071 const bool renderable, const webgl::PackingInfo& pi) {
1072 auto& usage = *fua.EditUsage(effFormat);
1073 const auto& format = *usage.format;
1075 const auto dui =
1076 webgl::DriverUnpackInfo{format.sizedFormat, pi.format, pi.type};
1077 fua.AddTexUnpack(&usage, pi, dui);
1079 fua.AllowSizedTexFormat(format.sizedFormat, &usage);
1080 fua.AllowUnsizedTexFormat(pi, &usage);
1082 if (renderable) {
1083 usage.SetRenderable();
1084 fua.AllowRBFormat(format.sizedFormat, &usage);
1088 fnAdd(webgl::EffectiveFormat::R16, true,
1089 {LOCAL_GL_RED, LOCAL_GL_UNSIGNED_SHORT});
1090 fnAdd(webgl::EffectiveFormat::RG16, true,
1091 {LOCAL_GL_RG, LOCAL_GL_UNSIGNED_SHORT});
1092 fnAdd(webgl::EffectiveFormat::RGB16, false,
1093 {LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT});
1094 fnAdd(webgl::EffectiveFormat::RGBA16, true,
1095 {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_SHORT});
1097 fnAdd(webgl::EffectiveFormat::R16_SNORM, false,
1098 {LOCAL_GL_RED, LOCAL_GL_SHORT});
1099 fnAdd(webgl::EffectiveFormat::RG16_SNORM, false,
1100 {LOCAL_GL_RG, LOCAL_GL_SHORT});
1101 fnAdd(webgl::EffectiveFormat::RGB16_SNORM, false,
1102 {LOCAL_GL_RGB, LOCAL_GL_SHORT});
1103 fnAdd(webgl::EffectiveFormat::RGBA16_SNORM, false,
1104 {LOCAL_GL_RGBA, LOCAL_GL_SHORT});
1107 } // namespace mozilla