wgcore 0.2.2

Utilities and abstractions for composable WGSL shaders.
Documentation
use nalgebra::{DVector, Vector4};
use wgcore::composer::ComposerExt;
use wgcore::gpu::GpuInstance;
use wgcore::kernel::{KernelInvocationBuilder, KernelInvocationQueue};
use wgcore::tensor::{GpuScalar, GpuVector};
use wgcore::Shader;
use wgpu::{BufferUsages, ComputePipeline};
use wgcore::hot_reloading::HotReloadState;

#[derive(Shader)]
#[shader(
    src = "hot_reloading.wgsl",
    composable = false
)]
struct ShaderHotReloading {
    main: ComputePipeline
}

#[async_std::main]
async fn main() -> anyhow::Result<()> {
    // Initialize the gpu device and its queue.
    //
    // Note that `GpuInstance` is just a simple helper struct for initializing the gpu resources.
    // You are free to initialize them independently if more control is needed, or reuse the ones
    // that were already created/owned by e.g., a game engine.
    let gpu = GpuInstance::new().await?;

    // Load and compile our kernel. The `from_device` function was generated by the `Shader` derive.
    // Note that its dependency to `Composable` is automatically resolved by the `Shader` derive
    // too.
    let mut kernel = ShaderHotReloading::from_device(gpu.device())?;

    // Create the buffers.
    let buffer = GpuScalar::init(gpu.device(), 0u32, BufferUsages::STORAGE | BufferUsages::COPY_SRC);
    let staging = GpuScalar::init(gpu.device(), 0u32, BufferUsages::COPY_DST | BufferUsages::MAP_READ);

    // Init hot-reloading.
    let mut hot_reload = HotReloadState::new()?;
    ShaderHotReloading::watch_sources(&mut hot_reload)?;

    // Queue the operation.
    println!("#############################");
    println!("Edit the file `hot_reloading.wgsl`.\nThe updated result will be printed below whenever a change is detected.");
    println!("#############################");

    for loop_id in 0.. {
        // Detect & apply changes.
        hot_reload.update_changes();
        match kernel.reload_if_changed(gpu.device(), &hot_reload) {
            Ok(changed) => {
                if changed || loop_id == 0 {
                    // We detected a change (or this is the first loop).
                    // Read the result.
                    let mut queue = KernelInvocationQueue::new(gpu.device());
                    KernelInvocationBuilder::new(&mut queue, &kernel.main)
                        .bind0([buffer.buffer()])
                        .queue(1);

                    // Encode & submit the operation to the gpu.
                    let mut encoder = gpu.device().create_command_encoder(&Default::default());
                    // Run our kernel.
                    queue.encode(&mut encoder, None);
                    // Copy the result to the staging buffer.
                    staging.copy_from(&mut encoder, &buffer);
                    gpu.queue().submit(Some(encoder.finish()));

                    let result_read = staging.read(gpu.device()).await.unwrap();
                    println!("Current result value: {}", result_read[0]);
                }
            }
            Err(e) => {
                // Hot-reloading failed, likely due to a syntax error in the shader.
                println!("Hot reloading error: {:?}", e);
            }
        }
    }

    Ok(())
}