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; type Context;
/// Consume the object and return the compiled output of the shader. /// 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( fn compile(
self, self,
options: Self::Options, options: Self::Options,
@ -139,6 +142,10 @@ where
) -> Result<ShaderReflection, ShaderReflectError> { ) -> Result<ShaderReflection, ShaderReflectError> {
self.backend.reflect(pass_number, semantics) self.backend.reflect(pass_number, semantics)
} }
fn validate(&mut self) -> Result<(), ShaderReflectError> {
self.backend.validate()
}
} }
impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> { impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> {
@ -149,6 +156,10 @@ impl<T: ReflectShader + ?Sized> ReflectShader for Box<T> {
) -> Result<ShaderReflection, ShaderReflectError> { ) -> Result<ShaderReflection, ShaderReflectError> {
(**self).reflect(pass_number, semantics) (**self).reflect(pass_number, semantics)
} }
fn validate(&mut self) -> Result<(), ShaderReflectError> {
(**self).validate()
}
} }
impl<O, T> CompileShader<T> for Box<O> impl<O, T> CompileShader<T> for Box<O>

View file

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

View file

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

View file

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

View file

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

View file

@ -219,7 +219,10 @@ impl ShaderSemantics {
/// Create pass semantics for a single pass in the given shader preset. /// Create pass semantics for a single pass in the given shader preset.
/// ///
/// This is meant as a convenience function for reflection use only. /// 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 where
E: From<ShaderReflectError>, E: From<ShaderReflectError>,
E: From<PreprocessError>, E: From<PreprocessError>,
@ -268,6 +271,4 @@ impl ShaderSemantics {
texture_semantics, texture_semantics,
}) })
} }
} }