[][src]Macro em::gpu_do

macro_rules! gpu_do {
    (load($i:ident)) => { ... };
    (read($i:ident)) => { ... };
    (launch()) => { ... };
}

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.

  1. Loading to the GPU with gpu_do!(load(data))
  2. Reading from the GPU with gpu_do!(read(data))
  3. 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 f32s 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.