test(gl): Add OpenGL render test

This commit is contained in:
chyyran 2024-09-24 00:45:48 -04:00 committed by Ronny Chan
parent 79513a301e
commit 799d409ddb
8 changed files with 316 additions and 56 deletions

72
Cargo.lock generated
View file

@ -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",

View file

@ -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" }

View file

@ -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"]

View file

@ -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"

View file

@ -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 = []

View file

@ -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<glow::Context>,
}
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<Self, anyhow::Error> {
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);

View file

@ -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<RGBA8>,
}
pub struct OpenGl3(OpenGl);
pub struct OpenGl4(OpenGl);
impl RenderTest for OpenGl3 {
fn render(&self, path: impl AsRef<Path>, frame_count: usize) -> anyhow::Result<RgbaImage> {
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<Path>, frame_count: usize) -> anyhow::Result<RgbaImage> {
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<Path>) -> anyhow::Result<Self> {
Ok(Self(OpenGl::new(image_path, false)?))
}
}
impl OpenGl4 {
pub fn new(image_path: impl AsRef<Path>) -> anyhow::Result<Self> {
Ok(Self(OpenGl::new(image_path, true)?))
}
}
impl OpenGl {
pub fn new(image_path: impl AsRef<Path>, use_dsa: bool) -> anyhow::Result<Self> {
let image: Image<RGBA8> = 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<RgbaImage, anyhow::Error> {
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"))?)
}
}

View file

@ -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)?;