From c1669916d4a1c1bd48a61dcac84f01f33aca3c88 Mon Sep 17 00:00:00 2001 From: chyyran Date: Sat, 14 Jan 2023 17:14:37 -0500 Subject: [PATCH] ld: expose runtime params api to loader --- include/librashader.h | 45 ++++- include/librashader_ld.h | 184 +++++++----------- librashader-capi/cbindgen.toml | 3 +- librashader-capi/src/presets.rs | 76 +++++--- librashader-runtime-vk/src/luts.rs | 6 +- .../librashader-capi-tests.cpp | 13 +- 6 files changed, 174 insertions(+), 153 deletions(-) diff --git a/include/librashader.h b/include/librashader.h index 4d3e41d..5e7c599 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -102,15 +102,15 @@ typedef struct libra_preset_param_t { } libra_preset_param_t; /// A list of preset parameters. -typedef struct libra_preset_parameter_list_t { +typedef struct libra_preset_param_list_t { /// A pointer to the parameter const struct libra_preset_param_t *parameters; - /// The number of parameters in the list + /// The number of parameters in the list. uint64_t length; /// For internal use only. /// Changing this causes immediate undefined behaviour on freeing this parameter list. uint64_t _internal_alloc; -} libra_preset_parameter_list_t; +} libra_preset_param_list_t; #if defined(LIBRA_RUNTIME_OPENGL) /// A GL function loader that librashader needs to be initialized with. @@ -291,6 +291,15 @@ typedef libra_error_t (*PFN_libra_preset_get_param)(libra_shader_preset_t *prese ///libra_preset_print typedef libra_error_t (*PFN_libra_preset_print)(libra_shader_preset_t *preset); +/// Function pointer definition for +///libra_preset_get_runtime_params +typedef libra_error_t (*PFN_libra_preset_get_runtime_params)(libra_shader_preset_t *preset, + struct libra_preset_param_list_t *out); + +/// Function pointer definition for +///libra_preset_free_runtime_params +typedef libra_error_t (*PFN_libra_preset_free_runtime_params)(struct libra_preset_param_list_t preset); + /// Function pointer definition for libra_error_errno typedef LIBRA_ERRNO (*PFN_libra_error_errno)(libra_error_t error); @@ -571,8 +580,34 @@ libra_error_t libra_preset_print(libra_shader_preset_t *preset); /// ## Safety /// - `preset` must be null or a valid and aligned pointer to a shader preset. /// - `out` must be an aligned pointer to a `libra_preset_parameter_list_t`. -libra_error_t libra_preset_get_runtime_parameters(libra_shader_preset_t *preset, - struct libra_preset_parameter_list_t *out); +/// - 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. +libra_error_t libra_preset_get_runtime_params(libra_shader_preset_t *preset, + struct libra_preset_param_list_t *out); + +/// 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. +libra_error_t libra_preset_free_runtime_params(struct libra_preset_param_list_t preset); #if defined(LIBRA_RUNTIME_OPENGL) /// Initialize the OpenGL Context for librashader. diff --git a/include/librashader_ld.h b/include/librashader_ld.h index b5dd275..b1d8255 100644 --- a/include/librashader_ld.h +++ b/include/librashader_ld.h @@ -32,8 +32,27 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #if defined(_WIN32) #include +#define _LIBRASHADER_ASSIGN(HMOD, INSTANCE, NAME) \ + { \ + FARPROC address = GetProcAddress(HMOD, "libra_" #NAME); \ + if (address != NULL) { \ + (INSTANCE).NAME = (PFN_libra_##NAME)address; \ + } \ + } +typedef HMODULE _LIBRASHADER_IMPL_HANDLE; +#define _LIBRASHADER_LOAD LoadLibraryW(L"librashader.dll") + #elif defined(__linux__) #include +#define _LIBRASHADER_ASSIGN(HMOD, INSTANCE, NAME) \ + { \ + void *address = dlsym(HMOD, "libra_" #NAME); \ + if (address != NULL) { \ + (INSTANCE).NAME = (PFN_libra_##NAME)address; \ + } \ + } +typedef void* _LIBRASHADER_IMPL_HANDLE; +#define _LIBRASHADER_LOAD dlopen(L"librashader.so", RTLD_LAZY) #endif #include "librashader.h" @@ -74,7 +93,13 @@ libra_error_t __librashader__noop_preset_get_param( libra_error_t __librashader__noop_preset_print(libra_shader_preset_t *preset) { return NULL; } - +libra_error_t __librashader__noop_preset_get_runtime_params( + libra_shader_preset_t *preset, struct libra_preset_param_list_t *out) { + return NULL; +} +libra_error_t __librashader__noop_preset_free_runtime_params(struct libra_preset_param_list_t out) { + return NULL; +} #if defined(LIBRA_RUNTIME_OPENGL) libra_error_t __librashader__noop_gl_init_context(libra_gl_loader_t loader) { return NULL; @@ -211,6 +236,8 @@ typedef struct libra_instance_t { PFN_libra_preset_set_param preset_set_param; PFN_libra_preset_get_param preset_get_param; PFN_libra_preset_print preset_print; + PFN_libra_preset_get_runtime_params preset_get_runtime_params; + PFN_libra_preset_free_runtime_params preset_free_runtime_params; PFN_libra_error_errno error_errno; PFN_libra_error_print error_print; @@ -263,7 +290,10 @@ libra_instance_t __librashader_make_null_instance() { .preset_set_param = __librashader__noop_preset_set_param, .preset_get_param = __librashader__noop_preset_get_param, .preset_print = __librashader__noop_preset_print, - + .preset_get_runtime_params = + __librashader__noop_preset_get_runtime_params, + .preset_free_runtime_params = + __librashader__noop_preset_free_runtime_params, .error_errno = __librashader__noop_error_errno, .error_print = __librashader__noop_error_print, .error_free = __librashader__noop_error_free, @@ -331,152 +361,78 @@ libra_instance_t __librashader_make_null_instance() { /// \return An `libra_instance_t` struct with loaded function pointers. libra_instance_t librashader_load_instance(); -#if defined(_WIN32) -#define _LIBRASHADER_ASSIGN_FARPROC(HMOD, INSTANCE, NAME) \ - { \ - FARPROC address = GetProcAddress(HMOD, "libra_" #NAME); \ - if (address != NULL) { \ - (INSTANCE).NAME = (PFN_libra_##NAME)address; \ - } \ - } - +#if defined(_WIN32) || defined(__linux__) libra_instance_t librashader_load_instance() { - HMODULE librashader = LoadLibraryW(L"librashader.dll"); + _LIBRASHADER_IMPL_HANDLE librashader = _LIBRASHADER_LOAD; libra_instance_t instance = __librashader_make_null_instance(); if (librashader == 0) { return instance; } - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, preset_create); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, preset_free); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, preset_set_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, preset_get_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, preset_print); + _LIBRASHADER_ASSIGN(librashader, instance, preset_create); + _LIBRASHADER_ASSIGN(librashader, instance, preset_free); + _LIBRASHADER_ASSIGN(librashader, instance, preset_set_param); + _LIBRASHADER_ASSIGN(librashader, instance, preset_get_param); + _LIBRASHADER_ASSIGN(librashader, instance, preset_print); + _LIBRASHADER_ASSIGN(librashader, instance, + preset_get_runtime_params); + _LIBRASHADER_ASSIGN(librashader, instance, + preset_free_runtime_params); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, error_errno); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, error_print); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, error_free); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, error_write); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, error_free_string); + _LIBRASHADER_ASSIGN(librashader, instance, error_errno); + _LIBRASHADER_ASSIGN(librashader, instance, error_print); + _LIBRASHADER_ASSIGN(librashader, instance, error_free); + _LIBRASHADER_ASSIGN(librashader, instance, error_write); + _LIBRASHADER_ASSIGN(librashader, instance, error_free_string); #if defined(LIBRA_RUNTIME_OPENGL) - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, gl_init_context); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, gl_filter_chain_create); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, gl_filter_chain_frame); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, gl_filter_chain_free); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, gl_init_context); + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_create); + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_frame); + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_free); + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_get_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_set_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, gl_filter_chain_set_active_pass_count); #endif #if defined(LIBRA_RUNTIME_D3D11) - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_create); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_frame); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, d3d11_filter_chain_free); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_free); + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_get_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_set_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_set_active_pass_count); #endif #if defined(LIBRA_RUNTIME_VULKAN) - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, vk_filter_chain_create); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, vk_filter_chain_frame); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, vk_filter_chain_free); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_create); + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_frame); + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_free); + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_get_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_set_param); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_FARPROC(librashader, instance, + _LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_set_active_pass_count); #endif return instance; } -#elif defined(__linux__) -#define _LIBRASHADER_ASSIGN_DLSYM(HMOD, INSTANCE, NAME) \ - { \ - void *address = dlsym(HMOD, "libra_" #NAME); \ - if (address != NULL) { \ - (INSTANCE).NAME = (PFN_libra_##NAME)address; \ - } \ - } - -libra_instance_t librashader_load_instance() { - void *librashader = dlopen(L"librashader.so", RTLD_LAZY); - libra_instance_t instance = __librashader_make_null_instance(); - if (librashader == NULL) { - return instance; - } - - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, preset_create); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, preset_free); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, preset_set_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, preset_get_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, preset_print); - - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, error_errno); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, error_print); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, error_free); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, error_write); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, error_free_string); - -#if defined(LIBRA_RUNTIME_OPENGL) - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_init_context); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_filter_chain_create); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_filter_chain_frame); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_filter_chain_free); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_filter_chain_get_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, gl_filter_chain_set_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - gl_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - gl_filter_chain_set_active_pass_count); -#endif - - // Not sure why you would want this -#if defined(LIBRA_RUNTIME_D3D11) - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, d3d11_filter_chain_create); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, d3d11_filter_chain_frame); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, d3d11_filter_chain_free); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - d3d11_filter_chain_get_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - d3d11_filter_chain_set_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - d3d11_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - d3d11_filter_chain_set_active_pass_count); - -#endif - -#if defined(LIBRA_RUNTIME_VULKAN) - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, vk_filter_chain_create); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, vk_filter_chain_frame); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, vk_filter_chain_free); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, vk_filter_chain_get_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, vk_filter_chain_set_param); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - vk_filter_chain_get_active_pass_count); - _LIBRASHADER_ASSIGN_DLSYM(librashader, instance, - vk_filter_chain_set_active_pass_count); -#endif - return instance; -} #else libra_instance_t librashader_load_instance() { return __librashader_make_null_instance(); diff --git a/librashader-capi/cbindgen.toml b/librashader-capi/cbindgen.toml index f4db13c..fc17fd3 100644 --- a/librashader-capi/cbindgen.toml +++ b/librashader-capi/cbindgen.toml @@ -37,7 +37,8 @@ include = [ "PFN_libra_preset_set_param", "PFN_libra_preset_get_param", "PFN_libra_preset_print", - "PFN_libra_preset_get_runtime_param_names", + "PFN_libra_preset_get_runtime_params", + "PFN_libra_preset_free_runtime_params", # error "PFN_libra_error_errno", diff --git a/librashader-capi/src/presets.rs b/librashader-capi/src/presets.rs index 2bf58d3..849ecb4 100644 --- a/librashader-capi/src/presets.rs +++ b/librashader-capi/src/presets.rs @@ -9,10 +9,10 @@ use std::ptr::NonNull; /// A list of preset parameters. #[repr(C)] -pub struct libra_preset_parameter_list_t { +pub struct libra_preset_param_list_t { /// A pointer to the parameter pub parameters: *const libra_preset_param_t, - /// The number of parameters in the list + /// The number of parameters in the list. pub length: u64, /// For internal use only. /// Changing this causes immediate undefined behaviour on freeing this parameter list. @@ -146,9 +146,14 @@ extern_fn! { /// ## Safety /// - `preset` must be null or a valid and aligned pointer to a shader preset. /// - `out` must be an aligned pointer to a `libra_preset_parameter_list_t`. - fn libra_preset_get_runtime_parameters( + /// - 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( preset: *mut libra_shader_preset_t, - out: *mut MaybeUninit + out: *mut MaybeUninit ) |preset| { assert_some_ptr!(preset); assert_non_null!(out); @@ -171,7 +176,7 @@ extern_fn! { } let (parts, len, cap) = values.into_raw_parts(); unsafe { - out.write(MaybeUninit::new(libra_preset_parameter_list_t { + out.write(MaybeUninit::new(libra_preset_param_list_t { parameters: parts, length: len as u64, _internal_alloc: cap as u64, @@ -180,28 +185,39 @@ extern_fn! { } } -// /// Get a list of runtime parameter names. -// /// -// /// The caller must provide a sufficiently sized buffer. -// /// If `value` is null, then size will be written to with the size of the buffer required -// /// to get the parameter names. -// /// ## Safety -// /// - `preset` must be null or a valid and aligned pointer to a shader preset. -// #[no_mangle] -// pub unsafe extern "C" fn libra_preset_free_runtime_param_names( -// value: MaybeUninit<*mut *const c_char>, -// ) -> libra_error_t { -// ffi_body!(|value| { -// let iter = librashader::presets::get_parameter_meta(preset)?; -// let mut c_strings = Vec::new(); -// for param in iter { -// let c_string = CString::new(param.id) -// .map_err(|err| LibrashaderError::UnknownError(Box::new(err)))?; -// c_strings.push(c_string.into_raw().cast_const()); -// } -// -// let (parts, _len, _cap) = c_strings.into_raw_parts(); -// -// value.write(parts); -// }) -// } +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 { + let values = Vec::from_raw_parts(preset.parameters.cast_mut(), + preset.length as usize, + preset._internal_alloc as usize); + + 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) + } + } + } +} diff --git a/librashader-runtime-vk/src/luts.rs b/librashader-runtime-vk/src/luts.rs index 2a37cc2..960f3bb 100644 --- a/librashader-runtime-vk/src/luts.rs +++ b/librashader-runtime-vk/src/luts.rs @@ -8,8 +8,10 @@ use librashader_runtime::image::{Image, BGRA8}; use librashader_runtime::scaling::MipmapSize; pub(crate) struct LutTexture { - pub memory: VulkanImageMemory, - pub staging: VulkanBuffer, + #[allow(dead_code)] + memory: VulkanImageMemory, + #[allow(dead_code)] + staging: VulkanBuffer, pub image: InputImage, } diff --git a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp index c4ddd53..fd1e36c 100644 --- a/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp +++ b/test/capi-tests/librashader-capi-tests/librashader-capi-tests/librashader-capi-tests.cpp @@ -10,6 +10,18 @@ int main() std::cout << "Hello World!\n"; std::cout << std::filesystem::current_path() << std::endl; auto instance = librashader_load_instance(); + libra_shader_preset_t preset; + auto error = instance.preset_create( + "../../../slang-shaders/border/gameboy-player/" + "gameboy-player-crt-royale.slangp", + &preset); + + libra_preset_param_list_t parameters; + error = instance.preset_get_runtime_params(&preset, ¶meters); + + libra_preset_param_t next = parameters.parameters[471]; + + instance.preset_free_runtime_params(parameters); /*libra_shader_preset_t preset; auto error = libra_preset_create("../../../slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp", &preset); @@ -20,7 +32,6 @@ int main() libra_gl_filter_chain_t chain; - error = libra_gl_filter_chain_create(NULL, NULL, &chain); if (error != NULL) { libra_error_print(error); char* error_str;