From 41bc9d0625dcef1d861ba50ab0fbb991f1828872 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 18 Jun 2021 00:38:27 -0400 Subject: [PATCH 01/33] hal/gl: start the backend, port the Instance --- Cargo.lock | 33 ++ wgpu-hal/Cargo.toml | 8 +- wgpu-hal/examples/halmark/main.rs | 4 +- wgpu-hal/src/gles/egl.rs | 556 ++++++++++++++++++++++++++++++ wgpu-hal/src/gles/mod.rs | 390 +++++++++++++++++++++ wgpu-hal/src/lib.rs | 5 +- 6 files changed, 993 insertions(+), 3 deletions(-) create mode 100644 wgpu-hal/src/gles/egl.rs create mode 100644 wgpu-hal/src/gles/mod.rs 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")] From d88bc440e67e1ab881ab63f3c2a6caaf9dd32cda Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 19 Jun 2021 01:14:59 -0400 Subject: [PATCH 02/33] hal/gles: describe format, adapter info --- wgpu-hal/src/gles/adapter.rs | 116 ++++++++++++++++++ wgpu-hal/src/gles/conv.rs | 222 ++++++++++++++++++++++++++++++++++ wgpu-hal/src/gles/egl.rs | 63 +++++++--- wgpu-hal/src/gles/mod.rs | 46 +++---- wgpu-hal/src/lib.rs | 2 +- wgpu-hal/src/metal/adapter.rs | 2 +- 6 files changed, 413 insertions(+), 38 deletions(-) create mode 100644 wgpu-hal/src/gles/adapter.rs create mode 100644 wgpu-hal/src/gles/conv.rs diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs new file mode 100644 index 0000000000..fc7b595eb5 --- /dev/null +++ b/wgpu-hal/src/gles/adapter.rs @@ -0,0 +1,116 @@ +use glow::HasContext; +use std::sync::Arc; + +// https://webgl2fundamentals.org/webgl/lessons/webgl-data-textures.html + +impl super::Adapter { + fn make_info(vendor_orig: String, renderer_orig: String) -> wgt::AdapterInfo { + let vendor = vendor_orig.to_lowercase(); + let renderer = renderer_orig.to_lowercase(); + + // opengl has no way to discern device_type, so we can try to infer it from the renderer string + let strings_that_imply_integrated = [ + " xpress", // space here is on purpose so we don't match express + "radeon hd 4200", + "radeon hd 4250", + "radeon hd 4290", + "radeon hd 4270", + "radeon hd 4225", + "radeon hd 3100", + "radeon hd 3200", + "radeon hd 3000", + "radeon hd 3300", + "radeon(tm) r4 graphics", + "radeon(tm) r5 graphics", + "radeon(tm) r6 graphics", + "radeon(tm) r7 graphics", + "radeon r7 graphics", + "nforce", // all nvidia nforce are integrated + "tegra", // all nvidia tegra are integrated + "shield", // all nvidia shield are integrated + "igp", + "mali", + "intel", + ]; + let strings_that_imply_cpu = ["mesa offscreen", "swiftshader", "lavapipe"]; + + //TODO: handle Intel Iris XE as discreet + let inferred_device_type = if vendor.contains("qualcomm") + || vendor.contains("intel") + || strings_that_imply_integrated + .iter() + .any(|&s| renderer.contains(s)) + { + wgt::DeviceType::IntegratedGpu + } else if strings_that_imply_cpu.iter().any(|&s| renderer.contains(s)) { + wgt::DeviceType::Cpu + } else { + wgt::DeviceType::DiscreteGpu + }; + + // source: Sascha Willems at Vulkan + let vendor_id = if vendor.contains("amd") { + 0x1002 + } else if vendor.contains("imgtec") { + 0x1010 + } else if vendor.contains("nvidia") { + 0x10DE + } else if vendor.contains("arm") { + 0x13B5 + } else if vendor.contains("qualcomm") { + 0x5143 + } else if vendor.contains("intel") { + 0x8086 + } else { + 0 + }; + + wgt::AdapterInfo { + name: renderer_orig, + vendor: vendor_id, + device: 0, + device_type: inferred_device_type, + backend: wgt::Backend::Gl, + } + } + + pub(super) unsafe fn expose(gl: glow::Context) -> crate::ExposedAdapter { + let vendor = gl.get_parameter_string(glow::VENDOR); + let renderer = gl.get_parameter_string(glow::RENDERER); + + let min_uniform_buffer_offset_alignment = + gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT); + let min_storage_buffer_offset_alignment = if super::is_webgl() { + 256 + } else { + gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) + }; + + crate::ExposedAdapter { + adapter: super::Adapter { + shared: Arc::new(super::AdapterShared { + context: gl, + private_caps: super::PrivateCapabilities {}, + }), + }, + info: Self::make_info(vendor, renderer), + features: wgt::Features::empty(), //TODO + capabilities: crate::Capabilities { + limits: wgt::Limits::default(), //TODO + downlevel: wgt::DownlevelCapabilities::default(), //TODO + alignments: crate::Alignments { + buffer_copy_offset: wgt::BufferSize::new(4).unwrap(), + buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(), + uniform_buffer_offset: wgt::BufferSize::new( + min_storage_buffer_offset_alignment as u64, + ) + .unwrap(), + storage_buffer_offset: wgt::BufferSize::new( + min_uniform_buffer_offset_alignment as u64, + ) + .unwrap(), + }, + }, + } + } +} diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs new file mode 100644 index 0000000000..2bcc76e62b --- /dev/null +++ b/wgpu-hal/src/gles/conv.rs @@ -0,0 +1,222 @@ +impl super::PrivateCapabilities { + pub(super) fn describe_texture_format( + &self, + format: wgt::TextureFormat, + ) -> super::FormatDescription { + use super::VertexAttribKind as Vak; + use wgt::TextureFormat as Tf; + + let (tex_internal, tex_external, data_type, num_components, va_kind) = match format { + Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE, 1, Vak::Float), + Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE, 1, Vak::Float), + Tf::R8Uint => ( + glow::R8UI, + glow::RED_INTEGER, + glow::UNSIGNED_BYTE, + 1, + Vak::Integer, + ), + Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE, 1, Vak::Integer), + Tf::R16Uint => ( + glow::R16UI, + glow::RED_INTEGER, + glow::UNSIGNED_SHORT, + 1, + Vak::Integer, + ), + Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT, 1, Vak::Integer), + Tf::R16Float => (glow::R16F, glow::RED, glow::UNSIGNED_SHORT, 1, Vak::Float), + Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE, 2, Vak::Float), + Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE, 2, Vak::Float), + Tf::Rg8Uint => ( + glow::RG8UI, + glow::RG_INTEGER, + glow::UNSIGNED_BYTE, + 2, + Vak::Integer, + ), + Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE, 2, Vak::Integer), + Tf::R32Uint => ( + glow::R32UI, + glow::RED_INTEGER, + glow::UNSIGNED_INT, + 1, + Vak::Integer, + ), + Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT, 1, Vak::Integer), + Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT, 1, Vak::Float), + Tf::Rg16Uint => ( + glow::RG16UI, + glow::RG_INTEGER, + glow::UNSIGNED_SHORT, + 2, + Vak::Integer, + ), + Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT, 2, Vak::Integer), + Tf::Rg16Float => (glow::RG16F, glow::RG, glow::UNSIGNED_SHORT, 2, Vak::Float), + Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE, 4, Vak::Float), + Tf::Rgba8UnormSrgb => ( + glow::SRGB8_ALPHA8, + glow::RGBA, + glow::UNSIGNED_BYTE, + 4, + Vak::Float, + ), + Tf::Bgra8UnormSrgb => ( + glow::SRGB8_ALPHA8, + glow::RGBA, + glow::UNSIGNED_BYTE, + 4, + Vak::Float, + ), //TODO? + Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE, 4, Vak::Float), + Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE, 4, Vak::Float), + Tf::Rgba8Uint => ( + glow::RGBA8UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_BYTE, + 4, + Vak::Integer, + ), + Tf::Rgba8Sint => ( + glow::RGBA8I, + glow::RGBA_INTEGER, + glow::BYTE, + 4, + Vak::Integer, + ), + Tf::Rgb10a2Unorm => ( + glow::RGB10_A2, + glow::RGBA, + glow::UNSIGNED_INT_2_10_10_10_REV, + 1, + Vak::Integer, + ), + Tf::Rg11b10Float => ( + glow::R11F_G11F_B10F, + glow::RGB, + glow::UNSIGNED_INT_10F_11F_11F_REV, + 1, + Vak::Integer, + ), + Tf::Rg32Uint => ( + glow::RG32UI, + glow::RG_INTEGER, + glow::UNSIGNED_INT, + 2, + Vak::Integer, + ), + Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT, 2, Vak::Integer), + Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT, 2, Vak::Float), + Tf::Rgba16Uint => ( + glow::RGBA16UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_SHORT, + 4, + Vak::Integer, + ), + Tf::Rgba16Sint => ( + glow::RGBA16I, + glow::RGBA_INTEGER, + glow::SHORT, + 4, + Vak::Integer, + ), + Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::UNSIGNED_SHORT, 4, Vak::Float), + Tf::Rgba32Uint => ( + glow::RGBA32UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_INT, + 4, + Vak::Integer, + ), + Tf::Rgba32Sint => ( + glow::RGBA32I, + glow::RGBA_INTEGER, + glow::INT, + 4, + Vak::Integer, + ), + Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT, 4, Vak::Float), + Tf::Depth32Float => ( + glow::DEPTH_COMPONENT32F, + glow::DEPTH_COMPONENT, + glow::FLOAT, + 1, + Vak::Float, + ), + Tf::Depth24Plus => ( + glow::DEPTH_COMPONENT24, + glow::DEPTH_COMPONENT, + glow::UNSIGNED_NORMALIZED, + 2, + Vak::Float, + ), + Tf::Depth24PlusStencil8 => ( + glow::DEPTH24_STENCIL8, + glow::DEPTH_COMPONENT, + glow::UNSIGNED_INT, + 2, + Vak::Float, + ), + Tf::Bc1RgbaUnorm + | Tf::Bc1RgbaUnormSrgb + | Tf::Bc2RgbaUnorm + | Tf::Bc2RgbaUnormSrgb + | Tf::Bc3RgbaUnorm + | Tf::Bc3RgbaUnormSrgb + | Tf::Bc4RUnorm + | Tf::Bc4RSnorm + | Tf::Bc5RgUnorm + | Tf::Bc5RgSnorm + | Tf::Bc6hRgbSfloat + | Tf::Bc6hRgbUfloat + | Tf::Bc7RgbaUnorm + | Tf::Bc7RgbaUnormSrgb + | Tf::Etc2RgbUnorm + | Tf::Etc2RgbUnormSrgb + | Tf::Etc2RgbA1Unorm + | Tf::Etc2RgbA1UnormSrgb + | Tf::EacRUnorm + | Tf::EacRSnorm + | Tf::EtcRgUnorm + | Tf::EtcRgSnorm + | Tf::Astc4x4RgbaUnorm + | Tf::Astc4x4RgbaUnormSrgb + | Tf::Astc5x4RgbaUnorm + | Tf::Astc5x4RgbaUnormSrgb + | Tf::Astc5x5RgbaUnorm + | Tf::Astc5x5RgbaUnormSrgb + | Tf::Astc6x5RgbaUnorm + | Tf::Astc6x5RgbaUnormSrgb + | Tf::Astc6x6RgbaUnorm + | Tf::Astc6x6RgbaUnormSrgb + | Tf::Astc8x5RgbaUnorm + | Tf::Astc8x5RgbaUnormSrgb + | Tf::Astc8x6RgbaUnorm + | Tf::Astc8x6RgbaUnormSrgb + | Tf::Astc10x5RgbaUnorm + | Tf::Astc10x5RgbaUnormSrgb + | Tf::Astc10x6RgbaUnorm + | Tf::Astc10x6RgbaUnormSrgb + | Tf::Astc8x8RgbaUnorm + | Tf::Astc8x8RgbaUnormSrgb + | Tf::Astc10x8RgbaUnorm + | Tf::Astc10x8RgbaUnormSrgb + | Tf::Astc10x10RgbaUnorm + | Tf::Astc10x10RgbaUnormSrgb + | Tf::Astc12x10RgbaUnorm + | Tf::Astc12x10RgbaUnormSrgb + | Tf::Astc12x12RgbaUnorm + | Tf::Astc12x12RgbaUnormSrgb => unimplemented!(), + }; + + super::FormatDescription { + tex_internal, + tex_external, + data_type, + num_components, + va_kind, + } + } +} diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index f021f5e065..03987d2adb 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -238,7 +238,7 @@ 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() } { + let egl = match egl::DynamicInstance::::load_required() { Ok(egl) => Arc::new(egl), Err(e) => { log::warn!("Unable to open libEGL.so: {:?}", e); @@ -447,10 +447,43 @@ impl crate::Instance for Instance { swapchain: None, }) } - unsafe fn destroy_surface(&self, surface: Surface) {} + unsafe fn destroy_surface(&self, surface: Surface) { + let inner = self.inner.lock(); + inner + .egl + .destroy_surface(inner.display, surface.raw) + .unwrap(); + if let Some(wl_window) = surface.wl_window { + let wl_egl_window_destroy: libloading::Symbol = self + .wsi_library + .as_ref() + .expect("unsupported window") + .get(b"wl_egl_window_destroy") + .unwrap(); + wl_egl_window_destroy(wl_window) + } + } unsafe fn enumerate_adapters(&self) -> Vec> { - Vec::new() + let inner = self.inner.lock(); + inner + .egl + .make_current( + inner.display, + inner.pbuffer, + inner.pbuffer, + Some(inner.context), + ) + .unwrap(); + + let context = glow::Context::from_loader_function(|name| { + inner + .egl + .get_proc_address(name) + .map_or(ptr::null(), |p| p as *const _) + }); + + vec![super::Adapter::expose(context)] } } @@ -482,7 +515,7 @@ unsafe impl Sync for Surface {} impl crate::Surface for Surface { unsafe fn configure( &mut self, - device: &super::Context, + device: &super::Device, config: &crate::SurfaceConfiguration, ) -> Result<(), crate::SurfaceError> { self.unconfigure(device); @@ -500,15 +533,16 @@ impl crate::Surface for Surface { ); } - //let desc = conv::describe_format(config.format).unwrap(); - let desc: super::FormatDescription = unimplemented!(); - - let gl: glow::Context = unimplemented!(); //&device.share.context; + let format_desc = device + .shared + .private_caps + .describe_texture_format(config.format); + let gl = &device.shared.context; let renderbuffer = gl.create_renderbuffer().unwrap(); gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)); gl.renderbuffer_storage( glow::RENDERBUFFER, - desc.tex_internal, + format_desc.tex_internal, config.extent.width as _, config.extent.height as _, ); @@ -527,20 +561,19 @@ impl crate::Surface for Surface { renderbuffer, framebuffer, extent: config.extent, - format: desc.tex_internal, + format: 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; + unsafe fn unconfigure(&mut self, device: &super::Device) { + let gl = &device.shared.context; if let Some(sc) = self.swapchain.take() { gl.delete_renderbuffer(sc.renderbuffer); gl.delete_framebuffer(sc.framebuffer); - }*/ + } } unsafe fn acquire_texture( @@ -552,5 +585,5 @@ impl crate::Surface for Surface { // native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel); Ok(None) } - unsafe fn discard_texture(&mut self, texture: super::Resource) {} + 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 index e4b76e2c57..19599654b4 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -3,10 +3,13 @@ #[cfg(not(target_arch = "wasm32"))] mod egl; +mod adapter; +mod conv; + #[cfg(not(target_arch = "wasm32"))] use self::egl::{Instance, Surface}; -use std::ops::Range; +use std::{ops::Range, sync::Arc}; #[derive(Clone)] pub struct Api; @@ -20,8 +23,8 @@ type DeviceResult = Result; impl crate::Api for Api { type Instance = Instance; type Surface = Surface; - type Adapter = Context; - type Device = Context; + type Adapter = Adapter; + type Device = Device; type Queue = Context; type CommandEncoder = Encoder; @@ -43,6 +46,10 @@ impl crate::Api for Api { type ComputePipeline = Resource; } +const fn is_webgl() -> bool { + cfg!(target_arch = "wasm32") +} + type TextureFormat = u32; #[derive(Debug, Clone, Copy)] @@ -60,25 +67,22 @@ struct FormatDescription { 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, - } - } +struct PrivateCapabilities {} + +struct AdapterShared { + context: glow::Context, + private_caps: PrivateCapabilities, +} + +pub struct Adapter { + shared: Arc, +} + +pub struct Device { + shared: Arc, } -impl crate::Adapter for Context { +impl crate::Adapter for Adapter { unsafe fn open(&self, features: wgt::Features) -> DeviceResult> { Err(crate::DeviceError::Lost) } @@ -110,7 +114,7 @@ impl crate::Queue for Context { } } -impl crate::Device for Context { +impl crate::Device for Device { unsafe fn exit(self) {} unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { Ok(Resource) diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 45db780473..cf67f8320e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -624,8 +624,8 @@ pub struct Alignments { /// The alignment of the row pitch of the texture data stored in a buffer that is /// used in a GPU copy operation. pub buffer_copy_pitch: wgt::BufferSize, - pub storage_buffer_offset: wgt::BufferSize, pub uniform_buffer_offset: wgt::BufferSize, + pub storage_buffer_offset: wgt::BufferSize, } #[derive(Clone, Debug)] diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 936a8423ed..ec3a6eb073 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -905,8 +905,8 @@ impl super::PrivateCapabilities { alignments: crate::Alignments { buffer_copy_offset: buffer_alignment, buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(), - storage_buffer_offset: buffer_alignment, uniform_buffer_offset: buffer_alignment, + storage_buffer_offset: buffer_alignment, }, downlevel, } From 804b17bb29d8f05516a4851499b5fbf8cab1b690 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 20 Jun 2021 02:28:47 -0400 Subject: [PATCH 03/33] hal/gl: version parsing --- wgpu-hal/src/gles/adapter.rs | 162 +++++++++++++++++++++++++++++++++-- wgpu-hal/src/gles/conv.rs | 2 +- wgpu-hal/src/gles/egl.rs | 3 +- wgpu-hal/src/gles/mod.rs | 28 ++++-- 4 files changed, 181 insertions(+), 14 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index fc7b595eb5..6ab1ad6fca 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -4,6 +4,89 @@ use std::sync::Arc; // https://webgl2fundamentals.org/webgl/lessons/webgl-data-textures.html impl super::Adapter { + /// According to the OpenGL specification, the version information is + /// expected to follow the following syntax: + /// + /// ~~~bnf + /// ::= + /// ::= + /// ::= + /// ::= + /// ::= "." ["." ] + /// ::= [" " ] + /// ~~~ + /// + /// Note that this function is intentionally lenient in regards to parsing, + /// and will try to recover at least the first two version numbers without + /// resulting in an `Err`. + /// # Notes + /// `WebGL 2` version returned as `OpenGL ES 3.0` + fn parse_version(mut src: &str) -> Result<(u8, u8), crate::InstanceError> { + let webgl_sig = "WebGL "; + // According to the WebGL specification + // VERSION WebGL1.0 + // SHADING_LANGUAGE_VERSION WebGLGLSLES1.0 + let is_webgl = src.starts_with(webgl_sig); + if is_webgl { + let pos = src.rfind(webgl_sig).unwrap_or(0); + src = &src[pos + webgl_sig.len()..]; + } else { + let es_sig = " ES "; + match src.rfind(es_sig) { + Some(pos) => { + src = &src[pos + es_sig.len()..]; + } + None => { + log::warn!("ES not found in '{}'", src); + return Err(crate::InstanceError); + } + } + }; + + let glsl_es_sig = "GLSL ES "; + let is_glsl = match src.find(glsl_es_sig) { + Some(pos) => { + src = &src[pos + glsl_es_sig.len()..]; + true + } + None => false, + }; + + let (version, vendor_info) = match src.find(' ') { + Some(i) => (&src[..i], src[i + 1..].to_string()), + None => (src, String::new()), + }; + + // TODO: make this even more lenient so that we can also accept + // ` "." []` + let mut it = version.split('.'); + let major = it.next().and_then(|s| s.parse().ok()); + let minor = it.next().and_then(|s| { + let trimmed = if s.starts_with('0') { + "0" + } else { + s.trim_end_matches('0') + }; + trimmed.parse().ok() + }); + + match (major, minor) { + (Some(major), Some(minor)) => Ok(( + // Return WebGL 2.0 version as OpenGL ES 3.0 + if is_webgl && !is_glsl { + major + 1 + } else { + major + }, + minor, + )), + _ => { + log::warn!("Unable to extract the version from '{}'", version); + Err(crate::InstanceError) + } + } + } + fn make_info(vendor_orig: String, renderer_orig: String) -> wgt::AdapterInfo { let vendor = vendor_orig.to_lowercase(); let renderer = renderer_orig.to_lowercase(); @@ -74,29 +157,63 @@ impl super::Adapter { } } - pub(super) unsafe fn expose(gl: glow::Context) -> crate::ExposedAdapter { + pub(super) unsafe fn expose(gl: glow::Context) -> Option> { let vendor = gl.get_parameter_string(glow::VENDOR); let renderer = gl.get_parameter_string(glow::RENDERER); + let version = gl.get_parameter_string(glow::VERSION); + + let ver = Self::parse_version(&version).ok()?; + + let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; let min_uniform_buffer_offset_alignment = gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT); - let min_storage_buffer_offset_alignment = if super::is_webgl() { + let min_storage_buffer_offset_alignment = if cfg!(target_arch = "wasm32") { 256 } else { gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) }; - crate::ExposedAdapter { + let limits = wgt::Limits { + max_texture_dimension_1d: max_texture_size, + max_texture_dimension_2d: max_texture_size, + max_texture_dimension_3d: max_texture_size, + max_texture_array_layers: gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) as u32, + max_bind_groups: 4, + max_dynamic_uniform_buffers_per_pipeline_layout: 8, + max_dynamic_storage_buffers_per_pipeline_layout: 4, + max_sampled_textures_per_shader_stage: 16, + max_samplers_per_shader_stage: 16, + max_storage_buffers_per_shader_stage: 8, + max_storage_textures_per_shader_stage: 8, + max_uniform_buffers_per_shader_stage: 12, + max_uniform_buffer_binding_size: 16384, + max_storage_buffer_binding_size: 128 << 20, + max_vertex_buffers: 8, + max_vertex_attributes: 16, + max_vertex_buffer_array_stride: 2048, + max_push_constant_size: 0, + }; + + let features = wgt::Features::empty(); //TODO + let mut private_caps = super::PrivateCapability::empty(); + private_caps.set( + super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER, + ver >= (3, 1), + ); + + Some(crate::ExposedAdapter { adapter: super::Adapter { shared: Arc::new(super::AdapterShared { context: gl, - private_caps: super::PrivateCapabilities {}, + private_caps, + extra_flags: super::ExtraDownlevelFlag::empty(), }), }, info: Self::make_info(vendor, renderer), - features: wgt::Features::empty(), //TODO + features, capabilities: crate::Capabilities { - limits: wgt::Limits::default(), //TODO + limits, downlevel: wgt::DownlevelCapabilities::default(), //TODO alignments: crate::Alignments { buffer_copy_offset: wgt::BufferSize::new(4).unwrap(), @@ -111,6 +228,37 @@ impl super::Adapter { .unwrap(), }, }, - } + }) + } +} + +#[cfg(test)] +mod tests { + use super::super::Adapter; + + #[test] + fn test_version_parse() { + let error = Err(crate::InstanceError); + assert_eq!(Adapter::parse_version("1"), error); + assert_eq!(Adapter::parse_version("1."), error); + assert_eq!(Adapter::parse_version("1 h3l1o. W0rld"), error); + assert_eq!(Adapter::parse_version("1. h3l1o. W0rld"), error); + assert_eq!(Adapter::parse_version("1.2.3"), error); + assert_eq!(Adapter::parse_version("OpenGL ES 3.1"), Ok((3, 1))); + assert_eq!( + Adapter::parse_version("OpenGL ES 2.0 Google Nexus"), + Ok((2, 0)) + ); + assert_eq!(Adapter::parse_version("GLSL ES 1.1"), Ok((1, 1))); + assert_eq!(Adapter::parse_version("OpenGL ES GLSL ES 3.20"), Ok((3, 2))); + assert_eq!( + // WebGL 2.0 should parse as OpenGL ES 3.0 + Adapter::parse_version("WebGL 2.0 (OpenGL ES 3.0 Chromium)"), + Ok((3, 0)) + ); + assert_eq!( + Adapter::parse_version("WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)"), + Ok((3, 0)) + ); } } diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 2bcc76e62b..3d6bec6d83 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -1,4 +1,4 @@ -impl super::PrivateCapabilities { +impl super::PrivateCapability { pub(super) fn describe_texture_format( &self, format: wgt::TextureFormat, diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 03987d2adb..bae87b1068 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -335,6 +335,7 @@ impl crate::Instance for Instance { * * See gfx-rs/gfx#3545 */ + log::warn!("Re-initializing Gles context due to Wayland window"); if inner .wl_display .map(|ptr| ptr != handle.display) @@ -483,7 +484,7 @@ impl crate::Instance for Instance { .map_or(ptr::null(), |p| p as *const _) }); - vec![super::Adapter::expose(context)] + super::Adapter::expose(context).into_iter().collect() } } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 19599654b4..51bce35042 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -46,8 +46,27 @@ impl crate::Api for Api { type ComputePipeline = Resource; } -const fn is_webgl() -> bool { - cfg!(target_arch = "wasm32") +//TODO: uplift these to `DownlevelFlags` +bitflags::bitflags! { + /// Flags for features that are required for Vulkan but may not + /// be supported by legacy backends (GL/DX11). + struct ExtraDownlevelFlag: u32 { + /// Support indirect drawing and dispatching. + const INDIRECT_EXECUTION = 0x00000001; + /// Support indexed drawing with base vertex. + const BASE_VERTEX = 0x00000010; + /// Support offsets for instanced drawing with base instance. + const BASE_INSTANCE = 0x0000020; + } +} + +bitflags::bitflags! { + /// Flags that affect internal code paths but do not + /// change the exposed feature set. + struct PrivateCapability: u32 { + /// Support explicit layouts in shader. + const EXPLICIT_LAYOUTS_IN_SHADER = 0x00002000; + } } type TextureFormat = u32; @@ -67,11 +86,10 @@ struct FormatDescription { va_kind: VertexAttribKind, } -struct PrivateCapabilities {} - struct AdapterShared { context: glow::Context, - private_caps: PrivateCapabilities, + extra_flags: ExtraDownlevelFlag, + private_caps: PrivateCapability, } pub struct Adapter { From 5083f56149ad39f5f504d2c8af3159019ba1690d Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 21 Jun 2021 00:26:17 -0400 Subject: [PATCH 04/33] Add more downlevel flags, implement device opening on Gles --- Cargo.lock | 3 +- wgpu-hal/Cargo.toml | 2 +- wgpu-hal/src/gles/adapter.rs | 115 ++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/egl.rs | 53 ++++++++++++++- wgpu-hal/src/gles/mod.rs | 38 ++--------- wgpu-hal/src/lib.rs | 5 +- wgpu-hal/src/metal/adapter.rs | 3 + wgpu-hal/src/vulkan/adapter.rs | 4 +- wgpu-types/src/lib.rs | 22 ++++--- 9 files changed, 186 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c43e46000..1727c05ce8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,8 +690,7 @@ dependencies = [ [[package]] name = "glow" version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945be163fdb893227410c8b44c2412dade922585b262d1daa6a7e96135217d4c" +source = "git+https://github.com/grovesNL/glow?rev=23d16276aaa8095d9ae507b1f70d0c9edfe3527f#23d16276aaa8095d9ae507b1f70d0c9edfe3527f" dependencies = [ "js-sys", "slotmap", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 2aeea651c3..95a3b22209 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -38,7 +38,7 @@ 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 } +glow = { git = "https://github.com/grovesNL/glow", rev = "23d16276aaa8095d9ae507b1f70d0c9edfe3527f", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 6ab1ad6fca..2b87939c93 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -161,10 +161,36 @@ impl super::Adapter { let vendor = gl.get_parameter_string(glow::VENDOR); let renderer = gl.get_parameter_string(glow::RENDERER); let version = gl.get_parameter_string(glow::VERSION); + log::info!("Vendor: {}", vendor); + log::info!("Renderer: {}", renderer); + log::info!("Version: {}", version); let ver = Self::parse_version(&version).ok()?; + let extensions = gl.supported_extensions(); + log::info!("Extensions: {:?}", extensions); + + let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE; + features.set( + wgt::Features::DEPTH_CLAMPING, + extensions.contains("GL_EXT_depth_clamp"), + ); + features.set(wgt::Features::VERTEX_WRITABLE_STORAGE, ver >= (3, 1)); + + let mut downlevel_flags = wgt::DownlevelFlags::empty() + | wgt::DownlevelFlags::DEVICE_LOCAL_IMAGE_COPIES + | wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES + | wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES + | wgt::DownlevelFlags::COMPARISON_SAMPLERS; + downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, ver >= (3, 1)); + downlevel_flags.set( + wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE, + ver >= (3, 1), + ); + downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1)); + downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2)); let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; + let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32; let min_uniform_buffer_offset_alignment = gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT); @@ -173,29 +199,36 @@ impl super::Adapter { } else { gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) }; + let max_uniform_buffers_per_shader_stage = + gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS) + .min(gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS)) as u32; let limits = wgt::Limits { max_texture_dimension_1d: max_texture_size, max_texture_dimension_2d: max_texture_size, - max_texture_dimension_3d: max_texture_size, + max_texture_dimension_3d: max_texture_3d_size, max_texture_array_layers: gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) as u32, - max_bind_groups: 4, + max_bind_groups: crate::MAX_BIND_GROUPS as u32, max_dynamic_uniform_buffers_per_pipeline_layout: 8, max_dynamic_storage_buffers_per_pipeline_layout: 4, max_sampled_textures_per_shader_stage: 16, max_samplers_per_shader_stage: 16, max_storage_buffers_per_shader_stage: 8, max_storage_textures_per_shader_stage: 8, - max_uniform_buffers_per_shader_stage: 12, - max_uniform_buffer_binding_size: 16384, - max_storage_buffer_binding_size: 128 << 20, - max_vertex_buffers: 8, - max_vertex_attributes: 16, + max_uniform_buffers_per_shader_stage, + max_uniform_buffer_binding_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE) + as u32, + max_storage_buffer_binding_size: if ver >= (3, 1) { + gl.get_parameter_i32(glow::MAX_SHADER_STORAGE_BLOCK_SIZE) as u32 + } else { + 0 + }, + max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32, + max_vertex_attributes: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32, max_vertex_buffer_array_stride: 2048, max_push_constant_size: 0, }; - let features = wgt::Features::empty(); //TODO let mut private_caps = super::PrivateCapability::empty(); private_caps.set( super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER, @@ -207,14 +240,16 @@ impl super::Adapter { shared: Arc::new(super::AdapterShared { context: gl, private_caps, - extra_flags: super::ExtraDownlevelFlag::empty(), }), }, info: Self::make_info(vendor, renderer), features, capabilities: crate::Capabilities { limits, - downlevel: wgt::DownlevelCapabilities::default(), //TODO + downlevel: wgt::DownlevelCapabilities { + flags: downlevel_flags, + shader_model: wgt::ShaderModel::Sm5, + }, alignments: crate::Alignments { buffer_copy_offset: wgt::BufferSize::new(4).unwrap(), buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(), @@ -232,6 +267,66 @@ impl super::Adapter { } } +impl crate::Adapter for super::Adapter { + unsafe fn open( + &self, + features: wgt::Features, + ) -> Result, crate::DeviceError> { + let gl = &self.shared.context; + gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); + let main_vao = gl.create_vertex_array().unwrap(); + gl.bind_vertex_array(Some(main_vao)); + + Ok(crate::OpenDevice { + device: super::Device { + shared: Arc::clone(&self.shared), + main_vao, + }, + queue: super::Queue { + shared: Arc::clone(&self.shared), + features, + }, + }) + } + + unsafe fn texture_format_capabilities( + &self, + format: wgt::TextureFormat, + ) -> crate::TextureFormatCapability { + crate::TextureFormatCapability::empty() //TODO + } + + unsafe fn surface_capabilities( + &self, + surface: &super::Surface, + ) -> Option { + if surface.presentable { + Some(crate::SurfaceCapabilities { + formats: vec![ + wgt::TextureFormat::Rgba8UnormSrgb, + wgt::TextureFormat::Bgra8UnormSrgb, + ], + present_modes: vec![wgt::PresentMode::Fifo], //TODO + composite_alpha_modes: vec![crate::CompositeAlphaMode::Opaque], //TODO + swap_chain_sizes: 2..=2, + current_extent: None, + extents: wgt::Extent3d { + width: 4, + height: 4, + depth_or_array_layers: 1, + }..=wgt::Extent3d { + width: 4096, + height: 4096, + depth_or_array_layers: 1, + }, + usage: crate::TextureUse::COLOR_TARGET, + }) + } else { + None + } + } +} + #[cfg(test)] mod tests { use super::super::Adapter; diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index bae87b1068..e564bf0edf 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -112,6 +112,48 @@ fn choose_config( Err(crate::InstanceError) } +fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) { + let source_str = match source { + glow::DEBUG_SOURCE_API => "API", + glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System", + glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler", + glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party", + glow::DEBUG_SOURCE_APPLICATION => "Application", + glow::DEBUG_SOURCE_OTHER => "Other", + _ => unreachable!(), + }; + + let log_severity = match severity { + glow::DEBUG_SEVERITY_HIGH => log::Level::Error, + glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn, + glow::DEBUG_SEVERITY_LOW => log::Level::Info, + glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace, + _ => unreachable!(), + }; + + let type_str = match gltype { + glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior", + glow::DEBUG_TYPE_ERROR => "Error", + glow::DEBUG_TYPE_MARKER => "Marker", + glow::DEBUG_TYPE_OTHER => "Other", + glow::DEBUG_TYPE_PERFORMANCE => "Performance", + glow::DEBUG_TYPE_POP_GROUP => "Pop Group", + glow::DEBUG_TYPE_PORTABILITY => "Portability", + glow::DEBUG_TYPE_PUSH_GROUP => "Push Group", + glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior", + _ => unreachable!(), + }; + + log::log!( + log_severity, + "[{}/{}] ID {} : {}", + source_str, + type_str, + id, + message + ); +} + #[derive(Debug)] struct Inner { egl: Arc>, @@ -477,14 +519,19 @@ impl crate::Instance for Instance { ) .unwrap(); - let context = glow::Context::from_loader_function(|name| { + let gl = glow::Context::from_loader_function(|name| { inner .egl .get_proc_address(name) .map_or(ptr::null(), |p| p as *const _) }); - super::Adapter::expose(context).into_iter().collect() + if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() { + gl.enable(glow::DEBUG_OUTPUT); + gl.debug_message_callback(debug_message_callback); + } + + super::Adapter::expose(gl).into_iter().collect() } } @@ -505,7 +552,7 @@ pub struct Surface { display: egl::Display, context: egl::Context, pbuffer: Option, - presentable: bool, + pub(super) presentable: bool, wl_window: Option<*mut raw::c_void>, swapchain: Option, } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 51bce35042..98df9f8f98 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -26,7 +26,7 @@ impl crate::Api for Api { type Adapter = Adapter; type Device = Device; - type Queue = Context; + type Queue = Queue; type CommandEncoder = Encoder; type CommandBuffer = Resource; @@ -46,20 +46,6 @@ impl crate::Api for Api { type ComputePipeline = Resource; } -//TODO: uplift these to `DownlevelFlags` -bitflags::bitflags! { - /// Flags for features that are required for Vulkan but may not - /// be supported by legacy backends (GL/DX11). - struct ExtraDownlevelFlag: u32 { - /// Support indirect drawing and dispatching. - const INDIRECT_EXECUTION = 0x00000001; - /// Support indexed drawing with base vertex. - const BASE_VERTEX = 0x00000010; - /// Support offsets for instanced drawing with base instance. - const BASE_INSTANCE = 0x0000020; - } -} - bitflags::bitflags! { /// Flags that affect internal code paths but do not /// change the exposed feature set. @@ -88,7 +74,6 @@ struct FormatDescription { struct AdapterShared { context: glow::Context, - extra_flags: ExtraDownlevelFlag, private_caps: PrivateCapability, } @@ -98,24 +83,15 @@ pub struct Adapter { pub struct Device { shared: Arc, + main_vao: glow::VertexArray, } -impl crate::Adapter for Adapter { - 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 - } +pub struct Queue { + shared: Arc, + features: wgt::Features, } -impl crate::Queue for Context { +impl crate::Queue for Queue { unsafe fn submit( &mut self, command_buffers: &[&Resource], @@ -201,7 +177,7 @@ impl crate::Device for Device { unsafe fn create_shader_module( &self, desc: &crate::ShaderModuleDescriptor, - shader: crate::NagaShader, + shader: crate::ShaderInput, ) -> Result { Ok(Resource) } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index cf67f8320e..df37f55403 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -45,11 +45,12 @@ compile_error!("Metal backend enabled on non-Apple OS. If your project is not using resolver=\"2\" in Cargo.toml, it should."); mod empty; +#[cfg(feature = "gles")] +mod gles; #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] mod metal; #[cfg(feature = "vulkan")] -mod vulkan;#[cfg(feature = "gles")] -mod gles; +mod vulkan; pub mod util; pub mod api { diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index ec3a6eb073..3d7cc3b2cf 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -880,6 +880,9 @@ impl super::PrivateCapabilities { wgt::DownlevelFlags::COMPARISON_SAMPLERS, self.mutable_comparison_samplers, ); + downlevel + .flags + .set(wgt::DownlevelFlags::ANISOTROPIC_FILTERING, true); crate::Capabilities { limits: wgt::Limits { diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index dbf0df96e7..9af802a82c 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -99,7 +99,7 @@ impl PhysicalDeviceFeatures { requested_features.contains(wgt::Features::VERTEX_WRITABLE_STORAGE), ) .fragment_stores_and_atomics( - downlevel_flags.contains(wgt::DownlevelFlags::STORAGE_IMAGES), + downlevel_flags.contains(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE), ) //.shader_image_gather_extended( //.shader_storage_image_extended_formats( @@ -239,7 +239,7 @@ impl PhysicalDeviceFeatures { dl_flags.set(Df::CUBE_ARRAY_TEXTURES, self.core.image_cube_array != 0); dl_flags.set(Df::ANISOTROPIC_FILTERING, self.core.sampler_anisotropy != 0); dl_flags.set( - Df::STORAGE_IMAGES, + Df::FRAGMENT_WRITABLE_STORAGE, self.core.fragment_stores_and_atomics != 0, ); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 0f1a107517..99fffc8ef1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -619,24 +619,30 @@ bitflags::bitflags! { pub struct DownlevelFlags: u32 { /// The device supports compiling and using compute shaders. const COMPUTE_SHADERS = 0x0000_0001; - /// Supports creating storage images. - const STORAGE_IMAGES = 0x0000_0002; + /// Supports binding storage buffers and textures to fragment shaders. + const FRAGMENT_WRITABLE_STORAGE = 0x0000_0002; + /// Supports indirect drawing and dispatching. + const INDIRECT_EXECUTION = 0x0000_0004; + /// Supports non-zero `base_vertex` parameter to indexed draw calls. + const BASE_VERTEX = 0x0000_0008; + /// Supports non-zero `base_instance` parameter to draw calls. + const BASE_INSTANCE = 0x0000_0010; /// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil attachment. - const READ_ONLY_DEPTH_STENCIL = 0x0000_0004; + const READ_ONLY_DEPTH_STENCIL = 0x0000_0020; /// Supports: /// - copy_image_to_image /// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage - const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0008; + const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0040; /// Supports textures with mipmaps which have a non power of two size. - const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0010; + const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0080; /// Supports textures that are cube arrays. - const CUBE_ARRAY_TEXTURES = 0x0000_0020; + const CUBE_ARRAY_TEXTURES = 0x0000_0100; /// Supports comparison samplers. - const COMPARISON_SAMPLERS = 0x0000_0040; + const COMPARISON_SAMPLERS = 0x0000_0200; /// Supports samplers with anisotropic filtering const ANISOTROPIC_FILTERING = 0x0001_0000; /// All flags are in their compliant state. - const COMPLIANT = 0x0000_007F; + const COMPLIANT = 0x0000_02FF; } } From 31e6ed82cb36c29347e5be54ca953e1a99df639b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 21 Jun 2021 01:56:45 -0400 Subject: [PATCH 05/33] hal/gles: creation of buffers, textures, view, and samplers --- wgpu-hal/src/gles/conv.rs | 48 +++++- wgpu-hal/src/gles/device.rs | 331 ++++++++++++++++++++++++++++++++++++ wgpu-hal/src/gles/egl.rs | 9 +- wgpu-hal/src/gles/mod.rs | 290 ++++++++++++++++--------------- 4 files changed, 532 insertions(+), 146 deletions(-) create mode 100644 wgpu-hal/src/gles/device.rs diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 3d6bec6d83..ba89e26b8e 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -1,4 +1,4 @@ -impl super::PrivateCapability { +impl super::AdapterShared { pub(super) fn describe_texture_format( &self, format: wgt::TextureFormat, @@ -220,3 +220,49 @@ impl super::PrivateCapability { } } } + +pub fn map_filter_modes( + min: wgt::FilterMode, + mag: wgt::FilterMode, + mip: wgt::FilterMode, +) -> (u32, u32) { + use wgt::FilterMode as Fm; + + let mag_filter = match mag { + Fm::Nearest => glow::NEAREST, + Fm::Linear => glow::LINEAR, + }; + + let min_filter = match (min, mip) { + (Fm::Nearest, Fm::Nearest) => glow::NEAREST_MIPMAP_NEAREST, + (Fm::Nearest, Fm::Linear) => glow::NEAREST_MIPMAP_LINEAR, + (Fm::Linear, Fm::Nearest) => glow::LINEAR_MIPMAP_NEAREST, + (Fm::Linear, Fm::Linear) => glow::LINEAR_MIPMAP_LINEAR, + }; + + (min_filter, mag_filter) +} + +pub fn map_address_mode(mode: wgt::AddressMode) -> u32 { + match mode { + wgt::AddressMode::Repeat => glow::REPEAT, + wgt::AddressMode::MirrorRepeat => glow::MIRRORED_REPEAT, + wgt::AddressMode::ClampToEdge => glow::CLAMP_TO_EDGE, + wgt::AddressMode::ClampToBorder => glow::CLAMP_TO_BORDER, + //wgt::AddressMode::MirrorClamp => glow::MIRROR_CLAMP_TO_EDGE, + } +} + +pub fn map_compare_func(fun: wgt::CompareFunction) -> u32 { + use wgt::CompareFunction as Cf; + match fun { + Cf::Never => glow::NEVER, + Cf::Less => glow::LESS, + Cf::LessEqual => glow::LEQUAL, + Cf::Equal => glow::EQUAL, + Cf::GreaterEqual => glow::GEQUAL, + Cf::Greater => glow::GREATER, + Cf::NotEqual => glow::NOTEQUAL, + Cf::Always => glow::ALWAYS, + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs new file mode 100644 index 0000000000..3ad0e88a75 --- /dev/null +++ b/wgpu-hal/src/gles/device.rs @@ -0,0 +1,331 @@ +use super::{DeviceResult, Encoder, Resource}; //TEMP +use glow::HasContext; +use std::{convert::TryInto, ptr::NonNull}; + +impl crate::Device for super::Device { + unsafe fn exit(self) { + let gl = &self.shared.context; + gl.delete_vertex_array(self.main_vao); + } + + unsafe fn create_buffer( + &self, + desc: &crate::BufferDescriptor, + ) -> Result { + let gl = &self.shared.context; + + let target = if desc.usage.contains(crate::BufferUse::INDEX) { + glow::ELEMENT_ARRAY_BUFFER + } else { + glow::ARRAY_BUFFER + }; + let map_coherent = false; + let map_flags = glow::MAP_PERSISTENT_BIT + | if map_coherent { + glow::MAP_COHERENT_BIT + } else { + 0 + }; + let mut storage_flags = 0; + if desc.usage.contains(crate::BufferUse::MAP_READ) { + storage_flags |= map_flags | glow::MAP_READ_BIT; + } + if desc.usage.contains(crate::BufferUse::MAP_WRITE) { + storage_flags |= map_flags | glow::MAP_WRITE_BIT; + } + + let raw = gl.create_buffer().unwrap(); + gl.bind_buffer(target, Some(raw)); + let raw_size = desc + .size + .try_into() + .map_err(|_| crate::DeviceError::OutOfMemory)?; + gl.buffer_storage(target, raw_size, None, storage_flags); + gl.bind_buffer(target, None); + + Ok(super::Buffer { + raw, + target, + map_flags, + }) + } + unsafe fn destroy_buffer(&self, buffer: super::Buffer) { + let gl = &self.shared.context; + gl.delete_buffer(buffer.raw); + } + + unsafe fn map_buffer( + &self, + buffer: &super::Buffer, + range: crate::MemoryRange, + ) -> Result { + let gl = &self.shared.context; + + gl.bind_buffer(buffer.target, Some(buffer.raw)); + let ptr = gl.map_buffer_range( + buffer.target, + range.start as i32, + (range.end - range.start) as i32, + buffer.map_flags, + ); + gl.bind_buffer(buffer.target, None); + + Ok(crate::BufferMapping { + ptr: NonNull::new(ptr).ok_or(crate::DeviceError::Lost)?, + is_coherent: buffer.map_flags & glow::MAP_COHERENT_BIT != 0, + }) + } + unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> DeviceResult<()> { + let gl = &self.shared.context; + gl.bind_buffer(buffer.target, Some(buffer.raw)); + gl.unmap_buffer(buffer.target); + gl.bind_buffer(buffer.target, None); + Ok(()) + } + unsafe fn flush_mapped_ranges(&self, buffer: &super::Buffer, ranges: I) + where + I: Iterator, + { + let gl = &self.shared.context; + for range in ranges { + gl.flush_mapped_buffer_range( + buffer.target, + range.start as i32, + (range.end - range.start) as i32, + ); + } + } + unsafe fn invalidate_mapped_ranges(&self, buffer: &super::Buffer, ranges: I) + where + I: Iterator, + { + let gl = &self.shared.context; + for range in ranges { + gl.invalidate_buffer_sub_data( + buffer.target, + range.start as i32, + (range.end - range.start) as i32, + ); + } + } + + unsafe fn create_texture( + &self, + desc: &crate::TextureDescriptor, + ) -> Result { + let gl = &self.shared.context; + + let render_usage = crate::TextureUse::COLOR_TARGET + | crate::TextureUse::DEPTH_STENCIL_WRITE + | crate::TextureUse::DEPTH_STENCIL_READ; + let format_desc = self.shared.describe_texture_format(desc.format); + Ok( + if render_usage.contains(desc.usage) + && desc.dimension == wgt::TextureDimension::D2 + && desc.size.depth_or_array_layers == 1 + { + let raw = gl.create_renderbuffer().unwrap(); + gl.bind_renderbuffer(glow::RENDERBUFFER, Some(raw)); + if desc.sample_count > 1 { + gl.renderbuffer_storage_multisample( + glow::RENDERBUFFER, + desc.sample_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); + } else { + gl.renderbuffer_storage( + glow::RENDERBUFFER, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); + } + super::Texture::Renderbuffer { + raw, + aspects: desc.format.into(), + } + } else { + let raw = gl.create_texture().unwrap(); + let target = match desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { + if desc.sample_count > 1 { + let target = glow::TEXTURE_2D; + gl.bind_texture(target, Some(raw)); + // https://github.com/grovesNL/glow/issues/169 + //gl.tex_storage_2d_multisample(target, desc.sample_count as i32, format_desc.tex_internal, desc.size.width as i32, desc.size.height as i32, true); + log::error!("TODO: support `tex_storage_2d_multisample` (https://github.com/grovesNL/glow/issues/169)"); + return Err(crate::DeviceError::Lost); + } else if desc.size.depth_or_array_layers > 1 { + let target = glow::TEXTURE_2D_ARRAY; + gl.bind_texture(target, Some(raw)); + gl.tex_storage_3d( + target, + desc.mip_level_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + desc.size.depth_or_array_layers as i32, + ); + target + } else { + let target = glow::TEXTURE_2D; + gl.bind_texture(target, Some(raw)); + gl.tex_storage_2d( + target, + desc.mip_level_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); + target + } + } + wgt::TextureDimension::D3 => { + let target = glow::TEXTURE_3D; + gl.bind_texture(target, Some(raw)); + gl.tex_storage_3d( + target, + desc.mip_level_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + desc.size.depth_or_array_layers as i32, + ); + target + } + }; + super::Texture::Texture { raw, target } + }, + ) + } + unsafe fn destroy_texture(&self, texture: super::Texture) { + let gl = &self.shared.context; + match texture { + super::Texture::Renderbuffer { raw, .. } => { + gl.delete_renderbuffer(raw); + } + super::Texture::Texture { raw, target } => { + gl.delete_texture(raw); + } + } + } + + unsafe fn create_texture_view( + &self, + texture: &super::Texture, + desc: &crate::TextureViewDescriptor, + ) -> Result { + Ok(match *texture { + super::Texture::Renderbuffer { raw, aspects } => super::TextureView::Renderbuffer { + raw, + aspects: aspects & crate::FormatAspect::from(desc.range.aspect), + }, + super::Texture::Texture { raw, target } => super::TextureView::Texture { + raw, + target, + range: desc.range.clone(), + }, + }) + } + unsafe fn destroy_texture_view(&self, view: super::TextureView) {} + + unsafe fn create_sampler( + &self, + desc: &crate::SamplerDescriptor, + ) -> Result { + use super::Sampled; + let gl = &self.shared.context; + + let raw = gl.create_sampler().unwrap(); + super::SamplerBinding(raw).configure_sampling(gl, desc); + + Ok(super::Sampler { raw }) + } + unsafe fn destroy_sampler(&self, sampler: super::Sampler) { + let gl = &self.shared.context; + gl.delete_sampler(sampler.raw); + } + + 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::ShaderInput, + ) -> 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) {} +} diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index e564bf0edf..ac5b60ac61 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -449,7 +449,7 @@ impl crate::Instance for Instance { crate::InstanceError }) } else { - let attributes_i32: Vec = attributes.iter().map(|a| (*a as i32).into()).collect(); + let attributes_i32: Vec = attributes.iter().map(|a| *a as i32).collect(); inner .egl .create_window_surface( @@ -581,10 +581,7 @@ impl crate::Surface for Surface { ); } - let format_desc = device - .shared - .private_caps - .describe_texture_format(config.format); + let format_desc = device.shared.describe_texture_format(config.format); let gl = &device.shared.context; let renderbuffer = gl.create_renderbuffer().unwrap(); gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)); @@ -633,5 +630,5 @@ impl crate::Surface for Surface { // native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel); Ok(None) } - unsafe fn discard_texture(&mut self, _texture: super::Resource) {} + unsafe fn discard_texture(&mut self, _texture: super::Texture) {} } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 98df9f8f98..557263d48a 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -5,10 +5,13 @@ mod egl; mod adapter; mod conv; +mod device; #[cfg(not(target_arch = "wasm32"))] use self::egl::{Instance, Surface}; +use glow::HasContext; + use std::{ops::Range, sync::Arc}; #[derive(Clone)] @@ -30,11 +33,11 @@ impl crate::Api for Api { type CommandEncoder = Encoder; type CommandBuffer = Resource; - type Buffer = Resource; - type Texture = Resource; - type SurfaceTexture = Resource; - type TextureView = Resource; - type Sampler = Resource; + type Buffer = Buffer; + type Texture = Texture; + type SurfaceTexture = Texture; + type TextureView = TextureView; + type Sampler = Sampler; type QuerySet = Resource; type Fence = Resource; @@ -55,8 +58,98 @@ bitflags::bitflags! { } } +type BindTarget = u32; type TextureFormat = u32; +trait Sampled { + unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32); + // see https://github.com/grovesNL/glow/issues/170 + unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]); + unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32); + + unsafe fn configure_sampling(&self, gl: &glow::Context, desc: &crate::SamplerDescriptor) { + let (min, mag) = + conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter); + + self.set_param_int(gl, glow::TEXTURE_MIN_FILTER, min as i32); + self.set_param_int(gl, glow::TEXTURE_MAG_FILTER, mag as i32); + + self.set_param_int( + gl, + glow::TEXTURE_WRAP_S, + conv::map_address_mode(desc.address_modes[0]) as i32, + ); + self.set_param_int( + gl, + glow::TEXTURE_WRAP_T, + conv::map_address_mode(desc.address_modes[1]) as i32, + ); + self.set_param_int( + gl, + glow::TEXTURE_WRAP_R, + conv::map_address_mode(desc.address_modes[2]) as i32, + ); + + if let Some(border_color) = desc.border_color { + let mut border = match border_color { + wgt::SamplerBorderColor::TransparentBlack => [0.0; 4], + wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0], + wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4], + }; + self.set_param_float_vec(gl, glow::TEXTURE_BORDER_COLOR, &mut border); + } + + if let Some(ref range) = desc.lod_clamp { + self.set_param_float(gl, glow::TEXTURE_MIN_LOD, range.start); + self.set_param_float(gl, glow::TEXTURE_MAX_LOD, range.end); + } + + //TODO: `desc.anisotropy_clamp` depends on the downlevel flag + // self.set_param_float(glow::TEXTURE_MAX_ANISOTROPY, aniso as f32); + + //set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0); + + if let Some(compare) = desc.compare { + self.set_param_int( + gl, + glow::TEXTURE_COMPARE_MODE, + glow::COMPARE_REF_TO_TEXTURE as i32, + ); + self.set_param_int( + gl, + glow::TEXTURE_COMPARE_FUNC, + conv::map_compare_func(compare) as i32, + ); + } + } +} + +struct SamplerBinding(glow::Sampler); +impl Sampled for SamplerBinding { + unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) { + gl.sampler_parameter_f32(self.0, key, value); + } + unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) { + gl.sampler_parameter_f32_slice(self.0, key, values); + } + unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) { + gl.sampler_parameter_i32(self.0, key, value); + } +} + +struct SampledTextureBinding(BindTarget); +impl Sampled for SampledTextureBinding { + unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) { + gl.tex_parameter_f32(self.0, key, value); + } + unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) { + gl.tex_parameter_f32_slice(self.0, key, values); + } + unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) { + gl.tex_parameter_i32(self.0, key, value); + } +} + #[derive(Debug, Clone, Copy)] enum VertexAttribKind { Float, // glVertexAttribPointer @@ -91,6 +184,43 @@ pub struct Queue { features: wgt::Features, } +#[derive(Debug)] +pub struct Buffer { + raw: glow::Buffer, + target: BindTarget, + map_flags: u32, +} + +#[derive(Debug)] +pub enum Texture { + Renderbuffer { + raw: glow::Renderbuffer, + aspects: crate::FormatAspect, + }, + Texture { + raw: glow::Texture, + target: BindTarget, + }, +} + +#[derive(Debug)] +pub enum TextureView { + Renderbuffer { + raw: glow::Renderbuffer, + aspects: crate::FormatAspect, + }, + Texture { + raw: glow::Texture, + target: BindTarget, + range: wgt::ImageSubresourceRange, + }, +} + +#[derive(Debug)] +pub struct Sampler { + raw: glow::Sampler, +} + impl crate::Queue for Queue { unsafe fn submit( &mut self, @@ -102,130 +232,12 @@ impl crate::Queue for Queue { unsafe fn present( &mut self, surface: &mut Surface, - texture: Resource, + texture: Texture, ) -> Result<(), crate::SurfaceError> { Ok(()) } } -impl crate::Device for Device { - 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::ShaderInput, - ) -> 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(()) @@ -248,26 +260,26 @@ impl crate::CommandEncoder for Encoder { { } - unsafe fn fill_buffer(&mut self, buffer: &Resource, range: crate::MemoryRange, value: u8) {} + unsafe fn fill_buffer(&mut self, buffer: &Buffer, range: crate::MemoryRange, value: u8) {} - unsafe fn copy_buffer_to_buffer(&mut self, src: &Resource, dst: &Resource, regions: T) {} + unsafe fn copy_buffer_to_buffer(&mut self, src: &Buffer, dst: &Buffer, regions: T) {} unsafe fn copy_texture_to_texture( &mut self, - src: &Resource, + src: &Texture, src_usage: crate::TextureUse, - dst: &Resource, + dst: &Texture, regions: T, ) { } - unsafe fn copy_buffer_to_texture(&mut self, src: &Resource, dst: &Resource, regions: T) {} + unsafe fn copy_buffer_to_texture(&mut self, src: &Buffer, dst: &Texture, regions: T) {} unsafe fn copy_texture_to_buffer( &mut self, - src: &Resource, + src: &Texture, src_usage: crate::TextureUse, - dst: &Resource, + dst: &Buffer, regions: T, ) { } @@ -280,7 +292,7 @@ impl crate::CommandEncoder for Encoder { &mut self, set: &Resource, range: Range, - buffer: &Resource, + buffer: &Buffer, offset: wgt::BufferAddress, ) { } @@ -345,32 +357,32 @@ impl crate::CommandEncoder for Encoder { } unsafe fn draw_indirect( &mut self, - buffer: &Resource, + buffer: &Buffer, offset: wgt::BufferAddress, draw_count: u32, ) { } unsafe fn draw_indexed_indirect( &mut self, - buffer: &Resource, + buffer: &Buffer, offset: wgt::BufferAddress, draw_count: u32, ) { } unsafe fn draw_indirect_count( &mut self, - buffer: &Resource, + buffer: &Buffer, offset: wgt::BufferAddress, - count_buffer: &Resource, + count_buffer: &Buffer, count_offset: wgt::BufferAddress, max_count: u32, ) { } unsafe fn draw_indexed_indirect_count( &mut self, - buffer: &Resource, + buffer: &Buffer, offset: wgt::BufferAddress, - count_buffer: &Resource, + count_buffer: &Buffer, count_offset: wgt::BufferAddress, max_count: u32, ) { @@ -384,5 +396,5 @@ impl crate::CommandEncoder for Encoder { 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) {} + unsafe fn dispatch_indirect(&mut self, buffer: &Buffer, offset: wgt::BufferAddress) {} } From 31da0f22782973606ffebae0b1b5504d9d55593f Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 21 Jun 2021 17:00:39 -0400 Subject: [PATCH 06/33] hal/gles: command module --- wgpu-hal/src/gles/command.rs | 180 ++++++++++++++++++++++++++++++++++ wgpu-hal/src/gles/device.rs | 12 ++- wgpu-hal/src/gles/mod.rs | 184 ++++------------------------------- 3 files changed, 205 insertions(+), 171 deletions(-) create mode 100644 wgpu-hal/src/gles/command.rs diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs new file mode 100644 index 0000000000..d7b506ae6b --- /dev/null +++ b/wgpu-hal/src/gles/command.rs @@ -0,0 +1,180 @@ +use super::Resource; //TEMP +use std::{mem, ops::Range}; + +impl crate::CommandEncoder for super::CommandEncoder { + unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { + Ok(()) + } + unsafe fn discard_encoding(&mut self) {} + unsafe fn end_encoding(&mut self) -> Result { + Ok(mem::take(&mut self.cmd_buffer)) + } + 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: &super::Buffer, range: crate::MemoryRange, value: u8) { + } + + unsafe fn copy_buffer_to_buffer( + &mut self, + src: &super::Buffer, + dst: &super::Buffer, + regions: T, + ) { + } + + unsafe fn copy_texture_to_texture( + &mut self, + src: &super::Texture, + src_usage: crate::TextureUse, + dst: &super::Texture, + regions: T, + ) { + } + + unsafe fn copy_buffer_to_texture( + &mut self, + src: &super::Buffer, + dst: &super::Texture, + regions: T, + ) { + } + + unsafe fn copy_texture_to_buffer( + &mut self, + src: &super::Texture, + src_usage: crate::TextureUse, + dst: &super::Buffer, + 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: &super::Buffer, + 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, super::Api>, + format: wgt::IndexFormat, + ) { + } + unsafe fn set_vertex_buffer<'a>( + &mut self, + index: u32, + binding: crate::BufferBinding<'a, super::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: &super::Buffer, + offset: wgt::BufferAddress, + draw_count: u32, + ) { + } + unsafe fn draw_indexed_indirect( + &mut self, + buffer: &super::Buffer, + offset: wgt::BufferAddress, + draw_count: u32, + ) { + } + unsafe fn draw_indirect_count( + &mut self, + buffer: &super::Buffer, + offset: wgt::BufferAddress, + count_buffer: &super::Buffer, + count_offset: wgt::BufferAddress, + max_count: u32, + ) { + } + unsafe fn draw_indexed_indirect_count( + &mut self, + buffer: &super::Buffer, + offset: wgt::BufferAddress, + count_buffer: &super::Buffer, + 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: &super::Buffer, offset: wgt::BufferAddress) {} +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 3ad0e88a75..5e4d7fa8bd 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1,4 +1,4 @@ -use super::{DeviceResult, Encoder, Resource}; //TEMP +use super::{DeviceResult, Resource}; //TEMP use glow::HasContext; use std::{convert::TryInto, ptr::NonNull}; @@ -229,7 +229,7 @@ impl crate::Device for super::Device { }, }) } - unsafe fn destroy_texture_view(&self, view: super::TextureView) {} + unsafe fn destroy_texture_view(&self, _view: super::TextureView) {} unsafe fn create_sampler( &self, @@ -251,10 +251,12 @@ impl crate::Device for super::Device { unsafe fn create_command_encoder( &self, desc: &crate::CommandEncoderDescriptor, - ) -> DeviceResult { - Ok(Encoder) + ) -> Result { + Ok(super::CommandEncoder { + cmd_buffer: super::CommandBuffer::default(), + }) } - unsafe fn destroy_command_encoder(&self, encoder: Encoder) {} + unsafe fn destroy_command_encoder(&self, _encoder: super::CommandEncoder) {} unsafe fn create_bind_group_layout( &self, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 557263d48a..d8d7a12b24 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -4,6 +4,7 @@ mod egl; mod adapter; +mod command; mod conv; mod device; @@ -12,12 +13,11 @@ use self::egl::{Instance, Surface}; use glow::HasContext; -use std::{ops::Range, sync::Arc}; +use std::sync::Arc; #[derive(Clone)] pub struct Api; pub struct Context; -pub struct Encoder; #[derive(Debug)] pub struct Resource; @@ -30,8 +30,8 @@ impl crate::Api for Api { type Device = Device; type Queue = Queue; - type CommandEncoder = Encoder; - type CommandBuffer = Resource; + type CommandEncoder = CommandEncoder; + type CommandBuffer = CommandBuffer; type Buffer = Buffer; type Texture = Texture; @@ -221,10 +221,23 @@ pub struct Sampler { raw: glow::Sampler, } +#[derive(Debug)] +enum Command {} + +#[derive(Default)] +pub struct CommandBuffer { + commands: Vec, + data: Vec, +} + +pub struct CommandEncoder { + cmd_buffer: CommandBuffer, +} + impl crate::Queue for Queue { unsafe fn submit( &mut self, - command_buffers: &[&Resource], + command_buffers: &[&CommandBuffer], signal_fence: Option<(&mut Resource, crate::FenceValue)>, ) -> DeviceResult<()> { Ok(()) @@ -237,164 +250,3 @@ impl crate::Queue for Queue { Ok(()) } } - -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: &Buffer, range: crate::MemoryRange, value: u8) {} - - unsafe fn copy_buffer_to_buffer(&mut self, src: &Buffer, dst: &Buffer, regions: T) {} - - unsafe fn copy_texture_to_texture( - &mut self, - src: &Texture, - src_usage: crate::TextureUse, - dst: &Texture, - regions: T, - ) { - } - - unsafe fn copy_buffer_to_texture(&mut self, src: &Buffer, dst: &Texture, regions: T) {} - - unsafe fn copy_texture_to_buffer( - &mut self, - src: &Texture, - src_usage: crate::TextureUse, - dst: &Buffer, - 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: &Buffer, - 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: &Buffer, - offset: wgt::BufferAddress, - draw_count: u32, - ) { - } - unsafe fn draw_indexed_indirect( - &mut self, - buffer: &Buffer, - offset: wgt::BufferAddress, - draw_count: u32, - ) { - } - unsafe fn draw_indirect_count( - &mut self, - buffer: &Buffer, - offset: wgt::BufferAddress, - count_buffer: &Buffer, - count_offset: wgt::BufferAddress, - max_count: u32, - ) { - } - unsafe fn draw_indexed_indirect_count( - &mut self, - buffer: &Buffer, - offset: wgt::BufferAddress, - count_buffer: &Buffer, - 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: &Buffer, offset: wgt::BufferAddress) {} -} From 4d42bef7f81f2ded1bc6f5c774af50d958bf8ef6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 22 Jun 2021 00:34:06 -0400 Subject: [PATCH 07/33] hal/gles: encoding copies and draws --- wgpu-hal/src/gles/command.rs | 181 ++++++++++++++++++++++++++++++----- wgpu-hal/src/gles/device.rs | 1 + wgpu-hal/src/gles/mod.rs | 99 ++++++++++++++++++- 3 files changed, 253 insertions(+), 28 deletions(-) diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index d7b506ae6b..989e44770f 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1,29 +1,46 @@ +use super::Command as C; use super::Resource; //TEMP use std::{mem, ops::Range}; +impl super::CommandBuffer { + fn clear(&mut self) { + self.label = None; + self.commands.clear(); + self.data.clear(); + } +} + impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { + self.cmd_buffer.label = label.map(str::to_string); Ok(()) } - unsafe fn discard_encoding(&mut self) {} + unsafe fn discard_encoding(&mut self) { + self.cmd_buffer.clear(); + } unsafe fn end_encoding(&mut self) -> Result { Ok(mem::take(&mut self.cmd_buffer)) } - unsafe fn reset_all(&mut self, command_buffers: I) {} + unsafe fn reset_all(&mut self, _command_buffers: I) {} - unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) + unsafe fn transition_buffers<'a, T>(&mut self, _barriers: T) where T: Iterator>, { } - unsafe fn transition_textures<'a, T>(&mut self, barriers: T) + unsafe fn transition_textures<'a, T>(&mut self, _barriers: T) where T: Iterator>, { } unsafe fn fill_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange, value: u8) { + self.cmd_buffer.commands.push(C::FillBuffer { + dst: buffer.raw, + range, + value, + }); } unsafe fn copy_buffer_to_buffer( @@ -31,16 +48,40 @@ impl crate::CommandEncoder for super::CommandEncoder { src: &super::Buffer, dst: &super::Buffer, regions: T, - ) { + ) where + T: Iterator, + { + for copy in regions { + self.cmd_buffer.commands.push(C::CopyBufferToBuffer { + src: src.raw, + src_target: src.target, + dst: dst.raw, + dst_target: dst.target, + copy, + }) + } } unsafe fn copy_texture_to_texture( &mut self, src: &super::Texture, - src_usage: crate::TextureUse, + _src_usage: crate::TextureUse, dst: &super::Texture, regions: T, - ) { + ) where + T: Iterator, + { + let (src_raw, src_target) = src.as_native(); + let (dst_raw, dst_target) = dst.as_native(); + for copy in regions { + self.cmd_buffer.commands.push(C::CopyTextureToTexture { + src: src_raw, + src_target: src_target, + dst: dst_raw, + dst_target: dst_target, + copy, + }) + } } unsafe fn copy_buffer_to_texture( @@ -48,16 +89,40 @@ impl crate::CommandEncoder for super::CommandEncoder { src: &super::Buffer, dst: &super::Texture, regions: T, - ) { + ) where + T: Iterator, + { + let (dst_raw, dst_target) = dst.as_native(); + for copy in regions { + self.cmd_buffer.commands.push(C::CopyBufferToTexture { + src: src.raw, + src_target: src.target, + dst: dst_raw, + dst_target: dst_target, + copy, + }) + } } unsafe fn copy_texture_to_buffer( &mut self, src: &super::Texture, - src_usage: crate::TextureUse, + _src_usage: crate::TextureUse, dst: &super::Buffer, regions: T, - ) { + ) where + T: Iterator, + { + let (src_raw, src_target) = src.as_native(); + for copy in regions { + self.cmd_buffer.commands.push(C::CopyTextureToBuffer { + src: src_raw, + src_target: src_target, + dst: dst.raw, + dst_target: dst.target, + copy, + }) + } } unsafe fn begin_query(&mut self, set: &Resource, index: u32) {} @@ -95,9 +160,17 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { } - 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 insert_debug_marker(&mut self, label: &str) { + let range = self.cmd_buffer.add_marker(label); + self.cmd_buffer.commands.push(C::InsertDebugMarker(range)); + } + unsafe fn begin_debug_marker(&mut self, group_label: &str) { + let range = self.cmd_buffer.add_marker(group_label); + self.cmd_buffer.commands.push(C::PushDebugGroup(range)); + } + unsafe fn end_debug_marker(&mut self) { + self.cmd_buffer.commands.push(C::PopDebugGroup); + } unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} @@ -106,6 +179,11 @@ impl crate::CommandEncoder for super::CommandEncoder { binding: crate::BufferBinding<'a, super::Api>, format: wgt::IndexFormat, ) { + self.state.index_offset = binding.offset; + self.state.index_format = format; + self.cmd_buffer + .commands + .push(C::SetIndexBuffer(binding.buffer.raw)); } unsafe fn set_vertex_buffer<'a>( &mut self, @@ -125,6 +203,13 @@ impl crate::CommandEncoder for super::CommandEncoder { start_instance: u32, instance_count: u32, ) { + debug_assert_eq!(start_instance, 0); + self.cmd_buffer.commands.push(C::Draw { + primitive: self.state.primitive, + start_vertex, + vertex_count, + instance_count, + }); } unsafe fn draw_indexed( &mut self, @@ -134,6 +219,20 @@ impl crate::CommandEncoder for super::CommandEncoder { start_instance: u32, instance_count: u32, ) { + debug_assert_eq!(start_instance, 0); + let (index_size, index_type) = match self.state.index_format { + wgt::IndexFormat::Uint16 => (2, glow::UNSIGNED_SHORT), + wgt::IndexFormat::Uint32 => (4, glow::UNSIGNED_INT), + }; + let index_offset = self.state.index_offset + index_size * start_index as wgt::BufferAddress; + self.cmd_buffer.commands.push(C::DrawIndexed { + primitive: self.state.primitive, + index_type, + index_offset, + index_count, + base_vertex, + instance_count, + }); } unsafe fn draw_indirect( &mut self, @@ -141,6 +240,15 @@ impl crate::CommandEncoder for super::CommandEncoder { offset: wgt::BufferAddress, draw_count: u32, ) { + for draw in 0..draw_count as wgt::BufferAddress { + let indirect_offset = + offset + draw * mem::size_of::() as wgt::BufferAddress; + self.cmd_buffer.commands.push(C::DrawIndirect { + primitive: self.state.primitive, + indirect_buf: buffer.raw, + indirect_offset, + }); + } } unsafe fn draw_indexed_indirect( &mut self, @@ -148,24 +256,40 @@ impl crate::CommandEncoder for super::CommandEncoder { offset: wgt::BufferAddress, draw_count: u32, ) { + let index_type = match self.state.index_format { + wgt::IndexFormat::Uint16 => glow::UNSIGNED_SHORT, + wgt::IndexFormat::Uint32 => glow::UNSIGNED_INT, + }; + for draw in 0..draw_count as wgt::BufferAddress { + let indirect_offset = offset + + draw * mem::size_of::() as wgt::BufferAddress; + self.cmd_buffer.commands.push(C::DrawIndexedIndirect { + primitive: self.state.primitive, + index_type, + indirect_buf: buffer.raw, + indirect_offset, + }); + } } unsafe fn draw_indirect_count( &mut self, - buffer: &super::Buffer, - offset: wgt::BufferAddress, - count_buffer: &super::Buffer, - count_offset: wgt::BufferAddress, - max_count: u32, + _buffer: &super::Buffer, + _offset: wgt::BufferAddress, + _count_buffer: &super::Buffer, + _count_offset: wgt::BufferAddress, + _max_count: u32, ) { + unimplemented!() } unsafe fn draw_indexed_indirect_count( &mut self, - buffer: &super::Buffer, - offset: wgt::BufferAddress, - count_buffer: &super::Buffer, - count_offset: wgt::BufferAddress, - max_count: u32, + _buffer: &super::Buffer, + _offset: wgt::BufferAddress, + _count_buffer: &super::Buffer, + _count_offset: wgt::BufferAddress, + _max_count: u32, ) { + unimplemented!() } // compute @@ -175,6 +299,13 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_compute_pipeline(&mut self, pipeline: &Resource) {} - unsafe fn dispatch(&mut self, count: [u32; 3]) {} - unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) {} + unsafe fn dispatch(&mut self, count: [u32; 3]) { + self.cmd_buffer.commands.push(C::Dispatch(count)); + } + unsafe fn dispatch_indirect(&mut self, buffer: &super::Buffer, offset: wgt::BufferAddress) { + self.cmd_buffer.commands.push(C::DispatchIndirect { + indirect_buf: buffer.raw, + indirect_offset: offset, + }); + } } diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 5e4d7fa8bd..4742ad54a6 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -254,6 +254,7 @@ impl crate::Device for super::Device { ) -> Result { Ok(super::CommandEncoder { cmd_buffer: super::CommandBuffer::default(), + state: super::CommandState::default(), }) } unsafe fn destroy_command_encoder(&self, _encoder: super::CommandEncoder) {} diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index d8d7a12b24..31ccbd18db 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -13,11 +13,10 @@ use self::egl::{Instance, Surface}; use glow::HasContext; -use std::sync::Arc; +use std::{ops::Range, sync::Arc}; #[derive(Clone)] pub struct Api; -pub struct Context; #[derive(Debug)] pub struct Resource; @@ -203,6 +202,15 @@ pub enum Texture { }, } +impl Texture { + fn as_native(&self) -> (glow::Texture, BindTarget) { + match *self { + Self::Renderbuffer { raw, .. } => panic!("Unexpected renderbuffer {}", raw), + Self::Texture { raw, target } => (raw, target), + } + } +} + #[derive(Debug)] pub enum TextureView { Renderbuffer { @@ -222,16 +230,101 @@ pub struct Sampler { } #[derive(Debug)] -enum Command {} +enum Command { + Draw { + primitive: u32, + start_vertex: u32, + vertex_count: u32, + instance_count: u32, + }, + DrawIndexed { + primitive: u32, + index_type: u32, + index_count: u32, + index_offset: wgt::BufferAddress, + base_vertex: i32, + instance_count: u32, + }, + DrawIndirect { + primitive: u32, + indirect_buf: glow::Buffer, + indirect_offset: wgt::BufferAddress, + }, + DrawIndexedIndirect { + primitive: u32, + index_type: u32, + indirect_buf: glow::Buffer, + indirect_offset: wgt::BufferAddress, + }, + Dispatch([u32; 3]), + DispatchIndirect { + indirect_buf: glow::Buffer, + indirect_offset: wgt::BufferAddress, + }, + FillBuffer { + dst: glow::Buffer, + range: crate::MemoryRange, + value: u8, + }, + CopyBufferToBuffer { + src: glow::Buffer, + src_target: BindTarget, + dst: glow::Buffer, + dst_target: BindTarget, + copy: crate::BufferCopy, + }, + CopyTextureToTexture { + src: glow::Texture, + src_target: BindTarget, + dst: glow::Texture, + dst_target: BindTarget, + copy: crate::TextureCopy, + }, + CopyBufferToTexture { + src: glow::Buffer, + src_target: BindTarget, + dst: glow::Texture, + dst_target: BindTarget, + copy: crate::BufferTextureCopy, + }, + CopyTextureToBuffer { + src: glow::Texture, + src_target: BindTarget, + dst: glow::Buffer, + dst_target: BindTarget, + copy: crate::BufferTextureCopy, + }, + SetIndexBuffer(glow::Buffer), + InsertDebugMarker(Range), + PushDebugGroup(Range), + PopDebugGroup, +} #[derive(Default)] pub struct CommandBuffer { + label: Option, commands: Vec, data: Vec, } +impl CommandBuffer { + fn add_marker(&mut self, marker: &str) -> Range { + let start = self.data.len() as u32; + self.data.extend(marker.as_bytes()); + start..self.data.len() as u32 + } +} + +#[derive(Default)] +struct CommandState { + primitive: u32, + index_format: wgt::IndexFormat, + index_offset: wgt::BufferAddress, +} + pub struct CommandEncoder { cmd_buffer: CommandBuffer, + state: CommandState, } impl crate::Queue for Queue { From b1fe86589a1fe98f287386b28c87959b4b9892e1 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 22 Jun 2021 01:56:27 -0400 Subject: [PATCH 08/33] hal/gles: queue module --- wgpu-hal/src/gles/adapter.rs | 1 + wgpu-hal/src/gles/command.rs | 10 +- wgpu-hal/src/gles/mod.rs | 31 ++---- wgpu-hal/src/gles/queue.rs | 188 +++++++++++++++++++++++++++++++++++ 4 files changed, 204 insertions(+), 26 deletions(-) create mode 100644 wgpu-hal/src/gles/queue.rs diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 2b87939c93..305f46cda8 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -285,6 +285,7 @@ impl crate::Adapter for super::Adapter { queue: super::Queue { shared: Arc::clone(&self.shared), features, + copy_fbo: gl.create_framebuffer().unwrap(), }, }) } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 989e44770f..dbf85c12f1 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -8,6 +8,12 @@ impl super::CommandBuffer { self.commands.clear(); self.data.clear(); } + + fn add_marker(&mut self, marker: &str) -> Range { + let start = self.data.len() as u32; + self.data.extend(marker.as_bytes()); + start..self.data.len() as u32 + } } impl crate::CommandEncoder for super::CommandEncoder { @@ -21,7 +27,9 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn end_encoding(&mut self) -> Result { Ok(mem::take(&mut self.cmd_buffer)) } - unsafe fn reset_all(&mut self, _command_buffers: I) {} + unsafe fn reset_all(&mut self, _command_buffers: I) { + //TODO: could re-use the allocations in all these command buffers + } unsafe fn transition_buffers<'a, T>(&mut self, _barriers: T) where diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 31ccbd18db..adcf238a18 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -7,6 +7,7 @@ mod adapter; mod command; mod conv; mod device; +mod queue; #[cfg(not(target_arch = "wasm32"))] use self::egl::{Instance, Surface}; @@ -181,6 +182,7 @@ pub struct Device { pub struct Queue { shared: Arc, features: wgt::Features, + copy_fbo: glow::Framebuffer, } #[derive(Debug)] @@ -307,14 +309,6 @@ pub struct CommandBuffer { data: Vec, } -impl CommandBuffer { - fn add_marker(&mut self, marker: &str) -> Range { - let start = self.data.len() as u32; - self.data.extend(marker.as_bytes()); - start..self.data.len() as u32 - } -} - #[derive(Default)] struct CommandState { primitive: u32, @@ -322,24 +316,11 @@ struct CommandState { index_offset: wgt::BufferAddress, } +//TODO: we would have something like `Arc` +// here and in the command buffers. So that everything grows +// inside the encoder and stays there until `reset_all`. + pub struct CommandEncoder { cmd_buffer: CommandBuffer, state: CommandState, } - -impl crate::Queue for Queue { - unsafe fn submit( - &mut self, - command_buffers: &[&CommandBuffer], - signal_fence: Option<(&mut Resource, crate::FenceValue)>, - ) -> DeviceResult<()> { - Ok(()) - } - unsafe fn present( - &mut self, - surface: &mut Surface, - texture: Texture, - ) -> Result<(), crate::SurfaceError> { - Ok(()) - } -} diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs new file mode 100644 index 0000000000..0cfacadedc --- /dev/null +++ b/wgpu-hal/src/gles/queue.rs @@ -0,0 +1,188 @@ +use super::Command as C; +use glow::HasContext; +use std::ops::Range; + +const DEBUG_ID: u32 = 0; + +fn extract_marker<'a>(data: &'a [u8], range: &Range) -> &'a str { + std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap() +} + +impl super::Queue { + unsafe fn process(&mut self, command: &C, data: &[u8]) { + let gl = &self.shared.context; + match *command { + C::Draw { + primitive, + start_vertex, + vertex_count, + instance_count, + } => { + if instance_count == 1 { + gl.draw_arrays(primitive, start_vertex as i32, vertex_count as i32); + } else { + gl.draw_arrays_instanced( + primitive, + start_vertex as i32, + vertex_count as i32, + instance_count as i32, + ); + } + } + C::DrawIndexed { + primitive, + index_type, + index_count, + index_offset, + base_vertex, + instance_count, + } => match (base_vertex, instance_count) { + (0, 1) => gl.draw_elements( + primitive, + index_count as i32, + index_type, + index_offset as i32, + ), + (0, _) => gl.draw_elements_instanced( + primitive, + index_count as i32, + index_type, + index_offset as i32, + instance_count as i32, + ), + (_, 1) => gl.draw_elements_base_vertex( + primitive, + index_count as i32, + index_type, + index_offset as i32, + base_vertex, + ), + (_, _) => gl.draw_elements_instanced_base_vertex( + primitive, + index_count as _, + index_type, + index_offset as i32, + instance_count as i32, + base_vertex, + ), + }, + C::DrawIndirect { + primitive: _, + indirect_buf, + indirect_offset: _, + } => { + gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); + //TODO: https://github.com/grovesNL/glow/issues/172 + //gl.draw_arrays_indirect(primitive, indirect_offset); + } + C::DrawIndexedIndirect { + primitive: _, + index_type: _, + indirect_buf, + indirect_offset: _, + } => { + gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); + //TODO: https://github.com/grovesNL/glow/issues/172 + } + C::Dispatch(group_counts) => { + gl.dispatch_compute(group_counts[0], group_counts[1], group_counts[2]); + } + C::DispatchIndirect { + indirect_buf, + indirect_offset, + } => { + gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); + gl.dispatch_compute_indirect(indirect_offset as i32); + } + C::FillBuffer { .. } => unimplemented!(), + C::CopyBufferToBuffer { + src, + src_target, + dst, + dst_target, + copy, + } => { + gl.bind_buffer(src_target, Some(src)); + gl.bind_buffer(dst_target, Some(dst)); + + gl.copy_buffer_sub_data( + src_target, + dst_target, + copy.src_offset as i32, + copy.dst_offset as i32, + copy.size.get() as i32, + ); + } + C::CopyTextureToTexture { + src, + src_target, + dst, + dst_target, + ref copy, + } => { + //TODO: bind src to self.copy_fbo + } + C::CopyBufferToTexture { + src, + src_target, + dst, + dst_target, + ref copy, + } => { + //TODO: bind src to self.copy_fbo + } + C::CopyTextureToBuffer { + src, + src_target, + dst, + dst_target, + ref copy, + } => { + //TODO: bind src to self.copy_fbo + } + C::SetIndexBuffer(buffer) => { + gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)); + } + C::InsertDebugMarker(ref range) => { + let marker = extract_marker(data, range); + gl.debug_message_insert( + glow::DEBUG_SOURCE_APPLICATION, + glow::DEBUG_TYPE_MARKER, + DEBUG_ID, + glow::DEBUG_SEVERITY_NOTIFICATION, + marker, + ); + } + C::PushDebugGroup(ref range) => { + let marker = extract_marker(data, range); + gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker); + } + C::PopDebugGroup => { + gl.pop_debug_group(); + } + } + } +} + +impl crate::Queue for super::Queue { + unsafe fn submit( + &mut self, + command_buffers: &[&super::CommandBuffer], + signal_fence: Option<(&mut super::Resource, crate::FenceValue)>, + ) -> Result<(), crate::DeviceError> { + for cmd_buf in command_buffers.iter() { + for command in cmd_buf.commands.iter() { + self.process(command, &cmd_buf.data); + } + } + Ok(()) + } + + unsafe fn present( + &mut self, + surface: &mut super::Surface, + texture: super::Texture, + ) -> Result<(), crate::SurfaceError> { + Ok(()) + } +} From 85e59c3d7fe18065b3095d42f0117f33750a029d Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 22 Jun 2021 21:22:52 -0400 Subject: [PATCH 09/33] hal/gles: texture copies --- wgpu-hal/src/gles/adapter.rs | 1 + wgpu-hal/src/gles/command.rs | 36 ++++++-- wgpu-hal/src/gles/device.rs | 161 ++++++++++++++++++----------------- wgpu-hal/src/gles/mod.rs | 21 ++++- wgpu-hal/src/gles/queue.rs | 128 +++++++++++++++++++++++++++- 5 files changed, 257 insertions(+), 90 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 305f46cda8..3c9a31cdc5 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -274,6 +274,7 @@ impl crate::Adapter for super::Adapter { ) -> Result, crate::DeviceError> { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); + gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1); let main_vao = gl.create_vertex_array().unwrap(); gl.bind_vertex_array(Some(main_vao)); diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index dbf85c12f1..b2e7fc8d97 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -79,14 +79,14 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - let (src_raw, src_target) = src.as_native(); - let (dst_raw, dst_target) = dst.as_native(); + let (src_raw, src_target) = src.inner.as_native(); + let (dst_raw, dst_target) = dst.inner.as_native(); for copy in regions { self.cmd_buffer.commands.push(C::CopyTextureToTexture { src: src_raw, - src_target: src_target, + src_target, dst: dst_raw, - dst_target: dst_target, + dst_target, copy, }) } @@ -100,13 +100,23 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - let (dst_raw, dst_target) = dst.as_native(); + assert_eq!( + dst.format_info.block_dimensions, + (1, 1), + "Compressed texture copies are TODO" + ); + let (dst_raw, dst_target) = dst.inner.as_native(); for copy in regions { self.cmd_buffer.commands.push(C::CopyBufferToTexture { src: src.raw, src_target: src.target, dst: dst_raw, - dst_target: dst_target, + dst_target, + dst_info: super::TextureCopyInfo { + external_format: dst.format_desc.tex_external, + data_type: dst.format_desc.data_type, + texel_size: dst.format_info.block_size, + }, copy, }) } @@ -121,11 +131,21 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - let (src_raw, src_target) = src.as_native(); + assert_eq!( + src.format_info.block_dimensions, + (1, 1), + "Compressed texture copies are TODO" + ); + let (src_raw, src_target) = src.inner.as_native(); for copy in regions { self.cmd_buffer.commands.push(C::CopyTextureToBuffer { src: src_raw, - src_target: src_target, + src_target, + src_info: super::TextureCopyInfo { + external_format: src.format_desc.tex_external, + data_type: src.format_desc.data_type, + texel_size: src.format_info.block_size, + }, dst: dst.raw, dst_target: dst.target, copy, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 4742ad54a6..97cb3f95f9 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -119,71 +119,46 @@ impl crate::Device for super::Device { | crate::TextureUse::DEPTH_STENCIL_WRITE | crate::TextureUse::DEPTH_STENCIL_READ; let format_desc = self.shared.describe_texture_format(desc.format); - Ok( - if render_usage.contains(desc.usage) - && desc.dimension == wgt::TextureDimension::D2 - && desc.size.depth_or_array_layers == 1 - { - let raw = gl.create_renderbuffer().unwrap(); - gl.bind_renderbuffer(glow::RENDERBUFFER, Some(raw)); - if desc.sample_count > 1 { - gl.renderbuffer_storage_multisample( - glow::RENDERBUFFER, - desc.sample_count as i32, - format_desc.tex_internal, - desc.size.width as i32, - desc.size.height as i32, - ); - } else { - gl.renderbuffer_storage( - glow::RENDERBUFFER, - format_desc.tex_internal, - desc.size.width as i32, - desc.size.height as i32, - ); - } - super::Texture::Renderbuffer { - raw, - aspects: desc.format.into(), - } + + let inner = if render_usage.contains(desc.usage) + && desc.dimension == wgt::TextureDimension::D2 + && desc.size.depth_or_array_layers == 1 + { + let raw = gl.create_renderbuffer().unwrap(); + gl.bind_renderbuffer(glow::RENDERBUFFER, Some(raw)); + if desc.sample_count > 1 { + gl.renderbuffer_storage_multisample( + glow::RENDERBUFFER, + desc.sample_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); } else { - let raw = gl.create_texture().unwrap(); - let target = match desc.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { - if desc.sample_count > 1 { - let target = glow::TEXTURE_2D; - gl.bind_texture(target, Some(raw)); - // https://github.com/grovesNL/glow/issues/169 - //gl.tex_storage_2d_multisample(target, desc.sample_count as i32, format_desc.tex_internal, desc.size.width as i32, desc.size.height as i32, true); - log::error!("TODO: support `tex_storage_2d_multisample` (https://github.com/grovesNL/glow/issues/169)"); - return Err(crate::DeviceError::Lost); - } else if desc.size.depth_or_array_layers > 1 { - let target = glow::TEXTURE_2D_ARRAY; - gl.bind_texture(target, Some(raw)); - gl.tex_storage_3d( - target, - desc.mip_level_count as i32, - format_desc.tex_internal, - desc.size.width as i32, - desc.size.height as i32, - desc.size.depth_or_array_layers as i32, - ); - target - } else { - let target = glow::TEXTURE_2D; - gl.bind_texture(target, Some(raw)); - gl.tex_storage_2d( - target, - desc.mip_level_count as i32, - format_desc.tex_internal, - desc.size.width as i32, - desc.size.height as i32, - ); - target - } - } - wgt::TextureDimension::D3 => { - let target = glow::TEXTURE_3D; + gl.renderbuffer_storage( + glow::RENDERBUFFER, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); + } + super::TextureInner::Renderbuffer { + raw, + aspects: desc.format.into(), + } + } else { + let raw = gl.create_texture().unwrap(); + let target = match desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { + if desc.sample_count > 1 { + let target = glow::TEXTURE_2D; + gl.bind_texture(target, Some(raw)); + // https://github.com/grovesNL/glow/issues/169 + //gl.tex_storage_2d_multisample(target, desc.sample_count as i32, format_desc.tex_internal, desc.size.width as i32, desc.size.height as i32, true); + log::error!("TODO: support `tex_storage_2d_multisample` (https://github.com/grovesNL/glow/issues/169)"); + return Err(crate::DeviceError::Lost); + } else if desc.size.depth_or_array_layers > 1 { + let target = glow::TEXTURE_2D_ARRAY; gl.bind_texture(target, Some(raw)); gl.tex_storage_3d( target, @@ -194,19 +169,49 @@ impl crate::Device for super::Device { desc.size.depth_or_array_layers as i32, ); target + } else { + let target = glow::TEXTURE_2D; + gl.bind_texture(target, Some(raw)); + gl.tex_storage_2d( + target, + desc.mip_level_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + ); + target } - }; - super::Texture::Texture { raw, target } - }, - ) + } + wgt::TextureDimension::D3 => { + let target = glow::TEXTURE_3D; + gl.bind_texture(target, Some(raw)); + gl.tex_storage_3d( + target, + desc.mip_level_count as i32, + format_desc.tex_internal, + desc.size.width as i32, + desc.size.height as i32, + desc.size.depth_or_array_layers as i32, + ); + target + } + }; + super::TextureInner::Texture { raw, target } + }; + + Ok(super::Texture { + inner, + format_desc, + format_info: desc.format.describe(), + }) } unsafe fn destroy_texture(&self, texture: super::Texture) { let gl = &self.shared.context; - match texture { - super::Texture::Renderbuffer { raw, .. } => { + match texture.inner { + super::TextureInner::Renderbuffer { raw, .. } => { gl.delete_renderbuffer(raw); } - super::Texture::Texture { raw, target } => { + super::TextureInner::Texture { raw, target } => { gl.delete_texture(raw); } } @@ -217,12 +222,14 @@ impl crate::Device for super::Device { texture: &super::Texture, desc: &crate::TextureViewDescriptor, ) -> Result { - Ok(match *texture { - super::Texture::Renderbuffer { raw, aspects } => super::TextureView::Renderbuffer { - raw, - aspects: aspects & crate::FormatAspect::from(desc.range.aspect), - }, - super::Texture::Texture { raw, target } => super::TextureView::Texture { + Ok(match texture.inner { + super::TextureInner::Renderbuffer { raw, aspects } => { + super::TextureView::Renderbuffer { + raw, + aspects: aspects & crate::FormatAspect::from(desc.range.aspect), + } + } + super::TextureInner::Texture { raw, target } => super::TextureView::Texture { raw, target, range: desc.range.clone(), diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index adcf238a18..a335a66ddd 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -157,6 +157,7 @@ enum VertexAttribKind { Double, // glVertexAttribLPointer } +#[derive(Debug)] struct FormatDescription { tex_internal: u32, tex_external: u32, @@ -193,7 +194,7 @@ pub struct Buffer { } #[derive(Debug)] -pub enum Texture { +enum TextureInner { Renderbuffer { raw: glow::Renderbuffer, aspects: crate::FormatAspect, @@ -204,7 +205,7 @@ pub enum Texture { }, } -impl Texture { +impl TextureInner { fn as_native(&self) -> (glow::Texture, BindTarget) { match *self { Self::Renderbuffer { raw, .. } => panic!("Unexpected renderbuffer {}", raw), @@ -213,6 +214,13 @@ impl Texture { } } +#[derive(Debug)] +pub struct Texture { + inner: TextureInner, + format_desc: FormatDescription, + format_info: wgt::TextureFormatInfo, +} + #[derive(Debug)] pub enum TextureView { Renderbuffer { @@ -231,6 +239,13 @@ pub struct Sampler { raw: glow::Sampler, } +#[derive(Debug)] +struct TextureCopyInfo { + external_format: u32, + data_type: u32, + texel_size: u8, +} + #[derive(Debug)] enum Command { Draw { @@ -287,11 +302,13 @@ enum Command { src_target: BindTarget, dst: glow::Texture, dst_target: BindTarget, + dst_info: TextureCopyInfo, copy: crate::BufferTextureCopy, }, CopyTextureToBuffer { src: glow::Texture, src_target: BindTarget, + src_info: TextureCopyInfo, dst: glow::Buffer, dst_target: BindTarget, copy: crate::BufferTextureCopy, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 0cfacadedc..25536dc250 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -8,6 +8,13 @@ fn extract_marker<'a>(data: &'a [u8], range: &Range) -> &'a str { std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap() } +fn is_3d_target(target: super::BindTarget) -> bool { + match target { + glow::TEXTURE_2D_ARRAY | glow::TEXTURE_3D => true, + _ => false, + } +} + impl super::Queue { unsafe fn process(&mut self, command: &C, data: &[u8]) { let gl = &self.shared.context; @@ -120,25 +127,140 @@ impl super::Queue { dst_target, ref copy, } => { - //TODO: bind src to self.copy_fbo + //TODO: how is depth handled? + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); + for layer in 0..copy.size.depth_or_array_layers as i32 { + if is_3d_target(src_target) { + //TODO: handle GLES without framebuffer_texture_3d + gl.framebuffer_texture_layer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + Some(src), + copy.src_base.mip_level as i32, + copy.src_base.origin.z as i32 + layer, + ); + } else { + gl.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + src_target, + Some(src), + copy.src_base.mip_level as i32, + ); + } + gl.bind_texture(dst_target, Some(dst)); + //TODO: https://github.com/grovesNL/glow/issues/173 + #[allow(clippy::if_same_then_else)] + if is_3d_target(dst_target) { + //gl.copy_tex_sub_image_3d(dst_target, copy.dst_base.mip_level, copy.dst_base.origin.x, copy.dst_base.origin.y, copy.dst_base.origin.z + layer, copy.src_base.origin.x, copy.src_base.origin.y, copy.size.width, copy.size.height); + } else { + //gl.copy_tex_sub_image_2d(dst_target, copy.dst_base.mip_level, copy.dst_base.origin.x, copy.dst_base.origin.y, copy.src_base.origin.x, copy.src_base.origin.y, copy.size.width, copy.size.height); + } + } } C::CopyBufferToTexture { src, src_target, dst, dst_target, + ref dst_info, ref copy, } => { - //TODO: bind src to self.copy_fbo + //TODO: compressed data + let row_texels = copy + .buffer_layout + .bytes_per_row + .map_or(0, |bpr| bpr.get() / dst_info.texel_size as u32); + let column_texels = copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get()); + gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32); + gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32); + gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(src)); + + let unpack_data = + glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32); + gl.bind_texture(dst_target, Some(dst)); + if is_3d_target(dst_target) { + gl.tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + dst_info.external_format, + dst_info.data_type, + unpack_data, + ); + } else { + gl.tex_sub_image_2d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + dst_info.external_format, + dst_info.data_type, + unpack_data, + ); + } } C::CopyTextureToBuffer { src, src_target, + ref src_info, dst, dst_target, ref copy, } => { - //TODO: bind src to self.copy_fbo + //TODO: compressed data + let row_texels = copy + .buffer_layout + .bytes_per_row + .map_or(copy.size.width, |bpr| { + bpr.get() / src_info.texel_size as u32 + }); + let column_texels = copy + .buffer_layout + .rows_per_image + .map_or(copy.size.height, |rpi| rpi.get()); + gl.pixel_store_i32(glow::PACK_ROW_LENGTH, row_texels as i32); + gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(dst)); + + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); + for layer in 0..copy.size.depth_or_array_layers { + let offset = copy.buffer_layout.offset as u32 + + layer * column_texels * row_texels * src_info.texel_size as u32; + if is_3d_target(src_target) { + //TODO: handle GLES without framebuffer_texture_3d + gl.framebuffer_texture_layer( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + Some(src), + copy.texture_base.mip_level as i32, + copy.texture_base.origin.z as i32 + layer as i32, + ); + } else { + gl.framebuffer_texture_2d( + glow::READ_FRAMEBUFFER, + glow::COLOR_ATTACHMENT0, + src_target, + Some(src), + copy.texture_base.mip_level as i32, + ); + } + gl.read_pixels( + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + src_info.external_format, + src_info.data_type, + glow::PixelPackData::BufferOffset(offset), + ); + } } C::SetIndexBuffer(buffer) => { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)); From d29c450ec36a4f0aa48cad3c98cf69de63e346dd Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 22 Jun 2021 23:50:39 -0400 Subject: [PATCH 10/33] hal/gles: bind group creation --- wgpu-core/src/device/mod.rs | 3 +- wgpu-hal/src/gles/command.rs | 6 +- wgpu-hal/src/gles/device.rs | 119 +++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/mod.rs | 54 ++++++++++++++- wgpu-hal/src/lib.rs | 5 ++ wgpu-hal/src/metal/device.rs | 5 +- wgpu-hal/src/metal/mod.rs | 2 +- wgpu-hal/src/vulkan/device.rs | 2 +- wgpu-hal/src/vulkan/mod.rs | 2 +- 9 files changed, 174 insertions(+), 24 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 50d5ae839f..7de5970bc2 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1035,7 +1035,8 @@ impl Device { })?; } - let hal_bindings = entry_map.values().cloned().collect::>(); + let mut hal_bindings = entry_map.values().cloned().collect::>(); + hal_bindings.sort_by_key(|b| b.binding); let hal_desc = hal::BindGroupLayoutDescriptor { label, entries: &hal_bindings, diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index b2e7fc8d97..525afe05be 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -173,15 +173,15 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_bind_group( &mut self, - layout: &Resource, + layout: &super::PipelineLayout, index: u32, - group: &Resource, + group: &super::BindGroup, dynamic_offsets: &[wgt::DynamicOffset], ) { } unsafe fn set_push_constants( &mut self, - layout: &Resource, + layout: &super::PipelineLayout, stages: wgt::ShaderStage, offset: u32, data: &[u32], diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 97cb3f95f9..404ba13037 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1,6 +1,6 @@ use super::{DeviceResult, Resource}; //TEMP use glow::HasContext; -use std::{convert::TryInto, ptr::NonNull}; +use std::{convert::TryInto, ptr::NonNull, sync::Arc}; impl crate::Device for super::Device { unsafe fn exit(self) { @@ -46,6 +46,7 @@ impl crate::Device for super::Device { Ok(super::Buffer { raw, target, + size: desc.size, map_flags, }) } @@ -269,24 +270,122 @@ impl crate::Device for super::Device { unsafe fn create_bind_group_layout( &self, desc: &crate::BindGroupLayoutDescriptor, - ) -> DeviceResult { - Ok(Resource) + ) -> Result { + Ok(super::BindGroupLayout { + entries: Arc::from(desc.entries), + }) } - unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {} + unsafe fn destroy_bind_group_layout(&self, _bg_layout: super::BindGroupLayout) {} + unsafe fn create_pipeline_layout( &self, desc: &crate::PipelineLayoutDescriptor, - ) -> DeviceResult { - Ok(Resource) + ) -> Result { + let mut group_infos = Vec::with_capacity(desc.bind_group_layouts.len()); + let mut num_samplers = 0u8; + let mut num_textures = 0u8; + let mut num_uniform_buffers = 0u8; + let mut num_storage_buffers = 0u8; + + for bg_layout in desc.bind_group_layouts { + // create a vector with the size enough to hold all the bindings, filled with `!0` + let mut binding_to_slot = vec![ + !0; + bg_layout + .entries + .last() + .map_or(0, |b| b.binding as usize + 1) + ] + .into_boxed_slice(); + + for entry in bg_layout.entries.iter() { + let counter = match entry.ty { + wgt::BindingType::Sampler { .. } => &mut num_samplers, + wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => { + &mut num_textures + } + wgt::BindingType::Buffer { + ty: wgt::BufferBindingType::Uniform, + .. + } => &mut num_uniform_buffers, + wgt::BindingType::Buffer { + ty: wgt::BufferBindingType::Storage { .. }, + .. + } => &mut num_storage_buffers, + }; + + binding_to_slot[entry.binding as usize] = *counter; + *counter += entry.count.map_or(1, |c| c.get() as u8); + } + + group_infos.push(super::BindGroupLayoutInfo { + entries: Arc::clone(&bg_layout.entries), + binding_to_slot, + }); + } + + Ok(super::PipelineLayout { + group_infos: group_infos.into_boxed_slice(), + }) } - unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {} + unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {} + unsafe fn create_bind_group( &self, desc: &crate::BindGroupDescriptor, - ) -> DeviceResult { - Ok(Resource) + ) -> Result { + let mut contents = Vec::new(); + + for (entry, layout) in desc.entries.iter().zip(desc.layout.entries.iter()) { + let binding = match layout.ty { + wgt::BindingType::Buffer { ty, .. } => { + let bb = &desc.buffers[entry.resource_index as usize]; + let register = match ty { + wgt::BufferBindingType::Uniform => super::BindingRegister::UniformBuffers, + wgt::BufferBindingType::Storage { .. } => { + super::BindingRegister::StorageBuffers + } + }; + super::RawBinding::Buffer { + register, + raw: bb.buffer.raw, + offset: bb.offset as i32, + size: match bb.size { + Some(s) => s.get() as i32, + None => (bb.buffer.size - bb.offset) as i32, + }, + } + } + wgt::BindingType::Sampler { .. } => { + let sampler = desc.samplers[entry.resource_index as usize]; + super::RawBinding::Sampler(sampler.raw) + } + wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => { + match *desc.textures[entry.resource_index as usize].view { + super::TextureView::Renderbuffer { .. } => { + panic!("Unable to use a renderbuffer in a group") + } + super::TextureView::Texture { + raw, + target, + ref range, + } => super::RawBinding::Texture { + raw, + target, + range: range.clone(), + }, + } + } + }; + contents.push(binding); + } + + Ok(super::BindGroup { + layout_entries: Arc::clone(&desc.layout.entries), + contents: contents.into_boxed_slice(), + }) } - unsafe fn destroy_bind_group(&self, group: Resource) {} + unsafe fn destroy_bind_group(&self, _group: super::BindGroup) {} unsafe fn create_shader_module( &self, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index a335a66ddd..0e5bed313c 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -41,9 +41,9 @@ impl crate::Api for Api { type QuerySet = Resource; type Fence = Resource; - type BindGroupLayout = Resource; - type BindGroup = Resource; - type PipelineLayout = Resource; + type BindGroupLayout = BindGroupLayout; + type BindGroup = BindGroup; + type PipelineLayout = PipelineLayout; type ShaderModule = Resource; type RenderPipeline = Resource; type ComputePipeline = Resource; @@ -190,6 +190,7 @@ pub struct Queue { pub struct Buffer { raw: glow::Buffer, target: BindTarget, + size: wgt::BufferAddress, map_flags: u32, } @@ -239,6 +240,53 @@ pub struct Sampler { raw: glow::Sampler, } +pub struct BindGroupLayout { + entries: Arc<[wgt::BindGroupLayoutEntry]>, +} + +struct BindGroupLayoutInfo { + entries: Arc<[wgt::BindGroupLayoutEntry]>, + /// Mapping of resources, indexed by `binding`, into the whole layout space. + /// For texture resources, the value is the texture slot index. + /// For sampler resources, the value is the index of the sampler in the whole layout. + /// For buffers, the value is the uniform or storage slot index. + /// For unused bindings, the value is `!0` + binding_to_slot: Box<[u8]>, +} + +pub struct PipelineLayout { + group_infos: Box<[BindGroupLayoutInfo]>, +} + +#[derive(Debug)] +enum BindingRegister { + Textures, + UniformBuffers, + StorageBuffers, +} + +#[derive(Debug)] +enum RawBinding { + Buffer { + register: BindingRegister, + raw: glow::Buffer, + offset: i32, + size: i32, + }, + Texture { + raw: glow::Texture, + target: BindTarget, + range: wgt::ImageSubresourceRange, + }, + Sampler(glow::Sampler), +} + +#[derive(Debug)] +pub struct BindGroup { + layout_entries: Arc<[wgt::BindGroupLayoutEntry]>, + contents: Box<[RawBinding]>, +} + #[derive(Debug)] struct TextureCopyInfo { external_format: u32, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index df37f55403..70adcff4a4 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -238,6 +238,7 @@ pub trait Device: Send + Sync { ) -> Result; unsafe fn destroy_command_encoder(&self, pool: A::CommandEncoder); + /// Creates a bind group layout. unsafe fn create_bind_group_layout( &self, desc: &BindGroupLayoutDescriptor, @@ -753,6 +754,10 @@ pub struct SamplerDescriptor<'a> { pub border_color: Option, } +/// BindGroupLayout descriptor. +/// +/// Valid usage: +/// - `entries` are sorted by ascending `wgt::BindGroupLayoutEntry::binding` #[derive(Clone, Debug)] pub struct BindGroupLayoutDescriptor<'a> { pub label: Label<'a>, diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 4d02f94564..c105aee316 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -363,11 +363,8 @@ impl crate::Device for super::Device { &self, desc: &crate::BindGroupLayoutDescriptor, ) -> DeviceResult { - let mut map = desc.entries.to_vec(); - map.sort_by_key(|e| e.binding); - Ok(super::BindGroupLayout { - entries: Arc::new(map), + entries: Arc::from(desc.entries), }) } unsafe fn destroy_bind_group_layout(&self, _bg_layout: super::BindGroupLayout) {} diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index bb0720ae9c..0a4f1b545e 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -412,7 +412,7 @@ impl Sampler { #[derive(Debug)] pub struct BindGroupLayout { /// Sorted list of BGL entries. - entries: Arc>, + entries: Arc<[wgt::BindGroupLayoutEntry]>, } #[derive(Clone, Debug, Default)] diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 3248921d2c..5574dca7f9 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -937,7 +937,7 @@ impl crate::Device for super::Device { Ok(super::BindGroupLayout { raw, desc_count, - types, + types: types.into_boxed_slice(), }) } unsafe fn destroy_bind_group_layout(&self, bg_layout: super::BindGroupLayout) { diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index ffc6d66c61..a235c115d0 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -271,7 +271,7 @@ pub struct Sampler { pub struct BindGroupLayout { raw: vk::DescriptorSetLayout, desc_count: gpu_descriptor::DescriptorTotalCount, - types: Vec<(vk::DescriptorType, u32)>, + types: Box<[(vk::DescriptorType, u32)]>, } #[derive(Debug)] From d3d2ed5a9e395c903f9e90fee27a648c1e2358ee Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 23 Jun 2021 01:40:02 -0400 Subject: [PATCH 11/33] hal/gles: pipeline creation --- wgpu-hal/src/gles/adapter.rs | 9 + wgpu-hal/src/gles/command.rs | 20 +- wgpu-hal/src/gles/conv.rs | 237 ++++++++++-------------- wgpu-hal/src/gles/device.rs | 345 ++++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/egl.rs | 4 +- wgpu-hal/src/gles/mod.rs | 91 +++++++-- wgpu-hal/src/gles/queue.rs | 22 +-- wgpu-hal/src/lib.rs | 9 +- wgpu-hal/src/metal/device.rs | 6 +- wgpu-hal/src/metal/mod.rs | 2 +- 10 files changed, 539 insertions(+), 206 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 3c9a31cdc5..d2c22d6c4a 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -169,6 +169,14 @@ impl super::Adapter { let extensions = gl.supported_extensions(); log::info!("Extensions: {:?}", extensions); + let shading_language_version = { + let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION); + log::info!("SL version: {}", sl_version); + let (sl_major, sl_minor) = Self::parse_version(&version).ok()?; + let value = (sl_major * 100 + sl_minor * 10) as u16; + naga::back::glsl::Version::Embedded(value) + }; + let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE; features.set( wgt::Features::DEPTH_CLAMPING, @@ -240,6 +248,7 @@ impl super::Adapter { shared: Arc::new(super::AdapterShared { context: gl, private_caps, + shading_language_version, }), }, info: Self::make_info(vendor, renderer), diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 525afe05be..b4ca8c0acb 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1,5 +1,5 @@ -use super::Command as C; use super::Resource; //TEMP +use super::{conv, Command as C}; use std::{mem, ops::Range}; impl super::CommandBuffer { @@ -113,7 +113,7 @@ impl crate::CommandEncoder for super::CommandEncoder { dst: dst_raw, dst_target, dst_info: super::TextureCopyInfo { - external_format: dst.format_desc.tex_external, + external_format: dst.format_desc.external, data_type: dst.format_desc.data_type, texel_size: dst.format_info.block_size, }, @@ -142,7 +142,7 @@ impl crate::CommandEncoder for super::CommandEncoder { src: src_raw, src_target, src_info: super::TextureCopyInfo { - external_format: src.format_desc.tex_external, + external_format: src.format_desc.external, data_type: src.format_desc.data_type, texel_size: src.format_info.block_size, }, @@ -200,7 +200,9 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::PopDebugGroup); } - unsafe fn set_render_pipeline(&mut self, pipeline: &Resource) {} + unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { + self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); + } unsafe fn set_index_buffer<'a>( &mut self, @@ -233,7 +235,7 @@ impl crate::CommandEncoder for super::CommandEncoder { ) { debug_assert_eq!(start_instance, 0); self.cmd_buffer.commands.push(C::Draw { - primitive: self.state.primitive, + topology: self.state.topology, start_vertex, vertex_count, instance_count, @@ -254,7 +256,7 @@ impl crate::CommandEncoder for super::CommandEncoder { }; let index_offset = self.state.index_offset + index_size * start_index as wgt::BufferAddress; self.cmd_buffer.commands.push(C::DrawIndexed { - primitive: self.state.primitive, + topology: self.state.topology, index_type, index_offset, index_count, @@ -272,7 +274,7 @@ impl crate::CommandEncoder for super::CommandEncoder { let indirect_offset = offset + draw * mem::size_of::() as wgt::BufferAddress; self.cmd_buffer.commands.push(C::DrawIndirect { - primitive: self.state.primitive, + topology: self.state.topology, indirect_buf: buffer.raw, indirect_offset, }); @@ -292,7 +294,7 @@ impl crate::CommandEncoder for super::CommandEncoder { let indirect_offset = offset + draw * mem::size_of::() as wgt::BufferAddress; self.cmd_buffer.commands.push(C::DrawIndexedIndirect { - primitive: self.state.primitive, + topology: self.state.topology, index_type, indirect_buf: buffer.raw, indirect_offset, @@ -325,7 +327,7 @@ impl crate::CommandEncoder for super::CommandEncoder { 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 set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} unsafe fn dispatch(&mut self, count: [u32; 3]) { self.cmd_buffer.commands.push(C::Dispatch(count)); diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index ba89e26b8e..1f3a2a2e7e 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -1,163 +1,64 @@ impl super::AdapterShared { pub(super) fn describe_texture_format( &self, - format: wgt::TextureFormat, - ) -> super::FormatDescription { - use super::VertexAttribKind as Vak; + texture_format: wgt::TextureFormat, + ) -> super::TextureFormatDesc { use wgt::TextureFormat as Tf; - let (tex_internal, tex_external, data_type, num_components, va_kind) = match format { - Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE, 1, Vak::Float), - Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE, 1, Vak::Float), - Tf::R8Uint => ( - glow::R8UI, - glow::RED_INTEGER, - glow::UNSIGNED_BYTE, - 1, - Vak::Integer, - ), - Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE, 1, Vak::Integer), - Tf::R16Uint => ( - glow::R16UI, - glow::RED_INTEGER, - glow::UNSIGNED_SHORT, - 1, - Vak::Integer, - ), - Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT, 1, Vak::Integer), - Tf::R16Float => (glow::R16F, glow::RED, glow::UNSIGNED_SHORT, 1, Vak::Float), - Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE, 2, Vak::Float), - Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE, 2, Vak::Float), - Tf::Rg8Uint => ( - glow::RG8UI, - glow::RG_INTEGER, - glow::UNSIGNED_BYTE, - 2, - Vak::Integer, - ), - Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE, 2, Vak::Integer), - Tf::R32Uint => ( - glow::R32UI, - glow::RED_INTEGER, - glow::UNSIGNED_INT, - 1, - Vak::Integer, - ), - Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT, 1, Vak::Integer), - Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT, 1, Vak::Float), - Tf::Rg16Uint => ( - glow::RG16UI, - glow::RG_INTEGER, - glow::UNSIGNED_SHORT, - 2, - Vak::Integer, - ), - Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT, 2, Vak::Integer), - Tf::Rg16Float => (glow::RG16F, glow::RG, glow::UNSIGNED_SHORT, 2, Vak::Float), - Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE, 4, Vak::Float), - Tf::Rgba8UnormSrgb => ( - glow::SRGB8_ALPHA8, - glow::RGBA, - glow::UNSIGNED_BYTE, - 4, - Vak::Float, - ), - Tf::Bgra8UnormSrgb => ( - glow::SRGB8_ALPHA8, - glow::RGBA, - glow::UNSIGNED_BYTE, - 4, - Vak::Float, - ), //TODO? - Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE, 4, Vak::Float), - Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE, 4, Vak::Float), - Tf::Rgba8Uint => ( - glow::RGBA8UI, - glow::RGBA_INTEGER, - glow::UNSIGNED_BYTE, - 4, - Vak::Integer, - ), - Tf::Rgba8Sint => ( - glow::RGBA8I, - glow::RGBA_INTEGER, - glow::BYTE, - 4, - Vak::Integer, - ), + let (internal, external, data_type) = match texture_format { + Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE), + Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE), + Tf::R8Uint => (glow::R8UI, glow::RED_INTEGER, glow::UNSIGNED_BYTE), + Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE), + Tf::R16Uint => (glow::R16UI, glow::RED_INTEGER, glow::UNSIGNED_SHORT), + Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT), + Tf::R16Float => (glow::R16F, glow::RED, glow::HALF_FLOAT), + Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE), + Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE), + Tf::Rg8Uint => (glow::RG8UI, glow::RG_INTEGER, glow::UNSIGNED_BYTE), + Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE), + Tf::R32Uint => (glow::R32UI, glow::RED_INTEGER, glow::UNSIGNED_INT), + Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT), + Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT), + Tf::Rg16Uint => (glow::RG16UI, glow::RG_INTEGER, glow::UNSIGNED_SHORT), + Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT), + Tf::Rg16Float => (glow::RG16F, glow::RG, glow::HALF_FLOAT), + Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE), + Tf::Rgba8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE), + Tf::Bgra8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE), //TODO? + Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE), + Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE), + Tf::Rgba8Uint => (glow::RGBA8UI, glow::RGBA_INTEGER, glow::UNSIGNED_BYTE), + Tf::Rgba8Sint => (glow::RGBA8I, glow::RGBA_INTEGER, glow::BYTE), Tf::Rgb10a2Unorm => ( glow::RGB10_A2, glow::RGBA, glow::UNSIGNED_INT_2_10_10_10_REV, - 1, - Vak::Integer, ), Tf::Rg11b10Float => ( glow::R11F_G11F_B10F, glow::RGB, glow::UNSIGNED_INT_10F_11F_11F_REV, - 1, - Vak::Integer, - ), - Tf::Rg32Uint => ( - glow::RG32UI, - glow::RG_INTEGER, - glow::UNSIGNED_INT, - 2, - Vak::Integer, - ), - Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT, 2, Vak::Integer), - Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT, 2, Vak::Float), - Tf::Rgba16Uint => ( - glow::RGBA16UI, - glow::RGBA_INTEGER, - glow::UNSIGNED_SHORT, - 4, - Vak::Integer, - ), - Tf::Rgba16Sint => ( - glow::RGBA16I, - glow::RGBA_INTEGER, - glow::SHORT, - 4, - Vak::Integer, - ), - Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::UNSIGNED_SHORT, 4, Vak::Float), - Tf::Rgba32Uint => ( - glow::RGBA32UI, - glow::RGBA_INTEGER, - glow::UNSIGNED_INT, - 4, - Vak::Integer, - ), - Tf::Rgba32Sint => ( - glow::RGBA32I, - glow::RGBA_INTEGER, - glow::INT, - 4, - Vak::Integer, - ), - Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT, 4, Vak::Float), - Tf::Depth32Float => ( - glow::DEPTH_COMPONENT32F, - glow::DEPTH_COMPONENT, - glow::FLOAT, - 1, - Vak::Float, ), + Tf::Rg32Uint => (glow::RG32UI, glow::RG_INTEGER, glow::UNSIGNED_INT), + Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT), + Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT), + Tf::Rgba16Uint => (glow::RGBA16UI, glow::RGBA_INTEGER, glow::UNSIGNED_SHORT), + Tf::Rgba16Sint => (glow::RGBA16I, glow::RGBA_INTEGER, glow::SHORT), + Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::HALF_FLOAT), + Tf::Rgba32Uint => (glow::RGBA32UI, glow::RGBA_INTEGER, glow::UNSIGNED_INT), + Tf::Rgba32Sint => (glow::RGBA32I, glow::RGBA_INTEGER, glow::INT), + Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT), + Tf::Depth32Float => (glow::DEPTH_COMPONENT32F, glow::DEPTH_COMPONENT, glow::FLOAT), Tf::Depth24Plus => ( glow::DEPTH_COMPONENT24, glow::DEPTH_COMPONENT, glow::UNSIGNED_NORMALIZED, - 2, - Vak::Float, ), Tf::Depth24PlusStencil8 => ( glow::DEPTH24_STENCIL8, glow::DEPTH_COMPONENT, glow::UNSIGNED_INT, - 2, - Vak::Float, ), Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb @@ -211,16 +112,59 @@ impl super::AdapterShared { | Tf::Astc12x12RgbaUnormSrgb => unimplemented!(), }; - super::FormatDescription { - tex_internal, - tex_external, + super::TextureFormatDesc { + internal, + external, data_type, - num_components, - va_kind, } } } +pub(super) fn describe_vertex_format(vertex_format: wgt::VertexFormat) -> super::VertexFormatDesc { + use super::VertexAttribKind as Vak; + use wgt::VertexFormat as Vf; + + let (element_count, element_format, attrib_kind) = match vertex_format { + Vf::Unorm8x2 => (2, glow::UNSIGNED_BYTE, Vak::Float), + Vf::Snorm8x2 => (2, glow::BYTE, Vak::Float), + Vf::Uint8x2 => (2, glow::UNSIGNED_BYTE, Vak::Integer), + Vf::Sint8x2 => (2, glow::BYTE, Vak::Integer), + Vf::Unorm8x4 => (4, glow::UNSIGNED_BYTE, Vak::Float), + Vf::Snorm8x4 => (4, glow::BYTE, Vak::Float), + Vf::Uint8x4 => (4, glow::UNSIGNED_BYTE, Vak::Integer), + Vf::Sint8x4 => (4, glow::BYTE, Vak::Integer), + Vf::Unorm16x2 => (2, glow::UNSIGNED_SHORT, Vak::Float), + Vf::Snorm16x2 => (2, glow::SHORT, Vak::Float), + Vf::Uint16x2 => (2, glow::UNSIGNED_SHORT, Vak::Integer), + Vf::Sint16x2 => (2, glow::SHORT, Vak::Integer), + Vf::Float16x2 => (2, glow::HALF_FLOAT, Vak::Float), + Vf::Unorm16x4 => (4, glow::UNSIGNED_SHORT, Vak::Float), + Vf::Snorm16x4 => (4, glow::SHORT, Vak::Float), + Vf::Uint16x4 => (4, glow::UNSIGNED_SHORT, Vak::Integer), + Vf::Sint16x4 => (4, glow::SHORT, Vak::Integer), + Vf::Float16x4 => (4, glow::HALF_FLOAT, Vak::Float), + Vf::Uint32 => (1, glow::UNSIGNED_INT, Vak::Integer), + Vf::Sint32 => (1, glow::INT, Vak::Integer), + Vf::Float32 => (1, glow::FLOAT, Vak::Float), + Vf::Uint32x2 => (2, glow::UNSIGNED_INT, Vak::Integer), + Vf::Sint32x2 => (2, glow::INT, Vak::Integer), + Vf::Float32x2 => (2, glow::FLOAT, Vak::Float), + Vf::Uint32x3 => (3, glow::UNSIGNED_INT, Vak::Integer), + Vf::Sint32x3 => (3, glow::INT, Vak::Integer), + Vf::Float32x3 => (3, glow::FLOAT, Vak::Float), + Vf::Uint32x4 => (4, glow::UNSIGNED_INT, Vak::Integer), + Vf::Sint32x4 => (4, glow::INT, Vak::Integer), + Vf::Float32x4 => (4, glow::FLOAT, Vak::Float), + Vf::Float64 | Vf::Float64x2 | Vf::Float64x3 | Vf::Float64x4 => unimplemented!(), + }; + + super::VertexFormatDesc { + element_count, + element_format, + attrib_kind, + } +} + pub fn map_filter_modes( min: wgt::FilterMode, mag: wgt::FilterMode, @@ -266,3 +210,14 @@ pub fn map_compare_func(fun: wgt::CompareFunction) -> u32 { Cf::Always => glow::ALWAYS, } } + +pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 { + use wgt::PrimitiveTopology as Pt; + match topology { + Pt::PointList => glow::POINTS, + Pt::LineList => glow::LINES, + Pt::LineStrip => glow::LINE_STRIP, + Pt::TriangleList => glow::TRIANGLES, + Pt::TriangleStrip => glow::TRIANGLE_STRIP, + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 404ba13037..56f39feb35 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1,6 +1,259 @@ -use super::{DeviceResult, Resource}; //TEMP +use super::conv; +use super::Resource; //TEMP +use crate::util::map_naga_stage; use glow::HasContext; -use std::{convert::TryInto, ptr::NonNull, sync::Arc}; +use std::{convert::TryInto, iter, ptr::NonNull, sync::Arc}; + +type ShaderStage<'a> = ( + naga::ShaderStage, + &'a crate::ProgrammableStage<'a, super::Api>, +); +type NameBindingMap = fxhash::FxHashMap; + +struct CompilationContext<'a> { + layout: &'a super::PipelineLayout, + sampler_map: &'a mut super::SamplerBindMap, + name_binding_map: &'a mut NameBindingMap, +} + +impl CompilationContext<'_> { + fn consume_reflection( + self, + module: &naga::Module, + ep_info: &naga::valid::FunctionInfo, + reflection_info: naga::back::glsl::ReflectionInfo, + ) { + for (handle, var) in module.global_variables.iter() { + if ep_info[handle].is_empty() { + continue; + } + let register = match var.class { + naga::StorageClass::Uniform => super::BindingRegister::UniformBuffers, + naga::StorageClass::Storage => super::BindingRegister::StorageBuffers, + _ => continue, + }; + //TODO: make Naga reflect all the names, not just textures + let br = var.binding.as_ref().unwrap(); + let slot = self.layout.get_slot(br); + + let name = reflection_info.uniforms[&handle].clone(); + log::debug!("Rebind buffer: {:?} -> {}", var.name.as_ref(), &name); + self.name_binding_map.insert(name, (register, slot)); + } + + for (name, mapping) in reflection_info.texture_mapping { + let tex_br = module.global_variables[mapping.texture] + .binding + .as_ref() + .unwrap(); + let texture_linear_index = self.layout.get_slot(tex_br); + + self.name_binding_map.insert( + name, + (super::BindingRegister::Textures, texture_linear_index), + ); + if let Some(sampler_handle) = mapping.sampler { + let sam_br = module.global_variables[sampler_handle] + .binding + .as_ref() + .unwrap(); + let sampler_linear_index = self.layout.get_slot(sam_br); + self.sampler_map[texture_linear_index as usize] = Some(sampler_linear_index); + } + } + } +} + +impl super::Device { + unsafe fn compile_shader( + &self, + shader: &str, + naga_stage: naga::ShaderStage, + ) -> Result { + let gl = &self.shared.context; + let target = match naga_stage { + naga::ShaderStage::Vertex => glow::VERTEX_SHADER, + naga::ShaderStage::Fragment => glow::FRAGMENT_SHADER, + naga::ShaderStage::Compute => glow::COMPUTE_SHADER, + }; + + let raw = gl.create_shader(target).unwrap(); + gl.shader_source(raw, shader); + gl.compile_shader(raw); + + log::info!("\tCompiled shader {:?}", raw); + + let compiled_ok = gl.get_shader_compile_status(raw); + let msg = gl.get_shader_info_log(raw); + if compiled_ok { + if !msg.is_empty() { + log::warn!("\tCompile: {}", msg); + } + Ok(raw) + } else { + Err(crate::PipelineError::Linkage( + map_naga_stage(naga_stage), + msg, + )) + } + } + + fn create_shader( + &self, + naga_stage: naga::ShaderStage, + stage: &crate::ProgrammableStage, + context: CompilationContext, + ) -> Result { + use naga::back::glsl; + let options = glsl::Options { + version: self.shared.shading_language_version, + shader_stage: naga_stage, + entry_point: stage.entry_point.to_string(), + }; + + let shader = &stage.module.naga; + let entry_point_index = (&shader.module.entry_points) + .into_iter() + .position(|ep| ep.name.as_str() == stage.entry_point) + .ok_or(crate::PipelineError::EntryPoint(naga_stage))?; + + let mut output = String::new(); + let mut writer = glsl::Writer::new(&mut output, &shader.module, &shader.info, &options) + .map_err(|e| { + let msg = format!("{}", e); + crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg) + })?; + + let reflection_info = writer.write().map_err(|e| { + let msg = format!("{}", e); + crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg) + })?; + + log::debug!("Naga generated shader:\n{}", output); + + context.consume_reflection( + &shader.module, + shader.info.get_entry_point(entry_point_index), + reflection_info, + ); + + unsafe { self.compile_shader(&output, naga_stage) } + } + + unsafe fn create_pipeline<'a, I: Iterator>>( + &self, + shaders: I, + layout: &super::PipelineLayout, + ) -> Result { + let gl = &self.shared.context; + let program = gl.create_program().unwrap(); + + let mut name_binding_map = NameBindingMap::default(); + let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS]; + let mut has_stages = wgt::ShaderStage::empty(); + let mut shaders_to_delete = arrayvec::ArrayVec::<[_; 3]>::new(); + + for (naga_stage, stage) in shaders { + has_stages |= map_naga_stage(naga_stage); + let context = CompilationContext { + layout, + sampler_map: &mut sampler_map, + name_binding_map: &mut name_binding_map, + }; + + let shader = self.create_shader(naga_stage, stage, context)?; + shaders_to_delete.push(shader); + } + + // Create empty fragment shader if only vertex shader is present + if has_stages == wgt::ShaderStage::VERTEX { + let version = match self.shared.shading_language_version { + naga::back::glsl::Version::Embedded(v) => v, + naga::back::glsl::Version::Desktop(_) => unreachable!(), + }; + let shader_src = format!("#version {} es \n void main(void) {{}}", version,); + log::info!("Only vertex shader is present. Creating an empty fragment shader",); + let shader = self.compile_shader(&shader_src, naga::ShaderStage::Fragment)?; + shaders_to_delete.push(shader); + } + + for &shader in shaders_to_delete.iter() { + gl.attach_shader(program, shader); + } + gl.link_program(program); + + for shader in shaders_to_delete { + gl.delete_shader(shader); + } + + log::info!("\tLinked program {:?}", program); + + let linked_ok = gl.get_program_link_status(program); + let msg = gl.get_program_info_log(program); + if !linked_ok { + return Err(crate::PipelineError::Linkage(has_stages, msg)); + } + if !msg.is_empty() { + log::warn!("\tLink: {}", msg); + } + + if !self + .shared + .private_caps + .contains(super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER) + { + gl.use_program(Some(program)); + for (ref name, (register, slot)) in name_binding_map { + log::trace!("Get binding {:?} from program {:?}", name, program); + match register { + super::BindingRegister::Textures => { + let loc = gl.get_uniform_location(program, name).unwrap(); + gl.uniform_1_i32(Some(&loc), slot as _); + } + super::BindingRegister::UniformBuffers => { + let index = gl.get_uniform_block_index(program, name).unwrap(); + gl.uniform_block_binding(program, index, slot as _); + } + super::BindingRegister::StorageBuffers => { + let index = gl.get_shader_storage_block_index(program, name).unwrap(); + gl.shader_storage_block_binding(program, index, slot as _); + } + } + } + } + + let uniforms = { + let count = gl.get_active_uniforms(program); + let mut offset = 0; + let mut uniforms = Vec::new(); + + for uniform in 0..count { + let glow::ActiveUniform { size, utype, name } = + gl.get_active_uniform(program, uniform).unwrap(); + + if let Some(location) = gl.get_uniform_location(program, &name) { + // Sampler2D won't show up in UniformLocation and the only other uniforms + // should be push constants + uniforms.push(super::UniformDesc { + location, + offset, + utype, + }); + + offset += size as u32; + } + } + + uniforms.into_boxed_slice() + }; + + Ok(super::PipelineInner { + program, + sampler_map, + uniforms, + }) + } +} impl crate::Device for super::Device { unsafe fn exit(self) { @@ -76,7 +329,7 @@ impl crate::Device for super::Device { is_coherent: buffer.map_flags & glow::MAP_COHERENT_BIT != 0, }) } - unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> DeviceResult<()> { + unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { let gl = &self.shared.context; gl.bind_buffer(buffer.target, Some(buffer.raw)); gl.unmap_buffer(buffer.target); @@ -131,14 +384,14 @@ impl crate::Device for super::Device { gl.renderbuffer_storage_multisample( glow::RENDERBUFFER, desc.sample_count as i32, - format_desc.tex_internal, + format_desc.internal, desc.size.width as i32, desc.size.height as i32, ); } else { gl.renderbuffer_storage( glow::RENDERBUFFER, - format_desc.tex_internal, + format_desc.internal, desc.size.width as i32, desc.size.height as i32, ); @@ -164,7 +417,7 @@ impl crate::Device for super::Device { gl.tex_storage_3d( target, desc.mip_level_count as i32, - format_desc.tex_internal, + format_desc.internal, desc.size.width as i32, desc.size.height as i32, desc.size.depth_or_array_layers as i32, @@ -176,7 +429,7 @@ impl crate::Device for super::Device { gl.tex_storage_2d( target, desc.mip_level_count as i32, - format_desc.tex_internal, + format_desc.internal, desc.size.width as i32, desc.size.height as i32, ); @@ -189,7 +442,7 @@ impl crate::Device for super::Device { gl.tex_storage_3d( target, desc.mip_level_count as i32, - format_desc.tex_internal, + format_desc.internal, desc.size.width as i32, desc.size.height as i32, desc.size.depth_or_array_layers as i32, @@ -391,37 +644,87 @@ impl crate::Device for super::Device { &self, desc: &crate::ShaderModuleDescriptor, shader: crate::ShaderInput, - ) -> Result { - Ok(Resource) + ) -> Result { + Ok(super::ShaderModule { + naga: match shader { + crate::ShaderInput::SpirV(_) => panic!("Unable to pass-through SPIR-V"), + crate::ShaderInput::Naga(naga) => naga, + }, + }) } - unsafe fn destroy_shader_module(&self, module: Resource) {} + unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) {} + unsafe fn create_render_pipeline( &self, desc: &crate::RenderPipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + let shaders = iter::once((naga::ShaderStage::Vertex, &desc.vertex_stage)).chain( + desc.fragment_stage + .as_ref() + .map(|fs| (naga::ShaderStage::Fragment, fs)), + ); + let inner = self.create_pipeline(shaders, desc.layout)?; + + let attributes = { + let gl = &self.shared.context; + let mut attributes = Vec::new(); + + for (index, vb_layout) in desc.vertex_buffers.iter().enumerate() { + for vat in vb_layout.attributes.iter() { + let format_desc = conv::describe_vertex_format(vat.format); + attributes.push(super::AttributeDesc { + location: vat.shader_location, + offset: vat.offset as u32, + buffer_index: index as u32, + format_desc, + }); + } + } + + attributes.into_boxed_slice() + }; + + Ok(super::RenderPipeline { + inner, + primitive: desc.primitive.clone(), + attributes, + depth: desc.depth_stencil.clone(), + }) } - unsafe fn destroy_render_pipeline(&self, pipeline: Resource) {} + unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) { + let gl = &self.shared.context; + gl.delete_program(pipeline.inner.program); + } + unsafe fn create_compute_pipeline( &self, desc: &crate::ComputePipelineDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + let shaders = iter::once((naga::ShaderStage::Compute, &desc.stage)); + let inner = self.create_pipeline(shaders, desc.layout)?; + + Ok(super::ComputePipeline { inner }) + } + unsafe fn destroy_compute_pipeline(&self, pipeline: super::ComputePipeline) { + let gl = &self.shared.context; + gl.delete_program(pipeline.inner.program); } - unsafe fn destroy_compute_pipeline(&self, pipeline: Resource) {} unsafe fn create_query_set( &self, desc: &wgt::QuerySetDescriptor, - ) -> DeviceResult { + ) -> Result { Ok(Resource) } unsafe fn destroy_query_set(&self, set: Resource) {} - unsafe fn create_fence(&self) -> DeviceResult { + unsafe fn create_fence(&self) -> Result { Ok(Resource) } unsafe fn destroy_fence(&self, fence: Resource) {} - unsafe fn get_fence_value(&self, fence: &Resource) -> DeviceResult { + unsafe fn get_fence_value( + &self, + fence: &Resource, + ) -> Result { Ok(0) } unsafe fn wait( @@ -429,7 +732,7 @@ impl crate::Device for super::Device { fence: &Resource, value: crate::FenceValue, timeout_ms: u32, - ) -> DeviceResult { + ) -> Result { Ok(true) } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index ac5b60ac61..456c5df5a6 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -587,7 +587,7 @@ impl crate::Surface for Surface { gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)); gl.renderbuffer_storage( glow::RENDERBUFFER, - format_desc.tex_internal, + format_desc.internal, config.extent.width as _, config.extent.height as _, ); @@ -606,7 +606,7 @@ impl crate::Surface for Surface { renderbuffer, framebuffer, extent: config.extent, - format: format_desc.tex_internal, + format: format_desc.internal, sample_type: wgt::TextureSampleType::Float { filterable: false }, }); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 0e5bed313c..6fae71f5c8 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -21,7 +21,10 @@ pub struct Api; #[derive(Debug)] pub struct Resource; -type DeviceResult = Result; +//Note: we can support more samplers if not every one of them is used at a time, +// but it probably doesn't worth it. +const MAX_SAMPLER_SLOTS: usize = 16; +const MAX_TEXTURE_SLOTS: usize = 16; impl crate::Api for Api { type Instance = Instance; @@ -44,9 +47,9 @@ impl crate::Api for Api { type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; type PipelineLayout = PipelineLayout; - type ShaderModule = Resource; - type RenderPipeline = Resource; - type ComputePipeline = Resource; + type ShaderModule = ShaderModule; + type RenderPipeline = RenderPipeline; + type ComputePipeline = ComputePipeline; } bitflags::bitflags! { @@ -152,23 +155,22 @@ impl Sampled for SampledTextureBinding { #[derive(Debug, Clone, Copy)] enum VertexAttribKind { - Float, // glVertexAttribPointer + Float, // glVertexAttribPointer Integer, // glVertexAttribIPointer - Double, // glVertexAttribLPointer + //Double, // glVertexAttribLPointer } #[derive(Debug)] -struct FormatDescription { - tex_internal: u32, - tex_external: u32, +struct TextureFormatDesc { + internal: u32, + external: u32, data_type: u32, - num_components: u8, - va_kind: VertexAttribKind, } struct AdapterShared { context: glow::Context, private_caps: PrivateCapability, + shading_language_version: naga::back::glsl::Version, } pub struct Adapter { @@ -218,7 +220,7 @@ impl TextureInner { #[derive(Debug)] pub struct Texture { inner: TextureInner, - format_desc: FormatDescription, + format_desc: TextureFormatDesc, format_info: wgt::TextureFormatInfo, } @@ -258,6 +260,13 @@ pub struct PipelineLayout { group_infos: Box<[BindGroupLayoutInfo]>, } +impl PipelineLayout { + fn get_slot(&self, br: &naga::ResourceBinding) -> u8 { + let group_info = &self.group_infos[br.group as usize]; + group_info.binding_to_slot[br.binding as usize] + } +} + #[derive(Debug)] enum BindingRegister { Textures, @@ -287,6 +296,54 @@ pub struct BindGroup { contents: Box<[RawBinding]>, } +#[derive(Debug)] +pub struct ShaderModule { + naga: crate::NagaShader, +} + +struct VertexFormatDesc { + element_count: i32, + element_format: u32, + attrib_kind: VertexAttribKind, +} + +struct AttributeDesc { + location: u32, + offset: u32, + buffer_index: u32, + format_desc: VertexFormatDesc, +} + +#[derive(Clone)] +struct UniformDesc { + location: glow::UniformLocation, + offset: u32, + utype: u32, +} + +/// For each texture in the pipeline layout, store the index of the only +/// sampler (in this layout) that the texture is used with. +type SamplerBindMap = [Option; MAX_TEXTURE_SLOTS]; + +struct PipelineInner { + program: glow::Program, + sampler_map: SamplerBindMap, + uniforms: Box<[UniformDesc]>, +} + +pub struct RenderPipeline { + inner: PipelineInner, + //blend_targets: Vec, + attributes: Box<[AttributeDesc]>, + //vertex_buffers: Box<[wgt::VertexBufferLayout]>, + primitive: wgt::PrimitiveState, + depth: Option, +} + +pub struct ComputePipeline { + inner: PipelineInner, +} + #[derive(Debug)] struct TextureCopyInfo { external_format: u32, @@ -297,13 +354,13 @@ struct TextureCopyInfo { #[derive(Debug)] enum Command { Draw { - primitive: u32, + topology: u32, start_vertex: u32, vertex_count: u32, instance_count: u32, }, DrawIndexed { - primitive: u32, + topology: u32, index_type: u32, index_count: u32, index_offset: wgt::BufferAddress, @@ -311,12 +368,12 @@ enum Command { instance_count: u32, }, DrawIndirect { - primitive: u32, + topology: u32, indirect_buf: glow::Buffer, indirect_offset: wgt::BufferAddress, }, DrawIndexedIndirect { - primitive: u32, + topology: u32, index_type: u32, indirect_buf: glow::Buffer, indirect_offset: wgt::BufferAddress, @@ -376,7 +433,7 @@ pub struct CommandBuffer { #[derive(Default)] struct CommandState { - primitive: u32, + topology: u32, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 25536dc250..94e607f7da 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -20,16 +20,16 @@ impl super::Queue { let gl = &self.shared.context; match *command { C::Draw { - primitive, + topology, start_vertex, vertex_count, instance_count, } => { if instance_count == 1 { - gl.draw_arrays(primitive, start_vertex as i32, vertex_count as i32); + gl.draw_arrays(topology, start_vertex as i32, vertex_count as i32); } else { gl.draw_arrays_instanced( - primitive, + topology, start_vertex as i32, vertex_count as i32, instance_count as i32, @@ -37,7 +37,7 @@ impl super::Queue { } } C::DrawIndexed { - primitive, + topology, index_type, index_count, index_offset, @@ -45,27 +45,27 @@ impl super::Queue { instance_count, } => match (base_vertex, instance_count) { (0, 1) => gl.draw_elements( - primitive, + topology, index_count as i32, index_type, index_offset as i32, ), (0, _) => gl.draw_elements_instanced( - primitive, + topology, index_count as i32, index_type, index_offset as i32, instance_count as i32, ), (_, 1) => gl.draw_elements_base_vertex( - primitive, + topology, index_count as i32, index_type, index_offset as i32, base_vertex, ), (_, _) => gl.draw_elements_instanced_base_vertex( - primitive, + topology, index_count as _, index_type, index_offset as i32, @@ -74,16 +74,16 @@ impl super::Queue { ), }, C::DrawIndirect { - primitive: _, + topology: _, indirect_buf, indirect_offset: _, } => { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); //TODO: https://github.com/grovesNL/glow/issues/172 - //gl.draw_arrays_indirect(primitive, indirect_offset); + //gl.draw_arrays_indirect(topology, indirect_offset); } C::DrawIndexedIndirect { - primitive: _, + topology: _, index_type: _, indirect_buf, indirect_offset: _, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 70adcff4a4..c7092e7bdd 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -837,7 +837,6 @@ pub struct CommandEncoderDescriptor<'a, A: Api> { } /// Naga shader module. -#[derive(Debug)] pub struct NagaShader { /// Shader module IR. pub module: naga::Module, @@ -845,6 +844,14 @@ pub struct NagaShader { pub info: naga::valid::ModuleInfo, } +// Custom implementation avoids the need to generate Debug impl code +// for the whole Naga module and info. +impl fmt::Debug for NagaShader { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!(formatter, "Naga shader") + } +} + /// Shader input. pub enum ShaderInput<'a> { Naga(NagaShader), diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index c105aee316..658c071b02 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -61,10 +61,10 @@ impl super::Device { }, }; - let module = &stage.module.raw.module; + let module = &stage.module.naga.module; let (source, info) = naga::back::msl::write_string( module, - &stage.module.raw.info, + &stage.module.naga.info, &layout.naga_options, &pipeline_options, ) @@ -644,7 +644,7 @@ impl crate::Device for super::Device { shader: crate::ShaderInput, ) -> Result { match shader { - crate::ShaderInput::Naga(raw) => Ok(super::ShaderModule { raw }), + crate::ShaderInput::Naga(naga) => Ok(super::ShaderModule { naga }), crate::ShaderInput::SpirV(_) => { unreachable!("SPIRV_SHADER_PASSTHROUGH is not enabled for this backend") } diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 0a4f1b545e..b658d9a81b 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -555,7 +555,7 @@ unsafe impl Sync for BindGroup {} #[derive(Debug)] pub struct ShaderModule { - raw: crate::NagaShader, + naga: crate::NagaShader, } #[derive(Debug, Default)] From 91f98068318f2053eb521e12b6102b9c20b87d17 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 23 Jun 2021 21:00:00 -0400 Subject: [PATCH 12/33] hal/gles: fences and queries --- wgpu-hal/src/gles/adapter.rs | 4 +-- wgpu-hal/src/gles/command.rs | 42 ++++++++++++++++------ wgpu-hal/src/gles/device.rs | 67 +++++++++++++++++++++++++++++------- wgpu-hal/src/gles/mod.rs | 61 ++++++++++++++++++++++++++++---- wgpu-hal/src/gles/queue.rs | 48 ++++++++++++++++++++++---- 5 files changed, 185 insertions(+), 37 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index d2c22d6c4a..25e55b8ad1 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -279,7 +279,7 @@ impl super::Adapter { impl crate::Adapter for super::Adapter { unsafe fn open( &self, - features: wgt::Features, + _features: wgt::Features, ) -> Result, crate::DeviceError> { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); @@ -294,8 +294,8 @@ impl crate::Adapter for super::Adapter { }, queue: super::Queue { shared: Arc::clone(&self.shared), - features, copy_fbo: gl.create_framebuffer().unwrap(), + temp_query_results: Vec::new(), }, }) } diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index b4ca8c0acb..fcbad747df 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1,4 +1,3 @@ -use super::Resource; //TEMP use super::{conv, Command as C}; use std::{mem, ops::Range}; @@ -6,13 +5,14 @@ impl super::CommandBuffer { fn clear(&mut self) { self.label = None; self.commands.clear(); - self.data.clear(); + self.data_bytes.clear(); + self.data_words.clear(); } fn add_marker(&mut self, marker: &str) -> Range { - let start = self.data.len() as u32; - self.data.extend(marker.as_bytes()); - start..self.data.len() as u32 + let start = self.data_bytes.len() as u32; + self.data_bytes.extend(marker.as_bytes()); + start..self.data_bytes.len() as u32 } } @@ -153,17 +153,39 @@ impl crate::CommandEncoder for super::CommandEncoder { } } - 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 begin_query(&mut self, set: &super::QuerySet, index: u32) { + let query = set.queries[index as usize]; + self.cmd_buffer + .commands + .push(C::BeginQuery(query, set.target)); + } + unsafe fn end_query(&mut self, set: &super::QuerySet, _index: u32) { + self.cmd_buffer.commands.push(C::EndQuery(set.target)); + } + unsafe fn write_timestamp(&mut self, _set: &super::QuerySet, _index: u32) { + unimplemented!() + } + unsafe fn reset_queries(&mut self, _set: &super::QuerySet, _range: Range) { + //TODO: what do we do here? + } unsafe fn copy_query_results( &mut self, - set: &Resource, + set: &super::QuerySet, range: Range, buffer: &super::Buffer, offset: wgt::BufferAddress, ) { + let start = self.cmd_buffer.data_words.len(); + self.cmd_buffer + .data_words + .extend_from_slice(&set.queries[range.start as usize..range.end as usize]); + let query_range = start as u32..self.cmd_buffer.data_words.len() as u32; + self.cmd_buffer.commands.push(C::CopyQueryResults { + query_range, + dst: buffer.raw, + dst_target: buffer.target, + dst_offset: offset, + }); } // render diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 56f39feb35..b442f461cc 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -1,5 +1,4 @@ use super::conv; -use super::Resource; //TEMP use crate::util::map_naga_stage; use glow::HasContext; use std::{convert::TryInto, iter, ptr::NonNull, sync::Arc}; @@ -713,27 +712,71 @@ impl crate::Device for super::Device { unsafe fn create_query_set( &self, desc: &wgt::QuerySetDescriptor, - ) -> Result { - Ok(Resource) + ) -> Result { + let gl = &self.shared.context; + + let mut queries = Vec::with_capacity(desc.count as usize); + for _ in 0..desc.count { + let query = gl + .create_query() + .map_err(|_| crate::DeviceError::OutOfMemory)?; + queries.push(query); + } + + Ok(super::QuerySet { + queries: queries.into_boxed_slice(), + target: match desc.ty { + wgt::QueryType::Occlusion => glow::ANY_SAMPLES_PASSED, + _ => unimplemented!(), + }, + }) + } + unsafe fn destroy_query_set(&self, set: super::QuerySet) { + let gl = &self.shared.context; + for &query in set.queries.iter() { + gl.delete_query(query); + } } - unsafe fn destroy_query_set(&self, set: Resource) {} - unsafe fn create_fence(&self) -> Result { - Ok(Resource) + unsafe fn create_fence(&self) -> Result { + Ok(super::Fence { + last_completed: 0, + pending: Vec::new(), + }) + } + unsafe fn destroy_fence(&self, fence: super::Fence) { + let gl = &self.shared.context; + for (_, sync) in fence.pending { + gl.delete_sync(sync); + } } - unsafe fn destroy_fence(&self, fence: Resource) {} unsafe fn get_fence_value( &self, - fence: &Resource, + fence: &super::Fence, ) -> Result { - Ok(0) + Ok(fence.get_latest(&self.shared.context)) } unsafe fn wait( &self, - fence: &Resource, - value: crate::FenceValue, + fence: &super::Fence, + wait_value: crate::FenceValue, timeout_ms: u32, ) -> Result { - Ok(true) + if fence.last_completed < wait_value { + let gl = &self.shared.context; + let timeout_ns = (timeout_ms as u64 * 1_000_000).min(!0u32 as u64); + let &(_, sync) = fence + .pending + .iter() + .find(|&&(value, _)| value >= wait_value) + .unwrap(); + match gl.client_wait_sync(sync, glow::SYNC_FLUSH_COMMANDS_BIT, timeout_ns as i32) { + glow::TIMEOUT_EXPIRED => Ok(false), + glow::CONDITION_SATISFIED | glow::ALREADY_SIGNALED => Ok(true), + _ => Err(crate::DeviceError::Lost), + } + } else { + Ok(true) + } } unsafe fn start_capture(&self) -> bool { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 6fae71f5c8..172b228397 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -18,12 +18,9 @@ use std::{ops::Range, sync::Arc}; #[derive(Clone)] pub struct Api; -#[derive(Debug)] -pub struct Resource; //Note: we can support more samplers if not every one of them is used at a time, // but it probably doesn't worth it. -const MAX_SAMPLER_SLOTS: usize = 16; const MAX_TEXTURE_SLOTS: usize = 16; impl crate::Api for Api { @@ -41,8 +38,8 @@ impl crate::Api for Api { type SurfaceTexture = Texture; type TextureView = TextureView; type Sampler = Sampler; - type QuerySet = Resource; - type Fence = Resource; + type QuerySet = QuerySet; + type Fence = Fence; type BindGroupLayout = BindGroupLayout; type BindGroup = BindGroup; @@ -184,8 +181,8 @@ pub struct Device { pub struct Queue { shared: Arc, - features: wgt::Features, copy_fbo: glow::Framebuffer, + temp_query_results: Vec, } #[derive(Debug)] @@ -344,6 +341,47 @@ pub struct ComputePipeline { inner: PipelineInner, } +#[derive(Debug)] +pub struct QuerySet { + queries: Box<[glow::Query]>, + target: BindTarget, +} + +#[derive(Debug)] +pub struct Fence { + last_completed: crate::FenceValue, + pending: Vec<(crate::FenceValue, glow::Fence)>, +} + +unsafe impl Send for Fence {} +unsafe impl Sync for Fence {} + +impl Fence { + fn get_latest(&self, gl: &glow::Context) -> crate::FenceValue { + let mut max_value = self.last_completed; + for &(value, sync) in self.pending.iter() { + let status = unsafe { gl.get_sync_status(sync) }; + if status == glow::SIGNALED { + max_value = value; + } + } + max_value + } + + fn maintain(&mut self, gl: &glow::Context) { + let latest = self.get_latest(gl); + for &(value, sync) in self.pending.iter() { + if value <= latest { + unsafe { + gl.delete_sync(sync); + } + } + } + self.pending.retain(|&(value, _)| value > latest); + self.last_completed = latest; + } +} + #[derive(Debug)] struct TextureCopyInfo { external_format: u32, @@ -419,6 +457,14 @@ enum Command { copy: crate::BufferTextureCopy, }, SetIndexBuffer(glow::Buffer), + BeginQuery(glow::Query, BindTarget), + EndQuery(BindTarget), + CopyQueryResults { + query_range: Range, + dst: glow::Buffer, + dst_target: BindTarget, + dst_offset: wgt::BufferAddress, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, @@ -428,7 +474,8 @@ enum Command { pub struct CommandBuffer { label: Option, commands: Vec, - data: Vec, + data_bytes: Vec, + data_words: Vec, } #[derive(Default)] diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 94e607f7da..0e7ec7a091 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1,6 +1,6 @@ use super::Command as C; use glow::HasContext; -use std::ops::Range; +use std::{mem, ops::Range, slice}; const DEBUG_ID: u32 = 0; @@ -16,7 +16,7 @@ fn is_3d_target(target: super::BindTarget) -> bool { } impl super::Queue { - unsafe fn process(&mut self, command: &C, data: &[u8]) { + unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) { let gl = &self.shared.context; match *command { C::Draw { @@ -265,8 +265,34 @@ impl super::Queue { C::SetIndexBuffer(buffer) => { gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(buffer)); } + C::BeginQuery(query, target) => { + gl.begin_query(target, query); + } + C::EndQuery(target) => { + gl.end_query(target); + } + C::CopyQueryResults { + ref query_range, + dst, + dst_target, + dst_offset, + } => { + self.temp_query_results.clear(); + for &query in + data_words[query_range.start as usize..query_range.end as usize].iter() + { + let result = gl.get_query_parameter_u32(query, glow::QUERY_RESULT); + self.temp_query_results.push(result as u64); + } + let query_data = slice::from_raw_parts( + self.temp_query_results.as_ptr() as *const u8, + self.temp_query_results.len() * mem::size_of::(), + ); + gl.bind_buffer(dst_target, Some(dst)); + gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data); + } C::InsertDebugMarker(ref range) => { - let marker = extract_marker(data, range); + let marker = extract_marker(data_bytes, range); gl.debug_message_insert( glow::DEBUG_SOURCE_APPLICATION, glow::DEBUG_TYPE_MARKER, @@ -276,7 +302,7 @@ impl super::Queue { ); } C::PushDebugGroup(ref range) => { - let marker = extract_marker(data, range); + let marker = extract_marker(data_bytes, range); gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, marker); } C::PopDebugGroup => { @@ -290,13 +316,23 @@ impl crate::Queue for super::Queue { unsafe fn submit( &mut self, command_buffers: &[&super::CommandBuffer], - signal_fence: Option<(&mut super::Resource, crate::FenceValue)>, + signal_fence: Option<(&mut super::Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { for cmd_buf in command_buffers.iter() { for command in cmd_buf.commands.iter() { - self.process(command, &cmd_buf.data); + self.process(command, &cmd_buf.data_bytes, &cmd_buf.data_words); } } + + if let Some((fence, value)) = signal_fence { + let gl = &self.shared.context; + fence.maintain(gl); + let sync = gl + .fence_sync(glow::SYNC_GPU_COMMANDS_COMPLETE, 0) + .map_err(|_| crate::DeviceError::OutOfMemory)?; + fence.pending.push((value, sync)); + } + Ok(()) } From 24ff58c6c1b9ac078d026d3d72fee0b3ba759de8 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 23 Jun 2021 21:35:03 -0400 Subject: [PATCH 13/33] hal/gles: present, texture format caps --- wgpu-hal/src/gles/adapter.rs | 80 +++++++++++++++++++++++++++++++++++- wgpu-hal/src/gles/device.rs | 32 ++++++++------- wgpu-hal/src/gles/egl.rs | 51 +++++++++++++++++++++++ wgpu-hal/src/gles/mod.rs | 3 +- wgpu-hal/src/gles/queue.rs | 3 +- 5 files changed, 151 insertions(+), 18 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 25e55b8ad1..83eb7f358d 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -304,7 +304,85 @@ impl crate::Adapter for super::Adapter { &self, format: wgt::TextureFormat, ) -> crate::TextureFormatCapability { - crate::TextureFormatCapability::empty() //TODO + use crate::TextureFormatCapability as Tfc; + use wgt::TextureFormat as Tf; + // The storage types are sprinkled based on section + // "TEXTURE IMAGE LOADS AND STORES" of GLES-3.2 spec. + let unfiltered_color = Tfc::SAMPLED | Tfc::COLOR_ATTACHMENT; + let filtered_color = unfiltered_color | Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT_BLEND; + match format { + Tf::R8Unorm | Tf::R8Snorm => filtered_color, + Tf::R8Uint | Tf::R8Sint | Tf::R16Uint | Tf::R16Sint => unfiltered_color, + Tf::R16Float | Tf::Rg8Unorm | Tf::Rg8Snorm => filtered_color, + Tf::Rg8Uint | Tf::Rg8Sint | Tf::R32Uint | Tf::R32Sint => { + unfiltered_color | Tfc::STORAGE + } + Tf::R32Float => unfiltered_color, + Tf::Rg16Uint | Tf::Rg16Sint => unfiltered_color, + Tf::Rg16Float | Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => filtered_color | Tfc::STORAGE, + Tf::Bgra8UnormSrgb | Tf::Rgba8Snorm | Tf::Bgra8Unorm => filtered_color, + Tf::Rgba8Uint | Tf::Rgba8Sint => unfiltered_color | Tfc::STORAGE, + Tf::Rgb10a2Unorm | Tf::Rg11b10Float => filtered_color, + Tf::Rg32Uint | Tf::Rg32Sint => unfiltered_color, + Tf::Rg32Float => unfiltered_color | Tfc::STORAGE, + Tf::Rgba16Uint | Tf::Rgba16Sint => unfiltered_color | Tfc::STORAGE, + Tf::Rgba16Float => filtered_color | Tfc::STORAGE, + Tf::Rgba32Uint | Tf::Rgba32Sint => unfiltered_color | Tfc::STORAGE, + Tf::Rgba32Float => unfiltered_color | Tfc::STORAGE, + Tf::Depth32Float => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, + Tf::Depth24Plus => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, + Tf::Depth24PlusStencil8 => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, + Tf::Bc1RgbaUnorm + | Tf::Bc1RgbaUnormSrgb + | Tf::Bc2RgbaUnorm + | Tf::Bc2RgbaUnormSrgb + | Tf::Bc3RgbaUnorm + | Tf::Bc3RgbaUnormSrgb + | Tf::Bc4RUnorm + | Tf::Bc4RSnorm + | Tf::Bc5RgUnorm + | Tf::Bc5RgSnorm + | Tf::Bc6hRgbSfloat + | Tf::Bc6hRgbUfloat + | Tf::Bc7RgbaUnorm + | Tf::Bc7RgbaUnormSrgb + | Tf::Etc2RgbUnorm + | Tf::Etc2RgbUnormSrgb + | Tf::Etc2RgbA1Unorm + | Tf::Etc2RgbA1UnormSrgb + | Tf::EacRUnorm + | Tf::EacRSnorm + | Tf::EtcRgUnorm + | Tf::EtcRgSnorm + | Tf::Astc4x4RgbaUnorm + | Tf::Astc4x4RgbaUnormSrgb + | Tf::Astc5x4RgbaUnorm + | Tf::Astc5x4RgbaUnormSrgb + | Tf::Astc5x5RgbaUnorm + | Tf::Astc5x5RgbaUnormSrgb + | Tf::Astc6x5RgbaUnorm + | Tf::Astc6x5RgbaUnormSrgb + | Tf::Astc6x6RgbaUnorm + | Tf::Astc6x6RgbaUnormSrgb + | Tf::Astc8x5RgbaUnorm + | Tf::Astc8x5RgbaUnormSrgb + | Tf::Astc8x6RgbaUnorm + | Tf::Astc8x6RgbaUnormSrgb + | Tf::Astc10x5RgbaUnorm + | Tf::Astc10x5RgbaUnormSrgb + | Tf::Astc10x6RgbaUnorm + | Tf::Astc10x6RgbaUnormSrgb + | Tf::Astc8x8RgbaUnorm + | Tf::Astc8x8RgbaUnormSrgb + | Tf::Astc10x8RgbaUnorm + | Tf::Astc10x8RgbaUnormSrgb + | Tf::Astc10x10RgbaUnorm + | Tf::Astc10x10RgbaUnormSrgb + | Tf::Astc12x10RgbaUnorm + | Tf::Astc12x10RgbaUnormSrgb + | Tf::Astc12x12RgbaUnorm + | Tf::Astc12x12RgbaUnormSrgb => Tfc::SAMPLED | Tfc::SAMPLED_LINEAR, + } } unsafe fn surface_capabilities( diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index b442f461cc..8a761b3b73 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -41,16 +41,18 @@ impl CompilationContext<'_> { } for (name, mapping) in reflection_info.texture_mapping { - let tex_br = module.global_variables[mapping.texture] - .binding - .as_ref() - .unwrap(); + let var = &module.global_variables[mapping.texture]; + let register = if var.storage_access.is_empty() { + super::BindingRegister::Textures + } else { + super::BindingRegister::Images + }; + + let tex_br = var.binding.as_ref().unwrap(); let texture_linear_index = self.layout.get_slot(tex_br); - self.name_binding_map.insert( - name, - (super::BindingRegister::Textures, texture_linear_index), - ); + self.name_binding_map + .insert(name, (register, texture_linear_index)); if let Some(sampler_handle) = mapping.sampler { let sam_br = module.global_variables[sampler_handle] .binding @@ -205,10 +207,6 @@ impl super::Device { for (ref name, (register, slot)) in name_binding_map { log::trace!("Get binding {:?} from program {:?}", name, program); match register { - super::BindingRegister::Textures => { - let loc = gl.get_uniform_location(program, name).unwrap(); - gl.uniform_1_i32(Some(&loc), slot as _); - } super::BindingRegister::UniformBuffers => { let index = gl.get_uniform_block_index(program, name).unwrap(); gl.uniform_block_binding(program, index, slot as _); @@ -217,6 +215,10 @@ impl super::Device { let index = gl.get_shader_storage_block_index(program, name).unwrap(); gl.shader_storage_block_binding(program, index, slot as _); } + super::BindingRegister::Textures | super::BindingRegister::Images => { + let loc = gl.get_uniform_location(program, name).unwrap(); + gl.uniform_1_i32(Some(&loc), slot as _); + } } } } @@ -536,6 +538,7 @@ impl crate::Device for super::Device { let mut group_infos = Vec::with_capacity(desc.bind_group_layouts.len()); let mut num_samplers = 0u8; let mut num_textures = 0u8; + let mut num_images = 0u8; let mut num_uniform_buffers = 0u8; let mut num_storage_buffers = 0u8; @@ -553,9 +556,8 @@ impl crate::Device for super::Device { for entry in bg_layout.entries.iter() { let counter = match entry.ty { wgt::BindingType::Sampler { .. } => &mut num_samplers, - wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => { - &mut num_textures - } + wgt::BindingType::Texture { .. } => &mut num_textures, + wgt::BindingType::StorageTexture { .. } => &mut num_images, wgt::BindingType::Buffer { ty: wgt::BufferBindingType::Uniform, .. diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 456c5df5a6..f35693ea9e 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -560,6 +560,57 @@ pub struct Surface { unsafe impl Send for Surface {} unsafe impl Sync for Surface {} +impl Surface { + pub(super) unsafe fn present( + &mut self, + _suf_texture: super::Texture, + gl: &glow::Context, + ) -> Result<(), crate::SurfaceError> { + let sc = self.swapchain.as_ref().unwrap(); + + self.egl + .make_current( + self.display, + Some(self.raw), + Some(self.raw), + Some(self.context), + ) + .map_err(|e| { + log::error!("make_current(surface) failed: {}", e); + crate::SurfaceError::Lost + })?; + + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)); + gl.blit_framebuffer( + 0, + 0, + sc.extent.width as i32, + sc.extent.height as i32, + 0, + 0, + sc.extent.width as i32, + sc.extent.height as i32, + glow::COLOR_BUFFER_BIT, + glow::NEAREST, + ); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); + + self.egl.swap_buffers(self.display, self.raw).map_err(|e| { + log::error!("swap_buffers failed: {}", e); + crate::SurfaceError::Lost + })?; + self.egl + .make_current(self.display, self.pbuffer, self.pbuffer, Some(self.context)) + .map_err(|e| { + log::error!("make_current(null) failed: {}", e); + crate::SurfaceError::Lost + })?; + + Ok(()) + } +} + impl crate::Surface for Surface { unsafe fn configure( &mut self, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 172b228397..362ac00eff 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -266,9 +266,10 @@ impl PipelineLayout { #[derive(Debug)] enum BindingRegister { - Textures, UniformBuffers, StorageBuffers, + Textures, + Images, } #[derive(Debug)] diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 0e7ec7a091..8de53613fd 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -341,6 +341,7 @@ impl crate::Queue for super::Queue { surface: &mut super::Surface, texture: super::Texture, ) -> Result<(), crate::SurfaceError> { - Ok(()) + let gl = &self.shared.context; + surface.present(texture, gl) } } From 51dd90b1ab2dfe716da8d2b6775b5591c40acaa6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 24 Jun 2021 01:22:38 -0400 Subject: [PATCH 14/33] hal/gles: render passes --- wgpu-core/src/command/render.rs | 2 + wgpu-hal/examples/halmark/main.rs | 6 ++ wgpu-hal/src/gles/adapter.rs | 11 +++- wgpu-hal/src/gles/command.rs | 104 +++++++++++++++++++++++++++--- wgpu-hal/src/gles/conv.rs | 11 ++++ wgpu-hal/src/gles/device.rs | 54 +++++++--------- wgpu-hal/src/gles/mod.rs | 37 ++++++----- wgpu-hal/src/gles/queue.rs | 82 +++++++++++++++++++++++ wgpu-hal/src/lib.rs | 4 ++ wgpu-hal/src/vulkan/command.rs | 22 ++++--- wgpu-hal/src/vulkan/device.rs | 17 +---- wgpu-hal/src/vulkan/instance.rs | 2 - wgpu-hal/src/vulkan/mod.rs | 19 +----- 13 files changed, 273 insertions(+), 98 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index de9db623bb..40d0655be8 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -745,6 +745,8 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let hal_desc = hal::RenderPassDescriptor { label, + extent, + sample_count, color_attachments: &colors, depth_stencil_attachment: depth_stencil, }; diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 97dab2f20a..0fc766fe4b 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -597,6 +597,12 @@ impl Example { }; let pass_desc = hal::RenderPassDescriptor { label: None, + extent: wgt::Extent3d { + width: self.extent[0], + height: self.extent[1], + depth_or_array_layers: 1, + }, + sample_count: 1, color_attachments: &[hal::ColorAttachment { target: hal::Attachment { view: &surface_tex_view, diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 83eb7f358d..1f3b66317f 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -284,7 +284,9 @@ impl crate::Adapter for super::Adapter { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); gl.pixel_store_i32(glow::PACK_ALIGNMENT, 1); - let main_vao = gl.create_vertex_array().unwrap(); + let main_vao = gl + .create_vertex_array() + .map_err(|_| crate::DeviceError::OutOfMemory)?; gl.bind_vertex_array(Some(main_vao)); Ok(crate::OpenDevice { @@ -294,7 +296,12 @@ impl crate::Adapter for super::Adapter { }, queue: super::Queue { shared: Arc::clone(&self.shared), - copy_fbo: gl.create_framebuffer().unwrap(), + draw_fbo: gl + .create_framebuffer() + .map_err(|_| crate::DeviceError::OutOfMemory)?, + copy_fbo: gl + .create_framebuffer() + .map_err(|_| crate::DeviceError::OutOfMemory)?, temp_query_results: Vec::new(), }, }) diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index fcbad747df..74ebb87807 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -18,6 +18,7 @@ impl super::CommandBuffer { impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { + self.state = super::CommandState::default(); self.cmd_buffer.label = label.map(str::to_string); Ok(()) } @@ -100,8 +101,9 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { + let format_info = dst.format.describe(); assert_eq!( - dst.format_info.block_dimensions, + format_info.block_dimensions, (1, 1), "Compressed texture copies are TODO" ); @@ -115,7 +117,7 @@ impl crate::CommandEncoder for super::CommandEncoder { dst_info: super::TextureCopyInfo { external_format: dst.format_desc.external, data_type: dst.format_desc.data_type, - texel_size: dst.format_info.block_size, + texel_size: format_info.block_size, }, copy, }) @@ -131,8 +133,9 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { + let format_info = src.format.describe(); assert_eq!( - src.format_info.block_dimensions, + format_info.block_dimensions, (1, 1), "Compressed texture copies are TODO" ); @@ -144,7 +147,7 @@ impl crate::CommandEncoder for super::CommandEncoder { src_info: super::TextureCopyInfo { external_format: src.format_desc.external, data_type: src.format_desc.data_type, - texel_size: src.format_info.block_size, + texel_size: format_info.block_size, }, dst: dst.raw, dst_target: dst.target, @@ -190,8 +193,82 @@ impl crate::CommandEncoder for super::CommandEncoder { // render - unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) {} - unsafe fn end_render_pass(&mut self) {} + unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) { + if let Some(label) = desc.label { + let range = self.cmd_buffer.add_marker(label); + self.cmd_buffer.commands.push(C::PushDebugGroup(range)); + self.state.has_pass_label = true; + } + + // set the framebuffer + self.cmd_buffer + .commands + .push(C::ResetFramebuffer(desc.extent)); + for (i, cat) in desc.color_attachments.iter().enumerate() { + let attachment = glow::COLOR_ATTACHMENT0 + i as u32; + self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + attachment, + view: cat.target.view.clone(), + }); + } + if let Some(ref dsat) = desc.depth_stencil_attachment { + let attachment = match dsat.target.view.aspects { + crate::FormatAspect::DEPTH => glow::DEPTH_ATTACHMENT, + crate::FormatAspect::STENCIL => glow::STENCIL_ATTACHMENT, + _ => glow::DEPTH_STENCIL_ATTACHMENT, + }; + self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + attachment, + view: dsat.target.view.clone(), + }); + } + + self.cmd_buffer + .commands + .push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8)); + // issue the clears + for (i, cat) in desc.color_attachments.iter().enumerate() { + if !cat.ops.contains(crate::AttachmentOp::LOAD) { + let draw_buffer = glow::DRAW_BUFFER0 + i as u32; + let c = &cat.clear_value; + self.cmd_buffer + .commands + .push(match cat.target.view.sample_type { + wgt::TextureSampleType::Float { .. } => C::ClearColorF( + draw_buffer, + [c.r as f32, c.g as f32, c.r as f32, c.a as f32], + ), + wgt::TextureSampleType::Depth => unimplemented!(), + wgt::TextureSampleType::Uint => C::ClearColorU( + draw_buffer, + [c.r as u32, c.g as u32, c.r as u32, c.a as u32], + ), + wgt::TextureSampleType::Sint => C::ClearColorI( + draw_buffer, + [c.r as i32, c.g as i32, c.r as i32, c.a as i32], + ), + }); + } + } + if let Some(ref dsat) = desc.depth_stencil_attachment { + if !dsat.depth_ops.contains(crate::AttachmentOp::LOAD) { + self.cmd_buffer + .commands + .push(C::ClearDepth(dsat.clear_value.0)); + } + if !dsat.stencil_ops.contains(crate::AttachmentOp::LOAD) { + self.cmd_buffer + .commands + .push(C::ClearStencil(dsat.clear_value.1)); + } + } + } + unsafe fn end_render_pass(&mut self) { + if self.state.has_pass_label { + self.cmd_buffer.commands.push(C::PopDebugGroup); + self.state.has_pass_label = false; + } + } unsafe fn set_bind_group( &mut self, @@ -346,8 +423,19 @@ impl crate::CommandEncoder for super::CommandEncoder { // compute - unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) {} - unsafe fn end_compute_pass(&mut self) {} + unsafe fn begin_compute_pass(&mut self, desc: &crate::ComputePassDescriptor) { + if let Some(label) = desc.label { + let range = self.cmd_buffer.add_marker(label); + self.cmd_buffer.commands.push(C::PushDebugGroup(range)); + self.state.has_pass_label = true; + } + } + unsafe fn end_compute_pass(&mut self) { + if self.state.has_pass_label { + self.cmd_buffer.commands.push(C::PopDebugGroup); + self.state.has_pass_label = false; + } + } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 1f3a2a2e7e..3162e84e6e 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -221,3 +221,14 @@ pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 { Pt::TriangleStrip => glow::TRIANGLE_STRIP, } } + +pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { + use wgt::TextureViewDimension as Tvd; + match dim { + Tvd::D1 | Tvd::D2 => glow::TEXTURE_2D, + Tvd::D2Array => glow::TEXTURE_2D_ARRAY, + Tvd::Cube => glow::TEXTURE_CUBE_MAP, + Tvd::CubeArray => glow::TEXTURE_CUBE_MAP_ARRAY, + Tvd::D3 => glow::TEXTURE_3D, + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 8a761b3b73..048d7e8bbb 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -113,8 +113,10 @@ impl super::Device { }; let shader = &stage.module.naga; - let entry_point_index = (&shader.module.entry_points) - .into_iter() + let entry_point_index = shader + .module + .entry_points + .iter() .position(|ep| ep.name.as_str() == stage.entry_point) .ok_or(crate::PipelineError::EntryPoint(naga_stage))?; @@ -397,10 +399,7 @@ impl crate::Device for super::Device { desc.size.height as i32, ); } - super::TextureInner::Renderbuffer { - raw, - aspects: desc.format.into(), - } + super::TextureInner::Renderbuffer { raw } } else { let raw = gl.create_texture().unwrap(); let target = match desc.dimension { @@ -456,8 +455,8 @@ impl crate::Device for super::Device { Ok(super::Texture { inner, + format: desc.format, format_desc, - format_info: desc.format.describe(), }) } unsafe fn destroy_texture(&self, texture: super::Texture) { @@ -477,18 +476,21 @@ impl crate::Device for super::Device { texture: &super::Texture, desc: &crate::TextureViewDescriptor, ) -> Result { - Ok(match texture.inner { - super::TextureInner::Renderbuffer { raw, aspects } => { - super::TextureView::Renderbuffer { - raw, - aspects: aspects & crate::FormatAspect::from(desc.range.aspect), + Ok(super::TextureView { + inner: match texture.inner { + super::TextureInner::Renderbuffer { raw } => { + super::TextureInner::Renderbuffer { raw } } - } - super::TextureInner::Texture { raw, target } => super::TextureView::Texture { - raw, - target, - range: desc.range.clone(), + super::TextureInner::Texture { raw, target: _ } => super::TextureInner::Texture { + raw, + target: conv::map_view_dimension(desc.dimension), + }, }, + sample_type: texture.format.describe().sample_type, + aspects: crate::FormatAspect::from(texture.format) + & crate::FormatAspect::from(desc.range.aspect), + base_mip_level: desc.range.base_mip_level, + base_array_layer: desc.range.base_array_layer, }) } unsafe fn destroy_texture_view(&self, _view: super::TextureView) {} @@ -615,19 +617,13 @@ impl crate::Device for super::Device { super::RawBinding::Sampler(sampler.raw) } wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => { - match *desc.textures[entry.resource_index as usize].view { - super::TextureView::Renderbuffer { .. } => { + match desc.textures[entry.resource_index as usize].view.inner { + super::TextureInner::Renderbuffer { .. } => { panic!("Unable to use a renderbuffer in a group") } - super::TextureView::Texture { - raw, - target, - ref range, - } => super::RawBinding::Texture { - raw, - target, - range: range.clone(), - }, + super::TextureInner::Texture { raw, target } => { + super::RawBinding::Texture { raw, target } + } } } }; @@ -687,7 +683,7 @@ impl crate::Device for super::Device { Ok(super::RenderPipeline { inner, - primitive: desc.primitive.clone(), + primitive: desc.primitive, attributes, depth: desc.depth_stencil.clone(), }) diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 362ac00eff..60660a7654 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -181,6 +181,7 @@ pub struct Device { pub struct Queue { shared: Arc, + draw_fbo: glow::Framebuffer, copy_fbo: glow::Framebuffer, temp_query_results: Vec, } @@ -193,11 +194,10 @@ pub struct Buffer { map_flags: u32, } -#[derive(Debug)] +#[derive(Clone, Debug)] enum TextureInner { Renderbuffer { raw: glow::Renderbuffer, - aspects: crate::FormatAspect, }, Texture { raw: glow::Texture, @@ -217,21 +217,17 @@ impl TextureInner { #[derive(Debug)] pub struct Texture { inner: TextureInner, + format: wgt::TextureFormat, format_desc: TextureFormatDesc, - format_info: wgt::TextureFormatInfo, } -#[derive(Debug)] -pub enum TextureView { - Renderbuffer { - raw: glow::Renderbuffer, - aspects: crate::FormatAspect, - }, - Texture { - raw: glow::Texture, - target: BindTarget, - range: wgt::ImageSubresourceRange, - }, +#[derive(Clone, Debug)] +pub struct TextureView { + inner: TextureInner, + sample_type: wgt::TextureSampleType, + aspects: crate::FormatAspect, + base_mip_level: u32, + base_array_layer: u32, } #[derive(Debug)] @@ -283,7 +279,6 @@ enum RawBinding { Texture { raw: glow::Texture, target: BindTarget, - range: wgt::ImageSubresourceRange, }, Sampler(glow::Sampler), } @@ -466,6 +461,17 @@ enum Command { dst_target: BindTarget, dst_offset: wgt::BufferAddress, }, + ResetFramebuffer(wgt::Extent3d), + SetFramebufferAttachment { + attachment: u32, + view: TextureView, + }, + SetDrawColorBuffers(u8), + ClearColorF(u32, [f32; 4]), + ClearColorU(u32, [u32; 4]), + ClearColorI(u32, [i32; 4]), + ClearDepth(f32), + ClearStencil(u32), InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, @@ -484,6 +490,7 @@ struct CommandState { topology: u32, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, + has_pass_label: bool, } //TODO: we would have something like `Arc` diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 8de53613fd..91f42bd8c1 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -1,4 +1,5 @@ use super::Command as C; +use arrayvec::ArrayVec; use glow::HasContext; use std::{mem, ops::Range, slice}; @@ -291,6 +292,87 @@ impl super::Queue { gl.bind_buffer(dst_target, Some(dst)); gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data); } + C::ResetFramebuffer(extent) => { + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); + gl.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + glow::DEPTH_STENCIL_ATTACHMENT, + glow::TEXTURE_2D, + None, + 0, + ); + for i in 0..crate::MAX_COLOR_TARGETS { + let target = glow::COLOR_ATTACHMENT0 + i as u32; + gl.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + target, + glow::TEXTURE_2D, + None, + 0, + ); + } + gl.color_mask(true, true, true, true); + gl.depth_mask(true); + gl.stencil_mask(!0); + gl.disable(glow::DEPTH_TEST); + gl.disable(glow::STENCIL_TEST); + gl.disable(glow::SCISSOR_TEST); + gl.scissor(0, 0, extent.width as i32, extent.height as i32); + gl.viewport(0, 0, extent.width as i32, extent.height as i32); + } + C::SetFramebufferAttachment { + attachment, + ref view, + } => match view.inner { + super::TextureInner::Renderbuffer { raw } => { + gl.framebuffer_renderbuffer( + glow::DRAW_FRAMEBUFFER, + attachment, + glow::RENDERBUFFER, + Some(raw), + ); + } + super::TextureInner::Texture { raw, target } => { + if is_3d_target(target) { + gl.framebuffer_texture_layer( + glow::DRAW_FRAMEBUFFER, + attachment, + Some(raw), + view.base_mip_level as i32, + view.base_array_layer as i32, + ); + } else { + gl.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + attachment, + target, + Some(raw), + view.base_mip_level as i32, + ); + } + } + }, + C::SetDrawColorBuffers(count) => { + let indices = (0..count as u32) + .map(|i| glow::COLOR_ATTACHMENT0 + i) + .collect::>(); + gl.draw_buffers(&indices); + } + C::ClearColorF(draw_buffer, mut color) => { + gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, &mut color); + } + C::ClearColorU(draw_buffer, mut color) => { + gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, &mut color); + } + C::ClearColorI(draw_buffer, mut color) => { + gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, &mut color); + } + C::ClearDepth(depth) => { + gl.clear_buffer_depth_stencil(glow::DEPTH, 0, depth, 0); + } + C::ClearStencil(value) => { + gl.clear_buffer_depth_stencil(glow::STENCIL, 0, 0.0, value as i32); + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index c7092e7bdd..54158e5ee9 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -557,6 +557,8 @@ bitflags!( } ); +//TODO: it's not intuitive for the backends to consider `LOAD` being optional. + bitflags!( pub struct AttachmentOp: u8 { const LOAD = 1; @@ -1067,6 +1069,8 @@ pub struct DepthStencilAttachment<'a, A: Api> { #[derive(Clone, Debug)] pub struct RenderPassDescriptor<'a, A: Api> { pub label: Label<'a>, + pub extent: wgt::Extent3d, + pub sample_count: u32, pub color_attachments: &'a [ColorAttachment<'a, A>], pub depth_stencil_attachment: Option>, } diff --git a/wgpu-hal/src/vulkan/command.rs b/wgpu-hal/src/vulkan/command.rs index 32d4831074..7b1cd2b098 100644 --- a/wgpu-hal/src/vulkan/command.rs +++ b/wgpu-hal/src/vulkan/command.rs @@ -351,7 +351,11 @@ impl crate::CommandEncoder for super::CommandEncoder { let mut vk_clear_values = ArrayVec::<[vk::ClearValue; super::MAX_TOTAL_ATTACHMENTS]>::new(); let mut vk_image_views = ArrayVec::<[vk::ImageView; super::MAX_TOTAL_ATTACHMENTS]>::new(); let mut rp_key = super::RenderPassKey::default(); - let mut fb_key = super::FramebufferKey::default(); + let mut fb_key = super::FramebufferKey { + attachments: ArrayVec::default(), + extent: desc.extent, + sample_count: desc.sample_count, + }; let caps = &self.device.private_caps; for cat in desc.color_attachments { @@ -366,11 +370,11 @@ impl crate::CommandEncoder for super::CommandEncoder { .as_ref() .map(|target| target.make_attachment_key(crate::AttachmentOp::STORE, caps)), }); - fb_key.add(cat.target.view); + fb_key.attachments.push(cat.target.view.attachment.clone()); if let Some(ref at) = cat.resolve_target { vk_clear_values.push(mem::zeroed()); vk_image_views.push(at.view.raw); - fb_key.add(at.view); + fb_key.attachments.push(at.view.attachment.clone()); } } if let Some(ref ds) = desc.depth_stencil_attachment { @@ -385,26 +389,26 @@ impl crate::CommandEncoder for super::CommandEncoder { base: ds.target.make_attachment_key(ds.depth_ops, caps), stencil_ops: ds.stencil_ops, }); - fb_key.add(ds.target.view); + fb_key.attachments.push(ds.target.view.attachment.clone()); } rp_key.sample_count = fb_key.sample_count; let render_area = vk::Rect2D { offset: vk::Offset2D { x: 0, y: 0 }, extent: vk::Extent2D { - width: fb_key.extent.width, - height: fb_key.extent.height, + width: desc.extent.width, + height: desc.extent.height, }, }; let vk_viewports = [vk::Viewport { x: 0.0, y: if self.device.private_caps.flip_y_requires_shift { - fb_key.extent.height as f32 + desc.extent.height as f32 } else { 0.0 }, - width: fb_key.extent.width as f32, - height: -(fb_key.extent.height as f32), + width: desc.extent.width as f32, + height: -(desc.extent.height as f32), min_depth: 0.0, max_depth: 1.0, }]; diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 5574dca7f9..51bfbee127 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -5,7 +5,7 @@ use ash::{extensions::khr, version::DeviceV1_0, vk}; use inplace_it::inplace_or_alloc_from_iter; use parking_lot::Mutex; -use std::{borrow::Cow, cmp, collections::hash_map::Entry, ffi::CString, ptr, sync::Arc}; +use std::{borrow::Cow, collections::hash_map::Entry, ffi::CString, ptr, sync::Arc}; impl super::DeviceShared { pub(super) unsafe fn set_object_name( @@ -697,8 +697,6 @@ impl crate::Device for super::Device { dim: desc.dimension, aspects: crate::FormatAspect::from(desc.format), format_info: desc.format.describe(), - sample_count: desc.sample_count, - size: desc.size, raw_flags, }) } @@ -746,19 +744,8 @@ impl crate::Device for super::Device { raw_image_flags: texture.raw_flags, view_format: desc.format, }; - let sample_count = texture.sample_count; - let render_size = wgt::Extent3d { - width: cmp::max(1, texture.size.width >> desc.range.base_mip_level), - height: cmp::max(1, texture.size.height >> desc.range.base_mip_level), - depth_or_array_layers: 1, - }; - Ok(super::TextureView { - raw, - attachment, - sample_count, - render_size, - }) + Ok(super::TextureView { raw, attachment }) } unsafe fn destroy_texture_view(&self, view: super::TextureView) { if !self.shared.private_caps.imageless_framebuffers { diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index aa0708df8b..1563d33c28 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -638,8 +638,6 @@ impl crate::Surface for super::Surface { dim: wgt::TextureDimension::D2, aspects: crate::FormatAspect::COLOR, format_info: sc.config.format.describe(), - sample_count: 1, - size: sc.config.extent, raw_flags: vk::ImageCreateFlags::empty(), }, }; diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index a235c115d0..dd27836c7e 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -181,26 +181,13 @@ struct FramebufferAttachment { view_format: wgt::TextureFormat, } -#[derive(Clone, Eq, Default, Hash, PartialEq)] +#[derive(Clone, Eq, Hash, PartialEq)] struct FramebufferKey { attachments: ArrayVec<[FramebufferAttachment; MAX_TOTAL_ATTACHMENTS]>, extent: wgt::Extent3d, sample_count: u32, } -impl FramebufferKey { - fn add(&mut self, view: &TextureView) { - self.extent.width = self.extent.width.max(view.render_size.width); - self.extent.height = self.extent.height.max(view.render_size.height); - self.extent.depth_or_array_layers = self - .extent - .depth_or_array_layers - .max(view.render_size.depth_or_array_layers); - self.sample_count = self.sample_count.max(view.sample_count); - self.attachments.push(view.attachment.clone()); - } -} - struct DeviceShared { raw: ash::Device, instance: Arc, @@ -243,8 +230,6 @@ pub struct Texture { dim: wgt::TextureDimension, aspects: crate::FormatAspect, format_info: wgt::TextureFormatInfo, - sample_count: u32, - size: wgt::Extent3d, raw_flags: vk::ImageCreateFlags, } @@ -252,8 +237,6 @@ pub struct Texture { pub struct TextureView { raw: vk::ImageView, attachment: FramebufferAttachment, - sample_count: u32, - render_size: wgt::Extent3d, } impl TextureView { From 205327d3aa3a1adf4f18e9b9003360923c05f104 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 24 Jun 2021 11:56:49 -0400 Subject: [PATCH 15/33] hal/gles: barriers --- wgpu-hal/src/gles/adapter.rs | 1 + wgpu-hal/src/gles/command.rs | 38 +++++++++++++++++++++-- wgpu-hal/src/gles/device.rs | 7 +++-- wgpu-hal/src/gles/mod.rs | 7 ++++- wgpu-hal/src/gles/queue.rs | 58 ++++++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 5 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 1f3b66317f..0216e19f53 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -242,6 +242,7 @@ impl super::Adapter { super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER, ver >= (3, 1), ); + private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1)); Some(crate::ExposedAdapter { adapter: super::Adapter { diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 74ebb87807..d821f13186 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -32,16 +32,50 @@ impl crate::CommandEncoder for super::CommandEncoder { //TODO: could re-use the allocations in all these command buffers } - unsafe fn transition_buffers<'a, T>(&mut self, _barriers: T) + unsafe fn transition_buffers<'a, T>(&mut self, barriers: T) where T: Iterator>, { + if !self + .private_caps + .contains(super::PrivateCapability::MEMORY_BARRIERS) + { + return; + } + for bar in barriers { + // GLES only synchronizes storage -> anything explicitly + if !bar.usage.start.contains(crate::BufferUse::STORAGE_STORE) { + continue; + } + self.cmd_buffer + .commands + .push(C::BufferBarrier(bar.buffer.raw, bar.usage.end)); + } } - unsafe fn transition_textures<'a, T>(&mut self, _barriers: T) + unsafe fn transition_textures<'a, T>(&mut self, barriers: T) where T: Iterator>, { + if !self + .private_caps + .contains(super::PrivateCapability::MEMORY_BARRIERS) + { + return; + } + for bar in barriers { + // GLES only synchronizes storage -> anything explicitly + if !bar.usage.start.contains(crate::TextureUse::STORAGE_STORE) { + continue; + } + let raw = match bar.texture.inner { + super::TextureInner::Texture { raw, .. } => raw, + super::TextureInner::Renderbuffer { .. } => continue, + }; + self.cmd_buffer + .commands + .push(C::TextureBarrier(raw, bar.usage.end)); + } } unsafe fn fill_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange, value: u8) { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 048d7e8bbb..ef1e8ea2d2 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -31,7 +31,7 @@ impl CompilationContext<'_> { naga::StorageClass::Storage => super::BindingRegister::StorageBuffers, _ => continue, }; - //TODO: make Naga reflect all the names, not just textures + let br = var.binding.as_ref().unwrap(); let slot = self.layout.get_slot(br); @@ -519,6 +519,7 @@ impl crate::Device for super::Device { Ok(super::CommandEncoder { cmd_buffer: super::CommandBuffer::default(), state: super::CommandState::default(), + private_caps: self.shared.private_caps, }) } unsafe fn destroy_command_encoder(&self, _encoder: super::CommandEncoder) {} @@ -644,7 +645,9 @@ impl crate::Device for super::Device { ) -> Result { Ok(super::ShaderModule { naga: match shader { - crate::ShaderInput::SpirV(_) => panic!("Unable to pass-through SPIR-V"), + crate::ShaderInput::SpirV(_) => { + panic!("`Features::SPIRV_SHADER_PASSTHROUGH` is not enabled") + } crate::ShaderInput::Naga(naga) => naga, }, }) diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 60660a7654..7d7d9a9a0c 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -54,7 +54,9 @@ bitflags::bitflags! { /// change the exposed feature set. struct PrivateCapability: u32 { /// Support explicit layouts in shader. - const EXPLICIT_LAYOUTS_IN_SHADER = 0x00002000; + const EXPLICIT_LAYOUTS_IN_SHADER = 0x0001; + /// Support memory barriers. + const MEMORY_BARRIERS = 0x0002; } } @@ -472,6 +474,8 @@ enum Command { ClearColorI(u32, [i32; 4]), ClearDepth(f32), ClearStencil(u32), + BufferBarrier(glow::Buffer, crate::BufferUse), + TextureBarrier(glow::Texture, crate::TextureUse), InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, @@ -500,4 +504,5 @@ struct CommandState { pub struct CommandEncoder { cmd_buffer: CommandBuffer, state: CommandState, + private_caps: PrivateCapability, } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 91f42bd8c1..0692d86afe 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -373,6 +373,64 @@ impl super::Queue { C::ClearStencil(value) => { gl.clear_buffer_depth_stencil(glow::STENCIL, 0, 0.0, value as i32); } + C::BufferBarrier(raw, usage) => { + let mut flags = 0; + if usage.contains(crate::BufferUse::VERTEX) { + flags |= glow::VERTEX_ATTRIB_ARRAY_BARRIER_BIT; + gl.bind_buffer(glow::ARRAY_BUFFER, Some(raw)); + gl.vertex_attrib_pointer_f32(0, 1, glow::BYTE, true, 0, 0); + } + if usage.contains(crate::BufferUse::INDEX) { + flags |= glow::ELEMENT_ARRAY_BARRIER_BIT; + gl.bind_buffer(glow::ELEMENT_ARRAY_BUFFER, Some(raw)); + } + if usage.contains(crate::BufferUse::UNIFORM) { + flags |= glow::UNIFORM_BARRIER_BIT; + } + if usage.contains(crate::BufferUse::INDIRECT) { + flags |= glow::COMMAND_BARRIER_BIT; + gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(raw)); + } + if usage.contains(crate::BufferUse::COPY_SRC) { + flags |= glow::PIXEL_BUFFER_BARRIER_BIT; + gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(raw)); + } + if usage.contains(crate::BufferUse::COPY_DST) { + flags |= glow::PIXEL_BUFFER_BARRIER_BIT; + gl.bind_buffer(glow::PIXEL_PACK_BUFFER, Some(raw)); + } + if usage.intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) { + flags |= glow::BUFFER_UPDATE_BARRIER_BIT; + } + if usage + .intersects(crate::BufferUse::STORAGE_LOAD | crate::BufferUse::STORAGE_STORE) + { + flags |= glow::SHADER_STORAGE_BARRIER_BIT; + } + gl.memory_barrier(flags); + } + C::TextureBarrier(_raw, usage) => { + let mut flags = 0; + if usage.contains(crate::TextureUse::SAMPLED) { + flags |= glow::TEXTURE_FETCH_BARRIER_BIT; + } + if usage + .intersects(crate::TextureUse::STORAGE_LOAD | crate::TextureUse::STORAGE_STORE) + { + flags |= glow::SHADER_IMAGE_ACCESS_BARRIER_BIT; + } + if usage.contains(crate::TextureUse::COPY_DST) { + flags |= glow::TEXTURE_UPDATE_BARRIER_BIT; + } + if usage.intersects( + crate::TextureUse::COLOR_TARGET + | crate::TextureUse::DEPTH_STENCIL_READ + | crate::TextureUse::DEPTH_STENCIL_WRITE, + ) { + flags |= glow::FRAMEBUFFER_BARRIER_BIT; + } + gl.memory_barrier(flags); + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( From 13b0a61dc8a53e5f9ca4b9de6047d56a0d3fbda4 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 24 Jun 2021 17:19:26 -0400 Subject: [PATCH 16/33] hal/gles: stencil and vertex state --- wgpu-hal/src/gles/adapter.rs | 3 +- wgpu-hal/src/gles/command.rs | 185 ++++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/conv.rs | 41 ++++++++ wgpu-hal/src/gles/device.rs | 29 ++++-- wgpu-hal/src/gles/mod.rs | 105 +++++++++++++++++--- wgpu-hal/src/gles/queue.rs | 55 ++++++++++- 6 files changed, 377 insertions(+), 41 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 0216e19f53..1c96a9376e 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -232,7 +232,8 @@ impl super::Adapter { 0 }, max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32, - max_vertex_attributes: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32, + max_vertex_attributes: (gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32) + .min(super::MAX_VERTEX_ATTRIBUTES as u32), max_vertex_buffer_array_stride: 2048, max_push_constant_size: 0, }; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index d821f13186..24806fb21a 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -1,6 +1,26 @@ use super::{conv, Command as C}; +use arrayvec::ArrayVec; use std::{mem, ops::Range}; +bitflags::bitflags! { + #[derive(Default)] + struct Dirty: u32 { + const VERTEX_BUFFERS = 0x0001; + } +} + +#[derive(Default)] +pub(super) struct State { + topology: u32, + index_format: wgt::IndexFormat, + index_offset: wgt::BufferAddress, + vertex_buffers: [super::VertexBufferDesc; crate::MAX_VERTEX_BUFFERS], + vertex_attributes: ArrayVec<[super::AttributeDesc; super::MAX_VERTEX_ATTRIBUTES]>, + stencil: super::StencilState, + has_pass_label: bool, + dirty: Dirty, +} + impl super::CommandBuffer { fn clear(&mut self) { self.label = None; @@ -16,9 +36,62 @@ impl super::CommandBuffer { } } +impl super::CommandEncoder { + fn rebind_stencil_func(&mut self) { + fn make(s: &super::StencilSide, face: u32) -> C { + C::SetStencilFunc { + face, + function: s.function, + reference: s.reference, + read_mask: s.mask_read, + } + } + + let s = &self.state.stencil; + if s.front.function == s.back.function + && s.front.mask_read == s.back.mask_read + && s.front.reference == s.back.reference + { + self.cmd_buffer + .commands + .push(make(&s.front, glow::FRONT_AND_BACK)); + } else { + self.cmd_buffer.commands.push(make(&s.front, glow::FRONT)); + self.cmd_buffer.commands.push(make(&s.back, glow::BACK)); + } + } + + fn rebind_vertex_attributes(&mut self, first_instance: u32) { + for attribute in self.state.vertex_attributes.iter() { + let vb = self.state.vertex_buffers[attribute.buffer_index as usize].clone(); + + let mut vat = attribute.clone(); + vat.offset += vb.offset as u32; + + if vb.step == wgt::InputStepMode::Instance { + vat.offset += vb.stride * first_instance; + } + + self.cmd_buffer + .commands + .push(C::SetVertexAttribute(vat, vb)); + } + } + + fn prepare_draw(&mut self, first_instance: u32) { + if first_instance != 0 { + self.rebind_vertex_attributes(first_instance); + self.state.dirty.set(Dirty::VERTEX_BUFFERS, true); + } else if self.state.dirty.contains(Dirty::VERTEX_BUFFERS) { + self.rebind_vertex_attributes(0); + self.state.dirty.set(Dirty::VERTEX_BUFFERS, false); + } + } +} + impl crate::CommandEncoder for super::CommandEncoder { unsafe fn begin_encoding(&mut self, label: crate::Label) -> Result<(), crate::DeviceError> { - self.state = super::CommandState::default(); + self.state = State::default(); self.cmd_buffer.label = label.map(str::to_string); Ok(()) } @@ -63,18 +136,22 @@ impl crate::CommandEncoder for super::CommandEncoder { { return; } + + let mut combined_usage = crate::TextureUse::empty(); for bar in barriers { // GLES only synchronizes storage -> anything explicitly if !bar.usage.start.contains(crate::TextureUse::STORAGE_STORE) { continue; } - let raw = match bar.texture.inner { - super::TextureInner::Texture { raw, .. } => raw, - super::TextureInner::Renderbuffer { .. } => continue, - }; + // unlike buffers, there is no need for a concrete texture + // object to be bound anywhere for a barrier + combined_usage |= bar.usage.end; + } + + if !combined_usage.is_empty() { self.cmd_buffer .commands - .push(C::TextureBarrier(raw, bar.usage.end)); + .push(C::TextureBarrier(combined_usage)); } } @@ -235,9 +312,7 @@ impl crate::CommandEncoder for super::CommandEncoder { } // set the framebuffer - self.cmd_buffer - .commands - .push(C::ResetFramebuffer(desc.extent)); + self.cmd_buffer.commands.push(C::ResetFramebuffer); for (i, cat) in desc.color_attachments.iter().enumerate() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; self.cmd_buffer.commands.push(C::SetFramebufferAttachment { @@ -257,9 +332,22 @@ impl crate::CommandEncoder for super::CommandEncoder { }); } + // set the draw buffers and states self.cmd_buffer .commands .push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8)); + let rect = crate::Rect { + x: 0, + y: 0, + w: desc.extent.width as i32, + h: desc.extent.height as i32, + }; + self.cmd_buffer.commands.push(C::SetScissor(rect.clone())); + self.cmd_buffer.commands.push(C::SetViewport { + rect, + depth: 0.0..1.0, + }); + // issue the clears for (i, cat) in desc.color_attachments.iter().enumerate() { if !cat.ops.contains(crate::AttachmentOp::LOAD) { @@ -302,6 +390,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; } + self.state.dirty = Dirty::empty(); } unsafe fn set_bind_group( @@ -335,6 +424,46 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); + self.state.dirty |= Dirty::VERTEX_BUFFERS; + + self.state.vertex_attributes.clear(); + for vat in pipeline.vertex_attributes.iter() { + self.state.vertex_attributes.push(vat.clone()); + } + for (state_desc, pipe_desc) in self + .state + .vertex_buffers + .iter_mut() + .zip(pipeline.vertex_buffers.iter()) + { + state_desc.step = pipe_desc.step; + state_desc.stride = pipe_desc.stride; + } + + if let Some(ref stencil) = pipeline.stencil { + self.state.stencil = stencil.clone(); + self.rebind_stencil_func(); + if stencil.front.ops == stencil.back.ops + && stencil.front.mask_write == stencil.back.mask_write + { + self.cmd_buffer.commands.push(C::SetStencilOps { + face: glow::FRONT_AND_BACK, + write_mask: stencil.front.mask_write, + ops: stencil.front.ops.clone(), + }); + } else { + self.cmd_buffer.commands.push(C::SetStencilOps { + face: glow::FRONT, + write_mask: stencil.front.mask_write, + ops: stencil.front.ops.clone(), + }); + self.cmd_buffer.commands.push(C::SetStencilOps { + face: glow::BACK, + write_mask: stencil.back.mask_write, + ops: stencil.back.ops.clone(), + }); + } + } } unsafe fn set_index_buffer<'a>( @@ -353,10 +482,35 @@ impl crate::CommandEncoder for super::CommandEncoder { index: u32, binding: crate::BufferBinding<'a, super::Api>, ) { + self.state.dirty |= Dirty::VERTEX_BUFFERS; + let vb = &mut self.state.vertex_buffers[index as usize]; + vb.raw = binding.buffer.raw; + vb.offset = binding.offset; + } + unsafe fn set_viewport(&mut self, rect: &crate::Rect, depth: Range) { + self.cmd_buffer.commands.push(C::SetViewport { + rect: crate::Rect { + x: rect.x as i32, + y: rect.y as i32, + w: rect.w as i32, + h: rect.h as i32, + }, + depth, + }); + } + unsafe fn set_scissor_rect(&mut self, rect: &crate::Rect) { + self.cmd_buffer.commands.push(C::SetScissor(crate::Rect { + x: rect.x as i32, + y: rect.y as i32, + w: rect.w as i32, + h: rect.h as i32, + })); + } + unsafe fn set_stencil_reference(&mut self, value: u32) { + self.state.stencil.front.reference = value; + self.state.stencil.back.reference = value; + self.rebind_stencil_func(); } - 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( @@ -366,7 +520,7 @@ impl crate::CommandEncoder for super::CommandEncoder { start_instance: u32, instance_count: u32, ) { - debug_assert_eq!(start_instance, 0); + self.prepare_draw(start_instance); self.cmd_buffer.commands.push(C::Draw { topology: self.state.topology, start_vertex, @@ -382,7 +536,7 @@ impl crate::CommandEncoder for super::CommandEncoder { start_instance: u32, instance_count: u32, ) { - debug_assert_eq!(start_instance, 0); + self.prepare_draw(start_instance); let (index_size, index_type) = match self.state.index_format { wgt::IndexFormat::Uint16 => (2, glow::UNSIGNED_SHORT), wgt::IndexFormat::Uint32 => (4, glow::UNSIGNED_INT), @@ -403,6 +557,7 @@ impl crate::CommandEncoder for super::CommandEncoder { offset: wgt::BufferAddress, draw_count: u32, ) { + self.prepare_draw(0); for draw in 0..draw_count as wgt::BufferAddress { let indirect_offset = offset + draw * mem::size_of::() as wgt::BufferAddress; @@ -419,6 +574,7 @@ impl crate::CommandEncoder for super::CommandEncoder { offset: wgt::BufferAddress, draw_count: u32, ) { + self.prepare_draw(0); let index_type = match self.state.index_format { wgt::IndexFormat::Uint16 => glow::UNSIGNED_SHORT, wgt::IndexFormat::Uint32 => glow::UNSIGNED_INT, @@ -469,6 +625,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; } + self.state.dirty = Dirty::empty(); } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 3162e84e6e..a415fb5b38 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -232,3 +232,44 @@ pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { Tvd::D3 => glow::TEXTURE_3D, } } + +fn map_stencil_op(operation: wgt::StencilOperation) -> u32 { + use wgt::StencilOperation as So; + match operation { + So::Keep => glow::KEEP, + So::Zero => glow::ZERO, + So::Replace => glow::REPLACE, + So::Invert => glow::INVERT, + So::IncrementClamp => glow::INCR, + So::DecrementClamp => glow::DECR, + So::IncrementWrap => glow::INCR_WRAP, + So::DecrementWrap => glow::DECR_WRAP, + } +} + +fn map_stencil_ops(face: &wgt::StencilFaceState) -> super::StencilOps { + super::StencilOps { + pass: map_stencil_op(face.pass_op), + fail: map_stencil_op(face.fail_op), + depth_fail: map_stencil_op(face.depth_fail_op), + } +} + +pub(super) fn map_stencil(state: &wgt::StencilState) -> super::StencilState { + super::StencilState { + front: super::StencilSide { + function: map_compare_func(state.front.compare), + mask_read: state.read_mask, + mask_write: state.write_mask, + reference: 0, + ops: map_stencil_ops(&state.front), + }, + back: super::StencilSide { + function: map_compare_func(state.back.compare), + mask_read: state.read_mask, + mask_write: state.write_mask, + reference: 0, + ops: map_stencil_ops(&state.back), + }, + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index ef1e8ea2d2..a3042a809e 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -518,7 +518,7 @@ impl crate::Device for super::Device { ) -> Result { Ok(super::CommandEncoder { cmd_buffer: super::CommandBuffer::default(), - state: super::CommandState::default(), + state: Default::default(), private_caps: self.shared.private_caps, }) } @@ -665,11 +665,16 @@ impl crate::Device for super::Device { ); let inner = self.create_pipeline(shaders, desc.layout)?; - let attributes = { - let gl = &self.shared.context; + let (vertex_buffers, vertex_attributes) = { + let mut buffers = Vec::new(); let mut attributes = Vec::new(); - for (index, vb_layout) in desc.vertex_buffers.iter().enumerate() { + buffers.push(super::VertexBufferDesc { + raw: 0, + offset: 0, + step: vb_layout.step_mode, + stride: vb_layout.array_stride as u32, + }); for vat in vb_layout.attributes.iter() { let format_desc = conv::describe_vertex_format(vat.format); attributes.push(super::AttributeDesc { @@ -680,15 +685,23 @@ impl crate::Device for super::Device { }); } } - - attributes.into_boxed_slice() + (buffers.into_boxed_slice(), attributes.into_boxed_slice()) }; Ok(super::RenderPipeline { inner, primitive: desc.primitive, - attributes, - depth: desc.depth_stencil.clone(), + vertex_buffers, + vertex_attributes, + depth: desc.depth_stencil.as_ref().map(|ds| super::DepthState { + function: conv::map_compare_func(ds.depth_compare), + mask: ds.depth_write_enabled, + }), + depth_bias: desc.depth_stencil.as_ref().map(|ds| ds.bias), + stencil: desc + .depth_stencil + .as_ref() + .map(|ds| conv::map_stencil(&ds.stencil)), }) } unsafe fn destroy_render_pipeline(&self, pipeline: super::RenderPipeline) { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 7d7d9a9a0c..31ae5368df 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -22,6 +22,7 @@ pub struct Api; //Note: we can support more samplers if not every one of them is used at a time, // but it probably doesn't worth it. const MAX_TEXTURE_SLOTS: usize = 16; +const MAX_VERTEX_ATTRIBUTES: usize = 16; impl crate::Api for Api { type Instance = Instance; @@ -159,6 +160,12 @@ enum VertexAttribKind { //Double, // glVertexAttribLPointer } +impl Default for VertexAttribKind { + fn default() -> Self { + Self::Float + } +} + #[derive(Debug)] struct TextureFormatDesc { internal: u32, @@ -296,12 +303,14 @@ pub struct ShaderModule { naga: crate::NagaShader, } +#[derive(Clone, Debug, Default)] struct VertexFormatDesc { element_count: i32, element_format: u32, attrib_kind: VertexAttribKind, } +#[derive(Clone, Debug, Default)] struct AttributeDesc { location: u32, offset: u32, @@ -309,6 +318,14 @@ struct AttributeDesc { format_desc: VertexFormatDesc, } +#[derive(Clone, Debug, Default)] +struct VertexBufferDesc { + raw: glow::Buffer, + offset: wgt::BufferAddress, + step: wgt::InputStepMode, + stride: u32, +} + #[derive(Clone)] struct UniformDesc { location: glow::UniformLocation, @@ -326,13 +343,20 @@ struct PipelineInner { uniforms: Box<[UniformDesc]>, } +struct DepthState { + function: u32, + mask: bool, +} + pub struct RenderPipeline { inner: PipelineInner, //blend_targets: Vec, - attributes: Box<[AttributeDesc]>, - //vertex_buffers: Box<[wgt::VertexBufferLayout]>, + vertex_buffers: Box<[VertexBufferDesc]>, + vertex_attributes: Box<[AttributeDesc]>, primitive: wgt::PrimitiveState, - depth: Option, + depth: Option, + depth_bias: Option, + stencil: Option, } pub struct ComputePipeline { @@ -387,6 +411,50 @@ struct TextureCopyInfo { texel_size: u8, } +#[derive(Clone, Debug, PartialEq)] +struct StencilOps { + pass: u32, + fail: u32, + depth_fail: u32, +} + +impl Default for StencilOps { + fn default() -> Self { + Self { + pass: glow::KEEP, + fail: glow::KEEP, + depth_fail: glow::KEEP, + } + } +} + +#[derive(Clone, Debug, PartialEq)] +struct StencilSide { + function: u32, + mask_read: u32, + mask_write: u32, + reference: u32, + ops: StencilOps, +} + +impl Default for StencilSide { + fn default() -> Self { + Self { + function: glow::ALWAYS, + mask_read: 0xFF, + mask_write: 0xFF, + reference: 0, + ops: StencilOps::default(), + } + } +} + +#[derive(Clone, Default)] +struct StencilState { + front: StencilSide, + back: StencilSide, +} + #[derive(Debug)] enum Command { Draw { @@ -463,7 +531,7 @@ enum Command { dst_target: BindTarget, dst_offset: wgt::BufferAddress, }, - ResetFramebuffer(wgt::Extent3d), + ResetFramebuffer, SetFramebufferAttachment { attachment: u32, view: TextureView, @@ -475,7 +543,24 @@ enum Command { ClearDepth(f32), ClearStencil(u32), BufferBarrier(glow::Buffer, crate::BufferUse), - TextureBarrier(glow::Texture, crate::TextureUse), + TextureBarrier(crate::TextureUse), + SetViewport { + rect: crate::Rect, + depth: Range, + }, + SetScissor(crate::Rect), + SetStencilFunc { + face: u32, + function: u32, + reference: u32, + read_mask: u32, + }, + SetStencilOps { + face: u32, + write_mask: u32, + ops: StencilOps, + }, + SetVertexAttribute(AttributeDesc, VertexBufferDesc), InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, @@ -489,20 +574,12 @@ pub struct CommandBuffer { data_words: Vec, } -#[derive(Default)] -struct CommandState { - topology: u32, - index_format: wgt::IndexFormat, - index_offset: wgt::BufferAddress, - has_pass_label: bool, -} - //TODO: we would have something like `Arc` // here and in the command buffers. So that everything grows // inside the encoder and stays there until `reset_all`. pub struct CommandEncoder { cmd_buffer: CommandBuffer, - state: CommandState, + state: command::State, private_caps: PrivateCapability, } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 0692d86afe..3f914b2665 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -292,7 +292,7 @@ impl super::Queue { gl.bind_buffer(dst_target, Some(dst)); gl.buffer_sub_data_u8_slice(dst_target, dst_offset as i32, query_data); } - C::ResetFramebuffer(extent) => { + C::ResetFramebuffer => { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); gl.framebuffer_texture_2d( glow::DRAW_FRAMEBUFFER, @@ -317,8 +317,6 @@ impl super::Queue { gl.disable(glow::DEPTH_TEST); gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); - gl.scissor(0, 0, extent.width as i32, extent.height as i32); - gl.viewport(0, 0, extent.width as i32, extent.height as i32); } C::SetFramebufferAttachment { attachment, @@ -409,7 +407,7 @@ impl super::Queue { } gl.memory_barrier(flags); } - C::TextureBarrier(_raw, usage) => { + C::TextureBarrier(usage) => { let mut flags = 0; if usage.contains(crate::TextureUse::SAMPLED) { flags |= glow::TEXTURE_FETCH_BARRIER_BIT; @@ -431,6 +429,55 @@ impl super::Queue { } gl.memory_barrier(flags); } + C::SetViewport { + ref rect, + ref depth, + } => { + gl.viewport(rect.x, rect.y, rect.w, rect.h); + gl.depth_range_f32(depth.start, depth.end); + } + C::SetScissor(ref rect) => { + gl.scissor(rect.x, rect.y, rect.w, rect.h); + } + C::SetStencilFunc { + face, + function, + reference, + read_mask, + } => { + gl.stencil_func_separate(face, function, reference as i32, read_mask); + } + C::SetStencilOps { + face, + write_mask, + ref ops, + } => { + gl.stencil_mask_separate(face, write_mask); + gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass); + } + C::SetVertexAttribute(ref vat, ref vb) => { + gl.bind_buffer(glow::ARRAY_BUFFER, Some(vb.raw)); + let offset = vat.offset as i32 + vb.offset as i32; + match vat.format_desc.attrib_kind { + super::VertexAttribKind::Float => gl.vertex_attrib_pointer_f32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + true, // always normalized + vb.stride as i32, + offset, + ), + super::VertexAttribKind::Integer => gl.vertex_attrib_pointer_i32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + vb.stride as i32, + offset, + ), + } + gl.vertex_attrib_divisor(vat.location, vb.step as u32); + gl.enable_vertex_attrib_array(vat.location); + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( From 91df1574629128081a40b7c26eee2e7a589dabc3 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 00:52:12 -0400 Subject: [PATCH 17/33] Refactor downlevel support a bit, implement blending for hal/gles --- wgpu-core/src/command/compute.rs | 18 +---- wgpu-core/src/command/mod.rs | 4 +- wgpu-core/src/device/mod.rs | 37 ++++++++-- wgpu-core/src/pipeline.rs | 13 ++-- wgpu-hal/src/gles/adapter.rs | 6 +- wgpu-hal/src/gles/command.rs | 89 +++++++++++++++++++---- wgpu-hal/src/gles/conv.rs | 40 ++++++++++ wgpu-hal/src/gles/device.rs | 30 ++++++-- wgpu-hal/src/gles/mod.rs | 49 +++++++++++-- wgpu-hal/src/gles/queue.rs | 121 +++++++++++++++++++++++++++++-- wgpu-types/src/lib.rs | 16 ++-- 11 files changed, 344 insertions(+), 79 deletions(-) diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index a9cec8ac43..c698dc0860 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -11,7 +11,7 @@ use crate::{ resource::{Buffer, Texture}, track::{StatefulTrackerSubset, TrackerSet, UsageConflict, UseExtendError}, validation::{check_buffer_usage, MissingBufferUsageError}, - Label, DOWNLEVEL_ERROR_WARNING_MESSAGE, + Label, }; use hal::CommandEncoder as _; @@ -149,11 +149,6 @@ pub enum ComputePassErrorInner { MissingBufferUsage(#[from] MissingBufferUsageError), #[error("cannot pop debug group, because number of pushed debug groups is zero")] InvalidPopDebugGroup, - #[error( - "Compute shaders are not supported by the underlying platform. {}", - DOWNLEVEL_ERROR_WARNING_MESSAGE - )] - ComputeShadersUnsupported, #[error(transparent)] Dispatch(#[from] DispatchError), #[error(transparent)] @@ -276,17 +271,6 @@ impl Global { }); } - if !cmd_buf - .downlevel - .flags - .contains(wgt::DownlevelFlags::COMPUTE_SHADERS) - { - return Err(ComputePassError { - scope: PassErrorScope::Pass(encoder_id), - inner: ComputePassErrorInner::ComputeShadersUnsupported, - }); - } - let (_, mut token) = hub.render_bundles.read(&mut token); let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index d40b99132b..9a2292f202 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -77,7 +77,6 @@ pub struct CommandBuffer { pub(crate) used_swap_chains: SmallVec<[Stored; 1]>, pub(crate) buffer_memory_init_actions: Vec>, limits: wgt::Limits, - downlevel: wgt::DownlevelCapabilities, support_fill_buffer_texture: bool, #[cfg(feature = "trace")] pub(crate) commands: Option>, @@ -88,7 +87,7 @@ impl CommandBuffer { encoder: A::CommandEncoder, device_id: Stored, limits: wgt::Limits, - downlevel: wgt::DownlevelCapabilities, + _downlevel: wgt::DownlevelCapabilities, features: wgt::Features, #[cfg(feature = "trace")] enable_tracing: bool, label: &Label, @@ -106,7 +105,6 @@ impl CommandBuffer { used_swap_chains: Default::default(), buffer_memory_init_actions: Default::default(), limits, - downlevel, support_fill_buffer_texture: features.contains(wgt::Features::CLEAR_COMMANDS), #[cfg(feature = "trace")] commands: if enable_tracing { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 7de5970bc2..555c0501a7 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -8,6 +8,7 @@ use crate::{ track::{BufferState, TextureSelector, TextureState, TrackerSet, UsageConflict}, validation::{self, check_buffer_usage, check_texture_usage}, FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, Stored, SubmissionIndex, + DOWNLEVEL_ERROR_WARNING_MESSAGE, }; use arrayvec::ArrayVec; @@ -319,6 +320,17 @@ impl Device { } } + pub(crate) fn require_downlevel_flags( + &self, + flags: wgt::DownlevelFlags, + ) -> Result<(), MissingDownlevelFlags> { + if self.downlevel.flags.contains(flags) { + Ok(()) + } else { + Err(MissingDownlevelFlags(flags)) + } + } + fn lock_life_internal<'this, 'token: 'this>( tracker: &'this Mutex>, _token: &mut Token<'token, Self>, @@ -1729,13 +1741,7 @@ impl Device { } } - if !self - .downlevel - .flags - .contains(wgt::DownlevelFlags::COMPUTE_SHADERS) - { - return Err(pipeline::CreateComputePipelineError::ComputeShadersUnsupported); - } + self.require_downlevel_flags(wgt::DownlevelFlags::COMPUTE_SHADERS)?; let mut derived_group_layouts = ArrayVec::<[binding_model::BindEntryMap; hal::MAX_BIND_GROUPS]>::new(); @@ -1858,6 +1864,16 @@ impl Device { .map_or(&[][..], |fragment| &fragment.targets); let depth_stencil_state = desc.depth_stencil.as_ref(); + if !color_targets.is_empty() && { + let first = &color_targets[0]; + color_targets[1..] + .iter() + .any(|ct| ct.write_mask != first.write_mask || ct.blend != first.blend) + } { + log::error!("Color targets: {:?}", color_targets); + self.require_downlevel_flags(wgt::DownlevelFlags::INDEPENDENT_BLENDING)?; + } + let mut io = validation::StageIo::default(); let mut validated_stages = wgt::ShaderStage::empty(); @@ -2405,6 +2421,13 @@ impl From for DeviceError { #[error("Features {0:?} are required but not enabled on the device")] pub struct MissingFeatures(pub wgt::Features); +#[derive(Clone, Debug, Error)] +#[error( + "Downlevel flags {0:?} are required but not supported on the device. {}", + DOWNLEVEL_ERROR_WARNING_MESSAGE +)] +pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags); + #[derive(Clone, Debug)] #[cfg_attr(feature = "trace", derive(serde::Serialize))] #[cfg_attr(feature = "replay", derive(serde::Deserialize))] diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 6d9510a5f0..9d32afd0b6 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -1,9 +1,9 @@ use crate::{ binding_model::{CreateBindGroupLayoutError, CreatePipelineLayoutError}, - device::{DeviceError, MissingFeatures, RenderPassContext}, + device::{DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext}, hub::Resource, id::{DeviceId, PipelineLayoutId, ShaderModuleId}, - validation, Label, LifeGuard, Stored, DOWNLEVEL_ERROR_WARNING_MESSAGE, + validation, Label, LifeGuard, Stored, }; use std::borrow::Cow; use thiserror::Error; @@ -109,11 +109,8 @@ pub enum CreateComputePipelineError { Stage(#[from] validation::StageError), #[error("Internal error: {0}")] Internal(String), - #[error( - "Compute shaders are not supported by the underlying platform. {}", - DOWNLEVEL_ERROR_WARNING_MESSAGE - )] - ComputeShadersUnsupported, + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } #[derive(Debug)] @@ -258,6 +255,8 @@ pub enum CreateRenderPipelineError { ConservativeRasterizationNonFillPolygonMode, #[error(transparent)] MissingFeatures(#[from] MissingFeatures), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error("error matching {stage:?} shader requirements against the pipeline")] Stage { stage: wgt::ShaderStage, diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 1c96a9376e..6ab35ad74d 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -52,7 +52,7 @@ impl super::Adapter { None => false, }; - let (version, vendor_info) = match src.find(' ') { + let (version, _vendor_info) = match src.find(' ') { Some(i) => (&src[..i], src[i + 1..].to_string()), None => (src, String::new()), }; @@ -196,6 +196,10 @@ impl super::Adapter { ); downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1)); downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2)); + downlevel_flags.set( + wgt::DownlevelFlags::INDEPENDENT_BLENDING, + ver >= (3, 2) || extensions.contains("GL_EXT_draw_buffers_indexed"), + ); let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 24806fb21a..8d7423b94a 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -14,9 +14,11 @@ pub(super) struct State { topology: u32, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, - vertex_buffers: [super::VertexBufferDesc; crate::MAX_VERTEX_BUFFERS], + vertex_buffers: [(super::VertexBufferDesc, super::BufferBinding); crate::MAX_VERTEX_BUFFERS], vertex_attributes: ArrayVec<[super::AttributeDesc; super::MAX_VERTEX_ATTRIBUTES]>, + color_targets: ArrayVec<[super::ColorTargetDesc; crate::MAX_COLOR_TARGETS]>, stencil: super::StencilState, + depth_bias: wgt::DepthBiasState, has_pass_label: bool, dirty: Dirty, } @@ -63,18 +65,19 @@ impl super::CommandEncoder { fn rebind_vertex_attributes(&mut self, first_instance: u32) { for attribute in self.state.vertex_attributes.iter() { - let vb = self.state.vertex_buffers[attribute.buffer_index as usize].clone(); + let (buffer_desc, buffer) = + self.state.vertex_buffers[attribute.buffer_index as usize].clone(); - let mut vat = attribute.clone(); - vat.offset += vb.offset as u32; - - if vb.step == wgt::InputStepMode::Instance { - vat.offset += vb.stride * first_instance; + let mut attribute_desc = attribute.clone(); + if buffer_desc.step == wgt::InputStepMode::Instance { + attribute_desc.offset += buffer_desc.stride * first_instance; } - self.cmd_buffer - .commands - .push(C::SetVertexAttribute(vat, vb)); + self.cmd_buffer.commands.push(C::SetVertexAttribute { + buffer_desc, + buffer, + attribute_desc, + }); } } @@ -391,6 +394,8 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.has_pass_label = false; } self.state.dirty = Dirty::empty(); + self.state.color_targets.clear(); + self.state.vertex_attributes.clear(); } unsafe fn set_bind_group( @@ -426,11 +431,15 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); self.state.dirty |= Dirty::VERTEX_BUFFERS; + self.cmd_buffer + .commands + .push(C::SetProgram(pipeline.inner.program)); + self.state.vertex_attributes.clear(); for vat in pipeline.vertex_attributes.iter() { self.state.vertex_attributes.push(vat.clone()); } - for (state_desc, pipe_desc) in self + for (&mut (ref mut state_desc, _), pipe_desc) in self .state .vertex_buffers .iter_mut() @@ -440,7 +449,19 @@ impl crate::CommandEncoder for super::CommandEncoder { state_desc.stride = pipe_desc.stride; } + let mut aspects = crate::FormatAspect::empty(); + if pipeline.depth_bias != self.state.depth_bias { + self.state.depth_bias = pipeline.depth_bias; + self.cmd_buffer + .commands + .push(C::SetDepthBias(pipeline.depth_bias)); + } + if let Some(ref depth) = pipeline.depth { + aspects |= crate::FormatAspect::DEPTH; + self.cmd_buffer.commands.push(C::SetDepth(depth.clone())); + } if let Some(ref stencil) = pipeline.stencil { + aspects |= crate::FormatAspect::STENCIL; self.state.stencil = stencil.clone(); self.rebind_stencil_func(); if stencil.front.ops == stencil.back.ops @@ -464,6 +485,34 @@ impl crate::CommandEncoder for super::CommandEncoder { }); } } + self.cmd_buffer + .commands + .push(C::ConfigureDepthStencil(aspects)); + + if self.state.color_targets[..] != pipeline.color_targets[..] { + if pipeline + .color_targets + .iter() + .skip(1) + .any(|ct| *ct != pipeline.color_targets[0]) + { + for (index, ct) in pipeline.color_targets.iter().enumerate() { + self.cmd_buffer.commands.push(C::SetColorTarget { + draw_buffer_index: Some(index as u32), + desc: ct.clone(), + }); + } + } else { + self.cmd_buffer.commands.push(C::SetColorTarget { + draw_buffer_index: None, + desc: pipeline.color_targets.first().cloned().unwrap_or_default(), + }); + } + } + self.state.color_targets.clear(); + for ct in pipeline.color_targets.iter() { + self.state.color_targets.push(ct.clone()); + } } unsafe fn set_index_buffer<'a>( @@ -483,7 +532,7 @@ impl crate::CommandEncoder for super::CommandEncoder { binding: crate::BufferBinding<'a, super::Api>, ) { self.state.dirty |= Dirty::VERTEX_BUFFERS; - let vb = &mut self.state.vertex_buffers[index as usize]; + let vb = &mut self.state.vertex_buffers[index as usize].1; vb.raw = binding.buffer.raw; vb.offset = binding.offset; } @@ -511,7 +560,15 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.stencil.back.reference = value; self.rebind_stencil_func(); } - unsafe fn set_blend_constants(&mut self, color: &wgt::Color) {} + unsafe fn set_blend_constants(&mut self, color: &wgt::Color) { + let color = [ + color.r as f32, + color.g as f32, + color.b as f32, + color.a as f32, + ]; + self.cmd_buffer.commands.push(C::SetBlendConstant(color)); + } unsafe fn draw( &mut self, @@ -628,7 +685,11 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.dirty = Dirty::empty(); } - unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) {} + unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { + self.cmd_buffer + .commands + .push(C::SetProgram(pipeline.inner.program)); + } unsafe fn dispatch(&mut self, count: [u32; 3]) { self.cmd_buffer.commands.push(C::Dispatch(count)); diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index a415fb5b38..cc75b68d5f 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -273,3 +273,43 @@ pub(super) fn map_stencil(state: &wgt::StencilState) -> super::StencilState { }, } } + +fn map_blend_factor(factor: wgt::BlendFactor) -> u32 { + use wgt::BlendFactor as Bf; + match factor { + Bf::Zero => glow::ZERO, + Bf::One => glow::ONE, + Bf::Src => glow::SRC_COLOR, + Bf::OneMinusSrc => glow::ONE_MINUS_SRC_COLOR, + Bf::Dst => glow::DST_COLOR, + Bf::OneMinusDst => glow::ONE_MINUS_DST_COLOR, + Bf::SrcAlpha => glow::SRC_ALPHA, + Bf::OneMinusSrcAlpha => glow::ONE_MINUS_SRC_ALPHA, + Bf::DstAlpha => glow::DST_ALPHA, + Bf::OneMinusDstAlpha => glow::ONE_MINUS_DST_ALPHA, + Bf::Constant => glow::CONSTANT_COLOR, + Bf::OneMinusConstant => glow::ONE_MINUS_CONSTANT_COLOR, + Bf::SrcAlphaSaturated => glow::SRC_ALPHA_SATURATE, + } +} + +fn map_blend_component(component: &wgt::BlendComponent) -> super::BlendComponent { + super::BlendComponent { + src: map_blend_factor(component.src_factor), + dst: map_blend_factor(component.dst_factor), + equation: match component.operation { + wgt::BlendOperation::Add => glow::FUNC_ADD, + wgt::BlendOperation::Subtract => glow::FUNC_SUBTRACT, + wgt::BlendOperation::ReverseSubtract => glow::FUNC_REVERSE_SUBTRACT, + wgt::BlendOperation::Min => glow::MIN, + wgt::BlendOperation::Max => glow::MAX, + }, + } +} + +pub(super) fn map_blend(blend: &wgt::BlendState) -> super::BlendDesc { + super::BlendDesc { + color: map_blend_component(&blend.color), + alpha: map_blend_component(&blend.alpha), + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index a3042a809e..8da560e492 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -465,7 +465,7 @@ impl crate::Device for super::Device { super::TextureInner::Renderbuffer { raw, .. } => { gl.delete_renderbuffer(raw); } - super::TextureInner::Texture { raw, target } => { + super::TextureInner::Texture { raw, .. } => { gl.delete_texture(raw); } } @@ -514,7 +514,7 @@ impl crate::Device for super::Device { unsafe fn create_command_encoder( &self, - desc: &crate::CommandEncoderDescriptor, + _desc: &crate::CommandEncoderDescriptor, ) -> Result { Ok(super::CommandEncoder { cmd_buffer: super::CommandBuffer::default(), @@ -585,7 +585,7 @@ impl crate::Device for super::Device { group_infos: group_infos.into_boxed_slice(), }) } - unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {} + unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: super::PipelineLayout) {} unsafe fn create_bind_group( &self, @@ -640,7 +640,7 @@ impl crate::Device for super::Device { unsafe fn create_shader_module( &self, - desc: &crate::ShaderModuleDescriptor, + _desc: &crate::ShaderModuleDescriptor, shader: crate::ShaderInput, ) -> Result { Ok(super::ShaderModule { @@ -670,8 +670,6 @@ impl crate::Device for super::Device { let mut attributes = Vec::new(); for (index, vb_layout) in desc.vertex_buffers.iter().enumerate() { buffers.push(super::VertexBufferDesc { - raw: 0, - offset: 0, step: vb_layout.step_mode, stride: vb_layout.array_stride as u32, }); @@ -688,16 +686,34 @@ impl crate::Device for super::Device { (buffers.into_boxed_slice(), attributes.into_boxed_slice()) }; + let color_targets = { + let mut targets = Vec::new(); + for ct in desc.color_targets.iter() { + targets.push(super::ColorTargetDesc { + mask: ct.write_mask, + blend: ct.blend.as_ref().map(conv::map_blend), + }); + } + //Note: if any of the states are different, and `INDEPENDENT_BLEND` flag + // is not exposed, then this pipeline will not bind correctly. + targets.into_boxed_slice() + }; + Ok(super::RenderPipeline { inner, primitive: desc.primitive, vertex_buffers, vertex_attributes, + color_targets, depth: desc.depth_stencil.as_ref().map(|ds| super::DepthState { function: conv::map_compare_func(ds.depth_compare), mask: ds.depth_write_enabled, }), - depth_bias: desc.depth_stencil.as_ref().map(|ds| ds.bias), + depth_bias: desc + .depth_stencil + .as_ref() + .map(|ds| ds.bias) + .unwrap_or_default(), stencil: desc .depth_stencil .as_ref() diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 31ae5368df..53dd24e8a1 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - #[cfg(not(target_arch = "wasm32"))] mod egl; @@ -319,9 +317,13 @@ struct AttributeDesc { } #[derive(Clone, Debug, Default)] -struct VertexBufferDesc { +struct BufferBinding { raw: glow::Buffer, offset: wgt::BufferAddress, +} + +#[derive(Clone, Debug, Default)] +struct VertexBufferDesc { step: wgt::InputStepMode, stride: u32, } @@ -343,19 +345,39 @@ struct PipelineInner { uniforms: Box<[UniformDesc]>, } +#[derive(Clone, Debug)] struct DepthState { function: u32, mask: bool, } +#[derive(Clone, Debug, PartialEq)] +struct BlendComponent { + src: u32, + dst: u32, + equation: u32, +} + +#[derive(Clone, Debug, PartialEq)] +struct BlendDesc { + alpha: BlendComponent, + color: BlendComponent, +} + +#[derive(Clone, Debug, Default, PartialEq)] +struct ColorTargetDesc { + mask: wgt::ColorWrite, + blend: Option, +} + pub struct RenderPipeline { inner: PipelineInner, - //blend_targets: Vec, + primitive: wgt::PrimitiveState, vertex_buffers: Box<[VertexBufferDesc]>, vertex_attributes: Box<[AttributeDesc]>, - primitive: wgt::PrimitiveState, + color_targets: Box<[ColorTargetDesc]>, depth: Option, - depth_bias: Option, + depth_bias: wgt::DepthBiasState, stencil: Option, } @@ -560,7 +582,20 @@ enum Command { write_mask: u32, ops: StencilOps, }, - SetVertexAttribute(AttributeDesc, VertexBufferDesc), + SetDepth(DepthState), + SetDepthBias(wgt::DepthBiasState), + ConfigureDepthStencil(crate::FormatAspect), + SetVertexAttribute { + buffer: BufferBinding, + buffer_desc: VertexBufferDesc, + attribute_desc: AttributeDesc, + }, + SetProgram(glow::Program), + SetBlendConstant([f32; 4]), + SetColorTarget { + draw_buffer_index: Option, + desc: ColorTargetDesc, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 3f914b2665..9f51204c53 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -17,6 +17,16 @@ fn is_3d_target(target: super::BindTarget) -> bool { } impl super::Queue { + unsafe fn reset_state(&self) { + let gl = &self.shared.context; + gl.use_program(None); + gl.polygon_offset(0.0, 0.0); + gl.disable(glow::DEPTH_TEST); + gl.disable(glow::STENCIL_TEST); + gl.disable(glow::SCISSOR_TEST); + gl.disable(glow::BLEND); + } + unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) { let gl = &self.shared.context; match *command { @@ -161,7 +171,7 @@ impl super::Queue { } C::CopyBufferToTexture { src, - src_target, + src_target: _, dst, dst_target, ref dst_info, @@ -213,7 +223,7 @@ impl super::Queue { src_target, ref src_info, dst, - dst_target, + dst_target: _, ref copy, } => { //TODO: compressed data @@ -355,6 +365,9 @@ impl super::Queue { .map(|i| glow::COLOR_ATTACHMENT0 + i) .collect::>(); gl.draw_buffers(&indices); + for draw_buffer in 0..count as u32 { + gl.disable_draw_buffer(glow::BLEND, draw_buffer); + } } C::ClearColorF(draw_buffer, mut color) => { gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, &mut color); @@ -438,6 +451,7 @@ impl super::Queue { } C::SetScissor(ref rect) => { gl.scissor(rect.x, rect.y, rect.w, rect.h); + gl.enable(glow::SCISSOR_TEST); } C::SetStencilFunc { face, @@ -455,29 +469,119 @@ impl super::Queue { gl.stencil_mask_separate(face, write_mask); gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass); } - C::SetVertexAttribute(ref vat, ref vb) => { - gl.bind_buffer(glow::ARRAY_BUFFER, Some(vb.raw)); - let offset = vat.offset as i32 + vb.offset as i32; + C::SetVertexAttribute { + ref buffer_desc, + ref buffer, + attribute_desc: ref vat, + } => { + gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer.raw)); + let offset = vat.offset as i32 + buffer.offset as i32; match vat.format_desc.attrib_kind { super::VertexAttribKind::Float => gl.vertex_attrib_pointer_f32( vat.location, vat.format_desc.element_count, vat.format_desc.element_format, true, // always normalized - vb.stride as i32, + buffer_desc.stride as i32, offset, ), super::VertexAttribKind::Integer => gl.vertex_attrib_pointer_i32( vat.location, vat.format_desc.element_count, vat.format_desc.element_format, - vb.stride as i32, + buffer_desc.stride as i32, offset, ), } - gl.vertex_attrib_divisor(vat.location, vb.step as u32); + gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32); gl.enable_vertex_attrib_array(vat.location); } + C::SetDepth(ref depth) => { + gl.depth_func(depth.function); + gl.depth_mask(depth.mask); + } + C::SetDepthBias(bias) => { + gl.polygon_offset(bias.constant as f32, bias.slope_scale); + } + C::ConfigureDepthStencil(aspects) => { + if aspects.contains(crate::FormatAspect::DEPTH) { + gl.enable(glow::DEPTH_TEST); + } else { + gl.disable(glow::DEPTH_TEST); + } + if aspects.contains(crate::FormatAspect::STENCIL) { + gl.enable(glow::STENCIL_TEST); + } else { + gl.disable(glow::STENCIL_TEST); + } + } + C::SetProgram(program) => { + gl.use_program(Some(program)); + } + C::SetBlendConstant(c) => { + gl.blend_color(c[0], c[1], c[2], c[3]); + } + C::SetColorTarget { + draw_buffer_index, + desc: super::ColorTargetDesc { mask, ref blend }, + } => { + use wgt::ColorWrite as Cw; + if let Some(index) = draw_buffer_index { + gl.color_mask_draw_buffer( + index, + mask.contains(Cw::RED), + mask.contains(Cw::GREEN), + mask.contains(Cw::BLUE), + mask.contains(Cw::ALPHA), + ); + if let Some(ref blend) = *blend { + gl.enable_draw_buffer(index, glow::BLEND); + if blend.color != blend.alpha { + gl.blend_equation_separate_draw_buffer( + index, + blend.color.equation, + blend.alpha.equation, + ); + gl.blend_func_separate_draw_buffer( + index, + blend.color.src, + blend.color.dst, + blend.alpha.src, + blend.alpha.dst, + ); + } else { + gl.blend_equation_draw_buffer(index, blend.color.equation); + gl.blend_func_draw_buffer(index, blend.color.src, blend.color.dst); + } + } else { + gl.disable_draw_buffer(index, glow::BLEND); + } + } else { + gl.color_mask( + mask.contains(Cw::RED), + mask.contains(Cw::GREEN), + mask.contains(Cw::BLUE), + mask.contains(Cw::ALPHA), + ); + if let Some(ref blend) = *blend { + gl.enable(glow::BLEND); + if blend.color != blend.alpha { + gl.blend_equation_separate(blend.color.equation, blend.alpha.equation); + gl.blend_func_separate( + blend.color.src, + blend.color.dst, + blend.alpha.src, + blend.alpha.dst, + ); + } else { + gl.blend_equation(blend.color.equation); + gl.blend_func(blend.color.src, blend.color.dst); + } + } else { + gl.disable(glow::BLEND); + } + } + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( @@ -505,6 +609,7 @@ impl crate::Queue for super::Queue { command_buffers: &[&super::CommandBuffer], signal_fence: Option<(&mut super::Fence, crate::FenceValue)>, ) -> Result<(), crate::DeviceError> { + self.reset_state(); for cmd_buf in command_buffers.iter() { for command in cmd_buf.commands.iter() { self.process(command, &cmd_buf.data_bytes, &cmd_buf.data_words); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 99fffc8ef1..94016d881f 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -625,24 +625,24 @@ bitflags::bitflags! { const INDIRECT_EXECUTION = 0x0000_0004; /// Supports non-zero `base_vertex` parameter to indexed draw calls. const BASE_VERTEX = 0x0000_0008; - /// Supports non-zero `base_instance` parameter to draw calls. - const BASE_INSTANCE = 0x0000_0010; /// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil attachment. - const READ_ONLY_DEPTH_STENCIL = 0x0000_0020; + const READ_ONLY_DEPTH_STENCIL = 0x0000_0010; /// Supports: /// - copy_image_to_image /// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage - const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0040; + const DEVICE_LOCAL_IMAGE_COPIES = 0x0000_0020; /// Supports textures with mipmaps which have a non power of two size. - const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0080; + const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 0x0000_0040; /// Supports textures that are cube arrays. - const CUBE_ARRAY_TEXTURES = 0x0000_0100; + const CUBE_ARRAY_TEXTURES = 0x0000_0080; /// Supports comparison samplers. - const COMPARISON_SAMPLERS = 0x0000_0200; + const COMPARISON_SAMPLERS = 0x0000_0100; + /// Supports different blending modes per color target. + const INDEPENDENT_BLENDING = 0x0000_0200; /// Supports samplers with anisotropic filtering const ANISOTROPIC_FILTERING = 0x0001_0000; /// All flags are in their compliant state. - const COMPLIANT = 0x0000_02FF; + const COMPLIANT = 0x0000_13FF; } } From 673ec6039670a81e0952073c737aa80ccfebfc6b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 01:36:21 -0400 Subject: [PATCH 18/33] hal/gles: resource binding --- wgpu-hal/src/gles/command.rs | 128 ++++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/device.rs | 10 +-- wgpu-hal/src/gles/egl.rs | 22 ++++-- wgpu-hal/src/gles/mod.rs | 19 ++++-- wgpu-hal/src/gles/queue.rs | 20 ++++++ 5 files changed, 170 insertions(+), 29 deletions(-) diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 8d7423b94a..d23845e381 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -9,6 +9,12 @@ bitflags::bitflags! { } } +#[derive(Clone, Copy, Debug, Default)] +struct TextureSlotDesc { + tex_target: super::BindTarget, + sampler_index: Option, +} + #[derive(Default)] pub(super) struct State { topology: u32, @@ -19,6 +25,8 @@ pub(super) struct State { color_targets: ArrayVec<[super::ColorTargetDesc; crate::MAX_COLOR_TARGETS]>, stencil: super::StencilState, depth_bias: wgt::DepthBiasState, + samplers: [Option; super::MAX_SAMPLERS], + texture_slots: [TextureSlotDesc; super::MAX_TEXTURE_SLOTS], has_pass_label: bool, dirty: Dirty, } @@ -81,6 +89,22 @@ impl super::CommandEncoder { } } + fn rebind_sampler_states(&mut self, dirty_textures: u32, dirty_samplers: u32) { + for (texture_index, slot) in self.state.texture_slots.iter().enumerate() { + if let Some(sampler_index) = slot.sampler_index { + if dirty_textures & (1 << texture_index) != 0 + || dirty_samplers & (1 << sampler_index) != 0 + { + if let Some(sampler) = self.state.samplers[sampler_index as usize] { + self.cmd_buffer + .commands + .push(C::BindSampler(texture_index as u32, sampler)); + } + } + } + } + } + fn prepare_draw(&mut self, first_instance: u32) { if first_instance != 0 { self.rebind_vertex_attributes(first_instance); @@ -90,6 +114,31 @@ impl super::CommandEncoder { self.state.dirty.set(Dirty::VERTEX_BUFFERS, false); } } + + fn set_pipeline_inner(&mut self, inner: &super::PipelineInner) { + self.cmd_buffer.commands.push(C::SetProgram(inner.program)); + + //TODO: push constants + let _ = &inner.uniforms; + + // rebind textures, if needed + let mut dirty_textures = 0u32; + for (texture_index, (slot, &sampler_index)) in self + .state + .texture_slots + .iter_mut() + .zip(inner.sampler_map.iter()) + .enumerate() + { + if slot.sampler_index != sampler_index { + slot.sampler_index = sampler_index; + dirty_textures |= 1 << texture_index; + } + } + if dirty_textures != 0 { + self.rebind_sampler_states(dirty_textures, 0); + } + } } impl crate::CommandEncoder for super::CommandEncoder { @@ -405,14 +454,74 @@ impl crate::CommandEncoder for super::CommandEncoder { group: &super::BindGroup, dynamic_offsets: &[wgt::DynamicOffset], ) { + let mut do_index = 0; + let mut dirty_textures = 0u32; + let mut dirty_samplers = 0u32; + let group_info = &layout.group_infos[index as usize]; + + for (binding_layout, raw_binding) in group_info.entries.iter().zip(group.contents.iter()) { + let slot = group_info.binding_to_slot[binding_layout.binding as usize] as u32; + match *raw_binding { + super::RawBinding::Buffer { + raw, + offset: base_offset, + size, + } => { + let mut offset = base_offset; + let target = match binding_layout.ty { + wgt::BindingType::Buffer { + ty, + has_dynamic_offset, + min_binding_size: _, + } => { + if has_dynamic_offset { + offset += dynamic_offsets[do_index] as i32; + do_index += 1; + } + match ty { + wgt::BufferBindingType::Uniform => glow::UNIFORM_BUFFER, + wgt::BufferBindingType::Storage { .. } => { + glow::SHADER_STORAGE_BUFFER + } + } + } + _ => unreachable!(), + }; + self.cmd_buffer.commands.push(C::BindBuffer { + target, + slot, + buffer: raw, + offset, + size, + }); + } + super::RawBinding::Texture { raw, target } => { + dirty_textures |= 1 << slot; + self.state.texture_slots[slot as usize].tex_target = target; + self.cmd_buffer.commands.push(C::BindTexture { + slot, + texture: raw, + target, + }); + } + super::RawBinding::Sampler(sampler) => { + dirty_samplers |= 1 << slot; + self.state.samplers[slot as usize] = Some(sampler); + } + } + } + + self.rebind_sampler_states(dirty_textures, dirty_samplers); } + unsafe fn set_push_constants( &mut self, - layout: &super::PipelineLayout, - stages: wgt::ShaderStage, - offset: u32, - data: &[u32], + _layout: &super::PipelineLayout, + _stages: wgt::ShaderStage, + _offset: u32, + _data: &[u32], ) { + unimplemented!() } unsafe fn insert_debug_marker(&mut self, label: &str) { @@ -431,10 +540,9 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); self.state.dirty |= Dirty::VERTEX_BUFFERS; - self.cmd_buffer - .commands - .push(C::SetProgram(pipeline.inner.program)); + self.set_pipeline_inner(&pipeline.inner); + // set vertex state self.state.vertex_attributes.clear(); for vat in pipeline.vertex_attributes.iter() { self.state.vertex_attributes.push(vat.clone()); @@ -449,6 +557,7 @@ impl crate::CommandEncoder for super::CommandEncoder { state_desc.stride = pipe_desc.stride; } + // set depth/stencil states let mut aspects = crate::FormatAspect::empty(); if pipeline.depth_bias != self.state.depth_bias { self.state.depth_bias = pipeline.depth_bias; @@ -489,6 +598,7 @@ impl crate::CommandEncoder for super::CommandEncoder { .commands .push(C::ConfigureDepthStencil(aspects)); + // set blend states if self.state.color_targets[..] != pipeline.color_targets[..] { if pipeline .color_targets @@ -686,9 +796,7 @@ impl crate::CommandEncoder for super::CommandEncoder { } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { - self.cmd_buffer - .commands - .push(C::SetProgram(pipeline.inner.program)); + self.set_pipeline_inner(&pipeline.inner); } unsafe fn dispatch(&mut self, count: [u32; 3]) { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 8da560e492..eae77c8879 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -595,16 +595,9 @@ impl crate::Device for super::Device { for (entry, layout) in desc.entries.iter().zip(desc.layout.entries.iter()) { let binding = match layout.ty { - wgt::BindingType::Buffer { ty, .. } => { + wgt::BindingType::Buffer { .. } => { let bb = &desc.buffers[entry.resource_index as usize]; - let register = match ty { - wgt::BufferBindingType::Uniform => super::BindingRegister::UniformBuffers, - wgt::BufferBindingType::Storage { .. } => { - super::BindingRegister::StorageBuffers - } - }; super::RawBinding::Buffer { - register, raw: bb.buffer.raw, offset: bb.offset as i32, size: match bb.size { @@ -632,7 +625,6 @@ impl crate::Device for super::Device { } Ok(super::BindGroup { - layout_entries: Arc::clone(&desc.layout.entries), contents: contents.into_boxed_slice(), }) } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index f35693ea9e..35aad685d0 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -541,7 +541,8 @@ pub struct Swapchain { renderbuffer: glow::Renderbuffer, /// Extent because the window lies extent: wgt::Extent3d, - format: super::TextureFormat, + format: wgt::TextureFormat, + format_desc: super::TextureFormatDesc, sample_type: wgt::TextureSampleType, } @@ -657,7 +658,8 @@ impl crate::Surface for Surface { renderbuffer, framebuffer, extent: config.extent, - format: format_desc.internal, + format: config.format, + format_desc, sample_type: wgt::TextureSampleType::Float { filterable: false }, }); @@ -674,12 +676,20 @@ impl crate::Surface for Surface { unsafe fn acquire_texture( &mut self, - timeout_ms: u32, + _timeout_ms: u32, //TODO ) -> 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) + let texture = super::Texture { + inner: super::TextureInner::Renderbuffer { + raw: sc.renderbuffer, + }, + format: sc.format, + format_desc: sc.format_desc.clone(), + }; + Ok(Some(crate::AcquiredSurfaceTexture { + texture, + suboptimal: false, + })) } unsafe fn discard_texture(&mut self, _texture: super::Texture) {} } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 53dd24e8a1..88fc439477 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -20,6 +20,7 @@ pub struct Api; //Note: we can support more samplers if not every one of them is used at a time, // but it probably doesn't worth it. const MAX_TEXTURE_SLOTS: usize = 16; +const MAX_SAMPLERS: usize = 16; const MAX_VERTEX_ATTRIBUTES: usize = 16; impl crate::Api for Api { @@ -60,7 +61,6 @@ bitflags::bitflags! { } type BindTarget = u32; -type TextureFormat = u32; trait Sampled { unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32); @@ -164,7 +164,7 @@ impl Default for VertexAttribKind { } } -#[derive(Debug)] +#[derive(Clone, Debug)] struct TextureFormatDesc { internal: u32, external: u32, @@ -278,7 +278,6 @@ enum BindingRegister { #[derive(Debug)] enum RawBinding { Buffer { - register: BindingRegister, raw: glow::Buffer, offset: i32, size: i32, @@ -292,7 +291,6 @@ enum RawBinding { #[derive(Debug)] pub struct BindGroup { - layout_entries: Arc<[wgt::BindGroupLayoutEntry]>, contents: Box<[RawBinding]>, } @@ -596,6 +594,19 @@ enum Command { draw_buffer_index: Option, desc: ColorTargetDesc, }, + BindBuffer { + target: BindTarget, + slot: u32, + buffer: glow::Buffer, + offset: i32, + size: i32, + }, + BindSampler(u32, glow::Sampler), + BindTexture { + slot: u32, + texture: glow::Texture, + target: BindTarget, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 9f51204c53..58d13bd418 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -582,6 +582,26 @@ impl super::Queue { } } } + C::BindBuffer { + target, + slot, + buffer, + offset, + size, + } => { + gl.bind_buffer_range(target, slot, Some(buffer), offset, size); + } + C::BindSampler(texture_index, sampler) => { + gl.bind_sampler(texture_index, Some(sampler)); + } + C::BindTexture { + slot, + texture, + target, + } => { + gl.active_texture(glow::TEXTURE0 + slot); + gl.bind_texture(target, Some(texture)); + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( From c7356e124e129391d2f2dea91234c3a6e3f04cb9 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 10:40:49 -0400 Subject: [PATCH 19/33] hal/gles: storage texture bindings --- wgpu-hal/src/gles/adapter.rs | 2 ++ wgpu-hal/src/gles/command.rs | 12 ++++++--- wgpu-hal/src/gles/conv.rs | 8 ++++++ wgpu-hal/src/gles/device.rs | 49 +++++++++++++++++++++++++++++++++--- wgpu-hal/src/gles/egl.rs | 2 ++ wgpu-hal/src/gles/mod.rs | 21 ++++++++++++++-- wgpu-hal/src/gles/queue.rs | 15 ++++++++--- 7 files changed, 97 insertions(+), 12 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 6ab35ad74d..0f5812e341 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -190,6 +190,8 @@ impl super::Adapter { | wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES | wgt::DownlevelFlags::COMPARISON_SAMPLERS; downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, ver >= (3, 1)); + //Note: storage textures aren't supported atm, only buffers. See + // https://github.com/grovesNL/glow/issues/174 downlevel_flags.set( wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE, ver >= (3, 1), diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index d23845e381..a932633324 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -495,6 +495,10 @@ impl crate::CommandEncoder for super::CommandEncoder { size, }); } + super::RawBinding::Sampler(sampler) => { + dirty_samplers |= 1 << slot; + self.state.samplers[slot as usize] = Some(sampler); + } super::RawBinding::Texture { raw, target } => { dirty_textures |= 1 << slot; self.state.texture_slots[slot as usize].tex_target = target; @@ -504,9 +508,11 @@ impl crate::CommandEncoder for super::CommandEncoder { target, }); } - super::RawBinding::Sampler(sampler) => { - dirty_samplers |= 1 << slot; - self.state.samplers[slot as usize] = Some(sampler); + super::RawBinding::Image(ref binding) => { + self.cmd_buffer.commands.push(C::BindImage { + slot, + binding: binding.clone(), + }); } } } diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index cc75b68d5f..0fe545d856 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -313,3 +313,11 @@ pub(super) fn map_blend(blend: &wgt::BlendState) -> super::BlendDesc { alpha: map_blend_component(&blend.alpha), } } + +pub(super) fn map_storage_access(access: wgt::StorageTextureAccess) -> u32 { + match access { + wgt::StorageTextureAccess::ReadOnly => glow::READ_ONLY, + wgt::StorageTextureAccess::WriteOnly => glow::WRITE_ONLY, + wgt::StorageTextureAccess::ReadWrite => glow::READ_WRITE, + } +} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index eae77c8879..c024b44f9b 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -455,6 +455,12 @@ impl crate::Device for super::Device { Ok(super::Texture { inner, + mip_level_count: desc.mip_level_count, + array_layer_count: if desc.dimension == wgt::TextureDimension::D2 { + desc.size.depth_or_array_layers + } else { + 1 + }, format: desc.format, format_desc, }) @@ -476,6 +482,14 @@ impl crate::Device for super::Device { texture: &super::Texture, desc: &crate::TextureViewDescriptor, ) -> Result { + let end_array_layer = match desc.range.array_layer_count { + Some(count) => desc.range.base_array_layer + count.get(), + None => texture.array_layer_count, + }; + let end_mip_level = match desc.range.mip_level_count { + Some(count) => desc.range.base_mip_level + count.get(), + None => texture.mip_level_count, + }; Ok(super::TextureView { inner: match texture.inner { super::TextureInner::Renderbuffer { raw } => { @@ -489,8 +503,8 @@ impl crate::Device for super::Device { sample_type: texture.format.describe().sample_type, aspects: crate::FormatAspect::from(texture.format) & crate::FormatAspect::from(desc.range.aspect), - base_mip_level: desc.range.base_mip_level, - base_array_layer: desc.range.base_array_layer, + mip_levels: desc.range.base_mip_level..end_mip_level, + array_layers: desc.range.base_array_layer..end_array_layer, }) } unsafe fn destroy_texture_view(&self, _view: super::TextureView) {} @@ -610,8 +624,9 @@ impl crate::Device for super::Device { let sampler = desc.samplers[entry.resource_index as usize]; super::RawBinding::Sampler(sampler.raw) } - wgt::BindingType::Texture { .. } | wgt::BindingType::StorageTexture { .. } => { - match desc.textures[entry.resource_index as usize].view.inner { + wgt::BindingType::Texture { .. } => { + let view = desc.textures[entry.resource_index as usize].view; + match view.inner { super::TextureInner::Renderbuffer { .. } => { panic!("Unable to use a renderbuffer in a group") } @@ -620,6 +635,32 @@ impl crate::Device for super::Device { } } } + wgt::BindingType::StorageTexture { + access, + format, + view_dimension, + } => { + let view = desc.textures[entry.resource_index as usize].view; + let format_desc = self.shared.describe_texture_format(format); + match view.inner { + super::TextureInner::Renderbuffer { .. } => { + panic!("Unable to use a renderbuffer in a group") + } + super::TextureInner::Texture { raw, .. } => { + super::RawBinding::Image(super::ImageBinding { + raw, + mip_level: view.mip_levels.start, + array_layer: match view_dimension { + wgt::TextureViewDimension::D2Array + | wgt::TextureViewDimension::CubeArray => None, + _ => Some(view.array_layers.start), + }, + access: conv::map_storage_access(access), + format: format_desc.internal, + }) + } + } + } }; contents.push(binding); } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 35aad685d0..5eabfb8bf8 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -683,6 +683,8 @@ impl crate::Surface for Surface { inner: super::TextureInner::Renderbuffer { raw: sc.renderbuffer, }, + array_layer_count: 1, + mip_level_count: 1, format: sc.format, format_desc: sc.format_desc.clone(), }; diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 88fc439477..a042dc20a2 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -224,6 +224,8 @@ impl TextureInner { #[derive(Debug)] pub struct Texture { inner: TextureInner, + mip_level_count: u32, + array_layer_count: u32, format: wgt::TextureFormat, format_desc: TextureFormatDesc, } @@ -233,8 +235,8 @@ pub struct TextureView { inner: TextureInner, sample_type: wgt::TextureSampleType, aspects: crate::FormatAspect, - base_mip_level: u32, - base_array_layer: u32, + mip_levels: Range, + array_layers: Range, } #[derive(Debug)] @@ -285,7 +287,9 @@ enum RawBinding { Texture { raw: glow::Texture, target: BindTarget, + //TODO: mip levels, array layers }, + Image(ImageBinding), Sampler(glow::Sampler), } @@ -320,6 +324,15 @@ struct BufferBinding { offset: wgt::BufferAddress, } +#[derive(Clone, Debug)] +struct ImageBinding { + raw: glow::Texture, + mip_level: u32, + array_layer: Option, + access: u32, + format: u32, +} + #[derive(Clone, Debug, Default)] struct VertexBufferDesc { step: wgt::InputStepMode, @@ -607,6 +620,10 @@ enum Command { texture: glow::Texture, target: BindTarget, }, + BindImage { + slot: u32, + binding: ImageBinding, + }, InsertDebugMarker(Range), PushDebugGroup(Range), PopDebugGroup, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 58d13bd418..362c221093 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -346,8 +346,8 @@ impl super::Queue { glow::DRAW_FRAMEBUFFER, attachment, Some(raw), - view.base_mip_level as i32, - view.base_array_layer as i32, + view.mip_levels.start as i32, + view.array_layers.start as i32, ); } else { gl.framebuffer_texture_2d( @@ -355,7 +355,7 @@ impl super::Queue { attachment, target, Some(raw), - view.base_mip_level as i32, + view.mip_levels.start as i32, ); } } @@ -602,6 +602,15 @@ impl super::Queue { gl.active_texture(glow::TEXTURE0 + slot); gl.bind_texture(target, Some(texture)); } + C::BindImage { + slot: _, + binding: _, + } => { + //TODO: https://github.com/grovesNL/glow/issues/174 + //gl.bind_image_texture(slot, Some(binding.raw), binding.mip_level as i32, + // binding.array_layer.is_none(), binding.array_layer.unwrap_or_default(), + // binding.access, binding.format); + } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); gl.debug_message_insert( From 8fd6b36e6ced80767d7b216e0393151dee8a2fe0 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 16:58:01 -0400 Subject: [PATCH 20/33] hal/egl: add coherence preference, hook up EGL_KHR_debug message callbacks --- wgpu-hal/examples/halmark/main.rs | 15 ++-- wgpu-hal/src/gles/adapter.rs | 6 +- wgpu-hal/src/gles/command.rs | 13 ++-- wgpu-hal/src/gles/device.rs | 78 +++++++++++++++++---- wgpu-hal/src/gles/egl.rs | 113 +++++++++++++++++++++++++----- wgpu-hal/src/gles/mod.rs | 89 ----------------------- wgpu-hal/src/gles/queue.rs | 1 + wgpu-hal/src/lib.rs | 1 + wgpu-hal/src/metal/device.rs | 1 + wgpu-hal/src/vulkan/device.rs | 5 ++ 10 files changed, 189 insertions(+), 133 deletions(-) diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index 0fc766fe4b..cd68c053d4 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -239,7 +239,7 @@ impl Example { label: Some("stage"), size: texture_data.len() as wgt::BufferAddress, usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::COPY_SRC, - memory_flags: hal::MemoryFlag::TRANSIENT, + memory_flags: hal::MemoryFlag::TRANSIENT | hal::MemoryFlag::PREFER_COHERENT, }; let staging_buffer = unsafe { device.create_buffer(&staging_buffer_desc).unwrap() }; unsafe { @@ -342,7 +342,7 @@ impl Example { label: Some("global"), size: mem::size_of::() as wgt::BufferAddress, usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::UNIFORM, - memory_flags: hal::MemoryFlag::empty(), + memory_flags: hal::MemoryFlag::PREFER_COHERENT, }; let global_buffer = unsafe { let buffer = device.create_buffer(&global_buffer_desc).unwrap(); @@ -363,7 +363,7 @@ impl Example { label: Some("local"), size: (MAX_BUNNIES as wgt::BufferAddress) * wgt::BIND_BUFFER_ALIGNMENT, usage: hal::BufferUse::MAP_WRITE | hal::BufferUse::UNIFORM, - memory_flags: hal::MemoryFlag::empty(), + memory_flags: hal::MemoryFlag::PREFER_COHERENT, }; let local_buffer = unsafe { device.create_buffer(&local_buffer_desc).unwrap() }; @@ -474,6 +474,10 @@ impl Example { }) } + fn is_empty(&self) -> bool { + self.bunnies.is_empty() + } + fn exit(mut self) { unsafe { { @@ -732,11 +736,12 @@ fn main() { } }, winit::event::Event::RedrawRequested(_) => { + let ex = example.as_mut().unwrap(); { accum_time += last_frame_inst.elapsed().as_secs_f32(); last_frame_inst = Instant::now(); frame_count += 1; - if frame_count == 100 { + if frame_count == 100 && !ex.is_empty() { println!( "Avg frame time {}ms", accum_time * 1000.0 / frame_count as f32 @@ -745,7 +750,7 @@ fn main() { frame_count = 0; } } - example.as_mut().unwrap().render(); + ex.render(); } winit::event::Event::LoopDestroyed => { example.take().unwrap().exit(); diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 0f5812e341..75db09a837 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -167,13 +167,13 @@ impl super::Adapter { let ver = Self::parse_version(&version).ok()?; let extensions = gl.supported_extensions(); - log::info!("Extensions: {:?}", extensions); + log::debug!("Extensions: {:#?}", extensions); let shading_language_version = { let sl_version = gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION); log::info!("SL version: {}", sl_version); - let (sl_major, sl_minor) = Self::parse_version(&version).ok()?; - let value = (sl_major * 100 + sl_minor * 10) as u16; + let (sl_major, sl_minor) = Self::parse_version(&sl_version).ok()?; + let value = sl_major as u16 * 100 + sl_minor as u16 * 10; naga::back::glsl::Version::Embedded(value) }; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index a932633324..769078f023 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -403,23 +403,22 @@ impl crate::CommandEncoder for super::CommandEncoder { // issue the clears for (i, cat) in desc.color_attachments.iter().enumerate() { if !cat.ops.contains(crate::AttachmentOp::LOAD) { - let draw_buffer = glow::DRAW_BUFFER0 + i as u32; let c = &cat.clear_value; self.cmd_buffer .commands .push(match cat.target.view.sample_type { wgt::TextureSampleType::Float { .. } => C::ClearColorF( - draw_buffer, - [c.r as f32, c.g as f32, c.r as f32, c.a as f32], + i as u32, + [c.r as f32, c.g as f32, c.b as f32, c.a as f32], ), wgt::TextureSampleType::Depth => unimplemented!(), wgt::TextureSampleType::Uint => C::ClearColorU( - draw_buffer, - [c.r as u32, c.g as u32, c.r as u32, c.a as u32], + i as u32, + [c.r as u32, c.g as u32, c.b as u32, c.a as u32], ), wgt::TextureSampleType::Sint => C::ClearColorI( - draw_buffer, - [c.r as i32, c.g as i32, c.r as i32, c.a as i32], + i as u32, + [c.r as i32, c.g as i32, c.b as i32, c.a as i32], ), }); } diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index c024b44f9b..e6cc1e8333 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -275,19 +275,19 @@ impl crate::Device for super::Device { } else { glow::ARRAY_BUFFER }; - let map_coherent = false; - let map_flags = glow::MAP_PERSISTENT_BIT - | if map_coherent { - glow::MAP_COHERENT_BIT - } else { - 0 - }; - let mut storage_flags = 0; + + let mut map_flags = glow::MAP_PERSISTENT_BIT; + if desc + .memory_flags + .contains(crate::MemoryFlag::PREFER_COHERENT) + { + map_flags |= glow::MAP_COHERENT_BIT; + } if desc.usage.contains(crate::BufferUse::MAP_READ) { - storage_flags |= map_flags | glow::MAP_READ_BIT; + map_flags |= glow::MAP_READ_BIT; } if desc.usage.contains(crate::BufferUse::MAP_WRITE) { - storage_flags |= map_flags | glow::MAP_WRITE_BIT; + map_flags |= glow::MAP_WRITE_BIT; } let raw = gl.create_buffer().unwrap(); @@ -296,7 +296,7 @@ impl crate::Device for super::Device { .size .try_into() .map_err(|_| crate::DeviceError::OutOfMemory)?; - gl.buffer_storage(target, raw_size, None, storage_flags); + gl.buffer_storage(target, raw_size, None, map_flags); gl.bind_buffer(target, None); Ok(super::Buffer { @@ -513,11 +513,63 @@ impl crate::Device for super::Device { &self, desc: &crate::SamplerDescriptor, ) -> Result { - use super::Sampled; let gl = &self.shared.context; let raw = gl.create_sampler().unwrap(); - super::SamplerBinding(raw).configure_sampling(gl, desc); + + let (min, mag) = + conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter); + + gl.sampler_parameter_i32(raw, glow::TEXTURE_MIN_FILTER, min as i32); + gl.sampler_parameter_i32(raw, glow::TEXTURE_MAG_FILTER, mag as i32); + + gl.sampler_parameter_i32( + raw, + glow::TEXTURE_WRAP_S, + conv::map_address_mode(desc.address_modes[0]) as i32, + ); + gl.sampler_parameter_i32( + raw, + glow::TEXTURE_WRAP_T, + conv::map_address_mode(desc.address_modes[1]) as i32, + ); + gl.sampler_parameter_i32( + raw, + glow::TEXTURE_WRAP_R, + conv::map_address_mode(desc.address_modes[2]) as i32, + ); + + if let Some(border_color) = desc.border_color { + let mut border = match border_color { + wgt::SamplerBorderColor::TransparentBlack => [0.0; 4], + wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0], + wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4], + }; + gl.sampler_parameter_f32_slice(raw, glow::TEXTURE_BORDER_COLOR, &mut border); + } + + if let Some(ref range) = desc.lod_clamp { + gl.sampler_parameter_f32(raw, glow::TEXTURE_MIN_LOD, range.start); + gl.sampler_parameter_f32(raw, glow::TEXTURE_MAX_LOD, range.end); + } + + //TODO: `desc.anisotropy_clamp` depends on the downlevel flag + // gl.sampler_parameter_f32(rawow::TEXTURE_MAX_ANISOTROPY, aniso as f32); + + //set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0); + + if let Some(compare) = desc.compare { + gl.sampler_parameter_i32( + raw, + glow::TEXTURE_COMPARE_MODE, + glow::COMPARE_REF_TO_TEXTURE as i32, + ); + gl.sampler_parameter_i32( + raw, + glow::TEXTURE_COMPARE_FUNC, + conv::map_compare_func(compare) as i32, + ); + } Ok(super::Sampler { raw }) } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 5eabfb8bf8..8a2bd1bff0 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -1,7 +1,7 @@ use glow::HasContext; use parking_lot::Mutex; -use std::{os::raw, ptr, sync::Arc}; +use std::{ffi::CStr, os::raw, ptr, sync::Arc}; const EGL_PLATFORM_WAYLAND_KHR: u32 = 0x31D8; const EGL_PLATFORM_X11_KHR: u32 = 0x31D5; @@ -41,6 +41,56 @@ extern "C" { ) -> i32; } +type EglLabel = *const raw::c_void; +type EGLDEBUGPROCKHR = Option< + unsafe extern "system" fn( + error: egl::Enum, + command: *const raw::c_char, + message_type: u32, + thread_label: EglLabel, + object_label: EglLabel, + message: *const raw::c_char, + ), +>; + +const EGL_DEBUG_MSG_CRITICAL_KHR: u32 = 0x33B9; +const EGL_DEBUG_MSG_ERROR_KHR: u32 = 0x33BA; +const EGL_DEBUG_MSG_WARN_KHR: u32 = 0x33BB; +const EGL_DEBUG_MSG_INFO_KHR: u32 = 0x33BC; + +type EglDebugMessageControlFun = + unsafe extern "system" fn(proc: EGLDEBUGPROCKHR, attrib_list: *const egl::Attrib) -> raw::c_int; + +unsafe extern "system" fn egl_debug_proc( + error: egl::Enum, + command_raw: *const raw::c_char, + message_type: u32, + _thread_label: EglLabel, + _object_label: EglLabel, + message_raw: *const raw::c_char, +) { + let log_severity = match message_type { + EGL_DEBUG_MSG_CRITICAL_KHR | EGL_DEBUG_MSG_ERROR_KHR => log::Level::Error, + EGL_DEBUG_MSG_WARN_KHR => log::Level::Warn, + EGL_DEBUG_MSG_INFO_KHR => log::Level::Info, + _ => log::Level::Debug, + }; + let command = CStr::from_ptr(command_raw).to_string_lossy(); + let message = if message_raw.is_null() { + "".into() + } else { + CStr::from_ptr(message_raw).to_string_lossy() + }; + + log::log!( + log_severity, + "EGL '{}' code 0x{:x}: {}", + command, + error, + message, + ); +} + fn open_x_display() -> Option<(ptr::NonNull, libloading::Library)> { log::info!("Loading X11 library to get the current display"); unsafe { @@ -112,7 +162,7 @@ fn choose_config( Err(crate::InstanceError) } -fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) { +fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) { let source_str = match source { glow::DEBUG_SOURCE_API => "API", glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System", @@ -146,12 +196,16 @@ fn debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, mess log::log!( log_severity, - "[{}/{}] ID {} : {}", + "GLES: [{}/{}] ID {} : {}", source_str, type_str, id, message ); + + if log_severity == log::Level::Error { + std::process::exit(1); + } } #[derive(Debug)] @@ -181,11 +235,10 @@ impl Inner { .query_string(Some(display), egl::EXTENSIONS) .unwrap() .to_string_lossy(); - log::info!( - "Display vendor {:?}, version {:?}, extensions: {:?}", - vendor, - version, - display_extensions + log::info!("Display vendor {:?}, version {:?}", vendor, version,); + log::debug!( + "Display extensions: {:#?}", + display_extensions.split_whitespace().collect::>() ); if log::max_level() >= log::LevelFilter::Trace { @@ -211,7 +264,7 @@ impl Inner { egl::CONTEXT_CLIENT_VERSION, 3, // Request GLES 3.0 or higher ]; - if flags.contains(crate::InstanceFlag::VALIDATION) + if flags.contains(crate::InstanceFlag::DEBUG) && wsi_library.is_none() && !cfg!(target_os = "android") { @@ -294,7 +347,10 @@ impl crate::Instance for Instance { Ok(ext) => ext.to_string_lossy().into_owned(), Err(_) => String::new(), }; - log::info!("Client extensions: {:?}", client_ext_str); + log::debug!( + "Client extensions: {:#?}", + client_ext_str.split_whitespace().collect::>() + ); let mut wsi_library = None; @@ -335,6 +391,26 @@ impl crate::Instance for Instance { egl.get_display(egl::DEFAULT_DISPLAY).unwrap() }; + if desc.flags.contains(crate::InstanceFlag::VALIDATION) + && client_ext_str.contains(&"EGL_KHR_debug") + { + log::info!("Enabling EGL debug output"); + let function: EglDebugMessageControlFun = + std::mem::transmute(egl.get_proc_address("eglDebugMessageControlKHR").unwrap()); + let attributes = [ + EGL_DEBUG_MSG_CRITICAL_KHR as egl::Attrib, + 1, + EGL_DEBUG_MSG_ERROR_KHR as egl::Attrib, + 1, + EGL_DEBUG_MSG_WARN_KHR as egl::Attrib, + 1, + EGL_DEBUG_MSG_INFO_KHR as egl::Attrib, + 1, + egl::ATTRIB_NONE, + ]; + (function)(Some(egl_debug_proc), attributes.as_ptr()); + } + let inner = Inner::create(desc.flags, egl, display, wsi_library.as_ref())?; Ok(Instance { @@ -356,6 +432,7 @@ impl crate::Instance for Instance { #[cfg(not(any(target_os = "android", target_os = "macos")))] let (mut temp_xlib_handle, mut temp_xcb_handle); + #[allow(trivial_casts)] let native_window_ptr = match has_handle.raw_window_handle() { #[cfg(not(any(target_os = "android", target_os = "macos")))] Rwh::Xlib(handle) => { @@ -396,9 +473,13 @@ impl crate::Instance for Instance { ) .unwrap(); - let new_inner = - Inner::create(inner.egl.clone(), display, self.wsi_library.as_ref()) - .map_err(|_| w::InitError::UnsupportedWindowHandle)?; + let new_inner = Inner::create( + self.flags, + inner.egl.clone(), + display, + self.wsi_library.as_ref(), + ) + .map_err(|_| crate::InstanceError)?; let old_inner = std::mem::replace(inner.deref_mut(), new_inner); inner.wl_display = Some(handle.display); @@ -526,9 +607,10 @@ impl crate::Instance for Instance { .map_or(ptr::null(), |p| p as *const _) }); - if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() { + if self.flags.contains(crate::InstanceFlag::VALIDATION) && gl.supports_debug() { + log::info!("Enabling GLES debug output"); gl.enable(glow::DEBUG_OUTPUT); - gl.debug_message_callback(debug_message_callback); + gl.debug_message_callback(gl_debug_message_callback); } super::Adapter::expose(gl).into_iter().collect() @@ -581,7 +663,6 @@ impl Surface { crate::SurfaceError::Lost })?; - gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)); gl.blit_framebuffer( 0, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index a042dc20a2..17c7e9ed83 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -62,95 +62,6 @@ bitflags::bitflags! { type BindTarget = u32; -trait Sampled { - unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32); - // see https://github.com/grovesNL/glow/issues/170 - unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]); - unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32); - - unsafe fn configure_sampling(&self, gl: &glow::Context, desc: &crate::SamplerDescriptor) { - let (min, mag) = - conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter); - - self.set_param_int(gl, glow::TEXTURE_MIN_FILTER, min as i32); - self.set_param_int(gl, glow::TEXTURE_MAG_FILTER, mag as i32); - - self.set_param_int( - gl, - glow::TEXTURE_WRAP_S, - conv::map_address_mode(desc.address_modes[0]) as i32, - ); - self.set_param_int( - gl, - glow::TEXTURE_WRAP_T, - conv::map_address_mode(desc.address_modes[1]) as i32, - ); - self.set_param_int( - gl, - glow::TEXTURE_WRAP_R, - conv::map_address_mode(desc.address_modes[2]) as i32, - ); - - if let Some(border_color) = desc.border_color { - let mut border = match border_color { - wgt::SamplerBorderColor::TransparentBlack => [0.0; 4], - wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0], - wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4], - }; - self.set_param_float_vec(gl, glow::TEXTURE_BORDER_COLOR, &mut border); - } - - if let Some(ref range) = desc.lod_clamp { - self.set_param_float(gl, glow::TEXTURE_MIN_LOD, range.start); - self.set_param_float(gl, glow::TEXTURE_MAX_LOD, range.end); - } - - //TODO: `desc.anisotropy_clamp` depends on the downlevel flag - // self.set_param_float(glow::TEXTURE_MAX_ANISOTROPY, aniso as f32); - - //set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0); - - if let Some(compare) = desc.compare { - self.set_param_int( - gl, - glow::TEXTURE_COMPARE_MODE, - glow::COMPARE_REF_TO_TEXTURE as i32, - ); - self.set_param_int( - gl, - glow::TEXTURE_COMPARE_FUNC, - conv::map_compare_func(compare) as i32, - ); - } - } -} - -struct SamplerBinding(glow::Sampler); -impl Sampled for SamplerBinding { - unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) { - gl.sampler_parameter_f32(self.0, key, value); - } - unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) { - gl.sampler_parameter_f32_slice(self.0, key, values); - } - unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) { - gl.sampler_parameter_i32(self.0, key, value); - } -} - -struct SampledTextureBinding(BindTarget); -impl Sampled for SampledTextureBinding { - unsafe fn set_param_float(&self, gl: &glow::Context, key: u32, value: f32) { - gl.tex_parameter_f32(self.0, key, value); - } - unsafe fn set_param_float_vec(&self, gl: &glow::Context, key: u32, values: &mut [f32]) { - gl.tex_parameter_f32_slice(self.0, key, values); - } - unsafe fn set_param_int(&self, gl: &glow::Context, key: u32, value: i32) { - gl.tex_parameter_i32(self.0, key, value); - } -} - #[derive(Debug, Clone, Copy)] enum VertexAttribKind { Float, // glVertexAttribPointer diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 362c221093..214a644554 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -20,6 +20,7 @@ impl super::Queue { unsafe fn reset_state(&self) { let gl = &self.shared.context; gl.use_program(None); + gl.bind_framebuffer(glow::FRAMEBUFFER, None); gl.polygon_offset(0.0, 0.0); gl.disable(glow::DEPTH_TEST); gl.disable(glow::STENCIL_TEST); diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 54158e5ee9..c437a04413 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -554,6 +554,7 @@ impl From for FormatAspect { bitflags!( pub struct MemoryFlag: u32 { const TRANSIENT = 1; + const PREFER_COHERENT = 2; } ); diff --git a/wgpu-hal/src/metal/device.rs b/wgpu-hal/src/metal/device.rs index 658c071b02..91b2f60a98 100644 --- a/wgpu-hal/src/metal/device.rs +++ b/wgpu-hal/src/metal/device.rs @@ -140,6 +140,7 @@ impl crate::Device for super::Device { let mut options = mtl::MTLResourceOptions::empty(); options |= if map_read || map_write { + // `crate::MemoryFlag::PREFER_COHERENT` is ignored here mtl::MTLResourceOptions::StorageModeShared } else { mtl::MTLResourceOptions::StorageModePrivate diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 51bfbee127..f158ddc3aa 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -557,6 +557,11 @@ impl crate::Device for super::Device { .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) { let mut flags = gpu_alloc::UsageFlags::HOST_ACCESS; + flags.set( + gpu_alloc::UsageFlags::COHERENT, + desc.memory_flags + .contains(crate::MemoryFlag::PREFER_COHERENT), + ); flags.set( gpu_alloc::UsageFlags::DOWNLOAD, desc.usage.contains(crate::BufferUse::MAP_READ), From cf10138c64d155504a1b55149f88ae4101c70b74 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 16:58:01 -0400 Subject: [PATCH 21/33] hal/egl: add coherence preference, hook up EGL_KHR_debug message callbacks --- wgpu-hal/src/gles/device.rs | 8 +++----- wgpu-hal/src/vulkan/device.rs | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index e6cc1e8333..6d7742fe9c 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -36,7 +36,8 @@ impl CompilationContext<'_> { let slot = self.layout.get_slot(br); let name = reflection_info.uniforms[&handle].clone(); - log::debug!("Rebind buffer: {:?} -> {}", var.name.as_ref(), &name); + log::debug!("Rebind buffer: {:?} -> {}, register={:?}, slot={}", + var.name.as_ref(), &name, register, slot); self.name_binding_map.insert(name, (register, slot)); } @@ -200,10 +201,7 @@ impl super::Device { log::warn!("\tLink: {}", msg); } - if !self - .shared - .private_caps - .contains(super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER) + //TODO: check for `PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER`? { gl.use_program(Some(program)); for (ref name, (register, slot)) in name_binding_map { diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index f158ddc3aa..d2a57f7998 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -557,6 +557,7 @@ impl crate::Device for super::Device { .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) { let mut flags = gpu_alloc::UsageFlags::HOST_ACCESS; + //TODO: find a way to use `crate::MemoryFlag::PREFER_COHERENT` flags.set( gpu_alloc::UsageFlags::COHERENT, desc.memory_flags From 952173efdebe74756ef7f68d9c26dcb9f4d26f51 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 25 Jun 2021 23:03:11 -0400 Subject: [PATCH 22/33] Enable Gles backend, add checks for downlevel flags --- wgpu-core/Cargo.toml | 2 +- wgpu-core/build.rs | 2 +- wgpu-core/src/binding_model.rs | 4 ++- wgpu-core/src/command/bundle.rs | 15 +++++++++- wgpu-core/src/command/compute.rs | 11 +++++++ wgpu-core/src/command/render.rs | 44 +++++++++++++--------------- wgpu-core/src/device/mod.rs | 50 +++++++++++++++++++------------- wgpu-core/src/hub.rs | 4 +-- wgpu-core/src/instance.rs | 38 ++++++++++++------------ wgpu-core/src/lib.rs | 14 ++++----- wgpu-hal/src/gles/adapter.rs | 4 --- wgpu-hal/src/gles/device.rs | 9 ++++-- wgpu-hal/src/gles/egl.rs | 4 ++- wgpu-hal/src/gles/mod.rs | 4 +-- wgpu-hal/src/vulkan/device.rs | 5 ---- 15 files changed, 118 insertions(+), 92 deletions(-) diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index c226235b70..dcd72f749f 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -54,7 +54,7 @@ hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["metal"] } #Note: could also enable "vulkan" for Vulkan Portability [target.'cfg(all(not(target_arch = "wasm32"), unix, not(target_os = "ios"), not(target_os = "macos")))'.dependencies] -hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan"] } +hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan", "gles"] } [target.'cfg(all(not(target_arch = "wasm32"), windows))'.dependencies] hal = { path = "../wgpu-hal", package = "wgpu-hal", features = ["vulkan"] } diff --git a/wgpu-core/build.rs b/wgpu-core/build.rs index ad2c8d8364..f9cba2a418 100644 --- a/wgpu-core/build.rs +++ b/wgpu-core/build.rs @@ -11,6 +11,6 @@ fn main() { metal: { all(not(wasm), apple) }, dx12: { all(false, not(wasm), windows) }, dx11: { all(false, not(wasm), windows) }, - gl: { all(false, any(wasm, unix_wo_apple)) }, + gl: { all(not(wasm), unix_wo_apple) }, } } diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 76be6b52ae..c949d71f0d 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -1,5 +1,5 @@ use crate::{ - device::{DeviceError, MissingFeatures, SHADER_STAGE_COUNT}, + device::{DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT}, hub::Resource, id::{BindGroupLayoutId, BufferId, DeviceId, SamplerId, TextureViewId, Valid}, memory_init_tracker::MemoryInitTrackerAction, @@ -28,6 +28,8 @@ pub enum BindGroupLayoutEntryError { ArrayUnsupported, #[error(transparent)] MissingFeatures(#[from] MissingFeatures), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } #[derive(Clone, Debug, Error)] diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 7918d23220..cd9b9a61ff 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -39,7 +39,10 @@ use crate::{ StateChange, }, conv, - device::{AttachmentData, Device, DeviceError, RenderPassContext, SHADER_STAGE_COUNT}, + device::{ + AttachmentData, Device, DeviceError, MissingDownlevelFlags, RenderPassContext, + SHADER_STAGE_COUNT, + }, hub::{GlobalIdentityHandlerFactory, HalApi, Hub, Resource, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -403,6 +406,10 @@ impl RenderBundleEncoder { indirect: true, pipeline: state.pipeline.last_state, }; + device + .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) + .map_pass_err(scope)?; + let buffer = state .trackers .buffers @@ -439,6 +446,10 @@ impl RenderBundleEncoder { indirect: true, pipeline: state.pipeline.last_state, }; + device + .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) + .map_pass_err(scope)?; + let buffer = state .trackers .buffers @@ -1104,6 +1115,8 @@ pub(super) enum RenderBundleErrorInner { ResourceUsageConflict(#[from] UsageConflict), #[error(transparent)] Draw(#[from] DrawError), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } impl From for RenderBundleErrorInner diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index c698dc0860..73f0374609 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -5,6 +5,7 @@ use crate::{ CommandEncoderError, CommandEncoderStatus, MapPassErr, PassErrorScope, QueryUseError, StateChange, }, + device::MissingDownlevelFlags, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -157,6 +158,8 @@ pub enum ComputePassErrorInner { PushConstants(#[from] PushConstantUploadError), #[error(transparent)] QueryUse(#[from] QueryUseError), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } /// Error encountered when performing a compute pass. @@ -257,6 +260,8 @@ impl Global { let hub = A::hub(self); let mut token = Token::root(); + let (device_guard, mut token) = hub.devices.read(&mut token); + let (mut cmd_buf_guard, mut token) = hub.command_buffers.write(&mut token); let cmd_buf = CommandBuffer::get_encoder_mut(&mut *cmd_buf_guard, encoder_id).map_pass_err(scope)?; @@ -264,6 +269,8 @@ impl Global { cmd_buf.status = CommandEncoderStatus::Error; let raw = cmd_buf.encoder.open(); + let device = &device_guard[cmd_buf.device_id.value]; + #[cfg(feature = "trace")] if let Some(ref mut list) = cmd_buf.commands { list.push(crate::device::trace::Command::RunComputePass { @@ -500,6 +507,10 @@ impl Global { state.is_ready().map_pass_err(scope)?; + device + .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) + .map_pass_err(scope)?; + let indirect_buffer = state .trackers .buffers diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 40d0655be8..66c0965fa0 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -6,7 +6,10 @@ use crate::{ PassErrorScope, QueryResetMap, QueryUseError, RenderCommand, RenderCommandError, StateChange, }, - device::{AttachmentData, RenderPassCompatibilityError, RenderPassContext}, + device::{ + AttachmentData, MissingDownlevelFlags, MissingFeatures, RenderPassCompatibilityError, + RenderPassContext, + }, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, @@ -419,8 +422,10 @@ pub enum RenderPassErrorInner { SampleCountMismatch { actual: u32, expected: u32 }, #[error("setting `values_offset` to be `None` is only for internal use in render bundles")] InvalidValuesOffset, - #[error("required device features not enabled: {0:?}")] - MissingDeviceFeatures(wgt::Features), + #[error(transparent)] + MissingFeatures(#[from] MissingFeatures), + #[error(transparent)] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), #[error("indirect draw uses bytes {offset}..{end_offset} {} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!("(using count {})", v)))] IndirectBufferOverrun { count: Option, @@ -483,17 +488,6 @@ where } } -fn check_device_features( - actual: wgt::Features, - expected: wgt::Features, -) -> Result<(), RenderPassErrorInner> { - if !actual.contains(expected) { - Err(RenderPassErrorInner::MissingDeviceFeatures(expected)) - } else { - Ok(()) - } -} - struct RenderAttachment<'a> { texture_id: &'a Stored, selector: &'a TextureSelector, @@ -1402,12 +1396,13 @@ impl Global { }; if count.is_some() { - check_device_features( - device.features, - wgt::Features::MULTI_DRAW_INDIRECT, - ) - .map_pass_err(scope)?; + device + .require_features(wgt::Features::MULTI_DRAW_INDIRECT) + .map_pass_err(scope)?; } + device + .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) + .map_pass_err(scope)?; let indirect_buffer = info .trackers @@ -1476,11 +1471,12 @@ impl Global { true => mem::size_of::(), } as u64; - check_device_features( - device.features, - wgt::Features::MULTI_DRAW_INDIRECT_COUNT, - ) - .map_pass_err(scope)?; + device + .require_features(wgt::Features::MULTI_DRAW_INDIRECT_COUNT) + .map_pass_err(scope)?; + device + .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) + .map_pass_err(scope)?; let indirect_buffer = info .trackers diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 555c0501a7..56ea142f9b 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -254,6 +254,27 @@ pub enum CreateDeviceError { OutOfMemory, } +impl Device { + pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> { + if self.features.contains(feature) { + Ok(()) + } else { + Err(MissingFeatures(feature)) + } + } + + pub(crate) fn require_downlevel_flags( + &self, + flags: wgt::DownlevelFlags, + ) -> Result<(), MissingDownlevelFlags> { + if self.downlevel.flags.contains(flags) { + Ok(()) + } else { + Err(MissingDownlevelFlags(flags)) + } + } +} + impl Device { #[allow(clippy::too_many_arguments)] pub(crate) fn new( @@ -312,25 +333,6 @@ impl Device { }) } - pub(crate) fn require_features(&self, feature: wgt::Features) -> Result<(), MissingFeatures> { - if self.features.contains(feature) { - Ok(()) - } else { - Err(MissingFeatures(feature)) - } - } - - pub(crate) fn require_downlevel_flags( - &self, - flags: wgt::DownlevelFlags, - ) -> Result<(), MissingDownlevelFlags> { - if self.downlevel.flags.contains(flags) { - Ok(()) - } else { - Err(MissingDownlevelFlags(flags)) - } - } - fn lock_life_internal<'this, 'token: 'this>( tracker: &'this Mutex>, _token: &mut Token<'token, Self>, @@ -1038,6 +1040,14 @@ impl Device { if is_writable_storage && entry.visibility.contains(wgt::ShaderStage::VERTEX) { required_features |= wgt::Features::VERTEX_WRITABLE_STORAGE; } + if is_writable_storage && entry.visibility.contains(wgt::ShaderStage::FRAGMENT) { + self.require_downlevel_flags(wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE) + .map_err(binding_model::BindGroupLayoutEntryError::MissingDownlevelFlags) + .map_err(|error| binding_model::CreateBindGroupLayoutError::Entry { + binding: entry.binding, + error, + })?; + } self.require_features(required_features) .map_err(binding_model::BindGroupLayoutEntryError::MissingFeatures) @@ -2423,7 +2433,7 @@ pub struct MissingFeatures(pub wgt::Features); #[derive(Clone, Debug, Error)] #[error( - "Downlevel flags {0:?} are required but not supported on the device. {}", + "Downlevel flags {0:?} are required but not supported on the device.\n{}", DOWNLEVEL_ERROR_WARNING_MESSAGE )] pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags); diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 85676e44b8..5a27fcb6fd 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -854,7 +854,7 @@ impl HalApi for hal::api::Dx11 { surface.dx11.as_mut().unwrap() } } - +*/ #[cfg(gl)] impl HalApi for hal::api::Gles { const VARIANT: Backend = Backend::Gl; @@ -864,7 +864,7 @@ impl HalApi for hal::api::Gles { fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { surface.gl.as_mut().unwrap() } -}*/ +} #[cfg(test)] fn _test_send_sync(global: &Global) { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index cf4a6f3ecb..4e5039e2f7 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -31,35 +31,35 @@ pub struct Instance { impl Instance { pub fn new(name: &str, backends: BackendBit) -> Self { - let mut flags = hal::InstanceFlag::empty(); - if cfg!(debug_assertions) { - flags |= hal::InstanceFlag::VALIDATION; - flags |= hal::InstanceFlag::DEBUG; - } - let hal_desc = hal::InstanceDescriptor { - name: "wgpu", - flags, - }; - - let map = |backend: Backend| unsafe { - if backends.contains(backend.into()) { - hal::Instance::init(&hal_desc).ok() + fn init(mask: BackendBit) -> Option { + if mask.contains(A::VARIANT.into()) { + let mut flags = hal::InstanceFlag::empty(); + if cfg!(debug_assertions) { + flags |= hal::InstanceFlag::VALIDATION; + flags |= hal::InstanceFlag::DEBUG; + } + let hal_desc = hal::InstanceDescriptor { + name: "wgpu", + flags, + }; + unsafe { hal::Instance::init(&hal_desc).ok() } } else { None } - }; + } + Self { name: name.to_string(), #[cfg(vulkan)] - vulkan: map(Backend::Vulkan), + vulkan: init::(backends), #[cfg(metal)] - metal: map(Backend::Metal), + metal: init::(backends), #[cfg(dx12)] - dx12: map(Backend::Dx12), + dx12: init(Backend::Dx12, backends), #[cfg(dx11)] - dx11: map(Backend::Dx11), + dx11: init(Backend::Dx11, backends), #[cfg(gl)] - gl: map(Backend::Gl), + gl: init::(backends), } } diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index f1aa612db1..e8118b86b4 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -207,14 +207,12 @@ macro_rules! gfx_select { wgt::Backend::Vulkan => $global.$method::<$crate::api::Vulkan>( $($param),* ), #[cfg(all(not(target_arch = "wasm32"), any(target_os = "ios", target_os = "macos")))] wgt::Backend::Metal => $global.$method::<$crate::api::Metal>( $($param),* ), - /* - #[cfg(all(not(target_arch = "wasm32"), windows))] - wgt::Backend::Dx12 => $global.$method::<$crate::backend::Dx12>( $($param),* ), - #[cfg(all(not(target_arch = "wasm32"), windows))] - wgt::Backend::Dx11 => $global.$method::<$crate::backend::Dx11>( $($param),* ), - #[cfg(any(target_arch = "wasm32", all(unix, not(any(target_os = "ios", target_os = "macos")))))] - wgt::Backend::Gl => $global.$method::<$crate::backend::Gl>( $($param),+ ), - */ + //#[cfg(all(not(target_arch = "wasm32"), windows))] + //wgt::Backend::Dx12 => $global.$method::<$crate::api::Dx12>( $($param),* ), + //#[cfg(all(not(target_arch = "wasm32"), windows))] + //wgt::Backend::Dx11 => $global.$method::<$crate::api::Dx11>( $($param),* ), + #[cfg(all(not(target_arch = "wasm32"), unix, not(any(target_os = "ios", target_os = "macos"))))] + wgt::Backend::Gl => $global.$method::<$crate::api::Gles>( $($param),+ ), other => panic!("Unexpected backend {:?}", other), } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 75db09a837..e9194d3487 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -245,10 +245,6 @@ impl super::Adapter { }; let mut private_caps = super::PrivateCapability::empty(); - private_caps.set( - super::PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER, - ver >= (3, 1), - ); private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1)); Some(crate::ExposedAdapter { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 6d7742fe9c..55ad914e72 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -36,8 +36,13 @@ impl CompilationContext<'_> { let slot = self.layout.get_slot(br); let name = reflection_info.uniforms[&handle].clone(); - log::debug!("Rebind buffer: {:?} -> {}, register={:?}, slot={}", - var.name.as_ref(), &name, register, slot); + log::debug!( + "Rebind buffer: {:?} -> {}, register={:?}, slot={}", + var.name.as_ref(), + &name, + register, + slot + ); self.name_binding_map.insert(name, (register, slot)); } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 8a2bd1bff0..33e9d83f36 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -42,6 +42,8 @@ extern "C" { } type EglLabel = *const raw::c_void; + +#[allow(clippy::upper_case_acronyms)] type EGLDEBUGPROCKHR = Option< unsafe extern "system" fn( error: egl::Enum, @@ -203,7 +205,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m message ); - if log_severity == log::Level::Error { + if log_severity == log::Level::Error && false { std::process::exit(1); } } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 17c7e9ed83..f25b7ed993 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -53,10 +53,8 @@ bitflags::bitflags! { /// Flags that affect internal code paths but do not /// change the exposed feature set. struct PrivateCapability: u32 { - /// Support explicit layouts in shader. - const EXPLICIT_LAYOUTS_IN_SHADER = 0x0001; /// Support memory barriers. - const MEMORY_BARRIERS = 0x0002; + const MEMORY_BARRIERS = 0x0001; } } diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index d2a57f7998..22117dc520 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -558,11 +558,6 @@ impl crate::Device for super::Device { { let mut flags = gpu_alloc::UsageFlags::HOST_ACCESS; //TODO: find a way to use `crate::MemoryFlag::PREFER_COHERENT` - flags.set( - gpu_alloc::UsageFlags::COHERENT, - desc.memory_flags - .contains(crate::MemoryFlag::PREFER_COHERENT), - ); flags.set( gpu_alloc::UsageFlags::DOWNLOAD, desc.usage.contains(crate::BufferUse::MAP_READ), From bf61908824f0255911fba4e65c4bf783176bbf21 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 26 Jun 2021 02:15:47 -0400 Subject: [PATCH 23/33] hal/gles: primitive state and framebuffer operations --- wgpu-hal/src/gles/adapter.rs | 5 +- wgpu-hal/src/gles/command.rs | 65 +++++++++++++++++-- wgpu-hal/src/gles/conv.rs | 16 +++++ wgpu-hal/src/gles/device.rs | 50 +++++++++++++-- wgpu-hal/src/gles/egl.rs | 5 +- wgpu-hal/src/gles/mod.rs | 19 +++++- wgpu-hal/src/gles/queue.rs | 121 +++++++++++++++++++++++++---------- 7 files changed, 231 insertions(+), 50 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index e9194d3487..09c2ce3ea5 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -177,7 +177,7 @@ impl super::Adapter { naga::back::glsl::Version::Embedded(value) }; - let mut features = wgt::Features::empty() | wgt::Features::NON_FILL_POLYGON_MODE; + let mut features = wgt::Features::empty(); features.set( wgt::Features::DEPTH_CLAMPING, extensions.contains("GL_EXT_depth_clamp"), @@ -283,7 +283,7 @@ impl super::Adapter { impl crate::Adapter for super::Adapter { unsafe fn open( &self, - _features: wgt::Features, + features: wgt::Features, ) -> Result, crate::DeviceError> { let gl = &self.shared.context; gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); @@ -300,6 +300,7 @@ impl crate::Adapter for super::Adapter { }, queue: super::Queue { shared: Arc::clone(&self.shared), + features, draw_fbo: gl .create_framebuffer() .map_err(|_| crate::DeviceError::OutOfMemory)?, diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 769078f023..e97e0fcbe9 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -18,6 +18,7 @@ struct TextureSlotDesc { #[derive(Default)] pub(super) struct State { topology: u32, + primitive: super::PrimitiveState, index_format: wgt::IndexFormat, index_offset: wgt::BufferAddress, vertex_buffers: [(super::VertexBufferDesc, super::BufferBinding); crate::MAX_VERTEX_BUFFERS], @@ -27,6 +28,9 @@ pub(super) struct State { depth_bias: wgt::DepthBiasState, samplers: [Option; super::MAX_SAMPLERS], texture_slots: [TextureSlotDesc; super::MAX_TEXTURE_SLOTS], + render_size: wgt::Extent3d, + resolve_attachments: ArrayVec<[(u32, super::TextureView); crate::MAX_COLOR_TARGETS]>, + invalidate_attachments: ArrayVec<[u32; crate::MAX_COLOR_TARGETS + 2]>, has_pass_label: bool, dirty: Dirty, } @@ -223,12 +227,14 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { + //TODO: preserve `src.target` and `dst.target` + // at least for the buffers that require it. for copy in regions { self.cmd_buffer.commands.push(C::CopyBufferToBuffer { src: src.raw, - src_target: src.target, + src_target: glow::COPY_READ_BUFFER, dst: dst.raw, - dst_target: dst.target, + dst_target: glow::COPY_WRITE_BUFFER, copy, }) } @@ -357,6 +363,9 @@ impl crate::CommandEncoder for super::CommandEncoder { // render unsafe fn begin_render_pass(&mut self, desc: &crate::RenderPassDescriptor) { + self.state.render_size = desc.extent; + self.state.resolve_attachments.clear(); + self.state.invalidate_attachments.clear(); if let Some(label) = desc.label { let range = self.cmd_buffer.add_marker(label); self.cmd_buffer.commands.push(C::PushDebugGroup(range)); @@ -367,21 +376,44 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::ResetFramebuffer); for (i, cat) in desc.color_attachments.iter().enumerate() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; - self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: cat.target.view.clone(), }); + if let Some(ref rat) = cat.resolve_target { + self.state + .resolve_attachments + .push((attachment, rat.view.clone())); + } + if !cat.ops.contains(crate::AttachmentOp::STORE) { + self.state.invalidate_attachments.push(attachment); + } } if let Some(ref dsat) = desc.depth_stencil_attachment { - let attachment = match dsat.target.view.aspects { + let aspects = dsat.target.view.aspects; + let attachment = match aspects { crate::FormatAspect::DEPTH => glow::DEPTH_ATTACHMENT, crate::FormatAspect::STENCIL => glow::STENCIL_ATTACHMENT, _ => glow::DEPTH_STENCIL_ATTACHMENT, }; - self.cmd_buffer.commands.push(C::SetFramebufferAttachment { + self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: dsat.target.view.clone(), }); + if aspects.contains(crate::FormatAspect::DEPTH) + && !dsat.depth_ops.contains(crate::AttachmentOp::STORE) + { + self.state + .invalidate_attachments + .push(glow::DEPTH_ATTACHMENT); + } + if aspects.contains(crate::FormatAspect::STENCIL) + && !dsat.stencil_ops.contains(crate::AttachmentOp::STORE) + { + self.state + .invalidate_attachments + .push(glow::STENCIL_ATTACHMENT); + } } // set the draw buffers and states @@ -437,6 +469,19 @@ impl crate::CommandEncoder for super::CommandEncoder { } } unsafe fn end_render_pass(&mut self) { + for (attachment, dst) in self.state.resolve_attachments.drain(..) { + self.cmd_buffer.commands.push(C::ResolveAttachment { + attachment, + dst, + size: self.state.render_size, + }); + } + if !self.state.invalidate_attachments.is_empty() { + self.cmd_buffer.commands.push(C::InvalidateAttachments( + self.state.invalidate_attachments.clone(), + )); + self.state.invalidate_attachments.clear(); + } if self.state.has_pass_label { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; @@ -444,6 +489,7 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.dirty = Dirty::empty(); self.state.color_targets.clear(); self.state.vertex_attributes.clear(); + self.state.primitive = super::PrimitiveState::default(); } unsafe fn set_bind_group( @@ -562,6 +608,15 @@ impl crate::CommandEncoder for super::CommandEncoder { state_desc.stride = pipe_desc.stride; } + // set primitive state + let prim_state = conv::map_primitive_state(&pipeline.primitive); + if prim_state != self.state.primitive { + self.cmd_buffer + .commands + .push(C::SetPrimitive(prim_state.clone())); + self.state.primitive = prim_state; + } + // set depth/stencil states let mut aspects = crate::FormatAspect::empty(); if pipeline.depth_bias != self.state.depth_bias { diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 0fe545d856..8da57e2704 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -222,6 +222,22 @@ pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 { } } +pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::PrimitiveState { + //Note: state.polygon_mode is not supported, see `Features::NON_FILL_POLYGON_MODE` + super::PrimitiveState { + front_face: match state.front_face { + wgt::FrontFace::Cw => glow::CW, + wgt::FrontFace::Ccw => glow::CCW, + }, + cull_face: match state.cull_mode { + Some(wgt::Face::Front) => glow::FRONT, + Some(wgt::Face::Back) => glow::BACK, + None => 0, + }, + clamp_depth: state.clamp_depth, + } +} + pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { use wgt::TextureViewDimension as Tvd; match dim { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 55ad914e72..3a0d24a516 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -218,7 +218,13 @@ impl super::Device { } super::BindingRegister::StorageBuffers => { let index = gl.get_shader_storage_block_index(program, name).unwrap(); - gl.shader_storage_block_binding(program, index, slot as _); + log::error!( + "Unable to re-map shader storage block {} to {}", + name, + index + ); + //gl.shader_storage_block_binding(program, index, slot as _); + return Err(crate::DeviceError::Lost.into()); } super::BindingRegister::Textures | super::BindingRegister::Images => { let loc = gl.get_uniform_location(program, name).unwrap(); @@ -279,12 +285,18 @@ impl crate::Device for super::Device { glow::ARRAY_BUFFER }; - let mut map_flags = glow::MAP_PERSISTENT_BIT; + let mut map_flags = 0; if desc - .memory_flags - .contains(crate::MemoryFlag::PREFER_COHERENT) + .usage + .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) { - map_flags |= glow::MAP_COHERENT_BIT; + map_flags |= glow::MAP_PERSISTENT_BIT; + if desc + .memory_flags + .contains(crate::MemoryFlag::PREFER_COHERENT) + { + map_flags |= glow::MAP_COHERENT_BIT; + } } if desc.usage.contains(crate::BufferUse::MAP_READ) { map_flags |= glow::MAP_READ_BIT; @@ -321,18 +333,24 @@ impl crate::Device for super::Device { ) -> Result { let gl = &self.shared.context; + let is_coherent = buffer.map_flags & glow::MAP_COHERENT_BIT != 0; + let mut flags = buffer.map_flags | glow::MAP_UNSYNCHRONIZED_BIT; + if !is_coherent { + flags |= glow::MAP_FLUSH_EXPLICIT_BIT; + } + gl.bind_buffer(buffer.target, Some(buffer.raw)); let ptr = gl.map_buffer_range( buffer.target, range.start as i32, (range.end - range.start) as i32, - buffer.map_flags, + flags, ); gl.bind_buffer(buffer.target, None); Ok(crate::BufferMapping { ptr: NonNull::new(ptr).ok_or(crate::DeviceError::Lost)?, - is_coherent: buffer.map_flags & glow::MAP_COHERENT_BIT != 0, + is_coherent, }) } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { @@ -347,6 +365,7 @@ impl crate::Device for super::Device { I: Iterator, { let gl = &self.shared.context; + gl.bind_buffer(buffer.target, Some(buffer.raw)); for range in ranges { gl.flush_mapped_buffer_range( buffer.target, @@ -360,6 +379,7 @@ impl crate::Device for super::Device { I: Iterator, { let gl = &self.shared.context; + gl.bind_buffer(buffer.target, Some(buffer.raw)); for range in ranges { gl.invalidate_buffer_sub_data( buffer.target, @@ -402,6 +422,8 @@ impl crate::Device for super::Device { desc.size.height as i32, ); } + + gl.bind_renderbuffer(glow::RENDERBUFFER, None); super::TextureInner::Renderbuffer { raw } } else { let raw = gl.create_texture().unwrap(); @@ -453,6 +475,20 @@ impl crate::Device for super::Device { target } }; + + match desc.format.describe().sample_type { + wgt::TextureSampleType::Float { filterable: false } + | wgt::TextureSampleType::Uint + | wgt::TextureSampleType::Sint => { + // reset default filtering mode + gl.tex_parameter_i32(target, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); + gl.tex_parameter_i32(target, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); + } + wgt::TextureSampleType::Float { filterable: true } + | wgt::TextureSampleType::Depth => {} + } + + gl.bind_texture(target, None); super::TextureInner::Texture { raw, target } }; diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 33e9d83f36..a587ef9157 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -205,7 +205,7 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m message ); - if log_severity == log::Level::Error && false { + if cfg!(debug_assertions) && log_severity == log::Level::Error { std::process::exit(1); } } @@ -558,7 +558,7 @@ impl crate::Instance for Instance { if ret != 0 { log::error!("Error returned from ANativeWindow_setBuffersGeometry"); - return Err(w::InitError::UnsupportedWindowHandle); + return Err(crate::InstanceError); } } @@ -665,6 +665,7 @@ impl Surface { crate::SurfaceError::Lost })?; + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)); gl.blit_framebuffer( 0, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index f25b7ed993..21d7d82c02 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -97,6 +97,7 @@ pub struct Device { pub struct Queue { shared: Arc, + features: wgt::Features, draw_fbo: glow::Framebuffer, copy_fbo: glow::Framebuffer, temp_query_results: Vec, @@ -397,6 +398,15 @@ struct StencilState { back: StencilSide, } +#[derive(Clone, Debug, Default, PartialEq)] +struct PrimitiveState { + front_face: u32, + cull_face: u32, + clamp_depth: bool, +} + +type InvalidatedAttachments = arrayvec::ArrayVec<[u32; crate::MAX_COLOR_TARGETS + 2]>; + #[derive(Debug)] enum Command { Draw { @@ -474,10 +484,16 @@ enum Command { dst_offset: wgt::BufferAddress, }, ResetFramebuffer, - SetFramebufferAttachment { + BindAttachment { attachment: u32, view: TextureView, }, + ResolveAttachment { + attachment: u32, + dst: TextureView, + size: wgt::Extent3d, + }, + InvalidateAttachments(InvalidatedAttachments), SetDrawColorBuffers(u8), ClearColorF(u32, [f32; 4]), ClearColorU(u32, [u32; 4]), @@ -511,6 +527,7 @@ enum Command { attribute_desc: AttributeDesc, }, SetProgram(glow::Program), + SetPrimitive(PrimitiveState), SetBlendConstant([f32; 4]), SetColorTarget { draw_buffer_index: Option, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 214a644554..c7284290a9 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -26,6 +26,39 @@ impl super::Queue { gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); gl.disable(glow::BLEND); + gl.disable(glow::CULL_FACE); + gl.disable(glow::POLYGON_OFFSET_FILL); + if self.features.contains(wgt::Features::DEPTH_CLAMPING) { + gl.disable(glow::DEPTH_CLAMP); + } + } + + unsafe fn set_attachment(&self, fbo_target: u32, attachment: u32, view: &super::TextureView) { + let gl = &self.shared.context; + match view.inner { + super::TextureInner::Renderbuffer { raw } => { + gl.framebuffer_renderbuffer(fbo_target, attachment, glow::RENDERBUFFER, Some(raw)); + } + super::TextureInner::Texture { raw, target } => { + if is_3d_target(target) { + gl.framebuffer_texture_layer( + fbo_target, + attachment, + Some(raw), + view.mip_levels.start as i32, + view.array_layers.start as i32, + ); + } else { + gl.framebuffer_texture_2d( + fbo_target, + attachment, + target, + Some(raw), + view.mip_levels.start as i32, + ); + } + } + } } unsafe fn process(&mut self, command: &C, data_bytes: &[u8], data_words: &[u32]) { @@ -329,38 +362,39 @@ impl super::Queue { gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); } - C::SetFramebufferAttachment { + C::BindAttachment { attachment, ref view, - } => match view.inner { - super::TextureInner::Renderbuffer { raw } => { - gl.framebuffer_renderbuffer( - glow::DRAW_FRAMEBUFFER, - attachment, - glow::RENDERBUFFER, - Some(raw), - ); - } - super::TextureInner::Texture { raw, target } => { - if is_3d_target(target) { - gl.framebuffer_texture_layer( - glow::DRAW_FRAMEBUFFER, - attachment, - Some(raw), - view.mip_levels.start as i32, - view.array_layers.start as i32, - ); - } else { - gl.framebuffer_texture_2d( - glow::DRAW_FRAMEBUFFER, - attachment, - target, - Some(raw), - view.mip_levels.start as i32, - ); - } - } - }, + } => { + self.set_attachment(glow::DRAW_FRAMEBUFFER, attachment, view); + } + C::ResolveAttachment { + attachment, + ref dst, + ref size, + } => { + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.draw_fbo)); + gl.read_buffer(attachment); + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.copy_fbo)); + self.set_attachment(glow::DRAW_FRAMEBUFFER, glow::COLOR_ATTACHMENT0, dst); + gl.blit_framebuffer( + 0, + 0, + size.width as i32, + size.height as i32, + 0, + 0, + size.width as i32, + size.height as i32, + glow::COLOR_BUFFER_BIT, + glow::NEAREST, + ); + gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); + } + C::InvalidateAttachments(ref list) => { + gl.invalidate_framebuffer(glow::DRAW_FRAMEBUFFER, list); + } C::SetDrawColorBuffers(count) => { let indices = (0..count as u32) .map(|i| glow::COLOR_ATTACHMENT0 + i) @@ -380,10 +414,10 @@ impl super::Queue { gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, &mut color); } C::ClearDepth(depth) => { - gl.clear_buffer_depth_stencil(glow::DEPTH, 0, depth, 0); + gl.clear_buffer_f32_slice(glow::DEPTH, 0, &mut [depth]); } C::ClearStencil(value) => { - gl.clear_buffer_depth_stencil(glow::STENCIL, 0, 0.0, value as i32); + gl.clear_buffer_i32_slice(glow::STENCIL, 0, &mut [value as i32]); } C::BufferBarrier(raw, usage) => { let mut flags = 0; @@ -502,7 +536,12 @@ impl super::Queue { gl.depth_mask(depth.mask); } C::SetDepthBias(bias) => { - gl.polygon_offset(bias.constant as f32, bias.slope_scale); + if bias.is_enabled() { + gl.enable(glow::POLYGON_OFFSET_FILL); + gl.polygon_offset(bias.constant as f32, bias.slope_scale); + } else { + gl.disable(glow::POLYGON_OFFSET_FILL); + } } C::ConfigureDepthStencil(aspects) => { if aspects.contains(crate::FormatAspect::DEPTH) { @@ -519,6 +558,22 @@ impl super::Queue { C::SetProgram(program) => { gl.use_program(Some(program)); } + C::SetPrimitive(ref state) => { + gl.front_face(state.front_face); + if state.cull_face != 0 { + gl.enable(glow::CULL_FACE); + gl.cull_face(state.cull_face); + } else { + gl.disable(glow::CULL_FACE); + } + if self.features.contains(wgt::Features::DEPTH_CLAMPING) { + if state.clamp_depth { + gl.enable(glow::DEPTH_CLAMP); + } else { + gl.disable(glow::DEPTH_CLAMP); + } + } + } C::SetBlendConstant(c) => { gl.blend_color(c[0], c[1], c[2], c[3]); } From 403ff6faf85a9786582d1e0ca0ef1c3a4f0d6f89 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 27 Jun 2021 01:59:22 -0400 Subject: [PATCH 24/33] hal/gles: Update glow and fill up the missing methods --- Cargo.lock | 2 +- wgpu-core/src/hub.rs | 1 + wgpu-hal/Cargo.toml | 2 +- wgpu-hal/src/gles/adapter.rs | 6 ++- wgpu-hal/src/gles/device.rs | 44 ++++++++++++++------- wgpu-hal/src/gles/mod.rs | 4 +- wgpu-hal/src/gles/queue.rs | 75 ++++++++++++++++++++++-------------- 7 files changed, 87 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1727c05ce8..5b6e5e7e70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,7 +690,7 @@ dependencies = [ [[package]] name = "glow" version = "0.10.0" -source = "git+https://github.com/grovesNL/glow?rev=23d16276aaa8095d9ae507b1f70d0c9edfe3527f#23d16276aaa8095d9ae507b1f70d0c9edfe3527f" +source = "git+https://github.com/kvark/glow?branch=missing-stuff#23a3f95b396ef7b3a99054494f331af25c071705" dependencies = [ "js-sys", "slotmap", diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 5a27fcb6fd..e592c70b6c 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -855,6 +855,7 @@ impl HalApi for hal::api::Dx11 { } } */ + #[cfg(gl)] impl HalApi for hal::api::Gles { const VARIANT: Backend = Backend::Gl; diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 95a3b22209..a0892ef56c 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -38,7 +38,7 @@ 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 = { git = "https://github.com/grovesNL/glow", rev = "23d16276aaa8095d9ae507b1f70d0c9edfe3527f", optional = true } +glow = { git = "https://github.com/kvark/glow", branch = "missing-stuff", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 09c2ce3ea5..fb9573b0dd 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -190,8 +190,6 @@ impl super::Adapter { | wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES | wgt::DownlevelFlags::COMPARISON_SAMPLERS; downlevel_flags.set(wgt::DownlevelFlags::COMPUTE_SHADERS, ver >= (3, 1)); - //Note: storage textures aren't supported atm, only buffers. See - // https://github.com/grovesNL/glow/issues/174 downlevel_flags.set( wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE, ver >= (3, 1), @@ -245,6 +243,10 @@ impl super::Adapter { }; let mut private_caps = super::PrivateCapability::empty(); + private_caps.set( + super::PrivateCapability::SHADER_BINDING_LAYOUT, + ver >= (3, 1), + ); private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1)); Some(crate::ExposedAdapter { diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 3a0d24a516..04f77c811b 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -114,6 +114,9 @@ impl super::Device { use naga::back::glsl; let options = glsl::Options { version: self.shared.shading_language_version, + binding_map: Default::default(), //TODO + }; + let pipeline_options = glsl::PipelineOptions { shader_stage: naga_stage, entry_point: stage.entry_point.to_string(), }; @@ -127,11 +130,17 @@ impl super::Device { .ok_or(crate::PipelineError::EntryPoint(naga_stage))?; let mut output = String::new(); - let mut writer = glsl::Writer::new(&mut output, &shader.module, &shader.info, &options) - .map_err(|e| { - let msg = format!("{}", e); - crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg) - })?; + let mut writer = glsl::Writer::new( + &mut output, + &shader.module, + &shader.info, + &options, + &pipeline_options, + ) + .map_err(|e| { + let msg = format!("{}", e); + crate::PipelineError::Linkage(map_naga_stage(naga_stage), msg) + })?; let reflection_info = writer.write().map_err(|e| { let msg = format!("{}", e); @@ -206,8 +215,13 @@ impl super::Device { log::warn!("\tLink: {}", msg); } - //TODO: check for `PrivateCapability::EXPLICIT_LAYOUTS_IN_SHADER`? + if !self + .shared + .private_caps + .contains(super::PrivateCapability::SHADER_BINDING_LAYOUT) { + // This remapping is only needed if we aren't able to put the binding layout + // in the shader. We can't remap storage buffers this way. gl.use_program(Some(program)); for (ref name, (register, slot)) in name_binding_map { log::trace!("Get binding {:?} from program {:?}", name, program); @@ -223,7 +237,6 @@ impl super::Device { name, index ); - //gl.shader_storage_block_binding(program, index, slot as _); return Err(crate::DeviceError::Lost.into()); } super::BindingRegister::Textures | super::BindingRegister::Images => { @@ -432,10 +445,15 @@ impl crate::Device for super::Device { if desc.sample_count > 1 { let target = glow::TEXTURE_2D; gl.bind_texture(target, Some(raw)); - // https://github.com/grovesNL/glow/issues/169 - //gl.tex_storage_2d_multisample(target, desc.sample_count as i32, format_desc.tex_internal, desc.size.width as i32, desc.size.height as i32, true); - log::error!("TODO: support `tex_storage_2d_multisample` (https://github.com/grovesNL/glow/issues/169)"); - return Err(crate::DeviceError::Lost); + gl.tex_storage_2d_multisample( + target, + desc.sample_count as i32, + format_desc.internal, + desc.size.width as i32, + desc.size.height as i32, + true, + ); + target } else if desc.size.depth_or_array_layers > 1 { let target = glow::TEXTURE_2D_ARRAY; gl.bind_texture(target, Some(raw)); @@ -579,12 +597,12 @@ impl crate::Device for super::Device { ); if let Some(border_color) = desc.border_color { - let mut border = match border_color { + let border = match border_color { wgt::SamplerBorderColor::TransparentBlack => [0.0; 4], wgt::SamplerBorderColor::OpaqueBlack => [0.0, 0.0, 0.0, 1.0], wgt::SamplerBorderColor::OpaqueWhite => [1.0; 4], }; - gl.sampler_parameter_f32_slice(raw, glow::TEXTURE_BORDER_COLOR, &mut border); + gl.sampler_parameter_f32_slice(raw, glow::TEXTURE_BORDER_COLOR, &border); } if let Some(ref range) = desc.lod_clamp { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 21d7d82c02..27ac47199e 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -53,8 +53,10 @@ bitflags::bitflags! { /// Flags that affect internal code paths but do not /// change the exposed feature set. struct PrivateCapability: u32 { + /// Support explicit layouts in shader. + const SHADER_BINDING_LAYOUT = 0x0001; /// Support memory barriers. - const MEMORY_BARRIERS = 0x0001; + const MEMORY_BARRIERS = 0x0002; } } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index c7284290a9..37c55ed5e5 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -21,7 +21,6 @@ impl super::Queue { let gl = &self.shared.context; gl.use_program(None); gl.bind_framebuffer(glow::FRAMEBUFFER, None); - gl.polygon_offset(0.0, 0.0); gl.disable(glow::DEPTH_TEST); gl.disable(glow::STENCIL_TEST); gl.disable(glow::SCISSOR_TEST); @@ -119,22 +118,21 @@ impl super::Queue { ), }, C::DrawIndirect { - topology: _, + topology, indirect_buf, - indirect_offset: _, + indirect_offset, } => { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); - //TODO: https://github.com/grovesNL/glow/issues/172 - //gl.draw_arrays_indirect(topology, indirect_offset); + gl.draw_arrays_indirect_offset(topology, indirect_offset as i32); } C::DrawIndexedIndirect { - topology: _, - index_type: _, + topology, + index_type, indirect_buf, - indirect_offset: _, + indirect_offset, } => { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); - //TODO: https://github.com/grovesNL/glow/issues/172 + gl.draw_elements_indirect_offset(topology, index_type, indirect_offset as i32); } C::Dispatch(group_counts) => { gl.dispatch_compute(group_counts[0], group_counts[1], group_counts[2]); @@ -194,12 +192,29 @@ impl super::Queue { ); } gl.bind_texture(dst_target, Some(dst)); - //TODO: https://github.com/grovesNL/glow/issues/173 - #[allow(clippy::if_same_then_else)] if is_3d_target(dst_target) { - //gl.copy_tex_sub_image_3d(dst_target, copy.dst_base.mip_level, copy.dst_base.origin.x, copy.dst_base.origin.y, copy.dst_base.origin.z + layer, copy.src_base.origin.x, copy.src_base.origin.y, copy.size.width, copy.size.height); + gl.copy_tex_sub_image_3d( + dst_target, + copy.dst_base.mip_level as i32, + copy.dst_base.origin.x as i32, + copy.dst_base.origin.y as i32, + copy.dst_base.origin.z as i32 + layer, + copy.src_base.origin.x as i32, + copy.src_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + ); } else { - //gl.copy_tex_sub_image_2d(dst_target, copy.dst_base.mip_level, copy.dst_base.origin.x, copy.dst_base.origin.y, copy.src_base.origin.x, copy.src_base.origin.y, copy.size.width, copy.size.height); + gl.copy_tex_sub_image_2d( + dst_target, + copy.dst_base.mip_level as i32, + copy.dst_base.origin.x as i32, + copy.dst_base.origin.y as i32, + copy.src_base.origin.x as i32, + copy.src_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + ); } } } @@ -404,20 +419,20 @@ impl super::Queue { gl.disable_draw_buffer(glow::BLEND, draw_buffer); } } - C::ClearColorF(draw_buffer, mut color) => { - gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, &mut color); + C::ClearColorF(draw_buffer, ref color) => { + gl.clear_buffer_f32_slice(glow::COLOR, draw_buffer, color); } - C::ClearColorU(draw_buffer, mut color) => { - gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, &mut color); + C::ClearColorU(draw_buffer, ref color) => { + gl.clear_buffer_u32_slice(glow::COLOR, draw_buffer, color); } - C::ClearColorI(draw_buffer, mut color) => { - gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, &mut color); + C::ClearColorI(draw_buffer, ref color) => { + gl.clear_buffer_i32_slice(glow::COLOR, draw_buffer, color); } C::ClearDepth(depth) => { - gl.clear_buffer_f32_slice(glow::DEPTH, 0, &mut [depth]); + gl.clear_buffer_f32_slice(glow::DEPTH, 0, &[depth]); } C::ClearStencil(value) => { - gl.clear_buffer_i32_slice(glow::STENCIL, 0, &mut [value as i32]); + gl.clear_buffer_i32_slice(glow::STENCIL, 0, &[value as i32]); } C::BufferBarrier(raw, usage) => { let mut flags = 0; @@ -658,14 +673,16 @@ impl super::Queue { gl.active_texture(glow::TEXTURE0 + slot); gl.bind_texture(target, Some(texture)); } - C::BindImage { - slot: _, - binding: _, - } => { - //TODO: https://github.com/grovesNL/glow/issues/174 - //gl.bind_image_texture(slot, Some(binding.raw), binding.mip_level as i32, - // binding.array_layer.is_none(), binding.array_layer.unwrap_or_default(), - // binding.access, binding.format); + C::BindImage { slot, ref binding } => { + gl.bind_image_texture( + slot, + binding.raw, + binding.mip_level as i32, + binding.array_layer.is_none(), + binding.array_layer.unwrap_or_default() as i32, + binding.access, + binding.format, + ); } C::InsertDebugMarker(ref range) => { let marker = extract_marker(data_bytes, range); From e4aee903416d7aa3e2d7936ea6053eedab2ac801 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 28 Jun 2021 15:41:08 -0400 Subject: [PATCH 25/33] hal/gles: object labels, view dimensions, and buffer clears --- Cargo.lock | 4 +- wgpu-core/Cargo.toml | 2 +- wgpu-core/src/instance.rs | 7 ++- wgpu-hal/Cargo.toml | 6 +-- wgpu-hal/src/gles/adapter.rs | 12 +++++ wgpu-hal/src/gles/command.rs | 2 + wgpu-hal/src/gles/conv.rs | 2 +- wgpu-hal/src/gles/device.rs | 97 ++++++++++++++++++++++++++++-------- wgpu-hal/src/gles/egl.rs | 7 +++ wgpu-hal/src/gles/mod.rs | 12 ++++- wgpu-hal/src/gles/queue.rs | 23 ++++++++- wgpu-hal/src/lib.rs | 2 + wgpu/Cargo.toml | 6 +-- 13 files changed, 148 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b6e5e7e70..b138275799 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,7 +690,7 @@ dependencies = [ [[package]] name = "glow" version = "0.10.0" -source = "git+https://github.com/kvark/glow?branch=missing-stuff#23a3f95b396ef7b3a99054494f331af25c071705" +source = "git+https://github.com/grovesNL/glow?rev=57177a01b1dd91a82ccfd2d7b687fcc36116157c#57177a01b1dd91a82ccfd2d7b687fcc36116157c" dependencies = [ "js-sys", "slotmap", @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "naga" version = "0.5.0" -source = "git+https://github.com/gfx-rs/naga?rev=57b325602015ce6445749a4d8ee5d491edc818d7#57b325602015ce6445749a4d8ee5d491edc818d7" +source = "git+https://github.com/gfx-rs/naga?rev=e8b71b8dc5cd70535308591f1dd2dba5f92f44eb#e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" dependencies = [ "bit-set", "bitflags", diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index dcd72f749f..c5df52b8f9 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -36,7 +36,7 @@ thiserror = "1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" features = ["wgsl-in"] [dependencies.wgt] diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 4e5039e2f7..6a16a6633a 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -210,7 +210,12 @@ impl Adapter { let caps = &self.raw.capabilities; if !caps.downlevel.is_webgpu_compliant() { - log::warn!("{}", DOWNLEVEL_WARNING_MESSAGE); + let missing_flags = wgt::DownlevelFlags::COMPLIANT - caps.downlevel.flags; + log::warn!( + "Missing downlevel flags: {:?}\n{}", + missing_flags, + DOWNLEVEL_WARNING_MESSAGE + ); } // Verify feature preconditions diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index a0892ef56c..b9dee0688a 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -38,7 +38,7 @@ 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 = { git = "https://github.com/kvark/glow", branch = "missing-stuff", optional = true } +glow = { git = "https://github.com/grovesNL/glow", rev = "57177a01b1dd91a82ccfd2d7b687fcc36116157c", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true } @@ -54,11 +54,11 @@ core-graphics-types = "0.1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" features = ["wgsl-in"] [dev-dependencies] diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index fb9573b0dd..ba14afd9b3 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -247,6 +247,10 @@ impl super::Adapter { super::PrivateCapability::SHADER_BINDING_LAYOUT, ver >= (3, 1), ); + private_caps.set( + super::PrivateCapability::SHADER_TEXTURE_SHADOW_LOD, + extensions.contains("GL_EXT_texture_shadow_lod"), + ); private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1)); Some(crate::ExposedAdapter { @@ -295,6 +299,13 @@ impl crate::Adapter for super::Adapter { .map_err(|_| crate::DeviceError::OutOfMemory)?; gl.bind_vertex_array(Some(main_vao)); + let zero_buffer = gl + .create_buffer() + .map_err(|_| crate::DeviceError::OutOfMemory)?; + gl.bind_buffer(glow::COPY_READ_BUFFER, Some(zero_buffer)); + let zeroes = vec![0u8; super::ZERO_BUFFER_SIZE]; + gl.buffer_data_u8_slice(glow::COPY_READ_BUFFER, &zeroes, glow::STATIC_DRAW); + Ok(crate::OpenDevice { device: super::Device { shared: Arc::clone(&self.shared), @@ -309,6 +320,7 @@ impl crate::Adapter for super::Adapter { copy_fbo: gl .create_framebuffer() .map_err(|_| crate::DeviceError::OutOfMemory)?, + zero_buffer, temp_query_results: Vec::new(), }, }) diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index e97e0fcbe9..87194678b2 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -214,6 +214,7 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn fill_buffer(&mut self, buffer: &super::Buffer, range: crate::MemoryRange, value: u8) { self.cmd_buffer.commands.push(C::FillBuffer { dst: buffer.raw, + dst_target: buffer.target, range, value, }); @@ -346,6 +347,7 @@ impl crate::CommandEncoder for super::CommandEncoder { range: Range, buffer: &super::Buffer, offset: wgt::BufferAddress, + _stride: wgt::BufferSize, ) { let start = self.cmd_buffer.data_words.len(); self.cmd_buffer diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 8da57e2704..7b00cd9871 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -238,7 +238,7 @@ pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::Primiti } } -pub fn map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { +pub fn _map_view_dimension(dim: wgt::TextureViewDimension) -> u32 { use wgt::TextureViewDimension as Tvd; match dim { Tvd::D1 | Tvd::D2 => glow::TEXTURE_2D, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 04f77c811b..ff51975b56 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -76,6 +76,7 @@ impl super::Device { &self, shader: &str, naga_stage: naga::ShaderStage, + label: Option<&str>, ) -> Result { let gl = &self.shared.context; let target = match naga_stage { @@ -85,6 +86,10 @@ impl super::Device { }; let raw = gl.create_shader(target).unwrap(); + if gl.supports_debug() { + gl.object_label(glow::SHADER, raw, label); + } + gl.shader_source(raw, shader); gl.compile_shader(raw); @@ -112,10 +117,6 @@ impl super::Device { context: CompilationContext, ) -> Result { use naga::back::glsl; - let options = glsl::Options { - version: self.shared.shading_language_version, - binding_map: Default::default(), //TODO - }; let pipeline_options = glsl::PipelineOptions { shader_stage: naga_stage, entry_point: stage.entry_point.to_string(), @@ -134,7 +135,7 @@ impl super::Device { &mut output, &shader.module, &shader.info, - &options, + &context.layout.naga_options, &pipeline_options, ) .map_err(|e| { @@ -155,16 +156,22 @@ impl super::Device { reflection_info, ); - unsafe { self.compile_shader(&output, naga_stage) } + unsafe { self.compile_shader(&output, naga_stage, stage.module.label.as_deref()) } } unsafe fn create_pipeline<'a, I: Iterator>>( &self, shaders: I, layout: &super::PipelineLayout, + label: crate::Label, ) -> Result { let gl = &self.shared.context; let program = gl.create_program().unwrap(); + if let Some(label) = label { + if gl.supports_debug() { + gl.object_label(glow::PROGRAM, program, Some(label)); + } + } let mut name_binding_map = NameBindingMap::default(); let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS]; @@ -191,7 +198,8 @@ impl super::Device { }; let shader_src = format!("#version {} es \n void main(void) {{}}", version,); log::info!("Only vertex shader is present. Creating an empty fragment shader",); - let shader = self.compile_shader(&shader_src, naga::ShaderStage::Fragment)?; + let shader = + self.compile_shader(&shader_src, naga::ShaderStage::Fragment, Some("_dummy"))?; shaders_to_delete.push(shader); } @@ -327,6 +335,12 @@ impl crate::Device for super::Device { gl.buffer_storage(target, raw_size, None, map_flags); gl.bind_buffer(target, None); + if let Some(label) = desc.label { + if gl.supports_debug() { + gl.object_label(glow::BUFFER, raw, Some(label)); + } + } + Ok(super::Buffer { raw, target, @@ -436,6 +450,12 @@ impl crate::Device for super::Device { ); } + if let Some(label) = desc.label { + if gl.supports_debug() { + gl.object_label(glow::RENDERBUFFER, raw, Some(label)); + } + } + gl.bind_renderbuffer(glow::RENDERBUFFER, None); super::TextureInner::Renderbuffer { raw } } else { @@ -494,6 +514,12 @@ impl crate::Device for super::Device { } }; + if let Some(label) = desc.label { + if gl.supports_debug() { + gl.object_label(glow::TEXTURE, raw, Some(label)); + } + } + match desc.format.describe().sample_type { wgt::TextureSampleType::Float { filterable: false } | wgt::TextureSampleType::Uint @@ -548,15 +574,8 @@ impl crate::Device for super::Device { None => texture.mip_level_count, }; Ok(super::TextureView { - inner: match texture.inner { - super::TextureInner::Renderbuffer { raw } => { - super::TextureInner::Renderbuffer { raw } - } - super::TextureInner::Texture { raw, target: _ } => super::TextureInner::Texture { - raw, - target: conv::map_view_dimension(desc.dimension), - }, - }, + //TODO: use `conv::map_view_dimension(desc.dimension)`? + inner: texture.inner.clone(), sample_type: texture.format.describe().sample_type, aspects: crate::FormatAspect::from(texture.format) & crate::FormatAspect::from(desc.range.aspect), @@ -573,6 +592,11 @@ impl crate::Device for super::Device { let gl = &self.shared.context; let raw = gl.create_sampler().unwrap(); + if let Some(label) = desc.label { + if gl.supports_debug() { + gl.object_label(glow::SAMPLER, raw, Some(label)); + } + } let (min, mag) = conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter); @@ -661,6 +685,8 @@ impl crate::Device for super::Device { &self, desc: &crate::PipelineLayoutDescriptor, ) -> Result { + use naga::back::glsl; + let mut group_infos = Vec::with_capacity(desc.bind_group_layouts.len()); let mut num_samplers = 0u8; let mut num_textures = 0u8; @@ -668,7 +694,16 @@ impl crate::Device for super::Device { let mut num_uniform_buffers = 0u8; let mut num_storage_buffers = 0u8; - for bg_layout in desc.bind_group_layouts { + let mut writer_flags = glsl::WriterFlags::ADJUST_COORDINATE_SPACE; + writer_flags.set( + glsl::WriterFlags::TEXTURE_SHADOW_LOD, + self.shared + .private_caps + .contains(super::PrivateCapability::SHADER_TEXTURE_SHADOW_LOD), + ); + let mut binding_map = glsl::BindingMap::default(); + + for (group_index, bg_layout) in desc.bind_group_layouts.iter().enumerate() { // create a vector with the size enough to hold all the bindings, filled with `!0` let mut binding_to_slot = vec![ !0; @@ -695,6 +730,11 @@ impl crate::Device for super::Device { }; binding_to_slot[entry.binding as usize] = *counter; + let br = naga::ResourceBinding { + group: group_index as u32, + binding: entry.binding, + }; + binding_map.insert(br, *counter); *counter += entry.count.map_or(1, |c| c.get() as u8); } @@ -706,6 +746,11 @@ impl crate::Device for super::Device { Ok(super::PipelineLayout { group_infos: group_infos.into_boxed_slice(), + naga_options: glsl::Options { + version: self.shared.shading_language_version, + writer_flags, + binding_map, + }, }) } unsafe fn destroy_pipeline_layout(&self, _pipeline_layout: super::PipelineLayout) {} @@ -782,7 +827,7 @@ impl crate::Device for super::Device { unsafe fn create_shader_module( &self, - _desc: &crate::ShaderModuleDescriptor, + desc: &crate::ShaderModuleDescriptor, shader: crate::ShaderInput, ) -> Result { Ok(super::ShaderModule { @@ -792,6 +837,7 @@ impl crate::Device for super::Device { } crate::ShaderInput::Naga(naga) => naga, }, + label: desc.label.map(|str| str.to_string()), }) } unsafe fn destroy_shader_module(&self, _module: super::ShaderModule) {} @@ -805,7 +851,7 @@ impl crate::Device for super::Device { .as_ref() .map(|fs| (naga::ShaderStage::Fragment, fs)), ); - let inner = self.create_pipeline(shaders, desc.layout)?; + let inner = self.create_pipeline(shaders, desc.layout, desc.label)?; let (vertex_buffers, vertex_attributes) = { let mut buffers = Vec::new(); @@ -872,7 +918,7 @@ impl crate::Device for super::Device { desc: &crate::ComputePipelineDescriptor, ) -> Result { let shaders = iter::once((naga::ShaderStage::Compute, &desc.stage)); - let inner = self.create_pipeline(shaders, desc.layout)?; + let inner = self.create_pipeline(shaders, desc.layout, desc.label)?; Ok(super::ComputePipeline { inner }) } @@ -885,13 +931,22 @@ impl crate::Device for super::Device { &self, desc: &wgt::QuerySetDescriptor, ) -> Result { + use std::fmt::Write; let gl = &self.shared.context; + let mut temp_string = String::new(); let mut queries = Vec::with_capacity(desc.count as usize); - for _ in 0..desc.count { + for i in 0..desc.count { let query = gl .create_query() .map_err(|_| crate::DeviceError::OutOfMemory)?; + if gl.supports_debug() { + if let Some(label) = desc.label { + temp_string.clear(); + let _ = write!(temp_string, "{}[{}]", label, i); + gl.object_label(glow::QUERY, query, Some(&temp_string)); + } + } queries.push(query); } diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index a587ef9157..85d61cc174 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -609,6 +609,13 @@ impl crate::Instance for Instance { .map_or(ptr::null(), |p| p as *const _) }); + if self.flags.contains(crate::InstanceFlag::DEBUG) && gl.supports_debug() { + log::info!( + "Max label length: {}", + gl.get_parameter_i32(glow::MAX_LABEL_LENGTH) + ); + } + if self.flags.contains(crate::InstanceFlag::VALIDATION) && gl.supports_debug() { log::info!("Enabling GLES debug output"); gl.enable(glow::DEBUG_OUTPUT); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 27ac47199e..7fc8d9ecc1 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -22,6 +22,7 @@ pub struct Api; const MAX_TEXTURE_SLOTS: usize = 16; const MAX_SAMPLERS: usize = 16; const MAX_VERTEX_ATTRIBUTES: usize = 16; +const ZERO_BUFFER_SIZE: usize = 256 << 10; impl crate::Api for Api { type Instance = Instance; @@ -55,8 +56,10 @@ bitflags::bitflags! { struct PrivateCapability: u32 { /// Support explicit layouts in shader. const SHADER_BINDING_LAYOUT = 0x0001; + /// Support extended shadow sampling instructions. + const SHADER_TEXTURE_SHADOW_LOD = 0x0002; /// Support memory barriers. - const MEMORY_BARRIERS = 0x0002; + const MEMORY_BARRIERS = 0x0004; } } @@ -102,6 +105,10 @@ pub struct Queue { features: wgt::Features, draw_fbo: glow::Framebuffer, copy_fbo: glow::Framebuffer, + /// Keep a reasonably large buffer filled with zeroes, + /// so that we can implement `FillBuffer` of zeroes + /// by copying from it. + zero_buffer: glow::Buffer, temp_query_results: Vec, } @@ -172,6 +179,7 @@ struct BindGroupLayoutInfo { pub struct PipelineLayout { group_infos: Box<[BindGroupLayoutInfo]>, + naga_options: naga::back::glsl::Options, } impl PipelineLayout { @@ -213,6 +221,7 @@ pub struct BindGroup { #[derive(Debug)] pub struct ShaderModule { naga: crate::NagaShader, + label: Option, } #[derive(Clone, Debug, Default)] @@ -443,6 +452,7 @@ enum Command { }, FillBuffer { dst: glow::Buffer, + dst_target: BindTarget, range: crate::MemoryRange, value: u8, }, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 37c55ed5e5..a00fa883d1 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -144,7 +144,28 @@ impl super::Queue { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)); gl.dispatch_compute_indirect(indirect_offset as i32); } - C::FillBuffer { .. } => unimplemented!(), + C::FillBuffer { + dst, + dst_target, + ref range, + value, + } => { + assert_eq!(value, 0); // other values require `wgt::Features::CLEAR_COMMANDS`. + gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer)); + gl.bind_buffer(dst_target, Some(dst)); + let mut dst_offset = range.start; + while dst_offset < range.end { + let size = (range.end - dst_offset).min(super::ZERO_BUFFER_SIZE as u64); + gl.copy_buffer_sub_data( + glow::COPY_READ_BUFFER, + dst_target, + 0, + dst_offset as i32, + size as i32, + ); + dst_offset += size; + } + } C::CopyBufferToBuffer { src, src_target, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index c437a04413..2d066d681f 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -337,6 +337,8 @@ pub trait CommandEncoder: Send + Sync { // copy operations + /// This is valid to call with `value == 0`. + /// Otherwise `wgt::Features::CLEAR_COMMANDS` is required. unsafe fn fill_buffer(&mut self, buffer: &A::Buffer, range: MemoryRange, value: u8); unsafe fn copy_buffer_to_buffer(&mut self, src: &A::Buffer, dst: &A::Buffer, regions: T) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 5e0f5efbee..08c0938b7e 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -73,19 +73,19 @@ env_logger = "0.8" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" optional = true # used to test all the example shaders [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" features = ["wgsl-in"] # used to generate SPIR-V for the Web target [target.'cfg(target_arch = "wasm32")'.dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "57b325602015ce6445749a4d8ee5d491edc818d7" +rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" features = ["wgsl-in", "spv-out"] [[example]] From 25ec7447e26cd0167743dc95107b902d08d06f3d Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 28 Jun 2021 16:21:12 -0400 Subject: [PATCH 26/33] hal/gles: improve the exposed limits --- wgpu-hal/src/gles/adapter.rs | 23 ++++++++++++++++------- wgpu-hal/src/gles/command.rs | 4 ++-- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index ba14afd9b3..1a1717083a 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -195,6 +195,8 @@ impl super::Adapter { ver >= (3, 1), ); downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, ver >= (3, 1)); + //TODO: we can actually support positive `base_vertex` in the same way + // as we emulate the `start_instance`. But we can't deal with negatives... downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, ver >= (3, 2)); downlevel_flags.set( wgt::DownlevelFlags::INDEPENDENT_BLENDING, @@ -214,6 +216,12 @@ impl super::Adapter { let max_uniform_buffers_per_shader_stage = gl.get_parameter_i32(glow::MAX_VERTEX_UNIFORM_BLOCKS) .min(gl.get_parameter_i32(glow::MAX_FRAGMENT_UNIFORM_BLOCKS)) as u32; + let max_storage_buffers_per_shader_stage = gl + .get_parameter_i32(glow::MAX_VERTEX_SHADER_STORAGE_BLOCKS) + .min(gl.get_parameter_i32(glow::MAX_FRAGMENT_SHADER_STORAGE_BLOCKS)) + as u32; + let max_storage_textures_per_shader_stage = + gl.get_parameter_i32(glow::MAX_FRAGMENT_IMAGE_UNIFORMS) as u32; let limits = wgt::Limits { max_texture_dimension_1d: max_texture_size, @@ -221,12 +229,12 @@ impl super::Adapter { max_texture_dimension_3d: max_texture_3d_size, max_texture_array_layers: gl.get_parameter_i32(glow::MAX_ARRAY_TEXTURE_LAYERS) as u32, max_bind_groups: crate::MAX_BIND_GROUPS as u32, - max_dynamic_uniform_buffers_per_pipeline_layout: 8, - max_dynamic_storage_buffers_per_pipeline_layout: 4, - max_sampled_textures_per_shader_stage: 16, - max_samplers_per_shader_stage: 16, - max_storage_buffers_per_shader_stage: 8, - max_storage_textures_per_shader_stage: 8, + max_dynamic_uniform_buffers_per_pipeline_layout: max_uniform_buffers_per_shader_stage, + max_dynamic_storage_buffers_per_pipeline_layout: max_storage_buffers_per_shader_stage, + max_sampled_textures_per_shader_stage: super::MAX_TEXTURE_SLOTS as u32, + max_samplers_per_shader_stage: super::MAX_SAMPLERS as u32, + max_storage_buffers_per_shader_stage, + max_storage_textures_per_shader_stage, max_uniform_buffers_per_shader_stage, max_uniform_buffer_binding_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE) as u32, @@ -238,7 +246,8 @@ impl super::Adapter { max_vertex_buffers: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_BINDINGS) as u32, max_vertex_attributes: (gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIBS) as u32) .min(super::MAX_VERTEX_ATTRIBUTES as u32), - max_vertex_buffer_array_stride: 2048, + max_vertex_buffer_array_stride: gl.get_parameter_i32(glow::MAX_VERTEX_ATTRIB_STRIDE) + as u32, max_push_constant_size: 0, }; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 87194678b2..8ba5fbebb0 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -827,7 +827,7 @@ impl crate::CommandEncoder for super::CommandEncoder { _count_offset: wgt::BufferAddress, _max_count: u32, ) { - unimplemented!() + unreachable!() } unsafe fn draw_indexed_indirect_count( &mut self, @@ -837,7 +837,7 @@ impl crate::CommandEncoder for super::CommandEncoder { _count_offset: wgt::BufferAddress, _max_count: u32, ) { - unimplemented!() + unreachable!() } // compute From 6025a8d25e9809527b2cc132dbbf8c9f3620e427 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 28 Jun 2021 23:01:08 -0400 Subject: [PATCH 27/33] hal/gles: enable robust access by default --- wgpu-hal/src/gles/egl.rs | 53 ++++++++++++++++----------------- wgpu-hal/src/vulkan/instance.rs | 8 +++++ wgpu/src/util/init.rs | 4 +-- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 85d61cc174..c976b480d0 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -140,7 +140,7 @@ fn choose_config( 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); + log::info!("\tTrying {}", name); attributes.clear(); for &(_, tier_attr) in tiers[..=tier_max].iter() { @@ -229,7 +229,6 @@ impl Inner { 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(); @@ -266,14 +265,18 @@ impl Inner { egl::CONTEXT_CLIENT_VERSION, 3, // Request GLES 3.0 or higher ]; - if flags.contains(crate::InstanceFlag::DEBUG) - && wsi_library.is_none() - && !cfg!(target_os = "android") - { + if flags.contains(crate::InstanceFlag::DEBUG) && !cfg!(target_os = "android") { + log::info!("\tEGL context: +debug"); //TODO: figure out why this is needed context_attributes.push(egl::CONTEXT_OPENGL_DEBUG); context_attributes.push(egl::TRUE as _); } + if display_extensions.contains("EGL_EXT_create_context_robustness") { + log::info!("\tEGL context: +robust access"); + context_attributes.push(egl::CONTEXT_OPENGL_ROBUST_ACCESS); + context_attributes.push(egl::TRUE as _); + //TODO do we need `egl::CONTEXT_OPENGL_NOTIFICATION_STRATEGY_EXT`? + } context_attributes.push(egl::NONE); let context = match egl.create_context(display, config, None, &context_attributes) { Ok(context) => context, @@ -285,20 +288,19 @@ impl Inner { // 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 - }; + 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!("\tEGL context: +surfaceless"); + None + }; Ok(Self { egl, @@ -413,7 +415,7 @@ impl crate::Instance for Instance { (function)(Some(egl_debug_proc), attributes.as_ptr()); } - let inner = Inner::create(desc.flags, egl, display, wsi_library.as_ref())?; + let inner = Inner::create(desc.flags, egl, display)?; Ok(Instance { wsi_library, @@ -475,13 +477,8 @@ impl crate::Instance for Instance { ) .unwrap(); - let new_inner = Inner::create( - self.flags, - inner.egl.clone(), - display, - self.wsi_library.as_ref(), - ) - .map_err(|_| crate::InstanceError)?; + let new_inner = Inner::create(self.flags, inner.egl.clone(), display) + .map_err(|_| crate::InstanceError)?; let old_inner = std::mem::replace(inner.deref_mut(), new_inner); inner.wl_display = Some(handle.display); diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 1563d33c28..584435d655 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -287,6 +287,14 @@ impl super::Instance { } } +impl Drop for super::Instance { + fn drop(&mut self) { + unsafe { + self.shared.raw.destroy_instance(None); + } + } +} + impl crate::Instance for super::Instance { unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { let entry = match ash::Entry::new() { diff --git a/wgpu/src/util/init.rs b/wgpu/src/util/init.rs index d5587ebfd7..8afaa24457 100644 --- a/wgpu/src/util/init.rs +++ b/wgpu/src/util/init.rs @@ -42,13 +42,13 @@ pub fn initialize_adapter_from_env( instance: &Instance, backend_bits: BackendBit, ) -> Option { - let adapters = instance.enumerate_adapters(backend_bits); - let desired_adapter_name = std::env::var("WGPU_ADAPTER_NAME") .as_deref() .map(str::to_lowercase) .ok()?; + let adapters = instance.enumerate_adapters(backend_bits); + let mut chosen_adapter = None; for adapter in adapters { let info = adapter.get_info(); From 3a796c22446ff0248953a538b7cc4e080f979979 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 28 Jun 2021 23:43:40 -0400 Subject: [PATCH 28/33] hal/gles: fix buffer mapping --- wgpu-hal/src/gles/device.rs | 54 ++++++++++++++------------------ wgpu-hal/src/vulkan/instance.rs | 8 +++-- wgpu-hal/src/vulkan/mod.rs | 1 - wgpu/examples/boids/compute.wgsl | 6 ++-- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index ff51975b56..1dd1f1d008 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -306,16 +306,17 @@ impl crate::Device for super::Device { glow::ARRAY_BUFFER }; - let mut map_flags = 0; - if desc + let is_host_visible = desc .usage - .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE) - { + .intersects(crate::BufferUse::MAP_READ | crate::BufferUse::MAP_WRITE); + let is_coherent = desc + .memory_flags + .contains(crate::MemoryFlag::PREFER_COHERENT); + let mut map_flags = 0; + + if is_host_visible { map_flags |= glow::MAP_PERSISTENT_BIT; - if desc - .memory_flags - .contains(crate::MemoryFlag::PREFER_COHERENT) - { + if is_coherent { map_flags |= glow::MAP_COHERENT_BIT; } } @@ -335,6 +336,11 @@ impl crate::Device for super::Device { gl.buffer_storage(target, raw_size, None, map_flags); gl.bind_buffer(target, None); + if !is_coherent && desc.usage.contains(crate::BufferUse::MAP_WRITE) { + map_flags |= glow::MAP_FLUSH_EXPLICIT_BIT; + } + //TODO: do we need `glow::MAP_UNSYNCHRONIZED_BIT`? + if let Some(label) = desc.label { if gl.supports_debug() { gl.object_label(glow::BUFFER, raw, Some(label)); @@ -361,17 +367,13 @@ impl crate::Device for super::Device { let gl = &self.shared.context; let is_coherent = buffer.map_flags & glow::MAP_COHERENT_BIT != 0; - let mut flags = buffer.map_flags | glow::MAP_UNSYNCHRONIZED_BIT; - if !is_coherent { - flags |= glow::MAP_FLUSH_EXPLICIT_BIT; - } gl.bind_buffer(buffer.target, Some(buffer.raw)); let ptr = gl.map_buffer_range( buffer.target, range.start as i32, (range.end - range.start) as i32, - flags, + buffer.map_flags, ); gl.bind_buffer(buffer.target, None); @@ -401,19 +403,8 @@ impl crate::Device for super::Device { ); } } - unsafe fn invalidate_mapped_ranges(&self, buffer: &super::Buffer, ranges: I) - where - I: Iterator, - { - let gl = &self.shared.context; - gl.bind_buffer(buffer.target, Some(buffer.raw)); - for range in ranges { - gl.invalidate_buffer_sub_data( - buffer.target, - range.start as i32, - (range.end - range.start) as i32, - ); - } + unsafe fn invalidate_mapped_ranges(&self, _buffer: &super::Buffer, _ranges: I) { + //TODO: do we need to do anything? } unsafe fn create_texture( @@ -592,11 +583,6 @@ impl crate::Device for super::Device { let gl = &self.shared.context; let raw = gl.create_sampler().unwrap(); - if let Some(label) = desc.label { - if gl.supports_debug() { - gl.object_label(glow::SAMPLER, raw, Some(label)); - } - } let (min, mag) = conv::map_filter_modes(desc.min_filter, desc.mag_filter, desc.mipmap_filter); @@ -652,6 +638,12 @@ impl crate::Device for super::Device { ); } + if let Some(label) = desc.label { + if gl.supports_debug() { + gl.object_label(glow::SAMPLER, raw, Some(label)); + } + } + Ok(super::Sampler { raw }) } unsafe fn destroy_sampler(&self, sampler: super::Sampler) { diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 584435d655..1f046ec02c 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -287,10 +287,14 @@ impl super::Instance { } } -impl Drop for super::Instance { +impl Drop for super::InstanceShared { fn drop(&mut self) { unsafe { - self.shared.raw.destroy_instance(None); + if let Some(du) = self.debug_utils.take() { + du.extension + .destroy_debug_utils_messenger(du.messenger, None); + } + self.raw.destroy_instance(None); } } } diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index dd27836c7e..133bb21f92 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -48,7 +48,6 @@ impl crate::Api for Api { struct DebugUtils { extension: ext::DebugUtils, - #[allow(dead_code)] messenger: vk::DebugUtilsMessengerEXT, } diff --git a/wgpu/examples/boids/compute.wgsl b/wgpu/examples/boids/compute.wgsl index bddb260a2d..e0c6e9e71d 100644 --- a/wgpu/examples/boids/compute.wgsl +++ b/wgpu/examples/boids/compute.wgsl @@ -41,8 +41,6 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3) { var cMassCount : i32 = 0; var cVelCount : i32 = 0; - var pos : vec2; - var vel : vec2; var i : u32 = 0u; loop { if (i >= total) { @@ -52,8 +50,8 @@ fn main([[builtin(global_invocation_id)]] global_invocation_id: vec3) { continue; } - pos = particlesSrc.particles[i].pos; - vel = particlesSrc.particles[i].vel; + let pos = particlesSrc.particles[i].pos; + let vel = particlesSrc.particles[i].vel; if (distance(pos, vPos) < params.rule1Distance) { cMass = cMass + pos; From 582c128520814e0e2de50293787026ec626d58be Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 29 Jun 2021 01:51:52 -0400 Subject: [PATCH 29/33] Pick up naga's GLSL continuing and Y-flip fixes --- Cargo.lock | 2 +- wgpu-core/Cargo.toml | 2 +- wgpu-hal/Cargo.toml | 4 ++-- wgpu-hal/src/gles/conv.rs | 7 +++++-- wgpu-hal/src/gles/egl.rs | 7 +++++-- wgpu/Cargo.toml | 6 +++--- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b138275799..e098ea1b95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "naga" version = "0.5.0" -source = "git+https://github.com/gfx-rs/naga?rev=e8b71b8dc5cd70535308591f1dd2dba5f92f44eb#e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +source = "git+https://github.com/gfx-rs/naga?rev=68a2efd3c5db62c2c011ccbad84f58be5e539fe3#68a2efd3c5db62c2c011ccbad84f58be5e539fe3" dependencies = [ "bit-set", "bitflags", diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index c5df52b8f9..458a8cda90 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -36,7 +36,7 @@ thiserror = "1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" features = ["wgsl-in"] [dependencies.wgt] diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index b9dee0688a..49445d39b9 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -54,11 +54,11 @@ core-graphics-types = "0.1" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" features = ["wgsl-in"] [dev-dependencies] diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 7b00cd9871..2f1f4fc98a 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -225,9 +225,12 @@ pub fn map_primitive_topology(topology: wgt::PrimitiveTopology) -> u32 { pub(super) fn map_primitive_state(state: &wgt::PrimitiveState) -> super::PrimitiveState { //Note: state.polygon_mode is not supported, see `Features::NON_FILL_POLYGON_MODE` super::PrimitiveState { + //Note: we are flipping the front face, so that + // the Y-flip in the generated GLSL keeps the same visibility. + // See `naga::back::glsl::WriterFlags::ADJUST_COORDINATE_SPACE`. front_face: match state.front_face { - wgt::FrontFace::Cw => glow::CW, - wgt::FrontFace::Ccw => glow::CCW, + wgt::FrontFace::Cw => glow::CCW, + wgt::FrontFace::Ccw => glow::CW, }, cull_face: match state.cull_mode { Some(wgt::Face::Front) => glow::FRONT, diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index c976b480d0..62ced7e9a2 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -671,11 +671,14 @@ impl Surface { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)); + // Note the Y-flipping here. GL's presentation is not flipped, + // but main rendering is. Therefore, we Y-flip the output positions + // in the shader, and also this blit. gl.blit_framebuffer( 0, - 0, - sc.extent.width as i32, sc.extent.height as i32, + sc.extent.width as i32, + 0, 0, 0, sc.extent.width as i32, diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 08c0938b7e..a81036ac8e 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -73,19 +73,19 @@ env_logger = "0.8" [dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" optional = true # used to test all the example shaders [dev-dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" features = ["wgsl-in"] # used to generate SPIR-V for the Web target [target.'cfg(target_arch = "wasm32")'.dependencies.naga] git = "https://github.com/gfx-rs/naga" -rev = "e8b71b8dc5cd70535308591f1dd2dba5f92f44eb" +rev = "68a2efd3c5db62c2c011ccbad84f58be5e539fe3" features = ["wgsl-in", "spv-out"] [[example]] From 40e2c33c6f8426615f1713d3428bdb87a90091c6 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 29 Jun 2021 15:25:03 -0400 Subject: [PATCH 30/33] hal/gles: hack around cubemap support --- wgpu-hal/src/gles/device.rs | 24 +++++++-- wgpu-hal/src/gles/queue.rs | 101 ++++++++++++++++++++++++++---------- 2 files changed, 96 insertions(+), 29 deletions(-) diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 1dd1f1d008..e8e2e78ab4 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -451,6 +451,14 @@ impl crate::Device for super::Device { super::TextureInner::Renderbuffer { raw } } else { let raw = gl.create_texture().unwrap(); + //HACK: detect a cube map + let cube_count = if desc.size.width == desc.size.height + && desc.size.depth_or_array_layers % 6 == 0 + { + Some(desc.size.depth_or_array_layers / 6) + } else { + None + }; let target = match desc.dimension { wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { if desc.sample_count > 1 { @@ -465,8 +473,11 @@ impl crate::Device for super::Device { true, ); target - } else if desc.size.depth_or_array_layers > 1 { - let target = glow::TEXTURE_2D_ARRAY; + } else if desc.size.depth_or_array_layers > 1 && cube_count != Some(1) { + let target = match cube_count { + Some(_) => glow::TEXTURE_CUBE_MAP_ARRAY, + None => glow::TEXTURE_2D_ARRAY, + }; gl.bind_texture(target, Some(raw)); gl.tex_storage_3d( target, @@ -478,7 +489,10 @@ impl crate::Device for super::Device { ); target } else { - let target = glow::TEXTURE_2D; + let target = match cube_count { + Some(_) => glow::TEXTURE_CUBE_MAP, + None => glow::TEXTURE_2D, + }; gl.bind_texture(target, Some(raw)); gl.tex_storage_2d( target, @@ -772,6 +786,10 @@ impl crate::Device for super::Device { } wgt::BindingType::Texture { .. } => { let view = desc.textures[entry.resource_index as usize].view; + if view.mip_levels.start != 0 || view.array_layers.start != 0 { + log::error!("Unable to create a sampled texture binding for non-zero mipmap level or array layer.\n{}", + "This is an implementation problem of wgpu-hal/gles backend.") + } match view.inner { super::TextureInner::Renderbuffer { .. } => { panic!("Unable to use a renderbuffer in a group") diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index a00fa883d1..04e34d48c7 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -5,6 +5,15 @@ use std::{mem, ops::Range, slice}; const DEBUG_ID: u32 = 0; +const CUBEMAP_FACES: [u32; 6] = [ + glow::TEXTURE_CUBE_MAP_POSITIVE_X, + glow::TEXTURE_CUBE_MAP_NEGATIVE_X, + glow::TEXTURE_CUBE_MAP_POSITIVE_Y, + glow::TEXTURE_CUBE_MAP_NEGATIVE_Y, + glow::TEXTURE_CUBE_MAP_POSITIVE_Z, + glow::TEXTURE_CUBE_MAP_NEGATIVE_Z, +]; + fn extract_marker<'a>(data: &'a [u8], range: &Range) -> &'a str { std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap() } @@ -191,6 +200,7 @@ impl super::Queue { dst_target, ref copy, } => { + //TODO: cubemaps //TODO: how is depth handled? gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); for layer in 0..copy.size.depth_or_array_layers as i32 { @@ -260,32 +270,70 @@ impl super::Queue { let unpack_data = glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32); gl.bind_texture(dst_target, Some(dst)); - if is_3d_target(dst_target) { - gl.tex_sub_image_3d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.texture_base.origin.z as i32, - copy.size.width as i32, - copy.size.height as i32, - copy.size.depth_or_array_layers as i32, - dst_info.external_format, - dst_info.data_type, - unpack_data, - ); - } else { - gl.tex_sub_image_2d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - dst_info.external_format, - dst_info.data_type, - unpack_data, - ); + match dst_target { + glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { + gl.tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + dst_info.external_format, + dst_info.data_type, + unpack_data, + ); + } + glow::TEXTURE_2D => { + gl.tex_sub_image_2d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + dst_info.external_format, + dst_info.data_type, + unpack_data, + ); + } + glow::TEXTURE_CUBE_MAP => { + let mut offset = copy.buffer_layout.offset as u32; + for face_index in 0..copy.size.depth_or_array_layers { + gl.tex_sub_image_2d( + CUBEMAP_FACES[(copy.texture_base.origin.z + face_index) as usize], + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + dst_info.external_format, + dst_info.data_type, + glow::PixelUnpackData::BufferOffset(offset), + ); + offset += copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get()) + * copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get()); + } + } + glow::TEXTURE_CUBE_MAP_ARRAY => { + //Note: not sure if this is correct! + gl.tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + dst_info.external_format, + dst_info.data_type, + unpack_data, + ); + } + _ => unreachable!(), } } C::CopyTextureToBuffer { @@ -297,6 +345,7 @@ impl super::Queue { ref copy, } => { //TODO: compressed data + //TODO: cubemaps let row_texels = copy .buffer_layout .bytes_per_row From 4be8864b38f05a47a63e82d4406f19a22e9e656c Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 29 Jun 2021 23:40:14 -0400 Subject: [PATCH 31/33] hal/gles: totally rework the vertex data binding --- wgpu-core/src/command/render.rs | 1 + wgpu-core/src/device/mod.rs | 4 +- wgpu-core/src/instance.rs | 5 +- wgpu-hal/src/gles/adapter.rs | 7 ++ wgpu-hal/src/gles/command.rs | 132 ++++++++++++++++++++++---------- wgpu-hal/src/gles/mod.rs | 70 ++++++++++++++++- wgpu-hal/src/gles/queue.rs | 80 ++++++++++++++----- wgpu-info/src/main.rs | 3 +- wgpu-types/src/lib.rs | 22 +++++- wgpu/tests/common/mod.rs | 1 + 10 files changed, 255 insertions(+), 70 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 66c0965fa0..0acba4a778 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1171,6 +1171,7 @@ impl Global { .inputs .extend(iter::repeat(VertexBufferState::EMPTY).take(empty_slots)); let vertex_state = &mut state.vertex.inputs[slot as usize]; + //TODO: where are we checking that the offset is in bound? vertex_state.total_size = match size { Some(s) => s.get(), None => buffer.size - offset, diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 56ea142f9b..4d972ad68b 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2518,7 +2518,7 @@ impl Global { let (device_guard, _) = hub.devices.read(&mut token); let device = device_guard.get(device_id).map_err(|_| InvalidDevice)?; - Ok(device.downlevel) + Ok(device.downlevel.clone()) } pub fn device_create_buffer( @@ -3640,7 +3640,7 @@ impl Global { encoder, dev_stored, device.limits.clone(), - device.downlevel, + device.downlevel.clone(), device.features, #[cfg(feature = "trace")] device.trace.is_some(), diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 6a16a6633a..2d6cd1368b 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -216,6 +216,7 @@ impl Adapter { missing_flags, DOWNLEVEL_WARNING_MESSAGE ); + log::info!("{:#?}", caps.downlevel); } // Verify feature preconditions @@ -257,7 +258,7 @@ impl Adapter { ref_count: self.life_guard.add_ref(), }, caps.alignments.clone(), - caps.downlevel, + caps.downlevel.clone(), desc, trace_path, ) @@ -658,7 +659,7 @@ impl Global { let (adapter_guard, _) = hub.adapters.read(&mut token); adapter_guard .get(adapter_id) - .map(|adapter| adapter.raw.capabilities.downlevel) + .map(|adapter| adapter.raw.capabilities.downlevel.clone()) .map_err(|_| InvalidAdapter) } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 1a1717083a..9230da3d4f 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -261,6 +261,12 @@ impl super::Adapter { extensions.contains("GL_EXT_texture_shadow_lod"), ); private_caps.set(super::PrivateCapability::MEMORY_BARRIERS, ver >= (3, 1)); + private_caps.set( + super::PrivateCapability::VERTEX_BUFFER_LAYOUT, + ver >= (3, 1), + ); + + let downlevel_limits = wgt::DownlevelLimits {}; Some(crate::ExposedAdapter { adapter: super::Adapter { @@ -276,6 +282,7 @@ impl super::Adapter { limits, downlevel: wgt::DownlevelCapabilities { flags: downlevel_flags, + limits: downlevel_limits, shader_model: wgt::ShaderModel::Sm5, }, alignments: crate::Alignments { diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 8ba5fbebb0..859fc7e102 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -2,13 +2,6 @@ use super::{conv, Command as C}; use arrayvec::ArrayVec; use std::{mem, ops::Range}; -bitflags::bitflags! { - #[derive(Default)] - struct Dirty: u32 { - const VERTEX_BUFFERS = 0x0001; - } -} - #[derive(Clone, Copy, Debug, Default)] struct TextureSlotDesc { tex_target: super::BindTarget, @@ -32,7 +25,8 @@ pub(super) struct State { resolve_attachments: ArrayVec<[(u32, super::TextureView); crate::MAX_COLOR_TARGETS]>, invalidate_attachments: ArrayVec<[u32; crate::MAX_COLOR_TARGETS + 2]>, has_pass_label: bool, - dirty: Dirty, + instance_vbuf_mask: usize, + dirty_vbuf_mask: usize, } impl super::CommandBuffer { @@ -75,21 +69,48 @@ impl super::CommandEncoder { } } - fn rebind_vertex_attributes(&mut self, first_instance: u32) { - for attribute in self.state.vertex_attributes.iter() { - let (buffer_desc, buffer) = - self.state.vertex_buffers[attribute.buffer_index as usize].clone(); - - let mut attribute_desc = attribute.clone(); - if buffer_desc.step == wgt::InputStepMode::Instance { - attribute_desc.offset += buffer_desc.stride * first_instance; + fn rebind_vertex_data(&mut self, first_instance: u32) { + if self + .private_caps + .contains(super::PrivateCapability::VERTEX_BUFFER_LAYOUT) + { + for (index, &(ref vb_desc, ref vb)) in self.state.vertex_buffers.iter().enumerate() { + if self.state.dirty_vbuf_mask & (1 << index) == 0 { + continue; + } + let instance_offset = match vb_desc.step { + wgt::InputStepMode::Vertex => 0, + wgt::InputStepMode::Instance => first_instance * vb_desc.stride, + }; + self.cmd_buffer.commands.push(C::SetVertexBuffer { + index: index as u32, + buffer: super::BufferBinding { + raw: vb.raw, + offset: vb.offset + instance_offset as wgt::BufferAddress, + }, + buffer_desc: vb_desc.clone(), + }); } + } else { + for attribute in self.state.vertex_attributes.iter() { + if self.state.dirty_vbuf_mask & (1 << attribute.buffer_index) == 0 { + continue; + } + let (buffer_desc, buffer) = + self.state.vertex_buffers[attribute.buffer_index as usize].clone(); - self.cmd_buffer.commands.push(C::SetVertexAttribute { - buffer_desc, - buffer, - attribute_desc, - }); + let mut attribute_desc = attribute.clone(); + attribute_desc.offset += buffer.offset as u32; + if buffer_desc.step == wgt::InputStepMode::Instance { + attribute_desc.offset += buffer_desc.stride * first_instance; + } + + self.cmd_buffer.commands.push(C::SetVertexAttribute { + buffer: Some(buffer.raw), + buffer_desc, + attribute_desc, + }); + } } } @@ -111,11 +132,13 @@ impl super::CommandEncoder { fn prepare_draw(&mut self, first_instance: u32) { if first_instance != 0 { - self.rebind_vertex_attributes(first_instance); - self.state.dirty.set(Dirty::VERTEX_BUFFERS, true); - } else if self.state.dirty.contains(Dirty::VERTEX_BUFFERS) { - self.rebind_vertex_attributes(0); - self.state.dirty.set(Dirty::VERTEX_BUFFERS, false); + self.state.dirty_vbuf_mask = self.state.instance_vbuf_mask; + } + if self.state.dirty_vbuf_mask != 0 { + self.rebind_vertex_data(first_instance); + if first_instance == 0 { + self.state.dirty_vbuf_mask = 0; + } } } @@ -488,7 +511,8 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; } - self.state.dirty = Dirty::empty(); + self.state.instance_vbuf_mask = 0; + self.state.dirty_vbuf_mask = 0; self.state.color_targets.clear(); self.state.vertex_attributes.clear(); self.state.primitive = super::PrimitiveState::default(); @@ -591,25 +615,56 @@ impl crate::CommandEncoder for super::CommandEncoder { unsafe fn set_render_pipeline(&mut self, pipeline: &super::RenderPipeline) { self.state.topology = conv::map_primitive_topology(pipeline.primitive.topology); - self.state.dirty |= Dirty::VERTEX_BUFFERS; - self.set_pipeline_inner(&pipeline.inner); + for index in self.state.vertex_attributes.len()..pipeline.vertex_attributes.len() { + self.cmd_buffer + .commands + .push(C::UnsetVertexAttribute(index as u32)); + } - // set vertex state - self.state.vertex_attributes.clear(); - for vat in pipeline.vertex_attributes.iter() { - self.state.vertex_attributes.push(vat.clone()); + if self + .private_caps + .contains(super::PrivateCapability::VERTEX_BUFFER_LAYOUT) + { + for vat in pipeline.vertex_attributes.iter() { + let vb = &pipeline.vertex_buffers[vat.buffer_index as usize]; + // set the layout + self.cmd_buffer.commands.push(C::SetVertexAttribute { + buffer: None, + buffer_desc: vb.clone(), + attribute_desc: vat.clone(), + }); + } + } else { + self.state.dirty_vbuf_mask = 0; + // copy vertex attributes + for vat in pipeline.vertex_attributes.iter() { + //Note: we can invalidate more carefully here. + self.state.dirty_vbuf_mask |= 1 << vat.buffer_index; + self.state.vertex_attributes.push(vat.clone()); + } } - for (&mut (ref mut state_desc, _), pipe_desc) in self + + self.state.instance_vbuf_mask = 0; + // copy vertex state + for (index, (&mut (ref mut state_desc, _), pipe_desc)) in self .state .vertex_buffers .iter_mut() .zip(pipeline.vertex_buffers.iter()) + .enumerate() { - state_desc.step = pipe_desc.step; - state_desc.stride = pipe_desc.stride; + if pipe_desc.step == wgt::InputStepMode::Instance { + self.state.instance_vbuf_mask |= 1 << index; + } + if state_desc != pipe_desc { + self.state.dirty_vbuf_mask |= 1 << index; + *state_desc = pipe_desc.clone(); + } } + self.set_pipeline_inner(&pipeline.inner); + // set primitive state let prim_state = conv::map_primitive_state(&pipeline.primitive); if prim_state != self.state.primitive { @@ -703,8 +758,8 @@ impl crate::CommandEncoder for super::CommandEncoder { index: u32, binding: crate::BufferBinding<'a, super::Api>, ) { - self.state.dirty |= Dirty::VERTEX_BUFFERS; - let vb = &mut self.state.vertex_buffers[index as usize].1; + self.state.dirty_vbuf_mask |= 1 << index; + let (_, ref mut vb) = self.state.vertex_buffers[index as usize]; vb.raw = binding.buffer.raw; vb.offset = binding.offset; } @@ -854,7 +909,6 @@ impl crate::CommandEncoder for super::CommandEncoder { self.cmd_buffer.commands.push(C::PopDebugGroup); self.state.has_pass_label = false; } - self.state.dirty = Dirty::empty(); } unsafe fn set_compute_pipeline(&mut self, pipeline: &super::ComputePipeline) { diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 7fc8d9ecc1..4258e585b0 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -1,3 +1,61 @@ +/*! +# OpenGL ES3 API (aka GLES3). + +Designed to work on Linux and Android, with context provided by EGL. + +## Texture views + +GLES3 doesn't really have separate texture view objects. We have to remember the +original texture and the sub-range into it. Problem is, however, that there is +no way to expose a subset of array layers or mip levels of a sampled texture. + +## Binding model + +Binding model is very different from WebGPU, especially with regards to samplers. +GLES3 has sampler objects, but they aren't separately bindable to the shaders. +Each sampled texture is exposed to the shader as a combined texture-sampler binding. + +When building the pipeline layout, we linearize binding entries based on the groups +(uniform/storage buffers, uniform/storage textures), and record the mapping into +`BindGroupLayoutInfo`. +When a pipeline gets created, and we track all the texture-sampler associations +from the static use in the shader. +We only support at most one sampler used with each texture so far. The linear index +of this sampler is stored per texture slot in `SamplerBindMap` array. + +The texture-sampler pairs get potentially invalidated in 2 places: + - when a new pipeline is set, we update the linear indices of associated samplers + - when a new bind group is set, we update both the textures and the samplers + +We expect that the changes to sampler states between any 2 pipelines of the same layout +will be minimal, if any. + +## Vertex data + +Generally, vertex buffers are marked as dirty and lazily bound on draw. + +GLES3 doesn't support "base instance" semantics. However, it's easy to support, +since we are forced to do late binding anyway. We just adjust the offsets +into the vertex data. + +### Old path + +In GLES-3.0 and WebGL2, vertex buffer layout is provided +together with the actual buffer binding. +We invalidate the attributes on the vertex buffer change, and re-bind them. + +### New path + +In GLES-3.1 and higher, the vertex buffer layout can be declared separately +from the vertex data itself. This mostly matches WebGPU, however there is a catch: +`stride` needs to be specified with the data, not as a part of the layout. + +To address this, we invalidate the vertex buffers based on: + - whether or not `start_instance` is used + - stride has changed + +*/ + #[cfg(not(target_arch = "wasm32"))] mod egl; @@ -60,6 +118,8 @@ bitflags::bitflags! { const SHADER_TEXTURE_SHADOW_LOD = 0x0002; /// Support memory barriers. const MEMORY_BARRIERS = 0x0004; + /// Vertex buffer layouts separate from the data. + const VERTEX_BUFFER_LAYOUT = 0x0008; } } @@ -254,7 +314,7 @@ struct ImageBinding { format: u32, } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug, Default, PartialEq)] struct VertexBufferDesc { step: wgt::InputStepMode, stride: u32, @@ -534,10 +594,16 @@ enum Command { SetDepthBias(wgt::DepthBiasState), ConfigureDepthStencil(crate::FormatAspect), SetVertexAttribute { - buffer: BufferBinding, + buffer: Option, buffer_desc: VertexBufferDesc, attribute_desc: AttributeDesc, }, + UnsetVertexAttribute(u32), + SetVertexBuffer { + index: u32, + buffer: BufferBinding, + buffer_desc: VertexBufferDesc, + }, SetProgram(glow::Program), SetPrimitive(PrimitiveState), SetBlendConstant([f32; 4]), diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 04e34d48c7..65595a352d 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -590,31 +590,69 @@ impl super::Queue { gl.stencil_op_separate(face, ops.fail, ops.depth_fail, ops.pass); } C::SetVertexAttribute { + buffer, ref buffer_desc, - ref buffer, attribute_desc: ref vat, } => { - gl.bind_buffer(glow::ARRAY_BUFFER, Some(buffer.raw)); - let offset = vat.offset as i32 + buffer.offset as i32; - match vat.format_desc.attrib_kind { - super::VertexAttribKind::Float => gl.vertex_attrib_pointer_f32( - vat.location, - vat.format_desc.element_count, - vat.format_desc.element_format, - true, // always normalized - buffer_desc.stride as i32, - offset, - ), - super::VertexAttribKind::Integer => gl.vertex_attrib_pointer_i32( - vat.location, - vat.format_desc.element_count, - vat.format_desc.element_format, - buffer_desc.stride as i32, - offset, - ), - } - gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32); + gl.bind_buffer(glow::ARRAY_BUFFER, buffer); gl.enable_vertex_attrib_array(vat.location); + + if buffer.is_none() { + match vat.format_desc.attrib_kind { + super::VertexAttribKind::Float => gl.vertex_attrib_format_f32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + true, // always normalized + vat.offset, + ), + super::VertexAttribKind::Integer => gl.vertex_attrib_format_i32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + vat.offset, + ), + } + + //Note: there is apparently a bug on AMD 3500U: + // this call is ignored if the current array is disabled. + gl.vertex_attrib_binding(vat.location, vat.buffer_index); + } else { + match vat.format_desc.attrib_kind { + super::VertexAttribKind::Float => gl.vertex_attrib_pointer_f32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + true, // always normalized + buffer_desc.stride as i32, + vat.offset as i32, + ), + super::VertexAttribKind::Integer => gl.vertex_attrib_pointer_i32( + vat.location, + vat.format_desc.element_count, + vat.format_desc.element_format, + buffer_desc.stride as i32, + vat.offset as i32, + ), + } + gl.vertex_attrib_divisor(vat.location, buffer_desc.step as u32); + } + } + C::UnsetVertexAttribute(location) => { + gl.disable_vertex_attrib_array(location); + } + C::SetVertexBuffer { + index, + ref buffer, + ref buffer_desc, + } => { + gl.vertex_binding_divisor(index, buffer_desc.step as u32); + gl.bind_vertex_buffer( + index, + Some(buffer.raw), + buffer.offset as i32, + buffer_desc.stride as i32, + ); } C::SetDepth(ref depth) => { gl.depth_func(depth.function); diff --git a/wgpu-info/src/main.rs b/wgpu-info/src/main.rs index 0f79cfd745..c1cdd4221f 100644 --- a/wgpu-info/src/main.rs +++ b/wgpu-info/src/main.rs @@ -70,7 +70,8 @@ fn print_info_from_adapter(adapter: &wgpu::Adapter, idx: usize) { println!("\tDownlevel Properties:"); let wgpu::DownlevelCapabilities { shader_model, - flags + limits: _, + flags, } = downlevel; println!("\t\tShader Model: {:?}", shader_model); for i in 0..(size_of::() * 8) { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 94016d881f..a732ef7aa7 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -586,11 +586,24 @@ impl Default for Limits { } } +/// Represents the sets of additional limits on an adapter, +/// which take place when running on downlevel backends. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct DownlevelLimits {} + +impl Default for DownlevelLimits { + fn default() -> Self { + DownlevelLimits {} + } +} + /// Lists various ways the underlying platform does not conform to the WebGPU standard. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct DownlevelCapabilities { /// Combined boolean flags. pub flags: DownlevelFlags, + /// Additional limits + pub limits: DownlevelLimits, /// Which collections of features shaders support. Defined in terms of D3D's shader models. pub shader_model: ShaderModel, } @@ -599,6 +612,7 @@ impl Default for DownlevelCapabilities { fn default() -> Self { Self { flags: DownlevelFlags::COMPLIANT, + limits: DownlevelLimits::default(), shader_model: ShaderModel::Sm5, } } @@ -609,8 +623,10 @@ impl DownlevelCapabilities { /// /// If this returns false, some parts of the API will result in validation errors where they would not normally. /// These parts can be determined by the values in this structure. - pub fn is_webgpu_compliant(self) -> bool { - self.flags.contains(DownlevelFlags::COMPLIANT) && self.shader_model >= ShaderModel::Sm5 + pub fn is_webgpu_compliant(&self) -> bool { + self.flags.contains(DownlevelFlags::COMPLIANT) + && self.limits == DownlevelLimits::default() + && self.shader_model >= ShaderModel::Sm5 } } diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index 4b4422a5ed..3304849209 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -66,6 +66,7 @@ pub fn lowest_reasonable_limits() -> Limits { fn lowest_downlevel_properties() -> DownlevelCapabilities { DownlevelCapabilities { flags: wgt::DownlevelFlags::empty(), + limits: wgt::DownlevelLimits {}, shader_model: wgt::ShaderModel::Sm2, } } From 45074b2939b18a39266f8b6b5a9e2c76da6d47b2 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 29 Jun 2021 23:47:20 -0400 Subject: [PATCH 32/33] hal: more implementation comments --- wgpu-hal/src/metal/mod.rs | 15 +++++++++++++++ wgpu-hal/src/vulkan/mod.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index b658d9a81b..caf61044ff 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -1,3 +1,18 @@ +/*! +# Metal API internals. + +## Pipeline Layout + +In Metal, push constants, vertex buffers, and resources in the bind groups +are all placed together in the native resource bindings, which work similarly to D3D11: +there are tables of textures, buffers, and samplers. + +We put push constants first (if any) in the table, followed by bind group 0 +resources, followed by other bind groups. The vertex buffers are bound at the very +end of the VS buffer table. + +!*/ + mod adapter; mod command; mod conv; diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 133bb21f92..2a87e4a749 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -1,3 +1,25 @@ +/*! +# Vulkan API internals. + +## Stack memory + +Ash expects slices, which we don't generally have available. +We cope with this requirement by the combination of the following ways: + - temporarily allocating `Vec` on heap, where overhead is permitted + - growing temporary local storage + - using `implace_it` on iterators + +## Framebuffers and Render passes + +Render passes are cached on the device and kept forever. + +Framebuffers are also cached on the device, but they are removed when +any of the image views (they have) gets removed. +If Vulkan supports image-less framebuffers, +then the actual views are excluded from the framebuffer key. + +!*/ + mod adapter; mod command; mod conv; From 6f13eebb7b55db77e3d75d57449607fb3d70579b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 30 Jun 2021 00:28:10 -0400 Subject: [PATCH 33/33] hal/gles: compressed ETC2 texture support --- Cargo.lock | 2 +- Cargo.toml | 3 + wgpu-core/src/validation.rs | 2 +- wgpu-hal/Cargo.toml | 2 +- wgpu-hal/src/gles/adapter.rs | 6 +- wgpu-hal/src/gles/command.rs | 24 +--- wgpu-hal/src/gles/conv.rs | 28 ++-- wgpu-hal/src/gles/mod.rs | 11 +- wgpu-hal/src/gles/queue.rs | 233 +++++++++++++++++++++++---------- wgpu-hal/src/metal/adapter.rs | 8 +- wgpu-hal/src/vulkan/adapter.rs | 1 + wgpu-hal/src/vulkan/conv.rs | 4 +- wgpu-types/src/lib.rs | 8 +- wgpu/examples/skybox/main.rs | 4 + 14 files changed, 209 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e098ea1b95..7fce4ca1ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -690,7 +690,7 @@ dependencies = [ [[package]] name = "glow" version = "0.10.0" -source = "git+https://github.com/grovesNL/glow?rev=57177a01b1dd91a82ccfd2d7b687fcc36116157c#57177a01b1dd91a82ccfd2d7b687fcc36116157c" +source = "git+https://github.com/grovesNL/glow?rev=0864897a28bbdd43f89f4fd8fdd4ed781b719f8a#0864897a28bbdd43f89f4fd8fdd4ed781b719f8a" dependencies = [ "js-sys", "slotmap", diff --git a/Cargo.toml b/Cargo.toml index 964a706ec9..90bce2ccc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ default-members = ["wgpu", "player", "wgpu-hal", "wgpu-info"] [patch."https://github.com/zakarumych/gpu-alloc"] #gpu-alloc = { path = "../gpu-alloc/gpu-alloc" } +[patch."https://github.com/grovesNL/glow"] +#glow = { path = "../glow" } + [patch.crates-io] #web-sys = { path = "../wasm-bindgen/crates/web-sys" } #js-sys = { path = "../wasm-bindgen/crates/js-sys" } diff --git a/wgpu-core/src/validation.rs b/wgpu-core/src/validation.rs index 721d3d09d2..8f136f430e 100644 --- a/wgpu-core/src/validation.rs +++ b/wgpu-core/src/validation.rs @@ -658,7 +658,7 @@ impl NumericType { Tf::Bc4RUnorm | Tf::Bc4RSnorm | Tf::EacRUnorm | Tf::EacRSnorm => { (NumericDimension::Scalar, Sk::Float) } - Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EtcRgUnorm | Tf::EtcRgSnorm => { + Tf::Bc5RgUnorm | Tf::Bc5RgSnorm | Tf::EacRgUnorm | Tf::EacRgSnorm => { (NumericDimension::Vector(Vs::Bi), Sk::Float) } Tf::Bc6hRgbUfloat | Tf::Bc6hRgbSfloat | Tf::Etc2RgbUnorm | Tf::Etc2RgbUnormSrgb => { diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 49445d39b9..2985281572 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -38,7 +38,7 @@ 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 = { git = "https://github.com/grovesNL/glow", rev = "57177a01b1dd91a82ccfd2d7b687fcc36116157c", optional = true } +glow = { git = "https://github.com/grovesNL/glow", rev = "0864897a28bbdd43f89f4fd8fdd4ed781b719f8a", optional = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] egl = { package = "khronos-egl", version = "4.1", features = ["dynamic"], optional = true } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 9230da3d4f..3ef2d98b65 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -177,7 +177,7 @@ impl super::Adapter { naga::back::glsl::Version::Embedded(value) }; - let mut features = wgt::Features::empty(); + let mut features = wgt::Features::empty() | wgt::Features::TEXTURE_COMPRESSION_ETC2; features.set( wgt::Features::DEPTH_CLAMPING, extensions.contains("GL_EXT_depth_clamp"), @@ -394,8 +394,8 @@ impl crate::Adapter for super::Adapter { | Tf::Etc2RgbA1UnormSrgb | Tf::EacRUnorm | Tf::EacRSnorm - | Tf::EtcRgUnorm - | Tf::EtcRgSnorm + | Tf::EacRgUnorm + | Tf::EacRgSnorm | Tf::Astc4x4RgbaUnorm | Tf::Astc4x4RgbaUnormSrgb | Tf::Astc5x4RgbaUnorm diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 859fc7e102..fc0bbe4c68 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -294,12 +294,6 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - let format_info = dst.format.describe(); - assert_eq!( - format_info.block_dimensions, - (1, 1), - "Compressed texture copies are TODO" - ); let (dst_raw, dst_target) = dst.inner.as_native(); for copy in regions { self.cmd_buffer.commands.push(C::CopyBufferToTexture { @@ -307,11 +301,7 @@ impl crate::CommandEncoder for super::CommandEncoder { src_target: src.target, dst: dst_raw, dst_target, - dst_info: super::TextureCopyInfo { - external_format: dst.format_desc.external, - data_type: dst.format_desc.data_type, - texel_size: format_info.block_size, - }, + dst_format: dst.format, copy, }) } @@ -326,22 +316,12 @@ impl crate::CommandEncoder for super::CommandEncoder { ) where T: Iterator, { - let format_info = src.format.describe(); - assert_eq!( - format_info.block_dimensions, - (1, 1), - "Compressed texture copies are TODO" - ); let (src_raw, src_target) = src.inner.as_native(); for copy in regions { self.cmd_buffer.commands.push(C::CopyTextureToBuffer { src: src_raw, src_target, - src_info: super::TextureCopyInfo { - external_format: src.format_desc.external, - data_type: src.format_desc.data_type, - texel_size: format_info.block_size, - }, + src_format: src.format, dst: dst.raw, dst_target: dst.target, copy, diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 2f1f4fc98a..fbba13b96e 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -73,16 +73,24 @@ impl super::AdapterShared { | Tf::Bc6hRgbSfloat | Tf::Bc6hRgbUfloat | Tf::Bc7RgbaUnorm - | Tf::Bc7RgbaUnormSrgb - | Tf::Etc2RgbUnorm - | Tf::Etc2RgbUnormSrgb - | Tf::Etc2RgbA1Unorm - | Tf::Etc2RgbA1UnormSrgb - | Tf::EacRUnorm - | Tf::EacRSnorm - | Tf::EtcRgUnorm - | Tf::EtcRgSnorm - | Tf::Astc4x4RgbaUnorm + | Tf::Bc7RgbaUnormSrgb => unimplemented!(), + Tf::Etc2RgbUnorm => (glow::COMPRESSED_RGB8_ETC2, glow::RGB, 0), + Tf::Etc2RgbUnormSrgb => (glow::COMPRESSED_SRGB8_ETC2, glow::RGB, 0), + Tf::Etc2RgbA1Unorm => ( + glow::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2, + glow::RGBA, + 0, + ), + Tf::Etc2RgbA1UnormSrgb => ( + glow::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, + glow::RGBA, + 0, + ), + Tf::EacRUnorm => (glow::COMPRESSED_R11_EAC, glow::RED, 0), + Tf::EacRSnorm => (glow::COMPRESSED_SIGNED_R11_EAC, glow::RED, 0), + Tf::EacRgUnorm => (glow::COMPRESSED_RG11_EAC, glow::RG, 0), + Tf::EacRgSnorm => (glow::COMPRESSED_SIGNED_RG11_EAC, glow::RG, 0), + Tf::Astc4x4RgbaUnorm | Tf::Astc4x4RgbaUnormSrgb | Tf::Astc5x4RgbaUnorm | Tf::Astc5x4RgbaUnormSrgb diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 4258e585b0..2c42e7f7c5 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -418,13 +418,6 @@ impl Fence { } } -#[derive(Debug)] -struct TextureCopyInfo { - external_format: u32, - data_type: u32, - texel_size: u8, -} - #[derive(Clone, Debug, PartialEq)] struct StencilOps { pass: u32, @@ -535,13 +528,13 @@ enum Command { src_target: BindTarget, dst: glow::Texture, dst_target: BindTarget, - dst_info: TextureCopyInfo, + dst_format: wgt::TextureFormat, copy: crate::BufferTextureCopy, }, CopyTextureToBuffer { src: glow::Texture, src_target: BindTarget, - src_info: TextureCopyInfo, + src_format: wgt::TextureFormat, dst: glow::Buffer, dst_target: BindTarget, copy: crate::BufferTextureCopy, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 65595a352d..548fe6fbf7 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -254,103 +254,196 @@ impl super::Queue { src_target: _, dst, dst_target, - ref dst_info, + dst_format, ref copy, } => { - //TODO: compressed data - let row_texels = copy + let format_info = dst_format.describe(); + let format_desc = self.shared.describe_texture_format(dst_format); + + let row_texels = copy.buffer_layout.bytes_per_row.map_or(0, |bpr| { + format_info.block_dimensions.0 as u32 * bpr.get() + / format_info.block_size as u32 + }); + let column_texels = copy .buffer_layout - .bytes_per_row - .map_or(0, |bpr| bpr.get() / dst_info.texel_size as u32); - let column_texels = copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get()); + .rows_per_image + .map_or(0, |rpi| format_info.block_dimensions.1 as u32 * rpi.get()); gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, row_texels as i32); gl.pixel_store_i32(glow::UNPACK_IMAGE_HEIGHT, column_texels as i32); gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(src)); - - let unpack_data = - glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32); gl.bind_texture(dst_target, Some(dst)); - match dst_target { - glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { - gl.tex_sub_image_3d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.texture_base.origin.z as i32, - copy.size.width as i32, - copy.size.height as i32, - copy.size.depth_or_array_layers as i32, - dst_info.external_format, - dst_info.data_type, - unpack_data, - ); - } - glow::TEXTURE_2D => { - gl.tex_sub_image_2d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.size.width as i32, - copy.size.height as i32, - dst_info.external_format, - dst_info.data_type, - unpack_data, - ); - } - glow::TEXTURE_CUBE_MAP => { - let mut offset = copy.buffer_layout.offset as u32; - for face_index in 0..copy.size.depth_or_array_layers { + + if format_info.block_dimensions == (1, 1) { + let unpack_data = + glow::PixelUnpackData::BufferOffset(copy.buffer_layout.offset as u32); + match dst_target { + glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { + gl.tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + format_desc.external, + format_desc.data_type, + unpack_data, + ); + } + glow::TEXTURE_2D => { gl.tex_sub_image_2d( - CUBEMAP_FACES[(copy.texture_base.origin.z + face_index) as usize], + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.external, + format_desc.data_type, + unpack_data, + ); + } + glow::TEXTURE_CUBE_MAP => { + let mut offset = copy.buffer_layout.offset as u32; + for face_index in 0..copy.size.depth_or_array_layers { + gl.tex_sub_image_2d( + CUBEMAP_FACES + [(copy.texture_base.origin.z + face_index) as usize], + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.external, + format_desc.data_type, + glow::PixelUnpackData::BufferOffset(offset), + ); + offset += copy + .buffer_layout + .rows_per_image + .map_or(0, |rpi| rpi.get()) + * copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get()); + } + } + glow::TEXTURE_CUBE_MAP_ARRAY => { + //Note: not sure if this is correct! + gl.tex_sub_image_3d( + dst_target, copy.texture_base.mip_level as i32, copy.texture_base.origin.x as i32, copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, copy.size.width as i32, copy.size.height as i32, - dst_info.external_format, - dst_info.data_type, - glow::PixelUnpackData::BufferOffset(offset), + copy.size.depth_or_array_layers as i32, + format_desc.external, + format_desc.data_type, + unpack_data, ); - offset += copy.buffer_layout.rows_per_image.map_or(0, |rpi| rpi.get()) - * copy.buffer_layout.bytes_per_row.map_or(0, |bpr| bpr.get()); } + _ => unreachable!(), } - glow::TEXTURE_CUBE_MAP_ARRAY => { - //Note: not sure if this is correct! - gl.tex_sub_image_3d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.texture_base.origin.z as i32, - copy.size.width as i32, - copy.size.height as i32, - copy.size.depth_or_array_layers as i32, - dst_info.external_format, - dst_info.data_type, - unpack_data, - ); + } else { + let bytes_per_image = + copy.buffer_layout.rows_per_image.map_or(1, |rpi| rpi.get()) + * copy.buffer_layout.bytes_per_row.map_or(1, |bpr| bpr.get()); + let offset_end = copy.buffer_layout.offset as u32 + + bytes_per_image * copy.size.depth_or_array_layers; + let unpack_data = glow::CompressedPixelUnpackData::BufferRange( + copy.buffer_layout.offset as u32..offset_end, + ); + match dst_target { + glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { + gl.compressed_tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + format_desc.internal, + unpack_data, + ); + } + glow::TEXTURE_2D => { + gl.compressed_tex_sub_image_2d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.internal, + unpack_data, + ); + } + glow::TEXTURE_CUBE_MAP => { + let mut offset = copy.buffer_layout.offset as u32; + for face_index in 0..copy.size.depth_or_array_layers { + gl.compressed_tex_sub_image_2d( + CUBEMAP_FACES + [(copy.texture_base.origin.z + face_index) as usize], + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.size.width as i32, + copy.size.height as i32, + format_desc.internal, + glow::CompressedPixelUnpackData::BufferRange( + offset..offset + bytes_per_image, + ), + ); + offset += bytes_per_image; + } + } + glow::TEXTURE_CUBE_MAP_ARRAY => { + //Note: not sure if this is correct! + gl.compressed_tex_sub_image_3d( + dst_target, + copy.texture_base.mip_level as i32, + copy.texture_base.origin.x as i32, + copy.texture_base.origin.y as i32, + copy.texture_base.origin.z as i32, + copy.size.width as i32, + copy.size.height as i32, + copy.size.depth_or_array_layers as i32, + format_desc.internal, + unpack_data, + ); + } + _ => unreachable!(), } - _ => unreachable!(), } } C::CopyTextureToBuffer { src, src_target, - ref src_info, + src_format, dst, dst_target: _, ref copy, } => { - //TODO: compressed data - //TODO: cubemaps + let format_info = src_format.describe(); + if format_info.block_dimensions != (1, 1) { + log::error!("Not implemented yet: compressed texture copy to buffer"); + return; + } + if src_target == glow::TEXTURE_CUBE_MAP + || src_target == glow::TEXTURE_CUBE_MAP_ARRAY + { + log::error!("Not implemented yet: cubemap texture copy to buffer"); + return; + } + let format_desc = self.shared.describe_texture_format(src_format); let row_texels = copy .buffer_layout .bytes_per_row .map_or(copy.size.width, |bpr| { - bpr.get() / src_info.texel_size as u32 + bpr.get() / format_info.block_size as u32 }); let column_texels = copy .buffer_layout @@ -362,7 +455,7 @@ impl super::Queue { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)); for layer in 0..copy.size.depth_or_array_layers { let offset = copy.buffer_layout.offset as u32 - + layer * column_texels * row_texels * src_info.texel_size as u32; + + layer * column_texels * row_texels * format_info.block_size as u32; if is_3d_target(src_target) { //TODO: handle GLES without framebuffer_texture_3d gl.framebuffer_texture_layer( @@ -386,8 +479,8 @@ impl super::Queue { copy.texture_base.origin.y as i32, copy.size.width as i32, copy.size.height as i32, - src_info.external_format, - src_info.data_type, + format_desc.external, + format_desc.data_type, glow::PixelPackData::BufferOffset(offset), ); } diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 3d7cc3b2cf..0624a33be3 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -215,8 +215,8 @@ impl crate::Adapter for super::Adapter { | Tf::Etc2RgbA1UnormSrgb | Tf::EacRUnorm | Tf::EacRSnorm - | Tf::EtcRgUnorm - | Tf::EtcRgSnorm => { + | Tf::EacRgUnorm + | Tf::EacRgSnorm => { if pc.format_eac_etc { Tfc::SAMPLED_LINEAR } else { @@ -990,8 +990,8 @@ impl super::PrivateCapabilities { Tf::Etc2RgbA1UnormSrgb => ETC2_RGB8A1_sRGB, Tf::EacRUnorm => EAC_R11Unorm, Tf::EacRSnorm => EAC_R11Snorm, - Tf::EtcRgUnorm => EAC_RG11Unorm, - Tf::EtcRgSnorm => EAC_RG11Snorm, + Tf::EacRgUnorm => EAC_RG11Unorm, + Tf::EacRgSnorm => EAC_RG11Snorm, Tf::Astc4x4RgbaUnorm => ASTC_4x4_LDR, Tf::Astc4x4RgbaUnormSrgb => ASTC_4x4_sRGB, Tf::Astc5x4RgbaUnorm => ASTC_5x4_LDR, diff --git a/wgpu-hal/src/vulkan/adapter.rs b/wgpu-hal/src/vulkan/adapter.rs index 9af802a82c..604d482a6c 100644 --- a/wgpu-hal/src/vulkan/adapter.rs +++ b/wgpu-hal/src/vulkan/adapter.rs @@ -665,6 +665,7 @@ impl super::Instance { alignments: phd_capabilities.to_hal_alignments(), downlevel: wgt::DownlevelCapabilities { flags: downlevel_flags, + limits: wgt::DownlevelLimits {}, shader_model: wgt::ShaderModel::Sm5, //TODO? }, }; diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index 3ce8f67750..899492ab54 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -76,8 +76,8 @@ impl super::PrivateCapabilities { Tf::Etc2RgbA1UnormSrgb => F::ETC2_R8G8B8A1_SRGB_BLOCK, Tf::EacRUnorm => F::EAC_R11_UNORM_BLOCK, Tf::EacRSnorm => F::EAC_R11_SNORM_BLOCK, - Tf::EtcRgUnorm => F::EAC_R11G11_UNORM_BLOCK, - Tf::EtcRgSnorm => F::EAC_R11G11_SNORM_BLOCK, + Tf::EacRgUnorm => F::EAC_R11G11_UNORM_BLOCK, + Tf::EacRgSnorm => F::EAC_R11G11_SNORM_BLOCK, Tf::Astc4x4RgbaUnorm => F::ASTC_4X4_UNORM_BLOCK, Tf::Astc4x4RgbaUnormSrgb => F::ASTC_4X4_SRGB_BLOCK, Tf::Astc5x4RgbaUnorm => F::ASTC_5X4_UNORM_BLOCK, diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index a732ef7aa7..2a285277b1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -1416,12 +1416,12 @@ pub enum TextureFormat { /// [0, 255] converted to/from float [0, 1] in shader. /// /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format. - EtcRgUnorm = 60, + EacRgUnorm = 60, /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer R + 8 bit integer G. /// [-127, 127] converted to/from float [-1, 1] in shader. /// /// [`Features::TEXTURE_COMPRESSION_ETC2`] must be enabled to use this texture format. - EtcRgSnorm = 61, + EacRgSnorm = 61, /// 4x4 block compressed texture. 16 bytes per block (8 bit/px). Complex pallet. 8 bit integer RGBA. /// [0, 255] converted to/from float [0, 1] in shader. /// @@ -1670,8 +1670,8 @@ impl TextureFormat { //Self::Etc2RgbA8UnormSrgb => (etc2, float, srgb, (4, 4), 16, basic), Self::EacRUnorm => (etc2, float, linear, (4, 4), 8, basic), Self::EacRSnorm => (etc2, float, linear, (4, 4), 8, basic), - Self::EtcRgUnorm => (etc2, float, linear, (4, 4), 16, basic), - Self::EtcRgSnorm => (etc2, float, linear, (4, 4), 16, basic), + Self::EacRgUnorm => (etc2, float, linear, (4, 4), 16, basic), + Self::EacRgSnorm => (etc2, float, linear, (4, 4), 16, basic), // ASTC compressed textures Self::Astc4x4RgbaUnorm => (astc_ldr, float, linear, (4, 4), 16, basic), diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index a300c5261f..b036887c52 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -273,12 +273,16 @@ impl framework::Example for Skybox { let skybox_format = if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) { + log::info!("Using ASTC_LDR"); wgpu::TextureFormat::Astc4x4RgbaUnormSrgb } else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_ETC2) { + log::info!("Using ETC2"); wgpu::TextureFormat::Etc2RgbUnormSrgb } else if device_features.contains(wgpu::Features::TEXTURE_COMPRESSION_BC) { + log::info!("Using BC"); wgpu::TextureFormat::Bc1RgbaUnormSrgb } else { + log::info!("Using plain"); wgpu::TextureFormat::Bgra8UnormSrgb };