Is there any way in glium to pass an array to a shader? I tried to do it with a uniform block, like this:

//Rust #[derive(Copy, Clone)] struct Circle { position: (f32, f32), radius: u32 } #[derive(Copy, Clone)] struct UniformBlock { map: [Circle; 64] } implement_uniform_block!(Circle, position, radius); implement_uniform_block!(UniformBlock, map); let buffer = UniformBuffer::new(&display, UniformBlock::new([Circle::new((20., 20.), 8); 64])).unwrap(); uniform! { MapBlock: &buffer } //GLSL struct Circle { vec2 position; uint radius; }; layout(std140) uniform MapBlock { Circle map[64]; }; 

but got the following run-time error:

Err value: UniformBlockLayoutMismatch {name: "MapBlock", err: MemberMismatch {member: "map", err: MemberMismatch {member: "", err: MemberMismatch {member: "position", err : OffsetMismatch {expected: 16, obtained: 0}}}}}

This error can somehow be solved? Or are there other ways to pass an array to the shader? Full code:

 //Rust #[macro_use] extern crate glium; use glium::{ glutin, uniforms::{ UniformValue, UniformBuffer, AsUniformValue }, vertex::{ Attribute, AttributeType } }; extern crate nalgebra as na; use std::{ fs::File, fmt::Debug, io::prelude::* }; #[derive(Copy, Clone)] struct Point2<T: 'static + Copy + PartialEq + Debug>(na::Point2<T>); impl<T: 'static + Copy + PartialEq + Debug> Point2<T> { fn new(x: T, y: T) -> Self { Point2(na::Point2::new(x, y)) } } unsafe impl Attribute for Point2<f32> { #[inline] fn get_type() -> AttributeType { AttributeType::F32F32 } } impl AsUniformValue for Point2<f32> { fn as_uniform_value(&self) -> UniformValue { UniformValue::Vec2([self.0.x, self.0.y]) } } #[derive(Copy, Clone)] struct Vertex { position: Point2<f32> } impl Vertex { fn new(position: Point2<f32>) -> Self { Self { position } } } #[derive(Copy, Clone)] struct Circle { position: (f32, f32), radius: u32, _padding: u32 } impl Circle { fn new(position: (f32, f32), radius: u32) -> Self { Self { position, radius, _padding: 0 } } } #[derive(Copy, Clone)] struct UniformBlock { map: [Circle; 64] } impl UniformBlock { fn new(map: [Circle; 64]) -> Self { Self { map } } } implement_vertex!(Vertex, position); implement_uniform_block!(Circle, position, radius); implement_uniform_block!(UniformBlock, map); fn main() { let mut events_loop = glutin::EventsLoop::new(); let display = { let window = glutin::WindowBuilder::new() .with_title("Window"); let context = glutin::ContextBuilder::new() .with_vsync(true); glium::Display::new(window, context, &events_loop).unwrap() }; let vertex_buffer = glium::VertexBuffer::new(&display, &[ Vertex::new(Point2::new(-1.0, 1.0)), Vertex::new(Point2::new(-1.0, -1.0)), Vertex::new(Point2::new( 1.0, -1.0)), Vertex::new(Point2::new( 1.0, 1.0)) ]).unwrap(); let indices = glium::IndexBuffer::new(&display, glium::index::PrimitiveType::TrianglesList, &[ 0, 1, 3, 1, 2, 3u8 ]).unwrap(); let program = { let mut v_sh_src = String::new(); File::open("shaders/vertex.glsl").unwrap() .read_to_string(&mut v_sh_src).unwrap(); let mut f_sh_src = String::new(); File::open("shaders/fragment.glsl").unwrap() .read_to_string(&mut f_sh_src).unwrap(); glium::Program::from_source(&display, v_sh_src.as_str(), f_sh_src.as_str(), None).unwrap() }; let buffer = UniformBuffer::new(&display, UniformBlock::new([Circle::new((20., 20.), 8); 64])).unwrap(); let mut done = false; while !done { use glium::Surface; let mut target = display.draw(); target.clear_color(0.0, 0.0, 0.0, 1.0); target.draw(&vertex_buffer, &indices, &program, &uniform! { mapBlock: &buffer }, &Default::default()).unwrap(); target.finish().unwrap(); events_loop.poll_events(|event| { use glutin::{ Event, WindowEvent, ElementState, VirtualKeyCode }; match event { Event::WindowEvent { event, window_id } => if window_id == display.gl_window().id() { match event { WindowEvent::CloseRequested => done = true, WindowEvent::KeyboardInput { input, .. } => { match input.state { ElementState::Released => match input.virtual_keycode { Some(VirtualKeyCode::Escape) => done = true, _ => () } _ => () } } _ => () } } _ => () } }); } } //fragment.glsl #version 330 core struct Circle { vec2 position; uint radius; }; layout(std140) uniform mapBlock { Circle map[64]; }; void main() { for (int i = 0; i < 64; ++i) if (distance(map[i].position, gl_FragCoord.xy) <= map[i].radius) gl_FragColor = vec4(0.0f, 0.5f, 0.0f, 1.0f); } //vertex.glsl #version 330 core layout (location = 0) in vec2 position; void main() { gl_Position = vec4(position, 0.0f, 1.0f); } 
  • github.com/glium/glium/issues/1422 can from this task what will help - ozkriff
  • @ozkriff, read. The explanation of my problem is not there. I wanted to find a solution easier than to implement my uniform. - Rah_837
  • The error did not reproduce, the green circle was drawn. Correct the vertex shader. Indicate the versions of Rust, toolchain and libraries used. - Asaq
  • @Asaq, Rust - 1.28.0 stable, glium - 0.22.0, nalgebra - 0.16.0. And what's wrong with the vertex shader? - Rah_837
  • @Asaq, the shader corrected - Rah_837

1 answer 1

For the std140 there are field alignment rules:

  • Scalars bool , int , etc. - 4 bytes
  • vec2 - 8 bytes
  • vec4 - 16 bytes
  • vec3 - 16 bytes
  • struct is like vec4
  • array of scalars or vectors - like vec4
  • matrices are like vector arrays

For a complete list of rules, see The OpenGL® Graphics System specification , Version 4.5, Core Profile , June 29, 2017, p. 159. - §7.6.2.2 Standard Uniform Block Layout.

 struct Circle { vec2 position; uint radius; }; 

In your case, the structure fields are aligned by 8 and 4 bytes, but the structure must be aligned by 16 bytes. The size of the uniform block can be found through glGetActiveUniformBlockiv with the parameter GL_UNIFORM_BLOCK_DATA_SIZE .

Therefore, the structure in the application must be aligned to 16 bytes, for example:

 struct Circle { position: (f32, f32), radius: u32, padding: u32 } 
  • Each time a shader expects a structure with a different size, for example, like this: expected: 160, expected: 32, expected: 48 - Rah_837
  • Sometimes (after 4-8 launches) the sizes of the structures are the same and then everything works - Rah_837
  • padding work? - Asaq
  • padding helped, but partially. Without it, it did not work even in those rare cases when the expected block size coincided with the received one. He works with him, but, I repeat, in rare cases, so this did not solve the problem - Rah_837
  • Is it possible to lay out a minimal source code that gives an error, including shaders? - Asaq