diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index 117b9ba..a9d75c8 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -9,7 +9,7 @@ use crate::util::{gl_get_version, gl_u16_to_version}; use gl::types::{GLint, GLuint}; use crate::binding::BufferStorage; -use crate::gl::{DrawQuad, Framebuffer, GLInterface, LoadLut, UboRing}; +use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing}; use crate::options::{FilterChainOptions, FrameOptions}; use crate::samplers::SamplerSet; use crate::texture::Texture; @@ -30,20 +30,75 @@ use spirv_cross::spirv::Decoration; use std::collections::VecDeque; use std::path::Path; -pub struct FilterChain { +pub struct FilterChain { + filter: FilterChainInner +} + +impl FilterChain { + pub fn load_from_preset( + preset: ShaderPreset, + options: Option<&FilterChainOptions>, + ) -> Result { + if let Some(options) = options && options.use_dsa { + return Ok(Self { + filter: FilterChainInner::DSA(FilterChainImpl::load_from_preset(preset, Some(options))?) + }) + } + return Ok(Self { + filter: FilterChainInner::Compatibility(FilterChainImpl::load_from_preset(preset, options)?) + }) + } + + /// 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) + } + + /// 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<()> { + match &mut self.filter { + FilterChainInner::DSA(p) => { + p.frame(count, viewport, input, options) + } + FilterChainInner::Compatibility(p) => { + p.frame(count, viewport, input, options) + } + } + } +} + +enum FilterChainInner { + DSA(FilterChainImpl), + Compatibility(FilterChainImpl) +} + +struct FilterChainImpl { passes: Box<[FilterPass]>, common: FilterCommon, pub(crate) draw_quad: T::DrawQuad, - output_framebuffers: Box<[T::Framebuffer]>, - feedback_framebuffers: Box<[T::Framebuffer]>, - history_framebuffers: VecDeque, + output_framebuffers: Box<[Framebuffer]>, + feedback_framebuffers: Box<[Framebuffer]>, + history_framebuffers: VecDeque, } -pub struct FilterCommon { +pub(crate) struct FilterCommon { // semantics: ReflectSemantics, - pub(crate) config: FilterMutable, - pub(crate) luts: FxHashMap, - pub(crate) samplers: SamplerSet, + pub config: FilterMutable, + pub luts: FxHashMap, + pub samplers: SamplerSet, pub output_textures: Box<[Texture]>, pub feedback_textures: Box<[Texture]>, pub history_textures: Box<[Texture]>, @@ -54,7 +109,7 @@ pub struct FilterMutable { pub(crate) parameters: FxHashMap, } -impl FilterChain { +impl FilterChainImpl { fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation { // todo: support both ubo and pushco // todo: fix this. @@ -91,9 +146,9 @@ type ShaderPassMeta = ( >, ); -impl FilterChain { +impl FilterChainImpl { /// Load a filter chain from a pre-parsed `ShaderPreset`. - pub fn load_from_preset( + pub(crate) fn load_from_preset( preset: ShaderPreset, options: Option<&FilterChainOptions>, ) -> Result { @@ -116,13 +171,13 @@ impl FilterChain { // initialize output framebuffers let mut output_framebuffers = Vec::new(); - output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); + output_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::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)); + feedback_framebuffers.resize_with(filters.len(), || T::FramebufferInterface::new(1)); let mut feedback_textures = Vec::new(); feedback_textures.resize_with(filters.len(), Texture::default); @@ -130,12 +185,12 @@ impl FilterChain { let luts = T::LoadLut::load_luts(&preset.textures)?; let (history_framebuffers, history_textures) = - FilterChain::init_history(&filters, default_filter, default_wrap); + FilterChainImpl::init_history(&filters, default_filter, default_wrap); // create vertex objects let draw_quad = T::DrawQuad::new(); - Ok(FilterChain { + Ok(FilterChainImpl { passes: filters, output_framebuffers: output_framebuffers.into_boxed_slice(), feedback_framebuffers: feedback_framebuffers.into_boxed_slice(), @@ -159,16 +214,6 @@ 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 { - // load passes from preset - let preset = ShaderPreset::try_parse(path)?; - Self::load_from_preset(preset, options) - } - fn load_preset( passes: Vec, textures: &[TextureConfig], @@ -363,7 +408,7 @@ impl FilterChain { filters: &[FilterPass], filter: FilterMode, wrap_mode: WrapMode, - ) -> (VecDeque, Box<[Texture]>) { + ) -> (VecDeque, Box<[Texture]>) { let mut required_images = 0; for pass in filters { @@ -397,7 +442,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, || Framebuffer::new(1)); + framebuffers.resize_with(required_images, || T::FramebufferInterface::new(1)); let mut history_textures = Vec::new(); history_textures.resize_with(required_images, || Texture { @@ -412,12 +457,12 @@ impl FilterChain { 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)?; + T::FramebufferInterface::init(&mut back, input.size, input.format)?; } - back.copy_from(input)?; + back.copy_from::(input)?; self.history_framebuffers.push_front(back) } @@ -431,7 +476,7 @@ impl FilterChain { pub fn frame( &mut self, count: usize, - viewport: &Viewport, + viewport: &Viewport, input: &GLImage, options: Option<&FrameOptions>, ) -> Result<()> { @@ -440,7 +485,7 @@ impl FilterChain { if let Some(options) = options { if options.clear_history { for framebuffer in &self.history_framebuffers { - framebuffer.clear::() + framebuffer.clear::() } } } @@ -490,7 +535,7 @@ impl FilterChain { // rescale render buffers to ensure all bindings are valid. for (index, pass) in passes.iter_mut().enumerate() { - self.output_framebuffers[index].scale( + self.output_framebuffers[index].scale::( pass.config.scaling.clone(), pass.get_format(), viewport, @@ -498,7 +543,7 @@ impl FilterChain { &source, )?; - self.feedback_framebuffers[index].scale( + self.feedback_framebuffers[index].scale::( pass.config.scaling.clone(), pass.get_format(), viewport, diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs index c630b53..14cafc6 100644 --- a/librashader-runtime-gl/src/filter_pass.rs +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -14,7 +14,7 @@ use rustc_hash::FxHashMap; use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; use crate::filter_chain::FilterCommon; use crate::framebuffer::Viewport; -use crate::gl::{BindTexture, Framebuffer, GLInterface, UboRing}; +use crate::gl::{BindTexture, FramebufferInterface, GLInterface, UboRing}; use crate::render_target::RenderTarget; use crate::texture::Texture; @@ -39,15 +39,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); } @@ -57,7 +57,7 @@ impl FilterPass { output.mvp, frame_count, frame_direction, - framebuffer.size(), + framebuffer.size, viewport, original, source, @@ -73,9 +73,9 @@ impl FilterPass { unsafe { // can't use framebuffer.clear because it will unbind. - framebuffer.clear::(); + framebuffer.clear::(); - let framebuffer_size = framebuffer.size(); + let framebuffer_size = framebuffer.size; gl::Viewport( output.x, output.y, @@ -83,7 +83,7 @@ impl FilterPass { 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); @@ -120,7 +120,7 @@ impl FilterPass { frame_count: u32, frame_direction: i32, fb_size: Size, - viewport: &Viewport, + viewport: &Viewport, original: &Texture, source: &Texture, ) { @@ -145,7 +145,7 @@ impl FilterPass { .get(&VariableSemantics::FinalViewport.into()) { self.uniform_storage - .bind_vec4(*offset, viewport.output.size(), location.location()); + .bind_vec4(*offset, viewport.output.size, location.location()); } // bind FrameCount diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs index 1a75fcd..19f294e 100644 --- a/librashader-runtime-gl/src/framebuffer.rs +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -1,13 +1,13 @@ use gl::types::{GLenum, GLuint}; use librashader_common::Size; -use crate::gl::Framebuffer; +use crate::gl::{Framebuffer, FramebufferInterface}; #[derive(Debug, Copy, Clone)] -pub struct Viewport<'a, T: Framebuffer + ?Sized> { +pub struct Viewport<'a> { pub x: i32, pub y: i32, - pub output: &'a T, + pub output: &'a Framebuffer, pub mvp: Option<&'a [f32; 16]>, } diff --git a/librashader-runtime-gl/src/gl/framebuffer.rs b/librashader-runtime-gl/src/gl/framebuffer.rs new file mode 100644 index 0000000..eaadff0 --- /dev/null +++ b/librashader-runtime-gl/src/gl/framebuffer.rs @@ -0,0 +1,81 @@ +use crate::error::Result; +use crate::framebuffer::GLImage; +use crate::gl::FramebufferInterface; +use crate::texture::Texture; +use crate::Viewport; +use gl::types::{GLenum, GLuint}; +use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; +use librashader_presets::Scale2D; + +#[derive(Debug)] +pub struct Framebuffer { + pub image: GLuint, + pub handle: GLuint, + pub size: Size, + pub format: GLenum, + pub max_levels: u32, + pub mip_levels: u32, + pub is_raw: bool, +} + +impl Framebuffer { + pub fn new(max_levels: u32) -> Self { + T::new(max_levels) + } + + pub fn new_from_raw( + texture: GLuint, + handle: GLuint, + format: GLenum, + size: Size, + mip_levels: u32, + ) -> Self { + T::new_from_raw(texture, handle, format, size, mip_levels) + } + + pub fn clear(&self) { + T::clear::(&self) + } + + pub fn scale( + &mut self, + scaling: Scale2D, + format: ImageFormat, + viewport: &Viewport, + original: &Texture, + source: &Texture, + ) -> Result> { + T::scale(self, scaling, format, viewport, original, source) + } + + pub fn copy_from(&mut self, image: &GLImage) -> Result<()> { + T::copy_from(self, image) + } + + pub 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, + } + } +} + +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); + } + } + } +} diff --git a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs index 8b50387..47a732a 100644 --- a/librashader-runtime-gl/src/gl/gl3/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl3/framebuffer.rs @@ -1,40 +1,17 @@ use crate::error::{FilterChainError, Result}; use crate::framebuffer::{GLImage, Viewport}; -use crate::gl::Framebuffer; +use crate::gl::framebuffer::Framebuffer; +use crate::gl::FramebufferInterface; use crate::texture::Texture; use gl::types::{GLenum, GLint, GLsizei, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; #[derive(Debug)] -pub struct Gl3Framebuffer { - image: GLuint, - handle: GLuint, - size: Size, - format: GLenum, - max_levels: u32, - mip_levels: u32, - is_raw: bool, -} +pub struct Gl3Framebuffer; -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 { +impl FramebufferInterface for Gl3Framebuffer { + fn new(max_levels: u32) -> Framebuffer { let mut framebuffer = 0; unsafe { gl::GenFramebuffers(1, &mut framebuffer); @@ -42,7 +19,7 @@ impl Framebuffer for Gl3Framebuffer { gl::BindFramebuffer(gl::FRAMEBUFFER, 0); } - Gl3Framebuffer { + Framebuffer { image: 0, size: Size { width: 1, @@ -61,8 +38,8 @@ impl Framebuffer for Gl3Framebuffer { format: GLenum, size: Size, miplevels: u32, - ) -> Gl3Framebuffer { - Gl3Framebuffer { + ) -> Framebuffer { + Framebuffer { image: texture, size, format, @@ -72,38 +49,27 @@ impl Framebuffer for Gl3Framebuffer { is_raw: true, } } - 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, - } - } + fn scale( - &mut self, + fb: &mut Framebuffer, scaling: Scale2D, format: ImageFormat, - viewport: &Viewport, + viewport: &Viewport, _original: &Texture, source: &Texture, ) -> Result> { - if self.is_raw { - return Ok(self.size); + if fb.is_raw { + return Ok(fb.size); } let size = librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size); - if self.size != size { - self.size = size; + if fb.size != size { + fb.size = size; - self.init( + Self::init( + fb, size, if format == ImageFormat::Unknown { ImageFormat::R8G8B8A8Unorm @@ -114,10 +80,10 @@ impl Framebuffer for Gl3Framebuffer { } Ok(size) } - fn clear(&self) { + fn clear(fb: &Framebuffer) { unsafe { if REBIND { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); + gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle); } gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE); gl::ClearColor(0.0, 0.0, 0.0, 0.0); @@ -127,14 +93,15 @@ impl Framebuffer for Gl3Framebuffer { } } } - fn copy_from(&mut self, image: &GLImage) -> Result<()> { + fn copy_from(fb: &mut Framebuffer, 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)?; + if image.size != fb.size || image.format != fb.format { + Self::init( + fb,image.size, image.format)?; } unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); + gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle); gl::FramebufferTexture2D( gl::READ_FRAMEBUFFER, @@ -148,7 +115,7 @@ impl Framebuffer for Gl3Framebuffer { gl::DRAW_FRAMEBUFFER, gl::COLOR_ATTACHMENT1, gl::TEXTURE_2D, - self.image, + fb.image, 0, ); gl::ReadBuffer(gl::COLOR_ATTACHMENT0); @@ -156,12 +123,12 @@ impl Framebuffer for Gl3Framebuffer { gl::BlitFramebuffer( 0, 0, - self.size.width as GLint, - self.size.height as GLint, + fb.size.width as GLint, + fb.size.height as GLint, 0, 0, - self.size.width as GLint, - self.size.height as GLint, + fb.size.width as GLint, + fb.size.height as GLint, gl::COLOR_BUFFER_BIT, gl::NEAREST, ); @@ -188,7 +155,7 @@ impl Framebuffer for Gl3Framebuffer { gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, - self.image, + fb.image, 0, ); @@ -197,18 +164,18 @@ impl Framebuffer for Gl3Framebuffer { Ok(()) } - fn init(&mut self, mut size: Size, format: impl Into) -> Result<()> { - if self.is_raw { + fn init(fb: &mut Framebuffer, mut size: Size, format: impl Into) -> Result<()> { + if fb.is_raw { return Ok(()); } - self.format = format.into(); - self.size = size; + fb.format = format.into(); + fb.size = size; unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.handle); + gl::BindFramebuffer(gl::FRAMEBUFFER, fb.handle); // reset the framebuffer image - if self.image != 0 { + if fb.image != 0 { gl::FramebufferTexture2D( gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, @@ -216,11 +183,11 @@ impl Framebuffer for Gl3Framebuffer { 0, 0, ); - gl::DeleteTextures(1, &self.image); + gl::DeleteTextures(1, &fb.image); } - gl::GenTextures(1, &mut self.image); - gl::BindTexture(gl::TEXTURE_2D, self.image); + gl::GenTextures(1, &mut fb.image); + gl::BindTexture(gl::TEXTURE_2D, fb.image); if size.width == 0 { size.width = 1; @@ -229,18 +196,18 @@ impl Framebuffer for Gl3Framebuffer { 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; + fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size); + if fb.mip_levels > fb.max_levels { + fb.mip_levels = fb.max_levels; } - if self.mip_levels == 0 { - self.mip_levels = 1; + if fb.mip_levels == 0 { + fb.mip_levels = 1; } gl::TexStorage2D( gl::TEXTURE_2D, - self.mip_levels as GLsizei, - self.format, + fb.mip_levels as GLsizei, + fb.format, size.width as GLsizei, size.height as GLsizei, ); @@ -249,7 +216,7 @@ impl Framebuffer for Gl3Framebuffer { gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, - self.image, + fb.image, 0, ); @@ -266,21 +233,21 @@ impl Framebuffer for Gl3Framebuffer { 0, 0, ); - gl::DeleteTextures(1, &self.image); - gl::GenTextures(1, &mut self.image); - gl::BindTexture(gl::TEXTURE_2D, self.image); + gl::DeleteTextures(1, &fb.image); + gl::GenTextures(1, &mut fb.image); + gl::BindTexture(gl::TEXTURE_2D, fb.image); - self.mip_levels = librashader_runtime::scaling::calc_miplevel(size); - if self.mip_levels > self.max_levels { - self.mip_levels = self.max_levels; + fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size); + if fb.mip_levels > fb.max_levels { + fb.mip_levels = fb.max_levels; } - if self.mip_levels == 0 { - self.mip_levels = 1; + if fb.mip_levels == 0 { + fb.mip_levels = 1; } gl::TexStorage2D( gl::TEXTURE_2D, - self.mip_levels as GLsizei, + fb.mip_levels as GLsizei, ImageFormat::R8G8B8A8Unorm.into(), size.width as GLsizei, size.height as GLsizei, @@ -289,10 +256,10 @@ impl Framebuffer for Gl3Framebuffer { gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, - self.image, + fb.image, 0, ); - // self.init = + // fb.init = // gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; } _ => return Err(FilterChainError::FramebufferInit(status)), @@ -306,16 +273,3 @@ impl Framebuffer for Gl3Framebuffer { Ok(()) } } - -impl Drop for Gl3Framebuffer { - fn drop(&mut self) { - unsafe { - if self.handle != 0 { - gl::DeleteFramebuffers(1, &self.handle); - } - if self.image != 0 { - gl::DeleteTextures(1, &self.image); - } - } - } -} diff --git a/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs b/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs index 6e53e1b..50a0262 100644 --- a/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs +++ b/librashader-runtime-gl/src/gl/gl3/hello_triangle.rs @@ -10,7 +10,7 @@ use librashader_common::Size; use crate::filter_chain::FilterChain; use crate::framebuffer::{GLImage, Viewport}; use crate::gl::gl3::CompatibilityGL; -use crate::gl::{Framebuffer, GLInterface}; +use crate::gl::{FramebufferInterface, GLInterface}; 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 = ::Framebuffer::new_from_raw( + let output = ::FramebufferInterface::new_from_raw( output_texture, output_framebuffer_handle, gl::RGBA8, diff --git a/librashader-runtime-gl/src/gl/gl3/mod.rs b/librashader-runtime-gl/src/gl/gl3/mod.rs index 638f1d1..06a6b2f 100644 --- a/librashader-runtime-gl/src/gl/gl3/mod.rs +++ b/librashader-runtime-gl/src/gl/gl3/mod.rs @@ -15,7 +15,7 @@ use ubo_ring::*; pub struct CompatibilityGL; impl GLInterface for CompatibilityGL { - type Framebuffer = Gl3Framebuffer; + type FramebufferInterface = Gl3Framebuffer; type UboRing = Gl3UboRing<16>; type DrawQuad = Gl3DrawQuad; type LoadLut = Gl3LutLoad; diff --git a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs index 9f432c3..a16a65c 100644 --- a/librashader-runtime-gl/src/gl/gl46/framebuffer.rs +++ b/librashader-runtime-gl/src/gl/gl46/framebuffer.rs @@ -1,46 +1,23 @@ use crate::error::{FilterChainError, Result}; use crate::framebuffer::{GLImage, Viewport}; -use crate::gl::Framebuffer; +use crate::gl::framebuffer::Framebuffer; +use crate::gl::FramebufferInterface; use crate::texture::Texture; use gl::types::{GLenum, GLint, GLsizei, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::Scale2D; #[derive(Debug)] -pub struct Gl46Framebuffer { - image: GLuint, - handle: GLuint, - size: Size, - format: GLenum, - max_levels: u32, - levels: u32, - is_raw: bool, -} +pub struct Gl46Framebuffer; -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 { +impl FramebufferInterface for Gl46Framebuffer { + fn new(max_levels: u32) -> Framebuffer { let mut framebuffer = 0; unsafe { gl::CreateFramebuffers(1, &mut framebuffer); } - Gl46Framebuffer { + Framebuffer { image: 0, size: Size { width: 1, @@ -48,7 +25,7 @@ impl Framebuffer for Gl46Framebuffer { }, format: 0, max_levels, - levels: 0, + mip_levels: 0, handle: framebuffer, is_raw: false, } @@ -59,49 +36,38 @@ impl Framebuffer for Gl46Framebuffer { format: GLenum, size: Size, miplevels: u32, - ) -> Gl46Framebuffer { - Gl46Framebuffer { + ) -> Framebuffer { + Framebuffer { image: texture, size, format, max_levels: miplevels, - levels: miplevels, + mip_levels: miplevels, handle, is_raw: true, } } - 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, - } - } + fn scale( - &mut self, + fb: &mut Framebuffer, scaling: Scale2D, format: ImageFormat, - viewport: &Viewport, + viewport: &Viewport, _original: &Texture, source: &Texture, ) -> Result> { - if self.is_raw { - return Ok(self.size); + if fb.is_raw { + return Ok(fb.size); } let size = librashader_runtime::scaling::scale(scaling, source.image.size, viewport.output.size); - if self.size != size { - self.size = size; + if fb.size != size { + fb.size = size; - self.init( + Self::init( + fb, size, if format == ImageFormat::Unknown { ImageFormat::R8G8B8A8Unorm @@ -112,38 +78,40 @@ impl Framebuffer for Gl46Framebuffer { } Ok(size) } - fn clear(&self) { + fn clear(fb: &Framebuffer) { unsafe { gl::ClearNamedFramebufferfv( - self.handle, + fb.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(fb: &mut Framebuffer, 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)?; + if image.size != fb.size || image.format != fb.format { + Self::init( + fb, + image.size, image.format)?; } unsafe { - // gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); + // gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1); gl::NamedFramebufferReadBuffer(image.handle, gl::COLOR_ATTACHMENT0); - gl::NamedFramebufferDrawBuffer(self.handle, gl::COLOR_ATTACHMENT1); + gl::NamedFramebufferDrawBuffer(fb.handle, gl::COLOR_ATTACHMENT1); gl::BlitNamedFramebuffer( image.handle, - self.handle, + fb.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, + fb.size.width as GLint, + fb.size.height as GLint, gl::COLOR_BUFFER_BIT, gl::NEAREST, ); @@ -151,21 +119,21 @@ impl Framebuffer for Gl46Framebuffer { Ok(()) } - fn init(&mut self, mut size: Size, format: impl Into) -> Result<()> { - if self.is_raw { + fn init(fb: &mut Framebuffer, mut size: Size, format: impl Into) -> Result<()> { + if fb.is_raw { return Ok(()); } - self.format = format.into(); - self.size = size; + fb.format = format.into(); + fb.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); + if fb.image != 0 { + gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0); + gl::DeleteTextures(1, &fb.image); } - gl::CreateTextures(gl::TEXTURE_2D, 1, &mut self.image); + gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image); if size.width == 0 { size.width = 1; @@ -174,23 +142,23 @@ impl Framebuffer for Gl46Framebuffer { size.height = 1; } - self.levels = librashader_runtime::scaling::calc_miplevel(size); - if self.levels > self.max_levels { - self.levels = self.max_levels; + fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size); + if fb.mip_levels > fb.max_levels { + fb.mip_levels = fb.max_levels; } - if self.levels == 0 { - self.levels = 1; + if fb.mip_levels == 0 { + fb.mip_levels = 1; } gl::TextureStorage2D( - self.image, - self.levels as GLsizei, - self.format, + fb.image, + fb.mip_levels as GLsizei, + fb.format, size.width as GLsizei, size.height as GLsizei, ); - gl::NamedFramebufferTexture(self.handle, gl::COLOR_ATTACHMENT0, self.image, 0); + gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0); let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); if status != gl::FRAMEBUFFER_COMPLETE { @@ -198,32 +166,27 @@ impl Framebuffer for Gl46Framebuffer { 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); + gl::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, 0, 0); + gl::DeleteTextures(1, &fb.image); + gl::CreateTextures(gl::TEXTURE_2D, 1, &mut fb.image); - self.levels = librashader_runtime::scaling::calc_miplevel(size); - if self.levels > self.max_levels { - self.levels = self.max_levels; + fb.mip_levels = librashader_runtime::scaling::calc_miplevel(size); + if fb.mip_levels > fb.max_levels { + fb.mip_levels = fb.max_levels; } - if self.levels == 0 { - self.levels = 1; + if fb.mip_levels == 0 { + fb.mip_levels = 1; } gl::TextureStorage2D( - self.image, - self.levels as GLsizei, + fb.image, + fb.mip_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::NamedFramebufferTexture(fb.handle, gl::COLOR_ATTACHMENT0, fb.image, 0); + // fb.init = // gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; } _ => return Err(FilterChainError::FramebufferInit(status)), @@ -233,16 +196,3 @@ impl Framebuffer for Gl46Framebuffer { Ok(()) } } - -impl Drop for Gl46Framebuffer { - fn drop(&mut self) { - unsafe { - if self.handle != 0 { - gl::DeleteFramebuffers(1, &self.handle); - } - if self.image != 0 { - gl::DeleteTextures(1, &self.image); - } - } - } -} diff --git a/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs b/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs index 0828013..e9ca0c4 100644 --- a/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs +++ b/librashader-runtime-gl/src/gl/gl46/hello_triangle.rs @@ -10,7 +10,7 @@ use librashader_common::Size; use crate::filter_chain::FilterChain; use crate::framebuffer::{GLImage, Viewport}; use crate::gl::gl46::DirectStateAccessGL; -use crate::gl::{Framebuffer, GLInterface}; +use crate::gl::{FramebufferInterface, GLInterface}; const WIDTH: u32 = 900; const HEIGHT: u32 = 700; @@ -258,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; @@ -455,7 +455,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 = ::FramebufferInterface::new_from_raw( output_texture, output_framebuffer_handle, gl::RGBA8, diff --git a/librashader-runtime-gl/src/gl/gl46/mod.rs b/librashader-runtime-gl/src/gl/gl46/mod.rs index eb7e6ac..03178fa 100644 --- a/librashader-runtime-gl/src/gl/gl46/mod.rs +++ b/librashader-runtime-gl/src/gl/gl46/mod.rs @@ -16,7 +16,7 @@ use ubo_ring::*; pub struct DirectStateAccessGL; impl GLInterface for DirectStateAccessGL { - type Framebuffer = Gl46Framebuffer; + type FramebufferInterface = Gl46Framebuffer; type UboRing = Gl46UboRing<16>; type DrawQuad = Gl46DrawQuad; type LoadLut = Gl46LutLoad; diff --git a/librashader-runtime-gl/src/gl/mod.rs b/librashader-runtime-gl/src/gl/mod.rs index e7803d1..30b19f9 100644 --- a/librashader-runtime-gl/src/gl/mod.rs +++ b/librashader-runtime-gl/src/gl/mod.rs @@ -1,3 +1,4 @@ +mod framebuffer; pub(crate) mod gl3; pub(crate) mod gl46; @@ -6,6 +7,7 @@ use crate::error::Result; use crate::framebuffer::{GLImage, Viewport}; use crate::samplers::SamplerSet; use crate::texture::Texture; +pub use framebuffer::Framebuffer; use gl::types::{GLenum, GLuint}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_presets::{Scale2D, TextureConfig}; @@ -33,31 +35,26 @@ pub trait UboRing { ); } -pub trait Framebuffer { - fn new(max_levels: u32) -> Self; +pub trait FramebufferInterface { + fn new(max_levels: u32) -> Framebuffer; fn new_from_raw( texture: GLuint, handle: GLuint, format: GLenum, size: Size, miplevels: u32, - ) -> Self; - fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture; + ) -> Framebuffer; fn scale( - &mut self, + fb: &mut Framebuffer, 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 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; + fn clear(fb: &Framebuffer); + fn copy_from(fb: &mut Framebuffer, image: &GLImage) -> Result<()>; + fn init(fb: &mut Framebuffer, size: Size, format: impl Into) -> Result<()>; } pub trait BindTexture { @@ -65,7 +62,7 @@ pub trait BindTexture { } pub trait GLInterface { - type Framebuffer: Framebuffer; + type FramebufferInterface: FramebufferInterface; type UboRing: UboRing<16>; type DrawQuad: DrawQuad; type LoadLut: LoadLut; diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 6aacc86..d19b09d 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -1,5 +1,6 @@ #![feature(strict_provenance)] #![feature(type_alias_impl_trait)] +#![feature(let_chains)] mod binding; mod filter_chain; @@ -9,42 +10,29 @@ mod render_target; mod util; mod gl; -pub mod options; mod samplers; mod texture; +pub mod options; pub mod error; pub use filter_chain::FilterChain; pub use framebuffer::Viewport; - -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, - >; -} +pub use framebuffer::GLImage; #[cfg(test)] mod tests { use super::*; use crate::filter_chain::FilterChain; + use crate::options::FilterChainOptions; #[test] fn triangle_gl() { 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/vhs/VHSPro.slangp", Some(&FilterChainOptions { + gl_version: 0, + use_dsa: false, + })) // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None) .unwrap(); gl::gl3::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); @@ -54,7 +42,10 @@ mod tests { 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/vhs/VHSPro.slangp", Some(&FilterChainOptions { + gl_version: 0, + use_dsa: true, + })) // 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/options.rs b/librashader-runtime-gl/src/options.rs index a180c14..0853b77 100644 --- a/librashader-runtime-gl/src/options.rs +++ b/librashader-runtime-gl/src/options.rs @@ -8,4 +8,5 @@ pub struct FrameOptions { #[derive(Debug, Clone)] pub struct FilterChainOptions { pub gl_version: u16, + pub use_dsa: bool } diff --git a/librashader-runtime-gl/src/render_target.rs b/librashader-runtime-gl/src/render_target.rs index 094cd80..176e053 100644 --- a/librashader-runtime-gl/src/render_target.rs +++ b/librashader-runtime-gl/src/render_target.rs @@ -1,5 +1,5 @@ use crate::framebuffer::Viewport; -use crate::gl::Framebuffer; +use crate::gl::{Framebuffer, FramebufferInterface}; #[rustfmt::skip] static DEFAULT_MVP: &[f32; 16] = &[ @@ -10,15 +10,15 @@ static DEFAULT_MVP: &[f32; 16] = &[ ]; #[derive(Debug, Copy, Clone)] -pub(crate) struct RenderTarget<'a, T: Framebuffer> { +pub(crate) struct RenderTarget<'a> { pub mvp: &'a [f32; 16], - pub framebuffer: &'a T, + pub framebuffer: &'a Framebuffer, pub x: i32, pub y: i32, } -impl<'a, T: Framebuffer> RenderTarget<'a, T> { - pub fn new(backbuffer: &'a T, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self { +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, @@ -37,8 +37,8 @@ impl<'a, T: Framebuffer> RenderTarget<'a, T> { } } -impl<'a, T: Framebuffer> From<&Viewport<'a, T>> for RenderTarget<'a, T> { - fn from(value: &Viewport<'a, T>) -> Self { +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-gl/src/util.rs b/librashader-runtime-gl/src/util.rs index d4c4760..1c94575 100644 --- a/librashader-runtime-gl/src/util.rs +++ b/librashader-runtime-gl/src/util.rs @@ -101,6 +101,7 @@ pub fn gl_get_version() -> GlVersion { pub fn gl_u16_to_version(version: u16) -> GlVersion { match version { + 0 => gl_get_version(), 300 => GlVersion::V1_30, 310 => GlVersion::V1_40, 320 => GlVersion::V1_50, diff --git a/librashader/src/lib.rs b/librashader/src/lib.rs index 23e9e1a..136e0e5 100644 --- a/librashader/src/lib.rs +++ b/librashader/src/lib.rs @@ -31,18 +31,7 @@ pub mod targets { /// Shader runtime for OpenGL. pub mod runtime { - pub use librashader_runtime_gl::error; - pub use librashader_runtime_gl::options::*; - 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::*; - } + pub use librashader_runtime_gl::*; } }