diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index a95ea4cdd5..7cafb9956f 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -15,6 +15,7 @@ use crate::{ memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, pipeline::PipelineFlags, resource::{Texture, TextureView, TextureViewSource}, + swap_chain::SwapChain, track::{StatefulTrackerSubset, TextureSelector, UsageConflict}, validation::{ check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError, @@ -491,11 +492,11 @@ where struct RenderAttachment<'a> { texture_id: &'a Stored, selector: &'a TextureSelector, - previous_use: Option, - new_use: hal::TextureUses, + usage: hal::TextureUses, } -type AttachmentDataVec = ArrayVec; +const MAX_TOTAL_ATTACHMENTS: usize = hal::MAX_COLOR_TARGETS + hal::MAX_COLOR_TARGETS + 1; +type AttachmentDataVec = ArrayVec; struct RenderPassInfo<'a, A: hal::Api> { context: RenderPassContext, @@ -514,6 +515,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, cmd_buf: &mut CommandBuffer, view_guard: &'a Storage, id::TextureViewId>, + swap_chain_guard: &'a Storage, id::SwapChainId>, ) -> Result { profiling::scope!("start", "RenderPassInfo"); @@ -527,7 +529,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let mut attachment_type_name = ""; let mut extent = None; let mut sample_count = 0; - let mut used_swap_chain = None::>; + let mut used_swap_chain = None::<(Stored, hal::TextureUses)>; let mut add_view = |view: &TextureView, type_name| { if let Some(ex) = extent { @@ -577,12 +579,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } }; - // Using render pass for transition. - let previous_use = cmd_buf - .trackers - .textures - .query(source_id.value, view.selector.clone()); - let new_use = if at.is_read_only(ds_aspects)? { + let usage = if at.is_read_only(ds_aspects)? { is_ds_read_only = true; hal::TextureUses::DEPTH_STENCIL_READ | hal::TextureUses::SAMPLED } else { @@ -591,16 +588,13 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { render_attachments.push(RenderAttachment { texture_id: source_id, selector: &view.selector, - previous_use, - new_use, + usage, }); - let old_use = previous_use.unwrap_or(new_use); depth_stencil = Some(hal::DepthStencilAttachment { target: hal::Attachment { view: &view.raw, - usage: new_use, - boundary_usage: old_use..new_use, + usage, }, depth_ops: at.depth.hal_ops(), stencil_ops: at.stencil.hal_ops(), @@ -626,33 +620,22 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { )); } - let boundary_usage = match color_view.source { + match color_view.source { TextureViewSource::Native(ref source_id) => { - let previous_use = cmd_buf - .trackers - .textures - .query(source_id.value, color_view.selector.clone()); - let new_use = hal::TextureUses::COLOR_TARGET; render_attachments.push(RenderAttachment { texture_id: source_id, selector: &color_view.selector, - previous_use, - new_use, + usage: hal::TextureUses::COLOR_TARGET, }); - - let old_use = previous_use.unwrap_or(new_use); - old_use..new_use } TextureViewSource::SwapChain(ref source_id) => { - assert!(used_swap_chain.is_none()); - used_swap_chain = Some(source_id.clone()); - - let end = hal::TextureUses::empty(); - let start = match at.channel.load_op { + //HACK: guess the start usage based on the load op + let start_usage = match at.channel.load_op { + LoadOp::Load => hal::TextureUses::empty(), LoadOp::Clear => hal::TextureUses::UNINITIALIZED, - LoadOp::Load => end, }; - start..end + assert!(used_swap_chain.is_none()); + used_swap_chain = Some((source_id.clone(), start_usage)); } }; @@ -676,34 +659,25 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { return Err(RenderPassErrorInner::InvalidResolveTargetSampleCount); } - let boundary_usage = match resolve_view.source { + match resolve_view.source { TextureViewSource::Native(ref source_id) => { - let previous_use = cmd_buf - .trackers - .textures - .query(source_id.value, resolve_view.selector.clone()); - let new_use = hal::TextureUses::COLOR_TARGET; render_attachments.push(RenderAttachment { texture_id: source_id, selector: &resolve_view.selector, - previous_use, - new_use, + usage: hal::TextureUses::COLOR_TARGET, }); - - let old_use = previous_use.unwrap_or(new_use); - old_use..new_use } TextureViewSource::SwapChain(ref source_id) => { + //HACK: guess the start usage + let start_usage = hal::TextureUses::UNINITIALIZED; assert!(used_swap_chain.is_none()); - used_swap_chain = Some(source_id.clone()); - hal::TextureUses::UNINITIALIZED..hal::TextureUses::empty() + used_swap_chain = Some((source_id.clone(), start_usage)); } }; hal_resolve_target = Some(hal::Attachment { view: &resolve_view.raw, usage: hal::TextureUses::COLOR_TARGET, - boundary_usage, }); } @@ -711,7 +685,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { target: hal::Attachment { view: &color_view.raw, usage: hal::TextureUses::COLOR_TARGET, - boundary_usage, }, resolve_target: hal_resolve_target, ops: at.channel.hal_ops(), @@ -723,6 +696,21 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { return Err(RenderPassErrorInner::InvalidSampleCount(sample_count)); } + if let Some((ref sc_id, start_usage)) = used_swap_chain { + let &(_, ref suf_texture) = swap_chain_guard[sc_id.value] + .acquired_texture + .as_ref() + .unwrap(); + let barrier = hal::TextureBarrier { + texture: std::borrow::Borrow::borrow(suf_texture), + usage: start_usage..hal::TextureUses::COLOR_TARGET, + range: wgt::ImageSubresourceRange::default(), + }; + unsafe { + cmd_buf.encoder.raw.transition_textures(iter::once(barrier)); + } + } + let view_data = AttachmentData { colors: color_attachments .iter() @@ -756,7 +744,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { context, trackers: StatefulTrackerSubset::new(A::VARIANT), render_attachments, - used_swap_chain, + used_swap_chain: used_swap_chain.map(|(sc_id, _)| sc_id), is_ds_read_only, extent, _phantom: PhantomData, @@ -767,9 +755,28 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { mut self, raw: &mut A::CommandEncoder, texture_guard: &Storage, id::TextureId>, + swap_chain_guard: &Storage, id::SwapChainId>, ) -> Result<(StatefulTrackerSubset, Option>), RenderPassErrorInner> { profiling::scope!("finish", "RenderPassInfo"); + unsafe { + raw.end_render_pass(); + } + + if let Some(ref sc_id) = self.used_swap_chain { + let &(_, ref suf_texture) = swap_chain_guard[sc_id.value] + .acquired_texture + .as_ref() + .unwrap(); + let barrier = hal::TextureBarrier { + texture: std::borrow::Borrow::borrow(suf_texture), + usage: hal::TextureUses::COLOR_TARGET..hal::TextureUses::empty(), + range: wgt::ImageSubresourceRange::default(), + }; + unsafe { + raw.transition_textures(iter::once(barrier)); + } + } for ra in self.render_attachments { let texture = &texture_guard[ra.texture_id.value]; @@ -782,29 +789,11 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { ra.texture_id.value, &ra.texture_id.ref_count, ra.selector.clone(), - ra.new_use, + ra.usage, ) .map_err(UsageConflict::from)?; - - if let Some(usage) = ra.previous_use { - // Make the attachment tracks to be aware of the internal - // transition done by the render pass, by registering the - // previous usage as the initial state. - self.trackers - .textures - .prepend( - ra.texture_id.value, - &ra.texture_id.ref_count, - ra.selector.clone(), - usage, - ) - .unwrap(); - } } - unsafe { - raw.end_render_pass(); - } Ok((self.trackers, self.used_swap_chain)) } } @@ -842,7 +831,7 @@ impl Global { let (device_guard, mut token) = hub.devices.read(&mut token); let (pass_raw, trackers, query_reset_state) = { - // read-only lock guard + let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); let cmd_buf = @@ -886,6 +875,7 @@ impl Global { depth_stencil_attachment, cmd_buf, &*view_guard, + &*swap_chain_guard, ) .map_pass_err(scope)?; @@ -1744,8 +1734,10 @@ impl Global { } log::trace!("Merging {:?} with the render pass", encoder_id); - let (trackers, used_swapchain) = - info.finish(raw, &*texture_guard).map_pass_err(scope)?; + let (trackers, used_swapchain) = info + .finish(raw, &*texture_guard, &*swap_chain_guard) + .map_pass_err(scope)?; + let raw_cmd_buf = unsafe { raw.end_encoding() .map_err(|_| RenderPassErrorInner::OutOfMemory) diff --git a/wgpu-core/src/track/buffer.rs b/wgpu-core/src/track/buffer.rs index 8fb2da3699..35cceb253a 100644 --- a/wgpu-core/src/track/buffer.rs +++ b/wgpu-core/src/track/buffer.rs @@ -75,25 +75,6 @@ impl ResourceState for BufferState { Ok(()) } - fn prepend( - &mut self, - id: Valid, - _selector: Self::Selector, - usage: Self::Usage, - ) -> Result<(), PendingTransition> { - match self.first { - Some(old) if old != usage => Err(PendingTransition { - id, - selector: (), - usage: old..usage, - }), - _ => { - self.first = Some(usage); - Ok(()) - } - } - } - fn merge( &mut self, id: Valid, @@ -205,30 +186,4 @@ mod test { } ); } - - #[test] - fn prepend() { - let mut bs = Unit { - first: None, - last: BufferUses::VERTEX, - }; - let id = Id::dummy(); - bs.prepend(id, (), BufferUses::INDEX).unwrap(); - bs.prepend(id, (), BufferUses::INDEX).unwrap(); - assert_eq!( - bs.prepend(id, (), BufferUses::STORAGE_LOAD), - Err(PendingTransition { - id, - selector: (), - usage: BufferUses::INDEX..BufferUses::STORAGE_LOAD, - }) - ); - assert_eq!( - bs, - Unit { - first: Some(BufferUses::INDEX), - last: BufferUses::VERTEX, - } - ); - } } diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 5d6af42d8a..ce5e70a85c 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -76,14 +76,6 @@ pub(crate) trait ResourceState: Clone + Default { output: Option<&mut Vec>>, ) -> Result<(), PendingTransition>; - /// Sets up the first usage of the selected sub-resources. - fn prepend( - &mut self, - id: Valid, - selector: Self::Selector, - usage: Self::Usage, - ) -> Result<(), PendingTransition>; - /// Merge the state of this resource tracked by a different instance /// with the current one. /// @@ -309,6 +301,7 @@ impl ResourceTracker { /// /// Returns `Some(Usage)` only if this usage is consistent /// across the given selector. + #[allow(unused)] // TODO: figure out if this needs to be removed pub fn query(&self, id: Valid, selector: S::Selector) -> Option { let (index, epoch, backend) = id.0.unzip(); debug_assert_eq!(backend, self.backend); @@ -397,21 +390,6 @@ impl ResourceTracker { self.temp.drain(..) } - /// Turn the tracking from the "expand" mode into the "replace" one, - /// installing the selected usage as the "first". - /// This is a special operation only used by the render pass attachments. - pub(crate) fn prepend( - &mut self, - id: Valid, - ref_count: &RefCount, - selector: S::Selector, - usage: S::Usage, - ) -> Result<(), PendingTransition> { - Self::get_or_insert(self.backend, &mut self.map, id, ref_count) - .state - .prepend(id, selector, usage) - } - /// Merge another tracker into `self` by extending the current states /// without any transitions. pub(crate) fn merge_extend(&mut self, other: &Self) -> Result<(), PendingTransition> { @@ -528,15 +506,6 @@ impl ResourceState for PhantomData { Ok(()) } - fn prepend( - &mut self, - _id: Valid, - _selector: Self::Selector, - _usage: Self::Usage, - ) -> Result<(), PendingTransition> { - Ok(()) - } - fn merge( &mut self, _id: Valid, diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 84e3ae7499..d3fe33528f 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -136,40 +136,6 @@ impl ResourceState for TextureState { Ok(()) } - fn prepend( - &mut self, - id: Valid, - selector: Self::Selector, - usage: Self::Usage, - ) -> Result<(), PendingTransition> { - assert!(self.mips.len() >= selector.levels.end as usize); - for (mip_id, mip) in self.mips[selector.levels.start as usize..selector.levels.end as usize] - .iter_mut() - .enumerate() - { - let level = selector.levels.start + mip_id as u32; - let layers = mip.isolate(&selector.layers, Unit::new(usage)); - for &mut (ref range, ref mut unit) in layers { - match unit.first { - Some(old) if old != usage => { - return Err(PendingTransition { - id, - selector: TextureSelector { - levels: level..level + 1, - layers: range.clone(), - }, - usage: old..usage, - }); - } - _ => { - unit.first = Some(usage); - } - } - } - } - Ok(()) - } - fn merge( &mut self, id: Valid, diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index fb6c102028..9e762bb3a8 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -593,11 +593,18 @@ impl Example { let ctx = &mut self.contexts[self.context_index]; + let surface_tex = unsafe { self.surface.acquire_texture(!0).unwrap().unwrap().texture }; + + let target_barrier0 = hal::TextureBarrier { + texture: surface_tex.borrow(), + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::UNINITIALIZED..hal::TextureUses::COLOR_TARGET, + }; unsafe { ctx.encoder.begin_encoding(Some("frame")).unwrap(); + ctx.encoder.transition_textures(iter::once(target_barrier0)); } - let surface_tex = unsafe { self.surface.acquire_texture(!0).unwrap().unwrap().texture }; let surface_view_desc = hal::TextureViewDescriptor { label: None, format: self.surface_format, @@ -622,7 +629,6 @@ impl Example { target: hal::Attachment { view: &surface_tex_view, usage: hal::TextureUses::COLOR_TARGET, - boundary_usage: hal::TextureUses::UNINITIALIZED..hal::TextureUses::empty(), }, resolve_target: None, ops: hal::AttachmentOps::STORE, @@ -655,8 +661,17 @@ impl Example { ctx.frames_recorded += 1; let do_fence = ctx.frames_recorded > COMMAND_BUFFER_PER_CONTEXT; + let target_barrier1 = hal::TextureBarrier { + texture: surface_tex.borrow(), + range: wgt::ImageSubresourceRange::default(), + usage: hal::TextureUses::COLOR_TARGET..hal::TextureUses::empty(), + }; unsafe { ctx.encoder.end_render_pass(); + ctx.encoder.transition_textures(iter::once(target_barrier1)); + } + + unsafe { let cmd_buf = ctx.encoder.end_encoding().unwrap(); let fence_param = if do_fence { Some((&mut ctx.fence, ctx.fence_value)) diff --git a/wgpu-hal/src/dx12/mod.rs b/wgpu-hal/src/dx12/mod.rs index 30e26561d7..6be21520e9 100644 --- a/wgpu-hal/src/dx12/mod.rs +++ b/wgpu-hal/src/dx12/mod.rs @@ -349,7 +349,7 @@ pub struct PipelineLayout { total_slots: u32, // Storing for each associated bind group, which tables we created // in the root signature. This is required for binding descriptor sets. - elements: arrayvec::ArrayVec<[RootElement; crate::MAX_BIND_GROUPS]>, + elements: arrayvec::ArrayVec, } unsafe impl Send for PipelineLayout {} diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 4c8f434944..4e42368746 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -1044,13 +1044,9 @@ pub struct BufferTextureCopy { #[derive(Debug)] pub struct Attachment<'a, A: Api> { pub view: &'a A::TextureView, - /// Contains either a single mutating usage as a target, or a valid combination - /// of read-only usages. + /// Contains either a single mutating usage as a target, + /// or a valid combination of read-only usages. pub usage: TextureUses, - /// Defines the boundary usages for the attachment. - /// It is expected to begin a render pass with `boundary_usage.start` usage, - /// and will end it with `boundary_usage.end` usage. - pub boundary_usage: Range, } // Rust gets confused about the impl requirements for `A` @@ -1059,7 +1055,6 @@ impl Clone for Attachment<'_, A> { Self { view: self.view, usage: self.usage, - boundary_usage: self.boundary_usage.clone(), } } } diff --git a/wgpu-hal/src/vulkan/conv.rs b/wgpu-hal/src/vulkan/conv.rs index ffa38a4c18..aa057fc678 100644 --- a/wgpu-hal/src/vulkan/conv.rs +++ b/wgpu-hal/src/vulkan/conv.rs @@ -119,9 +119,7 @@ impl crate::Attachment<'_, super::Api> { let aspects = self.view.aspects(); super::AttachmentKey { format: caps.map_texture_format(self.view.attachment.view_format), - layout_pre: derive_image_layout(self.boundary_usage.start, aspects), - layout_in: derive_image_layout(self.usage, aspects), - layout_post: derive_image_layout(self.boundary_usage.end, aspects), + layout: derive_image_layout(self.usage, aspects), ops, } } @@ -250,7 +248,7 @@ pub fn map_texture_usage_to_barrier( access |= vk::AccessFlags::SHADER_WRITE; } - if usage == crate::TextureUses::UNINITIALIZED { + if usage == crate::TextureUses::UNINITIALIZED || usage.is_empty() { ( vk::PipelineStageFlags::TOP_OF_PIPE, vk::AccessFlags::empty(), diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 64156cf218..152c717293 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -74,7 +74,7 @@ impl super::DeviceShared { for cat in e.key().colors.iter() { color_refs.push(vk::AttachmentReference { attachment: vk_attachments.len() as u32, - layout: cat.base.layout_in, + layout: cat.base.layout, }); vk_attachments.push({ let (load_op, store_op) = conv::map_attachment_ops(cat.base.ops); @@ -83,14 +83,14 @@ impl super::DeviceShared { .samples(samples) .load_op(load_op) .store_op(store_op) - .initial_layout(cat.base.layout_pre) - .final_layout(cat.base.layout_post) + .initial_layout(cat.base.layout) + .final_layout(cat.base.layout) .build() }); let at_ref = if let Some(ref rat) = cat.resolve { let at_ref = vk::AttachmentReference { attachment: vk_attachments.len() as u32, - layout: rat.layout_in, + layout: rat.layout, }; let (load_op, store_op) = conv::map_attachment_ops(rat.ops); let vk_attachment = vk::AttachmentDescription::builder() @@ -98,8 +98,8 @@ impl super::DeviceShared { .samples(vk::SampleCountFlags::TYPE_1) .load_op(load_op) .store_op(store_op) - .initial_layout(rat.layout_pre) - .final_layout(rat.layout_post) + .initial_layout(rat.layout) + .final_layout(rat.layout) .build(); vk_attachments.push(vk_attachment); at_ref @@ -115,7 +115,7 @@ impl super::DeviceShared { if let Some(ref ds) = e.key().depth_stencil { ds_ref = Some(vk::AttachmentReference { attachment: vk_attachments.len() as u32, - layout: ds.base.layout_in, + layout: ds.base.layout, }); let (load_op, store_op) = conv::map_attachment_ops(ds.base.ops); let (stencil_load_op, stencil_store_op) = @@ -127,8 +127,8 @@ impl super::DeviceShared { .store_op(store_op) .stencil_load_op(stencil_load_op) .stencil_store_op(stencil_store_op) - .initial_layout(ds.base.layout_pre) - .final_layout(ds.base.layout_post) + .initial_layout(ds.base.layout) + .final_layout(ds.base.layout) .build(); vk_attachments.push(vk_attachment); } diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 387d079fd9..e29c37f83b 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -162,20 +162,16 @@ struct PrivateCapabilities { #[derive(Clone, Debug, Eq, Hash, PartialEq)] struct AttachmentKey { format: vk::Format, - layout_pre: vk::ImageLayout, - layout_in: vk::ImageLayout, - layout_post: vk::ImageLayout, + layout: vk::ImageLayout, ops: crate::AttachmentOps, } impl AttachmentKey { /// Returns an attachment key for a compatible attachment. - fn compatible(format: vk::Format, layout_in: vk::ImageLayout) -> Self { + fn compatible(format: vk::Format, layout: vk::ImageLayout) -> Self { Self { format, - layout_pre: vk::ImageLayout::GENERAL, - layout_in, - layout_post: vk::ImageLayout::GENERAL, + layout, ops: crate::AttachmentOps::all(), } }