use crate::error::{Result, ToContextError};
use crate::sealed::Sealed;
use crate::targets::Target;
use crate::{error, Compiler, CompilerStr, ContextRooted};
use spirv_cross_sys as sys;
use std::fmt::{Display, Formatter};
use std::ops::Deref;
#[cfg(feature = "glsl")]
#[cfg_attr(docsrs, doc(cfg(feature = "glsl")))]
pub mod glsl;
#[cfg(feature = "hlsl")]
#[cfg_attr(docsrs, doc(cfg(feature = "hlsl")))]
pub mod hlsl;
#[cfg(feature = "msl")]
#[cfg_attr(docsrs, doc(cfg(feature = "msl")))]
pub mod msl;
impl Sealed for CommonOptions {}
#[derive(Debug, spirv_cross2_derive::CompilerOptions)]
pub struct CommonOptions {
#[option(SPVC_COMPILER_OPTION_FORCE_TEMPORARY, false)]
pub force_temporary: bool,
#[option(SPVC_COMPILER_OPTION_FLATTEN_MULTIDIMENSIONAL_ARRAYS, false)]
pub flatten_multidimensional_arrays: bool,
#[option(SPVC_COMPILER_OPTION_FLIP_VERTEX_Y, false)]
pub flip_vertex_y: bool,
#[option(SPVC_COMPILER_OPTION_FIXUP_DEPTH_CONVENTION, false)]
pub fixup_clipspace: bool,
#[option(SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES, false)]
pub emit_line_directives: bool,
#[option(SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES, false)]
pub force_zero_initialized_variables: bool,
#[option(SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION, true)]
pub enable_storage_image_qualifier_deduction: bool,
#[option(SPVC_COMPILER_OPTION_RELAX_NAN_CHECKS, false)]
pub relax_nan_checks: bool,
}
pub struct CompiledArtifact<T> {
compiler: Compiler<T>,
source: CompilerStr<'static>,
}
impl<T> AsRef<str> for CompiledArtifact<T> {
fn as_ref(&self) -> &str {
self.source.as_ref()
}
}
impl<T> Display for CompiledArtifact<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.source, f)
}
}
impl<T> Deref for CompiledArtifact<T> {
type Target = Compiler<T>;
fn deref(&self) -> &Self::Target {
&self.compiler
}
}
impl<T: CompilableTarget> Compiler<T> {
pub fn add_header_line<'str>(&mut self, line: impl Into<CompilerStr<'str>>) -> Result<()> {
let line = line.into();
let cstring = line.into_cstring_ptr()?;
unsafe {
sys::spvc_compiler_add_header_line(self.ptr.as_ptr(), cstring.as_ptr()).ok(&*self)
}
}
pub fn require_extension<'str>(&mut self, ext: impl Into<CompilerStr<'str>>) -> Result<()> {
let ext = ext.into();
let cstring = ext.into_cstring_ptr()?;
unsafe {
sys::spvc_compiler_require_extension(self.ptr.as_ptr(), cstring.as_ptr().cast())
.ok(&*self)
}
}
fn set_compiler_options(&mut self, options: &T::Options) -> error::Result<()> {
use crate::compile::sealed::ApplyCompilerOptions;
unsafe {
let mut handle = std::ptr::null_mut();
sys::spvc_compiler_create_compiler_options(self.ptr.as_ptr(), &mut handle)
.ok(&*self)?;
options.apply(handle, &*self)?;
sys::spvc_compiler_install_compiler_options(self.ptr.as_ptr(), handle).ok(&*self)?;
Ok(())
}
}
pub fn compile(mut self, options: &T::Options) -> error::Result<CompiledArtifact<T>> {
self.set_compiler_options(options)?;
unsafe {
let mut src = std::ptr::null();
sys::spvc_compiler_compile(self.ptr.as_ptr(), &mut src).ok(&self)?;
let src = CompilerStr::from_ptr(src, self.ctx.drop_guard());
Ok(CompiledArtifact {
compiler: self,
source: src,
})
}
}
}
pub trait CompilerOptions: Default + sealed::ApplyCompilerOptions {}
pub(crate) mod sealed {
use crate::error;
use crate::error::ContextRooted;
use crate::sealed::Sealed;
use spirv_cross_sys::spvc_compiler_options;
pub trait ApplyCompilerOptions: Sealed {
#[doc(hidden)]
unsafe fn apply(
&self,
options: spvc_compiler_options,
root: impl ContextRooted + Copy,
) -> error::Result<()>;
}
}
#[cfg(test)]
mod test {
use crate::error::SpirvCrossError;
use crate::targets;
use crate::Compiler;
use crate::Module;
const BASIC_SPV: &[u8] = include_bytes!("../../basic.spv");
#[test]
pub fn create_compiler() -> Result<(), SpirvCrossError> {
let vec = Vec::from(BASIC_SPV);
let words = Module::from_words(bytemuck::cast_slice(&vec));
let compiler: Compiler<targets::None> = Compiler::new(words)?;
Ok(())
}
}
impl Sealed for NoOptions {}
#[derive(Debug, Default, spirv_cross2_derive::CompilerOptions)]
pub struct NoOptions;
pub trait CompilableTarget: Target {
type Options: CompilerOptions;
fn options() -> Self::Options {
Self::Options::default()
}
}