adds mipmapping

This commit is contained in:
zomseffen 2024-04-27 10:52:06 +02:00
parent 8afb2d2a3c
commit b5d3864d01
4 changed files with 167 additions and 12 deletions

View file

@ -48,6 +48,7 @@ pub struct AppData {
pub descriptor_pool: vk::DescriptorPool, pub descriptor_pool: vk::DescriptorPool,
pub descriptor_sets: Vec<vk::DescriptorSet>, pub descriptor_sets: Vec<vk::DescriptorSet>,
pub mip_levels: u32,
pub texture_image: vk::Image, pub texture_image: vk::Image,
pub texture_image_memory: vk::DeviceMemory, pub texture_image_memory: vk::DeviceMemory,
pub texture_image_view: vk::ImageView, pub texture_image_view: vk::ImageView,

View file

@ -16,6 +16,7 @@ pub unsafe fn create_depth_objects(
data, data,
data.swapchain_extent.width, data.swapchain_extent.width,
data.swapchain_extent.height, data.swapchain_extent.height,
1,
format, format,
vk::ImageTiling::OPTIMAL, vk::ImageTiling::OPTIMAL,
vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT, vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
@ -27,7 +28,7 @@ pub unsafe fn create_depth_objects(
// Image View // Image View
data.depth_image_view = image::create_image_view(device, data.depth_image, format, vk::ImageAspectFlags::DEPTH)?; data.depth_image_view = image::create_image_view(device, data.depth_image, format, vk::ImageAspectFlags::DEPTH, 1)?;
image::transition_image_layout( image::transition_image_layout(
device, device,
@ -36,6 +37,7 @@ pub unsafe fn create_depth_objects(
format, format,
vk::ImageLayout::UNDEFINED, vk::ImageLayout::UNDEFINED,
vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL, vk::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
1
)?; )?;
Ok(()) Ok(())

View file

@ -29,6 +29,8 @@ pub unsafe fn create_texture_image(
let size = reader.info().raw_bytes() as u64; let size = reader.info().raw_bytes() as u64;
let (width, height) = reader.info().size(); let (width, height) = reader.info().size();
data.mip_levels = (width.max(height) as f32).log2().floor() as u32 + 1;
if width != 1024 || height != 1024 || reader.info().color_type != png::ColorType::Rgba { if width != 1024 || height != 1024 || reader.info().color_type != png::ColorType::Rgba {
panic!("Invalid texture image (use https://kylemayes.github.io/vulkanalia/images/viking_room.png)."); panic!("Invalid texture image (use https://kylemayes.github.io/vulkanalia/images/viking_room.png).");
} }
@ -59,9 +61,12 @@ pub unsafe fn create_texture_image(
data, data,
width, width,
height, height,
data.mip_levels,
vk::Format::R8G8B8A8_SRGB, vk::Format::R8G8B8A8_SRGB,
vk::ImageTiling::OPTIMAL, vk::ImageTiling::OPTIMAL,
vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST, vk::ImageUsageFlags::SAMPLED
| vk::ImageUsageFlags::TRANSFER_DST
| vk::ImageUsageFlags::TRANSFER_SRC,
vk::MemoryPropertyFlags::DEVICE_LOCAL, vk::MemoryPropertyFlags::DEVICE_LOCAL,
)?; )?;
@ -75,6 +80,7 @@ pub unsafe fn create_texture_image(
vk::Format::R8G8B8A8_SRGB, vk::Format::R8G8B8A8_SRGB,
vk::ImageLayout::UNDEFINED, vk::ImageLayout::UNDEFINED,
vk::ImageLayout::TRANSFER_DST_OPTIMAL, vk::ImageLayout::TRANSFER_DST_OPTIMAL,
data.mip_levels
)?; )?;
copy_buffer_to_image( copy_buffer_to_image(
@ -86,13 +92,15 @@ pub unsafe fn create_texture_image(
height, height,
)?; )?;
transition_image_layout( generate_mipmaps(
instance,
device, device,
data, data,
data.texture_image, data.texture_image,
vk::Format::R8G8B8A8_SRGB, vk::Format::R8G8B8A8_SRGB,
vk::ImageLayout::TRANSFER_DST_OPTIMAL, width,
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, height,
data.mip_levels,
)?; )?;
device.destroy_buffer(staging_buffer, None); device.destroy_buffer(staging_buffer, None);
@ -107,6 +115,7 @@ pub unsafe fn create_image(
data: &app_data::AppData, data: &app_data::AppData,
width: u32, width: u32,
height: u32, height: u32,
mip_levels: u32,
format: vk::Format, format: vk::Format,
tiling: vk::ImageTiling, tiling: vk::ImageTiling,
usage: vk::ImageUsageFlags, usage: vk::ImageUsageFlags,
@ -119,7 +128,7 @@ pub unsafe fn create_image(
height, height,
depth: 1, depth: 1,
}) })
.mip_levels(1) .mip_levels(mip_levels)
.array_layers(1) .array_layers(1)
.format(format) .format(format)
.tiling(tiling) .tiling(tiling)
@ -155,6 +164,7 @@ pub unsafe fn transition_image_layout(
format: vk::Format, format: vk::Format,
old_layout: vk::ImageLayout, old_layout: vk::ImageLayout,
new_layout: vk::ImageLayout, new_layout: vk::ImageLayout,
mip_levels: u32,
) -> Result<()> { ) -> Result<()> {
let command_buffer = command_buffer::begin_single_time_commands(device, data)?; let command_buffer = command_buffer::begin_single_time_commands(device, data)?;
@ -198,7 +208,7 @@ pub unsafe fn transition_image_layout(
let subresource = vk::ImageSubresourceRange::builder() let subresource = vk::ImageSubresourceRange::builder()
.aspect_mask(aspect_mask) .aspect_mask(aspect_mask)
.base_mip_level(0) .base_mip_level(0)
.level_count(1) .level_count(mip_levels)
.base_array_layer(0) .base_array_layer(0)
.layer_count(1); .layer_count(1);
@ -269,11 +279,12 @@ pub unsafe fn create_image_view(
image: vk::Image, image: vk::Image,
format: vk::Format, format: vk::Format,
aspects: vk::ImageAspectFlags, aspects: vk::ImageAspectFlags,
mip_levels: u32,
) -> Result<vk::ImageView> { ) -> Result<vk::ImageView> {
let subresource_range = vk::ImageSubresourceRange::builder() let subresource_range = vk::ImageSubresourceRange::builder()
.aspect_mask(aspects) .aspect_mask(aspects)
.base_mip_level(0) .base_mip_level(0)
.level_count(1) .level_count(mip_levels)
.base_array_layer(0) .base_array_layer(0)
.layer_count(1); .layer_count(1);
@ -291,7 +302,8 @@ pub unsafe fn create_texture_image_view(device: &Device, data: &mut app_data::Ap
device, device,
data.texture_image, data.texture_image,
vk::Format::R8G8B8A8_SRGB, vk::Format::R8G8B8A8_SRGB,
vk::ImageAspectFlags::COLOR vk::ImageAspectFlags::COLOR,
data.mip_levels
)?; )?;
Ok(()) Ok(())
@ -312,10 +324,150 @@ pub unsafe fn create_texture_sampler(device: &Device, data: &mut app_data::AppDa
.compare_enable(false) .compare_enable(false)
.compare_op(vk::CompareOp::ALWAYS) .compare_op(vk::CompareOp::ALWAYS)
.mipmap_mode(vk::SamplerMipmapMode::LINEAR) .mipmap_mode(vk::SamplerMipmapMode::LINEAR)
.mip_lod_bias(0.0)
.min_lod(0.0) .min_lod(0.0)
.max_lod(0.0); .max_lod(data.mip_levels as f32)
.mip_lod_bias(0.0);
data.texture_sampler = device.create_sampler(&info, None)?; data.texture_sampler = device.create_sampler(&info, None)?;
Ok(()) Ok(())
} }
unsafe fn generate_mipmaps(
instance: &Instance,
device: &Device,
data: &app_data::AppData,
image: vk::Image,
format: vk::Format,
width: u32,
height: u32,
mip_levels: u32,
) -> Result<()> {
if !instance
.get_physical_device_format_properties(data.physical_device, format)
.optimal_tiling_features
.contains(vk::FormatFeatureFlags::SAMPLED_IMAGE_FILTER_LINEAR)
{
return Err(anyhow!("Texture image format does not support linear blitting!"));
}
let command_buffer = command_buffer::begin_single_time_commands(device, data)?;
let subresource = vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.base_array_layer(0)
.layer_count(1)
.level_count(1);
let mut barrier = vk::ImageMemoryBarrier::builder()
.image(image)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.subresource_range(subresource);
let mut mip_width = width;
let mut mip_height = height;
for i in 1..mip_levels {
barrier.subresource_range.base_mip_level = i - 1;
barrier.old_layout = vk::ImageLayout::TRANSFER_DST_OPTIMAL;
barrier.new_layout = vk::ImageLayout::TRANSFER_SRC_OPTIMAL;
barrier.src_access_mask = vk::AccessFlags::TRANSFER_WRITE;
barrier.dst_access_mask = vk::AccessFlags::TRANSFER_READ;
device.cmd_pipeline_barrier(
command_buffer,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::TRANSFER,
vk::DependencyFlags::empty(),
&[] as &[vk::MemoryBarrier],
&[] as &[vk::BufferMemoryBarrier],
&[barrier],
);
let src_subresource = vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(i - 1)
.base_array_layer(0)
.layer_count(1);
let dst_subresource = vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(i)
.base_array_layer(0)
.layer_count(1);
let blit = vk::ImageBlit::builder()
.src_offsets([
vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D {
x: mip_width as i32,
y: mip_height as i32,
z: 1,
},
])
.src_subresource(src_subresource)
.dst_offsets([
vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D {
x: (if mip_width > 1 { mip_width / 2 } else { 1 }) as i32,
y: (if mip_height > 1 { mip_height / 2 } else { 1 }) as i32,
z: 1,
},
])
.dst_subresource(dst_subresource);
device.cmd_blit_image(
command_buffer,
image,
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[blit],
vk::Filter::LINEAR,
);
barrier.old_layout = vk::ImageLayout::TRANSFER_SRC_OPTIMAL;
barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL;
barrier.src_access_mask = vk::AccessFlags::TRANSFER_READ;
barrier.dst_access_mask = vk::AccessFlags::SHADER_READ;
device.cmd_pipeline_barrier(
command_buffer,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::DependencyFlags::empty(),
&[] as &[vk::MemoryBarrier],
&[] as &[vk::BufferMemoryBarrier],
&[barrier],
);
if mip_width > 1 {
mip_width /= 2;
}
if mip_height > 1 {
mip_height /= 2;
}
}
barrier.subresource_range.base_mip_level = mip_levels - 1;
barrier.old_layout = vk::ImageLayout::TRANSFER_DST_OPTIMAL;
barrier.new_layout = vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL;
barrier.src_access_mask = vk::AccessFlags::TRANSFER_WRITE;
barrier.dst_access_mask = vk::AccessFlags::SHADER_READ;
device.cmd_pipeline_barrier(
command_buffer,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::DependencyFlags::empty(),
&[] as &[vk::MemoryBarrier],
&[] as &[vk::BufferMemoryBarrier],
&[barrier],
);
command_buffer::end_single_time_commands(device, data, command_buffer)?;
Ok(())
}

View file

@ -141,7 +141,7 @@ pub unsafe fn create_swapchain_image_views(
data.swapchain_image_views = data data.swapchain_image_views = data
.swapchain_images .swapchain_images
.iter() .iter()
.map(|i| image::create_image_view(device, *i, data.swapchain_format, vk::ImageAspectFlags::COLOR)) .map(|i| image::create_image_view(device, *i, data.swapchain_format, vk::ImageAspectFlags::COLOR, 1))
.collect::<Result<Vec<_>, _>>()?; .collect::<Result<Vec<_>, _>>()?;
Ok(()) Ok(())