diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index fbf866b..3dd4ed4 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -1,8 +1,6 @@ use crate::binding::{UniformLocation, VariableLocation}; use crate::filter_pass::FilterPass; -use crate::framebuffer::{GlImage, Viewport}; -use crate::gl::gl3::Gl3Framebuffer; -use crate::gl::gl3::{Gl3DrawQuad, Gl3LutLoad, Gl3UboRing}; +use crate::framebuffer::{GLImage, Viewport}; use crate::render_target::RenderTarget; use crate::util; use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer}; @@ -27,15 +25,15 @@ use crate::options::{FilterChainOptions, FrameOptions}; use crate::samplers::SamplerSet; use crate::texture::Texture; use crate::binding::BufferStorage; -use crate::gl::{DrawQuad, Framebuffer, LoadLut, UboRing}; +use crate::gl::{DrawQuad, Framebuffer, GLInterface, LoadLut, UboRing}; -pub struct FilterChain { - passes: Box<[FilterPass]>, +pub struct FilterChain { + passes: Box<[FilterPass]>, common: FilterCommon, - pub(crate) draw_quad: Gl3DrawQuad, - output_framebuffers: Box<[Gl3Framebuffer]>, - feedback_framebuffers: Box<[Gl3Framebuffer]>, - history_framebuffers: VecDeque, + pub(crate) draw_quad: T::DrawQuad, + output_framebuffers: Box<[T::Framebuffer]>, + feedback_framebuffers: Box<[T::Framebuffer]>, + history_framebuffers: VecDeque, } pub struct FilterCommon { @@ -53,7 +51,7 @@ pub struct FilterMutable { pub(crate) parameters: FxHashMap } -impl FilterChain { +impl FilterChain { fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation { // todo: support both ubo and pushco // todo: fix this. @@ -90,16 +88,16 @@ type ShaderPassMeta = ( >, ); -impl FilterChain { +impl FilterChain { /// Load a filter chain from a pre-parsed `ShaderPreset`. - pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result { - let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?; + pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result { + let (passes, semantics) = Self::load_preset(preset.shaders, &preset.textures)?; 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(version, passes, &semantics)?; + let filters = Self::init_passes(version, passes, &semantics)?; let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); let default_wrap = filters @@ -111,24 +109,24 @@ impl FilterChain { // initialize output framebuffers let mut output_framebuffers = Vec::new(); - output_framebuffers.resize_with(filters.len(), || Gl3Framebuffer::new(1)); + output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); let mut output_textures = Vec::new(); output_textures.resize_with(filters.len(), Texture::default); // initialize feedback framebuffers let mut feedback_framebuffers = Vec::new(); - feedback_framebuffers.resize_with(filters.len(), || Gl3Framebuffer::new(1)); + feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); let mut feedback_textures = Vec::new(); feedback_textures.resize_with(filters.len(), Texture::default); // load luts - let luts = Gl3LutLoad::load_luts(&preset.textures)?; + let luts = T::LoadLut::load_luts(&preset.textures)?; let (history_framebuffers, history_textures) = FilterChain::init_history(&filters, default_filter, default_wrap); // create vertex objects - let draw_quad = Gl3DrawQuad::new(); + let draw_quad = T::DrawQuad::new(); Ok(FilterChain { passes: filters, @@ -152,7 +150,7 @@ impl FilterChain { } /// Load the shader preset at the given path into a filter chain. - pub fn load_from_path(path: impl AsRef, options: Option<&FilterChainOptions>) -> 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, options) @@ -213,7 +211,7 @@ impl FilterChain { version: GlVersion, passes: Vec, semantics: &ReflectSemantics, - ) -> Result> { + ) -> Result]>> { let mut filters = Vec::new(); // initialize passes @@ -281,7 +279,7 @@ impl FilterChain { }; let ubo_ring = if let Some(ubo) = &reflection.ubo { - let ring = Gl3UboRing::new(ubo.size); + let ring = UboRing::new(ubo.size); Some(ring) } else { None @@ -305,7 +303,7 @@ impl FilterChain { uniform_bindings.insert( UniformBinding::Parameter(param.id.clone()), ( - FilterChain::reflect_uniform_location(program, param), + Self::reflect_uniform_location(program, param), param.offset, ), ); @@ -315,7 +313,7 @@ impl FilterChain { uniform_bindings.insert( UniformBinding::SemanticVariable(*semantics), ( - FilterChain::reflect_uniform_location(program, param), + Self::reflect_uniform_location(program, param), param.offset, ), ); @@ -325,7 +323,7 @@ impl FilterChain { uniform_bindings.insert( UniformBinding::TextureSize(*semantics), ( - FilterChain::reflect_uniform_location(program, param), + Self::reflect_uniform_location(program, param), param.offset, ), ); @@ -357,10 +355,10 @@ impl FilterChain { } fn init_history( - filters: &[FilterPass], + filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode, - ) -> (VecDeque, Box<[Texture]>) { + ) -> (VecDeque, Box<[Texture]>) { let mut required_images = 0; for pass in filters { @@ -394,7 +392,7 @@ impl FilterChain { eprintln!("[history] using frame history with {required_images} images"); let mut framebuffers = VecDeque::with_capacity(required_images); - framebuffers.resize_with(required_images, || Gl3Framebuffer::new(1)); + framebuffers.resize_with(required_images, || Framebuffer::new(1)); let mut history_textures = Vec::new(); history_textures.resize_with(required_images, || Texture { @@ -407,9 +405,9 @@ impl FilterChain { (framebuffers, history_textures.into_boxed_slice()) } - fn push_history(&mut self, input: &GlImage) -> Result<()> { + fn push_history(&mut self, input: &GLImage) -> Result<()> { if let Some(mut back) = self.history_framebuffers.pop_back() { - if back.size != input.size || (input.format != 0 && input.format != back.format) { + if back.size() != input.size || (input.format != 0 && input.format != back.format()) { eprintln!("[history] resizing"); back.init(input.size, input.format)?; } @@ -425,7 +423,7 @@ 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, options: Option<&FrameOptions>) -> Result<()> { + pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GLImage, options: Option<&FrameOptions>) -> Result<()> { // limit number of passes to those enabled. let passes = &mut self.passes[0..self.common.config.passes_enabled]; if let Some(options) = options { diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index eedbca9..a2ee870 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -14,27 +14,26 @@ use librashader_runtime::uniforms::UniformStorage; use crate::binding::{BufferStorage, GlUniformBinder, UniformLocation, VariableLocation}; use crate::filter_chain::FilterCommon; use crate::framebuffer::Viewport; -use crate::gl::gl3::{Gl3BindTexture, Gl3UboRing}; -use crate::gl::{BindTexture, Framebuffer, UboRing}; +use crate::gl::{BindTexture, Framebuffer, GLInterface, UboRing}; use crate::render_target::RenderTarget; use crate::samplers::SamplerSet; use crate::texture::Texture; use crate::util::{InlineRingBuffer, RingBuffer}; -pub struct FilterPass { +pub struct FilterPass { pub reflection: ShaderReflection, pub compiled: ShaderCompilerOutput, pub program: GLuint, pub ubo_location: UniformLocation, - pub ubo_ring: Option>, + pub ubo_ring: Option, pub(crate) uniform_storage: BufferStorage, pub uniform_bindings: FxHashMap, pub source: ShaderSource, pub config: ShaderPassConfig, } -impl FilterPass { +impl FilterPass { // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) pub(crate) fn draw( &mut self, @@ -42,15 +41,15 @@ impl FilterPass { parent: &FilterCommon, frame_count: u32, frame_direction: i32, - viewport: &Viewport, + viewport: &Viewport, original: &Texture, source: &Texture, - output: RenderTarget + output: RenderTarget ) { let framebuffer = output.framebuffer; unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle); + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle()); gl::UseProgram(self.program); } @@ -60,7 +59,7 @@ impl FilterPass { output.mvp, frame_count, frame_direction, - framebuffer.size, + framebuffer.size(), viewport, original, source, @@ -78,14 +77,15 @@ impl FilterPass { // can't use framebuffer.clear because it will unbind. framebuffer.clear::(); + let framebuffer_size = framebuffer.size(); gl::Viewport( output.x, output.y, - framebuffer.size.width as GLsizei, - framebuffer.size.height as GLsizei, + framebuffer_size.width as GLsizei, + framebuffer_size.height as GLsizei, ); - if framebuffer.format == gl::SRGB8_ALPHA8 { + if framebuffer.format() == gl::SRGB8_ALPHA8 { gl::Enable(gl::FRAMEBUFFER_SRGB); } else { gl::Disable(gl::FRAMEBUFFER_SRGB); @@ -100,14 +100,10 @@ impl FilterPass { gl::BindFramebuffer(gl::FRAMEBUFFER, 0); } } - - fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture) { - Gl3BindTexture::bind_texture(samplers, binding, texture) - } } -impl FilterPass { +impl FilterPass { pub fn get_format(&self) -> ImageFormat { let mut fb_format = ImageFormat::R8G8B8A8Unorm; if self.config.srgb_framebuffer { @@ -127,7 +123,7 @@ impl FilterPass { frame_count: u32, frame_direction: i32, fb_size: Size, - viewport: &Viewport, + viewport: &Viewport, original: &Texture, source: &Texture, ) { @@ -151,7 +147,7 @@ impl FilterPass { .uniform_bindings .get(&VariableSemantics::FinalViewport.into()) { - self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location()); + self.uniform_storage.bind_vec4(*offset,viewport.output.size(), location.location()); } // bind FrameCount @@ -177,7 +173,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::Original.semantics(0)) { - Self::bind_texture(&parent.samplers, binding, original); + T::BindTexture::bind_texture(&parent.samplers, binding, original); } // bind OriginalSize @@ -197,7 +193,7 @@ impl FilterPass { .get(&TextureSemantics::Source.semantics(0)) { // eprintln!("setting source binding to {}", binding.binding); - Self::bind_texture(&parent.samplers, binding, source); + T::BindTexture::bind_texture(&parent.samplers, binding, source); } // bind SourceSize @@ -215,7 +211,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::OriginalHistory.semantics(0)) { - Self::bind_texture(&parent.samplers, binding, original); + T::BindTexture::bind_texture(&parent.samplers, binding, original); } if let Some((location, offset)) = self .uniform_bindings @@ -235,7 +231,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::OriginalHistory.semantics(index + 1)) { - Self::bind_texture(&parent.samplers, binding, output); + T::BindTexture::bind_texture(&parent.samplers, binding, output); } if let Some((location, offset)) = self.uniform_bindings.get( @@ -259,7 +255,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::PassOutput.semantics(index)) { - Self::bind_texture(&parent.samplers, binding, output); + T::BindTexture::bind_texture(&parent.samplers, binding, output); } if let Some((location, offset)) = self @@ -282,10 +278,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::PassFeedback.semantics(index)) { - if feedback.image.handle == 0 { - eprintln!("[WARNING] trying to bind PassFeedback: {index} which has texture 0 to slot {} in pass {pass_index}", binding.binding) - } - Self::bind_texture(&parent.samplers, binding, feedback); + T::BindTexture::bind_texture(&parent.samplers, binding, feedback); } if let Some((location, offset)) = self @@ -334,7 +327,7 @@ impl FilterPass { .texture_meta .get(&TextureSemantics::User.semantics(*index)) { - Self::bind_texture(&parent.samplers, binding, lut); + T::BindTexture::bind_texture(&parent.samplers, binding, lut); } if let Some((location, offset)) = self diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs index 7a4bef5..91dc0d7 100644 --- a/librashader-runtime-gl/src/framebuffer.rs +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -6,18 +6,17 @@ use librashader_presets::{Scale2D, ScaleType, Scaling}; use crate::error::FilterChainError; use crate::error::Result; use crate::gl::Framebuffer; -use crate::gl::gl3::Gl3Framebuffer; #[derive(Debug, Copy, Clone)] -pub struct Viewport<'a> { +pub struct Viewport<'a, T: Framebuffer + ?Sized> { pub x: i32, pub y: i32, - pub output: &'a Gl3Framebuffer, + pub output: &'a T, pub mvp: Option<&'a [f32; 16]>, } #[derive(Default, Debug, Copy, Clone)] -pub struct GlImage { +pub struct GLImage { pub handle: GLuint, pub format: GLenum, pub size: Size, diff --git a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs index 9ed1ef1..b7a7804 100644 --- a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs @@ -1,24 +1,39 @@ use gl::types::{GLenum, GLint, GLsizei, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; -use crate::{GlImage, Viewport}; +use crate::framebuffer::{GLImage, Viewport}; use crate::error::{FilterChainError, Result}; use crate::gl::Framebuffer; use crate::texture::Texture; #[derive(Debug)] pub struct Gl3Framebuffer { - pub image: GLuint, - pub handle: GLuint, - pub size: Size, - pub format: GLenum, - pub max_levels: u32, - pub mip_levels: u32, + image: GLuint, + handle: GLuint, + size: Size, + format: GLenum, + max_levels: u32, + mip_levels: u32, is_raw: bool, } - impl Framebuffer for Gl3Framebuffer { + fn handle(&self) -> GLuint { + self.handle + } + + fn size(&self) -> Size { + self.size + } + + fn image(&self) -> GLuint { + self.image + } + + fn format(&self) -> GLenum { + self.format + } + fn new(max_levels: u32) -> Gl3Framebuffer { let mut framebuffer = 0; unsafe { @@ -59,7 +74,7 @@ impl Framebuffer for Gl3Framebuffer { } fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture { Texture { - image: GlImage { + image: GLImage { handle: self.image, format: self.format, size: self.size, @@ -74,7 +89,7 @@ impl Framebuffer for Gl3Framebuffer { &mut self, scaling: Scale2D, format: ImageFormat, - viewport: &Viewport, + viewport: &Viewport, _original: &Texture, source: &Texture, ) -> Result> { @@ -111,7 +126,7 @@ impl Framebuffer for Gl3Framebuffer { } } } - fn copy_from(&mut self, image: &GlImage) -> Result<()> { + fn copy_from(&mut self, image: &GLImage) -> Result<()> { // todo: may want to use a shader and draw a quad to be faster. if image.size != self.size || image.format != self.format { self.init(image.size, image.format)?; diff --git a/librashader-runtime-gl/src/gl3_hello_triangle.rs b/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs similarity index 98% rename from librashader-runtime-gl/src/gl3_hello_triangle.rs rename to librashader-runtime-gl/src/gl/gl3/hello_triangle.rs index 3041127..942916c 100644 --- a/librashader-runtime-gl/src/gl3_hello_triangle.rs +++ b/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs @@ -8,9 +8,9 @@ use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint}; use librashader_common::Size; use crate::filter_chain::FilterChain; -use crate::framebuffer::{GlImage, Viewport}; -use crate::gl::Framebuffer; -use crate::gl::gl3::Gl3Framebuffer; +use crate::framebuffer::{GLImage, Viewport}; +use crate::gl::{Framebuffer, GLInterface}; +use crate::gl::gl3::CompatibilityGL; const WIDTH: u32 = 900; const HEIGHT: u32 = 700; @@ -267,7 +267,7 @@ pub fn do_loop( events: Receiver<(f64, WindowEvent)>, triangle_program: GLuint, triangle_vao: GLuint, - filter: &mut FilterChain, + filter: &mut FilterChain, ) { let mut framecount = 0; let mut rendered_framebuffer = 0; @@ -464,7 +464,7 @@ void main() let (fb_width, fb_height) = window.get_framebuffer_size(); let (vp_width, vp_height) = window.get_size(); - let output = Gl3Framebuffer::new_from_raw( + let output = ::Framebuffer::new_from_raw( output_texture, output_framebuffer_handle, gl::RGBA8, @@ -509,7 +509,7 @@ void main() mvp: None, }; - let rendered = GlImage { + let rendered = GLImage { handle: rendered_texture, format: gl::RGBA8, size: Size { diff --git a/librashader-runtime-gl/src/gl/gl3/lut_load.rs b/librashader-runtime-gl/src/gl/gl3/lut_load.rs index 369890c..fff61cf 100644 --- a/librashader-runtime-gl/src/gl/gl3/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl3/lut_load.rs @@ -4,7 +4,7 @@ use librashader_common::image::Image; use librashader_common::Size; use librashader_presets::TextureConfig; use crate::gl::LoadLut; -use crate::{GlImage, util}; +use crate::framebuffer::{GLImage, Viewport}; use crate::texture::Texture; use crate::error::Result; @@ -64,7 +64,7 @@ impl LoadLut for Gl3LutLoad { luts.insert( index, Texture { - image: GlImage { + image: GLImage { handle, format: gl::RGBA8, size: image.size, diff --git a/librashader-runtime-gl/src/gl/gl3/mod.rs b/librashader-runtime-gl/src/gl/gl3/mod.rs index 34b59ec..0fa00cc 100644 --- a/librashader-runtime-gl/src/gl/gl3/mod.rs +++ b/librashader-runtime-gl/src/gl/gl3/mod.rs @@ -3,9 +3,21 @@ mod draw_quad; mod ubo_ring; mod framebuffer; mod texture_bind; +#[cfg(test)] +pub mod hello_triangle; -pub use lut_load::*; -pub use draw_quad::*; -pub use ubo_ring::*; -pub use framebuffer::*; -pub use texture_bind::*; \ No newline at end of file +use lut_load::*; +use draw_quad::*; +use ubo_ring::*; +use framebuffer::*; +use texture_bind::*; +use crate::gl::GLInterface; + +pub struct CompatibilityGL; +impl GLInterface for CompatibilityGL { + type Framebuffer = Gl3Framebuffer; + type UboRing = Gl3UboRing<16>; + type DrawQuad = Gl3DrawQuad; + type LoadLut = Gl3LutLoad; + type BindTexture = Gl3BindTexture; +} diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index 6c88bb7..8896535 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -1,30 +1,44 @@ use gl::types::{GLenum, GLint, GLsizei, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; -use crate::{GlImage, Viewport}; +use crate::framebuffer::{GLImage, Viewport}; use crate::error::{FilterChainError, Result}; use crate::gl::Framebuffer; use crate::texture::Texture; #[derive(Debug)] pub struct Gl46Framebuffer { - pub image: GLuint, - pub handle: GLuint, - pub size: Size, - pub format: GLenum, - pub max_levels: u32, - pub mip_levels: u32, + image: GLuint, + handle: GLuint, + size: Size, + format: GLenum, + max_levels: u32, + levels: u32, is_raw: bool, } impl Framebuffer for Gl46Framebuffer { + fn handle(&self) -> GLuint { + self.handle + } + + fn size(&self) -> Size { + self.size + } + + fn image(&self) -> GLuint { + self.image + } + + fn format(&self) -> GLenum { + self.format + } + fn new(max_levels: u32) -> Gl46Framebuffer { let mut framebuffer = 0; unsafe { - gl::GenFramebuffers(1, &mut framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl::CreateFramebuffers(1, &mut framebuffer); } Gl46Framebuffer { @@ -35,7 +49,7 @@ impl Framebuffer for Gl46Framebuffer { }, format: 0, max_levels, - mip_levels: 0, + levels: 0, handle: framebuffer, is_raw: false, } @@ -52,14 +66,14 @@ impl Framebuffer for Gl46Framebuffer { size, format, max_levels: miplevels, - mip_levels: miplevels, + levels: miplevels, handle, is_raw: true, } } fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture { Texture { - image: GlImage { + image: GLImage { handle: self.image, format: self.format, size: self.size, @@ -74,7 +88,7 @@ impl Framebuffer for Gl46Framebuffer { &mut self, scaling: Scale2D, format: ImageFormat, - viewport: &Viewport, + viewport: &Viewport, _original: &Texture, source: &Texture, ) -> Result> { @@ -100,83 +114,27 @@ impl Framebuffer for Gl46Framebuffer { } fn clear(&self) { unsafe { - if REBIND { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); - } - gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); - gl::ClearColor(0.0, 0.0, 0.0, 0.0); - gl::Clear(gl::COLOR_BUFFER_BIT); - if REBIND { - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - } + gl::ClearNamedFramebufferfv(self.handle, + gl::COLOR, 0, + [0.0f32, 0.0, 0.0, 0.0].as_ptr().cast()); } } - fn copy_from(&mut self, image: &GlImage) -> Result<()> { + fn copy_from(&mut self, image: &GLImage) -> Result<()> { // todo: may want to use a shader and draw a quad to be faster. if image.size != self.size || image.format != self.format { self.init(image.size, image.format)?; } unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); + // gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); + gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0); + gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); - gl::FramebufferTexture2D( - gl::READ_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - image.handle, - 0, - ); + gl::BlitNamedFramebuffer(image.handle, self.handle, + 0, 0, image.size.width as GLint, image.size.height as GLint, + 0, 0, self.size.width as GLint, self.size.height as GLint, + gl::COLOR_BUFFER_BIT, gl::NEAREST); - gl::FramebufferTexture2D( - gl::DRAW_FRAMEBUFFER, - gl::COLOR_ATTACHMENT1, - gl::TEXTURE_2D, - self.image, - 0, - ); - gl::ReadBuffer(gl::COLOR_ATTACHMENT0); - gl::DrawBuffer(gl::COLOR_ATTACHMENT1); - gl::BlitFramebuffer( - 0, - 0, - self.size.width as GLint, - self.size.height as GLint, - 0, - 0, - self.size.width as GLint, - self.size.height as GLint, - gl::COLOR_BUFFER_BIT, - gl::NEAREST, - ); - - // cleanup after ourselves. - gl::FramebufferTexture2D( - gl::READ_FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - 0, - 0, - ); - - gl::FramebufferTexture2D( - gl::DRAW_FRAMEBUFFER, - gl::COLOR_ATTACHMENT1, - gl::TEXTURE_2D, - 0, - 0, - ); - - // set this back to color_attachment 0 - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, - self.image, - 0, - ); - - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); } Ok(()) @@ -189,22 +147,18 @@ impl Framebuffer for Gl46Framebuffer { self.size = size; unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); - // reset the framebuffer image if self.image != 0 { - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, + gl::NamedFramebufferTexture( + self.handle, gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, 0, 0, ); gl::DeleteTextures(1, &self.image); } - gl::GenTextures(1, &mut self.image); - gl::BindTexture(gl::TEXTURE_2D, self.image); + gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image); if size.width == 0 { size.width = 1; @@ -213,26 +167,25 @@ impl Framebuffer for Gl46Framebuffer { size.height = 1; } - self.mip_levels = librashader_runtime::scaling::calc_miplevel(size); - if self.mip_levels > self.max_levels { - self.mip_levels = self.max_levels; + self.levels = librashader_runtime::scaling::calc_miplevel(size); + if self.levels > self.max_levels { + self.levels = self.max_levels; } - if self.mip_levels == 0 { - self.mip_levels = 1; + if self.levels == 0 { + self.levels = 1; } - gl::TexStorage2D( - gl::TEXTURE_2D, - self.mip_levels as GLsizei, + gl::TextureStorage2D( + self.image, + self.levels as GLsizei, self.format, size.width as GLsizei, size.height as GLsizei, ); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, + gl::NamedFramebufferTexture( + self.handle, gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, self.image, 0, ); @@ -243,36 +196,33 @@ impl Framebuffer for Gl46Framebuffer { gl::FRAMEBUFFER_UNSUPPORTED => { eprintln!("unsupported fbo"); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, + gl::NamedFramebufferTexture( + self.handle, gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, 0, 0, ); gl::DeleteTextures(1, &self.image); - gl::GenTextures(1, &mut self.image); - gl::BindTexture(gl::TEXTURE_2D, self.image); + gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image); - self.mip_levels = librashader_runtime::scaling::calc_miplevel(size); - if self.mip_levels > self.max_levels { - self.mip_levels = self.max_levels; + self.levels = librashader_runtime::scaling::calc_miplevel(size); + if self.levels > self.max_levels { + self.levels = self.max_levels; } - if self.mip_levels == 0 { - self.mip_levels = 1; + if self.levels == 0 { + self.levels = 1; } - gl::TexStorage2D( - gl::TEXTURE_2D, - self.mip_levels as GLsizei, + gl::TextureStorage2D( + self.image, + self.levels as GLsizei, ImageFormat::R8G8B8A8Unorm.into(), size.width as GLsizei, size.height as GLsizei, ); - gl::FramebufferTexture2D( - gl::FRAMEBUFFER, + gl::NamedFramebufferTexture( + self.handle, gl::COLOR_ATTACHMENT0, - gl::TEXTURE_2D, self.image, 0, ); @@ -282,11 +232,7 @@ impl Framebuffer for Gl46Framebuffer { _ => return Err(FilterChainError::FramebufferInit(status)) } } - - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::BindTexture(gl::TEXTURE_2D, 0); } - Ok(()) } } diff --git a/librashader-runtime-gl46/src/hello_triangle.rs b/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs similarity index 98% rename from librashader-runtime-gl46/src/hello_triangle.rs rename to librashader-runtime-gl/src/gl/gl46/hello_triangle.rs index 7b475ff..b2b9265 100644 --- a/librashader-runtime-gl46/src/hello_triangle.rs +++ b/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs @@ -8,7 +8,9 @@ use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint}; use librashader_common::Size; use crate::filter_chain::FilterChain; -use crate::framebuffer::{Framebuffer, GlImage, Viewport}; +use crate::framebuffer::{GLImage, Viewport}; +use crate::gl::{Framebuffer, GLInterface}; +use crate::gl::gl46::DirectStateAccessGL; const WIDTH: u32 = 900; const HEIGHT: u32 = 700; @@ -256,7 +258,7 @@ pub fn do_loop( events: Receiver<(f64, WindowEvent)>, triangle_program: GLuint, triangle_vao: GLuint, - filter: &mut FilterChain, + filter: &mut FilterChain, ) { let mut framecount = 0; let mut rendered_framebuffer = 0; @@ -445,7 +447,7 @@ void main() let (fb_width, fb_height) = window.get_framebuffer_size(); let (vp_width, vp_height) = window.get_size(); - let output = Framebuffer::new_from_raw( + let output = ::Framebuffer::new_from_raw( output_texture, output_framebuffer_handle, gl::RGBA8, @@ -488,7 +490,7 @@ void main() mvp: None, }; - let rendered = GlImage { + let rendered = GLImage { handle: rendered_texture, format: gl::RGBA8, size: Size { diff --git a/librashader-runtime-gl/src/gl/gl46/lut_load.rs b/librashader-runtime-gl/src/gl/gl46/lut_load.rs index 5911503..8d0705a 100644 --- a/librashader-runtime-gl/src/gl/gl46/lut_load.rs +++ b/librashader-runtime-gl/src/gl/gl46/lut_load.rs @@ -4,7 +4,7 @@ use librashader_common::image::Image; use librashader_common::Size; use librashader_presets::TextureConfig; use crate::gl::LoadLut; -use crate::{GlImage, util}; +use crate::framebuffer::{GLImage, Viewport}; use crate::texture::Texture; use crate::error::Result; @@ -64,7 +64,7 @@ impl LoadLut for Gl46LutLoad { luts.insert( index, Texture { - image: GlImage { + image: GLImage { handle, format: gl::RGBA8, size: image.size, diff --git a/librashader-runtime-gl/src/gl/gl46/mod.rs b/librashader-runtime-gl/src/gl/gl46/mod.rs index 34b59ec..ca97958 100644 --- a/librashader-runtime-gl/src/gl/gl46/mod.rs +++ b/librashader-runtime-gl/src/gl/gl46/mod.rs @@ -4,8 +4,21 @@ mod ubo_ring; mod framebuffer; mod texture_bind; -pub use lut_load::*; -pub use draw_quad::*; -pub use ubo_ring::*; -pub use framebuffer::*; -pub use texture_bind::*; \ No newline at end of file +#[cfg(test)] +pub mod hello_triangle; + +use lut_load::*; +use draw_quad::*; +use ubo_ring::*; +use framebuffer::*; +use texture_bind::*; +use crate::gl::GLInterface; + +pub struct DirectStateAccessGL; +impl GLInterface for DirectStateAccessGL { + type Framebuffer = Gl46Framebuffer; + type UboRing = Gl46UboRing<16>; + type DrawQuad = Gl46DrawQuad; + type LoadLut = Gl46LutLoad; + type BindTexture = Gl46BindTexture; +} \ No newline at end of file diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index 5712bd9..3fcd7cd 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -1,5 +1,5 @@ pub(crate) mod gl3; -mod gl46; +pub(crate) mod gl46; use gl::types::{GLenum, GLint, GLsizei, GLuint}; use rustc_hash::FxHashMap; @@ -10,7 +10,7 @@ use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess}; use crate::binding::UniformLocation; use crate::texture::Texture; use crate::error::{FilterChainError, Result}; -use crate::{GlImage, Viewport}; +use crate::framebuffer::{GLImage, Viewport}; use crate::samplers::SamplerSet; pub trait LoadLut { @@ -42,15 +42,27 @@ pub trait Framebuffer { &mut self, scaling: Scale2D, format: ImageFormat, - viewport: &Viewport, + viewport: &Viewport, _original: &Texture, source: &Texture, ) -> Result>; fn clear(&self); - fn copy_from(&mut self, image: &GlImage) -> Result<()>; + fn copy_from(&mut self, image: &GLImage) -> Result<()>; fn init(&mut self, size: Size, format: impl Into) -> Result<()>; + fn handle(&self) -> GLuint; + fn image(&self) -> GLuint; + fn size(&self) -> Size; + fn format(&self) -> GLenum; } pub trait BindTexture { fn bind_texture(samplers: &SamplerSet, binding: &TextureBinding, texture: &Texture); +} + +pub trait GLInterface { + type Framebuffer: Framebuffer; + type UboRing: UboRing<16>; + type DrawQuad: DrawQuad; + type LoadLut: LoadLut; + type BindTexture: BindTexture; } \ No newline at end of file diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 3b1d76f..6a379a8 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -7,19 +7,28 @@ mod filter_pass; mod framebuffer; mod render_target; mod util; -pub mod error; mod samplers; +mod texture; +pub mod options; +mod gl; + +pub mod error; pub use filter_chain::FilterChain; -pub use framebuffer::GlImage; pub use framebuffer::Viewport; -#[cfg(test)] -mod gl3_hello_triangle; -mod texture; -mod options; -mod gl; +pub mod gl3 { + pub use super::framebuffer::GLImage; + pub type FilterChain = super::filter_chain::FilterChain; + pub type Viewport<'a> = super::framebuffer::Viewport<'a, ::Framebuffer>; +} + +pub mod gl46 { + pub use super::framebuffer::GLImage; + pub type FilterChain = super::filter_chain::FilterChain; + pub type Viewport<'a> = super::framebuffer::Viewport<'a, ::Framebuffer>; +} #[cfg(test)] mod tests { @@ -28,11 +37,21 @@ mod tests { #[test] fn triangle_gl() { - let (glfw, window, events, shader, vao) = gl3_hello_triangle::setup(); + let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup(); let mut filter = FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) .unwrap(); - gl3_hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); + gl::gl3::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); + } + + #[test] + fn triangle_gl46() { + let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup(); + let mut filter = + FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp", None) + // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) + .unwrap(); + gl::gl46::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); } } diff --git a/librashader-runtime-gl/src/render_target.rs b/librashader-runtime-gl/src/render_target.rs index e275fe6..6d7a73d 100644 --- a/librashader-runtime-gl/src/render_target.rs +++ b/librashader-runtime-gl/src/render_target.rs @@ -1,6 +1,5 @@ use crate::framebuffer::Viewport; use crate::gl::Framebuffer; -use crate::gl::gl3::Gl3Framebuffer; #[rustfmt::skip] static DEFAULT_MVP: &[f32; 16] = &[ @@ -11,15 +10,15 @@ static DEFAULT_MVP: &[f32; 16] = &[ ]; #[derive(Debug, Copy, Clone)] -pub(crate) struct RenderTarget<'a> { +pub(crate) struct RenderTarget<'a, T: Framebuffer> { pub mvp: &'a [f32; 16], - pub framebuffer: &'a Gl3Framebuffer, + pub framebuffer: &'a T, pub x: i32, pub y: i32 } -impl<'a> RenderTarget<'a> { - pub fn new(backbuffer: &'a Gl3Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self { +impl<'a, T: Framebuffer> RenderTarget<'a, T> { + pub fn new(backbuffer: &'a T, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self { if let Some(mvp) = mvp { RenderTarget { framebuffer: backbuffer, @@ -38,8 +37,8 @@ impl<'a> RenderTarget<'a> { } } -impl<'a> From<&Viewport<'a>> for RenderTarget<'a> { - fn from(value: &Viewport<'a>) -> Self { +impl<'a, T: Framebuffer> From<&Viewport<'a, T>> for RenderTarget<'a, T> { + fn from(value: &Viewport<'a, T>) -> Self { RenderTarget::new(value.output, value.mvp, value.x, value.y) } } diff --git a/librashader-runtime-gl/src/texture.rs b/librashader-runtime-gl/src/texture.rs index e268567..b941484 100644 --- a/librashader-runtime-gl/src/texture.rs +++ b/librashader-runtime-gl/src/texture.rs @@ -1,9 +1,9 @@ use librashader_common::{FilterMode, WrapMode}; -use crate::GlImage; +use crate::framebuffer::GLImage; #[derive(Default, Debug, Copy, Clone)] pub struct Texture { - pub image: GlImage, + pub image: GLImage, pub filter: FilterMode, pub mip_filter: FilterMode, pub wrap_mode: WrapMode, diff --git a/librashader-runtime-gl46/Cargo.toml b/librashader-runtime-gl46/Cargo.toml deleted file mode 100644 index 7790b8c..0000000 --- a/librashader-runtime-gl46/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "librashader-runtime-gl46" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -librashader-common = { path = "../librashader-common", features = ["opengl"] } -librashader-presets = { path = "../librashader-presets" } -librashader-preprocess = { path = "../librashader-preprocess" } -librashader-reflect = { path = "../librashader-reflect" } -librashader-runtime = { path = "../librashader-runtime" } - -spirv_cross = "0.23.1" -rustc-hash = "1.1.0" -gl = "0.14.0" -bytemuck = "1.12.3" -thiserror = "1.0.37" - -[dev-dependencies] -glfw = "0.47.0" - -[features] -gl4 = [] \ No newline at end of file diff --git a/librashader-runtime-gl46/src/binding.rs b/librashader-runtime-gl46/src/binding.rs deleted file mode 100644 index 02b818d..0000000 --- a/librashader-runtime-gl46/src/binding.rs +++ /dev/null @@ -1,112 +0,0 @@ -use gl::types::GLint; -use librashader_reflect::reflect::semantics::BindingStage; -use librashader_runtime::uniforms::{BindUniform, UniformStorage, UniformScalar}; - -#[derive(Debug)] -pub enum VariableLocation { - Ubo(UniformLocation), - Push(UniformLocation), -} - -impl VariableLocation { - pub fn location(&self) -> UniformLocation { - match self { - VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l, - } - } -} - -#[derive(Debug, Copy, Clone)] -pub struct UniformLocation { - pub vertex: T, - pub fragment: T, -} - -impl UniformLocation { - 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 - } -} - -pub(crate) type BufferStorage = UniformStorage>; - - -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/error.rs b/librashader-runtime-gl46/src/error.rs deleted file mode 100644 index c2d187c..0000000 --- a/librashader-runtime-gl46/src/error.rs +++ /dev/null @@ -1,26 +0,0 @@ -use gl::types::GLenum; -use librashader_common::image::ImageError; -use librashader_preprocess::PreprocessError; -use librashader_presets::ParsePresetError; -use librashader_reflect::error::{ShaderCompileError, ShaderReflectError}; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum FilterChainError { - #[error("fbo initialization error")] - FramebufferInit(GLenum), - #[error("SPIRV reflection error")] - SpirvCrossReflectError(#[from] spirv_cross::ErrorCode), - #[error("shader preset parse error")] - ShaderPresetError(#[from] ParsePresetError), - #[error("shader preprocess error")] - ShaderPreprocessError(#[from] PreprocessError), - #[error("shader compile error")] - ShaderCompileError(#[from] ShaderCompileError), - #[error("shader reflect error")] - ShaderReflectError(#[from] ShaderReflectError), - #[error("lut loading error")] - LutLoadError(#[from] ImageError) -} - -pub type Result = std::result::Result; \ No newline at end of file diff --git a/librashader-runtime-gl46/src/filter_chain.rs b/librashader-runtime-gl46/src/filter_chain.rs deleted file mode 100644 index 512c3e9..0000000 --- a/librashader-runtime-gl46/src/filter_chain.rs +++ /dev/null @@ -1,645 +0,0 @@ -use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; -use crate::filter_pass::FilterPass; -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, gl_u16_to_version, InlineRingBuffer}; -use crate::error::{FilterChainError, Result}; - -use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint}; -use librashader_common::image::Image; -use librashader_common::{FilterMode, Size, WrapMode}; -use librashader_preprocess::ShaderSource; -use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; -use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion}; -use librashader_reflect::back::targets::GLSL; -use librashader_reflect::reflect::semantics::{MemberOffset, ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformMeta, UniformSemantic, VariableSemantics}; -use librashader_reflect::reflect::ReflectShader; -use rustc_hash::FxHashMap; -use spirv_cross::spirv::Decoration; -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; - -pub struct FilterChain { - passes: Box<[FilterPass]>, - common: FilterCommon, - pub(crate) draw_quad: DrawQuad, - output_framebuffers: Box<[Framebuffer]>, - feedback_framebuffers: Box<[Framebuffer]>, - history_framebuffers: VecDeque, -} - -pub struct FilterCommon { - // semantics: ReflectSemantics, - pub(crate) config: FilterMutable, - pub(crate) luts: FxHashMap, - pub(crate) samplers: SamplerSet, - pub output_textures: Box<[Texture]>, - pub feedback_textures: Box<[Texture]>, - pub history_textures: Box<[Texture]>, -} - -pub struct FilterMutable { - pub(crate) passes_enabled: usize, - pub(crate) parameters: FxHashMap -} - -impl FilterChain { - fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation { - // todo: support both ubo and pushco - // todo: fix this. - match meta.offset() { - MemberOffset::Ubo(_) => { - let vert_name = format!("LIBRA_UBO_VERTEX_INSTANCE.{}\0", meta.id()); - let frag_name = format!("LIBRA_UBO_FRAGMENT_INSTANCE.{}\0", meta.id()); - unsafe { - let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); - let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); - - VariableLocation::Ubo(UniformLocation { vertex, fragment }) - } - } - MemberOffset::PushConstant(_) => { - let vert_name = format!("LIBRA_PUSH_VERTEX_INSTANCE.{}\0", meta.id()); - let frag_name = format!("LIBRA_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id()); - unsafe { - let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); - let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); - - VariableLocation::Push(UniformLocation { vertex, fragment }) - } - } - } - } -} - -type ShaderPassMeta = ( - ShaderPassConfig, - ShaderSource, - CompilerBackend< - impl CompileShader + ReflectShader, - >, -); - -impl FilterChain { - /// Load a filter chain from a pre-parsed `ShaderPreset`. - pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result { - let (passes, semantics) = FilterChain::load_preset(preset.shaders, &preset.textures)?; - - 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(version, passes, &semantics)?; - - let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); - let default_wrap = filters - .first() - .map(|f| f.config.wrap_mode) - .unwrap_or_default(); - - let samplers = SamplerSet::new(); - - // initialize output framebuffers - let mut output_framebuffers = Vec::new(); - output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); - let mut output_textures = Vec::new(); - output_textures.resize_with(filters.len(), Texture::default); - - // initialize feedback framebuffers - let mut feedback_framebuffers = Vec::new(); - feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); - let mut feedback_textures = Vec::new(); - feedback_textures.resize_with(filters.len(), Texture::default); - - // load luts - let luts = FilterChain::load_luts(&preset.textures)?; - - let (history_framebuffers, history_textures) = - FilterChain::init_history(&filters, default_filter, default_wrap); - - // create VBO objects - let draw_quad = DrawQuad::new(); - - Ok(FilterChain { - passes: filters, - output_framebuffers: output_framebuffers.into_boxed_slice(), - feedback_framebuffers: feedback_framebuffers.into_boxed_slice(), - history_framebuffers, - draw_quad, - common: FilterCommon { - config: FilterMutable { - passes_enabled: preset.shader_count as usize, - parameters: preset.parameters.into_iter() - .map(|param| (param.name, param.value)).collect(), - }, - luts, - samplers, - output_textures: output_textures.into_boxed_slice(), - feedback_textures: feedback_textures.into_boxed_slice(), - history_textures, - }, - }) - } - - /// Load the shader preset at the given path into a filter chain. - 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, options) - } - - fn load_preset( - passes: Vec, - textures: &[TextureConfig] - ) -> Result<(Vec, ReflectSemantics)> { - let mut uniform_semantics: FxHashMap = Default::default(); - let mut texture_semantics: FxHashMap> = - Default::default(); - - let passes = passes - .into_iter() - .map(|shader| { - eprintln!("[gl] loading {}", &shader.name.display()); - let source: ShaderSource = ShaderSource::load(&shader.name)?; - - let spirv = GlslangCompilation::compile(&source)?; - let reflect = GLSL::from_compilation(spirv)?; - - for parameter in source.parameters.iter() { - uniform_semantics.insert( - parameter.id.clone(), - UniformSemantic::Variable(SemanticMap { - semantics: VariableSemantics::FloatParameter, - index: (), - }), - ); - } - Ok::<_, FilterChainError>((shader, source, reflect)) - }) - .into_iter() - .collect::)>>>()?; - - for details in &passes { - librashader_runtime::semantics::insert_pass_semantics( - &mut uniform_semantics, - &mut texture_semantics, - &details.0, - ) - } - - // add lut params - librashader_runtime::semantics::insert_lut_semantics(textures, - &mut uniform_semantics, - &mut texture_semantics); - let semantics = ReflectSemantics { - uniform_semantics, - texture_semantics, - }; - - Ok((passes, semantics)) - } - - fn load_luts(textures: &[TextureConfig]) -> Result> { - let mut luts = FxHashMap::default(); - let pixel_unpack = unsafe { - let mut binding = 0; - gl::GetIntegerv(gl::PIXEL_UNPACK_BUFFER_BINDING, &mut binding); - binding - }; - - unsafe { - gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0); - } - - for (index, texture) in textures.iter().enumerate() { - let image = Image::load(&texture.path)?; - let levels = if texture.mipmap { - util::calc_miplevel(image.size) - } else { - 1u32 - }; - - let mut handle = 0; - unsafe { - gl::CreateTextures(gl::TEXTURE_2D,1, &mut handle); - - gl::TextureStorage2D( - handle, - levels as GLsizei, - gl::RGBA8, - image.size.width as GLsizei, - image.size.height as GLsizei, - ); - - gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0); - gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4); - - gl::TextureSubImage2D( - handle, - 0, 0, 0, - image.size.width as GLsizei, - image.size.height as GLsizei, - gl::RGBA, - gl::UNSIGNED_BYTE, - image.bytes.as_ptr().cast(), - ); - - let mipmap = levels > 1; - if mipmap { - gl::GenerateTextureMipmap(handle); - } - } - - luts.insert( - index, - Texture { - image: GlImage { - handle, - format: gl::RGBA8, - size: image.size, - padded_size: Size::default(), - }, - filter: texture.filter_mode, - mip_filter: texture.filter_mode, - wrap_mode: texture.wrap_mode, - }, - ); - } - - unsafe { - gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, pixel_unpack as GLuint); - }; - Ok(luts) - } - - fn init_passes( - version: GlVersion, - passes: Vec, - semantics: &ReflectSemantics, - ) -> Result> { - let mut filters = Vec::new(); - - // initialize passes - for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() { - let reflection = reflect.reflect(index, semantics)?; - let glsl = reflect.compile(version)?; - - let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?; - - // todo: split this out. - let (program, ubo_location) = unsafe { - let vertex = util::gl_compile_shader(gl::VERTEX_SHADER, glsl.vertex.as_str()); - let fragment = util::gl_compile_shader(gl::FRAGMENT_SHADER, glsl.fragment.as_str()); - - let program = gl::CreateProgram(); - gl::AttachShader(program, vertex); - gl::AttachShader(program, fragment); - - for res in vertex_resources.stage_inputs { - let loc = glsl - .context - .compiler - .vertex - .get_decoration(res.id, Decoration::Location)?; - let mut name = res.name; - name.push('\0'); - - gl::BindAttribLocation(program, loc, name.as_str().as_ptr().cast()) - } - gl::LinkProgram(program); - gl::DeleteShader(vertex); - gl::DeleteShader(fragment); - - let mut status = 0; - gl::GetProgramiv(program, gl::LINK_STATUS, &mut status); - if status != 1 { - panic!("failed to link program") - } - - gl::UseProgram(program); - - for (name, binding) in &glsl.context.sampler_bindings { - let location = - gl::GetUniformLocation(program, name.as_str().as_ptr().cast()); - if location >= 0 { - // eprintln!("setting sampler {location} to sample from {binding}"); - gl::Uniform1i(location, *binding as GLint); - } - } - - gl::UseProgram(0); - ( - program, - UniformLocation { - vertex: gl::GetUniformBlockIndex( - program, - b"LIBRA_UBO_VERTEX\0".as_ptr().cast(), - ), - fragment: gl::GetUniformBlockIndex( - program, - b"LIBRA_UBO_FRAGMENT\0".as_ptr().cast(), - ), - }, - ) - }; - - let ubo_ring = if let Some(ubo) = &reflection.ubo { - let size = ubo.size; - let mut ring: InlineRingBuffer = InlineRingBuffer::new(); - unsafe { - gl::CreateBuffers(16, ring.items_mut().as_mut_ptr()); - for buffer in ring.items() { - gl::NamedBufferData( - *buffer, - size as GLsizeiptr, - std::ptr::null(), - gl::STREAM_DRAW, - ); - } - } - Some(ring) - } else { - None - }; - - 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() { - uniform_bindings.insert( - UniformBinding::Parameter(param.id.clone()), - ( - FilterChain::reflect_uniform_location(program, param), - param.offset, - ), - ); - } - - for (semantics, param) in &reflection.meta.variable_meta { - uniform_bindings.insert( - UniformBinding::SemanticVariable(*semantics), - ( - FilterChain::reflect_uniform_location(program, param), - param.offset, - ), - ); - } - - for (semantics, param) in &reflection.meta.texture_size_meta { - uniform_bindings.insert( - UniformBinding::TextureSize(*semantics), - ( - FilterChain::reflect_uniform_location(program, param), - param.offset, - ), - ); - } - - // eprintln!("{:#?}", reflection.meta.texture_meta); - // eprintln!("{:#?}", reflection.meta); - // eprintln!("{:#?}", locations); - // eprintln!("{:#?}", reflection.push_constant); - // eprintln!("====fragment===="); - // eprintln!("{:#}", glsl.fragment); - // eprintln!("====vertex===="); - // eprintln!("{:#}", glsl.vertex); - - filters.push(FilterPass { - reflection, - compiled: glsl, - program, - ubo_location, - ubo_ring, - uniform_storage, - uniform_bindings, - source, - config - }); - } - - Ok(filters.into_boxed_slice()) - } - - fn init_history( - filters: &[FilterPass], - filter: FilterMode, - wrap_mode: WrapMode, - ) -> (VecDeque, Box<[Texture]>) { - let mut required_images = 0; - - for pass in filters { - // If a shader uses history size, but not history, we still need to keep the texture. - let texture_count = pass - .reflection - .meta - .texture_meta - .iter() - .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory) - .count(); - let texture_size_count = pass - .reflection - .meta - .texture_size_meta - .iter() - .filter(|(semantics, _)| semantics.semantics == TextureSemantics::OriginalHistory) - .count(); - - required_images = std::cmp::max(required_images, texture_count); - required_images = std::cmp::max(required_images, texture_size_count); - } - - // not using frame history; - if required_images <= 1 { - println!("[history] not using frame history"); - return (VecDeque::new(), Box::new([])); - } - - // history0 is aliased with the original - - eprintln!("[history] using frame history with {required_images} images"); - let mut framebuffers = VecDeque::with_capacity(required_images); - framebuffers.resize_with(required_images, || Framebuffer::new(1)); - - let mut history_textures = Vec::new(); - history_textures.resize_with(required_images, || Texture { - image: Default::default(), - filter, - mip_filter: filter, - wrap_mode, - }); - - (framebuffers, history_textures.into_boxed_slice()) - } - - fn push_history(&mut self, input: &GlImage) -> Result<()> { - if let Some(mut back) = self.history_framebuffers.pop_back() { - if back.size != input.size || (input.format != 0 && input.format != back.format) { - eprintln!("[history] resizing"); - back.init(input.size, input.format)?; - } - - back.copy_from(input)?; - - self.history_framebuffers.push_front(back) - } - - Ok(()) - } - - /// 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, options: Option<&FrameOptions>) -> Result<()> { - // limit number of passes to those enabled. - let passes = &mut self.passes[0..self.common.config.passes_enabled]; - if let Some(options) = options { - if options.clear_history { - for framebuffer in &self.history_framebuffers { - framebuffer.clear() - } - } - } - - if passes.is_empty() { - return Ok(()); - } - - // do not need to rebind FBO 0 here since first `draw` will - // bind automatically. - self.draw_quad.bind_vao(); - - let filter = passes[0].config.filter; - let wrap_mode = passes[0].config.wrap_mode; - - // update history - for (texture, fbo) in self - .common - .history_textures - .iter_mut() - .zip(self.history_framebuffers.iter()) - { - texture.image = fbo.as_texture(filter, wrap_mode).image; - } - - for ((texture, fbo), pass) in self - .common - .feedback_textures - .iter_mut() - .zip(self.feedback_framebuffers.iter()) - .zip(passes.iter()) - { - texture.image = fbo - .as_texture(pass.config.filter, pass.config.wrap_mode) - .image; - } - - // shader_gl3: 2067 - let original = Texture { - image: *input, - filter, - mip_filter: filter, - wrap_mode, - }; - - let mut source = original; - - // rescale render buffers to ensure all bindings are valid. - for (index, pass) in passes.iter_mut().enumerate() { - self.output_framebuffers[index].scale( - pass.config.scaling.clone(), - pass.get_format(), - viewport, - &original, - &source, - )?; - - self.feedback_framebuffers[index].scale( - pass.config.scaling.clone(), - pass.get_format(), - viewport, - &original, - &source, - )?; - } - - let passes_len = passes.len(); - let (pass, last) = passes.split_at_mut(passes_len - 1); - - for (index, pass) in pass.iter_mut().enumerate() { - let target = &self.output_framebuffers[index]; - pass.draw( - index, - &self.common, - if pass.config.frame_count_mod > 0 { - count % pass.config.frame_count_mod as usize - } else { - count - } as u32, - 1, - viewport, - &original, - &source, - RenderTarget::new(target, None, 0, 0), - ); - - let target = target.as_texture(pass.config.filter, pass.config.wrap_mode); - self.common.output_textures[index] = target; - source = target; - } - - assert_eq!(last.len(), 1); - for pass in last { - source.filter = pass.config.filter; - source.mip_filter = pass.config.filter; - - pass.draw( - passes_len - 1, - &self.common, - if pass.config.frame_count_mod > 0 { - count % pass.config.frame_count_mod as usize - } else { - count - } as u32, - 1, - viewport, - &original, - &source, - RenderTarget::new(viewport.output, viewport.mvp, viewport.x, viewport.y), - ); - } - - // swap feedback framebuffers with output - for (output, feedback) in self - .output_framebuffers - .iter_mut() - .zip(self.feedback_framebuffers.iter_mut()) - { - std::mem::swap(output, feedback); - } - - self.push_history(input)?; - - // do not need to rebind FBO 0 here since first `draw` will - // bind automatically. - self.draw_quad.unbind_vao(); - - Ok(()) - } -} diff --git a/librashader-runtime-gl46/src/filter_pass.rs b/librashader-runtime-gl46/src/filter_pass.rs deleted file mode 100644 index 6ae26ac..0000000 --- a/librashader-runtime-gl46/src/filter_pass.rs +++ /dev/null @@ -1,365 +0,0 @@ -use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint}; -use librashader_reflect::back::cross::GlslangGlslContext; -use librashader_reflect::back::ShaderCompilerOutput; -use librashader_reflect::reflect::ShaderReflection; - -use librashader_common::{ImageFormat, Size}; -use librashader_preprocess::ShaderSource; -use librashader_presets::ShaderPassConfig; -use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; -use rustc_hash::FxHashMap; - -use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; -use crate::filter_chain::FilterCommon; -use crate::framebuffer::Viewport; -use crate::render_target::RenderTarget; -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(crate) uniform_storage: BufferStorage, - pub uniform_bindings: FxHashMap, - pub source: ShaderSource, - pub config: ShaderPassConfig, -} - -impl FilterPass { - // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) - pub fn draw( - &mut self, - pass_index: usize, - parent: &FilterCommon, - frame_count: u32, - frame_direction: i32, - viewport: &Viewport, - original: &Texture, - source: &Texture, - output: RenderTarget, - ) { - let framebuffer = output.framebuffer; - - unsafe { - gl::UseProgram(self.program); - } - - self.build_semantics( - pass_index, - parent, - output.mvp, - frame_count, - frame_direction, - framebuffer.size, - viewport, - original, - source, - ); - - if self.ubo_location.vertex != gl::INVALID_INDEX - && self.ubo_location.fragment != gl::INVALID_INDEX - { - if let (Some(ubo), Some(ring)) = (&self.reflection.ubo, &mut self.ubo_ring) { - let size = ubo.size; - let buffer = ring.current(); - - unsafe { - gl::NamedBufferSubData( - *buffer, - 0, - size as GLsizeiptr, - self.uniform_storage.ubo.as_ptr().cast(), - ); - - if self.ubo_location.vertex != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer); - } - if self.ubo_location.fragment != gl::INVALID_INDEX { - gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer); - } - } - ring.next() - } - } - - unsafe { - // can use because DSA - framebuffer.clear(); - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer.handle); - gl::Viewport( - output.x, - output.y, - framebuffer.size.width as GLsizei, - framebuffer.size.height as GLsizei, - ); - - if framebuffer.format == gl::SRGB8_ALPHA8 { - gl::Enable(gl::FRAMEBUFFER_SRGB); - } else { - gl::Disable(gl::FRAMEBUFFER_SRGB); - } - - gl::Disable(gl::CULL_FACE); - gl::Disable(gl::BLEND); - gl::Disable(gl::DEPTH_TEST); - - gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); - gl::Disable(gl::FRAMEBUFFER_SRGB); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - } - } - - 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) -> ImageFormat { - let mut fb_format = ImageFormat::R8G8B8A8Unorm; - if self.config.srgb_framebuffer { - fb_format = ImageFormat::R8G8B8A8Srgb; - } else if self.config.float_framebuffer { - fb_format = ImageFormat::R16G16B16A16Sfloat; - } - fb_format - } - - // framecount should be pre-modded - fn build_semantics( - &mut self, - pass_index: usize, - parent: &FilterCommon, - mvp: &[f32; 16], - frame_count: u32, - frame_direction: i32, - fb_size: Size, - viewport: &Viewport, - original: &Texture, - source: &Texture, - ) { - // Bind MVP - if let Some((location, offset)) = - self.uniform_bindings.get(&VariableSemantics::MVP.into()) - { - self.uniform_storage.bind_mat4(*offset, mvp, location.location()); - } - - // bind OutputSize - if let Some((location, offset)) = self - .uniform_bindings - .get(&VariableSemantics::Output.into()) - { - self.uniform_storage.bind_vec4(*offset, fb_size, location.location()); - } - - // bind FinalViewportSize - if let Some((location, offset)) = self - .uniform_bindings - .get(&VariableSemantics::FinalViewport.into()) - { - self.uniform_storage.bind_vec4(*offset,viewport.output.size, location.location()); - } - - // bind FrameCount - if let Some((location, offset)) = self - .uniform_bindings - .get(&VariableSemantics::FrameCount.into()) - { - self.uniform_storage.bind_scalar(*offset, frame_count, location.location()); - } - - // bind FrameDirection - if let Some((location, offset)) = self - .uniform_bindings - .get(&VariableSemantics::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)) - { - FilterPass::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); - FilterPass::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)) - { - FilterPass::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)) - { - FilterPass::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.iter().enumerate() { - if !output.is_bound() { - continue; - } - if let Some(binding) = self - .reflection - .meta - .texture_meta - .get(&TextureSemantics::PassOutput.semantics(index)) - { - FilterPass::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)) - { - if feedback.image.handle == 0 { - eprintln!("[WARNING] trying to bind PassFeedback: {index} which has texture 0 to slot {} in pass {pass_index}", binding.binding) - } - FilterPass::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)) - { - FilterPass::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()); - } - } - } -} diff --git a/librashader-runtime-gl46/src/framebuffer.rs b/librashader-runtime-gl46/src/framebuffer.rs deleted file mode 100644 index 3cf1c87..0000000 --- a/librashader-runtime-gl46/src/framebuffer.rs +++ /dev/null @@ -1,293 +0,0 @@ -use crate::util; -use crate::texture::Texture; -use gl::types::{GLenum, GLint, GLsizei, GLuint}; -use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; -use librashader_presets::{Scale2D, ScaleType, Scaling}; -use crate::error::FilterChainError; -use crate::error::Result; - -#[derive(Debug)] -pub struct Framebuffer { - pub image: GLuint, - pub handle: GLuint, - pub size: Size, - pub format: GLenum, - pub max_levels: u32, - pub levels: u32, - is_raw: bool, -} - -impl Framebuffer { - pub fn new(max_levels: u32) -> Framebuffer { - let mut framebuffer = 0; - unsafe { - gl::CreateFramebuffers(1, &mut framebuffer); - } - - Framebuffer { - image: 0, - size: Size { - width: 1, - height: 1, - }, - format: 0, - max_levels, - levels: 0, - handle: framebuffer, - is_raw: false, - } - } - - pub fn new_from_raw( - texture: GLuint, - handle: GLuint, - format: GLenum, - size: Size, - miplevels: u32, - ) -> Framebuffer { - Framebuffer { - image: texture, - size, - format, - max_levels: miplevels, - levels: miplevels, - handle, - is_raw: true, - } - } - - pub(crate) fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture { - Texture { - image: GlImage { - handle: self.image, - format: self.format, - size: self.size, - padded_size: Default::default(), - }, - filter, - mip_filter: filter, - wrap_mode, - } - } - - pub(crate) fn scale( - &mut self, - scaling: Scale2D, - format: ImageFormat, - viewport: &Viewport, - _original: &Texture, - source: &Texture, - ) -> Result> { - if self.is_raw { - return Ok(self.size); - } - - let width; - let height; - - match 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.output.size.width * factor, - }; - - match 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.output.size.height * factor, - }; - - let size = Size { - width: width.round() as u32, - height: height.round() as u32, - }; - - if self.size != size { - self.size = size; - - self.init( - size, - if format == ImageFormat::Unknown { - ImageFormat::R8G8B8A8Unorm - } else { - format - }, - )?; - } - Ok(size) - } - - pub(crate) fn clear(&self) { - unsafe { - gl::ClearNamedFramebufferfv(self.handle, - gl::COLOR, 0, - [0.0f32, 0.0, 0.0, 0.0].as_ptr().cast()); - } - } - - pub(crate) fn copy_from(&mut self, image: &GlImage) -> Result<()> { - // todo: may want to use a shader and draw a quad to be faster. - if image.size != self.size || image.format != self.format { - self.init(image.size, image.format)?; - } - - unsafe { - // gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); - gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0); - gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); - - gl::BlitNamedFramebuffer(image.handle, self.handle, - 0, 0, image.size.width as GLint, image.size.height as GLint, - 0, 0, self.size.width as GLint, self.size.height as GLint, - gl::COLOR_BUFFER_BIT, gl::NEAREST); - - } - - Ok(()) - } - - pub(crate) fn init(&mut self, mut size: Size, format: impl Into) -> Result<()> { - if self.is_raw { - return Ok(()); - } - self.format = format.into(); - self.size = size; - - unsafe { - // reset the framebuffer image - if self.image != 0 { - gl::NamedFramebufferTexture( - self.handle, - gl::COLOR_ATTACHMENT0, - 0, - 0, - ); - gl::DeleteTextures(1, &self.image); - } - - gl::CreateTextures(gl::TEXTURE_2D,1, &mut self.image); - - if size.width == 0 { - size.width = 1; - } - if size.height == 0 { - size.height = 1; - } - - self.levels = util::calc_miplevel(size); - if self.levels > self.max_levels { - self.levels = self.max_levels; - } - if self.levels == 0 { - self.levels = 1; - } - - gl::TextureStorage2D( - self.image, - self.levels as GLsizei, - self.format, - size.width as GLsizei, - size.height as GLsizei, - ); - - gl::NamedFramebufferTexture( - self.handle, - gl::COLOR_ATTACHMENT0, - self.image, - 0, - ); - - let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); - if status != gl::FRAMEBUFFER_COMPLETE { - match status { - gl::FRAMEBUFFER_UNSUPPORTED => { - eprintln!("unsupported fbo"); - - gl::NamedFramebufferTexture( - self.handle, - gl::COLOR_ATTACHMENT0, - 0, - 0, - ); - gl::DeleteTextures(1, &self.image); - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image); - - self.levels = util::calc_miplevel(size); - if self.levels > self.max_levels { - self.levels = self.max_levels; - } - if self.levels == 0 { - self.levels = 1; - } - - gl::TextureStorage2D( - self.image, - self.levels as GLsizei, - ImageFormat::R8G8B8A8Unorm.into(), - size.width as GLsizei, - size.height as GLsizei, - ); - gl::NamedFramebufferTexture( - self.handle, - gl::COLOR_ATTACHMENT0, - self.image, - 0, - ); - // self.init = - // gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; - } - _ => return Err(FilterChainError::FramebufferInit(status)) - } - } - } - - Ok(()) - } -} - -impl Drop for Framebuffer { - fn drop(&mut self) { - unsafe { - if self.handle != 0 { - gl::DeleteFramebuffers(1, &self.handle); - } - if self.image != 0 { - gl::DeleteTextures(1, &self.image); - } - } - } -} - -#[derive(Debug, Copy, Clone)] -pub struct Viewport<'a> { - pub x: i32, - pub y: i32, - pub output: &'a Framebuffer, - pub mvp: Option<&'a [f32; 16]>, -} - -#[derive(Default, Debug, Copy, Clone)] -pub struct GlImage { - pub handle: GLuint, - pub format: GLenum, - pub size: Size, - pub padded_size: Size, -} diff --git a/librashader-runtime-gl46/src/lib.rs b/librashader-runtime-gl46/src/lib.rs deleted file mode 100644 index 1c23733..0000000 --- a/librashader-runtime-gl46/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![feature(strict_provenance)] -#![feature(type_alias_impl_trait)] - -mod binding; -mod filter_chain; -mod filter_pass; -mod framebuffer; -mod quad_render; -mod render_target; -mod util; -pub mod error; - -mod samplers; - -pub use filter_chain::FilterChain; -pub use framebuffer::Framebuffer; -pub use framebuffer::GlImage; -pub use framebuffer::Viewport; - -#[cfg(test)] -mod hello_triangle; -mod texture; -mod options; - -#[cfg(test)] -mod tests { - use super::*; - use crate::filter_chain::FilterChain; - - #[test] - fn triangle_gl46() { - let (glfw, window, events, shader, vao) = hello_triangle::setup(); - let mut filter = - 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-gl46/src/options.rs b/librashader-runtime-gl46/src/options.rs deleted file mode 100644 index 1b3985c..0000000 --- a/librashader-runtime-gl46/src/options.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[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-gl46/src/quad_render.rs b/librashader-runtime-gl46/src/quad_render.rs deleted file mode 100644 index 064fdff..0000000 --- a/librashader-runtime-gl46/src/quad_render.rs +++ /dev/null @@ -1,63 +0,0 @@ -use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint}; - -#[rustfmt::skip] -static QUAD_VBO_DATA: &[f32; 16] = &[ - 0.0f32, 0.0f32, 0.0f32, 0.0f32, - 1.0f32, 0.0f32, 1.0f32, 0.0f32, - 0.0f32, 1.0f32, 0.0f32, 1.0f32, - 1.0f32, 1.0f32, 1.0f32, 1.0f32, -]; - -pub struct DrawQuad { - vbo: GLuint, - vao: GLuint, -} - -impl DrawQuad { - pub fn new() -> DrawQuad { - let mut vbo = 0; - let mut vao = 0; - - unsafe { - gl::CreateBuffers(1, &mut vbo); - gl::NamedBufferData( - vbo, - std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr, - QUAD_VBO_DATA.as_ptr().cast(), - gl::STATIC_DRAW, - ); - gl::CreateVertexArrays(1, &mut vao); - - gl::EnableVertexArrayAttrib(vao, 0); - gl::EnableVertexArrayAttrib(vao, 1); - - gl::VertexArrayVertexBuffer(vao, 0, - vbo, 0, 4 * std::mem::size_of::() as GLint - ); - - gl::VertexArrayAttribFormat(vao, 0, 2, - gl::FLOAT, gl::FALSE, 0); - gl::VertexArrayAttribFormat(vao, 1, 2, - gl::FLOAT, gl::FALSE, - 2 * std::mem::size_of::() as GLuint); - - gl::VertexArrayAttribBinding(vao, 0, 0); - gl::VertexArrayAttribBinding(vao, 1, 0); - - } - - DrawQuad { vbo, vao } - } - - pub fn bind_vao(&self) { - unsafe { - gl::BindVertexArray(self.vao); - } - } - - pub fn unbind_vao(&self) { - unsafe { - gl::BindVertexArray(0); - } - } -} diff --git a/librashader-runtime-gl46/src/render_target.rs b/librashader-runtime-gl46/src/render_target.rs deleted file mode 100644 index 44e2d5c..0000000 --- a/librashader-runtime-gl46/src/render_target.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::framebuffer::{Framebuffer, Viewport}; - -#[rustfmt::skip] -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, - -1.0, -1.0, 0.0, 1.0, -]; - -#[derive(Debug, Copy, Clone)] -pub struct RenderTarget<'a> { - 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; 16]>, x: i32, y: i32) -> Self { - if let Some(mvp) = mvp { - RenderTarget { - framebuffer: backbuffer, - x, - mvp, - y, - } - } else { - RenderTarget { - framebuffer: backbuffer, - x, - mvp: DEFAULT_MVP, - y, - } - } - } -} - -impl<'a> From<&Viewport<'a>> for RenderTarget<'a> { - fn from(value: &Viewport<'a>) -> Self { - RenderTarget::new(value.output, value.mvp, value.x, value.y) - } -} diff --git a/librashader-runtime-gl46/src/samplers.rs b/librashader-runtime-gl46/src/samplers.rs deleted file mode 100644 index 57cc5e9..0000000 --- a/librashader-runtime-gl46/src/samplers.rs +++ /dev/null @@ -1,83 +0,0 @@ -use gl::types::{GLenum, GLint, GLuint}; -use rustc_hash::FxHashMap; -use librashader_common::{FilterMode, WrapMode}; - -pub struct SamplerSet { - // todo: may need to deal with differences in mip filter. - samplers: FxHashMap<(WrapMode, FilterMode, FilterMode), GLuint> -} - -impl SamplerSet { - pub fn get(&self, wrap: WrapMode, filter: FilterMode, mip: FilterMode) -> GLuint { - - // eprintln!("{wrap}, {filter}, {mip}"); - *self.samplers.get(&(wrap, filter, mip)) - .unwrap() - } - - fn make_sampler(sampler: GLuint, wrap: WrapMode, filter: FilterMode, mip: FilterMode) { - unsafe { - gl::SamplerParameteri( - sampler, - gl::TEXTURE_WRAP_S, - GLenum::from(wrap) as GLint, - ); - gl::SamplerParameteri( - sampler, - gl::TEXTURE_WRAP_T, - GLenum::from(wrap) as GLint, - ); - gl::SamplerParameteri( - sampler, - gl::TEXTURE_MAG_FILTER, - GLenum::from(filter) as GLint, - ); - - gl::SamplerParameteri( - sampler, - gl::TEXTURE_MIN_FILTER, - GLenum::from(filter.gl_mip(mip)) as GLint, - ); - } - } - - pub fn new() -> SamplerSet { - let mut samplers = FxHashMap::default(); - let wrap_modes = - &[WrapMode::ClampToBorder, WrapMode::ClampToEdge, WrapMode::Repeat, WrapMode::MirroredRepeat]; - for wrap_mode in wrap_modes { - unsafe { - let mut linear_linear = 0; - let mut linear_nearest = 0; - - let mut nearest_nearest = 0; - let mut nearest_linear = 0; - gl::GenSamplers(1, &mut linear_linear); - gl::GenSamplers(1, &mut linear_nearest); - gl::GenSamplers(1, &mut nearest_linear); - gl::GenSamplers(1, &mut nearest_nearest); - - SamplerSet::make_sampler(linear_linear, *wrap_mode, - FilterMode::Linear, FilterMode::Linear); - SamplerSet::make_sampler(linear_nearest, *wrap_mode, - FilterMode::Linear, FilterMode::Nearest); - SamplerSet::make_sampler(nearest_linear, *wrap_mode, - FilterMode::Nearest, FilterMode::Linear); - SamplerSet::make_sampler(nearest_nearest, *wrap_mode, - FilterMode::Nearest, FilterMode::Nearest); - - - samplers.insert((*wrap_mode, FilterMode::Linear, FilterMode::Linear), linear_linear); - samplers.insert((*wrap_mode, FilterMode::Linear, FilterMode::Nearest), linear_nearest); - - samplers.insert((*wrap_mode, FilterMode::Nearest, FilterMode::Nearest), nearest_nearest); - samplers.insert((*wrap_mode, FilterMode::Nearest, FilterMode::Linear), nearest_linear); - } - } - - SamplerSet { - samplers - } - } -} - diff --git a/librashader-runtime-gl46/src/texture.rs b/librashader-runtime-gl46/src/texture.rs deleted file mode 100644 index e268567..0000000 --- a/librashader-runtime-gl46/src/texture.rs +++ /dev/null @@ -1,16 +0,0 @@ -use librashader_common::{FilterMode, WrapMode}; -use crate::GlImage; - -#[derive(Default, Debug, Copy, Clone)] -pub struct Texture { - pub image: GlImage, - pub filter: FilterMode, - pub mip_filter: FilterMode, - pub wrap_mode: WrapMode, -} - -impl Texture { - pub fn is_bound(&self) -> bool { - return self.image.handle != 0 - } -} \ No newline at end of file diff --git a/librashader-runtime-gl46/src/util.rs b/librashader-runtime-gl46/src/util.rs deleted file mode 100644 index f13db26..0000000 --- a/librashader-runtime-gl46/src/util.rs +++ /dev/null @@ -1,129 +0,0 @@ -use gl::types::{GLenum, GLuint}; -use librashader_common::Size; -use librashader_reflect::back::cross::GlVersion; - -pub fn calc_miplevel(size: Size) -> u32 { - let mut size = std::cmp::max(size.width, size.height); - let mut levels = 0; - while size != 0 { - levels += 1; - size >>= 1; - } - - levels -} - -pub trait RingBuffer { - fn current(&self) -> &T; - fn current_mut(&mut self) -> &mut T; - fn next(&mut self); -} - -impl RingBuffer for InlineRingBuffer { - fn current(&self) -> &T { - &self.items[self.index] - } - - fn current_mut(&mut self) -> &mut T { - &mut self.items[self.index] - } - - fn next(&mut self) { - self.index += 1; - if self.index >= SIZE { - self.index = 0 - } - } -} - -pub struct InlineRingBuffer { - items: [T; SIZE], - index: usize, -} - -impl InlineRingBuffer -where - T: Copy, - T: Default, -{ - pub fn new() -> Self { - Self { - items: [T::default(); SIZE], - index: 0, - } - } - - pub fn items(&self) -> &[T; SIZE] { - &self.items - } - - pub fn items_mut(&mut self) -> &mut [T; SIZE] { - &mut self.items - } -} - -pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { - let shader = gl::CreateShader(stage); - gl::ShaderSource( - shader, - 1, - &source.as_bytes().as_ptr().cast(), - std::ptr::null(), - ); - gl::CompileShader(shader); - let mut compile_status = 0; - gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status); - - if compile_status == 0 { - panic!("failed to compile") - } - shader -} - -pub fn gl_get_version() -> GlVersion { - let mut maj_ver = 0; - let mut min_ver = 0; - unsafe { - gl::GetIntegerv(gl::MAJOR_VERSION, &mut maj_ver); - gl::GetIntegerv(gl::MINOR_VERSION, &mut min_ver); - } - - match maj_ver { - 3 => match min_ver { - 3 => GlVersion::V3_30, - 2 => GlVersion::V1_50, - 1 => GlVersion::V1_40, - 0 => GlVersion::V1_30, - _ => GlVersion::V1_50, - } - 4 => match min_ver { - 6 => GlVersion::V4_60, - 5 => GlVersion::V4_50, - 4 => GlVersion::V4_40, - 3 => GlVersion::V4_30, - 2 => GlVersion::V4_20, - 1 => GlVersion::V4_10, - 0 => GlVersion::V4_00, - _ => GlVersion::V1_50 - } - _ => 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 diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 5059c70..f9ee485 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -32,25 +32,26 @@ pub mod targets { /// Shader compiler target for GLSL. pub use librashader_reflect::back::targets::GLSL; - /// Shader runtime for OpenGL. - pub mod runtime { - pub use librashader_runtime_gl::*; - } - } - - /// Shader compiler targets and runtime for OpenGL 4.6. - pub mod gl46 { - /// Shader compiler target for GLSL. - pub use librashader_reflect::back::targets::GLSL; /// Shader runtime for OpenGL. pub mod runtime { - pub use librashader_runtime_gl46::*; + pub use librashader_runtime_gl::options::*; + pub use librashader_runtime_gl::error; + pub use librashader_runtime_gl::FilterChain; + pub use librashader_runtime_gl::Viewport; + + pub mod gl3 { + pub use librashader_runtime_gl::gl3::*; + } + + pub mod gl46 { + pub use librashader_runtime_gl::gl46::*; + } } } /// Shader compiler targets and runtime for DirectX. - pub mod dx { + pub mod d3d { /// Shader compiler target for HLSL. pub use librashader_reflect::back::targets::HLSL;