[−][src]Macro em::gpu_do
A macro for declaring a thing that the GPU should do.
By declaring things that the GPU should do, this macro essentially serves as the "accelerating" part of Emu. It assumes a GPU is in scope and focuses on simply using that GPU to accelerate. Here's an example of usage.
#[gpu_use] // removing this will effectively switch to "no GPU" fn main() { let mut data = vec![0.1; 1000]; gpu_do!(load(data)); // load data to the GPU // now that data is loaded, we should not re-allocate it (by changing // its size) in between launches, reads that use the data gpu_do!(launch()); // launch the next thing encountered by the compiler // the next thing is a for loop so Emu compiles it into a "kernel" and // launches the kernel on the GPU for i in 0..1000 { data[i] = data[i] * 10.0; } gpu_do!(read(data)); // read data back from GPU }
Concretely, there are 3 (only 3 at the moment) commands to the GPU that can be declared.
- Loading to the GPU with
gpu_do!(load(data))
- Reading from the GPU with
gpu_do!(read(data))
- Launching on the GPU with
gpu_do!(launch())
Note that data must be an identifier. The only hard requirement for data is that it must have the 2 following methods.
fn as_slice(&self) -> &[f32]
fn as_mut_slice(&mut self) -> &mut [f32]
There is a soft requirement that the data should be representing a list of
f32
s and indexing it with data[i]
should return an f32
. But this is
really just to ensure that when we lift code from CPU to GPU it is
functionally equivalent in a sane way. Also, note that no invocation of
gpu_do!()
will ever expand to anything, unless the function it's being
used in is tagged with `#[gpu_use]
There is also a requirement that once data is loaded, it should not be re-allocated on the CPU in-between launches, reads that make use of it. So basically just make sure you don't resize it.
And in case the example doesn't make
this clear, gpu_do!(launch())
basically attempts to launch the following
expression/piece of code on the GPU. Now, you can't just put any code you
want there. There is a very, very small subset of Rust code that can
be launched. Anything outside of this subset will result in a compile-time
error that will explain to you what was outside of the subset.