From 857955483a2a458ddbb477a24d6ab1d80a17de2c Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 9 Jul 2020 16:07:53 -0400 Subject: [PATCH] [rs] Implement PUSH_CONSTANTS feature --- wgpu/Cargo.toml | 4 +- wgpu/examples/README.md | 3 +- wgpu/examples/boids/main.rs | 2 + wgpu/examples/cube/main.rs | 1 + wgpu/examples/framework.rs | 7 +- wgpu/examples/hello-compute/main.rs | 1 + wgpu/examples/hello-triangle/main.rs | 1 + wgpu/examples/hello/main.rs | 1 + wgpu/examples/mipmap/main.rs | 2 + wgpu/examples/msaa-line/main.rs | 1 + wgpu/examples/shadow/main.rs | 2 + wgpu/examples/skybox/main.rs | 1 + wgpu/examples/texture-arrays/main.rs | 96 ++++++---------- wgpu/examples/texture-arrays/uniform.frag | 2 +- wgpu/examples/texture-arrays/uniform.frag.spv | Bin 1028 -> 996 bytes wgpu/examples/water/main.rs | 2 + wgpu/src/backend/direct.rs | 56 ++++++++- wgpu/src/backend/web.rs | 6 + wgpu/src/lib.rs | 107 ++++++++++++++++-- 19 files changed, 214 insertions(+), 81 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index 06584ff01f..c2664909df 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -27,14 +27,14 @@ vulkan = ["wgc/gfx-backend-vulkan"] package = "wgpu-core" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "d7ee89018bed6b2e050b8160b2bd837d89f598a6" +rev = "f67771fb87ce17a7f7e09f9a01149b4132196928" features = ["raw-window-handle"] [dependencies.wgt] package = "wgpu-types" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "d7ee89018bed6b2e050b8160b2bd837d89f598a6" +rev = "f67771fb87ce17a7f7e09f9a01149b4132196928" [dependencies] arrayvec = "0.5" diff --git a/wgpu/examples/README.md b/wgpu/examples/README.md index f8f7c3eb53..d6e69079be 100644 --- a/wgpu/examples/README.md +++ b/wgpu/examples/README.md @@ -5,7 +5,7 @@ For the simplest examples without using any helping code (see `framework.rs` her - `hello-triangle` for graphics and presentation - `hello-compute` for pure computing -Notably, `capture` example show rendering without a surface/window. It reads back the contents and saves them to a file. +Notably, `capture` example shows rendering without a surface/window. It reads back the contents and saves them to a file. All framework-based examples render to the window. @@ -32,6 +32,7 @@ All framework-based examples render to the window. | compute passes | :star: | | | | | | | | | optional extensions | | | | | | | :star: | | | - binding indexing | | | | | | | :star: | | +| - push constants | | | | | | | :star: | | | WGSL shaders | | | | | | | | | ## Hacking diff --git a/wgpu/examples/boids/main.rs b/wgpu/examples/boids/main.rs index 0549ed65a7..ea33ac9fb7 100644 --- a/wgpu/examples/boids/main.rs +++ b/wgpu/examples/boids/main.rs @@ -90,6 +90,7 @@ impl framework::Example for Example { let compute_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&compute_bind_group_layout], + push_constant_ranges: &[], }); // create render pipeline with empty bind group layout @@ -97,6 +98,7 @@ impl framework::Example for Example { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[], + push_constant_ranges: &[], }); let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { diff --git a/wgpu/examples/cube/main.rs b/wgpu/examples/cube/main.rs index 9c0aa33ab2..41a68904e5 100644 --- a/wgpu/examples/cube/main.rs +++ b/wgpu/examples/cube/main.rs @@ -161,6 +161,7 @@ impl framework::Example for Example { }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }); // Create the texture diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index bef4ab4512..393a78bd5a 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -33,6 +33,9 @@ pub trait Example: 'static + Sized { fn needed_features() -> wgpu::Features { wgpu::Features::empty() } + fn needed_limits() -> wgpu::Limits { + wgpu::Limits::default() + } fn init( sc_desc: &wgpu::SwapChainDescriptor, device: &wgpu::Device, @@ -97,12 +100,14 @@ async fn setup(title: &str) -> Setup { let adapter_features = adapter.features(); + let needed_limits = E::needed_limits(); + let trace_dir = std::env::var("WGPU_TRACE"); let (device, queue) = adapter .request_device( &wgpu::DeviceDescriptor { features: adapter_features & needed_features, - limits: wgpu::Limits::default(), + limits: needed_limits, shader_validation: true, }, trace_dir.ok().as_ref().map(std::path::Path::new), diff --git a/wgpu/examples/hello-compute/main.rs b/wgpu/examples/hello-compute/main.rs index c6766fb836..6f41e490c3 100644 --- a/wgpu/examples/hello-compute/main.rs +++ b/wgpu/examples/hello-compute/main.rs @@ -81,6 +81,7 @@ async fn execute_gpu(numbers: Vec) -> Vec { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }); let compute_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor { diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index 91d1d63d33..69889ded0d 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -36,6 +36,7 @@ async fn run(event_loop: EventLoop<()>, window: Window, swapchain_format: wgpu:: let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[], + push_constant_ranges: &[], }); let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { diff --git a/wgpu/examples/hello/main.rs b/wgpu/examples/hello/main.rs index 9b45ce5256..b3aff1c149 100644 --- a/wgpu/examples/hello/main.rs +++ b/wgpu/examples/hello/main.rs @@ -1,5 +1,6 @@ /// This example shows how to describe the adapter in use. async fn run() { + #[cfg_attr(target_arch = "wasm32", allow(unused_variables))] let adapter = wgpu::Instance::new(wgpu::BackendBit::PRIMARY) .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::Default, diff --git a/wgpu/examples/mipmap/main.rs b/wgpu/examples/mipmap/main.rs index d658d7dd52..bbf24bca80 100644 --- a/wgpu/examples/mipmap/main.rs +++ b/wgpu/examples/mipmap/main.rs @@ -101,6 +101,7 @@ impl Example { }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }); let vs_module = device.create_shader_module(wgpu::include_spirv!("blit.vert.spv")); @@ -249,6 +250,7 @@ impl framework::Example for Example { }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }); // Create the texture diff --git a/wgpu/examples/msaa-line/main.rs b/wgpu/examples/msaa-line/main.rs index f42c9f92f0..79d479d115 100644 --- a/wgpu/examples/msaa-line/main.rs +++ b/wgpu/examples/msaa-line/main.rs @@ -141,6 +141,7 @@ impl framework::Example for Example { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[], + push_constant_ranges: &[], }); let multisampled_framebuffer = diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index b8ec879e19..7c32003f3e 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -442,6 +442,7 @@ impl framework::Example for Example { }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout, &local_bind_group_layout], + push_constant_ranges: &[], }); let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { @@ -553,6 +554,7 @@ impl framework::Example for Example { }); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout, &local_bind_group_layout], + push_constant_ranges: &[], }); let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index b95fde27ad..2abae7ef81 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -84,6 +84,7 @@ impl framework::Example for Skybox { let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }); // Create the render pipeline diff --git a/wgpu/examples/texture-arrays/main.rs b/wgpu/examples/texture-arrays/main.rs index 45772274e8..bf0ffec6d4 100644 --- a/wgpu/examples/texture-arrays/main.rs +++ b/wgpu/examples/texture-arrays/main.rs @@ -23,12 +23,6 @@ struct Uniform { 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], @@ -81,7 +75,7 @@ struct Example { bind_group: wgpu::BindGroup, vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, - uniform_workaround_data: Option, + uniform_workaround: bool, } impl framework::Example for Example { @@ -90,6 +84,13 @@ impl framework::Example for Example { | wgpu::Features::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING | wgpu::Features::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING | wgpu::Features::SAMPLED_TEXTURE_BINDING_ARRAY + | wgpu::Features::PUSH_CONSTANTS + } + fn needed_limits() -> wgpu::Limits { + wgpu::Limits { + max_push_constant_size: 4, + ..wgpu::Limits::default() + } } fn init( sc_desc: &wgpu::SwapChainDescriptor, @@ -131,56 +132,6 @@ 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 { - entries: &[wgpu::BindGroupLayoutEntry::new( - 0, - wgpu::ShaderStage::FRAGMENT, - wgpu::BindingType::UniformBuffer { - dynamic: false, - min_binding_size: None, - }, - )], - label: Some("uniform workaround bind group layout"), - }); - - let bind_group0 = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - entries: &[wgpu::BindGroupEntry { - 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, - entries: &[wgpu::BindGroupEntry { - 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); @@ -289,13 +240,18 @@ impl framework::Example for Example { label: Some("bind group"), }); - let pipeline_layout = if let Some(ref workaround) = uniform_workaround_data { + let pipeline_layout = if uniform_workaround { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout, &workaround.bind_group_layout], + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[wgpu::PushConstantRange { + stages: wgpu::ShaderStage::FRAGMENT, + range: 0..4, + }], }) } else { device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], }) }; @@ -342,7 +298,7 @@ impl framework::Example for Example { index_buffer, bind_group, pipeline, - uniform_workaround_data, + uniform_workaround, } } fn resize( @@ -378,14 +334,28 @@ impl framework::Example for Example { }], depth_stencil_attachment: None, }); + + let uniform_workaround_data = if self.uniform_workaround { + Some([Uniform { index: 0 }, Uniform { index: 1 }]) + } else { + 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(..)); - if let Some(ref workaround) = self.uniform_workaround_data { - rpass.set_bind_group(1, &workaround.bind_group0, &[]); + if let Some(ref data) = uniform_workaround_data { + rpass.set_push_constants( + wgpu::ShaderStage::FRAGMENT, + 0, + bytemuck::cast_slice(&data[0..1]), + ); rpass.draw_indexed(0..6, 0, 0..1); - rpass.set_bind_group(1, &workaround.bind_group1, &[]); + rpass.set_push_constants( + wgpu::ShaderStage::FRAGMENT, + 0, + bytemuck::cast_slice(&data[1..2]), + ); rpass.draw_indexed(6..12, 0, 0..1); } else { rpass.draw_indexed(0..12, 0, 0..1); diff --git a/wgpu/examples/texture-arrays/uniform.frag b/wgpu/examples/texture-arrays/uniform.frag index 396d77c67b..3b7a136b13 100644 --- a/wgpu/examples/texture-arrays/uniform.frag +++ b/wgpu/examples/texture-arrays/uniform.frag @@ -6,7 +6,7 @@ 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 { +layout(push_constant) uniform Uniforms { int u_Index; // dynamically uniform }; diff --git a/wgpu/examples/texture-arrays/uniform.frag.spv b/wgpu/examples/texture-arrays/uniform.frag.spv index 7846abbb83ed94d8d2a413c6e5fc78e20165489d..671a87262d79f94e5cdb1c9045910820d80a0f0f 100644 GIT binary patch delta 51 zcmZqSc)~v6z{Up#jEtO<1(}3pIT;ujv>8|!1c0;%5QBgMkS_|PIX62p9cBao2u=sW delta 77 zcmaFD-oi2AfTS=31A`I}GXk+Y0}BI)uL#5p8+V#BGBQp6$S5q!1mtQ1; mod pass_impl { use super::Context; use smallvec::SmallVec; + use std::convert::TryInto; use std::ops::Range; use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; @@ -56,6 +57,18 @@ mod pass_impl { ) } } + fn set_push_constants(&mut self, offset: u32, data: &[u32]) { + unsafe { + wgpu_compute_pass_set_push_constant( + self, + offset, + (data.len() * std::mem::size_of::()) + .try_into() + .unwrap(), + data.as_ptr(), + ) + } + } fn dispatch(&mut self, x: u32, y: u32, z: u32) { wgpu_compute_pass_dispatch(self, x, y, z) } @@ -105,6 +118,19 @@ mod pass_impl { ) { wgpu_render_pass_set_vertex_buffer(self, slot, *buffer, offset, size) } + fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u32]) { + unsafe { + wgpu_render_pass_set_push_constants( + self, + stages, + offset, + (data.len() * std::mem::size_of::()) + .try_into() + .unwrap(), + data.as_ptr(), + ) + } + } fn draw(&mut self, vertices: Range, instances: Range) { wgpu_render_pass_draw( self, @@ -288,6 +314,20 @@ mod pass_impl { ) { wgpu_render_bundle_set_vertex_buffer(self, slot, *buffer, offset, size) } + + fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u32]) { + unsafe { + wgpu_render_bundle_set_push_constants( + self, + stages, + offset, + (data.len() * std::mem::size_of::()) + .try_into() + .unwrap(), + data.as_ptr(), + ) + } + } fn draw(&mut self, vertices: Range, instances: Range) { wgpu_render_bundle_draw( self, @@ -583,17 +623,27 @@ impl crate::Context for Context { desc: &PipelineLayoutDescriptor, ) -> Self::PipelineLayoutId { wgc::span!(_guard, TRACE, "Device::create_pipeline_layout wrapper"); - //TODO: avoid allocation here + + // Limit is always less or equal to wgc::MAX_BIND_GROUPS, so this is always right + // Guards following ArrayVec + assert!( + desc.bind_group_layouts.len() <= wgc::MAX_BIND_GROUPS, + "Bind group layout count {} exceeds device bind group limit {}", + desc.bind_group_layouts.len(), + wgc::MAX_BIND_GROUPS + ); + let temp_layouts = desc .bind_group_layouts .iter() .map(|bgl| bgl.id) - .collect::>(); + .collect::>(); gfx_select!(*device => self.device_create_pipeline_layout( *device, - &wgc::binding_model::PipelineLayoutDescriptor { + &wgt::PipelineLayoutDescriptor { bind_group_layouts: &temp_layouts, + push_constant_ranges: &desc.push_constant_ranges, }, PhantomData )) diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 39543e432d..b3df3023be 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -71,6 +71,9 @@ impl crate::ComputePassInner for ComputePass { offsets.len() as u32, ); } + fn set_push_constants(&mut self, _offset: u32, _data: &[u32]) { + panic!("PUSH_CONSTANTS feature must be enabled to call multi_draw_indexed_indirect") + } fn dispatch(&mut self, x: u32, y: u32, z: u32) { self.0.dispatch_with_y_and_z(x, y, z); } @@ -129,6 +132,9 @@ impl crate::RenderInner for RenderPass { size.expect("TODO").get() as f64, ); } + fn set_push_constants(&mut self, _stages: wgt::ShaderStage, _offset: u32, _data: &[u32]) { + panic!("PUSH_CONSTANTS feature must be enabled to call multi_draw_indexed_indirect") + } fn draw(&mut self, vertices: Range, instances: Range) { self.0 .draw_with_instance_count_and_first_vertex_and_first_instance( diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 5530454915..c2a274120f 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -29,12 +29,13 @@ pub use wgt::{ ColorStateDescriptor, ColorWrite, CommandBufferDescriptor, CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset, Extent3d, Features, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, Origin3d, PowerPreference, PresentMode, - PrimitiveTopology, RasterizationStateDescriptor, RenderBundleEncoderDescriptor, ShaderLocation, - ShaderStage, StencilOperation, StencilStateFaceDescriptor, SwapChainDescriptor, - SwapChainStatus, TextureAspect, TextureComponentType, TextureDataLayout, TextureDimension, - TextureFormat, TextureUsage, TextureViewDimension, VertexAttributeDescriptor, - VertexBufferDescriptor, VertexFormat, VertexStateDescriptor, BIND_BUFFER_ALIGNMENT, - COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, + PrimitiveTopology, PushConstantRange, RasterizationStateDescriptor, + RenderBundleEncoderDescriptor, ShaderLocation, ShaderStage, StencilOperation, + StencilStateFaceDescriptor, SwapChainDescriptor, SwapChainStatus, TextureAspect, + TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage, + TextureViewDimension, VertexAttributeDescriptor, VertexBufferDescriptor, VertexFormat, + VertexStateDescriptor, BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, + COPY_BYTES_PER_ROW_ALIGNMENT, PUSH_CONSTANT_ALIGNMENT, }; use backend::Context as C; @@ -47,6 +48,7 @@ trait ComputePassInner { bind_group: &Ctx::BindGroupId, offsets: &[DynamicOffset], ); + fn set_push_constants(&mut self, offset: u32, data: &[u32]); fn dispatch(&mut self, x: u32, y: u32, z: u32); fn dispatch_indirect( &mut self, @@ -76,6 +78,7 @@ trait RenderInner { offset: BufferAddress, size: Option, ); + fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u32]); fn draw(&mut self, vertices: Range, instances: Range); fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range); fn draw_indirect(&mut self, indirect_buffer: &Ctx::BufferId, indirect_offset: BufferAddress); @@ -857,6 +860,10 @@ pub use wgt::TextureViewDescriptor as TextureViewDescriptorBase; /// Describes a [`TextureView`]. pub type TextureViewDescriptor<'a> = TextureViewDescriptorBase>; +pub use wgt::PipelineLayoutDescriptor as PipelineLayoutDescriptorBase; +/// Describes a [`PipelineLayout`]. +pub type PipelineLayoutDescriptor<'a> = PipelineLayoutDescriptorBase<'a, &'a BindGroupLayout>; + pub use wgt::SamplerDescriptor as SamplerDescriptorBase; /// Describes a [`Sampler`]. pub type SamplerDescriptor<'a> = SamplerDescriptorBase>; @@ -870,10 +877,6 @@ pub use wgt::BindGroupDescriptor as BindGroupDescriptorBase; pub type BindGroupDescriptor<'a> = BindGroupDescriptorBase<'a, &'a BindGroupLayout, BindGroupEntry<'a>>; -pub use wgt::PipelineLayoutDescriptor as PipelineLayoutDescriptorBase; -/// Describes a pipeline layout. -pub type PipelineLayoutDescriptor<'a> = PipelineLayoutDescriptorBase<'a, &'a BindGroupLayout>; - pub use wgt::ProgrammableStageDescriptor as ProgrammableStageDescriptorBase; /// Describes a programmable pipeline stage. pub type ProgrammableStageDescriptor<'a> = wgt::ProgrammableStageDescriptor<'a, &'a ShaderModule>; @@ -1921,6 +1924,41 @@ impl<'a> RenderPass<'a> { } } +/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions. +impl<'a> RenderPass<'a> { + /// Set push constant data. + /// + /// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`]. + /// + /// Data size must be a multiple of 4 and must be aligned to the 4s, so we take an array of u32. + /// For example, with an offset of 4 and an array of `[u32; 3]`, that will write to the range + /// of 4..16. + /// + /// For each byte in the range of push constant data written, the union of the stages of all push constant + /// ranges that covers that byte must be exactly `stages`. There's no good way of explaining this simply, + /// so here are some examples: + /// + /// ```text + /// For the given ranges: + /// - 0..4 Vertex + /// - 4..8 Fragment + /// ``` + /// + /// You would need to upload this in two set_push_constants calls. First for the `Vertex` range, second for the `Fragment` range. + /// + /// ```text + /// For the given ranges: + /// - 0..8 Vertex + /// - 4..12 Fragment + /// ``` + /// + /// You would need to upload this in three set_push_constants calls. First for the `Vertex` only range 0..4, second + /// for the `Vertex | Fragment` range 4..8, third for the `Fragment` range 8..12. + pub fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &'a [u32]) { + self.id.set_push_constants(stages, offset, data); + } +} + impl<'a> Drop for RenderPass<'a> { fn drop(&mut self) { if !thread::panicking() { @@ -1967,6 +2005,20 @@ impl<'a> ComputePass<'a> { } } +/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions. +impl<'a> ComputePass<'a> { + /// Set push constant data. + /// + /// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`]. + /// + /// Data size must be a multiple of 4 and must be aligned to the 4s, so we take an array of u32. + /// For example, with an offset of 4 and an array of `[u32; 3]`, that will write to the range + /// of 4..16. + pub fn set_push_constants(&mut self, offset: u32, data: &'a [u32]) { + self.id.set_push_constants(offset, data); + } +} + impl<'a> Drop for ComputePass<'a> { fn drop(&mut self) { if !thread::panicking() { @@ -2101,6 +2153,41 @@ impl<'a> RenderBundleEncoder<'a> { } } +/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call these functions. +impl<'a> RenderBundleEncoder<'a> { + /// Set push constant data. + /// + /// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`]. + /// + /// Data size must be a multiple of 4 and must be aligned to the 4s, so we take an array of u32. + /// For example, with an offset of 4 and an array of `[u32; 3]`, that will write to the range + /// of 4..16. + /// + /// For each byte in the range of push constant data written, the union of the stages of all push constant + /// ranges that covers that byte must be exactly `stages`. There's no good way of explaining this simply, + /// so here are some examples: + /// + /// ```text + /// For the given ranges: + /// - 0..4 Vertex + /// - 4..8 Fragment + /// ``` + /// + /// You would need to upload this in two set_push_constants calls. First for the `Vertex` range, second for the `Fragment` range. + /// + /// ```text + /// For the given ranges: + /// - 0..8 Vertex + /// - 4..12 Fragment + /// ``` + /// + /// You would need to upload this in three set_push_constants calls. First for the `Vertex` only range 0..4, second + /// for the `Vertex | Fragment` range 4..8, third for the `Fragment` range 8..12. + pub fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &'a [u32]) { + self.id.set_push_constants(stages, offset, data); + } +} + impl Queue { /// Schedule a data write into `buffer` starting at `offset`. pub fn write_buffer(&self, buffer: &Buffer, offset: BufferAddress, data: &[u8]) {