reflect: allow validation of shaders without reflecting against semantics

This commit is contained in:
chyyran 2024-09-26 03:21:14 -04:00 committed by Ronny Chan
parent 31ece05246
commit bac09ad2a3
6 changed files with 74 additions and 8 deletions

View file

@ -32,6 +32,9 @@ pub trait CompileShader<T: OutputTarget> {
type Context;
/// Consume the object and return the compiled output of the shader.
///
/// The shader should either be reflected or validated as
/// [ReflectShader] before being compiled, or the results may not be valid.
fn compile(
self,
options: Self::Options,
@ -139,6 +142,10 @@ where
) -> Result<ShaderReflection, ShaderReflectError> {
self.backend.reflect(pass_number, semantics)
}
fn validate(&mut self) -> Result<(), ShaderReflectError> {
self.backend.validate()
}
}
impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> {
@ -149,6 +156,10 @@ impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> {
) -> Result<ShaderReflection, ShaderReflectError> {
(**self).reflect(pass_number, semantics)
}
fn validate(&mut self) -> Result<(), ShaderReflectError> {
(**self).validate()
}
}
impl<O, T> CompileShader<T> for Box<O>

View file

@ -72,6 +72,10 @@ impl ReflectShader for WriteSpirV {
) -> Result<ShaderReflection, ShaderReflectError> {
self.reflect.reflect(pass_number, semantics)
}
fn validate(&mut self) -> Result<(), ShaderReflectError> {
self.reflect.validate()
}
}
impl CompileShader<SPIRV> for WriteSpirV {

View file

@ -160,7 +160,7 @@ impl<T> CrossReflect<T>
where
T: spirv_cross2::compile::CompilableTarget,
{
fn validate(
fn validate_semantics(
&self,
vertex_res: &AllResources,
fragment_res: &AllResources,
@ -714,7 +714,7 @@ where
) -> Result<ShaderReflection, ShaderReflectError> {
let vertex_res = self.vertex.shader_resources()?.all_resources()?;
let fragment_res = self.fragment.shader_resources()?.all_resources()?;
self.validate(&vertex_res, &fragment_res)?;
self.validate_semantics(&vertex_res, &fragment_res)?;
let vertex_ubo = vertex_res.uniform_buffers.first();
let fragment_ubo = fragment_res.uniform_buffers.first();
@ -797,6 +797,23 @@ where
meta,
})
}
fn validate(&mut self) -> Result<(), ShaderReflectError> {
let vertex_res = self.vertex.shader_resources()?.all_resources()?;
let fragment_res = self.fragment.shader_resources()?.all_resources()?;
self.validate_semantics(&vertex_res, &fragment_res)?;
let vertex_ubo = vertex_res.uniform_buffers.first();
let fragment_ubo = fragment_res.uniform_buffers.first();
self.reflect_ubos(vertex_ubo, fragment_ubo)?;
let vertex_push = vertex_res.push_constant_buffers.first();
let fragment_push = fragment_res.push_constant_buffers.first();
self.reflect_push_constant_buffer(vertex_push, fragment_push)?;
Ok(())
}
}
#[cfg(test)]

View file

@ -25,6 +25,9 @@ pub trait ReflectShader {
pass_number: usize,
semantics: &ShaderSemantics,
) -> Result<ShaderReflection, ShaderReflectError>;
/// Validate the shader without doing reflection against a set of semantics.
fn validate(&mut self) -> Result<(), ShaderReflectError>;
}
pub use semantics::ShaderReflection;

View file

@ -239,7 +239,7 @@ impl ValidateTypeSemantics<&TypeInner> for TextureSemantics {
impl NagaReflect {
fn reflect_ubos(
&mut self,
&self,
vertex_ubo: Option<Handle<GlobalVariable>>,
fragment_ubo: Option<Handle<GlobalVariable>>,
) -> Result<Option<BufferReflection<u32>>, ShaderReflectError> {
@ -429,7 +429,7 @@ impl NagaReflect {
}
}
fn validate(&self) -> Result<(), ShaderReflectError> {
fn validate_semantics(&self) -> Result<(), ShaderReflectError> {
// Verify types
if self.vertex.global_variables.iter().any(|(_, gv)| {
let ty = &self.vertex.types[gv.ty];
@ -882,7 +882,7 @@ impl ReflectShader for NagaReflect {
pass_number: usize,
semantics: &ShaderSemantics,
) -> Result<ShaderReflection, ShaderReflectError> {
self.validate()?;
self.validate_semantics()?;
// Validate verifies that there's only one uniform block.
let vertex_ubo = self
@ -1012,6 +1012,36 @@ impl ReflectShader for NagaReflect {
meta,
})
}
fn validate(&mut self) -> Result<(), ShaderReflectError> {
self.validate_semantics()?;
let vertex_push = self
.vertex
.global_variables
.iter()
.find_map(|(handle, gv)| {
if gv.space == AddressSpace::PushConstant {
Some(handle)
} else {
None
}
});
let fragment_push = self
.fragment
.global_variables
.iter()
.find_map(|(handle, gv)| {
if gv.space == AddressSpace::PushConstant {
Some(handle)
} else {
None
}
});
self.reflect_push_constant_buffer(vertex_push, fragment_push)?;
Ok(())
}
}
#[cfg(test)]

View file

@ -219,7 +219,10 @@ impl ShaderSemantics {
/// Create pass semantics for a single pass in the given shader preset.
///
/// This is meant as a convenience function for reflection use only.
pub fn create_pass_semantics<E>(preset: &ShaderPreset, index: usize) -> Result<ShaderSemantics, E>
pub fn create_pass_semantics<E>(
preset: &ShaderPreset,
index: usize,
) -> Result<ShaderSemantics, E>
where
E: From<ShaderReflectError>,
E: From<PreprocessError>,
@ -268,6 +271,4 @@ impl ShaderSemantics {
texture_semantics,
})
}
}