1 /* -*- Mode: C++; tab-width: 4; 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 "WebGLContext.h"
7 #include "ClientWebGLExtensions.h"
9 #include "mozilla/dom/BindingDeclarations.h"
10 #include "mozilla/dom/ToJSValue.h"
11 #include "mozilla/EnumeratedRange.h"
13 #include "WebGLContextUtils.h"
14 #include "WebGLExtensions.h"
18 const char* GetExtensionName(const WebGLExtensionID ext
) {
19 static EnumeratedArray
<WebGLExtensionID
, WebGLExtensionID::Max
, const char*>
20 sExtensionNamesEnumeratedArray
;
21 static bool initialized
= false;
26 #define WEBGL_EXTENSION_IDENTIFIER(x) \
27 sExtensionNamesEnumeratedArray[WebGLExtensionID::x] = #x;
29 WEBGL_EXTENSION_IDENTIFIER(ANGLE_instanced_arrays
)
30 WEBGL_EXTENSION_IDENTIFIER(EXT_blend_minmax
)
31 WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_float
)
32 WEBGL_EXTENSION_IDENTIFIER(EXT_color_buffer_half_float
)
33 WEBGL_EXTENSION_IDENTIFIER(EXT_disjoint_timer_query
)
34 WEBGL_EXTENSION_IDENTIFIER(EXT_float_blend
)
35 WEBGL_EXTENSION_IDENTIFIER(EXT_frag_depth
)
36 WEBGL_EXTENSION_IDENTIFIER(EXT_shader_texture_lod
)
37 WEBGL_EXTENSION_IDENTIFIER(EXT_sRGB
)
38 WEBGL_EXTENSION_IDENTIFIER(EXT_texture_compression_bptc
)
39 WEBGL_EXTENSION_IDENTIFIER(EXT_texture_compression_rgtc
)
40 WEBGL_EXTENSION_IDENTIFIER(EXT_texture_filter_anisotropic
)
41 WEBGL_EXTENSION_IDENTIFIER(EXT_texture_norm16
)
42 WEBGL_EXTENSION_IDENTIFIER(MOZ_debug
)
43 WEBGL_EXTENSION_IDENTIFIER(OES_element_index_uint
)
44 WEBGL_EXTENSION_IDENTIFIER(OES_fbo_render_mipmap
)
45 WEBGL_EXTENSION_IDENTIFIER(OES_standard_derivatives
)
46 WEBGL_EXTENSION_IDENTIFIER(OES_texture_float
)
47 WEBGL_EXTENSION_IDENTIFIER(OES_texture_float_linear
)
48 WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float
)
49 WEBGL_EXTENSION_IDENTIFIER(OES_texture_half_float_linear
)
50 WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object
)
51 WEBGL_EXTENSION_IDENTIFIER(OVR_multiview2
)
52 WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float
)
53 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_astc
)
54 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc
)
55 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1
)
56 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc
)
57 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc
)
58 WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc_srgb
)
59 WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_renderer_info
)
60 WEBGL_EXTENSION_IDENTIFIER(WEBGL_debug_shaders
)
61 WEBGL_EXTENSION_IDENTIFIER(WEBGL_depth_texture
)
62 WEBGL_EXTENSION_IDENTIFIER(WEBGL_draw_buffers
)
63 WEBGL_EXTENSION_IDENTIFIER(WEBGL_explicit_present
)
64 WEBGL_EXTENSION_IDENTIFIER(WEBGL_lose_context
)
66 #undef WEBGL_EXTENSION_IDENTIFIER
69 return sExtensionNamesEnumeratedArray
[ext
];
72 // ----------------------------
75 void ClientWebGLContext::GetExtension(JSContext
* cx
, const nsAString
& wideName
,
76 JS::MutableHandle
<JSObject
*> retval
,
77 dom::CallerType callerType
,
80 const FuncScope
funcScope(*this, "getExtension");
81 if (IsContextLost()) return;
83 const auto name
= NS_ConvertUTF16toUTF8(wideName
);
85 auto ext
= WebGLExtensionID::Max
;
87 // step 1: figure what extension is wanted
88 for (const auto extension
: MakeEnumeratedRange(WebGLExtensionID::Max
)) {
89 const auto& curName
= GetExtensionName(extension
);
90 if (name
.Equals(curName
, nsCaseInsensitiveCStringComparator
)) {
96 if (ext
== WebGLExtensionID::Max
) return;
98 RefPtr
<ClientWebGLExtensionBase
> extObj
;
99 if (ext
== WebGLExtensionID::WEBGL_lose_context
) {
100 extObj
= mExtLoseContext
;
102 extObj
= GetExtension(ext
, callerType
);
106 // Ugh, this would be easier returning `any` than `object`.
107 JS::Rooted
<JS::Value
> v(cx
);
108 MOZ_ALWAYS_TRUE(dom::ToJSValue(cx
, extObj
, &v
));
110 retval
.set(&v
.toObject());
114 RefPtr
<ClientWebGLExtensionBase
> ClientWebGLContext::GetExtension(
115 const WebGLExtensionID ext
, const dom::CallerType callerType
) {
116 if (ext
== WebGLExtensionID::WEBGL_lose_context
) {
118 return mExtLoseContext
;
121 if (!mNotLost
) return nullptr;
123 if (!IsSupported(ext
, callerType
)) return nullptr;
125 auto& extSlot
= mNotLost
->extensions
[UnderlyingValue(ext
)];
126 if (MOZ_UNLIKELY(!extSlot
)) {
127 extSlot
= [&]() -> RefPtr
<ClientWebGLExtensionBase
> {
130 case WebGLExtensionID::ANGLE_instanced_arrays
:
131 return new ClientWebGLExtensionInstancedArrays(*this);
134 case WebGLExtensionID::EXT_blend_minmax
:
135 return new ClientWebGLExtensionBlendMinMax(*this);
136 case WebGLExtensionID::EXT_color_buffer_float
:
137 return new ClientWebGLExtensionEXTColorBufferFloat(*this);
138 case WebGLExtensionID::EXT_color_buffer_half_float
:
139 return new ClientWebGLExtensionColorBufferHalfFloat(*this);
140 case WebGLExtensionID::EXT_disjoint_timer_query
:
141 return new ClientWebGLExtensionDisjointTimerQuery(*this);
142 case WebGLExtensionID::EXT_float_blend
:
143 return new ClientWebGLExtensionFloatBlend(*this);
144 case WebGLExtensionID::EXT_frag_depth
:
145 return new ClientWebGLExtensionFragDepth(*this);
146 case WebGLExtensionID::EXT_shader_texture_lod
:
147 return new ClientWebGLExtensionShaderTextureLod(*this);
148 case WebGLExtensionID::EXT_sRGB
:
149 return new ClientWebGLExtensionSRGB(*this);
150 case WebGLExtensionID::EXT_texture_compression_bptc
:
151 return new ClientWebGLExtensionCompressedTextureBPTC(*this);
152 case WebGLExtensionID::EXT_texture_compression_rgtc
:
153 return new ClientWebGLExtensionCompressedTextureRGTC(*this);
154 case WebGLExtensionID::EXT_texture_filter_anisotropic
:
155 return new ClientWebGLExtensionTextureFilterAnisotropic(*this);
156 case WebGLExtensionID::EXT_texture_norm16
:
157 return new ClientWebGLExtensionTextureNorm16(*this);
160 case WebGLExtensionID::MOZ_debug
:
161 return new ClientWebGLExtensionMOZDebug(*this);
164 case WebGLExtensionID::OES_element_index_uint
:
165 return new ClientWebGLExtensionElementIndexUint(*this);
166 case WebGLExtensionID::OES_fbo_render_mipmap
:
167 return new ClientWebGLExtensionFBORenderMipmap(*this);
168 case WebGLExtensionID::OES_standard_derivatives
:
169 return new ClientWebGLExtensionStandardDerivatives(*this);
170 case WebGLExtensionID::OES_texture_float
:
171 return new ClientWebGLExtensionTextureFloat(*this);
172 case WebGLExtensionID::OES_texture_float_linear
:
173 return new ClientWebGLExtensionTextureFloatLinear(*this);
174 case WebGLExtensionID::OES_texture_half_float
:
175 return new ClientWebGLExtensionTextureHalfFloat(*this);
176 case WebGLExtensionID::OES_texture_half_float_linear
:
177 return new ClientWebGLExtensionTextureHalfFloatLinear(*this);
178 case WebGLExtensionID::OES_vertex_array_object
:
179 return new ClientWebGLExtensionVertexArray(*this);
182 case WebGLExtensionID::OVR_multiview2
:
183 return new ClientWebGLExtensionMultiview(*this);
186 case WebGLExtensionID::WEBGL_color_buffer_float
:
187 return new ClientWebGLExtensionColorBufferFloat(*this);
188 case WebGLExtensionID::WEBGL_compressed_texture_astc
:
189 return new ClientWebGLExtensionCompressedTextureASTC(*this);
190 case WebGLExtensionID::WEBGL_compressed_texture_etc
:
191 return new ClientWebGLExtensionCompressedTextureES3(*this);
192 case WebGLExtensionID::WEBGL_compressed_texture_etc1
:
193 return new ClientWebGLExtensionCompressedTextureETC1(*this);
194 case WebGLExtensionID::WEBGL_compressed_texture_pvrtc
:
195 return new ClientWebGLExtensionCompressedTexturePVRTC(*this);
196 case WebGLExtensionID::WEBGL_compressed_texture_s3tc
:
197 return new ClientWebGLExtensionCompressedTextureS3TC(*this);
198 case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb
:
199 return new ClientWebGLExtensionCompressedTextureS3TC_SRGB(*this);
200 case WebGLExtensionID::WEBGL_debug_renderer_info
:
201 return new ClientWebGLExtensionDebugRendererInfo(*this);
202 case WebGLExtensionID::WEBGL_debug_shaders
:
203 return new ClientWebGLExtensionDebugShaders(*this);
204 case WebGLExtensionID::WEBGL_depth_texture
:
205 return new ClientWebGLExtensionDepthTexture(*this);
206 case WebGLExtensionID::WEBGL_draw_buffers
:
207 return new ClientWebGLExtensionDrawBuffers(*this);
208 case WebGLExtensionID::WEBGL_explicit_present
:
209 return new ClientWebGLExtensionExplicitPresent(*this);
211 case WebGLExtensionID::WEBGL_lose_context
:
212 case WebGLExtensionID::Max
:
215 MOZ_CRASH("illegal extension enum");
218 RequestExtension(ext
);
224 // ----------------------------
227 bool WebGLContext::IsExtensionSupported(WebGLExtensionID ext
) const {
229 case WebGLExtensionID::MOZ_debug
:
230 case WebGLExtensionID::WEBGL_debug_renderer_info
:
231 case WebGLExtensionID::WEBGL_debug_shaders
:
232 case WebGLExtensionID::WEBGL_lose_context
:
236 // In alphabetical order
238 case WebGLExtensionID::ANGLE_instanced_arrays
:
239 return WebGLExtensionInstancedArrays::IsSupported(this);
242 case WebGLExtensionID::EXT_blend_minmax
:
243 return WebGLExtensionBlendMinMax::IsSupported(this);
245 case WebGLExtensionID::EXT_color_buffer_float
:
246 return WebGLExtensionEXTColorBufferFloat::IsSupported(this);
248 case WebGLExtensionID::EXT_color_buffer_half_float
:
249 return WebGLExtensionColorBufferHalfFloat::IsSupported(this);
251 case WebGLExtensionID::EXT_disjoint_timer_query
:
252 return WebGLExtensionDisjointTimerQuery::IsSupported(this);
254 case WebGLExtensionID::EXT_float_blend
:
255 return WebGLExtensionFloatBlend::IsSupported(this);
257 case WebGLExtensionID::EXT_frag_depth
:
258 return WebGLExtensionFragDepth::IsSupported(this);
260 case WebGLExtensionID::EXT_shader_texture_lod
:
261 return WebGLExtensionShaderTextureLod::IsSupported(this);
263 case WebGLExtensionID::EXT_sRGB
:
264 return WebGLExtensionSRGB::IsSupported(this);
266 case WebGLExtensionID::EXT_texture_compression_bptc
:
267 return WebGLExtensionCompressedTextureBPTC::IsSupported(this);
269 case WebGLExtensionID::EXT_texture_compression_rgtc
:
270 return WebGLExtensionCompressedTextureRGTC::IsSupported(this);
272 case WebGLExtensionID::EXT_texture_filter_anisotropic
:
273 return gl
->IsExtensionSupported(
274 gl::GLContext::EXT_texture_filter_anisotropic
);
276 case WebGLExtensionID::EXT_texture_norm16
:
277 return WebGLExtensionTextureNorm16::IsSupported(this);
280 case WebGLExtensionID::OES_element_index_uint
:
281 if (IsWebGL2()) return false;
282 return gl
->IsSupported(gl::GLFeature::element_index_uint
);
284 case WebGLExtensionID::OES_fbo_render_mipmap
:
285 return WebGLExtensionFBORenderMipmap::IsSupported(this);
287 case WebGLExtensionID::OES_standard_derivatives
:
288 if (IsWebGL2()) return false;
289 return gl
->IsSupported(gl::GLFeature::standard_derivatives
);
291 case WebGLExtensionID::OES_texture_float
:
292 return WebGLExtensionTextureFloat::IsSupported(this);
294 case WebGLExtensionID::OES_texture_float_linear
:
295 return gl
->IsSupported(gl::GLFeature::texture_float_linear
);
297 case WebGLExtensionID::OES_texture_half_float
:
298 return WebGLExtensionTextureHalfFloat::IsSupported(this);
300 case WebGLExtensionID::OES_texture_half_float_linear
:
301 if (IsWebGL2()) return false;
302 return gl
->IsSupported(gl::GLFeature::texture_half_float_linear
);
304 case WebGLExtensionID::OES_vertex_array_object
:
305 return !IsWebGL2(); // Always supported in webgl1.
308 case WebGLExtensionID::OVR_multiview2
:
309 return WebGLExtensionMultiview::IsSupported(this);
312 case WebGLExtensionID::WEBGL_color_buffer_float
:
313 return WebGLExtensionColorBufferFloat::IsSupported(this);
315 case WebGLExtensionID::WEBGL_compressed_texture_astc
:
316 return WebGLExtensionCompressedTextureASTC::IsSupported(this);
318 case WebGLExtensionID::WEBGL_compressed_texture_etc
:
319 return gl
->IsSupported(gl::GLFeature::ES3_compatibility
) &&
322 case WebGLExtensionID::WEBGL_compressed_texture_etc1
:
323 return gl
->IsExtensionSupported(
324 gl::GLContext::OES_compressed_ETC1_RGB8_texture
) &&
327 case WebGLExtensionID::WEBGL_compressed_texture_pvrtc
:
328 return gl
->IsExtensionSupported(
329 gl::GLContext::IMG_texture_compression_pvrtc
);
331 case WebGLExtensionID::WEBGL_compressed_texture_s3tc
:
332 return WebGLExtensionCompressedTextureS3TC::IsSupported(this);
334 case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb
:
335 return WebGLExtensionCompressedTextureS3TC_SRGB::IsSupported(this);
337 case WebGLExtensionID::WEBGL_depth_texture
:
338 return WebGLExtensionDepthTexture::IsSupported(this);
340 case WebGLExtensionID::WEBGL_draw_buffers
:
341 return WebGLExtensionDrawBuffers::IsSupported(this);
343 case WebGLExtensionID::WEBGL_explicit_present
:
344 return WebGLExtensionExplicitPresent::IsSupported(this);
346 case WebGLExtensionID::Max
:
353 bool WebGLContext::IsExtensionExplicit(const WebGLExtensionID ext
) const {
354 return mExtensions
[ext
] && mExtensions
[ext
]->IsExplicit();
357 void WebGLContext::WarnIfImplicit(const WebGLExtensionID ext
) const {
358 const auto& extension
= mExtensions
[ext
];
359 if (!extension
|| extension
->IsExplicit()) return;
362 "Using format enabled by implicitly enabled extension: %s. "
363 "For maximal portability enable it explicitly.",
364 GetExtensionName(ext
));
367 void WebGLContext::RequestExtension(const WebGLExtensionID ext
,
368 const bool explicitly
) {
369 const auto& limits
= Limits();
370 if (!limits
.supportedExtensions
[ext
]) return;
372 auto& slot
= mExtensions
[ext
];
375 case WebGLExtensionID::ANGLE_instanced_arrays
:
376 slot
.reset(new WebGLExtensionInstancedArrays(this));
380 case WebGLExtensionID::EXT_blend_minmax
:
381 slot
.reset(new WebGLExtensionBlendMinMax(this));
383 case WebGLExtensionID::EXT_color_buffer_float
:
384 slot
.reset(new WebGLExtensionEXTColorBufferFloat(this));
386 case WebGLExtensionID::EXT_color_buffer_half_float
:
387 slot
.reset(new WebGLExtensionColorBufferHalfFloat(this));
389 case WebGLExtensionID::EXT_disjoint_timer_query
:
390 slot
.reset(new WebGLExtensionDisjointTimerQuery(this));
392 case WebGLExtensionID::EXT_float_blend
:
393 slot
.reset(new WebGLExtensionFloatBlend(this));
395 case WebGLExtensionID::EXT_frag_depth
:
396 slot
.reset(new WebGLExtensionFragDepth(this));
398 case WebGLExtensionID::EXT_shader_texture_lod
:
399 slot
.reset(new WebGLExtensionShaderTextureLod(this));
401 case WebGLExtensionID::EXT_sRGB
:
402 slot
.reset(new WebGLExtensionSRGB(this));
404 case WebGLExtensionID::EXT_texture_compression_bptc
:
405 slot
.reset(new WebGLExtensionCompressedTextureBPTC(this));
407 case WebGLExtensionID::EXT_texture_compression_rgtc
:
408 slot
.reset(new WebGLExtensionCompressedTextureRGTC(this));
410 case WebGLExtensionID::EXT_texture_filter_anisotropic
:
411 slot
.reset(new WebGLExtensionTextureFilterAnisotropic(this));
413 case WebGLExtensionID::EXT_texture_norm16
:
414 slot
.reset(new WebGLExtensionTextureNorm16(this));
418 case WebGLExtensionID::MOZ_debug
:
419 slot
.reset(new WebGLExtensionMOZDebug(this));
423 case WebGLExtensionID::OES_element_index_uint
:
424 slot
.reset(new WebGLExtensionElementIndexUint(this));
426 case WebGLExtensionID::OES_fbo_render_mipmap
:
427 slot
.reset(new WebGLExtensionFBORenderMipmap(this));
429 case WebGLExtensionID::OES_standard_derivatives
:
430 slot
.reset(new WebGLExtensionStandardDerivatives(this));
432 case WebGLExtensionID::OES_texture_float
:
433 slot
.reset(new WebGLExtensionTextureFloat(this));
435 case WebGLExtensionID::OES_texture_float_linear
:
436 slot
.reset(new WebGLExtensionTextureFloatLinear(this));
438 case WebGLExtensionID::OES_texture_half_float
:
439 slot
.reset(new WebGLExtensionTextureHalfFloat(this));
441 case WebGLExtensionID::OES_texture_half_float_linear
:
442 slot
.reset(new WebGLExtensionTextureHalfFloatLinear(this));
444 case WebGLExtensionID::OES_vertex_array_object
:
445 slot
.reset(new WebGLExtensionVertexArray(this));
449 case WebGLExtensionID::OVR_multiview2
:
450 slot
.reset(new WebGLExtensionMultiview(this));
454 case WebGLExtensionID::WEBGL_color_buffer_float
:
455 slot
.reset(new WebGLExtensionColorBufferFloat(this));
457 case WebGLExtensionID::WEBGL_compressed_texture_astc
:
458 slot
.reset(new WebGLExtensionCompressedTextureASTC(this));
460 case WebGLExtensionID::WEBGL_compressed_texture_etc
:
461 slot
.reset(new WebGLExtensionCompressedTextureES3(this));
463 case WebGLExtensionID::WEBGL_compressed_texture_etc1
:
464 slot
.reset(new WebGLExtensionCompressedTextureETC1(this));
466 case WebGLExtensionID::WEBGL_compressed_texture_pvrtc
:
467 slot
.reset(new WebGLExtensionCompressedTexturePVRTC(this));
469 case WebGLExtensionID::WEBGL_compressed_texture_s3tc
:
470 slot
.reset(new WebGLExtensionCompressedTextureS3TC(this));
472 case WebGLExtensionID::WEBGL_compressed_texture_s3tc_srgb
:
473 slot
.reset(new WebGLExtensionCompressedTextureS3TC_SRGB(this));
475 case WebGLExtensionID::WEBGL_debug_renderer_info
:
476 slot
.reset(new WebGLExtensionDebugRendererInfo(this));
478 case WebGLExtensionID::WEBGL_debug_shaders
:
479 slot
.reset(new WebGLExtensionDebugShaders(this));
481 case WebGLExtensionID::WEBGL_depth_texture
:
482 slot
.reset(new WebGLExtensionDepthTexture(this));
484 case WebGLExtensionID::WEBGL_draw_buffers
:
485 slot
.reset(new WebGLExtensionDrawBuffers(this));
487 case WebGLExtensionID::WEBGL_explicit_present
:
488 slot
.reset(new WebGLExtensionExplicitPresent(this));
490 case WebGLExtensionID::WEBGL_lose_context
:
491 slot
.reset(new WebGLExtensionLoseContext(this));
494 case WebGLExtensionID::Max
:
498 const auto& obj
= slot
;
500 if (explicitly
&& !obj
->IsExplicit()) {
504 // Also enable implied extensions.
506 case WebGLExtensionID::EXT_color_buffer_float
:
507 RequestExtension(WebGLExtensionID::EXT_float_blend
, false);
510 case WebGLExtensionID::OES_texture_float
:
511 RequestExtension(WebGLExtensionID::EXT_float_blend
, false);
512 RequestExtension(WebGLExtensionID::WEBGL_color_buffer_float
, false);
515 case WebGLExtensionID::OES_texture_half_float
:
516 RequestExtension(WebGLExtensionID::EXT_color_buffer_half_float
, false);
519 case WebGLExtensionID::WEBGL_color_buffer_float
:
520 RequestExtension(WebGLExtensionID::EXT_float_blend
, false);
528 } // namespace mozilla