From a267d0785d9827079b6e9a42ad2f1d60f6205d38 Mon Sep 17 00:00:00 2001 From: Chandler Newman Date: Fri, 12 Mar 2021 18:36:17 +0000 Subject: [PATCH] [rs] Add uniform and storage buffer arrays --- wgpu/Cargo.toml | 8 +++----- wgpu/examples/shadow/main.rs | 4 ++-- wgpu/src/backend/direct.rs | 27 +++++++++++++++++++++--- wgpu/src/backend/web.rs | 7 +++++-- wgpu/src/lib.rs | 40 +++++++++++++++++++++++++----------- 5 files changed, 62 insertions(+), 24 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index ea831cb88..888bb60b6 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -19,8 +19,6 @@ all-features = true default = [] trace = ["serde", "wgc/trace"] replay = ["serde", "wgc/replay"] -# Make Vulkan backend available on platforms where it is by default not, e.g. macOS -vulkan-portability = ["wgc/gfx-backend-vulkan"] webgl = ["wgc"] # Enable SPIRV-Cross cross = ["wgc/cross"] @@ -28,20 +26,20 @@ cross = ["wgc/cross"] [target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "13015c8621daade1decb7e1083b7e0f73eeab6c7" +rev = "e5ddb94be0221b0f53a8f43adfb15458daebfd7c" features = ["raw-window-handle"] [target.'cfg(target_arch = "wasm32")'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "13015c8621daade1decb7e1083b7e0f73eeab6c7" +rev = "e5ddb94be0221b0f53a8f43adfb15458daebfd7c" features = ["raw-window-handle"] optional = true [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "13015c8621daade1decb7e1083b7e0f73eeab6c7" +rev = "e5ddb94be0221b0f53a8f43adfb15458daebfd7c" [dependencies] arrayvec = "0.5" diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index 008576963..7b48b846b 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -349,11 +349,11 @@ impl framework::Example for Example { layout: &local_bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, - resource: wgpu::BindingResource::Buffer { + resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding { buffer: &entity_uniform_buf, offset: 0, size: wgpu::BufferSize::new(entity_uniform_size), - }, + }), }], label: None, }); diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 24f49ff9f..796e296d9 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -1,6 +1,6 @@ use crate::{ backend::{error::ContextError, native_gpu_future}, - AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, + AdapterInfo, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BufferBinding, CommandEncoderDescriptor, ComputePassDescriptor, ComputePipelineDescriptor, DownlevelProperties, Features, Label, Limits, LoadOp, MapMode, Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor, @@ -875,21 +875,42 @@ impl crate::Context for Context { } let mut remaining_arrayed_texture_views = &arrayed_texture_views[..]; + let mut arrayed_buffer_bindings = Vec::new(); + if device.features.contains(Features::BUFFER_BINDING_ARRAY) { + // gather all the buffers first + for entry in desc.entries.iter() { + if let BindingResource::BufferArray(array) = entry.resource { + arrayed_buffer_bindings.extend(array.iter().map(|binding| bm::BufferBinding { + buffer_id: binding.buffer.id.id, + offset: binding.offset, + size: binding.size, + })); + } + } + } + let mut remaining_arrayed_buffer_bindings = &arrayed_buffer_bindings[..]; + let entries = desc .entries .iter() .map(|entry| bm::BindGroupEntry { binding: entry.binding, resource: match entry.resource { - BindingResource::Buffer { + BindingResource::Buffer(BufferBinding { buffer, offset, size, - } => bm::BindingResource::Buffer(bm::BufferBinding { + }) => bm::BindingResource::Buffer(bm::BufferBinding { buffer_id: buffer.id.id, offset, size, }), + BindingResource::BufferArray(array) => { + let slice = &remaining_arrayed_buffer_bindings[..array.len()]; + remaining_arrayed_buffer_bindings = + &remaining_arrayed_buffer_bindings[array.len()..]; + bm::BindingResource::BufferArray(Borrowed(slice)) + } BindingResource::Sampler(sampler) => bm::BindingResource::Sampler(sampler.id), BindingResource::TextureView(texture_view) => { bm::BindingResource::TextureView(texture_view.id) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 0f2585d8c..27ec21b47 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1267,11 +1267,11 @@ impl crate::Context for Context { .iter() .map(|binding| { let mapped_resource = match binding.resource { - crate::BindingResource::Buffer { + crate::BindingResource::Buffer(crate::BufferBinding { ref buffer, offset, size, - } => { + }) => { let mut mapped_buffer_binding = web_sys::GpuBufferBinding::new(&buffer.id.0); mapped_buffer_binding.offset(offset as f64); @@ -1280,6 +1280,9 @@ impl crate::Context for Context { } JsValue::from(mapped_buffer_binding.clone()) } + crate::BindingResource::BufferArray(..) => { + panic!("Web backend does not support arrays of buffers") + } crate::BindingResource::Sampler(ref sampler) => { JsValue::from(sampler.id.0.clone()) } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index c59af3839..966f4a45b 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -949,17 +949,14 @@ pub enum BindingResource<'a> { /// /// Corresponds to [`wgt::BufferBindingType::Uniform`] and [`wgt::BufferBindingType::Storage`] /// with [`BindGroupLayoutEntry::count`] set to None. - Buffer { - /// The buffer to bind. - buffer: &'a Buffer, - /// Base offset of the buffer. For bindings with `dynamic == true`, this offset - /// will be added to the dynamic offset provided in [`RenderPass::set_bind_group`]. - /// - /// The offset has to be aligned to [`BIND_BUFFER_ALIGNMENT`]. - offset: BufferAddress, - /// Size of the binding, or `None` for using the rest of the buffer. - size: Option, - }, + Buffer(BufferBinding<'a>), + /// Binding is backed by an array of buffers. + /// + /// [`Features::BUFFER_BINDING_ARRAY`] must be supported to use this feature. + /// + /// Corresponds to [`wgt::BufferBindingType::Uniform`] and [`wgt::BufferBindingType::Storage`] + /// with [`BindGroupLayoutEntry::count`] set to Some. + BufferArray(&'a [BufferBinding<'a>]), /// Binding is a sampler. /// /// Corresponds to [`wgt::BindingType::Sampler`] with [`BindGroupLayoutEntry::count`] set to None. @@ -978,6 +975,20 @@ pub enum BindingResource<'a> { TextureViewArray(&'a [&'a TextureView]), } +/// Describes the segment of a buffer to bind. +#[derive(Clone, Debug)] +pub struct BufferBinding<'a> { + /// The buffer to bind. + pub buffer: &'a Buffer, + /// Base offset of the buffer. For bindings with `dynamic == true`, this offset + /// will be added to the dynamic offset provided in [`RenderPass::set_bind_group`]. + /// + /// The offset has to be aligned to [`BIND_BUFFER_ALIGNMENT`]. + pub offset: BufferAddress, + /// Size of the binding, or `None` for using the rest of the buffer. + pub size: Option, +} + /// Operation to perform to the output attachment at the start of a renderpass. /// /// The render target must be cleared at least once before its content is loaded. @@ -1833,7 +1844,12 @@ impl Drop for BufferViewMut<'_> { impl Buffer { /// Return the binding view of the entire buffer. pub fn as_entire_binding(&self) -> BindingResource { - BindingResource::Buffer { + BindingResource::Buffer(self.as_entire_buffer_binding()) + } + + /// Return the binding view of the entire buffer. + pub fn as_entire_buffer_binding(&self) -> BufferBinding { + BufferBinding { buffer: self, offset: 0, size: None,