librashader/librashader-reflect/src/reflect/cross/glsl.rs
chyyran 4cc3c875bf reflect: allow compilation of boxed trait objects
Add a hidden `compile_boxed` function to CompileShader to support this. This is to allow Box<dyn CompileReflectShader> to work.
2024-09-15 03:10:45 -04:00

176 lines
6.6 KiB
Rust

use crate::back::glsl::CrossGlslContext;
use crate::back::targets::GLSL;
use crate::back::{CompileShader, ShaderCompilerOutput};
use crate::error::ShaderCompileError;
use crate::reflect::cross::{CompiledProgram, CrossReflect};
use spirv::Decoration;
use spirv_cross2::compile::CompilableTarget;
use spirv_cross2::reflect::{DecorationValue, ResourceType};
use spirv_cross2::{targets, SpirvCrossError};
pub(crate) type GlslReflect = CrossReflect<targets::Glsl>;
impl CompileShader<GLSL> for CrossReflect<targets::Glsl> {
type Options = spirv_cross2::compile::glsl::GlslVersion;
type Context = CrossGlslContext;
fn compile(
mut self,
version: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
let mut options = targets::Glsl::options();
options.version = version;
options.es_default_float_precision_highp = true;
options.es_default_int_precision_highp = true;
options.enable_420pack_extension = false;
let vertex_resources = self.vertex.shader_resources()?;
let fragment_resources = self.fragment.shader_resources()?;
for res in vertex_resources.resources_for_type(ResourceType::StageOutput)? {
// let location = self.vertex.get_decoration(res.id, Decoration::Location)?;
// self.vertex
// .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?;
self.vertex
.set_decoration(res.id, Decoration::Location, DecorationValue::unset())?;
}
for res in fragment_resources.resources_for_type(ResourceType::StageInput)? {
// let location = self.fragment.get_decoration(res.id, Decoration::Location)?;
// self.fragment
// .set_name(res.id, &format!("LIBRA_VARYING_{location}"))?;
self.fragment
.set_decoration(res.id, Decoration::Location, DecorationValue::unset())?;
}
let vertex_pcb = vertex_resources.resources_for_type(ResourceType::PushConstant)?;
if vertex_pcb.len() > 1 {
return Err(ShaderCompileError::SpirvCrossCompileError(
SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer",
)),
));
}
for res in vertex_pcb {
self.vertex
.set_name(res.id, c"LIBRA_PUSH_VERTEX_INSTANCE")?;
self.vertex
.set_name(res.base_type_id, c"LIBRA_PUSH_VERTEX")?;
}
// todo: options
let _flatten = false;
let vertex_ubo = vertex_resources.resources_for_type(ResourceType::UniformBuffer)?;
if vertex_ubo.len() > 1 {
return Err(ShaderCompileError::SpirvCrossCompileError(
SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer",
)),
));
}
for res in vertex_ubo {
// if flatten {
// self.vertex.flatten_buffer_block(res.id)?;
// }
self.vertex.set_name(res.id, c"LIBRA_UBO_VERTEX_INSTANCE")?;
self.vertex
.set_name(res.base_type_id, c"LIBRA_UBO_VERTEX")?;
self.vertex.set_decoration(
res.id,
Decoration::DescriptorSet,
DecorationValue::unset(),
)?;
self.vertex
.set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?;
}
let fragment_pcb = fragment_resources.resources_for_type(ResourceType::PushConstant)?;
if fragment_pcb.len() > 1 {
return Err(ShaderCompileError::SpirvCrossCompileError(
SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one push constant buffer",
)),
));
}
for res in fragment_pcb {
self.fragment
.set_name(res.id, c"LIBRA_PUSH_FRAGMENT_INSTANCE")?;
self.fragment
.set_name(res.base_type_id, c"LIBRA_PUSH_FRAGMENT")?;
}
let fragment_ubo = fragment_resources.resources_for_type(ResourceType::UniformBuffer)?;
if fragment_ubo.len() > 1 {
return Err(ShaderCompileError::SpirvCrossCompileError(
SpirvCrossError::InvalidArgument(String::from(
"Cannot have more than one uniform buffer",
)),
));
}
for res in fragment_ubo {
// if flatten {
// self.fragment.flatten_buffer_block(res.id)?;
// }
self.fragment
.set_name(res.id, c"LIBRA_UBO_FRAGMENT_INSTANCE")?;
self.fragment
.set_name(res.base_type_id, c"LIBRA_UBO_FRAGMENT")?;
self.fragment.set_decoration(
res.id,
Decoration::DescriptorSet,
DecorationValue::unset(),
)?;
self.fragment
.set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?;
}
let mut texture_fixups = Vec::new();
for res in fragment_resources.resources_for_type(ResourceType::SampledImage)? {
let Some(DecorationValue::Literal(binding)) =
self.fragment.decoration(res.id, Decoration::Binding)?
else {
continue;
};
self.fragment.set_decoration(
res.id,
Decoration::DescriptorSet,
DecorationValue::unset(),
)?;
self.fragment
.set_decoration(res.id, Decoration::Binding, DecorationValue::unset())?;
let mut name = res.name.to_string();
name.push('\0');
texture_fixups.push((name, binding));
}
let vertex_compiled = self.vertex.compile(&options)?;
let fragment_compiled = self.fragment.compile(&options)?;
Ok(ShaderCompilerOutput {
vertex: vertex_compiled.to_string(),
fragment: fragment_compiled.to_string(),
context: CrossGlslContext {
sampler_bindings: texture_fixups,
artifact: CompiledProgram {
vertex: vertex_compiled,
fragment: fragment_compiled,
},
},
})
}
fn compile_boxed(
self: Box<Self>,
options: Self::Options,
) -> Result<ShaderCompilerOutput<String, Self::Context>, ShaderCompileError> {
<CrossReflect<targets::Glsl> as CompileShader<GLSL>>::compile(*self, options)
}
}