Allow for more pipelines

This commit is contained in:
2020-11-27 08:35:27 +01:00
parent 9b6a81ae93
commit 483645dcc5
3 changed files with 232 additions and 151 deletions

View File

@@ -6,7 +6,7 @@ use crate::gameobject::{GameObject, GameObjectHandle, Updatable};
use crate::input::InputState; use crate::input::InputState;
use crate::player::Player; use crate::player::Player;
use crate::vulkan::{Game, LinePoint, MeshHandle, VulkanRenderer}; use crate::vulkan::{Game, LinePoint, MeshHandle, VulkanRenderer};
use crate::vulkan::vs::ty::ObjectUniformData; use crate::pipelines::vs::ty::ObjectUniformData;
mod vulkan; mod vulkan;
mod input; mod input;
@@ -14,6 +14,7 @@ mod config;
mod mesh; mod mesh;
mod gameobject; mod gameobject;
mod player; mod player;
mod pipelines;
struct TestGame { struct TestGame {
input: InputState, input: InputState,
@@ -159,7 +160,7 @@ impl TestGame {
fn add_game_object(&mut self, renderer: &mut VulkanRenderer, mesh: MeshHandle) -> &mut GameObjectHandle { fn add_game_object(&mut self, renderer: &mut VulkanRenderer, mesh: MeshHandle) -> &mut GameObjectHandle {
let obj = GameObject::new(mesh); let obj = GameObject::new(mesh);
let obj_handle = renderer.add_game_object(obj); let obj_handle = renderer.add_game_object(obj, 0);
self.game_objects.push(obj_handle); self.game_objects.push(obj_handle);
self.game_objects.last_mut().unwrap() self.game_objects.last_mut().unwrap()
} }

182
src/pipelines.rs Normal file
View File

@@ -0,0 +1,182 @@
use vulkano::command_buffer::DynamicState;
use crate::vulkan::GameData;
use crate::vulkan::{LinePoint, Vertex};
use crate::GameObject;
use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::descriptor_set::PersistentDescriptorSet};
use crate::VulkanRenderer;
use vulkano::pipeline::{GraphicsPipeline};
use vulkano::framebuffer::Subpass;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::framebuffer::RenderPassAbstract;
use std::sync::Arc;
use vulkano::device::Device;
type RP = Arc<dyn RenderPassAbstract + Send + Sync>;
type GP = Arc<dyn GraphicsPipelineAbstract + Send + Sync>;
pub trait Drawcall {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState);
fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer);
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP);
fn get_pipeline(self: &Self) -> &GP;
}
pub mod vs {
vulkano_shaders::shader!{
ty: "vertex",
path: "shaders/triangle.vert"
}
}
pub mod fs {
vulkano_shaders::shader! {
ty: "fragment",
path: "shaders/triangle.frag"
}
}
#[derive(Clone)]
pub struct DefaultShader {
pipeline: GP,
}
impl DefaultShader {
pub fn new(device: Arc<Device>, render_pass: RP) -> Self {
DefaultShader {
pipeline: Self::create_pipeline(device, render_pass)
}
}
fn create_pipeline(device: Arc<Device>, render_pass: RP) -> GP {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
let vertex_shader = vs::Shader::load(device.clone()).unwrap();
let fragment_shader = fs::Shader::load(device.clone()).unwrap();
Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.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())
}
}
impl Drawcall for DefaultShader {
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP) {
self.pipeline = Self::create_pipeline(device, render_pass);
}
fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) {
let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone();
println!("Diff: {:?}, Norm: {:?}", game_object.texture_index, game_object.normal_map_index);
game_object.descriptor_sets = renderer.uniform_buffers.iter().map(|uniform_buffer| {
let descriptor_set: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>;
let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
descriptor_set = Arc::new(builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(renderer.game_data.textures[game_object.texture_index].clone(), renderer.sampler.clone()).unwrap()
.add_sampled_image(renderer.game_data.textures[game_object.normal_map_index].clone(), renderer.sampler.clone()).unwrap()
.build().unwrap());
descriptor_set
}).collect();
}
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) {
for i in 0..game_data.game_objects.len() {
let game_object = &game_data.game_objects[i];
let mesh = &game_data.meshes[game_object.mesh_index];
let mut push_constants = game_data.push_constants.clone();
push_constants.model = game_object.get_model_matrix().into();
builder.draw_indexed(
self.pipeline.clone(),
dynamic_state,
vec![mesh.vertex_buffer.clone()],
mesh.index_buffer.clone(),
game_object.descriptor_sets[fb_index].clone(),
push_constants).unwrap();
}
}
fn get_pipeline(self: &Self) -> &GP {
&self.pipeline
}
}
pub mod line_vs {
vulkano_shaders::shader!{
ty: "vertex",
path: "shaders/line.vert"
}
}
pub mod line_fs {
vulkano_shaders::shader! {
ty: "fragment",
path: "shaders/line.frag"
}
}
#[derive(Clone)]
pub struct LineShader {
pipeline: GP,
vertex_buffer: Arc<vulkano::buffer::CpuAccessibleBuffer<[LinePoint]>>
}
impl LineShader {
pub fn new(device: Arc<Device>, render_pass: RP, vertex_buffer: Arc<vulkano::buffer::CpuAccessibleBuffer<[LinePoint]>>) -> Self {
LineShader {
pipeline: Self::create_pipeline(device, render_pass),
vertex_buffer
}
}
fn create_pipeline(device: Arc<Device>, render_pass: RP) -> GP {
let sub_pass = Subpass::from(render_pass.clone(), 0).unwrap();
let vertex_shader = line_vs::Shader::load(device.clone()).unwrap();
let fragment_shader = line_fs::Shader::load(device.clone()).unwrap();
Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<LinePoint>()
.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())
}
}
impl Drawcall for LineShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, _fb_index: usize, game_data: &GameData, dynamic_state: &DynamicState) {
builder.draw(self.pipeline.clone(),
&dynamic_state,
vec![self.vertex_buffer.clone()],
(),
game_data.line_push_constants.clone()).unwrap();
}
fn create_descriptor_set(self: &Self, game_object: &mut GameObject, renderer: &VulkanRenderer) {
}
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP) {
self.pipeline = Self::create_pipeline(device, render_pass);
}
fn get_pipeline(self: &Self) -> &GP {
&self.pipeline
}
}

View File

@@ -1,3 +1,5 @@
use crate::pipelines::{Drawcall, LineShader};
use crate::pipelines::DefaultShader;
use std::sync::Arc; use std::sync::Arc;
use std::time::SystemTime; use std::time::SystemTime;
@@ -6,16 +8,13 @@ use image::{ImageBuffer, ImageFormat, Rgb, Rgba};
use image::buffer::ConvertBuffer; use image::buffer::ConvertBuffer;
use vulkano::{command_buffer::CommandBuffer, buffer::{BufferUsage, CpuAccessibleBuffer}, image::{ImageLayout, MipmapsCount}}; use vulkano::{command_buffer::CommandBuffer, buffer::{BufferUsage, CpuAccessibleBuffer}, image::{ImageLayout, MipmapsCount}};
use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState}; use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState};
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::DescriptorSet; use vulkano::descriptor::DescriptorSet;
use vulkano::device::{Device, DeviceExtensions, Queue}; use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::format::{ClearValue, Format}; use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass}; use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract};
use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage, ImageViewAccess}; use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage, ImageViewAccess};
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version}; use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version};
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType}; 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::pipeline::viewport::Viewport;
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode}; use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError}; use vulkano::swapchain::{AcquireError, ColorSpace, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError};
@@ -27,10 +26,11 @@ use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop}; use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder}; use winit::window::{Window, WindowBuilder};
use line_vs::ty::LinePushConstants; use crate::pipelines::{line_vs::ty::LinePushConstants};
use vs::ty::PushConstants; use crate::pipelines::vs::ty::PushConstants;
use crate::gameobject::{GameObject, GameObjectHandle}; use crate::pipelines::vs;
use crate::{gameobject::{GameObject, GameObjectHandle}};
use crate::mesh::CPUMesh; use crate::mesh::CPUMesh;
use crate::config::RenderConfig; use crate::config::RenderConfig;
@@ -63,8 +63,8 @@ pub trait Game {
} }
pub struct Mesh { pub struct Mesh {
vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>, pub vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>,
index_buffer: Arc<CpuAccessibleBuffer<[u32]>>, pub index_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -98,9 +98,7 @@ pub struct VulkanRenderer {
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>, pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pub sampler: Arc<Sampler>, pub sampler: Arc<Sampler>,
pub dynamic_state: DynamicState, pub dynamic_state: DynamicState,
pub pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>, pub pipelines: Vec<Box<dyn Drawcall>>,
pub line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
pub line_vertex_buffer: Arc<CpuAccessibleBuffer<[LinePoint], PotentialDedicatedAllocation<StdMemoryPoolAlloc>>>,
pub surface: Arc<Surface<Window>>, pub surface: Arc<Surface<Window>>,
pub swapchain: Arc<Swapchain<Window>>, pub swapchain: Arc<Swapchain<Window>>,
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>, pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
@@ -233,9 +231,6 @@ impl VulkanRenderer {
PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap() PresentMode::Fifo, FullscreenExclusive::Default, true, ColorSpace::SrgbNonLinear).unwrap()
}; };
// what is host_cached
let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
// Render pass // Render pass
let render_pass = Arc::new(vulkano::single_pass_renderpass!( let render_pass = Arc::new(vulkano::single_pass_renderpass!(
device.clone(), device.clone(),
@@ -272,10 +267,12 @@ impl VulkanRenderer {
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat, MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(); SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap();
let pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> = let line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
create_pipeline::<Vertex>(device.clone(), render_pass.clone(), false).unwrap();
let line_pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync> = let pipelines: Vec<Box<dyn Drawcall>> = vec![
create_pipeline::<LinePoint>(device.clone(), render_pass.clone(), true).unwrap(); Box::new(DefaultShader::new(device.clone(), render_pass.clone())),
Box::new(LineShader::new(device.clone(), render_pass.clone(), line_vertex_buffer)),
];
let default_tex = { let default_tex = {
let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"), let image = image::load_from_memory_with_format(include_bytes!("../models/missing-texture.jpg"),
@@ -337,8 +334,8 @@ impl VulkanRenderer {
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>); 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, dynamic_state, pipelines, uniform_buffers,
surface, swapchain, render_pass, queue, line_vertex_buffer, surface, swapchain, render_pass, queue,
recreate_swapchain: false, debug_callback, previous_frame_end, recreate_swapchain: false, debug_callback, previous_frame_end,
msaa_sample_count: render_config.msaa_samples msaa_sample_count: render_config.msaa_samples
}, events_loop) }, events_loop)
@@ -350,24 +347,9 @@ impl VulkanRenderer {
builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap(); builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap();
builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::None, ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap(); builder.begin_render_pass(self.framebuffers[fb_index].clone(), false, vec![ClearValue::None, ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
// Load and draw meshes etc. // Draw meshes etc.
for i in 0..self.game_data.game_objects.len() { for pipeline in &self.pipelines {
let game_object = &self.game_data.game_objects[i]; pipeline.draw(&mut builder, fb_index, &self.game_data, &self.dynamic_state);
let mesh = &self.game_data.meshes[game_object.mesh_index];
self.game_data.push_constants.model = game_object.get_model_matrix().into();
builder.draw_indexed(
self.pipeline.clone(),
&self.dynamic_state,
vec![mesh.vertex_buffer.clone()],
mesh.index_buffer.clone(),
game_object.descriptor_sets[fb_index].clone(),
self.game_data.push_constants.clone()).unwrap();
}
// Draw line grid
if self.game_data.use_line_pipeline {
builder.draw(self.line_pipeline.clone(), &self.dynamic_state, vec![self.line_vertex_buffer.clone()], (), self.game_data.line_push_constants.clone()).unwrap();
} }
// General cleanup // General cleanup
@@ -416,12 +398,9 @@ impl VulkanRenderer {
// recreate pipeline if requested // recreate pipeline if requested
if self.game_data.recreate_pipeline { if self.game_data.recreate_pipeline {
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), false) { let device = self.device.clone();
self.pipeline = pipeline_ok; let render_pass = self.render_pass.clone();
println!("Updated pipeline."); self.pipelines.iter_mut().for_each(|pipeline| pipeline.recreate_pipeline(device.clone(), render_pass.clone()));
} else {
println!("Failed to update pipeline.");
}
self.game_data.recreate_pipeline = false; self.game_data.recreate_pipeline = false;
} }
@@ -523,27 +502,27 @@ impl VulkanRenderer {
).unwrap(); ).unwrap();
// Generate mipmaps // Generate mipmaps
let mut mip_width = image_view.dimensions().width() as i32; // let mut mip_width = image_view.dimensions().width() as i32;
let mut mip_height = image_view.dimensions().height() as i32; // let mut mip_height = image_view.dimensions().height() as i32;
for i in 0..image_view.mipmap_levels() { // for i in 0..image_view.mipmap_levels() {
command_buffer_builder.blit_image( // command_buffer_builder.blit_image(
image_view.clone(), // image_view.clone(),
[0; 3], // [0; 3],
[mip_width, mip_height, 1], // [mip_width, mip_height, 1],
0, // 0,
i, // i,
image_view.clone(), // image_view.clone(),
[0; 3], // [0; 3],
[mip_width / 2, mip_height / 2, 1], // [mip_width / 2, mip_height / 2, 1],
0, // 0,
i + 1, // i + 1,
dimensions.array_layers_with_cube(), // dimensions.array_layers_with_cube(),
Filter::Linear).unwrap(); // Filter::Linear).unwrap();
if mip_width > 1 { mip_width = mip_width / 2; } // if mip_width > 1 { mip_width = mip_width / 2; }
if mip_height > 1 { mip_height = mip_height / 2; } // if mip_height > 1 { mip_height = mip_height / 2; }
} // }
let command_buffer = command_buffer_builder.build().unwrap(); let command_buffer = command_buffer_builder.build().unwrap();
let command_buffer_future = command_buffer.execute(self.queue.clone()).unwrap(); let command_buffer_future = command_buffer.execute(self.queue.clone()).unwrap();
@@ -552,22 +531,8 @@ impl VulkanRenderer {
self.game_data.textures.push(image_view); self.game_data.textures.push(image_view);
} }
pub fn add_game_object(self: &mut Self, mut game_object: GameObject) -> GameObjectHandle { pub fn add_game_object(self: &mut Self, mut game_object: GameObject, pipeline_index: usize) -> GameObjectHandle {
let descriptor_set_layout = self.pipeline.descriptor_set_layout(0).unwrap().clone(); self.pipelines[pipeline_index].create_descriptor_set(&mut game_object, self);
println!("Diff: {:?}, Norm: {:?}", game_object.texture_index, game_object.normal_map_index);
let descriptor_sets = self.uniform_buffers.iter().map(|uniform_buffer| {
let builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
let result: Arc<RendererDescriptorSets> = Arc::new(builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(self.game_data.textures[game_object.texture_index].clone(), self.sampler.clone()).unwrap()
.add_sampled_image(self.game_data.textures[game_object.normal_map_index].clone(), self.sampler.clone()).unwrap()
.build().unwrap());
result
}).collect();
game_object.descriptor_sets = descriptor_sets;
self.game_data.game_objects.push(game_object); self.game_data.game_objects.push(game_object);
GameObjectHandle { GameObjectHandle {
@@ -622,70 +587,3 @@ fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage
framebuffers framebuffers
} }
pub mod vs {
vulkano_shaders::shader!{
ty: "vertex",
path: "shaders/triangle.vert"
}
}
pub mod line_vs {
vulkano_shaders::shader!{
ty: "vertex",
path: "shaders/line.vert"
}
}
pub mod fs {
vulkano_shaders::shader! {
ty: "fragment",
path: "shaders/triangle.frag"
}
}
pub mod line_fs {
vulkano_shaders::shader! {
ty: "fragment",
path: "shaders/line.frag"
}
}
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;
if is_line {
let vertex_shader = line_vs::Shader::load(device.clone()).unwrap();
let fragment_shader = line_fs::Shader::load(device.clone()).unwrap();
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 {
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);
}