commit 386b531adc47098c98bd7aaeee732dd950163c8c Author: Willow Date: Thu Sep 3 22:32:17 2026 +0800 initial vulkan init stuff. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fabb133 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,417 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "ash-window" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" +dependencies = [ + "ash", + "raw-window-handle 0.6.2", + "raw-window-metal", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "cc" +version = "1.2.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556e016178bb5662a08681bbe0f00f8e17631781a4dfc8c45e466e4b185ec27f" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation", + "core-foundation", + "core-graphics", + "foreign-types", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation", + "core-graphics-types", + "libc", + "objc", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "dlib" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a" +dependencies = [ + "libloading", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "log" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8" + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quick-xml" +version = "0.39.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "raw-window-handle" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "raw-window-metal" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e8caa82e31bb98fee12fa8f051c94a6aa36b07cddb03f0d4fc558988360ff1" +dependencies = [ + "cocoa", + "core-graphics", + "objc", + "raw-window-handle 0.6.2", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "wayland-backend" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +dependencies = [ + "cc", + "downcast-rs", + "raw-window-handle 0.5.2", + "rustix", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +dependencies = [ + "bitflags 2.13.0", + "rustix", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +dependencies = [ + "proc-macro2", + "quick-xml", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be" +dependencies = [ + "dlib", + "log", + "pkg-config", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "workshop-or-town-or-someshit" +version = "0.1.0" +dependencies = [ + "ash", + "ash-window", + "raw-window-handle 0.6.2", + "wayland-backend", + "wayland-client", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..78e6782 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "workshop-or-town-or-someshit" +version = "0.1.0" +edition = "2024" + +[dependencies] +ash = { version = "0.38.0", features = ["linked"] } +ash-window = "0.13.0" +raw-window-handle = "0.6.2" +wayland-backend = { version = "0.3.15", features = ["client_system", "raw-window-handle"] } +wayland-client = "0.31.14" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..c08b6ab --- /dev/null +++ b/src/main.rs @@ -0,0 +1,230 @@ +use std::{ffi::{CStr, c_void}, ptr::NonNull}; + +use ash::{Entry, Instance, khr, vk::{self, DeviceQueueCreateInfo, PhysicalDevice, PhysicalDeviceFeatures, PhysicalDeviceMemoryProperties, PhysicalDeviceProperties, PresentModeKHR, QueueFamilyProperties, SurfaceCapabilitiesKHR, SurfaceFormatKHR, SurfaceKHR}}; +use raw_window_handle::{RawDisplayHandle, RawWindowHandle, WaylandDisplayHandle, WaylandWindowHandle}; +use wayland_client::Proxy; + +use crate::wayland::{bind_compositor, connect_to_wayland, create_surface}; + +mod wayland; + +#[derive(Clone)] +struct PhysicalDeviceDetail { + properties: PhysicalDeviceProperties, + features: PhysicalDeviceFeatures, + memory_properties: PhysicalDeviceMemoryProperties, + queue_family_properties: Vec<(QueueFamilyProperties, bool)>, + surface_capabilities: SurfaceCapabilitiesKHR, + surface_formats: Vec, + surface_present_modes: Vec, +} + +impl PhysicalDeviceDetail { + fn enumerate(instance: &ash::Instance, surface_loader: &khr::surface::Instance, surface: SurfaceKHR) -> (Vec, Vec) { + let pds = unsafe { instance.enumerate_physical_devices().expect("Failed to enumerate physical devices") }; + pds.iter().map(|pd| (*pd, PhysicalDeviceDetail { + properties: unsafe { instance.get_physical_device_properties(*pd) }, + features: unsafe { instance.get_physical_device_features(*pd) }, + memory_properties: unsafe { instance.get_physical_device_memory_properties(*pd) }, + queue_family_properties: unsafe { instance.get_physical_device_queue_family_properties(*pd).into_iter().enumerate().map(|(qfi,qfp)| (qfp, + surface_loader.get_physical_device_surface_support(*pd, qfi as u32, surface).expect("Failed to get physical device surface support") + ) ).collect::>() }, + surface_capabilities: unsafe { surface_loader.get_physical_device_surface_capabilities(*pd, surface).expect("Failed to get physical device surface support") }, + surface_formats: unsafe { surface_loader.get_physical_device_surface_formats(*pd, surface).expect("Failed to get physical device surface formats") }, + surface_present_modes: unsafe { surface_loader.get_physical_device_surface_present_modes(*pd, surface).expect("Failed to get physical device surface formats") }, + })).collect() + } +} + +struct DeviceQueuesToCreate { + queues: Vec<(u32, Vec)>, //family index, one priority per queue +} + +struct QueueFamilySelection { + graphics: u32, + present: u32, +} + +impl DeviceQueuesToCreate { + fn for_families(families: &QueueFamilySelection) -> DeviceQueuesToCreate { + //Vulkan rejects a queue family index appearing twice in DeviceCreateInfo. + let mut indices = vec![families.graphics]; + if families.present != families.graphics { + indices.push(families.present); + } + + DeviceQueuesToCreate { + queues: indices.into_iter().map(|family| (family, vec![1.0])).collect(), + } + } + + //The returned infos point into self.queues, so they must not outlive it. + fn create_infos(&self) -> Vec> { + self.queues.iter().map(|q| vk::DeviceQueueCreateInfo { + queue_family_index: q.0, + queue_count: q.1.len() as u32, + p_queue_priorities: q.1.as_slice().as_ptr(), + ..Default::default() + } + ).collect() + } +} + + +fn main() { + let (mut wayland_state, mut event_queue) = connect_to_wayland().unwrap(); + bind_compositor(&mut wayland_state).unwrap(); + create_surface(&mut wayland_state).unwrap(); + + let entry = Entry::linked(); + + let display_handle = RawDisplayHandle::Wayland(WaylandDisplayHandle::new(NonNull::new(wayland_state.connection.backend().display_ptr() as *mut c_void).unwrap())); + let mut instance_extensions = ash_window::enumerate_required_extensions(display_handle).expect("Failed to enumerate required instance extensions for surface").to_vec(); + + let application_name = c"Workshop or Town or Someshit"; + let engine_name = c"SomeShit Engine"; + + let instance = construct_instance(&entry, &mut instance_extensions, application_name, engine_name).unwrap(); + + let surface = construct_surface(&mut wayland_state, &entry, &instance).unwrap(); + let surface_loader = khr::surface::Instance::new(&entry, &instance); + + let (pds, pds_detail) = PhysicalDeviceDetail::enumerate(&instance, &surface_loader, surface); + + println!("{} physical devices.", pds.len()); + + //Now we sort through the physical devices to find one that suits. + let (chosen_device, chosen_device_queues, chosen_device_detail) = + choose_physical_device(&pds, &pds_detail).expect("No suitable physical device"); + + let queue_create_infos = chosen_device_queues.create_infos(); + + let enabled_extension_names = vec!(c"VK_KHR_swapchain".as_ptr()); + + let device_create_info = vk::DeviceCreateInfo { + queue_create_info_count: queue_create_infos.len() as u32, + p_queue_create_infos: queue_create_infos.as_ptr(), + ..Default::default() + }.enabled_extension_names(&enabled_extension_names); + + let device = unsafe { instance.create_device(chosen_device, &device_create_info, None).expect("failed to create device") }; + + // Ok, we have a device now. Finally. + // What now? +} + +fn construct_instance(entry: &Entry, extensions: &mut Vec<*const i8>, application_name: &CStr, engine_name: &CStr) -> Result { + + for extension in [c"VK_KHR_display"] { + //For each extension that I know I want. + + //Check if it's already in the list + if extensions.iter().find(|ext| extension.eq(unsafe {CStr::from_ptr(**ext)})).is_none() { + extensions.push(extension.as_ptr()); + } + } + + let app_info = vk::ApplicationInfo { + api_version: vk::make_api_version(0, 1, 0, 0), + application_version: 1, + engine_version: 1, + .. Default::default() + }.application_name(application_name) + .engine_name(engine_name); + + let layers = debug_layers(entry); + + let instance_create_info = vk::InstanceCreateInfo { + p_application_info: &app_info, + ..Default::default() + }.enabled_extension_names(extensions.as_slice()) + .enabled_layer_names(layers.as_slice()); + + Ok(unsafe { entry.create_instance(&instance_create_info, None) + .expect("failed to create instance") + }) +} + +//Validation reports spec violations to stderr. Debug builds only: it costs +//real performance, and a release machine may not have the layer installed. +fn debug_layers(entry: &Entry) -> Vec<*const i8> { + if !cfg!(debug_assertions) { + return Vec::new(); + } + + let validation = c"VK_LAYER_KHRONOS_validation"; + let available = unsafe { entry.enumerate_instance_layer_properties() } + .expect("Failed to enumerate instance layers"); + + if available.iter().any(|l| l.layer_name_as_c_str() == Ok(validation)) { + vec![validation.as_ptr()] + } else { + eprintln!("{validation:?} not installed; running without validation"); + Vec::new() + } +} + +fn construct_surface(wayland_state: &mut wayland::WaylandState, entry: &Entry, instance: &Instance) -> Result { + + let surface_ptr = wayland_state.surface.as_ref().unwrap().id().as_ptr() as *mut c_void; + let window_handle = RawWindowHandle::Wayland( + WaylandWindowHandle::new(NonNull::new(surface_ptr).unwrap()), + ); + + let display_handle = RawDisplayHandle::Wayland(WaylandDisplayHandle::new(NonNull::new(wayland_state.connection.backend().display_ptr() as *mut c_void).unwrap())); + + Ok(unsafe { ash_window::create_surface(entry, instance, display_handle, window_handle, None) + .expect("Failed to create surface") + }) +} + +fn select_queue_families(detail: &PhysicalDeviceDetail) -> Option { + let graphics_families = || { + detail + .queue_family_properties + .iter() + .enumerate() + .filter(|(_, (qfp, _))| qfp.queue_flags.contains(vk::QueueFlags::GRAPHICS)) + }; + + //One family that can do both is preferable, so look for that first. + if let Some((both, _)) = graphics_families().find(|(_, (_, present))| *present) { + return Some(QueueFamilySelection { graphics: both as u32, present: both as u32 }); + } + + let (graphics, _) = graphics_families().next()?; + let (present, _) = detail + .queue_family_properties + .iter() + .enumerate() + .find(|(_, (_, present))| *present)?; + + Some(QueueFamilySelection { graphics: graphics as u32, present: present as u32 }) +} + +fn choose_physical_device( + pds: &[PhysicalDevice], + details: &[PhysicalDeviceDetail], +) -> Option<(PhysicalDevice, DeviceQueuesToCreate, PhysicalDeviceDetail)> { + let (pd, detail, families) = pds + .iter() + .zip(details) + .filter(|(_, detail)| { + !detail.surface_formats.is_empty() && !detail.surface_present_modes.is_empty() + }) + .filter_map(|(pd, detail)| { + select_queue_families(detail).map(|families| (pd, detail, families)) + }) + .max_by_key(|(_, detail, families)| { + let device_type = match detail.properties.device_type { + vk::PhysicalDeviceType::DISCRETE_GPU => 3, + vk::PhysicalDeviceType::INTEGRATED_GPU => 2, + vk::PhysicalDeviceType::VIRTUAL_GPU => 1, + _ => 0, + }; + + (device_type, families.graphics == families.present) + })?; + + Some((*pd, DeviceQueuesToCreate::for_families(&families), detail.clone())) +} diff --git a/src/wayland.rs b/src/wayland.rs new file mode 100644 index 0000000..73203bd --- /dev/null +++ b/src/wayland.rs @@ -0,0 +1,111 @@ +use wayland_client::{ConnectError, Connection, Dispatch, EventQueue, QueueHandle, protocol::{wl_compositor::WlCompositor, wl_display::WlDisplay, wl_registry::{self, WlRegistry}, wl_surface::{self, WlSurface}}}; + +#[derive(Debug)] +pub enum WaylandError { + Connect(ConnectError) +} + +pub type WaylandResult = Result; + +pub struct WaylandState { + pub connection: Connection, + pub display: WlDisplay, + pub queue_handle: QueueHandle, + pub registry: WlRegistry, + pub globals: Vec<(u32, String, u32)>, //name, interface, version + pub compositor: Option, + pub surface: Option, +} + + +impl Dispatch for WaylandState { + fn event( + state: &mut Self, + _: &WlRegistry, + event: wl_registry::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + // When receiving events from the wl_registry, we are only interested in the + // `global` event, which signals a new available global. + // When receiving this event, we just print its characteristics in this example. + if let wl_registry::Event::Global { name, interface, version } = event { + println!("[{}] {} (v{})", name, interface, version); + state.globals.push((name, interface, version)) + } + } +} + +impl Dispatch for WaylandState { + fn event( + _: &mut Self, + _: &WlCompositor, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + //wl_compositor declares no events, so this can never be called. + unreachable!() + } +} + +impl Dispatch for WaylandState { + fn event( + _: &mut Self, + _: &WlSurface, + event: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + //Which outputs we're on. Needed once we care about per-monitor scale. + wl_surface::Event::Enter { .. } | wl_surface::Event::Leave { .. } => {} + //Only sent on wl_surface v6+, which we don't bind yet. + wl_surface::Event::PreferredBufferScale { .. } + | wl_surface::Event::PreferredBufferTransform { .. } => {} + _ => {} + } + } +} + + +pub fn connect_to_wayland() -> WaylandResult<(WaylandState, EventQueue)> { + let connection = Connection::connect_to_env().map_err(WaylandError::Connect)?; + let display = connection.display(); + let mut event_queue = connection.new_event_queue(); + let queue_handle = event_queue.handle(); + let registry = display.get_registry(&queue_handle, ()); + println!("Advertised globals:"); + + let mut state = WaylandState { + connection, + display, + queue_handle, + registry, + globals: Vec::new(), + compositor: None, + surface: None, + }; + + event_queue.roundtrip(&mut state).unwrap(); + + Ok((state, event_queue)) +} + +pub fn bind_compositor(state: &mut WaylandState) -> WaylandResult<()> { + let (name, _, version) = state.globals + .iter() + .find(|(_, interface, _)| interface == "wl_compositor") + .expect("compositor not advertised"); + + state.compositor = Some(state.registry.bind::(*name, (*version).min(6), &state.queue_handle, ())); + Ok(()) +} + +pub fn create_surface(state: &mut WaylandState) -> WaylandResult<()> { + state.surface = Some(if let Some(ref comp) = state.compositor {comp.create_surface(&state.queue_handle, ())} else { panic!("compositor not bound")}); + Ok(()) +} \ No newline at end of file