rt: pass device context to uniform binder if needed

This commit is contained in:
chyyran 2024-03-04 02:10:08 -05:00 committed by Ronny Chan
parent af3ea252ba
commit 7593f9f9b5
5 changed files with 71 additions and 59 deletions

View file

@ -59,11 +59,11 @@ impl GlUniformScalar for u32 {
}
pub(crate) struct GlUniformBinder;
impl<T> BindUniform<VariableLocation, T> for GlUniformBinder
impl<T> BindUniform<VariableLocation, T, ()> for GlUniformBinder
where
T: GlUniformScalar,
{
fn bind_uniform(block: UniformMemberBlock, value: T, location: VariableLocation) -> Option<()> {
fn bind_uniform(block: UniformMemberBlock, value: T, location: VariableLocation, _: &()) -> Option<()> {
if let Some(location) = location.location(block)
&& location.bindable()
{
@ -84,11 +84,12 @@ where
}
}
impl BindUniform<VariableLocation, &[f32; 4]> for GlUniformBinder {
impl BindUniform<VariableLocation, &[f32; 4], ()> for GlUniformBinder {
fn bind_uniform(
block: UniformMemberBlock,
vec4: &[f32; 4],
location: VariableLocation,
_: &()
) -> Option<()> {
if let Some(location) = location.location(block)
&& location.bindable()
@ -108,11 +109,12 @@ impl BindUniform<VariableLocation, &[f32; 4]> for GlUniformBinder {
}
}
impl BindUniform<VariableLocation, &[f32; 16]> for GlUniformBinder {
impl BindUniform<VariableLocation, &[f32; 16], ()> for GlUniformBinder {
fn bind_uniform(
block: UniformMemberBlock,
mat4: &[f32; 16],
location: VariableLocation,
_: &()
) -> Option<()> {
if let Some(location) = location.location(block)
&& location.bindable()

View file

@ -24,7 +24,7 @@ use std::sync::Arc;
pub struct FilterPass {
pub reflection: ShaderReflection,
pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer>,
pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer, Box<[u8]>, Arc<ash::Device>>,
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
pub source: ShaderSource,
pub config: ShaderPassConfig,

View file

@ -26,7 +26,7 @@ pub struct FilterPass {
pub device: Arc<wgpu::Device>,
pub reflection: ShaderReflection,
pub(crate) uniform_storage:
UniformStorage<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer>,
UniformStorage<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer, Arc<wgpu::Device>>,
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
pub source: ShaderSource,
pub config: ShaderPassConfig,

View file

@ -15,13 +15,13 @@ pub trait TextureInput {
}
/// A uniform member offset with context that needs to be resolved.
pub trait ContextOffset<H, C>
pub trait ContextOffset<H, C, D=()>
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]>,
H: BindUniform<C, f32, D>,
H: BindUniform<C, u32, D>,
H: BindUniform<C, i32, D>,
H: for<'a> BindUniform<C, &'a [f32; 4], D>,
H: for<'a> BindUniform<C, &'a [f32; 16], D>,
{
/// Gets the `MemberOffset` part of the offset.
fn offset(&self) -> MemberOffset;
@ -30,13 +30,13 @@ where
fn context(&self) -> C;
}
impl<H> ContextOffset<H, Option<()>> for MemberOffset
impl<D, H> ContextOffset<H, Option<()>, D> for MemberOffset
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]>,
H: BindUniform<Option<()>, f32, D>,
H: BindUniform<Option<()>, u32, D>,
H: BindUniform<Option<()>, i32, D>,
H: for<'a> BindUniform<Option<()>, &'a [f32; 4], D>,
H: for<'a> BindUniform<Option<()>, &'a [f32; 16], D>,
{
fn offset(&self) -> MemberOffset {
*self
@ -73,11 +73,11 @@ where
C: Copy,
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
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]>,
H: BindUniform<C, f32, Self::DeviceContext>,
H: BindUniform<C, u32, Self::DeviceContext>,
H: BindUniform<C, i32, Self::DeviceContext>,
H: for<'b> BindUniform<C, &'b [f32; 4], Self::DeviceContext>,
H: for<'b> BindUniform<C, &'b [f32; 16], Self::DeviceContext>,
{
/// The type of the input texture used for semantic binding.
type InputTexture: TextureInput;
@ -92,7 +92,7 @@ where
type DeviceContext;
/// The type of uniform offsets to use.
type UniformOffset: ContextOffset<H, C>;
type UniformOffset: ContextOffset<H, C, Self::DeviceContext>;
/// Bind a texture to the input descriptor set
fn bind_texture<'a>(
@ -108,7 +108,7 @@ where
fn bind_semantics<'a>(
device: &Self::DeviceContext,
sampler_set: &Self::SamplerSet,
uniform_storage: &mut UniformStorage<H, C, U, P>,
uniform_storage: &mut UniformStorage<H, C, U, P, Self::DeviceContext>,
descriptor_set: &mut Self::DescriptorSet<'a>,
uniform_inputs: UniformInputs<'_>,
original: &Self::InputTexture,
@ -124,7 +124,7 @@ where
) {
// Bind MVP
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
uniform_storage.bind_mat4(offset.offset(), uniform_inputs.mvp, offset.context());
uniform_storage.bind_mat4(offset.offset(), uniform_inputs.mvp, offset.context(), device);
}
// Bind OutputSize
@ -133,6 +133,7 @@ where
offset.offset(),
uniform_inputs.framebuffer_size,
offset.context(),
device
);
}
@ -142,6 +143,7 @@ where
offset.offset(),
uniform_inputs.viewport_size,
offset.context(),
device
);
}
@ -151,6 +153,7 @@ where
offset.offset(),
uniform_inputs.frame_count,
offset.context(),
device
);
}
@ -160,12 +163,13 @@ where
offset.offset(),
uniform_inputs.frame_direction,
offset.context(),
device
);
}
// bind Rotation
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
uniform_storage.bind_scalar(offset.offset(), uniform_inputs.rotation, offset.context());
uniform_storage.bind_scalar(offset.offset(), uniform_inputs.rotation, offset.context(), device);
}
// bind TotalSubFrames
@ -174,6 +178,7 @@ where
offset.offset(),
uniform_inputs.total_subframes,
offset.context(),
device
);
}
@ -183,6 +188,7 @@ where
offset.offset(),
uniform_inputs.current_subframe,
offset.context(),
device
);
}
@ -194,7 +200,7 @@ where
// bind OriginalSize
if let Some(offset) = uniform_bindings.get(&TextureSemantics::Original.semantics(0).into())
{
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
}
// bind Source sampler
@ -204,7 +210,7 @@ where
// bind SourceSize
if let Some(offset) = uniform_bindings.get(&TextureSemantics::Source.semantics(0).into()) {
uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), source.size(), offset.context(), device);
}
// OriginalHistory0 aliases OriginalHistory
@ -218,7 +224,7 @@ where
if let Some(offset) =
uniform_bindings.get(&TextureSemantics::OriginalHistory.semantics(0).into())
{
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), original.size(), offset.context(), device);
}
// bind OriginalHistory1-..
@ -240,7 +246,7 @@ where
.semantics(index + 1)
.into(),
) {
uniform_storage.bind_vec4(offset.offset(), history.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), history.size(), offset.context(), device);
}
}
@ -262,7 +268,7 @@ where
if let Some(offset) =
uniform_bindings.get(&TextureSemantics::PassOutput.semantics(index).into())
{
uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), output.size(), offset.context(), device);
}
}
@ -283,7 +289,7 @@ where
if let Some(offset) =
uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
{
uniform_storage.bind_vec4(offset.offset(), feedback.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), feedback.size(), offset.context(), device);
}
}
@ -301,7 +307,7 @@ where
let value = *runtime_parameters.get(id).unwrap_or(&default);
uniform_storage.bind_scalar(offset.offset(), value, offset.context());
uniform_storage.bind_scalar(offset.offset(), value, offset.context(), device);
}
// bind luts
@ -314,7 +320,7 @@ where
if let Some(offset) =
uniform_bindings.get(&TextureSemantics::User.semantics(index).into())
{
uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context());
uniform_storage.bind_vec4(offset.offset(), lut.size(), offset.context(), device);
}
}
}

View file

@ -9,13 +9,13 @@ impl UniformScalar for i32 {}
impl UniformScalar for u32 {}
/// A trait for a binder that binds the given value and context into the uniform for a shader pass.
pub trait BindUniform<C, T> {
pub trait BindUniform<C, T, D> {
/// Bind the given value to the shader uniforms given the input context.
///
/// A `BindUniform` implementation should not write to a backing buffer from a [`UniformStorage`](crate::uniforms::UniformStorage).
/// If the binding is successful and no writes to a backing buffer is necessary, this function should return `Some(())`.
/// If this function returns `None`, then the value will instead be written to the backing buffer.
fn bind_uniform(block: UniformMemberBlock, value: T, ctx: C) -> Option<()>;
fn bind_uniform(block: UniformMemberBlock, value: T, ctx: C, device: &D) -> Option<()>;
}
/// A trait to access the raw pointer to a backing uniform storage.
@ -37,7 +37,7 @@ pub trait UniformStorageAccess {
fn push_slice(&self) -> &[u8];
}
impl<T, H, U, P> UniformStorageAccess for UniformStorage<T, H, U, P>
impl<D, T, H, U, P> UniformStorageAccess for UniformStorage<T, H, U, P, D>
where
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
@ -62,14 +62,14 @@ where
/// A uniform binder that always returns `None`, and does not do any binding of uniforms.
/// All uniform data is thus written into the backing buffer storage.
pub struct NoUniformBinder;
impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
fn bind_uniform(_: UniformMemberBlock, _: T, _: Option<()>) -> Option<()> {
impl<T, D> BindUniform<Option<()>, T, D> for NoUniformBinder {
fn bind_uniform(_: UniformMemberBlock, _: T, _: Option<()>, _: &D) -> Option<()> {
None
}
}
/// A helper to bind uniform variables to UBO or Push Constant Buffers.
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>, D=()>
where
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
@ -78,9 +78,10 @@ where
push: P,
_h: PhantomData<H>,
_c: PhantomData<C>,
_d: PhantomData<D>
}
impl<H, C, U, P> UniformStorage<H, C, U, P>
impl<H, C, U, P, D> UniformStorage<H, C, U, P, D>
where
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
@ -103,7 +104,7 @@ where
}
}
impl<H, C, U, P> UniformStorage<H, C, U, P>
impl<H, C, U, P, D> UniformStorage<H, C, U, P, D>
where
C: Copy,
U: Deref<Target = [u8]> + DerefMut,
@ -117,12 +118,12 @@ where
/// Bind a scalar to the given offset.
#[inline(always)]
pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C)
pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C, device: &D)
where
H: BindUniform<C, T>,
H: BindUniform<C, T, D>,
{
for ty in UniformMemberBlock::TYPES {
if H::bind_uniform(ty, value, ctx).is_some() {
if H::bind_uniform(ty, value, ctx, device).is_some() {
continue;
}
@ -134,17 +135,18 @@ where
}
/// Create a new `UniformStorage` with the given backing storage
pub fn new_with_storage(ubo: U, push: P) -> UniformStorage<H, C, U, P> {
pub fn new_with_storage(ubo: U, push: P) -> UniformStorage<H, C, U, P, D> {
UniformStorage {
ubo,
push,
_h: Default::default(),
_c: Default::default(),
_d: Default::default(),
}
}
}
impl<H, C, U> UniformStorage<H, C, U, Box<[u8]>>
impl<H, C, U, D> UniformStorage<H, C, U, Box<[u8]>, D>
where
C: Copy,
U: Deref<Target = [u8]> + DerefMut,
@ -153,34 +155,36 @@ where
pub fn new_with_ubo_storage(
storage: U,
push_size: usize,
) -> UniformStorage<H, C, U, Box<[u8]>> {
) -> UniformStorage<H, C, U, Box<[u8]>, D> {
UniformStorage {
ubo: storage,
push: vec![0u8; push_size].into_boxed_slice(),
_h: Default::default(),
_c: Default::default(),
_d: Default::default(),
}
}
}
impl<H, C> UniformStorage<H, C, Box<[u8]>, Box<[u8]>> {
impl<H, C, D> UniformStorage<H, C, Box<[u8]>, Box<[u8]>, D> {
/// Create a new `UniformStorage` with the given size for UBO and Push Constant Buffer sizes.
pub fn new(ubo_size: usize, push_size: usize) -> UniformStorage<H, C, Box<[u8]>> {
pub fn new(ubo_size: usize, push_size: usize) -> UniformStorage<H, C, Box<[u8]>, Box<[u8]>, D> {
UniformStorage {
ubo: vec![0u8; ubo_size].into_boxed_slice(),
push: vec![0u8; push_size].into_boxed_slice(),
_h: Default::default(),
_c: Default::default(),
_d: Default::default(),
}
}
}
impl<H, C, U, P> UniformStorage<H, C, U, P>
impl<H, C, U, P, D> UniformStorage<H, C, U, P, D>
where
C: Copy,
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
H: for<'a> BindUniform<C, &'a [f32; 4]>,
H: for<'a> BindUniform<C, &'a [f32; 4], D>,
{
#[inline(always)]
fn write_vec4_inner(buffer: &mut [u8], vec4: &[f32; 4]) {
@ -189,11 +193,11 @@ where
}
/// Bind a `vec4` to the given offset.
#[inline(always)]
pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C) {
pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C, device: &D) {
let vec4 = value.into();
for ty in UniformMemberBlock::TYPES {
if H::bind_uniform(ty, &vec4, ctx).is_some() {
if H::bind_uniform(ty, &vec4, ctx, device).is_some() {
continue;
}
if let Some(offset) = offset.offset(ty) {
@ -207,12 +211,12 @@ where
}
}
impl<H, C, U, P> UniformStorage<H, C, U, P>
impl<H, C, U, P, D> UniformStorage<H, C, U, P, D>
where
C: Copy,
U: Deref<Target = [u8]> + DerefMut,
P: Deref<Target = [u8]> + DerefMut,
H: for<'a> BindUniform<C, &'a [f32; 16]>,
H: for<'a> BindUniform<C, &'a [f32; 16], D>,
{
#[inline(always)]
fn write_mat4_inner(buffer: &mut [u8], mat4: &[f32; 16]) {
@ -222,9 +226,9 @@ where
/// Bind a `mat4` to the given offset.
#[inline(always)]
pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C) {
pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C, device: &D) {
for ty in UniformMemberBlock::TYPES {
if H::bind_uniform(ty, value, ctx).is_some() {
if H::bind_uniform(ty, value, ctx, device).is_some() {
continue;
}
if let Some(offset) = offset.offset(ty) {