Switch branches/tags
Nothing to show
Clone or download

README.md

vulkan-tutorial-rs

Rust version of https://github.com/Overv/VulkanTutorial using Vulkano.

Goal: Rust port with code structure as similar as possible to the original C++, so the original tutorial can easily be followed (similar to learn-opengl-rs).

Current State: The chapters Drawing a triangle and Vertex buffers are complete.


Introduction

This tutorial consists of the the ported code and notes about the differences between the original C++ and the Rust code. The explanatory texts generally apply equally, although the Rust version is often shorter due to the use of Vulkano, a safe wrapper around the Vulkan API with some convencience functionality (the final triangle example is about 600 lines, compared to 950 lines in C++).

If you prefer a lower-level API closer to the Vulkan C API, have a look at Ash and vulkan-tutorial-rust.

Overview

https://vulkan-tutorial.com/Overview

(nothing to note here)

Development Environment

https://vulkan-tutorial.com/Development_environment

Download the Vulkan SDK as described, but ignore everything about library and project setup. Instead, create a new Cargo project:

$ cargo new vulkan-tutorial-rs

Then add this to your Cargo.toml:

[dependencies]
vulkano = "0.10.0"

On macOS, copy mac-env.sh, adapt the VULKAN_SDK path if necessary and source the file in your terminal. See also vulkano-rs/vulkano#macos-and-ios-setup.

Drawing a triangle

Setup

Base code

https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Base_code

General structure
extern crate vulkano;

struct HelloTriangleApplication {

}

impl HelloTriangleApplication {
    pub fn initialize() -> Self {
        Self {

        }
    }

    fn main_loop(&mut self) {

    }
}

fn main() {
    let mut app = HelloTriangleApplication::new();
    app.main_loop();
}
Resource management

Vulkano handles calling vkDestroyXXX/vkFreeXXX in the Drop implementation of all wrapper objects, so we will skip all cleanup code.

Integrating GLFW winit

Instead of GLFW we're using winit, an alternative window managment library written in pure Rust.

Add this to your Cargo.toml:

winit = "0.17.1"

And extend your main.rs:

extern crate winit;

use winit::{WindowBuilder, dpi::LogicalSize};

const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;

struct HelloTriangleApplication {
    events_loop: EventsLoop,
}
    pub fn initialize() -> Self {
        let events_loop = Self::init_window();

        Self {
            events_loop,
        }
    }

    fn init_window() -> EventsLoop {
        let events_loop = EventsLoop::new();
        let _window = WindowBuilder::new()
            .with_title("Vulkan")
            .with_dimensions(LogicalSize::new(f64::from(WIDTH), f64::from(HEIGHT)))
            .build(&events_loop);
        events_loop
    }
    fn main_loop(&mut self) {
        loop {
            let mut done = false;
            self.events_loop.poll_events(|ev| {
                match ev {
                    Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => done = true,
                    _ => ()
                }
            });
            if done {
                return;
            }
        }
    }

Complete code

Instance

https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance

Cargo.toml:

vulkano-win = "0.10.0"

main.rs:

extern crate vulkano_win;
use std::sync::Arc;
use vulkano::instance::{
    Instance,
    InstanceExtensions,
    ApplicationInfo,
    Version,
};
struct HelloTriangleApplication {
    instance: Option<Arc<Instance>>,
    events_loop: EventsLoop,
}
    pub fn initialize() -> Self {
        let instance = Self::create_instance();
        let events_loop = Self::init_window();

        Self {
            instance,
            events_loop,
        }
    }
    fn create_instance() -> Arc<Instance> {
        let supported_extensions = InstanceExtensions::supported_by_core()
            .expect("failed to retrieve supported extensions");
        println!("Supported extensions: {:?}", supported_extensions);

        let app_info = ApplicationInfo {
            application_name: Some("Hello Triangle".into()),
            application_version: Some(Version { major: 1, minor: 0, patch: 0 }),
            engine_name: Some("No Engine".into()),
            engine_version: Some(Version { major: 1, minor: 0, patch: 0 }),
        };

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

Complete code

Validation layers

https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Validation_layers

Diff / Complete code

Physical devices and queue families

https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Physical_devices_and_queue_families

Diff / Complete code

Logical device and queues

https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Logical_device_and_queues

Diff / Complete code

Presentation

Window surface

https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Window_surface

Diff / Complete code

Swap chain

https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Swap_chain

Diff / Complete code

Image views

https://vulkan-tutorial.com/Drawing_a_triangle/Presentation/Image_views

We're skipping this section because image views are handled by Vulkano and can be accessed via the SwapchainImages created in the last section.

Graphics pipeline basics

Introduction

https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics

Diff / Complete code

Shader Modules

https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Shader_modules

Instead of compiling the shaders to SPIR-V manually and loading them at runtime, we'll use vulkano-shader-derive to do the same at compile-time. Loading them at runtime is also possible, but a bit more invovled - see the runtime shader example of Vulkano.

Diff / Rust code / Vertex shader / Fragment shader

Fixed functions

https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Fixed_functions

Diff / Complete code

Render passes

https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Render_passes

Diff / Complete code

Conclusion

https://vulkan-tutorial.com/Drawing_a_triangle/Graphics_pipeline_basics/Conclusion

Diff / Complete code

Drawing

Framebuffers

https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Framebuffers

Diff / Complete code

Command buffers

https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Command_buffers

We're skipping the first part because Vulkano maintains a StandardCommandPool.

Diff / Complete code

Rendering and presentation

https://vulkan-tutorial.com/Drawing_a_triangle/Drawing/Rendering_and_presentation

Diff / Complete code

Swapchain recreation

https://vulkan-tutorial.com/Drawing_a_triangle/Swap_chain_recreation

Diff / Complete code

Vertex buffers

Vertex input description

https://vulkan-tutorial.com/Vertex_buffers/Vertex_input_description

Vertex shader diff / Vertex shader

(Rust code combined with next section, since this alone won't compile)

Vertex buffer creation

https://vulkan-tutorial.com/Vertex_buffers/Vertex_buffer_creation

Diff / Complete code

Staging buffer

https://vulkan-tutorial.com/Vertex_buffers/Staging_buffer

We're just replacing CpuAccessibleBuffer with ImmutableBuffer, which uses a staging buffer internally. See vulkano::buffer for an overview of Vulkano's buffer types.

Diff / Complete code

Index buffer

https://vulkan-tutorial.com/Vertex_buffers/Index_buffer

Diff / Complete code

Uniform buffers (TODO)

Texture mapping (TODO)

Depth buffering (TODO)

Loading models (TODO)

Generating Mipmaps (TODO)

Multisampling (TODO)