summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-01-24 14:46:03 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2013-01-24 15:25:16 +0000
commit8ecfbea9d1f83b2de62bee0f58299e7a90c741d1 (patch)
treed5cf796af6152b58238880397550a9aea3f9237c
parent778dba90cfc4e801a975bd661c56a565ce60524b (diff)
sna: Experiment with a threaded renderer for fallback compositing
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/Makefile.am2
-rw-r--r--src/sna/sna.h14
-rw-r--r--src/sna/sna_driver.c2
-rw-r--r--src/sna/sna_render.c20
-rw-r--r--src/sna/sna_threads.c236
5 files changed, 264 insertions, 10 deletions
diff --git a/src/sna/Makefile.am b/src/sna/Makefile.am
index bcf757ef..bfa836f6 100644
--- a/src/sna/Makefile.am
+++ b/src/sna/Makefile.am
@@ -34,6 +34,7 @@ AM_CFLAGS += @VALGRIND_CFLAGS@
34endif 34endif
35 35
36noinst_LTLIBRARIES = libsna.la 36noinst_LTLIBRARIES = libsna.la
37libsna_la_LDFLAGS = -pthread
37libsna_la_LIBADD = @UDEV_LIBS@ -lm @DRM_LIBS@ brw/libbrw.la fb/libfb.la 38libsna_la_LIBADD = @UDEV_LIBS@ -lm @DRM_LIBS@ brw/libbrw.la fb/libfb.la
38 39
39libsna_la_SOURCES = \ 40libsna_la_SOURCES = \
@@ -62,6 +63,7 @@ libsna_la_SOURCES = \
62 sna_trapezoids.c \ 63 sna_trapezoids.c \
63 sna_tiling.c \ 64 sna_tiling.c \
64 sna_transform.c \ 65 sna_transform.c \
66 sna_threads.c \
65 sna_video.c \ 67 sna_video.c \
66 sna_video.h \ 68 sna_video.h \
67 sna_video_overlay.c \ 69 sna_video_overlay.c \
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 2ba5fe43..549a337c 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -835,4 +835,18 @@ inline static bool is_clipped(const RegionRec *r,
835 r->extents.y2 - r->extents.y1 != d->height); 835 r->extents.y2 - r->extents.y1 != d->height);
836} 836}
837 837
838void sna_threads_init(void);
839void sna_image_composite(pixman_op_t op,
840 pixman_image_t *src,
841 pixman_image_t *mask,
842 pixman_image_t *dst,
843 int16_t src_x,
844 int16_t src_y,
845 int16_t mask_x,
846 int16_t mask_y,
847 int16_t dst_x,
848 int16_t dst_y,
849 uint16_t width,
850 uint16_t height);
851
838#endif /* _SNA_H */ 852#endif /* _SNA_H */
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index a0707ed6..8420aebe 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -1174,5 +1174,7 @@ Bool sna_init_scrn(ScrnInfoPtr scrn, int entity_num)
1174 xf86SetEntityInstanceForScreen(scrn, entity_num, 1174 xf86SetEntityInstanceForScreen(scrn, entity_num,
1175 xf86GetNumEntityInstances(entity_num)-1); 1175 xf86GetNumEntityInstances(entity_num)-1);
1176 1176
1177 sna_threads_init();
1178
1177 return TRUE; 1179 return TRUE;
1178} 1180}
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index 46ce64ba..84c6b351 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -1465,11 +1465,11 @@ sna_render_picture_approximate_gradient(struct sna *sna,
1465 pixman_transform_multiply(&t, picture->transform, &t); 1465 pixman_transform_multiply(&t, picture->transform, &t);
1466 pixman_image_set_transform(src, &t); 1466 pixman_image_set_transform(src, &t);
1467 1467
1468 pixman_image_composite(PictOpSrc, src, NULL, dst, 1468 sna_image_composite(PictOpSrc, src, NULL, dst,
1469 x + dx, y + dy, 1469 x+dx, y+dy,
1470 0, 0, 1470 0, 0,
1471 0, 0, 1471 0, 0,
1472 w2, h2); 1472 w2, h2);
1473 free_pixman_pict(picture, src); 1473 free_pixman_pict(picture, src);
1474 pixman_image_unref(dst); 1474 pixman_image_unref(dst);
1475 1475
@@ -1580,11 +1580,11 @@ do_fixup:
1580 1580
1581 DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n", 1581 DBG(("%s: compositing tmp=(%d+%d, %d+%d)x(%d, %d)\n",
1582 __FUNCTION__, x, dx, y, dy, w, h)); 1582 __FUNCTION__, x, dx, y, dy, w, h));
1583 pixman_image_composite(PictOpSrc, src, NULL, dst, 1583 sna_image_composite(PictOpSrc, src, NULL, dst,
1584 x + dx, y + dy, 1584 x + dx, y + dy,
1585 0, 0, 1585 0, 0,
1586 0, 0, 1586 0, 0,
1587 w, h); 1587 w, h);
1588 free_pixman_pict(picture, src); 1588 free_pixman_pict(picture, src);
1589 1589
1590 /* Then convert to card format */ 1590 /* Then convert to card format */
diff --git a/src/sna/sna_threads.c b/src/sna/sna_threads.c
new file mode 100644
index 00000000..afa260ff
--- /dev/null
+++ b/src/sna/sna_threads.c
@@ -0,0 +1,236 @@
1/*
2 * Copyright © 2013 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Chris Wilson <chris@chris-wilson.co.uk>
25 *
26 */
27
28#include "sna.h"
29
30#include <unistd.h>
31#include <pthread.h>
32
33static int max_threads = -1;
34
35static struct thread {
36 pthread_t thread;
37 pthread_mutex_t mutex;
38 pthread_cond_t cond;
39
40 void (*func)(void *arg);
41 void *arg;
42} *threads;
43
44static void *__run__(void *arg)
45{
46 struct thread *t = arg;
47
48 pthread_mutex_lock(&t->mutex);
49 while (1) {
50 while (t->func == NULL)
51 pthread_cond_wait(&t->cond, &t->mutex);
52 pthread_mutex_unlock(&t->mutex);
53
54 assert(t->func);
55 t->func(t->arg);
56
57 pthread_mutex_lock(&t->mutex);
58 t->func = NULL;
59 pthread_cond_signal(&t->cond);
60 }
61 pthread_mutex_unlock(&t->mutex);
62
63 return NULL;
64}
65
66void sna_threads_init(void)
67{
68 int n;
69
70 if (max_threads != -1)
71 return;
72
73 max_threads = sysconf (_SC_NPROCESSORS_ONLN) / 2;
74 if (max_threads <= 1)
75 goto bail;
76
77 DBG(("%s: creating a thread pool of %d threads\n",
78 __func__, max_threads));
79
80 threads = malloc (sizeof(threads[0])*max_threads);
81 if (threads == NULL)
82 goto bail;
83
84 for (n = 0; n < max_threads; n++) {
85 pthread_mutex_init(&threads[n].mutex, NULL);
86 pthread_cond_init(&threads[n].cond, NULL);
87
88 threads[n].func = NULL;
89 if (pthread_create(&threads[n].thread, NULL,
90 __run__, &threads[n]))
91 goto bail;
92 }
93
94 return;
95
96bail:
97 max_threads = 0;
98}
99
100static void
101threads_run(void (*func)(void *arg), void *arg)
102{
103 int n;
104
105 assert(max_threads > 0);
106
107 for (n = 0; n < max_threads; n++) {
108 if (threads[n].func)
109 continue;
110
111 pthread_mutex_lock(&threads[n].mutex);
112 if (threads[n].func) {
113 pthread_mutex_unlock(&threads[n].mutex);
114 continue;
115 }
116
117 goto execute;
118 }
119
120 n = rand() % max_threads;
121 pthread_mutex_lock(&threads[n].mutex);
122 while (threads[n].func)
123 pthread_cond_wait(&threads[n].cond, &threads[n].mutex);
124
125execute:
126 threads[n].func = func;
127 threads[n].arg = arg;
128 pthread_cond_signal(&threads[n].cond);
129 pthread_mutex_unlock(&threads[n].mutex);
130}
131
132static void threads_wait(void)
133{
134 int n;
135
136 assert(max_threads > 0);
137
138 for (n = 0; n < max_threads; n++) {
139 if (threads[n].func == NULL)
140 continue;
141
142 pthread_mutex_lock(&threads[n].mutex);
143 while (threads[n].func)
144 pthread_cond_wait(&threads[n].cond, &threads[n].mutex);
145 pthread_mutex_unlock(&threads[n].mutex);
146 }
147}
148
149static int
150use_threads (int width, int height, int threshold)
151{
152 int num_threads;
153
154 if (max_threads <= 0)
155 return 1;
156
157 num_threads = height / (128/width + 1) / threshold-1;
158 if (num_threads <= 0)
159 return 1;
160
161 if (num_threads > max_threads)
162 num_threads = max_threads;
163 return num_threads;
164}
165
166struct thread_composite {
167 pixman_image_t *src, *mask, *dst;
168 pixman_op_t op;
169 int16_t src_x, src_y;
170 int16_t mask_x, mask_y;
171 int16_t dst_x, dst_y;
172 uint16_t width, height;
173};
174
175static void thread_composite(void *arg)
176{
177 struct thread_composite *t = arg;
178 pixman_image_composite(t->op, t->src, t->mask, t->dst,
179 t->src_x, t->src_y,
180 t->mask_x, t->mask_y,
181 t->dst_x, t->dst_y,
182 t->width, t->height);
183}
184
185void sna_image_composite(pixman_op_t op,
186 pixman_image_t *src,
187 pixman_image_t *mask,
188 pixman_image_t *dst,
189 int16_t src_x,
190 int16_t src_y,
191 int16_t mask_x,
192 int16_t mask_y,
193 int16_t dst_x,
194 int16_t dst_y,
195 uint16_t width,
196 uint16_t height)
197{
198 int num_threads;
199
200 num_threads = use_threads(width, height, 16);
201 if (num_threads <= 1) {
202 pixman_image_composite(op, src, mask, dst,
203 src_x, src_y,
204 mask_x, mask_y,
205 dst_x, dst_y,
206 width, height);
207 return;
208 } else {
209 struct thread_composite threads[num_threads];
210 int y, dy, n;
211
212 y = dst_y;
213 dy = (height + num_threads - 1) / num_threads;
214 for (n = 0; n < num_threads; n++) {
215 threads[n].op = op;
216 threads[n].src = src;
217 threads[n].mask = mask;
218 threads[n].dst = dst;
219 threads[n].src_x = src_x;
220 threads[n].src_y = src_y + y - dst_y;
221 threads[n].mask_x = mask_x;
222 threads[n].mask_y = mask_y + y - dst_y;
223 threads[n].dst_x = dst_x;
224 threads[n].dst_y = y;
225 threads[n].width = width;
226 threads[n].height = dy;
227
228 threads_run(thread_composite, &threads[n]);
229
230 y += dy;
231 if (y + dy > dst_y + height)
232 dy = dst_y + height - y;
233 }
234 threads_wait();
235 }
236}