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]]