Fix and module update

This commit is contained in:
2020-06-25 00:59:10 +02:00
parent ae8b82c84d
commit e755d3b1d8
4 changed files with 235 additions and 293 deletions

View File

@@ -1,42 +1,36 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, AutoCommandBuffer};
use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, Subpass, RenderPassAbstract};
use vulkano::image::{SwapchainImage, AttachmentImage, ImageUsage, ImmutableImage, Dimensions};
use vulkano::instance::{Instance, PhysicalDevice, ApplicationInfo, Version, InstanceExtensions};
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule};
use vulkano::pipeline::viewport::Viewport;
use vulkano::swapchain::{AcquireError, PresentMode, SurfaceTransform, Swapchain, SwapchainCreationError, Surface};
use vulkano::swapchain;
use vulkano::sync::{GpuFuture, FlushError};
use vulkano::sync;
use vulkano::format::{Format, ClearValue};
use vulkano::instance::debug::{DebugCallback, MessageTypes};
use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc};
use vulkano::descriptor::descriptor_set::{FixedSizeDescriptorSetsPool, FixedSizeDescriptorSet, PersistentDescriptorSetBuf, PersistentDescriptorSetImg, PersistentDescriptorSetSampler};
use vulkano::sampler::{Sampler, Filter, MipmapMode, SamplerAddressMode};
use vulkano_win::VkSurfaceBuild;
use winit::{EventsLoop, Window, WindowBuilder, Event, WindowEvent};
use std::sync::{Arc, Mutex};
use std::sync::{Arc};
use std::time::SystemTime;
use std::path::{PathBuf};
use std::ffi::{CStr};
use cgmath::{Matrix4, SquareMatrix};
use image::{ImageBuffer, ImageFormat, Rgb, Rgba};
use image::buffer::ConvertBuffer;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState};
use vulkano::descriptor::descriptor_set::{PersistentDescriptorSet};
use vulkano::descriptor::DescriptorSet;
use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage};
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version};
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType};
use vulkano::memory::pool::{PotentialDedicatedAllocation, StdMemoryPoolAlloc};
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
use vulkano::pipeline::viewport::Viewport;
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError};
use vulkano::swapchain;
use vulkano::sync::{FlushError, GpuFuture};
use vulkano::sync;
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{EventLoop, ControlFlow};
use winit::window::{Window, WindowBuilder};
use shade_runner;
use shade_runner::{CompiledShaders, Entry};
use shaderc;
use vs::ty::PushConstants;
use line_vs::ty::LinePushConstants;
use crate::mesh::{CPUMesh};
use vs::ty::PushConstants;
use image::{ImageFormat, ConvertBuffer, ImageBuffer, Rgb, Rgba};
use crate::mesh::CPUMesh;
const VALIDATION_LAYERS: &[&str] = &[
"VK_LAYER_LUNARG_standard_validation"
@@ -58,7 +52,9 @@ vulkano::impl_vertex!(LinePoint, position);
pub trait Game {
/// Returns true if event should be ignored by the vulkan handler
fn on_window_event(self: &mut Self, event: &Event);
fn on_window_event(self: &mut Self, event: &Event<()>);
fn update(self: &mut Self, renderer: &mut VulkanRenderer) -> vs::ty::UniformBufferObject;
}
pub struct Mesh {
@@ -75,10 +71,6 @@ pub struct GameObject {
pub(crate) type GameObjectHandle = usize;
pub(crate) type MeshHandle = usize;
//type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((), PersistentDescriptorSetBuf<Arc<vulkano::buffer::cpu_access::CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>)>>;
//type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, (((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>)>>;
type FixedGraphicsDescriptorSet = Arc<FixedSizeDescriptorSet<Arc<dyn GraphicsPipelineAbstract + Send + Sync>, ((((), PersistentDescriptorSetBuf<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>), PersistentDescriptorSetImg<Arc<ImmutableImage<Format>>>), PersistentDescriptorSetSampler)>>;
pub struct GameData {
pub start_time: SystemTime,
pub line_vertices: Vec<LinePoint>,
@@ -92,36 +84,30 @@ pub struct GameData {
pub textures: Vec<Arc<ImmutableImage<Format>>>,
}
type Yeet = dyn DescriptorSet + Send + Sync;
pub struct VulkanRenderer {
pub game_data: GameData,
pub device: Arc<Device>,
pub framebuffers: Vec<Arc<FramebufferAbstract + Send + Sync>>,
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pub sampler: Arc<Sampler>,
pub dynamic_state: DynamicState,
pub pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
pub line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync>,
pub pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint], PotentialDedicatedAllocation<StdMemoryPoolAlloc>>>,
pub surface: Arc<Surface<Window>>,
pub swapchain: Arc<Swapchain<Window>>,
pub render_pass: Arc<RenderPassAbstract + Send + Sync>,
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
pub queue: Arc<Queue>,
pub events_loop: EventsLoop,
pub recreate_swapchain: bool,
pub debug_callback: Option<DebugCallback>,
pub previous_frame_end: Option<Box<GpuFuture>>,
pub previous_frame_end: Option<Box<dyn GpuFuture>>,
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::UniformBufferObject>>>,
pub descriptor_sets: Vec<FixedGraphicsDescriptorSet>,
}
pub enum RenderResult {
/// Contains buffer index and swapchain future
Ok,
Reload,
Quit,
pub descriptor_sets: Vec<Arc<Yeet>>,
}
impl VulkanRenderer {
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool) -> VulkanRenderer {
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool) -> (VulkanRenderer, EventLoop<()>) {
let mut data = GameData {
push_constants: PushConstants {
model: Matrix4::identity().into(),
@@ -147,7 +133,7 @@ impl VulkanRenderer {
let instance = {
let extensions = InstanceExtensions {
ext_debug_report: true,
ext_debug_utils: true,
..vulkano_win::required_extensions()
};
@@ -176,20 +162,24 @@ impl VulkanRenderer {
// lifetime of this is important, even tho it isn't used!
let mut debug_callback = None;
if enable_validation_layers {
let msg_types = MessageTypes {
error: true,
let msg_severity = MessageSeverity {
verbose: false,
information: true,
warning: true,
performance_warning: true,
information: false,
debug: true,
error: true
};
debug_callback = DebugCallback::new(&instance, msg_types, |msg| {
let type_str = match (msg.ty.error, msg.ty.warning, msg.ty.performance_warning, msg.ty.information, msg.ty.debug) {
(true, _, _, _, _) => "!!",
(_, true, _, _, _) => "!",
(_, _, true, _, _) => "p",
(_, _, _, true, _) => "i",
let msg_types = MessageType {
general: true,
performance: true,
validation: true
};
debug_callback = DebugCallback::new(&instance, msg_severity, msg_types, |msg| {
let type_str = match (msg.severity.error, msg.severity.warning, msg.severity.information, msg.severity.verbose) {
(true, _, _, _) => "!!",
(_, true, _, _) => "!",
(_, _, _, true) => "i",
_ => " "
};
@@ -202,7 +192,7 @@ impl VulkanRenderer {
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
let events_loop = EventsLoop::new();
let events_loop = EventLoop::new();
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
let window = surface.window();
@@ -222,19 +212,16 @@ impl VulkanRenderer {
let usage = caps.supported_usage_flags;
let alpha = caps.supported_composite_alpha.iter().next().unwrap();
let format = caps.supported_formats[0].0;
data.dimensions = if let Some(dimensions) = window.get_inner_size() {
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
[dimensions.0, dimensions.1]
} else {
panic!("Couldn't get window dimensions!");
};
let inner_size = window.inner_size();
data.dimensions = [inner_size.width, inner_size.height];
Swapchain::new(device.clone(), surface.clone(), caps.min_image_count, format,
data.dimensions, 1, usage, &queue, SurfaceTransform::Identity, alpha,
PresentMode::Fifo, true, None).unwrap()
PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap()
};
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), data.line_vertices.iter().cloned()).unwrap();
// what is host_cached
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
device.clone(),
@@ -264,14 +251,14 @@ impl VulkanRenderer {
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
let pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false).unwrap();
let line_pipeline: Arc<GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), "shaders/line.vert", "shaders/line.frag", true).unwrap();
let pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), false).unwrap();
let line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> =
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), true).unwrap();
let default_tex = {
let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"),
ImageFormat::JPEG).unwrap().to_rgba();
ImageFormat::Jpeg).unwrap().to_rgba();
let image_data = image.into_raw().clone();
let (image_view, future) = ImmutableImage::from_iter(
@@ -288,7 +275,7 @@ impl VulkanRenderer {
// Dynamic viewports allow us to recreate just the viewport when the window is resized
// Otherwise we would have to recreate the whole pipeline.
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None };
let mut dynamic_state = DynamicState { line_width: None, viewports: None, scissors: None, compare_mask: None, write_mask: None, reference: None };
// The render pass we created above only describes the layout of our framebuffers. Before we
// can draw we also need to create the actual framebuffers.
@@ -301,22 +288,21 @@ impl VulkanRenderer {
uniform_buffers.push(CpuAccessibleBuffer::from_data(
device.clone(),
BufferUsage::uniform_buffer_transfer_destination(),
false,
uniform_buffer,
).unwrap());
}
let descriptor_set_pool = Mutex::new(FixedSizeDescriptorSetsPool::new(pipeline.clone(), 0));
let descriptor_sets = uniform_buffers
.iter()
.map(|uniform_buffer| {
Arc::new(
descriptor_set_pool
.lock().unwrap().next()
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
.build().unwrap())
})
.collect();
let descriptor_set_layout = pipeline.descriptor_set_layout(0).unwrap().clone();
let descriptor_sets = uniform_buffers.iter().map(|uniform_buffer| {
let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
let result: Arc<Yeet> = Arc::new(builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(default_tex.clone(), sampler.clone()).unwrap()
.build().unwrap());
result
}).collect();
data.textures.push(default_tex);
@@ -328,38 +314,38 @@ impl VulkanRenderer {
// that, we store the submission of the previous frame here.
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
VulkanRenderer { game_data: data, device, framebuffers, sampler,
(VulkanRenderer { game_data: data, device, framebuffers, sampler,
dynamic_state, pipeline, line_pipeline, uniform_buffers, descriptor_sets,
surface, swapchain, render_pass, queue, line_vertex_buffer, events_loop,
recreate_swapchain: false, debug_callback, previous_frame_end }
surface, swapchain, render_pass, queue, line_vertex_buffer,
recreate_swapchain: false, debug_callback, previous_frame_end }, events_loop)
}
fn create_command_buffer(self: &mut Self, fb_index: usize, ubo: vs::ty::UniformBufferObject) -> Arc<AutoCommandBuffer> {
let mut cbb = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap()
.update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap()
.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap();
builder.update_buffer(self.uniform_buffers[fb_index].clone(), ubo).unwrap();
builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
for i in 0..self.game_data.game_objects.len() {
let game_object = &self.game_data.game_objects[i];
let mesh = &self.game_data.meshes[game_object.mesh_index];
self.game_data.push_constants.model = game_object.model_matrix.into();
cbb = cbb.draw_indexed(
builder.draw_indexed(
self.pipeline.clone(),
&self.dynamic_state,
vec![mesh.vertex_buffer.clone()],
mesh.index_buffer.clone(),
self.descriptor_sets[fb_index].clone(),
self.game_data.push_constants.clone()).unwrap()
self.game_data.push_constants.clone()).unwrap();
}
cbb = cbb.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap()
builder.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap()
.end_render_pass().unwrap();
Arc::new(cbb.build().unwrap())
Arc::new(builder.build().unwrap())
}
/// Returns false if rendering should stop
pub fn render_loop(self: &mut Self, game: &mut dyn Game, new_ubo: vs::ty::UniformBufferObject) -> RenderResult {
pub fn render_loop(self: &mut Self, new_ubo: vs::ty::UniformBufferObject) {
// It is important to call this function from time to time, otherwise resources will keep
// accumulating and you will eventually reach an out of memory error.
// Calling this function polls various fences in order to determine what the GPU has
@@ -368,20 +354,16 @@ impl VulkanRenderer {
if self.recreate_swapchain {
let window = self.surface.window();
self.game_data.dimensions = if let Some(dimensions) = window.get_inner_size() {
let dimensions: (u32, u32) = dimensions.to_physical(window.get_hidpi_factor()).into();
[dimensions.0, dimensions.1]
} else {
panic!("Window no longer exists!");
};
let inner_size = window.inner_size();
self.game_data.dimensions = [inner_size.width, inner_size.height];
let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimension(self.game_data.dimensions) {
let (new_swapchain, new_images) = match self.swapchain.recreate_with_dimensions(self.game_data.dimensions) {
Ok(r) => r,
// This error tends to happen when the user is manually resizing the window.
// Simply restarting the loop is the easiest way to fix this issue.
Err(SwapchainCreationError::UnsupportedDimensions) => {
println!("Swapchain rejected: UnsupportedDimensions");
return RenderResult::Reload;
return;
}
Err(err) => panic!("{:?}", err),
};
@@ -395,7 +377,7 @@ impl VulkanRenderer {
}
if self.game_data.recreate_pipeline {
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), "shaders/triangle.vert", "shaders/triangle.frag", false) {
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), false) {
self.pipeline = pipeline_ok;
println!("Updated pipeline.");
} else {
@@ -411,11 +393,11 @@ impl VulkanRenderer {
//
// This function can block if no image is available. The parameter is an optional timeout
// after which the function call will return an error.
let (fb_index, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) {
let (fb_index, _, acquire_future) = match swapchain::acquire_next_image(self.swapchain.clone(), None) {
Ok(r) => r,
Err(AcquireError::OutOfDate) => {
self.recreate_swapchain = true;
return RenderResult::Reload;
return;
},
Err(err) => panic!("{:?}", err)
};
@@ -451,33 +433,11 @@ impl VulkanRenderer {
self.previous_frame_end = Some(Box::new(sync::now(self.device.clone())) as Box<_>);
}
};
// Note that in more complex programs it is likely that one of `acquire_next_image`,
// `command_buffer::submit`, or `present` will block for some time. This happens when the
// GPU's queue is full and the driver has to wait until the GPU finished some work.
//
// Unfortunately the Vulkan API doesn't provide any way to not wait or to detect when a
// wait would happen. Blocking may be the desired behavior, but if you don't want to
// block you should spawn a separate thread dedicated to submissions.
let mut window_closed = false;
let mut resized = false;
self.events_loop.poll_events(|ev| {
game.on_window_event(&ev);
match ev {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => window_closed = true,
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => resized = true,
_ => {}
}
});
if resized { self.recreate_swapchain = true }
if self.game_data.shutdown || window_closed { return RenderResult::Quit; }
RenderResult::Ok
}
pub fn upload_mesh(self: &mut Self, mesh: CPUMesh) -> usize {
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), mesh.vertices.into_iter()).unwrap();
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), mesh.indices.into_iter()).unwrap();
let vertex_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::vertex_buffer(), false, mesh.vertices.into_iter()).unwrap();
let index_buffer = CpuAccessibleBuffer::from_iter(self.device.clone(), BufferUsage::index_buffer(), false, mesh.indices.into_iter()).unwrap();
self.game_data.meshes.push(Mesh { vertex_buffer, index_buffer });
self.game_data.meshes.len() - 1
}
@@ -504,6 +464,27 @@ impl VulkanRenderer {
}
}
pub fn start_event_loop(mut renderer: VulkanRenderer, mut game: Box<dyn Game>, event_loop: EventLoop<()>) {
let mut recreate_swapchain = false;
let ubo = game.update(&mut renderer);
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
*control_flow = ControlFlow::Exit;
},
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
recreate_swapchain = true;
},
Event::RedrawEventsCleared => {
game.update(&mut renderer);
renderer.render_loop(ubo);
},
_ => {}
}
});
}
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage<Window>>], render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, dynamic_state: &mut DynamicState) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();
@@ -554,93 +535,47 @@ pub mod line_fs {
}
}
fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<RenderPassAbstract + Send + Sync>, vertex_shader_path: &str, fragment_shader_path: &str, is_line: bool) -> Option<Arc<GraphicsPipelineAbstract + Send + Sync>> {
if let Some((shader, shader_data)) = read_shader(vertex_shader_path, fragment_shader_path) {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
fn create_pipeline<V: vulkano::pipeline::vertex::Vertex>(device: Arc<Device>, render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, is_line: bool) -> Option<Arc<dyn GraphicsPipelineAbstract + Send + Sync>> {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline;
let vertex_shader_entry;
let fragment_shader_entry;
let vertex_shader_module;
let fragment_shader_module;
if is_line {
let vertex_shader = line_vs::Shader::load(device.clone()).unwrap();
let fragment_shader = line_fs::Shader::load(device.clone()).unwrap();
unsafe {
vertex_shader_module = ShaderModule::from_words(device.clone(), &shader.vertex).expect("Failed to load vertex shader.");
vertex_shader_entry = vertex_shader_module.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
shader_data.vert_input,
shader_data.vert_output,
shader_data.vert_layout,
GraphicsShaderType::Vertex);
fragment_shader_module = ShaderModule::from_words(device.clone(), &shader.fragment).expect("Failed to load fragment shader.");
fragment_shader_entry = fragment_shader_module.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
shader_data.frag_input,
shader_data.frag_output,
shader_data.frag_layout,
GraphicsShaderType::Fragment);
};
let pipeline;
if is_line {
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader_entry.clone(), ())
.line_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader_entry.clone(), ())
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
} else {
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader_entry.clone(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader_entry.clone(), ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
}
return Some(pipeline);
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader.main_entry_point(), ())
.line_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader.main_entry_point(), ())
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
} else {
return None;
let vertex_shader = vs::Shader::load(device.clone()).unwrap();
let fragment_shader = fs::Shader::load(device.clone()).unwrap();
pipeline = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<V>()
.vertex_shader(vertex_shader.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fragment_shader.main_entry_point(), ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
}
return Some(pipeline);
}
impl GameObject {
pub fn new(mesh: MeshHandle, texture_index: usize) -> GameObject {
GameObject { mesh_index: mesh, texture_index, model_matrix: Matrix4::identity() }
}
}
fn read_shader(vert_path_relative: &str, frag_path_relative: &str) -> Option<(CompiledShaders, Entry)> {
let project_root = std::env::current_dir().expect("failed to get root directory");
let mut vert_path = project_root.clone();
vert_path.push(PathBuf::from(vert_path_relative));
let mut frag_path = project_root.clone();
frag_path.push(PathBuf::from(frag_path_relative));
let shader_result = shade_runner::load(vert_path, frag_path);
match shader_result {
Ok(shader) => {
let shader_data = shade_runner::parse(&shader).expect("Failed to parse");
return Some((shader, shader_data));
}
Err(shade_runner::error::Error::Compile(shade_runner::error::CompileError::Compile(shaderc::Error::CompilationError(line, error)))) => {
println!("Shader line {}: {:?}", line, error);
return None;
}
Err(error) => {
println!("Shader compilation error: {:?}", error);
return None;
}
}
}