mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-29 18:23:36 +00:00
Merge #685
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:
commit
fbc2c87de6
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -93,6 +93,7 @@ bitflags::bitflags! {
|
||||
pub struct PipelineFlags: u32 {
|
||||
const BLEND_COLOR = 1;
|
||||
const STENCIL_REFERENCE = 2;
|
||||
const DEPTH_STENCIL_READ_ONLY = 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
},
|
||||
)]);
|
||||
|
@ -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)]
|
||||
|
Loading…
Reference in New Issue
Block a user