685: Read-only depth-stencil support (RODS) r=cwfitzgerald a=kvark

**Connections**
Fixes #680 
- [ ] wgpu-native update
- [x] wgpu-rs update - https://github.com/gfx-rs/wgpu-rs/pull/340

**Description**
~~Interestingly, this requires us to create an extra pipeline state for RODS-compatible render pipelines (one main, and one with read-only depth-stencil). This also means we are creating another compatible render pass, internally (done once).~~

**Testing**
I don't know for sure that this works properly, but I'd be comfortable landing this at least if the existing functions aren't broken.


Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
bors[bot] 2020-06-02 00:11:54 +00:00 committed by GitHub
commit fbc2c87de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 239 additions and 153 deletions

View File

@ -211,6 +211,7 @@ struct PassComponent<T> {
load_op: wgt::LoadOp,
store_op: wgt::StoreOp,
clear_value: T,
read_only: bool,
}
// required for PeekPoke
@ -220,6 +221,7 @@ impl<T: Default> Default for PassComponent<T> {
load_op: wgt::LoadOp::Clear,
store_op: wgt::StoreOp::Clear,
clear_value: T::default(),
read_only: false,
}
}
}

View File

@ -37,6 +37,14 @@ pub type RenderPassColorAttachmentDescriptor =
pub type RenderPassDepthStencilAttachmentDescriptor =
RenderPassDepthStencilAttachmentDescriptorBase<id::TextureViewId>;
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
);
const MAX_TOTAL_ATTACHMENTS: usize = 10;
type OutputAttachment<'a> = (
&'a Stored<id::TextureId>,
&'a hal::image::SubresourceRange,
Option<TextureUse>,
);
struct OutputAttachment<'a> {
texture_id: &'a Stored<id::TextureId>,
range: &'a hal::image::SubresourceRange,
previous_use: Option<TextureUse>,
new_use: TextureUse,
}
let mut output_attachments =
ArrayVec::<[OutputAttachment; MAX_TOTAL_ATTACHMENTS]>::new();
@ -420,23 +438,29 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
};
// 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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
}
};
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
}
};
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<G: GlobalIdentityHandlerFactory> Global<G> {
),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts,
});
};
resolves.push((resolve_at, hal::image::Layout::ColorAttachmentOptimal));
}
RenderPassKey {
@ -584,30 +627,29 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
};
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
.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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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

View File

@ -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 {

View File

@ -107,7 +107,7 @@ impl RenderPassContext {
}
}
pub(crate) type RenderPassKey = AttachmentData<hal::pass::Attachment>;
pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::image::Layout)>;
pub(crate) type FramebufferKey = AttachmentData<id::TextureViewId>;
pub(crate) type RenderPassContext = AttachmentData<TextureFormat>;
@ -494,6 +494,39 @@ impl<B: GfxBackend> Device<B> {
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<B: hal::Backend> Device<B> {
@ -1857,12 +1890,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
// 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<G: GlobalIdentityHandlerFactory> Global<G> {
}
hal::pso::EntryPoint::<B> {
entry: entry_point_name, // TODO
entry: entry_point_name,
module: &shader_module.raw,
specialization: hal::pso::Specialization::EMPTY,
}
@ -1971,16 +1982,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
.create_graphics_pipeline(&pipeline_desc, None)
.unwrap()
};
(pipeline, layout.life_guard.add_ref())
};
@ -2023,6 +2037,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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 {

View File

@ -93,6 +93,7 @@ bitflags::bitflags! {
pub struct PipelineFlags: u32 {
const BLEND_COLOR = 1;
const STENCIL_REFERENCE = 2;
const DEPTH_STENCIL_READ_ONLY = 4;
}
}

View File

@ -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;
}
}

View File

@ -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,
},
)]);

View File

@ -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<T> {
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)]