-------------------------------------------------------------------- alkomp is a GPGPU library written in Rust for performing compute operations. It's designed to work over [WebGPU](https://www.w3.org/community/gpu/), enabling compute code to work on DirectX, Vulkan, Metal, and eventually OpenCL and the browser. Python bindings work around `numpy` arrays, with an example provided below. ### Example Create your project: `cargo new --bin gpuproject` Add to `cargo.toml`: ``` [dependencies] alkomp = {git = "https://github.com/RustyBamboo/alkomp", branch = "main"} ``` Modify `src/main.rs`. As an example, this code runs the [Collatz](https://en.wikipedia.org/wiki/Collatz_conjecture) sequence on the GPU. ```rust use alkomp; fn main() { let code = " #version 450 layout(local_size_x = 1) in; layout(set = 0, binding = 0) buffer PrimeIndices { uint[] indices; }; uint collatz_iterations(uint n) { uint i = 0; while(n != 1) { if (mod(n, 2) == 0) { n = n / 2; } else { n = (3 * n) + 1; } i++; } return i; } void main() { uint index = gl_GlobalInvocationID.x; indices[index] = collatz_iterations(indices[index]); }"; let mut spirv = alkomp::glslhelper::GLSLCompile::new(&code); let shader = spirv.compile("main").unwrap(); let arr: Vec = vec![1, 2, 3, 4]; let mut device = alkomp::Device::new(0); let data_gpu = device.to_device(arr.as_slice()); let args = alkomp::ParamsBuilder::new() .param(Some(&data_gpu)) .build(Some(0)); let compute = device.compile("main", &shader, &args.0).unwrap(); device.call(compute, (arr.len() as u32, 1, 1), &args.1); let collatz = futures::executor::block_on(device.get(&data_gpu)).unwrap(); let collatz = &collatz[0..collatz.len() - 1]; assert_eq!(&[0, 1, 7, 2], &collatz[..]); } ``` ### Python Wrappers (with numpy) In addition to writing Rust code, it is also possible to write Python code which interfaces with `alkomp`. At this time, the Python interface is designed to specifically work with `numpy ndarrays`. This means you can quickly send a numpy array to a GPU with `data_gpu = device.to_device(my_np_array)` and run a computation using `device.call(...)`. `to_device` returns an object that records the memory location of a GPU buffer, as well shape and type. In order to retrieve the contents of the buffer: `device.get(data_gpu)`. `get` function returns a numpy in the same shape as `my_np_array`. To build the python library read [this](py/README.md). As an example, we do the same computation as above but with python: ```python #!python3 import alkompy import numpy as np arr = np.array(range(1,5), dtype=np.uint32) # Retrieve a GPU device dev = alkompy.Device(0) # Send data to a GPU data_gpu = dev.to_device(arr) # GLSL code to compile code = """ #version 450 layout(local_size_x = 1) in; layout(set = 0, binding = 0) buffer PrimeIndices { uint[] indices; }; uint collatz_iterations(uint n) { uint i = 0; while(n != 1) { if (mod(n, 2) == 0) { n = n / 2; } else { n = (3 * n) + 1; } i++; } return i; } void main() { uint index = gl_GlobalInvocationID.x; indices[index] = collatz_iterations(indices[index]); }""" shader = alkompy.compile_glsl(code) # Run the shader and specifying the order of the bindings dev.run("main", shader, (len(arr), 1, 1), [data_gpu]) result = dev.get(data_gpu) assert((result == np.array([0, 1, 7, 2])).all()) ``` ### TODO - [ ] Build a crate of common operations for GPU - [X] Bindings for Python - [ ] Integrate [rust-gpu](https://github.com/EmbarkStudios/rust-gpu) to write native computer shaders Currently, compute kernel codes, which run on GPU, are not natively written in Rust. [Shaderc](https://github.com/google/shaderc) is used to compile `GLSL` to `SPIR-V`.