diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index ea8ed0e5c..ac6399b1d 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -211,6 +211,7 @@ struct PassComponent { load_op: wgt::LoadOp, store_op: wgt::StoreOp, clear_value: T, + read_only: bool, } // required for PeekPoke @@ -220,6 +221,7 @@ impl Default for PassComponent { load_op: wgt::LoadOp::Clear, store_op: wgt::StoreOp::Clear, clear_value: T::default(), + read_only: false, } } } diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index bab58d3e9..b0d77ac77 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -37,6 +37,14 @@ pub type RenderPassColorAttachmentDescriptor = pub type RenderPassDepthStencilAttachmentDescriptor = RenderPassDepthStencilAttachmentDescriptorBase; +fn is_depth_stencil_read_only( + desc: &RenderPassDepthStencilAttachmentDescriptor, + aspects: hal::format::Aspects, +) -> bool { + (desc.depth_read_only || !aspects.contains(hal::format::Aspects::DEPTH)) + && (desc.stencil_read_only || !aspects.contains(hal::format::Aspects::STENCIL)) +} + #[repr(C)] #[derive(Debug)] pub struct RenderPassDescriptor<'a> { @@ -130,11 +138,13 @@ impl super::RawPass { load_op: ds.depth_load_op, store_op: ds.depth_store_op, clear_value: ds.clear_depth, + read_only: ds.depth_read_only, }, stencil: PassComponent { load_op: ds.stencil_load_op, store_op: ds.stencil_store_op, clear_value: ds.clear_stencil, + read_only: ds.stencil_read_only, }, }; } @@ -150,6 +160,7 @@ impl super::RawPass { load_op: at.load_op, store_op: at.store_op, clear_value: at.clear_color, + read_only: false, }, }; } @@ -361,13 +372,19 @@ impl Global { attachment: id::TextureViewId::from_raw(at.attachment).unwrap(), depth_load_op: at.depth.load_op, depth_store_op: at.depth.store_op, + depth_read_only: at.depth.read_only, clear_depth: at.depth.clear_value, stencil_load_op: at.stencil.load_op, stencil_store_op: at.stencil.store_op, clear_stencil: at.stencil.clear_value, + stencil_read_only: at.stencil.read_only, }; Some(&depth_stencil_attachment_body) }; + // We default to false intentionally, even if depth-stencil isn't used at all. + // This allows us to use the primary raw pipeline in `RenderPipeline`, + // instead of the special read-only one, which would be `None`. + let mut is_ds_read_only = false; let (context, sample_count) = { use hal::device::Device as _; @@ -388,11 +405,12 @@ impl Global { ); const MAX_TOTAL_ATTACHMENTS: usize = 10; - type OutputAttachment<'a> = ( - &'a Stored, - &'a hal::image::SubresourceRange, - Option, - ); + struct OutputAttachment<'a> { + texture_id: &'a Stored, + range: &'a hal::image::SubresourceRange, + previous_use: Option, + new_use: TextureUse, + } let mut output_attachments = ArrayVec::<[OutputAttachment; MAX_TOTAL_ATTACHMENTS]>::new(); @@ -420,23 +438,29 @@ impl Global { }; // Using render pass for transition. - let consistent_use = base_trackers + let previous_use = base_trackers .textures .query(source_id.value, view.range.clone()); - output_attachments.push((source_id, &view.range, consistent_use)); + let new_use = if is_depth_stencil_read_only(at, view.range.aspects) { + is_ds_read_only = true; + TextureUse::ATTACHMENT_READ + } else { + TextureUse::ATTACHMENT_WRITE + }; + output_attachments.push(OutputAttachment { + texture_id: source_id, + range: &view.range, + previous_use, + new_use, + }); - let old_layout = match consistent_use { - Some(usage) => { - conv::map_texture_state( - usage, - hal::format::Aspects::DEPTH | hal::format::Aspects::STENCIL, - ) - .1 - } - None => hal::image::Layout::DepthStencilAttachmentOptimal, + let new_layout = conv::map_texture_state(new_use, view.range.aspects).1; + let old_layout = match previous_use { + Some(usage) => conv::map_texture_state(usage, view.range.aspects).1, + None => new_layout, }; - Some(hal::pass::Attachment { + let ds_at = hal::pass::Attachment { format: Some(conv::map_texture_format( view.format, device.private_features, @@ -447,8 +471,9 @@ impl Global { at.stencil_load_op, at.stencil_store_op, ), - layouts: old_layout..hal::image::Layout::DepthStencilAttachmentOptimal, - }) + layouts: old_layout..new_layout, + }; + Some((ds_at, new_layout)) } None => None, }; @@ -473,18 +498,26 @@ impl Global { let layouts = match view.inner { TextureViewInner::Native { ref source_id, .. } => { - let consistent_use = base_trackers + let previous_use = base_trackers .textures .query(source_id.value, view.range.clone()); - output_attachments.push((source_id, &view.range, consistent_use)); + let new_use = TextureUse::ATTACHMENT_WRITE; + output_attachments.push(OutputAttachment { + texture_id: source_id, + range: &view.range, + previous_use, + new_use, + }); - let old_layout = match consistent_use { + let new_layout = + conv::map_texture_state(new_use, hal::format::Aspects::COLOR).1; + let old_layout = match previous_use { Some(usage) => { conv::map_texture_state(usage, hal::format::Aspects::COLOR).1 } - None => hal::image::Layout::ColorAttachmentOptimal, + None => new_layout, }; - old_layout..hal::image::Layout::ColorAttachmentOptimal + old_layout..new_layout } TextureViewInner::SwapChain { ref source_id, .. } => { if let Some((ref sc_id, _)) = cmb.used_swap_chain { @@ -506,7 +539,7 @@ impl Global { } }; - colors.push(hal::pass::Attachment { + let color_at = hal::pass::Attachment { format: Some(conv::map_texture_format( view.format, device.private_features, @@ -515,7 +548,8 @@ impl Global { ops: conv::map_load_store_ops(at.load_op, at.store_op), stencil_ops: hal::pass::AttachmentOps::DONT_CARE, layouts, - }); + }; + colors.push((color_at, hal::image::Layout::ColorAttachmentOptimal)); } for resolve_target in color_attachments.iter().flat_map(|at| at.resolve_target) { @@ -535,18 +569,26 @@ impl Global { let layouts = match view.inner { TextureViewInner::Native { ref source_id, .. } => { - let consistent_use = base_trackers + let previous_use = base_trackers .textures .query(source_id.value, view.range.clone()); - output_attachments.push((source_id, &view.range, consistent_use)); + let new_use = TextureUse::ATTACHMENT_WRITE; + output_attachments.push(OutputAttachment { + texture_id: source_id, + range: &view.range, + previous_use, + new_use, + }); - let old_layout = match consistent_use { + let new_layout = + conv::map_texture_state(new_use, hal::format::Aspects::COLOR).1; + let old_layout = match previous_use { Some(usage) => { conv::map_texture_state(usage, hal::format::Aspects::COLOR).1 } - None => hal::image::Layout::ColorAttachmentOptimal, + None => new_layout, }; - old_layout..hal::image::Layout::ColorAttachmentOptimal + old_layout..new_layout } TextureViewInner::SwapChain { ref source_id, .. } => { if let Some((ref sc_id, _)) = cmb.used_swap_chain { @@ -562,7 +604,7 @@ impl Global { } }; - resolves.push(hal::pass::Attachment { + let resolve_at = hal::pass::Attachment { format: Some(conv::map_texture_format( view.format, device.private_features, @@ -574,7 +616,8 @@ impl Global { ), stencil_ops: hal::pass::AttachmentOps::DONT_CARE, layouts, - }); + }; + resolves.push((resolve_at, hal::image::Layout::ColorAttachmentOptimal)); } RenderPassKey { @@ -584,30 +627,29 @@ impl Global { } }; - for (source_id, view_range, consistent_use) in output_attachments { - let texture = &texture_guard[source_id.value]; + for ot in output_attachments { + let texture = &texture_guard[ot.texture_id.value]; assert!( texture.usage.contains(TextureUsage::OUTPUT_ATTACHMENT), "Texture usage {:?} must contain the usage flag OUTPUT_ATTACHMENT", texture.usage ); - let usage = consistent_use.unwrap_or(TextureUse::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, + ot.texture_id.value, + &ot.texture_id.ref_count, + ot.range.clone(), + ot.previous_use.unwrap_or(ot.new_use), ); - if consistent_use.is_some() { + if ot.previous_use.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(), - TextureUse::OUTPUT_ATTACHMENT, + ot.texture_id.value, + &ot.texture_id.ref_count, + ot.range.clone(), + ot.new_use, ); }; } @@ -615,8 +657,8 @@ impl Global { 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 = [ + Entry::Vacant(entry) => { + let color_ids: [hal::pass::AttachmentRef; MAX_COLOR_TARGETS] = [ (0, hal::image::Layout::ColorAttachmentOptimal), (1, hal::image::Layout::ColorAttachmentOptimal), (2, hal::image::Layout::ColorAttachmentOptimal), @@ -629,49 +671,55 @@ impl Global { .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, had a sample count of {}", - sample_count_check - ); - resolve_ids.push(( - attachment_index, - hal::image::Layout::ColorAttachmentOptimal, - )); - attachment_index += 1; - } + for ((i, at), &(_, layout)) in color_attachments + .iter() + .enumerate() + .zip(entry.key().resolves.iter()) + { + let real_attachment_index = match at.resolve_target { + Some(resolve_attachment) => { + assert_ne!( + view_guard[at.attachment].samples, + 1, + "RenderPassColorAttachmentDescriptor's attachment with a resolve_target must be multi-sampled", + ); + assert_eq!( + view_guard[resolve_attachment].samples, + 1, + "RenderPassColorAttachmentDescriptor's resolve_target must not be multi-sampled", + ); + attachment_index + i + } + None => hal::pass::ATTACHMENT_UNUSED, + }; + resolve_ids.push((real_attachment_index, layout)); } + attachment_index += color_attachments.len(); } - let depth_id = ( - attachment_index, - hal::image::Layout::DepthStencilAttachmentOptimal, - ); + let depth_id = depth_stencil_attachment.map(|at| { + let aspects = view_guard[at.attachment].range.aspects; + let usage = if is_depth_stencil_read_only(at, aspects) { + TextureUse::ATTACHMENT_READ + } else { + TextureUse::ATTACHMENT_WRITE + }; + (attachment_index, conv::map_texture_state(usage, aspects).1) + }); let subpass = hal::pass::SubpassDesc { colors: &color_ids[..color_attachments.len()], resolves: &resolve_ids, - depth_stencil: depth_stencil_attachment.map(|_| &depth_id), + depth_stencil: depth_id.as_ref(), inputs: &[], preserves: &[], }; + let all = entry.key().all().map(|(at, _)| at); - let pass = unsafe { - device - .raw - .create_render_pass(e.key().all(), &[subpass], &[]) - } - .unwrap(); - e.insert(pass) + let pass = + unsafe { device.raw.create_render_pass(all, iter::once(subpass), &[]) } + .unwrap(); + entry.insert(pass) } }; @@ -744,13 +792,13 @@ impl Global { let clear_values = color_attachments .iter() .zip(&rp_key.colors) - .flat_map(|(at, key)| { + .flat_map(|(at, (rat, _layout))| { 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 { + let value = match rat.format.unwrap().base_format().1 { ChannelType::Unorm | ChannelType::Snorm | ChannelType::Ufloat @@ -919,12 +967,17 @@ impl Global { assert!( context.compatible(&pipeline.pass_context), - "The render pipeline is not compatible with the pass!" + "The render pipeline output formats do not match render pass attachment formats!" ); assert_eq!( pipeline.sample_count, sample_count, "The render pipeline and renderpass have mismatching sample_count" ); + assert!( + !is_ds_read_only || pipeline.flags.contains(PipelineFlags::DEPTH_STENCIL_READ_ONLY), + "Pipeline {:?} is not compatible with the depth-stencil read-only render pass", + pipeline_id + ); state .blend_color diff --git a/wgpu-core/src/conv.rs b/wgpu-core/src/conv.rs index 0cf4cd1ff..df6460d31 100644 --- a/wgpu-core/src/conv.rs +++ b/wgpu-core/src/conv.rs @@ -530,8 +530,9 @@ pub(crate) fn map_texture_state( W::COPY_SRC => L::TransferSrcOptimal, W::COPY_DST => L::TransferDstOptimal, W::SAMPLED => L::ShaderReadOnlyOptimal, - W::OUTPUT_ATTACHMENT if is_color => L::ColorAttachmentOptimal, - W::OUTPUT_ATTACHMENT => L::DepthStencilAttachmentOptimal, //TODO: read-only depth/stencil + W::ATTACHMENT_READ | W::ATTACHMENT_WRITE if is_color => L::ColorAttachmentOptimal, + W::ATTACHMENT_READ => L::DepthStencilReadOnlyOptimal, + W::ATTACHMENT_WRITE => L::DepthStencilAttachmentOptimal, _ => L::General, }; @@ -545,8 +546,14 @@ pub(crate) fn map_texture_state( if usage.contains(W::SAMPLED) { access |= A::SHADER_READ; } - if usage.contains(W::OUTPUT_ATTACHMENT) { - //TODO: read-only attachments + if usage.contains(W::ATTACHMENT_READ) { + access |= if is_color { + A::COLOR_ATTACHMENT_READ + } else { + A::DEPTH_STENCIL_ATTACHMENT_READ + }; + } + if usage.contains(W::ATTACHMENT_WRITE) { access |= if is_color { A::COLOR_ATTACHMENT_WRITE } else { diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 829cee569..c7b6ec8ef 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -107,7 +107,7 @@ impl RenderPassContext { } } -pub(crate) type RenderPassKey = AttachmentData; +pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::image::Layout)>; pub(crate) type FramebufferKey = AttachmentData; pub(crate) type RenderPassContext = AttachmentData; @@ -494,6 +494,39 @@ impl Device { life_guard: LifeGuard::new(), } } + + /// Create a compatible render pass with a given key. + /// + /// This functions doesn't consider the following aspects for compatibility: + /// - image layouts + /// - resolve attachments + fn create_compatible_render_pass(&self, key: &RenderPassKey) -> B::RenderPass { + let mut color_ids = [(0, hal::image::Layout::ColorAttachmentOptimal); MAX_COLOR_TARGETS]; + for i in 0..key.colors.len() { + color_ids[i].0 = i; + } + let depth_id = key.depth_stencil.as_ref().map(|_| { + ( + key.colors.len(), + hal::image::Layout::DepthStencilAttachmentOptimal, + ) + }); + + let subpass = hal::pass::SubpassDesc { + colors: &color_ids[..key.colors.len()], + depth_stencil: depth_id.as_ref(), + inputs: &[], + resolves: &[], + preserves: &[], + }; + let all = key.all().map(|(at, _)| at); + + unsafe { + self.raw + .create_render_pass(all, iter::once(subpass), &[]) + .unwrap() + } + } } impl Device { @@ -1857,12 +1890,18 @@ impl Global { let rp_key = RenderPassKey { colors: color_states .iter() - .map(|at| hal::pass::Attachment { - format: Some(conv::map_texture_format(at.format, device.private_features)), - samples: sc, - ops: hal::pass::AttachmentOps::PRESERVE, - stencil_ops: hal::pass::AttachmentOps::DONT_CARE, - layouts: hal::image::Layout::General..hal::image::Layout::General, + .map(|state| { + let at = hal::pass::Attachment { + format: Some(conv::map_texture_format( + state.format, + device.private_features, + )), + samples: sc, + ops: hal::pass::AttachmentOps::PRESERVE, + stencil_ops: hal::pass::AttachmentOps::DONT_CARE, + layouts: hal::image::Layout::General..hal::image::Layout::General, + }; + (at, hal::image::Layout::ColorAttachmentOptimal) }) .collect(), // We can ignore the resolves as the vulkan specs says: @@ -1870,47 +1909,19 @@ impl Global { // they are compatible even if they have different resolve attachment references // or depth/stencil resolve modes but satisfy the other compatibility conditions. resolves: ArrayVec::new(), - depth_stencil: depth_stencil_state.map(|at| hal::pass::Attachment { - format: Some(conv::map_texture_format(at.format, device.private_features)), - samples: sc, - ops: hal::pass::AttachmentOps::PRESERVE, - stencil_ops: hal::pass::AttachmentOps::PRESERVE, - layouts: hal::image::Layout::General..hal::image::Layout::General, - }), - }; - - let mut render_pass_cache = device.render_passes.lock(); - let main_pass = match render_pass_cache.entry(rp_key) { - 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 depth_id = ( - desc.color_states_length, - hal::image::Layout::DepthStencilAttachmentOptimal, - ); - - let subpass = hal::pass::SubpassDesc { - colors: &color_ids[..desc.color_states_length], - depth_stencil: depth_stencil_state.map(|_| &depth_id), - inputs: &[], - resolves: &[], - preserves: &[], + depth_stencil: depth_stencil_state.map(|state| { + let at = hal::pass::Attachment { + format: Some(conv::map_texture_format( + state.format, + device.private_features, + )), + samples: sc, + ops: hal::pass::AttachmentOps::PRESERVE, + stencil_ops: hal::pass::AttachmentOps::PRESERVE, + layouts: hal::image::Layout::General..hal::image::Layout::General, }; - - let pass = unsafe { - device - .raw - .create_render_pass(e.key().all(), &[subpass], &[]) - } - .unwrap(); - e.insert(pass) - } + (at, hal::image::Layout::DepthStencilAttachmentOptimal) + }), }; let vertex = { @@ -1956,7 +1967,7 @@ impl Global { } hal::pso::EntryPoint:: { - entry: entry_point_name, // TODO + entry: entry_point_name, module: &shader_module.raw, specialization: hal::pso::Specialization::EMPTY, } @@ -1971,16 +1982,10 @@ impl Global { fragment, }; - let subpass = hal::pass::Subpass { - index: 0, - main_pass, - }; - // TODO let flags = hal::pso::PipelineCreationFlags::empty(); - // TODO - let parent = hal::pso::BasePipeline::None; + let mut render_pass_cache = device.render_passes.lock(); let pipeline_desc = hal::pso::GraphicsPipelineDesc { shaders, rasterizer, @@ -1992,11 +1997,19 @@ impl Global { multisampling, baked_states, layout: &layout.raw, - subpass, + subpass: hal::pass::Subpass { + index: 0, + main_pass: match render_pass_cache.entry(rp_key) { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + let pass = device.create_compatible_render_pass(e.key()); + e.insert(pass) + } + }, + }, flags, - parent, + parent: hal::pso::BasePipeline::None, }; - // TODO: cache let pipeline = unsafe { device @@ -2004,6 +2017,7 @@ impl Global { .create_graphics_pipeline(&pipeline_desc, None) .unwrap() }; + (pipeline, layout.life_guard.add_ref()) }; @@ -2023,6 +2037,9 @@ impl Global { if ds.needs_stencil_reference() { flags |= pipeline::PipelineFlags::STENCIL_REFERENCE; } + if ds.is_read_only() { + flags |= pipeline::PipelineFlags::DEPTH_STENCIL_READ_ONLY; + } } let pipeline = pipeline::RenderPipeline { diff --git a/wgpu-core/src/pipeline.rs b/wgpu-core/src/pipeline.rs index 0d3749998..bff27850b 100644 --- a/wgpu-core/src/pipeline.rs +++ b/wgpu-core/src/pipeline.rs @@ -93,6 +93,7 @@ bitflags::bitflags! { pub struct PipelineFlags: u32 { const BLEND_COLOR = 1; const STENCIL_REFERENCE = 2; + const DEPTH_STENCIL_READ_ONLY = 4; } } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 97d686a92..b02ad3c51 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -47,17 +47,18 @@ bitflags::bitflags! { const COPY_SRC = 1; const COPY_DST = 2; const SAMPLED = 4; - const OUTPUT_ATTACHMENT = 8; - const STORAGE_LOAD = 16; - const STORAGE_STORE = 32; + const ATTACHMENT_READ = 8; + const ATTACHMENT_WRITE = 16; + const STORAGE_LOAD = 32; + const STORAGE_STORE = 48; /// The combination of all read-only usages. - const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::STORAGE_LOAD.bits; + const READ_ALL = Self::COPY_SRC.bits | Self::SAMPLED.bits | Self::ATTACHMENT_READ.bits | Self::STORAGE_LOAD.bits; /// The combination of all write-only and read-write usages. - const WRITE_ALL = Self::COPY_DST.bits | Self::OUTPUT_ATTACHMENT.bits | Self::STORAGE_STORE.bits; + const WRITE_ALL = Self::COPY_DST.bits | Self::ATTACHMENT_WRITE.bits | Self::STORAGE_STORE.bits; /// The combination of all usages that the are guaranteed to be be ordered by the hardware. /// If a usage is not ordered, then even if it doesn't change between draw calls, there /// still need to be pipeline barriers inserted for synchronization. - const ORDERED = Self::READ_ALL.bits | Self::COPY_DST.bits | Self::OUTPUT_ATTACHMENT.bits; + const ORDERED = Self::READ_ALL.bits | Self::COPY_DST.bits | Self::ATTACHMENT_WRITE.bits; const UNINITIALIZED = 0xFFFF; } } diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 77d1cd713..4fc2720d0 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -342,7 +342,7 @@ mod test { 2..3, Unit { first: Some(TextureUse::COPY_SRC), - last: TextureUse::OUTPUT_ATTACHMENT, + last: TextureUse::ATTACHMENT_WRITE, }, ), ]); @@ -385,7 +385,7 @@ mod test { ts1.mips[0].query(&(2..3), |&v| v), Some(Ok(Unit { first: Some(TextureUse::SAMPLED), - last: TextureUse::OUTPUT_ATTACHMENT, + last: TextureUse::ATTACHMENT_WRITE, })), "wrong final layer 2 state" ); @@ -394,7 +394,7 @@ mod test { ts2.mips[0] = PlaneStates::from_slice(&[( 2..3, Unit { - first: Some(TextureUse::OUTPUT_ATTACHMENT), + first: Some(TextureUse::ATTACHMENT_WRITE), last: TextureUse::COPY_SRC, }, )]); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index d59e65061..7011b2ada 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -424,6 +424,9 @@ impl DepthStencilStateDescriptor { pub fn needs_stencil_reference(&self) -> bool { !self.stencil_front.compare.is_trivial() || !self.stencil_back.compare.is_trivial() } + pub fn is_read_only(&self) -> bool { + !self.depth_write_enabled && self.stencil_write_mask == 0 + } } #[repr(C)] @@ -719,9 +722,11 @@ pub struct RenderPassDepthStencilAttachmentDescriptorBase { pub depth_load_op: LoadOp, pub depth_store_op: StoreOp, pub clear_depth: f32, + pub depth_read_only: bool, pub stencil_load_op: LoadOp, pub stencil_store_op: StoreOp, pub clear_stencil: u32, + pub stencil_read_only: bool, } #[repr(C)]