librashader/librashader-runtime-vk/src/texture.rs

562 lines
20 KiB
Rust
Raw Normal View History

2023-01-14 09:59:22 +11:00
use crate::filter_chain::VulkanObjects;
2022-12-22 17:30:14 +11:00
use crate::util::find_vulkan_memory_type;
use crate::vulkan_primitives::VulkanImageMemory;
2023-01-13 13:29:42 +11:00
use crate::{error, util};
2023-01-10 14:54:54 +11:00
use ash::vk;
2023-01-15 19:06:09 +11:00
use std::sync::Arc;
use crate::error::FilterChainError;
2023-01-10 14:54:54 +11:00
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
2022-12-22 17:30:14 +11:00
2023-01-12 15:05:08 +11:00
pub struct OwnedImage {
pub device: Arc<ash::Device>,
pub mem_props: vk::PhysicalDeviceMemoryProperties,
2022-12-22 17:30:14 +11:00
pub image_view: vk::ImageView,
2022-12-25 17:18:11 +11:00
pub image: VulkanImage,
2022-12-22 17:30:14 +11:00
pub memory: VulkanImageMemory,
pub max_miplevels: u32,
pub levels: u32,
2022-12-22 17:30:14 +11:00
}
#[derive(Clone)]
pub struct OwnedImageLayout {
pub(crate) dst_layout: vk::ImageLayout,
pub(crate) dst_access: vk::AccessFlags,
pub(crate) src_stage: vk::PipelineStageFlags,
pub(crate) dst_stage: vk::PipelineStageFlags,
2023-01-13 13:29:42 +11:00
pub(crate) cmd: vk::CommandBuffer,
}
2023-01-12 15:05:08 +11:00
impl OwnedImage {
fn new_internal(
device: Arc<ash::Device>,
mem_props: vk::PhysicalDeviceMemoryProperties,
2023-01-10 14:54:54 +11:00
size: Size<u32>,
2023-01-12 16:00:45 +11:00
mut format: ImageFormat,
2023-01-10 14:54:54 +11:00
max_miplevels: u32,
2023-01-12 15:05:08 +11:00
) -> error::Result<OwnedImage> {
2023-01-12 16:00:45 +11:00
// default to something sane
if format == ImageFormat::Unknown {
format = ImageFormat::R8G8B8A8Unorm
}
2022-12-22 17:30:14 +11:00
let image_create_info = vk::ImageCreateInfo::builder()
.image_type(vk::ImageType::TYPE_2D)
2022-12-22 17:30:14 +11:00
.format(format.into())
.extent(size.into())
2023-01-10 14:54:54 +11:00
.mip_levels(std::cmp::min(max_miplevels, size.calculate_miplevels()))
2022-12-22 17:30:14 +11:00
.array_layers(1)
.samples(vk::SampleCountFlags::TYPE_1)
.tiling(vk::ImageTiling::OPTIMAL)
2023-01-11 14:22:42 +11:00
.flags(vk::ImageCreateFlags::MUTABLE_FORMAT)
2022-12-22 17:30:14 +11:00
.usage(
vk::ImageUsageFlags::SAMPLED
| vk::ImageUsageFlags::COLOR_ATTACHMENT
| vk::ImageUsageFlags::TRANSFER_DST
| vk::ImageUsageFlags::TRANSFER_SRC,
2022-12-22 17:30:14 +11:00
)
.sharing_mode(vk::SharingMode::EXCLUSIVE)
.initial_layout(vk::ImageLayout::UNDEFINED)
2022-12-22 17:30:14 +11:00
.build();
let image = unsafe { device.create_image(&image_create_info, None)? };
2023-01-16 03:08:13 +11:00
let mem_reqs = unsafe { device.get_image_memory_requirements(image) };
2022-12-22 17:30:14 +11:00
let alloc_info = vk::MemoryAllocateInfo::builder()
.allocation_size(mem_reqs.size)
.memory_type_index(find_vulkan_memory_type(
&mem_props,
2022-12-22 17:30:14 +11:00
mem_reqs.memory_type_bits,
vk::MemoryPropertyFlags::DEVICE_LOCAL,
2023-01-14 08:10:54 +11:00
)?)
2022-12-22 17:30:14 +11:00
.build();
// todo: optimize by reusing existing memory.
let memory = VulkanImageMemory::new(&device, &alloc_info)?;
2022-12-22 17:30:14 +11:00
memory.bind(&image)?;
let image_subresource = vk::ImageSubresourceRange::builder()
.base_mip_level(0)
.base_array_layer(0)
.level_count(image_create_info.mip_levels)
.layer_count(1)
.aspect_mask(vk::ImageAspectFlags::COLOR)
2022-12-22 17:30:14 +11:00
.build();
let swizzle_components = vk::ComponentMapping::builder()
.r(vk::ComponentSwizzle::R)
.g(vk::ComponentSwizzle::G)
.b(vk::ComponentSwizzle::B)
.a(vk::ComponentSwizzle::A)
.build();
2023-01-13 17:48:04 +11:00
let view_info = vk::ImageViewCreateInfo::builder()
.view_type(vk::ImageViewType::TYPE_2D)
2022-12-22 17:30:14 +11:00
.format(format.into())
2023-01-16 03:08:13 +11:00
.image(image)
2022-12-22 17:30:14 +11:00
.subresource_range(image_subresource)
.components(swizzle_components)
.build();
let image_view = unsafe { device.create_image_view(&view_info, None)? };
2022-12-22 17:30:14 +11:00
2023-01-12 15:05:08 +11:00
Ok(OwnedImage {
device,
mem_props,
2022-12-22 17:30:14 +11:00
image_view,
2022-12-25 17:18:11 +11:00
image: VulkanImage {
image,
size,
2023-01-10 14:54:54 +11:00
format: format.into(),
2022-12-25 17:18:11 +11:00
},
2022-12-22 17:30:14 +11:00
memory,
max_miplevels,
2023-01-13 13:29:42 +11:00
levels: std::cmp::min(max_miplevels, size.calculate_miplevels()),
2022-12-22 17:30:14 +11:00
})
}
pub fn new(
2023-01-14 09:59:22 +11:00
vulkan: &VulkanObjects,
size: Size<u32>,
format: ImageFormat,
max_miplevels: u32,
2023-01-12 15:05:08 +11:00
) -> error::Result<OwnedImage> {
2023-01-13 13:29:42 +11:00
Self::new_internal(
vulkan.device.clone(),
vulkan.memory_properties,
size,
format,
max_miplevels,
)
}
pub(crate) fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
mipmap: bool,
2023-01-13 13:29:42 +11:00
layout: Option<OwnedImageLayout>,
) -> error::Result<Size<u32>> {
let size = source_size.scale_viewport(scaling, *viewport_size);
2023-01-13 13:29:42 +11:00
if self.image.size != size
|| (mipmap && self.max_miplevels == 1)
|| (!mipmap && self.max_miplevels != 1)
|| vk::Format::from(format) != self.image.format
2023-01-13 13:29:42 +11:00
{
let max_levels = if mipmap { u32::MAX } else { 1 };
2023-01-13 17:48:04 +11:00
let new = OwnedImage::new_internal(
2023-01-13 13:29:42 +11:00
self.device.clone(),
self.mem_props,
size,
if format == ImageFormat::Unknown {
ImageFormat::R8G8B8A8Unorm
} else {
format
},
max_levels,
)?;
2023-01-11 14:22:42 +11:00
let old = std::mem::replace(self, new);
drop(old);
if let Some(layout) = layout {
unsafe {
2023-01-13 13:29:42 +11:00
util::vulkan_image_layout_transition_levels(
&self.device,
layout.cmd,
self.image.image,
self.levels,
vk::ImageLayout::UNDEFINED,
layout.dst_layout,
vk::AccessFlags::empty(),
layout.dst_access,
layout.src_stage,
layout.dst_stage,
vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED,
)
}
}
}
Ok(size)
}
2023-01-15 07:10:40 +11:00
pub(crate) fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputImage {
2023-01-13 13:11:44 +11:00
InputImage {
image: self.image.clone(),
2023-01-16 03:08:13 +11:00
image_view: self.image_view,
wrap_mode,
filter_mode: filter,
mip_filter: filter,
2023-01-13 13:11:44 +11:00
}
}
pub fn generate_mipmaps_and_end_pass(&self, cmd: vk::CommandBuffer) {
let input_barrier = vk::ImageMemoryBarrier::builder()
.src_access_mask(vk::AccessFlags::COLOR_ATTACHMENT_WRITE)
.dst_access_mask(vk::AccessFlags::TRANSFER_READ)
.old_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.new_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(self.image.image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: 1,
base_array_layer: 0,
2023-01-13 13:29:42 +11:00
layer_count: vk::REMAINING_ARRAY_LAYERS,
})
.build();
let mipchain_barrier = vk::ImageMemoryBarrier::builder()
.src_access_mask(vk::AccessFlags::empty())
.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(self.image.image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 1,
base_array_layer: 0,
level_count: vk::REMAINING_MIP_LEVELS,
2023-01-13 13:29:42 +11:00
layer_count: vk::REMAINING_ARRAY_LAYERS,
})
.build();
unsafe {
2023-01-13 13:29:42 +11:00
self.device.cmd_pipeline_barrier(
cmd,
vk::PipelineStageFlags::ALL_GRAPHICS,
vk::PipelineStageFlags::TRANSFER,
vk::DependencyFlags::empty(),
&[],
&[],
&[input_barrier, mipchain_barrier],
);
for level in 1..self.levels {
// need to transition from DST to SRC, one level at a time.
if level > 1 {
let next_barrier = vk::ImageMemoryBarrier::builder()
.src_access_mask(vk::AccessFlags::TRANSFER_WRITE)
.dst_access_mask(vk::AccessFlags::TRANSFER_READ)
.old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
.new_layout(vk::ImageLayout::TRANSFER_SRC_OPTIMAL)
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(self.image.image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: level - 1,
base_array_layer: 0,
level_count: 1,
2023-01-13 13:29:42 +11:00
layer_count: vk::REMAINING_ARRAY_LAYERS,
})
.build();
2023-01-13 13:29:42 +11:00
self.device.cmd_pipeline_barrier(
cmd,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::TRANSFER,
vk::DependencyFlags::empty(),
&[],
&[],
&[next_barrier],
);
}
let source_size = self.image.size.scale_mipmap(level - 1);
let target_size = self.image.size.scale_mipmap(level);
let src_offsets = [
vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D {
x: source_size.width as i32,
y: source_size.height as i32,
z: 1,
},
];
let dst_offsets = [
vk::Offset3D { x: 0, y: 0, z: 0 },
vk::Offset3D {
x: target_size.width as i32,
y: target_size.height as i32,
z: 1,
},
];
let src_subresource = vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(level - 1)
.base_array_layer(0)
.layer_count(1)
.build();
let dst_subresource = vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(level)
.base_array_layer(0)
.layer_count(1)
.build();
let image_blit = [vk::ImageBlit::builder()
.src_subresource(src_subresource)
.src_offsets(src_offsets)
.dst_subresource(dst_subresource)
.dst_offsets(dst_offsets)
.build()];
self.device.cmd_blit_image(
cmd,
self.image.image,
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
self.image.image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&image_blit,
vk::Filter::LINEAR,
);
}
// move everything to SHADER_READ_ONLY_OPTIMAL
let input_barrier = vk::ImageMemoryBarrier::builder()
.src_access_mask(vk::AccessFlags::TRANSFER_READ)
.dst_access_mask(vk::AccessFlags::SHADER_READ)
.old_layout(vk::ImageLayout::TRANSFER_SRC_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(self.image.image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: 0,
level_count: self.levels - 1,
base_array_layer: 0,
2023-01-13 13:29:42 +11:00
layer_count: vk::REMAINING_ARRAY_LAYERS,
})
.build();
let mipchain_barrier = vk::ImageMemoryBarrier::builder()
.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(self.image.image)
.subresource_range(vk::ImageSubresourceRange {
aspect_mask: vk::ImageAspectFlags::COLOR,
base_mip_level: self.levels - 1,
base_array_layer: 0,
level_count: 1,
2023-01-13 13:29:42 +11:00
layer_count: vk::REMAINING_ARRAY_LAYERS,
})
.build();
// next past waits for ALL_GRAPHICS, use dependency chain and FRAGMENT_SHADER dst stage
// to ensure that next pass doesn't start until mipchain is complete.
2023-01-13 13:29:42 +11:00
self.device.cmd_pipeline_barrier(
cmd,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::DependencyFlags::empty(),
&[],
&[],
&[input_barrier, mipchain_barrier],
);
}
}
/// SAFETY: self must fit the source image
2023-01-13 13:29:42 +11:00
pub unsafe fn copy_from(
&self,
cmd: vk::CommandBuffer,
source: &VulkanImage,
source_layout: vk::ImageLayout,
) {
let region = vk::ImageCopy::builder()
2023-01-13 13:29:42 +11:00
.src_subresource(
vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(0)
.base_array_layer(0)
.layer_count(1)
.build(),
)
2023-01-13 13:29:42 +11:00
.dst_subresource(
vk::ImageSubresourceLayers::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.mip_level(0)
.base_array_layer(0)
.layer_count(1)
.build(),
)
.src_offset(Default::default())
.dst_offset(Default::default())
.extent(source.size.into())
.build();
unsafe {
2023-01-13 13:29:42 +11:00
util::vulkan_image_layout_transition_levels(
&self.device,
cmd,
self.image.image,
vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::UNDEFINED,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::AccessFlags::empty(),
vk::AccessFlags::TRANSFER_WRITE,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::PipelineStageFlags::TRANSFER,
2023-01-13 13:29:42 +11:00
vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED,
);
2023-01-13 13:29:42 +11:00
self.device.cmd_copy_image(
cmd,
source.image,
source_layout,
self.image.image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&[region],
);
util::vulkan_image_layout_transition_levels(
&self.device,
cmd,
self.image.image,
vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
vk::AccessFlags::TRANSFER_WRITE,
vk::AccessFlags::SHADER_READ,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED,
);
}
}
pub fn clear(&self, cmd: vk::CommandBuffer) {
unsafe {
2023-01-13 13:29:42 +11:00
util::vulkan_image_layout_transition_levels(
&self.device,
cmd,
self.image.image,
vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::UNDEFINED,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::AccessFlags::empty(),
vk::AccessFlags::TRANSFER_WRITE,
vk::PipelineStageFlags::TOP_OF_PIPE,
vk::PipelineStageFlags::TRANSFER,
vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED,
);
2023-01-13 13:29:42 +11:00
self.device.cmd_clear_color_image(
cmd,
self.image.image,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
&vk::ClearColorValue {
float32: [0.0, 0.0, 0.0, 0.0],
},
&[vk::ImageSubresourceRange::builder()
.aspect_mask(vk::ImageAspectFlags::COLOR)
.base_mip_level(0)
.level_count(1)
.base_array_layer(0)
.layer_count(1)
.build()],
);
2023-01-13 13:29:42 +11:00
util::vulkan_image_layout_transition_levels(
&self.device,
cmd,
self.image.image,
vk::REMAINING_MIP_LEVELS,
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
vk::AccessFlags::TRANSFER_WRITE,
vk::AccessFlags::SHADER_READ,
vk::PipelineStageFlags::TRANSFER,
vk::PipelineStageFlags::FRAGMENT_SHADER,
vk::QUEUE_FAMILY_IGNORED,
vk::QUEUE_FAMILY_IGNORED,
);
}
}
2022-12-22 17:30:14 +11:00
}
2023-01-12 15:05:08 +11:00
impl Drop for OwnedImage {
2022-12-22 17:30:14 +11:00
fn drop(&mut self) {
unsafe {
if self.image_view != vk::ImageView::null() {
self.device.destroy_image_view(self.image_view, None);
}
2022-12-29 16:50:48 +11:00
if self.image.image != vk::Image::null() {
2022-12-25 17:18:11 +11:00
self.device.destroy_image(self.image.image, None);
2022-12-22 17:30:14 +11:00
}
}
}
}
2023-01-13 19:19:58 +11:00
/// A handle to a `VkImage` with size and format information.
#[derive(Clone)]
2022-12-25 17:18:11 +11:00
pub struct VulkanImage {
2023-01-15 07:10:40 +11:00
/// A handle to the `VkImage`.
2022-12-22 17:30:14 +11:00
pub image: vk::Image,
2023-01-15 07:10:40 +11:00
/// The size of the image.
pub size: Size<u32>,
/// The `VkFormat` of the image.
2022-12-22 17:30:14 +11:00
pub format: vk::Format,
2022-12-25 17:18:11 +11:00
}
#[derive(Clone)]
2023-01-15 19:01:23 +11:00
pub struct InputImage {
2023-01-15 07:10:40 +11:00
/// A handle to the `VkImage`.
2022-12-25 17:18:11 +11:00
pub image: VulkanImage,
2023-01-15 07:10:40 +11:00
/// A handle to the `VkImageView` for the image.
2022-12-25 17:18:11 +11:00
pub image_view: vk::ImageView,
2022-12-22 17:30:14 +11:00
pub wrap_mode: WrapMode,
pub filter_mode: FilterMode,
pub mip_filter: FilterMode,
}
2023-01-15 19:01:23 +11:00
impl AsRef<InputImage> for InputImage {
fn as_ref(&self) -> &InputImage {
2023-01-16 03:08:13 +11:00
self
2023-01-15 19:01:23 +11:00
}
2023-01-15 19:06:09 +11:00
}
impl ScaleFramebuffer for OwnedImage {
type Error = FilterChainError;
type Context = Option<OwnedImageLayout>;
fn scale(
&mut self,
scaling: Scale2D,
format: ImageFormat,
viewport_size: &Size<u32>,
source_size: &Size<u32>,
should_mipmap: bool,
context: &Self::Context,
) -> Result<Size<u32>, Self::Error> {
self.scale(
scaling,
format,
viewport_size,
source_size,
should_mipmap,
context.clone(),
)
}
}