diff --git a/Cargo.lock b/Cargo.lock index 96dc128f83..6c43e46000 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -687,6 +687,18 @@ dependencies = [ "weezl", ] +[[package]] +name = "glow" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945be163fdb893227410c8b44c2412dade922585b262d1daa6a7e96135217d4c" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gpu-alloc" version = "0.4.7" @@ -846,6 +858,16 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "khronos-egl" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c2352bd1d0bceb871cb9d40f24360c8133c11d7486b68b5381c1dd1a32015e3" +dependencies = [ + "libc", + "libloading 0.7.0", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1586,6 +1608,15 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +[[package]] +name = "slotmap" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585cd5dffe4e9e06f6dfdf66708b70aca3f781bed561f4f667b2d9c0d4559e36" +dependencies = [ + "version_check", +] + [[package]] name = "smallvec" version = "1.6.1" @@ -1957,9 +1988,11 @@ dependencies = [ "env_logger", "foreign-types", "fxhash", + "glow", "gpu-alloc", "gpu-descriptor", "inplace_it", + "khronos-egl", "libloading 0.7.0", "log", "metal", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 34b62ca5f4..2aeea651c3 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -15,6 +15,7 @@ license = "MIT OR Apache-2.0" default = [] metal = ["naga/msl-out", "block", "foreign-types"] vulkan = ["naga/spv-out", "ash", "gpu-alloc", "gpu-descriptor", "libloading", "inplace_it", "renderdoc-sys"] +gles = ["naga/glsl-out", "glow", "egl", "libloading"] [dependencies] bitflags = "1.0" @@ -26,7 +27,6 @@ wgt = { package = "wgpu-types", path = "../wgpu-types" } # backends common arrayvec = "0.5" fxhash = "0.2.1" -libloading = { version = "0.7", optional = true } log = "0.4" # backend: Metal block = { version = "0.1", optional = true } @@ -37,6 +37,12 @@ gpu-alloc = { version = "0.4", optional = true } gpu-descriptor = { version = "0.1", optional = true } inplace_it = { version ="0.3.3", optional = true } renderdoc-sys = { version = "0.7.1", optional = true } +# backend: Gles +glow = { version = "0.10", optional = true } + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true } +libloading = { version = "0.7", optional = true } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["libloaderapi", "windef", "winuser"] } diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index ec75abf179..97dab2f20a 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -681,7 +681,9 @@ impl Example { type Api = hal::api::Metal; #[cfg(all(feature = "vulkan", not(feature = "metal")))] type Api = hal::api::Vulkan; -#[cfg(all(not(feature = "vulkan"), not(feature = "metal")))] +#[cfg(all(feature = "gles", not(feature = "metal"), not(feature = "vulkan")))] +type Api = hal::api::Gles; +#[cfg(not(any(feature = "metal", feature = "vulkan", feature = "gles")))] type Api = hal::api::Empty; fn main() { diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs new file mode 100644 index 0000000000..f021f5e065 --- /dev/null +++ b/wgpu-hal/src/gles/egl.rs @@ -0,0 +1,556 @@ +use glow::HasContext; +use parking_lot::Mutex; + +use std::{os::raw, ptr, sync::Arc}; + +const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8; +const EGL_PLATFORM_X11_KHR: u32 = 0x31D5; + +type XOpenDisplayFun = + unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void; + +type WlDisplayConnectFun = + unsafe extern "system" fn(display_name: *const raw::c_char) -> *mut raw::c_void; + +type WlDisplayDisconnectFun = unsafe extern "system" fn(display: *const raw::c_void); + +#[cfg(not(any(target_os = "android", target_os = "macos")))] +type WlEglWindowCreateFun = unsafe extern "system" fn( + surface: *const raw::c_void, + width: raw::c_int, + height: raw::c_int, +) -> *mut raw::c_void; + +type WlEglWindowResizeFun = unsafe extern "system" fn( + window: *const raw::c_void, + width: raw::c_int, + height: raw::c_int, + dx: raw::c_int, + dy: raw::c_int, +); + +type WlEglWindowDestroyFun = unsafe extern "system" fn(window: *const raw::c_void); + +#[cfg(target_os = "android")] +extern "C" { + pub fn ANativeWindow_setBuffersGeometry( + window: *mut raw::c_void, + width: i32, + height: i32, + format: i32, + ) -> i32; +} + +fn open_x_display() -> Option<(ptr::NonNull, libloading::Library)> { + log::info!("Loading X11 library to get the current display"); + unsafe { + let library = libloading::Library::new("libX11.so").ok()?; + let func: libloading::Symbol = library.get(b"XOpenDisplay").unwrap(); + let result = func(ptr::null()); + ptr::NonNull::new(result).map(|ptr| (ptr, library)) + } +} + +fn test_wayland_display() -> Option { + /* We try to connect and disconnect here to simply ensure there + * is an active wayland display available. + */ + log::info!("Loading Wayland library to get the current display"); + let library = unsafe { + let client_library = libloading::Library::new("libwayland-client.so").ok()?; + let wl_display_connect: libloading::Symbol = + client_library.get(b"wl_display_connect").unwrap(); + let wl_display_disconnect: libloading::Symbol = + client_library.get(b"wl_display_disconnect").unwrap(); + let display = ptr::NonNull::new(wl_display_connect(ptr::null()))?; + wl_display_disconnect(display.as_ptr()); + libloading::Library::new("libwayland-egl.so").ok()? + }; + Some(library) +} + +/// Choose GLES framebuffer configuration. +fn choose_config( + egl: &egl::DynamicInstance, + display: egl::Display, +) -> Result<(egl::Config, bool), crate::InstanceError> { + //TODO: EGL_SLOW_CONFIG + let tiers = [ + ( + "off-screen", + &[egl::RENDERABLE_TYPE, egl::OPENGL_ES2_BIT][..], + ), + ("presentation", &[egl::SURFACE_TYPE, egl::WINDOW_BIT]), + #[cfg(not(target_os = "android"))] + ("native-render", &[egl::NATIVE_RENDERABLE, egl::TRUE as _]), + ]; + + let mut attributes = Vec::with_capacity(7); + for tier_max in (0..tiers.len()).rev() { + let name = tiers[tier_max].0; + log::info!("Trying {}", name); + + attributes.clear(); + for &(_, tier_attr) in tiers[..=tier_max].iter() { + attributes.extend_from_slice(tier_attr); + } + attributes.push(egl::NONE); + + match egl.choose_first_config(display, &attributes) { + Ok(Some(config)) => { + return Ok((config, tier_max >= 1)); + } + Ok(None) => { + log::warn!("No config found!"); + } + Err(e) => { + log::error!("error in choose_first_config: {:?}", e); + } + } + } + + Err(crate::InstanceError) +} + +#[derive(Debug)] +struct Inner { + egl: Arc>, + version: (i32, i32), + supports_native_window: bool, + display: egl::Display, + config: egl::Config, + context: egl::Context, + /// Dummy pbuffer (1x1). + /// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`. + pbuffer: Option, + wl_display: Option<*mut raw::c_void>, +} + +impl Inner { + fn create( + flags: crate::InstanceFlag, + egl: Arc>, + display: egl::Display, + wsi_library: Option<&libloading::Library>, + ) -> Result { + let version = egl.initialize(display).map_err(|_| crate::InstanceError)?; + let vendor = egl.query_string(Some(display), egl::VENDOR).unwrap(); + let display_extensions = egl + .query_string(Some(display), egl::EXTENSIONS) + .unwrap() + .to_string_lossy(); + log::info!( + "Display vendor {:?}, version {:?}, extensions: {:?}", + vendor, + version, + display_extensions + ); + + if log::max_level() >= log::LevelFilter::Trace { + log::trace!("Configurations:"); + let config_count = egl.get_config_count(display).unwrap(); + let mut configurations = Vec::with_capacity(config_count); + egl.get_configs(display, &mut configurations).unwrap(); + for &config in configurations.iter() { + log::trace!("\tCONFORMANT=0x{:X}, RENDERABLE=0x{:X}, NATIVE_RENDERABLE=0x{:X}, SURFACE_TYPE=0x{:X}", + egl.get_config_attrib(display, config, egl::CONFORMANT).unwrap(), + egl.get_config_attrib(display, config, egl::RENDERABLE_TYPE).unwrap(), + egl.get_config_attrib(display, config, egl::NATIVE_RENDERABLE).unwrap(), + egl.get_config_attrib(display, config, egl::SURFACE_TYPE).unwrap(), + ); + } + } + + let (config, supports_native_window) = choose_config(&egl, display)?; + egl.bind_api(egl::OPENGL_ES_API).unwrap(); + + //TODO: make it so `Device` == EGL Context + let mut context_attributes = vec![ + egl::CONTEXT_CLIENT_VERSION, + 3, // Request GLES 3.0 or higher + ]; + if flags.contains(crate::InstanceFlag::VALIDATION) + && wsi_library.is_none() + && !cfg!(target_os = "android") + { + //TODO: figure out why this is needed + context_attributes.push(egl::CONTEXT_OPENGL_DEBUG); + context_attributes.push(egl::TRUE as _); + } + context_attributes.push(egl::NONE); + let context = match egl.create_context(display, config, None, &context_attributes) { + Ok(context) => context, + Err(e) => { + log::warn!("unable to create GLES 3.x context: {:?}", e); + return Err(crate::InstanceError); + } + }; + + // Testing if context can be binded without surface + // and creating dummy pbuffer surface if not. + let pbuffer = if version < (1, 5) + || !display_extensions.contains("EGL_KHR_surfaceless_context") + { + let attributes = [egl::WIDTH, 1, egl::HEIGHT, 1, egl::NONE]; + egl.create_pbuffer_surface(display, config, &attributes) + .map(Some) + .map_err(|e| { + log::warn!("Error in create_pbuffer_surface: {:?}", e); + crate::InstanceError + })? + } else { + log::info!("EGL_KHR_surfaceless_context is present. No need to create a dummy pbuffer"); + None + }; + + Ok(Self { + egl, + display, + version, + supports_native_window, + config, + context, + pbuffer, + wl_display: None, + }) + } +} + +impl Drop for Inner { + fn drop(&mut self) { + if let Err(e) = self.egl.destroy_context(self.display, self.context) { + log::warn!("Error in destroy_context: {:?}", e); + } + if let Err(e) = self.egl.terminate(self.display) { + log::warn!("Error in terminate: {:?}", e); + } + } +} + +pub struct Instance { + wsi_library: Option, + flags: crate::InstanceFlag, + inner: Mutex, +} + +unsafe impl Send for Instance {} +unsafe impl Sync for Instance {} + +impl crate::Instance for Instance { + unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { + let egl = match unsafe { egl::DynamicInstance::::load_required() } { + Ok(egl) => Arc::new(egl), + Err(e) => { + log::warn!("Unable to open libEGL.so: {:?}", e); + return Err(crate::InstanceError); + } + }; + + let client_extensions = egl.query_string(None, egl::EXTENSIONS); + + let client_ext_str = match client_extensions { + Ok(ext) => ext.to_string_lossy().into_owned(), + Err(_) => String::new(), + }; + log::info!("Client extensions: {:?}", client_ext_str); + + let mut wsi_library = None; + + 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 display = if let (Some(library), Some(egl)) = + (wayland_library, egl.upcast::()) + { + log::info!("Using Wayland platform"); + let display_attributes = [egl::ATTRIB_NONE]; + wsi_library = Some(library); + egl.get_platform_display( + EGL_PLATFORM_WAYLAND_KHR, + egl::DEFAULT_DISPLAY, + &display_attributes, + ) + .unwrap() + } else if let (Some((display, library)), Some(egl)) = + (x11_display_library, egl.upcast::()) + { + log::info!("Using X11 platform"); + let display_attributes = [egl::ATTRIB_NONE]; + wsi_library = Some(library); + egl.get_platform_display(EGL_PLATFORM_X11_KHR, display.as_ptr(), &display_attributes) + .unwrap() + } else { + log::info!("Using default platform"); + egl.get_display(egl::DEFAULT_DISPLAY).unwrap() + }; + + let inner = Inner::create(desc.flags, egl, display, wsi_library.as_ref())?; + + Ok(Instance { + wsi_library, + flags: desc.flags, + inner: Mutex::new(inner), + }) + } + + #[cfg_attr(target_os = "macos", allow(unused, unused_mut, unreachable_code))] + unsafe fn create_surface( + &self, + has_handle: &impl raw_window_handle::HasRawWindowHandle, + ) -> Result { + use raw_window_handle::RawWindowHandle as Rwh; + + let mut inner = self.inner.lock(); + let mut wl_window = None; + #[cfg(not(any(target_os = "android", target_os = "macos")))] + let (mut temp_xlib_handle, mut temp_xcb_handle); + + let native_window_ptr = match has_handle.raw_window_handle() { + #[cfg(not(any(target_os = "android", target_os = "macos")))] + Rwh::Xlib(handle) => { + temp_xlib_handle = handle.window; + &mut temp_xlib_handle as *mut _ as *mut std::ffi::c_void + } + #[cfg(not(any(target_os = "android", target_os = "macos")))] + Rwh::Xcb(handle) => { + temp_xcb_handle = handle.window; + &mut temp_xcb_handle as *mut _ as *mut std::ffi::c_void + } + #[cfg(target_os = "android")] + Rwh::Android(handle) => handle.a_native_window as *mut _ as *mut std::ffi::c_void, + #[cfg(not(any(target_os = "android", target_os = "macos")))] + Rwh::Wayland(handle) => { + /* 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 + */ + if inner + .wl_display + .map(|ptr| ptr != handle.display) + .unwrap_or(true) + { + use std::ops::DerefMut; + let display_attributes = [egl::ATTRIB_NONE]; + let display = inner + .egl + .upcast::() + .unwrap() + .get_platform_display( + EGL_PLATFORM_WAYLAND_KHR, + handle.display, + &display_attributes, + ) + .unwrap(); + + let new_inner = + Inner::create(inner.egl.clone(), display, self.wsi_library.as_ref()) + .map_err(|_| w::InitError::UnsupportedWindowHandle)?; + + let old_inner = std::mem::replace(inner.deref_mut(), new_inner); + inner.wl_display = Some(handle.display); + drop(old_inner); + } + + let wl_egl_window_create: libloading::Symbol = self + .wsi_library + .as_ref() + .expect("unsupported window") + .get(b"wl_egl_window_create") + .unwrap(); + let result = wl_egl_window_create(handle.surface, 640, 480) as *mut _ + as *mut std::ffi::c_void; + wl_window = Some(result); + result + } + other => { + log::error!("Unsupported window: {:?}", other); + return Err(crate::InstanceError); + } + }; + + let mut attributes = vec![ + egl::RENDER_BUFFER as usize, + if cfg!(target_os = "android") { + egl::BACK_BUFFER as usize + } else { + egl::SINGLE_BUFFER as usize + }, + ]; + if inner.version >= (1, 5) { + // Always enable sRGB in EGL 1.5 + attributes.push(egl::GL_COLORSPACE as usize); + attributes.push(egl::GL_COLORSPACE_SRGB as usize); + } + attributes.push(egl::ATTRIB_NONE); + + let raw = if let Some(egl) = inner.egl.upcast::() { + egl.create_platform_window_surface( + inner.display, + inner.config, + native_window_ptr, + &attributes, + ) + .map_err(|e| { + log::warn!("Error in create_platform_window_surface: {:?}", e); + crate::InstanceError + }) + } else { + let attributes_i32: Vec = attributes.iter().map(|a| (*a as i32).into()).collect(); + inner + .egl + .create_window_surface( + inner.display, + inner.config, + native_window_ptr, + Some(&attributes_i32), + ) + .map_err(|e| { + log::warn!("Error in create_platform_window_surface: {:?}", e); + crate::InstanceError + }) + }?; + + #[cfg(target_os = "android")] + { + let format = inner + .egl + .get_config_attrib(inner.display, inner.config, egl::NATIVE_VISUAL_ID) + .unwrap(); + + let ret = ANativeWindow_setBuffersGeometry(native_window_ptr, 0, 0, format); + + if ret != 0 { + log::error!("Error returned from ANativeWindow_setBuffersGeometry"); + return Err(w::InitError::UnsupportedWindowHandle); + } + } + + Ok(Surface { + egl: Arc::clone(&inner.egl), + raw, + display: inner.display, + context: inner.context, + presentable: inner.supports_native_window, + pbuffer: inner.pbuffer, + wl_window, + swapchain: None, + }) + } + unsafe fn destroy_surface(&self, surface: Surface) {} + + unsafe fn enumerate_adapters(&self) -> Vec> { + Vec::new() + } +} + +#[derive(Debug)] +pub struct Swapchain { + framebuffer: glow::Framebuffer, + renderbuffer: glow::Renderbuffer, + /// Extent because the window lies + extent: wgt::Extent3d, + format: super::TextureFormat, + sample_type: wgt::TextureSampleType, +} + +#[derive(Debug)] +pub struct Surface { + egl: Arc>, + raw: egl::Surface, + display: egl::Display, + context: egl::Context, + pbuffer: Option, + presentable: bool, + wl_window: Option<*mut raw::c_void>, + swapchain: Option, +} + +unsafe impl Send for Surface {} +unsafe impl Sync for Surface {} + +impl crate::Surface for Surface { + unsafe fn configure( + &mut self, + device: &super::Context, + config: &crate::SurfaceConfiguration, + ) -> Result<(), crate::SurfaceError> { + self.unconfigure(device); + + if let Some(window) = self.wl_window { + let library = libloading::Library::new("libwayland-egl.so").unwrap(); + let wl_egl_window_resize: libloading::Symbol = + library.get(b"wl_egl_window_resize").unwrap(); + wl_egl_window_resize( + window, + config.extent.width as i32, + config.extent.height as i32, + 0, + 0, + ); + } + + //let desc = conv::describe_format(config.format).unwrap(); + let desc: super::FormatDescription = unimplemented!(); + + let gl: glow::Context = unimplemented!(); //&device.share.context; + let renderbuffer = gl.create_renderbuffer().unwrap(); + gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)); + gl.renderbuffer_storage( + glow::RENDERBUFFER, + desc.tex_internal, + config.extent.width as _, + config.extent.height as _, + ); + let framebuffer = gl.create_framebuffer().unwrap(); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(framebuffer)); + gl.framebuffer_renderbuffer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + glow::RENDERBUFFER, + Some(renderbuffer), + ); + gl.bind_renderbuffer(glow::RENDERBUFFER, None); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); + + self.swapchain = Some(Swapchain { + renderbuffer, + framebuffer, + extent: config.extent, + format: desc.tex_internal, + sample_type: wgt::TextureSampleType::Float { filterable: false }, + }); + + Ok(()) + } + + unsafe fn unconfigure(&mut self, device: &super::Context) { + /* + let gl = &device.share.context; + if let Some(sc) = self.swapchain.take() { + gl.delete_renderbuffer(sc.renderbuffer); + gl.delete_framebuffer(sc.framebuffer); + }*/ + } + + unsafe fn acquire_texture( + &mut self, + timeout_ms: u32, + ) -> Result>, crate::SurfaceError> { + let sc = self.swapchain.as_ref().unwrap(); + //let sc_image = + // native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel); + Ok(None) + } + unsafe fn discard_texture(&mut self, texture: super::Resource) {} +} diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs new file mode 100644 index 0000000000..e4b76e2c57 --- /dev/null +++ b/wgpu-hal/src/gles/mod.rs @@ -0,0 +1,390 @@ +#![allow(unused_variables)] + +#[cfg(not(target_arch = "wasm32"))] +mod egl; + +#[cfg(not(target_arch = "wasm32"))] +use self::egl::{Instance, Surface}; + +use std::ops::Range; + +#[derive(Clone)] +pub struct Api; +pub struct Context; +pub struct Encoder; +#[derive(Debug)] +pub struct Resource; + +type DeviceResult = Result; + +impl crate::Api for Api { + type Instance = Instance; + type Surface = Surface; + type Adapter = Context; + type Device = Context; + + type Queue = Context; + type CommandEncoder = Encoder; + type CommandBuffer = Resource; + + type Buffer = Resource; + type Texture = Resource; + type SurfaceTexture = Resource; + type TextureView = Resource; + type Sampler = Resource; + type QuerySet = Resource; + type Fence = Resource; + + type BindGroupLayout = Resource; + type BindGroup = Resource; + type PipelineLayout = Resource; + type ShaderModule = Resource; + type RenderPipeline = Resource; + type ComputePipeline = Resource; +} + +type TextureFormat = u32; + +#[derive(Debug, Clone, Copy)] +enum VertexAttribKind { + Float, // glVertexAttribPointer + Integer, // glVertexAttribIPointer + Double, // glVertexAttribLPointer +} + +struct FormatDescription { + tex_internal: u32, + tex_external: u32, + data_type: u32, + num_components: u8, + va_kind: VertexAttribKind, +} + +impl FormatDescription { + fn new( + tex_internal: u32, + tex_external: u32, + data_type: u32, + num_components: u8, + va_kind: VertexAttribKind, + ) -> Self { + FormatDescription { + tex_internal, + tex_external, + data_type, + num_components, + va_kind, + } + } +} + +impl crate::Adapter for Context { + unsafe fn open(&self, features: wgt::Features) -> DeviceResult> { + Err(crate::DeviceError::Lost) + } + unsafe fn texture_format_capabilities( + &self, + format: wgt::TextureFormat, + ) -> crate::TextureFormatCapability { + crate::TextureFormatCapability::empty() + } + unsafe fn surface_capabilities(&self, surface: &Surface) -> Option { + None + } +} + +impl crate::Queue for Context { + unsafe fn submit( + &mut self, + command_buffers: &[&Resource], + signal_fence: Option<(&mut Resource, crate::FenceValue)>, + ) -> DeviceResult<()> { + Ok(()) + } + unsafe fn present( + &mut self, + surface: &mut Surface, + texture: Resource, + ) -> Result<(), crate::SurfaceError> { + Ok(()) + } +} + +impl crate::Device for Context { + unsafe fn exit(self) {} + unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_buffer(&self, buffer: Resource) {} + unsafe fn map_buffer( + &self, + buffer: &Resource, + range: crate::MemoryRange, + ) -> DeviceResult { + Err(crate::DeviceError::Lost) + } + unsafe fn unmap_buffer(&self, buffer: &Resource) -> DeviceResult<()> { + Ok(()) + } + unsafe fn flush_mapped_ranges(&self, buffer: &Resource, ranges: I) {} + unsafe fn invalidate_mapped_ranges(&self, buffer: &Resource, ranges: I) {} + + unsafe fn create_texture(&self, desc: &crate::TextureDescriptor) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_texture(&self, texture: Resource) {} + unsafe fn create_texture_view( + &self, + texture: &Resource, + desc: &crate::TextureViewDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_texture_view(&self, view: Resource) {} + unsafe fn create_sampler(&self, desc: &crate::SamplerDescriptor) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_sampler(&self, sampler: Resource) {} + + unsafe fn create_command_encoder( + &self, + desc: &crate::CommandEncoderDescriptor, + ) -> DeviceResult { + Ok(Encoder) + } + unsafe fn destroy_command_encoder(&self, encoder: Encoder) {} + + unsafe fn create_bind_group_layout( + &self, + desc: &crate::BindGroupLayoutDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {} + unsafe fn create_pipeline_layout( + &self, + desc: &crate::PipelineLayoutDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {} + unsafe fn create_bind_group( + &self, + desc: &crate::BindGroupDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_bind_group(&self, group: Resource) {} + + unsafe fn create_shader_module( + &self, + desc: &crate::ShaderModuleDescriptor, + shader: crate::NagaShader, + ) -> Result { + Ok(Resource) + } + unsafe fn destroy_shader_module(&self, module: Resource) {} + unsafe fn create_render_pipeline( + &self, + desc: &crate::RenderPipelineDescriptor, + ) -> Result { + Ok(Resource) + } + unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {} + unsafe fn create_compute_pipeline( + &self, + desc: &crate::ComputePipelineDescriptor, + ) -> Result { + Ok(Resource) + } + unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} + + unsafe fn create_query_set( + &self, + desc: &wgt::QuerySetDescriptor, + ) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_query_set(&self, set: Resource) {} + unsafe fn create_fence(&self) -> DeviceResult { + Ok(Resource) + } + unsafe fn destroy_fence(&self, fence: Resource) {} + unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult { + Ok(0) + } + unsafe fn wait( + &self, + fence: &Resource, + value: crate::FenceValue, + timeout_ms: u32, + ) -> DeviceResult { + Ok(true) + } + + unsafe fn start_capture(&self) -> bool { + false + } + unsafe fn stop_capture(&self) {} +} + +impl crate::CommandEncoder for Encoder { + unsafe fn begin_encoding(&mut self, label: crate::Label) -> DeviceResult<()> { + Ok(()) + } + unsafe fn discard_encoding(&mut self) {} + unsafe fn end_encoding(&mut self) -> DeviceResult { + Ok(Resource) + } + unsafe fn reset_all(&mut self, command_buffers: I) {} + + unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) + where + T: Iterator>, + { + } + + unsafe fn transition_textures<'a, T>(&mut self, barriers: T) + where + T: Iterator>, + { + } + + unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {} + + unsafe fn copy_buffer_to_buffer(&mut self, src: &Resource, dst: &Resource, regions: T) {} + + unsafe fn copy_texture_to_texture( + &mut self, + src: &Resource, + src_usage: crate::TextureUse, + dst: &Resource, + regions: T, + ) { + } + + unsafe fn copy_buffer_to_texture(&mut self, src: &Resource, dst: &Resource, regions: T) {} + + unsafe fn copy_texture_to_buffer( + &mut self, + src: &Resource, + src_usage: crate::TextureUse, + dst: &Resource, + regions: T, + ) { + } + + unsafe fn begin_query(&mut self, set: &Resource, index: u32) {} + unsafe fn end_query(&mut self, set: &Resource, index: u32) {} + unsafe fn write_timestamp(&mut self, set: &Resource, index: u32) {} + unsafe fn reset_queries(&mut self, set: &Resource, range: Range) {} + unsafe fn copy_query_results( + &mut self, + set: &Resource, + range: Range, + buffer: &Resource, + offset: wgt::BufferAddress, + ) { + } + + // render + + unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) {} + unsafe fn end_render_pass(&mut self) {} + + unsafe fn set_bind_group( + &mut self, + layout: &Resource, + index: u32, + group: &Resource, + dynamic_offsets: &[wgt::DynamicOffset], + ) { + } + unsafe fn set_push_constants( + &mut self, + layout: &Resource, + stages: wgt::ShaderStage, + offset: u32, + data: &[u32], + ) { + } + + unsafe fn insert_debug_marker(&mut self, label: &str) {} + unsafe fn begin_debug_marker(&mut self, group_label: &str) {} + unsafe fn end_debug_marker(&mut self) {} + + unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} + + unsafe fn set_index_buffer<'a>( + &mut self, + binding: crate::BufferBinding<'a, Api>, + format: wgt::IndexFormat, + ) { + } + unsafe fn set_vertex_buffer<'a>(&mut self, index: u32, binding: crate::BufferBinding<'a, Api>) { + } + unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth_range: Range) {} + unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) {} + unsafe fn set_stencil_reference(&mut self, value: u32) {} + unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {} + + unsafe fn draw( + &mut self, + start_vertex: u32, + vertex_count: u32, + start_instance: u32, + instance_count: u32, + ) { + } + unsafe fn draw_indexed( + &mut self, + start_index: u32, + index_count: u32, + base_vertex: i32, + start_instance: u32, + instance_count: u32, + ) { + } + unsafe fn draw_indirect( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + draw_count: u32, + ) { + } + unsafe fn draw_indexed_indirect( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + draw_count: u32, + ) { + } + unsafe fn draw_indirect_count( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + count_buffer: &Resource, + count_offset: wgt::BufferAddress, + max_count: u32, + ) { + } + unsafe fn draw_indexed_indirect_count( + &mut self, + buffer: &Resource, + offset: wgt::BufferAddress, + count_buffer: &Resource, + count_offset: wgt::BufferAddress, + max_count: u32, + ) { + } + + // compute + + unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {} + unsafe fn end_compute_pass(&mut self) {} + + unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} + + unsafe fn dispatch(&mut self, count: [u32; 3]) {} + unsafe fn dispatch_indirect(&mut self, buffer: &Resource, offset: wgt::BufferAddress) {} +} diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 6fc38acff7..45db780473 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -48,11 +48,14 @@ mod empty; #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] mod metal; #[cfg(feature = "vulkan")] -mod vulkan; +mod vulkan;#[cfg(feature = "gles")] +mod gles; pub mod util; pub mod api { pub use super::empty::Api as Empty; + #[cfg(feature = "gles")] + pub use super::gles::Api as Gles; #[cfg(feature = "metal")] pub use super::metal::Api as Metal; #[cfg(feature = "vulkan")]