0adf3505ec
This doesn't cause an API break in the C API but we don't actually make an attempt to verify that it's safe to access any of the device contexts.
323 lines
12 KiB
Rust
323 lines
12 KiB
Rust
use crate::hello_triangle::find_memorytype_index;
|
|
|
|
use crate::hello_triangle::swapchain::VulkanSwapchain;
|
|
use crate::hello_triangle::vulkan_base::VulkanBase;
|
|
use ash::prelude::VkResult;
|
|
use ash::util::{read_spv, Align};
|
|
use ash::vk;
|
|
|
|
use std::ffi::CStr;
|
|
use std::io::Cursor;
|
|
use std::mem::align_of;
|
|
const ENTRY_POINT: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"main\0") };
|
|
|
|
#[derive(Default, Clone, Debug, Copy)]
|
|
#[repr(C)]
|
|
#[allow(dead_code)]
|
|
struct Vertex {
|
|
pos: [f32; 4],
|
|
color: [f32; 4],
|
|
}
|
|
|
|
pub struct VulkanPipeline {
|
|
pub graphic_pipeline: vk::Pipeline,
|
|
pub renderpass: vk::RenderPass,
|
|
pub pipeline_layout: vk::PipelineLayout,
|
|
}
|
|
|
|
impl VulkanPipeline {
|
|
pub unsafe fn new(base: &VulkanBase, swapchain: &VulkanSwapchain) -> VkResult<VulkanPipeline> {
|
|
// upload buffers
|
|
let index_buffer_data = [0u32, 1, 2];
|
|
let index_buffer_info = vk::BufferCreateInfo::builder()
|
|
.size(std::mem::size_of_val(&index_buffer_data) as u64)
|
|
.usage(vk::BufferUsageFlags::INDEX_BUFFER)
|
|
.sharing_mode(vk::SharingMode::EXCLUSIVE);
|
|
|
|
let index_buffer = base.device.create_buffer(&index_buffer_info, None).unwrap();
|
|
let index_buffer_memory_req = base.device.get_buffer_memory_requirements(index_buffer);
|
|
let index_buffer_memory_index = find_memorytype_index(
|
|
&index_buffer_memory_req,
|
|
&base.mem_props,
|
|
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
|
|
)
|
|
.expect("Unable to find suitable memorytype for the index buffer.");
|
|
|
|
let index_allocate_info = vk::MemoryAllocateInfo {
|
|
allocation_size: index_buffer_memory_req.size,
|
|
memory_type_index: index_buffer_memory_index,
|
|
..Default::default()
|
|
};
|
|
let index_buffer_memory = base
|
|
.device
|
|
.allocate_memory(&index_allocate_info, None)
|
|
.unwrap();
|
|
let index_ptr = base
|
|
.device
|
|
.map_memory(
|
|
index_buffer_memory,
|
|
0,
|
|
index_buffer_memory_req.size,
|
|
vk::MemoryMapFlags::empty(),
|
|
)
|
|
.unwrap();
|
|
let mut index_slice = Align::new(
|
|
index_ptr,
|
|
align_of::<u32>() as u64,
|
|
index_buffer_memory_req.size,
|
|
);
|
|
index_slice.copy_from_slice(&index_buffer_data);
|
|
base.device.unmap_memory(index_buffer_memory);
|
|
base.device
|
|
.bind_buffer_memory(index_buffer, index_buffer_memory, 0)
|
|
.unwrap();
|
|
|
|
let vertex_input_buffer_info = vk::BufferCreateInfo {
|
|
size: 3 * std::mem::size_of::<Vertex>() as u64,
|
|
usage: vk::BufferUsageFlags::VERTEX_BUFFER,
|
|
sharing_mode: vk::SharingMode::EXCLUSIVE,
|
|
..Default::default()
|
|
};
|
|
|
|
let vertex_input_buffer = base
|
|
.device
|
|
.create_buffer(&vertex_input_buffer_info, None)
|
|
.unwrap();
|
|
|
|
let vertex_input_buffer_memory_req = base
|
|
.device
|
|
.get_buffer_memory_requirements(vertex_input_buffer);
|
|
|
|
let vertex_input_buffer_memory_index = find_memorytype_index(
|
|
&vertex_input_buffer_memory_req,
|
|
&base.mem_props,
|
|
vk::MemoryPropertyFlags::HOST_VISIBLE | vk::MemoryPropertyFlags::HOST_COHERENT,
|
|
)
|
|
.expect("Unable to find suitable memorytype for the vertex buffer.");
|
|
|
|
let vertex_buffer_allocate_info = vk::MemoryAllocateInfo {
|
|
allocation_size: vertex_input_buffer_memory_req.size,
|
|
memory_type_index: vertex_input_buffer_memory_index,
|
|
..Default::default()
|
|
};
|
|
|
|
let vertex_input_buffer_memory = base
|
|
.device
|
|
.allocate_memory(&vertex_buffer_allocate_info, None)
|
|
.unwrap();
|
|
|
|
let vertices = [
|
|
// green
|
|
Vertex {
|
|
pos: [0.5, 0.5, 0.0, 1.0],
|
|
color: [0.0, 1.0, 0.0, 1.0],
|
|
},
|
|
// blue
|
|
Vertex {
|
|
pos: [-0.5, 0.5, 0.0, 1.0],
|
|
color: [0.0, 0.0, 1.0, 1.0],
|
|
},
|
|
Vertex {
|
|
pos: [0.0f32, -0.5, 0.0, 1.0],
|
|
color: [1.0, 0.0, 0.0, 1.0],
|
|
},
|
|
];
|
|
|
|
let vert_ptr = base
|
|
.device
|
|
.map_memory(
|
|
vertex_input_buffer_memory,
|
|
0,
|
|
vertex_input_buffer_memory_req.size,
|
|
vk::MemoryMapFlags::empty(),
|
|
)
|
|
.unwrap();
|
|
|
|
let mut vert_align = Align::new(
|
|
vert_ptr,
|
|
align_of::<Vertex>() as u64,
|
|
vertex_input_buffer_memory_req.size,
|
|
);
|
|
vert_align.copy_from_slice(&vertices);
|
|
base.device.unmap_memory(vertex_input_buffer_memory);
|
|
base.device
|
|
.bind_buffer_memory(vertex_input_buffer, vertex_input_buffer_memory, 0)
|
|
.unwrap();
|
|
|
|
// create pipeline
|
|
let mut vertex_spv_file =
|
|
Cursor::new(&include_bytes!("../../shader/triangle_simple/vert.spv")[..]);
|
|
let vertex_code =
|
|
read_spv(&mut vertex_spv_file).expect("Failed to read vertex shader spv file");
|
|
let vertex_shader_info = ShaderModule::new(&base.device, vertex_code)?;
|
|
let vertex_stage_info = vk::PipelineShaderStageCreateInfo::builder()
|
|
.module(vertex_shader_info.module)
|
|
.stage(vk::ShaderStageFlags::VERTEX)
|
|
.name(ENTRY_POINT);
|
|
|
|
let mut frag_spv_file =
|
|
Cursor::new(&include_bytes!("../../shader/triangle_simple/frag.spv")[..]);
|
|
let frag_code =
|
|
read_spv(&mut frag_spv_file).expect("Failed to read fragment shader spv file");
|
|
let frag_shader_info = ShaderModule::new(&base.device, frag_code)?;
|
|
let frag_stage_info = vk::PipelineShaderStageCreateInfo::builder()
|
|
.module(frag_shader_info.module)
|
|
.stage(vk::ShaderStageFlags::FRAGMENT)
|
|
.name(ENTRY_POINT);
|
|
|
|
let vertex_input_state_info = vk::PipelineVertexInputStateCreateInfo::builder()
|
|
.vertex_attribute_descriptions(&[])
|
|
.vertex_binding_descriptions(&[]);
|
|
|
|
let vertex_input_assembly_state_info = vk::PipelineInputAssemblyStateCreateInfo::builder()
|
|
.primitive_restart_enable(false)
|
|
.topology(vk::PrimitiveTopology::TRIANGLE_LIST);
|
|
|
|
let viewports = [vk::Viewport {
|
|
x: 0.0,
|
|
y: 0.0,
|
|
width: swapchain.extent.width as f32,
|
|
height: swapchain.extent.height as f32,
|
|
min_depth: 0.0,
|
|
max_depth: 1.0,
|
|
}];
|
|
let scissors = [vk::Rect2D {
|
|
offset: Default::default(),
|
|
extent: swapchain.extent,
|
|
}];
|
|
|
|
let layout_create_info = vk::PipelineLayoutCreateInfo::default();
|
|
|
|
let pipeline_layout = base
|
|
.device
|
|
.create_pipeline_layout(&layout_create_info, None)
|
|
.unwrap();
|
|
|
|
let states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR];
|
|
let dynamic_state = vk::PipelineDynamicStateCreateInfo::builder().dynamic_states(&states);
|
|
|
|
let viewport_state_info = vk::PipelineViewportStateCreateInfo::builder()
|
|
.scissors(&scissors)
|
|
.viewports(&viewports);
|
|
|
|
let rs_state_info = vk::PipelineRasterizationStateCreateInfo::builder()
|
|
.depth_clamp_enable(false)
|
|
.depth_bias_enable(false)
|
|
.rasterizer_discard_enable(false)
|
|
.polygon_mode(vk::PolygonMode::FILL)
|
|
.line_width(1.0f32)
|
|
.cull_mode(vk::CullModeFlags::BACK)
|
|
.front_face(vk::FrontFace::CLOCKWISE);
|
|
|
|
let multisample = vk::PipelineMultisampleStateCreateInfo::builder()
|
|
.rasterization_samples(vk::SampleCountFlags::TYPE_1)
|
|
.min_sample_shading(1.0f32)
|
|
.sample_shading_enable(false);
|
|
|
|
let color_blend_attachment = [*vk::PipelineColorBlendAttachmentState::builder()
|
|
.blend_enable(false)
|
|
.color_write_mask(vk::ColorComponentFlags::RGBA)
|
|
.src_color_blend_factor(vk::BlendFactor::ONE)
|
|
.dst_color_blend_factor(vk::BlendFactor::ZERO)
|
|
.color_blend_op(vk::BlendOp::ADD)
|
|
.src_alpha_blend_factor(vk::BlendFactor::ONE)
|
|
.dst_alpha_blend_factor(vk::BlendFactor::ZERO)
|
|
.alpha_blend_op(vk::BlendOp::ADD)];
|
|
|
|
let color_blend_state = vk::PipelineColorBlendStateCreateInfo::builder()
|
|
.logic_op(vk::LogicOp::COPY)
|
|
.attachments(&color_blend_attachment);
|
|
|
|
let renderpass_attachments = [vk::AttachmentDescription {
|
|
format: swapchain.format.format,
|
|
samples: vk::SampleCountFlags::TYPE_1,
|
|
load_op: vk::AttachmentLoadOp::CLEAR,
|
|
store_op: vk::AttachmentStoreOp::STORE,
|
|
initial_layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
|
|
final_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
|
..Default::default()
|
|
}];
|
|
let color_attachment_refs = [vk::AttachmentReference {
|
|
attachment: 0,
|
|
layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
|
|
}];
|
|
|
|
// gonna use an explicit transition instead
|
|
// let dependencies = [
|
|
// vk::SubpassDependency {
|
|
// 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::FRAGMENT_SHADER,
|
|
// ..Default::default()
|
|
// }];
|
|
|
|
let subpass = vk::SubpassDescription::builder()
|
|
.color_attachments(&color_attachment_refs)
|
|
.pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS);
|
|
|
|
let renderpass_create_info = vk::RenderPassCreateInfo::builder()
|
|
.attachments(&renderpass_attachments)
|
|
.subpasses(std::slice::from_ref(&subpass))
|
|
.dependencies(&[]);
|
|
|
|
let renderpass = base
|
|
.device
|
|
.create_render_pass(&renderpass_create_info, None)
|
|
.unwrap();
|
|
|
|
let infos = [*vertex_stage_info, *frag_stage_info];
|
|
let graphic_pipeline_info = vk::GraphicsPipelineCreateInfo::builder()
|
|
.stages(&infos)
|
|
.vertex_input_state(&vertex_input_state_info)
|
|
.input_assembly_state(&vertex_input_assembly_state_info)
|
|
.viewport_state(&viewport_state_info)
|
|
.rasterization_state(&rs_state_info)
|
|
.multisample_state(&multisample)
|
|
.color_blend_state(&color_blend_state)
|
|
.dynamic_state(&dynamic_state)
|
|
.layout(pipeline_layout)
|
|
.render_pass(renderpass);
|
|
let graphic_pipeline_info = [*graphic_pipeline_info];
|
|
|
|
let graphics_pipelines = base
|
|
.device
|
|
.create_graphics_pipelines(vk::PipelineCache::null(), &graphic_pipeline_info, None)
|
|
.expect("Unable to create graphics pipeline");
|
|
|
|
let graphic_pipeline = graphics_pipelines[0];
|
|
|
|
Ok(VulkanPipeline {
|
|
graphic_pipeline,
|
|
renderpass,
|
|
pipeline_layout,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub struct ShaderModule {
|
|
pub module: vk::ShaderModule,
|
|
device: ash::Device,
|
|
}
|
|
|
|
impl ShaderModule {
|
|
pub fn new(device: &ash::Device, spirv: Vec<u32>) -> VkResult<ShaderModule> {
|
|
let create_info = vk::ShaderModuleCreateInfo::builder().code(&spirv);
|
|
|
|
let module = unsafe { device.create_shader_module(&create_info, None)? };
|
|
|
|
Ok(ShaderModule {
|
|
module,
|
|
device: device.clone(),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl Drop for ShaderModule {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
self.device.destroy_shader_module(self.module, None);
|
|
}
|
|
}
|
|
}
|