use crate::front::storage::ShaderObject;
use crate::front::compiler::{compile_ir, Language};
use crate::back::{GPUDevice, WGPUShader, RenderPipelineBuilder};
use std::collections::HashMap;
pub struct Duo {
pub shader_object: ShaderObject,
pub pipeline: wgpu::RenderPipeline,
pub vertex_entry: String,
pub fragment_entry: Option<String>,
}
impl Duo {
pub fn new(shader_object: ShaderObject, pipeline: wgpu::RenderPipeline) -> Self {
let vertex_entry = shader_object.ir.metadata.entry_point.clone();
Self {
shader_object,
pipeline,
vertex_entry,
fragment_entry: None,
}
}
pub fn with_fragment_entry(mut self, entry: String) -> Self {
self.fragment_entry = Some(entry);
self
}
}
pub struct AssetManager {
gpu: GPUDevice,
shaders: HashMap<String, ShaderObject>,
pipelines: HashMap<String, Duo>,
}
impl AssetManager {
pub fn new() -> Self {
Self {
gpu: GPUDevice::new(),
shaders: HashMap::new(),
pipelines: HashMap::new(),
}
}
pub fn gpu_info(&self) -> wgpu::AdapterInfo {
self.gpu.info()
}
pub fn add_shader(
&mut self,
name: impl Into<String>,
source: &str,
stage: naga::ShaderStage,
language: Language,
) -> Result<(), String> {
let ir = compile_ir(source, stage, language)?;
let shader_obj = ShaderObject::new(ir, vec![]);
self.shaders.insert(name.into(), shader_obj);
Ok(())
}
pub fn add_shader_object(&mut self, name: impl Into<String>, shader_obj: ShaderObject) {
self.shaders.insert(name.into(), shader_obj);
}
pub fn get_shader(&self, name: &str) -> Option<&ShaderObject> {
self.shaders.get(name)
}
pub fn create_pipeline(
&mut self,
pipeline_name: impl Into<String>,
vertex_shader_name: &str,
fragment_shader_name: Option<&str>,
vertex_buffers: Vec<wgpu::VertexBufferLayout<'static>>,
color_format: wgpu::TextureFormat,
) -> Result<(), String> {
let vertex_obj = self.shaders.get(vertex_shader_name)
.ok_or_else(|| format!("Vertex shader '{}' not found", vertex_shader_name))?;
let vertex_shader = WGPUShader::from_shader_object(&self.gpu.device, vertex_obj);
let mut builder = RenderPipelineBuilder::new()
.vertex_shader(vertex_shader)
.vertex_buffers(vertex_buffers)
.color_target_format(color_format);
if let Some(frag_name) = fragment_shader_name {
let frag_obj = self.shaders.get(frag_name)
.ok_or_else(|| format!("Fragment shader '{}' not found", frag_name))?;
let fragment_shader = WGPUShader::from_shader_object(&self.gpu.device, frag_obj);
builder = builder.fragment_shader(fragment_shader);
}
let pipeline_layout = self.gpu.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let pipeline = builder.build(&self.gpu.device, &pipeline_layout)?;
let duo = Duo::new(vertex_obj.clone(), pipeline);
self.pipelines.insert(pipeline_name.into(), duo);
Ok(())
}
pub fn get_pipeline(&self, name: &str) -> Option<&Duo> {
self.pipelines.get(name)
}
pub fn get_pipeline_mut(&mut self, name: &str) -> Option<&mut Duo> {
self.pipelines.get_mut(name)
}
pub fn list_shaders(&self) -> Vec<&String> {
self.shaders.keys().collect()
}
pub fn list_pipelines(&self) -> Vec<&String> {
self.pipelines.keys().collect()
}
pub fn device(&self) -> &wgpu::Device {
&self.gpu.device
}
pub fn queue(&self) -> &wgpu::Queue {
&self.gpu.queue
}
pub fn adapter(&self) -> &wgpu::Adapter {
self.gpu.adapter()
}
pub fn instance(&self) -> &wgpu::Instance {
self.gpu.instance()
}
}
impl Default for AssetManager {
fn default() -> Self {
Self::new()
}
}