2023-02-12 07:37:21 +11:00
|
|
|
//! librashader preset C API (`libra_preset_*`).
|
2024-02-09 18:07:02 +11:00
|
|
|
use crate::ctypes::{libra_preset_ctx_t, libra_shader_preset_t};
|
2023-01-15 19:06:09 +11:00
|
|
|
use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError};
|
2023-01-15 07:52:58 +11:00
|
|
|
use crate::ffi::extern_fn;
|
2022-12-05 16:06:37 +11:00
|
|
|
use librashader::presets::ShaderPreset;
|
|
|
|
use std::ffi::{c_char, CStr, CString};
|
|
|
|
use std::mem::MaybeUninit;
|
2022-12-04 11:55:27 +11:00
|
|
|
use std::ptr::NonNull;
|
|
|
|
|
2023-02-10 17:29:49 +11:00
|
|
|
const _: () = crate::assert_thread_safe::<ShaderPreset>();
|
|
|
|
|
2023-01-15 07:52:58 +11:00
|
|
|
/// A list of preset parameters.
|
|
|
|
#[repr(C)]
|
2023-01-15 09:14:37 +11:00
|
|
|
pub struct libra_preset_param_list_t {
|
2023-01-15 07:52:58 +11:00
|
|
|
/// A pointer to the parameter
|
|
|
|
pub parameters: *const libra_preset_param_t,
|
2023-01-15 09:14:37 +11:00
|
|
|
/// The number of parameters in the list.
|
2023-01-15 07:52:58 +11:00
|
|
|
pub length: u64,
|
|
|
|
/// For internal use only.
|
|
|
|
/// Changing this causes immediate undefined behaviour on freeing this parameter list.
|
|
|
|
pub _internal_alloc: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A preset parameter.
|
|
|
|
#[repr(C)]
|
|
|
|
pub struct libra_preset_param_t {
|
|
|
|
/// The name of the parameter
|
|
|
|
pub name: *const c_char,
|
|
|
|
/// The description of the parameter.
|
|
|
|
pub description: *const c_char,
|
|
|
|
/// The initial value the parameter is set to.
|
|
|
|
pub initial: f32,
|
|
|
|
/// The minimum value that the parameter can be set to.
|
|
|
|
pub minimum: f32,
|
|
|
|
/// The maximum value that the parameter can be set to.
|
|
|
|
pub maximum: f32,
|
|
|
|
/// The step by which this parameter can be incremented or decremented.
|
|
|
|
pub step: f32,
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Load a preset.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
|
|
|
/// - `filename` must be either null or a valid, aligned pointer to a string path to the shader preset.
|
|
|
|
/// - `out` must be either null, or an aligned pointer to an uninitialized or invalid `libra_shader_preset_t`.
|
|
|
|
/// ## Returns
|
|
|
|
/// - If any parameters are null, `out` is unchanged, and this function returns `LIBRA_ERR_INVALID_PARAMETER`.
|
|
|
|
fn libra_preset_create(
|
|
|
|
filename: *const c_char,
|
|
|
|
out: *mut MaybeUninit<libra_shader_preset_t>
|
|
|
|
) {
|
2022-12-04 10:32:10 +11:00
|
|
|
assert_non_null!(filename);
|
|
|
|
assert_non_null!(out);
|
|
|
|
|
2022-12-05 16:06:37 +11:00
|
|
|
let filename = unsafe { CStr::from_ptr(filename) };
|
2022-12-04 10:32:10 +11:00
|
|
|
let filename = filename.to_str()?;
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
let preset = ShaderPreset::try_parse(filename)?;
|
2022-12-04 10:32:10 +11:00
|
|
|
unsafe {
|
2022-12-05 16:06:37 +11:00
|
|
|
out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new(
|
|
|
|
preset,
|
|
|
|
)))))
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2023-01-14 08:05:13 +11:00
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2024-02-09 18:07:02 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Load a preset with the given wildcard context.
|
|
|
|
///
|
|
|
|
/// The wildcard context is immediately invalidated and must be recreated after
|
|
|
|
/// the preset is created.
|
|
|
|
///
|
|
|
|
/// Path information variables `PRESET_DIR` and `PRESET` will automatically be filled in.
|
|
|
|
/// ## Safety
|
|
|
|
/// - `filename` must be either null or a valid, aligned pointer to a string path to the shader preset.
|
|
|
|
/// - `context` must be either null or a valid, aligned pointer to a initialized `libra_preset_ctx_t`.
|
|
|
|
/// - `context` is invalidated after this function returns.
|
|
|
|
/// - `out` must be either null, or an aligned pointer to an uninitialized or invalid `libra_shader_preset_t`.
|
|
|
|
/// ## Returns
|
|
|
|
/// - If any parameters are null, `out` is unchanged, and this function returns `LIBRA_ERR_INVALID_PARAMETER`.
|
|
|
|
fn libra_preset_create_with_context(
|
|
|
|
filename: *const c_char,
|
|
|
|
context: *mut libra_preset_ctx_t,
|
|
|
|
out: *mut MaybeUninit<libra_shader_preset_t>
|
|
|
|
) {
|
|
|
|
assert_non_null!(filename);
|
|
|
|
assert_non_null!(context);
|
|
|
|
assert_non_null!(out);
|
|
|
|
|
|
|
|
let filename = unsafe { CStr::from_ptr(filename) };
|
|
|
|
let filename = filename.to_str()?;
|
|
|
|
|
|
|
|
let mut context = unsafe {
|
|
|
|
let context_ptr = &mut *context;
|
|
|
|
let context = context_ptr.take();
|
|
|
|
Box::from_raw(context.unwrap().as_ptr())
|
|
|
|
};
|
|
|
|
|
|
|
|
context.add_path_defaults(filename);
|
|
|
|
|
|
|
|
let preset = ShaderPreset::try_parse_with_context(filename, *context)?;
|
|
|
|
unsafe {
|
|
|
|
out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new(
|
|
|
|
preset,
|
|
|
|
)))))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Free the preset.
|
|
|
|
///
|
|
|
|
/// If `preset` is null, this function does nothing. The resulting value in `preset` then becomes
|
|
|
|
/// null.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
2024-02-09 18:07:02 +11:00
|
|
|
/// - `preset` must be a valid and aligned pointer to a `libra_shader_preset_t`.
|
2023-01-14 08:05:13 +11:00
|
|
|
fn libra_preset_free(preset: *mut libra_shader_preset_t) {
|
2022-12-04 10:32:10 +11:00
|
|
|
assert_non_null!(preset);
|
|
|
|
unsafe {
|
|
|
|
let preset_ptr = &mut *preset;
|
2022-12-04 11:55:27 +11:00
|
|
|
let preset = preset_ptr.take();
|
|
|
|
drop(Box::from_raw(preset.unwrap().as_ptr()));
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2023-01-14 08:05:13 +11:00
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Set the value of the parameter in the preset.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
2024-02-09 18:07:02 +11:00
|
|
|
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
|
2023-01-14 08:05:13 +11:00
|
|
|
/// - `name` must be null or a valid and aligned pointer to a string.
|
|
|
|
fn libra_preset_set_param(
|
|
|
|
preset: *mut libra_shader_preset_t,
|
|
|
|
name: *const c_char,
|
|
|
|
value: f32
|
|
|
|
) |name|; mut |preset| {
|
2022-12-04 10:32:10 +11:00
|
|
|
let name = unsafe {
|
|
|
|
CStr::from_ptr(name)
|
|
|
|
};
|
|
|
|
|
|
|
|
let name = name.to_str()?;
|
2022-12-04 11:55:27 +11:00
|
|
|
assert_some_ptr!(mut preset);
|
2022-12-04 10:32:10 +11:00
|
|
|
|
|
|
|
if let Some(param) = preset.parameters.iter_mut().find(|c| c.name == name) {
|
|
|
|
param.value = value
|
|
|
|
}
|
2023-01-14 08:05:13 +11:00
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Get the value of the parameter as set in the preset.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
|
|
|
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
|
|
|
|
/// - `name` must be null or a valid and aligned pointer to a string.
|
|
|
|
/// - `value` may be a pointer to a uninitialized `float`.
|
|
|
|
fn libra_preset_get_param(
|
|
|
|
preset: *mut libra_shader_preset_t,
|
|
|
|
name: *const c_char,
|
|
|
|
value: *mut MaybeUninit<f32>
|
|
|
|
) |name, preset| {
|
2022-12-05 16:06:37 +11:00
|
|
|
let name = unsafe { CStr::from_ptr(name) };
|
2022-12-04 10:32:10 +11:00
|
|
|
let name = name.to_str()?;
|
2022-12-04 11:55:27 +11:00
|
|
|
assert_some_ptr!(preset);
|
2022-12-05 15:54:47 +11:00
|
|
|
assert_non_null!(value);
|
|
|
|
|
2022-12-04 10:32:10 +11:00
|
|
|
if let Some(param) = preset.parameters.iter().find(|c| c.name == name) {
|
2022-12-05 16:06:37 +11:00
|
|
|
unsafe { value.write(MaybeUninit::new(param.value)) }
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2023-01-14 08:05:13 +11:00
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2023-01-14 08:05:13 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Pretty print the shader preset.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
2024-02-09 18:07:02 +11:00
|
|
|
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
|
2023-01-14 08:05:13 +11:00
|
|
|
fn libra_preset_print(preset: *mut libra_shader_preset_t) |preset| {
|
2022-12-05 14:37:03 +11:00
|
|
|
assert_some_ptr!(preset);
|
2023-01-19 12:54:57 +11:00
|
|
|
println!("{preset:#?}");
|
2023-01-14 08:05:13 +11:00
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
|
|
|
|
2023-01-15 07:52:58 +11:00
|
|
|
extern_fn! {
|
2023-01-16 06:06:38 +11:00
|
|
|
/// Get a list of runtime parameters.
|
2023-01-15 07:52:58 +11:00
|
|
|
///
|
|
|
|
/// ## Safety
|
2024-02-09 18:07:02 +11:00
|
|
|
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
|
2023-01-15 07:52:58 +11:00
|
|
|
/// - `out` must be an aligned pointer to a `libra_preset_parameter_list_t`.
|
2023-01-15 09:14:37 +11:00
|
|
|
/// - The output struct should be treated as immutable. Mutating any struct fields
|
|
|
|
/// in the returned struct may at best cause memory leaks, and at worse
|
|
|
|
/// cause undefined behaviour when later freed.
|
|
|
|
/// - It is safe to call `libra_preset_get_runtime_params` multiple times, however
|
|
|
|
/// the output struct must only be freed once per call.
|
|
|
|
fn libra_preset_get_runtime_params(
|
2023-01-15 07:52:58 +11:00
|
|
|
preset: *mut libra_shader_preset_t,
|
2023-01-15 09:14:37 +11:00
|
|
|
out: *mut MaybeUninit<libra_preset_param_list_t>
|
2023-01-15 07:52:58 +11:00
|
|
|
) |preset| {
|
2022-12-04 11:55:27 +11:00
|
|
|
assert_some_ptr!(preset);
|
2023-01-15 07:52:58 +11:00
|
|
|
assert_non_null!(out);
|
2022-12-04 10:32:10 +11:00
|
|
|
|
|
|
|
let iter = librashader::presets::get_parameter_meta(preset)?;
|
2023-01-15 07:52:58 +11:00
|
|
|
let mut values = Vec::new();
|
2022-12-04 10:32:10 +11:00
|
|
|
for param in iter {
|
2024-09-04 15:53:48 +10:00
|
|
|
let name = CString::new(param.id.to_string())
|
2023-01-15 07:52:58 +11:00
|
|
|
.map_err(|err| LibrashaderError::UnknownError(Box::new(err)))?;
|
|
|
|
let description = CString::new(param.description)
|
|
|
|
.map_err(|err| LibrashaderError::UnknownError(Box::new(err)))?;
|
|
|
|
values.push(libra_preset_param_t {
|
|
|
|
name: name.into_raw().cast_const(),
|
|
|
|
description: description.into_raw().cast_const(),
|
|
|
|
initial: param.initial,
|
|
|
|
minimum: param.minimum,
|
|
|
|
maximum: param.maximum,
|
|
|
|
step: param.step
|
|
|
|
})
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2024-02-16 17:12:48 +11:00
|
|
|
|
|
|
|
let values = values.into_boxed_slice();
|
|
|
|
let (parts, len) = crate::ffi::boxed_slice_into_raw_parts(values);
|
|
|
|
|
2023-01-15 07:52:58 +11:00
|
|
|
unsafe {
|
2023-01-15 09:14:37 +11:00
|
|
|
out.write(MaybeUninit::new(libra_preset_param_list_t {
|
2023-01-15 07:52:58 +11:00
|
|
|
parameters: parts,
|
|
|
|
length: len as u64,
|
2024-02-16 17:12:48 +11:00
|
|
|
_internal_alloc: 0,
|
2023-01-15 07:52:58 +11:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
}
|
2022-12-04 10:32:10 +11:00
|
|
|
}
|
2023-01-15 07:52:58 +11:00
|
|
|
|
2023-01-15 09:14:37 +11:00
|
|
|
extern_fn! {
|
|
|
|
/// Free the runtime parameters.
|
|
|
|
///
|
|
|
|
/// Unlike the other `free` functions provided by librashader,
|
|
|
|
/// `libra_preset_free_runtime_params` takes the struct directly.
|
|
|
|
/// The caller must take care to maintain the lifetime of any pointers
|
|
|
|
/// contained within the input `libra_preset_param_list_t`.
|
|
|
|
///
|
|
|
|
/// ## Safety
|
|
|
|
/// - Any pointers rooted at `parameters` becomes invalid after this function returns,
|
|
|
|
/// including any strings accessible via the input `libra_preset_param_list_t`.
|
|
|
|
/// The caller must ensure that there are no live pointers, aliased or unaliased,
|
|
|
|
/// to data accessible via the input `libra_preset_param_list_t`.
|
|
|
|
///
|
|
|
|
/// - Accessing any data pointed to via the input `libra_preset_param_list_t` after it
|
|
|
|
/// has been freed is a use-after-free and is immediate undefined behaviour.
|
|
|
|
///
|
|
|
|
/// - If any struct fields of the input `libra_preset_param_list_t` was modified from
|
|
|
|
/// their values given after `libra_preset_get_runtime_params`, this may result
|
|
|
|
/// in undefined behaviour.
|
|
|
|
fn libra_preset_free_runtime_params(preset: libra_preset_param_list_t) {
|
|
|
|
unsafe {
|
2024-02-16 17:12:48 +11:00
|
|
|
let values =
|
|
|
|
crate::ffi::boxed_slice_from_raw_parts(preset.parameters.cast_mut(),
|
|
|
|
preset.length as usize).into_vec();
|
2023-01-15 09:14:37 +11:00
|
|
|
|
|
|
|
for value in values {
|
|
|
|
let name = CString::from_raw(value.name.cast_mut());
|
|
|
|
let description = CString::from_raw(value.description.cast_mut());
|
|
|
|
|
|
|
|
drop(name);
|
|
|
|
drop(description)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|