use crate::error;
use spirv_tools_sys::opt;
pub struct Options {
pub(crate) inner: *mut opt::OptimizerOptions,
}
impl From<super::Options> for Options {
fn from(o: super::Options) -> Self {
unsafe {
let inner = opt::optimizer_options_create();
if let Some(vopts) = o.validator_options {
let vopts = crate::val::compiled::Options::from(vopts);
opt::optimizer_options_run_validator(inner, true);
opt::optimizer_options_set_validator_options(inner, vopts.inner);
}
if let Some(max_bound) = o.max_id_bound {
opt::optimizer_options_set_max_id_bound(inner, max_bound);
}
if o.preserve_bindings {
opt::optimizer_options_preserve_bindings(inner, true);
}
if o.preserve_spec_constants {
opt::optimizer_options_preserve_spec_constants(inner, true);
}
Self { inner }
}
}
}
impl Drop for Options {
#[inline]
fn drop(&mut self) {
unsafe { opt::optimizer_options_destroy(self.inner) }
}
}
pub struct CompiledOptimizer {
inner: *mut opt::Optimizer,
}
use super::Optimizer;
impl Optimizer for CompiledOptimizer {
fn with_env(target: crate::TargetEnv) -> Self {
Self {
inner: unsafe { opt::optimizer_create(target) },
}
}
fn optimize<MC: error::MessageCallback>(
&self,
input: impl AsRef<[u32]>,
msg_callback: &mut MC,
options: Option<super::Options>,
) -> Result<crate::binary::Binary, crate::Error> {
unsafe {
struct Ctx<'a> {
cb: &'a mut dyn error::MessageCallback,
}
let mut ctx = Ctx { cb: msg_callback };
let cb_ctx: *mut std::ffi::c_void = (&mut ctx as *mut Ctx<'_>).cast();
extern "C" fn callback(
level: spirv_tools_sys::diagnostics::MessageLevel,
source: *const std::os::raw::c_char,
source_pos: *const spirv_tools_sys::diagnostics::Position,
msg: *const std::os::raw::c_char,
ctx: *mut std::ffi::c_void,
) {
unsafe {
let ctx: &mut Ctx<'_> = &mut *(ctx.cast::<Ctx<'_>>());
let msg = error::Message::from_parts(level, source, source_pos, msg);
ctx.cb.on_message(msg);
}
}
let mut binary = std::ptr::null_mut();
let options = options.map(Options::from);
let options = match &options {
Some(opts) => opts.inner,
None => std::ptr::null(),
};
let input = input.as_ref();
let res = opt::optimizer_run(
self.inner,
input.as_ptr(),
input.len(),
&mut binary,
callback,
cb_ctx,
options,
);
match res {
spirv_tools_sys::shared::SpirvResult::Success => {
if binary.is_null() {
return Err(error::Error {
inner: spirv_tools_sys::shared::SpirvResult::InternalError,
diagnostic: Some(crate::error::Diagnostic {
line: 0,
column: 0,
index: 0,
message: "spirv optimizer indicated success but did not return a valid binary".to_owned(),
is_text: false,
}),
});
}
Ok(crate::binary::Binary::External(
crate::binary::external::ExternalBinary::new(binary),
))
}
other => Err(error::Error {
inner: other,
diagnostic: None,
}),
}
}
}
#[inline]
fn register_pass(&mut self, pass: super::Passes) -> &mut Self {
unsafe { opt::optimizer_register_pass(self.inner, pass) }
self
}
#[inline]
fn register_performance_passes(&mut self) -> &mut Self {
unsafe { opt::optimizer_register_performance_passes(self.inner) }
self
}
#[inline]
fn register_size_passes(&mut self) -> &mut Self {
unsafe { opt::optimizer_register_size_passes(self.inner) }
self
}
#[inline]
fn register_hlsl_legalization_passes(&mut self) -> &mut Self {
unsafe { opt::optimizer_register_hlsl_legalization_passes(self.inner) }
self
}
}
impl Default for CompiledOptimizer {
fn default() -> Self {
Self::with_env(crate::TargetEnv::default())
}
}
impl Drop for CompiledOptimizer {
#[inline]
fn drop(&mut self) {
unsafe { opt::optimizer_destroy(self.inner) }
}
}