1
0
Fork 0
forked from wry/wry
wry/src/gfx_apis/vulkan/blend_buffer.rs
2025-02-24 11:36:10 +01:00

139 lines
5.1 KiB
Rust

use {
crate::{
gfx_api::GfxBlendBuffer,
gfx_apis::vulkan::{
VulkanError,
format::{BLEND_FORMAT, BLEND_USAGE},
image::{QueueFamily, QueueState, VulkanImage, VulkanImageMemory},
renderer::VulkanRenderer,
},
utils::on_drop::OnDrop,
},
ash::vk::{
DescriptorDataEXT, DescriptorGetInfoEXT, DescriptorImageInfo, DescriptorType, Extent3D,
ImageAspectFlags, ImageCreateInfo, ImageLayout, ImageSubresourceRange, ImageTiling,
ImageType, ImageViewCreateInfo, ImageViewType, SampleCountFlags, SharingMode,
},
gpu_alloc::UsageFlags,
std::{any::Any, cell::Cell, collections::hash_map::Entry, rc::Rc},
};
impl VulkanRenderer {
pub fn acquire_blend_buffer(
self: &Rc<Self>,
width: i32,
height: i32,
) -> Result<Rc<VulkanImage>, VulkanError> {
let Some(db) = &self.device.descriptor_buffer else {
return Err(VulkanError::NoDescriptorBuffer);
};
if width <= 0 || height <= 0 {
return Err(VulkanError::NonPositiveImageSize);
}
let width = width as u32;
let height = height as u32;
let cached = &mut *self.blend_buffers.borrow_mut();
let cached = cached.entry((width, height));
if let Entry::Occupied(entry) = &cached {
if let Some(buffer) = entry.get().upgrade() {
return Ok(buffer);
}
}
let limits = self.device.blend_limits;
if width > limits.max_width || height > limits.max_height {
return Err(VulkanError::ImageTooLarge);
}
let create_info = ImageCreateInfo::default()
.image_type(ImageType::TYPE_2D)
.format(BLEND_FORMAT.vk_format)
.mip_levels(1)
.array_layers(1)
.tiling(ImageTiling::OPTIMAL)
.samples(SampleCountFlags::TYPE_1)
.sharing_mode(SharingMode::EXCLUSIVE)
.initial_layout(ImageLayout::UNDEFINED)
.extent(Extent3D {
width,
height,
depth: 1,
})
.usage(BLEND_USAGE);
let image = unsafe { self.device.device.create_image(&create_info, None) };
let image = image.map_err(VulkanError::CreateImage)?;
let destroy_image = OnDrop(|| unsafe { self.device.device.destroy_image(image, None) });
let memory_requirements =
unsafe { self.device.device.get_image_memory_requirements(image) };
let allocation =
self.allocator
.alloc(&memory_requirements, UsageFlags::FAST_DEVICE_ACCESS, false)?;
let res = unsafe {
self.device
.device
.bind_image_memory(image, allocation.memory, allocation.offset)
};
res.map_err(VulkanError::BindImageMemory)?;
let image_view_create_info = ImageViewCreateInfo::default()
.image(image)
.format(BLEND_FORMAT.vk_format)
.view_type(ImageViewType::TYPE_2D)
.subresource_range(ImageSubresourceRange {
aspect_mask: ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: 1,
base_array_layer: 0,
layer_count: 1,
});
let view = unsafe {
self.device
.device
.create_image_view(&image_view_create_info, None)
};
let view = view.map_err(VulkanError::CreateImageView)?;
destroy_image.forget();
let sampled_image_descriptor = {
let mut buf = vec![0; self.device.sampled_image_descriptor_size].into_boxed_slice();
let image_info = DescriptorImageInfo::default()
.image_view(view)
.image_layout(ImageLayout::SHADER_READ_ONLY_OPTIMAL);
let info = DescriptorGetInfoEXT::default()
.ty(DescriptorType::SAMPLED_IMAGE)
.data(DescriptorDataEXT {
p_sampled_image: &image_info,
});
unsafe {
db.get_descriptor(&info, &mut buf);
}
buf
};
let img = Rc::new(VulkanImage {
renderer: self.clone(),
format: BLEND_FORMAT,
width,
height,
stride: 0,
texture_view: view,
render_view: None,
image,
is_undefined: Cell::new(true),
contents_are_undefined: Cell::new(true),
queue_state: Cell::new(QueueState::Acquired {
family: QueueFamily::Gfx,
}),
ty: VulkanImageMemory::Blend(allocation),
bridge: None,
shader_read_only_optimal_descriptor: Box::new([]),
sampled_image_descriptor,
descriptor_buffer_version: Default::default(),
descriptor_buffer_offset: Default::default(),
execution_version: Default::default(),
});
cached.insert_entry(Rc::downgrade(&img));
Ok(img)
}
}
impl GfxBlendBuffer for VulkanImage {
fn into_any(self: Rc<Self>) -> Rc<dyn Any> {
self
}
}