#![warn(missing_docs)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::too_many_arguments)]
pub mod accel_profile;
pub mod accel_stats;
pub mod buffer;
pub mod cache;
pub mod cpu_fallback;
pub mod device;
pub mod device_caps;
pub mod dispatch;
pub mod error;
pub mod fence_timeline;
pub mod kernels;
pub mod memory_arena;
pub mod memory_bandwidth;
pub mod ops;
pub mod pipeline_accel;
pub mod pool;
pub mod prefetch;
pub mod shaders;
pub mod task_graph;
pub mod task_scheduler;
pub mod traits;
pub mod vulkan;
pub mod workgroup;
pub use error::{AccelError, AccelResult};
pub use traits::{HardwareAccel, ScaleFilter};
pub use accel_stats::{AccelProfiler, ProfileEntry};
pub use memory_arena::{MemoryPressureMonitor, MemoryPressurePolicy, PressureLevel};
pub use ops::convolution::{ConvolutionConfig, ConvolutionFilter, EdgeMode};
pub use ops::deinterlace::{DeinterlaceConfig, DeinterlaceMethod, FieldOrder};
pub use ops::color::{
hlg_to_sdr_tonemap, pq_to_sdr_tonemap, rgb_to_yuv420, yuv420_to_rgb, YuvRange, YuvStandard,
};
pub use ops::{alpha_blend, alpha_blend_rgba};
pub use workgroup::{compute_optimal_workgroup, OpType};
pub mod descriptor_pool;
use device::DeviceSelector;
use std::sync::Arc;
use vulkan::VulkanAccel;
pub struct AccelContext {
backend: AccelBackend,
}
enum AccelBackend {
Vulkan(Arc<VulkanAccel>),
Cpu(Arc<cpu_fallback::CpuAccel>),
}
impl AccelContext {
pub fn new() -> AccelResult<Self> {
Self::with_device_selector(&DeviceSelector::default())
}
pub fn with_device_selector(selector: &DeviceSelector) -> AccelResult<Self> {
match VulkanAccel::new(selector) {
Ok(vulkan) => {
tracing::info!("Hardware acceleration: Vulkan GPU");
Ok(Self {
backend: AccelBackend::Vulkan(Arc::new(vulkan)),
})
}
Err(e) => {
tracing::warn!("Vulkan initialization failed: {}, using CPU fallback", e);
Ok(Self {
backend: AccelBackend::Cpu(Arc::new(cpu_fallback::CpuAccel::new())),
})
}
}
}
#[must_use]
pub fn cpu_only() -> Self {
tracing::info!("Hardware acceleration: CPU only (forced)");
Self {
backend: AccelBackend::Cpu(Arc::new(cpu_fallback::CpuAccel::new())),
}
}
#[must_use]
pub fn is_gpu_accelerated(&self) -> bool {
matches!(self.backend, AccelBackend::Vulkan(_))
}
#[must_use]
pub fn backend_name(&self) -> &str {
match &self.backend {
AccelBackend::Vulkan(v) => v.device_name(),
AccelBackend::Cpu(_) => "CPU",
}
}
}
impl HardwareAccel for AccelContext {
fn scale_image(
&self,
input: &[u8],
src_width: u32,
src_height: u32,
dst_width: u32,
dst_height: u32,
format: oximedia_core::PixelFormat,
filter: ScaleFilter,
) -> AccelResult<Vec<u8>> {
match &self.backend {
AccelBackend::Vulkan(v) => v.scale_image(
input, src_width, src_height, dst_width, dst_height, format, filter,
),
AccelBackend::Cpu(c) => c.scale_image(
input, src_width, src_height, dst_width, dst_height, format, filter,
),
}
}
fn convert_color(
&self,
input: &[u8],
width: u32,
height: u32,
src_format: oximedia_core::PixelFormat,
dst_format: oximedia_core::PixelFormat,
) -> AccelResult<Vec<u8>> {
match &self.backend {
AccelBackend::Vulkan(v) => {
v.convert_color(input, width, height, src_format, dst_format)
}
AccelBackend::Cpu(c) => c.convert_color(input, width, height, src_format, dst_format),
}
}
fn motion_estimation(
&self,
reference: &[u8],
current: &[u8],
width: u32,
height: u32,
block_size: u32,
) -> AccelResult<Vec<(i16, i16)>> {
match &self.backend {
AccelBackend::Vulkan(v) => {
v.motion_estimation(reference, current, width, height, block_size)
}
AccelBackend::Cpu(c) => {
c.motion_estimation(reference, current, width, height, block_size)
}
}
}
}