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
212
213
214
215
216
217
218
219
220
221
222
223
// 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.

//! Safe and rich Rust wrapper around the Vulkan API.
//! 
//! # Brief summary of Vulkan
//!
//! - The `Instance` object is the API entry point. It is the first object you must create before
//!   starting to use Vulkan.
//!
//! - The `PhysicalDevice` object represents an implementation of Vulkan available on the system
//!   (eg. a graphics card, a CPU implementation, multiple graphics card working together, etc.).
//!   Physical devices can be enumerated from an instance with `PhysicalDevice::enumerate()`.
//!
//! - Once you have chosen a physical device to use, you can a `Device` object from it. The
//!   `Device` is the most important object of Vulkan, as it represents an open channel of
//!   communicaton with a physical device.
//!
//! - `Buffer`s and `Image`s can be used to store data on memory accessible from the GPU (or
//!   Vulkan implementation). Buffers are usually used to store vertices, lights, etc. or
//!   arbitrary data, while images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a `Swapchain`. A `Swapchain` contains
//!   special `Image`s that correspond to the content of the window or the monitor. When you
//!   *present* a swapchain, the content of one of these special images is shown on the screen.
//!
//! - `ComputePipeline`s and `GraphicsPipeline`s describe the way the GPU must perform a certain
//!   operation. `Shader`s are programs that the GPU will execute as part of a pipeline.
//!   Descriptors can be used to access the content of buffers or images from within shaders.
//!
//! - For graphical operations, `RenderPass`es and `Framebuffer`s describe on which images the
//!   implementation must draw upon.
//!
//! - In order to ask the GPU to do something, you must create a `CommandBuffer`. A `CommandBuffer`
//!   contains a list of commands that the GPU must perform. This can include copies between
//!   buffers, compute operations, or graphics operations. For the work to start, the
//!   `CommandBuffer` must then be submitted to a `Queue`, which is obtained when you create
//!   the `Device`.
//!

//#![warn(missing_docs)]        // TODO: activate
#![allow(dead_code)]            // TODO: remove
#![allow(unused_variables)]     // TODO: remove

extern crate crossbeam;
extern crate fnv;
#[macro_use]
extern crate lazy_static;
extern crate shared_library;
extern crate smallvec;
extern crate vk_sys as vk;

#[macro_use]
mod tests;

mod features;
mod version;

pub mod buffer;
pub mod command_buffer;
pub mod descriptor;
pub mod device;
pub mod format;
#[macro_use]
pub mod framebuffer;
pub mod image;
pub mod instance;
pub mod memory;
pub mod pipeline;
pub mod query;
pub mod sampler;
pub mod swapchain;
pub mod sync;

use std::error;
use std::fmt;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::MutexGuard;

/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the internal identifier of an object.
pub unsafe trait SynchronizedVulkanObject {
    /// The type of the object.
    type Object;

    /// Returns a reference to the object.
    fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
}

/// Gives access to the Vulkan function pointers stored in this object.
trait VulkanPointers {
    /// The struct that provides access to the function pointers.
    type Pointers;

    // Returns a reference to the pointers.
    fn pointers(&self) -> &Self::Pointers;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl error::Error for OomError {
    #[inline]
    fn description(&self) -> &str {
        match *self {
            OomError::OutOfHostMemory => "no memory available on the host",
            OomError::OutOfDeviceMemory => "no memory available on the graphical device",
        }
    }
}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", error::Error::description(self))
    }
}

impl From<Error> for OomError {
    #[inline]
    fn from(err: Error) -> OomError {
        match err {
            Error::OutOfHostMemory => OomError::OutOfHostMemory,
            Error::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err)
        }
    }
}

/// All possible success codes returned by any Vulkan function.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
enum Success {
    Success = vk::SUCCESS,
    NotReady = vk::NOT_READY,
    Timeout = vk::TIMEOUT,
    EventSet = vk::EVENT_SET,
    EventReset = vk::EVENT_RESET,
    Incomplete = vk::INCOMPLETE,
    Suboptimal = vk::SUBOPTIMAL_KHR,
}

/// All possible errors returned by any Vulkan function.
///
/// This type is not public. Instead all public error types should implement `From<Error>` and
/// panic for error code that arent supposed to happen.
#[derive(Debug, Copy, Clone)]
#[repr(u32)]
#[doc(hidden)]      // TODO: this is necessary because of the stupid visibility rules in rustc
pub enum Error {
    OutOfHostMemory = vk::ERROR_OUT_OF_HOST_MEMORY,
    OutOfDeviceMemory = vk::ERROR_OUT_OF_DEVICE_MEMORY,
    InitializationFailed = vk::ERROR_INITIALIZATION_FAILED,
    DeviceLost = vk::ERROR_DEVICE_LOST,
    MemoryMapFailed = vk::ERROR_MEMORY_MAP_FAILED,
    LayerNotPresent = vk::ERROR_LAYER_NOT_PRESENT,
    ExtensionNotPresent = vk::ERROR_EXTENSION_NOT_PRESENT,
    FeatureNotPresent = vk::ERROR_FEATURE_NOT_PRESENT,
    IncompatibleDriver = vk::ERROR_INCOMPATIBLE_DRIVER,
    TooManyObjects = vk::ERROR_TOO_MANY_OBJECTS,
    FormatNotSupported = vk::ERROR_FORMAT_NOT_SUPPORTED,
    SurfaceLost = vk::ERROR_SURFACE_LOST_KHR,
    NativeWindowInUse = vk::ERROR_NATIVE_WINDOW_IN_USE_KHR,
    OutOfDate = vk::ERROR_OUT_OF_DATE_KHR,
    IncompatibleDisplay = vk::ERROR_INCOMPATIBLE_DISPLAY_KHR,
    ValidationFailed = vk::ERROR_VALIDATION_FAILED_EXT,
}

/// Checks whether the result returned correctly.
fn check_errors(result: vk::Result) -> Result<Success, Error> {
    match result {
        vk::SUCCESS => Ok(Success::Success),
        vk::NOT_READY => Ok(Success::NotReady),
        vk::TIMEOUT => Ok(Success::Timeout),
        vk::EVENT_SET => Ok(Success::EventSet),
        vk::EVENT_RESET => Ok(Success::EventReset),
        vk::INCOMPLETE => Ok(Success::Incomplete),
        vk::ERROR_OUT_OF_HOST_MEMORY => Err(Error::OutOfHostMemory),
        vk::ERROR_OUT_OF_DEVICE_MEMORY => Err(Error::OutOfDeviceMemory),
        vk::ERROR_INITIALIZATION_FAILED => Err(Error::InitializationFailed),
        vk::ERROR_DEVICE_LOST => Err(Error::DeviceLost),
        vk::ERROR_MEMORY_MAP_FAILED => Err(Error::MemoryMapFailed),
        vk::ERROR_LAYER_NOT_PRESENT => Err(Error::LayerNotPresent),
        vk::ERROR_EXTENSION_NOT_PRESENT => Err(Error::ExtensionNotPresent),
        vk::ERROR_FEATURE_NOT_PRESENT => Err(Error::FeatureNotPresent),
        vk::ERROR_INCOMPATIBLE_DRIVER => Err(Error::IncompatibleDriver),
        vk::ERROR_TOO_MANY_OBJECTS => Err(Error::TooManyObjects),
        vk::ERROR_FORMAT_NOT_SUPPORTED => Err(Error::FormatNotSupported),
        vk::ERROR_SURFACE_LOST_KHR => Err(Error::SurfaceLost),
        vk::ERROR_NATIVE_WINDOW_IN_USE_KHR => Err(Error::NativeWindowInUse),
        vk::SUBOPTIMAL_KHR => Ok(Success::Suboptimal),
        vk::ERROR_OUT_OF_DATE_KHR => Err(Error::OutOfDate),
        vk::ERROR_INCOMPATIBLE_DISPLAY_KHR => Err(Error::IncompatibleDisplay),
        vk::ERROR_VALIDATION_FAILED_EXT => Err(Error::ValidationFailed),
        c => unreachable!("Unexpected error code returned by Vulkan: {}", c)
    }
}