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
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! In the Vulkan API, command buffers must be allocated from *command pools*.
//! 
//! A command pool holds and manages the memory of one or more command buffers. If you destroy a
//! command pool, all of its command buffers are automatically destroyed.
//! 
//! In vulkano, creating a command buffer requires passing an implementation of the `CommandPool`
//! trait. By default vulkano will use the `StandardCommandPool` struct, but you can implement
//! this trait yourself by wrapping around the `UnsafeCommandPool` type.

use std::sync::Arc;

use instance::QueueFamily;

use device::Device;
use OomError;
use VulkanObject;
use vk;

pub use self::standard::StandardCommandPool;
pub use self::standard::StandardCommandPoolFinished;
pub use self::sys::UnsafeCommandPool;
pub use self::sys::UnsafeCommandPoolAllocIter;

mod standard;
mod sys;

/// Types that manage the memory of command buffers.
pub unsafe trait CommandPool {
    /// See `alloc()`.
    type Iter: Iterator<Item = AllocatedCommandBuffer>;
    /// See `lock()`.
    type Lock;
    /// See `finish()`.
    type Finished: CommandPoolFinished;

    /// Allocates command buffers from this pool.
    fn alloc(&self, secondary: bool, count: u32) -> Result<Self::Iter, OomError>;

    /// Frees command buffers from this pool.
    ///
    /// # Safety
    ///
    /// - The command buffers must have been allocated from this pool.
    /// - `secondary` must have the same value as what was passed to `alloc`.
    ///
    unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
        where I: Iterator<Item = AllocatedCommandBuffer>;

    /// Once a command buffer has finished being built, it should call this method in order to
    /// produce a `Finished` object.
    ///
    /// The `Finished` object must hold the pool alive.
    ///
    /// The point of this object is to change the Send/Sync strategy after a command buffer has
    /// finished being built compared to before.
    fn finish(self) -> Self::Finished;

    /// Before any command buffer allocated from this pool can be modified, the pool itself must
    /// be locked by calling this method.
    ///
    /// All the operations are atomic at the thread level, so the point of this lock is to
    /// prevent the pool from being accessed from multiple threads in parallel.
    fn lock(&self) -> Self::Lock;

    /// Returns true if command buffers can be reset individually. In other words, if the pool
    /// was created with `reset_cb` set to true.
    fn can_reset_invidual_command_buffers(&self) -> bool;

    /// Returns the device used to create this pool.
    fn device(&self) -> &Arc<Device>;

    /// Returns the queue family that this pool targets.
    fn queue_family(&self) -> QueueFamily;
}

/// See `CommandPool::finish()`.
pub unsafe trait CommandPoolFinished {
    /// Frees command buffers.
    ///
    /// # Safety
    ///
    /// - The command buffers must have been allocated from this pool.
    /// - `secondary` must have the same value as what was passed to `alloc`.
    ///
    unsafe fn free<I>(&self, secondary: bool, command_buffers: I)
        where I: Iterator<Item = AllocatedCommandBuffer>;

    /// Returns the device used to create this pool.
    fn device(&self) -> &Arc<Device>;

    /// Returns the queue family that this pool targets.
    fn queue_family(&self) -> QueueFamily;
}

/// Opaque type that represents a command buffer allocated from a pool.
pub struct AllocatedCommandBuffer(vk::CommandBuffer);

impl From<vk::CommandBuffer> for AllocatedCommandBuffer {
    #[inline]
    fn from(cmd: vk::CommandBuffer) -> AllocatedCommandBuffer {
        AllocatedCommandBuffer(cmd)
    }
}

unsafe impl VulkanObject for AllocatedCommandBuffer {
    type Object = vk::CommandBuffer;

    #[inline]
    fn internal_object(&self) -> vk::CommandBuffer {
        self.0
    }
}