Compare commits
3 commits
main
...
rendergrap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29dbdf9f94 | ||
|
|
d1a0fbd592 | ||
|
|
d1b5e427a7 |
|
|
@ -449,7 +449,11 @@ impl Image {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if !desc.mip_range.fits_in(self.desc.mip_levels) {
|
// update imageview desc to make sure the mip range and layer ranges don't contain `vk::REMAINING_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,
|
||||||
|
|
@ -785,10 +789,12 @@ 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 {
|
||||||
start: u32,
|
pub start: u32,
|
||||||
end: u32,
|
pub end: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MipRange {
|
impl Default for MipRange {
|
||||||
|
|
@ -801,6 +807,24 @@ 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
|
||||||
}
|
}
|
||||||
|
|
@ -813,6 +837,8 @@ 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),
|
||||||
|
|
@ -828,10 +854,19 @@ 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 intersects(&self, other: &Self) -> bool {
|
pub fn contains(&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),
|
||||||
|
|
@ -840,6 +875,59 @@ 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;
|
||||||
|
|
||||||
|
|
@ -1071,6 +1159,89 @@ 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,120 +41,142 @@ impl<T: Resource> Command for ImportResource<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub struct CopyBuffers {
|
pub trait BufferImageBufferCopyRegion {
|
||||||
// pub src: Read<BufferSlice>,
|
fn regions(&self) -> &[BufferRows];
|
||||||
// pub dst: Write<BufferSlice>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub struct CopyTextures {
|
|
||||||
// pub src: Read<TextureRegion>,
|
|
||||||
// pub dst: Write<TextureRegion>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub struct CopyBufferToTexture {
|
|
||||||
// pub src: Read<BufferSlice>,
|
|
||||||
// pub dst: Write<TextureRegion>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub struct CopyTextureToBuffer {
|
|
||||||
// pub src: Read<TextureRegion>,
|
|
||||||
// pub dst: Write<BufferSlice>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub struct Copy<T: Resource, U: Resource> {
|
|
||||||
pub src: T,
|
|
||||||
pub dst: U,
|
|
||||||
}
|
}
|
||||||
impl<T: Resource, U: Resource> Copy<T, U> {
|
impl BufferImageBufferCopyRegion for BufferRows {
|
||||||
fn side_effects_inner(&self, mut map: SideEffectMap) {
|
fn regions(&self) -> &[BufferRows] {
|
||||||
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
core::slice::from_ref(self)
|
||||||
vk::PipelineStageFlags2::TRANSFER,
|
}
|
||||||
|
}
|
||||||
|
impl<T: AsRef<[BufferRows]>> BufferImageBufferCopyRegion for T {
|
||||||
|
fn regions(&self) -> &[BufferRows] {
|
||||||
|
self.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ImageCopyRegion {
|
||||||
|
fn regions(&self) -> &[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 {
|
||||||
|
fn regions(&self) -> &[BufferRange];
|
||||||
|
}
|
||||||
|
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 src: Buffer,
|
||||||
|
pub src_region: T,
|
||||||
|
pub dst: Buffer,
|
||||||
|
pub dst_region: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyTextures<T: ImageCopyRegion> {
|
||||||
|
pub src: Texture,
|
||||||
|
pub src_region: T,
|
||||||
|
pub dst: Texture,
|
||||||
|
pub dst_region: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CopyBufferToTexture<T: BufferImageBufferCopyRegion, U: ImageCopyRegion> {
|
||||||
|
pub src: Buffer,
|
||||||
|
pub src_region: T,
|
||||||
|
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),
|
||||||
));
|
));
|
||||||
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
dst.side_effect(map.reborrow().into_side_effect_map2(
|
||||||
vk::PipelineStageFlags2::TRANSFER,
|
vk::PipelineStageFlags2::COPY,
|
||||||
vk::AccessFlags2::TRANSFER_WRITE,
|
vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
));
|
));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command for Copy<BufferRowSlice, TextureRegion> {
|
impl<T, U> Command for CopyBufferToTexture<T, U>
|
||||||
fn side_effects(&self, map: SideEffectMap) {
|
where
|
||||||
self.side_effects_inner(map)
|
T: BufferImageBufferCopyRegion,
|
||||||
|
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;
|
||||||
|
|
||||||
// it doesn't really make sense to copy the same data into multiple mip
|
let regions = self
|
||||||
// levels, considering the mip extents are different for each level.
|
.src_region
|
||||||
debug_assert_eq!(self.dst.range.mip_levels.len(), 1);
|
.regions()
|
||||||
|
|
||||||
let regions = &[vk::BufferImageCopy2::default()
|
|
||||||
.buffer_offset(self.src.row.offset)
|
|
||||||
.buffer_row_length(self.src.row.row_size)
|
|
||||||
.buffer_image_height(self.src.row.row_count)
|
|
||||||
.image_offset(self.dst.range.offset())
|
|
||||||
.image_extent(self.dst.range.extent())
|
|
||||||
.image_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()),
|
|
||||||
)];
|
|
||||||
|
|
||||||
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<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()
|
.iter()
|
||||||
.zip(self.dst.ranges.iter())
|
.zip(self.dst_region.regions())
|
||||||
.map(|(src_row, dst_range)| {
|
.map(|(src_region, dst_region)| {
|
||||||
vk::BufferImageCopy2::default()
|
vk::BufferImageCopy2::default()
|
||||||
.buffer_offset(src_row.offset)
|
.buffer_offset(src_region.offset)
|
||||||
.buffer_row_length(src_row.row_size)
|
.buffer_row_length(src_region.row_size)
|
||||||
.buffer_image_height(src_row.row_count)
|
.buffer_image_height(src_region.row_count)
|
||||||
.image_offset(dst_range.offset())
|
.image_offset(dst_region.offset)
|
||||||
.image_extent(dst_range.extent())
|
.image_extent(dst_region.extent)
|
||||||
.image_subresource(
|
.image_subresource(
|
||||||
vk::ImageSubresourceLayers::default()
|
vk::ImageSubresourceLayers::default()
|
||||||
.aspect_mask(dst_range.aspect)
|
.aspect_mask(dst_region.range.aspect)
|
||||||
.mip_level(dst_range.mip_levels.start())
|
.mip_level(dst_region.range.mip_level)
|
||||||
.base_array_layer(dst_range.array_layers.start())
|
.base_array_layer(dst_region.range.array_layers.start())
|
||||||
.layer_count(dst_range.array_layers.len()),
|
.layer_count(dst_region.range.array_layers.len()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.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(regions);
|
.regions(®ions);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.cmd_copy_buffer_to_image2(cmd.raw(), &info);
|
dev.cmd_copy_buffer_to_image2(cmd.raw(), &info);
|
||||||
|
|
@ -162,107 +184,6 @@ impl Command for Copy<BufferRowSlices, TextureRegions> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,6 +44,24 @@ 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::{MaybeUninit, size_of},
|
mem::{ManuallyDrop, MaybeUninit, size_of},
|
||||||
ptr::NonNull,
|
ptr::NonNull,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -12,7 +12,9 @@ use crate::{
|
||||||
images::ImageDesc,
|
images::ImageDesc,
|
||||||
render_graph::{
|
render_graph::{
|
||||||
commands::{Command, InsideRenderPass, OutsideRenderPass},
|
commands::{Command, InsideRenderPass, OutsideRenderPass},
|
||||||
resources::{ResourceAccess, ResourceId, ResourceRange, TextureRegion},
|
resources::{
|
||||||
|
ResourceId, Subresource, SubresourceScope, SubresourceScopeInner, TextureRegion,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -50,18 +52,27 @@ struct CommandMeta {
|
||||||
|
|
||||||
enum VecOrSingle<T> {
|
enum VecOrSingle<T> {
|
||||||
Vec(Vec<T>),
|
Vec(Vec<T>),
|
||||||
Single(T),
|
Single(ManuallyDrop<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 = std::mem::take(existing);
|
let existing = unsafe { ManuallyDrop::take(existing) };
|
||||||
*self = VecOrSingle::Vec(vec![existing, value]);
|
*self = VecOrSingle::Vec(vec![existing, value]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -69,27 +80,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(item).iter(),
|
VecOrSingle::Single(item) => core::slice::from_ref::<T>(item).iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct SideEffects {
|
struct SideEffects {
|
||||||
map: BTreeMap<(ResourceId, u32), VecOrSingle<ResourceAccess>>,
|
map: BTreeMap<(ResourceId, u32), VecOrSingle<SubresourceScope>>,
|
||||||
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, access: ResourceAccess) {
|
pub fn insert(&mut self, id: ResourceId, scope: SubresourceScope) {
|
||||||
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(access))
|
.and_modify(|entry| entry.push(scope))
|
||||||
.or_insert_with(|| VecOrSingle::Single(access));
|
.or_insert_with(|| scope.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reborrow(&mut self) -> SideEffectMap<'_> {
|
pub fn reborrow(&mut self) -> SideEffectMap<'_> {
|
||||||
|
|
@ -132,18 +143,30 @@ 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, vk::ImageLayout): Into<ResourceRange>,
|
T: Into<Subresource>,
|
||||||
{
|
{
|
||||||
self.inner.resources.insert(id);
|
self.inner.resources.insert(id);
|
||||||
|
|
||||||
SideEffectMap(self.inner, self.command_index).insert(
|
let subresource: Subresource = range.into();
|
||||||
id,
|
let scope = match subresource {
|
||||||
ResourceAccess {
|
Subresource::Buffer(buffer) => SubresourceScope {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -258,12 +281,12 @@ impl<'cmd> CommandList<'cmd> {
|
||||||
struct Barrier {
|
struct Barrier {
|
||||||
resource_id: ResourceId,
|
resource_id: ResourceId,
|
||||||
command_index: u32,
|
command_index: u32,
|
||||||
from: ResourceAccess,
|
from: SubresourceScope,
|
||||||
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<(ResourceAccess, SubresourceState)>> =
|
let mut subresource_state: BTreeMap<ResourceId, Vec<(SubresourceScope, SubresourceState)>> =
|
||||||
Default::default();
|
Default::default();
|
||||||
|
|
||||||
let mut barriers = Vec::new();
|
let mut barriers = Vec::new();
|
||||||
|
|
@ -293,7 +316,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_fold(&access) {
|
if !folded && sub.try_merge(&access) {
|
||||||
access = *sub;
|
access = *sub;
|
||||||
folded = true;
|
folded = true;
|
||||||
} else if sub.conflicts(&access) {
|
} else if sub.conflicts(&access) {
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,174 @@ 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
|
||||||
|
|
@ -102,7 +267,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);
|
map.insert_range(self.id(), range.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -149,150 +314,6 @@ 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 {
|
||||||
|
|
@ -303,8 +324,6 @@ 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,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -341,31 +360,70 @@ 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),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextureRange {
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub fn offset(&self) -> vk::Offset3D {
|
#[repr(C)]
|
||||||
vk::Offset3D {
|
pub struct TextureLayers {
|
||||||
x: self.origin.0,
|
pub aspect: vk::ImageAspectFlags,
|
||||||
y: self.origin.1,
|
pub mip_level: u32,
|
||||||
z: self.origin.2,
|
pub array_layers: MipRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
|
||||||
width: self.extent.0,
|
impl From<TextureRange> for vk::ImageSubresourceRange {
|
||||||
height: self.extent.1,
|
fn from(value: TextureRange) -> Self {
|
||||||
depth: self.extent.2,
|
vk::ImageSubresourceRange {
|
||||||
|
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 {
|
||||||
|
|
@ -381,8 +439,6 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -405,8 +461,6 @@ 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),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -448,13 +502,9 @@ pub struct BufferRowSlices {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextureRegion {
|
pub struct TextureRegion {
|
||||||
pub texture: Texture,
|
pub range: TextureLayers,
|
||||||
pub range: TextureRange,
|
pub offset: vk::Offset3D,
|
||||||
}
|
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