From 5e2d0d768082be83cc578fd23bef95ccbaf42fcf Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 9 Jun 2020 10:47:49 -0400 Subject: [PATCH] [rs] Render bundle support, use in msaa-line example --- wgpu/Cargo.toml | 4 +- wgpu/examples/msaa-line/main.rs | 75 ++++--- wgpu/src/backend/direct.rs | 157 ++++++++++++-- wgpu/src/backend/web.rs | 118 ++++++---- wgpu/src/lib.rs | 372 +++++++++++++++++++++++++------- 5 files changed, 553 insertions(+), 173 deletions(-) diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index d1cb311694..be19cc4106 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 = "64ae59072db443eb1e47ee14d77370eec9f4b012" +rev = "b0b99d89b71894cf01d8c938aae87b2348edeb5b" features = ["raw-window-handle"] [dependencies.wgt] package = "wgpu-types" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "64ae59072db443eb1e47ee14d77370eec9f4b012" +rev = "b0b99d89b71894cf01d8c938aae87b2348edeb5b" [dependencies] arrayvec = "0.5" diff --git a/wgpu/examples/msaa-line/main.rs b/wgpu/examples/msaa-line/main.rs index c33d045c0f..48c9c585a1 100644 --- a/wgpu/examples/msaa-line/main.rs +++ b/wgpu/examples/msaa-line/main.rs @@ -10,6 +10,8 @@ #[path = "../framework.rs"] mod framework; +use std::iter; + use bytemuck::{Pod, Zeroable}; use wgpu::vertex_attr_array; @@ -25,29 +27,31 @@ unsafe impl Pod for Vertex {} unsafe impl Zeroable for Vertex {} struct Example { + bundle: wgpu::RenderBundle, vs_module: wgpu::ShaderModule, fs_module: wgpu::ShaderModule, pipeline_layout: wgpu::PipelineLayout, - pipeline: wgpu::RenderPipeline, multisampled_framebuffer: wgpu::TextureView, vertex_buffer: wgpu::Buffer, vertex_count: u32, - rebuild_pipeline: bool, sample_count: u32, + rebuild_bundle: bool, sc_desc: wgpu::SwapChainDescriptor, } impl Example { - fn create_pipeline( + fn create_bundle( device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor, vs_module: &wgpu::ShaderModule, fs_module: &wgpu::ShaderModule, pipeline_layout: &wgpu::PipelineLayout, sample_count: u32, - ) -> wgpu::RenderPipeline { + vertex_buffer: &wgpu::Buffer, + vertex_count: u32, + ) -> wgpu::RenderBundle { log::info!("sample_count: {}", sample_count); - device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, vertex_stage: wgpu::ProgrammableStageDescriptor { module: vs_module, @@ -83,6 +87,19 @@ impl Example { sample_count, sample_mask: !0, alpha_to_coverage_enabled: false, + }); + let mut encoder = + device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor { + label: None, + color_formats: &[sc_desc.format], + depth_stencil_format: None, + sample_count, + }); + encoder.set_pipeline(&pipeline); + encoder.set_vertex_buffer(0, vertex_buffer.slice(..)); + encoder.draw(0..vertex_count, 0..1); + encoder.finish(&wgpu::RenderBundleDescriptor { + label: Some("main"), }) } @@ -132,14 +149,6 @@ impl framework::Example for Example { bind_group_layouts: &[], }); - let pipeline = Example::create_pipeline( - device, - &sc_desc, - &vs_module, - &fs_module, - &pipeline_layout, - sample_count, - ); let multisampled_framebuffer = Example::create_multisampled_framebuffer(device, sc_desc, sample_count); @@ -165,16 +174,27 @@ impl framework::Example for Example { ); let vertex_count = vertex_data.len() as u32; + let bundle = Example::create_bundle( + device, + &sc_desc, + &vs_module, + &fs_module, + &pipeline_layout, + sample_count, + &vertex_buffer, + vertex_count, + ); + let this = Example { + bundle, vs_module, fs_module, pipeline_layout, - pipeline, multisampled_framebuffer, vertex_buffer, vertex_count, - rebuild_pipeline: false, sample_count, + rebuild_bundle: false, sc_desc: sc_desc.clone(), }; (this, None) @@ -188,13 +208,13 @@ impl framework::Example for Example { Some(winit::event::VirtualKeyCode::Left) => { if self.sample_count >= 2 { self.sample_count = self.sample_count >> 1; - self.rebuild_pipeline = true; + self.rebuild_bundle = true; } } Some(winit::event::VirtualKeyCode::Right) => { if self.sample_count <= 16 { self.sample_count = self.sample_count << 1; - self.rebuild_pipeline = true; + self.rebuild_bundle = true; } } _ => {} @@ -222,18 +242,20 @@ impl framework::Example for Example { device: &wgpu::Device, _queue: &wgpu::Queue, ) -> wgpu::CommandBuffer { - if self.rebuild_pipeline { - self.pipeline = Example::create_pipeline( + if self.rebuild_bundle { + self.bundle = Example::create_bundle( device, &self.sc_desc, &self.vs_module, &self.fs_module, &self.pipeline_layout, self.sample_count, + &self.vertex_buffer, + self.vertex_count, ); self.multisampled_framebuffer = Example::create_multisampled_framebuffer(device, &self.sc_desc, self.sample_count); - self.rebuild_pipeline = false; + self.rebuild_bundle = false; } let mut encoder = @@ -257,13 +279,12 @@ impl framework::Example for Example { } }; - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[rpass_color_attachment], - depth_stencil_attachment: None, - }); - rpass.set_pipeline(&self.pipeline); - rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); - rpass.draw(0..self.vertex_count, 0..1); + encoder + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[rpass_color_attachment], + depth_stencil_attachment: None, + }) + .execute_bundles(iter::once(&self.bundle)); } encoder.finish() diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index d4e0706b37..079bfd626c 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -31,10 +31,11 @@ pub type Context = wgc::hub::Global; mod pass_impl { use super::Context; + use smallvec::SmallVec; use std::ops::Range; - use wgc::command::{compute_ffi::*, render_ffi::*}; + use wgc::command::{bundle_ffi::*, compute_ffi::*, render_ffi::*}; - impl crate::ComputePassInner for wgc::command::RawPass { + impl crate::ComputePassInner for wgc::command::RawPass { fn set_pipeline(&mut self, pipeline: &wgc::id::ComputePipelineId) { unsafe { wgpu_compute_pass_set_pipeline(self, *pipeline) } } @@ -66,7 +67,7 @@ mod pass_impl { } } - impl crate::RenderPassInner for wgc::command::RawPass { + impl crate::RenderInner for wgc::command::RawPass { fn set_pipeline(&mut self, pipeline: &wgc::id::RenderPipelineId) { unsafe { wgpu_render_pass_set_pipeline(self, *pipeline) } } @@ -103,6 +104,48 @@ mod pass_impl { ) { unsafe { wgpu_render_pass_set_vertex_buffer(self, slot, *buffer, offset, size) } } + fn draw(&mut self, vertices: Range, instances: Range) { + unsafe { + wgpu_render_pass_draw( + self, + vertices.end - vertices.start, + instances.end - instances.start, + vertices.start, + instances.start, + ) + } + } + fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range) { + unsafe { + wgpu_render_pass_draw_indexed( + self, + indices.end - indices.start, + instances.end - instances.start, + indices.start, + base_vertex, + instances.start, + ) + } + } + fn draw_indirect( + &mut self, + indirect_buffer: &wgc::id::BufferId, + indirect_offset: wgt::BufferAddress, + ) { + unsafe { wgpu_render_pass_draw_indirect(self, *indirect_buffer, indirect_offset) } + } + fn draw_indexed_indirect( + &mut self, + indirect_buffer: &wgc::id::BufferId, + indirect_offset: wgt::BufferAddress, + ) { + unsafe { + wgpu_render_pass_draw_indexed_indirect(self, *indirect_buffer, indirect_offset) + } + } + } + + impl crate::RenderPassInner for wgc::command::RawPass { fn set_blend_color(&mut self, color: wgt::Color) { unsafe { wgpu_render_pass_set_blend_color(self, &color) } } @@ -125,9 +168,62 @@ mod pass_impl { fn set_stencil_reference(&mut self, reference: u32) { unsafe { wgpu_render_pass_set_stencil_reference(self, reference) } } + + fn execute_bundles<'a, I: Iterator>( + &mut self, + render_bundles: I, + ) { + let temp_render_bundles = render_bundles.cloned().collect::>(); + unsafe { + wgpu_render_pass_execute_bundles( + self, + temp_render_bundles.as_ptr(), + temp_render_bundles.len(), + ) + } + } + } + + impl crate::RenderInner for wgc::command::RenderBundleEncoder { + fn set_pipeline(&mut self, pipeline: &wgc::id::RenderPipelineId) { + unsafe { wgpu_render_bundle_set_pipeline(self, *pipeline) } + } + fn set_bind_group( + &mut self, + index: u32, + bind_group: &wgc::id::BindGroupId, + offsets: &[wgt::DynamicOffset], + ) { + unsafe { + wgpu_render_bundle_set_bind_group( + self, + index, + *bind_group, + offsets.as_ptr(), + offsets.len(), + ) + } + } + fn set_index_buffer( + &mut self, + buffer: &wgc::id::BufferId, + offset: wgt::BufferAddress, + size: wgt::BufferSize, + ) { + unsafe { wgpu_render_bundle_set_index_buffer(self, *buffer, offset, size) } + } + fn set_vertex_buffer( + &mut self, + slot: u32, + buffer: &wgc::id::BufferId, + offset: wgt::BufferAddress, + size: wgt::BufferSize, + ) { + unsafe { wgpu_render_bundle_set_vertex_buffer(self, slot, *buffer, offset, size) } + } fn draw(&mut self, vertices: Range, instances: Range) { unsafe { - wgpu_render_pass_draw( + wgpu_render_bundle_draw( self, vertices.end - vertices.start, instances.end - instances.start, @@ -138,7 +234,7 @@ mod pass_impl { } fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range) { unsafe { - wgpu_render_pass_draw_indexed( + wgpu_render_bundle_draw_indexed( self, indices.end - indices.start, instances.end - instances.start, @@ -153,7 +249,7 @@ mod pass_impl { indirect_buffer: &wgc::id::BufferId, indirect_offset: wgt::BufferAddress, ) { - unsafe { wgpu_render_pass_draw_indirect(self, *indirect_buffer, indirect_offset) } + unsafe { wgpu_render_bundle_draw_indirect(self, *indirect_buffer, indirect_offset) } } fn draw_indexed_indirect( &mut self, @@ -161,7 +257,7 @@ mod pass_impl { indirect_offset: wgt::BufferAddress, ) { unsafe { - wgpu_render_pass_draw_indexed_indirect(self, *indirect_buffer, indirect_offset) + wgpu_render_pass_bundle_indexed_indirect(self, *indirect_buffer, indirect_offset) } } } @@ -197,11 +293,13 @@ impl crate::Context for Context { type RenderPipelineId = wgc::id::RenderPipelineId; type ComputePipelineId = wgc::id::ComputePipelineId; type CommandEncoderId = wgc::id::CommandEncoderId; - type ComputePassId = wgc::command::RawPass; + type ComputePassId = wgc::command::RawPass; + type RenderPassId = wgc::command::RawPass; type CommandBufferId = wgc::id::CommandBufferId; + type RenderBundleEncoderId = wgc::command::RenderBundleEncoder; + type RenderBundleId = wgc::id::RenderBundleId; type SurfaceId = wgc::id::SurfaceId; type SwapChainId = wgc::id::SwapChainId; - type RenderPassId = wgc::command::RawPass; type SwapChainOutputDetail = SwapChainOutputDetail; @@ -518,6 +616,14 @@ impl crate::Context for Context { )) } + fn device_create_render_bundle_encoder( + &self, + device: &Self::DeviceId, + desc: &wgt::RenderBundleEncoderDescriptor, + ) -> Self::RenderBundleEncoderId { + wgc::command::RenderBundleEncoder::new(desc, *device) + } + fn device_drop(&self, device: &Self::DeviceId) { #[cfg(not(target_arch = "wasm32"))] gfx_select!(*device => self.device_poll(*device, true)); @@ -663,6 +769,9 @@ impl crate::Context for Context { fn command_buffer_drop(&self, command_buffer: &Self::CommandBufferId) { gfx_select!(*command_buffer => self.command_buffer_destroy(*command_buffer)) } + fn render_bundle_drop(&self, render_bundle: &Self::RenderBundleId) { + gfx_select!(*render_bundle => self.render_bundle_destroy(*render_bundle)) + } fn compute_pipeline_drop(&self, pipeline: &Self::ComputePipelineId) { gfx_select!(*pipeline => self.compute_pipeline_destroy(*pipeline)) } @@ -670,7 +779,7 @@ impl crate::Context for Context { gfx_select!(*pipeline => self.render_pipeline_destroy(*pipeline)) } - fn encoder_copy_buffer_to_buffer( + fn command_encoder_copy_buffer_to_buffer( &self, encoder: &Self::CommandEncoderId, source: &Self::BufferId, @@ -689,7 +798,7 @@ impl crate::Context for Context { )) } - fn encoder_copy_buffer_to_texture( + fn command_encoder_copy_buffer_to_texture( &self, encoder: &Self::CommandEncoderId, source: crate::BufferCopyView, @@ -704,7 +813,7 @@ impl crate::Context for Context { )) } - fn encoder_copy_texture_to_buffer( + fn command_encoder_copy_texture_to_buffer( &self, encoder: &Self::CommandEncoderId, source: crate::TextureCopyView, @@ -719,7 +828,7 @@ impl crate::Context for Context { )) } - fn encoder_copy_texture_to_texture( + fn command_encoder_copy_texture_to_texture( &self, encoder: &Self::CommandEncoderId, source: crate::TextureCopyView, @@ -734,11 +843,14 @@ impl crate::Context for Context { )) } - fn encoder_begin_compute_pass(&self, encoder: &Self::CommandEncoderId) -> Self::ComputePassId { + fn command_encoder_begin_compute_pass( + &self, + encoder: &Self::CommandEncoderId, + ) -> Self::ComputePassId { unsafe { wgc::command::RawPass::new_compute(*encoder) } } - fn encoder_end_compute_pass( + fn command_encoder_end_compute_pass( &self, encoder: &Self::CommandEncoderId, pass: &mut Self::ComputePassId, @@ -752,7 +864,7 @@ impl crate::Context for Context { unsafe { pass.invalidate() }; } - fn encoder_begin_render_pass<'a>( + fn command_encoder_begin_render_pass<'a>( &self, encoder: &Self::CommandEncoderId, desc: &crate::RenderPassDescriptor<'a, '_>, @@ -795,7 +907,7 @@ impl crate::Context for Context { } } - fn encoder_end_render_pass( + fn command_encoder_end_render_pass( &self, encoder: &Self::CommandEncoderId, pass: &mut Self::RenderPassId, @@ -809,11 +921,20 @@ impl crate::Context for Context { unsafe { pass.invalidate() }; } - fn encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId { + fn command_encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId { let desc = wgt::CommandBufferDescriptor::default(); gfx_select!(*encoder => self.command_encoder_finish(*encoder, &desc)) } + fn render_bundle_encoder_finish( + &self, + encoder: Self::RenderBundleEncoderId, + desc: &crate::RenderBundleDescriptor, + ) -> Self::RenderBundleId { + let owned_label = OwnedLabel::new(desc.label.as_deref()); + gfx_select!(encoder.parent() => self.render_bundle_encoder_finish(encoder, &desc.map_label(|_| owned_label.as_ptr()), PhantomData)) + } + fn queue_write_buffer( &self, queue: &Self::QueueId, diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index d046cbec95..d4a0378dc2 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -84,7 +84,7 @@ impl crate::ComputePassInner for ComputePass { } } -impl crate::RenderPassInner for RenderPass { +impl crate::RenderInner for RenderPass { fn set_pipeline(&mut self, pipeline: &Sendable) { self.0.set_pipeline(&pipeline.0); } @@ -124,28 +124,6 @@ impl crate::RenderPassInner for RenderPass { self.0 .set_vertex_buffer_with_f64_and_f64(slot, &buffer.0, offset as f64, size.0 as f64); } - fn set_blend_color(&mut self, color: wgt::Color) { - self.0 - .set_blend_color_with_gpu_color_dict(&map_color(color)); - } - fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) { - self.0.set_scissor_rect(x, y, width, height); - } - fn set_viewport( - &mut self, - x: f32, - y: f32, - width: f32, - height: f32, - min_depth: f32, - max_depth: f32, - ) { - self.0 - .set_viewport(x, y, width, height, min_depth, max_depth); - } - fn set_stencil_reference(&mut self, reference: u32) { - self.0.set_stencil_reference(reference); - } fn draw(&mut self, vertices: Range, instances: Range) { self.0 .draw_with_instance_count_and_first_vertex_and_first_instance( @@ -183,6 +161,34 @@ impl crate::RenderPassInner for RenderPass { } } +impl crate::RenderPassInner for RenderPass { + fn set_blend_color(&mut self, color: wgt::Color) { + self.0 + .set_blend_color_with_gpu_color_dict(&map_color(color)); + } + fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32) { + self.0.set_scissor_rect(x, y, width, height); + } + fn set_viewport( + &mut self, + x: f32, + y: f32, + width: f32, + height: f32, + min_depth: f32, + max_depth: f32, + ) { + self.0 + .set_viewport(x, y, width, height, min_depth, max_depth); + } + fn set_stencil_reference(&mut self, reference: u32) { + self.0.set_stencil_reference(reference); + } + fn execute_bundles<'a, I: Iterator>(&mut self, render_bundles: I) { + unimplemented!() + } +} + fn map_texture_format(texture_format: wgt::TextureFormat) -> web_sys::GpuTextureFormat { use web_sys::GpuTextureFormat as tf; use wgt::TextureFormat; @@ -615,10 +621,12 @@ impl crate::Context for Context { type ComputePipelineId = Sendable; type CommandEncoderId = web_sys::GpuCommandEncoder; type ComputePassId = ComputePass; + type RenderPassId = RenderPass; type CommandBufferId = Sendable; + type RenderBundleEncoderId = RenderPass; //web_sys::GpuRenderBundleEncoder; + type RenderBundleId = (); //web_sys::GpuRenderBundle; type SurfaceId = Sendable; type SwapChainId = Sendable; - type RenderPassId = RenderPass; type SwapChainOutputDetail = SwapChainOutputDetail; @@ -1027,6 +1035,14 @@ impl crate::Context for Context { .create_command_encoder_with_descriptor(&mapped_desc) } + fn device_create_render_bundle_encoder( + &self, + _device: &Self::DeviceId, + _desc: &wgt::RenderBundleEncoderDescriptor, + ) -> Self::RenderBundleEncoderId { + unimplemented!() + } + fn device_drop(&self, _device: &Self::DeviceId) { // Device is dropped automatically } @@ -1117,40 +1133,43 @@ impl crate::Context for Context { } fn texture_drop(&self, _texture: &Self::TextureId) { - // Buffer is dropped automatically + // Dropped automatically } fn texture_view_drop(&self, _texture_view: &Self::TextureViewId) { - // Buffer is dropped automatically + // Dropped automatically } fn sampler_drop(&self, _sampler: &Self::SamplerId) { - // Buffer is dropped automatically + // Dropped automatically } fn buffer_drop(&self, _buffer: &Self::BufferId) { - // Buffer is dropped automatically + // Dropped automatically } fn bind_group_drop(&self, _bind_group: &Self::BindGroupId) { - // Buffer is dropped automatically + // Dropped automatically } fn bind_group_layout_drop(&self, _bind_group_layout: &Self::BindGroupLayoutId) { - // Buffer is dropped automatically + // Dropped automatically } fn pipeline_layout_drop(&self, _pipeline_layout: &Self::PipelineLayoutId) { - // Buffer is dropped automatically + // Dropped automatically } fn shader_module_drop(&self, _shader_module: &Self::ShaderModuleId) { - // Buffer is dropped automatically + // Dropped automatically } fn command_buffer_drop(&self, _command_buffer: &Self::CommandBufferId) { - // Buffer is dropped automatically + // Dropped automatically + } + fn render_bundle_drop(&self, _render_bundle: &Self::RenderBundleId) { + // Dropped automatically } fn compute_pipeline_drop(&self, _pipeline: &Self::ComputePipelineId) { - // Buffer is dropped automatically + // Dropped automatically } fn render_pipeline_drop(&self, _pipeline: &Self::RenderPipelineId) { - // Buffer is dropped automatically + // Dropped automatically } - fn encoder_copy_buffer_to_buffer( + fn command_encoder_copy_buffer_to_buffer( &self, encoder: &Self::CommandEncoderId, source: &Self::BufferId, @@ -1168,7 +1187,7 @@ impl crate::Context for Context { ) } - fn encoder_copy_buffer_to_texture( + fn command_encoder_copy_buffer_to_texture( &self, encoder: &Self::CommandEncoderId, source: crate::BufferCopyView, @@ -1182,7 +1201,7 @@ impl crate::Context for Context { ) } - fn encoder_copy_texture_to_buffer( + fn command_encoder_copy_texture_to_buffer( &self, encoder: &Self::CommandEncoderId, source: crate::TextureCopyView, @@ -1196,7 +1215,7 @@ impl crate::Context for Context { ) } - fn encoder_copy_texture_to_texture( + fn command_encoder_copy_texture_to_texture( &self, encoder: &Self::CommandEncoderId, source: crate::TextureCopyView, @@ -1210,7 +1229,10 @@ impl crate::Context for Context { ) } - fn encoder_begin_compute_pass(&self, encoder: &Self::CommandEncoderId) -> Self::ComputePassId { + fn command_encoder_begin_compute_pass( + &self, + encoder: &Self::CommandEncoderId, + ) -> Self::ComputePassId { let mut mapped_desc = web_sys::GpuComputePassDescriptor::new(); if let Some(ref label) = encoder.label() { mapped_desc.label(label); @@ -1218,7 +1240,7 @@ impl crate::Context for Context { ComputePass(encoder.begin_compute_pass_with_descriptor(&mapped_desc)) } - fn encoder_end_compute_pass( + fn command_encoder_end_compute_pass( &self, _encoder: &Self::CommandEncoderId, pass: &mut Self::ComputePassId, @@ -1226,7 +1248,7 @@ impl crate::Context for Context { pass.0.end_pass(); } - fn encoder_begin_render_pass<'a>( + fn command_encoder_begin_render_pass<'a>( &self, encoder: &Self::CommandEncoderId, desc: &crate::RenderPassDescriptor<'a, '_>, @@ -1284,7 +1306,7 @@ impl crate::Context for Context { RenderPass(encoder.begin_render_pass(&mapped_desc)) } - fn encoder_end_render_pass( + fn command_encoder_end_render_pass( &self, _encoder: &Self::CommandEncoderId, pass: &mut Self::RenderPassId, @@ -1292,7 +1314,7 @@ impl crate::Context for Context { pass.0.end_pass(); } - fn encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId { + fn command_encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId { let mut mapped_desc = web_sys::GpuCommandBufferDescriptor::new(); if let Some(ref label) = encoder.label() { mapped_desc.label(label); @@ -1300,6 +1322,14 @@ impl crate::Context for Context { Sendable(encoder.finish_with_descriptor(&mapped_desc)) } + fn render_bundle_encoder_finish( + &self, + _encoder: Self::RenderBundleEncoderId, + _desc: &crate::RenderBundleDescriptor, + ) -> Self::RenderBundleId { + unimplemented!() + } + fn queue_write_buffer( &self, _queue: &Self::QueueId, diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index ea4d758101..8623c8b26d 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -24,11 +24,11 @@ pub use wgt::{ 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, + 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; @@ -49,7 +49,7 @@ trait ComputePassInner { ); } -trait RenderPassInner { +trait RenderInner { fn set_pipeline(&mut self, pipeline: &Ctx::RenderPipelineId); fn set_bind_group( &mut self, @@ -65,7 +65,18 @@ trait RenderPassInner { offset: BufferAddress, size: BufferSize, ); - fn set_blend_color(&mut self, color: wgt::Color); + 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); + fn draw_indexed_indirect( + &mut self, + indirect_buffer: &Ctx::BufferId, + indirect_offset: BufferAddress, + ); +} + +trait RenderPassInner: RenderInner { + fn set_blend_color(&mut self, color: Color); fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32); fn set_viewport( &mut self, @@ -77,36 +88,34 @@ trait RenderPassInner { max_depth: f32, ); fn set_stencil_reference(&mut self, reference: 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); - fn draw_indexed_indirect( + fn execute_bundles<'a, I: Iterator>( &mut self, - indirect_buffer: &Ctx::BufferId, - indirect_offset: BufferAddress, + render_bundles: I, ); } trait Context: Sized { - type AdapterId: Send + Sync; - type DeviceId: Send + Sync; - type QueueId: Send + Sync; - type ShaderModuleId: Send + Sync; - type BindGroupLayoutId: Send + Sync; - type BindGroupId: Send + Sync; - type TextureViewId: Send + Sync; - type SamplerId: Send + Sync; - type BufferId: Send + Sync; - type TextureId: Send + Sync; - type PipelineLayoutId: Send + Sync; - type RenderPipelineId: Send + Sync; - type ComputePipelineId: Send + Sync; + type AdapterId: Send + Sync + 'static; + type DeviceId: Send + Sync + 'static; + type QueueId: Send + Sync + 'static; + type ShaderModuleId: Send + Sync + 'static; + type BindGroupLayoutId: Send + Sync + 'static; + type BindGroupId: Send + Sync + 'static; + type TextureViewId: Send + Sync + 'static; + type SamplerId: Send + Sync + 'static; + type BufferId: Send + Sync + 'static; + type TextureId: Send + Sync + 'static; + type PipelineLayoutId: Send + Sync + 'static; + type RenderPipelineId: Send + Sync + 'static; + type ComputePipelineId: Send + Sync + 'static; type CommandEncoderId; type ComputePassId: ComputePassInner; - type CommandBufferId: Send + Sync; - type SurfaceId: Send + Sync; - type SwapChainId: Send + Sync; type RenderPassId: RenderPassInner; + type CommandBufferId: Send + Sync; + type RenderBundleEncoderId: RenderInner; + type RenderBundleId: Send + Sync + 'static; + type SurfaceId: Send + Sync + 'static; + type SwapChainId: Send + Sync + 'static; type SwapChainOutputDetail: Send; @@ -123,8 +132,8 @@ trait Context: Sized { fn instance_request_adapter( &self, options: &RequestAdapterOptions<'_>, - unsafe_extensions: wgt::UnsafeExtensions, - backends: wgt::BackendBit, + unsafe_extensions: UnsafeExtensions, + backends: BackendBit, ) -> Self::RequestAdapterFuture; fn adapter_request_device( &self, @@ -193,6 +202,11 @@ trait Context: Sized { device: &Self::DeviceId, desc: &CommandEncoderDescriptor, ) -> Self::CommandEncoderId; + fn device_create_render_bundle_encoder( + &self, + device: &Self::DeviceId, + desc: &RenderBundleEncoderDescriptor, + ) -> Self::RenderBundleEncoderId; fn device_drop(&self, device: &Self::DeviceId); fn device_poll(&self, device: &Self::DeviceId, maintain: Maintain); @@ -238,10 +252,11 @@ trait Context: Sized { fn pipeline_layout_drop(&self, pipeline_layout: &Self::PipelineLayoutId); fn shader_module_drop(&self, shader_module: &Self::ShaderModuleId); fn command_buffer_drop(&self, command_buffer: &Self::CommandBufferId); + fn render_bundle_drop(&self, render_bundle: &Self::RenderBundleId); fn compute_pipeline_drop(&self, pipeline: &Self::ComputePipelineId); fn render_pipeline_drop(&self, pipeline: &Self::RenderPipelineId); - fn encoder_copy_buffer_to_buffer( + fn command_encoder_copy_buffer_to_buffer( &self, encoder: &Self::CommandEncoderId, source: &Self::BufferId, @@ -250,21 +265,21 @@ trait Context: Sized { destination_offset: BufferAddress, copy_size: BufferAddress, ); - fn encoder_copy_buffer_to_texture( + fn command_encoder_copy_buffer_to_texture( &self, encoder: &Self::CommandEncoderId, source: BufferCopyView, destination: TextureCopyView, copy_size: Extent3d, ); - fn encoder_copy_texture_to_buffer( + fn command_encoder_copy_texture_to_buffer( &self, encoder: &Self::CommandEncoderId, source: TextureCopyView, destination: BufferCopyView, copy_size: Extent3d, ); - fn encoder_copy_texture_to_texture( + fn command_encoder_copy_texture_to_texture( &self, encoder: &Self::CommandEncoderId, source: TextureCopyView, @@ -272,23 +287,31 @@ trait Context: Sized { copy_size: Extent3d, ); - fn encoder_begin_compute_pass(&self, encoder: &Self::CommandEncoderId) -> Self::ComputePassId; - fn encoder_end_compute_pass( + fn command_encoder_begin_compute_pass( + &self, + encoder: &Self::CommandEncoderId, + ) -> Self::ComputePassId; + fn command_encoder_end_compute_pass( &self, encoder: &Self::CommandEncoderId, pass: &mut Self::ComputePassId, ); - fn encoder_begin_render_pass<'a>( + fn command_encoder_begin_render_pass<'a>( &self, encoder: &Self::CommandEncoderId, desc: &RenderPassDescriptor<'a, '_>, ) -> Self::RenderPassId; - fn encoder_end_render_pass( + fn command_encoder_end_render_pass( &self, encoder: &Self::CommandEncoderId, pass: &mut Self::RenderPassId, ); - fn encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId; + fn command_encoder_finish(&self, encoder: &Self::CommandEncoderId) -> Self::CommandBufferId; + fn render_bundle_encoder_finish( + &self, + encoder: Self::RenderBundleEncoderId, + desc: &RenderBundleDescriptor, + ) -> Self::RenderBundleId; fn queue_write_buffer( &self, queue: &Self::QueueId, @@ -301,8 +324,8 @@ trait Context: Sized { queue: &Self::QueueId, texture: TextureCopyView, data: &[u8], - data_layout: wgt::TextureDataLayout, - size: wgt::Extent3d, + data_layout: TextureDataLayout, + size: Extent3d, ); fn queue_submit>( &self, @@ -462,7 +485,9 @@ pub struct Sampler { impl Drop for Sampler { fn drop(&mut self) { - self.context.sampler_drop(&self.id); + if !thread::panicking() { + self.context.sampler_drop(&self.id); + } } } @@ -496,7 +521,9 @@ pub struct BindGroupLayout { impl Drop for BindGroupLayout { fn drop(&mut self) { - self.context.bind_group_layout_drop(&self.id); + if !thread::panicking() { + self.context.bind_group_layout_drop(&self.id); + } } } @@ -513,7 +540,9 @@ pub struct BindGroup { impl Drop for BindGroup { fn drop(&mut self) { - self.context.bind_group_drop(&self.id); + if !thread::panicking() { + self.context.bind_group_drop(&self.id); + } } } @@ -529,7 +558,9 @@ pub struct ShaderModule { impl Drop for ShaderModule { fn drop(&mut self) { - self.context.shader_module_drop(&self.id); + if !thread::panicking() { + self.context.shader_module_drop(&self.id); + } } } @@ -543,7 +574,9 @@ pub struct PipelineLayout { impl Drop for PipelineLayout { fn drop(&mut self) { - self.context.pipeline_layout_drop(&self.id); + if !thread::panicking() { + self.context.pipeline_layout_drop(&self.id); + } } } @@ -558,7 +591,9 @@ pub struct RenderPipeline { impl Drop for RenderPipeline { fn drop(&mut self) { - self.context.render_pipeline_drop(&self.id); + if !thread::panicking() { + self.context.render_pipeline_drop(&self.id); + } } } @@ -570,7 +605,9 @@ pub struct ComputePipeline { impl Drop for ComputePipeline { fn drop(&mut self) { - self.context.compute_pipeline_drop(&self.id); + if !thread::panicking() { + self.context.compute_pipeline_drop(&self.id); + } } } @@ -586,8 +623,10 @@ pub struct CommandBuffer { impl Drop for CommandBuffer { fn drop(&mut self) { - if let Some(ref id) = self.id { - self.context.command_buffer_drop(id); + if !thread::panicking() { + if let Some(ref id) = self.id { + self.context.command_buffer_drop(id); + } } } } @@ -619,6 +658,32 @@ pub struct ComputePass<'a> { parent: &'a mut CommandEncoder, } +/// An object that encodes GPU operations into a render bundle. +/// +/// It only supports a handful of render commands, but it makes them re-usable. +pub struct RenderBundleEncoder<'a> { + context: Arc, + id: ::RenderBundleEncoderId, + _parent: &'a Device, + /// This type should be !Send !Sync, because it represents an allocation on this thread's + /// command buffer. + _p: PhantomData<*const u8>, +} + +/// A finished render bundle. +pub struct RenderBundle { + context: Arc, + id: ::RenderBundleId, +} + +impl Drop for RenderBundle { + fn drop(&mut self) { + if !thread::panicking() { + self.context.render_bundle_drop(&self.id); + } + } +} + /// A handle to a command queue on a device. /// /// A `Queue` executes recorded [`CommandBuffer`] objects. @@ -766,12 +831,10 @@ pub struct RenderPassDescriptor<'a, 'b> { pub type BufferDescriptor<'a> = wgt::BufferDescriptor>; /// A description of a command encoder. -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] -pub struct CommandEncoderDescriptor<'a> { - /// An optional label to apply to the command encoder. - /// This can be useful for debugging and performance analysis. - pub label: Option<&'a str>, -} +pub type CommandEncoderDescriptor<'a> = wgt::CommandEncoderDescriptor>; + +/// A description of a render bundle. +pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor>; /// A description of a texture. pub type TextureDescriptor<'a> = wgt::TextureDescriptor>; @@ -810,7 +873,7 @@ pub struct BufferCopyView<'a> { pub buffer: &'a Buffer, /// The layout of the texture data in this buffer. - pub layout: wgt::TextureDataLayout, + pub layout: TextureDataLayout, } /// A view of a texture which can be used to copy to or from a buffer or another texture. @@ -838,8 +901,8 @@ impl Instance { #[cfg(not(target_arch = "wasm32"))] pub fn enumerate_adapters( &self, - unsafe_extensions: wgt::UnsafeExtensions, - backends: wgt::BackendBit, + unsafe_extensions: UnsafeExtensions, + backends: BackendBit, ) -> impl Iterator { let context = Arc::clone(&self.context); self.context @@ -900,7 +963,7 @@ impl Instance { pub fn request_adapter( &self, options: &RequestAdapterOptions<'_>, - unsafe_extensions: wgt::UnsafeExtensions, + unsafe_extensions: UnsafeExtensions, backends: BackendBit, ) -> impl Future> + Send { let context = Arc::clone(&self.context); @@ -985,6 +1048,19 @@ impl Device { } } + /// Creates an empty [`RenderBundleEncoder`]. + pub fn create_render_bundle_encoder( + &self, + desc: &RenderBundleEncoderDescriptor, + ) -> RenderBundleEncoder { + RenderBundleEncoder { + context: Arc::clone(&self.context), + id: Context::device_create_render_bundle_encoder(&*self.context, &self.id, desc), + _parent: self, + _p: Default::default(), + } + } + /// Creates a new bind group. pub fn create_bind_group(&self, desc: &BindGroupDescriptor) -> BindGroup { BindGroup { @@ -1087,7 +1163,9 @@ impl Device { impl Drop for Device { fn drop(&mut self) { - self.context.device_drop(&self.id); + if !thread::panicking() { + self.context.device_drop(&self.id); + } } } @@ -1283,7 +1361,9 @@ impl BufferSlice<'_> { impl Drop for Buffer { fn drop(&mut self) { - self.context.buffer_drop(&self.id); + if !thread::panicking() { + self.context.buffer_drop(&self.id); + } } } @@ -1309,7 +1389,7 @@ impl Texture { impl Drop for Texture { fn drop(&mut self) { - if self.owned { + if self.owned && !thread::panicking() { self.context.texture_drop(&self.id); } } @@ -1317,7 +1397,7 @@ impl Drop for Texture { impl Drop for TextureView { fn drop(&mut self) { - if self.owned { + if self.owned && !thread::panicking() { self.context.texture_view_drop(&self.id); } } @@ -1328,7 +1408,7 @@ impl CommandEncoder { pub fn finish(self) -> CommandBuffer { CommandBuffer { context: Arc::clone(&self.context), - id: Some(Context::encoder_finish(&*self.context, &self.id)), + id: Some(Context::command_encoder_finish(&*self.context, &self.id)), } } @@ -1340,7 +1420,7 @@ impl CommandEncoder { desc: &RenderPassDescriptor<'a, '_>, ) -> RenderPass<'a> { RenderPass { - id: Context::encoder_begin_render_pass(&*self.context, &self.id, desc), + id: Context::command_encoder_begin_render_pass(&*self.context, &self.id, desc), parent: self, } } @@ -1350,7 +1430,7 @@ impl CommandEncoder { /// This function returns a [`ComputePass`] object which records a single compute pass. pub fn begin_compute_pass(&mut self) -> ComputePass { ComputePass { - id: Context::encoder_begin_compute_pass(&*self.context, &self.id), + id: Context::command_encoder_begin_compute_pass(&*self.context, &self.id), parent: self, } } @@ -1364,7 +1444,7 @@ impl CommandEncoder { destination_offset: BufferAddress, copy_size: BufferAddress, ) { - Context::encoder_copy_buffer_to_buffer( + Context::command_encoder_copy_buffer_to_buffer( &*self.context, &self.id, &source.id, @@ -1382,7 +1462,7 @@ impl CommandEncoder { destination: TextureCopyView, copy_size: Extent3d, ) { - Context::encoder_copy_buffer_to_texture( + Context::command_encoder_copy_buffer_to_texture( &*self.context, &self.id, source, @@ -1398,7 +1478,7 @@ impl CommandEncoder { destination: BufferCopyView, copy_size: Extent3d, ) { - Context::encoder_copy_texture_to_buffer( + Context::command_encoder_copy_texture_to_buffer( &*self.context, &self.id, source, @@ -1414,7 +1494,7 @@ impl CommandEncoder { destination: TextureCopyView, copy_size: Extent3d, ) { - Context::encoder_copy_texture_to_texture( + Context::command_encoder_copy_texture_to_texture( &*self.context, &self.id, source, @@ -1432,14 +1512,14 @@ impl<'a> RenderPass<'a> { bind_group: &'a BindGroup, offsets: &[DynamicOffset], ) { - RenderPassInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets) + RenderInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets) } /// Sets the active render pipeline. /// /// Subsequent draw calls will exhibit the behavior defined by `pipeline`. pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) { - RenderPassInner::set_pipeline(&mut self.id, &pipeline.id) + RenderInner::set_pipeline(&mut self.id, &pipeline.id) } pub fn set_blend_color(&mut self, color: Color) { @@ -1451,7 +1531,7 @@ impl<'a> RenderPass<'a> { /// Subsequent calls to [`draw_indexed`](RenderPass::draw_indexed) on this [`RenderPass`] will /// use `buffer` as the source index buffer. pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>) { - RenderPassInner::set_index_buffer( + RenderInner::set_index_buffer( &mut self.id, &buffer_slice.buffer.id, buffer_slice.offset, @@ -1472,7 +1552,7 @@ impl<'a> RenderPass<'a> { /// [`RenderPass`]: struct.RenderPass.html /// [`RenderPipelineDescriptor::vertex_buffers`]: struct.RenderPipelineDescriptor.html#structfield.vertex_buffers pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) { - RenderPassInner::set_vertex_buffer( + RenderInner::set_vertex_buffer( &mut self.id, slot, &buffer_slice.buffer.id, @@ -1506,7 +1586,7 @@ impl<'a> RenderPass<'a> { /// /// The active vertex buffers can be set with [`RenderPass::set_vertex_buffer`]. pub fn draw(&mut self, vertices: Range, instances: Range) { - RenderPassInner::draw(&mut self.id, vertices, instances) + RenderInner::draw(&mut self.id, vertices, instances) } /// Draws indexed primitives using the active index buffer and the active vertex buffers. @@ -1514,7 +1594,7 @@ impl<'a> RenderPass<'a> { /// The active index buffer can be set with [`RenderPass::set_index_buffer`], while the active /// vertex buffers can be set with [`RenderPass::set_vertex_buffer`]. pub fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range) { - RenderPassInner::draw_indexed(&mut self.id, indices, base_vertex, instances); + RenderInner::draw_indexed(&mut self.id, indices, base_vertex, instances); } /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`. @@ -1562,6 +1642,11 @@ impl<'a> RenderPass<'a> { self.id .draw_indexed_indirect(&indirect_buffer.id, indirect_offset); } + + pub fn execute_bundles>(&mut self, render_bundles: I) { + self.id + .execute_bundles(render_bundles.into_iter().map(|rb| &rb.id)) + } } impl<'a> Drop for RenderPass<'a> { @@ -1569,7 +1654,7 @@ impl<'a> Drop for RenderPass<'a> { if !thread::panicking() { self.parent .context - .encoder_end_render_pass(&self.parent.id, &mut self.id); + .command_encoder_end_render_pass(&self.parent.id, &mut self.id); } } } @@ -1612,9 +1697,132 @@ impl<'a> Drop for ComputePass<'a> { if !thread::panicking() { self.parent .context - .encoder_end_compute_pass(&self.parent.id, &mut self.id); + .command_encoder_end_compute_pass(&self.parent.id, &mut self.id); + } + } +} + +impl<'a> RenderBundleEncoder<'a> { + /// Finishes recording and returns a [`RenderBundle`] that can be executed in other render passes. + pub fn finish(self, desc: &RenderBundleDescriptor) -> RenderBundle { + RenderBundle { + context: Arc::clone(&self.context), + id: Context::render_bundle_encoder_finish(&*self.context, self.id, desc), } } + + /// Sets the active bind group for a given bind group index. + pub fn set_bind_group( + &mut self, + index: u32, + bind_group: &'a BindGroup, + offsets: &[DynamicOffset], + ) { + RenderInner::set_bind_group(&mut self.id, index, &bind_group.id, offsets) + } + + /// Sets the active render pipeline. + /// + /// Subsequent draw calls will exhibit the behavior defined by `pipeline`. + pub fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) { + RenderInner::set_pipeline(&mut self.id, &pipeline.id) + } + + /// Sets the active index buffer. + /// + /// Subsequent calls to [`draw_indexed`](RenderBundleEncoder::draw_indexed) on this [`RenderBundleEncoder`] will + /// use `buffer` as the source index buffer. + pub fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>) { + RenderInner::set_index_buffer( + &mut self.id, + &buffer_slice.buffer.id, + buffer_slice.offset, + buffer_slice.size, + ) + } + + /// Assign a vertex buffer to a slot. + /// + /// Subsequent calls to [`draw`] and [`draw_indexed`] on this + /// [`RenderBundleEncoder`] will use `buffer` as one of the source vertex buffers. + /// + /// The `slot` refers to the index of the matching descriptor in + /// [`RenderPipelineDescriptor::vertex_buffers`]. + /// + /// [`draw`]: #method.draw + /// [`draw_indexed`]: #method.draw_indexed + /// [`RenderBundleEncoder`]: struct.RenderBundleEncoder.html + /// [`RenderPipelineDescriptor::vertex_buffers`]: struct.RenderPipelineDescriptor.html#structfield.vertex_buffers + pub fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) { + RenderInner::set_vertex_buffer( + &mut self.id, + slot, + &buffer_slice.buffer.id, + buffer_slice.offset, + buffer_slice.size, + ) + } + + /// Draws primitives from the active vertex buffer(s). + /// + /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`]. + pub fn draw(&mut self, vertices: Range, instances: Range) { + RenderInner::draw(&mut self.id, vertices, instances) + } + + /// Draws indexed primitives using the active index buffer and the active vertex buffers. + /// + /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active + /// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`]. + pub fn draw_indexed(&mut self, indices: Range, base_vertex: i32, instances: Range) { + RenderInner::draw_indexed(&mut self.id, indices, base_vertex, instances); + } + + /// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`. + /// + /// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`]. + /// + /// The structure expected in `indirect_buffer` is the following: + /// + /// ```rust + /// #[repr(C)] + /// struct DrawIndirect { + /// vertex_count: u32, // The number of vertices to draw. + /// instance_count: u32, // The number of instances to draw. + /// base_vertex: u32, // The Index of the first vertex to draw. + /// base_instance: u32, // The instance ID of the first instance to draw. + /// } + /// ``` + pub fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) { + self.id.draw_indirect(&indirect_buffer.id, indirect_offset); + } + + /// Draws indexed primitives using the active index buffer and the active vertex buffers, + /// based on the contents of the `indirect_buffer`. + /// + /// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active + /// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`]. + /// + /// The structure expected in `indirect_buffer` is the following: + /// + /// ```rust + /// #[repr(C)] + /// struct DrawIndexedIndirect { + /// vertex_count: u32, // The number of vertices to draw. + /// instance_count: u32, // The number of instances to draw. + /// base_index: u32, // The base index within the index buffer. + /// vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer. + /// base_instance: u32, // The instance ID of the first instance to draw. + /// } + /// ``` + pub fn draw_indexed_indirect( + &mut self, + indirect_buffer: &'a Buffer, + indirect_offset: BufferAddress, + ) { + self.id + .draw_indexed_indirect(&indirect_buffer.id, indirect_offset); + } } impl Queue { @@ -1628,8 +1836,8 @@ impl Queue { &self, texture: TextureCopyView, data: &[u8], - data_layout: wgt::TextureDataLayout, - size: wgt::Extent3d, + data_layout: TextureDataLayout, + size: Extent3d, ) { Context::queue_write_texture(&*self.context, &self.id, texture, data, data_layout, size) }