rt: unify semantics binding logic

This commit is contained in:
chyyran 2023-01-15 03:01:23 -05:00
parent 474cf37e68
commit c3a532d729
20 changed files with 649 additions and 816 deletions

View file

@ -36,10 +36,10 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#if defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11) #if defined(_WIN32) && defined(LIBRA_RUNTIME_D3D11)
#include <d3d11.h> #include <d3d11.h>
#else #else
typedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D11ShaderResourceView; typedef void ID3D11Device;typedef void ID3D11RenderTargetView;typedef void ID3D1ShaderResourceView;
#endif #endif
#if defined(LIBRA_RUNTIME_VULKAN) #if defined(LIBRA_RUNTIME_VULKAN)
#include <vulkan/vulkan.h> #include <vulkan\vulkan.h>
#endif #endif
/// Error codes for librashader error types. /// Error codes for librashader error types.
@ -102,15 +102,15 @@ typedef struct libra_preset_param_t {
} libra_preset_param_t; } libra_preset_param_t;
/// A list of preset parameters. /// A list of preset parameters.
typedef struct libra_preset_param_list_t { typedef struct libra_preset_parameter_list_t {
/// A pointer to the parameter /// A pointer to the parameter
const struct libra_preset_param_t *parameters; const struct libra_preset_param_t *parameters;
/// The number of parameters in the list. /// The number of parameters in the list
uint64_t length; uint64_t length;
/// For internal use only. /// For internal use only.
/// Changing this causes immediate undefined behaviour on freeing this parameter list. /// Changing this causes immediate undefined behaviour on freeing this parameter list.
uint64_t _internal_alloc; uint64_t _internal_alloc;
} libra_preset_param_list_t; } libra_preset_parameter_list_t;
#if defined(LIBRA_RUNTIME_OPENGL) #if defined(LIBRA_RUNTIME_OPENGL)
/// A GL function loader that librashader needs to be initialized with. /// 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); typedef libra_error_t (*PFN_libra_preset_print)(libra_shader_preset_t *preset);
/// Function pointer definition for /// Function pointer definition for
///libra_preset_get_runtime_params ///libra_preset_get_runtime_parameters
typedef libra_error_t (*PFN_libra_preset_get_runtime_params)(libra_shader_preset_t *preset, typedef libra_error_t (*PFN_libra_preset_get_runtime_parameters)(libra_shader_preset_t *preset,
struct libra_preset_param_list_t *out); struct libra_preset_parameter_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);
/// Function pointer definition for libra_error_errno /// Function pointer definition for libra_error_errno
typedef LIBRA_ERRNO (*PFN_libra_error_errno)(libra_error_t error); 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 /// ## Safety
/// - `preset` must be null or a valid and aligned pointer to a shader preset. /// - `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`. /// - `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 libra_error_t libra_preset_get_runtime_parameters(libra_shader_preset_t *preset,
/// in the returned struct may at best cause memory leaks, and at worse struct libra_preset_parameter_list_t *out);
/// 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);
#if defined(LIBRA_RUNTIME_OPENGL) #if defined(LIBRA_RUNTIME_OPENGL)
/// Initialize the OpenGL Context for librashader. /// Initialize the OpenGL Context for librashader.

View file

@ -56,8 +56,11 @@ impl From<libra_source_image_gl_t> for GLImage {
extern_fn! { extern_fn! {
/// Initialize the OpenGL Context for librashader. /// 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 /// ## 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 /// Reinitializing the OpenGL context with a different loader immediately invalidates previous filter
/// chain objects, and drawing with them causes immediate undefined behaviour. /// chain objects, and drawing with them causes immediate undefined behaviour.

View file

@ -15,6 +15,7 @@ use windows::Win32::Graphics::Direct3D11::{
ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState, ID3D11Buffer, ID3D11InputLayout, ID3D11PixelShader, ID3D11SamplerState,
ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD, ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD,
}; };
use librashader_runtime::binding::{BindSemantics, TextureInput};
use crate::{D3D11OutputView, error}; use crate::{D3D11OutputView, error};
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
@ -50,6 +51,30 @@ const NULL_TEXTURES: &[Option<ID3D11ShaderResourceView>; 16] = &[
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
]; ];
impl TextureInput for InputTexture {
fn size(&self) -> Size<u32> {
self.view.size
}
}
impl BindSemantics for FilterPass {
type InputTexture = InputTexture;
type SamplerSet = SamplerSet;
type DescriptorSet<'a> = (&'a mut [Option<ID3D11ShaderResourceView>; 16], &'a mut [Option<ID3D11SamplerState>; 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 // slang_process.cpp 229
impl FilterPass { impl FilterPass {
pub fn get_format(&self) -> ImageFormat { pub fn get_format(&self) -> ImageFormat {
@ -76,7 +101,7 @@ impl FilterPass {
} }
// framecount should be pre-modded // framecount should be pre-modded
fn build_semantics( fn build_semantics<'a>(
&mut self, &mut self,
pass_index: usize, pass_index: usize,
parent: &FilterCommon, parent: &FilterCommon,
@ -85,264 +110,35 @@ impl FilterPass {
frame_direction: i32, frame_direction: i32,
fb_size: Size<u32>, fb_size: Size<u32>,
viewport_size: Size<u32>, viewport_size: Size<u32>,
mut descriptors: (&'a mut [Option<ID3D11ShaderResourceView>; 16], &'a mut [Option<ID3D11SamplerState>; 16]),
original: &InputTexture, original: &InputTexture,
source: &InputTexture, source: &InputTexture,
) -> (
[Option<ID3D11ShaderResourceView>; 16],
[Option<ID3D11SamplerState>; 16],
) { ) {
let mut textures: [Option<ID3D11ShaderResourceView>; 16] = std::array::from_fn(|_| None); Self::bind_semantics(
let mut samplers: [Option<ID3D11SamplerState>; 16] = std::array::from_fn(|_| None); &(),
&parent.samplers,
// Bind MVP &mut self.uniform_storage,
if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { &mut descriptors,
self.uniform_storage.bind_mat4(*offset, mvp, None); mvp,
} frame_count,
frame_direction,
// bind OutputSize fb_size,
if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) { viewport_size,
self.uniform_storage.bind_vec4(*offset, fb_size, None); original,
} source,
&self.uniform_bindings,
// bind FinalViewportSize &self.reflection.meta.texture_meta,
if let Some(offset) = self parent.output_textures[0..pass_index].iter()
.uniform_bindings .map(|o| o.as_ref()),
.get(&UniqueSemantics::FinalViewport.into()) parent.feedback_textures.iter()
{ .map(|o| o.as_ref()),
self.uniform_storage.bind_vec4(*offset, viewport_size, None); parent.history_textures.iter()
} .map(|o| o.as_ref()),
parent.luts.iter()
// bind FrameCount .map(|(u, i)| (*u, i.as_ref())),
if let Some(offset) = self &self.source.parameters,
.uniform_bindings &parent.config.parameters
.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)
} }
pub(crate) fn draw( pub(crate) fn draw(
@ -370,7 +166,11 @@ impl FilterPass {
context.PSSetShader(&self.pixel_shader, None); context.PSSetShader(&self.pixel_shader, None);
} }
let (textures, samplers) = self.build_semantics( let mut textures: [Option<ID3D11ShaderResourceView>; 16] = std::array::from_fn(|_| None);
let mut samplers: [Option<ID3D11SamplerState>; 16] = std::array::from_fn(|_| None);
let mut descriptors = (&mut textures, &mut samplers);
self.build_semantics(
pass_index, pass_index,
parent, parent,
output.mvp, output.mvp,
@ -378,6 +178,7 @@ impl FilterPass {
frame_direction, frame_direction,
output.output.size, output.output.size,
viewport.output.size, viewport.output.size,
descriptors,
original, original,
source, source,
); );

View file

@ -37,14 +37,14 @@ pub struct D3D11OutputView {
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct InputTexture { pub struct InputTexture {
pub view: D3D11InputView, pub view: D3D11InputView,
pub filter: FilterMode, pub filter: FilterMode,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,
} }
impl InputTexture { impl InputTexture {
pub fn from_framebuffer( pub(crate) fn from_framebuffer(
fbo: &OwnedFramebuffer, fbo: &OwnedFramebuffer,
wrap_mode: WrapMode, wrap_mode: WrapMode,
filter: FilterMode, filter: FilterMode,
@ -60,6 +60,12 @@ impl InputTexture {
} }
} }
impl AsRef<InputTexture> for InputTexture {
fn as_ref(&self) -> &InputTexture {
self
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct LutTexture { pub(crate) struct LutTexture {
// The handle to the Texture2D must be kept alive. // The handle to the Texture2D must be kept alive.
@ -70,6 +76,12 @@ pub(crate) struct LutTexture {
pub image: InputTexture, pub image: InputTexture,
} }
impl AsRef<InputTexture> for LutTexture {
fn as_ref(&self) -> &InputTexture {
&self.image
}
}
impl LutTexture { impl LutTexture {
pub fn new( pub fn new(
device: &ID3D11Device, device: &ID3D11Device,

View file

@ -1,11 +1,11 @@
use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation}; use crate::binding::{GlUniformStorage, UniformLocation, VariableLocation};
use crate::error::FilterChainError; 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::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing};
use crate::options::{FilterChainOptionsGL, FrameOptionsGL}; use crate::options::{FilterChainOptionsGL, FrameOptionsGL};
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::InputTexture;
use crate::util::{gl_get_version, gl_u16_to_version}; use crate::util::{gl_get_version, gl_u16_to_version};
use crate::{error, util, GLImage}; use crate::{error, util, GLImage};
use gl::types::{GLint, GLuint}; use gl::types::{GLint, GLuint};
@ -37,11 +37,11 @@ pub(crate) struct FilterChainImpl<T: GLInterface> {
pub(crate) struct FilterCommon { pub(crate) struct FilterCommon {
// semantics: ReflectSemantics, // semantics: ReflectSemantics,
pub config: FilterMutable, pub config: FilterMutable,
pub luts: FxHashMap<usize, Texture>, pub luts: FxHashMap<usize, InputTexture>,
pub samplers: SamplerSet, pub samplers: SamplerSet,
pub output_textures: Box<[Texture]>, pub output_textures: Box<[InputTexture]>,
pub feedback_textures: Box<[Texture]>, pub feedback_textures: Box<[InputTexture]>,
pub history_textures: Box<[Texture]>, pub history_textures: Box<[InputTexture]>,
pub disable_mipmaps: bool, pub disable_mipmaps: bool,
} }
@ -114,13 +114,13 @@ impl<T: GLInterface> FilterChainImpl<T> {
let mut output_framebuffers = Vec::new(); let mut output_framebuffers = Vec::new();
output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1)); output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut output_textures = Vec::new(); 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 // initialize feedback framebuffers
let mut feedback_framebuffers = Vec::new(); let mut feedback_framebuffers = Vec::new();
feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1)); feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1));
let mut feedback_textures = Vec::new(); let mut feedback_textures = Vec::new();
feedback_textures.resize_with(filters.len(), Texture::default); feedback_textures.resize_with(filters.len(), InputTexture::default);
// load luts // load luts
let luts = T::LoadLut::load_luts(&preset.textures)?; let luts = T::LoadLut::load_luts(&preset.textures)?;
@ -304,21 +304,21 @@ impl<T: GLInterface> FilterChainImpl<T> {
for param in reflection.meta.parameter_meta.values() { for param in reflection.meta.parameter_meta.values() {
uniform_bindings.insert( uniform_bindings.insert(
UniformBinding::Parameter(param.id.clone()), 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 { for (semantics, param) in &reflection.meta.unique_meta {
uniform_bindings.insert( uniform_bindings.insert(
UniformBinding::SemanticVariable(*semantics), 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 { for (semantics, param) in &reflection.meta.texture_size_meta {
uniform_bindings.insert( uniform_bindings.insert(
UniformBinding::TextureSize(*semantics), 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<T: GLInterface> FilterChainImpl<T> {
filters: &[FilterPass<T>], filters: &[FilterPass<T>],
filter: FilterMode, filter: FilterMode,
wrap_mode: WrapMode, wrap_mode: WrapMode,
) -> (VecDeque<Framebuffer>, Box<[Texture]>) { ) -> (VecDeque<Framebuffer>, Box<[InputTexture]>) {
let mut required_images = 0; let mut required_images = 0;
for pass in filters { for pass in filters {
@ -388,7 +388,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1)); framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1));
let mut history_textures = Vec::new(); let mut history_textures = Vec::new();
history_textures.resize_with(required_images, || Texture { history_textures.resize_with(required_images, || InputTexture {
image: Default::default(), image: Default::default(),
filter, filter,
mip_filter: filter, mip_filter: filter,
@ -470,7 +470,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
} }
// shader_gl3: 2067 // shader_gl3: 2067
let original = Texture { let original = InputTexture {
image: *input, image: *input,
filter, filter,
mip_filter: filter, mip_filter: filter,

View file

@ -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::cross::CrossGlslContext;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
@ -6,18 +6,32 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::reflect::semantics::{ use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics};
MemberOffset, TextureSemantics, UniformBinding, UniqueSemantics,
};
use rustc_hash::FxHashMap; 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::filter_chain::FilterCommon;
use crate::Framebuffer; use crate::Framebuffer;
use crate::gl::{BindTexture, GLInterface, UboRing}; use crate::gl::{BindTexture, GLInterface, UboRing};
use crate::render_target::RenderTarget; 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<T: GLInterface> { pub struct FilterPass<T: GLInterface> {
pub reflection: ShaderReflection, pub reflection: ShaderReflection,
@ -26,11 +40,42 @@ pub struct FilterPass<T: GLInterface> {
pub ubo_location: UniformLocation<GLuint>, pub ubo_location: UniformLocation<GLuint>,
pub ubo_ring: Option<T::UboRing>, pub ubo_ring: Option<T::UboRing>,
pub(crate) uniform_storage: GlUniformStorage, pub(crate) uniform_storage: GlUniformStorage,
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>, pub uniform_bindings: FxHashMap<UniformBinding, UniformOffset>,
pub source: ShaderSource, pub source: ShaderSource,
pub config: ShaderPassConfig, pub config: ShaderPassConfig,
} }
impl TextureInput for InputTexture {
fn size(&self) -> Size<u32> {
self.image.size
}
}
impl ContextOffset<GlUniformBinder, UniformLocation<GLint>> for UniformOffset {
fn offset(&self) -> MemberOffset {
self.offset
}
fn context(&self) -> UniformLocation<GLint> {
self.location.location()
}
}
impl<T: GLInterface> BindSemantics<GlUniformBinder, UniformLocation<GLint>> for FilterPass<T> {
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<T: GLInterface> FilterPass<T> { impl<T: GLInterface> FilterPass<T> {
pub(crate) fn draw( pub(crate) fn draw(
&mut self, &mut self,
@ -39,8 +84,8 @@ impl<T: GLInterface> FilterPass<T> {
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
original: &Texture, original: &InputTexture,
source: &Texture, source: &InputTexture,
output: RenderTarget, output: RenderTarget,
) { ) {
let framebuffer = output.framebuffer; let framebuffer = output.framebuffer;
@ -124,216 +169,33 @@ impl<T: GLInterface> FilterPass<T> {
frame_direction: i32, frame_direction: i32,
fb_size: Size<u32>, fb_size: Size<u32>,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
original: &Texture, original: &InputTexture,
source: &Texture, source: &InputTexture,
) { ) {
// Bind MVP Self::bind_semantics(
if let Some((location, offset)) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { &(),
self.uniform_storage &parent.samplers,
.bind_mat4(*offset, mvp, location.location()); &mut self.uniform_storage,
} &mut (),
mvp,
// bind OutputSize frame_count,
if let Some((location, offset)) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) frame_direction,
{ fb_size,
self.uniform_storage viewport.output.size,
.bind_vec4(*offset, fb_size, location.location()); original,
} source,
&self.uniform_bindings,
// bind FinalViewportSize &self.reflection.meta.texture_meta,
if let Some((location, offset)) = self parent.output_textures[0..pass_index].iter()
.uniform_bindings .map(|o| o.bound()),
.get(&UniqueSemantics::FinalViewport.into()) parent.feedback_textures.iter()
{ .map(|o| o.bound()),
self.uniform_storage parent.history_textures.iter()
.bind_vec4(*offset, viewport.output.size, location.location()); .map(|o| o.bound()),
} parent.luts.iter()
.map(|(u, i)| (*u, i)),
// bind FrameCount &self.source.parameters,
if let Some((location, offset)) = self &parent.config.parameters
.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());
}
}
} }
} }

View file

@ -1,7 +1,7 @@
use crate::error::Result; use crate::error::Result;
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::gl::FramebufferInterface; use crate::gl::FramebufferInterface;
use crate::texture::Texture; use crate::texture::InputTexture;
use gl::types::{GLenum, GLuint}; use gl::types::{GLenum, GLuint};
use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode}; use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
@ -52,8 +52,8 @@ impl Framebuffer {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
original: &Texture, original: &InputTexture,
source: &Texture, source: &InputTexture,
mipmap: bool, mipmap: bool,
) -> Result<Size<u32>> { ) -> Result<Size<u32>> {
T::scale(self, scaling, format, viewport, original, source, mipmap) T::scale(self, scaling, format, viewport, original, source, mipmap)
@ -63,8 +63,8 @@ impl Framebuffer {
T::copy_from(self, image) T::copy_from(self, image)
} }
pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture { pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputTexture {
Texture { InputTexture {
image: GLImage { image: GLImage {
handle: self.image, handle: self.image,
format: self.format, format: self.format,

View file

@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result};
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::gl::framebuffer::Framebuffer; use crate::gl::framebuffer::Framebuffer;
use crate::gl::FramebufferInterface; use crate::gl::FramebufferInterface;
use crate::texture::Texture; use crate::texture::InputTexture;
use gl::types::{GLenum, GLint, GLsizei}; use gl::types::{GLenum, GLint, GLsizei};
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
@ -39,8 +39,8 @@ impl FramebufferInterface for Gl3Framebuffer {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
_original: &Texture, _original: &InputTexture,
source: &Texture, source: &InputTexture,
mipmap: bool, mipmap: bool,
) -> Result<Size<u32>> { ) -> Result<Size<u32>> {
if fb.is_raw { if fb.is_raw {

View file

@ -1,7 +1,7 @@
use crate::error::Result; use crate::error::Result;
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::gl::LoadLut; use crate::gl::LoadLut;
use crate::texture::Texture; use crate::texture::InputTexture;
use gl::types::{GLsizei, GLuint}; use gl::types::{GLsizei, GLuint};
use librashader_common::Size; use librashader_common::Size;
use librashader_presets::TextureConfig; use librashader_presets::TextureConfig;
@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
pub struct Gl3LutLoad; pub struct Gl3LutLoad;
impl LoadLut for Gl3LutLoad { impl LoadLut for Gl3LutLoad {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> { fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>> {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
let pixel_unpack = unsafe { let pixel_unpack = unsafe {
let mut binding = 0; let mut binding = 0;
@ -64,7 +64,7 @@ impl LoadLut for Gl3LutLoad {
luts.insert( luts.insert(
index, index,
Texture { InputTexture {
image: GLImage { image: GLImage {
handle, handle,
format: gl::RGBA8, format: gl::RGBA8,

View file

@ -1,12 +1,12 @@
use crate::gl::BindTexture; use crate::gl::BindTexture;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::InputTexture;
use librashader_reflect::reflect::semantics::TextureBinding; use librashader_reflect::reflect::semantics::TextureBinding;
pub struct Gl3BindTexture; pub struct Gl3BindTexture;
impl BindTexture for Gl3BindTexture { impl BindTexture for Gl3BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) {
unsafe { unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + 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 { unsafe {
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::GenerateMipmap(gl::TEXTURE_2D); gl::GenerateMipmap(gl::TEXTURE_2D);

View file

@ -2,7 +2,7 @@ use crate::error::{FilterChainError, Result};
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::gl::framebuffer::Framebuffer; use crate::gl::framebuffer::Framebuffer;
use crate::gl::FramebufferInterface; use crate::gl::FramebufferInterface;
use crate::texture::Texture; use crate::texture::InputTexture;
use gl::types::{GLenum, GLint, GLsizei}; use gl::types::{GLenum, GLint, GLsizei};
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
@ -37,8 +37,8 @@ impl FramebufferInterface for Gl46Framebuffer {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
_original: &Texture, _original: &InputTexture,
source: &Texture, source: &InputTexture,
mipmap: bool, mipmap: bool,
) -> Result<Size<u32>> { ) -> Result<Size<u32>> {
if fb.is_raw { if fb.is_raw {

View file

@ -1,7 +1,7 @@
use crate::error::Result; use crate::error::Result;
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::gl::LoadLut; use crate::gl::LoadLut;
use crate::texture::Texture; use crate::texture::InputTexture;
use gl::types::{GLsizei, GLuint}; use gl::types::{GLsizei, GLuint};
use librashader_common::Size; use librashader_common::Size;
use librashader_presets::TextureConfig; use librashader_presets::TextureConfig;
@ -11,7 +11,7 @@ use rustc_hash::FxHashMap;
pub struct Gl46LutLoad; pub struct Gl46LutLoad;
impl LoadLut for Gl46LutLoad { impl LoadLut for Gl46LutLoad {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> { fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>> {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
let pixel_unpack = unsafe { let pixel_unpack = unsafe {
let mut binding = 0; let mut binding = 0;
@ -66,7 +66,7 @@ impl LoadLut for Gl46LutLoad {
luts.insert( luts.insert(
index, index,
Texture { InputTexture {
image: GLImage { image: GLImage {
handle, handle,
format: gl::RGBA8, format: gl::RGBA8,

View file

@ -1,12 +1,12 @@
use crate::gl::BindTexture; use crate::gl::BindTexture;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::InputTexture;
use librashader_reflect::reflect::semantics::TextureBinding; use librashader_reflect::reflect::semantics::TextureBinding;
pub struct Gl46BindTexture; pub struct Gl46BindTexture;
impl BindTexture for Gl46BindTexture { impl BindTexture for Gl46BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture) {
unsafe { unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::BindTextureUnit(binding.binding, texture.image.handle); 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) } unsafe { gl::GenerateTextureMipmap(texture.image.handle) }
} }
} }

View file

@ -6,7 +6,7 @@ use crate::binding::UniformLocation;
use crate::error::Result; use crate::error::Result;
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::InputTexture;
pub use framebuffer::Framebuffer; pub use framebuffer::Framebuffer;
use gl::types::{GLenum, GLuint}; use gl::types::{GLenum, GLuint};
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
@ -16,7 +16,7 @@ use librashader_runtime::uniforms::UniformStorageAccess;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
pub trait LoadLut { pub trait LoadLut {
fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>>; fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, InputTexture>>;
} }
pub trait DrawQuad { pub trait DrawQuad {
@ -42,8 +42,8 @@ pub trait FramebufferInterface {
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport: &Viewport<&Framebuffer>, viewport: &Viewport<&Framebuffer>,
_original: &Texture, _original: &InputTexture,
source: &Texture, source: &InputTexture,
mipmap: bool, mipmap: bool,
) -> Result<Size<u32>>; ) -> Result<Size<u32>>;
fn clear<const REBIND: bool>(fb: &Framebuffer); fn clear<const REBIND: bool>(fb: &Framebuffer);
@ -52,8 +52,8 @@ pub trait FramebufferInterface {
} }
pub trait BindTexture { pub trait BindTexture {
fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture); fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &InputTexture);
fn gen_mipmaps(texture: &Texture); fn gen_mipmaps(texture: &InputTexture);
} }
pub trait GLInterface { pub trait GLInterface {

View file

@ -1,16 +1,32 @@
use gl::types::GLuint;
use crate::framebuffer::GLImage; use crate::framebuffer::GLImage;
use librashader_common::{FilterMode, WrapMode}; use librashader_common::{FilterMode, WrapMode};
#[derive(Default, Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]
pub struct Texture { pub struct InputTexture {
pub image: GLImage, pub image: GLImage,
pub filter: FilterMode, pub filter: FilterMode,
pub mip_filter: FilterMode, pub mip_filter: FilterMode,
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,
} }
impl Texture { impl InputTexture {
pub fn is_bound(&self) -> bool { pub fn is_bound(&self) -> bool {
self.image.handle != 0 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<InputTexture> for InputTexture {
fn as_ref(&self) -> &InputTexture {
self
}
} }

View file

@ -14,8 +14,9 @@ use librashader_reflect::reflect::semantics::{
BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics, BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniqueSemantics,
}; };
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess}; use librashader_runtime::uniforms::{BindUniform, NoUniformBinder, UniformStorage, UniformStorageAccess};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use librashader_runtime::binding::{BindSemantics, TextureInput};
pub struct FilterPass { pub struct FilterPass {
pub device: Arc<ash::Device>, pub device: Arc<ash::Device>,
@ -30,6 +31,42 @@ pub struct FilterPass {
pub frames_in_flight: u32, pub frames_in_flight: u32,
} }
impl TextureInput for InputImage {
fn size(&self) -> Size<u32> {
self.image.size
}
}
impl BindSemantics for FilterPass {
type InputTexture = InputImage;
type SamplerSet = SamplerSet;
type DescriptorSet<'a> = vk::DescriptorSet;
type DeviceContext = Arc<ash::Device>;
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 { impl FilterPass {
#[inline(always)] #[inline(always)]
fn bind_texture( fn bind_texture(
@ -81,7 +118,7 @@ impl FilterPass {
source: &InputImage, source: &InputImage,
output: &RenderTarget, output: &RenderTarget,
) -> error::Result<()> { ) -> 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]; [(frame_count % self.frames_in_flight) as usize];
self.build_semantics( self.build_semantics(
@ -92,7 +129,7 @@ impl FilterPass {
frame_direction, frame_direction,
output.output.size, output.output.size,
viewport.output.size, viewport.output.size,
&descriptor, &mut descriptor,
original, original,
source, source,
); );
@ -182,262 +219,41 @@ impl FilterPass {
fn build_semantics( fn build_semantics(
&mut self, &mut self,
_pass_index: usize, pass_index: usize,
parent: &FilterCommon, parent: &FilterCommon,
mvp: &[f32; 16], mvp: &[f32; 16],
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
fb_size: Size<u32>, fb_size: Size<u32>,
viewport_size: Size<u32>, viewport_size: Size<u32>,
descriptor_set: &vk::DescriptorSet, mut descriptor_set: &mut vk::DescriptorSet,
original: &InputImage, original: &InputImage,
source: &InputImage, source: &InputImage,
) { ) {
if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::MVP.into()) { Self::bind_semantics(
self.uniform_storage.bind_mat4(*offset, mvp, None); &self.device,
} &parent.samplers,
&mut self.uniform_storage,
// bind OutputSize &mut descriptor_set,
if let Some(offset) = self.uniform_bindings.get(&UniqueSemantics::Output.into()) { mvp,
self.uniform_storage.bind_vec4(*offset, fb_size, None); frame_count,
} frame_direction,
fb_size,
// bind FinalViewportSize viewport_size,
if let Some(offset) = self original,
.uniform_bindings source,
.get(&UniqueSemantics::FinalViewport.into()) &self.uniform_bindings,
{ &self.reflection.meta.texture_meta,
self.uniform_storage.bind_vec4(*offset, viewport_size, None); parent.output_inputs[0..pass_index].iter()
} .map(|o| o.as_ref()),
parent.feedback_inputs.iter()
// bind FrameCount .map(|o| o.as_ref()),
if let Some(offset) = self parent.history_textures.iter()
.uniform_bindings .map(|o| o.as_ref()),
.get(&UniqueSemantics::FrameCount.into()) parent.luts.iter()
{ .map(|(u, i)| (*u, i.as_ref())),
self.uniform_storage.bind_scalar(*offset, frame_count, None); &self.source.parameters,
} &parent.config.parameters
);
// 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);
}
}
} }
} }

View file

@ -249,3 +249,9 @@ impl LutTexture {
}) })
} }
} }
impl AsRef<InputImage> for LutTexture {
fn as_ref(&self) -> &InputImage {
&self.image
}
}

View file

@ -518,7 +518,7 @@ pub struct VulkanImage {
} }
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct InputImage { pub struct InputImage {
/// A handle to the `VkImage`. /// A handle to the `VkImage`.
pub image: VulkanImage, pub image: VulkanImage,
/// A handle to the `VkImageView` for the image. /// A handle to the `VkImageView` for the image.
@ -527,3 +527,9 @@ pub(crate) struct InputImage {
pub filter_mode: FilterMode, pub filter_mode: FilterMode,
pub mip_filter: FilterMode, pub mip_filter: FilterMode,
} }
impl AsRef<InputImage> for InputImage {
fn as_ref(&self) -> &InputImage {
&self
}
}

View file

@ -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<u32>;
}
/// A uniform member offset with context that needs to be resolved.
pub trait ContextOffset<H, C>
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]>,
{
/// 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
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]>,
{
fn offset(&self) -> MemberOffset {
*self
}
fn context(&self) -> Option<()> {
None
}
}
/// Trait that abstracts binding of semantics to shader uniforms.
pub trait BindSemantics<H=NoUniformBinder, C=Option<()>>
where
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]>
{
/// 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,
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<H, C>,
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>)>,
parameter_defaults: &[ShaderParameter],
runtime_parameters: &HashMap<String, f32, impl BuildHasher>,
)
{
// 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());
}
}
}
}

View file

@ -18,3 +18,6 @@ pub mod image;
/// Ringbuffer helpers /// Ringbuffer helpers
pub mod ringbuffer; pub mod ringbuffer;
/// Generic implementation of semantics binding.
pub mod binding;