diff --git a/include/librashader.h b/include/librashader.h index 23a58ab..bcffc66 100644 --- a/include/librashader.h +++ b/include/librashader.h @@ -36,10 +36,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #if defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11) #include #else -typedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D11ShaderResourceView; +typedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D1ShaderResourceView; #endif #if defined(LIBRA_RUNTIME_VULKAN) -#include +#include #endif /// Error codes for librashader error types. @@ -102,15 +102,15 @@ typedef struct libra_preset_param_t { } libra_preset_param_t; /// A list of preset parameters. -typedef struct libra_preset_param_list_t { +typedef struct libra_preset_parameter_list_t { /// A pointer to the parameter const struct libra_preset_param_t *parameters; - /// The number of parameters in the list. + /// The number of parameters in the list uint64_t length; /// For internal use only. /// Changing this causes immediate undefined behaviour on freeing this parameter list. uint64_t _internal_alloc; -} libra_preset_param_list_t; +} libra_preset_parameter_list_t; #if defined(LIBRA_RUNTIME_OPENGL) /// A GL function loader that librashader needs to be initialized with. @@ -292,13 +292,9 @@ typedef libra_error_t (*PFN_libra_preset_get_param)(libra_shader_preset_t *prese typedef libra_error_t (*PFN_libra_preset_print)(libra_shader_preset_t *preset); /// Function pointer definition for -///libra_preset_get_runtime_params -typedef libra_error_t (*PFN_libra_preset_get_runtime_params)(libra_shader_preset_t *preset, - struct libra_preset_param_list_t *out); - -/// Function pointer definition for -///libra_preset_free_runtime_params -typedef libra_error_t (*PFN_libra_preset_free_runtime_params)(struct libra_preset_param_list_t preset); +///libra_preset_get_runtime_parameters +typedef libra_error_t (*PFN_libra_preset_get_runtime_parameters)(libra_shader_preset_t *preset, + struct libra_preset_parameter_list_t *out); /// Function pointer definition for libra_error_errno typedef LIBRA_ERRNO (*PFN_libra_error_errno)(libra_error_t error); @@ -580,34 +576,8 @@ libra_error_t libra_preset_print(libra_shader_preset_t *preset); /// ## Safety /// - `preset` must be null or a valid and aligned pointer to a shader preset. /// - `out` must be an aligned pointer to a `libra_preset_parameter_list_t`. -/// - The output struct should be treated as immutable. Mutating any struct fields -/// in the returned struct may at best cause memory leaks, and at worse -/// cause undefined behaviour when later freed. -/// - It is safe to call `libra_preset_get_runtime_params` multiple times, however -/// the output struct must only be freed once per call. -libra_error_t libra_preset_get_runtime_params(libra_shader_preset_t *preset, - struct libra_preset_param_list_t *out); - -/// Free the runtime parameters. -/// -/// Unlike the other `free` functions provided by librashader, -/// `libra_preset_free_runtime_params` takes the struct directly. -/// The caller must take care to maintain the lifetime of any pointers -/// contained within the input `libra_preset_param_list_t`. -/// -/// ## Safety -/// - Any pointers rooted at `parameters` becomes invalid after this function returns, -/// including any strings accessible via the input `libra_preset_param_list_t`. -/// The caller must ensure that there are no live pointers, aliased or unaliased, -/// to data accessible via the input `libra_preset_param_list_t`. -/// -/// - Accessing any data pointed to via the input `libra_preset_param_list_t` after it -/// has been freed is a use-after-free and is immediate undefined behaviour. -/// -/// - If any struct fields of the input `libra_preset_param_list_t` was modified from -/// their values given after `libra_preset_get_runtime_params`, this may result -/// in undefined behaviour. -libra_error_t libra_preset_free_runtime_params(struct libra_preset_param_list_t preset); +libra_error_t libra_preset_get_runtime_parameters(libra_shader_preset_t *preset, + struct libra_preset_parameter_list_t *out); #if defined(LIBRA_RUNTIME_OPENGL) /// Initialize the OpenGL Context for librashader. diff --git a/librashader-capi/src/runtime/gl/filter_chain.rs b/librashader-capi/src/runtime/gl/filter_chain.rs index 117a201..af40633 100644 --- a/librashader-capi/src/runtime/gl/filter_chain.rs +++ b/librashader-capi/src/runtime/gl/filter_chain.rs @@ -56,8 +56,11 @@ impl From for GLImage { extern_fn! { /// Initialize the OpenGL Context for librashader. /// + /// This only has to be done once throughout the lifetime of the application, + /// unless for whatever reason you switch OpenGL loaders mid-flight. + /// /// ## Safety - /// Attempting to create a filter chain will fail. + /// Attempting to create a filter chain will fail if the GL context is not initialized. /// /// Reinitializing the OpenGL context with a different loader immediately invalidates previous filter /// chain objects, and drawing with them causes immediate undefined behaviour. diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index afe50d1..4d02f92 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -15,6 +15,7 @@ use windows::Win32::Graphics::Direct3D11::{ ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD, }; +use librashader_runtime::binding::{BindSemantics, TextureInput}; use crate::{D3D11OutputView, error}; use crate::render_target::RenderTarget; @@ -50,6 +51,30 @@ const NULL_TEXTURES: &[Option; 16] = &[ None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, ]; +impl TextureInput for InputTexture { + fn size(&self) -> Size { + self.view.size + } +} + +impl BindSemantics for FilterPass { + type InputTexture = InputTexture; + type SamplerSet = SamplerSet; + type DescriptorSet<'a> = (&'a mut [Option; 16], &'a mut [Option; 16]); + type DeviceContext = (); + type UniformOffset = MemberOffset; + + fn bind_texture<'a>( + descriptors: &mut Self::DescriptorSet<'a>, samplers: &Self::SamplerSet, + binding: &TextureBinding, texture: &Self::InputTexture, + _device: &Self::DeviceContext) { + let (texture_binding, sampler_binding) = descriptors; + texture_binding[binding.binding as usize] = Some(texture.view.handle.clone()); + sampler_binding[binding.binding as usize] = + Some(samplers.get(texture.wrap_mode, texture.filter).clone()); + } +} + // slang_process.cpp 229 impl FilterPass { pub fn get_format(&self) -> ImageFormat { @@ -76,7 +101,7 @@ impl FilterPass { } // framecount should be pre-modded - fn build_semantics( + fn build_semantics<'a>( &mut self, pass_index: usize, parent: &FilterCommon, @@ -85,264 +110,35 @@ impl FilterPass { frame_direction: i32, fb_size: Size, viewport_size: Size, + mut descriptors: (&'a mut [Option; 16], &'a mut [Option; 16]), original: &InputTexture, source: &InputTexture, - ) -> ( - [Option; 16], - [Option; 16], ) { - let mut textures: [Option; 16] = std::array::from_fn(|_| None); - let mut samplers: [Option; 16] = std::array::from_fn(|_| None); - - // Bind MVP - if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { - self.uniform_storage.bind_mat4(*offset, mvp, None); - } - - // bind OutputSize - if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) { - self.uniform_storage.bind_vec4(*offset, fb_size, None); - } - - // bind FinalViewportSize - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FinalViewport.into()) - { - self.uniform_storage.bind_vec4(*offset, viewport_size, None); - } - - // bind FrameCount - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FrameCount.into()) - { - self.uniform_storage.bind_scalar(*offset, frame_count, None); - } - - // bind FrameDirection - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FrameDirection.into()) - { - self.uniform_storage - .bind_scalar(*offset, frame_direction, None); - } - - // bind Original sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Original.semantics(0)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - original, - ); - } - // - // bind OriginalSize - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::Original.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.view.size, None); - } - - // bind Source sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Source.semantics(0)) - { - // eprintln!("setting source binding to {}", binding.binding); - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - source, - ); - } - - // bind SourceSize - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::Source.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, source.view.size, None); - } - - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(0)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - original, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::OriginalHistory.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.view.size, None); - } - - for (index, output) in parent.history_textures.iter().enumerate() { - let Some(output) = output else { - // eprintln!("no history"); - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - output, - ); - } - - if let Some(offset) = self.uniform_bindings.get( - &TextureSemantics::OriginalHistory - .semantics(index + 1) - .into(), - ) { - self.uniform_storage - .bind_vec4(*offset, output.view.size, None); - } - } - - // PassOutput - for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() { - let Some(output) = output else { - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassOutput.semantics(index)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - output, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::PassOutput.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, output.view.size, None); - } - } - - // PassFeedback - for (index, feedback) in parent.feedback_textures.iter().enumerate() { - let Some(feedback) = feedback else { - // eprintln!("no passfeedback {index}"); - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassFeedback.semantics(index)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - feedback, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::PassFeedback.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, feedback.view.size, None); - } - } - - // bind float parameters - for (id, offset) in - self.uniform_bindings - .iter() - .filter_map(|(binding, value)| match binding { - UniformBinding::Parameter(id) => Some((id, value)), - _ => None, - }) - { - let id = id.as_str(); - - let default = self - .source - .parameters - .iter() - .find(|&p| p.id == id) - .map(|f| f.initial) - .unwrap_or(0f32); - - let value = *parent.config.parameters.get(id).unwrap_or(&default); - - self.uniform_storage.bind_scalar(*offset, value, None); - } - - // bind luts - for (index, lut) in &parent.luts { - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::User.semantics(*index)) - { - FilterPass::bind_texture( - &parent.samplers, - &mut textures, - &mut samplers, - binding, - &lut.image, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::User.semantics(*index).into()) - { - self.uniform_storage - .bind_vec4(*offset, lut.image.view.size, None); - } - } - - (textures, samplers) + Self::bind_semantics( + &(), + &parent.samplers, + &mut self.uniform_storage, + &mut descriptors, + mvp, + frame_count, + frame_direction, + fb_size, + viewport_size, + original, + source, + &self.uniform_bindings, + &self.reflection.meta.texture_meta, + parent.output_textures[0..pass_index].iter() + .map(|o| o.as_ref()), + parent.feedback_textures.iter() + .map(|o| o.as_ref()), + parent.history_textures.iter() + .map(|o| o.as_ref()), + parent.luts.iter() + .map(|(u, i)| (*u, i.as_ref())), + &self.source.parameters, + &parent.config.parameters + ); } pub(crate) fn draw( @@ -370,7 +166,11 @@ impl FilterPass { context.PSSetShader(&self.pixel_shader, None); } - let (textures, samplers) = self.build_semantics( + let mut textures: [Option; 16] = std::array::from_fn(|_| None); + let mut samplers: [Option; 16] = std::array::from_fn(|_| None); + let mut descriptors = (&mut textures, &mut samplers); + + self.build_semantics( pass_index, parent, output.mvp, @@ -378,6 +178,7 @@ impl FilterPass { frame_direction, output.output.size, viewport.output.size, + descriptors, original, source, ); diff --git a/librashader-runtime-d3d11/src/texture.rs b/librashader-runtime-d3d11/src/texture.rs index 9b179c1..3d65acf 100644 --- a/librashader-runtime-d3d11/src/texture.rs +++ b/librashader-runtime-d3d11/src/texture.rs @@ -37,14 +37,14 @@ pub struct D3D11OutputView { } #[derive(Debug, Clone)] -pub(crate) struct InputTexture { +pub struct InputTexture { pub view: D3D11InputView, pub filter: FilterMode, pub wrap_mode: WrapMode, } impl InputTexture { - pub fn from_framebuffer( + pub(crate) fn from_framebuffer( fbo: &OwnedFramebuffer, wrap_mode: WrapMode, filter: FilterMode, @@ -60,6 +60,12 @@ impl InputTexture { } } +impl AsRef for InputTexture { + fn as_ref(&self) -> &InputTexture { + self + } +} + #[derive(Debug, Clone)] pub(crate) struct LutTexture { // The handle to the Texture2D must be kept alive. @@ -70,6 +76,12 @@ pub(crate) struct LutTexture { pub image: InputTexture, } +impl AsRef for LutTexture { + fn as_ref(&self) -> &InputTexture { + &self.image + } +} + impl LutTexture { pub fn new( device: &ID3D11Device, diff --git a/librashader-runtime-gl/src/filter_chain/filter_impl.rs b/librashader-runtime-gl/src/filter_chain/filter_impl.rs index 64f718a..59f8e45 100644 --- a/librashader-runtime-gl/src/filter_chain/filter_impl.rs +++ b/librashader-runtime-gl/src/filter_chain/filter_impl.rs @@ -1,11 +1,11 @@ use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation}; use crate::error::FilterChainError; -use crate::filter_pass::FilterPass; +use crate::filter_pass::{FilterPass, UniformOffset}; use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing}; use crate::options::{FilterChainOptionsGL, FrameOptionsGL}; use crate::render_target::RenderTarget; use crate::samplers::SamplerSet; -use crate::texture::Texture; +use crate::texture::InputTexture; use crate::util::{gl_get_version, gl_u16_to_version}; use crate::{error, util, GLImage}; use gl::types::{GLint, GLuint}; @@ -37,11 +37,11 @@ pub(crate) struct FilterChainImpl { pub(crate) struct FilterCommon { // semantics: ReflectSemantics, pub config: FilterMutable, - pub luts: FxHashMap, + pub luts: FxHashMap, pub samplers: SamplerSet, - pub output_textures: Box<[Texture]>, - pub feedback_textures: Box<[Texture]>, - pub history_textures: Box<[Texture]>, + pub output_textures: Box<[InputTexture]>, + pub feedback_textures: Box<[InputTexture]>, + pub history_textures: Box<[InputTexture]>, pub disable_mipmaps: bool, } @@ -114,13 +114,13 @@ impl FilterChainImpl { let mut output_framebuffers = Vec::new(); output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1)); let mut output_textures = Vec::new(); - output_textures.resize_with(filters.len(), Texture::default); + output_textures.resize_with(filters.len(), InputTexture::default); // initialize feedback framebuffers let mut feedback_framebuffers = Vec::new(); feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1)); let mut feedback_textures = Vec::new(); - feedback_textures.resize_with(filters.len(), Texture::default); + feedback_textures.resize_with(filters.len(), InputTexture::default); // load luts let luts = T::LoadLut::load_luts(&preset.textures)?; @@ -304,21 +304,21 @@ impl FilterChainImpl { for param in reflection.meta.parameter_meta.values() { uniform_bindings.insert( UniformBinding::Parameter(param.id.clone()), - (Self::reflect_uniform_location(program, param), param.offset), + UniformOffset::new(Self::reflect_uniform_location(program, param), param.offset), ); } for (semantics, param) in &reflection.meta.unique_meta { uniform_bindings.insert( UniformBinding::SemanticVariable(*semantics), - (Self::reflect_uniform_location(program, param), param.offset), + UniformOffset::new(Self::reflect_uniform_location(program, param), param.offset), ); } for (semantics, param) in &reflection.meta.texture_size_meta { uniform_bindings.insert( UniformBinding::TextureSize(*semantics), - (Self::reflect_uniform_location(program, param), param.offset), + UniformOffset::new(Self::reflect_uniform_location(program, param), param.offset), ); } @@ -351,7 +351,7 @@ impl FilterChainImpl { filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode, - ) -> (VecDeque, Box<[Texture]>) { + ) -> (VecDeque, Box<[InputTexture]>) { let mut required_images = 0; for pass in filters { @@ -388,7 +388,7 @@ impl FilterChainImpl { framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1)); let mut history_textures = Vec::new(); - history_textures.resize_with(required_images, || Texture { + history_textures.resize_with(required_images, || InputTexture { image: Default::default(), filter, mip_filter: filter, @@ -470,7 +470,7 @@ impl FilterChainImpl { } // shader_gl3: 2067 - let original = Texture { + let original = InputTexture { image: *input, filter, mip_filter: filter, diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 3ac6d18..a2fcba0 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -1,4 +1,4 @@ -use gl::types::{GLsizei, GLuint}; +use gl::types::{GLint, GLsizei, GLuint}; use librashader_reflect::back::cross::CrossGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::ShaderReflection; @@ -6,18 +6,32 @@ use librashader_reflect::reflect::ShaderReflection; use librashader_common::{ImageFormat, Size, Viewport}; use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; -use librashader_reflect::reflect::semantics::{ - MemberOffset, TextureSemantics, UniformBinding, UniqueSemantics, -}; +use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics}; use rustc_hash::FxHashMap; +use librashader_runtime::binding::{BindSemantics, ContextOffset, TextureInput}; -use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation}; +use crate::binding::{GlUniformBinder, GlUniformStorage, UniformLocation, VariableLocation}; use crate::filter_chain::FilterCommon; use crate::Framebuffer; use crate::gl::{BindTexture, GLInterface, UboRing}; use crate::render_target::RenderTarget; +use crate::samplers::SamplerSet; -use crate::texture::Texture; +use crate::texture::InputTexture; + +pub struct UniformOffset { + pub location: VariableLocation, + pub offset: MemberOffset +} + +impl UniformOffset { + pub fn new(location: VariableLocation, offset: MemberOffset) -> Self { + Self { + location, + offset + } + } +} pub struct FilterPass { pub reflection: ShaderReflection, @@ -26,11 +40,42 @@ pub struct FilterPass { pub ubo_location: UniformLocation, pub ubo_ring: Option, pub(crate) uniform_storage: GlUniformStorage, - pub uniform_bindings: FxHashMap, + pub uniform_bindings: FxHashMap, pub source: ShaderSource, pub config: ShaderPassConfig, } +impl TextureInput for InputTexture { + fn size(&self) -> Size { + self.image.size + } +} + +impl ContextOffset> for UniformOffset { + fn offset(&self) -> MemberOffset { + self.offset + } + + fn context(&self) -> UniformLocation { + self.location.location() + } +} + +impl BindSemantics> for FilterPass { + type InputTexture = InputTexture; + type SamplerSet = SamplerSet; + type DescriptorSet<'a> = (); + type DeviceContext = (); + type UniformOffset = UniformOffset; + + fn bind_texture<'a>( + _descriptors: &mut Self::DescriptorSet<'a>, samplers: &Self::SamplerSet, + binding: &TextureBinding, texture: &Self::InputTexture, + _device: &Self::DeviceContext) { + T::BindTexture::bind_texture(&samplers, binding, texture); + } +} + impl FilterPass { pub(crate) fn draw( &mut self, @@ -39,8 +84,8 @@ impl FilterPass { frame_count: u32, frame_direction: i32, viewport: &Viewport<&Framebuffer>, - original: &Texture, - source: &Texture, + original: &InputTexture, + source: &InputTexture, output: RenderTarget, ) { let framebuffer = output.framebuffer; @@ -124,216 +169,33 @@ impl FilterPass { frame_direction: i32, fb_size: Size, viewport: &Viewport<&Framebuffer>, - original: &Texture, - source: &Texture, + original: &InputTexture, + source: &InputTexture, ) { - // Bind MVP - if let Some((location, offset)) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { - self.uniform_storage - .bind_mat4(*offset, mvp, location.location()); - } - - // bind OutputSize - if let Some((location, offset)) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) - { - self.uniform_storage - .bind_vec4(*offset, fb_size, location.location()); - } - - // bind FinalViewportSize - if let Some((location, offset)) = self - .uniform_bindings - .get(&UniqueSemantics::FinalViewport.into()) - { - self.uniform_storage - .bind_vec4(*offset, viewport.output.size, location.location()); - } - - // bind FrameCount - if let Some((location, offset)) = self - .uniform_bindings - .get(&UniqueSemantics::FrameCount.into()) - { - self.uniform_storage - .bind_scalar(*offset, frame_count, location.location()); - } - - // bind FrameDirection - if let Some((location, offset)) = self - .uniform_bindings - .get(&UniqueSemantics::FrameDirection.into()) - { - self.uniform_storage - .bind_scalar(*offset, frame_direction, location.location()); - } - - // bind Original sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Original.semantics(0)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, original); - } - - // bind OriginalSize - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::Original.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.image.size, location.location()); - } - - // bind Source sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Source.semantics(0)) - { - // eprintln!("setting source binding to {}", binding.binding); - T::BindTexture::bind_texture(&parent.samplers, binding, source); - } - - // bind SourceSize - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::Source.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, source.image.size, location.location()); - } - - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(0)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, original); - } - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::OriginalHistory.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.image.size, location.location()); - } - - for (index, output) in parent.history_textures.iter().enumerate() { - if !output.is_bound() { - continue; - } - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, output); - } - - if let Some((location, offset)) = self.uniform_bindings.get( - &TextureSemantics::OriginalHistory - .semantics(index + 1) - .into(), - ) { - self.uniform_storage - .bind_vec4(*offset, output.image.size, location.location()); - } - } - - // PassOutput - for (index, output) in parent.output_textures[0..pass_index].iter().enumerate() { - if !output.is_bound() { - continue; - } - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassOutput.semantics(index)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, output); - } - - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::PassOutput.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, output.image.size, location.location()); - } - } - - // PassFeedback - for (index, feedback) in parent.feedback_textures.iter().enumerate() { - if !feedback.is_bound() { - continue; - } - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassFeedback.semantics(index)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, feedback); - } - - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::PassFeedback.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, feedback.image.size, location.location()); - } - } - - // bind float parameters - for (id, (location, offset)) in - self.uniform_bindings - .iter() - .filter_map(|(binding, value)| match binding { - UniformBinding::Parameter(id) => Some((id, value)), - _ => None, - }) - { - let id = id.as_str(); - // presets override params - let default = self - .source - .parameters - .iter() - .find(|&p| p.id == id) - .map(|f| f.initial) - .unwrap_or(0f32); - - let value = *parent.config.parameters.get(id).unwrap_or(&default); - - self.uniform_storage - .bind_scalar(*offset, value, location.location()); - } - - // bind luts - for (index, lut) in &parent.luts { - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::User.semantics(*index)) - { - T::BindTexture::bind_texture(&parent.samplers, binding, lut); - } - - if let Some((location, offset)) = self - .uniform_bindings - .get(&TextureSemantics::User.semantics(*index).into()) - { - self.uniform_storage - .bind_vec4(*offset, lut.image.size, location.location()); - } - } + Self::bind_semantics( + &(), + &parent.samplers, + &mut self.uniform_storage, + &mut (), + mvp, + frame_count, + frame_direction, + fb_size, + viewport.output.size, + original, + source, + &self.uniform_bindings, + &self.reflection.meta.texture_meta, + parent.output_textures[0..pass_index].iter() + .map(|o| o.bound()), + parent.feedback_textures.iter() + .map(|o| o.bound()), + parent.history_textures.iter() + .map(|o| o.bound()), + parent.luts.iter() + .map(|(u, i)| (*u, i)), + &self.source.parameters, + &parent.config.parameters + ); } } diff --git a/librashader-runtime-gl/src/gl/framebuffer.rs b/librashader-runtime-gl/src/gl/framebuffer.rs index 881600e..2f93981 100644 --- a/librashader-runtime-gl/src/gl/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/framebuffer.rs @@ -1,7 +1,7 @@ use crate::error::Result; use crate::framebuffer::GLImage; use crate::gl::FramebufferInterface; -use crate::texture::Texture; +use crate::texture::InputTexture; use gl::types::{GLenum, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode}; use librashader_presets::Scale2D; @@ -52,8 +52,8 @@ impl Framebuffer { scaling: Scale2D, format: ImageFormat, viewport: &Viewport<&Framebuffer>, - original: &Texture, - source: &Texture, + original: &InputTexture, + source: &InputTexture, mipmap: bool, ) -> Result> { T::scale(self, scaling, format, viewport, original, source, mipmap) @@ -63,8 +63,8 @@ impl Framebuffer { T::copy_from(self, image) } - pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture { - Texture { + pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture { + InputTexture { image: GLImage { handle: self.image, format: self.format, diff --git a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs index da29f3d..d45e27e 100644 --- a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs @@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::framebuffer::Framebuffer; use crate::gl::FramebufferInterface; -use crate::texture::Texture; +use crate::texture::InputTexture; use gl::types::{GLenum, GLint, GLsizei}; use librashader_common::{ImageFormat, Size, Viewport}; use librashader_presets::Scale2D; @@ -39,8 +39,8 @@ impl FramebufferInterface for Gl3Framebuffer { scaling: Scale2D, format: ImageFormat, viewport: &Viewport<&Framebuffer>, - _original: &Texture, - source: &Texture, + _original: &InputTexture, + source: &InputTexture, mipmap: bool, ) -> Result> { if fb.is_raw { diff --git a/librashader-runtime-gl/src/gl/gl3/lut_load.rs b/librashader-runtime-gl/src/gl/gl3/lut_load.rs index c3a4523..55f17f0 100644 --- a/librashader-runtime-gl/src/gl/gl3/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl3/lut_load.rs @@ -1,7 +1,7 @@ use crate::error::Result; use crate::framebuffer::GLImage; use crate::gl::LoadLut; -use crate::texture::Texture; +use crate::texture::InputTexture; use gl::types::{GLsizei, GLuint}; use librashader_common::Size; use librashader_presets::TextureConfig; @@ -11,7 +11,7 @@ use rustc_hash::FxHashMap; pub struct Gl3LutLoad; impl LoadLut for Gl3LutLoad { - fn load_luts(textures: &[TextureConfig]) -> Result> { + fn load_luts(textures: &[TextureConfig]) -> Result> { let mut luts = FxHashMap::default(); let pixel_unpack = unsafe { let mut binding = 0; @@ -64,7 +64,7 @@ impl LoadLut for Gl3LutLoad { luts.insert( index, - Texture { + InputTexture { image: GLImage { handle, format: gl::RGBA8, diff --git a/librashader-runtime-gl/src/gl/gl3/texture_bind.rs b/librashader-runtime-gl/src/gl/gl3/texture_bind.rs index f3ede3b..73e8cdd 100644 --- a/librashader-runtime-gl/src/gl/gl3/texture_bind.rs +++ b/librashader-runtime-gl/src/gl/gl3/texture_bind.rs @@ -1,12 +1,12 @@ use crate::gl::BindTexture; use crate::samplers::SamplerSet; -use crate::texture::Texture; +use crate::texture::InputTexture; use librashader_reflect::reflect::semantics::TextureBinding; pub struct Gl3BindTexture; impl BindTexture for Gl3BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { + fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) { unsafe { // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); gl::ActiveTexture(gl::TEXTURE0 + binding.binding); @@ -19,7 +19,7 @@ impl BindTexture for Gl3BindTexture { } } - fn gen_mipmaps(texture: &Texture) { + fn gen_mipmaps(texture: &InputTexture) { unsafe { gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); gl::GenerateMipmap(gl::TEXTURE_2D); diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index d3f1235..ce74633 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result}; use crate::framebuffer::GLImage; use crate::gl::framebuffer::Framebuffer; use crate::gl::FramebufferInterface; -use crate::texture::Texture; +use crate::texture::InputTexture; use gl::types::{GLenum, GLint, GLsizei}; use librashader_common::{ImageFormat, Size, Viewport}; use librashader_presets::Scale2D; @@ -37,8 +37,8 @@ impl FramebufferInterface for Gl46Framebuffer { scaling: Scale2D, format: ImageFormat, viewport: &Viewport<&Framebuffer>, - _original: &Texture, - source: &Texture, + _original: &InputTexture, + source: &InputTexture, mipmap: bool, ) -> Result> { if fb.is_raw { diff --git a/librashader-runtime-gl/src/gl/gl46/lut_load.rs b/librashader-runtime-gl/src/gl/gl46/lut_load.rs index f4c8eba..33876b8 100644 --- a/librashader-runtime-gl/src/gl/gl46/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl46/lut_load.rs @@ -1,7 +1,7 @@ use crate::error::Result; use crate::framebuffer::GLImage; use crate::gl::LoadLut; -use crate::texture::Texture; +use crate::texture::InputTexture; use gl::types::{GLsizei, GLuint}; use librashader_common::Size; use librashader_presets::TextureConfig; @@ -11,7 +11,7 @@ use rustc_hash::FxHashMap; pub struct Gl46LutLoad; impl LoadLut for Gl46LutLoad { - fn load_luts(textures: &[TextureConfig]) -> Result> { + fn load_luts(textures: &[TextureConfig]) -> Result> { let mut luts = FxHashMap::default(); let pixel_unpack = unsafe { let mut binding = 0; @@ -66,7 +66,7 @@ impl LoadLut for Gl46LutLoad { luts.insert( index, - Texture { + InputTexture { image: GLImage { handle, format: gl::RGBA8, diff --git a/librashader-runtime-gl/src/gl/gl46/texture_bind.rs b/librashader-runtime-gl/src/gl/gl46/texture_bind.rs index 50ce9cc..276accb 100644 --- a/librashader-runtime-gl/src/gl/gl46/texture_bind.rs +++ b/librashader-runtime-gl/src/gl/gl46/texture_bind.rs @@ -1,12 +1,12 @@ use crate::gl::BindTexture; use crate::samplers::SamplerSet; -use crate::texture::Texture; +use crate::texture::InputTexture; use librashader_reflect::reflect::semantics::TextureBinding; pub struct Gl46BindTexture; impl BindTexture for Gl46BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { + fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) { unsafe { // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); gl::BindTextureUnit(binding.binding, texture.image.handle); @@ -17,7 +17,7 @@ impl BindTexture for Gl46BindTexture { } } - fn gen_mipmaps(texture: &Texture) { + fn gen_mipmaps(texture: &InputTexture) { unsafe { gl::GenerateTextureMipmap(texture.image.handle) } } } diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index 01fe411..08808cd 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -6,7 +6,7 @@ use crate::binding::UniformLocation; use crate::error::Result; use crate::framebuffer::GLImage; use crate::samplers::SamplerSet; -use crate::texture::Texture; +use crate::texture::InputTexture; pub use framebuffer::Framebuffer; use gl::types::{GLenum, GLuint}; use librashader_common::{ImageFormat, Size, Viewport}; @@ -16,7 +16,7 @@ use librashader_runtime::uniforms::UniformStorageAccess; use rustc_hash::FxHashMap; pub trait LoadLut { - fn load_luts(textures: &[TextureConfig]) -> Result>; + fn load_luts(textures: &[TextureConfig]) -> Result>; } pub trait DrawQuad { @@ -42,8 +42,8 @@ pub trait FramebufferInterface { scaling: Scale2D, format: ImageFormat, viewport: &Viewport<&Framebuffer>, - _original: &Texture, - source: &Texture, + _original: &InputTexture, + source: &InputTexture, mipmap: bool, ) -> Result>; fn clear(fb: &Framebuffer); @@ -52,8 +52,8 @@ pub trait FramebufferInterface { } pub trait BindTexture { - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture); - fn gen_mipmaps(texture: &Texture); + fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture); + fn gen_mipmaps(texture: &InputTexture); } pub trait GLInterface { diff --git a/librashader-runtime-gl/src/texture.rs b/librashader-runtime-gl/src/texture.rs index ce8aca2..39363ef 100644 --- a/librashader-runtime-gl/src/texture.rs +++ b/librashader-runtime-gl/src/texture.rs @@ -1,16 +1,32 @@ +use gl::types::GLuint; use crate::framebuffer::GLImage; use librashader_common::{FilterMode, WrapMode}; #[derive(Default, Debug, Copy, Clone)] -pub struct Texture { +pub struct InputTexture { pub image: GLImage, pub filter: FilterMode, pub mip_filter: FilterMode, pub wrap_mode: WrapMode, } -impl Texture { +impl InputTexture { pub fn is_bound(&self) -> bool { self.image.handle != 0 } + + /// Returns a reference to itself if the texture is bound. + pub fn bound(&self) -> Option<&Self> { + if self.is_bound() { + Some(&self) + } else { + None + } + } } + +impl AsRef for InputTexture { + fn as_ref(&self) -> &InputTexture { + self + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/filter_pass.rs b/librashader-runtime-vk/src/filter_pass.rs index 43192e3..9413b45 100644 --- a/librashader-runtime-vk/src/filter_pass.rs +++ b/librashader-runtime-vk/src/filter_pass.rs @@ -14,8 +14,9 @@ use librashader_reflect::reflect::semantics::{ BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics, }; use librashader_reflect::reflect::ShaderReflection; -use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess}; +use librashader_runtime::uniforms::{BindUniform, NoUniformBinder, UniformStorage, UniformStorageAccess}; use rustc_hash::FxHashMap; +use librashader_runtime::binding::{BindSemantics, TextureInput}; pub struct FilterPass { pub device: Arc, @@ -30,6 +31,42 @@ pub struct FilterPass { pub frames_in_flight: u32, } +impl TextureInput for InputImage { + fn size(&self) -> Size { + self.image.size + } +} + +impl BindSemantics for FilterPass { + type InputTexture = InputImage; + type SamplerSet = SamplerSet; + type DescriptorSet<'a> = vk::DescriptorSet; + type DeviceContext = Arc; + type UniformOffset = MemberOffset; + + fn bind_texture<'a>( + descriptors: &mut Self::DescriptorSet<'a>, samplers: &Self::SamplerSet, + binding: &TextureBinding, texture: &Self::InputTexture, device: &Self::DeviceContext) { + let sampler = samplers.get(texture.wrap_mode, texture.filter_mode, texture.mip_filter); + let image_info = [vk::DescriptorImageInfo::builder() + .sampler(sampler.handle) + .image_view(texture.image_view) + .image_layout(vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .build()]; + + let write_desc = [vk::WriteDescriptorSet::builder() + .dst_set(*descriptors) + .dst_binding(binding.binding) + .dst_array_element(0) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(&image_info) + .build()]; + unsafe { + device.update_descriptor_sets(&write_desc, &[]); + } + } +} + impl FilterPass { #[inline(always)] fn bind_texture( @@ -81,7 +118,7 @@ impl FilterPass { source: &InputImage, output: &RenderTarget, ) -> error::Result<()> { - let descriptor = *&self.graphics_pipeline.layout.descriptor_sets + let mut descriptor = *&self.graphics_pipeline.layout.descriptor_sets [(frame_count % self.frames_in_flight) as usize]; self.build_semantics( @@ -92,7 +129,7 @@ impl FilterPass { frame_direction, output.output.size, viewport.output.size, - &descriptor, + &mut descriptor, original, source, ); @@ -182,262 +219,41 @@ impl FilterPass { fn build_semantics( &mut self, - _pass_index: usize, + pass_index: usize, parent: &FilterCommon, mvp: &[f32; 16], frame_count: u32, frame_direction: i32, fb_size: Size, viewport_size: Size, - descriptor_set: &vk::DescriptorSet, + mut descriptor_set: &mut vk::DescriptorSet, original: &InputImage, source: &InputImage, ) { - if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { - self.uniform_storage.bind_mat4(*offset, mvp, None); - } - - // bind OutputSize - if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) { - self.uniform_storage.bind_vec4(*offset, fb_size, None); - } - - // bind FinalViewportSize - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FinalViewport.into()) - { - self.uniform_storage.bind_vec4(*offset, viewport_size, None); - } - - // bind FrameCount - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FrameCount.into()) - { - self.uniform_storage.bind_scalar(*offset, frame_count, None); - } - - // bind FrameDirection - if let Some(offset) = self - .uniform_bindings - .get(&UniqueSemantics::FrameDirection.into()) - { - self.uniform_storage - .bind_scalar(*offset, frame_direction, None); - } - - // bind Original sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Original.semantics(0)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - original, - ); - } - - // bind OriginalSize - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::Original.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.image.size, None); - } - - // bind Source sampler - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::Source.semantics(0)) - { - // eprintln!("setting source binding to {}", binding.binding); - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - source, - ); - } - - // bind SourceSize - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::Source.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, source.image.size, None); - } - - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(0)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - original, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::OriginalHistory.semantics(0).into()) - { - self.uniform_storage - .bind_vec4(*offset, original.image.size, None); - } - - for (index, output) in parent.history_textures.iter().enumerate() { - let Some(output) = output else { - // eprintln!("no history"); - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - output, - ); - } - - if let Some(offset) = self.uniform_bindings.get( - &TextureSemantics::OriginalHistory - .semantics(index + 1) - .into(), - ) { - self.uniform_storage - .bind_vec4(*offset, output.image.size, None); - } - } - - // PassOutput - for (index, output) in parent.output_inputs.iter().enumerate() { - let Some(output) = output else { - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassOutput.semantics(index)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - output, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::PassOutput.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, output.image.size, None); - } - } - - // PassFeedback - for (index, feedback) in parent.feedback_inputs.iter().enumerate() { - let Some(feedback) = feedback else { - // eprintln!("no passfeedback {index}"); - continue; - }; - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassFeedback.semantics(index)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - feedback, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::PassFeedback.semantics(index).into()) - { - self.uniform_storage - .bind_vec4(*offset, feedback.image.size, None); - } - } - - // bind float parameters - for (id, offset) in - self.uniform_bindings - .iter() - .filter_map(|(binding, value)| match binding { - UniformBinding::Parameter(id) => Some((id, value)), - _ => None, - }) - { - let id = id.as_str(); - - let default = self - .source - .parameters - .iter() - .find(|&p| p.id == id) - .map(|f| f.initial) - .unwrap_or(0f32); - - let value = *parent.config.parameters.get(id).unwrap_or(&default); - - self.uniform_storage.bind_scalar(*offset, value, None); - } - - // bind luts - for (index, lut) in &parent.luts { - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::User.semantics(*index)) - { - FilterPass::bind_texture( - &self.device, - &parent.samplers, - *descriptor_set, - binding, - &lut.image, - ); - } - - if let Some(offset) = self - .uniform_bindings - .get(&TextureSemantics::User.semantics(*index).into()) - { - self.uniform_storage - .bind_vec4(*offset, lut.image.image.size, None); - } - } + Self::bind_semantics( + &self.device, + &parent.samplers, + &mut self.uniform_storage, + &mut descriptor_set, + mvp, + frame_count, + frame_direction, + fb_size, + viewport_size, + original, + source, + &self.uniform_bindings, + &self.reflection.meta.texture_meta, + parent.output_inputs[0..pass_index].iter() + .map(|o| o.as_ref()), + parent.feedback_inputs.iter() + .map(|o| o.as_ref()), + parent.history_textures.iter() + .map(|o| o.as_ref()), + parent.luts.iter() + .map(|(u, i)| (*u, i.as_ref())), + &self.source.parameters, + &parent.config.parameters + ); } } diff --git a/librashader-runtime-vk/src/luts.rs b/librashader-runtime-vk/src/luts.rs index 960f3bb..2f5d58d 100644 --- a/librashader-runtime-vk/src/luts.rs +++ b/librashader-runtime-vk/src/luts.rs @@ -249,3 +249,9 @@ impl LutTexture { }) } } + +impl AsRef for LutTexture { + fn as_ref(&self) -> &InputImage { + &self.image + } +} \ No newline at end of file diff --git a/librashader-runtime-vk/src/texture.rs b/librashader-runtime-vk/src/texture.rs index 52f3278..b8d76c2 100644 --- a/librashader-runtime-vk/src/texture.rs +++ b/librashader-runtime-vk/src/texture.rs @@ -518,7 +518,7 @@ pub struct VulkanImage { } #[derive(Clone)] -pub(crate) struct InputImage { +pub struct InputImage { /// A handle to the `VkImage`. pub image: VulkanImage, /// A handle to the `VkImageView` for the image. @@ -527,3 +527,9 @@ pub(crate) struct InputImage { pub filter_mode: FilterMode, pub mip_filter: FilterMode, } + +impl AsRef for InputImage { + fn as_ref(&self) -> &InputImage { + &self + } +} \ No newline at end of file diff --git a/librashader-runtime/src/binding.rs b/librashader-runtime/src/binding.rs new file mode 100644 index 0000000..5d23003 --- /dev/null +++ b/librashader-runtime/src/binding.rs @@ -0,0 +1,338 @@ +use std::collections::HashMap; +use std::hash::BuildHasher; +use librashader_common::Size; +use librashader_preprocess::ShaderParameter; +use librashader_reflect::reflect::semantics::{MemberOffset, Semantic, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics}; +use crate::uniforms::{BindUniform, NoUniformBinder, UniformStorage}; + +/// Trait for input textures used during uniform binding, +pub trait TextureInput { + /// Gets the size of this input texture. + fn size(&self) -> Size; +} + +/// A uniform member offset with context that needs to be resolved. +pub trait ContextOffset + where + H: BindUniform, + H: BindUniform, + H: BindUniform, + H: for<'a> BindUniform, + H: for<'a> BindUniform, +{ + /// Gets the `MemberOffset` part of the offset. + fn offset(&self) -> MemberOffset; + + /// Gets the context part of the offset. + fn context(&self) -> C; +} + +impl ContextOffset> for MemberOffset + where + H: BindUniform, f32>, + H: BindUniform, u32>, + H: BindUniform, i32>, + H: for<'a> BindUniform, &'a [f32; 4]>, + H: for<'a> BindUniform, &'a [f32; 16]>, +{ + fn offset(&self) -> MemberOffset { + *self + } + + fn context(&self) -> Option<()> { + None + } +} + +/// Trait that abstracts binding of semantics to shader uniforms. +pub trait BindSemantics> + where + H: BindUniform, + H: BindUniform, + H: BindUniform, + H: for<'b> BindUniform, + H: for<'b> BindUniform +{ + /// 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; + + + /// 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, + device: &Self::DeviceContext + ); + + #[clippy::allow(too_many_arguments)] + /// Write uniform and texture semantics to the provided storages. + fn bind_semantics<'a>( + device: &Self::DeviceContext, + sampler_set: &Self::SamplerSet, + uniform_storage: &mut UniformStorage, + descriptor_set: &mut Self::DescriptorSet<'a>, + mvp: &[f32; 16], + frame_count: u32, + frame_direction: i32, + framebuffer_size: Size, + viewport_size: Size, + original: &Self::InputTexture, + source: &Self::InputTexture, + uniform_bindings: &HashMap, + texture_meta: &HashMap, TextureBinding, impl BuildHasher>, + pass_outputs: impl Iterator>>, + pass_feedback: impl Iterator>>, + original_history: impl Iterator>>, + lookup_textures: impl Iterator)>, + parameter_defaults: &[ShaderParameter], + runtime_parameters: &HashMap, + ) + { + // 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 + if let Some(offset) = uniform_bindings + .get(&UniqueSemantics::FinalViewport.into()) + { + uniform_storage.bind_vec4(offset.offset(), viewport_size, offset.context()); + } + + // bind FrameCount + if let Some(offset) = uniform_bindings + .get(&UniqueSemantics::FrameCount.into()) + { + uniform_storage.bind_scalar(offset.offset(), frame_count, offset.context()); + } + + // bind FrameDirection + if let Some(offset) = uniform_bindings + .get(&UniqueSemantics::FrameDirection.into()) + { + uniform_storage + .bind_scalar(offset.offset(), frame_direction, offset.context()); + } + + // bind Original sampler + if let Some(binding) = texture_meta + .get(&TextureSemantics::Original.semantics(0)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + original, + device + ); + } + + // bind OriginalSize + if let Some(offset) = uniform_bindings + .get(&TextureSemantics::Original.semantics(0).into()) + { + uniform_storage + .bind_vec4(offset.offset(), original.size(), offset.context()); + } + + // bind Source sampler + if let Some(binding) = texture_meta + .get(&TextureSemantics::Source.semantics(0)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + source, + device + ); + } + + // bind SourcelSize + if let Some(offset) = uniform_bindings + .get(&TextureSemantics::Source.semantics(0).into()) + { + uniform_storage + .bind_vec4(offset.offset(), source.size(), offset.context()); + } + + // OriginalHistory0 aliases OriginalHistory + + // bind OriginalHistory0 sampler + if let Some(binding) = texture_meta + .get(&TextureSemantics::OriginalHistory.semantics(0)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + original, + device + ); + } + + // bind OriginalHistory0Size + if let Some(offset) = uniform_bindings + .get(&TextureSemantics::OriginalHistory.semantics(0).into()) + { + uniform_storage + .bind_vec4(offset.offset(), original.size(), offset.context()); + } + + // bind OriginalHistory1-.. + for (index, history) in original_history.enumerate() { + let Some(history) = history else { + continue; + }; + + let history = history.as_ref(); + + if let Some(binding) = texture_meta + .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + history, + device + ); + } + + if let Some(offset) = uniform_bindings.get( + &TextureSemantics::OriginalHistory + .semantics(index + 1) + .into(), + ) { + uniform_storage + .bind_vec4(offset.offset(), history.size(), offset.context()); + } + } + + // 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(); + + if let Some(binding) = texture_meta + .get(&TextureSemantics::PassOutput.semantics(index)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + output, + device + ); + } + + if let Some(offset) = uniform_bindings.get( + &TextureSemantics::PassOutput + .semantics(index) + .into(), + ) { + uniform_storage + .bind_vec4(offset.offset(), output.size(), offset.context()); + } + } + + // bind PassFeedback0.. + for (index, feedback) in pass_feedback.enumerate() { + let Some(output) = feedback else { + continue; + }; + + let feedback = output.as_ref(); + + if let Some(binding) = texture_meta + .get(&TextureSemantics::PassFeedback.semantics(index)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + feedback, + device + ); + } + + if let Some(offset) = uniform_bindings.get( + &TextureSemantics::PassFeedback + .semantics(index) + .into(), + ) { + uniform_storage + .bind_vec4(offset.offset(), feedback.size(), offset.context()); + } + } + + // bind User parameters + for (id, offset) in + uniform_bindings + .iter() + .filter_map(|(binding, value)| match binding { + UniformBinding::Parameter(id) => Some((id, value)), + _ => None, + }) + { + let id = id.as_str(); + + let default = parameter_defaults.iter() + .find(|&p| p.id == id) + .map(|f| f.initial) + .unwrap_or(0f32); + + let value = *runtime_parameters.get(id).unwrap_or(&default); + + uniform_storage.bind_scalar(offset.offset(), value, offset.context()); + } + + // bind luts + for (index, lut) in lookup_textures { + let lut = lut.as_ref(); + if let Some(binding) = texture_meta + .get(&TextureSemantics::User.semantics(index)) + { + Self::bind_texture( + descriptor_set, + sampler_set, + binding, + lut, + device + ); + } + + if let Some(offset) = uniform_bindings + .get(&TextureSemantics::User.semantics(index).into()) + { + uniform_storage + .bind_vec4(offset.offset(), lut.size(), offset.context()); + } + } + } +} \ No newline at end of file diff --git a/librashader-runtime/src/lib.rs b/librashader-runtime/src/lib.rs index 418f6ed..2b8d5b6 100644 --- a/librashader-runtime/src/lib.rs +++ b/librashader-runtime/src/lib.rs @@ -18,3 +18,6 @@ pub mod image; /// Ringbuffer helpers pub mod ringbuffer; + +/// Generic implementation of semantics binding. +pub mod binding;