2023-01-15 19:06:09 +11:00
|
|
|
use crate::uniforms::{BindUniform, NoUniformBinder, UniformStorage};
|
2023-01-15 19:01:23 +11:00
|
|
|
use librashader_common::Size;
|
|
|
|
use librashader_preprocess::ShaderParameter;
|
2023-01-15 19:06:09 +11:00
|
|
|
use librashader_reflect::reflect::semantics::{
|
|
|
|
MemberOffset, Semantic, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics,
|
|
|
|
};
|
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::hash::BuildHasher;
|
2023-01-16 16:16:31 +11:00
|
|
|
use std::ops::{Deref, DerefMut};
|
2023-01-15 19:01:23 +11:00
|
|
|
|
|
|
|
/// Trait for input textures used during uniform binding,
|
|
|
|
pub trait TextureInput {
|
|
|
|
/// Gets the size of this input texture.
|
|
|
|
fn size(&self) -> Size<u32>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A uniform member offset with context that needs to be resolved.
|
|
|
|
pub trait ContextOffset<H, C>
|
2023-01-15 19:06:09 +11:00
|
|
|
where
|
|
|
|
H: BindUniform<C, f32>,
|
|
|
|
H: BindUniform<C, u32>,
|
|
|
|
H: BindUniform<C, i32>,
|
|
|
|
H: for<'a> BindUniform<C, &'a [f32; 4]>,
|
|
|
|
H: for<'a> BindUniform<C, &'a [f32; 16]>,
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
|
|
|
/// Gets the `MemberOffset` part of the offset.
|
|
|
|
fn offset(&self) -> MemberOffset;
|
|
|
|
|
|
|
|
/// Gets the context part of the offset.
|
|
|
|
fn context(&self) -> C;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<H> ContextOffset<H, Option<()>> for MemberOffset
|
2023-01-15 19:06:09 +11:00
|
|
|
where
|
|
|
|
H: BindUniform<Option<()>, f32>,
|
|
|
|
H: BindUniform<Option<()>, u32>,
|
|
|
|
H: BindUniform<Option<()>, i32>,
|
|
|
|
H: for<'a> BindUniform<Option<()>, &'a [f32; 4]>,
|
|
|
|
H: for<'a> BindUniform<Option<()>, &'a [f32; 16]>,
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
|
|
|
fn offset(&self) -> MemberOffset {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn context(&self) -> Option<()> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Trait that abstracts binding of semantics to shader uniforms.
|
2023-01-16 16:16:31 +11:00
|
|
|
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
2023-01-15 19:06:09 +11:00
|
|
|
where
|
2023-01-29 17:57:09 +11:00
|
|
|
C: Copy,
|
2023-01-16 16:16:31 +11:00
|
|
|
S: Deref<Target = [u8]> + DerefMut,
|
2023-01-15 19:06:09 +11:00
|
|
|
H: BindUniform<C, f32>,
|
|
|
|
H: BindUniform<C, u32>,
|
|
|
|
H: BindUniform<C, i32>,
|
|
|
|
H: for<'b> BindUniform<C, &'b [f32; 4]>,
|
|
|
|
H: for<'b> BindUniform<C, &'b [f32; 16]>,
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
|
|
|
/// The type of the input texture used for semantic binding.
|
|
|
|
type InputTexture: TextureInput;
|
|
|
|
|
|
|
|
/// The set of texture samplers available.
|
|
|
|
type SamplerSet;
|
|
|
|
|
|
|
|
/// The descriptor set or object that holds sampler and texture bindings.
|
|
|
|
type DescriptorSet<'a>;
|
|
|
|
|
|
|
|
/// The device context containing the state of the graphics processor.
|
|
|
|
type DeviceContext;
|
|
|
|
|
|
|
|
/// The type of uniform offsets to use.
|
|
|
|
type UniformOffset: ContextOffset<H, C>;
|
|
|
|
|
|
|
|
/// Bind a texture to the input descriptor set
|
|
|
|
fn bind_texture<'a>(
|
|
|
|
descriptors: &mut Self::DescriptorSet<'a>,
|
|
|
|
samplers: &Self::SamplerSet,
|
|
|
|
binding: &TextureBinding,
|
|
|
|
texture: &Self::InputTexture,
|
2023-01-15 19:06:09 +11:00
|
|
|
device: &Self::DeviceContext,
|
2023-01-15 19:01:23 +11:00
|
|
|
);
|
|
|
|
|
2023-01-16 03:08:13 +11:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2023-01-15 19:01:23 +11:00
|
|
|
/// Write uniform and texture semantics to the provided storages.
|
|
|
|
fn bind_semantics<'a>(
|
|
|
|
device: &Self::DeviceContext,
|
|
|
|
sampler_set: &Self::SamplerSet,
|
2023-01-16 16:16:31 +11:00
|
|
|
uniform_storage: &mut UniformStorage<H, C, S>,
|
2023-01-15 19:01:23 +11:00
|
|
|
descriptor_set: &mut Self::DescriptorSet<'a>,
|
|
|
|
mvp: &[f32; 16],
|
|
|
|
frame_count: u32,
|
|
|
|
frame_direction: i32,
|
|
|
|
framebuffer_size: Size<u32>,
|
|
|
|
viewport_size: Size<u32>,
|
|
|
|
original: &Self::InputTexture,
|
|
|
|
source: &Self::InputTexture,
|
|
|
|
uniform_bindings: &HashMap<UniformBinding, Self::UniformOffset, impl BuildHasher>,
|
|
|
|
texture_meta: &HashMap<Semantic<TextureSemantics>, TextureBinding, impl BuildHasher>,
|
|
|
|
pass_outputs: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
|
|
|
|
pass_feedback: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
|
|
|
|
original_history: impl Iterator<Item = Option<impl AsRef<Self::InputTexture>>>,
|
|
|
|
lookup_textures: impl Iterator<Item = (usize, impl AsRef<Self::InputTexture>)>,
|
2023-01-16 06:06:38 +11:00
|
|
|
parameter_defaults: &HashMap<String, ShaderParameter, impl BuildHasher>,
|
2023-01-15 19:01:23 +11:00
|
|
|
runtime_parameters: &HashMap<String, f32, impl BuildHasher>,
|
2023-01-15 19:06:09 +11:00
|
|
|
) {
|
2023-01-15 19:01:23 +11:00
|
|
|
// Bind MVP
|
|
|
|
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
|
|
|
|
uniform_storage.bind_mat4(offset.offset(), mvp, offset.context());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bind OutputSize
|
|
|
|
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Output.into()) {
|
|
|
|
uniform_storage.bind_vec4(offset.offset(), framebuffer_size, offset.context());
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind FinalViewportSize
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FinalViewport.into()) {
|
2023-01-15 19:01:23 +11:00
|
|
|
uniform_storage.bind_vec4(offset.offset(), viewport_size, offset.context());
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind FrameCount
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameCount.into()) {
|
2023-01-15 19:01:23 +11:00
|
|
|
uniform_storage.bind_scalar(offset.offset(), frame_count, offset.context());
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind FrameDirection
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::FrameDirection.into()) {
|
|
|
|
uniform_storage.bind_scalar(offset.offset(), frame_direction, offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind Original sampler
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) = texture_meta.get(&TextureSemantics::Original.semantics(0)) {
|
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind OriginalSize
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) = uniform_bindings.get(&TextureSemantics::Original.semantics(0).into())
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind Source sampler
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) = texture_meta.get(&TextureSemantics::Source.semantics(0)) {
|
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, source, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind SourcelSize
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) = uniform_bindings.get(&TextureSemantics::Source.semantics(0).into()) {
|
|
|
|
uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// OriginalHistory0 aliases OriginalHistory
|
|
|
|
|
|
|
|
// bind OriginalHistory0 sampler
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) = texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
|
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, original, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind OriginalHistory0Size
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) =
|
|
|
|
uniform_bindings.get(&TextureSemantics::OriginalHistory.semantics(0).into())
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
// bind OriginalHistory1-..
|
|
|
|
for (index, history) in original_history.enumerate() {
|
|
|
|
let Some(history) = history else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let history = history.as_ref();
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) =
|
|
|
|
texture_meta.get(&TextureSemantics::OriginalHistory.semantics(index + 1))
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, history, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(offset) = uniform_bindings.get(
|
|
|
|
&TextureSemantics::OriginalHistory
|
|
|
|
.semantics(index + 1)
|
|
|
|
.into(),
|
|
|
|
) {
|
2023-01-15 19:06:09 +11:00
|
|
|
uniform_storage.bind_vec4(offset.offset(), history.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind PassOutput0..
|
|
|
|
// The caller should be responsible for limiting this up to
|
|
|
|
// pass_index
|
|
|
|
for (index, output) in pass_outputs.enumerate() {
|
|
|
|
let Some(output) = output else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let output = output.as_ref();
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) = texture_meta.get(&TextureSemantics::PassOutput.semantics(index))
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, output, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) =
|
|
|
|
uniform_bindings.get(&TextureSemantics::PassOutput.semantics(index).into())
|
|
|
|
{
|
|
|
|
uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind PassFeedback0..
|
|
|
|
for (index, feedback) in pass_feedback.enumerate() {
|
|
|
|
let Some(output) = feedback else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let feedback = output.as_ref();
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) =
|
|
|
|
texture_meta.get(&TextureSemantics::PassFeedback.semantics(index))
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, feedback, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) =
|
|
|
|
uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
|
|
|
|
{
|
|
|
|
uniform_storage.bind_vec4(offset.offset(), feedback.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind User parameters
|
2023-01-15 19:06:09 +11:00
|
|
|
for (id, offset) in uniform_bindings
|
2023-01-15 19:01:23 +11:00
|
|
|
.iter()
|
|
|
|
.filter_map(|(binding, value)| match binding {
|
|
|
|
UniformBinding::Parameter(id) => Some((id, value)),
|
|
|
|
_ => None,
|
|
|
|
})
|
|
|
|
{
|
|
|
|
let id = id.as_str();
|
|
|
|
|
2023-01-16 10:21:01 +11:00
|
|
|
let default = parameter_defaults
|
|
|
|
.get(id)
|
2023-01-15 19:01:23 +11:00
|
|
|
.map(|f| f.initial)
|
|
|
|
.unwrap_or(0f32);
|
|
|
|
|
2023-01-16 10:21:01 +11:00
|
|
|
let value = *runtime_parameters.get(id).unwrap_or(&default);
|
2023-01-15 19:01:23 +11:00
|
|
|
|
|
|
|
uniform_storage.bind_scalar(offset.offset(), value, offset.context());
|
|
|
|
}
|
|
|
|
|
|
|
|
// bind luts
|
|
|
|
for (index, lut) in lookup_textures {
|
|
|
|
let lut = lut.as_ref();
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(binding) = texture_meta.get(&TextureSemantics::User.semantics(index)) {
|
|
|
|
Self::bind_texture(descriptor_set, sampler_set, binding, lut, device);
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
|
2023-01-15 19:06:09 +11:00
|
|
|
if let Some(offset) =
|
|
|
|
uniform_bindings.get(&TextureSemantics::User.semantics(index).into())
|
2023-01-15 19:01:23 +11:00
|
|
|
{
|
2023-01-15 19:06:09 +11:00
|
|
|
uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context());
|
2023-01-15 19:01:23 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-01-15 19:06:09 +11:00
|
|
|
}
|