Pass along the level of mip maps, and generate the mipmaps
This commit is contained in:
parent
da64696c8f
commit
bd370e1bf9
199
src/app/data.rs
199
src/app/data.rs
@ -69,6 +69,7 @@ pub(crate) struct AppData {
|
|||||||
depth_image_memory: vk::DeviceMemory,
|
depth_image_memory: vk::DeviceMemory,
|
||||||
depth_image_view: vk::ImageView,
|
depth_image_view: vk::ImageView,
|
||||||
// Texture
|
// Texture
|
||||||
|
mip_levels: u32,
|
||||||
texture_image: vk::Image,
|
texture_image: vk::Image,
|
||||||
texture_image_memory: vk::DeviceMemory,
|
texture_image_memory: vk::DeviceMemory,
|
||||||
texture_image_view: vk::ImageView,
|
texture_image_view: vk::ImageView,
|
||||||
@ -324,7 +325,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn check_physical_device_extensions(
|
unsafe fn check_physical_device_extensions(
|
||||||
instance: &Instance,
|
instance: &Instance,
|
||||||
physical_device: vk::PhysicalDevice,
|
physical_device: vk::PhysicalDevice,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
@ -475,6 +476,7 @@ impl AppData {
|
|||||||
device: &Device,
|
device: &Device,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
device.device_wait_idle()?;
|
device.device_wait_idle()?;
|
||||||
|
|
||||||
self.destroy_swapchain(device);
|
self.destroy_swapchain(device);
|
||||||
self.create_swapchain(window, instance, device)?;
|
self.create_swapchain(window, instance, device)?;
|
||||||
self.create_swapchain_image_views(device)?;
|
self.create_swapchain_image_views(device)?;
|
||||||
@ -503,6 +505,7 @@ impl AppData {
|
|||||||
*i,
|
*i,
|
||||||
self.swapchain_format,
|
self.swapchain_format,
|
||||||
vk::ImageAspectFlags::COLOR,
|
vk::ImageAspectFlags::COLOR,
|
||||||
|
1,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
@ -511,9 +514,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_swapchain_surface_format(
|
fn get_swapchain_surface_format(formats: &[vk::SurfaceFormatKHR]) -> vk::SurfaceFormatKHR {
|
||||||
formats: &[vk::SurfaceFormatKHR],
|
|
||||||
) -> vk::SurfaceFormatKHR {
|
|
||||||
formats
|
formats
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -524,9 +525,7 @@ pub(crate) fn get_swapchain_surface_format(
|
|||||||
.unwrap_or_else(|| formats[0])
|
.unwrap_or_else(|| formats[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_swapchain_present_mode(
|
fn get_swapchain_present_mode(present_modes: &[vk::PresentModeKHR]) -> vk::PresentModeKHR {
|
||||||
present_modes: &[vk::PresentModeKHR],
|
|
||||||
) -> vk::PresentModeKHR {
|
|
||||||
present_modes
|
present_modes
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -534,10 +533,7 @@ pub(crate) fn get_swapchain_present_mode(
|
|||||||
.unwrap_or(vk::PresentModeKHR::FIFO)
|
.unwrap_or(vk::PresentModeKHR::FIFO)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_swapchain_extent(
|
fn get_swapchain_extent(window: &Window, capabilities: vk::SurfaceCapabilitiesKHR) -> vk::Extent2D {
|
||||||
window: &Window,
|
|
||||||
capabilities: vk::SurfaceCapabilitiesKHR,
|
|
||||||
) -> vk::Extent2D {
|
|
||||||
if capabilities.current_extent.width != u32::MAX {
|
if capabilities.current_extent.width != u32::MAX {
|
||||||
capabilities.current_extent
|
capabilities.current_extent
|
||||||
} else {
|
} else {
|
||||||
@ -758,10 +754,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn create_shader_module(
|
unsafe fn create_shader_module(device: &Device, bytecode: &[u8]) -> Result<vk::ShaderModule> {
|
||||||
device: &Device,
|
|
||||||
bytecode: &[u8],
|
|
||||||
) -> Result<vk::ShaderModule> {
|
|
||||||
let bytecode = Vec::<u8>::from(bytecode);
|
let bytecode = Vec::<u8>::from(bytecode);
|
||||||
let (prefix, code, suffix) = bytecode.align_to::<u32>();
|
let (prefix, code, suffix) = bytecode.align_to::<u32>();
|
||||||
if !prefix.is_empty() || !suffix.is_empty() {
|
if !prefix.is_empty() || !suffix.is_empty() {
|
||||||
@ -829,6 +822,7 @@ impl AppData {
|
|||||||
device,
|
device,
|
||||||
self.swapchain_extent.width,
|
self.swapchain_extent.width,
|
||||||
self.swapchain_extent.height,
|
self.swapchain_extent.height,
|
||||||
|
1,
|
||||||
format,
|
format,
|
||||||
vk::ImageTiling::OPTIMAL,
|
vk::ImageTiling::OPTIMAL,
|
||||||
vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
|
vk::ImageUsageFlags::DEPTH_STENCIL_ATTACHMENT,
|
||||||
@ -843,6 +837,7 @@ impl AppData {
|
|||||||
self.depth_image,
|
self.depth_image,
|
||||||
format,
|
format,
|
||||||
vk::ImageAspectFlags::DEPTH,
|
vk::ImageAspectFlags::DEPTH,
|
||||||
|
1,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -905,6 +900,7 @@ impl AppData {
|
|||||||
|
|
||||||
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();
|
||||||
|
self.mip_levels = (width.max(height) as f32).log2().floor() as u32 + 1;
|
||||||
|
|
||||||
// Create the staging buffer
|
// Create the staging buffer
|
||||||
let (staging_buffer, staging_buffer_memory) = unsafe {
|
let (staging_buffer, staging_buffer_memory) = unsafe {
|
||||||
@ -931,9 +927,12 @@ impl AppData {
|
|||||||
device,
|
device,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
self.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,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -946,31 +945,176 @@ impl AppData {
|
|||||||
vk::Format::R8G8B8A8_SRGB,
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
vk::ImageLayout::UNDEFINED,
|
vk::ImageLayout::UNDEFINED,
|
||||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
self.mip_levels,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.copy_buffer_to_image(device, staging_buffer, self.texture_image, width, height)?;
|
self.copy_buffer_to_image(device, staging_buffer, self.texture_image, width, height)?;
|
||||||
|
|
||||||
self.transition_image_layout(
|
device.destroy_buffer(staging_buffer, None);
|
||||||
|
device.free_memory(staging_buffer_memory, None);
|
||||||
|
|
||||||
|
self.generate_mipmaps(
|
||||||
|
instance,
|
||||||
device,
|
device,
|
||||||
self.texture_image,
|
self.texture_image,
|
||||||
vk::Format::R8G8B8A8_SRGB,
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
width,
|
||||||
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
height,
|
||||||
|
self.mip_levels,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
device.destroy_buffer(staging_buffer, None);
|
|
||||||
device.free_memory(staging_buffer_memory, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn generate_mipmaps(
|
||||||
|
&self,
|
||||||
|
instance: &Instance,
|
||||||
|
device: &Device,
|
||||||
|
image: vk::Image,
|
||||||
|
format: vk::Format,
|
||||||
|
width: u32,
|
||||||
|
height: u32,
|
||||||
|
mip_levels: u32,
|
||||||
|
) -> Result<()> {
|
||||||
|
if !instance
|
||||||
|
.get_physical_device_format_properties(self.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 = self.begin_single_time_commands(device)?;
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
|
||||||
|
self.end_single_time_commands(device, command_buffer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn create_texture_image_view(&mut self, device: &Device) -> Result<()> {
|
unsafe fn create_texture_image_view(&mut self, device: &Device) -> Result<()> {
|
||||||
self.texture_image_view = create_image_view(
|
self.texture_image_view = create_image_view(
|
||||||
device,
|
device,
|
||||||
self.texture_image,
|
self.texture_image,
|
||||||
vk::Format::R8G8B8A8_SRGB,
|
vk::Format::R8G8B8A8_SRGB,
|
||||||
vk::ImageAspectFlags::COLOR,
|
vk::ImageAspectFlags::COLOR,
|
||||||
|
self.mip_levels,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -1385,6 +1529,7 @@ impl AppData {
|
|||||||
device: &Device,
|
device: &Device,
|
||||||
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,
|
||||||
@ -1397,7 +1542,7 @@ impl AppData {
|
|||||||
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)
|
||||||
@ -1428,6 +1573,7 @@ impl AppData {
|
|||||||
_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 (src_access_mask, dst_access_mask, src_stage_mask, dst_stage_mask) =
|
let (src_access_mask, dst_access_mask, src_stage_mask, dst_stage_mask) =
|
||||||
match (old_layout, new_layout) {
|
match (old_layout, new_layout) {
|
||||||
@ -1454,7 +1600,7 @@ impl AppData {
|
|||||||
let subresource = vk::ImageSubresourceRange::builder()
|
let subresource = vk::ImageSubresourceRange::builder()
|
||||||
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
.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);
|
||||||
|
|
||||||
@ -1525,16 +1671,17 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) unsafe fn create_image_view(
|
unsafe fn create_image_view(
|
||||||
device: &Device,
|
device: &Device,
|
||||||
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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user