capi: get rid of safer_ffi

This commit is contained in:
chyyran 2022-12-04 23:54:47 -05:00
parent 0e18b56752
commit ebe889df2f
7 changed files with 144 additions and 42 deletions

View file

@ -19,14 +19,12 @@ crate-type = [ "cdylib", "staticlib", "lib" ]
default = ["runtime-opengl", "runtime-d3d11"]
runtime-opengl = ["gl", "librashader/gl"]
runtime-d3d11 = ["windows", "librashader/d3d11"]
headers = ["safer-ffi/headers"]
[dependencies]
librashader = { path = "../librashader", version = "0.1.0-alpha.2" }
thiserror = "1.0.37"
paste = "1.0.9"
gl = { version = "0.14.0", optional = true }
safer-ffi = { version = "0.0.10", repository = "https://github.com/getditto/safer_ffi" }
[dependencies.windows]
version = "0.43.0"

View file

@ -4,13 +4,15 @@ include_guard = "__LIBRASHADER_H__"
pragma_once = true
usize_is_size_t = true
documentation_style = "c++"
header = "#ifdef _WIN32\n#include <d3d11.h>\n#else\ntypedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D1ShaderResourceView;\n#endif"
[parse]
parse_deps = true
include = ["librashader",
"librashader-presets",
"librashader-preprocess",
"librashader-reflect",
"librashader-runtime-gl"
"librashader-runtime-gl",
"librashader-runtime-d3d11"
]
@ -43,3 +45,6 @@ include = [
"FilterChainGL" = "_filter_chain_gl"
"FilterChainOptionsGL" = "filter_chain_gl_opt_t"
"FrameOptionsGL" = "frame_gl_opt_t"
"FilterChainD3D11" = "_filter_chain_d3d11"
"FilterChainOptionsD3D11" = "filter_chain_d3d11_opt_t"
"FrameOptionsD3D11" = "frame_d3d11_opt_t"

View file

@ -1,3 +0,0 @@
fn main() -> ::std::io::Result<()> {
::librashader_capi::generate_headers()
}

View file

@ -1,3 +1,9 @@
#ifdef _WIN32
#include <d3d11.h>
#else
typedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D1ShaderResourceView;
#endif
#ifndef __LIBRASHADER_H__
#define __LIBRASHADER_H__
@ -26,6 +32,8 @@ enum LIBRA_ERRNO
typedef int32_t LIBRA_ERRNO;
#endif // __cplusplus
typedef struct _filter_chain_d3d11 _filter_chain_d3d11;
typedef struct _filter_chain_gl _filter_chain_gl;
/// The error type for librashader.
@ -44,8 +52,11 @@ typedef struct _shader_preset *libra_shader_preset_t;
/// A GL function loader that librashader needs to be initialized with.
typedef const void *(*gl_loader_t)(const char*);
/// Options for filter chain creation.
typedef struct filter_chain_gl_opt_t {
/// The GLSL version. Should be at least `330`.
uint16_t gl_version;
/// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+.
bool use_dsa;
} filter_chain_gl_opt_t;
@ -81,11 +92,43 @@ typedef struct libra_draw_framebuffer_gl_t {
uint32_t format;
} libra_draw_framebuffer_gl_t;
/// Options for each OpenGL shader frame.
typedef struct frame_gl_opt_t {
/// Whether or not to clear the history buffers.
bool clear_history;
/// The direction of the frame. 1 should be vertical.
int32_t frame_direction;
} frame_gl_opt_t;
/// Options for Direct3D11 filter chain creation.
typedef struct filter_chain_d3d11_opt_t {
/// Use a deferred context to record shader rendering state.
///
/// The deferred context will be executed on the immediate context
/// with `RenderContextState = true`.
bool use_deferred_context;
} filter_chain_d3d11_opt_t;
typedef struct _filter_chain_d3d11 *libra_d3d11_filter_chain_t;
/// OpenGL parameters for the source image.
typedef struct libra_source_image_d3d11_t {
/// A shader resource view into the source image
const ID3D11ShaderResourceView *handle;
/// The width of the source image.
uint32_t width;
/// The height of the source image.
uint32_t height;
} libra_source_image_d3d11_t;
/// Options for each Direct3D11 shader frame.
typedef struct frame_d3d11_opt_t {
/// Whether or not to clear the history buffers.
bool clear_history;
/// The direction of the frame. 1 should be vertical.
int32_t frame_direction;
} frame_d3d11_opt_t;
typedef libra_error_t (*PFN_lbr_preset_free)(libra_shader_preset_t*);
typedef libra_error_t (*PFN_lbr_preset_set_param)(libra_shader_preset_t*, const char*, float);
@ -114,20 +157,36 @@ libra_error_t libra_preset_create(const char *filename,
///
/// If `preset` is null, this function does nothing. The resulting value in `preset` then becomes
/// null.
///
/// ## Safety
/// - `preset` must be a valid and aligned pointer to a shader preset.
libra_error_t libra_preset_free(libra_shader_preset_t *preset);
/// Set the value of the parameter 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.
libra_error_t libra_preset_set_param(libra_shader_preset_t *preset, const char *name, float value);
/// 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`.
libra_error_t libra_preset_get_param(libra_shader_preset_t *preset, const char *name, float *value);
/// Pretty print the shader preset.
///
/// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
libra_error_t libra_preset_print(libra_shader_preset_t *preset);
/// Get a list of runtime parameter names.
///
/// The returned value can not currently be freed.
/// This function should be considered in progress. Its use is discouraged.
libra_error_t libra_preset_get_runtime_param_names(libra_shader_preset_t *preset,
const char **value);
@ -177,6 +236,44 @@ libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_gl_filter_chain_t`.
libra_error_t libra_gl_filter_chain_free(libra_gl_filter_chain_t *chain);
/// Create the filter chain given the shader preset.
///
/// The shader preset is immediately invalidated and must be recreated after
/// the filter chain is created.
///
/// ## Safety:
/// - `preset` must be either null, or valid and aligned.
/// - `options` must be either null, or valid and aligned.
/// - `out` must be aligned, but may be null, invalid, or uninitialized.
libra_error_t libra_d3d11_filter_chain_create(libra_shader_preset_t *preset,
const struct filter_chain_d3d11_opt_t *options,
const ID3D11Device *device,
libra_d3d11_filter_chain_t *out);
/// Draw a frame with the given parameters for the given filter chain.
///
/// ## Safety
/// - `chain` may be null, invalid, but not uninitialized. If `chain` is null or invalid, this
/// function will return an error.
/// - `mvp` may be null, or if it is not null, must be an aligned pointer to 16 consecutive `float`
/// values for the model view projection matrix.
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_gl_opt_t`
/// struct.
libra_error_t libra_d3d11_filter_chain_frame(libra_d3d11_filter_chain_t *chain,
size_t frame_count,
struct libra_source_image_d3d11_t image,
struct libra_viewport_t viewport,
const ID3D11RenderTargetView *out,
const float *mvp,
const struct frame_d3d11_opt_t *opt);
/// Free a D3D11 filter chain.
///
/// The resulting value in `chain` then becomes null.
/// ## Safety
/// - `chain` must be either null or a valid and aligned pointer to an initialized `libra_d3d11_filter_chain_t`.
libra_error_t libra_d3d11_filter_chain_free(libra_d3d11_filter_chain_t *chain);
/// Get the error code corresponding to this error object.
///
/// ## Safety

View file

@ -22,6 +22,9 @@ pub enum LibrashaderError {
#[cfg(feature = "runtime-opengl")]
#[error("There was an error in the OpenGL filter chain.")]
OpenGlFilterError(#[from] librashader::runtime::gl::error::FilterChainError),
#[cfg(feature = "runtime-d3d11")]
#[error("There was an error in the D3D11 filter chain.")]
D3D11FilterError(#[from] librashader::runtime::d3d11::error::FilterChainError),
}
@ -151,7 +154,11 @@ impl LibrashaderError {
LibrashaderError::InvalidPath(_) => LIBRA_ERRNO::INVALID_PATH,
LibrashaderError::PresetError(_) => LIBRA_ERRNO::PRESET_ERROR,
LibrashaderError::PreprocessError(_) => LIBRA_ERRNO::PREPROCESS_ERROR,
LibrashaderError::OpenGlFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR
#[cfg(feature = "runtime-opengl")]
LibrashaderError::OpenGlFilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR,
#[cfg(feature = "runtime-d3d11")]
LibrashaderError::D3D11FilterError(_) => LIBRA_ERRNO::RUNTIME_ERROR
}
}
pub(crate) const fn ok() -> libra_error_t {
@ -172,6 +179,11 @@ macro_rules! assert_non_null {
if $value.is_null() {
return $crate::error::LibrashaderError::InvalidParameter(stringify!($value)).export()
}
};
(noexport $value:ident) => {
if $value.is_null() {
return Err($crate::error::LibrashaderError::InvalidParameter(stringify!($value)))
}
}
}
macro_rules! assert_some {

View file

@ -11,7 +11,7 @@
//!
//! Once an object is freed, the input pointer is always set to null. Attempting to free an object that was not
//! allocated from `librashader` or trying to free an object with a wrong `free` function results in
//! immediate **undefined behaviour**.
//! **immediate undefined behaviour**.
//!
//! In general, all functions will accept null pointers for all parameters. However, passing a null pointer
//! into any function that requires a non-null pointer will result in the function returning an error with code `INVALID_PARAMETER`.
@ -19,6 +19,15 @@
//! All types that begin with an underscore, such as `_libra_error` or `_shader_preset` are handles that
//! can not be constructed validly, and should always be used with pointer indirection via the corresponding `_t` types.
//!
//! All functions have safety invariants labeled `## Safety` that must be upheld. Failure to uphold these invariants
//! will result in **immediate undefined behaviour**. Generally speaking, all pointers passed to functions must be
//! **aligned** regardless of whether or not they are null.
//!
//! ## Booleans
//! Some option structs take `bool` values.
//! Any booleans passed to librashader **must have a bit pattern equivalent to either `1` or `0`**. Any other value will cause
//! **immediate undefined behaviour**.
//!
//! ## Errors
//! The librashader C API provides a robust, reflective error system. Every function returns a `libra_error_t`, which is either
//! a null pointer, or a handle to an opaque allocated error object. If the returned error is null, then the function was successful.
@ -36,11 +45,3 @@ pub mod runtime;
pub mod error;
pub mod ctypes;
mod ffi;
#[doc(hide)]
#[cfg(feature = "headers")] // c.f. the `Cargo.toml` section
pub fn generate_headers() -> ::std::io::Result<()> {
::safer_ffi::headers::builder()
.to_file("librashader.h")?
.generate()
}

View file

@ -7,32 +7,6 @@ use crate::ctypes::{libra_error_t, libra_shader_preset_t};
use crate::error::{assert_non_null, assert_some, assert_some_ptr, LibrashaderError};
use std::ptr::NonNull;
// use safer_ffi::prelude::*;
// use safer_ffi::ffi_export;
// use safer_ffi::char_p::char_p_ref as CStrRef;
// extern_fn! {
// /// SAFETY:
// /// - filename is aligned and valid for reads.
// fn load_preset(filename: *const c_char, out: *mut MaybeUninit<shader_preset_t>) {
// assert_non_null!(filename, "filename");
// assert_non_null!(out, "out");
//
// let filename = unsafe {
// CStr::from_ptr(filename)
// };
//
// let filename = filename.to_str()?;
//
// println!("loading {filename}");
// let preset = ShaderPreset::try_parse(filename)?;
//
// unsafe {
// out.write(MaybeUninit::new(ManuallyDrop::new(Box::new(preset))))
// }
// }
// }
pub type PFN_lbr_preset_create = unsafe extern "C" fn (*const c_char, *mut MaybeUninit<libra_shader_preset_t>) -> libra_error_t;
/// Load a preset.
@ -69,6 +43,9 @@ pub type PFN_lbr_preset_free = unsafe extern "C" fn (*mut libra_shader_preset_t)
///
/// If `preset` is null, this function does nothing. The resulting value in `preset` then becomes
/// null.
///
/// ## Safety
/// - `preset` must be a valid and aligned pointer to a shader preset.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_free(preset: *mut libra_shader_preset_t) -> libra_error_t {
ffi_body!({
@ -83,6 +60,10 @@ pub unsafe extern "C" fn libra_preset_free(preset: *mut libra_shader_preset_t) -
pub type PFN_lbr_preset_set_param = unsafe extern "C" fn (*mut libra_shader_preset_t, *const c_char, f32) -> libra_error_t;
/// Set the value of the parameter 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.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_set_param(preset: *mut libra_shader_preset_t,
name: *const c_char, value: f32) -> libra_error_t {
@ -103,6 +84,11 @@ pub unsafe extern "C" fn libra_preset_set_param(preset: *mut libra_shader_preset
pub type PFN_lbr_preset_get_param = unsafe extern "C" fn (*mut libra_shader_preset_t, *const c_char, *mut MaybeUninit<f32>) -> libra_error_t;
/// 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`.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_get_param(preset: *mut libra_shader_preset_t,
name: *const c_char, value: *mut MaybeUninit<f32>) -> libra_error_t {
@ -114,6 +100,8 @@ pub unsafe extern "C" fn libra_preset_get_param(preset: *mut libra_shader_preset
let name = name.to_str()?;
assert_some_ptr!(preset);
assert_non_null!(value);
if let Some(param) = preset.parameters.iter().find(|c| c.name == name) {
unsafe {
value.write(MaybeUninit::new(param.value))
@ -125,6 +113,9 @@ pub unsafe extern "C" fn libra_preset_get_param(preset: *mut libra_shader_preset
pub type PFN_lbr_preset_print = unsafe extern "C" fn (*mut libra_shader_preset_t) -> libra_error_t;
/// Pretty print the shader preset.
///
/// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_print(preset: *mut libra_shader_preset_t) -> libra_error_t {
ffi_body!(|preset| {
@ -139,6 +130,7 @@ pub type PFN_lbr_preset_get_runtime_param_names = unsafe extern "C" fn (*mut lib
/// Get a list of runtime parameter names.
///
/// The returned value can not currently be freed.
/// This function should be considered in progress. Its use is discouraged.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_get_runtime_param_names(preset: *mut libra_shader_preset_t, mut value: MaybeUninit<*mut *const c_char>) -> libra_error_t {
ffi_body!(|preset | {