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:
parent
ac4d046d4b
commit
a1a42c067a
|
@ -2,5 +2,6 @@
|
||||||
members = [
|
members = [
|
||||||
"examples",
|
"examples",
|
||||||
"ash",
|
"ash",
|
||||||
|
"ash-window",
|
||||||
"generator",
|
"generator",
|
||||||
]
|
]
|
||||||
|
|
24
ash-window/Cargo.toml
Normal file
24
ash-window/Cargo.toml
Normal 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
32
ash-window/Changelog.md
Normal 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
64
ash-window/README.md
Normal 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.
|
51
ash-window/examples/winit.rs
Normal file
51
ash-window/examples/winit.rs
Normal 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
177
ash-window/src/lib.rs
Normal 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)
|
||||||
|
}
|
Loading…
Reference in a new issue