pipewire_native_spa/interface/
cpu.rs

1// SPDX-License-Identifier: MIT
2// SPDX-FileCopyrightText: Copyright (c) 2025 Asymptotic Inc.
3// SPDX-FileCopyrightText: Copyright (c) 2025 Sanchayan Maity
4
5use bitflags::bitflags;
6use std::{any::Any, pin::Pin};
7
8use pipewire_native_macros::EnumU32;
9
10use super::plugin::Interface;
11
12pub const FORCE: &str = "cpu.force";
13pub const VM: &str = "cpu.vm";
14
15bitflags! {
16    #[repr(C)]
17    #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumU32)]
18    pub struct X86CpuFlags: u32 {
19        const MMX            = (1<<0);	/* standard MMX */
20        const MMXEXT         = (1<<1);	/* SSE integer or AMD MMX ext */
21        const AMD_3DNOW      = (1<<2);	/* AMD 3DNOW */
22        const SSE            = (1<<3);	/* SSE */
23        const SSE2           = (1<<4);	/* SSE2 */
24        const AMD_3DNOWEXT   = (1<<5);	/* AMD 3DNowExt */
25        const SSE3           = (1<<6);	/* Prescott SSE3 */
26        const SSSE3          = (1<<7);	/* Conroe SSSE3 */
27        const SSE41          = (1<<8);	/* Penryn SSE4.1 */
28        const SSE42          = (1<<9);	/* Nehalem SSE4.2 */
29        const AESNI          = (1<<10);	/* Advanced Encryption Standard */
30        const AVX            = (1<<11);	/* AVX */
31        const XOP            = (1<<12);	/* Bulldozer XOP */
32        const FMA4           = (1<<13);	/* Bulldozer FMA4 */
33        const CMOV           = (1<<14);	/* supports cmov */
34        const AVX2           = (1<<15);	/* AVX2 */
35        const FMA3           = (1<<16);	/* Haswell FMA3 */
36        const BMI1           = (1<<17);	/* Bit Manipulation Instruction Set 1 */
37        const BMI2           = (1<<18);	/* Bit Manipulation Instruction Set 2 */
38        const AVX512         = (1<<19);	/* AVX-512 */
39        const SLOW_UNALIGNED = (1<<20);	/* unaligned loads/stores are slow */
40        const _              = !0;      /* The source may set any bits */
41    }
42}
43
44bitflags! {
45    #[repr(C)]
46    #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumU32)]
47    pub struct PpcCpuFlags: u32 {
48        const ALTIVEC = (1<<0);	/* standard */
49        const VSX     = (1<<1);	/* ISA 2.06 */
50        const POWER8  = (1<<2);	/* ISA 2.07 */
51        const _       = !0;     /* The source may set any bits */
52    }
53}
54
55bitflags! {
56    #[repr(C)]
57    #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumU32)]
58    pub struct ArmCpuFlags : u32 {
59        const ARMV5TE = (1 << 0);
60        const ARMV6   = (1 << 1);
61        const ARMV6T2 = (1 << 2);
62        const VFP     = (1 << 3);
63        const VFPV3   = (1 << 4);
64        const NEON    = (1 << 5);
65        const ARMV8   = (1 << 6);
66        const _       = !0;       /* The source may set any bits */
67    }
68}
69
70bitflags! {
71    #[repr(C)]
72    #[derive(Debug, Clone, Copy, PartialEq, Eq, EnumU32)]
73    pub struct RiscvCpuFlags : u32 {
74        const RISCV_V = (1 << 0);
75        const _       = !0;       /* The source may set any bits */
76    }
77}
78
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub enum CpuFlags {
81    X86(X86CpuFlags),
82    Arm(ArmCpuFlags),
83    Ppc(PpcCpuFlags),
84    Riscv(RiscvCpuFlags),
85}
86
87impl TryFrom<u32> for CpuFlags {
88    type Error = ();
89
90    fn try_from(value: u32) -> Result<Self, Self::Error> {
91        #[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
92        return Ok(CpuFlags::X86(X86CpuFlags::from_bits(value).ok_or(())?));
93        #[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
94        return Ok(CpuFlags::Arm(ArmCpuFlags::from_bits(value).ok_or(())?));
95        #[cfg(any(target_arch = "powerpc64", target_arch = "powerpc"))]
96        return Ok(CpuFlags::Ppc(PpcCpuFlags::from_bits(value).ok_or(())?));
97        #[cfg(target_arch = "riscv64")]
98        return Ok(CpuFlags::Riscv(RiscvCpuFlags::from_bits(value).ok_or(())?));
99    }
100}
101
102impl From<CpuFlags> for u32 {
103    fn from(value: CpuFlags) -> Self {
104        match value {
105            CpuFlags::X86(flags) => flags.bits(),
106            CpuFlags::Arm(flags) => flags.bits(),
107            CpuFlags::Ppc(flags) => flags.bits(),
108            CpuFlags::Riscv(flags) => flags.bits(),
109        }
110    }
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq, EnumU32)]
114pub enum CpuVm {
115    None = 0,
116    Other,
117    Kvm,
118    Qemu,
119    Bochs,
120    Xen,
121    Uml,
122    Vmware,
123    Oracle,
124    Microsoft,
125    Zvm,
126    Parallels,
127    Bhyve,
128    Qnx,
129    Acrn,
130    PowerVm,
131}
132
133impl std::fmt::Display for CpuVm {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        let res = match self {
136            CpuVm::None => "0",
137            CpuVm::Other => "other",
138            CpuVm::Kvm => "kvm",
139            CpuVm::Qemu => "qemu",
140            CpuVm::Bochs => "bochs",
141            CpuVm::Xen => "xen",
142            CpuVm::Uml => "uml",
143            CpuVm::Vmware => "vmware",
144            CpuVm::Oracle => "oracle",
145            CpuVm::Microsoft => "microsoft",
146            CpuVm::Zvm => "zvm",
147            CpuVm::Parallels => "parallels",
148            CpuVm::Bhyve => "bhyve",
149            CpuVm::Qnx => "qnx",
150            CpuVm::Acrn => "acrn",
151            CpuVm::PowerVm => "powervm",
152        };
153
154        write!(f, "{}", res)
155    }
156}
157
158pub struct CpuImpl {
159    pub inner: Pin<Box<dyn Any>>,
160
161    pub get_flags: fn(this: &CpuImpl) -> CpuFlags,
162    pub force_flags: fn(this: &CpuImpl, flags: CpuFlags) -> i32,
163    pub get_count: fn(this: &CpuImpl) -> u32,
164    pub get_max_align: fn(this: &CpuImpl) -> u32,
165    pub get_vm_type: fn(this: &CpuImpl) -> CpuVm,
166    pub zero_denormals: fn(this: &CpuImpl, enable: bool) -> i32,
167}
168
169impl CpuImpl {
170    pub fn get_flags(&self) -> CpuFlags {
171        (self.get_flags)(self)
172    }
173
174    pub fn force_flags(&self, flags: CpuFlags) -> i32 {
175        (self.force_flags)(self, flags)
176    }
177
178    pub fn get_count(&self) -> u32 {
179        (self.get_count)(self)
180    }
181
182    pub fn get_max_align(&self) -> u32 {
183        (self.get_max_align)(self)
184    }
185
186    pub fn get_vm_type(&self) -> CpuVm {
187        (self.get_vm_type)(self)
188    }
189
190    pub fn zero_denormals(&self, enable: bool) -> i32 {
191        (self.zero_denormals)(self, enable)
192    }
193}
194
195impl Interface for CpuImpl {
196    unsafe fn make_native(&self) -> *mut super::ffi::CInterface {
197        crate::support::ffi::cpu::make_native(self)
198    }
199
200    unsafe fn free_native(cpu: *mut super::ffi::CInterface) {
201        crate::support::ffi::cpu::free_native(cpu)
202    }
203}
204
205unsafe impl Send for CpuImpl {}
206unsafe impl Sync for CpuImpl {}