From d37fc0ccb5dfdbb1cc888ff4e3b0089096b97c17 Mon Sep 17 00:00:00 2001 From: chyyran Date: Mon, 14 Nov 2022 01:49:51 -0500 Subject: [PATCH] gl: clean up the huge lib.rs file --- Cargo.lock | 7 + README.md | 26 +- librashader-reflect/src/reflect/semantics.rs | 16 + librashader-runtime-gl/Cargo.toml | 3 +- librashader-runtime-gl/src/filter_pass.rs | 81 ++++ librashader-runtime-gl/src/framebuffer.rs | 126 +++++++ librashader-runtime-gl/src/lib.rs | 368 +++++-------------- librashader-runtime-gl/src/util.rs | 99 +++++ 8 files changed, 452 insertions(+), 274 deletions(-) create mode 100644 librashader-runtime-gl/src/filter_pass.rs create mode 100644 librashader-runtime-gl/src/framebuffer.rs create mode 100644 librashader-runtime-gl/src/util.rs diff --git a/Cargo.lock b/Cargo.lock index ac728aa..e50c624 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -97,6 +97,12 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c676a478f63e9fa2dd5368a42f28bba0d6c560b775f38583c8bbaa7fcd67c9c" +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + [[package]] name = "byteorder" version = "1.4.3" @@ -512,6 +518,7 @@ dependencies = [ name = "librashader-runtime-gl" version = "0.1.0" dependencies = [ + "bytemuck", "gl", "glfw", "librashader", diff --git a/README.md b/README.md index 82aa54e..ca82143 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,27 @@ # librashader -Pure Rust implementation of the RetroArch shader pipeline as a dynamic library. +A preprocessor, compiler, and runtime for RetroArch 'slang' shaders, rewritten in pure Rust. -Heavily WIP \ No newline at end of file +Heavily WIP. + +## License +**There is not yet a functioning implementation of librashader but this section outlines its licensing goals in contrast to +RetroArch.** + +While librashader is an independent reimplementation of the RetroArch shader pipeline, referencing the RetroArch source +code was indispensable to its creation. As it is therefore considered a derivative work, the core parts of librashader +such as the preprocessor, the preset parser, the reflection library, and the runtimes, are all licensed under GPLv3. + +The librashader C API, i.e. its headers and definitions, *not its implementation in `librashader_capi`*, +are unique to librashader and are more permissively licensed, and may allow you to use librashader in your permissively +licensed or proprietary project. + +While the code for `librashader_capi` (`librashader.so` and `rashader.dll`) is still under GPLv3, +you may use librashader in a non-GPL work by linking against the MIT licensed `librashader_ld`, +which implements the librashader C API, and thunks its calls to any `librashader.so` or `rashader.dll` +library found in the load path, *provided that `librashader.so` or `rashader.dll` are distributed under the restrictions +of GPLv3*. + +Note that if your project is not compatible with GPLv3, you **can not distribute `librashader.so` or `rashader.dll`** +alongside your project, **only `librashader-ld.so` or `rashader-ld.dll`**, which will do nothing without a librashader +implementation in the load path. The end user must obtain the implementation of librashader themselves. \ No newline at end of file diff --git a/librashader-reflect/src/reflect/semantics.rs b/librashader-reflect/src/reflect/semantics.rs index 10e0655..ad2ee94 100644 --- a/librashader-reflect/src/reflect/semantics.rs +++ b/librashader-reflect/src/reflect/semantics.rs @@ -22,6 +22,15 @@ pub enum VariableSemantics { FloatParameter = 5, } +impl VariableSemantics { + pub const fn semantics(self) -> SemanticMap { + SemanticMap { + semantics: self, + index: () + } + } +} + #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Copy, Clone, Hash)] #[repr(i32)] pub enum TextureSemantics { @@ -68,6 +77,13 @@ impl TextureSemantics { pub fn is_array(&self) -> bool { !matches!(self, TextureSemantics::Original | TextureSemantics::Source) } + + pub const fn semantics(self, index: u32) -> SemanticMap { + SemanticMap { + semantics: self, + index + } + } } pub struct TypeInfo { diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index 617f572..39e92ed 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -13,4 +13,5 @@ edition = "2021" spirv_cross = "0.23.1" rustc-hash = "1.1.0" gl = "0.14.0" -glfw = "0.47.0" \ No newline at end of file +glfw = "0.47.0" +bytemuck = "1.12.3" \ No newline at end of file diff --git a/librashader-runtime-gl/src/filter_pass.rs b/librashader-runtime-gl/src/filter_pass.rs new file mode 100644 index 0000000..6e8b38c --- /dev/null +++ b/librashader-runtime-gl/src/filter_pass.rs @@ -0,0 +1,81 @@ +use std::iter::Filter; +use gl::types::{GLint, GLuint}; +use librashader_reflect::back::cross::GlslangGlslContext; +use librashader_reflect::back::ShaderCompilerOutput; +use librashader_reflect::reflect::ShaderReflection; +use librashader_reflect::reflect::TextureSemanticMap; +use librashader_reflect::reflect::VariableSemanticMap; +use rustc_hash::FxHashMap; +use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableMeta, VariableSemantics}; +use crate::framebuffer::Framebuffer; +use crate::util::{Location, VariableLocation, RingBuffer, Size, Texture}; + +pub struct FilterPass { + pub reflection: ShaderReflection, + pub compiled: ShaderCompilerOutput, + pub program: GLuint, + pub ubo_location: Location, + pub ubo_ring: Option>, + pub uniform_buffer: Box<[u8]>, + pub push_buffer: Box<[u8]>, + pub locations: FxHashMap, + pub framebuffer: Framebuffer, + pub feedback_framebuffer: Framebuffer, +} + +impl FilterPass { + fn build_mvp(buffer: &mut [u8], mvp: &[f32]) { + let mvp = bytemuck::cast_slice(mvp); + buffer.copy_from_slice(mvp); + } + + fn build_vec4(buffer: &mut [u8], width: u32, height: u32) { + let vec4 = [width as f32, height as f32, 1.0 / width as f32, 1.0/ height as f32]; + let vec4 = bytemuck::cast_slice(&vec4); + + buffer.copy_from_slice(vec4); + } + + fn build_vec4_uniform(location: Location, width: u32, height: u32) { + let vec4 = [width as f32, height as f32, 1.0 / width as f32, 1.0/ height as f32]; + unsafe { + if location.vertex >= 0 { + gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); + } + if location.fragment >= 0 { + gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); + } + } + } + + fn build_semantics(&mut self, mvp: Option<&[f32]>, fb_size: Size, vp_size: Size, original: &Texture, source: &Texture) { + if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::MVP) { + let mvp = mvp.unwrap_or(&[ + 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 + ]); + + let (buffer, offset) = match variable.offset { + MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), + MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) + }; + FilterPass::build_mvp(&mut buffer[offset..][..mvp.len()], mvp) + } + + if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::Output) { + let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location(); + if location.fragment >= 0 || location.vertex >= 0 { + FilterPass::build_vec4_uniform(location, fb_size.width, fb_size.height); + } else { + let (buffer, offset) = match variable.offset { + MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset), + MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset) + }; + + FilterPass::build_vec4(&mut buffer[offset..][..4], fb_size.width, fb_size.height) + } + } + } +} \ No newline at end of file diff --git a/librashader-runtime-gl/src/framebuffer.rs b/librashader-runtime-gl/src/framebuffer.rs new file mode 100644 index 0000000..58f0d7b --- /dev/null +++ b/librashader-runtime-gl/src/framebuffer.rs @@ -0,0 +1,126 @@ +use gl::types::{GLenum, GLsizei, GLuint}; +use librashader::ShaderFormat; +use crate::util; +use crate::util::Size; + +pub struct Framebuffer { + pub image: GLuint, + pub size: Size, + pub format: GLenum, + pub max_levels: u32, + pub levels: u32, + pub framebuffer: GLuint, + pub init: bool +} + +impl Drop for Framebuffer { + fn drop(&mut self) { + if self.framebuffer != 0 { + unsafe { + gl::DeleteFramebuffers(1, &self.framebuffer); + } + } + + if self.image != 0 { + unsafe { + gl::DeleteTextures(1, &self.image); + } + } + } +} + +impl Framebuffer { + pub fn new(max_levels: u32) -> Framebuffer { + let mut framebuffer = 0; + unsafe { + gl::GenFramebuffers(1, &mut framebuffer); + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); + } + + Framebuffer { + image: 0, + size: Size { width: 1, height: 1 }, + format: 0, + max_levels, + levels: 0, + framebuffer, + init: false + } + } + + fn init(&mut self, mut size: Size, mut format: ShaderFormat) { + if format == ShaderFormat::Unknown { + format = ShaderFormat::R8G8B8A8Unorm; + } + + self.format = GLenum::from(format); + self.size = size; + + unsafe { + gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer); + + // reset the framebuffer image + if self.image != 0 { + gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); + gl::DeleteTextures(1, &self.image); + } + + gl::GenTextures(1, &mut self.image); + gl::BindTexture(1, self.image); + + if size.width == 0 { + size.width = 1; + } + if size.height == 0 { + size.height = 1; + } + + self.levels = util::calc_miplevel(size.width, size.height); + if self.levels > self.max_levels { + self.levels = self.max_levels; + } + if self.levels == 0 { + self.levels = 1; + } + + gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, self.format, size.width as GLsizei, size.height as GLsizei); + gl::FramebufferTexture2D(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); + + let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); + if status != gl::FRAMEBUFFER_COMPLETE { + match status { + gl::FRAMEBUFFER_UNSUPPORTED => { + eprintln!("unsupported fbo"); + + gl::FramebufferTexture2D(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); + gl::DeleteTextures(1, &self.image); + gl::GenTextures(1, &mut self.image); + gl::BindTexture(1, self.image); + + self.levels = util::calc_miplevel(size.width, size.height); + if self.levels > self.max_levels { + self.levels = self.max_levels; + } + if self.levels == 0 { + self.levels = 1; + } + + gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, gl::RGBA8, size.width as GLsizei, size.height as GLsizei); + gl::FramebufferTexture2D(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); + self.init = gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; + } + _ => panic!("failed to complete: {status}") + } + } else { + self.init = true; + } + + gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + gl::BindTexture(gl::TEXTURE_2D, 0); + } + } +} diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 87e8507..61c0bdc 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -1,5 +1,8 @@ mod hello_triangle; mod filter; +mod filter_pass; +mod util; +mod framebuffer; use std::collections::HashMap; use std::error::Error; @@ -9,8 +12,10 @@ use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; use glfw::Key::P; use rustc_hash::FxHashMap; use spirv_cross::spirv::Decoration; +use filter_pass::FilterPass; +use framebuffer::Framebuffer; -use librashader::{ShaderFormat, ShaderSource}; +use librashader::{FilterMode, ShaderFormat, ShaderSource, WrapMode}; use librashader_presets::{ShaderPassConfig, ShaderPreset}; use librashader_reflect::back::{CompileShader, ShaderCompilerOutput}; use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion}; @@ -20,6 +25,7 @@ use librashader_reflect::reflect::cross::CrossReflect; use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, ShaderReflection, UniformSemantic}; use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableMeta, VariableSemantics}; use librashader_reflect::reflect::{TextureSemanticMap, VariableSemanticMap}; +use util::{Location, VariableLocation, RingBuffer, Size, Texture, TextureMeta, Viewport}; unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { let shader = gl::CreateShader(stage); @@ -35,226 +41,76 @@ unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { shader } -fn load_pass_semantics(uniform_semantics: &mut FxHashMap, texture_semantics: &mut FxHashMap>, +impl FilterChain { + fn load_pass_semantics(uniform_semantics: &mut FxHashMap, texture_semantics: &mut FxHashMap>, config: &ShaderPassConfig) { - let Some(alias) = &config.alias else { - return; - }; + let Some(alias) = &config.alias else { + return; + }; - // Ignore empty aliases - if alias.trim().is_empty() { - return; + // Ignore empty aliases + if alias.trim().is_empty() { + return; + } + + let index = config.id as u32; + + // PassOutput + texture_semantics.insert(alias.clone(), SemanticMap { + semantics: TextureSemantics::PassOutput, + index + }); + uniform_semantics.insert(format!("{alias}Size"), UniformSemantic::Texture(SemanticMap { + semantics: TextureSemantics::PassOutput, + index + })); + + // PassFeedback + texture_semantics.insert(format!("{alias}Feedback"), SemanticMap { + semantics: TextureSemantics::PassFeedback, + index + }); + uniform_semantics.insert(format!("{alias}FeedbackSize"), UniformSemantic::Texture(SemanticMap { + semantics: TextureSemantics::PassFeedback, + index + })); } - let index = config.id as u32; + fn reflect_parameter(pipeline: GLuint, meta: &VariableMeta) -> VariableLocation { + // todo: support both ubo and pushco + // todo: fix this. + match meta.offset { + MemberOffset::Ubo(_) => { + let vert_name = format!("RARCH_UBO_VERTEX_INSTANCE.{}\0", meta.id); + let frag_name = format!("RARCH_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()); - // PassOutput - texture_semantics.insert(alias.clone(), SemanticMap { - semantics: TextureSemantics::PassOutput, - index - }); - uniform_semantics.insert(format!("{alias}Size"), UniformSemantic::Texture(SemanticMap { - semantics: TextureSemantics::PassOutput, - index - })); - - // PassFeedback - texture_semantics.insert(format!("{alias}Feedback"), SemanticMap { - semantics: TextureSemantics::PassFeedback, - index - }); - uniform_semantics.insert(format!("{alias}FeedbackSize"), UniformSemantic::Texture(SemanticMap { - semantics: TextureSemantics::PassFeedback, - index - })); - -} - -pub struct RingBuffer { - items: [T; SIZE], - index: usize -} - -impl RingBuffer -where T: Copy, T: Default -{ - pub fn new() -> Self { - Self { - items: [T::default(); SIZE], - index: 0 - } - } -} - -impl RingBuffer { - pub fn current(&self) -> &T { - &self.items[self.index] - } - - pub fn next(&mut self) { - self.index += 1; - if self.index >= SIZE { - self.index = 0 - } - } -} - - -#[derive(Debug)] -pub struct Location { - vertex: T, - fragment: T, -} - -#[derive(Debug)] -pub enum ParameterLocation { - Ubo(Location), - Push(Location), -} -pub struct FilterPass { - reflection: ShaderReflection, - compiled: ShaderCompilerOutput, - program: GLuint, - ubo_location: Location, - ubo_ring: Option>, - uniform_buffer: Vec, - push_buffer: Vec, - locations: FxHashMap, - framebuffer: Framebuffer, - feedback_framebuffer: Framebuffer, -} - -pub struct Framebuffer { - image: GLuint, - size: Size, - format: GLenum, - max_levels: u32, - levels: u32, - framebuffer: GLuint, - init: bool -} - -impl Drop for Framebuffer { - fn drop(&mut self) { - if self.framebuffer != 0 { - unsafe { - gl::DeleteFramebuffers(1, &self.framebuffer); - } - } - - if self.image != 0 { - unsafe { - gl::DeleteTextures(1, &self.image); - } - } - } -} -impl Framebuffer { - pub fn new(max_levels: u32) -> Framebuffer { - let mut framebuffer = 0; - unsafe { - gl::GenFramebuffers(1, &mut framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); - gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer); - } - - Framebuffer { - image: 0, - size: Size { width: 1, height: 1 }, - format: 0, - max_levels, - levels: 0, - framebuffer, - init: false - } - } - - fn init(&mut self, mut size: Size, mut format: ShaderFormat) { - if format == ShaderFormat::Unknown { - format = ShaderFormat::R8G8B8A8Unorm; - } - - self.format = GLenum::from(format); - self.size = size; - - unsafe { - gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer); - - // reset the framebuffer image - if self.image != 0 { - gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); - gl::DeleteTextures(1, &self.image); - } - - gl::GenTextures(1, &mut self.image); - gl::BindTexture(1, self.image); - - if size.width == 0 { - size.width = 1; - } - if size.height == 0 { - size.height = 1; - } - - self.levels = calc_miplevel(size.width, size.height); - if self.levels > self.max_levels { - self.levels = self.max_levels; - } - if self.levels == 0 { - self.levels = 1; - } - - gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, self.format, size.width as GLsizei, size.height as GLsizei); - gl::FramebufferTexture2D(gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); - - let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER); - if status != gl::FRAMEBUFFER_COMPLETE { - match status { - gl::FRAMEBUFFER_UNSUPPORTED => { - eprintln!("unsupported fbo"); - - gl::FramebufferTexture2D(gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); - gl::DeleteTextures(1, &self.image); - gl::GenTextures(1, &mut self.image); - gl::BindTexture(1, self.image); - - self.levels = calc_miplevel(size.width, size.height); - if self.levels > self.max_levels { - self.levels = self.max_levels; - } - if self.levels == 0 { - self.levels = 1; - } - - gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, gl::RGBA8, size.width as GLsizei, size.height as GLsizei); - gl::FramebufferTexture2D(gl::FRAMEBUFFER, - gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); - self.init = gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; - } - _ => panic!("failed to complete: {status}") + VariableLocation::Ubo(Location { + vertex, + fragment + }) } - } else { - self.init = true; } + MemberOffset::PushConstant(_) => { + let vert_name = format!("RARCH_PUSH_VERTEX_INSTANCE.{}\0", meta.id); + let frag_name = format!("RARCH_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()); - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::BindTexture(gl::TEXTURE_2D, 0); + VariableLocation::Push(Location { + vertex, + fragment + }) + } + } } } + } -pub fn calc_miplevel(width: u32, height: u32) -> u32 { - let mut size = std::cmp::max(width, height); - let mut levels = 0; - while size != 0 { - levels += 1; - size >>= 1; - } - - return levels; -} pub struct FilterChain { passes: Vec, semantics: ReflectSemantics, @@ -264,38 +120,6 @@ pub struct FilterChain { feedback: Vec } -pub fn reflect_parameter(pipeline: GLuint, meta: &VariableMeta) -> ParameterLocation { - // todo: support both ubo and pushco - // todo: fix this. - match meta.offset { - MemberOffset::Ubo(_) => { - let vert_name = format!("RARCH_UBO_VERTEX_INSTANCE.{}\0", meta.id); - let frag_name = format!("RARCH_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()); - - ParameterLocation::Ubo(Location { - vertex, - fragment - }) - } - } - MemberOffset::PushConstant(_) => { - let vert_name = format!("RARCH_PUSH_VERTEX_INSTANCE.{}\0", meta.id); - let frag_name = format!("RARCH_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()); - - ParameterLocation::Push(Location { - vertex, - fragment - }) - } - } - } -} impl FilterChain { pub fn load(path: impl AsRef) -> Result> { @@ -326,7 +150,7 @@ impl FilterChain { // todo: this can probably be extracted out. for details in &passes { - load_pass_semantics(&mut uniform_semantics, &mut texture_semantics, details.0) + FilterChain::load_pass_semantics(&mut uniform_semantics, &mut texture_semantics, details.0) } // add lut params @@ -405,8 +229,8 @@ impl FilterChain { let size = ubo.size; let mut ring: RingBuffer = RingBuffer::new(); unsafe { - gl::GenBuffers(16, ring.items.as_mut_ptr()); - for buffer in &ring.items { + gl::GenBuffers(16, ring.items_mut().as_mut_ptr()); + for buffer in ring.items() { gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer); gl::BufferData(gl::UNIFORM_BUFFER, size as GLsizeiptr, std::ptr::null(), gl::STREAM_DRAW); } @@ -417,17 +241,17 @@ impl FilterChain { None }; - let uniform_buffer = vec![0; reflection.ubo.as_ref().map(|ubo| ubo.size as usize).unwrap_or(0)]; - let push_buffer = vec![0; reflection.push_constant.as_ref().map(|push| push.size as usize).unwrap_or(0)]; + let uniform_buffer = vec![0; reflection.ubo.as_ref().map(|ubo| ubo.size as usize).unwrap_or(0)].into_boxed_slice(); + let push_buffer = vec![0; reflection.push_constant.as_ref().map(|push| push.size as usize).unwrap_or(0)].into_boxed_slice(); // todo: reflect indexed parameters let mut locations = FxHashMap::default(); for param in reflection.meta.parameter_meta.values() { - locations.insert(param.id.clone(), reflect_parameter(program, param)); + locations.insert(param.id.clone(), FilterChain::reflect_parameter(program, param)); } for param in reflection.meta.variable_meta.values() { - locations.insert(param.id.clone(), reflect_parameter(program, param)); + locations.insert(param.id.clone(), FilterChain::reflect_parameter(program, param)); } @@ -489,34 +313,36 @@ impl FilterChain { // how much info do we actually need? - fn frame(&mut self, count: u64, vp: &Viewport, input: &Texture, clear: bool) { + // fn frame(&mut self, count: u64, vp: &Viewport, input: &Texture, clear: bool) { + // + // // todo: make copy + // + // let original = Texture { + // handle: input.handle, + // format: self.preset.shaders.first()., + // size: Size {}, + // padded_size: Size {} + // }; + // // todo: deal with the mess that is frame history + // } + + fn do_final_pass(&mut self, count: u64, vp: &Viewport, input: Texture, clear: bool, mvp: &[f32]) { + + // todo: make copy + + // todo: get filter info from pass data. + let original = TextureMeta { + texture: input, + filter: gl::LINEAR, + mip_filter: gl::LINEAR_MIPMAP_LINEAR, + wrap_mode: Default::default() + }; + // todo: deal with the mess that is frame history } } -#[derive(Debug, Copy, Clone)] -struct Viewport { - x: i32, - y: i32, - width: i32, - height: i32 -} - -#[derive(Debug, Copy, Clone)] -struct Size { - width: u32, - height: u32, -} - -#[derive(Debug, Copy, Clone)] -struct Texture { - handle: GLuint, - format: GLenum, - size: Size, - padded_size: Size -} - #[cfg(test)] mod tests { diff --git a/librashader-runtime-gl/src/util.rs b/librashader-runtime-gl/src/util.rs new file mode 100644 index 0000000..62c7327 --- /dev/null +++ b/librashader-runtime-gl/src/util.rs @@ -0,0 +1,99 @@ +use gl::types::{GLenum, GLint, GLuint}; +use librashader::WrapMode; + +#[derive(Debug, Copy, Clone)] +pub struct Location { + pub vertex: T, + pub fragment: T, +} + +#[derive(Debug)] +pub enum VariableLocation { + Ubo(Location), + Push(Location), +} + +impl VariableLocation { + pub fn location(&self) -> Location { + match self { + VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l + } + } +} + +pub fn calc_miplevel(width: u32, height: u32) -> u32 { + let mut size = std::cmp::max(width, height); + let mut levels = 0; + while size != 0 { + levels += 1; + size >>= 1; + } + + return levels; +} + +pub struct TextureMeta { + pub texture: Texture, + pub filter: GLenum, + pub mip_filter: GLenum, + pub wrap_mode: WrapMode +} + +#[derive(Debug, Copy, Clone)] +pub struct Viewport { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32 +} + +#[derive(Debug, Copy, Clone)] +pub struct Size { + pub width: u32, + pub height: u32, +} + +#[derive(Debug, Copy, Clone)] +pub struct Texture { + pub handle: GLuint, + pub format: GLenum, + pub size: Size, + pub padded_size: Size +} + +impl RingBuffer { + pub fn current(&self) -> &T { + &self.items[self.index] + } + + pub fn next(&mut self) { + self.index += 1; + if self.index >= SIZE { + self.index = 0 + } + } +} + +pub struct RingBuffer { + items: [T; SIZE], + index: usize +} + +impl RingBuffer +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 + } +}