use std::error::Error;
use std::sync::Arc;
use vulkano::{
buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer},
command_buffer::{
allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
PrimaryAutoCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo, SubpassContents,
SubpassEndInfo,
},
device::{Device, Queue},
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
pipeline::{
graphics::{
color_blend::{ColorBlendAttachmentState, ColorBlendState},
input_assembly::InputAssemblyState,
multisample::MultisampleState,
rasterization::RasterizationState,
vertex_input::{Vertex, VertexDefinition},
viewport::{Viewport, ViewportState},
GraphicsPipelineCreateInfo,
},
layout::PipelineDescriptorSetLayoutCreateInfo,
GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo,
},
render_pass::{Framebuffer, RenderPass, Subpass},
shader::EntryPoint,
swapchain::Swapchain,
};
use crate::shader;
use crate::util::{交换链执行, 创建命令缓冲分配器};
use crate::E;
use crate::{PmseRenderHost, PmseRenderSc};
#[derive(Debug, Clone, BufferContents, Vertex)]
#[repr(C)]
pub struct 顶点 {
#[format(R32G32B32_SFLOAT)]
p: [f32; 3],
#[format(R32G32B32_SFLOAT)]
color: [f32; 3],
}
impl 顶点 {
pub fn new(p: [f32; 3], color: [f32; 3]) -> Self {
Self { p, color }
}
}
pub struct PmseRenderTest {
h: PmseRenderHost,
sc: PmseRenderSc,
命令: Vec<Arc<PrimaryAutoCommandBuffer>>,
}
impl PmseRenderTest {
pub fn new(h: PmseRenderHost, size: (u32, u32)) -> Result<Self, Box<dyn Error>> {
let mut sc = PmseRenderSc::new(&h, size.into())?;
let (阶段, 顶点入口) = 加载着色器(h.d())?;
let (渲染过程, 分过程, 布局) = 创建渲染过程(h.d(), &阶段, sc.sc())?;
sc.init_framebuffer(&渲染过程)?;
let 视口 = Viewport {
offset: [0.0, 0.0],
extent: [size.0 as f32, size.1 as f32],
depth_range: 0.0..=1.0,
};
let 管线 = 创建图形管线(h.d(), 顶点入口, 阶段, 视口, 分过程, 布局)?;
let ca = 创建命令缓冲分配器(h.d());
let 顶点数据 = 创建顶点缓冲区(h.ma())?;
let mut 命令: Vec<Arc<PrimaryAutoCommandBuffer>> = Vec::new();
for i in sc.framebuffer() {
命令.push(创建命令缓冲区(&ca, h.q(), &管线, i, &顶点数据)?);
}
Ok(Self { h, sc, 命令 })
}
pub fn draw(&self) -> Result<(), Box<dyn Error>> {
println!("vulkan_test");
交换链执行(self.h.d(), self.h.q(), &self.命令, self.sc.sc())?;
Ok(())
}
}
fn 加载着色器(
设备: &Arc<Device>,
) -> Result<([PipelineShaderStageCreateInfo; 2], EntryPoint), Box<dyn Error>> {
let 顶点着色器 = shader::test_v::load(设备.clone())?;
let 片段着色器 = shader::test_f::load(设备.clone())?;
let 顶点入口 = 顶点着色器
.entry_point("main")
.ok_or(E("ERROR vulkan shader vs main".into()))?;
let 片段入口 = 片段着色器
.entry_point("main")
.ok_or(E("ERROR vulkan shader fs main".into()))?;
let 阶段 = [
PipelineShaderStageCreateInfo::new(顶点入口.clone()),
PipelineShaderStageCreateInfo::new(片段入口),
];
Ok((阶段, 顶点入口))
}
fn 创建渲染过程(
设备: &Arc<Device>,
阶段: &[PipelineShaderStageCreateInfo; 2],
交换链: &Arc<Swapchain>,
) -> Result<(Arc<RenderPass>, Subpass, Arc<PipelineLayout>), Box<dyn Error>> {
let 布局 = PipelineLayout::new(
设备.clone(),
PipelineDescriptorSetLayoutCreateInfo::from_stages(阶段)
.into_pipeline_layout_create_info(设备.clone())?,
)?;
let 渲染过程 = vulkano::single_pass_renderpass!(
设备.clone(),
attachments: {
color: {
format: 交换链.image_format(),
samples: 1,
load_op: Clear,
store_op: Store,
}
},
pass: {
color: [color],
depth_stencil: {},
}
)?;
let 分过程 = Subpass::from(渲染过程.clone(), 0).unwrap();
Ok((渲染过程, 分过程, 布局))
}
fn 创建图形管线(
设备: &Arc<Device>,
顶点入口: EntryPoint,
阶段: [PipelineShaderStageCreateInfo; 2],
视口: Viewport,
分过程: Subpass,
布局: Arc<PipelineLayout>,
) -> Result<Arc<GraphicsPipeline>, Box<dyn Error>> {
let 顶点输入状态 = 顶点::per_vertex().definition(&顶点入口.info().input_interface)?;
let 管线 = GraphicsPipeline::new(
设备.clone(),
None,
GraphicsPipelineCreateInfo {
stages: 阶段.into_iter().collect(),
vertex_input_state: Some(顶点输入状态),
input_assembly_state: Some(InputAssemblyState::default()),
viewport_state: Some(ViewportState {
viewports: [视口].into_iter().collect(),
..Default::default()
}),
rasterization_state: Some(RasterizationState::default()),
multisample_state: Some(MultisampleState::default()),
color_blend_state: Some(ColorBlendState::with_attachment_states(
分过程.num_color_attachments(),
ColorBlendAttachmentState::default(),
)),
subpass: Some(分过程.into()),
..GraphicsPipelineCreateInfo::layout(布局)
},
)?;
Ok(管线)
}
fn 创建顶点缓冲区(
ma: &Arc<StandardMemoryAllocator>,
) -> Result<Subbuffer<[顶点]>, Box<dyn Error>> {
Ok(Buffer::from_iter(
ma.clone(),
BufferCreateInfo {
usage: BufferUsage::VERTEX_BUFFER,
..Default::default()
},
AllocationCreateInfo {
memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
..Default::default()
},
vec![
顶点::new([0.1, 0.8, 0.0], [1.0, 0.0, 0.0]),
顶点::new([-0.8, -0.6, 0.0], [0.0, 1.0, 0.0]),
顶点::new([0.9, -0.9, 0.0], [0.0, 0.0, 1.0]),
],
)?)
}
fn 创建命令缓冲区(
ca: &StandardCommandBufferAllocator,
队列: &Arc<Queue>,
图形管线: &Arc<GraphicsPipeline>,
帧缓冲区: &Arc<Framebuffer>,
顶点缓冲区: &Subbuffer<[顶点]>,
) -> Result<Arc<PrimaryAutoCommandBuffer>, Box<dyn Error>> {
let mut b = AutoCommandBufferBuilder::primary(
ca,
队列.queue_family_index(),
CommandBufferUsage::MultipleSubmit,
)?;
b.begin_render_pass(
RenderPassBeginInfo {
clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
..RenderPassBeginInfo::framebuffer(帧缓冲区.clone())
},
SubpassBeginInfo {
contents: SubpassContents::Inline,
..Default::default()
},
)?
.bind_pipeline_graphics(图形管线.clone())?
.bind_vertex_buffers(0, 顶点缓冲区.clone())?
.draw(顶点缓冲区.len() as u32, 1, 0, 0)?
.end_render_pass(SubpassEndInfo::default())?;
Ok(b.build()?)
}