librashader_capi/
wildcard.rs

1//! librashader preset wildcard context C API (`libra_preset_ctx_*`).
2
3use crate::ctypes::{libra_preset_ctx_t, LIBRA_PRESET_CTX_ORIENTATION, LIBRA_PRESET_CTX_RUNTIME};
4use crate::error::{assert_non_null, assert_some_ptr};
5
6use librashader::presets::context::{
7    ContextItem, PresetExtension, Rotation, ShaderExtension, WildcardContext,
8};
9use std::ffi::{c_char, CStr};
10use std::mem::MaybeUninit;
11use std::ptr::NonNull;
12
13use crate::ffi::extern_fn;
14
15const _: () = crate::assert_thread_safe::<WildcardContext>();
16
17extern_fn! {
18    /// Create a wildcard context
19    ///
20    /// The C API does not allow directly setting certain variables
21    ///
22    /// - `PRESET_DIR` and `PRESET` are inferred on preset creation.
23    /// - `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are always set to `slang` and `slangp` for librashader.
24    /// - `VID-FINAL-ROT` is automatically calculated as the sum of `VID-USER-ROT` and `CORE-REQ-ROT` if either are present.
25    ///
26    /// These automatically inferred variables, as well as all other variables can be overridden with
27    /// `libra_preset_ctx_set_param`, but the expected string values must be provided.
28    /// See <https://github.com/libretro/RetroArch/pull/15023> for a list of expected string values.
29    ///
30    /// No variables can be removed once added to the context, however subsequent calls to set the same
31    /// variable will overwrite the expected variable.
32    /// ## Safety
33    ///  - `out` must be either null, or an aligned pointer to an uninitialized or invalid `libra_preset_ctx_t`.
34    /// ## Returns
35    ///  - If any parameters are null, `out` is unchanged, and this function returns `LIBRA_ERR_INVALID_PARAMETER`.
36    fn libra_preset_ctx_create(
37        out: *mut MaybeUninit<libra_preset_ctx_t>
38    ) {
39        assert_non_null!(out);
40
41        unsafe {
42            out.write(MaybeUninit::new(NonNull::new(Box::into_raw(Box::new(
43                WildcardContext::new(),
44            )))));
45        }
46    }
47}
48
49extern_fn! {
50    /// Free the wildcard context.
51    ///
52    /// If `context` is null, this function does nothing. The resulting value in `context` then becomes
53    /// null.
54    ///
55    /// ## Safety
56    /// - `context` must be a valid and aligned pointer to a `libra_preset_ctx_t`
57    fn libra_preset_ctx_free(context: *mut libra_preset_ctx_t) {
58        assert_non_null!(context);
59        unsafe {
60            let context_ptr = &mut *context;
61            let context = context_ptr.take();
62            drop(Box::from_raw(context.unwrap().as_ptr()));
63        }
64    }
65}
66
67extern_fn! {
68    /// Set the core name (`CORE`) variable in the context
69    ///
70    /// ## Safety
71    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
72    /// - `name` must be null or a valid and aligned pointer to a string.
73    fn libra_preset_ctx_set_core_name(
74        context: *mut libra_preset_ctx_t,
75        name: *const c_char,
76    ) |name|; mut |context| {
77        let name = unsafe {
78            CStr::from_ptr(name)
79        };
80
81        let name = name.to_str()?;
82        assert_some_ptr!(mut context);
83
84        context.append_item(ContextItem::CoreName(String::from(name)));
85    }
86}
87
88extern_fn! {
89    /// Set the content directory (`CONTENT-DIR`) variable in the context.
90    ///
91    /// ## Safety
92    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
93    /// - `name` must be null or a valid and aligned pointer to a string.
94    fn libra_preset_ctx_set_content_dir(
95        context: *mut libra_preset_ctx_t,
96        name: *const c_char,
97    ) |name|; mut |context| {
98        let name = unsafe {
99            CStr::from_ptr(name)
100        };
101
102        let name = name.to_str()?;
103        assert_some_ptr!(mut context);
104        context.append_item(ContextItem::ContentDirectory(String::from(name)));
105    }
106}
107
108extern_fn! {
109    /// Set a custom string variable in context.
110    ///
111    /// If the path contains this variable when loading a preset, it will be replaced with the
112    /// provided contents.
113    ///
114    /// ## Safety
115    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
116    /// - `name` must be null or a valid and aligned pointer to a string.
117    /// - `value` must be null or a valid and aligned pointer to a string.
118    fn libra_preset_ctx_set_param(
119        context: *mut libra_preset_ctx_t,
120        name: *const c_char,
121        value: *const c_char,
122    ) |name, value|; mut |context| {
123        let name = unsafe {
124            CStr::from_ptr(name)
125        };
126        let name = name.to_str()?;
127
128        let value = unsafe {
129            CStr::from_ptr(value)
130        };
131        let value = value.to_str()?;
132
133        assert_some_ptr!(mut context);
134        context.append_item(ContextItem::ExternContext(String::from(name), String::from(value)));
135    }
136}
137
138extern_fn! {
139    /// Set the graphics runtime (`VID-DRV`) variable in the context.
140    ///
141    /// Note that librashader only supports the following runtimes.
142    ///
143    /// - Vulkan
144    /// - GLCore
145    /// - Direct3D11
146    /// - Direct3D12
147    /// - Metal
148    /// - Direct3D9 (HLSL)
149    ///
150    /// This will also set the appropriate video driver extensions.
151    ///
152    /// For librashader, `VID-DRV-SHADER-EXT` and `VID-DRV-PRESET-EXT` are always `slang` and `slangp`.
153    /// To override this, use `libra_preset_ctx_set_param`.
154    ///
155    /// ## Safety
156    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
157    /// - `name` must be null or a valid and aligned pointer to a string.
158    fn libra_preset_ctx_set_runtime(
159        context: *mut libra_preset_ctx_t,
160        value: LIBRA_PRESET_CTX_RUNTIME,
161    ) mut |context| {
162        assert_some_ptr!(mut context);
163
164        context.append_item(ContextItem::VideoDriverPresetExtension(
165            PresetExtension::Slangp,
166        ));
167        context.append_item(ContextItem::VideoDriverShaderExtension(
168            ShaderExtension::Slang,
169        ));
170        context.append_item(ContextItem::VideoDriver(value.into()));
171    }
172}
173
174extern_fn! {
175    /// Set the core requested rotation (`CORE-REQ-ROT`) variable in the context.
176    ///
177    /// Rotation is represented by quarter rotations around the unit circle.
178    /// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
179    ///
180    /// ## Safety
181    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
182    fn libra_preset_ctx_set_core_rotation(
183        context: *mut libra_preset_ctx_t,
184        value: u32,
185    ) mut |context| {
186        assert_some_ptr!(mut context);
187        context.append_item(ContextItem::CoreRequestedRotation(Rotation::from(value)))
188    }
189}
190
191extern_fn! {
192    /// Set the user rotation (`VID-USER-ROT`) variable in the context.
193    ///
194    /// Rotation is represented by quarter rotations around the unit circle.
195    /// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
196    ///
197    /// ## Safety
198    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
199    fn libra_preset_ctx_set_user_rotation(
200        context: *mut libra_preset_ctx_t,
201        value: u32,
202    ) mut |context| {
203        assert_some_ptr!(mut context);
204        context.append_item(ContextItem::UserRotation(Rotation::from(value)))
205    }
206}
207
208extern_fn! {
209    /// Set the screen orientation (`SCREEN-ORIENT`) variable in the context.
210    ///
211    /// Orientation is represented by quarter rotations around the unit circle.
212    /// For example. `0` = 0deg, `1` = 90deg, `2` = 180deg, `3` = 270deg, `4` = 0deg.
213    ///
214    /// ## Safety
215    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
216    fn libra_preset_ctx_set_screen_orientation(
217        context: *mut libra_preset_ctx_t,
218        value: u32,
219    ) mut |context| {
220        assert_some_ptr!(mut context);
221        context.append_item(ContextItem::ScreenOrientation(Rotation::from(value)))
222    }
223}
224
225extern_fn! {
226    /// Set whether or not to allow rotation (`VID-ALLOW-CORE-ROT`) variable in the context.
227    ///
228    /// ## Safety
229    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
230    fn libra_preset_ctx_set_allow_rotation(
231        context: *mut libra_preset_ctx_t,
232        value: bool,
233    ) mut |context| {
234        assert_some_ptr!(mut context);
235        context.append_item(ContextItem::AllowCoreRotation(value.into()))
236    }
237}
238
239extern_fn! {
240    /// Set the view aspect orientation (`VIEW-ASPECT-ORIENT`) variable in the context.
241    //////
242    /// ## Safety
243    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
244    fn libra_preset_ctx_set_view_aspect_orientation(
245        context: *mut libra_preset_ctx_t,
246        value: LIBRA_PRESET_CTX_ORIENTATION,
247    ) mut |context| {
248        assert_some_ptr!(mut context);
249        context.append_item(ContextItem::ViewAspectOrientation(value.into()))
250    }
251}
252
253extern_fn! {
254    /// Set the core aspect orientation (`CORE-ASPECT-ORIENT`) variable in the context.
255    //////
256    /// ## Safety
257    /// - `context` must be null or a valid and aligned pointer to a `libra_preset_ctx_t`.
258    fn libra_preset_ctx_set_core_aspect_orientation(
259        context: *mut libra_preset_ctx_t,
260        value: LIBRA_PRESET_CTX_ORIENTATION,
261    ) mut |context| {
262        assert_some_ptr!(mut context);
263        context.append_item(ContextItem::CoreAspectOrientation(value.into()))
264    }
265}