231 lines
9.4 KiB
Rust
231 lines
9.4 KiB
Rust
// Copyright 2020 Sergiusz 'q3k' Bazanski <q3k@q3k.org>
|
|
//
|
|
// This file is part of Abrasion.
|
|
//
|
|
// Abrasion is free software: you can redistribute it and/or modify it under
|
|
// the terms of the GNU General Public License as published by the Free
|
|
// Software Foundation, version 3.
|
|
//
|
|
// Abrasion is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
// details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with
|
|
// Abrasion. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
use std::borrow::Cow;
|
|
use std::sync::Arc;
|
|
|
|
use vulkano::buffer as vb;
|
|
use vulkano::descriptor::descriptor as vdD;
|
|
use vulkano::descriptor::descriptor_set 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::memory as vm;
|
|
use vulkano::pipeline as vp;
|
|
use vulkano::pipeline::shader as vps;
|
|
use vulkano::pipeline::vertex as vpv;
|
|
use vulkano::sampler as vs;
|
|
|
|
use crate::render::vulkan::data;
|
|
use crate::render::vulkan::shaders;
|
|
use crate::render::vulkan::pipeline;
|
|
|
|
pub struct Forward {
|
|
pipeline: Arc<pipeline::VulkanoPipeline>,
|
|
descriptor_set_pool: vdd::FixedSizeDescriptorSetsPool,
|
|
device: Arc<vd::Device>,
|
|
}
|
|
|
|
impl Forward {
|
|
pub fn new(
|
|
device: Arc<vd::Device>,
|
|
viewport_dimensions: [u32; 2],
|
|
render_pass: Arc<dyn vf::RenderPassAbstract + Send + Sync>,
|
|
) -> Forward {
|
|
let vertex_shader = shaders::ShaderDefinition {
|
|
name: "//assets/shaders/forward_vert.spv".to_string(),
|
|
ty: vps::GraphicsShaderType::Vertex,
|
|
inputs: vec![
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 0..1, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("pos")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 1..2, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("normal")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 2..6, format: Format::R32G32B32A32Sfloat,
|
|
name: Some(Cow::Borrowed("model")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 6..7, format: Format::R32G32Sfloat,
|
|
name: Some(Cow::Borrowed("tex")),
|
|
},
|
|
],
|
|
outputs: vec![
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 0..1, format: Format::R32G32Sfloat,
|
|
name: Some(Cow::Borrowed("fragTexCoord")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 1..2, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("fragWorldPos")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 2..3, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("fragNormal")),
|
|
},
|
|
],
|
|
uniforms: vec![],
|
|
push_constants: vec![
|
|
vdp::PipelineLayoutDescPcRange {
|
|
offset: 0,
|
|
size: 64usize,
|
|
stages: vdD::ShaderStages {
|
|
vertex: true,
|
|
..vdD::ShaderStages::none()
|
|
},
|
|
},
|
|
],
|
|
}.load_into(device.clone()).expect("could not load vertex shader");
|
|
|
|
let fragment_shader = shaders::ShaderDefinition {
|
|
name: "//assets/shaders/forward_frag.spv".to_string(),
|
|
ty: vps::GraphicsShaderType::Fragment,
|
|
inputs: vec![
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 0..1, format: Format::R32G32Sfloat,
|
|
name: Some(Cow::Borrowed("fragTexCoord")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 1..2, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("fragWorldPos")),
|
|
},
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 2..3, format: Format::R32G32B32Sfloat,
|
|
name: Some(Cow::Borrowed("fragNormal")),
|
|
},
|
|
],
|
|
outputs: vec![
|
|
vps::ShaderInterfaceDefEntry {
|
|
location: 0..1, format: Format::R32G32B32A32Sfloat,
|
|
name: Some(Cow::Borrowed("outColor")),
|
|
}
|
|
],
|
|
uniforms: vec![
|
|
vdD::DescriptorDesc {
|
|
ty: vdD::DescriptorDescTy::Buffer(vdD::DescriptorBufferDesc {
|
|
dynamic: Some(false),
|
|
storage: false,
|
|
}),
|
|
array_count: 1,
|
|
readonly: true,
|
|
stages: vdD::ShaderStages {
|
|
fragment: true,
|
|
..vdD::ShaderStages::none()
|
|
},
|
|
},
|
|
vdD::DescriptorDesc {
|
|
ty: vdD::DescriptorDescTy::CombinedImageSampler(vdD::DescriptorImageDesc {
|
|
sampled: true,
|
|
dimensions: vdD::DescriptorImageDescDimensions::TwoDimensional,
|
|
format: None,
|
|
multisampled: false,
|
|
array_layers: vdD::DescriptorImageDescArray::NonArrayed,
|
|
}),
|
|
array_count: 1,
|
|
readonly: true,
|
|
stages: vdD::ShaderStages {
|
|
fragment: true,
|
|
..vdD::ShaderStages::none()
|
|
},
|
|
},
|
|
vdD::DescriptorDesc {
|
|
ty: vdD::DescriptorDescTy::CombinedImageSampler(vdD::DescriptorImageDesc {
|
|
sampled: true,
|
|
dimensions: vdD::DescriptorImageDescDimensions::TwoDimensional,
|
|
format: None,
|
|
multisampled: false,
|
|
array_layers: vdD::DescriptorImageDescArray::NonArrayed,
|
|
}),
|
|
array_count: 1,
|
|
readonly: true,
|
|
stages: vdD::ShaderStages {
|
|
fragment: true,
|
|
..vdD::ShaderStages::none()
|
|
},
|
|
},
|
|
],
|
|
push_constants: vec![
|
|
],
|
|
}.load_into(device.clone()).expect("could not load fragment shader");
|
|
|
|
let dimensions = [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32];
|
|
let viewport = vp::viewport::Viewport {
|
|
origin: [0.0, 0.0],
|
|
dimensions,
|
|
depth_range: 0.0 .. 1.0,
|
|
};
|
|
|
|
// Counter-clockwise facing triangles - this is because geometry data is left-handed, and
|
|
// the vertex shader performs a handedness flip by doing .y *= -1 on emitted vertices. To
|
|
// keep geomtry-space triangles clockwise after this transformation, the pipeline must be
|
|
// set to treat counter-clockwise triangles as front-facing. An alternative would be to
|
|
// fully embrace the vulkan coordinate system, including geometry - however this goes
|
|
// against most existing software and practices. This might bite us in the ass at some
|
|
// point in the future.
|
|
let pipeline = Arc::new(vp::GraphicsPipeline::start()
|
|
.vertex_input(vpv::OneVertexOneInstanceDefinition::<data::Vertex, data::Instance>::new())
|
|
.vertex_shader(vertex_shader.entry_point(), ())
|
|
.triangle_list()
|
|
.primitive_restart(false)
|
|
.viewports(vec![viewport])
|
|
.fragment_shader(fragment_shader.entry_point(), ())
|
|
.depth_clamp(false)
|
|
.polygon_mode_fill()
|
|
.line_width(1.0)
|
|
.cull_mode_back()
|
|
.front_face_counter_clockwise()
|
|
.blend_pass_through()
|
|
.depth_stencil(vulkano::pipeline::depth_stencil::DepthStencil::simple_depth_test())
|
|
.render_pass(vf::Subpass::from(render_pass.clone(), 0).unwrap())
|
|
.build(device.clone())
|
|
.unwrap())
|
|
as Arc<pipeline::VulkanoPipeline>;
|
|
|
|
let layout = pipeline.descriptor_set_layout(0).unwrap();
|
|
let descriptor_set_pool = vdd::FixedSizeDescriptorSetsPool::new(layout.clone());
|
|
|
|
Forward {
|
|
pipeline,
|
|
descriptor_set_pool,
|
|
device
|
|
}
|
|
}
|
|
}
|
|
|
|
impl pipeline::Pipeline for Forward {
|
|
fn get_pipeline(&self) -> Arc<pipeline::VulkanoPipeline> {
|
|
self.pipeline.clone()
|
|
}
|
|
|
|
fn make_descriptor_set(
|
|
&mut self,
|
|
textures: data::Textures,
|
|
fragment_ubo_buffer: Arc<vb::cpu_pool::CpuBufferPoolSubbuffer<data::FragmentUniformBufferObject, Arc<vm::pool::StdMemoryPool>>>,
|
|
) -> Arc<pipeline::VulkanoDescriptorSet> {
|
|
let image_sampler = vs::Sampler::simple_repeat_linear(self.device.clone());
|
|
|
|
Arc::new(self.descriptor_set_pool.next()
|
|
.add_buffer(fragment_ubo_buffer).unwrap()
|
|
.add_sampled_image(textures.diffuse.clone(), image_sampler.clone()).unwrap()
|
|
.add_sampled_image(textures.roughness.clone(), image_sampler.clone()).unwrap()
|
|
.build().unwrap())
|
|
}
|
|
}
|