foundry 0.3.0

A GPU-accelerated cellular automata library using Vulkan
Documentation
use std::sync::Arc;

use super::vulkano::device::Device;
use super::vulkano::device::DeviceExtensions;
use super::vulkano::device::Queue;
use super::vulkano::instance::Features;
use super::vulkano::instance::Instance;
use super::vulkano::instance::InstanceExtensions;
use super::vulkano::instance::PhysicalDevice;
use super::vulkano::instance::PhysicalDeviceType::DiscreteGpu;

pub fn vk_init() -> (Arc<Device>, Arc<Queue>) {
    let instance =
        Instance::new(None, &InstanceExtensions::none(), None).expect("failed to create instance");

    let physical = PhysicalDevice::enumerate(&instance)
        .find(|&dev| dev.ty() == DiscreteGpu)
        .expect("no discrete GPU available");

    let queue_family = physical
        .queue_families()
        .find(|&q| q.supports_graphics())
        .expect("couldn't find a graphical queue family");

    let img_extended_formats_feature = Features {
        shader_storage_image_extended_formats: true,
        ..Features::none()
    };

    let (device, mut queues) = Device::new(
        physical,
        &img_extended_formats_feature,
        &DeviceExtensions::none(),
        [(queue_family, 0.5)].iter().cloned(),
    )
    .expect("failed to create device");

    let queue = queues.next().unwrap();

    (device, queue)
}

pub mod ngs {
    #[derive(VulkanoShader)]
    #[ty = "compute"]
    #[src = "
    #version 450

    layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;

    layout(set = 0, binding = 0, r8) uniform readonly image2D img_in;

    layout(set = 0, binding = 1, r8) uniform writeonly image2D img_out;

    layout(set = 0, binding = 2) buffer Toroidal {
        int opt;
    } tor;

    layout(set = 0, binding = 3) buffer Survival {
        uint rules[];
    } srvl;

    layout(set = 0, binding = 4) buffer Birth {
        uint rules[];
    } brth;

    void main() {
        ivec2 offsets[8] = { ivec2(-1, -1), ivec2(0, -1), ivec2(1, -1), ivec2(-1, 0), ivec2(1, 0),
                             ivec2(-1, 1), ivec2(0, 1), ivec2(1, 1) };
        ivec2 grid_size = imageSize(img_in);
        int living_neighbors = 0;

        for (int i = 0; i < 8; i++) {
            ivec2 access_coord = ivec2(gl_GlobalInvocationID.xy) + offsets[i];

            if (tor.opt != 0) {
                if (access_coord.x == -1) {
                    access_coord.x = grid_size.x - 1;
                }
                if (access_coord.y == -1) {
                    access_coord.y = grid_size.y - 1;
                }
                if (access_coord.x == grid_size.x) {
                    access_coord.x = 0;
                }
                if (access_coord.y == grid_size.y) {
                    access_coord.y = 0;
                }
            }

            if (access_coord.x >= 0 && access_coord.x < grid_size.x && access_coord.y >= 0 &&
                access_coord.y < grid_size.y) {
                if (imageLoad(img_in, access_coord).x == 1.0) {
                    living_neighbors++;
                }
            }
        }

        vec4 to_write = vec4(0.0);

        if (imageLoad(img_in, ivec2(gl_GlobalInvocationID.xy)).x == 1.0) {
            for (int i = 0; i < srvl.rules.length(); i++) {
                if (living_neighbors == srvl.rules[i]) {
                    to_write.x = 1.0;
                }
            }
        } else {
            for (int i = 0; i < brth.rules.length(); i++) {
                if (living_neighbors == brth.rules[i]) {
                    to_write.x = 1.0;
                }
            }
        }

        imageStore(img_out, ivec2(gl_GlobalInvocationID.xy), to_write);
    }
    "]
    struct Dummy;
}

pub mod fms {
    #[derive(VulkanoShader)]
    #[ty = "compute"]
    #[src = "
    #version 450

    layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;

    layout(set = 0, binding = 0, r8) uniform readonly image2D img;

    layout(set = 0, binding = 1) buffer FlatMapX {
        int data[];
    } fmx;

    layout(set = 0, binding = 2) buffer FlatMapY {
        int data[];
    } fmy;

    void main() {
        ivec2 access_coord = ivec2(gl_GlobalInvocationID.xy);

        if (imageLoad(img, access_coord).x == 1.0) {
            fmx.data[access_coord.x] = 1;
            fmy.data[access_coord.y] = 1;
        }
    }
    "]
    struct Dummy;
}