diff --git a/Cargo.toml b/Cargo.toml index 04a6a3ca59..d1cb311694 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,19 +28,20 @@ vulkan = ["wgc/gfx-backend-vulkan"] package = "wgpu-core" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "eaf8f4af87237373105b016832662e7943b3899c" +rev = "64ae59072db443eb1e47ee14d77370eec9f4b012" features = ["raw-window-handle"] [dependencies.wgt] package = "wgpu-types" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "eaf8f4af87237373105b016832662e7943b3899c" +rev = "64ae59072db443eb1e47ee14d77370eec9f4b012" [dependencies] arrayvec = "0.5" futures = "0.3" smallvec = "1" +typed-arena = "2.0.1" raw-window-handle = "0.3" parking_lot = "0.10" @@ -72,6 +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-descriptor = { version = "0.1.0", path = "../gfx-extras/gfx-descriptor" } #gfx-memory = { version = "0.1.0", path = "../gfx-extras/gfx-memory" } diff --git a/examples/boids/main.rs b/examples/boids/main.rs index d52a5defd6..609c358f14 100644 --- a/examples/boids/main.rs +++ b/examples/boids/main.rs @@ -57,6 +57,7 @@ impl framework::Example for Example { binding: 0, visibility: wgpu::ShaderStage::COMPUTE, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, @@ -65,6 +66,7 @@ impl framework::Example for Example { dynamic: false, readonly: false, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 2, @@ -73,6 +75,7 @@ impl framework::Example for Example { dynamic: false, readonly: false, }, + ..Default::default() }, ], label: None, diff --git a/examples/cube/main.rs b/examples/cube/main.rs index ed0f619f5d..b66bb0f0a5 100644 --- a/examples/cube/main.rs +++ b/examples/cube/main.rs @@ -139,6 +139,7 @@ impl framework::Example for Example { binding: 0, visibility: wgpu::ShaderStage::VERTEX, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, @@ -148,11 +149,13 @@ impl framework::Example for Example { component_type: wgpu::TextureComponentType::Float, dimension: wgpu::TextureViewDimension::D2, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: false }, + ..Default::default() }, ], }); diff --git a/examples/framework.rs b/examples/framework.rs index ea38240d59..76a1223c3a 100644 --- a/examples/framework.rs +++ b/examples/framework.rs @@ -30,6 +30,9 @@ pub enum ShaderStage { } pub trait Example: 'static + Sized { + fn needed_extensions() -> (wgt::Extensions, wgt::UnsafeExtensions) { + (wgpu::Extensions::empty(), wgt::UnsafeExtensions::disallow()) + } fn init( sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device, @@ -60,23 +63,27 @@ async fn run_async(event_loop: EventLoop<()>, window: Window) { (size, surface) }; + let (needed_extensions, unsafe_extensions) = E::needed_extensions(); + let adapter = instance .request_adapter( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::Default, compatible_surface: Some(&surface), }, - wgpu::UnsafeExtensions::disallow(), + unsafe_extensions, wgpu::BackendBit::PRIMARY, ) .await .unwrap(); + let adapter_extensions = adapter.extensions(); + let trace_dir = std::env::var("WGPU_TRACE"); let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { - extensions: wgpu::Extensions::empty(), + extensions: adapter_extensions & needed_extensions, limits: wgpu::Limits::default(), shader_validation: true, }, diff --git a/examples/hello-compute/main.rs b/examples/hello-compute/main.rs index 8ac05d474f..07d953a864 100644 --- a/examples/hello-compute/main.rs +++ b/examples/hello-compute/main.rs @@ -72,6 +72,7 @@ async fn execute_gpu(numbers: Vec) -> Vec { dynamic: false, readonly: false, }, + ..Default::default() }], }); diff --git a/examples/mipmap/main.rs b/examples/mipmap/main.rs index 7c03f92d8a..071be587f3 100644 --- a/examples/mipmap/main.rs +++ b/examples/mipmap/main.rs @@ -92,11 +92,13 @@ impl Example { component_type: wgpu::TextureComponentType::Float, dimension: wgpu::TextureViewDimension::D2, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: false }, + ..Default::default() }, ], label: None, @@ -231,6 +233,7 @@ impl framework::Example for Example { binding: 0, visibility: wgpu::ShaderStage::VERTEX, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, @@ -240,11 +243,13 @@ impl framework::Example for Example { multisampled: false, dimension: wgpu::TextureViewDimension::D2, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: false }, + ..Default::default() }, ], label: None, diff --git a/examples/shadow/main.rs b/examples/shadow/main.rs index df11fd8b29..f4ae65f20c 100644 --- a/examples/shadow/main.rs +++ b/examples/shadow/main.rs @@ -248,6 +248,7 @@ impl framework::Example for Example { binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }], label: None, }); @@ -430,6 +431,7 @@ impl framework::Example for Example { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }], label: None, }); @@ -518,11 +520,13 @@ impl framework::Example for Example { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, // lights visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 2, @@ -532,11 +536,13 @@ impl framework::Example for Example { component_type: wgpu::TextureComponentType::Float, dimension: wgpu::TextureViewDimension::D2Array, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 3, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: true }, + ..Default::default() }, ], label: None, diff --git a/examples/skybox/main.rs b/examples/skybox/main.rs index 4532554dae..acbf7250bd 100644 --- a/examples/skybox/main.rs +++ b/examples/skybox/main.rs @@ -46,6 +46,7 @@ impl framework::Example for Skybox { binding: 0, visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 1, @@ -55,11 +56,13 @@ impl framework::Example for Skybox { multisampled: false, dimension: wgpu::TextureViewDimension::Cube, }, + ..Default::default() }, wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Sampler { comparison: false }, + ..Default::default() }, ], label: None, diff --git a/examples/texture-arrays/main.rs b/examples/texture-arrays/main.rs new file mode 100644 index 0000000000..78a64a947c --- /dev/null +++ b/examples/texture-arrays/main.rs @@ -0,0 +1,318 @@ +#[path = "../framework.rs"] +mod framework; + +use bytemuck::{Pod, Zeroable}; + +#[repr(C)] +#[derive(Clone, Copy)] +struct Vertex { + _pos: [f32; 2], + _tex_coord: [f32; 2], + _index: u32, +} + +unsafe impl Pod for Vertex {} +unsafe impl Zeroable for Vertex {} + +fn vertex(pos: [i8; 2], tc: [i8; 2], index: i8) -> Vertex { + Vertex { + _pos: [pos[0] as f32, pos[1] as f32], + _tex_coord: [tc[0] as f32, tc[1] as f32], + _index: index as u32, + } +} + +fn create_vertices() -> Vec { + vec![ + // left rectangle + vertex([-1, -1], [0, 1], 0), + vertex([-1, 1], [0, 0], 0), + vertex([0, 1], [1, 0], 0), + vertex([0, -1], [1, 1], 0), + // right rectangle + vertex([0, -1], [0, 1], 1), + vertex([0, 1], [0, 0], 1), + vertex([1, 1], [1, 0], 1), + vertex([1, -1], [1, 1], 1), + ] +} + +fn create_indices() -> Vec { + vec![ + // Left rectangle + 0, 1, 2, // 1st + 2, 0, 3, // 2nd + // Right rectangle + 4, 5, 6, // 1st + 6, 4, 7, // 2nd + ] +} + +#[derive(Copy, Clone)] +enum Color { + RED, + GREEN, +} + +fn create_texture_data(color: Color) -> [u8; 4] { + match color { + Color::RED => [255, 0, 0, 255], + Color::GREEN => [0, 255, 0, 255], + } +} + +struct Example { + pipeline: wgpu::RenderPipeline, + bind_group: wgpu::BindGroup, + vertex_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, +} + +impl framework::Example for Example { + fn needed_extensions() -> (wgpu::Extensions, wgpu::UnsafeExtensions) { + ( + wgpu::Extensions::TEXTURE_BINDING_ARRAY, + wgpu::UnsafeExtensions::disallow(), + ) + } + fn init( + sc_desc: &wgpu::SwapChainDescriptor, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> (Self, Option) { + let device_extensions = device.extensions(); + + assert!( + device_extensions.contains(wgpu::Extensions::TEXTURE_BINDING_ARRAY), + "Graphics Device does not support TEXTURE_BINDING_ARRAY extension" + ); + + let vertex_size = std::mem::size_of::(); + let vertex_data = create_vertices(); + let vertex_buffer = device.create_buffer_with_data( + bytemuck::cast_slice(&vertex_data), + wgpu::BufferUsage::VERTEX, + ); + + let index_data = create_indices(); + let index_buffer = device + .create_buffer_with_data(bytemuck::cast_slice(&index_data), wgpu::BufferUsage::INDEX); + + let red_texture_data = create_texture_data(Color::RED); + let green_texture_data = create_texture_data(Color::GREEN); + + let texture_descriptor = wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: 1, + height: 1, + depth: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8UnormSrgb, + usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, + label: None, + }; + let red_texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some("red"), + ..texture_descriptor + }); + let green_texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some("green"), + ..texture_descriptor + }); + + let red_texture_view = red_texture.create_default_view(); + let green_texture_view = green_texture.create_default_view(); + + queue.write_texture( + wgpu::TextureCopyView { + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + texture: &red_texture, + }, + &red_texture_data, + wgpu::TextureDataLayout { + offset: 0, + bytes_per_row: 4, + rows_per_image: 0, + }, + wgpu::Extent3d { + width: 1, + height: 1, + depth: 1, + }, + ); + queue.write_texture( + wgpu::TextureCopyView { + mip_level: 0, + origin: wgpu::Origin3d::ZERO, + texture: &green_texture, + }, + &green_texture_data, + wgpu::TextureDataLayout { + offset: 0, + bytes_per_row: 4, + rows_per_image: 0, + }, + wgpu::Extent3d { + width: 1, + height: 1, + depth: 1, + }, + ); + + let sampler = device.create_sampler(&wgpu::SamplerDescriptor::default()); + + let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + component_type: wgpu::TextureComponentType::Float, + dimension: wgpu::TextureViewDimension::D2, + multisampled: false, + }, + count: Some(2), + ..Default::default() + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { comparison: false }, + ..Default::default() + }, + ], + label: Some("bind group layout"), + }); + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::TextureViewArray(&[ + red_texture_view, + green_texture_view, + ]), + }, + wgpu::Binding { + binding: 1, + resource: wgpu::BindingResource::Sampler(&sampler), + }, + ], + layout: &bind_group_layout, + 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 = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &pipeline_layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: sc_desc.format, + color_blend: wgpu::BlendDescriptor::REPLACE, + alpha_blend: wgpu::BlendDescriptor::REPLACE, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: None, + vertex_state: wgpu::VertexStateDescriptor { + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[wgpu::VertexBufferDescriptor { + stride: vertex_size as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &wgpu::vertex_attr_array![0 => Float2, 1 => Float2, 2 => Int], + }], + }, + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + ( + Self { + vertex_buffer, + index_buffer, + bind_group, + pipeline, + }, + None, + ) + } + fn resize( + &mut self, + _sc_desc: &wgpu::SwapChainDescriptor, + _device: &wgpu::Device, + _queue: &wgpu::Queue, + ) { + // noop + } + fn update(&mut self, _event: winit::event::WindowEvent) { + // noop + } + fn render( + &mut self, + frame: &wgpu::SwapChainTexture, + device: &wgpu::Device, + _queue: &wgpu::Queue, + ) -> wgpu::CommandBuffer { + let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("primary"), + }); + + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 1.0, + }, + }], + depth_stencil_attachment: None, + }); + rpass.set_pipeline(&self.pipeline); + 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); + + drop(rpass); + + encoder.finish() + } +} + +fn main() { + framework::run::("texture-arrays"); +} diff --git a/examples/texture-arrays/shader.frag b/examples/texture-arrays/shader.frag new file mode 100644 index 0000000000..0149e9d833 --- /dev/null +++ b/examples/texture-arrays/shader.frag @@ -0,0 +1,18 @@ +#version 450 + +layout(location = 0) in vec2 v_TexCoord; +layout(location = 1) flat in int v_Index; +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() { + if (v_Index == 0) { + o_Color = vec4(texture(sampler2D(u_Textures[0], u_Sampler), v_TexCoord).rgb, 1.0); + } 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); + } +} diff --git a/examples/texture-arrays/shader.frag.spv b/examples/texture-arrays/shader.frag.spv new file mode 100644 index 0000000000..a50d941123 Binary files /dev/null and b/examples/texture-arrays/shader.frag.spv differ diff --git a/examples/texture-arrays/shader.vert b/examples/texture-arrays/shader.vert new file mode 100644 index 0000000000..cd7d2c7694 --- /dev/null +++ b/examples/texture-arrays/shader.vert @@ -0,0 +1,13 @@ +#version 450 + +layout(location = 0) in vec2 a_Pos; +layout(location = 1) in vec2 a_TexCoord; +layout(location = 2) in int a_Index; +layout(location = 0) out vec2 v_TexCoord; +layout(location = 1) flat out int v_Index; + +void main() { + v_TexCoord = a_TexCoord; + v_Index = a_Index; + gl_Position = vec4(a_Pos, 0.0, 1.0); +} diff --git a/examples/texture-arrays/shader.vert.spv b/examples/texture-arrays/shader.vert.spv new file mode 100644 index 0000000000..c1ca86d7fb Binary files /dev/null and b/examples/texture-arrays/shader.vert.spv differ diff --git a/src/backend/direct.rs b/src/backend/direct.rs index 1f28ffd6ef..d4e0706b37 100644 --- a/src/backend/direct.rs +++ b/src/backend/direct.rs @@ -1,14 +1,15 @@ use crate::{ backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, - BindingType, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, - Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, - SwapChainStatus, TextureDescriptor, TextureViewDescriptor, TextureViewDimension, + BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, Limits, + MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, + SwapChainStatus, TextureDescriptor, TextureViewDescriptor, }; use arrayvec::ArrayVec; use futures::future::{ready, Ready}; use smallvec::SmallVec; use std::{ffi::CString, marker::PhantomData, ops::Range, ptr, slice}; +use typed_arena::Arena; macro_rules! gfx_select { ($id:expr => $global:ident.$method:ident( $($param:expr),+ )) => { @@ -291,64 +292,9 @@ impl crate::Context for Context { device: &Self::DeviceId, desc: &BindGroupLayoutDescriptor, ) -> Self::BindGroupLayoutId { - use wgc::binding_model as bm; - - let temp_layouts = desc - .bindings - .iter() - .map(|bind| bm::BindGroupLayoutEntry { - binding: bind.binding, - visibility: bind.visibility, - ty: match bind.ty { - BindingType::UniformBuffer { .. } => bm::BindingType::UniformBuffer, - BindingType::StorageBuffer { - readonly: false, .. - } => bm::BindingType::StorageBuffer, - BindingType::StorageBuffer { readonly: true, .. } => { - bm::BindingType::ReadonlyStorageBuffer - } - BindingType::Sampler { comparison: false } => bm::BindingType::Sampler, - BindingType::Sampler { .. } => bm::BindingType::ComparisonSampler, - BindingType::SampledTexture { .. } => bm::BindingType::SampledTexture, - BindingType::StorageTexture { readonly: true, .. } => { - bm::BindingType::ReadonlyStorageTexture - } - BindingType::StorageTexture { .. } => bm::BindingType::WriteonlyStorageTexture, - }, - has_dynamic_offset: match bind.ty { - BindingType::UniformBuffer { dynamic } - | BindingType::StorageBuffer { dynamic, .. } => dynamic, - _ => false, - }, - multisampled: match bind.ty { - BindingType::SampledTexture { multisampled, .. } => multisampled, - _ => false, - }, - view_dimension: match bind.ty { - BindingType::SampledTexture { dimension, .. } - | BindingType::StorageTexture { dimension, .. } => dimension, - _ => TextureViewDimension::D2, - }, - texture_component_type: match bind.ty { - BindingType::SampledTexture { component_type, .. } - | BindingType::StorageTexture { component_type, .. } => component_type, - _ => wgt::TextureComponentType::Float, - }, - storage_texture_format: match bind.ty { - BindingType::StorageTexture { format, .. } => format, - _ => wgt::TextureFormat::Rgb10a2Unorm, // doesn't matter - }, - }) - .collect::>(); - - let owned_label = OwnedLabel::new(desc.label.as_deref()); gfx_select!(*device => self.device_create_bind_group_layout( *device, - &bm::BindGroupLayoutDescriptor { - entries: temp_layouts.as_ptr(), - entries_length: temp_layouts.len(), - label: owned_label.as_ptr(), - }, + desc, PhantomData )) .unwrap() @@ -361,13 +307,14 @@ impl crate::Context for Context { ) -> Self::BindGroupId { use wgc::binding_model as bm; + let texture_view_arena: Arena = Arena::new(); let bindings = desc .bindings .iter() .map(|binding| bm::BindGroupEntry { binding: binding.binding, - resource: match &binding.resource { - BindingResource::Buffer(buffer_slice) => { + resource: match binding.resource { + BindingResource::Buffer(ref buffer_slice) => { bm::BindingResource::Buffer(bm::BufferBinding { buffer: buffer_slice.buffer.id, offset: buffer_slice.offset, @@ -380,18 +327,22 @@ impl crate::Context for Context { BindingResource::TextureView(ref texture_view) => { bm::BindingResource::TextureView(texture_view.id) } + BindingResource::TextureViewArray(texture_view_array) => { + bm::BindingResource::TextureViewArray( + texture_view_arena + .alloc_extend(texture_view_array.iter().map(|view| view.id)), + ) + } }, }) .collect::>(); - let owned_label = OwnedLabel::new(desc.label.as_deref()); gfx_select!(*device => self.device_create_bind_group( *device, &bm::BindGroupDescriptor { + label: desc.label, layout: desc.layout.id, - entries: bindings.as_ptr(), - entries_length: bindings.len(), - label: owned_label.as_ptr(), + bindings: &bindings, }, PhantomData )) diff --git a/src/backend/web.rs b/src/backend/web.rs index d3d3da1743..d046cbec95 100644 --- a/src/backend/web.rs +++ b/src/backend/web.rs @@ -773,8 +773,14 @@ impl crate::Context for Context { bt::ReadonlyStorageTexture } BindingType::StorageTexture { .. } => bt::WriteonlyStorageTexture, + _ => unreachable!(), }; + assert!( + bind.count.is_none(), + "The web backend doesn't support arrays of bindings" + ); + let mut mapped_entry = web_sys::GpuBindGroupLayoutEntry::new( bind.binding, mapped_type, @@ -848,6 +854,9 @@ impl crate::Context for Context { BindingResource::TextureView(ref texture_view) => { JsValue::from(texture_view.id.0.clone()) } + BindingResource::TextureViewArray(..) => { + panic!("Web backend does not support TEXTURE_BINDING_ARRAY extension") + } }; web_sys::GpuBindGroupEntry::new(binding.binding, &mapped_resource) diff --git a/src/lib.rs b/src/lib.rs index 65ecb32820..36b263414b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,15 +19,15 @@ use parking_lot::Mutex; #[cfg(not(target_arch = "wasm32"))] pub use wgc::instance::{AdapterInfo, DeviceType}; pub use wgt::{ - read_spirv, AddressMode, Backend, BackendBit, 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, ShaderLocation, ShaderStage, StencilOperation, - StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect, - TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage, - TextureViewDimension, UnsafeExtensions, VertexAttributeDescriptor, VertexFormat, + 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, 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, }; @@ -606,10 +606,12 @@ pub struct Queue { } /// A resource that can be bound to a pipeline. +#[non_exhaustive] pub enum BindingResource<'a> { Buffer(BufferSlice<'a>), Sampler(&'a Sampler), TextureView(&'a TextureView), + TextureViewArray(&'a [TextureView]), } /// A bindable resource and the slot to bind it to. @@ -618,118 +620,6 @@ pub struct Binding<'a> { pub resource: BindingResource<'a>, } -/// Specific type of a binding. -/// WebGPU spec: https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub enum BindingType { - /// A buffer for uniform values. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout(std140, binding = 0) - /// uniform Globals { - /// vec2 aUniform; - /// vec2 anotherUniform; - /// }; - /// ``` - UniformBuffer { - /// Indicates that the binding has a dynamic offset. - /// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number. - dynamic: bool, - }, - /// A storage buffer. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout (set=0, binding=0) buffer myStorageBuffer { - /// vec4 myElement[]; - /// }; - /// ``` - StorageBuffer { - /// Indicates that the binding has a dynamic offset. - /// One offset must be passed to [RenderPass::set_bind_group] for each dynamic binding in increasing order of binding number. - dynamic: bool, - /// The buffer can only be read in the shader and it must be annotated with `readonly`. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout (set=0, binding=0) readonly buffer myStorageBuffer { - /// vec4 myElement[]; - /// }; - /// ``` - readonly: bool, - }, - /// A sampler that can be used to sample a texture. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout(binding = 0) - /// uniform sampler s; - /// ``` - Sampler { - /// Use as a comparison sampler instead of a normal sampler. - /// For more info take a look at the analogous functionality in OpenGL: https://www.khronos.org/opengl/wiki/Sampler_Object#Comparison_mode. - comparison: bool, - }, - /// A texture. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout(binding = 0) - /// uniform texture2D t; - /// ``` - SampledTexture { - /// Dimension of the texture view that is going to be sampled. - dimension: TextureViewDimension, - /// Component type of the texture. - /// This must be compatible with the format of the texture. - component_type: TextureComponentType, - /// True if the texture has a sample count greater than 1. - multisampled: bool, - }, - /// A storage texture. - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout(set=0, binding=0, r32f) uniform image2D myStorageImage; - /// ``` - /// Note that the texture format must be specified in the shader as well. - /// A list of valid formats can be found in the specification here: https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.html#layout-qualifiers - StorageTexture { - /// Dimension of the texture view that is going to be sampled. - dimension: TextureViewDimension, - /// Component type of the texture. - /// This must be compatible with the format of the texture. - component_type: TextureComponentType, - /// Format of the texture. - format: TextureFormat, - /// The texture can only be read in the shader and it must be annotated with `readonly`. - /// - /// Example GLSL syntax: - /// ```cpp,ignore - /// layout(set=0, binding=0, r32f) readonly uniform image2D myStorageImage; - /// ``` - readonly: bool, - }, -} - -/// A description of a single binding inside a bind group. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub struct BindGroupLayoutEntry { - pub binding: u32, - pub visibility: ShaderStage, - pub ty: BindingType, -} - -/// A description of a bind group layout. -#[derive(Clone, Debug)] -pub struct BindGroupLayoutDescriptor<'a> { - pub bindings: &'a [BindGroupLayoutEntry], - - /// An optional label to apply to the bind group layout. - /// This can be useful for debugging and performance analysis. - pub label: Option<&'a str>, -} - /// A description of a group of bindings and the resources to be bound. #[derive(Clone)] pub struct BindGroupDescriptor<'a> {