1use crate::parameters::RuntimeParameters;
2use crate::uniforms::{BindUniform, NoUniformBinder, UniformStorage};
3use librashader_common::map::{FastHashMap, ShortString};
4use librashader_common::Size;
5use librashader_preprocess::ShaderParameter;
6use librashader_reflect::reflect::semantics::{
7 BindingMeta, MemberOffset, Semantic, TextureBinding, TextureSemantics, UniformBinding,
8 UniformMeta, UniqueSemantics,
9};
10use num_traits::Zero;
11use std::ops::{Deref, DerefMut};
12
13pub trait TextureInput {
15 fn size(&self) -> Size<u32>;
17}
18
19pub trait ContextOffset<H, C, D = ()>
21where
22 H: BindUniform<C, f32, D>,
23 H: BindUniform<C, u32, D>,
24 H: BindUniform<C, i32, D>,
25 H: for<'a> BindUniform<C, &'a [f32; 4], D>,
26 H: for<'a> BindUniform<C, &'a [f32; 16], D>,
27{
28 fn offset(&self) -> MemberOffset;
30
31 fn context(&self) -> C;
33}
34
35impl<D, H> ContextOffset<H, Option<()>, D> for MemberOffset
36where
37 H: BindUniform<Option<()>, f32, D>,
38 H: BindUniform<Option<()>, u32, D>,
39 H: BindUniform<Option<()>, i32, D>,
40 H: for<'a> BindUniform<Option<()>, &'a [f32; 4], D>,
41 H: for<'a> BindUniform<Option<()>, &'a [f32; 16], D>,
42{
43 fn offset(&self) -> MemberOffset {
44 *self
45 }
46
47 fn context(&self) -> Option<()> {
48 None
49 }
50}
51
52pub struct UniformInputs<'a> {
54 pub mvp: &'a [f32; 16],
56 pub frame_count: u32,
58 pub rotation: u32,
60 pub total_subframes: u32,
62 pub current_subframe: u32,
64 pub frame_direction: i32,
66 pub aspect_ratio: f32,
68 pub frames_per_second: f32,
70 pub frametime_delta: u32,
72 pub framebuffer_size: Size<u32>,
74 pub viewport_size: Size<u32>,
76}
77
78pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
80where
81 C: Copy,
82 U: Deref<Target = [u8]> + DerefMut,
83 P: Deref<Target = [u8]> + DerefMut,
84 H: BindUniform<C, f32, Self::DeviceContext>,
85 H: BindUniform<C, u32, Self::DeviceContext>,
86 H: BindUniform<C, i32, Self::DeviceContext>,
87 H: for<'b> BindUniform<C, &'b [f32; 4], Self::DeviceContext>,
88 H: for<'b> BindUniform<C, &'b [f32; 16], Self::DeviceContext>,
89{
90 type InputTexture: TextureInput;
92
93 type SamplerSet;
95
96 type DescriptorSet<'a>;
98
99 type DeviceContext;
101
102 type UniformOffset: ContextOffset<H, C, Self::DeviceContext>;
104
105 fn bind_texture<'a>(
107 descriptors: &mut Self::DescriptorSet<'a>,
108 samplers: &Self::SamplerSet,
109 binding: &TextureBinding,
110 texture: &Self::InputTexture,
111 device: &Self::DeviceContext,
112 );
113
114 #[allow(clippy::too_many_arguments)]
115 fn bind_semantics<'a>(
117 device: &Self::DeviceContext,
118 sampler_set: &Self::SamplerSet,
119 uniform_storage: &mut UniformStorage<H, C, U, P, Self::DeviceContext>,
120 descriptor_set: &mut Self::DescriptorSet<'a>,
121 uniform_inputs: UniformInputs<'_>,
122 original: &Self::InputTexture,
123 source: &Self::InputTexture,
124 uniform_bindings: &FastHashMap<UniformBinding, Self::UniformOffset>,
125 texture_meta: &FastHashMap<Semantic<TextureSemantics>, TextureBinding>,
126 pass_outputs: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
127 pass_feedback: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
128 original_history: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
129 lookup_textures: impl Iterator<Item = (usize, impl AsRef<Self::InputTexture>)>,
130 parameter_defaults: &FastHashMap<ShortString, ShaderParameter>,
131 runtime_parameters: &RuntimeParameters,
132 ) {
133 let runtime_parameters = runtime_parameters.parameters.load();
134 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
136 uniform_storage.bind_mat4(
137 offset.offset(),
138 uniform_inputs.mvp,
139 offset.context(),
140 device,
141 );
142 }
143
144 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Output.into()) {
146 uniform_storage.bind_vec4(
147 offset.offset(),
148 uniform_inputs.framebuffer_size,
149 offset.context(),
150 device,
151 );
152 }
153
154 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FinalViewport.into()) {
156 uniform_storage.bind_vec4(
157 offset.offset(),
158 uniform_inputs.viewport_size,
159 offset.context(),
160 device,
161 );
162 }
163
164 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameCount.into()) {
166 uniform_storage.bind_scalar(
167 offset.offset(),
168 uniform_inputs.frame_count,
169 offset.context(),
170 device,
171 );
172 }
173
174 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameDirection.into()) {
176 uniform_storage.bind_scalar(
177 offset.offset(),
178 uniform_inputs.frame_direction,
179 offset.context(),
180 device,
181 );
182 }
183
184 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
186 uniform_storage.bind_scalar(
187 offset.offset(),
188 uniform_inputs.rotation,
189 offset.context(),
190 device,
191 );
192 }
193
194 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::TotalSubFrames.into()) {
196 uniform_storage.bind_scalar(
197 offset.offset(),
198 uniform_inputs.total_subframes,
199 offset.context(),
200 device,
201 );
202 }
203
204 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::CurrentSubFrame.into()) {
206 uniform_storage.bind_scalar(
207 offset.offset(),
208 uniform_inputs.current_subframe,
209 offset.context(),
210 device,
211 );
212 }
213
214 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalFPS.into()) {
216 uniform_storage.bind_scalar(
217 offset.offset(),
218 uniform_inputs.frames_per_second,
219 offset.context(),
220 device,
221 );
222 }
223
224 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameTimeDelta.into()) {
226 uniform_storage.bind_scalar(
227 offset.offset(),
228 uniform_inputs.frametime_delta,
229 offset.context(),
230 device,
231 );
232 }
233
234 let mut aspect_ratio = uniform_inputs.aspect_ratio;
235 if aspect_ratio.is_zero() {
236 aspect_ratio = original.size().aspect_ratio();
237 }
238
239 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspect.into()) {
241 uniform_storage.bind_scalar(offset.offset(), aspect_ratio, offset.context(), device);
242 }
243
244 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspectRotated.into()) {
245 let rotated_aspect = if uniform_inputs.rotation == 1 || uniform_inputs.rotation == 3 {
246 1.0f32 / aspect_ratio
247 } else {
248 aspect_ratio
249 };
250
251 uniform_storage.bind_scalar(offset.offset(), rotated_aspect, offset.context(), device);
252 }
253
254 if let Some(binding) = texture_meta.get(&TextureSemantics::Original.semantics(0)) {
256 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
257 }
258
259 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Original.semantics(0).into())
261 {
262 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
263 }
264
265 if let Some(binding) = texture_meta.get(&TextureSemantics::Source.semantics(0)) {
267 Self::bind_texture(descriptor_set, sampler_set, binding, source, device);
268 }
269
270 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Source.semantics(0).into()) {
272 uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context(), device);
273 }
274
275 if let Some(binding) = texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
279 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
280 }
281
282 if let Some(offset) =
284 uniform_bindings.get(&TextureSemantics::OriginalHistory.semantics(0).into())
285 {
286 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
287 }
288
289 for (index, history) in original_history.enumerate() {
291 let Some(history) = history else {
292 continue;
293 };
294
295 let history = history.as_ref();
296
297 if let Some(binding) =
298 texture_meta.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
299 {
300 Self::bind_texture(descriptor_set, sampler_set, binding, history, device);
301 }
302
303 if let Some(offset) = uniform_bindings.get(
304 &TextureSemantics::OriginalHistory
305 .semantics(index + 1)
306 .into(),
307 ) {
308 uniform_storage.bind_vec4(
309 offset.offset(),
310 history.size(),
311 offset.context(),
312 device,
313 );
314 }
315 }
316
317 for (index, output) in pass_outputs.enumerate() {
321 let Some(output) = output else {
322 continue;
323 };
324
325 let output = output.as_ref();
326
327 if let Some(binding) = texture_meta.get(&TextureSemantics::PassOutput.semantics(index))
328 {
329 Self::bind_texture(descriptor_set, sampler_set, binding, output, device);
330 }
331
332 if let Some(offset) =
333 uniform_bindings.get(&TextureSemantics::PassOutput.semantics(index).into())
334 {
335 uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context(), device);
336 }
337 }
338
339 for (index, feedback) in pass_feedback.enumerate() {
341 let Some(output) = feedback else {
342 continue;
343 };
344
345 let feedback = output.as_ref();
346
347 if let Some(binding) =
348 texture_meta.get(&TextureSemantics::PassFeedback.semantics(index))
349 {
350 Self::bind_texture(descriptor_set, sampler_set, binding, feedback, device);
351 }
352
353 if let Some(offset) =
354 uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
355 {
356 uniform_storage.bind_vec4(
357 offset.offset(),
358 feedback.size(),
359 offset.context(),
360 device,
361 );
362 }
363 }
364
365 for (id, offset) in uniform_bindings
367 .iter()
368 .filter_map(|(binding, value)| match binding {
369 UniformBinding::Parameter(id) => Some((id, value)),
370 _ => None,
371 })
372 {
373 let id = id.as_str();
374
375 let default = parameter_defaults.get(id).map_or(0f32, |f| f.initial);
376
377 let value = *runtime_parameters.get(id).unwrap_or(&default);
378
379 uniform_storage.bind_scalar(offset.offset(), value, offset.context(), device);
380 }
381
382 for (index, lut) in lookup_textures {
384 let lut = lut.as_ref();
385 if let Some(binding) = texture_meta.get(&TextureSemantics::User.semantics(index)) {
386 Self::bind_texture(descriptor_set, sampler_set, binding, lut, device);
387 }
388
389 if let Some(offset) =
390 uniform_bindings.get(&TextureSemantics::User.semantics(index).into())
391 {
392 uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context(), device);
393 }
394 }
395 }
396}
397
398#[derive(Debug)]
399pub struct BindingRequirements {
400 pub(crate) required_history: usize,
401 pub(crate) uses_final_pass_as_feedback: bool,
402}
403
404pub trait BindingUtil {
406 fn create_binding_map<T>(
408 &self,
409 f: impl Fn(&dyn UniformMeta) -> T,
410 ) -> FastHashMap<UniformBinding, T>;
411
412 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
414 where
415 Self: 'a;
416}
417
418impl BindingUtil for BindingMeta {
419 fn create_binding_map<T>(
420 &self,
421 f: impl Fn(&dyn UniformMeta) -> T,
422 ) -> FastHashMap<UniformBinding, T> {
423 let mut uniform_bindings = FastHashMap::default();
424 for param in self.parameter_meta.values() {
425 uniform_bindings.insert(UniformBinding::Parameter(param.id.clone()), f(param));
426 }
427
428 for (semantics, param) in &self.unique_meta {
429 uniform_bindings.insert(UniformBinding::SemanticVariable(*semantics), f(param));
430 }
431
432 for (semantics, param) in &self.texture_size_meta {
433 uniform_bindings.insert(UniformBinding::TextureSize(*semantics), f(param));
434 }
435
436 uniform_bindings
437 }
438
439 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
440 where
441 Self: 'a,
442 {
443 let mut required_images = 0;
444
445 let mut len: i64 = 0;
446 let mut latest_feedback_pass: i64 = -1;
447
448 for pass in pass_meta {
449 len += 1;
450
451 let history_texture_max_index = pass
453 .texture_meta
454 .iter()
455 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
456 .map(|(semantic, _)| semantic.index)
457 .fold(0, std::cmp::max);
458 let history_texture_size_max_index = pass
459 .texture_size_meta
460 .iter()
461 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
462 .map(|(semantic, _)| semantic.index)
463 .fold(0, std::cmp::max);
464
465 let feedback_max_index = pass
466 .texture_meta
467 .iter()
468 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback)
469 .map(|(semantic, _)| semantic.index as i64)
470 .fold(-1, std::cmp::max);
471 let feedback_max_size_index = pass
472 .texture_size_meta
473 .iter()
474 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback)
475 .map(|(semantic, _)| semantic.index as i64)
476 .fold(-1, std::cmp::max);
477
478 latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_index);
479 latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_size_index);
480
481 required_images = std::cmp::max(required_images, history_texture_max_index);
482 required_images = std::cmp::max(required_images, history_texture_size_max_index);
483 }
484
485 let uses_feedback = if latest_feedback_pass.is_negative() {
486 false
487 } else {
488 latest_feedback_pass + 1 >= len
492 };
493
494 BindingRequirements {
495 required_history: required_images,
496 uses_final_pass_as_feedback: uses_feedback,
497 }
498 }
499}
500
501#[macro_export]
502macro_rules! impl_default_frame_options {
503 ($ty:ident) => {
504 #[repr(C)]
506 #[derive(Debug, Clone)]
507 pub struct $ty {
508 pub clear_history: bool,
510 pub frame_direction: i32,
513 pub rotation: u32,
515 pub total_subframes: u32,
517 pub current_subframe: u32,
519 pub aspect_ratio: f32,
526 pub frames_per_second: f32,
528 pub frametime_delta: u32,
530 }
531
532 impl Default for $ty {
533 fn default() -> Self {
534 Self {
535 clear_history: false,
536 frame_direction: 1,
537 rotation: 0,
538 total_subframes: 1,
539 current_subframe: 1,
540 aspect_ratio: 0.0,
541 frametime_delta: 0,
542 frames_per_second: 1.0,
543 }
544 }
545 }
546 };
547}