diff --git a/librashader-presets/src/preset.rs b/librashader-presets/src/preset.rs index b3cb1df..9566588 100644 --- a/librashader-presets/src/preset.rs +++ b/librashader-presets/src/preset.rs @@ -1,9 +1,24 @@ use crate::error::ParsePresetError; use std::convert::Infallible; +use std::ops::Mul; use std::path::PathBuf; use std::str::FromStr; use librashader::{FilterMode, WrapMode}; +#[derive(Debug, Clone)] +pub struct ShaderPassConfig { + pub id: i32, + pub name: PathBuf, + pub alias: Option, + pub filter: FilterMode, + pub wrap_mode: WrapMode, + pub frame_count_mod: u32, + pub srgb_framebuffer: bool, + pub float_framebuffer: bool, + pub mipmap_input: bool, + pub scaling: Scale2D, +} + #[repr(i32)] #[derive(Default, Copy, Clone, Debug)] pub enum ScaleType { @@ -25,6 +40,37 @@ impl Default for ScaleFactor { } } +impl From for f32 { + fn from(value: ScaleFactor) -> Self { + match value { + ScaleFactor::Float(f) => f, + ScaleFactor::Absolute(f) => f as f32, + } + } +} + +impl Mul for f32 { + type Output = f32; + + fn mul(self, rhs: ScaleFactor) -> Self::Output { + match rhs { + ScaleFactor::Float(f) => f * self, + ScaleFactor::Absolute(f) => f as f32 * self + } + } +} + +impl Mul for u32 { + type Output = f32; + + fn mul(self, rhs: ScaleFactor) -> Self::Output { + match rhs { + ScaleFactor::Float(f) => f * self as f32, + ScaleFactor::Absolute(f) => (f as u32 * self) as f32 + } + } +} + impl FromStr for ScaleType { type Err = ParsePresetError; @@ -51,20 +97,6 @@ pub struct Scale2D { pub y: Scaling, } -#[derive(Debug, Clone)] -pub struct ShaderPassConfig { - pub id: i32, - pub name: PathBuf, - pub alias: Option, - pub filter: FilterMode, - pub wrap_mode: WrapMode, - pub frame_count_mod: u32, - pub srgb_framebuffer: bool, - pub float_framebuffer: bool, - pub mipmap_input: bool, - pub scaling: Scale2D, -} - #[derive(Debug, Clone)] pub struct TextureConfig { pub name: String, diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 50f4f2f..6039935 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -7,11 +7,11 @@ use librashader_reflect::reflect::TextureSemanticMap; use librashader_reflect::reflect::VariableSemanticMap; use rustc_hash::FxHashMap; use librashader::ShaderSource; -use librashader_presets::ShaderPreset; +use librashader_presets::{Scale2D, ScaleType, Scaling, ShaderPassConfig, ShaderPreset}; use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureImage, TextureSemantics, VariableMeta, VariableSemantics}; use crate::FilterChain; use crate::framebuffer::Framebuffer; -use crate::util::{Location, VariableLocation, RingBuffer, Size, Texture, TextureMeta}; +use crate::util::{Location, VariableLocation, RingBuffer, Size, GlImage, Texture, Viewport}; pub struct FilterPass { pub reflection: ShaderReflection, @@ -25,6 +25,7 @@ pub struct FilterPass { pub framebuffer: Framebuffer, pub feedback_framebuffer: Framebuffer, pub source: ShaderSource, + pub config: ShaderPassConfig } impl FilterPass { @@ -81,10 +82,10 @@ impl FilterPass { Self::build_uniform(location, buffer, value, gl::Uniform1f) } - fn set_texture(binding: &TextureImage, texture: &TextureMeta) { + fn set_texture(binding: &TextureImage, texture: &Texture) { unsafe { gl::ActiveTexture((gl::TEXTURE0 + binding.binding) as GLenum); - gl::BindTexture(gl::TEXTURE_2D, texture.texture.handle); + gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, GLenum::from(texture.filter) as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, texture.filter.gl_mip(texture.mip_filter) as GLint); @@ -92,10 +93,73 @@ impl FilterPass { gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, GLenum::from(texture.wrap_mode) as GLint); } } - // todo: build vec4 texture + fn scale_framebuffer(&mut self, viewport: &Viewport, original: &Texture, source: &Texture) -> Size { + let mut width = 0f32; + let mut height = 0f32; + + match self.config.scaling.x { + Scaling { + scale_type: ScaleType::Input, + factor + } => { + width = source.image.size.width * factor + }, + Scaling { + scale_type: ScaleType::Absolute, + factor + } => { + width = factor.into() + } + Scaling { + scale_type: ScaleType::Viewport, + factor + } => { + width = viewport.size.width * factor + } + }; + + match self.config.scaling.y { + Scaling { + scale_type: ScaleType::Input, + factor + } => { + height = source.image.size.height * factor + }, + Scaling { + scale_type: ScaleType::Absolute, + factor + } => { + height = factor.into() + } + Scaling { + scale_type: ScaleType::Viewport, + factor + } => { + height = viewport.size.height * factor + } + }; + + let size = Size { + width: width.round() as u32, + height: height.round() as u32 + }; + + self.framebuffer.size = size; + size + } + + pub fn build_commands(&mut self, parent: &FilterChain, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, viewport: &Viewport, original: &Texture, source: &Texture) { + unsafe { + gl::UseProgram(self.program); + } + + + } // framecount should be pre-modded - fn build_semantics(&mut self, parent: &FilterChain, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, fb_size: Size, vp_size: Size, original: &TextureMeta, source: &TextureMeta) { + fn build_semantics(&mut self, parent: &FilterChain, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, viewport: &Viewport, original: &Texture, source: &Texture) { + let fb_size = self.scale_framebuffer(viewport, original, source); + if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::MVP) { let mvp = mvp.unwrap_or(&[ 2f32, 0.0, 0.0, 0.0, @@ -118,17 +182,6 @@ impl FilterPass { MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }; FilterPass::build_vec4(location, &mut buffer[offset..][..4], fb_size) - // - // if location.fragment >= 0 || location.vertex >= 0 { - // FilterPass::build_vec4_uniform(location, fb_size); - // } else { - // let (buffer, offset) = match variable.offset { - // MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), - // MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) - // }; - // - // FilterPass::build_vec4(&mut buffer[offset..][..4], fb_size) - // } } if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::FinalViewport) { @@ -138,10 +191,9 @@ impl FilterPass { MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }; - FilterPass::build_vec4(location, &mut buffer[offset..][..4], vp_size) + FilterPass::build_vec4(location, &mut buffer[offset..][..4], viewport.size) } - if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::FrameCount) { // todo: do all variables have location..? let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location(); @@ -169,7 +221,7 @@ impl FilterPass { MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }; - FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.texture.size); + FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size); if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Original.semantics(0)) { FilterPass::set_texture(binding, original); @@ -182,10 +234,10 @@ impl FilterPass { MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }; - FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.texture.size); + FilterPass::build_vec4(location, &mut buffer[offset..][..4], source.image.size); if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Source.semantics(0)) { - FilterPass::set_texture(binding, original); + FilterPass::set_texture(binding, source); } } @@ -195,7 +247,7 @@ impl FilterPass { MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) }; - FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.texture.size); + FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size); if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) { FilterPass::set_texture(binding, original); @@ -221,8 +273,13 @@ impl FilterPass { FilterPass::build_float(location, &mut buffer[offset..][..4], value) } + // todo: deal with both lut name and index + // for (index, lut) in parent.luts.values().enumerate() { + // // todo: sort out order + // if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::User.semantics(index as u32)) { + // } + // + // } // todo history - - } } \ No newline at end of file diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 46b3dce..98eac13 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -26,7 +26,7 @@ use librashader_reflect::reflect::cross::CrossReflect; use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, ShaderReflection, UniformSemantic}; use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableMeta, VariableSemantics}; use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap}; -use util::{Location, VariableLocation, RingBuffer, Size, Texture, TextureMeta, Viewport}; +use util::{Location, VariableLocation, RingBuffer, Size, GlImage, Texture, Viewport}; unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { let shader = gl::CreateShader(stage); @@ -117,9 +117,9 @@ pub struct FilterChain { semantics: ReflectSemantics, preset: ShaderPreset, original_history: Vec, - history: Vec, - feedback: Vec, - luts: FxHashMap + history: Vec, + feedback: Vec, + luts: FxHashMap } impl FilterChain { @@ -279,6 +279,7 @@ impl FilterChain { // retroarch checks if feedback frames are used but we'll just init it tbh. framebuffer: Framebuffer::new(1), feedback_framebuffer: Framebuffer::new(1), + config: config.clone() }); } @@ -356,8 +357,8 @@ impl FilterChain { gl::BindTexture(gl::TEXTURE_2D, 0); } - luts.insert(texture.name.clone(), TextureMeta { - texture: Texture { + luts.insert(texture.name.clone(), Texture { + image: GlImage { handle, format: gl::RGBA8, size: Size { @@ -372,6 +373,7 @@ impl FilterChain { }); } + // todo: split params Ok(FilterChain { passes: filters, semantics, @@ -385,32 +387,44 @@ impl FilterChain { // how much info do we actually need? - // fn frame(&mut self, count: u64, vp: &Viewport, input: &Texture, clear: bool) { - // - // // todo: make copy - // - // let original = Texture { - // handle: input.handle, - // format: self.preset.shaders.first()., - // size: Size {}, - // padded_size: Size {} - // }; - // // todo: deal with the mess that is frame history - // } + fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, clear: bool) { - fn do_final_pass(&mut self, count: u64, vp: &Viewport, input: Texture, clear: bool, mvp: &[f32]) { + let filter = self.preset.shaders.first().map(|f| f.filter).unwrap_or_default(); + let wrap_mode = self.preset.shaders.first().map(|f| f.wrap_mode).unwrap_or_default(); + let original = Texture { + image: input, + filter, + mip_filter: filter, + wrap_mode + }; + + let mut source = original.clone(); + + for passes in &mut self.passes { + // passes.build_semantics(&self, None, count, 1, vp, &original, &source); + } + + // todo: deal with the mess that is frame history + } + + pub fn do_final_pass(&mut self, count: u64, vp: &Viewport, input: GlImage, clear: bool, mvp: &[f32]) { // todo: make copy // todo: get filter info from pass data. - let original = TextureMeta { - texture: input, - filter: FilterMode::Linear, - mip_filter: FilterMode::Linear, - wrap_mode: Default::default() + let filter = self.preset.shaders.first().map(|f| f.filter).unwrap_or_default(); + let wrap_mode = self.preset.shaders.first().map(|f| f.wrap_mode).unwrap_or_default(); + let original = Texture { + image: input, + filter, + mip_filter: filter, + wrap_mode }; + + + // todo: deal with the mess that is frame history } } @@ -423,8 +437,8 @@ mod tests { #[test] fn triangle() { let (glfw, window, events, shader, vao) = hello_triangle::setup(); - // FilterChain::load("../test/basic.slangp").unwrap(); - FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap(); + FilterChain::load("../test/basic.slangp").unwrap(); + // FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap(); hello_triangle::do_loop(glfw, window, events, shader, vao); } diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index bd346ee..f4912d2 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -32,8 +32,9 @@ pub fn calc_miplevel(width: u32, height: u32) -> u32 { return levels; } -pub struct TextureMeta { - pub texture: Texture, +#[derive(Debug, Copy, Clone)] +pub struct Texture { + pub image: GlImage, pub filter: FilterMode, pub mip_filter: FilterMode, pub wrap_mode: WrapMode @@ -43,8 +44,7 @@ pub struct TextureMeta { pub struct Viewport { pub x: i32, pub y: i32, - pub width: i32, - pub height: i32 + pub size: Size, } #[derive(Default, Debug, Copy, Clone)] @@ -54,7 +54,7 @@ pub struct Size { } #[derive(Debug, Copy, Clone)] -pub struct Texture { +pub struct GlImage { pub handle: GLuint, pub format: GLenum, pub size: Size,