Add interoperability functions for raw-window-handle (#308)

* Add ash-window as workspace member

* ash-window: fix repository link

* ash-window: Address CI fmt&clippy issues

* ash-window: Try fix SDL2 CI issues

* ash-window: Remove beryllium example
This commit is contained in:
msiglreith 2020-07-04 15:21:39 +02:00 committed by GitHub
parent ac4d046d4b
commit a1a42c067a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 349 additions and 0 deletions

View file

@ -2,5 +2,6 @@
members = [ members = [
"examples", "examples",
"ash", "ash",
"ash-window",
"generator", "generator",
] ]

24
ash-window/Cargo.toml Normal file
View file

@ -0,0 +1,24 @@
[package]
name = "ash-window"
version = "0.4.1"
authors = ["msiglreith <m.siglreith@gmail.com>"]
edition = "2018"
license = "MIT OR Apache-2.0"
description = "Interop library between ash and raw-window-handle"
documentation = "https://docs.rs/ash-window"
repository = "https://github.com/MaikKlein/ash"
readme = "README.md"
keywords = ["window", "ash", "graphics"]
categories = ["game-engines", "graphics"]
exclude = [".github/*"]
workspace = ".."
[dependencies]
ash = { path = "../ash" }
raw-window-handle = "0.3"
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies]
raw-window-metal = "0.1"
[dev-dependencies]
winit = "0.19.4"

32
ash-window/Changelog.md Normal file
View file

@ -0,0 +1,32 @@
### Changelog
## [Unreleased]
### Changed
- `impl HasRawWindowHandle` to `dyn HasRawWindowHandle`
## Version 0.4.1
### Changed
- Use `raw-window-metal` to automatically allocate a `CAMetalLayer` if there is none
## Version 0.4.0
### Changed
- Update `ash` version to 0.31
## Version 0.3.0
### Changed
- Update `ash` version to 0.30
## Version 0.2.0
### Changed
- `enumerate_required_extension` renamed to `enumerate_required_extensions`
- `enumerate_required_extensions` will return an error if the window handle is not supported instead of panic.
- `enumerate_required_extensions` may return multiple extension names. Includes all dependent extensions.
- `create_surface` will return an error if the window handle is not supported instead of panic.
## Version 0.1.0
Initial release for `raw-window-handle = "0.3"` with Windows, Linux, Android, MacOS/iOS support.

64
ash-window/README.md Normal file
View file

@ -0,0 +1,64 @@
<h1 align="center">ash-window</h1>
<p align="center">
<a href="https://crates.io/crates/ash-window">
<img src="https://img.shields.io/crates/v/ash-window?style=flat-square" alt = "crates.io">
</a>
<a href="https://docs.rs/ash-window">
<img src="https://docs.rs/ash-window/badge.svg?style=flat-square" alt="docs">
</a>
<a href="https://github.com/MaikKlein/ash/actions">
<img src="https://github.com/MaikKlein/ash/workflows/CI/badge.svg?style=flat" alt="ci">
</a>
<br>
<a href="LICENSE-MIT">
<img src="https://img.shields.io/badge/license-MIT-green.svg?style=flat-square" alt="License - MIT">
</a>
<a href="LICENSE-APACHE">
<img src="https://img.shields.io/badge/license-APACHE2-green.svg?style=flat-square" alt="License - Apache2">
</a>
</p>
Interoperability between [`ash`](https://github.com/MaikKlein/ash) and [`raw-window-handle`](https://github.com/rust-windowing/raw-window-handle) for surface creation.
```toml
ash-window = "0.4"
```
## Usage
The library exposes two functions:
- `enumerate_required_extensions` returns the required instance extensions needed for surface creation from a specific window handle.
- `create_surface` allows to create a surface from a type implementing `HasRawWindowHandle`
```rust
ash_window::create_surface(&entry, &instance, &window, None)?;
```
## Versions
```toml
ash = "0.31"
raw-window-handle = "0.3"
```
## Support
- [x] Windows (`VK_KHR_win32_surface`)
- [x] Unix (`VK_KHR_xlib_surface`/`VK_KHR_xcb_surface`/`VK_KHR_wayland_surface`)
- [x] MacOS/IOS (`VK_EXT_metal_surface`)
- [x] Android (`VK_KHR_android_surface`)
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
## Contribution
Unless you explicitly state otherwise, any Contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

View file

@ -0,0 +1,51 @@
//! Demonstrate interop with beryllium/SDL windows.
//!
//! Sample creates a surface from a window through the
//! platform agnostic window handle trait.
//!
//! On instance extensions platform specific extensions need to be enabled.
use ash::{version::EntryV1_0, vk};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let mut events_loop = winit::EventsLoop::new();
let window = winit::WindowBuilder::new()
.with_dimensions((800, 600).into())
.build(&events_loop)?;
unsafe {
let entry = ash::Entry::new()?;
let surface_extensions = ash_window::enumerate_required_extensions(&window)?;
let instance_extensions = surface_extensions
.iter()
.map(|ext| ext.as_ptr())
.collect::<Vec<_>>();
let app_desc = vk::ApplicationInfo::builder().api_version(vk::make_version(1, 0, 0));
let instance_desc = vk::InstanceCreateInfo::builder()
.application_info(&app_desc)
.enabled_extension_names(&instance_extensions);
let instance = entry.create_instance(&instance_desc, None)?;
// Create a surface from winit window.
let surface = ash_window::create_surface(&entry, &instance, &window, None)?;
let surface_fn = ash::extensions::khr::Surface::new(&entry, &instance);
println!("surface: {:?}", surface);
let mut running = true;
while running {
events_loop.poll_events(|event| match event {
winit::Event::WindowEvent {
event: winit::WindowEvent::CloseRequested,
..
} => running = false,
_ => (),
});
}
surface_fn.destroy_surface(surface, None);
}
Ok(())
}

177
ash-window/src/lib.rs Normal file
View file

@ -0,0 +1,177 @@
use ash::{
extensions::khr,
prelude::*,
version::{EntryV1_0, InstanceV1_0},
vk,
};
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
use std::ffi::CStr;
#[cfg(any(target_os = "macos", target_os = "ios"))]
use ash::extensions::ext; // portability extensions
/// Create a surface from a raw surface handle.
///
/// `instance` must have created with platform specific surface extensions enabled.
///
/// # Safety
///
/// In order for the created `SurfaceKHR` to be valid for the duration of its
/// usage, the `Instance` this was called on must be dropped later than the
/// resulting `SurfaceKHR`.
pub unsafe fn create_surface<E, I>(
entry: &E,
instance: &I,
window_handle: &dyn HasRawWindowHandle,
allocation_callbacks: Option<&vk::AllocationCallbacks>,
) -> VkResult<vk::SurfaceKHR>
where
E: EntryV1_0,
I: InstanceV1_0,
{
match window_handle.raw_window_handle() {
#[cfg(target_os = "windows")]
RawWindowHandle::Windows(handle) => {
let surface_desc = vk::Win32SurfaceCreateInfoKHR::builder()
.hinstance(handle.hinstance)
.hwnd(handle.hwnd);
let surface_fn = khr::Win32Surface::new(entry, instance);
surface_fn.create_win32_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Wayland(handle) => {
let surface_desc = vk::WaylandSurfaceCreateInfoKHR::builder()
.display(handle.display)
.surface(handle.surface);
let surface_fn = khr::WaylandSurface::new(entry, instance);
surface_fn.create_wayland_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Xlib(handle) => {
let surface_desc = vk::XlibSurfaceCreateInfoKHR::builder()
.dpy(handle.display as *mut _)
.window(handle.window);
let surface_fn = khr::XlibSurface::new(entry, instance);
surface_fn.create_xlib_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Xcb(handle) => {
let surface_desc = vk::XcbSurfaceCreateInfoKHR::builder()
.connection(handle.connection as *mut _)
.window(handle.window);
let surface_fn = khr::XcbSurface::new(entry, instance);
surface_fn.create_xcb_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(target_os = "android"))]
RawWindowHandle::Android(handle) => {
let surface_desc =
vk::AndroidSurfaceCreateInfoKHR::builder().window(handle.a_native_window as _);
let surface_fn = khr::AndroidSurface::new(entry, instance);
surface_fn.create_android_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(target_os = "macos"))]
RawWindowHandle::MacOS(handle) => {
use raw_window_metal::{macos, Layer};
let layer = match macos::metal_layer_from_handle(handle) {
Layer::Existing(layer) | Layer::Allocated(layer) => layer as *mut _,
Layer::None => return Err(vk::Result::ERROR_INITIALIZATION_FAILED),
};
let surface_desc = vk::MetalSurfaceCreateInfoEXT::builder().layer(&*layer);
let surface_fn = ext::MetalSurface::new(entry, instance);
surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)
}
#[cfg(any(target_os = "ios"))]
RawWindowHandle::IOS(handle) => {
use raw_window_metal::{ios, Layer};
let layer = match ios::metal_layer_from_handle(handle) {
Layer::Existing(layer) | Layer::Allocated(layer) => layer as *mut _,
Layer::None => return Err(vk::Result::ERROR_INITIALIZATION_FAILED),
};
let surface_desc = vk::MetalSurfaceCreateInfoEXT::builder().layer(&*layer);
let surface_fn = ext::MetalSurface::new(entry, instance);
surface_fn.create_metal_surface(&surface_desc, allocation_callbacks)
}
_ => Err(vk::Result::ERROR_EXTENSION_NOT_PRESENT), // not supported
}
}
/// Query the required instance extensions for creating a surface from a window handle.
///
/// The returned extensions will include all extension dependencies.
pub fn enumerate_required_extensions(
window_handle: &dyn HasRawWindowHandle,
) -> VkResult<Vec<&'static CStr>> {
let extensions = match window_handle.raw_window_handle() {
#[cfg(target_os = "windows")]
RawWindowHandle::Windows(_) => vec![khr::Surface::name(), khr::Win32Surface::name()],
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Wayland(_) => vec![khr::Surface::name(), khr::WaylandSurface::name()],
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Xlib(_) => vec![khr::Surface::name(), khr::XlibSurface::name()],
#[cfg(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
RawWindowHandle::Xcb(_) => vec![khr::Surface::name(), khr::XcbSurface::name()],
#[cfg(any(target_os = "android"))]
RawWindowHandle::Android(_) => vec![khr::Surface::name(), khr::AndroidSurface::name()],
#[cfg(any(target_os = "macos"))]
RawWindowHandle::MacOS(_) => vec![khr::Surface::name(), ext::MetalSurface::name()],
#[cfg(any(target_os = "ios"))]
RawWindowHandle::IOS(_) => vec![khr::Surface::name(), ext::MetalSurface::name()],
_ => return Err(vk::Result::ERROR_EXTENSION_NOT_PRESENT),
};
Ok(extensions)
}