vka 0.0.4

A minimal vulkan wrapper
Documentation
#![allow(unused, deprecated)]

use std::ffi::CString;
use std::io::Cursor;
use std::time::Duration;
use std::time::Instant;

use ash::vk;
use vka::*;

pub fn main() {
    env_logger::init();
    let event_loop = winit::event_loop::EventLoop::new().unwrap();
    let window = event_loop
        .create_window(winit::window::WindowAttributes::default().with_inner_size(winit::dpi::PhysicalSize::new(800, 600)))
        .unwrap();
    window.set_resizable(false);
    let rd = RenderingDevice::new(&RenderingDeviceDesc::with_window(&window)).unwrap();
    let mut color_image = rd.new_image(
        &ImageDesc::new_2d(vk::Format::B8G8R8A8_UNORM, 800, 600)
            .samples(4)
            .usage(vk::ImageUsageFlags::COLOR_ATTACHMENT),
    );

    let rpass = rd.new_render_pass(&RenderPassDesc {
        attachments: &[
            Attachment {
                format: color_image.format,
                samples: color_image.samples.as_raw(),
                layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
                ops: Operations::Color {
                    load: LoadOp::Clear(vka::color32(0.0, 1.0, 1.0, 0.5)),
                    store: StoreOp::Discard,
                },
            },
            Attachment {
                format: vk::Format::B8G8R8A8_UNORM,
                samples: 1,
                layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
                ops: Operations::Color {
                    load: LoadOp::Clear(vka::color32(0.0, 1.0, 1.0, 1.0)),
                    store: StoreOp::Store,
                },
            },
        ],
        subpasses: &[Subpass {
            colors: &[(0, Some(1))],
            bind_point: vk::PipelineBindPoint::GRAPHICS,
            ..Default::default()
        }],
    });

    let layout = rd.new_pipeline_layout(&[]);

    let vert_spv = include_bytes!("../shaders/triangle.vert.spv");
    let frag_spv = include_bytes!("../shaders/triangle.frag.spv");

    let vert_module = rd.new_shader(&ash::util::read_spv(&mut Cursor::new(vert_spv)).unwrap());
    let frag_module = rd.new_shader(&ash::util::read_spv(&mut Cursor::new(frag_spv)).unwrap());

    #[repr(C)]
    struct Vertex {
        pos: [f32; 4],
        color: [f32; 4],
    }
    let vertices = [
        Vertex {
            pos: [0.0, -0.5, 0.0, 1.0],
            color: [1.0, 0.0, 0.0, 0.5],
        },
        Vertex {
            pos: [0.5, 0.5, 0.0, 1.0],
            color: [0.0, 1.0, 0.0, 0.5],
        },
        Vertex {
            pos: [-0.5, 0.5, 0.0, 1.0],
            color: [0.0, 0.0, 1.0, 0.5],
        },
    ];
    let vertex_buf = rd.new_buffer(&BufferDesc::vertex((std::mem::size_of::<Vertex>() * 3) as u64));
    rd.write_buffer(&vertex_buf, &vertices, 0);
    rd.submit();
    rd.wait_queue();

    let attributes = vertex_attributes! {
        0 => vk::Format::R32G32B32A32_SFLOAT,
        1 => vk::Format::R32G32B32A32_SFLOAT
    };

    let vertex_input = &[VertexInputLayout {
        binding: 0,
        stride: std::mem::size_of::<Vertex>() as u32,
        rate: vk::VertexInputRate::VERTEX,
        attributes: &attributes,
    }];

    let main_name = CString::new("main").unwrap();

    let pipeline = rd.new_render_pipeline(&vka::RenderPipelineDesc {
        layout: &layout,
        stages: &[
            ShaderStage {
                stage: vk::ShaderStageFlags::VERTEX,
                module: &vert_module,
                name: &main_name,
            },
            ShaderStage {
                stage: vk::ShaderStageFlags::FRAGMENT,
                module: &frag_module,
                name: &main_name,
            },
        ],
        vertex_input,
        input_assembly: InputAssemblyState {
            topology: vk::PrimitiveTopology::TRIANGLE_LIST,
            primitive_restart_enable: false,
        },
        rasterization: RasterizationState::default(),
        multisample: MultisampleState {
            sample_count: color_image.samples.as_raw(),
            ..Default::default()
        },
        depth_stencil: None,
        color_blend: ColorBlendState {
            attachments: &[COLOR_BLEND_REPLACE],
            ..Default::default()
        },
        render_pass: Some(&rpass),
        subpass: 0,
    });

    let mut fps_timer = Instant::now();
    let mut frame_count = 0;
    let mut fps = 0.0;

    let buffer = rd.new_buffer(&BufferDesc::uniform(4 * 1024));

    let mut surface = rd.new_surface(&window, vka::SurfaceConfig::default());

    event_loop.run(|event, event_loop| match event {
        winit::event::Event::WindowEvent { event, .. } => match event {
            winit::event::WindowEvent::RedrawRequested => {
                let extent = surface.swapchain.extent;
                rd.record_frame(&mut surface, |cmd, image| {
                    let views = [color_image.full_view(), image.inner.full_view()];
                    cmd.begin_render_pass(
                        &rpass,
                        &views,
                        vk::Rect2D {
                            offset: vk::Offset2D::default(),
                            extent,
                        },
                    );
                    cmd.set_viewport(
                        0,
                        &[vk::Viewport {
                            x: 0.0,
                            y: 0.0,
                            width: extent.width as f32,
                            height: extent.height as f32,
                            min_depth: 0.0,
                            max_depth: 1.0,
                        }],
                    );
                    cmd.set_scissor(
                        0,
                        &[vk::Rect2D {
                            offset: vk::Offset2D::default(),
                            extent,
                        }],
                    );
                    cmd.bind_pipeline(&pipeline);
                    cmd.bind_vertex_buffers(0, &[vertex_buf.raw], &[0]);
                    cmd.draw(3, 1, 0, 0);
                    cmd.end_render_pass();

                    // let mut data = [0u8; 4];
                    // rd.read_buffer(&buffer, &mut data, 0); // we can submit mid-frame
                });
                rd.submit();
                surface.present();
                rd.advance_frame();

                frame_count += 1;
                let elapsed = fps_timer.elapsed();
                if elapsed >= Duration::from_secs(1) {
                    fps = frame_count as f64 / elapsed.as_secs_f64();
                    log::info!("FPS: {:.2}", fps);
                    frame_count = 0;
                    fps_timer = Instant::now();
                }

                window.request_redraw();
            }
            winit::event::WindowEvent::Resized(s) => {
                log::info!("Resized to {}x{}", s.width, s.height);
                surface.configure(vka::SurfaceConfig {
                    width: s.width,
                    height: s.height,
                    vsync: false,
                    frame_latency: 2,
                });
                color_image = rd.new_image(
                    &ImageDesc::new_2d(vk::Format::B8G8R8A8_UNORM, s.width, s.height)
                        .samples(4)
                        .usage(vk::ImageUsageFlags::COLOR_ATTACHMENT),
                );
                window.request_redraw();
            }
            winit::event::WindowEvent::CloseRequested => {
                event_loop.exit();
            }
            _ => (),
        },
        _ => (),
    });
}