1use std::sync::Mutex;
2
3use crate::handles::{GpuBufferHandle, GpuImageHandle};
4use crate::traits::GpuBackend;
5use crate::{
6 GpuAdapterInfo, GpuBackendKind, GpuCapabilities, GpuError, GpuFormat, GpuFormatFeatures,
7 GpuImageRequest, GpuMemoryLocation, GpuOptions, GpuRequest, buffer::TransferStats,
8};
9
10#[derive(Default)]
12pub struct NoopBackend {
13 stats: Mutex<TransferStats>,
14}
15
16impl GpuBackend for NoopBackend {
17 fn kind(&self) -> GpuBackendKind {
18 GpuBackendKind::Noop
19 }
20
21 fn as_any(&self) -> &dyn std::any::Any {
22 self
23 }
24
25 fn adapter_info(&self) -> GpuAdapterInfo {
26 GpuAdapterInfo {
27 name: "noop".into(),
28 backend: GpuBackendKind::Noop,
29 device_id: None,
30 vendor_id: None,
31 }
32 }
33
34 fn capabilities(&self) -> GpuCapabilities {
35 GpuCapabilities {
36 supported_formats: vec![GpuFormat::R8Unorm, GpuFormat::Rgba8Unorm],
37 format_features: vec![
38 GpuFormatFeatures {
39 format: GpuFormat::R8Unorm,
40 sampleable: true,
41 renderable: true,
42 storage: false,
43 max_samples: 1,
44 },
45 GpuFormatFeatures {
46 format: GpuFormat::Rgba8Unorm,
47 sampleable: true,
48 renderable: true,
49 storage: false,
50 max_samples: 1,
51 },
52 ],
53 format_blocks: vec![
54 crate::GpuBlockInfo {
55 format: GpuFormat::R8Unorm,
56 block_width: 1,
57 block_height: 1,
58 bytes_per_block: 1,
59 },
60 crate::GpuBlockInfo {
61 format: GpuFormat::Rgba8Unorm,
62 block_width: 1,
63 block_height: 1,
64 bytes_per_block: 4,
65 },
66 ],
67 max_buffer_size: 0,
68 max_texture_dimension: 0,
69 max_texture_samples: 1,
70 staging_alignment: 1,
71 max_inflight_copies: 1,
72 queue_count: 1,
73 min_buffer_copy_offset_alignment: 1,
74 bytes_per_row_alignment: 1,
75 rows_per_image_alignment: 1,
76 has_transfer_queue: false,
77 }
78 }
79
80 fn select_adapter(&self, _opts: &GpuOptions) -> Result<GpuAdapterInfo, GpuError> {
81 Ok(self.adapter_info())
82 }
83
84 fn create_buffer(&self, req: &GpuRequest) -> Result<GpuBufferHandle, GpuError> {
85 if req.usage.is_empty() {
86 return Err(GpuError::Unsupported);
87 }
88 let mut stats = self.stats.lock().expect("noop stats lock");
89 stats.record_upload(req.size_bytes);
90 Ok(GpuBufferHandle::new(
91 req.size_bytes,
92 GpuMemoryLocation::Cpu,
93 req.usage,
94 ))
95 }
96
97 fn create_image(&self, req: &GpuImageRequest) -> Result<GpuImageHandle, GpuError> {
98 if req.usage.is_empty() {
99 return Err(GpuError::Unsupported);
100 }
101 let mut stats = self.stats.lock().expect("noop stats lock");
102 let bpp = crate::format_bytes_per_pixel(req.format).unwrap_or(4) as u64;
103 let bytes = (req.width as u64) * (req.height as u64) * bpp;
104 stats.record_upload(bytes);
105 Ok(GpuImageHandle::new(
106 req.format,
107 req.width,
108 req.height,
109 GpuMemoryLocation::Cpu,
110 req.usage,
111 ))
112 }
113
114 fn stats(&self) -> TransferStats {
115 *self.stats.lock().expect("noop stats lock")
116 }
117
118 fn take_stats(&self) -> TransferStats {
119 self.stats.lock().expect("noop stats lock").take()
120 }
121
122 fn record_download(&self, bytes: u64) {
123 let mut stats = self.stats.lock().expect("noop stats lock");
124 stats.record_download(bytes);
125 }
126
127 fn upload_texture(
128 &self,
129 req: &GpuImageRequest,
130 data: &[u8],
131 ) -> Result<GpuImageHandle, GpuError> {
132 let handle = self.create_image(req)?;
133 let mut stats = self.stats.lock().expect("noop stats lock");
134 stats.record_upload(data.len() as u64);
135 Ok(handle)
136 }
137
138 fn read_texture(&self, handle: &GpuImageHandle) -> Result<Vec<u8>, GpuError> {
139 let bpp = crate::format_bytes_per_pixel(handle.format).unwrap_or(4) as usize;
140 let bytes = (handle.width as usize) * (handle.height as usize) * bpp;
141 self.record_download(bytes as u64);
142 Ok(vec![0; bytes])
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::GpuUsage;
150
151 #[test]
152 fn noop_creates_handles() {
153 let backend = NoopBackend::default();
154 let buf = backend
155 .create_buffer(&GpuRequest {
156 usage: GpuUsage::UPLOAD,
157 format: None,
158 size_bytes: 128,
159 })
160 .unwrap();
161 assert_eq!(buf.size_bytes, 128);
162 let img = backend
163 .create_image(&GpuImageRequest {
164 format: GpuFormat::Rgba8Unorm,
165 width: 1,
166 height: 1,
167 samples: 1,
168 usage: GpuUsage::RENDER_TARGET,
169 })
170 .unwrap();
171 assert_eq!(img.format, GpuFormat::Rgba8Unorm);
172 }
173}