From 799d409ddb3b61c9e9806b6511d2fe72652def0e Mon Sep 17 00:00:00 2001 From: chyyran Date: Tue, 24 Sep 2024 00:45:48 -0400 Subject: [PATCH] test(gl): Add OpenGL render test --- Cargo.lock | 72 +++----- Cargo.toml | 2 + librashader-runtime-gl/Cargo.toml | 2 +- librashader-runtime-vk/Cargo.toml | 1 - librashader-test/Cargo.toml | 4 + librashader-test/src/render/gl/context.rs | 72 ++++++++ librashader-test/src/render/gl/mod.rs | 190 ++++++++++++++++++++++ librashader-test/src/render/mod.rs | 29 +++- 8 files changed, 316 insertions(+), 56 deletions(-) create mode 100644 librashader-test/src/render/gl/context.rs create mode 100644 librashader-test/src/render/gl/mod.rs diff --git a/Cargo.lock b/Cargo.lock index afd0818..0b7b77f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -235,7 +235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52bca67b61cb81e5553babde81b8211f713cb6db79766f80168f3e5f40ea6c82" dependencies = [ "ash", - "raw-window-handle 0.6.2", + "raw-window-handle", "raw-window-metal", ] @@ -880,12 +880,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - [[package]] name = "cursor-icon" version = "1.1.0" @@ -1194,35 +1188,22 @@ dependencies = [ [[package]] name = "glfw" -version = "0.47.0" +version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c532509718cb34e0c449ec5ef74529c1af3a33b664e6b8ddfe29252f86f936" +checksum = "d1cad81f99085cabd6a4a99403335bc3f3d00d6cf4467e478f13c393ced9259d" dependencies = [ "bitflags 1.3.2", "glfw-sys", - "objc", - "raw-window-handle 0.4.3", - "winapi", -] - -[[package]] -name = "glfw" -version = "0.49.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70971598fc996224a36fe95256e90335242c00da647f7b0a0b125136613c54b" -dependencies = [ - "bitflags 1.3.2", - "glfw-sys", - "objc", - "raw-window-handle 0.5.2", + "objc2 0.5.2", + "raw-window-handle", "winapi", ] [[package]] name = "glfw-sys" -version = "4.0.0+3.3.5" +version = "5.0.0+3.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5abed6d39a50226676aab893d6b4ad154da7e93fcdfed90d7696758a1b477ed1" +checksum = "1dfc32d45fb58ff38b112696907963a7d671e9cf742b16f882062169a053cf88" dependencies = [ "cmake", ] @@ -1875,7 +1856,7 @@ version = "0.4.5" dependencies = [ "array-init", "bytemuck", - "glfw 0.47.0", + "glfw", "glow 0.14.1", "librashader-cache", "librashader-common", @@ -1917,7 +1898,6 @@ dependencies = [ "ash", "ash-window", "bytemuck", - "glfw 0.49.1", "gpu-allocator 0.27.0", "librashader-cache", "librashader-common", @@ -1927,7 +1907,7 @@ dependencies = [ "librashader-runtime", "num", "parking_lot", - "raw-window-handle 0.6.2", + "raw-window-handle", "rayon", "thiserror", "winit", @@ -1949,7 +1929,7 @@ dependencies = [ "librashader-runtime", "log", "pollster", - "raw-window-handle 0.6.2", + "raw-window-handle", "rayon", "thiserror", "wgpu", @@ -1962,7 +1942,12 @@ version = "0.1.0" dependencies = [ "anyhow", "ash", + "bitvec", + "d3d12-descriptor-heap", "gfx-maths", + "glfw", + "glow 0.14.1", + "gpu-allocator 0.27.0", "image", "image-compare", "librashader", @@ -2156,7 +2141,7 @@ dependencies = [ "log", "ndk-sys", "num_enum", - "raw-window-handle 0.6.2", + "raw-window-handle", "thiserror", ] @@ -2837,21 +2822,6 @@ dependencies = [ "rgb", ] -[[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 = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - [[package]] name = "raw-window-handle" version = "0.6.2" @@ -2867,7 +2837,7 @@ dependencies = [ "cocoa", "core-graphics", "objc", - "raw-window-handle 0.6.2", + "raw-window-handle", ] [[package]] @@ -3818,7 +3788,7 @@ dependencies = [ "naga", "parking_lot", "profiling", - "raw-window-handle 0.6.2", + "raw-window-handle", "smallvec", "static_assertions", "wasm-bindgen", @@ -3846,7 +3816,7 @@ dependencies = [ "once_cell", "parking_lot", "profiling", - "raw-window-handle 0.6.2", + "raw-window-handle", "rustc-hash 1.1.0", "smallvec", "thiserror", @@ -3888,7 +3858,7 @@ dependencies = [ "parking_lot", "profiling", "range-alloc", - "raw-window-handle 0.6.2", + "raw-window-handle", "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", @@ -4271,7 +4241,7 @@ dependencies = [ "once_cell", "orbclient", "percent-encoding", - "raw-window-handle 0.6.2", + "raw-window-handle", "redox_syscall 0.3.5", "rustix", "sctk-adwaita", diff --git a/Cargo.toml b/Cargo.toml index cfda6b8..57e52cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ spirv-cross2 = { version = "0.4", default-features = false } objc2-metal = { version = "0.2" } objc2 = { version = "0.5.0" } glow = { version = "0.14.1" } +glfw = { version = "0.58.0"} + wgpu = { version = "22", default-features = false } wgpu-types = { version = "22" } diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index 7d5d604..e4b0871 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -30,7 +30,7 @@ array-init = "2.1.0" stable = ["librashader-reflect/stable"] [dev-dependencies] -glfw = "0.47.0" +glfw = { workspace = true } [package.metadata.docs.rs] features = ["librashader-cache/docsrs"] diff --git a/librashader-runtime-vk/Cargo.toml b/librashader-runtime-vk/Cargo.toml index 8671833..ab37d66 100644 --- a/librashader-runtime-vk/Cargo.toml +++ b/librashader-runtime-vk/Cargo.toml @@ -35,7 +35,6 @@ stable = ["librashader-reflect/stable"] [dev-dependencies] num = "0.4.0" -glfw = "0.49.0" winit = { version = "0.29.10", features = ["rwh_06"] } raw-window-handle = "0.6.2" ash-window = "0.13.0" diff --git a/librashader-test/Cargo.toml b/librashader-test/Cargo.toml index f3a9a76..b33de2f 100644 --- a/librashader-test/Cargo.toml +++ b/librashader-test/Cargo.toml @@ -17,6 +17,10 @@ pollster = "0.3.0" parking_lot = "0.12.3" image-compare = "0.4.1" gpu-allocator = "0.27.0" +bitvec = "1.0.1" +d3d12-descriptor-heap = "0.1" +glow = "0.14.1" +glfw = "0.58.0" [features] vulkan-debug = [] diff --git a/librashader-test/src/render/gl/context.rs b/librashader-test/src/render/gl/context.rs new file mode 100644 index 0000000..22fbdf3 --- /dev/null +++ b/librashader-test/src/render/gl/context.rs @@ -0,0 +1,72 @@ +// Copyright (c) 2023 Christian Vallentin +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +use anyhow::anyhow; +use glfw::{fail_on_errors, Context, Glfw, OpenGlProfileHint, PWindow, WindowHint, WindowMode}; +use glow::HasContext; +use std::sync::Arc; + +pub struct GlfwContext { + wnd: PWindow, + glfw: Glfw, + pub gl: Arc, +} + +fn debug_callback(_source: u32, _err_type: u32, _id: u32, _severity: u32, message: &str) { + println!("[gl] {message:?}"); +} + +impl GlfwContext { + pub fn new(version: GLVersion, width: u32, height: u32) -> Result { + let mut glfw = glfw::init(fail_on_errors!())?; + + let GLVersion(major, minor) = version; + glfw.window_hint(WindowHint::ContextVersion(major, minor)); + glfw.window_hint(WindowHint::OpenGlProfile(OpenGlProfileHint::Core)); + glfw.window_hint(WindowHint::OpenGlForwardCompat(true)); + glfw.window_hint(WindowHint::Visible(false)); + glfw.window_hint(WindowHint::OpenGlDebugContext(true)); + + let (mut wnd, _events) = glfw + .create_window(width, height, env!("CARGO_PKG_NAME"), WindowMode::Windowed) + .ok_or_else(|| anyhow!("No window"))?; + + wnd.make_current(); + + let mut gl = + unsafe { glow::Context::from_loader_function(|proc| wnd.get_proc_address(proc) as _) }; + + unsafe { + gl.enable(glow::DEBUG_OUTPUT); + gl.enable(glow::DEBUG_OUTPUT_SYNCHRONOUS); + gl.debug_message_callback(debug_callback); + gl.debug_message_control(glow::DONT_CARE, glow::DONT_CARE, glow::DONT_CARE, &[], true); + } + + Ok(Self { + wnd, + glfw, + gl: Arc::new(gl), + }) + } +} + +#[derive(Debug)] +pub struct GLVersion(pub u32, pub u32); diff --git a/librashader-test/src/render/gl/mod.rs b/librashader-test/src/render/gl/mod.rs new file mode 100644 index 0000000..11f9ba1 --- /dev/null +++ b/librashader-test/src/render/gl/mod.rs @@ -0,0 +1,190 @@ +mod context; + +use crate::render::gl::context::{GLVersion, GlfwContext}; +use crate::render::RenderTest; +use anyhow::anyhow; +use glow::{HasContext, PixelPackData, PixelUnpackData}; +use image::RgbaImage; +use librashader::runtime::gl::{FilterChain, FilterChainOptions, GLImage}; +use librashader::runtime::Viewport; +use librashader_runtime::image::{Image, UVDirection, RGBA8}; +use std::path::Path; +use std::sync::Arc; + +struct OpenGl { + context: GlfwContext, + use_dsa: bool, + texture: GLImage, + image_bytes: Image, +} + +pub struct OpenGl3(OpenGl); +pub struct OpenGl4(OpenGl); + +impl RenderTest for OpenGl3 { + fn render(&self, path: impl AsRef, frame_count: usize) -> anyhow::Result { + let mut filter_chain = unsafe { + FilterChain::load_from_path( + path, + Arc::clone(&self.0.context.gl), + Some(&FilterChainOptions { + glsl_version: 330, + use_dsa: false, + force_no_mipmaps: false, + disable_cache: true, + }), + ) + }?; + + Ok(self.0.render(&mut filter_chain, frame_count)?) + } +} + +impl RenderTest for OpenGl4 { + fn render(&self, path: impl AsRef, frame_count: usize) -> anyhow::Result { + let mut filter_chain = unsafe { + FilterChain::load_from_path( + path, + Arc::clone(&self.0.context.gl), + Some(&FilterChainOptions { + glsl_version: 460, + use_dsa: true, + force_no_mipmaps: false, + disable_cache: true, + }), + ) + }?; + + Ok(self.0.render(&mut filter_chain, frame_count)?) + } +} + +impl OpenGl3 { + pub fn new(image_path: impl AsRef) -> anyhow::Result { + Ok(Self(OpenGl::new(image_path, false)?)) + } +} + +impl OpenGl4 { + pub fn new(image_path: impl AsRef) -> anyhow::Result { + Ok(Self(OpenGl::new(image_path, true)?)) + } +} + +impl OpenGl { + pub fn new(image_path: impl AsRef, use_dsa: bool) -> anyhow::Result { + let image: Image = Image::load(image_path.as_ref(), UVDirection::TopLeft)?; + let height = image.size.height; + let width = image.size.width; + let version = if use_dsa { + GLVersion(4, 6) + } else { + GLVersion(3, 3) + }; + + let context = GlfwContext::new(version, width, height)?; + + let texture = unsafe { + let tex = context.gl.create_texture().map_err(|s| anyhow!("{}", s))?; + context.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + context.gl.tex_storage_2d( + glow::TEXTURE_2D, + 1, + glow::RGBA8, + image.size.width as i32, + image.size.height as i32, + ); + + context.gl.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0); + context.gl.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4); + context.gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, None); + + context.gl.tex_sub_image_2d( + glow::TEXTURE_2D, + 0, + 0, + 0, + image.size.width as i32, + image.size.height as i32, + glow::RGBA, + glow::UNSIGNED_BYTE, + PixelUnpackData::Slice(&image.bytes), + ); + + context.gl.bind_texture(glow::TEXTURE_2D, None); + tex + }; + + Ok(Self { + context, + use_dsa, + texture: GLImage { + handle: Some(texture), + format: glow::RGBA8, + size: image.size, + }, + image_bytes: image, + }) + } + + pub fn render( + &self, + chain: &mut FilterChain, + frame_count: usize, + ) -> Result { + let render_texture = unsafe { + let tex = self + .context + .gl + .create_texture() + .map_err(|s| anyhow!("{}", s))?; + self.context.gl.bind_texture(glow::TEXTURE_2D, Some(tex)); + self.context.gl.tex_storage_2d( + glow::TEXTURE_2D, + 1, + glow::RGBA8, + self.image_bytes.size.width as i32, + self.image_bytes.size.height as i32, + ); + self.context.gl.bind_texture(glow::TEXTURE_2D, None); + tex + }; + + let output = GLImage { + handle: Some(render_texture), + format: glow::RGBA8, + size: self.image_bytes.size, + }; + + unsafe { + chain.frame( + &self.texture, + &Viewport::new_render_target_sized_origin(&output, None)?, + frame_count, + None, + )?; + } + + // should be the same size as the input image + let mut data = vec![0u8; self.image_bytes.bytes.len()]; + + unsafe { + self.context + .gl + .bind_texture(glow::TEXTURE_2D, output.handle); + self.context.gl.get_tex_image( + glow::TEXTURE_2D, + 0, + glow::RGBA, + glow::UNSIGNED_BYTE, + PixelPackData::Slice(&mut data), + ) + } + Ok(RgbaImage::from_raw( + self.image_bytes.size.width, + self.image_bytes.size.height, + data, + ) + .ok_or(anyhow!("failed to create image from slice"))?) + } +} diff --git a/librashader-test/src/render/mod.rs b/librashader-test/src/render/mod.rs index 1ec2a8a..be3c825 100644 --- a/librashader-test/src/render/mod.rs +++ b/librashader-test/src/render/mod.rs @@ -1,4 +1,5 @@ pub mod d3d11; +pub mod gl; pub mod vk; pub mod wgpu; @@ -28,10 +29,10 @@ mod test { use std::fs::File; const IMAGE_PATH: &str = "../triangle.png"; - // const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-royale.slangp"; + const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-royale.slangp"; - const FILTER_PATH: &str = - "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp"; + // const FILTER_PATH: &str = + // "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp"; #[test] pub fn test_d3d11() -> anyhow::Result<()> { @@ -63,6 +64,28 @@ mod test { Ok(()) } + #[test] + pub fn test_gl3() -> anyhow::Result<()> { + + let gl = super::gl::OpenGl3::new(IMAGE_PATH)?; + let image = gl.render(FILTER_PATH, 1000)?; + + let out = File::create("out.png")?; + image.write_with_encoder(PngEncoder::new(out))?; + Ok(()) + } + + #[test] + pub fn test_gl4() -> anyhow::Result<()> { + + let gl = super::gl::OpenGl4::new(IMAGE_PATH)?; + let image = gl.render(FILTER_PATH, 1000)?; + + let out = File::create("out.png")?; + image.write_with_encoder(PngEncoder::new(out))?; + Ok(()) + } + #[test] pub fn compare() -> anyhow::Result<()> { let d3d11 = super::d3d11::Direct3D11::new(IMAGE_PATH)?;