I wrote an YUV video render in Glium, just as I did in C++ with OpenGL + GTK, using the exact same techniques: upload data to 3 pixel buffers: which end up in the 3 textures: Y, U, V, which are combined together in shader to produce an RGB image.
On C++ I get excelent performance, but on Glium I'm getting very slow performance, which gets better when I resize the window to be smaller, which makes no sense to me.
Here's the full example, in just one file, dependent only on glium: https://github.com/lucaszanella/glium_yuv_render_benchmark/blob/2d2ea2065807a5f7a3473d4997a5b3ba15693a23/src/main.rs you can clone the project and just cargo run without any difficulties.
In this example I made a simple ffmpeg buffer simulator which is empty, and gets rendered green on screen which is exactly what an empty buffer should be rendered from YUV to RGB.
Here's a pseudocode summary of what I did:
event loop wake thread:
//wake up event loop
event_loop_proxy.send_event(());
//should wake up event loop 200 times per seconds, which is sufficient for rendering in high frame rate
sleep_for_5ms();
event loop thread:
//gets a new ffmpeg simulated frame (with blank data) of size 1920x1080
let frame = consume_frame();
//Reconstructs or constructs the pixel buffers and textures if they dont exist or changed resolution
parse_frame(&frame);
//uploads Y,U,V planes to pixel buffers, and uploads to textures from pixel buffers
draw(&frame);
draw function:
fn draw(&self, frame: Frame) {
//upload Y plane of frame to Y pixel buffer
//upload Y pixel buffer to texture
//upload U plane of frame to U pixel buffer
//upload U pixel buffer to texture
//upload V plane of frame to V pixel buffer
//upload V pixel buffer to texture
//This part of the code is what seems to take longer:
//--------------------------------------------
let uniforms = uniform! {
tex_y: self.y_texture.as_ref().unwrap(),
tex_u: self.u_texture.as_ref().unwrap(),
tex_v: self.v_texture.as_ref().unwrap(),
tex_format: 0 as i32,
alpha: 1.0f32
};
let mut target = self.display.as_ref().unwrap().draw();
target.clear_color(0.0, 0.0, 0.0, 0.0);
target
.draw(
self.vertex_buffer.as_ref().unwrap(),
self.index_buffer.as_ref().unwrap(),
self.planar_program.as_ref().unwrap(),
&uniforms,
&Default::default(),
)
.unwrap();
target.finish().unwrap();
//--------------------------------------------
}
In my computer I get an average of 60 fps when the window starts, and if I make it smaller I can get 200 fps. I'm on a VM which has no GPU.
When I try to decode real video and render on it, I get 8 fps average, but VLC can render 60fps 1080p without any problems on my computer. Since I'm doing color conversion on shader, I don't see why I couldn't achieve the same in my example.