rendy_command/buffer/
mod.rs

1//! Command buffer module docs.
2
3mod encoder;
4mod level;
5mod reset;
6mod state;
7mod submit;
8mod usage;
9
10use {
11    crate::{
12        capability::{Capability, Supports},
13        family::FamilyId,
14    },
15    rendy_core::hal::Backend,
16};
17
18pub use self::{encoder::*, level::*, reset::*, state::*, submit::*, usage::*};
19
20/// Command buffer wrapper.
21/// This wrapper defines state with usage, level and ability to be individually reset at type level.
22/// This way many methods become safe.
23#[derive(Debug)]
24pub struct CommandBuffer<B: Backend, C, S, L = PrimaryLevel, R = NoIndividualReset> {
25    raw: std::ptr::NonNull<B::CommandBuffer>,
26    capability: C,
27    state: S,
28    level: L,
29    reset: R,
30    family: FamilyId,
31    relevant: relevant::Relevant,
32}
33
34family_owned!(CommandBuffer<B, C, S, L, R>);
35
36unsafe impl<B, C, S, L, R> Send for CommandBuffer<B, C, S, L, R>
37where
38    B: Backend,
39    B::CommandBuffer: Send,
40    C: Send,
41    S: Send,
42    L: Send,
43    R: Send,
44    FamilyId: Send,
45    relevant::Relevant: Send,
46{
47}
48
49unsafe impl<B, C, S, L, R> Sync for CommandBuffer<B, C, S, L, R>
50where
51    B: Backend,
52    B::CommandBuffer: Sync,
53    C: Sync,
54    S: Sync,
55    L: Sync,
56    R: Sync,
57    FamilyId: Sync,
58    relevant::Relevant: Sync,
59{
60}
61
62impl<B, C, S, L, R> CommandBuffer<B, C, S, L, R>
63where
64    B: Backend,
65{
66    /// Wrap raw buffer handle.
67    ///
68    /// # Safety
69    ///
70    /// * `raw` must be valid command buffer handle.
71    /// * `capability` must be subset of `family` capability.
72    /// * `state` must represent actual state buffer currently in.
73    /// * command buffer must be allocated with specified `level`.
74    /// * If `reset` is `IndividualReset` then buffer must be allocated from pool created with `IndividualReset` marker.
75    /// * command buffer must be allocated from pool created for `family`.
76    pub(crate) unsafe fn from_raw(
77        raw: B::CommandBuffer,
78        capability: C,
79        state: S,
80        level: L,
81        reset: R,
82        family: FamilyId,
83    ) -> Self {
84        CommandBuffer {
85            raw: std::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(raw))),
86            capability,
87            state,
88            level,
89            reset,
90            family,
91            relevant: relevant::Relevant,
92        }
93    }
94
95    /// Change state of the command buffer.
96    ///
97    /// # Safety
98    ///
99    /// * This method must be used only to reflect state changed due to raw handle usage.
100    pub unsafe fn change_state<U>(self, f: impl FnOnce(S) -> U) -> CommandBuffer<B, C, U, L, R> {
101        CommandBuffer {
102            raw: self.raw,
103            capability: self.capability,
104            state: f(self.state),
105            level: self.level,
106            reset: self.reset,
107            family: self.family,
108            relevant: self.relevant,
109        }
110    }
111
112    /// Get buffers capability.
113    pub fn capability(&self) -> C
114    where
115        C: Capability,
116    {
117        self.capability
118    }
119
120    /// Get buffers family.
121    pub fn family(&self) -> FamilyId {
122        self.family
123    }
124
125    /// Convert capability level.
126    pub fn with_queue_type(self) -> CommandBuffer<B, rendy_core::hal::queue::QueueType, S, L, R>
127    where
128        C: Capability,
129    {
130        CommandBuffer {
131            raw: self.raw,
132            capability: self.capability.into_queue_type(),
133            state: self.state,
134            level: self.level,
135            reset: self.reset,
136            family: self.family,
137            relevant: self.relevant,
138        }
139    }
140
141    /// Convert capability level.
142    pub fn with_capability<U>(self) -> Result<CommandBuffer<B, U, S, L, R>, Self>
143    where
144        C: Supports<U>,
145    {
146        if let Some(capability) = self.capability.supports() {
147            Ok(CommandBuffer {
148                raw: self.raw,
149                capability: capability,
150                state: self.state,
151                level: self.level,
152                reset: self.reset,
153                family: self.family,
154                relevant: self.relevant,
155            })
156        } else {
157            Err(self)
158        }
159    }
160}
161
162/// Begin info for specific level and render pass relation.
163pub unsafe trait BeginInfo<'a, B: Backend, L> {
164    /// Pass relation type.
165    type PassRelation: RenderPassRelation<L>;
166
167    /// Get command buffer inheritance info.
168    fn inheritance_info(self) -> rendy_core::hal::command::CommandBufferInheritanceInfo<'a, B>;
169}
170
171unsafe impl<'a, B, L> BeginInfo<'a, B, L> for ()
172where
173    B: Backend,
174    L: Level,
175{
176    type PassRelation = OutsideRenderPass;
177
178    fn inheritance_info(self) -> rendy_core::hal::command::CommandBufferInheritanceInfo<'a, B> {
179        rendy_core::hal::command::CommandBufferInheritanceInfo::default()
180    }
181}
182
183unsafe impl<'a, B> BeginInfo<'a, B, SecondaryLevel> for rendy_core::hal::pass::Subpass<'a, B>
184where
185    B: Backend,
186{
187    type PassRelation = RenderPassContinue;
188
189    fn inheritance_info(self) -> rendy_core::hal::command::CommandBufferInheritanceInfo<'a, B> {
190        rendy_core::hal::command::CommandBufferInheritanceInfo {
191            subpass: Some(self),
192            framebuffer: None,
193            ..rendy_core::hal::command::CommandBufferInheritanceInfo::default()
194        }
195    }
196}
197
198unsafe impl<'a, B, F> BeginInfo<'a, B, SecondaryLevel>
199    for (rendy_core::hal::pass::Subpass<'a, B>, Option<&'a F>)
200where
201    B: Backend,
202    F: std::borrow::Borrow<B::Framebuffer>,
203{
204    type PassRelation = RenderPassContinue;
205
206    fn inheritance_info(self) -> rendy_core::hal::command::CommandBufferInheritanceInfo<'a, B> {
207        rendy_core::hal::command::CommandBufferInheritanceInfo {
208            subpass: Some(self.0),
209            framebuffer: self.1.map(F::borrow),
210            ..rendy_core::hal::command::CommandBufferInheritanceInfo::default()
211        }
212    }
213}
214
215unsafe impl<'a, B, F> BeginInfo<'a, B, SecondaryLevel>
216    for (rendy_core::hal::pass::Subpass<'a, B>, &'a F)
217where
218    B: Backend,
219    F: std::borrow::Borrow<B::Framebuffer>,
220{
221    type PassRelation = RenderPassContinue;
222
223    fn inheritance_info(self) -> rendy_core::hal::command::CommandBufferInheritanceInfo<'a, B> {
224        rendy_core::hal::command::CommandBufferInheritanceInfo {
225            subpass: Some(self.0),
226            framebuffer: Some(self.1.borrow()),
227            ..rendy_core::hal::command::CommandBufferInheritanceInfo::default()
228        }
229    }
230}
231
232impl<B, C, L, R> CommandBuffer<B, C, InitialState, L, R>
233where
234    B: Backend,
235{
236    /// Begin recording command buffer.
237    ///
238    /// # Parameters
239    ///
240    /// `usage` - specifies usage of the command buffer. Possible types are `OneShot`, `MultiShot`.
241    pub fn begin<'a, U, P>(
242        mut self,
243        usage: U,
244        info: impl BeginInfo<'a, B, L, PassRelation = P>,
245    ) -> CommandBuffer<B, C, RecordingState<U, P>, L, R>
246    where
247        U: Usage,
248        P: RenderPassRelation<L>,
249    {
250        let pass_relation = P::default();
251        unsafe {
252            rendy_core::hal::command::CommandBuffer::begin(
253                self.raw(),
254                usage.flags() | pass_relation.flags(),
255                info.inheritance_info(),
256            );
257
258            self.change_state(|_| RecordingState(usage, pass_relation))
259        }
260    }
261}
262
263impl<'a, B, C, U, P, L, R> CommandBuffer<B, C, RecordingState<U, P>, L, R>
264where
265    B: Backend,
266{
267    /// Finish recording command buffer.
268    pub fn finish(mut self) -> CommandBuffer<B, C, ExecutableState<U, P>, L, R> {
269        unsafe {
270            rendy_core::hal::command::CommandBuffer::finish(self.raw());
271
272            self.change_state(|s| ExecutableState(s.0, s.1))
273        }
274    }
275}
276
277impl<B, C, N, L, R> CommandBuffer<B, C, PendingState<N>, L, R>
278where
279    B: Backend,
280{
281    /// Mark command buffer as complete.
282    ///
283    /// # Safety
284    ///
285    /// None of [`Submit`] instances created from this `CommandBuffer` are alive.
286    ///
287    /// If this is `PrimaryLevel` buffer then
288    /// for each command queue where [`Submit`] instance (created from this `CommandBuffer`)
289    /// was submitted at least one [`Fence`] submitted within same `Submission` or later in unset state was `set`.
290    ///
291    /// If this is `Secondary` buffer then
292    /// all primary command buffers where [`Submit`] instance (created from this `CommandBuffer`)
293    /// was submitted must be complete.
294    ///
295    /// [`Submit`]: struct.Submit
296    /// [waiting]: ..rendy_core::hal/device/trait.Device.html#method.wait_for_fences
297    /// [`Fence`]: ..rendy_core::hal/trait.Backend.html#associatedtype.Fence
298    /// [submitted]: ..rendy_core::hal/queue/struct.CommandQueue.html#method.submit
299    pub unsafe fn mark_complete(self) -> CommandBuffer<B, C, N, L, R> {
300        self.change_state(|PendingState(state)| state)
301    }
302}
303
304impl<B, C, S, L> CommandBuffer<B, C, S, L, IndividualReset>
305where
306    B: Backend,
307    S: Resettable,
308{
309    /// Reset command buffer.
310    pub fn reset(self) -> CommandBuffer<B, C, InitialState, L, IndividualReset> {
311        unsafe { self.change_state(|_| InitialState) }
312    }
313}
314
315impl<B, C, S, L> CommandBuffer<B, C, S, L>
316where
317    B: Backend,
318    S: Resettable,
319{
320    /// Mark command buffer as reset.
321    ///
322    /// # Safety
323    ///
324    /// * This function must be used only to reflect command buffer being reset implicitly.
325    /// For instance:
326    /// * [`CommandPool::reset`](struct.CommandPool.html#method.reset) on pool from which the command buffer was allocated.
327    /// * Raw handle usage.
328    pub unsafe fn mark_reset(self) -> CommandBuffer<B, C, InitialState, L> {
329        self.change_state(|_| InitialState)
330    }
331}
332
333impl<B, C, S, L, R> CommandBuffer<B, C, S, L, R>
334where
335    B: Backend,
336    S: Resettable,
337{
338    /// Dispose of command buffer wrapper releasing raw comman buffer value.
339    /// This function is intended to be used to deallocate command buffer.
340    pub fn into_raw(self) -> B::CommandBuffer {
341        self.relevant.dispose();
342        unsafe {
343            // state guarantees that raw command buffer is not shared.
344            *Box::from_raw(self.raw.as_ptr())
345        }
346    }
347
348    /// Get raw command buffer handle.
349    pub fn raw(&mut self) -> &mut B::CommandBuffer {
350        unsafe {
351            // state guarantees that raw command buffer is not shared.
352            self.raw.as_mut()
353        }
354    }
355}