From 7808a4d4cdfb24368e4384dff3837e0dd7dd3e33 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Tue, 7 Jan 2020 17:31:11 -0500 Subject: [PATCH 1/9] Stand-alone compute passes --- wgpu-core/src/command/compute.rs | 195 ++++++++++++++++++++++++++++--- wgpu-core/src/command/mod.rs | 2 + wgpu-core/src/hub.rs | 3 + wgpu-remote/src/lib.rs | 28 +++++ wgpu-remote/src/server.rs | 48 ++++++++ 5 files changed, 262 insertions(+), 14 deletions(-) diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index a4da853735..e7d4d5b12a 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -6,24 +6,48 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, + OffsetIndex, }, device::{all_buffer_stages, BIND_BUFFER_ALIGNMENT}, hub::{GfxBackend, Global, IdentityFilter, Token}, - id::{BindGroupId, BufferId, CommandBufferId, ComputePassId, ComputePipelineId}, + id, resource::BufferUsage, track::TrackerSet, BufferAddress, Stored, }; -use hal::{self, command::CommandBuffer as _}; +use hal::command::CommandBuffer as _; -use std::iter; +use std::{iter, ops::Range}; + + +#[non_exhaustive] +#[derive(Debug)] +pub enum ComputeCommand { + SetBindGroup { + index: u32, + bind_group_id: id::BindGroupId, + offset_indices: Range, + }, + SetPipeline(id::ComputePipelineId), + Dispatch([u32; 3]), + DispatchIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + }, +} + +#[derive(Copy, Clone, Debug)] +pub struct StandaloneComputePass<'a> { + pub commands: &'a [ComputeCommand], + pub offsets: &'a [BufferAddress], +} #[derive(Debug)] pub struct ComputePass { raw: B::CommandBuffer, - cmb_id: Stored, + cmb_id: Stored, binder: Binder, trackers: TrackerSet, } @@ -31,7 +55,7 @@ pub struct ComputePass { impl ComputePass { pub(crate) fn new( raw: B::CommandBuffer, - cmb_id: Stored, + cmb_id: Stored, trackers: TrackerSet, max_bind_groups: u32, ) -> Self { @@ -46,8 +70,8 @@ impl ComputePass { // Common routines between render/compute -impl> Global { - pub fn compute_pass_end_pass(&self, pass_id: ComputePassId) { +impl> Global { + pub fn compute_pass_end_pass(&self, pass_id: id::ComputePassId) { let mut token = Token::root(); let hub = B::hub(self); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); @@ -63,11 +87,154 @@ impl> Global { } impl Global { + pub fn command_encoder_run_compute_pass( + &self, + encoder_id: id::CommandEncoderId, + pass: StandaloneComputePass, + ) { + let hub = B::hub(self); + let mut token = Token::root(); + + let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); + let cmb = &mut cmb_guard[encoder_id]; + let raw = cmb.raw.last_mut().unwrap(); + let mut binder = Binder::new(cmb.features.max_bind_groups); + + let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); + let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); + let (pipeline_guard, mut token) = hub.compute_pipelines.read(&mut token); + 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]; + if cfg!(debug_assertions) { + for off in offsets { + assert_eq!( + *off % BIND_BUFFER_ALIGNMENT, + 0, + "Misaligned dynamic buffer offset: {} does not align with {}", + off, + BIND_BUFFER_ALIGNMENT + ); + } + } + + let bind_group = cmb + .trackers + .bind_groups + .use_extend(&*bind_group_guard, bind_group_id, (), ()) + .unwrap(); + assert_eq!(bind_group.dynamic_count, offsets.len()); + + log::trace!( + "Encoding barriers on binding of {:?} to {:?}", + bind_group_id, + encoder_id + ); + CommandBuffer::insert_barriers( + raw, + &mut cmb.trackers, + &bind_group.used, + &*buffer_guard, + &*texture_guard, + ); + + if let Some((pipeline_layout_id, follow_ups)) = binder + .provide_entry(index as usize, bind_group_id, bind_group, offsets) + { + let bind_groups = iter::once(bind_group.raw.raw()) + .chain(follow_ups.clone().map(|(bg_id, _)| bind_group_guard[bg_id].raw.raw())); + unsafe { + raw.bind_compute_descriptor_sets( + &pipeline_layout_guard[pipeline_layout_id].raw, + index as usize, + bind_groups, + offsets + .iter() + .chain(follow_ups.flat_map(|(_, offsets)| offsets)) + .map(|&off| off as hal::command::DescriptorSetOffset), + ); + } + } + } + ComputeCommand::SetPipeline(pipeline_id) => { + let pipeline = &pipeline_guard[pipeline_id]; + + unsafe { + raw.bind_compute_pipeline(&pipeline.raw); + } + + // Rebind resources + if binder.pipeline_layout_id != Some(pipeline.layout_id) { + let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id]; + binder.pipeline_layout_id = Some(pipeline.layout_id); + binder + .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); + let mut is_compatible = true; + + for (index, (entry, &bgl_id)) in binder + .entries + .iter_mut() + .zip(&pipeline_layout.bind_group_layout_ids) + .enumerate() + { + match entry.expect_layout(bgl_id) { + LayoutChange::Match(bg_id, offsets) if is_compatible => { + let desc_set = bind_group_guard[bg_id].raw.raw(); + unsafe { + raw.bind_compute_descriptor_sets( + &pipeline_layout.raw, + index, + iter::once(desc_set), + offsets.iter().map(|offset| *offset as u32), + ); + } + } + LayoutChange::Match(..) | LayoutChange::Unchanged => {} + LayoutChange::Mismatch => { + is_compatible = false; + } + } + } + } + } + ComputeCommand::Dispatch(groups) => { + unsafe { + raw.dispatch(groups); + } + } + ComputeCommand::DispatchIndirect { buffer_id, offset } => { + let (src_buffer, src_pending) = cmb.trackers.buffers.use_replace( + &*buffer_guard, + buffer_id, + (), + BufferUsage::INDIRECT, + ); + assert!(src_buffer.usage.contains(BufferUsage::INDIRECT)); + + let barriers = src_pending.map(|pending| pending.into_hal(src_buffer)); + + unsafe { + raw.pipeline_barrier( + all_buffer_stages() .. all_buffer_stages(), + hal::memory::Dependencies::empty(), + barriers, + ); + raw.dispatch_indirect(&src_buffer.raw, offset); + } + } + } + } + } + pub fn compute_pass_set_bind_group( &self, - pass_id: ComputePassId, + pass_id: id::ComputePassId, index: u32, - bind_group_id: BindGroupId, + bind_group_id: id::BindGroupId, offsets: &[BufferAddress], ) { let hub = B::hub(self); @@ -140,7 +307,7 @@ impl Global { pub fn compute_pass_dispatch( &self, - pass_id: ComputePassId, + pass_id: id::ComputePassId, x: u32, y: u32, z: u32, @@ -155,8 +322,8 @@ impl Global { pub fn compute_pass_dispatch_indirect( &self, - pass_id: ComputePassId, - indirect_buffer_id: BufferId, + pass_id: id::ComputePassId, + indirect_buffer_id: id::BufferId, indirect_offset: BufferAddress, ) { let hub = B::hub(self); @@ -188,8 +355,8 @@ impl Global { pub fn compute_pass_set_pipeline( &self, - pass_id: ComputePassId, - pipeline_id: ComputePipelineId, + pass_id: id::ComputePassId, + pipeline_id: id::ComputePipelineId, ) { let hub = B::hub(self); let mut token = Token::root(); diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 9eaeabbdd4..1d55b37845 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -55,6 +55,8 @@ use std::{ }; +pub type OffsetIndex = u16; + pub struct RenderBundle { _raw: B::CommandBuffer, } diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index d27a43b9df..fef312e920 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -170,6 +170,7 @@ impl Access> for Adapter {} impl Access> for Device {} impl Access> for Root {} impl Access> for Device {} +impl Access> for CommandBuffer {} impl Access> for Root {} impl Access> for Device {} impl Access> for Root {} @@ -187,8 +188,10 @@ impl Access> for Root {} impl Access> for BindGroup {} impl Access> for CommandBuffer {} impl Access> for Root {} +impl Access> for BindGroup {} impl Access> for ComputePass {} impl Access> for Root {} +impl Access> for BindGroup {} impl Access> for RenderPass {} impl Access> for Root {} impl Access> for PipelineLayout {} diff --git a/wgpu-remote/src/lib.rs b/wgpu-remote/src/lib.rs index 38a62f4975..310c09f99d 100644 --- a/wgpu-remote/src/lib.rs +++ b/wgpu-remote/src/lib.rs @@ -20,6 +20,7 @@ struct IdentityHub { adapters: IdentityManager, devices: IdentityManager, buffers: IdentityManager, + command_buffers: IdentityManager, } #[derive(Debug, Default)] @@ -153,3 +154,30 @@ pub extern "C" fn wgpu_client_kill_buffer_id(client: &Client, id: id::BufferId) .buffers .free(id) } + +#[no_mangle] +pub extern "C" fn wgpu_client_make_encoder_id( + client: &Client, + device_id: id::DeviceId, +) -> id::CommandEncoderId { + let backend = device_id.backend(); + client + .identities + .lock() + .select(backend) + .command_buffers + .alloc(backend) +} + +#[no_mangle] +pub extern "C" fn wgpu_client_kill_encoder_id( + client: &Client, + id: id::CommandEncoderId, +) { + client + .identities + .lock() + .select(id.backend()) + .command_buffers + .free(id) +} diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index e19c47d642..3a4e5e4775 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -101,3 +101,51 @@ pub extern "C" fn wgpu_server_device_get_buffer_sub_data( pub extern "C" fn wgpu_server_buffer_destroy(global: &Global, self_id: id::BufferId) { gfx_select!(self_id => global.buffer_destroy(self_id)); } + +#[no_mangle] +pub extern "C" fn wgpu_server_device_create_encoder( + global: &Global, + self_id: id::DeviceId, + encoder_id: id::CommandEncoderId, +) { + let desc = core::command::CommandEncoderDescriptor { + todo: 0, + }; + gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, encoder_id)); +} + +#[no_mangle] +pub extern "C" fn wgpu_server_encoder_destroy( + _global: &Global, + _self_id: id::CommandEncoderId, +) { + //TODO + //gfx_select!(self_id => global.command_encoder_destroy(self_id)); +} + +#[no_mangle] +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, +) { + 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)); +} + +#[no_mangle] +pub unsafe extern "C" fn wgpu_server_queue_submit( + global: &Global, + self_id: id::QueueId, + command_buffer_ids: *const id::CommandBufferId, + command_buffer_id_length: usize, +) { + let command_buffers = slice::from_raw_parts(command_buffer_ids, command_buffer_id_length); + gfx_select!(self_id => global.queue_submit(self_id, command_buffers)); +} From 20cd803d67011084e87533a16be3a1b2aaec30cd Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 8 Jan 2020 00:31:47 -0500 Subject: [PATCH 2/9] Standalone render passes --- ffi/wgpu.h | 10 +- wgpu-core/src/command/compute.rs | 6 + wgpu-core/src/command/mod.rs | 62 +- wgpu-core/src/command/render.rs | 997 ++++++++++++++++++++++++++++++- wgpu-remote/src/server.rs | 21 + 5 files changed, 1010 insertions(+), 86 deletions(-) diff --git a/ffi/wgpu.h b/ffi/wgpu.h index c8a0cfce53..db5553d897 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -319,7 +319,9 @@ typedef struct { WGPULoadOp load_op; WGPUStoreOp store_op; WGPUColor clear_color; -} WGPURenderPassColorAttachmentDescriptor; +} WGPURenderPassColorAttachmentDescriptorBase_TextureViewId; + +typedef WGPURenderPassColorAttachmentDescriptorBase_TextureViewId WGPURenderPassColorAttachmentDescriptor; typedef struct { WGPUTextureViewId attachment; @@ -329,12 +331,14 @@ typedef struct { WGPULoadOp stencil_load_op; WGPUStoreOp stencil_store_op; uint32_t clear_stencil; -} WGPURenderPassDepthStencilAttachmentDescriptor_TextureViewId; +} WGPURenderPassDepthStencilAttachmentDescriptorBase_TextureViewId; + +typedef WGPURenderPassDepthStencilAttachmentDescriptorBase_TextureViewId WGPURenderPassDepthStencilAttachmentDescriptor; typedef struct { const WGPURenderPassColorAttachmentDescriptor *color_attachments; uintptr_t color_attachments_length; - const WGPURenderPassDepthStencilAttachmentDescriptor_TextureViewId *depth_stencil_attachment; + const WGPURenderPassDepthStencilAttachmentDescriptor *depth_stencil_attachment; } WGPURenderPassDescriptor; typedef struct { diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index e7d4d5b12a..d340251482 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -44,6 +44,12 @@ pub struct StandaloneComputePass<'a> { pub offsets: &'a [BufferAddress], } +#[repr(C)] +#[derive(Clone, Debug, Default)] +pub struct ComputePassDescriptor { + pub todo: u32, +} + #[derive(Debug)] pub struct ComputePass { raw: B::CommandBuffer, diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 1d55b37845..7be908a6f1 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -35,7 +35,6 @@ use crate::{ }, resource::{Buffer, Texture, TextureUsage, TextureViewInner}, track::TrackerSet, - Color, Features, LifeGuard, Stored, @@ -61,56 +60,6 @@ pub struct RenderBundle { _raw: B::CommandBuffer, } -#[repr(C)] -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub enum LoadOp { - Clear = 0, - Load = 1, -} - -#[repr(C)] -#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] -pub enum StoreOp { - Clear = 0, - Store = 1, -} - -#[repr(C)] -#[derive(Debug)] -pub struct RenderPassColorAttachmentDescriptor { - pub attachment: TextureViewId, - pub resolve_target: *const TextureViewId, - pub load_op: LoadOp, - pub store_op: StoreOp, - pub clear_color: Color, -} - -#[repr(C)] -#[derive(Debug)] -pub struct RenderPassDepthStencilAttachmentDescriptor { - pub attachment: T, - pub depth_load_op: LoadOp, - pub depth_store_op: StoreOp, - pub clear_depth: f32, - pub stencil_load_op: LoadOp, - pub stencil_store_op: StoreOp, - pub clear_stencil: u32, -} - -#[repr(C)] -#[derive(Debug)] -pub struct RenderPassDescriptor { - pub color_attachments: *const RenderPassColorAttachmentDescriptor, - pub color_attachments_length: usize, - pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor, -} - -#[repr(C)] -#[derive(Clone, Debug, Default)] -pub struct ComputePassDescriptor { - pub todo: u32, -} - #[derive(Debug)] pub struct CommandBuffer { pub(crate) raw: Vec, @@ -377,7 +326,7 @@ impl> Global { for &resolve_target in color_attachments .iter() - .flat_map(|at| unsafe { at.resolve_target.as_ref() }) + .flat_map(|at| at.resolve_target) { let view = &view_guard[resolve_target]; assert_eq!(extent, Some(view.extent)); @@ -485,10 +434,10 @@ impl> Global { let mut attachment_index = color_attachments.len(); if color_attachments .iter() - .any(|at| !at.resolve_target.is_null()) + .any(|at| at.resolve_target.is_some()) { for (i, at) in color_attachments.iter().enumerate() { - if at.resolve_target.is_null() { + if at.resolve_target.is_none() { resolve_ids.push(( hal::pass::ATTACHMENT_UNUSED, hal::image::Layout::ColorAttachmentOptimal, @@ -534,7 +483,8 @@ impl> Global { colors: color_attachments.iter().map(|at| at.attachment).collect(), resolves: color_attachments .iter() - .filter_map(|at| unsafe { at.resolve_target.as_ref() }.cloned()) + .filter_map(|at| at.resolve_target) + .cloned() .collect(), depth_stencil: depth_stencil_attachment.map(|at| at.attachment), }; @@ -665,7 +615,7 @@ impl> Global { .collect(), resolves: color_attachments .iter() - .filter_map(|at| unsafe { at.resolve_target.as_ref() }) + .filter_map(|at| at.resolve_target) .map(|resolve| view_guard[*resolve].format) .collect(), depth_stencil: depth_stencil_attachment.map(|at| view_guard[at.attachment].format), diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 3ca9004ae1..1dbfc61bea 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -6,22 +6,149 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, + OffsetIndex, }, conv, - device::{RenderPassContext, BIND_BUFFER_ALIGNMENT, MAX_VERTEX_BUFFERS}, + device::{ + FramebufferKey, + RenderPassContext, + RenderPassKey, + BIND_BUFFER_ALIGNMENT, + MAX_VERTEX_BUFFERS, + }, hub::{GfxBackend, Global, IdentityFilter, Token}, - id::{BindGroupId, BufferId, CommandBufferId, RenderPassId, RenderPipelineId}, + id, pipeline::{IndexFormat, InputStepMode, PipelineFlags}, - resource::BufferUsage, + resource::{BufferUsage, TextureUsage, TextureViewInner}, track::TrackerSet, BufferAddress, Color, Stored, }; +use arrayvec::ArrayVec; use hal::command::CommandBuffer as _; -use std::{iter, ops::Range}; +use std::{ + borrow::Borrow, + collections::hash_map::Entry, + iter, + marker::PhantomData, + ops::Range, +}; + + +#[repr(C)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum LoadOp { + Clear = 0, + Load = 1, +} + +#[repr(C)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] +pub enum StoreOp { + Clear = 0, + Store = 1, +} + +#[repr(C)] +#[derive(Debug)] +pub struct RenderPassColorAttachmentDescriptorBase<'a, T> { + pub attachment: id::TextureViewId, + pub resolve_target: Option<&'a T>, + pub load_op: LoadOp, + pub store_op: StoreOp, + pub clear_color: Color, +} + +#[repr(C)] +#[derive(Debug)] +pub struct RenderPassDepthStencilAttachmentDescriptorBase { + pub attachment: T, + pub depth_load_op: LoadOp, + pub depth_store_op: StoreOp, + pub clear_depth: f32, + pub stencil_load_op: LoadOp, + pub stencil_store_op: StoreOp, + pub clear_stencil: u32, +} + +pub type RenderPassDepthStencilAttachmentDescriptor = RenderPassDepthStencilAttachmentDescriptorBase; +pub type RenderPassColorAttachmentDescriptor<'a> = RenderPassColorAttachmentDescriptorBase<'a, id::TextureViewId>; + +#[repr(C)] +#[derive(Debug)] +pub struct RenderPassDescriptor<'a> { + pub color_attachments: *const RenderPassColorAttachmentDescriptor<'a>, + pub color_attachments_length: usize, + pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor, +} + +#[derive(Debug)] +pub struct Rect { + pub x: T, + pub y: T, + pub w: T, + pub h: T, +} + +#[non_exhaustive] +#[derive(Debug)] +pub enum RenderCommand { + SetBindGroup { + index: u32, + bind_group_id: id::BindGroupId, + offset_indices: Range, + }, + SetPipeline(id::RenderPipelineId), + SetIndexBuffer { + buffer_id: id::BufferId, + offset: BufferAddress, + }, + SetVertexBuffer { + index: u8, + buffer_id: id::BufferId, + offset: BufferAddress, + }, + SetBlendValue(Color), + SetStencilReference(u32), + SetViewport { + rect: Rect, + //TODO: use half-float to reduce the size? + depth: Range, + }, + SetScissor(Rect), + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + DrawIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + }, + DrawIndexedIndirect { + buffer_id: id::BufferId, + offset: BufferAddress, + }, +} + +#[derive(Copy, Clone, Debug)] +pub struct StandaloneRenderPass<'a> { + pub color_attachments: &'a [RenderPassColorAttachmentDescriptor<'a>], + pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachmentDescriptor>, + pub commands: &'a [RenderCommand], + pub offsets: &'a [BufferAddress], +} #[derive(Debug, PartialEq)] enum OptionalState { @@ -51,7 +178,7 @@ enum DrawError { #[derive(Debug)] pub struct IndexState { - bound_buffer_view: Option<(BufferId, Range)>, + bound_buffer_view: Option<(id::BufferId, Range)>, format: IndexFormat, limit: u32, } @@ -110,10 +237,39 @@ impl VertexState { } } +#[derive(Debug)] +struct State { + binder: Binder, + blend_color: OptionalState, + stencil_reference: OptionalState, + index: IndexState, + vertex: VertexState, +} + +impl State { + fn is_ready(&self) -> Result<(), DrawError> { + //TODO: vertex buffers + let bind_mask = self.binder.invalid_mask(); + if bind_mask != 0 { + //let (expected, provided) = self.binder.entries[index as usize].info(); + return Err(DrawError::IncompatibleBindGroup { + index: bind_mask.trailing_zeros() as u32, + }); + } + if self.blend_color == OptionalState::Required { + return Err(DrawError::MissingBlendColor); + } + if self.stencil_reference == OptionalState::Required { + return Err(DrawError::MissingStencilReference); + } + Ok(()) + } +} + #[derive(Debug)] pub struct RenderPass { raw: B::CommandBuffer, - cmb_id: Stored, + cmb_id: Stored, context: RenderPassContext, binder: Binder, trackers: TrackerSet, @@ -127,7 +283,7 @@ pub struct RenderPass { impl RenderPass { pub(crate) fn new( raw: B::CommandBuffer, - cmb_id: Stored, + cmb_id: Stored, context: RenderPassContext, trackers: TrackerSet, sample_count: u8, @@ -176,8 +332,8 @@ impl RenderPass { // Common routines between render/compute -impl> Global { - pub fn render_pass_end_pass(&self, pass_id: RenderPassId) { +impl> Global { + pub fn render_pass_end_pass(&self, pass_id: id::RenderPassId) { let hub = B::hub(self); let mut token = Token::root(); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); @@ -216,12 +372,795 @@ impl> Global { cmb.raw.push(pass.raw); } +} + +impl Global { + pub fn command_encoder_run_render_pass( + &self, + encoder_id: id::CommandEncoderId, + pass: StandaloneRenderPass, + ) { + let hub = B::hub(self); + let mut token = Token::root(); + + let (adapter_guard, mut token) = hub.adapters.read(&mut token); + let (device_guard, mut token) = hub.devices.read(&mut token); + let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); + let cmb = &mut cmb_guard[encoder_id]; + let raw = cmb.raw.last_mut().unwrap(); + let mut trackers = TrackerSet::new(B::VARIANT); + + let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); + let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); + let (pipeline_guard, mut token) = hub.render_pipelines.read(&mut token); + let (buffer_guard, mut token) = hub.buffers.read(&mut token); + let (texture_guard, mut token) = hub.textures.read(&mut token); + let (view_guard, _) = hub.texture_views.read(&mut token); + + let (context, sample_count) = { + use hal::{adapter::PhysicalDevice as _, device::Device as _}; + + let device = &device_guard[cmb.device_id.value]; + + let limits = adapter_guard[device.adapter_id] + .raw + .physical_device + .limits(); + let samples_count_limit = limits.framebuffer_color_sample_counts; + + let mut extent = None; + let mut used_swap_chain_image = None::>; + + let sample_count = pass.color_attachments + .get(0) + .map(|at| view_guard[at.attachment].samples) + .unwrap_or(1); + assert!( + sample_count & samples_count_limit != 0, + "Attachment sample_count must be supported by physical device limits" + ); + + const MAX_TOTAL_ATTACHMENTS: usize = 10; + type OutputAttachment<'a> = ( + &'a Stored, + &'a hal::image::SubresourceRange, + Option, + ); + let mut output_attachments = ArrayVec::<[OutputAttachment; MAX_TOTAL_ATTACHMENTS]>::new(); + + log::trace!( + "Encoding render pass begin in command buffer {:?}", + encoder_id + ); + let rp_key = { + let depth_stencil = match pass.depth_stencil_attachment { + Some(at) => { + let view = cmb.trackers + .views + .use_extend(&*view_guard, at.attachment, (), ()) + .unwrap(); + if let Some(ex) = extent { + assert_eq!(ex, view.extent); + } else { + extent = Some(view.extent); + } + let source_id = match view.inner { + TextureViewInner::Native { ref source_id, .. } => source_id, + TextureViewInner::SwapChain { .. } => { + panic!("Unexpected depth/stencil use of swapchain image!") + } + }; + + // Using render pass for transition. + let consistent_usage = cmb.trackers.textures.query( + source_id.value, + view.range.clone(), + ); + output_attachments.push((source_id, &view.range, consistent_usage)); + + let old_layout = match consistent_usage { + Some(usage) => conv::map_texture_state( + usage, + hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL, + ).1, + None => hal::image::Layout::DepthStencilAttachmentOptimal, + }; + + Some(hal::pass::Attachment { + format: Some(conv::map_texture_format(view.format, device.features)), + samples: view.samples, + ops: conv::map_load_store_ops(at.depth_load_op, at.depth_store_op), + stencil_ops: conv::map_load_store_ops( + at.stencil_load_op, + at.stencil_store_op, + ), + layouts: old_layout .. hal::image::Layout::DepthStencilAttachmentOptimal, + }) + } + None => None, + }; + + let mut colors = ArrayVec::new(); + let mut resolves = ArrayVec::new(); + + for at in pass.color_attachments { + let view = &view_guard[at.attachment]; + if let Some(ex) = extent { + assert_eq!(ex, view.extent); + } else { + extent = Some(view.extent); + } + assert_eq!( + view.samples, sample_count, + "All attachments must have the same sample_count" + ); + let first_use = cmb.trackers.views.init( + at.attachment, + view.life_guard.add_ref(), + PhantomData, + ).is_ok(); + + let layouts = match view.inner { + TextureViewInner::Native { ref source_id, .. } => { + let consistent_usage = cmb.trackers.textures.query( + source_id.value, + view.range.clone(), + ); + output_attachments.push((source_id, &view.range, consistent_usage)); + + let old_layout = match consistent_usage { + Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1, + None => hal::image::Layout::ColorAttachmentOptimal, + }; + old_layout .. hal::image::Layout::ColorAttachmentOptimal + } + TextureViewInner::SwapChain { .. } => { + if let Some((ref view_id, _)) = cmb.used_swap_chain { + assert_eq!(view_id.value, at.attachment); + } else { + assert!(used_swap_chain_image.is_none()); + used_swap_chain_image = Some(Stored { + value: at.attachment, + ref_count: view.life_guard.add_ref(), + }); + } + + let end = hal::image::Layout::Present; + let start = if first_use { + hal::image::Layout::Undefined + } else { + end + }; + start .. end + } + }; + + colors.push(hal::pass::Attachment { + format: Some(conv::map_texture_format(view.format, device.features)), + samples: view.samples, + ops: conv::map_load_store_ops(at.load_op, at.store_op), + stencil_ops: hal::pass::AttachmentOps::DONT_CARE, + layouts, + }); + } + + for &resolve_target in pass.color_attachments + .iter() + .flat_map(|at| at.resolve_target) + { + let view = &view_guard[resolve_target]; + assert_eq!(extent, Some(view.extent)); + assert_eq!( + view.samples, 1, + "All resolve_targets must have a sample_count of 1" + ); + let first_use = cmb.trackers.views.init( + resolve_target, + view.life_guard.add_ref(), + PhantomData, + ).is_ok(); + + let layouts = match view.inner { + TextureViewInner::Native { ref source_id, .. } => { + let consistent_usage = cmb.trackers.textures.query( + source_id.value, + view.range.clone(), + ); + output_attachments.push((source_id, &view.range, consistent_usage)); + + let old_layout = match consistent_usage { + Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1, + None => hal::image::Layout::ColorAttachmentOptimal, + }; + old_layout .. hal::image::Layout::ColorAttachmentOptimal + } + TextureViewInner::SwapChain { .. } => { + if let Some((ref view_id, _)) = cmb.used_swap_chain { + assert_eq!(view_id.value, resolve_target); + } else { + assert!(used_swap_chain_image.is_none()); + used_swap_chain_image = Some(Stored { + value: resolve_target, + ref_count: view.life_guard.add_ref(), + }); + } + + let end = hal::image::Layout::Present; + let start = if first_use { + hal::image::Layout::Undefined + } else { + end + }; + start .. end + } + }; + + resolves.push(hal::pass::Attachment { + format: Some(conv::map_texture_format(view.format, device.features)), + samples: view.samples, + ops: hal::pass::AttachmentOps::new( + hal::pass::AttachmentLoadOp::DontCare, + hal::pass::AttachmentStoreOp::Store, + ), + stencil_ops: hal::pass::AttachmentOps::DONT_CARE, + layouts, + }); + } + + RenderPassKey { + colors, + resolves, + depth_stencil, + } + }; + + for (source_id, view_range, consistent_usage) in output_attachments { + let texture = &texture_guard[source_id.value]; + assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT)); + + let usage = consistent_usage.unwrap_or(TextureUsage::OUTPUT_ATTACHMENT); + // this is important to record the `first` state. + let _ = trackers.textures.change_replace( + source_id.value, + &source_id.ref_count, + view_range.clone(), + usage, + ); + if consistent_usage.is_some() { + // If we expect the texture to be transited to a new state by the + // render pass configuration, make the tracker aware of that. + let _ = trackers.textures.change_replace( + source_id.value, + &source_id.ref_count, + view_range.clone(), + TextureUsage::OUTPUT_ATTACHMENT, + ); + }; + } + + let mut render_pass_cache = device.render_passes.lock(); + let render_pass = match render_pass_cache.entry(rp_key.clone()) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + let color_ids = [ + (0, hal::image::Layout::ColorAttachmentOptimal), + (1, hal::image::Layout::ColorAttachmentOptimal), + (2, hal::image::Layout::ColorAttachmentOptimal), + (3, hal::image::Layout::ColorAttachmentOptimal), + ]; + + let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new(); + let mut attachment_index = pass.color_attachments.len(); + if pass.color_attachments + .iter() + .any(|at| at.resolve_target.is_some()) + { + for (i, at) in pass.color_attachments.iter().enumerate() { + if at.resolve_target.is_none() { + resolve_ids.push(( + hal::pass::ATTACHMENT_UNUSED, + hal::image::Layout::ColorAttachmentOptimal, + )); + } else { + let sample_count_check = + view_guard[pass.color_attachments[i].attachment].samples; + assert!(sample_count_check > 1, "RenderPassColorAttachmentDescriptor with a resolve_target must have an attachment with sample_count > 1"); + resolve_ids.push(( + attachment_index, + hal::image::Layout::ColorAttachmentOptimal, + )); + attachment_index += 1; + } + } + } + + let depth_id = ( + attachment_index, + hal::image::Layout::DepthStencilAttachmentOptimal, + ); + + let subpass = hal::pass::SubpassDesc { + colors: &color_ids[.. pass.color_attachments.len()], + resolves: &resolve_ids, + depth_stencil: pass.depth_stencil_attachment.map(|_| &depth_id), + inputs: &[], + preserves: &[], + }; + + let pass = unsafe { + device + .raw + .create_render_pass(e.key().all(), &[subpass], &[]) + } + .unwrap(); + e.insert(pass) + } + }; + + let mut framebuffer_cache; + let fb_key = FramebufferKey { + colors: pass.color_attachments.iter().map(|at| at.attachment).collect(), + resolves: pass.color_attachments + .iter() + .filter_map(|at| at.resolve_target) + .cloned() + .collect(), + depth_stencil: pass.depth_stencil_attachment.map(|at| at.attachment), + }; + + let framebuffer = match used_swap_chain_image.take() { + Some(view_id) => { + assert!(cmb.used_swap_chain.is_none()); + // Always create a new framebuffer and delete it after presentation. + let attachments = fb_key.all().map(|&id| match view_guard[id].inner { + TextureViewInner::Native { ref raw, .. } => raw, + TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image), + }); + let framebuffer = unsafe { + device + .raw + .create_framebuffer(&render_pass, attachments, extent.unwrap()) + .unwrap() + }; + cmb.used_swap_chain = Some((view_id, framebuffer)); + &mut cmb.used_swap_chain.as_mut().unwrap().1 + } + None => { + // Cache framebuffers by the device. + framebuffer_cache = device.framebuffers.lock(); + match framebuffer_cache.entry(fb_key) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + let fb = { + let attachments = + e.key().all().map(|&id| match view_guard[id].inner { + TextureViewInner::Native { ref raw, .. } => raw, + TextureViewInner::SwapChain { ref image, .. } => { + Borrow::borrow(image) + } + }); + unsafe { + device.raw.create_framebuffer( + &render_pass, + attachments, + extent.unwrap(), + ) + } + .unwrap() + }; + e.insert(fb) + } + } + } + }; + + let rect = { + let ex = extent.unwrap(); + hal::pso::Rect { + x: 0, + y: 0, + w: ex.width as _, + h: ex.height as _, + } + }; + + let clear_values = pass.color_attachments + .iter() + .zip(&rp_key.colors) + .flat_map(|(at, key)| { + match at.load_op { + LoadOp::Load => None, + LoadOp::Clear => { + use hal::format::ChannelType; + //TODO: validate sign/unsign and normalized ranges of the color values + let value = match key.format.unwrap().base_format().1 { + ChannelType::Unorm + | ChannelType::Snorm + | ChannelType::Ufloat + | ChannelType::Sfloat + | ChannelType::Uscaled + | ChannelType::Sscaled + | ChannelType::Srgb => hal::command::ClearColor { + float32: conv::map_color_f32(&at.clear_color), + }, + ChannelType::Sint => hal::command::ClearColor { + sint32: conv::map_color_i32(&at.clear_color), + }, + ChannelType::Uint => hal::command::ClearColor { + uint32: conv::map_color_u32(&at.clear_color), + }, + }; + Some(hal::command::ClearValue { color: value }) + } + } + }) + .chain(pass.depth_stencil_attachment.and_then(|at| { + match (at.depth_load_op, at.stencil_load_op) { + (LoadOp::Load, LoadOp::Load) => None, + (LoadOp::Clear, _) | (_, LoadOp::Clear) => { + let value = hal::command::ClearDepthStencil { + depth: at.clear_depth, + stencil: at.clear_stencil, + }; + Some(hal::command::ClearValue { + depth_stencil: value, + }) + } + } + })); + + unsafe { + raw.begin_render_pass( + render_pass, + framebuffer, + rect, + clear_values, + hal::command::SubpassContents::Inline, + ); + raw.set_scissors(0, iter::once(&rect)); + raw.set_viewports( + 0, + iter::once(hal::pso::Viewport { + rect, + depth: 0.0 .. 1.0, + }), + ); + } + + let context = RenderPassContext { + colors: pass.color_attachments + .iter() + .map(|at| view_guard[at.attachment].format) + .collect(), + resolves: pass.color_attachments + .iter() + .filter_map(|at| at.resolve_target) + .map(|resolve| view_guard[*resolve].format) + .collect(), + depth_stencil: pass.depth_stencil_attachment.map(|at| view_guard[at.attachment].format), + }; + (context, sample_count) + }; + + let mut state = State { + binder: Binder::new(cmb.features.max_bind_groups), + blend_color: OptionalState::Unused, + stencil_reference: OptionalState::Unused, + index: IndexState { + bound_buffer_view: None, + format: IndexFormat::Uint16, + limit: 0, + }, + vertex: VertexState { + inputs: [VertexBufferState::EMPTY; MAX_VERTEX_BUFFERS], + vertex_limit: 0, + instance_limit: 0, + }, + }; + + for command in pass.commands { + match *command { + RenderCommand::SetBindGroup { index, bind_group_id, ref offset_indices } => { + let offsets = &pass.offsets[offset_indices.start as usize .. offset_indices.end as usize]; + if cfg!(debug_assertions) { + for off in offsets { + assert_eq!( + *off % BIND_BUFFER_ALIGNMENT, + 0, + "Misaligned dynamic buffer offset: {} does not align with {}", + off, + BIND_BUFFER_ALIGNMENT + ); + } + } + + let bind_group = trackers + .bind_groups + .use_extend(&*bind_group_guard, bind_group_id, (), ()) + .unwrap(); + assert_eq!(bind_group.dynamic_count, offsets.len()); + + trackers.merge_extend(&bind_group.used); + + if let Some((pipeline_layout_id, follow_ups)) = state.binder + .provide_entry(index as usize, bind_group_id, bind_group, offsets) + { + let bind_groups = iter::once(bind_group.raw.raw()) + .chain(follow_ups.clone().map(|(bg_id, _)| bind_group_guard[bg_id].raw.raw())); + unsafe { + raw.bind_graphics_descriptor_sets( + &&pipeline_layout_guard[pipeline_layout_id].raw, + index as usize, + bind_groups, + offsets + .iter() + .chain(follow_ups.flat_map(|(_, offsets)| offsets)) + .map(|&off| off as hal::command::DescriptorSetOffset), + ); + } + }; + } + RenderCommand::SetPipeline(pipeline_id) => { + let pipeline = &pipeline_guard[pipeline_id]; + + assert!( + context.compatible(&pipeline.pass_context), + "The render pipeline is not compatible with the pass!" + ); + assert_eq!( + pipeline.sample_count, sample_count, + "The render pipeline and renderpass have mismatching sample_count" + ); + + state.blend_color + .require(pipeline.flags.contains(PipelineFlags::BLEND_COLOR)); + state.stencil_reference + .require(pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE)); + + unsafe { + raw.bind_graphics_pipeline(&pipeline.raw); + } + + // Rebind resource + if state.binder.pipeline_layout_id != Some(pipeline.layout_id) { + let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id]; + state.binder.pipeline_layout_id = Some(pipeline.layout_id); + state.binder + .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); + let mut is_compatible = true; + + for (index, (entry, &bgl_id)) in state + .binder + .entries + .iter_mut() + .zip(&pipeline_layout.bind_group_layout_ids) + .enumerate() + { + match entry.expect_layout(bgl_id) { + LayoutChange::Match(bg_id, offsets) if is_compatible => { + let desc_set = bind_group_guard[bg_id].raw.raw(); + unsafe { + raw.bind_graphics_descriptor_sets( + &pipeline_layout.raw, + index, + iter::once(desc_set), + offsets.iter().map(|offset| *offset as u32), + ); + } + } + LayoutChange::Match(..) | LayoutChange::Unchanged => {} + LayoutChange::Mismatch => { + is_compatible = false; + } + } + } + } + + // Rebind index buffer if the index format has changed with the pipeline switch + if state.index.format != pipeline.index_format { + state.index.format = pipeline.index_format; + state.index.update_limit(); + + if let Some((buffer_id, ref range)) = state.index.bound_buffer_view { + let buffer = trackers + .buffers + .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX) + .unwrap(); + + let view = hal::buffer::IndexBufferView { + buffer: &buffer.raw, + offset: range.start, + index_type: conv::map_index_format(state.index.format), + }; + + unsafe { + raw.bind_index_buffer(view); + } + } + } + // Update vertex buffer limits + for (vbs, &(stride, rate)) in state + .vertex + .inputs + .iter_mut() + .zip(&pipeline.vertex_strides) + { + vbs.stride = stride; + vbs.rate = rate; + } + for vbs in state.vertex.inputs[pipeline.vertex_strides.len() ..].iter_mut() { + vbs.stride = 0; + vbs.rate = InputStepMode::Vertex; + } + state.vertex.update_limits(); + } + RenderCommand::SetIndexBuffer { buffer_id, offset } => { + let buffer = trackers + .buffers + .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX) + .unwrap(); + assert!(buffer.usage.contains(BufferUsage::INDEX)); + + let range = offset .. buffer.size; + state.index.bound_buffer_view = Some((buffer_id, range)); + state.index.update_limit(); + + let view = hal::buffer::IndexBufferView { + buffer: &buffer.raw, + offset, + index_type: conv::map_index_format(state.index.format), + }; + + unsafe { + raw.bind_index_buffer(view); + } + } + RenderCommand::SetVertexBuffer { index, buffer_id, offset } => { + let buffer = trackers + .buffers + .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::VERTEX) + .unwrap(); + assert!(buffer.usage.contains(BufferUsage::VERTEX)); + + state.vertex.inputs[index as usize].total_size = buffer.size - offset; + state.vertex.update_limits(); + + unsafe { + raw.bind_vertex_buffers( + index as u32, + iter::once((&buffer.raw, offset)), + ); + } + } + RenderCommand::SetBlendValue(ref color) => { + state.blend_color = OptionalState::Set; + unsafe { + raw.set_blend_constants(conv::map_color_f32(color)); + } + } + RenderCommand::SetStencilReference(value) => { + state.stencil_reference = OptionalState::Set; + unsafe { + raw.set_stencil_reference(hal::pso::Face::all(), value); + } + } + RenderCommand::SetViewport { ref rect, ref depth } => { + use std::{convert::TryFrom, i16}; + let r = hal::pso::Rect { + x: i16::try_from(rect.x.round() as i64).unwrap_or(0), + y: i16::try_from(rect.y.round() as i64).unwrap_or(0), + w: i16::try_from(rect.w.round() as i64).unwrap_or(i16::MAX), + h: i16::try_from(rect.h.round() as i64).unwrap_or(i16::MAX), + }; + unsafe { + raw.set_viewports( + 0, + iter::once(hal::pso::Viewport { + rect: r, + depth: depth.clone(), + }), + ); + } + } + RenderCommand::SetScissor(ref rect) => { + use std::{convert::TryFrom, i16}; + let r = hal::pso::Rect { + x: i16::try_from(rect.x).unwrap_or(0), + y: i16::try_from(rect.y).unwrap_or(0), + w: i16::try_from(rect.w).unwrap_or(i16::MAX), + h: i16::try_from(rect.h).unwrap_or(i16::MAX), + }; + unsafe { + raw.set_scissors( + 0, + iter::once(r), + ); + } + } + RenderCommand::Draw { vertex_count, instance_count, first_vertex, first_instance } => { + state.is_ready().unwrap(); + assert!( + first_vertex + vertex_count <= state.vertex.vertex_limit, + "Vertex out of range!" + ); + assert!( + first_instance + instance_count <= state.vertex.instance_limit, + "Instance out of range!" + ); + + unsafe { + raw.draw( + first_vertex .. first_vertex + vertex_count, + first_instance .. first_instance + instance_count, + ); + } + } + RenderCommand::DrawIndexed { index_count, instance_count, first_index, base_vertex, first_instance } => { + state.is_ready().unwrap(); + + //TODO: validate that base_vertex + max_index() is within the provided range + assert!( + first_index + index_count <= state.index.limit, + "Index out of range!" + ); + assert!( + first_instance + instance_count <= state.vertex.instance_limit, + "Instance out of range!" + ); + + unsafe { + raw.draw_indexed( + first_index .. first_index + index_count, + base_vertex, + first_instance .. first_instance + instance_count, + ); + } + } + RenderCommand::DrawIndirect { buffer_id, offset } => { + state.is_ready().unwrap(); + + let buffer = trackers + .buffers + .use_extend( + &*buffer_guard, + buffer_id, + (), + BufferUsage::INDIRECT, + ) + .unwrap(); + assert!(buffer.usage.contains(BufferUsage::INDIRECT)); + + unsafe { + raw.draw_indirect(&buffer.raw, offset, 1, 0); + } + } + RenderCommand::DrawIndexedIndirect { buffer_id, offset } => { + state.is_ready().unwrap(); + + let buffer = trackers + .buffers + .use_extend( + &*buffer_guard, + buffer_id, + (), + BufferUsage::INDIRECT, + ) + .unwrap(); + assert!(buffer.usage.contains(BufferUsage::INDIRECT)); + + unsafe { + raw.draw_indexed_indirect(&buffer.raw, offset, 1, 0); + } + } + } + } + } pub fn render_pass_set_bind_group( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, index: u32, - bind_group_id: BindGroupId, + bind_group_id: id::BindGroupId, offsets: &[BufferAddress], ) { let hub = B::hub(self); @@ -278,8 +1217,8 @@ impl> Global { pub fn render_pass_set_index_buffer( &self, - pass_id: RenderPassId, - buffer_id: BufferId, + pass_id: id::RenderPassId, + buffer_id: id::BufferId, offset: BufferAddress, ) { let hub = B::hub(self); @@ -312,9 +1251,9 @@ impl> Global { pub fn render_pass_set_vertex_buffers( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, start_slot: u32, - buffers: &[BufferId], + buffers: &[id::BufferId], offsets: &[BufferAddress], ) { let hub = B::hub(self); @@ -353,7 +1292,7 @@ impl> Global { pub fn render_pass_draw( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, vertex_count: u32, instance_count: u32, first_vertex: u32, @@ -384,8 +1323,8 @@ impl> Global { pub fn render_pass_draw_indirect( &self, - pass_id: RenderPassId, - indirect_buffer_id: BufferId, + pass_id: id::RenderPassId, + indirect_buffer_id: id::BufferId, indirect_offset: BufferAddress, ) { let hub = B::hub(self); @@ -414,7 +1353,7 @@ impl> Global { pub fn render_pass_draw_indexed( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, index_count: u32, instance_count: u32, first_index: u32, @@ -448,8 +1387,8 @@ impl> Global { pub fn render_pass_draw_indexed_indirect( &self, - pass_id: RenderPassId, - indirect_buffer_id: BufferId, + pass_id: id::RenderPassId, + indirect_buffer_id: id::BufferId, indirect_offset: BufferAddress, ) { let hub = B::hub(self); @@ -479,8 +1418,8 @@ impl> Global { pub fn render_pass_set_pipeline( &self, - pass_id: RenderPassId, - pipeline_id: RenderPipelineId, + pass_id: id::RenderPassId, + pipeline_id: id::RenderPipelineId, ) { let hub = B::hub(self); let mut token = Token::root(); @@ -585,7 +1524,11 @@ impl> Global { pass.vertex_state.update_limits(); } - pub fn render_pass_set_blend_color(&self, pass_id: RenderPassId, color: &Color) { + pub fn render_pass_set_blend_color( + &self, + pass_id: id::RenderPassId, + color: &Color, + ) { let hub = B::hub(self); let mut token = Token::root(); let (mut pass_guard, _) = hub.render_passes.write(&mut token); @@ -600,7 +1543,7 @@ impl> Global { pub fn render_pass_set_stencil_reference( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, value: u32, ) { let hub = B::hub(self); @@ -617,7 +1560,7 @@ impl> Global { pub fn render_pass_set_viewport( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, x: f32, y: f32, w: f32, @@ -651,7 +1594,7 @@ impl> Global { pub fn render_pass_set_scissor_rect( &self, - pass_id: RenderPassId, + pass_id: id::RenderPassId, x: u32, y: u32, w: u32, diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index 3a4e5e4775..f7e8e1412a 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -139,6 +139,27 @@ pub unsafe extern "C" fn wgpu_server_encode_compute_pass( gfx_select!(self_id => global.command_encoder_run_compute_pass(self_id, pass)); } +#[no_mangle] +pub unsafe extern "C" fn wgpu_server_encode_render_pass( + global: &Global, + 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)); +} + #[no_mangle] pub unsafe extern "C" fn wgpu_server_queue_submit( global: &Global, From c01a7c6abe670c2410218a2934bb5ca3dc2ad1ca Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Wed, 8 Jan 2020 14:26:51 -0500 Subject: [PATCH 3/9] Use peek-poke for compute pass encoding --- Cargo.lock | 56 ++++++++++++++++ ffi/wgpu.h | 15 +++++ wgpu-core/Cargo.toml | 1 + wgpu-core/src/command/compute.rs | 111 ++++++++++++++++++++++++++----- wgpu-core/src/command/mod.rs | 40 ++++++++++- wgpu-core/src/command/render.rs | 3 +- wgpu-core/src/id.rs | 17 ++++- wgpu-native/src/command.rs | 29 ++++++++ wgpu-remote/src/server.rs | 13 ++-- 9 files changed, 257 insertions(+), 28 deletions(-) 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] From 941fcca08d3b038059f2f7d59b0806864054eec8 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 9 Jan 2020 21:34:31 -0500 Subject: [PATCH 4/9] Raw render pass encoding --- ffi/wgpu.h | 7 +- wgpu-core/src/command/compute.rs | 48 ++---- wgpu-core/src/command/mod.rs | 57 +++++++ wgpu-core/src/command/render.rs | 279 ++++++++++++++++++++++++------- wgpu-core/src/lib.rs | 3 +- wgpu-native/src/command.rs | 15 +- wgpu-remote/src/server.rs | 14 +- 7 files changed, 302 insertions(+), 121 deletions(-) diff --git a/ffi/wgpu.h b/ffi/wgpu.h index eb00b73212..e6a8666be4 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -245,8 +245,6 @@ typedef enum { typedef struct WGPURawPass WGPURawPass; -typedef struct WGPURenderCommand WGPURenderCommand; - typedef uint64_t WGPUId_Device_Dummy; typedef WGPUId_Device_Dummy WGPUDeviceId; @@ -735,10 +733,7 @@ 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); + const WGPURawPass *pass); void wgpu_compute_pass_dispatch(WGPUComputePassId pass_id, uint32_t x, uint32_t y, uint32_t z); diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 3d18a46197..73d37d8dad 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -6,6 +6,7 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, + PhantomSlice, RawPass, }, device::{all_buffer_stages, BIND_BUFFER_ALIGNMENT}, @@ -20,15 +21,16 @@ use crate::{ use hal::command::CommandBuffer as _; use peek_poke::{Peek, PeekCopy, Poke}; -use std::{convert::TryInto, iter, mem, ptr, slice}; +use std::{convert::TryInto, iter, mem, slice}; #[derive(Clone, Copy, Debug, PeekCopy, Poke)] -pub enum ComputeCommand { +enum ComputeCommand { SetBindGroup { index: u32, num_dynamic_offsets: u8, bind_group_id: id::BindGroupId, + phantom_offsets: PhantomSlice, }, SetPipeline(id::ComputePipelineId), Dispatch([u32; 3]), @@ -114,15 +116,12 @@ impl Global { 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) + ComputeCommand::SetBindGroup { index, num_dynamic_offsets, bind_group_id, phantom_offsets } => { + let (new_peeker, offsets) = unsafe { + phantom_offsets.decode(peeker, num_dynamic_offsets as usize, raw_data_end) }; - peeker = end; + peeker = new_peeker; + if cfg!(debug_assertions) { for off in offsets { assert_eq!( @@ -424,22 +423,6 @@ 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, @@ -448,22 +431,19 @@ impl RawPass { offsets: *const BufferAddress, offset_length: usize, ) { - self.encode_with( + self.encode_with1( &ComputeCommand::SetBindGroup { index, num_dynamic_offsets: offset_length.try_into().unwrap(), bind_group_id, + phantom_offsets: PhantomSlice::new(), }, 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( + pub unsafe extern "C" fn wgpu_raw_compute_pass_set_pipeline( &mut self, pipeline_id: id::ComputePipelineId, ) { @@ -471,7 +451,7 @@ impl RawPass { } #[no_mangle] - pub unsafe extern "C" fn wgpu_standalone_compute_pass_dispatch( + pub unsafe extern "C" fn wgpu_raw_compute_pass_dispatch( &mut self, groups_x: u32, groups_y: u32, @@ -481,7 +461,7 @@ impl RawPass { } #[no_mangle] - pub unsafe extern "C" fn wgpu_standalone_compute_pass_dispatch_indirect( + pub unsafe extern "C" fn wgpu_raw_compute_pass_dispatch_indirect( &mut self, buffer_id: id::BufferId, offset: BufferAddress, diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 5833e884c5..6817357736 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -49,11 +49,31 @@ use std::{ iter, marker::PhantomData, mem, + ptr, slice, thread::ThreadId, }; +#[derive(Clone, Copy, Debug, peek_poke::PeekCopy, peek_poke::Poke)] +struct PhantomSlice(PhantomData); + +impl PhantomSlice { + fn new() -> Self { + PhantomSlice(PhantomData) + } + + unsafe fn decode<'a>( + self, pointer: *const u8, count: usize, bound: *const u8 + ) -> (*const u8, &'a [T]) { + debug_assert_eq!(pointer.align_offset(mem::align_of::()), 0); + let extra_size = count * mem::size_of::(); + let end = pointer.add(extra_size); + assert!(end <= bound); + (end, slice::from_raw_parts(pointer as *const T, count)) + } +} + pub struct RawPass { data: *mut u8, base: *mut u8, @@ -92,6 +112,43 @@ impl RawPass { self.capacity = vec.capacity(); } } + + #[inline] + unsafe fn encode(&mut self, command: &C) { + self.ensure_extra_size(mem::size_of::()); + self.data = command.poke_into(self.data); + } + + #[inline] + unsafe fn encode_with1( + &mut self, command: &C, 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); + } + + #[inline] + unsafe fn encode_with2( + &mut self, command: &C, extra1: &[T], extra2: &[V] + ) { + let extra1_size = extra1.len() * mem::size_of::(); + let extra2_size = extra2.len() * mem::size_of::(); + self.ensure_extra_size(mem::size_of::() + extra1_size + extra2_size); + self.data = command.poke_into(self.data); + + debug_assert_eq!(self.data.align_offset(mem::align_of::()), 0); + ptr::copy_nonoverlapping(extra1.as_ptr(), self.data as *mut T, extra1.len()); + self.data = self.data.add(extra1_size); + + debug_assert_eq!(self.data.align_offset(mem::align_of::()), 0); + ptr::copy_nonoverlapping(extra2.as_ptr(), self.data as *mut V, extra2.len()); + self.data = self.data.add(extra2_size); + } } pub struct RenderBundle { diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 8b3134ac26..e813d2f391 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -6,6 +6,8 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, CommandBuffer, + PhantomSlice, + RawPass, }, conv, device::{ @@ -27,18 +29,20 @@ use crate::{ use arrayvec::ArrayVec; use hal::command::CommandBuffer as _; +use peek_poke::{Peek, PeekCopy, Poke}; use std::{ borrow::Borrow, collections::hash_map::Entry, + convert::TryInto, iter, marker::PhantomData, + mem, ops::Range, + slice, }; -type OffsetIndex = u16; - #[repr(C)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)] pub enum LoadOp { @@ -86,7 +90,7 @@ pub struct RenderPassDescriptor<'a> { pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor, } -#[derive(Debug)] +#[derive(Clone, Copy, Debug, PeekCopy, Poke)] pub struct Rect { pub x: T, pub y: T, @@ -94,30 +98,32 @@ pub struct Rect { pub h: T, } -#[non_exhaustive] -#[derive(Debug)] -pub enum RenderCommand { +#[derive(Clone, Copy, Debug, PeekCopy, Poke)] +enum RenderCommand { SetBindGroup { index: u32, + num_dynamic_offsets: u8, bind_group_id: id::BindGroupId, - offset_indices: Range, + phantom_offsets: PhantomSlice, }, SetPipeline(id::RenderPipelineId), SetIndexBuffer { buffer_id: id::BufferId, offset: BufferAddress, }, - SetVertexBuffer { - index: u8, - buffer_id: id::BufferId, - offset: BufferAddress, + SetVertexBuffers { + start_index: u8, + count: u8, + phantom_buffer_ids: PhantomSlice, + phantom_offsets: PhantomSlice, }, - SetBlendValue(Color), + SetBlendColor(Color), SetStencilReference(u32), SetViewport { rect: Rect, //TODO: use half-float to reduce the size? - depth: Range, + depth_min: f32, + depth_max: f32, }, SetScissor(Rect), Draw { @@ -143,14 +149,6 @@ pub enum RenderCommand { }, } -#[derive(Copy, Clone, Debug)] -pub struct StandaloneRenderPass<'a> { - pub color_attachments: &'a [RenderPassColorAttachmentDescriptor<'a>], - pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachmentDescriptor>, - pub commands: &'a [RenderCommand], - pub offsets: &'a [BufferAddress], -} - #[derive(Debug, PartialEq)] enum OptionalState { Unused, @@ -379,7 +377,9 @@ impl Global { pub fn command_encoder_run_render_pass( &self, encoder_id: id::CommandEncoderId, - pass: StandaloneRenderPass, + color_attachments: &[RenderPassColorAttachmentDescriptor], + depth_stencil_attachment: Option<&RenderPassDepthStencilAttachmentDescriptor>, + raw_data: &[u8], ) { let hub = B::hub(self); let mut token = Token::root(); @@ -412,7 +412,7 @@ impl Global { let mut extent = None; let mut used_swap_chain_image = None::>; - let sample_count = pass.color_attachments + let sample_count = color_attachments .get(0) .map(|at| view_guard[at.attachment].samples) .unwrap_or(1); @@ -434,7 +434,7 @@ impl Global { encoder_id ); let rp_key = { - let depth_stencil = match pass.depth_stencil_attachment { + let depth_stencil = match depth_stencil_attachment { Some(at) => { let view = cmb.trackers .views @@ -484,7 +484,7 @@ impl Global { let mut colors = ArrayVec::new(); let mut resolves = ArrayVec::new(); - for at in pass.color_attachments { + for at in color_attachments { let view = &view_guard[at.attachment]; if let Some(ex) = extent { assert_eq!(ex, view.extent); @@ -545,7 +545,7 @@ impl Global { }); } - for &resolve_target in pass.color_attachments + for &resolve_target in color_attachments .iter() .flat_map(|at| at.resolve_target) { @@ -651,12 +651,12 @@ impl Global { ]; let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new(); - let mut attachment_index = pass.color_attachments.len(); - if pass.color_attachments + let mut attachment_index = color_attachments.len(); + if color_attachments .iter() .any(|at| at.resolve_target.is_some()) { - for (i, at) in pass.color_attachments.iter().enumerate() { + for (i, at) in color_attachments.iter().enumerate() { if at.resolve_target.is_none() { resolve_ids.push(( hal::pass::ATTACHMENT_UNUSED, @@ -664,7 +664,7 @@ impl Global { )); } else { let sample_count_check = - view_guard[pass.color_attachments[i].attachment].samples; + view_guard[color_attachments[i].attachment].samples; assert!(sample_count_check > 1, "RenderPassColorAttachmentDescriptor with a resolve_target must have an attachment with sample_count > 1"); resolve_ids.push(( attachment_index, @@ -681,9 +681,9 @@ impl Global { ); let subpass = hal::pass::SubpassDesc { - colors: &color_ids[.. pass.color_attachments.len()], + colors: &color_ids[.. color_attachments.len()], resolves: &resolve_ids, - depth_stencil: pass.depth_stencil_attachment.map(|_| &depth_id), + depth_stencil: depth_stencil_attachment.map(|_| &depth_id), inputs: &[], preserves: &[], }; @@ -700,13 +700,13 @@ impl Global { let mut framebuffer_cache; let fb_key = FramebufferKey { - colors: pass.color_attachments.iter().map(|at| at.attachment).collect(), - resolves: pass.color_attachments + colors: color_attachments.iter().map(|at| at.attachment).collect(), + resolves: color_attachments .iter() .filter_map(|at| at.resolve_target) .cloned() .collect(), - depth_stencil: pass.depth_stencil_attachment.map(|at| at.attachment), + depth_stencil: depth_stencil_attachment.map(|at| at.attachment), }; let framebuffer = match used_swap_chain_image.take() { @@ -765,7 +765,7 @@ impl Global { } }; - let clear_values = pass.color_attachments + let clear_values = color_attachments .iter() .zip(&rp_key.colors) .flat_map(|(at, key)| { @@ -795,7 +795,7 @@ impl Global { } } }) - .chain(pass.depth_stencil_attachment.and_then(|at| { + .chain(depth_stencil_attachment.and_then(|at| { match (at.depth_load_op, at.stencil_load_op) { (LoadOp::Load, LoadOp::Load) => None, (LoadOp::Clear, _) | (_, LoadOp::Clear) => { @@ -829,16 +829,16 @@ impl Global { } let context = RenderPassContext { - colors: pass.color_attachments + colors: color_attachments .iter() .map(|at| view_guard[at.attachment].format) .collect(), - resolves: pass.color_attachments + resolves: color_attachments .iter() .filter_map(|at| at.resolve_target) .map(|resolve| view_guard[*resolve].format) .collect(), - depth_stencil: pass.depth_stencil_attachment.map(|at| view_guard[at.attachment].format), + depth_stencil: depth_stencil_attachment.map(|at| view_guard[at.attachment].format), }; (context, sample_count) }; @@ -859,10 +859,25 @@ impl Global { }, }; - for command in pass.commands { - match *command { - RenderCommand::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 = RenderCommand::Draw { + vertex_count: 0, + instance_count: 0, + first_vertex: 0, + first_instance: 0, + }; + while unsafe { peeker.add(mem::size_of::()) } <= raw_data_end { + peeker = unsafe { command.peek_from(peeker) }; + match command { + RenderCommand::SetBindGroup { index, num_dynamic_offsets, bind_group_id, phantom_offsets } => { + let (new_peeker, offsets) = unsafe { + phantom_offsets.decode(peeker, num_dynamic_offsets as usize, raw_data_end) + }; + peeker = new_peeker; + if cfg!(debug_assertions) { for off in offsets { assert_eq!( @@ -1016,24 +1031,35 @@ impl Global { raw.bind_index_buffer(view); } } - RenderCommand::SetVertexBuffer { index, buffer_id, offset } => { - let buffer = trackers - .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::VERTEX) - .unwrap(); - assert!(buffer.usage.contains(BufferUsage::VERTEX)); + RenderCommand::SetVertexBuffers { start_index, count, phantom_buffer_ids, phantom_offsets } => { + let (new_peeker, buffer_ids) = unsafe { + phantom_buffer_ids.decode(peeker, count as usize, raw_data_end) + }; + let (new_peeker, offsets) = unsafe { + phantom_offsets.decode(new_peeker, count as usize, raw_data_end) + }; + peeker = new_peeker; - state.vertex.inputs[index as usize].total_size = buffer.size - offset; - state.vertex.update_limits(); + let pairs = state.vertex.inputs[start_index as usize ..] + .iter_mut() + .zip(buffer_ids.iter().zip(offsets)) + .map(|(vbs, (&id, &offset))| { + let buffer = trackers + .buffers + .use_extend(&*buffer_guard, id, (), BufferUsage::VERTEX) + .unwrap(); + assert!(buffer.usage.contains(BufferUsage::VERTEX)); + + vbs.total_size = buffer.size - offset; + (&buffer.raw, offset) + }); unsafe { - raw.bind_vertex_buffers( - index as u32, - iter::once((&buffer.raw, offset)), - ); + raw.bind_vertex_buffers(start_index as u32, pairs); } + state.vertex.update_limits(); } - RenderCommand::SetBlendValue(ref color) => { + RenderCommand::SetBlendColor(ref color) => { state.blend_color = OptionalState::Set; unsafe { raw.set_blend_constants(conv::map_color_f32(color)); @@ -1045,7 +1071,7 @@ impl Global { raw.set_stencil_reference(hal::pso::Face::all(), value); } } - RenderCommand::SetViewport { ref rect, ref depth } => { + RenderCommand::SetViewport { ref rect, depth_min, depth_max } => { use std::{convert::TryFrom, i16}; let r = hal::pso::Rect { x: i16::try_from(rect.x.round() as i64).unwrap_or(0), @@ -1058,7 +1084,7 @@ impl Global { 0, iter::once(hal::pso::Viewport { rect: r, - depth: depth.clone(), + depth: depth_min .. depth_max, }), ); } @@ -1155,6 +1181,8 @@ impl Global { } } } + + assert_eq!(peeker, raw_data_end); } pub fn render_pass_set_bind_group( @@ -1622,3 +1650,136 @@ impl Global { } } } + +impl RawPass { + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_bind_group( + &mut self, + index: u32, + bind_group_id: id::BindGroupId, + offsets: *const BufferAddress, + offset_length: usize, + ) { + self.encode_with1( + &RenderCommand::SetBindGroup { + index, + num_dynamic_offsets: offset_length.try_into().unwrap(), + bind_group_id, + phantom_offsets: PhantomSlice::new(), + }, + slice::from_raw_parts(offsets, offset_length), + ); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_pipeline( + &mut self, + pipeline_id: id::RenderPipelineId, + ) { + self.encode(&RenderCommand::SetPipeline(pipeline_id)); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_index_buffer( + &mut self, + buffer_id: id::BufferId, + offset: BufferAddress, + ) { + self.encode(&RenderCommand::SetIndexBuffer { + buffer_id, + offset, + }); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_vertex_buffers( + &mut self, + start_slot: u32, + buffer_ids: *const id::BufferId, + offsets: *const BufferAddress, + length: usize, + ) { + self.encode_with2( + &RenderCommand::SetVertexBuffers { + start_index: start_slot.try_into().unwrap(), + count: length.try_into().unwrap(), + phantom_buffer_ids: PhantomSlice::new(), + phantom_offsets: PhantomSlice::new(), + }, + slice::from_raw_parts(buffer_ids, length), + slice::from_raw_parts(offsets, length), + ); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_blend_color( + &mut self, + color: &Color, + ) { + self.encode(&RenderCommand::SetBlendColor(*color)); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_stencil_reference( + &mut self, + value: u32, + ) { + self.encode(&RenderCommand::SetStencilReference(value)); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_viewport( + &mut self, + x: f32, + y: f32, + w: f32, + h: f32, + depth_min: f32, + depth_max: f32, + ) { + self.encode(&RenderCommand::SetViewport { + rect: Rect { x, y, w, h }, + depth_min, + depth_max, + }); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_set_scissor( + &mut self, + x: u32, + y: u32, + w: u32, + h: u32, + ) { + self.encode(&RenderCommand::SetScissor(Rect { x, y, w, h })); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_draw( + &mut self, + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + ) { + self.encode(&RenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }); + } + + #[no_mangle] + pub unsafe extern "C" fn wgpu_raw_render_pass_draw_indirect( + &mut self, + buffer_id: id::BufferId, + offset: BufferAddress, + ) { + self.encode(&RenderCommand::DrawIndirect { + buffer_id, + offset, + }); + } +} diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 1789d38fec..d6e2fc9208 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -31,6 +31,7 @@ pub mod swap_chain; pub mod track; pub use hal::pso::read_spirv; +use peek_poke::{PeekCopy, Poke}; use std::{ os::raw::c_char, @@ -121,7 +122,7 @@ struct Stored { } #[repr(C)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PeekCopy, Poke)] pub struct Color { pub r: f64, pub g: f64, diff --git a/wgpu-native/src/command.rs b/wgpu-native/src/command.rs index 774e3ad285..1b2976738b 100644 --- a/wgpu-native/src/command.rs +++ b/wgpu-native/src/command.rs @@ -331,16 +331,9 @@ pub unsafe extern "C" fn wgpu_command_encoder_render_pass( 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, + pass: &core::command::RawPass, ) { - 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)); + let color_attachments = slice::from_raw_parts(color_attachments, color_attachment_length); + let raw_data = pass.to_slice(); + gfx_select!(self_id => GLOBAL.command_encoder_run_render_pass(self_id, color_attachments, depth_stencil_attachment, raw_data)); } diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index a8cc475a09..a8ff5dd329 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -141,18 +141,12 @@ pub unsafe extern "C" fn wgpu_server_encode_render_pass( color_attachments: *const core::command::RenderPassColorAttachmentDescriptor, color_attachment_length: usize, depth_stencil_attachment: Option<&core::command::RenderPassDepthStencilAttachmentDescriptor>, - commands: *const core::command::RenderCommand, + commands: *const u8, 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)); + let color_attachments = slice::from_raw_parts(color_attachments, color_attachment_length); + let raw_pass = slice::from_raw_parts(commands, command_length); + gfx_select!(self_id => global.command_encoder_run_render_pass(self_id, color_attachments, depth_stencil_attachment, raw_pass)); } #[no_mangle] From 40ac14e92c628af4771c90d0ea64d8b6c8f3b4a3 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 10 Jan 2020 12:22:06 -0500 Subject: [PATCH 5/9] Switch the examples to use the new raw passes --- Cargo.lock | 1 + examples/compute/main.c | 2 +- examples/triangle/main.c | 2 +- ffi/wgpu.h | 197 +++++++++++---------- wgpu-core/src/command/compute.rs | 94 +++++++--- wgpu-core/src/command/mod.rs | 196 ++++++++++++--------- wgpu-core/src/command/render.rs | 181 +++++++++++++------- wgpu-native/Cargo.toml | 1 + wgpu-native/cbindgen.toml | 6 + wgpu-native/src/command.rs | 283 ++++--------------------------- wgpu-remote/src/server.rs | 7 +- 11 files changed, 461 insertions(+), 509 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1853eb7894..f6ae82bfd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,6 +673,7 @@ dependencies = [ name = "wgpu-native" version = "0.4.0" dependencies = [ + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/examples/compute/main.c b/examples/compute/main.c index ef752ce2ef..a2df235e62 100644 --- a/examples/compute/main.c +++ b/examples/compute/main.c @@ -127,7 +127,7 @@ int main( .todo = 0 }); - WGPUComputePassId command_pass = + WGPURawComputePassId command_pass = //temp name wgpu_command_encoder_begin_compute_pass(encoder, NULL); wgpu_compute_pass_set_pipeline(command_pass, compute_pipeline); diff --git a/examples/triangle/main.c b/examples/triangle/main.c index 05eab3e59a..50080e2ce3 100644 --- a/examples/triangle/main.c +++ b/examples/triangle/main.c @@ -249,7 +249,7 @@ int main() { }, }; - WGPURenderPassId rpass = + WGPURawRenderPassId rpass = wgpu_command_encoder_begin_render_pass(cmd_encoder, &(WGPURenderPassDescriptor){ .color_attachments = color_attachments, diff --git a/ffi/wgpu.h b/ffi/wgpu.h index e6a8666be4..310f260734 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -19,6 +19,18 @@ #include #include +#define WGPUDEFAULT_BIND_GROUPS 4 + +#define WGPUDESIRED_NUM_FRAMES 3 + +#define WGPUMAX_BIND_GROUPS 4 + +#define WGPUMAX_COLOR_TARGETS 4 + +#define WGPUMAX_MIP_LEVELS 16 + +#define WGPUMAX_VERTEX_BUFFERS 8 + typedef enum { WGPUAddressMode_ClampToEdge = 0, WGPUAddressMode_Repeat = 1, @@ -243,8 +255,6 @@ typedef enum { WGPUVertexFormat_Int4 = 48, } WGPUVertexFormat; -typedef struct WGPURawPass WGPURawPass; - typedef uint64_t WGPUId_Device_Dummy; typedef WGPUId_Device_Dummy WGPUDeviceId; @@ -284,20 +294,21 @@ typedef uint64_t WGPUId_CommandBuffer_Dummy; typedef WGPUId_CommandBuffer_Dummy WGPUCommandBufferId; -typedef uint64_t WGPUId_ComputePass_Dummy; +typedef WGPUCommandBufferId WGPUCommandEncoderId; -typedef WGPUId_ComputePass_Dummy WGPUComputePassId; +typedef struct { + uint8_t *data; + uint8_t *base; + uintptr_t capacity; + WGPUCommandEncoderId parent; +} WGPURawPass; -typedef WGPUCommandBufferId WGPUCommandEncoderId; +typedef WGPURawPass *WGPURawComputePassId; typedef struct { uint32_t todo; } WGPUComputePassDescriptor; -typedef uint64_t WGPUId_RenderPass_Dummy; - -typedef WGPUId_RenderPass_Dummy WGPURenderPassId; - typedef uint64_t WGPUId_TextureView_Dummy; typedef WGPUId_TextureView_Dummy WGPUTextureViewId; @@ -317,13 +328,13 @@ typedef struct { typedef struct { WGPUTextureViewId attachment; - const WGPUTextureViewId *resolve_target; + WGPUTextureViewId resolve_target; WGPULoadOp load_op; WGPUStoreOp store_op; WGPUColor clear_color; -} WGPURenderPassColorAttachmentDescriptorBase_TextureViewId; +} WGPURenderPassColorAttachmentDescriptorBase_TextureViewId__TextureViewId; -typedef WGPURenderPassColorAttachmentDescriptorBase_TextureViewId WGPURenderPassColorAttachmentDescriptor; +typedef WGPURenderPassColorAttachmentDescriptorBase_TextureViewId__TextureViewId WGPURawRenderPassColorAttachmentDescriptor; typedef struct { WGPUTextureViewId attachment; @@ -337,6 +348,30 @@ typedef struct { typedef WGPURenderPassDepthStencilAttachmentDescriptorBase_TextureViewId WGPURenderPassDepthStencilAttachmentDescriptor; +typedef struct { + WGPURawRenderPassColorAttachmentDescriptor colors[WGPUMAX_COLOR_TARGETS]; + WGPURenderPassDepthStencilAttachmentDescriptor depth_stencil; +} WGPURawRenderTargets; + +typedef struct { + WGPURawPass raw; + WGPURawRenderTargets targets; +} WGPURawRenderPass; + +typedef WGPURawRenderPass *WGPURawRenderPassId; + +typedef const WGPUTextureViewId *WGPUOptionRef_TextureViewId; + +typedef struct { + WGPUTextureViewId attachment; + WGPUOptionRef_TextureViewId resolve_target; + WGPULoadOp load_op; + WGPUStoreOp store_op; + WGPUColor clear_color; +} WGPURenderPassColorAttachmentDescriptorBase_TextureViewId__OptionRef_TextureViewId; + +typedef WGPURenderPassColorAttachmentDescriptorBase_TextureViewId__OptionRef_TextureViewId WGPURenderPassColorAttachmentDescriptor; + typedef struct { const WGPURenderPassColorAttachmentDescriptor *color_attachments; uintptr_t color_attachments_length; @@ -694,13 +729,11 @@ void wgpu_buffer_unmap(WGPUBufferId buffer_id); void wgpu_command_buffer_destroy(WGPUCommandBufferId command_buffer_id); -WGPUComputePassId wgpu_command_encoder_begin_compute_pass(WGPUCommandEncoderId encoder_id, - const WGPUComputePassDescriptor *desc); - -WGPURenderPassId wgpu_command_encoder_begin_render_pass(WGPUCommandEncoderId encoder_id, - const WGPURenderPassDescriptor *desc); +WGPURawComputePassId wgpu_command_encoder_begin_compute_pass(WGPUCommandEncoderId encoder_id, + const WGPUComputePassDescriptor *_desc); -void wgpu_command_encoder_compute_pass(WGPUCommandEncoderId self_id, const WGPURawPass *pass); +WGPURawRenderPassId wgpu_command_encoder_begin_render_pass(WGPUCommandEncoderId encoder_id, + const WGPURenderPassDescriptor *desc); void wgpu_command_encoder_copy_buffer_to_buffer(WGPUCommandEncoderId command_encoder_id, WGPUBufferId source, @@ -729,33 +762,30 @@ 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 WGPURawPass *pass); +void wgpu_compute_pass_dispatch(WGPURawPass *pass, + uint32_t groups_x, + uint32_t groups_y, + uint32_t groups_z); -void wgpu_compute_pass_dispatch(WGPUComputePassId pass_id, uint32_t x, uint32_t y, uint32_t z); +void wgpu_compute_pass_dispatch_indirect(WGPURawPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); -void wgpu_compute_pass_dispatch_indirect(WGPUComputePassId pass_id, - WGPUBufferId indirect_buffer_id, - WGPUBufferAddress indirect_offset); +void wgpu_compute_pass_end_pass(WGPURawComputePassId pass_id); -void wgpu_compute_pass_end_pass(WGPUComputePassId pass_id); +void wgpu_compute_pass_insert_debug_marker(WGPURawPass *_pass, WGPURawString _label); -void wgpu_compute_pass_insert_debug_marker(WGPUComputePassId _pass_id, WGPURawString _label); +void wgpu_compute_pass_pop_debug_group(WGPURawPass *_pass); -void wgpu_compute_pass_pop_debug_group(WGPUComputePassId _pass_id); +void wgpu_compute_pass_push_debug_group(WGPURawPass *_pass, WGPURawString _label); -void wgpu_compute_pass_push_debug_group(WGPUComputePassId _pass_id, WGPURawString _label); - -void wgpu_compute_pass_set_bind_group(WGPUComputePassId pass_id, +void wgpu_compute_pass_set_bind_group(WGPURawPass *pass, uint32_t index, WGPUBindGroupId bind_group_id, const WGPUBufferAddress *offsets, - uintptr_t offsets_length); + uintptr_t offset_length); -void wgpu_compute_pass_set_pipeline(WGPUComputePassId pass_id, WGPUComputePipelineId pipeline_id); +void wgpu_compute_pass_set_pipeline(WGPURawPass *pass, WGPUComputePipelineId pipeline_id); WGPUSurfaceId wgpu_create_surface_from_metal_layer(void *layer); @@ -812,74 +842,63 @@ void wgpu_queue_submit(WGPUQueueId queue_id, const WGPUCommandBufferId *command_buffers, uintptr_t command_buffers_length); -void wgpu_render_pass_draw(WGPURenderPassId pass_id, - uint32_t vertex_count, - uint32_t instance_count, - uint32_t first_vertex, - uint32_t first_instance); - -void wgpu_render_pass_draw_indexed(WGPURenderPassId pass_id, - uint32_t index_count, - uint32_t instance_count, - uint32_t first_index, - int32_t base_vertex, - uint32_t first_instance); +void wgpu_raw_render_pass_draw(WGPURawRenderPass *pass, + uint32_t vertex_count, + uint32_t instance_count, + uint32_t first_vertex, + uint32_t first_instance); -void wgpu_render_pass_draw_indexed_indirect(WGPURenderPassId pass_id, - WGPUBufferId indirect_buffer_id, - WGPUBufferAddress indirect_offset); +void wgpu_raw_render_pass_draw_indirect(WGPURawRenderPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); -void wgpu_render_pass_draw_indirect(WGPURenderPassId pass_id, - WGPUBufferId indirect_buffer_id, - WGPUBufferAddress indirect_offset); +void wgpu_raw_render_pass_set_bind_group(WGPURawRenderPass *pass, + uint32_t index, + WGPUBindGroupId bind_group_id, + const WGPUBufferAddress *offsets, + uintptr_t offset_length); -void wgpu_render_pass_end_pass(WGPURenderPassId pass_id); +void wgpu_raw_render_pass_set_blend_color(WGPURawRenderPass *pass, const WGPUColor *color); -void wgpu_render_pass_execute_bundles(WGPURenderPassId _pass_id, - const WGPURenderBundleId *_bundles, - uintptr_t _bundles_length); +void wgpu_raw_render_pass_set_index_buffer(WGPURawRenderPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); -void wgpu_render_pass_insert_debug_marker(WGPURenderPassId _pass_id, WGPURawString _label); +void wgpu_raw_render_pass_set_pipeline(WGPURawRenderPass *pass, WGPURenderPipelineId pipeline_id); -void wgpu_render_pass_pop_debug_group(WGPURenderPassId _pass_id); +void wgpu_raw_render_pass_set_scissor(WGPURawRenderPass *pass, + uint32_t x, + uint32_t y, + uint32_t w, + uint32_t h); -void wgpu_render_pass_push_debug_group(WGPURenderPassId _pass_id, WGPURawString _label); +void wgpu_raw_render_pass_set_stencil_reference(WGPURawRenderPass *pass, uint32_t value); -void wgpu_render_pass_set_bind_group(WGPURenderPassId pass_id, - uint32_t index, - WGPUBindGroupId bind_group_id, - const WGPUBufferAddress *offsets, - uintptr_t offsets_length); +void wgpu_raw_render_pass_set_vertex_buffers(WGPURawRenderPass *pass, + uint32_t start_slot, + const WGPUBufferId *buffer_ids, + const WGPUBufferAddress *offsets, + uintptr_t length); -void wgpu_render_pass_set_blend_color(WGPURenderPassId pass_id, const WGPUColor *color); +void wgpu_raw_render_pass_set_viewport(WGPURawRenderPass *pass, + float x, + float y, + float w, + float h, + float depth_min, + float depth_max); -void wgpu_render_pass_set_index_buffer(WGPURenderPassId pass_id, - WGPUBufferId buffer_id, - WGPUBufferAddress offset); +void wgpu_render_pass_end_pass(WGPURawRenderPassId pass_id); -void wgpu_render_pass_set_pipeline(WGPURenderPassId pass_id, WGPURenderPipelineId pipeline_id); +void wgpu_render_pass_execute_bundles(WGPURawRenderPass *_pass, + const WGPURenderBundleId *_bundles, + uintptr_t _bundles_length); -void wgpu_render_pass_set_scissor_rect(WGPURenderPassId pass_id, - uint32_t x, - uint32_t y, - uint32_t w, - uint32_t h); +void wgpu_render_pass_insert_debug_marker(WGPURawRenderPass *_pass, WGPURawString _label); -void wgpu_render_pass_set_stencil_reference(WGPURenderPassId pass_id, uint32_t value); +void wgpu_render_pass_pop_debug_group(WGPURawRenderPass *_pass); -void wgpu_render_pass_set_vertex_buffers(WGPURenderPassId pass_id, - uint32_t start_slot, - const WGPUBufferId *buffers, - const WGPUBufferAddress *offsets, - uintptr_t length); - -void wgpu_render_pass_set_viewport(WGPURenderPassId pass_id, - float x, - float y, - float w, - float h, - float min_depth, - float max_depth); +void wgpu_render_pass_push_debug_group(WGPURawRenderPass *_pass, WGPURawString _label); void wgpu_request_adapter_async(const WGPURequestAdapterOptions *desc, WGPUBackendBit mask, diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 73d37d8dad..d4d503d0ab 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -7,7 +7,6 @@ use crate::{ bind::{Binder, LayoutChange}, CommandBuffer, PhantomSlice, - RawPass, }, device::{all_buffer_stages, BIND_BUFFER_ALIGNMENT}, hub::{GfxBackend, Global, IdentityFilter, Token}, @@ -21,13 +20,13 @@ use crate::{ use hal::command::CommandBuffer as _; use peek_poke::{Peek, PeekCopy, Poke}; -use std::{convert::TryInto, iter, mem, slice}; +use std::iter; #[derive(Clone, Copy, Debug, PeekCopy, Poke)] enum ComputeCommand { SetBindGroup { - index: u32, + index: u8, num_dynamic_offsets: u8, bind_group_id: id::BindGroupId, phantom_offsets: PhantomSlice, @@ -38,6 +37,17 @@ enum ComputeCommand { buffer_id: id::BufferId, offset: BufferAddress, }, + End, +} + +impl super::RawPass { + pub fn new_compute(parent: id::CommandEncoderId) -> Self { + Self::from_vec(Vec::::with_capacity(1), parent) + } + + pub unsafe fn finish_compute(self) -> (Vec, id::CommandEncoderId) { + self.finish_with(ComputeCommand::End) + } } #[repr(C)] @@ -113,7 +123,8 @@ impl Global { 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 { + loop { + assert!(unsafe { peeker.add(ComputeCommand::max_size()) } <= raw_data_end); peeker = unsafe { command.peek_from(peeker) }; match command { ComputeCommand::SetBindGroup { index, num_dynamic_offsets, bind_group_id, phantom_offsets } => { @@ -238,10 +249,9 @@ impl Global { raw.dispatch_indirect(&src_buffer.raw, offset); } } + ComputeCommand::End => break, } } - - assert_eq!(peeker, raw_data_end); } pub fn compute_pass_set_bind_group( @@ -422,53 +432,87 @@ impl Global { } } -impl RawPass { +mod ffi { + use super::{ + ComputeCommand, + super::{PhantomSlice, RawPass}, + }; + use crate::{ + id, + BufferAddress, + RawString, + }; + use std::{convert::TryInto, slice}; + #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_compute_pass_set_bind_group( - &mut self, + pub unsafe extern "C" fn wgpu_compute_pass_set_bind_group( + pass: &mut RawPass, index: u32, bind_group_id: id::BindGroupId, offsets: *const BufferAddress, offset_length: usize, ) { - self.encode_with1( - &ComputeCommand::SetBindGroup { - index, - num_dynamic_offsets: offset_length.try_into().unwrap(), - bind_group_id, - phantom_offsets: PhantomSlice::new(), - }, + pass.encode(&ComputeCommand::SetBindGroup { + index: index.try_into().unwrap(), + num_dynamic_offsets: offset_length.try_into().unwrap(), + bind_group_id, + phantom_offsets: PhantomSlice::new(), + }); + pass.encode_slice( slice::from_raw_parts(offsets, offset_length), ); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_compute_pass_set_pipeline( - &mut self, + pub unsafe extern "C" fn wgpu_compute_pass_set_pipeline( + pass: &mut RawPass, pipeline_id: id::ComputePipelineId, ) { - self.encode(&ComputeCommand::SetPipeline(pipeline_id)); + pass.encode(&ComputeCommand::SetPipeline(pipeline_id)); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_compute_pass_dispatch( - &mut self, + pub unsafe extern "C" fn wgpu_compute_pass_dispatch( + pass: &mut RawPass, groups_x: u32, groups_y: u32, groups_z: u32, ) { - self.encode(&ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); + pass.encode(&ComputeCommand::Dispatch([groups_x, groups_y, groups_z])); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_compute_pass_dispatch_indirect( - &mut self, + pub unsafe extern "C" fn wgpu_compute_pass_dispatch_indirect( + pass: &mut RawPass, buffer_id: id::BufferId, offset: BufferAddress, ) { - self.encode(&ComputeCommand::DispatchIndirect { + pass.encode(&ComputeCommand::DispatchIndirect { buffer_id, offset, }); } + + #[no_mangle] + pub extern "C" fn wgpu_compute_pass_push_debug_group( + _pass: &mut RawPass, + _label: RawString, + ) { + //TODO + } + + #[no_mangle] + pub extern "C" fn wgpu_compute_pass_pop_debug_group( + _pass: &mut RawPass, + ) { + //TODO + } + + #[no_mangle] + pub extern "C" fn wgpu_compute_pass_insert_debug_marker( + _pass: &mut RawPass, + _label: RawString, + ) { + //TODO + } } diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 6817357736..87b99af92f 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -16,6 +16,7 @@ pub use self::transfer::*; use crate::{ conv, device::{ + MAX_COLOR_TARGETS, all_buffer_stages, all_image_stages, FramebufferKey, @@ -23,16 +24,7 @@ use crate::{ RenderPassKey, }, hub::{GfxBackend, Global, IdentityFilter, Storage, Token}, - id::{ - BufferId, - CommandBufferId, - CommandEncoderId, - ComputePassId, - DeviceId, - RenderPassId, - TextureId, - TextureViewId, - }, + id, resource::{Buffer, Texture, TextureUsage, TextureViewInner}, track::TrackerSet, Features, @@ -41,7 +33,11 @@ use crate::{ }; use arrayvec::ArrayVec; -use hal::{adapter::PhysicalDevice as _, command::CommandBuffer as _, device::Device as _}; +use hal::{ + adapter::PhysicalDevice as _, + command::CommandBuffer as _, + device::Device as _, +}; use std::{ borrow::Borrow, @@ -49,12 +45,14 @@ use std::{ iter, marker::PhantomData, mem, - ptr, slice, thread::ThreadId, }; +pub type RawRenderPassId = *mut RawRenderPass; +pub type RawComputePassId = *mut RawPass; + #[derive(Clone, Copy, Debug, peek_poke::PeekCopy, peek_poke::Poke)] struct PhantomSlice(PhantomData); @@ -66,88 +64,80 @@ impl PhantomSlice { unsafe fn decode<'a>( self, pointer: *const u8, count: usize, bound: *const u8 ) -> (*const u8, &'a [T]) { - debug_assert_eq!(pointer.align_offset(mem::align_of::()), 0); - let extra_size = count * mem::size_of::(); - let end = pointer.add(extra_size); + let align_offset = pointer.align_offset(mem::align_of::()); + let aligned = pointer.add(align_offset); + let size = count * mem::size_of::(); + let end = aligned.add(size); assert!(end <= bound); - (end, slice::from_raw_parts(pointer as *const T, count)) + (end, slice::from_raw_parts(aligned as *const T, count)) } } +#[repr(C)] pub struct RawPass { data: *mut u8, base: *mut u8, capacity: usize, + parent: id::CommandEncoderId, } impl RawPass { - pub fn new() -> Self { - let mut vec = Vec::with_capacity(16); + fn from_vec( + mut vec: Vec, + encoder_id: id::CommandEncoderId, + ) -> Self { + let ptr = vec.as_mut_ptr() as *mut u8; + let capacity = vec.capacity() * mem::size_of::(); + mem::forget(vec); RawPass { - data: vec.as_mut_ptr(), - base: vec.as_mut_ptr(), - capacity: vec.capacity(), + data: ptr, + base: ptr, + capacity, + parent: encoder_id, } } - 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; + /// Finish encoding a raw pass. + /// + /// The last command is provided, yet the encoder + /// is guaranteed to have exactly `C::max_size()` space for it. + unsafe fn finish_with( + mut self, command: C + ) -> (Vec, id::CommandEncoderId) { + self.ensure_extra_size(C::max_size()); + command.poke_into(self.data); + let size = self.data as usize + C::max_size() - self.base as usize; assert!(size <= self.capacity); - slice::from_raw_parts(self.base, size) + (Vec::from_raw_parts(self.base, size, self.capacity), self.parent) } 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) { + if size + extra_size > self.capacity { let mut vec = Vec::from_raw_parts(self.base, size, self.capacity); - vec.reserve(extra_capacity); + vec.reserve(extra_size); //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(); + mem::forget(vec); } } #[inline] unsafe fn encode(&mut self, command: &C) { - self.ensure_extra_size(mem::size_of::()); + self.ensure_extra_size(C::max_size()); self.data = command.poke_into(self.data); } #[inline] - unsafe fn encode_with1( - &mut self, command: &C, 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); - } - - #[inline] - unsafe fn encode_with2( - &mut self, command: &C, extra1: &[T], extra2: &[V] - ) { - let extra1_size = extra1.len() * mem::size_of::(); - let extra2_size = extra2.len() * mem::size_of::(); - self.ensure_extra_size(mem::size_of::() + extra1_size + extra2_size); - self.data = command.poke_into(self.data); - - debug_assert_eq!(self.data.align_offset(mem::align_of::()), 0); - ptr::copy_nonoverlapping(extra1.as_ptr(), self.data as *mut T, extra1.len()); - self.data = self.data.add(extra1_size); - - debug_assert_eq!(self.data.align_offset(mem::align_of::()), 0); - ptr::copy_nonoverlapping(extra2.as_ptr(), self.data as *mut V, extra2.len()); - self.data = self.data.add(extra2_size); + unsafe fn encode_slice(&mut self, data: &[T]) { + let align_offset = self.data.align_offset(mem::align_of::()); + let extra = align_offset + mem::size_of::() * data.len(); + self.ensure_extra_size(extra); + slice::from_raw_parts_mut(self.data.add(align_offset) as *mut T, data.len()) + .copy_from_slice(data); + self.data = self.data.add(extra); } } @@ -160,10 +150,10 @@ pub struct CommandBuffer { pub(crate) raw: Vec, is_recording: bool, recorded_thread_id: ThreadId, - pub(crate) device_id: Stored, + pub(crate) device_id: Stored, pub(crate) life_guard: LifeGuard, pub(crate) trackers: TrackerSet, - pub(crate) used_swap_chain: Option<(Stored, B::Framebuffer)>, + pub(crate) used_swap_chain: Option<(Stored, B::Framebuffer)>, pub(crate) features: Features, } @@ -172,8 +162,8 @@ impl CommandBuffer { raw: &mut B::CommandBuffer, base: &mut TrackerSet, head: &TrackerSet, - buffer_guard: &Storage, BufferId>, - texture_guard: &Storage, TextureId>, + buffer_guard: &Storage, id::BufferId>, + texture_guard: &Storage, id::TextureId>, ) { debug_assert_eq!(B::VARIANT, base.backend()); debug_assert_eq!(B::VARIANT, head.backend()); @@ -221,12 +211,66 @@ pub struct CommandBufferDescriptor { pub todo: u32, } +#[no_mangle] +pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( + encoder_id: id::CommandEncoderId, + _desc: Option<&ComputePassDescriptor>, +) -> RawComputePassId { + let pass = RawPass::new_compute(encoder_id); + Box::into_raw(Box::new(pass)) +} + +type RawRenderPassColorAttachmentDescriptor = + RenderPassColorAttachmentDescriptorBase; + +#[repr(C)] +pub struct RawRenderTargets { + pub colors: [RawRenderPassColorAttachmentDescriptor; MAX_COLOR_TARGETS], + pub depth_stencil: RenderPassDepthStencilAttachmentDescriptor, +} + +#[repr(C)] +pub struct RawRenderPass { + raw: RawPass, + targets: RawRenderTargets, +} + +#[no_mangle] +pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( + encoder_id: id::CommandEncoderId, + desc: &RenderPassDescriptor, +) -> RawRenderPassId { + let mut colors: [RawRenderPassColorAttachmentDescriptor; MAX_COLOR_TARGETS] = mem::zeroed(); + for (color, at) in colors + .iter_mut() + .zip(slice::from_raw_parts(desc.color_attachments, desc.color_attachments_length)) + { + *color = RawRenderPassColorAttachmentDescriptor { + attachment: at.attachment, + resolve_target: at.resolve_target.map_or(id::TextureViewId::ERROR, |rt| *rt), + load_op: at.load_op, + store_op: at.store_op, + clear_color: at.clear_color, + }; + } + let pass = RawRenderPass { + raw: RawPass::new_render(encoder_id), + targets: RawRenderTargets { + colors, + depth_stencil: desc.depth_stencil_attachment + .cloned() + .unwrap_or_else(|| mem::zeroed()), + }, + }; + Box::into_raw(Box::new(pass)) +} + impl Global { pub fn command_encoder_finish( &self, - encoder_id: CommandEncoderId, + encoder_id: id::CommandEncoderId, _desc: &CommandBufferDescriptor, - ) -> CommandBufferId { + ) -> id::CommandBufferId { let hub = B::hub(self); let mut token = Token::root(); //TODO: actually close the last recorded command buffer @@ -243,13 +287,13 @@ impl Global { } } -impl> Global { +impl> Global { pub fn command_encoder_begin_render_pass( &self, - encoder_id: CommandEncoderId, + encoder_id: id::CommandEncoderId, desc: &RenderPassDescriptor, id_in: F::Input, - ) -> RenderPassId { + ) -> id::RenderPassId { let hub = B::hub(self); let mut token = Token::root(); @@ -279,12 +323,12 @@ impl> Global { let (view_guard, _) = hub.texture_views.read(&mut token); let mut extent = None; - let mut used_swap_chain_image = None::>; + let mut used_swap_chain_image = None::>; let color_attachments = unsafe { slice::from_raw_parts(desc.color_attachments, desc.color_attachments_length) }; - let depth_stencil_attachment = unsafe { desc.depth_stencil_attachment.as_ref() }; + let depth_stencil_attachment = desc.depth_stencil_attachment; let sample_count = color_attachments .get(0) @@ -297,7 +341,7 @@ impl> Global { const MAX_TOTAL_ATTACHMENTS: usize = 10; type OutputAttachment<'a> = ( - &'a Stored, + &'a Stored, &'a hal::image::SubresourceRange, Option, ); @@ -525,7 +569,7 @@ impl> Global { (3, hal::image::Layout::ColorAttachmentOptimal), ]; - let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new(); + let mut resolve_ids = ArrayVec::<[_; MAX_COLOR_TARGETS]>::new(); let mut attachment_index = color_attachments.len(); if color_attachments .iter() @@ -732,13 +776,13 @@ impl> Global { } } -impl> Global { +impl> Global { pub fn command_encoder_begin_compute_pass( &self, - encoder_id: CommandEncoderId, + encoder_id: id::CommandEncoderId, _desc: &ComputePassDescriptor, id_in: F::Input, - ) -> ComputePassId { + ) -> id::ComputePassId { let hub = B::hub(self); let mut token = Token::root(); diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index e813d2f391..d1daf64468 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -7,7 +7,7 @@ use crate::{ bind::{Binder, LayoutChange}, CommandBuffer, PhantomSlice, - RawPass, + RawRenderTargets, }, conv, device::{ @@ -16,6 +16,7 @@ use crate::{ RenderPassKey, BIND_BUFFER_ALIGNMENT, MAX_VERTEX_BUFFERS, + MAX_COLOR_TARGETS, }, hub::{GfxBackend, Global, IdentityFilter, Token}, id, @@ -34,12 +35,9 @@ use peek_poke::{Peek, PeekCopy, Poke}; use std::{ borrow::Borrow, collections::hash_map::Entry, - convert::TryInto, iter, marker::PhantomData, - mem, ops::Range, - slice, }; @@ -59,16 +57,16 @@ pub enum StoreOp { #[repr(C)] #[derive(Debug)] -pub struct RenderPassColorAttachmentDescriptorBase<'a, T> { - pub attachment: id::TextureViewId, - pub resolve_target: Option<&'a T>, +pub struct RenderPassColorAttachmentDescriptorBase { + pub attachment: T, + pub resolve_target: R, pub load_op: LoadOp, pub store_op: StoreOp, pub clear_color: Color, } #[repr(C)] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct RenderPassDepthStencilAttachmentDescriptorBase { pub attachment: T, pub depth_load_op: LoadOp, @@ -79,15 +77,20 @@ pub struct RenderPassDepthStencilAttachmentDescriptorBase { pub clear_stencil: u32, } -pub type RenderPassDepthStencilAttachmentDescriptor = RenderPassDepthStencilAttachmentDescriptorBase; -pub type RenderPassColorAttachmentDescriptor<'a> = RenderPassColorAttachmentDescriptorBase<'a, id::TextureViewId>; +//Note: this could look better if `cbindgen` wasn't confused by &T used in place of +// a generic paramter, it's not able to mange +pub type OptionRef<'a, T> = Option<&'a T>; +pub type RenderPassColorAttachmentDescriptor<'a> = + RenderPassColorAttachmentDescriptorBase>; +pub type RenderPassDepthStencilAttachmentDescriptor = + RenderPassDepthStencilAttachmentDescriptorBase; #[repr(C)] #[derive(Debug)] pub struct RenderPassDescriptor<'a> { pub color_attachments: *const RenderPassColorAttachmentDescriptor<'a>, pub color_attachments_length: usize, - pub depth_stencil_attachment: *const RenderPassDepthStencilAttachmentDescriptor, + pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachmentDescriptor>, } #[derive(Clone, Copy, Debug, PeekCopy, Poke)] @@ -101,7 +104,7 @@ pub struct Rect { #[derive(Clone, Copy, Debug, PeekCopy, Poke)] enum RenderCommand { SetBindGroup { - index: u32, + index: u8, num_dynamic_offsets: u8, bind_group_id: id::BindGroupId, phantom_offsets: PhantomSlice, @@ -147,6 +150,20 @@ enum RenderCommand { buffer_id: id::BufferId, offset: BufferAddress, }, + End, +} + +impl super::RawPass { + pub fn new_render(parent_id: id::CommandEncoderId) -> Self { + Self::from_vec(Vec::::with_capacity(1), parent_id) + } +} + +impl super::RawRenderPass { + pub unsafe fn finish_render(self) -> (Vec, id::CommandEncoderId, RawRenderTargets) { + let (vec, parent_id) = self.raw.finish_with(RenderCommand::End); + (vec, parent_id, self.targets) + } } #[derive(Debug, PartialEq)] @@ -650,7 +667,7 @@ impl Global { (3, hal::image::Layout::ColorAttachmentOptimal), ]; - let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new(); + let mut resolve_ids = ArrayVec::<[_; MAX_COLOR_TARGETS]>::new(); let mut attachment_index = color_attachments.len(); if color_attachments .iter() @@ -869,7 +886,8 @@ impl Global { first_vertex: 0, first_instance: 0, }; - while unsafe { peeker.add(mem::size_of::()) } <= raw_data_end { + loop { + assert!(unsafe { peeker.add(RenderCommand::max_size()) } <= raw_data_end); peeker = unsafe { command.peek_from(peeker) }; match command { RenderCommand::SetBindGroup { index, num_dynamic_offsets, bind_group_id, phantom_offsets } => { @@ -1179,10 +1197,9 @@ impl Global { raw.draw_indexed_indirect(&buffer.raw, offset, 1, 0); } } + RenderCommand::End => break, } } - - assert_eq!(peeker, raw_data_end); } pub fn render_pass_set_bind_group( @@ -1651,85 +1668,99 @@ impl Global { } } -impl RawPass { +mod ffi { + use super::{ + RenderCommand, + super::{PhantomSlice, RawRenderPass, Rect}, + }; + use crate::{ + id, + BufferAddress, + Color, + RawString, + }; + use std::{convert::TryInto, slice}; + #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_bind_group( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_bind_group( + pass: &mut RawRenderPass, index: u32, bind_group_id: id::BindGroupId, offsets: *const BufferAddress, offset_length: usize, ) { - self.encode_with1( - &RenderCommand::SetBindGroup { - index, - num_dynamic_offsets: offset_length.try_into().unwrap(), - bind_group_id, - phantom_offsets: PhantomSlice::new(), - }, + pass.raw.encode(&RenderCommand::SetBindGroup { + index: index.try_into().unwrap(), + num_dynamic_offsets: offset_length.try_into().unwrap(), + bind_group_id, + phantom_offsets: PhantomSlice::new(), + }); + pass.raw.encode_slice( slice::from_raw_parts(offsets, offset_length), ); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_pipeline( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_pipeline( + pass: &mut RawRenderPass, pipeline_id: id::RenderPipelineId, ) { - self.encode(&RenderCommand::SetPipeline(pipeline_id)); + pass.raw.encode(&RenderCommand::SetPipeline(pipeline_id)); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_index_buffer( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_index_buffer( + pass: &mut RawRenderPass, buffer_id: id::BufferId, offset: BufferAddress, ) { - self.encode(&RenderCommand::SetIndexBuffer { + pass.raw.encode(&RenderCommand::SetIndexBuffer { buffer_id, offset, }); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_vertex_buffers( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_vertex_buffers( + pass: &mut RawRenderPass, start_slot: u32, buffer_ids: *const id::BufferId, offsets: *const BufferAddress, length: usize, ) { - self.encode_with2( - &RenderCommand::SetVertexBuffers { - start_index: start_slot.try_into().unwrap(), - count: length.try_into().unwrap(), - phantom_buffer_ids: PhantomSlice::new(), - phantom_offsets: PhantomSlice::new(), - }, + pass.raw.encode(&RenderCommand::SetVertexBuffers { + start_index: start_slot.try_into().unwrap(), + count: length.try_into().unwrap(), + phantom_buffer_ids: PhantomSlice::new(), + phantom_offsets: PhantomSlice::new(), + }); + pass.raw.encode_slice( slice::from_raw_parts(buffer_ids, length), + ); + pass.raw.encode_slice( slice::from_raw_parts(offsets, length), ); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_blend_color( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_blend_color( + pass: &mut RawRenderPass, color: &Color, ) { - self.encode(&RenderCommand::SetBlendColor(*color)); + pass.raw.encode(&RenderCommand::SetBlendColor(*color)); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_stencil_reference( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_stencil_reference( + pass: &mut RawRenderPass, value: u32, ) { - self.encode(&RenderCommand::SetStencilReference(value)); + pass.raw.encode(&RenderCommand::SetStencilReference(value)); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_viewport( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_viewport( + pass: &mut RawRenderPass, x: f32, y: f32, w: f32, @@ -1737,7 +1768,7 @@ impl RawPass { depth_min: f32, depth_max: f32, ) { - self.encode(&RenderCommand::SetViewport { + pass.raw.encode(&RenderCommand::SetViewport { rect: Rect { x, y, w, h }, depth_min, depth_max, @@ -1745,25 +1776,25 @@ impl RawPass { } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_set_scissor( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_set_scissor( + pass: &mut RawRenderPass, x: u32, y: u32, w: u32, h: u32, ) { - self.encode(&RenderCommand::SetScissor(Rect { x, y, w, h })); + pass.raw.encode(&RenderCommand::SetScissor(Rect { x, y, w, h })); } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_draw( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_draw( + pass: &mut RawRenderPass, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32, ) { - self.encode(&RenderCommand::Draw { + pass.raw.encode(&RenderCommand::Draw { vertex_count, instance_count, first_vertex, @@ -1772,14 +1803,46 @@ impl RawPass { } #[no_mangle] - pub unsafe extern "C" fn wgpu_raw_render_pass_draw_indirect( - &mut self, + pub unsafe extern "C" fn wgpu_render_pass_draw_indirect( + pass: &mut RawRenderPass, buffer_id: id::BufferId, offset: BufferAddress, ) { - self.encode(&RenderCommand::DrawIndirect { + pass.raw.encode(&RenderCommand::DrawIndirect { buffer_id, offset, }); } + + #[no_mangle] + pub extern "C" fn wgpu_render_pass_execute_bundles( + _pass: &mut RawRenderPass, + _bundles: *const id::RenderBundleId, + _bundles_length: usize, + ) { + unimplemented!() + } + + #[no_mangle] + pub extern "C" fn wgpu_render_pass_push_debug_group( + _pass: &mut RawRenderPass, + _label: RawString, + ) { + //TODO + } + + #[no_mangle] + pub extern "C" fn wgpu_render_pass_pop_debug_group( + _pass: &mut RawRenderPass, + ) { + //TODO + } + + #[no_mangle] + pub extern "C" fn wgpu_render_pass_insert_debug_marker( + _pass: &mut RawRenderPass, + _label: RawString, + ) { + //TODO + } } diff --git a/wgpu-native/Cargo.toml b/wgpu-native/Cargo.toml index d1f6e01294..fe6423ed96 100644 --- a/wgpu-native/Cargo.toml +++ b/wgpu-native/Cargo.toml @@ -26,6 +26,7 @@ package = "wgpu-core" version = "0.1" [dependencies] +arrayvec = "0.5" lazy_static = "1.1" parking_lot = "0.9" raw-window-handle = "0.3" diff --git a/wgpu-native/cbindgen.toml b/wgpu-native/cbindgen.toml index 6dee67146a..87fcb28d32 100644 --- a/wgpu-native/cbindgen.toml +++ b/wgpu-native/cbindgen.toml @@ -25,6 +25,8 @@ exclude = ["BufferMapResult"] parse_deps = true include = ["wgpu-core"] +extra_bindings = ["wgpu-core"] + [fn] [struct] @@ -38,3 +40,7 @@ derive_helper_methods = true bitflags = true [defines] +#"target_os = ios" = "WGPU_TARGET_IOS" +#"target_os = macos" = "WGPU_TARGET_MACOS" +#"unix" = "WGPU_TARGET_FAMILY_UNIX" +#"windows" = "WGPU_TARGET_WINDOWS" diff --git a/wgpu-native/src/command.rs b/wgpu-native/src/command.rs index 1b2976738b..691dac0753 100644 --- a/wgpu-native/src/command.rs +++ b/wgpu-native/src/command.rs @@ -6,8 +6,6 @@ use crate::GLOBAL; use core::{gfx_select, id}; -use std::{marker::PhantomData, slice}; - #[no_mangle] pub extern "C" fn wgpu_command_encoder_finish( @@ -79,261 +77,38 @@ pub extern "C" fn wgpu_command_encoder_copy_texture_to_texture( #[no_mangle] -pub extern "C" fn wgpu_command_encoder_begin_render_pass( - encoder_id: id::CommandEncoderId, - desc: &core::command::RenderPassDescriptor, -) -> id::RenderPassId { - gfx_select!(encoder_id => GLOBAL.command_encoder_begin_render_pass(encoder_id, desc, PhantomData)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_end_pass(pass_id: id::RenderPassId) { - gfx_select!(pass_id => GLOBAL.render_pass_end_pass(pass_id)) -} - -#[no_mangle] -pub unsafe extern "C" fn wgpu_render_pass_set_bind_group( - pass_id: id::RenderPassId, - index: u32, - bind_group_id: id::BindGroupId, - offsets: *const core::BufferAddress, - offsets_length: usize, -) { - let offsets = if offsets_length != 0 { - slice::from_raw_parts(offsets, offsets_length) - } else { - &[] - }; - gfx_select!(pass_id => GLOBAL.render_pass_set_bind_group(pass_id, index, bind_group_id, offsets)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_push_debug_group( - _pass_id: id::RenderPassId, - _label: core::RawString, -) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_pop_debug_group(_pass_id: id::RenderPassId) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_insert_debug_marker( - _pass_id: id::RenderPassId, - _label: core::RawString, -) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_index_buffer( - pass_id: id::RenderPassId, - buffer_id: id::BufferId, - offset: core::BufferAddress, -) { - gfx_select!(pass_id => GLOBAL.render_pass_set_index_buffer(pass_id, buffer_id, offset)) -} - -#[no_mangle] -pub unsafe extern "C" fn wgpu_render_pass_set_vertex_buffers( - pass_id: id::RenderPassId, - start_slot: u32, - buffers: *const id::BufferId, - offsets: *const core::BufferAddress, - length: usize, -) { - let buffers = slice::from_raw_parts(buffers, length); - let offsets = slice::from_raw_parts(offsets, length); - gfx_select!(pass_id => GLOBAL.render_pass_set_vertex_buffers(pass_id, start_slot, buffers, offsets)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_draw( - pass_id: id::RenderPassId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, -) { - gfx_select!(pass_id => GLOBAL.render_pass_draw(pass_id, vertex_count, instance_count, first_vertex, first_instance)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_draw_indirect( - pass_id: id::RenderPassId, - indirect_buffer_id: id::BufferId, - indirect_offset: core::BufferAddress, -) { - gfx_select!(pass_id => GLOBAL.render_pass_draw_indirect(pass_id, indirect_buffer_id, indirect_offset)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_draw_indexed( - pass_id: id::RenderPassId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, -) { - gfx_select!(pass_id => GLOBAL.render_pass_draw_indexed(pass_id, index_count, instance_count, first_index, base_vertex, first_instance)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_draw_indexed_indirect( - pass_id: id::RenderPassId, - indirect_buffer_id: id::BufferId, - indirect_offset: core::BufferAddress, -) { - gfx_select!(pass_id => GLOBAL.render_pass_draw_indexed_indirect(pass_id, indirect_buffer_id, indirect_offset)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_pipeline( - pass_id: id::RenderPassId, - pipeline_id: id::RenderPipelineId, -) { - gfx_select!(pass_id => GLOBAL.render_pass_set_pipeline(pass_id, pipeline_id)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_blend_color(pass_id: id::RenderPassId, color: &core::Color) { - gfx_select!(pass_id => GLOBAL.render_pass_set_blend_color(pass_id, color)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_stencil_reference(pass_id: id::RenderPassId, value: u32) { - gfx_select!(pass_id => GLOBAL.render_pass_set_stencil_reference(pass_id, value)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_viewport( - pass_id: id::RenderPassId, - x: f32, - y: f32, - w: f32, - h: f32, - min_depth: f32, - max_depth: f32, -) { - gfx_select!(pass_id => GLOBAL.render_pass_set_viewport(pass_id, x, y, w, h, min_depth, max_depth)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_set_scissor_rect( - pass_id: id::RenderPassId, - x: u32, - y: u32, - w: u32, - h: u32, -) { - gfx_select!(pass_id => GLOBAL.render_pass_set_scissor_rect(pass_id, x, y, w, h)) -} - -#[no_mangle] -pub extern "C" fn wgpu_render_pass_execute_bundles( - _pass_id: id::RenderPassId, - _bundles: *const id::RenderBundleId, - _bundles_length: usize, -) { - unimplemented!() -} - - -#[no_mangle] -pub extern "C" fn wgpu_command_encoder_begin_compute_pass( - encoder_id: id::CommandEncoderId, - desc: Option<&core::command::ComputePassDescriptor>, -) -> id::ComputePassId { - let desc = &desc.cloned().unwrap_or_default(); - gfx_select!(encoder_id => GLOBAL.command_encoder_begin_compute_pass(encoder_id, desc, PhantomData)) -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_end_pass(pass_id: id::ComputePassId) { - gfx_select!(pass_id => GLOBAL.compute_pass_end_pass(pass_id)) -} - -#[no_mangle] -pub unsafe extern "C" fn wgpu_compute_pass_set_bind_group( - pass_id: id::ComputePassId, - index: u32, - bind_group_id: id::BindGroupId, - offsets: *const core::BufferAddress, - offsets_length: usize, -) { - let offsets = if offsets_length != 0 { - slice::from_raw_parts(offsets, offsets_length) +pub unsafe extern "C" fn wgpu_render_pass_end_pass(pass_id: core::command::RawRenderPassId) { + let (pass_data, encoder_id, targets) = Box::from_raw(pass_id).finish_render(); + let color_attachments: arrayvec::ArrayVec<[_; core::device::MAX_COLOR_TARGETS]> = targets.colors + .iter() + .flat_map(|at| { + if at.attachment == core::id::TextureViewId::ERROR { + None + } else { + Some(core::command::RenderPassColorAttachmentDescriptor { + attachment: at.attachment, + resolve_target: if at.resolve_target == core::id::TextureViewId::ERROR { + None + } else { + Some(&at.resolve_target) + }, + load_op: at.load_op, + store_op: at.store_op, + clear_color: at.clear_color, + }) + } + }) + .collect(); + let depth_stencil_attachment = if targets.depth_stencil.attachment == core::id::TextureViewId::ERROR { + None } else { - &[] + Some(&targets.depth_stencil) }; - gfx_select!(pass_id => GLOBAL.compute_pass_set_bind_group(pass_id, index, bind_group_id, offsets)) + gfx_select!(encoder_id => GLOBAL.command_encoder_run_render_pass(encoder_id, &color_attachments, depth_stencil_attachment, &pass_data)) } #[no_mangle] -pub extern "C" fn wgpu_compute_pass_push_debug_group( - _pass_id: id::ComputePassId, - _label: core::RawString, -) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_pop_debug_group(_pass_id: id::ComputePassId) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_insert_debug_marker( - _pass_id: id::ComputePassId, - _label: core::RawString, -) { - //TODO -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_dispatch(pass_id: id::ComputePassId, x: u32, y: u32, z: u32) { - gfx_select!(pass_id => GLOBAL.compute_pass_dispatch(pass_id, x, y, z)) -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_dispatch_indirect( - pass_id: id::ComputePassId, - indirect_buffer_id: id::BufferId, - indirect_offset: core::BufferAddress, -) { - gfx_select!(pass_id => GLOBAL.compute_pass_dispatch_indirect(pass_id, indirect_buffer_id, indirect_offset)) -} - -#[no_mangle] -pub extern "C" fn wgpu_compute_pass_set_pipeline( - pass_id: id::ComputePassId, - pipeline_id: id::ComputePipelineId, -) { - 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>, - pass: &core::command::RawPass, -) { - let color_attachments = slice::from_raw_parts(color_attachments, color_attachment_length); - let raw_data = pass.to_slice(); - gfx_select!(self_id => GLOBAL.command_encoder_run_render_pass(self_id, color_attachments, depth_stencil_attachment, raw_data)); +pub unsafe extern "C" fn wgpu_compute_pass_end_pass(pass_id: core::command::RawComputePassId) { + let (pass_data, encoder_id) = Box::from_raw(pass_id).finish_compute(); + gfx_select!(encoder_id => GLOBAL.command_encoder_run_compute_pass(encoder_id, &pass_data)) } diff --git a/wgpu-remote/src/server.rs b/wgpu-remote/src/server.rs index a8ff5dd329..abe7a6947a 100644 --- a/wgpu-remote/src/server.rs +++ b/wgpu-remote/src/server.rs @@ -116,11 +116,10 @@ pub extern "C" fn wgpu_server_device_create_encoder( #[no_mangle] pub extern "C" fn wgpu_server_encoder_destroy( - _global: &Global, - _self_id: id::CommandEncoderId, + global: &Global, + self_id: id::CommandEncoderId, ) { - //TODO - //gfx_select!(self_id => global.command_encoder_destroy(self_id)); + gfx_select!(self_id => global.command_encoder_destroy(self_id)); } #[no_mangle] From e0574ee899c38a5d3ecc404a2e559a4e3d28f0ac Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 12 Jan 2020 00:25:19 -0500 Subject: [PATCH 6/9] Remove the old render and compute passes --- examples/compute/main.c | 2 +- examples/triangle/main.c | 2 +- ffi/wgpu.h | 106 +++--- wgpu-core/src/command/compute.rs | 221 +----------- wgpu-core/src/command/mod.rs | 542 +---------------------------- wgpu-core/src/command/render.rs | 574 +------------------------------ wgpu-core/src/hub.rs | 20 +- wgpu-core/src/id.rs | 4 +- wgpu-native/src/command.rs | 10 +- 9 files changed, 71 insertions(+), 1410 deletions(-) diff --git a/examples/compute/main.c b/examples/compute/main.c index a2df235e62..ef752ce2ef 100644 --- a/examples/compute/main.c +++ b/examples/compute/main.c @@ -127,7 +127,7 @@ int main( .todo = 0 }); - WGPURawComputePassId command_pass = //temp name + WGPUComputePassId command_pass = wgpu_command_encoder_begin_compute_pass(encoder, NULL); wgpu_compute_pass_set_pipeline(command_pass, compute_pipeline); diff --git a/examples/triangle/main.c b/examples/triangle/main.c index 50080e2ce3..05eab3e59a 100644 --- a/examples/triangle/main.c +++ b/examples/triangle/main.c @@ -249,7 +249,7 @@ int main() { }, }; - WGPURawRenderPassId rpass = + WGPURenderPassId rpass = wgpu_command_encoder_begin_render_pass(cmd_encoder, &(WGPURenderPassDescriptor){ .color_attachments = color_attachments, diff --git a/ffi/wgpu.h b/ffi/wgpu.h index 310f260734..03d186891d 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -303,8 +303,6 @@ typedef struct { WGPUCommandEncoderId parent; } WGPURawPass; -typedef WGPURawPass *WGPURawComputePassId; - typedef struct { uint32_t todo; } WGPUComputePassDescriptor; @@ -358,8 +356,6 @@ typedef struct { WGPURawRenderTargets targets; } WGPURawRenderPass; -typedef WGPURawRenderPass *WGPURawRenderPassId; - typedef const WGPUTextureViewId *WGPUOptionRef_TextureViewId; typedef struct { @@ -413,6 +409,8 @@ typedef struct { uint32_t todo; } WGPUCommandBufferDescriptor; +typedef WGPURawPass *WGPUComputePassId; + typedef const char *WGPURawString; typedef uint64_t WGPUId_ComputePipeline_Dummy; @@ -680,6 +678,8 @@ typedef struct { typedef WGPUDeviceId WGPUQueueId; +typedef WGPURawRenderPass *WGPURenderPassId; + typedef uint64_t WGPUId_RenderBundle_Dummy; typedef WGPUId_RenderBundle_Dummy WGPURenderBundleId; @@ -729,11 +729,11 @@ void wgpu_buffer_unmap(WGPUBufferId buffer_id); void wgpu_command_buffer_destroy(WGPUCommandBufferId command_buffer_id); -WGPURawComputePassId wgpu_command_encoder_begin_compute_pass(WGPUCommandEncoderId encoder_id, - const WGPUComputePassDescriptor *_desc); +WGPURawPass *wgpu_command_encoder_begin_compute_pass(WGPUCommandEncoderId encoder_id, + const WGPUComputePassDescriptor *_desc); -WGPURawRenderPassId wgpu_command_encoder_begin_render_pass(WGPUCommandEncoderId encoder_id, - const WGPURenderPassDescriptor *desc); +WGPURawRenderPass *wgpu_command_encoder_begin_render_pass(WGPUCommandEncoderId encoder_id, + const WGPURenderPassDescriptor *desc); void wgpu_command_encoder_copy_buffer_to_buffer(WGPUCommandEncoderId command_encoder_id, WGPUBufferId source, @@ -771,7 +771,7 @@ void wgpu_compute_pass_dispatch_indirect(WGPURawPass *pass, WGPUBufferId buffer_id, WGPUBufferAddress offset); -void wgpu_compute_pass_end_pass(WGPURawComputePassId pass_id); +void wgpu_compute_pass_end_pass(WGPUComputePassId pass_id); void wgpu_compute_pass_insert_debug_marker(WGPURawPass *_pass, WGPURawString _label); @@ -842,63 +842,63 @@ void wgpu_queue_submit(WGPUQueueId queue_id, const WGPUCommandBufferId *command_buffers, uintptr_t command_buffers_length); -void wgpu_raw_render_pass_draw(WGPURawRenderPass *pass, - uint32_t vertex_count, - uint32_t instance_count, - uint32_t first_vertex, - uint32_t first_instance); - -void wgpu_raw_render_pass_draw_indirect(WGPURawRenderPass *pass, - WGPUBufferId buffer_id, - WGPUBufferAddress offset); +void wgpu_render_pass_draw(WGPURawRenderPass *pass, + uint32_t vertex_count, + uint32_t instance_count, + uint32_t first_vertex, + uint32_t first_instance); -void wgpu_raw_render_pass_set_bind_group(WGPURawRenderPass *pass, - uint32_t index, - WGPUBindGroupId bind_group_id, - const WGPUBufferAddress *offsets, - uintptr_t offset_length); +void wgpu_render_pass_draw_indirect(WGPURawRenderPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); -void wgpu_raw_render_pass_set_blend_color(WGPURawRenderPass *pass, const WGPUColor *color); +void wgpu_render_pass_end_pass(WGPURenderPassId pass_id); -void wgpu_raw_render_pass_set_index_buffer(WGPURawRenderPass *pass, - WGPUBufferId buffer_id, - WGPUBufferAddress offset); +void wgpu_render_pass_execute_bundles(WGPURawRenderPass *_pass, + const WGPURenderBundleId *_bundles, + uintptr_t _bundles_length); -void wgpu_raw_render_pass_set_pipeline(WGPURawRenderPass *pass, WGPURenderPipelineId pipeline_id); +void wgpu_render_pass_insert_debug_marker(WGPURawRenderPass *_pass, WGPURawString _label); -void wgpu_raw_render_pass_set_scissor(WGPURawRenderPass *pass, - uint32_t x, - uint32_t y, - uint32_t w, - uint32_t h); +void wgpu_render_pass_pop_debug_group(WGPURawRenderPass *_pass); -void wgpu_raw_render_pass_set_stencil_reference(WGPURawRenderPass *pass, uint32_t value); +void wgpu_render_pass_push_debug_group(WGPURawRenderPass *_pass, WGPURawString _label); -void wgpu_raw_render_pass_set_vertex_buffers(WGPURawRenderPass *pass, - uint32_t start_slot, - const WGPUBufferId *buffer_ids, - const WGPUBufferAddress *offsets, - uintptr_t length); +void wgpu_render_pass_set_bind_group(WGPURawRenderPass *pass, + uint32_t index, + WGPUBindGroupId bind_group_id, + const WGPUBufferAddress *offsets, + uintptr_t offset_length); -void wgpu_raw_render_pass_set_viewport(WGPURawRenderPass *pass, - float x, - float y, - float w, - float h, - float depth_min, - float depth_max); +void wgpu_render_pass_set_blend_color(WGPURawRenderPass *pass, const WGPUColor *color); -void wgpu_render_pass_end_pass(WGPURawRenderPassId pass_id); +void wgpu_render_pass_set_index_buffer(WGPURawRenderPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); -void wgpu_render_pass_execute_bundles(WGPURawRenderPass *_pass, - const WGPURenderBundleId *_bundles, - uintptr_t _bundles_length); +void wgpu_render_pass_set_pipeline(WGPURawRenderPass *pass, WGPURenderPipelineId pipeline_id); -void wgpu_render_pass_insert_debug_marker(WGPURawRenderPass *_pass, WGPURawString _label); +void wgpu_render_pass_set_scissor(WGPURawRenderPass *pass, + uint32_t x, + uint32_t y, + uint32_t w, + uint32_t h); -void wgpu_render_pass_pop_debug_group(WGPURawRenderPass *_pass); +void wgpu_render_pass_set_stencil_reference(WGPURawRenderPass *pass, uint32_t value); -void wgpu_render_pass_push_debug_group(WGPURawRenderPass *_pass, WGPURawString _label); +void wgpu_render_pass_set_vertex_buffers(WGPURawRenderPass *pass, + uint32_t start_slot, + const WGPUBufferId *buffer_ids, + const WGPUBufferAddress *offsets, + uintptr_t length); + +void wgpu_render_pass_set_viewport(WGPURawRenderPass *pass, + float x, + float y, + float w, + float h, + float depth_min, + float depth_max); void wgpu_request_adapter_async(const WGPURequestAdapterOptions *desc, WGPUBackendBit mask, diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index d4d503d0ab..d145b5e128 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -9,12 +9,10 @@ use crate::{ PhantomSlice, }, device::{all_buffer_stages, BIND_BUFFER_ALIGNMENT}, - hub::{GfxBackend, Global, IdentityFilter, Token}, + hub::{GfxBackend, Global, Token}, id, resource::BufferUsage, - track::TrackerSet, BufferAddress, - Stored, }; use hal::command::CommandBuffer as _; @@ -56,48 +54,8 @@ pub struct ComputePassDescriptor { pub todo: u32, } -#[derive(Debug)] -pub struct ComputePass { - raw: B::CommandBuffer, - cmb_id: Stored, - binder: Binder, - trackers: TrackerSet, -} - -impl ComputePass { - pub(crate) fn new( - raw: B::CommandBuffer, - cmb_id: Stored, - trackers: TrackerSet, - max_bind_groups: u32, - ) -> Self { - ComputePass { - raw, - cmb_id, - binder: Binder::new(max_bind_groups), - trackers, - } - } -} - // Common routines between render/compute -impl> Global { - pub fn compute_pass_end_pass(&self, pass_id: id::ComputePassId) { - let mut token = Token::root(); - let hub = B::hub(self); - let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); - let (pass, _) = hub.compute_passes.unregister(pass_id, &mut token); - let cmb = &mut cmb_guard[pass.cmb_id.value]; - - // There are no transitions to be made: we've already been inserting barriers - // into the parent command buffer while recording this compute pass. - log::debug!("Compute pass {:?} {:#?}", pass_id, pass.trackers); - cmb.trackers = pass.trackers; - cmb.raw.push(pass.raw); - } -} - impl Global { pub fn command_encoder_run_compute_pass( &self, @@ -253,183 +211,6 @@ impl Global { } } } - - pub fn compute_pass_set_bind_group( - &self, - pass_id: id::ComputePassId, - index: u32, - bind_group_id: id::BindGroupId, - offsets: &[BufferAddress], - ) { - let hub = B::hub(self); - let mut token = Token::root(); - - let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); - let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); - let (mut pass_guard, mut token) = hub.compute_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - let bind_group = pass - .trackers - .bind_groups - .use_extend(&*bind_group_guard, bind_group_id, (), ()) - .unwrap(); - - assert_eq!(bind_group.dynamic_count, offsets.len()); - - if cfg!(debug_assertions) { - for off in offsets { - assert_eq!( - *off % BIND_BUFFER_ALIGNMENT, - 0, - "Misaligned dynamic buffer offset: {} does not align with {}", - off, - BIND_BUFFER_ALIGNMENT - ); - } - } - - //Note: currently, WebGPU compute passes have synchronization defined - // at a dispatch granularity, so we insert the necessary barriers here. - let (buffer_guard, mut token) = hub.buffers.read(&mut token); - let (texture_guard, _) = hub.textures.read(&mut token); - - log::trace!( - "Encoding barriers on binding of {:?} in pass {:?}", - bind_group_id, - pass_id - ); - CommandBuffer::insert_barriers( - &mut pass.raw, - &mut pass.trackers, - &bind_group.used, - &*buffer_guard, - &*texture_guard, - ); - - if let Some((pipeline_layout_id, follow_ups)) = pass - .binder - .provide_entry(index as usize, bind_group_id, bind_group, offsets) - { - let bind_groups = iter::once(bind_group.raw.raw()) - .chain(follow_ups.clone().map(|(bg_id, _)| bind_group_guard[bg_id].raw.raw())); - unsafe { - pass.raw.bind_compute_descriptor_sets( - &pipeline_layout_guard[pipeline_layout_id].raw, - index as usize, - bind_groups, - offsets - .iter() - .chain(follow_ups.flat_map(|(_, offsets)| offsets)) - .map(|&off| off as hal::command::DescriptorSetOffset), - ); - } - }; - } - - // Compute-specific routines - - pub fn compute_pass_dispatch( - &self, - pass_id: id::ComputePassId, - x: u32, - y: u32, - z: u32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.compute_passes.write(&mut token); - unsafe { - pass_guard[pass_id].raw.dispatch([x, y, z]); - } - } - - pub fn compute_pass_dispatch_indirect( - &self, - pass_id: id::ComputePassId, - indirect_buffer_id: id::BufferId, - indirect_offset: BufferAddress, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, mut token) = hub.compute_passes.write(&mut token); - let (buffer_guard, _) = hub.buffers.read(&mut token); - - let pass = &mut pass_guard[pass_id]; - - let (src_buffer, src_pending) = pass.trackers.buffers.use_replace( - &*buffer_guard, - indirect_buffer_id, - (), - BufferUsage::INDIRECT, - ); - assert!(src_buffer.usage.contains(BufferUsage::INDIRECT)); - - let barriers = src_pending.map(|pending| pending.into_hal(src_buffer)); - - unsafe { - pass.raw.pipeline_barrier( - all_buffer_stages() .. all_buffer_stages(), - hal::memory::Dependencies::empty(), - barriers, - ); - pass.raw.dispatch_indirect(&src_buffer.raw, indirect_offset); - } - } - - pub fn compute_pass_set_pipeline( - &self, - pass_id: id::ComputePassId, - pipeline_id: id::ComputePipelineId, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); - let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); - let (mut pass_guard, mut token) = hub.compute_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - let (pipeline_guard, _) = hub.compute_pipelines.read(&mut token); - let pipeline = &pipeline_guard[pipeline_id]; - - unsafe { - pass.raw.bind_compute_pipeline(&pipeline.raw); - } - - // Rebind resources - if pass.binder.pipeline_layout_id != Some(pipeline.layout_id) { - let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id]; - pass.binder.pipeline_layout_id = Some(pipeline.layout_id); - pass.binder - .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); - let mut is_compatible = true; - - for (index, (entry, &bgl_id)) in pass - .binder - .entries - .iter_mut() - .zip(&pipeline_layout.bind_group_layout_ids) - .enumerate() - { - match entry.expect_layout(bgl_id) { - LayoutChange::Match(bg_id, offsets) if is_compatible => { - let desc_set = bind_group_guard[bg_id].raw.raw(); - unsafe { - pass.raw.bind_compute_descriptor_sets( - &pipeline_layout.raw, - index, - iter::once(desc_set), - offsets.iter().map(|offset| *offset as u32), - ); - } - } - LayoutChange::Match(..) | LayoutChange::Unchanged => {} - LayoutChange::Mismatch => { - is_compatible = false; - } - } - } - } - } } mod ffi { diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 87b99af92f..d623e646df 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -14,35 +14,21 @@ pub use self::render::*; pub use self::transfer::*; use crate::{ - conv, device::{ MAX_COLOR_TARGETS, all_buffer_stages, all_image_stages, - FramebufferKey, - RenderPassContext, - RenderPassKey, }, - hub::{GfxBackend, Global, IdentityFilter, Storage, Token}, + hub::{GfxBackend, Global, Storage, Token}, id, - resource::{Buffer, Texture, TextureUsage, TextureViewInner}, + resource::{Buffer, Texture}, track::TrackerSet, Features, LifeGuard, Stored, }; -use arrayvec::ArrayVec; -use hal::{ - adapter::PhysicalDevice as _, - command::CommandBuffer as _, - device::Device as _, -}; - use std::{ - borrow::Borrow, - collections::hash_map::Entry, - iter, marker::PhantomData, mem, slice, @@ -50,9 +36,6 @@ use std::{ }; -pub type RawRenderPassId = *mut RawRenderPass; -pub type RawComputePassId = *mut RawPass; - #[derive(Clone, Copy, Debug, peek_poke::PeekCopy, peek_poke::Poke)] struct PhantomSlice(PhantomData); @@ -165,6 +148,8 @@ impl CommandBuffer { buffer_guard: &Storage, id::BufferId>, texture_guard: &Storage, id::TextureId>, ) { + use hal::command::CommandBuffer as _; + debug_assert_eq!(B::VARIANT, base.backend()); debug_assert_eq!(B::VARIANT, head.backend()); @@ -215,7 +200,7 @@ pub struct CommandBufferDescriptor { pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass( encoder_id: id::CommandEncoderId, _desc: Option<&ComputePassDescriptor>, -) -> RawComputePassId { +) -> *mut RawPass { let pass = RawPass::new_compute(encoder_id); Box::into_raw(Box::new(pass)) } @@ -239,7 +224,7 @@ pub struct RawRenderPass { pub unsafe extern "C" fn wgpu_command_encoder_begin_render_pass( encoder_id: id::CommandEncoderId, desc: &RenderPassDescriptor, -) -> RawRenderPassId { +) -> *mut RawRenderPass { let mut colors: [RawRenderPassColorAttachmentDescriptor; MAX_COLOR_TARGETS] = mem::zeroed(); for (color, at) in colors .iter_mut() @@ -286,518 +271,3 @@ impl Global { encoder_id } } - -impl> Global { - pub fn command_encoder_begin_render_pass( - &self, - encoder_id: id::CommandEncoderId, - desc: &RenderPassDescriptor, - id_in: F::Input, - ) -> id::RenderPassId { - let hub = B::hub(self); - let mut token = Token::root(); - - let (adapter_guard, mut token) = hub.adapters.read(&mut token); - let (device_guard, mut token) = hub.devices.read(&mut token); - let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); - let cmb = &mut cmb_guard[encoder_id]; - let device = &device_guard[cmb.device_id.value]; - - let limits = adapter_guard[device.adapter_id] - .raw - .physical_device - .limits(); - let samples_count_limit = limits.framebuffer_color_sample_counts; - - let mut current_comb = device.com_allocator.extend(cmb); - unsafe { - current_comb.begin( - hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, - hal::command::CommandBufferInheritanceInfo::default(), - ); - } - - let pass = { - let (_, mut token) = hub.buffers.read(&mut token); //skip token - let (texture_guard, mut token) = hub.textures.read(&mut token); - let (view_guard, _) = hub.texture_views.read(&mut token); - - let mut extent = None; - let mut used_swap_chain_image = None::>; - - let color_attachments = unsafe { - slice::from_raw_parts(desc.color_attachments, desc.color_attachments_length) - }; - let depth_stencil_attachment = desc.depth_stencil_attachment; - - let sample_count = color_attachments - .get(0) - .map(|at| view_guard[at.attachment].samples) - .unwrap_or(1); - assert!( - sample_count & samples_count_limit != 0, - "Attachment sample_count must be supported by physical device limits" - ); - - const MAX_TOTAL_ATTACHMENTS: usize = 10; - type OutputAttachment<'a> = ( - &'a Stored, - &'a hal::image::SubresourceRange, - Option, - ); - let mut output_attachments = ArrayVec::<[OutputAttachment; MAX_TOTAL_ATTACHMENTS]>::new(); - - log::trace!( - "Encoding render pass begin in command buffer {:?}", - encoder_id - ); - let rp_key = { - let depth_stencil = match depth_stencil_attachment { - Some(at) => { - let view = cmb.trackers - .views - .use_extend(&*view_guard, at.attachment, (), ()) - .unwrap(); - if let Some(ex) = extent { - assert_eq!(ex, view.extent); - } else { - extent = Some(view.extent); - } - let source_id = match view.inner { - TextureViewInner::Native { ref source_id, .. } => source_id, - TextureViewInner::SwapChain { .. } => { - panic!("Unexpected depth/stencil use of swapchain image!") - } - }; - - // Using render pass for transition. - let consistent_usage = cmb.trackers.textures.query( - source_id.value, - view.range.clone(), - ); - output_attachments.push((source_id, &view.range, consistent_usage)); - - let old_layout = match consistent_usage { - Some(usage) => conv::map_texture_state( - usage, - hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL, - ).1, - None => hal::image::Layout::DepthStencilAttachmentOptimal, - }; - - Some(hal::pass::Attachment { - format: Some(conv::map_texture_format(view.format, device.features)), - samples: view.samples, - ops: conv::map_load_store_ops(at.depth_load_op, at.depth_store_op), - stencil_ops: conv::map_load_store_ops( - at.stencil_load_op, - at.stencil_store_op, - ), - layouts: old_layout .. hal::image::Layout::DepthStencilAttachmentOptimal, - }) - } - None => None, - }; - - let mut colors = ArrayVec::new(); - let mut resolves = ArrayVec::new(); - - for at in color_attachments { - let view = &view_guard[at.attachment]; - if let Some(ex) = extent { - assert_eq!(ex, view.extent); - } else { - extent = Some(view.extent); - } - assert_eq!( - view.samples, sample_count, - "All attachments must have the same sample_count" - ); - let first_use = cmb.trackers.views.init( - at.attachment, - view.life_guard.add_ref(), - PhantomData, - ).is_ok(); - - let layouts = match view.inner { - TextureViewInner::Native { ref source_id, .. } => { - let consistent_usage = cmb.trackers.textures.query( - source_id.value, - view.range.clone(), - ); - output_attachments.push((source_id, &view.range, consistent_usage)); - - let old_layout = match consistent_usage { - Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1, - None => hal::image::Layout::ColorAttachmentOptimal, - }; - old_layout .. hal::image::Layout::ColorAttachmentOptimal - } - TextureViewInner::SwapChain { .. } => { - if let Some((ref view_id, _)) = cmb.used_swap_chain { - assert_eq!(view_id.value, at.attachment); - } else { - assert!(used_swap_chain_image.is_none()); - used_swap_chain_image = Some(Stored { - value: at.attachment, - ref_count: view.life_guard.add_ref(), - }); - } - - let end = hal::image::Layout::Present; - let start = if first_use { - hal::image::Layout::Undefined - } else { - end - }; - start .. end - } - }; - - colors.push(hal::pass::Attachment { - format: Some(conv::map_texture_format(view.format, device.features)), - samples: view.samples, - ops: conv::map_load_store_ops(at.load_op, at.store_op), - stencil_ops: hal::pass::AttachmentOps::DONT_CARE, - layouts, - }); - } - - for &resolve_target in color_attachments - .iter() - .flat_map(|at| at.resolve_target) - { - let view = &view_guard[resolve_target]; - assert_eq!(extent, Some(view.extent)); - assert_eq!( - view.samples, 1, - "All resolve_targets must have a sample_count of 1" - ); - let first_use = cmb.trackers.views.init( - resolve_target, - view.life_guard.add_ref(), - PhantomData, - ).is_ok(); - - let layouts = match view.inner { - TextureViewInner::Native { ref source_id, .. } => { - let consistent_usage = cmb.trackers.textures.query( - source_id.value, - view.range.clone(), - ); - output_attachments.push((source_id, &view.range, consistent_usage)); - - let old_layout = match consistent_usage { - Some(usage) => conv::map_texture_state(usage, hal::format::Aspects::COLOR).1, - None => hal::image::Layout::ColorAttachmentOptimal, - }; - old_layout .. hal::image::Layout::ColorAttachmentOptimal - } - TextureViewInner::SwapChain { .. } => { - if let Some((ref view_id, _)) = cmb.used_swap_chain { - assert_eq!(view_id.value, resolve_target); - } else { - assert!(used_swap_chain_image.is_none()); - used_swap_chain_image = Some(Stored { - value: resolve_target, - ref_count: view.life_guard.add_ref(), - }); - } - - let end = hal::image::Layout::Present; - let start = if first_use { - hal::image::Layout::Undefined - } else { - end - }; - start .. end - } - }; - - resolves.push(hal::pass::Attachment { - format: Some(conv::map_texture_format(view.format, device.features)), - samples: view.samples, - ops: hal::pass::AttachmentOps::new( - hal::pass::AttachmentLoadOp::DontCare, - hal::pass::AttachmentStoreOp::Store, - ), - stencil_ops: hal::pass::AttachmentOps::DONT_CARE, - layouts, - }); - } - - RenderPassKey { - colors, - resolves, - depth_stencil, - } - }; - - let mut trackers = TrackerSet::new(B::VARIANT); - for (source_id, view_range, consistent_usage) in output_attachments { - let texture = &texture_guard[source_id.value]; - assert!(texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT)); - - let usage = consistent_usage.unwrap_or(TextureUsage::OUTPUT_ATTACHMENT); - // this is important to record the `first` state. - let _ = trackers.textures.change_replace( - source_id.value, - &source_id.ref_count, - view_range.clone(), - usage, - ); - if consistent_usage.is_some() { - // If we expect the texture to be transited to a new state by the - // render pass configuration, make the tracker aware of that. - let _ = trackers.textures.change_replace( - source_id.value, - &source_id.ref_count, - view_range.clone(), - TextureUsage::OUTPUT_ATTACHMENT, - ); - }; - } - - let mut render_pass_cache = device.render_passes.lock(); - let render_pass = match render_pass_cache.entry(rp_key.clone()) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(e) => { - let color_ids = [ - (0, hal::image::Layout::ColorAttachmentOptimal), - (1, hal::image::Layout::ColorAttachmentOptimal), - (2, hal::image::Layout::ColorAttachmentOptimal), - (3, hal::image::Layout::ColorAttachmentOptimal), - ]; - - let mut resolve_ids = ArrayVec::<[_; MAX_COLOR_TARGETS]>::new(); - let mut attachment_index = color_attachments.len(); - if color_attachments - .iter() - .any(|at| at.resolve_target.is_some()) - { - for (i, at) in color_attachments.iter().enumerate() { - if at.resolve_target.is_none() { - resolve_ids.push(( - hal::pass::ATTACHMENT_UNUSED, - hal::image::Layout::ColorAttachmentOptimal, - )); - } else { - let sample_count_check = - view_guard[color_attachments[i].attachment].samples; - assert!(sample_count_check > 1, "RenderPassColorAttachmentDescriptor with a resolve_target must have an attachment with sample_count > 1"); - resolve_ids.push(( - attachment_index, - hal::image::Layout::ColorAttachmentOptimal, - )); - attachment_index += 1; - } - } - } - - let depth_id = ( - attachment_index, - hal::image::Layout::DepthStencilAttachmentOptimal, - ); - - let subpass = hal::pass::SubpassDesc { - colors: &color_ids[.. color_attachments.len()], - resolves: &resolve_ids, - depth_stencil: depth_stencil_attachment.map(|_| &depth_id), - inputs: &[], - preserves: &[], - }; - - let pass = unsafe { - device - .raw - .create_render_pass(e.key().all(), &[subpass], &[]) - } - .unwrap(); - e.insert(pass) - } - }; - - let mut framebuffer_cache; - let fb_key = FramebufferKey { - colors: color_attachments.iter().map(|at| at.attachment).collect(), - resolves: color_attachments - .iter() - .filter_map(|at| at.resolve_target) - .cloned() - .collect(), - depth_stencil: depth_stencil_attachment.map(|at| at.attachment), - }; - - let framebuffer = match used_swap_chain_image.take() { - Some(view_id) => { - assert!(cmb.used_swap_chain.is_none()); - // Always create a new framebuffer and delete it after presentation. - let attachments = fb_key.all().map(|&id| match view_guard[id].inner { - TextureViewInner::Native { ref raw, .. } => raw, - TextureViewInner::SwapChain { ref image, .. } => Borrow::borrow(image), - }); - let framebuffer = unsafe { - device - .raw - .create_framebuffer(&render_pass, attachments, extent.unwrap()) - .unwrap() - }; - cmb.used_swap_chain = Some((view_id, framebuffer)); - &mut cmb.used_swap_chain.as_mut().unwrap().1 - } - None => { - // Cache framebuffers by the device. - framebuffer_cache = device.framebuffers.lock(); - match framebuffer_cache.entry(fb_key) { - Entry::Occupied(e) => e.into_mut(), - Entry::Vacant(e) => { - let fb = { - let attachments = - e.key().all().map(|&id| match view_guard[id].inner { - TextureViewInner::Native { ref raw, .. } => raw, - TextureViewInner::SwapChain { ref image, .. } => { - Borrow::borrow(image) - } - }); - unsafe { - device.raw.create_framebuffer( - &render_pass, - attachments, - extent.unwrap(), - ) - } - .unwrap() - }; - e.insert(fb) - } - } - } - }; - - let rect = { - let ex = extent.unwrap(); - hal::pso::Rect { - x: 0, - y: 0, - w: ex.width as _, - h: ex.height as _, - } - }; - - let clear_values = color_attachments - .iter() - .zip(&rp_key.colors) - .flat_map(|(at, key)| { - match at.load_op { - LoadOp::Load => None, - LoadOp::Clear => { - use hal::format::ChannelType; - //TODO: validate sign/unsign and normalized ranges of the color values - let value = match key.format.unwrap().base_format().1 { - ChannelType::Unorm - | ChannelType::Snorm - | ChannelType::Ufloat - | ChannelType::Sfloat - | ChannelType::Uscaled - | ChannelType::Sscaled - | ChannelType::Srgb => hal::command::ClearColor { - float32: conv::map_color_f32(&at.clear_color), - }, - ChannelType::Sint => hal::command::ClearColor { - sint32: conv::map_color_i32(&at.clear_color), - }, - ChannelType::Uint => hal::command::ClearColor { - uint32: conv::map_color_u32(&at.clear_color), - }, - }; - Some(hal::command::ClearValue { color: value }) - } - } - }) - .chain(depth_stencil_attachment.and_then(|at| { - match (at.depth_load_op, at.stencil_load_op) { - (LoadOp::Load, LoadOp::Load) => None, - (LoadOp::Clear, _) | (_, LoadOp::Clear) => { - let value = hal::command::ClearDepthStencil { - depth: at.clear_depth, - stencil: at.clear_stencil, - }; - Some(hal::command::ClearValue { - depth_stencil: value, - }) - } - } - })); - - unsafe { - current_comb.begin_render_pass( - render_pass, - framebuffer, - rect, - clear_values, - hal::command::SubpassContents::Inline, - ); - current_comb.set_scissors(0, iter::once(&rect)); - current_comb.set_viewports( - 0, - iter::once(hal::pso::Viewport { - rect, - depth: 0.0 .. 1.0, - }), - ); - } - - let context = RenderPassContext { - colors: color_attachments - .iter() - .map(|at| view_guard[at.attachment].format) - .collect(), - resolves: color_attachments - .iter() - .filter_map(|at| at.resolve_target) - .map(|resolve| view_guard[*resolve].format) - .collect(), - depth_stencil: depth_stencil_attachment.map(|at| view_guard[at.attachment].format), - }; - - RenderPass::new( - current_comb, - Stored { - value: encoder_id, - ref_count: cmb.life_guard.add_ref(), - }, - context, - trackers, - sample_count, - cmb.features.max_bind_groups, - ) - }; - hub.render_passes.register_identity(id_in, pass, &mut token) - } -} - -impl> Global { - pub fn command_encoder_begin_compute_pass( - &self, - encoder_id: id::CommandEncoderId, - _desc: &ComputePassDescriptor, - id_in: F::Input, - ) -> id::ComputePassId { - let hub = B::hub(self); - let mut token = Token::root(); - - let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); - let cmb = &mut cmb_guard[encoder_id]; - - let raw = cmb.raw.pop().unwrap(); - let trackers = mem::replace(&mut cmb.trackers, TrackerSet::new(encoder_id.backend())); - let stored = Stored { - value: encoder_id, - ref_count: cmb.life_guard.add_ref(), - }; - - let pass = ComputePass::new(raw, stored, trackers, cmb.features.max_bind_groups); - hub.compute_passes - .register_identity(id_in, pass, &mut token) - } -} diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index d1daf64468..299f8d8b5e 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -5,7 +5,6 @@ use crate::{ command::{ bind::{Binder, LayoutChange}, - CommandBuffer, PhantomSlice, RawRenderTargets, }, @@ -18,7 +17,7 @@ use crate::{ MAX_VERTEX_BUFFERS, MAX_COLOR_TARGETS, }, - hub::{GfxBackend, Global, IdentityFilter, Token}, + hub::{GfxBackend, Global, Token}, id, pipeline::{IndexFormat, InputStepMode, PipelineFlags}, resource::{BufferUsage, TextureUsage, TextureViewInner}, @@ -282,114 +281,8 @@ impl State { } } -#[derive(Debug)] -pub struct RenderPass { - raw: B::CommandBuffer, - cmb_id: Stored, - context: RenderPassContext, - binder: Binder, - trackers: TrackerSet, - blend_color_status: OptionalState, - stencil_reference_status: OptionalState, - index_state: IndexState, - vertex_state: VertexState, - sample_count: u8, -} - -impl RenderPass { - pub(crate) fn new( - raw: B::CommandBuffer, - cmb_id: Stored, - context: RenderPassContext, - trackers: TrackerSet, - sample_count: u8, - max_bind_groups: u32, - ) -> Self { - RenderPass { - raw, - cmb_id, - context, - binder: Binder::new(max_bind_groups), - trackers, - blend_color_status: OptionalState::Unused, - stencil_reference_status: OptionalState::Unused, - index_state: IndexState { - bound_buffer_view: None, - format: IndexFormat::Uint16, - limit: 0, - }, - vertex_state: VertexState { - inputs: [VertexBufferState::EMPTY; MAX_VERTEX_BUFFERS], - vertex_limit: 0, - instance_limit: 0, - }, - sample_count, - } - } - - fn is_ready(&self) -> Result<(), DrawError> { - //TODO: vertex buffers - let bind_mask = self.binder.invalid_mask(); - if bind_mask != 0 { - //let (expected, provided) = self.binder.entries[index as usize].info(); - return Err(DrawError::IncompatibleBindGroup { - index: bind_mask.trailing_zeros() as u32, - }); - } - if self.blend_color_status == OptionalState::Required { - return Err(DrawError::MissingBlendColor); - } - if self.stencil_reference_status == OptionalState::Required { - return Err(DrawError::MissingStencilReference); - } - Ok(()) - } -} - // Common routines between render/compute -impl> Global { - pub fn render_pass_end_pass(&self, pass_id: id::RenderPassId) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); - let (mut pass, mut token) = hub.render_passes.unregister(pass_id, &mut token); - unsafe { - pass.raw.end_render_pass(); - } - pass.trackers.optimize(); - log::debug!("Render pass {:?} {:#?}", pass_id, pass.trackers); - - let cmb = &mut cmb_guard[pass.cmb_id.value]; - let (buffer_guard, mut token) = hub.buffers.read(&mut token); - let (texture_guard, _) = hub.textures.read(&mut token); - - match cmb.raw.last_mut() { - Some(last) => { - log::trace!("Encoding barriers before pass {:?}", pass_id); - CommandBuffer::insert_barriers( - last, - &mut cmb.trackers, - &pass.trackers, - &*buffer_guard, - &*texture_guard, - ); - unsafe { last.finish() }; - } - None => { - cmb.trackers.merge_extend(&pass.trackers); - } - } - - if false { - log::debug!("Command buffer {:?} after render pass {:#?}", - pass.cmb_id.value, cmb.trackers); - } - - cmb.raw.push(pass.raw); - } -} - impl Global { pub fn command_encoder_run_render_pass( &self, @@ -1201,471 +1094,6 @@ impl Global { } } } - - pub fn render_pass_set_bind_group( - &self, - pass_id: id::RenderPassId, - index: u32, - bind_group_id: id::BindGroupId, - offsets: &[BufferAddress], - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); - let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); - - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - let bind_group = pass - .trackers - .bind_groups - .use_extend(&*bind_group_guard, bind_group_id, (), ()) - .unwrap(); - - assert_eq!(bind_group.dynamic_count, offsets.len()); - - if cfg!(debug_assertions) { - for off in offsets { - assert_eq!( - *off % BIND_BUFFER_ALIGNMENT, - 0, - "Misaligned dynamic buffer offset: {} does not align with {}", - off, - BIND_BUFFER_ALIGNMENT - ); - } - } - - pass.trackers.merge_extend(&bind_group.used); - - if let Some((pipeline_layout_id, follow_ups)) = pass - .binder - .provide_entry(index as usize, bind_group_id, bind_group, offsets) - { - let bind_groups = iter::once(bind_group.raw.raw()) - .chain(follow_ups.clone().map(|(bg_id, _)| bind_group_guard[bg_id].raw.raw())); - unsafe { - pass.raw.bind_graphics_descriptor_sets( - &&pipeline_layout_guard[pipeline_layout_id].raw, - index as usize, - bind_groups, - offsets - .iter() - .chain(follow_ups.flat_map(|(_, offsets)| offsets)) - .map(|&off| off as hal::command::DescriptorSetOffset), - ); - } - }; - } - - // Render-specific routines - - pub fn render_pass_set_index_buffer( - &self, - pass_id: id::RenderPassId, - buffer_id: id::BufferId, - offset: BufferAddress, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, mut token) = hub.render_passes.write(&mut token); - let (buffer_guard, _) = hub.buffers.read(&mut token); - - let pass = &mut pass_guard[pass_id]; - let buffer = pass - .trackers - .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX) - .unwrap(); - assert!(buffer.usage.contains(BufferUsage::INDEX)); - - let range = offset .. buffer.size; - pass.index_state.bound_buffer_view = Some((buffer_id, range)); - pass.index_state.update_limit(); - - let view = hal::buffer::IndexBufferView { - buffer: &buffer.raw, - offset, - index_type: conv::map_index_format(pass.index_state.format), - }; - - unsafe { - pass.raw.bind_index_buffer(view); - } - } - - pub fn render_pass_set_vertex_buffers( - &self, - pass_id: id::RenderPassId, - start_slot: u32, - buffers: &[id::BufferId], - offsets: &[BufferAddress], - ) { - let hub = B::hub(self); - let mut token = Token::root(); - assert_eq!(buffers.len(), offsets.len()); - - let (mut pass_guard, mut token) = hub.render_passes.write(&mut token); - let (buffer_guard, _) = hub.buffers.read(&mut token); - - let pass = &mut pass_guard[pass_id]; - for (vbs, (&id, &offset)) in pass.vertex_state.inputs[start_slot as usize ..] - .iter_mut() - .zip(buffers.iter().zip(offsets)) - { - let buffer = pass - .trackers - .buffers - .use_extend(&*buffer_guard, id, (), BufferUsage::VERTEX) - .unwrap(); - assert!(buffer.usage.contains(BufferUsage::VERTEX)); - - vbs.total_size = buffer.size - offset; - } - - pass.vertex_state.update_limits(); - - let buffers = buffers - .iter() - .map(|&id| &buffer_guard[id].raw) - .zip(offsets.iter().cloned()); - - unsafe { - pass.raw.bind_vertex_buffers(start_slot, buffers); - } - } - - pub fn render_pass_draw( - &self, - pass_id: id::RenderPassId, - vertex_count: u32, - instance_count: u32, - first_vertex: u32, - first_instance: u32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - pass.is_ready().unwrap(); - - assert!( - first_vertex + vertex_count <= pass.vertex_state.vertex_limit, - "Vertex out of range!" - ); - assert!( - first_instance + instance_count <= pass.vertex_state.instance_limit, - "Instance out of range!" - ); - - unsafe { - pass.raw.draw( - first_vertex .. first_vertex + vertex_count, - first_instance .. first_instance + instance_count, - ); - } - } - - pub fn render_pass_draw_indirect( - &self, - pass_id: id::RenderPassId, - indirect_buffer_id: id::BufferId, - indirect_offset: BufferAddress, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, mut token) = hub.render_passes.write(&mut token); - let (buffer_guard, _) = hub.buffers.read(&mut token); - let pass = &mut pass_guard[pass_id]; - pass.is_ready().unwrap(); - - let buffer = pass - .trackers - .buffers - .use_extend( - &*buffer_guard, - indirect_buffer_id, - (), - BufferUsage::INDIRECT, - ) - .unwrap(); - assert!(buffer.usage.contains(BufferUsage::INDIRECT)); - - unsafe { - pass.raw.draw_indirect(&buffer.raw, indirect_offset, 1, 0); - } - } - - pub fn render_pass_draw_indexed( - &self, - pass_id: id::RenderPassId, - index_count: u32, - instance_count: u32, - first_index: u32, - base_vertex: i32, - first_instance: u32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - pass.is_ready().unwrap(); - - //TODO: validate that base_vertex + max_index() is within the provided range - assert!( - first_index + index_count <= pass.index_state.limit, - "Index out of range!" - ); - assert!( - first_instance + instance_count <= pass.vertex_state.instance_limit, - "Instance out of range!" - ); - - unsafe { - pass.raw.draw_indexed( - first_index .. first_index + index_count, - base_vertex, - first_instance .. first_instance + instance_count, - ); - } - } - - pub fn render_pass_draw_indexed_indirect( - &self, - pass_id: id::RenderPassId, - indirect_buffer_id: id::BufferId, - indirect_offset: BufferAddress, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, mut token) = hub.render_passes.write(&mut token); - let (buffer_guard, _) = hub.buffers.read(&mut token); - let pass = &mut pass_guard[pass_id]; - pass.is_ready().unwrap(); - - let buffer = pass - .trackers - .buffers - .use_extend( - &*buffer_guard, - indirect_buffer_id, - (), - BufferUsage::INDIRECT, - ) - .unwrap(); - assert!(buffer.usage.contains(BufferUsage::INDIRECT)); - - unsafe { - pass.raw - .draw_indexed_indirect(&buffer.raw, indirect_offset, 1, 0); - } - } - - pub fn render_pass_set_pipeline( - &self, - pass_id: id::RenderPassId, - pipeline_id: id::RenderPipelineId, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); - let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); - let (mut pass_guard, mut token) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - let (pipeline_guard, mut token) = hub.render_pipelines.read(&mut token); - let pipeline = &pipeline_guard[pipeline_id]; - - assert!( - pass.context.compatible(&pipeline.pass_context), - "The render pipeline is not compatible with the pass!" - ); - assert_eq!( - pipeline.sample_count, pass.sample_count, - "The render pipeline and renderpass have mismatching sample_count" - ); - - pass.blend_color_status - .require(pipeline.flags.contains(PipelineFlags::BLEND_COLOR)); - pass.stencil_reference_status - .require(pipeline.flags.contains(PipelineFlags::STENCIL_REFERENCE)); - - unsafe { - pass.raw.bind_graphics_pipeline(&pipeline.raw); - } - - // Rebind resource - if pass.binder.pipeline_layout_id != Some(pipeline.layout_id) { - let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id]; - pass.binder.pipeline_layout_id = Some(pipeline.layout_id); - pass.binder - .reset_expectations(pipeline_layout.bind_group_layout_ids.len()); - let mut is_compatible = true; - - for (index, (entry, &bgl_id)) in pass - .binder - .entries - .iter_mut() - .zip(&pipeline_layout.bind_group_layout_ids) - .enumerate() - { - match entry.expect_layout(bgl_id) { - LayoutChange::Match(bg_id, offsets) if is_compatible => { - let desc_set = bind_group_guard[bg_id].raw.raw(); - unsafe { - pass.raw.bind_graphics_descriptor_sets( - &pipeline_layout.raw, - index, - iter::once(desc_set), - offsets.iter().map(|offset| *offset as u32), - ); - } - } - LayoutChange::Match(..) | LayoutChange::Unchanged => {} - LayoutChange::Mismatch => { - is_compatible = false; - } - } - } - } - - // Rebind index buffer if the index format has changed with the pipeline switch - if pass.index_state.format != pipeline.index_format { - pass.index_state.format = pipeline.index_format; - pass.index_state.update_limit(); - - if let Some((buffer_id, ref range)) = pass.index_state.bound_buffer_view { - let (buffer_guard, _) = hub.buffers.read(&mut token); - let buffer = pass - .trackers - .buffers - .use_extend(&*buffer_guard, buffer_id, (), BufferUsage::INDEX) - .unwrap(); - - let view = hal::buffer::IndexBufferView { - buffer: &buffer.raw, - offset: range.start, - index_type: conv::map_index_format(pass.index_state.format), - }; - - unsafe { - pass.raw.bind_index_buffer(view); - } - } - } - // Update vertex buffer limits - for (vbs, &(stride, rate)) in pass - .vertex_state - .inputs - .iter_mut() - .zip(&pipeline.vertex_strides) - { - vbs.stride = stride; - vbs.rate = rate; - } - for vbs in pass.vertex_state.inputs[pipeline.vertex_strides.len() ..].iter_mut() { - vbs.stride = 0; - vbs.rate = InputStepMode::Vertex; - } - pass.vertex_state.update_limits(); - } - - pub fn render_pass_set_blend_color( - &self, - pass_id: id::RenderPassId, - color: &Color, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - pass.blend_color_status = OptionalState::Set; - - unsafe { - pass.raw.set_blend_constants(conv::map_color_f32(color)); - } - } - - pub fn render_pass_set_stencil_reference( - &self, - pass_id: id::RenderPassId, - value: u32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - pass.stencil_reference_status = OptionalState::Set; - - unsafe { - pass.raw.set_stencil_reference(hal::pso::Face::all(), value); - } - } - - pub fn render_pass_set_viewport( - &self, - pass_id: id::RenderPassId, - x: f32, - y: f32, - w: f32, - h: f32, - min_depth: f32, - max_depth: f32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - unsafe { - use std::convert::TryFrom; - use std::i16; - - pass.raw.set_viewports( - 0, - &[hal::pso::Viewport { - rect: hal::pso::Rect { - x: i16::try_from(x.round() as i64).unwrap_or(0), - y: i16::try_from(y.round() as i64).unwrap_or(0), - w: i16::try_from(w.round() as i64).unwrap_or(i16::MAX), - h: i16::try_from(h.round() as i64).unwrap_or(i16::MAX), - }, - depth: min_depth .. max_depth, - }], - ); - } - } - - pub fn render_pass_set_scissor_rect( - &self, - pass_id: id::RenderPassId, - x: u32, - y: u32, - w: u32, - h: u32, - ) { - let hub = B::hub(self); - let mut token = Token::root(); - let (mut pass_guard, _) = hub.render_passes.write(&mut token); - let pass = &mut pass_guard[pass_id]; - - unsafe { - use std::convert::TryFrom; - use std::i16; - - pass.raw.set_scissors( - 0, - &[hal::pso::Rect { - x: i16::try_from(x).unwrap_or(0), - y: i16::try_from(y).unwrap_or(0), - w: i16::try_from(w).unwrap_or(i16::MAX), - h: i16::try_from(h).unwrap_or(i16::MAX), - }], - ); - } - } } mod ffi { diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index fef312e920..208ed5ad97 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -5,7 +5,7 @@ use crate::{ backend, binding_model::{BindGroup, BindGroupLayout, PipelineLayout}, - command::{CommandBuffer, ComputePass, RenderPass}, + command::CommandBuffer, device::{Device, ShaderModule}, id::{ AdapterId, @@ -13,11 +13,9 @@ use crate::{ BindGroupLayoutId, BufferId, CommandBufferId, - ComputePassId, ComputePipelineId, DeviceId, PipelineLayoutId, - RenderPassId, RenderPipelineId, SamplerId, ShaderModuleId, @@ -181,18 +179,10 @@ impl Access> for CommandBuffer {} impl Access> for Root {} impl Access> for Device {} impl Access> for SwapChain {} -impl Access> for Root {} -impl Access> for BindGroup {} -impl Access> for CommandBuffer {} -impl Access> for Root {} -impl Access> for BindGroup {} -impl Access> for CommandBuffer {} impl Access> for Root {} impl Access> for BindGroup {} -impl Access> for ComputePass {} impl Access> for Root {} impl Access> for BindGroup {} -impl Access> for RenderPass {} impl Access> for Root {} impl Access> for PipelineLayout {} impl Access> for Root {} @@ -200,9 +190,7 @@ impl Access> for Device {} impl Access> for BindGroupLayout {} impl Access> for BindGroup {} impl Access> for CommandBuffer {} -impl Access> for ComputePass {} impl Access> for ComputePipeline {} -impl Access> for RenderPass {} impl Access> for RenderPipeline {} impl Access> for Root {} impl Access> for Device {} @@ -379,9 +367,7 @@ pub struct Hub { pub bind_group_layouts: Registry, BindGroupLayoutId, F>, pub bind_groups: Registry, BindGroupId, F>, pub command_buffers: Registry, CommandBufferId, F>, - pub render_passes: Registry, RenderPassId, F>, pub render_pipelines: Registry, RenderPipelineId, F>, - pub compute_passes: Registry, ComputePassId, F>, pub compute_pipelines: Registry, ComputePipelineId, F>, pub buffers: Registry, BufferId, F>, pub textures: Registry, TextureId, F>, @@ -400,9 +386,7 @@ impl Default for Hub { bind_group_layouts: Registry::new(B::VARIANT), bind_groups: Registry::new(B::VARIANT), command_buffers: Registry::new(B::VARIANT), - render_passes: Registry::new(B::VARIANT), render_pipelines: Registry::new(B::VARIANT), - compute_passes: Registry::new(B::VARIANT), compute_pipelines: Registry::new(B::VARIANT), buffers: Registry::new(B::VARIANT), textures: Registry::new(B::VARIANT), @@ -459,9 +443,7 @@ impl Drop for Hub { //TODO: // self.compute_pipelines - // self.compute_passes // self.render_pipelines - // self.render_passes // self.bind_group_layouts // self.pipeline_layouts // self.shader_modules diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index e5d3308809..b2492b49b7 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -115,9 +115,9 @@ pub type ComputePipelineId = Id>; // Command pub type CommandBufferId = Id>; pub type CommandEncoderId = CommandBufferId; +pub type RenderPassId = *mut crate::command::RawRenderPass; +pub type ComputePassId = *mut crate::command::RawPass; pub type RenderBundleId = Id>; -pub type RenderPassId = Id>; -pub type ComputePassId = Id>; // Swap chain pub type SwapChainId = Id>; diff --git a/wgpu-native/src/command.rs b/wgpu-native/src/command.rs index 691dac0753..dd04565254 100644 --- a/wgpu-native/src/command.rs +++ b/wgpu-native/src/command.rs @@ -77,17 +77,17 @@ pub extern "C" fn wgpu_command_encoder_copy_texture_to_texture( #[no_mangle] -pub unsafe extern "C" fn wgpu_render_pass_end_pass(pass_id: core::command::RawRenderPassId) { +pub unsafe extern "C" fn wgpu_render_pass_end_pass(pass_id: id::RenderPassId) { let (pass_data, encoder_id, targets) = Box::from_raw(pass_id).finish_render(); let color_attachments: arrayvec::ArrayVec<[_; core::device::MAX_COLOR_TARGETS]> = targets.colors .iter() .flat_map(|at| { - if at.attachment == core::id::TextureViewId::ERROR { + if at.attachment == id::TextureViewId::ERROR { None } else { Some(core::command::RenderPassColorAttachmentDescriptor { attachment: at.attachment, - resolve_target: if at.resolve_target == core::id::TextureViewId::ERROR { + resolve_target: if at.resolve_target == id::TextureViewId::ERROR { None } else { Some(&at.resolve_target) @@ -99,7 +99,7 @@ pub unsafe extern "C" fn wgpu_render_pass_end_pass(pass_id: core::command::RawRe } }) .collect(); - let depth_stencil_attachment = if targets.depth_stencil.attachment == core::id::TextureViewId::ERROR { + let depth_stencil_attachment = if targets.depth_stencil.attachment == id::TextureViewId::ERROR { None } else { Some(&targets.depth_stencil) @@ -108,7 +108,7 @@ pub unsafe extern "C" fn wgpu_render_pass_end_pass(pass_id: core::command::RawRe } #[no_mangle] -pub unsafe extern "C" fn wgpu_compute_pass_end_pass(pass_id: core::command::RawComputePassId) { +pub unsafe extern "C" fn wgpu_compute_pass_end_pass(pass_id: id::ComputePassId) { let (pass_data, encoder_id) = Box::from_raw(pass_id).finish_compute(); gfx_select!(encoder_id => GLOBAL.command_encoder_run_compute_pass(encoder_id, &pass_data)) } From f798f7c631d93df84152d40278fa2b7256ea5c68 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sun, 12 Jan 2020 00:48:13 -0500 Subject: [PATCH 7/9] Add missing render pass methods --- ffi/wgpu.h | 21 +++++++++++++++----- wgpu-core/src/command/compute.rs | 2 +- wgpu-core/src/command/render.rs | 34 ++++++++++++++++++++++++++++++-- wgpu-native/src/command.rs | 7 +++++++ 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/ffi/wgpu.h b/ffi/wgpu.h index 03d186891d..c8499a90fc 100644 --- a/ffi/wgpu.h +++ b/ffi/wgpu.h @@ -848,6 +848,17 @@ void wgpu_render_pass_draw(WGPURawRenderPass *pass, uint32_t first_vertex, uint32_t first_instance); +void wgpu_render_pass_draw_indexed(WGPURawRenderPass *pass, + uint32_t index_count, + uint32_t instance_count, + uint32_t first_index, + int32_t base_vertex, + uint32_t first_instance); + +void wgpu_render_pass_draw_indexed_indirect(WGPURawRenderPass *pass, + WGPUBufferId buffer_id, + WGPUBufferAddress offset); + void wgpu_render_pass_draw_indirect(WGPURawRenderPass *pass, WGPUBufferId buffer_id, WGPUBufferAddress offset); @@ -878,11 +889,11 @@ void wgpu_render_pass_set_index_buffer(WGPURawRenderPass *pass, void wgpu_render_pass_set_pipeline(WGPURawRenderPass *pass, WGPURenderPipelineId pipeline_id); -void wgpu_render_pass_set_scissor(WGPURawRenderPass *pass, - uint32_t x, - uint32_t y, - uint32_t w, - uint32_t h); +void wgpu_render_pass_set_scissor_rect(WGPURawRenderPass *pass, + uint32_t x, + uint32_t y, + uint32_t w, + uint32_t h); void wgpu_render_pass_set_stencil_reference(WGPURawRenderPass *pass, uint32_t value); diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index d145b5e128..631488dfec 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -213,7 +213,7 @@ impl Global { } } -mod ffi { +pub mod compute_ffi { use super::{ ComputeCommand, super::{PhantomSlice, RawPass}, diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 299f8d8b5e..ebd36d0772 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1096,7 +1096,7 @@ impl Global { } } -mod ffi { +pub mod render_ffi { use super::{ RenderCommand, super::{PhantomSlice, RawRenderPass, Rect}, @@ -1204,7 +1204,7 @@ mod ffi { } #[no_mangle] - pub unsafe extern "C" fn wgpu_render_pass_set_scissor( + pub unsafe extern "C" fn wgpu_render_pass_set_scissor_rect( pass: &mut RawRenderPass, x: u32, y: u32, @@ -1230,6 +1230,24 @@ mod ffi { }); } + #[no_mangle] + pub unsafe extern "C" fn wgpu_render_pass_draw_indexed( + pass: &mut RawRenderPass, + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + ) { + pass.raw.encode(&RenderCommand::DrawIndexed { + index_count, + instance_count, + first_index, + base_vertex, + first_instance, + }); + } + #[no_mangle] pub unsafe extern "C" fn wgpu_render_pass_draw_indirect( pass: &mut RawRenderPass, @@ -1242,6 +1260,18 @@ mod ffi { }); } + #[no_mangle] + pub unsafe extern "C" fn wgpu_render_pass_draw_indexed_indirect( + pass: &mut RawRenderPass, + buffer_id: id::BufferId, + offset: BufferAddress, + ) { + pass.raw.encode(&RenderCommand::DrawIndexedIndirect { + buffer_id, + offset, + }); + } + #[no_mangle] pub extern "C" fn wgpu_render_pass_execute_bundles( _pass: &mut RawRenderPass, diff --git a/wgpu-native/src/command.rs b/wgpu-native/src/command.rs index dd04565254..ddbb67a6d6 100644 --- a/wgpu-native/src/command.rs +++ b/wgpu-native/src/command.rs @@ -4,6 +4,13 @@ use crate::GLOBAL; +pub use core::command::{ + wgpu_command_encoder_begin_compute_pass, + wgpu_command_encoder_begin_render_pass, + compute_ffi::*, + render_ffi::*, +}; + use core::{gfx_select, id}; From 92441c38a21b52de265e2e5e1a475a9213f1d2a7 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 13 Jan 2020 12:37:27 -0500 Subject: [PATCH 8/9] Fix missing transitions before the render pass --- wgpu-core/src/command/render.rs | 38 ++++++++++++++++++++++++--------- wgpu-core/src/device/mod.rs | 6 ++---- wgpu-core/src/track/mod.rs | 2 +- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index ebd36d0772..959cf7f04e 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -297,9 +297,15 @@ impl Global { let (adapter_guard, mut token) = hub.adapters.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); - let cmb = &mut cmb_guard[encoder_id]; - let raw = cmb.raw.last_mut().unwrap(); + let mut trackers = TrackerSet::new(B::VARIANT); + let cmb = &mut cmb_guard[encoder_id]; + let device = &device_guard[cmb.device_id.value]; + let mut raw = device.com_allocator.extend(cmb); + + unsafe { + raw.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT); + } let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token); let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); @@ -311,13 +317,12 @@ impl Global { let (context, sample_count) = { use hal::{adapter::PhysicalDevice as _, device::Device as _}; - let device = &device_guard[cmb.device_id.value]; - let limits = adapter_guard[device.adapter_id] .raw .physical_device .limits(); let samples_count_limit = limits.framebuffer_color_sample_counts; + let base_trackers = &cmb.trackers; let mut extent = None; let mut used_swap_chain_image = None::>; @@ -346,7 +351,7 @@ impl Global { let rp_key = { let depth_stencil = match depth_stencil_attachment { Some(at) => { - let view = cmb.trackers + let view = trackers .views .use_extend(&*view_guard, at.attachment, (), ()) .unwrap(); @@ -363,7 +368,7 @@ impl Global { }; // Using render pass for transition. - let consistent_usage = cmb.trackers.textures.query( + let consistent_usage = base_trackers.textures.query( source_id.value, view.range.clone(), ); @@ -405,7 +410,7 @@ impl Global { view.samples, sample_count, "All attachments must have the same sample_count" ); - let first_use = cmb.trackers.views.init( + let first_use = trackers.views.init( at.attachment, view.life_guard.add_ref(), PhantomData, @@ -413,7 +418,7 @@ impl Global { let layouts = match view.inner { TextureViewInner::Native { ref source_id, .. } => { - let consistent_usage = cmb.trackers.textures.query( + let consistent_usage = base_trackers.textures.query( source_id.value, view.range.clone(), ); @@ -465,7 +470,7 @@ impl Global { view.samples, 1, "All resolve_targets must have a sample_count of 1" ); - let first_use = cmb.trackers.views.init( + let first_use = trackers.views.init( resolve_target, view.life_guard.add_ref(), PhantomData, @@ -473,7 +478,7 @@ impl Global { let layouts = match view.inner { TextureViewInner::Native { ref source_id, .. } => { - let consistent_usage = cmb.trackers.textures.query( + let consistent_usage = base_trackers.textures.query( source_id.value, view.range.clone(), ); @@ -1093,6 +1098,19 @@ impl Global { RenderCommand::End => break, } } + + super::CommandBuffer::insert_barriers( + cmb.raw.last_mut().unwrap(), + &mut cmb.trackers, + &trackers, + &*buffer_guard, + &*texture_guard, + ); + unsafe { + cmb.raw.last_mut().unwrap().finish(); + raw.end_render_pass(); + } + cmb.raw.push(raw); } } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index c2f8140752..4b5f35846b 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -1216,9 +1216,8 @@ impl> Global { .com_allocator .allocate(dev_stored, &device.raw, device.features, lowest_active_index); unsafe { - comb.raw.last_mut().unwrap().begin( + comb.raw.last_mut().unwrap().begin_primary( hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, - hal::command::CommandBufferInheritanceInfo::default(), ); } @@ -1381,9 +1380,8 @@ impl> Global { // execute resource transitions let mut transit = device.com_allocator.extend(comb); unsafe { - transit.begin( + transit.begin_primary( hal::command::CommandBufferFlags::ONE_TIME_SUBMIT, - hal::command::CommandBufferInheritanceInfo::default(), ); } log::trace!("Stitching command buffer {:?} before submission", cmb_id); diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 01f973dd89..fdbf962496 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -280,7 +280,7 @@ impl ResourceTracker { /// /// Returns `Some(Usage)` only if this usage is consistent /// across the given selector. - pub fn query(&mut self, id: S::Id, selector: S::Selector) -> Option { + pub fn query(&self, id: S::Id, selector: S::Selector) -> Option { let (index, epoch, backend) = id.unzip(); debug_assert_eq!(backend, self.backend); let res = self.map.get(&index)?; From a51019795ef036ccb14b8dd424d6aaef9d8788d2 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 13 Jan 2020 16:52:51 -0500 Subject: [PATCH 9/9] Switch to a custom fork of peek-poke --- Cargo.lock | 53 ++++++++------------------------------------ wgpu-core/Cargo.toml | 2 +- 2 files changed, 10 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6ae82bfd0..2d140c2e8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,19 +368,19 @@ dependencies = [ [[package]] name = "peek-poke" version = "0.2.0" -source = "git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8#728591c140ead9a6b646a27eaad29e5136fb96b8" +source = "git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075#969bd7fe2be1a83f87916dc8b388c63cfd457075" dependencies = [ - "peek-poke-derive 0.2.0 (git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8)", + "peek-poke-derive 0.2.0 (git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075)", ] [[package]] name = "peek-poke-derive" version = "0.2.0" -source = "git+https://github.com/djg/peek-poke?rev=728591c140ead9a6b646a27eaad29e5136fb96b8#728591c140ead9a6b646a27eaad29e5136fb96b8" +source = "git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075#969bd7fe2be1a83f87916dc8b388c63cfd457075" 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)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -388,14 +388,6 @@ 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" @@ -404,14 +396,6 @@ 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" @@ -561,16 +545,6 @@ 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" @@ -581,11 +555,6 @@ 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" @@ -661,7 +630,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)", + "peek-poke 0.2.0 (git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075)", "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)", @@ -768,12 +737,10 @@ 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 peek-poke 0.2.0 (git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075)" = "" +"checksum peek-poke-derive 0.2.0 (git+https://github.com/kvark/peek-poke?rev=969bd7fe2be1a83f87916dc8b388c63cfd457075)" = "" "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" @@ -793,9 +760,7 @@ 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/wgpu-core/Cargo.toml b/wgpu-core/Cargo.toml index 637d4f8b0b..2df606641b 100644 --- a/wgpu-core/Cargo.toml +++ b/wgpu-core/Cargo.toml @@ -29,7 +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" } +peek-poke = { git = "https://github.com/kvark/peek-poke", rev = "969bd7fe2be1a83f87916dc8b388c63cfd457075" } rendy-memory = "0.5" rendy-descriptor = "0.5" serde = { version = "1.0", features = ["serde_derive"], optional = true }