Vulkan Tutorial의 Rust 버전을 해 보았다 ~Window편~

12389 단어 Vulkan입문Rust
Vulkan의 입문을 Rust로 해 나갑니다. 목차는 이쪽 . 이번까지의 구현을 했다 GitHub는 이쪽 .

Vulkan으로 그리기



전회는 Vulkan이라고 하면서 일절 GUI가 나오지 않는 회였습니다만, 드디어 윈도우를 그립니다. 라고 해도, 윈도우 그 자체는 Vulkan 관계 없습니다만.

winit으로 창 표시



Rust의 경우 윈도우 표시에는 winit을 사용하는 경우가 많으므로 여기에서도 winit을 사용합니다. 이하에서는, 최소한의 윈도우 표시와 위도를 닫는 처리를 하고 있습니다.
let event_loop = EventLoop::new();
let _window = WindowBuilder::new().build(&event_loop).unwrap();
event_loop.run(|event, _, control_flow| {
    *control_flow = ControlFlow::Wait;
    match event {
        Event::WindowEvent {
            event: WindowEvent::CloseRequested,
            ..
        } => {
            *control_flow = ControlFlow::Exit;
        }
        _ => {}
    };
});

winit은 비교적 자주 API가 바뀌고 있기 때문에 언제나 익숙하지 않은 느낌입니다만, winit = "0.22.0" 의 단계에서는 이렇게 쓰는 것이 올바른 것 같습니다.

Surface 만들기



Vulkan이 그리는 것은 VkSurfaceKHR 에 대해서이며, 이것은 각 플랫폼 고유의 부분과 Vulkan를 연결하기 위해, 각 윈도우 라이브러리에 대응한 Surface 를 준비할 필요가 있습니다. 이 경우 vulkano-win이 그것에 해당하므로 그것을 사용하여 Surface를 만듭니다.
먼저 InstanceExtensions 를 변경합니다. 지금까지는
InstanceExtensions::supported_by_core().unwrap()

라고 쓰고 있던 곳을,
vulkano_win::required_extensions()

합니다. 그런 다음 위에서
WindowBuilder::new().build(&event_loop)

곳을
WindowBuilder::new().build_vk_surface(&event_loop, instance)

로 변경합니다. 이것으로 얻을 수 있는 값이 Window 로부터 Surface<Window> 로 바뀝니다.

Queue 추가



전회에서는 논리 디바이스의 작성시에 supports_graphics 를 만족하는 Queue 만을 요구하고 있었습니다만, 이번은 표시용의 Queue 도 필요이므로 이것을 추가합니다.

[추기] 여기서 QueueFamily가 중복되지 않도록 하십시오. 그렇지 않으면 런타임 오류로 강제 종료됩니다. [추기 종료]
let (_device, mut queues) = PhysicalDevice::enumerate(&instance)
    .filter_map(|device| {
        let graphics_queue_family = device
            .queue_families()
            .find(|queue_family| queue_family.supports_graphics());
        let present_queue_family = device
            .queue_families()
            .find(|queue_family| surface.is_supported(*queue_family) == Ok(true));
        let mut queue_families_set = HashSet::new();
        let unique_queue_families: Vec<_> = vec![graphics_queue_family, present_queue_family]
            .iter()
            .filter_map(|queue_family| *queue_family)
            .filter(|queue_family| queue_families_set.insert(queue_family.id()))
            .collect();
            Some((device, unique_queue_families))
    })
    .filter_map(|(device, queue_families)| {
        Device::new(
            device,
            &Features::none(),
            &DeviceExtensions::supported_by_device(device),
            queue_families
                .iter()
                .map(|queue_family| (*queue_family, 1.0)),
        )
        .ok()
    })
    .next()
    .expect("Could not find any GPU");

조금 길어져 버렸습니다만, 전회는 1개만 건네주고 있던 QueueFamily 를 복수 건네줄 수 있도록(듯이) 했기 때문입니다.

swap chain 만들기



swap chain이란 이른바 더블 버퍼링이나 트리플 버퍼링이라고 생각합니다. [추기] 아무래도 다른 것 같습니다. 단순히 표시 대기의 이미지의 큐라고 하는 것 같습니다만, 이해 부족입니다. [추기 종료]
swap chainの説明画像
(이미지는 h tps://ゔヵ응.ぅ나 rg. 이 m/도 c/sdk/1. 2.131. HTML에서 인용)

swap chain을 지원하는지 확인



장치가 swap chain을 지원하지 않을 수 있으므로 논리 장치를 만들 때 DeviceExtensions로 swap chain을 요청합니다.
let extensions = DeviceExtensions {
    khr_swapchain: true,
    ..DeviceExtensions::supported_by_device(device)
};
Device::new(
    device,
    &Features::none(),
    &extensions,
    queue_families
    .iter()
    .map(|queue_family| (*queue_family, 1.0)),
)
.ok()

swap chain 요구



위에서 얻은 디바이스는 swap chain에 대응하고 있으므로, 다음은 만들고 싶은 swap chain의 설정을 해, 요구합니다. 덧붙여 Swapchain::new 로 모든 설정을 인수에 건네 가는데 수가 많아, 또 참고원의 값을 거의 그대로 찍고 있을 뿐이므로 개개의 설정에 대해서는 생략합니다.
let (_swapchain, _swapchain_image) = Swapchain::new(...).unwrap();

정리와 감상



이번에는 창을 표시하고 스왑 체인을 만들었습니다. swap chain은 확실히 세세하게 설정할 수 있을 것 같습니다만 그만큼 기술량이 많아 대단하다는, Vulkan다움(?)을 맛보았습니다. 아직 실질 아무것도 표시되어 있지 않습니다만, 다음 번부터 드디어 셰이더에 관련될 것 같습니다.

좋은 웹페이지 즐겨찾기