1use crate::parameters::RuntimeParameters;
2use crate::uniforms::{BindUniform, NoUniformBinder, UniformStorage};
3use bit_set::BitSet;
4use librashader_common::map::{FastHashMap, ShortString};
5use librashader_common::Size;
6use librashader_preprocess::ShaderParameter;
7use librashader_reflect::reflect::semantics::{
8 BindingMeta, MemberOffset, Semantic, TextureBinding, TextureSemantics, UniformBinding,
9 UniformMeta, UniqueSemantics,
10};
11use num_traits::Zero;
12use std::ops::{Deref, DerefMut};
13
14pub trait TextureInput {
16 fn size(&self) -> Size<u32>;
18}
19
20pub trait ContextOffset<H, C, D = ()>
22where
23 H: BindUniform<C, f32, D>,
24 H: BindUniform<C, u32, D>,
25 H: BindUniform<C, i32, D>,
26 H: for<'a> BindUniform<C, &'a [f32; 3], D>,
27 H: for<'a> BindUniform<C, &'a [f32; 4], D>,
28 H: for<'a> BindUniform<C, &'a [f32; 16], D>,
29{
30 fn offset(&self) -> MemberOffset;
32
33 fn context(&self) -> C;
35}
36
37impl<D, H> ContextOffset<H, Option<()>, D> for MemberOffset
38where
39 H: BindUniform<Option<()>, f32, D>,
40 H: BindUniform<Option<()>, u32, D>,
41 H: BindUniform<Option<()>, i32, D>,
42 H: for<'a> BindUniform<Option<()>, &'a [f32; 3], D>,
43 H: for<'a> BindUniform<Option<()>, &'a [f32; 4], D>,
44 H: for<'a> BindUniform<Option<()>, &'a [f32; 16], D>,
45{
46 fn offset(&self) -> MemberOffset {
47 *self
48 }
49
50 fn context(&self) -> Option<()> {
51 None
52 }
53}
54
55pub struct UniformInputs<'a> {
57 pub mvp: &'a [f32; 16],
59 pub frame_count: u32,
61 pub rotation: u32,
63 pub total_subframes: u32,
65 pub current_subframe: u32,
67 pub frame_direction: i32,
69 pub aspect_ratio: f32,
71 pub frames_per_second: f32,
73 pub frametime_delta: u32,
75 pub framebuffer_size: Size<u32>,
77 pub viewport_size: Size<u32>,
79 pub hdr_inputs: HdrUniformInputs,
81 pub sensor_inputs: SensorUniformInputs,
83}
84
85pub struct SensorUniformInputs {
87 pub gyroscope: [f32; 3],
89 pub accelerometer: [f32; 3],
91 pub accelerometer_rest: [f32; 3],
93}
94
95pub struct HdrUniformInputs {
96 pub color_space: librashader_common::ColorSpace,
98 pub brightness_nits: f32,
100 pub expand_gamut: u32,
102}
103
104pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
106where
107 C: Copy,
108 U: Deref<Target = [u8]> + DerefMut,
109 P: Deref<Target = [u8]> + DerefMut,
110 H: BindUniform<C, f32, Self::DeviceContext>,
111 H: BindUniform<C, u32, Self::DeviceContext>,
112 H: BindUniform<C, i32, Self::DeviceContext>,
113 H: for<'b> BindUniform<C, &'b [f32; 3], Self::DeviceContext>,
114 H: for<'b> BindUniform<C, &'b [f32; 4], Self::DeviceContext>,
115 H: for<'b> BindUniform<C, &'b [f32; 16], Self::DeviceContext>,
116{
117 type InputTexture: TextureInput;
119
120 type SamplerSet;
122
123 type DescriptorSet<'a>;
125
126 type DeviceContext;
128
129 type UniformOffset: ContextOffset<H, C, Self::DeviceContext>;
131
132 fn bind_texture<'a>(
134 descriptors: &mut Self::DescriptorSet<'a>,
135 samplers: &Self::SamplerSet,
136 binding: &TextureBinding,
137 texture: &Self::InputTexture,
138 device: &Self::DeviceContext,
139 );
140
141 #[allow(clippy::too_many_arguments)]
142 fn bind_semantics<'a>(
144 device: &Self::DeviceContext,
145 sampler_set: &Self::SamplerSet,
146 uniform_storage: &mut UniformStorage<H, C, U, P, Self::DeviceContext>,
147 descriptor_set: &mut Self::DescriptorSet<'a>,
148 uniform_inputs: UniformInputs<'_>,
149 original: &Self::InputTexture,
150 source: &Self::InputTexture,
151 uniform_bindings: &FastHashMap<UniformBinding, Self::UniformOffset>,
152 texture_meta: &FastHashMap<Semantic<TextureSemantics>, TextureBinding>,
153 pass_outputs: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
154 pass_feedback: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
155 original_history: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
156 lookup_textures: impl Iterator<Item = (usize, impl AsRef<Self::InputTexture>)>,
157 parameter_defaults: &FastHashMap<ShortString, ShaderParameter>,
158 runtime_parameters: &RuntimeParameters,
159 ) {
160 let runtime_parameters = runtime_parameters.parameters.load();
161 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
163 uniform_storage.bind_mat4(
164 offset.offset(),
165 uniform_inputs.mvp,
166 offset.context(),
167 device,
168 );
169 }
170
171 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Output.into()) {
173 uniform_storage.bind_vec4(
174 offset.offset(),
175 uniform_inputs.framebuffer_size,
176 offset.context(),
177 device,
178 );
179 }
180
181 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FinalViewport.into()) {
183 uniform_storage.bind_vec4(
184 offset.offset(),
185 uniform_inputs.viewport_size,
186 offset.context(),
187 device,
188 );
189 }
190
191 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameCount.into()) {
193 uniform_storage.bind_scalar(
194 offset.offset(),
195 uniform_inputs.frame_count,
196 offset.context(),
197 device,
198 );
199 }
200
201 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameDirection.into()) {
203 uniform_storage.bind_scalar(
204 offset.offset(),
205 uniform_inputs.frame_direction,
206 offset.context(),
207 device,
208 );
209 }
210
211 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
213 uniform_storage.bind_scalar(
214 offset.offset(),
215 uniform_inputs.rotation,
216 offset.context(),
217 device,
218 );
219 }
220
221 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::TotalSubFrames.into()) {
223 uniform_storage.bind_scalar(
224 offset.offset(),
225 uniform_inputs.total_subframes,
226 offset.context(),
227 device,
228 );
229 }
230
231 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::CurrentSubFrame.into()) {
233 uniform_storage.bind_scalar(
234 offset.offset(),
235 uniform_inputs.current_subframe,
236 offset.context(),
237 device,
238 );
239 }
240
241 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalFPS.into()) {
243 uniform_storage.bind_scalar(
244 offset.offset(),
245 uniform_inputs.frames_per_second,
246 offset.context(),
247 device,
248 );
249 }
250
251 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameTimeDelta.into()) {
253 uniform_storage.bind_scalar(
254 offset.offset(),
255 uniform_inputs.frametime_delta,
256 offset.context(),
257 device,
258 );
259 }
260
261 let mut aspect_ratio = uniform_inputs.aspect_ratio;
262 if aspect_ratio.is_zero() {
263 aspect_ratio = original.size().aspect_ratio();
264 }
265
266 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspect.into()) {
268 uniform_storage.bind_scalar(offset.offset(), aspect_ratio, offset.context(), device);
269 }
270
271 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspectRotated.into()) {
272 let rotated_aspect = if uniform_inputs.rotation == 1 || uniform_inputs.rotation == 3 {
273 1.0f32 / aspect_ratio
274 } else {
275 aspect_ratio
276 };
277
278 uniform_storage.bind_scalar(offset.offset(), rotated_aspect, offset.context(), device);
279 }
280
281 let hdr = uniform_inputs.hdr_inputs;
282 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::HDRMode.into()) {
284 uniform_storage.bind_scalar(
285 offset.offset(),
286 hdr.color_space as u32,
287 offset.context(),
288 device,
289 );
290 }
291
292 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::BrightnessNits.into()) {
294 uniform_storage.bind_scalar(
295 offset.offset(),
296 hdr.brightness_nits,
297 offset.context(),
298 device,
299 );
300 }
301
302 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::ExpandGamut.into()) {
304 uniform_storage.bind_scalar(
305 offset.offset(),
306 hdr.expand_gamut,
307 offset.context(),
308 device,
309 );
310 }
311
312 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Scanlines.into()) {
318 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
319 }
320 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::InverseTonemap.into()) {
321 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
322 }
323 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::HDR10.into()) {
324 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
325 }
326 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::SubpixelLayout.into()) {
327 uniform_storage.bind_scalar(offset.offset(), 0u32, offset.context(), device);
328 }
329
330 let sensors = uniform_inputs.sensor_inputs;
331 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Gyroscope.into()) {
333 uniform_storage.bind_vec3(offset.offset(), sensors.gyroscope, offset.context(), device);
334 }
335
336 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Accelerometer.into()) {
338 uniform_storage.bind_vec3(
339 offset.offset(),
340 sensors.accelerometer,
341 offset.context(),
342 device,
343 );
344 }
345
346 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::AccelerometerRest.into()) {
348 uniform_storage.bind_vec3(
349 offset.offset(),
350 sensors.accelerometer_rest,
351 offset.context(),
352 device,
353 );
354 }
355
356 if let Some(binding) = texture_meta.get(&TextureSemantics::Original.semantics(0)) {
358 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
359 }
360
361 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Original.semantics(0).into())
363 {
364 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
365 }
366
367 if let Some(binding) = texture_meta.get(&TextureSemantics::Source.semantics(0)) {
369 Self::bind_texture(descriptor_set, sampler_set, binding, source, device);
370 }
371
372 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Source.semantics(0).into()) {
374 uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context(), device);
375 }
376
377 if let Some(binding) = texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
381 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
382 }
383
384 if let Some(offset) =
386 uniform_bindings.get(&TextureSemantics::OriginalHistory.semantics(0).into())
387 {
388 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
389 }
390
391 for (index, history) in original_history.enumerate() {
393 let Some(history) = history else {
394 continue;
395 };
396
397 let history = history.as_ref();
398
399 if let Some(binding) =
400 texture_meta.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
401 {
402 Self::bind_texture(descriptor_set, sampler_set, binding, history, device);
403 }
404
405 if let Some(offset) = uniform_bindings.get(
406 &TextureSemantics::OriginalHistory
407 .semantics(index + 1)
408 .into(),
409 ) {
410 uniform_storage.bind_vec4(
411 offset.offset(),
412 history.size(),
413 offset.context(),
414 device,
415 );
416 }
417 }
418
419 for (index, output) in pass_outputs.enumerate() {
423 let Some(output) = output else {
424 continue;
425 };
426
427 let output = output.as_ref();
428
429 if let Some(binding) = texture_meta.get(&TextureSemantics::PassOutput.semantics(index))
430 {
431 Self::bind_texture(descriptor_set, sampler_set, binding, output, device);
432 }
433
434 if let Some(offset) =
435 uniform_bindings.get(&TextureSemantics::PassOutput.semantics(index).into())
436 {
437 uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context(), device);
438 }
439 }
440
441 for (index, feedback) in pass_feedback.enumerate() {
443 let Some(output) = feedback else {
444 continue;
445 };
446
447 let feedback = output.as_ref();
448
449 if let Some(binding) =
450 texture_meta.get(&TextureSemantics::PassFeedback.semantics(index))
451 {
452 Self::bind_texture(descriptor_set, sampler_set, binding, feedback, device);
453 }
454
455 if let Some(offset) =
456 uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
457 {
458 uniform_storage.bind_vec4(
459 offset.offset(),
460 feedback.size(),
461 offset.context(),
462 device,
463 );
464 }
465 }
466
467 for (id, offset) in uniform_bindings
469 .iter()
470 .filter_map(|(binding, value)| match binding {
471 UniformBinding::Parameter(id) => Some((id, value)),
472 _ => None,
473 })
474 {
475 let default = parameter_defaults.get(id).map_or(0f32, |f| f.initial);
476
477 let value = *runtime_parameters.get(id).unwrap_or(&default);
478
479 uniform_storage.bind_scalar(offset.offset(), value, offset.context(), device);
480 }
481
482 for (index, lut) in lookup_textures {
484 let lut = lut.as_ref();
485 if let Some(binding) = texture_meta.get(&TextureSemantics::User.semantics(index)) {
486 Self::bind_texture(descriptor_set, sampler_set, binding, lut, device);
487 }
488
489 if let Some(offset) =
490 uniform_bindings.get(&TextureSemantics::User.semantics(index).into())
491 {
492 uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context(), device);
493 }
494 }
495 }
496}
497
498#[derive(Debug)]
499pub struct BindingRequirements {
500 pub(crate) required_history: usize,
502 pub(crate) uses_final_pass_as_feedback: bool,
504 pub(crate) feedback_mask: BitSet,
506 pub(crate) last_use: Box<[usize]>,
508}
509
510pub trait BindingUtil {
512 fn create_binding_map<T>(
514 &self,
515 f: impl Fn(&dyn UniformMeta) -> T,
516 ) -> FastHashMap<UniformBinding, T>;
517
518 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
520 where
521 Self: 'a;
522}
523
524impl BindingUtil for BindingMeta {
525 fn create_binding_map<T>(
526 &self,
527 f: impl Fn(&dyn UniformMeta) -> T,
528 ) -> FastHashMap<UniformBinding, T> {
529 let mut uniform_bindings = FastHashMap::default();
530 for param in self.parameter_meta.values() {
531 uniform_bindings.insert(UniformBinding::Parameter(param.id.clone()), f(param));
532 }
533
534 for (semantics, param) in &self.unique_meta {
535 uniform_bindings.insert(UniformBinding::SemanticVariable(*semantics), f(param));
536 }
537
538 for (semantics, param) in &self.texture_size_meta {
539 uniform_bindings.insert(UniformBinding::TextureSize(*semantics), f(param));
540 }
541
542 uniform_bindings
543 }
544
545 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
546 where
547 Self: 'a,
548 {
549 let passes: Vec<&BindingMeta> = pass_meta.collect();
550 let len = passes.len();
551
552 let mut required_images = 0;
553 let mut latest_feedback_pass: i64 = -1;
554 let mut feedback_mask = BitSet::new();
555
556 let mut last_use = vec![0usize; len];
559 for index in 0..len {
560 last_use[index] = if index + 1 < len { index + 1 } else { index };
561 }
562
563 for (pass_index, pass) in passes.iter().enumerate() {
564 let history_texture_max_index = pass
566 .texture_meta
567 .keys()
568 .filter(|semantics| semantics.semantics == TextureSemantics::OriginalHistory)
569 .map(|semantic| semantic.index)
570 .fold(0, std::cmp::max);
571 let history_texture_size_max_index = pass
572 .texture_size_meta
573 .keys()
574 .filter(|semantics| semantics.semantics == TextureSemantics::OriginalHistory)
575 .map(|semantic| semantic.index)
576 .fold(0, std::cmp::max);
577
578 for semantic in pass
581 .texture_meta
582 .keys()
583 .chain(pass.texture_size_meta.keys())
584 .filter(|semantics| semantics.semantics == TextureSemantics::PassFeedback)
585 {
586 feedback_mask.insert(semantic.index);
587 latest_feedback_pass = std::cmp::max(latest_feedback_pass, semantic.index as i64);
588 }
589
590 for semantic in pass
592 .texture_meta
593 .keys()
594 .chain(pass.texture_size_meta.keys())
595 .filter(|semantics| semantics.semantics == TextureSemantics::PassOutput)
596 {
597 if semantic.index < len {
598 last_use[semantic.index] = std::cmp::max(last_use[semantic.index], pass_index);
599 }
600 }
601
602 required_images = std::cmp::max(required_images, history_texture_max_index);
603 required_images = std::cmp::max(required_images, history_texture_size_max_index);
604 }
605
606 for index in feedback_mask.iter() {
609 if index < len {
610 last_use[index] = len.saturating_sub(1);
611 }
612 }
613
614 let uses_feedback = if latest_feedback_pass.is_negative() {
615 false
616 } else {
617 latest_feedback_pass + 1 >= len as i64
621 };
622
623 BindingRequirements {
624 required_history: required_images,
625 uses_final_pass_as_feedback: uses_feedback,
626 feedback_mask,
627 last_use: last_use.into_boxed_slice(),
628 }
629 }
630}
631
632#[macro_export]
633macro_rules! impl_default_frame_options {
634 ($ty:ident) => {
635 #[repr(C)]
637 #[derive(Debug, Clone)]
638 pub struct $ty {
639 pub clear_history: bool,
641 pub frame_direction: i32,
644 pub rotation: u32,
646 pub total_subframes: u32,
648 pub current_subframe: u32,
650 pub aspect_ratio: f32,
657 pub frames_per_second: f32,
659 pub frametime_delta: u32,
661 pub color_space: $crate::__ColorSpace,
665 pub brightness_nits: f32,
668 pub expand_gamut: u32,
670 pub gyroscope: [f32; 3],
672 pub accelerometer: [f32; 3],
674 pub accelerometer_rest: [f32; 3],
676 }
677
678 impl Default for $ty {
679 fn default() -> Self {
680 Self {
681 clear_history: false,
682 frame_direction: 1,
683 rotation: 0,
684 total_subframes: 1,
685 current_subframe: 1,
686 aspect_ratio: 0.0,
687 frametime_delta: 0,
688 frames_per_second: 1.0,
689 color_space: $crate::__ColorSpace::Sdr,
690 brightness_nits: 200.0,
691 expand_gamut: 0,
692 gyroscope: [0.0, 0.0, 0.0],
693 accelerometer: [0.0, 0.0, 0.0],
694 accelerometer_rest: [0.0, 0.0, 0.0],
695 }
696 }
697 }
698 };
699}