pmse_render/vulkan/test/
draw_t.rs

1//! vulkan 渲染测试: 绘制三角形
2use std::error::Error;
3use std::sync::Arc;
4
5use log::debug;
6use vulkano::{
7    buffer::{Buffer, BufferContents, BufferCreateInfo, BufferUsage, Subbuffer},
8    command_buffer::{
9        allocator::StandardCommandBufferAllocator, AutoCommandBufferBuilder, CommandBufferUsage,
10        PrimaryAutoCommandBuffer, RenderPassBeginInfo, SubpassBeginInfo, SubpassContents,
11        SubpassEndInfo,
12    },
13    device::{Device, Queue},
14    memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
15    pipeline::{
16        graphics::{
17            color_blend::{ColorBlendAttachmentState, ColorBlendState},
18            input_assembly::InputAssemblyState,
19            multisample::MultisampleState,
20            rasterization::RasterizationState,
21            vertex_input::{Vertex, VertexDefinition},
22            viewport::{Viewport, ViewportState},
23            GraphicsPipelineCreateInfo,
24        },
25        layout::PipelineDescriptorSetLayoutCreateInfo,
26        GraphicsPipeline, PipelineLayout, PipelineShaderStageCreateInfo,
27    },
28    render_pass::{Framebuffer, RenderPass, Subpass},
29    shader::EntryPoint,
30    swapchain::Swapchain,
31};
32
33use super::super::{shader, CreateCommand, PmseRenderHost, PmseRenderSc};
34use crate::E;
35
36/// 要绘制的三角形顶点数据
37#[derive(Debug, Clone)]
38pub struct 三角形 {
39    /// 顶点位置坐标 (x, y, z)
40    位置: [[f32; 3]; 3],
41    /// 顶点颜色 (RGB)
42    颜色: [[f32; 3]; 3],
43}
44
45impl 三角形 {
46    pub fn new(位置: [[f32; 3]; 3], 颜色: [[f32; 3]; 3]) -> Self {
47        Self { 位置, 颜色 }
48    }
49
50    /// 输出顶点
51    pub(self) fn 生成顶点(&self, 输出: &mut Vec<顶点>) {
52        for i in 0..3 {
53            输出.push(顶点 {
54                p: self.位置[i],
55                color: self.颜色[i],
56            });
57        }
58    }
59}
60
61impl Default for 三角形 {
62    /// 默认测试用三角形顶点数据
63    fn default() -> Self {
64        Self {
65            位置: [[0.1, 0.8, 0.0], [-0.8, -0.6, 0.0], [0.9, -0.9, 0.0]],
66            颜色: [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
67        }
68    }
69}
70
71/// 顶点数据结构
72#[derive(Debug, Clone, BufferContents, Vertex)]
73#[repr(C)]
74struct 顶点 {
75    /// 位置坐标 (x, y, z)
76    #[format(R32G32B32_SFLOAT)]
77    pub p: [f32; 3],
78    /// 颜色
79    #[format(R32G32B32_SFLOAT)]
80    pub color: [f32; 3],
81}
82
83/// vulkan 绘制三角形
84#[derive(Debug)]
85pub struct PmseRenderT {
86    h: PmseRenderHost,
87    /// 交换链
88    sc: PmseRenderSc,
89    /// 命令缓冲区 分配器
90    ca: Arc<StandardCommandBufferAllocator>,
91    /// 图形管线
92    管线: Arc<GraphicsPipeline>,
93}
94
95impl PmseRenderT {
96    /// 初始化
97    pub fn new(h: PmseRenderHost, size: (u32, u32)) -> Result<Self, Box<dyn Error>> {
98        // 创建交换链
99        let mut sc = PmseRenderSc::new(&h, size.into())?;
100
101        let (阶段, 顶点入口) = 加载着色器(h.d())?;
102        let (渲染过程, 分过程, 布局) = 创建渲染过程(h.d(), &阶段, sc.sc())?;
103        // 初始化 帧缓冲区
104        sc.init_framebuffer(&渲染过程)?;
105
106        let 视口 = Viewport {
107            offset: [0.0, 0.0],
108            extent: [size.0 as f32, size.1 as f32],
109            depth_range: 0.0..=1.0,
110        };
111        let 管线 = 创建图形管线(h.d(), 顶点入口, 阶段, 视口, 分过程, 布局)?;
112
113        let ca = Arc::new(h.ca());
114        Ok(Self { h, sc, ca, 管线 })
115    }
116
117    /// 绘制三角形
118    pub fn draw(&self, 列表: Vec<三角形>) -> Result<(), Box<dyn Error>> {
119        debug!("vulkan_test T");
120
121        let 顶点数据 = 创建顶点缓冲区(self.h.ma(), 列表)?;
122        let c = 命令生成器::new(
123            self.ca.clone(),
124            self.h.q().clone(),
125            self.管线.clone(),
126            顶点数据,
127        );
128
129        self.sc.execute(&c)?;
130        Ok(())
131    }
132}
133
134struct 命令生成器 {
135    ca: Arc<StandardCommandBufferAllocator>,
136    q: Arc<Queue>,
137    管线: Arc<GraphicsPipeline>,
138    /// 顶点数据
139    顶点缓冲区: Subbuffer<[顶点]>,
140}
141
142impl 命令生成器 {
143    pub fn new(
144        ca: Arc<StandardCommandBufferAllocator>,
145        q: Arc<Queue>,
146        管线: Arc<GraphicsPipeline>,
147        顶点缓冲区: Subbuffer<[顶点]>,
148    ) -> Self {
149        Self {
150            ca,
151            q,
152            管线,
153            顶点缓冲区,
154        }
155    }
156}
157
158impl CreateCommand for 命令生成器 {
159    fn c(&self, fb: &Arc<Framebuffer>) -> Result<Arc<PrimaryAutoCommandBuffer>, Box<dyn Error>> {
160        创建命令缓冲区(&self.ca, &self.q, &self.管线, fb, &self.顶点缓冲区)
161    }
162}
163
164/// 初始化 (加载/编译) 着色器
165fn 加载着色器(
166    设备: &Arc<Device>,
167) -> Result<([PipelineShaderStageCreateInfo; 2], EntryPoint), Box<dyn Error>> {
168    let 顶点着色器 = shader::test_v::load(设备.clone())?;
169    let 片段着色器 = shader::test_f::load(设备.clone())?;
170
171    // 着色器 入口函数
172    let 顶点入口 = 顶点着色器
173        .entry_point("main")
174        .ok_or(E("ERROR vulkan shader vs main".into()))?;
175    let 片段入口 = 片段着色器
176        .entry_point("main")
177        .ok_or(E("ERROR vulkan shader fs main".into()))?;
178
179    let 阶段 = [
180        PipelineShaderStageCreateInfo::new(顶点入口.clone()),
181        PipelineShaderStageCreateInfo::new(片段入口),
182    ];
183
184    Ok((阶段, 顶点入口))
185}
186
187/// 创建渲染过程
188fn 创建渲染过程(
189    设备: &Arc<Device>,
190    阶段: &[PipelineShaderStageCreateInfo; 2],
191    交换链: &Arc<Swapchain>,
192) -> Result<(Arc<RenderPass>, Subpass, Arc<PipelineLayout>), Box<dyn Error>> {
193    let 布局 = PipelineLayout::new(
194        设备.clone(),
195        PipelineDescriptorSetLayoutCreateInfo::from_stages(阶段)
196            .into_pipeline_layout_create_info(设备.clone())?,
197    )?;
198    let 渲染过程 = vulkano::single_pass_renderpass!(
199        设备.clone(),
200        attachments: {
201            color: {
202                format: 交换链.image_format(),
203                samples: 1,
204                load_op: Clear,
205                store_op: Store,
206            }
207        },
208        pass: {
209            color: [color],
210            depth_stencil: {},
211        }
212    )?;
213    let 分过程 = Subpass::from(渲染过程.clone(), 0).unwrap();
214
215    Ok((渲染过程, 分过程, 布局))
216}
217
218/// 创建图形渲染管线
219fn 创建图形管线(
220    设备: &Arc<Device>,
221    顶点入口: EntryPoint,
222    阶段: [PipelineShaderStageCreateInfo; 2],
223    视口: Viewport,
224    分过程: Subpass,
225    布局: Arc<PipelineLayout>,
226) -> Result<Arc<GraphicsPipeline>, Box<dyn Error>> {
227    let 顶点输入状态 = 顶点::per_vertex().definition(&顶点入口.info().input_interface)?;
228    let 管线 = GraphicsPipeline::new(
229        设备.clone(),
230        None,
231        GraphicsPipelineCreateInfo {
232            stages: 阶段.into_iter().collect(),
233            vertex_input_state: Some(顶点输入状态),
234            input_assembly_state: Some(InputAssemblyState::default()),
235            viewport_state: Some(ViewportState {
236                viewports: [视口].into_iter().collect(),
237                ..Default::default()
238            }),
239            rasterization_state: Some(RasterizationState::default()),
240            multisample_state: Some(MultisampleState::default()),
241            color_blend_state: Some(ColorBlendState::with_attachment_states(
242                分过程.num_color_attachments(),
243                ColorBlendAttachmentState::default(),
244            )),
245            subpass: Some(分过程.into()),
246            ..GraphicsPipelineCreateInfo::layout(布局)
247        },
248    )?;
249    Ok(管线)
250}
251
252/// 创建 顶点数据缓冲区 (三角形)
253fn 创建顶点缓冲区(
254    ma: &Arc<StandardMemoryAllocator>,
255    数据: Vec<三角形>,
256) -> Result<Subbuffer<[顶点]>, Box<dyn Error>> {
257    let mut 顶点数据: Vec<顶点> = Vec::new();
258    for i in 数据 {
259        i.生成顶点(&mut 顶点数据);
260    }
261
262    Ok(Buffer::from_iter(
263        ma.clone(),
264        BufferCreateInfo {
265            usage: BufferUsage::VERTEX_BUFFER,
266            ..Default::default()
267        },
268        AllocationCreateInfo {
269            memory_type_filter: MemoryTypeFilter::PREFER_DEVICE
270                | MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
271            ..Default::default()
272        },
273        顶点数据,
274    )?)
275}
276
277/// 创建 命令缓冲区
278fn 创建命令缓冲区(
279    ca: &StandardCommandBufferAllocator,
280    队列: &Arc<Queue>,
281    图形管线: &Arc<GraphicsPipeline>,
282    帧缓冲区: &Arc<Framebuffer>,
283    顶点缓冲区: &Subbuffer<[顶点]>,
284) -> Result<Arc<PrimaryAutoCommandBuffer>, Box<dyn Error>> {
285    let mut b = AutoCommandBufferBuilder::primary(
286        ca,
287        队列.queue_family_index(),
288        CommandBufferUsage::OneTimeSubmit,
289    )?;
290    // 渲染命令
291    b.begin_render_pass(
292        RenderPassBeginInfo {
293            clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())],
294            ..RenderPassBeginInfo::framebuffer(帧缓冲区.clone())
295        },
296        SubpassBeginInfo {
297            contents: SubpassContents::Inline,
298            ..Default::default()
299        },
300    )?
301    .bind_pipeline_graphics(图形管线.clone())?
302    .bind_vertex_buffers(0, 顶点缓冲区.clone())?
303    .draw(顶点缓冲区.len() as u32, 1, 0, 0)?
304    .end_render_pass(SubpassEndInfo::default())?;
305
306    Ok(b.build()?)
307}