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