use gfx_hal::{
device::Device,
pso::Specialization as ShaderSpecializations,
};
#[cfg(test)]
use mockall::automock;
use super::gpu;
pub enum ShaderModuleType {
Vertex,
Fragment,
Compute,
}
pub struct ShaderModuleBuilder {
entry_name: String,
specializations: ShaderSpecializations<'static>,
}
#[cfg_attr(test, automock)]
impl ShaderModuleBuilder {
pub fn new() -> Self {
return Self {
entry_name: "main".to_string(),
specializations: ShaderSpecializations::EMPTY,
};
}
pub fn with_entry_name(mut self, entry_name: &str) -> Self {
self.entry_name = entry_name.to_string();
return self;
}
pub fn with_specializations(
mut self,
specializations: ShaderSpecializations<'static>,
) -> Self {
self.specializations = specializations;
return self;
}
pub fn build<RenderBackend: gfx_hal::Backend>(
self,
gpu: &mut gpu::Gpu<RenderBackend>,
shader_binary: &Vec<u32>,
shader_type: ShaderModuleType,
) -> ShaderModule<RenderBackend> {
let shader_module = unsafe {
gpu
.internal_logical_device()
.create_shader_module(&shader_binary)
.expect("Failed to create a shader module.")
};
return ShaderModule {
entry_name: self.entry_name,
shader_module,
specializations: self.specializations,
shader_type,
};
}
}
pub struct ShaderModule<RenderBackend: gfx_hal::Backend> {
entry_name: String,
shader_module: RenderBackend::ShaderModule,
specializations: ShaderSpecializations<'static>,
shader_type: ShaderModuleType,
}
#[cfg_attr(test, automock)]
impl<RenderBackend: gfx_hal::Backend> ShaderModule<RenderBackend> {
pub fn destroy(self, gpu: &mut gpu::Gpu<RenderBackend>) {
unsafe {
gpu
.internal_logical_device()
.destroy_shader_module(self.shader_module)
}
}
pub fn entry(&self) -> &str {
return self.entry_name.as_str();
}
pub fn specializations(&self) -> &ShaderSpecializations<'static> {
return &self.specializations;
}
}
#[cfg(test)]
mod tests {
#[test]
fn shader_builder_initial_state() {
let shader_builder = super::ShaderModuleBuilder::new();
assert_eq!(shader_builder.entry_name, "main");
assert_eq!(shader_builder.specializations.data.len(), 0);
}
#[test]
fn shader_builder_with_properties() {
let shader_builder = super::ShaderModuleBuilder::new()
.with_entry_name("test")
.with_specializations(super::ShaderSpecializations::default());
assert_eq!(shader_builder.entry_name, "test");
assert_eq!(
shader_builder.specializations.data,
super::ShaderSpecializations::default().data
);
}
#[test]
fn shader_builder_builds_correctly() {
let shader_builder = super::ShaderModuleBuilder::new()
.with_entry_name("test")
.with_specializations(super::ShaderSpecializations::default());
}
}
pub mod internal {
use super::ShaderModule;
#[inline]
pub fn module_for<RenderBackend: gfx_hal::Backend>(
shader_module: &ShaderModule<RenderBackend>,
) -> &RenderBackend::ShaderModule {
return &shader_module.shader_module;
}
}