From 6fcee1691f3aa74aa8b2229a168a761bfd4934a1 Mon Sep 17 00:00:00 2001 From: chyyran Date: Fri, 11 Nov 2022 21:52:22 -0500 Subject: [PATCH] gl: implement hello triangle test for further debug --- Cargo.lock | 56 +++ librashader-runtime-gl/Cargo.toml | 3 +- librashader-runtime-gl/src/hello_triangle.rs | 352 +++++++++++++++++++ librashader-runtime-gl/src/lib.rs | 10 +- 4 files changed, 419 insertions(+), 2 deletions(-) create mode 100644 librashader-runtime-gl/src/hello_triangle.rs diff --git a/Cargo.lock b/Cargo.lock index 3809a72..0b45967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -255,6 +255,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + [[package]] name = "derive_arbitrary" version = "1.2.0" @@ -326,6 +332,28 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "glfw" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2c532509718cb34e0c449ec5ef74529c1af3a33b664e6b8ddfe29252f86f936" +dependencies = [ + "bitflags", + "glfw-sys", + "objc", + "raw-window-handle", + "winapi", +] + +[[package]] +name = "glfw-sys" +version = "4.0.0+3.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5abed6d39a50226676aab893d6b4ad154da7e93fcdfed90d7696758a1b477ed1" +dependencies = [ + "cmake", +] + [[package]] name = "half" version = "1.8.2" @@ -481,6 +509,7 @@ name = "librashader-runtime-gl" version = "0.1.0" dependencies = [ "gl", + "glfw", "librashader", "librashader-preprocess", "librashader-presets", @@ -498,6 +527,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + [[package]] name = "memchr" version = "2.5.0" @@ -587,6 +625,15 @@ dependencies = [ "libc", ] +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + [[package]] name = "once_cell" version = "1.15.0" @@ -664,6 +711,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "raw-window-handle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" +dependencies = [ + "cty", +] + [[package]] name = "rayon" version = "1.5.3" diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index 9c61238..67a70ef 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -12,4 +12,5 @@ edition = "2021" "librashader-reflect" = { path = "../librashader-reflect" } spirv_cross = "0.23.1" rustc-hash = "1.1.0" -gl = "0.14.0" \ No newline at end of file +gl = "0.14.0" +glfw = "0.47.0" \ No newline at end of file diff --git a/librashader-runtime-gl/src/hello_triangle.rs b/librashader-runtime-gl/src/hello_triangle.rs new file mode 100644 index 0000000..6e86090 --- /dev/null +++ b/librashader-runtime-gl/src/hello_triangle.rs @@ -0,0 +1,352 @@ +use std::convert::TryInto; +use std::sync::mpsc::Receiver; + +use glfw; +use glfw::{Context, Glfw, Window, WindowEvent}; +use gl; +use gl::types::{GLint, GLsizei, GLuint}; +use glfw::Key::P; + +const WIDTH: u32 = 900; +const HEIGHT: u32 = 700; +const TITLE: &str = "Hello From OpenGL World!"; + +pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { + let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) }; + unsafe { + gl::ShaderSource(vertex_shader, 1, &vertex.as_bytes().as_ptr().cast(), &vertex.len().try_into().unwrap()); + gl::CompileShader(vertex_shader); + + let mut success = 0; + gl::GetShaderiv(vertex_shader, gl::COMPILE_STATUS, &mut success); + if success == 0 { + let mut log_len = 0_i32; + // gl::GetShaderiv(vertex_shader, gl::INFO_LOG_LENGTH, &mut log_len); + // let mut v: Vec = Vec::with_capacity(log_len as usize); + // gl::GetShaderInfoLog(vertex_shader, log_len, &mut log_len, v.as_mut_ptr().cast()); + let mut v: Vec = Vec::with_capacity(1024); + gl::GetShaderInfoLog(vertex_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); + v.set_len(log_len.try_into().unwrap()); + panic!("Vertex Shader Compile Error: {}", String::from_utf8_lossy(&v)); + } + } + + let fragment_shader = unsafe { gl::CreateShader(gl::FRAGMENT_SHADER) }; + unsafe { + gl::ShaderSource(fragment_shader, 1, &fragment.as_bytes().as_ptr().cast(), &fragment.len().try_into().unwrap()); + gl::CompileShader(fragment_shader); + + let mut success = 0; + gl::GetShaderiv(fragment_shader, gl::COMPILE_STATUS, &mut success); + if success == 0 { + let mut v: Vec = Vec::with_capacity(1024); + let mut log_len = 0_i32; + gl::GetShaderInfoLog(fragment_shader, 1024, &mut log_len, v.as_mut_ptr().cast()); + v.set_len(log_len.try_into().unwrap()); + panic!("Fragment Shader Compile Error: {}", String::from_utf8_lossy(&v)); + } + } + + let shader_program = unsafe { gl::CreateProgram() }; + unsafe { + gl::AttachShader(shader_program, vertex_shader); + gl::AttachShader(shader_program, fragment_shader); + gl::LinkProgram(shader_program); + + let mut success = 0; + gl::GetProgramiv(shader_program, gl::LINK_STATUS, &mut success); + if success == 0 { + let mut v: Vec = Vec::with_capacity(1024); + let mut log_len = 0_i32; + gl::GetProgramInfoLog(shader_program, 1024, &mut log_len, v.as_mut_ptr().cast()); + v.set_len(log_len.try_into().unwrap()); + panic!("Program Link Error: {}", String::from_utf8_lossy(&v)); + } + + gl::DetachShader(shader_program, vertex_shader); + gl::DetachShader(shader_program, fragment_shader); + gl::DeleteShader(vertex_shader); + gl::DeleteShader(fragment_shader); + } + + shader_program +} + +pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) { + let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap(); + glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3)); + glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core)); + glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true)); + glfw.window_hint(glfw::WindowHint::Resizable(false)); + + let (mut window, events) = glfw.create_window(WIDTH, HEIGHT, TITLE, glfw::WindowMode::Windowed).unwrap(); + let (screen_width, screen_height) = window.get_framebuffer_size(); + + window.make_current(); + window.set_key_polling(true); + gl::load_with(|ptr| window.get_proc_address(ptr) as *const _); + + unsafe { + gl::Viewport(0, 0, screen_width, screen_height); + clear_color(Color(0.4, 0.4, 0.4, 1.0)); + } + // ------------------------------------------- + + const VERT_SHADER: &str = "#version 330 core + +layout (location = 0) in vec3 Position; +layout (location = 1) in vec3 Color; + +out VS_OUTPUT { + vec3 Color; +} OUT; + +void main() +{ + gl_Position = vec4(Position, 1.0); + OUT.Color = Color; +}"; + + const FRAG_SHADER: &str = "#version 330 core + +in VS_OUTPUT { + vec3 Color; +} IN; + +layout(location = 0) out vec4 Color; + +void main() +{ + Color = vec4(IN.Color, 1.0f); +}"; + let shader_program = compile_program(VERT_SHADER, FRAG_SHADER); + + let vertices = &[ + // positions // colors + 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.0, 0.5, 0.0, 0.0, 0.0, 1.0 // top + ]; + let mut vbo: gl::types::GLuint = 0; + unsafe { + gl::GenBuffers(1, &mut vbo); + } + + unsafe { + gl::BindBuffer(gl::ARRAY_BUFFER, vbo); + gl::BufferData( + gl::ARRAY_BUFFER, // target + (vertices.len() * std::mem::size_of::()) as gl::types::GLsizeiptr, // size of data in bytes + vertices.as_ptr() as *const gl::types::GLvoid, // pointer to data + gl::STATIC_DRAW, // usage + ); + gl::BindBuffer(gl::ARRAY_BUFFER, 0); + } + + // set up vertex array object + + let mut vao: gl::types::GLuint = 0; + unsafe { + gl::GenVertexArrays(1, &mut vao); + } + + unsafe { + gl::BindVertexArray(vao); + gl::BindBuffer(gl::ARRAY_BUFFER, vbo); + + gl::EnableVertexAttribArray(0); // this is "layout (location = 0)" in vertex shader + gl::VertexAttribPointer( + 0, // index of the generic vertex attribute ("layout (location = 0)") + 3, // the number of components per generic vertex attribute + gl::FLOAT, // data type + gl::FALSE, // normalized (int-to-float conversion) + (6 * std::mem::size_of::()) as gl::types::GLint, // stride (byte offset between consecutive attributes) + std::ptr::null(), // offset of the first component + ); + gl::EnableVertexAttribArray(1); // this is "layout (location = 0)" in vertex shader + gl::VertexAttribPointer( + 1, // index of the generic vertex attribute ("layout (location = 0)") + 3, // the number of components per generic vertex attribute + gl::FLOAT, // data type + gl::FALSE, // normalized (int-to-float conversion) + (6 * std::mem::size_of::()) as gl::types::GLint, // stride (byte offset between consecutive attributes) + (3 * std::mem::size_of::()) as *const gl::types::GLvoid, // offset of the first component + ); + + gl::BindBuffer(gl::ARRAY_BUFFER, 0); + gl::BindVertexArray(0); + } + + // set up shared state for window + + unsafe { + gl::Viewport(0, 0, 900, 700); + gl::ClearColor(0.3, 0.3, 0.5, 1.0); + } + + + // ------------------------------------------- + println!("OpenGL version: {}", gl_get_string(gl::VERSION)); + println!("GLSL version: {}", gl_get_string(gl::SHADING_LANGUAGE_VERSION)); + + (glfw, window, events, shader_program, vao) +} + +pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, WindowEvent)>, shader_program: GLuint, vao: GLuint) { + let mut framebuffer_handle = 0; + let mut rendered_texture = 0; + let mut quad_vbuf = 0; + + unsafe { + // do frmaebuffer + gl::GenFramebuffers(1, &mut framebuffer_handle); + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_handle); + + // make tetxure + gl::GenTextures(1, &mut rendered_texture); + gl::BindTexture(gl::TEXTURE_2D, rendered_texture); + + // empty image + gl::TexImage2D(gl::TEXTURE_2D, 0, gl::RGB as GLint, WIDTH as GLsizei, HEIGHT as GLsizei, 0, gl::RGB, gl::UNSIGNED_BYTE, std::ptr::null_mut()); + + 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::FramebufferTexture(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, rendered_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 quad_vbuf); + gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbuf); + gl::BufferData( + gl::ARRAY_BUFFER, // target + (fullscreen_fbo.len() * std::mem::size_of::()) 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; + +const vec2 pos[4]=vec2[4](vec2(-1.0, 1.0), + vec2(-1.0,-1.0), + vec2( 1.0, 1.0), + vec2( 1.0,-1.0)); + +void main() +{ + v_tex=0.5*pos[gl_VertexID] + vec2(0.5); + gl_Position=vec4(pos[gl_VertexID], 0.0, 1.0); +} +"; + + const FRAG_SHADER: &str = r" +#version 150 core +in vec2 v_tex; +uniform sampler2D texSampler; +out vec4 color; +void main() +{ + color=texture(texSampler, v_tex); +}"; + + + let quad_programid = compile_program(VERT_SHADER, FRAG_SHADER); + let mut quad_vao = 0; + unsafe { + gl::GenVertexArrays(1, &mut quad_vao); + } + + while !window.should_close() { + glfw.poll_events(); + for (_, event) in glfw::flush_messages(&events) { + glfw_handle_event(&mut window, event); + } + + unsafe { + // render to fb + gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer_handle); + // gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + + + gl::Viewport(0, 0, WIDTH as GLsizei, HEIGHT as GLsizei); + + // clear color + // clear_color(Color(0.3, 0.4, 0.6, 1.0)); + gl::Clear(gl::COLOR_BUFFER_BIT); + + + // do the drawing + gl::UseProgram(shader_program); + // select vertices + gl::BindVertexArray(vao); + + // draw to bound target + gl::DrawArrays(gl::TRIANGLES, 0, 3); + + // unselect vertices + gl::BindVertexArray(0); + + + // texture is done now. + + // todo: insert postprocessing stuff to rendered_texture + + // map quad to screen + gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + + gl::ActiveTexture(gl::TEXTURE0); + gl::BindTexture(gl::TEXTURE_2D, rendered_texture); + + gl::UseProgram(quad_programid); + gl::BindVertexArray(quad_vao); + + gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4) + } + + window.swap_buffers(); + } +} + +pub struct Color(f32, f32, f32, f32); + +pub fn clear_color(c: Color) { + unsafe { gl::ClearColor(c.0, c.1, c.2, c.3) } +} + +pub fn gl_get_string<'a>(name: gl::types::GLenum) -> &'a str { + let v = unsafe { gl::GetString(name) }; + let v: &std::ffi::CStr = unsafe { std::ffi::CStr::from_ptr(v as *const i8) }; + v.to_str().unwrap() +} + +fn glfw_handle_event(window: &mut glfw::Window, event: glfw::WindowEvent) { + use glfw::WindowEvent as Event; + use glfw::Key; + use glfw::Action; + + match event { + Event::Key(Key::Escape, _, Action::Press, _) => { + window.set_should_close(true); + }, + _ => {}, + } +} \ No newline at end of file diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index f75d0f9..4619797 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -1,3 +1,5 @@ +mod hello_triangle; + use std::collections::HashMap; use std::error::Error; use std::path::Path; @@ -97,7 +99,7 @@ pub fn load(path: impl AsRef) -> Result<(), Box>{ let mut reflections = Vec::new(); let mut compiled = Vec::new(); - for (index, (config, source, reflect)) in passes.iter_mut().enumerate() { + for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() { let reflection = reflect.reflect(index as u32, &semantics)?; let glsl = reflect.compile(GlVersion::V4_60)?; @@ -159,6 +161,12 @@ unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint { mod tests { use super::*; + #[test] + fn triangle() { + let (glfw, window, events, shader, vao) = hello_triangle::setup(); + hello_triangle::do_loop(glfw, window, events, shader, vao); + } + #[test] fn load_preset() {