前回の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"