diff --git a/Cargo.lock b/Cargo.lock index 86e8e96a26..1853eb7894 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,11 +365,37 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "peek-poke" +version = "0.2.0" +source = "git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8#728591c140ead9a6b646a27eaad29e5136fb96b8" +dependencies = [ + "peek-poke-derive 0.2.0 (git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8)", +] + +[[package]] +name = "peek-poke-derive" +version = "0.2.0" +source = "git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8#728591c140ead9a6b646a27eaad29e5136fb96b8" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pkg-config" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "1.0.6" @@ -378,6 +404,14 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "1.0.2" @@ -527,6 +561,16 @@ dependencies = [ "lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "1.0.11" @@ -537,6 +581,11 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -612,6 +661,7 @@ dependencies = [ "gfx-hal 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "peek-poke 0.2.0 (git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8)", "rendy-descriptor 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rendy-memory 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -717,8 +767,12 @@ dependencies = [ "checksum objc_exception 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" "checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum peek-poke 0.2.0 (git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8)" = "" +"checksum peek-poke-derive 0.2.0 (git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8)" = "" "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum range-alloc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5927936723a9e8b715d37d7e4b390455087c4bdf25b9f702309460577b14f9" "checksum raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" @@ -738,7 +792,9 @@ dependencies = [ "checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" "checksum spirv_cross 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbbe441b3ac8ec0ae6a4f05234239bd372a241ce15793eef694e8b24afc267bb" "checksum storage-map 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd0a4829a5c591dc24a944a736d6b1e4053e51339a79fd5d4702c4c999a9c45e" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum wasm-bindgen 0.2.55 (registry+https://github.com/rust-lang/crates.io-index)" = "29ae32af33bacd663a9a28241abecf01f2be64e6a185c6139b04f18b6385c5f2" diff --git a/ffi/wgpu.h b/ffi/wgpu.h index db5553d897..eb00b73212 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -243,6 +243,10 @@ typedef enum { WGPUVertexFormat_Int4 = 48, } WGPUVertexFormat; +typedef struct WGPURawPass WGPURawPass; + +typedef struct WGPURenderCommand WGPURenderCommand; + typedef uint64_t WGPUId_Device_Dummy; typedef WGPUId_Device_Dummy WGPUDeviceId; @@ -698,6 +702,8 @@ WGPUComputePassId wgpu_command_encoder_begin_compute_pass(WGPUCommandEncoderId e WGPURenderPassId wgpu_command_encoder_begin_render_pass(WGPUCommandEncoderId encoder_id, const WGPURenderPassDescriptor *desc); +void wgpu_command_encoder_compute_pass(WGPUCommandEncoderId self_id, const WGPURawPass *pass); + void wgpu_command_encoder_copy_buffer_to_buffer(WGPUCommandEncoderId command_encoder_id, WGPUBufferId source, WGPUBufferAddress source_offset, @@ -725,6 +731,15 @@ void wgpu_command_encoder_destroy(WGPUCommandEncoderId command_encoder_id); WGPUCommandBufferId wgpu_command_encoder_finish(WGPUCommandEncoderId encoder_id, const WGPUCommandBufferDescriptor *desc); +void wgpu_command_encoder_render_pass(WGPUCommandEncoderId self_id, + const WGPURenderPassColorAttachmentDescriptor *color_attachments, + uintptr_t color_attachment_length, + const WGPURenderPassDepthStencilAttachmentDescriptor *depth_stencil_attachment, + const WGPURenderCommand *commands, + uintptr_t command_length, + const WGPUBufferAddress *offsets, + uintptr_t offset_length); + void wgpu_compute_pass_dispatch(WGPUComputePassId pass_id, uint32_t x, uint32_t y, uint32_t z); void wgpu_compute_pass_dispatch_indirect(WGPUComputePassId pass_id, diff --git a/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 7ce6d763b7..637d4f8b0b 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -29,6 +29,7 @@ log = "0.4" hal = { package = "gfx-hal", version = "0.4" } gfx-backend-empty = { version = "0.4" } parking_lot = "0.9" +peek-poke = { git = "https://github.com/djg/peek-poke", rev = "728591c140ead9a6b646a27eaad29e5136fb96b8" } rendy-memory = "0.5" rendy-descriptor = "0.5" serde = { version = "1.0", features = ["serde_derive"], optional = true } diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index d340251482..3d18a46197 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -6,7 +6,7 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, - OffsetIndex, + RawPass, }, device::{all_buffer_stages, BIND_BUFFER_ALIGNMENT}, hub::{GfxBackend, Global, IdentityFilter, Token}, @@ -18,17 +18,17 @@ use crate::{ }; use hal::command::CommandBuffer as _; +use peek_poke::{Peek, PeekCopy, Poke}; -use std::{iter, ops::Range}; +use std::{convert::TryInto, iter, mem, ptr, slice}; -#[non_exhaustive] -#[derive(Debug)] +#[derive(Clone, Copy, Debug, PeekCopy, Poke)] pub enum ComputeCommand { SetBindGroup { index: u32, + num_dynamic_offsets: u8, bind_group_id: id::BindGroupId, - offset_indices: Range, }, SetPipeline(id::ComputePipelineId), Dispatch([u32; 3]), @@ -38,12 +38,6 @@ pub enum ComputeCommand { }, } -#[derive(Copy, Clone, Debug)] -pub struct StandaloneComputePass<'a> { - pub commands: &'a [ComputeCommand], - pub offsets: &'a [BufferAddress], -} - #[repr(C)] #[derive(Clone, Debug, Default)] pub struct ComputePassDescriptor { @@ -96,7 +90,7 @@ impl Global { pub fn command_encoder_run_compute_pass( &self, encoder_id: id::CommandEncoderId, - pass: StandaloneComputePass, + raw_data: &[u8], ) { let hub = B::hub(self); let mut token = Token::root(); @@ -112,10 +106,23 @@ impl Global { let (buffer_guard, mut token) = hub.buffers.read(&mut token); let (texture_guard, _) = hub.textures.read(&mut token); - for command in pass.commands { - match *command { - ComputeCommand::SetBindGroup { index, bind_group_id, ref offset_indices } => { - let offsets = &pass.offsets[offset_indices.start as usize .. offset_indices.end as usize]; + let mut peeker = raw_data.as_ptr(); + let raw_data_end = unsafe { + raw_data.as_ptr().add(raw_data.len()) + }; + let mut command = ComputeCommand::Dispatch([0; 3]); // dummy + while unsafe { peeker.add(mem::size_of::()) } <= raw_data_end { + peeker = unsafe { command.peek_from(peeker) }; + match command { + ComputeCommand::SetBindGroup { index, num_dynamic_offsets, bind_group_id } => { + debug_assert_eq!(peeker.align_offset(mem::align_of::()), 0); + let extra_size = (num_dynamic_offsets as usize) * mem::size_of::(); + let end = unsafe { peeker.add(extra_size) }; + assert!(end <= raw_data_end); + let offsets = unsafe { + slice::from_raw_parts(peeker as *const BufferAddress, num_dynamic_offsets as usize) + }; + peeker = end; if cfg!(debug_assertions) { for off in offsets { assert_eq!( @@ -234,6 +241,8 @@ impl Global { } } } + + assert_eq!(peeker, raw_data_end); } pub fn compute_pass_set_bind_group( @@ -413,3 +422,73 @@ impl Global { } } } + +impl RawPass { + #[inline] + unsafe fn encode(&mut self, command: &ComputeCommand) { + self.ensure_extra_size(mem::size_of::()); + self.data = command.poke_into(self.data); + } + + #[inline] + unsafe fn encode_with(&mut self, command: &ComputeCommand, extra: &[T]) { + let extra_size = extra.len() * mem::size_of::(); + self.ensure_extra_size(mem::size_of::() + extra_size); + self.data = command.poke_into(self.data); + debug_assert_eq!(self.data.align_offset(mem::align_of::()), 0); + ptr::copy_nonoverlapping(extra.as_ptr(), self.data as *mut T, extra.len()); + self.data = self.data.add(extra_size); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_compute_pass_set_bind_group( + &mut self, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const BufferAddress, + offset_length: usize, + ) { + self.encode_with( + &ComputeCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length.try_into().unwrap(), + bind_group_id, + }, + slice::from_raw_parts(offsets, offset_length), + ); + + for offset in slice::from_raw_parts(offsets, offset_length) { + self.data = offset.poke_into(self.data); + } + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_standalone_compute_pass_set_pipeline( + &mut self, + pipeline_id: id::ComputePipelineId, + ) { + self.encode(&ComputeCommand::SetPipeline(pipeline_id)); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_standalone_compute_pass_dispatch( + &mut self, + groups_x: u32, + groups_y: u32, + groups_z: u32, + ) { + self.encode(&ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_standalone_compute_pass_dispatch_indirect( + &mut self, + buffer_id: id::BufferId, + offset: BufferAddress, + ) { + self.encode(&ComputeCommand::DispatchIndirect { + buffer_id, + offset, + }); + } +} diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 7be908a6f1..5833e884c5 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -54,7 +54,45 @@ use std::{ }; -pub type OffsetIndex = u16; +pub struct RawPass { + data: *mut u8, + base: *mut u8, + capacity: usize, +} + +impl RawPass { + pub fn new() -> Self { + let mut vec = Vec::with_capacity(16); + RawPass { + data: vec.as_mut_ptr(), + base: vec.as_mut_ptr(), + capacity: vec.capacity(), + } + } + + pub unsafe fn delete(self) { + let size = self.data as usize - self.base as usize; + let _ = Vec::from_raw_parts(self.base, size, self.capacity); + } + + pub unsafe fn to_slice(&self) -> &[u8] { + let size = self.data as usize - self.base as usize; + assert!(size <= self.capacity); + slice::from_raw_parts(self.base, size) + } + + unsafe fn ensure_extra_size(&mut self, extra_size: usize) { + let size = self.data as usize - self.base as usize; + if let Some(extra_capacity) = (size + extra_size).checked_sub(self.capacity) { + let mut vec = Vec::from_raw_parts(self.base, size, self.capacity); + vec.reserve(extra_capacity); + //let (data, size, capacity) = vec.into_raw_parts(); //TODO: when stable + self.data = vec.as_mut_ptr().add(vec.len()); + self.base = vec.as_mut_ptr(); + self.capacity = vec.capacity(); + } + } +} pub struct RenderBundle { _raw: B::CommandBuffer, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 1dbfc61bea..8b3134ac26 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -6,7 +6,6 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, - OffsetIndex, }, conv, device::{ @@ -38,6 +37,8 @@ use std::{ }; +type OffsetIndex = u16; + #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum LoadOp { diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 4df6fea703..e5d3308809 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -5,7 +5,7 @@ use crate::{Backend, Epoch, Index}; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; -use std::{fmt, marker::PhantomData}; +use std::{fmt, marker::PhantomData, mem}; const BACKEND_BITS: usize = 3; const EPOCH_MASK: u32 = (1 << (32 - BACKEND_BITS)) - 1; @@ -57,6 +57,21 @@ impl PartialEq for Id { } } +unsafe impl peek_poke::Poke for Id { + fn max_size() -> usize { + mem::size_of::() + } + unsafe fn poke_into(&self, data: *mut u8) -> *mut u8 { + self.0.poke_into(data) + } +} + +impl peek_poke::Peek for Id { + unsafe fn peek_from(&mut self, data: *const u8) -> *const u8 { + self.0.peek_from(data) + } +} + pub trait TypedId { fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self; fn unzip(self) -> (Index, Epoch, Backend); diff --git a/wgpu-native/src/command.rs b/wgpu-native/src/command.rs index 79f4a2bd3a..774e3ad285 100644 --- a/wgpu-native/src/command.rs +++ b/wgpu-native/src/command.rs @@ -315,3 +315,32 @@ pub extern "C" fn wgpu_compute_pass_set_pipeline( ) { gfx_select!(pass_id => GLOBAL.compute_pass_set_pipeline(pass_id, pipeline_id)) } + +#[no_mangle] +pub unsafe extern "C" fn wgpu_command_encoder_compute_pass( + self_id: id::CommandEncoderId, + pass: &core::command::RawPass, +) { + let raw_data = pass.to_slice(); + gfx_select!(self_id => GLOBAL.command_encoder_run_compute_pass(self_id, raw_data)); +} + +#[no_mangle] +pub unsafe extern "C" fn wgpu_command_encoder_render_pass( + self_id: id::CommandEncoderId, + color_attachments: *const core::command::RenderPassColorAttachmentDescriptor, + color_attachment_length: usize, + depth_stencil_attachment: Option<&core::command::RenderPassDepthStencilAttachmentDescriptor>, + commands: *const core::command::RenderCommand, + command_length: usize, + offsets: *const core::BufferAddress, + offset_length: usize, +) { + let pass = core::command::StandaloneRenderPass { + color_attachments: slice::from_raw_parts(color_attachments, color_attachment_length), + depth_stencil_attachment, + commands: slice::from_raw_parts(commands, command_length), + offsets: slice::from_raw_parts(offsets, offset_length), + }; + gfx_select!(self_id => GLOBAL.command_encoder_run_render_pass(self_id, pass)); +} diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index f7e8e1412a..a8cc475a09 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -127,16 +127,11 @@ pub extern "C" fn wgpu_server_encoder_destroy( pub unsafe extern "C" fn wgpu_server_encode_compute_pass( global: &Global, self_id: id::CommandEncoderId, - commands: *const core::command::ComputeCommand, - command_length: usize, - offsets: *const core::BufferAddress, - offset_length: usize, + bytes: *const u8, + byte_length: usize, ) { - let pass = core::command::StandaloneComputePass { - commands: slice::from_raw_parts(commands, command_length), - offsets: slice::from_raw_parts(offsets, offset_length), - }; - gfx_select!(self_id => global.command_encoder_run_compute_pass(self_id, pass)); + let raw_data = slice::from_raw_parts(bytes, byte_length); + gfx_select!(self_id => global.command_encoder_run_compute_pass(self_id, raw_data)); } #[no_mangle]