1use crate::{Error, GlContainer, MAX_COLOR_ATTACHMENTS};
2use glow::HasContext;
3use hal::{DynamicStates, Features, Limits, PerformanceCaveats, PhysicalDeviceProperties};
4use std::{collections::HashSet, fmt, str};
5
6#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)]
8pub struct Version {
9 pub major: u32,
10 pub minor: u32,
11 pub is_embedded: bool,
12 pub revision: Option<u32>,
13 pub vendor_info: String,
14}
15
16impl Version {
17 pub fn new(major: u32, minor: u32, revision: Option<u32>, vendor_info: String) -> Self {
19 Version {
20 major: major,
21 minor: minor,
22 is_embedded: false,
23 revision: revision,
24 vendor_info,
25 }
26 }
27 pub fn new_embedded(major: u32, minor: u32, vendor_info: String) -> Self {
29 Version {
30 major,
31 minor,
32 is_embedded: true,
33 revision: None,
34 vendor_info,
35 }
36 }
37
38 pub fn tuple(&self) -> (u32, u32) {
40 (self.major, self.minor)
41 }
42
43 pub fn parse(mut src: &str) -> Result<Version, &str> {
61 let webgl_sig = "WebGL ";
62 let is_webgl = src.starts_with(webgl_sig);
66 let is_es = if is_webgl {
67 let pos = src.rfind(webgl_sig).unwrap_or(0);
68 src = &src[pos + webgl_sig.len()..];
69 true
70 } else {
71 let es_sig = " ES ";
72 match src.rfind(es_sig) {
73 Some(pos) => {
74 src = &src[pos + es_sig.len()..];
75 true
76 }
77 None => false,
78 }
79 };
80
81 let glsl_es_sig = "GLSL ES ";
82 let is_glsl = match src.find(glsl_es_sig) {
83 Some(pos) => {
84 src = &src[pos + glsl_es_sig.len()..];
85 true
86 }
87 None => false,
88 };
89
90 let (version, vendor_info) = match src.find(' ') {
91 Some(i) => (&src[..i], src[i + 1..].to_string()),
92 None => (src, String::new()),
93 };
94
95 let mut it = version.split('.');
98 let major = it.next().and_then(|s| s.parse().ok());
99 let minor = it.next().and_then(|s| {
100 let trimmed = if s.starts_with('0') {
101 "0"
102 } else {
103 s.trim_end_matches('0')
104 };
105 trimmed.parse().ok()
106 });
107 let revision = if is_webgl {
108 None
109 } else {
110 it.next().and_then(|s| s.parse().ok())
111 };
112
113 match (major, minor, revision) {
114 (Some(major), Some(minor), revision) => Ok(Version {
115 major: if is_webgl && !is_glsl {
117 major + 1
118 } else {
119 major
120 },
121 minor,
122 is_embedded: is_es,
123 revision,
124 vendor_info,
125 }),
126 (_, _, _) => Err(src),
127 }
128 }
129}
130
131impl fmt::Debug for Version {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 match (
134 self.major,
135 self.minor,
136 self.revision,
137 self.vendor_info.as_str(),
138 ) {
139 (major, minor, Some(revision), "") => write!(f, "{}.{}.{}", major, minor, revision),
140 (major, minor, None, "") => write!(f, "{}.{}", major, minor),
141 (major, minor, Some(revision), vendor_info) => {
142 write!(f, "{}.{}.{}, {}", major, minor, revision, vendor_info)
143 }
144 (major, minor, None, vendor_info) => write!(f, "{}.{}, {}", major, minor, vendor_info),
145 }
146 }
147}
148
149fn get_string(gl: &GlContainer, name: u32) -> Result<String, Error> {
150 let value = unsafe { gl.get_parameter_string(name) };
151 let err = Error::from_error_code(unsafe { gl.get_error() });
152 if err != Error::NoError {
153 Err(err)
154 } else {
155 Ok(value)
156 }
157}
158fn get_usize(gl: &GlContainer, name: u32) -> Result<usize, Error> {
159 let value = unsafe { gl.get_parameter_i32(name) };
160 let err = Error::from_error_code(unsafe { gl.get_error() });
161 if err != Error::NoError {
162 Err(err)
163 } else {
164 Ok(value as usize)
165 }
166}
167fn get_u64(gl: &GlContainer, name: u32) -> Result<u64, Error> {
168 let value = unsafe { gl.get_parameter_i32(name) };
169 let err = Error::from_error_code(unsafe { gl.get_error() });
170 if err != Error::NoError {
171 Err(err)
172 } else {
173 Ok(value as u64)
174 }
175}
176
177#[derive(Clone, Eq, PartialEq, Debug)]
179pub struct PlatformName {
180 pub vendor: String,
182 pub renderer: String,
184}
185
186impl PlatformName {
187 fn get(gl: &GlContainer) -> Self {
188 PlatformName {
189 vendor: get_string(gl, glow::VENDOR).unwrap_or_default(),
190 renderer: get_string(gl, glow::RENDERER).unwrap_or_default(),
191 }
192 }
193}
194
195#[derive(Debug)]
199pub struct PrivateCaps {
200 pub vertex_array: bool,
202 pub framebuffer: bool,
204 pub framebuffer_texture: bool,
206 pub index_buffer_role_change: bool,
209 pub buffer_storage: bool,
210 pub image_storage: bool,
211 pub clear_buffer: bool,
212 pub program_interface: bool,
213 pub frag_data_location: bool,
214 pub sync: bool,
215 pub emulate_map: bool,
222 pub depth_range_f64_precision: bool,
224 pub draw_buffers: bool,
226 pub per_slot_color_mask: bool,
228 pub get_tex_image: bool,
230 pub memory_barrier: bool,
232}
233
234#[derive(Debug)]
236pub struct Info {
237 pub platform_name: PlatformName,
239 pub version: Version,
241 pub shading_language: Version,
243 pub extensions: HashSet<String>,
245}
246
247bitflags::bitflags! {
248 pub struct LegacyFeatures: u32 {
251 const INDIRECT_EXECUTION = 0x00000001;
253 const DRAW_INSTANCED = 0x00000002;
255 const DRAW_INSTANCED_BASE = 0x00000004;
257 const DRAW_INDEXED_BASE = 0x00000008;
259 const DRAW_INDEXED_INSTANCED = 0x00000010;
261 const DRAW_INDEXED_INSTANCED_BASE_VERTEX = 0x00000020;
263 const VERTEX_BASE = 0x00000080;
265 const SRGB_COLOR = 0x00000100;
267 const CONSTANT_BUFFER = 0x00000200;
269 const UNORDERED_ACCESS_VIEW = 0x00000400;
271 const COPY_BUFFER = 0x00000800;
273 const SAMPLER_OBJECTS = 0x00001000;
275 const EXPLICIT_LAYOUTS_IN_SHADER = 0x00002000;
277 const INSTANCED_ATTRIBUTE_BINDING = 0x00004000;
279 }
280}
281
282#[derive(Copy, Clone)]
283pub enum Requirement<'a> {
284 Core(u32, u32),
285 Es(u32, u32),
286 Ext(&'a str),
287}
288
289impl Info {
290 fn get(gl: &GlContainer) -> Info {
291 let platform_name = PlatformName::get(gl);
292 let raw_version = get_string(gl, glow::VERSION).unwrap_or_default();
293 let version = Version::parse(&raw_version).unwrap();
294 let shading_language = {
295 let raw_shader_version =
296 get_string(gl, glow::SHADING_LANGUAGE_VERSION).unwrap_or_default();
297 Version::parse(&raw_shader_version).unwrap()
298 };
299
300 let extensions = if crate::is_webgl() {
303 HashSet::new()
304 } else if (version >= Version::new(3, 0, None, String::from("")))
305 || (version >= Version::new_embedded(3, 0, String::from("")))
306 {
307 let num_exts = get_usize(gl, glow::NUM_EXTENSIONS).unwrap();
308 (0..num_exts)
309 .map(|i| unsafe { gl.get_parameter_indexed_string(glow::EXTENSIONS, i as u32) })
310 .collect()
311 } else {
312 get_string(gl, glow::EXTENSIONS)
314 .unwrap_or_else(|_| String::from(""))
315 .split(' ')
316 .map(|s| s.to_string())
317 .collect()
318 };
319
320 Info {
321 platform_name,
322 version,
323 shading_language,
324 extensions,
325 }
326 }
327
328 pub fn is_version_supported(&self, major: u32, minor: u32) -> bool {
329 !self.version.is_embedded
330 && self.version >= Version::new(major, minor, None, String::from(""))
331 }
332
333 pub fn is_embedded_version_supported(&self, major: u32, minor: u32) -> bool {
334 self.version.is_embedded
335 && self.version >= Version::new_embedded(major, minor, String::from(""))
336 }
337
338 pub fn is_extension_supported(&self, s: &str) -> bool {
340 self.extensions.contains(s)
341 }
342
343 pub fn is_version_or_extension_supported(&self, major: u32, minor: u32, ext: &str) -> bool {
344 self.is_version_supported(major, minor) || self.is_extension_supported(ext)
345 }
346
347 pub fn is_any_extension_supported(&self, exts: &[String]) -> bool {
348 exts.iter().any(|e| self.extensions.contains(e))
349 }
350
351 pub fn is_supported(&self, requirements: &[Requirement]) -> bool {
352 use self::Requirement::*;
353 requirements.iter().any(|r| match *r {
354 Core(major, minor) => self.is_version_supported(major, minor),
355 Es(major, minor) => self.is_embedded_version_supported(major, minor),
356 Ext(extension) => self.is_extension_supported(extension),
357 })
358 }
359}
360
361#[derive(Debug)]
371pub enum TextureFormatFilter {
372 Whitelist { whitelist: HashSet<(u32, u32, u32)> },
376 Permissive,
379}
380impl TextureFormatFilter {
381 const ES3_TABLE: &'static [(u32, u32, u32)] = &[
398 (glow::RGB, glow::RGB, glow::UNSIGNED_BYTE),
400 (glow::RGB, glow::RGB, glow::UNSIGNED_SHORT_5_6_5),
401 (glow::RGBA, glow::RGBA, glow::UNSIGNED_BYTE),
402 (glow::RGBA, glow::RGBA, glow::UNSIGNED_SHORT_4_4_4_4),
403 (glow::RGBA, glow::RGBA, glow::UNSIGNED_SHORT_5_5_5_1),
404 (
405 glow::LUMINANCE_ALPHA,
406 glow::LUMINANCE_ALPHA,
407 glow::UNSIGNED_BYTE,
408 ),
409 (glow::LUMINANCE, glow::LUMINANCE, glow::UNSIGNED_BYTE),
410 (glow::ALPHA, glow::ALPHA, glow::UNSIGNED_BYTE),
411 (glow::R8, glow::RED, glow::UNSIGNED_BYTE),
413 (glow::R8_SNORM, glow::RED, glow::BYTE),
414 (glow::R16F, glow::RED, glow::HALF_FLOAT),
415 (glow::R16F, glow::RED, glow::FLOAT),
416 (glow::R32F, glow::RED, glow::FLOAT),
417 (glow::R8UI, glow::RED_INTEGER, glow::UNSIGNED_BYTE),
418 (glow::R8I, glow::RED_INTEGER, glow::BYTE),
419 (glow::R16UI, glow::RED_INTEGER, glow::UNSIGNED_SHORT),
420 (glow::R16I, glow::RED_INTEGER, glow::SHORT),
421 (glow::R32UI, glow::RED_INTEGER, glow::UNSIGNED_INT),
422 (glow::R32I, glow::RED_INTEGER, glow::INT),
423 (glow::RG8, glow::RG, glow::UNSIGNED_BYTE),
424 (glow::RG8_SNORM, glow::RG, glow::BYTE),
425 (glow::RG16F, glow::RG, glow::HALF_FLOAT),
426 (glow::RG16F, glow::RG, glow::FLOAT),
427 (glow::RG32F, glow::RG, glow::FLOAT),
428 (glow::RG8UI, glow::RG_INTEGER, glow::UNSIGNED_BYTE),
429 (glow::RG8I, glow::RG_INTEGER, glow::BYTE),
430 (glow::RG16UI, glow::RG_INTEGER, glow::UNSIGNED_SHORT),
431 (glow::RG16I, glow::RG_INTEGER, glow::SHORT),
432 (glow::RG32UI, glow::RG_INTEGER, glow::UNSIGNED_INT),
433 (glow::RG32I, glow::RG_INTEGER, glow::INT),
434 (glow::RGB8, glow::RGB, glow::UNSIGNED_BYTE),
435 (glow::SRGB8, glow::RGB, glow::UNSIGNED_BYTE),
436 (glow::RGB565, glow::RGB, glow::UNSIGNED_BYTE),
437 (glow::RGB565, glow::RGB, glow::UNSIGNED_SHORT_5_6_5),
438 (glow::RGB8_SNORM, glow::RGB, glow::BYTE),
439 (
440 glow::R11F_G11F_B10F,
441 glow::RGB,
442 glow::UNSIGNED_INT_10F_11F_11F_REV,
443 ),
444 (glow::R11F_G11F_B10F, glow::RGB, glow::HALF_FLOAT),
445 (glow::R11F_G11F_B10F, glow::RGB, glow::FLOAT),
446 (glow::RGB9_E5, glow::RGB, glow::UNSIGNED_INT_5_9_9_9_REV),
447 (glow::RGB9_E5, glow::RGB, glow::HALF_FLOAT),
448 (glow::RGB9_E5, glow::RGB, glow::FLOAT),
449 (glow::RGB16F, glow::RGB, glow::HALF_FLOAT),
450 (glow::RGB16F, glow::RGB, glow::FLOAT),
451 (glow::RGB32F, glow::RGB, glow::FLOAT),
452 (glow::RGB8UI, glow::RGB_INTEGER, glow::UNSIGNED_BYTE),
453 (glow::RGB8I, glow::RGB_INTEGER, glow::BYTE),
454 (glow::RGB16UI, glow::RGB_INTEGER, glow::UNSIGNED_SHORT),
455 (glow::RGB16I, glow::RGB_INTEGER, glow::SHORT),
456 (glow::RGB32UI, glow::RGB_INTEGER, glow::UNSIGNED_INT),
457 (glow::RGB32I, glow::RGB_INTEGER, glow::INT),
458 (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE),
459 (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE),
460 (glow::RGBA8_SNORM, glow::RGBA, glow::BYTE),
461 (glow::RGB5_A1, glow::RGBA, glow::UNSIGNED_BYTE),
462 (glow::RGB5_A1, glow::RGBA, glow::UNSIGNED_SHORT_5_5_5_1),
463 (glow::RGB5_A1, glow::RGBA, glow::UNSIGNED_INT_2_10_10_10_REV),
464 (glow::RGBA4, glow::RGBA, glow::UNSIGNED_BYTE),
465 (glow::RGBA4, glow::RGBA, glow::UNSIGNED_SHORT_4_4_4_4),
466 (
467 glow::RGB10_A2,
468 glow::RGBA,
469 glow::UNSIGNED_INT_2_10_10_10_REV,
470 ),
471 (glow::RGBA16F, glow::RGBA, glow::HALF_FLOAT),
472 (glow::RGBA16F, glow::RGBA, glow::FLOAT),
473 (glow::RGBA32F, glow::RGBA, glow::FLOAT),
474 (glow::RGBA8UI, glow::RGBA_INTEGER, glow::UNSIGNED_BYTE),
475 (glow::RGBA8I, glow::RGBA_INTEGER, glow::BYTE),
476 (
477 glow::RGB10_A2UI,
478 glow::RGBA_INTEGER,
479 glow::UNSIGNED_INT_2_10_10_10_REV,
480 ),
481 (glow::RGBA16UI, glow::RGBA_INTEGER, glow::UNSIGNED_SHORT),
482 (glow::RGBA16I, glow::RGBA_INTEGER, glow::SHORT),
483 (glow::RGBA32I, glow::RGBA_INTEGER, glow::INT),
484 (glow::RGBA32UI, glow::RGBA_INTEGER, glow::UNSIGNED_INT),
485 (
486 glow::DEPTH_COMPONENT16,
487 glow::DEPTH_COMPONENT,
488 glow::UNSIGNED_SHORT,
489 ),
490 (
491 glow::DEPTH_COMPONENT16,
492 glow::DEPTH_COMPONENT,
493 glow::UNSIGNED_INT,
494 ),
495 (
496 glow::DEPTH_COMPONENT24,
497 glow::DEPTH_COMPONENT,
498 glow::UNSIGNED_INT,
499 ),
500 (glow::DEPTH_COMPONENT32F, glow::DEPTH_COMPONENT, glow::FLOAT),
501 (
502 glow::DEPTH24_STENCIL8,
503 glow::DEPTH_STENCIL,
504 glow::UNSIGNED_INT_24_8,
505 ),
506 (
507 glow::DEPTH32F_STENCIL8,
508 glow::DEPTH_STENCIL,
509 glow::FLOAT_32_UNSIGNED_INT_24_8_REV,
510 ),
511 (
512 glow::STENCIL_INDEX8,
513 glow::STENCIL_INDEX,
514 glow::UNSIGNED_BYTE,
515 ),
516 ];
517
518 const ES1_ES2_TABLE: &'static [(u32, u32, u32)] = &[
529 (glow::ALPHA, glow::ALPHA, glow::UNSIGNED_BYTE),
530 (glow::RGB, glow::RGB, glow::UNSIGNED_BYTE),
531 (glow::RGB, glow::RGB, glow::UNSIGNED_SHORT_5_6_5),
532 (glow::RGBA, glow::RGBA, glow::UNSIGNED_BYTE),
533 (glow::RGBA, glow::RGBA, glow::UNSIGNED_SHORT_4_4_4_4),
534 (glow::RGBA, glow::RGBA, glow::UNSIGNED_SHORT_5_5_5_1),
535 (glow::LUMINANCE, glow::LUMINANCE, glow::UNSIGNED_BYTE),
536 (
537 glow::LUMINANCE_ALPHA,
538 glow::LUMINANCE_ALPHA,
539 glow::UNSIGNED_BYTE,
540 ),
541 ];
542
543 fn new_es3() -> Self {
545 Self::Whitelist {
546 whitelist: {
547 let mut whitelist = HashSet::<(u32, u32, u32)>::default();
548 whitelist.extend(Self::ES3_TABLE);
549
550 whitelist
551 },
552 }
553 }
554
555 fn new_es1_es2() -> Self {
557 Self::Whitelist {
558 whitelist: {
559 let mut whitelist = HashSet::<(u32, u32, u32)>::default();
560 whitelist.extend(Self::ES1_ES2_TABLE);
561
562 whitelist
563 },
564 }
565 }
566
567 fn new_permissive() -> Self {
569 Self::Permissive
570 }
571
572 pub fn check(&self, internal_format: u32, format: u32, type_: u32) -> bool {
575 match self {
576 Self::Whitelist { whitelist } => whitelist.contains(&(internal_format, format, type_)),
577 Self::Permissive => true,
578 }
579 }
580}
581
582pub(crate) fn query_all(
585 gl: &GlContainer,
586) -> (
587 Info,
588 Features,
589 LegacyFeatures,
590 PhysicalDeviceProperties,
591 PrivateCaps,
592 TextureFormatFilter,
593) {
594 use self::Requirement::*;
595 let info = Info::get(gl);
596 let max_texture_size = get_usize(gl, glow::MAX_TEXTURE_SIZE).unwrap_or(64) as u32;
597 let max_samples = get_usize(gl, glow::MAX_SAMPLES).unwrap_or(8);
598 let max_samples_mask = (max_samples * 2 - 1) as u8;
599 let max_texel_elements = if crate::is_webgl() {
600 0
601 } else {
602 get_usize(gl, glow::MAX_TEXTURE_BUFFER_SIZE).unwrap_or(0)
603 };
604 let min_storage_buffer_offset_alignment = if crate::is_webgl() {
605 256
606 } else {
607 get_u64(gl, glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT).unwrap_or(256)
608 };
609
610 let mut limits = Limits {
611 max_image_1d_size: max_texture_size,
612 max_image_2d_size: max_texture_size,
613 max_image_3d_size: max_texture_size,
614 max_image_cube_size: max_texture_size,
615 max_image_array_layers: get_usize(gl, glow::MAX_ARRAY_TEXTURE_LAYERS).unwrap_or(1) as u16,
616 max_texel_elements,
617 max_viewports: 1,
618 optimal_buffer_copy_offset_alignment: 1,
619 optimal_buffer_copy_pitch_alignment: 1,
620 min_texel_buffer_offset_alignment: 1,
621 min_uniform_buffer_offset_alignment: get_u64(gl, glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT)
622 .unwrap_or(1024),
623 min_storage_buffer_offset_alignment,
624 framebuffer_color_sample_counts: max_samples_mask,
625 non_coherent_atom_size: 1,
626 max_color_attachments: get_usize(gl, glow::MAX_COLOR_ATTACHMENTS)
627 .unwrap_or(1)
628 .min(MAX_COLOR_ATTACHMENTS),
629 ..Limits::default()
630 };
631
632 if info.is_supported(&[Core(4, 0), Ext("GL_ARB_tessellation_shader")]) {
633 limits.max_patch_size = get_usize(gl, glow::MAX_PATCH_VERTICES).unwrap_or(0) as _;
634 }
635 if info.is_supported(&[Core(4, 1)]) {
636 limits.max_viewports = get_usize(gl, glow::MAX_VIEWPORTS).unwrap_or(0);
638 }
639
640 if info.is_supported(&[Core(4, 3), Es(3, 2), Ext("GL_ARB_compute_shader")]) {
644 for (i, (count, size)) in limits
645 .max_compute_work_group_count
646 .iter_mut()
647 .zip(limits.max_compute_work_group_size.iter_mut())
648 .enumerate()
649 {
650 unsafe {
651 *count =
652 gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_COUNT, i as _) as u32;
653 *size =
654 gl.get_parameter_indexed_i32(glow::MAX_COMPUTE_WORK_GROUP_SIZE, i as _) as u32;
655 }
656 }
657 }
658
659 let mut features = Features::NDC_Y_UP | Features::MUTABLE_COMPARISON_SAMPLER;
660 let mut downlevel = hal::DownlevelProperties::all_enabled();
662 let mut legacy = LegacyFeatures::empty();
664
665 if info.is_supported(&[
666 Core(4, 6),
667 Ext("GL_ARB_texture_filter_anisotropic"),
668 Ext("GL_EXT_texture_filter_anisotropic"),
669 ]) {
670 features |= Features::SAMPLER_ANISOTROPY;
671 }
672 if info.is_supported(&[Core(4, 2), Es(3, 1)]) {
673 legacy |= LegacyFeatures::EXPLICIT_LAYOUTS_IN_SHADER;
674 }
675 if info.is_supported(&[Core(3, 3), Es(3, 0), Ext("GL_ARB_instanced_arrays")]) {
676 features |= Features::INSTANCE_RATE;
677 }
678 if info.is_supported(&[Core(3, 3)]) {
679 features |= Features::SAMPLER_MIP_LOD_BIAS;
681 }
682 if info.is_supported(&[Core(2, 1)]) {
683 features |= Features::SAMPLER_BORDER_COLOR;
684 }
685 if info.is_supported(&[Core(4, 4), Ext("ARB_texture_mirror_clamp_to_edge")]) {
686 features |= Features::SAMPLER_MIRROR_CLAMP_EDGE;
687 }
688 if info.is_supported(&[Core(4, 0), Es(3, 2), Ext("GL_EXT_draw_buffers2")]) && !crate::is_webgl()
689 {
690 features |= Features::INDEPENDENT_BLENDING;
691 }
692
693 if false && info.is_supported(&[Core(4, 3), Es(3, 1)]) {
695 legacy |= LegacyFeatures::INDIRECT_EXECUTION;
697 }
698 if info.is_supported(&[Core(3, 1), Es(3, 0), Ext("GL_ARB_draw_instanced")]) {
699 legacy |= LegacyFeatures::DRAW_INSTANCED;
700 }
701 if info.is_supported(&[Core(4, 2), Ext("GL_ARB_base_instance")]) {
702 legacy |= LegacyFeatures::DRAW_INSTANCED_BASE;
703 }
704 if info.is_supported(&[Core(3, 2)]) {
705 legacy |= LegacyFeatures::DRAW_INDEXED_BASE;
707 }
708 if info.is_supported(&[Core(3, 1), Es(3, 0)]) {
709 legacy |= LegacyFeatures::DRAW_INDEXED_INSTANCED;
711 }
712 if info.is_supported(&[Core(3, 2)]) {
713 legacy |= LegacyFeatures::DRAW_INDEXED_INSTANCED_BASE_VERTEX;
715 }
716 if info.is_supported(&[
717 Core(3, 2),
718 Es(3, 2),
719 Ext("GL_ARB_draw_elements_base_vertex"),
720 ]) {
721 legacy |= LegacyFeatures::VERTEX_BASE;
722 }
723 if info.is_supported(&[
724 Core(3, 1),
725 Es(3, 0),
726 Ext("GL_ARB_framebuffer_sRGB"),
727 Ext("GL_EXT_sRGB"),
728 ]) {
729 legacy |= LegacyFeatures::SRGB_COLOR;
730 }
731 if info.is_supported(&[Core(3, 1), Es(3, 0), Ext("GL_ARB_uniform_buffer_object")]) {
732 legacy |= LegacyFeatures::CONSTANT_BUFFER;
733 }
734 if info.is_supported(&[Core(4, 0)]) {
735 legacy |= LegacyFeatures::UNORDERED_ACCESS_VIEW;
737 }
738 if info.is_supported(&[
739 Core(3, 1),
740 Es(3, 0),
741 Ext("GL_ARB_copy_buffer"),
742 Ext("GL_NV_copy_buffer"),
743 ]) {
744 legacy |= LegacyFeatures::COPY_BUFFER;
745 }
746 if info.is_supported(&[Core(3, 3), Es(3, 0), Ext("GL_ARB_sampler_objects")]) {
747 legacy |= LegacyFeatures::SAMPLER_OBJECTS;
748 }
749 if info.is_supported(&[Core(3, 3), Es(3, 0)]) {
750 legacy |= LegacyFeatures::INSTANCED_ATTRIBUTE_BINDING;
751 }
752
753 let mut performance_caveats = PerformanceCaveats::empty();
754 if !info.is_supported(&[Core(4, 2)]) {
756 performance_caveats |= PerformanceCaveats::BASE_VERTEX_INSTANCE_DRAWING;
757 }
758 let properties = PhysicalDeviceProperties {
759 limits,
760 performance_caveats,
761 dynamic_pipeline_states: DynamicStates::all(),
762 ..PhysicalDeviceProperties::default()
763 };
764
765 let buffer_storage = info.is_supported(&[
766 Core(4, 4),
767 Ext("GL_ARB_buffer_storage"),
768 Ext("GL_EXT_buffer_storage"),
769 ]);
770 let emulate_map = crate::is_webgl() || !buffer_storage;
772
773 let private = PrivateCaps {
774 vertex_array: info.is_supported(&[Core(3, 0), Es(3, 0), Ext("GL_ARB_vertex_array_object")]),
775 framebuffer: info.is_supported(&[Core(3, 0), Es(2, 0), Ext("GL_ARB_framebuffer_object")]),
777 framebuffer_texture: info.is_supported(&[Core(3, 0)]), index_buffer_role_change: info.is_supported(&[Core(2, 0), Es(2, 0)]) && !crate::is_webgl(),
781 image_storage: info.is_supported(&[Core(4, 2), Es(3, 0), Ext("GL_ARB_texture_storage")]),
782 buffer_storage,
783 clear_buffer: info.is_supported(&[Core(3, 0), Es(3, 0)]),
784 program_interface: info.is_supported(&[Core(4, 3), Ext("GL_ARB_program_interface_query")]),
785 frag_data_location: !info.version.is_embedded,
786 sync: info.is_supported(&[Core(3, 2), Es(3, 0), Ext("GL_ARB_sync")]), emulate_map,
788 depth_range_f64_precision: !info.version.is_embedded, draw_buffers: info.is_supported(&[Core(2, 0), Es(3, 0)]),
790 per_slot_color_mask: info.is_supported(&[Core(3, 0)]),
791 get_tex_image: !info.version.is_embedded,
792 memory_barrier: info.is_supported(&[Core(4, 2), Es(3, 1)]),
793 };
794
795 let filter = if info.is_supported(&[Es(3, 0)]) {
796 TextureFormatFilter::new_es3()
798 } else if info.is_supported(&[Es(1, 0)]) {
799 TextureFormatFilter::new_es1_es2()
801 } else {
802 TextureFormatFilter::new_permissive()
806 };
807
808 (info, features, legacy, properties, private, filter)
809}
810
811#[cfg(test)]
812mod tests {
813 use super::Version;
814
815 #[test]
816 fn test_version_parse() {
817 assert_eq!(Version::parse("1"), Err("1"));
818 assert_eq!(Version::parse("1."), Err("1."));
819 assert_eq!(Version::parse("1 h3l1o. W0rld"), Err("1 h3l1o. W0rld"));
820 assert_eq!(Version::parse("1. h3l1o. W0rld"), Err("1. h3l1o. W0rld"));
821 assert_eq!(
822 Version::parse("1.2.3"),
823 Ok(Version::new(1, 2, Some(3), String::new()))
824 );
825 assert_eq!(
826 Version::parse("1.2"),
827 Ok(Version::new(1, 2, None, String::new()))
828 );
829 assert_eq!(
830 Version::parse("1.2 h3l1o. W0rld"),
831 Ok(Version::new(1, 2, None, "h3l1o. W0rld".to_string()))
832 );
833 assert_eq!(
834 Version::parse("1.2.h3l1o. W0rld"),
835 Ok(Version::new(1, 2, None, "W0rld".to_string()))
836 );
837 assert_eq!(
838 Version::parse("1.2. h3l1o. W0rld"),
839 Ok(Version::new(1, 2, None, "h3l1o. W0rld".to_string()))
840 );
841 assert_eq!(
842 Version::parse("1.2.3.h3l1o. W0rld"),
843 Ok(Version::new(1, 2, Some(3), "W0rld".to_string()))
844 );
845 assert_eq!(
846 Version::parse("1.2.3 h3l1o. W0rld"),
847 Ok(Version::new(1, 2, Some(3), "h3l1o. W0rld".to_string()))
848 );
849 assert_eq!(
850 Version::parse("OpenGL ES 3.1"),
851 Ok(Version::new_embedded(3, 1, String::new()))
852 );
853 assert_eq!(
854 Version::parse("OpenGL ES 2.0 Google Nexus"),
855 Ok(Version::new_embedded(2, 0, "Google Nexus".to_string()))
856 );
857 assert_eq!(
858 Version::parse("GLSL ES 1.1"),
859 Ok(Version::new_embedded(1, 1, String::new()))
860 );
861 assert_eq!(
862 Version::parse("OpenGL ES GLSL ES 3.20"),
863 Ok(Version::new_embedded(3, 2, String::new()))
864 );
865 assert_eq!(
866 Version::parse("WebGL 2.0 (OpenGL ES 3.0 Chromium)"),
868 Ok(Version::new_embedded(
869 3,
870 0,
871 "(OpenGL ES 3.0 Chromium)".to_string()
872 ))
873 );
874 assert_eq!(
875 Version::parse("WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)"),
876 Ok(Version::new_embedded(
877 3,
878 0,
879 "(OpenGL ES GLSL ES 3.0 Chromium)".to_string()
880 ))
881 );
882 }
883}