From f3eee020e67f5bfdbad00d531117b81e3d01888a Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 30 Mar 2020 09:07:07 -0400 Subject: [PATCH] Check surface compatibility --- examples/triangle/main.c | 95 +++++++++++++++++++------------------ ffi/wgpu.h | 5 +- wgpu-core/src/hub.rs | 26 +++++++--- wgpu-core/src/instance.rs | 76 +++++++++++++++++++++++++---- wgpu-native/src/device.rs | 4 +- wgpu-remote/src/identity.rs | 30 ++++++------ wgpu-remote/src/server.rs | 2 +- wgpu-types/src/lib.rs | 15 ------ 8 files changed, 158 insertions(+), 95 deletions(-) diff --git a/examples/triangle/main.c b/examples/triangle/main.c index 0b12294e8..695335914 100644 --- a/examples/triangle/main.c +++ b/examples/triangle/main.c @@ -43,10 +43,58 @@ void request_adapter_callback(WGPUAdapterId received, void *userdata) { } int main() { + if (!glfwInit()) { + printf("Cannot initialize glfw"); + return 1; + } + + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + GLFWwindow *window = + glfwCreateWindow(640, 480, "wgpu with glfw", NULL, NULL); + + if (!window) { + printf("Cannot create window"); + return 1; + } + + WGPUSurfaceId surface; + +#if WGPU_TARGET == WGPU_TARGET_MACOS + { + id metal_layer = NULL; + NSWindow *ns_window = glfwGetCocoaWindow(window); + [ns_window.contentView setWantsLayer:YES]; + metal_layer = [CAMetalLayer layer]; + [ns_window.contentView setLayer:metal_layer]; + surface = wgpu_create_surface_from_metal_layer(metal_layer); + } +#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11 + { + Display *x11_display = glfwGetX11Display(); + Window x11_window = glfwGetX11Window(window); + surface = wgpu_create_surface_from_xlib((const void **)x11_display, x11_window); + } +#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND + { + struct wl_display *wayland_display = glfwGetWaylandDisplay(); + struct wl_surface *wayland_surface = glfwGetWaylandWindow(window); + surface = wgpu_create_surface_from_wayland(wayland_surface, wayland_display); + } +#elif WGPU_TARGET == WGPU_TARGET_WINDOWS + { + HWND hwnd = glfwGetWin32Window(window); + HINSTANCE hinstance = GetModuleHandle(NULL); + surface = wgpu_create_surface_from_windows_hwnd(hinstance, hwnd); + } +#else + #error "Unsupported WGPU_TARGET" +#endif + WGPUAdapterId adapter = { 0 }; wgpu_request_adapter_async( &(WGPURequestAdapterOptions){ .power_preference = WGPUPowerPreference_LowPower, + .compatible_surface = surface, }, 2 | 4 | 8, request_adapter_callback, @@ -153,53 +201,6 @@ int main() { .sample_count = 1, }); - if (!glfwInit()) { - printf("Cannot initialize glfw"); - return 1; - } - - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - GLFWwindow *window = - glfwCreateWindow(640, 480, "wgpu with glfw", NULL, NULL); - - if (!window) { - printf("Cannot create window"); - return 1; - } - - WGPUSurfaceId surface; - -#if WGPU_TARGET == WGPU_TARGET_MACOS - { - id metal_layer = NULL; - NSWindow *ns_window = glfwGetCocoaWindow(window); - [ns_window.contentView setWantsLayer:YES]; - metal_layer = [CAMetalLayer layer]; - [ns_window.contentView setLayer:metal_layer]; - surface = wgpu_create_surface_from_metal_layer(metal_layer); - } -#elif WGPU_TARGET == WGPU_TARGET_LINUX_X11 - { - Display *x11_display = glfwGetX11Display(); - Window x11_window = glfwGetX11Window(window); - surface = wgpu_create_surface_from_xlib((const void **)x11_display, x11_window); - } -#elif WGPU_TARGET == WGPU_TARGET_LINUX_WAYLAND - { - struct wl_display *wayland_display = glfwGetWaylandDisplay(); - struct wl_surface *wayland_surface = glfwGetWaylandWindow(window); - surface = wgpu_create_surface_from_wayland(wayland_surface, wayland_display); - } -#elif WGPU_TARGET == WGPU_TARGET_WINDOWS - { - HWND hwnd = glfwGetWin32Window(window); - HINSTANCE hinstance = GetModuleHandle(NULL); - surface = wgpu_create_surface_from_windows_hwnd(hinstance, hwnd); - } -#else - #error "Unsupported WGPU_TARGET" -#endif - int prev_width = 0; int prev_height = 0; glfwGetWindowSize(window, &prev_width, &prev_height); diff --git a/ffi/wgpu.h b/ffi/wgpu.h index 201b117bc..774ebf719 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -/* Generated with cbindgen:0.13.2 */ +/* Generated with cbindgen:0.13.1 */ /* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen. * To generate this file: @@ -19,6 +19,8 @@ #include #include +#define WGPUBIND_BUFFER_ALIGNMENT 256 + #define WGPUDEFAULT_BIND_GROUPS 4 #define WGPUDESIRED_NUM_FRAMES 3 @@ -695,6 +697,7 @@ typedef WGPUId_RenderBundle_Dummy WGPURenderBundleId; typedef struct { WGPUPowerPreference power_preference; + WGPUSurfaceId compatible_surface; } WGPURequestAdapterOptions; typedef uint32_t WGPUBackendBit; diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 0d634be25..63e42d128 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -39,7 +39,7 @@ use vec_map::VecMap; #[cfg(debug_assertions)] use std::cell::Cell; -use std::{fmt::Debug, marker::PhantomData, ops}; +use std::{fmt::Debug, iter, marker::PhantomData, ops}; /// A simple structure to manage identities of objects. @@ -271,7 +271,7 @@ impl IdentityHandler for Mutex { pub trait IdentityHandlerFactory { type Filter: IdentityHandler; - fn spawn(&self) -> Self::Filter; + fn spawn(&self, min_index: Index) -> Self::Filter; } #[derive(Debug)] @@ -279,8 +279,11 @@ pub struct IdentityManagerFactory; impl IdentityHandlerFactory for IdentityManagerFactory { type Filter = Mutex; - fn spawn(&self) -> Self::Filter { - Mutex::new(IdentityManager::default()) + fn spawn(&self, min_index: Index) -> Self::Filter { + let mut man = IdentityManager::default(); + man.free.extend(0 .. min_index); + man.epochs.extend(iter::repeat(1).take(min_index as usize)); + Mutex::new(man) } } @@ -317,7 +320,7 @@ pub struct Registry> { impl> Registry { fn new(backend: Backend, factory: &F) -> Self { Registry { - identity: factory.spawn(), + identity: factory.spawn(0), data: RwLock::new(Storage { map: VecMap::new(), _phantom: PhantomData, @@ -325,6 +328,17 @@ impl> Registry { backend, } } + + fn without_backend(factory: &F) -> Self { + Registry { + identity: factory.spawn(1), + data: RwLock::new(Storage { + map: VecMap::new(), + _phantom: PhantomData, + }), + backend: Backend::Empty, + } + } } impl> Registry { @@ -545,7 +559,7 @@ impl Global { pub fn new(name: &str, factory: G) -> Self { Global { instance: Instance::new(name, 1), - surfaces: Registry::new(Backend::Empty, &factory), + surfaces: Registry::without_backend(&factory), hubs: Hubs::new(&factory), } } diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 5d531ffca..ea2506b06 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -6,23 +6,45 @@ use crate::{ backend, device::Device, hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Token}, - id::{AdapterId, DeviceId}, + id::{AdapterId, DeviceId, SurfaceId}, power, }; -use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, RequestAdapterOptions, BIND_BUFFER_ALIGNMENT}; +use wgt::{Backend, BackendBit, DeviceDescriptor, PowerPreference, BIND_BUFFER_ALIGNMENT}; #[cfg(feature = "serde")] use serde_crate::{Deserialize, Serialize}; use hal::{ self, - adapter::{AdapterInfo as HalAdapterInfo, DeviceType as HalDeviceType, PhysicalDevice as _}, + adapter::{ + AdapterInfo as HalAdapterInfo, + DeviceType as HalDeviceType, + PhysicalDevice as _, + }, queue::QueueFamily as _, + window::Surface as _, Instance as _, }; +#[repr(C)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(crate="serde_crate"))] +pub struct RequestAdapterOptions { + pub power_preference: PowerPreference, + pub compatible_surface: SurfaceId, +} + +impl Default for RequestAdapterOptions { + fn default() -> Self { + RequestAdapterOptions { + power_preference: PowerPreference::Default, + compatible_surface: SurfaceId::ERROR, + } + } +} + #[derive(Debug)] pub struct Instance { #[cfg(any( @@ -261,6 +283,13 @@ impl Global { inputs: AdapterInputs>, ) -> Option { let instance = &self.instance; + let mut token = Token::root(); + let (surface_guard, mut token) = self.surfaces.read(&mut token); + let compatible_surface = if desc.compatible_surface != SurfaceId::ERROR { + Some(&surface_guard[desc.compatible_surface]) + } else { + None + }; let mut device_types = Vec::new(); let id_vulkan = inputs.find(Backend::Vulkan); @@ -274,7 +303,15 @@ impl Global { ))] let mut adapters_vk = match instance.vulkan { Some(ref inst) if id_vulkan.is_some() => { - let adapters = inst.enumerate_adapters(); + let mut adapters = inst.enumerate_adapters(); + if let Some(&Surface { vulkan: Some(ref surface), .. }) = compatible_surface { + adapters.retain(|a| + a.queue_families + .iter() + .find(|qf| qf.queue_type().supports_graphics()) + .map_or(false, |qf| surface.supports_queue_family(qf)) + ); + } device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone())); adapters } @@ -282,7 +319,15 @@ impl Global { }; #[cfg(any(target_os = "ios", target_os = "macos"))] let mut adapters_mtl = if id_metal.is_some() { - let adapters = instance.metal.enumerate_adapters(); + let mut adapters = instance.metal.enumerate_adapters(); + if let Some(surface) = compatible_surface { + adapters.retain(|a| + a.queue_families + .iter() + .find(|qf| qf.queue_type().supports_graphics()) + .map_or(false, |qf| surface.metal.supports_queue_family(qf)) + ); + } device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone())); adapters } else { @@ -291,7 +336,15 @@ impl Global { #[cfg(windows)] let mut adapters_dx12 = match instance.dx12 { Some(ref inst) if id_dx12.is_some() => { - let adapters = inst.enumerate_adapters(); + let mut adapters = inst.enumerate_adapters(); + if let Some(&Surface { dx12: Some(ref surface), .. }) = compatible_surface { + adapters.retain(|a| + a.queue_families + .iter() + .find(|qf| qf.queue_type().supports_graphics()) + .map_or(false, |qf| surface.supports_queue_family(qf)) + ); + } device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone())); adapters } @@ -299,7 +352,15 @@ impl Global { }; #[cfg(windows)] let mut adapters_dx11 = if id_dx11.is_some() { - let adapters = instance.dx11.enumerate_adapters(); + let mut adapters = instance.dx11.enumerate_adapters(); + if let Some(surface) = compatible_surface { + adapters.retain(|a| + a.queue_families + .iter() + .find(|qf| qf.queue_type().supports_graphics()) + .map_or(false, |qf| surface.dx11.supports_queue_family(qf)) + ); + } device_types.extend(adapters.iter().map(|ad| ad.info.device_type.clone())); adapters } else { @@ -345,7 +406,6 @@ impl Global { PowerPreference::HighPerformance => discrete.or(other).or(integrated).or(virt), }; - let mut token = Token::root(); let mut selected = preferred_gpu.unwrap_or(0); #[cfg(any( not(any(target_os = "ios", target_os = "macos")), diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index 6edb37ec2..ff3d2120a 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -4,7 +4,7 @@ use crate::GLOBAL; -use wgt::{BackendBit, DeviceDescriptor, Limits, RequestAdapterOptions}; +use wgt::{BackendBit, DeviceDescriptor, Limits}; use core::{gfx_select, hub::Token, id}; use std::{marker::PhantomData, slice}; @@ -153,7 +153,7 @@ pub fn wgpu_enumerate_adapters(mask: BackendBit) -> Vec { /// This function is unsafe as it calls an unsafe extern callback. #[no_mangle] pub unsafe extern "C" fn wgpu_request_adapter_async( - desc: Option<&RequestAdapterOptions>, + desc: Option<&core::instance::RequestAdapterOptions>, mask: BackendBit, callback: RequestAdapterCallback, userdata: *mut std::ffi::c_void, diff --git a/wgpu-remote/src/identity.rs b/wgpu-remote/src/identity.rs index 6a208e392..e2e4c22df 100644 --- a/wgpu-remote/src/identity.rs +++ b/wgpu-remote/src/identity.rs @@ -49,7 +49,7 @@ pub struct IdentityRecyclerFactory { impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_adapter, param: self.param, @@ -59,7 +59,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactor } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_device, param: self.param, @@ -69,7 +69,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_swap_chain, param: self.param, @@ -79,7 +79,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFact } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_pipeline_layout, param: self.param, @@ -89,7 +89,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecycle } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_shader_module, param: self.param, @@ -99,7 +99,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerF } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_bind_group_layout, param: self.param, @@ -109,7 +109,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecycl } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_bind_group, param: self.param, @@ -119,7 +119,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFact } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_command_buffer, param: self.param, @@ -129,7 +129,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecycler } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_render_pipeline, param: self.param, @@ -139,7 +139,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecycle } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_compute_pipeline, param: self.param, @@ -149,7 +149,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecycl } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_buffer, param: self.param, @@ -159,7 +159,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_texture, param: self.param, @@ -169,7 +169,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactor } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_texture_view, param: self.param, @@ -179,7 +179,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFa } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_sampler, param: self.param, @@ -189,7 +189,7 @@ impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactor } impl core::hub::IdentityHandlerFactory for IdentityRecyclerFactory { type Filter = IdentityRecycler; - fn spawn(&self) -> Self::Filter { + fn spawn(&self, _min_index: u32) -> Self::Filter { IdentityRecycler { fun: self.free_surface, param: self.param, diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index d9f013910..17a8cedf8 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -46,7 +46,7 @@ pub extern "C" fn wgpu_server_poll_all_devices(global: &Global, force_wait: bool #[no_mangle] pub unsafe extern "C" fn wgpu_server_instance_request_adapter( global: &Global, - desc: &wgt::RequestAdapterOptions, + desc: &core::instance::RequestAdapterOptions, ids: *const id::AdapterId, id_length: usize, ) -> i8 { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 285e3eb16..3b003854f 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -30,21 +30,6 @@ pub enum PowerPreference { HighPerformance = 2, } -#[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct RequestAdapterOptions { - pub power_preference: PowerPreference, -} - -impl Default for RequestAdapterOptions { - fn default() -> Self { - RequestAdapterOptions { - power_preference: PowerPreference::Default, - } - } -} - bitflags::bitflags! { #[repr(transparent)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]