Compare commits
No commits in common. "rendergraph2" and "main" have entirely different histories.
rendergrap
...
main
|
|
@ -449,11 +449,7 @@ impl Image {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// update imageview desc to make sure the mip range and layer ranges don't contain `vk::REMAINING_MIP_LEVELS`.
|
if !desc.mip_range.fits_in(self.desc.mip_levels) {
|
||||||
desc.mip_range.set_max_end(self.desc.mip_levels);
|
|
||||||
desc.layer_range.set_max_end(self.desc.array_layers);
|
|
||||||
|
|
||||||
if !MipRange::from(..self.desc.mip_levels).contains(desc.mip_range) {
|
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
"image view mip range {:?} exceeds image mip levels {}",
|
"image view mip range {:?} exceeds image mip levels {}",
|
||||||
desc.mip_range,
|
desc.mip_range,
|
||||||
|
|
@ -789,12 +785,10 @@ impl From<(i32, i32, i32)> for Offset {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `start..end` range of mip levels or array layers.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
#[repr(C)]
|
|
||||||
pub struct MipRange {
|
pub struct MipRange {
|
||||||
pub start: u32,
|
start: u32,
|
||||||
pub end: u32,
|
end: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MipRange {
|
impl Default for MipRange {
|
||||||
|
|
@ -807,24 +801,6 @@ impl Default for MipRange {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MipRange {
|
impl MipRange {
|
||||||
pub fn new(start: u32, end: u32) -> Self {
|
|
||||||
Self { start, end }
|
|
||||||
}
|
|
||||||
pub fn single(level: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
start: level,
|
|
||||||
end: level + 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn with_max_end(mut self, end: u32) -> Self {
|
|
||||||
self.set_max_end(end);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
pub fn set_max_end(&mut self, end: u32) {
|
|
||||||
if self.end == vk::REMAINING_MIP_LEVELS {
|
|
||||||
self.end = end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn len(&self) -> u32 {
|
pub fn len(&self) -> u32 {
|
||||||
self.end - self.start
|
self.end - self.start
|
||||||
}
|
}
|
||||||
|
|
@ -837,8 +813,6 @@ impl MipRange {
|
||||||
self.end
|
self.end
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the intersection of this range with another range.
|
|
||||||
/// If the ranges do not intersect, returns an empty range.
|
|
||||||
pub fn range(&self, other: &Self) -> Self {
|
pub fn range(&self, other: &Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: self.start.max(other.start).min(self.end),
|
start: self.start.max(other.start).min(self.end),
|
||||||
|
|
@ -854,19 +828,10 @@ impl MipRange {
|
||||||
self.start < total_mips && (self.end == vk::REMAINING_MIP_LEVELS || self.end <= total_mips)
|
self.start < total_mips && (self.end == vk::REMAINING_MIP_LEVELS || self.end <= total_mips)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn contains(&self, other: Self) -> bool {
|
pub fn intersects(&self, other: &Self) -> bool {
|
||||||
self.start <= other.start && self.end >= other.end
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn intersects(&self, other: Self) -> bool {
|
|
||||||
self.start < other.end && self.end > other.start
|
self.start < other.end && self.end > other.start
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the union of this range with another range.
|
|
||||||
/// The union of two ranges is the smallest range that contains both ranges.
|
|
||||||
/// Note that since the union of two ranges may contain values that are not
|
|
||||||
/// in either range, this function does not satisfy the properties of a
|
|
||||||
/// mathematical union operation.
|
|
||||||
pub fn union(&self, other: &Self) -> Self {
|
pub fn union(&self, other: &Self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start: self.start.min(other.start),
|
start: self.start.min(other.start),
|
||||||
|
|
@ -875,59 +840,6 @@ impl MipRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};
|
|
||||||
|
|
||||||
macro_rules! impl_op {
|
|
||||||
(impl $trait:ident {$fn:ident} for $ty:ident { fn: $method:ident }) => {
|
|
||||||
impl $trait for $ty {
|
|
||||||
type Output = $ty;
|
|
||||||
|
|
||||||
fn $fn(self, rhs: $ty) -> Self::Output {
|
|
||||||
self.$method(&rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl $trait<&$ty> for $ty {
|
|
||||||
type Output = $ty;
|
|
||||||
|
|
||||||
fn $fn(self, rhs: &$ty) -> Self::Output {
|
|
||||||
self.$method(rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl $trait<&$ty> for &$ty {
|
|
||||||
type Output = $ty;
|
|
||||||
|
|
||||||
fn $fn(self, rhs: &$ty) -> Self::Output {
|
|
||||||
self.$method(rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl $trait<$ty> for &$ty {
|
|
||||||
type Output = $ty;
|
|
||||||
|
|
||||||
fn $fn(self, rhs: $ty) -> Self::Output {
|
|
||||||
self.$method(&rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
(impl $trait:ident {$fn:ident} for $ty:ident { λ: $method:expr }) => {
|
|
||||||
impl $trait for $ty {
|
|
||||||
fn $fn(&mut self, rhs: $ty) {
|
|
||||||
$method(self, &rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl $trait<&$ty> for $ty {
|
|
||||||
fn $fn(&mut self, rhs: &$ty) {
|
|
||||||
$method(self, rhs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_op!(impl BitOr { bitor } for MipRange { fn: union });
|
|
||||||
impl_op!(impl BitOrAssign { bitor_assign } for MipRange { λ: |this: &mut MipRange, other: &MipRange| {*this = this.union(other)} });
|
|
||||||
impl_op!(impl BitAnd { bitand } for MipRange { fn: range });
|
|
||||||
impl_op!(impl BitAndAssign { bitand_assign } for MipRange { λ: |this: &mut MipRange, other: &MipRange| {*this = this.range(other)} });
|
|
||||||
|
|
||||||
impl IntoIterator for MipRange {
|
impl IntoIterator for MipRange {
|
||||||
type Item = u32;
|
type Item = u32;
|
||||||
|
|
||||||
|
|
@ -1159,89 +1071,6 @@ pub enum FormatClass {
|
||||||
YuvG14X2B14X2R14X2Biplane422,
|
YuvG14X2B14X2R14X2Biplane422,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatClass {
|
|
||||||
pub fn block_size(self) -> u32 {
|
|
||||||
use FormatClass::*;
|
|
||||||
|
|
||||||
match self {
|
|
||||||
S8 | Bits8 | Alpha8 => 1,
|
|
||||||
D16 | Bits16 => 2,
|
|
||||||
Bits24 | D24 | D16S8 => 3,
|
|
||||||
Bits32 | D24S8 => 4,
|
|
||||||
D32S8 => 5,
|
|
||||||
Bits48 => 6,
|
|
||||||
Bits64 | D32 => 8,
|
|
||||||
Bits96 => 12,
|
|
||||||
Bits128 => 16,
|
|
||||||
Bits192 => 24,
|
|
||||||
Bits256 => 32,
|
|
||||||
|
|
||||||
Bc1Rgb | Bc1Rgba => 8,
|
|
||||||
Bc2 | Bc3 | Bc6h | Bc7 => 16,
|
|
||||||
Bc4 => 8,
|
|
||||||
Bc5 => 16,
|
|
||||||
|
|
||||||
Etc2Rgb | Etc2Rgba | EacR => 8,
|
|
||||||
Etc2EacRgba | EacRg => 16,
|
|
||||||
|
|
||||||
Astc4x4 | Astc5x4 | Astc5x5 | Astc6x5 | Astc6x6 | Astc8x5 | Astc8x6 | Astc8x8
|
|
||||||
| Astc10x5 | Astc10x6 | Astc10x8 | Astc10x10 | Astc12x10 | Astc12x12 => 16,
|
|
||||||
|
|
||||||
YuvG8B8G8R8_422 | YuvB8G8R8G8_422 => 2,
|
|
||||||
|
|
||||||
YuvG8B8R8Triplane420
|
|
||||||
| YuvG8B8R8Biplane420
|
|
||||||
| YuvG10X6B10X6R10X6Triplane420
|
|
||||||
| YuvG10X6B10X6R10X6Biplane420
|
|
||||||
| YuvG12X4B12X4R12X4Triplane420
|
|
||||||
| YuvG12X4B12X4R12X4Biplane420
|
|
||||||
| YuvG16B16R16Triplane420
|
|
||||||
| YuvG16B16R16Biplane420 => 1,
|
|
||||||
YuvG8B8R8Triplane422 => todo!(),
|
|
||||||
YuvG8B8R8Biplane422 => todo!(),
|
|
||||||
YuvG8B8R8Triplane444 => todo!(),
|
|
||||||
YuvG10X6B10X6R10X6Triplane422 => todo!(),
|
|
||||||
YuvG10X6B10X6R10X6Biplane422 => todo!(),
|
|
||||||
YuvG10X6B10X6R10X6Triplane444 => todo!(),
|
|
||||||
YuvG12X4B12X4R12X4Triplane422 => todo!(),
|
|
||||||
YuvG12X4B12X4R12X4Biplane422 => todo!(),
|
|
||||||
YuvG12X4B12X4R12X4Triplane444 => todo!(),
|
|
||||||
YuvG16B16R16Triplane422 => todo!(),
|
|
||||||
YuvG16B16R16Biplane422 => todo!(),
|
|
||||||
YuvG16B16R16Triplane444 => todo!(),
|
|
||||||
YuvG8B8R8Biplane444 => todo!(),
|
|
||||||
YuvG10X6B10X6R10X6Biplane444 => todo!(),
|
|
||||||
YuvG12X4B12X4R12X4Biplane444 => todo!(),
|
|
||||||
YuvG16B16R16Biplane444 => todo!(),
|
|
||||||
Bits64R10G10B10A10 => todo!(),
|
|
||||||
Bits64G10B10G10R10_422 => todo!(),
|
|
||||||
Bits64B10G10R10G10_422 => todo!(),
|
|
||||||
Bits64R12G12B12A12 => todo!(),
|
|
||||||
Bits64G12B12G12R12_422 => todo!(),
|
|
||||||
Bits64B12G12R12G12_422 => todo!(),
|
|
||||||
Bits64G16B16G16R16_422 => todo!(),
|
|
||||||
Bits64B16G16R16G16_422 => todo!(),
|
|
||||||
Bits64R14G14B14A14 => todo!(),
|
|
||||||
Pvrtc1_2bpp => todo!(),
|
|
||||||
Pvrtc1_4bpp => todo!(),
|
|
||||||
Pvrtc2_2bpp => todo!(),
|
|
||||||
Pvrtc2_4bpp => todo!(),
|
|
||||||
Astc3x3x3 => todo!(),
|
|
||||||
Astc4x3x3 => todo!(),
|
|
||||||
Astc4x4x3 => todo!(),
|
|
||||||
Astc4x4x4 => todo!(),
|
|
||||||
Astc5x4x4 => todo!(),
|
|
||||||
Astc5x5x4 => todo!(),
|
|
||||||
Astc5x5x5 => todo!(),
|
|
||||||
Astc6x5x5 => todo!(),
|
|
||||||
Astc6x6x5 => todo!(),
|
|
||||||
Astc6x6x6 => todo!(),
|
|
||||||
YuvG14X2B14X2R14X2Biplane420 => todo!(),
|
|
||||||
YuvG14X2B14X2R14X2Biplane422 => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<vk::Format> for FormatClass {
|
impl From<vk::Format> for FormatClass {
|
||||||
fn from(format: vk::Format) -> Self {
|
fn from(format: vk::Format) -> Self {
|
||||||
use vk::Format as F;
|
use vk::Format as F;
|
||||||
|
|
|
||||||
|
|
@ -41,142 +41,77 @@ impl<T: Resource> Command for ImportResource<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait BufferImageBufferCopyRegion {
|
// pub struct CopyBuffers {
|
||||||
fn regions(&self) -> &[BufferRows];
|
// pub src: Read<BufferSlice>,
|
||||||
}
|
// pub dst: Write<BufferSlice>,
|
||||||
impl BufferImageBufferCopyRegion for BufferRows {
|
// }
|
||||||
fn regions(&self) -> &[BufferRows] {
|
|
||||||
core::slice::from_ref(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: AsRef<[BufferRows]>> BufferImageBufferCopyRegion for T {
|
|
||||||
fn regions(&self) -> &[BufferRows] {
|
|
||||||
self.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ImageCopyRegion {
|
// pub struct CopyTextures {
|
||||||
fn regions(&self) -> &[TextureRegion];
|
// pub src: Read<TextureRegion>,
|
||||||
}
|
// pub dst: Write<TextureRegion>,
|
||||||
impl ImageCopyRegion for TextureRegion {
|
// }
|
||||||
fn regions(&self) -> &[TextureRegion] {
|
|
||||||
core::slice::from_ref(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: AsRef<[TextureRegion]>> ImageCopyRegion for T {
|
|
||||||
fn regions(&self) -> &[TextureRegion] {
|
|
||||||
self.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait BufferCopyRegion {
|
// pub struct CopyBufferToTexture {
|
||||||
fn regions(&self) -> &[BufferRange];
|
// pub src: Read<BufferSlice>,
|
||||||
}
|
// pub dst: Write<TextureRegion>,
|
||||||
impl BufferCopyRegion for BufferRange {
|
// }
|
||||||
fn regions(&self) -> &[BufferRange] {
|
|
||||||
core::slice::from_ref(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: AsRef<[BufferRange]>> BufferCopyRegion for T {
|
|
||||||
fn regions(&self) -> &[BufferRange] {
|
|
||||||
self.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CopyBuffers<T: BufferCopyRegion> {
|
// pub struct CopyTextureToBuffer {
|
||||||
pub src: Buffer,
|
// pub src: Read<TextureRegion>,
|
||||||
pub src_region: T,
|
// pub dst: Write<BufferSlice>,
|
||||||
pub dst: Buffer,
|
// }
|
||||||
pub dst_region: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CopyTextures<T: ImageCopyRegion> {
|
pub struct Copy<T: Resource, U: Resource> {
|
||||||
pub src: Texture,
|
pub src: T,
|
||||||
pub src_region: T,
|
pub dst: U,
|
||||||
pub dst: Texture,
|
|
||||||
pub dst_region: T,
|
|
||||||
}
|
}
|
||||||
|
impl<T: Resource, U: Resource> Copy<T, U> {
|
||||||
pub struct CopyBufferToTexture<T: BufferImageBufferCopyRegion, U: ImageCopyRegion> {
|
fn side_effects_inner(&self, mut map: SideEffectMap) {
|
||||||
pub src: Buffer,
|
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
||||||
pub src_region: T,
|
vk::PipelineStageFlags2::TRANSFER,
|
||||||
pub dst: Texture,
|
|
||||||
pub dst_region: U,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CopyTextureToBuffer<T: ImageCopyRegion, U: BufferImageBufferCopyRegion> {
|
|
||||||
pub src: Texture,
|
|
||||||
pub src_region: T,
|
|
||||||
pub dst: Buffer,
|
|
||||||
pub dst_region: U,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn copy_side_effects_inner<T, U>(src: &T, dst: &U, mut map: SideEffectMap)
|
|
||||||
where
|
|
||||||
T: Resource,
|
|
||||||
U: Resource,
|
|
||||||
{
|
|
||||||
src.side_effect(map.reborrow().into_side_effect_map2(
|
|
||||||
vk::PipelineStageFlags2::COPY,
|
|
||||||
vk::AccessFlags2::TRANSFER_READ,
|
vk::AccessFlags2::TRANSFER_READ,
|
||||||
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
||||||
));
|
));
|
||||||
dst.side_effect(map.reborrow().into_side_effect_map2(
|
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
||||||
vk::PipelineStageFlags2::COPY,
|
vk::PipelineStageFlags2::TRANSFER,
|
||||||
vk::AccessFlags2::TRANSFER_WRITE,
|
vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
));
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> Command for CopyBufferToTexture<T, U>
|
impl Command for Copy<BufferRowSlice, TextureRegion> {
|
||||||
where
|
fn side_effects(&self, map: SideEffectMap) {
|
||||||
T: BufferImageBufferCopyRegion,
|
self.side_effects_inner(map)
|
||||||
U: ImageCopyRegion,
|
|
||||||
{
|
|
||||||
fn side_effects(&self, mut map: SideEffectMap) {
|
|
||||||
let src_map = map.reborrow().into_side_effect_map2(
|
|
||||||
vk::PipelineStageFlags2::COPY,
|
|
||||||
vk::AccessFlags2::TRANSFER_READ,
|
|
||||||
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
|
||||||
);
|
|
||||||
|
|
||||||
let src_id = self.src.id();
|
|
||||||
for region in self.src_region.regions() {
|
|
||||||
src_map.insert_range(src_id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply(self, recorder: &mut CommandRecorder) {
|
fn apply(self, recorder: &mut CommandRecorder) {
|
||||||
let cmd = recorder.cmd_buffer();
|
let cmd = recorder.cmd_buffer();
|
||||||
let dev = &cmd.device().raw;
|
let dev = &cmd.device().raw;
|
||||||
|
|
||||||
let regions = self
|
// it doesn't really make sense to copy the same data into multiple mip
|
||||||
.src_region
|
// levels, considering the mip extents are different for each level.
|
||||||
.regions()
|
debug_assert_eq!(self.dst.range.mip_levels.len(), 1);
|
||||||
.iter()
|
|
||||||
.zip(self.dst_region.regions())
|
let regions = &[vk::BufferImageCopy2::default()
|
||||||
.map(|(src_region, dst_region)| {
|
.buffer_offset(self.src.row.offset)
|
||||||
vk::BufferImageCopy2::default()
|
.buffer_row_length(self.src.row.row_size)
|
||||||
.buffer_offset(src_region.offset)
|
.buffer_image_height(self.src.row.row_count)
|
||||||
.buffer_row_length(src_region.row_size)
|
.image_offset(self.dst.range.offset())
|
||||||
.buffer_image_height(src_region.row_count)
|
.image_extent(self.dst.range.extent())
|
||||||
.image_offset(dst_region.offset)
|
|
||||||
.image_extent(dst_region.extent)
|
|
||||||
.image_subresource(
|
.image_subresource(
|
||||||
vk::ImageSubresourceLayers::default()
|
vk::ImageSubresourceLayers::default()
|
||||||
.aspect_mask(dst_region.range.aspect)
|
.aspect_mask(self.dst.range.aspect)
|
||||||
.mip_level(dst_region.range.mip_level)
|
.mip_level(self.dst.range.mip_levels.start())
|
||||||
.base_array_layer(dst_region.range.array_layers.start())
|
.base_array_layer(self.dst.range.array_layers.start())
|
||||||
.layer_count(dst_region.range.array_layers.len()),
|
.layer_count(self.dst.range.array_layers.len()),
|
||||||
)
|
)];
|
||||||
})
|
|
||||||
.collect::<Box<[_]>>();
|
|
||||||
|
|
||||||
let info = vk::CopyBufferToImageInfo2::default()
|
let info = vk::CopyBufferToImageInfo2::default()
|
||||||
.src_buffer(recorder.get_buffer_handle(self.src.id()))
|
.src_buffer(recorder.get_buffer_handle(self.src.id()))
|
||||||
.dst_image(recorder.get_image_handle(self.dst.id()))
|
.dst_image(recorder.get_image_handle(self.dst.id()))
|
||||||
.dst_image_layout(recorder.get_image_layout(self.dst.id()))
|
.dst_image_layout(recorder.get_image_layout(self.dst.id()))
|
||||||
.regions(®ions);
|
.regions(regions);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.cmd_copy_buffer_to_image2(cmd.raw(), &info);
|
dev.cmd_copy_buffer_to_image2(cmd.raw(), &info);
|
||||||
|
|
@ -184,6 +119,150 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Command for Copy<BufferRowSlices, TextureRegions> {
|
||||||
|
fn side_effects(&self, map: SideEffectMap) {
|
||||||
|
self.side_effects_inner(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, recorder: &mut CommandRecorder) {
|
||||||
|
let cmd = recorder.cmd_buffer();
|
||||||
|
let dev = &cmd.device().raw;
|
||||||
|
|
||||||
|
let regions = &self
|
||||||
|
.src
|
||||||
|
.rows
|
||||||
|
.iter()
|
||||||
|
.zip(self.dst.ranges.iter())
|
||||||
|
.map(|(src_row, dst_range)| {
|
||||||
|
vk::BufferImageCopy2::default()
|
||||||
|
.buffer_offset(src_row.offset)
|
||||||
|
.buffer_row_length(src_row.row_size)
|
||||||
|
.buffer_image_height(src_row.row_count)
|
||||||
|
.image_offset(dst_range.offset())
|
||||||
|
.image_extent(dst_range.extent())
|
||||||
|
.image_subresource(
|
||||||
|
vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(dst_range.aspect)
|
||||||
|
.mip_level(dst_range.mip_levels.start())
|
||||||
|
.base_array_layer(dst_range.array_layers.start())
|
||||||
|
.layer_count(dst_range.array_layers.len()),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let info = vk::CopyBufferToImageInfo2::default()
|
||||||
|
.src_buffer(recorder.get_buffer_handle(self.src.id()))
|
||||||
|
.dst_image(recorder.get_image_handle(self.dst.id()))
|
||||||
|
.dst_image_layout(recorder.get_image_layout(self.dst.id()))
|
||||||
|
.regions(regions);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
dev.cmd_copy_buffer_to_image2(cmd.raw(), &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Command for Copy<TextureRegion, BufferRowSlice> {
|
||||||
|
fn side_effects(&self, map: SideEffectMap) {
|
||||||
|
self.side_effects_inner(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, recorder: &mut CommandRecorder) {
|
||||||
|
let cmd = recorder.cmd_buffer();
|
||||||
|
let dev = &cmd.device().raw;
|
||||||
|
|
||||||
|
let regions = &[vk::BufferImageCopy2::default()
|
||||||
|
.buffer_offset(self.dst.row.offset)
|
||||||
|
.buffer_row_length(self.dst.row.row_size)
|
||||||
|
.buffer_image_height(self.dst.row.row_count)
|
||||||
|
.image_offset(self.src.range.offset())
|
||||||
|
.image_extent(self.src.range.extent())
|
||||||
|
.image_subresource(
|
||||||
|
vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(self.src.range.aspect)
|
||||||
|
.mip_level(self.src.range.mip_levels.start())
|
||||||
|
.base_array_layer(self.src.range.array_layers.start())
|
||||||
|
.layer_count(self.src.range.array_layers.len()),
|
||||||
|
)];
|
||||||
|
|
||||||
|
let info = vk::CopyImageToBufferInfo2::default()
|
||||||
|
.dst_buffer(recorder.get_buffer_handle(self.dst.id()))
|
||||||
|
.src_image(recorder.get_image_handle(self.src.id()))
|
||||||
|
.src_image_layout(recorder.get_image_layout(self.src.id()))
|
||||||
|
.regions(regions);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
dev.cmd_copy_image_to_buffer2(cmd.raw(), &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Command for Copy<TextureRegion, TextureRegion> {
|
||||||
|
fn side_effects(&self, map: SideEffectMap) {
|
||||||
|
self.side_effects_inner(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, recorder: &mut CommandRecorder) {
|
||||||
|
let cmd = recorder.cmd_buffer();
|
||||||
|
let dev = &cmd.device().raw;
|
||||||
|
|
||||||
|
let regions = &[vk::ImageCopy2::default()
|
||||||
|
.extent(self.src.range.extent())
|
||||||
|
.dst_offset(self.dst.range.offset())
|
||||||
|
.src_offset(self.src.range.offset())
|
||||||
|
.dst_subresource(
|
||||||
|
vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(self.dst.range.aspect)
|
||||||
|
.mip_level(self.dst.range.mip_levels.start())
|
||||||
|
.base_array_layer(self.dst.range.array_layers.start())
|
||||||
|
.layer_count(self.dst.range.array_layers.len()),
|
||||||
|
)
|
||||||
|
.src_subresource(
|
||||||
|
vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(self.src.range.aspect)
|
||||||
|
.mip_level(self.src.range.mip_levels.start())
|
||||||
|
.base_array_layer(self.src.range.array_layers.start())
|
||||||
|
.layer_count(self.src.range.array_layers.len()),
|
||||||
|
)];
|
||||||
|
|
||||||
|
let info = vk::CopyImageInfo2::default()
|
||||||
|
.dst_image(recorder.get_image_handle(self.dst.id()))
|
||||||
|
.dst_image_layout(recorder.get_image_layout(self.dst.id()))
|
||||||
|
.src_image(recorder.get_image_handle(self.src.id()))
|
||||||
|
.src_image_layout(recorder.get_image_layout(self.src.id()))
|
||||||
|
.regions(regions);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
dev.cmd_copy_image2(cmd.raw(), &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Command for Copy<BufferSlice, BufferSlice> {
|
||||||
|
fn side_effects(&self, map: SideEffectMap) {
|
||||||
|
self.side_effects_inner(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply(self, recorder: &mut CommandRecorder) {
|
||||||
|
let cmd = recorder.cmd_buffer();
|
||||||
|
let dev = &cmd.device().raw;
|
||||||
|
|
||||||
|
debug_assert_eq!(self.src.range.size, self.dst.range.size);
|
||||||
|
|
||||||
|
let regions = &[vk::BufferCopy2::default()
|
||||||
|
.dst_offset(self.dst.range.offset)
|
||||||
|
.src_offset(self.src.range.offset)
|
||||||
|
.size(self.src.range.size)];
|
||||||
|
|
||||||
|
let info = vk::CopyBufferInfo2::default()
|
||||||
|
.dst_buffer(recorder.get_buffer_handle(self.dst.id()))
|
||||||
|
.src_buffer(recorder.get_buffer_handle(self.src.id()))
|
||||||
|
.regions(regions);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
dev.cmd_copy_buffer2(cmd.raw(), &info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ClearTexture {
|
pub struct ClearTexture {
|
||||||
pub dst: Write<TextureRegion>,
|
pub dst: Write<TextureRegion>,
|
||||||
pub clear_value: [f32; 4],
|
pub clear_value: [f32; 4],
|
||||||
|
|
|
||||||
|
|
@ -44,24 +44,6 @@ impl<'r> GraphBuilder<'r> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_persistent_buffer(
|
|
||||||
&self,
|
|
||||||
_size: u64,
|
|
||||||
_usage: vk::BufferUsageFlags,
|
|
||||||
_location: gpu_allocator::MemoryLocation,
|
|
||||||
) -> Buffer<'r> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_transient_buffer(
|
|
||||||
&self,
|
|
||||||
_size: u64,
|
|
||||||
_usage: vk::BufferUsageFlags,
|
|
||||||
_location: gpu_allocator::MemoryLocation,
|
|
||||||
) -> Buffer<'r> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_buffer(
|
fn make_buffer(
|
||||||
&self,
|
&self,
|
||||||
_size: u64,
|
_size: u64,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
mem::{ManuallyDrop, MaybeUninit, size_of},
|
mem::{MaybeUninit, size_of},
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -12,9 +12,7 @@ use crate::{
|
||||||
images::ImageDesc,
|
images::ImageDesc,
|
||||||
render_graph::{
|
render_graph::{
|
||||||
commands::{Command, InsideRenderPass, OutsideRenderPass},
|
commands::{Command, InsideRenderPass, OutsideRenderPass},
|
||||||
resources::{
|
resources::{ResourceAccess, ResourceId, ResourceRange, TextureRegion},
|
||||||
ResourceId, Subresource, SubresourceScope, SubresourceScopeInner, TextureRegion,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -52,27 +50,18 @@ struct CommandMeta {
|
||||||
|
|
||||||
enum VecOrSingle<T> {
|
enum VecOrSingle<T> {
|
||||||
Vec(Vec<T>),
|
Vec(Vec<T>),
|
||||||
Single(ManuallyDrop<T>),
|
Single(T),
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<T> for VecOrSingle<T> {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self::Single(ManuallyDrop::new(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> From<Vec<T>> for VecOrSingle<T> {
|
|
||||||
fn from(vec: Vec<T>) -> Self {
|
|
||||||
Self::Vec(vec)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> VecOrSingle<T> {
|
impl<T> VecOrSingle<T> {
|
||||||
fn push(&mut self, value: T) {
|
fn push(&mut self, value: T)
|
||||||
|
where
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
match self {
|
match self {
|
||||||
VecOrSingle::Vec(vec) => vec.push(value),
|
VecOrSingle::Vec(vec) => vec.push(value),
|
||||||
VecOrSingle::Single(existing) => {
|
VecOrSingle::Single(existing) => {
|
||||||
let existing = unsafe { ManuallyDrop::take(existing) };
|
let existing = std::mem::take(existing);
|
||||||
*self = VecOrSingle::Vec(vec![existing, value]);
|
*self = VecOrSingle::Vec(vec![existing, value]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,27 +69,27 @@ impl<T> VecOrSingle<T> {
|
||||||
fn iter(&self) -> core::slice::Iter<'_, T> {
|
fn iter(&self) -> core::slice::Iter<'_, T> {
|
||||||
match self {
|
match self {
|
||||||
VecOrSingle::Vec(items) => items.as_slice().iter(),
|
VecOrSingle::Vec(items) => items.as_slice().iter(),
|
||||||
VecOrSingle::Single(item) => core::slice::from_ref::<T>(item).iter(),
|
VecOrSingle::Single(item) => core::slice::from_ref(item).iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct SideEffects {
|
struct SideEffects {
|
||||||
map: BTreeMap<(ResourceId, u32), VecOrSingle<SubresourceScope>>,
|
map: BTreeMap<(ResourceId, u32), VecOrSingle<ResourceAccess>>,
|
||||||
resources: BTreeSet<ResourceId>,
|
resources: BTreeSet<ResourceId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SideEffectMap<'a>(&'a mut SideEffects, u32);
|
pub struct SideEffectMap<'a>(&'a mut SideEffects, u32);
|
||||||
|
|
||||||
impl<'a> SideEffectMap<'a> {
|
impl<'a> SideEffectMap<'a> {
|
||||||
pub fn insert(&mut self, id: ResourceId, scope: SubresourceScope) {
|
pub fn insert(&mut self, id: ResourceId, access: ResourceAccess) {
|
||||||
self.0.resources.insert(id);
|
self.0.resources.insert(id);
|
||||||
self.0
|
self.0
|
||||||
.map
|
.map
|
||||||
.entry((id, self.1))
|
.entry((id, self.1))
|
||||||
.and_modify(|entry| entry.push(scope))
|
.and_modify(|entry| entry.push(access))
|
||||||
.or_insert_with(|| scope.into());
|
.or_insert_with(|| VecOrSingle::Single(access));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reborrow(&mut self) -> SideEffectMap<'_> {
|
pub fn reborrow(&mut self) -> SideEffectMap<'_> {
|
||||||
|
|
@ -143,30 +132,18 @@ impl<'a> SideEffectMap2<'a> {
|
||||||
}
|
}
|
||||||
pub fn insert_range<T>(&mut self, id: ResourceId, range: T)
|
pub fn insert_range<T>(&mut self, id: ResourceId, range: T)
|
||||||
where
|
where
|
||||||
T: Into<Subresource>,
|
(T, vk::ImageLayout): Into<ResourceRange>,
|
||||||
{
|
{
|
||||||
self.inner.resources.insert(id);
|
self.inner.resources.insert(id);
|
||||||
|
|
||||||
let subresource: Subresource = range.into();
|
SideEffectMap(self.inner, self.command_index).insert(
|
||||||
let scope = match subresource {
|
id,
|
||||||
Subresource::Buffer(buffer) => SubresourceScope {
|
ResourceAccess {
|
||||||
|
range: (range, self.required_layout.unwrap_or_default()).into(),
|
||||||
|
stages: self.stage_flags,
|
||||||
access: self.access_flags,
|
access: self.access_flags,
|
||||||
stage: self.stage_flags,
|
|
||||||
subresource: SubresourceScopeInner::Buffer {
|
|
||||||
subresource: buffer,
|
|
||||||
},
|
},
|
||||||
},
|
);
|
||||||
Subresource::Texture(texture) => SubresourceScope {
|
|
||||||
access: self.access_flags,
|
|
||||||
stage: self.stage_flags,
|
|
||||||
subresource: SubresourceScopeInner::Texture {
|
|
||||||
subresource: texture,
|
|
||||||
layout: self.required_layout.unwrap_or_default(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
SideEffectMap(self.inner, self.command_index).insert(id, scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -281,12 +258,12 @@ impl<'cmd> CommandList<'cmd> {
|
||||||
struct Barrier {
|
struct Barrier {
|
||||||
resource_id: ResourceId,
|
resource_id: ResourceId,
|
||||||
command_index: u32,
|
command_index: u32,
|
||||||
from: SubresourceScope,
|
from: ResourceAccess,
|
||||||
to: usize,
|
to: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
// map to keep track of the current state of each subresource
|
// map to keep track of the current state of each subresource
|
||||||
let mut subresource_state: BTreeMap<ResourceId, Vec<(SubresourceScope, SubresourceState)>> =
|
let mut subresource_state: BTreeMap<ResourceId, Vec<(ResourceAccess, SubresourceState)>> =
|
||||||
Default::default();
|
Default::default();
|
||||||
|
|
||||||
let mut barriers = Vec::new();
|
let mut barriers = Vec::new();
|
||||||
|
|
@ -316,7 +293,7 @@ impl<'cmd> CommandList<'cmd> {
|
||||||
let mut folded = false;
|
let mut folded = false;
|
||||||
let len = entry.len();
|
let len = entry.len();
|
||||||
for (_i, (sub, _state)) in &mut entry.iter_mut().enumerate().rev() {
|
for (_i, (sub, _state)) in &mut entry.iter_mut().enumerate().rev() {
|
||||||
if !folded && sub.try_merge(&access) {
|
if !folded && sub.try_fold(&access) {
|
||||||
access = *sub;
|
access = *sub;
|
||||||
folded = true;
|
folded = true;
|
||||||
} else if sub.conflicts(&access) {
|
} else if sub.conflicts(&access) {
|
||||||
|
|
|
||||||
|
|
@ -9,174 +9,9 @@ pub trait Resource: Sized {
|
||||||
fn side_effect(&self, map: SideEffectMap2);
|
fn side_effect(&self, map: SideEffectMap2);
|
||||||
}
|
}
|
||||||
|
|
||||||
mod sealed {
|
|
||||||
pub trait Texture {
|
|
||||||
fn format(&self) -> vk::Format {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub trait Buffer {
|
|
||||||
fn size(&self) -> u64 {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum Subresource {
|
|
||||||
Buffer(BufferRange),
|
|
||||||
Texture(TextureRange),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct SubresourceScope {
|
|
||||||
pub access: vk::AccessFlags2,
|
|
||||||
pub stage: vk::PipelineStageFlags2,
|
|
||||||
pub subresource: SubresourceScopeInner,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub enum SubresourceScopeInner {
|
|
||||||
Buffer {
|
|
||||||
subresource: BufferRange,
|
|
||||||
},
|
|
||||||
Texture {
|
|
||||||
subresource: TextureRange,
|
|
||||||
layout: vk::ImageLayout,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SubresourceScope {
|
|
||||||
pub fn try_merge(&mut self, other: &Self) -> bool {
|
|
||||||
// cannot merge a read and a write.
|
|
||||||
if access_flag_is_read(self.access) != access_flag_is_read(other.access) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
use SubresourceScopeInner::*;
|
|
||||||
match (self.subresource, other.subresource) {
|
|
||||||
(Buffer { subresource: lhs }, Buffer { subresource: rhs }) => {
|
|
||||||
if lhs.offset > rhs.offset || lhs.offset + lhs.size < rhs.offset + rhs.size {
|
|
||||||
// other is not a subresource of self, so we can't merge them.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.stage |= other.stage;
|
|
||||||
self.access |= other.access;
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
(
|
|
||||||
Texture {
|
|
||||||
subresource: lhs,
|
|
||||||
layout: lhs_layout,
|
|
||||||
},
|
|
||||||
Texture {
|
|
||||||
subresource: rhs,
|
|
||||||
layout: rhs_layout,
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
// layout transition required even on reads, so can't fold if layouts differ.
|
|
||||||
if lhs_layout != rhs_layout {
|
|
||||||
// TODO: consider if we can still merge `other` into `self`
|
|
||||||
// if they overlap, and reduce the second barrier to only a
|
|
||||||
// layout transition.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// two accesses conflict if they overlap;
|
|
||||||
// they overlap if they share mip levels or array layers with
|
|
||||||
// the same aspects.
|
|
||||||
// If one access contains the other, we can merge them (i
|
|
||||||
// think), however: if a previous access requires a less general
|
|
||||||
// barrier, then is it better to split?
|
|
||||||
|
|
||||||
let overlaps = lhs.aspect.intersects(rhs.aspect)
|
|
||||||
&& lhs.mip_levels.intersects(rhs.mip_levels)
|
|
||||||
&& lhs.array_layers.intersects(rhs.array_layers);
|
|
||||||
|
|
||||||
// non-overlapping sub-resources shouldn't be merged.
|
|
||||||
if !overlaps {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let lhs_contains_rhs = lhs.aspect.contains(rhs.aspect)
|
|
||||||
&& lhs.mip_levels.contains(rhs.mip_levels)
|
|
||||||
&& lhs.array_layers.contains(rhs.array_layers);
|
|
||||||
|
|
||||||
// other is not a subresource of self, so we can't merge them.
|
|
||||||
if !lhs_contains_rhs {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.stage |= other.stage;
|
|
||||||
self.access |= other.access;
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
// different resource types can't merge
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn conflicts(&self, other: &Self) -> bool {
|
|
||||||
use SubresourceScopeInner::*;
|
|
||||||
match (self.subresource, other.subresource) {
|
|
||||||
(Buffer { subresource: lhs }, Buffer { subresource: rhs }) => {
|
|
||||||
// two reads don't conflict
|
|
||||||
if access_flag_is_read(self.access) && access_flag_is_read(other.access) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if they overlap, they conflict
|
|
||||||
!(lhs.offset > rhs.offset + rhs.size || rhs.offset > lhs.offset + lhs.size)
|
|
||||||
}
|
|
||||||
(
|
|
||||||
Texture {
|
|
||||||
subresource: lhs,
|
|
||||||
layout: lhs_layout,
|
|
||||||
},
|
|
||||||
Texture {
|
|
||||||
subresource: rhs,
|
|
||||||
layout: rhs_layout,
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
// image subresource ranges overlap if they share mip levels and
|
|
||||||
// array layers with the same aspects.
|
|
||||||
let overlaps = lhs.aspect.intersects(rhs.aspect)
|
|
||||||
&& lhs.mip_levels.intersects(rhs.mip_levels)
|
|
||||||
&& lhs.array_layers.intersects(rhs.array_layers);
|
|
||||||
|
|
||||||
if !overlaps {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if they require different layouts, they conflict even on
|
|
||||||
// reads, since a layout transition is required.
|
|
||||||
if lhs_layout != rhs_layout {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally, two reads don't conflict
|
|
||||||
access_flag_is_read(self.access) && access_flag_is_read(other.access)
|
|
||||||
}
|
|
||||||
|
|
||||||
// different resource types can't conflict
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod impls {
|
mod impls {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
impl sealed::Texture for Texture {}
|
|
||||||
impl sealed::Texture for TextureRegion {}
|
|
||||||
impl sealed::Texture for TextureView {}
|
|
||||||
|
|
||||||
impl sealed::Buffer for Buffer {}
|
|
||||||
impl sealed::Buffer for BufferSlice {}
|
|
||||||
|
|
||||||
impl Resource for Buffer {
|
impl Resource for Buffer {
|
||||||
fn id(&self) -> ResourceId {
|
fn id(&self) -> ResourceId {
|
||||||
self.0
|
self.0
|
||||||
|
|
@ -267,7 +102,7 @@ mod impls {
|
||||||
|
|
||||||
fn side_effect(&self, mut map: SideEffectMap2) {
|
fn side_effect(&self, mut map: SideEffectMap2) {
|
||||||
for range in &self.ranges {
|
for range in &self.ranges {
|
||||||
map.insert_range(self.id(), range.0);
|
map.insert_range(self.id(), *range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -314,6 +149,150 @@ mod impls {
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct ResourceId(pub u64);
|
pub struct ResourceId(pub u64);
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub struct ResourceAccess {
|
||||||
|
pub range: ResourceRange,
|
||||||
|
pub access: vk::AccessFlags2,
|
||||||
|
pub stages: vk::PipelineStageFlags2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ResourceAccess {
|
||||||
|
/// Attempts to fold another ResourceAccess into this one. Returns true if
|
||||||
|
/// successful, false if they are incompatible.
|
||||||
|
pub fn try_fold(&mut self, other: &Self) -> bool {
|
||||||
|
// if `other` has access flags that aren't in `self`, we can't fold
|
||||||
|
// them.
|
||||||
|
if !self.access.contains(other.access) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match (&mut self.range, &other.range) {
|
||||||
|
(
|
||||||
|
ResourceRange::Buffer { offset, size },
|
||||||
|
ResourceRange::Buffer {
|
||||||
|
offset: offset_b,
|
||||||
|
size: size_b,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
// only fold if other lies within self
|
||||||
|
if *offset > *offset_b || *offset + *size < *offset_b + *size_b {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge stages: we need the barrier to scope all stages that
|
||||||
|
// touch the resource.
|
||||||
|
self.stages |= other.stages;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
(
|
||||||
|
ResourceRange::Texture {
|
||||||
|
aspect,
|
||||||
|
mip_level,
|
||||||
|
array_layers,
|
||||||
|
layout,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
ResourceRange::Texture {
|
||||||
|
aspect: aspect_b,
|
||||||
|
mip_level: mip_level_b,
|
||||||
|
array_layers: array_layers_b,
|
||||||
|
layout: layout_b,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
// two accesses conflict if they overlap;
|
||||||
|
// they overlap if they share mip levels or array layers with
|
||||||
|
// the same aspects.
|
||||||
|
// If one access contains the other, we can merge them (i
|
||||||
|
// think), however: if a previous access requires a less general
|
||||||
|
// barrier, then is it better to split?
|
||||||
|
if !aspect.contains(*aspect_b)
|
||||||
|
|| layout != layout_b
|
||||||
|
|| !mip_level.intersects(mip_level_b)
|
||||||
|
|| !array_layers.intersects(array_layers_b)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*aspect = *aspect | *aspect_b;
|
||||||
|
*mip_level = mip_level.union(mip_level_b);
|
||||||
|
*array_layers = array_layers.union(array_layers_b);
|
||||||
|
// let lower_left = Offset::from(*origin).min(Offset::from(*origin_b));
|
||||||
|
// let upper_right = (Offset::from(*origin) + Extent::from(*extent).as_offset())
|
||||||
|
// .max(Offset::from(*origin_b) + Extent::from(*extent_b).as_offset());
|
||||||
|
// *origin = lower_left.into();
|
||||||
|
// *extent = Extent::from_offset(upper_right - lower_left).into();
|
||||||
|
|
||||||
|
// merge stages: we need the barrier to scope all stages that
|
||||||
|
// touch the resource.
|
||||||
|
self.stages |= other.stages;
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
// different resource types can't fold
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn conflicts(&self, other: &Self) -> bool {
|
||||||
|
match (&self.range, &other.range) {
|
||||||
|
(ResourceRange::Buffer { .. }, ResourceRange::Texture { .. }) => false,
|
||||||
|
(ResourceRange::Texture { .. }, ResourceRange::Buffer { .. }) => false,
|
||||||
|
(
|
||||||
|
ResourceRange::Buffer { offset, size },
|
||||||
|
ResourceRange::Buffer {
|
||||||
|
offset: offset_b,
|
||||||
|
size: size_b,
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
// two reads don't conflict
|
||||||
|
// TODO: two writes may conflict if the user cares about the order of writes.
|
||||||
|
if access_flag_is_read(self.access) == access_flag_is_read(other.access) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// must be a read/write conflict, check if sub-resources intersect
|
||||||
|
!(*offset > *offset_b + *size_b || *offset_b > *offset + *size)
|
||||||
|
}
|
||||||
|
(
|
||||||
|
ResourceRange::Texture {
|
||||||
|
aspect,
|
||||||
|
mip_level,
|
||||||
|
array_layers,
|
||||||
|
layout,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
ResourceRange::Texture {
|
||||||
|
aspect: aspect_b,
|
||||||
|
mip_level: mip_level_b,
|
||||||
|
array_layers: array_layers_b,
|
||||||
|
layout: layout_b,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => {
|
||||||
|
// check if sub-resources intersect
|
||||||
|
let overlaps = aspect.intersects(*aspect_b)
|
||||||
|
&& (mip_level.intersects(mip_level_b)
|
||||||
|
|| array_layers.intersects(array_layers_b));
|
||||||
|
|
||||||
|
// non-overlapping sub-resources never conflict
|
||||||
|
if !overlaps {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// layout transition required even on reads
|
||||||
|
if layout != layout_b {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// two reads don't conflict
|
||||||
|
access_flag_is_read(self.access) != access_flag_is_read(other.access)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum ResourceRange {
|
pub enum ResourceRange {
|
||||||
Buffer {
|
Buffer {
|
||||||
|
|
@ -324,6 +303,8 @@ pub enum ResourceRange {
|
||||||
aspect: vk::ImageAspectFlags,
|
aspect: vk::ImageAspectFlags,
|
||||||
mip_level: MipRange,
|
mip_level: MipRange,
|
||||||
array_layers: MipRange,
|
array_layers: MipRange,
|
||||||
|
origin: (i32, i32, i32),
|
||||||
|
extent: (u32, u32, u32),
|
||||||
layout: vk::ImageLayout,
|
layout: vk::ImageLayout,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -360,70 +341,31 @@ pub struct BufferRows {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
#[repr(C)]
|
|
||||||
pub struct TextureRange {
|
pub struct TextureRange {
|
||||||
pub aspect: vk::ImageAspectFlags,
|
pub aspect: vk::ImageAspectFlags,
|
||||||
pub mip_levels: MipRange,
|
pub mip_levels: MipRange,
|
||||||
pub array_layers: MipRange,
|
pub array_layers: MipRange,
|
||||||
|
pub origin: (i32, i32, i32),
|
||||||
|
pub extent: (u32, u32, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone, Copy)]
|
impl TextureRange {
|
||||||
#[repr(C)]
|
pub fn offset(&self) -> vk::Offset3D {
|
||||||
pub struct TextureLayers {
|
vk::Offset3D {
|
||||||
pub aspect: vk::ImageAspectFlags,
|
x: self.origin.0,
|
||||||
pub mip_level: u32,
|
y: self.origin.1,
|
||||||
pub array_layers: MipRange,
|
z: self.origin.2,
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TextureLayers> for vk::ImageSubresourceLayers {
|
|
||||||
fn from(value: TextureLayers) -> Self {
|
|
||||||
vk::ImageSubresourceLayers {
|
|
||||||
aspect_mask: value.aspect,
|
|
||||||
mip_level: value.mip_level,
|
|
||||||
base_array_layer: value.array_layers.start,
|
|
||||||
layer_count: value.array_layers.end - value.array_layers.start,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
pub fn extent(&self) -> vk::Extent3D {
|
||||||
|
vk::Extent3D {
|
||||||
impl From<TextureRange> for vk::ImageSubresourceRange {
|
width: self.extent.0,
|
||||||
fn from(value: TextureRange) -> Self {
|
height: self.extent.1,
|
||||||
vk::ImageSubresourceRange {
|
depth: self.extent.2,
|
||||||
aspect_mask: value.aspect,
|
|
||||||
base_mip_level: value.mip_levels.start,
|
|
||||||
level_count: value.mip_levels.end - value.mip_levels.start,
|
|
||||||
base_array_layer: value.array_layers.start,
|
|
||||||
layer_count: value.array_layers.end - value.array_layers.start,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TextureLayers> for TextureRange {
|
|
||||||
fn from(value: TextureLayers) -> Self {
|
|
||||||
Self {
|
|
||||||
aspect: value.aspect,
|
|
||||||
mip_levels: MipRange::single(value.mip_level),
|
|
||||||
array_layers: value.array_layers,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TextureLayers> for Subresource {
|
|
||||||
fn from(value: TextureLayers) -> Self {
|
|
||||||
Subresource::Texture(TextureRange {
|
|
||||||
aspect: value.aspect,
|
|
||||||
mip_levels: MipRange::single(value.mip_level),
|
|
||||||
array_layers: value.array_layers,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<TextureRange> for Subresource {
|
|
||||||
fn from(value: TextureRange) -> Self {
|
|
||||||
Subresource::Texture(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<(BufferRange, vk::ImageLayout)> for ResourceRange {
|
impl From<(BufferRange, vk::ImageLayout)> for ResourceRange {
|
||||||
fn from((value, _): (BufferRange, vk::ImageLayout)) -> Self {
|
fn from((value, _): (BufferRange, vk::ImageLayout)) -> Self {
|
||||||
ResourceRange::Buffer {
|
ResourceRange::Buffer {
|
||||||
|
|
@ -439,6 +381,8 @@ impl From<(TextureRange, vk::ImageLayout)> for ResourceRange {
|
||||||
aspect: value.aspect,
|
aspect: value.aspect,
|
||||||
mip_level: value.mip_levels,
|
mip_level: value.mip_levels,
|
||||||
array_layers: value.array_layers,
|
array_layers: value.array_layers,
|
||||||
|
origin: value.origin,
|
||||||
|
extent: value.extent,
|
||||||
layout,
|
layout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -461,6 +405,8 @@ impl TextureRange {
|
||||||
| vk::ImageAspectFlags::STENCIL,
|
| vk::ImageAspectFlags::STENCIL,
|
||||||
mip_levels: MipRange::default(),
|
mip_levels: MipRange::default(),
|
||||||
array_layers: MipRange::default(),
|
array_layers: MipRange::default(),
|
||||||
|
origin: (0, 0, 0),
|
||||||
|
extent: (u32::MAX, u32::MAX, u32::MAX),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -502,9 +448,13 @@ pub struct BufferRowSlices {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextureRegion {
|
pub struct TextureRegion {
|
||||||
pub range: TextureLayers,
|
pub texture: Texture,
|
||||||
pub offset: vk::Offset3D,
|
pub range: TextureRange,
|
||||||
pub extent: vk::Extent3D,
|
}
|
||||||
|
|
||||||
|
pub struct TextureRegions {
|
||||||
|
pub texture: Texture,
|
||||||
|
pub ranges: Vec<TextureRange>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextureView {
|
pub struct TextureView {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue