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 mut features = wgt::Features::empty()
449 | wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
450 | wgt::Features::CLEAR_TEXTURE
451 | wgt::Features::IMMEDIATES
452 | wgt::Features::DEPTH32FLOAT_STENCIL8
453 | wgt::Features::PASSTHROUGH_SHADERS;
454 features.set(
455 wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER | wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO,
456 extensions.contains("GL_EXT_texture_border_clamp")
457 || extensions.contains("GL_ARB_texture_border_clamp"),
458 );
459 features.set(
460 wgt::Features::DEPTH_CLIP_CONTROL,
461 extensions.contains("GL_EXT_depth_clamp") || extensions.contains("GL_ARB_depth_clamp"),
462 );
463 features.set(
464 wgt::Features::VERTEX_WRITABLE_STORAGE,
465 downlevel_flags.contains(wgt::DownlevelFlags::VERTEX_STORAGE)
466 && vertex_shader_storage_textures != 0,
467 );
468 features.set(
469 wgt::Features::MULTIVIEW,
470 extensions.contains("OVR_multiview2") || extensions.contains("GL_OVR_multiview2"),
471 );
472 features.set(
473 wgt::Features::DUAL_SOURCE_BLENDING,
474 extensions.contains("GL_EXT_blend_func_extended")
475 || extensions.contains("GL_ARB_blend_func_extended"),
476 );
477 features.set(
478 wgt::Features::CLIP_DISTANCES,
479 full_ver.is_some() || extensions.contains("GL_EXT_clip_cull_distance"),
480 );
481 features.set(
482 wgt::Features::PRIMITIVE_INDEX,
483 supported((3, 2), (3, 2))
484 || extensions.contains("OES_geometry_shader")
485 || extensions.contains("GL_ARB_geometry_shader4"),
486 );
487 features.set(
488 wgt::Features::SHADER_EARLY_DEPTH_TEST,
489 supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
490 );
491 if extensions.contains("GL_ARB_timer_query") {
492 features.set(wgt::Features::TIMESTAMP_QUERY, true);
493 features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);
494 features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_PASSES, true);
495 }
496 let gl_bcn_exts = [
497 "GL_EXT_texture_compression_s3tc",
498 "GL_EXT_texture_compression_rgtc",
499 "GL_ARB_texture_compression_bptc",
500 ];
501 let gles_bcn_exts = [
502 "GL_EXT_texture_compression_s3tc_srgb",
503 "GL_EXT_texture_compression_rgtc",
504 "GL_EXT_texture_compression_bptc",
505 ];
506 let webgl_bcn_exts = [
507 "WEBGL_compressed_texture_s3tc",
508 "WEBGL_compressed_texture_s3tc_srgb",
509 "EXT_texture_compression_rgtc",
510 "EXT_texture_compression_bptc",
511 ];
512 let bcn_exts = if cfg!(any(webgl, Emscripten)) {
513 &webgl_bcn_exts[..]
514 } else if es_ver.is_some() {
515 &gles_bcn_exts[..]
516 } else {
517 &gl_bcn_exts[..]
518 };
519 features.set(
520 wgt::Features::TEXTURE_COMPRESSION_BC,
521 bcn_exts.iter().all(|&ext| extensions.contains(ext)),
522 );
523 features.set(
524 wgt::Features::TEXTURE_COMPRESSION_BC_SLICED_3D,
525 bcn_exts.iter().all(|&ext| extensions.contains(ext)), );
527 let has_etc = if cfg!(any(webgl, Emscripten)) {
528 extensions.contains("WEBGL_compressed_texture_etc")
529 } else {
530 es_ver.is_some() || extensions.contains("GL_ARB_ES3_compatibility")
531 };
532 features.set(wgt::Features::TEXTURE_COMPRESSION_ETC2, has_etc);
533
534 if extensions.contains("WEBGL_compressed_texture_astc")
536 || extensions.contains("GL_OES_texture_compression_astc")
537 {
538 #[cfg(webgl)]
539 {
540 if context
541 .glow_context
542 .compressed_texture_astc_supports_ldr_profile()
543 {
544 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC);
545 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D);
546 }
547 if context
548 .glow_context
549 .compressed_texture_astc_supports_hdr_profile()
550 {
551 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR);
552 }
553 }
554
555 #[cfg(any(native, Emscripten))]
556 {
557 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC);
558 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D);
559 features.insert(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR);
560 }
561 } else {
562 features.set(
563 wgt::Features::TEXTURE_COMPRESSION_ASTC,
564 extensions.contains("GL_KHR_texture_compression_astc_ldr"),
565 );
566 features.set(
567 wgt::Features::TEXTURE_COMPRESSION_ASTC_SLICED_3D,
568 extensions.contains("GL_KHR_texture_compression_astc_ldr")
569 && extensions.contains("GL_KHR_texture_compression_astc_sliced_3d"),
570 );
571 features.set(
572 wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR,
573 extensions.contains("GL_KHR_texture_compression_astc_hdr"),
574 );
575 }
576
577 features.set(
578 wgt::Features::FLOAT32_FILTERABLE,
579 extensions.contains("GL_ARB_color_buffer_float")
580 || extensions.contains("GL_EXT_color_buffer_float")
581 || extensions.contains("OES_texture_float_linear"),
582 );
583
584 if es_ver.is_none() {
585 features |= wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT;
586 }
587
588 let mut private_caps = super::PrivateCapabilities::empty();
591 private_caps.set(
592 super::PrivateCapabilities::BUFFER_ALLOCATION,
593 extensions.contains("GL_EXT_buffer_storage")
594 || extensions.contains("GL_ARB_buffer_storage"),
595 );
596 private_caps.set(
597 super::PrivateCapabilities::SHADER_BINDING_LAYOUT,
598 supports_compute,
599 );
600 private_caps.set(
601 super::PrivateCapabilities::SHADER_TEXTURE_SHADOW_LOD,
602 extensions.contains("GL_EXT_texture_shadow_lod"),
603 );
604 private_caps.set(
605 super::PrivateCapabilities::MEMORY_BARRIERS,
606 supported((3, 1), (4, 2)),
607 );
608 private_caps.set(
609 super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT,
610 supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_vertex_attrib_binding"),
611 );
612 private_caps.set(
613 super::PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE,
614 !cfg!(any(webgl, Emscripten)),
615 );
616 private_caps.set(
617 super::PrivateCapabilities::GET_BUFFER_SUB_DATA,
618 cfg!(any(webgl, Emscripten)) || full_ver.is_some(),
619 );
620 let color_buffer_float = extensions.contains("GL_EXT_color_buffer_float")
621 || extensions.contains("GL_ARB_color_buffer_float")
622 || extensions.contains("EXT_color_buffer_float");
623 let color_buffer_half_float = extensions.contains("GL_EXT_color_buffer_half_float")
624 || extensions.contains("GL_ARB_half_float_pixel");
625 private_caps.set(
626 super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT,
627 color_buffer_half_float || color_buffer_float,
628 );
629 private_caps.set(
630 super::PrivateCapabilities::COLOR_BUFFER_FLOAT,
631 color_buffer_float,
632 );
633 private_caps.set(super::PrivateCapabilities::QUERY_BUFFERS, query_buffers);
634 private_caps.set(super::PrivateCapabilities::QUERY_64BIT, full_ver.is_some());
635 private_caps.set(
636 super::PrivateCapabilities::TEXTURE_STORAGE,
637 supported((3, 0), (4, 2)),
638 );
639 let is_mali = renderer.to_lowercase().contains("mali");
640 let debug_fns_enabled = match backend_options.debug_fns {
641 wgt::GlDebugFns::Auto => gl.supports_debug() && !is_mali,
642 wgt::GlDebugFns::ForceEnabled => gl.supports_debug(),
643 wgt::GlDebugFns::Disabled => false,
644 };
645 private_caps.set(super::PrivateCapabilities::DEBUG_FNS, debug_fns_enabled);
646 private_caps.set(
647 super::PrivateCapabilities::INVALIDATE_FRAMEBUFFER,
648 supported((3, 0), (4, 3)),
649 );
650 if let Some(full_ver) = full_ver {
651 let supported =
652 full_ver >= (4, 2) && extensions.contains("GL_ARB_shader_draw_parameters");
653 private_caps.set(
654 super::PrivateCapabilities::FULLY_FEATURED_INSTANCING,
655 supported,
656 );
657 features.set(wgt::Features::INDIRECT_FIRST_INSTANCE, supported);
664 }
665 private_caps.set(
666 super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE,
667 extensions.contains("GL_EXT_multisampled_render_to_texture"),
668 );
669
670 if supports_storage {
673 features |= wgt::Features::MEMORY_DECORATION_COHERENT
674 | wgt::Features::MEMORY_DECORATION_VOLATILE;
675 }
676
677 let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32;
678 let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32;
679
680 let min_uniform_buffer_offset_alignment =
681 (unsafe { gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT) } as u32);
682 let min_storage_buffer_offset_alignment = if supports_storage {
683 (unsafe { gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) } as u32)
684 } else {
685 256
686 };
687 let max_uniform_buffers_per_shader_stage =
688 unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS) }
689 .min(unsafe { gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS) })
690 as u32;
691
692 let max_compute_workgroups_per_dimension = if supports_work_group_params {
693 unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 0) }
694 .min(unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 1) })
695 .min(unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, 2) })
696 as u32
697 } else {
698 0
699 };
700
701 let max_color_attachments = unsafe {
702 gl.get_parameter_i32(glow::MAX_COLOR_ATTACHMENTS)
703 .min(gl.get_parameter_i32(glow::MAX_DRAW_BUFFERS)) as u32
704 };
705
706 let max_color_attachment_bytes_per_sample =
708 max_color_attachments * wgt::TextureFormat::MAX_TARGET_PIXEL_BYTE_COST;
709
710 let limits = crate::auxil::adjust_raw_limits(wgt::Limits {
711 max_texture_dimension_1d: max_texture_size,
712 max_texture_dimension_2d: max_texture_size,
713 max_texture_dimension_3d: max_texture_3d_size,
714 max_texture_array_layers: unsafe {
715 gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS)
716 } as u32,
717 max_bind_groups: u32::MAX,
718 max_bind_groups_plus_vertex_buffers: u32::MAX,
720 max_bindings_per_bind_group: u32::MAX,
722 max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage,
723 max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage,
724 max_sampled_textures_per_shader_stage: super::MAX_TEXTURE_SLOTS as u32,
725 max_samplers_per_shader_stage: super::MAX_SAMPLERS as u32,
726 max_storage_buffers_per_shader_stage,
727 max_storage_textures_per_shader_stage,
728 max_uniform_buffers_per_shader_stage,
729 max_binding_array_elements_per_shader_stage: 0,
730 max_binding_array_sampler_elements_per_shader_stage: 0,
731 max_binding_array_acceleration_structure_elements_per_shader_stage: 0,
732 max_uniform_buffer_binding_size: unsafe {
733 gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE)
734 } as u64,
735 max_storage_buffer_binding_size: if supports_storage {
736 unsafe { gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) }
737 } else {
738 0
739 } as u64,
740 max_vertex_buffers: if private_caps
741 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
742 {
743 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) } as u32)
744 } else {
745 16 },
747 max_vertex_attributes: (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) }
748 as u32)
749 .min(super::MAX_VERTEX_ATTRIBUTES as u32),
750 max_vertex_buffer_array_stride: if private_caps
751 .contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
752 {
753 if let Some(full_ver) = full_ver {
754 if full_ver >= (4, 4) {
755 let value =
757 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) })
758 as u32;
759
760 if value == 0 {
761 log::debug!("Max vertex attribute stride is 0. Assuming it is the OpenGL minimum spec 2048");
765 2048
766 } else {
767 value
768 }
769 } else {
770 log::debug!("Max vertex attribute stride unknown. Assuming it is the OpenGL minimum spec 2048");
771 2048
772 }
773 } else {
774 (unsafe { gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) }) as u32
775 }
776 } else {
777 !0
778 },
779 max_immediate_size: super::MAX_IMMEDIATES as u32 * 4,
780 min_uniform_buffer_offset_alignment,
781 min_storage_buffer_offset_alignment,
782 max_inter_stage_shader_variables: {
783 let max_varying_components =
787 unsafe { gl.get_parameter_i32(glow::MAX_VARYING_COMPONENTS) } as u32;
788 if max_varying_components == 0 {
789 15
791 } else {
792 max_varying_components / 4
793 }
794 },
795 max_color_attachments,
796 max_color_attachment_bytes_per_sample,
797 max_compute_workgroup_storage_size: if supports_work_group_params {
798 (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_SHARED_MEMORY_SIZE) } as u32)
799 } else {
800 0
801 },
802 max_compute_invocations_per_workgroup: if supports_work_group_params {
803 (unsafe { gl.get_parameter_i32(glow::MAX_COMPUTE_WORK_GROUP_INVOCATIONS) } as u32)
804 } else {
805 0
806 },
807 max_compute_workgroup_size_x: if supports_work_group_params {
808 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 0) }
809 as u32)
810 } else {
811 0
812 },
813 max_compute_workgroup_size_y: if supports_work_group_params {
814 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 1) }
815 as u32)
816 } else {
817 0
818 },
819 max_compute_workgroup_size_z: if supports_work_group_params {
820 (unsafe { gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, 2) }
821 as u32)
822 } else {
823 0
824 },
825 max_compute_workgroups_per_dimension,
826 max_buffer_size: i32::MAX as u64,
827 max_non_sampler_bindings: u32::MAX,
828
829 max_task_workgroup_total_count: 0,
830 max_task_workgroups_per_dimension: 0,
831 max_mesh_workgroup_total_count: 0,
832 max_mesh_workgroups_per_dimension: 0,
833 max_task_invocations_per_workgroup: 0,
834 max_task_invocations_per_dimension: 0,
835 max_mesh_invocations_per_workgroup: 0,
836 max_mesh_invocations_per_dimension: 0,
837 max_task_payload_size: 0,
838 max_mesh_output_vertices: 0,
839 max_mesh_output_primitives: 0,
840 max_mesh_output_layers: 0,
841 max_mesh_multiview_view_count: 0,
842
843 max_blas_primitive_count: 0,
844 max_blas_geometry_count: 0,
845 max_tlas_instance_count: 0,
846 max_acceleration_structures_per_shader_stage: 0,
847
848 max_multiview_view_count: 0,
849 });
850
851 let mut workarounds = super::Workarounds::empty();
852
853 workarounds.set(
854 super::Workarounds::EMULATE_BUFFER_MAP,
855 cfg!(any(webgl, Emscripten)),
856 );
857
858 let r = renderer.to_lowercase();
859 if context.is_owned()
862 && r.contains("mesa")
863 && r.contains("intel")
864 && r.split(&[' ', '(', ')'][..])
865 .any(|substr| substr.len() == 3 && substr.chars().nth(2) == Some('l'))
866 {
867 log::debug!(
868 "Detected skylake derivative running on mesa i915. Clears to srgb textures will \
869 use manual shader clears."
870 );
871 workarounds.set(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR, true);
872 }
873
874 let downlevel_defaults = wgt::DownlevelLimits {};
875 let max_samples = unsafe { gl.get_parameter_i32(glow::MAX_SAMPLES) };
876
877 #[cfg_attr(target_arch = "wasm32", allow(dropping_references))]
881 drop(gl);
882
883 Some(crate::ExposedAdapter {
884 adapter: super::Adapter {
885 shared: Arc::new(super::AdapterShared {
886 context,
887 private_caps,
888 workarounds,
889 features,
890 limits: limits.clone(),
891 options: backend_options,
892 shading_language_version,
893 next_shader_id: Default::default(),
894 program_cache: Default::default(),
895 es: es_ver.is_some(),
896 max_msaa_samples: max_samples,
897 }),
898 },
899 info: Self::make_info(vendor, renderer, version),
900 features,
901 capabilities: crate::Capabilities {
902 limits,
903 downlevel: wgt::DownlevelCapabilities {
904 flags: downlevel_flags,
905 limits: downlevel_defaults,
906 shader_model: wgt::ShaderModel::Sm5,
907 },
908 alignments: crate::Alignments {
909 buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
910 buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
911 uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
921 raw_tlas_instance_size: 0,
922 ray_tracing_scratch_buffer_alignment: 0,
923 },
924 cooperative_matrix_properties: Vec::new(),
925 },
926 })
927 }
928
929 unsafe fn compile_shader(
930 source: &str,
931 gl: &glow::Context,
932 shader_type: u32,
933 es: bool,
934 ) -> Option<glow::Shader> {
935 let source = if es {
936 format!("#version 300 es\nprecision lowp float;\n{source}")
937 } else {
938 let version = gl.version();
939 if version.major == 3 && version.minor == 0 {
940 format!("#version 130\n{source}")
942 } else {
943 format!("#version 140\n{source}")
945 }
946 };
947 let shader = unsafe { gl.create_shader(shader_type) }.expect("Could not create shader");
948 unsafe { gl.shader_source(shader, &source) };
949 unsafe { gl.compile_shader(shader) };
950
951 if !unsafe { gl.get_shader_compile_status(shader) } {
952 let msg = unsafe { gl.get_shader_info_log(shader) };
953 if !msg.is_empty() {
954 log::error!("\tShader compile error: {msg}");
955 }
956 unsafe { gl.delete_shader(shader) };
957 None
958 } else {
959 Some(shader)
960 }
961 }
962
963 unsafe fn create_shader_clear_program(
964 gl: &glow::Context,
965 es: bool,
966 ) -> Option<ShaderClearProgram> {
967 let program = unsafe { gl.create_program() }.expect("Could not create shader program");
968 let vertex = unsafe {
969 Self::compile_shader(
970 include_str!("./shaders/clear.vert"),
971 gl,
972 glow::VERTEX_SHADER,
973 es,
974 )?
975 };
976 let fragment = unsafe {
977 Self::compile_shader(
978 include_str!("./shaders/clear.frag"),
979 gl,
980 glow::FRAGMENT_SHADER,
981 es,
982 )?
983 };
984 unsafe { gl.attach_shader(program, vertex) };
985 unsafe { gl.attach_shader(program, fragment) };
986 unsafe { gl.link_program(program) };
987
988 let linked_ok = unsafe { gl.get_program_link_status(program) };
989 let msg = unsafe { gl.get_program_info_log(program) };
990 if !msg.is_empty() {
991 log::error!("Shader link error: {msg}");
992 }
993 if !linked_ok {
994 return None;
995 }
996
997 let color_uniform_location = unsafe { gl.get_uniform_location(program, "color") }
998 .expect("Could not find color uniform in shader clear shader");
999 unsafe { gl.delete_shader(vertex) };
1000 unsafe { gl.delete_shader(fragment) };
1001
1002 Some(ShaderClearProgram {
1003 program,
1004 color_uniform_location,
1005 })
1006 }
1007}
1008
1009impl crate::Adapter for super::Adapter {
1010 type A = super::Api;
1011
1012 unsafe fn open(
1013 &self,
1014 features: wgt::Features,
1015 _limits: &wgt::Limits,
1016 _memory_hints: &wgt::MemoryHints,
1017 ) -> Result<crate::OpenDevice<super::Api>, crate::DeviceError> {
1018 let gl = &self.shared.context.lock();
1019 unsafe { gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1) };
1020 unsafe { gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1) };
1021 let main_vao =
1022 unsafe { gl.create_vertex_array() }.map_err(|_| crate::DeviceError::OutOfMemory)?;
1023 unsafe { gl.bind_vertex_array(Some(main_vao)) };
1024
1025 let zero_buffer =
1026 unsafe { gl.create_buffer() }.map_err(|_| crate::DeviceError::OutOfMemory)?;
1027 unsafe { gl.bind_buffer(glow::COPY_READ_BUFFER, Some(zero_buffer)) };
1028 let zeroes = vec![0u8; super::ZERO_BUFFER_SIZE];
1029 unsafe { gl.buffer_data_u8_slice(glow::COPY_READ_BUFFER, &zeroes, glow::STATIC_DRAW) };
1030
1031 let shader_clear_program = if self
1035 .shared
1036 .workarounds
1037 .contains(super::Workarounds::MESA_I915_SRGB_SHADER_CLEAR)
1038 {
1039 Some(unsafe {
1040 Self::create_shader_clear_program(gl, self.shared.es)
1041 .ok_or(crate::DeviceError::Lost)?
1042 })
1043 } else {
1044 None
1046 };
1047
1048 Ok(crate::OpenDevice {
1049 device: super::Device {
1050 shared: Arc::clone(&self.shared),
1051 main_vao,
1052 #[cfg(all(native, feature = "renderdoc"))]
1053 render_doc: Default::default(),
1054 counters: Default::default(),
1055 },
1056 queue: super::Queue {
1057 shared: Arc::clone(&self.shared),
1058 features,
1059 draw_fbo: unsafe { gl.create_framebuffer() }
1060 .map_err(|_| crate::DeviceError::OutOfMemory)?,
1061 copy_fbo: unsafe { gl.create_framebuffer() }
1062 .map_err(|_| crate::DeviceError::OutOfMemory)?,
1063 shader_clear_program,
1064 zero_buffer,
1065 temp_query_results: Mutex::new(Vec::new()),
1066 draw_buffer_count: AtomicU8::new(1),
1067 current_index_buffer: Mutex::new(None),
1068 },
1069 })
1070 }
1071
1072 unsafe fn texture_format_capabilities(
1073 &self,
1074 format: wgt::TextureFormat,
1075 ) -> crate::TextureFormatCapabilities {
1076 use crate::TextureFormatCapabilities as Tfc;
1077 use wgt::TextureFormat as Tf;
1078
1079 let sample_count = {
1080 let max_samples = self.shared.max_msaa_samples;
1081 if max_samples >= 16 {
1082 Tfc::MULTISAMPLE_X2
1083 | Tfc::MULTISAMPLE_X4
1084 | Tfc::MULTISAMPLE_X8
1085 | Tfc::MULTISAMPLE_X16
1086 } else if max_samples >= 8 {
1087 Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4 | Tfc::MULTISAMPLE_X8
1088 } else {
1089 Tfc::MULTISAMPLE_X2 | Tfc::MULTISAMPLE_X4
1094 }
1095 };
1096
1097 let empty = Tfc::empty();
1102 let base = Tfc::COPY_SRC | Tfc::COPY_DST;
1103 let unfilterable = base | Tfc::SAMPLED;
1104 let depth = base | Tfc::SAMPLED | sample_count | Tfc::DEPTH_STENCIL_ATTACHMENT;
1105 let filterable = unfilterable | Tfc::SAMPLED_LINEAR;
1106 let renderable =
1107 unfilterable | Tfc::COLOR_ATTACHMENT | sample_count | Tfc::MULTISAMPLE_RESOLVE;
1108 let filterable_renderable = filterable | renderable | Tfc::COLOR_ATTACHMENT_BLEND;
1109 let storage =
1110 base | Tfc::STORAGE_READ_WRITE | Tfc::STORAGE_READ_ONLY | Tfc::STORAGE_WRITE_ONLY;
1111
1112 let feature_fn = |f, caps| {
1113 if self.shared.features.contains(f) {
1114 caps
1115 } else {
1116 empty
1117 }
1118 };
1119
1120 let bcn_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_BC, filterable);
1121 let etc2_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ETC2, filterable);
1122 let astc_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ASTC, filterable);
1123 let astc_hdr_features = feature_fn(wgt::Features::TEXTURE_COMPRESSION_ASTC_HDR, filterable);
1124
1125 let private_caps_fn = |f, caps| {
1126 if self.shared.private_caps.contains(f) {
1127 caps
1128 } else {
1129 empty
1130 }
1131 };
1132
1133 let half_float_renderable = private_caps_fn(
1134 super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT,
1135 Tfc::COLOR_ATTACHMENT
1136 | Tfc::COLOR_ATTACHMENT_BLEND
1137 | sample_count
1138 | Tfc::MULTISAMPLE_RESOLVE,
1139 );
1140
1141 let float_renderable = private_caps_fn(
1142 super::PrivateCapabilities::COLOR_BUFFER_FLOAT,
1143 Tfc::COLOR_ATTACHMENT
1144 | Tfc::COLOR_ATTACHMENT_BLEND
1145 | sample_count
1146 | Tfc::MULTISAMPLE_RESOLVE,
1147 );
1148
1149 let texture_float_linear = feature_fn(wgt::Features::FLOAT32_FILTERABLE, filterable);
1150
1151 let image_atomic = feature_fn(wgt::Features::TEXTURE_ATOMIC, Tfc::STORAGE_ATOMIC);
1152 let image_64_atomic = feature_fn(wgt::Features::TEXTURE_INT64_ATOMIC, Tfc::STORAGE_ATOMIC);
1153
1154 match format {
1155 Tf::R8Unorm => filterable_renderable,
1156 Tf::R8Snorm => filterable,
1157 Tf::R8Uint => renderable,
1158 Tf::R8Sint => renderable,
1159 Tf::R16Uint => renderable,
1160 Tf::R16Sint => renderable,
1161 Tf::R16Unorm => empty,
1162 Tf::R16Snorm => empty,
1163 Tf::R16Float => filterable | half_float_renderable,
1164 Tf::Rg8Unorm => filterable_renderable,
1165 Tf::Rg8Snorm => filterable,
1166 Tf::Rg8Uint => renderable,
1167 Tf::Rg8Sint => renderable,
1168 Tf::R32Uint => renderable | storage | image_atomic,
1169 Tf::R32Sint => renderable | storage | image_atomic,
1170 Tf::R32Float => unfilterable | storage | float_renderable | texture_float_linear,
1171 Tf::Rg16Uint => renderable,
1172 Tf::Rg16Sint => renderable,
1173 Tf::Rg16Unorm => empty,
1174 Tf::Rg16Snorm => empty,
1175 Tf::Rg16Float => filterable | half_float_renderable,
1176 Tf::Rgba8Unorm => filterable_renderable | storage,
1177 Tf::Rgba8UnormSrgb => filterable_renderable,
1178 Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => filterable_renderable,
1179 Tf::Rgba8Snorm => filterable | storage,
1180 Tf::Rgba8Uint => renderable | storage,
1181 Tf::Rgba8Sint => renderable | storage,
1182 Tf::Rgb10a2Uint => renderable,
1183 Tf::Rgb10a2Unorm => filterable_renderable,
1184 Tf::Rg11b10Ufloat => filterable | float_renderable,
1185 Tf::R64Uint => image_64_atomic,
1186 Tf::Rg32Uint => renderable,
1187 Tf::Rg32Sint => renderable,
1188 Tf::Rg32Float => unfilterable | float_renderable | texture_float_linear,
1189 Tf::Rgba16Uint => renderable | storage,
1190 Tf::Rgba16Sint => renderable | storage,
1191 Tf::Rgba16Unorm => empty,
1192 Tf::Rgba16Snorm => empty,
1193 Tf::Rgba16Float => filterable | storage | half_float_renderable,
1194 Tf::Rgba32Uint => renderable | storage,
1195 Tf::Rgba32Sint => renderable | storage,
1196 Tf::Rgba32Float => unfilterable | storage | float_renderable | texture_float_linear,
1197 Tf::Stencil8
1198 | Tf::Depth16Unorm
1199 | Tf::Depth32Float
1200 | Tf::Depth32FloatStencil8
1201 | Tf::Depth24Plus
1202 | Tf::Depth24PlusStencil8 => depth,
1203 Tf::NV12 => empty,
1204 Tf::P010 => empty,
1205 Tf::Rgb9e5Ufloat => filterable,
1206 Tf::Bc1RgbaUnorm
1207 | Tf::Bc1RgbaUnormSrgb
1208 | Tf::Bc2RgbaUnorm
1209 | Tf::Bc2RgbaUnormSrgb
1210 | Tf::Bc3RgbaUnorm
1211 | Tf::Bc3RgbaUnormSrgb
1212 | Tf::Bc4RUnorm
1213 | Tf::Bc4RSnorm
1214 | Tf::Bc5RgUnorm
1215 | Tf::Bc5RgSnorm
1216 | Tf::Bc6hRgbFloat
1217 | Tf::Bc6hRgbUfloat
1218 | Tf::Bc7RgbaUnorm
1219 | Tf::Bc7RgbaUnormSrgb => bcn_features,
1220 Tf::Etc2Rgb8Unorm
1221 | Tf::Etc2Rgb8UnormSrgb
1222 | Tf::Etc2Rgb8A1Unorm
1223 | Tf::Etc2Rgb8A1UnormSrgb
1224 | Tf::Etc2Rgba8Unorm
1225 | Tf::Etc2Rgba8UnormSrgb
1226 | Tf::EacR11Unorm
1227 | Tf::EacR11Snorm
1228 | Tf::EacRg11Unorm
1229 | Tf::EacRg11Snorm => etc2_features,
1230 Tf::Astc {
1231 block: _,
1232 channel: AstcChannel::Unorm | AstcChannel::UnormSrgb,
1233 } => astc_features,
1234 Tf::Astc {
1235 block: _,
1236 channel: AstcChannel::Hdr,
1237 } => astc_hdr_features,
1238 }
1239 }
1240
1241 unsafe fn surface_capabilities(
1242 &self,
1243 surface: &super::Surface,
1244 ) -> Option<crate::SurfaceCapabilities> {
1245 #[cfg(webgl)]
1246 if self.shared.context.webgl2_context != surface.webgl2_context {
1247 return None;
1248 }
1249
1250 if surface.presentable {
1251 let mut formats = vec![
1252 wgt::TextureFormat::Rgba8Unorm,
1253 #[cfg(native)]
1254 wgt::TextureFormat::Bgra8Unorm,
1255 ];
1256 if surface.supports_srgb() {
1257 formats.extend([
1258 wgt::TextureFormat::Rgba8UnormSrgb,
1259 #[cfg(native)]
1260 wgt::TextureFormat::Bgra8UnormSrgb,
1261 ])
1262 }
1263 if self
1264 .shared
1265 .private_caps
1266 .contains(super::PrivateCapabilities::COLOR_BUFFER_HALF_FLOAT)
1267 {
1268 formats.push(wgt::TextureFormat::Rgba16Float)
1269 }
1270
1271 Some(crate::SurfaceCapabilities {
1272 formats,
1273 present_modes: if cfg!(windows) {
1274 vec![wgt::PresentMode::Fifo, wgt::PresentMode::Immediate]
1275 } else {
1276 vec![wgt::PresentMode::Fifo] },
1278 composite_alpha_modes: vec![wgt::CompositeAlphaMode::Opaque], maximum_frame_latency: 2..=2, current_extent: None,
1281 usage: wgt::TextureUses::COLOR_TARGET,
1282 })
1283 } else {
1284 None
1285 }
1286 }
1287
1288 unsafe fn get_presentation_timestamp(&self) -> wgt::PresentationTimestamp {
1289 wgt::PresentationTimestamp::INVALID_TIMESTAMP
1290 }
1291
1292 fn get_ordered_buffer_usages(&self) -> wgt::BufferUses {
1293 wgt::BufferUses::INCLUSIVE | wgt::BufferUses::MAP_WRITE
1294 }
1295
1296 fn get_ordered_texture_usages(&self) -> wgt::TextureUses {
1298 wgt::TextureUses::INCLUSIVE
1299 | wgt::TextureUses::COLOR_TARGET
1300 | wgt::TextureUses::DEPTH_STENCIL_WRITE
1301 }
1302}
1303
1304impl super::AdapterShared {
1305 pub(super) unsafe fn get_buffer_sub_data(
1306 &self,
1307 gl: &glow::Context,
1308 target: u32,
1309 offset: i32,
1310 dst_data: &mut [u8],
1311 ) {
1312 if self
1313 .private_caps
1314 .contains(super::PrivateCapabilities::GET_BUFFER_SUB_DATA)
1315 {
1316 unsafe { gl.get_buffer_sub_data(target, offset, dst_data) };
1317 } else {
1318 log::error!("Fake map");
1319 let length = dst_data.len();
1320 let buffer_mapping =
1321 unsafe { gl.map_buffer_range(target, offset, length as _, glow::MAP_READ_BIT) };
1322
1323 unsafe {
1324 core::ptr::copy_nonoverlapping(buffer_mapping, dst_data.as_mut_ptr(), length)
1325 };
1326
1327 unsafe { gl.unmap_buffer(target) };
1328 }
1329 }
1330}
1331
1332#[cfg(send_sync)]
1333unsafe impl Sync for super::Adapter {}
1334#[cfg(send_sync)]
1335unsafe impl Send for super::Adapter {}
1336
1337#[cfg(test)]
1338mod tests {
1339 use super::super::Adapter;
1340
1341 #[test]
1342 fn test_version_parse() {
1343 Adapter::parse_version("1").unwrap_err();
1344 Adapter::parse_version("1.").unwrap_err();
1345 Adapter::parse_version("1 h3l1o. W0rld").unwrap_err();
1346 Adapter::parse_version("1. h3l1o. W0rld").unwrap_err();
1347 Adapter::parse_version("1.2.3").unwrap_err();
1348
1349 assert_eq!(Adapter::parse_version("OpenGL ES 3.1").unwrap(), (3, 1));
1350 assert_eq!(
1351 Adapter::parse_version("OpenGL ES 2.0 Google Nexus").unwrap(),
1352 (2, 0)
1353 );
1354 assert_eq!(Adapter::parse_version("GLSL ES 1.1").unwrap(), (1, 1));
1355 assert_eq!(
1356 Adapter::parse_version("OpenGL ES GLSL ES 3.20").unwrap(),
1357 (3, 2)
1358 );
1359 assert_eq!(
1360 Adapter::parse_version("WebGL 2.0 (OpenGL ES 3.0 Chromium)").unwrap(),
1362 (3, 0)
1363 );
1364 assert_eq!(
1365 Adapter::parse_version("WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)").unwrap(),
1366 (3, 0)
1367 );
1368 }
1369}