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:
parent
964da02c39
commit
9e2c914e57
|
@ -392,7 +392,7 @@ impl FilterChain {
|
|||
|
||||
let semantics = ReflectSemantics {
|
||||
uniform_semantics,
|
||||
non_uniform_semantics: texture_semantics,
|
||||
texture_semantics: texture_semantics,
|
||||
};
|
||||
|
||||
Ok((passes, semantics))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -517,7 +517,7 @@ void main()
|
|||
padded_size: Default::default(),
|
||||
};
|
||||
|
||||
filter.frame(framecount, &viewport, &rendered, false)
|
||||
filter.frame(framecount, &viewport, &rendered, None)
|
||||
.unwrap();
|
||||
|
||||
unsafe {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
11
librashader-runtime-gl/src/options.rs
Normal file
11
librashader-runtime-gl/src/options.rs
Normal 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
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue