use std::sync::{
Arc,
atomic::{AtomicBool, AtomicU64, Ordering},
};
use timeline_syncobj::timeline_syncobj::TimelineSyncObj;
use vulkano::{
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer},
device::DeviceOwnedVulkanObject as _,
format::Format,
image::{
Image, ImageCreateFlags, ImageCreateInfo, ImageLayout, ImageTiling, ImageUsage,
SampleCount,
sampler::{ComponentMapping, ComponentSwizzle},
view::{ImageView, ImageViewCreateInfo},
},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
sync::Sharing,
};
use crate::{
Context,
command_buffer::StarlightCommandBuffer,
images::{AlphaMode, ImageManager, ImageRef, ImageRefSource, ImageResolution, SamplerRef},
resources::{
ReadOp, WriteOp,
buffer::StarlightSubBuffer,
image::{ImageReadOp, ImageWriteOp},
},
};
pub struct LocalImage {
image: Arc<Image>,
image_view: Arc<ImageView>,
timeline: Arc<TimelineSyncObj>,
next_acquire: AtomicU64,
alpha_mode: Option<AlphaMode>,
requires_manual_srgb_mapping: bool,
seen: Arc<AtomicBool>,
}
impl LocalImage {
pub fn new(
ctx: &Context,
software_srgb: bool,
format: Format,
alpha_mode: Option<AlphaMode>,
swizzle: Option<ComponentMapping>,
res: ImageResolution,
layers: u32,
usage: ImageUsage,
debug_name: Option<&str>,
memory_type_filter: MemoryTypeFilter,
) -> Self {
let image = Image::new(
ctx.alloc.clone(),
ImageCreateInfo {
flags: ImageCreateFlags::empty(),
image_type: res.image_type(),
format,
view_formats: vec![],
extent: res.extents(),
array_layers: layers,
mip_levels: 1,
samples: SampleCount::Sample1,
tiling: ImageTiling::Optimal,
usage,
sharing: Sharing::Exclusive,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter,
..Default::default()
},
)
.unwrap();
let mut component_mapping = swizzle.unwrap_or(ComponentMapping::identity());
if alpha_mode.is_none() {
component_mapping.a = ComponentSwizzle::One;
}
let image_view = ImageView::new(
image.clone(),
ImageViewCreateInfo {
component_mapping,
..ImageViewCreateInfo::from_image(&image)
},
)
.unwrap();
if let Some(debug_name) = debug_name {
_ = image.set_debug_utils_object_name(Some(debug_name));
_ = image_view.set_debug_utils_object_name(Some(&format!("{debug_name} View")));
}
let timeline = TimelineSyncObj::new(&ctx.drm_render_node).unwrap();
unsafe { timeline.signal(1).unwrap() };
Self {
image,
image_view,
alpha_mode,
requires_manual_srgb_mapping: software_srgb
|| alpha_mode.is_some_and(|v| v == AlphaMode::PremultipliedElectrical),
timeline: Arc::new(timeline),
next_acquire: AtomicU64::new(1),
seen: AtomicBool::new(false).into(),
}
}
pub fn new_write_op(&self) -> Box<LocalImageWriteOp> {
let acquire = self.next_acquire.fetch_add(1, Ordering::Relaxed);
let release = acquire + 1;
Box::new(LocalImageWriteOp {
image: self.image.clone(),
timeline: self.timeline.clone(),
acquire,
release,
image_view: self.image_view.clone(),
seen: self.seen.clone(),
})
}
pub async fn new_read_op(
&self,
ctx: &Context,
manager: &mut ImageManager,
sampler: Arc<SamplerRef>,
) -> Arc<LocalImageReadOp> {
let image_ref = manager.alloc(ctx, self, sampler).await;
let acquire = self.next_acquire.fetch_add(1, Ordering::Relaxed);
let release = acquire + 1;
Arc::new(LocalImageReadOp {
image: self.image.clone(),
image_view: self.image_view.clone(),
image_ref,
timeline: self.timeline.clone(),
acquire,
release,
})
}
}
pub struct LocalImageReadOp {
image: Arc<Image>,
image_view: Arc<ImageView>,
image_ref: Arc<ImageRef>,
timeline: Arc<TimelineSyncObj>,
acquire: u64,
release: u64,
}
impl ImageReadOp for LocalImageReadOp {
fn image(&self) -> &Arc<Image> {
&self.image
}
fn image_view(&self) -> &Arc<ImageView> {
&self.image_view
}
fn image_ref(&self) -> &ImageRef {
&self.image_ref
}
}
impl ReadOp for LocalImageReadOp {
fn timeline(&self) -> &TimelineSyncObj {
&self.timeline
}
fn acquire_point(&self) -> u64 {
self.acquire
}
}
impl Drop for LocalImageReadOp {
fn drop(&mut self) {
unsafe { self.timeline.signal(self.release).unwrap() };
}
}
pub struct LocalImageWriteOp {
image: Arc<Image>,
image_view: Arc<ImageView>,
timeline: Arc<TimelineSyncObj>,
acquire: u64,
release: u64,
seen: Arc<AtomicBool>,
}
impl LocalImageWriteOp {
pub async fn upload_tmp_staged<Data: BufferContents + Copy>(
self: Box<Self>,
ctx: &Context,
data: &[Data],
) {
let buf: Subbuffer<[Data]> = Buffer::new_slice(
ctx.alloc.clone(),
BufferCreateInfo {
usage: BufferUsage::TRANSFER_SRC,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
data.len() as u64,
)
.unwrap();
buf.write().unwrap().copy_from_slice(data);
let buf = StarlightSubBuffer::from_subbuffer(ctx, buf);
let buf_read = buf.new_read_op();
let queue = ctx
.transfer_queue
.clone()
.unwrap_or_else(|| ctx.gfx_queue.clone());
let mut cmds = StarlightCommandBuffer::new(ctx, queue.queue_family_index()).unwrap();
cmds.set_debug_label(Some(
"LocalImageWriteOp::upload_tmp_staged Buffer To Image Copy",
))
.unwrap();
cmds.buffer_to_image_copy(buf_read, self);
queue.submit(cmds, vec![], vec![]).await;
}
}
impl ImageWriteOp for LocalImageWriteOp {
fn image(&self) -> &Arc<Image> {
&self.image
}
fn image_view(&self) -> &Arc<ImageView> {
&self.image_view
}
fn current_layout(&self) -> ImageLayout {
if self.seen.swap(true, Ordering::Relaxed) {
ImageLayout::General
} else {
ImageLayout::Undefined
}
}
fn target_layout(&self) -> ImageLayout {
ImageLayout::General
}
}
impl WriteOp for LocalImageWriteOp {
fn timeline(&self) -> &TimelineSyncObj {
&self.timeline
}
fn acquire_point(&self) -> u64 {
self.acquire
}
fn release_point(&self) -> u64 {
self.release
}
}
impl ImageRefSource for LocalImage {
fn get_image_ref_info(&self) -> super::ImageRefInfo {
let requires_unmultiply = self.alpha_mode.is_some_and(|v| match v {
AlphaMode::PremultipliedElectrical => true,
AlphaMode::PremultipliedOptical => false,
AlphaMode::Unpremmultiplied => false,
});
let requires_multiply = self.alpha_mode.is_some_and(|v| match v {
AlphaMode::PremultipliedElectrical => true,
AlphaMode::PremultipliedOptical => false,
AlphaMode::Unpremmultiplied => true,
});
super::ImageRefInfo {
requires_software_srgb: self.requires_manual_srgb_mapping,
requires_unmultiplication: requires_unmultiply,
requires_multiplication: requires_multiply,
}
}
fn get_image(&self) -> Arc<Image> {
self.image.clone()
}
fn get_image_view(&self) -> Arc<ImageView> {
self.image_view.clone()
}
}