use crate::error::CryptoError;
use crate::hardware::gpu::device::{
DeviceCapabilities, DeviceHealth, DeviceState, XpuDevice, XpuKernel, XpuType,
};
use crate::types::Algorithm;
use std::sync::Arc;
#[cfg(feature = "gpu-opencl")]
use ocl::{Context, Device, DeviceType, Platform};
#[cfg(feature = "gpu-opencl")]
use ocl::enums::DeviceInfo;
#[cfg(feature = "gpu-opencl")]
pub struct OpenclDevice {
device_id: usize,
device_name: String,
capabilities: DeviceCapabilities,
state: DeviceState,
platform: Option<Platform>,
device: Option<Device>,
context: Option<Context>,
}
#[cfg(feature = "gpu-opencl")]
impl OpenclDevice {
pub fn enumerate() -> Result<Vec<Self>, CryptoError> {
let mut devices = Vec::new();
let platforms = match std::panic::catch_unwind(Platform::list) {
Ok(p) => p,
Err(_) => {
return Ok(devices);
}
};
let mut device_count = 0usize;
for platform in &platforms {
let platform_devices =
match std::panic::catch_unwind(|| Device::list(platform, None)) {
Ok(devices) => devices,
Err(_) => {
continue;
}
}
.map_err(|e| CryptoError::HardwareAccelerationUnavailable(e.to_string()))?;
for device in platform_devices {
let name = device
.name()
.unwrap_or_else(|_| "Unknown OpenCL Device".to_string());
let compute_units = match device.info(DeviceInfo::MaxComputeUnits) {
Ok(ocl::enums::DeviceInfoResult::MaxComputeUnits(val)) => val,
_ => 1,
};
let max_work_group_size = match device.info(DeviceInfo::MaxWorkGroupSize) {
Ok(ocl::enums::DeviceInfoResult::MaxWorkGroupSize(val)) => val,
_ => 256,
};
let global_memory = match device.info(DeviceInfo::GlobalMemSize) {
Ok(ocl::enums::DeviceInfoResult::GlobalMemSize(val)) => val,
_ => 0,
};
let max_alloc_size = match device.info(DeviceInfo::MaxMemAllocSize) {
Ok(ocl::enums::DeviceInfoResult::MaxMemAllocSize(val)) => val,
_ => 1024 * 1024 * 1024,
};
let device_type_info = device.info(DeviceInfo::Type);
let device_type = match device_type_info {
Ok(ocl::enums::DeviceInfoResult::Type(dt)) => {
if dt.contains(DeviceType::GPU) {
if name.contains("AMD") || name.contains("Radeon") {
XpuType::AmdGpu
} else if name.contains("Intel") {
XpuType::IntelGpu
} else {
XpuType::Unknown
}
} else if dt.contains(DeviceType::CPU) {
XpuType::IntelCpu
} else {
XpuType::Unknown
}
}
_ => XpuType::Unknown,
};
let capabilities = DeviceCapabilities {
device_type,
device_name: name.clone(),
compute_units,
max_work_group_size,
global_memory: global_memory as usize,
max_alloc_size: max_alloc_size as usize,
supported_algorithms: vec![
crate::types::Algorithm::SHA256,
crate::types::Algorithm::SHA512,
crate::types::Algorithm::AES256GCM,
crate::types::Algorithm::ECDSAP256,
crate::types::Algorithm::ECDSAP384,
crate::types::Algorithm::Ed25519,
],
has_local_memory: true,
ecc_supported: false,
};
devices.push(Self {
device_id: device_count,
device_name: name,
capabilities,
state: DeviceState::Uninitialized,
platform: Some(*platform),
device: Some(device),
context: None,
});
device_count += 1;
}
}
Ok(devices)
}
}
#[cfg(not(feature = "gpu-opencl"))]
impl OpenclDevice {
pub fn enumerate() -> Result<Vec<Self>, CryptoError> {
Ok(Vec::new())
}
}
#[cfg(feature = "gpu-opencl")]
impl XpuDevice for OpenclDevice {
fn device_type(&self) -> XpuType {
XpuType::AmdGpu
}
fn device_name(&self) -> &str {
&self.device_name
}
fn capabilities(&self) -> &DeviceCapabilities {
&self.capabilities
}
fn state(&self) -> DeviceState {
self.state.clone()
}
fn is_available(&self) -> bool {
self.state == DeviceState::Ready
}
fn initialize(&mut self) -> Result<(), CryptoError> {
if self.state == DeviceState::Ready {
return Ok(());
}
let device = self.device.as_ref().ok_or_else(|| {
CryptoError::HardwareAccelerationUnavailable("OpenCL device not found".into())
})?;
let context = Context::builder()
.devices(*device)
.build()
.map_err(|e| CryptoError::HardwareAccelerationUnavailable(e.to_string()))?;
self.context = Some(context);
self.state = DeviceState::Ready;
Ok(())
}
fn shutdown(&mut self) -> Result<(), CryptoError> {
self.context.take();
self.state = DeviceState::Shutdown;
Ok(())
}
fn check_health(&self) -> Result<DeviceHealth, CryptoError> {
let health = DeviceHealth {
is_healthy: self.state == DeviceState::Ready,
temperature: None,
memory_used: 0,
memory_total: self.capabilities.global_memory,
compute_utilization: 0.0,
error_count: 0,
};
Ok(health)
}
fn allocate_host_buffer(&self, _size: usize) -> Result<Vec<u8>, CryptoError> {
Ok(vec![0u8; _size])
}
fn allocate_device_buffer(&self, _size: usize) -> Result<(), CryptoError> {
Ok(())
}
fn deallocate_device_buffer(&self, _buffer_id: u64) -> Result<(), CryptoError> {
Ok(())
}
fn copy_to_device(&self, _host_data: &[u8], _device_offset: usize) -> Result<(), CryptoError> {
Ok(())
}
fn copy_from_device(
&self,
_device_offset: usize,
_size: usize,
) -> Result<Vec<u8>, CryptoError> {
Ok(vec![0u8; _size])
}
fn get_kernel(&self, _algorithm: Algorithm) -> Result<Arc<dyn XpuKernel>, CryptoError> {
Err(CryptoError::HardwareAccelerationUnavailable(
"OpenCL kernel not implemented".into(),
))
}
}