triangle GET

ecs
q3k 2020-01-19 16:59:05 +01:00
parent 6a53f5fc69
commit dfef4de4d8
7 changed files with 296 additions and 7 deletions

View File

@ -9,6 +9,7 @@ rust_binary(
"src/render/vulkan/mod.rs",
"src/render/vulkan/binding.rs",
"src/render/vulkan/qfi.rs",
"src/render/vulkan/shaders.rs",
"src/render/vulkan/swapchains.rs",
],
deps = [
@ -17,5 +18,10 @@ rust_binary(
"//third_party/cargo:env_logger",
"//third_party/cargo:vulkano",
"//third_party/cargo:vulkano_win",
"@io_bazel_rules_rust//tools/runfiles",
],
data = [
"//engine/shaders:triangle_vert",
"//engine/shaders:triangle_frag",
],
)

View File

@ -5,6 +5,7 @@ glsl_binary(
srcs = [
"triangle.vert"
],
visibility = ["//engine:__pkg__"],
)
glsl_binary(
@ -12,4 +13,5 @@ glsl_binary(
srcs = [
"triangle.frag"
],
visibility = ["//engine:__pkg__"],
)

View File

@ -2,8 +2,9 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec3 fragColor;
layout(location = 0) out vec4 outColor;
void main() {
outColor = vec4(1.0, 0.0, 0.0, 1.0);
outColor = vec4(fragColor, 1.0);
}

View File

@ -27,6 +27,7 @@ impl Renderer {
let mut instance = vulkan::Instance::new("abrasion".to_string());
let (events_loop, surface) = Self::init_window(instance.get_vulkan());
instance.use_surface(&surface);
Self {
instance,
events_loop,
@ -43,8 +44,15 @@ impl Renderer {
(events_loop, surface)
}
fn draw_frame(&mut self) {
let future = self.instance.flip();
future.wait(None).unwrap()
}
pub fn main_loop(&mut self) {
loop {
self.draw_frame();
let mut done = false;
self.events_loop.poll_events(|ev| {
if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev {

View File

@ -1,11 +1,15 @@
use std::sync::Arc;
use log;
use vulkano::command_buffer as vc;
use vulkano::instance as vi;
use vulkano::swapchain as vs;
use std::ops::Deref;
use vulkano::framebuffer as vf;
use vulkano::pipeline::vertex as vpv;
use vulkano::sync::{FenceSignalFuture, GpuFuture};
mod binding;
mod shaders;
mod swapchains;
mod qfi;
@ -23,9 +27,12 @@ pub struct Instance<WT> {
binding: Option<binding::Binding<WT>>,
swapchains: Option<swapchains::Swapchains<WT>>,
render_pass: Option<Arc<dyn vf::RenderPassAbstract + Send + Sync>>,
framebuffers: Vec<Arc<dyn vf::FramebufferAbstract + Send + Sync>>,
command_buffers: Vec<Arc<vc::AutoCommandBuffer>>,
}
impl<WT> Instance<WT> {
impl<WT: 'static + Send + Sync> Instance<WT> {
pub fn new(name: String) -> Self {
let ai = vi::ApplicationInfo {
application_name: Some(name.clone().into()),
@ -46,6 +53,9 @@ impl<WT> Instance<WT> {
binding: None,
swapchains: None,
render_pass: None,
framebuffers: vec![],
command_buffers: vec![],
}
}
@ -53,11 +63,95 @@ impl<WT> Instance<WT> {
self.vulkan.clone()
}
pub fn get_swapchain(&self) -> Arc<vs::Swapchain<WT>> {
self.swapchains.as_ref().unwrap().chain.clone()
}
pub fn use_surface(&mut self, surface: &Arc<vs::Surface<WT>>) {
self.binding = Some(binding::Binding::new(&self.vulkan, &surface));
self.swapchains = Some(swapchains::Swapchains::new(self.binding.as_ref().unwrap()));
log::info!("Bound to Vulkan Device: {}", self.binding.as_ref().unwrap().physical_device().name());
let device = self.binding.as_ref().unwrap().device.clone();
let chain = self.get_swapchain();
self.create_render_pass(chain.format());
let render_pass = self.render_pass.as_ref().unwrap().clone();
let pipeline = shaders::pipeline_triangle(device, chain.dimensions(), render_pass);
self.create_framebuffers();
self.create_command_buffers(pipeline);
}
pub fn flip(&self) -> FenceSignalFuture<vs::PresentFuture<vc::CommandBufferExecFuture<vs::SwapchainAcquireFuture<WT>, Arc<vc::AutoCommandBuffer>>, WT>> {
let chain = self.get_swapchain();
let (image_index, acquire_future) = vs::acquire_next_image(chain.clone(), None).unwrap();
let command_buffer = self.command_buffers[image_index].clone();
let gq = self.binding.as_ref().unwrap().graphics_queue.clone();
let pq = self.binding.as_ref().unwrap().present_queue.clone();
acquire_future
.then_execute(gq, command_buffer)
.unwrap()
.then_swapchain_present(pq, chain, image_index)
.then_signal_fence_and_flush()
.unwrap()
}
fn create_render_pass(&mut self, color_format: vulkano::format::Format) {
let device = self.binding.as_ref().unwrap().device.clone();
self.render_pass = Some(Arc::new(vulkano::single_pass_renderpass!(device.clone(),
attachments: {
color: {
load: Clear,
store: Store,
format: color_format,
samples: 1,
}
},
pass: {
color: [color],
depth_stencil: {}
}
).unwrap()))
}
fn create_framebuffers(&mut self) {
let render_pass = self.render_pass.as_ref().unwrap().clone();
self.framebuffers = self.swapchains.as_ref().unwrap().images.iter()
.map(|image| {
let fba: Arc<dyn vf::FramebufferAbstract + Send + Sync> = Arc::new(vf::Framebuffer::start(render_pass.clone())
.add(image.clone()).unwrap()
.build().unwrap());
fba
})
.collect::<Vec<_>>();
}
fn create_command_buffers(&mut self, pipeline: Arc<shaders::ConcreteGraphicsPipeline>) {
let device = self.binding.as_ref().unwrap().device.clone();
let qf = self.binding.as_ref().unwrap().graphics_queue.family();
self.command_buffers = self.framebuffers.iter()
.map(|framebuffer| {
let vertices = vpv::BufferlessVertices { vertices: 3, instances: 1 };
Arc::new(vc::AutoCommandBufferBuilder::primary_simultaneous_use(device.clone(), qf)
.unwrap()
.begin_render_pass(framebuffer.clone(), false, vec![[0.0, 0.0, 0.0, 1.0].into()])
.unwrap()
.draw(pipeline.clone(), &vc::DynamicState::none(),
vertices, (), ())
.unwrap()
.end_render_pass()
.unwrap()
.build()
.unwrap())
})
.collect();
}
@ -74,5 +168,3 @@ impl<WT> Instance<WT> {
}).expect("could not create debug callback")
}
}

View File

@ -0,0 +1,180 @@
use log;
use std::borrow::Cow;
use std::ffi::CStr;
use std::fs::File;
use std::io::prelude::*;
use std::sync::Arc;
use runfiles::Runfiles;
use vulkano::descriptor as vD;
use vulkano::descriptor::descriptor as vdd;
use vulkano::descriptor::pipeline_layout as vdp;
use vulkano::device as vd;
use vulkano::format::Format;
use vulkano::framebuffer as vf;
use vulkano::pipeline as vp;
use vulkano::pipeline::shader as vps;
use vulkano::pipeline::vertex as vpv;
pub type ConcreteGraphicsPipeline = vp::GraphicsPipeline<vpv::BufferlessDefinition, Box<dyn vD::PipelineLayoutAbstract + Send + Sync + 'static>, Arc<dyn vf::RenderPassAbstract + Send + Sync + 'static>>;
pub fn pipeline_triangle(
device: Arc<vd::Device>,
swap_chain_extent: [u32; 2],
render_pass: Arc<dyn vf::RenderPassAbstract + Send + Sync>,
) -> Arc<ConcreteGraphicsPipeline> {
let vertex = ShaderDefinition {
name: "triangle_vert.spv".to_string(),
ty: vps::GraphicsShaderType::Vertex,
inputs: vec![],
outputs: vec![
vps::ShaderInterfaceDefEntry { location: 0..1, format: Format::R32G32B32Sfloat, name: Some(Cow::Borrowed("fragColor")) }
],
}.load_into(device.clone()).expect("could not load vertex shader");
let fragment = ShaderDefinition {
name: "triangle_frag.spv".to_string(),
ty: vps::GraphicsShaderType::Fragment,
inputs: vec![
vps::ShaderInterfaceDefEntry { location: 0..1, format: Format::R32G32B32Sfloat, name: Some(Cow::Borrowed("fragColor")) }
],
outputs: vec![
vps::ShaderInterfaceDefEntry { location: 0..1, format: Format::R32G32B32A32Sfloat, name: Some(Cow::Borrowed("outColor")) }
],
}.load_into(device.clone()).expect("could not load fragment shader");
let dimensions = [swap_chain_extent[0] as f32, swap_chain_extent[1] as f32];
let viewport = vp::viewport::Viewport {
origin: [0.0, 0.0],
dimensions,
depth_range: 0.0 .. 1.0,
};
Arc::new(vp::GraphicsPipeline::start()
.vertex_input(vpv::BufferlessDefinition {})
.vertex_shader(vertex.entry_point(), ())
.triangle_list()
.primitive_restart(false)
.viewports(vec![viewport])
.fragment_shader(fragment.entry_point(), ())
.depth_clamp(false)
.polygon_mode_fill()
.line_width(1.0)
.cull_mode_back()
.front_face_clockwise()
.blend_pass_through()
.render_pass(vf::Subpass::from(render_pass.clone(), 0).unwrap())
.build(device.clone())
.unwrap()
)
}
struct ShaderDefinition {
name: String,
ty: vps::GraphicsShaderType,
inputs: Vec<vps::ShaderInterfaceDefEntry>,
outputs: Vec<vps::ShaderInterfaceDefEntry>,
}
impl ShaderDefinition {
fn load_into(self, device: Arc<vd::Device>) -> Result<LoadedShader, String> {
fn stringify(x: std::io::Error) -> String { format!("IO error: {}", x) }
let r = Runfiles::create().map_err(stringify)?;
let path = r.rlocation(format!("abrasion/engine/shaders/{}", self.name));
log::info!("Loading shader {}", path.to_str().unwrap_or("UNKNOWN"));
let mut f = File::open(path).map_err(stringify)?;
let mut v = vec![];
f.read_to_end(&mut v).map_err(stringify)?;
let module = unsafe {
vps::ShaderModule::new(device.clone(), &v).unwrap()
};
Ok(LoadedShader {
def: self,
module: module,
})
}
}
struct LoadedShader {
def: ShaderDefinition,
module: Arc<vps::ShaderModule>,
}
impl LoadedShader {
fn ios(&self) -> (ShaderInterface, ShaderInterface) {
(
ShaderInterface { entries: self.def.inputs.clone() },
ShaderInterface { entries: self.def.outputs.clone() },
)
}
fn layout(&self) -> ShaderLayout {
match self.def.ty {
vps::GraphicsShaderType::Vertex => ShaderLayout(vdd::ShaderStages{ vertex: true, ..vdd::ShaderStages::none() }),
vps::GraphicsShaderType::Fragment => ShaderLayout(vdd::ShaderStages{ fragment: true, ..vdd::ShaderStages::none() }),
_ => panic!("unknown shader type")
}
}
pub fn entry_point<'a, S>(&'a self) -> vps::GraphicsEntryPoint<'a, S, ShaderInterface, ShaderInterface, ShaderLayout> {
let (input, output) = self.ios();
let layout = self.layout();
unsafe {
self.module.graphics_entry_point(
CStr::from_bytes_with_nul_unchecked(b"main\0"),
input,
output,
layout,
self.def.ty)
}
}
}
#[derive (Debug, Clone)]
struct ShaderLayout(vdd::ShaderStages);
unsafe impl vdp::PipelineLayoutDesc for ShaderLayout {
fn num_sets(&self) -> usize { 0 }
fn num_bindings_in_set(&self, _set: usize) -> Option<usize> { None }
fn descriptor(&self, _set: usize, _binding: usize) -> Option<vdd::DescriptorDesc> { None }
fn num_push_constants_ranges(&self) -> usize { 0 }
fn push_constants_range(&self, _num: usize) -> Option<vdp::PipelineLayoutDescPcRange> { None }
}
struct ShaderInterface {
entries: Vec<vps::ShaderInterfaceDefEntry>,
}
unsafe impl vps::ShaderInterfaceDef for ShaderInterface {
type Iter = InterfaceIterator;
fn elements(&self) -> Self::Iter {
InterfaceIterator {
entries: self.entries.clone(),
}
}
}
pub struct InterfaceIterator {
entries: Vec<vps::ShaderInterfaceDefEntry>,
}
impl std::iter::Iterator for InterfaceIterator {
type Item = vps::ShaderInterfaceDefEntry;
fn next(&mut self) -> Option<vps::ShaderInterfaceDefEntry> {
let cur = self.entries.first()?.clone();
self.entries = self.entries[1..].to_vec();
Some(cur)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.entries.len();
(len, Some(len))
}
}
impl std::iter::ExactSizeIterator for InterfaceIterator {}

View File

@ -6,8 +6,8 @@ use vulkano::format as vf;
use vulkano::sync as vy;
pub struct Swapchains<WT> {
chain: Arc<vs::Swapchain<WT>>,
images: Vec<Arc<vm::SwapchainImage<WT>>>,
pub chain: Arc<vs::Swapchain<WT>>,
pub images: Vec<Arc<vm::SwapchainImage<WT>>>,
}
impl<WT> Swapchains<WT> {