gl: fix sampler binding

This commit is contained in:
chyyran 2022-11-19 22:03:58 -05:00
parent d49fa5307a
commit 090df176c8
7 changed files with 243 additions and 162 deletions

View file

@ -7,7 +7,7 @@ use crate::reflect::ReflectShader;
pub type GlVersion = spirv_cross::glsl::Version;
pub struct GlslangGlslContext {
pub texture_fixups: Vec<u32>,
pub sampler_bindings: Vec<u32>,
pub compiler: CompiledAst<spirv_cross::glsl::Target>
}
impl FromCompilation<GlslangCompilation> for GLSL {

View file

@ -810,7 +810,7 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
vertex: self.vertex.compile()?,
fragment: self.fragment.compile()?,
context: GlslangGlslContext {
texture_fixups,
sampler_bindings: texture_fixups,
compiler: CompiledAst {
vertex: self.vertex,
fragment: self.fragment

View file

@ -24,7 +24,6 @@ pub struct FilterPass {
pub uniform_buffer: Box<[u8]>,
pub push_buffer: Box<[u8]>,
pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub framebuffer: Framebuffer,
pub feedback_framebuffer: Framebuffer,
pub source: ShaderSource,
pub config: ShaderPassConfig
@ -86,8 +85,8 @@ impl FilterPass {
fn bind_texture(binding: &TextureImage, texture: &Texture) {
unsafe {
// eprintln!("binding {} = texture {}", binding.binding, texture.image.handle);
gl::ActiveTexture((gl::TEXTURE0 + binding.binding) as GLenum);
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, GLenum::from(texture.filter) as GLint);
@ -97,87 +96,25 @@ impl FilterPass {
}
}
fn scale_framebuffer(&mut self, format: ShaderFormat, viewport: &Viewport, original: &Texture, source: &Texture) -> Size {
let mut width = 0f32;
let mut height = 0f32;
match self.config.scaling.x {
Scaling {
scale_type: ScaleType::Input,
factor
} => {
width = source.image.size.width * factor
},
Scaling {
scale_type: ScaleType::Absolute,
factor
} => {
width = factor.into()
}
Scaling {
scale_type: ScaleType::Viewport,
factor
} => {
width = viewport.size.width * factor
}
};
match self.config.scaling.y {
Scaling {
scale_type: ScaleType::Input,
factor
} => {
height = source.image.size.height * factor
},
Scaling {
scale_type: ScaleType::Absolute,
factor
} => {
height = factor.into()
}
Scaling {
scale_type: ScaleType::Viewport,
factor
} => {
height = viewport.size.height * factor
}
};
let size = Size {
width: width.round() as u32,
height: height.round() as u32
};
if self.framebuffer.size != size {
self.framebuffer.size = size;
self.framebuffer.init(size,if format == ShaderFormat::Unknown {
ShaderFormat::R8G8B8A8Unorm
} else {
format
});
}
size
}
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn build_commands(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32, frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture) {
pub fn get_format(&self) -> ShaderFormat {
let mut fb_format = ShaderFormat::R8G8B8A8Unorm;
if self.config.srgb_framebuffer {
fb_format = ShaderFormat::R8G8B8A8Srgb;
} else if self.config.float_framebuffer {
fb_format = ShaderFormat::R16G16B16A16Sfloat;
}
fb_format
}
let fb_size = self.scale_framebuffer(fb_format, viewport, original, source);
// println!("[frame] Using framebuffer {}, image {}", self.framebuffer.framebuffer, self.framebuffer.image);
// todo: fix rendertargets (i.e. non-final pass is internal, final pass is user provided fbo)
pub fn draw(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32,
frame_direction: i32, viewport: &Viewport, original: &Texture, source: &Texture, output: &Framebuffer) {
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer.framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer);
gl::UseProgram(self.program);
}
self.build_semantics(parent, mvp, frame_count, frame_direction, fb_size, viewport, original, source);
self.build_semantics(parent, mvp, frame_count, frame_direction, output.size, viewport, original, source);
// shader_gl3:1514
if self.ubo_location.vertex != gl::INVALID_INDEX && self.ubo_location.fragment != gl::INVALID_INDEX {
@ -205,14 +142,14 @@ impl FilterPass {
// todo: final pass?
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer.framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, output.framebuffer);
gl::ColorMask(gl::TRUE, gl::TRUE, gl::TRUE, gl::TRUE);
gl::ClearColor(0.0f32, 0.0f32, 0.0f32, 0.0f32);
gl::Clear(gl::COLOR_BUFFER_BIT);
//
gl::Viewport(0, 0, fb_size.width as GLsizei, fb_size.height as GLsizei);
gl::Viewport(0, 0, output.size.width as GLsizei, output.size.height as GLsizei);
if self.framebuffer.format == gl::SRGB8_ALPHA8 {
if output.format == gl::SRGB8_ALPHA8 {
gl::Enable(gl::FRAMEBUFFER_SRGB);
} else {
gl::Disable(gl::FRAMEBUFFER_SRGB);
@ -280,7 +217,7 @@ impl FilterPass {
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], viewport.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()) {

View file

@ -1,8 +1,10 @@
use gl::types::{GLenum, GLsizei, GLuint};
use librashader::ShaderFormat;
use librashader::{FilterMode, ShaderFormat, WrapMode};
use librashader_presets::{Scale2D, ScaleType, Scaling};
use crate::util;
use crate::util::Size;
use crate::util::{GlImage, Size, Texture, Viewport};
#[derive(Debug)]
pub struct Framebuffer {
pub image: GLuint,
pub size: Size,
@ -33,7 +35,96 @@ impl Framebuffer {
}
}
pub(crate) fn init(&mut self, mut size: Size, mut format: impl Into<GLenum>) {
pub fn new_from_raw(texture: GLuint, handle: GLuint, format: GLenum, size: Size, miplevels: u32) -> Framebuffer {
Framebuffer {
image: texture,
size,
format,
max_levels: miplevels,
levels: miplevels,
framebuffer: handle,
init: true
}
}
pub fn as_texture(&self, filter: FilterMode, wrap_mode: WrapMode) -> Texture {
Texture {
image: GlImage {
handle: self.image,
format: self.format,
size: self.size,
padded_size: Default::default()
},
filter,
mip_filter: filter,
wrap_mode
}
}
pub fn scale(&mut self, scaling: Scale2D, format: ShaderFormat, viewport: &Viewport, original: &Texture, source: &Texture) -> Size {
let mut width = 0f32;
let mut height = 0f32;
match scaling.x {
Scaling {
scale_type: ScaleType::Input,
factor
} => {
width = source.image.size.width * factor
},
Scaling {
scale_type: ScaleType::Absolute,
factor
} => {
width = factor.into()
}
Scaling {
scale_type: ScaleType::Viewport,
factor
} => {
width = viewport.output.size.width * factor
}
};
match scaling.y {
Scaling {
scale_type: ScaleType::Input,
factor
} => {
height = source.image.size.height * factor
},
Scaling {
scale_type: ScaleType::Absolute,
factor
} => {
height = factor.into()
}
Scaling {
scale_type: ScaleType::Viewport,
factor
} => {
height = viewport.output.size.height * factor
}
};
let size = Size {
width: width.round() as u32,
height: height.round() as u32
};
if self.size != size {
self.size = size;
self.init(size,if format == ShaderFormat::Unknown {
ShaderFormat::R8G8B8A8Unorm
} else {
format
});
}
size
}
fn init(&mut self, mut size: Size, mut format: impl Into<GLenum>) {
self.format = format.into();
self.size = size;

View file

@ -8,6 +8,7 @@ use gl;
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use glfw::Key::P;
use crate::FilterChain;
use crate::framebuffer::Framebuffer;
use crate::util::{GlImage, Size, Viewport};
const WIDTH: u32 = 900;
@ -145,6 +146,10 @@ void main()
}";
let shader_program = compile_program(VERT_SHADER, FRAG_SHADER);
unsafe {
gl::ObjectLabel(gl::SHADER, shader_program, -1, b"color_shader\0".as_ptr().cast());
}
let vertices = &[
// positions // colors
0.5f32, -0.5, 0.0, 1.0, 0.0, 0.0, // bottom right
@ -154,6 +159,8 @@ void main()
let mut vbo: gl::types::GLuint = 0;
unsafe {
gl::GenBuffers(1, &mut vbo);
gl::ObjectLabel(gl::BUFFER, vbo, -1, b"triangle_vbo\0".as_ptr().cast());
}
unsafe {
@ -172,6 +179,8 @@ void main()
let mut vao: gl::types::GLuint = 0;
unsafe {
gl::GenVertexArrays(1, &mut vao);
gl::ObjectLabel(gl::VERTEX_ARRAY, vao, -1, b"triangle_vao\0".as_ptr().cast());
}
unsafe {
@ -216,20 +225,28 @@ void main()
(glfw, window, events, shader_program, vao)
}
pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, WindowEvent)>, triangle_program: GLuint, vao: GLuint, filter: &mut FilterChain) {
let mut framebuffer_handle = 0;
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_texture = 0;
let mut quad_vbuf = 0;
let mut output_texture = 0;
let mut output_framebuffer_handle = 0;
let mut output_quad_vbuf = 0;
unsafe {
// do frmaebuffer
gl::GenFramebuffers(1, &mut framebuffer_handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_handle);
gl::GenFramebuffers(1, &mut rendered_framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer);
gl::ObjectLabel(gl::FRAMEBUFFER, rendered_framebuffer, -1, b"rendered_framebuffer\0".as_ptr().cast());
// make tetxure
gl::GenTextures(1, &mut rendered_texture);
gl::BindTexture(gl::TEXTURE_2D, rendered_texture);
gl::ObjectLabel(gl::TEXTURE, rendered_texture, -1, b"rendered_texture\0".as_ptr().cast());
// empty image
gl::TexStorage2D(gl::TEXTURE_2D, 1, gl::RGBA8, WIDTH as GLsizei, HEIGHT as GLsizei);
@ -267,6 +284,56 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
);
}
unsafe {
// do frmaebuffer
gl::GenFramebuffers(1, &mut 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());
// make tetxure
gl::GenTextures(1, &mut output_texture);
gl::BindTexture(gl::TEXTURE_2D, output_texture);
gl::ObjectLabel(gl::TEXTURE, output_texture, -1, b"output_texture\0".as_ptr().cast());
// empty image
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_MIN_FILTER, gl::NEAREST as GLint);
gl::TexParameteri(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
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, output_texture, 0);
let buffers = [gl::COLOR_ATTACHMENT0];
gl::DrawBuffers(1, buffers.as_ptr());
if gl::CheckFramebufferStatus(gl::FRAMEBUFFER) != gl::FRAMEBUFFER_COMPLETE {
panic!("failed to create fbo")
}
let fullscreen_fbo = [
-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,
];
gl::GenBuffers(1, &mut output_quad_vbuf);
gl::BindBuffer(gl::ARRAY_BUFFER, output_quad_vbuf);
gl::BufferData(
gl::ARRAY_BUFFER, // target
(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
gl::STATIC_DRAW, // usage
);
}
const VERT_SHADER: &str = r"#version 150 core
out vec2 v_tex;
@ -299,6 +366,11 @@ void main()
gl::GenVertexArrays(1, &mut quad_vao);
}
let fb = Framebuffer::new_from_raw(output_texture, output_framebuffer_handle, gl::RGBA8, Size {
width: WIDTH,
height: HEIGHT
}, 1);
while !window.should_close() {
glfw.poll_events();
for (_, event) in glfw::flush_messages(&events) {
@ -307,7 +379,7 @@ void main()
unsafe {
// render to fb
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_handle);
gl::BindFramebuffer(gl::FRAMEBUFFER, rendered_framebuffer);
// gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
@ -321,7 +393,7 @@ void main()
// do the drawing
gl::UseProgram(triangle_program);
// select vertices
gl::BindVertexArray(vao);
gl::BindVertexArray(triangle_vao);
// draw to bound target
gl::DrawArrays(gl::TRIANGLES, 0, 3);
@ -337,14 +409,16 @@ void main()
// eprintln!("[core] rendered texture is {rendered_texture}");
// do offscreen passes
// unsafe {
// gl::ActiveTexture(gl::TEXTURE0);
// gl::BindTexture(gl::TEXTURE_2D, rendered_texture);
// }
unsafe {
filter.frame(0, &Viewport {
x: 0,
y: 0,
size: Size {
width: WIDTH,
height: HEIGHT
}
output: &fb
}, GlImage {
handle: rendered_texture,
format: gl::RGBA8,
@ -363,14 +437,16 @@ void main()
// map quad to screen
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::UseProgram(quad_programid);
gl::ActiveTexture(gl::TEXTURE0);
gl::BindTexture(gl::TEXTURE_2D, rendered_texture);
gl::BindTexture(gl::TEXTURE_2D, output_texture);
gl::UseProgram(quad_programid);
gl::BindVertexArray(quad_vao);
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4)
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
}
window.swap_buffers();

View file

@ -10,6 +10,7 @@ mod binding;
use std::collections::HashMap;
use std::error::Error;
use std::iter::Filter;
use std::ops::Deref;
use std::path::Path;
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use glfw::Key::P;
@ -37,7 +38,6 @@ unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint {
let shader = gl::CreateShader(stage);
gl::ShaderSource(shader, 1, &source.as_bytes().as_ptr().cast(), std::ptr::null());
gl::CompileShader(shader);
let mut compile_status = 0;
gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut compile_status);
@ -137,8 +137,8 @@ pub struct FilterCommon {
history: Vec<Texture>,
feedback: Vec<Texture>,
luts: FxHashMap<usize, Texture>,
outputs: Vec<Framebuffer>,
pub quad_vbo: GLuint,
pub input_framebuffer: Framebuffer,
}
impl FilterChain {
@ -192,6 +192,7 @@ impl FilterChain {
};
let mut filters = Vec::new();
let mut output_framebuffers = Vec::new();
// initialize passes
for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() {
@ -227,23 +228,22 @@ impl FilterChain {
panic!("failed to link program")
}
for binding in &glsl.context.texture_fixups {
gl::UseProgram(program);
for binding in &glsl.context.sampler_bindings {
let loc_name = format!("LIBRA_TEXTURE_{}\0", *binding);
unsafe {
let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
if location >= 0 {
gl::Uniform1i(location, *binding as GLint);
}
let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
if location >= 0 {
// eprintln!("setting sampler {location} to sample from {binding}");
gl::Uniform1i(location, *binding as GLint);
}
}
unsafe {
gl::UseProgram(0);
(program, 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()),
})
}
gl::UseProgram(0);
(program, 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 {
@ -282,12 +282,13 @@ impl FilterChain {
(FilterChain::reflect_uniform_location(program, param), param.offset));
}
// need output framebuffers.
output_framebuffers.push(Framebuffer::new(1));
// eprintln!("{:#?}", semantics);
eprintln!("{:#?}", reflection.meta);
eprintln!("{:#?}", locations);
eprintln!("{:#?}", reflection.push_constant);
// eprintln!("{:#?}", reflection.meta);
// eprintln!("{:#?}", locations);
// eprintln!("{:#?}", reflection.push_constant);
// eprintln!("====fragment====");
// eprintln!("{:#}", glsl.fragment);
// eprintln!("====vertex====");
@ -305,32 +306,11 @@ impl FilterChain {
source,
// no idea if this works.
// retroarch checks if feedback frames are used but we'll just init it tbh.
framebuffer: Framebuffer::new(1),
feedback_framebuffer: Framebuffer::new(1),
config: config.clone()
});
}
eprintln!("{:?}", filters.iter().map(|f| f.program).collect::<Vec<_>>());
// let mut glprogram: Vec<GLuint> = Vec::new();
// for compilation in &compiled {
// // compilation.context.compiler.vertex
// }
// eprintln!("{:#?}", reflections);
// eprintln!("{:#?}", compiled./);
// eprintln!("{:?}", preset);
// eprintln!("{:?}", reflect.reflect(&ReflectOptions {
// pass_number: i as u32,
// uniform_semantics,
// non_uniform_semantics: Default::default(),
// }));
// todo: apply shader pass
// gl3.cpp: 1942
// load luts
let mut luts = FxHashMap::default();
@ -415,7 +395,6 @@ impl FilterChain {
gl::GenVertexArrays(1, &mut quad_vao);
}
// todo: split params
Ok(FilterChain {
passes: filters,
quad_vao,
@ -426,8 +405,8 @@ impl FilterChain {
history: vec![],
feedback: vec![],
luts,
outputs: output_framebuffers,
quad_vbo,
input_framebuffer: Framebuffer::new(1)
}
})
}
@ -455,37 +434,34 @@ impl FilterChain {
let mut source = original.clone();
for passes in &mut self.passes {
passes.build_commands(&self.common, None, count, 1, vp, &original, &source);
let passes_len = self.passes.len();
let (pass, last) = self.passes.split_at_mut(passes_len - 1);
for (index, pass) in pass.iter_mut().enumerate() {
{
let target = &mut self.common.outputs[index];
let framebuffer_size = target.scale(pass.config.scaling.clone(), pass.get_format(), vp, &original, &source);
}
let target = &self.common.outputs[index];
pass.draw(&self.common, None, count, 1, vp, &original, &source, &target);
let target = target.as_texture(pass.config.filter, pass.config.wrap_mode);
// todo: update-pass-outputs
source = target;
// passes.build_semantics(&self, None, count, 1, vp, &original, &source);
}
assert_eq!(last.len(), 1);
for pass in last {
source.filter = pass.config.filter;
source.mip_filter = pass.config.filter;
pass.draw(&self.common, None, count, 1, vp, &original, &source, &vp.output);
}
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
gl::BindVertexArray(0);
}
// todo: deal with the mess that is frame history
}
pub fn do_final_pass(&mut self, count: u64, vp: &Viewport, input: GlImage, clear: bool, mvp: &[f32]) {
// todo: make copy
// todo: get filter info from pass data.
let filter = self.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 {
image: input,
filter,
mip_filter: filter,
wrap_mode
};
// todo: deal with the mess that is frame history
}
}

View file

@ -1,5 +1,6 @@
use gl::types::{GLenum, GLint, GLuint};
use librashader::{FilterMode, WrapMode};
use crate::framebuffer::Framebuffer;
pub fn calc_miplevel(width: u32, height: u32) -> u32 {
let mut size = std::cmp::max(width, height);
@ -21,10 +22,10 @@ pub struct Texture {
}
#[derive(Debug, Copy, Clone)]
pub struct Viewport {
pub struct Viewport<'a> {
pub x: i32,
pub y: i32,
pub size: Size,
pub output: &'a Framebuffer,
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]