diff --git a/README.md b/README.md index d187ef5..55e5079 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,12 @@ Displays a triangle with vertex colors. cd examples cargo run --bin triangle ``` +#### macOS +Install the [LunarG Vulkan SDK](https://lunarg.com/vulkan-sdk/). This basically entails extracting the downloaded tarball to any location you choose and then setting a few environment variables. Specifically, if `SDK_PATH` is set to the root extracted SDK directory, + +* `DYLD_LIBRARY_PATH = $SDK_PATH/macOS/lib` +* `VK_ICD_FILENAMES = $SDK_PATH/macOS/etc/vulkan/icd.d/MoltenVK_icd.json` +* `VK_LAYER_PATH = $SDK_PATH/macOS/etc/vulkan/explicit_layer.d` ![screenshot](http://i.imgur.com/PQZcL6w.jpg) diff --git a/ash/src/entry.rs b/ash/src/entry.rs index a663932..ec55c45 100644 --- a/ash/src/entry.rs +++ b/ash/src/entry.rs @@ -19,7 +19,10 @@ const LIB_PATH: &'static str = "libvulkan.so.1"; #[cfg(target_os = "android")] const LIB_PATH: &'static str = "libvulkan.so"; -#[cfg(any(target_os = "macos", target_os = "ios"))] +#[cfg(target_os = "macos")] +const LIB_PATH: &'static str = "libvulkan.1.dylib"; + +#[cfg(target_os = "ios")] const LIB_PATH: &'static str = "libMoltenVK.dylib"; lazy_static!{ diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 3ad5c47..a7a26a4 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -10,3 +10,8 @@ ash = { path = "../ash" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.4", features = ["windef", "winuser"] } + +[target.'cfg(target_os = "macos")'.dependencies] +metal-rs = "0.6" +cocoa = "0.13" +objc = "0.2.2" diff --git a/examples/src/lib.rs b/examples/src/lib.rs index 269281f..fcd1cf2 100644 --- a/examples/src/lib.rs +++ b/examples/src/lib.rs @@ -1,16 +1,39 @@ #[macro_use] extern crate ash; -#[cfg(windows)] +#[cfg(target_os = "windows")] extern crate winapi; extern crate winit; +#[cfg(target_os = "macos")] +extern crate objc; +#[cfg(target_os = "macos")] +extern crate cocoa; +#[cfg(target_os = "macos")] +extern crate metal_rs as metal; +#[cfg(target_os = "macos")] +use cocoa::appkit::{NSView, NSWindow}; +#[cfg(target_os = "macos")] +use cocoa::base::id as cocoa_id; +#[cfg(target_os = "macos")] +use metal::CoreAnimationLayer; +#[cfg(target_os = "macos")] +use objc::runtime::YES; +#[cfg(target_os = "macos")] +use std::mem; + use ash::vk; use std::default::Default; use ash::Entry; use ash::Instance; use ash::Device; pub use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, V1_0}; -use ash::extensions::{DebugReport, Surface, Swapchain, Win32Surface, XlibSurface}; +use ash::extensions::{DebugReport, Surface, Swapchain}; +#[cfg(target_os = "windows")] +use ash::extensions::Win32Surface; +#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] +use ash::extensions::XlibSurface; +#[cfg(target_os = "macos")] +use ash::extensions::MacOSSurface; use std::cell::RefCell; use std::ptr; use std::ffi::{CStr, CString}; @@ -88,7 +111,7 @@ pub fn record_submit_commandbuffer( entry: &E, instance: &I, @@ -109,7 +132,41 @@ unsafe fn create_surface( xlib_surface_loader.create_xlib_surface_khr(&x11_create_info, None) } -#[cfg(windows)] +#[cfg(target_os = "macos")] +unsafe fn create_surface( + entry: &E, + instance: &I, + window: &winit::Window, +) -> Result { + use winit::os::macos::WindowExt; + + let wnd: cocoa_id = mem::transmute(window.get_nswindow()); + + let layer = CoreAnimationLayer::new(); + + layer.set_edge_antialiasing_mask(0); + layer.set_presents_with_transaction(false); + layer.remove_all_animations(); + + let view = wnd.contentView(); + + layer.set_contents_scale(view.backingScaleFactor()); + view.setLayer(mem::transmute(layer.as_ref())); + view.setWantsLayer(YES); + + let create_info = vk::MacOSSurfaceCreateInfoMVK { + s_type: vk::StructureType::MacOSSurfaceCreateInfoMvk, + p_next: ptr::null(), + flags: Default::default(), + p_view: window.get_nsview() as *const vk::types::c_void + }; + + let macos_surface_loader = + MacOSSurface::new(entry, instance).expect("Unable to load macOS surface"); + macos_surface_loader.create_macos_surface_mvk(&create_info, None) +} + +#[cfg(target_os = "windows")] unsafe fn create_surface( entry: &E, instance: &I, @@ -133,7 +190,7 @@ unsafe fn create_surface( win32_surface_loader.create_win32_surface_khr(&win32_create_info, None) } -#[cfg(all(unix, not(target_os = "android")))] +#[cfg(all(unix, not(target_os = "android"), not(target_os = "macos")))] fn extension_names() -> Vec<*const i8> { vec![ Surface::name().as_ptr(), @@ -142,6 +199,15 @@ fn extension_names() -> Vec<*const i8> { ] } +#[cfg(target_os = "macos")] +fn extension_names() -> Vec<*const i8> { + vec![ + Surface::name().as_ptr(), + MacOSSurface::name().as_ptr(), + DebugReport::name().as_ptr(), + ] +} + #[cfg(all(windows))] fn extension_names() -> Vec<*const i8> { vec![ @@ -277,6 +343,7 @@ impl ExampleBase { .iter() .map(|raw_name| raw_name.as_ptr()) .collect(); + let extension_names_raw = extension_names(); let appinfo = vk::ApplicationInfo { p_application_name: raw_name,