Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Rust Vulkano Tutorial(1) Window Creation(2)

 前回のWindow Creation(1)のつづきです。

2 ウィンドウの初期化
 つづけて、ウィンドウの初期化を行います。次の処理が続きます。
(6)スワップチェーン(Swapchain)とイメージ(SwapchainImage)の作成
(7)レンダーパスと(render_pass)フレームバッファ(framebuffer)の作成
(8)スワップチェーンイメージの取得
(9)コマンドバッファ(command_buffer)の作成
(10)コマンドバッファの実行と同期処理

(6)スワップチェーンとイメージの作成
  ウィンドウサーフェイスへの描画には、スワップチェーンが必要です。
 スワップチェーンは、スワップチェーン・イメージとともに作成します。
 先に、作成に必要となる引数を設定します。

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 (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");

(7)レンダーパスとフレームバッファの作成
  スワップチェーン・イメージは初期化して使用します。初期化は、
 レンダーパスとフレームバッファを使って行います。スワップチェーン・
 イメージの各イメージにレンダーパスを設定し、これらをイメージリスト
 としてまとめたフレームバッファを作成します。

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

(8)スワップチェーンイメージの取得
  スワップチェーンから、スワップチェーンイメージのインデックス
 (image_num)とGPUの描画を管理するオブジェクト(acquire_future)
 を取得します。

let (image_num, acquire_future) = swapchain::acquire_next_image(swapchain.clone(), None).unwrap();

(9)コマンドバッファの作成
  コマンドバッファは、描画等のコマンドを記述したコマンドリストです。
 ここでは、begin_render_passに青色([0.0, 0.0, 1.0, 1.0])で画面を初期化する
 処理を記述しています。

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();

(10)コマンドバッファの実行と同期処理
  初めの行は、GPUの描画を管理するオブジェクト(GpuFuture)のメモリを
 確保(Box)するものです。ここに、先程スワップチェーンから取得した
 acquire_futureを結合します。次にコマンドバッファを実行(then_execute)し、
 スワップチェーンイメージを表示(then_swapchain_present)します。
 最後にこれらの同期処理(then_signal_fence_and_flush)を行います。

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

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();

全体のプログラムは以下のようになります。
初期化したウィンドウを表示します。

#[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::{Swapchain, SurfaceTransform, PresentMode};
use vulkano::swapchain;
use std::sync::Arc;
use vulkano::framebuffer::Framebuffer;
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::sync;
use vulkano::sync::GpuFuture;

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();

    // 02
    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();
    //

    // 03
    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 (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");
    //

    // 04
    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 framebuffer = images.iter().map(|image| {
        Arc::new(Framebuffer::start(render_pass.clone())
            .add(image.clone()).unwrap()
            .build().unwrap())
    }).collect::<Vec<_>>();
    //

    // 05
    let (image_num, acquire_future) = swapchain::acquire_next_image(swapchain.clone(), None).unwrap();

    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();
    //

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

    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();
    //

    let mut done = false;
    loop {
        events_loop.poll_events(|event| {
            match event {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. }
                    => done = true,
                _ => ()
            }
        });

        if done { return; }
    }
}


Cargo.tomlの [dependencies] 部分です。

[dependencies]
vulkano-win = "0.11"
winit = "0.18"
vulkano = "0.11"