vulkano_taskgraph/command_buffer/
mod.rs

1//! Recording commands to execute on the device.
2
3#[allow(unused_imports)] // everything is exported for future-proofing
4pub use self::commands::{clear::*, copy::*, dynamic_state::*, pipeline::*, sync::*};
5use crate::{graph::ResourceMap, resource::DeathRow, Id};
6use ash::vk;
7use std::{any::Any, sync::Arc};
8use vulkano::{
9    buffer::Buffer,
10    command_buffer as raw,
11    device::{Device, DeviceOwned},
12    image::Image,
13    VulkanObject,
14};
15
16mod commands;
17
18/// A command buffer in the recording state.
19///
20/// Unlike [the raw `RecordingCommandBuffer`], this type has knowledge of the current task context
21/// and can therefore validate resource accesses. (TODO)
22///
23/// [the raw `RecordingCommandBuffer`]: raw::RecordingCommandBuffer
24pub struct RecordingCommandBuffer<'a> {
25    inner: &'a mut raw::RecordingCommandBuffer,
26    accesses: ResourceAccesses<'a>,
27    death_row: &'a mut DeathRow,
28}
29
30struct ResourceAccesses<'a> {
31    resource_map: &'a ResourceMap<'a>,
32}
33
34impl<'a> RecordingCommandBuffer<'a> {
35    pub(crate) unsafe fn new(
36        inner: &'a mut raw::RecordingCommandBuffer,
37        resource_map: &'a ResourceMap<'a>,
38        death_row: &'a mut DeathRow,
39    ) -> Self {
40        RecordingCommandBuffer {
41            inner,
42            accesses: ResourceAccesses { resource_map },
43            death_row,
44        }
45    }
46
47    /// Returns the underlying raw command buffer.
48    ///
49    /// While this method is safe, using the command buffer isn't. You must guarantee that any
50    /// subresources you use while recording commands are either accounted for in the [task's
51    /// access set], or that those subresources don't require any synchronization (including layout
52    /// transitions and queue family ownership transfers), or that no other task is accessing the
53    /// subresources at the same time without appropriate synchronization.
54    #[inline]
55    pub fn as_raw(&mut self) -> &mut raw::RecordingCommandBuffer {
56        self.inner
57    }
58
59    /// Queues the destruction of the given `object` after the destruction of the command buffer.
60    #[inline]
61    pub fn destroy_object(&mut self, object: Arc<impl Any + Send + Sync>) {
62        self.death_row.push(object);
63    }
64
65    /// Queues the destruction of the given `objects` after the destruction of the command buffer.
66    #[inline]
67    pub fn destroy_objects(
68        &mut self,
69        objects: impl IntoIterator<Item = Arc<impl Any + Send + Sync>>,
70    ) {
71        self.death_row
72            .extend(objects.into_iter().map(|object| object as _));
73    }
74}
75
76unsafe impl DeviceOwned for RecordingCommandBuffer<'_> {
77    #[inline]
78    fn device(&self) -> &Arc<Device> {
79        self.inner.device()
80    }
81}
82
83unsafe impl VulkanObject for RecordingCommandBuffer<'_> {
84    type Handle = vk::CommandBuffer;
85
86    #[inline]
87    fn handle(&self) -> Self::Handle {
88        self.inner.handle()
89    }
90}
91
92impl<'a> ResourceAccesses<'a> {
93    unsafe fn buffer_unchecked(&self, id: Id<Buffer>) -> &'a Arc<Buffer> {
94        if id.is_virtual() {
95            // SAFETY:
96            // * The caller of `Task::execute` must ensure that `self.resource_map` maps the virtual
97            //   IDs of the graph exhaustively.
98            // * The caller must ensure that `id` is valid.
99            unsafe { self.resource_map.buffer_unchecked(id) }.buffer()
100        } else {
101            let resources = self.resource_map.resources();
102
103            // SAFETY:
104            // * `ResourceMap` owns an `epoch::Guard`.
105            // * The caller must ensure that `id` is valid.
106            unsafe { resources.buffer_unchecked_unprotected(id) }.buffer()
107        }
108    }
109
110    unsafe fn image_unchecked(&self, id: Id<Image>) -> &'a Arc<Image> {
111        if id.is_virtual() {
112            // SAFETY:
113            // * The caller must ensure that `id` is valid.
114            // * The caller of `Task::execute` must ensure that `self.resource_map` maps the virtual
115            //   IDs of the graph exhaustively.
116            unsafe { self.resource_map.image_unchecked(id) }.image()
117        } else {
118            let resources = self.resource_map.resources();
119
120            // SAFETY:
121            // * The caller must ensure that `id` is valid.
122            // * `ResourceMap` owns an `epoch::Guard`.
123            unsafe { resources.image_unchecked_unprotected(id) }.image()
124        }
125    }
126}
127
128type Result<T = (), E = Box<vulkano::ValidationError>> = ::std::result::Result<T, E>;