diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index 37885f1..ed158df 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -392,7 +392,7 @@ impl FilterChain { let semantics = ReflectSemantics { uniform_semantics, - non_uniform_semantics: texture_semantics, + texture_semantics: texture_semantics, }; Ok((passes, semantics)) diff --git a/librashader-runtime-gl/src/binding.rs b/librashader-runtime-gl/src/binding.rs index 9340246..fb88910 100644 --- a/librashader-runtime-gl/src/binding.rs +++ b/librashader-runtime-gl/src/binding.rs @@ -1,8 +1,5 @@ use gl::types::GLint; -use librashader_reflect::reflect::semantics::{ - MemberOffset, SemanticMap, TextureSemantics, VariableSemantics, -}; -use std::hash::Hash; +use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset}; #[derive(Debug)] pub enum VariableLocation { @@ -25,24 +22,22 @@ pub struct UniformLocation { } impl UniformLocation { - pub fn is_fragment_valid(&self) -> bool { - self.fragment >= 0 - } + // pub fn is_fragment_valid(&self) -> bool { + // self.fragment >= 0 + // } + // + // pub fn is_vertex_valid(&self) -> bool { + // self.vertex >= 0 + // } - pub fn is_vertex_valid(&self) -> bool { - self.vertex >= 0 - } - - pub fn is_valid(&self) -> bool { - self.is_fragment_valid() || self.is_vertex_valid() + pub fn is_valid(&self, stage: BindingStage) -> bool { + let mut validity = false; + if stage.contains(BindingStage::FRAGMENT) { + validity = validity || self.fragment >= 0; + } + if stage.contains(BindingStage::VERTEX) { + validity = validity || self.vertex >= 0; + } + validity } } - -#[derive(Debug, Copy, Clone)] -pub enum MemberLocation { - Offset(MemberOffset), - Uniform(UniformLocation), -} - -#[derive(Debug, Copy, Clone)] -pub struct TextureUnit(T); diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index d2d0f71..2bc56fe 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -4,10 +4,10 @@ use crate::framebuffer::{Framebuffer, GlImage, Viewport}; use crate::quad_render::DrawQuad; use crate::render_target::RenderTarget; use crate::util; -use crate::util::{gl_get_version, InlineRingBuffer}; +use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer}; use crate::error::{FilterChainError, Result}; -use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; +use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint}; use librashader_common::image::Image; use librashader_common::{FilterMode, Size, WrapMode}; use librashader_preprocess::ShaderSource; @@ -22,6 +22,7 @@ use std::collections::VecDeque; use std::path::Path; use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation}; use librashader_reflect::front::shaderc::GlslangCompilation; +use crate::options::{FilterChainOptions, FrameOptions}; use crate::samplers::SamplerSet; use crate::texture::Texture; @@ -133,11 +134,14 @@ type ShaderPassMeta<'a> = ( impl FilterChain { /// Load a filter chain from a pre-parsed `ShaderPreset`. - pub fn load_from_preset(preset: ShaderPreset) -> Result { + pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result { let (passes, semantics) = FilterChain::load_preset(&preset)?; + let version = options.map(|o| gl_u16_to_version(o.gl_version)) + .unwrap_or_else(|| gl_get_version()); + // initialize passes - let filters = FilterChain::init_passes(passes, &semantics)?; + let filters = FilterChain::init_passes(version, passes, &semantics)?; let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); let default_wrap = filters @@ -160,7 +164,7 @@ impl FilterChain { feedback_textures.resize_with(filters.len(), Texture::default); // load luts - let luts = FilterChain::load_luts(&samplers, &preset.textures)?; + let luts = FilterChain::load_luts(&preset.textures)?; let (history_framebuffers, history_textures) = FilterChain::init_history(&filters, default_filter, default_wrap); @@ -194,10 +198,10 @@ impl FilterChain { } /// Load the shader preset at the given path into a filter chain. - pub fn load_from_path(path: impl AsRef) -> Result { + pub fn load_from_path(path: impl AsRef, options: Option<&FilterChainOptions>) -> Result { // load passes from preset let preset = ShaderPreset::try_parse(path)?; - Self::load_from_preset(preset) + Self::load_from_preset(preset, options) } fn load_preset( @@ -260,13 +264,13 @@ impl FilterChain { let semantics = ReflectSemantics { uniform_semantics, - non_uniform_semantics: texture_semantics, + texture_semantics, }; Ok((passes, semantics)) } - fn load_luts(samplers: &SamplerSet, textures: &[TextureConfig]) -> Result> { + fn load_luts(textures: &[TextureConfig]) -> Result> { let mut luts = FxHashMap::default(); for (index, texture) in textures.iter().enumerate() { @@ -305,10 +309,6 @@ impl FilterChain { ); let mipmap = levels > 1; - // let linear = texture.filter_mode == FilterMode::Linear; - - // set mipmaps and wrapping - if mipmap { gl::GenerateMipmap(gl::TEXTURE_2D); } @@ -335,6 +335,7 @@ impl FilterChain { } fn init_passes( + version: GlVersion, passes: Vec, semantics: &ReflectSemantics, ) -> Result> { @@ -343,7 +344,7 @@ impl FilterChain { // initialize passes for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() { let reflection = reflect.reflect(index, semantics)?; - let glsl = reflect.compile(gl_get_version())?; + let glsl = reflect.compile(version)?; let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?; @@ -444,7 +445,6 @@ impl FilterChain { ] .into_boxed_slice(); - // todo: reflect indexed parameters let mut uniform_bindings = FxHashMap::default(); for param in reflection.meta.parameter_meta.values() { uniform_bindings.insert( @@ -571,10 +571,12 @@ impl FilterChain { /// Process a frame with the input image. /// /// When this frame returns, GL_FRAMEBUFFER is bound to 0. - pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, clear: bool) -> Result<()> { - if clear { - for framebuffer in &self.history_framebuffers { - framebuffer.clear() + pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, options: Option<&FrameOptions>) -> Result<()> { + if let Some(options) = options { + if options.clear_history { + for framebuffer in &self.history_framebuffers { + framebuffer.clear() + } } } diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 20dc805..d67043c 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -1,4 +1,4 @@ -use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; +use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint}; use librashader_reflect::back::cross::GlslangGlslContext; use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::reflect::ShaderReflection; @@ -6,7 +6,7 @@ use librashader_reflect::reflect::ShaderReflection; use librashader_common::{ShaderFormat, Size}; use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; -use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; +use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; use rustc_hash::FxHashMap; use crate::binding::{UniformLocation, VariableLocation}; @@ -31,19 +31,30 @@ pub struct FilterPass { } impl FilterPass { - fn build_mvp(buffer: &mut [u8], mvp: &[f32]) { - let mvp = bytemuck::cast_slice(mvp); - buffer.copy_from_slice(mvp); + fn build_mat4(location: UniformLocation, buffer: &mut [u8], mvp: &[f32; 16]) { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mvp.as_ptr()); + } + if location.is_valid(BindingStage::FRAGMENT) { + gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mvp.as_ptr()); + } + } + } else { + let mvp = bytemuck::cast_slice(mvp); + buffer.copy_from_slice(mvp); + } } fn build_vec4(location: UniformLocation, buffer: &mut [u8], size: impl Into<[f32; 4]>) { let vec4 = size.into(); - if location.fragment >= 0 || location.vertex >= 0 { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { unsafe { - if location.vertex >= 0 { + if location.is_valid(BindingStage::VERTEX) { gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); } - if location.fragment >= 0 { + if location.is_valid(BindingStage::FRAGMENT) { gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); } } @@ -63,12 +74,12 @@ impl FilterPass { T: Copy, T: bytemuck::Pod, { - if location.fragment >= 0 || location.vertex >= 0 { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { unsafe { - if location.vertex >= 0 { + if location.is_valid(BindingStage::VERTEX) { glfn(location.vertex, value); } - if location.fragment >= 0 { + if location.is_valid(BindingStage::FRAGMENT) { glfn(location.fragment, value); } } @@ -163,7 +174,7 @@ impl FilterPass { if self.ubo_location.vertex != gl::INVALID_INDEX { gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer); } - if self.ubo_location.vertex != gl::INVALID_INDEX { + if self.ubo_location.fragment != gl::INVALID_INDEX { gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer); } } @@ -233,7 +244,7 @@ impl FilterPass { &mut self, pass_index: usize, parent: &FilterCommon, - mvp: &[f32], + mvp: &[f32; 16], frame_count: u32, frame_direction: i32, fb_size: Size, @@ -242,7 +253,7 @@ impl FilterPass { source: &Texture, ) { // Bind MVP - if let Some((_location, offset)) = + if let Some((location, offset)) = self.uniform_bindings.get(&VariableSemantics::MVP.into()) { let mvp_size = mvp.len() * std::mem::size_of::(); @@ -250,7 +261,7 @@ impl FilterPass { MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), }; - FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp) + FilterPass::build_mat4(location.location(), &mut buffer[offset..][..mvp_size], mvp) } // bind OutputSize diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs index 960a7b7..28b55bd 100644 --- a/librashader-runtime-gl/src/framebuffer.rs +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -344,7 +344,7 @@ pub struct Viewport<'a> { pub x: i32, pub y: i32, pub output: &'a Framebuffer, - pub mvp: Option<&'a [f32]>, + pub mvp: Option<&'a [f32; 16]>, } #[derive(Default, Debug, Copy, Clone)] diff --git a/librashader-runtime-gl/src/hello_triangle.rs b/librashader-runtime-gl/src/hello_triangle.rs index d16eb72..36a59e8 100644 --- a/librashader-runtime-gl/src/hello_triangle.rs +++ b/librashader-runtime-gl/src/hello_triangle.rs @@ -517,7 +517,7 @@ void main() padded_size: Default::default(), }; - filter.frame(framecount, &viewport, &rendered, false) + filter.frame(framecount, &viewport, &rendered, None) .unwrap(); unsafe { diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 2a4337f..669e0f7 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -20,6 +20,7 @@ pub use framebuffer::Viewport; #[cfg(test)] mod hello_triangle; mod texture; +mod options; #[cfg(test)] mod tests { @@ -30,7 +31,7 @@ mod tests { fn triangle_gl() { let (glfw, window, events, shader, vao) = hello_triangle::setup(); let mut filter = - FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp") + FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp", None) .unwrap(); hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); } diff --git a/librashader-runtime-gl/src/options.rs b/librashader-runtime-gl/src/options.rs new file mode 100644 index 0000000..1b3985c --- /dev/null +++ b/librashader-runtime-gl/src/options.rs @@ -0,0 +1,11 @@ +#[repr(C)] +#[derive(Debug, Clone)] +pub struct FrameOptions { + pub clear_history: bool +} + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct FilterChainOptions { + pub gl_version: u16 +} diff --git a/librashader-runtime-gl/src/render_target.rs b/librashader-runtime-gl/src/render_target.rs index d3db5e5..44e2d5c 100644 --- a/librashader-runtime-gl/src/render_target.rs +++ b/librashader-runtime-gl/src/render_target.rs @@ -1,7 +1,7 @@ use crate::framebuffer::{Framebuffer, Viewport}; #[rustfmt::skip] -static DEFAULT_MVP: &[f32] = &[ +static DEFAULT_MVP: &[f32; 16] = &[ 2f32, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, @@ -10,14 +10,14 @@ static DEFAULT_MVP: &[f32] = &[ #[derive(Debug, Copy, Clone)] pub struct RenderTarget<'a> { - pub mvp: &'a [f32], + pub mvp: &'a [f32; 16], pub framebuffer: &'a Framebuffer, pub x: i32, pub y: i32 } impl<'a> RenderTarget<'a> { - pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32]>, x: i32, y: i32) -> Self { + pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self { if let Some(mvp) = mvp { RenderTarget { framebuffer: backbuffer, diff --git a/librashader-runtime-gl/src/samplers.rs b/librashader-runtime-gl/src/samplers.rs index 3eb0452..57cc5e9 100644 --- a/librashader-runtime-gl/src/samplers.rs +++ b/librashader-runtime-gl/src/samplers.rs @@ -1,8 +1,6 @@ -use std::iter::Filter; use gl::types::{GLenum, GLint, GLuint}; use rustc_hash::FxHashMap; use librashader_common::{FilterMode, WrapMode}; -use crate::error::Result; pub struct SamplerSet { // todo: may need to deal with differences in mip filter. diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index 46afd3c..f13db26 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -1,6 +1,5 @@ -use crate::framebuffer::GlImage; use gl::types::{GLenum, GLuint}; -use librashader_common::{FilterMode, Size, WrapMode}; +use librashader_common::Size; use librashader_reflect::back::cross::GlVersion; pub fn calc_miplevel(size: Size) -> u32 { @@ -110,4 +109,21 @@ pub fn gl_get_version() -> GlVersion { _ => GlVersion::V1_50 } +} + +pub fn gl_u16_to_version(version: u16) -> GlVersion { + match version { + 300 => GlVersion::V1_30, + 310 => GlVersion::V1_40, + 320 => GlVersion::V1_50, + 330 => GlVersion::V3_30, + 400 => GlVersion::V4_00, + 410 => GlVersion::V4_10, + 420 => GlVersion::V4_20, + 430 => GlVersion::V4_30, + 440 => GlVersion::V4_40, + 450 => GlVersion::V4_50, + 460 => GlVersion::V4_60, + _ => GlVersion::V1_50 + } } \ No newline at end of file