use ash::vk::{self, Handle};
use imgui::TextureId;
use vk_mem::Alloc;
use crate::util::RaiiWrapper;
use super::{FontsCreateError, Texture};
impl<A> super::Renderer<A>
where
A: vk_mem::Alloc,
{
pub(crate) unsafe fn create_fonts_texture(
&mut self,
context: &mut imgui::Context,
) -> Result<(), FontsCreateError> {
if self.fonts_texture.is_some() {
unsafe { self.destroy_fonts_texture(Some(context)) };
}
let device = &self.device;
{
unsafe {
device.reset_command_pool(
self.device_objects.tex_command_pool,
vk::CommandPoolResetFlags::empty(),
)
}
.map_err(FontsCreateError::CommandPoolResetError)?;
let begin_info = vk::CommandBufferBeginInfo::default()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
unsafe {
device.begin_command_buffer(self.device_objects.tex_command_buffer, &begin_info)
}
.map_err(FontsCreateError::CommandBeginError)?;
}
let font_atlas = context.fonts().build_rgba32_texture();
let alloc = self.allocator.allocator();
let image_and_alloc = {
let create_info = vk::ImageCreateInfo::default()
.image_type(vk::ImageType::TYPE_2D)
.format(vk::Format::R8G8B8A8_UNORM)
.extent(
vk::Extent3D::default()
.width(font_atlas.width)
.height(font_atlas.height)
.depth(1),
)
.mip_levels(1)
.array_layers(1)
.samples(vk::SampleCountFlags::TYPE_1)
.tiling(vk::ImageTiling::OPTIMAL)
.usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST)
.sharing_mode(vk::SharingMode::EXCLUSIVE)
.initial_layout(vk::ImageLayout::UNDEFINED);
let alloc_info = vk_mem::AllocationCreateInfo {
usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default()
};
RaiiWrapper::new(
unsafe { alloc.create_image(&create_info, &alloc_info) }
.map_err(FontsCreateError::ImageAllocError)?,
|(img, mut allocation)| unsafe {
alloc.destroy_image(img, &mut allocation);
},
)
};
let view = {
let create_info = vk::ImageViewCreateInfo::default()
.image(image_and_alloc.0)
.view_type(vk::ImageViewType::TYPE_2D)
.format(vk::Format::R8G8B8A8_UNORM)
.subresource_range(
vk::ImageSubresourceRange::default()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.level_count(1)
.layer_count(1),
);
RaiiWrapper::new(
unsafe { device.create_image_view(&create_info, None) }
.map_err(FontsCreateError::ImageViewCreateError)?,
|v| unsafe { device.destroy_image_view(v, None) },
)
};
let sampler = self.device_objects.tex_sampler;
let texture =
self.add_texture(sampler, *view, vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)?;
let desriptor_set = RaiiWrapper::new(texture, |s| unsafe {
self.remove_texture(s);
});
let mut upload_buffer_and_alloc = {
let create_info = vk::BufferCreateInfo::default()
.size(font_atlas.data.len() as _)
.usage(vk::BufferUsageFlags::TRANSFER_SRC)
.sharing_mode(vk::SharingMode::EXCLUSIVE);
let alloc_info = vk_mem::AllocationCreateInfo {
usage: vk_mem::MemoryUsage::AutoPreferDevice,
flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
..Default::default()
};
RaiiWrapper::new(
unsafe { alloc.create_buffer(&create_info, &alloc_info) }
.map_err(FontsCreateError::TransferbufferCreateError)?,
|(buf, mut allocation)| unsafe { alloc.destroy_buffer(buf, &mut allocation) },
)
};
{
let memory = unsafe { alloc.map_memory(&mut upload_buffer_and_alloc.1) }
.map_err(FontsCreateError::MmapError)?;
unsafe {
core::ptr::copy_nonoverlapping(
font_atlas.data.as_ptr(),
memory,
font_atlas.data.len(),
);
}
unsafe {
alloc.unmap_memory(&mut upload_buffer_and_alloc.1);
alloc.flush_allocation(&upload_buffer_and_alloc.1, 0, font_atlas.data.len() as _)
}
.map_err(FontsCreateError::FlushError)?;
}
{
let copy_barrier = [vk::ImageMemoryBarrier::default()
.dst_access_mask(vk::AccessFlags::TRANSFER_WRITE)
.old_layout(vk::ImageLayout::UNDEFINED)
.new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image_and_alloc.0)
.subresource_range(
vk::ImageSubresourceRange::default()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.level_count(1)
.layer_count(1),
)];
unsafe {
device.cmd_pipeline_barrier(
self.device_objects.tex_command_buffer,
vk::PipelineStageFlags::HOST,
vk::PipelineStageFlags::TRANSFER,
vk::DependencyFlags::empty(),
&[],
&[],
©_barrier,
);
}
let region = vk::BufferImageCopy::default()
.image_subresource(
vk::ImageSubresourceLayers::default()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.layer_count(1),
)
.image_extent(
vk::Extent3D::default()
.width(font_atlas.width)
.height(font_atlas.height)
.depth(1),
);
unsafe {
self.device.cmd_copy_buffer_to_image(
self.device_objects.tex_command_buffer,
upload_buffer_and_alloc.0,
image_and_alloc.0,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[region],
);
}
let use_barrier = [vk::ImageMemoryBarrier::default()
.src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
.dst_access_mask(vk::AccessFlags::SHADER_READ)
.old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
.new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image_and_alloc.0)
.subresource_range(
vk::ImageSubresourceRange::default()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.level_count(1)
.layer_count(1),
)];
unsafe {
self.device.cmd_pipeline_barrier(
self.device_objects.tex_command_buffer,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::DependencyFlags::empty(),
&[],
&[],
&use_barrier,
);
}
}
unsafe { device.end_command_buffer(self.device_objects.tex_command_buffer) }
.map_err(FontsCreateError::CommandEndError)?;
let tex_buffers = [self.device_objects.tex_command_buffer];
let submit_info = vk::SubmitInfo::default().command_buffers(&tex_buffers);
unsafe {
device.queue_submit(
self.create_info.queue,
&[submit_info],
self.device_objects.wait_fence,
)
}
.map_err(FontsCreateError::SubmitError)?;
unsafe {
device
.wait_for_fences(
&[self.device_objects.wait_fence],
true,
core::time::Duration::from_secs(10).as_nanos() as u64,
)
.unwrap()
}
context.fonts().tex_id = TextureId::new(desriptor_set.as_raw() as _);
let (image, alloc) = image_and_alloc.finalise();
let texture = Texture {
image,
memory: alloc,
descriptor_set: desriptor_set.finalise(),
image_view: view.finalise(),
};
self.fonts_texture = Some(texture);
Ok(())
}
pub(crate) unsafe fn destroy_fonts_texture(&mut self, context: Option<&mut imgui::Context>) {
if let Some(mut texture) = self.fonts_texture.take() {
unsafe { self.remove_texture(texture.descriptor_set) };
if let Some(context) = context {
context.fonts().tex_id = TextureId::new(0);
}
unsafe {
self.device.destroy_image_view(texture.image_view, None);
self.allocator
.allocator()
.destroy_image(texture.image, &mut texture.memory);
}
}
}
}