From ebe889df2fef2fcb5dd418f78d596e4518b65d04 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sun, 4 Dec 2022 23:54:47 -0500 Subject: [PATCH] capi: get rid of safer_ffi --- librashader-capi/Cargo.toml | 2 - librashader-capi/cbindgen.toml | 7 +- librashader-capi/examples/generate-headers.rs | 3 - librashader-capi/librashader.h | 97 +++++++++++++++++++ librashader-capi/src/error.rs | 14 ++- librashader-capi/src/lib.rs | 19 ++-- librashader-capi/src/presets.rs | 44 ++++----- 7 files changed, 144 insertions(+), 42 deletions(-) delete mode 100644 librashader-capi/examples/generate-headers.rs diff --git a/librashader-capi/Cargo.toml b/librashader-capi/Cargo.toml index 3603571..dbbb374 100644 --- a/librashader-capi/Cargo.toml +++ b/librashader-capi/Cargo.toml @@ -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" diff --git a/librashader-capi/cbindgen.toml b/librashader-capi/cbindgen.toml index 5a13671..5227655 100644 --- a/librashader-capi/cbindgen.toml +++ b/librashader-capi/cbindgen.toml @@ -4,13 +4,15 @@ include_guard = "__LIBRASHADER_H__" pragma_once = true usize_is_size_t = true documentation_style = "c++" +header = "#ifdef _WIN32\n#include \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" \ No newline at end of file diff --git a/librashader-capi/examples/generate-headers.rs b/librashader-capi/examples/generate-headers.rs deleted file mode 100644 index 8e22169..0000000 --- a/librashader-capi/examples/generate-headers.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() -> ::std::io::Result<()> { - ::librashader_capi::generate_headers() -} \ No newline at end of file diff --git a/librashader-capi/librashader.h b/librashader-capi/librashader.h index 3abf8a9..ff5300a 100644 --- a/librashader-capi/librashader.h +++ b/librashader-capi/librashader.h @@ -1,3 +1,9 @@ +#ifdef _WIN32 +#include +#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 diff --git a/librashader-capi/src/error.rs b/librashader-capi/src/error.rs index 822c9b2..b518dba 100644 --- a/librashader-capi/src/error.rs +++ b/librashader-capi/src/error.rs @@ -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 { diff --git a/librashader-capi/src/lib.rs b/librashader-capi/src/lib.rs index b96bb24..bce5532 100644 --- a/librashader-capi/src/lib.rs +++ b/librashader-capi/src/lib.rs @@ -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() -} \ No newline at end of file diff --git a/librashader-capi/src/presets.rs b/librashader-capi/src/presets.rs index 7d206c6..4ed0a38 100644 --- a/librashader-capi/src/presets.rs +++ b/librashader-capi/src/presets.rs @@ -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) { -// 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_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) -> 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) -> 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 | {