diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index fb42a9435c..f5b1fd8364 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"] package = "wgpu-core" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "ad34c37127c8361bc2b07e8775816b2bbf8c0a73" +rev = "2dd3439475de6ea59488a91ea7d66096d3aecbbf" features = ["raw-window-handle"] [dependencies.wgt] package = "wgpu-types" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "ad34c37127c8361bc2b07e8775816b2bbf8c0a73" +rev = "2dd3439475de6ea59488a91ea7d66096d3aecbbf" [dependencies] arrayvec = "0.5" @@ -73,7 +73,7 @@ test = true #gfx-backend-vulkan = { version = "0.5.0", path = "../gfx/src/backend/vulkan" } #gfx-backend-dx12 = { version = "0.5.0", path = "../gfx/src/backend/dx12" } #gfx-backend-dx11 = { version = "0.5.0", path = "../gfx/src/backend/dx11" } -#gfx-backend-metal = { version = "0.5.0", path = "../gfx/src/backend/dx11" } +#gfx-backend-metal = { version = "0.5.0", path = "../gfx/src/backend/metal" } #gfx-descriptor = { version = "0.1.0", path = "../gfx-extras/gfx-descriptor" } #gfx-memory = { version = "0.1.0", path = "../gfx-extras/gfx-memory" } diff --git a/wgpu/examples/texture-arrays/shader.frag b/wgpu/examples/texture-arrays/constant.frag similarity index 74% rename from wgpu/examples/texture-arrays/shader.frag rename to wgpu/examples/texture-arrays/constant.frag index 0149e9d833..c4cb2894b0 100644 --- a/wgpu/examples/texture-arrays/shader.frag +++ b/wgpu/examples/texture-arrays/constant.frag @@ -1,7 +1,7 @@ #version 450 layout(location = 0) in vec2 v_TexCoord; -layout(location = 1) flat in int v_Index; +layout(location = 1) flat in int v_Index; // dynamically non-uniform layout(location = 0) out vec4 o_Color; layout(set = 0, binding = 0) uniform texture2D u_Textures[2]; @@ -13,6 +13,7 @@ void main() { } else if (v_Index == 1) { o_Color = vec4(texture(sampler2D(u_Textures[1], u_Sampler), v_TexCoord).rgb, 1.0); } else { - o_Color = vec4(0.0, 0.0, 1.0, 1.0); + // We need to write something to output color + o_Color = vec4(0.0, 0.0, 1.0, 0.0); } } diff --git a/wgpu/examples/texture-arrays/shader.frag.spv b/wgpu/examples/texture-arrays/constant.frag.spv similarity index 95% rename from wgpu/examples/texture-arrays/shader.frag.spv rename to wgpu/examples/texture-arrays/constant.frag.spv index a50d941123..cd85dc6401 100644 Binary files a/wgpu/examples/texture-arrays/shader.frag.spv and b/wgpu/examples/texture-arrays/constant.frag.spv differ diff --git a/wgpu/examples/texture-arrays/main.rs b/wgpu/examples/texture-arrays/main.rs index f33adc1fa2..fc24ff23d0 100644 --- a/wgpu/examples/texture-arrays/main.rs +++ b/wgpu/examples/texture-arrays/main.rs @@ -14,6 +14,21 @@ struct Vertex { unsafe impl Pod for Vertex {} unsafe impl Zeroable for Vertex {} +#[repr(C)] +#[derive(Clone, Copy)] +struct Uniform { + index: u32, +} + +unsafe impl Pod for Uniform {} +unsafe impl Zeroable for Uniform {} + +struct UniformWorkaroundData { + bind_group_layout: wgpu::BindGroupLayout, + bind_group0: wgpu::BindGroup, + bind_group1: wgpu::BindGroup, +} + fn vertex(pos: [i8; 2], tc: [i8; 2], index: i8) -> Vertex { Vertex { _pos: [pos[0] as f32, pos[1] as f32], @@ -66,12 +81,13 @@ struct Example { bind_group: wgpu::BindGroup, vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, + uniform_workaround_data: Option, } impl framework::Example for Example { fn needed_extensions() -> (wgpu::Extensions, wgpu::UnsafeExtensions) { ( - wgpu::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY, + wgpu::Extensions::BINDING_INDEXING, wgpu::UnsafeExtensions::disallow(), ) } @@ -80,12 +96,30 @@ impl framework::Example for Example { device: &wgpu::Device, queue: &wgpu::Queue, ) -> (Self, Option) { - let device_extensions = device.extensions(); - - assert!( - device_extensions.contains(wgpu::Extensions::SAMPLED_TEXTURE_BINDING_ARRAY), - "Graphics Device does not support SAMPLED_TEXTURE_BINDING_ARRAY extension" - ); + let mut uniform_workaround = false; + let vs_bytes: &[u8] = include_bytes!("shader.vert.spv"); + let fs_bytes: &[u8] = match device.capabilities() { + c if c.contains(wgpu::Capabilities::UNSIZED_BINDING_ARRAY) => { + include_bytes!("unsized-non-uniform.frag.spv") + } + c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => { + include_bytes!("non-uniform.frag.spv") + } + c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => { + uniform_workaround = true; + include_bytes!("uniform.frag.spv") + } + c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY) => { + include_bytes!("constant.frag.spv") + } + _ => { + panic!("Graphics adapter does not support any of the capabilities needed for this example"); + } + }; + let vs_module = + device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(vs_bytes)).unwrap()); + let fs_module = + device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(fs_bytes)).unwrap()); let vertex_size = std::mem::size_of::(); let vertex_data = create_vertices(); @@ -98,6 +132,54 @@ impl framework::Example for Example { let index_buffer = device .create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX); + let uniform_workaround_data = if uniform_workaround { + let buffer0 = device.create_buffer_with_data( + &bytemuck::cast_slice(&[Uniform { index: 0 }]), + wgpu::BufferUsage::UNIFORM, + ); + let buffer1 = device.create_buffer_with_data( + &bytemuck::cast_slice(&[Uniform { index: 1 }]), + wgpu::BufferUsage::UNIFORM, + ); + + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..wgpu::BindGroupLayoutEntry::default() + }], + label: Some("uniform workaround bind group layout"), + }); + + let bind_group0 = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer(buffer0.slice(..)), + }], + label: Some("uniform workaround bind group 0"), + }); + + let bind_group1 = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer(buffer1.slice(..)), + }], + label: Some("uniform workaround bind group 1"), + }); + + Some(UniformWorkaroundData { + bind_group_layout, + bind_group0, + bind_group1, + }) + } else { + None + }; + let red_texture_data = create_texture_data(Color::RED); let green_texture_data = create_texture_data(Color::GREEN); @@ -206,16 +288,15 @@ impl framework::Example for Example { label: Some("bind group"), }); - let vs_bytes = include_bytes!("shader.vert.spv"); - let fs_bytes = include_bytes!("shader.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); - - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout], - }); + let pipeline_layout = if let Some(ref workaround) = uniform_workaround_data { + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout, &workaround.bind_group_layout], + }) + } else { + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout], + }) + }; let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, @@ -261,6 +342,7 @@ impl framework::Example for Example { index_buffer, bind_group, pipeline, + uniform_workaround_data, }, None, ) @@ -305,7 +387,14 @@ impl framework::Example for Example { rpass.set_bind_group(0, &self.bind_group, &[]); rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); rpass.set_index_buffer(self.index_buffer.slice(..)); - rpass.draw_indexed(0..12, 0, 0..1); + if let Some(ref workaround) = self.uniform_workaround_data { + rpass.set_bind_group(1, &workaround.bind_group0, &[]); + rpass.draw_indexed(0..6, 0, 0..1); + rpass.set_bind_group(1, &workaround.bind_group1, &[]); + rpass.draw_indexed(6..12, 0, 0..1); + } else { + rpass.draw_indexed(0..12, 0, 0..1); + } drop(rpass); diff --git a/wgpu/examples/texture-arrays/non-uniform.frag b/wgpu/examples/texture-arrays/non-uniform.frag new file mode 100644 index 0000000000..994c50a664 --- /dev/null +++ b/wgpu/examples/texture-arrays/non-uniform.frag @@ -0,0 +1,14 @@ +#version 450 + +#extension GL_EXT_nonuniform_qualifier : require + +layout(location = 0) in vec2 v_TexCoord; +layout(location = 1) flat in int v_Index; // dynamically non-uniform +layout(location = 0) out vec4 o_Color; + +layout(set = 0, binding = 0) uniform texture2D u_Textures[2]; +layout(set = 0, binding = 1) uniform sampler u_Sampler; + +void main() { + o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler), v_TexCoord).rgb, 1.0); +} diff --git a/wgpu/examples/texture-arrays/non-uniform.frag.spv b/wgpu/examples/texture-arrays/non-uniform.frag.spv new file mode 100644 index 0000000000..1c0be40cdb Binary files /dev/null and b/wgpu/examples/texture-arrays/non-uniform.frag.spv differ diff --git a/wgpu/examples/texture-arrays/uniform.frag b/wgpu/examples/texture-arrays/uniform.frag new file mode 100644 index 0000000000..396d77c67b --- /dev/null +++ b/wgpu/examples/texture-arrays/uniform.frag @@ -0,0 +1,15 @@ +#version 450 + +layout(location = 0) in vec2 v_TexCoord; +layout(location = 1) flat in int v_Index; // dynamically non-uniform +layout(location = 0) out vec4 o_Color; + +layout(set = 0, binding = 0) uniform texture2D u_Textures[2]; +layout(set = 0, binding = 1) uniform sampler u_Sampler; +layout(set = 1, binding = 0) uniform Uniforms { + int u_Index; // dynamically uniform +}; + +void main() { + o_Color = vec4(texture(sampler2D(u_Textures[u_Index], u_Sampler), v_TexCoord).rgb, 1.0); +} diff --git a/wgpu/examples/texture-arrays/uniform.frag.spv b/wgpu/examples/texture-arrays/uniform.frag.spv new file mode 100644 index 0000000000..7846abbb83 Binary files /dev/null and b/wgpu/examples/texture-arrays/uniform.frag.spv differ diff --git a/wgpu/examples/texture-arrays/unsized-non-uniform.frag b/wgpu/examples/texture-arrays/unsized-non-uniform.frag new file mode 100644 index 0000000000..c1013f6ab0 --- /dev/null +++ b/wgpu/examples/texture-arrays/unsized-non-uniform.frag @@ -0,0 +1,14 @@ +#version 450 + +#extension GL_EXT_nonuniform_qualifier : require + +layout(location = 0) in vec2 v_TexCoord; +layout(location = 1) flat in int v_Index; // dynamically non-uniform +layout(location = 0) out vec4 o_Color; + +layout(set = 0, binding = 0) uniform texture2D u_Textures[]; +layout(set = 0, binding = 1) uniform sampler u_Sampler; + +void main() { + o_Color = vec4(texture(sampler2D(u_Textures[v_Index], u_Sampler), v_TexCoord).rgb, 1.0); +} diff --git a/wgpu/examples/texture-arrays/unsized-non-uniform.frag.spv b/wgpu/examples/texture-arrays/unsized-non-uniform.frag.spv new file mode 100644 index 0000000000..995f84d62d Binary files /dev/null and b/wgpu/examples/texture-arrays/unsized-non-uniform.frag.spv differ diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 35c3bc4d29..80badfab28 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1,8 +1,8 @@ use crate::{ backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, - BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, Limits, - MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, - SwapChainStatus, TextureDescriptor, TextureViewDescriptor, + BufferDescriptor, Capabilities, CommandEncoderDescriptor, ComputePipelineDescriptor, + Extensions, Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, + SamplerDescriptor, SwapChainStatus, TextureDescriptor, TextureViewDescriptor, }; use arrayvec::ArrayVec; @@ -354,6 +354,10 @@ impl crate::Context for Context { gfx_select!(*adapter => self.adapter_limits(*adapter)) } + fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities { + gfx_select!(*adapter => self.adapter_capabilities(*adapter)) + } + fn device_extensions(&self, device: &Self::DeviceId) -> Extensions { gfx_select!(*device => self.device_extensions(*device)) } @@ -362,6 +366,10 @@ impl crate::Context for Context { gfx_select!(*device => self.device_limits(*device)) } + fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities { + gfx_select!(*device => self.device_capabilities(*device)) + } + fn device_create_swap_chain( &self, device: &Self::DeviceId, diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 64a75c7215..86a38756d4 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -725,6 +725,11 @@ impl crate::Context for Context { wgt::Limits::default() } + fn adapter_capabilities(&self, _adapter: &Self::AdapterId) -> wgt::Capabilities { + // TODO: webgpu doesn't support capabilities, so return an empty set of capabilities + wgt::Capabilities::default() + } + fn device_extensions(&self, _device: &Self::DeviceId) -> wgt::Extensions { // TODO: web-sys has no way of getting extensions on devices wgt::Extensions::empty() @@ -735,6 +740,11 @@ impl crate::Context for Context { wgt::Limits::default() } + fn device_capabilities(&self, _device: &Self::DeviceId) -> wgt::Capabilities { + // TODO: webgpu doesn't support capabilities, so return an empty set of capabilities + wgt::Capabilities::default() + } + fn device_create_swap_chain( &self, device: &Self::DeviceId, @@ -863,9 +873,9 @@ impl crate::Context for Context { view: ref texture_view, read_only_depth_stencil: _, } => JsValue::from(texture_view.id.0.clone()), - BindingResource::TextureViewArray(..) => { - panic!("Web backend does not support TEXTURE_BINDING_ARRAY extension") - } + BindingResource::TextureViewArray(..) => panic!( + "Web backend does not support SAMPLED_TEXTURE_BINDING_ARRAY extension" + ), }; web_sys::GpuBindGroupEntry::new(binding.binding, &mapped_resource) diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index f32f238ee0..2163323c2e 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -21,14 +21,15 @@ pub use wgc::instance::{AdapterInfo, DeviceType}; pub use wgt::{ read_spirv, AddressMode, Backend, BackendBit, BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingType, BlendDescriptor, BlendFactor, BlendOperation, BufferAddress, BufferSize, - BufferUsage, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor, CompareFunction, - CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset, Extensions, Extent3d, - FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp, Origin3d, PowerPreference, - PresentMode, PrimitiveTopology, RasterizationStateDescriptor, RenderBundleEncoderDescriptor, - ShaderLocation, ShaderStage, StencilOperation, StencilStateFaceDescriptor, StoreOp, - SwapChainDescriptor, SwapChainStatus, TextureAspect, TextureComponentType, TextureDataLayout, - TextureDimension, TextureFormat, TextureUsage, TextureViewDimension, UnsafeExtensions, - VertexAttributeDescriptor, VertexFormat, BIND_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, + BufferUsage, Capabilities, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor, + CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset, + Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp, + Origin3d, PowerPreference, PresentMode, PrimitiveTopology, RasterizationStateDescriptor, + RenderBundleEncoderDescriptor, ShaderLocation, ShaderStage, StencilOperation, + StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect, + TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage, + TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat, + BIND_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, }; use backend::Context as C; @@ -143,9 +144,11 @@ trait Context: Sized { ) -> Self::RequestDeviceFuture; fn adapter_extensions(&self, adapter: &Self::AdapterId) -> Extensions; fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits; + fn adapter_capabilities(&self, adapter: &Self::AdapterId) -> Capabilities; fn device_extensions(&self, device: &Self::DeviceId) -> Extensions; fn device_limits(&self, device: &Self::DeviceId) -> Limits; + fn device_capabilities(&self, device: &Self::DeviceId) -> Capabilities; fn device_create_swap_chain( &self, device: &Self::DeviceId, @@ -1013,10 +1016,14 @@ impl Adapter { Context::adapter_limits(&*self.context, &self.id) } + pub fn capabilities(&self) -> Capabilities { + Context::adapter_capabilities(&*self.context, &self.id) + } + #[cfg(not(target_arch = "wasm32"))] pub fn get_info(&self) -> AdapterInfo { - //wgn::adapter_get_info(self.id) - unimplemented!() + let context = &self.context; + wgc::gfx_select!(self.id => context.adapter_get_info(self.id)) } } @@ -1034,6 +1041,10 @@ impl Device { Context::device_limits(&*self.context, &self.id) } + pub fn capabilities(&self) -> Capabilities { + Context::device_capabilities(&*self.context, &self.id) + } + /// Creates a shader module from SPIR-V source code. pub fn create_shader_module(&self, spv: &[u32]) -> ShaderModule { ShaderModule {