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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
//! Command buffers.
//!
//! A command buffer collects a list of commands to be submitted to the device.
//! Each command buffer has specific capabilities for graphics, compute or transfer operations,
//! and can be either a "primary" command buffer or a "secondary" command buffer.  Operations
//! always start from a primary command buffer, but a primary command buffer can contain calls
//! to secondary command buffers that contain snippets of commands that do specific things, similar
//! to function calls.
//!
//! All the possible commands are implemented in the `RawCommandBuffer` trait, and then the `CommandBuffer`
//! and related types make a generic, strongly-typed wrapper around it that only expose the methods that
//! are valid for the capabilities it provides.

// TODO: Document pipelines and subpasses better.

use crate::queue::capability::{Capability, Supports};
use crate::Backend;

use std::borrow::Borrow;
use std::marker::PhantomData;

mod compute;
mod graphics;
mod raw;
mod render_pass;
mod transfer;

pub use self::graphics::*;
pub use self::raw::{
    ClearColorRaw, ClearDepthStencilRaw, ClearValueRaw, CommandBufferFlags,
    CommandBufferInheritanceInfo, DescriptorSetOffset, IntoRawCommandBuffer, Level as RawLevel,
    RawCommandBuffer,
};
pub use self::render_pass::*;
pub use self::transfer::*;

/// Trait indicating how many times a Submit object can be submitted to a command buffer.
pub trait Shot {}
/// Indicates a Submit that can only be submitted once.
#[derive(Debug)]
pub enum OneShot {}
impl Shot for OneShot {}

/// Indicates a Submit that can be submitted multiple times.
#[derive(Debug)]
pub enum MultiShot {}
impl Shot for MultiShot {}

/// A trait indicating the level of a command buffer.
pub trait Level {}

/// Indicates a primary command buffer.

/// Vulkan describes a primary command buffer as one which can be directly submitted
/// to a queue, and can execute `Secondary` command buffers.
#[derive(Debug)]
pub enum Primary {}
impl Level for Primary {}

/// Indicates a secondary command buffer.
///
/// Vulkan describes a secondary command buffer as one which cannot be directly submitted
/// to a queue, but can be executed by a primary command buffer. This allows
/// multiple secondary command buffers to be constructed which do specific
/// things and can then be composed together into primary command buffers.
#[derive(Debug)]
pub enum Secondary {}
impl Level for Secondary {}

/// A property of a command buffer to be submitted to a queue with specific capability.
pub trait Submittable<B: Backend, C: Capability, L: Level>: Borrow<B::CommandBuffer> {}

/// A convenience alias for not typing out the full signature of a secondary command buffer.
pub type SecondaryCommandBuffer<B, C, S = OneShot> = CommandBuffer<B, C, S, Secondary>;

/// A strongly-typed command buffer that will only implement methods that are valid for the operations
/// it supports.
#[derive(Debug)]
pub struct CommandBuffer<B: Backend, C, S = OneShot, L = Primary, R = <B as Backend>::CommandBuffer>
{
    pub(crate) raw: R,
    pub(crate) _marker: PhantomData<(B, C, S, L)>,
}

impl<B, C, S, L, R> Borrow<R> for CommandBuffer<B, C, S, L, R>
where
    R: RawCommandBuffer<B>,
    B: Backend<CommandBuffer = R>,
{
    fn borrow(&self) -> &B::CommandBuffer {
        &self.raw
    }
}

impl<B: Backend, C, K: Capability + Supports<C>, S, L: Level> Submittable<B, K, L>
    for CommandBuffer<B, C, S, L>
{
}

impl<B: Backend, C, S, L> IntoRawCommandBuffer<B, C> for CommandBuffer<B, C, S, L> {
    fn into_raw(self) -> B::CommandBuffer {
        self.raw
    }
}

impl<B: Backend, C> CommandBuffer<B, C, OneShot, Primary> {
    /// Begin recording a one-shot primary command buffer.
    pub unsafe fn begin(&mut self) {
        let flags = CommandBufferFlags::ONE_TIME_SUBMIT;
        self.raw
            .begin(flags, CommandBufferInheritanceInfo::default());
    }
}

impl<B: Backend, C> CommandBuffer<B, C, MultiShot, Primary> {
    /// Begin recording a multi-shot primary command buffer.
    pub unsafe fn begin(&mut self, allow_pending_resubmit: bool) {
        let flags = if allow_pending_resubmit {
            CommandBufferFlags::SIMULTANEOUS_USE
        } else {
            CommandBufferFlags::empty()
        };
        self.raw
            .begin(flags, CommandBufferInheritanceInfo::default());
    }
}

impl<B: Backend, C> CommandBuffer<B, C, OneShot, Secondary> {
    /// Begin recording a one-shot secondary command buffer.
    pub unsafe fn begin(&mut self, inheritance: CommandBufferInheritanceInfo<B>) {
        let flags = CommandBufferFlags::ONE_TIME_SUBMIT;
        self.raw.begin(flags, inheritance);
    }
}

impl<B: Backend, C> CommandBuffer<B, C, MultiShot, Secondary> {
    /// Begin recording a multi-shot secondary command buffer.
    pub unsafe fn begin(
        &mut self,
        allow_pending_resubmit: bool,
        inheritance: CommandBufferInheritanceInfo<B>,
    ) {
        let flags = if allow_pending_resubmit {
            CommandBufferFlags::SIMULTANEOUS_USE
        } else {
            CommandBufferFlags::empty()
        };
        self.raw.begin(flags, inheritance);
    }
}

impl<B: Backend, C, S: Shot, L: Level> CommandBuffer<B, C, S, L> {
    /// Create a new typed command buffer from a raw command pool.
    pub unsafe fn new(raw: B::CommandBuffer) -> Self {
        CommandBuffer {
            raw,
            _marker: PhantomData,
        }
    }

    /// Finish recording commands to the command buffers.
    ///
    /// The command buffer must be reset to able to re-record commands.
    pub unsafe fn finish(&mut self) {
        self.raw.finish();
    }

    /// Empties the command buffer, optionally releasing all resources from the
    /// commands that have been submitted. The command buffer is moved back to
    /// the "initial" state.
    ///
    /// The command buffer must not be in the "pending" state. Additionally, the
    /// command pool must have been created with the RESET_INDIVIDUAL flag to be
    /// able to reset individual buffers.
    pub unsafe fn reset(&mut self, release_resources: bool) {
        self.raw.reset(release_resources);
    }

    /*
    /// Get a reference to the raw command buffer
    pub fn as_raw(&self) -> &B::CommandBuffer {
        &self.raw
    }

    /// Get a mutable reference to the raw command buffer
    pub fn as_raw_mut(&mut self) -> &mut B::CommandBuffer {
        &mut self.raw
    }*/

    /// Downgrade a command buffer to a lesser capability type.
    pub unsafe fn downgrade<D>(&mut self) -> &mut CommandBuffer<B, D, S>
    where
        C: Supports<D>,
    {
        ::std::mem::transmute(self)
    }
}

impl<B: Backend, C, S: Shot> CommandBuffer<B, C, S, Primary> {
    /// Identical to the `RawCommandBuffer` method of the same name.
    pub unsafe fn execute_commands<'a, I, T, K>(&mut self, cmd_buffers: I)
    where
        K: Capability,
        T: 'a + Submittable<B, K, Secondary>,
        I: IntoIterator<Item = &'a T>,
        C: Supports<K>,
    {
        self.raw
            .execute_commands(cmd_buffers.into_iter().map(|cmb| cmb.borrow()));
    }
}