triangle GET
parent
6a53f5fc69
commit
dfef4de4d8
|
@ -9,6 +9,7 @@ rust_binary(
|
||||||
"src/render/vulkan/mod.rs",
|
"src/render/vulkan/mod.rs",
|
||||||
"src/render/vulkan/binding.rs",
|
"src/render/vulkan/binding.rs",
|
||||||
"src/render/vulkan/qfi.rs",
|
"src/render/vulkan/qfi.rs",
|
||||||
|
"src/render/vulkan/shaders.rs",
|
||||||
"src/render/vulkan/swapchains.rs",
|
"src/render/vulkan/swapchains.rs",
|
||||||
],
|
],
|
||||||
deps = [
|
deps = [
|
||||||
|
@ -17,5 +18,10 @@ rust_binary(
|
||||||
"//third_party/cargo:env_logger",
|
"//third_party/cargo:env_logger",
|
||||||
"//third_party/cargo:vulkano",
|
"//third_party/cargo:vulkano",
|
||||||
"//third_party/cargo:vulkano_win",
|
"//third_party/cargo:vulkano_win",
|
||||||
|
"@io_bazel_rules_rust//tools/runfiles",
|
||||||
|
],
|
||||||
|
data = [
|
||||||
|
"//engine/shaders:triangle_vert",
|
||||||
|
"//engine/shaders:triangle_frag",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ glsl_binary(
|
||||||
srcs = [
|
srcs = [
|
||||||
"triangle.vert"
|
"triangle.vert"
|
||||||
],
|
],
|
||||||
|
visibility = ["//engine:__pkg__"],
|
||||||
)
|
)
|
||||||
|
|
||||||
glsl_binary(
|
glsl_binary(
|
||||||
|
@ -12,4 +13,5 @@ glsl_binary(
|
||||||
srcs = [
|
srcs = [
|
||||||
"triangle.frag"
|
"triangle.frag"
|
||||||
],
|
],
|
||||||
|
visibility = ["//engine:__pkg__"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
#version 450
|
#version 450
|
||||||
#extension GL_ARB_separate_shader_objects : enable
|
#extension GL_ARB_separate_shader_objects : enable
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 fragColor;
|
||||||
layout(location = 0) out vec4 outColor;
|
layout(location = 0) out vec4 outColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(1.0, 0.0, 0.0, 1.0);
|
outColor = vec4(fragColor, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ impl Renderer {
|
||||||
let mut instance = vulkan::Instance::new("abrasion".to_string());
|
let mut instance = vulkan::Instance::new("abrasion".to_string());
|
||||||
let (events_loop, surface) = Self::init_window(instance.get_vulkan());
|
let (events_loop, surface) = Self::init_window(instance.get_vulkan());
|
||||||
instance.use_surface(&surface);
|
instance.use_surface(&surface);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
instance,
|
instance,
|
||||||
events_loop,
|
events_loop,
|
||||||
|
@ -43,8 +44,15 @@ impl Renderer {
|
||||||
(events_loop, surface)
|
(events_loop, surface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn draw_frame(&mut self) {
|
||||||
|
let future = self.instance.flip();
|
||||||
|
future.wait(None).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn main_loop(&mut self) {
|
pub fn main_loop(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
|
self.draw_frame();
|
||||||
|
|
||||||
let mut done = false;
|
let mut done = false;
|
||||||
self.events_loop.poll_events(|ev| {
|
self.events_loop.poll_events(|ev| {
|
||||||
if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev {
|
if let Event::WindowEvent { event: WindowEvent::CloseRequested, .. } = ev {
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use log;
|
use log;
|
||||||
|
|
||||||
|
use vulkano::command_buffer as vc;
|
||||||
use vulkano::instance as vi;
|
use vulkano::instance as vi;
|
||||||
use vulkano::swapchain as vs;
|
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 binding;
|
||||||
|
mod shaders;
|
||||||
mod swapchains;
|
mod swapchains;
|
||||||
mod qfi;
|
mod qfi;
|
||||||
|
|
||||||
|
@ -23,9 +27,12 @@ pub struct Instance<WT> {
|
||||||
|
|
||||||
binding: Option<binding::Binding<WT>>,
|
binding: Option<binding::Binding<WT>>,
|
||||||
swapchains: Option<swapchains::Swapchains<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 {
|
pub fn new(name: String) -> Self {
|
||||||
let ai = vi::ApplicationInfo {
|
let ai = vi::ApplicationInfo {
|
||||||
application_name: Some(name.clone().into()),
|
application_name: Some(name.clone().into()),
|
||||||
|
@ -46,6 +53,9 @@ impl<WT> Instance<WT> {
|
||||||
|
|
||||||
binding: None,
|
binding: None,
|
||||||
swapchains: None,
|
swapchains: None,
|
||||||
|
render_pass: None,
|
||||||
|
framebuffers: vec![],
|
||||||
|
command_buffers: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,11 +63,95 @@ impl<WT> Instance<WT> {
|
||||||
self.vulkan.clone()
|
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>>) {
|
pub fn use_surface(&mut self, surface: &Arc<vs::Surface<WT>>) {
|
||||||
self.binding = Some(binding::Binding::new(&self.vulkan, &surface));
|
self.binding = Some(binding::Binding::new(&self.vulkan, &surface));
|
||||||
self.swapchains = Some(swapchains::Swapchains::new(self.binding.as_ref().unwrap()));
|
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());
|
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")
|
}).expect("could not create debug callback")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {}
|
|
@ -6,8 +6,8 @@ use vulkano::format as vf;
|
||||||
use vulkano::sync as vy;
|
use vulkano::sync as vy;
|
||||||
|
|
||||||
pub struct Swapchains<WT> {
|
pub struct Swapchains<WT> {
|
||||||
chain: Arc<vs::Swapchain<WT>>,
|
pub chain: Arc<vs::Swapchain<WT>>,
|
||||||
images: Vec<Arc<vm::SwapchainImage<WT>>>,
|
pub images: Vec<Arc<vm::SwapchainImage<WT>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<WT> Swapchains<WT> {
|
impl<WT> Swapchains<WT> {
|
||||||
|
|
Loading…
Reference in New Issue