Threading Behavior
vk-graph is intended to provide scalable performance when used on multiple host threads.
Resources are externally synchronized, and mutable graph-building APIs such as Graph::begin_cmd
require exclusive access to the Graph itself.
API docs: Submission,
Submission::queue_submit,
Submission::queue_resource,
Submission::queue_resource_dependencies,
CommandBuffer::has_executed.
More precisely, vk-graph stores the most recent access type of each subresource of a resource. As
commands are submitted to the Vulkan implementation queue, the internal state of these resources is
updated.
Resource state is updated during the following function calls:
Submission::queue_submitSubmission::queue_resourceSubmission::queue_resource_dependencies
Caution
Do not call any
Submissionqueue function that accesses buffers, images, or acceleration structures currently being submitted on other threads.
Execution
The provided Submission queue functions are designed to support a typical swapchain-based
workflow:
- Queue all commands the swapchain depends on
- Acquire swapchain
- Queue swapchain commands
- Present swapchain
- Submit any final unrelated commands
Safe Patterns
Resources (buffers, images, or acceleration structures) are the only mutable types which require any
thread safety notes. All other types provided by vk-graph are immutable data structures or Vulkan
handle smart pointers.
For example, there is no race condition or thread contention caused by using the same pipeline on two threads.1 In fact, there is no runtime overhead at all from this.
Additionally, it is safe to build Graph instances, bind resources, record command buffers, and
call Graph::into_submission at any time on any thread, as long as each Graph instance is not
mutably shared across threads at the same time.
These patterns are safe:
- Build
GraphandSendto another thread for submission - Build
GraphandDropit without submission Sendresources to other threads or share asArc<T>Clonedevices or pipelines andSendthem to other threads
Risky Patterns
Host-mappable buffers require extra understanding to use properly.
The contents of a buffer are undefined from the time of submission until that Submission has been
fully executed, as indicated by CommandBuffer::has_executed. This means that you should not call
Buffer::mapped_slice during any submission or execution accessing that memory.
-
The internal implementation of
GraphicPipelinedoes do a bit of caching in order to improve performance, however this behavior should not generate issues with any reasonable workload. ↩