fmt: run rustfmt and clippy

This commit is contained in:
chyyran 2022-11-19 23:16:57 -05:00
parent e911d40429
commit 5ed6cc6e52
8 changed files with 790 additions and 375 deletions

View file

@ -1,7 +1,8 @@
use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use gl::types::GLint; use gl::types::GLint;
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, VariableSemantics}; use librashader_reflect::reflect::semantics::{
MemberOffset, SemanticMap, TextureSemantics, VariableSemantics,
};
use std::hash::Hash;
#[derive(Debug)] #[derive(Debug)]
pub enum VariableLocation { pub enum VariableLocation {
@ -12,7 +13,7 @@ pub enum VariableLocation {
impl VariableLocation { impl VariableLocation {
pub fn location(&self) -> UniformLocation<GLint> { pub fn location(&self) -> UniformLocation<GLint> {
match self { match self {
VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l,
} }
} }
} }
@ -40,7 +41,7 @@ impl UniformLocation<GLint> {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum MemberLocation { pub enum MemberLocation {
Offset(MemberOffset), Offset(MemberOffset),
Uniform(UniformLocation<GLint>) Uniform(UniformLocation<GLint>),
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]

View file

@ -1,33 +1,36 @@
use rustc_hash::FxHashMap;
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use librashader_presets::{ShaderPassConfig, ShaderPreset};
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureSemantics, UniformMeta, VariableSemantics};
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
use std::path::Path;
use std::error::Error;
use librashader::{FilterMode, ShaderSource};
use librashader_reflect::back::cross::GlVersion;
use librashader_reflect::back::targets::{FromCompilation, GLSL};
use spirv_cross::spirv::Decoration;
use librashader::image::Image;
use librashader_reflect::back::CompileShader;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation}; use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_pass::FilterPass; use crate::filter_pass::FilterPass;
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::util; use crate::util;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport}; use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport};
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use librashader::image::Image;
use librashader::{FilterMode, ShaderSource};
use librashader_presets::{ShaderPassConfig, ShaderPreset};
use librashader_reflect::back::cross::GlVersion;
use librashader_reflect::back::targets::{FromCompilation, GLSL};
use librashader_reflect::back::CompileShader;
use librashader_reflect::reflect::semantics::{
MemberOffset, SemanticMap, TextureSemantics, UniformMeta, VariableSemantics,
};
use librashader_reflect::reflect::{ReflectSemantics, ReflectShader, UniformSemantic};
use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration;
use std::error::Error;
use std::path::Path;
static QUAD_VBO_DATA: &'static [f32; 16] = &[ static QUAD_VBO_DATA: &[f32; 16] = &[
0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32, 0.0f32, 0.0f32, 1.0f32, 0.0f32, 1.0f32,
1.0f32, 0.0f32, 1.0f32, 0.0f32,
0.0f32, 1.0f32, 0.0f32, 1.0f32,
1.0f32, 1.0f32, 1.0f32, 1.0f32, 1.0f32, 1.0f32, 1.0f32, 1.0f32,
]; ];
impl FilterChain { impl FilterChain {
fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>, fn load_pass_semantics(
config: &ShaderPassConfig) { uniform_semantics: &mut FxHashMap<String, UniformSemantic>,
texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
config: &ShaderPassConfig,
) {
let Some(alias) = &config.alias else { let Some(alias) = &config.alias else {
return; return;
}; };
@ -40,24 +43,36 @@ impl FilterChain {
let index = config.id as usize; let index = config.id as usize;
// PassOutput // PassOutput
texture_semantics.insert(alias.clone(), SemanticMap { texture_semantics.insert(
semantics: TextureSemantics::PassOutput, alias.clone(),
index SemanticMap {
}); semantics: TextureSemantics::PassOutput,
uniform_semantics.insert(format!("{alias}Size"), UniformSemantic::Texture(SemanticMap { index,
semantics: TextureSemantics::PassOutput, },
index );
})); uniform_semantics.insert(
format!("{alias}Size"),
UniformSemantic::Texture(SemanticMap {
semantics: TextureSemantics::PassOutput,
index,
}),
);
// PassFeedback // PassFeedback
texture_semantics.insert(format!("{alias}Feedback"), SemanticMap { texture_semantics.insert(
semantics: TextureSemantics::PassFeedback, format!("{alias}Feedback"),
index SemanticMap {
}); semantics: TextureSemantics::PassFeedback,
uniform_semantics.insert(format!("{alias}FeedbackSize"), UniformSemantic::Texture(SemanticMap { index,
semantics: TextureSemantics::PassFeedback, },
index );
})); uniform_semantics.insert(
format!("{alias}FeedbackSize"),
UniformSemantic::Texture(SemanticMap {
semantics: TextureSemantics::PassFeedback,
index,
}),
);
} }
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation { fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
@ -71,10 +86,7 @@ impl FilterChain {
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
VariableLocation::Ubo(UniformLocation { VariableLocation::Ubo(UniformLocation { vertex, fragment })
vertex,
fragment
})
} }
} }
MemberOffset::PushConstant(_) => { MemberOffset::PushConstant(_) => {
@ -84,15 +96,11 @@ impl FilterChain {
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast()); let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast()); let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
VariableLocation::Push(UniformLocation { VariableLocation::Push(UniformLocation { vertex, fragment })
vertex,
fragment
})
} }
} }
} }
} }
} }
pub struct FilterChain { pub struct FilterChain {
@ -116,50 +124,66 @@ impl FilterChain {
pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> { pub fn load(path: impl AsRef<Path>) -> Result<FilterChain, Box<dyn Error>> {
let preset = ShaderPreset::try_parse(path)?; let preset = ShaderPreset::try_parse(path)?;
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default(); let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = Default::default(); let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default();
let mut passes: Vec<(&ShaderPassConfig, ShaderSource, _)> = preset.shaders.iter() let passes: Vec<(&ShaderPassConfig, ShaderSource, _)> = preset
.shaders
.iter()
.map(|shader| { .map(|shader| {
eprintln!("[gl] loading {}", &shader.name.display()); eprintln!("[gl] loading {}", &shader.name.display());
let source: ShaderSource = librashader_preprocess::load_shader_source(&shader.name) let source: ShaderSource =
.unwrap(); librashader_preprocess::load_shader_source(&shader.name).unwrap();
let spirv = librashader_reflect::front::shaderc::compile_spirv(&source) let spirv = librashader_reflect::front::shaderc::compile_spirv(&source).unwrap();
.unwrap(); let reflect = GLSL::from_compilation(spirv).unwrap();
let mut reflect = GLSL::from_compilation(spirv).unwrap();
for parameter in source.parameters.iter() { for parameter in source.parameters.iter() {
uniform_semantics.insert(parameter.id.clone(), UniformSemantic::Variable(SemanticMap { uniform_semantics.insert(
semantics: VariableSemantics::FloatParameter, parameter.id.clone(),
index: () UniformSemantic::Variable(SemanticMap {
})); semantics: VariableSemantics::FloatParameter,
index: (),
}),
);
} }
(shader, source, reflect) (shader, source, reflect)
}).collect(); })
.collect();
// todo: this can probably be extracted out. // todo: this can probably be extracted out.
for details in &passes { for details in &passes {
FilterChain::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 // add lut params
for (index, texture) in preset.textures.iter().enumerate() { for (index, texture) in preset.textures.iter().enumerate() {
texture_semantics.insert(texture.name.clone(), SemanticMap { texture_semantics.insert(
semantics: TextureSemantics::User, texture.name.clone(),
index SemanticMap {
}); semantics: TextureSemantics::User,
index,
},
);
uniform_semantics.insert(format!("{}Size", texture.name), UniformSemantic::Texture(SemanticMap { uniform_semantics.insert(
semantics: TextureSemantics::User, format!("{}Size", texture.name),
index UniformSemantic::Texture(SemanticMap {
})); semantics: TextureSemantics::User,
index,
}),
);
} }
let semantics = ReflectSemantics { let semantics = ReflectSemantics {
uniform_semantics, uniform_semantics,
non_uniform_semantics: texture_semantics non_uniform_semantics: texture_semantics,
}; };
let mut filters = Vec::new(); let mut filters = Vec::new();
@ -167,7 +191,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 mut semantics = semantics.clone(); let semantics = semantics.clone();
let reflection = reflect.reflect(index, &semantics)?; let reflection = reflect.reflect(index, &semantics)?;
let glsl = reflect.compile(GlVersion::V4_60)?; let glsl = reflect.compile(GlVersion::V4_60)?;
@ -184,7 +208,11 @@ impl FilterChain {
gl::AttachShader(program, fragment); gl::AttachShader(program, fragment);
for res in &vertex_resources.stage_inputs { for res in &vertex_resources.stage_inputs {
let loc = glsl.context.compiler.vertex.get_decoration(res.id, Decoration::Location)?; let loc = glsl
.context
.compiler
.vertex
.get_decoration(res.id, Decoration::Location)?;
let loc_name = format!("LIBRA_ATTRIBUTE_{loc}\0"); let loc_name = format!("LIBRA_ATTRIBUTE_{loc}\0");
eprintln!("{loc_name}"); eprintln!("{loc_name}");
gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast()) gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
@ -203,7 +231,8 @@ impl FilterChain {
for binding in &glsl.context.sampler_bindings { for binding in &glsl.context.sampler_bindings {
let loc_name = format!("LIBRA_TEXTURE_{}\0", *binding); let loc_name = format!("LIBRA_TEXTURE_{}\0", *binding);
let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast()); let location =
gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
if location >= 0 { if location >= 0 {
// eprintln!("setting sampler {location} to sample from {binding}"); // eprintln!("setting sampler {location} to sample from {binding}");
gl::Uniform1i(location, *binding as GLint); gl::Uniform1i(location, *binding as GLint);
@ -211,10 +240,19 @@ impl FilterChain {
} }
gl::UseProgram(0); gl::UseProgram(0);
(program, UniformLocation { (
vertex: gl::GetUniformBlockIndex(program, b"LIBRA_UBO_VERTEX\0".as_ptr().cast()), program,
fragment: gl::GetUniformBlockIndex(program, b"LIBRA_UBO_FRAGMENT\0".as_ptr().cast()), UniformLocation {
}) vertex: gl::GetUniformBlockIndex(
program,
b"LIBRA_UBO_VERTEX\0".as_ptr().cast(),
),
fragment: gl::GetUniformBlockIndex(
program,
b"LIBRA_UBO_FRAGMENT\0".as_ptr().cast(),
),
},
)
}; };
let ubo_ring = if let Some(ubo) = &reflection.ubo { let ubo_ring = if let Some(ubo) = &reflection.ubo {
@ -224,7 +262,12 @@ impl FilterChain {
gl::GenBuffers(16, ring.items_mut().as_mut_ptr()); gl::GenBuffers(16, ring.items_mut().as_mut_ptr());
for buffer in ring.items() { for buffer in ring.items() {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer); gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferData(gl::UNIFORM_BUFFER, size as GLsizeiptr, std::ptr::null(), gl::STREAM_DRAW); gl::BufferData(
gl::UNIFORM_BUFFER,
size as GLsizeiptr,
std::ptr::null(),
gl::STREAM_DRAW,
);
} }
gl::BindBuffer(gl::UNIFORM_BUFFER, 0); gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
} }
@ -233,24 +276,55 @@ impl FilterChain {
None None
}; };
let uniform_buffer = vec![0; reflection.ubo.as_ref().map(|ubo| ubo.size as usize).unwrap_or(0)].into_boxed_slice(); let uniform_buffer = vec![
let push_buffer = vec![0; reflection.push_constant.as_ref().map(|push| push.size as usize).unwrap_or(0)].into_boxed_slice(); 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 // todo: reflect indexed parameters
let mut locations = FxHashMap::default(); let mut locations = FxHashMap::default();
for param in reflection.meta.parameter_meta.values() { for param in reflection.meta.parameter_meta.values() {
locations.insert(UniformBinding::Parameter(param.id.clone()), locations.insert(
(FilterChain::reflect_uniform_location(program, param), param.offset)); UniformBinding::Parameter(param.id.clone()),
(
FilterChain::reflect_uniform_location(program, param),
param.offset,
),
);
} }
for (semantics, param) in &reflection.meta.variable_meta { for (semantics, param) in &reflection.meta.variable_meta {
locations.insert(UniformBinding::SemanticVariable(semantics.clone()), locations.insert(
(FilterChain::reflect_uniform_location(program, param), param.offset)); UniformBinding::SemanticVariable(*semantics),
(
FilterChain::reflect_uniform_location(program, param),
param.offset,
),
);
} }
for (semantics, param) in &reflection.meta.texture_size_meta { for (semantics, param) in &reflection.meta.texture_size_meta {
locations.insert(UniformBinding::TextureSize(semantics.clone()), locations.insert(
(FilterChain::reflect_uniform_location(program, param), param.offset)); UniformBinding::TextureSize(*semantics),
(
FilterChain::reflect_uniform_location(program, param),
param.offset,
),
);
} }
// need output framebuffers. // need output framebuffers.
@ -275,7 +349,7 @@ impl FilterChain {
push_buffer, push_buffer,
variable_bindings: locations, variable_bindings: locations,
source, source,
config: config.clone() config: config.clone(),
}); });
} }
@ -294,15 +368,28 @@ impl FilterChain {
unsafe { unsafe {
gl::GenTextures(1, &mut handle); gl::GenTextures(1, &mut handle);
gl::BindTexture(gl::TEXTURE_2D, handle); gl::BindTexture(gl::TEXTURE_2D, handle);
gl::TexStorage2D(gl::TEXTURE_2D, levels as GLsizei, gl::RGBA8, gl::TexStorage2D(
image.width as GLsizei, image.height as GLsizei); gl::TEXTURE_2D,
levels as GLsizei,
gl::RGBA8,
image.width as GLsizei,
image.height as GLsizei,
);
gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0); gl::PixelStorei(gl::UNPACK_ROW_LENGTH, 0);
gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4); gl::PixelStorei(gl::UNPACK_ALIGNMENT, 4);
gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0); gl::BindBuffer(gl::PIXEL_UNPACK_BUFFER, 0);
gl::TexSubImage2D(gl::TEXTURE_2D, 0, 0, 0, gl::TexSubImage2D(
image.width as GLsizei, image.height as GLsizei, gl::TEXTURE_2D,
gl::RGBA, gl::UNSIGNED_BYTE, image.bytes.as_ptr().cast()); 0,
0,
0,
image.width as GLsizei,
image.height as GLsizei,
gl::RGBA,
gl::UNSIGNED_BYTE,
image.bytes.as_ptr().cast(),
);
let mipmap = levels > 1; let mipmap = levels > 1;
let linear = texture.filter_mode == FilterMode::Linear; let linear = texture.filter_mode == FilterMode::Linear;
@ -313,8 +400,16 @@ impl FilterChain {
gl::GenerateMipmap(gl::TEXTURE_2D); gl::GenerateMipmap(gl::TEXTURE_2D);
} }
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, GLenum::from(texture.wrap_mode) as GLint); gl::TexParameteri(
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, GLenum::from(texture.wrap_mode) as GLint); gl::TEXTURE_2D,
gl::TEXTURE_WRAP_S,
GLenum::from(texture.wrap_mode) as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_T,
GLenum::from(texture.wrap_mode) as GLint,
);
if !linear { if !linear {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
@ -322,39 +417,52 @@ impl FilterChain {
} else { } else {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
if mipmap { if mipmap {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::TexParameteri(
gl::LINEAR_MIPMAP_LINEAR as GLint); gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
gl::LINEAR_MIPMAP_LINEAR as GLint,
);
} else { } else {
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::TexParameteri(
gl::LINEAR as GLint); gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
gl::LINEAR as GLint,
);
} }
} }
gl::BindTexture(gl::TEXTURE_2D, 0); gl::BindTexture(gl::TEXTURE_2D, 0);
} }
luts.insert(index, Texture { luts.insert(
image: GlImage { index,
handle, Texture {
format: gl::RGBA8, image: GlImage {
size: Size { handle,
width: image.width, format: gl::RGBA8,
height: image.height size: Size {
width: image.width,
height: image.height,
},
padded_size: Size::default(),
}, },
padded_size: Size::default() filter: texture.filter_mode,
mip_filter: texture.filter_mode,
wrap_mode: texture.wrap_mode,
}, },
filter: texture.filter_mode, );
mip_filter: texture.filter_mode,
wrap_mode: texture.wrap_mode
});
} }
let mut quad_vbo = 0; let mut quad_vbo = 0;
unsafe { unsafe {
gl::GenBuffers(1, &mut quad_vbo); gl::GenBuffers(1, &mut quad_vbo);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbo); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbo);
gl::BufferData(gl::ARRAY_BUFFER, std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr, gl::BufferData(
QUAD_VBO_DATA.as_ptr().cast(), gl::STATIC_DRAW); gl::ARRAY_BUFFER,
std::mem::size_of_val(QUAD_VBO_DATA) as GLsizeiptr,
QUAD_VBO_DATA.as_ptr().cast(),
gl::STATIC_DRAW,
);
gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0);
} }
@ -375,11 +483,11 @@ impl FilterChain {
luts, luts,
outputs: output_framebuffers, outputs: output_framebuffers,
quad_vbo, quad_vbo,
} },
}) })
} }
pub fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, clear: bool) { pub fn frame(&mut self, count: u32, vp: &Viewport, input: GlImage, _clear: bool) {
if self.passes.is_empty() { if self.passes.is_empty() {
return; return;
} }
@ -391,17 +499,29 @@ impl FilterChain {
// todo: copy framebuffer // todo: copy framebuffer
// shader_gl3: 2067 // shader_gl3: 2067
let filter = self.common.preset.shaders.first().map(|f| f.filter).unwrap_or_default(); let filter = self
let wrap_mode = self.common.preset.shaders.first().map(|f| f.wrap_mode).unwrap_or_default(); .common
.preset
.shaders
.first()
.map(|f| f.filter)
.unwrap_or_default();
let wrap_mode = self
.common
.preset
.shaders
.first()
.map(|f| f.wrap_mode)
.unwrap_or_default();
let original = Texture { let original = Texture {
image: input, image: input,
filter, filter,
mip_filter: filter, mip_filter: filter,
wrap_mode wrap_mode,
}; };
let mut source = original.clone(); let mut source = original;
let passes_len = self.passes.len(); let passes_len = self.passes.len();
let (pass, last) = self.passes.split_at_mut(passes_len - 1); let (pass, last) = self.passes.split_at_mut(passes_len - 1);
@ -409,10 +529,24 @@ impl FilterChain {
for (index, pass) in pass.iter_mut().enumerate() { for (index, pass) in pass.iter_mut().enumerate() {
{ {
let target = &mut self.common.outputs[index]; let target = &mut self.common.outputs[index];
let framebuffer_size = target.scale(pass.config.scaling.clone(), pass.get_format(), vp, &original, &source); let _framebuffer_size = target.scale(
pass.config.scaling.clone(),
pass.get_format(),
vp,
&original,
&source,
);
} }
let target = &self.common.outputs[index]; let target = &self.common.outputs[index];
pass.draw(&self.common, count, 1, vp, &original, &source, RenderTarget::new(target, None)); pass.draw(
&self.common,
count,
1,
vp,
&original,
&source,
RenderTarget::new(target, None),
);
let target = target.as_texture(pass.config.filter, pass.config.wrap_mode); let target = target.as_texture(pass.config.filter, pass.config.wrap_mode);
// todo: update-pass-outputs // todo: update-pass-outputs
@ -424,7 +558,15 @@ impl FilterChain {
for pass in last { for pass in last {
source.filter = pass.config.filter; source.filter = pass.config.filter;
source.mip_filter = pass.config.filter; source.mip_filter = pass.config.filter;
pass.draw(&self.common, count, 1, vp, &original, &source, RenderTarget::new(&vp.output, vp.mvp)); pass.draw(
&self.common,
count,
1,
vp,
&original,
&source,
RenderTarget::new(vp.output, vp.mvp),
);
} }
unsafe { unsafe {

View file

@ -1,20 +1,19 @@
use std::borrow::Borrow;
use std::iter::Filter;
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint}; use gl::types::{GLenum, 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;
use librashader_reflect::reflect::TextureSemanticMap;
use librashader_reflect::reflect::VariableSemanticMap;
use rustc_hash::FxHashMap;
use librashader::{ShaderFormat, ShaderSource}; use librashader::{ShaderFormat, ShaderSource};
use librashader_presets::{Scale2D, ScaleType, Scaling, ShaderPassConfig, ShaderPreset}; use librashader_presets::ShaderPassConfig;
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureImage, TextureSemantics, VariableMeta, VariableSemantics}; use librashader_reflect::reflect::semantics::{
use crate::framebuffer::Framebuffer; MemberOffset, TextureImage, TextureSemantics, VariableSemantics,
};
use rustc_hash::FxHashMap;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation}; use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::filter_chain::{FilterChain, FilterCommon}; use crate::filter_chain::FilterCommon;
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::util::{GlImage, RingBuffer, Size, Texture, Viewport}; use crate::util::{RingBuffer, Size, Texture, Viewport};
pub struct FilterPass { pub struct FilterPass {
pub reflection: ShaderReflection, pub reflection: ShaderReflection,
@ -26,7 +25,7 @@ pub struct FilterPass {
pub push_buffer: Box<[u8]>, pub push_buffer: Box<[u8]>,
pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>, pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub source: ShaderSource, pub source: ShaderSource,
pub config: ShaderPassConfig pub config: ShaderPassConfig,
} }
impl FilterPass { impl FilterPass {
@ -36,7 +35,12 @@ impl FilterPass {
} }
fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: Size) { fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: Size) {
let vec4 = [size.width as f32, size.height as f32, 1.0 / size.width as f32, 1.0/ size.height as f32]; let vec4 = [
size.width as f32,
size.height as f32,
1.0 / size.width as f32,
1.0 / size.height as f32,
];
if location.fragment >= 0 || location.vertex >= 0 { if location.fragment >= 0 || location.vertex >= 0 {
unsafe { unsafe {
if location.vertex >= 0 { if location.vertex >= 0 {
@ -53,8 +57,14 @@ impl FilterPass {
} }
#[inline(always)] #[inline(always)]
fn build_uniform<T>(location: UniformLocation<GLint>, buffer: &mut [u8], value: T, glfn: unsafe fn(GLint, T) -> ()) fn build_uniform<T>(
where T: Copy, T: bytemuck::Pod location: UniformLocation<GLint>,
buffer: &mut [u8],
value: T,
glfn: unsafe fn(GLint, T) -> (),
) where
T: Copy,
T: bytemuck::Pod,
{ {
if location.fragment >= 0 || location.vertex >= 0 { if location.fragment >= 0 || location.vertex >= 0 {
unsafe { unsafe {
@ -66,7 +76,7 @@ impl FilterPass {
} }
} }
} else { } else {
let mut buffer = bytemuck::cast_slice_mut(buffer); let buffer = bytemuck::cast_slice_mut(buffer);
buffer[0] = value; buffer[0] = value;
} }
} }
@ -89,10 +99,26 @@ impl FilterPass {
gl::ActiveTexture(gl::TEXTURE0 + binding.binding); gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle); gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, GLenum::from(texture.filter) as GLint); gl::TexParameteri(
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, texture.filter.gl_mip(texture.mip_filter) as GLint); gl::TEXTURE_2D,
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, GLenum::from(texture.wrap_mode) as GLint); gl::TEXTURE_MAG_FILTER,
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, GLenum::from(texture.wrap_mode) as GLint); GLenum::from(texture.filter) as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
texture.filter.gl_mip(texture.mip_filter) as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_S,
GLenum::from(texture.wrap_mode) as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_T,
GLenum::from(texture.wrap_mode) as GLint,
);
} }
} }
@ -107,9 +133,16 @@ impl FilterPass {
} }
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo) // todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn draw(&mut self, parent: &FilterCommon, frame_count: u32, pub fn draw(
frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: RenderTarget) { &mut self,
parent: &FilterCommon,
frame_count: u32,
frame_direction: i32,
viewport: &Viewport,
original: &Texture,
source: &Texture,
output: RenderTarget,
) {
let framebuffer = output.framebuffer; let framebuffer = output.framebuffer;
unsafe { unsafe {
@ -117,18 +150,33 @@ impl FilterPass {
gl::UseProgram(self.program); gl::UseProgram(self.program);
} }
self.build_semantics(parent, output.mvp, frame_count, frame_direction, framebuffer.size, viewport, original, source); self.build_semantics(
parent,
output.mvp,
frame_count,
frame_direction,
framebuffer.size,
viewport,
original,
source,
);
// shader_gl3:1514 // shader_gl3:1514
if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX { if self.ubo_location.vertex != gl::INVALID_INDEX
&& self.ubo_location.fragment != gl::INVALID_INDEX
{
if let (Some(ubo), Some(ring)) = (&self.reflection.ubo, &mut self.ubo_ring) { if let (Some(ubo), Some(ring)) = (&self.reflection.ubo, &mut self.ubo_ring) {
let size = ubo.size; let size = ubo.size;
let buffer = ring.current(); let buffer = ring.current();
unsafe { unsafe {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer); gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferSubData(gl::UNIFORM_BUFFER, 0, size as GLsizeiptr, gl::BufferSubData(
self.uniform_buffer.as_ptr().cast()); gl::UNIFORM_BUFFER,
0,
size as GLsizeiptr,
self.uniform_buffer.as_ptr().cast(),
);
gl::BindBuffer(gl::UNIFORM_BUFFER, 0); gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
if self.ubo_location.vertex != gl::INVALID_INDEX { if self.ubo_location.vertex != gl::INVALID_INDEX {
@ -150,7 +198,12 @@ impl FilterPass {
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32); gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
// //
gl::Viewport(0, 0, framebuffer.size.width as GLsizei, framebuffer.size.height as GLsizei); gl::Viewport(
0,
0,
framebuffer.size.width as GLsizei,
framebuffer.size.height as GLsizei,
);
if framebuffer.format == gl::SRGB8_ALPHA8 { if framebuffer.format == gl::SRGB8_ALPHA8 {
gl::Enable(gl::FRAMEBUFFER_SRGB); gl::Enable(gl::FRAMEBUFFER_SRGB);
@ -170,13 +223,24 @@ impl FilterPass {
/// the provided pointers are of OpenGL provenance with respect to the buffer bound to quad_vbo, /// the provided pointers are of OpenGL provenance with respect to the buffer bound to quad_vbo,
/// and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers. /// and not a known provenance to the Rust abstract machine, therefore we give it invalid pointers.
/// that are inexpressible in Rust /// that are inexpressible in Rust
gl::VertexAttribPointer(0, 2, gl::FLOAT, gl::FALSE, (4 * std::mem::size_of::<f32>()) as GLsizei, gl::VertexAttribPointer(
std::ptr::invalid(0)); 0,
gl::VertexAttribPointer(1, 2, gl::FLOAT, gl::FALSE, (4 * std::mem::size_of::<f32>()) as GLsizei, 2,
std::ptr::invalid(2 * std::mem::size_of::<f32>())); gl::FLOAT,
gl::FALSE,
(4 * std::mem::size_of::<f32>()) as GLsizei,
std::ptr::invalid(0),
);
gl::VertexAttribPointer(
1,
2,
gl::FLOAT,
gl::FALSE,
(4 * std::mem::size_of::<f32>()) as GLsizei,
std::ptr::invalid(2 * std::mem::size_of::<f32>()),
);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
gl::BindBuffer(gl::ARRAY_BUFFER, 0); gl::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::DisableVertexAttribArray(0); gl::DisableVertexAttribArray(0);
gl::DisableVertexAttribArray(1); gl::DisableVertexAttribArray(1);
@ -185,78 +249,133 @@ impl FilterPass {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
} }
// todo: draw image onto fbo // todo: draw image onto fbo
// shader_gl3 1579 // shader_gl3 1579
} }
// framecount should be pre-modded // framecount should be pre-modded
fn build_semantics(&mut self, parent: &FilterCommon, mvp: &[f32], frame_count: u32, frame_direction: i32, fb_size: Size, viewport: &Viewport, original: &Texture, source: &Texture) { fn build_semantics(
if let Some((_location, offset)) = self.variable_bindings.get(&VariableSemantics::MVP.into()) { &mut self,
let mvp_size = mvp.len() * std::mem::size_of::<f32>(); parent: &FilterCommon,
let (buffer, offset) = match offset { mvp: &[f32],
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset), frame_count: u32,
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset) frame_direction: i32,
}; fb_size: Size,
FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp) viewport: &Viewport,
} original: &Texture,
source: &Texture,
if let Some((location, offset)) = self.variable_bindings.get(&VariableSemantics::Output.into()) { ) {
if let Some((_location, offset)) =
self.variable_bindings.get(&VariableSemantics::MVP.into())
{
let mvp_size = mvp.len() * std::mem::size_of::<f32>();
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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)
}
if let Some((location, offset)) = self
.variable_bindings
.get(&VariableSemantics::Output.into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
}; };
FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], fb_size) FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], fb_size)
} }
if let Some((location, offset)) = self.variable_bindings.get(&VariableSemantics::FinalViewport.into()) { if let Some((location, offset)) = self
.variable_bindings
.get(&VariableSemantics::FinalViewport.into())
{
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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_vec4(location.location(), &mut buffer[offset..][..4], viewport.output.size) FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..4],
viewport.output.size,
)
} }
if let Some((location, offset)) = self.variable_bindings.get(&VariableSemantics::FrameCount.into()) { if let Some((location, offset)) = self
.variable_bindings
.get(&VariableSemantics::FrameCount.into())
{
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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_uint(location.location(), &mut buffer[offset..][..4], frame_count) FilterPass::build_uint(location.location(), &mut buffer[offset..][..4], frame_count)
} }
if let Some((location, offset)) = self.variable_bindings.get(&VariableSemantics::FrameDirection.into()) { if let Some((location, offset)) = self
.variable_bindings
.get(&VariableSemantics::FrameDirection.into())
{
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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_sint(location.location(), &mut buffer[offset..][..4], frame_direction) FilterPass::build_sint(
location.location(),
&mut buffer[offset..][..4],
frame_direction,
)
} }
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Original.semantics(0)) { if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::Original.semantics(0))
{
eprintln!("setting original binding to {}", binding.binding); eprintln!("setting original binding to {}", binding.binding);
FilterPass::bind_texture(binding, original); FilterPass::bind_texture(binding, original);
} }
if let Some((location, offset)) = self.variable_bindings.get(&TextureSemantics::Original.semantics(0).into()) { if let Some((location, offset)) = self
.variable_bindings
.get(&TextureSemantics::Original.semantics(0).into())
{
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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_vec4(location.location(), &mut buffer[offset..][..4], original.image.size); FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..4],
original.image.size,
);
} }
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Source.semantics(0)) { if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::Source.semantics(0))
{
// eprintln!("setting source binding to {}", binding.binding); // eprintln!("setting source binding to {}", binding.binding);
FilterPass::bind_texture(binding, source); FilterPass::bind_texture(binding, source);
} }
if let Some((location, offset)) = self.variable_bindings.get(&TextureSemantics::Source.semantics(0).into()) { if let Some((location, offset)) = self
.variable_bindings
.get(&TextureSemantics::Source.semantics(0).into())
{
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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_vec4(location.location(), &mut buffer[offset..][..4], source.image.size); FilterPass::build_vec4(
location.location(),
&mut buffer[offset..][..4],
source.image.size,
);
} }
// // todo: history // // todo: history
@ -273,60 +392,72 @@ impl FilterPass {
// // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size); // // FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
// // } // // }
// //
for (id, (location, offset)) in self.variable_bindings.iter() for (id, (location, offset)) in
.filter_map(|(binding, value)| match binding { self.variable_bindings
UniformBinding::Parameter(id) => { .iter()
Some((id, value)) .filter_map(|(binding, value)| match binding {
} UniformBinding::Parameter(id) => Some((id, value)),
_ => None _ => None,
}) })
{ {
let id = id.as_str(); let id = id.as_str();
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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),
}; };
// presets override params // presets override params
let default = self.source.parameters.iter().find(|&p| p.id == id) let default = self
.source
.parameters
.iter()
.find(|&p| p.id == id)
.map(|f| f.initial) .map(|f| f.initial)
.unwrap_or(0f32); .unwrap_or(0f32);
let value = parent.preset.parameters.iter().find(|&p| p.name == id) let value = parent
.preset
.parameters
.iter()
.find(|&p| p.name == id)
.map(|p| p.value) .map(|p| p.value)
.unwrap_or(default); .unwrap_or(default);
FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value) FilterPass::build_float(location.location(), &mut buffer[offset..][..4], value)
} }
for (id, (location, offset)) in self.variable_bindings.iter() for (id, (location, offset)) in
.filter_map(|(binding, value)| match binding { self.variable_bindings
UniformBinding::TextureSize(semantics) => { .iter()
if semantics.semantics == TextureSemantics::User { .filter_map(|(binding, value)| match binding {
Some((semantics, value)) UniformBinding::TextureSize(semantics) => {
} else { if semantics.semantics == TextureSemantics::User {
None Some((semantics, value))
} else {
None
}
} }
} _ => None,
_ => None })
})
{ {
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
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),
}; };
if let Some(lut) = parent.luts.get(&id.index) { if let Some(lut) = parent.luts.get(&id.index) {
if let Some(binding) = self.reflection.meta.texture_meta.get(&id) { if let Some(binding) = self.reflection.meta.texture_meta.get(id) {
FilterPass::bind_texture(binding, lut); FilterPass::bind_texture(binding, lut);
} }
FilterPass::build_vec4(location.location(), &mut buffer[offset..][..4], FilterPass::build_vec4(
lut.image.size); location.location(),
&mut buffer[offset..][..4],
lut.image.size,
);
} }
} }
// // todo history // // todo history
} }
} }

View file

@ -1,8 +1,8 @@
use crate::util;
use crate::util::{GlImage, Size, Texture, Viewport};
use gl::types::{GLenum, GLsizei, GLuint}; use gl::types::{GLenum, GLsizei, GLuint};
use librashader::{FilterMode, ShaderFormat, WrapMode}; use librashader::{FilterMode, ShaderFormat, WrapMode};
use librashader_presets::{Scale2D, ScaleType, Scaling}; use librashader_presets::{Scale2D, ScaleType, Scaling};
use crate::util;
use crate::util::{GlImage, Size, Texture, Viewport};
#[derive(Debug)] #[derive(Debug)]
pub struct Framebuffer { pub struct Framebuffer {
@ -12,7 +12,7 @@ pub struct Framebuffer {
pub max_levels: u32, pub max_levels: u32,
pub levels: u32, pub levels: u32,
pub handle: GLuint, pub handle: GLuint,
pub init: bool pub init: bool,
} }
impl Framebuffer { impl Framebuffer {
@ -26,24 +26,33 @@ impl Framebuffer {
Framebuffer { Framebuffer {
image: 0, image: 0,
size: Size { width: 1, height: 1 }, size: Size {
width: 1,
height: 1,
},
format: 0, format: 0,
max_levels, max_levels,
levels: 0, levels: 0,
handle: framebuffer, handle: framebuffer,
init: false init: false,
} }
} }
pub fn new_from_raw(texture: GLuint, handle: GLuint, format: GLenum, size: Size, miplevels: u32) -> Framebuffer { pub fn new_from_raw(
texture: GLuint,
handle: GLuint,
format: GLenum,
size: Size,
miplevels: u32,
) -> Framebuffer {
Framebuffer { Framebuffer {
image: texture, image: texture,
size, size,
format, format,
max_levels: miplevels, max_levels: miplevels,
levels: miplevels, levels: miplevels,
handle: handle, handle,
init: true init: true,
} }
} }
@ -53,78 +62,76 @@ impl Framebuffer {
handle: self.image, handle: self.image,
format: self.format, format: self.format,
size: self.size, size: self.size,
padded_size: Default::default() padded_size: Default::default(),
}, },
filter, filter,
mip_filter: filter, mip_filter: filter,
wrap_mode wrap_mode,
} }
} }
pub fn scale(&mut self, scaling: Scale2D, format: ShaderFormat, viewport: &Viewport, original: &Texture, source: &Texture) -> Size { pub fn scale(
&mut self,
scaling: Scale2D,
format: ShaderFormat,
viewport: &Viewport,
_original: &Texture,
source: &Texture,
) -> Size {
let mut width = 0f32; let mut width = 0f32;
let mut height = 0f32; let mut height = 0f32;
match scaling.x { match scaling.x {
Scaling { Scaling {
scale_type: ScaleType::Input, scale_type: ScaleType::Input,
factor factor,
} => { } => width = source.image.size.width * factor,
width = source.image.size.width * factor
},
Scaling { Scaling {
scale_type: ScaleType::Absolute, scale_type: ScaleType::Absolute,
factor factor,
} => { } => width = factor.into(),
width = factor.into()
}
Scaling { Scaling {
scale_type: ScaleType::Viewport, scale_type: ScaleType::Viewport,
factor factor,
} => { } => width = viewport.output.size.width * factor,
width = viewport.output.size.width * factor
}
}; };
match scaling.y { match scaling.y {
Scaling { Scaling {
scale_type: ScaleType::Input, scale_type: ScaleType::Input,
factor factor,
} => { } => height = source.image.size.height * factor,
height = source.image.size.height * factor
},
Scaling { Scaling {
scale_type: ScaleType::Absolute, scale_type: ScaleType::Absolute,
factor factor,
} => { } => height = factor.into(),
height = factor.into()
}
Scaling { Scaling {
scale_type: ScaleType::Viewport, scale_type: ScaleType::Viewport,
factor factor,
} => { } => height = viewport.output.size.height * factor,
height = viewport.output.size.height * factor
}
}; };
let size = Size { let size = Size {
width: width.round() as u32, width: width.round() as u32,
height: height.round() as u32 height: height.round() as u32,
}; };
if self.size != size { if self.size != size {
self.size = size; self.size = size;
self.init(size,if format == ShaderFormat::Unknown { self.init(
ShaderFormat::R8G8B8A8Unorm size,
} else { if format == ShaderFormat::Unknown {
format ShaderFormat::R8G8B8A8Unorm
}); } else {
format
},
);
} }
size size
} }
fn init(&mut self, mut size: Size, mut format: impl Into<GLenum>) { fn init(&mut self, mut size: Size, format: impl Into<GLenum>) {
self.format = format.into(); self.format = format.into();
self.size = size; self.size = size;
@ -133,7 +140,13 @@ impl Framebuffer {
// reset the framebuffer image // reset the framebuffer image
if self.image != 0 { if self.image != 0 {
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image); gl::DeleteTextures(1, &self.image);
} }
@ -155,9 +168,20 @@ impl Framebuffer {
self.levels = 1; self.levels = 1;
} }
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, self.format, size.width as GLsizei, size.height as GLsizei); gl::TexStorage2D(
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::TEXTURE_2D,
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); 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); let status = gl::CheckFramebufferStatus(gl::FRAMEBUFFER);
if status != gl::FRAMEBUFFER_COMPLETE { if status != gl::FRAMEBUFFER_COMPLETE {
@ -165,8 +189,13 @@ impl Framebuffer {
gl::FRAMEBUFFER_UNSUPPORTED => { gl::FRAMEBUFFER_UNSUPPORTED => {
eprintln!("unsupported fbo"); eprintln!("unsupported fbo");
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::FramebufferTexture2D(
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, 0, 0); gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
0,
0,
);
gl::DeleteTextures(1, &self.image); gl::DeleteTextures(1, &self.image);
gl::GenTextures(1, &mut self.image); gl::GenTextures(1, &mut self.image);
gl::BindTexture(1, self.image); gl::BindTexture(1, self.image);
@ -179,12 +208,24 @@ impl Framebuffer {
self.levels = 1; self.levels = 1;
} }
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, ShaderFormat::R8G8B8A8Unorm.into(), size.width as GLsizei, size.height as GLsizei); gl::TexStorage2D(
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::TEXTURE_2D,
gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, self.image, 0); self.levels as GLsizei,
self.init = gl::CheckFramebufferStatus(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE; ShaderFormat::R8G8B8A8Unorm.into(),
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:x}") _ => panic!("failed to complete: {status:x}"),
} }
} else { } else {
self.init = true; self.init = true;
@ -207,4 +248,4 @@ impl Drop for Framebuffer {
} }
} }
} }
} }

View file

@ -2,11 +2,10 @@ use std::convert::TryInto;
use std::ffi::{c_void, CStr}; use std::ffi::{c_void, CStr};
use std::sync::mpsc::Receiver; use std::sync::mpsc::Receiver;
use glfw;
use glfw::{Context, Glfw, Window, WindowEvent}; use glfw::{Context, Glfw, Window, WindowEvent};
use gl;
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint}; use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use glfw::Key::P;
use crate::filter_chain::FilterChain; use crate::filter_chain::FilterChain;
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use crate::util::{GlImage, Size, Viewport}; use crate::util::{GlImage, Size, Viewport};
@ -18,7 +17,12 @@ const TITLE: &str = "Hello From OpenGL World!";
pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) }; let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) };
unsafe { unsafe {
gl::ShaderSource(vertex_shader, 1, &vertex.as_bytes().as_ptr().cast(), &vertex.len().try_into().unwrap()); gl::ShaderSource(
vertex_shader,
1,
&vertex.as_bytes().as_ptr().cast(),
&vertex.len().try_into().unwrap(),
);
gl::CompileShader(vertex_shader); gl::CompileShader(vertex_shader);
let mut success = 0; let mut success = 0;
@ -31,13 +35,21 @@ pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
let mut v: Vec<u8> = Vec::with_capacity(1024); let mut v: Vec<u8> = Vec::with_capacity(1024);
gl::GetShaderInfoLog(vertex_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); gl::GetShaderInfoLog(vertex_shader, 1024, &mut log_len, v.as_mut_ptr().cast());
v.set_len(log_len.try_into().unwrap()); v.set_len(log_len.try_into().unwrap());
panic!("Vertex Shader Compile Error: {}", String::from_utf8_lossy(&v)); panic!(
"Vertex Shader Compile Error: {}",
String::from_utf8_lossy(&v)
);
} }
} }
let fragment_shader = unsafe { gl::CreateShader(gl::FRAGMENT_SHADER) }; let fragment_shader = unsafe { gl::CreateShader(gl::FRAGMENT_SHADER) };
unsafe { unsafe {
gl::ShaderSource(fragment_shader, 1, &fragment.as_bytes().as_ptr().cast(), &fragment.len().try_into().unwrap()); gl::ShaderSource(
fragment_shader,
1,
&fragment.as_bytes().as_ptr().cast(),
&fragment.len().try_into().unwrap(),
);
gl::CompileShader(fragment_shader); gl::CompileShader(fragment_shader);
let mut success = 0; let mut success = 0;
@ -47,7 +59,10 @@ pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
let mut log_len = 0_i32; let mut log_len = 0_i32;
gl::GetShaderInfoLog(fragment_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); gl::GetShaderInfoLog(fragment_shader, 1024, &mut log_len, v.as_mut_ptr().cast());
v.set_len(log_len.try_into().unwrap()); v.set_len(log_len.try_into().unwrap());
panic!("Fragment Shader Compile Error: {}", String::from_utf8_lossy(&v)); panic!(
"Fragment Shader Compile Error: {}",
String::from_utf8_lossy(&v)
);
} }
} }
@ -76,39 +91,53 @@ pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
shader_program shader_program
} }
extern "system" fn debug_callback(
extern "system" fn debug_callback(source: GLenum, err_type: GLenum, id: GLuint, severity: GLenum, length: GLsizei, message: *const GLchar, _user: *mut c_void) { _source: GLenum,
_err_type: GLenum,
_id: GLuint,
_severity: GLenum,
_length: GLsizei,
message: *const GLchar,
_user: *mut c_void,
) {
unsafe { unsafe {
let message = CStr::from_ptr(message); let message = CStr::from_ptr(message);
eprintln!("{:?}", message); eprintln!("{message:?}");
} }
} }
pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) {
let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core)); glfw.window_hint(glfw::WindowHint::OpenGlProfile(
glfw::OpenGlProfileHint::Core,
));
glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true)); glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));
glfw.window_hint(glfw::WindowHint::Resizable(false)); glfw.window_hint(glfw::WindowHint::Resizable(false));
glfw.window_hint(glfw::WindowHint::OpenGlDebugContext(true)); glfw.window_hint(glfw::WindowHint::OpenGlDebugContext(true));
let (mut window, events) = glfw.create_window(WIDTH, HEIGHT, TITLE, glfw::WindowMode::Windowed).unwrap(); let (mut window, events) = glfw
.create_window(WIDTH, HEIGHT, TITLE, glfw::WindowMode::Windowed)
.unwrap();
let (screen_width, screen_height) = window.get_framebuffer_size(); let (screen_width, screen_height) = window.get_framebuffer_size();
window.make_current(); window.make_current();
window.set_key_polling(true); window.set_key_polling(true);
gl::load_with(|ptr| window.get_proc_address(ptr) as *const _); gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
unsafe { unsafe {
gl::Enable(gl::DEBUG_OUTPUT); gl::Enable(gl::DEBUG_OUTPUT);
gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS); gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
gl::DebugMessageCallback(Some(debug_callback), std::ptr::null_mut()); gl::DebugMessageCallback(Some(debug_callback), std::ptr::null_mut());
gl::DebugMessageControl(gl::DONT_CARE, gl::DebugMessageControl(
gl::DONT_CARE, gl::DONT_CARE,
gl::DONT_CARE, gl::DONT_CARE,
0, std::ptr::null(), gl::TRUE); gl::DONT_CARE,
0,
std::ptr::null(),
gl::TRUE,
);
} }
unsafe { unsafe {
@ -147,20 +176,24 @@ void main()
let shader_program = compile_program(VERT_SHADER, FRAG_SHADER); let shader_program = compile_program(VERT_SHADER, FRAG_SHADER);
unsafe { unsafe {
gl::ObjectLabel(gl::SHADER, shader_program, -1, b"color_shader\0".as_ptr().cast()); gl::ObjectLabel(
gl::SHADER,
shader_program,
-1,
b"color_shader\0".as_ptr().cast(),
);
} }
let vertices = &[ let vertices = &[
// positions // colors // positions // colors
0.5f32, -0.5, 0.0, 1.0, 0.0, 0.0, // bottom right 0.5f32, -0.5, 0.0, 1.0, 0.0, 0.0, // bottom right
-0.5, -0.5, 0.0, 0.0, 1.0, 0.0, // bottom left -0.5, -0.5, 0.0, 0.0, 1.0, 0.0, // bottom left
0.0, 0.5, 0.0, 0.0, 0.0, 1.0 // top 0.0, 0.5, 0.0, 0.0, 0.0, 1.0, // top
]; ];
let mut vbo: gl::types::GLuint = 0; let mut vbo: gl::types::GLuint = 0;
unsafe { unsafe {
gl::GenBuffers(1, &mut vbo); gl::GenBuffers(1, &mut vbo);
gl::ObjectLabel(gl::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast()); gl::ObjectLabel(gl::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast());
} }
unsafe { unsafe {
@ -180,7 +213,6 @@ void main()
unsafe { unsafe {
gl::GenVertexArrays(1, &mut vao); gl::GenVertexArrays(1, &mut vao);
gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast()); gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast());
} }
unsafe { unsafe {
@ -217,15 +249,24 @@ void main()
gl::ClearColor(0.3, 0.3, 0.5, 1.0); gl::ClearColor(0.3, 0.3, 0.5, 1.0);
} }
// ------------------------------------------- // -------------------------------------------
println!("OpenGL version: {}", gl_get_string(gl::VERSION)); println!("OpenGL version: {}", gl_get_string(gl::VERSION));
println!("GLSL version: {}", gl_get_string(gl::SHADING_LANGUAGE_VERSION)); println!(
"GLSL version: {}",
gl_get_string(gl::SHADING_LANGUAGE_VERSION)
);
(glfw, window, events, shader_program, vao) (glfw, window, events, shader_program, vao)
} }
pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, WindowEvent)>, triangle_program: GLuint, triangle_vao: GLuint, filter: &mut FilterChain) { pub fn do_loop(
mut glfw: Glfw,
mut window: Window,
events: Receiver<(f64, WindowEvent)>,
triangle_program: GLuint,
triangle_vao: GLuint,
filter: &mut FilterChain,
) {
let mut rendered_framebuffer = 0; let mut rendered_framebuffer = 0;
let mut rendered_texture = 0; let mut rendered_texture = 0;
let mut quad_vbuf = 0; let mut quad_vbuf = 0;
@ -239,24 +280,54 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
gl::GenFramebuffers(1, &mut rendered_framebuffer); gl::GenFramebuffers(1, &mut rendered_framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer);
gl::ObjectLabel(gl::FRAMEBUFFER, rendered_framebuffer, -1, b"rendered_framebuffer\0".as_ptr().cast()); gl::ObjectLabel(
gl::FRAMEBUFFER,
rendered_framebuffer,
-1,
b"rendered_framebuffer\0".as_ptr().cast(),
);
// make tetxure // make tetxure
gl::GenTextures(1, &mut rendered_texture); gl::GenTextures(1, &mut rendered_texture);
gl::BindTexture(gl::TEXTURE_2D, rendered_texture); gl::BindTexture(gl::TEXTURE_2D, rendered_texture);
gl::ObjectLabel(gl::TEXTURE, rendered_texture, -1, b"rendered_texture\0".as_ptr().cast()); gl::ObjectLabel(
gl::TEXTURE,
rendered_texture,
-1,
b"rendered_texture\0".as_ptr().cast(),
);
// empty image // empty image
gl::TexStorage2D(gl::TEXTURE_2D, 1, gl::RGBA8, WIDTH as GLsizei, HEIGHT as GLsizei); gl::TexStorage2D(
gl::TEXTURE_2D,
1,
gl::RGBA8,
WIDTH as GLsizei,
HEIGHT as GLsizei,
);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint); gl::TexParameteri(
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint); gl::TEXTURE_2D,
gl::TEXTURE_WRAP_S,
gl::CLAMP_TO_EDGE as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_T,
gl::CLAMP_TO_EDGE as GLint,
);
// set color attachment // set color attachment
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, rendered_texture, 0); gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
rendered_texture,
0,
);
let buffers = [gl::COLOR_ATTACHMENT0]; let buffers = [gl::COLOR_ATTACHMENT0];
gl::DrawBuffers(1, buffers.as_ptr()); gl::DrawBuffers(1, buffers.as_ptr());
@ -266,21 +337,17 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
} }
let fullscreen_fbo = [ let fullscreen_fbo = [
-1.0f32, -1.0, 0.0, -1.0f32, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0,
1.0, -1.0, 0.0, 1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
]; ];
gl::GenBuffers(1, &mut quad_vbuf); gl::GenBuffers(1, &mut quad_vbuf);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbuf); gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbuf);
gl::BufferData( gl::BufferData(
gl::ARRAY_BUFFER, // target gl::ARRAY_BUFFER, // target
(fullscreen_fbo.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr, // size of data in bytes (fullscreen_fbo.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr, // size of data in bytes
fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data
gl::STATIC_DRAW, // usage gl::STATIC_DRAW, // usage
); );
} }
@ -289,24 +356,54 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
gl::GenFramebuffers(1, &mut output_framebuffer_handle); gl::GenFramebuffers(1, &mut output_framebuffer_handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, output_framebuffer_handle); gl::BindFramebuffer(gl::FRAMEBUFFER, output_framebuffer_handle);
gl::ObjectLabel(gl::FRAMEBUFFER, output_framebuffer_handle, -1, b"output_framebuffer\0".as_ptr().cast()); gl::ObjectLabel(
gl::FRAMEBUFFER,
output_framebuffer_handle,
-1,
b"output_framebuffer\0".as_ptr().cast(),
);
// make tetxure // make tetxure
gl::GenTextures(1, &mut output_texture); gl::GenTextures(1, &mut output_texture);
gl::BindTexture(gl::TEXTURE_2D, output_texture); gl::BindTexture(gl::TEXTURE_2D, output_texture);
gl::ObjectLabel(gl::TEXTURE, output_texture, -1, b"output_texture\0".as_ptr().cast()); gl::ObjectLabel(
gl::TEXTURE,
output_texture,
-1,
b"output_texture\0".as_ptr().cast(),
);
// empty image // empty image
gl::TexStorage2D(gl::TEXTURE_2D, 1, gl::RGBA8, WIDTH as GLsizei, HEIGHT as GLsizei); gl::TexStorage2D(
gl::TEXTURE_2D,
1,
gl::RGBA8,
WIDTH as GLsizei,
HEIGHT as GLsizei,
);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint); gl::TexParameteri(
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint); gl::TEXTURE_2D,
gl::TEXTURE_WRAP_S,
gl::CLAMP_TO_EDGE as GLint,
);
gl::TexParameteri(
gl::TEXTURE_2D,
gl::TEXTURE_WRAP_T,
gl::CLAMP_TO_EDGE as GLint,
);
// set color attachment // set color attachment
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, output_texture, 0); gl::FramebufferTexture2D(
gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
output_texture,
0,
);
let buffers = [gl::COLOR_ATTACHMENT0]; let buffers = [gl::COLOR_ATTACHMENT0];
gl::DrawBuffers(1, buffers.as_ptr()); gl::DrawBuffers(1, buffers.as_ptr());
@ -316,21 +413,17 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
} }
let fullscreen_fbo = [ let fullscreen_fbo = [
-1.0f32, -1.0, 0.0, -1.0f32, -1.0, 0.0, 1.0, -1.0, 0.0, -1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0,
1.0, -1.0, 0.0, 1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
]; ];
gl::GenBuffers(1, &mut output_quad_vbuf); gl::GenBuffers(1, &mut output_quad_vbuf);
gl::BindBuffer(gl::ARRAY_BUFFER, output_quad_vbuf); gl::BindBuffer(gl::ARRAY_BUFFER, output_quad_vbuf);
gl::BufferData( gl::BufferData(
gl::ARRAY_BUFFER, // target gl::ARRAY_BUFFER, // target
(fullscreen_fbo.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr, // size of data in bytes (fullscreen_fbo.len() * std::mem::size_of::<f32>()) as gl::types::GLsizeiptr, // size of data in bytes
fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data fullscreen_fbo.as_ptr() as *const gl::types::GLvoid, // pointer to data
gl::STATIC_DRAW, // usage gl::STATIC_DRAW, // usage
); );
} }
@ -359,17 +452,22 @@ void main()
color=texture(texSampler, v_tex); color=texture(texSampler, v_tex);
}"; }";
let quad_programid = compile_program(VERT_SHADER, FRAG_SHADER); let quad_programid = compile_program(VERT_SHADER, FRAG_SHADER);
let mut quad_vao = 0; let mut quad_vao = 0;
unsafe { unsafe {
gl::GenVertexArrays(1, &mut quad_vao); gl::GenVertexArrays(1, &mut quad_vao);
} }
let fb = Framebuffer::new_from_raw(output_texture, output_framebuffer_handle, gl::RGBA8, Size { let fb = Framebuffer::new_from_raw(
width: WIDTH, output_texture,
height: HEIGHT output_framebuffer_handle,
}, 1); gl::RGBA8,
Size {
width: WIDTH,
height: HEIGHT,
},
1,
);
while !window.should_close() { while !window.should_close() {
glfw.poll_events(); glfw.poll_events();
@ -382,14 +480,12 @@ void main()
gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer); gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer);
// gl::BindFramebuffer(gl::FRAMEBUFFER, 0); // gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::Viewport(0, 0, WIDTH as GLsizei, HEIGHT as GLsizei); gl::Viewport(0, 0, WIDTH as GLsizei, HEIGHT as GLsizei);
// clear color // clear color
clear_color(Color(0.3, 0.4, 0.6, 1.0)); clear_color(Color(0.3, 0.4, 0.6, 1.0));
gl::Clear(gl::COLOR_BUFFER_BIT); gl::Clear(gl::COLOR_BUFFER_BIT);
// do the drawing // do the drawing
gl::UseProgram(triangle_program); gl::UseProgram(triangle_program);
// select vertices // select vertices
@ -403,7 +499,6 @@ void main()
// unselect fbo // unselect fbo
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
} }
// eprintln!("[core] rendered texture is {rendered_texture}"); // eprintln!("[core] rendered texture is {rendered_texture}");
@ -415,20 +510,25 @@ void main()
// gl::BindTexture(gl::TEXTURE_2D, rendered_texture); // gl::BindTexture(gl::TEXTURE_2D, rendered_texture);
// } // }
unsafe { unsafe {
filter.frame(0, &Viewport { filter.frame(
x: 0, 0,
y: 0, &Viewport {
output: &fb, x: 0,
mvp: None y: 0,
}, GlImage { output: &fb,
handle: rendered_texture, mvp: None,
format: gl::RGBA8,
size: Size {
width: WIDTH,
height: HEIGHT
}, },
padded_size: Default::default() GlImage {
}, false) handle: rendered_texture,
format: gl::RGBA8,
size: Size {
width: WIDTH,
height: HEIGHT,
},
padded_size: Default::default(),
},
false,
)
} }
unsafe { unsafe {
@ -440,8 +540,6 @@ void main()
gl::BindFramebuffer(gl::FRAMEBUFFER, 0); gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::UseProgram(quad_programid); gl::UseProgram(quad_programid);
gl::ActiveTexture(gl::TEXTURE0); gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, output_texture); gl::BindTexture(gl::TEXTURE_2D, output_texture);
@ -467,14 +565,14 @@ pub fn gl_get_string<'a>(name: gl::types::GLenum) -> &'a str {
} }
fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) { fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) {
use glfw::WindowEvent as Event;
use glfw::Key;
use glfw::Action; use glfw::Action;
use glfw::Key;
use glfw::WindowEvent as Event;
match event { match event {
Event::Key(Key::Escape, _, Action::Press, _) => { Event::Key(Key::Escape, _, Action::Press, _) => {
window.set_should_close(true); window.set_should_close(true);
}, }
_ => {}, _ => {}
} }
} }

View file

@ -1,28 +1,26 @@
#![feature(strict_provenance)] #![feature(strict_provenance)]
mod hello_triangle;
mod filter_pass;
mod util;
mod framebuffer;
mod binding; mod binding;
mod filter_chain; mod filter_chain;
mod filter_pass;
mod framebuffer;
mod hello_triangle;
mod render_target; mod render_target;
mod util;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::filter_chain::FilterChain;
use super::*; use super::*;
use crate::filter_chain::FilterChain;
#[test] #[test]
fn triangle() { fn triangle() {
let (glfw, window, events, shader, vao) = hello_triangle::setup(); let (glfw, window, events, shader, vao) = hello_triangle::setup();
let mut filter = FilterChain::load("../test/basic.slangp").unwrap(); let mut filter = FilterChain::load("../test/basic.slangp").unwrap();
// FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap(); // FilterChain::load("../test/slang-shaders/crt/crt-royale.slangp").unwrap();
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter ); hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
} }
// #[test] // #[test]

View file

@ -2,36 +2,33 @@ use crate::framebuffer::Framebuffer;
use crate::util::Viewport; use crate::util::Viewport;
static DEFAULT_MVP: &[f32] = &[ static DEFAULT_MVP: &[f32] = &[
2f32, 0.0, 0.0, 0.0, 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,
0.0, 2.0, 0.0, 0.0,
0.0, 0.0, 2.0, 0.0,
-1.0, -1.0, 0.0, 1.0
]; ];
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct RenderTarget<'a> { pub struct RenderTarget<'a> {
pub mvp: &'a [f32], pub mvp: &'a [f32],
pub framebuffer: &'a Framebuffer pub framebuffer: &'a Framebuffer,
} }
impl <'a> RenderTarget<'a> { impl<'a> RenderTarget<'a> {
pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32]>) -> Self { pub fn new(backbuffer: &'a Framebuffer, mvp: Option<&'a [f32]>) -> Self {
if let Some(mvp) = mvp { if let Some(mvp) = mvp {
RenderTarget { RenderTarget {
framebuffer: backbuffer, framebuffer: backbuffer,
mvp mvp,
} }
} else { } else {
RenderTarget { RenderTarget {
framebuffer: backbuffer, framebuffer: backbuffer,
mvp: DEFAULT_MVP mvp: DEFAULT_MVP,
} }
} }
} }
} }
impl <'a> From<&Viewport<'a>> for RenderTarget<'a> { impl<'a> From<&Viewport<'a>> for RenderTarget<'a> {
fn from(value: &Viewport<'a>) -> Self { fn from(value: &Viewport<'a>) -> Self {
RenderTarget::new(value.output, value.mvp) RenderTarget::new(value.output, value.mvp)
} }
} }

View file

@ -1,6 +1,6 @@
use gl::types::{GLenum, GLint, GLuint};
use librashader::{FilterMode, WrapMode};
use crate::framebuffer::Framebuffer; use crate::framebuffer::Framebuffer;
use gl::types::{GLenum, GLuint};
use librashader::{FilterMode, WrapMode};
pub fn calc_miplevel(width: u32, height: u32) -> u32 { pub fn calc_miplevel(width: u32, height: u32) -> u32 {
let mut size = std::cmp::max(width, height); let mut size = std::cmp::max(width, height);
@ -10,7 +10,7 @@ pub fn calc_miplevel(width: u32, height: u32) -> u32 {
size >>= 1; size >>= 1;
} }
return levels; levels
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -18,7 +18,7 @@ pub struct Texture {
pub image: GlImage, pub image: GlImage,
pub filter: FilterMode, pub filter: FilterMode,
pub mip_filter: FilterMode, pub mip_filter: FilterMode,
pub wrap_mode: WrapMode pub wrap_mode: WrapMode,
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@ -26,7 +26,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]>,
} }
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
@ -40,10 +40,10 @@ pub struct GlImage {
pub handle: GLuint, pub handle: GLuint,
pub format: GLenum, pub format: GLenum,
pub size: Size, pub size: Size,
pub padded_size: Size pub padded_size: Size,
} }
impl <T, const SIZE: usize> RingBuffer<T, SIZE> { impl<T, const SIZE: usize> RingBuffer<T, SIZE> {
pub fn current(&self) -> &T { pub fn current(&self) -> &T {
&self.items[self.index] &self.items[self.index]
} }
@ -58,16 +58,18 @@ impl <T, const SIZE: usize> RingBuffer<T, SIZE> {
pub struct RingBuffer<T, const SIZE: usize> { pub struct RingBuffer<T, const SIZE: usize> {
items: [T; SIZE], items: [T; SIZE],
index: usize index: usize,
} }
impl <T, const SIZE: usize> RingBuffer<T, SIZE> impl<T, const SIZE: usize> RingBuffer<T, SIZE>
where T: Copy, T: Default where
T: Copy,
T: Default,
{ {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
items: [T::default(); SIZE], items: [T::default(); SIZE],
index: 0 index: 0,
} }
} }
@ -82,7 +84,12 @@ where T: Copy, T: Default
pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { pub unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint {
let shader = gl::CreateShader(stage); let shader = gl::CreateShader(stage);
gl::ShaderSource(shader, 1, &source.as_bytes().as_ptr().cast(), std::ptr::null()); gl::ShaderSource(
shader,
1,
&source.as_bytes().as_ptr().cast(),
std::ptr::null(),
);
gl::CompileShader(shader); gl::CompileShader(shader);
let mut compile_status = 0; let mut compile_status = 0;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status); gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status);