diff --git a/Cargo.lock b/Cargo.lock index 8a67c3562eb..0ba45d19fc4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5109,6 +5109,7 @@ dependencies = [ "smallvec", "thiserror 2.0.12", "wasm-bindgen", + "wayland-sys", "web-sys", "wgpu-types", "windows 0.58.0", @@ -5188,6 +5189,7 @@ dependencies = [ "bytemuck", "js-sys", "log", + "raw-window-handle 0.6.2", "serde", "serde_json", "thiserror 2.0.12", diff --git a/Cargo.toml b/Cargo.toml index e8af139f6fd..83b2151dddd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -165,7 +165,7 @@ pp-rs = "0.2.1" profiling = { version = "1.0.1", default-features = false } quote = "1.0.38" raw-window-handle = { version = "0.6.2", default-features = false } -rwh_05 = { version = "0.5.2", package = "raw-window-handle" } # temporary compatibility for glutin-winit +rwh_05 = { version = "0.5.2", package = "raw-window-handle" } # temporary compatibility for glutin-winit rayon = "1.3" regex-lite = "0.1" renderdoc-sys = "1" diff --git a/deno_webgpu/lib.rs b/deno_webgpu/lib.rs index 6ce31a29c52..3d37f9a5ec2 100644 --- a/deno_webgpu/lib.rs +++ b/deno_webgpu/lib.rs @@ -162,6 +162,7 @@ impl GPU { gl: wgpu_types::GlBackendOptions::default(), noop: wgpu_types::NoopBackendOptions::default(), }, + display: None, }, ))); state.borrow::() diff --git a/examples/features/src/cube/mod.rs b/examples/features/src/cube/mod.rs index f3e9f768035..cdddc068b8a 100644 --- a/examples/features/src/cube/mod.rs +++ b/examples/features/src/cube/mod.rs @@ -1,6 +1,6 @@ use bytemuck::{Pod, Zeroable}; use std::f32::consts; -use wgpu::util::DeviceExt; +use wgpu::{util::DeviceExt, TextureViewDimension}; #[repr(C)] #[derive(Clone, Copy, Pod, Zeroable)] @@ -149,7 +149,7 @@ impl crate::framework::Example for Example { ty: wgpu::BindingType::Texture { multisampled: false, sample_type: wgpu::TextureSampleType::Uint, - view_dimension: wgpu::TextureViewDimension::D2, + view_dimension: wgpu::TextureViewDimension::D2Array, }, count: None, }, @@ -177,9 +177,20 @@ impl crate::framework::Example for Example { dimension: wgpu::TextureDimension::D2, format: wgpu::TextureFormat::R8Uint, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST, + texture_binding_view_dimension: Some(TextureViewDimension::D2Array), view_formats: &[], }); - let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor { + label: None, + format: None, + dimension: Some(wgpu::TextureViewDimension::D2Array), + usage: None, + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + mip_level_count: None, + base_array_layer: 0, + array_layer_count: Some(1), + }); queue.write_texture( texture.as_image_copy(), &texels, diff --git a/examples/features/src/cube/shader.wgsl b/examples/features/src/cube/shader.wgsl index 8e9fa6c4950..e0d20e5df99 100644 --- a/examples/features/src/cube/shader.wgsl +++ b/examples/features/src/cube/shader.wgsl @@ -20,11 +20,11 @@ fn vs_main( @group(0) @binding(1) -var r_color: texture_2d; +var r_color: texture_2d_array; @fragment fn fs_main(vertex: VertexOutput) -> @location(0) vec4 { - let tex = textureLoad(r_color, vec2(vertex.tex_coord * 256.0), 0); + let tex = textureLoad(r_color, vec2(vertex.tex_coord * 256.0), 0, 0); let v = f32(tex.x) / 255.0; return vec4(1.0 - (v * 5.0), 1.0 - (v * 15.0), 1.0 - (v * 50.0), 1.0); } diff --git a/examples/features/src/framework.rs b/examples/features/src/framework.rs index 7a3017848fa..0cdd6694c0c 100644 --- a/examples/features/src/framework.rs +++ b/examples/features/src/framework.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use wgpu::{Instance, Surface}; +use wgpu::{rwh::HasDisplayHandle, Instance, Surface}; use winit::{ dpi::PhysicalSize, event::{Event, KeyEvent, StartCause, WindowEvent}, @@ -268,7 +268,10 @@ impl ExampleContext { async fn init_async(surface: &mut SurfaceWrapper, window: Arc) -> Self { log::info!("Initializing wgpu..."); - let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default()); + let mut desc = wgpu::InstanceDescriptor::from_env_or_default(); + // XXX: Could also come from EventLoop before Window is created + desc.display = Some(window.display_handle().unwrap().as_raw()); + let instance = wgpu::Instance::new(&desc); surface.pre_adapter(&instance, window); let adapter = get_adapter_with_capabilities_or_from_env( diff --git a/examples/features/src/lib.rs b/examples/features/src/lib.rs index 271241f1ae0..1f23fa2b671 100644 --- a/examples/features/src/lib.rs +++ b/examples/features/src/lib.rs @@ -4,36 +4,35 @@ pub mod framework; pub mod utils; -pub mod big_compute_buffers; -pub mod boids; -pub mod bunnymark; -pub mod conservative_raster; +//pub mod big_compute_buffers; +//pub mod boids; +//pub mod bunnymark; +//pub mod conservative_raster; pub mod cube; -pub mod hello_synchronization; -pub mod hello_triangle; -pub mod hello_windows; -pub mod hello_workgroups; -pub mod mesh_shader; -pub mod mipmap; -pub mod msaa_line; -pub mod multiple_render_targets; -pub mod ray_cube_compute; -pub mod ray_cube_fragment; -pub mod ray_cube_normals; -pub mod ray_scene; -pub mod ray_shadows; -pub mod ray_traced_triangle; -pub mod render_to_texture; -pub mod repeated_compute; -pub mod shadow; -pub mod skybox; -pub mod srgb_blend; -pub mod stencil_triangles; -pub mod storage_texture; -pub mod texture_arrays; -pub mod timestamp_queries; -pub mod uniform_values; -pub mod water; +//pub mod hello_synchronization; +//pub mod hello_triangle; +//pub mod hello_windows; +//pub mod hello_workgroups; +//pub mod mipmap; +//pub mod msaa_line; +//pub mod multiple_render_targets; +//pub mod ray_cube_compute; +//pub mod ray_cube_fragment; +//pub mod ray_cube_normals; +//pub mod ray_scene; +//pub mod ray_shadows; +//pub mod ray_traced_triangle; +//pub mod render_to_texture; +//pub mod repeated_compute; +//pub mod shadow; +//pub mod skybox; +//pub mod srgb_blend; +//pub mod stencil_triangles; +//pub mod storage_texture; +//pub mod texture_arrays; +//pub mod timestamp_queries; +//pub mod uniform_values; +//pub mod water; #[cfg(test)] wgpu_test::gpu_test_main!(); diff --git a/examples/features/src/main.rs b/examples/features/src/main.rs index c9fc31259c9..e9452df9fa5 100644 --- a/examples/features/src/main.rs +++ b/examples/features/src/main.rs @@ -8,6 +8,7 @@ struct ExampleDesc { } const EXAMPLES: &[ExampleDesc] = &[ + /* ExampleDesc { name: "big_compute_buffers", function: wgpu_examples::big_compute_buffers::main, @@ -32,12 +33,14 @@ const EXAMPLES: &[ExampleDesc] = &[ webgl: false, // No conservative raster webgpu: false, // No conservative raster }, + */ ExampleDesc { name: "cube", function: wgpu_examples::cube::main, webgl: true, webgpu: true, }, + /* ExampleDesc { name: "hello_synchronization", function: wgpu_examples::hello_synchronization::main, @@ -188,6 +191,7 @@ const EXAMPLES: &[ExampleDesc] = &[ webgl: false, webgpu: false, }, + */ ]; fn get_example_name() -> Option { diff --git a/tests/src/init.rs b/tests/src/init.rs index d2aac6f14e1..f448dbc1e67 100644 --- a/tests/src/init.rs +++ b/tests/src/init.rs @@ -68,6 +68,7 @@ pub fn initialize_instance(backends: wgpu::Backends, params: &TestParameters) -> // TODO(https://github.com/gfx-rs/wgpu/issues/7119): Enable noop backend? noop: wgpu::NoopBackendOptions::default(), }, + display: None, }) } diff --git a/tests/tests/wgpu-validation/api/instance.rs b/tests/tests/wgpu-validation/api/instance.rs index 4f30e90293f..bfea3b5fdb6 100644 --- a/tests/tests/wgpu-validation/api/instance.rs +++ b/tests/tests/wgpu-validation/api/instance.rs @@ -41,6 +41,7 @@ mod request_adapter_error { flags: wgpu::InstanceFlags::default(), memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(), backend_options: wgpu::BackendOptions::default(), + display: None, } } diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index ed03fce774b..a4731447d79 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -1263,6 +1263,7 @@ impl Device { sample_count: desc.sample_count, dimension: desc.dimension, format: desc.format, + texture_binding_view_dimension: desc.texture_binding_view_dimension, usage: hal_usage, memory_flags: hal::MemoryFlags::empty(), view_formats: hal_view_formats, diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 99f967f033b..5d25b378d62 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -8,6 +8,7 @@ use alloc::{ }; use hashbrown::HashMap; +use raw_window_handle::DisplayHandle; use thiserror::Error; use wgt::error::{ErrorType, WebGpuError}; @@ -131,6 +132,10 @@ impl Instance { flags: self.flags, memory_budget_thresholds: instance_desc.memory_budget_thresholds, backend_options: instance_desc.backend_options.clone(), + display: instance_desc + .display + // XXX: This assigns a bogus lifetime. hal::InstanceDescriptor should also take Raw? + .map(|r| unsafe { DisplayHandle::borrow_raw(r) }), }; use hal::Instance as _; diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index 4ad9a4c0f0b..a3ec02d56b3 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -190,6 +190,7 @@ impl Surface { mip_level_count: 1, format: config.format, dimension: wgt::TextureDimension::D2, + texture_binding_view_dimension: None, usage: config.usage, view_formats: config.view_formats, }; diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 94dc0e07e0c..44f8aeefa59 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -112,6 +112,7 @@ gles = [ "dep:hashbrown", "dep:js-sys", "dep:khronos-egl", + "dep:wayland-sys", "dep:libloading", "dep:log", "dep:ndk-sys", @@ -245,6 +246,9 @@ renderdoc-sys = { workspace = true, optional = true } [target.'cfg(unix)'.dependencies] # Backend: Vulkan libc = { workspace = true, optional = true } +# backend: GLES +# XXX: Using crate to copy from glutin. Better yet, use wayland-client or replace entire backend with glutin entirely. +wayland-sys = { version = "0.31", features = ["client", "dlopen", "egl"], optional = true } ######################### ### Platform: Windows ### diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 22f211c909b..ccb34d3edf0 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -93,21 +93,24 @@ struct Example { impl Example { fn init(window: &winit::window::Window) -> Result> { + // XXX: Could be from the EventLoop as well + let raw_display_handle = window.display_handle()?; + let instance_desc = hal::InstanceDescriptor { name: "example", flags: wgpu_types::InstanceFlags::from_build_config().with_env(), memory_budget_thresholds: wgpu_types::MemoryBudgetThresholds::default(), // Can't rely on having DXC available, so use FXC instead backend_options: wgpu_types::BackendOptions::default(), + display: Some(raw_display_handle), }; let instance = unsafe { A::Instance::init(&instance_desc)? }; let surface = { let raw_window_handle = window.window_handle()?.as_raw(); - let raw_display_handle = window.display_handle()?.as_raw(); unsafe { instance - .create_surface(raw_display_handle, raw_window_handle) + .create_surface(raw_display_handle.as_raw(), raw_window_handle) .unwrap() } }; diff --git a/wgpu-hal/examples/ray-traced-triangle/main.rs b/wgpu-hal/examples/ray-traced-triangle/main.rs index 2947d1a6014..a182bcc11d9 100644 --- a/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -235,6 +235,9 @@ impl Example { log::info!("using index buffer") } + // XXX: Could be from the EventLoop as well + let raw_display_handle = window.display_handle()?; + let instance_desc = hal::InstanceDescriptor { name: "example", flags: wgpu_types::InstanceFlags::default(), @@ -245,15 +248,16 @@ impl Example { }, ..Default::default() }, + // XXX: Coudla + display: Some(raw_display_handle), }; let instance = unsafe { A::Instance::init(&instance_desc)? }; let surface = { let raw_window_handle = window.window_handle()?.as_raw(); - let raw_display_handle = window.display_handle()?.as_raw(); unsafe { instance - .create_surface(raw_display_handle, raw_window_handle) + .create_surface(raw_display_handle.as_raw(), raw_window_handle) .unwrap() } }; diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 865f35013c7..80588f65792 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -410,6 +410,7 @@ impl super::Adapter { unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_MAX_ANISOTROPY_EXT) } as u32; downlevel_flags.set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, max_aniso >= 16); } + downlevel_flags.set( wgt::DownlevelFlags::BUFFER_BINDINGS_NOT_16_BYTE_ALIGNED, !(cfg!(any(webgl, Emscripten)) || is_angle), diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index ff4d77a3357..c4ccf59b27c 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -1,5 +1,6 @@ -use alloc::{rc::Rc, string::String, sync::Arc, vec::Vec}; +use alloc::{string::String, sync::Arc, vec::Vec}; use core::{ffi, mem::ManuallyDrop, ptr, time::Duration}; +use raw_window_handle::RawDisplayHandle; use std::sync::LazyLock; use glow::HasContext; @@ -14,45 +15,19 @@ const EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR: i32 = 0x0001; const EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT: i32 = 0x30BF; const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8; const EGL_PLATFORM_X11_KHR: u32 = 0x31D5; -const EGL_PLATFORM_ANGLE_ANGLE: u32 = 0x3202; -const EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE: u32 = 0x348F; -const EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED: u32 = 0x3451; +// const EGL_PLATFORM_ANGLE_ANGLE: u32 = 0x3202; +// const EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE: u32 = 0x348F; +// const EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED: u32 = 0x3451; const EGL_PLATFORM_SURFACELESS_MESA: u32 = 0x31DD; const EGL_GL_COLORSPACE_KHR: u32 = 0x309D; const EGL_GL_COLORSPACE_SRGB_KHR: u32 = 0x3089; -type XOpenDisplayFun = - unsafe extern "system" fn(display_name: *const ffi::c_char) -> *mut ffi::c_void; - -type XCloseDisplayFun = unsafe extern "system" fn(display: *mut ffi::c_void) -> ffi::c_int; - -type WlDisplayConnectFun = - unsafe extern "system" fn(display_name: *const ffi::c_char) -> *mut ffi::c_void; - -type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const ffi::c_void); - #[cfg(not(Emscripten))] type EglInstance = khronos_egl::DynamicInstance; #[cfg(Emscripten)] type EglInstance = khronos_egl::Instance; -type WlEglWindowCreateFun = unsafe extern "system" fn( - surface: *const ffi::c_void, - width: ffi::c_int, - height: ffi::c_int, -) -> *mut ffi::c_void; - -type WlEglWindowResizeFun = unsafe extern "system" fn( - window: *const ffi::c_void, - width: ffi::c_int, - height: ffi::c_int, - dx: ffi::c_int, - dy: ffi::c_int, -); - -type WlEglWindowDestroyFun = unsafe extern "system" fn(window: *const ffi::c_void); - type EglLabel = *const ffi::c_void; #[allow(clippy::upper_case_acronyms)] @@ -101,97 +76,6 @@ unsafe extern "system" fn egl_debug_proc( log::log!(log_severity, "EGL '{command}' code 0x{error:x}: {message}",); } -/// A simple wrapper around an X11 or Wayland display handle. -/// Since the logic in this file doesn't actually need to directly -/// persist a wayland connection handle, the only load-bearing -/// enum variant is the X11 variant -#[derive(Debug)] -enum DisplayRef { - X11(ptr::NonNull), - Wayland, -} - -impl DisplayRef { - /// Convenience for getting the underlying pointer - fn as_ptr(&self) -> *mut ffi::c_void { - match *self { - Self::X11(ptr) => ptr.as_ptr(), - Self::Wayland => unreachable!(), - } - } -} - -/// DisplayOwner ties the lifetime of the system display handle -/// to that of the loaded library. -/// It implements Drop to ensure that the display handle is closed -/// prior to unloading the library so that we don't leak the -/// associated file descriptors -#[derive(Debug)] -struct DisplayOwner { - library: libloading::Library, - display: DisplayRef, -} - -impl Drop for DisplayOwner { - fn drop(&mut self) { - match self.display { - DisplayRef::X11(ptr) => unsafe { - let func: libloading::Symbol = - self.library.get(c"XCloseDisplay".to_bytes()).unwrap(); - func(ptr.as_ptr()); - }, - DisplayRef::Wayland => {} - } - } -} - -fn open_x_display() -> Option { - log::debug!("Loading X11 library to get the current display"); - unsafe { - let library = find_library(&["libX11.so.6", "libX11.so"])?; - let func: libloading::Symbol = - library.get(c"XOpenDisplay".to_bytes()).unwrap(); - let result = func(ptr::null()); - ptr::NonNull::new(result).map(|ptr| DisplayOwner { - display: DisplayRef::X11(ptr), - library, - }) - } -} - -unsafe fn find_library(paths: &[&str]) -> Option { - for path in paths { - match unsafe { libloading::Library::new(path) } { - Ok(lib) => return Some(lib), - _ => continue, - }; - } - None -} - -fn test_wayland_display() -> Option { - /* We try to connect and disconnect here to simply ensure there - * is an active wayland display available. - */ - log::debug!("Loading Wayland library to get the current display"); - let library = unsafe { - let client_library = find_library(&["libwayland-client.so.0", "libwayland-client.so"])?; - let wl_display_connect: libloading::Symbol = client_library - .get(c"wl_display_connect".to_bytes()) - .unwrap(); - let wl_display_disconnect: libloading::Symbol = client_library - .get(c"wl_display_disconnect".to_bytes()) - .unwrap(); - let display = ptr::NonNull::new(wl_display_connect(ptr::null()))?; - wl_display_disconnect(display.as_ptr()); - find_library(&["libwayland-egl.so.1", "libwayland-egl.so"])? - }; - Some(DisplayOwner { - library, - display: DisplayRef::Wayland, - }) -} - #[derive(Clone, Copy, Debug)] enum SrgbFrameBufferKind { /// No support for SRGB surface @@ -453,10 +337,11 @@ struct Inner { version: (i32, i32), supports_native_window: bool, config: khronos_egl::Config, - #[cfg_attr(Emscripten, allow(dead_code))] - wl_display: Option<*mut ffi::c_void>, - #[cfg_attr(Emscripten, allow(dead_code))] - force_gles_minor_version: wgt::Gles3MinorVersion, + // XXX: Store RawDisplayHandle for validation in create_surface()? + // #[cfg_attr(Emscripten, allow(dead_code))] + // wl_display: Option<*mut ffi::c_void>, + // #[cfg_attr(Emscripten, allow(dead_code))] + // force_gles_minor_version: wgt::Gles3MinorVersion, /// Method by which the framebuffer should support srgb srgb_kind: SrgbFrameBufferKind, } @@ -751,15 +636,19 @@ impl Inner { version, supports_native_window, config, - wl_display: None, + // wl_display: None, + // raw_display, srgb_kind, - force_gles_minor_version, + // force_gles_minor_version, }) } } impl Drop for Inner { fn drop(&mut self) { + // ERROR: Since EglContext is erroneously Clone, these handles could be copied and + // accidentally used elsewhere outside of Inner, despite us assuming ownership and + // destroying the handles here. if let Err(e) = self .egl .instance @@ -784,7 +673,6 @@ enum WindowKind { #[derive(Clone, Debug)] struct WindowSystemInterface { - display_owner: Option>, kind: WindowKind, } @@ -869,74 +757,82 @@ impl crate::Instance for Instance { client_ext_str.split_whitespace().collect::>() ); - let wayland_library = if client_ext_str.contains("EGL_EXT_platform_wayland") { - test_wayland_display() - } else { - None - }; - let x11_display_library = if client_ext_str.contains("EGL_EXT_platform_x11") { - open_x_display() - } else { - None - }; - let angle_x11_display_library = if client_ext_str.contains("EGL_ANGLE_platform_angle") { - open_x_display() - } else { - None - }; - #[cfg(not(Emscripten))] let egl1_5 = egl.upcast::(); #[cfg(Emscripten)] let egl1_5: Option<&Arc> = Some(&egl); - let (display, display_owner, wsi_kind) = - if let (Some(library), Some(egl)) = (wayland_library, egl1_5) { + // TODO: Copypaste glutin... Or use glutin... + let (display, wsi_kind) = match (desc.display.map(|d| d.as_raw()), egl1_5) { + #[cfg(unix)] + (Some(RawDisplayHandle::Wayland(wayland_display_handle)), Some(egl)) => { log::info!("Using Wayland platform"); let display_attributes = [khronos_egl::ATTRIB_NONE]; let display = unsafe { egl.get_platform_display( EGL_PLATFORM_WAYLAND_KHR, - khronos_egl::DEFAULT_DISPLAY, + wayland_display_handle.display.as_ptr(), &display_attributes, ) } .unwrap(); - (display, Some(Rc::new(library)), WindowKind::Wayland) - } else if let (Some(display_owner), Some(egl)) = (x11_display_library, egl1_5) { + (display, WindowKind::Wayland) + } + // RawDisplayHandle::UiKit(ui_kit_display_handle) => todo!(), + // RawDisplayHandle::AppKit(app_kit_display_handle) => todo!(), + // RawDisplayHandle::Orbital(orbital_display_handle) => todo!(), + // RawDisplayHandle::Ohos(ohos_display_handle) => todo!(), + #[cfg(unix)] + (Some(RawDisplayHandle::Xlib(xlib_display_handle)), Some(egl)) => { log::info!("Using X11 platform"); let display_attributes = [khronos_egl::ATTRIB_NONE]; let display = unsafe { egl.get_platform_display( EGL_PLATFORM_X11_KHR, - display_owner.display.as_ptr(), - &display_attributes, - ) - } - .unwrap(); - (display, Some(Rc::new(display_owner)), WindowKind::X11) - } else if let (Some(display_owner), Some(egl)) = (angle_x11_display_library, egl1_5) { - log::info!("Using Angle platform with X11"); - let display_attributes = [ - EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE as khronos_egl::Attrib, - EGL_PLATFORM_X11_KHR as khronos_egl::Attrib, - EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED as khronos_egl::Attrib, - usize::from(desc.flags.contains(wgt::InstanceFlags::VALIDATION)), - khronos_egl::ATTRIB_NONE, - ]; - let display = unsafe { - egl.get_platform_display( - EGL_PLATFORM_ANGLE_ANGLE, - display_owner.display.as_ptr(), + xlib_display_handle + .display + .map_or(khronos_egl::DEFAULT_DISPLAY, ptr::NonNull::as_ptr), &display_attributes, ) } .unwrap(); - (display, Some(Rc::new(display_owner)), WindowKind::AngleX11) - } else if client_ext_str.contains("EGL_MESA_platform_surfaceless") { - log::warn!("No windowing system present. Using surfaceless platform"); - #[allow(clippy::unnecessary_literal_unwrap)] // This is only a literal on Emscripten + (display, WindowKind::X11) + } + // AngleX11 => { + // log::info!("Using Angle platform with X11"); + // let display_attributes = [ + // EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE as khronos_egl::Attrib, + // EGL_PLATFORM_X11_KHR as khronos_egl::Attrib, + // EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED as khronos_egl::Attrib, + // usize::from(desc.flags.contains(wgt::InstanceFlags::VALIDATION)), + // khronos_egl::ATTRIB_NONE, + // ]; + // let display = unsafe { + // egl.get_platform_display( + // EGL_PLATFORM_ANGLE_ANGLE, + // display_owner.display.as_ptr(), + // &display_attributes, + // ) + // } + // .unwrap(); + // (display, WindowKind::AngleX11) + // } + #[cfg(unix)] + (Some(RawDisplayHandle::Xcb(_xcb_display_handle)), Some(_egl)) => todo!("xcb"), + // RawDisplayHandle::Drm(drm_display_handle) => todo!(), + // RawDisplayHandle::Gbm(gbm_display_handle) => todo!(), + // RawDisplayHandle::Windows(windows_display_handle) => todo!(), + // RawDisplayHandle::Web(web_display_handle) => todo!(), + // RawDisplayHandle::Android(android_display_handle) => todo!(), + // RawDisplayHandle::Haiku(haiku_display_handle) => todo!(), + x if client_ext_str.contains("EGL_MESA_platform_surfaceless") => { + log::warn!( + "No (or unknown) windowing system ({x:?}) present. Using surfaceless platform" + ); + #[allow(clippy::unnecessary_literal_unwrap)] + // This is only a literal on Emscripten + // XXX: This extension is also supported on EGL 1.4 with EGL_EXT_platform_base: https://registry.khronos.org/EGL/extensions/MESA/EGL_MESA_platform_surfaceless.txt let egl = egl1_5.expect("Failed to get EGL 1.5 for surfaceless"); let display = unsafe { egl.get_platform_display( @@ -947,12 +843,16 @@ impl crate::Instance for Instance { } .unwrap(); - (display, None, WindowKind::Unknown) - } else { - log::warn!("EGL_MESA_platform_surfaceless not available. Using default platform"); + (display, WindowKind::Unknown) + } + x => { + log::warn!( + "No (or unknown) windowing system {x:?} and EGL_MESA_platform_surfaceless not available. Using default platform" + ); let display = unsafe { egl.get_display(khronos_egl::DEFAULT_DISPLAY) }.unwrap(); - (display, None, WindowKind::Unknown) - }; + (display, WindowKind::Unknown) + } + }; if desc.flags.contains(wgt::InstanceFlags::VALIDATION) && client_ext_str.contains("EGL_KHR_debug") @@ -984,10 +884,7 @@ impl crate::Instance for Instance { )?; Ok(Instance { - wsi: WindowSystemInterface { - display_owner, - kind: wsi_kind, - }, + wsi: WindowSystemInterface { kind: wsi_kind }, flags: desc.flags, options: desc.backend_options.gl.clone(), inner: Mutex::new(inner), @@ -997,13 +894,12 @@ impl crate::Instance for Instance { #[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))] unsafe fn create_surface( &self, - display_handle: raw_window_handle::RawDisplayHandle, + display_handle: RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, ) -> Result { use raw_window_handle::RawWindowHandle as Rwh; - #[cfg_attr(any(target_os = "android", Emscripten), allow(unused_mut))] - let mut inner = self.inner.lock(); + let inner = self.inner.lock(); match (window_handle, display_handle) { (Rwh::Xlib(_), _) => {} @@ -1023,6 +919,7 @@ impl crate::Instance for Instance { ) .unwrap(); + // TODO: Now, all we need is to get rid of this weird/unnecessary thing. let ret = unsafe { ndk_sys::ANativeWindow_setBuffersGeometry( handle @@ -1041,51 +938,7 @@ impl crate::Instance for Instance { ))); } } - #[cfg(not(Emscripten))] - (Rwh::Wayland(_), raw_window_handle::RawDisplayHandle::Wayland(display_handle)) => { - if inner - .wl_display - .map(|ptr| ptr != display_handle.display.as_ptr()) - .unwrap_or(true) - { - /* Wayland displays are not sharable between surfaces so if the - * surface we receive from this handle is from a different - * display, we must re-initialize the context. - * - * See gfx-rs/gfx#3545 - */ - log::warn!("Re-initializing Gles context due to Wayland window"); - - use core::ops::DerefMut; - let display_attributes = [khronos_egl::ATTRIB_NONE]; - - let display = unsafe { - inner - .egl - .instance - .upcast::() - .unwrap() - .get_platform_display( - EGL_PLATFORM_WAYLAND_KHR, - display_handle.display.as_ptr(), - &display_attributes, - ) - } - .unwrap(); - - let new_inner = Inner::create( - self.flags, - Arc::clone(&inner.egl.instance), - display, - inner.force_gles_minor_version, - )?; - - let old_inner = core::mem::replace(inner.deref_mut(), new_inner); - inner.wl_display = Some(display_handle.display.as_ptr()); - - drop(old_inner); - } - } + (Rwh::Wayland(_), _) => {} #[cfg(Emscripten)] (Rwh::Web(_), _) => {} other => { @@ -1153,6 +1006,7 @@ impl crate::Instance for Instance { super::Adapter::expose( AdapterContext { glow: Mutex::new(gl), + // ERROR: Copying owned reference handles here, be careful to not drop them! egl: Some(inner.egl.clone()), }, self.options.clone(), @@ -1362,13 +1216,16 @@ impl crate::Surface for Surface { handle.a_native_window.as_ptr() } (WindowKind::Unknown, Rwh::OhosNdk(handle)) => handle.native_window.as_ptr(), + #[cfg(unix)] (WindowKind::Wayland, Rwh::Wayland(handle)) => { - let library = &self.wsi.display_owner.as_ref().unwrap().library; - let wl_egl_window_create: libloading::Symbol = - unsafe { library.get(c"wl_egl_window_create".to_bytes()) }.unwrap(); - let window = - unsafe { wl_egl_window_create(handle.surface.as_ptr(), 640, 480) } - .cast(); + let window = wayland_sys::ffi_dispatch!( + wayland_sys::egl::wayland_egl_handle(), + wl_egl_window_create, + handle.surface.as_ptr().cast(), + config.extent.width as i32, + config.extent.height as i32, + ); + let window = window.cast(); // XXX: Make code type-safe wl_window = Some(window); window } @@ -1474,19 +1331,17 @@ impl crate::Surface for Surface { } }; + // XXX: Skip if the window was created with a sane size? if let Some(window) = wl_window { - let library = &self.wsi.display_owner.as_ref().unwrap().library; - let wl_egl_window_resize: libloading::Symbol = - unsafe { library.get(c"wl_egl_window_resize".to_bytes()) }.unwrap(); - unsafe { - wl_egl_window_resize( - window, - config.extent.width as i32, - config.extent.height as i32, - 0, - 0, - ) - }; + wayland_sys::ffi_dispatch!( + wayland_sys::egl::wayland_egl_handle(), + wl_egl_window_resize, + window.cast(), // XXX: Make type-safe + config.extent.width as i32, + config.extent.height as i32, + 0, + 0, + ); } let format_desc = device.shared.describe_texture_format(config.format); @@ -1542,15 +1397,11 @@ impl crate::Surface for Surface { .destroy_surface(self.egl.display, surface) .unwrap(); if let Some(window) = wl_window { - let library = &self - .wsi - .display_owner - .as_ref() - .expect("unsupported window") - .library; - let wl_egl_window_destroy: libloading::Symbol = - unsafe { library.get(c"wl_egl_window_destroy".to_bytes()) }.unwrap(); - unsafe { wl_egl_window_destroy(window) }; + wayland_sys::ffi_dispatch!( + wayland_sys::egl::wayland_egl_handle(), + wl_egl_window_destroy, + window.cast(), // XXX: Make type-safe + ); } } } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 94416086d2e..05427120c1d 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -449,20 +449,24 @@ impl Texture { /// Returns the `target`, whether the image is 3d and whether the image is a cubemap. fn get_info_from_desc(desc: &TextureDescriptor) -> u32 { - match desc.dimension { - // WebGL (1 and 2) as well as some GLES versions do not have 1D textures, so we are - // doing `TEXTURE_2D` instead - wgt::TextureDimension::D1 => glow::TEXTURE_2D, - wgt::TextureDimension::D2 => { - // HACK: detect a cube map; forces cube compatible textures to be cube textures - match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) { - (false, 1) => glow::TEXTURE_2D, - (false, _) => glow::TEXTURE_2D_ARRAY, - (true, 6) => glow::TEXTURE_CUBE_MAP, - (true, _) => glow::TEXTURE_CUBE_MAP_ARRAY, + if let Some(dim) = desc.texture_binding_view_dimension { + conv::_map_view_dimension(dim) + } else { + match desc.dimension { + // WebGL (1 and 2) as well as some GLES versions do not have 1D textures, so we are + // doing `TEXTURE_2D` instead + wgt::TextureDimension::D1 => glow::TEXTURE_2D, + wgt::TextureDimension::D2 => { + // HACK: detect a cube map; forces cube compatible textures to be cube textures + match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) { + (false, 1) => glow::TEXTURE_2D, + (false, _) => glow::TEXTURE_2D_ARRAY, + (true, 6) => glow::TEXTURE_CUBE_MAP, + (true, _) => glow::TEXTURE_CUBE_MAP_ARRAY, + } } + wgt::TextureDimension::D3 => glow::TEXTURE_3D, } - wgt::TextureDimension::D3 => glow::TEXTURE_3D, } } @@ -510,6 +514,7 @@ impl Texture { "`D2` textures with ", "`depth_or_array_layers > 6 && depth_or_array_layers % 6 == 0` ", "are assumed to have view dimension `CubeArray`\n", + "Pass texture_binding_view_dimension to TextureDescriptor to avoid.", ), got, view_dimension, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index e6b4e0b0f89..078089310be 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -280,6 +280,7 @@ mod dynamic; #[cfg(feature = "validation_canary")] mod validation_canary; +use raw_window_handle::DisplayHandle; #[cfg(feature = "validation_canary")] pub use validation_canary::{ValidationCanary, VALIDATION_CANARY}; @@ -1764,6 +1765,7 @@ pub struct InstanceDescriptor<'a> { pub flags: wgt::InstanceFlags, pub memory_budget_thresholds: wgt::MemoryBudgetThresholds, pub backend_options: wgt::BackendOptions, + pub display: Option>, } #[derive(Clone, Debug)] @@ -1898,6 +1900,7 @@ pub struct TextureDescriptor<'a> { pub format: wgt::TextureFormat, pub usage: wgt::TextureUses, pub memory_flags: MemoryFlags, + pub texture_binding_view_dimension: Option, /// Allows views of this texture to have a different format /// than the texture does. pub view_formats: Vec, diff --git a/wgpu-hal/src/noop/mod.rs b/wgpu-hal/src/noop/mod.rs index 55965a7e2fb..02d7881d645 100644 --- a/wgpu-hal/src/noop/mod.rs +++ b/wgpu-hal/src/noop/mod.rs @@ -98,6 +98,7 @@ impl crate::Instance for Context { name: _, flags: _, memory_budget_thresholds: _, + display: _, } = *desc; if enable { Ok(Context) diff --git a/wgpu-types/Cargo.toml b/wgpu-types/Cargo.toml index 921f319592a..a2cd84cbbcc 100644 --- a/wgpu-types/Cargo.toml +++ b/wgpu-types/Cargo.toml @@ -57,6 +57,7 @@ serde = { workspace = true, default-features = false, features = [ "alloc", "derive", ], optional = true } +raw-window-handle.workspace = true [target.'cfg(target_arch = "wasm32")'.dependencies] js-sys = { workspace = true, optional = true, default-features = false } diff --git a/wgpu-types/src/instance.rs b/wgpu-types/src/instance.rs index 79e3f7b2526..bd86c60e51e 100644 --- a/wgpu-types/src/instance.rs +++ b/wgpu-types/src/instance.rs @@ -37,6 +37,12 @@ pub struct InstanceDescriptor { pub memory_budget_thresholds: MemoryBudgetThresholds, /// Options the control the behavior of specific backends. pub backend_options: BackendOptions, + /// System platform or compositor connection to connect this `Instance` to. + /// + /// - On GLES, this is required when intending to present on the platform. + /// - On Vulkan, this could be used to skip extensions. + // Cannot have the safe borrow variant here... + pub display: Option, } impl InstanceDescriptor { @@ -61,6 +67,7 @@ impl InstanceDescriptor { flags, memory_budget_thresholds: MemoryBudgetThresholds::default(), backend_options, + display: None, } } } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 6252e5c6778..4ad8618a381 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -6152,6 +6152,7 @@ pub struct TextureDescriptor { pub sample_count: u32, /// Dimensions of the texture. pub dimension: TextureDimension, + pub texture_binding_view_dimension: Option, /// Format of the texture. pub format: TextureFormat, /// Allowed usages of the texture. If used in other ways, the operation will panic. @@ -6180,6 +6181,7 @@ impl TextureDescriptor { format: self.format, usage: self.usage, view_formats: self.view_formats.clone(), + texture_binding_view_dimension: self.texture_binding_view_dimension, } } @@ -6201,6 +6203,7 @@ impl TextureDescriptor { dimension: self.dimension, format: self.format, usage: self.usage, + texture_binding_view_dimension: self.texture_binding_view_dimension, view_formats: v_fun(self.view_formats.clone()), } } diff --git a/wgpu/src/api/surface.rs b/wgpu/src/api/surface.rs index 113f46639e6..d5a9df0696e 100644 --- a/wgpu/src/api/surface.rs +++ b/wgpu/src/api/surface.rs @@ -134,6 +134,7 @@ impl Surface<'_> { mip_level_count: 1, sample_count: 1, dimension: TextureDimension::D2, + texture_binding_view_dimension: None, view_formats: &[], };