Add frame timer

This commit is contained in:
Mark Poliakov 2022-07-05 21:11:06 +03:00
parent f8a1c65b8c
commit 12731f507c
8 changed files with 218 additions and 101 deletions

7
Cargo.lock generated
View File

@ -11,12 +11,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
[[package]]
name = "approx"
version = "0.5.1"
@ -1435,7 +1429,6 @@ checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
name = "yray"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"bytemuck_derive",
"log",

View File

@ -6,7 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
anyhow = "1.0.58"
bytemuck = "1.10.0"
bytemuck_derive = "1.1.0"
log = "0.4.17"

View File

@ -2,11 +2,11 @@ extern crate nalgebra_glm as glm;
use std::time::Instant;
use bytemuck_derive::{Pod, Zeroable};
use glm::TMat4;
use log::LevelFilter;
use render::event::RenderEvent;
use simplelog::{ColorChoice, CombinedLogger, SharedLogger, TermLogger, TerminalMode};
use vulkano::{
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool},
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool, TypedBufferAccess},
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
pipeline::{
@ -24,35 +24,42 @@ use winit::{
window::WindowBuilder,
};
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
struct Vertex {
position: [f32; 3],
color: [f32; 3],
}
vulkano::impl_vertex!(Vertex, position, color);
pub mod error;
pub mod render;
use crate::render::{context::VulkanContext, shaders};
#[repr(C)]
#[derive(Default, Clone, Copy)]
struct ModelViewProjection {
model: TMat4<f32>,
view: TMat4<f32>,
projection: TMat4<f32>,
}
use crate::render::{
context::VulkanContext,
data::{ModelViewProjection, Vertex},
shaders,
};
fn main() {
let loggers: Vec<Box<dyn SharedLogger>> = vec![TermLogger::new(
LevelFilter::Debug,
simplelog::ConfigBuilder::new().build(),
TerminalMode::Mixed,
ColorChoice::Auto,
)];
let _ = CombinedLogger::init(loggers);
log::info!("yray starting");
let mut mvp = ModelViewProjection {
model: glm::identity(),
..Default::default()
};
let event_loop = EventLoop::new();
let vk = VulkanContext::new_windowed(&event_loop, WindowBuilder::new()).unwrap();
let vk = VulkanContext::new_windowed(
&event_loop,
WindowBuilder::new()
.with_title("yray engine")
.with_resizable(false),
)
.unwrap();
log::info!("Vulkan initialized");
let vs = shaders::vs::load(vk.device().clone()).unwrap();
let fs = shaders::fs::load(vk.device().clone()).unwrap();
@ -75,17 +82,43 @@ fn main() {
BufferUsage::vertex_buffer(),
false,
[
// Front
Vertex {
position: [-1.0, -1.0, 0.0],
color: [1.0, 0.0, 0.0],
position: [-0.5, -0.5, -0.5],
},
Vertex {
position: [0.0, 1.0, 0.0],
color: [0.0, 1.0, 0.0],
position: [ 0.5, -0.5, -0.5],
},
Vertex {
position: [1.0, -1.0, 0.0],
color: [0.0, 0.0, 1.0],
position: [ 0.5, 0.5, -0.5],
},
Vertex {
position: [ 0.5, 0.5, -0.5],
},
Vertex {
position: [-0.5, 0.5, -0.5],
},
Vertex {
position: [-0.5, -0.5, -0.5],
},
// Right
Vertex {
position: [ 0.5, -0.5, -0.5],
},
Vertex {
position: [ 0.5, -0.5, 0.5],
},
Vertex {
position: [ 0.5, 0.5, 0.5],
},
Vertex {
position: [ 0.5, 0.5, 0.5],
},
Vertex {
position: [ 0.5, 0.5, -0.5],
},
Vertex {
position: [ 0.5, -0.5, -0.5],
},
]
.iter()
@ -103,71 +136,75 @@ fn main() {
100.0,
);
vk.run(event_loop, move |event, ctl| match event {
RenderEvent::CloseRequested => {
*ctl = ControlFlow::Exit;
}
RenderEvent::ViewportResized(size) => {
mvp.projection = glm::perspective(
size.0 / size.1,
45.0,
0.01,
100.0,
);
}
}, move |vk, future, framebuffer| {
let clear_values = vec![[0.0, 0.68, 1.0, 1.0].into()];
log::info!("Entering event loop");
let uniform_buffer_subbuffer = {
let elapsed = rotation_start.elapsed().as_secs() as f64
+ rotation_start.elapsed().subsec_nanos() as f64 / 1_000_000_000.0;
vk.run(
event_loop,
move |event, ctl| match event {
RenderEvent::CloseRequested => {
*ctl = ControlFlow::Exit;
}
RenderEvent::ViewportResized(size) => {
log::debug!("Window resized, new size: {}x{}", size.0, size.1);
mvp.projection = glm::perspective(size.0 / size.1, 45.0, 0.01, 100.0);
}
},
move |vk, future, framebuffer| {
let clear_values = vec![[0.0, 0.68, 1.0, 1.0].into()];
mvp.view = glm::look_at(
&glm::vec3(elapsed.cos() as f32 * 5.0, 5.0, elapsed.sin() as f32 * 5.0),
&glm::vec3(0.0, 0.0, 0.0),
&glm::vec3(0.0, 1.0, 0.0),
);
let uniform_buffer_subbuffer = {
let elapsed = rotation_start.elapsed().as_secs() as f64
+ rotation_start.elapsed().subsec_nanos() as f64 / 1_000_000_000.0;
let uniform_data = shaders::vs::ty::MVP_Data {
model: mvp.model.into(),
view: mvp.view.into(),
projection: mvp.projection.into(),
mvp.view = glm::look_at(
&glm::vec3(elapsed.cos() as f32 * 5.0, 5.0, elapsed.sin() as f32 * 5.0),
&glm::vec3(0.0, 0.0, 0.0),
&glm::vec3(0.0, 1.0, 0.0),
);
let uniform_data = shaders::vs::ty::MVP_Data {
model: mvp.model.into(),
view: mvp.view.into(),
projection: mvp.projection.into(),
};
uniform_buffer.next(uniform_data).unwrap()
};
uniform_buffer.next(uniform_data).unwrap()
};
let layout = pipeline.layout().set_layouts().get(0).unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
)
.unwrap();
let mut cmd_buffer_builder = AutoCommandBufferBuilder::primary(vk.device().clone(), vk.queue_family(), CommandBufferUsage::OneTimeSubmit)
.unwrap();
cmd_buffer_builder
.begin_render_pass(
framebuffer,
SubpassContents::Inline,
clear_values,
let layout = pipeline.layout().set_layouts().get(0).unwrap();
let set = PersistentDescriptorSet::new(
layout.clone(),
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
)
.unwrap()
.set_viewport(0, [vk.viewport().clone()])
.bind_pipeline_graphics(pipeline.clone())
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
set,
)
.bind_vertex_buffers(0, vertex_buffer.clone())
.draw(3, 1, 0, 0)
.unwrap()
.end_render_pass()
.unwrap();
let command_buffer = cmd_buffer_builder.build().unwrap();
future.then_execute(vk.queue().clone(), command_buffer).unwrap()
});
let mut cmd_buffer_builder = AutoCommandBufferBuilder::primary(
vk.device().clone(),
vk.queue_family(),
CommandBufferUsage::OneTimeSubmit,
)
.unwrap();
cmd_buffer_builder
.begin_render_pass(framebuffer, SubpassContents::Inline, clear_values)
.unwrap()
.set_viewport(0, [vk.viewport().clone()])
.bind_pipeline_graphics(pipeline.clone())
.bind_descriptor_sets(
PipelineBindPoint::Graphics,
pipeline.layout().clone(),
0,
set,
)
.bind_vertex_buffers(0, vertex_buffer.clone())
.draw(vertex_buffer.len() as u32, 1, 0, 0)
.unwrap()
.end_render_pass()
.unwrap();
let command_buffer = cmd_buffer_builder.build().unwrap();
future
.then_execute(vk.queue().clone(), command_buffer)
.unwrap()
},
);
}

View File

@ -26,7 +26,7 @@ use winit::{
use crate::error::EngineError;
use super::event::RenderEvent;
use super::{event::RenderEvent, FrameTimer};
pub struct VulkanContext {
#[allow(dead_code)]
@ -155,6 +155,7 @@ impl VulkanContext {
let mut recreate_swapchain = false;
let mut previous_frame_end =
Some(Box::new(sync::now(self.device().clone())) as Box<dyn GpuFuture>);
let mut frame_timer = FrameTimer::new();
event_loop.run(move |event, _, ctl| {
match event {
@ -217,11 +218,16 @@ impl VulkanContext {
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
}
Err(e) => {
println!("Failed to flush future: {:?}", e);
log::error!("Failed to flush future: {:?}", e);
previous_frame_end =
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
}
}
frame_timer.frame_done();
if frame_timer.update() {
log::debug!("{} frames/s", frame_timer.fps());
}
}
_ => (),
};

17
src/render/data.rs Normal file
View File

@ -0,0 +1,17 @@
use bytemuck_derive::{Pod, Zeroable};
use glm::TMat4;
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Zeroable, Pod)]
pub struct Vertex {
pub position: [f32; 3],
}
vulkano::impl_vertex!(Vertex, position);
#[repr(C)]
#[derive(Default, Clone, Copy)]
pub struct ModelViewProjection {
pub model: TMat4<f32>,
pub view: TMat4<f32>,
pub projection: TMat4<f32>,
}

View File

@ -1,3 +1,45 @@
use std::time::Instant;
pub mod context;
pub mod shaders;
pub mod event;
pub mod data;
pub struct FrameTimer {
last_time: Instant,
frames_per_second: u64,
counter: u64
}
impl FrameTimer {
pub fn new() -> Self {
Self {
last_time: Instant::now(),
frames_per_second: 0,
counter: 0
}
}
pub fn update(&mut self) -> bool {
let now = Instant::now();
let delta = now - self.last_time;
if delta.as_secs() >= 1 {
self.frames_per_second = self.counter / delta.as_secs();
self.counter = 0;
self.last_time = now;
true
} else {
false
}
}
pub fn frame_done(&mut self) {
self.counter += 1;
}
pub const fn fps(&self) -> u64 {
self.frames_per_second
}
}

View File

@ -7,8 +7,6 @@ pub mod vs {
#version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color;
layout(location = 0) out vec3 out_color;
layout(set = 0, binding = 0) uniform MVP_Data {
mat4 model;
@ -19,7 +17,6 @@ layout(set = 0, binding = 0) uniform MVP_Data {
void main() {
mat4 worldview = uniforms.view * uniforms.model;
gl_Position = uniforms.projection * worldview * vec4(position, 1.0);
out_color = color;
}",
types_meta: {
use bytemuck::{Pod, Zeroable};
@ -35,11 +32,10 @@ pub mod fs {
src: "
#version 450
layout(location = 0) in vec3 in_color;
layout(location = 0) out vec4 f_color;
void main() {
f_color = vec4(in_color, 1.0);
f_color = vec4(1.0, 0.0, 0.0, 1.0);
}"
}
}

27
yray.cap Normal file
View File

@ -0,0 +1,27 @@
{
"rdocCaptureSettings": 1,
"settings": {
"autoStart": false,
"commandLine": "",
"environment": [
],
"executable": "/home/alnyan/build/sandbox/yray/target/debug/yray",
"inject": false,
"numQueuedFrames": 2,
"options": {
"allowFullscreen": true,
"allowVSync": true,
"apiValidation": false,
"captureAllCmdLists": false,
"captureCallstacks": false,
"captureCallstacksOnlyDraws": false,
"debugOutputMute": true,
"delayForDebugger": 0,
"hookIntoChildren": false,
"refAllResources": false,
"verifyBufferAccess": false
},
"queuedFrameCap": 0,
"workingDir": "/home/alnyan/build/sandbox/yray"
}
}