#[cfg(windows)]
use std::marker::PhantomData;
use std::path::PathBuf;
use serde::Deserialize;
use serde::Deserializer;
use serde::Serialize;
use serde::Serializer;
use serde_keyvalue::FromKeyValues;
use vm_control::gpu::DisplayParameters;
use super::GpuMode;
use super::GpuWsi;
use crate::virtio::gpu::VIRTIO_GPU_MAX_SCANOUTS;
use crate::PciAddress;
mod serde_capset_mask {
    use super::*;
    pub fn serialize<S>(capset_mask: &u64, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let context_types = rutabaga_gfx::calculate_capset_names(*capset_mask).join(":");
        serializer.serialize_str(context_types.as_str())
    }
    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u64, D::Error> {
        let s = String::deserialize(deserializer)?;
        Ok(rutabaga_gfx::calculate_capset_mask(s.split(':')))
    }
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AudioDeviceMode {
    #[serde(rename = "per-surface")]
    PerSurface,
    #[serde(rename = "one-global")]
    OneGlobal,
}
#[derive(Clone, Debug, Serialize, Deserialize, FromKeyValues)]
#[serde(deny_unknown_fields, default, rename_all = "kebab-case")]
pub struct GpuParameters {
    #[serde(rename = "backend")]
    pub mode: GpuMode,
    #[serde(default = "default_max_num_displays")]
    pub max_num_displays: u32,
    #[serde(default = "default_audio_device_mode")]
    pub audio_device_mode: AudioDeviceMode,
    #[serde(rename = "displays")]
    pub display_params: Vec<DisplayParameters>,
    #[serde(rename = "width")]
    pub __width_compat: Option<u32>,
    #[serde(rename = "height")]
    pub __height_compat: Option<u32>,
    #[serde(rename = "egl")]
    pub renderer_use_egl: bool,
    #[serde(rename = "gles")]
    pub renderer_use_gles: bool,
    #[serde(rename = "glx")]
    pub renderer_use_glx: bool,
    #[serde(rename = "surfaceless")]
    pub renderer_use_surfaceless: bool,
    #[serde(rename = "vulkan")]
    pub use_vulkan: Option<bool>,
    pub wsi: Option<GpuWsi>,
    pub udmabuf: bool,
    pub cache_path: Option<String>,
    pub cache_size: Option<String>,
    pub pci_address: Option<PciAddress>,
    pub pci_bar_size: u64,
    #[serde(rename = "context-types", with = "serde_capset_mask")]
    pub capset_mask: u64,
    pub external_blob: bool,
    pub system_blob: bool,
    pub fixed_blob_mapping: bool,
    #[serde(rename = "implicit-render-server")]
    pub allow_implicit_render_server_exec: bool,
    pub renderer_features: Option<String>,
    pub snapshot_scratch_path: Option<PathBuf>,
}
impl Default for GpuParameters {
    fn default() -> Self {
        GpuParameters {
            max_num_displays: default_max_num_displays(),
            audio_device_mode: default_audio_device_mode(),
            display_params: vec![],
            __width_compat: None,
            __height_compat: None,
            renderer_use_egl: true,
            renderer_use_gles: true,
            renderer_use_glx: false,
            renderer_use_surfaceless: true,
            use_vulkan: None,
            mode: Default::default(),
            wsi: None,
            cache_path: None,
            cache_size: None,
            pci_address: None,
            pci_bar_size: (1 << 33),
            udmabuf: false,
            capset_mask: 0,
            external_blob: false,
            system_blob: false,
            fixed_blob_mapping: false,
            allow_implicit_render_server_exec: false,
            renderer_features: None,
            snapshot_scratch_path: None,
        }
    }
}
fn default_max_num_displays() -> u32 {
    VIRTIO_GPU_MAX_SCANOUTS as u32
}
fn default_audio_device_mode() -> AudioDeviceMode {
    AudioDeviceMode::PerSurface
}
#[cfg(test)]
mod tests {
    use serde_json::*;
    use super::*;
    #[test]
    fn capset_mask_serialize_deserialize() {
        #[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
        struct CapsetMask {
            #[serde(rename = "context-types", with = "serde_capset_mask")]
            pub value: u64,
        }
        const CAPSET_MASK: u64 = 0b1010;
        const SERIALIZED_CAPSET_MASK: &str = "{\"context-types\":\"virgl:gfxstream-vulkan\"}";
        let capset_mask = CapsetMask { value: CAPSET_MASK };
        assert_eq!(to_string(&capset_mask).unwrap(), SERIALIZED_CAPSET_MASK);
        assert_eq!(
            from_str::<CapsetMask>(SERIALIZED_CAPSET_MASK).unwrap(),
            capset_mask
        );
    }
}