Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

Rust Vulkano Tutorial(1) Window Creation(1)

Rust Vulkano のチュートリアルです。
今回は初期化したウィンドウ(Window)の作成について記述しています。
Vulkanoガイド(https://vulkano.rs/guide/introduction)とVulkano Triangle Example
https://github.com/vulkano-rs/vulkano)を参考にしています。

1 Vulkanオブジェクトの初期化
 Vulkanでは直接GPUを扱います。GPUにアクセスできるように、Vulkanデバイス
(Device)を作成します。
 Vulkanデバイスの作成には、決まった手続きがあります。次のようにして
 作成します。
 (1)インスタンス(Instance)の作成
 (2)サーフェイス(Surface)の作成
 (3)物理デバイス(Physical_device)の取得
 (4)キュー・ファミリー(Queue_family)の取得
 (5)Vulkanデバイス(Device)とキュー(Queue)の作成

(1)インスタンスの作成

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

(2)サーフェイスの作成
  キュー・ファミリーの取得時に必要となるので、ここでサーフェイスを
 作成します。同時にウィンドウも作成されます。

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

  サーフェイスの作成時にイベント・ループ(EventsLoop)が必要となるので、
 先にイベント・ループを作成します。

(3)物理デバイスの取得
  使用する物理デバイスを取得します。

let physical = PhysicalDevice::enumerate(&instance).next().unwrap();

  使用可能な物理デバイスを列挙(enumerate)し、最初のデバイスを取得
 (next)します。

(4)キュー・ファミリーの取得
  Vulkanデバイスの作成時に必要となるので、ここで物理デバイスからキュー・
 ファミリーを取得します。
  条件「q.supports_graphics() && surface.is_supported(q)」を満たすキュー・
 ファミリー(グラフィックス用でサーフェイスに描画できる
 キュー・ファミリー)を取り出します。

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

(5)Vulkanデバイスとキューの作成
  Vulkanデバイスとキューを作成します。

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

  最後の行で、作成したqueues(キューのイテレータ)から、最初の要素
 (next)を使用するキューとして取り出します。

 ここまでの段階では、作成されたウィンドウは瞬時に閉じてしまいます。
そこで、events_loopを使ってウィンドウの表示を行います。

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

    if done { return; }
}

 ウィンドウの終了フラッグ(done)を用いて、ウィンドウのクローズボタンが
押されたときにウィンドウを閉じるようにします。

 これで、黒い画面(初期化されていない)のウィンドウが表示されます。

 全体のプログラムは、次のようになります。

extern crate vulkano_win;
extern crate winit;
extern crate vulkano;

use vulkano_win::VkSurfaceBuild;
use winit::EventsLoop;
use winit::WindowBuilder;
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::device::Device;

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

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

    // Physical Device
    let physical = PhysicalDevice::enumerate(&instance).next().unwrap();

    // QueueFamily
    let queue_family = physical.queue_families().find(|&q| {
        q.supports_graphics() && surface.is_supported(q).unwrap_or(false)
    }).unwrap();

    // Device and Queues
    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 mut done = false;
    loop {
        // EventsLoop
        events_loop.poll_events(|event| {
            match event {
                winit::Event::WindowEvent { event: winit::WindowEvent::CloseRequested, .. }
                    => done = true,
                _ => ()
            }
        });

        if done { return; }
    }
}