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 {
uniform_semantics,
non_uniform_semantics: texture_semantics,
texture_semantics: texture_semantics,
};
Ok((passes, semantics))

View file

@ -1,8 +1,5 @@
use gl::types::GLint;
use librashader_reflect::reflect::semantics::{
MemberOffset, SemanticMap, TextureSemantics, VariableSemantics,
};
use std::hash::Hash;
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset};
#[derive(Debug)]
pub enum VariableLocation {
@ -25,24 +22,22 @@ pub struct UniformLocation<T> {
}
impl UniformLocation<GLint> {
pub fn is_fragment_valid(&self) -> bool {
self.fragment >= 0
}
// pub fn is_fragment_valid(&self) -> bool {
// self.fragment >= 0
// }
//
// pub fn is_vertex_valid(&self) -> bool {
// self.vertex >= 0
// }
pub fn is_vertex_valid(&self) -> bool {
self.vertex >= 0
}
pub fn is_valid(&self) -> bool {
self.is_fragment_valid() || self.is_vertex_valid()
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
}
}
#[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::render_target::RenderTarget;
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 gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use gl::types::{GLint, GLsizei, GLsizeiptr, GLuint};
use librashader_common::image::Image;
use librashader_common::{FilterMode, Size, WrapMode};
use librashader_preprocess::ShaderSource;
@ -22,6 +22,7 @@ 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;
@ -133,11 +134,14 @@ type ShaderPassMeta<'a> = (
impl FilterChain {
/// 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 version = options.map(|o| gl_u16_to_version(o.gl_version))
.unwrap_or_else(|| gl_get_version());
// 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_wrap = filters
@ -160,7 +164,7 @@ impl FilterChain {
feedback_textures.resize_with(filters.len(), Texture::default);
// load luts
let luts = FilterChain::load_luts(&samplers, &preset.textures)?;
let luts = FilterChain::load_luts(&preset.textures)?;
let (history_framebuffers, history_textures) =
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.
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
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset)
Self::load_from_preset(preset, options)
}
fn load_preset(
@ -260,13 +264,13 @@ impl FilterChain {
let semantics = ReflectSemantics {
uniform_semantics,
non_uniform_semantics: texture_semantics,
texture_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();
for (index, texture) in textures.iter().enumerate() {
@ -305,10 +309,6 @@ impl FilterChain {
);
let mipmap = levels > 1;
// let linear = texture.filter_mode == FilterMode::Linear;
// set mipmaps and wrapping
if mipmap {
gl::GenerateMipmap(gl::TEXTURE_2D);
}
@ -335,6 +335,7 @@ impl FilterChain {
}
fn init_passes(
version: GlVersion,
passes: Vec<ShaderPassMeta>,
semantics: &ReflectSemantics,
) -> Result<Box<[FilterPass]>> {
@ -343,7 +344,7 @@ impl FilterChain {
// initialize passes
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
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()?;
@ -444,7 +445,6 @@ impl FilterChain {
]
.into_boxed_slice();
// todo: reflect indexed parameters
let mut uniform_bindings = FxHashMap::default();
for param in reflection.meta.parameter_meta.values() {
uniform_bindings.insert(
@ -571,10 +571,12 @@ 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, clear: bool) -> Result<()> {
if clear {
for framebuffer in &self.history_framebuffers {
framebuffer.clear()
pub fn frame(&mut self, count: usize, viewport: &Viewport, input: &GlImage, options: Option<&FrameOptions>) -> Result<()> {
if let Some(options) = options {
if options.clear_history {
for framebuffer in &self.history_framebuffers {
framebuffer.clear()
}
}
}

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::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection;
@ -6,7 +6,7 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_common::{ShaderFormat, Size};
use librashader_preprocess::ShaderSource;
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 crate::binding::{UniformLocation, VariableLocation};
@ -31,19 +31,30 @@ pub struct FilterPass {
}
impl FilterPass {
fn build_mvp(buffer: &mut [u8], mvp: &[f32]) {
let mvp = bytemuck::cast_slice(mvp);
buffer.copy_from_slice(mvp);
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);
buffer.copy_from_slice(mvp);
}
}
fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: impl Into<[f32; 4]>) {
let vec4 = size.into();
if location.fragment >= 0 || location.vertex >= 0 {
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
unsafe {
if location.vertex >= 0 {
if location.is_valid(BindingStage::VERTEX) {
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());
}
}
@ -63,12 +74,12 @@ impl FilterPass {
T: Copy,
T: bytemuck::Pod,
{
if location.fragment >= 0 || location.vertex >= 0 {
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
unsafe {
if location.vertex >= 0 {
if location.is_valid(BindingStage::VERTEX) {
glfn(location.vertex, value);
}
if location.fragment >= 0 {
if location.is_valid(BindingStage::FRAGMENT) {
glfn(location.fragment, value);
}
}
@ -163,7 +174,7 @@ impl FilterPass {
if self.ubo_location.vertex != gl::INVALID_INDEX {
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);
}
}
@ -233,7 +244,7 @@ impl FilterPass {
&mut self,
pass_index: usize,
parent: &FilterCommon,
mvp: &[f32],
mvp: &[f32; 16],
frame_count: u32,
frame_direction: i32,
fb_size: Size<u32>,
@ -242,7 +253,7 @@ impl FilterPass {
source: &Texture,
) {
// Bind MVP
if let Some((_location, offset)) =
if let Some((location, offset)) =
self.uniform_bindings.get(&VariableSemantics::MVP.into())
{
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::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

View file

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

View file

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

View file

@ -20,6 +20,7 @@ pub use framebuffer::Viewport;
#[cfg(test)]
mod hello_triangle;
mod texture;
mod options;
#[cfg(test)]
mod tests {
@ -30,7 +31,7 @@ mod tests {
fn triangle_gl() {
let (glfw, window, events, shader, vao) = hello_triangle::setup();
let mut filter =
FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp")
FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp", None)
.unwrap();
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};
#[rustfmt::skip]
static DEFAULT_MVP: &[f32] = &[
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,
@ -10,14 +10,14 @@ static DEFAULT_MVP: &[f32] = &[
#[derive(Debug, Copy, Clone)]
pub struct RenderTarget<'a> {
pub mvp: &'a [f32],
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]>, 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 {
RenderTarget {
framebuffer: backbuffer,

View file

@ -1,8 +1,6 @@
use std::iter::Filter;
use gl::types::{GLenum, GLint, GLuint};
use rustc_hash::FxHashMap;
use librashader_common::{FilterMode, WrapMode};
use crate::error::Result;
pub struct SamplerSet {
// 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 librashader_common::{FilterMode, Size, WrapMode};
use librashader_common::Size;
use librashader_reflect::back::cross::GlVersion;
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
}
}