From 2b250db353c56bcaefd08f563c7e2e46482156a5 Mon Sep 17 00:00:00 2001 From: chyyran Date: Thu, 9 Feb 2023 23:36:09 -0500 Subject: [PATCH] capi: make _opt* structs more forwards compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit yay another abi break 🙃 hopefully for the last time --- README.md | 17 ++--- include/librashader.h | 56 +++++++++++++--- librashader-capi/cbindgen.toml | 8 --- librashader-capi/src/ctypes.rs | 43 +++++++++++++ librashader-capi/src/ffi.rs | 12 ++-- librashader-capi/src/lib.rs | 6 ++ .../src/runtime/d3d11/filter_chain.rs | 58 +++++++++++++++-- .../src/runtime/d3d12/filter_chain.rs | 64 ++++++++++++++++--- .../src/runtime/gl/filter_chain.rs | 55 ++++++++++++++-- .../src/runtime/vk/filter_chain.rs | 54 ++++++++++++++-- librashader-runtime-d3d11/src/options.rs | 10 +-- librashader-runtime-d3d12/src/options.rs | 10 +-- .../src/filter_chain/filter_impl.rs | 2 +- librashader-runtime-gl/src/lib.rs | 4 +- librashader-runtime-gl/src/options.rs | 6 +- librashader-runtime-vk/src/options.rs | 4 +- .../examples/example_win32_directx11/main.cpp | 11 ++-- 17 files changed, 338 insertions(+), 82 deletions(-) diff --git a/README.md b/README.md index aab1424..e80f9f6 100644 --- a/README.md +++ b/README.md @@ -62,21 +62,11 @@ cargo post build --release --package librashader-capi This will output a `librashader.dll` or `librashader.so` in the target folder. ### C ABI Compatibility -The recommended way of integrating `librashader` is by the `librashader_ld` single header library, ABI stability +As the recommended way of integrating `librashader` is by the `librashader_ld` single header library, ABI stability is important to ensure that updates to librashader do not break existing consumers. -Pre-1.0, nothing is guaranteed to be stable, but the following APIs are unlikely to change their ABI unless otherwise indicated. - -* `libra_preset_*` -* `libra_error_*` - -The following APIs, mostly runtime, are more likely to change their ABI before a 1.0 release as I experiment with what -works best. - -* `libra_gl_*` -* `libra_vk_*` -* `libra_d3d11_*` -* `libra_d3d12_*` +As of `0.1.0-rc.3`, the C ABI should be mostly stable. We reserve the right to make breaking changes before a numbered +release without following semantic versioning. Linking against `librashader.h` directly is possible, but is not officially supported. You will need to ensure linkage parameters are correct in order to successfully link with `librashader.lib` or `librashader.a`. The [corrosion](https://github.com/corrosion-rs/) @@ -109,6 +99,7 @@ Please report an issue if you run into a shader that works in RetroArch, but not * For performance reasons, mipmaps are never generated for the input texture. In theory, this means that presets with `mipmap_input0 = "true"` will not get a mipmapped input. In practice, no known shader presets set `mipmap_input0 = "true"`. + ### Runtime specific differences * OpenGL * Copying of in-flight framebuffer contents to history is done via `glBlitFramebuffer` rather than drawing a quad into an intermediate FBO. diff --git a/include/librashader.h b/include/librashader.h index ba34336..7005e7b 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -138,15 +138,21 @@ typedef struct libra_preset_param_list_t { typedef const void *(*libra_gl_loader_t)(const char*); #endif +typedef size_t LIBRASHADER_API_VERSION; + +#if defined(LIBRA_RUNTIME_OPENGL) /// Options for filter chain creation. typedef struct filter_chain_gl_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// The GLSL version. Should be at least `330`. - uint16_t gl_version; + uint16_t glsl_version; /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. bool use_dsa; /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. bool force_no_mipmaps; } filter_chain_gl_opt_t; +#endif #if defined(LIBRA_RUNTIME_OPENGL) /// A handle to a OpenGL filter chain. @@ -191,14 +197,18 @@ typedef struct libra_output_framebuffer_gl_t { } libra_output_framebuffer_gl_t; #endif +#if defined(LIBRA_RUNTIME_OPENGL) /// Options for each OpenGL shader frame. typedef struct frame_gl_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// Whether or not to clear the history buffers. bool clear_history; /// The direction of rendering. /// -1 indicates that the frames are played in reverse order. int32_t frame_direction; } frame_gl_opt_t; +#endif #if defined(LIBRA_RUNTIME_VULKAN) /// Handles required to instantiate vulkan @@ -217,8 +227,11 @@ typedef struct libra_device_vk_t { } libra_device_vk_t; #endif +#if defined(LIBRA_RUNTIME_VULKAN) /// Options for filter chain creation. typedef struct filter_chain_vk_opt_t { + /// The librashader API version. + size_t version; /// The number of frames in flight to keep. If zero, defaults to three. uint32_t frames_in_flight; /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. @@ -227,6 +240,7 @@ typedef struct filter_chain_vk_opt_t { /// because render-pass mode will create new framebuffers per pass. bool use_render_pass; } filter_chain_vk_opt_t; +#endif #if defined(LIBRA_RUNTIME_VULKAN) /// A handle to a Vulkan filter chain. @@ -257,17 +271,24 @@ typedef struct libra_output_image_vk_t { } libra_output_image_vk_t; #endif -/// Options for each Vulkan shader frame. +#if defined(LIBRA_RUNTIME_VULKAN) +/// Options for each OpenGL shader frame. typedef struct frame_vk_opt_t { + /// The librashader API version. + size_t version; /// Whether or not to clear the history buffers. bool clear_history; /// The direction of rendering. /// -1 indicates that the frames are played in reverse order. int32_t frame_direction; } frame_vk_opt_t; +#endif -/// Options for Direct3D11 filter chain creation. +#if defined(LIBRA_RUNTIME_D3D11) +/// Options for Direct3D 11 filter chain creation. typedef struct filter_chain_d3d11_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// Use a deferred context to record shader rendering state. /// /// The deferred context will be executed on the immediate context @@ -277,6 +298,7 @@ typedef struct filter_chain_d3d11_opt_t { /// generation regardless of shader preset settings. bool force_no_mipmaps; } filter_chain_d3d11_opt_t; +#endif #if defined(LIBRA_RUNTIME_D3D11) /// A handle to a Direct3D 11 filter chain. @@ -295,17 +317,24 @@ typedef struct libra_source_image_d3d11_t { } libra_source_image_d3d11_t; #endif -/// Options for each Direct3D11 shader frame. +#if defined(LIBRA_RUNTIME_D3D11) +/// Options for each Direct3D 11 shader frame. typedef struct frame_d3d11_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// Whether or not to clear the history buffers. bool clear_history; /// The direction of rendering. /// -1 indicates that the frames are played in reverse order. int32_t frame_direction; } frame_d3d11_opt_t; +#endif +#if defined(LIBRA_RUNTIME_D3D12) /// Options for Direct3D11 filter chain creation. typedef struct filter_chain_d3d12_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// Force the HLSL shader pipeline. This may reduce shader compatibility. bool force_hlsl_pipeline; /// Whether or not to explicitly disable mipmap @@ -313,6 +342,7 @@ typedef struct filter_chain_d3d12_opt_t { /// of shader preset settings. bool force_no_mipmaps; } filter_chain_d3d12_opt_t; +#endif #if defined(LIBRA_RUNTIME_D3D12) /// A handle to a Direct3D 12 filter chain. @@ -345,14 +375,18 @@ typedef struct libra_output_image_d3d12_t { } libra_output_image_d3d12_t; #endif -/// Options for each Direct3D11 shader frame. +#if defined(LIBRA_RUNTIME_D3D12) +/// Options for each Direct3D 12 shader frame. typedef struct frame_d3d12_opt_t { + /// The librashader API version. + LIBRASHADER_API_VERSION version; /// Whether or not to clear the history buffers. bool clear_history; /// The direction of rendering. /// -1 indicates that the frames are played in reverse order. int32_t frame_direction; } frame_d3d12_opt_t; +#endif /// Function pointer definition for ///libra_preset_create @@ -583,7 +617,7 @@ typedef libra_error_t (*PFN_libra_d3d11_filter_chain_free)(libra_d3d11_filter_ch /// Function pointer definition for ///libra_d3d12_filter_chain_create typedef libra_error_t (*PFN_libra_d3d12_filter_chain_create)(libra_shader_preset_t *preset, - const struct filter_chain_d3d12_opt_t *options, + const struct filter_chain_d3d12_opt_t *opt, const ID3D12Device * device, libra_d3d12_filter_chain_t *out); #endif @@ -598,7 +632,7 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_frame)(libra_d3d12_filter_c struct libra_viewport_t viewport, struct libra_output_image_d3d12_t out, const float *mvp, - const struct frame_d3d12_opt_t *opt); + const struct frame_d3d12_opt_t *options); #endif #if defined(LIBRA_RUNTIME_D3D12) @@ -637,6 +671,10 @@ typedef libra_error_t (*PFN_libra_d3d12_filter_chain_get_active_pass_count)(libr typedef libra_error_t (*PFN_libra_d3d12_filter_chain_free)(libra_d3d12_filter_chain_t *chain); #endif +/// The current version of the librashader API/ABI. +/// Pass this into `version` for config structs. +#define LIBRASHADER_CURRENT_VERSION 0 + #ifdef __cplusplus extern "C" { #endif // __cplusplus @@ -1049,7 +1087,7 @@ libra_error_t libra_d3d11_filter_chain_free(libra_d3d11_filter_chain_t *chain); /// - `device` must not be null. /// - `out` must be aligned, but may be null, invalid, or uninitialized. libra_error_t libra_d3d12_filter_chain_create(libra_shader_preset_t *preset, - const struct filter_chain_d3d12_opt_t *options, + const struct filter_chain_d3d12_opt_t *opt, const ID3D12Device * device, libra_d3d12_filter_chain_t *out); #endif @@ -1075,7 +1113,7 @@ libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain, struct libra_viewport_t viewport, struct libra_output_image_d3d12_t out, const float *mvp, - const struct frame_d3d12_opt_t *opt); + const struct frame_d3d12_opt_t *options); #endif #if defined(LIBRA_RUNTIME_D3D12) diff --git a/librashader-capi/cbindgen.toml b/librashader-capi/cbindgen.toml index 2c994be..bbdba5a 100644 --- a/librashader-capi/cbindgen.toml +++ b/librashader-capi/cbindgen.toml @@ -144,17 +144,9 @@ include = [ "LibrashaderError" = "_libra_error" "ShaderPreset" = "_shader_preset" "FilterChainGL" = "_filter_chain_gl" -"FilterChainOptionsGL" = "filter_chain_gl_opt_t" -"FrameOptionsGL" = "frame_gl_opt_t" "FilterChainVulkan" = "_filter_chain_vk" -"FilterChainOptionsVulkan" = "filter_chain_vk_opt_t" -"FrameOptionsVulkan" = "frame_vk_opt_t" "FilterChainD3D11" = "_filter_chain_d3d11" -"FilterChainOptionsD3D11" = "filter_chain_d3d11_opt_t" -"FrameOptionsD3D11" = "frame_d3d11_opt_t" "FilterChainD3D12" = "_filter_chain_d3d12" -"FilterChainOptionsD3D12" = "filter_chain_d3d12_opt_t" -"FrameOptionsD3D12" = "frame_d3d12_opt_t" # vulkan renames "PhysicalDevice" = "VkPhysicalDevice" diff --git a/librashader-capi/src/ctypes.rs b/librashader-capi/src/ctypes.rs index 47fb6e8..08351a8 100644 --- a/librashader-capi/src/ctypes.rs +++ b/librashader-capi/src/ctypes.rs @@ -1,6 +1,7 @@ //! Binding types for the librashader C API. use crate::error::LibrashaderError; use librashader::presets::ShaderPreset; +use std::mem::MaybeUninit; use std::ptr::NonNull; /// A handle to a shader preset object. @@ -44,3 +45,45 @@ pub struct libra_viewport_t { /// The height of the viewport framebuffer. pub height: u32, } + +pub(crate) trait FromUninit +where + Self: Sized, +{ + fn from_uninit(value: MaybeUninit) -> T; +} + +macro_rules! config_set_field { + ($options:ident.$field:ident <- $ptr:ident) => { + $options.$field = unsafe { ::std::ptr::addr_of!((*$ptr).$field).read() }; + }; +} + +macro_rules! config_version_set { + ($version:literal => [$($field:ident),+ $(,)?] ($options:ident <- $ptr:ident)) => { + let version = unsafe { ::std::ptr::addr_of!((*$ptr).version).read() }; + #[allow(unused_comparisons)] + if version >= $version { + $($crate::ctypes::config_set_field!($options.$field <- $ptr);)+ + } + } +} + +macro_rules! config_struct { + (impl $rust:ty => $capi:ty {$($version:literal => [$($field:ident),+ $(,)?]);+ $(;)?}) => { + impl $crate::ctypes::FromUninit<$rust> for $capi { + fn from_uninit(value: ::std::mem::MaybeUninit) -> $rust { + let ptr = value.as_ptr(); + let mut options = <$rust>::default(); + $( + $crate::ctypes::config_version_set!($version => [$($field),+] (options <- ptr)); + )+ + options + } + } + } +} + +pub(crate) use config_set_field; +pub(crate) use config_struct; +pub(crate) use config_version_set; diff --git a/librashader-capi/src/ffi.rs b/librashader-capi/src/ffi.rs index 49c379a..552d796 100644 --- a/librashader-capi/src/ffi.rs +++ b/librashader-capi/src/ffi.rs @@ -58,7 +58,7 @@ macro_rules! ffi_body { } macro_rules! extern_fn { - ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) $body:block) => { + ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => { ::paste::paste! { /// Function pointer definition for #[doc = ::std::stringify!($func_name)] @@ -72,11 +72,11 @@ macro_rules! extern_fn { } }; - ($(#[$($attrss:tt)*])* raw fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) $body:block) => { + ($(#[$($attrss:tt)*])* raw fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) $body:block) => { ::paste::paste! { /// Function pointer definition for #[doc = ::std::stringify!($func_name)] - pub type [] = unsafe extern "C" fn($($arg_name: $arg_ty,)*) -> $crate::ctypes::libra_error_t; + pub type [] = unsafe extern "C" fn($($arg_name: $arg_ty,)* ) -> $crate::ctypes::libra_error_t; } #[no_mangle] @@ -86,7 +86,7 @@ macro_rules! extern_fn { } }; - ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => { + ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*|; mut |$($mut_capture:ident),*| $body:block) => { ::paste::paste! { /// Function pointer definition for #[doc = ::std::stringify!($func_name)] @@ -100,7 +100,7 @@ macro_rules! extern_fn { } }; - ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) mut |$($mut_capture:ident),*| $body:block) => { + ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) mut |$($mut_capture:ident),*| $body:block) => { ::paste::paste! { /// Function pointer definition for #[doc = ::std::stringify!($func_name)] @@ -113,7 +113,7 @@ macro_rules! extern_fn { $crate::ffi::ffi_body!(mut |$($mut_capture),*| $body) } }; - ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),*) |$($ref_capture:ident),*| $body:block) => { + ($(#[$($attrss:tt)*])* fn $func_name:ident ($($arg_name:ident : $arg_ty:ty),* $(,)?) |$($ref_capture:ident),*| $body:block) => { ::paste::paste! { /// Function pointer definition for #[doc = ::std::stringify!($func_name)] diff --git a/librashader-capi/src/lib.rs b/librashader-capi/src/lib.rs index 1981840..a48c7b2 100644 --- a/librashader-capi/src/lib.rs +++ b/librashader-capi/src/lib.rs @@ -67,3 +67,9 @@ pub mod presets; pub mod reflect; pub mod runtime; + +pub type LIBRASHADER_API_VERSION = usize; + +/// The current version of the librashader API/ABI. +/// Pass this into `version` for config structs. +pub const LIBRASHADER_CURRENT_VERSION: LIBRASHADER_API_VERSION = 0; diff --git a/librashader-capi/src/runtime/d3d11/filter_chain.rs b/librashader-capi/src/runtime/d3d11/filter_chain.rs index 76d427a..288fc24 100644 --- a/librashader-capi/src/runtime/d3d11/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d11/filter_chain.rs @@ -1,4 +1,6 @@ -use crate::ctypes::{libra_d3d11_filter_chain_t, libra_shader_preset_t, libra_viewport_t}; +use crate::ctypes::{ + config_struct, libra_d3d11_filter_chain_t, libra_shader_preset_t, libra_viewport_t, FromUninit, +}; use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError}; use crate::ffi::extern_fn; use librashader::runtime::d3d11::{D3D11InputView, D3D11OutputView}; @@ -15,6 +17,7 @@ pub use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11; pub use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11; use librashader::runtime::{FilterChainParameters, Size, Viewport}; +use crate::LIBRASHADER_API_VERSION; /// Direct3D 11 parameters for the source image. #[repr(C)] @@ -40,6 +43,48 @@ impl TryFrom for D3D11InputView { } } +/// Options for Direct3D 11 filter chain creation. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct filter_chain_d3d11_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + /// Use a deferred context to record shader rendering state. + /// + /// The deferred context will be executed on the immediate context + /// with `RenderContextState = true`. + pub use_deferred_context: bool, + + /// Whether or not to explicitly disable mipmap + /// generation regardless of shader preset settings. + pub force_no_mipmaps: bool, +} + +config_struct! { + impl FilterChainOptionsD3D11 => filter_chain_d3d11_opt_t { + 0 => [use_deferred_context, force_no_mipmaps]; + } +} + +/// Options for each Direct3D 11 shader frame. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct frame_d3d11_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + /// Whether or not to clear the history buffers. + pub clear_history: bool, + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + pub frame_direction: i32, +} + +config_struct! { + impl FrameOptionsD3D11 => frame_d3d11_opt_t { + 0 => [clear_history, frame_direction]; + } +} + extern_fn! { /// Create the filter chain given the shader preset. /// @@ -53,7 +98,7 @@ extern_fn! { /// - `out` must be aligned, but may be null, invalid, or uninitialized. fn libra_d3d11_filter_chain_create( preset: *mut libra_shader_preset_t, - options: *const FilterChainOptionsD3D11, + options: *const MaybeUninit, device: ManuallyDrop, out: *mut MaybeUninit ) { @@ -67,13 +112,14 @@ extern_fn! { let options = if options.is_null() { None } else { - Some(unsafe { &*options }) + Some(unsafe { options.read() }) }; + let options = options.map(FromUninit::from_uninit); let chain = librashader::runtime::d3d11::capi::FilterChainD3D11::load_from_preset( &device, *preset, - options, + options.as_ref(), )?; unsafe { @@ -103,7 +149,7 @@ extern_fn! { viewport: libra_viewport_t, out: ManuallyDrop, mvp: *const f32, - opt: *const FrameOptionsD3D11 + opt: *const MaybeUninit ) mut |chain| { assert_some_ptr!(mut chain); @@ -129,6 +175,8 @@ extern_fn! { mvp, }; + let opt = opt.map(FromUninit::from_uninit); + let image = image.try_into()?; chain.frame(image, &viewport, frame_count, opt.as_ref())?; } diff --git a/librashader-capi/src/runtime/d3d12/filter_chain.rs b/librashader-capi/src/runtime/d3d12/filter_chain.rs index 325aadd..6bef61e 100644 --- a/librashader-capi/src/runtime/d3d12/filter_chain.rs +++ b/librashader-capi/src/runtime/d3d12/filter_chain.rs @@ -1,4 +1,6 @@ -use crate::ctypes::{libra_d3d12_filter_chain_t, libra_shader_preset_t, libra_viewport_t}; +use crate::ctypes::{ + config_struct, libra_d3d12_filter_chain_t, libra_shader_preset_t, libra_viewport_t, FromUninit, +}; use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError}; use crate::ffi::extern_fn; use std::ffi::c_char; @@ -16,6 +18,7 @@ pub use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12; use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView}; use librashader::runtime::{FilterChainParameters, Size, Viewport}; +use crate::LIBRASHADER_API_VERSION; /// Direct3D 12 parameters for the source image. #[repr(C)] @@ -41,6 +44,47 @@ pub struct libra_output_image_d3d12_t { pub format: DXGI_FORMAT, } +/// Options for each Direct3D 12 shader frame. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct frame_d3d12_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + /// Whether or not to clear the history buffers. + pub clear_history: bool, + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + pub frame_direction: i32, +} + +config_struct! { + impl FrameOptionsD3D12 => frame_d3d12_opt_t { + 0 => [clear_history, frame_direction]; + } +} + +/// Options for Direct3D11 filter chain creation. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct filter_chain_d3d12_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + + /// Force the HLSL shader pipeline. This may reduce shader compatibility. + pub force_hlsl_pipeline: bool, + + /// Whether or not to explicitly disable mipmap + /// generation for intermediate passes regardless + /// of shader preset settings. + pub force_no_mipmaps: bool, +} + +config_struct! { + impl FilterChainOptionsD3D12 => filter_chain_d3d12_opt_t { + 0 => [force_hlsl_pipeline, force_no_mipmaps]; + } +} + impl TryFrom for D3D12InputImage { type Error = LibrashaderError; @@ -69,7 +113,7 @@ extern_fn! { /// - `out` must be aligned, but may be null, invalid, or uninitialized. fn libra_d3d12_filter_chain_create( preset: *mut libra_shader_preset_t, - options: *const FilterChainOptionsD3D12, + opt: *const MaybeUninit, device: ManuallyDrop, out: *mut MaybeUninit ) { @@ -80,16 +124,17 @@ extern_fn! { Box::from_raw(preset.unwrap().as_ptr()) }; - let options = if options.is_null() { + let opt = if opt.is_null() { None } else { - Some(unsafe { &*options }) + Some(unsafe { opt.read() }) }; + let opt = opt.map(FromUninit::from_uninit); let chain = librashader::runtime::d3d12::capi::FilterChainD3D12::load_from_preset( &device, *preset, - options, + opt.as_ref(), )?; unsafe { @@ -122,7 +167,7 @@ extern_fn! { viewport: libra_viewport_t, out: libra_output_image_d3d12_t, mvp: *const f32, - opt: *const FrameOptionsD3D12 + options: *const MaybeUninit ) mut |chain| { assert_some_ptr!(mut chain); @@ -132,12 +177,13 @@ extern_fn! { Some(<&[f32; 16]>::try_from(unsafe { slice::from_raw_parts(mvp, 16) }).unwrap()) }; - let opt = if opt.is_null() { + let options = if options.is_null() { None } else { - Some(unsafe { opt.read() }) + Some(unsafe { options.read() }) }; + let options = options.map(FromUninit::from_uninit); let viewport = Viewport { x: viewport.x, y: viewport.y, @@ -146,7 +192,7 @@ extern_fn! { }; let image = image.try_into()?; - chain.frame(&command_list, image, &viewport, frame_count, opt.as_ref())?; + chain.frame(&command_list, image, &viewport, frame_count, options.as_ref())?; } } diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index 595f48e..d524023 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -1,4 +1,6 @@ -use crate::ctypes::{libra_gl_filter_chain_t, libra_shader_preset_t, libra_viewport_t}; +use crate::ctypes::{ + config_struct, libra_gl_filter_chain_t, libra_shader_preset_t, libra_viewport_t, FromUninit, +}; use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError}; use crate::ffi::extern_fn; use librashader::runtime::gl::{Framebuffer, GLImage}; @@ -12,6 +14,7 @@ pub use librashader::runtime::gl::capi::options::FilterChainOptionsGL; pub use librashader::runtime::gl::capi::options::FrameOptionsGL; use librashader::runtime::FilterChainParameters; use librashader::runtime::{Size, Viewport}; +use crate::LIBRASHADER_API_VERSION; /// A GL function loader that librashader needs to be initialized with. pub type libra_gl_loader_t = unsafe extern "system" fn(*const c_char) -> *const c_void; @@ -51,6 +54,45 @@ impl From for GLImage { } } +/// Options for each OpenGL shader frame. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct frame_gl_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + /// Whether or not to clear the history buffers. + pub clear_history: bool, + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + pub frame_direction: i32, +} + +config_struct! { + impl FrameOptionsGL => frame_gl_opt_t { + 0 => [clear_history, frame_direction]; + } +} + +/// Options for filter chain creation. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct filter_chain_gl_opt_t { + /// The librashader API version. + pub version: LIBRASHADER_API_VERSION, + /// The GLSL version. Should be at least `330`. + pub glsl_version: u16, + /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. + pub use_dsa: bool, + /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. + pub force_no_mipmaps: bool, +} + +config_struct! { + impl FilterChainOptionsGL => filter_chain_gl_opt_t { + 0 => [glsl_version, use_dsa, force_no_mipmaps]; + } +} + extern_fn! { /// Initialize the OpenGL Context for librashader. /// @@ -84,7 +126,7 @@ extern_fn! { /// - `out` must be aligned, but may be null, invalid, or uninitialized. fn libra_gl_filter_chain_create( preset: *mut libra_shader_preset_t, - options: *const FilterChainOptionsGL, + options: *const MaybeUninit, out: *mut MaybeUninit ) { assert_non_null!(preset); @@ -97,10 +139,11 @@ extern_fn! { let options = if options.is_null() { None } else { - Some(unsafe { &*options }) + Some(unsafe { options.read() }) }; - let chain = librashader::runtime::gl::capi::FilterChainGL::load_from_preset(*preset, options)?; + let options = options.map(FromUninit::from_uninit); + let chain = librashader::runtime::gl::capi::FilterChainGL::load_from_preset(*preset, options.as_ref())?; unsafe { out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new( @@ -127,7 +170,7 @@ extern_fn! { viewport: libra_viewport_t, out: libra_output_framebuffer_gl_t, mvp: *const f32, - opt: *const FrameOptionsGL + opt: *const MaybeUninit, ) mut |chain| { assert_some_ptr!(mut chain); let image: GLImage = image.into(); @@ -141,6 +184,8 @@ extern_fn! { } else { Some(unsafe { opt.read() }) }; + + let opt = opt.map(FromUninit::from_uninit); let framebuffer = Framebuffer::new_from_raw(out.texture, out.handle, out.format, Size::new(viewport.width, viewport.height), 1); let viewport = Viewport { x: viewport.x, diff --git a/librashader-capi/src/runtime/vk/filter_chain.rs b/librashader-capi/src/runtime/vk/filter_chain.rs index 9616739..002f8fb 100644 --- a/librashader-capi/src/runtime/vk/filter_chain.rs +++ b/librashader-capi/src/runtime/vk/filter_chain.rs @@ -1,4 +1,6 @@ -use crate::ctypes::{libra_shader_preset_t, libra_viewport_t, libra_vk_filter_chain_t}; +use crate::ctypes::{ + config_struct, libra_shader_preset_t, libra_viewport_t, libra_vk_filter_chain_t, FromUninit, +}; use crate::error::{assert_non_null, assert_some_ptr, LibrashaderError}; use crate::ffi::extern_fn; use librashader::runtime::vk::{VulkanImage, VulkanInstance}; @@ -80,6 +82,46 @@ impl From for VulkanInstance { } } +/// Options for each OpenGL shader frame. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct frame_vk_opt_t { + /// The librashader API version. + pub version: usize, + /// Whether or not to clear the history buffers. + pub clear_history: bool, + /// The direction of rendering. + /// -1 indicates that the frames are played in reverse order. + pub frame_direction: i32, +} + +config_struct! { + impl FrameOptionsVulkan => frame_vk_opt_t { + 0 => [clear_history, frame_direction]; + } +} + +/// Options for filter chain creation. +#[repr(C)] +#[derive(Default, Debug, Clone)] +pub struct filter_chain_vk_opt_t { + /// The librashader API version. + pub version: usize, + /// The number of frames in flight to keep. If zero, defaults to three. + pub frames_in_flight: u32, + /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. + pub force_no_mipmaps: bool, + /// Use explicit render pass objects It is recommended if possible to use dynamic rendering, + /// because render-pass mode will create new framebuffers per pass. + pub use_render_pass: bool, +} + +config_struct! { + impl FilterChainOptionsVulkan => filter_chain_vk_opt_t { + 0 => [frames_in_flight, force_no_mipmaps, use_render_pass]; + } +} + extern_fn! { /// Create the filter chain given the shader preset. /// @@ -96,7 +138,7 @@ extern_fn! { fn libra_vk_filter_chain_create( vulkan: libra_device_vk_t, preset: *mut libra_shader_preset_t, - options: *const FilterChainOptionsVulkan, + options: *const MaybeUninit, out: *mut MaybeUninit ) { assert_non_null!(preset); @@ -109,12 +151,13 @@ extern_fn! { let options = if options.is_null() { None } else { - Some(unsafe { &*options }) + Some(unsafe { options.read() }) }; let vulkan: VulkanInstance = vulkan.into(); + let options = options.map(FromUninit::from_uninit); - let chain = librashader::runtime::vk::capi::FilterChainVulkan::load_from_preset(vulkan, *preset, options)?; + let chain = librashader::runtime::vk::capi::FilterChainVulkan::load_from_preset(vulkan, *preset, options.as_ref())?; unsafe { out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new( @@ -147,7 +190,7 @@ extern_fn! { viewport: libra_viewport_t, out: libra_output_image_vk_t, mvp: *const f32, - opt: *const FrameOptionsVulkan + opt: *const MaybeUninit ) mut |chain| { assert_some_ptr!(mut chain); let image: VulkanImage = image.into(); @@ -166,6 +209,7 @@ extern_fn! { } else { Some(unsafe { opt.read() }) }; + let opt = opt.map(FromUninit::from_uninit); let viewport = Viewport { x: viewport.x, y: viewport.y, diff --git a/librashader-runtime-d3d11/src/options.rs b/librashader-runtime-d3d11/src/options.rs index 097b166..e8cbff8 100644 --- a/librashader-runtime-d3d11/src/options.rs +++ b/librashader-runtime-d3d11/src/options.rs @@ -1,8 +1,8 @@ -//! Direct3D11 shader runtime options. +//! Direct3D 11 shader runtime options. -/// Options for each Direct3D11 shader frame. +/// Options for each Direct3D 11 shader frame. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FrameOptionsD3D11 { /// Whether or not to clear the history buffers. pub clear_history: bool, @@ -11,9 +11,9 @@ pub struct FrameOptionsD3D11 { pub frame_direction: i32, } -/// Options for Direct3D11 filter chain creation. +/// Options for Direct3D 11 filter chain creation. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FilterChainOptionsD3D11 { /// Use a deferred context to record shader rendering state. /// diff --git a/librashader-runtime-d3d12/src/options.rs b/librashader-runtime-d3d12/src/options.rs index 3847833..1a4d4c3 100644 --- a/librashader-runtime-d3d12/src/options.rs +++ b/librashader-runtime-d3d12/src/options.rs @@ -1,8 +1,8 @@ -//! Direct3D12 shader runtime options. +//! Direct3D 12 shader runtime options. -/// Options for each Direct3D11 shader frame. +/// Options for each Direct3D12 shader frame. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FrameOptionsD3D12 { /// Whether or not to clear the history buffers. pub clear_history: bool, @@ -11,9 +11,9 @@ pub struct FrameOptionsD3D12 { pub frame_direction: i32, } -/// Options for Direct3D11 filter chain creation. +/// Options for Direct3D 12 filter chain creation. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FilterChainOptionsD3D12 { /// Force the HLSL shader pipeline. This may reduce shader compatibility. pub force_hlsl_pipeline: bool, diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/filter_impl.rs index 0c6c4b5..2e0bb7c 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/filter_impl.rs @@ -107,7 +107,7 @@ impl FilterChainImpl { FilterChainError, >(preset.shaders, &preset.textures)?; - let version = options.map_or_else(gl_get_version, |o| gl_u16_to_version(o.gl_version)); + let version = options.map_or_else(gl_get_version, |o| gl_u16_to_version(o.glsl_version)); // initialize passes let filters = Self::init_passes(version, passes, &semantics)?; diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 337b293..099229b 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -37,7 +37,7 @@ mod tests { let mut filter = FilterChainGL::load_from_path( "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", Some(&FilterChainOptionsGL { - gl_version: 0, + glsl_version: 0, use_dsa: false, force_no_mipmaps: false, }), @@ -54,7 +54,7 @@ mod tests { // "../test/slang-shaders/vhs/VHSPro.slangp", "../test/slang-shaders/crt/crt-royale.slangp", Some(&FilterChainOptionsGL { - gl_version: 0, + glsl_version: 0, use_dsa: true, force_no_mipmaps: false, }), diff --git a/librashader-runtime-gl/src/options.rs b/librashader-runtime-gl/src/options.rs index f7ab097..b8009c2 100644 --- a/librashader-runtime-gl/src/options.rs +++ b/librashader-runtime-gl/src/options.rs @@ -2,7 +2,7 @@ /// Options for each OpenGL shader frame. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FrameOptionsGL { /// Whether or not to clear the history buffers. pub clear_history: bool, @@ -13,10 +13,10 @@ pub struct FrameOptionsGL { /// Options for filter chain creation. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FilterChainOptionsGL { /// The GLSL version. Should be at least `330`. - pub gl_version: u16, + pub glsl_version: u16, /// Whether or not to use the Direct State Access APIs. Only available on OpenGL 4.5+. pub use_dsa: bool, /// Whether or not to explicitly disable mipmap generation regardless of shader preset settings. diff --git a/librashader-runtime-vk/src/options.rs b/librashader-runtime-vk/src/options.rs index 7d6a35f..7ef3c6f 100644 --- a/librashader-runtime-vk/src/options.rs +++ b/librashader-runtime-vk/src/options.rs @@ -2,7 +2,7 @@ /// Options for each Vulkan shader frame. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FrameOptionsVulkan { /// Whether or not to clear the history buffers. pub clear_history: bool, @@ -13,7 +13,7 @@ pub struct FrameOptionsVulkan { /// Options for filter chain creation. #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Default, Debug, Clone)] pub struct FilterChainOptionsVulkan { /// The number of frames in flight to keep. If zero, defaults to three. pub frames_in_flight: u32, diff --git a/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp b/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp index 947dac6..a8d5374 100644 --- a/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp +++ b/test/capi-tests/imgui/examples/example_win32_directx11/main.cpp @@ -66,12 +66,12 @@ int main(int, char**) auto libra = librashader_load_instance(); libra_shader_preset_t preset; auto error = libra.preset_create( - "../../../../../../slang-shaders/crt/crt-royale.slangp", &preset); + "../../../../../../slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV-GLASS.slangp", &preset); libra_d3d11_filter_chain_t filter_chain; filter_chain_d3d11_opt_t opt = { .use_deferred_context = true, - .force_no_mipmaps = false, + .force_no_mipmaps = true, }; libra.d3d11_filter_chain_create(&preset, &opt, g_pd3dDevice, &filter_chain); @@ -181,8 +181,11 @@ int main(int, char**) framebufferTextureDesc.Width, framebufferTextureDesc.Height, }; - frame_d3d11_opt_t frame_opt = {.clear_history = false, - .frame_direction = -1}; + frame_d3d11_opt_t frame_opt = { + .version = 0, + .clear_history = false, + .frame_direction = -1 + }; libra.d3d11_filter_chain_frame(&filter_chain, frameCount, input, vp, g_mainRenderTargetView, NULL, &frame_opt);