Expand description
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. 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
§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.
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.
let device_context = api.device_context();
Most objects are created via RafxDeviceContext
. For example:
// (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.
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.
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.
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.
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!)
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:
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
let texture = device_context.create_texture(&RafxTextureDef {
extents: RafxExtents3D {
width: 512,
height: 512,
depth: 1,
},
format: RafxFormat::R8G8B8A8_UNORM,
..Default::default()
})?;
Re-exports§
pub use raw_window_handle;
pub use extra::swapchain_helper::*;
pub use crate::extra::indirect::*;
Modules§
Structs§
- Rafx
ApiDef - General configuration that all APIs will make best effort to respect
- Rafx
Blend State - Affects the way the result of a pixel shader is blended with a value it will overwrite. Commonly used to enable “alpha-blending”.
- Rafx
Blend State Render Target - Configures blend state for a particular render target
- Rafx
Blend State Targets - Indicates what render targets are affected by a blend state
- Rafx
Buffer Barrier - A memory barrier for buffers. This is used to transition buffers between resource states and possibly from one queue to another
- Rafx
Buffer Def - Used to create a
RafxBuffer
- Rafx
Buffer Element Data - Rafx
CmdBlit Params - Parameters for blitting one image to another (vulkan backend only)
- Rafx
CmdCopy Buffer ToBuffer Params - Parameters for copying a buffer to a texture
- Rafx
CmdCopy Buffer ToTexture Params - Parameters for copying a buffer to a texture
- Rafx
CmdCopy Texture ToTexture Params - Rafx
Color Clear Value - A clear value for color attachments
- Rafx
Color Flags - Flags for enabling/disabling color channels, used with
RafxBlendState
- Rafx
Color Render Target Binding - A color render target bound during a renderpass
- Rafx
Command Buffer Def - Used to create a
RafxCommandBuffer
- Rafx
Command Pool Def - Used to create a
RafxCommandPool
- Rafx
Compute Pipeline Def - Used to create a
RafxPipeline
for compute operations - Rafx
Depth State - Affects depth testing and stencil usage. Commonly used to enable “Z-buffering”.
- Rafx
Depth Stencil Clear Value - A clear values for depth/stencil attachments. One or both values may be used depending on the format of the attached image
- Rafx
Depth Stencil Render Target Binding - A depth/stencil render target to be bound during a renderpass
- Rafx
Descriptor Elements - Specifies what value to assign to a descriptor set
- Rafx
Descriptor Index - A rafx-specific index that refers to a particular binding. Instead of doing name/binding lookups every frame, query the descriptor index during startup and use it instead. This is a more efficient way to address descriptors.
- Rafx
Descriptor SetArray Def - Used to create a
RafxDescriptorSetArray
- Rafx
Descriptor Update - Describes how to update a single descriptor
- Rafx
Device Info - Information about the device, mostly limits, requirements (like memory alignment), and flags to indicate whether certain features are supported
- Rafx
Dispatch Indirect Command - Rafx
Draw Indexed Indirect Command - Rafx
Draw Indirect Command - Rafx
Extents2D - A 2d size for windows, textures, etc.
- Rafx
Extents3D - A 3d size for windows, textures, etc.
- Rafx
GlUniform Member - Rafx
Graphics Pipeline Def - Used to create a
RafxPipeline
for graphics operations - Rafx
Hashed Shader Package - A shader package and its hash. This allows storing the package with a pre-generated hash to file. The shader package is immutable to ensure the hash is never stale.
- Rafx
Immutable Samplers - Describes an immutable sampler key/value pair
- Rafx
Index Buffer Binding - An index buffer to be bound during a renderpass
- Rafx
Offset Size - Used in various APIs where we supply an offset/size pair
- Rafx
Pipeline Reflection - Reflection data for a pipeline, created by merging shader stage reflection data
- Rafx
Rasterizer State - Affects rasterization, commonly used to enable backface culling or wireframe rendering
- Rafx
Reflected Descriptor SetLayout - Rafx
Reflected Descriptor SetLayout Binding - Rafx
Reflected Entry Point - Rafx
Reflected Vertex Input - Rafx
Resource State - The current state of a resource. When an operation is performed that references a resource, it must be in the correct state. Resources are moved between state using barriers.
- Rafx
Resource Type - Indicates how a resource will be used. In some cases, multiple flags are allowed.
- Rafx
Root Signature Def - Used to create a
RafxRootSignature
- Rafx
Sampler Def - Used to create a
RafxSampler
- Rafx
Shader Module Def - Used to create a RafxShaderModule
- Rafx
Shader Package - Owns data necessary to create a shader module in (optionally) multiple APIs.
- Rafx
Shader Package Hash - Provides a stable has for contents of a shader package
- Rafx
Shader Resource - A data source within a shader. Often a descriptor or push constant.
- Rafx
Shader Resource Binding Key - Indicates where a resource is bound
- Rafx
Shader Stage Def - Describes a single stage within a shader
- Rafx
Shader Stage Flags - Indicates a particular stage of a shader, or set of stages in a shader. Similar to VkShaderStageFlagBits
- Rafx
Shader Stage Reflection - Reflection data for a single shader stage
- Rafx
Swapchain Def - Used to create a
RafxSwapchain
- Rafx
Swapchain Image - Represents an image owned by the swapchain
- Rafx
Texture Barrier - A memory barrier for textures. This is used to transition textures between resource states and possibly from one queue to another.
- Rafx
Texture Def - Used to create a
RafxTexture
- Rafx
Vertex Buffer Binding - A vertex buffer to be bound during a renderpass
- Rafx
Vertex Layout - Describes how vertex attributes are laid out within one or more buffers
- Rafx
Vertex Layout Attribute - Describes an attribute within a RafxVertexLayout
- Rafx
Vertex Layout Buffer - Describes a buffer that provides vertex attribute data (See RafxVertexLayout)
Enums§
- Rafx
Address Mode - Affects image sampling, particularly for UV coordinates outside the [0, 1] range. Similar to VkSamplerAddressMode
- RafxApi
- Primary entry point to using the API. Use the
new_*
functions to initialize the desired backend. - Rafx
ApiType - Rafx
Barrier Queue Transition - Determines if a barrier is transferring a resource from one queue to another.
- Rafx
Blend Factor - Affects blending. Similar to VkBlendFactor
- Rafx
Blend Op - Affects blending. Similar to VkBlendOp
- Rafx
Buffer - Memory that can be accessed by the rendering API. It may reside in CPU or GPU memory.
- Rafx
Color Type - The color space an image data is in. The correct color space often varies between texture types (like normal maps vs. albedo maps).
- Rafx
Command Buffer - A list of commands recorded by the CPU and submitted to the GPU.
- Rafx
Command Pool - A pool of command buffers. A command pool is necessary to create a command buffer.
- Rafx
Compare Op - Affects depth testing and sampling. Similar to VkCompareOp
- Rafx
Cull Mode - Determines if we cull polygons that are front-facing or back-facing. Facing direction is determined by RafxFrontFace, sometimes called “winding order”. Similar to VkCullModeFlags
- Rafx
Descriptor Key - Selects a particular descriptor in a descriptor set
- Rafx
Descriptor SetArray - An array of descriptor sets. These are expected to be pooled and reused.
- Rafx
Descriptor SetHandle - A lightweight handle to a specific descriptor set in a
RafxDescriptorSetArray
. - Rafx
Device Context - A cloneable, thread-safe handle used to create graphics resources.
- Rafx
Error - Generic error that contains all the different kinds of errors that may occur when using the API
- Rafx
Fence - A GPU -> CPU synchronization mechanism.
- Rafx
Fence Status - Indicates the current state of a fence.
- Rafx
Fill Mode - Whether to fill in polygons or not. Similar to VkPolygonMode
- Rafx
Filter Type - Filtering method when sampling. Similar to VkFilter
- Rafx
Format - Describes the encoding of an image or buffer.
- Rafx
Front Face - Determines what winding order is considerered the front face of a polygon. Similar to VkFrontFace
- Rafx
Immutable Sampler Key - Indicates which immutable sampler is being set
- Rafx
Index Type - The size of index buffer elements
- Rafx
Load Op - Determines if the contents of an image attachment in a renderpass begins with its previous contents, a clear value, or undefined data. Similar to VkAttachmentLoadOp
- Rafx
Memory Usage - Indicates how the memory will be accessed and affects where in memory it needs to be allocated.
- Rafx
MipMap Mode - Similar to VkSamplerMipmapMode
- Rafx
Pipeline - Represents a complete GPU configuration for executing work.
- Rafx
Pipeline Type - Indicates the type of pipeline, roughly corresponds with RafxQueueType
- Rafx
Present Success Result - Indicates the result of presenting a swapchain image
- Rafx
Primitive Topology - How to intepret vertex data into a form of geometry. Similar to VkPrimitiveTopology
- Rafx
Queue - A queue allows work to be submitted to the GPU
- Rafx
Queue Type - Used to indicate which type of queue to use. Some operations require certain types of queues.
- Rafx
Root Signature - Represents the full “layout” or “interface” of a shader (or set of shaders.)
- Rafx
Sample Count - Number of MSAA samples to use. 1xMSAA and 4xMSAA are most broadly supported
- Rafx
Sampler - Configures how images will be sampled by the GPU
- Rafx
Semaphore - A GPU -> GPU synchronization mechanism.
- Rafx
Shader - Represents one or more shader stages, producing an entire “program” to execute on the GPU
- Rafx
Shader Module - Rrepresents loaded shader code that can be used to create a pipeline.
- Rafx
Shader Package Dx12 - Metal-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is used to initialize a shader module GPU object
- Rafx
Shader Package Gles2 - GL ES 2.0-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is used to initialize a shader module GPU object
- Rafx
Shader Package Gles3 - GL ES 3.0-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is used to initialize a shader module GPU object
- Rafx
Shader Package Metal - Metal-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is used to initialize a shader module GPU object
- Rafx
Shader Package Vulkan - Vulkan-specific shader package. Can be used to create a RafxShaderModuleDef, which in turn is used to initialize a shader module GPU object
- Rafx
Stencil Op - Similar to VkStencilOp
- Rafx
Store Op - Determines if the contents of an image attachment in a rander pass will store the resulting state for use after the render pass
- Rafx
Swapchain - A set of images that act as a “backbuffer” of a window.
- Rafx
Swapchain Color Space - Rafx
Texture - An image that can be used by the GPU.
- Rafx
Texture Bind Type - Used when binding a texture to select between different ways to bind the texture
- Rafx
Texture Dimensions - Determines how many dimensions the texture will have.
- Rafx
Validation Mode - Controls if validation is enabled or not. The requirements/behaviors of validation is API-specific.
- Rafx
Vertex Attribute Rate - Affects how quickly vertex attributes are consumed from buffers, similar to VkVertexInputRate
Constants§
- ALL_
SHADER_ STAGE_ FLAGS - Contains all the individual stages
- MAX_
DESCRIPTOR_ SET_ LAYOUTS - The maximum descriptor set layout index allowed. Vulkan only guarantees up to 4 are available
- MAX_
RENDER_ TARGET_ ATTACHMENTS - The maximum number of simultaneously attached render targets
- MAX_
VERTEX_ INPUT_ BINDINGS - RAFX_
VALID_ API_ TYPES