abrasion/engine/render/vulkan/shaders.rs

170 lines
4.8 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::ffi::CStr;
use std::fs::File;
use std::io::prelude::*;
use std::sync::Arc;
use vulkano::descriptor::descriptor as vdd;
use vulkano::descriptor::pipeline_layout as vdp;
use vulkano::device as vd;
use vulkano::pipeline::shader as vps;
use crate::util::file;
pub struct ShaderDefinition {
pub name: String,
pub ty: vps::GraphicsShaderType,
pub inputs: Vec<vps::ShaderInterfaceDefEntry>,
pub outputs: Vec<vps::ShaderInterfaceDefEntry>,
pub uniforms: Vec<vdd::DescriptorDesc>,
pub push_constants: Vec<vdp::PipelineLayoutDescPcRange>,
}
#[derive(Debug)]
pub enum ShaderError {
ResourceError(file::ResourceError),
IOError(std::io::Error),
}
impl From<file::ResourceError> for ShaderError {
fn from(v: file::ResourceError) -> Self {
ShaderError::ResourceError(v)
}
}
impl From<std::io::Error> for ShaderError {
fn from(v: std::io::Error) -> Self {
ShaderError::IOError(v)
}
}
type Result<T> = std::result::Result<T, ShaderError>;
impl ShaderDefinition {
pub fn load_into(self, device: Arc<vd::Device>) -> Result<LoadedShader> {
let mut r = file::resource(self.name.clone())?;
let mut v = vec![];
r.read_to_end(&mut v)?;
let module = unsafe {
vps::ShaderModule::new(device.clone(), &v).unwrap()
};
Ok(LoadedShader {
def: self,
module: module,
})
}
}
pub 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) -> RuntimeShaderLayout {
RuntimeShaderLayout{ descs: vec![self.def.uniforms.clone()], push_constants: self.def.push_constants.clone(), }
}
pub fn entry_point<'a, S>(&'a self) -> vps::GraphicsEntryPoint<'a, S, ShaderInterface, ShaderInterface, RuntimeShaderLayout> {
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)]
pub struct RuntimeShaderLayout {
descs: Vec<Vec<vdd::DescriptorDesc>>,
push_constants: Vec<vdp::PipelineLayoutDescPcRange>,
}
unsafe impl vdp::PipelineLayoutDesc for RuntimeShaderLayout {
fn num_sets(&self) -> usize { self.descs.len() }
fn num_bindings_in_set(&self, set: usize) -> Option<usize> {
if set >= self.descs.len() {
return None
}
Some(self.descs[set].len())
}
fn descriptor(&self, set: usize, binding: usize) -> Option<vdd::DescriptorDesc> {
if set >= self.descs.len() {
return None
}
if binding >= self.descs[set].len() {
return None
}
Some(self.descs[set][binding].clone())
}
fn num_push_constants_ranges(&self) -> usize { self.push_constants.len() }
fn push_constants_range(&self, num: usize) -> Option<vdp::PipelineLayoutDescPcRange> {
if num >= self.push_constants.len() {
return None
}
Some(self.push_constants[0].clone())
}
}
pub 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 {}