use {
    crate::{
        allocator::BufferObject,
        eventfd_cache::EventfdCache,
        format::XRGB8888,
        gfx_apis::vulkan::{
            VulkanError,
            format::{VulkanBlendBufferLimits, VulkanFormat},
            instance::VulkanInstance,
        },
        utils::{bitflags::BitflagsExt, oserror::OsErrorExt2},
        video::{
            dmabuf::DmaBufIds,
            drm::{Drm, syncobj::SyncobjCtx},
            gbm::{GBM_BO_USE_RENDERING, GbmDevice},
        },
        vulkan_core::{
            ApiVersionDisplay, Extensions, VULKAN_API_VERSION, VulkanCoreInstance,
            device::VulkanDeviceInf, map_extension_properties,
        },
    },
    ahash::AHashMap,
    arrayvec::ArrayVec,
    ash::{
        Device,
        ext::{
            descriptor_buffer, external_memory_dma_buf, image_drm_format_modifier,
            physical_device_drm, queue_family_foreign,
        },
        khr::{
            self, driver_properties, external_fence_fd, external_memory_fd, external_semaphore_fd,
            push_descriptor,
        },
        vk::{
            self, DeviceCreateInfo, DeviceQueueCreateInfo, DeviceQueueGlobalPriorityCreateInfoKHR,
            DeviceSize, DriverId, ExternalSemaphoreFeatureFlags, ExternalSemaphoreHandleTypeFlags,
            ExternalSemaphoreProperties, MAX_MEMORY_TYPES, MemoryPropertyFlags, MemoryType,
            PhysicalDevice, PhysicalDeviceBufferDeviceAddressFeatures,
            PhysicalDeviceDescriptorBufferFeaturesEXT, PhysicalDeviceDescriptorBufferPropertiesEXT,
            PhysicalDeviceDriverProperties, PhysicalDeviceDriverPropertiesKHR,
            PhysicalDeviceDrmPropertiesEXT, PhysicalDeviceDynamicRenderingFeatures,
            PhysicalDeviceExternalSemaphoreInfo, PhysicalDeviceProperties,
            PhysicalDeviceProperties2, PhysicalDeviceSynchronization2Features,
            PhysicalDeviceTimelineSemaphoreFeatures, PhysicalDeviceType,
            PhysicalDeviceUniformBufferStandardLayoutFeatures, PhysicalDeviceVulkan12Properties,
            Queue, QueueFamilyProperties2, QueueFlags, QueueGlobalPriorityKHR,
        },
    },
    isnt::std_1::collections::IsntHashMapExt,
    run_on_drop::on_drop,
    std::{
        cell::Cell,
        ffi::{CStr, CString},
        rc::Rc,
        sync::Arc,
    },
    uapi::{Ustr, c::O_RDWR},
    vk::QueueFamilyGlobalPriorityPropertiesKHR,
};

pub struct VulkanDevice {
    pub(super) physical_device: PhysicalDevice,
    pub(super) render_node: Rc<CString>,
    pub(super) gbm: Rc<GbmDevice>,
    pub(super) sync_ctx: Rc<SyncobjCtx>,
    pub(super) instance: Rc<VulkanInstance>,
    pub(super) device: Arc<Device>,
    pub(super) eventfd_cache: Rc<EventfdCache>,
    pub(super) external_memory_fd: external_memory_fd::Device,
    pub(super) external_semaphore_fd: external_semaphore_fd::Device,
    pub(super) external_fence_fd: external_fence_fd::Device,
    pub(super) push_descriptor: push_descriptor::Device,
    pub(super) image_drm_format_modifier: image_drm_format_modifier::Device,
    pub(super) descriptor_buffer: Option<descriptor_buffer::Device>,
    pub(super) formats: AHashMap<u32, VulkanFormat>,
    pub(super) blend_limits: VulkanBlendBufferLimits,
    pub(super) memory_types: ArrayVec<MemoryType, MAX_MEMORY_TYPES>,
    pub(super) graphics_queue: Queue,
    pub(super) graphics_queue_idx: u32,
    pub(super) transfer_queue: Option<Queue>,
    pub(super) distinct_transfer_queue_family_idx: Option<u32>,
    pub(super) transfer_granularity_mask: (u32, u32),
    pub(super) descriptor_buffer_offset_mask: DeviceSize,
    pub(super) sampler_descriptor_size: usize,
    pub(super) sampled_image_descriptor_size: usize,
    pub(super) is_anv: bool,
    pub(super) uniform_buffer_offset_mask: DeviceSize,
    pub(super) uniform_buffer_descriptor_size: usize,
    pub(super) lost: Cell<bool>,
    pub(super) fast_ram_access: bool,
    pub(super) supports_timeline_opaque_export: bool,
}

impl Drop for VulkanDevice {
    fn drop(&mut self) {
        unsafe {
            self.device.destroy_device(None);
        }
    }
}

impl VulkanDevice {
    pub(super) fn find_memory_type(
        &self,
        flags: MemoryPropertyFlags,
        memory_type_bits: u32,
    ) -> Option<u32> {
        for (idx, ty) in self.memory_types.iter().enumerate() {
            if memory_type_bits & (1 << idx as u32) != 0 {
                if ty.property_flags.contains(flags) {
                    return Some(idx as _);
                }
            }
        }
        None
    }

    #[inline(always)]
    pub(super) fn idl(&self) -> impl Fn(&vk::Result) + use<'_> {
        |res| {
            if *res == vk::Result::ERROR_DEVICE_LOST {
                self.lost.set(true);
            }
        }
    }
}

impl VulkanInstance {
    fn get_device_extensions(&self, phy_dev: PhysicalDevice) -> Result<Extensions, VulkanError> {
        unsafe {
            self.instance
                .enumerate_device_extension_properties(phy_dev)
                .map(map_extension_properties)
                .map_err(VulkanError::DeviceExtensions)
        }
    }

    fn find_dev(&self, drm: &Drm) -> Result<(PhysicalDevice, PhysicalDeviceType), VulkanError> {
        let dev = drm.dev();
        log::log!(
            self.log_level,
            "Searching for vulkan device with devnum {}:{}",
            uapi::major(dev),
            uapi::minor(dev)
        );
        let phy_devs = unsafe { self.instance.enumerate_physical_devices() };
        let phy_devs = match phy_devs {
            Ok(d) => d,
            Err(e) => return Err(VulkanError::EnumeratePhysicalDevices(e)),
        };
        let mut devices = vec![];
        for phy_dev in phy_devs {
            let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
            if props.api_version < VULKAN_API_VERSION {
                devices.push((props, None, None));
                continue;
            }
            let extensions = match self.get_device_extensions(phy_dev) {
                Ok(e) => e,
                Err(e) => {
                    log::error!(
                        "Could not enumerate extensions of device with id {}: {:#}",
                        props.device_id,
                        e
                    );
                    devices.push((props, None, None));
                    continue;
                }
            };
            if !extensions.contains_key(physical_device_drm::NAME) {
                devices.push((props, Some(extensions), None));
                continue;
            }
            let has_driver_props = extensions.contains_key(driver_properties::NAME);
            let mut drm_props = PhysicalDeviceDrmPropertiesEXT::default();
            let mut driver_props = PhysicalDeviceDriverPropertiesKHR::default();
            let mut props2 = PhysicalDeviceProperties2::default().push_next(&mut drm_props);
            if has_driver_props {
                props2 = props2.push_next(&mut driver_props);
            }
            unsafe {
                self.instance
                    .get_physical_device_properties2(phy_dev, &mut props2);
            }
            let primary_dev =
                uapi::makedev(drm_props.primary_major as _, drm_props.primary_minor as _);
            let render_dev =
                uapi::makedev(drm_props.render_major as _, drm_props.render_minor as _);
            if primary_dev == dev || render_dev == dev {
                log::log!(self.log_level, "Device with id {} matches", props.device_id);
                log_device(
                    self.log_level,
                    &props,
                    Some(&extensions),
                    Some(&driver_props),
                );
                return Ok((phy_dev, props.device_type));
            }
            devices.push((props, Some(extensions), Some(driver_props)));
        }
        if devices.is_empty() {
            log::warn!("Found no devices");
        } else {
            log::warn!("Found the following devices but none matches:");
            for (props, extensions, driver_props) in devices.iter() {
                log::warn!("-----");
                log_device(
                    self.log_level,
                    props,
                    extensions.as_ref(),
                    driver_props.as_ref(),
                );
            }
        }
        Err(VulkanError::NoDeviceFound(dev))
    }

    fn find_software_renderer(&self) -> Result<(PhysicalDevice, PhysicalDeviceType), VulkanError> {
        let phy_devs = unsafe { self.instance.enumerate_physical_devices() };
        let phy_devs = match phy_devs {
            Ok(d) => d,
            Err(e) => return Err(VulkanError::EnumeratePhysicalDevices(e)),
        };
        for phy_dev in phy_devs {
            let props = unsafe { self.instance.get_physical_device_properties(phy_dev) };
            if props.api_version < VULKAN_API_VERSION {
                continue;
            }
            if props.device_type == PhysicalDeviceType::CPU {
                return Ok((phy_dev, props.device_type));
            }
        }
        Err(VulkanError::NoSoftwareRenderer)
    }

    fn find_queues(
        &self,
        phy_dev: PhysicalDevice,
    ) -> Result<
        (
            u32,
            Option<(u32, u32, u32)>,
            QueueGlobalPriorityKHR,
            QueueGlobalPriorityKHR,
        ),
        VulkanError,
    > {
        let len = unsafe {
            self.instance
                .get_physical_device_queue_family_properties2_len(phy_dev)
        };
        let mut priority_props = vec![QueueFamilyGlobalPriorityPropertiesKHR::default(); len];
        let mut props: Vec<_> = priority_props
            .iter_mut()
            .map(|p| QueueFamilyProperties2::default().push_next(p))
            .collect();
        unsafe {
            self.instance
                .get_physical_device_queue_family_properties2(phy_dev, &mut props[..])
        }
        let gfx_queue = props
            .iter()
            .position(|p| {
                p.queue_family_properties
                    .queue_flags
                    .contains(QueueFlags::GRAPHICS)
            })
            .ok_or(VulkanError::NoGraphicsQueue)?;
        let transfer_queue = 'transfer: {
            let mut transfer_only = None;
            let mut compute_only = None;
            let mut separate_gfx = None;
            for (idx, props) in props.iter().enumerate() {
                let props = &props.queue_family_properties;
                if idx == gfx_queue {
                    continue;
                }
                let g = &props.min_image_transfer_granularity;
                if g.width == 0 || g.height == 0 {
                    continue;
                }
                let f = props.queue_flags;
                use QueueFlags as F;
                if !f.intersects(F::GRAPHICS | F::COMPUTE) && f.intersects(F::TRANSFER) {
                    transfer_only = Some(idx);
                } else if !f.intersects(F::GRAPHICS) && f.intersects(F::COMPUTE) {
                    compute_only = Some(idx);
                } else if f.intersects(F::GRAPHICS) {
                    separate_gfx = Some(idx);
                }
            }
            if let Some(idx) = transfer_only.or(compute_only).or(separate_gfx) {
                break 'transfer Some(idx);
            }
            if props[gfx_queue].queue_family_properties.queue_count > 1 {
                break 'transfer Some(gfx_queue);
            }
            None
        };
        let mut width_mask = 0;
        let mut height_mask = 0;
        if let Some(idx) = transfer_queue {
            let g = &props[idx]
                .queue_family_properties
                .min_image_transfer_granularity;
            width_mask = g.width.wrapping_sub(1);
            height_mask = g.height.wrapping_sub(1);
        }
        let get_priority = |idx: usize| {
            let props = &priority_props[idx];
            if props.priority_count > 0 {
                props.priorities[props.priority_count as usize - 1]
            } else {
                QueueGlobalPriorityKHR::MEDIUM
            }
        };
        Ok((
            gfx_queue as _,
            transfer_queue.map(|v| (v as _, width_mask, height_mask)),
            get_priority(gfx_queue),
            transfer_queue
                .map(get_priority)
                .unwrap_or(QueueGlobalPriorityKHR::MEDIUM),
        ))
    }

    fn supports_semaphore_import(&self, phy_dev: PhysicalDevice) -> bool {
        let mut props = ExternalSemaphoreProperties::default();
        let info = PhysicalDeviceExternalSemaphoreInfo::default()
            .handle_type(ExternalSemaphoreHandleTypeFlags::SYNC_FD);
        unsafe {
            self.instance
                .get_physical_device_external_semaphore_properties(phy_dev, &info, &mut props);
        }
        props
            .external_semaphore_features
            .contains(ExternalSemaphoreFeatureFlags::IMPORTABLE)
    }

    pub fn create_device(
        self: &Rc<Self>,
        drm: &Drm,
        eventfd_cache: &Rc<EventfdCache>,
        mut high_priority: bool,
        software: bool,
    ) -> Result<Rc<VulkanDevice>, VulkanError> {
        let render_node = drm
            .get_render_node()
            .map_err(VulkanError::FetchRenderNode)?
            .ok_or(VulkanError::NoRenderNode)
            .map(Rc::new)?;
        let gbm = GbmDevice::new(drm).map_err(VulkanError::Gbm)?;
        let (phy_dev, dev_ty) = match software {
            true => self.find_software_renderer()?,
            false => self.find_dev(drm)?,
        };
        let extensions = self.get_device_extensions(phy_dev)?;
        for &ext in REQUIRED_DEVICE_EXTENSIONS {
            if extensions.not_contains_key(ext) {
                return Err(VulkanError::MissingDeviceExtension(ext));
            }
        }
        let supports_descriptor_buffer = extensions.contains_key(descriptor_buffer::NAME);
        if !supports_descriptor_buffer {
            log::warn!("Vulkan device does not support descriptor buffers");
        }
        let supports_queue_priority = extensions.contains_key(khr::global_priority::NAME);
        if !supports_queue_priority && high_priority {
            high_priority = false;
            log::warn!("Vulkan device does not support queue priorities");
        }
        let (
            graphics_queue_family_idx,
            transfer_queue_family,
            max_graphics_priority,
            max_transfer_priority,
        ) = self.find_queues(phy_dev)?;
        let mut distinct_transfer_queue_family_idx = None;
        let mut transfer_granularity_mask = (0, 0);
        if let Some((idx, width_mask, height_mask)) = transfer_queue_family {
            if idx != graphics_queue_family_idx {
                distinct_transfer_queue_family_idx = Some(idx);
            }
            transfer_granularity_mask = (width_mask, height_mask);
        }
        let features = self.get_features(phy_dev);
        let supports_timeline_opaque_export =
            self.supports_timeline_opaque_export(phy_dev, &features);
        if !self.supports_semaphore_import(phy_dev) {
            return Err(VulkanError::SyncFileImport);
        }
        let mut enabled_extensions: Vec<_> = REQUIRED_DEVICE_EXTENSIONS
            .iter()
            .map(|n| n.as_ptr())
            .collect();
        if supports_descriptor_buffer {
            enabled_extensions.push(descriptor_buffer::NAME.as_ptr());
        }
        let mut semaphore_features = PhysicalDeviceTimelineSemaphoreFeatures::default()
            .timeline_semaphore(supports_timeline_opaque_export);
        let mut synchronization2_features =
            PhysicalDeviceSynchronization2Features::default().synchronization2(true);
        let mut dynamic_rendering_features =
            PhysicalDeviceDynamicRenderingFeatures::default().dynamic_rendering(true);
        let mut descriptor_buffer_features =
            PhysicalDeviceDescriptorBufferFeaturesEXT::default().descriptor_buffer(true);
        let mut buffer_device_address_features =
            PhysicalDeviceBufferDeviceAddressFeatures::default().buffer_device_address(true);
        let mut uniform_buffer_standard_layout_features =
            PhysicalDeviceUniformBufferStandardLayoutFeatures::default()
                .uniform_buffer_standard_layout(true);
        let mut gfx_queue_device_queue_global_priority_create_info =
            DeviceQueueGlobalPriorityCreateInfoKHR::default()
                .global_priority(max_graphics_priority);
        let mut trn_queue_device_queue_global_priority_create_info =
            DeviceQueueGlobalPriorityCreateInfoKHR::default()
                .global_priority(max_transfer_priority);
        let mut queue_create_infos = ArrayVec::<_, 2>::new();
        let queue_create_info = |idx, priority_info| {
            let mut info = DeviceQueueCreateInfo::default()
                .queue_family_index(idx)
                .queue_priorities(&[1.0]);
            if high_priority {
                info = info.push_next(priority_info);
            }
            info
        };
        queue_create_infos.push(queue_create_info(
            graphics_queue_family_idx,
            &mut gfx_queue_device_queue_global_priority_create_info,
        ));
        if let Some((tq, _, _)) = transfer_queue_family {
            queue_create_infos.push(queue_create_info(
                tq,
                &mut trn_queue_device_queue_global_priority_create_info,
            ));
        }
        let mut device_create_info = DeviceCreateInfo::default()
            .push_next(&mut semaphore_features)
            .push_next(&mut synchronization2_features)
            .push_next(&mut dynamic_rendering_features)
            .push_next(&mut uniform_buffer_standard_layout_features)
            .queue_create_infos(&queue_create_infos)
            .enabled_extension_names(&enabled_extensions);
        if supports_descriptor_buffer {
            device_create_info = device_create_info
                .push_next(&mut descriptor_buffer_features)
                .push_next(&mut buffer_device_address_features);
        }
        let device = unsafe {
            self.instance
                .create_device(phy_dev, &device_create_info, None)
        };
        let device = match device {
            Ok(d) => d,
            Err(e) => return Err(VulkanError::CreateDevice(e)),
        };
        let destroy_device = on_drop(|| unsafe { device.destroy_device(None) });
        let blend_limits = self.load_blend_format_limits(phy_dev)?;
        let formats = self.load_formats(phy_dev)?;
        let supports_xrgb8888 = formats
            .get(&XRGB8888.drm)
            .map(|f| {
                let mut supports_rendering = false;
                let mut supports_texturing = false;
                f.modifiers.values().for_each(|v| {
                    supports_rendering |= v.render_limits.is_some();
                    supports_texturing |= v.texture_limits.is_some();
                });
                supports_rendering && supports_texturing
            })
            .unwrap_or(false);
        if !supports_xrgb8888 {
            return Err(VulkanError::XRGB8888);
        }
        if software {
            let bo = gbm
                .create_bo(
                    &DmaBufIds::default(),
                    1,
                    1,
                    XRGB8888,
                    formats.get(&XRGB8888.drm).unwrap().modifiers.keys(),
                    GBM_BO_USE_RENDERING,
                )
                .map_err(VulkanError::AllocGbm)?;
            let fl =
                uapi::fcntl_getfl(bo.dmabuf().planes[0].fd.raw()).map_os_err(VulkanError::GetFl)?;
            if fl.not_contains(O_RDWR) {
                return Err(VulkanError::SoftwareRendererNotUsable);
            }
        }
        destroy_device.forget();
        let external_memory_fd = external_memory_fd::Device::new(&self.instance, &device);
        let external_semaphore_fd = external_semaphore_fd::Device::new(&self.instance, &device);
        let external_fence_fd = external_fence_fd::Device::new(&self.instance, &device);
        let push_descriptor = push_descriptor::Device::new(&self.instance, &device);
        let image_drm_format_modifier =
            image_drm_format_modifier::Device::new(&self.instance, &device);
        let descriptor_buffer = supports_descriptor_buffer
            .then(|| descriptor_buffer::Device::new(&self.instance, &device));
        let mut descriptor_buffer_props = PhysicalDeviceDescriptorBufferPropertiesEXT::default();
        let mut physical_device_vulkan12_properties = PhysicalDeviceVulkan12Properties::default();
        let mut physical_device_properties2 = PhysicalDeviceProperties2::default()
            .push_next(&mut physical_device_vulkan12_properties);
        if supports_descriptor_buffer {
            physical_device_properties2 =
                physical_device_properties2.push_next(&mut descriptor_buffer_props);
        }
        unsafe {
            self.instance
                .get_physical_device_properties2(phy_dev, &mut physical_device_properties2);
        }
        let mut descriptor_buffer_offset_mask = 0;
        let mut sampler_descriptor_size = 0;
        let mut sampled_image_descriptor_size = 0;
        let mut uniform_buffer_descriptor_size = 0;
        let uniform_buffer_offset_mask = physical_device_properties2
            .properties
            .limits
            .min_uniform_buffer_offset_alignment
            .checked_next_power_of_two()
            .unwrap()
            - 1;
        if supports_descriptor_buffer {
            descriptor_buffer_offset_mask = descriptor_buffer_props
                .descriptor_buffer_offset_alignment
                .checked_next_power_of_two()
                .unwrap()
                - 1;
            sampler_descriptor_size = descriptor_buffer_props.sampler_descriptor_size;
            sampled_image_descriptor_size = descriptor_buffer_props.sampled_image_descriptor_size;
            uniform_buffer_descriptor_size = descriptor_buffer_props.uniform_buffer_descriptor_size;
        }
        let memory_properties =
            unsafe { self.instance.get_physical_device_memory_properties(phy_dev) };
        let memory_types = memory_properties.memory_types
            [..memory_properties.memory_type_count as _]
            .iter()
            .copied()
            .collect();
        let graphics_queue = unsafe { device.get_device_queue(graphics_queue_family_idx, 0) };
        let transfer_queue = transfer_queue_family.map(|(family_idx, _, _)| {
            let queue_idx = match family_idx == graphics_queue_family_idx {
                true => 1,
                false => 0,
            };
            unsafe { device.get_device_queue(family_idx, queue_idx) }
        });
        if high_priority {
            log::info!(
                "Created queues with priorities {max_graphics_priority:?}/{max_transfer_priority:?}",
            );
        }
        let fast_ram_access = match dev_ty {
            PhysicalDeviceType::CPU => true,
            PhysicalDeviceType::INTEGRATED_GPU => true,
            _ => false,
        };
        Ok(Rc::new(VulkanDevice {
            physical_device: phy_dev,
            render_node,
            sync_ctx: Rc::new(SyncobjCtx::new(gbm.drm.fd())),
            gbm: Rc::new(gbm),
            instance: self.clone(),
            device: Arc::new(device),
            eventfd_cache: eventfd_cache.clone(),
            external_memory_fd,
            external_semaphore_fd,
            external_fence_fd,
            push_descriptor,
            image_drm_format_modifier,
            descriptor_buffer,
            formats,
            memory_types,
            graphics_queue,
            graphics_queue_idx: graphics_queue_family_idx,
            transfer_queue,
            distinct_transfer_queue_family_idx,
            transfer_granularity_mask,
            descriptor_buffer_offset_mask,
            sampler_descriptor_size,
            sampled_image_descriptor_size,
            blend_limits,
            is_anv: physical_device_vulkan12_properties.driver_id
                == DriverId::INTEL_OPEN_SOURCE_MESA,
            uniform_buffer_offset_mask,
            uniform_buffer_descriptor_size,
            lost: Cell::new(false),
            fast_ram_access,
            supports_timeline_opaque_export,
        }))
    }
}

const REQUIRED_DEVICE_EXTENSIONS: &[&CStr] = &[
    external_memory_fd::NAME,
    external_semaphore_fd::NAME,
    external_fence_fd::NAME,
    external_memory_dma_buf::NAME,
    queue_family_foreign::NAME,
    image_drm_format_modifier::NAME,
    push_descriptor::NAME,
];

fn log_device(
    level: log::Level,
    props: &PhysicalDeviceProperties,
    extensions: Option<&Extensions>,
    driver_props: Option<&PhysicalDeviceDriverProperties>,
) {
    log::log!(
        level,
        "  api version: {}",
        ApiVersionDisplay(props.api_version)
    );
    log::log!(
        level,
        "  driver version: {}",
        ApiVersionDisplay(props.driver_version)
    );
    log::log!(level, "  vendor id: {}", props.vendor_id);
    log::log!(level, "  device id: {}", props.device_id);
    log::log!(level, "  device type: {:?}", props.device_type);
    unsafe {
        log::log!(
            level,
            "  device name: {}",
            Ustr::from_ptr(props.device_name.as_ptr()).display()
        );
    }
    if props.api_version < VULKAN_API_VERSION {
        log::warn!("  device does not support vulkan 1.3");
    }
    if let Some(extensions) = extensions {
        if !extensions.contains_key(physical_device_drm::NAME) {
            log::warn!("  device does support not the VK_EXT_physical_device_drm extension");
        }
    }
    if let Some(driver_props) = driver_props {
        unsafe {
            log::log!(
                level,
                "  driver: {} ({})",
                Ustr::from_ptr(driver_props.driver_name.as_ptr()).display(),
                Ustr::from_ptr(driver_props.driver_info.as_ptr()).display()
            );
        }
    }
}

impl VulkanDeviceInf for VulkanDevice {
    fn instance(&self) -> &VulkanCoreInstance {
        &self.instance
    }

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

    fn external_fence_fd(&self) -> &external_fence_fd::Device {
        &self.external_fence_fd
    }

    fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device {
        &self.external_semaphore_fd
    }

    fn supports_timeline_opaque_export(&self) -> bool {
        self.supports_timeline_opaque_export
    }

    fn sync_ctx(&self) -> Option<&Rc<SyncobjCtx>> {
        Some(&self.sync_ctx)
    }

    fn eventfd_cache(&self) -> &Rc<EventfdCache> {
        &self.eventfd_cache
    }
}
