1use crate::GpuDevice;
7use std::sync::Arc;
8use wgpu::{CommandBuffer, CommandEncoder, Queue, SubmissionIndex};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub enum QueueType {
13 Compute,
15 Transfer,
17 Graphics,
19}
20
21pub struct CommandQueue {
23 queue: Arc<Queue>,
24 device: Arc<wgpu::Device>,
25 queue_type: QueueType,
26}
27
28impl CommandQueue {
29 #[must_use]
31 pub fn new(device: &GpuDevice, queue_type: QueueType) -> Self {
32 Self {
33 queue: Arc::clone(device.queue()),
34 device: Arc::clone(device.device()),
35 queue_type,
36 }
37 }
38
39 #[must_use]
49 pub fn submit_single(&self, command_buffer: CommandBuffer) -> SubmissionIndex {
50 self.queue.submit(Some(command_buffer))
51 }
52
53 #[must_use]
63 pub fn submit_many(&self, command_buffers: Vec<CommandBuffer>) -> SubmissionIndex {
64 self.queue.submit(command_buffers)
65 }
66
67 #[must_use]
77 pub fn submit_encoder(&self, encoder: CommandEncoder) -> SubmissionIndex {
78 self.queue.submit(Some(encoder.finish()))
79 }
80
81 pub fn write_buffer(&self, buffer: &wgpu::Buffer, offset: u64, data: &[u8]) {
92 self.queue.write_buffer(buffer, offset, data);
93 }
94
95 pub fn wait(&self) {
97 let _ = self.device.poll(wgpu::PollType::wait_indefinitely());
98 }
99
100 #[must_use]
102 pub fn queue_type(&self) -> QueueType {
103 self.queue_type
104 }
105
106 #[must_use]
108 pub fn queue(&self) -> &Arc<Queue> {
109 &self.queue
110 }
111}
112
113pub struct QueueManager {
115 compute_queue: CommandQueue,
116 transfer_queue: CommandQueue,
117 graphics_queue: CommandQueue,
118}
119
120impl QueueManager {
121 #[must_use]
126 pub fn new(device: &GpuDevice) -> Self {
127 Self {
128 compute_queue: CommandQueue::new(device, QueueType::Compute),
129 transfer_queue: CommandQueue::new(device, QueueType::Transfer),
130 graphics_queue: CommandQueue::new(device, QueueType::Graphics),
131 }
132 }
133
134 #[must_use]
136 pub fn compute(&self) -> &CommandQueue {
137 &self.compute_queue
138 }
139
140 #[must_use]
142 pub fn transfer(&self) -> &CommandQueue {
143 &self.transfer_queue
144 }
145
146 #[must_use]
148 pub fn graphics(&self) -> &CommandQueue {
149 &self.graphics_queue
150 }
151
152 #[must_use]
154 pub fn get_queue(&self, queue_type: QueueType) -> &CommandQueue {
155 match queue_type {
156 QueueType::Compute => &self.compute_queue,
157 QueueType::Transfer => &self.transfer_queue,
158 QueueType::Graphics => &self.graphics_queue,
159 }
160 }
161
162 pub fn wait_all(&self) {
164 self.compute_queue.wait();
165 self.transfer_queue.wait();
166 self.graphics_queue.wait();
167 }
168}
169
170pub struct CommandBufferBuilder {
172 encoder: CommandEncoder,
173 label: String,
174}
175
176impl CommandBufferBuilder {
177 pub fn new(device: &GpuDevice, label: impl Into<String>) -> Self {
179 let label_string = label.into();
180 let encoder = device
181 .device()
182 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
183 label: Some(&label_string),
184 });
185
186 Self {
187 encoder,
188 label: label_string,
189 }
190 }
191
192 pub fn encoder(&mut self) -> &mut CommandEncoder {
194 &mut self.encoder
195 }
196
197 #[must_use]
199 pub fn finish(self) -> CommandBuffer {
200 self.encoder.finish()
201 }
202
203 #[must_use]
205 pub fn submit(self, queue: &CommandQueue) -> SubmissionIndex {
206 queue.submit_encoder(self.encoder)
207 }
208
209 #[must_use]
211 pub fn label(&self) -> &str {
212 &self.label
213 }
214}
215
216pub struct AsyncSubmission {
218 submission_index: SubmissionIndex,
219 device: Arc<wgpu::Device>,
220}
221
222impl AsyncSubmission {
223 #[must_use]
225 pub fn new(submission_index: SubmissionIndex, device: Arc<wgpu::Device>) -> Self {
226 Self {
227 submission_index,
228 device,
229 }
230 }
231
232 pub fn wait(&self) {
234 let _ = self.device.poll(wgpu::PollType::wait_indefinitely());
235 }
236
237 #[must_use]
239 pub fn index(&self) -> &SubmissionIndex {
240 &self.submission_index
241 }
242}
243
244pub struct BatchSubmitter {
246 command_buffers: Vec<CommandBuffer>,
247 max_batch_size: usize,
248}
249
250impl BatchSubmitter {
251 #[must_use]
257 pub fn new(max_batch_size: usize) -> Self {
258 Self {
259 command_buffers: Vec::with_capacity(max_batch_size),
260 max_batch_size,
261 }
262 }
263
264 pub fn add(
277 &mut self,
278 command_buffer: CommandBuffer,
279 queue: &CommandQueue,
280 ) -> Option<SubmissionIndex> {
281 self.command_buffers.push(command_buffer);
282
283 if self.command_buffers.len() >= self.max_batch_size {
284 Some(self.flush(queue))
285 } else {
286 None
287 }
288 }
289
290 pub fn flush(&mut self, queue: &CommandQueue) -> SubmissionIndex {
300 let buffers = std::mem::take(&mut self.command_buffers);
301 queue.submit_many(buffers)
302 }
303
304 #[must_use]
306 pub fn pending_count(&self) -> usize {
307 self.command_buffers.len()
308 }
309
310 #[must_use]
312 pub fn is_empty(&self) -> bool {
313 self.command_buffers.is_empty()
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_queue_type() {
323 assert_eq!(QueueType::Compute, QueueType::Compute);
324 assert_ne!(QueueType::Compute, QueueType::Transfer);
325 assert_ne!(QueueType::Compute, QueueType::Graphics);
326 }
327
328 #[test]
329 fn test_batch_submitter() {
330 let submitter = BatchSubmitter::new(5);
331
332 assert_eq!(submitter.pending_count(), 0);
333 assert!(submitter.is_empty());
334 }
335}