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; 3], D>,
26 H: for<'a> BindUniform<C, &'a [f32; 4], D>,
27 H: for<'a> BindUniform<C, &'a [f32; 16], D>,
28{
29 fn offset(&self) -> MemberOffset;
31
32 fn context(&self) -> C;
34}
35
36impl<D, H> ContextOffset<H, Option<()>, D> for MemberOffset
37where
38 H: BindUniform<Option<()>, f32, D>,
39 H: BindUniform<Option<()>, u32, D>,
40 H: BindUniform<Option<()>, i32, D>,
41 H: for<'a> BindUniform<Option<()>, &'a [f32; 3], D>,
42 H: for<'a> BindUniform<Option<()>, &'a [f32; 4], D>,
43 H: for<'a> BindUniform<Option<()>, &'a [f32; 16], D>,
44{
45 fn offset(&self) -> MemberOffset {
46 *self
47 }
48
49 fn context(&self) -> Option<()> {
50 None
51 }
52}
53
54pub struct UniformInputs<'a> {
56 pub mvp: &'a [f32; 16],
58 pub frame_count: u32,
60 pub rotation: u32,
62 pub total_subframes: u32,
64 pub current_subframe: u32,
66 pub frame_direction: i32,
68 pub aspect_ratio: f32,
70 pub frames_per_second: f32,
72 pub frametime_delta: u32,
74 pub framebuffer_size: Size<u32>,
76 pub viewport_size: Size<u32>,
78 pub hdr_inputs: HdrUniformInputs,
80 pub sensor_inputs: SensorUniformInputs,
82}
83
84pub struct SensorUniformInputs {
86 pub gyroscope: [f32; 3],
88 pub accelerometer: [f32; 3],
90 pub accelerometer_rest: [f32; 3],
92}
93
94pub struct HdrUniformInputs {
95 pub color_space: librashader_common::ColorSpace,
97 pub brightness_nits: f32,
99 pub expand_gamut: u32,
101}
102
103pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
105where
106 C: Copy,
107 U: Deref<Target = [u8]> + DerefMut,
108 P: Deref<Target = [u8]> + DerefMut,
109 H: BindUniform<C, f32, Self::DeviceContext>,
110 H: BindUniform<C, u32, Self::DeviceContext>,
111 H: BindUniform<C, i32, Self::DeviceContext>,
112 H: for<'b> BindUniform<C, &'b [f32; 3], Self::DeviceContext>,
113 H: for<'b> BindUniform<C, &'b [f32; 4], Self::DeviceContext>,
114 H: for<'b> BindUniform<C, &'b [f32; 16], Self::DeviceContext>,
115{
116 type InputTexture: TextureInput;
118
119 type SamplerSet;
121
122 type DescriptorSet<'a>;
124
125 type DeviceContext;
127
128 type UniformOffset: ContextOffset<H, C, Self::DeviceContext>;
130
131 fn bind_texture<'a>(
133 descriptors: &mut Self::DescriptorSet<'a>,
134 samplers: &Self::SamplerSet,
135 binding: &TextureBinding,
136 texture: &Self::InputTexture,
137 device: &Self::DeviceContext,
138 );
139
140 #[allow(clippy::too_many_arguments)]
141 fn bind_semantics<'a>(
143 device: &Self::DeviceContext,
144 sampler_set: &Self::SamplerSet,
145 uniform_storage: &mut UniformStorage<H, C, U, P, Self::DeviceContext>,
146 descriptor_set: &mut Self::DescriptorSet<'a>,
147 uniform_inputs: UniformInputs<'_>,
148 original: &Self::InputTexture,
149 source: &Self::InputTexture,
150 uniform_bindings: &FastHashMap<UniformBinding, Self::UniformOffset>,
151 texture_meta: &FastHashMap<Semantic<TextureSemantics>, TextureBinding>,
152 pass_outputs: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
153 pass_feedback: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
154 original_history: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
155 lookup_textures: impl Iterator<Item = (usize, impl AsRef<Self::InputTexture>)>,
156 parameter_defaults: &FastHashMap<ShortString, ShaderParameter>,
157 runtime_parameters: &RuntimeParameters,
158 ) {
159 let runtime_parameters = runtime_parameters.parameters.load();
160 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
162 uniform_storage.bind_mat4(
163 offset.offset(),
164 uniform_inputs.mvp,
165 offset.context(),
166 device,
167 );
168 }
169
170 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Output.into()) {
172 uniform_storage.bind_vec4(
173 offset.offset(),
174 uniform_inputs.framebuffer_size,
175 offset.context(),
176 device,
177 );
178 }
179
180 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FinalViewport.into()) {
182 uniform_storage.bind_vec4(
183 offset.offset(),
184 uniform_inputs.viewport_size,
185 offset.context(),
186 device,
187 );
188 }
189
190 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameCount.into()) {
192 uniform_storage.bind_scalar(
193 offset.offset(),
194 uniform_inputs.frame_count,
195 offset.context(),
196 device,
197 );
198 }
199
200 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameDirection.into()) {
202 uniform_storage.bind_scalar(
203 offset.offset(),
204 uniform_inputs.frame_direction,
205 offset.context(),
206 device,
207 );
208 }
209
210 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
212 uniform_storage.bind_scalar(
213 offset.offset(),
214 uniform_inputs.rotation,
215 offset.context(),
216 device,
217 );
218 }
219
220 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::TotalSubFrames.into()) {
222 uniform_storage.bind_scalar(
223 offset.offset(),
224 uniform_inputs.total_subframes,
225 offset.context(),
226 device,
227 );
228 }
229
230 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::CurrentSubFrame.into()) {
232 uniform_storage.bind_scalar(
233 offset.offset(),
234 uniform_inputs.current_subframe,
235 offset.context(),
236 device,
237 );
238 }
239
240 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalFPS.into()) {
242 uniform_storage.bind_scalar(
243 offset.offset(),
244 uniform_inputs.frames_per_second,
245 offset.context(),
246 device,
247 );
248 }
249
250 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameTimeDelta.into()) {
252 uniform_storage.bind_scalar(
253 offset.offset(),
254 uniform_inputs.frametime_delta,
255 offset.context(),
256 device,
257 );
258 }
259
260 let mut aspect_ratio = uniform_inputs.aspect_ratio;
261 if aspect_ratio.is_zero() {
262 aspect_ratio = original.size().aspect_ratio();
263 }
264
265 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspect.into()) {
267 uniform_storage.bind_scalar(offset.offset(), aspect_ratio, offset.context(), device);
268 }
269
270 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::OriginalAspectRotated.into()) {
271 let rotated_aspect = if uniform_inputs.rotation == 1 || uniform_inputs.rotation == 3 {
272 1.0f32 / aspect_ratio
273 } else {
274 aspect_ratio
275 };
276
277 uniform_storage.bind_scalar(offset.offset(), rotated_aspect, offset.context(), device);
278 }
279
280 let hdr = uniform_inputs.hdr_inputs;
281 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::HDRMode.into()) {
283 uniform_storage.bind_scalar(
284 offset.offset(),
285 hdr.color_space as u32,
286 offset.context(),
287 device,
288 );
289 }
290
291 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::BrightnessNits.into()) {
293 uniform_storage.bind_scalar(
294 offset.offset(),
295 hdr.brightness_nits,
296 offset.context(),
297 device,
298 );
299 }
300
301 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::ExpandGamut.into()) {
303 uniform_storage.bind_scalar(
304 offset.offset(),
305 hdr.expand_gamut,
306 offset.context(),
307 device,
308 );
309 }
310
311 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Scanlines.into()) {
317 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
318 }
319 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::InverseTonemap.into()) {
320 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
321 }
322 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::HDR10.into()) {
323 uniform_storage.bind_scalar(offset.offset(), 0.0f32, offset.context(), device);
324 }
325 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::SubpixelLayout.into()) {
326 uniform_storage.bind_scalar(offset.offset(), 0u32, offset.context(), device);
327 }
328
329 let sensors = uniform_inputs.sensor_inputs;
330 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Gyroscope.into()) {
332 uniform_storage.bind_vec3(offset.offset(), sensors.gyroscope, offset.context(), device);
333 }
334
335 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Accelerometer.into()) {
337 uniform_storage.bind_vec3(
338 offset.offset(),
339 sensors.accelerometer,
340 offset.context(),
341 device,
342 );
343 }
344
345 if let Some(offset) = uniform_bindings.get(&UniqueSemantics::AccelerometerRest.into()) {
347 uniform_storage.bind_vec3(
348 offset.offset(),
349 sensors.accelerometer_rest,
350 offset.context(),
351 device,
352 );
353 }
354
355 if let Some(binding) = texture_meta.get(&TextureSemantics::Original.semantics(0)) {
357 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
358 }
359
360 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Original.semantics(0).into())
362 {
363 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
364 }
365
366 if let Some(binding) = texture_meta.get(&TextureSemantics::Source.semantics(0)) {
368 Self::bind_texture(descriptor_set, sampler_set, binding, source, device);
369 }
370
371 if let Some(offset) = uniform_bindings.get(&TextureSemantics::Source.semantics(0).into()) {
373 uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context(), device);
374 }
375
376 if let Some(binding) = texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
380 Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
381 }
382
383 if let Some(offset) =
385 uniform_bindings.get(&TextureSemantics::OriginalHistory.semantics(0).into())
386 {
387 uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
388 }
389
390 for (index, history) in original_history.enumerate() {
392 let Some(history) = history else {
393 continue;
394 };
395
396 let history = history.as_ref();
397
398 if let Some(binding) =
399 texture_meta.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
400 {
401 Self::bind_texture(descriptor_set, sampler_set, binding, history, device);
402 }
403
404 if let Some(offset) = uniform_bindings.get(
405 &TextureSemantics::OriginalHistory
406 .semantics(index + 1)
407 .into(),
408 ) {
409 uniform_storage.bind_vec4(
410 offset.offset(),
411 history.size(),
412 offset.context(),
413 device,
414 );
415 }
416 }
417
418 for (index, output) in pass_outputs.enumerate() {
422 let Some(output) = output else {
423 continue;
424 };
425
426 let output = output.as_ref();
427
428 if let Some(binding) = texture_meta.get(&TextureSemantics::PassOutput.semantics(index))
429 {
430 Self::bind_texture(descriptor_set, sampler_set, binding, output, device);
431 }
432
433 if let Some(offset) =
434 uniform_bindings.get(&TextureSemantics::PassOutput.semantics(index).into())
435 {
436 uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context(), device);
437 }
438 }
439
440 for (index, feedback) in pass_feedback.enumerate() {
442 let Some(output) = feedback else {
443 continue;
444 };
445
446 let feedback = output.as_ref();
447
448 if let Some(binding) =
449 texture_meta.get(&TextureSemantics::PassFeedback.semantics(index))
450 {
451 Self::bind_texture(descriptor_set, sampler_set, binding, feedback, device);
452 }
453
454 if let Some(offset) =
455 uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
456 {
457 uniform_storage.bind_vec4(
458 offset.offset(),
459 feedback.size(),
460 offset.context(),
461 device,
462 );
463 }
464 }
465
466 for (id, offset) in uniform_bindings
468 .iter()
469 .filter_map(|(binding, value)| match binding {
470 UniformBinding::Parameter(id) => Some((id, value)),
471 _ => None,
472 })
473 {
474 let default = parameter_defaults.get(id).map_or(0f32, |f| f.initial);
475
476 let value = *runtime_parameters.get(id).unwrap_or(&default);
477
478 uniform_storage.bind_scalar(offset.offset(), value, offset.context(), device);
479 }
480
481 for (index, lut) in lookup_textures {
483 let lut = lut.as_ref();
484 if let Some(binding) = texture_meta.get(&TextureSemantics::User.semantics(index)) {
485 Self::bind_texture(descriptor_set, sampler_set, binding, lut, device);
486 }
487
488 if let Some(offset) =
489 uniform_bindings.get(&TextureSemantics::User.semantics(index).into())
490 {
491 uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context(), device);
492 }
493 }
494 }
495}
496
497#[derive(Debug)]
498pub struct BindingRequirements {
499 pub(crate) required_history: usize,
500 pub(crate) uses_final_pass_as_feedback: bool,
501}
502
503pub trait BindingUtil {
505 fn create_binding_map<T>(
507 &self,
508 f: impl Fn(&dyn UniformMeta) -> T,
509 ) -> FastHashMap<UniformBinding, T>;
510
511 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
513 where
514 Self: 'a;
515}
516
517impl BindingUtil for BindingMeta {
518 fn create_binding_map<T>(
519 &self,
520 f: impl Fn(&dyn UniformMeta) -> T,
521 ) -> FastHashMap<UniformBinding, T> {
522 let mut uniform_bindings = FastHashMap::default();
523 for param in self.parameter_meta.values() {
524 uniform_bindings.insert(UniformBinding::Parameter(param.id.clone()), f(param));
525 }
526
527 for (semantics, param) in &self.unique_meta {
528 uniform_bindings.insert(UniformBinding::SemanticVariable(*semantics), f(param));
529 }
530
531 for (semantics, param) in &self.texture_size_meta {
532 uniform_bindings.insert(UniformBinding::TextureSize(*semantics), f(param));
533 }
534
535 uniform_bindings
536 }
537
538 fn calculate_requirements<'a>(pass_meta: impl Iterator<Item = &'a Self>) -> BindingRequirements
539 where
540 Self: 'a,
541 {
542 let mut required_images = 0;
543
544 let mut len: i64 = 0;
545 let mut latest_feedback_pass: i64 = -1;
546
547 for pass in pass_meta {
548 len += 1;
549
550 let history_texture_max_index = pass
552 .texture_meta
553 .iter()
554 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
555 .map(|(semantic, _)| semantic.index)
556 .fold(0, std::cmp::max);
557 let history_texture_size_max_index = pass
558 .texture_size_meta
559 .iter()
560 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory)
561 .map(|(semantic, _)| semantic.index)
562 .fold(0, std::cmp::max);
563
564 let feedback_max_index = pass
565 .texture_meta
566 .iter()
567 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback)
568 .map(|(semantic, _)| semantic.index as i64)
569 .fold(-1, std::cmp::max);
570 let feedback_max_size_index = pass
571 .texture_size_meta
572 .iter()
573 .filter(|(semantics, _)| semantics.semantics == TextureSemantics::PassFeedback)
574 .map(|(semantic, _)| semantic.index as i64)
575 .fold(-1, std::cmp::max);
576
577 latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_index);
578 latest_feedback_pass = std::cmp::max(latest_feedback_pass, feedback_max_size_index);
579
580 required_images = std::cmp::max(required_images, history_texture_max_index);
581 required_images = std::cmp::max(required_images, history_texture_size_max_index);
582 }
583
584 let uses_feedback = if latest_feedback_pass.is_negative() {
585 false
586 } else {
587 latest_feedback_pass + 1 >= len
591 };
592
593 BindingRequirements {
594 required_history: required_images,
595 uses_final_pass_as_feedback: uses_feedback,
596 }
597 }
598}
599
600#[macro_export]
601macro_rules! impl_default_frame_options {
602 ($ty:ident) => {
603 #[repr(C)]
605 #[derive(Debug, Clone)]
606 pub struct $ty {
607 pub clear_history: bool,
609 pub frame_direction: i32,
612 pub rotation: u32,
614 pub total_subframes: u32,
616 pub current_subframe: u32,
618 pub aspect_ratio: f32,
625 pub frames_per_second: f32,
627 pub frametime_delta: u32,
629 pub color_space: $crate::__ColorSpace,
633 pub brightness_nits: f32,
636 pub expand_gamut: u32,
638 pub gyroscope: [f32; 3],
640 pub accelerometer: [f32; 3],
642 pub accelerometer_rest: [f32; 3],
644 }
645
646 impl Default for $ty {
647 fn default() -> Self {
648 Self {
649 clear_history: false,
650 frame_direction: 1,
651 rotation: 0,
652 total_subframes: 1,
653 current_subframe: 1,
654 aspect_ratio: 0.0,
655 frametime_delta: 0,
656 frames_per_second: 1.0,
657 color_space: $crate::__ColorSpace::Sdr,
658 brightness_nits: 200.0,
659 expand_gamut: 0,
660 gyroscope: [0.0, 0.0, 0.0],
661 accelerometer: [0.0, 0.0, 0.0],
662 accelerometer_rest: [0.0, 0.0, 0.0],
663 }
664 }
665 }
666 };
667}