1use alloc::{borrow::ToOwned as _, format, string::String, sync::Arc, vec, vec::Vec};
2use core::sync::atomic::AtomicU8;
3
4use glow::HasContext;
5use parking_lot::Mutex;
6use wgt::AstcChannel;
7
8use crate::auxil::db;
9use crate::gles::ShaderClearProgram;
10
11const GL_UNMASKED_VENDOR_WEBGL: u32 = 0x9245;
14const GL_UNMASKED_RENDERER_WEBGL: u32 = 0x9246;
15
16impl super::Adapter {
17 pub fn get_glsl_version(&self) -> naga::back::glsl::Version {
18 self.shared.shading_language_version
19 }
20
21 fn parse_version(mut src: &str) -> Result<(u8, u8), crate::InstanceError> {
27 let webgl_sig = "WebGL ";
28 let is_webgl = src.starts_with(webgl_sig);
32 if is_webgl {
33 let pos = src.rfind(webgl_sig).unwrap_or(0);
34 src = &src[pos + webgl_sig.len()..];
35 } else {
36 let es_sig = " ES ";
37 match src.rfind(es_sig) {
38 Some(pos) => {
39 src = &src[pos + es_sig.len()..];
40 }
41 None => {
42 return Err(crate::InstanceError::new(format!(
43 "OpenGL version {src:?} does not contain 'ES'"
44 )));
45 }
46 }
47 };
48
49 let glsl_es_sig = "GLSL ES ";
50 let is_glsl = match src.find(glsl_es_sig) {
51 Some(pos) => {
52 src = &src[pos + glsl_es_sig.len()..];
53 true
54 }
55 None => false,
56 };
57
58 Self::parse_full_version(src).map(|(major, minor)| {
59 (
60 if is_webgl && !is_glsl {
62 major + 1
63 } else {
64 major
65 },
66 minor,
67 )
68 })
69 }
70
71 pub(super) fn parse_full_version(src: &str) -> Result<(u8, u8), crate::InstanceError> {
87 let (version, _vendor_info) = match src.find(' ') {
88 Some(i) => (&src[..i], src[i + 1..].to_owned()),
89 None => (src, String::new()),
90 };
91
92 let mut it = version.split('.');
95 let major = it.next().and_then(|s| s.parse().ok());
96 let minor = it.next().and_then(|s| {
97 let trimmed = if s.starts_with('0') {
98 "0"
99 } else {
100 s.trim_end_matches('0')
101 };
102 trimmed.parse().ok()
103 });
104
105 match (major, minor) {
106 (Some(major), Some(minor)) => Ok((major, minor)),
107 _ => Err(crate::InstanceError::new(format!(
108 "unable to extract OpenGL version from {version:?}"
109 ))),
110 }
111 }
112
113 fn make_info(vendor_orig: String, renderer_orig: String, version: String) -> wgt::AdapterInfo {
114 let vendor = vendor_orig.to_lowercase();
115 let renderer = renderer_orig.to_lowercase();
116
117 let strings_that_imply_integrated = [
119 " xpress", "amd renoir",
121 "radeon hd 4200",
122 "radeon hd 4250",
123 "radeon hd 4290",
124 "radeon hd 4270",
125 "radeon hd 4225",
126 "radeon hd 3100",
127 "radeon hd 3200",
128 "radeon hd 3000",
129 "radeon hd 3300",
130 "radeon(tm) r4 graphics",
131 "radeon(tm) r5 graphics",
132 "radeon(tm) r6 graphics",
133 "radeon(tm) r7 graphics",
134 "radeon r7 graphics",
135 "nforce", "tegra", "shield", "igp",
139 "mali",
140 "intel",
141 "v3d",
142 "apple m", ];
144 let strings_that_imply_cpu = ["mesa offscreen", "swiftshader", "llvmpipe"];
145
146 let inferred_device_type = if vendor.contains("qualcomm")
148 || vendor.contains("intel")
149 || strings_that_imply_integrated
150 .iter()
151 .any(|&s| renderer.contains(s))
152 {
153 wgt::DeviceType::IntegratedGpu
154 } else if strings_that_imply_cpu.iter().any(|&s| renderer.contains(s)) {
155 wgt::DeviceType::Cpu
156 } else {
157 wgt::DeviceType::Other
163 };
164
165 let vendor_id = if vendor.contains("amd") {
167 db::amd::VENDOR
168 } else if vendor.contains("imgtec") {
169 db::imgtec::VENDOR
170 } else if vendor.contains("nvidia") {
171 db::nvidia::VENDOR
172 } else if vendor.contains("arm") {
173 db::arm::VENDOR
174 } else if vendor.contains("qualcomm") {
175 db::qualcomm::VENDOR
176 } else if vendor.contains("intel") {
177 db::intel::VENDOR
178 } else if vendor.contains("broadcom") {
179 db::broadcom::VENDOR
180 } else if vendor.contains("mesa") {
181 db::mesa::VENDOR
182 } else if vendor.contains("apple") {
183 db::apple::VENDOR
184 } else {
185 0
186 };
187
188 wgt::AdapterInfo {
189 name: renderer_orig,
190 vendor: vendor_id,
191 driver_info: version,
192 ..wgt::AdapterInfo::new(inferred_device_type, wgt::Backend::Gl)
193 }
194 }
195
196 pub(super) unsafe fn expose(
197 context: super::AdapterContext,
198 backend_options: wgt::GlBackendOptions,
199 ) -> Option<crate::ExposedAdapter<super::Api>> {
200 let gl = context.lock();
201 let extensions = gl.supported_extensions();
202
203 let (vendor_const, renderer_const) = if extensions.contains("WEBGL_debug_renderer_info") {
204 #[cfg(Emscripten)]
207 if unsafe {
208 super::emscripten::enable_extension(c"WEBGL_debug_renderer_info".to_str().unwrap())
209 } {
210 (GL_UNMASKED_VENDOR_WEBGL, GL_UNMASKED_RENDERER_WEBGL)
211 } else {
212 (glow::VENDOR, glow::RENDERER)
213 }
214 #[cfg(not(Emscripten))]
216 (GL_UNMASKED_VENDOR_WEBGL, GL_UNMASKED_RENDERER_WEBGL)
217 } else {
218 (glow::VENDOR, glow::RENDERER)
219 };
220
221 let vendor = unsafe { gl.get_parameter_string(vendor_const) };
222 let renderer = unsafe { gl.get_parameter_string(renderer_const) };
223 let version = unsafe { gl.get_parameter_string(glow::VERSION) };
224 log::debug!("Vendor: {vendor}");
225 log::debug!("Renderer: {renderer}");
226 log::debug!("Version: {version}");
227
228 let full_ver = Self::parse_full_version(&version).ok();
229 let es_ver = full_ver.map_or_else(|| Self::parse_version(&version).ok(), |_| None);
230
231 if let Some(full_ver) = full_ver {
232 let core_profile = (full_ver >= (3, 2)).then(|| unsafe {
233 gl.get_parameter_i32(glow::CONTEXT_PROFILE_MASK)
234 & glow::CONTEXT_CORE_PROFILE_BIT as i32
235 != 0
236 });
237 log::trace!(
238 "Profile: {}",
239 core_profile
240 .map(|core_profile| if core_profile {
241 "Core"
242 } else {
243 "Compatibility"
244 })
245 .unwrap_or("Legacy")
246 );
247 }
248
249 if es_ver.is_none() && full_ver.is_none() {
250 log::warn!("Unable to parse OpenGL version");
251 return None;
252 }
253
254 if let Some(es_ver) = es_ver {
255 if es_ver < (3, 0) {
256 log::warn!(
257 "Returned GLES context is {}.{}, when 3.0+ was requested",
258 es_ver.0,
259 es_ver.1
260 );
261 return None;
262 }
263 }
264
265 if let Some(full_ver) = full_ver {
266 if full_ver < (3, 3) {
267 log::warn!(
268 "Returned GL context is {}.{}, when 3.3+ is needed",
269 full_ver.0,
270 full_ver.1
271 );
272 return None;
273 }
274 }
275
276 let shading_language_version = {
277 let sl_version = unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
278 log::debug!("SL version: {}", &sl_version);
279 if full_ver.is_some() {
280 let (sl_major, sl_minor) = Self::parse_full_version(&sl_version).ok()?;
281 let mut value = sl_major as u16 * 100 + sl_minor as u16 * 10;
282 if value > 450 {
284 value = 450;
285 }
286 naga::back::glsl::Version::Desktop(value)
287 } else {
288 let (sl_major, sl_minor) = Self::parse_version(&sl_version).ok()?;
289 let value = sl_major as u16 * 100 + sl_minor as u16 * 10;
290 naga::back::glsl::Version::Embedded {
291 version: value,
292 is_webgl: cfg!(any(webgl, Emscripten)),
293 }
294 }
295 };
296
297 log::debug!("Supported GL Extensions: {extensions:#?}");
298
299 let supported = |(req_es_major, req_es_minor), (req_full_major, req_full_minor)| {
300 let es_supported = es_ver
301 .map(|es_ver| es_ver >= (req_es_major, req_es_minor))
302 .unwrap_or_default();
303
304 let full_supported = full_ver
305 .map(|full_ver| full_ver >= (req_full_major, req_full_minor))
306 .unwrap_or_default();
307
308 es_supported || full_supported
309 };
310
311 let supports_storage =
312 supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_shader_storage_buffer_object");
313 let supports_compute =
314 supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_compute_shader");
315 let supports_work_group_params = supports_compute;
316
317 let is_angle = renderer.contains("ANGLE");
319
320 let vertex_shader_storage_blocks = if supports_storage {
321 let value =
322 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) } as u32);
323
324 if value == 0 && extensions.contains("GL_ARB_shader_storage_buffer_object") {
325 let new = (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_SHADER_STORAGE_BLOCKS) }
328 as u32);
329 log::debug!("Max vertex shader storage blocks is zero, but GL_ARB_shader_storage_buffer_object is specified. Assuming the compute value {new}");
330 new
331 } else {
332 value
333 }
334 } else {
335 0
336 };
337 let fragment_shader_storage_blocks = if supports_storage {
338 (unsafe { gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS) } as u32)
339 } else {
340 0
341 };
342 let vertex_shader_storage_textures = if supports_storage {
343 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_IMAGE_UNIFORMS) } as u32)
344 } else {
345 0
346 };
347 let fragment_shader_storage_textures = if supports_storage {
348 (unsafe { gl.get_parameter_i32(glow::MAX_FRAGMENT_IMAGE_UNIFORMS) } as u32)
349 } else {
350 0
351 };
352 let max_storage_block_size = if supports_storage {
353 (unsafe { gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) } as u32)
354 } else {
355 0
356 };
357 let max_element_index = unsafe { gl.get_parameter_i32(glow::MAX_ELEMENT_INDEX) } as u32;
358
359 let vertex_ssbo_false_zero =
365 vertex_shader_storage_blocks == 0 && vertex_shader_storage_textures != 0;
366 if vertex_ssbo_false_zero {
367 log::debug!("Max vertex shader SSBO == 0 and SSTO != 0. Interpreting as false zero.");
369 }
370
371 let max_storage_buffers_per_shader_stage = if vertex_shader_storage_blocks == 0 {
372 fragment_shader_storage_blocks
373 } else {
374 vertex_shader_storage_blocks.min(fragment_shader_storage_blocks)
375 };
376 let max_storage_textures_per_shader_stage = if vertex_shader_storage_textures == 0 {
377 fragment_shader_storage_textures
378 } else {
379 vertex_shader_storage_textures.min(fragment_shader_storage_textures)
380 };
381 let indirect_execution = supported((3, 1), (4, 3))
383 || (extensions.contains("GL_ARB_draw_indirect") && supports_compute);
384 let supports_cube_array = supported((3, 2), (4, 0))
385 || (supported((3, 1), (4, 0)) && extensions.contains("GL_EXT_texture_cube_map_array"));
386
387 let mut downlevel_flags = wgt::DownlevelFlags::empty()
388 | wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
389 | wgt::DownlevelFlags::COMPARISON_SAMPLERS
390 | wgt::DownlevelFlags::SHADER_F16_IN_F32
391 | wgt::DownlevelFlags::MSL2_1;
392 downlevel_flags.set(
393 wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES,
394 supports_cube_array,
395 );
396 downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, supports_compute);
397 downlevel_flags.set(
398 wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE,
399 max_storage_block_size != 0,
400 );
401 downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, indirect_execution);
402 downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, supported((3, 2), (3, 2)));
403 downlevel_flags.set(
404 wgt::DownlevelFlags::INDEPENDENT_BLEND,
405 supported((3, 2), (4, 0)) || extensions.contains("GL_EXT_draw_buffers_indexed"),
406 );
407 downlevel_flags.set(
408 wgt::DownlevelFlags::VERTEX_STORAGE,
409 max_storage_block_size != 0
410 && max_storage_buffers_per_shader_stage != 0
411 && (vertex_shader_storage_blocks != 0 || vertex_ssbo_false_zero),
412 );
413 downlevel_flags.set(wgt::DownlevelFlags::FRAGMENT_STORAGE, supports_storage);
414 if extensions.contains("EXT_texture_filter_anisotropic")
415 || extensions.contains("GL_EXT_texture_filter_anisotropic")
416 {
417 let max_aniso =
418 unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_MAX_ANISOTROPY_EXT) } as u32;
419 downlevel_flags.set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, max_aniso >= 16);
420 }
421 downlevel_flags.set(
422 wgt::DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED,
423 !(cfg!(any(webgl, Emscripten)) || is_angle),
424 );
425 downlevel_flags.set(
427 wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER,
428 !cfg!(any(webgl, Emscripten)),
429 );
430 downlevel_flags.set(
431 wgt::DownlevelFlags::UNRESTRICTED_EXTERNAL_TEXTURE_COPIES,
432 !cfg!(any(webgl, Emscripten)),
433 );
434 downlevel_flags.set(
435 wgt::DownlevelFlags::FULL_DRAW_INDEX_UINT32,
436 max_element_index == u32::MAX,
437 );
438 downlevel_flags.set(
439 wgt::DownlevelFlags::MULTISAMPLED_SHADING,
440 supported((3, 2), (4, 0)) || extensions.contains("OES_sample_variables"),
441 );
442 let query_buffers = extensions.contains("GL_ARB_query_buffer_object")
443 || extensions.contains("GL_AMD_query_buffer_object");
444 if query_buffers {
445 downlevel_flags.set(wgt::DownlevelFlags::NONBLOCKING_QUERY_RESOLVE, true);
446 }
447
448 let supports_16bit_norm = if es_ver.is_some() {
451 extensions.contains("GL_EXT_texture_norm16")
452 || extensions.contains("EXT_texture_norm16")
453 } else {
454 true
455 };
456 let supports_16bit_snorm_renderable = supports_16bit_norm
462 && (extensions.contains("GL_EXT_render_snorm")
463 || extensions.contains("EXT_render_snorm"));
464 let supports_16bit_norm_storage = supports_16bit_norm
476 && if es_ver.is_some() {
477 extensions.contains("GL_NV_image_formats")
478 } else {
479 full_ver.is_some_and(|v| v >= (4, 2))
480 || extensions.contains("GL_ARB_shader_image_load_store")
481 };
482
483 let mut features = wgt::Features::empty()
484 | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
485 | wgt::Features::CLEAR_TEXTURE
486 | wgt::Features::IMMEDIATES
487 | wgt::Features::DEPTH32FLOAT_STENCIL8
488 | wgt::Features::PASSTHROUGH_SHADERS;
489 features.set(
490 wgt::Features::TEXTURE_FORMAT_16BIT_NORM,
491 supports_16bit_norm,
492 );
493 features.set(
494 wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER | wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO,
495 extensions.contains("GL_EXT_texture_border_clamp")
496 || extensions.contains("GL_ARB_texture_border_clamp"),
497 );
498 features.set(
499 wgt::Features::DEPTH_CLIP_CONTROL,
500 extensions.contains("GL_EXT_depth_clamp") || extensions.contains("GL_ARB_depth_clamp"),
501 );
502 features.set(
503 wgt::Features::VERTEX_WRITABLE_STORAGE,
504 downlevel_flags.contains(wgt::DownlevelFlags::VERTEX_STORAGE)
505 && vertex_shader_storage_textures != 0,
506 );
507 features.set(
508 wgt::Features::MULTIVIEW,
509 extensions.contains("OVR_multiview2") || extensions.contains("GL_OVR_multiview2"),
510 );
511 features.set(
512 wgt::Features::DUAL_SOURCE_BLENDING,
513 extensions.contains("GL_EXT_blend_func_extended")
514 || extensions.contains("GL_ARB_blend_func_extended"),
515 );
516 features.set(
517 wgt::Features::CLIP_DISTANCES,
518 full_ver.is_some() || extensions.contains("GL_EXT_clip_cull_distance"),
519 );
520 features.set(
521 wgt::Features::PRIMITIVE_INDEX,
522 supported((3, 2), (3, 2))
523 || extensions.contains("OES_geometry_shader")
524 || extensions.contains("GL_ARB_geometry_shader4"),
525 );
526 features.set(
527 wgt::Features::SHADER_EARLY_DEPTH_TEST,
528 supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
529 );
530 if extensions.contains("GL_ARB_timer_query") {
531 features.set(wgt::Features::TIMESTAMP_QUERY, true);
532 features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);
533 features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES, true);
534 }
535 let gl_bcn_exts = [
536 "GL_EXT_texture_compression_s3tc",
537 "GL_EXT_texture_compression_rgtc",
538 "GL_ARB_texture_compression_bptc",
539 ];
540 let gles_bcn_exts = [
541 "GL_EXT_texture_compression_s3tc_srgb",
542 "GL_EXT_texture_compression_rgtc",
543 "GL_EXT_texture_compression_bptc",
544 ];
545 let webgl_bcn_exts = [
546 "WEBGL_compressed_texture_s3tc",
547 "WEBGL_compressed_texture_s3tc_srgb",
548 "EXT_texture_compression_rgtc",
549 "EXT_texture_compression_bptc",
550 ];
551 let bcn_exts = if cfg!(any(webgl, Emscripten)) {
552 &webgl_bcn_exts[..]
553 } else if es_ver.is_some() {
554 &gles_bcn_exts[..]
555 } else {
556 &gl_bcn_exts[..]
557 };
558 features.set(
559 wgt::Features::TEXTURE_COMPRESSION_BC,
560 bcn_exts.iter().all(|&ext| extensions.contains(ext)),
561 );
562 features.set(
563 wgt::Features::TEXTURE_COMPRESSION_BC_SLICED_3D,
564 bcn_exts.iter().all(|&ext| extensions.contains(ext)), );
566 let has_etc = if cfg!(any(webgl, Emscripten)) {
567 extensions.contains("WEBGL_compressed_texture_etc")
568 } else {
569 es_ver.is_some() || extensions.contains("GL_ARB_ES3_compatibility")
570 };
571 features.set(wgt::Features::TEXTURE_COMPRESSION_ETC2, has_etc);
572
573 if extensions.contains("WEBGL_compressed_texture_astc")
575 || extensions.contains("GL_OES_texture_compression_astc")
576 {
577 #[cfg(webgl)]
578 {
579 if context
580 .glow_context
581 .compressed_texture_astc_supports_ldr_profile()
582 {
583 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC);
584 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D);
585 }
586 if context
587 .glow_context
588 .compressed_texture_astc_supports_hdr_profile()
589 {
590 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR);
591 }
592 }
593
594 #[cfg(any(native, Emscripten))]
595 {
596 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC);
597 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D);
598 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR);
599 }
600 } else {
601 features.set(
602 wgt::Features::TEXTURE_COMPRESSION_ASTC,
603 extensions.contains("GL_KHR_texture_compression_astc_ldr"),
604 );
605 features.set(
606 wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D,
607 extensions.contains("GL_KHR_texture_compression_astc_ldr")
608 && extensions.contains("GL_KHR_texture_compression_astc_sliced_3d"),
609 );
610 features.set(
611 wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR,
612 extensions.contains("GL_KHR_texture_compression_astc_hdr"),
613 );
614 }
615
616 downlevel_flags.set(
617 wgt::DownlevelFlags::TEXTURE_COMPRESSION,
618 features.contains(wgt::Features::TEXTURE_COMPRESSION_BC)
619 || features.contains(
620 wgt::Features::TEXTURE_COMPRESSION_ETC2
621 | wgt::Features::TEXTURE_COMPRESSION_ASTC,
622 ),
623 );
624
625 features.set(
626 wgt::Features::FLOAT32_FILTERABLE,
627 extensions.contains("GL_ARB_color_buffer_float")
628 || extensions.contains("GL_EXT_color_buffer_float")
629 || extensions.contains("OES_texture_float_linear"),
630 );
631
632 if es_ver.is_none() {
633 features |= wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT;
634 }
635
636 let mut private_caps = super::PrivateCapabilities::empty();
639 private_caps.set(
640 super::PrivateCapabilities::BUFFER_ALLOCATION,
641 extensions.contains("GL_EXT_buffer_storage")
642 || extensions.contains("GL_ARB_buffer_storage"),
643 );
644 private_caps.set(
645 super::PrivateCapabilities::SHADER_BINDING_LAYOUT,
646 supports_compute,
647 );
648 private_caps.set(
649 super::PrivateCapabilities::SHADER_TEXTURE_SHADOW_LOD,
650 extensions.contains("GL_EXT_texture_shadow_lod"),
651 );
652 private_caps.set(
653 super::PrivateCapabilities::MEMORY_BARRIERS,
654 supported((3, 1), (4, 2)),
655 );
656 private_caps.set(
657 super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT,
658 supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_vertex_attrib_binding"),
659 );
660 private_caps.set(
661 super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE,
662 !cfg!(any(webgl, Emscripten)),
663 );
664 private_caps.set(
665 super::PrivateCapabilities::GET_BUFFER_SUB_DATA,
666 cfg!(any(webgl, Emscripten)) || full_ver.is_some(),
667 );
668 let color_buffer_float = extensions.contains("GL_EXT_color_buffer_float")
669 || extensions.contains("GL_ARB_color_buffer_float")
670 || extensions.contains("EXT_color_buffer_float");
671 let color_buffer_half_float = extensions.contains("GL_EXT_color_buffer_half_float")
672 || extensions.contains("GL_ARB_half_float_pixel");
673 private_caps.set(
674 super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT,
675 color_buffer_half_float || color_buffer_float,
676 );
677 private_caps.set(
678 super::PrivateCapabilities::COLOR_BUFFER_FLOAT,
679 color_buffer_float,
680 );
681 private_caps.set(super::PrivateCapabilities::QUERY_BUFFERS, query_buffers);
682 private_caps.set(super::PrivateCapabilities::QUERY_64BIT, full_ver.is_some());
683 private_caps.set(
684 super::PrivateCapabilities::TEXTURE_STORAGE,
685 supported((3, 0), (4, 2)),
686 );
687 let is_mali = renderer.to_lowercase().contains("mali");
688 let debug_fns_enabled = match backend_options.debug_fns {
689 wgt::GlDebugFns::Auto => gl.supports_debug() && !is_mali,
690 wgt::GlDebugFns::ForceEnabled => gl.supports_debug(),
691 wgt::GlDebugFns::Disabled => false,
692 };
693 private_caps.set(super::PrivateCapabilities::DEBUG_FNS, debug_fns_enabled);
694 private_caps.set(
695 super::PrivateCapabilities::INVALIDATE_FRAMEBUFFER,
696 supported((3, 0), (4, 3)),
697 );
698 if let Some(full_ver) = full_ver {
699 let supported =
700 full_ver >= (4, 2) && extensions.contains("GL_ARB_shader_draw_parameters");
701 private_caps.set(
702 super::PrivateCapabilities::FULLY_FEATURED_INSTANCING,
703 supported,
704 );
705 features.set(wgt::Features::INDIRECT_FIRST_INSTANCE, supported);
712 }
713 private_caps.set(
714 super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE,
715 extensions.contains("GL_EXT_multisampled_render_to_texture"),
716 );
717 private_caps.set(
718 super::PrivateCapabilities::TEXTURE_FORMAT_NORM16,
719 supports_16bit_norm,
720 );
721 private_caps.set(
722 super::PrivateCapabilities::TEXTURE_FORMAT_SNORM16_RENDERABLE,
723 supports_16bit_snorm_renderable,
724 );
725 private_caps.set(
726 super::PrivateCapabilities::TEXTURE_FORMAT_NORM16_STORAGE,
727 supports_16bit_norm_storage,
728 );
729
730 if supports_storage {
733 features |= wgt::Features::MEMORY_DECORATION_COHERENT
734 | wgt::Features::MEMORY_DECORATION_VOLATILE;
735 }
736
737 let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32;
738 let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32;
739
740 let min_uniform_buffer_offset_alignment =
741 (unsafe { gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT) } as u32);
742 let min_storage_buffer_offset_alignment = if supports_storage {
743 (unsafe { gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) } as u32)
744 } else {
745 256
746 };
747 let max_uniform_buffers_per_shader_stage =
748 unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS) }
749 .min(unsafe { gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS) })
750 as u32;
751
752 let max_compute_workgroups_per_dimension = if supports_work_group_params {
753 unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 0) }
754 .min(unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 1) })
755 .min(unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 2) })
756 as u32
757 } else {
758 0
759 };
760
761 let max_color_attachments = unsafe {
762 gl.get_parameter_i32(glow::MAX_COLOR_ATTACHMENTS)
763 .min(gl.get_parameter_i32(glow::MAX_DRAW_BUFFERS)) as u32
764 };
765
766 let max_color_attachment_bytes_per_sample =
768 max_color_attachments * wgt::TextureFormat::MAX_TARGET_PIXEL_BYTE_COST;
769
770 let limits = crate::auxil::adjust_raw_limits(wgt::Limits {
771 max_texture_dimension_1d: max_texture_size,
772 max_texture_dimension_2d: max_texture_size,
773 max_texture_dimension_3d: max_texture_3d_size,
774 max_texture_array_layers: unsafe {
775 gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS)
776 } as u32,
777 max_bind_groups: u32::MAX,
778 max_bind_groups_plus_vertex_buffers: u32::MAX,
780 max_bindings_per_bind_group: u32::MAX,
782 max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage,
783 max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage,
784 max_sampled_textures_per_shader_stage: super::MAX_TEXTURE_SLOTS as u32,
785 max_samplers_per_shader_stage: super::MAX_SAMPLERS as u32,
786 max_storage_buffers_per_shader_stage,
787 max_storage_textures_per_shader_stage,
788 max_uniform_buffers_per_shader_stage,
789 max_binding_array_elements_per_shader_stage: 0,
790 max_binding_array_sampler_elements_per_shader_stage: 0,
791 max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
792 max_uniform_buffer_binding_size: unsafe {
793 gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
794 } as u64,
795 max_storage_buffer_binding_size: if supports_storage {
796 unsafe { gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) }
797 } else {
798 0
799 } as u64,
800 max_vertex_buffers: if private_caps
801 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
802 {
803 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) } as u32)
804 } else {
805 16 },
807 max_vertex_attributes: (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) }
808 as u32)
809 .min(super::MAX_VERTEX_ATTRIBUTES as u32),
810 max_vertex_buffer_array_stride: if private_caps
811 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
812 {
813 if let Some(full_ver) = full_ver {
814 if full_ver >= (4, 4) {
815 let value =
817 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) })
818 as u32;
819
820 if value == 0 {
821 log::debug!("Max vertex attribute stride is 0. Assuming it is the OpenGL minimum spec 2048");
825 2048
826 } else {
827 value
828 }
829 } else {
830 log::debug!("Max vertex attribute stride unknown. Assuming it is the OpenGL minimum spec 2048");
831 2048
832 }
833 } else {
834 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) }) as u32
835 }
836 } else {
837 !0
838 },
839 max_immediate_size: super::MAX_IMMEDIATES as u32 * 4,
840 min_uniform_buffer_offset_alignment,
841 min_storage_buffer_offset_alignment,
842 max_inter_stage_shader_variables: {
843 let max_varying_components =
847 unsafe { gl.get_parameter_i32(glow::MAX_VARYING_COMPONENTS) } as u32;
848 if max_varying_components == 0 {
849 15
851 } else {
852 max_varying_components / 4
853 }
854 },
855 max_color_attachments,
856 max_color_attachment_bytes_per_sample,
857 max_compute_workgroup_storage_size: if supports_work_group_params {
858 (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_SHARED_MEMORY_SIZE) } as u32)
859 } else {
860 0
861 },
862 max_compute_invocations_per_workgroup: if supports_work_group_params {
863 (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_WORK_GROUP_INVOCATIONS) } as u32)
864 } else {
865 0
866 },
867 max_compute_workgroup_size_x: if supports_work_group_params {
868 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 0) }
869 as u32)
870 } else {
871 0
872 },
873 max_compute_workgroup_size_y: if supports_work_group_params {
874 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 1) }
875 as u32)
876 } else {
877 0
878 },
879 max_compute_workgroup_size_z: if supports_work_group_params {
880 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 2) }
881 as u32)
882 } else {
883 0
884 },
885 max_compute_workgroups_per_dimension,
886 max_buffer_size: i32::MAX as u64,
887 max_non_sampler_bindings: u32::MAX,
888
889 max_task_workgroup_total_count: 0,
890 max_task_workgroups_per_dimension: 0,
891 max_mesh_workgroup_total_count: 0,
892 max_mesh_workgroups_per_dimension: 0,
893 max_task_invocations_per_workgroup: 0,
894 max_task_invocations_per_dimension: 0,
895 max_mesh_invocations_per_workgroup: 0,
896 max_mesh_invocations_per_dimension: 0,
897 max_task_payload_size: 0,
898 max_mesh_output_vertices: 0,
899 max_mesh_output_primitives: 0,
900 max_mesh_output_layers: 0,
901 max_mesh_multiview_view_count: 0,
902
903 max_blas_primitive_count: 0,
904 max_blas_geometry_count: 0,
905 max_tlas_instance_count: 0,
906 max_acceleration_structures_per_shader_stage: 0,
907
908 max_multiview_view_count: 0,
909 });
910
911 let mut workarounds = super::Workarounds::empty();
912
913 workarounds.set(
914 super::Workarounds::EMULATE_BUFFER_MAP,
915 cfg!(any(webgl, Emscripten)),
916 );
917
918 let r = renderer.to_lowercase();
919 if context.is_owned()
922 && r.contains("mesa")
923 && r.contains("intel")
924 && r.split(&[' ', '(', ')'][..])
925 .any(|substr| substr.len() == 3 && substr.chars().nth(2) == Some('l'))
926 {
927 log::debug!(
928 "Detected skylake derivative running on mesa i915. Clears to srgb textures will \
929 use manual shader clears."
930 );
931 workarounds.set(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR, true);
932 }
933
934 let downlevel_defaults = wgt::DownlevelLimits {};
935 let max_samples = unsafe { gl.get_parameter_i32(glow::MAX_SAMPLES) };
936
937 #[cfg_attr(target_arch = "wasm32", allow(dropping_references))]
941 drop(gl);
942
943 Some(crate::ExposedAdapter {
944 adapter: super::Adapter {
945 shared: Arc::new(super::AdapterShared {
946 context,
947 private_caps,
948 workarounds,
949 features,
950 limits: limits.clone(),
951 options: backend_options,
952 shading_language_version,
953 next_shader_id: Default::default(),
954 program_cache: Default::default(),
955 es: es_ver.is_some(),
956 max_msaa_samples: max_samples,
957 }),
958 },
959 info: Self::make_info(vendor, renderer, version),
960 features,
961 capabilities: crate::Capabilities {
962 limits,
963 downlevel: wgt::DownlevelCapabilities {
964 flags: downlevel_flags,
965 limits: downlevel_defaults,
966 shader_model: wgt::ShaderModel::Sm5,
967 },
968 alignments: crate::Alignments {
969 buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
970 buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
971 uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
981 raw_tlas_instance_size: 0,
982 ray_tracing_scratch_buffer_alignment: 0,
983 },
984 cooperative_matrix_properties: Vec::new(),
985 },
986 })
987 }
988
989 unsafe fn compile_shader(
990 source: &str,
991 gl: &glow::Context,
992 shader_type: u32,
993 es: bool,
994 ) -> Option<glow::Shader> {
995 let source = if es {
996 format!("#version 300 es\nprecision lowp float;\n{source}")
997 } else {
998 let version = gl.version();
999 if version.major == 3 && version.minor == 0 {
1000 format!("#version 130\n{source}")
1002 } else {
1003 format!("#version 140\n{source}")
1005 }
1006 };
1007 let shader = unsafe { gl.create_shader(shader_type) }.expect("Could not create shader");
1008 unsafe { gl.shader_source(shader, &source) };
1009 unsafe { gl.compile_shader(shader) };
1010
1011 if !unsafe { gl.get_shader_compile_status(shader) } {
1012 let msg = unsafe { gl.get_shader_info_log(shader) };
1013 if !msg.is_empty() {
1014 log::error!("\tShader compile error: {msg}");
1015 }
1016 unsafe { gl.delete_shader(shader) };
1017 None
1018 } else {
1019 Some(shader)
1020 }
1021 }
1022
1023 unsafe fn create_shader_clear_program(
1024 gl: &glow::Context,
1025 es: bool,
1026 ) -> Option<ShaderClearProgram> {
1027 let program = unsafe { gl.create_program() }.expect("Could not create shader program");
1028 let vertex = unsafe {
1029 Self::compile_shader(
1030 include_str!("./shaders/clear.vert"),
1031 gl,
1032 glow::VERTEX_SHADER,
1033 es,
1034 )?
1035 };
1036 let fragment = unsafe {
1037 Self::compile_shader(
1038 include_str!("./shaders/clear.frag"),
1039 gl,
1040 glow::FRAGMENT_SHADER,
1041 es,
1042 )?
1043 };
1044 unsafe { gl.attach_shader(program, vertex) };
1045 unsafe { gl.attach_shader(program, fragment) };
1046 unsafe { gl.link_program(program) };
1047
1048 let linked_ok = unsafe { gl.get_program_link_status(program) };
1049 let msg = unsafe { gl.get_program_info_log(program) };
1050 if !msg.is_empty() {
1051 log::error!("Shader link error: {msg}");
1052 }
1053 if !linked_ok {
1054 return None;
1055 }
1056
1057 let color_uniform_location = unsafe { gl.get_uniform_location(program, "color") }
1058 .expect("Could not find color uniform in shader clear shader");
1059 unsafe { gl.delete_shader(vertex) };
1060 unsafe { gl.delete_shader(fragment) };
1061
1062 Some(ShaderClearProgram {
1063 program,
1064 color_uniform_location,
1065 })
1066 }
1067}
1068
1069impl crate::Adapter for super::Adapter {
1070 type A = super::Api;
1071
1072 unsafe fn open(
1073 &self,
1074 features: wgt::Features,
1075 _limits: &wgt::Limits,
1076 _memory_hints: &wgt::MemoryHints,
1077 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1078 let gl = &self.shared.context.lock();
1079 unsafe { gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1) };
1080 unsafe { gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1) };
1081 let main_vao =
1082 unsafe { gl.create_vertex_array() }.map_err(|_| crate::DeviceError::OutOfMemory)?;
1083 unsafe { gl.bind_vertex_array(Some(main_vao)) };
1084
1085 let zero_buffer =
1086 unsafe { gl.create_buffer() }.map_err(|_| crate::DeviceError::OutOfMemory)?;
1087 unsafe { gl.bind_buffer(glow::COPY_READ_BUFFER, Some(zero_buffer)) };
1088 let zeroes = vec![0u8; super::ZERO_BUFFER_SIZE];
1089 unsafe { gl.buffer_data_u8_slice(glow::COPY_READ_BUFFER, &zeroes, glow::STATIC_DRAW) };
1090
1091 let shader_clear_program = if self
1095 .shared
1096 .workarounds
1097 .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1098 {
1099 Some(unsafe {
1100 Self::create_shader_clear_program(gl, self.shared.es)
1101 .ok_or(crate::DeviceError::Lost)?
1102 })
1103 } else {
1104 None
1106 };
1107
1108 Ok(crate::OpenDevice {
1109 device: super::Device {
1110 shared: Arc::clone(&self.shared),
1111 main_vao,
1112 #[cfg(all(native, feature = "renderdoc"))]
1113 render_doc: Default::default(),
1114 counters: Default::default(),
1115 },
1116 queue: super::Queue {
1117 shared: Arc::clone(&self.shared),
1118 features,
1119 draw_fbo: unsafe { gl.create_framebuffer() }
1120 .map_err(|_| crate::DeviceError::OutOfMemory)?,
1121 copy_fbo: unsafe { gl.create_framebuffer() }
1122 .map_err(|_| crate::DeviceError::OutOfMemory)?,
1123 shader_clear_program,
1124 zero_buffer,
1125 temp_query_results: Mutex::new(Vec::new()),
1126 draw_buffer_count: AtomicU8::new(1),
1127 current_index_buffer: Mutex::new(None),
1128 },
1129 })
1130 }
1131
1132 unsafe fn texture_format_capabilities(
1133 &self,
1134 format: wgt::TextureFormat,
1135 ) -> crate::TextureFormatCapabilities {
1136 use crate::TextureFormatCapabilities as Tfc;
1137 use wgt::TextureFormat as Tf;
1138
1139 let sample_count = {
1140 let max_samples = self.shared.max_msaa_samples;
1141 if max_samples >= 16 {
1142 Tfc::MULTISAMPLE_X2
1143 | Tfc::MULTISAMPLE_X4
1144 | Tfc::MULTISAMPLE_X8
1145 | Tfc::MULTISAMPLE_X16
1146 } else if max_samples >= 8 {
1147 Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4 | Tfc::MULTISAMPLE_X8
1148 } else {
1149 Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4
1154 }
1155 };
1156
1157 let empty = Tfc::empty();
1162 let base = Tfc::COPY_SRC | Tfc::COPY_DST;
1163 let unfilterable = base | Tfc::SAMPLED;
1164 let depth = base | Tfc::SAMPLED | sample_count | Tfc::DEPTH_STENCIL_ATTACHMENT;
1165 let filterable = unfilterable | Tfc::SAMPLED_LINEAR;
1166 let renderable =
1167 unfilterable | Tfc::COLOR_ATTACHMENT | sample_count | Tfc::MULTISAMPLE_RESOLVE;
1168 let filterable_renderable = filterable | renderable | Tfc::COLOR_ATTACHMENT_BLEND;
1169 let storage =
1170 base | Tfc::STORAGE_READ_WRITE | Tfc::STORAGE_READ_ONLY | Tfc::STORAGE_WRITE_ONLY;
1171
1172 let feature_fn = |f, caps| {
1173 if self.shared.features.contains(f) {
1174 caps
1175 } else {
1176 empty
1177 }
1178 };
1179
1180 let bcn_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_BC, filterable);
1181 let etc2_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ETC2, filterable);
1182 let astc_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ASTC, filterable);
1183 let astc_hdr_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR, filterable);
1184
1185 let private_caps_fn = |f, caps| {
1186 if self.shared.private_caps.contains(f) {
1187 caps
1188 } else {
1189 empty
1190 }
1191 };
1192
1193 let half_float_renderable = private_caps_fn(
1194 super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT,
1195 Tfc::COLOR_ATTACHMENT
1196 | Tfc::COLOR_ATTACHMENT_BLEND
1197 | sample_count
1198 | Tfc::MULTISAMPLE_RESOLVE,
1199 );
1200
1201 let float_renderable = private_caps_fn(
1202 super::PrivateCapabilities::COLOR_BUFFER_FLOAT,
1203 Tfc::COLOR_ATTACHMENT
1204 | Tfc::COLOR_ATTACHMENT_BLEND
1205 | sample_count
1206 | Tfc::MULTISAMPLE_RESOLVE,
1207 );
1208
1209 let texture_float_linear = feature_fn(wgt::Features::FLOAT32_FILTERABLE, filterable);
1210
1211 let image_atomic = feature_fn(wgt::Features::TEXTURE_ATOMIC, Tfc::STORAGE_ATOMIC);
1212 let image_64_atomic = feature_fn(wgt::Features::TEXTURE_INT64_ATOMIC, Tfc::STORAGE_ATOMIC);
1213
1214 let norm16_unorm = private_caps_fn(
1219 super::PrivateCapabilities::TEXTURE_FORMAT_NORM16,
1220 filterable_renderable,
1221 );
1222 let norm16_snorm = if self
1223 .shared
1224 .private_caps
1225 .contains(super::PrivateCapabilities::TEXTURE_FORMAT_SNORM16_RENDERABLE)
1226 {
1227 norm16_unorm
1228 } else {
1229 private_caps_fn(
1230 super::PrivateCapabilities::TEXTURE_FORMAT_NORM16,
1231 filterable,
1232 )
1233 };
1234 let norm16_storage = private_caps_fn(
1235 super::PrivateCapabilities::TEXTURE_FORMAT_NORM16_STORAGE,
1236 storage,
1237 );
1238
1239 match format {
1240 Tf::R8Unorm => filterable_renderable,
1241 Tf::R8Snorm => filterable,
1242 Tf::R8Uint => renderable,
1243 Tf::R8Sint => renderable,
1244 Tf::R16Uint => renderable,
1245 Tf::R16Sint => renderable,
1246 Tf::R16Unorm => norm16_unorm | norm16_storage,
1247 Tf::R16Snorm => norm16_snorm | norm16_storage,
1248 Tf::R16Float => filterable | half_float_renderable,
1249 Tf::Rg8Unorm => filterable_renderable,
1250 Tf::Rg8Snorm => filterable,
1251 Tf::Rg8Uint => renderable,
1252 Tf::Rg8Sint => renderable,
1253 Tf::R32Uint => renderable | storage | image_atomic,
1254 Tf::R32Sint => renderable | storage | image_atomic,
1255 Tf::R32Float => unfilterable | storage | float_renderable | texture_float_linear,
1256 Tf::Rg16Uint => renderable,
1257 Tf::Rg16Sint => renderable,
1258 Tf::Rg16Unorm => norm16_unorm | norm16_storage,
1259 Tf::Rg16Snorm => norm16_snorm | norm16_storage,
1260 Tf::Rg16Float => filterable | half_float_renderable,
1261 Tf::Rgba8Unorm => filterable_renderable | storage,
1262 Tf::Rgba8UnormSrgb => filterable_renderable,
1263 Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => filterable_renderable,
1264 Tf::Rgba8Snorm => filterable | storage,
1265 Tf::Rgba8Uint => renderable | storage,
1266 Tf::Rgba8Sint => renderable | storage,
1267 Tf::Rgb10a2Uint => renderable,
1268 Tf::Rgb10a2Unorm => filterable_renderable,
1269 Tf::Rg11b10Ufloat => filterable | float_renderable,
1270 Tf::R64Uint => image_64_atomic,
1271 Tf::Rg32Uint => renderable,
1272 Tf::Rg32Sint => renderable,
1273 Tf::Rg32Float => unfilterable | float_renderable | texture_float_linear,
1274 Tf::Rgba16Uint => renderable | storage,
1275 Tf::Rgba16Sint => renderable | storage,
1276 Tf::Rgba16Unorm => norm16_unorm | norm16_storage,
1277 Tf::Rgba16Snorm => norm16_snorm | norm16_storage,
1278 Tf::Rgba16Float => filterable | storage | half_float_renderable,
1279 Tf::Rgba32Uint => renderable | storage,
1280 Tf::Rgba32Sint => renderable | storage,
1281 Tf::Rgba32Float => unfilterable | storage | float_renderable | texture_float_linear,
1282 Tf::Stencil8
1283 | Tf::Depth16Unorm
1284 | Tf::Depth32Float
1285 | Tf::Depth32FloatStencil8
1286 | Tf::Depth24Plus
1287 | Tf::Depth24PlusStencil8 => depth,
1288 Tf::NV12 => empty,
1289 Tf::P010 => empty,
1290 Tf::Rgb9e5Ufloat => filterable,
1291 Tf::Bc1RgbaUnorm
1292 | Tf::Bc1RgbaUnormSrgb
1293 | Tf::Bc2RgbaUnorm
1294 | Tf::Bc2RgbaUnormSrgb
1295 | Tf::Bc3RgbaUnorm
1296 | Tf::Bc3RgbaUnormSrgb
1297 | Tf::Bc4RUnorm
1298 | Tf::Bc4RSnorm
1299 | Tf::Bc5RgUnorm
1300 | Tf::Bc5RgSnorm
1301 | Tf::Bc6hRgbFloat
1302 | Tf::Bc6hRgbUfloat
1303 | Tf::Bc7RgbaUnorm
1304 | Tf::Bc7RgbaUnormSrgb => bcn_features,
1305 Tf::Etc2Rgb8Unorm
1306 | Tf::Etc2Rgb8UnormSrgb
1307 | Tf::Etc2Rgb8A1Unorm
1308 | Tf::Etc2Rgb8A1UnormSrgb
1309 | Tf::Etc2Rgba8Unorm
1310 | Tf::Etc2Rgba8UnormSrgb
1311 | Tf::EacR11Unorm
1312 | Tf::EacR11Snorm
1313 | Tf::EacRg11Unorm
1314 | Tf::EacRg11Snorm => etc2_features,
1315 Tf::Astc {
1316 block: _,
1317 channel: AstcChannel::Unorm | AstcChannel::UnormSrgb,
1318 } => astc_features,
1319 Tf::Astc {
1320 block: _,
1321 channel: AstcChannel::Hdr,
1322 } => astc_hdr_features,
1323 }
1324 }
1325
1326 unsafe fn surface_capabilities(
1327 &self,
1328 surface: &super::Surface,
1329 ) -> Option<crate::SurfaceCapabilities> {
1330 #[cfg(webgl)]
1331 if self.shared.context.webgl2_context != surface.webgl2_context {
1332 return None;
1333 }
1334
1335 if surface.presentable {
1336 let mut formats = vec![
1337 wgt::TextureFormat::Rgba8Unorm,
1338 #[cfg(native)]
1339 wgt::TextureFormat::Bgra8Unorm,
1340 ];
1341 if surface.supports_srgb() {
1342 formats.extend([
1343 wgt::TextureFormat::Rgba8UnormSrgb,
1344 #[cfg(native)]
1345 wgt::TextureFormat::Bgra8UnormSrgb,
1346 ])
1347 }
1348 if self
1349 .shared
1350 .private_caps
1351 .contains(super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT)
1352 {
1353 formats.push(wgt::TextureFormat::Rgba16Float)
1354 }
1355
1356 Some(crate::SurfaceCapabilities {
1357 formats,
1358 present_modes: if cfg!(windows) {
1359 vec![wgt::PresentMode::Fifo, wgt::PresentMode::Immediate]
1360 } else {
1361 vec![wgt::PresentMode::Fifo] },
1363 composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], maximum_frame_latency: 2..=2, current_extent: None,
1366 usage: wgt::TextureUses::COLOR_TARGET,
1367 })
1368 } else {
1369 None
1370 }
1371 }
1372
1373 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
1374 wgt::PresentationTimestamp::INVALID_TIMESTAMP
1375 }
1376
1377 fn get_ordered_buffer_usages(&self) -> wgt::BufferUses {
1378 wgt::BufferUses::INCLUSIVE | wgt::BufferUses::MAP_WRITE
1379 }
1380
1381 fn get_ordered_texture_usages(&self) -> wgt::TextureUses {
1383 wgt::TextureUses::INCLUSIVE
1384 | wgt::TextureUses::COLOR_TARGET
1385 | wgt::TextureUses::DEPTH_STENCIL_WRITE
1386 }
1387}
1388
1389impl super::AdapterShared {
1390 pub(super) unsafe fn get_buffer_sub_data(
1391 &self,
1392 gl: &glow::Context,
1393 target: u32,
1394 offset: i32,
1395 dst_data: &mut [u8],
1396 ) {
1397 if self
1398 .private_caps
1399 .contains(super::PrivateCapabilities::GET_BUFFER_SUB_DATA)
1400 {
1401 unsafe { gl.get_buffer_sub_data(target, offset, dst_data) };
1402 } else {
1403 log::error!("Fake map");
1404 let length = dst_data.len();
1405 if length != 0 {
1407 let buffer_mapping =
1408 unsafe { gl.map_buffer_range(target, offset, length as _, glow::MAP_READ_BIT) };
1409
1410 unsafe {
1411 core::ptr::copy_nonoverlapping(buffer_mapping, dst_data.as_mut_ptr(), length)
1412 };
1413
1414 unsafe { gl.unmap_buffer(target) };
1415 }
1416 }
1417 }
1418}
1419
1420#[cfg(send_sync)]
1421unsafe impl Sync for super::Adapter {}
1422#[cfg(send_sync)]
1423unsafe impl Send for super::Adapter {}
1424
1425#[cfg(test)]
1426mod tests {
1427 use super::super::Adapter;
1428
1429 #[test]
1430 fn test_version_parse() {
1431 Adapter::parse_version("1").unwrap_err();
1432 Adapter::parse_version("1.").unwrap_err();
1433 Adapter::parse_version("1 h3l1o. W0rld").unwrap_err();
1434 Adapter::parse_version("1. h3l1o. W0rld").unwrap_err();
1435 Adapter::parse_version("1.2.3").unwrap_err();
1436
1437 assert_eq!(Adapter::parse_version("OpenGL ES 3.1").unwrap(), (3, 1));
1438 assert_eq!(
1439 Adapter::parse_version("OpenGL ES 2.0 Google Nexus").unwrap(),
1440 (2, 0)
1441 );
1442 assert_eq!(Adapter::parse_version("GLSL ES 1.1").unwrap(), (1, 1));
1443 assert_eq!(
1444 Adapter::parse_version("OpenGL ES GLSL ES 3.20").unwrap(),
1445 (3, 2)
1446 );
1447 assert_eq!(
1448 Adapter::parse_version("WebGL 2.0 (OpenGL ES 3.0 Chromium)").unwrap(),
1450 (3, 0)
1451 );
1452 assert_eq!(
1453 Adapter::parse_version("WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)").unwrap(),
1454 (3, 0)
1455 );
1456 }
1457}