vulkano バージョンアップ V0.17
vulkano が v0.17 にバージョンアップしました。
バージョンアップにともなって、以下の部分が変更になりました。
1 rustc のバージョンアップによる変更
v1.37.0 (2019-08-15)より trait object で dyn を省略するとワーニングが出るように
なりました。"dyn Trait"と書くことが推奨されています。
Box<GpuFuture> => Box<dyn GpuFuture>
2 winit のバージョンアップによる変更
winit のバージョンが v0.21 になりました。
2-1 module 名の変更
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent}; => use winit::window::{WindowBuilder, Window}; use winit::event_loop::{EventLoop, ControlFlow}; use winit::event::{Event, WindowEvent};
2-2 イベントループの変更
loop式(rust) + event_loop.poll_events() method => event_loop.run() method
3 vulkano のバージョンアップによる変更
vulkano のバージョンが v0.17 になりました。
3-1 window dimension の書式の変更
let initial_dimensions = if let Some(dimensions) = window.get_inner_size() { let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into(); [dimensions.0, dimensions.1] } else { return; }; => let dimensions: [u32; 2] = surface.window().inner_size().into();
3-2 swapchain new method の引数の変更
Swapchain::new(device, surface, num_images, format, dimensions, layers, usage, sharing, transform, alpha, mode, clipped, old_swapchain) => Swapchain::new(device, surface, num_images, format, dimensions, layers, usage, sharing, transform, alpha, mode, fullscreen_exclusive, clipped, color_space)
3-3 Vertex struct に対する [#derive]アトリビュートの変更
Default Trait を追加
#[derive(Default, Debug, Clone)] struct Vertex { position: [f32; 2] } vulkano::impl_vertex!(Vertex, position);
3-4 CpuAccessibleBuffer::from_iter method の引数の変更
CpuAccessibleBuffer::from_iter(device, usage, data) => CpuAccessibleBuffer::from_iter(device, usage, host_cached, data)
3-5 DynamicState struct のフィールド数の変更
(v0.16 より変更)
DynamicState { line_width, viewports, scissors } -> DynamicState { line_width, viewports, scissors, compare_mask, write_mask, reference }
3-6 previous_frame_end 変数の扱いの変更
Box::new(sync::now(device.clone())) as Box<dyn GpuFuture> -> Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>)
3-7 swapchain module の acquire_next_image 関数の変更
pub fn acquire_next_image( swapchain, timeout ) -> Result<(usize, SwapchainAcquireFuture), AcquireError> => pub fn acquire_next_image( swapchain, timeout ) -> Result<(usize, bool, SwapchainAcquireFuture), AcquireError>
v0.17 での triangle example は、以下のようになります。
プログラム
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer}; use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState}; use vulkano::device::{Device, DeviceExtensions}; use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract}; use vulkano::image::SwapchainImage; use vulkano::instance::{Instance, PhysicalDevice}; use vulkano::pipeline::GraphicsPipeline; use vulkano::pipeline::viewport::Viewport; use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, ColorSpace, FullscreenExclusive}; use vulkano::swapchain; use vulkano::sync::{GpuFuture, FlushError}; use vulkano::sync; use vulkano_win::VkSurfaceBuild; use winit::window::{WindowBuilder, Window}; use winit::event_loop::{EventLoop, ControlFlow}; use winit::event::{Event, WindowEvent}; use std::sync::Arc; fn main() { // instance let required_extensions = vulkano_win::required_extensions(); let instance = Instance::new(None, &required_extensions, None).unwrap(); // physical device let physical = PhysicalDevice::enumerate(&instance).next().unwrap(); println!("Using device: {} (type: {:?})", physical.name(), physical.ty()); // surface let event_loop = EventLoop::new(); let surface = WindowBuilder::new().build_vk_surface(&event_loop, instance.clone()).unwrap(); // devices and queue let queue_family = physical.queue_families().find(|&q| { q.supports_graphics() && surface.is_supported(q).unwrap_or(false) }).unwrap(); let device_ext = DeviceExtensions { khr_swapchain: true, .. DeviceExtensions::none() }; let (device, mut queues) = Device::new(physical, physical.supported_features(), &device_ext, [(queue_family, 0.5)].iter().cloned()).unwrap(); let queue = queues.next().unwrap(); // swapchain and image let (mut swapchain, images) = { let caps = surface.capabilities(physical).unwrap(); let usage = caps.supported_usage_flags; let alpha = caps.supported_composite_alpha.iter().next().unwrap(); let format = caps.supported_formats[0].0; let dimensions: [u32; 2] = surface.window().inner_size().into(); Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format, dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha, PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap() }; // buffer #[derive(Default, Debug, Clone)] struct Vertex { position: [f32; 2] } vulkano::impl_vertex!(Vertex, position); let vertex_buffer = { //#[derive(Default, Debug, Clone)] //struct Vertex { position: [f32; 2] } //vulkano::impl_vertex!(Vertex, position); CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::all(), false, [ Vertex { position: [-0.5, -0.25] }, Vertex { position: [0.0, 0.5] }, Vertex { position: [0.25, -0.1] } ].iter().cloned()).unwrap() }; // shaders mod vs { vulkano_shaders::shader!{ ty: "vertex", src: " #version 450 layout(location = 0) in vec2 position; void main() { gl_Position = vec4(position, 0.0, 1.0); } " } } mod fs { vulkano_shaders::shader!{ ty: "fragment", src: " #version 450 layout(location = 0) out vec4 f_color; void main() { f_color = vec4(1.0, 0.0, 0.0, 1.0); } " } } let vs = vs::Shader::load(device.clone()).unwrap(); let fs = fs::Shader::load(device.clone()).unwrap(); // rendere_pass let render_pass = Arc::new(vulkano::single_pass_renderpass!( device.clone(), attachments: { color: { load: Clear, store: Store, format: swapchain.format(), samples: 1, } }, pass: { color: [color], depth_stencil: {} } ).unwrap()); // pipeline let pipeline = Arc::new(GraphicsPipeline::start() .vertex_input_single_buffer() .vertex_shader(vs.main_entry_point(), ()) .triangle_list() .viewports_dynamic_scissors_irrelevant(1) .fragment_shader(fs.main_entry_point(), ()) .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) .build(device.clone()) .unwrap()); let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None }; // framebuffers let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state); let mut recreate_swapchain = false; let mut previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>); // event loop event_loop.run(move |event, _, control_flow| { match event { Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => { *control_flow = ControlFlow::Exit; }, Event::WindowEvent { event: WindowEvent::Resized(_), .. } => { recreate_swapchain = true; }, Event::RedrawEventsCleared => { previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let dimensions: [u32; 2] = surface.window().inner_size().into(); let (new_swapchain, new_images) = match swapchain.recreate_with_dimensions(dimensions) { Ok(r) => r, Err(SwapchainCreationError::UnsupportedDimensions) => return, Err(e) => panic!("Failed to recreate swapchain: {:?}", e) }; swapchain = new_swapchain; framebuffers = window_size_dependent_setup(&new_images, render_pass.clone(), &mut dynamic_state); recreate_swapchain = false; } let (image_num, suboptimal, acquire_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { recreate_swapchain = true; return; }, Err(e) => panic!("Failed to acquire next image: {:?}", e) }; if suboptimal { recreate_swapchain = true; } let clear_values = vec!([0.0, 0.0, 1.0, 1.0].into()); // command buffer let command_buffer = AutoCommandBufferBuilder::primary_one_time_submit(device.clone(), queue.family()).unwrap() .begin_render_pass(framebuffers[image_num].clone(), false, clear_values).unwrap() .draw(pipeline.clone(), &dynamic_state, vertex_buffer.clone(), (), ()).unwrap() .end_render_pass().unwrap() .build().unwrap(); let future = previous_frame_end.take().unwrap() .join(acquire_future) .then_execute(queue.clone(), command_buffer).unwrap() .then_swapchain_present(queue.clone(), swapchain.clone(), image_num) .then_signal_fence_and_flush(); match future { Ok(future) => { previous_frame_end = Some(Box::new(future) as Box<_>); }, Err(FlushError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>); } Err(e) => { println!("Failed to flush future: {:?}", e); previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>); } } }, _ => () } }); } /// This method is called once during initialization, then again whenever the window is resized fn window_size_dependent_setup( images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState ) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> { let dimensions = images[0].dimensions(); let viewport = Viewport { origin: [0.0, 0.0], dimensions: [dimensions[0] as f32, dimensions[1] as f32], depth_range: 0.0 .. 1.0, }; dynamic_state.viewports = Some(vec!(viewport)); images.iter().map(|image| { Arc::new( Framebuffer::start(render_pass.clone()) .add(image.clone()).unwrap() .build().unwrap() ) as Arc<dyn FramebufferAbstract + Send + Sync> }).collect::<Vec<_>>() }
Cargo.toml
[package] name = "ex1" version = "0.1.0" authors = ["****"] [dependencies] vulkano = "0.17.0" vulkano-shaders = "0.17.0" vulkano-win = "0.17.0" winit = "0.21"