vulkano reeeeeeeeeeee

This commit is contained in:
2021-10-24 18:57:46 +02:00
parent 23e19bf9d0
commit 2834623ba7
12 changed files with 193 additions and 192 deletions

View File

@@ -1,7 +1,8 @@
use std::fs;
use std::{convert::TryInto, fs};
use serde_derive::{Deserialize, Serialize};
use toml;
use vulkano::image::SampleCount;
#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
pub struct LogConfigInput {
@@ -33,4 +34,8 @@ impl RenderConfig {
pub fn from_file(path: &str) -> Self {
toml::from_slice(&fs::read(path).expect("Failed to read render config!")).expect("Failed to parse render config!")
}
pub fn get_msaa(&self) -> Option<SampleCount> {
if self.msaa_samples > 0 { self.msaa_samples.try_into().ok() } else { None }
}
}

View File

@@ -58,7 +58,7 @@ impl UiQuad {
}
impl Updatable for UiQuad {
fn update(&mut self, delta_time: f32, input: &InputState, game_state: &mut GameState, game_objects: &mut Vec<GameObject>, renderer: &mut VulkanRenderer) {
fn update(&mut self, _delta_time: f32, _input: &InputState, _game_state: &mut GameState, _game_objects: &mut Vec<GameObject>, _renderer: &mut VulkanRenderer) {
}
}

View File

@@ -55,10 +55,6 @@ impl Camera {
self.proj.y.y *= -1.0;
self.ortho_proj = cgmath::ortho(0., width, 0., height, -1., 1.);
// Upload
renderer.game_data.line_push_constants.view = self.view.into();
renderer.game_data.line_push_constants.projection = self.proj.into();
}
pub fn viewport_pos_to_ray_direction(&self, viewport_pos: Vector2<f64>, viewport_dimensions: [u32; 2]) -> Option<Vector3<f32>> {
@@ -135,9 +131,9 @@ pub fn intersection_distance(ray_origin: Vector3<f32>, ray_direction: Vector3<f3
let index_lock = mesh.index_buffer.read().unwrap();
let vertex_lock = mesh.vertex_buffer.read().unwrap();
(0..mesh.index_buffer.len() / 3).map(|tri_idx| {
let vtx_a = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx * 3 ] as usize].position);
let vtx_b = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx * 3 + 1] as usize].position);
let vtx_c = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx * 3 + 2] as usize].position);
let vtx_a = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx as usize * 3 ] as usize].position);
let vtx_b = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx as usize * 3 + 1] as usize].position);
let vtx_c = game_object.get_model_matrix() * vec4_from_pos(vertex_lock[index_lock[tri_idx as usize * 3 + 2] as usize].position);
intersect_triangle(ray_origin, ray_direction, vtx_a.truncate().into(), vtx_b.truncate().into(), vtx_c.truncate().into())
}).fold(None, |acc, x| {
if let Some(smallest) = acc {

View File

@@ -4,7 +4,7 @@ use vulkan::gameobject::GameObject;
use crate::config::{LogConfig, RenderConfig};
use crate::game::TestGame;
use crate::vulkan::{LinePoint, VulkanRenderer};
use crate::vulkan::VulkanRenderer;
mod vulkan;
mod input;
@@ -18,17 +18,7 @@ fn main() {
let mut game = TestGame::new("config/input.toml", log_config);
let line_count = 30;
let line_vertices = (-line_count..=line_count)
.flat_map(|it| vec![
LinePoint { position: [it as f32, 0., -line_count as f32] },
LinePoint { position: [it as f32, 0., line_count as f32] },
LinePoint { position: [-line_count as f32, 0., it as f32] },
LinePoint { position: [line_count as f32, 0., it as f32] },
]).collect();
let (mut renderer, event_loop) = VulkanRenderer::init(
line_vertices,
log_config.vulkan_validation_layers,
RenderConfig::from_file("config/graphics.toml")
);

View File

@@ -1,5 +1,5 @@
use glyph_brush::{BrushAction, BrushError, GlyphBrush, GlyphBrushBuilder, GlyphVertex, Rectangle, Section, Text, ab_glyph::FontArc};
use vulkano::{format::Format, image::Dimensions, sampler::{Filter, SamplerAddressMode}};
use vulkano::{format::Format, image::ImageDimensions, sampler::{Filter, SamplerAddressMode}};
use crate::vulkan::{MeshHandle, TextVertex, TextureHandle, VulkanRenderer, gameobject::{GameObject, GameObjectHandle}, mesh::{CPUMesh, CPUVertexList}};
@@ -20,7 +20,7 @@ pub fn update_text(game_object_handle: GameObjectHandle, new_text: &str, new_siz
},
Ok(BrushAction::ReDraw) => {},
Err(BrushError::TextureTooSmall { suggested }) => {
let size = Dimensions::Dim2d { width: suggested.0, height: suggested.1 };
let size = ImageDimensions::Dim2d { width: suggested.0, height: suggested.1, array_layers: 1 };
debug_assert!(go.textures.len() == 1);
renderer.resize_texture(go, go.textures[0], size);
brush.resize_texture(suggested.0, suggested.1);
@@ -70,7 +70,7 @@ pub fn update_text_texture(old_texture: Option<TextureHandle>, renderer: &mut Vu
renderer.update_texture(tex_handle, text_data, [rect.width(), rect.height(), 1], [rect.min[0], rect.min[1], 0], renderer.device.clone());
None
} else {
let tex = renderer.upload_texture(text_data, size, size, Format::R8Unorm, Filter::Nearest, SamplerAddressMode::ClampToEdge, renderer.device.clone());
let tex = renderer.upload_texture(text_data, size, size, Format::R8_UNORM, Filter::Nearest, SamplerAddressMode::ClampToEdge, renderer.device.clone());
renderer.game_data.textures.push(tex.clone());
Some(renderer.game_data.textures.len() - 1)
}

View File

@@ -25,12 +25,12 @@ pub fn upload_texture_from_file(path: &str, renderer: &mut VulkanRenderer) -> Re
println!("Texture width: {}, height: {}, bytes: {}", tex_width, tex_height, tex_byte_count);
let texture = if is_dxt1 {
renderer.upload_texture(&tex_bytes[128..], tex_width, tex_height, Format::BC1_RGBUnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone())
renderer.upload_texture(&tex_bytes[128..], tex_width, tex_height, Format::BC1_RGB_UNORM_BLOCK, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone())
} else if is_dx10 {
let dxgi_type = u32::from_ne_bytes(tex_bytes[128..132].try_into()?);
assert!(dxgi_type == 83); // BC5 Unorm Typeless
renderer.upload_texture(&tex_bytes[128+20..], tex_width, tex_height, Format::BC5UnormBlock, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone())
renderer.upload_texture(&tex_bytes[128+20..], tex_width, tex_height, Format::BC5_UNORM_BLOCK, Filter::Linear, SamplerAddressMode::Repeat, renderer.device.clone())
} else {
panic!("Unknown texture type!");
};
@@ -40,8 +40,8 @@ pub fn upload_texture_from_file(path: &str, renderer: &mut VulkanRenderer) -> Re
pub fn get_block_size(format: Format) -> Option<u32> {
match format {
Format::BC1_RGBUnormBlock => Some(8),
Format::BC5UnormBlock => Some(16),
Format::BC1_RGB_UNORM_BLOCK => Some(8),
Format::BC5_UNORM_BLOCK => Some(16),
_ => None
}
}

View File

@@ -1,11 +1,11 @@
use std::sync::Arc;
use vulkano::command_buffer::DynamicState;
use vulkano::device::Device;
use vulkano::format::Format;
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract};
use vulkano::image::{AttachmentImage, ImageUsage, SwapchainImage};
use vulkano::image::view::ImageView;
use vulkano::image::{AttachmentImage, ImageUsage, SampleCount, SwapchainImage};
use vulkano::pipeline::viewport::Viewport;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass};
use winit::window::Window;
use vulkano::swapchain::Swapchain;
@@ -13,29 +13,21 @@ use vulkano::swapchain::Swapchain;
pub fn create_framebuffers(device: Arc<Device>,
swapchain: &Arc<Swapchain<Window>>,
images: &[Arc<SwapchainImage<Window>>],
msaa_sample_count: u32,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
dynamic_state: &mut DynamicState)
msaa_sample_count: Option<SampleCount>,
render_pass: Arc<RenderPass>)
-> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dim_array = images[0].dimensions();
let dim_array_f32 = [dim_array[0] as f32, dim_array[1] as f32];
let viewport = Viewport {
origin: [0.0, 0.0],
dimensions: dim_array_f32,
depth_range: 0.0..1.0,
};
dynamic_state.viewports = Some(vec!(viewport));
let depth_image = if msaa_sample_count > 0 {
AttachmentImage::multisampled_with_usage(device.clone(), dim_array, msaa_sample_count, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap()
let depth_image = if let Some(sample_count) = msaa_sample_count {
AttachmentImage::multisampled_with_usage(device.clone(), dim_array, sample_count, Format::D16_UNORM, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap()
} else {
AttachmentImage::with_usage(device.clone(), dim_array, Format::D16Unorm, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap()
AttachmentImage::with_usage(device.clone(), dim_array, Format::D16_UNORM, ImageUsage { depth_stencil_attachment: true, ..ImageUsage::none() }).unwrap()
};
let depth_image_view = ImageView::new(depth_image.clone()).unwrap();
let msaa_buffers = if msaa_sample_count > 0 {
Some(create_msaa_buffers(device.clone(), dim_array, swapchain, msaa_sample_count))
let msaa_buffers = if let Some(sample_count) = msaa_sample_count {
Some(create_msaa_buffers(device.clone(), dim_array, swapchain, sample_count))
} else {
None
};
@@ -44,18 +36,21 @@ pub fn create_framebuffers(device: Arc<Device>,
for i in 0..images.len() {
let image_buffer = &images[i];
let view = ImageView::new(image_buffer.clone()).unwrap();
if let Some(msaa_buffers_exist) = &msaa_buffers {
let msaa_view = ImageView::new((&msaa_buffers_exist[i]).clone()).unwrap();
framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone())
.add(image_buffer.clone()).unwrap()
.add((&msaa_buffers_exist[i]).clone()).unwrap()
.add(depth_image.clone()).unwrap()
.add(view).unwrap()
.add(msaa_view).unwrap()
.add(depth_image_view.clone()).unwrap()
.build().unwrap()
) as Arc<dyn FramebufferAbstract + Send + Sync>);
} else {
framebuffers.push(Arc::new(Framebuffer::start(render_pass.clone())
.add(image_buffer.clone()).unwrap()
.add(depth_image.clone()).unwrap()
.add(view).unwrap()
.add(depth_image_view.clone()).unwrap()
.build().unwrap()
) as Arc<dyn FramebufferAbstract + Send + Sync>);
}
@@ -64,7 +59,7 @@ pub fn create_framebuffers(device: Arc<Device>,
framebuffers
}
fn create_msaa_buffers(device: Arc<Device>, dimensions: [u32; 2], swapchain: &Arc<Swapchain<Window>>, sample_count: u32) -> Vec<Arc<AttachmentImage>> {
fn create_msaa_buffers(device: Arc<Device>, dimensions: [u32; 2], swapchain: &Arc<Swapchain<Window>>, sample_count: SampleCount) -> Vec<Arc<AttachmentImage>> {
let mut msaa_attachments = vec![];
for _ in 0..swapchain.num_images() {
msaa_attachments.push(AttachmentImage::transient_multisampled(device.clone(), dimensions, sample_count, swapchain.format()).unwrap());

View File

@@ -1,13 +1,18 @@
use std::sync::Arc;
use cgmath::{Deg, Euler, Matrix4, Quaternion, Vector3};
use vulkano::descriptor_set::PersistentDescriptorSet;
use crate::game::GameState;
use crate::input::InputState;
use crate::vulkan::{RendererDescriptorSets, TextureHandle};
use crate::vulkan::TextureHandle;
use crate::vulkan::{MeshHandle, VulkanRenderer};
use super::pipelines::vs;
use super::pipelines::{vs, vs_text};
pub trait PushConstant {}
impl PushConstant for vs::ty::PushConstants {}
impl PushConstant for vs_text::ty::PushConstants {}
#[derive(Clone)]
pub struct GameObject {
@@ -17,7 +22,7 @@ pub struct GameObject {
pub rotation: Quaternion<f32>,
pub scale: Vector3<f32>,
pub children: Vec<GameObject>,
pub descriptor_sets: Vec<Vec<Arc<RendererDescriptorSets>>>,
pub descriptor_sets: Vec<Vec<Arc<PersistentDescriptorSet>>>,
pub is_selected: bool,
pub pipeline_index: usize,
pub visible: bool,
@@ -60,11 +65,11 @@ impl GameObject {
self.rotation = self.rotation * Quaternion::from(Euler::new(Deg(x), Deg(y), Deg(z)));
}
pub fn get_push_constants(&self) -> vs::ty::PushConstants {
vs::ty::PushConstants {
pub fn get_push_constants(&self) -> Box<dyn PushConstant> {
Box::new(vs::ty::PushConstants {
model: self.get_model_matrix().into(),
is_selected: if self.is_selected { 1 } else { 0 },
}
})
}
pub fn get_model_matrix(&self) -> Matrix4<f32> {

View File

@@ -3,14 +3,15 @@ use std::time::SystemTime;
use cgmath::{Matrix4, SquareMatrix};
use dds::get_block_size;
use vulkano::{buffer::{BufferUsage, CpuAccessibleBuffer}, command_buffer::{CommandBuffer, SubpassContents}, image::{ImageAccess, ImageLayout, ImageUsage, MipmapsCount, immutable::SubImage}};
use vulkano::command_buffer::{AutoCommandBuffer, AutoCommandBufferBuilder, DynamicState};
use vulkano::descriptor::DescriptorSet;
use vulkano::device::{Device, DeviceExtensions, Queue};
use vulkano::device::physical::PhysicalDevice;
use vulkano::pipeline::viewport::Viewport;
use vulkano::render_pass::{FramebufferAbstract, RenderPass};
use vulkano::{buffer::{BufferUsage, CpuAccessibleBuffer}, command_buffer::SubpassContents, image::{ImageAccess, ImageLayout, ImageUsage, MipmapsCount, immutable::SubImage}};
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer, PrimaryCommandBuffer};
use vulkano::device::{Device, DeviceExtensions, Features, Queue};
use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::{RenderPassAbstract, FramebufferAbstract};
use vulkano::image::{Dimensions, ImmutableImage};
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, PhysicalDevice, Version};
use vulkano::image::{ImageCreateFlags, ImageDimensions, ImmutableImage};
use vulkano::instance::{ApplicationInfo, Instance, InstanceExtensions, Version};
use vulkano::instance::debug::{DebugCallback, MessageSeverity, MessageType};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain::{AcquireError, FullscreenExclusive, PresentMode, Surface, SurfaceTransform, Swapchain, SwapchainCreationError};
@@ -20,13 +21,12 @@ use vulkano::sync;
use vulkano_win::VkSurfaceBuild;
use winit::event::{Event, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use mesh::CPUMesh;
use pipelines::{Drawcall};
use pipelines::line_vs::ty::LinePushConstants;
use pipelines::{DefaultShader, TextShader};
use pipelines::vs;
use winit::window::{Window, WindowBuilder};
use crate::config::RenderConfig;
use crate::vulkan::gameobject::GameObject;
@@ -100,14 +100,12 @@ pub struct MeshHandle {
pub(crate) type TextureHandle = usize;
#[derive(Debug, Clone)]
pub struct Texture {
pub image: Arc<ImmutableImage<Format>>,
pub image: Arc<ImmutableImage>,
pub sampler: Arc<Sampler>
}
pub struct GameData {
pub start_time: SystemTime,
pub line_vertices: Vec<LinePoint>,
pub line_push_constants: LinePushConstants,
pub recreate_pipeline: bool,
pub dimensions: [u32; 2],
pub shutdown: bool,
@@ -121,38 +119,30 @@ pub struct GameData {
pub performance_counter_index: usize,
}
pub(crate) type RendererDescriptorSets = dyn DescriptorSet + Send + Sync;
pub struct VulkanRenderer {
pub game_data: GameData,
pub device: Arc<Device>,
pub framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pub dynamic_state: DynamicState,
pub pipelines: Vec<Box<dyn Drawcall>>,
pub surface: Arc<Surface<Window>>,
pub swapchain: Arc<Swapchain<Window>>,
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
pub render_pass: Arc<RenderPass>,
pub queue: Arc<Queue>,
pub recreate_swapchain: bool,
pub debug_callback: Option<DebugCallback>,
pub previous_frame_end: Option<Box<dyn GpuFuture>>,
pub uniform_buffers: Vec<Arc<CpuAccessibleBuffer<vs::ty::ObjectUniformData>>>,
pub render_config: RenderConfig
pub render_config: RenderConfig,
pub viewport: Viewport
}
impl VulkanRenderer {
pub fn init(line_vertices: Vec<LinePoint>, enable_validation_layers: bool, render_config: RenderConfig) -> (VulkanRenderer, EventLoop<()>) {
pub fn init(enable_validation_layers: bool, render_config: RenderConfig) -> (VulkanRenderer, EventLoop<()>) {
// Create empty game data struct to be filled
let mut data = GameData {
line_push_constants: LinePushConstants {
model: Matrix4::identity().into(),
view: Matrix4::identity().into(),
projection: Matrix4::identity().into(),
},
start_time: SystemTime::now(),
recreate_pipeline: false,
shutdown: false,
line_vertices,
dimensions: [0, 0],
meshes: vec![],
meshes_text: vec![],
@@ -190,9 +180,9 @@ impl VulkanRenderer {
}
});
Instance::new(Some(&app_info), &extensions, VALIDATION_LAYERS.iter().cloned()).expect("failed to create Vulkan instance")
Instance::new(Some(&app_info), Version::V1_1, &extensions, VALIDATION_LAYERS.iter().cloned()).expect("failed to create Vulkan instance")
} else {
Instance::new(Some(&app_info), &extensions, None).expect("failed to create Vulkan instance")
Instance::new(Some(&app_info), Version::V1_1, &extensions, None).expect("failed to create Vulkan instance")
}
};
@@ -224,13 +214,12 @@ impl VulkanRenderer {
let layer_str = msg.layer_prefix;
println!("[{}][{}]: {}", type_str, layer_str, msg.description);
println!("[{}][{}]: {}", type_str, layer_str.unwrap_or(""), msg.description);
}).ok();
}
// TODO: Create device selector
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
println!("Using device: {} (type: {:?})", physical.name(), physical.ty());
let events_loop = EventLoop::new();
let surface = WindowBuilder::new().build_vk_surface(&events_loop, instance.clone()).unwrap();
@@ -242,7 +231,7 @@ impl VulkanRenderer {
}).unwrap();
let device_ext = DeviceExtensions { khr_swapchain: true, ..DeviceExtensions::none() };
let (device, mut queues) = Device::new(physical, physical.supported_features(), &device_ext,
let (device, mut queues) = Device::new(physical, &Features::none(), &device_ext,
[(queue_family, 0.5)].iter().cloned()).unwrap();
let queue = queues.next().unwrap();
@@ -255,9 +244,27 @@ impl VulkanRenderer {
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, FullscreenExclusive::Default, true, color_space).unwrap()
Swapchain::start(device.clone(), surface.clone())
.num_images(caps.min_image_count)
.format(format)
.dimensions(data.dimensions)
.layers(1)
.usage(usage)
.sharing_mode(&queue)
.transform(SurfaceTransform::Identity)
.composite_alpha(alpha)
.present_mode(PresentMode::Fifo)
.fullscreen_exclusive(FullscreenExclusive::Default)
.clipped(true)
.color_space(color_space)
.build().unwrap()
};
let size = images[0].dimensions().width_height();
let viewport = Viewport {
origin: [0.0, 0.0],
dimensions: [size[0] as f32, size[1] as f32],
depth_range: 0.0..1.0,
};
// Render pass
@@ -269,15 +276,9 @@ impl VulkanRenderer {
Box::new(TextShader::new(device.clone(), render_pass_text.clone())),
];
// 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, 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.
let framebuffers = framebuffers::create_framebuffers(device.clone(), &swapchain, &images, render_config.msaa_samples, render_pass.clone(), &mut dynamic_state);
let framebuffers = framebuffers::create_framebuffers(device.clone(), &swapchain, &images, render_config.get_msaa(), render_pass.clone());
let mut uniform_buffers = Vec::new();
let uniform_buffer = vs::ty::ObjectUniformData {
@@ -311,28 +312,30 @@ impl VulkanRenderer {
let previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<dyn GpuFuture>);
(VulkanRenderer { game_data: data, device, framebuffers,
dynamic_state, pipelines, uniform_buffers,
pipelines, uniform_buffers,
surface, swapchain, render_pass, queue,
recreate_swapchain: false, debug_callback, previous_frame_end,
render_config,
render_config, viewport
}, events_loop)
}
fn create_command_buffer(self: &mut Self, fb_index: usize, uniform_buffer_data: vs::ty::ObjectUniformData, game_objects: &Vec<GameObject>) -> Arc<AutoCommandBuffer> {
fn create_command_buffer(self: &mut Self, fb_index: usize, uniform_buffer_data: vs::ty::ObjectUniformData, game_objects: &Vec<GameObject>) -> Arc<PrimaryAutoCommandBuffer> {
// General setup
let mut builder = AutoCommandBufferBuilder::primary_simultaneous_use(self.device.clone(), self.queue.family()).unwrap();
builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap();
let mut builder = AutoCommandBufferBuilder::primary(self.device.clone(), self.queue.family(), CommandBufferUsage::OneTimeSubmit).unwrap();
// builder.update_buffer(self.uniform_buffers[fb_index].clone(), uniform_buffer_data).unwrap();
if self.render_config.msaa_samples > 0 {
builder.begin_render_pass(self.framebuffers[fb_index].clone(), SubpassContents::Inline, vec![ClearValue::None, ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
} else {
builder.begin_render_pass(self.framebuffers[fb_index].clone(), SubpassContents::Inline, vec![ClearValue::Float([0.0, 0.0, 0.0, 1.0]), ClearValue::Depth(1.0)]).unwrap();
}
builder.set_viewport(0, [self.viewport.clone()]);
// Draw meshes etc.
let mut index = 0;
for pipeline in &self.pipelines {
let objects = game_objects.iter().filter(|go| go.visible && go.pipeline_index == index).collect();
pipeline.draw(&mut builder, fb_index, objects, &self.game_data, &self.dynamic_state);
pipeline.draw(&mut builder, fb_index, objects, &self.game_data);
index += 1;
}
@@ -353,7 +356,7 @@ impl VulkanRenderer {
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_dimensions(self.game_data.dimensions) {
let (new_swapchain, new_images) = match self.swapchain.recreate().dimensions(self.game_data.dimensions).build() {
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.
@@ -364,6 +367,14 @@ impl VulkanRenderer {
Err(err) => panic!("{:?}", err),
};
let size = new_images[0].dimensions().width_height();
self.viewport = Viewport {
origin: [0.0, 0.0],
dimensions: [size[0] as f32, size[1] as f32],
depth_range: 0.0..1.0,
};
self.render_pass = renderpass::create_render_pass(self.device.clone(), &self.render_config, new_swapchain.format());
self.pipelines = vec![
@@ -374,7 +385,7 @@ impl VulkanRenderer {
self.swapchain = new_swapchain;
// Because framebuffers contains an Arc on the old swapchain, we need to
// recreate framebuffers as well.
self.framebuffers = framebuffers::create_framebuffers(self.device.clone(), &self.swapchain, &new_images, self.render_config.msaa_samples, self.render_pass.clone(), &mut self.dynamic_state);
self.framebuffers = framebuffers::create_framebuffers(self.device.clone(), &self.swapchain, &new_images, self.render_config.get_msaa(), self.render_pass.clone());
self.recreate_swapchain = false;
}
@@ -473,7 +484,7 @@ impl VulkanRenderer {
}
pub fn upload_texture(self: &mut Self, bytes: &[u8], width: u32, height: u32, format: Format, filter: Filter, wrap: SamplerAddressMode, device: Arc<Device>) -> Texture {
let dimensions = Dimensions::Dim2d { width, height };
let dimensions = ImageDimensions::Dim2d { width, height, array_layers: 1 };
let usage = ImageUsage {
transfer_destination: true,
@@ -482,7 +493,7 @@ impl VulkanRenderer {
..ImageUsage::none()
};
let mip_maps = if format == Format::R8Uint { MipmapsCount::One } else { MipmapsCount::Log2 };
let mip_maps = if format == Format::R8_UINT { MipmapsCount::One } else { MipmapsCount::Log2 };
let (image_view, initializer) = ImmutableImage::uninitialized(
device.clone(),
@@ -490,6 +501,7 @@ impl VulkanRenderer {
format,
mip_maps,
usage,
ImageCreateFlags::default(),
ImageLayout::ShaderReadOnlyOptimal,
device.active_queue_families(),
).unwrap();
@@ -503,7 +515,7 @@ impl VulkanRenderer {
ImageLayout::ShaderReadOnlyOptimal,
);
let mut cbb = AutoCommandBufferBuilder::new(device.clone(), self.queue.family()).unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(device.clone(), self.queue.family(), CommandBufferUsage::OneTimeSubmit).unwrap();
let mut offset = 0;
@@ -523,7 +535,7 @@ impl VulkanRenderer {
[0, 0, 0],
mip_size,
0,
dimensions.array_layers_with_cube(),
dimensions.array_layers(),
mip_index,
).unwrap();
};
@@ -531,7 +543,7 @@ impl VulkanRenderer {
if let Some(block_byte_size) = block_bytes {
for i in 0..image_view.mipmap_levels() {
let mip_size = dimensions.to_image_dimensions().mipmap_dimensions(i).unwrap().width_height_depth();
let mip_size = dimensions.mipmap_dimensions(i).unwrap().width_height_depth();
let mip_byte_size = (
(u32::max(4, mip_size[0]) / 4)
@@ -545,7 +557,7 @@ impl VulkanRenderer {
} else {
let mut texture_bytes: Vec<u8> = bytes.to_vec();
texture_bytes.resize((width * height) as usize, 0u8);
upload_bytes(&texture_bytes, 0, dimensions.to_image_dimensions().width_height_depth());
upload_bytes(&texture_bytes, 0, dimensions.width_height_depth());
}
let cb = cbb.build().unwrap();
@@ -576,7 +588,7 @@ impl VulkanRenderer {
ImageLayout::ShaderReadOnlyOptimal,
);
let mut cbb = AutoCommandBufferBuilder::new(device.clone(), self.queue.family()).unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(device.clone(), self.queue.family(), CommandBufferUsage::OneTimeSubmit).unwrap();
let upload_source = CpuAccessibleBuffer::from_iter(
device.clone(),
@@ -602,7 +614,7 @@ impl VulkanRenderer {
future.flush().unwrap();
}
pub fn resize_texture(&mut self, game_object: &mut GameObject, texture_handle: TextureHandle, new_size: Dimensions) {
pub fn resize_texture(&mut self, game_object: &mut GameObject, texture_handle: TextureHandle, new_size: ImageDimensions) {
let mut texture = &mut self.game_data.textures[texture_handle];
let new_image_usage = ImageUsage {
@@ -618,6 +630,7 @@ impl VulkanRenderer {
texture.image.format(),
texture.image.mipmap_levels(),
new_image_usage,
ImageCreateFlags::default(),
ImageLayout::ShaderReadOnlyOptimal,
self.device.active_queue_families(),
).unwrap();
@@ -640,7 +653,7 @@ impl VulkanRenderer {
ImageLayout::ShaderReadOnlyOptimal,
);
let mut cbb = AutoCommandBufferBuilder::new(self.device.clone(), self.queue.family()).unwrap();
let mut cbb = AutoCommandBufferBuilder::primary(self.device.clone(), self.queue.family(), CommandBufferUsage::OneTimeSubmit).unwrap();
cbb.copy_image(
old_sub_image.clone(),

View File

@@ -1,27 +1,22 @@
use std::{convert::TryInto, io::{self, ErrorKind, Read, Write}, path::PathBuf, sync::Arc};
use vulkano::{command_buffer::AutoCommandBufferBuilder, descriptor::{DescriptorSet, descriptor::ShaderStages, descriptor_set::PersistentDescriptorSet, pipeline_layout::PipelineLayoutDesc}, pipeline::{shader::{ShaderModule}}};
use vulkano::command_buffer::DynamicState;
use vulkano::{buffer::TypedBufferAccess, command_buffer::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer}, descriptor_set::PersistentDescriptorSet, image::view::ImageView, pipeline::{PipelineBindPoint, shader::ShaderModule}, render_pass::{RenderPass, Subpass}};
use vulkano::device::Device;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::pipeline::shader::GraphicsShaderType;
use crate::{GameObject, vulkan::{TextVertex}};
use crate::vulkan::{LinePoint, Vertex};
use crate::{GameObject, vulkan::TextVertex};
use crate::vulkan::Vertex;
use crate::vulkan::GameData;
use crate::VulkanRenderer;
use super::TextureHandle;
type RP = Arc<dyn RenderPassAbstract + Send + Sync>;
type GP = Arc<dyn GraphicsPipelineAbstract + Send + Sync>;
type DS = Arc<dyn DescriptorSet + Send + Sync>;
type RP = Arc<RenderPass>;
type GP = Arc<GraphicsPipeline>;
type DS = Arc<PersistentDescriptorSet>;
pub trait Drawcall {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState);
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData);
fn create_descriptor_sets(self: &Self, textures: &Vec<TextureHandle>, renderer: &VulkanRenderer) -> Vec<Vec<DS>>;
fn recreate_pipeline(self: &mut Self, device: Arc<Device>, render_pass: RP);
fn get_pipeline(self: &Self) -> &GP;
@@ -46,7 +41,7 @@ pub struct DefaultShader {
pipeline: GP,
}
fn shader_module_from_file(device: Arc<Device>, path: &str) -> Arc<ShaderModule> {
fn _shader_module_from_file(device: Arc<Device>, path: &str) -> Arc<ShaderModule> {
let mut file = std::fs::File::open(path).unwrap();
let mut buffer = vec![];
file.read_to_end(&mut buffer).unwrap();
@@ -105,11 +100,12 @@ impl DefaultShader {
}
unsafe {
/*
static ENTRY_NAME: [u8; 5usize] = [109u8, 97u8, 105u8, 110u8, 0];
let entry_name_c = std::ffi::CStr::from_ptr(ENTRY_NAME.as_ptr() as *const _);
let fs_module = shader_module_from_file(device.clone(), "shaders/triangle.frag.spv");
let fs_layout = fs::Layout(ShaderStages {
let fs_layout = fs::MainLayout(ShaderStages {
fragment: true,
..ShaderStages::none()
});
@@ -121,14 +117,17 @@ impl DefaultShader {
..ShaderStages::none()
});
let vs_entry = vs_module.graphics_entry_point(entry_name_c, vs::MainInput, vs::MainOutput, vs_layout, GraphicsShaderType::Vertex);
*/
let vs = vs::Shader::load(device.clone()).unwrap();
let fs = fs::Shader::load(device.clone()).unwrap();
Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_shader(vs_entry, ())
.vertex_shader(vs.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fs_entry, ())
.fragment_shader(fs.main_entry_point(), ())
.blend_alpha_blending()
.cull_mode_back()
.render_pass(sub_pass.clone())
@@ -139,39 +138,39 @@ impl DefaultShader {
}
impl Drawcall for DefaultShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData) {
for i in 0..game_objects.len() {
let game_object = &game_objects[i];
let mesh = &game_data.meshes[game_object.mesh_index];
let push_constants = game_object.get_push_constants();
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();
builder
.bind_pipeline_graphics(self.pipeline.clone())
.bind_descriptor_sets(PipelineBindPoint::Graphics, self.pipeline.layout().clone(), 0, game_object.descriptor_sets[fb_index].clone())
.bind_vertex_buffers(0, mesh.vertex_buffer.clone())
.bind_index_buffer(mesh.index_buffer.clone())
.push_constants(self.pipeline.layout().clone(), 0, push_constants)
.draw_indexed(mesh.index_buffer.len() as u32, 1, 0, 0, 0).unwrap();
}
}
fn create_descriptor_sets(self: &Self, textures: &Vec<TextureHandle>, renderer: &VulkanRenderer) -> Vec<Vec<DS>> {
let descriptor_set_layout_0 = self.get_pipeline().descriptor_set_layout(0).unwrap().clone();
let descriptor_set_layout_0 = self.get_pipeline().layout().descriptor_set_layouts().get(0).unwrap().clone();
renderer.uniform_buffers.iter().map(|uniform_buffer| {
let descriptor_set_0: Arc<(dyn vulkano::descriptor::DescriptorSet + std::marker::Send + std::marker::Sync + 'static)>;
debug_assert!(textures.len() == 2, "Expected diffuse and normal map for object shader!");
let diffuse = &renderer.game_data.textures[textures[0]];
let diffuse_view = ImageView::new(diffuse.image.clone()).unwrap();
let normal_map = &renderer.game_data.textures[textures[1]];
let normal_view = ImageView::new(normal_map.image.clone()).unwrap();
descriptor_set_0 = Arc::new(PersistentDescriptorSet::start(descriptor_set_layout_0.clone())
let mut builder = PersistentDescriptorSet::start(descriptor_set_layout_0.clone());
builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(diffuse.image.clone(), diffuse.sampler.clone()).unwrap()
.add_sampled_image(normal_map.image.clone(), normal_map.sampler.clone()).unwrap()
.build().unwrap());
.add_sampled_image(diffuse_view, diffuse.sampler.clone()).unwrap()
.add_sampled_image(normal_view, normal_map.sampler.clone()).unwrap();
vec![descriptor_set_0]
vec![Arc::new(builder.build().unwrap())]
}).collect()
}
@@ -184,6 +183,7 @@ impl Drawcall for DefaultShader {
}
}
/*
pub mod line_vs {
vulkano_shaders::shader!{
ty: "vertex",
@@ -231,9 +231,8 @@ impl LineShader {
}
impl Drawcall for LineShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, _fb_index: usize, _game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>, _fb_index: usize, _game_objects: Vec<&GameObject>, game_data: &GameData) {
builder.draw(self.pipeline.clone(),
&dynamic_state,
vec![self.vertex_buffer.clone()],
(),
game_data.line_push_constants.clone()).unwrap();
@@ -251,6 +250,7 @@ impl Drawcall for LineShader {
&self.pipeline
}
}
*/
pub mod vs_text {
vulkano_shaders::shader!{
@@ -287,6 +287,7 @@ impl TextShader {
}
unsafe {
/*
static ENTRY_NAME: [u8; 5usize] = [109u8, 97u8, 105u8, 110u8, 0];
let entry_name_c = std::ffi::CStr::from_ptr(ENTRY_NAME.as_ptr() as *const _);
@@ -303,23 +304,27 @@ impl TextShader {
..ShaderStages::none()
});
let vs_entry = vs_module.graphics_entry_point(entry_name_c, vs_text::MainInput, vs_text::MainOutput, vs_layout, GraphicsShaderType::Vertex);
*/
let vs = vs_text::Shader::load(device.clone()).unwrap();
let fs = fs_text::Shader::load(device.clone()).unwrap();
let gp = Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<TextVertex>()
.vertex_shader(vs_entry, ())
.vertex_shader(vs.main_entry_point(), ())
.triangle_list()
.viewports_dynamic_scissors_irrelevant(1)
.depth_stencil_simple_depth()
.fragment_shader(fs_entry, ())
.fragment_shader(fs.main_entry_point(), ())
.blend_alpha_blending()
.cull_mode_disabled()
.render_pass(sub_pass.clone())
.build(device.clone())
.unwrap());
println!("{:?}", gp.descriptor(0, 0).unwrap().ty);
println!("{:?}", gp.descriptor(0, 1).unwrap().ty);
println!("{:?}", gp.descriptor(0, 2).unwrap().ty); // TODO: Why does this exist?
// println!("{:?}", gp.descriptor(0, 0).unwrap().ty);
// println!("{:?}", gp.descriptor(0, 1).unwrap().ty);
// println!("{:?}", gp.descriptor(0, 2).unwrap().ty); // TODO: Why does this exist?
gp
}
@@ -327,43 +332,37 @@ impl TextShader {
}
impl Drawcall for TextShader {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData, dynamic_state: &DynamicState) {
fn draw(self: &Self, builder: &mut AutoCommandBufferBuilder<PrimaryAutoCommandBuffer>, fb_index: usize, game_objects: Vec<&GameObject>, game_data: &GameData) {
for i in 0..game_objects.len() {
let game_object = &game_objects[i];
let mesh = &game_data.meshes_text[game_object.mesh_index];
let push_constants = game_object.get_push_constants();
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();
builder.bind_pipeline_graphics(self.pipeline.clone())
.bind_descriptor_sets(PipelineBindPoint::Graphics, self.pipeline.layout().clone(), 0, game_object.descriptor_sets[fb_index].clone())
.bind_vertex_buffers(0, mesh.vertex_buffer.clone())
.bind_index_buffer(mesh.index_buffer.clone())
.push_constants(self.pipeline.layout().clone(), 0, game_object.get_push_constants())
.draw_indexed(mesh.index_buffer.len() as u32, 1, 0, 0, 0).unwrap();
}
}
fn create_descriptor_sets(self: &Self, textures: &Vec<TextureHandle>, renderer: &VulkanRenderer) -> Vec<Vec<DS>> {
let descriptor_set_layout = self.get_pipeline().descriptor_set_layout(0).unwrap().clone();
let descriptor_set_layout = self.get_pipeline().layout().descriptor_set_layouts().get(0).unwrap().clone();
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());
let diffuse_index = match textures.len() {
0 => 0,
1 => textures[0],
_ => panic!("Expected only diffuse map for text shader!"),
};
let diffuse = &renderer.game_data.textures[diffuse_index];
let diffuse_view = ImageView::new(diffuse.image.clone()).unwrap();
descriptor_set = Arc::new(builder
.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(diffuse.image.clone(), diffuse.sampler.clone()).unwrap()
.add_sampled_image(diffuse.image.clone(), diffuse.sampler.clone()).unwrap() // TODO: delet this
.build().unwrap());
let mut builder = PersistentDescriptorSet::start(descriptor_set_layout.clone());
builder.add_buffer(uniform_buffer.clone()).unwrap()
.add_sampled_image(diffuse_view.clone(), diffuse.sampler.clone()).unwrap();
vec![descriptor_set]
vec![Arc::new(builder.build().unwrap())]
}).collect()
}

View File

@@ -1,10 +1,8 @@
use crate::RenderConfig;
use std::sync::Arc;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::format::Format;
use vulkano::device::Device;
use vulkano::{device::Device, format::Format, render_pass::RenderPass};
pub fn create_render_pass(device: Arc<Device>, render_config: &RenderConfig, swapchain_format: Format) -> Arc<dyn RenderPassAbstract + Send + Sync> {
pub fn create_render_pass(device: Arc<Device>, render_config: &RenderConfig, swapchain_format: Format) -> Arc<RenderPass> {
if render_config.msaa_samples > 0 {
Arc::new(vulkano::single_pass_renderpass!(
device.clone(),
@@ -24,7 +22,7 @@ pub fn create_render_pass(device: Arc<Device>, render_config: &RenderConfig, swa
depth: {
load: Clear,
store: Store,
format: Format::D16Unorm,
format: Format::D16_UNORM,
samples: render_config.msaa_samples,
initial_layout: ImageLayout::Undefined,
final_layout: ImageLayout::DepthStencilAttachmentOptimal,
@@ -49,7 +47,7 @@ pub fn create_render_pass(device: Arc<Device>, render_config: &RenderConfig, swa
depth: {
load: Clear,
store: Store,
format: Format::D16Unorm,
format: Format::D16_UNORM,
samples: 1,
initial_layout: ImageLayout::Undefined,
final_layout: ImageLayout::DepthStencilAttachmentOptimal,