gl: cleanup and refactor

- allow frame and filterchain init to take optional config object by caller
- allow binding MVP as a uniform
This commit is contained in:
chyyran 2022-11-27 23:27:21 -05:00
parent 964da02c39
commit 9e2c914e57
11 changed files with 101 additions and 67 deletions

View file

@ -392,7 +392,7 @@ impl FilterChain {
let semantics = ReflectSemantics { let semantics = ReflectSemantics {
uniform_semantics, uniform_semantics,
non_uniform_semantics: texture_semantics, texture_semantics: texture_semantics,
}; };
Ok((passes, semantics)) Ok((passes, semantics))

View file

@ -1,8 +1,5 @@
use gl::types::GLint; use gl::types::GLint;
use librashader_reflect::reflect::semantics::{ use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset};
MemberOffset, SemanticMap, TextureSemantics, VariableSemantics,
};
use std::hash::Hash;
#[derive(Debug)] #[derive(Debug)]
pub enum VariableLocation { pub enum VariableLocation {
@ -25,24 +22,22 @@ pub struct UniformLocation<T> {
} }
impl UniformLocation<GLint> { impl UniformLocation<GLint> {
pub fn is_fragment_valid(&self) -> bool { // pub fn is_fragment_valid(&self) -> bool {
self.fragment >= 0 // self.fragment >= 0
} // }
//
// pub fn is_vertex_valid(&self) -> bool {
// self.vertex >= 0
// }
pub fn is_vertex_valid(&self) -> bool { pub fn is_valid(&self, stage: BindingStage) -> bool {
self.vertex >= 0 let mut validity = false;
if stage.contains(BindingStage::FRAGMENT) {
validity = validity || self.fragment >= 0;
} }
if stage.contains(BindingStage::VERTEX) {
pub fn is_valid(&self) -> bool { validity = validity || self.vertex >= 0;
self.is_fragment_valid() || self.is_vertex_valid() }
validity
} }
} }
#[derive(Debug, Copy, Clone)]
pub enum MemberLocation {
Offset(MemberOffset),
Uniform(UniformLocation<GLint>),
}
#[derive(Debug, Copy, Clone)]
pub struct TextureUnit<T>(T);

View file

@ -4,10 +4,10 @@ use crate::framebuffer::{Framebuffer, GlImage, Viewport};
use crate::quad_render::DrawQuad; use crate::quad_render::DrawQuad;
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::util; use crate::util;
use crate::util::{gl_get_version, InlineRingBuffer}; use crate::util::{gl_get_version, gl_u16_to_version, InlineRingBuffer};
use crate::error::{FilterChainError, Result}; use crate::error::{FilterChainError, Result};
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
use librashader_common::image::Image; use librashader_common::image::Image;
use librashader_common::{FilterMode, Size, WrapMode}; use librashader_common::{FilterMode, Size, WrapMode};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
@ -22,6 +22,7 @@ use std::collections::VecDeque;
use std::path::Path; use std::path::Path;
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation}; use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
use librashader_reflect::front::shaderc::GlslangCompilation; use librashader_reflect::front::shaderc::GlslangCompilation;
use crate::options::{FilterChainOptions, FrameOptions};
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::Texture;
@ -133,11 +134,14 @@ type ShaderPassMeta<'a> = (
impl FilterChain { impl FilterChain {
/// Load a filter chain from a pre-parsed `ShaderPreset`. /// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(preset: ShaderPreset) -> Result<FilterChain> { pub fn load_from_preset(preset: ShaderPreset, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
let (passes, semantics) = FilterChain::load_preset(&preset)?; let (passes, semantics) = FilterChain::load_preset(&preset)?;
let version = options.map(|o| gl_u16_to_version(o.gl_version))
.unwrap_or_else(|| gl_get_version());
// initialize passes // initialize passes
let filters = FilterChain::init_passes(passes, &semantics)?; let filters = FilterChain::init_passes(version, passes, &semantics)?;
let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
let default_wrap = filters let default_wrap = filters
@ -160,7 +164,7 @@ impl FilterChain {
feedback_textures.resize_with(filters.len(), Texture::default); feedback_textures.resize_with(filters.len(), Texture::default);
// load luts // load luts
let luts = FilterChain::load_luts(&samplers, &preset.textures)?; let luts = FilterChain::load_luts(&preset.textures)?;
let (history_framebuffers, history_textures) = let (history_framebuffers, history_textures) =
FilterChain::init_history(&filters, default_filter, default_wrap); FilterChain::init_history(&filters, default_filter, default_wrap);
@ -194,10 +198,10 @@ impl FilterChain {
} }
/// Load the shader preset at the given path into a filter chain. /// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(path: impl AsRef<Path>) -> Result<FilterChain> { pub fn load_from_path(path: impl AsRef<Path>, options: Option<&FilterChainOptions>) -> Result<FilterChain> {
// load passes from preset // load passes from preset
let preset = ShaderPreset::try_parse(path)?; let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset) Self::load_from_preset(preset, options)
} }
fn load_preset( fn load_preset(
@ -260,13 +264,13 @@ impl FilterChain {
let semantics = ReflectSemantics { let semantics = ReflectSemantics {
uniform_semantics, uniform_semantics,
non_uniform_semantics: texture_semantics, texture_semantics,
}; };
Ok((passes, semantics)) Ok((passes, semantics))
} }
fn load_luts(samplers: &SamplerSet, textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> { fn load_luts(textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
@ -305,10 +309,6 @@ impl FilterChain {
); );
let mipmap = levels > 1; let mipmap = levels > 1;
// let linear = texture.filter_mode == FilterMode::Linear;
// set mipmaps and wrapping
if mipmap { if mipmap {
gl::GenerateMipmap(gl::TEXTURE_2D); gl::GenerateMipmap(gl::TEXTURE_2D);
} }
@ -335,6 +335,7 @@ impl FilterChain {
} }
fn init_passes( fn init_passes(
version: GlVersion,
passes: Vec<ShaderPassMeta>, passes: Vec<ShaderPassMeta>,
semantics: &ReflectSemantics, semantics: &ReflectSemantics,
) -> Result<Box<[FilterPass]>> { ) -> Result<Box<[FilterPass]>> {
@ -343,7 +344,7 @@ impl FilterChain {
// initialize passes // initialize passes
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() { for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
let reflection = reflect.reflect(index, semantics)?; let reflection = reflect.reflect(index, semantics)?;
let glsl = reflect.compile(gl_get_version())?; let glsl = reflect.compile(version)?;
let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?; let vertex_resources = glsl.context.compiler.vertex.get_shader_resources()?;
@ -444,7 +445,6 @@ impl FilterChain {
] ]
.into_boxed_slice(); .into_boxed_slice();
// todo: reflect indexed parameters
let mut uniform_bindings = FxHashMap::default(); let mut uniform_bindings = FxHashMap::default();
for param in reflection.meta.parameter_meta.values() { for param in reflection.meta.parameter_meta.values() {
uniform_bindings.insert( uniform_bindings.insert(
@ -571,12 +571,14 @@ impl FilterChain {
/// Process a frame with the input image. /// Process a frame with the input image.
/// ///
/// When this frame returns, GL_FRAMEBUFFER is bound to 0. /// When this frame returns, GL_FRAMEBUFFER is bound to 0.
pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, clear: bool) -> Result<()> { pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, options: Option<&FrameOptions>) -> Result<()> {
if clear { if let Some(options) = options {
if options.clear_history {
for framebuffer in &self.history_framebuffers { for framebuffer in &self.history_framebuffers {
framebuffer.clear() framebuffer.clear()
} }
} }
}
if self.passes.is_empty() { if self.passes.is_empty() {
return Ok(()); return Ok(());

View file

@ -1,4 +1,4 @@
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
use librashader_reflect::back::cross::GlslangGlslContext; use librashader_reflect::back::cross::GlslangGlslContext;
use librashader_reflect::back::ShaderCompilerOutput; use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection; use librashader_reflect::reflect::ShaderReflection;
@ -6,7 +6,7 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_common::{ShaderFormat, Size}; use librashader_common::{ShaderFormat, Size};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig; use librashader_presets::ShaderPassConfig;
use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics}; use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use crate::binding::{UniformLocation, VariableLocation}; use crate::binding::{UniformLocation, VariableLocation};
@ -31,19 +31,30 @@ pub struct FilterPass {
} }
impl FilterPass { impl FilterPass {
fn build_mvp(buffer: &mut [u8], mvp: &[f32]) { fn build_mat4(location: UniformLocation<GLint>, buffer: &mut [u8], mvp: &[f32; 16]) {
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
unsafe {
if location.is_valid(BindingStage::VERTEX) {
gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mvp.as_ptr());
}
if location.is_valid(BindingStage::FRAGMENT) {
gl::UniformMatrix4fv(location.fragment, 1, gl::FALSE, mvp.as_ptr());
}
}
} else {
let mvp = bytemuck::cast_slice(mvp); let mvp = bytemuck::cast_slice(mvp);
buffer.copy_from_slice(mvp); buffer.copy_from_slice(mvp);
} }
}
fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: impl Into<[f32; 4]>) { fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: impl Into<[f32; 4]>) {
let vec4 = size.into(); let vec4 = size.into();
if location.fragment >= 0 || location.vertex >= 0 { if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
unsafe { unsafe {
if location.vertex >= 0 { if location.is_valid(BindingStage::VERTEX) {
gl::Uniform4fv(location.vertex, 1, vec4.as_ptr()); gl::Uniform4fv(location.vertex, 1, vec4.as_ptr());
} }
if location.fragment >= 0 { if location.is_valid(BindingStage::FRAGMENT) {
gl::Uniform4fv(location.fragment, 1, vec4.as_ptr()); gl::Uniform4fv(location.fragment, 1, vec4.as_ptr());
} }
} }
@ -63,12 +74,12 @@ impl FilterPass {
T: Copy, T: Copy,
T: bytemuck::Pod, T: bytemuck::Pod,
{ {
if location.fragment >= 0 || location.vertex >= 0 { if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
unsafe { unsafe {
if location.vertex >= 0 { if location.is_valid(BindingStage::VERTEX) {
glfn(location.vertex, value); glfn(location.vertex, value);
} }
if location.fragment >= 0 { if location.is_valid(BindingStage::FRAGMENT) {
glfn(location.fragment, value); glfn(location.fragment, value);
} }
} }
@ -163,7 +174,7 @@ impl FilterPass {
if self.ubo_location.vertex != gl::INVALID_INDEX { if self.ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer); gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer);
} }
if self.ubo_location.vertex != gl::INVALID_INDEX { if self.ubo_location.fragment != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer); gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer);
} }
} }
@ -233,7 +244,7 @@ impl FilterPass {
&mut self, &mut self,
pass_index: usize, pass_index: usize,
parent: &FilterCommon, parent: &FilterCommon,
mvp: &[f32], mvp: &[f32; 16],
frame_count: u32, frame_count: u32,
frame_direction: i32, frame_direction: i32,
fb_size: Size<u32>, fb_size: Size<u32>,
@ -242,7 +253,7 @@ impl FilterPass {
source: &Texture, source: &Texture,
) { ) {
// Bind MVP // Bind MVP
if let Some((_location, offset)) = if let Some((location, offset)) =
self.uniform_bindings.get(&VariableSemantics::MVP.into()) self.uniform_bindings.get(&VariableSemantics::MVP.into())
{ {
let mvp_size = mvp.len() * std::mem::size_of::<f32>(); let mvp_size = mvp.len() * std::mem::size_of::<f32>();
@ -250,7 +261,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset), MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
}; };
FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp) FilterPass::build_mat4(location.location(), &mut buffer[offset..][..mvp_size], mvp)
} }
// bind OutputSize // bind OutputSize

View file

@ -344,7 +344,7 @@ pub struct Viewport<'a> {
pub x: i32, pub x: i32,
pub y: i32, pub y: i32,
pub output: &'a Framebuffer, pub output: &'a Framebuffer,
pub mvp: Option<&'a [f32]>, pub mvp: Option<&'a [f32; 16]>,
} }
#[derive(Default, Debug, Copy, Clone)] #[derive(Default, Debug, Copy, Clone)]

View file

@ -517,7 +517,7 @@ void main()
padded_size: Default::default(), padded_size: Default::default(),
}; };
filter.frame(framecount, &viewport, &rendered, false) filter.frame(framecount, &viewport, &rendered, None)
.unwrap(); .unwrap();
unsafe { unsafe {

View file

@ -20,6 +20,7 @@ pub use framebuffer::Viewport;
#[cfg(test)] #[cfg(test)]
mod hello_triangle; mod hello_triangle;
mod texture; mod texture;
mod options;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -30,7 +31,7 @@ mod tests {
fn triangle_gl() { fn triangle_gl() {
let (glfw, window, events, shader, vao) = hello_triangle::setup(); let (glfw, window, events, shader, vao) = hello_triangle::setup();
let mut filter = let mut filter =
FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp") FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp", None)
.unwrap(); .unwrap();
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
} }

View file

@ -0,0 +1,11 @@
#[repr(C)]
#[derive(Debug, Clone)]
pub struct FrameOptions {
pub clear_history: bool
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct FilterChainOptions {
pub gl_version: u16
}

View file

@ -1,7 +1,7 @@
use crate::framebuffer::{Framebuffer, Viewport}; use crate::framebuffer::{Framebuffer, Viewport};
#[rustfmt::skip] #[rustfmt::skip]
static DEFAULT_MVP: &[f32] = &[ static DEFAULT_MVP: &[f32; 16] = &[
2f32, 0.0, 0.0, 0.0, 2f32, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0,
@ -10,14 +10,14 @@ static DEFAULT_MVP: &[f32] = &[
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct RenderTarget<'a> { pub struct RenderTarget<'a> {
pub mvp: &'a [f32], pub mvp: &'a [f32; 16],
pub framebuffer: &'a Framebuffer, pub framebuffer: &'a Framebuffer,
pub x: i32, pub x: i32,
pub y: i32 pub y: i32
} }
impl<'a> RenderTarget<'a> { impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32]>, x: i32, y: i32) -> Self { pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32; 16]>, x: i32, y: i32) -> Self {
if let Some(mvp) = mvp { if let Some(mvp) = mvp {
RenderTarget { RenderTarget {
framebuffer: backbuffer, framebuffer: backbuffer,

View file

@ -1,8 +1,6 @@
use std::iter::Filter;
use gl::types::{GLenum, GLint, GLuint}; use gl::types::{GLenum, GLint, GLuint};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use librashader_common::{FilterMode, WrapMode}; use librashader_common::{FilterMode, WrapMode};
use crate::error::Result;
pub struct SamplerSet { pub struct SamplerSet {
// todo: may need to deal with differences in mip filter. // todo: may need to deal with differences in mip filter.

View file

@ -1,6 +1,5 @@
use crate::framebuffer::GlImage;
use gl::types::{GLenum, GLuint}; use gl::types::{GLenum, GLuint};
use librashader_common::{FilterMode, Size, WrapMode}; use librashader_common::Size;
use librashader_reflect::back::cross::GlVersion; use librashader_reflect::back::cross::GlVersion;
pub fn calc_miplevel(size: Size<u32>) -> u32 { pub fn calc_miplevel(size: Size<u32>) -> u32 {
@ -111,3 +110,20 @@ pub fn gl_get_version() -> GlVersion {
} }
} }
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
}
}