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 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
//! Rafx API is an `unsafe` graphics API abstraction layer designed specifically for games and tools
//! for games. The goal is to achieve near-native performance with reduced complexity. It may be
//! used directly, or indirectly through other crates in rafx (such as [rafx-resources] and
//! [rafx-assets]).
//!
//! `rafx-api` is an **opinionated** API. It does not expose every possible operation a graphics API
//! might provide. However, the wrapped API-specific objects are exposed in an easily accessible
//! manner.
//!
//! The API does not track resource lifetimes or states (such as vulkan image layouts) or try to
//! enforce safe usage at compile time or runtime. Safer abstractions are available in
//! rafx-framework and rafx-assets.
//!
//! **Every API call is potentially unsafe.** However, the unsafe keyword is only placed on APIs
//! that are particularly likely to cause undefined behavior if used incorrectly.
//!
//! The general shape of the API is inspired by
//! [The Forge](https://github.com/ConfettiFX/The-Forge). It was chosen for its modern design,
//! multiple working backends, open development model, and track record of shipped games. However,
//! there are some changes in API design, feature set, and implementation details.
//!
//! [Additional high-level documentation is available in the github repo](https://github.com/aclysma/rafx/blob/master/docs/index.md)
//!
//! # Main API Objects
//!
//! * [RafxApi] - Primary entry point to using the API. Use the new_* functions to initialize the desired backend.
//! * [RafxBuffer] - Memory that can be accessed by the rendering API. It may reside in CPU or GPU memory.
//! * [RafxCommandBuffer] - A list of commands recorded by the CPU and submitted to the GPU.
//! * [RafxCommandPool] - A pool of command buffers. A command pool is necessary to create a command buffer.
//! * [RafxDescriptorSetArray] - An array of descriptor sets. These are expected to be pooled and reused.
//! * [RafxDeviceContext] - A cloneable, thread-safe handle used to create graphics resources.
//! * [RafxFence] - A GPU -> CPU synchronization mechanism.
//! * [RafxPipeline] - Represents a complete GPU configuration for executing work.
//! * [RafxQueue] - A queue allows work to be submitted to the GPU
//! * [RafxRootSignature] - Represents the full "layout" or "interface" of a shader (or set of shaders.)
//! * [RafxSampler] - Configures how images will be sampled by the GPU
//! * [RafxSemaphore] - A GPU -> GPU synchronization mechanism.
//! * [RafxShader] - Represents one or more shader stages, producing an entire "program" to execute on the GPU
//! * [RafxShaderModule] - Rrepresents loaded shader code that can be used to create a pipeline.
//! * [RafxSwapchain] - A set of images that act as a "backbuffer" of a window.
//! * [RafxTexture] - An image that can be used by the GPU.
//!
//! # Usage Summary
//!
//! In order to interact with a graphics API, construct a `RafxApi`. A different new_* function
//! exists for each backend.
//!
//! ```ignore
//! let api = RafxApi::new_vulkan(...);
//! ```
//!
//! After initialization, most interaction will be via `RafxDeviceContext` Call
//! `RafxApi::device_context()` on the the api object to obtain a cloneable handle that can be
//! used from multiple threads.
//!
//! ```ignore
//! let device_context = api.device_context();
//! ```
//!
//! Most objects are created via `RafxDeviceContext`. For example:
//!
//! ```ignore
//! // (See examples for more detail here!)
//! let texture = device_context.create_texture(...)?;
//! let buffer = device_context.create_buffer(...)?;
//! let shader_module = device_context.create_shader_module(...)?;
//! ```
//!
//! In order to submit work to the GPU, a `RafxCommandBuffer` must be submitted to a `RafxQueue`.
//! Most commonly, this needs to be a "Graphics" queue.
//!
//! Obtaining a `RafxQueue` is straightforward. Here we will get a "Graphics" queue. This queue type
//! supports ALL operations (including compute) and is usually the correct one to use if you aren't
//! sure.
//!
//! ```ignore
//! let queue = device_context.create_queue(RafxQueueType::Graphics)?;
//! ```
//!
//! A command buffer cannot be created directly. It must be allocated out of a pool.
//!
//! The command pool and all command buffers allocated from it share memory. The standard rust rules
//! about mutability apply but are not enforced at compile time or runtime.
//! * Do not modify two command buffers from the same pool concurrently
//! * Do not allocate from a command pool while modifying one of its command buffers
//! * Once a command buffer is submitted to the GPU, do not modify its pool, or any command buffers
//! created from it, until the GPU completes its work.
//!
//! In general, do not modify textures, buffers, command buffers, or other GPU resources while a
//! command buffer referencing them is submitted. Additionally, these resources must persist for
//! the entire duration of the submitted workload.
//!
//! ```ignore
//! let command_pool = queue.create_command_pool(&RafxCommandPoolDef {
//! transient: true
//! })?;
//!
//! let command_buffer = command_pool.create_command_buffer(&RafxCommandBufferDef {
//! is_secondary: false,
//! })?;
//! ```
//!
//! Once a command buffer is obtained, write to it by calling "cmd" functions on it, For example,
//! drawing primitives looks like this. Call begin() before writing to it, and end() after finished
//! writing to it.
//!
//! ```ignore
//! command_buffer.begin()?;
//! // other setup...
//! command_buffer.cmd_draw(3, 0)?;
//! command_buffer.end()?;
//! ```
//!
//! For the most part, no actual work is performed when calling these functions. We are just
//! "scheduling" work to happen later when we give the command buffer to the GPU.
//!
//! After writing the command buffer, it must be submitted to the queue. The "scheduled" work
//! described in the command buffer will happen asynchronously from the rest of the program.
//!
//! ```ignore
//! queue.submit(
//! &[&command_buffer],
//! &[], // No semaphores or fences in this example
//! &[],
//! None
//! )?;
//! queue.wait_for_queue_idle()?;
//! ```
//!
//! The command buffer, the command pool it was allocated from, all other command buffers allocated
//! from that pool, and any other resources referenced by this command buffer cannot be dropped
//! until the queued work is complete, and generally speaking must remain immutable.
//!
//! More fine-grained synchronization is available via RafxFence and RafxSemaphore but that will
//! not be covered here.
//!
//! # Resource Barriers
//!
//! CPUs generally provide a single "coherent" view of memory, but this is not the case for GPUs.
//! Resources can also be stored in many forms depending on how they are used. (The details of this
//! are device-specific and outside the scope of these docs). Resources must be placed into an
//! appropriate state to use them.
//!
//! Additionally modifying a resource (or transitioning its state) can result in memory hazards. A
//! memory hazard is when reading/writing to memory occurs in an undefined order, resulting in
//! undefined behavior.
//!
//! `Barriers` are used to transition resources into the correct state and to avoid these hazards.
//! Here is an example where we take an image from the swapchain and prepare it for use.
//! (We will also need a barrier after we modify it to transition it back to PRESENT!)
//!
//! ```ignore
//! command_buffer.cmd_resource_barrier(
//! &[], // no buffers to transition
//! &[
//! // Transition `texture` from PRESENT state to RENDER_TARGET state
//! RafxTextureBarrier::state_transition(
//! &texture,
//! RafxResourceState::PRESENT,
//! RafxResourceState::RENDER_TARGET,
//! )
//! ],
//! )?;
//! ```
//!
//! # "Definition" structs
//!
//! Many functions take a "def" parameter. For example, `RafxDeviceContext::create_texture()` takes
//! a single `RafxTextureDef` parameter. Here is an example call:
//!
//! ```ignore
//! let texture = device_context.create_texture(&RafxTextureDef {
//! extents: RafxExtents3D {
//! width: 512,
//! height: 512,
//! depth: 1,
//! },
//! array_length: 1,
//! mip_count: 1,
//! sample_count: RafxSampleCount::SampleCount1,
//! format: RafxFormat::R8G8B8A8_UNORM,
//! resource_type: RafxResourceType::TEXTURE,
//! dimensions: RafxTextureDimensions::Dim2D,
//! })?;
//! ```
//!
//! There are advantages to this approach:
//! * The code is easier to read - parameters are clearly labeled
//! * Default values can be used
//! * When new "parameters" are added, if Default is used, the code will still compile. This avoids
//! boilerplate to implement the builder pattern
//!
//! ```ignore
//! let texture = device_context.create_texture(&RafxTextureDef {
//! extents: RafxExtents3D {
//! width: 512,
//! height: 512,
//! depth: 1,
//! },
//! format: RafxFormat::R8G8B8A8_UNORM,
//! ..Default::default()
//! })?;
//! ```
//!
//!
//
// Re-export upstream metal crates
//
#[cfg(feature = "rafx-metal")]
pub use foreign_types_shared;
#[cfg(feature = "rafx-metal")]
pub use metal_rs;
#[cfg(feature = "rafx-metal")]
pub use objc;
//
// Re-export upstream vulkan crates
//
#[cfg(feature = "rafx-vulkan")]
pub use ash;
#[cfg(feature = "rafx-vulkan")]
pub use gpu_allocator;
//
// Re-export upstream API-agnostic crates
//
pub use raw_window_handle;
//
// Backends
//
#[cfg(feature = "rafx-dx12")]
pub use backends::dx12;
#[cfg(feature = "rafx-dx12")]
pub use backends::dx12::RafxApiDefDx12;
#[cfg(feature = "rafx-metal")]
pub use backends::metal;
#[cfg(feature = "rafx-metal")]
pub use backends::metal::RafxApiDefMetal;
#[cfg(feature = "rafx-vulkan")]
pub use backends::vulkan;
#[cfg(feature = "rafx-vulkan")]
pub use backends::vulkan::RafxApiDefVulkan;
#[cfg(feature = "rafx-gles2")]
pub use backends::gles2;
#[cfg(feature = "rafx-gles2")]
pub use backends::gles2::RafxApiDefGles2;
#[cfg(feature = "rafx-gles3")]
pub use backends::gles3;
#[cfg(feature = "rafx-gles3")]
pub use backends::gles3::RafxApiDefGles3;
#[cfg(any(
feature = "rafx-empty",
not(any(
feature = "rafx-dx12",
feature = "rafx-metal",
feature = "rafx-vulkan",
feature = "rafx-gles2",
feature = "rafx-gles3"
))
))]
pub use backends::empty;
//
// Public modules
//
pub mod extra;
//
// Internal Modules
//
mod backends;
mod error;
mod internal_shared;
mod reflection;
mod types;
//
// API-agnostic API modules
//
mod api;
mod buffer;
mod command_buffer;
mod command_pool;
mod descriptor_set_array;
mod device_context;
mod fence;
mod pipeline;
mod queue;
mod root_signature;
mod sampler;
mod semaphore;
mod shader;
mod shader_module;
mod swapchain;
mod texture;
//
// Constants
//
/// The maximum descriptor set layout index allowed. Vulkan only guarantees up to 4 are available
pub const MAX_DESCRIPTOR_SET_LAYOUTS: usize = 4;
/// The maximum number of simultaneously attached render targets
// In sync with RafxBlendStateTargets
// Also coupled to d3d12 API D3D12_GRAPHICS_PIPELINE_STATE_DESC
pub const MAX_RENDER_TARGET_ATTACHMENTS: usize = 8;
// Vulkan guarantees up to 16
pub const MAX_VERTEX_INPUT_BINDINGS: usize = 16;
//
// Exported public API
//
pub use api::*;
pub use buffer::*;
pub use command_buffer::*;
pub use command_pool::*;
pub use descriptor_set_array::*;
pub use device_context::*;
pub use error::*;
pub use extra::swapchain_helper::*;
pub use fence::*;
pub use pipeline::*;
pub use queue::*;
pub use root_signature::*;
pub use sampler::*;
pub use semaphore::*;
pub use shader::*;
pub use shader_module::*;
pub use swapchain::*;
pub use texture::*;
pub use types::*;