#![feature(
    closure_lifetime_binder,
    negative_impls,
    map_try_insert,
    debug_closure_helpers,
    slice_partition_dedup
)]

use std::{collections::HashMap, ffi::CStr, fmt::Debug, marker::PhantomData, sync::Arc};

use raw_window_handle::{RawDisplayHandle, RawWindowHandle};

use ash::{
    ext,
    prelude::VkResult,
    vk::{self, SurfaceCapabilitiesKHR},
};
use dyn_clone::DynClone;

pub use ash;

mod buffers;
pub mod commands;
mod debug;
pub mod device;
#[path = "egui.rs"]
mod egui_pass;
mod images;
pub mod instance;
mod pipeline;
pub mod render_graph;
pub mod rendering;
pub mod swapchain;
pub mod sync;
mod text;
pub mod util;

use device::{Device, DeviceOwned, DeviceQueueFamilies};

mod texture {
    use std::{collections::BTreeMap, sync::Arc};

    use crate::{Device, def_monotonic_id, images::Image};

    def_monotonic_id!(pub TextureId);

    pub struct TextureManager {
        pub textures: BTreeMap<TextureId, Arc<Image>>,
        #[allow(unused)]
        dev: Device,
    }

    impl TextureManager {
        pub fn new(dev: Device) -> Self {
            Self {
                dev,
                textures: BTreeMap::new(),
            }
        }

        pub fn insert_image(&mut self, image: Arc<Image>) -> TextureId {
            let id = TextureId::new();
            self.textures.insert(id, image);
            id
        }
        pub fn insert_image_with_id(&mut self, id: TextureId, image: Arc<Image>) {
            self.textures.insert(id, image);
        }

        pub fn remove_texture(&mut self, id: TextureId) -> Option<Arc<Image>> {
            self.textures.remove(&id)
        }

        pub fn get_texture(&self, id: TextureId) -> Option<Arc<Image>> {
            self.textures.get(&id).cloned()
        }
    }
}

use util::Rgba;

#[derive(Debug, thiserror::Error)]
pub enum Error {
    #[error("No Physical Device found for this instance.")]
    NoAdapter,
    #[error("Swapchain suboptimal.")]
    SuboptimalSwapchain,
    #[error(transparent)]
    LoadingError(#[from] ash::LoadingError),
    #[error(transparent)]
    Result(#[from] ash::vk::Result),
    #[error(transparent)]
    CStrError(#[from] core::ffi::c_str::FromBytesUntilNulError),
    #[error(transparent)]
    Utf8Error(#[from] core::str::Utf8Error),
    #[error(transparent)]
    NulError(#[from] std::ffi::NulError),
    #[error(transparent)]
    GpuAllocatorError(#[from] gpu_allocator::AllocationError),
    #[error("No Physical Device found.")]
    NoPhysicalDevice,
    #[error(transparent)]
    Io(#[from] std::io::Error),
    #[error(
        "Image dimensions ({width}x{height}) exceed the maximum allowed size of {max_size}x{max_size}."
    )]
    ImageTooLarge {
        width: u32,
        height: u32,
        max_size: u32,
    },
    #[error("Image dimensions cannot be zero.")]
    ImageZeroSized,
    #[error("Incompatible image view kind {view_kind:?} for image kind {image_kind:?}.")]
    IncompatibleImageViewKind {
        view_kind: vk::ImageViewType,
        image_kind: vk::ImageType,
    },
    #[error("Unspecified Error")]
    Unspecified,
}

pub type Result<T> = core::result::Result<T, Error>;

struct VkNameList<'a> {
    names: Vec<*const i8>,
    _pd: PhantomData<&'a ()>,
}

impl<'a> VkNameList<'a> {
    fn from_strs(strs: &[&'a CStr]) -> Self {
        let names = strs.iter().map(|str| str.as_ptr()).collect::<Vec<_>>();

        Self {
            names,
            _pd: PhantomData,
        }
    }
}

#[derive(Debug, Clone)]
#[allow(dead_code)]
struct DeviceExtension<'a> {
    name: &'a core::ffi::CStr,
    version: u32,
}

fn make_extention_properties(name: &CStr, version: u32) -> vk::ExtensionProperties {
    vk::ExtensionProperties::default()
        .spec_version(version)
        .extension_name(name)
        .unwrap()
}

/// returns true if lhs and rhs have the same name and lhs spec_version is less
/// than or equal to rhs spec_version
#[allow(dead_code)]
fn compatible_extension_properties(
    lhs: &vk::ExtensionProperties,
    rhs: &vk::ExtensionProperties,
) -> bool {
    let Some(lhs_name) = lhs.extension_name_as_c_str().ok() else {
        return false;
    };
    let Some(rhs_name) = rhs.extension_name_as_c_str().ok() else {
        return false;
    };

    if lhs_name == rhs_name {
        lhs.spec_version <= rhs.spec_version
    } else {
        false
    }
}

pub mod queue;

pub trait ExtendsDeviceFeatures2Debug:
    vk::ExtendsPhysicalDeviceFeatures2 + Debug + Send + Sync
{
}
pub trait ExtendsDeviceProperties2Debug:
    vk::ExtendsPhysicalDeviceProperties2 + Debug + DynClone + Send + Sync
{
}

impl<T: vk::ExtendsPhysicalDeviceFeatures2 + Debug + Send + Sync> ExtendsDeviceFeatures2Debug
    for T
{
}
impl<T: vk::ExtendsPhysicalDeviceProperties2 + Debug + DynClone + Send + Sync>
    ExtendsDeviceProperties2Debug for T
{
}

#[derive(Debug)]
pub struct PhysicalDeviceInfo {
    pub pdev: vk::PhysicalDevice,
    pub properties: PhysicalDeviceProperties,
    pub features: PhysicalDeviceFeatures,
}

#[derive(Debug)]
pub struct SurfaceCapabilities {
    pub capabilities: SurfaceCapabilitiesKHR,
    pub formats: Vec<vk::SurfaceFormatKHR>,
    pub present_modes: Vec<vk::PresentModeKHR>,
}

#[derive(Default, Debug)]
pub struct PhysicalDeviceFeatures {
    pub core: vk::PhysicalDeviceFeatures,
    pub core11: vk::PhysicalDeviceVulkan11Features<'static>,
    pub core12: vk::PhysicalDeviceVulkan12Features<'static>,
    pub core13: vk::PhysicalDeviceVulkan13Features<'static>,
    pub mesh_shader: Option<vk::PhysicalDeviceMeshShaderFeaturesEXT<'static>>,
}

impl PhysicalDeviceFeatures {
    pub fn push_to_device_create_info<'a>(
        &'a mut self,
        mut create_info: vk::DeviceCreateInfo<'a>,
    ) -> vk::DeviceCreateInfo<'a> {
        create_info = create_info
            .push_next(&mut self.core11)
            .push_next(&mut self.core12)
            .push_next(&mut self.core13);

        if let Some(mesh_shader) = &mut self.mesh_shader {
            create_info = create_info.push_next(mesh_shader);
        }
        create_info
    }
    pub fn superset_of(&self, other: &PhysicalDeviceFeatures) -> bool {
        fn core_superset_of(
            a: &vk::PhysicalDeviceFeatures,
            b: &vk::PhysicalDeviceFeatures,
        ) -> bool {
            (b.robust_buffer_access == vk::FALSE
                || a.robust_buffer_access != b.robust_buffer_access)
                && (b.full_draw_index_uint32 == vk::FALSE
                    || a.full_draw_index_uint32 != b.full_draw_index_uint32)
                && (b.image_cube_array == vk::FALSE || a.image_cube_array != b.image_cube_array)
                && (b.independent_blend == vk::FALSE || a.independent_blend != b.independent_blend)
                && (b.geometry_shader == vk::FALSE || a.geometry_shader != b.geometry_shader)
                && (b.tessellation_shader == vk::FALSE
                    || a.tessellation_shader != b.tessellation_shader)
                && (b.sample_rate_shading == vk::FALSE
                    || a.sample_rate_shading != b.sample_rate_shading)
                && (b.dual_src_blend == vk::FALSE || a.dual_src_blend != b.dual_src_blend)
                && (b.logic_op == vk::FALSE || a.logic_op != b.logic_op)
                && (b.multi_draw_indirect == vk::FALSE
                    || a.multi_draw_indirect != b.multi_draw_indirect)
                && (b.draw_indirect_first_instance == vk::FALSE
                    || a.draw_indirect_first_instance != b.draw_indirect_first_instance)
                && (b.depth_clamp == vk::FALSE || a.depth_clamp != b.depth_clamp)
                && (b.depth_bias_clamp == vk::FALSE || a.depth_bias_clamp != b.depth_bias_clamp)
                && (b.fill_mode_non_solid == vk::FALSE
                    || a.fill_mode_non_solid != b.fill_mode_non_solid)
                && (b.depth_bounds == vk::FALSE || a.depth_bounds != b.depth_bounds)
                && (b.wide_lines == vk::FALSE || a.wide_lines != b.wide_lines)
                && (b.large_points == vk::FALSE || a.large_points != b.large_points)
                && (b.alpha_to_one == vk::FALSE || a.alpha_to_one != b.alpha_to_one)
                && (b.multi_viewport == vk::FALSE || a.multi_viewport != b.multi_viewport)
                && (b.sampler_anisotropy == vk::FALSE
                    || a.sampler_anisotropy != b.sampler_anisotropy)
                && (b.texture_compression_etc2 == vk::FALSE
                    || a.texture_compression_etc2 != b.texture_compression_etc2)
                && (b.texture_compression_astc_ldr == vk::FALSE
                    || a.texture_compression_astc_ldr != b.texture_compression_astc_ldr)
                && (b.texture_compression_bc == vk::FALSE
                    || a.texture_compression_bc != b.texture_compression_bc)
                && (b.occlusion_query_precise == vk::FALSE
                    || a.occlusion_query_precise != b.occlusion_query_precise)
                && (b.pipeline_statistics_query == vk::FALSE
                    || a.pipeline_statistics_query != b.pipeline_statistics_query)
                && (b.vertex_pipeline_stores_and_atomics == vk::FALSE
                    || a.vertex_pipeline_stores_and_atomics != b.vertex_pipeline_stores_and_atomics)
                && (b.fragment_stores_and_atomics == vk::FALSE
                    || a.fragment_stores_and_atomics != b.fragment_stores_and_atomics)
                && (b.shader_tessellation_and_geometry_point_size == vk::FALSE
                    || a.shader_tessellation_and_geometry_point_size
                        != b.shader_tessellation_and_geometry_point_size)
                && (b.shader_image_gather_extended == vk::FALSE
                    || a.shader_image_gather_extended != b.shader_image_gather_extended)
                && (b.shader_storage_image_extended_formats == vk::FALSE
                    || a.shader_storage_image_extended_formats
                        != b.shader_storage_image_extended_formats)
                && (b.shader_storage_image_multisample == vk::FALSE
                    || a.shader_storage_image_multisample != b.shader_storage_image_multisample)
                && (b.shader_storage_image_read_without_format == vk::FALSE
                    || a.shader_storage_image_read_without_format
                        != b.shader_storage_image_read_without_format)
                && (b.shader_storage_image_write_without_format == vk::FALSE
                    || a.shader_storage_image_write_without_format
                        != b.shader_storage_image_write_without_format)
                && (b.shader_uniform_buffer_array_dynamic_indexing == vk::FALSE
                    || a.shader_uniform_buffer_array_dynamic_indexing
                        != b.shader_uniform_buffer_array_dynamic_indexing)
                && (b.shader_sampled_image_array_dynamic_indexing == vk::FALSE
                    || a.shader_sampled_image_array_dynamic_indexing
                        != b.shader_sampled_image_array_dynamic_indexing)
                && (b.shader_storage_buffer_array_dynamic_indexing == vk::FALSE
                    || a.shader_storage_buffer_array_dynamic_indexing
                        != b.shader_storage_buffer_array_dynamic_indexing)
                && (b.shader_storage_image_array_dynamic_indexing == vk::FALSE
                    || a.shader_storage_image_array_dynamic_indexing
                        != b.shader_storage_image_array_dynamic_indexing)
                && (b.shader_clip_distance == vk::FALSE
                    || a.shader_clip_distance != b.shader_clip_distance)
                && (b.shader_cull_distance == vk::FALSE
                    || a.shader_cull_distance != b.shader_cull_distance)
                && (b.shader_float64 == vk::FALSE || a.shader_float64 != b.shader_float64)
                && (b.shader_int64 == vk::FALSE || a.shader_int64 != b.shader_int64)
                && (b.shader_int16 == vk::FALSE || a.shader_int16 != b.shader_int16)
                && (b.shader_resource_residency == vk::FALSE
                    || a.shader_resource_residency != b.shader_resource_residency)
                && (b.shader_resource_min_lod == vk::FALSE
                    || a.shader_resource_min_lod != b.shader_resource_min_lod)
                && (b.sparse_binding == vk::FALSE || a.sparse_binding != b.sparse_binding)
                && (b.sparse_residency_buffer == vk::FALSE
                    || a.sparse_residency_buffer != b.sparse_residency_buffer)
                && (b.sparse_residency_image2_d == vk::FALSE
                    || a.sparse_residency_image2_d != b.sparse_residency_image2_d)
                && (b.sparse_residency_image3_d == vk::FALSE
                    || a.sparse_residency_image3_d != b.sparse_residency_image3_d)
                && (b.sparse_residency2_samples == vk::FALSE
                    || a.sparse_residency2_samples != b.sparse_residency2_samples)
                && (b.sparse_residency4_samples == vk::FALSE
                    || a.sparse_residency4_samples != b.sparse_residency4_samples)
                && (b.sparse_residency8_samples == vk::FALSE
                    || a.sparse_residency8_samples != b.sparse_residency8_samples)
                && (b.sparse_residency16_samples == vk::FALSE
                    || a.sparse_residency16_samples != b.sparse_residency16_samples)
                && (b.sparse_residency_aliased == vk::FALSE
                    || a.sparse_residency_aliased != b.sparse_residency_aliased)
                && (b.variable_multisample_rate == vk::FALSE
                    || a.variable_multisample_rate != b.variable_multisample_rate)
                && (b.inherited_queries == vk::FALSE || a.inherited_queries != b.inherited_queries)
        }

        fn core11_superset_of(
            a: &vk::PhysicalDeviceVulkan11Features,
            b: &vk::PhysicalDeviceVulkan11Features,
        ) -> bool {
            (b.storage_buffer16_bit_access == vk::FALSE
                || a.storage_buffer16_bit_access != b.storage_buffer16_bit_access)
                && (b.uniform_and_storage_buffer16_bit_access == vk::FALSE
                    || a.uniform_and_storage_buffer16_bit_access
                        != b.uniform_and_storage_buffer16_bit_access)
                && (b.storage_push_constant16 == vk::FALSE
                    || a.storage_push_constant16 != b.storage_push_constant16)
                && (b.storage_input_output16 == vk::FALSE
                    || a.storage_input_output16 != b.storage_input_output16)
                && (b.multiview == vk::FALSE || a.multiview != b.multiview)
                && (b.multiview_geometry_shader == vk::FALSE
                    || a.multiview_geometry_shader != b.multiview_geometry_shader)
                && (b.multiview_tessellation_shader == vk::FALSE
                    || a.multiview_tessellation_shader != b.multiview_tessellation_shader)
                && (b.variable_pointers_storage_buffer == vk::FALSE
                    || a.variable_pointers_storage_buffer != b.variable_pointers_storage_buffer)
                && (b.variable_pointers == vk::FALSE || a.variable_pointers != b.variable_pointers)
                && (b.protected_memory == vk::FALSE || a.protected_memory != b.protected_memory)
                && (b.sampler_ycbcr_conversion == vk::FALSE
                    || a.sampler_ycbcr_conversion != b.sampler_ycbcr_conversion)
                && (b.shader_draw_parameters == vk::FALSE
                    || a.shader_draw_parameters != b.shader_draw_parameters)
        }

        fn core12_superset_of(
            a: &vk::PhysicalDeviceVulkan12Features,
            b: &vk::PhysicalDeviceVulkan12Features,
        ) -> bool {
            (b.sampler_mirror_clamp_to_edge == vk::FALSE
                || a.sampler_mirror_clamp_to_edge != b.sampler_mirror_clamp_to_edge)
                && (b.draw_indirect_count == vk::FALSE
                    || a.draw_indirect_count != b.draw_indirect_count)
                && (b.storage_buffer8_bit_access == vk::FALSE
                    || a.storage_buffer8_bit_access != b.storage_buffer8_bit_access)
                && (b.uniform_and_storage_buffer8_bit_access == vk::FALSE
                    || a.uniform_and_storage_buffer8_bit_access
                        != b.uniform_and_storage_buffer8_bit_access)
                && (b.storage_push_constant8 == vk::FALSE
                    || a.storage_push_constant8 != b.storage_push_constant8)
                && (b.shader_buffer_int64_atomics == vk::FALSE
                    || a.shader_buffer_int64_atomics != b.shader_buffer_int64_atomics)
                && (b.shader_shared_int64_atomics == vk::FALSE
                    || a.shader_shared_int64_atomics != b.shader_shared_int64_atomics)
                && (b.shader_float16 == vk::FALSE || a.shader_float16 != b.shader_float16)
                && (b.shader_int8 == vk::FALSE || a.shader_int8 != b.shader_int8)
                && (b.descriptor_indexing == vk::FALSE
                    || a.descriptor_indexing != b.descriptor_indexing)
                && (b.shader_input_attachment_array_dynamic_indexing == vk::FALSE
                    || a.shader_input_attachment_array_dynamic_indexing
                        != b.shader_input_attachment_array_dynamic_indexing)
                && (b.shader_uniform_texel_buffer_array_dynamic_indexing == vk::FALSE
                    || a.shader_uniform_texel_buffer_array_dynamic_indexing
                        != b.shader_uniform_texel_buffer_array_dynamic_indexing)
                && (b.shader_storage_texel_buffer_array_dynamic_indexing == vk::FALSE
                    || a.shader_storage_texel_buffer_array_dynamic_indexing
                        != b.shader_storage_texel_buffer_array_dynamic_indexing)
                && (b.shader_uniform_buffer_array_non_uniform_indexing == vk::FALSE
                    || a.shader_uniform_buffer_array_non_uniform_indexing
                        != b.shader_uniform_buffer_array_non_uniform_indexing)
                && (b.shader_sampled_image_array_non_uniform_indexing == vk::FALSE
                    || a.shader_sampled_image_array_non_uniform_indexing
                        != b.shader_sampled_image_array_non_uniform_indexing)
                && (b.shader_storage_buffer_array_non_uniform_indexing == vk::FALSE
                    || a.shader_storage_buffer_array_non_uniform_indexing
                        != b.shader_storage_buffer_array_non_uniform_indexing)
                && (b.shader_storage_image_array_non_uniform_indexing == vk::FALSE
                    || a.shader_storage_image_array_non_uniform_indexing
                        != b.shader_storage_image_array_non_uniform_indexing)
                && (b.shader_input_attachment_array_non_uniform_indexing == vk::FALSE
                    || a.shader_input_attachment_array_non_uniform_indexing
                        != b.shader_input_attachment_array_non_uniform_indexing)
                && (b.shader_uniform_texel_buffer_array_non_uniform_indexing == vk::FALSE
                    || a.shader_uniform_texel_buffer_array_non_uniform_indexing
                        != b.shader_uniform_texel_buffer_array_non_uniform_indexing)
                && (b.shader_storage_texel_buffer_array_non_uniform_indexing == vk::FALSE
                    || a.shader_storage_texel_buffer_array_non_uniform_indexing
                        != b.shader_storage_texel_buffer_array_non_uniform_indexing)
                && (b.descriptor_binding_uniform_buffer_update_after_bind == vk::FALSE
                    || a.descriptor_binding_uniform_buffer_update_after_bind
                        != b.descriptor_binding_uniform_buffer_update_after_bind)
                && (b.descriptor_binding_sampled_image_update_after_bind == vk::FALSE
                    || a.descriptor_binding_sampled_image_update_after_bind
                        != b.descriptor_binding_sampled_image_update_after_bind)
                && (b.descriptor_binding_storage_image_update_after_bind == vk::FALSE
                    || a.descriptor_binding_storage_image_update_after_bind
                        != b.descriptor_binding_storage_image_update_after_bind)
                && (b.descriptor_binding_storage_buffer_update_after_bind == vk::FALSE
                    || a.descriptor_binding_storage_buffer_update_after_bind
                        != b.descriptor_binding_storage_buffer_update_after_bind)
                && (b.descriptor_binding_uniform_texel_buffer_update_after_bind == vk::FALSE
                    || a.descriptor_binding_uniform_texel_buffer_update_after_bind
                        != b.descriptor_binding_uniform_texel_buffer_update_after_bind)
                && (b.descriptor_binding_storage_texel_buffer_update_after_bind == vk::FALSE
                    || a.descriptor_binding_storage_texel_buffer_update_after_bind
                        != b.descriptor_binding_storage_texel_buffer_update_after_bind)
                && (b.descriptor_binding_update_unused_while_pending == vk::FALSE
                    || a.descriptor_binding_update_unused_while_pending
                        != b.descriptor_binding_update_unused_while_pending)
                && (b.descriptor_binding_partially_bound == vk::FALSE
                    || a.descriptor_binding_partially_bound != b.descriptor_binding_partially_bound)
                && (b.descriptor_binding_variable_descriptor_count == vk::FALSE
                    || a.descriptor_binding_variable_descriptor_count
                        != b.descriptor_binding_variable_descriptor_count)
                && (b.runtime_descriptor_array == vk::FALSE
                    || a.runtime_descriptor_array != b.runtime_descriptor_array)
                && (b.sampler_filter_minmax == vk::FALSE
                    || a.sampler_filter_minmax != b.sampler_filter_minmax)
                && (b.scalar_block_layout == vk::FALSE
                    || a.scalar_block_layout != b.scalar_block_layout)
                && (b.imageless_framebuffer == vk::FALSE
                    || a.imageless_framebuffer != b.imageless_framebuffer)
                && (b.uniform_buffer_standard_layout == vk::FALSE
                    || a.uniform_buffer_standard_layout != b.uniform_buffer_standard_layout)
                && (b.shader_subgroup_extended_types == vk::FALSE
                    || a.shader_subgroup_extended_types != b.shader_subgroup_extended_types)
                && (b.separate_depth_stencil_layouts == vk::FALSE
                    || a.separate_depth_stencil_layouts != b.separate_depth_stencil_layouts)
                && (b.host_query_reset == vk::FALSE || a.host_query_reset != b.host_query_reset)
                && (b.timeline_semaphore == vk::FALSE
                    || a.timeline_semaphore != b.timeline_semaphore)
                && (b.buffer_device_address == vk::FALSE
                    || a.buffer_device_address != b.buffer_device_address)
                && (b.buffer_device_address_capture_replay == vk::FALSE
                    || a.buffer_device_address_capture_replay
                        != b.buffer_device_address_capture_replay)
                && (b.buffer_device_address_multi_device == vk::FALSE
                    || a.buffer_device_address_multi_device != b.buffer_device_address_multi_device)
                && (b.vulkan_memory_model == vk::FALSE
                    || a.vulkan_memory_model != b.vulkan_memory_model)
                && (b.vulkan_memory_model_device_scope == vk::FALSE
                    || a.vulkan_memory_model_device_scope != b.vulkan_memory_model_device_scope)
                && (b.vulkan_memory_model_availability_visibility_chains == vk::FALSE
                    || a.vulkan_memory_model_availability_visibility_chains
                        != b.vulkan_memory_model_availability_visibility_chains)
                && (b.shader_output_viewport_index == vk::FALSE
                    || a.shader_output_viewport_index != b.shader_output_viewport_index)
                && (b.shader_output_layer == vk::FALSE
                    || a.shader_output_layer != b.shader_output_layer)
                && (b.subgroup_broadcast_dynamic_id == vk::FALSE
                    || a.subgroup_broadcast_dynamic_id != b.subgroup_broadcast_dynamic_id)
        }

        fn core13_superset_of(
            a: &vk::PhysicalDeviceVulkan13Features,
            b: &vk::PhysicalDeviceVulkan13Features,
        ) -> bool {
            (b.robust_image_access == vk::FALSE || a.robust_image_access != b.robust_image_access)
                && (b.inline_uniform_block == vk::FALSE
                    || a.inline_uniform_block != b.inline_uniform_block)
                && (b.descriptor_binding_inline_uniform_block_update_after_bind == vk::FALSE
                    || a.descriptor_binding_inline_uniform_block_update_after_bind
                        != b.descriptor_binding_inline_uniform_block_update_after_bind)
                && (b.pipeline_creation_cache_control == vk::FALSE
                    || a.pipeline_creation_cache_control != b.pipeline_creation_cache_control)
                && (b.private_data == vk::FALSE || a.private_data != b.private_data)
                && (b.shader_demote_to_helper_invocation == vk::FALSE
                    || a.shader_demote_to_helper_invocation != b.shader_demote_to_helper_invocation)
                && (b.shader_terminate_invocation == vk::FALSE
                    || a.shader_terminate_invocation != b.shader_terminate_invocation)
                && (b.subgroup_size_control == vk::FALSE
                    || a.subgroup_size_control != b.subgroup_size_control)
                && (b.compute_full_subgroups == vk::FALSE
                    || a.compute_full_subgroups != b.compute_full_subgroups)
                && (b.synchronization2 == vk::FALSE || a.synchronization2 != b.synchronization2)
                && (b.texture_compression_astc_hdr == vk::FALSE
                    || a.texture_compression_astc_hdr != b.texture_compression_astc_hdr)
                && (b.shader_zero_initialize_workgroup_memory == vk::FALSE
                    || a.shader_zero_initialize_workgroup_memory
                        != b.shader_zero_initialize_workgroup_memory)
                && (b.dynamic_rendering == vk::FALSE || a.dynamic_rendering != b.dynamic_rendering)
                && (b.shader_integer_dot_product == vk::FALSE
                    || a.shader_integer_dot_product != b.shader_integer_dot_product)
                && (b.maintenance4 == vk::FALSE || a.maintenance4 != b.maintenance4)
        }

        fn mesh_shader_superset_of(
            a: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
            b: &vk::PhysicalDeviceMeshShaderFeaturesEXT,
        ) -> bool {
            (b.task_shader == vk::FALSE || a.task_shader != b.task_shader)
                && (b.mesh_shader == vk::FALSE || a.mesh_shader != b.mesh_shader)
                && (b.multiview_mesh_shader == vk::FALSE
                    || a.multiview_mesh_shader != b.multiview_mesh_shader)
                && (b.primitive_fragment_shading_rate_mesh_shader == vk::FALSE
                    || a.primitive_fragment_shading_rate_mesh_shader
                        != b.primitive_fragment_shading_rate_mesh_shader)
                && (b.mesh_shader_queries == vk::FALSE
                    || a.mesh_shader_queries != b.mesh_shader_queries)
        }

        core_superset_of(&self.core, &other.core)
            && core11_superset_of(&self.core11, &other.core11)
            && core12_superset_of(&self.core12, &other.core12)
            && core13_superset_of(&self.core13, &other.core13)
            && match (&self.mesh_shader, &other.mesh_shader) {
                (Some(a), Some(b)) => mesh_shader_superset_of(a, b),
                (None, Some(_)) => false,
                _ => true,
            }
    }
}

#[derive(Debug, Default)]
pub(crate) struct PhysicalDeviceProperties {
    /// Extensions supported by the device, as reported by `enumerate_device_extension_properties`.
    supported_extensions: Vec<vk::ExtensionProperties>,
    /// Vulkan 1.0 properties.
    core: vk::PhysicalDeviceProperties,
    /// Vulkan 1.1 properties.
    core11: vk::PhysicalDeviceVulkan11Properties<'static>,
    /// Vulkan 1.2 properties.
    core12: vk::PhysicalDeviceVulkan12Properties<'static>,
    /// Vulkan 1.3 properties.
    core13: vk::PhysicalDeviceVulkan13Properties<'static>,
    /// Mesh shader properties from the `VK_EXT_mesh_shader` extension, if supported.
    mesh_shader: Option<vk::PhysicalDeviceMeshShaderPropertiesEXT<'static>>,
    /// Memory properties of the device, as reported by `get_physical_device_memory_properties`.
    memory_properties: vk::PhysicalDeviceMemoryProperties,
    /// The API version supported by the device.
    device_api_version: u32,
}

impl PhysicalDeviceProperties {
    pub(crate) fn get_device_local_memory_count(&self) -> u64 {
        self.memory_properties
            .memory_heaps
            .iter()
            .filter(|heap| heap.flags.contains(vk::MemoryHeapFlags::DEVICE_LOCAL))
            .map(|heap| heap.size)
            .sum::<u64>()
    }
}

fn get_physical_device_features(
    instance: &InstanceInner,
    pdev: vk::PhysicalDevice,
    properties: &PhysicalDeviceProperties,
) -> Result<PhysicalDeviceFeatures> {
    let mut features = PhysicalDeviceFeatures::default();
    let mut features2 = vk::PhysicalDeviceFeatures2::default();

    if properties.supports_extension(make_extension!(ext::mesh_shader)) {
        features2 = features2.push_next(
            features
                .mesh_shader
                .insert(vk::PhysicalDeviceMeshShaderFeaturesEXT::default()),
        );
    }

    unsafe {
        instance
            .raw
            .get_physical_device_features2(pdev, &mut features2);
    }

    todo!()
}

fn get_physical_device_properties(
    instance: &InstanceInner,
    pdev: vk::PhysicalDevice,
) -> Result<PhysicalDeviceProperties> {
    let mut props = PhysicalDeviceProperties::default();
    props.core = unsafe { instance.raw.get_physical_device_properties(pdev) };
    props.device_api_version = props.core.api_version;
    props.supported_extensions =
        unsafe { instance.raw.enumerate_device_extension_properties(pdev)? };
    props.memory_properties = unsafe { instance.raw.get_physical_device_memory_properties(pdev) };

    let supports_mesh_shader = props.supports_extension(make_extension!(ext::mesh_shader));

    // TODO: fallibly check anything beyond 1.0
    let mut props2 = vk::PhysicalDeviceProperties2::default()
        .push_next(&mut props.core11)
        .push_next(&mut props.core12)
        .push_next(&mut props.core13);

    if supports_mesh_shader {
        let next = props
            .mesh_shader
            .insert(vk::PhysicalDeviceMeshShaderPropertiesEXT::default());
        props2 = props2.push_next(next);
    }

    unsafe {
        instance
            .raw
            .get_physical_device_properties2(pdev, &mut props2);
    }

    Ok(props)
}

pub(crate) fn extension_intersection<'a>(
    supported: &'a [vk::ExtensionProperties],
    required: &[Extension<'a>],
) -> Vec<vk::ExtensionProperties> {
    supported
        .iter()
        .filter(|ext| {
            required.iter().any(|req| {
                ext.extension_name_as_c_str() == Ok(req.name) && ext.spec_version >= req.version
            })
        })
        .cloned()
        .collect()
}

impl PhysicalDeviceProperties {
    pub(crate) fn supports_extension(&self, e: Extension) -> bool {
        self.supported_extensions
            .iter()
            .any(|ext| ext.extension_name_as_c_str() == Ok(e.name) && ext.spec_version >= e.version)
    }
}

#[derive(Debug)]
pub struct PhysicalDevice {
    pdev: vk::PhysicalDevice,
    queue_families: DeviceQueueFamilies,
    #[allow(dead_code)]
    properties: PhysicalDeviceProperties,
}

pub(crate) use instance::DebugUtils;
pub use instance::{DebugUtilsCreateInfo, Instance};

pub struct SamplerCache {
    device: Device,
    samplers: HashMap<pipeline::SamplerDesc, pipeline::Sampler>,
}

impl SamplerCache {
    pub fn new(device: Device) -> SamplerCache {
        Self {
            device,
            samplers: HashMap::new(),
        }
    }

    pub fn get_sampler(&mut self, desc: pipeline::SamplerDesc) -> VkResult<vk::Sampler> {
        use std::collections::hash_map::Entry;
        let entry = match self.samplers.entry(desc) {
            Entry::Occupied(entry) => entry.get().handle(),
            Entry::Vacant(entry) => {
                let sampler = pipeline::Sampler::new(self.device.clone(), entry.key())?;
                entry.insert(sampler).handle()
            }
        };

        Ok(entry)
    }
}

#[derive(Debug)]
pub struct EguiState {
    textures: HashMap<egui::TextureId, EguiTextureInfo>,
    #[allow(unused)]
    descriptor_pool: pipeline::DescriptorPool,
    descriptor_set: vk::DescriptorSet,
    #[allow(unused)]
    descriptor_layout: pipeline::DescriptorSetLayout,
    pipeline_layout: Arc<pipeline::PipelineLayout>,
    pipeline: Arc<pipeline::Pipeline>,
}

#[derive(Debug, Clone, Copy)]
pub struct EguiTextureInfo {
    id: texture::TextureId,
    options: egui::epaint::textures::TextureOptions,
}

impl EguiTextureInfo {
    fn as_sampler_desc(&self) -> pipeline::SamplerDesc {
        let address_mode = match self.options.wrap_mode {
            egui::TextureWrapMode::ClampToEdge => vk::SamplerAddressMode::CLAMP_TO_EDGE,
            egui::TextureWrapMode::Repeat => vk::SamplerAddressMode::REPEAT,
            egui::TextureWrapMode::MirroredRepeat => vk::SamplerAddressMode::MIRRORED_REPEAT,
        };
        pipeline::SamplerDesc {
            min_filter: match self.options.minification {
                egui::TextureFilter::Nearest => vk::Filter::NEAREST,
                egui::TextureFilter::Linear => vk::Filter::LINEAR,
            },
            mag_filter: match self.options.magnification {
                egui::TextureFilter::Nearest => vk::Filter::NEAREST,
                egui::TextureFilter::Linear => vk::Filter::LINEAR,
            },
            mipmap_mode: match self.options.mipmap_mode {
                Some(egui::TextureFilter::Linear) => vk::SamplerMipmapMode::LINEAR,
                Some(egui::TextureFilter::Nearest) => vk::SamplerMipmapMode::NEAREST,
                None => Default::default(),
            },
            address_u: address_mode,
            address_v: address_mode,
            address_w: address_mode,
            max_lod: vk::LOD_CLAMP_NONE,
            ..Default::default()
        }
    }
}

impl EguiState {
    const TEXTURE_BINDING: u32 = 0;
    const UNIFORM_BINDING: u32 = 1;
    pub fn new(device: Device) -> Result<Self> {
        let (descriptor_pool, descriptor_layout, sets) =
            util::timed("Create Descriptor Set", || {
                let descriptor_pool = pipeline::DescriptorPool::new(
                    device.clone(),
                    pipeline::DescriptorPoolDesc {
                        flags: vk::DescriptorPoolCreateFlags::UPDATE_AFTER_BIND,
                        name: Some("egui-descriptorpool".into()),
                        sizes: &[
                            vk::DescriptorPoolSize {
                                ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
                                descriptor_count: 10,
                            },
                            vk::DescriptorPoolSize {
                                ty: vk::DescriptorType::STORAGE_BUFFER,
                                descriptor_count: 1,
                            },
                        ],
                        max_sets: 1,
                        ..Default::default()
                    },
                )?;
                let descriptor_layout = pipeline::DescriptorSetLayout::new(
                    device.clone(),
                    pipeline::DescriptorSetLayoutDesc {
                        flags: vk::DescriptorSetLayoutCreateFlags::UPDATE_AFTER_BIND_POOL,
                        name: Some("egui-descriptor-layout".into()),
                        bindings: &[
                            pipeline::DescriptorSetLayoutBindingDesc {
                                binding: Self::TEXTURE_BINDING,
                                count: 10,
                                kind: vk::DescriptorType::COMBINED_IMAGE_SAMPLER,
                                stage: vk::ShaderStageFlags::FRAGMENT,
                                flags: Some(
                                    vk::DescriptorBindingFlags::PARTIALLY_BOUND
                                        | vk::DescriptorBindingFlags::UPDATE_AFTER_BIND,
                                ),
                            },
                            pipeline::DescriptorSetLayoutBindingDesc {
                                binding: Self::UNIFORM_BINDING,
                                count: 1,
                                kind: vk::DescriptorType::STORAGE_BUFFER,
                                stage: vk::ShaderStageFlags::FRAGMENT,
                                flags: None,
                            },
                        ],
                    },
                )?;

                let sets = descriptor_pool.allocate(&[pipeline::DescriptorSetAllocDesc {
                    name: None,
                    layout: &descriptor_layout,
                }])?;

                Result::Ok((descriptor_pool, descriptor_layout, sets))
            })?;

        let pipeline_layout = pipeline::PipelineLayout::new(
            device.clone(),
            pipeline::PipelineLayoutDesc {
                descriptor_set_layouts: &[&descriptor_layout],
                push_constant_ranges: &[vk::PushConstantRange {
                    offset: 0,
                    size: 128,
                    stage_flags: vk::ShaderStageFlags::VERTEX,
                }],
                name: Some("egui-pipeline-layout".into()),
            },
        )?;

        let frag_shader = pipeline::ShaderModule::new_from_path(
            device.clone(),
            "crates/renderer/shaders/egui_frag.spv",
        )?;
        let vert_shader = pipeline::ShaderModule::new_from_path(
            device.clone(),
            "crates/renderer/shaders/egui_vert.spv",
        )?;

        let pipeline = pipeline::Pipeline::new(
            device.clone(),
            pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
                flags: Default::default(),
                name: Some("egui-pipeline".into()),
                shader_stages: &[
                    pipeline::ShaderStageDesc {
                        flags: vk::PipelineShaderStageCreateFlags::empty(),
                        module: &frag_shader,
                        stage: vk::ShaderStageFlags::FRAGMENT,
                        entry: c"main".into(),
                    },
                    pipeline::ShaderStageDesc {
                        flags: vk::PipelineShaderStageCreateFlags::empty(),
                        module: &vert_shader,
                        stage: vk::ShaderStageFlags::VERTEX,
                        entry: c"main".into(),
                    },
                ],
                render_pass: None,
                layout: &pipeline_layout,
                subpass: None,
                base_pipeline: None,
                vertex_input: Some(pipeline::VertexInputState {
                    bindings: &[vk::VertexInputBindingDescription {
                        binding: 0,
                        stride: 20,
                        input_rate: vk::VertexInputRate::VERTEX,
                    }],
                    attributes: &[
                        vk::VertexInputAttributeDescription {
                            location: 0,
                            binding: 0,
                            format: vk::Format::R32G32_SFLOAT,
                            offset: 0,
                        },
                        vk::VertexInputAttributeDescription {
                            location: 1,
                            binding: 0,
                            format: vk::Format::R32G32_SFLOAT,
                            offset: 8,
                        },
                        vk::VertexInputAttributeDescription {
                            location: 2,
                            binding: 0,
                            format: vk::Format::R8G8B8A8_UNORM,
                            offset: 16,
                        },
                    ],
                }),
                input_assembly: Some(pipeline::InputAssemblyState {
                    topology: vk::PrimitiveTopology::TRIANGLE_LIST,
                    primitive_restart: false,
                }),
                tessellation: None,
                viewport: Some(pipeline::ViewportState {
                    num_viewports: 1,
                    num_scissors: 1,
                    ..Default::default()
                }),
                rasterization: Some(pipeline::RasterizationState {
                    cull_mode: vk::CullModeFlags::NONE,
                    ..Default::default()
                }),
                multisample: Some(pipeline::MultisampleState {
                    ..Default::default()
                }),
                depth_stencil: Some(pipeline::DepthStencilState {
                    depth: Some(pipeline::DepthState {
                        write_enable: false,
                        compare_op: Some(vk::CompareOp::LESS),
                        bounds: Some(pipeline::DepthBounds { min: 0.0, max: 1.0 }),
                    }),
                    ..Default::default()
                }),
                color_blend: Some(pipeline::ColorBlendState {
                    attachments: &[vk::PipelineColorBlendAttachmentState::default()
                        .color_write_mask(vk::ColorComponentFlags::RGBA)
                        .blend_enable(true)
                        .color_blend_op(vk::BlendOp::ADD)
                        .src_color_blend_factor(vk::BlendFactor::ONE)
                        .dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
                        .alpha_blend_op(vk::BlendOp::ADD)
                        .src_alpha_blend_factor(vk::BlendFactor::ONE)
                        .dst_alpha_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)],
                    ..Default::default()
                }),
                rendering: Some(pipeline::RenderingState {
                    color_formats: &[vk::Format::R8G8B8A8_UNORM],
                    ..Default::default()
                }),
                dynamic: Some(pipeline::DynamicState {
                    dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
                    ..Default::default()
                }),
            }),
        )?;

        Ok(Self {
            textures: HashMap::new(),
            descriptor_pool,
            descriptor_layout,
            descriptor_set: sets[0],
            pipeline: Arc::new(pipeline),
            pipeline_layout: Arc::new(pipeline_layout),
        })
    }

    pub fn lookup_texture(&self, id: egui::epaint::TextureId) -> Option<texture::TextureId> {
        self.textures.get(&id).map(|entry| entry.id)
    }
}

pub struct Renderer2 {
    device: Device,
    pub samplers: SamplerCache,
    pub texture_manager: texture::TextureManager,

    #[allow(unused)]
    // keep this around because the vulkan device has been created with this
    // display handle in mind. Might not be necessary.
    display: RawDisplayHandle,
}

impl Renderer2 {
    pub fn new(display: RawDisplayHandle) -> Result<Self> {
        let instance = Instance::new(&InstanceDesc {
            ..Default::default()
        })?;
        let adapter = instance.choose_adapter_default(None, &[], None)?;
        let device = adapter.create_logical_device(
            &instance,
            &[],
            PhysicalDeviceFeatures::default(),
            Some(display),
        )?;

        Ok(Self {
            samplers: SamplerCache::new(device.clone()),
            texture_manager: texture::TextureManager::new(device.clone()),
            display,
            device,
        })
    }

    pub fn device(&self) -> &Device {
        &self.device
    }

    pub fn samplers_mut(&mut self) -> &mut SamplerCache {
        &mut self.samplers
    }
    pub fn samplers(&self) -> &SamplerCache {
        &self.samplers
    }
    pub fn texture_manager_mut(&mut self) -> &mut texture::TextureManager {
        &mut self.texture_manager
    }
    pub fn texture_manager(&self) -> &texture::TextureManager {
        &self.texture_manager
    }

    pub fn create_surface(
        &self,
        window: RawWindowHandle,
        extent: vk::Extent2D,
    ) -> Result<swapchain::Surface> {
        let surface = unsafe {
            swapchain::Surface::new_from_raw_window_handle(
                &self.device.instance,
                self.display,
                window,
            )?
        };
        surface.configure(
            &self.device,
            swapchain::SwapchainConfiguration {
                present_mode: vk::PresentModeKHR::MAILBOX,
                format: vk::Format::R8G8B8A8_UNORM,
                color_space: vk::ColorSpaceKHR::SRGB_NONLINEAR,
                image_count: 3,
                extent,
                composite_alpha_mode: vk::CompositeAlphaFlagsKHR::OPAQUE,
                usage: vk::ImageUsageFlags::COLOR_ATTACHMENT | vk::ImageUsageFlags::TRANSFER_DST,
            },
        )?;
        Ok(surface)
    }

    pub async fn draw_graph<T, F: FnOnce(&mut Renderer2, &mut render_graph::RenderGraph) -> T>(
        &mut self,
        surface: &swapchain::Surface,
        cb: F,
    ) -> Result<T> {
        let Some(frame) = surface.acquire_image() else {
            return Err(Error::SuboptimalSwapchain);
        };
        let (frame, _suboptimal) = frame.await?;

        let mut rg = render_graph::RenderGraph::new();
        let _framebuffer = rg.import_framebuffer(frame.image().clone());

        let out = cb(self, &mut rg);

        let cmds = rg.resolve(self.device.clone())?;

        let future = cmds.submit(
            Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)),
            Some(frame.release),
            Arc::new(sync::Fence::from_pool(&self.device.pools.fences, None)?),
        )?;

        future.await;

        // window.window.pre_present_notify();
        let wait = Some(frame.release);
        frame.present(wait)?;

        Ok(out)
    }
}

pub use vk::Extent2D;

use crate::{
    device::Extension,
    instance::{InstanceDesc, InstanceInner},
};

pub mod utils {
    #![allow(dead_code)]

    use ash::vk;
    pub trait SplitCollect: Iterator {
        fn collect2<F>(self, mut pred: F) -> (Vec<Self::Item>, Vec<Self::Item>)
        where
            Self: Sized,
            F: FnMut(&Self::Item) -> bool,
        {
            let mut left = Vec::new();
            let mut right = Vec::new();

            for item in self {
                if pred(&item) {
                    left.push(item);
                } else {
                    right.push(item);
                }
            }

            (left, right)
        }
    }

    pub fn eq_device_features10(
        lhs: &vk::PhysicalDeviceFeatures,
        rhs: &vk::PhysicalDeviceFeatures,
    ) -> bool {
        lhs.robust_buffer_access == rhs.robust_buffer_access
            && lhs.full_draw_index_uint32 == rhs.full_draw_index_uint32
            && lhs.image_cube_array == rhs.image_cube_array
            && lhs.independent_blend == rhs.independent_blend
            && lhs.geometry_shader == rhs.geometry_shader
            && lhs.tessellation_shader == rhs.tessellation_shader
            && lhs.sample_rate_shading == rhs.sample_rate_shading
            && lhs.dual_src_blend == rhs.dual_src_blend
            && lhs.logic_op == rhs.logic_op
            && lhs.multi_draw_indirect == rhs.multi_draw_indirect
            && lhs.draw_indirect_first_instance == rhs.draw_indirect_first_instance
            && lhs.depth_clamp == rhs.depth_clamp
            && lhs.depth_bias_clamp == rhs.depth_bias_clamp
            && lhs.fill_mode_non_solid == rhs.fill_mode_non_solid
            && lhs.depth_bounds == rhs.depth_bounds
            && lhs.wide_lines == rhs.wide_lines
            && lhs.large_points == rhs.large_points
            && lhs.alpha_to_one == rhs.alpha_to_one
            && lhs.multi_viewport == rhs.multi_viewport
            && lhs.sampler_anisotropy == rhs.sampler_anisotropy
            && lhs.texture_compression_etc2 == rhs.texture_compression_etc2
            && lhs.texture_compression_astc_ldr == rhs.texture_compression_astc_ldr
            && lhs.texture_compression_bc == rhs.texture_compression_bc
            && lhs.occlusion_query_precise == rhs.occlusion_query_precise
            && lhs.pipeline_statistics_query == rhs.pipeline_statistics_query
            && lhs.vertex_pipeline_stores_and_atomics == rhs.vertex_pipeline_stores_and_atomics
            && lhs.fragment_stores_and_atomics == rhs.fragment_stores_and_atomics
            && lhs.shader_tessellation_and_geometry_point_size
                == rhs.shader_tessellation_and_geometry_point_size
            && lhs.shader_image_gather_extended == rhs.shader_image_gather_extended
            && lhs.shader_storage_image_extended_formats
                == rhs.shader_storage_image_extended_formats
            && lhs.shader_storage_image_multisample == rhs.shader_storage_image_multisample
            && lhs.shader_storage_image_read_without_format
                == rhs.shader_storage_image_read_without_format
            && lhs.shader_storage_image_write_without_format
                == rhs.shader_storage_image_write_without_format
            && lhs.shader_uniform_buffer_array_dynamic_indexing
                == rhs.shader_uniform_buffer_array_dynamic_indexing
            && lhs.shader_sampled_image_array_dynamic_indexing
                == rhs.shader_sampled_image_array_dynamic_indexing
            && lhs.shader_storage_buffer_array_dynamic_indexing
                == rhs.shader_storage_buffer_array_dynamic_indexing
            && lhs.shader_storage_image_array_dynamic_indexing
                == rhs.shader_storage_image_array_dynamic_indexing
            && lhs.shader_clip_distance == rhs.shader_clip_distance
            && lhs.shader_cull_distance == rhs.shader_cull_distance
            && lhs.shader_float64 == rhs.shader_float64
            && lhs.shader_int64 == rhs.shader_int64
            && lhs.shader_int16 == rhs.shader_int16
            && lhs.shader_resource_residency == rhs.shader_resource_residency
            && lhs.shader_resource_min_lod == rhs.shader_resource_min_lod
            && lhs.sparse_binding == rhs.sparse_binding
            && lhs.sparse_residency_buffer == rhs.sparse_residency_buffer
            && lhs.sparse_residency_image2_d == rhs.sparse_residency_image2_d
            && lhs.sparse_residency_image3_d == rhs.sparse_residency_image3_d
            && lhs.sparse_residency2_samples == rhs.sparse_residency2_samples
            && lhs.sparse_residency4_samples == rhs.sparse_residency4_samples
            && lhs.sparse_residency8_samples == rhs.sparse_residency8_samples
            && lhs.sparse_residency16_samples == rhs.sparse_residency16_samples
            && lhs.sparse_residency_aliased == rhs.sparse_residency_aliased
            && lhs.variable_multisample_rate == rhs.variable_multisample_rate
            && lhs.inherited_queries == rhs.inherited_queries
    }

    pub fn eq_device_features11(
        lhs: &vk::PhysicalDeviceVulkan11Features,
        rhs: &vk::PhysicalDeviceVulkan11Features,
    ) -> bool {
        lhs.storage_buffer16_bit_access == rhs.storage_buffer16_bit_access
            && lhs.uniform_and_storage_buffer16_bit_access
                == rhs.uniform_and_storage_buffer16_bit_access
            && lhs.storage_push_constant16 == rhs.storage_push_constant16
            && lhs.storage_input_output16 == rhs.storage_input_output16
            && lhs.multiview == rhs.multiview
            && lhs.multiview_geometry_shader == rhs.multiview_geometry_shader
            && lhs.multiview_tessellation_shader == rhs.multiview_tessellation_shader
            && lhs.variable_pointers_storage_buffer == rhs.variable_pointers_storage_buffer
            && lhs.variable_pointers == rhs.variable_pointers
            && lhs.protected_memory == rhs.protected_memory
            && lhs.sampler_ycbcr_conversion == rhs.sampler_ycbcr_conversion
            && lhs.shader_draw_parameters == rhs.shader_draw_parameters
    }

    pub fn eq_device_features12(
        lhs: &vk::PhysicalDeviceVulkan12Features,
        rhs: &vk::PhysicalDeviceVulkan12Features,
    ) -> bool {
        lhs.sampler_mirror_clamp_to_edge == rhs.sampler_mirror_clamp_to_edge
            && lhs.draw_indirect_count == rhs.draw_indirect_count
            && lhs.storage_buffer8_bit_access == rhs.storage_buffer8_bit_access
            && lhs.uniform_and_storage_buffer8_bit_access
                == rhs.uniform_and_storage_buffer8_bit_access
            && lhs.storage_push_constant8 == rhs.storage_push_constant8
            && lhs.shader_buffer_int64_atomics == rhs.shader_buffer_int64_atomics
            && lhs.shader_shared_int64_atomics == rhs.shader_shared_int64_atomics
            && lhs.shader_float16 == rhs.shader_float16
            && lhs.shader_int8 == rhs.shader_int8
            && lhs.descriptor_indexing == rhs.descriptor_indexing
            && lhs.shader_input_attachment_array_dynamic_indexing
                == rhs.shader_input_attachment_array_dynamic_indexing
            && lhs.shader_uniform_texel_buffer_array_dynamic_indexing
                == rhs.shader_uniform_texel_buffer_array_dynamic_indexing
            && lhs.shader_storage_texel_buffer_array_dynamic_indexing
                == rhs.shader_storage_texel_buffer_array_dynamic_indexing
            && lhs.shader_uniform_buffer_array_non_uniform_indexing
                == rhs.shader_uniform_buffer_array_non_uniform_indexing
            && lhs.shader_sampled_image_array_non_uniform_indexing
                == rhs.shader_sampled_image_array_non_uniform_indexing
            && lhs.shader_storage_buffer_array_non_uniform_indexing
                == rhs.shader_storage_buffer_array_non_uniform_indexing
            && lhs.shader_storage_image_array_non_uniform_indexing
                == rhs.shader_storage_image_array_non_uniform_indexing
            && lhs.shader_input_attachment_array_non_uniform_indexing
                == rhs.shader_input_attachment_array_non_uniform_indexing
            && lhs.shader_uniform_texel_buffer_array_non_uniform_indexing
                == rhs.shader_uniform_texel_buffer_array_non_uniform_indexing
            && lhs.shader_storage_texel_buffer_array_non_uniform_indexing
                == rhs.shader_storage_texel_buffer_array_non_uniform_indexing
            && lhs.descriptor_binding_uniform_buffer_update_after_bind
                == rhs.descriptor_binding_uniform_buffer_update_after_bind
            && lhs.descriptor_binding_sampled_image_update_after_bind
                == rhs.descriptor_binding_sampled_image_update_after_bind
            && lhs.descriptor_binding_storage_image_update_after_bind
                == rhs.descriptor_binding_storage_image_update_after_bind
            && lhs.descriptor_binding_storage_buffer_update_after_bind
                == rhs.descriptor_binding_storage_buffer_update_after_bind
            && lhs.descriptor_binding_uniform_texel_buffer_update_after_bind
                == rhs.descriptor_binding_uniform_texel_buffer_update_after_bind
            && lhs.descriptor_binding_storage_texel_buffer_update_after_bind
                == rhs.descriptor_binding_storage_texel_buffer_update_after_bind
            && lhs.descriptor_binding_update_unused_while_pending
                == rhs.descriptor_binding_update_unused_while_pending
            && lhs.descriptor_binding_partially_bound == rhs.descriptor_binding_partially_bound
            && lhs.descriptor_binding_variable_descriptor_count
                == rhs.descriptor_binding_variable_descriptor_count
            && lhs.runtime_descriptor_array == rhs.runtime_descriptor_array
            && lhs.sampler_filter_minmax == rhs.sampler_filter_minmax
            && lhs.scalar_block_layout == rhs.scalar_block_layout
            && lhs.imageless_framebuffer == rhs.imageless_framebuffer
            && lhs.uniform_buffer_standard_layout == rhs.uniform_buffer_standard_layout
            && lhs.shader_subgroup_extended_types == rhs.shader_subgroup_extended_types
            && lhs.separate_depth_stencil_layouts == rhs.separate_depth_stencil_layouts
            && lhs.host_query_reset == rhs.host_query_reset
            && lhs.timeline_semaphore == rhs.timeline_semaphore
            && lhs.buffer_device_address == rhs.buffer_device_address
            && lhs.buffer_device_address_capture_replay == rhs.buffer_device_address_capture_replay
            && lhs.buffer_device_address_multi_device == rhs.buffer_device_address_multi_device
            && lhs.vulkan_memory_model == rhs.vulkan_memory_model
            && lhs.vulkan_memory_model_device_scope == rhs.vulkan_memory_model_device_scope
            && lhs.vulkan_memory_model_availability_visibility_chains
                == rhs.vulkan_memory_model_availability_visibility_chains
            && lhs.shader_output_viewport_index == rhs.shader_output_viewport_index
            && lhs.shader_output_layer == rhs.shader_output_layer
            && lhs.subgroup_broadcast_dynamic_id == rhs.subgroup_broadcast_dynamic_id
    }

    pub fn eq_device_features13(
        lhs: &vk::PhysicalDeviceVulkan13Features,
        rhs: &vk::PhysicalDeviceVulkan13Features,
    ) -> bool {
        lhs.robust_image_access == rhs.robust_image_access
            && lhs.inline_uniform_block == rhs.inline_uniform_block
            && lhs.descriptor_binding_inline_uniform_block_update_after_bind
                == rhs.descriptor_binding_inline_uniform_block_update_after_bind
            && lhs.pipeline_creation_cache_control == rhs.pipeline_creation_cache_control
            && lhs.private_data == rhs.private_data
            && lhs.shader_demote_to_helper_invocation == rhs.shader_demote_to_helper_invocation
            && lhs.shader_terminate_invocation == rhs.shader_terminate_invocation
            && lhs.subgroup_size_control == rhs.subgroup_size_control
            && lhs.compute_full_subgroups == rhs.compute_full_subgroups
            && lhs.synchronization2 == rhs.synchronization2
            && lhs.texture_compression_astc_hdr == rhs.texture_compression_astc_hdr
            && lhs.shader_zero_initialize_workgroup_memory
                == rhs.shader_zero_initialize_workgroup_memory
            && lhs.dynamic_rendering == rhs.dynamic_rendering
            && lhs.shader_integer_dot_product == rhs.shader_integer_dot_product
            && lhs.maintenance4 == rhs.maintenance4
    }

    pub fn bitand_device_features10(
        lhs: &vk::PhysicalDeviceFeatures,
        rhs: &vk::PhysicalDeviceFeatures,
    ) -> vk::PhysicalDeviceFeatures {
        use core::ops::BitAnd;
        vk::PhysicalDeviceFeatures {
            robust_buffer_access: lhs.robust_buffer_access.bitand(&rhs.robust_buffer_access),
            full_draw_index_uint32: lhs
                .full_draw_index_uint32
                .bitand(&rhs.full_draw_index_uint32),
            image_cube_array: lhs.image_cube_array.bitand(&rhs.image_cube_array),
            independent_blend: lhs.independent_blend.bitand(&rhs.independent_blend),
            geometry_shader: lhs.geometry_shader.bitand(&rhs.geometry_shader),
            tessellation_shader: lhs.tessellation_shader.bitand(&rhs.tessellation_shader),
            sample_rate_shading: lhs.sample_rate_shading.bitand(&rhs.sample_rate_shading),
            dual_src_blend: lhs.dual_src_blend.bitand(&rhs.dual_src_blend),
            logic_op: lhs.logic_op.bitand(&rhs.logic_op),
            multi_draw_indirect: lhs.multi_draw_indirect.bitand(&rhs.multi_draw_indirect),
            draw_indirect_first_instance: lhs
                .draw_indirect_first_instance
                .bitand(&rhs.draw_indirect_first_instance),
            depth_clamp: lhs.depth_clamp.bitand(&rhs.depth_clamp),
            depth_bias_clamp: lhs.depth_bias_clamp.bitand(&rhs.depth_bias_clamp),
            fill_mode_non_solid: lhs.fill_mode_non_solid.bitand(&rhs.fill_mode_non_solid),
            depth_bounds: lhs.depth_bounds.bitand(&rhs.depth_bounds),
            wide_lines: lhs.wide_lines.bitand(&rhs.wide_lines),
            large_points: lhs.large_points.bitand(&rhs.large_points),
            alpha_to_one: lhs.alpha_to_one.bitand(&rhs.alpha_to_one),
            multi_viewport: lhs.multi_viewport.bitand(&rhs.multi_viewport),
            sampler_anisotropy: lhs.sampler_anisotropy.bitand(&rhs.sampler_anisotropy),
            texture_compression_etc2: lhs
                .texture_compression_etc2
                .bitand(&rhs.texture_compression_etc2),
            texture_compression_astc_ldr: lhs
                .texture_compression_astc_ldr
                .bitand(&rhs.texture_compression_astc_ldr),
            texture_compression_bc: lhs
                .texture_compression_bc
                .bitand(&rhs.texture_compression_bc),
            occlusion_query_precise: lhs
                .occlusion_query_precise
                .bitand(&rhs.occlusion_query_precise),
            pipeline_statistics_query: lhs
                .pipeline_statistics_query
                .bitand(&rhs.pipeline_statistics_query),
            vertex_pipeline_stores_and_atomics: lhs
                .vertex_pipeline_stores_and_atomics
                .bitand(&rhs.vertex_pipeline_stores_and_atomics),
            fragment_stores_and_atomics: lhs
                .fragment_stores_and_atomics
                .bitand(&rhs.fragment_stores_and_atomics),
            shader_tessellation_and_geometry_point_size: lhs
                .shader_tessellation_and_geometry_point_size
                .bitand(&rhs.shader_tessellation_and_geometry_point_size),
            shader_image_gather_extended: lhs
                .shader_image_gather_extended
                .bitand(&rhs.shader_image_gather_extended),
            shader_storage_image_extended_formats: lhs
                .shader_storage_image_extended_formats
                .bitand(&rhs.shader_storage_image_extended_formats),
            shader_storage_image_multisample: lhs
                .shader_storage_image_multisample
                .bitand(&rhs.shader_storage_image_multisample),
            shader_storage_image_read_without_format: lhs
                .shader_storage_image_read_without_format
                .bitand(&rhs.shader_storage_image_read_without_format),
            shader_storage_image_write_without_format: lhs
                .shader_storage_image_write_without_format
                .bitand(&rhs.shader_storage_image_write_without_format),
            shader_uniform_buffer_array_dynamic_indexing: lhs
                .shader_uniform_buffer_array_dynamic_indexing
                .bitand(&rhs.shader_uniform_buffer_array_dynamic_indexing),
            shader_sampled_image_array_dynamic_indexing: lhs
                .shader_sampled_image_array_dynamic_indexing
                .bitand(&rhs.shader_sampled_image_array_dynamic_indexing),
            shader_storage_buffer_array_dynamic_indexing: lhs
                .shader_storage_buffer_array_dynamic_indexing
                .bitand(&rhs.shader_storage_buffer_array_dynamic_indexing),
            shader_storage_image_array_dynamic_indexing: lhs
                .shader_storage_image_array_dynamic_indexing
                .bitand(&rhs.shader_storage_image_array_dynamic_indexing),
            shader_clip_distance: lhs.shader_clip_distance.bitand(&rhs.shader_clip_distance),
            shader_cull_distance: lhs.shader_cull_distance.bitand(&rhs.shader_cull_distance),
            shader_float64: lhs.shader_float64.bitand(&rhs.shader_float64),
            shader_int64: lhs.shader_int64.bitand(&rhs.shader_int64),
            shader_int16: lhs.shader_int16.bitand(&rhs.shader_int16),
            shader_resource_residency: lhs
                .shader_resource_residency
                .bitand(&rhs.shader_resource_residency),
            shader_resource_min_lod: lhs
                .shader_resource_min_lod
                .bitand(&rhs.shader_resource_min_lod),
            sparse_binding: lhs.sparse_binding.bitand(&rhs.sparse_binding),
            sparse_residency_buffer: lhs
                .sparse_residency_buffer
                .bitand(&rhs.sparse_residency_buffer),
            sparse_residency_image2_d: lhs
                .sparse_residency_image2_d
                .bitand(&rhs.sparse_residency_image2_d),
            sparse_residency_image3_d: lhs
                .sparse_residency_image3_d
                .bitand(&rhs.sparse_residency_image3_d),
            sparse_residency2_samples: lhs
                .sparse_residency2_samples
                .bitand(&rhs.sparse_residency2_samples),
            sparse_residency4_samples: lhs
                .sparse_residency4_samples
                .bitand(&rhs.sparse_residency4_samples),
            sparse_residency8_samples: lhs
                .sparse_residency8_samples
                .bitand(&rhs.sparse_residency8_samples),
            sparse_residency16_samples: lhs
                .sparse_residency16_samples
                .bitand(&rhs.sparse_residency16_samples),
            sparse_residency_aliased: lhs
                .sparse_residency_aliased
                .bitand(&rhs.sparse_residency_aliased),
            variable_multisample_rate: lhs
                .variable_multisample_rate
                .bitand(&rhs.variable_multisample_rate),
            inherited_queries: lhs.inherited_queries.bitand(&rhs.inherited_queries),
        }
    }

    pub fn bitand_device_features11(
        lhs: &vk::PhysicalDeviceVulkan11Features,
        rhs: &vk::PhysicalDeviceVulkan11Features,
    ) -> vk::PhysicalDeviceVulkan11Features<'static> {
        use core::ops::BitAnd;
        vk::PhysicalDeviceVulkan11Features {
            storage_buffer16_bit_access: lhs
                .storage_buffer16_bit_access
                .bitand(&rhs.storage_buffer16_bit_access),
            uniform_and_storage_buffer16_bit_access: lhs
                .uniform_and_storage_buffer16_bit_access
                .bitand(&rhs.uniform_and_storage_buffer16_bit_access),
            storage_push_constant16: lhs
                .storage_push_constant16
                .bitand(&rhs.storage_push_constant16),
            storage_input_output16: lhs
                .storage_input_output16
                .bitand(&rhs.storage_input_output16),
            multiview: lhs.multiview.bitand(&rhs.multiview),
            multiview_geometry_shader: lhs
                .multiview_geometry_shader
                .bitand(&rhs.multiview_geometry_shader),
            multiview_tessellation_shader: lhs
                .multiview_tessellation_shader
                .bitand(&rhs.multiview_tessellation_shader),
            variable_pointers_storage_buffer: lhs
                .variable_pointers_storage_buffer
                .bitand(&rhs.variable_pointers_storage_buffer),
            variable_pointers: lhs.variable_pointers.bitand(&rhs.variable_pointers),
            protected_memory: lhs.protected_memory.bitand(&rhs.protected_memory),
            sampler_ycbcr_conversion: lhs
                .sampler_ycbcr_conversion
                .bitand(&rhs.sampler_ycbcr_conversion),
            shader_draw_parameters: lhs
                .shader_draw_parameters
                .bitand(&rhs.shader_draw_parameters),
            ..Default::default()
        }
    }

    pub fn bitand_device_features12(
        lhs: &vk::PhysicalDeviceVulkan12Features,
        rhs: &vk::PhysicalDeviceVulkan12Features,
    ) -> vk::PhysicalDeviceVulkan12Features<'static> {
        use core::ops::BitAnd;
        vk::PhysicalDeviceVulkan12Features {
            sampler_mirror_clamp_to_edge: lhs
                .sampler_mirror_clamp_to_edge
                .bitand(&rhs.sampler_mirror_clamp_to_edge),
            draw_indirect_count: lhs.draw_indirect_count.bitand(&rhs.draw_indirect_count),
            storage_buffer8_bit_access: lhs
                .storage_buffer8_bit_access
                .bitand(&rhs.storage_buffer8_bit_access),
            uniform_and_storage_buffer8_bit_access: lhs
                .uniform_and_storage_buffer8_bit_access
                .bitand(&rhs.uniform_and_storage_buffer8_bit_access),
            storage_push_constant8: lhs
                .storage_push_constant8
                .bitand(&rhs.storage_push_constant8),
            shader_buffer_int64_atomics: lhs
                .shader_buffer_int64_atomics
                .bitand(&rhs.shader_buffer_int64_atomics),
            shader_shared_int64_atomics: lhs
                .shader_shared_int64_atomics
                .bitand(&rhs.shader_shared_int64_atomics),
            shader_float16: lhs.shader_float16.bitand(&rhs.shader_float16),
            shader_int8: lhs.shader_int8.bitand(&rhs.shader_int8),
            descriptor_indexing: lhs.descriptor_indexing.bitand(&rhs.descriptor_indexing),
            shader_input_attachment_array_dynamic_indexing: lhs
                .shader_input_attachment_array_dynamic_indexing
                .bitand(&rhs.shader_input_attachment_array_dynamic_indexing),
            shader_uniform_texel_buffer_array_dynamic_indexing: lhs
                .shader_uniform_texel_buffer_array_dynamic_indexing
                .bitand(&rhs.shader_uniform_texel_buffer_array_dynamic_indexing),
            shader_storage_texel_buffer_array_dynamic_indexing: lhs
                .shader_storage_texel_buffer_array_dynamic_indexing
                .bitand(&rhs.shader_storage_texel_buffer_array_dynamic_indexing),
            shader_uniform_buffer_array_non_uniform_indexing: lhs
                .shader_uniform_buffer_array_non_uniform_indexing
                .bitand(&rhs.shader_uniform_buffer_array_non_uniform_indexing),
            shader_sampled_image_array_non_uniform_indexing: lhs
                .shader_sampled_image_array_non_uniform_indexing
                .bitand(&rhs.shader_sampled_image_array_non_uniform_indexing),
            shader_storage_buffer_array_non_uniform_indexing: lhs
                .shader_storage_buffer_array_non_uniform_indexing
                .bitand(&rhs.shader_storage_buffer_array_non_uniform_indexing),
            shader_storage_image_array_non_uniform_indexing: lhs
                .shader_storage_image_array_non_uniform_indexing
                .bitand(&rhs.shader_storage_image_array_non_uniform_indexing),
            shader_input_attachment_array_non_uniform_indexing: lhs
                .shader_input_attachment_array_non_uniform_indexing
                .bitand(&rhs.shader_input_attachment_array_non_uniform_indexing),
            shader_uniform_texel_buffer_array_non_uniform_indexing: lhs
                .shader_uniform_texel_buffer_array_non_uniform_indexing
                .bitand(&rhs.shader_uniform_texel_buffer_array_non_uniform_indexing),
            shader_storage_texel_buffer_array_non_uniform_indexing: lhs
                .shader_storage_texel_buffer_array_non_uniform_indexing
                .bitand(&rhs.shader_storage_texel_buffer_array_non_uniform_indexing),
            descriptor_binding_uniform_buffer_update_after_bind: lhs
                .descriptor_binding_uniform_buffer_update_after_bind
                .bitand(&rhs.descriptor_binding_uniform_buffer_update_after_bind),
            descriptor_binding_sampled_image_update_after_bind: lhs
                .descriptor_binding_sampled_image_update_after_bind
                .bitand(&rhs.descriptor_binding_sampled_image_update_after_bind),
            descriptor_binding_storage_image_update_after_bind: lhs
                .descriptor_binding_storage_image_update_after_bind
                .bitand(&rhs.descriptor_binding_storage_image_update_after_bind),
            descriptor_binding_storage_buffer_update_after_bind: lhs
                .descriptor_binding_storage_buffer_update_after_bind
                .bitand(&rhs.descriptor_binding_storage_buffer_update_after_bind),
            descriptor_binding_uniform_texel_buffer_update_after_bind: lhs
                .descriptor_binding_uniform_texel_buffer_update_after_bind
                .bitand(&rhs.descriptor_binding_uniform_texel_buffer_update_after_bind),
            descriptor_binding_storage_texel_buffer_update_after_bind: lhs
                .descriptor_binding_storage_texel_buffer_update_after_bind
                .bitand(&rhs.descriptor_binding_storage_texel_buffer_update_after_bind),
            descriptor_binding_update_unused_while_pending: lhs
                .descriptor_binding_update_unused_while_pending
                .bitand(&rhs.descriptor_binding_update_unused_while_pending),
            descriptor_binding_partially_bound: lhs
                .descriptor_binding_partially_bound
                .bitand(&rhs.descriptor_binding_partially_bound),
            descriptor_binding_variable_descriptor_count: lhs
                .descriptor_binding_variable_descriptor_count
                .bitand(&rhs.descriptor_binding_variable_descriptor_count),
            runtime_descriptor_array: lhs
                .runtime_descriptor_array
                .bitand(&rhs.runtime_descriptor_array),
            sampler_filter_minmax: lhs.sampler_filter_minmax.bitand(&rhs.sampler_filter_minmax),
            scalar_block_layout: lhs.scalar_block_layout.bitand(&rhs.scalar_block_layout),
            imageless_framebuffer: lhs.imageless_framebuffer.bitand(&rhs.imageless_framebuffer),
            uniform_buffer_standard_layout: lhs
                .uniform_buffer_standard_layout
                .bitand(&rhs.uniform_buffer_standard_layout),
            shader_subgroup_extended_types: lhs
                .shader_subgroup_extended_types
                .bitand(&rhs.shader_subgroup_extended_types),
            separate_depth_stencil_layouts: lhs
                .separate_depth_stencil_layouts
                .bitand(&rhs.separate_depth_stencil_layouts),
            host_query_reset: lhs.host_query_reset.bitand(&rhs.host_query_reset),
            timeline_semaphore: lhs.timeline_semaphore.bitand(&rhs.timeline_semaphore),
            buffer_device_address: lhs.buffer_device_address.bitand(&rhs.buffer_device_address),
            buffer_device_address_capture_replay: lhs
                .buffer_device_address_capture_replay
                .bitand(&rhs.buffer_device_address_capture_replay),
            buffer_device_address_multi_device: lhs
                .buffer_device_address_multi_device
                .bitand(&rhs.buffer_device_address_multi_device),
            vulkan_memory_model: lhs.vulkan_memory_model.bitand(&rhs.vulkan_memory_model),
            vulkan_memory_model_device_scope: lhs
                .vulkan_memory_model_device_scope
                .bitand(&rhs.vulkan_memory_model_device_scope),
            vulkan_memory_model_availability_visibility_chains: lhs
                .vulkan_memory_model_availability_visibility_chains
                .bitand(&rhs.vulkan_memory_model_availability_visibility_chains),
            shader_output_viewport_index: lhs
                .shader_output_viewport_index
                .bitand(&rhs.shader_output_viewport_index),
            shader_output_layer: lhs.shader_output_layer.bitand(&rhs.shader_output_layer),
            subgroup_broadcast_dynamic_id: lhs
                .subgroup_broadcast_dynamic_id
                .bitand(&rhs.subgroup_broadcast_dynamic_id),
            ..Default::default()
        }
    }
    pub fn bitand_device_features13(
        lhs: &vk::PhysicalDeviceVulkan13Features,
        rhs: &vk::PhysicalDeviceVulkan13Features,
    ) -> vk::PhysicalDeviceVulkan13Features<'static> {
        use core::ops::BitAnd;
        vk::PhysicalDeviceVulkan13Features {
            robust_image_access: lhs.robust_image_access.bitand(&rhs.robust_image_access),
            inline_uniform_block: lhs.inline_uniform_block.bitand(&rhs.inline_uniform_block),
            descriptor_binding_inline_uniform_block_update_after_bind: lhs
                .descriptor_binding_inline_uniform_block_update_after_bind
                .bitand(&rhs.descriptor_binding_inline_uniform_block_update_after_bind),
            pipeline_creation_cache_control: lhs
                .pipeline_creation_cache_control
                .bitand(&rhs.pipeline_creation_cache_control),
            private_data: lhs.private_data.bitand(&rhs.private_data),
            shader_demote_to_helper_invocation: lhs
                .shader_demote_to_helper_invocation
                .bitand(&rhs.shader_demote_to_helper_invocation),
            shader_terminate_invocation: lhs
                .shader_terminate_invocation
                .bitand(&rhs.shader_terminate_invocation),
            subgroup_size_control: lhs.subgroup_size_control.bitand(&rhs.subgroup_size_control),
            compute_full_subgroups: lhs
                .compute_full_subgroups
                .bitand(&rhs.compute_full_subgroups),
            synchronization2: lhs.synchronization2.bitand(&rhs.synchronization2),
            texture_compression_astc_hdr: lhs
                .texture_compression_astc_hdr
                .bitand(&rhs.texture_compression_astc_hdr),
            shader_zero_initialize_workgroup_memory: lhs
                .shader_zero_initialize_workgroup_memory
                .bitand(&rhs.shader_zero_initialize_workgroup_memory),
            dynamic_rendering: lhs.dynamic_rendering.bitand(&rhs.dynamic_rendering),
            shader_integer_dot_product: lhs
                .shader_integer_dot_product
                .bitand(&rhs.shader_integer_dot_product),
            maintenance4: lhs.maintenance4.bitand(&rhs.maintenance4),
            ..Default::default()
        }
    }
}
