Add frame timer
This commit is contained in:
Generated
-7
@@ -11,12 +11,6 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.58"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "approx"
|
name = "approx"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -1435,7 +1429,6 @@ checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
|
|||||||
name = "yray"
|
name = "yray"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
"log",
|
"log",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.58"
|
|
||||||
bytemuck = "1.10.0"
|
bytemuck = "1.10.0"
|
||||||
bytemuck_derive = "1.1.0"
|
bytemuck_derive = "1.1.0"
|
||||||
log = "0.4.17"
|
log = "0.4.17"
|
||||||
|
|||||||
+123
-86
@@ -2,11 +2,11 @@ extern crate nalgebra_glm as glm;
|
|||||||
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use bytemuck_derive::{Pod, Zeroable};
|
use log::LevelFilter;
|
||||||
use glm::TMat4;
|
|
||||||
use render::event::RenderEvent;
|
use render::event::RenderEvent;
|
||||||
|
use simplelog::{ColorChoice, CombinedLogger, SharedLogger, TermLogger, TerminalMode};
|
||||||
use vulkano::{
|
use vulkano::{
|
||||||
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool},
|
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool, TypedBufferAccess},
|
||||||
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
|
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
|
||||||
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
|
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
|
||||||
pipeline::{
|
pipeline::{
|
||||||
@@ -24,35 +24,42 @@ use winit::{
|
|||||||
window::WindowBuilder,
|
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 error;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
|
|
||||||
use crate::render::{context::VulkanContext, shaders};
|
use crate::render::{
|
||||||
|
context::VulkanContext,
|
||||||
#[repr(C)]
|
data::{ModelViewProjection, Vertex},
|
||||||
#[derive(Default, Clone, Copy)]
|
shaders,
|
||||||
struct ModelViewProjection {
|
};
|
||||||
model: TMat4<f32>,
|
|
||||||
view: TMat4<f32>,
|
|
||||||
projection: TMat4<f32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
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 {
|
let mut mvp = ModelViewProjection {
|
||||||
model: glm::identity(),
|
model: glm::identity(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let event_loop = EventLoop::new();
|
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 vs = shaders::vs::load(vk.device().clone()).unwrap();
|
||||||
let fs = shaders::fs::load(vk.device().clone()).unwrap();
|
let fs = shaders::fs::load(vk.device().clone()).unwrap();
|
||||||
@@ -75,17 +82,43 @@ fn main() {
|
|||||||
BufferUsage::vertex_buffer(),
|
BufferUsage::vertex_buffer(),
|
||||||
false,
|
false,
|
||||||
[
|
[
|
||||||
|
// Front
|
||||||
Vertex {
|
Vertex {
|
||||||
position: [-1.0, -1.0, 0.0],
|
position: [-0.5, -0.5, -0.5],
|
||||||
color: [1.0, 0.0, 0.0],
|
|
||||||
},
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
position: [0.0, 1.0, 0.0],
|
position: [ 0.5, -0.5, -0.5],
|
||||||
color: [0.0, 1.0, 0.0],
|
|
||||||
},
|
},
|
||||||
Vertex {
|
Vertex {
|
||||||
position: [1.0, -1.0, 0.0],
|
position: [ 0.5, 0.5, -0.5],
|
||||||
color: [0.0, 0.0, 1.0],
|
},
|
||||||
|
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()
|
.iter()
|
||||||
@@ -103,71 +136,75 @@ fn main() {
|
|||||||
100.0,
|
100.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
vk.run(event_loop, move |event, ctl| match event {
|
log::info!("Entering event loop");
|
||||||
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()];
|
|
||||||
|
|
||||||
let uniform_buffer_subbuffer = {
|
vk.run(
|
||||||
let elapsed = rotation_start.elapsed().as_secs() as f64
|
event_loop,
|
||||||
+ rotation_start.elapsed().subsec_nanos() as f64 / 1_000_000_000.0;
|
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(
|
let uniform_buffer_subbuffer = {
|
||||||
&glm::vec3(elapsed.cos() as f32 * 5.0, 5.0, elapsed.sin() as f32 * 5.0),
|
let elapsed = rotation_start.elapsed().as_secs() as f64
|
||||||
&glm::vec3(0.0, 0.0, 0.0),
|
+ rotation_start.elapsed().subsec_nanos() as f64 / 1_000_000_000.0;
|
||||||
&glm::vec3(0.0, 1.0, 0.0),
|
|
||||||
);
|
|
||||||
|
|
||||||
let uniform_data = shaders::vs::ty::MVP_Data {
|
mvp.view = glm::look_at(
|
||||||
model: mvp.model.into(),
|
&glm::vec3(elapsed.cos() as f32 * 5.0, 5.0, elapsed.sin() as f32 * 5.0),
|
||||||
view: mvp.view.into(),
|
&glm::vec3(0.0, 0.0, 0.0),
|
||||||
projection: mvp.projection.into(),
|
&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(),
|
||||||
let layout = pipeline.layout().set_layouts().get(0).unwrap();
|
[WriteDescriptorSet::buffer(0, uniform_buffer_subbuffer)],
|
||||||
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,
|
|
||||||
)
|
)
|
||||||
.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();
|
.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()
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use winit::{
|
|||||||
|
|
||||||
use crate::error::EngineError;
|
use crate::error::EngineError;
|
||||||
|
|
||||||
use super::event::RenderEvent;
|
use super::{event::RenderEvent, FrameTimer};
|
||||||
|
|
||||||
pub struct VulkanContext {
|
pub struct VulkanContext {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@@ -155,6 +155,7 @@ impl VulkanContext {
|
|||||||
let mut recreate_swapchain = false;
|
let mut recreate_swapchain = false;
|
||||||
let mut previous_frame_end =
|
let mut previous_frame_end =
|
||||||
Some(Box::new(sync::now(self.device().clone())) as Box<dyn GpuFuture>);
|
Some(Box::new(sync::now(self.device().clone())) as Box<dyn GpuFuture>);
|
||||||
|
let mut frame_timer = FrameTimer::new();
|
||||||
|
|
||||||
event_loop.run(move |event, _, ctl| {
|
event_loop.run(move |event, _, ctl| {
|
||||||
match event {
|
match event {
|
||||||
@@ -217,11 +218,16 @@ impl VulkanContext {
|
|||||||
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Failed to flush future: {:?}", e);
|
log::error!("Failed to flush future: {:?}", e);
|
||||||
previous_frame_end =
|
previous_frame_end =
|
||||||
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
}
|
||||||
@@ -1,3 +1,45 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod shaders;
|
pub mod shaders;
|
||||||
pub mod event;
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ pub mod vs {
|
|||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 position;
|
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 {
|
layout(set = 0, binding = 0) uniform MVP_Data {
|
||||||
mat4 model;
|
mat4 model;
|
||||||
@@ -19,7 +17,6 @@ layout(set = 0, binding = 0) uniform MVP_Data {
|
|||||||
void main() {
|
void main() {
|
||||||
mat4 worldview = uniforms.view * uniforms.model;
|
mat4 worldview = uniforms.view * uniforms.model;
|
||||||
gl_Position = uniforms.projection * worldview * vec4(position, 1.0);
|
gl_Position = uniforms.projection * worldview * vec4(position, 1.0);
|
||||||
out_color = color;
|
|
||||||
}",
|
}",
|
||||||
types_meta: {
|
types_meta: {
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
@@ -35,11 +32,10 @@ pub mod fs {
|
|||||||
src: "
|
src: "
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 in_color;
|
|
||||||
layout(location = 0) out vec4 f_color;
|
layout(location = 0) out vec4 f_color;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
f_color = vec4(in_color, 1.0);
|
f_color = vec4(1.0, 0.0, 0.0, 1.0);
|
||||||
}"
|
}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user