* Expose gpu allocation configuration options This commit adds hints to control memory allocations strategies to the configuration options. These hints allow for automatic profiles such as optimizing for performance (the default, makes sense for a game), optimizing for memory usage (typically more useful for a web browser or UI library) and specifying settings manually. The details of gpu allocation are still in flux. The goal is to switch vulkan and metal to gpu_allocator which is currently used with d3d12. gpu_allocator will also likely receive more configuration options, in particular the ability to start with smaller memory block sizes and progressively grow the block size. So the manual settings already provision for this upcoming option. Another approach could be to wait and add the manual option after the dust settles. The reason for providing presets and defining values in the backends is that I am convinced that optimal fonigurations should take hardware capabilities into consideration. It's a deep rabbithole, though, so that will be an exercise for later. * changelog * Update CHANGELOG.md Co-authored-by: Andreas Reich <r_andreas2@web.de> * Add a comment about not entirely knowing what we are doing --------- Co-authored-by: Andreas Reich <r_andreas2@web.de>
hello_synchronization
This example is
- A small demonstration of the importance of synchronization.
- How basic synchronization you can understand from the CPU is preformed on the GPU.
To Run
cargo run --bin wgpu-examples hello_synchronization
A Primer on WGSL Synchronization Functions
The official documentation is a little scattered and sparse. The meat of the subject is found here but there's also a bit on control barriers here. The most important part comes from that first link though, where the spec says "the affected memory and atomic operations program-ordered before the synchronization function must be visible to all other threads in the workgroup before any affected memory or atomic operation program-ordered after the synchronization function is executed by a member of the workgroup." And at the second, we also get "a control barrier is executed by all invocations in the same workgroup as if it were executed concurrently."
That's rather vague (and it is by design) so let's break it down and make a comparison that should make that sentence come a bit more into focus. Barriers in Rust fit both bills rather nicely. Firstly, Rust barriers are executed as if they were executed concurrently because they are - at least as long as you define the execution by when it finishes, when Barrier::wait finally unblocks the thread and execution continues concurrently from there. Rust barriers also fit the first bill; because all affected threads must execute Barrier::wait in order for execution to continue, we can guarantee that all (synchronous) operations ordered before the wait call are executed before any operations ordered after the wait call begin execution. Applying this to WGSL barriers, we can think of a barrier in WGSL as a checkpoint all invocations within each workgroup must reach before the entire workgroup continues with the program together.
There are two key differences though and one is that although Rust barriers don't enforce that atomic operations called before the barrier are visible after the barrier, WGSL barriers do. This is incredibly useful and important though and is demonstrated in this example.
Another is that WGSL's synchronous functions only affect memory and atomic operations in a certain address space. This applies to the whole 'all atomic operations called before the function are visible after the function' thing. There are currently three different synchronization functions:
storageBarrierwhich works in the storage address space and is a simple barrier.workgroupBarrierwhich works in the workgroup address space and is a simple barrier.workgroupUniformLoadwhich also works in the workgroup address space and is more than just a barrier. Read up on all three here.