1#![warn(missing_docs)]
55#![allow(clippy::module_name_repetitions)]
56#![allow(clippy::too_many_arguments)]
57
58pub mod accel_profile;
59pub mod accel_stats;
60pub mod buffer;
61pub mod cache;
62pub mod cpu_fallback;
63pub mod device;
64pub mod device_caps;
65pub mod dispatch;
66pub mod error;
67pub mod fence_timeline;
68pub mod kernels;
69pub mod memory_arena;
70pub mod memory_bandwidth;
71pub mod ops;
72pub mod pipeline_accel;
73pub mod pool;
74pub mod prefetch;
75pub mod shaders;
76pub mod task_graph;
77pub mod task_scheduler;
78pub mod traits;
79pub mod vulkan;
80pub mod workgroup;
81
82pub use error::{AccelError, AccelResult};
84pub use traits::{HardwareAccel, ScaleFilter};
85
86pub use accel_stats::{AccelProfiler, ProfileEntry};
88pub use memory_arena::{MemoryPressureMonitor, MemoryPressurePolicy, PressureLevel};
89pub use ops::convolution::{ConvolutionConfig, ConvolutionFilter, EdgeMode};
90pub use ops::deinterlace::{DeinterlaceConfig, DeinterlaceMethod, FieldOrder};
91
92pub use ops::color::{
94 hlg_to_sdr_tonemap, pq_to_sdr_tonemap, rgb_to_yuv420, yuv420_to_rgb, YuvRange, YuvStandard,
95};
96pub use ops::{alpha_blend, alpha_blend_rgba};
97
98pub use workgroup::{compute_optimal_workgroup, OpType};
100
101pub mod descriptor_pool;
103
104use device::DeviceSelector;
105use std::sync::Arc;
106use vulkan::VulkanAccel;
107
108pub struct AccelContext {
114 backend: AccelBackend,
115}
116
117enum AccelBackend {
118 Vulkan(Arc<VulkanAccel>),
119 Cpu(Arc<cpu_fallback::CpuAccel>),
120}
121
122impl AccelContext {
123 pub fn new() -> AccelResult<Self> {
133 Self::with_device_selector(&DeviceSelector::default())
134 }
135
136 pub fn with_device_selector(selector: &DeviceSelector) -> AccelResult<Self> {
142 match VulkanAccel::new(selector) {
143 Ok(vulkan) => {
144 tracing::info!("Hardware acceleration: Vulkan GPU");
145 Ok(Self {
146 backend: AccelBackend::Vulkan(Arc::new(vulkan)),
147 })
148 }
149 Err(e) => {
150 tracing::warn!("Vulkan initialization failed: {}, using CPU fallback", e);
151 Ok(Self {
152 backend: AccelBackend::Cpu(Arc::new(cpu_fallback::CpuAccel::new())),
153 })
154 }
155 }
156 }
157
158 #[must_use]
162 pub fn cpu_only() -> Self {
163 tracing::info!("Hardware acceleration: CPU only (forced)");
164 Self {
165 backend: AccelBackend::Cpu(Arc::new(cpu_fallback::CpuAccel::new())),
166 }
167 }
168
169 #[must_use]
171 pub fn is_gpu_accelerated(&self) -> bool {
172 matches!(self.backend, AccelBackend::Vulkan(_))
173 }
174
175 #[must_use]
177 pub fn backend_name(&self) -> &str {
178 match &self.backend {
179 AccelBackend::Vulkan(v) => v.device_name(),
180 AccelBackend::Cpu(_) => "CPU",
181 }
182 }
183}
184
185impl HardwareAccel for AccelContext {
186 fn scale_image(
187 &self,
188 input: &[u8],
189 src_width: u32,
190 src_height: u32,
191 dst_width: u32,
192 dst_height: u32,
193 format: oximedia_core::PixelFormat,
194 filter: ScaleFilter,
195 ) -> AccelResult<Vec<u8>> {
196 match &self.backend {
197 AccelBackend::Vulkan(v) => v.scale_image(
198 input, src_width, src_height, dst_width, dst_height, format, filter,
199 ),
200 AccelBackend::Cpu(c) => c.scale_image(
201 input, src_width, src_height, dst_width, dst_height, format, filter,
202 ),
203 }
204 }
205
206 fn convert_color(
207 &self,
208 input: &[u8],
209 width: u32,
210 height: u32,
211 src_format: oximedia_core::PixelFormat,
212 dst_format: oximedia_core::PixelFormat,
213 ) -> AccelResult<Vec<u8>> {
214 match &self.backend {
215 AccelBackend::Vulkan(v) => {
216 v.convert_color(input, width, height, src_format, dst_format)
217 }
218 AccelBackend::Cpu(c) => c.convert_color(input, width, height, src_format, dst_format),
219 }
220 }
221
222 fn motion_estimation(
223 &self,
224 reference: &[u8],
225 current: &[u8],
226 width: u32,
227 height: u32,
228 block_size: u32,
229 ) -> AccelResult<Vec<(i16, i16)>> {
230 match &self.backend {
231 AccelBackend::Vulkan(v) => {
232 v.motion_estimation(reference, current, width, height, block_size)
233 }
234 AccelBackend::Cpu(c) => {
235 c.motion_estimation(reference, current, width, height, block_size)
236 }
237 }
238 }
239}