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::player::Player;
use crate::vulkan::{Game, LinePoint, MeshHandle, VulkanRenderer};
use crate::vulkan::vs::ty::ObjectUniformData;
use crate::pipelines::vs::ty::ObjectUniformData;
mod vulkan;
mod input;
@@ -14,6 +14,7 @@ mod config;
mod mesh;
mod gameobject;
mod player;
mod pipelines;
struct TestGame {
input: InputState,
@@ -159,7 +160,7 @@ impl TestGame {
fn add_game_object(&mut self, renderer: &mut VulkanRenderer, mesh: MeshHandle) -> &mut GameObjectHandle {
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.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::time::SystemTime;
@@ -6,16 +8,13 @@ use image::{ImageBuffer, ImageFormat, Rgb, Rgba};
use image::buffer::ConvertBuffer;
use vulkano::{command_buffer::CommandBuffer, buffer::{BufferUsage, CpuAccessibleBuffer}, image::{ImageLayout, MipmapsCount}};
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::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract};
use vulkano::image::{AttachmentImage, Dimensions, ImageUsage, ImmutableImage, SwapchainImage, ImageViewAccess};
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};
@@ -27,10 +26,11 @@ use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use line_vs::ty::LinePushConstants;
use vs::ty::PushConstants;
use crate::pipelines::{line_vs::ty::LinePushConstants};
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::config::RenderConfig;
@@ -63,8 +63,8 @@ pub trait Game {
}
pub struct Mesh {
vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>,
index_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
pub vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>,
pub index_buffer: Arc<CpuAccessibleBuffer<[u32]>>,
}
#[derive(Debug, Copy, Clone)]
@@ -98,9 +98,7 @@ pub struct VulkanRenderer {
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pub sampler: Arc<Sampler>,
pub dynamic_state: DynamicState,
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 pipelines: Vec<Box<dyn Drawcall>>,
pub surface: Arc<Surface<Window>>,
pub swapchain: Arc<Swapchain<Window>>,
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
@@ -233,9 +231,6 @@ impl VulkanRenderer {
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
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
device.clone(),
@@ -272,10 +267,12 @@ impl VulkanRenderer {
MipmapMode::Nearest, SamplerAddressMode::Repeat, SamplerAddressMode::Repeat,
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).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 line_vertex_buffer = CpuAccessibleBuffer::from_iter(device.clone(), BufferUsage::vertex_buffer(), false, data.line_vertices.iter().cloned()).unwrap();
let pipelines: Vec<Box<dyn Drawcall>> = vec![
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 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>);
(VulkanRenderer { game_data: data, device, framebuffers, sampler,
dynamic_state, pipeline, line_pipeline, uniform_buffers,
surface, swapchain, render_pass, queue, line_vertex_buffer,
dynamic_state, pipelines, uniform_buffers,
surface, swapchain, render_pass, queue,
recreate_swapchain: false, debug_callback, previous_frame_end,
msaa_sample_count: render_config.msaa_samples
}, events_loop)
@@ -350,24 +347,9 @@ impl VulkanRenderer {
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();
// Load and draw meshes etc.
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.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();
// Draw meshes etc.
for pipeline in &self.pipelines {
pipeline.draw(&mut builder, fb_index, &self.game_data, &self.dynamic_state);
}
// General cleanup
@@ -416,12 +398,9 @@ impl VulkanRenderer {
// recreate pipeline if requested
if self.game_data.recreate_pipeline {
if let Some(pipeline_ok) = create_pipeline::<Vertex>(self.device.clone(), self.render_pass.clone(), false) {
self.pipeline = pipeline_ok;
println!("Updated pipeline.");
} else {
println!("Failed to update pipeline.");
}
let device = self.device.clone();
let render_pass = self.render_pass.clone();
self.pipelines.iter_mut().for_each(|pipeline| pipeline.recreate_pipeline(device.clone(), render_pass.clone()));
self.game_data.recreate_pipeline = false;
}
@@ -523,27 +502,27 @@ impl VulkanRenderer {
).unwrap();
// Generate mipmaps
let mut mip_width = image_view.dimensions().width() as i32;
let mut mip_height = image_view.dimensions().height() as i32;
// let mut mip_width = image_view.dimensions().width() as i32;
// let mut mip_height = image_view.dimensions().height() as i32;
for i in 0..image_view.mipmap_levels() {
command_buffer_builder.blit_image(
image_view.clone(),
[0; 3],
[mip_width, mip_height, 1],
0,
i,
image_view.clone(),
[0; 3],
[mip_width / 2, mip_height / 2, 1],
0,
i + 1,
dimensions.array_layers_with_cube(),
Filter::Linear).unwrap();
// for i in 0..image_view.mipmap_levels() {
// command_buffer_builder.blit_image(
// image_view.clone(),
// [0; 3],
// [mip_width, mip_height, 1],
// 0,
// i,
// image_view.clone(),
// [0; 3],
// [mip_width / 2, mip_height / 2, 1],
// 0,
// i + 1,
// dimensions.array_layers_with_cube(),
// Filter::Linear).unwrap();
if mip_width > 1 { mip_width = mip_width / 2; }
if mip_height > 1 { mip_height = mip_height / 2; }
}
// if mip_width > 1 { mip_width = mip_width / 2; }
// if mip_height > 1 { mip_height = mip_height / 2; }
// }
let command_buffer = command_buffer_builder.build().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);
}
pub fn add_game_object(self: &mut Self, mut game_object: GameObject) -> GameObjectHandle {
let descriptor_set_layout = self.pipeline.descriptor_set_layout(0).unwrap().clone();
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;
pub fn add_game_object(self: &mut Self, mut game_object: GameObject, pipeline_index: usize) -> GameObjectHandle {
self.pipelines[pipeline_index].create_descriptor_set(&mut game_object, self);
self.game_data.game_objects.push(game_object);
GameObjectHandle {
@@ -622,70 +587,3 @@ fn window_size_dependent_setup(device: Arc<Device>, images: &[Arc<SwapchainImage
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);
}