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}