diff --git a/Cargo.lock b/Cargo.lock index 48ad59b..5d1c87e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -456,6 +456,7 @@ name = "librashader-reflect" version = "0.1.0" dependencies = [ "bitflags", + "bytemuck", "librashader-common", "librashader-preprocess", "naga", diff --git a/librashader-reflect/Cargo.toml b/librashader-reflect/Cargo.toml index c493da7..687f8be 100644 --- a/librashader-reflect/Cargo.toml +++ b/librashader-reflect/Cargo.toml @@ -21,6 +21,9 @@ naga = { version = "0.10.0", features = ["glsl-in", "spv-in", "spv-out", "glsl-o rspirv = { version = "0.11.0+1.5.4", optional = true } rspirv-reflect = { git = "https://github.com/Traverse-Research/rspirv-reflect", optional = true } + +bytemuck = "1.12.3" + [features] default = [] unstable-rust-pipeline = [ "naga", "rspirv", "rspirv-reflect" ] diff --git a/librashader-reflect/src/reflect/mod.rs b/librashader-reflect/src/reflect/mod.rs index 8489a31..a554a4d 100644 --- a/librashader-reflect/src/reflect/mod.rs +++ b/librashader-reflect/src/reflect/mod.rs @@ -13,6 +13,7 @@ pub mod semantics; mod naga; #[cfg(feature = "unstable-rust-pipeline")] mod rspirv; +pub mod uniforms; pub trait ReflectShader { fn reflect( diff --git a/librashader-reflect/src/reflect/uniforms.rs b/librashader-reflect/src/reflect/uniforms.rs new file mode 100644 index 0000000..6e6d2f3 --- /dev/null +++ b/librashader-reflect/src/reflect/uniforms.rs @@ -0,0 +1,96 @@ +use std::marker::PhantomData; +use crate::reflect::semantics::MemberOffset; + +pub trait UniformScalar: Copy + bytemuck::Pod {} +impl UniformScalar for f32 {} +impl UniformScalar for i32 {} +impl UniformScalar for u32 {} + +pub struct NoUniformBinder; +impl BindUniform, T> for NoUniformBinder { + fn bind_uniform(_: T, _: Option<()>) -> Option<()> { + None + } +} + +pub trait BindUniform { + fn bind_uniform(value: T, ctx: C) -> Option<()>; +} + +pub struct UniformBuffer> { + pub ubo: Box<[u8]>, + pub push: Box<[u8]>, + _h: PhantomData, + _c: PhantomData +} + +impl UniformBuffer +where H: BindUniform, H: BindUniform, H: BindUniform, +H: for <'a> BindUniform, +H: for <'a> BindUniform +{ + pub fn new(ubo_size: usize, push_size: usize) -> Self { + UniformBuffer { + ubo: vec![0u8; ubo_size].into_boxed_slice(), + push: vec![0u8; push_size].into_boxed_slice(), + _h: Default::default(), + _c: Default::default(), + } + } + + #[inline(always)] + fn write_scalar_inner(buffer: &mut [u8], value: T, ctx: C) + where H: BindUniform + { + if let None = H::bind_uniform(value, ctx) { + let buffer = bytemuck::cast_slice_mut(buffer); + buffer[0] = value; + }; + } + + fn write_mat4_inner(buffer: &mut [u8], mat4: &[f32; 16], ctx: C) { + if let None = H::bind_uniform(mat4, ctx) { + let mat4 = bytemuck::cast_slice(mat4); + buffer.copy_from_slice(mat4); + } + } + + fn write_vec4_inner(buffer: &mut [u8], vec4: impl Into<[f32; 4]>, ctx: C) { + let vec4 = vec4.into(); + if let None = H::bind_uniform(&vec4, ctx) { + let vec4 = bytemuck::cast_slice(&vec4); + buffer.copy_from_slice(vec4); + } + } + + + pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C) { + let (buffer, offset) = match offset { + MemberOffset::Ubo(offset) => (&mut self.ubo, offset), + MemberOffset::PushConstant(offset) => (&mut self.push, offset), + }; + let size = value.len() * std::mem::size_of::(); + + Self::write_mat4_inner(&mut buffer[offset..][..size], value, ctx); + } + + pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C) { + let (buffer, offset) = match offset { + MemberOffset::Ubo(offset) => (&mut self.ubo, offset), + MemberOffset::PushConstant(offset) => (&mut self.push, offset), + }; + + Self::write_vec4_inner(&mut buffer[offset..][..16], value, ctx); + } + + pub fn bind_scalar(&mut self, offset: MemberOffset, value: T, ctx: C) + where H: BindUniform + { + let (buffer, offset) = match offset { + MemberOffset::Ubo(offset) => (&mut self.ubo, offset), + MemberOffset::PushConstant(offset) => (&mut self.push, offset), + }; + + Self::write_scalar_inner(&mut buffer[offset..][..4], value, ctx) + } +} \ No newline at end of file diff --git a/librashader-runtime-gl/src/binding.rs b/librashader-runtime-gl/src/binding.rs index eb08aa4..1ecd529 100644 --- a/librashader-runtime-gl/src/binding.rs +++ b/librashader-runtime-gl/src/binding.rs @@ -1,5 +1,6 @@ use gl::types::GLint; use librashader_reflect::reflect::semantics::BindingStage; +use librashader_reflect::reflect::uniforms::{BindUniform, UniformBuffer, UniformScalar}; #[derive(Debug)] pub enum VariableLocation { @@ -33,3 +34,79 @@ impl UniformLocation { validity } } + +pub(crate) type BufferStorage = UniformBuffer>; + + +pub trait GlUniformScalar: UniformScalar { + const FACTORY: unsafe fn(GLint, Self) -> (); +} + +impl GlUniformScalar for f32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1f; +} + +impl GlUniformScalar for i32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1i; +} + +impl GlUniformScalar for u32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1ui; +} + +pub(crate) struct GlUniformBinder; +impl BindUniform, T> for GlUniformBinder + where T: GlUniformScalar +{ + fn bind_uniform(value: T, location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + T::FACTORY(location.vertex, value); + } + if location.is_valid(BindingStage::FRAGMENT) { + T::FACTORY(location.fragment, value); + } + } + Some(()) + } else { + None + } + } +} + +impl BindUniform, &[f32; 4]> for GlUniformBinder { + fn bind_uniform(vec4: &[f32; 4], location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); + } + if location.is_valid(BindingStage::FRAGMENT) { + gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); + } + } + Some(()) + } else { + None + } + } +} + +impl BindUniform, &[f32; 16]> for GlUniformBinder { + fn bind_uniform(mat4: &[f32; 16], location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr()); + } + if location.is_valid(BindingStage::FRAGMENT) { + gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mat4.as_ptr()); + } + } + Some(()) + }else { + None + } + } +} \ No newline at end of file diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index e7c54fc..1203aa0 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -25,6 +25,7 @@ use librashader_reflect::front::shaderc::GlslangCompilation; use crate::options::{FilterChainOptions, FrameOptions}; use crate::samplers::SamplerSet; use crate::texture::Texture; +use crate::binding::BufferStorage; pub struct FilterChain { passes: Box<[FilterPass]>, @@ -435,24 +436,18 @@ impl FilterChain { None }; - let uniform_buffer = vec![ - 0; - reflection - .ubo - .as_ref() - .map(|ubo| ubo.size as usize) - .unwrap_or(0) - ] - .into_boxed_slice(); - let push_buffer = vec![ - 0; - reflection - .push_constant - .as_ref() - .map(|push| push.size as usize) - .unwrap_or(0) - ] - .into_boxed_slice(); + let uniform_storage = BufferStorage::new(reflection + .ubo + .as_ref() + .map(|ubo| ubo.size as usize) + .unwrap_or(0), + reflection + .push_constant + .as_ref() + .map(|push| push.size as usize) + .unwrap_or(0) + ); + let mut uniform_bindings = FxHashMap::default(); for param in reflection.meta.parameter_meta.values() { @@ -500,8 +495,7 @@ impl FilterChain { program, ubo_location, ubo_ring, - uniform_buffer, - push_buffer, + uniform_storage, uniform_bindings, source, config diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index 8c85ab0..a6366d2 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -8,8 +8,9 @@ use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; use rustc_hash::FxHashMap; +use librashader_reflect::reflect::uniforms::UniformBuffer; -use crate::binding::{UniformLocation, VariableLocation}; +use crate::binding::{BufferStorage, GlUniformBinder, UniformLocation, VariableLocation}; use crate::filter_chain::FilterCommon; use crate::framebuffer::Viewport; use crate::render_target::RenderTarget; @@ -17,111 +18,20 @@ use crate::samplers::SamplerSet; use crate::texture::Texture; use crate::util::{InlineRingBuffer, RingBuffer}; + pub struct FilterPass { pub reflection: ShaderReflection, pub compiled: ShaderCompilerOutput, pub program: GLuint, pub ubo_location: UniformLocation, pub ubo_ring: Option>, - pub uniform_buffer: Box<[u8]>, - pub push_buffer: Box<[u8]>, + pub(crate) uniform_storage: BufferStorage, pub uniform_bindings: FxHashMap, pub source: ShaderSource, pub config: ShaderPassConfig, } impl FilterPass { - 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.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { - unsafe { - if location.is_valid(BindingStage::VERTEX) { - gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); - } - if location.is_valid(BindingStage::FRAGMENT) { - gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); - } - } - } else { - let vec4 = bytemuck::cast_slice(&vec4); - buffer.copy_from_slice(vec4); - } - } - - #[inline(always)] - fn build_uniform( - location: UniformLocation, - buffer: &mut [u8], - value: T, - glfn: unsafe fn(GLint, T) -> (), - ) where - T: Copy, - T: bytemuck::Pod, - { - if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { - unsafe { - if location.is_valid(BindingStage::VERTEX) { - glfn(location.vertex, value); - } - if location.is_valid(BindingStage::FRAGMENT) { - glfn(location.fragment, value); - } - } - } else { - let buffer = bytemuck::cast_slice_mut(buffer); - buffer[0] = value; - } - } - - fn build_uint(location: UniformLocation, buffer: &mut [u8], value: u32) { - Self::build_uniform(location, buffer, value, gl::Uniform1ui) - } - - fn build_sint(location: UniformLocation, buffer: &mut [u8], value: i32) { - Self::build_uniform(location, buffer, value, gl::Uniform1i) - } - - fn build_float(location: UniformLocation, buffer: &mut [u8], value: f32) { - Self::build_uniform(location, buffer, value, gl::Uniform1f) - } - - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { - unsafe { - // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); - gl::ActiveTexture(gl::TEXTURE0 + binding.binding); - - gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); - gl::BindSampler(binding.binding, - samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)); - } - } - - pub fn get_format(&self) -> ShaderFormat { - let mut fb_format = ShaderFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ShaderFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ShaderFormat::R16G16B16A16Sfloat; - } - fb_format - } - // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) pub fn draw( &mut self, @@ -152,7 +62,6 @@ impl FilterPass { original, source, ); - // shader_gl3:1514 if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX @@ -167,7 +76,7 @@ impl FilterPass { gl::UNIFORM_BUFFER, 0, size as GLsizeiptr, - self.uniform_buffer.as_ptr().cast(), + self.uniform_storage.ubo.as_ptr().cast(), ); gl::BindBuffer(gl::UNIFORM_BUFFER, 0); @@ -211,6 +120,30 @@ impl FilterPass { } } + fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { + unsafe { + // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); + gl::ActiveTexture(gl::TEXTURE0 + binding.binding); + + gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); + gl::BindSampler(binding.binding, + samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)); + } + } +} + + +impl FilterPass { + pub fn get_format(&self) -> ShaderFormat { + let mut fb_format = ShaderFormat::R8G8B8A8Unorm; + if self.config.srgb_framebuffer { + fb_format = ShaderFormat::R8G8B8A8Srgb; + } else if self.config.float_framebuffer { + fb_format = ShaderFormat::R16G16B16A16Sfloat; + } + fb_format + } + // framecount should be pre-modded fn build_semantics( &mut self, @@ -228,12 +161,7 @@ impl FilterPass { if let Some((location, offset)) = self.uniform_bindings.get(&VariableSemantics::MVP.into()) { - let mvp_size = mvp.len() * std::mem::size_of::(); - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_mat4(location.location(), &mut buffer[offset..][..mvp_size], mvp) + self.uniform_storage.bind_mat4(*offset, mvp, location.location()); } // bind OutputSize @@ -241,12 +169,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::Output.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - - FilterPass::build_vec4(location.location(), &mut buffer[offset..][..16], fb_size) + self.uniform_storage.bind_vec4(*offset, fb_size, location.location()); } // bind FinalViewportSize @@ -254,15 +177,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FinalViewport.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - viewport.output.size, - ) + self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location()); } // bind FrameCount @@ -270,11 +185,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FrameCount.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count) + self.uniform_storage.bind_scalar(*offset, frame_count, location.location()); } // bind FrameDirection @@ -282,15 +193,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FrameDirection.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_sint( - location.location(), - &mut buffer[offset..][..4], - frame_direction, - ) + self.uniform_storage.bind_scalar(*offset, frame_direction, location.location()); } // bind Original sampler @@ -308,15 +211,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::Original.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - original.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,original.image.size, location.location()); } // bind Source sampler @@ -335,15 +231,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::Source.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - source.image.size, - ); + self.uniform_storage.bind_vec4(*offset, + source.image.size, location.location()); } if let Some(binding) = self @@ -358,15 +247,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::OriginalHistory.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - original.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,original.image.size, location.location()); } for (index, output) in parent.history_textures.iter().enumerate() { @@ -384,15 +266,8 @@ impl FilterPass { .semantics(index + 1) .into(), ) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - output.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,output.image.size, location.location()); } } @@ -411,15 +286,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::PassOutput.semantics(index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - output.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,output.image.size, location.location()); } } @@ -441,15 +309,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::PassFeedback.semantics(index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - feedback.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,feedback.image.size, location.location()); } } @@ -463,12 +324,6 @@ impl FilterPass { }) { let id = id.as_str(); - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - - // todo: cache parameters. // presets override params let default = self .source @@ -484,7 +339,8 @@ impl FilterPass { .get(id) .unwrap_or(&default); - FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value) + self.uniform_storage + .bind_scalar(*offset, value, location.location()); } // bind luts @@ -502,15 +358,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::User.semantics(*index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - lut.image.size, - ); + self.uniform_storage + .bind_vec4(*offset, lut.image.size, location.location()); } } } diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 669e0f7..fdfa43e 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -31,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", None) + FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None) .unwrap(); hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); } diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index f13db26..45b28a7 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -1,6 +1,9 @@ -use gl::types::{GLenum, GLuint}; +use gl::types::{GLenum, GLint, GLuint}; use librashader_common::Size; use librashader_reflect::back::cross::GlVersion; +use librashader_reflect::reflect::semantics::BindingStage; +use librashader_reflect::reflect::uniforms::{BindUniform, UniformBuffer, UniformScalar}; +use crate::binding::UniformLocation; pub fn calc_miplevel(size: Size) -> u32 { let mut size = std::cmp::max(size.width, size.height); @@ -126,4 +129,4 @@ pub fn gl_u16_to_version(version: u16) -> GlVersion { 460 => GlVersion::V4_60, _ => GlVersion::V1_50 } -} \ No newline at end of file +} diff --git a/librashader-runtime-gl46/src/binding.rs b/librashader-runtime-gl46/src/binding.rs index eb08aa4..1ecd529 100644 --- a/librashader-runtime-gl46/src/binding.rs +++ b/librashader-runtime-gl46/src/binding.rs @@ -1,5 +1,6 @@ use gl::types::GLint; use librashader_reflect::reflect::semantics::BindingStage; +use librashader_reflect::reflect::uniforms::{BindUniform, UniformBuffer, UniformScalar}; #[derive(Debug)] pub enum VariableLocation { @@ -33,3 +34,79 @@ impl UniformLocation { validity } } + +pub(crate) type BufferStorage = UniformBuffer>; + + +pub trait GlUniformScalar: UniformScalar { + const FACTORY: unsafe fn(GLint, Self) -> (); +} + +impl GlUniformScalar for f32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1f; +} + +impl GlUniformScalar for i32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1i; +} + +impl GlUniformScalar for u32 { + const FACTORY: unsafe fn(GLint, Self) -> () = gl::Uniform1ui; +} + +pub(crate) struct GlUniformBinder; +impl BindUniform, T> for GlUniformBinder + where T: GlUniformScalar +{ + fn bind_uniform(value: T, location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + T::FACTORY(location.vertex, value); + } + if location.is_valid(BindingStage::FRAGMENT) { + T::FACTORY(location.fragment, value); + } + } + Some(()) + } else { + None + } + } +} + +impl BindUniform, &[f32; 4]> for GlUniformBinder { + fn bind_uniform(vec4: &[f32; 4], location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); + } + if location.is_valid(BindingStage::FRAGMENT) { + gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); + } + } + Some(()) + } else { + None + } + } +} + +impl BindUniform, &[f32; 16]> for GlUniformBinder { + fn bind_uniform(mat4: &[f32; 16], location: UniformLocation) -> Option<()> { + if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { + unsafe { + if location.is_valid(BindingStage::VERTEX) { + gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr()); + } + if location.is_valid(BindingStage::FRAGMENT) { + gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mat4.as_ptr()); + } + } + Some(()) + }else { + None + } + } +} \ No newline at end of file diff --git a/librashader-runtime-gl46/src/filter_chain.rs b/librashader-runtime-gl46/src/filter_chain.rs index eac1648..a56cec7 100644 --- a/librashader-runtime-gl46/src/filter_chain.rs +++ b/librashader-runtime-gl46/src/filter_chain.rs @@ -1,4 +1,4 @@ -use crate::binding::{UniformLocation, VariableLocation}; +use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; use crate::filter_pass::FilterPass; use crate::framebuffer::{Framebuffer, GlImage, Viewport}; use crate::quad_render::DrawQuad; @@ -433,24 +433,17 @@ impl FilterChain { None }; - let uniform_buffer = vec![ - 0; - reflection - .ubo - .as_ref() - .map(|ubo| ubo.size as usize) - .unwrap_or(0) - ] - .into_boxed_slice(); - let push_buffer = vec![ - 0; - reflection - .push_constant - .as_ref() - .map(|push| push.size as usize) - .unwrap_or(0) - ] - .into_boxed_slice(); + let uniform_storage = BufferStorage::new(reflection + .ubo + .as_ref() + .map(|ubo| ubo.size as usize) + .unwrap_or(0), + reflection + .push_constant + .as_ref() + .map(|push| push.size as usize) + .unwrap_or(0) + ); let mut uniform_bindings = FxHashMap::default(); for param in reflection.meta.parameter_meta.values() { @@ -498,8 +491,7 @@ impl FilterChain { program, ubo_location, ubo_ring, - uniform_buffer, - push_buffer, + uniform_storage, uniform_bindings, source, config diff --git a/librashader-runtime-gl46/src/filter_pass.rs b/librashader-runtime-gl46/src/filter_pass.rs index 5dfdef5..7c3445d 100644 --- a/librashader-runtime-gl46/src/filter_pass.rs +++ b/librashader-runtime-gl46/src/filter_pass.rs @@ -9,7 +9,7 @@ use librashader_presets::ShaderPassConfig; use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; use rustc_hash::FxHashMap; -use crate::binding::{UniformLocation, VariableLocation}; +use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; use crate::filter_chain::FilterCommon; use crate::framebuffer::Viewport; use crate::render_target::RenderTarget; @@ -23,103 +23,13 @@ pub struct FilterPass { pub program: GLuint, pub ubo_location: UniformLocation, pub ubo_ring: Option>, - pub uniform_buffer: Box<[u8]>, - pub push_buffer: Box<[u8]>, + pub(crate) uniform_storage: BufferStorage, pub uniform_bindings: FxHashMap, pub source: ShaderSource, pub config: ShaderPassConfig, } impl FilterPass { - 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.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { - unsafe { - if location.is_valid(BindingStage::VERTEX) { - gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); - } - if location.is_valid(BindingStage::FRAGMENT) { - gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); - } - } - } else { - let vec4 = bytemuck::cast_slice(&vec4); - buffer.copy_from_slice(vec4); - } - } - - #[inline(always)] - fn build_uniform( - location: UniformLocation, - buffer: &mut [u8], - value: T, - glfn: unsafe fn(GLint, T) -> (), - ) where - T: Copy, - T: bytemuck::Pod, - { - if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) { - unsafe { - if location.is_valid(BindingStage::VERTEX) { - glfn(location.vertex, value); - } - if location.is_valid(BindingStage::FRAGMENT) { - glfn(location.fragment, value); - } - } - } else { - let buffer = bytemuck::cast_slice_mut(buffer); - buffer[0] = value; - } - } - - fn build_uint(location: UniformLocation, buffer: &mut [u8], value: u32) { - Self::build_uniform(location, buffer, value, gl::Uniform1ui) - } - - fn build_sint(location: UniformLocation, buffer: &mut [u8], value: i32) { - Self::build_uniform(location, buffer, value, gl::Uniform1i) - } - - fn build_float(location: UniformLocation, buffer: &mut [u8], value: f32) { - Self::build_uniform(location, buffer, value, gl::Uniform1f) - } - - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { - unsafe { - // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); - gl::BindTextureUnit(binding.binding, texture.image.handle); - gl::BindSampler(binding.binding, - samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)); - } - } - - pub fn get_format(&self) -> ShaderFormat { - let mut fb_format = ShaderFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ShaderFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ShaderFormat::R16G16B16A16Sfloat; - } - fb_format - } - // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) pub fn draw( &mut self, @@ -135,7 +45,6 @@ impl FilterPass { let framebuffer = output.framebuffer; unsafe { - // gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle); gl::UseProgram(self.program); } @@ -150,7 +59,6 @@ impl FilterPass { original, source, ); - // shader_gl3:1514 if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX @@ -164,7 +72,7 @@ impl FilterPass { *buffer, 0, size as GLsizeiptr, - self.uniform_buffer.as_ptr().cast(), + self.uniform_storage.ubo.as_ptr().cast(), ); if self.ubo_location.vertex != gl::INVALID_INDEX { @@ -205,6 +113,27 @@ impl FilterPass { } } + fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { + unsafe { + // eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding); + gl::BindTextureUnit(binding.binding, texture.image.handle); + gl::BindSampler(binding.binding, + samplers.get(texture.wrap_mode, texture.filter, texture.mip_filter)); + } + } +} + +impl FilterPass { + pub fn get_format(&self) -> ShaderFormat { + let mut fb_format = ShaderFormat::R8G8B8A8Unorm; + if self.config.srgb_framebuffer { + fb_format = ShaderFormat::R8G8B8A8Srgb; + } else if self.config.float_framebuffer { + fb_format = ShaderFormat::R16G16B16A16Sfloat; + } + fb_format + } + // framecount should be pre-modded fn build_semantics( &mut self, @@ -222,12 +151,7 @@ impl FilterPass { if let Some((location, offset)) = self.uniform_bindings.get(&VariableSemantics::MVP.into()) { - let mvp_size = mvp.len() * std::mem::size_of::(); - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_mat4(location.location(), &mut buffer[offset..][..mvp_size], mvp) + self.uniform_storage.bind_mat4(*offset, mvp, location.location()); } // bind OutputSize @@ -235,12 +159,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::Output.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - - FilterPass::build_vec4(location.location(), &mut buffer[offset..][..16], fb_size) + self.uniform_storage.bind_vec4(*offset, fb_size, location.location()); } // bind FinalViewportSize @@ -248,15 +167,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FinalViewport.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - viewport.output.size, - ) + self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location()); } // bind FrameCount @@ -264,11 +175,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FrameCount.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count) + self.uniform_storage.bind_scalar(*offset, frame_count, location.location()); } // bind FrameDirection @@ -276,15 +183,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FrameDirection.into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_sint( - location.location(), - &mut buffer[offset..][..4], - frame_direction, - ) + self.uniform_storage.bind_scalar(*offset, frame_direction, location.location()); } // bind Original sampler @@ -302,15 +201,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::Original.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - original.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,original.image.size, location.location()); } // bind Source sampler @@ -329,15 +221,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::Source.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - source.image.size, - ); + self.uniform_storage.bind_vec4(*offset, + source.image.size, location.location()); } if let Some(binding) = self @@ -352,15 +237,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::OriginalHistory.semantics(0).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - original.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,original.image.size, location.location()); } for (index, output) in parent.history_textures.iter().enumerate() { @@ -378,15 +256,8 @@ impl FilterPass { .semantics(index + 1) .into(), ) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - output.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,output.image.size, location.location()); } } @@ -405,15 +276,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::PassOutput.semantics(index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - output.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,output.image.size, location.location()); } } @@ -435,15 +299,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::PassFeedback.semantics(index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - feedback.image.size, - ); + self.uniform_storage + .bind_vec4(*offset,feedback.image.size, location.location()); } } @@ -457,12 +314,6 @@ impl FilterPass { }) { let id = id.as_str(); - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - - // todo: cache parameters. // presets override params let default = self .source @@ -478,7 +329,8 @@ impl FilterPass { .get(id) .unwrap_or(&default); - FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value) + self.uniform_storage + .bind_scalar(*offset, value, location.location()); } // bind luts @@ -496,15 +348,8 @@ impl FilterPass { .uniform_bindings .get(&TextureSemantics::User.semantics(*index).into()) { - let (buffer, offset) = match offset { - MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), - MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), - }; - FilterPass::build_vec4( - location.location(), - &mut buffer[offset..][..16], - lut.image.size, - ); + self.uniform_storage + .bind_vec4(*offset, lut.image.size, location.location()); } } }