capi: add preset_ctx C API

This commit is contained in:
chyyran 2024-02-09 02:07:02 -05:00
parent 9732812b91
commit 2fbc7f92da
17 changed files with 3172 additions and 628 deletions

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#pragma once
// Uncomment the following defines to activate runtimes.
// #define LIBRA_RUNTIME_OPENGL
// #define LIBRA_RUNTIME_VULKAN
@ -39,7 +39,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#if defined(_WIN32)
#include <windows.h>
#define _LIBRASHADER_ASSIGN(HMOD, INSTANCE, NAME) \
#define _LIBRASHADER_ASSIGN(HMOD, INSTANCE, NAME) \
{ \
FARPROC address = GetProcAddress(HMOD, "libra_" #NAME); \
if (address != NULL) { \
@ -57,9 +57,9 @@ typedef HMODULE _LIBRASHADER_IMPL_HANDLE;
(INSTANCE).NAME = (PFN_libra_##NAME)address; \
} \
}
typedef void* _LIBRASHADER_IMPL_HANDLE;
typedef void *_LIBRASHADER_IMPL_HANDLE;
#define _LIBRASHADER_LOAD dlopen("librashader.dylib", RTLD_LAZY)
#elif defined(__unix__) || defined (__linux__)
#elif defined(__unix__) || defined(__linux__)
#include <dlfcn.h>
#define _LIBRASHADER_ASSIGN(HMOD, INSTANCE, NAME) \
{ \
@ -68,7 +68,7 @@ typedef void* _LIBRASHADER_IMPL_HANDLE;
(INSTANCE).NAME = (PFN_libra_##NAME)address; \
} \
}
typedef void* _LIBRASHADER_IMPL_HANDLE;
typedef void *_LIBRASHADER_IMPL_HANDLE;
#define _LIBRASHADER_LOAD dlopen("librashader.so", RTLD_LAZY)
#endif
@ -92,6 +92,72 @@ int32_t __librashader__noop_error_write(libra_error_t error, char **out) {
int32_t __librashader__noop_error_free_string(char **out) { return 1; }
libra_error_t __librashader__noop_preset_ctx_create(libra_preset_ctx_t *out) {
*out = NULL;
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_free(libra_preset_ctx_t *context) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_core_name(
libra_preset_ctx_t *context, const char *name) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_content_dir(
libra_preset_ctx_t *context, const char *name) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_param(
libra_preset_ctx_t *context, const char *name, const char *value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_runtime(
libra_preset_ctx_t *context, LIBRA_PRESET_CTX_RUNTIME value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_core_rotation(
libra_preset_ctx_t *context, uint32_t value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_user_rotation(
libra_preset_ctx_t *context, uint32_t value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_screen_orientation(
libra_preset_ctx_t *context, uint32_t value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_allow_rotation(
libra_preset_ctx_t *context, bool value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_view_aspect_orientation(
libra_preset_ctx_t *context, LIBRA_PRESET_CTX_ORIENTATION value) {
return NULL;
}
libra_error_t __librashader__noop_preset_ctx_set_core_aspect_orientation(
libra_preset_ctx_t *context, LIBRA_PRESET_CTX_ORIENTATION value) {
return NULL;
}
libra_error_t __librashader__noop_preset_create_with_context(
const char *filename, libra_preset_ctx_t *context,
libra_shader_preset_t *out) {
*out = NULL;
return NULL;
}
libra_error_t __librashader__noop_preset_create(const char *filename,
libra_shader_preset_t *out) {
*out = NULL;
@ -119,7 +185,8 @@ 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) {
libra_error_t __librashader__noop_preset_free_runtime_params(
struct libra_preset_param_list_t out) {
return NULL;
}
#if defined(LIBRA_RUNTIME_OPENGL)
@ -228,7 +295,8 @@ libra_error_t __librashader__noop_d3d11_filter_chain_create(
}
libra_error_t __librashader__noop_d3d11_filter_chain_create_deferred(
libra_shader_preset_t *preset, ID3D11Device *device, ID3D11DeviceContext *device_context,
libra_shader_preset_t *preset, ID3D11Device *device,
ID3D11DeviceContext *device_context,
const struct filter_chain_d3d11_opt_t *options,
libra_d3d11_filter_chain_t *out) {
*out = NULL;
@ -236,11 +304,10 @@ libra_error_t __librashader__noop_d3d11_filter_chain_create_deferred(
}
libra_error_t __librashader__noop_d3d11_filter_chain_frame(
libra_d3d11_filter_chain_t *chain,
ID3D11DeviceContext *device_context, size_t frame_count,
struct libra_source_image_d3d11_t image, struct libra_viewport_t viewport,
ID3D11RenderTargetView *out, const float *mvp,
const struct frame_d3d11_opt_t *opt) {
libra_d3d11_filter_chain_t *chain, ID3D11DeviceContext *device_context,
size_t frame_count, struct libra_source_image_d3d11_t image,
struct libra_viewport_t viewport, ID3D11RenderTargetView *out,
const float *mvp, const struct frame_d3d11_opt_t *opt) {
return NULL;
}
@ -270,7 +337,6 @@ libra_error_t __librashader__noop_d3d11_filter_chain_get_active_pass_count(
}
#endif
#if defined(LIBRA_RUNTIME_D3D12)
libra_error_t __librashader__noop_d3d12_filter_chain_create(
libra_shader_preset_t *preset, ID3D12Device *device,
@ -290,11 +356,10 @@ libra_error_t __librashader__noop_d3d12_filter_chain_create_deferred(
}
libra_error_t __librashader__noop_d3d12_filter_chain_frame(
libra_d3d12_filter_chain_t *chain,
ID3D12GraphicsCommandList *command_list, size_t frame_count,
struct libra_source_image_d3d12_t image, struct libra_viewport_t viewport,
struct libra_output_image_d3d12_t out, const float *mvp,
const struct frame_d3d12_opt_t *opt) {
libra_d3d12_filter_chain_t *chain, ID3D12GraphicsCommandList *command_list,
size_t frame_count, struct libra_source_image_d3d12_t image,
struct libra_viewport_t viewport, struct libra_output_image_d3d12_t out,
const float *mvp, const struct frame_d3d12_opt_t *opt) {
return NULL;
}
@ -335,6 +400,151 @@ typedef struct libra_instance_t {
/// The null instance has API version 0.
PFN_libra_instance_api_version instance_api_version;
/// Create a wildcard context
///
/// The C API does not allow directly setting certain variables
///
/// - `PRESET_DIR` and `PRESET` are inferred on preset creation.
/// - `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are always set to
/// `slang` and `slangp` for librashader.
/// - `VID-FINAL-ROT` is automatically calculated as the sum of
/// `VID-USER-ROT` and `CORE-REQ-ROT` if either are present.
///
/// These automatically inferred variables, as well as all other variables
/// can be overridden with `libra_preset_ctx_set_param`, but the expected
/// string values must be provided. See
/// https://github.com/libretro/RetroArch/pull/15023 for a list of expected
/// string values.
///
/// No variables can be removed once added to the context, however
/// subsequent calls to set the same variable will overwrite the expected
/// variable.
/// ## Safety
/// - `out` must be either null, or an aligned pointer to an uninitialized
/// or invalid `libra_preset_ctx_t`.
/// ## Returns
/// - If any parameters are null, `out` is unchanged, and this function
/// returns `LIBRA_ERR_INVALID_PARAMETER`.
PFN_libra_preset_ctx_create preset_ctx_create;
/// Free the wildcard context.
///
/// If `context` is null, this function does nothing. The resulting value in
/// `context` then becomes null.
///
/// ## Safety
/// - `context` must be a valid and aligned pointer to a
/// `libra_preset_ctx_t`
PFN_libra_preset_ctx_free preset_ctx_free;
/// Set the core name (`CORE`) variable in the context
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
PFN_libra_preset_ctx_set_core_name preset_ctx_set_core_name;
/// Set the content directory (`CONTENT-DIR`) variable in the context.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
PFN_libra_preset_ctx_set_content_dir preset_ctx_set_content_dir;
/// Set a custom string variable in context.
///
/// If the path contains this variable when loading a preset, it will be
/// replaced with the provided contents.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
/// - `value` must be null or a valid and aligned pointer to a string.
PFN_libra_preset_ctx_set_param preset_ctx_set_param;
/// Set the graphics runtime (`VID-DRV`) variable in the context.
///
/// Note that librashader only supports the following runtimes.
///
/// - Vulkan
/// - GLCore
/// - Direct3D11
/// - Direct3D12
///
/// This will also set the appropriate video driver extensions.
///
/// For librashader, `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are
/// always `slang` and `slangp`. To override this, use
/// `libra_preset_ctx_set_param`.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
PFN_libra_preset_ctx_set_runtime preset_ctx_set_runtime;
/// Set the core requested rotation (`CORE-REQ-ROT`) variable in the
/// context.
///
/// Rotation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` =
/// 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_core_rotation preset_ctx_set_core_rotation;
/// Set the user rotation (`VID-USER-ROT`) variable in the context.
///
/// Rotation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` =
/// 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_user_rotation preset_ctx_set_user_rotation;
/// Set the screen orientation (`SCREEN-ORIENT`) variable in the context.
///
/// Orientation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` =
/// 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_screen_orientation
preset_ctx_set_screen_orientation;
/// Set whether or not to allow rotation (`VID-ALLOW-CORE-ROT`) variable in
/// the context.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_allow_rotation preset_ctx_set_allow_rotation;
/// Set the view aspect orientation (`VIEW-ASPECT-ORIENT`) variable in the
/// context.
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_view_aspect_orientation
preset_ctx_set_view_aspect_orientation;
/// Set the core aspect orientation (`CORE-ASPECT-ORIENT`) variable in the
/// context.
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a
/// `libra_preset_ctx_t`.
PFN_libra_preset_ctx_set_core_aspect_orientation
preset_ctx_set_core_aspect_orientation;
/// Load a preset.
///
/// If this function is not loaded, `out` will unconditionally be set to
@ -351,6 +561,26 @@ typedef struct libra_instance_t {
/// returns `LIBRA_ERR_INVALID_PARAMETER`.
PFN_libra_preset_create preset_create;
/// 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`.
PFN_libra_preset_create_with_context preset_create_with_context;
/// Free the preset.
///
/// If `preset` is null, this function does nothing. The resulting value in
@ -425,7 +655,6 @@ typedef struct libra_instance_t {
/// result in undefined behaviour.
PFN_libra_preset_free_runtime_params preset_free_runtime_params;
/// Get the error code corresponding to this error object.
///
/// ## Safety
@ -473,7 +702,8 @@ typedef struct libra_instance_t {
/// Initialize the OpenGL Context for librashader.
///
/// ## Safety
/// Attempting to create a filter chain will fail if the context is not initialized.
/// Attempting to create a filter chain will fail if the context is not
/// initialized.
///
/// Reinitializing the OpenGL context with a different loader immediately
/// invalidates previous filter chain objects, and drawing with them causes
@ -717,7 +947,8 @@ typedef struct libra_instance_t {
///
/// If the context is immediate, then access to the immediate context
/// requires external synchronization.
PFN_libra_d3d11_filter_chain_create_deferred d3d11_filter_chain_create_deferred;
PFN_libra_d3d11_filter_chain_create_deferred
d3d11_filter_chain_create_deferred;
/// Draw a frame with the given parameters for the given filter chain.
///
@ -776,7 +1007,6 @@ typedef struct libra_instance_t {
PFN_libra_d3d11_filter_chain_set_param d3d11_filter_chain_set_param;
#endif
#if defined(LIBRA_RUNTIME_D3D12)
/// Create the filter chain given the shader preset.
///
@ -801,8 +1031,9 @@ typedef struct libra_instance_t {
/// The shader preset is immediately invalidated and must be recreated after
/// the filter chain is created.
///
/// If this function is not loaded, `out` will unconditionally be set to null.
/// If this function returns an error, the state of `out` is unspecified.
/// If this function is not loaded, `out` will unconditionally be set to
/// null. If this function returns an error, the state of `out` is
/// unspecified.
///
/// ## Safety:
/// - `preset` must be either null, or valid and aligned.
@ -815,7 +1046,8 @@ typedef struct libra_instance_t {
/// prior commands. The caller is responsible for ending the command list
/// and immediately submitting it to a graphics queue. The command list must
/// be completely executed before calling `libra_d3d12_filter_chain_frame`
PFN_libra_d3d12_filter_chain_create_deferred d3d12_filter_chain_create_deferred;
PFN_libra_d3d12_filter_chain_create_deferred
d3d12_filter_chain_create_deferred;
/// Draw a frame with the given parameters for the given filter chain.
///
@ -881,7 +1113,8 @@ typedef struct libra_instance_t {
/// was created with librashader_load_instance if and only if:
///
/// 1. A librashader library was found in the search path.
/// 2. The ABI version of the librashader library in the search path is compatible.
/// 2. The ABI version of the librashader library in the search path is
/// compatible.
///
/// This flag can only be relied upon when checked immediately after
/// librashader_load_instance as there is no protection against mutating
@ -894,8 +1127,6 @@ typedef struct libra_instance_t {
bool instance_loaded;
} libra_instance_t;
libra_instance_t __librashader_make_null_instance() {
return libra_instance_t {
.instance_abi_version = __librashader__noop_instance_abi_version,
@ -934,7 +1165,8 @@ libra_instance_t __librashader_make_null_instance() {
#if defined(LIBRA_RUNTIME_VULKAN)
.vk_filter_chain_create = __librashader__noop_vk_filter_chain_create,
.vk_filter_chain_create_deferred = __librashader__noop_vk_filter_chain_create_deferred,
.vk_filter_chain_create_deferred =
__librashader__noop_vk_filter_chain_create_deferred,
.vk_filter_chain_frame = __librashader__noop_vk_filter_chain_frame,
.vk_filter_chain_free = __librashader__noop_vk_filter_chain_free,
.vk_filter_chain_get_active_pass_count =
@ -1000,7 +1232,8 @@ 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) || defined(__linux__) || defined(__unix__) || defined(__APPLE__)
#if defined(_WIN32) || defined(__linux__) || defined(__unix__) || \
defined(__APPLE__)
libra_instance_t librashader_load_instance() {
_LIBRASHADER_IMPL_HANDLE librashader = _LIBRASHADER_LOAD;
libra_instance_t instance = __librashader_make_null_instance();
@ -1016,15 +1249,31 @@ libra_instance_t librashader_load_instance() {
return instance;
}
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_create);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_free);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_core_name);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_content_dir);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_param);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_runtime);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_core_rotation);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_user_rotation);
_LIBRASHADER_ASSIGN(librashader, instance,
preset_ctx_set_screen_orientation);
_LIBRASHADER_ASSIGN(librashader, instance, preset_ctx_set_allow_rotation);
_LIBRASHADER_ASSIGN(librashader, instance,
preset_ctx_set_view_aspect_orientation);
_LIBRASHADER_ASSIGN(librashader, instance,
preset_ctx_set_core_aspect_orientation);
_LIBRASHADER_ASSIGN(librashader, instance, preset_create);
_LIBRASHADER_ASSIGN(librashader, instance, preset_create_with_context);
_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(librashader, instance, preset_get_runtime_params);
_LIBRASHADER_ASSIGN(librashader, instance, preset_free_runtime_params);
_LIBRASHADER_ASSIGN(librashader, instance, error_errno);
_LIBRASHADER_ASSIGN(librashader, instance, error_print);
@ -1037,14 +1286,12 @@ libra_instance_t librashader_load_instance() {
_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(librashader, instance, gl_filter_chain_set_param);
_LIBRASHADER_ASSIGN(librashader, instance,
gl_filter_chain_get_param);
gl_filter_chain_get_active_pass_count);
_LIBRASHADER_ASSIGN(librashader, instance,
gl_filter_chain_set_param);
_LIBRASHADER_ASSIGN(librashader, instance,
gl_filter_chain_get_active_pass_count);
_LIBRASHADER_ASSIGN(librashader, instance,
gl_filter_chain_set_active_pass_count);
gl_filter_chain_set_active_pass_count);
#endif
@ -1053,19 +1300,18 @@ libra_instance_t librashader_load_instance() {
_LIBRASHADER_ASSIGN(librashader, instance, vk_filter_chain_create_deferred);
_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(librashader, instance, vk_filter_chain_set_param);
_LIBRASHADER_ASSIGN(librashader, instance,
vk_filter_chain_get_param);
vk_filter_chain_get_active_pass_count);
_LIBRASHADER_ASSIGN(librashader, instance,
vk_filter_chain_set_param);
_LIBRASHADER_ASSIGN(librashader, instance,
vk_filter_chain_get_active_pass_count);
_LIBRASHADER_ASSIGN(librashader, instance,
vk_filter_chain_set_active_pass_count);
vk_filter_chain_set_active_pass_count);
#endif
#if defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11)
_LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_create);
_LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_create_deferred);
_LIBRASHADER_ASSIGN(librashader, instance,
d3d11_filter_chain_create_deferred);
_LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_frame);
_LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_free);
_LIBRASHADER_ASSIGN(librashader, instance, d3d11_filter_chain_get_param);
@ -1078,7 +1324,8 @@ libra_instance_t librashader_load_instance() {
#if defined(_WIN32) && defined(LIBRA_RUNTIME_D3D12)
_LIBRASHADER_ASSIGN(librashader, instance, d3d12_filter_chain_create);
_LIBRASHADER_ASSIGN(librashader, instance, d3d12_filter_chain_create_deferred);
_LIBRASHADER_ASSIGN(librashader, instance,
d3d12_filter_chain_create_deferred);
_LIBRASHADER_ASSIGN(librashader, instance, d3d12_filter_chain_frame);
_LIBRASHADER_ASSIGN(librashader, instance, d3d12_filter_chain_free);
_LIBRASHADER_ASSIGN(librashader, instance, d3d12_filter_chain_get_param);

View file

@ -73,8 +73,7 @@ pub fn main() {
let ext = ext.replace("_capi", "");
fs::rename(output_dir.join(artifact), output_dir.join(ext)).unwrap();
}
}
else if cfg!(target_family = "unix") {
} else if cfg!(target_family = "unix") {
let artifacts = &["liblibrashader_capi.so", "liblibrashader_capi.a"];
for artifact in artifacts {
let ext = artifact.strip_prefix("lib").unwrap();

View file

@ -99,6 +99,20 @@ include = [
"PFN_libra_preset_print",
"PFN_libra_preset_get_runtime_params",
"PFN_libra_preset_free_runtime_params",
"PFN_libra_preset_create_with_context",
"PFN_libra_preset_ctx_create",
"PFN_libra_preset_ctx_free",
"PFN_libra_preset_ctx_set_core_name",
"PFN_libra_preset_ctx_set_content_dir",
"PFN_libra_preset_ctx_set_param",
"PFN_libra_preset_ctx_set_core_rotation",
"PFN_libra_preset_ctx_set_user_rotation",
"PFN_libra_preset_ctx_set_screen_orientation",
"PFN_libra_preset_ctx_set_allow_rotation",
"PFN_libra_preset_ctx_set_view_aspect_orientation",
"PFN_libra_preset_ctx_set_core_aspect_orientation",
"PFN_libra_preset_ctx_set_runtime",
# error
"PFN_libra_error_errno",
@ -147,6 +161,8 @@ include = [
"PFN_libra_d3d12_filter_chain_set_active_pass_count",
"PFN_libra_d3d12_filter_chain_get_active_pass_count",
"PFN_libra_d3d12_filter_chain_free",
"WildcardPresetContext"
]
exclude = ["Option_ID3D11DeviceContext"]
@ -154,6 +170,11 @@ exclude = ["Option_ID3D11DeviceContext"]
[export.rename]
"LibrashaderError" = "_libra_error"
"ShaderPreset" = "_shader_preset"
# I don't know why its literally just WildcardContext??
"WildcardContext" = "_preset_ctx"
"WildcardPresetContext" = "_aaaa_preset_ctx"
"FilterChainGL" = "_filter_chain_gl"
"FilterChainVulkan" = "_filter_chain_vk"
"FilterChainD3D11" = "_filter_chain_d3d11"
@ -180,4 +201,4 @@ exclude = ["Option_ID3D11DeviceContext"]
# hack to get proper pointer indirection for COM pointers
"ID3D12Device" = "ID3D12Device *"
"ID3D12Resource" = "ID3D12Resource *"
"ID3D12GraphicsCommandList" = "ID3D12GraphicsCommandList *"
"ID3D12GraphicsCommandList" = "ID3D12GraphicsCommandList *"

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
//! Binding types for the librashader C API.
use crate::error::LibrashaderError;
use librashader::presets::context::{Orientation, VideoDriver, WildcardContext};
use librashader::presets::ShaderPreset;
use std::mem::MaybeUninit;
use std::ptr::NonNull;
@ -7,9 +8,53 @@ use std::ptr::NonNull;
/// A handle to a shader preset object.
pub type libra_shader_preset_t = Option<NonNull<ShaderPreset>>;
/// A handle to a preset wildcard context object.
pub type libra_preset_ctx_t = Option<NonNull<WildcardContext>>;
/// A handle to a librashader error object.
pub type libra_error_t = Option<NonNull<LibrashaderError>>;
/// An enum representing orientation for use in preset contexts.
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum LIBRA_PRESET_CTX_ORIENTATION {
Vertical = 0,
Horizontal,
}
impl From<LIBRA_PRESET_CTX_ORIENTATION> for Orientation {
fn from(value: LIBRA_PRESET_CTX_ORIENTATION) -> Self {
match value {
LIBRA_PRESET_CTX_ORIENTATION::Vertical => Orientation::Vertical,
LIBRA_PRESET_CTX_ORIENTATION::Horizontal => Orientation::Horizontal,
}
}
}
// An enum representing graphics runtimes (video drivers) for use in preset contexts.
#[repr(u32)]
#[derive(Debug, Copy, Clone)]
pub enum LIBRA_PRESET_CTX_RUNTIME {
None = 0,
GlCore,
Vulkan,
D3D11,
D3D12,
Metal,
}
impl From<LIBRA_PRESET_CTX_RUNTIME> for VideoDriver {
fn from(value: LIBRA_PRESET_CTX_RUNTIME) -> Self {
match value {
LIBRA_PRESET_CTX_RUNTIME::None => VideoDriver::None,
LIBRA_PRESET_CTX_RUNTIME::GlCore => VideoDriver::GlCore,
LIBRA_PRESET_CTX_RUNTIME::Vulkan => VideoDriver::Vulkan,
LIBRA_PRESET_CTX_RUNTIME::D3D11 => VideoDriver::Direct3D11,
LIBRA_PRESET_CTX_RUNTIME::D3D12 => VideoDriver::Direct3D12,
LIBRA_PRESET_CTX_RUNTIME::Metal => VideoDriver::Metal,
}
}
}
/// A handle to a OpenGL filter chain.
#[cfg(feature = "runtime-opengl")]
#[doc(cfg(feature = "runtime-opengl"))]

View file

@ -80,6 +80,7 @@ pub mod reflect;
pub mod runtime;
pub mod version;
pub mod wildcard;
pub use version::LIBRASHADER_ABI_VERSION;
pub use version::LIBRASHADER_API_VERSION;

View file

@ -1,5 +1,5 @@
//! librashader preset C API (`libra_preset_*`).
use crate::ctypes::libra_shader_preset_t;
use crate::ctypes::{libra_preset_ctx_t, libra_shader_preset_t};
use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError};
use crate::ffi::extern_fn;
use librashader::presets::ShaderPreset;
@ -55,7 +55,6 @@ extern_fn! {
let filename = unsafe { CStr::from_ptr(filename) };
let filename = filename.to_str()?;
println!("loading {filename}");
let preset = ShaderPreset::try_parse(filename)?;
unsafe {
@ -66,6 +65,49 @@ extern_fn! {
}
}
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,
)))))
}
}
}
extern_fn! {
/// Free the preset.
///
@ -73,7 +115,7 @@ extern_fn! {
/// null.
///
/// ## Safety
/// - `preset` must be a valid and aligned pointer to a shader preset.
/// - `preset` must be a valid and aligned pointer to a `libra_shader_preset_t`.
fn libra_preset_free(preset: *mut libra_shader_preset_t) {
assert_non_null!(preset);
unsafe {
@ -88,7 +130,7 @@ extern_fn! {
/// Set the value of the parameter in the preset.
///
/// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
fn libra_preset_set_param(
preset: *mut libra_shader_preset_t,
@ -135,7 +177,7 @@ extern_fn! {
/// Pretty print the shader preset.
///
/// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
fn libra_preset_print(preset: *mut libra_shader_preset_t) |preset| {
assert_some_ptr!(preset);
println!("{preset:#?}");
@ -146,7 +188,7 @@ extern_fn! {
/// Get a list of runtime parameters.
///
/// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset.
/// - `preset` must be null or a valid and aligned pointer to a `libra_shader_preset_t`.
/// - `out` must be an aligned pointer to a `libra_preset_parameter_list_t`.
/// - 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

View file

@ -0,0 +1,263 @@
//! librashader preset wildcard context C API (`libra_preset_ctx_*`).
use crate::ctypes::{libra_preset_ctx_t, LIBRA_PRESET_CTX_ORIENTATION, LIBRA_PRESET_CTX_RUNTIME};
use crate::error::{assert_non_null, assert_some_ptr};
use librashader::presets::context::{
ContextItem, PresetExtension, Rotation, ShaderExtension, WildcardContext,
};
use std::ffi::{c_char, CStr};
use std::mem::MaybeUninit;
use std::ptr::NonNull;
use crate::ffi::extern_fn;
const _: () = crate::assert_thread_safe::<WildcardContext>();
extern_fn! {
/// Create a wildcard context
///
/// The C API does not allow directly setting certain variables
///
/// - `PRESET_DIR` and `PRESET` are inferred on preset creation.
/// - `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are always set to `slang` and `slangp` for librashader.
/// - `VID-FINAL-ROT` is automatically calculated as the sum of `VID-USER-ROT` and `CORE-REQ-ROT` if either are present.
///
/// These automatically inferred variables, as well as all other variables can be overridden with
/// `libra_preset_ctx_set_param`, but the expected string values must be provided.
/// See https://github.com/libretro/RetroArch/pull/15023 for a list of expected string values.
///
/// No variables can be removed once added to the context, however subsequent calls to set the same
/// variable will overwrite the expected variable.
/// ## Safety
/// - `out` must be either null, or an aligned pointer to an uninitialized or invalid `libra_preset_ctx_t`.
/// ## Returns
/// - If any parameters are null, `out` is unchanged, and this function returns `LIBRA_ERR_INVALID_PARAMETER`.
fn libra_preset_ctx_create(
out: *mut MaybeUninit<libra_preset_ctx_t>
) {
assert_non_null!(out);
unsafe {
out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new(
WildcardContext::new(),
)))));
}
}
}
extern_fn! {
/// Free the wildcard context.
///
/// If `context` is null, this function does nothing. The resulting value in `context` then becomes
/// null.
///
/// ## Safety
/// - `context` must be a valid and aligned pointer to a `libra_preset_ctx_t`
fn libra_preset_ctx_free(context: *mut libra_preset_ctx_t) {
assert_non_null!(context);
unsafe {
let context_ptr = &mut *context;
let context = context_ptr.take();
drop(Box::from_raw(context.unwrap().as_ptr()));
}
}
}
extern_fn! {
/// Set the core name (`CORE`) variable in the context
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
fn libra_preset_ctx_set_core_name(
context: *mut libra_preset_ctx_t,
name: *const c_char,
) |name|; mut |context| {
let name = unsafe {
CStr::from_ptr(name)
};
let name = name.to_str()?;
assert_some_ptr!(mut context);
context.append_item(ContextItem::CoreName(String::from(name)));
}
}
extern_fn! {
/// Set the content directory (`CONTENT-DIR`) variable in the context.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
fn libra_preset_ctx_set_content_dir(
context: *mut libra_preset_ctx_t,
name: *const c_char,
) |name|; mut |context| {
let name = unsafe {
CStr::from_ptr(name)
};
let name = name.to_str()?;
assert_some_ptr!(mut context);
context.append_item(ContextItem::ContentDirectory(String::from(name)));
}
}
extern_fn! {
/// Set a custom string variable in context.
///
/// If the path contains this variable when loading a preset, it will be replaced with the
/// provided contents.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
/// - `value` must be null or a valid and aligned pointer to a string.
fn libra_preset_ctx_set_param(
context: *mut libra_preset_ctx_t,
name: *const c_char,
value: *const c_char,
) |name, value|; mut |context| {
let name = unsafe {
CStr::from_ptr(name)
};
let name = name.to_str()?;
let value = unsafe {
CStr::from_ptr(value)
};
let value = value.to_str()?;
assert_some_ptr!(mut context);
context.append_item(ContextItem::ExternContext(String::from(name), String::from(value)));
}
}
extern_fn! {
/// Set the graphics runtime (`VID-DRV`) variable in the context.
///
/// Note that librashader only supports the following runtimes.
///
/// - Vulkan
/// - GLCore
/// - Direct3D11
/// - Direct3D12
///
/// This will also set the appropriate video driver extensions.
///
/// For librashader, `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are always `slang` and `slangp`.
/// To override this, use `libra_preset_ctx_set_param`.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
/// - `name` must be null or a valid and aligned pointer to a string.
fn libra_preset_ctx_set_runtime(
context: *mut libra_preset_ctx_t,
value: LIBRA_PRESET_CTX_RUNTIME,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::VideoDriverPresetExtension(
PresetExtension::Slangp,
));
context.append_item(ContextItem::VideoDriverShaderExtension(
ShaderExtension::Slang,
));
context.append_item(ContextItem::VideoDriver(value.into()));
}
}
extern_fn! {
/// Set the core requested rotation (`CORE-REQ-ROT`) variable in the context.
///
/// Rotation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_core_rotation(
context: *mut libra_preset_ctx_t,
value: u32,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::CoreRequestedRotation(Rotation::from(value)))
}
}
extern_fn! {
/// Set the user rotation (`VID-USER-ROT`) variable in the context.
///
/// Rotation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_user_rotation(
context: *mut libra_preset_ctx_t,
value: u32,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::UserRotation(Rotation::from(value)))
}
}
extern_fn! {
/// Set the screen orientation (`SCREEN-ORIENT`) variable in the context.
///
/// Orientation is represented by quarter rotations around the unit circle.
/// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_screen_orientation(
context: *mut libra_preset_ctx_t,
value: u32,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::ScreenOrientation(Rotation::from(value)))
}
}
extern_fn! {
/// Set whether or not to allow rotation (`VID-ALLOW-CORE-ROT`) variable in the context.
///
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_allow_rotation(
context: *mut libra_preset_ctx_t,
value: bool,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::AllowCoreRotation(value.into()))
}
}
extern_fn! {
/// Set the view aspect orientation (`VIEW-ASPECT-ORIENT`) variable in the context.
//////
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_view_aspect_orientation(
context: *mut libra_preset_ctx_t,
value: LIBRA_PRESET_CTX_ORIENTATION,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::ViewAspectOrientation(value.into()))
}
}
extern_fn! {
/// Set the core aspect orientation (`CORE-ASPECT-ORIENT`) variable in the context.
//////
/// ## Safety
/// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
fn libra_preset_ctx_set_core_aspect_orientation(
context: *mut libra_preset_ctx_t,
value: LIBRA_PRESET_CTX_ORIENTATION,
) mut |context| {
assert_some_ptr!(mut context);
context.append_item(ContextItem::CoreAspectOrientation(value.into()))
}
}

View file

@ -4,7 +4,6 @@ use rustc_hash::FxHashMap;
use std::collections::VecDeque;
use std::ffi::{OsStr, OsString};
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::ops::Add;
use std::path::{Component, Path, PathBuf};
@ -85,14 +84,10 @@ pub enum Rotation {
Reflex = 3,
}
impl Add for Rotation {
type Output = Rotation;
fn add(self, rhs: Self) -> Self::Output {
let lhs = self as u32;
let out = lhs + rhs as u32;
let out = out % 4;
match out {
impl From<u32> for Rotation {
fn from(value: u32) -> Self {
let value = value % 4;
match value {
0 => Rotation::Zero,
1 => Rotation::Right,
2 => Rotation::Straight,
@ -102,6 +97,16 @@ impl Add for Rotation {
}
}
impl Add for Rotation {
type Output = Rotation;
fn add(self, rhs: Self) -> Self::Output {
let lhs = self as u32;
let out = lhs + rhs as u32;
Rotation::from(out)
}
}
impl Display for Rotation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
@ -213,7 +218,7 @@ impl Display for ContextItem {
}
}
/// A builder for preset wildcard context.
/// A preset wildcard context.
///
/// Any items added after will have higher priority
/// when passed to the shader preset parser.
@ -247,13 +252,13 @@ impl WildcardContext {
///
/// Any values added, either previously or afterwards will not be overridden.
pub fn add_video_driver_defaults(&mut self, video_driver: VideoDriver) {
self.0.push_front(ContextItem::VideoDriverPresetExtension(
self.prepend_item(ContextItem::VideoDriverPresetExtension(
PresetExtension::Slangp,
));
self.0.push_front(ContextItem::VideoDriverShaderExtension(
self.prepend_item(ContextItem::VideoDriverShaderExtension(
ShaderExtension::Slang,
));
self.0.push_front(ContextItem::VideoDriver(video_driver));
self.prepend_item(ContextItem::VideoDriver(video_driver));
}
/// Prepend default entries from the path of the preset.
@ -263,7 +268,7 @@ impl WildcardContext {
let path = path.as_ref();
if let Some(preset_name) = path.file_stem() {
let preset_name = preset_name.to_string_lossy();
self.0.push_front(ContextItem::Preset(preset_name.into()))
self.prepend_item(ContextItem::Preset(preset_name.into()))
}
if let Some(preset_dir_name) = path.parent().and_then(|p| {
@ -273,8 +278,7 @@ impl WildcardContext {
p.file_name()
}) {
let preset_dir_name = preset_dir_name.to_string_lossy();
self.0
.push_front(ContextItem::PresetDirectory(preset_dir_name.into()))
self.prepend_item(ContextItem::PresetDirectory(preset_dir_name.into()))
}
}

View file

@ -1,4 +1,3 @@
use std::collections::HashMap;
use std::path::Path;
use nom_locate::LocatedSpan;

View file

@ -4,7 +4,7 @@ use crate::{ScaleFactor, ScaleType};
use nom::bytes::complete::tag;
use nom::character::complete::digit1;
use nom::combinator::{eof, map_res};
use std::collections::{VecDeque};
use std::collections::VecDeque;
use nom::IResult;
use num_traits::cast::ToPrimitive;

View file

@ -26,8 +26,8 @@ librashader-presets = { path = "../librashader-presets", version = "0.2.0-beta.7
spirv_cross = { package = "librashader-spirv-cross", version = "0.23", optional = true }
naga = { version = "0.19.0", features = ["spv-in", "wgsl-out"], optional = true }
rspirv = { version = "0.12.0+sdk-1.3.268.0", optional = true }
spirv = { version = "0.3.0+sdk-1.3.268.0", optional = true}
rspirv = { version = "0.12.0", optional = true }
spirv = { version = "0.3.0", optional = true}
serde = { version = "1.0", features = ["derive"], optional = true }

View file

@ -24,6 +24,7 @@ use crate::util::d3d11_compile_bound_shader;
use crate::{error, util, D3D11OutputView};
use librashader_cache::cache_shader_object;
use librashader_cache::CachedCompilation;
use librashader_presets::context::VideoDriver;
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::framebuffer::FramebufferInit;
@ -39,7 +40,6 @@ use windows::Win32::Graphics::Direct3D11::{
D3D11_USAGE_DYNAMIC,
};
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM;
use librashader_presets::context::VideoDriver;
pub struct FilterMutable {
pub(crate) passes_enabled: usize,

View file

@ -47,11 +47,11 @@ use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_UNKNOWN;
use windows::Win32::System::Threading::{CreateEventA, WaitForSingleObject, INFINITE};
use librashader_cache::CachedCompilation;
use librashader_presets::context::VideoDriver;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rayon::prelude::*;
use librashader_presets::context::VideoDriver;
const MIPMAP_RESERVED_WORKHEAP_DESCRIPTORS: usize = 4096;

View file

@ -25,7 +25,7 @@ spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
rustc-hash = "1.1.0"
bytemuck = "1.12.3"
thiserror = "1.0.37"
ash = { version = "0.37.1+1.3.235", features = ["debug"] }
ash = { version = "0.37", features = ["debug"] }
gpu-allocator = { version = "0.22.0", default-features = false, features = ["vulkan"] }
parking_lot = "0.12.1"
rayon = "1.6.1"

View file

@ -33,11 +33,11 @@ use std::path::Path;
use std::sync::Arc;
use librashader_cache::CachedCompilation;
use librashader_presets::context::VideoDriver;
use librashader_runtime::framebuffer::FramebufferInit;
use librashader_runtime::render_target::RenderTarget;
use librashader_runtime::scaling::ScaleFramebuffer;
use rayon::prelude::*;
use librashader_presets::context::VideoDriver;
/// A Vulkan device and metadata that is required by the shader runtime.
pub struct VulkanObjects {