gl: use texture storage

This commit is contained in:
chyyran 2022-11-19 01:55:49 -05:00
parent afc750c37c
commit 3aee36a361
5 changed files with 264 additions and 76 deletions

View file

@ -1,15 +1,15 @@
use std::iter::Filter;
use gl::types::{GLenum, GLint, GLuint};
use gl::types::{GLenum, GLint, GLsizei, GLsizeiptr, GLuint};
use librashader_reflect::back::cross::GlslangGlslContext;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::ShaderReflection;
use librashader_reflect::reflect::TextureSemanticMap;
use librashader_reflect::reflect::VariableSemanticMap;
use rustc_hash::FxHashMap;
use librashader::ShaderSource;
use librashader::{ShaderFormat, ShaderSource};
use librashader_presets::{Scale2D, ScaleType, Scaling, ShaderPassConfig, ShaderPreset};
use librashader_reflect::reflect::semantics::{MemberOffset, SemanticMap, TextureImage, TextureSemantics, VariableMeta, VariableSemantics};
use crate::FilterChain;
use crate::{FilterChain, FilterCommon};
use crate::framebuffer::Framebuffer;
use crate::util::{Location, VariableLocation, RingBuffer, Size, GlImage, Texture, Viewport};
@ -84,6 +84,7 @@ impl FilterPass {
fn set_texture(binding: &TextureImage, texture: &Texture) {
unsafe {
// eprintln!("binding {} = texture {}", binding.binding, texture.image.handle);
gl::ActiveTexture((gl::TEXTURE0 + binding.binding) as GLenum);
gl::BindTexture(gl::TEXTURE_2D, texture.image.handle);
@ -94,7 +95,7 @@ impl FilterPass {
}
}
fn scale_framebuffer(&mut self, viewport: &Viewport, original: &Texture, source: &Texture) -> Size {
fn scale_framebuffer(&mut self, format: ShaderFormat, viewport: &Viewport, original: &Texture, source: &Texture) -> Size {
let mut width = 0f32;
let mut height = 0f32;
@ -145,20 +146,107 @@ impl FilterPass {
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
}
pub fn build_commands(&mut self, parent: &FilterChain, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, viewport: &Viewport, original: &Texture, source: &Texture) {
pub fn build_commands(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, viewport: &Viewport, original: &Texture, source: &Texture) {
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;
}
let fb_size = self.scale_framebuffer(fb_format, viewport, original, source);
// println!("[frame] Using framebuffer {}, image {}", self.framebuffer.framebuffer, self.framebuffer.image);
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer.framebuffer);
gl::UseProgram(self.program);
}
self.build_semantics(parent, mvp, frame_count, frame_direction, fb_size, viewport, original, source);
// shader_gl3:1514
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) {
let size = ubo.size;
let buffer = ring.current();
unsafe {
gl::BindBuffer(gl::UNIFORM_BUFFER, *buffer);
gl::BufferSubData(gl::UNIFORM_BUFFER, 0, size as GLsizeiptr, self.uniform_buffer.as_ptr().cast());
gl::BindBuffer(gl::UNIFORM_BUFFER, 0);
if self.ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.vertex, *buffer);
}
if self.ubo_location.vertex != gl::INVALID_INDEX {
gl::BindBufferBase(gl::UNIFORM_BUFFER, self.ubo_location.fragment, *buffer);
}
}
ring.next()
}
}
// todo: final pass?
unsafe {
gl::BindFramebuffer(gl::FRAMEBUFFER, self.framebuffer.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(viewport.x, viewport.y, fb_size.width as GLsizei, fb_size.height as GLsizei);
if self.framebuffer.format == gl::SRGB8_ALPHA8 {
gl::Enable(gl::FRAMEBUFFER_SRGB);
} else {
gl::Disable(gl::FRAMEBUFFER_SRGB);
}
gl::Disable(gl::CULL_FACE);
gl::Disable(gl::BLEND);
gl::Disable(gl::DEPTH_TEST);
gl::EnableVertexAttribArray(0);
gl::EnableVertexAttribArray(1);
gl::BindBuffer(gl::ARRAY_BUFFER, parent.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.
/// that are inexpressible in Rust
gl::VertexAttribPointer(0, 2, 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::BindBuffer(gl::ARRAY_BUFFER, 0);
gl::DisableVertexAttribArray(0);
gl::DisableVertexAttribArray(1);
gl::Disable(gl::FRAMEBUFFER_SRGB);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
// todo: draw image onto fbo
// shader_gl3 1579
}
// framecount should be pre-modded
fn build_semantics(&mut self, parent: &FilterChain, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, viewport: &Viewport, original: &Texture, source: &Texture) {
let fb_size = self.scale_framebuffer(viewport, original, source);
fn build_semantics(&mut self, parent: &FilterCommon, mvp: Option<&[f32]>, frame_count: u32, frame_direction: u32, fb_size: Size, viewport: &Viewport, original: &Texture, source: &Texture) {
if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::MVP) {
let mvp = mvp.unwrap_or(&[
@ -172,7 +260,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset)
};
FilterPass::build_mvp(&mut buffer[offset..][..mvp.len()], mvp)
FilterPass::build_mvp(&mut buffer[offset..][..mvp.len() * std::mem::size_of::<f32>()], mvp)
}
if let Some(variable) = self.reflection.meta.variable_meta.get(&VariableSemantics::Output) {
@ -215,6 +303,11 @@ impl FilterPass {
FilterPass::build_uint(location, &mut buffer[offset..][..4], frame_direction)
}
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Original.semantics(0)) {
eprintln!("setting original binding to {}", binding.binding);
FilterPass::set_texture(binding, original);
}
if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::Original.semantics(0)) {
let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();
let (buffer, offset) = match variable.offset {
@ -223,11 +316,13 @@ impl FilterPass {
};
FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Original.semantics(0)) {
FilterPass::set_texture(binding, original);
}
}
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Source.semantics(0)) {
// eprintln!("setting source binding to {}", binding.binding);
FilterPass::set_texture(binding, source);
}
if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::Source.semantics(0)) {
let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();
let (buffer, offset) = match variable.offset {
@ -235,24 +330,22 @@ impl FilterPass {
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset)
};
FilterPass::build_vec4(location, &mut buffer[offset..][..4], source.image.size);
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::Source.semantics(0)) {
FilterPass::set_texture(binding, source);
}
}
if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();
let (buffer, offset) = match variable.offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset)
};
FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
FilterPass::set_texture(binding, original);
}
}
// todo: history
// if let Some(binding) = self.reflection.meta.texture_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
// FilterPass::set_texture(binding, original);
// }
// if let Some(variable) = self.reflection.meta.texture_size_meta.get(&TextureSemantics::OriginalHistory.semantics(0)) {
// let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();
// let (buffer, offset) = match variable.offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer, offset)
// };
// FilterPass::build_vec4(location, &mut buffer[offset..][..4], original.image.size);
// }
for variable in self.reflection.meta.parameter_meta.values() {
let location = self.locations.get(&variable.id).expect("variable did not have location mapped").location();

View file

@ -13,29 +13,13 @@ pub struct Framebuffer {
pub init: bool
}
impl Drop for Framebuffer {
fn drop(&mut self) {
if self.framebuffer != 0 {
unsafe {
gl::DeleteFramebuffers(1, &self.framebuffer);
}
}
if self.image != 0 {
unsafe {
gl::DeleteTextures(1, &self.image);
}
}
}
}
impl Framebuffer {
pub fn new(max_levels: u32) -> Framebuffer {
let mut framebuffer = 0;
unsafe {
gl::GenFramebuffers(1, &mut framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, framebuffer);
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
Framebuffer {
@ -49,12 +33,8 @@ impl Framebuffer {
}
}
fn init(&mut self, mut size: Size, mut format: ShaderFormat) {
if format == ShaderFormat::Unknown {
format = ShaderFormat::R8G8B8A8Unorm;
}
self.format = GLenum::from(format);
pub(crate) fn init(&mut self, mut size: Size, mut format: impl Into<GLenum>) {
self.format = format.into();
self.size = size;
unsafe {
@ -67,7 +47,7 @@ impl Framebuffer {
}
gl::GenTextures(1, &mut self.image);
gl::BindTexture(1, self.image);
gl::BindTexture(gl::TEXTURE_2D, self.image);
if size.width == 0 {
size.width = 1;
@ -108,12 +88,12 @@ impl Framebuffer {
self.levels = 1;
}
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, gl::RGBA8, size.width as GLsizei, size.height as GLsizei);
gl::TexStorage2D(gl::TEXTURE_2D, self.levels as GLsizei, 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}")
_ => panic!("failed to complete: {status:x}")
}
} else {
self.init = true;
@ -124,3 +104,16 @@ impl Framebuffer {
}
}
}
impl Drop for Framebuffer {
fn drop(&mut self) {
unsafe {
if self.framebuffer != 0 {
gl::DeleteFramebuffers(1, &self.framebuffer);
}
if self.image != 0 {
gl::DeleteTextures(1, &self.image);
}
}
}
}

View file

@ -1,11 +1,14 @@
use std::convert::TryInto;
use std::ffi::{c_void, CStr};
use std::sync::mpsc::Receiver;
use glfw;
use glfw::{Context, Glfw, Window, WindowEvent};
use gl;
use gl::types::{GLint, GLsizei, GLuint};
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use glfw::Key::P;
use crate::FilterChain;
use crate::util::{GlImage, Size, Viewport};
const WIDTH: u32 = 900;
const HEIGHT: u32 = 700;
@ -72,12 +75,21 @@ pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
shader_program
}
extern "system" fn debug_callback(source: GLenum, err_type: GLenum, id: GLuint, severity: GLenum, length: GLsizei, message: *const GLchar, _user: *mut c_void) {
unsafe {
let message = CStr::from_ptr(message);
eprintln!("{:?}", message);
}
}
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));
glfw.window_hint(glfw::WindowHint::OpenGlDebugContext(true));
let (mut window, events) = glfw.create_window(WIDTH, HEIGHT, TITLE, glfw::WindowMode::Windowed).unwrap();
let (screen_width, screen_height) = window.get_framebuffer_size();
@ -86,6 +98,18 @@ pub fn setup() -> (Glfw, Window, Receiver<(f64, WindowEvent)>, GLuint, GLuint) {
window.set_key_polling(true);
gl::load_with(|ptr| window.get_proc_address(ptr) as *const _);
unsafe {
gl::Enable(gl::DEBUG_OUTPUT);
gl::Enable(gl::DEBUG_OUTPUT_SYNCHRONOUS);
gl::DebugMessageCallback(Some(debug_callback), std::ptr::null_mut());
gl::DebugMessageControl(gl::DONT_CARE,
gl::DONT_CARE,
gl::DONT_CARE,
0, std::ptr::null(), gl::TRUE);
}
unsafe {
gl::Viewport(0, 0, screen_width, screen_height);
clear_color(Color(0.4, 0.4, 0.4, 1.0));
@ -192,7 +216,7 @@ void main()
(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) {
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;
let mut rendered_texture = 0;
let mut quad_vbuf = 0;
@ -207,7 +231,7 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
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::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);
@ -215,7 +239,7 @@ pub fn do_loop(mut glfw: Glfw, mut window: Window, events: Receiver<(f64, Window
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);
gl::FramebufferTexture2D(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, rendered_texture, 0);
let buffers = [gl::COLOR_ATTACHMENT0];
gl::DrawBuffers(1, buffers.as_ptr());
@ -290,12 +314,12 @@ void main()
gl::Viewport(0, 0, WIDTH as GLsizei, HEIGHT as GLsizei);
// 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);
// do the drawing
gl::UseProgram(shader_program);
gl::UseProgram(triangle_program);
// select vertices
gl::BindVertexArray(vao);
@ -305,7 +329,33 @@ void main()
// unselect vertices
gl::BindVertexArray(0);
// unselect fbo
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
}
// eprintln!("[core] rendered texture is {rendered_texture}");
unsafe {
filter.frame(0, &Viewport {
x: 0,
y: 0,
size: Size {
width: WIDTH,
height: HEIGHT
}
}, GlImage {
handle: rendered_texture,
format: gl::RGBA,
size: Size {
width: WIDTH,
height: HEIGHT
},
padded_size: Default::default()
}, false)
}
unsafe {
// texture is done now.
// todo: insert postprocessing stuff to rendered_texture

View file

@ -1,3 +1,5 @@
#![feature(strict_provenance)]
mod hello_triangle;
mod filter;
mod filter_pass;
@ -42,6 +44,13 @@ unsafe fn gl_compile_shader(stage: GLenum, source: &str) -> GLuint {
shader
}
static QUAD_VBO_DATA: &'static [f32; 16] = &[
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, 1.0f32, 1.0f32, 1.0f32,
];
impl FilterChain {
fn load_pass_semantics(uniform_semantics: &mut FxHashMap<String, UniformSemantic>, texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
config: &ShaderPassConfig) {
@ -114,12 +123,19 @@ impl FilterChain {
pub struct FilterChain {
passes: Vec<FilterPass>,
common: FilterCommon,
pub quad_vao: GLuint,
}
pub struct FilterCommon {
semantics: ReflectSemantics,
preset: ShaderPreset,
original_history: Vec<Framebuffer>,
history: Vec<Texture>,
feedback: Vec<Texture>,
luts: FxHashMap<String, Texture>
luts: FxHashMap<String, Texture>,
pub quad_vbo: GLuint,
pub input_framebuffer: Framebuffer,
}
impl FilterChain {
@ -194,7 +210,8 @@ impl FilterChain {
for res in &vertex_resources.stage_inputs {
let loc = glsl.context.compiler.vertex.get_decoration(res.id, Decoration::Location)?;
let loc_name = format!("RARCH_ATTRIBUTE_{loc}");
let loc_name = format!("RARCH_ATTRIBUTE_{loc}\0");
eprintln!("{loc_name}");
gl::BindAttribLocation(program, loc, loc_name.as_str().as_ptr().cast())
}
gl::LinkProgram(program);
@ -208,7 +225,7 @@ impl FilterChain {
}
for binding in &glsl.context.texture_fixups {
let loc_name = format!("RARCH_TEXTURE_{}", *binding);
let loc_name = format!("RARCH_TEXTURE_{}\0", *binding);
unsafe {
let location = gl::GetUniformLocation(program, loc_name.as_str().as_ptr().cast());
if location >= 0 {
@ -373,24 +390,51 @@ impl FilterChain {
});
}
let mut quad_vbo = 0;
unsafe {
gl::GenBuffers(1, &mut quad_vbo);
gl::BindBuffer(gl::ARRAY_BUFFER, quad_vbo);
gl::BufferData(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);
}
let mut quad_vao = 0;
unsafe {
gl::GenVertexArrays(1, &mut quad_vao);
}
// todo: split params
Ok(FilterChain {
passes: filters,
quad_vao,
common: FilterCommon {
semantics,
preset,
original_history: vec![],
history: vec![],
feedback: vec![],
luts,
quad_vbo,
input_framebuffer: Framebuffer::new(1)
}
})
}
// how much info do we actually need?
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) {
//
// unsafe {
// gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
// gl::BindVertexArray(self.quad_vao);
// }
// todo: copy framebuffer
// shader_gl3: 2067
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 filter = self.preset.shaders.first().map(|f| f.filter).unwrap_or_default();
let wrap_mode = self.preset.shaders.first().map(|f| f.wrap_mode).unwrap_or_default();
let original = Texture {
image: input,
filter,
@ -401,9 +445,15 @@ impl FilterChain {
let mut source = original.clone();
for passes in &mut self.passes {
passes.build_commands(&self.common, None, count, 1, vp, &original, &source);
// passes.build_semantics(&self, None, count, 1, vp, &original, &source);
}
// unsafe {
// gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
// gl::BindVertexArray(0);
// }
// todo: deal with the mess that is frame history
}
@ -412,8 +462,8 @@ impl FilterChain {
// todo: make copy
// todo: get filter info from pass data.
let filter = self.preset.shaders.first().map(|f| f.filter).unwrap_or_default();
let wrap_mode = self.preset.shaders.first().map(|f| f.wrap_mode).unwrap_or_default();
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,
@ -437,10 +487,12 @@ mod tests {
#[test]
fn triangle() {
let (glfw, window, events, shader, vao) = hello_triangle::setup();
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();
hello_triangle::do_loop(glfw, window, events, shader, vao);
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter );
}
// #[test]

View file

@ -47,7 +47,7 @@ pub struct Viewport {
pub size: Size,
}
#[derive(Default, Debug, Copy, Clone)]
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Size {
pub width: u32,
pub height: u32,