Rafx has three layers:
distill
asset pipelineRafx also provides tools, the main one being rafx-shader-processor
which accepts GLSL shaders and produces assets
necessary to create and use that shader on various platforms.
This document covers just rafx-api
.
RafxFormat
or RafxBufferDef
Rafx is an unsafe API. Functions that are unsafe but purely touch CPU are marked as unsafe, but functions that are unsafe simply because they interact with the GPU are not marked unsafe. (Because if they were, every single API in rafx would be marked unsafe.)
GPU resources must not be dropped if the GPU is using them. Resources must also be in the correct state when they are used. Details on Safety in Rafx
High level rafx “objects” like RafxBuffer
or RafxTexture
are just enums. The
rationale:
RafxBufferVulkan
/RafxBufferMetal
) are always accessiblepub enum RafxBuffer {
Vk(RafxBufferVulkan),
Metal(RafxBufferMetal),
}
While it might first appear that the enum is adding overhead to access the underlying type, this is unlikely:
RafxApi
The first step to using the API is to initialize a RafxApi
.
use rafx::api::RafxApi;
let mut api = RafxApi::new(&sdl2_systems.window, &Default::default())?;
This object may not be dropped until all objects created from it are dropped. RafxApi::destroy()
can optionally be
called to ensure the rafx API completely shuts down at that point. Otherwise, it will be called automatically when
RafxApi
is dropped.
Additionally, the underlying RafxApiMetal
, RafxApiVulkan
, etc. can be obtained by calling RafxApi::metal_api()
or
RafxApi::vk_api()
. The API of these objects is less stable and less documented, but this provides an escape hatch into
the native API if you need it. For example, Rafx does not provide abstraction for raytracing (yet) but you can use Rafx
to set up the vulkan API for you and only write extra vulkan code where necessary.
Once RafxApi
is created, you can get the RafxDeviceContext
by calling RafxApi::device_context()
. The device
context is a cloneable, thread-friendly object. You can create as many as you like.
Most GPU objects are created by calling RafxDeviceContext::create_*
// Get the device context from the API. Clone it and pass it around as much as you like
let device_context = api.device_context();
// Use the device context to create a buffer
device_context.create_buffer(&RafxBufferDef {
size: 512,
memory_usage: RafxMemoryUsage::CpuToGpu,
resource_type: RafxResourceType::VERTEX_BUFFER,
..Default::default()
})
All RafxDeviceContexts (and other Rafx API objects) must be destroyed before dropping RafxApi
or calling
RafxApi::destroy
Some resources have a RafxResourceType
and/or RafxResourceState
Rafx does not provide separate types for every possible kind of resource. A RafxTexture
could be read-only, read-write,
a cube texture, or some combination of the above. Setting a resource type flag enables the resource to be used in
additional ways, but may require additional resources to be created (like for vulkan, a vk::ImageView). In general,
specify only the type flags that you need
Some operations require resources to be placed in the correct state. For example, a RafxTexture
may only be
presented if it is in the PRESENT state. However, while it is being written to, it must be in the RENDER_TARGET
state.
States are required partially because underlying GPU APIs require them. (Like in vulkan, VkImageLayout
).
However, rafx may inject some synchronization or memory barriers for you when a resource changes states.
Descriptor sets can be quite tricky to manage and there are many possible approaches. The API level of rafx only provides a bare minimum layer on top of descriptor sets.
To create a descriptor set, allocate a RafxDescriptorSetArray
. There is some memory overhead to creating this wrapper,
so it is expected that they will be allocated in blocks.
You should try to reuse these blocks. A rafx backend implementation is allowed to permanently leak any descriptor set arrays that you drop. (You should pool and reuse them!)
rafx-framework
provides a system for pooling and reusing descriptor sets in an easy, reference-counted way with many
ergonomic improvements over the low-level API.