From c5557d5043fa8282c28768fa647ea057d67ce727 Mon Sep 17 00:00:00 2001 From: Imanol Fernandez Date: Mon, 26 Sep 2016 12:27:43 +0200 Subject: [PATCH 1/2] Implement multithreading tests --- src/tests.rs | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/src/tests.rs b/src/tests.rs index a46bae5..8daecf2 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -12,6 +12,8 @@ use NativeGLContext; use NativeGLContextMethods; use GLContextAttributes; use ColorAttachmentType; +use std::{thread, time}; +use std::sync::mpsc; #[cfg(target_os="macos")] #[link(name="OpenGL", kind="framework")] @@ -157,6 +159,119 @@ fn test_sharing() { test_pixels(&vec); } +#[test] +fn test_multithread_render() { + load_gl(); + + let size = Size2D::new(256, 256); + let primary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + None).unwrap(); + test_gl_context(&primary); + let (sender, receiver) = mpsc::channel(); + thread::spawn(move ||{ + //create the context in a different thread + let secondary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + None).unwrap(); + secondary.make_current().unwrap(); + assert!(secondary.is_current()); + //render green adn test pixels + gl::clear_color(0.0, 1.0, 0.0, 1.0); + gl::clear(gl::COLOR_BUFFER_BIT); + + let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); + test_pixels_eq(&vec, &[0, 255, 0, 255]); + + sender.send(()).unwrap(); + + // Avoid drop until test ends + loop { + thread::sleep(time::Duration::from_millis(200)); + } + }); + // Wait until thread has drawn the texture + receiver.recv().unwrap(); + // This context must remain to be current in this thread + assert!(primary.is_current()); + + // The colors must remain unchanged + let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); + test_pixels_eq(&vec, &[255, 0, 0, 255]); +} + +struct SGLUint(gl::GLuint); +unsafe impl Sync for SGLUint {} +unsafe impl Send for SGLUint {} + +#[test] +fn test_multithread_sharing() { + load_gl(); + + let size = Size2D::new(256, 256); + let primary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + None).unwrap(); + primary.make_current().unwrap(); + + let primary_texture_id = primary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); + assert!(primary_texture_id != 0); + + let (sender, receiver) = mpsc::channel(); + let primary_handle = primary.handle(); + + // Unbind required by some APIs as WGL + primary.unbind().unwrap(); + + thread::spawn(move || { + // Create the context in a different thread + let secondary = GLContext::::new(size, + GLContextAttributes::default(), + ColorAttachmentType::Texture, + Some(&primary_handle)).unwrap(); + // Make the context current on this thread only + secondary.make_current().unwrap(); + // Paint the second context red + test_gl_context(&secondary); + // Send texture_id to main thread + let texture_id = secondary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); + assert!(texture_id != 0); + sender.send(SGLUint(texture_id)).unwrap(); + // Avoid drop until test ends + loop { + thread::sleep(time::Duration::from_millis(200)); + } + }); + // Wait until thread has drawn the texture + let secondary_texture_id = receiver.recv().unwrap().0; + + primary.make_current().unwrap(); + + // Clearing and re-binding to a framebuffer instead of using getTexImage since it's not + // available in GLES2 + gl::clear_color(0.0, 0.0, 0.0, 1.0); + gl::clear(gl::COLOR_BUFFER_BIT); + + let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); + test_pixels_eq(&vec, &[0, 0, 0, 255]); + + + unsafe { + gl::FramebufferTexture2D(gl::FRAMEBUFFER, + gl::COLOR_ATTACHMENT0, + gl::TEXTURE_2D, + secondary_texture_id, 0); + } + + let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); + assert!(gl::get_error() == gl::NO_ERROR); + + test_pixels(&vec); +} + #[test] fn test_limits() { load_gl(); @@ -263,4 +378,4 @@ fn test_zero_size() { GLContextAttributes::default(), ColorAttachmentType::Texture, None).unwrap(); -} +} \ No newline at end of file From 9a9765f655b6cfb62aa4a89b9aecba0cf8643a48 Mon Sep 17 00:00:00 2001 From: Imanol Fernandez Date: Mon, 26 Sep 2016 14:13:18 +0200 Subject: [PATCH 2/2] Improve multithread test end waiting code --- src/tests.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index 8daecf2..d6b7cbf 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -12,7 +12,7 @@ use NativeGLContext; use NativeGLContextMethods; use GLContextAttributes; use ColorAttachmentType; -use std::{thread, time}; +use std::thread; use std::sync::mpsc; #[cfg(target_os="macos")] @@ -169,7 +169,8 @@ fn test_multithread_render() { ColorAttachmentType::Texture, None).unwrap(); test_gl_context(&primary); - let (sender, receiver) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); + let (end_tx, end_rx) = mpsc::channel(); thread::spawn(move ||{ //create the context in a different thread let secondary = GLContext::::new(size, @@ -185,21 +186,21 @@ fn test_multithread_render() { let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); test_pixels_eq(&vec, &[0, 255, 0, 255]); - sender.send(()).unwrap(); + tx.send(()).unwrap(); // Avoid drop until test ends - loop { - thread::sleep(time::Duration::from_millis(200)); - } + end_rx.recv().unwrap(); }); // Wait until thread has drawn the texture - receiver.recv().unwrap(); + rx.recv().unwrap(); // This context must remain to be current in this thread assert!(primary.is_current()); // The colors must remain unchanged let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE); test_pixels_eq(&vec, &[255, 0, 0, 255]); + + end_tx.send(()).unwrap(); } struct SGLUint(gl::GLuint); @@ -220,7 +221,8 @@ fn test_multithread_sharing() { let primary_texture_id = primary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); assert!(primary_texture_id != 0); - let (sender, receiver) = mpsc::channel(); + let (tx, rx) = mpsc::channel(); + let (end_tx, end_rx) = mpsc::channel(); let primary_handle = primary.handle(); // Unbind required by some APIs as WGL @@ -239,14 +241,12 @@ fn test_multithread_sharing() { // Send texture_id to main thread let texture_id = secondary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap(); assert!(texture_id != 0); - sender.send(SGLUint(texture_id)).unwrap(); + tx.send(SGLUint(texture_id)).unwrap(); // Avoid drop until test ends - loop { - thread::sleep(time::Duration::from_millis(200)); - } + end_rx.recv().unwrap(); }); // Wait until thread has drawn the texture - let secondary_texture_id = receiver.recv().unwrap().0; + let secondary_texture_id = rx.recv().unwrap().0; primary.make_current().unwrap(); @@ -270,6 +270,7 @@ fn test_multithread_sharing() { assert!(gl::get_error() == gl::NO_ERROR); test_pixels(&vec); + end_tx.send(()).unwrap(); } #[test]