mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 16:25:31 +00:00
Work on renderpass layout
This commit is contained in:
parent
e0795b55b7
commit
25be5132cf
@ -9,5 +9,8 @@
|
|||||||
|
|
||||||
- [Can't cast an `ImageResource` into a `Resource` even though the former depends on the latter](https://github.com/rust-lang/rust/issues/5665).
|
- [Can't cast an `ImageResource` into a `Resource` even though the former depends on the latter](https://github.com/rust-lang/rust/issues/5665).
|
||||||
|
|
||||||
|
- This library was designed with specialization in mind. There are several `is_compatible` trait methods that perform deep comparisons between
|
||||||
|
layouts. With specialization available, these methods could be specialized as `true` for layouts that are known to always be compatible.
|
||||||
|
|
||||||
- https://github.com/rust-lang/rust/issues/29328
|
- https://github.com/rust-lang/rust/issues/29328
|
||||||
|
|
||||||
|
@ -44,9 +44,6 @@ pub unsafe trait RenderPassLayout {
|
|||||||
/// Iterator that produces one clear value per attachment.
|
/// Iterator that produces one clear value per attachment.
|
||||||
type ClearValuesIter: Iterator<Item = ClearValue>;
|
type ClearValuesIter: Iterator<Item = ClearValue>;
|
||||||
|
|
||||||
/// Iterator that produces attachments.
|
|
||||||
type AttachmentsIter: Iterator<Item = AttachmentDescription>;
|
|
||||||
|
|
||||||
/// Decodes a `ClearValues` into a list of clear values where each element corresponds
|
/// Decodes a `ClearValues` into a list of clear values where each element corresponds
|
||||||
/// to an attachment. The size of the returned array must be the same as the number of
|
/// to an attachment. The size of the returned array must be the same as the number of
|
||||||
/// attachments.
|
/// attachments.
|
||||||
@ -55,8 +52,23 @@ pub unsafe trait RenderPassLayout {
|
|||||||
/// that are loaded with `LoadOp::Clear` must have an entry in the array.
|
/// that are loaded with `LoadOp::Clear` must have an entry in the array.
|
||||||
fn convert_clear_values(&self, Self::ClearValues) -> Self::ClearValuesIter;
|
fn convert_clear_values(&self, Self::ClearValues) -> Self::ClearValuesIter;
|
||||||
|
|
||||||
|
/// Iterator that produces attachments.
|
||||||
|
type AttachmentsIter: ExactSizeIterator<Item = AttachmentDescription>;
|
||||||
|
|
||||||
/// Returns the descriptions of the attachments.
|
/// Returns the descriptions of the attachments.
|
||||||
fn attachments(&self) -> Self::AttachmentsIter;
|
fn attachments(&self) -> Self::AttachmentsIter;
|
||||||
|
|
||||||
|
/// Iterator that produces passes.
|
||||||
|
type PassesIter: ExactSizeIterator<Item = PassDescription>;
|
||||||
|
|
||||||
|
/// Returns the descriptions of the passes.
|
||||||
|
fn passes(&self) -> Self::PassesIter;
|
||||||
|
|
||||||
|
/// Iterator that produces pass dependencies.
|
||||||
|
type PassDependenciesIter: ExactSizeIterator<Item = PassDependencyDescription>;
|
||||||
|
|
||||||
|
/// Returns the descriptions of the dependencies between passes.
|
||||||
|
fn pass_dependencies(&self) -> Self::PassDependenciesIter;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe trait RenderPassLayoutExt<'a, M: 'a>: RenderPassLayout {
|
pub unsafe trait RenderPassLayoutExt<'a, M: 'a>: RenderPassLayout {
|
||||||
@ -65,6 +77,35 @@ pub unsafe trait RenderPassLayoutExt<'a, M: 'a>: RenderPassLayout {
|
|||||||
fn ids(&self, &Self::AttachmentsList) -> (Vec<Arc<ImageResource>>, Vec<u64>);
|
fn ids(&self, &Self::AttachmentsList) -> (Vec<Arc<ImageResource>>, Vec<u64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait implemented on renderpass layouts to check whether they are compatible
|
||||||
|
/// with another layout.
|
||||||
|
///
|
||||||
|
/// The trait is automatically implemented for all type that implement `RenderPassLayout`.
|
||||||
|
// TODO: once specialization lands, this trait can be specialized for pairs that are known to
|
||||||
|
// always be compatible
|
||||||
|
// TODO: maybe this can be unimplemented on some pairs, to provide compile-time checks?
|
||||||
|
pub unsafe trait CompatibleLayout<Other>: RenderPassLayout where Other: RenderPassLayout {
|
||||||
|
/// Returns `true` if this layout is compatible with the other layout, as defined in the
|
||||||
|
/// `Render Pass Compatibility` section of the Vulkan specs.
|
||||||
|
fn is_compatible_with(&self, other: &Other) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<A, B> CompatibleLayout<B> for A
|
||||||
|
where A: RenderPassLayout, B: RenderPassLayout
|
||||||
|
{
|
||||||
|
fn is_compatible_with(&self, other: &B) -> bool {
|
||||||
|
for (atch1, atch2) in self.attachments().zip(other.attachments()) {
|
||||||
|
if !atch1.is_compatible_with(&atch2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// FIXME: finish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes a uniform value that will be used to fill an attachment at the start of the
|
/// Describes a uniform value that will be used to fill an attachment at the start of the
|
||||||
/// renderpass.
|
/// renderpass.
|
||||||
// TODO: should have the same layout as `vk::ClearValue` for performances
|
// TODO: should have the same layout as `vk::ClearValue` for performances
|
||||||
@ -96,6 +137,41 @@ pub struct AttachmentDescription {
|
|||||||
pub final_layout: ImageLayout,
|
pub final_layout: ImageLayout,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AttachmentDescription {
|
||||||
|
/// Returns true if this attachment is compatible with another attachment, as defined in the
|
||||||
|
/// `Render Pass Compatibility` section of the Vulkan specs.
|
||||||
|
#[inline]
|
||||||
|
pub fn is_compatible_with(&self, other: &AttachmentDescription) -> bool {
|
||||||
|
self.format == other.format && self.samples == other.samples
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PassDescription {
|
||||||
|
/// Indices of attachments to use as color attachments.
|
||||||
|
pub color_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
|
||||||
|
pub depth_stencil: Option<(usize, ImageLayout)>,
|
||||||
|
/// Indices of attachments to use as input attachments.
|
||||||
|
pub input_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
|
||||||
|
/// If not empty, each color attachment will be resolved into each corresponding entry of
|
||||||
|
/// this list.
|
||||||
|
///
|
||||||
|
/// If this value is not empty, it **must** be the same length as `color_attachments`.
|
||||||
|
pub resolve_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
|
||||||
|
/// Indices of attachments that will be preserved during this pass.
|
||||||
|
pub preserve_attachments: Vec<usize>, // TODO: Vec is slow
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: finish
|
||||||
|
pub struct PassDependencyDescription {
|
||||||
|
pub source_subpass: usize,
|
||||||
|
pub destination_subpass: usize,
|
||||||
|
/*VkPipelineStageFlags srcStageMask;
|
||||||
|
VkPipelineStageFlags dstStageMask;
|
||||||
|
VkAccessFlags srcAccessMask;
|
||||||
|
VkAccessFlags dstAccessMask;*/
|
||||||
|
pub by_region: bool,
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a `RenderPass` object.
|
/// Builds a `RenderPass` object.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! renderpass {
|
macro_rules! renderpass {
|
||||||
@ -218,6 +294,8 @@ impl<L> RenderPass<L> where L: RenderPassLayout {
|
|||||||
pub fn new(device: &Arc<Device>, layout: L) -> Result<Arc<RenderPass<L>>, OomError> {
|
pub fn new(device: &Arc<Device>, layout: L) -> Result<Arc<RenderPass<L>>, OomError> {
|
||||||
let vk = device.pointers();
|
let vk = device.pointers();
|
||||||
|
|
||||||
|
// TODO: check the validity of the renderpass layout with debug_assert!
|
||||||
|
|
||||||
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
||||||
let attachments = layout.attachments().map(|attachment| {
|
let attachments = layout.attachments().map(|attachment| {
|
||||||
vk::AttachmentDescription {
|
vk::AttachmentDescription {
|
||||||
@ -233,28 +311,91 @@ impl<L> RenderPass<L> where L: RenderPassLayout {
|
|||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// FIXME: totally hacky
|
|
||||||
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
||||||
let color_attachment_references = layout.attachments().map(|attachment| {
|
let attachment_references = layout.passes().flat_map(|pass| {
|
||||||
vk::AttachmentReference {
|
debug_assert!(pass.resolve_attachments.is_empty() ||
|
||||||
attachment: 0,
|
pass.resolve_attachments.len() == pass.color_attachments.len());
|
||||||
layout: vk::IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
let resolve = pass.resolve_attachments.into_iter().map(|(offset, img_la)| {
|
||||||
}
|
debug_assert!(offset < layout.attachments().len());
|
||||||
|
vk::AttachmentReference { attachment: offset as u32, layout: img_la as u32, }
|
||||||
|
});
|
||||||
|
|
||||||
|
let color = pass.color_attachments.into_iter().map(|(offset, img_la)| {
|
||||||
|
debug_assert!(offset < layout.attachments().len());
|
||||||
|
vk::AttachmentReference { attachment: offset as u32, layout: img_la as u32, }
|
||||||
|
});
|
||||||
|
|
||||||
|
let input = pass.input_attachments.into_iter().map(|(offset, img_la)| {
|
||||||
|
debug_assert!(offset < layout.attachments().len());
|
||||||
|
vk::AttachmentReference { attachment: offset as u32, layout: img_la as u32, }
|
||||||
|
});
|
||||||
|
|
||||||
|
let depthstencil = if let Some((offset, img_la)) = pass.depth_stencil {
|
||||||
|
Some(vk::AttachmentReference { attachment: offset as u32, layout: img_la as u32, })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}.into_iter();
|
||||||
|
|
||||||
|
color.chain(input).chain(resolve).chain(depthstencil)
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
||||||
let passes = (0 .. 1).map(|_| {
|
let preserve_attachments_references = layout.passes().flat_map(|pass| {
|
||||||
|
pass.preserve_attachments.into_iter().map(|offset| offset as u32)
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
||||||
|
let mut ref_index = 0usize;
|
||||||
|
let mut preserve_ref_index = 0usize;
|
||||||
|
let passes = layout.passes().map(|pass| {
|
||||||
|
unsafe {
|
||||||
|
let color_attachments = attachment_references.as_ptr().offset(ref_index as isize);
|
||||||
|
ref_index += pass.color_attachments.len();
|
||||||
|
let input_attachments = attachment_references.as_ptr().offset(ref_index as isize);
|
||||||
|
ref_index += pass.input_attachments.len();
|
||||||
|
let resolve_attachments = attachment_references.as_ptr().offset(ref_index as isize);
|
||||||
|
ref_index += pass.resolve_attachments.len();
|
||||||
|
let depth_stencil = if pass.depth_stencil.is_some() {
|
||||||
|
let a = attachment_references.as_ptr().offset(ref_index as isize);
|
||||||
|
ref_index += 1;
|
||||||
|
a
|
||||||
|
} else {
|
||||||
|
ptr::null()
|
||||||
|
};
|
||||||
|
|
||||||
|
let preserve_attachments = preserve_attachments_references.as_ptr().offset(preserve_ref_index as isize);
|
||||||
|
preserve_ref_index += pass.preserve_attachments.len();
|
||||||
|
|
||||||
vk::SubpassDescription {
|
vk::SubpassDescription {
|
||||||
flags: 0, // reserved
|
flags: 0, // reserved
|
||||||
pipelineBindPoint: vk::PIPELINE_BIND_POINT_GRAPHICS,
|
pipelineBindPoint: vk::PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
inputAttachmentCount: 0, // FIXME:
|
inputAttachmentCount: pass.input_attachments.len() as u32,
|
||||||
pInputAttachments: ptr::null(), // FIXME:
|
pInputAttachments: input_attachments,
|
||||||
colorAttachmentCount: color_attachment_references.len() as u32, // FIXME:
|
colorAttachmentCount: pass.input_attachments.len() as u32,
|
||||||
pColorAttachments: color_attachment_references.as_ptr(), // FIXME:
|
pColorAttachments: color_attachments,
|
||||||
pResolveAttachments: ptr::null(), // FIXME:
|
pResolveAttachments: if pass.resolve_attachments.len() == 0 { ptr::null() } else { resolve_attachments },
|
||||||
pDepthStencilAttachment: ptr::null(), // FIXME:
|
pDepthStencilAttachment: ptr::null(), // FIXME:
|
||||||
preserveAttachmentCount: 0, // FIXME:
|
preserveAttachmentCount: pass.preserve_attachments.len() as u32,
|
||||||
pPreserveAttachments: ptr::null(), // FIXME:
|
pPreserveAttachments: preserve_attachments,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).collect::<Vec<_>>();
|
||||||
|
debug_assert!(ref_index == attachment_references.len());
|
||||||
|
debug_assert!(preserve_ref_index == preserve_attachments_references.len());
|
||||||
|
|
||||||
|
// TODO: allocate on stack instead (https://github.com/rust-lang/rfcs/issues/618)
|
||||||
|
let dependencies = layout.pass_dependencies().map(|dependency| {
|
||||||
|
debug_assert!(dependency.source_subpass < layout.passes().len());
|
||||||
|
debug_assert!(dependency.destination_subpass < layout.passes().len());
|
||||||
|
|
||||||
|
vk::SubpassDependency {
|
||||||
|
srcSubpass: dependency.source_subpass as u32,
|
||||||
|
dstSubpass: dependency.destination_subpass as u32,
|
||||||
|
srcStageMask: vk::PIPELINE_STAGE_ALL_COMMANDS_BIT, // FIXME:
|
||||||
|
dstStageMask: vk::PIPELINE_STAGE_ALL_COMMANDS_BIT, // FIXME:
|
||||||
|
srcAccessMask: vk::ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // FIXME:
|
||||||
|
dstAccessMask: vk::ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // FIXME:
|
||||||
|
dependencyFlags: if dependency.by_region { vk::DEPENDENCY_BY_REGION_BIT } else { 0 },
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
|
||||||
@ -267,8 +408,8 @@ impl<L> RenderPass<L> where L: RenderPassLayout {
|
|||||||
pAttachments: attachments.as_ptr(),
|
pAttachments: attachments.as_ptr(),
|
||||||
subpassCount: passes.len() as u32,
|
subpassCount: passes.len() as u32,
|
||||||
pSubpasses: passes.as_ptr(),
|
pSubpasses: passes.as_ptr(),
|
||||||
dependencyCount: 0, // FIXME:
|
dependencyCount: dependencies.len() as u32,
|
||||||
pDependencies: ptr::null(), // FIXME:
|
pDependencies: dependencies.as_ptr(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = mem::uninitialized();
|
let mut output = mem::uninitialized();
|
||||||
@ -315,8 +456,11 @@ impl<L> RenderPass<L> where L: RenderPassLayout {
|
|||||||
///
|
///
|
||||||
/// This means that framebuffers created with this renderpass can also be used alongside with
|
/// This means that framebuffers created with this renderpass can also be used alongside with
|
||||||
/// the other renderpass.
|
/// the other renderpass.
|
||||||
pub fn is_compatible_with<R2>(&self, other: &RenderPass<R2>) -> bool {
|
#[inline]
|
||||||
true // FIXME:
|
pub fn is_compatible_with<R2>(&self, other: &RenderPass<R2>) -> bool
|
||||||
|
where R2: RenderPassLayout
|
||||||
|
{
|
||||||
|
self.layout.is_compatible_with(&other.layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the layout used to create this renderpass.
|
/// Returns the layout used to create this renderpass.
|
||||||
|
Loading…
Reference in New Issue
Block a user