Skip to main content

softgpu_core/
agent.rs

1//! Virtual SoftGPU agents backed by a device profile.
2
3use crate::handle::PackedHandle;
4use crate::profile::DeviceProfile;
5use crate::queue::{
6    QUEUE_TYPE_MULTI, SOFTGPU_QUEUES_MAX, SOFTGPU_QUEUE_MAX_SIZE, SOFTGPU_QUEUE_MIN_SIZE,
7};
8
9/// SoftGPU agent device class (vendor-neutral).
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub enum AgentKind {
12    Cpu,
13    Gpu,
14}
15
16impl AgentKind {
17    pub fn as_str(self) -> &'static str {
18        match self {
19            Self::Cpu => "cpu",
20            Self::Gpu => "gpu",
21        }
22    }
23}
24
25/// `HSA_AGENT_FEATURE_KERNEL_DISPATCH` — SoftGPU queue + AQL intercept claim only.
26pub const AGENT_FEATURE_KERNEL_DISPATCH: u32 = 1;
27
28/// Attributes SoftGPU may answer for an agent.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum AgentInfoAttr {
31    Name,
32    VendorName,
33    Feature,
34    Device,
35    VersionMajor,
36    VersionMinor,
37    QueuesMax,
38    QueueMinSize,
39    QueueMaxSize,
40    QueueType,
41}
42
43impl AgentInfoAttr {
44    pub fn as_str(self) -> &'static str {
45        match self {
46            Self::Name => "name",
47            Self::VendorName => "vendor_name",
48            Self::Feature => "feature",
49            Self::Device => "device",
50            Self::VersionMajor => "version_major",
51            Self::VersionMinor => "version_minor",
52            Self::QueuesMax => "queues_max",
53            Self::QueueMinSize => "queue_min_size",
54            Self::QueueMaxSize => "queue_max_size",
55            Self::QueueType => "queue_type",
56        }
57    }
58}
59
60/// One virtual agent instance.
61#[derive(Debug, Clone)]
62pub struct VirtualAgent {
63    pub handle: PackedHandle,
64    pub kind: AgentKind,
65    pub name: String,
66    pub vendor_name: String,
67    /// Bitmask of agent features. SoftGPU: `KERNEL_DISPATCH` for queue + AQL intercept only.
68    pub feature_mask: u32,
69    pub profile_id: String,
70    pub profile_revision: String,
71    pub queues_max: u32,
72    pub queue_min_size: u32,
73    pub queue_max_size: u32,
74    pub queue_type: u32,
75}
76
77impl VirtualAgent {
78    /// Build the SoftGPU GPU agent from a device profile.
79    pub fn gpu_from_profile(handle: PackedHandle, profile: &DeviceProfile) -> Self {
80        let mut name = profile.identity.product_name.clone();
81        name.truncate(63);
82        let mut vendor_name = profile.identity.vendor.clone();
83        vendor_name.truncate(63);
84        Self {
85            handle,
86            kind: AgentKind::Gpu,
87            name,
88            vendor_name,
89            // SoftGPU Phase 3: advertise kernel-agent for queue ABI observation.
90            // Packet execution remains unsupported (Phase 4).
91            feature_mask: AGENT_FEATURE_KERNEL_DISPATCH,
92            profile_id: profile.profile_id.clone(),
93            profile_revision: profile.profile_revision.clone(),
94            queues_max: SOFTGPU_QUEUES_MAX,
95            queue_min_size: SOFTGPU_QUEUE_MIN_SIZE,
96            queue_max_size: SOFTGPU_QUEUE_MAX_SIZE,
97            queue_type: QUEUE_TYPE_MULTI,
98        }
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105    use crate::fidelity::FidelityLevel;
106    use crate::handle::HandleKind;
107    use crate::profile::{ProfileField, ProfileIdentity, ResourceLimits};
108
109    #[test]
110    fn gpu_agent_truncates_names_and_claims_kernel_dispatch() {
111        let profile = DeviceProfile {
112            schema_version: 1,
113            profile_id: "amd-radeon-ai-pro-r9700-gfx1201".into(),
114            profile_revision: "0".into(),
115            identity: ProfileIdentity {
116                vendor: "AMD".into(),
117                product_name: "Radeon AI PRO R9700".into(),
118                architecture_family: "RDNA 4".into(),
119                llvm_target: ProfileField::verified(
120                    "gfx1201".into(),
121                    "docs/sources.md#rocm-compatibility-r9700-gfx1201",
122                ),
123            },
124            max_fidelity: FidelityLevel::Abi,
125            conformance_allowed: false,
126            resource_limits: ResourceLimits::default(),
127            analytical_performance: Default::default(),
128            quirks: vec![],
129        };
130        let agent =
131            VirtualAgent::gpu_from_profile(PackedHandle::pack(HandleKind::Agent, 1, 0), &profile);
132        assert_eq!(agent.kind, AgentKind::Gpu);
133        assert_eq!(agent.feature_mask, AGENT_FEATURE_KERNEL_DISPATCH);
134        assert_eq!(agent.name, "Radeon AI PRO R9700");
135        assert_eq!(agent.vendor_name, "AMD");
136    }
137}