capi: docs

This commit is contained in:
chyyran 2022-12-04 22:37:03 -05:00
parent 8935ab28e9
commit 45913c32bf
11 changed files with 268 additions and 75 deletions

View file

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

View file

@ -3,7 +3,7 @@ cpp_compat = true
include_guard = "__LIBRASHADER_H__"
pragma_once = true
usize_is_size_t = true
documentation_style = "c++"
[parse]
parse_deps = true
include = ["librashader",
@ -22,13 +22,16 @@ prefix_with_name = true
[export]
include = [
# preset
"PFN_lbr_load_preset",
"PFN_lbr_preset_free",
"PFN_lbr_preset_set_param",
"PFN_lbr_preset_get_param",
"PFN_lbr_preset_print",
"PFN_lbr_preset_get_runtime_param_names",
"FilterChain"
# error
"PFN_lbr_error_code",
]
@ -39,3 +42,4 @@ include = [
"ShaderPreset" = "_shader_preset"
"FilterChainGL" = "_filter_chain_gl"
"FilterChainOptionsGL" = "filter_chain_gl_opt_t"
"FrameOptionsGL" = "frame_gl_opt_t"

View file

@ -9,22 +9,39 @@
#include <stdint.h>
#include <stdlib.h>
/// Error codes for librashader error types.
enum LIBRA_ERRNO
#ifdef __cplusplus
: int32_t
#endif // __cplusplus
{
LIBRA_ERRNO_UNKNOWN_ERROR = 0,
LIBRA_ERRNO_INVALID_PARAMETER = 1,
LIBRA_ERRNO_INVALID_PATH = 2,
LIBRA_ERRNO_PRESET_ERROR = 3,
LIBRA_ERRNO_PREPROCESS_ERROR = 4,
LIBRA_ERRNO_RUNTIME_ERROR = 5,
};
#ifndef __cplusplus
typedef int32_t LIBRA_ERRNO;
#endif // __cplusplus
typedef struct _filter_chain_gl _filter_chain_gl;
/// The error type for librashader.
typedef struct _libra_error _libra_error;
/**
* A shader preset including all specified parameters, textures, and paths to specified shaders.
*
* A shader preset can be used to create a filter chain runtime instance, or reflected to get
* parameter metadata.
*/
/// A shader preset including all specified parameters, textures, and paths to specified shaders.
///
/// A shader preset can be used to create a filter chain runtime instance, or reflected to get
/// parameter metadata.
typedef struct _shader_preset _shader_preset;
typedef const struct _libra_error *libra_error_t;
typedef struct _libra_error *libra_error_t;
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*);
typedef struct filter_chain_gl_opt_t {
@ -34,13 +51,19 @@ typedef struct filter_chain_gl_opt_t {
typedef struct _filter_chain_gl *libra_gl_filter_chain_t;
/// OpenGL parameters for the source image.
typedef struct libra_source_image_gl_t {
/// A texture GLuint to the source image.
uint32_t handle;
/// The format of the source image.
uint32_t format;
/// The width of the source image.
uint32_t width;
/// The height of the source image.
uint32_t height;
} libra_source_image_gl_t;
/// Parameters for the output viewport.
typedef struct libra_viewport_t {
float x;
float y;
@ -48,17 +71,21 @@ typedef struct libra_viewport_t {
uint32_t height;
} libra_viewport_t;
/// OpenGL parameters for the output framebuffer.
typedef struct libra_draw_framebuffer_gl_t {
/// A framebuffer GLuint to the output framebuffer.
uint32_t handle;
/// A texture GLuint to the logical buffer of the output framebuffer.
uint32_t texture;
/// The format of the output framebuffer.
uint32_t format;
uint32_t width;
uint32_t height;
} libra_draw_framebuffer_gl_t;
/**
* Load a preset.
*/
typedef struct frame_gl_opt_t {
bool clear_history;
int32_t frame_direction;
} frame_gl_opt_t;
typedef libra_error_t (*PFN_lbr_load_preset)(const char*, libra_shader_preset_t*);
typedef libra_error_t (*PFN_lbr_preset_free)(libra_shader_preset_t*);
@ -75,71 +102,122 @@ typedef libra_error_t (*PFN_lbr_preset_get_runtime_param_names)(libra_shader_pre
extern "C" {
#endif // __cplusplus
libra_error_t libra_load_preset(const char *filename, libra_shader_preset_t *out);
/// 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`.
libra_error_t libra_load_preset(const char *filename,
libra_shader_preset_t *out);
/**
* Free the preset.
*/
/// Free the preset.
///
/// If `preset` is null, this function does nothing. The resulting value in `preset` then becomes
/// null.
libra_error_t libra_preset_free(libra_shader_preset_t *preset);
/**
* Set the value of the parameter in the preset.
*/
/// Set the value of the parameter in the preset.
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.
*/
/// Get the value of the parameter as set in the preset.
libra_error_t libra_preset_get_param(libra_shader_preset_t *preset, const char *name, float *value);
/**
* Pretty print the shader preset.
*/
/// Pretty print the 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.
*/
/// Get a list of runtime parameter names.
///
/// The returned value can not currently be freed.
libra_error_t libra_preset_get_runtime_param_names(libra_shader_preset_t *preset,
const char **value);
/**
* Initialize the OpenGL Context for librashader.
*
* ## Safety
* Attempting to create a filter chain will fail.
*
* Reinitializing the OpenGL context with a different loader immediately invalidates previous filter
* chain objects, and drawing with them causes immediate undefined behaviour.
*/
/// Initialize the OpenGL Context for librashader.
///
/// ## Safety
/// Attempting to create a filter chain will fail.
///
/// Reinitializing the OpenGL context with a different loader immediately invalidates previous filter
/// chain objects, and drawing with them causes immediate undefined behaviour.
libra_error_t libra_gl_init_context(gl_loader_t loader);
/**
* 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` may be either null or uninitialized, but must be aligned.
*/
/// 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_gl_filter_chain_create(libra_shader_preset_t *preset,
const struct filter_chain_gl_opt_t *options,
libra_gl_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_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
size_t frame_count,
struct libra_source_image_gl_t image,
struct libra_viewport_t viewport,
struct libra_draw_framebuffer_gl_t out,
const float *mvp);
const float *mvp,
const struct frame_gl_opt_t *opt);
/// Free a GL 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_gl_filter_chain_t`.
libra_error_t libra_gl_filter_chain_free(libra_gl_filter_chain_t *chain);
/// Get the error code corresponding to this error object.
///
/// ## Safety
/// - `error` must be valid and initialized.
LIBRA_ERRNO libra_error_errno(libra_error_t error);
/// Print the error message.
///
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
/// ## Safety
/// - `error` must be a valid and initialized instance of `libra_error_t`.
int32_t libra_error_print(libra_error_t error);
/// Frees any internal state kept by the error.
///
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
/// The resulting error object becomes null.
/// ## Safety
/// - `error` must be null or a pointer to a valid and initialized instance of `libra_error_t`.
int32_t libra_error_free(libra_error_t *error);
/// Writes the error message into `out`
///
/// If `error` is null, this function does nothing and returns 1. Otherwise, this function returns 0.
/// ## Safety
/// - `error` must be a valid and initialized instance of `libra_error_t`.
/// - `out` must be a non-null pointer. The resulting string must not be modified.
int32_t libra_error_write(libra_error_t error,
char **out);
/// Frees an error string previously allocated by `libra_error_write`.
///
/// After freeing, the pointer will be set to null.
/// ## Safety
/// - If `libra_error_write` is not null, it must point to a string previously returned by `libra_error_write`.
/// Attempting to free anything else, including strings or objects from other librashader functions, is immediate
/// Undefined Behaviour.
int32_t libra_error_free_string(char **out);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

View file

@ -3,11 +3,12 @@ use librashader::presets::ShaderPreset;
use crate::error::LibrashaderError;
pub type libra_shader_preset_t = Option<NonNull<ShaderPreset>>;
pub type libra_error_t = *const LibrashaderError;
pub type libra_error_t = Option<NonNull<LibrashaderError>>;
// #[cfg(feature = "runtime-opengl")]
#[cfg(feature = "runtime-opengl")]
pub type libra_gl_filter_chain_t = Option<NonNull<librashader::runtime::gl::FilterChainGL>>;
/// Parameters for the output viewport.
#[repr(C)]
pub struct libra_viewport_t {
pub x: f32,

View file

@ -1,3 +1,29 @@
//! The C API for [librashader](https://docs.rs/librashader/).
//!
//! The librashader C API is designed to be loaded dynamically via `librashader_ld.h`, but static usage is also
//! possible by linking against `librashader.h` as well as any static libraries used by `librashader`.
//!
//! ## Usage
//! ⚠ Rust consumers should take a look at [librashader](https://docs.rs/librashader/) ⚠
//!
//! The C API is designed to be easy to use and safe. Most objects are only accessible behind an opaque pointer.
//! Every allocated object can be freed with a corresponding `free` function **for that specific object type**.
//!
//! 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**.
//!
//! 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`.
//!
//! 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.
//!
//! ## 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.
//! Otherwise, error information can be accessed via the `libra_error_` set of APIs. If an error indeed occurs, it may be freed by
//! `libra_error_free`.
#![allow(non_camel_case_types)]
#![feature(try_blocks)]
#![feature(vec_into_raw_parts)]
@ -11,8 +37,7 @@ pub mod error;
pub mod ctypes;
mod ffi;
pub type PK_s = unsafe extern "C" fn(filename: *const c_char);
#[doc(hide)]
#[cfg(feature = "headers")] // c.f. the `Cargo.toml` section
pub fn generate_headers() -> ::std::io::Result<()> {
::safer_ffi::headers::builder()

View file

@ -32,8 +32,15 @@ use std::ptr::NonNull;
// }
// }
/// Load a preset.
pub type PFN_lbr_load_preset = unsafe extern "C" fn (*const c_char, *mut MaybeUninit<libra_shader_preset_t>) -> libra_error_t;
/// 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`.
#[no_mangle]
pub unsafe extern "C" fn libra_load_preset(filename: *const c_char, out: *mut MaybeUninit<libra_shader_preset_t>) -> libra_error_t {
ffi_body!({
@ -58,6 +65,9 @@ pub unsafe extern "C" fn libra_load_preset(filename: *const c_char, out: *mut Ma
pub type PFN_lbr_preset_free = unsafe extern "C" fn (*mut libra_shader_preset_t) -> libra_error_t;
/// Free the preset.
///
/// If `preset` is null, this function does nothing. The resulting value in `preset` then becomes
/// null.
#[no_mangle]
pub unsafe extern "C" fn libra_preset_free(preset: *mut libra_shader_preset_t) -> libra_error_t {
ffi_body!({
@ -117,8 +127,8 @@ pub type PFN_lbr_preset_print = unsafe extern "C" fn (*mut libra_shader_preset_t
#[no_mangle]
pub unsafe extern "C" fn libra_preset_print(preset: *mut libra_shader_preset_t) -> libra_error_t {
ffi_body!(|preset| {
assert_some!(preset);
println!("{:#?}", preset.as_ref().unwrap());
assert_some_ptr!(preset);
println!("{:#?}", preset);
})
}

View file

@ -4,13 +4,17 @@ use crate::ctypes::{libra_error_t, libra_gl_filter_chain_t, libra_shader_preset_
use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError};
use crate::ffi::ffi_body;
use std::ptr::NonNull;
use std::slice;
use librashader::runtime::FilterChain;
use librashader::runtime::gl::{GLImage, Viewport};
pub use librashader::runtime::gl::options::FilterChainOptionsGL;
pub use librashader::runtime::gl::options::FrameOptionsGL;
use librashader::Size;
/// A GL function loader that librashader needs to be initialized with.
pub type gl_loader_t = unsafe extern "C" fn (*const c_char) -> *const c_void;
/// Initialize the OpenGL Context for librashader.
///
/// ## Safety
@ -38,7 +42,7 @@ pub unsafe extern "C" fn libra_gl_init_context(loader: gl_loader_t) -> libra_err
/// ## Safety:
/// - `preset` must be either null, or valid and aligned.
/// - `options` must be either null, or valid and aligned.
/// - `out` may be either null or uninitialized, but must be aligned.
/// - `out` must be aligned, but may be null, invalid, or uninitialized.
#[no_mangle]
pub unsafe extern "C" fn libra_gl_filter_chain_create(preset: *mut libra_shader_preset_t,
options: *const FilterChainOptionsGL,
@ -66,21 +70,28 @@ pub unsafe extern "C" fn libra_gl_filter_chain_create(preset: *mut libra_shader_
})
}
/// OpenGL parameters for the source image.
#[repr(C)]
pub struct libra_source_image_gl_t {
/// A texture GLuint to the source image.
pub handle: u32,
/// The format of the source image.
pub format: u32,
/// The width of the source image.
pub width: u32,
/// The height of the source image.
pub height: u32
}
/// OpenGL parameters for the output framebuffer.
#[repr(C)]
pub struct libra_draw_framebuffer_gl_t {
/// A framebuffer GLuint to the output framebuffer.
pub handle: u32,
/// A texture GLuint to the logical buffer of the output framebuffer.
pub texture: u32,
/// The format of the output framebuffer.
pub format: u32,
pub width: u32,
pub height: u32
}
impl From<libra_source_image_gl_t> for GLImage {
@ -94,6 +105,15 @@ impl From<libra_source_image_gl_t> for GLImage {
}
}
/// 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.
#[no_mangle]
pub unsafe extern "C" fn libra_gl_filter_chain_frame(chain: *mut libra_gl_filter_chain_t,
frame_count: usize,
@ -101,23 +121,41 @@ pub unsafe extern "C" fn libra_gl_filter_chain_frame(chain: *mut libra_gl_filter
viewport: libra_viewport_t,
out: libra_draw_framebuffer_gl_t,
mvp: *const f32,
opt: *const FrameOptionsGL,
) -> libra_error_t {
ffi_body!(mut |chain| {
assert_some_ptr!(mut chain);
let image: GLImage = image.into();
let mvp = if mvp.is_null() {
None
} else {
Some(<&[f32; 16]>::try_from(unsafe { slice::from_raw_parts(mvp, 16) }).unwrap())
};
let opt = if opt.is_null() {
None
} else {
Some(unsafe { opt.read() })
};
let viewport = Viewport {
x: viewport.x,
y: viewport.y,
output: &chain.create_framebuffer_raw(out.texture, out.handle, out.format, Size::new(out.width, out.height), 1),
mvp: None,
output: &chain.create_framebuffer_raw(out.texture, out.handle, out.format, Size::new(viewport.width, viewport.height), 1),
mvp,
};
chain.frame(&image, &viewport, frame_count, None)?;
chain.frame(&image, &viewport, frame_count, opt.as_ref())?;
})
}
/// Free a GL 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_gl_filter_chain_t`.
#[no_mangle]
pub unsafe extern "C" fn libra_gl_filter_chain_free(chain: *mut libra_gl_filter_chain_t) -> libra_error_t {
ffi_body!({

View file

@ -0,0 +1 @@
pub mod filter_chain;

View file

@ -1 +1,2 @@
pub mod gl;
#[cfg(feature = "runtime-opengl")]
mod gl;

View file

@ -1,7 +1,33 @@
//! Re-exports for usage of librashader in consuming libraries.
#![forbid(missing_docs)]
//! RetroArch shader preset compiler and runtime.
//!
//! librashader provides convenient and safe access to RetroArch ['slang' shaders](https://github.com/libretro/slang-shaders).
//! The preset parser, shader preprocessor, and shader runtimes have all been reimplemented in Rust to provide easy access to
//! the rich library of shaders.
//!
//! ## Usage
//! The core objects in librashader are the [`ShaderPreset`](crate::presets::ShaderPreset) and the
//! [`FilterChain`](crate::runtime::FilterChain), the implementation of which is runtime dependent.
//!
//! The basic workflow involves parsing a `ShaderPreset`, which can then be used to construct
//! a `FilterChain`. All shaders will then be compiled, after which `FilterChain::frame` can be
//! called with appropriate input and output parameters to draw a frame with the shader effect applied.
//!
//! ## Runtimes
//! Currently available runtimes are OpenGL 3.3+ and 4.6 (with DSA), and Direct3D 11.
//! Work on the Vulkan and Direct3D 12 runtimes are in progress.
//!
//! | **API** | **Status** | **`librashader` feature** |
//! |-------------|------------|---------------------------|
//! | OpenGL 3.3+ | ✔ | `gl` |
//! | OpenGL 4.6 | ✔ | `gl` |
//! | Vulkan | 🚧 | `vk` |
//! | Direct3D 11 | ✔ | `d3d11` |
//! | Direct3D 12 | 🚧 | `d3d12` |
//! | OpenGL 2 | ❌ | |
//! | DirectX 9 | ❌ | |
//! | Metal | ❌ | |
//!
//! Runtime implementations should depend directly on constituent crates.
#[cfg(feature = "presets")]
/// Parsing and usage of shader presets.
@ -67,6 +93,9 @@ pub mod runtime {
#[cfg(feature = "gl")]
/// Shader runtime for OpenGL 3.3+.
///
/// Note that the OpenGL runtime requires `gl` to be
/// initialized with [`gl::load_with`](https://docs.rs/gl/0.14.0/gl/fn.load_with.html).
pub mod gl {
pub use librashader_runtime_gl::*;
}

View file

@ -16,9 +16,15 @@ int main()
}
libra_preset_print(&preset);
libra_gl_filter_chain_t chain;
error = libra_gl_create_filter_chain(&preset, NULL, &chain);
error = libra_gl_filter_chain_create(NULL, NULL, &chain);
if (error != NULL) {
std::cout << "error happened\n";
libra_error_print(error);
char* error_str;
libra_error_write(error, &error_str);
printf("%s", error_str);
libra_error_free_string(&error_str);
printf("%s", error_str);
}
return 0;
}