Git Product home page Git Product logo

lava's Introduction

THIS PROJECT IS NO LONGER MAINTAINED

Lava

Wrapper to manipulate the Vulkan API in Rust more conveniently than with bindings:

  • removes the need to specify the structure type when sending structures to Vulkan
  • takes care of making double Vulkan calls when necessary (when retrieving a list of Vulkan objects)
  • returns objects retrieved by Vulkan in a Result instead of requiring a user-provided pointer
  • allows to manipulate references, slices and options instead of pointers (in particular, allows to provide slice instead of pointer + length)
  • exposes the API in an object-oriented way (e.g instance.enumerate_physical_devices() instead of enumerate_physical_devices(&instance))
  • removes the extension suffix from function and data-structure names (modules are used instead)
  • exposes bit flags as structures instead of integers
  • provides a default value for all structures, allowing to "auto-complete" structure with optional fields using ..Default::default()
  • manages the calls to vkGetInstanceProcAddr and vkGetDeviceProcAddr to manipulate functions that are not exposed statically
  • provides a generic create_surface method to create surfaces

Lava is entirely generated from the C header files of Vulkan.

Current restrictions

  • no way to provide allocator callbacks
  • no way to set the pNext field of structures

Usage

[dependencies]
lava = "0.4"

Examples

This code creates a Vulkan instance, adds a debug report callback and displays the name of each GPU of the machine:

#[macro_use] extern crate lava;
use lava::*;

fn main() {
    let instance = vk_create_instance(VkInstanceCreateInfo {
        flags: VkInstanceCreateFlags!(),
        application_info: Some(VkApplicationInfo {
            application_name: Some("lava-example"),
            application_version: 1,
            engine_name: None,
            engine_version: 1,
            api_version: VkVersion(1, 0, 0),
        }),
        enabled_layer_names: vec![VK_LAYER_KHRONOS_VALIDATION_NAME],
        enabled_extension_names: vec![VK_EXT_DEBUG_REPORT_EXTENSION_NAME]
    }).expect("Failed to create instance");

    let debug_report_callback = instance.create_debug_report_callback(VkDebugReportCallbackCreateInfo {
        flags: VkDebugReportFlags!(error, warning),
        callback: |data: VkDebugReportCallbackData| {
            println!("{}", data.message);
        }
    }).expect("Failed to create debug callback");

    let physical_devices = instance.enumerate_physical_devices()
        .expect("Failed to retrieve physical devices");

    for physical_device in &physical_devices {
        let properties = physical_device.get_properties();

        println!("{}", properties.device_name);
    }

    debug_report_callback.destroy();
    instance.destroy();
}

This snippet shows how to create a surface from a GLFW window:

// We assume that `window` is a pointer to a GLFWwindow, as described here:
// http://www.glfw.org/docs/latest/group__vulkan.html#ga1a24536bec3f80b08ead18e28e6ae965

let surface = instance.create_surface(
    |handle, allocator, surface| unsafe { glfwCreateWindowSurface(handle, window, allocator, surface) }
).expect("Failed to create surface from glfw window");

Additional usage information

Module partitionning

Data-structures are separated in multiple modules, according to their extension (KHR, EXT, etc). Data-structures that have no extension are in the lava::vk module.

Some constants (e.g validation layer names) are located in the lava::constants module.

Lava re-exports all the members of lava::vk, lava::constants, lava::ext and lava::khr ("use lava::*" makes all data-structures contained in these modules available without needing to prefix them).

Bit flags

Bit flags are represented as structures instead of integers. Moreover all bit flags structures have static none() and all() functions. The typical way of creating a bit flags structure is as following:

// Creates a structure with the `vertex` and `fragment` flag enabled, and all the others disabled
VkShaderStageFlags {
    vertex: true,
    fragment: true,
    ..VkShaderStageFlags::none()
}

Since it can be tedious to write, all bit flags structures have a macro shortcut:

// Same effect as previous snippet
VkShaderStageFlags!(vertex, fragment)

Additionally, all bit flags structures have the following methods:

let no_shader_stage = VkShaderStageFlags::none();
let all_shader_stages = VkShaderStageFlags::all();
let shader_stages = VkShaderStageFlags::from_u32(17);
let shader_stages_int = shader_stages.to_u32();

Results

When relevant, functions return a Result<T, (VkResult, T)>. The return value is Ok(T) if the VkResult returned by the Vulkan function is 0. Otherwise it's Err((VkResult, T)). The first element of the tuple is the error code returned by the Vulkan function. The second element is, in the specific case where the VkResult is not 0 but is not an error either (e.g when calling swapchain.acquire_next_image()), the value produced by the function. Otherwise it's a zeroed value that will most likely crash when used.

Objects destruction and drop

Users are required to manually destroy their objects themselves, instead of Rust doing it automatically when the object is dropped. There are two reasons for that:

  • In the C API some objects must not be destroyed by the user. For example, the VkImage objects of a swapchain are automatically destroyed when the swapchain is destroyed, and attempting to destroy them manually will produce an error. But the user is still expected to destroy the VkImage objects that they create manually. An automatic destruction mechanism would require some context on where the object comes from, and this is out of scope.
  • The order in which objects are dropped has a good chance to not match the oder in which they must be destroyed, especially when structures are dropped.

Manual build

The content of the src/vulkan/ folder is generated from the vulkan_core.h and vk.xml files of the Vulkan documentation repository.

If you wish to re-generate it manually, you can do (requires Node.js):

  • npm install
  • node generate.js [ --tag <version> ]

Where <version> is a branch or tag name of the Vulkan-Docs repository (for example v1.1.80). If omitted, it defaults to master. The script will download the corresponding files in the download/ folder and generate the new source files.

License

MIT

lava's People

Contributors

symil avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

lava's Issues

Documentation improvements

  • Document all(), none() and to_u32()
  • Have only one impl block implement these 3 methods
  • Remove the flags macros from the front page
  • Document the flags macros in the relevant flags structure

Correctly handle the array of VkResult in VkPresentInfoKHR

I think a reasonnable solution is to have the present method return a Result<Vec<VkResult>, VkResult> and replace the pResults field with a boolean. If the boolean is false, then the returned vector is always empty. If it's true, then the returned vector contains individual results for the swapchains.

Explore macros to create flags structures faster

It's tedious to do things like:

command_buffer.begin(&VkCommandBufferBeginInfo {
    flags: VkCommandBufferUsageFlags {
        simultaneous_use: true,
        ..VkCommandBufferUsageFlags::none()
    },
    inheritance_info: None
});

Something like that would be better:

command_buffer.begin(&VkCommandBufferBeginInfo {
    flags: vk_flags!(simultaneous_use),
    inheritance_info: None
});

Return the VkResult and the return value if the result is not success

List of methods for which a non VK_SUCCESS VkResult is still a success:

  • vkAcquireNextImageKHR: VK_SUBOPTIMAL_KHR is valid and must be also retrieved to the caller
  • vkQueuePresentKHR: same as above
  • vkGetSwapchainStatusKHR: VK_SUCCESS and VK_SUBOPTIMAL_KHR indicate the status of the swapchain
  • vkGetFenceStatus: VK_SUCCESS and VK_NOT_READY mean "signaled" and "unsignaled"
  • vkGetEventStatus: can return VK_EVENT_SET or VK_EVENT_RESET, which indicate the state of the event, maybe would require their own enum (signaled or unsignaled)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.