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`.
|
||||
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) {
|
||||
if !desc.mip_range.fits_in(self.desc.mip_levels) {
|
||||
tracing::error!(
|
||||
"image view mip range {:?} exceeds image mip levels {}",
|
||||
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)]
|
||||
#[repr(C)]
|
||||
pub struct MipRange {
|
||||
pub start: u32,
|
||||
pub end: u32,
|
||||
start: u32,
|
||||
end: u32,
|
||||
}
|
||||
|
||||
impl Default for MipRange {
|
||||
|
|
@ -807,24 +801,6 @@ impl Default for 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 {
|
||||
self.end - self.start
|
||||
}
|
||||
|
|
@ -837,8 +813,6 @@ impl MipRange {
|
|||
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 {
|
||||
Self {
|
||||
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)
|
||||
}
|
||||
|
||||
pub fn contains(&self, other: Self) -> bool {
|
||||
self.start <= other.start && self.end >= other.end
|
||||
}
|
||||
|
||||
pub fn intersects(&self, other: Self) -> bool {
|
||||
pub fn intersects(&self, other: &Self) -> bool {
|
||||
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 {
|
||||
Self {
|
||||
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 {
|
||||
type Item = u32;
|
||||
|
||||
|
|
@ -1159,89 +1071,6 @@ pub enum FormatClass {
|
|||
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 {
|
||||
fn from(format: vk::Format) -> Self {
|
||||
use vk::Format as F;
|
||||
|
|
|
|||
|
|
@ -41,142 +41,77 @@ impl<T: Resource> Command for ImportResource<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub trait BufferImageBufferCopyRegion {
|
||||
fn regions(&self) -> &[BufferRows];
|
||||
}
|
||||
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 struct CopyBuffers {
|
||||
// pub src: Read<BufferSlice>,
|
||||
// pub dst: Write<BufferSlice>,
|
||||
// }
|
||||
|
||||
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 struct CopyTextures {
|
||||
// pub src: Read<TextureRegion>,
|
||||
// pub dst: Write<TextureRegion>,
|
||||
// }
|
||||
|
||||
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 CopyBufferToTexture {
|
||||
// pub src: Read<BufferSlice>,
|
||||
// pub dst: Write<TextureRegion>,
|
||||
// }
|
||||
|
||||
pub struct CopyBuffers<T: BufferCopyRegion> {
|
||||
pub src: Buffer,
|
||||
pub src_region: T,
|
||||
pub dst: Buffer,
|
||||
pub dst_region: T,
|
||||
}
|
||||
// pub struct CopyTextureToBuffer {
|
||||
// pub src: Read<TextureRegion>,
|
||||
// pub dst: Write<BufferSlice>,
|
||||
// }
|
||||
|
||||
pub struct CopyTextures<T: ImageCopyRegion> {
|
||||
pub src: Texture,
|
||||
pub src_region: T,
|
||||
pub dst: Texture,
|
||||
pub dst_region: T,
|
||||
pub struct Copy<T: Resource, U: Resource> {
|
||||
pub src: T,
|
||||
pub dst: U,
|
||||
}
|
||||
|
||||
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,
|
||||
impl<T: Resource, U: Resource> Copy<T, U> {
|
||||
fn side_effects_inner(&self, mut map: SideEffectMap) {
|
||||
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_READ,
|
||||
Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
||||
));
|
||||
dst.side_effect(map.reborrow().into_side_effect_map2(
|
||||
vk::PipelineStageFlags2::COPY,
|
||||
self.src.side_effect(map.reborrow().into_side_effect_map2(
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||
));
|
||||
}
|
||||
|
||||
impl<T, U> Command for CopyBufferToTexture<T, U>
|
||||
where
|
||||
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);
|
||||
}
|
||||
|
||||
impl Command for Copy<BufferRowSlice, 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 = self
|
||||
.src_region
|
||||
.regions()
|
||||
.iter()
|
||||
.zip(self.dst_region.regions())
|
||||
.map(|(src_region, dst_region)| {
|
||||
vk::BufferImageCopy2::default()
|
||||
.buffer_offset(src_region.offset)
|
||||
.buffer_row_length(src_region.row_size)
|
||||
.buffer_image_height(src_region.row_count)
|
||||
.image_offset(dst_region.offset)
|
||||
.image_extent(dst_region.extent)
|
||||
// it doesn't really make sense to copy the same data into multiple mip
|
||||
// levels, considering the mip extents are different for each level.
|
||||
debug_assert_eq!(self.dst.range.mip_levels.len(), 1);
|
||||
|
||||
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(dst_region.range.aspect)
|
||||
.mip_level(dst_region.range.mip_level)
|
||||
.base_array_layer(dst_region.range.array_layers.start())
|
||||
.layer_count(dst_region.range.array_layers.len()),
|
||||
)
|
||||
})
|
||||
.collect::<Box<[_]>>();
|
||||
.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(®ions);
|
||||
.regions(regions);
|
||||
|
||||
unsafe {
|
||||
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 dst: Write<TextureRegion>,
|
||||
pub clear_value: [f32; 4],
|
||||
|
|
|
|||
|
|
@ -44,24 +44,6 @@ impl<'r> GraphBuilder<'r> {
|
|||
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(
|
||||
&self,
|
||||
_size: u64,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
marker::PhantomData,
|
||||
mem::{ManuallyDrop, MaybeUninit, size_of},
|
||||
mem::{MaybeUninit, size_of},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
|
|
@ -12,9 +12,7 @@ use crate::{
|
|||
images::ImageDesc,
|
||||
render_graph::{
|
||||
commands::{Command, InsideRenderPass, OutsideRenderPass},
|
||||
resources::{
|
||||
ResourceId, Subresource, SubresourceScope, SubresourceScopeInner, TextureRegion,
|
||||
},
|
||||
resources::{ResourceAccess, ResourceId, ResourceRange, TextureRegion},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -52,27 +50,18 @@ struct CommandMeta {
|
|||
|
||||
enum VecOrSingle<T> {
|
||||
Vec(Vec<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)
|
||||
}
|
||||
Single(T),
|
||||
}
|
||||
|
||||
impl<T> VecOrSingle<T> {
|
||||
fn push(&mut self, value: T) {
|
||||
fn push(&mut self, value: T)
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
match self {
|
||||
VecOrSingle::Vec(vec) => vec.push(value),
|
||||
VecOrSingle::Single(existing) => {
|
||||
let existing = unsafe { ManuallyDrop::take(existing) };
|
||||
let existing = std::mem::take(existing);
|
||||
*self = VecOrSingle::Vec(vec![existing, value]);
|
||||
}
|
||||
}
|
||||
|
|
@ -80,27 +69,27 @@ impl<T> VecOrSingle<T> {
|
|||
fn iter(&self) -> core::slice::Iter<'_, T> {
|
||||
match self {
|
||||
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)]
|
||||
struct SideEffects {
|
||||
map: BTreeMap<(ResourceId, u32), VecOrSingle<SubresourceScope>>,
|
||||
map: BTreeMap<(ResourceId, u32), VecOrSingle<ResourceAccess>>,
|
||||
resources: BTreeSet<ResourceId>,
|
||||
}
|
||||
|
||||
pub struct SideEffectMap<'a>(&'a mut SideEffects, u32);
|
||||
|
||||
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
|
||||
.map
|
||||
.entry((id, self.1))
|
||||
.and_modify(|entry| entry.push(scope))
|
||||
.or_insert_with(|| scope.into());
|
||||
.and_modify(|entry| entry.push(access))
|
||||
.or_insert_with(|| VecOrSingle::Single(access));
|
||||
}
|
||||
|
||||
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)
|
||||
where
|
||||
T: Into<Subresource>,
|
||||
(T, vk::ImageLayout): Into<ResourceRange>,
|
||||
{
|
||||
self.inner.resources.insert(id);
|
||||
|
||||
let subresource: Subresource = range.into();
|
||||
let scope = match subresource {
|
||||
Subresource::Buffer(buffer) => SubresourceScope {
|
||||
SideEffectMap(self.inner, self.command_index).insert(
|
||||
id,
|
||||
ResourceAccess {
|
||||
range: (range, self.required_layout.unwrap_or_default()).into(),
|
||||
stages: self.stage_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 {
|
||||
resource_id: ResourceId,
|
||||
command_index: u32,
|
||||
from: SubresourceScope,
|
||||
from: ResourceAccess,
|
||||
to: usize,
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
let mut barriers = Vec::new();
|
||||
|
|
@ -316,7 +293,7 @@ impl<'cmd> CommandList<'cmd> {
|
|||
let mut folded = false;
|
||||
let len = entry.len();
|
||||
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;
|
||||
folded = true;
|
||||
} else if sub.conflicts(&access) {
|
||||
|
|
|
|||
|
|
@ -9,174 +9,9 @@ pub trait Resource: Sized {
|
|||
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 {
|
||||
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 {
|
||||
fn id(&self) -> ResourceId {
|
||||
self.0
|
||||
|
|
@ -267,7 +102,7 @@ mod impls {
|
|||
|
||||
fn side_effect(&self, mut map: SideEffectMap2) {
|
||||
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)]
|
||||
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)]
|
||||
pub enum ResourceRange {
|
||||
Buffer {
|
||||
|
|
@ -324,6 +303,8 @@ pub enum ResourceRange {
|
|||
aspect: vk::ImageAspectFlags,
|
||||
mip_level: MipRange,
|
||||
array_layers: MipRange,
|
||||
origin: (i32, i32, i32),
|
||||
extent: (u32, u32, u32),
|
||||
layout: vk::ImageLayout,
|
||||
},
|
||||
}
|
||||
|
|
@ -360,67 +341,28 @@ pub struct BufferRows {
|
|||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct TextureRange {
|
||||
pub aspect: vk::ImageAspectFlags,
|
||||
pub mip_levels: MipRange,
|
||||
pub array_layers: MipRange,
|
||||
pub origin: (i32, i32, i32),
|
||||
pub extent: (u32, u32, u32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct TextureLayers {
|
||||
pub aspect: vk::ImageAspectFlags,
|
||||
pub mip_level: u32,
|
||||
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,
|
||||
impl TextureRange {
|
||||
pub fn offset(&self) -> vk::Offset3D {
|
||||
vk::Offset3D {
|
||||
x: self.origin.0,
|
||||
y: self.origin.1,
|
||||
z: self.origin.2,
|
||||
}
|
||||
}
|
||||
pub fn extent(&self) -> vk::Extent3D {
|
||||
vk::Extent3D {
|
||||
width: self.extent.0,
|
||||
height: self.extent.1,
|
||||
depth: self.extent.2,
|
||||
}
|
||||
|
||||
impl From<TextureRange> for vk::ImageSubresourceRange {
|
||||
fn from(value: TextureRange) -> Self {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,6 +381,8 @@ impl From<(TextureRange, vk::ImageLayout)> for ResourceRange {
|
|||
aspect: value.aspect,
|
||||
mip_level: value.mip_levels,
|
||||
array_layers: value.array_layers,
|
||||
origin: value.origin,
|
||||
extent: value.extent,
|
||||
layout,
|
||||
}
|
||||
}
|
||||
|
|
@ -461,6 +405,8 @@ impl TextureRange {
|
|||
| vk::ImageAspectFlags::STENCIL,
|
||||
mip_levels: 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 range: TextureLayers,
|
||||
pub offset: vk::Offset3D,
|
||||
pub extent: vk::Extent3D,
|
||||
pub texture: Texture,
|
||||
pub range: TextureRange,
|
||||
}
|
||||
|
||||
pub struct TextureRegions {
|
||||
pub texture: Texture,
|
||||
pub ranges: Vec<TextureRange>,
|
||||
}
|
||||
|
||||
pub struct TextureView {
|
||||
|
|
|
|||
Loading…
Reference in a new issue