Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
953
third-party/vendor/gpu-allocator/examples/vulkan-visualization/imgui_renderer.rs
vendored
Normal file
953
third-party/vendor/gpu-allocator/examples/vulkan-visualization/imgui_renderer.rs
vendored
Normal file
|
|
@ -0,0 +1,953 @@
|
|||
use ash::vk;
|
||||
|
||||
use crate::helper::record_and_submit_command_buffer;
|
||||
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme, Allocator};
|
||||
use gpu_allocator::MemoryLocation;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
struct ImGuiCBuffer {
|
||||
scale: [f32; 2],
|
||||
translation: [f32; 2],
|
||||
}
|
||||
pub struct ImGuiRenderer {
|
||||
sampler: vk::Sampler,
|
||||
|
||||
vb_capacity: u64,
|
||||
ib_capacity: u64,
|
||||
vb_allocation: Allocation,
|
||||
ib_allocation: Allocation,
|
||||
vertex_buffer: vk::Buffer,
|
||||
index_buffer: vk::Buffer,
|
||||
|
||||
cb_allocation: Allocation,
|
||||
constant_buffer: vk::Buffer,
|
||||
|
||||
font_image: vk::Image,
|
||||
font_image_memory: Allocation,
|
||||
font_image_view: vk::ImageView,
|
||||
|
||||
descriptor_sets: Vec<vk::DescriptorSet>,
|
||||
|
||||
vs_module: vk::ShaderModule,
|
||||
ps_module: vk::ShaderModule,
|
||||
descriptor_set_layouts: Vec<vk::DescriptorSetLayout>,
|
||||
pipeline_layout: vk::PipelineLayout,
|
||||
pub(crate) render_pass: vk::RenderPass,
|
||||
pipeline: vk::Pipeline,
|
||||
}
|
||||
|
||||
impl ImGuiRenderer {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub(crate) fn new(
|
||||
imgui: &mut imgui::Context,
|
||||
device: &ash::Device,
|
||||
descriptor_pool: vk::DescriptorPool,
|
||||
render_target_format: vk::Format,
|
||||
allocator: &mut Allocator,
|
||||
cmd: vk::CommandBuffer,
|
||||
cmd_reuse_fence: vk::Fence,
|
||||
queue: vk::Queue,
|
||||
) -> Result<Self, vk::Result> {
|
||||
let (pipeline_layout, descriptor_set_layouts) = {
|
||||
let bindings = [
|
||||
vk::DescriptorSetLayoutBinding {
|
||||
binding: 0,
|
||||
descriptor_type: vk::DescriptorType::UNIFORM_BUFFER,
|
||||
descriptor_count: 1,
|
||||
stage_flags: vk::ShaderStageFlags::VERTEX,
|
||||
p_immutable_samplers: std::ptr::null(),
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding {
|
||||
binding: 1,
|
||||
descriptor_type: vk::DescriptorType::SAMPLER,
|
||||
descriptor_count: 1,
|
||||
stage_flags: vk::ShaderStageFlags::FRAGMENT,
|
||||
p_immutable_samplers: std::ptr::null(),
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding {
|
||||
binding: 2,
|
||||
descriptor_type: vk::DescriptorType::SAMPLED_IMAGE,
|
||||
descriptor_count: 1,
|
||||
stage_flags: vk::ShaderStageFlags::FRAGMENT,
|
||||
p_immutable_samplers: std::ptr::null(),
|
||||
},
|
||||
];
|
||||
|
||||
let set_layout_infos =
|
||||
[vk::DescriptorSetLayoutCreateInfo::builder().bindings(&bindings)];
|
||||
let set_layouts = set_layout_infos
|
||||
.iter()
|
||||
.map(|info| unsafe { device.create_descriptor_set_layout(info, None) })
|
||||
.collect::<Result<Vec<_>, vk::Result>>()?;
|
||||
|
||||
let layout_info = vk::PipelineLayoutCreateInfo::builder().set_layouts(&set_layouts);
|
||||
let pipeline_layout = unsafe { device.create_pipeline_layout(&layout_info, None) }?;
|
||||
|
||||
(pipeline_layout, set_layouts)
|
||||
};
|
||||
|
||||
let render_pass = {
|
||||
let attachments = vk::AttachmentDescription::builder()
|
||||
.format(render_target_format)
|
||||
.samples(vk::SampleCountFlags::TYPE_1)
|
||||
.load_op(vk::AttachmentLoadOp::CLEAR)
|
||||
.store_op(vk::AttachmentStoreOp::STORE)
|
||||
.final_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
let subpass_attachment = vk::AttachmentReference::builder()
|
||||
.attachment(0)
|
||||
.layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL);
|
||||
let subpass_description = vk::SubpassDescription::builder()
|
||||
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS)
|
||||
.color_attachments(std::slice::from_ref(&subpass_attachment));
|
||||
|
||||
let dependencies = vk::SubpassDependency::builder()
|
||||
.src_subpass(vk::SUBPASS_EXTERNAL)
|
||||
.src_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT)
|
||||
.dst_access_mask(
|
||||
vk::AccessFlags::COLOR_ATTACHMENT_READ
|
||||
| vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
|
||||
)
|
||||
.dst_stage_mask(vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT);
|
||||
|
||||
let render_pass_create_info = vk::RenderPassCreateInfo::builder()
|
||||
.attachments(std::slice::from_ref(&attachments))
|
||||
.subpasses(std::slice::from_ref(&subpass_description))
|
||||
.dependencies(std::slice::from_ref(&dependencies));
|
||||
unsafe { device.create_render_pass(&render_pass_create_info, None) }.unwrap()
|
||||
};
|
||||
|
||||
let vs_module = {
|
||||
let vs = include_bytes!("./spirv/imgui.vs.spv");
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let shader_info = vk::ShaderModuleCreateInfo::builder().code(unsafe {
|
||||
assert_eq!(vs.len() % 4, 0);
|
||||
std::slice::from_raw_parts(vs.as_ptr().cast(), vs.len() / 4)
|
||||
});
|
||||
unsafe { device.create_shader_module(&shader_info, None) }?
|
||||
};
|
||||
let ps_module = {
|
||||
let ps = include_bytes!("./spirv/imgui.ps.spv");
|
||||
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
let shader_info = vk::ShaderModuleCreateInfo::builder().code(unsafe {
|
||||
assert_eq!(ps.len() % 4, 0);
|
||||
std::slice::from_raw_parts(ps.as_ptr().cast(), ps.len() / 4)
|
||||
});
|
||||
unsafe { device.create_shader_module(&shader_info, None) }?
|
||||
};
|
||||
|
||||
let pipeline = {
|
||||
let vertex_stage = vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(vk::ShaderStageFlags::VERTEX)
|
||||
.module(vs_module)
|
||||
.name(std::ffi::CStr::from_bytes_with_nul(b"main\0").unwrap());
|
||||
let fragment_stage = vk::PipelineShaderStageCreateInfo::builder()
|
||||
.stage(vk::ShaderStageFlags::FRAGMENT)
|
||||
.module(ps_module)
|
||||
.name(std::ffi::CStr::from_bytes_with_nul(b"main\0").unwrap());
|
||||
let stages = [vertex_stage.build(), fragment_stage.build()];
|
||||
|
||||
let vertex_binding_descriptions = [vk::VertexInputBindingDescription {
|
||||
binding: 0,
|
||||
stride: std::mem::size_of::<imgui::DrawVert>() as u32,
|
||||
input_rate: vk::VertexInputRate::VERTEX,
|
||||
}];
|
||||
let vertex_attribute_descriptions = [
|
||||
vk::VertexInputAttributeDescription {
|
||||
location: 0,
|
||||
binding: 0,
|
||||
format: vk::Format::R32G32_SFLOAT,
|
||||
offset: 0,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
location: 1,
|
||||
binding: 0,
|
||||
format: vk::Format::R32G32_SFLOAT,
|
||||
offset: 8,
|
||||
},
|
||||
vk::VertexInputAttributeDescription {
|
||||
location: 2,
|
||||
binding: 0,
|
||||
format: vk::Format::R8G8B8A8_UNORM,
|
||||
offset: 16,
|
||||
},
|
||||
];
|
||||
let vertex_input_state = vk::PipelineVertexInputStateCreateInfo::builder()
|
||||
.vertex_binding_descriptions(&vertex_binding_descriptions)
|
||||
.vertex_attribute_descriptions(&vertex_attribute_descriptions);
|
||||
let input_assembly_state = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
||||
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
||||
let viewport_state = vk::PipelineViewportStateCreateInfo::builder()
|
||||
.viewport_count(1)
|
||||
.scissor_count(1);
|
||||
let rasterization_state = vk::PipelineRasterizationStateCreateInfo::builder()
|
||||
.polygon_mode(vk::PolygonMode::FILL)
|
||||
.cull_mode(vk::CullModeFlags::NONE)
|
||||
.front_face(vk::FrontFace::CLOCKWISE)
|
||||
.depth_bias_enable(false)
|
||||
.line_width(1.0);
|
||||
let multisample_state = vk::PipelineMultisampleStateCreateInfo::builder()
|
||||
.rasterization_samples(vk::SampleCountFlags::TYPE_1);
|
||||
let noop_stencil_state = vk::StencilOpState {
|
||||
fail_op: vk::StencilOp::KEEP,
|
||||
pass_op: vk::StencilOp::KEEP,
|
||||
depth_fail_op: vk::StencilOp::KEEP,
|
||||
compare_op: vk::CompareOp::ALWAYS,
|
||||
..Default::default()
|
||||
};
|
||||
let depth_stencil_state = vk::PipelineDepthStencilStateCreateInfo::builder()
|
||||
.depth_test_enable(false)
|
||||
.depth_write_enable(false)
|
||||
.depth_compare_op(vk::CompareOp::ALWAYS)
|
||||
.depth_bounds_test_enable(false)
|
||||
.stencil_test_enable(false)
|
||||
.front(noop_stencil_state)
|
||||
.back(noop_stencil_state)
|
||||
.max_depth_bounds(1.0);
|
||||
let attachments = vk::PipelineColorBlendAttachmentState::builder()
|
||||
.blend_enable(true)
|
||||
.src_color_blend_factor(vk::BlendFactor::SRC_ALPHA)
|
||||
.dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
|
||||
.color_blend_op(vk::BlendOp::ADD)
|
||||
.src_alpha_blend_factor(vk::BlendFactor::ZERO)
|
||||
.dst_alpha_blend_factor(vk::BlendFactor::ZERO)
|
||||
.alpha_blend_op(vk::BlendOp::ADD)
|
||||
.color_write_mask({
|
||||
vk::ColorComponentFlags::R
|
||||
| vk::ColorComponentFlags::G
|
||||
| vk::ColorComponentFlags::B
|
||||
| vk::ColorComponentFlags::A
|
||||
});
|
||||
let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder()
|
||||
.logic_op(vk::LogicOp::CLEAR)
|
||||
.attachments(std::slice::from_ref(&attachments));
|
||||
let dynamic_state = vk::PipelineDynamicStateCreateInfo::builder()
|
||||
.dynamic_states(&[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]);
|
||||
|
||||
let pipeline_create_info = vk::GraphicsPipelineCreateInfo::builder()
|
||||
.stages(&stages)
|
||||
.vertex_input_state(&vertex_input_state)
|
||||
.input_assembly_state(&input_assembly_state)
|
||||
.viewport_state(&viewport_state)
|
||||
.rasterization_state(&rasterization_state)
|
||||
.multisample_state(&multisample_state)
|
||||
.depth_stencil_state(&depth_stencil_state)
|
||||
.color_blend_state(&color_blend_state)
|
||||
.dynamic_state(&dynamic_state)
|
||||
.layout(pipeline_layout)
|
||||
.render_pass(render_pass)
|
||||
.subpass(0);
|
||||
|
||||
unsafe {
|
||||
device.create_graphics_pipelines(
|
||||
vk::PipelineCache::null(),
|
||||
std::slice::from_ref(&pipeline_create_info),
|
||||
None,
|
||||
)
|
||||
}
|
||||
.unwrap()[0]
|
||||
};
|
||||
|
||||
let (font_image, font_image_memory, font_image_view) = {
|
||||
let fonts = imgui.fonts();
|
||||
let font_atlas = fonts.build_rgba32_texture();
|
||||
|
||||
// Create image
|
||||
let image_usage = vk::ImageUsageFlags::SAMPLED
|
||||
| vk::ImageUsageFlags::TRANSFER_DST
|
||||
| vk::ImageUsageFlags::TRANSFER_SRC;
|
||||
let create_info = vk::ImageCreateInfo::builder()
|
||||
.image_type(vk::ImageType::TYPE_2D)
|
||||
.format(vk::Format::R8G8B8A8_UNORM)
|
||||
.extent(vk::Extent3D {
|
||||
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(image_usage)
|
||||
.initial_layout(vk::ImageLayout::UNDEFINED);
|
||||
let image = unsafe { device.create_image(&create_info, None) }?;
|
||||
|
||||
// Allocate and bind memory to image
|
||||
let requirements = unsafe { device.get_image_memory_requirements(image) };
|
||||
let allocation = allocator
|
||||
.allocate(&AllocationCreateDesc {
|
||||
name: "ImGui font image",
|
||||
requirements,
|
||||
location: MemoryLocation::GpuOnly,
|
||||
linear: false,
|
||||
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||
})
|
||||
.unwrap();
|
||||
unsafe { device.bind_image_memory(image, allocation.memory(), allocation.offset()) }
|
||||
.unwrap();
|
||||
|
||||
// Create image view
|
||||
let view_create_info = vk::ImageViewCreateInfo::builder()
|
||||
.image(image)
|
||||
.view_type(vk::ImageViewType::TYPE_2D)
|
||||
.format(vk::Format::R8G8B8A8_UNORM)
|
||||
.components(vk::ComponentMapping {
|
||||
r: vk::ComponentSwizzle::R,
|
||||
g: vk::ComponentSwizzle::G,
|
||||
b: vk::ComponentSwizzle::B,
|
||||
a: vk::ComponentSwizzle::A,
|
||||
})
|
||||
.subresource_range(vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
base_mip_level: 0,
|
||||
level_count: 1,
|
||||
base_array_layer: 0,
|
||||
layer_count: 1,
|
||||
});
|
||||
let image_view = unsafe { device.create_image_view(&view_create_info, None) }?;
|
||||
|
||||
// Create upload buffer
|
||||
let (upload_buffer, upload_buffer_memory) = {
|
||||
let create_info = vk::BufferCreateInfo::builder()
|
||||
.size((font_atlas.width * font_atlas.height * 4) as u64)
|
||||
.usage(vk::BufferUsageFlags::TRANSFER_SRC);
|
||||
let buffer = unsafe { device.create_buffer(&create_info, None) }?;
|
||||
|
||||
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
|
||||
|
||||
let buffer_memory = allocator
|
||||
.allocate(&AllocationCreateDesc {
|
||||
name: "ImGui font image upload buffer",
|
||||
requirements,
|
||||
location: MemoryLocation::CpuToGpu,
|
||||
linear: true,
|
||||
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
device.bind_buffer_memory(
|
||||
buffer,
|
||||
buffer_memory.memory(),
|
||||
buffer_memory.offset(),
|
||||
)
|
||||
}?;
|
||||
|
||||
(buffer, buffer_memory)
|
||||
};
|
||||
|
||||
// Copy font data to upload buffer
|
||||
let dst = upload_buffer_memory.mapped_ptr().unwrap().cast().as_ptr();
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
font_atlas.data.as_ptr(),
|
||||
dst,
|
||||
(font_atlas.width * font_atlas.height * 4) as usize,
|
||||
);
|
||||
}
|
||||
|
||||
// Copy upload buffer to image
|
||||
record_and_submit_command_buffer(
|
||||
device,
|
||||
cmd,
|
||||
cmd_reuse_fence,
|
||||
queue,
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
|device, cmd| {
|
||||
{
|
||||
let layout_transition_barriers = vk::ImageMemoryBarrier::builder()
|
||||
.image(image)
|
||||
.dst_access_mask(vk::AccessFlags::TRANSFER_WRITE)
|
||||
.new_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||
.old_layout(vk::ImageLayout::UNDEFINED)
|
||||
.subresource_range(vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
base_mip_level: 0,
|
||||
level_count: vk::REMAINING_MIP_LEVELS,
|
||||
base_array_layer: 0,
|
||||
layer_count: vk::REMAINING_ARRAY_LAYERS,
|
||||
});
|
||||
|
||||
unsafe {
|
||||
device.cmd_pipeline_barrier(
|
||||
cmd,
|
||||
vk::PipelineStageFlags::BOTTOM_OF_PIPE,
|
||||
vk::PipelineStageFlags::TRANSFER,
|
||||
vk::DependencyFlags::empty(),
|
||||
&[],
|
||||
&[],
|
||||
std::slice::from_ref(&layout_transition_barriers),
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let regions = vk::BufferImageCopy::builder()
|
||||
.buffer_offset(0)
|
||||
.buffer_row_length(font_atlas.width)
|
||||
.buffer_image_height(font_atlas.height)
|
||||
.image_subresource(vk::ImageSubresourceLayers {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
mip_level: 0,
|
||||
base_array_layer: 0,
|
||||
layer_count: 1,
|
||||
})
|
||||
.image_offset(vk::Offset3D { x: 0, y: 0, z: 0 })
|
||||
.image_extent(vk::Extent3D {
|
||||
width: font_atlas.width,
|
||||
height: font_atlas.height,
|
||||
depth: 1,
|
||||
});
|
||||
unsafe {
|
||||
device.cmd_copy_buffer_to_image(
|
||||
cmd,
|
||||
upload_buffer,
|
||||
image,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
std::slice::from_ref(®ions),
|
||||
)
|
||||
};
|
||||
|
||||
{
|
||||
let layout_transition_barriers = vk::ImageMemoryBarrier::builder()
|
||||
.image(image)
|
||||
.dst_access_mask(vk::AccessFlags::SHADER_READ)
|
||||
.new_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL)
|
||||
.old_layout(vk::ImageLayout::TRANSFER_DST_OPTIMAL)
|
||||
.subresource_range(vk::ImageSubresourceRange {
|
||||
aspect_mask: vk::ImageAspectFlags::COLOR,
|
||||
base_mip_level: 0,
|
||||
level_count: vk::REMAINING_MIP_LEVELS,
|
||||
base_array_layer: 0,
|
||||
layer_count: vk::REMAINING_ARRAY_LAYERS,
|
||||
});
|
||||
|
||||
unsafe {
|
||||
device.cmd_pipeline_barrier(
|
||||
cmd,
|
||||
vk::PipelineStageFlags::BOTTOM_OF_PIPE,
|
||||
vk::PipelineStageFlags::FRAGMENT_SHADER,
|
||||
vk::DependencyFlags::empty(),
|
||||
&[],
|
||||
&[],
|
||||
std::slice::from_ref(&layout_transition_barriers),
|
||||
)
|
||||
};
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
unsafe { device.queue_wait_idle(queue) }?;
|
||||
|
||||
// Free upload buffer
|
||||
unsafe { device.destroy_buffer(upload_buffer, None) };
|
||||
allocator.free(upload_buffer_memory).unwrap();
|
||||
|
||||
(image, allocation, image_view)
|
||||
};
|
||||
|
||||
let sampler = {
|
||||
let create_info = vk::SamplerCreateInfo::builder()
|
||||
.mag_filter(vk::Filter::NEAREST)
|
||||
.min_filter(vk::Filter::NEAREST)
|
||||
.mipmap_mode(vk::SamplerMipmapMode::NEAREST)
|
||||
.address_mode_u(vk::SamplerAddressMode::REPEAT)
|
||||
.address_mode_v(vk::SamplerAddressMode::REPEAT)
|
||||
.address_mode_w(vk::SamplerAddressMode::REPEAT)
|
||||
.mip_lod_bias(0.0)
|
||||
.anisotropy_enable(false)
|
||||
.compare_enable(false)
|
||||
.unnormalized_coordinates(false);
|
||||
unsafe { device.create_sampler(&create_info, None) }?
|
||||
};
|
||||
|
||||
let (vertex_buffer, vb_allocation, vb_capacity) = {
|
||||
let capacity = 1024 * 1024;
|
||||
|
||||
let create_info = vk::BufferCreateInfo::builder()
|
||||
.size(capacity)
|
||||
.usage(vk::BufferUsageFlags::VERTEX_BUFFER)
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
||||
|
||||
let buffer = unsafe { device.create_buffer(&create_info, None) }?;
|
||||
|
||||
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
|
||||
|
||||
let allocation = allocator
|
||||
.allocate(&AllocationCreateDesc {
|
||||
name: "ImGui Vertex buffer",
|
||||
requirements,
|
||||
location: MemoryLocation::CpuToGpu,
|
||||
linear: true,
|
||||
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
unsafe { device.bind_buffer_memory(buffer, allocation.memory(), allocation.offset()) }?;
|
||||
|
||||
(buffer, allocation, capacity)
|
||||
};
|
||||
let (index_buffer, ib_allocation, ib_capacity) = {
|
||||
let capacity = 1024 * 1024;
|
||||
|
||||
let create_info = vk::BufferCreateInfo::builder()
|
||||
.size(capacity)
|
||||
.usage(vk::BufferUsageFlags::INDEX_BUFFER)
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
||||
|
||||
let buffer = unsafe { device.create_buffer(&create_info, None) }?;
|
||||
|
||||
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
|
||||
|
||||
let allocation = allocator
|
||||
.allocate(&AllocationCreateDesc {
|
||||
name: "ImGui Index buffer",
|
||||
requirements,
|
||||
location: MemoryLocation::CpuToGpu,
|
||||
linear: true,
|
||||
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
unsafe { device.bind_buffer_memory(buffer, allocation.memory(), allocation.offset()) }?;
|
||||
|
||||
(buffer, allocation, capacity)
|
||||
};
|
||||
let (constant_buffer, cb_allocation) = {
|
||||
let create_info = vk::BufferCreateInfo::builder()
|
||||
.size(std::mem::size_of::<ImGuiCBuffer>() as u64)
|
||||
.usage(vk::BufferUsageFlags::UNIFORM_BUFFER)
|
||||
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
||||
|
||||
let buffer = unsafe { device.create_buffer(&create_info, None) }?;
|
||||
|
||||
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
|
||||
|
||||
let allocation = allocator
|
||||
.allocate(&AllocationCreateDesc {
|
||||
name: "ImGui Constant buffer",
|
||||
requirements,
|
||||
location: MemoryLocation::CpuToGpu,
|
||||
linear: true,
|
||||
allocation_scheme: AllocationScheme::GpuAllocatorManaged,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
unsafe { device.bind_buffer_memory(buffer, allocation.memory(), allocation.offset()) }?;
|
||||
|
||||
(buffer, allocation)
|
||||
};
|
||||
|
||||
let descriptor_sets = {
|
||||
let alloc_info = vk::DescriptorSetAllocateInfo::builder()
|
||||
.descriptor_pool(descriptor_pool)
|
||||
.set_layouts(&descriptor_set_layouts);
|
||||
let descriptor_sets = unsafe { device.allocate_descriptor_sets(&alloc_info) }?;
|
||||
|
||||
let buffer_info = vk::DescriptorBufferInfo::builder()
|
||||
.buffer(constant_buffer)
|
||||
.offset(0)
|
||||
.range(std::mem::size_of::<ImGuiCBuffer>() as u64);
|
||||
let uniform_buffer = vk::WriteDescriptorSet::builder()
|
||||
.dst_set(descriptor_sets[0])
|
||||
.dst_binding(0)
|
||||
.descriptor_type(vk::DescriptorType::UNIFORM_BUFFER)
|
||||
.buffer_info(std::slice::from_ref(&buffer_info));
|
||||
|
||||
let image_info = vk::DescriptorImageInfo::builder().sampler(sampler);
|
||||
let sampler = vk::WriteDescriptorSet::builder()
|
||||
.dst_set(descriptor_sets[0])
|
||||
.dst_binding(1)
|
||||
.descriptor_type(vk::DescriptorType::SAMPLER)
|
||||
.image_info(std::slice::from_ref(&image_info));
|
||||
|
||||
let image_info = vk::DescriptorImageInfo::builder()
|
||||
.image_view(font_image_view)
|
||||
.image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL);
|
||||
let sampled_image = vk::WriteDescriptorSet::builder()
|
||||
.dst_set(descriptor_sets[0])
|
||||
.dst_binding(2)
|
||||
.descriptor_type(vk::DescriptorType::SAMPLED_IMAGE)
|
||||
.image_info(std::slice::from_ref(&image_info));
|
||||
|
||||
unsafe {
|
||||
device.update_descriptor_sets(
|
||||
&[
|
||||
uniform_buffer.build(),
|
||||
sampler.build(),
|
||||
sampled_image.build(),
|
||||
],
|
||||
&[],
|
||||
)
|
||||
};
|
||||
descriptor_sets
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
sampler,
|
||||
|
||||
vb_capacity,
|
||||
ib_capacity,
|
||||
vb_allocation,
|
||||
ib_allocation,
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
cb_allocation,
|
||||
constant_buffer,
|
||||
|
||||
font_image,
|
||||
font_image_memory,
|
||||
font_image_view,
|
||||
|
||||
descriptor_sets,
|
||||
|
||||
vs_module,
|
||||
ps_module,
|
||||
descriptor_set_layouts,
|
||||
pipeline_layout,
|
||||
render_pass,
|
||||
pipeline,
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn render(
|
||||
&mut self,
|
||||
imgui_draw_data: &imgui::DrawData,
|
||||
device: &ash::Device,
|
||||
window_width: u32,
|
||||
window_height: u32,
|
||||
framebuffer: vk::Framebuffer,
|
||||
cmd: vk::CommandBuffer,
|
||||
) {
|
||||
// Update constant buffer
|
||||
{
|
||||
let left = imgui_draw_data.display_pos[0];
|
||||
let right = imgui_draw_data.display_pos[0] + imgui_draw_data.display_size[0];
|
||||
let top = imgui_draw_data.display_pos[1];
|
||||
let bottom = imgui_draw_data.display_pos[1] + imgui_draw_data.display_size[1];
|
||||
|
||||
let cbuffer_data = ImGuiCBuffer {
|
||||
scale: [(2.0 / (right - left)), (2.0 / (bottom - top))],
|
||||
translation: [
|
||||
(right + left) / (left - right),
|
||||
(top + bottom) / (top - bottom),
|
||||
],
|
||||
};
|
||||
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(
|
||||
&cbuffer_data,
|
||||
self.cb_allocation.mapped_ptr().unwrap().cast().as_ptr(),
|
||||
1,
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
let render_pass_begin_info = vk::RenderPassBeginInfo::builder()
|
||||
.render_pass(self.render_pass)
|
||||
.framebuffer(framebuffer)
|
||||
.render_area(vk::Rect2D {
|
||||
offset: vk::Offset2D { x: 0, y: 0 },
|
||||
extent: vk::Extent2D {
|
||||
width: window_width,
|
||||
height: window_height,
|
||||
},
|
||||
})
|
||||
.clear_values(&[vk::ClearValue {
|
||||
color: vk::ClearColorValue {
|
||||
float32: [1.0, 0.5, 1.0, 0.0],
|
||||
},
|
||||
}]);
|
||||
unsafe {
|
||||
device.cmd_begin_render_pass(cmd, &render_pass_begin_info, vk::SubpassContents::INLINE)
|
||||
};
|
||||
|
||||
unsafe { device.cmd_bind_pipeline(cmd, vk::PipelineBindPoint::GRAPHICS, self.pipeline) };
|
||||
|
||||
let viewport = vk::Viewport::builder()
|
||||
.x(0.0)
|
||||
.y(0.0)
|
||||
.width(window_width as f32)
|
||||
.height(window_height as f32);
|
||||
unsafe { device.cmd_set_viewport(cmd, 0, std::slice::from_ref(&viewport)) };
|
||||
{
|
||||
let scissor_rect = vk::Rect2D {
|
||||
offset: vk::Offset2D { x: 0, y: 0 },
|
||||
extent: vk::Extent2D {
|
||||
width: window_width,
|
||||
height: window_height,
|
||||
},
|
||||
};
|
||||
unsafe { device.cmd_set_scissor(cmd, 0, &[scissor_rect]) };
|
||||
}
|
||||
|
||||
unsafe {
|
||||
device.cmd_bind_descriptor_sets(
|
||||
cmd,
|
||||
vk::PipelineBindPoint::GRAPHICS,
|
||||
self.pipeline_layout,
|
||||
0,
|
||||
&self.descriptor_sets,
|
||||
&[],
|
||||
)
|
||||
};
|
||||
|
||||
let (vtx_count, idx_count) =
|
||||
imgui_draw_data
|
||||
.draw_lists()
|
||||
.fold((0, 0), |(vtx_count, idx_count), draw_list| {
|
||||
(
|
||||
vtx_count + draw_list.vtx_buffer().len(),
|
||||
idx_count + draw_list.idx_buffer().len(),
|
||||
)
|
||||
});
|
||||
|
||||
let vtx_size = (vtx_count * std::mem::size_of::<imgui::DrawVert>()) as u64;
|
||||
if vtx_size > self.vb_capacity {
|
||||
// reallocate vertex buffer
|
||||
todo!();
|
||||
}
|
||||
let idx_size = (idx_count * std::mem::size_of::<imgui::DrawIdx>()) as u64;
|
||||
if idx_size > self.ib_capacity {
|
||||
// reallocate index buffer
|
||||
todo!();
|
||||
}
|
||||
|
||||
let mut vb_offset = 0;
|
||||
let mut ib_offset = 0;
|
||||
|
||||
for draw_list in imgui_draw_data.draw_lists() {
|
||||
unsafe {
|
||||
device.cmd_bind_vertex_buffers(
|
||||
cmd,
|
||||
0,
|
||||
&[self.vertex_buffer],
|
||||
&[vb_offset as u64 * std::mem::size_of::<imgui::DrawVert>() as u64],
|
||||
)
|
||||
};
|
||||
unsafe {
|
||||
device.cmd_bind_index_buffer(
|
||||
cmd,
|
||||
self.index_buffer,
|
||||
ib_offset as u64 * std::mem::size_of::<imgui::DrawIdx>() as u64,
|
||||
vk::IndexType::UINT16,
|
||||
)
|
||||
};
|
||||
|
||||
{
|
||||
let vertices = draw_list.vtx_buffer();
|
||||
let dst_ptr = self
|
||||
.vb_allocation
|
||||
.mapped_ptr()
|
||||
.unwrap()
|
||||
.cast::<imgui::DrawVert>()
|
||||
.as_ptr();
|
||||
let dst_ptr = unsafe { dst_ptr.offset(vb_offset) };
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(vertices.as_ptr(), dst_ptr, vertices.len())
|
||||
};
|
||||
vb_offset += vertices.len() as isize;
|
||||
}
|
||||
|
||||
{
|
||||
let indices = draw_list.idx_buffer();
|
||||
let dst_ptr = self
|
||||
.ib_allocation
|
||||
.mapped_ptr()
|
||||
.unwrap()
|
||||
.cast::<imgui::DrawIdx>()
|
||||
.as_ptr();
|
||||
let dst_ptr = unsafe { dst_ptr.offset(ib_offset) };
|
||||
unsafe { std::ptr::copy_nonoverlapping(indices.as_ptr(), dst_ptr, indices.len()) };
|
||||
ib_offset += indices.len() as isize;
|
||||
}
|
||||
|
||||
for command in draw_list.commands() {
|
||||
match command {
|
||||
imgui::DrawCmd::Elements { count, cmd_params } => {
|
||||
let scissor_rect = vk::Rect2D {
|
||||
offset: vk::Offset2D {
|
||||
x: cmd_params.clip_rect[0] as i32,
|
||||
y: cmd_params.clip_rect[1] as i32,
|
||||
},
|
||||
extent: vk::Extent2D {
|
||||
width: (cmd_params.clip_rect[2] - cmd_params.clip_rect[0]) as u32,
|
||||
height: (cmd_params.clip_rect[3] - cmd_params.clip_rect[1]) as u32,
|
||||
},
|
||||
};
|
||||
unsafe { device.cmd_set_scissor(cmd, 0, &[scissor_rect]) };
|
||||
|
||||
unsafe {
|
||||
device.cmd_draw_indexed(
|
||||
cmd,
|
||||
count as u32,
|
||||
1,
|
||||
cmd_params.idx_offset as u32,
|
||||
cmd_params.vtx_offset as i32,
|
||||
0,
|
||||
)
|
||||
};
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { device.cmd_end_render_pass(cmd) };
|
||||
}
|
||||
|
||||
pub(crate) fn destroy(self, device: &ash::Device, allocator: &mut Allocator) {
|
||||
unsafe { device.destroy_buffer(self.constant_buffer, None) };
|
||||
allocator.free(self.cb_allocation).unwrap();
|
||||
|
||||
unsafe { device.destroy_buffer(self.index_buffer, None) };
|
||||
allocator.free(self.ib_allocation).unwrap();
|
||||
|
||||
unsafe { device.destroy_buffer(self.vertex_buffer, None) };
|
||||
allocator.free(self.vb_allocation).unwrap();
|
||||
|
||||
unsafe {
|
||||
device.destroy_sampler(self.sampler, None);
|
||||
}
|
||||
unsafe {
|
||||
device.destroy_image_view(self.font_image_view, None);
|
||||
}
|
||||
unsafe {
|
||||
device.destroy_image(self.font_image, None);
|
||||
}
|
||||
allocator.free(self.font_image_memory).unwrap();
|
||||
|
||||
unsafe { device.destroy_shader_module(self.ps_module, None) };
|
||||
unsafe { device.destroy_shader_module(self.vs_module, None) };
|
||||
|
||||
unsafe { device.destroy_pipeline(self.pipeline, None) };
|
||||
|
||||
unsafe { device.destroy_render_pass(self.render_pass, None) };
|
||||
|
||||
unsafe {
|
||||
device.destroy_pipeline_layout(self.pipeline_layout, None);
|
||||
}
|
||||
|
||||
for &layout in self.descriptor_set_layouts.iter() {
|
||||
unsafe { device.destroy_descriptor_set_layout(layout, None) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_imgui_event(
|
||||
io: &mut imgui::Io,
|
||||
window: &winit::window::Window,
|
||||
event: &winit::event::Event<'_, ()>,
|
||||
) -> bool {
|
||||
use winit::event::{
|
||||
DeviceEvent, ElementState, Event, KeyboardInput, MouseButton, MouseScrollDelta, TouchPhase,
|
||||
VirtualKeyCode, WindowEvent,
|
||||
};
|
||||
|
||||
match event {
|
||||
Event::WindowEvent { event, window_id } if *window_id == window.id() => match *event {
|
||||
WindowEvent::Resized(physical_size) => {
|
||||
io.display_size = [physical_size.width as f32, physical_size.height as f32];
|
||||
false
|
||||
}
|
||||
WindowEvent::KeyboardInput {
|
||||
input:
|
||||
KeyboardInput {
|
||||
virtual_keycode: Some(key),
|
||||
state,
|
||||
..
|
||||
},
|
||||
..
|
||||
} => {
|
||||
let pressed = state == ElementState::Pressed;
|
||||
io.keys_down[key as usize] = pressed;
|
||||
match key {
|
||||
VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = pressed,
|
||||
VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = pressed,
|
||||
VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = pressed,
|
||||
VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = pressed,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
io.want_capture_keyboard
|
||||
}
|
||||
WindowEvent::ReceivedCharacter(ch) => {
|
||||
io.add_input_character(ch);
|
||||
|
||||
io.want_capture_keyboard
|
||||
}
|
||||
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
io.mouse_pos = [position.x as f32, position.y as f32];
|
||||
|
||||
io.want_capture_mouse
|
||||
}
|
||||
WindowEvent::MouseWheel {
|
||||
delta,
|
||||
phase: TouchPhase::Moved,
|
||||
..
|
||||
} => {
|
||||
match delta {
|
||||
MouseScrollDelta::LineDelta(h, v) => {
|
||||
io.mouse_wheel_h = h;
|
||||
io.mouse_wheel = v;
|
||||
}
|
||||
MouseScrollDelta::PixelDelta(pos) => {
|
||||
match pos.x.partial_cmp(&0.0) {
|
||||
Some(std::cmp::Ordering::Greater) => io.mouse_wheel_h += 1.0,
|
||||
Some(std::cmp::Ordering::Less) => io.mouse_wheel_h -= 1.0,
|
||||
_ => (),
|
||||
}
|
||||
match pos.y.partial_cmp(&0.0) {
|
||||
Some(std::cmp::Ordering::Greater) => io.mouse_wheel += 1.0,
|
||||
Some(std::cmp::Ordering::Less) => io.mouse_wheel -= 1.0,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
io.want_capture_mouse
|
||||
}
|
||||
WindowEvent::MouseInput { state, button, .. } => {
|
||||
let pressed = state == ElementState::Pressed;
|
||||
match button {
|
||||
MouseButton::Left => io.mouse_down[0] = pressed,
|
||||
MouseButton::Right => io.mouse_down[1] = pressed,
|
||||
MouseButton::Middle => io.mouse_down[2] = pressed,
|
||||
MouseButton::Other(idx @ 0..=4) => io.mouse_down[idx as usize] = pressed,
|
||||
MouseButton::Other(_) => (),
|
||||
}
|
||||
|
||||
io.want_capture_mouse
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
// Track key release events outside our window. If we don't do this,
|
||||
// we might never see the release event if some other window gets focus.
|
||||
Event::DeviceEvent {
|
||||
event:
|
||||
DeviceEvent::Key(KeyboardInput {
|
||||
state: ElementState::Released,
|
||||
virtual_keycode: Some(key),
|
||||
..
|
||||
}),
|
||||
..
|
||||
} => {
|
||||
io.keys_down[*key as usize] = false;
|
||||
match *key {
|
||||
VirtualKeyCode::LShift | VirtualKeyCode::RShift => io.key_shift = false,
|
||||
VirtualKeyCode::LControl | VirtualKeyCode::RControl => io.key_ctrl = false,
|
||||
VirtualKeyCode::LAlt | VirtualKeyCode::RAlt => io.key_alt = false,
|
||||
VirtualKeyCode::LWin | VirtualKeyCode::RWin => io.key_super = false,
|
||||
_ => (),
|
||||
}
|
||||
|
||||
io.want_capture_keyboard
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue