Skip to content
This repository was archived by the owner on Jun 8, 2021. It is now read-only.

Commit 00eb0b2

Browse files
Merge pull request #184 from sdroege/cairo-threads
Fix compilation of cairo-threads example
2 parents 1c45c3e + bbc8cbe commit 00eb0b2

File tree

1 file changed

+32
-33
lines changed

1 file changed

+32
-33
lines changed

src/bin/cairo_threads.rs

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,17 @@ macro_rules! clone {
4444
// | 2 | 3 |
4545
// +---+---+
4646
//
47-
// Each worker thread waits for a buffer (Box<[u8]>) to render into, wraps
48-
// it into ImageSurface, sleeps for a while, does the drawing, then sends the
49-
// underlying buffer back and waits for the next one.
47+
// Each worker thread waits for an image (cairo::ImageSurface) to render into, sleeps for a while,
48+
// does the drawing, then sends the image back and waits for the next one.
5049
//
5150
// The GUI thread holds an ImageSurface per image part at all times, these
5251
// surfaces are painted on a DrawingArea in its 'draw' signal handler. This
53-
// thread periodically checks if any worker has sent a freshly rendered buffer.
52+
// thread periodically checks if any worker has sent a freshly rendered image.
5453
// Upon receipt it's wrapped in ImageSurface and swapped with the previously
55-
// held surface, whose buffer is sent to the worker thread again. Then the
54+
// held surface, whose image is sent to the worker thread again. Then the
5655
// appropriate part of the DrawingArea is invalidated prompting a redraw.
5756
//
58-
// The two buffers per thread are allocated and initialized once and sent back
57+
// The two images per thread are allocated and initialized once and sent back
5958
// and forth repeatedly.
6059

6160
fn build_ui(application: &gtk::Application) {
@@ -73,7 +72,7 @@ fn build_ui(application: &gtk::Application) {
7372
let height = 200;
7473
area.set_size_request(width * 2, height * 2);
7574

76-
let (initial_buf, stride) = draw_initial(format, width, height);
75+
let initial_image = draw_initial(format, width, height);
7776
let (ready_tx, ready_rx) = mpsc::channel();
7877

7978
let mut images = Vec::new();
@@ -82,15 +81,13 @@ fn build_ui(application: &gtk::Application) {
8281

8382
for thread_num in 0..4 {
8483
let (tx, rx) = mpsc::channel();
85-
// allocate two buffers and copy the initial pattern into them
86-
let buf0 = initial_buf.clone();
87-
let buf1 = initial_buf.clone();
88-
// wrap the first one in a surface and set it up to be sent to the
89-
// worker when the surface is destroyed
90-
images.push(ImageSurface::create_for_data(buf0, clone!(tx => move |b| { let _ = tx.send(b); }),
91-
format, width, height, stride).expect("Can't create surface"));
84+
// copy the initial image in two images for the workers
85+
let image0 = duplicate_image(&initial_image);
86+
let image1 = duplicate_image(&initial_image);
87+
// store the first one in our vec
88+
images.push(image0);
9289
// send the second one immediately
93-
let _ = tx.send(buf1);
90+
let _ = tx.send(image1);
9491
origins.push(match thread_num {
9592
0 => (0, 0),
9693
1 => (width, 0),
@@ -106,16 +103,13 @@ fn build_ui(application: &gtk::Application) {
106103
// spawn the worker thread
107104
thread::spawn(clone!(ready_tx => move || {
108105
let mut n = 0;
109-
for buf in rx.iter() {
106+
for image in rx.iter() {
110107
n = (n + 1) % 0x10000;
111-
// create the surface and send the buffer back when it's destroyed
112-
let image = ImageSurface::create_for_data(buf,
113-
clone!(ready_tx => move |b| { let _ = ready_tx.send((thread_num, b)); }),
114-
format, width, height, stride).expect("Can't create surface");
115108
let cr = Context::new(&image);
116109
// draw an arc with a weirdly calculated radius
117110
draw_slow(&cr, delay, x, y, 1.2_f64.powi(((n as i32) << thread_num) % 32));
118111
image.flush();
112+
let _ = ready_tx.send((thread_num, image));
119113
}
120114
}));
121115
}
@@ -128,21 +122,16 @@ fn build_ui(application: &gtk::Application) {
128122
let (ref images, ref origins, _) = *cell.borrow();
129123
for (image, origin) in images.iter().zip(origins.iter()) {
130124
draw_image_if_dirty(&cr, image, *origin, (width, height));
131-
// if we don't reset the source, the context may hold on to
132-
// the surface indefinitely, the buffer will be stuck there
133-
// and the worker thread will starve
134-
cr.set_source_rgb(0., 0., 0.);
135125
}
136126
Inhibit(false)
137127
}));
138128

139129
gtk::timeout_add(100, move || {
140-
while let Ok((thread_num, buf)) = ready_rx.try_recv() {
130+
while let Ok((thread_num, mut image)) = ready_rx.try_recv() {
141131
let &mut (ref mut images, ref origins, ref workers) = &mut *cell.borrow_mut();
142-
let tx = workers[thread_num].clone();
143-
let mut image = ImageSurface::create_for_data(buf, move |b| { let _ = tx.send(b); },
144-
format, width, height, stride).expect("Can't create surface");
132+
let tx = &workers[thread_num];
145133
mem::swap(&mut images[thread_num], &mut image);
134+
let _ = tx.send(image);
146135
area.queue_draw_area(origins[thread_num].0, origins[thread_num].1, width, height);
147136
}
148137
Continue(true)
@@ -164,17 +153,16 @@ fn main() {
164153
application.run(&args().collect::<Vec<_>>());
165154
}
166155

167-
fn draw_initial(format: Format, width: i32, height: i32) -> (Box<[u8]>, i32) {
168-
let mut image = ImageSurface::create(format, width, height).expect("Can't create surface");
156+
fn draw_initial(format: Format, width: i32, height: i32) -> ImageSurface {
157+
let image = ImageSurface::create(format, width, height).expect("Can't create surface");
169158
{
170159
let cr = Context::new(&image);
171160
cr.set_source_rgb(0., 1., 0.);
172161
cr.paint();
173162
// Destroying the context releases its reference to `image`.
174163
}
175-
// We have a unique reference to `image` again.
176-
let buf = image.get_data().expect("Couldn't get data from image").to_vec();
177-
(buf.into_boxed_slice(), image.get_stride())
164+
// We have a unique reference to `image` again and return it
165+
image
178166
}
179167

180168
fn draw_slow(cr: &Context, delay: Duration, x: f64, y: f64, radius: f64) {
@@ -199,3 +187,14 @@ fn draw_image_if_dirty(cr: &Context, image: &ImageSurface, origin: (i32, i32),
199187
cr.set_source_surface(image, x, y);
200188
cr.paint();
201189
}
190+
191+
fn duplicate_image(image: &ImageSurface) -> ImageSurface {
192+
let image_dup = ImageSurface::create(image.get_format(), image.get_width(), image.get_height()).expect("Can't create surface");
193+
{
194+
let cr = Context::new(&image_dup);
195+
cr.set_source_surface(image, 0.0, 0.0);
196+
cr.paint();
197+
}
198+
199+
image_dup
200+
}

0 commit comments

Comments
 (0)