Initial commit
This commit is contained in:
commit
f8a1c65b8c
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
1448
Cargo.lock
generated
Normal file
1448
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
Cargo.toml
Normal file
18
Cargo.toml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "yray"
|
||||||
|
version = "0.1.0"
|
||||||
|
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"
|
||||||
|
nalgebra-glm = "0.17.0"
|
||||||
|
simplelog = "^0.12.0"
|
||||||
|
vulkano = "0.29.0"
|
||||||
|
vulkano-shaders = "0.29.0"
|
||||||
|
vulkano-win = "0.29.0"
|
||||||
|
winit = "^0.26.1"
|
56
src/error.rs
Normal file
56
src/error.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
|
use vulkano::{
|
||||||
|
device::{physical::SurfacePropertiesError, DeviceCreationError},
|
||||||
|
image::view::ImageViewCreationError,
|
||||||
|
instance::InstanceCreationError,
|
||||||
|
render_pass::FramebufferCreationError,
|
||||||
|
swapchain::SwapchainCreationError,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum EngineError {
|
||||||
|
NoPhysicalDeviceFound,
|
||||||
|
SwapchainRecreateFailed,
|
||||||
|
VulkanInstanceError(InstanceCreationError),
|
||||||
|
VulkanDeviceError(DeviceCreationError),
|
||||||
|
WindowError(vulkano_win::CreationError),
|
||||||
|
VulkanSwapchainError(SwapchainCreationError),
|
||||||
|
VulkanSurfacePropertiesError(SurfacePropertiesError),
|
||||||
|
VulkanImageViewError(ImageViewCreationError),
|
||||||
|
VulkanFramebufferError(FramebufferCreationError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for EngineError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{:?}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! wrap {
|
||||||
|
($dst:ty, $src:ty, $variant:ident) => {
|
||||||
|
impl From<$src> for $dst {
|
||||||
|
fn from(e: $src) -> Self {
|
||||||
|
Self::$variant(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
wrap!(EngineError, DeviceCreationError, VulkanDeviceError);
|
||||||
|
wrap!(EngineError, InstanceCreationError, VulkanInstanceError);
|
||||||
|
wrap!(EngineError, vulkano_win::CreationError, WindowError);
|
||||||
|
wrap!(
|
||||||
|
EngineError,
|
||||||
|
SurfacePropertiesError,
|
||||||
|
VulkanSurfacePropertiesError
|
||||||
|
);
|
||||||
|
wrap!(EngineError, SwapchainCreationError, VulkanSwapchainError);
|
||||||
|
wrap!(EngineError, ImageViewCreationError, VulkanImageViewError);
|
||||||
|
wrap!(
|
||||||
|
EngineError,
|
||||||
|
FramebufferCreationError,
|
||||||
|
VulkanFramebufferError
|
||||||
|
);
|
||||||
|
|
||||||
|
impl std::error::Error for EngineError {}
|
173
src/main.rs
Normal file
173
src/main.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
extern crate nalgebra_glm as glm;
|
||||||
|
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use bytemuck_derive::{Pod, Zeroable};
|
||||||
|
use glm::TMat4;
|
||||||
|
use render::event::RenderEvent;
|
||||||
|
use vulkano::{
|
||||||
|
buffer::{BufferUsage, CpuAccessibleBuffer, CpuBufferPool},
|
||||||
|
command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents},
|
||||||
|
descriptor_set::{PersistentDescriptorSet, WriteDescriptorSet},
|
||||||
|
pipeline::{
|
||||||
|
graphics::{
|
||||||
|
input_assembly::InputAssemblyState, vertex_input::BuffersDefinition,
|
||||||
|
viewport::ViewportState,
|
||||||
|
},
|
||||||
|
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||||
|
},
|
||||||
|
render_pass::Subpass,
|
||||||
|
sync::GpuFuture,
|
||||||
|
};
|
||||||
|
use winit::{
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
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>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
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 vs = shaders::vs::load(vk.device().clone()).unwrap();
|
||||||
|
let fs = shaders::fs::load(vk.device().clone()).unwrap();
|
||||||
|
|
||||||
|
let uniform_buffer: CpuBufferPool<shaders::vs::ty::MVP_Data> =
|
||||||
|
CpuBufferPool::uniform_buffer(vk.device().clone());
|
||||||
|
|
||||||
|
let pipeline = GraphicsPipeline::start()
|
||||||
|
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
|
||||||
|
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||||
|
.input_assembly_state(InputAssemblyState::new())
|
||||||
|
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||||
|
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||||
|
.render_pass(Subpass::from(vk.render_pass().clone(), 0).unwrap())
|
||||||
|
.build(vk.device().clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let vertex_buffer = CpuAccessibleBuffer::from_iter(
|
||||||
|
vk.device().clone(),
|
||||||
|
BufferUsage::vertex_buffer(),
|
||||||
|
false,
|
||||||
|
[
|
||||||
|
Vertex {
|
||||||
|
position: [-1.0, -1.0, 0.0],
|
||||||
|
color: [1.0, 0.0, 0.0],
|
||||||
|
},
|
||||||
|
Vertex {
|
||||||
|
position: [0.0, 1.0, 0.0],
|
||||||
|
color: [0.0, 1.0, 0.0],
|
||||||
|
},
|
||||||
|
Vertex {
|
||||||
|
position: [1.0, -1.0, 0.0],
|
||||||
|
color: [0.0, 0.0, 1.0],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let rotation_start = Instant::now();
|
||||||
|
|
||||||
|
let viewport = vk.viewport();
|
||||||
|
mvp.projection = glm::perspective(
|
||||||
|
viewport.dimensions[0] / viewport.dimensions[1],
|
||||||
|
45.0,
|
||||||
|
0.01,
|
||||||
|
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()];
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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()
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
.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()
|
||||||
|
});
|
||||||
|
}
|
328
src/render/context.rs
Normal file
328
src/render/context.rs
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use vulkano::{
|
||||||
|
device::{
|
||||||
|
physical::{PhysicalDevice, PhysicalDeviceType, QueueFamily},
|
||||||
|
Device, DeviceCreateInfo, DeviceExtensions, Queue, QueueCreateInfo,
|
||||||
|
},
|
||||||
|
image::{view::ImageView, SwapchainImage},
|
||||||
|
instance::{Instance, InstanceCreateInfo},
|
||||||
|
pipeline::graphics::viewport::Viewport,
|
||||||
|
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass},
|
||||||
|
swapchain::{
|
||||||
|
self, AcquireError, Surface, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo,
|
||||||
|
SwapchainCreationError,
|
||||||
|
},
|
||||||
|
sync::{self, FlushError},
|
||||||
|
sync::{GpuFuture, JoinFuture},
|
||||||
|
Version,
|
||||||
|
};
|
||||||
|
use vulkano_win::VkSurfaceBuild;
|
||||||
|
use winit::{
|
||||||
|
event::{Event, WindowEvent},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::{Window, WindowBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::error::EngineError;
|
||||||
|
|
||||||
|
use super::event::RenderEvent;
|
||||||
|
|
||||||
|
pub struct VulkanContext {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
instance: Arc<Instance>,
|
||||||
|
device: Arc<Device>,
|
||||||
|
queue: Arc<Queue>,
|
||||||
|
|
||||||
|
swapchain: Arc<Swapchain<Window>>,
|
||||||
|
swapchain_images: Vec<Arc<SwapchainImage<Window>>>,
|
||||||
|
render_pass: Arc<RenderPass>,
|
||||||
|
framebuffers: Vec<Arc<Framebuffer>>,
|
||||||
|
|
||||||
|
surface: Arc<Surface<Window>>,
|
||||||
|
viewport: Viewport,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VulkanContext {
|
||||||
|
pub fn new_windowed(
|
||||||
|
event_loop: &EventLoop<()>,
|
||||||
|
window_builder: WindowBuilder,
|
||||||
|
) -> Result<Self, EngineError> {
|
||||||
|
let required_extensions = vulkano_win::required_extensions();
|
||||||
|
let device_extensions = DeviceExtensions {
|
||||||
|
khr_swapchain: true,
|
||||||
|
..DeviceExtensions::none()
|
||||||
|
};
|
||||||
|
|
||||||
|
let instance = Instance::new(InstanceCreateInfo {
|
||||||
|
enabled_extensions: required_extensions,
|
||||||
|
max_api_version: Some(Version::V1_1),
|
||||||
|
..Default::default()
|
||||||
|
})?;
|
||||||
|
let surface = window_builder.build_vk_surface(event_loop, instance.clone())?;
|
||||||
|
|
||||||
|
let (physical, queue_family) =
|
||||||
|
Self::select_physical_device(&instance, surface.clone(), device_extensions)
|
||||||
|
.ok_or(EngineError::NoPhysicalDeviceFound)?;
|
||||||
|
|
||||||
|
let (device, mut queues) = Device::new(
|
||||||
|
physical,
|
||||||
|
DeviceCreateInfo {
|
||||||
|
enabled_extensions: physical.required_extensions().union(&device_extensions),
|
||||||
|
|
||||||
|
queue_create_infos: vec![QueueCreateInfo::family(queue_family)],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let queue = queues.next().unwrap();
|
||||||
|
|
||||||
|
let dim = surface.window().inner_size();
|
||||||
|
let (swapchain, swapchain_images) = {
|
||||||
|
let caps = physical
|
||||||
|
.surface_capabilities(&surface, Default::default())
|
||||||
|
.unwrap();
|
||||||
|
let usage = caps.supported_usage_flags;
|
||||||
|
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
|
||||||
|
let image_format = Some(physical.surface_formats(&surface, Default::default())?[0].0);
|
||||||
|
|
||||||
|
Swapchain::new(
|
||||||
|
device.clone(),
|
||||||
|
surface.clone(),
|
||||||
|
SwapchainCreateInfo {
|
||||||
|
min_image_count: caps.min_image_count,
|
||||||
|
image_format,
|
||||||
|
image_extent: dim.into(),
|
||||||
|
image_usage: usage,
|
||||||
|
composite_alpha: alpha,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let render_pass = vulkano::single_pass_renderpass!(
|
||||||
|
device.clone(),
|
||||||
|
attachments: {
|
||||||
|
color: {
|
||||||
|
load: Clear,
|
||||||
|
store: Store,
|
||||||
|
format: swapchain.image_format(),
|
||||||
|
samples: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pass: {
|
||||||
|
color: [color],
|
||||||
|
depth_stencil: {}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let framebuffers = Self::create_framebuffers(&swapchain_images, render_pass.clone())?;
|
||||||
|
|
||||||
|
let viewport = Viewport {
|
||||||
|
origin: [0.0, 0.0],
|
||||||
|
dimensions: dim.into(),
|
||||||
|
depth_range: 0.0..1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
instance,
|
||||||
|
surface,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
swapchain,
|
||||||
|
swapchain_images,
|
||||||
|
render_pass,
|
||||||
|
framebuffers,
|
||||||
|
viewport,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run<
|
||||||
|
T: GpuFuture + 'static,
|
||||||
|
EventHandler: 'static + FnMut(RenderEvent, &mut ControlFlow),
|
||||||
|
RenderHandler: 'static
|
||||||
|
+ FnMut(
|
||||||
|
&mut VulkanContext,
|
||||||
|
JoinFuture<Box<dyn GpuFuture>, SwapchainAcquireFuture<Window>>,
|
||||||
|
Arc<Framebuffer>,
|
||||||
|
) -> T,
|
||||||
|
>(
|
||||||
|
mut self,
|
||||||
|
event_loop: EventLoop<()>,
|
||||||
|
mut event_handler: EventHandler,
|
||||||
|
mut render_handler: RenderHandler,
|
||||||
|
) -> ! {
|
||||||
|
let mut recreate_swapchain = false;
|
||||||
|
let mut previous_frame_end =
|
||||||
|
Some(Box::new(sync::now(self.device().clone())) as Box<dyn GpuFuture>);
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, ctl| {
|
||||||
|
match event {
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
event_handler(RenderEvent::CloseRequested, ctl);
|
||||||
|
}
|
||||||
|
Event::WindowEvent {
|
||||||
|
event: WindowEvent::Resized(_),
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
}
|
||||||
|
Event::RedrawEventsCleared => {
|
||||||
|
previous_frame_end
|
||||||
|
.as_mut()
|
||||||
|
.take()
|
||||||
|
.unwrap()
|
||||||
|
.cleanup_finished();
|
||||||
|
|
||||||
|
if recreate_swapchain {
|
||||||
|
let size = self.recreate_swapchain().unwrap();
|
||||||
|
event_handler(RenderEvent::ViewportResized(size), ctl);
|
||||||
|
recreate_swapchain = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let (image_num, suboptimal, acquire_future) =
|
||||||
|
match swapchain::acquire_next_image(self.swapchain.clone(), None) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(AcquireError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Err(e) => panic!("Failed to acquire next image: {:?}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
if suboptimal {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let future = previous_frame_end.take().unwrap().join(acquire_future);
|
||||||
|
let framebuffer = self.framebuffers[image_num].clone();
|
||||||
|
let future = render_handler(&mut self, future, framebuffer)
|
||||||
|
.then_swapchain_present(
|
||||||
|
self.queue.clone(),
|
||||||
|
self.swapchain.clone(),
|
||||||
|
image_num,
|
||||||
|
)
|
||||||
|
.then_signal_semaphore_and_flush();
|
||||||
|
|
||||||
|
match future {
|
||||||
|
Ok(future) => {
|
||||||
|
previous_frame_end = Some(Box::new(future) as Box<_>);
|
||||||
|
}
|
||||||
|
Err(FlushError::OutOfDate) => {
|
||||||
|
recreate_swapchain = true;
|
||||||
|
previous_frame_end =
|
||||||
|
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to flush future: {:?}", e);
|
||||||
|
previous_frame_end =
|
||||||
|
Some(Box::new(sync::now(self.device.clone())) as Box<_>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn recreate_swapchain(&mut self) -> Result<(f32, f32), EngineError> {
|
||||||
|
let dim = self.surface.window().inner_size();
|
||||||
|
self.viewport.dimensions = dim.into();
|
||||||
|
|
||||||
|
let (new_swapchain, new_images) = match self.swapchain.recreate(SwapchainCreateInfo {
|
||||||
|
image_extent: dim.into(),
|
||||||
|
..self.swapchain.create_info()
|
||||||
|
}) {
|
||||||
|
Ok(r) => r,
|
||||||
|
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => {
|
||||||
|
return Err(EngineError::SwapchainRecreateFailed);
|
||||||
|
}
|
||||||
|
Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.swapchain = new_swapchain;
|
||||||
|
self.framebuffers = Self::create_framebuffers(&new_images, self.render_pass.clone())?;
|
||||||
|
self.swapchain_images = new_images;
|
||||||
|
|
||||||
|
Ok(dim.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device(&self) -> &Arc<Device> {
|
||||||
|
&self.device
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render_pass(&self) -> &Arc<RenderPass> {
|
||||||
|
&self.render_pass
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn viewport(&self) -> &Viewport {
|
||||||
|
&self.viewport
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swapchain(&self) -> &Arc<Swapchain<Window>> {
|
||||||
|
&self.swapchain
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queue_family(&self) -> QueueFamily {
|
||||||
|
self.queue.family()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn framebuffers(&self) -> &[Arc<Framebuffer>] {
|
||||||
|
&self.framebuffers
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn queue(&self) -> &Arc<Queue> {
|
||||||
|
&self.queue
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select_physical_device(
|
||||||
|
instance: &Arc<Instance>,
|
||||||
|
surface: Arc<Surface<Window>>,
|
||||||
|
device_extensions: DeviceExtensions,
|
||||||
|
) -> Option<(PhysicalDevice, QueueFamily)> {
|
||||||
|
PhysicalDevice::enumerate(instance)
|
||||||
|
.filter(|&p| p.supported_extensions().is_superset_of(&device_extensions))
|
||||||
|
.filter_map(|p| {
|
||||||
|
p.queue_families()
|
||||||
|
.find(|&q| {
|
||||||
|
q.supports_graphics() && q.supports_surface(&surface).unwrap_or(false)
|
||||||
|
})
|
||||||
|
.map(|q| (p, q))
|
||||||
|
})
|
||||||
|
.min_by_key(|(p, _)| match p.properties().device_type {
|
||||||
|
PhysicalDeviceType::DiscreteGpu => 0,
|
||||||
|
PhysicalDeviceType::IntegratedGpu => 1,
|
||||||
|
PhysicalDeviceType::VirtualGpu => 2,
|
||||||
|
PhysicalDeviceType::Cpu => 3,
|
||||||
|
PhysicalDeviceType::Other => 4,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_single_framebuffer(
|
||||||
|
image: Arc<SwapchainImage<Window>>,
|
||||||
|
render_pass: Arc<RenderPass>,
|
||||||
|
) -> Result<Arc<Framebuffer>, EngineError> {
|
||||||
|
let view = ImageView::new_default(image)?;
|
||||||
|
let res = Framebuffer::new(
|
||||||
|
render_pass,
|
||||||
|
FramebufferCreateInfo {
|
||||||
|
attachments: vec![view],
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_framebuffers(
|
||||||
|
images: &[Arc<SwapchainImage<Window>>],
|
||||||
|
render_pass: Arc<RenderPass>,
|
||||||
|
) -> Result<Vec<Arc<Framebuffer>>, EngineError> {
|
||||||
|
images
|
||||||
|
.iter()
|
||||||
|
.map(|image| Self::create_single_framebuffer(image.clone(), render_pass.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
5
src/render/event.rs
Normal file
5
src/render/event.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
pub enum RenderEvent {
|
||||||
|
ViewportResized((f32, f32)),
|
||||||
|
CloseRequested,
|
||||||
|
}
|
3
src/render/mod.rs
Normal file
3
src/render/mod.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub mod context;
|
||||||
|
pub mod shaders;
|
||||||
|
pub mod event;
|
45
src/render/shaders.rs
Normal file
45
src/render/shaders.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#![allow(clippy::needless_question_mark)]
|
||||||
|
|
||||||
|
pub mod vs {
|
||||||
|
vulkano_shaders::shader! {
|
||||||
|
ty: "vertex",
|
||||||
|
src: "
|
||||||
|
#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;
|
||||||
|
mat4 view;
|
||||||
|
mat4 projection;
|
||||||
|
} uniforms;
|
||||||
|
|
||||||
|
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};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Zeroable, Pod)]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod fs {
|
||||||
|
vulkano_shaders::shader! {
|
||||||
|
ty: "fragment",
|
||||||
|
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);
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user