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