1
2#![allow(dead_code)]
3#![allow(clippy::too_many_arguments)]
4
5pub mod common;
7
8pub mod init;
10
11pub mod basics;
13
14pub mod device;
16
17pub mod surface;
19
20pub mod renderpass;
22
23pub mod framebuffer;
25
26pub mod rendertarget;
28
29pub mod swapchain;
31
32pub mod cmdpool;
34
35pub mod shader;
37
38pub mod descpool;
40
41pub mod context;
43
44pub mod buffer;
46
47pub mod buffervec;
49
50pub mod texture;
52
53pub mod material;
55
56pub mod mesh;
58
59pub mod descprops;
61
62pub mod pipeline;
64
65pub mod wavefrontobj;
67
68extern crate nalgebra_glm as glm;
69
70pub mod prelude {
72 pub use vkcore_rs::*;
73 pub use glm::*;
74 pub use half::f16;
75 pub use ffi_struct::*;
76 pub use crate::common::*;
77 pub use crate::init::*;
78 pub use crate::basics::*;
79 pub use crate::device::*;
80 pub use crate::surface::*;
81 pub use crate::renderpass::*;
82 pub use crate::framebuffer::*;
83 pub use crate::rendertarget::*;
84 pub use crate::swapchain::*;
85 pub use crate::cmdpool::*;
86 pub use crate::shader::*;
87 pub use crate::descpool::*;
88 pub use crate::context::*;
89 pub use crate::buffer::*;
90 pub use crate::buffervec::*;
91 pub use crate::texture::*;
92 pub use crate::material::*;
93 pub use crate::mesh::*;
94 pub use crate::descprops::*;
95 pub use crate::pipeline::*;
96 pub use crate::wavefrontobj::*;
97 pub use crate::derive_vertex_type;
98 pub use crate::derive_uniform_buffer_type;
99 pub use crate::derive_storage_buffer_type;
100 pub use crate::get_generic_uniform_buffer_cache;
101 pub use crate::get_generic_storage_buffer_cache;
102
103 unsafe extern "C" {
104 fn glfwGetTime() -> f64;
105 fn glfwSetTime(time: f64);
106 }
107
108 pub fn glfw_get_time() -> f64 {
109 unsafe {glfwGetTime()}
110 }
111
112 pub fn glfw_set_time(time: f64) {
113 unsafe {glfwSetTime(time)}
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use glfw::*;
120 use crate::prelude::*;
121 use std::{
122 collections::HashMap,
123 ffi::CStr,
124 path::PathBuf,
125 sync::{
126 Arc,
127 Mutex,
128 RwLock,
129 atomic::{
130 AtomicBool,
131 Ordering,
132 }
133 },
134 thread,
135 time::Duration,
136 };
137
138 const TEST_TIME: f64 = 10.0;
139
140 #[derive(Debug)]
141 pub struct TestInstance {
142 pub ctx: Arc<VulkanContext>,
143 pub window: PWindow,
144 pub events: GlfwReceiver<(f64, WindowEvent)>,
145 pub glfw: Glfw,
146 }
147
148 impl TestInstance {
149 pub fn new(width: u32, height: u32, title: &str, window_mode: glfw::WindowMode, additional_hints: Option<&[WindowHint]>) -> Result<Self, VulkanError> {
150 static GLFW_LOCK: Mutex<u32> = Mutex::new(0);
151 let glfw_lock = GLFW_LOCK.lock().unwrap();
152 let mut glfw = glfw::init(glfw::fail_on_errors).unwrap();
153 glfw.window_hint(WindowHint::ClientApi(ClientApiHint::NoApi));
154 additional_hints.map(|hints| hints.iter().map(|hint| glfw.window_hint(hint.clone())));
155 let (mut window, events) = glfw.create_window(width, height, title, window_mode).expect("Failed to create GLFW window.");
156 drop(glfw_lock);
157 window.set_key_polling(true);
158 let device_requirement = DeviceRequirement {
159 can_graphics: true,
160 can_compute: false,
161 name_subtring: "",
162 };
163 let ctx = Arc::new(create_vulkan_context(&window, device_requirement, PresentInterval::VSync, 1, false)?);
164 for gpu in VulkanGpuInfo::get_gpu_info(&ctx.vkcore)?.iter() {
165 println!("Found GPU: {}", unsafe{CStr::from_ptr(gpu.properties.deviceName.as_ptr())}.to_str().unwrap());
166 }
167 println!("Chosen GPU name: {}", unsafe{CStr::from_ptr(ctx.device.get_gpu().properties.deviceName.as_ptr())}.to_str().unwrap());
168 println!("Chosen GPU type: {:?}", ctx.device.get_gpu().properties.deviceType);
169 Ok(Self {
170 glfw,
171 window,
172 events,
173 ctx,
174 })
175 }
176
177 pub fn get_time(&self) -> f64 {
178 glfw_get_time()
179 }
180
181 pub fn set_time(&self, time: f64) {
182 glfw_set_time(time)
183 }
184
185 pub fn run(&mut self,
186 test_time: Option<f64>,
187 mut on_render: impl FnMut(&VulkanContext, f64) -> Result<(), VulkanError> + Send + 'static
188 ) -> Result<(), VulkanError> {
189 let exit_flag = Arc::new(AtomicBool::new(false));
190 let exit_flag_cloned = exit_flag.clone();
191 let start_time = self.glfw.get_time();
192 let ctx = self.ctx.clone();
193 let renderer_thread = thread::spawn(move || {
194 let mut num_frames = 0;
195 let mut time_in_sec: u64 = 0;
196 let mut num_frames_prev: u64 = 0;
197 while !exit_flag_cloned.load(Ordering::Relaxed) {
198 let cur_frame_time = glfw_get_time();
199 let run_time = cur_frame_time - start_time;
200 on_render(&ctx, run_time).unwrap();
201 num_frames += 1;
202 let new_time_in_sec = run_time.floor() as u64;
203 if new_time_in_sec > time_in_sec {
204 let fps = num_frames - num_frames_prev;
205 println!("FPS: {fps}\tat {new_time_in_sec}s");
206 time_in_sec = new_time_in_sec;
207 num_frames_prev = num_frames;
208 }
209 }
210 });
211 while !self.window.should_close() {
212 let run_time = glfw_get_time() - start_time;
213 thread::sleep(Duration::from_millis(1));
214 self.glfw.poll_events();
215 for (_, event) in glfw::flush_messages(&self.events) {
216 match event {
217 glfw::WindowEvent::Key(Key::Escape, _, Action::Press, _) => {
218 self.window.set_should_close(true);
219 }
220 _ => {}
221 }
222 }
223 if let Some(test_time) = test_time {
224 if run_time >= test_time {
225 self.window.set_should_close(true);
226 }
227 }
228 }
229 exit_flag.store(true, Ordering::Relaxed);
230 renderer_thread.join().unwrap();
231 println!("End of the test");
232 Ok(())
233 }
234 }
235
236 unsafe impl Send for TestInstance {}
237 unsafe impl Sync for TestInstance {}
238
239 #[test]
240 fn device_info() {
241 let additional_hints = [WindowHint::Visible(false)];
242 let inst = Box::new(TestInstance::new(1024, 768, "Vulkan test", glfw::WindowMode::Windowed, Some(&additional_hints)).unwrap());
243 let gpu = inst.ctx.device.get_gpu();
244 for i in 0..gpu.mem_properties.memoryTypeCount {
245 let memtype = &gpu.mem_properties.memoryTypes[i as usize];
246 println!("memory type {i}: {memtype:#?}");
247 }
248 for i in 0..gpu.mem_properties.memoryHeapCount {
249 let heap = &gpu.mem_properties.memoryHeaps[i as usize];
250 println!("heap {i}: {}: {heap:#?}", format_size(heap.size));
251 }
252 }
253
254 #[test]
255 fn basic_test() {
256 derive_vertex_type! {
257 pub struct VertexType {
258 pub position: Vec2,
259 }
260 }
261 derive_uniform_buffer_type! {
262 pub struct UniformInput {
263 resolution: Vec3,
264 time: f32,
265 }
266 }
267 struct Resources {
268 uniform_input: Arc<dyn GenericUniformBuffer>,
269 pipeline: Pipeline,
270 }
271
272 impl Resources {
273 pub fn new(ctx: &VulkanContext) -> Result<Self, VulkanError> {
274 let device = ctx.device.clone();
275 let draw_shaders = Arc::new(DrawShaders::new(
276 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::VertexShader(PathBuf::from("shaders/test.vsh")), false, "main", OptimizationLevel::Performance, false)?),
277 None,
278 None,
279 None,
280 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::FragmentShader(PathBuf::from("shaders/test.fsh")), false, "main", OptimizationLevel::Performance, false)?),
281 ));
282 let uniform_input: Arc<dyn GenericUniformBuffer> = Arc::new(UniformBuffer::<UniformInput>::new(device.clone(), None)?);
283 let desc_props = Arc::new(DescriptorProps::default());
284 desc_props.new_uniform_buffer(0, 0, uniform_input.clone());
285 let pool_in_use = ctx.cmdpools[0].use_pool(None)?;
286 let vertices_data = vec![
287 VertexType {
288 position: Vec2::new(-1.0, 1.0),
289 },
290 VertexType {
291 position: Vec2::new( 1.0, 1.0),
292 },
293 VertexType {
294 position: Vec2::new(-1.0, -1.0),
295 },
296 VertexType {
297 position: Vec2::new( 1.0, -1.0),
298 },
299 ];
300 let vertices = Arc::new(RwLock::new(BufferWithType::new(device.clone(), &vertices_data, pool_in_use.cmdbuf, VkBufferUsageFlagBits::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT as VkBufferUsageFlags)?));
301 let mesh = Arc::new(GenericMeshWithMaterial::new(Arc::new(Mesh::new(VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, buffer_unused(), buffer_unused(), buffer_unused())), "", None));
302 mesh.geometry.flush(pool_in_use.cmdbuf)?;
303 drop(pool_in_use);
304 ctx.cmdpools[0].wait_for_submit(u64::MAX)?;
305 mesh.geometry.discard_staging_buffers();
306 let pipeline = ctx.create_pipeline_builder(mesh, draw_shaders, desc_props)?
307 .set_depth_test(false)
308 .set_depth_write(false)
309 .build()?;
310 Ok(Self {
311 uniform_input,
312 pipeline,
313 })
314 }
315
316 pub fn draw(&self, ctx: &VulkanContext, run_time: f64) -> Result<(), VulkanError> {
317 let scene = ctx.begin_scene(0, None)?;
318 let cmdbuf = scene.get_cmdbuf();
319 let extent = scene.get_rendertarget_extent();
320
321 let ui_data = unsafe {get_generic_uniform_buffer_cache!(self.uniform_input, UniformInput)};
322 *ui_data = UniformInput {
323 resolution: Vec3::new(extent.width as f32, extent.height as f32, 1.0),
324 time: run_time as f32,
325 };
326 self.uniform_input.flush(cmdbuf)?;
327
328 scene.set_viewport_swapchain(0.0, 1.0)?;
329 scene.set_scissor_swapchain()?;
330 scene.begin_renderpass(Vec4::new(0.0, 0.0, 0.2, 1.0), 1.0, 0)?;
331 self.pipeline.draw(cmdbuf)?;
332 scene.end_renderpass()?;
333 scene.finish();
334 Ok(())
335 }
336 }
337
338 let mut inst = Box::new(TestInstance::new(1024, 768, "Vulkan test", glfw::WindowMode::Windowed, None).unwrap());
339 let resources = Resources::new(&inst.ctx).unwrap();
340 inst.run(Some(TEST_TIME),
341 move |ctx: &VulkanContext, run_time: f64| -> Result<(), VulkanError> {
342 resources.draw(ctx, run_time)
343 }).unwrap();
344 }
345
346 #[test]
347 fn avocado() {
348 derive_vertex_type! {
349 pub struct InstanceType {
350 pub transform: Mat4,
351 }
352 }
353 derive_uniform_buffer_type! {
354 pub struct UniformInputScene {
355 view_matrix: Mat4,
356 proj_matrix: Mat4,
357 light_dir: Vec3,
358 light_color: Vec3,
359 ambient_color: Vec3,
360 }
361 }
362 struct Resources {
363 uniform_input_scene: Arc<dyn GenericUniformBuffer>,
364 object: GenericMeshSet<InstanceType>,
365 pipelines: HashMap<String, Pipeline>,
366 }
367
368 impl Resources {
369 const OBJ_ROWS: usize = 4;
370 const OBJ_COLS: usize = 4;
371
372 pub fn new(ctx: &VulkanContext) -> Result<Self, VulkanError> {
373 let device = ctx.device.clone();
374 let draw_shaders = Arc::new(DrawShaders::new(
375 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::VertexShader(PathBuf::from("shaders/objdisp.vsh")), false, "main", OptimizationLevel::Performance, false)?),
376 None,
377 None,
378 None,
379 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::FragmentShader(PathBuf::from("shaders/objdisp.fsh")), false, "main", OptimizationLevel::Performance, false)?),
380 ));
381 let pool_in_use = ctx.cmdpools[0].use_pool(None)?;
382 let object = GenericMeshSet::create_meshset_from_obj_file::<f32, ObjVertPositionTexcoord2DNormalTangent, _>(device.clone(), "assets/testobj/avocado.obj", pool_in_use.cmdbuf, Some(&[InstanceType {transform: Mat4::identity()}; Self::OBJ_ROWS * Self::OBJ_COLS]))?;
383 let uniform_input_scene: Arc<dyn GenericUniformBuffer> = Arc::new(UniformBuffer::<UniformInputScene>::new(device.clone(), None)?);
384 let mut desc_props_set = HashMap::new();
385 let mut pipelines: HashMap<String, Pipeline> = HashMap::with_capacity(object.meshset.len());
386 for (set_name, mesh) in object.meshset.iter() {
387 let desc_props = Arc::new(DescriptorProps::default());
388 desc_props.new_uniform_buffer(0, 0, uniform_input_scene.clone());
389 if let Some(material) = &mesh.material {
390 if let Some(albedo) = material.get_albedo() {
391 if let MaterialComponent::Texture(texture) = albedo {
392 texture.prepare_for_sample(pool_in_use.cmdbuf)?;
393 let texture_input_albedo = TextureForSample {
394 texture: texture.clone(),
395 sampler: Arc::new(VulkanSampler::new_linear(device.clone(), true, false)?),
396 };
397 desc_props.new_texture(0, 1, texture_input_albedo);
398 }
399 }
400 if let Some(normal) = material.get_normal() {
401 if let MaterialComponent::Texture(texture) = normal {
402 texture.prepare_for_sample(pool_in_use.cmdbuf)?;
403 let texture_input_normal = TextureForSample {
404 texture: texture.clone(),
405 sampler: Arc::new(VulkanSampler::new_linear(device.clone(), true, false)?),
406 };
407 desc_props.new_texture(0, 2, texture_input_normal);
408 }
409 }
410 }
411 desc_props_set.insert(set_name, desc_props);
412 }
413 drop(pool_in_use);
414 ctx.cmdpools[0].wait_for_submit(u64::MAX)?;
415 object.discard_staging_buffers();
416 for (set_name, mesh) in object.meshset.iter() {
417 let pipeline = ctx.create_pipeline_builder(mesh.clone(), draw_shaders.clone(), desc_props_set.get(set_name).unwrap().clone())?
418 .set_depth_test(true)
419 .set_depth_write(true)
420 .build()?;
421 pipelines.insert(set_name.clone(), pipeline);
422 }
423 Ok(Self {
424 uniform_input_scene,
425 object,
426 pipelines,
427 })
428 }
429
430 pub fn draw(&self, ctx: &VulkanContext, run_time: f64) -> Result<(), VulkanError> {
431 let scene = ctx.begin_scene(0, None)?;
432 let cmdbuf = scene.get_cmdbuf();
433 let extent = scene.get_rendertarget_extent();
434
435 let view_matrix = {
436 let eye = glm::vec3(25.0, 25.0, 25.0);
437 let center = glm::vec3(0.0, 0.0, 0.0);
438 let up = glm::vec3(0.0, 1.0, 0.0);
439 glm::look_at(&eye, ¢er, &up)
440 };
441
442 let mut proj_matrix = {
443 let fovy = pi::<f32>() / 3.0;
444 let aspect = extent.width as f32 / extent.height as f32;
445 perspective(aspect, fovy, 0.1, 1000.0)
446 };
447 proj_matrix[(1, 1)] *= -1.0;
448
449 let mut lock = self.object.edit_instances().unwrap();
450 for (i, x, y) in (0..Self::OBJ_ROWS).flat_map(|y| (0..Self::OBJ_COLS).map(move |x| (y * Self::OBJ_COLS + x, x, y))) {
451 let x = x as f32 - Self::OBJ_ROWS as f32 * 0.5;
452 let y = y as f32 - Self::OBJ_COLS as f32 * 0.5;
453 lock[i] = InstanceType {
454 transform: glm::rotate(&glm::translate(&Mat4::identity(), &Vec3::new(-x * 8.0, -5.0, -y * 8.0)), run_time as f32 + i as f32, &normalize(&glm::vec3(0.0, 1.0, i as f32))),
455 };
456 }
457 drop(lock);
458
459 scene.set_viewport_swapchain(0.0, 1.0)?;
460 scene.set_scissor_swapchain()?;
461 for pipeline in self.pipelines.values() {
462 let ui_data = unsafe {get_generic_uniform_buffer_cache!(self.uniform_input_scene, UniformInputScene)};
463 ui_data.view_matrix = view_matrix;
464 ui_data.proj_matrix = proj_matrix;
465 ui_data.light_dir = normalize(&Vec3::new(-1.2, -1.0, -1.0));
466 ui_data.light_color = Vec3::new(1.0, 1.0, 1.0);
467 ui_data.ambient_color = Vec3::new(0.1, 0.2, 0.1);
468 self.uniform_input_scene.flush(cmdbuf)?;
469 pipeline.prepare_data(cmdbuf)?;
470 scene.begin_renderpass(Vec4::new(0.0, 0.2, 0.3, 1.0), 1.0, 0)?;
471 pipeline.draw(cmdbuf)?;
472 scene.end_renderpass()?;
473 }
474 scene.finish();
475 Ok(())
476 }
477 }
478
479 let mut inst = Box::new(TestInstance::new(1024, 768, "Vulkan avocado test", glfw::WindowMode::Windowed, None).unwrap());
480 let resources = Resources::new(&inst.ctx).unwrap();
481 inst.run(Some(TEST_TIME),
482 move |ctx: &VulkanContext, run_time: f64| -> Result<(), VulkanError> {
483 resources.draw(ctx, run_time)
484 }).unwrap();
485 }
486
487 #[test]
488 fn pano() {
489 derive_vertex_type! {
490 pub struct VertexType {
491 pub position: Vec2,
492 }
493 }
494 derive_vertex_type! {
495 pub struct InstanceType {
496 pub transform: Mat4,
497 }
498 }
499 derive_uniform_buffer_type! {
500 pub struct UniformInputSky {
501 resolution: Vec2,
502 view_matrix: Mat4,
503 proj_matrix: Mat4,
504 }
505 }
506 derive_uniform_buffer_type! {
507 pub struct UniformInputScene {
508 camera: Vec3,
509 view_matrix: Mat4,
510 proj_matrix: Mat4,
511 }
512 }
513
514 struct Resources {
515 uniform_input_sky: Arc<dyn GenericUniformBuffer>,
516 uniform_input_scene: Arc<dyn GenericUniformBuffer>,
517 pipeline_pano: Pipeline,
518 pipelines_avocado: HashMap<String, Pipeline>,
519 }
520
521 impl Resources {
522 pub fn new(ctx: &VulkanContext) -> Result<Self, VulkanError> {
523 let device = ctx.device.clone();
524 let pano_shaders = Arc::new(DrawShaders::new(
525 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::VertexShader(PathBuf::from("shaders/panosky.vsh")), false, "main", OptimizationLevel::Performance, false)?),
526 None,
527 None,
528 None,
529 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::FragmentShader(PathBuf::from("shaders/panosky.fsh")), false, "main", OptimizationLevel::Performance, false)?),
530 ));
531 let reflection_shaders = Arc::new(DrawShaders::new(
532 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::VertexShader(PathBuf::from("shaders/objdisp_refl.vsh")), false, "main", OptimizationLevel::Performance, false)?),
533 None,
534 None,
535 None,
536 Arc::new(VulkanShader::new_from_source_file_or_cache(device.clone(), ShaderSourcePath::FragmentShader(PathBuf::from("shaders/objdisp_refl.fsh")), false, "main", OptimizationLevel::Performance, false)?),
537 ));
538 let pool_in_use = ctx.cmdpools[0].use_pool(None)?;
539 let vertices_data = vec![
540 VertexType {
541 position: Vec2::new(-1.0, 1.0),
542 },
543 VertexType {
544 position: Vec2::new( 1.0, 1.0),
545 },
546 VertexType {
547 position: Vec2::new(-1.0, -1.0),
548 },
549 VertexType {
550 position: Vec2::new( 1.0, -1.0),
551 },
552 ];
553 let uniform_input_sky: Arc<dyn GenericUniformBuffer> = Arc::new(UniformBuffer::<UniformInputSky>::new(device.clone(), None)?);
554 let uniform_input_scene: Arc<dyn GenericUniformBuffer> = Arc::new(UniformBuffer::<UniformInputScene>::new(device.clone(), None)?);
555 let texture_pano = Arc::new(VulkanTexture::new_from_path(device.clone(), pool_in_use.cmdbuf, "assets/pano.jpg", true, None, VkImageUsageFlagBits::VK_IMAGE_USAGE_SAMPLED_BIT as VkImageUsageFlags)?);
556 let texture_pano_sample = TextureForSample {
557 texture: texture_pano.clone(),
558 sampler: Arc::new(VulkanSampler::new_linear_clamp(device.clone(), false, false)?),
559 };
560 texture_pano.prepare_for_sample(pool_in_use.cmdbuf)?;
561 let pano_shaders_inputs = Arc::new(DescriptorProps::default());
562 pano_shaders_inputs.new_uniform_buffer(0, 0, uniform_input_sky.clone());
563 pano_shaders_inputs.new_texture(0, 1, texture_pano_sample.clone());
564 let vertices = Arc::new(RwLock::new(BufferWithType::new(device.clone(), &vertices_data, pool_in_use.cmdbuf, VkBufferUsageFlagBits::VK_BUFFER_USAGE_VERTEX_BUFFER_BIT as VkBufferUsageFlags)?));
565 let mesh = Arc::new(GenericMeshWithMaterial::new(Arc::new(Mesh::new(VkPrimitiveTopology::VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, buffer_unused(), buffer_unused(), buffer_unused())), "", None));
566 mesh.geometry.flush(pool_in_use.cmdbuf)?;
567 let object = GenericMeshSet::create_meshset_from_obj_file::<f32, ObjVertPositionTexcoord2DNormalTangent, _>(device.clone(), "assets/testobj/avocado.obj", pool_in_use.cmdbuf, Some(&[InstanceType {transform: Mat4::identity()}; 1]))?;
568 let mut avocado_shader_inputs = HashMap::new();
569 let mut pipelines_avocado: HashMap<String, Pipeline> = HashMap::with_capacity(object.meshset.len());
570 for (set_name, mesh) in object.meshset.iter() {
571 let desc_props = Arc::new(DescriptorProps::default());
572 desc_props.new_uniform_buffer(0, 0, uniform_input_scene.clone());
573 desc_props.new_texture(0, 3, texture_pano_sample.clone());
574 if let Some(material) = &mesh.material {
575 if let Some(albedo) = material.get_albedo() {
576 if let MaterialComponent::Texture(texture) = albedo {
577 texture.prepare_for_sample(pool_in_use.cmdbuf)?;
578 let texture_input_albedo = TextureForSample {
579 texture: texture.clone(),
580 sampler: Arc::new(VulkanSampler::new_linear(device.clone(), true, false)?),
581 };
582 desc_props.new_texture(0, 1, texture_input_albedo);
583 }
584 }
585 if let Some(normal) = material.get_normal() {
586 if let MaterialComponent::Texture(texture) = normal {
587 texture.prepare_for_sample(pool_in_use.cmdbuf)?;
588 let texture_input_normal = TextureForSample {
589 texture: texture.clone(),
590 sampler: Arc::new(VulkanSampler::new_linear(device.clone(), true, false)?),
591 };
592 desc_props.new_texture(0, 2, texture_input_normal);
593 }
594 }
595 }
596 avocado_shader_inputs.insert(set_name, desc_props);
597 }
598 drop(pool_in_use);
599 ctx.cmdpools[0].wait_for_submit(u64::MAX)?;
600 mesh.geometry.discard_staging_buffers();
601 texture_pano.discard_staging_buffer();
602 let pipeline_pano = ctx.create_pipeline_builder(mesh, pano_shaders, pano_shaders_inputs)?
603 .set_depth_test(false)
604 .set_depth_write(false)
605 .build()?;
606 for (set_name, mesh) in object.meshset.iter() {
607 let pipeline = ctx.create_pipeline_builder(mesh.clone(), reflection_shaders.clone(), avocado_shader_inputs.get(set_name).unwrap().clone())?
608 .set_depth_test(true)
609 .set_depth_write(true)
610 .build()?;
611 pipelines_avocado.insert(set_name.clone(), pipeline);
612 }
613 Ok(Self {
614 uniform_input_sky,
615 uniform_input_scene,
616 pipeline_pano,
617 pipelines_avocado,
618 })
619 }
620
621 pub fn draw(&self, ctx: &VulkanContext, run_time: f64) -> Result<(), VulkanError> {
622 let scene = ctx.begin_scene(0, None)?;
623 let cmdbuf = scene.get_cmdbuf();
624 let extent = scene.get_rendertarget_extent();
625
626 let h_rotation = run_time * pi::<f64>() * 0.2;
627 let eye = glm::normalize(&glm::vec3(h_rotation.cos() as f32, (run_time * 0.3).sin() as f32, h_rotation.sin() as f32)) * 30.0;
628 let view_matrix = {
629 let center = glm::vec3(0.0, 0.0, 0.0);
630 let up = glm::vec3(0.0, 1.0, 0.0);
631 glm::look_at(&eye, ¢er, &up)
632 };
633
634 let mut proj_matrix = {
635 let fovy = pi::<f32>() / 3.0;
636 let aspect = extent.width as f32 / extent.height as f32;
637 perspective(aspect, fovy, 0.1, 1000.0)
638 };
639 proj_matrix[(1, 1)] *= -1.0;
640
641 let ui_data = unsafe {get_generic_uniform_buffer_cache!(self.uniform_input_sky, UniformInputSky)};
642 ui_data.resolution = Vec2::new(extent.width as f32, extent.height as f32);
643 ui_data.view_matrix = view_matrix;
644 ui_data.proj_matrix = proj_matrix;
645 self.uniform_input_sky.flush(cmdbuf)?;
646
647 let ui_data = unsafe {get_generic_uniform_buffer_cache!(self.uniform_input_scene, UniformInputScene)};
648 ui_data.camera = eye;
649 ui_data.view_matrix = view_matrix;
650 ui_data.proj_matrix = proj_matrix;
651 self.uniform_input_scene.flush(cmdbuf)?;
652 for pipeline_avocado in self.pipelines_avocado.values() {
653 pipeline_avocado.prepare_data(cmdbuf)?;
654 }
655
656 scene.set_viewport_swapchain(0.0, 1.0)?;
657 scene.set_scissor_swapchain()?;
658 scene.begin_renderpass(Vec4::new(0.0, 0.0, 0.2, 1.0), 1.0, 0)?;
659 self.pipeline_pano.draw(cmdbuf)?;
660 for pipeline_avocado in self.pipelines_avocado.values() {
661 pipeline_avocado.draw(cmdbuf)?;
662 }
663 scene.end_renderpass()?;
664 scene.finish();
665 Ok(())
666 }
667 }
668
669 let mut inst = Box::new(TestInstance::new(1024, 768, "Vulkan panorama test", glfw::WindowMode::Windowed, None).unwrap());
670 let resources = Resources::new(&inst.ctx).unwrap();
671 inst.run(Some(TEST_TIME),
672 move |ctx: &VulkanContext, run_time: f64| -> Result<(), VulkanError> {
673 resources.draw(ctx, run_time)
674 }).unwrap();
675 }
676}