Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Rust Vulkano Tutorial(1) Window Creation(3) Resize

前回のプログラムは、ウィンドウのリサイズに対応していません。
ウインドウを拡大したとき、描画領域ののサイズが対応していません。

3 ウィンドウのリサイズ
 ウインドウのリサイズに対応するには、ウィンドウをリサイズしたとき、
スワップチェーンとフレームバッファを再作成し、スワップチェーン・
イメージの取得、コマンドの実行を行います。これらの処理は、リサイズが
行われる度に実行するので、繰り返し処理(loop)の中で行います。
また、ウィンドウのリサイズに対応して、スワップチェーンの再作成を
recreate_swapchainフラッグでコントロールします。

ウィンドウのリサイズに関する部分は次のようになります。

let window = surface.window();

let mut recreate_swapchain = false;

loop {
    previous_frame_end.cleanup_finished();

    if recreate_swapchain {
        let dimensions = window.get_inner_size().unwrap();
        let win_width = dimensions.width;
        let win_height = dimensions.height;

        let (new_swapchain, new_images) =
            swapchain.recreate_with_dimension([win_width as u32, win_height as u32])
            .expect("swapcahain not recreate");
        swapchain = new_swapchain;

        framebuffer = new_images.iter().map(|image| {
            Arc::new(Framebuffer::start(render_pass.clone())
            .add(image.clone()).unwrap()
            .build().unwrap())
        }).collect::<Vec<_>>();

        recreate_swapchain = false;
    }

    let (image_num, acquire_future) =
        match swapchain::acquire_next_image(swapchain.clone(), None) {
            Ok(r) => r,
            Err(AcquireError::OutOfDate) => {
                recreate_swapchain = true;
                continue;
            },
            Err(err) => panic!("{:?}", err)
        };
        
    let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(
        device.clone(), queue.family()).unwrap()
        .begin_render_pass(framebuffer[image_num].clone(), false, vec![[0.0, 0.0, 1.0, 1.0].into()])
        .unwrap()
        .end_render_pass()
        .unwrap()
        .build()
        .unwrap();

    let _future = previous_frame_end.join(acquire_future)
        .then_execute(queue.clone(), command_buffer).unwrap()
        .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
        .then_signal_fence_and_flush();

    previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;

    events_loop.poll_events(|event| {
        match event {
            winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. }
                 => done = true,
                
            winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. }
                => recreate_swapchain = true,
               
            _ => ()
        }
    });

    if done { return; }
}


全体のプログラム

#[macro_use]
extern crate vulkano;
extern crate vulkano_win;
extern crate winit;

use vulkano_win::VkSurfaceBuild;
use winit::EventsLoop;
use winit::WindowBuilder;
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::device::Device;
use vulkano::swapchain;
use vulkano::swapchain::{AcquireError, Swapchain, SurfaceTransform, PresentMode};
use vulkano::framebuffer::Framebuffer;
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::sync;
use vulkano::sync::GpuFuture;
use std::sync::Arc;

fn main() {
    let instance = {
        let extensions = vulkano_win::required_extensions();
        Instance::new(None, &extensions, None).expect("failed to create Vulkan instance")
    };

    let mut events_loop = EventsLoop::new();
    let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();

    let window = surface.window();

    let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
    let queue_family = physical.queue_families().find(|&q| {
        q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
    }).unwrap();

    let (device, mut queues) = {
        let device_ext = vulkano::device::DeviceExtensions {
            khr_swapchain: true,
            .. vulkano::device::DeviceExtensions::none()
        };

        Device::new(physical, physical.supported_features(), &device_ext,
            [(queue_family, 0.5)].iter().cloned()).expect("failed to create device")
    };
    let queue = queues.next().unwrap();

    let caps = surface.capabilities(physical)
        .expect("failed to get surface capabilities");
    let dimensions = caps.current_extent.unwrap_or([1280, 1024]);
    let alpha = caps.supported_composite_alpha.iter().next().unwrap();
    let format = caps.supported_formats[0].0;

    let (mut swapchain, images) = Swapchain::new(device.clone(), surface.clone(),
        caps.min_image_count, format, dimensions, 1, caps.supported_usage_flags, &queue,
        SurfaceTransform::Identity, alpha, PresentMode::Fifo, true, None)
        .expect("failed to create swapchain");

    let render_pass = Arc::new(single_pass_renderpass!(device.clone(),
        attachments: {
            color: {
                load: Clear,
                store: Store,
                format: swapchain.format(),
                samples: 1,
            }
        },
        pass: {
            color: [color],
            depth_stencil: {}
        }
    ).unwrap());

    let mut framebuffer = images.iter().map(|image| {
        Arc::new(Framebuffer::start(render_pass.clone())
            .add(image.clone()).unwrap()
            .build().unwrap())
    }).collect::<Vec<_>>();

    let mut previous_frame_end = Box::new(sync::now(device.clone())) as Box<GpuFuture>;

    let mut recreate_swapchain = false;

    let mut done = false;
    loop {
        previous_frame_end.cleanup_finished();

        if recreate_swapchain {
            let dimensions = window.get_inner_size().unwrap();
            let win_width = dimensions.width;
            let win_height = dimensions.height;

            let (new_swapchain, new_images) =
                swapchain.recreate_with_dimension([win_width as u32, win_height as u32])
                .expect("swapcahain not recreate");
            swapchain = new_swapchain;

            framebuffer = new_images.iter().map(|image| {
                Arc::new(Framebuffer::start(render_pass.clone())
                .add(image.clone()).unwrap()
                .build().unwrap())
            }).collect::<Vec<_>>();

            recreate_swapchain = false;
        }

        let (image_num, acquire_future) =
            match swapchain::acquire_next_image(swapchain.clone(), None) {
                Ok(r) => r,
                Err(AcquireError::OutOfDate) => {
                    recreate_swapchain = true;
                    continue;
                },
                Err(err) => panic!("{:?}", err)
            };
        
        let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(
            device.clone(), queue.family()).unwrap()
            .begin_render_pass(framebuffer[image_num].clone(), false, vec![[0.0, 0.0, 1.0, 1.0].into()])
            .unwrap()
            .end_render_pass()
            .unwrap()
            .build()
            .unwrap();

        let _future = previous_frame_end.join(acquire_future)
            .then_execute(queue.clone(), command_buffer).unwrap()
            .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
            .then_signal_fence_and_flush();

        previous_frame_end = Box::new(sync::now(device.clone())) as Box<_>;

        events_loop.poll_events(|event| {
            match event {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. }
                    => done = true,
                winit::Event::WindowEvent { event: winit::WindowEvent::Resized(_), .. }
                    => recreate_swapchain = true,
                _ => ()
            }
        });

        if done { return; }
    }
}